Commit Graph

46 Commits

Author SHA1 Message Date
Turtle
fac6c35e9a Trim redundant source comments 2026-07-25 13:02:37 +08:00
Tianyi Cui
53615c91e7 Merge master into worktree-windows-runtime 2026-07-21 23:39:14 +08:00
Tianyi Cui
78eb93f7e6 Merge branch 'master' into worktree-windows-runtime 2026-07-20 20:39:13 +08:00
Tianyi Cui
1145ee5fc3 fix(invariants): assert runtime relationships, not API shapes 2026-07-20 19:34:19 +08:00
Tianyi Cui
684fcf3357 Merge branch 'codex/invariant-package-registration-gate' into codex/package-invariant-checks
# Conflicts:
#	.agents/notes/implemented/architecture/2026-07-19-package-invariant-runtime-contracts.i18n.yaml
#	.agents/notes/implemented/architecture/2026-07-19-package-invariant-runtime-contracts.md
#	.agents/notes/implemented/architecture/2026-07-19-package-invariant-runtime-contracts.zh.md
#	.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.i18n.yaml
#	docs/rfc/INDEX.md
#	packages/AGENTS.md
2026-07-20 00:54:28 +08:00
Tianyi Cui
941b0411d8 feat(invariants): implement package runtime checks 2026-07-20 00:38:37 +08:00
Tianyi Cui
6520f71f94 Merge remote-tracking branch 'origin/codex/invariant-service-seam' into codex/invariant-package-registration-gate
# Conflicts:
#	.agents/notes/implemented/architecture/2026-07-19-package-owned-invariant-service.i18n.yaml
#	docs/core-data-structures/session.md
#	docs/module-graph.md
#	package.json
#	packages/sdk/scripts/tsconfig.json
2026-07-20 00:35:06 +08:00
Tianyi Cui
e8eddc7ef8 Rename RFCs to Agent Notes 2026-07-19 22:52:03 +08:00
Tianyi Cui
433670a754 feat(invariants): require package-owned companions 2026-07-19 22:13:50 +08:00
Tianyi Cui
2b673bd68d fix(fs): preserve Windows DACLs across atomic replacement
Copy an existing target's DACL onto the empty staging file before any content is written, then publish with ReplaceFileW so Windows replacement keeps the target security descriptor instead of inheriting the broader parent policy.

Keep new-file inheritance and POSIX mode behavior unchanged, retain the already-protected temp when a concurrently removed target requires rename fallback, and translate native errors into Node-style codes for the filesystem error boundary.

