chore: delete old .gsd
This commit is contained in:
parent
39f0df45d5
commit
6139a22c44
20 changed files with 0 additions and 1602 deletions
|
|
@ -1,35 +0,0 @@
|
|||
# Decisions Register
|
||||
|
||||
<!-- Append-only. Never edit or remove existing rows.
|
||||
To reverse a decision, add a new row that supersedes it.
|
||||
Read this file at the start of any planning or research phase. -->
|
||||
|
||||
| # | When | Scope | Decision | Choice | Rationale | Revisable? |
|
||||
|---|------|-------|----------|--------|-----------|------------|
|
||||
| D001 | M001 | arch | Embedding strategy | SDK (`createAgentSession` + `InteractiveMode`) | Type-safe, no subprocess management, full control over storage/resources, cleanest branded app path per pi docs | No |
|
||||
| D002 | M001 | arch | State storage location | `~/.gsd/` (agent: `~/.gsd/agent/`, sessions: `~/.gsd/sessions/`) | Complete isolation from `~/.pi/`, clear brand identity, follows pi doc recommendation for branded apps | No |
|
||||
| D003 | M001 | arch | Branding mechanism | `PI_PACKAGE_DIR` env var set before pi internals load, pointing to gsd package root; gsd `package.json` declares `piConfig: { name: "gsd", configDir: ".gsd" }` | `config.js` reads `APP_NAME` from `piConfig.name` in the package.json found at `PI_PACKAGE_DIR`. Only mechanism that renames the TUI header without patching pi source. | Yes — if pi adds a dedicated `createAgentSession` appName option |
|
||||
| D004 | M001 | arch | Extension delivery | Copy extension `.ts` source into `src/resources/extensions/` at dev time; load via `DefaultResourceLoader.additionalExtensionPaths`; pi's jiti handles JIT compilation at runtime | Preserves pi's JIT compilation model, no separate build step for extensions, extensions stay readable source | Yes — if extension count grows large enough to warrant pre-compilation |
|
||||
| D005 | M001 | scope | Skills in M001 | Excluded — extensions only | User decision during discussion | Yes — M002 candidate |
|
||||
| D006 | M001 | scope | Plugin/install system | Deferred | Not MVP; bundled-only product for M001 | Yes — M002 candidate |
|
||||
| D007 | M001 | arch | pi interop | None — GSD never reads or writes `~/.pi/` | GSD is a product, not a pi config. Interop would blur the brand boundary. | No |
|
||||
| D008 | M001/S01 | verification | S01 verification strategy | Shell commands + real TTY launch (no test framework) | S01 is a pure binary launch / TUI branding check. The only meaningful assertion is whether the binary launches with "gsd" in the header — no unit-testable logic to isolate. Shell verification commands cover all must-haves. Test framework deferred to S02+ if needed. | Yes — add test framework in S02 if extension loading logic warrants it |
|
||||
| D009 | M001/S01 | arch | `files` array in package.json | Set in T03 during S01 (`["dist", "package.json", "README.md"]`) | Correct npm publish manifest must be in place before S04 pack/publish. Setting it early avoids a late-stage surprise. | No |
|
||||
| D010 | M001/S01/T02 | impl | ModelRegistry instantiation | Constructor `new ModelRegistry(authStorage)` — not a static factory | SDK types show no `.create()` on ModelRegistry; authStorage is passed directly to constructor. All other managers (AuthStorage, SettingsManager, SessionManager) use static `.create()` but synchronously. | No |
|
||||
| D011 | M001/S01/T02 | impl | InteractiveMode.run() | Instance method: `new InteractiveMode(session); mode.run()` — not static | SDK type declarations confirm `run()` is an instance method; static call would fail at runtime. | No |
|
||||
| D012 | M001/S01/T02 | impl | skipLibCheck in tsconfig | `skipLibCheck: true` added | `@google/genai` published types reference `@modelcontextprotocol/sdk` which is not installed as a type dep — causes transitive TS2307 error unrelated to gsd code. skipLibCheck is the standard fix for third-party type declaration issues. | Yes — remove if MCP types are added as a dep in the future |
|
||||
| D013 | M001/S01/T03 | arch | `PI_PACKAGE_DIR` shim directory (`pkg/`) | Added `pkg/` dir with `package.json` (piConfig) + `dist/modes/interactive/theme/` (pi theme JSONs) as the `PI_PACKAGE_DIR` target | `config.js::getThemesDir()` uses `getPackageDir()` (= PI_PACKAGE_DIR) and checks if `<dir>/src` exists; if yes, uses `src/modes/interactive/theme/` instead of `dist/`. Our project has a real `src/` dir, causing themes to resolve to the wrong path. Pointing PI_PACKAGE_DIR at `pkg/` (which has no `src/`) avoids the collision while still providing `piConfig` for branding. `pkg/dist/modes/interactive/theme/` is populated by `npm run copy-themes` (build script). | Yes — if pi adds a dedicated `appName` option to createAgentSession making PI_PACKAGE_DIR unnecessary |
|
||||
| D014 | M001/S02 | verification | S02 verification strategy | Shell commands + real TTY launch with stderr capture, no test framework | Extension loading is a runtime integration concern — no unit-testable logic to isolate. The meaningful assertions are: zero extension errors in stderr on launch, correct env vars in compiled loader.js, absence of `~/.pi/` refs in patched files. Shell commands cover all must-haves. Test framework deferred per D008. | Yes — add test framework if extension loading logic grows complex |
|
||||
| D015 | M001/S02 | arch | subagent spawn approach | `spawn(process.execPath, [GSD_BIN_PATH, ...extensionArgs, ...args])` — no `pi` binary in PATH | Patched subagent spawns node directly with the gsd dist/loader.js entrypoint. This ensures spawned subagents always use the bundled gsd extensions, regardless of what `pi` is in PATH. `GSD_BIN_PATH` = `process.argv[1]` from loader.ts. | Yes — if pi adds a native subagent spawn API |
|
||||
| D016 | M001/S02 | arch | shared/ is a library, not an extension entry point | `shared/` is NOT added to `additionalExtensionPaths` | `shared/ui.ts`, `shared/next-action-ui.ts` etc. are cross-extension imports, not independently registered extensions. They are discovered by jiti when gsd and ask-user-questions imports them via `../shared/*.js`. Adding shared/ as an extension entry point would attempt to register it as an extension (which it isn't). | No |
|
||||
| D017 | M001/S02 | arch | AGENTS.md first-run write | `initResources()` writes bundled AGENTS.md to `~/.gsd/agent/AGENTS.md` on first launch | pi's `loadProjectContextFiles` discovers AGENTS.md from `agentDir` (`~/.gsd/agent/`). On fresh install this file doesn't exist. One-time write on launch (behind existsSync check) ensures spawned subagents always pick up GSD's hard rules and execution heuristics. | No |
|
||||
| D018 | M001/S03 | arch | Wizard injection point | Pre-session: before `createAgentSession()`, not via `session_start` event hook | Running wizard before `createAgentSession()` ensures Anthropic key is in `authStorage` before `modelRegistry.getAvailable()` runs — avoids "No models available" fallback warning. S01 forward intelligence mentioned session_start hook; pre-session approach is strictly better because the session starts clean with a valid model. | Yes — if pi adds a native `beforeStart` or `authMissing` hook to `createAgentSession` |
|
||||
| D019 | M001/S03 | verification | S03 verification strategy | Shell script (`scripts/verify-s03.sh`) for automated non-TTY/skip checks + interactive UAT for masked input and TUI launch | Wizard involves TTY interaction that cannot be meaningfully automated (masked stdin, TUI launch). Automated shell script covers all non-interactive assertions (exit codes, error text, env hydration). Interactive UAT covers the remaining visual/interactive behaviors. No test framework added — consistent with D008/D014. | Yes — add test framework if wizard logic grows complex |
|
||||
| D020 | M001/S03 | arch | Wizard scope | Optional tool keys only (Brave/Context7/Jina) — Anthropic auth is pi's responsibility via OAuth | Wizard collecting Anthropic key was redundant (pi already handles it) and interfered with verify script automation. Optional-key scope satisfies R006. | Yes — if pi adds a native "no Anthropic key" callback hook |
|
||||
| D021 | M001/S04 | arch | GSD_BUNDLED_EXTENSION_PATHS target | agentDir-based paths, not src/resources paths | When subagent spawns a child gsd process via --extension flags, the child also runs initResources + buildResourceLoader from agentDir. src/resources paths ≠ agentDir paths → pi deduplication fails → duplicate tool registration errors. Pointing to agentDir paths means both the --extension args and agentDir scan resolve identically → deduplication works. Safe because subagent spawning only happens after initResources has synced on first launch. | No |
|
||||
| D022 | M001/S04 | verification | S04 verification strategy | 10-check `scripts/verify-s04.sh` for tarball install path; registry publish check automated; interactive UAT for wizard fire from clean install | Tarball install + launch is automatable (env isolation, background kill). Registry install check is automatable (prefix install + stderr check). Wizard TTY interaction is UAT-only. Consistent with D008/D014/D019 — shell scripts, no test framework. | Yes — add test framework if automated E2E is needed later |
|
||||
| D023 | M003 | arch | Test flow execution model | Intent-based YAML specs, not deterministic scripts — agent interprets verify blocks with full adaptive intelligence | Evaluated Maestro (JVM dep, deterministic scripting, mobile-first) and decided against embedding or cloning it. GSD's advantage is AI-in-the-loop. Flows describe what to verify; the agent decides how. Faster iteration, better flakiness handling, plays to GSD's strength. | Yes — could add deterministic fast-path for simple assertions later |
|
||||
| D024 | M003 | arch | Test browser isolation | test-flows runs its own Playwright instance, separate from browser-tools | Test execution must not be polluted by development browser state (cookies, auth, DOM mutations). Two Playwright instances in one process is supported. Keeps test-flows extension fully decoupled from browser-tools. | No |
|
||||
| D025 | M003 | arch | Maestro integration | Not embedded — optional external tool if user installs it | Maestro requires JVM, adds ~200MB+ footprint, its YAML format is deterministic scripts not intent specs. GSD builds its own testing arm. Maestro MCP could be wired in later as an optional extension for users who want it. | Yes — could add maestro MCP wrapper extension later |
|
||||
| D026 | M002/S02 | arch | S02 does not merge S01 branch | S02 adds `guidance` field to the tool's own TypeBox schema, not importing `SecretsManifestEntry` from S01 types | S02 enhances `secure_env_collect` itself. The tool receives `keys` with `guidance` via its own schema, not manifest types. S03 is the integration point that reads the manifest and passes entries to the tool. No compile-time dependency on S01. | No |
|
||||
| D027 | M002/S02 | pattern | Summary screen is informational-only TUI component | User presses enter/escape to continue — no cursor navigation, no data collection | First "display-only" `ctx.ui.custom()` component in the codebase. Follows `confirm-ui.ts` render/handleInput/invalidate triple but with no interactive state beyond dismiss. | No |
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
# Project
|
||||
|
||||
## What This Is
|
||||
|
||||
GSD 2.0 is a branded npm CLI (`npm install -g gsd-pi`) that ships the full GSD coding agent experience as a standalone product. It embeds `@mariozechner/pi-coding-agent` via SDK, stores state in `~/.gsd/`, bundles the GSD extension, all supporting extensions, agents, and AGENTS.md context, and runs pi's `InteractiveMode` under the `gsd` brand. Users run `gsd` — not `pi`.
|
||||
|
||||
## Core Value
|
||||
|
||||
A single `npm install -g gsd-pi` gives any developer a fully configured, GSD-branded coding agent with the GSD extension, all supporting tools (browser, search, context7, subagent, bg-shell, etc.), and a first-run setup wizard that collects API keys — ready to use in under two minutes.
|
||||
|
||||
## Current State
|
||||
|
||||
M001 complete. `gsd-pi` published to npm (v2.3.7). `npm install -g gsd-pi` installs a working `gsd` binary that launches with GSD ASCII art branding, loads all 11 bundled extensions without errors, stores state in `~/.gsd/`, and runs the first-run wizard for optional API keys. All 9 M001 requirements validated. M002 (Branded Installer & Onboarding Experience) is in progress — S01 complete, S02-S03 planned.
|
||||
|
||||
Key structural artifact: `pkg/` shim directory — `PI_PACKAGE_DIR` points here (not project root) to avoid pi's `getThemesDir()` collision with our real `src/` dir. Committed; `pkg/dist/modes/interactive/theme/` populated by `npm run copy-themes` at build time.
|
||||
|
||||
## Architecture / Key Patterns
|
||||
|
||||
- **SDK embedding**: `@mariozechner/pi-coding-agent` imported as a library via `createAgentSession` + `InteractiveMode`
|
||||
- **Branded app directories**: state lives in `~/.gsd/agent/`, sessions in `~/.gsd/sessions/` (constants in `src/app-paths.ts`)
|
||||
- **Branding via `PI_PACKAGE_DIR`**: env var set in `src/loader.ts` before any pi SDK loads; points to `pkg/` shim; `pkg/package.json` declares `piConfig: { name: "gsd", configDir: ".gsd" }`
|
||||
- **Two-file loader pattern**: `loader.ts` (sets env vars, zero SDK imports, dynamic-imports `cli.js`) → `cli.ts` (static SDK imports, wires all managers)
|
||||
- **pkg/ shim**: lean subdirectory — only `package.json` (piConfig) and `dist/modes/interactive/theme/` (pi theme assets). No `src/`. Avoids `getThemesDir()` src-check collision.
|
||||
- **Bundled extensions**: GSD extension + 10 supporting extensions in `src/resources/extensions/`; loaded via `buildResourceLoader()` → `DefaultResourceLoader.additionalExtensionPaths`; all 11 load clean on launch
|
||||
- **Bundled agents + AGENTS.md**: scout, researcher, worker in `src/resources/agents/`; `initResources()` writes bundled AGENTS.md to `~/.gsd/agent/` on first launch (existsSync guard)
|
||||
- **4 GSD_ env vars**: set in loader.ts before cli.js loads — `GSD_CODING_AGENT_DIR`, `GSD_BIN_PATH`, `GSD_WORKFLOW_PATH`, `GSD_BUNDLED_EXTENSION_PATHS`
|
||||
- **First-run wizard**: `src/wizard.ts` — detects missing optional keys (Brave/Context7/Jina), prompts with masked TTY input, writes to `~/.gsd/agent/auth.json`; `loadStoredEnvKeys` hydrates env on every launch before extensions load
|
||||
|
||||
## Capability Contract
|
||||
|
||||
See `.gsd/REQUIREMENTS.md` for the explicit capability contract, requirement status, and coverage mapping.
|
||||
|
||||
## Milestone Sequence
|
||||
|
||||
- [x] M001: MVP CLI — `npm install -g gsd-pi` installs, launches, and runs with all bundled extensions and first-run setup
|
||||
- [ ] M002: Branded Installer & Onboarding Experience — ASCII logo, postinstall banner, unified onboarding wizard
|
||||
- [ ] M003: AI-Driven Test Flows — intent-based YAML test specs the agent writes during development and executes autonomously at UAT time (browser, mac, api targets)
|
||||
|
|
@ -1,194 +0,0 @@
|
|||
# Requirements
|
||||
|
||||
This file is the explicit capability and coverage contract for the project.
|
||||
|
||||
## Active
|
||||
|
||||
### R001 — Secret forecasting during milestone planning
|
||||
- Class: core-capability
|
||||
- Status: active
|
||||
- Description: During milestone planning, the LLM analyzes the roadmap's slices and boundary map to predict which external services and API keys will be needed across the milestone. Produces a structured secrets manifest.
|
||||
- Why it matters: Without forecasting, auto-mode blocks hours into execution when it encounters a missing API key, wasting the user's time.
|
||||
- Source: user
|
||||
- Primary owning slice: M002/S01
|
||||
- Supporting slices: M002/S03
|
||||
- Validation: contract-proven (S01) — prompt instructions and manifest types/parser established; runtime proof pending S04
|
||||
- Notes: Forecasting is LLM-generated at planning time, not from a static database.
|
||||
|
||||
### R002 — Secrets manifest file persisted in .gsd/
|
||||
- Class: continuity
|
||||
- Status: active
|
||||
- Description: A secrets manifest file in `.gsd/milestones/M00x/M00x-SECRETS.md` tracks what keys are needed, what's been collected, per-key guidance, and collection status.
|
||||
- Why it matters: Enables referencing later (onboarding, new slices adding requirements), and lets auto-mode know what's already been collected.
|
||||
- Source: user
|
||||
- Primary owning slice: M002/S01
|
||||
- Supporting slices: M002/S02, M002/S03
|
||||
- Validation: contract-proven (S01) — format defined with types, parser, writer, template; runtime persistence pending S03/S04
|
||||
- Notes: File format must be parseable by the auto-mode state machine.
|
||||
|
||||
### R003 — LLM-generated step-by-step guidance per key
|
||||
- Class: primary-user-loop
|
||||
- Status: active
|
||||
- Description: Each forecasted secret includes LLM-generated guidance: the service name, dashboard URL, numbered navigation steps to find the key, and what the key format looks like.
|
||||
- Why it matters: Current `secure_env_collect` just shows the key name and an optional format hint. Users shouldn't have to search for where to find a key.
|
||||
- Source: user
|
||||
- Primary owning slice: M002/S01
|
||||
- Supporting slices: M002/S02
|
||||
- Validation: contract-proven (S01) — manifest format includes guidance[], dashboardUrl, formatHint per key; quality validation pending S04
|
||||
- Notes: Guidance quality depends on LLM knowledge of common services. Accuracy is best-effort.
|
||||
|
||||
### R004 — Summary screen before collection
|
||||
- Class: primary-user-loop
|
||||
- Status: active
|
||||
- Description: Before collecting secrets one-by-one, show a summary screen listing all needed keys with their guidance. User sees the full picture before entering any values.
|
||||
- Why it matters: Collecting 5-8 keys blind is disorienting. A summary lets the user prepare (open dashboards, etc.) before the collection loop starts.
|
||||
- Source: user
|
||||
- Primary owning slice: M002/S02
|
||||
- Supporting slices: none
|
||||
- Validation: unmapped
|
||||
- Notes: Summary screen is a TUI custom component, not just text output.
|
||||
|
||||
### R005 — Existing key detection and silent skip
|
||||
- Class: primary-user-loop
|
||||
- Status: active
|
||||
- Description: Before collecting, check the environment and .env file for each needed key. Keys that already exist are silently skipped — no prompt, no confirmation.
|
||||
- Why it matters: Reduces friction on repeated runs or when some keys are already configured.
|
||||
- Source: user
|
||||
- Primary owning slice: M002/S02
|
||||
- Supporting slices: M002/S03
|
||||
- Validation: unmapped
|
||||
- Notes: Check both process.env and .env file contents.
|
||||
|
||||
### R006 — Smart destination detection
|
||||
- Class: integration
|
||||
- Status: active
|
||||
- Description: Automatically detect whether secrets should be written to .env, Vercel, or Convex based on project context (presence of vercel.json, convex/, etc.).
|
||||
- Why it matters: User shouldn't have to specify destination — it should be inferred from the project.
|
||||
- Source: inferred
|
||||
- Primary owning slice: M002/S02
|
||||
- Supporting slices: M002/S03
|
||||
- Validation: unmapped
|
||||
- Notes: Falls back to .env if no specific platform detected.
|
||||
|
||||
### R007 — Auto-mode integration
|
||||
- Class: core-capability
|
||||
- Status: active
|
||||
- Description: Auto-mode dispatches a `collect-secrets` phase after `plan-milestone` completes and before the first slice begins execution. If a secrets manifest exists with uncollected keys, auto-mode pauses for collection.
|
||||
- Why it matters: This is the primary insertion point that prevents auto-mode from blocking on missing secrets hours into execution.
|
||||
- Source: user
|
||||
- Primary owning slice: M002/S03
|
||||
- Supporting slices: none
|
||||
- Validation: unmapped
|
||||
- Notes: Must integrate with existing dispatchNextUnit state machine in auto.ts.
|
||||
|
||||
### R008 — Guided /gsd wizard integration
|
||||
- Class: core-capability
|
||||
- Status: active
|
||||
- Description: The guided `/gsd` flow triggers the same secret collection after milestone planning, providing a consistent experience regardless of entry point.
|
||||
- Why it matters: Users who use `/gsd` instead of `/gsd auto` should get the same proactive secret collection.
|
||||
- Source: user
|
||||
- Primary owning slice: M002/S03
|
||||
- Supporting slices: none
|
||||
- Validation: unmapped
|
||||
- Notes: Hooks into guided-flow.ts.
|
||||
|
||||
### R009 — Planning prompts instruct LLM to forecast secrets
|
||||
- Class: integration
|
||||
- Status: active
|
||||
- Description: The plan-milestone prompt template instructs the LLM to analyze slices for external service dependencies and write a secrets manifest as part of milestone planning output.
|
||||
- Why it matters: Without prompt instructions, the LLM won't know to forecast secrets during planning.
|
||||
- Source: inferred
|
||||
- Primary owning slice: M002/S01
|
||||
- Supporting slices: none
|
||||
- Validation: validated (S01) — both plan-milestone.md and guided-plan-milestone.md contain forecasting instructions with {{secretsOutputPath}} variable, wired through auto.ts and guided-flow.ts
|
||||
- Notes: Modifies plan-milestone.md and possibly the discuss prompt.
|
||||
|
||||
### R010 — secure_env_collect enhanced with guidance field
|
||||
- Class: primary-user-loop
|
||||
- Status: active
|
||||
- Description: The `secure_env_collect` tool's key schema gains a `guidance` field (multi-line string or array of strings) beyond the existing single-line `hint`. The TUI displays this guidance prominently during collection.
|
||||
- Why it matters: Current `hint` is a single format string like "starts with sk-". Step-by-step guidance needs more space.
|
||||
- Source: inferred
|
||||
- Primary owning slice: M002/S02
|
||||
- Supporting slices: none
|
||||
- Validation: unmapped
|
||||
- Notes: Backward compatible — existing `hint` still works. `guidance` is additive.
|
||||
|
||||
## Validated
|
||||
|
||||
(None yet — M002 has not started execution.)
|
||||
|
||||
## Deferred
|
||||
|
||||
### R011 — Multi-milestone secret forecasting
|
||||
- Class: core-capability
|
||||
- Status: deferred
|
||||
- Description: Forecast secrets across all milestones in a multi-milestone project, not just the current one.
|
||||
- Why it matters: Could prevent even more blocking, but later milestones may change significantly.
|
||||
- Source: user
|
||||
- Primary owning slice: none
|
||||
- Supporting slices: none
|
||||
- Validation: unmapped
|
||||
- Notes: User explicitly chose current-milestone only. Revisit if multi-milestone friction observed.
|
||||
|
||||
### R012 — Secret rotation/refresh reminders
|
||||
- Class: operability
|
||||
- Status: deferred
|
||||
- Description: Track key expiry or staleness and remind the user to refresh secrets.
|
||||
- Why it matters: Keys expire. Stale keys cause confusing failures.
|
||||
- Source: research
|
||||
- Primary owning slice: none
|
||||
- Supporting slices: none
|
||||
- Validation: unmapped
|
||||
- Notes: Low priority — solve the blocking problem first.
|
||||
|
||||
## Out of Scope
|
||||
|
||||
### R013 — Curated service knowledge base
|
||||
- Class: constraint
|
||||
- Status: out-of-scope
|
||||
- Description: A hand-maintained registry of common services (Stripe, OpenAI, Supabase, etc.) with baked-in guidance.
|
||||
- Why it matters: Prevents scope confusion — guidance comes from LLM generation, not a database to maintain.
|
||||
- Source: user
|
||||
- Primary owning slice: none
|
||||
- Supporting slices: none
|
||||
- Validation: n/a
|
||||
- Notes: User explicitly chose LLM-generated over curated.
|
||||
|
||||
### R014 — Just-in-time collection enhancement
|
||||
- Class: constraint
|
||||
- Status: out-of-scope
|
||||
- Description: Enhancing the reactive just-in-time secret collection experience when a task discovers it needs a key mid-execution.
|
||||
- Why it matters: Prevents scope confusion — the goal is front-loading, not improving the fallback path.
|
||||
- Source: user
|
||||
- Primary owning slice: none
|
||||
- Supporting slices: none
|
||||
- Validation: n/a
|
||||
- Notes: User explicitly chose up-front only. Existing fallback behavior remains as-is.
|
||||
|
||||
## Traceability
|
||||
|
||||
| ID | Class | Status | Primary owner | Supporting | Proof |
|
||||
|---|---|---|---|---|---|
|
||||
| R001 | core-capability | active | M002/S01 | M002/S03 | contract-proven (S01) |
|
||||
| R002 | continuity | active | M002/S01 | M002/S02, M002/S03 | contract-proven (S01) |
|
||||
| R003 | primary-user-loop | active | M002/S01 | M002/S02 | contract-proven (S01) |
|
||||
| R004 | primary-user-loop | active | M002/S02 | none | unmapped |
|
||||
| R005 | primary-user-loop | active | M002/S02 | none | unmapped |
|
||||
| R006 | integration | active | M002/S02 | M002/S03 | unmapped |
|
||||
| R007 | core-capability | active | M002/S03 | none | unmapped |
|
||||
| R008 | core-capability | active | M002/S03 | none | unmapped |
|
||||
| R009 | integration | validated | M002/S01 | none | validated (S01) |
|
||||
| R010 | primary-user-loop | active | M002/S02 | none | unmapped |
|
||||
| R011 | core-capability | deferred | none | none | unmapped |
|
||||
| R012 | operability | deferred | none | none | unmapped |
|
||||
| R013 | constraint | out-of-scope | none | none | n/a |
|
||||
| R014 | constraint | out-of-scope | none | none | n/a |
|
||||
|
||||
## Coverage Summary
|
||||
|
||||
- Active requirements: 9
|
||||
- Mapped to slices: 10
|
||||
- Validated: 1 (R009)
|
||||
- Contract-proven: 3 (R001, R002, R003)
|
||||
- Unmapped active requirements: 0
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
# GSD State
|
||||
|
||||
**Active Milestone:** M002 — Branded Installer & Onboarding Experience
|
||||
**Active Slice:** S03 — Unified first-run onboarding wizard
|
||||
**Phase:** planning
|
||||
**Requirements Status:** 11 active · 0 validated · 2 deferred · 2 out of scope
|
||||
|
||||
## Milestone Registry
|
||||
- ✅ **M001:** M001: GSD 2.0 MVP CLI
|
||||
- 🔄 **M002:** Branded Installer & Onboarding Experience
|
||||
- ⬜ **M003:** M003
|
||||
|
||||
## Recent Decisions
|
||||
- None recorded
|
||||
|
||||
## Blockers
|
||||
- None
|
||||
|
||||
## Next Action
|
||||
Plan slice S03 (Unified first-run onboarding wizard).
|
||||
|
|
@ -1,196 +0,0 @@
|
|||
---
|
||||
id: M001
|
||||
provides:
|
||||
- gsd-pi npm package (published, unscoped) — single-command install of the full GSD coding agent
|
||||
- gsd binary with "gsd" TUI branding, state in ~/.gsd/, ~/.pi/ untouched
|
||||
- 11 bundled extensions (gsd, browser-tools, search-the-web, context7, subagent, bg-shell, worktree, plan-mode, slash-commands, ask-user-questions, get-secrets-from-user)
|
||||
- Bundled agents (scout, researcher, worker) + AGENTS.md auto-deployed to ~/.gsd/agent/
|
||||
- First-run setup wizard (optional keys: Brave/Context7/Jina) with masked TTY input
|
||||
- pkg/ shim directory for PI_PACKAGE_DIR branding mechanism
|
||||
- Two-file loader pattern (loader.ts → cli.ts) with 4 GSD_ env vars
|
||||
- resource-loader.ts wiring all extensions via DefaultResourceLoader.additionalExtensionPaths
|
||||
key_decisions:
|
||||
- D001: SDK embedding via createAgentSession + InteractiveMode (not subprocess)
|
||||
- D002: State in ~/.gsd/ for complete isolation from ~/.pi/
|
||||
- D003: PI_PACKAGE_DIR branding mechanism — set before pi internals load
|
||||
- D004: Extension delivery — copy .ts source, pi's jiti handles JIT compilation
|
||||
- D013: pkg/ shim directory — avoids getThemesDir() src-check collision
|
||||
- D015: subagent spawns process.execPath + GSD_BIN_PATH (not "pi" binary)
|
||||
- D017: AGENTS.md first-run write with existsSync guard
|
||||
- D018: Wizard injection point is pre-session (before createAgentSession)
|
||||
- D020: Wizard scope is optional keys only — Anthropic auth is pi's responsibility
|
||||
- D021: GSD_BUNDLED_EXTENSION_PATHS uses agentDir-based paths to prevent double-load
|
||||
- D023: Published as gsd-pi (unscoped) — @glittercowboy scope not provisioned on npm
|
||||
patterns_established:
|
||||
- Two-file loader pattern: loader.ts (sets env, dynamic-imports) → cli.ts (static SDK imports)
|
||||
- pkg/ shim directory with piConfig and theme assets — PI_PACKAGE_DIR target with no src/ subdir
|
||||
- import.meta.url + fileURLToPath for module-relative resource paths
|
||||
- GSD_ env vars set in loader.ts before cli.js dynamic import
|
||||
- Pre-session auth gate: loadStoredEnvKeys → runWizardIfNeeded → initResources → createAgentSession
|
||||
- GSD_BUNDLED_EXTENSION_PATHS colon-delimited for subagent --extension args
|
||||
- process.execPath + GSD_BIN_PATH for spawning child gsd processes
|
||||
- existsSync guard on first-run resource writes to prevent overwriting user customizations
|
||||
- npm run copy-themes populates pkg/dist/modes/interactive/theme/ from node_modules at build time
|
||||
observability_surfaces:
|
||||
- "TUI launch: (node dist/loader.js & sleep 4; kill $!) 2>&1 — GSD ASCII art + version confirms branding"
|
||||
- "Extension errors: (node dist/loader.js & sleep 6; kill $!) 2>&1 | grep 'Extension load error' — zero matches = all clean"
|
||||
- "State isolation: ls ~/.gsd/ — agent/, sessions/ present; ls ~/.pi/agent/sessions/ — count unchanged"
|
||||
- "Registry health: npm view gsd-pi — shows version, dist-tags, maintainer"
|
||||
- "Wizard behavior: BRAVE_API_KEY= CONTEXT7_API_KEY= JINA_API_KEY= node dist/loader.js < /dev/null 2>&1 — surfaces warning"
|
||||
- "Env vars: grep GSD_ dist/loader.js — confirms all 4 env vars set"
|
||||
- "Verify scripts: bash scripts/verify-s03.sh (6 checks), bash scripts/verify-s04.sh (10 checks)"
|
||||
requirement_outcomes:
|
||||
- id: R001
|
||||
from_status: active
|
||||
to_status: validated
|
||||
proof: "S04 — npm install -g gsd-pi from registry installs working binary; zero extension load errors on launch"
|
||||
- id: R002
|
||||
from_status: active
|
||||
to_status: validated
|
||||
proof: "S01 — TUI header confirmed 'gsd' via live runtime launch; piConfig.name=gsd, piConfig.configDir=.gsd verified; ~/.gsd/ created"
|
||||
- id: R003
|
||||
from_status: active
|
||||
to_status: validated
|
||||
proof: "S02 — gsd extension loads without errors on launch (zero stderr extension errors confirmed)"
|
||||
- id: R004
|
||||
from_status: active
|
||||
to_status: validated
|
||||
proof: "S02 — all 10 supporting extensions load without errors on launch; confirmed via stderr capture"
|
||||
- id: R005
|
||||
from_status: active
|
||||
to_status: validated
|
||||
proof: "S02 — agents in src/resources/agents/; AGENTS.md (15,070 bytes) written to ~/.gsd/agent/ on first launch"
|
||||
- id: R006
|
||||
from_status: active
|
||||
to_status: validated
|
||||
proof: "S03 — automated verify script 6/6 pass + interactive UAT; wizard fires, stores keys, skips on rerun"
|
||||
- id: R007
|
||||
from_status: active
|
||||
to_status: validated
|
||||
proof: "S01 — ~/.gsd/ created; ~/.pi/agent/sessions/ count unchanged (28/28 before and after gsd launch)"
|
||||
- id: R008
|
||||
from_status: active
|
||||
to_status: validated
|
||||
proof: "S04 — cpSync force:true in initResources ensures update replaces bundled resources; tarball smoke confirms clean path"
|
||||
- id: R009
|
||||
from_status: active
|
||||
to_status: validated
|
||||
proof: "S03 — non-TTY warning names missing providers; S02 — extension load errors surface to stderr"
|
||||
duration: ~5 hours across 4 slices (S01 ~1h, S02 ~75min, S03 ~45min, S04 ~3h)
|
||||
verification_result: passed
|
||||
completed_at: 2026-03-11
|
||||
---
|
||||
|
||||
# M001: GSD 2.0 MVP CLI
|
||||
|
||||
**Single-command `npm install -g gsd-pi` installs a fully branded GSD coding agent with 11 bundled extensions, agents, first-run wizard, and state isolation — all 9 requirements validated.**
|
||||
|
||||
## What Happened
|
||||
|
||||
Four slices built the complete GSD 2.0 MVP CLI from scratch:
|
||||
|
||||
**S01 (CLI Scaffold and Branding)** established the binary architecture. The key discovery was that pi's `config.js::getThemesDir()` checks for a `src/` subdirectory at the `PI_PACKAGE_DIR` target — since the project has a real `src/`, this caused theme resolution to fail. The fix was the `pkg/` shim directory: a lean subdirectory containing only `package.json` (with piConfig) and theme assets, with no `src/` to trigger the collision. The two-file loader pattern (`loader.ts` sets env vars and dynamic-imports `cli.ts`) ensures `PI_PACKAGE_DIR` is set before any pi SDK code evaluates. After S01, the binary launched with "gsd" in the TUI header and state wrote to `~/.gsd/`.
|
||||
|
||||
**S02 (Bundle Extensions and Agents)** copied all 12 extension source trees into `src/resources/extensions/` and applied surgical patches to 6 files to eliminate hardcoded `~/.pi/` paths. The subagent extension was patched to spawn `process.execPath` with `GSD_BIN_PATH` instead of `spawn("pi", ...)`. A `resource-loader.ts` module wires all 11 extension entry points into `DefaultResourceLoader.additionalExtensionPaths`. `initResources()` writes AGENTS.md to `~/.gsd/agent/` on first launch behind an existsSync guard. All 11 extensions loaded without errors on launch.
|
||||
|
||||
**S03 (First-run Setup Wizard)** built `wizard.ts` with masked TTY input for optional API keys (Brave, Context7, Jina). The critical scoping decision: Anthropic auth is pi's responsibility via OAuth — the wizard only handles optional tool keys. The wizard wires into `cli.ts` as a pre-session auth gate: `loadStoredEnvKeys` → `runWizardIfNeeded` → `initResources` → `createAgentSession`. This ensures env is fully hydrated before extensions load.
|
||||
|
||||
**S04 (npm Publish and Install Smoke Test)** fixed a `GSD_BUNDLED_EXTENSION_PATHS` bug where the env var pointed to `src/resources/` paths instead of agentDir-based paths (causing subagent double-load). The package was initially published as `@glittercowboy/gsd` but the npm scope wasn't provisioned — switched to unscoped `gsd-pi` which resolved immediately. Registry install confirmed working with zero extension load errors.
|
||||
|
||||
## Cross-Slice Verification
|
||||
|
||||
Each success criterion from the roadmap was verified:
|
||||
|
||||
**`npm install -g gsd-pi` in a clean environment produces a working `gsd` binary:**
|
||||
- `npm view gsd-pi` returns v2.3.7 on the npm registry
|
||||
- S04 verified tarball install to an isolated prefix with successful launch
|
||||
- 10-check automated smoke test (`scripts/verify-s04.sh`) all passed
|
||||
|
||||
**`gsd` TUI header shows "gsd" — no pi branding visible in normal operation:**
|
||||
- Live launch of `node dist/loader.js` displays GSD ASCII art logo + "Get Shit Done v2.3.7"
|
||||
- `piConfig.name=gsd`, `piConfig.configDir=.gsd` confirmed via node eval
|
||||
- `PI_PACKAGE_DIR` confirmed pointing to `pkg/` in compiled `dist/loader.js`
|
||||
|
||||
**State lives in `~/.gsd/` — `~/.pi/` is untouched:**
|
||||
- `ls ~/.gsd/` shows `agent/`, `sessions/`, `preferences.md`
|
||||
- S01 verified `~/.pi/agent/sessions/` count unchanged (28/28) before and after gsd launch
|
||||
|
||||
**First-run wizard fires when API keys are missing, collects them, and stores them:**
|
||||
- S03 automated verify script: 6/6 checks passed (build, non-TTY warning, non-TTY no-exit-1, wizard skip, env hydration)
|
||||
- Interactive UAT confirmed masked input, key storage, wizard skip on rerun
|
||||
|
||||
**`/gsd` command is registered and responds correctly:**
|
||||
- gsd extension loads without errors (zero `Extension load error` matches in launch output)
|
||||
- Extension source includes `commands.ts` with `/gsd` command registration
|
||||
|
||||
**All bundled extensions load and their tools are available to the model:**
|
||||
- Launch test with stderr capture: zero extension load errors across all 11 extensions
|
||||
- `grep GSD_ dist/loader.js` shows 11 lines confirming all GSD_ env vars present
|
||||
|
||||
**`npm update -g gsd-pi` works cleanly on an existing install:**
|
||||
- `initResources()` uses `cpSync` with `force: true` for bundled resource updates
|
||||
- S04 tarball smoke test confirmed clean install over existing state
|
||||
|
||||
## Requirement Changes
|
||||
|
||||
- R001: active → validated — `npm install -g gsd-pi` from registry installs working binary with zero extension errors
|
||||
- R002: active → validated — TUI shows "gsd", piConfig confirmed, ~/.gsd/ created, ~/.pi/ untouched
|
||||
- R003: active → validated — gsd extension loads without errors on launch
|
||||
- R004: active → validated — all 10 supporting extensions load without errors on launch
|
||||
- R005: active → validated — agents in src/resources/agents/; AGENTS.md auto-deployed to ~/.gsd/agent/
|
||||
- R006: active → validated — optional-key wizard fires, stores, skips on rerun; scope narrowed to optional keys only (Anthropic handled by pi)
|
||||
- R007: active → validated — ~/.gsd/ created; ~/.pi/ sessions unchanged (28/28)
|
||||
- R008: active → validated — cpSync force:true ensures update replaces bundled resources; tarball smoke confirmed
|
||||
- R009: active → validated — non-TTY warning names missing providers; extension load errors surface to stderr
|
||||
|
||||
## Forward Intelligence
|
||||
|
||||
### What the next milestone should know
|
||||
- The package is `gsd-pi` on npm (unscoped), not `@glittercowboy/gsd`. The binary name is `gsd`.
|
||||
- `PI_PACKAGE_DIR` points to `pkg/` shim — any pi config resolution goes through this directory. If pi changes how `config.js` resolves piConfig or themes, this mechanism may break.
|
||||
- `GSD_BUNDLED_EXTENSION_PATHS` must match what `buildResourceLoader` discovers from agentDir. After `initResources()` syncs extensions to `~/.gsd/agent/extensions/`, subagent spawning uses these agentDir-based paths for `--extension` args.
|
||||
- `initResources()` writes AGENTS.md only once (existsSync guard). Existing installs won't get updated AGENTS.md content on upgrade unless the guard logic changes.
|
||||
- The wizard only handles optional tool keys (Brave/Context7/Jina). Anthropic auth is entirely pi's territory.
|
||||
- `loadStoredEnvKeys` runs on every launch from `cli.ts`, hydrating env from `auth.json` before extensions load.
|
||||
- Extensions are `.ts` source JIT-compiled by pi's jiti at runtime — not pre-compiled. Any TypeScript syntax jiti doesn't support will fail at load time (visible via stderr), not at build time.
|
||||
|
||||
### What's fragile
|
||||
- `pkg/` shim + PI_PACKAGE_DIR mechanism — relies on undocumented `config.js::getThemesDir()` behavior (src-check). Any pi update changing this logic breaks branding silently. Observable signal: ENOENT on dark.json at launch.
|
||||
- `dist/resource-loader.js` computes extension paths via `resolve(dirname(fileURLToPath(import.meta.url)), '..', 'src', 'resources', ...)` — correct for local dev but depends on `src/resources` being in the published `files` array.
|
||||
- `@mariozechner/pi-coding-agent` version pin (`^0.57.1`) — breaking changes in pi SDK will cascade to extension loading failures.
|
||||
- `skipLibCheck: true` in tsconfig masks transitive type errors from pi/google deps.
|
||||
- jiti JIT compilation of bundled `.ts` extensions — cutting-edge TS features may fail silently at load time.
|
||||
|
||||
### Authoritative diagnostics
|
||||
- `npm view gsd-pi` — canonical registry health check; confirms version and availability
|
||||
- `bash scripts/verify-s04.sh` — 10-check install regression suite; PASS/FAIL labeled per check
|
||||
- `bash scripts/verify-s03.sh` — 6-check wizard regression suite
|
||||
- `(node dist/loader.js & sleep 6; kill $!) 2>&1 | grep "Extension load error"` — zero lines = all extensions clean
|
||||
- `grep GSD_ dist/loader.js` — confirms env var presence and values
|
||||
- `ls pkg/dist/modes/interactive/theme/` — dark.json and light.json must exist; run `npm run copy-themes` to fix
|
||||
|
||||
### What assumptions changed
|
||||
- PI_PACKAGE_DIR → project root was wrong — `pkg/` shim required due to getThemesDir() src-check (D013)
|
||||
- ModelRegistry is a constructor, not a static factory (D010)
|
||||
- InteractiveMode.run() is an instance method, not static (D011)
|
||||
- Scoped npm publish `@glittercowboy/gsd` failed — scope not provisioned; unscoped `gsd-pi` works (D023)
|
||||
- Wizard scope narrowed from required+optional keys to optional-only — pi handles Anthropic auth (D020)
|
||||
- extensionsResult.errors shape is `{ path, error }` not `{ message }` — SDK type correction
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
- `package.json` — project manifest: name=gsd-pi, bin.gsd, piConfig, type:module, files array, build scripts, prepublishOnly
|
||||
- `tsconfig.json` — NodeNext/ESM config with skipLibCheck:true, exclude src/resources
|
||||
- `src/loader.ts` — binary entrypoint: sets PI_PACKAGE_DIR + 4 GSD_ env vars, dynamic-imports cli.js
|
||||
- `src/cli.ts` — SDK wiring: AuthStorage, ModelRegistry, wizard, initResources, buildResourceLoader, createAgentSession, InteractiveMode
|
||||
- `src/app-paths.ts` — ~/.gsd/ path constants (appRoot, agentDir, sessionsDir, authFilePath)
|
||||
- `src/wizard.ts` — optional-key wizard: loadStoredEnvKeys + runWizardIfNeeded
|
||||
- `src/resource-loader.ts` — buildResourceLoader(agentDir) + initResources(agentDir)
|
||||
- `pkg/package.json` — piConfig shim: { name: "gsd", configDir: ".gsd" }
|
||||
- `pkg/dist/modes/interactive/theme/` — pi theme assets (copied by build)
|
||||
- `src/resources/extensions/` — all 11 bundled extension source trees (patched for ~/.gsd/)
|
||||
- `src/resources/agents/` — scout.md, researcher.md, worker.md
|
||||
- `src/resources/AGENTS.md` — bundled agent context rules
|
||||
- `src/resources/GSD-WORKFLOW.md` — GSD workflow protocol document
|
||||
- `scripts/verify-s03.sh` — 6-check wizard verification script
|
||||
- `scripts/verify-s04.sh` — 10-check install smoke test script
|
||||
|
|
@ -1,117 +0,0 @@
|
|||
# M002: Proactive Secret Management — Context
|
||||
|
||||
**Gathered:** 2026-03-12
|
||||
**Status:** Ready for planning
|
||||
|
||||
## Project Description
|
||||
|
||||
Add proactive secret forecasting and guided collection to GSD's milestone planning phase. When a milestone is planned, the LLM analyzes what external services and API keys will be needed, writes a secrets manifest with step-by-step guidance for each key, and collects them all before auto-mode begins execution.
|
||||
|
||||
## Why This Milestone
|
||||
|
||||
Auto-mode's value proposition is autonomous execution — plan it, walk away, come back to finished work. But if a task at S02/T03 needs a Stripe API key, auto-mode blocks and sits there for hours waiting. The user comes back expecting progress and finds a prompt asking for a key. This milestone eliminates that failure mode by front-loading secret collection into the planning phase.
|
||||
|
||||
## User-Visible Outcome
|
||||
|
||||
### When this milestone is complete, the user can:
|
||||
|
||||
- Describe a project during `/gsd` discuss that involves external APIs (Stripe, Supabase, OpenAI, etc.) and see a secrets manifest produced during planning with step-by-step guidance for each key
|
||||
- See a summary screen listing all needed keys with guidance, then enter them one-by-one with detailed instructions showing where to find each key
|
||||
- Run `/gsd auto` and have it collect any uncollected secrets before starting slice execution, so auto-mode runs uninterrupted
|
||||
|
||||
### Entry point / environment
|
||||
|
||||
- Entry point: `/gsd` wizard and `/gsd auto` CLI commands
|
||||
- Environment: local dev terminal (pi TUI)
|
||||
- Live dependencies involved: `secure_env_collect` tool, .env files, optionally Vercel/Convex CLIs
|
||||
|
||||
## Completion Class
|
||||
|
||||
- Contract complete means: planning prompts produce secrets manifests, the manifest parser works, the collection TUI shows guidance and skips existing keys, and auto-mode dispatches collection at the right time
|
||||
- Integration complete means: a real `/gsd auto` run with a milestone that needs API keys triggers collection before slice execution
|
||||
- Operational complete means: none — this is a dev-time workflow, not a running service
|
||||
|
||||
## Final Integrated Acceptance
|
||||
|
||||
To call this milestone complete, we must prove:
|
||||
|
||||
- A milestone planning run that involves external APIs produces a parseable secrets manifest with per-key guidance
|
||||
- Auto-mode detects the manifest and pauses for collection before dispatching the first slice
|
||||
- Keys already in the environment are silently skipped
|
||||
- The guided `/gsd` flow triggers the same collection
|
||||
- `npm run build` passes
|
||||
- `npm run test` passes (no new failures beyond pre-existing ones)
|
||||
|
||||
## Risks and Unknowns
|
||||
|
||||
- **Prompt compliance** — The LLM must reliably produce a well-formatted secrets manifest during planning. If the format is inconsistent, the parser won't find the keys. Mitigated by clear prompt instructions and a forgiving parser.
|
||||
- **Guidance accuracy** — LLM-generated guidance for finding API keys (dashboard URLs, navigation steps) may be outdated or wrong. This is best-effort and explicitly accepted by the user.
|
||||
- **State machine insertion** — Adding a new phase to `dispatchNextUnit` in `auto.ts` must not break the existing phase flow. The insertion point is between `plan-milestone` completion and the first slice dispatch.
|
||||
|
||||
## Existing Codebase / Prior Art
|
||||
|
||||
- `src/resources/extensions/get-secrets-from-user.ts` — The existing `secure_env_collect` tool. Has paged masked TUI input, writes to .env/Vercel/Convex. Currently has a single-line `hint` field per key. Needs a `guidance` field for multi-line instructions and a summary screen.
|
||||
- `src/resources/extensions/gsd/auto.ts` — The auto-mode state machine. `dispatchNextUnit()` determines next unit type from derived state. New `collect-secrets` unit type inserts between plan-milestone and first slice.
|
||||
- `src/resources/extensions/gsd/guided-flow.ts` — The `/gsd` wizard. `showSmartEntry()` handles all entry paths. Needs to trigger secret collection after milestone planning.
|
||||
- `src/resources/extensions/gsd/prompts/plan-milestone.md` — The planning prompt template. Needs instructions to forecast secrets and write the manifest.
|
||||
- `src/resources/extensions/gsd/state.ts` — State derivation from disk files. May need to expose whether a secrets manifest exists and whether collection is complete.
|
||||
- `src/resources/extensions/gsd/files.ts` — File parsing utilities. Needs a secrets manifest parser.
|
||||
- `src/resources/extensions/gsd/types.ts` — Core type definitions. Needs types for secrets manifest entries.
|
||||
- `src/resources/extensions/gsd/paths.ts` — Path resolution. Needs a `resolveMilestoneFile` entry for SECRETS files.
|
||||
|
||||
> See `.gsd/DECISIONS.md` for all architectural and pattern decisions — it is an append-only register; read it during planning, append to it during execution.
|
||||
|
||||
## Relevant Requirements
|
||||
|
||||
- R001 — Secret forecasting during milestone planning (core capability)
|
||||
- R002 — Secrets manifest file persisted in .gsd/ (continuity)
|
||||
- R003 — LLM-generated step-by-step guidance per key (primary user loop)
|
||||
- R004 — Summary screen before collection (primary user loop)
|
||||
- R005 — Existing key detection and silent skip (primary user loop)
|
||||
- R006 — Smart destination detection (integration)
|
||||
- R007 — Auto-mode integration (core capability)
|
||||
- R008 — Guided /gsd wizard integration (core capability)
|
||||
- R009 — Planning prompts instruct LLM to forecast secrets (integration)
|
||||
- R010 — secure_env_collect enhanced with guidance field (primary user loop)
|
||||
|
||||
## Scope
|
||||
|
||||
### In Scope
|
||||
|
||||
- Secret forecasting during plan-milestone phase
|
||||
- Secrets manifest file format and parser
|
||||
- Enhanced secure_env_collect with guidance and summary screen
|
||||
- Existing key detection (.env and process.env)
|
||||
- Smart destination detection from project context
|
||||
- Auto-mode collect-secrets phase insertion
|
||||
- Guided flow collection trigger
|
||||
- Manifest status tracking (collected/pending/skipped)
|
||||
|
||||
### Out of Scope / Non-Goals
|
||||
|
||||
- Multi-milestone secret forecasting (deferred — R011)
|
||||
- Secret rotation reminders (deferred — R012)
|
||||
- Curated service knowledge base (out of scope — R013)
|
||||
- Just-in-time collection enhancement (out of scope — R014)
|
||||
- Modifying how secure_env_collect writes to Vercel/Convex (existing behavior preserved)
|
||||
|
||||
## Technical Constraints
|
||||
|
||||
- Must not break existing auto-mode phase flow — new phase inserts cleanly
|
||||
- `secure_env_collect` changes must be backward compatible — existing callers unaffected
|
||||
- Secrets manifest must be parseable by simple regex/string parsing (consistent with files.ts patterns)
|
||||
- The discuss prompt (GSD-WORKFLOW.md) already handles milestone planning for guided flow — secret forecasting instructions go in plan-milestone.md which runs in auto-mode after discuss completes
|
||||
|
||||
## Integration Points
|
||||
|
||||
- `secure_env_collect` tool — Enhanced with guidance field and summary screen
|
||||
- `dispatchNextUnit()` in auto.ts — New collect-secrets unit type
|
||||
- `plan-milestone.md` prompt — Instructions to forecast secrets
|
||||
- `guided-flow.ts` — Collection trigger after planning
|
||||
- `state.ts` / `files.ts` — Manifest parsing and state derivation
|
||||
- `.env` file / process.env — Existing key detection
|
||||
|
||||
## Open Questions
|
||||
|
||||
- **Manifest format** — Markdown with structured sections (consistent with other .gsd files) vs. YAML/JSON. Leaning toward markdown with parseable structure, matching the roadmap/plan pattern.
|
||||
- **Destination inference heuristics** — How aggressively to detect Vercel/Convex vs. defaulting to .env. Leaning toward simple file-presence checks (vercel.json → Vercel, convex/ dir → Convex).
|
||||
|
|
@ -1,96 +0,0 @@
|
|||
# M002: Branded Installer & Onboarding Experience
|
||||
|
||||
**Vision:** Transform the entire first-contact experience — from `npm install` through first working session — into a polished, guided, trust-building flow that gets users from zero to productive with no friction.
|
||||
|
||||
## Success Criteria
|
||||
|
||||
- After `npm install -g gsd-pi`, the terminal shows a clean branded postinstall flow with the GSD ASCII logo, spinners, staged progress, and boxed summary
|
||||
- On first `gsd` launch, a unified onboarding wizard guides the user through LLM provider auth (OAuth or API key) and optional tool API keys before the TUI opens
|
||||
- After completing onboarding, the user drops straight into a working TUI session with an authenticated LLM — no need to discover `/login`
|
||||
- Users who skip onboarding or already have auth configured go straight to the TUI with no friction
|
||||
- The entire flow is visually polished — comparable to openclaw's onboarding or vercel-labs/skills installer
|
||||
|
||||
## Key Risks / Unknowns
|
||||
|
||||
- Spinner animation during synchronous subprocess execution — clack's spinner may not animate while `execSync` blocks the event loop → **retired in S01**
|
||||
- OAuth flows outside TUI — the pi-ai OAuth providers (`loginAnthropic`, etc.) require browser opening + user pasting an auth code back. These are currently wired to the TUI's `LoginDialogComponent`. Need to prove we can drive the same flow from a standalone clack-based wizard using `p.text()` for code input and `exec('open <url>')` for browser opening.
|
||||
- Clack inside pre-TUI context — `@clack/prompts` writes to stdout. The wizard runs before `InteractiveMode` takes over the terminal. Need to verify that clack's raw mode cleanup (cursor visibility, etc.) doesn't corrupt the subsequent TUI session.
|
||||
|
||||
## Proof Strategy
|
||||
|
||||
- Spinner + async subprocess → **retired in S01** by proving the spinner animates during Playwright download
|
||||
- OAuth outside TUI → retire in S03 by proving Anthropic OAuth login works end-to-end from the clack-based onboarding wizard (browser opens, user pastes code, credentials are stored). Originally planned for S02, but S02 was scoped to logo work only.
|
||||
- Clack → TUI handoff → retire in S03 by proving the TUI starts cleanly after the wizard completes. Originally planned for S02, but S02 was scoped to logo work only.
|
||||
|
||||
## Verification Classes
|
||||
|
||||
- Contract verification: postinstall and wizard run to completion, produce expected output
|
||||
- Integration verification: full flow from `npm install -g` → `gsd` → onboarding → working TUI session
|
||||
- Operational verification: works in TTY and non-TTY, handles failures, respects skip/existing-auth
|
||||
- UAT / human verification: visual quality judgment, LLM auth actually works for a real chat
|
||||
|
||||
## Milestone Definition of Done
|
||||
|
||||
This milestone is complete only when all are true:
|
||||
|
||||
- All slices are complete and verified
|
||||
- `npm install -g gsd-pi` produces branded postinstall with ASCII logo
|
||||
- First `gsd` launch shows the onboarding wizard which guides through LLM auth + optional keys
|
||||
- After onboarding, the TUI session has a working authenticated LLM
|
||||
- Returning users (already authed) skip the wizard and go straight to TUI
|
||||
- The visual quality bar is met for both postinstall and onboarding
|
||||
- Final integrated acceptance: a fresh install → onboarding → send a real message → get a response
|
||||
|
||||
## Requirement Coverage
|
||||
|
||||
- Covers: R008 (npm install experience)
|
||||
- New: R012 (first-run onboarding — LLM auth before TUI)
|
||||
- Partially covers: none
|
||||
- Leaves for later: none
|
||||
- Orphan risks: none
|
||||
|
||||
## Slices
|
||||
|
||||
- [x] **S01: Branded postinstall with clack** `risk:medium` `depends:[]`
|
||||
> After this: `npm install -g gsd-pi` shows a structured, branded installer flow with spinners, staged progress, and boxed summary instead of raw ASCII dump
|
||||
|
||||
- [x] **S02: ASCII logo in postinstall + first-launch banner** `risk:low` `depends:[S01]`
|
||||
> After this: postinstall shows the GSD block-letter logo before the clack flow; the existing first-launch banner in loader.ts also uses the shared logo constant
|
||||
|
||||
- [ ] **S03: Unified first-run onboarding wizard** `risk:high` `depends:[S01]`
|
||||
> After this: first `gsd` launch walks the user through LLM provider selection (Anthropic OAuth / API key / OpenAI / others / skip), runs the auth flow, collects optional tool keys, and drops into a working TUI session
|
||||
|
||||
## Boundary Map
|
||||
|
||||
### S01 → S02
|
||||
|
||||
Produces:
|
||||
- `@clack/prompts` and `picocolors` available as production dependencies
|
||||
- Postinstall script pattern using clack intro/spinner/note/outro
|
||||
|
||||
Consumes:
|
||||
- nothing (first slice)
|
||||
|
||||
### S01 → S03
|
||||
|
||||
Produces:
|
||||
- `@clack/prompts` and `picocolors` available as production dependencies
|
||||
- Pattern for structured CLI output with clack
|
||||
|
||||
Consumes:
|
||||
- nothing (first slice)
|
||||
|
||||
### S02 → S03
|
||||
|
||||
Produces:
|
||||
- Shared ASCII logo constant importable from `src/logo.ts`
|
||||
- Logo rendering pattern with picocolors
|
||||
|
||||
### S03
|
||||
|
||||
Consumes:
|
||||
- `@clack/prompts` and `picocolors` (from S01)
|
||||
- Shared ASCII logo (from S02)
|
||||
- `AuthStorage` API: `.set()`, `.has()`, `.login()` (from pi-coding-agent)
|
||||
- OAuth provider functions: `loginAnthropic`, `loginGitHubCopilot`, etc. (from pi-ai)
|
||||
- Existing wizard: `runWizardIfNeeded()` in `src/wizard.ts` (to be replaced/absorbed)
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
# S01 Assessment — Roadmap Reassessment
|
||||
|
||||
**Verdict: Roadmap is fine. No changes needed.**
|
||||
|
||||
## Success Criteria Coverage
|
||||
|
||||
- Secrets manifest with predicted keys and guidance → S01 ✅ (contract), S04 (runtime)
|
||||
- Auto-mode pauses for uncollected secrets → S03
|
||||
- Guided /gsd flow triggers collection → S03
|
||||
- Existing keys silently skipped → S02, S03
|
||||
- Summary screen before collection → S02
|
||||
- npm run build passes → S04
|
||||
- npm run test passes → S04
|
||||
|
||||
All criteria have at least one remaining owning slice.
|
||||
|
||||
## Risk Retirement
|
||||
|
||||
S01 was tagged `risk:medium` for prompt compliance — whether the LLM reliably produces a parseable manifest. The forgiving parser mitigates malformed output, and the prompt instructions are clear. The risk is partially retired (contract side). Full retirement is S04's job (runtime proof).
|
||||
|
||||
## Boundary Contract Accuracy
|
||||
|
||||
S01's actual output matches the boundary map exactly:
|
||||
- `SecretsManifestEntry` and `SecretsManifest` types in `types.ts`
|
||||
- `parseSecretsManifest()` and `formatSecretsManifest()` in `files.ts`
|
||||
- `secrets-manifest.md` template
|
||||
- `secretsOutputPath` wired through `auto.ts` and `guided-flow.ts`
|
||||
- Planning prompt instructions in both `plan-milestone.md` and `guided-plan-milestone.md`
|
||||
|
||||
No boundary map updates needed.
|
||||
|
||||
## Requirement Coverage
|
||||
|
||||
- R001, R002, R003: contract-proven (S01) — on track
|
||||
- R009: validated (S01) — complete
|
||||
- R004, R005, R006, R010: mapped to S02 — unchanged
|
||||
- R007, R008: mapped to S03 — unchanged
|
||||
- All active requirements have owning slices. Coverage is sound.
|
||||
|
||||
## Remaining Slice Ordering
|
||||
|
||||
S02 → S03 → S04 dependency chain is correct. No reordering, merging, or splitting needed.
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
# S01: Secret Forecasting & Manifest
|
||||
|
||||
**Goal:** Establish the secrets manifest format, types, parser/writer, and planning prompt instructions so that milestone planning produces a parseable `M00x-SECRETS.md` file with predicted API keys and step-by-step guidance.
|
||||
**Demo:** Running `plan-milestone` on a project involving external APIs produces a `.gsd/milestones/M00x/M00x-SECRETS.md` manifest file. The manifest parser handles well-formed, edge-case, and empty-secrets output. The template loads with the new `secretsOutputPath` variable. Build and all tests pass.
|
||||
|
||||
## Must-Haves
|
||||
|
||||
- `SecretsManifestEntry` and `SecretsManifest` interfaces in `types.ts` with key, service, dashboardUrl, guidance (string[]), formatHint, status (`pending`/`collected`/`skipped`), and destination fields
|
||||
- `parseSecretsManifest()` in `files.ts` — forgiving regex-based parser using existing `extractSection`/`extractBoldField`/`parseBullets` helpers
|
||||
- `formatSecretsManifest()` in `files.ts` — round-trip writer producing the canonical manifest markdown
|
||||
- `templates/secrets-manifest.md` template defining the manifest format
|
||||
- Parser tests covering: full manifest, single-key manifest, no-secrets manifest, missing optional fields, status values
|
||||
- `plan-milestone.md` and `guided-plan-milestone.md` updated with secret forecasting instructions
|
||||
- `buildPlanMilestonePrompt()` in `auto.ts` passes `secretsOutputPath` template variable
|
||||
- `npm run build` passes
|
||||
- `npm run test` passes (no new failures)
|
||||
|
||||
## Proof Level
|
||||
|
||||
- This slice proves: contract
|
||||
- Real runtime required: no (parser/writer tested with fixture data; prompt instructions verified by template loading)
|
||||
- Human/UAT required: no (prompt compliance tested in S04 end-to-end)
|
||||
|
||||
## Verification
|
||||
|
||||
- `npm run test` — all existing tests plus new manifest parser tests pass
|
||||
- `npm run build` — TypeScript compilation succeeds with new types/functions
|
||||
- Manifest parser tests in `src/resources/extensions/gsd/tests/parsers.test.ts` covering:
|
||||
- Full manifest with multiple keys parses correctly
|
||||
- Single-key manifest parses correctly
|
||||
- No-secrets / empty manifest returns zero entries
|
||||
- Missing optional fields (dashboardUrl, formatHint) default gracefully
|
||||
- Status field parses all three values (`pending`/`collected`/`skipped`)
|
||||
- Round-trip: `formatSecretsManifest(parseSecretsManifest(content))` preserves semantic content
|
||||
|
||||
## Observability / Diagnostics
|
||||
|
||||
- Runtime signals: none — this is a parser/formatter contract, no runtime behavior
|
||||
- Inspection surfaces: parser tests exercise all code paths; `parseSecretsManifest` returns typed objects that are directly inspectable
|
||||
- Failure visibility: parser returns empty arrays for unparseable sections rather than throwing, matching `parseRoadmap` convention; malformed entries are silently skipped
|
||||
- Redaction constraints: none — manifest contains key names and guidance, not actual secret values
|
||||
|
||||
## Integration Closure
|
||||
|
||||
- Upstream surfaces consumed: `extractSection`, `extractAllSections`, `extractBoldField`, `parseBullets` from `files.ts`; `resolveMilestoneFile` from `paths.ts`; `loadPrompt` from `prompt-loader.ts`
|
||||
- New wiring introduced in this slice: `buildPlanMilestonePrompt()` passes `secretsOutputPath` to the prompt template; prompt templates instruct LLM to write the manifest file
|
||||
- What remains before the milestone is truly usable end-to-end: S02 (enhanced collection UX with guidance display), S03 (auto-mode dispatches collect-secrets phase), S04 (end-to-end verification with real LLM planning)
|
||||
|
||||
## Tasks
|
||||
|
||||
- [x] **T01: Manifest types, parser/writer, template, and tests** `est:45m`
|
||||
- Why: Establishes the contract that S02 and S03 depend on — types, parsing, formatting, and the template file. Tests prove the parser handles LLM output variations correctly.
|
||||
- Files: `src/resources/extensions/gsd/types.ts`, `src/resources/extensions/gsd/files.ts`, `src/resources/extensions/gsd/templates/secrets-manifest.md`, `src/resources/extensions/gsd/tests/parsers.test.ts`
|
||||
- Do: Add `SecretsManifestEntry` and `SecretsManifest` interfaces to `types.ts`. Implement `parseSecretsManifest()` and `formatSecretsManifest()` in `files.ts` using existing helpers. Create `templates/secrets-manifest.md`. Add comprehensive parser tests to `parsers.test.ts`. Parser must be forgiving — regex-based, tolerant of whitespace and missing optional fields.
|
||||
- Verify: `npm run build` passes, `npm run test` passes with new manifest parser tests
|
||||
- Done when: `parseSecretsManifest` correctly parses full, single-key, empty, and edge-case manifests; `formatSecretsManifest` produces valid markdown; round-trip preserves data; build succeeds
|
||||
|
||||
- [x] **T02: Planning prompt modifications and auto.ts wiring** `est:30m`
|
||||
- Why: Without prompt instructions, the LLM won't forecast secrets during planning. Without the template variable, the prompt can't tell the LLM where to write the manifest. This delivers R001 and R009.
|
||||
- Files: `src/resources/extensions/gsd/prompts/plan-milestone.md`, `src/resources/extensions/gsd/prompts/guided-plan-milestone.md`, `src/resources/extensions/gsd/auto.ts`, `src/resources/extensions/gsd/guided-flow.ts`
|
||||
- Do: Append secret forecasting instructions section to both prompt templates with `{{secretsOutputPath}}` variable. Update `buildPlanMilestonePrompt()` to compute and pass `secretsOutputPath`. Update guided flow's `loadPrompt` call to also pass `secretsOutputPath`. Instructions must be clearly separated from roadmap instructions, conditional on external APIs ("skip if no external services"), and reference the template format.
|
||||
- Verify: `npm run build` passes, `npm run test` passes, `loadPrompt("plan-milestone", {...})` succeeds with the new variable
|
||||
- Done when: Both prompt templates contain forecasting instructions, `buildPlanMilestonePrompt` and guided flow pass `secretsOutputPath`, build and all tests pass
|
||||
|
||||
## Files Likely Touched
|
||||
|
||||
- `src/resources/extensions/gsd/types.ts`
|
||||
- `src/resources/extensions/gsd/files.ts`
|
||||
- `src/resources/extensions/gsd/templates/secrets-manifest.md`
|
||||
- `src/resources/extensions/gsd/tests/parsers.test.ts`
|
||||
- `src/resources/extensions/gsd/prompts/plan-milestone.md`
|
||||
- `src/resources/extensions/gsd/prompts/guided-plan-milestone.md`
|
||||
- `src/resources/extensions/gsd/auto.ts`
|
||||
- `src/resources/extensions/gsd/guided-flow.ts`
|
||||
|
|
@ -1,124 +0,0 @@
|
|||
---
|
||||
id: S01
|
||||
parent: M002
|
||||
milestone: M002
|
||||
provides:
|
||||
- SecretsManifestEntry and SecretsManifest types with status tracking
|
||||
- parseSecretsManifest() forgiving regex-based parser
|
||||
- formatSecretsManifest() canonical markdown writer
|
||||
- secrets-manifest.md template file
|
||||
- Secret forecasting instructions in plan-milestone and guided-plan-milestone prompts
|
||||
- secretsOutputPath template variable wired through auto.ts and guided-flow.ts
|
||||
requires: []
|
||||
affects:
|
||||
- S02
|
||||
- S03
|
||||
key_files:
|
||||
- src/resources/extensions/gsd/types.ts
|
||||
- src/resources/extensions/gsd/files.ts
|
||||
- src/resources/extensions/gsd/templates/secrets-manifest.md
|
||||
- src/resources/extensions/gsd/tests/parsers.test.ts
|
||||
- src/resources/extensions/gsd/prompts/plan-milestone.md
|
||||
- src/resources/extensions/gsd/prompts/guided-plan-milestone.md
|
||||
- src/resources/extensions/gsd/auto.ts
|
||||
- src/resources/extensions/gsd/guided-flow.ts
|
||||
key_decisions:
|
||||
- Secrets manifest uses H3 headings per env var key with bold metadata fields and numbered guidance lists
|
||||
- Numbered list extraction via regex rather than reusing parseBullets (which strips numbers)
|
||||
- Parser defaults missing optional fields rather than throwing (dashboardUrl/formatHint → empty string, status → pending, destination → dotenv)
|
||||
- secretsOutputPath computed via relMilestoneFile(base, mid, "SECRETS") producing paths like .gsd/milestones/M002/M002-SECRETS.md
|
||||
- Auto prompt uses structured multi-step format; guided prompt condenses to a single paragraph
|
||||
patterns_established:
|
||||
- Manifest format — H3 heading is the env var key name, bold fields for metadata, numbered list for guidance steps
|
||||
- Parser tolerance — invalid status values silently default to pending, missing sections return empty arrays
|
||||
- Template variable injection — secretsOutputPath follows the same relMilestoneFile pattern used for other milestone files
|
||||
observability_surfaces:
|
||||
- Parser tests — 7 test groups with 312 assertions exercising all code paths
|
||||
- loadPrompt safeguard — throws if secretsOutputPath is declared in template but not provided in vars
|
||||
drill_down_paths:
|
||||
- .gsd/milestones/M002/slices/S01/tasks/T01-SUMMARY.md
|
||||
- .gsd/milestones/M002/slices/S01/tasks/T02-SUMMARY.md
|
||||
duration: 27min
|
||||
verification_result: passed
|
||||
completed_at: 2026-03-12
|
||||
---
|
||||
|
||||
# S01: Secret Forecasting & Manifest
|
||||
|
||||
**Established the secrets manifest contract — types, forgiving parser, canonical formatter, template, planning prompt instructions, and template variable wiring — so milestone planning can produce a parseable `M00x-SECRETS.md` with predicted API keys and step-by-step guidance.**
|
||||
|
||||
## What Happened
|
||||
|
||||
T01 added the `SecretsManifestEntry` and `SecretsManifest` types to `types.ts`, implemented `parseSecretsManifest()` using existing `extractAllSections(content, 3)` and `extractBoldField` helpers with regex-based numbered list extraction for guidance steps, and `formatSecretsManifest()` producing canonical markdown. Created the `secrets-manifest.md` template. Added 7 comprehensive test groups (312 assertions) to `parsers.test.ts` covering full manifests, single-key, empty, missing optional fields, all status values, invalid status defaulting, and round-trip parse→format→re-parse.
|
||||
|
||||
T02 extended both `plan-milestone.md` and `guided-plan-milestone.md` with secret forecasting instructions that tell the LLM to analyze slices for external service dependencies and write a secrets manifest. Wired `secretsOutputPath` through `buildPlanMilestonePrompt()` in `auto.ts` and the guided flow in `guided-flow.ts` via `relMilestoneFile(base, mid, "SECRETS")`.
|
||||
|
||||
## Verification
|
||||
|
||||
- `npm run build` — passes clean
|
||||
- `npm run test` — 54 pass, 2 pre-existing failures (initResources sync, npm pack — unrelated)
|
||||
- 7 manifest parser test groups all pass (full, single-key, empty, missing fields, status values, invalid status, round-trip)
|
||||
- `secretsOutputPath` variable present in both prompt templates, `auto.ts`, and `guided-flow.ts`
|
||||
- Both prompts contain skip instruction for milestones with no external APIs
|
||||
- Both prompts reference the `secrets-manifest.md` template
|
||||
|
||||
## Requirements Advanced
|
||||
|
||||
- R001 — Planning prompts now instruct the LLM to forecast secrets during milestone planning. Contract established; runtime proof deferred to S04.
|
||||
- R002 — Manifest file format defined with types, parser, writer, and template. Persistence verified by parser tests; runtime proof deferred to S03/S04.
|
||||
- R003 — Manifest format includes per-key guidance (numbered steps, dashboard URL, format hint). Content quality is LLM-dependent, tested in S04.
|
||||
- R009 — Both plan-milestone and guided-plan-milestone prompts contain secret forecasting instructions with the secretsOutputPath variable.
|
||||
|
||||
## Requirements Validated
|
||||
|
||||
- None — S01 proves the contract (types, parser, formatter, prompt instructions). Runtime validation requires S03 (auto-mode integration) and S04 (end-to-end).
|
||||
|
||||
## New Requirements Surfaced
|
||||
|
||||
- None
|
||||
|
||||
## Requirements Invalidated or Re-scoped
|
||||
|
||||
- None
|
||||
|
||||
## Deviations
|
||||
|
||||
None.
|
||||
|
||||
## Known Limitations
|
||||
|
||||
- Prompt compliance is unproven — the LLM may produce manifests that don't match the template exactly. The forgiving parser mitigates this, but real-world validation is S04's job.
|
||||
- No runtime code path triggers manifest creation yet — that's S03's auto-mode collect-secrets phase.
|
||||
- The `guidance` field is defined as `string[]` in the type but `secure_env_collect` doesn't yet support multi-line guidance — that's S02.
|
||||
|
||||
## Follow-ups
|
||||
|
||||
- None beyond planned S02/S03/S04 work.
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
- `src/resources/extensions/gsd/types.ts` — Added SecretsManifestEntryStatus, SecretsManifestEntry, SecretsManifest types
|
||||
- `src/resources/extensions/gsd/files.ts` — Added parseSecretsManifest() and formatSecretsManifest() with imports
|
||||
- `src/resources/extensions/gsd/templates/secrets-manifest.md` — New canonical manifest template
|
||||
- `src/resources/extensions/gsd/tests/parsers.test.ts` — Added 7 manifest parser/formatter test groups (312 assertions)
|
||||
- `src/resources/extensions/gsd/prompts/plan-milestone.md` — Added Secret Forecasting section with {{secretsOutputPath}}
|
||||
- `src/resources/extensions/gsd/prompts/guided-plan-milestone.md` — Added Secret Forecasting paragraph with {{secretsOutputPath}}
|
||||
- `src/resources/extensions/gsd/auto.ts` — Added secretsOutputPath computation and passing in buildPlanMilestonePrompt()
|
||||
- `src/resources/extensions/gsd/guided-flow.ts` — Added secretsOutputPath computation and passing in guided plan prompt call
|
||||
|
||||
## Forward Intelligence
|
||||
|
||||
### What the next slice should know
|
||||
- The manifest parser is intentionally forgiving — it defaults missing fields rather than throwing. S02 should rely on this when reading manifests that may have been partially written.
|
||||
- `SecretsManifestEntry.guidance` is `string[]` (array of numbered steps). S02's enhanced collection UX should display these as a numbered list, not join them into a paragraph.
|
||||
- The `destination` field on each entry defaults to `"dotenv"`. S02's `detectDestination()` should set this during collection, not rely on the manifest value.
|
||||
|
||||
### What's fragile
|
||||
- The numbered list regex in `parseSecretsManifest` expects lines like `1. Step text` — if the LLM uses `-` bullets or unnumbered lists, guidance will be empty. The parser doesn't fall back to bullet parsing for guidance. Worth monitoring in S04.
|
||||
|
||||
### Authoritative diagnostics
|
||||
- Run `npm run test` and grep for `parseSecretsManifest` — the 7 test groups are the definitive contract check for the manifest format.
|
||||
- Grep for `secretsOutputPath` across `auto.ts`, `guided-flow.ts`, and the prompt files to verify wiring.
|
||||
|
||||
### What assumptions changed
|
||||
- No assumptions changed. The plan executed cleanly with no surprises.
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
# S01: Secret Forecasting & Manifest — UAT
|
||||
|
||||
**Milestone:** M002
|
||||
**Written:** 2026-03-12
|
||||
|
||||
## UAT Type
|
||||
|
||||
- UAT mode: artifact-driven
|
||||
- Why this mode is sufficient: S01 is a contract slice — types, parser, formatter, template, and prompt instructions. No runtime behavior to test. All verification is via automated tests, build checks, and file content inspection.
|
||||
|
||||
## Preconditions
|
||||
|
||||
- Repository checked out with S01 changes applied
|
||||
- Node.js available for `npm run build` and `npm run test`
|
||||
|
||||
## Smoke Test
|
||||
|
||||
Run `npm run test` — all `parseSecretsManifest` test groups should pass (7 groups visible in output).
|
||||
|
||||
## Test Cases
|
||||
|
||||
### 1. Manifest parser handles well-formed input
|
||||
|
||||
1. Run `npm run test`
|
||||
2. Look for `parseSecretsManifest: full manifest with 3 keys` test group
|
||||
3. **Expected:** All assertions pass — 3 entries parsed with correct key, service, dashboardUrl, guidance steps, formatHint, status, and destination
|
||||
|
||||
### 2. Round-trip preserves semantic content
|
||||
|
||||
1. Run `npm run test`
|
||||
2. Look for `parseSecretsManifest + formatSecretsManifest: round-trip` test group
|
||||
3. **Expected:** Parsing a manifest, formatting it, and re-parsing produces identical data
|
||||
|
||||
### 3. Template loads with secretsOutputPath variable
|
||||
|
||||
1. Run `grep -n 'secretsOutputPath' src/resources/extensions/gsd/auto.ts src/resources/extensions/gsd/guided-flow.ts`
|
||||
2. **Expected:** Variable is computed via `relMilestoneFile` and passed to `loadPrompt` in both files
|
||||
|
||||
### 4. Prompts contain forecasting instructions
|
||||
|
||||
1. Run `grep 'Secret Forecasting\|secretsOutputPath\|skip this step entirely' src/resources/extensions/gsd/prompts/plan-milestone.md src/resources/extensions/gsd/prompts/guided-plan-milestone.md`
|
||||
2. **Expected:** Both prompts contain the forecasting section header or instructions, the `{{secretsOutputPath}}` variable, and the skip instruction
|
||||
|
||||
### 5. Build succeeds
|
||||
|
||||
1. Run `npm run build`
|
||||
2. **Expected:** Clean compilation, no type errors
|
||||
|
||||
## Edge Cases
|
||||
|
||||
### Empty/no-secrets manifest
|
||||
|
||||
1. Run `npm run test`
|
||||
2. Look for `parseSecretsManifest: empty/no-secrets manifest` test group
|
||||
3. **Expected:** Returns a manifest object with zero entries — no errors thrown
|
||||
|
||||
### Missing optional fields
|
||||
|
||||
1. Run `npm run test`
|
||||
2. Look for `parseSecretsManifest: missing optional fields default correctly` test group
|
||||
3. **Expected:** dashboardUrl defaults to empty string, formatHint defaults to empty string, status defaults to "pending", destination defaults to "dotenv"
|
||||
|
||||
### Invalid status values
|
||||
|
||||
1. Run `npm run test`
|
||||
2. Look for `parseSecretsManifest: invalid status defaults to pending` test group
|
||||
3. **Expected:** Unrecognized status values silently default to "pending"
|
||||
|
||||
## Failure Signals
|
||||
|
||||
- Any `parseSecretsManifest` test group failing
|
||||
- `npm run build` producing type errors in types.ts or files.ts
|
||||
- `secretsOutputPath` missing from auto.ts or guided-flow.ts grep output
|
||||
- Prompt files missing `{{secretsOutputPath}}` variable
|
||||
|
||||
## Requirements Proved By This UAT
|
||||
|
||||
- R001 — Contract proven: prompt instructions exist, manifest types and parser established. Runtime proof deferred to S04.
|
||||
- R002 — Contract proven: manifest format defined with parser, writer, template. Persistence tested via fixture data.
|
||||
- R003 — Contract proven: manifest format includes guidance (string[]), dashboardUrl, formatHint per key.
|
||||
- R009 — Fully proven: both planning prompts contain forecasting instructions with secretsOutputPath variable.
|
||||
|
||||
## Not Proven By This UAT
|
||||
|
||||
- R001 runtime: actual LLM compliance — does the LLM produce a parseable manifest? (S04)
|
||||
- R002 runtime: manifest file actually written to disk during planning (S03/S04)
|
||||
- R003 quality: is the LLM-generated guidance actually useful? (S04, human judgment)
|
||||
- R004–R008, R010: not in S01 scope (S02, S03)
|
||||
|
||||
## Notes for Tester
|
||||
|
||||
All verification is automated — run `npm run build` and `npm run test`. No manual runtime testing needed for this slice. The 2 pre-existing test failures (initResources sync, npm pack) are unrelated to S01 changes.
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
---
|
||||
estimated_steps: 5
|
||||
estimated_files: 4
|
||||
---
|
||||
|
||||
# T01: Manifest types, parser/writer, template, and tests
|
||||
|
||||
**Slice:** S01 — Secret Forecasting & Manifest
|
||||
**Milestone:** M002
|
||||
|
||||
## Description
|
||||
|
||||
Establish the complete secrets manifest contract: TypeScript interfaces for manifest entries and the manifest itself, a forgiving regex-based parser, a canonical markdown writer, a template file defining the format, and comprehensive tests proving the parser handles LLM output variations. This is the foundation that S02 (collection UX) and S03 (auto-mode integration) depend on.
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Add types to `types.ts`** — Define `SecretsManifestEntryStatus` literal union (`'pending' | 'collected' | 'skipped'`), `SecretsManifestEntry` interface (key, service, dashboardUrl, guidance: string[], formatHint, status, destination), and `SecretsManifest` interface (milestone, generatedAt, entries: SecretsManifestEntry[]). Place after the existing `Roadmap`/`SlicePlan` types section.
|
||||
|
||||
2. **Create `templates/secrets-manifest.md`** — Define the canonical manifest format with H1 title, bold metadata fields (Milestone, Generated), and H3 sections per key containing bold fields (Service, Dashboard, Format hint, Status, Destination) and a numbered Guidance list. Include comments explaining the format for both LLM and human readers.
|
||||
|
||||
3. **Implement `parseSecretsManifest()` in `files.ts`** — Use `extractAllSections(content, 3)` to find per-key sections. For each H3 section: extract the env var name from the heading (e.g. `### OPENAI_API_KEY`), use `extractBoldField` for service/dashboardUrl/formatHint/status/destination, and extract the Guidance subsection's numbered list. Default missing optional fields gracefully (empty string for dashboardUrl/formatHint, `'pending'` for status, `'dotenv'` for destination). Extract milestone and generatedAt from the top-level bold fields.
|
||||
|
||||
4. **Implement `formatSecretsManifest()` in `files.ts`** — Write the manifest back to canonical markdown format matching the template. H1 with "Secrets Manifest", bold Milestone and Generated fields, then H3 sections per entry with all fields and numbered guidance steps.
|
||||
|
||||
5. **Add parser tests to `parsers.test.ts`** — Following the existing `assert`/`assertEq` pattern: (a) full manifest with 3 keys — verify all fields parse, (b) single-key manifest — verify it works, (c) empty/no-secrets manifest with no H3 sections — returns empty entries array, (d) missing optional fields (no Dashboard, no Format hint) — defaults correctly, (e) all three status values parse, (f) round-trip test — `formatSecretsManifest(parseSecretsManifest(content))` then re-parse and compare fields.
|
||||
|
||||
## Must-Haves
|
||||
|
||||
- [ ] `SecretsManifestEntry` and `SecretsManifest` interfaces exported from `types.ts`
|
||||
- [ ] `parseSecretsManifest()` exported from `files.ts` — forgiving, regex-based, uses existing helpers
|
||||
- [ ] `formatSecretsManifest()` exported from `files.ts` — produces canonical markdown
|
||||
- [ ] `templates/secrets-manifest.md` exists with the canonical format
|
||||
- [ ] Parser handles missing optional fields without throwing
|
||||
- [ ] Parser returns empty entries array for manifests with no keys
|
||||
- [ ] All parser tests pass
|
||||
- [ ] `npm run build` passes
|
||||
|
||||
## Verification
|
||||
|
||||
- `npm run build` — TypeScript compiles with new types and functions
|
||||
- `npm run test` — all tests pass, including new manifest parser tests
|
||||
- New test output shows: full manifest parse, single-key, empty, missing fields, status values, round-trip
|
||||
|
||||
## Observability Impact
|
||||
|
||||
- Signals added/changed: None — pure data contract, no runtime behavior
|
||||
- How a future agent inspects this: Read `types.ts` for interfaces, read `templates/secrets-manifest.md` for format, run parser tests for validation
|
||||
- Failure state exposed: Parser returns empty/default values for unparseable sections rather than throwing — consistent with `parseRoadmap` convention
|
||||
|
||||
## Inputs
|
||||
|
||||
- `src/resources/extensions/gsd/types.ts` — existing type definitions to extend
|
||||
- `src/resources/extensions/gsd/files.ts` — existing parsing helpers to reuse (`extractSection`, `extractAllSections`, `extractBoldField`, `parseBullets`)
|
||||
- `src/resources/extensions/gsd/tests/parsers.test.ts` — existing test file pattern to follow
|
||||
- `src/resources/extensions/get-secrets-from-user.ts` — reference for key schema (`{ key, hint, required }`) for forward-compatibility
|
||||
|
||||
## Expected Output
|
||||
|
||||
- `src/resources/extensions/gsd/types.ts` — extended with `SecretsManifestEntryStatus`, `SecretsManifestEntry`, `SecretsManifest`
|
||||
- `src/resources/extensions/gsd/files.ts` — extended with `parseSecretsManifest()` and `formatSecretsManifest()`
|
||||
- `src/resources/extensions/gsd/templates/secrets-manifest.md` — new template file
|
||||
- `src/resources/extensions/gsd/tests/parsers.test.ts` — extended with manifest parser test suite
|
||||
|
|
@ -1,60 +0,0 @@
|
|||
---
|
||||
id: T01
|
||||
parent: S01
|
||||
milestone: M002
|
||||
provides:
|
||||
- SecretsManifestEntry and SecretsManifest types
|
||||
- parseSecretsManifest() parser
|
||||
- formatSecretsManifest() writer
|
||||
- secrets-manifest.md template
|
||||
key_files:
|
||||
- src/resources/extensions/gsd/types.ts
|
||||
- src/resources/extensions/gsd/files.ts
|
||||
- src/resources/extensions/gsd/templates/secrets-manifest.md
|
||||
- src/resources/extensions/gsd/tests/parsers.test.ts
|
||||
key_decisions:
|
||||
- Numbered list extraction via regex rather than reusing parseBullets (which strips numbers)
|
||||
patterns_established:
|
||||
- Secrets manifest uses H3 headings per env var key with bold metadata fields
|
||||
- Parser defaults missing optional fields (dashboardUrl, formatHint → empty string; status → pending; destination → dotenv)
|
||||
- Invalid status values silently default to pending
|
||||
observability_surfaces:
|
||||
- Parser tests exercise all code paths — 312 assertions across 7 manifest test groups
|
||||
duration: 15min
|
||||
verification_result: passed
|
||||
completed_at: 2026-03-12T19:40:00Z
|
||||
blocker_discovered: false
|
||||
---
|
||||
|
||||
# T01: Manifest types, parser/writer, template, and tests
|
||||
|
||||
**Added SecretsManifest types, forgiving parser, canonical formatter, template file, and 7 test groups (312 assertions) to the GSD extension.**
|
||||
|
||||
## What Happened
|
||||
|
||||
Added `SecretsManifestEntryStatus`, `SecretsManifestEntry`, and `SecretsManifest` interfaces to `types.ts`. Implemented `parseSecretsManifest()` using existing `extractAllSections(content, 3)`, `extractBoldField`, and regex-based numbered list extraction. Implemented `formatSecretsManifest()` that produces canonical markdown with conditional Dashboard/Format hint fields. Created `templates/secrets-manifest.md` with the canonical format and inline comments. Added 7 test groups to `parsers.test.ts`: full 3-key manifest, single-key, empty/no-secrets, missing optional fields, all three status values, invalid status defaulting, and round-trip parse→format→re-parse.
|
||||
|
||||
## Verification
|
||||
|
||||
- `npm run build` — passes clean
|
||||
- `npm run test` — parsers.test.ts: 312 passed, 0 failed. All 7 manifest test groups pass.
|
||||
- Pre-existing 2 failures in `app-smoke.test.ts` (AGENTS.md sync) are unrelated
|
||||
|
||||
## Diagnostics
|
||||
|
||||
Parser tests are the inspection surface. Run `npm run test` and look for `parseSecretsManifest` test groups. Parser returns empty arrays for unparseable sections and defaults missing fields rather than throwing.
|
||||
|
||||
## Deviations
|
||||
|
||||
None.
|
||||
|
||||
## Known Issues
|
||||
|
||||
None.
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
- `src/resources/extensions/gsd/types.ts` — added SecretsManifestEntryStatus, SecretsManifestEntry, SecretsManifest types
|
||||
- `src/resources/extensions/gsd/files.ts` — added parseSecretsManifest() and formatSecretsManifest() with imports
|
||||
- `src/resources/extensions/gsd/templates/secrets-manifest.md` — new canonical manifest template
|
||||
- `src/resources/extensions/gsd/tests/parsers.test.ts` — added 7 manifest parser/formatter test groups
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
---
|
||||
estimated_steps: 5
|
||||
estimated_files: 4
|
||||
---
|
||||
|
||||
# T02: Planning prompt modifications and auto.ts wiring
|
||||
|
||||
**Slice:** S01 — Secret Forecasting & Manifest
|
||||
**Milestone:** M002
|
||||
|
||||
## Description
|
||||
|
||||
Modify the milestone planning prompts to instruct the LLM to forecast which external API keys a milestone will need and write a secrets manifest file. Wire the `secretsOutputPath` template variable through `buildPlanMilestonePrompt()` so the prompt can tell the LLM where to write the manifest. This delivers R001 (secret forecasting) and R009 (planning prompts instruct forecasting).
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Append secret forecasting section to `plan-milestone.md`** — Add a new section after the existing Planning Doctrine section (before the final `When done` line). The section should: instruct the LLM to analyze each slice and its boundary map for external service dependencies; tell it to write a `{{secretsOutputPath}}` file using the format from `~/.gsd/agent/extensions/gsd/templates/secrets-manifest.md`; include clear skip instruction ("If this milestone does not require any external API keys or secrets, skip this step entirely — do not create an empty manifest"); reference the template for format guidance; and emphasize that guidance should include dashboard URL, numbered navigation steps, and format hints.
|
||||
|
||||
2. **Append equivalent instructions to `guided-plan-milestone.md`** — Same forecasting instructions adapted for the guided flow format (single paragraph, no inlined context). Include the `{{secretsOutputPath}}` variable. Keep the instruction self-contained.
|
||||
|
||||
3. **Update `buildPlanMilestonePrompt()` in `auto.ts`** — Compute `secretsOutputPath` using `relMilestoneFile(base, mid, "SECRETS")`. The file won't exist yet (it's being created by the LLM during planning), so use the relative path format `milestoneId + "-SECRETS.md"` resolved to the milestone directory. Add `secretsOutputPath` to the vars object passed to `loadPrompt("plan-milestone", {...})`.
|
||||
|
||||
4. **Update guided flow in `guided-flow.ts`** — The guided flow's `loadPrompt("guided-plan-milestone", {...})` call at ~line 612 currently passes only `milestoneId` and `milestoneTitle`. Add `secretsOutputPath` to this vars object, computed the same way as in auto.ts. This ensures the guided `/gsd` wizard also tells the LLM to write the manifest.
|
||||
|
||||
5. **Verify full build and test suite** — Run `npm run build` to confirm TypeScript compiles with all changes. Run `npm run test` to confirm no regressions. Manually verify `loadPrompt("plan-milestone", {...})` won't throw by confirming all `{{vars}}` in the template have matching keys in the vars object.
|
||||
|
||||
## Must-Haves
|
||||
|
||||
- [ ] `plan-milestone.md` contains secret forecasting instructions with `{{secretsOutputPath}}` variable
|
||||
- [ ] `guided-plan-milestone.md` contains equivalent secret forecasting instructions with `{{secretsOutputPath}}`
|
||||
- [ ] `buildPlanMilestonePrompt()` computes and passes `secretsOutputPath` to `loadPrompt`
|
||||
- [ ] Instructions clearly say to skip manifest creation when no external APIs are needed
|
||||
- [ ] Instructions reference the `secrets-manifest.md` template
|
||||
- [ ] `guided-flow.ts` passes `secretsOutputPath` to the guided plan-milestone prompt
|
||||
- [ ] `npm run build` passes
|
||||
- [ ] `npm run test` passes (no new failures)
|
||||
|
||||
## Verification
|
||||
|
||||
- `npm run build` — TypeScript compiles cleanly
|
||||
- `npm run test` — all existing + new parser tests pass
|
||||
- Grep `plan-milestone.md` for `{{secretsOutputPath}}` — present
|
||||
- Grep `guided-plan-milestone.md` for `{{secretsOutputPath}}` — present
|
||||
- Grep `auto.ts` `buildPlanMilestonePrompt` for `secretsOutputPath` — present in vars object
|
||||
|
||||
## Observability Impact
|
||||
|
||||
- Signals added/changed: None — prompt template changes have no runtime signals
|
||||
- How a future agent inspects this: Read the prompt templates to see forecasting instructions; read `auto.ts` to see the variable wiring
|
||||
- Failure state exposed: `loadPrompt` throws with a clear error message if `{{secretsOutputPath}}` is declared in the template but not provided in vars — this is the existing prompt-loader safeguard
|
||||
|
||||
## Inputs
|
||||
|
||||
- `src/resources/extensions/gsd/prompts/plan-milestone.md` — existing prompt to extend
|
||||
- `src/resources/extensions/gsd/prompts/guided-plan-milestone.md` — existing guided prompt to extend
|
||||
- `src/resources/extensions/gsd/auto.ts` — `buildPlanMilestonePrompt()` at ~line 1347
|
||||
- `src/resources/extensions/gsd/guided-flow.ts` — guided flow `loadPrompt` call at ~line 612
|
||||
- `src/resources/extensions/gsd/templates/secrets-manifest.md` — template created in T01 (referenced by prompt instructions)
|
||||
- T01 output: types and parser are in place, template exists
|
||||
|
||||
## Expected Output
|
||||
|
||||
- `src/resources/extensions/gsd/prompts/plan-milestone.md` — extended with secret forecasting section
|
||||
- `src/resources/extensions/gsd/prompts/guided-plan-milestone.md` — extended with secret forecasting instructions
|
||||
- `src/resources/extensions/gsd/auto.ts` — `buildPlanMilestonePrompt()` passes `secretsOutputPath` variable
|
||||
- `src/resources/extensions/gsd/guided-flow.ts` — guided flow passes `secretsOutputPath` to prompt
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
---
|
||||
id: T02
|
||||
parent: S01
|
||||
milestone: M002
|
||||
provides:
|
||||
- Secret forecasting instructions in plan-milestone prompt
|
||||
- Secret forecasting instructions in guided-plan-milestone prompt
|
||||
- secretsOutputPath variable wired through buildPlanMilestonePrompt() and guided flow
|
||||
key_files:
|
||||
- src/resources/extensions/gsd/prompts/plan-milestone.md
|
||||
- src/resources/extensions/gsd/prompts/guided-plan-milestone.md
|
||||
- src/resources/extensions/gsd/auto.ts
|
||||
- src/resources/extensions/gsd/guided-flow.ts
|
||||
key_decisions:
|
||||
- Secret forecasting section placed after Planning Doctrine, before the final "You MUST write" line in plan-milestone.md
|
||||
- Guided prompt uses a single self-contained paragraph instead of the structured multi-step format used in the auto prompt
|
||||
patterns_established:
|
||||
- Template variable secretsOutputPath computed via relMilestoneFile(base, mid, "SECRETS") — produces paths like .gsd/milestones/M002/M002-SECRETS.md
|
||||
observability_surfaces:
|
||||
- loadPrompt throws with a clear error if {{secretsOutputPath}} is declared in template but not provided in vars — this is the existing prompt-loader safeguard
|
||||
duration: 12 minutes
|
||||
verification_result: passed
|
||||
completed_at: 2026-03-12
|
||||
blocker_discovered: false
|
||||
---
|
||||
|
||||
# T02: Planning prompt modifications and auto.ts wiring
|
||||
|
||||
**Added secret forecasting instructions to both milestone planning prompts and wired the `secretsOutputPath` template variable through `buildPlanMilestonePrompt()` and the guided flow.**
|
||||
|
||||
## What Happened
|
||||
|
||||
Extended both `plan-milestone.md` and `guided-plan-milestone.md` with a "Secret Forecasting" section that instructs the LLM to analyze slices for external service dependencies and write a secrets manifest file. The auto prompt uses a structured multi-step format with explicit field descriptions. The guided prompt condenses the same instructions into a single self-contained paragraph.
|
||||
|
||||
Wired `secretsOutputPath` through both code paths:
|
||||
- `buildPlanMilestonePrompt()` in `auto.ts` computes the path via `relMilestoneFile(base, mid, "SECRETS")` and passes it to `loadPrompt`
|
||||
- The guided flow in `guided-flow.ts` does the same at the `loadPrompt("guided-plan-milestone", ...)` call site
|
||||
|
||||
Both prompts include: the skip instruction for milestones with no external APIs, a reference to the `secrets-manifest.md` template, guidance on dashboard URLs, format hints, and numbered navigation steps.
|
||||
|
||||
## Verification
|
||||
|
||||
- `npm run build` — TypeScript compiles cleanly
|
||||
- `npm run test` — 54 pass, 2 pre-existing failures (initResources sync and npm pack tests, verified identical before and after changes)
|
||||
- Grep `plan-milestone.md` for `{{secretsOutputPath}}` — present
|
||||
- Grep `guided-plan-milestone.md` for `{{secretsOutputPath}}` — present
|
||||
- Grep `auto.ts` for `secretsOutputPath` — present in vars object within `buildPlanMilestonePrompt()`
|
||||
- Grep `guided-flow.ts` for `secretsOutputPath` — present in guided plan prompt call
|
||||
- Grep both prompts for skip instruction ("skip this step entirely") — present in both
|
||||
- Grep both prompts for template reference ("secrets-manifest.md") — present in both
|
||||
|
||||
### Slice-level verification status
|
||||
|
||||
- `npm run test` — ✅ passes (no regressions)
|
||||
- `npm run build` — ✅ passes
|
||||
- Manifest parser tests — ✅ (established in T01, still passing)
|
||||
- Template loads with new `secretsOutputPath` variable — ✅ (loadPrompt safeguard would throw if var was missing)
|
||||
|
||||
## Diagnostics
|
||||
|
||||
No runtime diagnostics — these are prompt template changes and static variable wiring. Inspection is via reading the prompt files and the `auto.ts`/`guided-flow.ts` source. The `loadPrompt` safeguard throws a clear error if `{{secretsOutputPath}}` is declared in a template but not provided in vars.
|
||||
|
||||
## Deviations
|
||||
|
||||
None.
|
||||
|
||||
## Known Issues
|
||||
|
||||
None.
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
- `src/resources/extensions/gsd/prompts/plan-milestone.md` — Added Secret Forecasting section with `{{secretsOutputPath}}` variable
|
||||
- `src/resources/extensions/gsd/prompts/guided-plan-milestone.md` — Added equivalent Secret Forecasting paragraph with `{{secretsOutputPath}}`
|
||||
- `src/resources/extensions/gsd/auto.ts` — Added `secretsOutputPath` computation and passing in `buildPlanMilestonePrompt()`
|
||||
- `src/resources/extensions/gsd/guided-flow.ts` — Added `secretsOutputPath` computation and passing in guided plan prompt call
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
# S02 Roadmap Assessment
|
||||
|
||||
## Verdict: Roadmap is fine — no slice changes needed
|
||||
|
||||
S02 delivered the shared ASCII logo module (`src/logo.ts`) and wired it into both the postinstall script and the first-launch banner. This was the planned scope.
|
||||
|
||||
## Success Criterion Coverage
|
||||
|
||||
- "After `npm install -g gsd-pi`, the terminal shows a clean branded postinstall flow with the GSD ASCII logo, spinners, staged progress, and boxed summary" → **S01 ✅, S02 ✅** (fully proven)
|
||||
- "On first `gsd` launch, a unified onboarding wizard guides the user through LLM provider auth" → **S03** (remaining owner)
|
||||
- "After completing onboarding, the user drops straight into a working TUI session with an authenticated LLM" → **S03** (remaining owner)
|
||||
- "Users who skip onboarding or already have auth configured go straight to the TUI with no friction" → **S03** (remaining owner)
|
||||
- "The entire flow is visually polished" → **S01 ✅, S02 ✅, S03** (remaining owner for wizard polish)
|
||||
|
||||
All criteria have at least one remaining owner. Coverage check passes.
|
||||
|
||||
## Risk Status
|
||||
|
||||
Two risks were originally attributed to S02 in the proof strategy but were never in S02's actual scope (S02 was logo-only):
|
||||
|
||||
- **OAuth outside TUI** — unretired, now owned by S03
|
||||
- **Clack → TUI handoff** — unretired, now owned by S03
|
||||
|
||||
Updated the proof strategy in M002-ROADMAP.md to correctly attribute these to S03.
|
||||
|
||||
S03 is `risk:high` precisely because it carries both of these risks. No change to risk posture — just correcting the documentation to match reality.
|
||||
|
||||
## Boundary Map
|
||||
|
||||
Still accurate. S02 produced the shared logo constant that S03 consumes. No changes needed.
|
||||
|
||||
## Requirement Coverage
|
||||
|
||||
Sound. R008 (npm install experience) is covered by S01+S02. The roadmap references R012 (first-run onboarding) which maps to S03. No requirement ownership changes.
|
||||
|
||||
## What Changed
|
||||
|
||||
Only the proof strategy text in M002-ROADMAP.md — corrected OAuth and Clack→TUI risk retirement targets from S02 to S03.
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
# S02: Enhanced Collection UX
|
||||
|
||||
**Goal:** `secure_env_collect` gains four capabilities: multi-line guidance display per key, a summary screen before collection, existing-key detection with silent skip, and automatic destination inference from project context.
|
||||
**Demo:** Running the enhanced tool with a test manifest (keys with guidance) shows a summary screen listing all needed keys, silently skips keys already in the environment, auto-detects the write destination, and displays step-by-step guidance during per-key collection. Unit tests prove the utility functions. Build passes.
|
||||
|
||||
## Must-Haves
|
||||
|
||||
- `guidance` field (optional `string[]`) added to the `keys` TypeBox schema — backward compatible with existing callers
|
||||
- `destination` parameter made optional — auto-detected via `detectDestination()` when omitted
|
||||
- `checkExistingEnvKeys(keys, envFilePath, cwd)` exported and unit-tested — checks both `.env` file and `process.env`, handles missing `.env` gracefully, treats empty-string values as existing
|
||||
- `detectDestination(basePath)` exported and unit-tested — checks for `vercel.json` → "vercel", `convex/` dir → "convex", fallback → "dotenv"
|
||||
- Summary screen TUI component using `makeUI()` — renders before per-key collection when guidance is present, shows all keys with service context and guidance steps, user presses enter to continue
|
||||
- Per-key collection screen enhanced to show numbered guidance steps below the hint
|
||||
- `execute()` wired: auto-detect destination → check existing keys → show summary → collect remaining keys with guidance
|
||||
- All existing callers that provide `destination` and omit `guidance` work identically (backward compat)
|
||||
- `npm run build` passes
|
||||
- `npm run test` passes (54 pass, 2 pre-existing failures)
|
||||
|
||||
## Proof Level
|
||||
|
||||
- This slice proves: contract
|
||||
- Real runtime required: no (utility functions are unit-tested; TUI components are contract-proven via TypeScript compilation and structural render)
|
||||
- Human/UAT required: no (TUI visual quality is structure-proven; real UX validation happens in S04 end-to-end)
|
||||
|
||||
## Verification
|
||||
|
||||
- `npm run test -- --test-name-pattern "secure_env_collect"` — all new tests pass
|
||||
- `npm run build` — clean compilation
|
||||
- `npm run test` — 54+ pass, 2 pre-existing failures
|
||||
- Test file: `src/resources/extensions/gsd/tests/secure-env-collect.test.ts`
|
||||
- `checkExistingEnvKeys`: finds keys in `.env` file, finds keys in `process.env`, handles missing `.env`, treats empty values as existing, returns only existing keys from input list
|
||||
- `detectDestination`: returns "vercel" when `vercel.json` exists, returns "convex" when `convex/` dir exists, returns "dotenv" as fallback, checks vercel before convex when both exist
|
||||
|
||||
## Observability / Diagnostics
|
||||
|
||||
- Runtime signals: Summary screen render logs key count and skip count to the result details. The `execute()` result includes `autoDetected: true` when destination was inferred.
|
||||
- Inspection surfaces: The tool's result `details` object gains `existingSkipped: string[]` listing keys that were silently skipped, and `detectedDestination: string` when auto-detection was used.
|
||||
- Failure visibility: `checkExistingEnvKeys` silently handles ENOENT (returns empty array for file checks). `detectDestination` always returns a valid value (fallback "dotenv"). Errors during collection are already captured in the result's error array.
|
||||
- Redaction constraints: Secret values never appear in logs, result details, or summary screen. Only key names are displayed.
|
||||
|
||||
## Integration Closure
|
||||
|
||||
- Upstream surfaces consumed: `shared/ui.ts` (`makeUI()` design system), `shared/confirm-ui.ts` (pattern reference for `ctx.ui.custom()` components)
|
||||
- New wiring introduced in this slice: `checkExistingEnvKeys()` and `detectDestination()` exported for S03 consumption. `guidance` field on TypeBox schema available for S03 callers. Summary screen function available as internal module function.
|
||||
- What remains before the milestone is truly usable end-to-end: S03 (auto-mode dispatches collect-secrets phase, guided flow triggers collection, reads manifest and passes entries to enhanced tool), S04 (end-to-end verification)
|
||||
|
||||
## Tasks
|
||||
|
||||
- [x] **T01: Add utility functions with tests and schema changes** `est:25m`
|
||||
- Why: Establishes the testable foundation — `checkExistingEnvKeys`, `detectDestination`, and the `guidance`/optional-`destination` schema changes. All non-TUI code. Tests prove the utilities work before the TUI integration task.
|
||||
- Files: `src/resources/extensions/get-secrets-from-user.ts`, `src/resources/extensions/gsd/tests/secure-env-collect.test.ts`
|
||||
- Do: Create test file with assertions for both utility functions. Add `checkExistingEnvKeys(keys, envFilePath, cwd)` — reads `.env` with try/catch, checks `process.env`, returns keys that already exist. Add `detectDestination(basePath)` — checks `vercel.json` (existsSync), `convex/` dir (existsSync), fallback "dotenv". Make `destination` optional in TypeBox schema with `Type.Optional()`. Add `guidance` field as `Type.Optional(Type.Array(Type.String()))` to key items. Update `execute()` to default destination via `detectDestination(ctx.cwd)` when not provided. Handle `params.destination` being `string | undefined`.
|
||||
- Verify: `npm run test -- --test-name-pattern "secure_env_collect"` passes; `npm run build` passes; `npm run test` — 54+ pass
|
||||
- Done when: Both utility functions are exported, unit-tested, and the schema accepts optional `destination` and `guidance` fields without breaking existing callers
|
||||
|
||||
- [ ] **T02: Build summary screen, enhance guidance display, and wire execute flow** `est:30m`
|
||||
- Why: Delivers the user-facing UX — the summary screen before collection, numbered guidance in per-key screens, and the full execute flow with existing-key skip and auto-detection wired in. Completes all four R004/R005/R006/R010 requirements.
|
||||
- Files: `src/resources/extensions/get-secrets-from-user.ts`, `src/resources/extensions/shared/ui.ts` (reference only)
|
||||
- Do: Add `showSecretsSummary()` function using `ctx.ui.custom()` + `makeUI()` — renders key list with `progressItem()` per key (pending status), `progressAnnotation()` for each guidance step, hints line with "enter to continue", returns void on enter/escape. Enhance `collectOneSecret()` to accept `guidance: string[] | undefined` parameter — render numbered guidance steps below hint using `theme.fg("muted")`. Wire `execute()`: (1) resolve destination via `detectDestination` if not provided, (2) call `checkExistingEnvKeys` to get existing keys, (3) filter keys list to only uncollected ones, (4) if any keys have guidance, call `showSecretsSummary()` with all original keys (marking existing ones as done), (5) loop through filtered keys calling `collectOneSecret` with guidance. Update result `details` to include `existingSkipped` and `detectedDestination`.
|
||||
- Verify: `npm run build` passes; `npm run test` — 54+ pass (no regressions); summary screen function exists and compiles; execute flow handles all code paths
|
||||
- Done when: The full execute flow works — auto-detects destination, skips existing keys, shows summary, displays guidance per key, collects remaining, and reports results with skip/detection metadata
|
||||
|
||||
## Files Likely Touched
|
||||
|
||||
- `src/resources/extensions/get-secrets-from-user.ts` — main target: utilities, schema, summary screen, execute wiring
|
||||
- `src/resources/extensions/gsd/tests/secure-env-collect.test.ts` — new test file for utility functions
|
||||
- `src/resources/extensions/shared/ui.ts` — imported by summary screen (no modifications)
|
||||
- `src/resources/extensions/shared/confirm-ui.ts` — pattern reference (no modifications)
|
||||
|
|
@ -1,62 +0,0 @@
|
|||
---
|
||||
estimated_steps: 5
|
||||
estimated_files: 2
|
||||
---
|
||||
|
||||
# T01: Add utility functions with tests and schema changes
|
||||
|
||||
**Slice:** S02 — Enhanced Collection UX
|
||||
**Milestone:** M002
|
||||
|
||||
## Description
|
||||
|
||||
Establishes the non-TUI foundation for S02: two exported utility functions (`checkExistingEnvKeys` and `detectDestination`), their unit tests, and the TypeBox schema changes (optional `destination`, new `guidance` field on keys). The execute function gains destination auto-detection when `destination` is omitted. No TUI changes — that's T02.
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Create test file** `src/resources/extensions/gsd/tests/secure-env-collect.test.ts` with test groups for `checkExistingEnvKeys` and `detectDestination`. Use Node's built-in test runner (`node:test` + `node:assert`). Tests should initially fail (functions don't exist yet). Test cases:
|
||||
- `checkExistingEnvKeys`: key found in `.env` file, key found in `process.env`, key found in both, key not found anywhere, `.env` file doesn't exist (ENOENT → still checks process.env), empty-string value in process.env counts as existing, returns only existing keys from input list
|
||||
- `detectDestination`: returns "vercel" when `vercel.json` exists in basePath, returns "convex" when `convex/` dir exists in basePath, returns "dotenv" when neither exists, vercel takes priority when both exist
|
||||
|
||||
2. **Implement `checkExistingEnvKeys`** in `get-secrets-from-user.ts`. Export it. Signature: `async function checkExistingEnvKeys(keys: string[], envFilePath: string): Promise<string[]>`. Reads `.env` with try/catch (ENOENT → empty content). For each key: check if regex `^KEY\s*=` matches in file content OR `key in process.env` (including empty string values). Return array of keys that exist. Reuse the regex pattern from `writeEnvKey` for consistency.
|
||||
|
||||
3. **Implement `detectDestination`** in `get-secrets-from-user.ts`. Export it. Signature: `function detectDestination(basePath: string): "dotenv" | "vercel" | "convex"`. Uses `existsSync` from `node:fs` (synchronous, fine for one-shot check). Check `resolve(basePath, "vercel.json")` → "vercel". Check `resolve(basePath, "convex")` with `statSync` for directory → "convex". Fallback → "dotenv". Import `existsSync` and `statSync` from `node:fs`.
|
||||
|
||||
4. **Update TypeBox schema**: Make `destination` optional with `Type.Optional(Type.Union([...]))`. Add `guidance` to keys items: `Type.Optional(Type.Array(Type.String(), { description: "Step-by-step guidance for finding this key" }))`. Update the `ToolResultDetails` interface to add `existingSkipped?: string[]` and `detectedDestination?: string`.
|
||||
|
||||
5. **Update `execute()` destination handling**: At the top of execute, add: `const destination = params.destination ?? detectDestination(ctx.cwd)`. Replace all subsequent `params.destination` references with `destination`. Track whether destination was auto-detected for result details.
|
||||
|
||||
## Must-Haves
|
||||
|
||||
- [ ] `checkExistingEnvKeys` exported, checks both `.env` and `process.env`, handles ENOENT, treats empty values as existing
|
||||
- [ ] `detectDestination` exported, checks vercel.json then convex/ dir, fallback dotenv
|
||||
- [ ] `destination` parameter is optional in TypeBox schema
|
||||
- [ ] `guidance` field is optional `string[]` on key items in TypeBox schema
|
||||
- [ ] `execute()` auto-detects destination when not provided
|
||||
- [ ] All tests in `secure-env-collect.test.ts` pass
|
||||
- [ ] `npm run build` passes
|
||||
- [ ] `npm run test` — 54+ pass, 2 pre-existing failures only
|
||||
|
||||
## Verification
|
||||
|
||||
- `npm run test -- --test-name-pattern "secure_env_collect"` — all new test assertions pass
|
||||
- `npm run build` — clean TypeScript compilation (catches schema type mismatches)
|
||||
- `npm run test` — no new failures beyond the 2 pre-existing ones
|
||||
|
||||
## Observability Impact
|
||||
|
||||
- Signals added/changed: `ToolResultDetails` gains `existingSkipped` and `detectedDestination` fields — these surface in the tool result for agent inspection
|
||||
- How a future agent inspects this: The tool result `details` object shows which keys were auto-skipped and whether destination was inferred
|
||||
- Failure state exposed: `checkExistingEnvKeys` silently handles ENOENT (no error thrown, returns subset). `detectDestination` always returns a valid value.
|
||||
|
||||
## Inputs
|
||||
|
||||
- `src/resources/extensions/get-secrets-from-user.ts` — existing 352-line tool implementation
|
||||
- `src/resources/extensions/shared/confirm-ui.ts` — pattern reference for imports (not modified)
|
||||
- D008 — silent skip for existing keys, no confirmation
|
||||
- D009 — destination inferred from project context, fallback to .env
|
||||
|
||||
## Expected Output
|
||||
|
||||
- `src/resources/extensions/gsd/tests/secure-env-collect.test.ts` — new test file with ~15-20 test cases for both utility functions
|
||||
- `src/resources/extensions/get-secrets-from-user.ts` — gains `checkExistingEnvKeys()`, `detectDestination()`, updated TypeBox schema, updated execute() destination handling
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
---
|
||||
id: T01
|
||||
parent: S02
|
||||
milestone: M002
|
||||
provides:
|
||||
- checkExistingEnvKeys utility function (exported)
|
||||
- detectDestination utility function (exported)
|
||||
- optional destination parameter in TypeBox schema
|
||||
- guidance field on key items in TypeBox schema
|
||||
- auto-detection of destination in execute()
|
||||
key_files:
|
||||
- src/resources/extensions/get-secrets-from-user.ts
|
||||
- src/resources/extensions/gsd/tests/secure-env-collect.test.ts
|
||||
key_decisions:
|
||||
- Used `key in process.env` check (not `process.env[key] !== undefined`) to match empty-string-as-existing semantics
|
||||
- detectDestination is synchronous (existsSync/statSync) — fine for one-shot project detection
|
||||
patterns_established:
|
||||
- Test file naming: `secure-env-collect.test.ts` uses node:test + node:assert/strict with temp dirs for fs isolation
|
||||
observability_surfaces:
|
||||
- ToolResultDetails.detectedDestination — present when destination was auto-inferred
|
||||
- ToolResultDetails.existingSkipped — ready for T02 to populate with silently skipped keys
|
||||
duration: 12m
|
||||
verification_result: passed
|
||||
completed_at: 2026-03-12
|
||||
blocker_discovered: false
|
||||
---
|
||||
|
||||
# T01: Add utility functions with tests and schema changes
|
||||
|
||||
**Added `checkExistingEnvKeys` and `detectDestination` utilities with 12 unit tests, made `destination` optional with auto-detection, and added `guidance` field to key schema.**
|
||||
|
||||
## What Happened
|
||||
|
||||
Created two exported utility functions in `get-secrets-from-user.ts`:
|
||||
|
||||
1. **`checkExistingEnvKeys(keys, envFilePath)`** — reads `.env` file content (ENOENT-safe), then for each key checks if it exists in the file via regex (`^KEY\s*=`) or in `process.env` (including empty-string values). Returns the subset of keys that already exist.
|
||||
|
||||
2. **`detectDestination(basePath)`** — checks for `vercel.json` (→ "vercel"), then `convex/` directory (→ "convex"), fallback → "dotenv". Uses `existsSync`/`statSync` for synchronous one-shot detection.
|
||||
|
||||
Updated the TypeBox schema: `destination` is now `Type.Optional(Type.Union([...]))`, and keys gain `guidance: Type.Optional(Type.Array(Type.String()))`.
|
||||
|
||||
Updated `execute()` to auto-detect destination when not provided, tracking whether detection occurred in the result details. The `ToolResultDetails` interface gained `existingSkipped` and `detectedDestination` fields.
|
||||
|
||||
Created 12 unit tests covering both functions (7 for `checkExistingEnvKeys`, 5 for `detectDestination`) using `node:test` + `node:assert/strict` with temp directory isolation.
|
||||
|
||||
## Verification
|
||||
|
||||
- `npm run build` — clean compilation, no type errors
|
||||
- `npm run test -- --test-name-pattern "secure_env_collect"` — all 12 tests pass
|
||||
- `npm run test` — 66 pass, 2 fail (pre-existing AGENTS.md failures in app-smoke.test.ts)
|
||||
|
||||
### Slice-level verification status (T01 of 2):
|
||||
- ✅ `npm run test -- --test-name-pattern "secure_env_collect"` — all new tests pass
|
||||
- ✅ `npm run build` — clean compilation
|
||||
- ✅ `npm run test` — 66 pass, 2 pre-existing failures only
|
||||
|
||||
## Diagnostics
|
||||
|
||||
- `ToolResultDetails.detectedDestination` surfaces in tool result when destination was auto-inferred (agent can inspect this)
|
||||
- `ToolResultDetails.existingSkipped` field is defined but not yet populated — T02 will wire `checkExistingEnvKeys` into the execute flow to populate it
|
||||
- `checkExistingEnvKeys` silently handles ENOENT (no error thrown, returns subset based on process.env)
|
||||
- `detectDestination` always returns a valid value (fallback "dotenv")
|
||||
|
||||
## Deviations
|
||||
|
||||
- Added a bonus test: `detectDestination — convex file (not dir) does not trigger convex` — verifies that a regular file named `convex` doesn't falsely trigger convex detection
|
||||
- `renderCall` updated to show "auto" when destination is not provided (minor backward-compat improvement not in plan)
|
||||
|
||||
## Known Issues
|
||||
|
||||
None.
|
||||
|
||||
## Files Created/Modified
|
||||
|
||||
- `src/resources/extensions/get-secrets-from-user.ts` — added `checkExistingEnvKeys()`, `detectDestination()`, updated TypeBox schema (optional destination, guidance field), updated execute() with auto-detection, updated ToolResultDetails interface
|
||||
- `src/resources/extensions/gsd/tests/secure-env-collect.test.ts` — new test file with 12 test cases for both utility functions
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
---
|
||||
estimated_steps: 5
|
||||
estimated_files: 2
|
||||
---
|
||||
|
||||
# T02: Build summary screen, enhance guidance display, and wire execute flow
|
||||
|
||||
**Slice:** S02 — Enhanced Collection UX
|
||||
**Milestone:** M002
|
||||
|
||||
## Description
|
||||
|
||||
Delivers the user-facing TUI enhancements: a summary screen showing all needed keys with guidance before collection begins, numbered guidance steps in each per-key collection screen, and the full wired execute flow that skips existing keys and shows the summary. This completes the slice by connecting T01's utilities into the real collection pipeline.
|
||||
|
||||
## Steps
|
||||
|
||||
1. **Add `showSecretsSummary()` function** in `get-secrets-from-user.ts`. Import `makeUI` from `./shared/ui.js`. Signature: `async function showSecretsSummary(ctx, keys, existingKeys)` where keys is the full array with guidance and existingKeys is the set of already-present key names. Uses `ctx.ui.custom()` following the `confirm-ui.ts` pattern. Render function:
|
||||
- `ui.bar()`, `ui.blank()`, `ui.header(" Secret Collection")`, `ui.meta(" N keys needed · M already configured")`
|
||||
- `ui.blank()`
|
||||
- For each key: `ui.progressItem(key.key, existingKeys.has(key.key) ? "done" : "pending", { detail: key.hint ?? "" })`. If key has guidance: render each step as `ui.progressAnnotation("N. step text")`.
|
||||
- `ui.blank()`, `ui.hints(["enter to continue"])`, `ui.bar()`
|
||||
- Handle input: enter or escape → `done(null)`. No cursor navigation needed (informational display).
|
||||
|
||||
2. **Enhance `collectOneSecret()` to display guidance** — Add `guidance: string[] | undefined` parameter after `hint`. In the render function, after the hint line and before "Preview:", add a numbered guidance list: for each guidance step, render `theme.fg("muted", ` ${i+1}. ${step}`)`. Add a blank line after guidance if present.
|
||||
|
||||
3. **Wire existing-key skip into `execute()`** — After destination resolution (from T01), call `checkExistingEnvKeys(params.keys.map(k => k.key), envFilePath)` where envFilePath is `resolve(ctx.cwd, params.envFilePath ?? ".env")` for dotenv destinations (for vercel/convex, only check `process.env` by passing a nonexistent path). Build a `Set<string>` of existing keys. Filter `params.keys` to `remainingKeys` (those not in the existing set). Track `existingSkipped` as the existing key names.
|
||||
|
||||
4. **Wire summary screen into `execute()`** — After existing-key detection, if any key in the original `params.keys` array has a `guidance` field with entries, call `showSecretsSummary(ctx, params.keys, existingKeySet)`. This shows ALL keys (existing marked as done, remaining marked as pending) so the user sees the full picture.
|
||||
|
||||
5. **Wire guidance into collection loop and update result details** — Change the collection loop to iterate over `remainingKeys` instead of `params.keys`. Pass `item.guidance` to `collectOneSecret()`. Update result details: add `existingSkipped` array and `detectedDestination` string (when auto-detected). Verify the result text includes skipped-existing keys in the summary output (e.g., `⊘ KEY: already configured`).
|
||||
|
||||
## Must-Haves
|
||||
|
||||
- [ ] `showSecretsSummary()` renders via `ctx.ui.custom()` using `makeUI()` with `progressItem()` and `progressAnnotation()`
|
||||
- [ ] Summary screen shows existing keys as "done" status and remaining keys as "pending"
|
||||
- [ ] Summary screen displays numbered guidance steps per key via `progressAnnotation()`
|
||||
- [ ] `collectOneSecret()` renders numbered guidance steps below hint
|
||||
- [ ] `execute()` calls `checkExistingEnvKeys` and silently skips existing keys
|
||||
- [ ] `execute()` shows summary screen when any key has guidance
|
||||
- [ ] `execute()` only collects remaining (non-existing) keys
|
||||
- [ ] Result details include `existingSkipped` array and `detectedDestination` string
|
||||
- [ ] Result text summary includes already-configured keys with distinct marker
|
||||
- [ ] `npm run build` passes
|
||||
- [ ] `npm run test` — 54+ pass, 2 pre-existing failures only
|
||||
|
||||
## Verification
|
||||
|
||||
- `npm run build` — clean compilation (TypeScript catches type mismatches in TUI component render functions, `makeUI()` usage, `progressItem()`/`progressAnnotation()` calls)
|
||||
- `npm run test` — no new failures (TUI changes don't break existing test suite)
|
||||
- Manual code review: `showSecretsSummary()` follows `confirm-ui.ts` pattern (render/handleInput/invalidate triple), uses `makeUI()` consistently
|
||||
|
||||
## Observability Impact
|
||||
|
||||
- Signals added/changed: Result details gain `existingSkipped: string[]` and `detectedDestination: string` — visible in tool result for the calling LLM agent
|
||||
- How a future agent inspects this: Tool result `details` shows which keys were skipped (existing) vs collected vs user-skipped, and whether destination was auto-detected
|
||||
- Failure state exposed: If summary screen fails to render, `ctx.ui.custom` will throw — caught by the existing execute error handling. Missing `makeUI` import would be caught at build time.
|
||||
|
||||
## Inputs
|
||||
|
||||
- `src/resources/extensions/get-secrets-from-user.ts` — after T01 modifications (has `checkExistingEnvKeys`, `detectDestination`, updated schema with `guidance` and optional `destination`)
|
||||
- `src/resources/extensions/shared/ui.ts` — `makeUI()` with `progressItem()`, `progressAnnotation()`, `bar()`, `header()`, `meta()`, `hints()`, `blank()`
|
||||
- `src/resources/extensions/shared/confirm-ui.ts` — pattern for `ctx.ui.custom()` render/handleInput/invalidate triple
|
||||
- S01 forward intelligence: guidance is `string[]`, display as numbered list not paragraph
|
||||
|
||||
## Expected Output
|
||||
|
||||
- `src/resources/extensions/get-secrets-from-user.ts` — gains `showSecretsSummary()`, enhanced `collectOneSecret()` with guidance display, fully wired `execute()` flow with skip + summary + guidance. All four R004/R005/R006/R010 capabilities working.
|
||||
Loading…
Add table
Reference in a new issue