- doRender() now catches render errors and emits a fallback line
- autonomousStatus ANSI formatting extracted to renderAutonomousStatus()
with named color constants instead of raw escape strings
- parseCellSizeResponse extracted to pure function with proper validation
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- TUI.useInk() opts into Ink-backed rendering (call before start())
- In start(): if _useInk || process.stdout.isTTY, mount Ink renderer via
startInkRenderer() and skip the legacy differential render path entirely
- In stop(): unmount Ink handle and return early; legacy terminal cleanup
(cursor repositioning, showCursor, terminal.stop) is skipped since Ink
handles terminal restoration itself
- Passes this.render()/invalidate() via a plain Component wrapper to avoid
the private handleInput TypeScript conflict
- Two new contract tests: useInk() flag and stop() Ink handle teardown
- 80/80 tests pass; legacy path unchanged for non-TTY (CI/tests)
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Install ink@7.0.2 + react@19.2.6. Add JSX/react-jsx support to
packages/tui tsconfig. Create ink-bridge.tsx: LegacyComponentView wraps
existing Component objects as React nodes, startInkRenderer drives the
Ink render loop around any legacy Component tree.
Exports startInkRenderer from @singularity-forge/tui public API.
All 78 existing tui tests pass; 3 new ink-bridge tests added.
This is the infrastructure step for migrating components one-by-one from
the custom differential renderer to native Ink React components, without
breaking interactive mode.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Remove vestigial experimentalDecorators/emitDecoratorMetadata from all
package tsconfigs (no actual decorators in source — flags were from
pi-mono vendor copy)
- Add @typescript/native-preview for 8-10x faster type checking (measured
4.6x on this repo: tsc 6.5s vs tsgo 1.4s)
- Fix tsconfig.extensions.json: remove baseUrl (removed in tsgo/TS7) and
use relative paths in paths mappings — compatible with both tsc and tsgo
- Add typecheck/typecheck:extensions scripts using tsgo
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- fix(compaction): tokensBefore undefined crash on reload
compaction-orchestrator now falls back to preparation.totalTokens when
extension returns tokensBefore: undefined; compaction-summary-message
guards with ?? 0 defensively
- feat(exec): inline truncation notice in sf_exec digest
appends [stdout truncated — read full output: <path>] when
stdout_truncated=true so agent knows to use sf_exec_search
- feat(exec): wire onUpdate progress for sf_exec
calls onUpdate before execution starts with status/command so TUI
shows live feedback during long-running commands
- feat(security): prompt injection defense for external content
new sanitize-external-content.js utility: strips HTML comments,
detects 15 injection patterns (instruction override, role reassignment,
fake system messages, encoded payloads); wired into exec-tool digest
- feat(tools): sf_session_todo tool (persisted cross-compaction)
add/check/list ops; persists to .sf/session_todo.json; pending todos
injected into compaction summary block for context continuity
- feat(hooks): shell hooks surface (.sf/hooks/pre-tool/*.sh, post-tool/*.sh)
pre-tool hooks block tool execution (exit≠0 = block with stdout reason)
post-tool hooks fire-and-forget; JSON context piped to stdin; 5s timeout
- fix(db): WAL autocheckpoint disabled to prevent corruption
PRAGMA wal_autocheckpoint=0 in initSchema(); explicit checkpointWal()
after successful finalize verification — the only safe checkpoint point
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When the agent is already streaming (system-triggered turn, e.g. autonomous
dispatch at startup) and the user sends a message without an explicit
streamingBehavior, default to followUp instead of steer.
Steer injects mid-stream into the current turn. FollowUp queues the
message as a clean new turn after the system work finishes — which is
what the user expects when they type their first message at startup.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace 'Use steer() or followUp()' with plain language guidance.
Users see this when sending a message while the agent is still working.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Align google-gemini-cli-provider's @google/gemini-cli-core dep from
0.40.1 → 0.41.2 to match root; npm deduplicates to a single module
instance, so diag.setLogger is called only once (no 'overwritten' warn)
- Add logtape.meta logger config at 'warning' level to suppress LogTape's
own 'loggers are configured' info message on every startup
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- packages/native/tsconfig.json: add types:["node"] so Buffer/process/
__dirname resolve correctly (root tsconfig has no lib/types for node)
- scripts/check-sf-extension-inventory.mjs: add footer-config, undo-turn,
review-code to HIDDEN_OR_ALIAS_SUBCOMMANDS (they are aliases for statusline,
rewind, rubber-duck)
- src/resources/extensions/sf/commands/catalog.js: add session-rename entry
(real command handled in core.js, was missing from TOP_LEVEL_SUBCOMMANDS)
- src/resources/extensions/sf/extension-manifest.json: add 19 commands that
exist in catalog but were absent from provides.commands
- src/resources/extensions/sf/guided-flow.js: remove showSmartEntry compat alias
(no live imports — only a comment reference in headless-context.ts)
- src/resources/extensions/sf/graph.js: remove graphFromDefinition compat alias
build:core now passes end-to-end.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
v1 no longer exists — the suffix is just noise. Update all import sites
and rename the test file to match.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Shift+Tab: cycles work mode (chat→plan→build→review→repair→research)
when idle; opens steerable panel during autonomous execution
- Ctrl+T: cycles thinking level (replaces shift+tab binding)
- Removed toggleThinking from default Ctrl+T (superseded by cycleThinkingLevel)
- Drop hint for toggleThinking from interactive mode help text
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Create vault-resolver.js: URI parser, auth chain (env → file → AppRole), in-memory caching
- Add resolveConfigValueAsync() to pi-coding-agent for lazy vault URI resolution
- Integrate vault credential resolution into auth-storage credential loading path
- Add doctor check (checkVaultHealth) for vault setup validation at startup
- Document vault setup, auth methods, examples, troubleshooting in preferences-reference.md
- Add comprehensive test suite (18 tests) for vault URI parsing, auth, caching, fallback
Auth Chain:
1. VAULT_TOKEN env var (simplest for local dev)
2. ~/.vault-token file (recommended for local dev)
3. VAULT_ROLE_ID + VAULT_SECRET_ID env vars (AppRole for CI/CD)
Fail-open behavior: If vault unavailable, falls back to plaintext URIs to allow continued operation.
URI Format: vault://secret/path/to/secret#fieldname
Example: ANTHROPIC_API_KEY=vault://secret/anthropic/prod#api_key
Tests: parseVaultUri, isVaultUri, resolveSecret, caching, edge cases all passing (18/18).
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Rename tests to match actual behavior: degrades_silently / degrades_to_no_op
- Remove incorrect status-bar routing assertions from setWidget tests
- Add federated-memory module with test