golem-cc 2.1.2 → 3.0.0

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.
Files changed (84) hide show
  1. package/.claude/commands/golem/build.md +18 -0
  2. package/.claude/commands/golem/config.md +39 -0
  3. package/.claude/commands/golem/continue.md +73 -0
  4. package/.claude/commands/golem/doctor.md +46 -0
  5. package/.claude/commands/golem/document.md +138 -0
  6. package/.claude/commands/golem/help.md +58 -0
  7. package/.claude/commands/golem/pause.md +130 -0
  8. package/.claude/commands/golem/plan.md +111 -0
  9. package/.claude/commands/golem/review.md +166 -0
  10. package/.claude/commands/golem/security.md +186 -0
  11. package/.claude/commands/golem/simplify.md +76 -0
  12. package/.claude/commands/golem/spec.md +105 -0
  13. package/.claude/commands/golem/status.md +33 -0
  14. package/.golem/agents/code-simplifier.md +54 -0
  15. package/.golem/agents/review-architecture.md +59 -0
  16. package/.golem/agents/review-logic.md +50 -0
  17. package/.golem/agents/review-security.md +50 -0
  18. package/.golem/agents/review-style.md +48 -0
  19. package/.golem/agents/review-tests.md +48 -0
  20. package/.golem/agents/spec-builder.md +60 -0
  21. package/.golem/bin/golem.mjs +270 -0
  22. package/.golem/lib/build.mjs +557 -0
  23. package/.golem/lib/claude.mjs +95 -0
  24. package/.golem/lib/config.mjs +421 -0
  25. package/.golem/lib/display.mjs +191 -0
  26. package/.golem/lib/doctor.mjs +197 -0
  27. package/.golem/lib/document.mjs +792 -0
  28. package/.golem/lib/gates.mjs +78 -0
  29. package/.golem/lib/init.mjs +166 -0
  30. package/.golem/lib/output.mjs +40 -0
  31. package/.golem/lib/ratelimit.mjs +86 -0
  32. package/.golem/lib/security.mjs +603 -0
  33. package/.golem/lib/simplify.mjs +101 -0
  34. package/.golem/lib/tui.mjs +368 -0
  35. package/.golem/lib/usage.mjs +119 -0
  36. package/.golem/lib/worktree.mjs +509 -0
  37. package/.golem/prompts/build.md +23 -0
  38. package/.golem/prompts/document-inline.md +66 -0
  39. package/.golem/prompts/document-markdown.md +80 -0
  40. package/.golem/prompts/simplify.md +35 -0
  41. package/README.md +141 -142
  42. package/bin/golem-shim.mjs +36 -0
  43. package/bin/install.mjs +193 -0
  44. package/package.json +27 -32
  45. package/.env.example +0 -17
  46. package/bin/golem +0 -1040
  47. package/commands/golem/build.md +0 -235
  48. package/commands/golem/config.md +0 -55
  49. package/commands/golem/doctor.md +0 -137
  50. package/commands/golem/help.md +0 -212
  51. package/commands/golem/plan.md +0 -214
  52. package/commands/golem/review.md +0 -376
  53. package/commands/golem/security.md +0 -204
  54. package/commands/golem/simplify.md +0 -94
  55. package/commands/golem/spec.md +0 -226
  56. package/commands/golem/status.md +0 -60
  57. package/dist/api/freshworks.d.ts +0 -61
  58. package/dist/api/freshworks.d.ts.map +0 -1
  59. package/dist/api/freshworks.js +0 -119
  60. package/dist/api/freshworks.js.map +0 -1
  61. package/dist/api/gitea.d.ts +0 -96
  62. package/dist/api/gitea.d.ts.map +0 -1
  63. package/dist/api/gitea.js +0 -154
  64. package/dist/api/gitea.js.map +0 -1
  65. package/dist/cli/index.d.ts +0 -9
  66. package/dist/cli/index.d.ts.map +0 -1
  67. package/dist/cli/index.js +0 -352
  68. package/dist/cli/index.js.map +0 -1
  69. package/dist/sync/ticket-sync.d.ts +0 -53
  70. package/dist/sync/ticket-sync.d.ts.map +0 -1
  71. package/dist/sync/ticket-sync.js +0 -226
  72. package/dist/sync/ticket-sync.js.map +0 -1
  73. package/dist/types.d.ts +0 -125
  74. package/dist/types.d.ts.map +0 -1
  75. package/dist/types.js +0 -5
  76. package/dist/types.js.map +0 -1
  77. package/dist/worktree/manager.d.ts +0 -54
  78. package/dist/worktree/manager.d.ts.map +0 -1
  79. package/dist/worktree/manager.js +0 -190
  80. package/dist/worktree/manager.js.map +0 -1
  81. package/golem/agents/code-simplifier.md +0 -81
  82. package/golem/agents/spec-builder.md +0 -90
  83. package/golem/prompts/PROMPT_build.md +0 -71
  84. package/golem/prompts/PROMPT_plan.md +0 -102
