Skip to content

feat(coding-agent): generate the session-cwd surface via fluessig#323

Draft
zmaril wants to merge 1 commit into
napi-fluessig/strip-ansifrom
napi-fluessig/session-cwd
Draft

feat(coding-agent): generate the session-cwd surface via fluessig#323
zmaril wants to merge 1 commit into
napi-fluessig/strip-ansifrom
napi-fluessig/session-cwd

Conversation

@zmaril

@zmaril zmaril commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Swap the hand-written #[napi] session-cwd exports (coding-agent core/session-cwd.ts) to the fluessig-generated path.

Module 12 of the pidgin-napi → fluessig campaign (module 2 of this stacked batch of 3). Stacked on napi-fluessig/strip-ansi (#322).

What changed

  • Author 3 ops + the SessionCwdIssueJs DTO in schema/api.json.
  • Add the 3 core_impl delegations (DTO conversions + SessionCwdSource adapter) reaching the same pidgin_coding::core::session_cwd port the hand-written exports called.
  • Regenerate src/generated.rs; delete src/session_cwd.rs and drop pub mod session_cwd;.

First DTO-both-directions swap

SessionCwdIssueJs is a fluessig model used as a nullable return (getMissingSessionCwdIssue -> SessionCwdIssueJs | null), a by-value param (both formatters take issue: SessionCwdIssueJs), and carries an optional field (sessionFile?: string). fluessig lowers Option<Model> return, Model param, and the nullable model field (Option<String>) with no gap.

Gates

  • Byte-diff vs a pre-swap build of the base: the SessionCwdIssueJs interface (sessionFile?: string) and all three function JSDoc+signature blocks, their .js module.exports lines, and nativeBinding destructure entries are byte-identical (only file position moves into the generated cluster).
  • cargo build -p pidgin-napi, cargo fmt --all --check, cargo clippy -p pidgin-napi --all-targets -- -D warnings clean; codespell 0.
  • straitjacket v0.2.3: 0 errors.
  • Oracle slice coding-agent/test/session-cwd.test.ts: 3/3 pass against the locally-built generated addon.

🤖 Generated with Claude Code

https://claude.ai/code/session_017xL2W7dkhPsTSRuXQNCDeY


Generated by Claude Code

Swap the hand-written `#[napi]` session-cwd exports (coding-agent
core/session-cwd.ts: `getMissingSessionCwdIssue`, `formatMissingSessionCwdError`,
`formatMissingSessionCwdPrompt`, plus the `SessionCwdIssueJs` DTO) to the
fluessig-generated path: author the ops + DTO in schema/api.json, add the three
`core_impl` delegations (with the DTO conversions and the `SessionCwdSource`
adapter) to core_impl.rs, regenerate src/generated.rs, and delete the
hand-written src/session_cwd.rs module (dropping `pub mod session_cwd;`).

This is the first swap to exercise a DTO across the boundary in BOTH directions:
`SessionCwdIssueJs` is a fluessig `model` used as a nullable RETURN
(`getMissingSessionCwdIssue -> SessionCwdIssueJs | null`) and as a by-value PARAM
(the two formatters take `issue: SessionCwdIssueJs`), and it carries an optional
field (`sessionFile?: string`). fluessig lowers all three — `Option<Model>`
return, `Model` param, and the nullable model field (`Option<String>`) — with no
gap. The `core_impl` methods reach the SAME `pidgin_coding::core::session_cwd`
port the hand-written exports called (the empty-cwd guard + `existsSync` ->
`Path::exists` probe + both format strings), so JS-visible behavior is unchanged;
pi's `MissingSessionCwdError` class identity stays in the TS shim.

Verified: each swapped symbol's generated `.d.ts` block (the `SessionCwdIssueJs`
interface with `sessionFile?: string`, and all three function JSDoc+signature
blocks), its `.js` `module.exports` line, and its nativeBinding destructure entry
are byte-identical to a pre-swap build of the base (only file position moves into
the generated cluster). cargo build/fmt/clippy clean; codespell 0; straitjacket 0
errors; the session-cwd oracle slice (coding-agent/test/session-cwd.test.ts, 3
tests) passes 3/3 against the locally-built generated addon.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017xL2W7dkhPsTSRuXQNCDeY
@github-actions

