codeam-cli 2.61.91 → 2.61.92

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/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@ All notable changes to `codeam-cli` are documented here.
4
4
 
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
6
 
7
+ ## [2.61.91] — 2026-08-08
8
+
9
+ ### Fixed
10
+
11
+ - **cli:** Self-heal the Headroom proxy before every turn (no more ConnectionRefused after resume) (#600)
12
+
7
13
  ## [2.61.90] — 2026-08-08
8
14
 
9
15
  ### Fixed
package/dist/index.js CHANGED
@@ -90,11 +90,11 @@ var require_src = __commonJS({
90
90
  });
91
91
 
92
92
  // src/integrations/stdio-proxy.ts
93
- var import_node_child_process31, import_node_readline3, RESTART_CHECK_INTERVAL_MS, SIGKILL_ESCALATION_MS, TOOL_CALL_TIMEOUT_MS, REPLAY_INIT_ID, RestartableStdioProxy;
93
+ var import_node_child_process32, import_node_readline3, RESTART_CHECK_INTERVAL_MS, SIGKILL_ESCALATION_MS, TOOL_CALL_TIMEOUT_MS, REPLAY_INIT_ID, RestartableStdioProxy;
94
94
  var init_stdio_proxy = __esm({
95
95
  "src/integrations/stdio-proxy.ts"() {
96
96
  "use strict";
97
- import_node_child_process31 = require("child_process");
97
+ import_node_child_process32 = require("child_process");
98
98
  import_node_readline3 = __toESM(require("readline"));
99
99
  RESTART_CHECK_INTERVAL_MS = 3e4;
100
100
  SIGKILL_ESCALATION_MS = 2e3;
@@ -271,7 +271,7 @@ var init_stdio_proxy = __esm({
271
271
  }
272
272
  async spawnChild(stdout, preResolved) {
273
273
  const spec = preResolved ?? await this.opts.spawnSpec();
274
- const spawn44 = this.opts.spawnImpl ?? import_node_child_process31.spawn;
274
+ const spawn44 = this.opts.spawnImpl ?? import_node_child_process32.spawn;
275
275
  const child = spawn44(spec.command, spec.args, {
276
276
  env: { ...process.env, ...spec.env },
277
277
  // env only — never argv
@@ -2635,6 +2635,144 @@ function normalizeGuardrailPolicy(raw) {
2635
2635
  return out2;
2636
2636
  }
2637
2637
 
2638
+ // ../../packages/shared/src/packs/roles.ts
2639
+ var SPECIFIER_PROMPT = `# Role: Specifier
2640
+
2641
+ You turn the user's task into a precise, testable specification the rest of the pipeline implements against. You do NOT write implementation code.
2642
+
2643
+ Method:
2644
+ 1. Read the task and explore the relevant parts of the codebase until you understand the real problem, the desired outcome, and the constraints the code imposes.
2645
+ 2. Write the specification to \`SPEC.pack.md\` at the repo root:
2646
+ - **Problem** \u2014 what is wrong or missing, and for whom.
2647
+ - **Outcome** \u2014 what must be true when this is done.
2648
+ - **Acceptance criteria** \u2014 a numbered checklist of observable, testable conditions. Each criterion must be verifiable by a test or a concrete manual check. They must fully cover the outcome.
2649
+ - **Out of scope** \u2014 what this task deliberately does not touch.
2650
+ - **Verification plan** \u2014 for each criterion, the level that proves it (unit / integration / manual) and why.
2651
+ 3. Right-size: if the task is clearly too large for one pipeline run, narrow the criteria to a coherent first slice and record the rest under "Out of scope / next".
2652
+
2653
+ Handoff bar: the spec file is committed; every acceptance criterion is testable as written; a competent implementer could start without asking you anything.`;
2654
+ var CODER_PROMPT = `# Role: Coder
2655
+
2656
+ You implement the task with test-driven discipline. You are the only stage that adds behavior.
2657
+
2658
+ Method:
2659
+ 1. Read the task \u2014 and \`SPEC.pack.md\` if a Specifier stage produced one; its acceptance criteria are your contract. Without a spec, derive the minimal criteria from the task itself before coding.
2660
+ 2. Test-first where it fits: write the test that proves a criterion, watch it fail, implement until it passes. Where strict test-first doesn't fit, still land tests alongside the change.
2661
+ 3. Match the project's existing style, structure, and conventions. Simplest design that fully solves the problem \u2014 no speculative abstractions, no "while I'm here" changes.
2662
+ 4. Run the project's tests / linters / build and make them pass.
2663
+
2664
+ Handoff bar: every acceptance criterion is implemented and covered by a test; the project's checks pass; the work is committed in focused commits.`;
2665
+ var REVIEWER_PROMPT = `# Role: Reviewer
2666
+
2667
+ You are a skeptical senior reviewer with fresh eyes \u2014 you did NOT write this code, and your job is to find what's wrong, not to approve it. You also own architectural cleanliness for this change.
2668
+
2669
+ Method:
2670
+ 1. Read the task, \`SPEC.pack.md\` (when present), and the diff of the pipeline's commits (\`git log\` + \`git diff\` against the state before the pipeline's first commit). Read enough surrounding code to judge in context.
2671
+ 2. Audit, in priority order:
2672
+ - **Correctness** \u2014 logic, edge cases, error paths. For each acceptance criterion: point to the test that proves it, and check the test would FAIL if the behavior broke.
2673
+ - **Scope** \u2014 anything beyond the task is flagged and reverted unless it is load-bearing.
2674
+ - **Design** \u2014 duplication, dead code, needless complexity, dependency direction, encapsulation. Verify every API/library call actually exists in the project's dependencies.
2675
+ - **Conventions & naming** \u2014 matches the surrounding code; names say what things are.
2676
+ - **Safety** \u2014 no secrets, credentials, or debugging remnants in code, tests, or fixtures.
2677
+ 3. Fix what is justified \u2014 smallest change that resolves the finding, keeping behavior. Re-run the checks after material fixes.
2678
+ 4. Record your findings honestly in your closing summary: what you found, what you fixed, what you deliberately left, and what you could not verify.
2679
+
2680
+ Handoff bar: checks pass on YOUR final commit; every fix is committed; your summary lists findings \u2192 resolutions (an empty findings list must say what you checked).`;
2681
+ var QA_PROMPT = `# Role: QA
2682
+
2683
+ You are the final gate. You verify the delivered work against the acceptance criteria as a whole \u2014 end to end, the way a demanding user would \u2014 and produce the run's closing report.
2684
+
2685
+ Method:
2686
+ 1. Read the task and \`SPEC.pack.md\` (when present). Your contract is the acceptance criteria; without a spec, derive them from the task.
2687
+ 2. For EACH criterion, verify it against the real project: run the relevant tests, execute the code paths where feasible, inspect actual behavior/output. Do not take earlier stages' word for anything.
2688
+ 3. Run the project's full checks (tests, lint, types, build) one final time.
2689
+ 4. Write \`QA-REPORT.pack.md\` at the repo root: per-criterion verdict (\u2705 verified / \u26A0\uFE0F partially / \u274C failed \u2014 with evidence for each), the checks' results, anything not verifiable in this environment (stated plainly), and a short "ready to ship?" conclusion.
2690
+ 5. If a criterion FAILS: fix it only when the fix is small and unambiguous; otherwise mark it failed with exact evidence \u2014 the user decides. Never paper over a failure.
2691
+
2692
+ Handoff bar: the report is committed; every verdict carries evidence; the conclusion is honest about anything unverified.`;
2693
+
2694
+ // ../../packages/shared/src/packs/registry.ts
2695
+ var PACK_REGISTRY = {
2696
+ "quick-pack": {
2697
+ id: "quick-pack",
2698
+ name: "Quick Pack",
2699
+ tagline: "Implement, then a fresh-eyes review \u2014 the tight loop.",
2700
+ gate: "free",
2701
+ stages: [
2702
+ {
2703
+ role: "coder",
2704
+ name: "Coder",
2705
+ description: "Implements the task with tests, TDD-first.",
2706
+ skillIds: ["spec-driven-development"],
2707
+ prompt: CODER_PROMPT
2708
+ },
2709
+ {
2710
+ role: "reviewer",
2711
+ name: "Reviewer",
2712
+ description: "Skeptical review in a fresh context \u2014 finds and fixes what the coder missed.",
2713
+ skillIds: ["code-review", "code-naming"],
2714
+ prompt: REVIEWER_PROMPT
2715
+ }
2716
+ ]
2717
+ },
2718
+ "full-pack": {
2719
+ id: "full-pack",
2720
+ name: "Full Pack",
2721
+ tagline: "Spec \u2192 implement \u2192 review \u2192 verify. Every quality gate, one run.",
2722
+ gate: "pro",
2723
+ stages: [
2724
+ {
2725
+ role: "specifier",
2726
+ name: "Specifier",
2727
+ description: "Turns the task into testable acceptance criteria before any code.",
2728
+ skillIds: ["spec-driven-development"],
2729
+ prompt: SPECIFIER_PROMPT
2730
+ },
2731
+ {
2732
+ role: "coder",
2733
+ name: "Coder",
2734
+ description: "Implements the acceptance criteria with tests, TDD-first.",
2735
+ skillIds: [],
2736
+ prompt: CODER_PROMPT
2737
+ },
2738
+ {
2739
+ role: "reviewer",
2740
+ name: "Reviewer",
2741
+ description: "Audits correctness, scope, design, and conventions with fresh eyes.",
2742
+ skillIds: ["code-review", "code-naming"],
2743
+ prompt: REVIEWER_PROMPT
2744
+ },
2745
+ {
2746
+ role: "qa",
2747
+ name: "QA",
2748
+ description: "Verifies every acceptance criterion end to end and writes the final report.",
2749
+ skillIds: [],
2750
+ prompt: QA_PROMPT
2751
+ }
2752
+ ]
2753
+ }
2754
+ };
2755
+ function isPackId(id) {
2756
+ return Object.prototype.hasOwnProperty.call(PACK_REGISTRY, id);
2757
+ }
2758
+ function getPackDefinition(id) {
2759
+ return isPackId(id) ? PACK_REGISTRY[id] : null;
2760
+ }
2761
+
2762
+ // ../../packages/shared/src/packs/workflow-article.ts
2763
+ var PACK_WORKFLOW_ARTICLE = `## Pipeline rules (you are one stage of an assembly line)
2764
+
2765
+ You are ONE specialist role in a multi-role pipeline running on this repository. Other specialist roles ran before you and/or run after you, each in a separate conversation. Follow these rules exactly:
2766
+
2767
+ - **Do only your role's job.** The next stage exists for a reason \u2014 don't do its work, and don't redo a previous stage's work unless your role explicitly calls for correcting it.
2768
+ - **Work from the handoff.** The previous stage's handoff (commit + summary) is your input. Start by reading the current state of the working tree \u2014 it already contains all prior stages' work.
2769
+ - **Commit your work when your stage is complete.** One or more focused commits; the final state of the tree IS your handoff to the next stage. End every commit message with your role byline on its own line: \`By <role>.\`
2770
+ - **Never leave the tree broken.** Run the project's checks before finishing when the project has them; your stage ends with a working tree the next role can build on.
2771
+ - **Do not push, force-push, or touch remotes** \u2014 the pipeline works locally; publishing is the user's call at the end.
2772
+ - **Never read, edit, or commit anything under \`.codeam/\`** \u2014 that is the pipeline's own ledger, not project code.
2773
+ - **Finish decisively.** When your stage's job is done and committed, say so in 2-4 lines (what you did, what you verified, anything the next stage should know) and stop. Don't ask "should I continue?" \u2014 the pipeline advances automatically.
2774
+ - **If you are genuinely blocked** (contradictory requirements, missing access), say exactly what is blocking you and stop \u2014 the user is supervising and will decide.`;
2775
+
2638
2776
  // ../../packages/shared/src/api-url.ts
2639
2777
  var DEFAULT_API_BASE_URL = "https://api.codeagent-mobile.com";
2640
2778
  var DEV_API_BASE_URL = "https://dev-api.codeagent-mobile.com";
@@ -2781,7 +2919,12 @@ var USER_EVENTS = {
2781
2919
  * toast when the review runs server-side (Inngest). Mobile-only surface,
2782
2920
  * produced by api-v2 (the CLI neither produces nor consumes it). Mirrored in
2783
2921
  * repo A. */
2784
- PR_REVIEW_LAUNCH: "pr_review_launch"
2922
+ PR_REVIEW_LAUNCH: "pr_review_launch",
2923
+ /** Agent Packs — full `PackRunState` republished by the backend on every
2924
+ * pipeline transition (stage start/done, pause, stall, completion). CLI
2925
+ * posts to /api/packs/events; mobile's pack.store renders the pipeline.
2926
+ * Mirrored in repo A's app-shared events.ts. */
2927
+ PACK_STATE: "pack_state"
2785
2928
  };
2786
2929
 
2787
2930
  // ../../packages/shared/src/preview-prompts.ts
@@ -2972,11 +3115,11 @@ function quiet(fn) {
2972
3115
  log.debug(TAG, "ignored sync error", err);
2973
3116
  }
2974
3117
  }
2975
- function rmIfExistsQuiet(path87) {
3118
+ function rmIfExistsQuiet(path89) {
2976
3119
  try {
2977
- fs2.rmSync(path87, { force: true });
3120
+ fs2.rmSync(path89, { force: true });
2978
3121
  } catch (err) {
2979
- log.debug(TAG, `rmIfExists failed for ${path87}`, err);
3122
+ log.debug(TAG, `rmIfExists failed for ${path89}`, err);
2980
3123
  }
2981
3124
  }
2982
3125
  function killQuiet(target, signal = "SIGTERM") {
@@ -3160,8 +3303,8 @@ function createGetModuleFromFilename(basePath = process.argv[1] ? (0, import_pat
3160
3303
  return decodedFile;
3161
3304
  };
3162
3305
  }
3163
- function normalizeWindowsPath(path87) {
3164
- return path87.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
3306
+ function normalizeWindowsPath(path89) {
3307
+ return path89.replace(/^[A-Z]:/, "").replace(/\\/g, "/");
3165
3308
  }
3166
3309
 
3167
3310
  // ../../node_modules/@posthog/core/dist/featureFlagUtils.mjs
@@ -5641,9 +5784,9 @@ async function addSourceContext(frames) {
5641
5784
  LRU_FILE_CONTENTS_CACHE.reduce();
5642
5785
  return frames;
5643
5786
  }
5644
- function getContextLinesFromFile(path87, ranges, output) {
5787
+ function getContextLinesFromFile(path89, ranges, output) {
5645
5788
  return new Promise((resolve9) => {
5646
- const stream = (0, import_node_fs.createReadStream)(path87);
5789
+ const stream = (0, import_node_fs.createReadStream)(path89);
5647
5790
  const lineReaded = (0, import_node_readline.createInterface)({
5648
5791
  input: stream
5649
5792
  });
@@ -5658,7 +5801,7 @@ function getContextLinesFromFile(path87, ranges, output) {
5658
5801
  let rangeStart = range[0];
5659
5802
  let rangeEnd = range[1];
5660
5803
  function onStreamError() {
5661
- LRU_FILE_CONTENTS_FS_READ_FAILED.set(path87, 1);
5804
+ LRU_FILE_CONTENTS_FS_READ_FAILED.set(path89, 1);
5662
5805
  lineReaded.close();
5663
5806
  lineReaded.removeAllListeners();
5664
5807
  destroyStreamAndResolve();
@@ -5719,8 +5862,8 @@ function clearLineContext(frame) {
5719
5862
  delete frame.context_line;
5720
5863
  delete frame.post_context;
5721
5864
  }
5722
- function shouldSkipContextLinesForFile(path87) {
5723
- return path87.startsWith("node:") || path87.endsWith(".min.js") || path87.endsWith(".min.cjs") || path87.endsWith(".min.mjs") || path87.startsWith("data:");
5865
+ function shouldSkipContextLinesForFile(path89) {
5866
+ return path89.startsWith("node:") || path89.endsWith(".min.js") || path89.endsWith(".min.cjs") || path89.endsWith(".min.mjs") || path89.startsWith("data:");
5724
5867
  }
5725
5868
  function shouldSkipContextLinesForFrame(frame) {
5726
5869
  if (void 0 !== frame.lineno && frame.lineno > MAX_CONTEXTLINES_LINENO) return true;
@@ -7874,7 +8017,7 @@ function readAnonId() {
7874
8017
  }
7875
8018
  function superProperties() {
7876
8019
  return {
7877
- cliVersion: true ? "2.61.91" : "0.0.0-dev",
8020
+ cliVersion: true ? "2.61.92" : "0.0.0-dev",
7878
8021
  nodeVersion: process.version,
7879
8022
  platform: process.platform,
7880
8023
  arch: process.arch,
@@ -8055,7 +8198,7 @@ var os4 = __toESM(require("os"));
8055
8198
  // package.json
8056
8199
  var package_default = {
8057
8200
  name: "codeam-cli",
8058
- version: "2.61.91",
8201
+ version: "2.61.92",
8059
8202
  description: "Workflow-continuity bridge for AI coding agents. Wrap Claude Code or Codex in a PTY and supervise, approve, and redirect the session from any device \u2014 async. The terminal companion for CodeAgent Mobile.",
8060
8203
  type: "commonjs",
8061
8204
  main: "dist/index.js",
@@ -9360,7 +9503,7 @@ var CommandRelayService = class _CommandRelayService {
9360
9503
  // fresh + clear the "CLI update available" banner after a self-update
9361
9504
  // (a codespace that reinstalls @latest reconnects via heartbeat, not
9362
9505
  // pair/reconnect). Older backends ignore the extra field.
9363
- ..."2.61.91" ? { ideVersion: "2.61.91" } : {}
9506
+ ..."2.61.92" ? { ideVersion: "2.61.92" } : {}
9364
9507
  }).then(() => log.trace("relay", `heartbeat ok online=${online}`)).catch((err) => log.trace("relay", `heartbeat failed online=${online}`, err));
9365
9508
  }
9366
9509
  /**
@@ -15969,8 +16112,8 @@ function pickLine(obj) {
15969
16112
  function toHunk(raw, groupSeverity) {
15970
16113
  if (!raw || typeof raw !== "object") return null;
15971
16114
  const o = raw;
15972
- const path87 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
15973
- if (!path87) return null;
16115
+ const path89 = asString(pick(o, ["file_path", "filePath", "file", "path", "filename", "fileName"])) ?? asString(pick(o, ["location"])?.path);
16116
+ if (!path89) return null;
15974
16117
  const message = asString(
15975
16118
  pick(o, [
15976
16119
  "comment",
@@ -15987,7 +16130,7 @@ function toHunk(raw, groupSeverity) {
15987
16130
  const severity = normSeverity(pick(o, ["severity", "level", "priority", "impact"])) ?? normSeverity(groupSeverity);
15988
16131
  const locObj = pick(o, ["location"]) ?? o;
15989
16132
  return {
15990
- path: path87.trim(),
16133
+ path: path89.trim(),
15991
16134
  line: pickLine(o) ?? pickLine(locObj),
15992
16135
  severity,
15993
16136
  message: (title && message ? `${title}: ${message}` : title || message).trim() || "(no message)"
@@ -16070,10 +16213,10 @@ function parsePlain(stdout) {
16070
16213
  for (const line of stdout.split(/\r?\n/)) {
16071
16214
  const m = line.match(HUNK_LINE_RE);
16072
16215
  if (!m) continue;
16073
- const [, path87, lineNo, sevToken, message] = m;
16074
- if (!path87 || !lineNo || !message) continue;
16216
+ const [, path89, lineNo, sevToken, message] = m;
16217
+ if (!path89 || !lineNo || !message) continue;
16075
16218
  hunks.push({
16076
- path: path87.trim(),
16219
+ path: path89.trim(),
16077
16220
  line: Number(lineNo),
16078
16221
  severity: sevToken ? SEVERITY_MAP[sevToken.toLowerCase()] : void 0,
16079
16222
  message: message.trim().replace(/^[*-]\s+/, "")
@@ -20533,7 +20676,7 @@ async function autoUpgradeBeforeCriticalCommand() {
20533
20676
  if (process.env.NODE_ENV === "test") return;
20534
20677
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
20535
20678
  if (process.env.CI) return;
20536
- const current2 = true ? "2.61.91" : null;
20679
+ const current2 = true ? "2.61.92" : null;
20537
20680
  if (!current2) return;
20538
20681
  const cache = readCache();
20539
20682
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -20550,7 +20693,7 @@ function checkForUpdates() {
20550
20693
  if (process.env.CODEAM_DISABLE_UPDATE_CHECK === "1") return;
20551
20694
  if (process.env.CI) return;
20552
20695
  if (!process.stdout.isTTY) return;
20553
- const current2 = true ? "2.61.91" : null;
20696
+ const current2 = true ? "2.61.92" : null;
20554
20697
  if (!current2) return;
20555
20698
  const cache = readCache();
20556
20699
  const fresh = cache && Date.now() - cache.fetchedAt < TTL_MS;
@@ -20570,7 +20713,7 @@ var SELF_UPDATE_INTERVAL_MS = 60 * 60 * 1e3;
20570
20713
  var SELF_UPDATE_VIEW_TIMEOUT_MS = 3e4;
20571
20714
  var SELF_UPDATE_INSTALL_TIMEOUT_MS = 18e4;
20572
20715
  function currentCliVersion() {
20573
- return true ? "2.61.91" : null;
20716
+ return true ? "2.61.92" : null;
20574
20717
  }
20575
20718
  function runCmd(cmd, args2, timeoutMs) {
20576
20719
  return new Promise((resolve9) => {
@@ -25926,13 +26069,13 @@ function resolveGlobalNodeModulesDir(opts) {
25926
26069
  var STALE_STAGING_AGE_MS = CLI_UPDATE_INSTALL_TIMEOUT_MS;
25927
26070
  function sweepStaleCliStagingDirs(nodeModulesDir, now = Date.now(), deps) {
25928
26071
  if (!nodeModulesDir) return 0;
25929
- const readdirSync13 = deps?.readdirSync ?? fs62.readdirSync;
26072
+ const readdirSync14 = deps?.readdirSync ?? fs62.readdirSync;
25930
26073
  const statSync17 = deps?.statSync ?? fs62.statSync;
25931
26074
  const rmSync9 = deps?.rmSync ?? fs62.rmSync;
25932
26075
  let removed = 0;
25933
26076
  let entries;
25934
26077
  try {
25935
- entries = readdirSync13(nodeModulesDir);
26078
+ entries = readdirSync14(nodeModulesDir);
25936
26079
  } catch {
25937
26080
  return 0;
25938
26081
  }
@@ -26815,11 +26958,11 @@ function resolveTokenValue(args2) {
26815
26958
  }
26816
26959
  const fileFlag = args2.find((a) => a.startsWith("--token-file="));
26817
26960
  if (fileFlag) {
26818
- const path87 = fileFlag.slice("--token-file=".length);
26961
+ const path89 = fileFlag.slice("--token-file=".length);
26819
26962
  try {
26820
- const content = fs63.readFileSync(path87, "utf8").trim();
26821
- if (content.length === 0) fail(`--token-file ${path87} is empty`);
26822
- rmIfExistsQuiet(path87);
26963
+ const content = fs63.readFileSync(path89, "utf8").trim();
26964
+ if (content.length === 0) fail(`--token-file ${path89} is empty`);
26965
+ rmIfExistsQuiet(path89);
26823
26966
  return content;
26824
26967
  } catch (err) {
26825
26968
  fail(`Could not read --token-file: ${err.message}`);
@@ -27465,14 +27608,14 @@ function defaultSdkDir() {
27465
27608
  return resolveSdkDirViaRequire();
27466
27609
  }
27467
27610
  function resolveClaudeNativeBinary(deps = {}) {
27468
- const existsSync28 = deps.existsSync ?? import_fs6.default.existsSync;
27611
+ const existsSync29 = deps.existsSync ?? import_fs6.default.existsSync;
27469
27612
  const platformKey = deps.platformKey ?? currentPlatformKey();
27470
27613
  const sdkDir = deps.sdkDir !== void 0 ? deps.sdkDir : defaultSdkDir();
27471
27614
  if (!sdkDir) return null;
27472
27615
  const scopeDir = import_path8.default.dirname(sdkDir);
27473
27616
  const binName = platformKey.startsWith("win32-") ? "claude.exe" : "claude";
27474
27617
  const candidate = import_path8.default.join(scopeDir, `claude-agent-sdk-${platformKey}`, binName);
27475
- return existsSync28(candidate) ? candidate : null;
27618
+ return existsSync29(candidate) ? candidate : null;
27476
27619
  }
27477
27620
  var realSleep = (ms) => new Promise((resolve9) => setTimeout(resolve9, ms));
27478
27621
  async function waitForClaudeNativeBinary(opts = {}) {
@@ -27523,18 +27666,18 @@ async function waitForCommandOnPath(cmd, opts = {}) {
27523
27666
  return check();
27524
27667
  }
27525
27668
  function resolveCursorAgentBinary(deps = {}) {
27526
- const existsSync28 = deps.existsSync ?? import_fs6.default.existsSync;
27669
+ const existsSync29 = deps.existsSync ?? import_fs6.default.existsSync;
27527
27670
  const platform3 = deps.platform ?? process.platform;
27528
27671
  const env = deps.env ?? process.env;
27529
27672
  if (platform3 === "win32") {
27530
27673
  const localAppData = env.LOCALAPPDATA;
27531
27674
  if (!localAppData) return null;
27532
27675
  const exe = import_path8.default.win32.join(localAppData, "cursor-agent", "cursor-agent.exe");
27533
- return existsSync28(exe) ? exe : null;
27676
+ return existsSync29(exe) ? exe : null;
27534
27677
  }
27535
27678
  const home = deps.homedir ?? import_os11.default.homedir();
27536
27679
  const unix = import_path8.default.posix.join(home, ".local", "bin", "cursor-agent");
27537
- return existsSync28(unix) ? unix : null;
27680
+ return existsSync29(unix) ? unix : null;
27538
27681
  }
27539
27682
  async function waitForCursorAgent(opts = {}) {
27540
27683
  const timeoutMs = opts.timeoutMs ?? 18e4;
@@ -33078,6 +33221,28 @@ var AcpClient = class {
33078
33221
  * reply cleanly. The `finally` guarantees the guard clears even if the load
33079
33222
  * throws, so a failed recovery can't wedge streaming off.
33080
33223
  */
33224
+ /**
33225
+ * Start a BRAND-NEW conversation on the SAME running adapter process and make
33226
+ * it the active session. Agent Packs' stage boundary: each pipeline role runs
33227
+ * in a fresh conversation (fresh context — the reviewer must not see the
33228
+ * coder's conversation), so the pack runner calls this between stages instead
33229
+ * of respawning the agent. Same `session/new` the startup handshake and
33230
+ * {@link reestablishSession} send; callers own re-pointing the history anchor
33231
+ * (`AcpHistory.switchActiveSession` + `onActiveSessionChanged`), exactly like
33232
+ * the `resume_session` rail.
33233
+ */
33234
+ async newConversation() {
33235
+ if (!this.connection) {
33236
+ throw new Error("AcpClient.newConversation called before start()");
33237
+ }
33238
+ const ns = await this.connection.newSession({
33239
+ cwd: this.opts.cwd,
33240
+ mcpServers: this.opts.mcpServers ?? []
33241
+ });
33242
+ this.sessionId = ns.sessionId;
33243
+ log.info("acpClient", `newConversation \u2190 ok sid=${ns.sessionId.slice(0, 8)}`);
33244
+ return ns.sessionId;
33245
+ }
33081
33246
  async reestablishSession() {
33082
33247
  if (!this.connection) throw new Error("AcpClient.reestablishSession: no connection");
33083
33248
  const cwd = this.opts.cwd;
@@ -34559,7 +34724,7 @@ function defaultRunGit(cwd, args2) {
34559
34724
  });
34560
34725
  }
34561
34726
  async function discoverRepos(workingDir, maxDepth = 4) {
34562
- const fs77 = await import("fs/promises");
34727
+ const fs79 = await import("fs/promises");
34563
34728
  const out2 = [];
34564
34729
  await walk(workingDir, 0);
34565
34730
  return out2;
@@ -34567,7 +34732,7 @@ async function discoverRepos(workingDir, maxDepth = 4) {
34567
34732
  if (depth > maxDepth) return;
34568
34733
  let entries = [];
34569
34734
  try {
34570
- const dirents = await fs77.readdir(dir, { withFileTypes: true });
34735
+ const dirents = await fs79.readdir(dir, { withFileTypes: true });
34571
34736
  entries = dirents.filter((d3) => !d3.name.startsWith(".") || d3.name === ".git").map((d3) => ({ name: d3.name, isDirectory: d3.isDirectory() }));
34572
34737
  } catch {
34573
34738
  return;
@@ -35210,6 +35375,514 @@ async function postBudgetReached(opts, fetchImpl = fetch) {
35210
35375
  }
35211
35376
  }
35212
35377
 
35378
+ // src/packs/gates.ts
35379
+ var import_node_child_process30 = require("child_process");
35380
+ var fs71 = __toESM(require("fs"));
35381
+ var path77 = __toESM(require("path"));
35382
+ var defaultCommandRunner = (file, args2, cwd, timeoutMs) => new Promise((resolve9) => {
35383
+ (0, import_node_child_process30.execFile)(
35384
+ file,
35385
+ args2,
35386
+ { cwd, timeout: timeoutMs, maxBuffer: 4 * 1024 * 1024 },
35387
+ (err, stdout, stderr) => {
35388
+ let code = 0;
35389
+ if (err) {
35390
+ const rawCode = err.code;
35391
+ code = typeof rawCode === "number" ? rawCode : 1;
35392
+ }
35393
+ resolve9({ code, stdout: stdout ?? "", stderr: stderr ?? "" });
35394
+ }
35395
+ );
35396
+ });
35397
+ var GIT_TIMEOUT_MS = 15e3;
35398
+ async function gitHead(run, cwd) {
35399
+ const res = await run("git", ["rev-parse", "HEAD"], cwd, GIT_TIMEOUT_MS);
35400
+ return res.code === 0 ? res.stdout.trim() : null;
35401
+ }
35402
+ async function canonicalCommit(run, cwd, sha) {
35403
+ const verify = await run("git", ["rev-parse", "--verify", `${sha}^{commit}`], cwd, GIT_TIMEOUT_MS);
35404
+ if (verify.code !== 0) return null;
35405
+ const short = await run("git", ["rev-parse", "--short=10", sha], cwd, GIT_TIMEOUT_MS);
35406
+ return short.code === 0 ? short.stdout.trim() : null;
35407
+ }
35408
+ async function diffStat(run, cwd, from, to) {
35409
+ const res = await run("git", ["diff", "--stat", `${from}..${to}`], cwd, GIT_TIMEOUT_MS);
35410
+ if (res.code !== 0) return "";
35411
+ const lines = res.stdout.trim().split("\n").filter(Boolean);
35412
+ return lines.length > 0 ? lines[lines.length - 1].trim() : "";
35413
+ }
35414
+ var NO_TEST_PLACEHOLDER = 'echo "Error: no test specified"';
35415
+ var CHECKS_TIMEOUT_MS = 5 * 6e4;
35416
+ function detectChecksCommand(cwd) {
35417
+ try {
35418
+ const cfg = JSON.parse(fs71.readFileSync(path77.join(cwd, ".codeam", "pack.json"), "utf8"));
35419
+ if (typeof cfg.checksCommand === "string" && cfg.checksCommand.trim().length > 0) {
35420
+ return cfg.checksCommand.trim();
35421
+ }
35422
+ } catch {
35423
+ }
35424
+ try {
35425
+ const pkg = JSON.parse(fs71.readFileSync(path77.join(cwd, "package.json"), "utf8"));
35426
+ const test = pkg.scripts?.test;
35427
+ if (typeof test === "string" && test.trim().length > 0 && !test.includes(NO_TEST_PLACEHOLDER)) {
35428
+ return "npm test";
35429
+ }
35430
+ } catch {
35431
+ }
35432
+ return null;
35433
+ }
35434
+ async function runChecks(run, cwd, command2) {
35435
+ const res = await run("sh", ["-c", command2], cwd, CHECKS_TIMEOUT_MS);
35436
+ const combined = `${res.stdout}
35437
+ ${res.stderr}`.trim();
35438
+ const tail = combined.split("\n").slice(-12).join("\n").slice(-1500);
35439
+ return { command: command2, passed: res.code === 0, tail };
35440
+ }
35441
+
35442
+ // src/packs/run-store.ts
35443
+ var fs72 = __toESM(require("fs"));
35444
+ var path78 = __toESM(require("path"));
35445
+ var crypto5 = __toESM(require("crypto"));
35446
+ function packsDir(cwd) {
35447
+ return path78.join(cwd, ".codeam", "packs");
35448
+ }
35449
+ function runDir(cwd, runId) {
35450
+ return path78.join(packsDir(cwd), runId);
35451
+ }
35452
+ function newRunId() {
35453
+ return `pk_${Date.now().toString(36)}_${crypto5.randomBytes(4).toString("hex")}`;
35454
+ }
35455
+ function writeJsonAtomic(file, value) {
35456
+ fs72.mkdirSync(path78.dirname(file), { recursive: true });
35457
+ const tmp = `${file}.tmp`;
35458
+ fs72.writeFileSync(tmp, JSON.stringify(value, null, 2));
35459
+ fs72.renameSync(tmp, file);
35460
+ }
35461
+ function saveRun(cwd, state) {
35462
+ writeJsonAtomic(path78.join(runDir(cwd, state.runId), "run.json"), state);
35463
+ }
35464
+ function saveStageHandoff(cwd, runId, stageIndex, role, handoff) {
35465
+ const name = `${String(stageIndex + 1).padStart(2, "0")}-${role}.json`;
35466
+ writeJsonAtomic(path78.join(runDir(cwd, runId), name), handoff);
35467
+ }
35468
+ function loadLatestRun(cwd) {
35469
+ try {
35470
+ const dir = packsDir(cwd);
35471
+ const entries = fs72.readdirSync(dir, { withFileTypes: true }).filter((e) => e.isDirectory()).map((e) => e.name).sort();
35472
+ for (let i = entries.length - 1; i >= 0; i--) {
35473
+ const file = path78.join(dir, entries[i], "run.json");
35474
+ try {
35475
+ const parsed = JSON.parse(fs72.readFileSync(file, "utf8"));
35476
+ if (parsed && typeof parsed.runId === "string") return parsed;
35477
+ } catch {
35478
+ }
35479
+ }
35480
+ } catch {
35481
+ }
35482
+ return null;
35483
+ }
35484
+ function ensureLedgerIgnored(cwd) {
35485
+ try {
35486
+ const gitDir = path78.join(cwd, ".git");
35487
+ if (!fs72.existsSync(gitDir)) return;
35488
+ const exclude = path78.join(gitDir, "info", "exclude");
35489
+ let existing = "";
35490
+ try {
35491
+ existing = fs72.readFileSync(exclude, "utf8");
35492
+ } catch {
35493
+ }
35494
+ if (existing.includes(".codeam/packs/")) return;
35495
+ fs72.mkdirSync(path78.dirname(exclude), { recursive: true });
35496
+ fs72.writeFileSync(exclude, `${existing.trimEnd()}
35497
+ .codeam/packs/
35498
+ `.trimStart());
35499
+ } catch {
35500
+ }
35501
+ }
35502
+
35503
+ // src/packs/events.ts
35504
+ async function postPackState(opts, state, fetchImpl = fetch) {
35505
+ const url2 = `${resolveApiBaseUrl()}/api/packs/events`;
35506
+ const body = JSON.stringify({ sessionId: opts.sessionId, pluginId: opts.pluginId, state });
35507
+ try {
35508
+ const makeHeaders = (token) => ({
35509
+ "Content-Type": "application/json",
35510
+ "X-Plugin-Auth-Token": token
35511
+ });
35512
+ const response = await fetchImpl(url2, {
35513
+ method: "POST",
35514
+ headers: makeHeaders(opts.pluginAuthToken),
35515
+ body
35516
+ });
35517
+ if (response.status === 401 || response.status === 403) {
35518
+ const freshToken = await fetchCurrentPluginAuthToken(
35519
+ opts.sessionId,
35520
+ opts.pluginId,
35521
+ opts.pollSecret
35522
+ );
35523
+ if (freshToken !== null) {
35524
+ await fetchImpl(url2, { method: "POST", headers: makeHeaders(freshToken), body });
35525
+ }
35526
+ }
35527
+ } catch {
35528
+ }
35529
+ }
35530
+
35531
+ // src/packs/runner.ts
35532
+ var NUDGE_PROMPT = "Your stage is not committed yet. Commit your completed work now (focused commits, ending with your role byline `By <role>.` on its own line), then summarize in 2-4 lines and stop. If you are blocked, say exactly what is blocking you instead.";
35533
+ var SUMMARY_MAX_CHARS = 600;
35534
+ function composeStagePrompt(pack, stageIndex, task, previous) {
35535
+ const stage = pack.stages[stageIndex];
35536
+ const pipeline2 = pack.stages.map((s, i) => i === stageIndex ? `[${s.name}]` : s.name).join(" \u2192 ");
35537
+ const parts = [
35538
+ stage.prompt,
35539
+ PACK_WORKFLOW_ARTICLE,
35540
+ `## Your pipeline position
35541
+ ${pack.name}: ${pipeline2} \u2014 you are stage ${stageIndex + 1} of ${pack.stages.length}. Your commit byline: \`By ${stage.role}.\``,
35542
+ `## Task
35543
+ ${task}`
35544
+ ];
35545
+ if (previous) {
35546
+ parts.push(
35547
+ `## Previous stage handoff (${previous.role})
35548
+ commit: ${previous.handoff.commit}
35549
+ ${previous.handoff.diffStat}
35550
+
35551
+ ${previous.handoff.summary}`
35552
+ );
35553
+ }
35554
+ return parts.join("\n\n");
35555
+ }
35556
+ function nowIso() {
35557
+ return (/* @__PURE__ */ new Date()).toISOString();
35558
+ }
35559
+ var PackRunner = class _PackRunner {
35560
+ constructor(deps, pack, initial) {
35561
+ this.deps = deps;
35562
+ this.pack = pack;
35563
+ this.state = initial;
35564
+ }
35565
+ deps;
35566
+ pack;
35567
+ state;
35568
+ control = "run";
35569
+ looping = false;
35570
+ static create(deps, packId, task, runId) {
35571
+ const pack = getPackDefinition(packId);
35572
+ if (!pack) throw new Error(`unknown pack: ${packId}`);
35573
+ const stages = pack.stages.map((s) => ({
35574
+ role: s.role,
35575
+ name: s.name,
35576
+ status: "pending"
35577
+ }));
35578
+ const state = {
35579
+ runId,
35580
+ packId: pack.id,
35581
+ task,
35582
+ status: "running",
35583
+ currentStage: 0,
35584
+ stages,
35585
+ startedAt: nowIso(),
35586
+ updatedAt: nowIso()
35587
+ };
35588
+ return new _PackRunner(deps, pack, state);
35589
+ }
35590
+ getState() {
35591
+ return this.state;
35592
+ }
35593
+ /** Persist + post the current state (ledger first — it's the truth). */
35594
+ async publish() {
35595
+ this.state = { ...this.state, updatedAt: nowIso() };
35596
+ try {
35597
+ this.deps.ledger.saveRun(this.state);
35598
+ } catch (err) {
35599
+ this.deps.log(`pack ledger save failed: ${err.message}`);
35600
+ }
35601
+ await this.deps.postState(this.state);
35602
+ }
35603
+ async settle(status2, stalledReason) {
35604
+ this.state = { ...this.state, status: status2, stalledReason };
35605
+ await this.publish();
35606
+ }
35607
+ // ── Control surface (relay `pack_action`) ────────────────────────────────
35608
+ async applyAction(action) {
35609
+ switch (action) {
35610
+ case "pause":
35611
+ this.control = "pause";
35612
+ if (this.state.status === "running") {
35613
+ this.state = { ...this.state, status: "paused" };
35614
+ await this.publish();
35615
+ }
35616
+ break;
35617
+ case "resume":
35618
+ this.control = "run";
35619
+ if (this.state.status === "paused" || this.state.status === "stalled") {
35620
+ this.state = { ...this.state, status: "running", stalledReason: void 0 };
35621
+ await this.publish();
35622
+ void this.run();
35623
+ }
35624
+ break;
35625
+ case "retry_stage": {
35626
+ const idx = this.state.currentStage;
35627
+ if (idx < this.state.stages.length) {
35628
+ const stages = this.state.stages.slice();
35629
+ stages[idx] = { role: stages[idx].role, name: stages[idx].name, status: "pending" };
35630
+ this.control = "run";
35631
+ this.state = { ...this.state, stages, status: "running", stalledReason: void 0 };
35632
+ await this.publish();
35633
+ void this.run();
35634
+ }
35635
+ break;
35636
+ }
35637
+ case "skip_stage": {
35638
+ const idx = this.state.currentStage;
35639
+ if (idx < this.state.stages.length) {
35640
+ const stages = this.state.stages.slice();
35641
+ stages[idx] = { ...stages[idx], status: "skipped" };
35642
+ this.control = "run";
35643
+ this.state = {
35644
+ ...this.state,
35645
+ stages,
35646
+ currentStage: idx + 1,
35647
+ status: "running",
35648
+ stalledReason: void 0
35649
+ };
35650
+ await this.publish();
35651
+ void this.run();
35652
+ }
35653
+ break;
35654
+ }
35655
+ case "abort":
35656
+ this.control = "abort";
35657
+ await this.deps.driver.cancel().catch(() => void 0);
35658
+ if (!this.looping) await this.settle("aborted");
35659
+ break;
35660
+ }
35661
+ return this.state;
35662
+ }
35663
+ // ── The loop ──────────────────────────────────────────────────────────────
35664
+ async run() {
35665
+ if (this.looping) return;
35666
+ this.looping = true;
35667
+ try {
35668
+ while (this.state.currentStage < this.state.stages.length) {
35669
+ if (this.control === "abort") {
35670
+ await this.settle("aborted");
35671
+ return;
35672
+ }
35673
+ if (this.control === "pause") {
35674
+ await this.settle("paused");
35675
+ return;
35676
+ }
35677
+ const advanced = await this.runStage(this.state.currentStage);
35678
+ if (!advanced) return;
35679
+ }
35680
+ await this.settle("completed");
35681
+ this.deps.log(`pack run ${this.state.runId} completed`);
35682
+ } catch (err) {
35683
+ await this.settle("failed", err.message).catch(() => void 0);
35684
+ } finally {
35685
+ this.looping = false;
35686
+ }
35687
+ }
35688
+ /** Run one stage to its handoff. True = advanced; false = run settled. */
35689
+ async runStage(index) {
35690
+ const stageDef = this.pack.stages[index];
35691
+ const startedMs = Date.now();
35692
+ const startSha = await this.deps.gates.head();
35693
+ let stages = this.state.stages.slice();
35694
+ stages[index] = { ...stages[index], status: "active" };
35695
+ this.state = { ...this.state, stages, status: "running" };
35696
+ try {
35697
+ const conversationId = await this.deps.driver.newConversation();
35698
+ stages = this.state.stages.slice();
35699
+ stages[index] = { ...stages[index], conversationId };
35700
+ this.state = { ...this.state, stages };
35701
+ await this.publish();
35702
+ this.deps.driver.mountSkills(stageDef.skillIds);
35703
+ const previous = this.previousHandoff(index);
35704
+ const prompt = composeStagePrompt(this.pack, index, this.state.task, previous);
35705
+ const displayLine = `\u25B6 ${this.pack.name} \u2014 stage ${index + 1}/${this.pack.stages.length}: ${stageDef.name}`;
35706
+ let reply = await this.deps.driver.runTurn(prompt, displayLine);
35707
+ if (this.control === "abort") {
35708
+ await this.settle("aborted");
35709
+ return false;
35710
+ }
35711
+ let endSha = await this.deps.gates.head();
35712
+ if (!endSha || endSha === startSha) {
35713
+ reply = await this.deps.driver.runTurn(NUDGE_PROMPT, "\u25B6 Waiting for the stage commit\u2026");
35714
+ endSha = await this.deps.gates.head();
35715
+ if (!endSha || endSha === startSha) {
35716
+ return this.stall(index, "stage produced no commit", reply);
35717
+ }
35718
+ }
35719
+ const commit = await this.deps.gates.canonicalCommit(endSha);
35720
+ if (!commit) return this.stall(index, "stage HEAD did not resolve to a commit", reply);
35721
+ const handoff = {
35722
+ commit,
35723
+ summary: reply.trim().slice(-SUMMARY_MAX_CHARS),
35724
+ diffStat: startSha ? await this.deps.gates.diffStat(startSha, endSha) : "",
35725
+ checks: await this.deps.gates.runChecks() ?? void 0,
35726
+ durationMs: Date.now() - startedMs
35727
+ };
35728
+ stages = this.state.stages.slice();
35729
+ stages[index] = { ...stages[index], status: "done", handoff };
35730
+ this.state = { ...this.state, stages, currentStage: index + 1 };
35731
+ try {
35732
+ this.deps.ledger.saveStageHandoff(this.state.runId, index, stageDef.role, handoff);
35733
+ } catch (err) {
35734
+ this.deps.log(`pack handoff save failed: ${err.message}`);
35735
+ }
35736
+ await this.publish();
35737
+ return true;
35738
+ } catch (err) {
35739
+ if (this.control === "abort") {
35740
+ await this.settle("aborted");
35741
+ return false;
35742
+ }
35743
+ return this.stall(index, err.message);
35744
+ }
35745
+ }
35746
+ async stall(index, reason, lastReply) {
35747
+ const stages = this.state.stages.slice();
35748
+ stages[index] = { ...stages[index], status: "failed", error: reason };
35749
+ this.state = { ...this.state, stages };
35750
+ await this.settle("stalled", lastReply ? `${reason} \u2014 last reply: ${lastReply.slice(-300)}` : reason);
35751
+ this.deps.log(`pack run ${this.state.runId} stalled at stage ${index + 1}: ${reason}`);
35752
+ return false;
35753
+ }
35754
+ previousHandoff(index) {
35755
+ for (let i = index - 1; i >= 0; i--) {
35756
+ const s = this.state.stages[i];
35757
+ if (s.status === "done" && s.handoff) return { role: s.role, handoff: s.handoff };
35758
+ }
35759
+ return null;
35760
+ }
35761
+ };
35762
+
35763
+ // src/packs/active.ts
35764
+ var active = null;
35765
+ function setActivePackRunner(runner) {
35766
+ active = runner;
35767
+ }
35768
+ function getActivePackRunner() {
35769
+ return active;
35770
+ }
35771
+
35772
+ // src/packs/handlers.ts
35773
+ var TERMINAL_STATUSES = /* @__PURE__ */ new Set(["completed", "aborted", "failed"]);
35774
+ var PACK_ACTIONS = /* @__PURE__ */ new Set(["pause", "resume", "retry_stage", "skip_stage", "abort"]);
35775
+ function buildPackRunnerDeps(ctx) {
35776
+ const cwd = ctx.opts.cwd;
35777
+ const run = defaultCommandRunner;
35778
+ return {
35779
+ driver: {
35780
+ newConversation: async () => {
35781
+ const id = await ctx.client.newConversation();
35782
+ ctx.history.switchActiveSession(id);
35783
+ ctx.onActiveSessionChanged?.(id);
35784
+ return id;
35785
+ },
35786
+ runTurn: async (prompt, displayLine) => {
35787
+ await ctx.streaming.beginTurn();
35788
+ ctx.history.appendUserPrompt(displayLine);
35789
+ await ctx.client.prompt(prompt);
35790
+ const text = ctx.streaming.getCurrentText();
35791
+ await ctx.streaming.closeTurnWithInteractiveDetection();
35792
+ ctx.history.appendAgentReply(text);
35793
+ await ctx.history.flush();
35794
+ return text;
35795
+ },
35796
+ cancel: () => ctx.client.cancel(),
35797
+ mountSkills: (skillIds) => {
35798
+ for (const id of skillIds) {
35799
+ try {
35800
+ configureSkill("add", id);
35801
+ } catch (err) {
35802
+ log.warn("packs", `skill mount failed for ${id}: ${err.message}`);
35803
+ }
35804
+ }
35805
+ }
35806
+ },
35807
+ gates: {
35808
+ head: () => gitHead(run, cwd),
35809
+ canonicalCommit: (sha) => canonicalCommit(run, cwd, sha),
35810
+ diffStat: (from, to) => diffStat(run, cwd, from, to),
35811
+ runChecks: async () => {
35812
+ const command2 = detectChecksCommand(cwd);
35813
+ return command2 ? runChecks(run, cwd, command2) : null;
35814
+ }
35815
+ },
35816
+ ledger: {
35817
+ saveRun: (state) => saveRun(cwd, state),
35818
+ saveStageHandoff: (runId, index, role, handoff) => saveStageHandoff(cwd, runId, index, role, handoff)
35819
+ },
35820
+ postState: (state) => postPackState(
35821
+ {
35822
+ sessionId: ctx.opts.sessionId,
35823
+ pluginId: ctx.opts.pluginId,
35824
+ pluginAuthToken: ctx.opts.pluginAuthToken,
35825
+ pollSecret: ctx.opts.pollSecret
35826
+ },
35827
+ state
35828
+ ),
35829
+ log: (message) => log.info("packs", message)
35830
+ };
35831
+ }
35832
+ var packStartH = async (ctx) => {
35833
+ const payload = ctx.cmd.payload;
35834
+ const packId = typeof payload?.packId === "string" ? payload.packId : "";
35835
+ const task = typeof payload?.task === "string" ? payload.task.trim() : "";
35836
+ if (!isPackId(packId)) {
35837
+ await ctx.relay.sendResult(ctx.cmd.id, "failed", { error: `unknown pack: ${packId || "(none)"}` });
35838
+ return;
35839
+ }
35840
+ if (task.length === 0) {
35841
+ await ctx.relay.sendResult(ctx.cmd.id, "failed", { error: "pack_start requires a non-empty task" });
35842
+ return;
35843
+ }
35844
+ const existing = getActivePackRunner();
35845
+ if (existing && !TERMINAL_STATUSES.has(existing.getState().status)) {
35846
+ await ctx.relay.sendResult(ctx.cmd.id, "failed", {
35847
+ error: "a pack run is already active on this session \u2014 pause/abort it first",
35848
+ state: existing.getState()
35849
+ });
35850
+ return;
35851
+ }
35852
+ ensureLedgerIgnored(ctx.opts.cwd);
35853
+ const runner = PackRunner.create(buildPackRunnerDeps(ctx), packId, task, newRunId());
35854
+ setActivePackRunner(runner);
35855
+ log.info("packs", `pack_start ${packId} run=${runner.getState().runId}`);
35856
+ await ctx.relay.sendResult(ctx.cmd.id, "completed", {
35857
+ accepted: true,
35858
+ runId: runner.getState().runId,
35859
+ state: runner.getState()
35860
+ });
35861
+ void runner.run();
35862
+ };
35863
+ var packActionH = async (ctx) => {
35864
+ const payload = ctx.cmd.payload;
35865
+ const action = typeof payload?.action === "string" ? payload.action : "";
35866
+ if (!PACK_ACTIONS.has(action)) {
35867
+ await ctx.relay.sendResult(ctx.cmd.id, "failed", { error: `unknown pack action: ${action || "(none)"}` });
35868
+ return;
35869
+ }
35870
+ const runner = getActivePackRunner();
35871
+ if (!runner) {
35872
+ await ctx.relay.sendResult(ctx.cmd.id, "failed", {
35873
+ error: "no active pack run in this session",
35874
+ state: loadLatestRun(ctx.opts.cwd)
35875
+ });
35876
+ return;
35877
+ }
35878
+ const state = await runner.applyAction(action);
35879
+ await ctx.relay.sendResult(ctx.cmd.id, "completed", { state });
35880
+ };
35881
+ var packStatusH = async (ctx) => {
35882
+ const state = getActivePackRunner()?.getState() ?? loadLatestRun(ctx.opts.cwd);
35883
+ await ctx.relay.sendResult(ctx.cmd.id, "completed", { state });
35884
+ };
35885
+
35213
35886
  // src/integrations/provision.ts
35214
35887
  function buildMcpServersForStart(ctx) {
35215
35888
  const manifest = readIntegrationsManifest();
@@ -35348,7 +36021,7 @@ async function detectRepoStack(cwd, runtime) {
35348
36021
  }
35349
36022
 
35350
36023
  // src/agents/acp/command-handlers.ts
35351
- var import_node_child_process30 = require("child_process");
36024
+ var import_node_child_process31 = require("child_process");
35352
36025
 
35353
36026
  // src/agents/acp/buildAcpPromptBlocks.ts
35354
36027
  var MIME_FROM_EXT = {
@@ -35385,35 +36058,35 @@ function buildAcpPromptBlocks(payload) {
35385
36058
  }
35386
36059
 
35387
36060
  // src/agents/agent-standard.ts
35388
- var fs72 = __toESM(require("fs"));
35389
- var path78 = __toESM(require("path"));
36061
+ var fs74 = __toESM(require("fs"));
36062
+ var path80 = __toESM(require("path"));
35390
36063
  var os57 = __toESM(require("os"));
35391
36064
  function ensureAgentStandard(homeDir2 = os57.homedir()) {
35392
36065
  try {
35393
- const file = path78.join(homeDir2, ".claude", "CLAUDE.md");
36066
+ const file = path80.join(homeDir2, ".claude", "CLAUDE.md");
35394
36067
  let existing = "";
35395
36068
  try {
35396
- existing = fs72.readFileSync(file, "utf8");
36069
+ existing = fs74.readFileSync(file, "utf8");
35397
36070
  } catch {
35398
36071
  }
35399
36072
  if (existing.includes(AGENT_STANDARD_MARKER)) return;
35400
- fs72.mkdirSync(path78.dirname(file), { recursive: true });
36073
+ fs74.mkdirSync(path80.dirname(file), { recursive: true });
35401
36074
  const next = existing.trim() ? `${existing.trimEnd()}
35402
36075
 
35403
36076
  ${AGENT_STANDARD_BLOCK}
35404
36077
  ` : `${AGENT_STANDARD_BLOCK}
35405
36078
  `;
35406
- fs72.writeFileSync(file, next);
36079
+ fs74.writeFileSync(file, next);
35407
36080
  } catch {
35408
36081
  }
35409
36082
  }
35410
36083
  var _agentStandardSeam = {
35411
36084
  isLocalSession: () => isLocalSession(),
35412
- markerPath: (sessionId) => path78.join(os57.homedir(), ".codeam", "agent-standard", `${sessionId}.done`),
35413
- exists: (p2) => fs72.existsSync(p2),
36085
+ markerPath: (sessionId) => path80.join(os57.homedir(), ".codeam", "agent-standard", `${sessionId}.done`),
36086
+ exists: (p2) => fs74.existsSync(p2),
35414
36087
  write: (p2) => {
35415
- fs72.mkdirSync(path78.dirname(p2), { recursive: true });
35416
- fs72.writeFileSync(p2, "");
36088
+ fs74.mkdirSync(path80.dirname(p2), { recursive: true });
36089
+ fs74.writeFileSync(p2, "");
35417
36090
  }
35418
36091
  };
35419
36092
  function isClaude(agent) {
@@ -36042,7 +36715,7 @@ async function prewarmNewMcpEntries(manifest, previousIds) {
36042
36715
  fresh.map(
36043
36716
  (e) => new Promise((resolve9) => {
36044
36717
  const mcp = e.delivery.mcp;
36045
- const child = (0, import_node_child_process30.execFile)(
36718
+ const child = (0, import_node_child_process31.execFile)(
36046
36719
  mcp.command,
36047
36720
  [...mcp.args, "--help"],
36048
36721
  { timeout: 9e4 },
@@ -36123,7 +36796,10 @@ var ACP_COMMAND_HANDLERS = {
36123
36796
  preview_start: previewH,
36124
36797
  preview_stop: previewH,
36125
36798
  save_preview_config: previewH,
36126
- skills_configure: skillsConfigureH2
36799
+ skills_configure: skillsConfigureH2,
36800
+ pack_start: packStartH,
36801
+ pack_action: packActionH,
36802
+ pack_status: packStatusH
36127
36803
  };
36128
36804
  async function dispatchAcpCommand(ctx) {
36129
36805
  const handler = ACP_COMMAND_HANDLERS[ctx.cmd.type];
@@ -38034,7 +38710,7 @@ function fetchQuotaUsage(runtime, historySvc) {
38034
38710
 
38035
38711
  // src/agents/claude/credential-sync.ts
38036
38712
  var import_chokidar2 = __toESM(require("chokidar"));
38037
- var crypto5 = __toESM(require("crypto"));
38713
+ var crypto6 = __toESM(require("crypto"));
38038
38714
  var CLAUDE_PUBLIC_AGENT_ID = "claude_code";
38039
38715
  function startClaudeCredentialSync(opts) {
38040
38716
  const push = opts.push ?? postCredentialSync;
@@ -38046,7 +38722,7 @@ function startClaudeCredentialSync(opts) {
38046
38722
  try {
38047
38723
  const tok = await read2();
38048
38724
  if (!tok || !tok.credential) return;
38049
- const hash = crypto5.createHash("sha256").update(tok.credential).digest("hex");
38725
+ const hash = crypto6.createHash("sha256").update(tok.credential).digest("hex");
38050
38726
  if (hash === lastHash) return;
38051
38727
  lastHash = hash;
38052
38728
  await push({
@@ -38083,8 +38759,8 @@ function startClaudeCredentialSync(opts) {
38083
38759
  }
38084
38760
 
38085
38761
  // src/beads/workflow-hint.ts
38086
- var fs73 = __toESM(require("fs"));
38087
- var path79 = __toESM(require("path"));
38762
+ var fs75 = __toESM(require("fs"));
38763
+ var path81 = __toESM(require("path"));
38088
38764
  var os58 = __toESM(require("os"));
38089
38765
  var BEADS_HINT_MARKER = "<!-- codeam:beads-workflow -->";
38090
38766
  var BEADS_HINT = `${BEADS_HINT_MARKER}
@@ -38101,20 +38777,20 @@ This environment uses **bd (beads)** for issue/task tracking and persistent memo
38101
38777
  ${BEADS_HINT_MARKER}`;
38102
38778
  function ensureBeadsWorkflowHint(homeDir2 = os58.homedir()) {
38103
38779
  try {
38104
- const file = path79.join(homeDir2, ".claude", "CLAUDE.md");
38780
+ const file = path81.join(homeDir2, ".claude", "CLAUDE.md");
38105
38781
  let existing = "";
38106
38782
  try {
38107
- existing = fs73.readFileSync(file, "utf8");
38783
+ existing = fs75.readFileSync(file, "utf8");
38108
38784
  } catch {
38109
38785
  }
38110
38786
  if (existing.includes(BEADS_HINT_MARKER)) return;
38111
- fs73.mkdirSync(path79.dirname(file), { recursive: true });
38787
+ fs75.mkdirSync(path81.dirname(file), { recursive: true });
38112
38788
  const next = existing.trim() ? `${existing.trimEnd()}
38113
38789
 
38114
38790
  ${BEADS_HINT}
38115
38791
  ` : `${BEADS_HINT}
38116
38792
  `;
38117
- fs73.writeFileSync(file, next);
38793
+ fs75.writeFileSync(file, next);
38118
38794
  } catch {
38119
38795
  }
38120
38796
  }
@@ -38486,7 +39162,7 @@ var AcpDriver = class {
38486
39162
  };
38487
39163
 
38488
39164
  // src/baton/transcript-mirror.ts
38489
- var fs74 = __toESM(require("fs"));
39165
+ var fs76 = __toESM(require("fs"));
38490
39166
  var TranscriptMirror = class {
38491
39167
  constructor(deps) {
38492
39168
  this.deps = deps;
@@ -38553,7 +39229,7 @@ var TranscriptMirror = class {
38553
39229
  }
38554
39230
  };
38555
39231
  function defaultWatch(file, onChange) {
38556
- const w3 = fs74.watch(file, { persistent: false }, () => onChange());
39232
+ const w3 = fs76.watch(file, { persistent: false }, () => onChange());
38557
39233
  return () => w3.close();
38558
39234
  }
38559
39235
 
@@ -38815,16 +39491,16 @@ function toEpochMs(ts) {
38815
39491
  }
38816
39492
 
38817
39493
  // src/agents/claude/onboarding.ts
38818
- var fs75 = __toESM(require("fs"));
39494
+ var fs77 = __toESM(require("fs"));
38819
39495
  var os60 = __toESM(require("os"));
38820
- var path80 = __toESM(require("path"));
39496
+ var path82 = __toESM(require("path"));
38821
39497
  var ONBOARDING_VERSION_SENTINEL = "9999.0.0";
38822
39498
  function ensureClaudeOnboarded(cwd) {
38823
39499
  try {
38824
- const file = path80.join(os60.homedir(), ".claude.json");
39500
+ const file = path82.join(os60.homedir(), ".claude.json");
38825
39501
  let config = {};
38826
39502
  try {
38827
- config = JSON.parse(fs75.readFileSync(file, "utf8"));
39503
+ config = JSON.parse(fs77.readFileSync(file, "utf8"));
38828
39504
  } catch {
38829
39505
  }
38830
39506
  let changed = false;
@@ -38849,8 +39525,8 @@ function ensureClaudeOnboarded(cwd) {
38849
39525
  }
38850
39526
  }
38851
39527
  if (!changed) return;
38852
- fs75.mkdirSync(path80.dirname(file), { recursive: true });
38853
- fs75.writeFileSync(file, JSON.stringify(config, null, 2));
39528
+ fs77.mkdirSync(path82.dirname(file), { recursive: true });
39529
+ fs77.writeFileSync(file, JSON.stringify(config, null, 2));
38854
39530
  log.info(
38855
39531
  "claude",
38856
39532
  `pre-completed Claude onboarding${cwd ? ` + trusted workspace ${cwd}` : ""}`
@@ -39522,13 +40198,13 @@ var import_picocolors7 = __toESM(require("picocolors"));
39522
40198
  function status() {
39523
40199
  showIntro();
39524
40200
  const config = getConfig();
39525
- const active = config.sessions.find((s) => s.id === config.activeSessionId) ?? null;
40201
+ const active2 = config.sessions.find((s) => s.id === config.activeSessionId) ?? null;
39526
40202
  console.log(import_picocolors7.default.bold(" Status\n"));
39527
40203
  console.log(` Plugin ID ${import_picocolors7.default.dim(config.pluginId || "not generated yet")}`);
39528
40204
  console.log(` Sessions ${config.sessions.length} paired`);
39529
- if (active) {
39530
- console.log(` Active ${import_picocolors7.default.bold(active.userName)} ${import_picocolors7.default.cyan(active.plan)}`);
39531
- console.log(` Session ID ${import_picocolors7.default.dim(active.id)}`);
40205
+ if (active2) {
40206
+ console.log(` Active ${import_picocolors7.default.bold(active2.userName)} ${import_picocolors7.default.cyan(active2.plan)}`);
40207
+ console.log(` Session ID ${import_picocolors7.default.dim(active2.id)}`);
39532
40208
  } else {
39533
40209
  console.log(` Active ${import_picocolors7.default.yellow("none")} ${import_picocolors7.default.dim("run codeam pair to connect")}`);
39534
40210
  }
@@ -39580,7 +40256,7 @@ var import_picocolors11 = __toESM(require("picocolors"));
39580
40256
  var import_child_process29 = require("child_process");
39581
40257
  var import_util4 = require("util");
39582
40258
  var import_picocolors9 = __toESM(require("picocolors"));
39583
- var path81 = __toESM(require("path"));
40259
+ var path83 = __toESM(require("path"));
39584
40260
  var execFileP6 = (0, import_util4.promisify)(import_child_process29.execFile);
39585
40261
  var MAX_BUFFER = 8 * 1024 * 1024;
39586
40262
  function resetStdinForChild() {
@@ -40069,7 +40745,7 @@ var GitHubCodespacesProvider = class {
40069
40745
  });
40070
40746
  }
40071
40747
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
40072
- const remoteDir = path81.posix.dirname(remotePath);
40748
+ const remoteDir = path83.posix.dirname(remotePath);
40073
40749
  const parts = [
40074
40750
  `mkdir -p ${shellQuote(remoteDir)}`,
40075
40751
  `cat > ${shellQuote(remotePath)}`
@@ -40139,7 +40815,7 @@ function shellQuote(s) {
40139
40815
  // src/services/providers/gitpod.ts
40140
40816
  var import_child_process30 = require("child_process");
40141
40817
  var import_util5 = require("util");
40142
- var path82 = __toESM(require("path"));
40818
+ var path84 = __toESM(require("path"));
40143
40819
  var import_picocolors10 = __toESM(require("picocolors"));
40144
40820
  var execFileP7 = (0, import_util5.promisify)(import_child_process30.execFile);
40145
40821
  var MAX_BUFFER2 = 8 * 1024 * 1024;
@@ -40379,7 +41055,7 @@ var GitpodProvider = class {
40379
41055
  });
40380
41056
  }
40381
41057
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
40382
- const remoteDir = path82.posix.dirname(remotePath);
41058
+ const remoteDir = path84.posix.dirname(remotePath);
40383
41059
  const parts = [
40384
41060
  `mkdir -p ${shellQuote2(remoteDir)}`,
40385
41061
  `cat > ${shellQuote2(remotePath)}`
@@ -40415,7 +41091,7 @@ function shellQuote2(s) {
40415
41091
  // src/services/providers/gitlab-workspaces.ts
40416
41092
  var import_child_process31 = require("child_process");
40417
41093
  var import_util6 = require("util");
40418
- var path83 = __toESM(require("path"));
41094
+ var path85 = __toESM(require("path"));
40419
41095
  var execFileP8 = (0, import_util6.promisify)(import_child_process31.execFile);
40420
41096
  var MAX_BUFFER3 = 8 * 1024 * 1024;
40421
41097
  var GITLAB_API_BASE = process.env.CODEAM_GITLAB_API_URL ?? "https://gitlab.com/api/v4";
@@ -40675,7 +41351,7 @@ Docs: https://docs.gitlab.com/ee/user/workspace/configuration.html`
40675
41351
  }
40676
41352
  async uploadFile(workspaceId, remotePath, contents, options = {}) {
40677
41353
  const sshHost = process.env.CODEAM_GITLAB_SSH_HOST ?? "workspaces.gitlab.com";
40678
- const remoteDir = path83.posix.dirname(remotePath);
41354
+ const remoteDir = path85.posix.dirname(remotePath);
40679
41355
  const parts = [`mkdir -p ${shellQuote3(remoteDir)}`, `cat > ${shellQuote3(remotePath)}`];
40680
41356
  if (options.mode != null) {
40681
41357
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote3(remotePath)}`);
@@ -40743,7 +41419,7 @@ function shellQuote3(s) {
40743
41419
  // src/services/providers/railway.ts
40744
41420
  var import_child_process32 = require("child_process");
40745
41421
  var import_util7 = require("util");
40746
- var path84 = __toESM(require("path"));
41422
+ var path86 = __toESM(require("path"));
40747
41423
  var execFileP9 = (0, import_util7.promisify)(import_child_process32.execFile);
40748
41424
  var MAX_BUFFER4 = 8 * 1024 * 1024;
40749
41425
  function resetStdinForChild4() {
@@ -40979,7 +41655,7 @@ var RailwayProvider = class {
40979
41655
  if (!projectId || !serviceId) {
40980
41656
  throw new Error("Invalid Railway workspace id (expected projectId/serviceId).");
40981
41657
  }
40982
- const remoteDir = path84.posix.dirname(remotePath);
41658
+ const remoteDir = path86.posix.dirname(remotePath);
40983
41659
  const parts = [`mkdir -p ${shellQuote4(remoteDir)}`, `cat > ${shellQuote4(remotePath)}`];
40984
41660
  if (options.mode != null) {
40985
41661
  parts.push(`chmod ${options.mode.toString(8)} ${shellQuote4(remotePath)}`);
@@ -41510,9 +42186,9 @@ async function probeCodeamPair(provider, workspace) {
41510
42186
  }
41511
42187
  async function stopWorkspaceFromLocal(target) {
41512
42188
  if (target.provider.id === "github-codespaces") {
41513
- const { execFile: execFile15 } = await import("child_process");
42189
+ const { execFile: execFile16 } = await import("child_process");
41514
42190
  const { promisify: promisify11 } = await import("util");
41515
- const execFileP10 = promisify11(execFile15);
42191
+ const execFileP10 = promisify11(execFile16);
41516
42192
  await execFileP10("gh", ["codespace", "stop", "-c", target.id], { maxBuffer: 8 * 1024 * 1024 });
41517
42193
  return;
41518
42194
  }
@@ -41625,8 +42301,8 @@ async function invite() {
41625
42301
  var import_node_dns = require("dns");
41626
42302
  var import_node_util5 = require("util");
41627
42303
  var import_node_crypto13 = require("crypto");
41628
- var fs76 = __toESM(require("fs"));
41629
- var path85 = __toESM(require("path"));
42304
+ var fs78 = __toESM(require("fs"));
42305
+ var path87 = __toESM(require("path"));
41630
42306
  var import_picocolors14 = __toESM(require("picocolors"));
41631
42307
  var dnsResolveP = (0, import_node_util5.promisify)(import_node_dns.resolve);
41632
42308
  async function checkDns(apiBase2) {
@@ -41682,13 +42358,13 @@ async function checkHealth(apiBase2) {
41682
42358
  }
41683
42359
  }
41684
42360
  function checkConfigDir() {
41685
- const dir = path85.join(require("os").homedir(), ".codeam");
42361
+ const dir = path87.join(require("os").homedir(), ".codeam");
41686
42362
  try {
41687
- fs76.mkdirSync(dir, { recursive: true, mode: 448 });
41688
- const probe = path85.join(dir, ".doctor-probe");
41689
- fs76.writeFileSync(probe, "ok", { mode: 384 });
41690
- const read2 = fs76.readFileSync(probe, "utf8");
41691
- fs76.unlinkSync(probe);
42363
+ fs78.mkdirSync(dir, { recursive: true, mode: 448 });
42364
+ const probe = path87.join(dir, ".doctor-probe");
42365
+ fs78.writeFileSync(probe, "ok", { mode: 384 });
42366
+ const read2 = fs78.readFileSync(probe, "utf8");
42367
+ fs78.unlinkSync(probe);
41692
42368
  if (read2 !== "ok") throw new Error("write/read round-trip mismatch");
41693
42369
  return {
41694
42370
  id: "config-dir",
@@ -41752,7 +42428,7 @@ function checkNodePty() {
41752
42428
  detail: "not required on this platform"
41753
42429
  };
41754
42430
  }
41755
- const vendoredPath = path85.join(__dirname, "vendor", "node-pty");
42431
+ const vendoredPath = path87.join(__dirname, "vendor", "node-pty");
41756
42432
  for (const target of [vendoredPath, "node-pty"]) {
41757
42433
  try {
41758
42434
  require(target);
@@ -41794,7 +42470,7 @@ function checkChokidar() {
41794
42470
  }
41795
42471
  async function doctor(args2 = []) {
41796
42472
  const json = args2.includes("--json");
41797
- const cliVersion = true ? "2.61.91" : "0.0.0-dev";
42473
+ const cliVersion = true ? "2.61.92" : "0.0.0-dev";
41798
42474
  const apiBase2 = resolveApiBaseUrl();
41799
42475
  const diagnosticId = (0, import_node_crypto13.randomUUID)();
41800
42476
  log.info("doctor", `run id=${diagnosticId} cli=${cliVersion}`);
@@ -41991,7 +42667,7 @@ async function completion(args2) {
41991
42667
  }
41992
42668
 
41993
42669
  // src/integrations/mcp-run.ts
41994
- var import_node_child_process32 = require("child_process");
42670
+ var import_node_child_process33 = require("child_process");
41995
42671
  var import_node_fs12 = require("fs");
41996
42672
  var import_node_os14 = __toESM(require("os"));
41997
42673
  var import_node_path12 = __toESM(require("path"));
@@ -42066,7 +42742,7 @@ function resolveDelivery(id) {
42066
42742
  function commandExists(command2) {
42067
42743
  try {
42068
42744
  const probe = process.platform === "win32" ? "where" : "which";
42069
- (0, import_node_child_process32.execFileSync)(probe, [command2], { stdio: "ignore" });
42745
+ (0, import_node_child_process33.execFileSync)(probe, [command2], { stdio: "ignore" });
42070
42746
  return true;
42071
42747
  } catch {
42072
42748
  return false;
@@ -42099,7 +42775,7 @@ function ensureCommand(command2) {
42099
42775
  }
42100
42776
  if (command2 === "uvx") {
42101
42777
  try {
42102
- (0, import_node_child_process32.execSync)("curl -LsSf https://astral.sh/uv/install.sh | sh", {
42778
+ (0, import_node_child_process33.execSync)("curl -LsSf https://astral.sh/uv/install.sh | sh", {
42103
42779
  stdio: ["ignore", process.stderr, process.stderr],
42104
42780
  timeout: 18e4,
42105
42781
  env: { ...process.env, UV_NO_MODIFY_PATH: "1" }
@@ -42108,7 +42784,7 @@ function ensureCommand(command2) {
42108
42784
  }
42109
42785
  if (resolveLauncherPath(command2) !== command2) return;
42110
42786
  try {
42111
- (0, import_node_child_process32.execSync)("python3 -m pip install --user --quiet uv", {
42787
+ (0, import_node_child_process33.execSync)("python3 -m pip install --user --quiet uv", {
42112
42788
  stdio: ["ignore", process.stderr, process.stderr],
42113
42789
  timeout: 18e4
42114
42790
  });
@@ -42185,7 +42861,7 @@ async function mcpRun(args2) {
42185
42861
  // src/commands/version.ts
42186
42862
  var import_picocolors15 = __toESM(require("picocolors"));
42187
42863
  function version2() {
42188
- const v = true ? "2.61.91" : "unknown";
42864
+ const v = true ? "2.61.92" : "unknown";
42189
42865
  console.log(`${import_picocolors15.default.bold("codeam-cli")} ${import_picocolors15.default.cyan(v)}`);
42190
42866
  }
42191
42867
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeam-cli",
3
- "version": "2.61.91",
3
+ "version": "2.61.92",
4
4
  "description": "Workflow-continuity bridge for AI coding agents. Wrap Claude Code or Codex in a PTY and supervise, approve, and redirect the session from any device — async. The terminal companion for CodeAgent Mobile.",
5
5
  "type": "commonjs",
6
6
  "main": "dist/index.js",