Add host-independent Win32 binding coverage, native Windows descriptor assertions, package documentation, and a bilingual implemented RFC that supersedes the earlier inheritance-only replacement claim.
2026-07-19 12:38:18 +08:00
imccyu
7d28b611b2 test(windows): align platform coverage ignores 2026-07-18 15:55:37 +08:00
imccyu
588f4d948d test(windows): mark platform-only coverage branches 2026-07-18 12:40:13 +08:00
Huanqi Cao
e47ae0643c fs-local: POSIX-only mode-bit assertions, document Windows DACL-inheritance semantics
Windows drives only the read-only attribute through chmod and reports
synthetic stat mode bits, so writeFileAtomic's mode arguments are inert
there; write-in-progress privacy comes from the staging dir (created in
the target's parent) inheriting the destination directory's DACL.
Production is deliberately unchanged -- the chmod calls are benign
no-ops and platform-guarding them out buys nothing. Tests guard the
mode-bit expects to POSIX; there is no Windows ACL assertion because an
ACL check would pin OS inheritance plus the machine's %TEMP% ACL, not
this package. Decision and rejected alternatives (explicit DACLs,
Get-Acl/icacls test verification) recorded in the new RFC.
2026-07-18 12:40:12 +08:00
Huanqi Cao
715aa7372a Restore ENOTDIR semantic distinction in resolveLocalTarget on Windows 2026-07-18 12:40:12 +08:00
Yichen Jiang
ca14bcc34b Merge remote-tracking branch 'origin/master' into codex/project-instruction-files
# Conflicts:
#	AGENTS.md
#	docs/config-catalog.md
#	docs/cordis-catalog/services.md
#	docs/event-producer-consumer.md
#	packages/fs/fs-local/src/index.ts
#	pnpm-lock.yaml
2026-07-15 13:07:11 +08:00
Yichen Jiang
ee111fd978 Merge remote-tracking branch 'origin/master' into codex/project-instruction-files
# Conflicts:
#	AGENTS.md
#	docs/config-catalog.md
#	docs/cordis-catalog/events.md
#	docs/cordis-catalog/services.md
#	docs/core-data-structures/core.md
#	docs/event-producer-consumer.md
#	docs/persistence-catalog.md
#	docs/rfc/implemented/architecture/2026-07-05-reconstructable-requests.md
#	docs/rfc/implemented/feature/2026-06-15-code-mode.md
#	docs/rfc/implemented/feature/2026-06-30-hook-bridges.md
#	docs/rfc/implemented/feature/2026-06-30-interception-seams.md
#	docs/rfc/implemented/feature/2026-07-08-repeat-tool-guard.md
#	docs/rfc/proposed/simplification/2026-07-04-prune-dead-core-spine-surface.md
#	examples/AGENTS.md
#	examples/acp-agent/cordis.yml
#	examples/acp-agent/tests/acp.snapshot.ts
#	examples/echo-agent/cordis.yml
#	examples/sandbox-acp-agent/cordis.yml
#	packages/cordis/tool-cordis/src/api-catalog.ts
#	packages/core/agent-core/README.md
#	packages/core/agent-core/src/index.ts
#	packages/core/agent-loop/README.md
#	packages/core/agent-loop/src/loop.ts
#	packages/core/agent-loop/tests/interception.spec.ts
#	packages/core/agent/src/types.ts
#	packages/core/tools/README.md
#	packages/core/tools/src/code-mode.ts
#	packages/core/tools/src/index.ts
#	packages/fs/fs-local/src/index.ts
#	packages/fs/fs/README.md
#	packages/fs/fs/src/index.ts
#	packages/guard/repeat-tool-guard/README.md
#	packages/guard/repeat-tool-guard/src/index.ts
#	packages/hooks/hooks-claude/src/index.ts
#	packages/hooks/hooks-codex/src/index.ts
#	packages/ui/acp-agent/src/index.ts
2026-07-14 19:50:25 +08:00
Tianyi Cui
89aedb5ea6 Merge remote-tracking branch 'origin/master' into codex/simp-hide-fs-internals
# Conflicts:
#	docs/config-catalog.md
2026-07-14 17:33:52 +08:00
Tianyi Cui
f9db1a6a08 refactor: hide filesystem implementation helpers 2026-07-14 03:30:23 +08:00
Tianyi Cui
148046b9c8 docs: rebalance prose cleanup and add trimming skill 2026-07-13 23:27:00 +08:00
Yichen Jiang
c2f2740a3e Fix workspace instruction lifecycle edge cases 2026-07-13 20:39:32 +08:00
Yichen Jiang
a0e917ffe3 Optimize workspace instruction change detection 2026-07-13 17:01:42 +08:00
Yichen Jiang
aa62b5109a Fix workspace context review findings 2026-07-13 16:31:03 +08:00
Tianyi Cui
e9a54f0e71 fix(workspace-context): require explicit byte budgets 2026-07-12 12:09:35 +08:00
Tianyi Cui
75838e10b5 docs: trim generated prose 2026-07-12 03:36:43 +08:00
Yichen Jiang
3fe196a751 Adapt workspace context to session prefixes 2026-07-10 14:32:44 +08:00
Yichen Jiang
7b54768ee7 Merge remote-tracking branch 'origin/master' into codex/project-instruction-files
# Conflicts:
#	AGENTS.md
#	docs/architecture.md
#	docs/event-producer-consumer.md
#	docs/module-graph.md
#	docs/rfc/INDEX.md
#	packages/bash/bash-local/tests/executor.spec.ts
#	packages/bash/bash-local/tests/run.spec.ts
#	packages/core/agent-core/src/index.ts
#	packages/core/agent-core/tests/agent-core.spec.ts
#	packages/fs/fs-local/src/fsio.ts
#	packages/ui/acp-agent/package.json
#	packages/ui/acp-agent/src/index.ts
#	packages/ui/acp-agent/tsconfig.json
#	packages/ui/stdio-agent/package.json
#	packages/ui/stdio-agent/tsconfig.json
#	packages/util/README.md
#	pnpm-lock.yaml
#	tsconfig.build.json
#	tsconfig.json
2026-07-09 23:04:41 +08:00
Tianyi Cui
cd9737d569 Gate JSDoc completeness on every package export
New doc-sync gate verify-export-jsdoc walks every module-level exported
name under packages/*/*/src and requires description prose everywhere,
plus @param per parameter and @returns on non-void annotated returns for
function-like exports, public class methods, properties, and accessors.
The parsing + check helpers move out of gen-cordis-catalog.ts into a
shared scripts/jsdoc.ts so 'documented' means one thing on both gated
surfaces.

Deliberate exemptions (documented in the RFC): heritage-declared class
members (the seam declaration is the doc's one home — the one checker
query in an otherwise pure-AST walk), cordis plugin-protocol slots
(name/inject/reusable/Config/apply, top-level and static), constructors,
overload implementations, declare-module augmentation bodies, and
re-export statements (checked at the defining module).

The 203 under-documented exports the gate found at adoption are filled
in this change, so the gate lands green; generated catalogs/graphs are
regenerated for the shifted line pointers.

RFC: docs/rfc/implemented/process/2026-07-06-export-surface-jsdoc-gate.md
2026-07-06 22:09:30 +08:00
Yichen Jiang
901315d8ab Preserve instruction symlink guard through fs seam 2026-07-06 13:55:20 +08:00
Tianyi Cui
e64623ebfd refactor(fs): prune write-only fields and the dead routing knob from the seam
The fs seam split left four pieces of pre-split surface populated on
every call and read by nobody:

- STREAM_MIN_SIZE + FsIoInternals.streamMinSize in dsh-fs-local: the
  backend has no read routing (readWholeText/streamWholeText are
  separate primitives the caller picks), and the real 10 MiB routing
  constant lives in dsh-tool-fs's read tool. Delete the dead mirror and
  the knob whose JSDoc claimed an override that did not exist; the
  remaining FsIoInternals knobs stay (the atomic-write tests use them).
- FsTarget.inputPath: a "diagnostics only" field every backend and test
  fake had to fabricate, with zero production readers (policy and error
  messages use targetKey/displayPath). listDir gave children the bare
  entry name, which was nobody's input.
- FsEditOutcome.replacements/.replaceAll: replacements had no reader
  (the single-match policy is enforced by the FS_AMBIGUOUS_EDIT /
  FS_EDIT_NOT_FOUND throws, whose message keeps the internal count);
  replaceAll only echoed the replace_all argument back to
  formatEditOutput, which now takes it from the parsed args. The
  outcome shrinks to { version, before, after }, parallel to
  FsWriteOutcome's backend-discovered fields. Emitted text is unchanged
  for both branches (no snapshot churn).
- FileReadOutcome.limit/.version: formatReadOutput renders
  offset/lines/totalLines/truncatedByBytes only, and the fs/observed
  emit uses info.version directly.

Backends shed four fabrication obligations and gain none. Doc pastes
(core-data-structures/filesystem.md), the dsh-fs README resolve row,
and the test fakes shrink with the types. RFC moved to
implemented/simplification and amended to the shipped shape
(FsEditSpec -> FsEditRequest name fix; manifest rows needed no change).
2026-07-04 15:37:43 +08:00
Tianyi Cui
bf1966326e Merge remote-tracking branch 'origin/master' into codex/fs-directory-listing
# Conflicts:
#	docs/rfc/README.md
#	packages/fs/fs-local/src/index.ts
2026-07-04 00:56:17 +08:00
Tianyi Cui
497ea15bdf fix(acp): relativize the completed diff card title
The result-time diff card sent view.title raw, so a completed edit/write
of an absolute in-workspace path flipped the card header back from the
relativized `Edit src/b.ts` to the absolute path — the pending card
relativizes, the result did not, and tool_call_update.title replaces the
header. Apply displayTitle to the result diff arm using the diff path,
mirroring the call-side card. Regression test proven red on the unfixed
arm.

Also record the overwrite diff-basis pre-read as a bounded follow-up
(TODO(overwrite-diff-bound) + RFC non-goal): overwriting a large file
reads the whole prior text into memory for a UI-only diff.
2026-07-03 23:14:22 +08:00
Tianyi Cui
5dfe09959d fix(fs): keep listDir child keys under stable parent 2026-07-03 22:02:16 +08:00
Tianyi Cui
e07886599c docs: finish the whole-file-diff sweep across comments and RFCs
Codex's stale-prose pass found seven more spots still describing the
result diff as ALWAYS an applied contextual hunk, or a create/binary
overwrite as rendering "only the call-time card": the DiffCallView JSDoc
and the acp bridge diff-arm comment, the FsWriteOutcome.before and
readTextForDiff JSDoc, and three RFC lines. All now say: the result diff
is the applied change — a contextual hunk when there is a before-image,
else a whole-file diff (create / undiffable binary) — and a successful
mutation always returns the result diff so the model-facing text can't
clobber it. Regenerate the cordis catalog (source line shift).
2026-07-03 21:50:52 +08:00
Tianyi Cui
d753660d66 docs(fs-local): a null before-image still renders a whole-file diff card
The writeText comment still said a null `before` (a create or an
undiffable binary file) means "a consumer renders no result-time diff,
only the call-time whole-file card." That is stale since write's
presentResult renders a whole-file diff for a null before-image. Correct
it: a null `before` gives no contextual-hunk basis, so the consumer falls
back to a whole-file diff — the tool still renders a result diff card, not
the raw result text.
2026-07-03 21:38:42 +08:00
Tianyi Cui
dee2dee402 fix(tool-fs): CRLF-safe write diff, opaque meta, doc sync
Address the applied-hunk-diffs review:

- CRLF write overwrite emitted bogus every-line-changed hunks: write's
  `before` was LF-normalized but `after` kept the raw model content, so a
  CRLF rewrite of an LF file diffed every line. Normalize write's `after`
  to LF so both sides share the diff basis (edit already did). Regression
  test proves it fails on the raw-after path.
- The tool-private `meta` payload is now typed `unknown` (opaque) at every
  seam instead of `JsonValue`. This drops the `dsh-tools -> dsh-session`
  package edge that existed only to name the type, and removes the
  `FileDiff` index signature that had been widening the type solely for
  JsonValue-assignability. Serializability is still enforced at runtime by
  `Session.append`'s isJsonValue check, which was always the real guard.
- Sync the docs the new result/meta surface left stale: ToolResultView's
  diff card + ToolExecutionResult.meta in tools.md/session.md type-equiv
  blocks, the acp/tools READMEs, and the adding-a-tool cookbook; regenerate
  the cordis catalog and module graph.
2026-07-03 18:00:16 +08:00
Tianyi Cui
d8fd3225af feat(tool-fs): result-time applied-hunk diffs for write/edit
fs write/edit now emit a result-time contextual-diff tool_call_update
(the applied hunk with ±3 context lines, one hunk per replace_all site),
matching what claude-agent-acp sends and what makes an editor render the
change in place. The call-time snippet diff stays; the result hunk
supersedes it (ACP content-replace).

Mechanism:
- A persisted tool-private `meta` channel: execute may return
  `{ content, meta }`; `meta` (JsonValue) rides on the tool/result event
  and is handed back to presentResult, so the diff reproduces on replay
  (event-sourced). JsonValue is now exported from dsh-session.
- The backend returns raw before/after text (storage facts) on
  FsWriteOutcome/FsEditOutcome; the tool computes the hunk via the npm
  `diff` package's structuredPatch. A create has no before → no result
  diff; a failed/aborted mutation carries no meta.
- ToolResultView gains a DiffResultView; the bridge's result-side switch
  renders it as {type:'diff'} content blocks.

RFC: docs/rfc/implemented/architecture/2026-07-02-result-time-applied-hunk-diffs.md
(justifies the npm `diff` runtime dep over vendoring and the meta channel);
the render-intent-union RFC's Non-goal is updated to record this shipped.
All fs snapshot goldens re-recorded; edit/overwrite gain the contextual
result diff, create/read/policy-reject unchanged in structure.
2026-07-03 17:12:00 +08:00
Yichen Jiang
6fc2cee837 fix(fs): translate listDir metadata failures 2026-07-03 15:12:40 +08:00
Yichen Jiang
803ed4bd95 feat(fs): add directory listing seam 2026-07-03 14:36:20 +08:00
Tianyi Cui
743eb9ea09 fix(fs): resolve paths against the caller's session cwd
The ACP bridge gives each session its own workspace (SessionHeader.cwd), and
dsh-tool-bash already resolves a bash workdir against it. But ctx.fs.resolve(path)
took no caller context and dsh-fs-local resolved every relative path against a
fixed config.cwd (process.cwd() at plugin load) — so in the ACP demo `write
foo.txt` and `bash cat foo.txt` hit different directories the moment an editor
opens any project other than the server's launch dir.

Thread the session cwd into resolution, mirroring dsh-tool-bash: widen
FileSystem.resolve to resolve(path, opts?: { cwd?: string }); dsh-fs-local bases
a relative path on opts.cwd ?? config.cwd (absolute paths ignore it); the
read/write/edit tools derive it via a shared sessionCwd(exec) helper
(exec.agent?.session.header.cwd). The provider stays free of dsh-agent/dsh-session
— the tool projects exec → cwd and hands over a plain string, per the
explicit-at-seams convention. Backward compatible (the arg is optional).

Tests: fs-local resolve(path,{cwd}) bases relative on the passed cwd / ignores it
for absolute; tool integration writes/reads/edits in a session cwd != config.cwd
and verifies the file on disk (proven to fail on the pre-fix no-cwd path). Fakes
that stood in a bare {session:{}} now carry a header so sessionCwd doesn't throw.
RFC in docs/rfc/implemented/architecture/2026-07-02-fs-per-session-cwd.md.
2026-07-02 18:29:29 +08:00
Tianyi Cui
30c1863755 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
Dudu-0223
90dceea0e4 refactor(fs): make dsh-file-context an event-gate plugin, not a method service
Invert the tool↔policy control flow per the file-context event-gate RFC.
dsh-tool-fs becomes the executor — it reads/writes/edits through ctx.fs
directly, owns read windowing, and dispatches fs/write-expectation /
fs/edit-expectation (single-slot waterfalls) plus a contained fs/observed
emit. dsh-file-context drops its ctx.fileContext service and becomes a pure
event-gate plugin (observed-state + read-before-edit + version-guarded
write/edit, decided on those events). The provider's version guard becomes
optional so ctx.fs alone is a complete unconstrained text-storage seam:
removing the policy plugin gracefully loses the policy instead of breaking
the tool at a service-injection boundary.
2026-06-28 13:49:02 +08:00
Dudu-0223
b802912067 fix: address codex review round 2
Resolve targetKey by realpathing the nearest EXISTING ancestor and re-appending
the missing suffix, so a not-yet-created file under a symlinked ancestor with
missing intermediate dirs gets the same key before and after creation — keeping
observed-state intact across a write→edit cycle. Make the socket-type probe test
skip (not fail) when a sandbox forbids unix-domain sockets.
2026-06-26 17:59:40 +08:00
Dudu-0223
1409e2ed15 fix: address codex review round 1
Translate a mid-read AbortError from readFile into the seam's structured
FsError('FS_ABORTED') in readWholeText and readForEdit (the streaming/write
paths already did), and make the socket-type probe test reject on a listen
error instead of hanging where unix-domain sockets are unavailable.
2026-06-26 17:45:54 +08:00
Dudu-0223
ef37ce3b9d refactor(fs): split filesystem seam into provider ctx.fs + policy ctx.fileContext
Implements the split-the-filesystem-seam RFC. ctx.fs shrinks to a text-storage
provider seam (resolve/stat/readText/streamText/writeText/editText with branded
FsTargetKey/FsVersion and an explicit FsWriteExpectation); the new
dsh-file-context package owns the model-facing policy (read windowing,
observed-state, write/edit freshness) as the concrete ctx.fileContext service.

Authorization is now freshness-based rather than full/partial view: a windowed
read records the file version and authorizes a later edit when the file is
unchanged, removing the dead-end where reading lines 100-150 of a large file
could not edit line 120. editText stays a provider primitive so version guard +
literal match + atomic rewrite remain one critical section, and the stale check
runs before matching so a stale edit reports FS_STALE_VERSION. tool-fs injects
fileContext, never reaching around to ctx.fs (the no-bypass contract).
2026-06-26 17:23:18 +08:00
Dudu-0223
c7a197fb5f fix(fs-local): reject unsafe text observations 2026-06-22 18:51:30 +08:00
Dudu-0223
5e01564afb Add filesystem capability seam and tools 2026-06-22 10:48:41 +08:00