chief-clancy 0.2.0 → 0.3.1

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 (141) hide show
  1. package/README.md +13 -24
  2. package/dist/bundle/clancy-afk.js +101 -0
  3. package/dist/bundle/clancy-once.js +13902 -0
  4. package/dist/installer/file-ops/file-ops.d.ts +32 -0
  5. package/dist/installer/file-ops/file-ops.d.ts.map +1 -0
  6. package/dist/installer/file-ops/file-ops.js +58 -0
  7. package/dist/installer/file-ops/file-ops.js.map +1 -0
  8. package/dist/installer/hook-installer/hook-installer.d.ts +29 -0
  9. package/dist/installer/hook-installer/hook-installer.d.ts.map +1 -0
  10. package/dist/installer/hook-installer/hook-installer.js +96 -0
  11. package/dist/installer/hook-installer/hook-installer.js.map +1 -0
  12. package/dist/installer/install.d.ts +3 -0
  13. package/dist/installer/install.d.ts.map +1 -0
  14. package/dist/installer/install.js +248 -0
  15. package/dist/installer/install.js.map +1 -0
  16. package/dist/installer/manifest/manifest.d.ts +41 -0
  17. package/dist/installer/manifest/manifest.d.ts.map +1 -0
  18. package/dist/installer/manifest/manifest.js +97 -0
  19. package/dist/installer/manifest/manifest.js.map +1 -0
  20. package/dist/installer/prompts/prompts.d.ts +33 -0
  21. package/dist/installer/prompts/prompts.d.ts.map +1 -0
  22. package/dist/installer/prompts/prompts.js +55 -0
  23. package/dist/installer/prompts/prompts.js.map +1 -0
  24. package/dist/schemas/env.d.ts +75 -0
  25. package/dist/schemas/env.d.ts.map +1 -0
  26. package/dist/schemas/env.js +40 -0
  27. package/dist/schemas/env.js.map +1 -0
  28. package/dist/schemas/github.d.ts +27 -0
  29. package/dist/schemas/github.d.ts.map +1 -0
  30. package/dist/schemas/github.js +17 -0
  31. package/dist/schemas/github.js.map +1 -0
  32. package/dist/schemas/index.d.ts +9 -0
  33. package/dist/schemas/index.d.ts.map +1 -0
  34. package/dist/schemas/index.js +5 -0
  35. package/dist/schemas/index.js.map +1 -0
  36. package/dist/schemas/jira.d.ts +37 -0
  37. package/dist/schemas/jira.d.ts.map +1 -0
  38. package/dist/schemas/jira.js +37 -0
  39. package/dist/schemas/jira.js.map +1 -0
  40. package/dist/schemas/linear.d.ts +67 -0
  41. package/dist/schemas/linear.d.ts.map +1 -0
  42. package/dist/schemas/linear.js +50 -0
  43. package/dist/schemas/linear.js.map +1 -0
  44. package/dist/scripts/afk/afk.d.ts +21 -0
  45. package/dist/scripts/afk/afk.d.ts.map +1 -0
  46. package/dist/scripts/afk/afk.js +124 -0
  47. package/dist/scripts/afk/afk.js.map +1 -0
  48. package/dist/scripts/board/github/github.d.ts +40 -0
  49. package/dist/scripts/board/github/github.d.ts.map +1 -0
  50. package/dist/scripts/board/github/github.js +121 -0
  51. package/dist/scripts/board/github/github.js.map +1 -0
  52. package/dist/scripts/board/jira/jira.d.ts +90 -0
  53. package/dist/scripts/board/jira/jira.d.ts.map +1 -0
  54. package/dist/scripts/board/jira/jira.js +251 -0
  55. package/dist/scripts/board/jira/jira.js.map +1 -0
  56. package/dist/scripts/board/linear/linear.d.ts +85 -0
  57. package/dist/scripts/board/linear/linear.d.ts.map +1 -0
  58. package/dist/scripts/board/linear/linear.js +209 -0
  59. package/dist/scripts/board/linear/linear.js.map +1 -0
  60. package/dist/scripts/once/once.d.ts +12 -0
  61. package/dist/scripts/once/once.d.ts.map +1 -0
  62. package/dist/scripts/once/once.js +330 -0
  63. package/dist/scripts/once/once.js.map +1 -0
  64. package/dist/scripts/shared/branch/branch.d.ts +50 -0
  65. package/dist/scripts/shared/branch/branch.d.ts.map +1 -0
  66. package/dist/scripts/shared/branch/branch.js +61 -0
  67. package/dist/scripts/shared/branch/branch.js.map +1 -0
  68. package/dist/scripts/shared/claude-cli/claude-cli.d.ts +17 -0
  69. package/dist/scripts/shared/claude-cli/claude-cli.d.ts.map +1 -0
  70. package/dist/scripts/shared/claude-cli/claude-cli.js +35 -0
  71. package/dist/scripts/shared/claude-cli/claude-cli.js.map +1 -0
  72. package/dist/scripts/shared/env-parser/env-parser.d.ts +30 -0
  73. package/dist/scripts/shared/env-parser/env-parser.d.ts.map +1 -0
  74. package/dist/scripts/shared/env-parser/env-parser.js +64 -0
  75. package/dist/scripts/shared/env-parser/env-parser.js.map +1 -0
  76. package/dist/scripts/shared/env-schema/env-schema.d.ts +27 -0
  77. package/dist/scripts/shared/env-schema/env-schema.d.ts.map +1 -0
  78. package/dist/scripts/shared/env-schema/env-schema.js +46 -0
  79. package/dist/scripts/shared/env-schema/env-schema.js.map +1 -0
  80. package/dist/scripts/shared/git-ops/git-ops.d.ts +52 -0
  81. package/dist/scripts/shared/git-ops/git-ops.d.ts.map +1 -0
  82. package/dist/scripts/shared/git-ops/git-ops.js +107 -0
  83. package/dist/scripts/shared/git-ops/git-ops.js.map +1 -0
  84. package/dist/scripts/shared/http/http.d.ts +52 -0
  85. package/dist/scripts/shared/http/http.d.ts.map +1 -0
  86. package/dist/scripts/shared/http/http.js +74 -0
  87. package/dist/scripts/shared/http/http.js.map +1 -0
  88. package/dist/scripts/shared/notify/notify.d.ts +46 -0
  89. package/dist/scripts/shared/notify/notify.d.ts.map +1 -0
  90. package/dist/scripts/shared/notify/notify.js +88 -0
  91. package/dist/scripts/shared/notify/notify.js.map +1 -0
  92. package/dist/scripts/shared/preflight/preflight.d.ts +40 -0
  93. package/dist/scripts/shared/preflight/preflight.d.ts.map +1 -0
  94. package/dist/scripts/shared/preflight/preflight.js +84 -0
  95. package/dist/scripts/shared/preflight/preflight.js.map +1 -0
  96. package/dist/scripts/shared/progress/progress.d.ts +25 -0
  97. package/dist/scripts/shared/progress/progress.d.ts.map +1 -0
  98. package/dist/scripts/shared/progress/progress.js +46 -0
  99. package/dist/scripts/shared/progress/progress.js.map +1 -0
  100. package/dist/scripts/shared/prompt/prompt.d.ts +38 -0
  101. package/dist/scripts/shared/prompt/prompt.d.ts.map +1 -0
  102. package/dist/scripts/shared/prompt/prompt.js +77 -0
  103. package/dist/scripts/shared/prompt/prompt.js.map +1 -0
  104. package/dist/types/board.d.ts +13 -0
  105. package/dist/types/board.d.ts.map +1 -0
  106. package/dist/types/board.js +5 -0
  107. package/dist/types/board.js.map +1 -0
  108. package/dist/types/index.d.ts +3 -0
  109. package/dist/types/index.d.ts.map +1 -0
  110. package/dist/types/index.js +2 -0
  111. package/dist/types/index.js.map +1 -0
  112. package/dist/utils/ansi/ansi.d.ts +55 -0
  113. package/dist/utils/ansi/ansi.d.ts.map +1 -0
  114. package/dist/utils/ansi/ansi.js +55 -0
  115. package/dist/utils/ansi/ansi.js.map +1 -0
  116. package/dist/utils/parse-json/parse-json.d.ts +20 -0
  117. package/dist/utils/parse-json/parse-json.d.ts.map +1 -0
  118. package/dist/utils/parse-json/parse-json.js +27 -0
  119. package/dist/utils/parse-json/parse-json.js.map +1 -0
  120. package/hooks/clancy-check-update.js +2 -2
  121. package/hooks/clancy-credential-guard.js +8 -1
  122. package/package.json +48 -8
  123. package/registry/boards.json +3 -6
  124. package/src/templates/CLAUDE.md +1 -1
  125. package/src/workflows/doctor.md +32 -23
  126. package/src/workflows/init.md +101 -26
  127. package/src/workflows/logs.md +13 -6
  128. package/src/workflows/map-codebase.md +17 -16
  129. package/src/workflows/once.md +22 -12
  130. package/src/workflows/review.md +40 -27
  131. package/src/workflows/run.md +20 -12
  132. package/src/workflows/scaffold.md +5 -1034
  133. package/src/workflows/settings.md +9 -6
  134. package/src/workflows/status.md +17 -8
  135. package/src/workflows/uninstall.md +11 -6
  136. package/src/workflows/update.md +20 -13
  137. package/bin/install.js +0 -362
  138. package/src/templates/scripts/clancy-afk.sh +0 -111
  139. package/src/templates/scripts/clancy-once-github.sh +0 -249
  140. package/src/templates/scripts/clancy-once-linear.sh +0 -320
  141. 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?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-94%20passing-brightgreen?style=for-the-badge)](./test/) [![GitHub Stars](https://img.shields.io/github/stars/Pushedskydiver/clancy?style=for-the-badge)](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,101 @@
1
+ // dist/scripts/afk/afk.js
2
+ import { spawnSync } from "node:child_process";
3
+ import { existsSync } from "node:fs";
4
+ import { dirname, join, resolve } from "node:path";
5
+ import { setTimeout as sleep } from "node:timers/promises";
6
+ import { fileURLToPath } from "node:url";
7
+
8
+ // dist/utils/ansi/ansi.js
9
+ var dim = (s) => `\x1B[2m${s}\x1B[0m`;
10
+ var bold = (s) => `\x1B[1m${s}\x1B[0m`;
11
+ var green = (s) => `\x1B[32m${s}\x1B[0m`;
12
+ var red = (s) => `\x1B[31m${s}\x1B[0m`;
13
+
14
+ // dist/scripts/afk/afk.js
15
+ function formatDuration(ms) {
16
+ const secs = Math.floor(ms / 1e3);
17
+ if (secs < 60)
18
+ return `${secs}s`;
19
+ const mins = Math.floor(secs / 60);
20
+ const remSecs = secs % 60;
21
+ return remSecs > 0 ? `${mins}m ${remSecs}s` : `${mins}m`;
22
+ }
23
+ var STOP_PATTERNS = {
24
+ noTickets: /No tickets found|No issues found|All done/,
25
+ skipped: /Ticket skipped/,
26
+ preflightFail: /^✗ /m
27
+ };
28
+ function checkStopCondition(output) {
29
+ if (STOP_PATTERNS.noTickets.test(output)) {
30
+ return { stop: true, reason: "No more tickets \u2014 all done" };
31
+ }
32
+ if (STOP_PATTERNS.skipped.test(output)) {
33
+ return {
34
+ stop: true,
35
+ reason: "Ticket was skipped \u2014 update the ticket and re-run"
36
+ };
37
+ }
38
+ if (STOP_PATTERNS.preflightFail.test(output)) {
39
+ return { stop: true, reason: "Preflight check failed" };
40
+ }
41
+ return { stop: false };
42
+ }
43
+ async function runAfkLoop(scriptDir, maxIterations = 5) {
44
+ const onceScript = join(scriptDir, "clancy-once.js");
45
+ if (!existsSync(onceScript)) {
46
+ console.error(red("\u2717 clancy-once.js not found in"), scriptDir);
47
+ return;
48
+ }
49
+ console.log(dim("\u250C\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510"));
50
+ console.log(dim("\u2502") + bold(" \u{1F916} Clancy \u2014 AFK mode ") + dim("\u2502"));
51
+ console.log(dim("\u2502") + dim(` "I'm on it. Proceed to the abandoned warehouse." `) + dim("\u2502"));
52
+ console.log(dim("\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518"));
53
+ const loopStart = Date.now();
54
+ for (let i = 1; i <= maxIterations; i++) {
55
+ const iterStart = Date.now();
56
+ console.log("");
57
+ console.log(bold(`\u{1F501} Iteration ${i}/${maxIterations}`));
58
+ const result = spawnSync("node", [onceScript], {
59
+ encoding: "utf8",
60
+ stdio: ["inherit", "pipe", "inherit"],
61
+ cwd: process.cwd()
62
+ });
63
+ const output = result.stdout ?? "";
64
+ if (output) {
65
+ process.stdout.write(output);
66
+ }
67
+ const iterElapsed = formatDuration(Date.now() - iterStart);
68
+ if (result.error) {
69
+ console.error(red(`\u2717 Failed to run clancy-once: ${result.error.message}`));
70
+ return;
71
+ }
72
+ const condition = checkStopCondition(output);
73
+ if (condition.stop) {
74
+ const totalElapsed2 = formatDuration(Date.now() - loopStart);
75
+ console.log("");
76
+ console.log(dim(` Iteration ${i} took ${iterElapsed}`));
77
+ console.log(`
78
+ ${condition.reason}`);
79
+ console.log(dim(` Total: ${i} iteration${i > 1 ? "s" : ""} in ${totalElapsed2}`));
80
+ return;
81
+ }
82
+ console.log(dim(` Iteration ${i} took ${iterElapsed}`));
83
+ if (i < maxIterations) {
84
+ await sleep(2e3);
85
+ }
86
+ }
87
+ const totalElapsed = formatDuration(Date.now() - loopStart);
88
+ console.log("");
89
+ console.log(green(`\u{1F3C1} Completed ${maxIterations} iterations`) + dim(` (${totalElapsed})`));
90
+ console.log(dim(` "That's some good police work."`));
91
+ console.log(dim(" Run clancy-afk again to continue."));
92
+ }
93
+ if (process.argv[1] && fileURLToPath(import.meta.url) === resolve(process.argv[1])) {
94
+ const scriptDir = dirname(fileURLToPath(import.meta.url));
95
+ const maxIterations = parseInt(process.env.MAX_ITERATIONS ?? "5", 10) || 5;
96
+ runAfkLoop(scriptDir, maxIterations);
97
+ }
98
+ export {
99
+ checkStopCondition,
100
+ runAfkLoop
101
+ };