Skip to content

feat(knowledge): Phase 7 — setup wizard#256

Open
leeovery wants to merge 5 commits intofeat/knowledge-base-phase-6from
feat/knowledge-base-phase-7
Open

feat(knowledge): Phase 7 — setup wizard#256
leeovery wants to merge 5 commits intofeat/knowledge-base-phase-6from
feat/knowledge-base-phase-7

Conversation

@leeovery
Copy link
Copy Markdown
Owner

Summary

  • Replaces the knowledge setup stub with a real interactive wizard (src/knowledge/setup.js): system config at ~/.config/workflows/config.json, project init at .workflows/.knowledge/, and initial bulk indexing in one guided readline flow.
  • Non-TTY invocation (Claude, pipes, CI) aborts with a clear "requires an interactive terminal" message. Idempotent: per-step prompts detect existing state; the bulk index naturally skips already-indexed artifacts.
  • Stub-to-full provider upgrade is detected and surfaces a "run knowledge rebuild" instruction rather than auto-rebuilding.
  • cmdIndexBulk is dependency-injected into cmdSetup to avoid a circular require that broke esbuild's CJS wrapping.

Stacks on feat/knowledge-base-phase-6, not main — do not merge until the knowledge-base rollout is ready for go-live.

Test plan

  • bash tests/scripts/test-knowledge-cli.sh — 129 passed (includes new non-TTY-abort + dispatch assertions)
  • node --test tests/scripts/test-knowledge-config.cjs — 39 passed (new unit tests for writeConfigFile, config builders, detectSystemConfig, detectProjectInit)
  • bash tests/scripts/test-workflow-manifest.sh — 176 passed
  • All 37 migration tests green
  • npm run build clean; committed bundle matches source
  • Manual validation (required before merge — interactive prompts can't be automated). Copy .workflows/ to $TMPDIR/kb-phase7-test/ and from there run:
    • Fresh run: prompts for provider, writes system config, creates project dir, indexes files
    • Stub-mode run (choose skip at provider): writes stub config, project init proceeds, indexing runs in keyword-only mode
    • Re-run on fully-configured project: per-step prompts detect existing state; choosing skip at each step exits cleanly with 0 new files indexed
    • Interrupted-then-resumed: Ctrl+C mid-indexing → re-run processes pending queue items
    • Non-TTY abort: echo '' | node .../knowledge.cjs setup → aborts with "requires an interactive terminal" (covered by Test 3)

🤖 Generated with Claude Code

leeovery and others added 5 commits April 19, 2026 17:37
Replace the setup stub with an interactive readline wizard that handles
system config (~/.config/workflows/config.json) and project init
(.workflows/.knowledge/config.json + store.msp + metadata.json) in one
guided flow. Aborts cleanly on non-TTY invocation. Idempotent: fully
configured projects prompt to skip; partial configs are completed.
OpenAI path validates the API key via a test embed; stub path writes a
minimal config for keyword-only mode.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Wire the existing bulk index as the wizard's final step. cmdIndexBulk
is dependency-injected into cmdSetup to avoid a circular require —
esbuild's CJS wrapping breaks `require.main === module` on the entry
when two modules require each other. Readline closes before indexing
so a non-interactive long-running embed pass doesn't leave a lingering
TTY handle. Indexing failures don't abort the setup — the project is
initialised and the pending queue retains partial state. On stub-to-full
upgrade, the wizard surfaces the rebuild instruction rather than
auto-rebuilding. SKILL.md loses the "not yet implemented" wording.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds the credentials-at-rest half of a hybrid auth model: a separate
~/.config/workflows/credentials.json at mode 0600, keyed by provider
({ "credentials": { "openai": { "api_key": "sk-..." } } }), resolved
only when the provider-specific env var (OPENAI_API_KEY for openai)
is not set. Env var wins — matches the AWS SDK pattern.

config.js gains loadCredentials, writeCredentials, resolveApiKey, and
a PROVIDER_ENV_VARS map. loadConfig stops reading api_key_env from
config files and instead delegates to resolveApiKey. Design doc's
Configuration Hierarchy section is rewritten: two config files
(non-secret) plus one credentials file (secret, 0600), explicit
precedence, rationale for the split.

The wizard still writes the old api_key_env field into config.json
— that field is now inert and gets cleaned up in the next commit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Rewrites the openai branch of the setup wizard to match the hybrid
credential model introduced in the previous commit. Flow becomes:

  1. Prompt for model and dimensions.
  2. Write the non-secret system config to disk (can be kept even if
     the key step aborts or the user Ctrl-Cs mid-key-entry).
  3. Resolve the API key via the same precedence loadConfig uses:
       a. $OPENAI_API_KEY if set — validate inline, nothing written.
       b. Existing credentials.json — validate; if broken, offer to
          replace with an inline prompt.
       c. No key anywhere — show the explainer (portal link, dedicated-
          key recommendation, where it's stored, env-override escape
          hatch), prompt inline, validate, write to credentials.json.

Secret input is read through a new askSecret helper: stdin goes into
raw mode during the key prompt, each character is echoed as a '*' so
the key never touches terminal scrollback. Ctrl-C aborts cleanly,
Ctrl-D submits, backspace edits.

Validation failures route through describeValidationError, which maps
common OpenAI responses (401, 403, 429, 5xx, network errors) to a
short cause line plus a practical next-step hint — no raw
"Provider/model changed" errors bubble up to the user.

The api_key_env field is gone from buildSystemConfigOpenAI and from
every wizard prompt. Config.js already ignored it on read.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…silently returning {}

The previous try/catch swallowed every read error, including JSON
parse failures on a corrupt manifest. Callers then initialised
work_units = {}, merged in their own entry, and wrote back — erasing
every previously-registered work unit. This silently ate 7 of 8
work_units in a real project (tick) when an unrelated Go refactor
commit introduced a trailing comma into the manifest and the next
workflow command hit the swallow path.

Now distinguishes ENOENT (legitimate first-write, return {}) from
parse errors and other I/O errors (die with a clear message pointing
the user at the file). Corrupt manifests are preserved on disk —
they're surfaced, not silently overwritten.

Test covers the exact clobber pattern: trailing-comma manifest +
init command. Asserts exit 1, error mentions "not valid JSON" and
"by hand", and the corrupt file is still corrupt afterwards (no
write happened). Also a positive test that missing manifest is
treated as first-write.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant