bellwether 0.0.4 → 0.0.5
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/.claude-plugin/plugin.json +1 -1
- package/dist/bin.js +2 -14
- package/dist/bin.js.map +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +10 -3
- package/dist/cli.js.map +1 -1
- package/dist/commands/hook-add.d.ts +14 -1
- package/dist/commands/hook-add.d.ts.map +1 -1
- package/dist/commands/hook-add.js +15 -19
- package/dist/commands/hook-add.js.map +1 -1
- package/dist/commands/hook-check.d.ts +18 -1
- package/dist/commands/hook-check.d.ts.map +1 -1
- package/dist/commands/hook-check.js +34 -26
- package/dist/commands/hook-check.js.map +1 -1
- package/hooks/hooks.json +3 -3
- package/package.json +1 -1
- package/src/bin.ts +2 -13
- package/src/cli.ts +13 -3
- package/src/commands/hook-add.ts +15 -22
- package/src/commands/hook-check.ts +43 -29
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "bellwether",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"description": "Drive PRs to merge-ready: watch CI, fix failures, resolve review comments. Self-contained watch loop that keeps going until pr.ready=true.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Roderik van der Veer",
|
package/dist/bin.js
CHANGED
|
@@ -1,17 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
const
|
|
3
|
-
|
|
4
|
-
if (cmd === "hook-check") {
|
|
5
|
-
const { run } = await import("./commands/hook-check.js");
|
|
6
|
-
await run();
|
|
7
|
-
}
|
|
8
|
-
else if (cmd === "hook-add") {
|
|
9
|
-
const { run } = await import("./commands/hook-add.js");
|
|
10
|
-
await run();
|
|
11
|
-
}
|
|
12
|
-
else {
|
|
13
|
-
const { cli } = await import("./cli.js");
|
|
14
|
-
void cli.serve();
|
|
15
|
-
}
|
|
2
|
+
const { cli } = await import("./cli.js");
|
|
3
|
+
void cli.serve();
|
|
16
4
|
export {};
|
|
17
5
|
//# sourceMappingURL=bin.js.map
|
package/dist/bin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AAEA,MAAM,
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AAEA,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;AACzC,KAAK,GAAG,CAAC,KAAK,EAAE,CAAC"}
|
package/dist/cli.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAa,KAAK,OAAO,EAAE,MAAM,cAAc,CAAC;AASvD,QAAA,MAAM,GAAG;;;;;;;kBAyBP,CAAC;AAaH,OAAO,EAAE,GAAG,EAAE,CAAC;AACf,eAAe,GAAG,CAAC"}
|
package/dist/cli.js
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
1
2
|
import { join } from "node:path";
|
|
2
3
|
import { Cli, z } from "incur";
|
|
3
4
|
import { bootstrap } from "./context.js";
|
|
4
5
|
import { checkCommand } from "./commands/check.js";
|
|
6
|
+
import { hookAddCommand } from "./commands/hook-add.js";
|
|
7
|
+
import { hookCheckCommand } from "./commands/hook-check.js";
|
|
8
|
+
const pkg = JSON.parse(readFileSync(join(import.meta.dirname, "..", "package.json"), "utf-8"));
|
|
5
9
|
const cli = Cli.create("bellwether", {
|
|
6
|
-
version:
|
|
10
|
+
version: pkg.version,
|
|
7
11
|
description: "Monitor GitHub PRs — review comments and CI status",
|
|
8
12
|
vars: z.object({
|
|
9
13
|
ctx: z.custom(),
|
|
@@ -19,7 +23,6 @@ const cli = Cli.create("bellwether", {
|
|
|
19
23
|
}),
|
|
20
24
|
sync: {
|
|
21
25
|
depth: 0,
|
|
22
|
-
cwd: join(import.meta.dirname, ".."),
|
|
23
26
|
include: ["_root"],
|
|
24
27
|
suggestions: [
|
|
25
28
|
"check CI and reviews for this PR",
|
|
@@ -30,10 +33,14 @@ const cli = Cli.create("bellwether", {
|
|
|
30
33
|
},
|
|
31
34
|
});
|
|
32
35
|
cli.use(async (c, next) => {
|
|
33
|
-
c.
|
|
36
|
+
if (!c.command.startsWith("hook")) {
|
|
37
|
+
c.set("ctx", await bootstrap());
|
|
38
|
+
}
|
|
34
39
|
await next();
|
|
35
40
|
});
|
|
36
41
|
cli.command("check", checkCommand);
|
|
42
|
+
cli.command("hook-add", hookAddCommand);
|
|
43
|
+
cli.command("hook-check", hookCheckCommand);
|
|
37
44
|
export { cli };
|
|
38
45
|
export default cli;
|
|
39
46
|
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,SAAS,EAAgB,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,SAAS,EAAgB,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AACxD,OAAO,EAAE,gBAAgB,EAAE,MAAM,0BAA0B,CAAC;AAE5D,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,CAE5F,CAAC;AAEF,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,YAAY,EAAE;IACnC,OAAO,EAAE,GAAG,CAAC,OAAO;IACpB,WAAW,EAAE,oDAAoD;IACjE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;QACb,GAAG,EAAE,CAAC,CAAC,MAAM,EAAW;KACzB,CAAC;IACF,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC;QACZ,YAAY,EAAE,CAAC;aACZ,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,wEAAwE,CAAC;QACrF,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kCAAkC,CAAC;QAC5E,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,0CAA0C,CAAC;QACnF,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,kDAAkD,CAAC;KAChG,CAAC;IACF,IAAI,EAAE;QACJ,KAAK,EAAE,CAAC;QACR,OAAO,EAAE,CAAC,OAAO,CAAC;QAClB,WAAW,EAAE;YACX,kCAAkC;YAClC,iCAAiC;YACjC,yBAAyB;YACzB,+BAA+B;SAChC;KACF;CACF,CAAC,CAAC;AAEH,GAAG,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,EAAE;IACxB,IAAI,CAAC,CAAC,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QAClC,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,SAAS,EAAE,CAAC,CAAC;IAClC,CAAC;IACD,MAAM,IAAI,EAAE,CAAC;AACf,CAAC,CAAC,CAAC;AAEH,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,YAA4D,CAAC,CAAC;AACnF,GAAG,CAAC,OAAO,CAAC,UAAU,EAAE,cAA8D,CAAC,CAAC;AACxF,GAAG,CAAC,OAAO,CAAC,YAAY,EAAE,gBAAgE,CAAC,CAAC;AAE5F,OAAO,EAAE,GAAG,EAAE,CAAC;AACf,eAAe,GAAG,CAAC"}
|
|
@@ -1,2 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
import { z } from "incur";
|
|
2
|
+
export declare const hookAddCommand: {
|
|
3
|
+
description: string;
|
|
4
|
+
output: z.ZodObject<{
|
|
5
|
+
claude: z.ZodString;
|
|
6
|
+
codex: z.ZodNullable<z.ZodString>;
|
|
7
|
+
}, z.core.$strip>;
|
|
8
|
+
run(c: {
|
|
9
|
+
ok: (data: {
|
|
10
|
+
claude: string;
|
|
11
|
+
codex: string | null;
|
|
12
|
+
}) => unknown;
|
|
13
|
+
}): Promise<unknown>;
|
|
14
|
+
};
|
|
2
15
|
//# sourceMappingURL=hook-add.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hook-add.d.ts","sourceRoot":"","sources":["../../src/commands/hook-add.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hook-add.d.ts","sourceRoot":"","sources":["../../src/commands/hook-add.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,CAAC,EAAE,MAAM,OAAO,CAAC;AAoH1B,eAAO,MAAM,cAAc;;;;;;WAMZ;QAAE,EAAE,EAAE,CAAC,IAAI,EAAE;YAAE,MAAM,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;SAAE,KAAK,OAAO,CAAA;KAAE;CAKjF,CAAC"}
|
|
@@ -1,11 +1,9 @@
|
|
|
1
|
-
// Standalone hook installer — bypasses incur.
|
|
2
|
-
// Configures PostToolUse hooks in Claude Code and Codex globally.
|
|
3
|
-
// Idempotent: checks if already configured, updates if needed.
|
|
4
1
|
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
5
2
|
import { existsSync } from "node:fs";
|
|
6
3
|
import { join } from "node:path";
|
|
7
4
|
import { homedir } from "node:os";
|
|
8
|
-
|
|
5
|
+
import { z } from "incur";
|
|
6
|
+
const HOOK_COMMAND = "npx -y bellwether@latest hook-check --format json";
|
|
9
7
|
const HOOK_TIMEOUT = 15;
|
|
10
8
|
const BELLWETHER_MARKER = "bellwether@latest hook-check";
|
|
11
9
|
function buildClaudeHooks() {
|
|
@@ -78,20 +76,18 @@ async function configureCodex() {
|
|
|
78
76
|
return hooksPath;
|
|
79
77
|
}
|
|
80
78
|
// ---------------------------------------------------------------------------
|
|
81
|
-
//
|
|
79
|
+
// Incur command
|
|
82
80
|
// ---------------------------------------------------------------------------
|
|
83
|
-
export
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
console.log("The LLM will be prompted to run bellwether to monitor the PR.");
|
|
96
|
-
}
|
|
81
|
+
export const hookAddCommand = {
|
|
82
|
+
description: "Install PostToolUse hooks for Claude Code and Codex",
|
|
83
|
+
output: z.object({
|
|
84
|
+
claude: z.string().describe("Path to Claude Code settings file"),
|
|
85
|
+
codex: z.string().nullable().describe("Path to Codex hooks file, or null if not installed"),
|
|
86
|
+
}),
|
|
87
|
+
async run(c) {
|
|
88
|
+
const claudePath = await configureClaude();
|
|
89
|
+
const codexPath = await configureCodex();
|
|
90
|
+
return c.ok({ claude: claudePath, codex: codexPath });
|
|
91
|
+
},
|
|
92
|
+
};
|
|
97
93
|
//# sourceMappingURL=hook-add.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hook-add.js","sourceRoot":"","sources":["../../src/commands/hook-add.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"hook-add.js","sourceRoot":"","sources":["../../src/commands/hook-add.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,2 +1,19 @@
|
|
|
1
|
-
|
|
1
|
+
import { z } from "incur";
|
|
2
|
+
export declare const hookCheckCommand: {
|
|
3
|
+
description: string;
|
|
4
|
+
output: z.ZodObject<{
|
|
5
|
+
hookSpecificOutput: z.ZodOptional<z.ZodObject<{
|
|
6
|
+
hookEventName: z.ZodString;
|
|
7
|
+
additionalContext: z.ZodString;
|
|
8
|
+
}, z.core.$strip>>;
|
|
9
|
+
}, z.core.$strip>;
|
|
10
|
+
run(c: {
|
|
11
|
+
ok: (data: {
|
|
12
|
+
hookSpecificOutput?: {
|
|
13
|
+
hookEventName: string;
|
|
14
|
+
additionalContext: string;
|
|
15
|
+
};
|
|
16
|
+
}) => unknown;
|
|
17
|
+
}): Promise<unknown>;
|
|
18
|
+
};
|
|
2
19
|
//# sourceMappingURL=hook-check.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hook-check.d.ts","sourceRoot":"","sources":["../../src/commands/hook-check.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"hook-check.d.ts","sourceRoot":"","sources":["../../src/commands/hook-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,OAAO,CAAC;AAI1B,eAAO,MAAM,gBAAgB;;;;;;;;WAWd;QACX,EAAE,EAAE,CAAC,IAAI,EAAE;YACT,kBAAkB,CAAC,EAAE;gBAAE,aAAa,EAAE,MAAM,CAAC;gBAAC,iBAAiB,EAAE,MAAM,CAAA;aAAE,CAAC;SAC3E,KAAK,OAAO,CAAC;KACf;CA6BF,CAAC"}
|
|
@@ -1,29 +1,37 @@
|
|
|
1
|
-
|
|
2
|
-
// Reads Claude/Codex PostToolUse JSON from stdin.
|
|
3
|
-
// If the command is a PR-related action, outputs additionalContext
|
|
4
|
-
// telling the LLM to start monitoring with bellwether.
|
|
1
|
+
import { z } from "incur";
|
|
5
2
|
const PR_PATTERN = /\bgit\s+push\b|\bgh\s+pr\s+(create|ready)\b/;
|
|
6
|
-
export
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
},
|
|
21
|
-
};
|
|
22
|
-
process.stdout.write(JSON.stringify(output));
|
|
3
|
+
export const hookCheckCommand = {
|
|
4
|
+
description: "PostToolUse hook handler — reads hook event from stdin, outputs context if PR-related",
|
|
5
|
+
output: z.object({
|
|
6
|
+
hookSpecificOutput: z
|
|
7
|
+
.object({
|
|
8
|
+
hookEventName: z.string(),
|
|
9
|
+
additionalContext: z.string(),
|
|
10
|
+
})
|
|
11
|
+
.optional(),
|
|
12
|
+
}),
|
|
13
|
+
async run(c) {
|
|
14
|
+
const chunks = [];
|
|
15
|
+
for await (const chunk of process.stdin) {
|
|
16
|
+
chunks.push(chunk);
|
|
23
17
|
}
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
18
|
+
let command = "";
|
|
19
|
+
try {
|
|
20
|
+
const input = JSON.parse(Buffer.concat(chunks).toString());
|
|
21
|
+
command = input.tool_input?.command ?? "";
|
|
22
|
+
if (PR_PATTERN.test(command)) {
|
|
23
|
+
return c.ok({
|
|
24
|
+
hookSpecificOutput: {
|
|
25
|
+
hookEventName: input.hook_event_name ?? "PostToolUse",
|
|
26
|
+
additionalContext: "PR pushed. Run `npx -y bellwether@latest check --watch` to monitor CI and reviews until merge-ready.",
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// Malformed input — return empty
|
|
33
|
+
}
|
|
34
|
+
return c.ok({});
|
|
35
|
+
},
|
|
36
|
+
};
|
|
29
37
|
//# sourceMappingURL=hook-check.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hook-check.js","sourceRoot":"","sources":["../../src/commands/hook-check.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"hook-check.js","sourceRoot":"","sources":["../../src/commands/hook-check.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,OAAO,CAAC;AAE1B,MAAM,UAAU,GAAG,6CAA6C,CAAC;AAEjE,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,WAAW,EACT,uFAAuF;IACzF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,kBAAkB,EAAE,CAAC;aAClB,MAAM,CAAC;YACN,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE;YACzB,iBAAiB,EAAE,CAAC,CAAC,MAAM,EAAE;SAC9B,CAAC;aACD,QAAQ,EAAE;KACd,CAAC;IACF,KAAK,CAAC,GAAG,CAAC,CAIT;QACC,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;YACxC,MAAM,CAAC,IAAI,CAAC,KAAe,CAAC,CAAC;QAC/B,CAAC;QAED,IAAI,OAAO,GAAG,EAAE,CAAC;QACjB,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAGxD,CAAC;YACF,OAAO,GAAG,KAAK,CAAC,UAAU,EAAE,OAAO,IAAI,EAAE,CAAC;YAE1C,IAAI,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;gBAC7B,OAAO,CAAC,CAAC,EAAE,CAAC;oBACV,kBAAkB,EAAE;wBAClB,aAAa,EAAE,KAAK,CAAC,eAAe,IAAI,aAAa;wBACrD,iBAAiB,EACf,sGAAsG;qBACzG;iBACF,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,iCAAiC;QACnC,CAAC;QAED,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IAClB,CAAC;CACF,CAAC"}
|
package/hooks/hooks.json
CHANGED
|
@@ -7,19 +7,19 @@
|
|
|
7
7
|
{
|
|
8
8
|
"type": "command",
|
|
9
9
|
"if": "Bash(git push*)",
|
|
10
|
-
"command": "npx -y bellwether@latest hook-check",
|
|
10
|
+
"command": "npx -y bellwether@latest hook-check --format json",
|
|
11
11
|
"timeout": 15
|
|
12
12
|
},
|
|
13
13
|
{
|
|
14
14
|
"type": "command",
|
|
15
15
|
"if": "Bash(gh pr create*)",
|
|
16
|
-
"command": "npx -y bellwether@latest hook-check",
|
|
16
|
+
"command": "npx -y bellwether@latest hook-check --format json",
|
|
17
17
|
"timeout": 15
|
|
18
18
|
},
|
|
19
19
|
{
|
|
20
20
|
"type": "command",
|
|
21
21
|
"if": "Bash(gh pr ready*)",
|
|
22
|
-
"command": "npx -y bellwether@latest hook-check",
|
|
22
|
+
"command": "npx -y bellwether@latest hook-check --format json",
|
|
23
23
|
"timeout": 15
|
|
24
24
|
}
|
|
25
25
|
]
|
package/package.json
CHANGED
package/src/bin.ts
CHANGED
|
@@ -1,15 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
// Fast path for hook commands — bypass incur entirely for speed
|
|
6
|
-
if (cmd === "hook-check") {
|
|
7
|
-
const { run } = await import("./commands/hook-check.js");
|
|
8
|
-
await run();
|
|
9
|
-
} else if (cmd === "hook-add") {
|
|
10
|
-
const { run } = await import("./commands/hook-add.js");
|
|
11
|
-
await run();
|
|
12
|
-
} else {
|
|
13
|
-
const { cli } = await import("./cli.js");
|
|
14
|
-
void cli.serve();
|
|
15
|
-
}
|
|
3
|
+
const { cli } = await import("./cli.js");
|
|
4
|
+
void cli.serve();
|
package/src/cli.ts
CHANGED
|
@@ -1,10 +1,17 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
1
2
|
import { join } from "node:path";
|
|
2
3
|
import { Cli, z } from "incur";
|
|
3
4
|
import { bootstrap, type Context } from "./context.js";
|
|
4
5
|
import { checkCommand } from "./commands/check.js";
|
|
6
|
+
import { hookAddCommand } from "./commands/hook-add.js";
|
|
7
|
+
import { hookCheckCommand } from "./commands/hook-check.js";
|
|
8
|
+
|
|
9
|
+
const pkg = JSON.parse(readFileSync(join(import.meta.dirname, "..", "package.json"), "utf-8")) as {
|
|
10
|
+
version: string;
|
|
11
|
+
};
|
|
5
12
|
|
|
6
13
|
const cli = Cli.create("bellwether", {
|
|
7
|
-
version:
|
|
14
|
+
version: pkg.version,
|
|
8
15
|
description: "Monitor GitHub PRs — review comments and CI status",
|
|
9
16
|
vars: z.object({
|
|
10
17
|
ctx: z.custom<Context>(),
|
|
@@ -20,7 +27,6 @@ const cli = Cli.create("bellwether", {
|
|
|
20
27
|
}),
|
|
21
28
|
sync: {
|
|
22
29
|
depth: 0,
|
|
23
|
-
cwd: join(import.meta.dirname, ".."),
|
|
24
30
|
include: ["_root"],
|
|
25
31
|
suggestions: [
|
|
26
32
|
"check CI and reviews for this PR",
|
|
@@ -32,11 +38,15 @@ const cli = Cli.create("bellwether", {
|
|
|
32
38
|
});
|
|
33
39
|
|
|
34
40
|
cli.use(async (c, next) => {
|
|
35
|
-
c.
|
|
41
|
+
if (!c.command.startsWith("hook")) {
|
|
42
|
+
c.set("ctx", await bootstrap());
|
|
43
|
+
}
|
|
36
44
|
await next();
|
|
37
45
|
});
|
|
38
46
|
|
|
39
47
|
cli.command("check", checkCommand as unknown as Parameters<typeof cli.command>[1]);
|
|
48
|
+
cli.command("hook-add", hookAddCommand as unknown as Parameters<typeof cli.command>[1]);
|
|
49
|
+
cli.command("hook-check", hookCheckCommand as unknown as Parameters<typeof cli.command>[1]);
|
|
40
50
|
|
|
41
51
|
export { cli };
|
|
42
52
|
export default cli;
|
package/src/commands/hook-add.ts
CHANGED
|
@@ -1,13 +1,10 @@
|
|
|
1
|
-
// Standalone hook installer — bypasses incur.
|
|
2
|
-
// Configures PostToolUse hooks in Claude Code and Codex globally.
|
|
3
|
-
// Idempotent: checks if already configured, updates if needed.
|
|
4
|
-
|
|
5
1
|
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
6
2
|
import { existsSync } from "node:fs";
|
|
7
3
|
import { join } from "node:path";
|
|
8
4
|
import { homedir } from "node:os";
|
|
5
|
+
import { z } from "incur";
|
|
9
6
|
|
|
10
|
-
const HOOK_COMMAND = "npx -y bellwether@latest hook-check";
|
|
7
|
+
const HOOK_COMMAND = "npx -y bellwether@latest hook-check --format json";
|
|
11
8
|
const HOOK_TIMEOUT = 15;
|
|
12
9
|
const BELLWETHER_MARKER = "bellwether@latest hook-check";
|
|
13
10
|
|
|
@@ -118,22 +115,18 @@ async function configureCodex(): Promise<string | null> {
|
|
|
118
115
|
}
|
|
119
116
|
|
|
120
117
|
// ---------------------------------------------------------------------------
|
|
121
|
-
//
|
|
118
|
+
// Incur command
|
|
122
119
|
// ---------------------------------------------------------------------------
|
|
123
120
|
|
|
124
|
-
export
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
console.log("\nHooks will trigger when git push or gh pr create/ready is detected.");
|
|
138
|
-
console.log("The LLM will be prompted to run bellwether to monitor the PR.");
|
|
139
|
-
}
|
|
121
|
+
export const hookAddCommand = {
|
|
122
|
+
description: "Install PostToolUse hooks for Claude Code and Codex",
|
|
123
|
+
output: z.object({
|
|
124
|
+
claude: z.string().describe("Path to Claude Code settings file"),
|
|
125
|
+
codex: z.string().nullable().describe("Path to Codex hooks file, or null if not installed"),
|
|
126
|
+
}),
|
|
127
|
+
async run(c: { ok: (data: { claude: string; codex: string | null }) => unknown }) {
|
|
128
|
+
const claudePath = await configureClaude();
|
|
129
|
+
const codexPath = await configureCodex();
|
|
130
|
+
return c.ok({ claude: claudePath, codex: codexPath });
|
|
131
|
+
},
|
|
132
|
+
};
|
|
@@ -1,35 +1,49 @@
|
|
|
1
|
-
|
|
2
|
-
// Reads Claude/Codex PostToolUse JSON from stdin.
|
|
3
|
-
// If the command is a PR-related action, outputs additionalContext
|
|
4
|
-
// telling the LLM to start monitoring with bellwether.
|
|
1
|
+
import { z } from "incur";
|
|
5
2
|
|
|
6
3
|
const PR_PATTERN = /\bgit\s+push\b|\bgh\s+pr\s+(create|ready)\b/;
|
|
7
4
|
|
|
8
|
-
export
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
5
|
+
export const hookCheckCommand = {
|
|
6
|
+
description:
|
|
7
|
+
"PostToolUse hook handler — reads hook event from stdin, outputs context if PR-related",
|
|
8
|
+
output: z.object({
|
|
9
|
+
hookSpecificOutput: z
|
|
10
|
+
.object({
|
|
11
|
+
hookEventName: z.string(),
|
|
12
|
+
additionalContext: z.string(),
|
|
13
|
+
})
|
|
14
|
+
.optional(),
|
|
15
|
+
}),
|
|
16
|
+
async run(c: {
|
|
17
|
+
ok: (data: {
|
|
18
|
+
hookSpecificOutput?: { hookEventName: string; additionalContext: string };
|
|
19
|
+
}) => unknown;
|
|
20
|
+
}) {
|
|
21
|
+
const chunks: Buffer[] = [];
|
|
22
|
+
for await (const chunk of process.stdin) {
|
|
23
|
+
chunks.push(chunk as Buffer);
|
|
24
|
+
}
|
|
21
25
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
"PR pushed. Run `npx -y bellwether@latest check --watch` to monitor CI and reviews until merge-ready.",
|
|
28
|
-
},
|
|
26
|
+
let command = "";
|
|
27
|
+
try {
|
|
28
|
+
const input = JSON.parse(Buffer.concat(chunks).toString()) as {
|
|
29
|
+
tool_input?: { command?: string };
|
|
30
|
+
hook_event_name?: string;
|
|
29
31
|
};
|
|
30
|
-
|
|
32
|
+
command = input.tool_input?.command ?? "";
|
|
33
|
+
|
|
34
|
+
if (PR_PATTERN.test(command)) {
|
|
35
|
+
return c.ok({
|
|
36
|
+
hookSpecificOutput: {
|
|
37
|
+
hookEventName: input.hook_event_name ?? "PostToolUse",
|
|
38
|
+
additionalContext:
|
|
39
|
+
"PR pushed. Run `npx -y bellwether@latest check --watch` to monitor CI and reviews until merge-ready.",
|
|
40
|
+
},
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
} catch {
|
|
44
|
+
// Malformed input — return empty
|
|
31
45
|
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
}
|
|
35
|
-
}
|
|
46
|
+
|
|
47
|
+
return c.ok({});
|
|
48
|
+
},
|
|
49
|
+
};
|