chief-clancy 0.2.0-beta.3 → 0.3.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 (143) hide show
  1. package/README.md +13 -24
  2. package/dist/installer/file-ops/file-ops.d.ts +32 -0
  3. package/dist/installer/file-ops/file-ops.d.ts.map +1 -0
  4. package/dist/installer/file-ops/file-ops.js +58 -0
  5. package/dist/installer/file-ops/file-ops.js.map +1 -0
  6. package/dist/installer/hook-installer/hook-installer.d.ts +29 -0
  7. package/dist/installer/hook-installer/hook-installer.d.ts.map +1 -0
  8. package/dist/installer/hook-installer/hook-installer.js +96 -0
  9. package/dist/installer/hook-installer/hook-installer.js.map +1 -0
  10. package/dist/installer/install.d.ts +3 -0
  11. package/dist/installer/install.d.ts.map +1 -0
  12. package/dist/installer/install.js +227 -0
  13. package/dist/installer/install.js.map +1 -0
  14. package/dist/installer/manifest/manifest.d.ts +41 -0
  15. package/dist/installer/manifest/manifest.d.ts.map +1 -0
  16. package/dist/installer/manifest/manifest.js +97 -0
  17. package/dist/installer/manifest/manifest.js.map +1 -0
  18. package/dist/installer/prompts/prompts.d.ts +33 -0
  19. package/dist/installer/prompts/prompts.d.ts.map +1 -0
  20. package/dist/installer/prompts/prompts.js +55 -0
  21. package/dist/installer/prompts/prompts.js.map +1 -0
  22. package/dist/schemas/env.d.ts +75 -0
  23. package/dist/schemas/env.d.ts.map +1 -0
  24. package/dist/schemas/env.js +40 -0
  25. package/dist/schemas/env.js.map +1 -0
  26. package/dist/schemas/github.d.ts +27 -0
  27. package/dist/schemas/github.d.ts.map +1 -0
  28. package/dist/schemas/github.js +17 -0
  29. package/dist/schemas/github.js.map +1 -0
  30. package/dist/schemas/index.d.ts +9 -0
  31. package/dist/schemas/index.d.ts.map +1 -0
  32. package/dist/schemas/index.js +5 -0
  33. package/dist/schemas/index.js.map +1 -0
  34. package/dist/schemas/jira.d.ts +37 -0
  35. package/dist/schemas/jira.d.ts.map +1 -0
  36. package/dist/schemas/jira.js +37 -0
  37. package/dist/schemas/jira.js.map +1 -0
  38. package/dist/schemas/linear.d.ts +67 -0
  39. package/dist/schemas/linear.d.ts.map +1 -0
  40. package/dist/schemas/linear.js +50 -0
  41. package/dist/schemas/linear.js.map +1 -0
  42. package/dist/scripts/afk/afk.d.ts +21 -0
  43. package/dist/scripts/afk/afk.d.ts.map +1 -0
  44. package/dist/scripts/afk/afk.js +116 -0
  45. package/dist/scripts/afk/afk.js.map +1 -0
  46. package/dist/scripts/board/github/github.d.ts +56 -0
  47. package/dist/scripts/board/github/github.d.ts.map +1 -0
  48. package/dist/scripts/board/github/github.js +142 -0
  49. package/dist/scripts/board/github/github.js.map +1 -0
  50. package/dist/scripts/board/jira/jira.d.ts +90 -0
  51. package/dist/scripts/board/jira/jira.d.ts.map +1 -0
  52. package/dist/scripts/board/jira/jira.js +251 -0
  53. package/dist/scripts/board/jira/jira.js.map +1 -0
  54. package/dist/scripts/board/linear/linear.d.ts +85 -0
  55. package/dist/scripts/board/linear/linear.d.ts.map +1 -0
  56. package/dist/scripts/board/linear/linear.js +209 -0
  57. package/dist/scripts/board/linear/linear.js.map +1 -0
  58. package/dist/scripts/once/once.d.ts +12 -0
  59. package/dist/scripts/once/once.d.ts.map +1 -0
  60. package/dist/scripts/once/once.js +323 -0
  61. package/dist/scripts/once/once.js.map +1 -0
  62. package/dist/scripts/shared/branch/branch.d.ts +50 -0
  63. package/dist/scripts/shared/branch/branch.d.ts.map +1 -0
  64. package/dist/scripts/shared/branch/branch.js +61 -0
  65. package/dist/scripts/shared/branch/branch.js.map +1 -0
  66. package/dist/scripts/shared/claude-cli/claude-cli.d.ts +17 -0
  67. package/dist/scripts/shared/claude-cli/claude-cli.d.ts.map +1 -0
  68. package/dist/scripts/shared/claude-cli/claude-cli.js +35 -0
  69. package/dist/scripts/shared/claude-cli/claude-cli.js.map +1 -0
  70. package/dist/scripts/shared/env-parser/env-parser.d.ts +30 -0
  71. package/dist/scripts/shared/env-parser/env-parser.d.ts.map +1 -0
  72. package/dist/scripts/shared/env-parser/env-parser.js +64 -0
  73. package/dist/scripts/shared/env-parser/env-parser.js.map +1 -0
  74. package/dist/scripts/shared/env-schema/env-schema.d.ts +27 -0
  75. package/dist/scripts/shared/env-schema/env-schema.d.ts.map +1 -0
  76. package/dist/scripts/shared/env-schema/env-schema.js +46 -0
  77. package/dist/scripts/shared/env-schema/env-schema.js.map +1 -0
  78. package/dist/scripts/shared/git-ops/git-ops.d.ts +52 -0
  79. package/dist/scripts/shared/git-ops/git-ops.d.ts.map +1 -0
  80. package/dist/scripts/shared/git-ops/git-ops.js +107 -0
  81. package/dist/scripts/shared/git-ops/git-ops.js.map +1 -0
  82. package/dist/scripts/shared/http/http.d.ts +52 -0
  83. package/dist/scripts/shared/http/http.d.ts.map +1 -0
  84. package/dist/scripts/shared/http/http.js +74 -0
  85. package/dist/scripts/shared/http/http.js.map +1 -0
  86. package/dist/scripts/shared/notify/notify.d.ts +46 -0
  87. package/dist/scripts/shared/notify/notify.d.ts.map +1 -0
  88. package/dist/scripts/shared/notify/notify.js +88 -0
  89. package/dist/scripts/shared/notify/notify.js.map +1 -0
  90. package/dist/scripts/shared/preflight/preflight.d.ts +40 -0
  91. package/dist/scripts/shared/preflight/preflight.d.ts.map +1 -0
  92. package/dist/scripts/shared/preflight/preflight.js +84 -0
  93. package/dist/scripts/shared/preflight/preflight.js.map +1 -0
  94. package/dist/scripts/shared/progress/progress.d.ts +25 -0
  95. package/dist/scripts/shared/progress/progress.d.ts.map +1 -0
  96. package/dist/scripts/shared/progress/progress.js +46 -0
  97. package/dist/scripts/shared/progress/progress.js.map +1 -0
  98. package/dist/scripts/shared/prompt/prompt.d.ts +38 -0
  99. package/dist/scripts/shared/prompt/prompt.d.ts.map +1 -0
  100. package/dist/scripts/shared/prompt/prompt.js +77 -0
  101. package/dist/scripts/shared/prompt/prompt.js.map +1 -0
  102. package/dist/types/board.d.ts +13 -0
  103. package/dist/types/board.d.ts.map +1 -0
  104. package/dist/types/board.js +5 -0
  105. package/dist/types/board.js.map +1 -0
  106. package/dist/types/index.d.ts +3 -0
  107. package/dist/types/index.d.ts.map +1 -0
  108. package/dist/types/index.js +2 -0
  109. package/dist/types/index.js.map +1 -0
  110. package/dist/utils/ansi/ansi.d.ts +55 -0
  111. package/dist/utils/ansi/ansi.d.ts.map +1 -0
  112. package/dist/utils/ansi/ansi.js +55 -0
  113. package/dist/utils/ansi/ansi.js.map +1 -0
  114. package/dist/utils/index.d.ts +3 -0
  115. package/dist/utils/index.d.ts.map +1 -0
  116. package/dist/utils/index.js +3 -0
  117. package/dist/utils/index.js.map +1 -0
  118. package/dist/utils/parse-json/parse-json.d.ts +20 -0
  119. package/dist/utils/parse-json/parse-json.d.ts.map +1 -0
  120. package/dist/utils/parse-json/parse-json.js +27 -0
  121. package/dist/utils/parse-json/parse-json.js.map +1 -0
  122. package/hooks/clancy-check-update.js +2 -2
  123. package/hooks/clancy-credential-guard.js +8 -1
  124. package/package.json +52 -8
  125. package/registry/boards.json +3 -6
  126. package/src/templates/CLAUDE.md +1 -1
  127. package/src/workflows/doctor.md +32 -23
  128. package/src/workflows/init.md +88 -19
  129. package/src/workflows/logs.md +13 -6
  130. package/src/workflows/map-codebase.md +17 -16
  131. package/src/workflows/once.md +22 -12
  132. package/src/workflows/review.md +40 -27
  133. package/src/workflows/run.md +20 -12
  134. package/src/workflows/scaffold.md +12 -1023
  135. package/src/workflows/settings.md +9 -6
  136. package/src/workflows/status.md +17 -8
  137. package/src/workflows/uninstall.md +11 -6
  138. package/src/workflows/update.md +13 -11
  139. package/bin/install.js +0 -362
  140. package/src/templates/scripts/clancy-afk.sh +0 -111
  141. package/src/templates/scripts/clancy-once-github.sh +0 -249
  142. package/src/templates/scripts/clancy-once-linear.sh +0 -320
  143. package/src/templates/scripts/clancy-once.sh +0 -322
