feat: add /review skill, /test skill, chokidar file watcher, subcommand help
- Add /review skill: reviews staged/unstaged/commit changes for security,
performance, bugs, and quality with structured findings by severity
- Add /test skill: auto-detects test framework, generates comprehensive
tests for source files, or runs suites with failure analysis
- Add chokidar file watcher: watches ~/.gsd/agent/ for config changes
(settings.json, auth.json, models.json, extensions/) with debounced
events on an EventBus
- Add --help per subcommand: `gsd config --help` and `gsd update --help`
show subcommand-specific usage information
- 8 new file-watcher tests (start/stop, event emission, debouncing,
unrelated file filtering)
2026-03-16 13:47:25 -05:00
const SUBCOMMAND_HELP : Record < string , string > = {
2026-04-29 12:42:31 +02:00
config : [
"Usage: sf config" ,
"" ,
"Re-run the interactive setup wizard to configure:" ,
" - LLM provider (Anthropic, OpenAI, Google, OpenRouter, Ollama, LM Studio, etc.)" ,
" - Web search provider (Brave, Tavily, built-in)" ,
" - Remote questions (Discord, Slack, Telegram)" ,
" - Tool API keys (Context7, Jina, Groq)" ,
"" ,
"All steps are skippable and can be changed later with /login or /search-provider." ,
"" ,
"For detailed provider setup instructions (OpenRouter, Ollama, LM Studio, vLLM," ,
"and other OpenAI-compatible endpoints), see docs/providers.md." ,
] . join ( "\n" ) ,
feat: add /review skill, /test skill, chokidar file watcher, subcommand help
- Add /review skill: reviews staged/unstaged/commit changes for security,
performance, bugs, and quality with structured findings by severity
- Add /test skill: auto-detects test framework, generates comprehensive
tests for source files, or runs suites with failure analysis
- Add chokidar file watcher: watches ~/.gsd/agent/ for config changes
(settings.json, auth.json, models.json, extensions/) with debounced
events on an EventBus
- Add --help per subcommand: `gsd config --help` and `gsd update --help`
show subcommand-specific usage information
- 8 new file-watcher tests (start/stop, event emission, debouncing,
unrelated file filtering)
2026-03-16 13:47:25 -05:00
2026-04-29 12:42:31 +02:00
update : [
"Usage: sf update" ,
"" ,
"Update SF to the latest version." ,
"" ,
2026-05-05 16:31:53 +02:00
"Equivalent to: npm install -g singularity-forge@latest" ,
2026-04-29 12:42:31 +02:00
] . join ( "\n" ) ,
2026-03-16 15:27:10 -06:00
2026-04-29 12:42:31 +02:00
sessions : [
"Usage: sf sessions" ,
2026-05-01 20:18:50 +02:00
" sf sessions --all" ,
2026-04-29 12:42:31 +02:00
"" ,
2026-05-01 20:18:50 +02:00
"List saved sessions and interactively pick one to resume. Shows date," ,
"message count, and a preview of the first message for each session." ,
2026-04-29 12:42:31 +02:00
"" ,
2026-05-01 20:18:50 +02:00
"Sessions are stored per-directory by default. Use --all to list sessions" ,
"across all projects." ,
"" ,
" sf sessions List sessions for the current directory" ,
" sf sessions --all List sessions across all projects" ,
2026-04-29 12:42:31 +02:00
"" ,
"Compare with --continue (-c) which always resumes the most recent session." ,
] . join ( "\n" ) ,
feat: add `gsd headless` CLI subcommand for non-interactive auto-mode
Adds a first-class `gsd headless` command that runs auto-mode without a
TUI by spawning a child process in RPC mode via RpcClient. Useful for
CI/CD pipelines, scripts, and unattended execution.
CLI interface:
gsd headless - Run auto-mode until complete
gsd headless --step - Run one unit only (sends /gsd next)
gsd headless --timeout 300000 - Custom timeout (default 5 min)
gsd headless --json - Forward RPC events as JSONL to stdout
gsd headless --verbose - Show full agent text and tool results
gsd headless --model <id> - Override model
Exit codes: 0 = complete, 1 = error/timeout, 2 = blocked
Features:
- Extension UI auto-responder (handles select, confirm, input, editor,
notify, setStatus, setWidget, setTitle, set_editor_text)
- Completion detection via terminal notification keywords + idle timeout
- Human-readable progress output to stderr
- SIGINT/SIGTERM forwarding for clean shutdown
- Child process crash detection
- Completion summary with diagnostics on failure
2026-03-16 16:18:25 -03:00
2026-04-29 12:42:31 +02:00
install : [
"Usage: sf install <source> [-l, --local]" ,
"" ,
"Install a package/extension source and run post-install validation (dependency checks, setup)." ,
"" ,
"Examples:" ,
" sf install npm:@foo/bar" ,
" sf install git:github.com/user/repo" ,
" sf install https://github.com/user/repo" ,
" sf install ./local/path" ,
] . join ( "\n" ) ,
feat(core): support for 'non-api-key' provider extensions like Claude Code CLI (#2382)
* feat(core): add generic native post-install hooks for package install
* feat(core): add before/after install/remove lifecycle hooks
* refactor(core): remove postInstall alias from lifecycle hook fallback
* feat(core): complete authMode support for keyless providers
The initial authMode implementation fixed model-registry, sdk, and
fallback-resolver but missed agent-session.ts (6 callsites) and
compaction-orchestrator.ts (2 callsites) that block externalCli
providers at runtime.
Architecture: separate readiness gating from credential retrieval.
- isProviderRequestReady(): authMode-aware readiness check
- getApiKey()/getApiKeyForProvider(): return undefined for
externalCli/none providers instead of triggering auth errors
- All 8 callsites in agent-session and compaction-orchestrator
now gate on readiness, not key presence
- Downstream signatures (compaction, branch-summarization) accept
apiKey: string | undefined
- Replaced hardcoded ollama exception in discoverModels with
isProviderRequestReady
Zero behavioral change for classic apiKey/oauth providers.
* feat(core): add isReady callback for provider readiness verification
Extensions can now provide an isReady() callback when registering any
provider. isProviderRequestReady() calls it before default auth checks,
allowing providers to verify actual reachability (CLI authenticated,
API key valid, service online) rather than relying solely on credential
presence.
* test(core): expand authMode test coverage
Cover all four auth modes (apiKey, oauth, externalCli, none),
isReady callback behavior, getProviderAuthMode defaults,
isProviderRequestReady for each mode, getAvailable filtering,
and getApiKey early-return for keyless providers.
* chore: remove provider-api-bridge files from this branch
These files implement GSD core → provider-api wiring (deps + tool
registry) and belong in a separate PR. Reverts register-extension.ts
to upstream state.
2026-03-24 21:50:12 +00:00
2026-04-29 12:42:31 +02:00
remove : [
"Usage: sf remove <source> [-l, --local]" ,
"" ,
"Remove an installed package source and its settings entry." ,
] . join ( "\n" ) ,
feat(core): support for 'non-api-key' provider extensions like Claude Code CLI (#2382)
* feat(core): add generic native post-install hooks for package install
* feat(core): add before/after install/remove lifecycle hooks
* refactor(core): remove postInstall alias from lifecycle hook fallback
* feat(core): complete authMode support for keyless providers
The initial authMode implementation fixed model-registry, sdk, and
fallback-resolver but missed agent-session.ts (6 callsites) and
compaction-orchestrator.ts (2 callsites) that block externalCli
providers at runtime.
Architecture: separate readiness gating from credential retrieval.
- isProviderRequestReady(): authMode-aware readiness check
- getApiKey()/getApiKeyForProvider(): return undefined for
externalCli/none providers instead of triggering auth errors
- All 8 callsites in agent-session and compaction-orchestrator
now gate on readiness, not key presence
- Downstream signatures (compaction, branch-summarization) accept
apiKey: string | undefined
- Replaced hardcoded ollama exception in discoverModels with
isProviderRequestReady
Zero behavioral change for classic apiKey/oauth providers.
* feat(core): add isReady callback for provider readiness verification
Extensions can now provide an isReady() callback when registering any
provider. isProviderRequestReady() calls it before default auth checks,
allowing providers to verify actual reachability (CLI authenticated,
API key valid, service online) rather than relying solely on credential
presence.
* test(core): expand authMode test coverage
Cover all four auth modes (apiKey, oauth, externalCli, none),
isReady callback behavior, getProviderAuthMode defaults,
isProviderRequestReady for each mode, getAvailable filtering,
and getApiKey early-return for keyless providers.
* chore: remove provider-api-bridge files from this branch
These files implement GSD core → provider-api wiring (deps + tool
registry) and belong in a separate PR. Reverts register-extension.ts
to upstream state.
2026-03-24 21:50:12 +00:00
2026-04-29 12:42:31 +02:00
list : [
"Usage: sf list" ,
"" ,
"List installed package sources from user and project settings." ,
] . join ( "\n" ) ,
feat(core): support for 'non-api-key' provider extensions like Claude Code CLI (#2382)
* feat(core): add generic native post-install hooks for package install
* feat(core): add before/after install/remove lifecycle hooks
* refactor(core): remove postInstall alias from lifecycle hook fallback
* feat(core): complete authMode support for keyless providers
The initial authMode implementation fixed model-registry, sdk, and
fallback-resolver but missed agent-session.ts (6 callsites) and
compaction-orchestrator.ts (2 callsites) that block externalCli
providers at runtime.
Architecture: separate readiness gating from credential retrieval.
- isProviderRequestReady(): authMode-aware readiness check
- getApiKey()/getApiKeyForProvider(): return undefined for
externalCli/none providers instead of triggering auth errors
- All 8 callsites in agent-session and compaction-orchestrator
now gate on readiness, not key presence
- Downstream signatures (compaction, branch-summarization) accept
apiKey: string | undefined
- Replaced hardcoded ollama exception in discoverModels with
isProviderRequestReady
Zero behavioral change for classic apiKey/oauth providers.
* feat(core): add isReady callback for provider readiness verification
Extensions can now provide an isReady() callback when registering any
provider. isProviderRequestReady() calls it before default auth checks,
allowing providers to verify actual reachability (CLI authenticated,
API key valid, service online) rather than relying solely on credential
presence.
* test(core): expand authMode test coverage
Cover all four auth modes (apiKey, oauth, externalCli, none),
isReady callback behavior, getProviderAuthMode defaults,
isProviderRequestReady for each mode, getAvailable filtering,
and getApiKey early-return for keyless providers.
* chore: remove provider-api-bridge files from this branch
These files implement GSD core → provider-api wiring (deps + tool
registry) and belong in a separate PR. Reverts register-extension.ts
to upstream state.
2026-03-24 21:50:12 +00:00
2026-04-29 12:42:31 +02:00
logs : [
"Usage: sf logs tail|follow [--source notif|session|activity|audit] [--severity level]" ,
"" ,
"Follow a merged live stream from .sf/notifications.jsonl, the latest" ,
"headless session JSONL, the latest .sf/activity JSONL, and .sf/audit-log.jsonl." ,
"" ,
"Examples:" ,
" sf logs tail" ,
" sf logs follow --source audit" ,
" sf logs tail --severity error" ,
] . join ( "\n" ) ,
2026-04-28 11:52:42 +02:00
2026-04-29 12:42:31 +02:00
status : [
"Usage: sf status --live [--watch]" ,
"" ,
"Show a printable aggregate project view: current milestone, slice, task," ,
"phase, next dispatch, recent events, session cost, and current model." ,
"" ,
"Examples:" ,
" sf status --live" ,
" sf status --live --watch" ,
" sf dash --watch" ,
] . join ( "\n" ) ,
2026-04-28 11:52:42 +02:00
2026-04-29 12:42:31 +02:00
dash : [ "Usage: sf dash [--watch]" , "" , "Alias for sf status --live." ] . join (
"\n" ,
) ,
2026-04-28 11:52:42 +02:00
2026-04-29 12:42:31 +02:00
stats : [
"Usage: sf stats models [--unit-type <type>] [--since <duration>]" ,
"" ,
"Summarize Bayesian model outcome rows from .sf/sf.db." ,
"" ,
"Examples:" ,
" sf stats models --since 7d" ,
" sf stats models --unit-type execute-task --since 24h" ,
] . join ( "\n" ) ,
2026-04-28 11:52:42 +02:00
2026-04-29 12:42:31 +02:00
worktree : [
"Usage: sf worktree <command> [args]" ,
"" ,
"Manage isolated git worktrees for parallel work streams." ,
"" ,
"Commands:" ,
" list List worktrees with status (files changed, commits, dirty)" ,
" merge [name] Squash-merge a worktree into main and clean up" ,
" clean Remove all worktrees that have been merged or are empty" ,
" remove <name> Remove a worktree (--force to remove with unmerged changes)" ,
"" ,
"The -w flag creates/resumes worktrees for interactive sessions:" ,
" sf -w Auto-name a new worktree, or resume the only active one" ,
" sf -w my-feature Create or resume a named worktree" ,
"" ,
"Lifecycle:" ,
" 1. sf -w Create worktree, start session inside it" ,
" 2. (work normally) All changes happen on the worktree branch" ,
" 3. Ctrl+C Exit — dirty work is auto-committed" ,
" 4. sf -w Resume where you left off" ,
" 5. sf worktree merge Squash-merge into main when done" ,
"" ,
"Examples:" ,
" sf -w Start in a new auto-named worktree" ,
' sf -w auth-refactor Create/resume "auth-refactor" worktree' ,
" sf worktree list See all worktrees and their status" ,
" sf worktree merge auth-refactor Merge and clean up" ,
" sf worktree clean Remove all merged/empty worktrees" ,
" sf worktree remove old-branch Remove a specific worktree" ,
" sf worktree remove old-branch --force Remove even with unmerged changes" ,
] . join ( "\n" ) ,
2026-03-18 14:57:25 -06:00
2026-04-29 12:42:31 +02:00
graph : [
"Usage: sf graph <subcommand> [options]" ,
"" ,
"Manage the SF project knowledge graph. Reads .sf/ artifacts and builds" ,
"a queryable graph of milestones, slices, tasks, rules, patterns, and lessons." ,
"" ,
"Subcommands:" ,
" build Parse .sf/ artifacts (STATE.md, milestone ROADMAPs, slice PLANs," ,
" KNOWLEDGE.md) and write .sf/graphs/graph.json atomically." ,
" query Search graph nodes by term (BFS from seed matches, budget-trimmed)." ,
" Returns matching nodes and reachable edges within the token budget." ,
" status Show whether graph.json exists, its age, node/edge counts, and" ,
" whether it is stale (built more than 24 hours ago)." ,
" diff Compare current graph.json with .last-build-snapshot.json." ,
" Returns added, removed, and changed nodes and edges." ,
"" ,
"Examples:" ,
" sf graph build Build the graph from .sf/ artifacts" ,
" sf graph status Check graph age and node/edge counts" ,
' sf graph query auth Find nodes related to "auth"' ,
" sf graph diff Show changes since last snapshot" ,
] . join ( "\n" ) ,
feat(graph): implement knowledge graph system (closes #4202)
Ports the v1 graphify system to v2 as a native TypeScript implementation.
The knowledge graph builds semantic relationships between milestones, slices,
tasks, and knowledge entries — and injects relevant subgraphs automatically
into every agent dispatch prompt.
## Core implementation (packages/mcp-server/src/readers/graph.ts)
- `buildGraph(projectDir)` — walks all .gsd/ artifacts (STATE.md,
milestone PLANs, slice PLANs, KNOWLEDGE.md), extracts nodes and edges
with confidence tiers (EXTRACTED / INFERRED / AMBIGUOUS). Parse errors
skip the node rather than crashing.
- `writeGraph(gsdRoot, graph)` — atomic write via tmp file + rename.
- `writeSnapshot(gsdRoot)` — saves a diff baseline before each rebuild.
- `graphQuery(projectDir, term, budget?)` — BFS subgraph search with
case-insensitive matching on label + description; trims AMBIGUOUS edges
first, then INFERRED, respecting the token budget (default 4 000).
- `graphStatus(projectDir)` — freshness check; stale = older than 24 h.
- `graphDiff(projectDir)` — compares current graph to last snapshot,
returns added / removed / changed counts for nodes and edges.
## MCP tool (packages/mcp-server/src/server.ts)
Registers `gsd_graph` immediately after `gsd_knowledge` with four modes:
build | query | status | diff. All errors returned as isError: true.
## CLI subcommand (src/cli.ts, src/help-text.ts)
`gsd graph build|status|query <term>|diff` — follows the established
`if (cliFlags.messages[0] === '...')` dispatch pattern. Uses
`resolveGsdRoot()` for git-root-aware path resolution (not a naive
`.gsd` append). Help text updated with correct positional argument format.
## Auto-rebuild after slice completion
(src/resources/extensions/gsd/tools/complete-slice.ts)
Fire-and-forget `buildGraph → writeGraph` triggered after every slice
completion. Uses `@gsd-build/mcp-server` package import (not a relative
src path) and `resolveGsdRoot()` for correct path resolution in monorepos.
## Graph-aware dispatch injection
(src/resources/extensions/gsd/graph-context.ts,
src/resources/extensions/gsd/auto-prompts.ts)
`inlineGraphSubgraph(projectDir, term, { budget })` queries the graph and
formats the result as a `### Knowledge Graph Context` markdown block,
consistent with all other inlined context blocks. Adds a stale warning
annotation when the graph is older than 24 h. Returns null (graceful
skip) when graph.json is missing, the query returns zero nodes, or the
import fails — no agent dispatch is ever blocked by graph availability.
Injected into three prompt builders:
- `buildResearchSlicePrompt` — 3 000 token budget
- `buildPlanSlicePrompt` — 3 000 token budget
- `buildExecuteTaskPrompt` — 2 000 token budget
## Tests
- 22 tests for the core graph reader (graph.test.ts)
- 14 tests for the dispatch injection helper (graph-context.test.ts)
- All tests use real on-disk fixtures (no module mocking needed)
- Full suite: 6 318 passed, 0 failed
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 02:20:49 +02:00
2026-05-04 23:27:20 +02:00
plan : [
"Usage: sf plan <command>" ,
"" ,
2026-05-08 00:17:47 +02:00
"Manage SF milestone planning artifacts and human docs exports." ,
2026-05-04 23:27:20 +02:00
"" ,
"Commands:" ,
" promote <source> Copy a file from .sf/ to docs/plans/, docs/adr/, or docs/specs/" ,
" list List milestone and slice files in .sf/" ,
" diff Compare .sf/ state with promoted docs/ artifacts" ,
2026-05-08 00:17:47 +02:00
" specs <cmd> Generate, diff, or check docs/specs exports from .sf state" ,
2026-05-04 23:27:20 +02:00
"" ,
"See docs/plans/README.md, docs/adr/README.md, and docs/specs/README.md for conventions." ,
] . join ( "\n" ) ,
2026-05-06 06:02:46 +02:00
schedule : [
"Usage: sf schedule <command> [args]" ,
"" ,
"Manage time-bound reminders and deferred work items." ,
2026-05-07 03:36:56 +02:00
"Entries are stored as versioned append-only JSONL in .sf/schedule.jsonl (project)" ,
2026-05-06 06:02:46 +02:00
"or ~/.sf/schedule.jsonl (global). No daemon required — items surface on pull." ,
"" ,
"Commands:" ,
" add --in <duration> [--kind <kind>] [--scope <scope>] <title>" ,
" --at <ISO-date> Schedule by absolute date instead" ,
" list [--due] [--all] [--json] [--scope <scope>]" ,
" done <id> Mark a scheduled item as done" ,
" cancel <id> Cancel a scheduled item" ,
" snooze <id> --by <duration> Postpone by relative time" ,
" run <id> Execute a scheduled item (show reminder or run command)" ,
"" ,
"Duration format: <number><unit> where unit is w(weeks), d(days), h(hours), m(minutes)." ,
" e.g. 30m, 4h, 2d, 1w" ,
"" ,
"Scope: project (default, stored in .sf/schedule.jsonl) or global (~/.sf/schedule.jsonl)." ,
"" ,
"Kinds: reminder, milestone_check, review_due, review, audit, recurring, command" ,
"" ,
"Examples:" ,
' sf schedule add --in 2w "Review feature adoption metrics"' ,
' sf schedule add --at 2026-06-01T09:00:00Z --kind audit "Audit ADR-007"' ,
" sf schedule list --due" ,
" sf schedule snooze 01ARZ3ND --by 1d" ,
" sf schedule done 01ARZ3ND" ,
] . join ( "\n" ) ,
2026-05-15 16:37:04 +02:00
key : [
"Usage: sf key <subcommand> [args]" ,
"" ,
"Manage provider API keys stored in ~/.sf/agent/auth.json." ,
"" ,
"Credentials for SF runtime live in ~/.sf/agent/auth.json." ,
"SF does NOT read API keys from environment variables at runtime —" ,
"env is only used during initial provider setup. Use `sf key set`" ,
"to rotate keys. auth.json is always the authoritative source." ,
"" ,
"Subcommands:" ,
" set <provider> <api-key> Set or rotate the API key for a provider" ,
" get <provider> Show key status (last 4 chars only, never full key)" ,
" remove <provider> [--yes] Remove the credential (prompts unless --yes)" ,
" list List all providers with credential status" ,
"" ,
"Examples:" ,
" sf key set anthropic sk-ant-abc123 Set the Anthropic API key" ,
" sf key set xiaomi tp-abc123 Set the Xiaomi API key" ,
" sf key get anthropic Show masked key for anthropic" ,
" sf key remove anthropic Remove anthropic credential (confirms)" ,
" sf key remove anthropic --yes Remove without prompting" ,
" sf key list List all providers" ,
"" ,
"Security:" ,
" - Keys are never echoed in full. Only the last 4 characters are shown." ,
" - All writes go through AuthStorage (file-locked, chmod 600)." ,
" - sf key remove always asks for confirmation unless --yes is passed." ,
] . join ( "\n" ) ,
2026-04-29 12:42:31 +02:00
headless : [
"Usage: sf headless [flags] [command] [args...]" ,
"" ,
2026-05-08 05:28:43 +02:00
"Machine surface for direct SF commands. Runs the same SF flow without rendering the TUI." ,
2026-04-29 12:42:31 +02:00
"" ,
"Flags:" ,
" --timeout N Overall timeout in ms (default: 300000)" ,
" --json JSONL event stream to stdout (alias for --output-format stream-json)" ,
" --output-format <fmt> Output format: text (default), json (structured result), stream-json (JSONL events)" ,
" --bare Minimal context: skip CLAUDE.md, AGENTS.md, user settings, user skills" ,
" --resume <id> Resume a prior headless session by ID" ,
" --model ID Override model" ,
" --supervised Forward interactive UI requests to orchestrator via stdout/stdin" ,
" --response-timeout N Timeout (ms) for orchestrator response (default: 30000)" ,
" --answers <path> Pre-supply answers and secrets (JSON file)" ,
" --events <types> Filter JSONL output to specific event types (comma-separated)" ,
"" ,
"Commands:" ,
2026-05-06 02:24:15 +02:00
" autonomous Run all queued product units continuously" ,
2026-04-29 12:42:31 +02:00
" next Run one unit" ,
" status Show progress dashboard" ,
" new-milestone Create a milestone from a specification document" ,
2026-05-08 00:17:47 +02:00
" query Machine snapshot: JSON state + next dispatch + costs (no LLM)" ,
feat(headless,gemini-cli): add sf headless usage + unify gemini quota path
Adds a machine-readable headless surface for live LLM-provider usage and
unifies the gemini-cli quota fetch through one helper, removing the
duplication that existed between usage-bar.js and the new package.
1. snapshotGeminiCliAccount in @singularity-forge/google-gemini-cli-provider
- Single source of truth for { projectId, userTierId, userTierName,
paidTier, models[] } via setupUser + retrieveUserQuota.
- Dedups buckets per modelId, keeping the worst (lowest remainingFraction)
so consumers always see the most-restrictive window. Code Assist
sometimes returns multiple buckets per model; the pessimistic choice
is what every consumer needs.
- discoverGeminiCliModels(cwd?) wraps it for catalog-cache callers that
only need the IDs.
2. sf headless usage subcommand
- New src/headless-usage.ts handler. text (default) and --json output.
Uses the package's snapshot directly — no RPC child, no jiti
gymnastics — matching the shape of headless-uok-status / headless-doctor.
- Wired into src/headless.ts after the doctor block.
- Help text adds the command line.
3. usage-bar.js refactored to delegate
- fetchGeminiUsage no longer imports gemini-cli-core directly. It calls
snapshotGeminiCliAccount and reshapes the result into the existing
{ provider, displayName, windows[] } UI contract.
- Eliminates the duplicate setupUser + retrieveUserQuota code path.
- The fast existsSync(~/.gemini/oauth_creds.json) pre-flight stays
so unauth'd users get a friendly message without paying for OAuth
bootstrap.
4. Model registry refactor (separate track committed alongside)
- src/resources/extensions/sf/model-registry.ts (new) consolidates
canonical model identity, capability tier, and generation tags into
one source of truth that auto-model-selection, benchmark-selector,
and model-router now consume instead of maintaining parallel maps.
All 1487 tests pass (151 files); typecheck clean for both the package
and the SF extensions.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 03:42:53 +02:00
" usage Live LLM-provider usage snapshot (today: gemini-cli tier + per-model quota)" ,
feat(reflection): wire LLM dispatch (sf headless reflect --run)
Phase 1B of the reflection layer: complete the operator-driven loop by
adding actual LLM dispatch. Phase 1A (commit e161a59e2) shipped the
corpus assembler + prompt template + the prompt-emit operator surface.
This commit wires the dispatch end so `sf headless reflect --run`
produces a real report on disk without manual model piping.
Why shell-out to the gemini CLI and not SF's provider abstraction:
reflection is a single-prompt one-shot inference. Going through SF's
full agent dispatch would require a session, model registry, tool
registration, recovery shell — overkill for "render this prompt,
capture text." The gemini CLI handles auth (~/.gemini/oauth_creds.json),
Code Assist project discovery, and protocol drift on its behalf.
Subprocess cost is paid once per reflection (rare).
Implementation:
- reflection.js: runGeminiReflection(prompt, options) spawns
`gemini --yolo --model <model> -p "<directive>"` and pipes the giant
rendered template via stdin (gemini -p reads stdin and appends).
Returns { ok, content, cleanFinish, exitCode, error, stderr }; never
throws. Defaults to gemini-3-pro-preview (0% used on AI Ultra,
strongest agentic model with quota). 8-minute timeout.
cleanFinish detected by REFLECTION_COMPLETE terminator (emitted by
the prompt template's output contract) — operator gets a warning when
the report is truncated.
- headless-reflect.ts: --run flag triggers dispatch + report write
via writeReflectionReport. --model overrides the default. Errors
surface as JSON or text per --json. Successful runs emit the report
path on stdout; failures emit error + truncated stderr.
- help-text.ts: documents --run and --model flags.
- Tests (4 new, 13 total): use a fake `gemini` binary on PATH to
exercise the spawn path without real OAuth/network — covers
ok+cleanFinish, non-zero exit, hang/timeout, missing-terminator.
All 1538 SF extension tests pass; typecheck clean.
Phase 2 follow-up (still gated on sf-mp4rxkwb-l4baga
triage-not-a-first-class-unit-type landing): reflection-pass becomes a
real autonomous-loop unit type, milestone-close auto-triggers it, the
report's `Recommended new self-feedback entries` section gets parsed
and the entries auto-filed.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 04:33:16 +02:00
" reflect Assemble reflection corpus + render prompt for cross-corpus pattern analysis (--json for raw, --run to dispatch to gemini-cli, --model <id> to override)" ,
2026-05-14 19:43:01 +02:00
" triage Render canonical self-feedback triage prompt (--list/--json inspect, --run writes decisions, --apply runs triage-decider -> review-code)" ,
2026-05-15 16:09:36 +02:00
" complete-slice Mark a slice complete out-of-band: complete-slice <M>/<S> [--reason <txt>]" ,
" skip-slice Mark a slice skipped out-of-band (placeholder/migration cleanup)" ,
" complete-milestone Mark a milestone complete out-of-band: complete-milestone <M> [--reason <txt>]" ,
2026-05-15 18:40:27 +02:00
" feedback add File a self_feedback entry (--summary <txt> --severity low|medium|high|critical [--kind <k>] [--evidence <t>] [--suggested-fix <t>] [--milestone M --slice S --task T] [--impact-score N] [--effort-estimate N] [--blocking] [--purpose <fragment>])" ,
" feedback list List self_feedback entries [--unresolved] [--severity <s>] [--purpose <fragment>] [--json]" ,
2026-05-15 17:13:40 +02:00
" feedback resolve Resolve an entry: feedback resolve <id> --reason <txt> [--evidence-kind human-clear|agent-fix|...]" ,
2026-04-29 12:42:31 +02:00
"" ,
"new-milestone flags:" ,
" --context <path> Path to spec/PRD file (use '-' for stdin)" ,
" --context-text <txt> Inline specification text" ,
2026-05-08 01:07:24 +02:00
" --autonomous Start autonomous mode after milestone creation" ,
2026-04-29 12:42:31 +02:00
" --verbose Show tool calls in progress output" ,
feat(headless): enforce ADR-0000 PDD-fields gate at new-milestone
Restoration of forgotten doctrine: ADR-0000 declares the eight PDD
fields (Purpose, Consumer, Contract, Failure boundary, Evidence,
Non-goals, Invariants, Assumptions) the purpose gate, but
`sf headless new-milestone --context <file>` was accepting any
context including empty or trivially-thin seed docs. This wires a
pre-create check that refuses the run when fields are missing or
too thin, naming exactly which ones so the operator can fix the
seed doc and retry.
- new src/resources/extensions/sf/headless-pdd-check.js: scans
context for the eight fields (heading and inline-label forms) and
reports missing/sparse, plus a minimum-spine check (Purpose +
Consumer + Contract + Evidence-or-Falsifier).
- src/headless.ts calls the check after loadContext, before
bootstrapping .sf/. Refusal exits 1 with formatPddRefusal text.
- --skip-pdd-check is the migration escape hatch (warning printed,
PDD gate bypassed) for milestones that pre-date the gate.
- SF-internal auto-bootstrap (autonomous→new-milestone fallback)
is exempted because the seed is SF-generated, not operator-PDD.
- vitest test covers missing-Purpose, missing-Consumer, all-8,
sparse, inline-label form, Falsifier-as-Evidence spine, and the
doctrine field order.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 18:37:06 +02:00
" --skip-pdd-check Bypass the ADR-0000 PDD-fields gate (migration escape hatch)" ,
2026-04-29 12:42:31 +02:00
"" ,
"Output formats:" ,
" text Human-readable progress on stderr (default)" ,
2026-05-08 00:17:47 +02:00
" json Collect events silently, emit one structured result on stdout at exit" ,
2026-04-29 12:42:31 +02:00
" stream-json Stream JSONL events to stdout in real time (same as --json)" ,
"" ,
"Examples:" ,
2026-05-06 02:24:15 +02:00
" sf headless Show this help" ,
2026-05-08 05:28:43 +02:00
" sf headless autonomous Run autonomous mode through the machine surface" ,
2026-04-29 12:42:31 +02:00
" sf headless next Run one unit" ,
2026-05-01 20:18:50 +02:00
" sf headless --output-format json autonomous Structured JSON result on stdout" ,
2026-04-29 12:42:31 +02:00
" sf headless --json status Machine-readable JSONL stream" ,
2026-05-08 00:17:47 +02:00
" sf headless --timeout 60000 autonomous Run autonomous with 1-minute timeout" ,
2026-05-01 20:18:50 +02:00
" sf headless --bare autonomous Minimal context (CI/ecosystem use)" ,
" sf headless --resume abc123 autonomous Resume a prior session" ,
2026-04-29 12:42:31 +02:00
" sf headless new-milestone --context spec.md Create milestone from file" ,
" cat spec.md | sf headless new-milestone --context - From stdin" ,
2026-05-08 01:07:24 +02:00
" sf headless new-milestone --context spec.md --autonomous Create + run autonomously" ,
2026-05-01 20:18:50 +02:00
" sf headless --supervised autonomous Supervised orchestrator mode" ,
" sf headless --answers answers.json autonomous With pre-supplied answers" ,
" sf headless --events agent_end,extension_ui_request autonomous Filtered event stream" ,
2026-05-08 00:17:47 +02:00
" sf headless query Instant machine JSON state snapshot" ,
2026-05-11 18:31:03 +02:00
" sf headless status uok UOK gate health table (last 24h)" ,
" sf headless status uok --json UOK gate health as JSON" ,
2026-05-14 07:44:34 +02:00
" sf headless triage --list Self-feedback queue digest (impact↓ effort↑ ts↑)" ,
" sf headless triage | sf-some-model Pipe triage prompt to any model" ,
" sf headless triage --run Dispatch triage to default model + write decisions" ,
2026-05-14 19:43:01 +02:00
" sf headless triage --apply Apply via triage-decider, then gate with review-code" ,
2026-05-14 07:44:34 +02:00
" sf headless reflect Render reflection prompt for piping" ,
" sf headless reflect --run Dispatch reflection + write report" ,
2026-05-15 16:09:36 +02:00
" sf headless complete-slice M010/S03 Flip M010/S03 to status=complete (idempotent)" ,
" sf headless skip-slice M003/S01 --reason \"migration placeholder\" Mark placeholder slice skipped" ,
" sf headless complete-milestone M010 Flip milestone to status=complete" ,
2026-05-15 17:13:40 +02:00
" sf headless feedback add --severity high --summary \"30K truncate drops the why\" File self-feedback" ,
2026-05-15 18:40:27 +02:00
" sf headless feedback add --summary \"...\" --purpose \"M015 vision: ...\" Anchor to a purpose (ADR-0000)" ,
2026-05-15 17:13:40 +02:00
" sf headless feedback list --unresolved Pending self-feedback entries" ,
2026-05-15 18:40:27 +02:00
" sf headless feedback list --purpose \"M015 vision\" Triage by purpose anchor" ,
2026-05-15 17:13:40 +02:00
" sf headless feedback resolve sf-mp4xxx --reason \"shipped in 7b85a6\" Resolve an entry" ,
2026-04-29 12:42:31 +02:00
"" ,
"Exit codes: 0 = success, 1 = error/timeout, 10 = blocked, 11 = cancelled" ,
] . join ( "\n" ) ,
} ;
feat: add /review skill, /test skill, chokidar file watcher, subcommand help
- Add /review skill: reviews staged/unstaged/commit changes for security,
performance, bugs, and quality with structured findings by severity
- Add /test skill: auto-detects test framework, generates comprehensive
tests for source files, or runs suites with failure analysis
- Add chokidar file watcher: watches ~/.gsd/agent/ for config changes
(settings.json, auth.json, models.json, extensions/) with debounced
events on an EventBus
- Add --help per subcommand: `gsd config --help` and `gsd update --help`
show subcommand-specific usage information
- 8 new file-watcher tests (start/stop, event emission, debouncing,
unrelated file filtering)
2026-03-16 13:47:25 -05:00
2026-04-15 15:37:12 +02:00
// Alias: `sf wt --help` → same as `sf worktree --help`
2026-04-29 12:42:31 +02:00
SUBCOMMAND_HELP [ "wt" ] = SUBCOMMAND_HELP [ "worktree" ] ;
2026-03-18 14:57:25 -06:00
2026-03-16 13:29:31 -05:00
export function printHelp ( version : string ) : void {
2026-04-29 12:42:31 +02:00
process . stdout . write ( ` SF v ${ version } — Singularity Forge \ n \ n ` ) ;
process . stdout . write ( "Usage: sf [options] [message...]\n\n" ) ;
process . stdout . write ( "Options:\n" ) ;
process . stdout . write (
2026-05-08 00:17:47 +02:00
" --mode <text|json|rpc> Session I/O mode: text/json print format or RPC protocol\n" ,
2026-04-29 12:42:31 +02:00
) ;
process . stdout . write ( " --print, -p Single-shot print mode\n" ) ;
process . stdout . write (
" --continue, -c Resume the most recent session\n" ,
) ;
process . stdout . write (
" --worktree, -w [name] Start in an isolated worktree (auto-named if omitted)\n" ,
) ;
process . stdout . write (
" --model <id> Override model (e.g. provider/model-id)\n" ,
) ;
process . stdout . write (
" --no-session Disable session persistence\n" ,
) ;
process . stdout . write (
" --extension <path> Load additional extension\n" ,
) ;
process . stdout . write ( " --tools <a,b,c> Restrict available tools\n" ) ;
process . stdout . write (
" --list-models [search] List available models and exit\n" ,
) ;
2026-04-30 07:41:24 +02:00
process . stdout . write (
" --discover Force live verification for filtered --list-models\n" ,
) ;
2026-04-29 12:42:31 +02:00
process . stdout . write ( " --version, -v Print version and exit\n" ) ;
process . stdout . write ( " --help, -h Print this help and exit\n" ) ;
process . stdout . write ( "\nSubcommands:\n" ) ;
process . stdout . write ( " config Re-run the setup wizard\n" ) ;
process . stdout . write (
" install <source> Install a package/extension source\n" ,
) ;
process . stdout . write (
" remove <source> Remove an installed package source\n" ,
) ;
process . stdout . write (
" list List installed package sources\n" ,
) ;
process . stdout . write (
" update Update SF to the latest version\n" ,
) ;
process . stdout . write (
" sessions List and resume a past session\n" ,
) ;
process . stdout . write ( " logs tail|follow Follow merged SF logs\n" ) ;
process . stdout . write (
" status --live Show aggregate project status\n" ,
) ;
process . stdout . write ( " dash Alias for status --live\n" ) ;
process . stdout . write ( " stats models Summarize model outcomes\n" ) ;
process . stdout . write (
" worktree <cmd> Manage worktrees (list, merge, clean, remove)\n" ,
) ;
process . stdout . write (
2026-05-08 00:17:47 +02:00
" autonomous [args] Run autonomous mode through the machine surface (pipeable)\n" ,
2026-05-01 20:18:50 +02:00
) ;
2026-04-29 12:42:31 +02:00
process . stdout . write (
2026-05-08 05:28:43 +02:00
" headless [cmd] [args] Machine surface for direct SF commands\n" ,
2026-04-29 12:42:31 +02:00
) ;
process . stdout . write (
" graph <subcommand> Manage knowledge graph (build, query, status, diff)\n" ,
) ;
2026-05-04 23:27:20 +02:00
process . stdout . write (
2026-05-08 00:17:47 +02:00
" plan <cmd> Manage SF planning artifacts and docs exports\n" ,
2026-05-04 23:27:20 +02:00
) ;
2026-05-06 06:02:46 +02:00
process . stdout . write (
" schedule <cmd> Manage time-bound reminders (add, list, done, cancel, snooze, run)\n" ,
) ;
2026-05-15 16:37:04 +02:00
process . stdout . write (
" key <set|get|remove|list> Manage provider API keys in auth.json\n" ,
) ;
2026-04-29 12:42:31 +02:00
process . stdout . write (
"\nRun sf <subcommand> --help for subcommand-specific help.\n" ,
) ;
feat: add /review skill, /test skill, chokidar file watcher, subcommand help
- Add /review skill: reviews staged/unstaged/commit changes for security,
performance, bugs, and quality with structured findings by severity
- Add /test skill: auto-detects test framework, generates comprehensive
tests for source files, or runs suites with failure analysis
- Add chokidar file watcher: watches ~/.gsd/agent/ for config changes
(settings.json, auth.json, models.json, extensions/) with debounced
events on an EventBus
- Add --help per subcommand: `gsd config --help` and `gsd update --help`
show subcommand-specific usage information
- 8 new file-watcher tests (start/stop, event emission, debouncing,
unrelated file filtering)
2026-03-16 13:47:25 -05:00
}
2026-04-29 12:42:31 +02:00
export function printSubcommandHelp (
subcommand : string ,
version : string ,
) : boolean {
const help = SUBCOMMAND_HELP [ subcommand ] ;
if ( ! help ) return false ;
process . stdout . write ( ` SF v ${ version } — Singularity Forge \ n \ n ` ) ;
process . stdout . write ( help + "\n" ) ;
return true ;
2026-03-16 13:29:31 -05:00
}