bellwether 0.0.3 → 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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bellwether",
3
- "version": "0.0.3",
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 cmd = process.argv[2];
3
- // Fast path for hook commands — bypass incur entirely for speed
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,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAE5B,gEAAgE;AAChE,IAAI,GAAG,KAAK,YAAY,EAAE,CAAC;IACzB,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,0BAA0B,CAAC,CAAC;IACzD,MAAM,GAAG,EAAE,CAAC;AACd,CAAC;KAAM,IAAI,GAAG,KAAK,UAAU,EAAE,CAAC;IAC9B,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,wBAAwB,CAAC,CAAC;IACvD,MAAM,GAAG,EAAE,CAAC;AACd,CAAC;KAAM,CAAC;IACN,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;IACzC,KAAK,GAAG,CAAC,KAAK,EAAE,CAAC;AACnB,CAAC"}
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":"AAAA,OAAO,EAAE,GAAG,EAAE,CAAC,EAAE,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAa,KAAK,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvD,QAAA,MAAM,GAAG;;;;;;;kBAyBP,CAAC;AASH,OAAO,EAAE,GAAG,EAAE,CAAC;AACf,eAAe,GAAG,CAAC"}
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,8 +1,13 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { join } from "node:path";
1
3
  import { Cli, z } from "incur";
2
4
  import { bootstrap } from "./context.js";
