When offset or limit are specified, use Node.js readline streaming instead of
loading the entire file into memory. This fixes the truncation issue for large
files (>50KB) where the read tool would return truncated content even when
requesting a small slice.
- Add readLinesStreamed() for memory-efficient line reading
- Add countLines() for total line count without full read
- Use streaming path when offset !== undefined || limit !== undefined
- Keep existing full-file read path when no offset/limit specified
- Add tests for streaming behavior with large files
Fixes the long-standing issue where reading large files like src/headless.ts
(~50KB) with offset/limit would still hit truncation limits.
- gap-audit prompt detection: Add DYNAMICALLY_LOADED_PROMPTS set for prompts
loaded through wrappers (research-slice, plan-slice, execute-task, etc.)
and detect loadPrompt calls with comma-separated args (#sf-moobj36l-ewu7js)
- gap-audit command detection: Detect exact match, prefix match, and
switch/case patterns for command dispatch (#sf-moobj36o-n8b7g9)
- empty task summary: Add isValidTaskSummary() to require non-empty content
with frontmatter or H1 before reconciliation marks task complete
(#sf-moobj36o-6rxy6e)
- journal write failures: Emit bounded health warning to .write-failures.jsonl
on journal write failure with per-session dedup (#sf-moobj36p-ikq3b2)
- resource sync manifest divergence: Add verifyManifestFilesExist() to check
all manifest-listed files exist on disk after hash match (#sf-moody5qi-8gbwp2)
- self-feedback markdown stale: Regenerate SELF-FEEDBACK.md from jsonl on
markResolved with resolved entries section (#sf-moobj36p-rlo95i)
- self-feedback context bloat: Cap entries to 20 max, 4000 chars, inject
compact summaries only with pointer to jsonl for full evidence
(#sf-moobj36p-ko6snt)
- hook-emitter types: Replace unknown with EventResult discriminated union,
implement emitExtensionEvent call with fallback warning when _pi missing
(#sf-moobmhwt-bxejb6, #sf-moobmhx4-gk9g83)
- export visualizer types: Add VisualizerExportData interface with proper
PhaseAggregate/SliceAggregate/ModelAggregate/ProjectTotals types
replacing any (#sf-moobmhx0-ow5fhy)
- native-edit-bridge: Already resolved (artifact removed from repo)
(#sf-moobj36q-z4id3u)
Three production gaps Codex's adversarial review flagged are now closed:
1. Real legacy-vs-UOK parity diff (per turn, per plane):
- parity-diff-capture.ts captures plan / graph / model-policy /
audit-envelope / gitops decisions for both paths and emits
ParityDiffEvent records to .sf/runtime/uok-parity.jsonl.
- parity-report.ts aggregates divergencesByPlane, populates
criticalMismatches with real divergence summaries, and tracks
enterEvents / exitEvents / missingExitEvents for symmetry.
2. Exit-event symmetry:
- sessionId / turnId now flow through enter+exit parity events.
- writeParityHeartbeat lets kernel/loop-adapter emit best-effort
diagnostics on plane failure paths so missing-exit gaps shrink.
3. Commit-gating on divergence or missing-exit:
- resolveParitySafeGitAction (in uok/gitops.ts) reads the parity
report and downgrades turn_action to status-only when divergence
count > 0 or missing-exit count > 0 — UOK can no longer commit
on top of unverified state.
- auto-post-unit.ts now resolves a configuredTurnAction from UOK
flags then asks the parity gate for the safe action; the gate's
decision is what flows to the actual git op.
- new test: tests/uok-gitops-commit-gate.test.ts.
- existing gitops-wiring assertion updated for the renamed
configuredTurnAction (semantic preserved).
Tests: 53/53 UOK pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Since Node >= 24 is the minimum engine, remove the better-sqlite3 fallback
chain from sf-db.ts, unit-ownership.ts, and cli-stats.ts. Use DatabaseSync
from node:sqlite directly. Also replace the `glob` npm package with built-in
node:fs/promises.glob and node:fs.globSync in pi-coding-agent LSP utils.
- Remove createRequire boilerplate and suppressSqliteWarning helper
- Simplify loadProvider() and openRawDb()
- Net -177 lines of fallback/middleware code
💘 Generated with Crush
Assisted-by: GLM-5.1 via Crush <crush@charm.land>
- Convert remaining node:test → vitest imports in packages/* and studio/*
- Fix mock.callCount() → mock.callCount property access for vitest compat
- Fix mock.calls[N].arguments → mock.calls[N] for vitest compat
- Update tsconfig.extensions.json to exclude test files from tsc
- Harden migrate-to-vitest-all.mjs regex for single quotes and optional semicolons
Add vitest.config.ts with forks pool, v8 coverage, and package aliases.
Run migrate-to-vitest.mjs to replace `from "node:test"` imports with
`from 'vitest'` across 749 test files, converting mock.fn→vi.fn and
mock.timers→vi fake timers where needed.
💘 Generated with Crush
Assisted-by: GLM-5.1 via Crush <crush@charm.land>
- openai-codex.ts: replace hand-rolled PKCE flow with simple read of
~/.codex/auth.json written by the real codex CLI after user authentication.
Removes ~250 lines of local callback server + browser dance code.
- openai-codex-responses.ts: minor residual cleanup
- openai-completions.ts: drop remaining `as any` stream_options cast
- anthropic-shared.ts: use `unknown` cast on thinkingNoBudget path
- pi-coding-agent/extensions/types.ts: minor type addition
- db-tools.ts: explicit AgentToolResult return type on execute handlers
- requesting-code-review/SKILL.md: prompt wording cleanup
- subagent/index.ts: capability registration wiring
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- package.json: add 'typecheck' script (build:pi + tsc --noEmit) so pi-ai
and pi-coding-agent typecheck under the same command surface SF uses.
- anthropic-shared.ts: replace 'as any' casts with proper Anthropic SDK
types (ServerToolUseBlockParam, WebSearchToolResultBlockParam,
CacheControlEphemeral). The cache_control variant is documented inline
so the cast is auditable.
- openai-completions.ts: drop the 'as any' on stream_options — the type
system can verify the assignment now.
- openai-codex-responses.ts, package-manager.ts, skills.ts: annotate the
three remaining empty catches with one-line WHY comments (best-effort
cleanup, malformed ignore files, partial directory traversal). Empty
catch with no rationale is an SF012 anti-pattern; with rationale it is
a deliberate fallback.
- oauth/github-copilot.ts, oauth/openai-codex.ts: add UPSTREAM AUDIT
blocks documenting why these hand-rolled OAuth flows stay hand-rolled
rather than delegating to @octokit/auth-oauth-device or @openai/codex.
AbortSignal coverage and provider-specific surface area are the gating
concerns; re-audit triggers are named.
Replace ~700 LOC of hand-rolled OAuth and onboarding with cli-core's own
getOauthClient + setupUser. The provider now reads ~/.gemini/oauth_creds.json
itself (via cli-core), refreshes tokens, and discovers the Code Assist
project + tier server-side — exactly like the real gemini CLI does.
- provider/google-gemini-cli.ts: drop apiKey={token,projectId} JSON
plumbing; getCodeAssistServer() uses cli-core for everything
- delete utils/oauth/google-gemini-cli.ts (457 LOC: hand-rolled login,
PKCE, callback server, discoverProject, onboardUser, tier handling)
- delete utils/oauth/google-oauth-utils.ts (201 LOC: only consumed by
the deleted gemini-cli helper)
- oauth/index.ts: remove gemini-cli from BUILT_IN_OAUTH_PROVIDERS
registry; google-gemini-cli is no longer SF-managed
- auth-storage.ts: update 3 error messages to direct users to the real
gemini CLI for authentication instead of the removed /login command
Login UX: users authenticate with the real gemini CLI; we just consume
~/.gemini/oauth_creds.json. Whole-provider disable goes through manual
settings.json edit (per-model toggle still works in interactive UI).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Replace brittle string-matching in headless-events.ts with structured
source/kind/blocking/dedupe_key metadata on notify() events. String
matching is preserved as a fallback for the ~940 untagged call sites.
- Add NotificationMetadata type to headless-types.ts (canonical definition)
- Extend rpc-types.ts notify event with optional metadata field
- Extend ExtensionUIContext.notify() signature with optional 3rd arg
- Pass metadata through RPC notify implementation in rpc-mode.ts
- Update headless-events.ts: isTerminalNotification, isBlockedNotification,
isMilestoneReadyNotification, isPauseNotification all check metadata first
- Update notification-store.ts: store metadata on NotificationEntry; use
metadata.dedupe_key as dedup key when provided (falls back to message hash)
- Update notify-interceptor.ts to thread metadata through to store + original
- Tag critical emit sites with structured metadata:
stopAuto → { kind: "terminal" } (+ blocking: true when reason includes "block")
pauseAuto → { kind: "terminal", blocking: true }
guided-flow milestone ready → { kind: "approval_request", blocking: true }
- Update notification-overlay.ts to prefer metadata.source for [label] display
- Add 17-test regression suite (notification-event-model.test.ts)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>