Merge branch 'master' into worktree-tasks-service-seam

This commit is contained in:
Tianyi Cui
2026-07-26 22:57:38 +08:00
committed by GitHub
154 changed files with 6354 additions and 1834 deletions

View File

@@ -1,4 +1,4 @@
import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from 'node:fs'
import { existsSync, mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { dirname, join } from 'node:path'
import { afterEach, describe, expect, it } from 'vitest'
@@ -59,4 +59,21 @@ describe('RepositoryCleaner', () => {
await expect(new RepositoryCleaner(root).clean()).rejects.toThrow('packages/removed/ghost/notes.txt')
expect(existsSync(join(root, 'products/shell/lib'))).toBe(true)
})
it('refuses project outputs reached through a symlink outside the repository', async () => {
const root = fixture()
const externalProject = fixture()
write(join(root, 'tsconfig.json'), JSON.stringify({ files: [], references: [{ path: './linked' }] }))
write(join(externalProject, 'tsconfig.json'), JSON.stringify({
compilerOptions: { composite: true, outDir: 'lib/types' },
include: ['src'],
}))
write(join(externalProject, 'src/index.ts'), 'export {}\n')
write(join(externalProject, 'lib/types/index.js'))
symlinkSync(externalProject, join(root, 'linked'), process.platform === 'win32' ? 'junction' : 'dir')
await expect(new RepositoryCleaner(root).clean()).rejects.toThrow('outside repository')
expect(existsSync(join(externalProject, 'lib/types/index.js'))).toBe(true)
})
})

View File

@@ -1,4 +1,4 @@
import { lstat, readdir, rm } from 'node:fs/promises'
import { lstat, readdir, realpath, rm } from 'node:fs/promises'
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path'
import { fileURLToPath } from 'node:url'
import ts from 'typescript'
@@ -45,7 +45,11 @@ function parseConfig(configPath: string): ts.ParsedCommandLine {
/** Plans and removes repository-owned build output without crossing the repository boundary. */
export class RepositoryCleaner {
constructor(private readonly root: string) {}
private readonly root: string
constructor(root: string) {
this.root = resolve(root)
}
/**
* Remove generated build state and package directories containing only known residue.
@@ -61,9 +65,10 @@ export class RepositoryCleaner {
private async plan(): Promise<string[]> {
const targets = new Set<string>()
const unsafeOrphans: string[] = []
const canonicalRoot = await realpath(this.root)
// These checks cover legacy root-level incremental state emitted by older configs.
await this.addIfPresent(targets, join(this.root, '.typecheck'))
await this.addIfPresent(targets, join(this.root, '.typecheck'), canonicalRoot)
for (const entry of await readdir(this.root, { withFileTypes: true })) {
if (entry.isFile() && entry.name.endsWith('.tsbuildinfo')) targets.add(join(this.root, entry.name))
}
@@ -72,7 +77,7 @@ export class RepositoryCleaner {
// Each emitting project declares lib/types as outDir; its parent lib also owns
// the sibling runtime bundles, so the complete build output root is removed.
for (const outputDirectory of this.buildOutputDirectories()) {
await this.addIfPresent(targets, outputDirectory)
await this.addIfPresent(targets, outputDirectory, canonicalRoot)
}
for (const groupDirectory of await childDirectories(join(this.root, 'packages'))) {
@@ -90,7 +95,7 @@ export class RepositoryCleaner {
if (unknown.length > 0) {
unsafeOrphans.push(...unknown.map(entry => repositoryPath(this.root, join(packageDirectory, entry))))
} else {
targets.add(packageDirectory)
await this.addIfPresent(targets, packageDirectory, canonicalRoot)
}
}
}
@@ -137,15 +142,24 @@ export class RepositoryCleaner {
}
private assertRepositoryTarget(path: string): void {
const repositoryRelative = relative(this.root, path)
this.assertDescendant(this.root, path, path)
}
private assertDescendant(root: string, path: string, displayPath: string): void {
const repositoryRelative = relative(root, path)
if (repositoryRelative === '' || repositoryRelative === '..' || repositoryRelative.startsWith(`..${sep}`) || isAbsolute(repositoryRelative)) {
throw new Error(`clean: refusing build output outside repository: ${path}`)
throw new Error(`clean: refusing deletion target outside repository: ${displayPath}`)
}
}
private async addIfPresent(targets: Set<string>, path: string): Promise<void> {
private async addIfPresent(targets: Set<string>, path: string, canonicalRoot: string): Promise<void> {
// Missing outputs are normal on a clean checkout; only existing paths become deletion targets.
if (await exists(path)) targets.add(path)
if (!await exists(path)) return
// Resolve the parent rather than the final entry: rm unlinks a final symlink,
// but a symlink in an ancestor would make deletion cross the repository boundary.
const canonicalParent = await realpath(dirname(path))
this.assertDescendant(canonicalRoot, join(canonicalParent, basename(path)), path)
targets.add(path)
}
}

View File

@@ -169,14 +169,14 @@ const TOOL_PACKAGES: ToolPackage[] = [
dir: 'tools',
source: 'packages/core/tools/src/code-mode.ts',
requires: ['ctx.tools', 'ctx.codeRuntime (execution time)', 'ctx.systemPrompt'],
writes: ['tool/call', 'one tool/code-dispatch per bridged sub-call', 'tool/result'],
writes: ['tool/call', 'one tool/code-dispatch-start + tool/code-dispatch pair per bridged sub-call', 'tool/result'],
// The registry's OWN tool: run_code exists only under a non-native mode
// (the registry registers it in its constructor; the code runtime is read
// at assembly/execution time, so the schema harvest needs none mounted).
toolsConfig: { mode: 'code' },
async mount() {},
note:
'Owned by the tool registry as a reserved transport outside filterable capability layers under `mode: code` / `mode: both` (see the Code Mode Agent Note). Under `code` it is the registry\'s only wire contribution; the other visible capabilities are declared in a generated TypeScript SDK section, and a program calls them through serialized bindings that re-enter the complete guarded tool pipeline and link each nested execution to this outer result.',
'Owned by the tool registry as a reserved transport outside filterable capability layers under `mode: code` / `mode: both` (see the Code Mode Agent Note). Under `code` it is the registry\'s only wire contribution; the other visible capabilities are declared in a generated TypeScript SDK section, and a program calls them through bindings scheduled under the native concurrency contract (submission-ordered starts and policy; concurrency-safe bodies overlap up to `maxParallelSubCalls`) that re-enter the complete guarded tool pipeline and link each nested execution to this outer result.',
},
{
pkg: '@deepseek-ai/dsh-plan-mode',

View File

@@ -151,7 +151,11 @@ def completion_chunks(body: dict[str, object]) -> list[dict[str, object]]:
)
if prompt == CODE_PROMPT:
assert_advertised_tool(body, "run_code")
return tool_call_chunks("call-code-worker", "run_code", {"code": "return 6 * 7"})
return tool_call_chunks(
"call-code-worker",
"run_code",
{"code": "return 6 * 7", "description": "Compute the smoke value"},
)
if prompt == WORKFLOW_PROMPT:
assert_advertised_tool(body, "workflow")
return tool_call_chunks(