Merge branch 'worktree-session-modes-rfc' (master: sandbox stack #169, skills #109, prompt snapshots #254)
The stack rebases onto a moved master through its base branch. Beyond mechanical unions (both branches' demo scripts, example rows, service roles, tool lists, acp deps, doc budgets — each side fit alone, the union needs the higher ceilings), three semantic reconciliations: - The ACP bridge now carries BOTH per-session surfaces: the sandbox stack's config options + approval answerer and this branch's session modes; session/new and session/load advertise modes AND configOptions side by side. - The feature matrix supersedes the sandbox stance per the RFC's second-lander rule: session/set_mode and current_mode_update flip to shipped-by-dsh-mode, config-option rows stay as #169 wrote them, and §6 records both landed features under the picker-to-modes / knobs-to-config-options division. - The snapshot pin grammar (#254: one header snapshot + declared deltas + a Markdown prompt golden) gains a symmetric declaration for what a delta cannot express: expectedHeaderSnapshots — a plan-mode flip resorts the canonical tool list, so its widening lands as a second full snapshot, now its own Markdown section. The pin-less-class and model-turn-only-pin amendments carry over; new fixtures cover the extended writer paths, and the plan-acp-agent scenarios re-recorded under the merged composition (the app now bundles the skill tool) with the suite's refresh mode wired through.
This commit is contained in:
@@ -105,12 +105,6 @@ const dshBinPackageFiles = [
|
||||
'src',
|
||||
] as const
|
||||
|
||||
// Packages that ship a worker-thread entry as a sibling runtime bundle
|
||||
// (lib/worker.js, its own tsdown entry): the bootstrap is loaded via
|
||||
// `new Worker(new URL('./worker.js', import.meta.url))`, so it cannot live
|
||||
// inside the index bundle and must be published alongside it.
|
||||
const workerEntryPackages = new Set(['@deepseek-ai/dsh-code-runtime-worker'])
|
||||
|
||||
const dshWorkerPackageFiles = [
|
||||
'lib/index.js',
|
||||
'lib/worker.js',
|
||||
@@ -124,8 +118,12 @@ function sameStringList(actual: readonly string[] | undefined, expected: readonl
|
||||
}
|
||||
|
||||
function expectedDshPackageFiles(manifest: PackageManifest): readonly string[] {
|
||||
if (manifest.name && workerEntryPackages.has(manifest.name)) return dshWorkerPackageFiles
|
||||
return manifest.bin ? dshBinPackageFiles : dshPackageFiles
|
||||
if (manifest.bin) return dshBinPackageFiles
|
||||
// A declared "./worker" subpath export sanctions the one extra runtime
|
||||
// bundle a worker-thread entry needs (and NodeNext/publint then validate
|
||||
// that subpath's targets like any other export).
|
||||
if (manifest.exports?.['./worker']) return dshWorkerPackageFiles
|
||||
return dshPackageFiles
|
||||
}
|
||||
|
||||
function checkWorkspace({ dir, manifest }: WorkspaceManifest): string[] {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"AGENTS.md": 1802,
|
||||
"AGENTS.md": 1820,
|
||||
"docs/AGENTS.md": 1315,
|
||||
"docs/architecture.md": 1650,
|
||||
"docs/architecture.md": 1750,
|
||||
"docs/cordis-primer.md": 550,
|
||||
"docs/defensive-patterns.md": 550,
|
||||
"docs/testing.md": 800,
|
||||
"examples/AGENTS.md": 680,
|
||||
"examples/AGENTS.md": 700,
|
||||
"packages/AGENTS.md": 450,
|
||||
"packages/README.md": 660
|
||||
"packages/README.md": 700
|
||||
}
|
||||
|
||||
@@ -633,11 +633,17 @@ export function collectConfigCatalog(scanRoot: string = root): CatalogEntry[] {
|
||||
const manifests: { dir: string; pkg: string }[] = []
|
||||
for (const manifestRel of globSync('packages/*/*/package.json', { cwd: scanRoot }).sort()) {
|
||||
const dir = manifestRel.slice(0, -'/package.json'.length)
|
||||
const pkg = (JSON.parse(readFileSync(resolve(scanRoot, manifestRel), 'utf8')) as { name?: string }).name
|
||||
const manifest = JSON.parse(readFileSync(resolve(scanRoot, manifestRel), 'utf8')) as { name?: string; os?: string[]; cpu?: string[] }
|
||||
const pkg = manifest.name
|
||||
if (!pkg) {
|
||||
violations.push(`${manifestRel} has no "name".`)
|
||||
continue
|
||||
}
|
||||
if (manifest.os !== undefined && manifest.cpu !== undefined) {
|
||||
// A per-platform native-binary package (npm os/cpu selection) ships no
|
||||
// JavaScript at all — nothing to classify, no Config to catalog.
|
||||
continue
|
||||
}
|
||||
pkgDirByName.set(pkg, dir)
|
||||
manifests.push({ dir, pkg })
|
||||
}
|
||||
|
||||
@@ -92,11 +92,17 @@ export const LINK_MAP: Record<string, string> = {
|
||||
ToolDefinition: 'tools.md',
|
||||
ToolExecution: 'tools.md',
|
||||
ToolExecutionResult: 'tools.md',
|
||||
ApprovalOutcome: 'approval.md',
|
||||
ApprovalPolicy: 'approval.md',
|
||||
ApprovalRequest: 'approval.md',
|
||||
BashExecRequest: 'bash.md',
|
||||
BashExecSpec: 'bash.md',
|
||||
BashRunResult: 'bash.md',
|
||||
BashTask: 'bash.md',
|
||||
BashTaskRead: 'bash.md',
|
||||
ConfinedArgv: 'sandbox.md',
|
||||
SandboxMode: 'sandbox.md',
|
||||
SandboxPolicy: 'sandbox.md',
|
||||
CodeRunRequest: 'code-runtime.md',
|
||||
CodeRunResult: 'code-runtime.md',
|
||||
FsEditOutcome: 'filesystem.md',
|
||||
|
||||
@@ -70,7 +70,9 @@ const GROUP_ORDER = [
|
||||
'llm',
|
||||
'core',
|
||||
'bash',
|
||||
'sandbox',
|
||||
'fs',
|
||||
'skill',
|
||||
'compact',
|
||||
'subagent',
|
||||
'web',
|
||||
@@ -123,7 +125,7 @@ const SERVICE_ROLES: ServiceRole[] = [
|
||||
pkg: 'tools',
|
||||
title: 'Tool registry and execution waterfall',
|
||||
mode: 'core',
|
||||
consumers: ['agent-loop', 'tool-ask-user', 'tool-bash', 'tool-cordis', 'tool-fs', 'tool-subagent', 'tool-todo', 'tool-web', 'acp'],
|
||||
consumers: ['agent-loop', 'tool-ask-user', 'tool-bash', 'tool-cordis', 'tool-fs', 'tool-skill', 'tool-subagent', 'tool-todo', 'tool-web', 'acp'],
|
||||
note: 'Registers tool definitions, exposes schemas to the prompt, and routes calls through tools/pre-execute and tools/post-execute.',
|
||||
},
|
||||
{
|
||||
@@ -143,6 +145,15 @@ const SERVICE_ROLES: ServiceRole[] = [
|
||||
consumers: ['stdio-agent', 'acp'],
|
||||
note: 'Folds the logged per-agent mode (mode/set), flushes user flips at turn boundaries, and enforces the mode through the assemble filter and the tools/pre-execute gate.',
|
||||
},
|
||||
{
|
||||
key: 'skills',
|
||||
pkg: 'skill',
|
||||
title: 'Skill provider registry',
|
||||
mode: 'seam',
|
||||
implementations: ['skill-local'],
|
||||
consumers: ['tool-skill'],
|
||||
note: 'Merges provider skill catalogs; tool-skill renders the session-prefix catalog and loads complete skill bodies.',
|
||||
},
|
||||
{
|
||||
key: 'agents',
|
||||
pkg: 'agent',
|
||||
@@ -164,9 +175,27 @@ const SERVICE_ROLES: ServiceRole[] = [
|
||||
pkg: 'bash',
|
||||
title: 'Bash executor seam',
|
||||
mode: 'seam',
|
||||
implementations: ['bash-local'],
|
||||
implementations: ['bash-local', 'bash-sandbox'],
|
||||
consumers: ['tool-bash', 'hooks-claude', 'hooks-codex'],
|
||||
note: 'The model-facing bash tools and hook bridges consume this seam; sandboxed or remote executors can replace bash-local.',
|
||||
note: 'The model-facing bash tools and hook bridges consume this seam; sandboxed or remote executors replace bash-local without touching them.',
|
||||
},
|
||||
{
|
||||
key: 'sandbox',
|
||||
pkg: 'sandbox',
|
||||
title: 'Process-sandbox seam',
|
||||
mode: 'seam',
|
||||
implementations: ['sandbox-local'],
|
||||
consumers: ['bash-sandbox'],
|
||||
note: 'Consumers hand over the exact argv they are about to spawn; same-world backends wrap it under a per-call policy and report enforcement.',
|
||||
},
|
||||
{
|
||||
key: 'approval',
|
||||
pkg: 'approval',
|
||||
title: 'Approval seam',
|
||||
mode: 'seam',
|
||||
implementations: ['acp'],
|
||||
consumers: ['tools', 'tool-bash'],
|
||||
note: 'One-shot permission decisions dispatched over the `approval/request` waterfall; answerers are listeners (the ACP bridge for its own agents), absence fails closed to `unavailable`.',
|
||||
},
|
||||
{
|
||||
key: 'codeRuntime',
|
||||
@@ -214,6 +243,15 @@ const SERVICE_ROLES: ServiceRole[] = [
|
||||
consumers: ['tool-web'],
|
||||
note: 'Search and fetch providers register into one ctx.web seam; tool-web owns the stable model-facing names.',
|
||||
},
|
||||
{
|
||||
key: 'workflows',
|
||||
pkg: 'workflow',
|
||||
title: 'Workflow script engine',
|
||||
mode: 'seam',
|
||||
implementations: ['workflow-workerthread'],
|
||||
consumers: ['tool-workflow'],
|
||||
note: 'One engine per context (bash shape, no named-provider registry); the worker-thread engine fans agent() calls out through ctx.subagents.',
|
||||
},
|
||||
]
|
||||
|
||||
const DYNAMIC_EVENT_DISPATCHERS: Array<{ event: string; pkg: string; method: string }> = [
|
||||
@@ -222,6 +260,14 @@ const DYNAMIC_EVENT_DISPATCHERS: Array<{ event: string; pkg: string; method: str
|
||||
// listeners or strand an already-started child run.
|
||||
{ event: 'subagent/start', pkg: 'subagent', method: 'events.dispatch' },
|
||||
{ event: 'subagent/end', pkg: 'subagent', method: 'events.dispatch' },
|
||||
// The workflow/* lifecycle events dispatch the same way, for the same
|
||||
// per-listener-containment reason (WorkflowService.emitWorkflowEvent).
|
||||
{ event: 'workflow/start', pkg: 'workflow', method: 'events.dispatch' },
|
||||
{ event: 'workflow/phase', pkg: 'workflow', method: 'events.dispatch' },
|
||||
{ event: 'workflow/log', pkg: 'workflow', method: 'events.dispatch' },
|
||||
{ event: 'workflow/agent-start', pkg: 'workflow', method: 'events.dispatch' },
|
||||
{ event: 'workflow/agent-end', pkg: 'workflow', method: 'events.dispatch' },
|
||||
{ event: 'workflow/end', pkg: 'workflow', method: 'events.dispatch' },
|
||||
]
|
||||
|
||||
function generatedHeader(title: string): string[] {
|
||||
@@ -673,7 +719,8 @@ function renderToolPipeline(): string {
|
||||
` toolCall["Session event: ${mermaidCode('tool/call')}<br/>logged before execution"]`,
|
||||
' presentCall["UI pending card<br/>presentCall(args)"]',
|
||||
` pre["${mermaidCode('tools/pre-execute')} waterfall<br/>hooks, permission, sandbox"]`,
|
||||
' denied["deny or ask<br/>tool body skipped"]',
|
||||
' denied["denied<br/>tool body skipped"]',
|
||||
` approval["${mermaidCode('ctx.approval')} one-shot prompt<br/>absent or unanswerable: deny"]`,
|
||||
` around["${mermaidCode('tools/execute')} waterfall<br/>timeout, retry, metrics (around dispatch)"]`,
|
||||
' toolBody["Registered tool execute() body"]',
|
||||
` fsGate["${mermaidCode('fs/write-intent')} or ${mermaidCode('fs/edit-intent')}<br/>tool-fs mutations only"]`,
|
||||
@@ -687,7 +734,10 @@ function renderToolPipeline(): string {
|
||||
' toolCall --> pre',
|
||||
' pre -->|allow| around',
|
||||
' around --> toolBody',
|
||||
' pre -->|deny or ask| denied',
|
||||
' pre -->|deny| denied',
|
||||
' pre -->|ask| approval',
|
||||
' approval -->|allowed-once| around',
|
||||
' approval -->|rejected, cancelled, unavailable| denied',
|
||||
' denied --> post',
|
||||
' toolBody --> fsGate',
|
||||
' fsGate --> toolBody',
|
||||
@@ -699,7 +749,7 @@ function renderToolPipeline(): string {
|
||||
' toolResult --> presentResult',
|
||||
'```',
|
||||
'',
|
||||
'Filesystem read-before-edit checks live below `tool-fs` on the `fs/*` event gate; hook bridges and future permission prompts live on the generic pre/post tool waterfalls; and around-dispatch concerns like the tool-call timeout policy (`@deepseek-ai/dsh-timeout-policy`) wrap core dispatch on `tools/execute`. That split lets the same hooks observe bash, fs, web, todo, and subagent calls without coupling those tools to one policy service. Code Mode rides the same pipeline twice over: `run_code` is itself a registered tool body, and each tool call its program makes re-enters `ctx.tools.execute()` through BOTH waterfalls — serialized one at a time, logged as a `tool/code-dispatch` session event, with a deny surfacing to the program as a binding rejection (a sub-call\'s `additionalContext` is deliberately dropped — no safe outlet mid-run preserves call/result adjacency).',
|
||||
'Filesystem read-before-edit checks live below `tool-fs` on the `fs/*` event gate; hook bridges and the approval seam\'s permission prompts live on the generic pre/post tool waterfalls; and around-dispatch concerns like the tool-call timeout policy (`@deepseek-ai/dsh-timeout-policy`) wrap core dispatch on `tools/execute`. That split lets the same hooks observe bash, fs, web, todo, and subagent calls without coupling those tools to one policy service.',
|
||||
'',
|
||||
...maintenanceFooter(maintenance),
|
||||
].join('\n')
|
||||
|
||||
@@ -42,6 +42,7 @@ const GROUP_ORDER = [
|
||||
'core',
|
||||
'bash',
|
||||
'fs',
|
||||
'skill',
|
||||
'compact',
|
||||
'subagent',
|
||||
'web',
|
||||
|
||||
@@ -48,13 +48,18 @@ import * as WebSearchExa from '@deepseek-ai/dsh-web-search-exa'
|
||||
import * as WebFetchLocal from '@deepseek-ai/dsh-web-fetch-local'
|
||||
import SubagentService from '@deepseek-ai/dsh-subagent'
|
||||
import * as SubagentMock from '@deepseek-ai/dsh-subagent-mock'
|
||||
import SkillService from '@deepseek-ai/dsh-skill'
|
||||
import * as SkillLocal from '@deepseek-ai/dsh-skill-local'
|
||||
import * as ToolAskUser from '@deepseek-ai/dsh-tool-ask-user'
|
||||
import * as ToolBash from '@deepseek-ai/dsh-tool-bash'
|
||||
import * as ToolCordis from '@deepseek-ai/dsh-tool-cordis'
|
||||
import * as ToolFs from '@deepseek-ai/dsh-tool-fs'
|
||||
import * as ToolSkill from '@deepseek-ai/dsh-tool-skill'
|
||||
import * as ToolTodo from '@deepseek-ai/dsh-tool-todo'
|
||||
import * as ToolSubagent from '@deepseek-ai/dsh-tool-subagent'
|
||||
import * as ToolWeb from '@deepseek-ai/dsh-tool-web'
|
||||
import VmWorkflowEngine from '@deepseek-ai/dsh-workflow-workerthread'
|
||||
import * as ToolWorkflow from '@deepseek-ai/dsh-tool-workflow'
|
||||
|
||||
const root = resolve(import.meta.dirname, '..')
|
||||
const OUT = 'docs/tool-catalog.md'
|
||||
@@ -191,6 +196,21 @@ const TOOL_PACKAGES: ToolPackage[] = [
|
||||
note:
|
||||
'The read-before-write/edit policy is added by `@deepseek-ai/dsh-fs-policy` (an `fs/*` event-gate plugin, no schema change); a deployment that loads these tools is expected to also load it. The tool schemas above are identical with or without the policy plugin.',
|
||||
},
|
||||
{
|
||||
pkg: '@deepseek-ai/dsh-tool-skill',
|
||||
dir: 'tool-skill',
|
||||
source: 'packages/skill/tool-skill/src/index.ts',
|
||||
requires: ['ctx.tools', 'ctx.skills'],
|
||||
writes: ['tool/call', 'tool/result'],
|
||||
async mount(ctx) {
|
||||
await ctx.plugin(SkillService)
|
||||
await ctx.plugin(SkillLocal, {
|
||||
dshHome: resolve(root, '.tmp/tool-catalog/.dsh'),
|
||||
agentsHome: resolve(root, '.tmp/tool-catalog/.agents'),
|
||||
})
|
||||
await ctx.plugin(ToolSkill)
|
||||
},
|
||||
},
|
||||
{
|
||||
pkg: '@deepseek-ai/dsh-tool-subagent',
|
||||
dir: 'tool-subagent',
|
||||
@@ -219,6 +239,22 @@ const TOOL_PACKAGES: ToolPackage[] = [
|
||||
note:
|
||||
'todo_write is session-owned state; UIs render the latest todo/write event as a checklist or ACP plan.',
|
||||
},
|
||||
{
|
||||
pkg: '@deepseek-ai/dsh-tool-workflow',
|
||||
dir: 'tool-workflow',
|
||||
source: 'packages/workflow/tool-workflow/src/index.ts',
|
||||
requires: ['ctx.tools', 'ctx.workflows', 'ctx.systemPrompt', 'a calling Agent (exec.agent parents the script children)'],
|
||||
writes: ['tool/call', 'tool/result'],
|
||||
async mount(ctx) {
|
||||
// The tool injects `workflows`; boot the vm engine over a scripted
|
||||
// subagent provider to satisfy it. The schema does not depend on which
|
||||
// provider backs the engine.
|
||||
await ctx.plugin(SubagentService)
|
||||
await ctx.plugin(SubagentMock, { name: 'mock' })
|
||||
await ctx.plugin(VmWorkflowEngine, { provider: 'mock' })
|
||||
await ctx.plugin(ToolWorkflow)
|
||||
},
|
||||
},
|
||||
{
|
||||
pkg: '@deepseek-ai/dsh-tool-web',
|
||||
dir: 'tool-web',
|
||||
|
||||
@@ -286,18 +286,28 @@ function demoSmokeGate(options: { needs?: string[] } = {}): Gate {
|
||||
...dependencyOptions,
|
||||
verify: async (result) => {
|
||||
const output = result.stdout + result.stderr
|
||||
if (!output.includes('[tool call] echo({"text":"ci smoke"})')) {
|
||||
throw new Error('demo smoke did not show the echo tool call.')
|
||||
const sessionsRoot = join(root, '.sessions')
|
||||
try {
|
||||
if (!output.includes('[tool call] echo({"text":"ci smoke"})')) {
|
||||
throw new Error('demo smoke did not show the echo tool call.')
|
||||
}
|
||||
if (!output.includes('[tool result] ECHO: CI SMOKE')) {
|
||||
throw new Error('demo smoke did not show the echo tool result.')
|
||||
}
|
||||
const buckets = await readdir(sessionsRoot, { withFileTypes: true })
|
||||
let found = false
|
||||
for (const bucket of buckets) {
|
||||
if (!bucket.isDirectory() || !bucket.name.startsWith('cwd-')) continue
|
||||
const entries = await readdir(join(sessionsRoot, bucket.name))
|
||||
if (entries.some(entry => /^main-session-.+\.jsonl$/.test(entry))) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!found) throw new Error('demo smoke did not create a main-session JSONL log in a cwd bucket.')
|
||||
} finally {
|
||||
await rm(sessionsRoot, { recursive: true, force: true })
|
||||
}
|
||||
if (!output.includes('[tool result] ECHO: CI SMOKE')) {
|
||||
throw new Error('demo smoke did not show the echo tool result.')
|
||||
}
|
||||
const sessionDir = join(root, '.sessions', '_no-cwd')
|
||||
const entries = await readdir(sessionDir)
|
||||
if (!entries.some(entry => /^main-session-.+\.jsonl$/.test(entry))) {
|
||||
throw new Error('demo smoke did not create a main-session JSONL log.')
|
||||
}
|
||||
await rm(join(root, '.sessions'), { recursive: true, force: true })
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -310,6 +320,10 @@ function builtBinSmokeGate(): Gate {
|
||||
'vitest.e2e.config.ts',
|
||||
'packages/ui/stdio-agent/tests/built-bin.e2e.ts',
|
||||
'packages/ui/acp-agent/tests/built-bin.e2e.ts',
|
||||
// The worker-entry packages' built bundles: the only automated proof
|
||||
// that lib/index.js resolves its sibling lib/worker.js under plain node
|
||||
// (the e2e lane runs unbuilt, so these files self-skip there).
|
||||
'packages/workflow/workflow-workerthread/tests/built-worker.e2e.ts',
|
||||
'packages/code-runtime/code-runtime-worker/tests/built-lib.e2e.ts',
|
||||
], {
|
||||
label: 'built-bin smoke',
|
||||
|
||||
@@ -56,13 +56,25 @@
|
||||
{ "doc": "docs/core-data-structures/user-interaction.md", "symbol": "UserInteractionProvider", "source": "packages/ui/user-interaction/src/index.ts" },
|
||||
{ "doc": "docs/core-data-structures/user-interaction.md", "symbol": "UserInteractionError", "source": "packages/ui/user-interaction/src/index.ts" },
|
||||
|
||||
{ "doc": "docs/core-data-structures/approval.md", "symbol": "ApprovalRequestId", "source": "packages/ui/user-approval/src/index.ts" },
|
||||
{ "doc": "docs/core-data-structures/approval.md", "symbol": "ApprovalOutcome", "source": "packages/ui/user-approval/src/index.ts" },
|
||||
{ "doc": "docs/core-data-structures/approval.md", "symbol": "ApprovalPolicy", "source": "packages/ui/user-approval/src/index.ts" },
|
||||
{ "doc": "docs/core-data-structures/approval.md", "symbol": "ApprovalRequest", "source": "packages/ui/user-approval/src/index.ts" },
|
||||
|
||||
{ "doc": "docs/core-data-structures/bash.md", "symbol": "BashExecRequest", "source": "packages/bash/bash/src/types.ts" },
|
||||
{ "doc": "docs/core-data-structures/bash.md", "symbol": "BashExecSpec", "source": "packages/bash/bash/src/types.ts" },
|
||||
{ "doc": "docs/core-data-structures/bash.md", "symbol": "BashRunResult", "source": "packages/bash/bash/src/types.ts" },
|
||||
{ "doc": "docs/core-data-structures/bash.md", "symbol": "BashSandboxInfo", "source": "packages/bash/bash/src/types.ts" },
|
||||
{ "doc": "docs/core-data-structures/bash.md", "symbol": "CollectedOutput", "source": "packages/bash/bash/src/types.ts" },
|
||||
{ "doc": "docs/core-data-structures/bash.md", "symbol": "BashTask", "source": "packages/bash/bash/src/types.ts" },
|
||||
{ "doc": "docs/core-data-structures/bash.md", "symbol": "BashTaskRead", "source": "packages/bash/bash/src/types.ts" },
|
||||
|
||||
{ "doc": "docs/core-data-structures/sandbox.md", "symbol": "SandboxMode", "source": "packages/sandbox/sandbox/src/index.ts" },
|
||||
{ "doc": "docs/core-data-structures/sandbox.md", "symbol": "ConfinedSandboxMode", "source": "packages/sandbox/sandbox/src/index.ts" },
|
||||
{ "doc": "docs/core-data-structures/sandbox.md", "symbol": "SandboxEnforcement", "source": "packages/sandbox/sandbox/src/index.ts" },
|
||||
{ "doc": "docs/core-data-structures/sandbox.md", "symbol": "SandboxPolicy", "source": "packages/sandbox/sandbox/src/index.ts" },
|
||||
{ "doc": "docs/core-data-structures/sandbox.md", "symbol": "ConfinedArgv", "source": "packages/sandbox/sandbox/src/index.ts" },
|
||||
|
||||
{ "doc": "docs/core-data-structures/code-runtime.md", "symbol": "CodeRunRequest", "source": "packages/code-runtime/code-runtime/src/types.ts" },
|
||||
{ "doc": "docs/core-data-structures/code-runtime.md", "symbol": "CodeRunResult", "source": "packages/code-runtime/code-runtime/src/types.ts" },
|
||||
{ "doc": "docs/core-data-structures/code-runtime.md", "symbol": "CodeBindingNamespace", "source": "packages/code-runtime/code-runtime/src/types.ts" },
|
||||
@@ -83,6 +95,16 @@
|
||||
{ "doc": "docs/core-data-structures/filesystem.md", "symbol": "FsPolicyExec", "source": "packages/fs/fs-policy/src/types.ts" },
|
||||
{ "doc": "docs/core-data-structures/filesystem.md", "symbol": "FileReadOutcome", "source": "packages/fs/tool-fs/src/read-render.ts" },
|
||||
|
||||
{ "doc": "docs/core-data-structures/skills.md", "symbol": "SkillSource", "source": "packages/skill/skill/src/index.ts" },
|
||||
{ "doc": "docs/core-data-structures/skills.md", "symbol": "SkillResourceBase", "source": "packages/skill/skill/src/index.ts" },
|
||||
{ "doc": "docs/core-data-structures/skills.md", "symbol": "SkillSummary", "source": "packages/skill/skill/src/index.ts" },
|
||||
{ "doc": "docs/core-data-structures/skills.md", "symbol": "SkillCandidate", "source": "packages/skill/skill/src/index.ts" },
|
||||
{ "doc": "docs/core-data-structures/skills.md", "symbol": "SkillDefinition", "source": "packages/skill/skill/src/index.ts" },
|
||||
{ "doc": "docs/core-data-structures/skills.md", "symbol": "SkillRegistration", "source": "packages/skill/skill/src/index.ts" },
|
||||
{ "doc": "docs/core-data-structures/skills.md", "symbol": "SkillLookupOptions", "source": "packages/skill/skill/src/index.ts" },
|
||||
{ "doc": "docs/core-data-structures/skills.md", "symbol": "SkillProvider", "source": "packages/skill/skill/src/index.ts" },
|
||||
{ "doc": "docs/core-data-structures/skills.md", "symbol": "Config", "source": "packages/skill/skill/src/index.ts" },
|
||||
|
||||
{ "doc": "docs/core-data-structures/compaction.md", "symbol": "CompactionResult", "source": "packages/compact/compact/src/types.ts" },
|
||||
|
||||
{ "doc": "docs/core-data-structures/subagent.md", "symbol": "SubagentCapabilities", "source": "packages/subagent/subagent/src/types.ts" },
|
||||
@@ -98,6 +120,11 @@
|
||||
{ "doc": "docs/core-data-structures/web.md", "symbol": "WebFetchRequest", "source": "packages/web/web/src/types.ts" },
|
||||
{ "doc": "docs/core-data-structures/web.md", "symbol": "WebFetchResult", "source": "packages/web/web/src/types.ts" },
|
||||
{ "doc": "docs/core-data-structures/web.md", "symbol": "WebFetchBody", "source": "packages/web/web/src/types.ts" },
|
||||
{ "doc": "docs/core-data-structures/web.md", "symbol": "WebProviderStatus", "source": "packages/web/web/src/types.ts" }
|
||||
{ "doc": "docs/core-data-structures/web.md", "symbol": "WebProviderStatus", "source": "packages/web/web/src/types.ts" },
|
||||
|
||||
{ "doc": "docs/core-data-structures/workflow.md", "symbol": "WorkflowStartRequest", "source": "packages/workflow/workflow/src/types.ts" },
|
||||
{ "doc": "docs/core-data-structures/workflow.md", "symbol": "WorkflowMeta", "source": "packages/workflow/workflow/src/types.ts" },
|
||||
{ "doc": "docs/core-data-structures/workflow.md", "symbol": "WorkflowResult", "source": "packages/workflow/workflow/src/types.ts" },
|
||||
{ "doc": "docs/core-data-structures/workflow.md", "symbol": "WorkflowRun", "source": "packages/workflow/workflow/src/types.ts" }
|
||||
]
|
||||
}
|
||||
|
||||
@@ -18,9 +18,11 @@
|
||||
* A wrapped paragraph inside a list item or blockquote is still a `paragraph`
|
||||
* node, so those are caught too. Scope mirrors doc-typecheck plus the two
|
||||
* AGENTS.md files that doc-sync does NOT otherwise cover (the convention itself
|
||||
* lives there): README.md, docs/** /*.md, packages/* /*.md, AGENTS.md,
|
||||
* packages/AGENTS.md. The root and packages/ CLAUDE.md are symlinks to the
|
||||
* AGENTS.md files, so they are deduped by real path.
|
||||
* lives there), plus generated system-prompt Markdown goldens: README.md,
|
||||
* docs/** /*.md, packages/* /*.md, examples/** /system-prompt.golden.md,
|
||||
* packages/** /system-prompt.golden.md, AGENTS.md, packages/AGENTS.md. The root
|
||||
* and packages/ CLAUDE.md are symlinks to the AGENTS.md files, so they are
|
||||
* deduped by real path.
|
||||
*
|
||||
* Run: `tsx scripts/verify-md-wrap.ts`.
|
||||
*/
|
||||
@@ -34,8 +36,18 @@ import type { Nodes } from 'mdast'
|
||||
|
||||
const root = resolve(import.meta.dirname, '..')
|
||||
|
||||
/** Files to check: doc-typecheck's scope plus the AGENTS.md pair. */
|
||||
const PATTERNS = ['README.md', 'README.zh.md', 'docs/**/*.md', 'packages/*/*.md', 'packages/*/*/*.md', 'AGENTS.md', 'packages/AGENTS.md']
|
||||
/** Files to check: doc-typecheck's scope, prompt goldens, and the AGENTS.md pair. */
|
||||
const PATTERNS = [
|
||||
'README.md',
|
||||
'README.zh.md',
|
||||
'docs/**/*.md',
|
||||
'packages/*/*.md',
|
||||
'packages/*/*/*.md',
|
||||
'examples/**/system-prompt.golden.md',
|
||||
'packages/**/system-prompt.golden.md',
|
||||
'AGENTS.md',
|
||||
'packages/AGENTS.md',
|
||||
]
|
||||
|
||||
/** A located hard-wrap: a prose paragraph spanning more than one source line. */
|
||||
interface Violation {
|
||||
|
||||
Reference in New Issue
Block a user