wildcrane-runner 0.6.18 → 0.6.19

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 +1 @@
1
- {"name":"wildcrane","version":"0.11.16","akbContract":5,"type":"module","private":true}
1
+ {"name":"wildcrane","version":"0.11.17","akbContract":5,"type":"module","private":true}
package/dist/launcher.mjs CHANGED
@@ -1,4 +1,4 @@
1
- // wildcrane-runner 0.6.18 — built by runner/scripts/build.mjs. Do not edit.
1
+ // wildcrane-runner 0.6.19 — built by runner/scripts/build.mjs. Do not edit.
2
2
  import { createRequire as __ai4kanbanRequire } from 'node:module'
3
3
  const require = __ai4kanbanRequire(import.meta.url)
4
4
 
@@ -108,7 +108,7 @@ function status(line) {
108
108
  }
109
109
 
110
110
  // src/protocol.ts
111
- var VERSION = true ? "0.6.18" : "0.0.0";
111
+ var VERSION = true ? "0.6.19" : "0.0.0";
112
112
  var EXIT_REFUSED = 10;
113
113
  var EXIT_OUTDATED = 11;
114
114
  var EXIT_UPDATE = 12;
@@ -2612,7 +2612,7 @@ function createTail(log) {
2612
2612
  // ../cli/package.json
2613
2613
  var package_default = {
2614
2614
  name: "wildcrane",
2615
- version: "0.11.16",
2615
+ version: "0.11.17",
2616
2616
  akbContract: 5,
2617
2617
  description: "WildCrane's `akb` command \u2014 scaffold the Markdown board under docs/kanban/, put an agent on a card, and carry the flows the agent works by.",
2618
2618
  keywords: [
@@ -3694,12 +3694,27 @@ function codexProxyEnv(env2 = process.env, platform = process.platform, read = (
3694
3694
  // ../cli/src/lib/agent/worktree.ts
3695
3695
  import { spawnSync as spawnSync3 } from "node:child_process";
3696
3696
  var MAX_OUTPUT = 64 * 1024 * 1024;
3697
+ var gitLimits = { timeoutMs: 3e4 };
3698
+ var GitTimeoutError = class extends Error {
3699
+ };
3700
+ function spawnGit(args, options) {
3701
+ const out = spawnSync3("git", args, {
3702
+ ...options,
3703
+ encoding: "utf8",
3704
+ stdio: ["ignore", "pipe", "pipe"],
3705
+ timeout: gitLimits.timeoutMs,
3706
+ killSignal: "SIGKILL"
3707
+ });
3708
+ if (out.error?.code === "ETIMEDOUT") throw new GitTimeoutError(`Git ${args[0]} timed out after ${gitLimits.timeoutMs / 1e3}s; the command was killed.`);
3709
+ return out;
3710
+ }
3697
3711
  function git(args, cwd = REPO_ROOT) {
3698
3712
  try {
3699
- const out = spawnSync3("git", args, { cwd, encoding: "utf8", maxBuffer: MAX_OUTPUT, windowsHide: true });
3713
+ const out = spawnGit(args, { cwd, encoding: "utf8", maxBuffer: MAX_OUTPUT, windowsHide: true });
3700
3714
  if (out.error || out.status !== 0) return null;
3701
3715
  return out.stdout;
3702
- } catch {
3716
+ } catch (error) {
3717
+ if (error instanceof GitTimeoutError) throw error;
3703
3718
  return null;
3704
3719
  }
3705
3720
  }
package/dist/runner.mjs CHANGED
@@ -1,4 +1,4 @@
1
- // wildcrane-runner 0.6.18 — built by runner/scripts/build.mjs. Do not edit.
1
+ // wildcrane-runner 0.6.19 — built by runner/scripts/build.mjs. Do not edit.
2
2
  import { createRequire as __ai4kanbanRequire } from 'node:module'
3
3
  const require = __ai4kanbanRequire(import.meta.url)
4
4
  var __create = Object.create;
@@ -84438,8 +84438,8 @@ function status(line) {
84438
84438
  }
84439
84439
 
84440
84440
  // src/protocol.ts
84441
- var VERSION = true ? "0.6.18" : "0.0.0";
84442
- var AKB_VERSION = true ? "0.11.16" : "0.0.0";
84441
+ var VERSION = true ? "0.6.19" : "0.0.0";
84442
+ var AKB_VERSION = true ? "0.11.17" : "0.0.0";
84443
84443
  var AKB_CONTRACT = true ? 5 : 0;
84444
84444
  var EXIT_REFUSED = 10;
84445
84445
  var EXIT_OUTDATED = 11;
@@ -85964,7 +85964,7 @@ function createTail(log) {
85964
85964
  // ../cli/package.json
85965
85965
  var package_default = {
85966
85966
  name: "wildcrane",
85967
- version: "0.11.16",
85967
+ version: "0.11.17",
85968
85968
  akbContract: 5,
85969
85969
  description: "WildCrane's `akb` command \u2014 scaffold the Markdown board under docs/kanban/, put an agent on a card, and carry the flows the agent works by.",
85970
85970
  keywords: [
@@ -87096,12 +87096,27 @@ function codexProxyEnv(env2 = process.env, platform = process.platform, read2 =
87096
87096
  // ../cli/src/lib/agent/worktree.ts
87097
87097
  import { spawnSync as spawnSync2 } from "node:child_process";
87098
87098
  var MAX_OUTPUT = 64 * 1024 * 1024;
87099
+ var gitLimits = { timeoutMs: 3e4 };
87100
+ var GitTimeoutError = class extends Error {
87101
+ };
87102
+ function spawnGit(args, options) {
87103
+ const out = spawnSync2("git", args, {
87104
+ ...options,
87105
+ encoding: "utf8",
87106
+ stdio: ["ignore", "pipe", "pipe"],
87107
+ timeout: gitLimits.timeoutMs,
87108
+ killSignal: "SIGKILL"
87109
+ });
87110
+ if (out.error?.code === "ETIMEDOUT") throw new GitTimeoutError(`Git ${args[0]} timed out after ${gitLimits.timeoutMs / 1e3}s; the command was killed.`);
87111
+ return out;
87112
+ }
87099
87113
  function git(args, cwd = REPO_ROOT) {
87100
87114
  try {
87101
- const out = spawnSync2("git", args, { cwd, encoding: "utf8", maxBuffer: MAX_OUTPUT, windowsHide: true });
87115
+ const out = spawnGit(args, { cwd, encoding: "utf8", maxBuffer: MAX_OUTPUT, windowsHide: true });
87102
87116
  if (out.error || out.status !== 0) return null;
87103
87117
  return out.stdout;
87104
- } catch {
87118
+ } catch (error) {
87119
+ if (error instanceof GitTimeoutError) throw error;
87105
87120
  return null;
87106
87121
  }
87107
87122
  }
@@ -92371,16 +92386,25 @@ function prepareKanbanSkill(root) {
92371
92386
  import { spawnSync as spawnSync6 } from "node:child_process";
92372
92387
  import fs28 from "node:fs";
92373
92388
  import path31 from "node:path";
92389
+
92390
+ // ../cli/src/lib/agent/landing-lock.ts
92391
+ var landingLimits = { staleMs: 5 * 6e4 };
92392
+
92393
+ // ../cli/src/lib/skill/hook.ts
92374
92394
  var MARKER = "# ai4kanban commit guard";
92375
92395
  var MARKER_LINE = new RegExp(`^${MARKER}\\b`, "m");
92376
92396
  var CHECK = [
92377
92397
  "try{",
92378
92398
  'const[top,branch]=require("child_process")',
92379
- '.execFileSync("git",["rev-parse","--show-toplevel","--abbrev-ref","HEAD"],{encoding:"utf8"}).trim().split("\\n");',
92399
+ '.execFileSync("git",["rev-parse","--show-toplevel","--abbrev-ref","HEAD"],{encoding:"utf8",timeout:3000,killSignal:"SIGKILL"}).trim().split("\\n");',
92380
92400
  'if(/\\/\\.akb\\/worktrees\\//.test(top+"/"))process.exit(0);',
92381
92401
  'const d=(JSON.parse(require("fs").readFileSync(process.argv[1],"utf8")).deliveries||[])',
92382
- '.find((x)=>x&&x.status==="active"&&x.commitMode==="auto"&&x.targetBranch===branch&&(!x.landing||x.landing.status!=="landed"));',
92402
+ '.find((x)=>x&&x.status==="active"&&x.commitMode==="auto"&&x.targetBranch===branch&&x.landing&&x.landing.status==="landing");',
92383
92403
  "if(!d)process.exit(0);",
92404
+ 'const fs=require("fs"),lock=process.argv[2],entries=fs.readdirSync(lock);',
92405
+ `if(Date.now()-fs.statSync(lock).mtimeMs>${landingLimits.staleMs})process.exit(0);`,
92406
+ "if(entries.length!==1||!/^\\d+-[a-f0-9-]{36}$/.test(entries[0]))process.exit(0);",
92407
+ 'try{process.kill(Number(entries[0].split("-")[0]),0)}catch(e){if(e.code!=="EPERM")process.exit(0)}',
92384
92408
  "process.stderr.write(",
92385
92409
  '"ai4kanban: delivery "+d.deliveryId+" is landing #"+d.cardId+" on "+branch+", so a commit here moves the target under it\\n"',
92386
92410
  '+" \u2014 commit on another branch, or `git commit --no-verify` to commit anyway.\\n");',
@@ -92388,7 +92412,7 @@ var CHECK = [
92388
92412
  "}catch(e){process.exit(0)}"
92389
92413
  ].join("");
92390
92414
  var quoted = (p2) => `"${p2.replace(/(["$`\\])/g, "\\$1")}"`;
92391
- var guardLine = (sessions) => `if command -v node >/dev/null 2>&1; then node -e '${CHECK}' ${quoted(sessions)} || exit 1; fi`;
92415
+ var guardLine = (sessions) => `if command -v node >/dev/null 2>&1; then node -e '${CHECK}' ${quoted(sessions)} ${quoted(path31.join(path31.dirname(sessions), SESSIONS_FOLDER, ".landing.lock"))} || exit 1; fi`;
92392
92416
  function hookScript(sessions) {
92393
92417
  return [
92394
92418
  "#!/bin/sh",
@@ -93083,18 +93107,31 @@ ${draftLine(ws)}
93083
93107
  }
93084
93108
  if (verb === "revise" && !text3) return fail("Say what to change.");
93085
93109
  let note = verb === "resolve" || verb === "revise" ? text3 : "";
93110
+ let continuation;
93111
+ let expectedDelivery;
93086
93112
  if (verb === "implement" && flow.resume) {
93087
- const resumed = answerOf2(await akb(["delivery", "resume", String(id2), "--json"]));
93113
+ const restored = await akb(["delivery", "resume", String(id2), "--json"]);
93114
+ const resumed = answerOf2(restored);
93088
93115
  if (io.lost()) return fail("");
93089
93116
  if (resumed?.landed) return { ok: true, report: { card: id2 } };
93117
+ if (restored.code !== 0 && resumed?.error?.reason !== "deliveryActive") return fail(resumed?.error?.message ?? refusal(restored));
93118
+ const deliveryId = resumed?.deliveryId ?? resumed?.error?.args?.id;
93119
+ if (!deliveryId) return fail("\u627E\u4E0D\u5230\u4E0A\u6B21\u6784\u5EFA\u7684\u4EA4\u4ED8\u8BB0\u5F55\uFF0C\u65E0\u6CD5\u6062\u590D\u539F\u5BF9\u8BDD\u3002");
93120
+ expectedDelivery = deliveryId;
93121
+ const previous = answerOf2(await akb(["run", "list", "--card", String(id2), "--all", "--json"]))?.runs?.filter((r2) => ["implement", "conflict", "hook"].includes(r2.action ?? "") && r2.deliveryId === deliveryId).sort((a3, b2) => (b2.startedAt ?? 0) - (a3.startedAt ?? 0))[0];
93122
+ if (!previous) return fail("\u627E\u4E0D\u5230\u4E0A\u6B21\u6784\u5EFA\u7684\u8FD0\u884C\u8BB0\u5F55\uFF0C\u65E0\u6CD5\u6062\u590D\u539F\u5BF9\u8BDD\u3002");
93123
+ continuation = previous.status === "done" ? ["run", "log", previous.sessionId] : ["run", "resume", previous.sessionId, "--require-session"];
93090
93124
  } else if (verb === "implement" && text3) {
93091
93125
  const resolved = await akb(["card", "resolve", String(id2), "--follow", "--events", "--json", "--", text3], true);
93092
93126
  if (io.lost()) return fail("");
93093
93127
  if (resolved.code !== 0) note = text3;
93094
93128
  }
93095
- const ran = await akb(["card", verb, String(id2), "--follow", "--events", "--json", ...carryArgs(verb), ...note ? ["--", note] : []], true);
93129
+ const ran = await akb(continuation ? [...continuation, "--follow", "--events", "--json"] : ["card", verb, String(id2), "--follow", "--events", "--json", ...carryArgs(verb), ...note ? ["--", note] : []], true);
93096
93130
  if (io.lost()) return fail("");
93097
93131
  const answer = answerOf2(ran);
93132
+ if (expectedDelivery && answer?.delivery?.id && answer.delivery.id !== expectedDelivery) {
93133
+ return fail("\u7EED\u8DD1\u8FD4\u56DE\u4E86\u5176\u4ED6\u4EA4\u4ED8\u7684\u7ED3\u679C\uFF0C\u539F\u4EA4\u4ED8\u4FDD\u6301\u672A\u5B8C\u6210\u3002");
93134
+ }
93098
93135
  if (verb === "implement") {
93099
93136
  const ending = deliveryEnding(ws, answer?.delivery?.id ?? answer?.error?.delivery?.id);
93100
93137
  if (ending) return ending;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wildcrane-runner",
3
- "version": "0.6.18",
3
+ "version": "0.6.19",
4
4
  "description": "WildCrane's Local Runner — connects this computer to WildCrane and runs its jobs on your local Claude Code, Codex, OpenCode or Cursor.",
5
5
  "license": "FSL-1.1-ALv2",
6
6
  "homepage": "https://wildcrane.ai/",