3
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"));
4
9
  const cli = Cli.create("bellwether", {
5
- version: "0.0.1",
10
+ version: pkg.version,
6
11
  description: "Monitor GitHub PRs — review comments and CI status",
7
12
  vars: z.object({
8
13
  ctx: z.custom(),
@@ -28,10 +33,14 @@ const cli = Cli.create("bellwether", {
28
33
  },
29
34
  });
30
35
  cli.use(async (c, next) => {
31
- c.set("ctx", await bootstrap());
36
+ if (!c.command.startsWith("hook")) {
37
+ c.set("ctx", await bootstrap());
38
+ }
32
39
  await next();
33
40
  });
34
41
  cli.command("check", checkCommand);
42
+ cli.command("hook-add", hookAddCommand);
43
+ cli.command("hook-check", hookCheckCommand);
35
44
  export { cli };
36
45
  export default cli;
37
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,GAAG,EAAE,CAAC,EAAE,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,SAAS,EAAgB,MAAM,cAAc,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,MAAM,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,YAAY,EAAE;IACnC,OAAO,EAAE,OAAO;IAChB,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,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,SAAS,EAAE,CAAC,CAAC;IAChC,MAAM,IAAI,EAAE,CAAC;AACf,CAAC,CAAC,CAAC;AAEH,GAAG,CAAC,OAAO,CAAC,OAAO,EAAE,YAA4D,CAAC,CAAC;AAEnF,OAAO,EAAE,GAAG,EAAE,CAAC;AACf,eAAe,GAAG,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
- export declare function run(): Promise<void>;
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":"AA2HA,wBAAsB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CAezC"}
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
- const HOOK_COMMAND = "npx -y bellwether@latest hook-check";
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
- // Main
79
+ // Incur command
82
80
  // ---------------------------------------------------------------------------
83
- export async function run() {
84
- console.log("Configuring bellwether hooks...\n");
85
- const claudePath = await configureClaude();
86
- console.log(` Claude Code: ${claudePath}`);
87
- const codexPath = await configureCodex();
88
- if (codexPath) {
89
- console.log(` Codex: ${codexPath}`);
90
- }
91
- else {
92
- console.log(" Codex: skipped (not installed)");
93
- }
94
- console.log("\nHooks will trigger when git push or gh pr create/ready is detected.");
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":"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"}
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
- export declare function run(): Promise<void>;
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":"AAOA,wBAAsB,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC,CA2BzC"}
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
- // Standalone hook handler bypasses incur for speed.
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 async function run() {
7
- const chunks = [];
8
- for await (const chunk of process.stdin) {
9
- chunks.push(chunk);
10
- }
11
- let command = "";
12
- try {
13
- const input = JSON.parse(Buffer.concat(chunks).toString());
14
- command = input.tool_input?.command ?? "";
15
- if (PR_PATTERN.test(command)) {
16
- const output = {
17
- hookSpecificOutput: {
18
- hookEventName: input.hook_event_name ?? "PostToolUse",
19
- additionalContext: "PR pushed. Run `npx -y bellwether@latest check --watch` to monitor CI and reviews until merge-ready.",
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
- catch {
26
- // Malformed input exit silently
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,sDAAsD;AACtD,kDAAkD;AAClD,mEAAmE;AACnE,uDAAuD;AAEvD,MAAM,UAAU,GAAG,6CAA6C,CAAC;AAEjE,MAAM,CAAC,KAAK,UAAU,GAAG;IACvB,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,KAAK,EAAE,MAAM,KAAK,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;QACxC,MAAM,CAAC,IAAI,CAAC,KAAe,CAAC,CAAC;IAC/B,CAAC;IAED,IAAI,OAAO,GAAG,EAAE,CAAC;IACjB,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,CAGxD,CAAC;QACF,OAAO,GAAG,KAAK,CAAC,UAAU,EAAE,OAAO,IAAI,EAAE,CAAC;QAE1C,IAAI,UAAU,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAC7B,MAAM,MAAM,GAAG;gBACb,kBAAkB,EAAE;oBAClB,aAAa,EAAE,KAAK,CAAC,eAAe,IAAI,aAAa;oBACrD,iBAAiB,EACf,sGAAsG;iBACzG;aACF,CAAC;YACF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,kCAAkC;IACpC,CAAC;AACH,CAAC"}
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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "bellwether",
3
3
  "type": "module",
4
- "version": "0.0.3",
4
+ "version": "0.0.5",
5
5
  "description": "Drive GitHub PRs to merge-ready: watch CI, fix failures, resolve review comments.",
6
6
  "private": false,
7
7
  "author": {
package/src/bin.ts CHANGED
@@ -1,15 +1,4 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const cmd = process.argv[2];
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,9 +1,17 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { join } from "node:path";
1
3
  import { Cli, z } from "incur";
2
4
  import { bootstrap, type Context } from "./context.js";
3
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
+ };
4
12
 
5
13
  const cli = Cli.create("bellwether", {
6
- version: "0.0.1",
14
+ version: pkg.version,
7
15
  description: "Monitor GitHub PRs — review comments and CI status",
8
16
  vars: z.object({
9
17
  ctx: z.custom<Context>(),
@@ -30,11 +38,15 @@ const cli = Cli.create("bellwether", {
30
38
  });
31
39
 
32
40
  cli.use(async (c, next) => {
33
- c.set("ctx", await bootstrap());
41
+ if (!c.command.startsWith("hook")) {
42
+ c.set("ctx", await bootstrap());
43
+ }
34
44
  await next();
35
45
  });
36
46
 
37
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]);
38
50
 
39
51
  export { cli };
40
52
  export default cli;
@@ -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
- // Main
118
+ // Incur command
122
119
  // ---------------------------------------------------------------------------
123
120
 
124
- export async function run(): Promise<void> {
125
- console.log("Configuring bellwether hooks...\n");
126
-
127
- const claudePath = await configureClaude();
128
- console.log(` Claude Code: ${claudePath}`);
129
-
130
- const codexPath = await configureCodex();
131
- if (codexPath) {
132
- console.log(` Codex: ${codexPath}`);
133
- } else {
134
- console.log(" Codex: skipped (not installed)");
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
- // Standalone hook handler bypasses incur for speed.
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 async function run(): Promise<void> {
9
- const chunks: Buffer[] = [];
10
- for await (const chunk of process.stdin) {
11
- chunks.push(chunk as Buffer);
12
- }
13
-
14
- let command = "";
15
- try {
16
- const input = JSON.parse(Buffer.concat(chunks).toString()) as {
17
- tool_input?: { command?: string };
18
- hook_event_name?: string;
19
- };
20
- command = input.tool_input?.command ?? "";
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
- if (PR_PATTERN.test(command)) {
23
- const output = {
24
- hookSpecificOutput: {
25
- hookEventName: input.hook_event_name ?? "PostToolUse",
26
- additionalContext:
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
- process.stdout.write(JSON.stringify(output));
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
- } catch {
33
- // Malformed input — exit silently
34
- }
35
- }
46
+
47
+ return c.ok({});
48
+ },
49
+ };