@@ -0,0 +1,509 @@
1
+ import { cp, access, stat, realpath } from 'node:fs/promises';
2
+ import { join, resolve, relative, normalize } from 'node:path';
3
+ import { execSync } from 'node:child_process';
4
+ import { expandTilde, getRepoName } from './config.mjs';
5
+ import { table } from './output.mjs';
6
+
7
+ /**
8
+ * Check if a source path should be excluded based on the excludes list.
9
+ * Matches if the source path starts with any exclude entry (after normalization).
10
+ */
11
+ function isExcluded(relPath, excludes) {
12
+ const norm = normalize(relPath).replace(/\/+$/, '');
13
+ return excludes.some(ex => {
14
+ const normEx = normalize(ex).replace(/\/+$/, '');
15
+ return norm === normEx || norm.startsWith(normEx + '/');
16
+ });
17
+ }
18
+
19
+ /**
20
+ * Recursively copy a source to destination, skipping excluded paths.
21
+ * For files: copy if not excluded.
22
+ * For directories: walk and copy non-excluded entries.
23
+ */
24
+ async function copyWithExcludes(src, dest, mainRepoPath, excludes) {
25
+ const relPath = relative(mainRepoPath, src);
26
+
27
+ if (isExcluded(relPath, excludes)) return;
28
+
29
+ const info = await stat(src);
30
+
31
+ if (info.isFile()) {
32
+ await cp(src, dest);
33
+ return;
34
+ }
35
+
36
+ if (info.isDirectory()) {
37
+ const { readdir, mkdir } = await import('node:fs/promises');
38
+ await mkdir(dest, { recursive: true });
39
+ const entries = await readdir(src);
40
+ for (const entry of entries) {
41
+ await copyWithExcludes(join(src, entry), join(dest, entry), mainRepoPath, excludes);
42
+ }
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Bootstrap a worktree by copying configured files and running setup.
48
+ *
49
+ * @param {string} worktreePath - Path to the new worktree directory
50
+ * @param {string} mainRepoPath - Path to the main repository
51
+ * @param {object} config - Loaded golem config (with worktree defaults merged)
52
+ */
53
+ export async function bootstrapWorktree(worktreePath, mainRepoPath, config) {
54
+ const { copies = [], excludes = [], setup = '' } = config.worktree || {};
55
+
56
+ // Copy each entry from main repo to worktree
57
+ for (const entry of copies) {
58
+ const src = join(mainRepoPath, entry);
59
+
60
+ // Skip silently if source doesn't exist
61
+ try {
62
+ await access(src);
63
+ } catch {
64
+ continue;
65
+ }
66
+
67
+ try {
68
+ await copyWithExcludes(src, join(worktreePath, entry), mainRepoPath, excludes);
69
+ } catch (err) {
70
+ console.warn(`Warning: failed to copy ${entry}: ${err.message}`);
71
+ }
72
+ }
73
+
74
+ // Run setup command if configured
75
+ if (setup) {
76
+ try {
77
+ execSync(setup, { cwd: worktreePath, stdio: 'inherit' });
78
+ } catch (err) {
79
+ console.warn(`Warning: setup command failed: ${err.message}`);
80
+ }
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Check if a git branch exists locally.
86
+ */
87
+ function branchExists(name, cwd) {
88
+ try {
89
+ execSync(`git rev-parse --verify refs/heads/${name}`, { cwd, stdio: 'pipe' });
90
+ return true;
91
+ } catch {
92
+ return false;
93
+ }
94
+ }
95
+
96
+ /**
97
+ * Create a new git worktree with bootstrap.
98
+ *
99
+ * @param {string} name - Branch/worktree name
100
+ * @param {object} config - Loaded golem config (with worktree defaults merged)
101
+ * @returns {string} Full path to the created worktree
102
+ */
103
+ export async function worktreeCreate(name, config) {
104
+ if (!name) {
105
+ throw new Error('Worktree name is required. Usage: golem worktree create <name>');
106
+ }
107
+
108
+ const mainRepoPath = process.cwd();
109
+ const repoName = getRepoName();
110
+ const baseDir = expandTilde(config.worktree.dir);
111
+ const worktreePath = join(baseDir, repoName, name);
112
+
113
+ if (branchExists(name, mainRepoPath)) {
114
+ execSync(`git worktree add ${worktreePath} ${name}`, { cwd: mainRepoPath, stdio: 'pipe' });
115
+ } else {
116
+ execSync(`git worktree add -b ${name} ${worktreePath}`, { cwd: mainRepoPath, stdio: 'pipe' });
117
+ }
118
+
119
+ await bootstrapWorktree(worktreePath, mainRepoPath, config);
120
+
121
+ console.log(worktreePath);
122
+ return worktreePath;
123
+ }
124
+
125
+ /**
126
+ * Parse git worktree list --porcelain output into structured data.
127
+ *
128
+ * @param {string} porcelainOutput - Output from `git worktree list --porcelain`
129
+ * @returns {Array<{path: string, head: string, branch: string}>}
130
+ */
131
+ function parseWorktreePorcelain(porcelainOutput) {
132
+ const worktrees = [];
133
+ const lines = porcelainOutput.trim().split('\n');
134
+ let current = {};
135
+
136
+ for (const line of lines) {
137
+ if (line.startsWith('worktree ')) {
138
+ // Start of a new worktree entry
139
+ if (current.path) {
140
+ worktrees.push(current);
141
+ }
142
+ current = { path: line.slice('worktree '.length) };
143
+ } else if (line.startsWith('HEAD ')) {
144
+ current.head = line.slice('HEAD '.length);
145
+ } else if (line.startsWith('branch ')) {
146
+ // Extract branch name from refs/heads/branch-name
147
+ const fullRef = line.slice('branch '.length);
148
+ current.branch = fullRef.replace(/^refs\/heads\//, '');
149
+ } else if (line === '') {
150
+ // Empty line marks end of an entry
151
+ if (current.path) {
152
+ worktrees.push(current);
153
+ current = {};
154
+ }
155
+ }
156
+ }
157
+
158
+ // Push the last entry if it exists
159
+ if (current.path) {
160
+ worktrees.push(current);
161
+ }
162
+
163
+ return worktrees;
164
+ }
165
+
166
+ /**
167
+ * Resolve a path to its real path, following symlinks.
168
+ * Returns the original path if it doesn't exist or can't be resolved.
169
+ */
170
+ async function safeRealpath(path) {
171
+ try {
172
+ return await realpath(path);
173
+ } catch {
174
+ return path;
175
+ }
176
+ }
177
+
178
+ /**
179
+ * Get the repository name from git, even when inside a worktree.
180
+ * First tries to get the name from the git remote URL.
181
+ * Falls back to the main worktree directory name.
182
+ */
183
+ function getRepoNameFromGit() {
184
+ try {
185
+ // Try to get from remote URL
186
+ const remoteUrl = execSync('git remote get-url origin', {
187
+ cwd: process.cwd(),
188
+ stdio: 'pipe',
189
+ encoding: 'utf-8'
190
+ }).trim();
191
+ const lastSegment = remoteUrl.split('/').pop();
192
+ return lastSegment.replace(/\.git$/, '');
193
+ } catch {
194
+ // No remote - parse the main worktree path from git worktree list
195
+ try {
196
+ const output = execSync('git worktree list --porcelain', {
197
+ cwd: process.cwd(),
198
+ stdio: 'pipe',
199
+ encoding: 'utf-8'
200
+ });
201
+
202
+ // The first worktree entry is always the main one
203
+ const lines = output.trim().split('\n');
204
+ for (const line of lines) {
205
+ if (line.startsWith('worktree ')) {
206
+ const mainPath = line.slice('worktree '.length);
207
+ return mainPath.split('/').pop();
208
+ }
209
+ }
210
+
211
+ // Fallback to getRepoName
212
+ return getRepoName();
213
+ } catch {
214
+ // Not in a git repo - fall back to getRepoName()
215
+ return getRepoName();
216
+ }
217
+ }
218
+ }
219
+
220
+ /**
221
+ * List all worktrees for the current repository.
222
+ *
223
+ * @param {object} config - Loaded golem config (with worktree defaults merged)
224
+ * @param {object} opts - Options for display
225
+ * @param {boolean} opts.display - If true, print a formatted table (default: true)
226
+ * @returns {Promise<Array<{path: string, head: string, branch: string, current: boolean}>>}
227
+ */
228
+ export async function worktreeList(config, opts = { display: true }) {
229
+ const repoName = getRepoNameFromGit();
230
+ const baseDir = expandTilde(config.worktree.dir);
231
+
232
+ // Resolve the base dir to handle symlinks (like /var -> /private/var on macOS)
233
+ const baseDirResolved = await safeRealpath(baseDir);
234
+ const expectedPrefix = join(baseDirResolved, repoName);
235
+ const cwd = await safeRealpath(process.cwd());
236
+
237
+ // Get all worktrees
238
+ let output;
239
+ try {
240
+ output = execSync('git worktree list --porcelain', {
241
+ cwd: process.cwd(),
242
+ encoding: 'utf-8',
243
+ stdio: 'pipe',
244
+ });
245
+ } catch (err) {
246
+ throw new Error(`Failed to list worktrees: ${err.message}`);
247
+ }
248
+
249
+ // Parse the porcelain output
250
+ const allWorktrees = parseWorktreePorcelain(output);
251
+
252
+ // Filter to only worktrees under the configured directory for this repo
253
+ const filtered = allWorktrees.filter(wt =>
254
+ wt.path.startsWith(expectedPrefix)
255
+ );
256
+
257
+ // Mark the current worktree if we're inside one
258
+ for (const wt of filtered) {
259
+ wt.current = cwd.startsWith(wt.path);
260
+ }
261
+
262
+ // Display formatted table if requested
263
+ if (opts.display) {
264
+ if (filtered.length === 0) {
265
+ console.log('No worktrees found.');
266
+ } else {
267
+ const rows = filtered.map(wt => [
268
+ wt.current ? '* ' + wt.branch : wt.branch,
269
+ wt.path,
270
+ wt.head.slice(0, 7),
271
+ ]);
272
+ table(['Branch', 'Path', 'HEAD'], rows);
273
+ }
274
+ }
275
+
276
+ return filtered;
277
+ }
278
+
279
+ /**
280
+ * Detect if the current working directory is inside a git worktree.
281
+ * Inside a worktree, --git-common-dir and --git-dir differ.
282
+ *
283
+ * @param {string} cwd - Directory to check
284
+ * @returns {{ isWorktree: boolean, gitCommonDir: string|null, gitDir: string|null }}
285
+ */
286
+ function detectWorktree(cwd) {
287
+ try {
288
+ const gitDir = execSync('git rev-parse --git-dir', {
289
+ cwd, stdio: 'pipe', encoding: 'utf-8',
290
+ }).trim();
291
+ const gitCommonDir = execSync('git rev-parse --git-common-dir', {
292
+ cwd, stdio: 'pipe', encoding: 'utf-8',
293
+ }).trim();
294
+ // Inside a worktree, gitDir is something like /path/to/.git/worktrees/<name>
295
+ // while gitCommonDir is /path/to/.git — they differ.
296
+ // In the main repo, both resolve to .git (or the same absolute path).
297
+ // Use resolve() to handle both relative and absolute paths from git.
298
+ const resolvedDir = resolve(cwd, gitDir);
299
+ const resolvedCommon = resolve(cwd, gitCommonDir);
300
+ return {
301
+ isWorktree: resolvedDir !== resolvedCommon,
302
+ gitCommonDir: resolvedCommon,
303
+ gitDir: resolvedDir,
304
+ };
305
+ } catch {
306
+ return { isWorktree: false, gitCommonDir: null, gitDir: null };
307
+ }
308
+ }
309
+
310
+ /**
311
+ * Detect the default branch name (main or master).
312
+ *
313
+ * @param {string} cwd - Directory to run git commands in
314
+ * @returns {string} The default branch name
315
+ */
316
+ function detectDefaultBranch(cwd) {
317
+ // Check if 'main' exists
318
+ try {
319
+ execSync('git rev-parse --verify refs/heads/main', { cwd, stdio: 'pipe' });
320
+ return 'main';
321
+ } catch {
322
+ // fall through
323
+ }
324
+ // Check if 'master' exists
325
+ try {
326
+ execSync('git rev-parse --verify refs/heads/master', { cwd, stdio: 'pipe' });
327
+ return 'master';
328
+ } catch {
329
+ // fall through
330
+ }
331
+ throw new Error('Could not detect default branch (neither main nor master found).');
332
+ }
333
+
334
+ /**
335
+ * Merge the current worktree branch back into the default branch.
336
+ * Must be run from inside a worktree — fails with clear error otherwise.
337
+ *
338
+ * Steps:
339
+ * 1. Stage and commit any uncommitted changes
340
+ * 2. Save branch name and worktree path
341
+ * 3. Navigate to main repo via git-common-dir/..
342
+ * 4. Remove the worktree (branch/commits survive in .git)
343
+ * 5. Rebase branch onto default branch
344
+ * 6. Switch to default branch
345
+ * 7. Fast-forward merge the branch
346
+ * 8. Delete the branch
347
+ *
348
+ * If rebase fails, stops and prints instructions. Branch and commits are safe.
349
+ */
350
+ export async function worktreeMerge() {
351
+ const cwd = process.cwd();
352
+
353
+ // Step 0: Detect if we're inside a worktree
354
+ const { isWorktree, gitCommonDir } = detectWorktree(cwd);
355
+ if (!isWorktree) {
356
+ throw new Error(
357
+ 'Not inside a worktree. Run this command from inside a worktree directory.'
358
+ );
359
+ }
360
+
361
+ // Step 1: Stage and commit any uncommitted changes
362
+ const status = execSync('git status --porcelain', {
363
+ cwd, stdio: 'pipe', encoding: 'utf-8',
364
+ }).trim();
365
+
366
+ if (status) {
367
+ execSync('git add -A', { cwd, stdio: 'pipe' });
368
+ execSync('git commit -m "wip: uncommitted changes before merge"', {
369
+ cwd, stdio: 'pipe',
370
+ });
371
+ }
372
+
373
+ // Step 2: Save branch name and worktree path
374
+ const branch = execSync('git rev-parse --abbrev-ref HEAD', {
375
+ cwd, stdio: 'pipe', encoding: 'utf-8',
376
+ }).trim();
377
+
378
+ const worktreePath = execSync('git rev-parse --show-toplevel', {
379
+ cwd, stdio: 'pipe', encoding: 'utf-8',
380
+ }).trim();
381
+
382
+ // Step 3: Navigate to main repo via git-common-dir/..
383
+ const mainRepoPath = resolve(gitCommonDir, '..');
384
+
385
+ // Step 4: Remove the worktree (branch and commits are safe in .git)
386
+ execSync(`git worktree remove ${worktreePath}`, {
387
+ cwd: mainRepoPath, stdio: 'pipe',
388
+ });
389
+
390
+ // Step 5: Detect default branch and rebase
391
+ const defaultBranch = detectDefaultBranch(mainRepoPath);
392
+
393
+ try {
394
+ execSync(`git rebase ${defaultBranch} ${branch}`, {
395
+ cwd: mainRepoPath, stdio: 'pipe',
396
+ });
397
+ } catch {
398
+ // Abort the failed rebase so git is clean
399
+ try {
400
+ execSync('git rebase --abort', { cwd: mainRepoPath, stdio: 'pipe' });
401
+ } catch {
402
+ // rebase --abort may fail if there's nothing to abort
403
+ }
404
+ throw new Error(
405
+ `Rebase of '${branch}' onto '${defaultBranch}' failed due to conflicts.\n` +
406
+ `Your branch '${branch}' and all commits are safe.\n` +
407
+ `The worktree has been removed, but you can resolve from the main repo:\n\n` +
408
+ ` cd ${mainRepoPath}\n` +
409
+ ` git rebase ${defaultBranch} ${branch}\n` +
410
+ ` # resolve conflicts, then:\n` +
411
+ ` git rebase --continue\n` +
412
+ ` git switch ${defaultBranch}\n` +
413
+ ` git merge --ff-only ${branch}\n` +
414
+ ` git branch -d ${branch}`
415
+ );
416
+ }
417
+
418
+ // Step 6: Switch to default branch
419
+ execSync(`git switch ${defaultBranch}`, {
420
+ cwd: mainRepoPath, stdio: 'pipe',
421
+ });
422
+
423
+ // Step 7: Fast-forward merge
424
+ execSync(`git merge --ff-only ${branch}`, {
425
+ cwd: mainRepoPath, stdio: 'pipe',
426
+ });
427
+
428
+ // Step 8: Delete the branch
429
+ execSync(`git branch -d ${branch}`, {
430
+ cwd: mainRepoPath, stdio: 'pipe',
431
+ });
432
+
433
+ return { branch, defaultBranch, mainRepoPath };
434
+ }
435
+
436
+ /**
437
+ * Remove a worktree and delete its branch without merging.
438
+ * Used for abandoned work.
439
+ *
440
+ * @param {string} name - Name of the worktree/branch to remove
441
+ * @param {object} config - Loaded golem config (with worktree defaults merged)
442
+ * @returns {Promise<{path: string, branch: string}>}
443
+ */
444
+ export async function worktreeRemove(name, config) {
445
+ if (!name) {
446
+ throw new Error('Worktree name is required. Usage: golem worktree remove <name>');
447
+ }
448
+
449
+ const mainRepoPath = process.cwd();
450
+ const repoName = getRepoName();
451
+ const baseDir = expandTilde(config.worktree.dir);
452
+ const worktreePath = join(baseDir, repoName, name);
453
+
454
+ // Resolve both paths to handle symlinks (like /var -> /private/var on macOS)
455
+ const worktreePathResolved = await safeRealpath(worktreePath);
456
+
457
+ // Check if the worktree exists
458
+ let worktreeList;
459
+ try {
460
+ worktreeList = execSync('git worktree list --porcelain', {
461
+ cwd: mainRepoPath,
462
+ encoding: 'utf-8',
463
+ stdio: 'pipe',
464
+ });
465
+ } catch (err) {
466
+ throw new Error(`Failed to list worktrees: ${err.message}`);
467
+ }
468
+
469
+ const worktrees = parseWorktreePorcelain(worktreeList);
470
+
471
+ // Resolve all worktree paths and compare
472
+ const resolvedWorktrees = await Promise.all(
473
+ worktrees.map(async wt => ({
474
+ ...wt,
475
+ resolvedPath: await safeRealpath(wt.path)
476
+ }))
477
+ );
478
+
479
+ const exists = resolvedWorktrees.some(wt =>
480
+ wt.resolvedPath === worktreePathResolved || wt.path === worktreePath
481
+ );
482
+
483
+ if (!exists) {
484
+ throw new Error(`Worktree '${name}' does not exist at ${worktreePath}`);
485
+ }
486
+
487
+ // Remove the worktree
488
+ try {
489
+ execSync(`git worktree remove ${worktreePath}`, {
490
+ cwd: mainRepoPath,
491
+ stdio: 'pipe',
492
+ });
493
+ } catch (err) {
494
+ throw new Error(`Failed to remove worktree: ${err.message}`);
495
+ }
496
+
497
+ // Delete the branch with -D (force delete, in case it's not merged)
498
+ try {
499
+ execSync(`git branch -D ${name}`, {
500
+ cwd: mainRepoPath,
501
+ stdio: 'pipe',
502
+ });
503
+ } catch (err) {
504
+ // If branch deletion fails, warn but don't fail the whole operation
505
+ console.warn(`Warning: failed to delete branch '${name}': ${err.message}`);
506
+ }
507
+
508
+ return { path: worktreePath, branch: name };
509
+ }
@@ -0,0 +1,23 @@
1
+ You are an autonomous coding agent working on a single task. You have fresh context — assume no prior knowledge of this codebase.
2
+
3
+ ## Instructions
4
+
5
+ 1. Read `.golem/AGENTS.md` for test, build, and lint commands
6
+ 2. Read ALL relevant spec files in `.golem/specs/`
7
+ 3. Investigate the codebase — read existing code that's related to your task
8
+ 4. Implement the task described below
9
+ 5. Run ALL validation gates:
10
+ - Test command from AGENTS.md
11
+ - Type checking (if applicable)
12
+ - Lint (if applicable)
13
+ 6. Fix any failures before reporting success
14
+
15
+ ## Rules
16
+
17
+ - Do NOT commit changes (the orchestrator handles git)
18
+ - Do NOT modify `.golem/IMPLEMENTATION_PLAN.md`
19
+ - Do NOT modify files outside the project directory
20
+ - Keep changes minimal and focused on the task
21
+ - Follow existing code patterns and conventions
22
+ - If tests fail, fix them — do not skip or disable tests
23
+ - If you can't complete the task, explain why clearly
@@ -0,0 +1,66 @@
1
+ You are a documentation agent. Your job is to add inline documentation to source files following the conventions of the detected project type.
2
+
3
+ ## Project Type
4
+
5
+ {{PROJECT_TYPE}}
6
+
7
+ ## Documentation Standards by Type
8
+
9
+ ### JavaScript (JSDoc)
10
+ - Use `/** ... */` block comments on functions, classes, and non-obvious exports
11
+ - Include `@param`, `@returns`, and `@throws` tags where meaningful
12
+ - File header: `/** @file <description of the file's role in the system> */`
13
+
14
+ ### TypeScript (TSDoc)
15
+ - Use `/** ... */` block comments on functions, classes, interfaces, and type aliases
16
+ - Include `@param`, `@returns`, `@throws`, and `@example` tags on public API functions
17
+ - File header: `/** @file <description of the file's role in the system> */`
18
+
19
+ ### Python (Google-style docstrings)
20
+ - Use triple-quoted Google-style docstrings on modules, classes, and functions
21
+ - Include Args, Returns, Raises sections where meaningful
22
+ - Module docstring at the top of every file explaining its purpose
23
+
24
+ ### SQL (comment blocks)
25
+ - Use `--` comment blocks above tables, columns, constraints, stored procedures, and views
26
+ - Group related comments into header blocks for each object
27
+ - Explain relationships, constraints, and non-obvious column purposes
28
+
29
+ ### Vue / Nuxt SFCs
30
+ - `<script>`: JSDoc or TSDoc depending on language (JS or TS)
31
+ - `<template>`: `<!-- ... -->` comments for non-obvious markup, conditional rendering logic, and slot usage
32
+ - `<style>`: `/* ... */` comments for non-obvious selectors, layout tricks, and overrides
33
+
34
+ ### React / Next
35
+ - JSDoc or TSDoc depending on language (JS or TS)
36
+ - Document prop types and their purpose on component functions
37
+ - Document hooks, context providers, and non-obvious rendering logic
38
+
39
+ ## Rules
40
+
41
+ 1. **Document non-obvious functions** — if a function's name and signature don't fully explain what it does, why it exists, or what side effects it has, add documentation
42
+ 2. **Add file headers** — every source file gets a header comment explaining what the file does and its role in the system
43
+ 3. **Educational tone** — write documentation so someone new to the codebase can learn from it; explain the "why", not just the "what"
44
+ 4. **Skip trivial one-liners** — simple getters, identity functions, and self-documenting one-line arrow functions don't need docs unless they have non-obvious side effects
45
+ 5. **Update stale docs** — if existing documentation doesn't match current code behavior, update it; stale docs are worse than no docs
46
+ 6. **Preserve accurate docs** — don't rewrite documentation that is already correct and clear
47
+ 7. **Don't change behavior** — documentation only; never modify logic, add type annotations to JS files, or alter control flow
48
+ 8. **Don't restate signatures** — `@param name - the name` adds no value; describe what the parameter controls or why it matters
49
+ 9. **Document complex logic inline** — non-obvious conditionals, "why" decisions, and tricky control flow get inline comments where they occur
50
+ 10. **Don't touch excluded files** — skip test files, generated files, lock files, node_modules, dist/, and minified/bundled output
51
+
52
+ ## Target Files
53
+
54
+ {{FILES}}
55
+
56
+ ## Process
57
+
58
+ For each file:
59
+ 1. Read the file
60
+ 2. Determine the correct documentation standard from the project type
61
+ 3. Add file header if missing
62
+ 4. Document non-obvious functions, classes, and exports
63
+ 5. Update any stale existing documentation
64
+ 6. Add inline comments for complex logic
65
+ 7. For Vue SFCs: cover `<template>` and `<style>` sections too
66
+ 8. Move to the next file
@@ -0,0 +1,80 @@
1
+ You are a documentation agent. Your job is to generate and update project-level markdown documentation files.
2
+
3
+ ## Output Directory
4
+
5
+ {{DOCS_PATH}}
6
+
7
+ ## Project Structure
8
+
9
+ {{PROJECT_STRUCTURE}}
10
+
11
+ ## Directory Layout
12
+
13
+ Generate the following structure under the docs path. Only create files for things that actually exist in the codebase — never create empty placeholders.
14
+
15
+ ```
16
+ {docsPath}/
17
+ index.md — project overview
18
+ architecture.md — system design, how components connect
19
+ getting-started.md — setup, install, prerequisites, first run
20
+ configuration.md — all config options with explanations
21
+ modules/
22
+ {module-name}.md — one per major module or component
23
+ api/
24
+ {resource}.md — API reference (if project has endpoints)
25
+ database/
26
+ schema.md — full schema overview with relationships
27
+ {table-name}.md — per-table docs (columns, types, constraints, purpose)
28
+ guides/
29
+ setup.md — dev environment setup
30
+ {workflow}.md — project-specific how-to walkthroughs
31
+ deprecated/
32
+ {old-thing}.md — archived docs with deprecation date and replacement notes
33
+ ```
34
+
35
+ ## Frontmatter
36
+
37
+ Every markdown file must include YAML frontmatter with these fields:
38
+
39
+ ```yaml
40
+ ---
41
+ title: "Page Title"
42
+ description: "Brief description of what this page covers"
43
+ navigation:
44
+ order: 1
45
+ ---
46
+ ```
47
+
48
+ Use `navigation.order` to control page ordering within each directory. Start at 1 and increment.
49
+
50
+ ## Rules
51
+
52
+ 1. **Use CommonMark only** — no platform-specific markdown extensions (no GitHub admonitions, no MDX unless the project uses it)
53
+ 2. **No empty placeholders** — only create docs for modules, APIs, tables, and guides that actually exist in the codebase
54
+ 3. **Never delete existing docs** — if a documented module has been removed from the codebase, move its doc to `{docsPath}/deprecated/` with a `deprecated_date` frontmatter field and notes on what replaced it
55
+ 4. **Architecture overview** — include a text-based diagram or structured description showing how major components connect
56
+ 5. **Module docs from source** — generate one doc per major module explaining purpose, exports, dependencies, and usage; reference file paths, don't dump source code
57
+ 6. **Database docs from files** — generate schema docs from migration files, ORM definitions (Prisma, Drizzle, Knex, SQLAlchemy, Alembic), or raw SQL files in the repo; no live database connection
58
+ 7. **Relationship descriptions** — document foreign keys, one-to-many, and other relationships in plain language
59
+ 8. **Getting-started guide** — use actual project commands, config values, and file paths; not generic boilerplate
60
+ 9. **Guides section** — generate project-specific how-tos based on detected workflows (e.g., "How to add a new API endpoint" if the project has an API layer)
61
+ 10. **Cross-link related docs** — module docs link to the API docs that expose them, database docs link to the modules that query them
62
+ 11. **Don't include source code dumps** — explain behavior and usage, reference file paths for code
63
+ 12. **README.md** — generate or update the project root README with project name, description, quick start, and links into the docs directory
64
+ 13. **CHANGELOG.md** — generate from git history in plain, non-technical language for managers and non-developers; group by date with sections: New Features, Improvements, Bug Fixes; no jargon
65
+
66
+ ## Process
67
+
68
+ 1. Read the project structure to understand what modules, APIs, database schemas, and configs exist
69
+ 2. Create the docs directory structure
70
+ 3. Generate `index.md` with project overview
71
+ 4. Generate `architecture.md` with system design and component relationships
72
+ 5. Generate `getting-started.md` with actual setup instructions
73
+ 6. Generate `configuration.md` documenting all config options
74
+ 7. Generate module docs for each major module
75
+ 8. Generate API docs if the project has endpoints
76
+ 9. Generate database docs if schema/migration files exist
77
+ 10. Generate guides based on detected project workflows
78
+ 11. Move docs for removed modules to `deprecated/`
79
+ 12. Update `README.md` at project root
80
+ 13. Generate `CHANGELOG.md` from git history