diff --git a/src/config/schema/commands.ts b/src/config/schema/commands.ts index 714580729..95e0aa395 100644 --- a/src/config/schema/commands.ts +++ b/src/config/schema/commands.ts @@ -9,6 +9,11 @@ export const BuiltinCommandNameSchema = z.enum([ "start-work", "stop-continuation", "remove-ai-slops", + "wiki-init", + "wiki-ingest", + "wiki-query", + "wiki-lint", + "wiki-update", ]) export type BuiltinCommandName = z.infer diff --git a/src/features/builtin-commands/commands.test.ts b/src/features/builtin-commands/commands.test.ts index 0849b1555..4b0a06a71 100644 --- a/src/features/builtin-commands/commands.test.ts +++ b/src/features/builtin-commands/commands.test.ts @@ -4,6 +4,11 @@ import { afterEach, beforeEach, describe, test, expect } from "bun:test" import { loadBuiltinCommands } from "./commands" import { HANDOFF_TEMPLATE } from "./templates/handoff" import { REMOVE_AI_SLOPS_TEMPLATE } from "./templates/remove-ai-slops" +import { WIKI_INIT_TEMPLATE } from "./templates/wiki-init" +import { WIKI_INGEST_TEMPLATE } from "./templates/wiki-ingest" +import { WIKI_QUERY_TEMPLATE } from "./templates/wiki-query" +import { WIKI_LINT_TEMPLATE } from "./templates/wiki-lint" +import { WIKI_UPDATE_TEMPLATE } from "./templates/wiki-update" import type { BuiltinCommandName } from "./types" import { _resetForTesting, registerAgentName } from "../claude-code-session-state" @@ -259,3 +264,374 @@ describe("HANDOFF_TEMPLATE", () => { expect(emojiRegex.test(HANDOFF_TEMPLATE)).toBe(false) }) }) + +describe("loadBuiltinCommands - wiki commands", () => { + test("should register wiki-init in loaded commands", () => { + //#given + const disabledCommands: BuiltinCommandName[] = [] + + //#when + const commands = loadBuiltinCommands(disabledCommands) + + //#then + expect(commands["wiki-init"]).toBeDefined() + expect(commands["wiki-init"].name).toBe("wiki-init") + expect(commands["wiki-init"].template).toContain(WIKI_INIT_TEMPLATE) + expect(commands["wiki-init"].description).toContain("(builtin)") + }) + + test("should register wiki-ingest in loaded commands", () => { + //#given + const disabledCommands: BuiltinCommandName[] = [] + + //#when + const commands = loadBuiltinCommands(disabledCommands) + + //#then + expect(commands["wiki-ingest"]).toBeDefined() + expect(commands["wiki-ingest"].name).toBe("wiki-ingest") + expect(commands["wiki-ingest"].template).toContain(WIKI_INGEST_TEMPLATE) + expect(commands["wiki-ingest"].template).toContain("$ARGUMENTS") + }) + + test("should register wiki-query in loaded commands", () => { + //#given + const disabledCommands: BuiltinCommandName[] = [] + + //#when + const commands = loadBuiltinCommands(disabledCommands) + + //#then + expect(commands["wiki-query"]).toBeDefined() + expect(commands["wiki-query"].name).toBe("wiki-query") + expect(commands["wiki-query"].template).toContain(WIKI_QUERY_TEMPLATE) + expect(commands["wiki-query"].template).toContain("$ARGUMENTS") + }) + + test("should register wiki-lint in loaded commands", () => { + //#given + const disabledCommands: BuiltinCommandName[] = [] + + //#when + const commands = loadBuiltinCommands(disabledCommands) + + //#then + expect(commands["wiki-lint"]).toBeDefined() + expect(commands["wiki-lint"].name).toBe("wiki-lint") + expect(commands["wiki-lint"].template).toContain(WIKI_LINT_TEMPLATE) + }) + + test("should register wiki-update in loaded commands", () => { + //#given + const disabledCommands: BuiltinCommandName[] = [] + + //#when + const commands = loadBuiltinCommands(disabledCommands) + + //#then + expect(commands["wiki-update"]).toBeDefined() + expect(commands["wiki-update"].name).toBe("wiki-update") + expect(commands["wiki-update"].template).toContain(WIKI_UPDATE_TEMPLATE) + expect(commands["wiki-update"].template).toContain("$ARGUMENTS") + }) + + test("should exclude wiki-init when disabled", () => { + //#given + const disabledCommands: BuiltinCommandName[] = ["wiki-init"] + + //#when + const commands = loadBuiltinCommands(disabledCommands) + + //#then + expect(commands["wiki-init"]).toBeUndefined() + }) + + test("should exclude wiki-ingest when disabled", () => { + //#given + const disabledCommands: BuiltinCommandName[] = ["wiki-ingest"] + + //#when + const commands = loadBuiltinCommands(disabledCommands) + + //#then + expect(commands["wiki-ingest"]).toBeUndefined() + }) + + test("should exclude wiki-query when disabled", () => { + //#given + const disabledCommands: BuiltinCommandName[] = ["wiki-query"] + + //#when + const commands = loadBuiltinCommands(disabledCommands) + + //#then + expect(commands["wiki-query"]).toBeUndefined() + }) + + test("should exclude wiki-lint when disabled", () => { + //#given + const disabledCommands: BuiltinCommandName[] = ["wiki-lint"] + + //#when + const commands = loadBuiltinCommands(disabledCommands) + + //#then + expect(commands["wiki-lint"]).toBeUndefined() + }) + + test("should exclude wiki-update when disabled", () => { + //#given + const disabledCommands: BuiltinCommandName[] = ["wiki-update"] + + //#when + const commands = loadBuiltinCommands(disabledCommands) + + //#then + expect(commands["wiki-update"]).toBeUndefined() + }) +}) + +describe("WIKI_INIT_TEMPLATE", () => { + test("should reference the canonical wiki root .sisyphus/wiki/", () => { + //#given - the template string + + //#when / #then + expect(WIKI_INIT_TEMPLATE).toContain(".sisyphus/wiki/") + }) + + test("should create the four canonical top-level files and pages directory", () => { + //#given - the template string + + //#when / #then + expect(WIKI_INIT_TEMPLATE).toContain("index.md") + expect(WIKI_INIT_TEMPLATE).toContain("log.md") + expect(WIKI_INIT_TEMPLATE).toContain("overview.md") + expect(WIKI_INIT_TEMPLATE).toContain("SCHEMA.md") + expect(WIKI_INIT_TEMPLATE).toContain("pages/") + }) + + test("should refuse to clobber an existing wiki without explicit user consent", () => { + //#given - the template string + + //#when / #then + expect(WIKI_INIT_TEMPLATE).toContain("already exists") + }) + + test("should declare the page front-matter contract", () => { + //#given - the template string + + //#when / #then + expect(WIKI_INIT_TEMPLATE).toContain("front-matter") + expect(WIKI_INIT_TEMPLATE).toContain("sources") + expect(WIKI_INIT_TEMPLATE).toContain("backlinks") + }) + + test("should not contain emojis", () => { + //#given - the template string + + //#when / #then + const emojiRegex = /[\u{1F600}-\u{1F64F}\u{1F300}-\u{1F5FF}\u{1F680}-\u{1F6FF}\u{1F1E0}-\u{1F1FF}\u{2702}-\u{27B0}\u{24C2}-\u{1F251}\u{1F900}-\u{1F9FF}\u{1FA00}-\u{1FA6F}\u{1FA70}-\u{1FAFF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]/u + expect(emojiRegex.test(WIKI_INIT_TEMPLATE)).toBe(false) + }) +}) + +describe("WIKI_INGEST_TEMPLATE", () => { + test("should require reading the source before writing anything", () => { + //#given - the template string + + //#when / #then + expect(WIKI_INGEST_TEMPLATE).toContain("Read") + expect(WIKI_INGEST_TEMPLATE).toContain("source") + }) + + test("should ban writing claims that are not present in the source", () => { + //#given - the template string + + //#when / #then + expect(WIKI_INGEST_TEMPLATE).toContain("memory") + expect(WIKI_INGEST_TEMPLATE).toContain("only what the source supports") + }) + + test("should require extracting takeaways before drafting the page", () => { + //#given - the template string + + //#when / #then + expect(WIKI_INGEST_TEMPLATE).toContain("Takeaways") + }) + + test("should require updating index.md and appending to log.md", () => { + //#given - the template string + + //#when / #then + expect(WIKI_INGEST_TEMPLATE).toContain("index.md") + expect(WIKI_INGEST_TEMPLATE).toContain("log.md") + }) + + test("should require a backlink audit pass", () => { + //#given - the template string + + //#when / #then + expect(WIKI_INGEST_TEMPLATE).toContain("backlink") + }) + + test("should write pages under .sisyphus/wiki/pages/", () => { + //#given - the template string + + //#when / #then + expect(WIKI_INGEST_TEMPLATE).toContain(".sisyphus/wiki/pages/") + }) + + test("should not contain emojis", () => { + //#given - the template string + + //#when / #then + const emojiRegex = /[\u{1F600}-\u{1F64F}\u{1F300}-\u{1F5FF}\u{1F680}-\u{1F6FF}\u{1F1E0}-\u{1F1FF}\u{2702}-\u{27B0}\u{24C2}-\u{1F251}\u{1F900}-\u{1F9FF}\u{1FA00}-\u{1FA6F}\u{1FA70}-\u{1FAFF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]/u + expect(emojiRegex.test(WIKI_INGEST_TEMPLATE)).toBe(false) + }) +}) + +describe("WIKI_QUERY_TEMPLATE", () => { + test("should answer strictly from wiki contents and never from memory", () => { + //#given - the template string + + //#when / #then + expect(WIKI_QUERY_TEMPLATE).toContain("never") + expect(WIKI_QUERY_TEMPLATE).toContain("memory") + }) + + test("should require reading index.md first", () => { + //#given - the template string + + //#when / #then + expect(WIKI_QUERY_TEMPLATE).toContain("index.md") + }) + + test("should require citing every claim by source", () => { + //#given - the template string + + //#when / #then + expect(WIKI_QUERY_TEMPLATE).toContain("cite") + }) + + test("should offer to save the answer as a new cited page", () => { + //#given - the template string + + //#when / #then + expect(WIKI_QUERY_TEMPLATE).toContain("save") + expect(WIKI_QUERY_TEMPLATE).toContain("page") + }) + + test("should declare an explicit fallback when the wiki has no answer", () => { + //#given - the template string + + //#when / #then + expect(WIKI_QUERY_TEMPLATE).toContain("not in the wiki") + }) + + test("should not contain emojis", () => { + //#given - the template string + + //#when / #then + const emojiRegex = /[\u{1F600}-\u{1F64F}\u{1F300}-\u{1F5FF}\u{1F680}-\u{1F6FF}\u{1F1E0}-\u{1F1FF}\u{2702}-\u{27B0}\u{24C2}-\u{1F251}\u{1F900}-\u{1F9FF}\u{1FA00}-\u{1FA6F}\u{1FA70}-\u{1FAFF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]/u + expect(emojiRegex.test(WIKI_QUERY_TEMPLATE)).toBe(false) + }) +}) + +describe("WIKI_LINT_TEMPLATE", () => { + test("should detect contradictions across pages", () => { + //#given - the template string + + //#when / #then + expect(WIKI_LINT_TEMPLATE).toContain("contradiction") + }) + + test("should detect broken internal links", () => { + //#given - the template string + + //#when / #then + expect(WIKI_LINT_TEMPLATE).toContain("broken link") + }) + + test("should detect orphan pages with no inbound backlinks", () => { + //#given - the template string + + //#when / #then + expect(WIKI_LINT_TEMPLATE).toContain("orphan") + }) + + test("should detect coverage gaps", () => { + //#given - the template string + + //#when / #then + expect(WIKI_LINT_TEMPLATE).toContain("gap") + }) + + test("should write the report to pages/lint-report.md", () => { + //#given - the template string + + //#when / #then + expect(WIKI_LINT_TEMPLATE).toContain("pages/lint-report.md") + }) + + test("should not modify any other page", () => { + //#given - the template string + + //#when / #then + expect(WIKI_LINT_TEMPLATE).toContain("read-only") + }) + + test("should not contain emojis", () => { + //#given - the template string + + //#when / #then + const emojiRegex = /[\u{1F600}-\u{1F64F}\u{1F300}-\u{1F5FF}\u{1F680}-\u{1F6FF}\u{1F1E0}-\u{1F1FF}\u{2702}-\u{27B0}\u{24C2}-\u{1F251}\u{1F900}-\u{1F9FF}\u{1FA00}-\u{1FA6F}\u{1FA70}-\u{1FAFF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]/u + expect(emojiRegex.test(WIKI_LINT_TEMPLATE)).toBe(false) + }) +}) + +describe("WIKI_UPDATE_TEMPLATE", () => { + test("should show diffs of every modified page before writing", () => { + //#given - the template string + + //#when / #then + expect(WIKI_UPDATE_TEMPLATE).toContain("diff") + }) + + test("should require citing the new source for every changed claim", () => { + //#given - the template string + + //#when / #then + expect(WIKI_UPDATE_TEMPLATE).toContain("cite") + expect(WIKI_UPDATE_TEMPLATE).toContain("source") + }) + + test("should sweep stale claims that no longer match the source", () => { + //#given - the template string + + //#when / #then + expect(WIKI_UPDATE_TEMPLATE).toContain("stale") + }) + + test("should append the update to log.md", () => { + //#given - the template string + + //#when / #then + expect(WIKI_UPDATE_TEMPLATE).toContain("log.md") + }) + + test("should bump the updated timestamp in front-matter", () => { + //#given - the template string + + //#when / #then + expect(WIKI_UPDATE_TEMPLATE).toContain("updated") + expect(WIKI_UPDATE_TEMPLATE).toContain("front-matter") + }) + + test("should not contain emojis", () => { + //#given - the template string + + //#when / #then + const emojiRegex = /[\u{1F600}-\u{1F64F}\u{1F300}-\u{1F5FF}\u{1F680}-\u{1F6FF}\u{1F1E0}-\u{1F1FF}\u{2702}-\u{27B0}\u{24C2}-\u{1F251}\u{1F900}-\u{1F9FF}\u{1FA00}-\u{1FA6F}\u{1FA70}-\u{1FAFF}\u{2600}-\u{26FF}\u{2700}-\u{27BF}]/u + expect(emojiRegex.test(WIKI_UPDATE_TEMPLATE)).toBe(false) + }) +}) diff --git a/src/features/builtin-commands/commands.ts b/src/features/builtin-commands/commands.ts index fe581498d..c1a8e5a8f 100644 --- a/src/features/builtin-commands/commands.ts +++ b/src/features/builtin-commands/commands.ts @@ -8,6 +8,11 @@ import { REFACTOR_TEMPLATE } from "./templates/refactor" import { START_WORK_TEMPLATE } from "./templates/start-work" import { HANDOFF_TEMPLATE } from "./templates/handoff" import { REMOVE_AI_SLOPS_TEMPLATE } from "./templates/remove-ai-slops" +import { WIKI_INIT_TEMPLATE } from "./templates/wiki-init" +import { WIKI_INGEST_TEMPLATE } from "./templates/wiki-ingest" +import { WIKI_QUERY_TEMPLATE } from "./templates/wiki-query" +import { WIKI_LINT_TEMPLATE } from "./templates/wiki-lint" +import { WIKI_UPDATE_TEMPLATE } from "./templates/wiki-update" export interface LoadBuiltinCommandsOptions { useRegisteredAgents?: boolean @@ -121,6 +126,51 @@ $ARGUMENTS `, argumentHint: "[goal]", }, + "wiki-init": { + description: "(builtin) Bootstrap a new LLM-maintained wiki for knowledge accumulation", + template: ` +${WIKI_INIT_TEMPLATE} +`, + }, + "wiki-ingest": { + description: "(builtin) Add a source (paper, URL, file, transcript) to the wiki", + template: ` +${WIKI_INGEST_TEMPLATE} + + + +$ARGUMENTS +`, + argumentHint: "", + }, + "wiki-query": { + description: "(builtin) Ask a question against the wiki knowledge base", + template: ` +${WIKI_QUERY_TEMPLATE} + + + +$ARGUMENTS +`, + argumentHint: "", + }, + "wiki-lint": { + description: "(builtin) Health audit: find contradictions, broken links, orphans, and coverage gaps", + template: ` +${WIKI_LINT_TEMPLATE} +`, + }, + "wiki-update": { + description: "(builtin) Revise existing wiki pages when knowledge changes", + template: ` +${WIKI_UPDATE_TEMPLATE} + + + +$ARGUMENTS +`, + argumentHint: "", + }, } } diff --git a/src/features/builtin-commands/templates/wiki-ingest.ts b/src/features/builtin-commands/templates/wiki-ingest.ts new file mode 100644 index 000000000..2e99fc148 --- /dev/null +++ b/src/features/builtin-commands/templates/wiki-ingest.ts @@ -0,0 +1,67 @@ +export const WIKI_INGEST_TEMPLATE = `# /wiki-ingest -- Add Source to Wiki + +Add a source (paper, URL, file, transcript) to the wiki at \`.sisyphus/wiki/\`. + +**CRITICAL: Never write from memory. Write only what the source supports.** + +## Pipeline + +### Step 1: Verify wiki exists +Check \`.sisyphus/wiki/index.md\`. If missing, tell user to run \`/wiki-init\` first. + +### Step 2: Read SCHEMA.md +Read \`.sisyphus/wiki/SCHEMA.md\` for naming conventions. + +### Step 3: Read the source +- File path: use Read tool +- URL: use WebFetch or Read +- Transcript: use provided text + +### Step 4: Extract Takeaways +Identify 5-10 most important facts, concepts, or claims. Be specific, no filler. + +### Step 5: Confirm with user +Show extracted takeaways and ask: +- Which to emphasize? +- Any specific topics for pages? +- One page or multiple? + +Wait for confirmation before writing. + +### Step 6: Create wiki page(s) +Create in \`.sisyphus/wiki/pages/{slug}.md\`: +\`\`\`markdown +# {Title} + +> Sources: {source path or URL} +> Created: {today} +> Updated: {today} + +## Summary +{2-3 sentence summary} + +## Key Points +- {takeaway 1} +- {takeaway 2} + +## Details +{full content} + +## See Also +- [[related-page]] +\`\`\` + +### Step 7: Update index.md +Append: \`- [[slug]] -- one-line summary\`. Keep alphabetical. + +### Step 8: Backlink audit +Read all existing pages. For each, check if new content is relevant. Add bidirectional \`[[new-slug]]\` links to "See Also" sections. + +### Step 9: Update overview.md +Re-read and update the synthesis to include new knowledge. Keep concise. + +### Step 10: Append to log.md +Add: \`| {today} | ingest | Added [[slug]] from {source} |\` + +### Step 11: Confirm +Show: pages created, backlinks added, overview updates.` diff --git a/src/features/builtin-commands/templates/wiki-init.ts b/src/features/builtin-commands/templates/wiki-init.ts new file mode 100644 index 000000000..19a47993f --- /dev/null +++ b/src/features/builtin-commands/templates/wiki-init.ts @@ -0,0 +1,54 @@ +export const WIKI_INIT_TEMPLATE = `# /wiki-init -- Bootstrap LLM Wiki + +Bootstrap a new structured wiki based on Karpathy's LLM Wiki pattern at \`.sisyphus/wiki/\`. + +**Important:** If \`.sisyphus/wiki/\` already exists, warn the user and ask for confirmation before overwriting. + +## Task + +Create the wiki directory structure: + +- .sisyphus/wiki/SCHEMA.md +- .sisyphus/wiki/index.md +- .sisyphus/wiki/log.md +- .sisyphus/wiki/overview.md +- .sisyphus/wiki/pages/.gitkeep + +### SCHEMA.md +Document conventions: +- Wiki root path: \`.sisyphus/wiki/\` +- Page naming: lowercase slugs with hyphens (e.g., \`api-authentication.md\`) +- Link format: \`[[page-slug]]\` for internal wiki links +- Source citation: \`[source: filename or URL]\` +- front-matter: \`# Title\`, \`> Sources: ...\`, \`> Created: date\`, \`> Updated: date\`, \`> Backlinks: ...\` +- Index format: one line per page -- \`- [[slug]] -- one-line summary\` +- All sources must be cited. No claims from memory. +- The backlinks section lists all pages linking to this page. + +### index.md +\`\`\`markdown +# Wiki Index + +*No pages yet. Use /wiki-ingest to add sources.* +\`\`\` + +### log.md +\`\`\`markdown +# Wiki Log + +| Date | Operation | Details | +|------|-----------|---------| +| {today} | init | Wiki bootstrapped | +\`\`\` + +### overview.md +\`\`\`markdown +# Wiki Overview + +*This overview will be automatically updated as pages are added.* +\`\`\` + +### pages/.gitkeep +Create empty file to ensure directory exists. + +After creating all files, confirm what was created and suggest: "Use /wiki-ingest to add your first source."` diff --git a/src/features/builtin-commands/templates/wiki-lint.ts b/src/features/builtin-commands/templates/wiki-lint.ts new file mode 100644 index 000000000..aafcbd1ec --- /dev/null +++ b/src/features/builtin-commands/templates/wiki-lint.ts @@ -0,0 +1,48 @@ +export const WIKI_LINT_TEMPLATE = `# /wiki-lint -- Wiki Health Audit + +Comprehensive read-only health audit of the wiki at \`.sisyphus/wiki/\`. + +This audit is read-only -- it reports issues but does not modify any page except writing the report. + +## Pipeline + +### Step 1: Verify wiki exists +Check \`.sisyphus/wiki/index.md\`. If missing, stop. + +### Step 2: Read everything +Read: SCHEMA.md, index.md, overview.md, and ALL files in pages/. + +### Step 3: Check for issues + +**Broken Links (ERROR)** +Scan all pages for \`[[link]]\` references. Check for any broken link where the target does not exist in pages/. + +**Orphan Pages (WARNING)** +Pages in pages/ not referenced from index.md or any other page. Flag every orphan page found. + +**Index Drift (WARNING)** +Pages in pages/ not in index.md, or index entries pointing to missing pages. + +**Contradictions (ERROR)** +Compare claims across pages. Flag any contradiction where two pages state conflicting facts. + +**Stale Sources (INFO)** +Pages with no "Updated" date or updated more than 30 days ago. + +**Coverage Gaps (INFO)** +Topics in overview.md with no dedicated page. Report each coverage gap found. + +**Link Density (INFO)** +Pages with zero outgoing [[links]]. + +### Step 4: Write report +Create \`.sisyphus/wiki/pages/lint-report.md\` with severity tiers. + +### Step 5: Offer fixes +For each ERROR/WARNING, offer to fix: +- Broken link targets: remove or create missing page +- Orphan pages: add to index +- Contradictions: show both, ask which is correct + +### Step 6: Log +Append to log.md: \`| {today} | lint | {errors} errors, {warnings} warnings |\`` diff --git a/src/features/builtin-commands/templates/wiki-query.ts b/src/features/builtin-commands/templates/wiki-query.ts new file mode 100644 index 000000000..1e4fc927e --- /dev/null +++ b/src/features/builtin-commands/templates/wiki-query.ts @@ -0,0 +1,33 @@ +export const WIKI_QUERY_TEMPLATE = `# /wiki-query -- Query the Wiki + +Answer a question using ONLY the structured wiki at \`.sisyphus/wiki/\`. + +## CRITICAL RULE +**You must never answer from your own knowledge or memory.** Only cite information found in wiki pages. If the wiki doesn't have the answer, say "not in the wiki" explicitly. + +## Pipeline + +### Step 1: Verify wiki exists +Check \`.sisyphus/wiki/index.md\`. If missing, tell user to run \`/wiki-init\`. + +### Step 2: Read the index +Read \`.sisyphus/wiki/index.md\` to see all available pages. + +### Step 3: Identify relevant pages +Based on the question, determine which pages are relevant. Read those pages. + +### Step 4: Follow links +If pages reference other pages via \`[[links]]\`, follow them if relevant. + +### Step 5: Synthesize answer +Compose answer using ONLY wiki content. Cite every claim by source page: +\`According to [[page-slug]], {fact}.\` + +### Step 6: Assess gaps +If partially answerable, clearly state what the wiki covers vs what is "not in the wiki". + +### Step 7: Offer to save +If the answer combines multiple sources into new insight, offer: +"This answer combines information from multiple pages. Save as a new page [[suggested-slug]]?" + +If yes: create page with citations, update index, run backlink audit, log to log.md.` diff --git a/src/features/builtin-commands/templates/wiki-update.ts b/src/features/builtin-commands/templates/wiki-update.ts new file mode 100644 index 000000000..5c267e155 --- /dev/null +++ b/src/features/builtin-commands/templates/wiki-update.ts @@ -0,0 +1,50 @@ +export const WIKI_UPDATE_TEMPLATE = `# /wiki-update -- Revise Wiki Pages + +Update existing wiki pages at \`.sisyphus/wiki/\` with new information. + +## Pipeline + +### Step 1: Verify wiki exists +Check \`.sisyphus/wiki/index.md\`. If missing, stop. + +### Step 2: Read SCHEMA.md +Read conventions from \`.sisyphus/wiki/SCHEMA.md\`. + +### Step 3: Identify affected pages +Based on the update, read index and find all pages containing old/stale information. + +### Step 4: Read affected pages +Read each potentially affected page in full. + +### Step 5: Show diffs BEFORE writing +For EACH page needing changes, show the diff: +\`\`\` +## Page: [[slug]] +### Old content: +> {exact text being replaced} +### New content: +> {proposed replacement} +### Reason: +Cite the new source for this change. +\`\`\` + +**Wait for user confirmation before making any edits.** + +### Step 6: Apply changes +After confirmation: +- Update content +- Bump "updated" date in front-matter +- Add new source to "Sources:" if applicable +- Verify [[links]] still valid + +### Step 7: Sweep stale claims +After updating direct pages, scan ALL other pages for the same stale claim. Show user and offer to fix. + +### Step 8: Update overview.md +If the change affects high-level synthesis, update overview.md. + +### Step 9: Log +Append to log.md: \`| {today} | update | Updated [[page-1]], [[page-2]] -- {reason} |\` + +### Step 10: Confirm +Show: pages updated, stale claims swept, sources cited.` diff --git a/src/features/builtin-commands/types.ts b/src/features/builtin-commands/types.ts index 47a803379..98448ca74 100644 --- a/src/features/builtin-commands/types.ts +++ b/src/features/builtin-commands/types.ts @@ -1,6 +1,20 @@ import type { CommandDefinition } from "../claude-code-command-loader" -export type BuiltinCommandName = "init-deep" | "ralph-loop" | "cancel-ralph" | "ulw-loop" | "refactor" | "start-work" | "stop-continuation" | "handoff" | "remove-ai-slops" +export type BuiltinCommandName = + | "init-deep" + | "ralph-loop" + | "cancel-ralph" + | "ulw-loop" + | "refactor" + | "start-work" + | "stop-continuation" + | "handoff" + | "remove-ai-slops" + | "wiki-init" + | "wiki-ingest" + | "wiki-query" + | "wiki-lint" + | "wiki-update" export interface BuiltinCommandConfig { disabled_commands?: BuiltinCommandName[]