github-router 0.3.117 → 0.3.118

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/dist/main.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
- import { a as removeOwnClaudeConfigMirror, i as isUnderClaudeConfigMirror, l as writeRuntimeFileSecure, n as ensureClaudeConfigMirror, r as ensurePaths, t as PATHS } from "./paths-CDWhYOdp.js";
3
- import { c as parseBoolEnv, d as runCommandVoid, f as runManagedExeCapture, l as resolveExecutable, n as isPidAlive, o as trackChild, r as registerColbertExitHandlers, s as killManagedTree, t as getColbertInstanceUuid, u as runCommandCapture } from "./lifecycle-DzJicg68.js";
4
- import { a as sweepRegistry, i as registerExitHandlers$1, n as getInstanceUuid, r as recordWorkerRepo, t as WorktreeRegistry } from "./lifecycle-D6zt0iH_.js";
2
+ import { a as removeOwnClaudeConfigMirror, i as isUnderClaudeConfigMirror, l as writeRuntimeFileSecure, n as ensureClaudeConfigMirror, r as ensurePaths, t as PATHS } from "./paths-BJvMAFht.js";
3
+ import { c as killManagedTree, d as runCommandCapture, f as runCommandVoid, l as parseBoolEnv, n as isPidAlive, o as trackChild, p as runManagedExeCapture, r as registerColbertExitHandlers, s as killChildProcessTree, t as getColbertInstanceUuid, u as resolveExecutable } from "./lifecycle-CELOx6yB.js";
4
+ import { a as sweepRegistry, i as registerExitHandlers$1, n as getInstanceUuid, r as recordWorkerRepo, t as WorktreeRegistry } from "./lifecycle-CfYzpXK-.js";
5
5
  import { createRequire } from "node:module";
6
6
  import { defineCommand, runMain } from "citty";
7
7
  import consola from "consola";