package/README.md CHANGED
@@ -2,13 +2,13 @@
2
2
 
3
3
  **Autonomous, board-driven development for Claude Code.**
4
4
 
5
- [![npm](https://img.shields.io/npm/v/chief-clancy?color=cb3837)](https://www.npmjs.com/package/chief-clancy) [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE) [![Tests](https://img.shields.io/badge/tests-55%20passing-brightgreen)](./test/) [![GitHub Stars](https://img.shields.io/github/stars/Pushedskydiver/clancy?style=flat)](https://github.com/Pushedskydiver/clancy/stargazers)
5
+ [![npm](https://img.shields.io/npm/v/chief-clancy?style=for-the-badge&color=cb3837)](https://www.npmjs.com/package/chief-clancy) [![License: MIT](https://img.shields.io/badge/License-MIT-blue?style=for-the-badge)](./LICENSE) [![Tests](https://img.shields.io/badge/tests-146%20passing-brightgreen?style=for-the-badge)](docs/TESTING.md) [![GitHub Stars](https://img.shields.io/github/stars/Pushedskydiver/clancy?style=for-the-badge)](https://github.com/Pushedskydiver/clancy/stargazers)
6
6
 
7
7
  ```bash
8
8
  npx chief-clancy
9
9
  ```
10
10
 
11
- Works on Mac and Linux. Windows requires [WSL](https://learn.microsoft.com/en-us/windows/wsl/install).
11
+ Works on Mac, Linux, and Windows.
12
12
 
13
13
  [What it does](#what-it-does) · [Install](#install) · [Commands](#commands) · [Supported boards](#supported-boards) · [Comparison](./COMPARISON.md) · [Roadmap](./ROADMAP.md) · [Contributing](./CONTRIBUTING.md)
14
14
 
@@ -101,8 +101,7 @@ You'll be asked: global install (`~/.claude`) or local (`./.claude`). Either wor
101
101
  **Prerequisites:**
102
102
 
103
103
  - [Claude Code](https://claude.ai/code) CLI installed
104
- - `jq` installed (`brew install jq` or `apt install jq`)
105
- - `curl` installed (comes with macOS/most Linux)
104
+ - Node.js 22+ (`node -v`)
106
105
  - `git` installed (comes with most development environments)
107
106
 
108
107
  ### Permissions
@@ -114,7 +113,7 @@ claude --dangerously-skip-permissions
114
113
  ```
115
114
 
116
115
  > [!TIP]
117
- > This is how Clancy is intended to be used — stopping to approve `git commit` and `curl` 50 times defeats the purpose. Only use it on codebases you own and trust.
116
+ > This is how Clancy is intended to be used — stopping to approve `git commit` and `node` 50 times defeats the purpose. Only use it on codebases you own and trust.
118
117
 
119
118
  ---
120
119
 
@@ -168,8 +167,8 @@ npx chief-clancy
168
167
 
169
168
  ```
170
169
  .clancy/
171
- clancy-once.sh — picks up one ticket, implements, commits, merges
172
- clancy-afk.sh — loop runner (board-agnostic)
170
+ clancy-once.js — picks up one ticket, implements, commits, merges
171
+ clancy-afk.js — loop runner (board-agnostic)
173
172
  docs/ — 10 structured docs read before every run
174
173
  STACK.md
175
174
  INTEGRATIONS.md
@@ -241,9 +240,9 @@ Posts to Slack or Teams when a ticket completes or Clancy hits an error. URL is
241
240
  ## How the loop works
242
241
 
243
242
  ```
244
- clancy-afk.sh
243
+ clancy-afk.js
245
244
  └─ while i < MAX_ITERATIONS:
246
- bash clancy-once.sh
245
+ node clancy-once.js
247
246
  1. Preflight checks (credentials, git state, board reachability)
248
247
  2. Fetch next ticket from board (maxResults=1)
249
248
  3. git checkout $EPIC_BRANCH
@@ -253,7 +252,7 @@ clancy-afk.sh
253
252
  7. git checkout $EPIC_BRANCH
254
253
  8. git merge --squash feature/{ticket-key}
255
254
  9. git commit -m "feat(TICKET): summary"
256
- 10. git branch -d feature/{ticket-key}
255
+ 10. git branch -D feature/{ticket-key}
257
256
  11. Append to .clancy/progress.txt
258
257
  if "No tickets found": break
259
258
  ```
@@ -294,9 +293,7 @@ Clancy runs Claude with `--dangerously-skip-permissions`, which suppresses all p
294
293
  "allow": [
295
294
  "Bash(git:*)",
296
295
  "Bash(bash:*)",
297
- "Bash(curl:*)",
298
- "Bash(jq:*)",
299
- "Bash(chmod:*)",
296
+ "Bash(node:*)",
300
297
  "Bash(npm:*)",
301
298
  "Bash(mkdir:*)",
302
299
  "Bash(cat:*)",
@@ -318,7 +315,7 @@ Clancy runs Claude with `--dangerously-skip-permissions`, which suppresses all p
318
315
 
319
316
  ### Protect your credentials from Claude
320
317
 
321
- Your board tokens and API keys live in `.clancy/.env`. Although Claude doesn't need to read this file during a run (the shell script sources it before invoking Claude), adding it to Claude Code's deny list is good defence-in-depth. Add it to `.claude/settings.json` in your project, or `~/.claude/settings.json` globally:
318
+ Your board tokens and API keys live in `.clancy/.env`. Although Claude doesn't need to read this file during a run (the JS shim loads it before invoking Claude), adding it to Claude Code's deny list is good defence-in-depth. Add it to `.claude/settings.json` in your project, or `~/.claude/settings.json` globally:
322
319
 
323
320
  ```json
324
321
  {
@@ -394,15 +391,7 @@ Run `/clancy:status` to see what Clancy would pick up. If the queue is empty:
394
391
 
395
392
  ---
396
393
 
397
- **Scripts not executable?**
398
-
399
- ```bash
400
- chmod +x .clancy/*.sh
401
- ```
402
-
403
- ---
404
-
405
- **`.clancy/clancy-once.sh` not found?**
394
+ **`.clancy/clancy-once.js` not found?**
406
395
 
407
396
  Re-run `/clancy:init` — it will detect the existing setup and offer to re-scaffold without asking for credentials again.
408
397
 
@@ -440,7 +429,7 @@ Removes slash commands from your chosen location. Cleans up the `<!-- clancy:sta
440
429
 
441
430
  ## Contributing
442
431
 
443
- See [CONTRIBUTING.md](./CONTRIBUTING.md). The most useful contribution is adding a new board — it's a shell script + a JSON entry.
432
+ See [CONTRIBUTING.md](./CONTRIBUTING.md). The most useful contribution is adding a new board — it's a TypeScript module + a JSON entry.
444
433
 
445
434
  ## License
446
435
 
@@ -0,0 +1,32 @@
1
+ /** Minimal directory-entry shape returned by `readdirSync({ withFileTypes: true })`. */
2
+ export type DirentLike = {
3
+ name: string;
4
+ isDirectory(): boolean;
5
+ };
6
+ /**
7
+ * Compute the SHA-256 hash of a file.
8
+ *
9
+ * @param filePath - Absolute path to the file.
10
+ * @returns The hex-encoded SHA-256 hash string.
11
+ *
12
+ * @example
13
+ * ```ts
14
+ * const hash = fileHash('/path/to/file.md');
15
+ * // 'e3b0c44298fc1c149afbf4c8996fb924...'
16
+ * ```
17
+ */
18
+ export declare function fileHash(filePath: string): string;
19
+ /**
20
+ * Recursively copy a directory, throwing if the destination is a symlink.
21
+ *
22
+ * @param src - Source directory path.
23
+ * @param dest - Destination directory path.
24
+ * @throws If the destination is a symlink.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * copyDir('src/commands', '/home/user/.claude/commands/clancy');
29
+ * ```
30
+ */
31
+ export declare function copyDir(src: string, dest: string): void;
32
+ //# sourceMappingURL=file-ops.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-ops.d.ts","sourceRoot":"","sources":["../../../src/installer/file-ops/file-ops.ts"],"names":[],"mappings":"AAgBA,wFAAwF;AACxF,MAAM,MAAM,UAAU,GAAG;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,WAAW,IAAI,OAAO,CAAA;CAAE,CAAC;AAElE;;;;;;;;;;;GAWG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAGjD;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAuBvD"}
@@ -0,0 +1,58 @@
1
+ /**
2
+ * Low-level file system helpers for the installer.
3
+ *
4
+ * Provides SHA-256 hashing and recursive directory copying with symlink detection.
5
+ */
6
+ import { createHash } from 'node:crypto';
7
+ import { copyFileSync, existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, } from 'node:fs';
8
+ import { join } from 'node:path';
9
+ /**
10
+ * Compute the SHA-256 hash of a file.
11
+ *
12
+ * @param filePath - Absolute path to the file.
13
+ * @returns The hex-encoded SHA-256 hash string.
14
+ *
15
+ * @example
16
+ * ```ts
17
+ * const hash = fileHash('/path/to/file.md');
18
+ * // 'e3b0c44298fc1c149afbf4c8996fb924...'
19
+ * ```
20
+ */
21
+ export function fileHash(filePath) {
22
+ const content = readFileSync(filePath);
23
+ return createHash('sha256').update(content).digest('hex');
24
+ }
25
+ /**
26
+ * Recursively copy a directory, throwing if the destination is a symlink.
27
+ *
28
+ * @param src - Source directory path.
29
+ * @param dest - Destination directory path.
30
+ * @throws If the destination is a symlink.
31
+ *
32
+ * @example
33
+ * ```ts
34
+ * copyDir('src/commands', '/home/user/.claude/commands/clancy');
35
+ * ```
36
+ */
37
+ export function copyDir(src, dest) {
38
+ if (existsSync(dest)) {
39
+ const stat = lstatSync(dest);
40
+ if (stat.isSymbolicLink()) {
41
+ throw new Error(`${dest} is a symlink. Remove it first before installing.`);
42
+ }
43
+ }
44
+ mkdirSync(dest, { recursive: true });
45
+ for (const entry of readdirSync(src, {
46
+ withFileTypes: true,
47
+ })) {
48
+ const s = join(src, entry.name);
49
+ const d = join(dest, entry.name);
50
+ if (entry.isDirectory()) {
51
+ copyDir(s, d);
52
+ }
53
+ else {
54
+ copyFileSync(s, d);
55
+ }
56
+ }
57
+ }
58
+ //# sourceMappingURL=file-ops.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file-ops.js","sourceRoot":"","sources":["../../../src/installer/file-ops/file-ops.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EACL,YAAY,EACZ,UAAU,EACV,SAAS,EACT,SAAS,EACT,YAAY,EACZ,WAAW,GACZ,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAKjC;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,QAAQ,CAAC,QAAgB;IACvC,MAAM,OAAO,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACvC,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC5D,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,OAAO,CAAC,GAAW,EAAE,IAAY;IAC/C,IAAI,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC;QAC7B,IAAI,IAAI,CAAC,cAAc,EAAE,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CACb,GAAG,IAAI,mDAAmD,CAC3D,CAAC;QACJ,CAAC;IACH,CAAC;IAED,SAAS,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAErC,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,GAAG,EAAE;QACnC,aAAa,EAAE,IAAI;KACpB,CAAiB,EAAE,CAAC;QACnB,MAAM,CAAC,GAAG,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAChC,MAAM,CAAC,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAChB,CAAC;aAAM,CAAC;YACN,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,29 @@
1
+ /** Options for the hook installer. */
2
+ type HookInstallerOptions = {
3
+ /** The Claude config directory (e.g., `~/.claude` or `./.claude`). */
4
+ claudeConfigDir: string;
5
+ /** Path to the directory containing compiled hook JS files. */
6
+ hooksSourceDir: string;
7
+ };
8
+ /**
9
+ * Install Clancy hooks into the Claude config directory.
10
+ *
11
+ * Copies hook scripts, writes a CommonJS `package.json` to the hooks dir,
12
+ * and merges hook registrations into `settings.json`.
13
+ *
14
+ * Best-effort — never throws. Returns `false` if installation fails.
15
+ *
16
+ * @param options - The hook installer options.
17
+ * @returns `true` if hooks were installed successfully.
18
+ *
19
+ * @example
20
+ * ```ts
21
+ * installHooks({
22
+ * claudeConfigDir: '/home/user/.claude',
23
+ * hooksSourceDir: '/path/to/clancy/hooks',
24
+ * });
25
+ * ```
26
+ */
27
+ export declare function installHooks(options: HookInstallerOptions): boolean;
28
+ export {};
29
+ //# sourceMappingURL=hook-installer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-installer.d.ts","sourceRoot":"","sources":["../../../src/installer/hook-installer/hook-installer.ts"],"names":[],"mappings":"AAkBA,sCAAsC;AACtC,KAAK,oBAAoB,GAAG;IAC1B,sEAAsE;IACtE,eAAe,EAAE,MAAM,CAAC;IACxB,+DAA+D;IAC/D,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAyBF;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAmEnE"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Hook installer for Claude Code settings.
3
+ *
4
+ * Copies compiled hook scripts into the Claude config directory and
5
+ * registers them in `settings.json` without clobbering existing config.
6
+ */
7
+ import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync, } from 'node:fs';
8
+ import { join } from 'node:path';
9
+ /**
10
+ * Add a hook command to a settings event array if not already registered.
11
+ *
12
+ * @param hooks - The hooks record from settings.json.
13
+ * @param event - The hook event name (e.g., `'SessionStart'`).
14
+ * @param command - The shell command to register.
15
+ */
16
+ function registerHook(hooks, event, command) {
17
+ if (!hooks[event])
18
+ hooks[event] = [];
19
+ const already = hooks[event].some((h) => h.hooks && h.hooks.some((hh) => hh.command === command));
20
+ if (!already) {
21
+ hooks[event].push({ hooks: [{ type: 'command', command }] });
22
+ }
23
+ }
24
+ /**
25
+ * Install Clancy hooks into the Claude config directory.
26
+ *
27
+ * Copies hook scripts, writes a CommonJS `package.json` to the hooks dir,
28
+ * and merges hook registrations into `settings.json`.
29
+ *
30
+ * Best-effort — never throws. Returns `false` if installation fails.
31
+ *
32
+ * @param options - The hook installer options.
33
+ * @returns `true` if hooks were installed successfully.
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * installHooks({
38
+ * claudeConfigDir: '/home/user/.claude',
39
+ * hooksSourceDir: '/path/to/clancy/hooks',
40
+ * });
41
+ * ```
42
+ */
43
+ export function installHooks(options) {
44
+ const { claudeConfigDir, hooksSourceDir } = options;
45
+ const hooksInstallDir = join(claudeConfigDir, 'hooks');
46
+ const settingsFile = join(claudeConfigDir, 'settings.json');
47
+ const hookFiles = [
48
+ 'clancy-check-update.js',
49
+ 'clancy-statusline.js',
50
+ 'clancy-context-monitor.js',
51
+ 'clancy-credential-guard.js',
52
+ ];
53
+ try {
54
+ mkdirSync(hooksInstallDir, { recursive: true });
55
+ for (const f of hookFiles) {
56
+ copyFileSync(join(hooksSourceDir, f), join(hooksInstallDir, f));
57
+ }
58
+ // Force CommonJS resolution for hook files — projects with "type":"module"
59
+ // in their package.json would otherwise treat .js files as ESM.
60
+ writeFileSync(join(hooksInstallDir, 'package.json'), JSON.stringify({ type: 'commonjs' }, null, 2) + '\n');
61
+ // Merge hooks into settings.json without clobbering existing config
62
+ let settings = {};
63
+ if (existsSync(settingsFile)) {
64
+ try {
65
+ settings = JSON.parse(readFileSync(settingsFile, 'utf8'));
66
+ }
67
+ catch {
68
+ // Ignore parse errors — start fresh
69
+ }
70
+ }
71
+ if (!settings.hooks)
72
+ settings.hooks = {};
73
+ const hooks = settings.hooks;
74
+ const updateScript = join(hooksInstallDir, 'clancy-check-update.js');
75
+ const statuslineScript = join(hooksInstallDir, 'clancy-statusline.js');
76
+ const monitorScript = join(hooksInstallDir, 'clancy-context-monitor.js');
77
+ const guardScript = join(hooksInstallDir, 'clancy-credential-guard.js');
78
+ registerHook(hooks, 'SessionStart', `node ${JSON.stringify(updateScript)}`);
79
+ registerHook(hooks, 'PostToolUse', `node ${JSON.stringify(monitorScript)}`);
80
+ registerHook(hooks, 'PreToolUse', `node ${JSON.stringify(guardScript)}`);
81
+ // Statusline: registered as top-level key, not inside hooks
82
+ if (!settings.statusLine) {
83
+ settings.statusLine = {
84
+ type: 'command',
85
+ command: `node ${JSON.stringify(statuslineScript)}`,
86
+ };
87
+ }
88
+ writeFileSync(settingsFile, JSON.stringify(settings, null, 2) + '\n');
89
+ return true;
90
+ }
91
+ catch {
92
+ // Hook registration is best-effort — don't fail the install
93
+ return false;
94
+ }
95
+ }
96
+ //# sourceMappingURL=hook-installer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"hook-installer.js","sourceRoot":"","sources":["../../../src/installer/hook-installer/hook-installer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/installer/install.ts"],"names":[],"mappings":""}
@@ -0,0 +1,227 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Clancy installer — interactive CLI entry point.
4
+ *
5
+ * Prompts the user to choose global (~/.claude) or local (./.claude) install,
6
+ * copies commands and workflows, inlines workflow references for global installs,
7
+ * detects and backs up user-modified files, and registers hooks in Claude settings.
8
+ */
9
+ import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync, } from 'node:fs';
10
+ import { createRequire } from 'node:module';
11
+ import { dirname, join } from 'node:path';
12
+ import { fileURLToPath } from 'node:url';
13
+ import { copyDir } from '../installer/file-ops/file-ops.js';
14
+ import { installHooks } from '../installer/hook-installer/hook-installer.js';
15
+ import { backupModifiedFiles, buildManifest, detectModifiedFiles, } from '../installer/manifest/manifest.js';
16
+ import { ask, choose, closePrompts } from '../installer/prompts/prompts.js';
17
+ import { blue, bold, cyan, dim, green, red } from '../utils/ansi/ansi.js';
18
+ // ---------------------------------------------------------------------------
19
+ // Paths
20
+ // ---------------------------------------------------------------------------
21
+ const __filename = fileURLToPath(import.meta.url);
22
+ const __dirname = dirname(__filename);
23
+ const require = createRequire(import.meta.url);
24
+ const PKG = require('../../package.json');
25
+ const COMMANDS_SRC = join(__dirname, '..', '..', 'src', 'commands');
26
+ const WORKFLOWS_SRC = join(__dirname, '..', '..', 'src', 'workflows');
27
+ const HOOKS_SRC = join(__dirname, '..', '..', 'hooks');
28
+ const _homeDir = process.env.HOME ?? process.env.USERPROFILE;
29
+ if (!_homeDir) {
30
+ process.stderr.write('\x1b[31m\n Error: HOME or USERPROFILE environment variable is not set.\x1b[0m\n');
31
+ process.exit(1);
32
+ }
33
+ const homeDir = _homeDir;
34
+ const GLOBAL_DEST = join(homeDir, '.claude', 'commands', 'clancy');
35
+ const LOCAL_DEST = join(process.cwd(), '.claude', 'commands', 'clancy');
36
+ const GLOBAL_WORKFLOWS_DEST = join(homeDir, '.claude', 'clancy', 'workflows');
37
+ const LOCAL_WORKFLOWS_DEST = join(process.cwd(), '.claude', 'clancy', 'workflows');
38
+ // ---------------------------------------------------------------------------
39
+ // Banner
40
+ // ---------------------------------------------------------------------------
41
+ /**
42
+ * Print the Clancy ASCII banner and version info.
43
+ */
44
+ function printBanner() {
45
+ console.log('');
46
+ console.log(blue(' ██████╗██╗ █████╗ ███╗ ██╗ ██████╗██╗ ██╗'));
47
+ console.log(blue(' ██╔════╝██║ ██╔══██╗████╗ ██║██╔════╝╚██╗ ██╔╝'));
48
+ console.log(blue(' ██║ ██║ ███████║██╔██╗ ██║██║ ╚████╔╝ '));
49
+ console.log(blue(' ██║ ██║ ██╔══██║██║╚██╗██║██║ ╚██╔╝ '));
50
+ console.log(blue(' ╚██████╗███████╗██║ ██║██║ ╚████║╚██████╗ ██║ '));
51
+ console.log(blue(' ╚═════╝╚══════╝╚═╝ ╚═╝╚═╝ ╚═══╝ ╚═════╝ ╚═╝ '));
52
+ console.log('');
53
+ console.log(' ' +
54
+ bold(`v${PKG.version}`) +
55
+ dim(' Autonomous, board-driven development for Claude Code.'));
56
+ console.log(dim(' Named after Chief Clancy Wiggum. Built on the Ralph technique by Geoffrey Huntley.'));
57
+ }
58
+ /**
59
+ * Print the post-install success message with available commands.
60
+ */
61
+ function printSuccess() {
62
+ console.log('');
63
+ console.log(green(' ✓ Clancy installed successfully.'));
64
+ console.log('');
65
+ console.log(' Next steps:');
66
+ console.log(dim(' 1. Open a project in Claude Code'));
67
+ console.log(` 2. Run: ${cyan('/clancy:init')}`);
68
+ console.log('');
69
+ console.log(' Commands available:');
70
+ console.log('');
71
+ const cmds = [
72
+ ['/clancy:init', 'Set up Clancy in your project'],
73
+ ['/clancy:map-codebase', 'Scan codebase with 5 parallel agents'],
74
+ ['/clancy:run', 'Run Clancy in loop mode'],
75
+ ['/clancy:once', 'Pick up one ticket and stop'],
76
+ ['/clancy:dry-run', 'Preview next ticket without making changes'],
77
+ ['/clancy:status', 'Show next tickets without running'],
78
+ ['/clancy:review', 'Score next ticket and get recommendations'],
79
+ ['/clancy:logs', 'Display progress log'],
80
+ ['/clancy:settings', 'View and change configuration'],
81
+ ['/clancy:doctor', 'Diagnose your setup'],
82
+ ['/clancy:update', 'Update Clancy to latest version'],
83
+ ['/clancy:help', 'Show all commands'],
84
+ ];
85
+ for (const [cmd, desc] of cmds) {
86
+ console.log(` ${cyan(cmd.padEnd(22))} ${dim(desc)}`);
87
+ }
88
+ console.log('');
89
+ }
90
+ // ---------------------------------------------------------------------------
91
+ // Workflow inlining
92
+ // ---------------------------------------------------------------------------
93
+ /** Regex matching an @-file workflow reference in a command file. */
94
+ const WORKFLOW_REF = /^@\.claude\/clancy\/workflows\/(.+\.md)$/m;
95
+ /**
96
+ * Inline workflow file content into global command files.
97
+ *
98
+ * For global installs, @-file references resolve relative to the project root
99
+ * (not ~/.claude), so the workflow files won't be found at runtime. This
100
+ * replaces the @-file reference with the actual workflow content.
101
+ *
102
+ * @param commandsDir - The installed commands directory.
103
+ * @param workflowsDir - The installed workflows directory.
104
+ */
105
+ function inlineWorkflows(commandsDir, workflowsDir) {
106
+ for (const file of readdirSync(commandsDir)) {
107
+ if (!file.endsWith('.md'))
108
+ continue;
109
+ const cmdPath = join(commandsDir, file);
110
+ const content = readFileSync(cmdPath, 'utf8');
111
+ const match = content.match(WORKFLOW_REF);
112
+ if (!match)
113
+ continue;
114
+ const workflowFile = join(workflowsDir, match[1]);
115
+ if (!existsSync(workflowFile))
116
+ continue;
117
+ const workflowContent = readFileSync(workflowFile, 'utf8');
118
+ writeFileSync(cmdPath, content.replace(match[0], workflowContent));
119
+ }
120
+ }
121
+ // ---------------------------------------------------------------------------
122
+ // Main
123
+ // ---------------------------------------------------------------------------
124
+ async function main() {
125
+ printBanner();
126
+ const installChoice = await choose('Where would you like to install?', [
127
+ `Global ${dim('(~/.claude)')} — available in all projects`,
128
+ `Local ${dim('(./.claude)')} — this project only`,
129
+ ]);
130
+ let dest;
131
+ let workflowsDest;
132
+ if (installChoice === '1' || installChoice.toLowerCase() === 'global') {
133
+ dest = GLOBAL_DEST;
134
+ workflowsDest = GLOBAL_WORKFLOWS_DEST;
135
+ }
136
+ else if (installChoice === '2' || installChoice.toLowerCase() === 'local') {
137
+ dest = LOCAL_DEST;
138
+ workflowsDest = LOCAL_WORKFLOWS_DEST;
139
+ }
140
+ else {
141
+ console.log(red('\n Invalid choice. Run npx chief-clancy again and enter 1 or 2.'));
142
+ closePrompts();
143
+ process.exit(1);
144
+ }
145
+ // Validate source directories — guards against corrupted npm package
146
+ for (const [label, src] of [
147
+ ['Commands', COMMANDS_SRC],
148
+ ['Workflows', WORKFLOWS_SRC],
149
+ ]) {
150
+ if (!existsSync(src)) {
151
+ console.error(red(`\n Error: ${label} source not found: ${src}`));
152
+ console.error(red(' The npm package may be corrupted. Try: npm cache clean --force'));
153
+ closePrompts();
154
+ process.exit(1);
155
+ }
156
+ }
157
+ console.log('');
158
+ console.log(dim(` Installing to: ${dest}`));
159
+ try {
160
+ const claudeDir = dirname(dirname(dest)); // .claude/
161
+ const manifestPath = join(claudeDir, 'clancy', 'manifest.json');
162
+ const workflowsManifestPath = join(claudeDir, 'clancy', 'workflows-manifest.json');
163
+ const patchesDir = join(claudeDir, 'clancy', 'local-patches');
164
+ // Handle existing installation
165
+ if (existsSync(dest) || existsSync(workflowsDest)) {
166
+ console.log('');
167
+ const modified = detectModifiedFiles(dest, manifestPath);
168
+ const modifiedWorkflows = detectModifiedFiles(workflowsDest, workflowsManifestPath);
169
+ const allModified = [...modified, ...modifiedWorkflows];
170
+ if (allModified.length > 0) {
171
+ console.log(blue(' Modified files detected:'));
172
+ for (const { rel } of allModified) {
173
+ console.log(` ${dim('•')} ${rel}`);
174
+ }
175
+ console.log('');
176
+ console.log(dim(' These will be backed up to .claude/clancy/local-patches/'));
177
+ console.log(dim(' before overwriting. You can reapply them after the update.'));
178
+ console.log('');
179
+ }
180
+ const overwrite = await ask(blue(` Commands already exist at ${dest}. Overwrite? [y/N] `));
181
+ if (!overwrite.trim().toLowerCase().startsWith('y')) {
182
+ console.log('\n Aborted. No files changed.');
183
+ closePrompts();
184
+ process.exit(0);
185
+ }
186
+ if (allModified.length > 0) {
187
+ backupModifiedFiles(allModified, patchesDir);
188
+ console.log(green(`\n ✓ ${allModified.length} modified file(s) backed up to local-patches/`));
189
+ }
190
+ }
191
+ // Copy commands and workflows
192
+ copyDir(COMMANDS_SRC, dest);
193
+ copyDir(WORKFLOWS_SRC, workflowsDest);
194
+ // Inline workflows for global installs
195
+ if (dest === GLOBAL_DEST) {
196
+ inlineWorkflows(dest, workflowsDest);
197
+ }
198
+ // Write VERSION file
199
+ writeFileSync(join(dest, 'VERSION'), PKG.version);
200
+ // Write manifests for future update detection
201
+ mkdirSync(dirname(manifestPath), { recursive: true });
202
+ writeFileSync(manifestPath, JSON.stringify(buildManifest(dest), null, 2));
203
+ writeFileSync(workflowsManifestPath, JSON.stringify(buildManifest(workflowsDest), null, 2));
204
+ // Install hooks
205
+ const claudeConfigDir = dest === GLOBAL_DEST
206
+ ? join(homeDir, '.claude')
207
+ : join(process.cwd(), '.claude');
208
+ installHooks({
209
+ claudeConfigDir,
210
+ hooksSourceDir: HOOKS_SRC,
211
+ });
212
+ printSuccess();
213
+ }
214
+ catch (err) {
215
+ const message = err instanceof Error ? err.message : String(err);
216
+ console.error(red(`\n Install failed: ${message}`));
217
+ closePrompts();
218
+ process.exit(1);
219
+ }
220
+ closePrompts();
221
+ }
222
+ main().catch((err) => {
223
+ const message = err instanceof Error ? err.message : String(err);
224
+ console.error(red(`\n Install failed: ${message}`));
225
+ process.exit(1);
226
+ });
227
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/installer/install.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ /** A file that has been modified by the user since last install. */
2
+ export type ModifiedFile = {
3
+ rel: string;
4
+ absPath: string;
5
+ };
6
+ /**
7
+ * Build a manifest of installed files with SHA-256 hashes.
8
+ *
9
+ * Recursively walks a directory and records the hash of every file.
10
+ *
11
+ * @param baseDir - Root directory to scan.
12
+ * @returns A record mapping relative paths to their SHA-256 hashes.
13
+ *
14
+ * @example
15
+ * ```ts
16
+ * const manifest = buildManifest('/path/to/.claude/commands/clancy');
17
+ * // { "init.md": "abc123...", "run.md": "def456..." }
18
+ * ```
19
+ */
20
+ export declare function buildManifest(baseDir: string): Record<string, string>;
21
+ /**
22
+ * Detect files modified by the user since last install.
23
+ *
24
+ * Compares current file hashes against the stored manifest to find changes.
25
+ *
26
+ * @param baseDir - The installed directory to check.
27
+ * @param manifestPath - Path to the stored manifest JSON.
28
+ * @returns Array of modified file records with relative and absolute paths.
29
+ */
30
+ export declare function detectModifiedFiles(baseDir: string, manifestPath: string): ModifiedFile[];
31
+ /**
32
+ * Back up modified files to a patches directory.
33
+ *
34
+ * Copies each modified file and writes a `backup-meta.json` with metadata.
35
+ *
36
+ * @param modified - Array of modified file records.
37
+ * @param patchesDir - Directory to store backups.
38
+ * @returns The patches directory path, or `null` if no files were backed up.
39
+ */
40
+ export declare function backupModifiedFiles(modified: ModifiedFile[], patchesDir: string): string | null;
41
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/installer/manifest/manifest.ts"],"names":[],"mappings":"AAmBA,oEAAoE;AACpE,MAAM,MAAM,YAAY,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAE5D;;;;;;;;;;;;;GAaG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAoBrE;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,GACnB,YAAY,EAAE,CA0BhB;AAED;;;;;;;;GAQG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,YAAY,EAAE,EACxB,UAAU,EAAE,MAAM,GACjB,MAAM,GAAG,IAAI,CAwBf"}