2026-06-11 10:52:45 +08:00
|
|
|
{
|
|
|
|
|
"extends": "./tsconfig.base.json",
|
2026-06-17 23:41:18 +08:00
|
|
|
"compilerOptions": {
|
2026-06-22 09:03:28 +08:00
|
|
|
"noEmit": true,
|
|
|
|
|
"rewriteRelativeImportExtensions": false
|
2026-06-17 23:41:18 +08:00
|
|
|
},
|
|
|
|
|
"include": [
|
|
|
|
|
"examples/*/src/**/*.ts",
|
|
|
|
|
"examples/*/start.ts",
|
|
|
|
|
"examples/*/tests/**/*.ts",
|
2026-06-22 00:35:51 +08:00
|
|
|
"packages/*/*/tests/**/*.ts",
|
2026-07-13 15:38:47 +08:00
|
|
|
"scripts/**/*.ts",
|
|
|
|
|
"website/**/*.ts",
|
|
|
|
|
"website/.vitepress/**/*.ts"
|
2026-06-17 23:41:18 +08:00
|
|
|
],
|
|
|
|
|
"references": [
|
|
|
|
|
{ "path": "./vendor/cosmokit" },
|
|
|
|
|
{ "path": "./vendor/schemastery" },
|
|
|
|
|
{ "path": "./vendor/cordis" },
|
|
|
|
|
{ "path": "./vendor/loader" },
|
|
|
|
|
{ "path": "./vendor/include" },
|
|
|
|
|
{ "path": "./vendor/group" },
|
|
|
|
|
{ "path": "./vendor/timer" },
|
|
|
|
|
{ "path": "./vendor/hmr" },
|
|
|
|
|
{ "path": "./vendor/logger-console" },
|
2026-06-22 00:51:41 +08:00
|
|
|
{ "path": "./packages/util/brand" },
|
2026-07-12 16:30:01 +08:00
|
|
|
{ "path": "./packages/util/home" },
|
2026-06-29 21:42:23 +08:00
|
|
|
{ "path": "./packages/util/paths" },
|
2026-07-06 16:23:52 +08:00
|
|
|
{ "path": "./packages/util/timeout" },
|
2026-07-07 09:31:53 +08:00
|
|
|
{ "path": "./packages/util/retention" },
|
2026-06-22 00:51:41 +08:00
|
|
|
{ "path": "./packages/llm/llm" },
|
2026-07-15 14:47:29 +08:00
|
|
|
{ "path": "./packages/llm/token-meter" },
|
2026-06-22 00:51:41 +08:00
|
|
|
{ "path": "./packages/core/session" },
|
2026-07-08 23:54:03 +08:00
|
|
|
{ "path": "./packages/core/scope" },
|
2026-06-22 00:51:41 +08:00
|
|
|
{ "path": "./packages/session-persistence/session-persistence" },
|
|
|
|
|
{ "path": "./packages/session-persistence/session-persistence-jsonl" },
|
|
|
|
|
{ "path": "./packages/session-persistence/session-persistence-sqlite" },
|
2026-07-10 16:51:19 +08:00
|
|
|
{ "path": "./packages/session-query/session-query" },
|
2026-07-21 01:53:24 +08:00
|
|
|
{ "path": "./packages/session-title/session-title" },
|
|
|
|
|
{ "path": "./packages/session-title/session-title-llm" },
|
|
|
|
|
{ "path": "./packages/session-title/session-title-first-message-llm" },
|
|
|
|
|
{ "path": "./packages/session-title/session-title-all-messages-llm" },
|
2026-06-22 00:51:41 +08:00
|
|
|
{ "path": "./packages/core/system-prompt" },
|
|
|
|
|
{ "path": "./packages/core/agent" },
|
2026-07-14 16:04:34 +08:00
|
|
|
{ "path": "./packages/context/time-context" },
|
2026-07-09 17:55:01 +08:00
|
|
|
{ "path": "./packages/ui/user-interaction" },
|
2026-07-11 21:37:38 +08:00
|
|
|
{ "path": "./packages/ui/user-approval" },
|
feat(permission): user-facing permission presets — one Permissions select over the two knobs
A preset names a bundle of the two mechanism knobs — request =
workspace-write + ask, yolo = danger-full-access + never — so the editor
shows ONE 'Permissions' select where the sandbox-mode and approval-policy
tiers stay orthogonal capabilities (the Codex /approvals shape: presets over
two dials). ctx.permission (dsh-permission) owns the config-defined table,
validates the default preset's bundle against the composed knob defaults at
load (fails loud), and writes a switch THROUGH: one log-only
permission/preset event (the audit fact reverse-mapping cannot recover —
the planned 'agent' preset shares request's knob values and differs only in
composed policy) plus each knob event via its own setter, deduped — a
net-zero switch appends nothing. Every knob consumer keeps reading its own
fold, untouched.
The current preset DERIVES from the effective knob values — the fold breaks
bundle ties, a knob state outside the table is the reserved 'custom' value
(a state, not an error: shown while it holds, switchable FROM, never a
target), and defaultPreset disappears (zero-event state reverse-maps from
the composition defaults).
The ACP bridge drops the two per-knob selects for the one preset select
(advertised only when ctx.permission is composed); pending/anchor/no-op
semantics carry over unchanged, with the no-op echo acknowledged before
vocabulary validation so a client re-pushing a derived 'custom' current
never errors. The sandbox variant example composes the
service with a workspace-write default; the permission-switching,
escalation-approved and escalation-rejected scenarios are re-recorded under
it (escalations now target an outside-workspace /tmp path under
danger-full-access, self-cleaning) and config-options is re-authored on the
single-select wire.
2026-07-12 21:03:41 +08:00
|
|
|
{ "path": "./packages/ui/permission" },
|
2026-06-22 00:51:41 +08:00
|
|
|
{ "path": "./packages/core/tools" },
|
2026-07-10 14:19:06 +08:00
|
|
|
{ "path": "./packages/skill/skill" },
|
|
|
|
|
{ "path": "./packages/skill/skill-local" },
|
|
|
|
|
{ "path": "./packages/skill/tool-skill" },
|
2026-06-29 10:49:07 +08:00
|
|
|
{ "path": "./packages/ui/tool-ask-user" },
|
2026-07-16 16:01:06 +08:00
|
|
|
{ "path": "./packages/context/workspace-context" },
|
2026-06-22 00:51:41 +08:00
|
|
|
{ "path": "./packages/core/agent-loop" },
|
2026-07-20 03:34:19 +08:00
|
|
|
{ "path": "./packages/llm/llm-retry" },
|
2026-07-15 15:57:57 +08:00
|
|
|
{ "path": "./packages/examples/agent-spine-demo" },
|
2026-07-15 21:21:24 +08:00
|
|
|
{ "path": "./packages/examples/cli-demo" },
|
2026-06-22 00:51:41 +08:00
|
|
|
{ "path": "./packages/bash/bash" },
|
2026-07-08 02:17:24 +08:00
|
|
|
{ "path": "./packages/code-runtime/code-runtime" },
|
feat: add the worker-thread code runtime (dsh-code-runtime-worker)
The shipped backend of the code-execution seam, per the Code Mode RFC's
worker-thread section: one fresh Node worker per run, executing the
model's TypeScript after a host-side type-strip (wrapped in an
async-function shell so top-level return/await parse, sliced back out
position-preserved), bindings bridged over the message port under
hostile-peer rules (own-property name lookup, at-most-once replies,
post-settlement drops, null-prototype namespaces), logs streamed eagerly
with an in-band truncation marker, and two independent budgets — measured
event-loop busy time (computeMs) plus a never-pausing wall ceiling
(maxWallMs) — funneling into worker.terminate(). env: {} and execArgv: []
keep the isolate hermetic; disposal aborts in-flight runs and awaits
worker exits.
The worker entry loads unbuilt via Node's native type stripping
(src/worker.ts, erasable-only) and ships built as a sibling tsdown bundle
(lib/worker.js); tests/built-lib.e2e.ts pins the built load path under
plain node and joins the built-artifact smoke gate. Unit suites cover the
bootstrap in-process (fake port) and the runtime over real workers,
per-file 100%.
2026-07-08 11:00:06 +08:00
|
|
|
{ "path": "./packages/code-runtime/code-runtime-worker" },
|
2026-06-22 00:51:41 +08:00
|
|
|
{ "path": "./packages/llm/llm-deepseek" },
|
|
|
|
|
{ "path": "./packages/llm/llm-pi-ai" },
|
|
|
|
|
{ "path": "./packages/bash/bash-local" },
|
2026-07-09 16:44:32 +08:00
|
|
|
{ "path": "./packages/sandbox/sandbox" },
|
|
|
|
|
{ "path": "./packages/sandbox/sandbox-local" },
|
feat(sandbox): cross-family file sandbox — one policy home, sandboxed fs provider, fs escalation parity
Extend SandboxMode enforcement from bash to the filesystem tools, the sandbox
RFC's deferred cross-family phase.
- dsh-sandbox-policy (new, ctx.sandboxPolicy): the single home for the
deployment default mode + workspaceRoot and the per-session override event,
renamed bash/sandbox-mode -> sandbox/mode and moved here with its fold/setter.
Decouples the bash seam from dsh-session.
- dsh-fs-sandbox (new): SandboxedFileSystem extends LocalFileSystem and fences
write/edit by the per-call mode (read-only denies, workspace-write contains to
the workspace + temp roots via the shared writableRoots, danger passes
through); reads pass through. Structured FS_SANDBOX_DENIED; in-lock parent
re-canonicalization. A policy fence in trusted code, not a kernel boundary.
- dsh-sandbox: the shared escalation kit (writableRoots, the strictly-wider
ladder, denial/hint markers, approveEscalation) both tool families use;
approveEscalation takes a structural approver so dsh-sandbox gains no
approval/agent dependency, and both tools stay duplication-free.
- tool-fs: write/edit advertise sandbox_permissions/justification under a
confining ctx.fs, map FS_SANDBOX_DENIED to the shared [sandbox: ...] marker,
and resolve the same one-approved-wider retry.
- examples/acp-agent: composes sandbox-policy + fs-sandbox, drops the gating
that disabled the fs stack under confined modes.
RFC docs/rfc/implemented/feature/2026-07-14-cross-family-fs-sandbox.md; the old
sandbox RFC's In-process/deferred/FAQ sections updated to shipped fact.
2026-07-14 20:05:57 +08:00
|
|
|
{ "path": "./packages/sandbox/sandbox-policy" },
|
2026-07-09 16:44:32 +08:00
|
|
|
{ "path": "./packages/bash/bash-sandbox" },
|
2026-06-22 00:51:41 +08:00
|
|
|
{ "path": "./packages/bash/tool-bash" },
|
2026-06-28 17:24:45 +08:00
|
|
|
{ "path": "./packages/fs/fs" },
|
|
|
|
|
{ "path": "./packages/fs/fs-local" },
|
fix(fs): address review — rename to dsh-fs-policy, fs/*-intent events, RFC currency, ENOTDIR
Rename per review naming decisions:
- package dsh-file-context → dsh-fs-policy (dir, package name, plugin name,
tsconfig refs, importers, type-equiv manifest, generated catalog + module-graph)
- events fs/write-expectation → fs/write-intent, fs/edit-expectation → fs/edit-intent
(fs/observed unchanged); type FsWriteExpectation → FsWriteIntent, "expectation"
wording → "intent" throughout
- exported FileContextExec → FsPolicyExec
Make the implemented RFCs describe what shipped, not the superseded designs:
the 2026-06-17 capability-seam + tool-schemas RFCs no longer place policy on
ctx.fs or use full/partial-view authorization, and the fsspec RFC's ctx.fileContext
service prose is rewritten to the fs/* event-gate reality (freshness-based auth).
Sharpen docs/rfc/implemented/AGENTS.md: a rename is a fact to fix IN PLACE — the
"new RFC" escape hatch is for macro decision reversals only, not renames.
Code fixes from review:
- fsio.ts resolveLocalTarget/probe translate ENOTDIR (a parent path segment is a
file) into the structured FsError taxonomy instead of leaking a raw Node error;
resolve reports FS_NOT_FOUND, probe reports absent. Regression tests proven to
fail on the unfixed code.
- tool-fs HMR test now asserts prompt sections (not just tool schemas) are
withdrawn on disposal.
- fs/observed is a plain (unguarded) ctx.emit: correct the fs-policy comment,
filesystem.md, and tool-fs module doc that wrongly claimed the tool "contains"
a throwing listener; a throw surfaces as the tool's isError result.
- drop the false "loaded by the default product config" claim (no config wires
the fs tools yet), the duplicate ctx.bash service-map row, the stale
FileReadRequest catalog link-map entry, and the fs/fs README EOF blank line;
correct the dsh-fs package.json description.
2026-07-02 03:12:38 +08:00
|
|
|
{ "path": "./packages/fs/fs-policy" },
|
feat(sandbox): cross-family file sandbox — one policy home, sandboxed fs provider, fs escalation parity
Extend SandboxMode enforcement from bash to the filesystem tools, the sandbox
RFC's deferred cross-family phase.
- dsh-sandbox-policy (new, ctx.sandboxPolicy): the single home for the
deployment default mode + workspaceRoot and the per-session override event,
renamed bash/sandbox-mode -> sandbox/mode and moved here with its fold/setter.
Decouples the bash seam from dsh-session.
- dsh-fs-sandbox (new): SandboxedFileSystem extends LocalFileSystem and fences
write/edit by the per-call mode (read-only denies, workspace-write contains to
the workspace + temp roots via the shared writableRoots, danger passes
through); reads pass through. Structured FS_SANDBOX_DENIED; in-lock parent
re-canonicalization. A policy fence in trusted code, not a kernel boundary.
- dsh-sandbox: the shared escalation kit (writableRoots, the strictly-wider
ladder, denial/hint markers, approveEscalation) both tool families use;
approveEscalation takes a structural approver so dsh-sandbox gains no
approval/agent dependency, and both tools stay duplication-free.
- tool-fs: write/edit advertise sandbox_permissions/justification under a
confining ctx.fs, map FS_SANDBOX_DENIED to the shared [sandbox: ...] marker,
and resolve the same one-approved-wider retry.
- examples/acp-agent: composes sandbox-policy + fs-sandbox, drops the gating
that disabled the fs stack under confined modes.
RFC docs/rfc/implemented/feature/2026-07-14-cross-family-fs-sandbox.md; the old
sandbox RFC's In-process/deferred/FAQ sections updated to shipped fact.
2026-07-14 20:05:57 +08:00
|
|
|
{ "path": "./packages/fs/fs-sandbox" },
|
2026-06-28 17:24:45 +08:00
|
|
|
{ "path": "./packages/fs/tool-fs" },
|
2026-07-09 20:44:32 +08:00
|
|
|
{ "path": "./packages/fs/tool-fs-search" },
|
2026-06-25 09:10:50 +08:00
|
|
|
{ "path": "./packages/compact/compact" },
|
2026-06-25 17:30:42 +08:00
|
|
|
{ "path": "./packages/compact/compact-basic" },
|
2026-07-16 18:51:26 +08:00
|
|
|
{ "path": "./packages/compact/compact-tool-result-prune" },
|
2026-06-26 19:18:46 +08:00
|
|
|
{ "path": "./packages/web/web" },
|
|
|
|
|
{ "path": "./packages/web/web-search-exa" },
|
|
|
|
|
{ "path": "./packages/web/web-search-perplexity" },
|
2026-06-29 15:21:12 +08:00
|
|
|
{ "path": "./packages/web/web-search-deepseek" },
|
2026-06-26 19:18:46 +08:00
|
|
|
{ "path": "./packages/web/web-fetch-local" },
|
|
|
|
|
{ "path": "./packages/web/tool-web" },
|
2026-07-08 19:20:50 +08:00
|
|
|
{ "path": "./packages/spill/spill" },
|
|
|
|
|
{ "path": "./packages/spill/spill-local" },
|
|
|
|
|
{ "path": "./packages/spill/spill-policy" },
|
2026-07-08 10:06:07 +08:00
|
|
|
{ "path": "./packages/timeout/timeout-policy" },
|
2026-06-22 00:51:41 +08:00
|
|
|
{ "path": "./packages/support/invariants" },
|
2026-07-16 17:39:53 +08:00
|
|
|
{ "path": "./packages/support/agent-loop-testkit" },
|
2026-06-22 00:51:41 +08:00
|
|
|
{ "path": "./packages/ui/acp" },
|
2026-07-15 15:57:57 +08:00
|
|
|
{ "path": "./packages/examples/acp-demo" },
|
feat(ui): share the app bins' boot glue in @deepseek-ai/dsh-app-boot
The four near-twin helpers the two published bins carried — loadEnv,
installFailLoud, assertEntriesLoaded, boot — live once in
packages/ui/app-boot, parameterized by the bin's diagnostic prefix and
injectable at their side-effect seams (warn sink, process slice), so
every branch sits under the per-file 100% coverage gate: the unit suite
drives boot() in-process against the real Loader (relative-specifier
configs) through both the settled-tree path and the fiber-less-entry
rejection, and exercises the ENOENT/unloadable .env split, the
Error/non-Error/stackless fail-loud arms, and the disabled-entry
exclusion. resolveConfigPath (snapshot-aware) becomes the single path
resolver for both bins.
Each bin.ts is now a thin self-executing composition plus its
app-specific lifecycle (acp: replay env-skip + stdin-EOF dispose;
stdio: nothing extra), exports nothing, and stays coverage-excluded;
the built-bin smokes still prove both artifacts under plain node in the
node_modules-shaped temp dir (now symlinking ui/app-boot), including
the missing-config non-zero exit.
Implements docs/rfc/implemented/simplification/2026-07-04-share-app-bin-boot-glue.md
(moved from proposed/ and amended); the extract-example-app-packages
RFC's bin-ownership facts are amended in the same change.
2026-07-04 16:43:06 +08:00
|
|
|
{ "path": "./packages/ui/app-boot" },
|
2026-07-11 14:08:12 +08:00
|
|
|
{ "path": "./packages/ui/jsonrpc" },
|
2026-07-15 15:57:57 +08:00
|
|
|
{ "path": "./packages/examples/jsonrpc-demo" },
|
2026-07-17 12:01:37 +08:00
|
|
|
{ "path": "./packages/ui/tui" },
|
2026-07-20 19:26:04 +08:00
|
|
|
{ "path": "./packages/examples/tui-demo" },
|
2026-06-22 14:35:35 +08:00
|
|
|
{ "path": "./packages/support/llm-replay" },
|
feat(acp-snapshot): extract the ACP snapshot suite into a support package
The snapshot tier's machinery leaves examples/acp-agent/tests for
packages/support/acp-snapshot (@deepseek-ai/dsh-acp-snapshot), where the
coverage gate measures it and a second example can consume it instead of
forking it: harness.ts (runScenario, parameterized by an AgentUnderTest
{binScript, configPath, tsconfigPath} instead of module constants),
normalize.ts (moved verbatim), and suite.ts (defineAcpSnapshotSuite — the
per-scenario golden/log compares, record write-back, per-suite header pin
with its uniformity guard, and the fixture guard block, lifted from
acp.snapshot.ts). The example file collapses to its scenario table plus
one factory call; env reading (DSH_SNAPSHOT) stays at that edge.
The exactly-one-pin meta-test generalizes from the hardcoded text-turn
name to "exactly one per suite" — which scenario pins is the scenario
table's reviewable choice (per-suite pinning per the proposal RFC).
Extraction parity: pnpm run test:snapshot is 36 passed + fs-policy-reject
failing BEFORE AND AFTER (BSD-sed environment failure, reproduced at the
base commit in a clean worktree — the recorded golden's sed -i syntax is
GNU-only), with zero byte changes under examples/acp-agent/tests/snapshots/.
Coverage for the new src files lands in the next commit.
2026-07-08 01:44:20 +08:00
|
|
|
{ "path": "./packages/support/acp-snapshot" },
|
2026-07-14 05:00:54 +08:00
|
|
|
{ "path": "./packages/support/loader-smoke" },
|
2026-06-22 14:35:35 +08:00
|
|
|
{ "path": "./packages/subagent/subagent" },
|
2026-06-22 14:43:51 +08:00
|
|
|
{ "path": "./packages/subagent/tool-subagent" },
|
|
|
|
|
{ "path": "./packages/subagent/subagent-inprocess" },
|
rename: @deepseek-ai/dsh-subagent-process -> @deepseek-ai/dsh-subagent-subprocess
The extracted library's name sat one edit away from @deepseek-ai/dsh-subagent-inprocess
(process/inprocess), inviting a typo'd import to silently resolve to the wrong
package. subagent-subprocess also reads as the deliberate counterpart to
subagent-inprocess (in-process vs. subprocess), matching how the two shared
drivers actually differ.
Package directory, npm name, module doc, JSDoc module tags, test-file name and
its temp-dir prefixes, the subagent-acp import and its Config/tsconfig/package.json
references, root tsconfig.json/tsconfig.build.json/knip.json entries, and the
packages/subagent group README all renamed together; regenerated
docs/module-graph.md and docs/config-catalog.md. Pure rename — no behavior,
export, or Config shape changed.
2026-07-09 13:42:03 +08:00
|
|
|
{ "path": "./packages/subagent/subagent-subprocess" },
|
2026-06-22 14:43:51 +08:00
|
|
|
{ "path": "./packages/subagent/subagent-spawn" },
|
2026-06-22 14:58:03 +08:00
|
|
|
{ "path": "./packages/subagent/subagent-fork" },
|
feat(tool-todo): add the model-facing todo_write tool
Add @deepseek-ai/dsh-tool-todo (a new packages/todo/ group): a model-facing
todo_write(todos: [{content, status}]) tool with whole-list-replace semantics.
Each call appends the full list as a todo/write event to the calling agent's
session log; the current list is the most recent such event (last-write-wins).
Single-owner — a non-agent caller is rejected. Beyond the schema's
type/required/enum checks, execute rejects empty/duplicate content and more than
one in_progress task, narrowing the loosely-typed args into a real TodoItem[].
Both UIs render off the existing session/event: the stdio UI prints a glyphed
checklist; the ACP bridge maps the list to a `plan` sessionUpdate (todosToPlan
synthesizes the priority ACP requires; status maps 1:1). Wired into the
coding-agent, acp-agent, and snapshot example configs with a system-prompt nudge.
Tests: unit (schema, validation, append/replace, no-agent rejection, presentCall,
HMR-safety, Loader export-shape guard), full-loop integration through the agent
loop, the ACP todosToPlan mapping + stream-update arm, the stdio render arm, and
a session/load replay that re-emits the plan. New-group TS wiring added to
tsconfig.base/json/build. RFC + a doc-inventory sweep (architecture, packages
README, AGENTS layout, cookbook group list, example READMEs) ship with it.
The todo-plan ACP snapshot scenario is recorded separately (needs an API key).
2026-06-29 10:30:52 +08:00
|
|
|
{ "path": "./packages/subagent/subagent-acp" },
|
feat(tasks): background task runtime, generic task_* control tools, bash/subagent producers
One shared ctx.tasks registry (branded <kind>-N ids, owner-fenced
read/kill/wait/list, attachSurface misconfiguration fence, reported-flag
notice dedup, atomic register) + dsh-tool-tasks (task_output/task_list/
task_kill, completion-notice injection, background prompt habit).
Producers opt in via their own enableRunInBackground config: bash
(stream kind; seam slimmed to resolve/run/start returning a BashProcess
handle, bash_output/bash_kill deleted) and subagent (final-output kind;
done settles after run.dispose()). Owner disposal drains tasks through
the new awaited ctx.agents.onCleanup seam in the loop's disposal chain.
Both RFCs moved to implemented/; docs, catalogs, snapshots re-pinned.
2026-07-09 21:22:54 +08:00
|
|
|
{ "path": "./packages/tasks/tasks" },
|
|
|
|
|
{ "path": "./packages/tasks/tool-tasks" },
|
workflow: dynamic workflows — script-driven multi-agent orchestration
A new capability family at packages/workflow/ in the bash seam shape,
modeled on Claude Code's dynamic workflows: the model writes a JavaScript
orchestration script (export const meta = {...} + plain-JS body), a runtime
executes it, and the script — not the conversation — holds the loop, the
branching, and the intermediate results.
- dsh-workflow (ctx.workflows): abstract WorkflowService + run vocabulary
(WorkflowRun whose result NEVER rejects) + observe-only workflow/* events
carrying data snapshots (id + meta, never the live run), per-listener
contained like subagent/*.
- dsh-workflow-vm: in-process node:vm engine. Meta extraction via a
string/comment-aware scanner (template interpolation rejected; literal
evaluated alone in an empty timed context; statement blanked line-
preservingly so stacks keep script line numbers). Hooks: agent(prompt,
{label, phase, schema, model}) over ctx.subagents, parallel(), pipeline()
(no cross-stage barrier), phase(), log(), args. Fatal-vs-null discipline:
hook misuse (unknown/deferred options, bad arguments, unsupported
schemas, tripped caps, seam start failures, cancellation) throws fatal
WorkflowErrors the combinators RE-THROW — never dissolved into the
per-item null reserved for child failures. Realm boundary: inbound values
materialized by descriptor walks that never invoke accessors (defineProperty
copies, __proto__-safe); outbound values rebuilt in-realm via the
context's own JSON.parse. Determinism bans (Date.now/Math.random/argless
new Date) kept so future resume support cannot break scripts. Caps and
timeouts are validated Config. Every hook promise carries a no-op
rejection consumer (app-boot exits on unhandled rejections).
- dsh-tool-workflow: the model-facing workflow tool, synchronous like
dsh-tool-subagent (start → await → try/finally dispose; abort bridged;
non-completed → isError). Generic render card titled by a textual
meta.name sniff. The tool description carries the authoring contract.
Wired into examples/{coding-agent,acp-agent} with explicit-ask-only
guidance. Coverage at every tier: unit (meta scanner, materializer incl.
counting-getter and __proto__ regressions, combinator semantics,
concurrency ceiling, caps, cancellation, no-unhandled-rejection abandon),
integration over the real spawn stack, with-key e2e (real two-phase run +
the tool through the registry pipeline), and a recorded ACP snapshot
scenario (workflow-run, 1 child session). RFC:
docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.md (deferred
work explicitly listed). AGENTS.md budget 1575 → 1590 for the new group's
layout line.
2026-07-05 13:29:35 +08:00
|
|
|
{ "path": "./packages/workflow/workflow" },
|
2026-07-09 19:06:55 +08:00
|
|
|
{ "path": "./packages/workflow/workflow-workerthread" },
|
workflow: dynamic workflows — script-driven multi-agent orchestration
A new capability family at packages/workflow/ in the bash seam shape,
modeled on Claude Code's dynamic workflows: the model writes a JavaScript
orchestration script (export const meta = {...} + plain-JS body), a runtime
executes it, and the script — not the conversation — holds the loop, the
branching, and the intermediate results.
- dsh-workflow (ctx.workflows): abstract WorkflowService + run vocabulary
(WorkflowRun whose result NEVER rejects) + observe-only workflow/* events
carrying data snapshots (id + meta, never the live run), per-listener
contained like subagent/*.
- dsh-workflow-vm: in-process node:vm engine. Meta extraction via a
string/comment-aware scanner (template interpolation rejected; literal
evaluated alone in an empty timed context; statement blanked line-
preservingly so stacks keep script line numbers). Hooks: agent(prompt,
{label, phase, schema, model}) over ctx.subagents, parallel(), pipeline()
(no cross-stage barrier), phase(), log(), args. Fatal-vs-null discipline:
hook misuse (unknown/deferred options, bad arguments, unsupported
schemas, tripped caps, seam start failures, cancellation) throws fatal
WorkflowErrors the combinators RE-THROW — never dissolved into the
per-item null reserved for child failures. Realm boundary: inbound values
materialized by descriptor walks that never invoke accessors (defineProperty
copies, __proto__-safe); outbound values rebuilt in-realm via the
context's own JSON.parse. Determinism bans (Date.now/Math.random/argless
new Date) kept so future resume support cannot break scripts. Caps and
timeouts are validated Config. Every hook promise carries a no-op
rejection consumer (app-boot exits on unhandled rejections).
- dsh-tool-workflow: the model-facing workflow tool, synchronous like
dsh-tool-subagent (start → await → try/finally dispose; abort bridged;
non-completed → isError). Generic render card titled by a textual
meta.name sniff. The tool description carries the authoring contract.
Wired into examples/{coding-agent,acp-agent} with explicit-ask-only
guidance. Coverage at every tier: unit (meta scanner, materializer incl.
counting-getter and __proto__ regressions, combinator semantics,
concurrency ceiling, caps, cancellation, no-unhandled-rejection abandon),
integration over the real spawn stack, with-key e2e (real two-phase run +
the tool through the registry pipeline), and a recorded ACP snapshot
scenario (workflow-run, 1 child session). RFC:
docs/rfc/implemented/feature/2026-07-05-dynamic-workflows.md (deferred
work explicitly listed). AGENTS.md budget 1575 → 1590 for the new group's
layout line.
2026-07-05 13:29:35 +08:00
|
|
|
{ "path": "./packages/workflow/tool-workflow" },
|
feat(hooks): dsh-hook-protocol — shared Claude Code / Codex hook wire-protocol core
The two hook bridges (dsh-hooks-claude, dsh-hooks-codex) would otherwise duplicate
the bulk of the protocol — Codex deliberately reimplements a SUBSET of the Claude
Code protocol (same hooks.json shape, exit-code/stdout contract, command-hook
model). This library holds the genuinely-identical primitives; each bridge owns
only what differs (per-event stdin payload, env/substitution, decision mapping).
New packages/hooks/ group; hook-protocol is a LIBRARY (no plugin, registers/injects
nothing):
- matcher: matchesMatcher(pattern, query, mode) — the one dialect axis collapsed to
a mode param (claude = literal-or-regex with pipe alternation; codex = always
unanchored regex). Match-all on absent/''/'*'; invalid regex matches nothing.
- codec: parseHookOutput(exit, stdout, stderr) → dialect-neutral HookOutput. Exit 0
→ lenient JSON; exit 2 → blocking error (stderr = reason, surfaced as
decision:'block'); other → non-blocking. Parses the CC superset
(continue/stopReason/decision/hookSpecificOutput.{permissionDecision,
additionalContext,updatedInput}/systemMessage); permissionDecision overrides the
legacy top-level decision.
- runner: runHook(bash, hook, opts, now) — runs a command hook via ctx.bash (stdin
payload + trusted-plugin env), honors timeoutSec, never throws (executor reject →
non-blocking-error HookOutput). Injected clock for testable durations.
- merge: mergeHookOutputs — most-restrictive fold (deny>ask>allow, sticky stop,
block reasons joined, context/system-messages accumulated).
- hook/* session events (declaration-merged into SessionEventMap, log-only like
compact/*) + appendHookInvoked/appendHookResult helpers.
updatedInput is parsed but NOT honored (deferred pre-tool-input-rewrite RFC); a
bridge logs+warns. 47 unit tests at per-file 100% (matcher per-mode, codec per
exit-code/field, runner plumbing w/ stub executor, merge precedence, hook/*
helpers). RFC: implemented/feature/2026-06-30-hook-protocol-lib.md.
2026-07-01 00:38:06 +08:00
|
|
|
{ "path": "./packages/todo/tool-todo" },
|
2026-07-08 14:24:20 +08:00
|
|
|
{ "path": "./packages/guard/repeat-tool-guard" },
|
feat(cordis): @deepseek-ai/dsh-tool-cordis — inspect/mount/unmount over the live runtime
New top-level packages/cordis/ group with the self-referential toolset:
cordis_inspect (services / plugin tree / tools / dynamic mounts / api / events,
the api section intersecting the generated catalog with the live service store),
cordis_mount (model-written code evaluated in a node:vm sandbox, mounted under
one cordis-dynamic group fiber as dyn-<n>), cordis_unmount (awaited disposal to
quiescence). Boundary mechanisms: dual-realm instanceof, JSON realm
normalization of dynamic tool results, marker-guarded registration, SchemaSpec
teaching errors, parse failures surfaced with the offending line + caret and a
line-scoped TypeScript hint, and the unmount-first recipe on tool-name
collisions. Config: vmTimeoutMs (schemastery, default 5000). Design record:
docs/rfc/implemented/feature/2026-07-08-self-referential-cordis-toolset.md.
The tool-catalog boot manifest, its regenerated output, and the pinned
tool-name list land here rather than with the other repo registration: the
completeness guard globs packages/*/tool-* and fails the generator (and the
core/tools spec) the moment the package directory exists.
2026-07-08 11:45:46 +08:00
|
|
|
{ "path": "./packages/cordis/tool-cordis" },
|
feat(hooks): dsh-hooks-claude + dsh-hooks-codex bridges (hooks stack PR-F)
The two bridge plugins that run a user's existing Claude Code / Codex hook
config on the harness's typed interception seams, built on the shared
dsh-hook-protocol library. A bridge is a faithfulness adapter, not a power
tool: anything it does a native cordis plugin does more powerfully — the
bridge exists only to run UNMODIFIED external hooks.
- dsh-hooks-claude: CC dialect. Seven hook points (SessionStart,
UserPromptSubmit, PreToolUse, PostToolUse, Stop, SubagentStart,
SubagentStop), CC per-event stdin payloads, env + ${CLAUDE_PLUGIN_ROOT}/
${CLAUDE_PROJECT_DIR} substitution, literal-or-regex matcher.
- dsh-hooks-codex: Codex dialect — a deliberate subset. Five hook points,
always-regex matcher, snake_case payloads (turn_id/model, no trailing
newline), no env/substitution, block-only decisions.
Both map the neutral merged outcome onto the seam's typed Decision and stamp
an explicit {kind:'plugin'} source on injected context (so it is never
mislabeled as a user prompt). Config parse-failure is contained; only command
hooks run. updatedInput is logged+warned (input rewrite deferred); the Stop
loop-guard is deferred (TODO).
Tests: per-file 100% — config-parse unit branches + per-seam mappings
end-to-end through the REAL loop + REAL bash + REAL shell scripts (scripted
mock model only) + a real-Loader export-shape guard. A keyless ACP snapshot
scenario (hook-prompt-block) proves a UserPromptSubmit hook blocks a prompt
end-to-end (rejected turn -> ACP cancelled, hook/* events in the log); a
with-key e2e (hooks.e2e.ts) proves a PreToolUse hook blocks real bash
(verified on disk). The snapshot normalizer now scrubs hook/result.durationMs.
RFC: docs/rfc/implemented/feature/2026-06-30-hook-bridges.md
2026-07-01 04:22:00 +08:00
|
|
|
{ "path": "./packages/hooks/hook-protocol" },
|
|
|
|
|
{ "path": "./packages/hooks/hooks-claude" },
|
2026-07-07 23:21:54 +08:00
|
|
|
{ "path": "./packages/hooks/hooks-codex" },
|
2026-07-15 18:17:38 +08:00
|
|
|
{ "path": "./packages/mcp/mcp-client" },
|
|
|
|
|
{ "path": "./packages/sdk/helper" },
|
|
|
|
|
{ "path": "./packages/sdk/scripts" },
|
2026-07-17 13:20:34 +08:00
|
|
|
{ "path": "./packages/sdk/create-sdk" },
|
2026-07-17 13:16:51 +08:00
|
|
|
{ "path": "./packages/sdk/telemetry" }
|
2026-06-17 23:41:18 +08:00
|
|
|
]
|
2026-06-11 10:52:45 +08:00
|
|
|
}
|