@@ -1415,6 +1415,120 @@ function envInt$1(key, fallback) {
1415
1415
  const UPSTREAM_FETCH_TIMEOUT_MS = envInt$1("UPSTREAM_FETCH_TIMEOUT_MS", 0);
1416
1416
  const UPSTREAM_INACTIVITY_TIMEOUT_MS = envInt$1("UPSTREAM_INACTIVITY_TIMEOUT_MS", 3e5);
1417
1417
 
1418
+ //#endregion
1419
+ //#region src/lib/process-guard/index.ts
1420
+ /**
1421
+ * Live reaper children, held so the GC can't collect the `ChildProcess`
1422
+ * (and with it the stdin write-end that is the proxy-death signal) while
1423
+ * the proxy runs. Entries self-remove on the reaper's exit. We do NOT
1424
+ * proactively kill these on graceful shutdown: when the proxy exits the OS
1425
+ * closes the stdin pipe, the reaper hits EOF, re-verifies the child's
1426
+ * identity, and reaps any survivor that ignored the graceful SIGTERM —
1427
+ * exactly the backstop we want.
1428
+ */
1429
+ const _activeReapers = /* @__PURE__ */ new Set();
1430
+ /** Guard is on by default; `GH_ROUTER_DISABLE_PROCESS_GUARD=1` opts out. */
1431
+ function processGuardEnabled() {
1432
+ return parseBoolEnv(process$1.env.GH_ROUTER_DISABLE_PROCESS_GUARD) !== true;
1433
+ }
1434
+ /**
1435
+ * Build the start-time-verified node reaper script (POSIX). PURE — `pid`
1436
+ * is our own integer. `detachedGroup` selects `kill(-pid)` (process group,
1437
+ * the detached CLI) vs `kill(pid)` on POSIX.
1438
+ *
1439
+ * Kept dependency-free (require'd builtins only) so it runs under `node -e`
1440
+ * with no module resolution against the dist bundle.
1441
+ */
1442
+ function buildNodeReaperScript(pid, detachedGroup) {
1443
+ const target = detachedGroup ? "-PID" : "PID";
1444
+ return `
1445
+ const cp = require("node:child_process");
1446
+ const fs = require("node:fs");
1447
+ const PID = ${pid >>> 0};
1448
+ function startTime() {
1449
+ try {
1450
+ if (process.platform === "linux") {
1451
+ const stat = fs.readFileSync("/proc/" + PID + "/stat", "utf8");
1452
+ const post = stat.slice(stat.lastIndexOf(")") + 1).trim().split(/\\s+/);
1453
+ return post[19] || null; // field 22 (starttime) = index 19 after comm
1454
+ }
1455
+ const out = cp.execFileSync("ps", ["-o","lstart=","-p",String(PID)],
1456
+ { stdio: ["ignore","pipe","ignore"], timeout: 2000 }).toString().trim();
1457
+ return out || null;
1458
+ } catch { return null; }
1459
+ }
1460
+ function alive() { try { process.kill(PID, 0); return true; } catch { return false; } }
1461
+ function treeKill() {
1462
+ try { process.kill(${target}, "SIGTERM"); } catch {}
1463
+ // NOT unref'd: this must keep the loop alive to deliver the escalated
1464
+ // SIGKILL (the onDeath exit timer below stays alive past 500ms too).
1465
+ setTimeout(() => { try { process.kill(${target}, "SIGKILL"); } catch {} }, 500);
1466
+ }
1467
+ const snap = (() => {
1468
+ // The child is definitely ours and alive at startup, so a null here is a
1469
+ // transient probe failure (e.g. a momentary 'ps' hiccup), NOT a real
1470
+ // identity loss. Retry a few times so a one-off failure can't silently
1471
+ // disable the guard for the rest of the run.
1472
+ for (let i = 0; i < 3; i++) { const s = startTime(); if (s !== null) return s; }
1473
+ return null;
1474
+ })();
1475
+ let done = false;
1476
+ function onDeath() {
1477
+ if (done) return; done = true;
1478
+ // Re-verify identity: kill ONLY if the live PID is still our child.
1479
+ if (snap !== null && alive() && startTime() === snap) treeKill();
1480
+ // REF'd (NOT unref'd): stdin has closed, so an unref'd timer would let
1481
+ // the loop empty and the process exit immediately — dropping the 500ms
1482
+ // SIGKILL escalation. Keep the loop alive to deliver it, then exit.
1483
+ setTimeout(() => process.exit(0), 1500);
1484
+ }
1485
+ process.stdin.resume();
1486
+ process.stdin.on("end", onDeath);
1487
+ process.stdin.on("close", onDeath);
1488
+ process.stdin.on("error", onDeath);
1489
+ const cap = setTimeout(() => process.exit(0), 24*3600*1000); if (cap.unref) cap.unref();
1490
+ `.trim();
1491
+ }
1492
+ /**
1493
+ * Spawn the detached node reaper holding the stdin death-pipe. Always
1494
+ * `detached` so it outlives a force-kill of the proxy, and `unref`'d so it
1495
+ * never holds the proxy's event loop open. Returns null on spawn failure.
1496
+ */
1497
+ function spawnNodeReaper(pid, detachedGroup) {
1498
+ try {
1499
+ const child = spawn(process$1.execPath, ["-e", buildNodeReaperScript(pid, detachedGroup)], {
1500
+ stdio: [
1501
+ "pipe",
1502
+ "ignore",
1503
+ "ignore"
1504
+ ],
1505
+ detached: true,
1506
+ windowsHide: true,
1507
+ shell: false
1508
+ });
1509
+ child.on("error", () => {});
1510
+ child.stdin?.on("error", () => {});
1511
+ _activeReapers.add(child);
1512
+ child.once("exit", () => _activeReapers.delete(child));
1513
+ child.unref();
1514
+ return child;
1515
+ } catch {
1516
+ return null;
1517
+ }
1518
+ }
1519
+ /**
1520
+ * Start the crash-safe guard for a launched CLI child. No-op on Windows
1521
+ * (Node's Job Object already reaps the tree on proxy death) and when
1522
+ * disabled / unspawnable. Fire-and-forget; never throws.
1523
+ */
1524
+ function startProcessGuard(child) {
1525
+ if (!processGuardEnabled()) return;
1526
+ const pid = child.pid;
1527
+ if (!pid) return;
1528
+ if (process$1.platform === "win32") return;
1529
+ spawnNodeReaper(pid, true);
1530
+ }
1531
+
1418
1532
  //#endregion
1419
1533
  //#region src/lib/toolbelt/path-inject.ts
1420
1534
  /**
@@ -1498,7 +1612,8 @@ const STRIPPED_PARENT_ENV_KEYS = [
1498
1612
  "CLAUDE_CODE_ADDITIONAL_PROTECTION",
1499
1613
  "OPENAI_API_KEY",
1500
1614
  "OPENAI_BASE_URL",
1501
- "CODEX_HOME"
1615
+ "CODEX_HOME",
1616
+ "AIORDIE_CLAUDE_BIND"
1502
1617
  ];
1503
1618
  /**
1504
1619
  * Strip auth-related keys from a parent-process env object. The result
@@ -1618,6 +1733,18 @@ function buildLaunchCommand(target) {
1618
1733
  })
1619
1734
  };
1620
1735
  }
1736
+ /**
1737
+ * Whether a resolved Windows executable must be launched through cmd.exe
1738
+ * (`shell:true`). Only batch shims (`.cmd`/`.bat`) need it — and even then
1739
+ * cmd.exe stays alive as the CLI's parent, so `taskkill /T` reaps the
1740
+ * whole tree. A real `.exe` (e.g. the native-installer `claude.exe`) is
1741
+ * spawned DIRECTLY so the CLI is the direct child, with no cmd.exe
1742
+ * intermediary to orphan its node/MCP grandchildren on a kill.
1743
+ */
1744
+ function windowsLaunchNeedsShell(executable) {
1745
+ const ext = nodePath.extname(executable).toLowerCase();
1746
+ return ext === ".cmd" || ext === ".bat";
1747
+ }
1621
1748
  function launchChild(target, server$1, options = {}) {
1622
1749
  const { cmd, env } = buildLaunchCommand(target);
1623
1750
  const executable = cmd[0];
@@ -1629,7 +1756,7 @@ function launchChild(target, server$1, options = {}) {
1629
1756
  }
1630
1757
  let child;
1631
1758
  try {
1632
- if (process$1.platform === "win32") child = spawn(cmd.map((a) => a.includes(" ") ? `"${a}"` : a).join(" "), [], {
1759
+ if (process$1.platform === "win32") if (windowsLaunchNeedsShell(cmd[0])) child = spawn(cmd.map((a) => a.includes(" ") ? `"${a}"` : a).join(" "), [], {
1633
1760
  env,
1634
1761
  stdio: "inherit",
1635
1762
  shell: true
@@ -1638,6 +1765,11 @@ function launchChild(target, server$1, options = {}) {
1638
1765
  env,
1639
1766
  stdio: "inherit"
1640
1767
  });
1768
+ else child = spawn(cmd[0], cmd.slice(1), {
1769
+ env,
1770
+ stdio: "inherit",
1771
+ detached: true
1772
+ });
1641
1773
  } catch (error) {
1642
1774
  const msg = `Failed to launch ${executable}: ${error instanceof Error ? error.message : String(error)}`;
1643
1775
  consola.error(msg);
@@ -1646,15 +1778,16 @@ function launchChild(target, server$1, options = {}) {
1646
1778
  if (options.onShutdown) Promise.resolve(options.onShutdown()).catch(() => {});
1647
1779
  process$1.exit(1);
1648
1780
  }
1781
+ startProcessGuard(child);
1649
1782
  let cleaned = false;
1650
1783
  let exiting = false;
1651
1784
  async function cleanup() {
1652
1785
  if (cleaned) return;
1653
1786
  cleaned = true;
1787
+ const timeout = setTimeout(() => process$1.exit(1), 5e3);
1654
1788
  try {
1655
- child.kill();
1789
+ killChildProcessTree(child, { detachedGroup: process$1.platform !== "win32" });
1656
1790
  } catch {}
1657
- const timeout = setTimeout(() => process$1.exit(1), 5e3);
1658
1791
  try {
1659
1792
  await server$1.close(true);
1660
1793
  } catch {}
@@ -1668,11 +1801,33 @@ function launchChild(target, server$1, options = {}) {
1668
1801
  exiting = true;
1669
1802
  process$1.exit(code);
1670
1803
  }
1671
- const onSignal = () => {
1804
+ let forwardGrace = null;
1805
+ const lastForwardAt = {
1806
+ SIGINT: 0,
1807
+ SIGTERM: 0
1808
+ };
1809
+ const onSignal = (sig) => {
1810
+ if (process$1.platform !== "win32" && child.pid && !cleaned) {
1811
+ const now = Date.now();
1812
+ if (now - lastForwardAt[sig] > 250) {
1813
+ lastForwardAt[sig] = now;
1814
+ try {
1815
+ process$1.kill(-child.pid, sig);
1816
+ } catch {}
1817
+ }
1818
+ const graceMs = sig === "SIGINT" ? 1e4 : 3e3;
1819
+ if (!forwardGrace) {
1820
+ forwardGrace = setTimeout(() => {
1821
+ cleanup().then(() => exit(130)).catch(() => exit(1));
1822
+ }, graceMs);
1823
+ forwardGrace.unref?.();
1824
+ }
1825
+ return;
1826
+ }
1672
1827
  cleanup().then(() => exit(130)).catch(() => exit(1));
1673
1828
  };
1674
- process$1.on("SIGINT", onSignal);
1675
- process$1.on("SIGTERM", onSignal);
1829
+ process$1.on("SIGINT", () => onSignal("SIGINT"));
1830
+ process$1.on("SIGTERM", () => onSignal("SIGTERM"));
1676
1831
  child.on("exit", (exitCode, signal) => {
1677
1832
  try {
1678
1833
  sweepRegistry();
@@ -7103,7 +7258,7 @@ function logAudit$1(record) {
7103
7258
  try {
7104
7259
  const fs$2 = await import("node:fs/promises");
7105
7260
  const path$1 = await import("node:path");
7106
- const { PATHS: PATHS$1 } = await import("./paths-DNVIKCZP.js");
7261
+ const { PATHS: PATHS$1 } = await import("./paths-BdQSPUOg.js");
7107
7262
  const dir = path$1.join(PATHS$1.APP_DIR, "browser-mcp");
7108
7263
  await fs$2.mkdir(dir, { recursive: true });
7109
7264
  const line = JSON.stringify({
@@ -9900,9 +10055,15 @@ const exitHandler = () => {
9900
10055
  inFlight$1.clear();
9901
10056
  lastUsedSeq.clear();
9902
10057
  };
9903
- process$1.on("SIGINT", sigintHandler);
9904
- process$1.on("SIGTERM", sigtermHandler);
9905
- process$1.on("exit", exitHandler);
10058
+ let _exitHandlersRegistered = false;
10059
+ function registerExitHandlers$2() {
10060
+ if (_exitHandlersRegistered) return;
10061
+ _exitHandlersRegistered = true;
10062
+ process$1.on("SIGINT", sigintHandler);
10063
+ process$1.on("SIGTERM", sigtermHandler);
10064
+ process$1.on("exit", exitHandler);
10065
+ }
10066
+ registerExitHandlers$2();
9906
10067
 
9907
10068
  //#endregion
9908
10069
  //#region src/vendor/pi/ai/api-registry.ts
@@ -19437,6 +19598,18 @@ function buildStopHookCommand(execPath, scriptPath) {
19437
19598
  return `${q(execPath)} internal-stop-hook`;
19438
19599
  }
19439
19600
  /**
19601
+ * Build the shell command Claude Code runs for the SessionStart/SessionEnd hooks
19602
+ * (registered only when github-router runs inside an ai-or-die Terminal tab). The
19603
+ * sidecar path is baked in as a literal `--out` arg — NOT passed via env — so it
19604
+ * survives `AIORDIE_CLAUDE_BIND` being stripped from the child's environment and a
19605
+ * nested `github-router claude` can't inherit it. Pure (binary + script + out
19606
+ * paths) for unit-testable quoting; the live firing is verified end-to-end.
19607
+ */
19608
+ function buildSessionBindHookCommand(execPath, scriptPath, outPath) {
19609
+ const q = (s) => `"${s}"`;
19610
+ return `${scriptPath && scriptPath !== execPath ? `${q(execPath)} ${q(scriptPath)}` : q(execPath)} internal-session-bind --out ${q(outPath)}`;
19611
+ }
19612
+ /**
19440
19613
  * Read-merge-atomic-write the Stop hook into a Claude Code `settings.json` file
19441
19614
  * (the mirrored one). A MISSING file (ENOENT) starts from `{}`; any OTHER read or
19442
19615
  * parse error THROWS (the caller's try/catch warns and continues) rather than
@@ -23346,7 +23519,7 @@ function initProxyFromEnv() {
23346
23519
  //#endregion
23347
23520
  //#region package.json
23348
23521
  var name = "github-router";
23349
- var version$1 = "0.3.117";
23522
+ var version$1 = "0.3.118";
23350
23523
 
23351
23524
  //#endregion
23352
23525
  //#region src/lib/approval.ts
@@ -25532,6 +25705,15 @@ const claude = defineCommand({
25532
25705
  if (skillsWritten > 0) process$1.stderr.write(`Floor-raising skills injected (${skillsWritten}/${INJECTED_SKILLS.length}): /gh-research, /gh-orchestrate, /gh-floor-keeper.
25533
25706
  `);
25534
25707
  }
25708
+ const aiordieSidecar = (process$1.env.AIORDIE_CLAUDE_BIND ?? "").trim();
25709
+ if (aiordieSidecar.length > 0 && !aiordieSidecar.includes("\"")) try {
25710
+ const settingsPath = nodePath.join(PATHS.CLAUDE_CONFIG_DIR, "settings.json");
25711
+ const command = buildSessionBindHookCommand(process$1.execPath, process$1.argv[1], aiordieSidecar);
25712
+ await injectStopHookIntoSettingsFile(settingsPath, command, "SessionStart");
25713
+ await injectStopHookIntoSettingsFile(settingsPath, command, "SessionEnd");
25714
+ } catch (err) {
25715
+ consola.warn(`Could not register the ai-or-die session-bind hook: ${String(err)}`);
25716
+ }
25535
25717
  if (args["trust-gate"] === true) try {
25536
25718
  const root = await trustRepo(sessionCwd);
25537
25719
  process$1.stderr.write(`Structural gate trusted for this repo (${root}); it will run on launch here from now on.\n`);
@@ -25855,7 +26037,7 @@ async function postJson(url, payload, opts) {
25855
26037
  * no such handle. Hooks always receive piped/redirected stdin, so this never
25856
26038
  * blocks (guarded against an interactive TTY, and any error -> "").
25857
26039
  */
25858
- function readStdin$1() {
26040
+ function readStdin$2() {
25859
26041
  try {
25860
26042
  if (process.stdin.isTTY) return "";
25861
26043
  return readFileSync(0, "utf8");
@@ -25886,7 +26068,7 @@ const internalPromptSubmit = defineCommand({
25886
26068
  },
25887
26069
  async run() {
25888
26070
  try {
25889
- const stdin = readStdin$1();
26071
+ const stdin = readStdin$2();
25890
26072
  const steerEnabled = parseBoolEnv(process.env.GH_ROUTER_DISABLE_PROMPT_STEER) !== true;
25891
26073
  const runtime = hookMcpRuntimeFromEnv();
25892
26074
  let decision;
@@ -25938,6 +26120,111 @@ const internalPromptSubmit = defineCommand({
25938
26120
  }
25939
26121
  });
25940
26122
 
26123
+ //#endregion
26124
+ //#region src/internal-session-bind.ts
26125
+ /**
26126
+ * Read the hook payload from stdin SYNCHRONOUSLY (`readFileSync(0)`). An async
26127
+ * stdin read leaves an in-flight libuv FS request that, on Windows, races process
26128
+ * teardown and trips a `uv_async_send` assertion; a synchronous read has no such
26129
+ * handle. Hooks always receive piped stdin (guarded against a TTY; any error -> "").
26130
+ */
26131
+ function readStdin$1() {
26132
+ try {
26133
+ if (process.stdin.isTTY) return "";
26134
+ return readFileSync(0, "utf8");
26135
+ } catch {
26136
+ return "";
26137
+ }
26138
+ }
26139
+ /**
26140
+ * Resolve a transcript path to its real location. The path claude reports sits
26141
+ * under the per-launch CLAUDE_CONFIG_DIR mirror, whose `projects` entry is a
26142
+ * junction/symlink back to the real `~/.claude/projects`. ai-or-die reads the
26143
+ * real dir, and the per-launch mirror is swept on github-router shutdown, so we
26144
+ * persist the REAL path. The file (and even intermediate dirs) may not exist yet
26145
+ * at SessionStart, so we realpath the DEEPEST EXISTING ancestor and rejoin the
26146
+ * not-yet-created trailing segments. Best-effort: if nothing resolves, keep raw.
26147
+ */
26148
+ function realTranscriptPath(tp) {
26149
+ if (!tp) return "";
26150
+ try {
26151
+ return realpathSync.native(tp);
26152
+ } catch {}
26153
+ const missing = [];
26154
+ let cur = tp;
26155
+ for (let i = 0; i < 64; i++) {
26156
+ missing.unshift(nodePath.basename(cur));
26157
+ const parent = nodePath.dirname(cur);
26158
+ if (parent === cur) break;
26159
+ try {
26160
+ return nodePath.join(realpathSync.native(parent), ...missing);
26161
+ } catch {
26162
+ cur = parent;
26163
+ }
26164
+ }
26165
+ return tp;
26166
+ }
26167
+ /**
26168
+ * Pure core: turn a raw Claude Code hook payload (stdin string) into the sidecar
26169
+ * record, or `null` when there's nothing to write. Returns null for: non-JSON
26170
+ * input, a subagent/teammate payload (agent_id/agent_type present — top-level
26171
+ * filter), or a missing session_id. Exported for unit tests.
26172
+ */
26173
+ function decodeSessionBind(stdin) {
26174
+ let payload = {};
26175
+ try {
26176
+ const p = JSON.parse(stdin);
26177
+ if (p && typeof p === "object") payload = p;
26178
+ else return null;
26179
+ } catch {
26180
+ return null;
26181
+ }
26182
+ if (isSubagentContext(payload)) return null;
26183
+ const claudeSessionId = typeof payload.session_id === "string" ? payload.session_id : "";
26184
+ if (!claudeSessionId) return null;
26185
+ const event = (typeof payload.hook_event_name === "string" ? payload.hook_event_name : "") === "SessionEnd" ? "end" : "start";
26186
+ const record = {
26187
+ schema: 1,
26188
+ claudeSessionId,
26189
+ transcriptPath: realTranscriptPath(typeof payload.transcript_path === "string" ? payload.transcript_path : ""),
26190
+ cwd: typeof payload.cwd === "string" ? payload.cwd : "",
26191
+ event,
26192
+ at: Date.now()
26193
+ };
26194
+ if (event === "start" && typeof payload.source === "string") record.source = payload.source;
26195
+ if (event === "end" && typeof payload.reason === "string") record.reason = payload.reason;
26196
+ return record;
26197
+ }
26198
+ /** Atomically write the sidecar (temp + rename) so the reader never sees a partial file. */
26199
+ function writeSidecar(out, record) {
26200
+ try {
26201
+ mkdirSync(nodePath.dirname(out), { recursive: true });
26202
+ } catch {}
26203
+ const tmp = `${out}.${process.pid}.${randomBytes(4).toString("hex")}.tmp`;
26204
+ writeFileSync(tmp, JSON.stringify(record), { mode: 384 });
26205
+ renameSync(tmp, out);
26206
+ }
26207
+ const internalSessionBind = defineCommand({
26208
+ meta: {
26209
+ name: "internal-session-bind",
26210
+ description: "Internal: the SessionStart/SessionEnd hook. Reads the Claude Code hook payload on stdin and atomically writes the active session id + transcript path to the --out sidecar file (consumed by ai-or-die to bind a tab's sticky-note summariser). Side-effect only."
26211
+ },
26212
+ args: { out: {
26213
+ type: "string",
26214
+ description: "Absolute path to the sidecar file to (atomically) write.",
26215
+ required: false
26216
+ } },
26217
+ run({ args }) {
26218
+ try {
26219
+ const out = typeof args.out === "string" ? args.out.trim() : "";
26220
+ if (!out) return;
26221
+ const record = decodeSessionBind(readStdin$1());
26222
+ if (record) writeSidecar(out, record);
26223
+ } catch {}
26224
+ process.exitCode = 0;
26225
+ }
26226
+ });
26227
+
25941
26228
  //#endregion
25942
26229
  //#region src/internal-stop-hook.ts
25943
26230
  /**
@@ -26450,7 +26737,7 @@ process.on("uncaughtException", (error) => {
26450
26737
  const version = getPackageVersion();
26451
26738
  const argv = process.argv.slice(2);
26452
26739
  const isVersionFlag = argv.includes("--version");
26453
- const isInternalHook = argv[0] === "internal-stop-hook" || argv[0] === "internal-prompt-submit" || argv[0] === "internal-stop-review";
26740
+ const isInternalHook = argv[0] === "internal-stop-hook" || argv[0] === "internal-prompt-submit" || argv[0] === "internal-stop-review" || argv[0] === "internal-session-bind";
26454
26741
  if (!isVersionFlag && !isInternalHook) consola.info(`github-router v${version}`);
26455
26742
  await runMain(defineCommand({
26456
26743
  meta: {
@@ -26468,7 +26755,8 @@ await runMain(defineCommand({
26468
26755
  debug,
26469
26756
  "internal-stop-hook": internalStopHook,
26470
26757
  "internal-prompt-submit": internalPromptSubmit,
26471
- "internal-stop-review": internalStopReview
26758
+ "internal-stop-review": internalStopReview,
26759
+ "internal-session-bind": internalSessionBind
26472
26760
  }
26473
26761
  }));
26474
26762