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.
- package/README.md +13 -24
- package/dist/bundle/clancy-afk.js +101 -0
- package/dist/bundle/clancy-once.js +13902 -0
- package/dist/installer/file-ops/file-ops.d.ts +32 -0
- package/dist/installer/file-ops/file-ops.d.ts.map +1 -0
- package/dist/installer/file-ops/file-ops.js +58 -0
- package/dist/installer/file-ops/file-ops.js.map +1 -0
- package/dist/installer/hook-installer/hook-installer.d.ts +29 -0
- package/dist/installer/hook-installer/hook-installer.d.ts.map +1 -0
- package/dist/installer/hook-installer/hook-installer.js +96 -0
- package/dist/installer/hook-installer/hook-installer.js.map +1 -0
- package/dist/installer/install.d.ts +3 -0
- package/dist/installer/install.d.ts.map +1 -0
- package/dist/installer/install.js +248 -0
- package/dist/installer/install.js.map +1 -0
- package/dist/installer/manifest/manifest.d.ts +41 -0
- package/dist/installer/manifest/manifest.d.ts.map +1 -0
- package/dist/installer/manifest/manifest.js +97 -0
- package/dist/installer/manifest/manifest.js.map +1 -0
- package/dist/installer/prompts/prompts.d.ts +33 -0
- package/dist/installer/prompts/prompts.d.ts.map +1 -0
- package/dist/installer/prompts/prompts.js +55 -0
- package/dist/installer/prompts/prompts.js.map +1 -0
- package/dist/schemas/env.d.ts +75 -0
- package/dist/schemas/env.d.ts.map +1 -0
- package/dist/schemas/env.js +40 -0
- package/dist/schemas/env.js.map +1 -0
- package/dist/schemas/github.d.ts +27 -0
- package/dist/schemas/github.d.ts.map +1 -0
- package/dist/schemas/github.js +17 -0
- package/dist/schemas/github.js.map +1 -0
- package/dist/schemas/index.d.ts +9 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +5 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/jira.d.ts +37 -0
- package/dist/schemas/jira.d.ts.map +1 -0
- package/dist/schemas/jira.js +37 -0
- package/dist/schemas/jira.js.map +1 -0
- package/dist/schemas/linear.d.ts +67 -0
- package/dist/schemas/linear.d.ts.map +1 -0
- package/dist/schemas/linear.js +50 -0
- package/dist/schemas/linear.js.map +1 -0
- package/dist/scripts/afk/afk.d.ts +21 -0
- package/dist/scripts/afk/afk.d.ts.map +1 -0
- package/dist/scripts/afk/afk.js +124 -0
- package/dist/scripts/afk/afk.js.map +1 -0
- package/dist/scripts/board/github/github.d.ts +40 -0
- package/dist/scripts/board/github/github.d.ts.map +1 -0
- package/dist/scripts/board/github/github.js +121 -0
- package/dist/scripts/board/github/github.js.map +1 -0
- package/dist/scripts/board/jira/jira.d.ts +90 -0
- package/dist/scripts/board/jira/jira.d.ts.map +1 -0
- package/dist/scripts/board/jira/jira.js +251 -0
- package/dist/scripts/board/jira/jira.js.map +1 -0
- package/dist/scripts/board/linear/linear.d.ts +85 -0
- package/dist/scripts/board/linear/linear.d.ts.map +1 -0
- package/dist/scripts/board/linear/linear.js +209 -0
- package/dist/scripts/board/linear/linear.js.map +1 -0
- package/dist/scripts/once/once.d.ts +12 -0
- package/dist/scripts/once/once.d.ts.map +1 -0
- package/dist/scripts/once/once.js +330 -0
- package/dist/scripts/once/once.js.map +1 -0
- package/dist/scripts/shared/branch/branch.d.ts +50 -0
- package/dist/scripts/shared/branch/branch.d.ts.map +1 -0
- package/dist/scripts/shared/branch/branch.js +61 -0
- package/dist/scripts/shared/branch/branch.js.map +1 -0
- package/dist/scripts/shared/claude-cli/claude-cli.d.ts +17 -0
- package/dist/scripts/shared/claude-cli/claude-cli.d.ts.map +1 -0
- package/dist/scripts/shared/claude-cli/claude-cli.js +35 -0
- package/dist/scripts/shared/claude-cli/claude-cli.js.map +1 -0
- package/dist/scripts/shared/env-parser/env-parser.d.ts +30 -0
- package/dist/scripts/shared/env-parser/env-parser.d.ts.map +1 -0
- package/dist/scripts/shared/env-parser/env-parser.js +64 -0
- package/dist/scripts/shared/env-parser/env-parser.js.map +1 -0
- package/dist/scripts/shared/env-schema/env-schema.d.ts +27 -0
- package/dist/scripts/shared/env-schema/env-schema.d.ts.map +1 -0
- package/dist/scripts/shared/env-schema/env-schema.js +46 -0
- package/dist/scripts/shared/env-schema/env-schema.js.map +1 -0
- package/dist/scripts/shared/git-ops/git-ops.d.ts +52 -0
- package/dist/scripts/shared/git-ops/git-ops.d.ts.map +1 -0
- package/dist/scripts/shared/git-ops/git-ops.js +107 -0
- package/dist/scripts/shared/git-ops/git-ops.js.map +1 -0
- package/dist/scripts/shared/http/http.d.ts +52 -0
- package/dist/scripts/shared/http/http.d.ts.map +1 -0
- package/dist/scripts/shared/http/http.js +74 -0
- package/dist/scripts/shared/http/http.js.map +1 -0
- package/dist/scripts/shared/notify/notify.d.ts +46 -0
- package/dist/scripts/shared/notify/notify.d.ts.map +1 -0
- package/dist/scripts/shared/notify/notify.js +88 -0
- package/dist/scripts/shared/notify/notify.js.map +1 -0
- package/dist/scripts/shared/preflight/preflight.d.ts +40 -0
- package/dist/scripts/shared/preflight/preflight.d.ts.map +1 -0
- package/dist/scripts/shared/preflight/preflight.js +84 -0
- package/dist/scripts/shared/preflight/preflight.js.map +1 -0
- package/dist/scripts/shared/progress/progress.d.ts +25 -0
- package/dist/scripts/shared/progress/progress.d.ts.map +1 -0
- package/dist/scripts/shared/progress/progress.js +46 -0
- package/dist/scripts/shared/progress/progress.js.map +1 -0
- package/dist/scripts/shared/prompt/prompt.d.ts +38 -0
- package/dist/scripts/shared/prompt/prompt.d.ts.map +1 -0
- package/dist/scripts/shared/prompt/prompt.js +77 -0
- package/dist/scripts/shared/prompt/prompt.js.map +1 -0
- package/dist/types/board.d.ts +13 -0
- package/dist/types/board.d.ts.map +1 -0
- package/dist/types/board.js +5 -0
- package/dist/types/board.js.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/ansi/ansi.d.ts +55 -0
- package/dist/utils/ansi/ansi.d.ts.map +1 -0
- package/dist/utils/ansi/ansi.js +55 -0
- package/dist/utils/ansi/ansi.js.map +1 -0
- package/dist/utils/parse-json/parse-json.d.ts +20 -0
- package/dist/utils/parse-json/parse-json.d.ts.map +1 -0
- package/dist/utils/parse-json/parse-json.js +27 -0
- package/dist/utils/parse-json/parse-json.js.map +1 -0
- package/hooks/clancy-check-update.js +2 -2
- package/hooks/clancy-credential-guard.js +8 -1
- package/package.json +48 -8
- package/registry/boards.json +3 -6
- package/src/templates/CLAUDE.md +1 -1
- package/src/workflows/doctor.md +32 -23
- package/src/workflows/init.md +101 -26
- package/src/workflows/logs.md +13 -6
- package/src/workflows/map-codebase.md +17 -16
- package/src/workflows/once.md +22 -12
- package/src/workflows/review.md +40 -27
- package/src/workflows/run.md +20 -12
- package/src/workflows/scaffold.md +5 -1034
- package/src/workflows/settings.md +9 -6
- package/src/workflows/status.md +17 -8
- package/src/workflows/uninstall.md +11 -6
- package/src/workflows/update.md +20 -13
- package/bin/install.js +0 -362
- package/src/templates/scripts/clancy-afk.sh +0 -111
- package/src/templates/scripts/clancy-once-github.sh +0 -249
- package/src/templates/scripts/clancy-once-linear.sh +0 -320
- 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
|
-
[](https://www.npmjs.com/package/chief-clancy) [](./LICENSE) [](https://www.npmjs.com/package/chief-clancy) [](./LICENSE) [](docs/TESTING.md) [](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
|
|
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
|
-
-
|
|
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 `
|
|
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.
|
|
172
|
-
clancy-afk.
|
|
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.
|
|
243
|
+
clancy-afk.js
|
|
245
244
|
└─ while i < MAX_ITERATIONS:
|
|
246
|
-
|
|
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 -
|
|
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(
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
+
};
|