Copy link
Copy Markdown

Conformance smoke: agent + ai + tui

  • pi_sha: 3da591ab74ab9ab407e72ed882600b2c851fae21
  • manifest_native_modules: 45

Headline is rust-backed: passing cases in files whose module-under-test is a native (Rust addon) module. Raw all-pass is shown secondary — it is inflated by unflipped TypeScript that passes without touching any Rust.

Package rust-backed Native modules raw pass (secondary) Failing Skipped
agent 55/180 (30.6%) 5 180/180 0 0
ai 74/1293 (5.7%) 8 553/1293 3 737
tui 375/678 (55.3%) 14 678/678 0 0
smoke total 504/2151 (23.4%) 27 1411/2151 3 737

agent: 55/180 (30.6%) · ai: 74/1293 (5.7%) · tui: 375/678 (55.3%)

rust-backed = passing / total tests run, per the manifest's per-native-row tests lists. The Native modules column counts modules served by the Rust addon. This is the agent+ai+tui smoke subset; the full baseline lives in committed conformance.json.

Attribution

A pi test file is rust-backed iff the module it primarily exercises — its module-under-test — is status=native in conformance/manifest.json. A package's rust-backed count is the passing cases in its rust-backed files. Transitive or infrastructure use does not count (e.g. ~30 ai files construct the native faux provider but test other things — only faux-provider.test.ts, whose subject is faux, counts). A file that substantially tests both a native and an original module is excluded rather than counted, so the number under-reports rather than over-claims.

Per-file decisions (from each native manifest row's tests list):

Native module Test file Decision
ai/api/anthropic-messages.ts test/anthropic-sse-parsing.test.ts counted
ai/providers/faux.ts test/faux-provider.test.ts counted
coding-agent/utils/ansi.ts test/ansi-utils.test.ts counted
coding-agent/utils/changelog.ts test/changelog.test.ts counted
coding-agent/utils/git.ts test/git-ssh-url.test.ts counted
coding-agent/core/tools/path-utils.ts test/path-utils.test.ts counted
tui/keys.ts test/keys.test.ts counted
tui/utils.ts test/truncate-to-width.test.ts, test/regression-regional-indicator-width.test.ts counted
coding-agent/utils/mime.ts test/image-process.test.ts mixed — excluded (2 of 3 cases test processImage/original)
coding-agent/utils/version-check.ts test/version-check.test.ts mixed — excluded (fetch cases mock the original; not separable per-file)
coding-agent/core/export-html/ansi-to-html.ts test/export-html-whitespace.test.ts mixed — excluded (asset-grep + tool-renderer/original dominate)
coding-agent/core/tools/truncate.ts no dedicated test (exercised via tools.test.ts, subject is the read/edit factory/original)
coding-agent/core/tools/edit-diff.ts no dedicated test (edit-tool tests' subject is the edit tool/original)

CLI conformance (black-box, against the pidgin binary)

  • CLI conformance: 15/15 pass against target/release/pidgin (pass delta ±0, fail delta ±0).
File Passing Failing Skipped
packages/coding-agent/test/session-file-invalid.test.ts 1 0 0
packages/coding-agent/test/session-id-readonly.test.ts 7 0 0
packages/coding-agent/test/startup-session-name.test.ts 2 0 0
packages/coding-agent/test/stdout-cleanliness.test.ts 5 0 0

The four repointed coding-agent CLI test files spawn the compiled pidgin binary via $PIDGIN_BIN instead of pi's own cli.ts. This is a separate signal from the module smoke table and is never folded into the per-package Native count.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants