@zelari/core 0.7.10 → 0.7.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,17 +1,17 @@
1
1
  import * as skillsModule from '../../skills.js';
2
- const CLARIFICATION_PROTOCOL = `
3
-
4
- WHEN TO ASK THE USER (clarification):
5
- If a single missing fact would materially change your output (target platform, scope, a binary design choice with significant trade-offs, a constraint you cannot safely assume), pause and ask the user by appending EXACTLY this block at the end of your message:
6
-
7
- ---QUESTION---
8
- { "question": "One focused question", "choices": ["Option A", "Option B", "Option C"], "context": "Why this matters" }
9
- ---END---
10
-
11
- Rules for clarifications:
12
- - Ask AT MOST ONE question per turn, and only when genuinely blocked.
13
- - Prefer a small set of concrete "choices" (2-4). The user can still type a wave-in response.
14
- - Do NOT ask for information that could be reasonably assumed or already in shared context.
2
+ const CLARIFICATION_PROTOCOL = `
3
+
4
+ WHEN TO ASK THE USER (clarification):
5
+ If a single missing fact would materially change your output (target platform, scope, a binary design choice with significant trade-offs, a constraint you cannot safely assume), pause and ask the user by appending EXACTLY this block at the end of your message:
6
+
7
+ ---QUESTION---
8
+ { "question": "One focused question", "choices": ["Option A", "Option B", "Option C"], "context": "Why this matters" }
9
+ ---END---
10
+
11
+ Rules for clarifications:
12
+ - Ask AT MOST ONE question per turn, and only when genuinely blocked.
13
+ - Prefer a small set of concrete "choices" (2-4). The user can still type a wave-in response.
14
+ - Do NOT ask for information that could be reasonably assumed or already in shared context.
15
15
  - If you can proceed with a sound documented assumption, DO SO instead of asking.`;
16
16
  const reproduceBug = {
17
17
  id: 'reproduce-bug',
@@ -43,31 +43,31 @@ const reproduceBug = {
43
43
  {
44
44
  input: 'Bug report: "Council sometimes shows duplicate messages at the start of a session"',
45
45
  output: {
46
- minimalRepro: `// tests/regression/duplicate-messages.test.ts
47
- import { runCouncilPure } from '../agents/councilApi.js';
48
-
49
- describe('council duplicate message bug', () => {
50
- it('does not emit duplicate user message when session resumes', async () => {
51
- const mockProvider = async function* () {
52
- yield { kind: 'text', delta: 'first' };
53
- yield { kind: 'finish', reason: 'stop' };
54
- };
55
- const harness = new AgentHarness({
56
- model: 'test', provider: 'test',
57
- messages: [
58
- { role: 'user', content: 'hi' },
59
- { role: 'user', content: 'hi' }, // duplicate from session resume
60
- ],
61
- tools: [],
62
- providerStream: mockProvider,
63
- });
64
- const events = [];
65
- for await (const e of harness.run()) events.push(e);
66
- const userMessages = events.filter(e => e.type === 'message_delta').length;
67
- expect(userMessages).toBeGreaterThan(0); // sanity
68
- // The actual bug: duplicate is rendered twice
69
- // After fix, expect exactly 1 user message rendered
70
- });
46
+ minimalRepro: `// tests/regression/duplicate-messages.test.ts
47
+ import { runCouncilPure } from '../agents/councilApi.js';
48
+
49
+ describe('council duplicate message bug', () => {
50
+ it('does not emit duplicate user message when session resumes', async () => {
51
+ const mockProvider = async function* () {
52
+ yield { kind: 'text', delta: 'first' };
53
+ yield { kind: 'finish', reason: 'stop' };
54
+ };
55
+ const harness = new AgentHarness({
56
+ model: 'test', provider: 'test',
57
+ messages: [
58
+ { role: 'user', content: 'hi' },
59
+ { role: 'user', content: 'hi' }, // duplicate from session resume
60
+ ],
61
+ tools: [],
62
+ providerStream: mockProvider,
63
+ });
64
+ const events = [];
65
+ for await (const e of harness.run()) events.push(e);
66
+ const userMessages = events.filter(e => e.type === 'message_delta').length;
67
+ expect(userMessages).toBeGreaterThan(0); // sanity
68
+ // The actual bug: duplicate is rendered twice
69
+ // After fix, expect exactly 1 user message rendered
70
+ });
71
71
  });`,
72
72
  reproSteps: [
73
73
  '1. Set up session with duplicate user message in transcript',
@@ -79,28 +79,28 @@ describe('council duplicate message bug', () => {
79
79
  },
80
80
  ],
81
81
  outputSchema: '{ minimalRepro: string; reproSteps: string[]; whyMinimal: string }',
82
- systemPromptFragment: `You are converting a bug report into a minimal failing test.
83
-
84
- ## Methodology
85
- 1. **Read the bug report** carefully: what's the exact symptom? When does it happen?
86
- 2. **Strip to essentials**: remove every agent, tool, env var, user state that isn't strictly required.
87
- 3. **Identify the trigger**: what ONE input causes the bug?
88
- 4. **Write the failing test**: it must FAIL on the current (buggy) code.
89
- 5. **Verify it fails**: the test must fail without any code changes.
90
- 6. **After the fix lands**, the test must PASS.
91
-
92
- ## Output format (JSON-typed)
93
- - minimalRepro: string (the test code, runnable as-is)
94
- - reproSteps: string[] (3-7 numbered steps to reproduce manually)
95
- - whyMinimal: string (what you stripped + why)
96
-
97
- ## Minimal-repro principles
98
- - **One assertion per test** — easier to debug when the test fails
99
- - **Deterministic** — no flaky timing, no random data
100
- - **No external dependencies** — use mocks for network/DB
101
- - **Fast** — under 100ms if possible
102
- - **Independent** — doesn't depend on other tests' state
103
-
82
+ systemPromptFragment: `You are converting a bug report into a minimal failing test.
83
+
84
+ ## Methodology
85
+ 1. **Read the bug report** carefully: what's the exact symptom? When does it happen?
86
+ 2. **Strip to essentials**: remove every agent, tool, env var, user state that isn't strictly required.
87
+ 3. **Identify the trigger**: what ONE input causes the bug?
88
+ 4. **Write the failing test**: it must FAIL on the current (buggy) code.
89
+ 5. **Verify it fails**: the test must fail without any code changes.
90
+ 6. **After the fix lands**, the test must PASS.
91
+
92
+ ## Output format (JSON-typed)
93
+ - minimalRepro: string (the test code, runnable as-is)
94
+ - reproSteps: string[] (3-7 numbered steps to reproduce manually)
95
+ - whyMinimal: string (what you stripped + why)
96
+
97
+ ## Minimal-repro principles
98
+ - **One assertion per test** — easier to debug when the test fails
99
+ - **Deterministic** — no flaky timing, no random data
100
+ - **No external dependencies** — use mocks for network/DB
101
+ - **Fast** — under 100ms if possible
102
+ - **Independent** — doesn't depend on other tests' state
103
+
104
104
  Stay under 300 words.${CLARIFICATION_PROTOCOL}`,
105
105
  };
106
106
  const debugWithRag = {
@@ -136,38 +136,38 @@ const debugWithRag = {
136
136
  ragSearch: 'searchRAG(query="Council.tsx undefined map error") returned 2 prior incidents: similar bug fixed in commit a3f9d by adding optional chaining; another similar issue in Council.tsx:612.',
137
137
  stackTraceAnalysis: 'Line 847 is inside `renderMessages()`. The most likely cause: `messages` is undefined when `runCouncilPure()` returns early on the first iteration before any agent has produced output.',
138
138
  rootCause: 'race condition: messages array is set after the first agent completes, but renderMessages() is called during the loading state when messages is still undefined.',
139
- proposedFix: `function renderMessages() {
140
- const messages = session.messages ?? [];
141
- return messages.map(m => <Message key={m.id} {...m} />);
139
+ proposedFix: `function renderMessages() {
140
+ const messages = session.messages ?? [];
141
+ return messages.map(m => <Message key={m.id} {...m} />);
142
142
  }`,
143
143
  verification: 'Add a unit test that calls renderMessages() with messages=undefined and expects [] (not crash). Manual: trigger the bug scenario, confirm no crash.',
144
144
  },
145
145
  },
146
146
  ],
147
147
  outputSchema: '{ ragSearch: string; stackTraceAnalysis: string; rootCause: string; proposedFix: string; verification: string }',
148
- systemPromptFragment: `You are debugging a bug using the knowledge base.
149
-
150
- ## Methodology
151
- 1. **Extract key terms** from the error message + stack trace (file names, function names, error type).
152
- 2. **Search the knowledge base** with the retrieval tool listed in your AVAILABLE TOOLS (searchDocuments or searchRAG — never call one that is not listed), query: "<key terms>"
153
- 3. **Read the relevant files**: use read_file with line ranges from the stack trace.
154
- 4. **Identify the root cause**: what's the actual logic error? Don't just fix the symptom.
155
- 5. **Propose a minimal fix**: the SMALLEST change that addresses the root cause.
156
- 6. **Specify verification**: how to confirm the fix works (test case + manual steps).
157
-
158
- ## Output format (JSON-typed)
159
- - ragSearch: string (what you searched + what you found)
160
- - stackTraceAnalysis: string (which line + what's likely happening)
161
- - rootCause: string (the actual bug, not the symptom)
162
- - proposedFix: string (code snippet)
163
- - verification: string (test + manual steps)
164
-
165
- ## Debugging principles
166
- - **Fix the cause, not the symptom** (e.g. don't add a try/catch to silence an error)
167
- - **Minimal change** — don't refactor surrounding code while debugging
168
- - **One hypothesis at a time** — don't list 5 possible causes
169
- - **Verify the fix actually fixes** — write a failing test BEFORE the fix
170
-
148
+ systemPromptFragment: `You are debugging a bug using the knowledge base.
149
+
150
+ ## Methodology
151
+ 1. **Extract key terms** from the error message + stack trace (file names, function names, error type).
152
+ 2. **Search the knowledge base** with the retrieval tool listed in your AVAILABLE TOOLS (searchDocuments or searchRAG — never call one that is not listed), query: "<key terms>"
153
+ 3. **Read the relevant files**: use read_file with line ranges from the stack trace.
154
+ 4. **Identify the root cause**: what's the actual logic error? Don't just fix the symptom.
155
+ 5. **Propose a minimal fix**: the SMALLEST change that addresses the root cause.
156
+ 6. **Specify verification**: how to confirm the fix works (test case + manual steps).
157
+
158
+ ## Output format (JSON-typed)
159
+ - ragSearch: string (what you searched + what you found)
160
+ - stackTraceAnalysis: string (which line + what's likely happening)
161
+ - rootCause: string (the actual bug, not the symptom)
162
+ - proposedFix: string (code snippet)
163
+ - verification: string (test + manual steps)
164
+
165
+ ## Debugging principles
166
+ - **Fix the cause, not the symptom** (e.g. don't add a try/catch to silence an error)
167
+ - **Minimal change** — don't refactor surrounding code while debugging
168
+ - **One hypothesis at a time** — don't list 5 possible causes
169
+ - **Verify the fix actually fixes** — write a failing test BEFORE the fix
170
+
171
171
  Stay under 400 words.${CLARIFICATION_PROTOCOL}`,
172
172
  };
173
173
  const rootCauseFiveWhys = {
@@ -215,29 +215,29 @@ const rootCauseFiveWhys = {
215
215
  },
216
216
  ],
217
217
  outputSchema: '{ whys: Array<{ level: number; question: string; answer: string }>; rootCause: string; systemicFix: string; processFix: string; councilConsensus: string }',
218
- systemPromptFragment: `You are applying the 5-whys technique with council consensus.
219
-
220
- ## Methodology
221
- 1. **State the symptom** as the starting point for "why?"
222
- 2. **Ask "why?" 5 times**, drilling down through layers of cause
223
- 3. **Each answer must be FACTUAL**, not speculative
224
- 4. **At the 5th why**, you've reached the systemic root cause
225
- 5. **Propose TWO fixes**: systemic (code/architecture) + process (team/workflow)
226
- 6. **Get council consensus**: chairman summarizes agreement from sisyphus (orchestrator) and oracle (analyst)
227
-
228
- ## Output format (JSON-typed)
229
- - whys: Array<{ level: number; question: string; answer: string }>
230
- - rootCause: string (the deepest why)
231
- - systemicFix: string (code/architecture change)
232
- - processFix: string (team/workflow change)
233
- - councilConsensus: string (chairman's summary of agreement)
234
-
235
- ## Anti-patterns to avoid
236
- - **"Human error"** is NEVER the root cause — the system should make the error impossible
237
- - **"Lack of training"** is NEVER the root cause — automation + checklists > training
238
- - **"Not enough time"** is NEVER the root cause — find the constraint, not the excuse
239
- - Stop at the FIRST level if it's a trivial bug — don't overthink simple cases
240
-
218
+ systemPromptFragment: `You are applying the 5-whys technique with council consensus.
219
+
220
+ ## Methodology
221
+ 1. **State the symptom** as the starting point for "why?"
222
+ 2. **Ask "why?" 5 times**, drilling down through layers of cause
223
+ 3. **Each answer must be FACTUAL**, not speculative
224
+ 4. **At the 5th why**, you've reached the systemic root cause
225
+ 5. **Propose TWO fixes**: systemic (code/architecture) + process (team/workflow)
226
+ 6. **Get council consensus**: chairman summarizes agreement from sisyphus (orchestrator) and oracle (analyst)
227
+
228
+ ## Output format (JSON-typed)
229
+ - whys: Array<{ level: number; question: string; answer: string }>
230
+ - rootCause: string (the deepest why)
231
+ - systemicFix: string (code/architecture change)
232
+ - processFix: string (team/workflow change)
233
+ - councilConsensus: string (chairman's summary of agreement)
234
+
235
+ ## Anti-patterns to avoid
236
+ - **"Human error"** is NEVER the root cause — the system should make the error impossible
237
+ - **"Lack of training"** is NEVER the root cause — automation + checklists > training
238
+ - **"Not enough time"** is NEVER the root cause — find the constraint, not the excuse
239
+ - Stop at the FIRST level if it's a trivial bug — don't overthink simple cases
240
+
241
241
  Stay under 500 words.${CLARIFICATION_PROTOCOL}`,
242
242
  };
243
243
  // prettier-ignore
@@ -1,17 +1,17 @@
1
1
  import { registerCodingSkill } from '../../skills.js';
2
- const CLARIFICATION_PROTOCOL = `
3
-
4
- WHEN TO ASK THE USER (clarification):
5
- If a single missing fact would materially change your output (target platform, scope, a binary design choice with significant trade-offs, a constraint you cannot safely assume), pause and ask the user by appending EXACTLY this block at the end of your message:
6
-
7
- ---QUESTION---
8
- { "question": "One focused question", "choices": ["Option A", "Option B", "Option C"], "context": "Why this matters" }
9
- ---END---
10
-
11
- Rules for clarifications:
12
- - Ask AT MOST ONE question per turn, and only when genuinely blocked.
13
- - Prefer a small set of concrete "choices" (2-4). The user can still type a custom answer.
14
- - Do NOT ask for information that could be reasonably assumed or already in shared context.
2
+ const CLARIFICATION_PROTOCOL = `
3
+
4
+ WHEN TO ASK THE USER (clarification):
5
+ If a single missing fact would materially change your output (target platform, scope, a binary design choice with significant trade-offs, a constraint you cannot safely assume), pause and ask the user by appending EXACTLY this block at the end of your message:
6
+
7
+ ---QUESTION---
8
+ { "question": "One focused question", "choices": ["Option A", "Option B", "Option C"], "context": "Why this matters" }
9
+ ---END---
10
+
11
+ Rules for clarifications:
12
+ - Ask AT MOST ONE question per turn, and only when genuinely blocked.
13
+ - Prefer a small set of concrete "choices" (2-4). The user can still type a custom answer.
14
+ - Do NOT ask for information that could be reasonably assumed or already in shared context.
15
15
  - If you can proceed with a sound documented assumption, DO SO instead of asking.`;
16
16
  const writeReadme = {
17
17
  id: 'write-readme',
@@ -42,81 +42,81 @@ const writeReadme = {
42
42
  {
43
43
  input: 'Generate README for AnathemaBrain (Electron + React + TypeScript AI agent platform)',
44
44
  output: {
45
- readme: `# AnathemaBrain
46
-
47
- > An educational Python project for learning how coding agents are built.
48
-
49
- AnathemaBrain is an Electron desktop app... (truncated)
50
-
51
- ## Quick Start
52
-
53
- \`\`\`bash
54
- npm install
55
- npm run dev
56
- \`\`\`
57
-
58
- ## Architecture
59
-
60
- - **Main process** (electron/main/): Node.js, IPC handlers, LLM streaming
61
- - **Renderer** (src/): React 19 UI, Zustand stores
62
- - **Agent system** (src/agents/): Council multi-agent orchestration
63
-
64
- ## Development
65
-
66
- \`\`\`bash
67
- npm run typecheck
68
- npm run test
69
- npm run lint
70
- \`\`\`
71
-
72
- ## Testing
73
-
74
- 96+ tests via Vitest + jsdom.
75
-
76
- ## Deployment
77
-
78
- \`\`\`bash
79
- npm run build
80
- npm run electron:build
81
- \`\`\`
82
-
83
- ## Contributing
84
-
85
- See docs/plans/ for active roadmaps. Pull requests welcome.
86
-
87
- ## License
88
-
89
- Apache 2.0
45
+ readme: `# AnathemaBrain
46
+
47
+ > An educational Python project for learning how coding agents are built.
48
+
49
+ AnathemaBrain is an Electron desktop app... (truncated)
50
+
51
+ ## Quick Start
52
+
53
+ \`\`\`bash
54
+ npm install
55
+ npm run dev
56
+ \`\`\`
57
+
58
+ ## Architecture
59
+
60
+ - **Main process** (electron/main/): Node.js, IPC handlers, LLM streaming
61
+ - **Renderer** (src/): React 19 UI, Zustand stores
62
+ - **Agent system** (src/agents/): Council multi-agent orchestration
63
+
64
+ ## Development
65
+
66
+ \`\`\`bash
67
+ npm run typecheck
68
+ npm run test
69
+ npm run lint
70
+ \`\`\`
71
+
72
+ ## Testing
73
+
74
+ 96+ tests via Vitest + jsdom.
75
+
76
+ ## Deployment
77
+
78
+ \`\`\`bash
79
+ npm run build
80
+ npm run electron:build
81
+ \`\`\`
82
+
83
+ ## Contributing
84
+
85
+ See docs/plans/ for active roadmaps. Pull requests welcome.
86
+
87
+ ## License
88
+
89
+ Apache 2.0
90
90
  `,
91
91
  sections: ['Title + tagline', 'Badges', 'Description', 'Quick Start', 'Architecture diagram', 'Development commands', 'Testing', 'Deployment', 'Contributing link', 'License'],
92
92
  },
93
93
  },
94
94
  ],
95
95
  outputSchema: '{ readme: string; sections: string[] }',
96
- systemPromptFragment: `You are writing a project README.md.
97
-
98
- ## Required sections (in order)
99
- 1. **Title + tagline** (1 sentence): what is this project?
100
- 2. **Badges** (optional): CI status, npm version, license
101
- 3. **Description** (2-3 paragraphs): what does it do, who is it for
102
- 4. **Quick Start** (5-10 lines): install + run + see something working
103
- 5. **Architecture** (1-2 paragraphs + diagram): high-level structure
104
- 6. **Development** (commands): how to run tests, typecheck, lint
105
- 7. **Testing**: what kind of tests exist, how to run them
106
- 8. **Deployment** (if applicable): how to build + ship
107
- 9. **Contributing**: link to CONTRIBUTING.md or describe PR process
108
- 10. **License**: license type
109
-
110
- ## Output format (JSON-typed)
111
- - readme: string (the full README content in markdown)
112
- - sections: string[] (the sections you included)
113
-
114
- ## README principles
115
- - **Show, don't tell**: code examples for non-trivial concepts
116
- - **Up-to-date**: don't include commands that don't work
117
- - **Scannable**: use headers, bullets, code blocks
118
- - **One page max**: link to deeper docs rather than nesting everything
119
-
96
+ systemPromptFragment: `You are writing a project README.md.
97
+
98
+ ## Required sections (in order)
99
+ 1. **Title + tagline** (1 sentence): what is this project?
100
+ 2. **Badges** (optional): CI status, npm version, license
101
+ 3. **Description** (2-3 paragraphs): what does it do, who is it for
102
+ 4. **Quick Start** (5-10 lines): install + run + see something working
103
+ 5. **Architecture** (1-2 paragraphs + diagram): high-level structure
104
+ 6. **Development** (commands): how to run tests, typecheck, lint
105
+ 7. **Testing**: what kind of tests exist, how to run them
106
+ 8. **Deployment** (if applicable): how to build + ship
107
+ 9. **Contributing**: link to CONTRIBUTING.md or describe PR process
108
+ 10. **License**: license type
109
+
110
+ ## Output format (JSON-typed)
111
+ - readme: string (the full README content in markdown)
112
+ - sections: string[] (the sections you included)
113
+
114
+ ## README principles
115
+ - **Show, don't tell**: code examples for non-trivial concepts
116
+ - **Up-to-date**: don't include commands that don't work
117
+ - **Scannable**: use headers, bullets, code blocks
118
+ - **One page max**: link to deeper docs rather than nesting everything
119
+
120
120
  Stay under 600 words.${CLARIFICATION_PROTOCOL}`,
121
121
  };
122
122
  const writeTsdoc = {
@@ -148,54 +148,54 @@ const writeTsdoc = {
148
148
  {
149
149
  input: 'Add TSDoc to src/lib/formatDuration.ts',
150
150
  output: {
151
- documented: `/**
152
- * Formats a duration in milliseconds as a human-readable string.
153
- *
154
- * @param ms - Duration in milliseconds. Must be a non-negative finite number.
155
- * @param opts - Formatting options.
156
- * @param opts.style - 'compact' (1h 23m), 'full' (1:23:45), or 'minimal' (23m).
157
- * Defaults to 'compact'.
158
- * @returns The formatted duration string.
159
- * @throws {RangeError} If ms is negative.
160
- * @throws {TypeError} If ms is NaN or Infinity.
161
- *
162
- * @example
163
- * formatDuration(4980000); // '1h 23m'
164
- * formatDuration(4980000, { style: 'full' }); // '1:23:45'
165
- * formatDuration(60000, { style: 'minimal' }); // '1m'
166
- */
167
- export function formatDuration(ms: number, opts?: { style?: 'compact' | 'full' | 'minimal' }): string {
168
- // ... existing implementation
151
+ documented: `/**
152
+ * Formats a duration in milliseconds as a human-readable string.
153
+ *
154
+ * @param ms - Duration in milliseconds. Must be a non-negative finite number.
155
+ * @param opts - Formatting options.
156
+ * @param opts.style - 'compact' (1h 23m), 'full' (1:23:45), or 'minimal' (23m).
157
+ * Defaults to 'compact'.
158
+ * @returns The formatted duration string.
159
+ * @throws {RangeError} If ms is negative.
160
+ * @throws {TypeError} If ms is NaN or Infinity.
161
+ *
162
+ * @example
163
+ * formatDuration(4980000); // '1h 23m'
164
+ * formatDuration(4980000, { style: 'full' }); // '1:23:45'
165
+ * formatDuration(60000, { style: 'minimal' }); // '1m'
166
+ */
167
+ export function formatDuration(ms: number, opts?: { style?: 'compact' | 'full' | 'minimal' }): string {
168
+ // ... existing implementation
169
169
  }`,
170
170
  tagsAdded: ['@param', '@param (nested)', '@returns', '@throws x2', '@example'],
171
171
  },
172
172
  },
173
173
  ],
174
174
  outputSchema: '{ documented: string; tagsAdded: string[] }',
175
- systemPromptFragment: `You are writing TSDoc comments for a TypeScript function or class.
176
-
177
- ## TSDoc tags (use these)
178
- - \`@param {type} name - description\` — for each parameter
179
- - \`@returns description\` (or \`@return\` legacy alias)
180
- - \`@throws {ErrorType} condition\` — for each throw path
181
- - \`@example\` followed by code block (for non-trivial usage)
182
- - \`@deprecated reason\` — if the function is being phased out
183
- - \`@see FunctionName\` — for cross-references
184
- - \`@remarks\` — additional context
185
- - \`@internal\` — for internal helpers (suppresses from public docs)
186
-
187
- ## Output format (JSON-typed)
188
- - documented: string (the full code block with TSDoc added)
189
- - tagsAdded: string[] (which tags you included)
190
-
191
- ## TSDoc principles
192
- - **First sentence is the summary**: ends with a period, capital letter
193
- - **One @param per parameter**: don't omit even if obvious
194
- - **@throws for EVERY throw path**: callers need to know
195
- - **@example for non-trivial usage**: best way to communicate intent
196
- - **No marketing language**: just describe what the function does
197
- - **No implementation details**: TSDoc is for the API contract, not internals
198
-
175
+ systemPromptFragment: `You are writing TSDoc comments for a TypeScript function or class.
176
+
177
+ ## TSDoc tags (use these)
178
+ - \`@param {type} name - description\` — for each parameter
179
+ - \`@returns description\` (or \`@return\` legacy alias)
180
+ - \`@throws {ErrorType} condition\` — for each throw path
181
+ - \`@example\` followed by code block (for non-trivial usage)
182
+ - \`@deprecated reason\` — if the function is being phased out
183
+ - \`@see FunctionName\` — for cross-references
184
+ - \`@remarks\` — additional context
185
+ - \`@internal\` — for internal helpers (suppresses from public docs)
186
+
187
+ ## Output format (JSON-typed)
188
+ - documented: string (the full code block with TSDoc added)
189
+ - tagsAdded: string[] (which tags you included)
190
+
191
+ ## TSDoc principles
192
+ - **First sentence is the summary**: ends with a period, capital letter
193
+ - **One @param per parameter**: don't omit even if obvious
194
+ - **@throws for EVERY throw path**: callers need to know
195
+ - **@example for non-trivial usage**: best way to communicate intent
196
+ - **No marketing language**: just describe what the function does
197
+ - **No implementation details**: TSDoc is for the API contract, not internals
198
+
199
199
  Stay under 400 words.${CLARIFICATION_PROTOCOL}`,
200
200
  };
201
201
  const writeChangelog = {
@@ -227,23 +227,23 @@ const writeChangelog = {
227
227
  {
228
228
  input: 'Generate changelog for v0.3.1 from commits since v0.3.0 (last 30 commits)',
229
229
  output: {
230
- changelog: `# Changelog
231
-
232
- All notable changes to zelari-code are documented in this file.
233
-
234
- ## [0.3.1] - 2026-07-01
235
-
236
- ### Added
237
- - **Council roles renamed to Dante's Inferno bosses**: Sisyphus→Caronte, Prometheus→Nettuno, Hephaestus→Gerione, Atlas→Plutone, Oracle→Minosse, Chairman→Lucifero.
238
-
239
- ### Changed
240
- - Versioning aligned across main.ts, package.json, package-lock.json
241
- - Stale Electron path references removed from CLI dispatcher comments
242
-
243
- ### Fixed
244
- - Background update check now compares correct version against npm registry
245
-
246
- [0.3.0] - 2026-07-01
230
+ changelog: `# Changelog
231
+
232
+ All notable changes to zelari-code are documented in this file.
233
+
234
+ ## [0.3.1] - 2026-07-01
235
+
236
+ ### Added
237
+ - **Council roles renamed to Dante's Inferno bosses**: Sisyphus→Caronte, Prometheus→Nettuno, Hephaestus→Gerione, Atlas→Plutone, Oracle→Minosse, Chairman→Lucifero.
238
+
239
+ ### Changed
240
+ - Versioning aligned across main.ts, package.json, package-lock.json
241
+ - Stale Electron path references removed from CLI dispatcher comments
242
+
243
+ ### Fixed
244
+ - Background update check now compares correct version against npm registry
245
+
246
+ [0.3.0] - 2026-07-01
247
247
  ... (previous entries)`,
248
248
  sectionsUsed: ['Added', 'Changed', 'Fixed'],
249
249
  commitsProcessed: 30,
@@ -251,37 +251,37 @@ All notable changes to zelari-code are documented in this file.
251
251
  },
252
252
  ],
253
253
  outputSchema: '{ changelog: string; sectionsUsed: string[]; commitsProcessed: number }',
254
- systemPromptFragment: `You are writing a CHANGELOG.md entry from git history.
255
-
256
- ## Keep a Changelog format
257
- Sections (use only those with content):
258
- - **Added** — new features
259
- - **Changed** — changes in existing functionality
260
- - **Deprecated** — soon-to-be removed features
261
- - **Removed** — now removed features
262
- - **Fixed** — bug fixes
263
- - **Security** — vulnerability fixes
264
-
265
- ## Methodology
266
- 1. **List commits since the last release** (use git log).
267
- 2. **Categorize each commit** into the right section.
268
- 3. **Translate to user-facing language**: "feat: add event bus" → "EventBus: typed in-memory pub/sub".
269
- 4. **Group related commits**: if 5 commits all touch the event system, write ONE entry.
270
- 5. **Skip internal-only changes**: refactors that don't change behavior.
271
- 6. **Add version + date**: top of the entry.
272
-
273
- ## Output format (JSON-typed)
274
- - changelog: string (the full CHANGELOG.md content)
275
- - sectionsUsed: string[] (which sections you wrote)
276
- - commitsProcessed: number
277
-
278
- ## Changelog principles
279
- - **User-facing language**: write for end-users, not developers
280
- - **Group, don't list**: 1 entry per feature, not 1 per commit
281
- - **Highlight breaking changes**: bold or callout
282
- - **Link to issues/PRs**: reference #123, fixes #456
283
- - **Date format**: ISO 8601 (YYYY-MM-DD)
284
-
254
+ systemPromptFragment: `You are writing a CHANGELOG.md entry from git history.
255
+
256
+ ## Keep a Changelog format
257
+ Sections (use only those with content):
258
+ - **Added** — new features
259
+ - **Changed** — changes in existing functionality
260
+ - **Deprecated** — soon-to-be removed features
261
+ - **Removed** — now removed features
262
+ - **Fixed** — bug fixes
263
+ - **Security** — vulnerability fixes
264
+
265
+ ## Methodology
266
+ 1. **List commits since the last release** (use git log).
267
+ 2. **Categorize each commit** into the right section.
268
+ 3. **Translate to user-facing language**: "feat: add event bus" → "EventBus: typed in-memory pub/sub".
269
+ 4. **Group related commits**: if 5 commits all touch the event system, write ONE entry.
270
+ 5. **Skip internal-only changes**: refactors that don't change behavior.
271
+ 6. **Add version + date**: top of the entry.
272
+
273
+ ## Output format (JSON-typed)
274
+ - changelog: string (the full CHANGELOG.md content)
275
+ - sectionsUsed: string[] (which sections you wrote)
276
+ - commitsProcessed: number
277
+
278
+ ## Changelog principles
279
+ - **User-facing language**: write for end-users, not developers
280
+ - **Group, don't list**: 1 entry per feature, not 1 per commit
281
+ - **Highlight breaking changes**: bold or callout
282
+ - **Link to issues/PRs**: reference #123, fixes #456
283
+ - **Date format**: ISO 8601 (YYYY-MM-DD)
284
+
285
285
  Stay under 500 words.${CLARIFICATION_PROTOCOL}`,
286
286
  };
287
287
  // Register all skills