wildcrane-runner 0.6.16 → 0.6.18

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/runner.mjs CHANGED
@@ -1,4 +1,4 @@
1
- // wildcrane-runner 0.6.16 — built by runner/scripts/build.mjs. Do not edit.
1
+ // wildcrane-runner 0.6.18 — 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;
@@ -7517,7 +7517,7 @@ var require_react_dom_server_node_production = __commonJS({
7517
7517
  "node_modules/react-dom/cjs/react-dom-server.node.production.js"(exports) {
7518
7518
  "use strict";
7519
7519
  var util = __require("util");
7520
- var crypto7 = __require("crypto");
7520
+ var crypto8 = __require("crypto");
7521
7521
  var async_hooks = __require("async_hooks");
7522
7522
  var React4 = require_react();
7523
7523
  var ReactDOM = require_react_dom();
@@ -10382,7 +10382,7 @@ var require_react_dom_server_node_production = __commonJS({
10382
10382
  function createPostbackActionStateKey(permalink, componentKeyPath, hookIndex) {
10383
10383
  if (void 0 !== permalink) return "p" + permalink;
10384
10384
  permalink = JSON.stringify([componentKeyPath, null, hookIndex]);
10385
- componentKeyPath = crypto7.createHash("md5");
10385
+ componentKeyPath = crypto8.createHash("md5");
10386
10386
  componentKeyPath.update(permalink);
10387
10387
  return "k" + componentKeyPath.digest("hex");
10388
10388
  }
@@ -11493,8 +11493,8 @@ var require_react_dom_server_node_production = __commonJS({
11493
11493
  0
11494
11494
  );
11495
11495
  }
11496
- var autoName = JSCompiler_inline_result$jscomp$2, resumableState$jscomp$1 = request2.resumableState, update2 = getViewTransitionClassName(props.default, props.update), enter = getViewTransitionClassName(props.default, props.enter), exit = getViewTransitionClassName(props.default, props.exit), share = getViewTransitionClassName(props.default, props.share), name = props.name;
11497
- null == update2 && (update2 = "auto");
11496
+ var autoName = JSCompiler_inline_result$jscomp$2, resumableState$jscomp$1 = request2.resumableState, update3 = getViewTransitionClassName(props.default, props.update), enter = getViewTransitionClassName(props.default, props.enter), exit = getViewTransitionClassName(props.default, props.exit), share = getViewTransitionClassName(props.default, props.share), name = props.name;
11497
+ null == update3 && (update3 = "auto");
11498
11498
  null == enter && (enter = "auto");
11499
11499
  null == exit && (exit = "auto");
11500
11500
  if (null == name) {
@@ -11505,7 +11505,7 @@ var require_react_dom_server_node_production = __commonJS({
11505
11505
  prevContext$jscomp$0.tagScope & 8 ? resumableState$jscomp$1.instructions |= 128 : exit = "none";
11506
11506
  prevContext$jscomp$0.tagScope & 16 ? resumableState$jscomp$1.instructions |= 128 : enter = "none";
11507
11507
  var viewTransition = {
11508
- update: update2,
11508
+ update: update3,
11509
11509
  enter,
11510
11510
  exit,
11511
11511
  share,
@@ -11515,7 +11515,7 @@ var require_react_dom_server_node_production = __commonJS({
11515
11515
  autoName,
11516
11516
  nameIdx: 0
11517
11517
  }, subtreeScope = prevContext$jscomp$0.tagScope & -25;
11518
- subtreeScope = "none" !== update2 ? subtreeScope | 32 : subtreeScope & -33;
11518
+ subtreeScope = "none" !== update3 ? subtreeScope | 32 : subtreeScope & -33;
11519
11519
  "none" !== enter && (subtreeScope |= 64);
11520
11520
  var JSCompiler_inline_result$jscomp$3 = createFormatContext(
11521
11521
  prevContext$jscomp$0.insertionMode,
@@ -13136,15 +13136,15 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
13136
13136
  request2 = request2.renderLifetimeController;
13137
13137
  null !== request2 && request2.abort("The render ended.");
13138
13138
  }
13139
- function attachAbortSignal(request2, signal) {
13140
- if (signal.aborted) abort(request2, signal.reason);
13139
+ function attachAbortSignal(request2, signal2) {
13140
+ if (signal2.aborted) abort(request2, signal2.reason);
13141
13141
  else {
13142
13142
  var renderLifetimeController = new AbortController();
13143
13143
  request2.renderLifetimeController = renderLifetimeController;
13144
- signal.addEventListener(
13144
+ signal2.addEventListener(
13145
13145
  "abort",
13146
13146
  function() {
13147
- abort(request2, signal.reason);
13147
+ abort(request2, signal2.reason);
13148
13148
  },
13149
13149
  { signal: renderLifetimeController.signal }
13150
13150
  );
@@ -24376,7 +24376,7 @@ var require_react_dom_server_node_development = __commonJS({
24376
24376
  function createPostbackActionStateKey(permalink, componentKeyPath, hookIndex) {
24377
24377
  if (void 0 !== permalink) return "p" + permalink;
24378
24378
  permalink = JSON.stringify([componentKeyPath, null, hookIndex]);
24379
- componentKeyPath = crypto7.createHash("md5");
24379
+ componentKeyPath = crypto8.createHash("md5");
24380
24380
  componentKeyPath.update(permalink);
24381
24381
  return "k" + componentKeyPath.digest("hex");
24382
24382
  }
@@ -25837,8 +25837,8 @@ var require_react_dom_server_node_development = __commonJS({
25837
25837
  var treeId = getTreeId(task.treeContext);
25838
25838
  autoName = makeId(resumableState$jscomp$0, treeId, 0);
25839
25839
  }
25840
- var resumableState$jscomp$1 = request2.resumableState, update2 = getViewTransitionClassName(props.default, props.update), enter = getViewTransitionClassName(props.default, props.enter), exit = getViewTransitionClassName(props.default, props.exit), share = getViewTransitionClassName(props.default, props.share), name$jscomp$0 = props.name, autoName$jscomp$0 = autoName;
25841
- null == update2 && (update2 = "auto");
25840
+ var resumableState$jscomp$1 = request2.resumableState, update3 = getViewTransitionClassName(props.default, props.update), enter = getViewTransitionClassName(props.default, props.enter), exit = getViewTransitionClassName(props.default, props.exit), share = getViewTransitionClassName(props.default, props.share), name$jscomp$0 = props.name, autoName$jscomp$0 = autoName;
25841
+ null == update3 && (update3 = "auto");
25842
25842
  null == enter && (enter = "auto");
25843
25843
  null == exit && (exit = "auto");
25844
25844
  if (null == name$jscomp$0) {
@@ -25849,7 +25849,7 @@ var require_react_dom_server_node_development = __commonJS({
25849
25849
  prevContext$jscomp$0.tagScope & 8 ? resumableState$jscomp$1.instructions |= NeedUpgradeToViewTransitions : exit = "none";
25850
25850
  prevContext$jscomp$0.tagScope & 16 ? resumableState$jscomp$1.instructions |= NeedUpgradeToViewTransitions : enter = "none";
25851
25851
  var viewTransition = {
25852
- update: update2,
25852
+ update: update3,
25853
25853
  enter,
25854
25854
  exit,
25855
25855
  share,
@@ -25859,7 +25859,7 @@ var require_react_dom_server_node_development = __commonJS({
25859
25859
  autoName: autoName$jscomp$0,
25860
25860
  nameIdx: 0
25861
25861
  }, subtreeScope = prevContext$jscomp$0.tagScope & -25;
25862
- subtreeScope = "none" !== update2 ? subtreeScope | 32 : subtreeScope & -33;
25862
+ subtreeScope = "none" !== update3 ? subtreeScope | 32 : subtreeScope & -33;
25863
25863
  "none" !== enter && (subtreeScope |= 64);
25864
25864
  var JSCompiler_inline_result$jscomp$0 = createFormatContext(
25865
25865
  prevContext$jscomp$0.insertionMode,
@@ -27848,15 +27848,15 @@ var require_react_dom_server_node_development = __commonJS({
27848
27848
  request2 = request2.renderLifetimeController;
27849
27849
  null !== request2 && request2.abort(RENDER_ENDED);
27850
27850
  }
27851
- function attachAbortSignal(request2, signal) {
27852
- if (signal.aborted) abort(request2, signal.reason);
27851
+ function attachAbortSignal(request2, signal2) {
27852
+ if (signal2.aborted) abort(request2, signal2.reason);
27853
27853
  else {
27854
27854
  var renderLifetimeController = new AbortController();
27855
27855
  request2.renderLifetimeController = renderLifetimeController;
27856
- signal.addEventListener(
27856
+ signal2.addEventListener(
27857
27857
  "abort",
27858
27858
  function() {
27859
- abort(request2, signal.reason);
27859
+ abort(request2, signal2.reason);
27860
27860
  },
27861
27861
  { signal: renderLifetimeController.signal }
27862
27862
  );
@@ -28038,7 +28038,7 @@ var require_react_dom_server_node_development = __commonJS({
28038
28038
  }
28039
28039
  };
28040
28040
  }
28041
- var util = __require("util"), crypto7 = __require("crypto"), async_hooks = __require("async_hooks"), React4 = require_react(), ReactDOM = require_react_dom(), stream = __require("stream"), REACT_ELEMENT_TYPE = /* @__PURE__ */ Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = /* @__PURE__ */ Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = /* @__PURE__ */ Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = /* @__PURE__ */ Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = /* @__PURE__ */ Symbol.for("react.profiler"), REACT_CONSUMER_TYPE = /* @__PURE__ */ Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = /* @__PURE__ */ Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = /* @__PURE__ */ Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = /* @__PURE__ */ Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = /* @__PURE__ */ Symbol.for("react.suspense_list"), REACT_MEMO_TYPE = /* @__PURE__ */ Symbol.for("react.memo"), REACT_LAZY_TYPE = /* @__PURE__ */ Symbol.for("react.lazy"), REACT_SCOPE_TYPE = /* @__PURE__ */ Symbol.for("react.scope"), REACT_ACTIVITY_TYPE = /* @__PURE__ */ Symbol.for("react.activity"), REACT_LEGACY_HIDDEN_TYPE = /* @__PURE__ */ Symbol.for("react.legacy_hidden"), REACT_MEMO_CACHE_SENTINEL = /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel"), REACT_VIEW_TRANSITION_TYPE = /* @__PURE__ */ Symbol.for("react.view_transition"), REACT_RECOVERABLE_TYPE = /* @__PURE__ */ Symbol.for("react.recoverable"), MAYBE_ITERATOR_SYMBOL = Symbol.iterator, ASYNC_ITERATOR = Symbol.asyncIterator, REACT_OPTIMISTIC_KEY = /* @__PURE__ */ Symbol.for("react.optimistic_key"), isArrayImpl = Array.isArray, jsxPropsParents = /* @__PURE__ */ new WeakMap(), jsxChildrenParents = /* @__PURE__ */ new WeakMap(), CLIENT_REFERENCE_TAG = /* @__PURE__ */ Symbol.for("react.client.reference"), hasOwnProperty = Object.prototype.hasOwnProperty, supportsArrayBufferDetached = hasOwnProperty.call(
28041
+ var util = __require("util"), crypto8 = __require("crypto"), async_hooks = __require("async_hooks"), React4 = require_react(), ReactDOM = require_react_dom(), stream = __require("stream"), REACT_ELEMENT_TYPE = /* @__PURE__ */ Symbol.for("react.transitional.element"), REACT_PORTAL_TYPE = /* @__PURE__ */ Symbol.for("react.portal"), REACT_FRAGMENT_TYPE = /* @__PURE__ */ Symbol.for("react.fragment"), REACT_STRICT_MODE_TYPE = /* @__PURE__ */ Symbol.for("react.strict_mode"), REACT_PROFILER_TYPE = /* @__PURE__ */ Symbol.for("react.profiler"), REACT_CONSUMER_TYPE = /* @__PURE__ */ Symbol.for("react.consumer"), REACT_CONTEXT_TYPE = /* @__PURE__ */ Symbol.for("react.context"), REACT_FORWARD_REF_TYPE = /* @__PURE__ */ Symbol.for("react.forward_ref"), REACT_SUSPENSE_TYPE = /* @__PURE__ */ Symbol.for("react.suspense"), REACT_SUSPENSE_LIST_TYPE = /* @__PURE__ */ Symbol.for("react.suspense_list"), REACT_MEMO_TYPE = /* @__PURE__ */ Symbol.for("react.memo"), REACT_LAZY_TYPE = /* @__PURE__ */ Symbol.for("react.lazy"), REACT_SCOPE_TYPE = /* @__PURE__ */ Symbol.for("react.scope"), REACT_ACTIVITY_TYPE = /* @__PURE__ */ Symbol.for("react.activity"), REACT_LEGACY_HIDDEN_TYPE = /* @__PURE__ */ Symbol.for("react.legacy_hidden"), REACT_MEMO_CACHE_SENTINEL = /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel"), REACT_VIEW_TRANSITION_TYPE = /* @__PURE__ */ Symbol.for("react.view_transition"), REACT_RECOVERABLE_TYPE = /* @__PURE__ */ Symbol.for("react.recoverable"), MAYBE_ITERATOR_SYMBOL = Symbol.iterator, ASYNC_ITERATOR = Symbol.asyncIterator, REACT_OPTIMISTIC_KEY = /* @__PURE__ */ Symbol.for("react.optimistic_key"), isArrayImpl = Array.isArray, jsxPropsParents = /* @__PURE__ */ new WeakMap(), jsxChildrenParents = /* @__PURE__ */ new WeakMap(), CLIENT_REFERENCE_TAG = /* @__PURE__ */ Symbol.for("react.client.reference"), hasOwnProperty = Object.prototype.hasOwnProperty, supportsArrayBufferDetached = hasOwnProperty.call(
28042
28042
  ArrayBuffer.prototype,
28043
28043
  "detached"
28044
28044
  ), didWarnAboutMissingArrayBufferDetached = false, scheduleMicrotask = queueMicrotask, currentView = null, writtenBytes = 0, destinationHasCapacity$1 = true, textEncoder = new util.TextEncoder(), assign = Object.assign, VALID_ATTRIBUTE_NAME_REGEX = RegExp(
@@ -41256,8 +41256,8 @@ var require_JSXTransformer = __commonJS({
41256
41256
  }
41257
41257
  if (this.isAutomaticRuntime) {
41258
41258
  if (this.importProcessor) {
41259
- for (const [path37, resolvedName] of Object.entries(this.cjsAutomaticModuleNameResolutions)) {
41260
- prefix += `var ${resolvedName} = require("${path37}");`;
41259
+ for (const [path40, resolvedName] of Object.entries(this.cjsAutomaticModuleNameResolutions)) {
41260
+ prefix += `var ${resolvedName} = require("${path40}");`;
41261
41261
  }
41262
41262
  } else {
41263
41263
  const { createElement: createElementResolution, ...otherResolutions } = this.esmAutomaticImportNameResolutions;
@@ -41450,11 +41450,11 @@ var require_JSXTransformer = __commonJS({
41450
41450
  }
41451
41451
  claimAutoImportedName(funcName, importPathSuffix) {
41452
41452
  if (this.importProcessor) {
41453
- const path37 = this.jsxImportSource + importPathSuffix;
41454
- if (!this.cjsAutomaticModuleNameResolutions[path37]) {
41455
- this.cjsAutomaticModuleNameResolutions[path37] = this.importProcessor.getFreeIdentifierForPath(path37);
41453
+ const path40 = this.jsxImportSource + importPathSuffix;
41454
+ if (!this.cjsAutomaticModuleNameResolutions[path40]) {
41455
+ this.cjsAutomaticModuleNameResolutions[path40] = this.importProcessor.getFreeIdentifierForPath(path40);
41456
41456
  }
41457
- return `${this.cjsAutomaticModuleNameResolutions[path37]}.${funcName}`;
41457
+ return `${this.cjsAutomaticModuleNameResolutions[path40]}.${funcName}`;
41458
41458
  } else {
41459
41459
  if (!this.esmAutomaticImportNameResolutions[funcName]) {
41460
41460
  this.esmAutomaticImportNameResolutions[funcName] = this.nameManager.claimFreeName(
@@ -41890,7 +41890,7 @@ var require_CJSImportProcessor = __commonJS({
41890
41890
  */
41891
41891
  pruneTypeOnlyImports() {
41892
41892
  this.nonTypeIdentifiers = _getNonTypeIdentifiers.getNonTypeIdentifiers.call(void 0, this.tokens, this.options);
41893
- for (const [path37, importInfo] of this.importInfoByPath.entries()) {
41893
+ for (const [path40, importInfo] of this.importInfoByPath.entries()) {
41894
41894
  if (importInfo.hasBareImport || importInfo.hasStarExport || importInfo.exportStarNames.length > 0 || importInfo.namedExports.length > 0) {
41895
41895
  continue;
41896
41896
  }
@@ -41900,7 +41900,7 @@ var require_CJSImportProcessor = __commonJS({
41900
41900
  ...importInfo.namedImports.map(({ localName }) => localName)
41901
41901
  ];
41902
41902
  if (names2.every((name) => this.shouldAutomaticallyElideImportedName(name))) {
41903
- this.importsToReplace.set(path37, "");
41903
+ this.importsToReplace.set(path40, "");
41904
41904
  }
41905
41905
  }
41906
41906
  }
@@ -41908,7 +41908,7 @@ var require_CJSImportProcessor = __commonJS({
41908
41908
  return this.isTypeScriptTransformEnabled && !this.keepUnusedImports && !this.nonTypeIdentifiers.has(name);
41909
41909
  }
41910
41910
  generateImportReplacements() {
41911
- for (const [path37, importInfo] of this.importInfoByPath.entries()) {
41911
+ for (const [path40, importInfo] of this.importInfoByPath.entries()) {
41912
41912
  const {
41913
41913
  defaultNames,
41914
41914
  wildcardNames,
@@ -41918,17 +41918,17 @@ var require_CJSImportProcessor = __commonJS({
41918
41918
  hasStarExport
41919
41919
  } = importInfo;
41920
41920
  if (defaultNames.length === 0 && wildcardNames.length === 0 && namedImports.length === 0 && namedExports.length === 0 && exportStarNames.length === 0 && !hasStarExport) {
41921
- this.importsToReplace.set(path37, `require('${path37}');`);
41921
+ this.importsToReplace.set(path40, `require('${path40}');`);
41922
41922
  continue;
41923
41923
  }
41924
- const primaryImportName = this.getFreeIdentifierForPath(path37);
41924
+ const primaryImportName = this.getFreeIdentifierForPath(path40);
41925
41925
  let secondaryImportName;
41926
41926
  if (this.enableLegacyTypeScriptModuleInterop) {
41927
41927
  secondaryImportName = primaryImportName;
41928
41928
  } else {
41929
- secondaryImportName = wildcardNames.length > 0 ? wildcardNames[0] : this.getFreeIdentifierForPath(path37);
41929
+ secondaryImportName = wildcardNames.length > 0 ? wildcardNames[0] : this.getFreeIdentifierForPath(path40);
41930
41930
  }
41931
- let requireCode = `var ${primaryImportName} = require('${path37}');`;
41931
+ let requireCode = `var ${primaryImportName} = require('${path40}');`;
41932
41932
  if (wildcardNames.length > 0) {
41933
41933
  for (const wildcardName of wildcardNames) {
41934
41934
  const moduleExpr = this.enableLegacyTypeScriptModuleInterop ? primaryImportName : `${this.helperManager.getHelperName("interopRequireWildcard")}(${primaryImportName})`;
@@ -41956,7 +41956,7 @@ var require_CJSImportProcessor = __commonJS({
41956
41956
  "createStarExport"
41957
41957
  )}(${primaryImportName});`;
41958
41958
  }
41959
- this.importsToReplace.set(path37, requireCode);
41959
+ this.importsToReplace.set(path40, requireCode);
41960
41960
  for (const defaultName of defaultNames) {
41961
41961
  this.identifierReplacements.set(defaultName, `${secondaryImportName}.default`);
41962
41962
  }
@@ -41965,8 +41965,8 @@ var require_CJSImportProcessor = __commonJS({
41965
41965
  }
41966
41966
  }
41967
41967
  }
41968
- getFreeIdentifierForPath(path37) {
41969
- const components = path37.split("/");
41968
+ getFreeIdentifierForPath(path40) {
41969
+ const components = path40.split("/");
41970
41970
  const lastComponent = components[components.length - 1];
41971
41971
  const baseName = lastComponent.replace(/\W/g, "");
41972
41972
  return this.nameManager.claimFreeName(`_${baseName}`);
@@ -42011,8 +42011,8 @@ var require_CJSImportProcessor = __commonJS({
42011
42011
  if (!this.tokens.matches1AtIndex(index, _types.TokenType.string)) {
42012
42012
  throw new Error("Expected string token at the end of import statement.");
42013
42013
  }
42014
- const path37 = this.tokens.stringValueAtIndex(index);
42015
- const importInfo = this.getImportInfo(path37);
42014
+ const path40 = this.tokens.stringValueAtIndex(index);
42015
+ const importInfo = this.getImportInfo(path40);
42016
42016
  importInfo.defaultNames.push(...defaultNames);
42017
42017
  importInfo.wildcardNames.push(...wildcardNames);
42018
42018
  importInfo.namedImports.push(...namedImports);
@@ -42079,8 +42079,8 @@ var require_CJSImportProcessor = __commonJS({
42079
42079
  if (!this.tokens.matches1AtIndex(index, _types.TokenType.string)) {
42080
42080
  throw new Error("Expected string token at the end of import statement.");
42081
42081
  }
42082
- const path37 = this.tokens.stringValueAtIndex(index);
42083
- const importInfo = this.getImportInfo(path37);
42082
+ const path40 = this.tokens.stringValueAtIndex(index);
42083
+ const importInfo = this.getImportInfo(path40);
42084
42084
  importInfo.namedExports.push(...namedImports);
42085
42085
  }
42086
42086
  preprocessExportStarAtIndex(index) {
@@ -42095,8 +42095,8 @@ var require_CJSImportProcessor = __commonJS({
42095
42095
  if (!this.tokens.matches1AtIndex(index, _types.TokenType.string)) {
42096
42096
  throw new Error("Expected string token at the end of star export statement.");
42097
42097
  }
42098
- const path37 = this.tokens.stringValueAtIndex(index);
42099
- const importInfo = this.getImportInfo(path37);
42098
+ const path40 = this.tokens.stringValueAtIndex(index);
42099
+ const importInfo = this.getImportInfo(path40);
42100
42100
  if (exportedName !== null) {
42101
42101
  importInfo.exportStarNames.push(exportedName);
42102
42102
  } else {
@@ -42136,8 +42136,8 @@ var require_CJSImportProcessor = __commonJS({
42136
42136
  * Get a mutable import info object for this path, creating one if it doesn't
42137
42137
  * exist yet.
42138
42138
  */
42139
- getImportInfo(path37) {
42140
- const existingInfo = this.importInfoByPath.get(path37);
42139
+ getImportInfo(path40) {
42140
+ const existingInfo = this.importInfoByPath.get(path40);
42141
42141
  if (existingInfo) {
42142
42142
  return existingInfo;
42143
42143
  }
@@ -42150,7 +42150,7 @@ var require_CJSImportProcessor = __commonJS({
42150
42150
  exportStarNames: [],
42151
42151
  hasStarExport: false
42152
42152
  };
42153
- this.importInfoByPath.set(path37, newInfo);
42153
+ this.importInfoByPath.set(path40, newInfo);
42154
42154
  return newInfo;
42155
42155
  }
42156
42156
  addExportBinding(localName, exportedName) {
@@ -42730,16 +42730,16 @@ var require_resolve_uri_umd = __commonJS({
42730
42730
  }
42731
42731
  function parseFileUrl(input) {
42732
42732
  const match = fileRegex.exec(input);
42733
- const path37 = match[2];
42734
- return makeUrl("file:", "", match[1] || "", "", isAbsolutePath(path37) ? path37 : "/" + path37, match[3] || "", match[4] || "");
42733
+ const path40 = match[2];
42734
+ return makeUrl("file:", "", match[1] || "", "", isAbsolutePath(path40) ? path40 : "/" + path40, match[3] || "", match[4] || "");
42735
42735
  }
42736
- function makeUrl(scheme, user, host, port, path37, query, hash) {
42736
+ function makeUrl(scheme, user, host, port, path40, query, hash) {
42737
42737
  return {
42738
42738
  scheme,
42739
42739
  user,
42740
42740
  host,
42741
42741
  port,
42742
- path: path37,
42742
+ path: path40,
42743
42743
  query,
42744
42744
  hash,
42745
42745
  type: 7
@@ -42769,11 +42769,11 @@ var require_resolve_uri_umd = __commonJS({
42769
42769
  url.type = input ? input.startsWith("?") ? 3 : input.startsWith("#") ? 2 : 4 : 1;
42770
42770
  return url;
42771
42771
  }
42772
- function stripPathFilename(path37) {
42773
- if (path37.endsWith("/.."))
42774
- return path37;
42775
- const index = path37.lastIndexOf("/");
42776
- return path37.slice(0, index + 1);
42772
+ function stripPathFilename(path40) {
42773
+ if (path40.endsWith("/.."))
42774
+ return path40;
42775
+ const index = path40.lastIndexOf("/");
42776
+ return path40.slice(0, index + 1);
42777
42777
  }
42778
42778
  function mergePaths(url, base) {
42779
42779
  normalizePath(base, base.type);
@@ -42811,14 +42811,14 @@ var require_resolve_uri_umd = __commonJS({
42811
42811
  pieces[pointer++] = piece;
42812
42812
  positive++;
42813
42813
  }
42814
- let path37 = "";
42814
+ let path40 = "";
42815
42815
  for (let i = 1; i < pointer; i++) {
42816
- path37 += "/" + pieces[i];
42816
+ path40 += "/" + pieces[i];
42817
42817
  }
42818
- if (!path37 || addTrailingSlash && !path37.endsWith("/..")) {
42819
- path37 += "/";
42818
+ if (!path40 || addTrailingSlash && !path40.endsWith("/..")) {
42819
+ path40 += "/";
42820
42820
  }
42821
- url.path = path37;
42821
+ url.path = path40;
42822
42822
  }
42823
42823
  function resolve2(input, base) {
42824
42824
  if (!input && !base)
@@ -42859,13 +42859,13 @@ var require_resolve_uri_umd = __commonJS({
42859
42859
  case 3:
42860
42860
  return queryHash;
42861
42861
  case 4: {
42862
- const path37 = url.path.slice(1);
42863
- if (!path37)
42862
+ const path40 = url.path.slice(1);
42863
+ if (!path40)
42864
42864
  return queryHash || ".";
42865
- if (isRelative(base || input) && !isRelative(path37)) {
42866
- return "./" + path37 + queryHash;
42865
+ if (isRelative(base || input) && !isRelative(path40)) {
42866
+ return "./" + path40 + queryHash;
42867
42867
  }
42868
- return path37 + queryHash;
42868
+ return path40 + queryHash;
42869
42869
  }
42870
42870
  case 5:
42871
42871
  return url.path + queryHash;
@@ -42964,10 +42964,10 @@ var require_trace_mapping_umd = __commonJS({
42964
42964
  module2.exports = __toCommonJS(trace_mapping_exports);
42965
42965
  var import_sourcemap_codec = __toESM2(require_sourcemap_codec());
42966
42966
  var import_resolve_uri = __toESM2(require_resolve_uri());
42967
- function stripFilename(path37) {
42968
- if (!path37) return "";
42969
- const index = path37.lastIndexOf("/");
42970
- return path37.slice(0, index + 1);
42967
+ function stripFilename(path40) {
42968
+ if (!path40) return "";
42969
+ const index = path40.lastIndexOf("/");
42970
+ return path40.slice(0, index + 1);
42971
42971
  }
42972
42972
  function resolver(mapUrl, sourceRoot) {
42973
42973
  const from = stripFilename(mapUrl);
@@ -44175,9 +44175,9 @@ var require_util2 = __commonJS({
44175
44175
  /** @class */
44176
44176
  (function(_super) {
44177
44177
  __extends(VError2, _super);
44178
- function VError2(path37, message) {
44178
+ function VError2(path40, message) {
44179
44179
  var _this = _super.call(this, message) || this;
44180
- _this.path = path37;
44180
+ _this.path = path40;
44181
44181
  Object.setPrototypeOf(_this, VError2.prototype);
44182
44182
  return _this;
44183
44183
  }
@@ -44237,26 +44237,26 @@ var require_util2 = __commonJS({
44237
44237
  (_b = this._messages).push.apply(_b, best._messages);
44238
44238
  }
44239
44239
  };
44240
- DetailContext2.prototype.getError = function(path37) {
44240
+ DetailContext2.prototype.getError = function(path40) {
44241
44241
  var msgParts = [];
44242
44242
  for (var i = this._propNames.length - 1; i >= 0; i--) {
44243
44243
  var p2 = this._propNames[i];
44244
- path37 += typeof p2 === "number" ? "[" + p2 + "]" : p2 ? "." + p2 : "";
44244
+ path40 += typeof p2 === "number" ? "[" + p2 + "]" : p2 ? "." + p2 : "";
44245
44245
  var m = this._messages[i];
44246
44246
  if (m) {
44247
- msgParts.push(path37 + " " + m);
44247
+ msgParts.push(path40 + " " + m);
44248
44248
  }
44249
44249
  }
44250
- return new VError(path37, msgParts.join("; "));
44250
+ return new VError(path40, msgParts.join("; "));
44251
44251
  };
44252
- DetailContext2.prototype.getErrorDetail = function(path37) {
44252
+ DetailContext2.prototype.getErrorDetail = function(path40) {
44253
44253
  var details = [];
44254
44254
  for (var i = this._propNames.length - 1; i >= 0; i--) {
44255
44255
  var p2 = this._propNames[i];
44256
- path37 += typeof p2 === "number" ? "[" + p2 + "]" : p2 ? "." + p2 : "";
44256
+ path40 += typeof p2 === "number" ? "[" + p2 + "]" : p2 ? "." + p2 : "";
44257
44257
  var message = this._messages[i];
44258
44258
  if (message) {
44259
- details.push({ path: path37, message });
44259
+ details.push({ path: path40, message });
44260
44260
  }
44261
44261
  }
44262
44262
  var detail = null;
@@ -45069,8 +45069,8 @@ var require_dist = __commonJS({
45069
45069
  this.checkerPlain = this.ttype.getChecker(suite, false);
45070
45070
  this.checkerStrict = this.ttype.getChecker(suite, true);
45071
45071
  }
45072
- Checker2.prototype.setReportedPath = function(path37) {
45073
- this._path = path37;
45072
+ Checker2.prototype.setReportedPath = function(path40) {
45073
+ this._path = path40;
45074
45074
  };
45075
45075
  Checker2.prototype.check = function(value) {
45076
45076
  return this._doCheck(this.checkerPlain, value);
@@ -50503,9 +50503,9 @@ var require_CJSImportTransformer = __commonJS({
50503
50503
  if (shouldElideImport) {
50504
50504
  this.tokens.removeToken();
50505
50505
  } else {
50506
- const path37 = this.tokens.stringValue();
50507
- this.tokens.replaceTokenTrimmingLeftWhitespace(this.importProcessor.claimImportCode(path37));
50508
- this.tokens.appendCode(this.importProcessor.claimImportCode(path37));
50506
+ const path40 = this.tokens.stringValue();
50507
+ this.tokens.replaceTokenTrimmingLeftWhitespace(this.importProcessor.claimImportCode(path40));
50508
+ this.tokens.appendCode(this.importProcessor.claimImportCode(path40));
50509
50509
  }
50510
50510
  _removeMaybeImportAttributes.removeMaybeImportAttributes.call(void 0, this.tokens);
50511
50511
  if (this.tokens.matches1(_types.TokenType.semi)) {
@@ -51085,8 +51085,8 @@ var require_CJSImportTransformer = __commonJS({
51085
51085
  }
51086
51086
  if (this.tokens.matchesContextual(_keywords.ContextualKeyword._from)) {
51087
51087
  this.tokens.removeToken();
51088
- const path37 = this.tokens.stringValue();
51089
- this.tokens.replaceTokenTrimmingLeftWhitespace(this.importProcessor.claimImportCode(path37));
51088
+ const path40 = this.tokens.stringValue();
51089
+ this.tokens.replaceTokenTrimmingLeftWhitespace(this.importProcessor.claimImportCode(path40));
51090
51090
  _removeMaybeImportAttributes.removeMaybeImportAttributes.call(void 0, this.tokens);
51091
51091
  } else {
51092
51092
  this.tokens.appendCode(exportStatements.join(" "));
@@ -51100,8 +51100,8 @@ var require_CJSImportTransformer = __commonJS({
51100
51100
  while (!this.tokens.matches1(_types.TokenType.string)) {
51101
51101
  this.tokens.removeToken();
51102
51102
  }
51103
- const path37 = this.tokens.stringValue();
51104
- this.tokens.replaceTokenTrimmingLeftWhitespace(this.importProcessor.claimImportCode(path37));
51103
+ const path40 = this.tokens.stringValue();
51104
+ this.tokens.replaceTokenTrimmingLeftWhitespace(this.importProcessor.claimImportCode(path40));
51105
51105
  _removeMaybeImportAttributes.removeMaybeImportAttributes.call(void 0, this.tokens);
51106
51106
  if (this.tokens.matches1(_types.TokenType.semi)) {
51107
51107
  this.tokens.removeToken();
@@ -80745,9 +80745,9 @@ var init_bundle_mjs = __esm({
80745
80745
  processClassesRecursively(value, getPart(classPartObject, key), classGroupId, theme);
80746
80746
  }
80747
80747
  };
80748
- getPart = (classPartObject, path37) => {
80748
+ getPart = (classPartObject, path40) => {
80749
80749
  let current = classPartObject;
80750
- const parts = path37.split(CLASS_PART_SEPARATOR);
80750
+ const parts = path40.split(CLASS_PART_SEPARATOR);
80751
80751
  const len = parts.length;
80752
80752
  for (let i = 0; i < len; i++) {
80753
80753
  const part = parts[i];
@@ -80772,7 +80772,7 @@ var init_bundle_mjs = __esm({
80772
80772
  let cacheSize = 0;
80773
80773
  let cache = /* @__PURE__ */ Object.create(null);
80774
80774
  let previousCache = /* @__PURE__ */ Object.create(null);
80775
- const update2 = (key, value) => {
80775
+ const update3 = (key, value) => {
80776
80776
  cache[key] = value;
80777
80777
  cacheSize++;
80778
80778
  if (cacheSize > maxCacheSize) {
@@ -80788,7 +80788,7 @@ var init_bundle_mjs = __esm({
80788
80788
  return value;
80789
80789
  }
80790
80790
  if ((value = previousCache[key]) !== void 0) {
80791
- update2(key, value);
80791
+ update3(key, value);
80792
80792
  return value;
80793
80793
  }
80794
80794
  },
@@ -80796,7 +80796,7 @@ var init_bundle_mjs = __esm({
80796
80796
  if (key in cache) {
80797
80797
  cache[key] = value;
80798
80798
  } else {
80799
- update2(key, value);
80799
+ update3(key, value);
80800
80800
  }
80801
80801
  }
80802
80802
  };
@@ -84001,8 +84001,8 @@ var mockup_exports = {};
84001
84001
  __export(mockup_exports, {
84002
84002
  drawMockup: () => drawMockup
84003
84003
  });
84004
- import fs20 from "node:fs";
84005
- import path23 from "node:path";
84004
+ import fs21 from "node:fs";
84005
+ import path25 from "node:path";
84006
84006
  import vm from "node:vm";
84007
84007
  async function loadPackage(id) {
84008
84008
  if (id === "react") return import_react3.default;
@@ -84015,20 +84015,20 @@ async function loadPackage(id) {
84015
84015
  return { __esModule: true, ...await load() };
84016
84016
  }
84017
84017
  function resolveFile(id, from, folder) {
84018
- const at2 = path23.resolve(path23.dirname(from), id);
84019
- if (at2 !== folder && !at2.startsWith(folder + path23.sep)) throw new Error(`${id} is outside the mockup's folder`);
84020
- const tries = path23.extname(at2) ? [at2] : [...CODE_EXTS.map((e2) => at2 + e2), ...CODE_EXTS.map((e2) => path23.join(at2, `index${e2}`))];
84021
- const file2 = tries.find((f2) => fs20.statSync(f2, { throwIfNoEntry: false })?.isFile());
84018
+ const at2 = path25.resolve(path25.dirname(from), id);
84019
+ if (at2 !== folder && !at2.startsWith(folder + path25.sep)) throw new Error(`${id} is outside the mockup's folder`);
84020
+ const tries = path25.extname(at2) ? [at2] : [...CODE_EXTS.map((e2) => at2 + e2), ...CODE_EXTS.map((e2) => path25.join(at2, `index${e2}`))];
84021
+ const file2 = tries.find((f2) => fs21.statSync(f2, { throwIfNoEntry: false })?.isFile());
84022
84022
  if (!file2) throw new Error(`no such file: ${id}`);
84023
84023
  return file2;
84024
84024
  }
84025
84025
  async function readGraph(entry) {
84026
- const folder = path23.dirname(entry);
84026
+ const folder = path25.dirname(entry);
84027
84027
  const graph = { code: /* @__PURE__ */ new Map(), links: /* @__PURE__ */ new Map(), sheets: [], packages: /* @__PURE__ */ new Map() };
84028
84028
  const walk = async (file2) => {
84029
84029
  if (graph.code.has(file2)) return;
84030
84030
  if (graph.code.size >= MAX_FILES) throw new Error(`a mockup imports more than ${MAX_FILES} files`);
84031
- const js = (0, import_sucrase.transform)(fs20.readFileSync(file2, "utf8"), { transforms: ["typescript", "jsx", "imports"], jsxRuntime: "automatic", production: true, filePath: file2 }).code;
84031
+ const js = (0, import_sucrase.transform)(fs21.readFileSync(file2, "utf8"), { transforms: ["typescript", "jsx", "imports"], jsxRuntime: "automatic", production: true, filePath: file2 }).code;
84032
84032
  graph.code.set(file2, js);
84033
84033
  const link = /* @__PURE__ */ new Map();
84034
84034
  graph.links.set(file2, link);
@@ -84040,7 +84040,7 @@ async function readGraph(entry) {
84040
84040
  const target = resolveFile(id, file2, folder);
84041
84041
  link.set(id, target);
84042
84042
  if (!target.endsWith(".css")) await walk(target);
84043
- else if (!graph.sheets.some((s) => s.path === target)) graph.sheets.push({ path: target, content: fs20.readFileSync(target, "utf8") });
84043
+ else if (!graph.sheets.some((s) => s.path === target)) graph.sheets.push({ path: target, content: fs21.readFileSync(target, "utf8") });
84044
84044
  }
84045
84045
  };
84046
84046
  await walk(entry);
@@ -84054,25 +84054,25 @@ function run(script, context, name, deadline) {
84054
84054
  async function tailwindFor(markup, sheets) {
84055
84055
  const source = sheets.length ? sheets.map((s) => s.content).join("\n") : '@import "tailwindcss";';
84056
84056
  const compiler = await zf(source, {
84057
- base: sheets.length ? path23.dirname(sheets[0].path) : "/",
84057
+ base: sheets.length ? path25.dirname(sheets[0].path) : "/",
84058
84058
  loadStylesheet: async (id, from) => {
84059
84059
  if (id === "tailwindcss" || id.startsWith("tailwindcss/")) return { path: "tailwindcss/index.css", base: "/", content: tailwindcss_default };
84060
84060
  if (!id.startsWith(".")) throw new Error(`a mockup cannot import ${id}`);
84061
- const at2 = path23.resolve(from, id);
84062
- return { path: at2, base: path23.dirname(at2), content: fs20.readFileSync(at2, "utf8") };
84061
+ const at2 = path25.resolve(from, id);
84062
+ return { path: at2, base: path25.dirname(at2), content: fs21.readFileSync(at2, "utf8") };
84063
84063
  }
84064
84064
  });
84065
84065
  const classes = [...markup.matchAll(/class="([^"]*)"/g)].flatMap((m) => m[1].split(/\s+/));
84066
84066
  return compiler.build(classes.filter(Boolean));
84067
84067
  }
84068
84068
  function dressPage(file2) {
84069
- const folder = path23.dirname(file2);
84070
- const html = fs20.readFileSync(file2, "utf8").replace(/<link\b[^>]*>/gi, (tag) => {
84069
+ const folder = path25.dirname(file2);
84070
+ const html = fs21.readFileSync(file2, "utf8").replace(/<link\b[^>]*>/gi, (tag) => {
84071
84071
  const href = /\bhref\s*=\s*["']?([^"'\s>]+)/i.exec(tag)?.[1];
84072
84072
  if (!/\brel\s*=\s*["']?stylesheet/i.test(tag) || !href || /^[a-z][\w+.-]*:|^\/\//i.test(href)) return tag;
84073
- const at3 = path23.resolve(folder, href);
84074
- if (!at3.startsWith(folder + path23.sep) || !fs20.existsSync(at3)) return tag;
84075
- return `<style>${fs20.readFileSync(at3, "utf8").replace(/<\/style/gi, "<\\/style")}</style>`;
84073
+ const at3 = path25.resolve(folder, href);
84074
+ if (!at3.startsWith(folder + path25.sep) || !fs21.existsSync(at3)) return tag;
84075
+ return `<style>${fs21.readFileSync(at3, "utf8").replace(/<\/style/gi, "<\\/style")}</style>`;
84076
84076
  });
84077
84077
  const at2 = /^\uFEFF?\s*(?:<!--[\s\S]*?-->\s*)*(?:<!doctype\b[^>]*>)?/i.exec(html)[0].length;
84078
84078
  return /<!doctype\b|<html[\s>]|<head[\s>]/i.test(html) ? html.slice(0, at2) + head + html.slice(at2) : `<!doctype html><html><head>${head}</head><body>${html}</body></html>`;
@@ -84272,6 +84272,9 @@ async function refresh() {
84272
84272
  }
84273
84273
  const fresh = sessionFrom(await response.json(), now);
84274
84274
  if (!fresh) return { ok: false, reason: "expired" };
84275
+ const current = readSession();
84276
+ if (!current || current.subject !== now.subject) return { ok: false, reason: "expired" };
84277
+ if (current.refreshToken !== now.refreshToken) return { ok: true, token: current.accessToken, session: current };
84275
84278
  writeSession(fresh);
84276
84279
  return { ok: true, token: fresh.accessToken, session: fresh };
84277
84280
  } finally {
@@ -84435,8 +84438,8 @@ function status(line) {
84435
84438
  }
84436
84439
 
84437
84440
  // src/protocol.ts
84438
- var VERSION = true ? "0.6.16" : "0.0.0";
84439
- var AKB_VERSION = true ? "0.11.13" : "0.0.0";
84441
+ var VERSION = true ? "0.6.18" : "0.0.0";
84442
+ var AKB_VERSION = true ? "0.11.16" : "0.0.0";
84440
84443
  var AKB_CONTRACT = true ? 5 : 0;
84441
84444
  var EXIT_REFUSED = 10;
84442
84445
  var EXIT_OUTDATED = 11;
@@ -84447,7 +84450,40 @@ import { spawn as spawn2 } from "node:child_process";
84447
84450
  import { randomUUID } from "node:crypto";
84448
84451
  import fs11 from "node:fs";
84449
84452
  import os4 from "node:os";
84450
- import path14 from "node:path";
84453
+ import path15 from "node:path";
84454
+
84455
+ // ../cli/src/lib/agent/language.ts
84456
+ var LANGUAGE_ENV = "AI4KANBAN_LANGUAGE";
84457
+ var LANGUAGE_LINE_ENV = "AI4KANBAN_LANGUAGE_LINE";
84458
+ var SYSTEM_LANGUAGE_ZH = "\u7528\u4E2D\u6587\u56DE\u590D\u3002\u6210\u679C\u8BED\u8A00\u4F9D\u6B21\u9075\u5FAA\u7528\u6237\u660E\u786E\u8981\u6C42\u3001\u6210\u679C\u4E13\u7528\u6307\u4EE4\u3001\u65E2\u6709\u6210\u679C\u6216\u9879\u76EE\u60EF\u4F8B\uFF0C\u6700\u540E\u91C7\u7528\u672C\u6B21\u8BF7\u6C42\u7684\u8BED\u8A00\u3002\u4EE3\u7801\u3001\u547D\u4EE4\u3001\u6587\u4EF6\u540D\u548C\u5B57\u6BB5\u540D\u4FDD\u6301\u539F\u6587\u3002";
84459
+ var SYSTEM_LANGUAGE_EN = "Reply in English. Artifact language follows explicit user requests, artifact instructions, existing or project conventions, then the current request's language. Keep code, commands, filenames, and field names unchanged.";
84460
+ var systemLanguages = /* @__PURE__ */ new Set([
84461
+ SYSTEM_LANGUAGE_ZH,
84462
+ SYSTEM_LANGUAGE_EN,
84463
+ "\u65E0\u8BBA\u5BF9\u8BDD\u91CC\u7684\u5361\u7247\u3001\u4EE3\u7801\u548C\u8D34\u8FDB\u6765\u7684\u5185\u5BB9\u662F\u4EC0\u4E48\u8BED\u8A00\uFF0C\u56DE\u590D\u548C\u5199\u4E0B\u7684\u5185\u5BB9\u90FD\u7528\u4E2D\u6587\u3002\u4EE3\u7801\u3001\u547D\u4EE4\u3001\u6587\u4EF6\u540D\u548C\u5B57\u6BB5\u540D\u4FDD\u6301\u539F\u6587\u3002",
84464
+ "\u5BF9\u8BDD\u548C\u89E3\u91CA\u4F7F\u7528\u4E2D\u6587\uFF1B\u4EA7\u7269\u4F7F\u7528\u7528\u6237\u660E\u786E\u6307\u5B9A\u7684\u8BED\u8A00\uFF0C\u5426\u5219\u4F7F\u7528\u6240\u5C5E agent \u660E\u786E\u6307\u5B9A\u7684\u8BED\u8A00\uFF0C\u5747\u672A\u6307\u5B9A\u65F6\u4F7F\u7528\u4E2D\u6587\u3002\u4EE3\u7801\u3001\u547D\u4EE4\u3001\u6587\u4EF6\u540D\u548C\u5B57\u6BB5\u540D\u4FDD\u6301\u539F\u6587\u3002",
84465
+ "Use English for conversation and explanations. For artifacts, use the language explicitly specified by the user, otherwise the responsible agent, otherwise English. Keep code, commands, filenames, and field names unchanged."
84466
+ ]);
84467
+ var isSystemLanguage = (text3) => systemLanguages.has(text3);
84468
+ var legacy = /* @__PURE__ */ new Map([
84469
+ ["\u8BF7\u7528\u4E2D\u6587\u56DE\u590D\u548C\u5199\u4F5C\u3002", "zh"],
84470
+ ["Reply and write in English.", "en"]
84471
+ ]);
84472
+ var languageCode = (value) => value === "zh" || value === "en" ? value : null;
84473
+ var legacyLanguage = (line) => typeof line === "string" ? legacy.get(line) ?? null : null;
84474
+ var systemLanguage = (language) => language === "zh" ? SYSTEM_LANGUAGE_ZH : language === "en" ? SYSTEM_LANGUAGE_EN : "";
84475
+ function cloudLanguage(input) {
84476
+ if (input.test) return null;
84477
+ return "language" in input ? languageCode(input.language) : legacyLanguage(input.languageLine);
84478
+ }
84479
+ function cloudPrompt(input) {
84480
+ if ("language" in input || input.test || input.flow || input.review || input.agent || !legacyLanguage(input.languageLine)) return input.prompt;
84481
+ if (input.prompt === input.languageLine) return "";
84482
+ const suffix = `
84483
+
84484
+ ${input.languageLine}`;
84485
+ return input.prompt.endsWith(suffix) ? input.prompt.slice(0, -suffix.length) : input.prompt;
84486
+ }
84451
84487
 
84452
84488
  // ../cli/src/lib/agent/argv.ts
84453
84489
  function splitCommand(command) {
@@ -84483,6 +84519,7 @@ function quoteArg(arg) {
84483
84519
  }
84484
84520
 
84485
84521
  // ../cli/src/lib/agent/harnesses/types.ts
84522
+ import { createHash } from "node:crypto";
84486
84523
  import fs3 from "node:fs";
84487
84524
  import path4 from "node:path";
84488
84525
  var SKILL_SENTENCE = "Use the kanban skill";
@@ -84506,7 +84543,8 @@ var MCP_CONFIG = {
84506
84543
  help: "A JSON file of `mcpServers`, as Claude Code's --mcp-config takes. Empty opens no servers."
84507
84544
  };
84508
84545
  function machineFile(name, text3) {
84509
- const file2 = path4.join(machineHome(), "prompts", name);
84546
+ const suffix = createHash("sha256").update(text3).digest("hex").slice(0, 16);
84547
+ const file2 = path4.join(machineHome(), "prompts", `${path4.parse(name).name}-${suffix}${path4.extname(name)}`);
84510
84548
  try {
84511
84549
  if (fs3.readFileSync(file2, "utf8") === text3) return file2;
84512
84550
  } catch {
@@ -85292,10 +85330,10 @@ function findRollout(threadId) {
85292
85330
  }
85293
85331
  for (const name of names2) {
85294
85332
  if (!name.startsWith("rollout-") || !name.endsWith(tail)) continue;
85295
- const path37 = join(dir, name);
85333
+ const path40 = join(dir, name);
85296
85334
  try {
85297
- const at2 = statSync(path37).mtimeMs;
85298
- if (!newest2 || at2 > newest2.at) newest2 = { path: path37, at: at2 };
85335
+ const at2 = statSync(path40).mtimeMs;
85336
+ if (!newest2 || at2 > newest2.at) newest2 = { path: path40, at: at2 };
85299
85337
  } catch {
85300
85338
  }
85301
85339
  }
@@ -85303,11 +85341,11 @@ function findRollout(threadId) {
85303
85341
  return newest2?.path;
85304
85342
  }
85305
85343
  function readCodexRunFacts(threadId) {
85306
- const path37 = findRollout(threadId);
85307
- if (!path37) return void 0;
85344
+ const path40 = findRollout(threadId);
85345
+ if (!path40) return void 0;
85308
85346
  let raw;
85309
85347
  try {
85310
- raw = readFileSync(path37, "utf8");
85348
+ raw = readFileSync(path40, "utf8");
85311
85349
  } catch {
85312
85350
  return void 0;
85313
85351
  }
@@ -85415,14 +85453,19 @@ function renderCompleted(item) {
85415
85453
  const changes = Array.isArray(item.changes) ? item.changes : [];
85416
85454
  return changes.map((raw) => {
85417
85455
  const change = obj(raw);
85418
- const path37 = str(change.path);
85419
- return path37 ? `\u23FA ${str(change.kind) || "change"}(${path37})
85456
+ const path40 = str(change.path);
85457
+ return path40 ? `\u23FA ${str(change.kind) || "change"}(${path40})
85420
85458
  ` : "";
85421
85459
  }).join("");
85422
85460
  }
85423
85461
  case "error":
85424
85462
  return `[error] ${str(item.message)}
85425
85463
  `;
85464
+ case "mcp_tool_call": {
85465
+ const error = str(obj(item.error).message);
85466
+ return error ? `[MCP ${str(item.server)}.${str(item.tool)}] ${error}
85467
+ ` : "";
85468
+ }
85426
85469
  default:
85427
85470
  return "";
85428
85471
  }
@@ -85538,16 +85581,13 @@ function createCodexStreamRenderer(carried = false) {
85538
85581
  return renderCompleted(item);
85539
85582
  }
85540
85583
  case "turn.completed":
85584
+ failure = void 0;
85541
85585
  total = codexUsage(ev.usage) ?? total;
85542
85586
  return "";
85543
- // The two events that say the RUN did not get there — the turn giving up, and the
85544
- // stream itself failing. Kept as the run's failure (#525), because `codex exec`
85545
- // reports its reason on this stream and nowhere else, and a retry has to read it.
85546
- // An item's own `error` is not one of them: a tool that failed is the agent's
85547
- // problem to work around, and the turn around it may still finish.
85587
+ // 最终失败保留;连接提示只在没有后续成功完成时才作为失败。
85548
85588
  case "turn.failed": {
85549
- const said = str(obj(ev.error).message);
85550
- failure = said || failure;
85589
+ const said = str(obj(ev.error).message) || failure || "Codex \u6267\u884C\u5931\u8D25";
85590
+ failure = said;
85551
85591
  events.error(said);
85552
85592
  return `[error] ${said}
85553
85593
  `;
@@ -85555,8 +85595,9 @@ function createCodexStreamRenderer(carried = false) {
85555
85595
  case "error": {
85556
85596
  const said = str(ev.message);
85557
85597
  failure = said || failure;
85558
- events.error(said);
85559
- return `[error] ${said}
85598
+ events.log(`[Codex] ${said}
85599
+ `);
85600
+ return `[Codex] ${said}
85560
85601
  `;
85561
85602
  }
85562
85603
  default:
@@ -85664,10 +85705,10 @@ function readKimiRunFacts(sessionId) {
85664
85705
  const total = { input: 0, cacheCreation: 0, cacheRead: 0, output: 0 };
85665
85706
  let model;
85666
85707
  let holding = 0;
85667
- for (const { path: path37, main: main2 } of wireFiles(entry.sessionDir)) {
85708
+ for (const { path: path40, main: main2 } of wireFiles(entry.sessionDir)) {
85668
85709
  let raw;
85669
85710
  try {
85670
- raw = readFileSync2(path37, "utf8");
85711
+ raw = readFileSync2(path40, "utf8");
85671
85712
  } catch {
85672
85713
  continue;
85673
85714
  }
@@ -85923,7 +85964,7 @@ function createTail(log) {
85923
85964
  // ../cli/package.json
85924
85965
  var package_default = {
85925
85966
  name: "wildcrane",
85926
- version: "0.11.13",
85967
+ version: "0.11.16",
85927
85968
  akbContract: 5,
85928
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.",
85929
85970
  keywords: [
@@ -85983,13 +86024,13 @@ var CLIENT_CAPABILITIES = {
85983
86024
  fs: { readTextFile: false, writeTextFile: false },
85984
86025
  terminal: false
85985
86026
  };
85986
- function whereHint(update2, title) {
85987
- const locations = Array.isArray(update2.locations) ? update2.locations : [];
85988
- const path37 = str(obj(locations[0]).path);
85989
- return path37 && !title.includes(path37) ? hint(path37) : "";
86027
+ function whereHint(update3, title) {
86028
+ const locations = Array.isArray(update3.locations) ? update3.locations : [];
86029
+ const path40 = str(obj(locations[0]).path);
86030
+ return path40 && !title.includes(path40) ? hint(path40) : "";
85990
86031
  }
85991
- function saidBy(update2) {
85992
- const content = Array.isArray(update2.content) ? update2.content : [];
86032
+ function saidBy(update3) {
86033
+ const content = Array.isArray(update3.content) ? update3.content : [];
85993
86034
  for (const raw of content) {
85994
86035
  const part = obj(raw);
85995
86036
  const text3 = str(obj(part.content).text) || str(part.text);
@@ -86631,9 +86672,12 @@ var CLAUDE_CODE = {
86631
86672
  forkArgs(argv, resumeId, sessionId) {
86632
86673
  return [...claudeStreamArgs(argv), "--resume", resumeId, "--fork-session", "--session-id", sessionId];
86633
86674
  },
86634
- // Set again on every turn, a resumed one too: the system prompt is not part of the session.
86675
+ // 默认快照会忽略续跑传入的新规则;仅显式关闭快照的会话支持更新。
86635
86676
  systemPrompt(text3, argv) {
86636
- return namesFlag(argv, ["--append-system-prompt", "--append-system-prompt-file"]) ? {} : { args: ["--append-system-prompt", text3] };
86677
+ if (namesFlag(argv, ["--append-system-prompt", "--append-system-prompt-file"])) return {};
86678
+ const snapshot = argv.flatMap((arg, i) => arg === "--system-prompt-snapshot" ? [argv[i + 1]] : arg.startsWith("--system-prompt-snapshot=") ? [arg.slice("--system-prompt-snapshot=".length)] : []).at(-1);
86679
+ if (namesFlag(argv, ["--resume", "-r", "--continue", "-c"]) && snapshot !== "off") return {};
86680
+ return { args: ["--append-system-prompt", text3] };
86637
86681
  },
86638
86682
  // What Claude Code takes: who pays for the run, where that run goes, a model id, and how
86639
86683
  // hard that model thinks. The provider comes first because it decides the rest — which
@@ -87015,30 +87059,49 @@ function setBoardRoot(root, named2 = false) {
87015
87059
  }
87016
87060
  setBoardRoot(process.cwd());
87017
87061
 
87062
+ // ../cli/src/lib/agent/proxy.ts
87063
+ import { execFileSync } from "node:child_process";
87064
+ var PROXY_KEYS = ["HTTPS_PROXY", "https_proxy", "HTTP_PROXY", "http_proxy", "ALL_PROXY", "all_proxy"];
87065
+ function codexProxyEnv(env2 = process.env, platform = process.platform, read2 = () => execFileSync("/usr/sbin/scutil", ["--proxy"], { encoding: "utf8", timeout: 1e3, stdio: ["ignore", "pipe", "ignore"] })) {
87066
+ const out = { ...env2 };
87067
+ if (platform !== "darwin" || PROXY_KEYS.some((key) => env2[key] !== void 0)) return out;
87068
+ let raw;
87069
+ try {
87070
+ raw = read2();
87071
+ } catch {
87072
+ return out;
87073
+ }
87074
+ const value = (key) => new RegExp(`^\\s*${key}\\s*:\\s*(.*?)\\s*$`, "m").exec(raw)?.[1];
87075
+ for (const [name, key, scheme] of [["HTTP", "HTTP_PROXY", "http"], ["HTTPS", "HTTPS_PROXY", "http"], ["SOCKS", "ALL_PROXY", "socks5"]]) {
87076
+ if (value(`${name}Enable`) !== "1") continue;
87077
+ const host = value(`${name}Proxy`);
87078
+ const port = Number(value(`${name}Port`));
87079
+ if (!host || /[\s/@?#]/.test(host) || !Number.isInteger(port) || port < 1 || port > 65535) continue;
87080
+ try {
87081
+ out[key] = new URL(`${scheme}://${host.includes(":") && !host.startsWith("[") ? `[${host}]` : host}:${port}`).href.replace(/\/$/, "");
87082
+ } catch {
87083
+ }
87084
+ }
87085
+ if (PROXY_KEYS.some((key) => out[key]) && env2.NO_PROXY === void 0 && env2.no_proxy === void 0) {
87086
+ const exceptions = /ExceptionsList\s*:\s*<array>\s*\{([^}]+)\}/.exec(raw)?.[1];
87087
+ const bypass = exceptions?.split("\n").flatMap((line) => {
87088
+ const host = /^\s*\d+\s*:\s*(\S+)\s*$/.exec(line)?.[1];
87089
+ return host ? [host.startsWith("*.") ? host.slice(1) : host] : [];
87090
+ });
87091
+ if (bypass?.length) out.NO_PROXY = bypass.join(",");
87092
+ }
87093
+ return out;
87094
+ }
87095
+
87018
87096
  // ../cli/src/lib/agent/worktree.ts
87019
87097
  import { spawnSync as spawnSync2 } from "node:child_process";
87020
87098
  var MAX_OUTPUT = 64 * 1024 * 1024;
87021
- var gitLimits = { timeoutMs: 3e4 };
87022
- var GitTimeoutError = class extends Error {
87023
- };
87024
- function spawnGit(args, options) {
87025
- const out = spawnSync2("git", args, {
87026
- ...options,
87027
- encoding: "utf8",
87028
- stdio: ["ignore", "pipe", "pipe"],
87029
- timeout: gitLimits.timeoutMs,
87030
- killSignal: "SIGKILL"
87031
- });
87032
- if (out.error?.code === "ETIMEDOUT") throw new GitTimeoutError(`Git ${args[0]} timed out after ${gitLimits.timeoutMs / 1e3}s; the command was killed.`);
87033
- return out;
87034
- }
87035
87099
  function git(args, cwd = REPO_ROOT) {
87036
87100
  try {
87037
- const out = spawnGit(args, { cwd, encoding: "utf8", maxBuffer: MAX_OUTPUT, windowsHide: true });
87101
+ const out = spawnSync2("git", args, { cwd, encoding: "utf8", maxBuffer: MAX_OUTPUT, windowsHide: true });
87038
87102
  if (out.error || out.status !== 0) return null;
87039
87103
  return out.stdout;
87040
- } catch (error) {
87041
- if (error instanceof GitTimeoutError) throw error;
87104
+ } catch {
87042
87105
  return null;
87043
87106
  }
87044
87107
  }
@@ -87174,10 +87237,15 @@ var CODEX = {
87174
87237
  forkArgs(argv, resumeId, _sessionId, cwd) {
87175
87238
  return [...codexExtraArgs(argv, cwd), "fork", resumeId];
87176
87239
  },
87177
- // Codex's developer message. `-c` is global, so it may sit before `exec`. It stands in for a
87178
- // `developer_instructions` in the user's config.toml, which is then left out of board runs.
87240
+ // 自设系统指令保持原样;无法追加时由调用方明确提示。
87179
87241
  systemPrompt(text3, argv) {
87180
- return namesFlag(argv, ["developer_instructions"]) ? {} : { args: ["-c", `developer_instructions=${JSON.stringify(text3)}`] };
87242
+ if (namesFlag(argv, ["developer_instructions", "model_instructions_file"])) return {};
87243
+ try {
87244
+ const config = fs7.readFileSync(path10.join(process.env.CODEX_HOME || home2(".codex"), "config.toml"), "utf8");
87245
+ if (/^\s*(?:developer_instructions|model_instructions_file)\s*=/m.test(config)) return {};
87246
+ } catch {
87247
+ }
87248
+ return { args: ["-c", `developer_instructions=${JSON.stringify(text3)}`] };
87181
87249
  },
87182
87250
  // What Codex takes, in the order Claude Code's dialog draws the same four: who pays for
87183
87251
  // the run and where it goes, that endpoint's address, the key, a model, and how hard that
@@ -87305,7 +87373,7 @@ var CODEX = {
87305
87373
  // No `providerEnv` either: the pick already drops and sets OPENAI_API_KEY, and there is
87306
87374
  // no second variable to drop. Codex reads no base URL from the environment — an exported
87307
87375
  // OPENAI_BASE_URL moves nothing — and where a run goes is settled on its command line.
87308
- env: () => ({ ...process.env }),
87376
+ env: () => codexProxyEnv(),
87309
87377
  // A completed turn carries its token counts and nothing else. The model comes from the
87310
87378
  // session's rollout on disk instead, and the price is worked out from the two
87311
87379
  // (agent/wire/codex-stream.ts). A model whose rates the board doesn't know shows no price.
@@ -87498,9 +87566,9 @@ var DSH = {
87498
87566
  // dsh-acp's persona IS its system prompt, so the ask is added to the one in effect: the
87499
87567
  // user's own `DSH_SYSTEM_PROMPT`, else the bridge's default. A `--persona` on the command
87500
87568
  // line outranks both, and is left alone.
87501
- systemPrompt(text3, argv) {
87569
+ systemPrompt(text3, argv, env2) {
87502
87570
  if (namesFlag(argv, ["--persona"])) return {};
87503
- return { env: { DSH_SYSTEM_PROMPT: `${process.env.DSH_SYSTEM_PROMPT || DSH_PERSONA}
87571
+ return { env: { DSH_SYSTEM_PROMPT: `${env2.DSH_SYSTEM_PROMPT || DSH_PERSONA}
87504
87572
 
87505
87573
  ${text3}` } };
87506
87574
  },
@@ -87891,12 +87959,12 @@ var OPENCODE = {
87891
87959
  env: () => ({ ...process.env }),
87892
87960
  // `instructions` files join the system prompt, and OpenCode adds this config's list to the
87893
87961
  // user's own rather than replacing it.
87894
- systemPrompt(text3) {
87962
+ systemPrompt(text3, _argv, env2) {
87895
87963
  const file2 = machineFile("opencode-language.md", `${text3}
87896
87964
  `);
87897
87965
  let own = {};
87898
87966
  try {
87899
- own = obj2(JSON.parse(process.env.OPENCODE_CONFIG_CONTENT ?? "{}"));
87967
+ own = obj2(JSON.parse(env2.OPENCODE_CONFIG_CONTENT ?? "{}"));
87900
87968
  } catch {
87901
87969
  }
87902
87970
  const instructions = [...Array.isArray(own.instructions) ? own.instructions : [], file2];
@@ -88039,26 +88107,18 @@ var HARNESSES = [CLAUDE_CODE, CODEX, CURSOR, OPENCODE, KIMI, DSH, ZCODE, GROK].m
88039
88107
  var DEFAULT_HARNESS = HARNESSES[0];
88040
88108
  checkHarnesses(HARNESSES);
88041
88109
 
88110
+ // ../cli/src/lib/agent/run-settings.ts
88111
+ import path12 from "node:path";
88112
+
88042
88113
  // ../cli/src/lib/agent/env.ts
88043
88114
  var RUN_ENV = "KANBAN_RUN";
88044
88115
  var SCHEDULED_AGENTS_ENV = "AI4KANBAN_SCHEDULED_AGENTS";
88116
+ var STOP_ENV = "KANBAN_STOP_ID";
88045
88117
  var SESSION_VARS = {
88046
88118
  "claude-code": "CLAUDE_CODE_SESSION_ID",
88047
88119
  codex: "CODEX_THREAD_ID"
88048
88120
  };
88049
88121
 
88050
- // ../cli/src/lib/agent/language.ts
88051
- var LANGUAGE_LINE_ENV = "AI4KANBAN_LANGUAGE_LINE";
88052
- var LINES = {
88053
- en: "",
88054
- zh: "\u8BF7\u7528\u4E2D\u6587\u56DE\u590D\u548C\u5199\u4F5C\u3002"
88055
- };
88056
- var SYSTEM = {
88057
- [LINES.zh]: "\u65E0\u8BBA\u5BF9\u8BDD\u91CC\u7684\u5361\u7247\u3001\u4EE3\u7801\u548C\u8D34\u8FDB\u6765\u7684\u5185\u5BB9\u662F\u4EC0\u4E48\u8BED\u8A00\uFF0C\u56DE\u590D\u548C\u5199\u4E0B\u7684\u5185\u5BB9\u90FD\u7528\u4E2D\u6587\u3002\u4EE3\u7801\u3001\u547D\u4EE4\u3001\u6587\u4EF6\u540D\u548C\u5B57\u6BB5\u540D\u4FDD\u6301\u539F\u6587\u3002"
88058
- };
88059
- var asksForTranslation = (line) => line !== "" && !/\bEnglish\b/.test(line);
88060
- var systemLanguage = (line) => asksForTranslation(line) ? SYSTEM[line] ?? line : "";
88061
-
88062
88122
  // ../cli/src/lib/agent/providers.ts
88063
88123
  function providerSetting(settings) {
88064
88124
  return settings.find((s) => s.kind === "provider");
@@ -88150,11 +88210,34 @@ function effectiveValues(harness, held4) {
88150
88210
  }
88151
88211
  return out;
88152
88212
  }
88153
- function withSystemLanguage(harness, argv, env2, line) {
88154
- const text3 = systemLanguage(line);
88155
- const added = text3 && argv.length ? harness.systemPrompt?.(text3, argv) : void 0;
88156
- if (!added) return { argv, env: env2 };
88157
- return { argv: [argv[0], ...added.args ?? [], ...argv.slice(1)], env: { ...env2, ...added.env } };
88213
+ function languageEnv(given) {
88214
+ const env2 = { ...given };
88215
+ if (env2.DSH_SYSTEM_PROMPT) {
88216
+ const parts = env2.DSH_SYSTEM_PROMPT.split("\n\n");
88217
+ while (isSystemLanguage(parts.at(-1) ?? "")) parts.pop();
88218
+ env2.DSH_SYSTEM_PROMPT = parts.join("\n\n");
88219
+ }
88220
+ try {
88221
+ const config = JSON.parse(env2.OPENCODE_CONFIG_CONTENT ?? "{}");
88222
+ if (Array.isArray(config.instructions)) {
88223
+ config.instructions = config.instructions.filter((file2) => typeof file2 !== "string" || path12.dirname(file2) !== path12.join(machineHome(), "prompts") || !/^opencode-language(?:-[a-f0-9]{16})?\.md$/.test(path12.basename(file2)));
88224
+ env2.OPENCODE_CONFIG_CONTENT = JSON.stringify(config);
88225
+ }
88226
+ } catch {
88227
+ }
88228
+ return env2;
88229
+ }
88230
+ function withSystemLanguage(harness, argv, env2, language) {
88231
+ env2 = languageEnv(env2);
88232
+ const text3 = systemLanguage(language);
88233
+ if (!text3) return { argv, env: env2 };
88234
+ const added = argv.length ? harness.systemPrompt?.(text3, argv, env2) : void 0;
88235
+ if (!added?.args?.length && !Object.keys(added?.env ?? {}).length) {
88236
+ const note = language === "zh" ? "\u8BED\u8A00\u89C4\u5219\u672A\u80FD\u66F4\u65B0\uFF1A\u8FDE\u63A5\u5668\u3001\u5DF2\u6709\u4F1A\u8BDD\u6216\u81EA\u8BBE\u7CFB\u7EDF\u63D0\u793A\u8BCD\u4E0D\u652F\u6301\u6CE8\u5165\u3002\u8BF7\u81EA\u884C\u53E6\u5F00\u652F\u6301\u7684\u4F1A\u8BDD\u4EE5\u91C7\u7528\u65B0\u89C4\u5219\u3002" : "Language rules could not be updated: the connector, existing session, or custom system prompt prevents injection. Open a supported new session to apply them.";
88237
+ return { argv, env: env2, note };
88238
+ }
88239
+ const at2 = /^node(?:\.exe)?$/.test(path12.basename(argv[0])) && argv[1] && !argv[1].startsWith("-") ? 2 : 1;
88240
+ return { argv: [...argv.slice(0, at2), ...added?.args ?? [], ...argv.slice(at2)], env: { ...env2, ...added?.env } };
88158
88241
  }
88159
88242
 
88160
88243
  // src/api.ts
@@ -88167,6 +88250,7 @@ __export(api_exports, {
88167
88250
  claimJob: () => claimJob,
88168
88251
  commitBoard: () => commitBoard,
88169
88252
  createArtifact: () => createArtifact,
88253
+ createProject: () => createProject,
88170
88254
  createUpload: () => createUpload,
88171
88255
  createVersion: () => createVersion,
88172
88256
  dispatchReview: () => dispatchReview,
@@ -88216,14 +88300,14 @@ __export(api_exports, {
88216
88300
 
88217
88301
  // src/goals.ts
88218
88302
  import fs9 from "node:fs";
88219
- import path12 from "node:path";
88303
+ import path13 from "node:path";
88220
88304
  function goalsOf(held4) {
88221
88305
  if (held4.goals !== void 0 && held4.ideas !== void 0 && JSON.stringify(held4.goals) !== JSON.stringify(held4.ideas)) throw new Error("goals and ideas do not match.");
88222
88306
  const goals = held4.goals ?? held4.ideas;
88223
88307
  if (!Array.isArray(goals)) throw new Error("The goals array is missing or invalid.");
88224
88308
  return goals;
88225
88309
  }
88226
- var goalsFileOf = (job) => path12.join(runnerHome(), "ideas", `${job.id}.json`);
88310
+ var goalsFileOf = (job) => path13.join(runnerHome(), "ideas", `${job.id}.json`);
88227
88311
  async function writeGoals(job, list) {
88228
88312
  let goals;
88229
88313
  try {
@@ -88240,7 +88324,7 @@ async function writeGoals(job, list) {
88240
88324
  after = page.value.next;
88241
88325
  } while (after);
88242
88326
  const file2 = goalsFileOf(job);
88243
- fs9.mkdirSync(path12.dirname(file2), { recursive: true });
88327
+ fs9.mkdirSync(path13.dirname(file2), { recursive: true });
88244
88328
  fs9.writeFileSync(file2, `${JSON.stringify({ workflows, ideas: goals }, null, 2)}
88245
88329
  `);
88246
88330
  return { file: file2 };
@@ -88257,8 +88341,8 @@ function readGoals(file2) {
88257
88341
 
88258
88342
  // src/secrets.ts
88259
88343
  import fs10 from "node:fs";
88260
- import path13 from "node:path";
88261
- var file = () => path13.join(runnerHome(), "secrets.json");
88344
+ import path14 from "node:path";
88345
+ var file = () => path14.join(runnerHome(), "secrets.json");
88262
88346
  function readAll() {
88263
88347
  try {
88264
88348
  const held4 = JSON.parse(fs10.readFileSync(file(), "utf8"));
@@ -88287,10 +88371,10 @@ var secretsSet = () => Object.fromEntries(Object.entries(readAll()).map(([id, ke
88287
88371
 
88288
88372
  // src/api.ts
88289
88373
  var RUNTIMES = ["claude-code", "codex", "cursor", "opencode", "kimi", "dsh", "zcode", "grok"];
88290
- var PROTOCOL = 13;
88374
+ var PROTOCOL = 15;
88291
88375
  var TIMEOUT_MS = 2e4;
88292
- async function send(method, route, body, signedIn, ms, type) {
88293
- const headers = { accept: "application/json" };
88376
+ async function send(method, route, body, signedIn, ms, type, extra = {}) {
88377
+ const headers = { accept: "application/json", ...extra };
88294
88378
  if (signedIn) {
88295
88379
  const token = await accessToken();
88296
88380
  if (!token.ok) {
@@ -88374,7 +88458,11 @@ var listFolders = (machineId2) => request("GET", `/v1/runner/folders?machine=${q
88374
88458
  var listElsewhere = (machineId2) => request("GET", `/v1/runner/folders?machine=${q(machineId2)}&elsewhere=1`);
88375
88459
  var listMachineTasks = (machineId2) => request("GET", `/v1/runner/tasks?machine=${q(machineId2)}`);
88376
88460
  var stopTask = (task, how) => request("POST", how === "chat" ? `/v1/tasks/${q(task)}/chat/stop` : `/v1/tasks/${q(task)}/stop`, {});
88377
- var addFolder = (machineId2, name, path37, project) => request("POST", "/v1/runner/folders", { machineId: machineId2, name, path: path37, ...project ? { project } : {} });
88461
+ var addFolder = (machineId2, name, path40, project) => request("POST", "/v1/runner/folders", { machineId: machineId2, name, path: path40, ...project ? { project } : {} });
88462
+ async function createProject(name, workspace, key) {
88463
+ const sent = await send("POST", "/v1/projects", { name, workspace }, true, TIMEOUT_MS, void 0, { "idempotency-key": key });
88464
+ return sent.ok ? answerOf(sent.value) : sent;
88465
+ }
88378
88466
  var removeFolder = (machineId2, project) => request("POST", `/v1/runner/folders/${q(project)}/remove`, { machineId: machineId2 });
88379
88467
  var readBoard = (project, since) => request("GET", `/v1/projects/${q(project)}/board${since === null ? "" : `?since=${since}`}`);
88380
88468
  async function commitBoard(project, job, machine, files) {
@@ -88448,7 +88536,7 @@ function commandOf(harness) {
88448
88536
  const [binary, ...flags] = splitCommand(harness.command);
88449
88537
  return [spawnName(chooseCopy(harness, SPAWN_MS), binary), ...flags];
88450
88538
  }
88451
- function plan(runtime, prompt, cwd, resume, model, given = {}, fork = false, line = "") {
88539
+ function plan(runtime, prompt, cwd, resume, model, given = {}, fork = false, language = null) {
88452
88540
  const harness = HARNESSES2[runtime];
88453
88541
  const values = held(runtime, model, given);
88454
88542
  const [binary, ...flags] = commandOf(harness);
@@ -88457,21 +88545,22 @@ function plan(runtime, prompt, cwd, resume, model, given = {}, fork = false, lin
88457
88545
  const copied = fork && resume && harness.forkArgs ? harness.forkArgs(base, resume, id, cwd) : null;
88458
88546
  if (fork) resume = null;
88459
88547
  const extra = copied ?? (resume ? harness.resumeArgs(base, resume, cwd) : harness.extraArgs(base, id, cwd));
88460
- const quiet = (line2) => harness.quietStderr?.(line2) ?? false;
88461
- const { argv, env: env2 } = withSystemLanguage(harness, [...base, ...extra], copyEnv(binary, { ...process.env, ...settingEnv(harness, values, given.secrets ?? {}, cwd), WILDCRANE_JOB: "1" }), line);
88548
+ const quiet = (line) => harness.quietStderr?.(line) ?? false;
88549
+ const { argv, env: env2, note } = withSystemLanguage(harness, [...base, ...extra], copyEnv(binary, { ...process.env, ...settingEnv(harness, values, given.secrets ?? {}, cwd), WILDCRANE_JOB: "1", [LANGUAGE_ENV]: language ?? "", [LANGUAGE_LINE_ENV]: void 0 }), language);
88462
88550
  if (harness.client) {
88463
88551
  const client = harness.client(effectiveValues(harness, values));
88464
88552
  let session;
88465
88553
  let named2;
88466
88554
  return {
88555
+ startNote: note,
88467
88556
  command: argv[0],
88468
88557
  args: argv.slice(1),
88469
88558
  env: env2,
88470
- converse: (child, event2) => client.turn({
88559
+ converse: (child, event2, restart = true) => client.turn({
88471
88560
  stdout: child.stdout,
88472
88561
  stdin: child.stdin,
88473
88562
  prompt,
88474
- restartPrompt: prompt,
88563
+ restartPrompt: restart ? prompt : void 0,
88475
88564
  cwd,
88476
88565
  resumeId: resume ?? void 0,
88477
88566
  log: () => {
@@ -88490,6 +88579,7 @@ function plan(runtime, prompt, cwd, resume, model, given = {}, fork = false, lin
88490
88579
  const renderer = harness.renderer(cwd, argv[0], argv);
88491
88580
  const toStdin = harness.stdinPrompt?.(argv);
88492
88581
  return {
88582
+ startNote: note,
88493
88583
  command: argv[0],
88494
88584
  args: [...argv.slice(1), ...toStdin ? [] : [prompt]],
88495
88585
  env: env2,
@@ -88541,14 +88631,14 @@ var listed = (harness) => async () => (harness.models?.() ?? []).map((id) => ({
88541
88631
  var readModels = (name) => (MODELS[name] ?? listed(HARNESSES2[name]))().catch(() => []);
88542
88632
  var MODELS = {
88543
88633
  "claude-code": async () => {
88544
- const cached2 = claudeModels(path14.join(process.env.CLAUDE_CONFIG_DIR || path14.join(os4.homedir(), ".claude"), "cache", "model-catalog"));
88634
+ const cached2 = claudeModels(path15.join(process.env.CLAUDE_CONFIG_DIR || path15.join(os4.homedir(), ".claude"), "cache", "model-catalog"));
88545
88635
  return cached2.length ? cached2 : [
88546
88636
  { id: "opus", name: "Opus" },
88547
88637
  { id: "sonnet", name: "Sonnet" },
88548
88638
  { id: "haiku", name: "Haiku" }
88549
88639
  ];
88550
88640
  },
88551
- codex: async () => codexModels(path14.join(process.env.CODEX_HOME || path14.join(os4.homedir(), ".codex"), "models_cache.json")),
88641
+ codex: async () => codexModels(path15.join(process.env.CODEX_HOME || path15.join(os4.homedir(), ".codex"), "models_cache.json")),
88552
88642
  opencode: async () => opencodeModels(await output(commandOf(HARNESSES2.opencode)[0], ["models"])),
88553
88643
  cursor: () => cursorModels()
88554
88644
  };
@@ -88620,7 +88710,7 @@ function claudeModels(dir) {
88620
88710
  }
88621
88711
  const catalogs = files.flatMap((f2) => {
88622
88712
  try {
88623
- const data = obj(JSON.parse(fs11.readFileSync(path14.join(dir, f2), "utf8")));
88713
+ const data = obj(JSON.parse(fs11.readFileSync(path15.join(dir, f2), "utf8")));
88624
88714
  const catalog = obj(data.catalog);
88625
88715
  const surface = str(catalog.surface);
88626
88716
  return surface === "cc" || surface === "ccd" ? [{ surface, at: Number(data.fetchedAt) || 0, config: obj(catalog.config) }] : [];
@@ -88812,6 +88902,114 @@ function connectCloudLive(handlers) {
88812
88902
  };
88813
88903
  }
88814
88904
 
88905
+ // src/folders.ts
88906
+ import fs12 from "node:fs";
88907
+ import path16 from "node:path";
88908
+ var projectsFile = () => path16.join(runnerHome(), "projects.json");
88909
+ function realpath(p2) {
88910
+ try {
88911
+ return fs12.realpathSync(p2);
88912
+ } catch {
88913
+ return null;
88914
+ }
88915
+ }
88916
+ function readGrants() {
88917
+ try {
88918
+ const held4 = JSON.parse(fs12.readFileSync(projectsFile(), "utf8"));
88919
+ if (!Array.isArray(held4.projects)) throw new Error("invalid_projects");
88920
+ return held4;
88921
+ } catch (error) {
88922
+ if (error.code === "ENOENT") return { projects: [] };
88923
+ throw error;
88924
+ }
88925
+ }
88926
+ function listOf(held4) {
88927
+ const subject = readSession()?.subject;
88928
+ if (!held4.accounts) return held4.projects;
88929
+ return subject ? held4.accounts[subject] ?? [] : [];
88930
+ }
88931
+ function update2(change) {
88932
+ fs12.mkdirSync(runnerHome(), { recursive: true, mode: 448 });
88933
+ const lock = `${projectsFile()}.lock`;
88934
+ let fd;
88935
+ const until = Date.now() + 2e3;
88936
+ for (; ; ) {
88937
+ try {
88938
+ fd = fs12.openSync(lock, "wx", 384);
88939
+ fs12.writeFileSync(fd, String(process.pid));
88940
+ break;
88941
+ } catch {
88942
+ try {
88943
+ const pid = Number(fs12.readFileSync(lock, "utf8"));
88944
+ if (pid > 0) {
88945
+ try {
88946
+ process.kill(pid, 0);
88947
+ } catch {
88948
+ fs12.rmSync(lock, { force: true });
88949
+ }
88950
+ }
88951
+ } catch {
88952
+ }
88953
+ if (Date.now() > until) throw new Error("authorization_busy");
88954
+ Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 10);
88955
+ }
88956
+ }
88957
+ try {
88958
+ const held4 = readGrants();
88959
+ const subject = readSession()?.subject;
88960
+ const before = listOf(held4);
88961
+ const after = [...new Set(change(before))];
88962
+ if (subject) {
88963
+ if (!held4.accounts) {
88964
+ held4.accounts = { [subject]: held4.projects };
88965
+ held4.legacyOwner = subject;
88966
+ }
88967
+ held4.accounts[subject] = after;
88968
+ held4.projects = after;
88969
+ } else held4.projects = after;
88970
+ const tmp = `${projectsFile()}.${process.pid}.tmp`;
88971
+ fs12.writeFileSync(tmp, `${JSON.stringify(held4, null, 2)}
88972
+ `, { mode: 384 });
88973
+ fs12.renameSync(tmp, projectsFile());
88974
+ return before.filter((p2) => !after.includes(p2));
88975
+ } finally {
88976
+ fs12.closeSync(fd);
88977
+ fs12.rmSync(lock, { force: true });
88978
+ }
88979
+ }
88980
+ function adoptLegacy() {
88981
+ if (readSession() && !readGrants().accounts) update2((list) => list);
88982
+ }
88983
+ function allowedProjects() {
88984
+ return listOf(readGrants()).flatMap((p2) => {
88985
+ const real = realpath(p2);
88986
+ return real && fs12.statSync(real).isDirectory() ? [real] : [];
88987
+ });
88988
+ }
88989
+
88990
+ // src/connect.ts
88991
+ import fs36 from "node:fs";
88992
+ import path39 from "node:path";
88993
+
88994
+ // src/settings-control.ts
88995
+ import fs13 from "node:fs";
88996
+ import path17 from "node:path";
88997
+ var directory = () => path17.join(runnerHome(), "executors");
88998
+ var epochFile = () => path17.join(runnerHome(), "account-generation");
88999
+ function accountGeneration() {
89000
+ try {
89001
+ return fs13.readFileSync(epochFile(), "utf8");
89002
+ } catch {
89003
+ return "";
89004
+ }
89005
+ }
89006
+ function executorRecord() {
89007
+ fs13.mkdirSync(directory(), { recursive: true, mode: 448 });
89008
+ const file2 = path17.join(directory(), `${process.pid}.json`);
89009
+ fs13.writeFileSync(file2, "{}", { mode: 384 });
89010
+ return () => fs13.rmSync(file2, { force: true });
89011
+ }
89012
+
88815
89013
  // ../cli/src/lib/cadence.ts
88816
89014
  var AUTO_CADENCE = "auto";
88817
89015
  var isAuto = (cadence) => cadence.trim().toLowerCase() === AUTO_CADENCE;
@@ -88927,48 +89125,48 @@ async function askDueAgents(machineId2, now = Date.now()) {
88927
89125
 
88928
89126
  // src/akb-version.ts
88929
89127
  import { execFile } from "node:child_process";
88930
- import fs16 from "node:fs";
88931
- import path19 from "node:path";
89128
+ import fs17 from "node:fs";
89129
+ import path21 from "node:path";
88932
89130
 
88933
89131
  // src/akb.ts
88934
89132
  import { spawn as spawn3 } from "node:child_process";
88935
- import fs12 from "node:fs";
88936
- import path15 from "node:path";
89133
+ import fs14 from "node:fs";
89134
+ import path18 from "node:path";
88937
89135
  import { fileURLToPath } from "node:url";
88938
- var akbHome = () => path15.join(runnerHome(), "bin", "akb");
89136
+ var akbHome = () => path18.join(runnerHome(), "bin", "akb");
88939
89137
  var BUNDLED_SHIM = `bundled-${AKB_VERSION}`;
88940
89138
  var bundledAkb = () => ({
88941
89139
  command: process.execPath,
88942
- args: [path15.join(path15.dirname(fileURLToPath(import.meta.url)), "akb", "bin", "ai4kanban.mjs")],
89140
+ args: [path18.join(path18.dirname(fileURLToPath(import.meta.url)), "akb", "bin", "ai4kanban.mjs")],
88943
89141
  version: AKB_VERSION,
88944
- shim: path15.join(akbHome(), BUNDLED_SHIM)
89142
+ shim: path18.join(akbHome(), BUNDLED_SHIM)
88945
89143
  });
88946
89144
  var quote = (s) => /^[\w./:@=-]+$/.test(s) ? s : `"${s}"`;
88947
89145
  function shimDir(akb) {
88948
89146
  const dir = akb.shim;
88949
89147
  const line = [akb.command, ...akb.args].map(quote).join(" ");
88950
- const [file2, text3] = process.platform === "win32" ? [path15.join(dir, "akb.cmd"), `@${line} %*\r
88951
- `] : [path15.join(dir, "akb"), `#!/bin/sh
89148
+ const [file2, text3] = process.platform === "win32" ? [path18.join(dir, "akb.cmd"), `@${line} %*\r
89149
+ `] : [path18.join(dir, "akb"), `#!/bin/sh
88952
89150
  exec ${line} "$@"
88953
89151
  `];
88954
89152
  try {
88955
- if (fs12.readFileSync(file2, "utf8") === text3) return dir;
89153
+ if (fs14.readFileSync(file2, "utf8") === text3) return dir;
88956
89154
  } catch {
88957
89155
  }
88958
- fs12.mkdirSync(dir, { recursive: true });
88959
- fs12.writeFileSync(file2, text3, { mode: 493 });
89156
+ fs14.mkdirSync(dir, { recursive: true });
89157
+ fs14.writeFileSync(file2, text3, { mode: 493 });
88960
89158
  return dir;
88961
89159
  }
88962
- function akbEnv(akb, board, task, line) {
89160
+ function akbEnv(akb, board, task, language, base = process.env) {
88963
89161
  const env2 = {};
88964
- const dropped = ["AI4KANBAN_BOARD", "AI4KANBAN_TASK", "AI4KANBAN_EXECUTION", LANGUAGE_LINE_ENV, SCHEDULED_AGENTS_ENV];
88965
- for (const [k, v2] of Object.entries(process.env)) if (!k.startsWith("KANBAN_") && !dropped.includes(k)) env2[k] = v2;
89162
+ const dropped = ["AI4KANBAN_BOARD", "AI4KANBAN_TASK", "AI4KANBAN_EXECUTION", LANGUAGE_ENV, LANGUAGE_LINE_ENV, SCHEDULED_AGENTS_ENV];
89163
+ for (const [k, v2] of Object.entries(base)) if (!k.startsWith("KANBAN_") && !dropped.includes(k)) env2[k] = v2;
88966
89164
  const key = Object.keys(env2).find((k) => k.toUpperCase() === "PATH") ?? "PATH";
88967
- env2[key] = [shimDir(akb), env2[key]].filter(Boolean).join(path15.delimiter);
89165
+ env2[key] = [shimDir(akb), env2[key]].filter(Boolean).join(path18.delimiter);
88968
89166
  env2.AI4KANBAN_COMMAND = "akb";
88969
89167
  if (board) env2.AI4KANBAN_BOARD = board;
88970
89168
  if (task) env2.AI4KANBAN_TASK = task;
88971
- if (line !== void 0) env2[LANGUAGE_LINE_ENV] = line;
89169
+ if (language !== void 0) env2[LANGUAGE_ENV] = language ?? "";
88972
89170
  return env2;
88973
89171
  }
88974
89172
  var KEEP = 256 * 1024;
@@ -88982,7 +89180,7 @@ function runAkb(akb, args, opts) {
88982
89180
  };
88983
89181
  let child;
88984
89182
  try {
88985
- child = spawn3(akb.command, [...akb.args, ...args], { cwd: opts.cwd, env: { ...akbEnv(akb, opts.board, opts.task, opts.line), ...opts.env }, detached: process.platform !== "win32", stdio: ["ignore", "pipe", "pipe"] });
89183
+ child = spawn3(akb.command, [...akb.args, ...args], { cwd: opts.cwd, env: { ...akbEnv(akb, opts.board, opts.task, opts.language), ...opts.env }, detached: process.platform !== "win32", stdio: ["ignore", "pipe", "pipe"] });
88986
89184
  } catch (e2) {
88987
89185
  return resolve2({ code: null, out: "", last: e2 instanceof Error ? e2.message : String(e2) });
88988
89186
  }
@@ -89013,65 +89211,45 @@ function answerOf2(ran) {
89013
89211
 
89014
89212
  // src/cache.ts
89015
89213
  import { spawnSync as spawnSync3 } from "node:child_process";
89016
- import fs14 from "node:fs";
89017
- import path17 from "node:path";
89018
-
89019
- // src/folders.ts
89020
- import fs13 from "node:fs";
89021
- import path16 from "node:path";
89022
- var projectsFile = () => path16.join(runnerHome(), "projects.json");
89023
- function realpath(p2) {
89024
- try {
89025
- return fs13.realpathSync(p2);
89026
- } catch {
89027
- return null;
89028
- }
89029
- }
89030
- function readList() {
89031
- try {
89032
- const held4 = JSON.parse(fs13.readFileSync(projectsFile(), "utf8"));
89033
- return Array.isArray(held4.projects) ? held4.projects.filter((p2) => typeof p2 === "string") : [];
89034
- } catch {
89035
- return [];
89036
- }
89037
- }
89038
- function allowedProjects() {
89039
- return readList().flatMap((p2) => [realpath(p2)].filter((r2) => !!r2));
89040
- }
89041
-
89042
- // src/cache.ts
89214
+ import crypto2 from "node:crypto";
89215
+ import fs15 from "node:fs";
89216
+ import path19 from "node:path";
89043
89217
  var IDLE_MS = 7 * 24 * 60 * 6e4;
89044
89218
  var SWEEP_MS = 24 * 60 * 6e4;
89045
89219
  var PROJECT_ID = /^[\w-]{1,100}$/;
89046
- var cacheRoot = () => path17.join(runnerHome(), "cache");
89220
+ var cacheRoot = () => path19.join(runnerHome(), "cache");
89047
89221
  function cacheDir(project) {
89048
89222
  if (!PROJECT_ID.test(project)) throw new Error("This job names no project.");
89049
- return path17.join(cacheRoot(), project);
89223
+ return path19.join(cacheRoot(), project);
89050
89224
  }
89051
- var akbDir = (dir) => path17.join(dir, ".akb");
89052
- var usedFile = (dir) => path17.join(akbDir(dir), "used.json");
89053
- var unsentFile = (dir) => path17.join(akbDir(dir), "unsent");
89225
+ var akbDir = (dir) => path19.join(dir, ".akb");
89226
+ var usedFile = (dir) => path19.join(akbDir(dir), "used.json");
89227
+ var unsentFile = (dir) => path19.join(akbDir(dir), "unsent");
89054
89228
  function markUsed(dir, at2 = Date.now()) {
89055
- fs14.mkdirSync(akbDir(dir), { recursive: true });
89056
- fs14.writeFileSync(usedFile(dir), `${JSON.stringify({ at: at2 })}
89229
+ fs15.mkdirSync(akbDir(dir), { recursive: true });
89230
+ fs15.writeFileSync(usedFile(dir), `${JSON.stringify({ at: at2 })}
89057
89231
  `);
89058
89232
  }
89059
89233
  function usedAt(dir) {
89060
89234
  try {
89061
- const at2 = JSON.parse(fs14.readFileSync(usedFile(dir), "utf8")).at;
89235
+ const at2 = JSON.parse(fs15.readFileSync(usedFile(dir), "utf8")).at;
89062
89236
  return typeof at2 === "number" ? at2 : null;
89063
89237
  } catch {
89064
89238
  return null;
89065
89239
  }
89066
89240
  }
89067
- var unsent = (dir) => fs14.existsSync(unsentFile(dir));
89241
+ var unsent = (dir) => fs15.existsSync(unsentFile(dir));
89068
89242
  function markUnsent(dir, unsent2) {
89069
- if (!unsent2) return void fs14.rmSync(unsentFile(dir), { force: true });
89070
- fs14.mkdirSync(akbDir(dir), { recursive: true });
89071
- fs14.writeFileSync(unsentFile(dir), "");
89243
+ if (!unsent2) return void fs15.rmSync(unsentFile(dir), { force: true });
89244
+ fs15.mkdirSync(akbDir(dir), { recursive: true });
89245
+ fs15.writeFileSync(unsentFile(dir), "");
89072
89246
  }
89073
89247
  var holds = /* @__PURE__ */ new Map();
89248
+ var holdsDir = () => path19.join(runnerHome(), "holds");
89249
+ var holdFile = (dir) => path19.join(holdsDir(), `${crypto2.createHash("sha256").update(dir).digest("hex")}.${process.pid}`);
89074
89250
  function hold(dir) {
89251
+ fs15.mkdirSync(holdsDir(), { recursive: true, mode: 448 });
89252
+ fs15.writeFileSync(holdFile(dir), "", { mode: 384 });
89075
89253
  holds.set(dir, (holds.get(dir) ?? 0) + 1);
89076
89254
  let held4 = true;
89077
89255
  return () => {
@@ -89079,30 +89257,49 @@ function hold(dir) {
89079
89257
  held4 = false;
89080
89258
  const left = holds.get(dir) - 1;
89081
89259
  if (left) holds.set(dir, left);
89082
- else holds.delete(dir);
89260
+ else {
89261
+ holds.delete(dir);
89262
+ fs15.rmSync(holdFile(dir), { force: true });
89263
+ }
89083
89264
  };
89084
89265
  }
89085
89266
  function paused(dir) {
89086
89267
  try {
89087
- const file2 = path17.join(projectStateDir(path17.join(akbDir(dir), "kanban")), SESSIONS_FILE);
89088
- const held4 = JSON.parse(fs14.readFileSync(file2, "utf8"));
89268
+ const file2 = path19.join(projectStateDir(path19.join(akbDir(dir), "kanban")), SESSIONS_FILE);
89269
+ const held4 = JSON.parse(fs15.readFileSync(file2, "utf8"));
89089
89270
  return (held4.deliveries ?? []).some((d2) => d2.status === "active");
89090
89271
  } catch {
89091
89272
  return false;
89092
89273
  }
89093
89274
  }
89094
- var busy = (dir) => holds.has(dir);
89275
+ function busy(dir) {
89276
+ if (holds.has(dir)) return true;
89277
+ const prefix = path19.basename(holdFile(dir)).split(".")[0] + ".";
89278
+ try {
89279
+ return fs15.readdirSync(holdsDir()).filter((file2) => file2.startsWith(prefix)).some((file2) => {
89280
+ try {
89281
+ process.kill(Number(file2.split(".")[1]), 0);
89282
+ return true;
89283
+ } catch {
89284
+ fs15.rmSync(path19.join(holdsDir(), file2), { force: true });
89285
+ return false;
89286
+ }
89287
+ });
89288
+ } catch {
89289
+ return false;
89290
+ }
89291
+ }
89095
89292
  var kept2 = (dir) => busy(dir) || unsent(dir) || paused(dir);
89096
89293
  function clearAkb(dir) {
89097
89294
  dir = realpath2(dir);
89098
89295
  if (kept2(dir)) return false;
89099
89296
  let entries;
89100
89297
  try {
89101
- entries = fs14.readdirSync(akbDir(dir));
89298
+ entries = fs15.readdirSync(akbDir(dir));
89102
89299
  } catch {
89103
89300
  return true;
89104
89301
  }
89105
- for (const name of entries) fs14.rmSync(path17.join(akbDir(dir), name), { recursive: true, force: true });
89302
+ for (const name of entries) fs15.rmSync(path19.join(akbDir(dir), name), { recursive: true, force: true });
89106
89303
  spawnSync3("git", ["-C", dir, "worktree", "prune"], { stdio: "ignore" });
89107
89304
  return true;
89108
89305
  }
@@ -89117,7 +89314,7 @@ async function readAccess(machineId2) {
89117
89314
  }
89118
89315
  function realpath2(p2) {
89119
89316
  try {
89120
- return fs14.realpathSync(p2);
89317
+ return fs15.realpathSync(p2);
89121
89318
  } catch {
89122
89319
  return p2;
89123
89320
  }
@@ -89132,22 +89329,22 @@ async function sweepCache(machineId2, now = Date.now()) {
89132
89329
  const swept = [];
89133
89330
  let cached2 = [];
89134
89331
  try {
89135
- cached2 = fs14.readdirSync(cacheRoot(), { withFileTypes: true });
89332
+ cached2 = fs15.readdirSync(cacheRoot(), { withFileTypes: true });
89136
89333
  } catch {
89137
89334
  }
89138
89335
  for (const e2 of cached2) {
89139
- const dir = path17.join(cacheRoot(), e2.name);
89336
+ const dir = path19.join(cacheRoot(), e2.name);
89140
89337
  if (!e2.isDirectory() || kept2(dir)) continue;
89141
89338
  const gone = access && !access.projects.has(e2.name);
89142
89339
  if (idle(dir, now) || gone) {
89143
- fs14.rmSync(dir, { recursive: true, force: true });
89340
+ fs15.rmSync(dir, { recursive: true, force: true });
89144
89341
  swept.push(dir);
89145
89342
  }
89146
89343
  }
89147
89344
  for (const dir of allowedProjects()) {
89148
89345
  let held4 = [];
89149
89346
  try {
89150
- held4 = fs14.readdirSync(akbDir(dir));
89347
+ held4 = fs15.readdirSync(akbDir(dir));
89151
89348
  } catch {
89152
89349
  }
89153
89350
  if (!held4.length) continue;
@@ -89158,31 +89355,31 @@ async function sweepCache(machineId2, now = Date.now()) {
89158
89355
  }
89159
89356
  function removeLegacy() {
89160
89357
  const home4 = runnerHome();
89161
- for (const name of ["boards", "akb-bin"]) fs14.rmSync(path17.join(home4, name), { recursive: true, force: true });
89358
+ for (const name of ["boards", "akb-bin"]) fs15.rmSync(path19.join(home4, name), { recursive: true, force: true });
89162
89359
  let entries = [];
89163
89360
  try {
89164
- entries = fs14.readdirSync(home4, { withFileTypes: true });
89361
+ entries = fs15.readdirSync(home4, { withFileTypes: true });
89165
89362
  } catch {
89166
89363
  return;
89167
89364
  }
89168
89365
  for (const e2 of entries) {
89169
- const account = path17.join(home4, e2.name);
89170
- if (!e2.isDirectory() || !fs14.existsSync(path17.join(account, "unfiled"))) continue;
89171
- fs14.rmSync(path17.join(account, "unfiled"), { recursive: true, force: true });
89172
- if (!fs14.readdirSync(account).length) fs14.rmdirSync(account);
89366
+ const account = path19.join(home4, e2.name);
89367
+ if (!e2.isDirectory() || !fs15.existsSync(path19.join(account, "unfiled"))) continue;
89368
+ fs15.rmSync(path19.join(account, "unfiled"), { recursive: true, force: true });
89369
+ if (!fs15.readdirSync(account).length) fs15.rmdirSync(account);
89173
89370
  }
89174
89371
  }
89175
89372
 
89176
89373
  // src/update.ts
89177
- import crypto2 from "node:crypto";
89178
- import fs15 from "node:fs";
89179
- import path18 from "node:path";
89374
+ import crypto3 from "node:crypto";
89375
+ import fs16 from "node:fs";
89376
+ import path20 from "node:path";
89180
89377
  import zlib from "node:zlib";
89181
89378
  var TIMEOUT_MS2 = 6e4;
89182
89379
  var registry = () => (process.env.npm_config_registry || "https://registry.npmjs.org").replace(/\/+$/, "");
89183
89380
  async function installPackage(pkg, version, nodeVersion = process.versions.node) {
89184
89381
  const dir = pkg.dirOf(version);
89185
- if (fs15.existsSync(pkg.entryOf(dir))) return { ok: true, dir };
89382
+ if (fs16.existsSync(pkg.entryOf(dir))) return { ok: true, dir };
89186
89383
  let meta;
89187
89384
  let tarball;
89188
89385
  try {
@@ -89199,17 +89396,17 @@ async function installPackage(pkg, version, nodeVersion = process.versions.node)
89199
89396
  return { ok: false, why: "unreachable", detail: e2 instanceof Error ? e2.message : String(e2) };
89200
89397
  }
89201
89398
  const expected = /^sha512-(.+)$/.exec(meta.dist.integrity ?? "")?.[1];
89202
- const actual = crypto2.createHash("sha512").update(tarball).digest("base64");
89399
+ const actual = crypto3.createHash("sha512").update(tarball).digest("base64");
89203
89400
  if (!expected || expected !== actual) return { ok: false, why: "integrity", detail: "sha512 mismatch" };
89204
89401
  const staging = `${dir}.${process.pid}.tmp`;
89205
89402
  try {
89206
- fs15.rmSync(staging, { recursive: true, force: true });
89403
+ fs16.rmSync(staging, { recursive: true, force: true });
89207
89404
  extract(zlib.gunzipSync(tarball), staging);
89208
- if (!fs15.existsSync(pkg.entryOf(staging))) throw new Error(`the package carries no ${path18.relative(staging, pkg.entryOf(staging))}`);
89209
- fs15.rmSync(dir, { recursive: true, force: true });
89210
- fs15.renameSync(staging, dir);
89405
+ if (!fs16.existsSync(pkg.entryOf(staging))) throw new Error(`the package carries no ${path20.relative(staging, pkg.entryOf(staging))}`);
89406
+ fs16.rmSync(dir, { recursive: true, force: true });
89407
+ fs16.renameSync(staging, dir);
89211
89408
  } catch (e2) {
89212
- fs15.rmSync(staging, { recursive: true, force: true });
89409
+ fs16.rmSync(staging, { recursive: true, force: true });
89213
89410
  return { ok: false, why: "integrity", detail: e2 instanceof Error ? e2.message : String(e2) };
89214
89411
  }
89215
89412
  return { ok: true, dir };
@@ -89239,12 +89436,12 @@ function extract(tar, into) {
89239
89436
  if (type !== "0" && type !== "5") continue;
89240
89437
  const relative = name.replace(/^[^/]+\//, "");
89241
89438
  if (!relative) continue;
89242
- const target = path18.resolve(into, relative);
89243
- if (!target.startsWith(path18.resolve(into) + path18.sep)) throw new Error(`refusing ${name}`);
89244
- if (type === "5") fs15.mkdirSync(target, { recursive: true });
89439
+ const target = path20.resolve(into, relative);
89440
+ if (!target.startsWith(path20.resolve(into) + path20.sep)) throw new Error(`refusing ${name}`);
89441
+ if (type === "5") fs16.mkdirSync(target, { recursive: true });
89245
89442
  else {
89246
- fs15.mkdirSync(path18.dirname(target), { recursive: true });
89247
- fs15.writeFileSync(target, body);
89443
+ fs16.mkdirSync(path20.dirname(target), { recursive: true });
89444
+ fs16.writeFileSync(target, body);
89248
89445
  }
89249
89446
  }
89250
89447
  }
@@ -89292,33 +89489,33 @@ function meets(version, comparator) {
89292
89489
  // src/akb-version.ts
89293
89490
  var CHECK_MS2 = 1e4;
89294
89491
  var VERSION2 = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
89295
- var stateFile = () => path19.join(akbHome(), "state.json");
89296
- var akbVersionDir = (version) => path19.join(akbHome(), version);
89297
- var entryOf = (dir) => path19.join(dir, "bin", "ai4kanban.mjs");
89492
+ var stateFile = () => path21.join(akbHome(), "state.json");
89493
+ var akbVersionDir = (version) => path21.join(akbHome(), version);
89494
+ var entryOf = (dir) => path21.join(dir, "bin", "ai4kanban.mjs");
89298
89495
  var AKB = { name: "wildcrane", dirOf: akbVersionDir, entryOf };
89299
89496
  function readAkbState() {
89300
89497
  try {
89301
- const held4 = JSON.parse(fs16.readFileSync(stateFile(), "utf8"));
89498
+ const held4 = JSON.parse(fs17.readFileSync(stateFile(), "utf8"));
89302
89499
  return { current: held4.current ?? null, bad: held4.bad ?? [] };
89303
89500
  } catch {
89304
89501
  return { current: null, bad: [] };
89305
89502
  }
89306
89503
  }
89307
89504
  function writeAkbState(state) {
89308
- fs16.mkdirSync(akbHome(), { recursive: true });
89505
+ fs17.mkdirSync(akbHome(), { recursive: true });
89309
89506
  const staging = `${stateFile()}.${process.pid}.tmp`;
89310
- fs16.writeFileSync(staging, `${JSON.stringify(state, null, 2)}
89507
+ fs17.writeFileSync(staging, `${JSON.stringify(state, null, 2)}
89311
89508
  `);
89312
- fs16.renameSync(staging, stateFile());
89509
+ fs17.renameSync(staging, stateFile());
89313
89510
  }
89314
89511
  function contractOf(dir) {
89315
89512
  try {
89316
- return JSON.parse(fs16.readFileSync(path19.join(dir, "package.json"), "utf8")).akbContract ?? null;
89513
+ return JSON.parse(fs17.readFileSync(path21.join(dir, "package.json"), "utf8")).akbContract ?? null;
89317
89514
  } catch {
89318
89515
  return null;
89319
89516
  }
89320
89517
  }
89321
- var usable = (dir) => fs16.existsSync(entryOf(dir)) && contractOf(dir) === AKB_CONTRACT;
89518
+ var usable = (dir) => fs17.existsSync(entryOf(dir)) && contractOf(dir) === AKB_CONTRACT;
89322
89519
  function currentAkb() {
89323
89520
  const { current } = readAkbState();
89324
89521
  if (!current) return bundledAkb();
@@ -89326,10 +89523,10 @@ function currentAkb() {
89326
89523
  if (!usable(dir)) return bundledAkb();
89327
89524
  try {
89328
89525
  const now = /* @__PURE__ */ new Date();
89329
- fs16.utimesSync(dir, now, now);
89526
+ fs17.utimesSync(dir, now, now);
89330
89527
  } catch {
89331
89528
  }
89332
- return { command: process.execPath, args: [entryOf(dir)], version: current, shim: path19.join(dir, "shim") };
89529
+ return { command: process.execPath, args: [entryOf(dir)], version: current, shim: path21.join(dir, "shim") };
89333
89530
  }
89334
89531
  var answers2 = (dir, version) => new Promise((resolve2) => {
89335
89532
  execFile(process.execPath, [entryOf(dir), "--version"], { timeout: CHECK_MS2, killSignal: "SIGKILL" }, (error, stdout) => resolve2(!error && stdout.trim().split(/\s+/).at(-1) === version));
@@ -89369,20 +89566,20 @@ function sweepAkb(now = Date.now()) {
89369
89566
  const { current } = readAkbState();
89370
89567
  let entries = [];
89371
89568
  try {
89372
- entries = fs16.readdirSync(akbHome(), { withFileTypes: true });
89569
+ entries = fs17.readdirSync(akbHome(), { withFileTypes: true });
89373
89570
  } catch {
89374
89571
  return;
89375
89572
  }
89376
89573
  for (const e2 of entries) {
89377
89574
  if (!e2.isDirectory() || e2.name === current || e2.name === BUNDLED_SHIM) continue;
89378
- const dir = path19.join(akbHome(), e2.name);
89379
- if (now - fs16.statSync(dir).mtimeMs > IDLE_MS) fs16.rmSync(dir, { recursive: true, force: true });
89575
+ const dir = path21.join(akbHome(), e2.name);
89576
+ if (now - fs17.statSync(dir).mtimeMs > IDLE_MS) fs17.rmSync(dir, { recursive: true, force: true });
89380
89577
  }
89381
89578
  }
89382
89579
 
89383
89580
  // src/chats.ts
89384
- import fs18 from "node:fs";
89385
- import path21 from "node:path";
89581
+ import fs19 from "node:fs";
89582
+ import path23 from "node:path";
89386
89583
 
89387
89584
  // ../cloud/src/config.ts
89388
89585
  var CLAIM_LEASE_SECONDS = 15 * 60;
@@ -89398,18 +89595,18 @@ var CONTACT_ATTEMPT_WINDOW_SECONDS = 60 * 60;
89398
89595
  var CHAT_KEEP_DAYS = 30;
89399
89596
 
89400
89597
  // ../cli/src/lib/agent/task-chats.ts
89401
- import fs17 from "node:fs";
89402
- import path20 from "node:path";
89598
+ import fs18 from "node:fs";
89599
+ import path22 from "node:path";
89403
89600
  var TASK = /^[\w-]{1,100}$/;
89404
- var taskChatsDir = (home4 = machineHome()) => path20.join(home4, "chats");
89601
+ var taskChatsDir = (home4 = machineHome()) => path22.join(home4, "chats");
89405
89602
  function taskChatFile(task, home4) {
89406
89603
  if (!TASK.test(task)) throw new Error(`${task} is not a task id.`);
89407
- return path20.join(taskChatsDir(home4), `${task}.jsonl`);
89604
+ return path22.join(taskChatsDir(home4), `${task}.jsonl`);
89408
89605
  }
89409
89606
  function readTaskChat(task, home4) {
89410
89607
  let text3;
89411
89608
  try {
89412
- text3 = fs17.readFileSync(taskChatFile(task, home4), "utf8");
89609
+ text3 = fs18.readFileSync(taskChatFile(task, home4), "utf8");
89413
89610
  } catch {
89414
89611
  return [];
89415
89612
  }
@@ -89430,18 +89627,18 @@ var DAY_MS = 24 * 60 * 6e4;
89430
89627
  var REVIEW_EVERY_MS = DAY_MS;
89431
89628
  var KEEP_MS2 = CHAT_KEEP_DAYS * DAY_MS;
89432
89629
  var home3 = () => runnerHome();
89433
- var reviewedFile = () => path21.join(taskChatsDir(home3()), "reviewed.json");
89630
+ var reviewedFile = () => path23.join(taskChatsDir(home3()), "reviewed.json");
89434
89631
  function readReviewed() {
89435
89632
  try {
89436
- const held4 = JSON.parse(fs18.readFileSync(reviewedFile(), "utf8"));
89633
+ const held4 = JSON.parse(fs19.readFileSync(reviewedFile(), "utf8"));
89437
89634
  return { checkedAt: Number(held4.checkedAt) || 0, tasks: held4.tasks ?? {} };
89438
89635
  } catch {
89439
89636
  return { checkedAt: 0, tasks: {} };
89440
89637
  }
89441
89638
  }
89442
89639
  function writeReviewed(reviewed) {
89443
- fs18.mkdirSync(path21.dirname(reviewedFile()), { recursive: true });
89444
- fs18.writeFileSync(reviewedFile(), `${JSON.stringify(reviewed, null, 2)}
89640
+ fs19.mkdirSync(path23.dirname(reviewedFile()), { recursive: true });
89641
+ fs19.writeFileSync(reviewedFile(), `${JSON.stringify(reviewed, null, 2)}
89445
89642
  `);
89446
89643
  }
89447
89644
  function keepChat(job, reply, at2 = Date.now()) {
@@ -89451,16 +89648,16 @@ function keepChat(job, reply, at2 = Date.now()) {
89451
89648
  { id: job.id, role: "agent", text: reply, at: at2, runtime: job.runtime, model: job.model ?? null }
89452
89649
  ];
89453
89650
  const file2 = taskChatFile(job.task, home3());
89454
- fs18.mkdirSync(path21.dirname(file2), { recursive: true });
89455
- fs18.appendFileSync(file2, lines.map((l2) => `${JSON.stringify(l2)}
89651
+ fs19.mkdirSync(path23.dirname(file2), { recursive: true });
89652
+ fs19.appendFileSync(file2, lines.map((l2) => `${JSON.stringify(l2)}
89456
89653
  `).join(""));
89457
89654
  }
89458
89655
  function keepCloudChat(task, messages) {
89459
89656
  const file2 = taskChatFile(task, home3());
89460
- if (!messages.length) return fs18.rmSync(file2, { force: true });
89657
+ if (!messages.length) return fs19.rmSync(file2, { force: true });
89461
89658
  const lines = messages.map((m) => ({ id: m.id, role: m.role, text: m.body, at: Date.parse(m.created_at) || Date.now() }));
89462
- fs18.mkdirSync(path21.dirname(file2), { recursive: true });
89463
- fs18.writeFileSync(file2, lines.map((l2) => `${JSON.stringify(l2)}
89659
+ fs19.mkdirSync(path23.dirname(file2), { recursive: true });
89660
+ fs19.writeFileSync(file2, lines.map((l2) => `${JSON.stringify(l2)}
89464
89661
  `).join(""));
89465
89662
  }
89466
89663
  async function keepDecisions(task, read2) {
@@ -89478,13 +89675,13 @@ async function keepDecisions(task, read2) {
89478
89675
  const ids = new Set(comments.map((c2) => c2.id));
89479
89676
  const lines = [...readTaskChat(task, home3()).filter((l2) => !ids.has(l2.id)), ...comments].sort((a3, b2) => a3.at - b2.at);
89480
89677
  const file2 = taskChatFile(task, home3());
89481
- fs18.mkdirSync(path21.dirname(file2), { recursive: true });
89482
- fs18.writeFileSync(file2, lines.map((l2) => `${JSON.stringify(l2)}
89678
+ fs19.mkdirSync(path23.dirname(file2), { recursive: true });
89679
+ fs19.writeFileSync(file2, lines.map((l2) => `${JSON.stringify(l2)}
89483
89680
  `).join(""));
89484
89681
  }
89485
89682
  var tasksKept = () => {
89486
89683
  try {
89487
- return fs18.readdirSync(taskChatsDir(home3())).map((n) => /^([\w-]{1,100})\.jsonl$/.exec(n)?.[1]).filter((t2) => !!t2);
89684
+ return fs19.readdirSync(taskChatsDir(home3())).map((n) => /^([\w-]{1,100})\.jsonl$/.exec(n)?.[1]).filter((t2) => !!t2);
89488
89685
  } catch {
89489
89686
  return [];
89490
89687
  }
@@ -89495,9 +89692,9 @@ function pruneChats(now = Date.now()) {
89495
89692
  const kept4 = lines.filter((l2) => now - l2.at < KEEP_MS2);
89496
89693
  if (kept4.length === lines.length) continue;
89497
89694
  const file2 = taskChatFile(task, home3());
89498
- if (kept4.length) fs18.writeFileSync(file2, kept4.map((l2) => `${JSON.stringify(l2)}
89695
+ if (kept4.length) fs19.writeFileSync(file2, kept4.map((l2) => `${JSON.stringify(l2)}
89499
89696
  `).join(""));
89500
- else fs18.rmSync(file2, { force: true });
89697
+ else fs19.rmSync(file2, { force: true });
89501
89698
  }
89502
89699
  }
89503
89700
  var lastOf = (task) => readTaskChat(task, home3()).at(-1);
@@ -89535,28 +89732,28 @@ async function reviewChats(machineId2, runtimes, now = Date.now()) {
89535
89732
  }
89536
89733
 
89537
89734
  // src/board-watch.ts
89538
- import fs22 from "node:fs";
89539
- import path25 from "node:path";
89735
+ import fs23 from "node:fs";
89736
+ import path27 from "node:path";
89540
89737
 
89541
89738
  // ../cloud/src/board-files.ts
89542
89739
  var ROOTS = ["todo/", ".archive/", "memory/", "workflows/", "triage/", "assets/", "rules/"];
89543
89740
  var SETTINGS = ["modules.md", "config.md"];
89544
- var isSettingsPath = (path37) => SETTINGS.includes(path37) || /^rules\/(?:workflows\/)?[^/]+\.md$/.test(path37);
89741
+ var isSettingsPath = (path40) => SETTINGS.includes(path40) || /^rules\/(?:workflows\/)?[^/]+\.md$/.test(path40);
89545
89742
  var BOARD_FILE_LIMIT = 256 * 1024;
89546
- function isBoardPath(path37) {
89547
- if (!path37 || path37.length > 500 || path37.startsWith("/") || path37.includes("\\") || path37.includes("\0")) return false;
89548
- if (path37.split("/").some((part) => !part || part === "." || part === "..")) return false;
89549
- if (path37 === "todo/README.md" || path37.split("/").includes(".sync")) return false;
89550
- if (path37.startsWith("workflows/")) return true;
89551
- if (SETTINGS.includes(path37)) return true;
89552
- if (path37.startsWith("rules/")) return isSettingsPath(path37);
89553
- if (path37.startsWith("assets/")) return path37.endsWith(".json");
89554
- return ROOTS.some((root) => path37.startsWith(root)) && path37.endsWith(".md");
89743
+ function isBoardPath(path40) {
89744
+ if (!path40 || path40.length > 500 || path40.startsWith("/") || path40.includes("\\") || path40.includes("\0")) return false;
89745
+ if (path40.split("/").some((part) => !part || part === "." || part === "..")) return false;
89746
+ if (path40 === "todo/README.md" || path40.split("/").includes(".sync")) return false;
89747
+ if (path40.startsWith("workflows/")) return true;
89748
+ if (SETTINGS.includes(path40)) return true;
89749
+ if (path40.startsWith("rules/")) return isSettingsPath(path40);
89750
+ if (path40.startsWith("assets/")) return path40.endsWith(".json");
89751
+ return ROOTS.some((root) => path40.startsWith(root)) && path40.endsWith(".md");
89555
89752
  }
89556
89753
  var CARD = /^(?:todo|\.archive)\/(?:[^/]+\/)*(\d+)-[^/]*\.md$/;
89557
89754
  var ROOT = /^(?:todo|\.archive)\/(?:[^/]+\/)*(\d+)-[^/]+\/root\.md$/;
89558
- function numberOfCard(path37) {
89559
- const n = ROOT.exec(path37)?.[1] ?? CARD.exec(path37)?.[1];
89755
+ function numberOfCard(path40) {
89756
+ const n = ROOT.exec(path40)?.[1] ?? CARD.exec(path40)?.[1];
89560
89757
  return n ? Number(n) : null;
89561
89758
  }
89562
89759
  var cardSlug = (task) => task.toLowerCase().replace(/_/g, "-");
@@ -89764,9 +89961,9 @@ function collect(body, card, host) {
89764
89961
 
89765
89962
  // src/task-folder.ts
89766
89963
  import { spawnSync as spawnSync4 } from "node:child_process";
89767
- import crypto3 from "node:crypto";
89768
- import fs21 from "node:fs";
89769
- import path24 from "node:path";
89964
+ import crypto4 from "node:crypto";
89965
+ import fs22 from "node:fs";
89966
+ import path26 from "node:path";
89770
89967
 
89771
89968
  // node_modules/node-diff3/dist/diff3.mjs
89772
89969
  function LCS(buffer1, buffer2) {
@@ -90005,8 +90202,8 @@ function unquote2(v2) {
90005
90202
 
90006
90203
  // ../cloud/src/triage-files.ts
90007
90204
  var ITEM = /^triage\/(?:(dismissed|archived)\/)?([^/]+)\.md$/;
90008
- function itemAt(path37) {
90009
- const m = ITEM.exec(path37);
90205
+ function itemAt(path40) {
90206
+ const m = ITEM.exec(path40);
90010
90207
  if (!m) return null;
90011
90208
  return { state: m[1] === "dismissed" ? "dismissed" : m[1] === "archived" ? "carded" : "open", name: m[2] };
90012
90209
  }
@@ -90023,11 +90220,11 @@ function stampItem(content, fields) {
90023
90220
  }
90024
90221
 
90025
90222
  // ../cli/src/lib/agents/shared-memory.ts
90026
- import fs19 from "node:fs";
90027
- import path22 from "node:path";
90223
+ import fs20 from "node:fs";
90224
+ import path24 from "node:path";
90028
90225
 
90029
90226
  // ../cli/src/agents/builder/AGENT.md
90030
- var AGENT_default = "---\nname: builder\ndescription: \u5B9E\u73B0\u5E76\u843D\u5730\u5DF2\u6279\u51C6\u7684\u8F6F\u4EF6\u53D8\u66F4\u3002\n---\n\n- **\u5DF2\u6279\u51C6\u7684\u754C\u9762\u9884\u89C8**\uFF1A\u5B9E\u73B0\u5361\u7247\u9884\u89C8\u4E2D\u7684\u6BCF\u4E2A\u5C4F\u5E55\uFF0C\u5728\u684C\u9762\u548C\u624B\u673A\u5BBD\u5EA6\u4E0B\u9010\u4E00\u5BF9\u7167\u5E76\u4FEE\u6B63\u5DEE\u5F02\u3002\n- **\u5DF2\u6279\u51C6\u7684 API \u9884\u89C8**\uFF1A\u6309\u5361\u7247\u9884\u89C8\u5B9E\u73B0\u6BCF\u4E2A\u63A5\u53E3\uFF0C\u5E76\u636E\u6B64\u7F16\u5199\u6587\u6863\u3002\n- **\u5DF2\u6279\u51C6\u7684\u6570\u636E\u5E93\u9884\u89C8**\uFF1A\u7F16\u5199\u8FC1\u79FB\uFF0C\u4F7F\u6700\u7EC8\u7ED3\u6784\u4E0E\u5361\u7247\u6279\u51C6\u7684\u9884\u89C8\u4E00\u81F4\u3002\n- **\u5B8C\u6210\u8FB9\u754C**\uFF1A\u9664\u975E\u5361\u7247\u7684\u76EE\u6807\u672C\u8EAB\u5C31\u662F\u90E8\u7F72\u6216\u53D1\u5E03\uFF0C\u5426\u5219\u53D8\u66F4\u843D\u5730\u4E14\u68C0\u67E5\u901A\u8FC7\u5373\u5B8C\u6210\uFF1B\u4E0D\u8981\u4E3A\u5B8C\u6210\u4EFB\u52A1\u800C\u63A8\u9001\u3001\u90E8\u7F72\u6216\u53D1\u5E03\u3002\n- **\u9700\u8981\u4E0A\u7EBF\u7684\u4E8B\u9879**\uFF1A\u628A\u5FC5\u987B\u4E0A\u7EBF\u624D\u80FD\u8FDB\u884C\u7684\u9A8C\u8BC1\u6216\u6B65\u9AA4\u4EA4\u7ED9\u7528\u6237\uFF0C\u53EA\u5728\u6700\u7EC8\u56DE\u590D\u4E2D\u8BF4\u660E\uFF0C\u4E0D\u521B\u5EFA\u8DDF\u8FDB\u4EFB\u52A1\uFF0C\u4E5F\u4E0D\u63D0\u95EE\u3002\n- **\u68C0\u67E5**\uFF1A\u6B64\u540E\u6CA1\u6709\u4EBA\u518D\u5BA1\u67E5\u5B9E\u73B0\uFF1B\u8FD0\u884C\u53D7\u5F71\u54CD\u8DEF\u5F84\u7684\u9488\u5BF9\u6027\u68C0\u67E5\uFF0C\u4EE5\u53CA\u4ED3\u5E93\u8981\u6C42\u7684\u5168\u90E8\u68C0\u67E5\u3002\n";
90227
+ var AGENT_default = "---\nname: builder\ndescription: Implement and land approved software changes.\n---\n\n- **Autonomy**: Decide technical details within the approved scope and existing permissions. Diagnose build problems, fix them, verify the result, and continue; do not repeat the same failed attempt instead of investigating. Ask the user only for decisions or blockers only they can resolve.\n- **Approved UI previews**: Implement every screen in the approved previews, compare desktop and mobile layouts, and correct differences.\n- **Approved API previews**: Implement every approved endpoint and document it.\n- **Approved database previews**: Write migrations that match the approved structure.\n- **Completion**: Finish when changes have landed and checks pass, unless deployment or publication is the task's goal. Do not push, deploy, or publish merely to finish a task.\n- **Production steps**: Hand the user any steps or validation that require production access. Mention them only in the final response; create no follow-up tasks and ask no questions.\n- **Checks**: Nobody reviews the implementation after you. Run targeted checks for the affected paths and all checks the repository requires for the changes.\n";
90031
90228
 
90032
90229
  // ../cli/src/agents/api-designer/AGENT.md
90033
90230
  var AGENT_default2 = "---\nname: api-designer\ndescription: Writes the caller's documentation for the APIs a card changes.\nakb:\n when: A card adds or changes a surface a user or third party calls directly, such as HTTP routes, WebSocket messages, MCP tools, or CLI commands and flags. Not a protocol between the project's own components.\n i18n:\n en:\n title: API docs\n zh:\n title: \u63A5\u53E3\u6587\u6863\n description: \u4E3A\u5361\u7247\u6539\u52A8\u7684\u63A5\u53E3\u5199\u51FA\u8C03\u7528\u65B9\u6587\u6863\u3002\n when: \u5361\u7247\u65B0\u589E\u6216\u4FEE\u6539\u7528\u6237\u6216\u7B2C\u4E09\u65B9\u76F4\u63A5\u8C03\u7528\u7684\u63A5\u53E3\u65F6\uFF0C\u5982 HTTP \u8DEF\u7531\u3001WebSocket \u6D88\u606F\u3001MCP \u5DE5\u5177\u3001CLI \u547D\u4EE4\u548C\u53C2\u6570\u3002\u4E0D\u542B\u9879\u76EE\u81EA\u8EAB\u7EC4\u4EF6\u4E4B\u95F4\u7684\u534F\u8BAE\u3002\n---\n\nWrite each surface this card changes as the documentation entry that will be committed, in\nthe project's existing docs style: inputs, outputs, errors and one example call. Use a\n`diff` when an entry already exists, and a `mermaid` `sequenceDiagram` for a message\nexchange. One design, no alternatives, nothing else in the section.\n\n- **Glanceable**: a junior engineer understands each entry in one read. Plain names, short\n lines, no field or error the card does not change.\n";
@@ -90602,10 +90799,10 @@ function readScalar(value) {
90602
90799
  function readBlock(lines, start, parentIndent) {
90603
90800
  if (start >= lines.length || lines[start].indent <= parentIndent) return ["", start];
90604
90801
  const indent = lines[start].indent;
90605
- if (lines[start].text.startsWith("-")) return readList2(lines, start, indent);
90802
+ if (lines[start].text.startsWith("-")) return readList(lines, start, indent);
90606
90803
  return readMap(lines, start, indent);
90607
90804
  }
90608
- function readList2(lines, start, indent) {
90805
+ function readList(lines, start, indent) {
90609
90806
  const out = [];
90610
90807
  let i = start;
90611
90808
  while (i < lines.length && lines[i].indent === indent && lines[i].text.startsWith("-")) {
@@ -90757,16 +90954,16 @@ function sharedMemory(board) {
90757
90954
  const at2 = /^([^/]+)\/AGENT\.md$/.exec(key);
90758
90955
  if (at2) take(at2[1], text3, true);
90759
90956
  }
90760
- const root = path22.join(board, "agents");
90957
+ const root = path24.join(board, "agents");
90761
90958
  let folders2 = [];
90762
90959
  try {
90763
- folders2 = fs19.readdirSync(root, { withFileTypes: true }).filter((e2) => e2.isDirectory() && !e2.name.startsWith(".")).map((e2) => e2.name);
90960
+ folders2 = fs20.readdirSync(root, { withFileTypes: true }).filter((e2) => e2.isDirectory() && !e2.name.startsWith(".")).map((e2) => e2.name);
90764
90961
  } catch {
90765
90962
  }
90766
90963
  for (const folder of folders2.sort()) {
90767
90964
  let text3 = null;
90768
90965
  try {
90769
- text3 = fs19.readFileSync(path22.join(root, folder, "AGENT.md"), "utf8");
90966
+ text3 = fs20.readFileSync(path24.join(root, folder, "AGENT.md"), "utf8");
90770
90967
  } catch {
90771
90968
  }
90772
90969
  take(folder, text3, false);
@@ -90790,16 +90987,16 @@ function openTaskFolder(job, projectDir2) {
90790
90987
  projectDir2 ??= openCached(job.project);
90791
90988
  keepOutOfGit(projectDir2);
90792
90989
  markUsed(projectDir2);
90793
- const board = path24.join(projectDir2, ".akb", "kanban");
90794
- fs21.mkdirSync(board, { recursive: true });
90990
+ const board = path26.join(projectDir2, ".akb", "kanban");
90991
+ fs22.mkdirSync(board, { recursive: true });
90795
90992
  return { task, cloudTask: task, board, cwd: projectDir2, project: job.project, number: job.number ?? null, workflow: job.workflow ?? job.flow?.workflow ?? null };
90796
90993
  }
90797
90994
  function openAgentFolder(job, projectDir2) {
90798
90995
  if (!job.project || !job.agent) throw new Error("This job names no project.");
90799
90996
  keepOutOfGit(projectDir2);
90800
90997
  markUsed(projectDir2);
90801
- const board = path24.join(projectDir2, ".akb", "kanban");
90802
- fs21.mkdirSync(board, { recursive: true });
90998
+ const board = path26.join(projectDir2, ".akb", "kanban");
90999
+ fs22.mkdirSync(board, { recursive: true });
90803
91000
  return {
90804
91001
  task: `agent-${safe(job.agent.workflow ? `${job.agent.workflow}-${job.agent.name}` : job.agent.name)}`,
90805
91002
  cloudTask: job.agent.tasks?.[0]?.id ?? null,
@@ -90814,13 +91011,13 @@ function openDiscussionFolder(job, projectDir2) {
90814
91011
  if (!job.project) throw new Error("This job names no project.");
90815
91012
  keepOutOfGit(projectDir2);
90816
91013
  markUsed(projectDir2);
90817
- const board = path24.join(projectDir2, ".akb", "kanban");
90818
- fs21.mkdirSync(board, { recursive: true });
91014
+ const board = path26.join(projectDir2, ".akb", "kanban");
91015
+ fs22.mkdirSync(board, { recursive: true });
90819
91016
  return { task: "discussion", cloudTask: null, board, cwd: projectDir2, project: job.project, number: null, workflow: null };
90820
91017
  }
90821
91018
  var boardFolder = (ws) => ({ task: "board", cloudTask: null, board: ws.board, cwd: ws.cwd, project: ws.project, number: null, workflow: null });
90822
91019
  function keptBoard(cwd) {
90823
- const board = path24.join(cwd, ".akb", "kanban");
91020
+ const board = path26.join(cwd, ".akb", "kanban");
90824
91021
  const base = readBase({ cwd });
90825
91022
  const project = base.project ?? /^projects\/([^/]+)\//.exec(Object.keys(base.files).find((p2) => p2.startsWith("projects/")) ?? "")?.[1];
90826
91023
  return base.head_seq === null || !project ? null : boardFolder({ board, cwd, project });
@@ -90837,8 +91034,8 @@ function inFolder(dir, work) {
90837
91034
  var safe = (name) => name.replace(/[^\w.-]/g, "_") || "default";
90838
91035
  function openCached(project) {
90839
91036
  const dir = cacheDir(project);
90840
- if (fs21.existsSync(path24.join(dir, ".git"))) return dir;
90841
- fs21.mkdirSync(dir, { recursive: true });
91037
+ if (fs22.existsSync(path26.join(dir, ".git"))) return dir;
91038
+ fs22.mkdirSync(dir, { recursive: true });
90842
91039
  const git4 = (...args) => spawnSync4("git", ["-C", dir, ...args], { encoding: "utf8" }).status === 0;
90843
91040
  if (git4("init", "-q")) git4("-c", "user.name=WildCrane", "-c", "user.email=runner@wildcrane.ai", "commit", "-q", "--allow-empty", "-m", "general");
90844
91041
  return dir;
@@ -90851,56 +91048,56 @@ function keepOutOfGit(dir, folders2 = SKILL_FOLDERS) {
90851
91048
  if (inside.status !== 0) return;
90852
91049
  const missing = [".akb/", ...folders2.map((f2) => `${f2}/`)].filter((p2) => git4("check-ignore", "-q", p2).status !== 0);
90853
91050
  if (!missing.length) return;
90854
- const exclude = path24.resolve(dir, inside.stdout.trim());
90855
- fs21.mkdirSync(path24.dirname(exclude), { recursive: true });
90856
- const held4 = fs21.existsSync(exclude) ? fs21.readFileSync(exclude, "utf8") : "";
90857
- fs21.writeFileSync(exclude, `${held4}${held4 && !held4.endsWith("\n") ? "\n" : ""}${missing.join("\n")}
91051
+ const exclude = path26.resolve(dir, inside.stdout.trim());
91052
+ fs22.mkdirSync(path26.dirname(exclude), { recursive: true });
91053
+ const held4 = fs22.existsSync(exclude) ? fs22.readFileSync(exclude, "utf8") : "";
91054
+ fs22.writeFileSync(exclude, `${held4}${held4 && !held4.endsWith("\n") ? "\n" : ""}${missing.join("\n")}
90858
91055
  `);
90859
91056
  }
90860
- var cardFile = (ws) => (ws.number ? findCard(ws.board, ws.number) : null) ?? path24.join(ws.board, "todo", `${ws.number ?? 0}-task.md`);
91057
+ var cardFile = (ws) => (ws.number ? findCard(ws.board, ws.number) : null) ?? path26.join(ws.board, "todo", `${ws.number ?? 0}-task.md`);
90861
91058
  function findCard(board, number) {
90862
91059
  const named2 = new RegExp(`^${number}-`);
90863
91060
  const walk = (dir) => {
90864
91061
  let entries;
90865
91062
  try {
90866
- entries = fs21.readdirSync(dir, { withFileTypes: true });
91063
+ entries = fs22.readdirSync(dir, { withFileTypes: true });
90867
91064
  } catch {
90868
91065
  return null;
90869
91066
  }
90870
91067
  for (const e2 of entries) {
90871
91068
  if (!named2.test(e2.name)) continue;
90872
- if (e2.isFile() && e2.name.endsWith(".md")) return path24.join(dir, e2.name);
90873
- const root = path24.join(dir, e2.name, "root.md");
90874
- if (e2.isDirectory() && fs21.existsSync(root)) return root;
91069
+ if (e2.isFile() && e2.name.endsWith(".md")) return path26.join(dir, e2.name);
91070
+ const root = path26.join(dir, e2.name, "root.md");
91071
+ if (e2.isDirectory() && fs22.existsSync(root)) return root;
90875
91072
  }
90876
91073
  for (const e2 of entries) if (e2.isDirectory() && !e2.name.startsWith(".")) {
90877
- const hit = walk(path24.join(dir, e2.name));
91074
+ const hit = walk(path26.join(dir, e2.name));
90878
91075
  if (hit) return hit;
90879
91076
  }
90880
91077
  return null;
90881
91078
  };
90882
- return walk(path24.join(board, "todo")) ?? walk(path24.join(board, ".archive"));
91079
+ return walk(path26.join(board, "todo")) ?? walk(path26.join(board, ".archive"));
90883
91080
  }
90884
91081
  function akbCardOf(ws) {
90885
91082
  return ws.number && findCard(ws.board, ws.number) ? ws.number : void 0;
90886
91083
  }
90887
- var recordFile = (ws) => path24.join(ws.board, ".sync", `${ws.task}.json`);
91084
+ var recordFile = (ws) => path26.join(ws.board, ".sync", `${ws.task}.json`);
90888
91085
  function readRecord(ws) {
90889
91086
  try {
90890
- return { ...EMPTY, ...JSON.parse(fs21.readFileSync(recordFile(ws), "utf8")) };
91087
+ return { ...EMPTY, ...JSON.parse(fs22.readFileSync(recordFile(ws), "utf8")) };
90891
91088
  } catch {
90892
91089
  return structuredClone(EMPTY);
90893
91090
  }
90894
91091
  }
90895
91092
  function writeRecord(ws, record) {
90896
- fs21.mkdirSync(path24.dirname(recordFile(ws)), { recursive: true });
90897
- fs21.writeFileSync(recordFile(ws), `${JSON.stringify(record, null, 2)}
91093
+ fs22.mkdirSync(path26.dirname(recordFile(ws)), { recursive: true });
91094
+ fs22.writeFileSync(recordFile(ws), `${JSON.stringify(record, null, 2)}
90898
91095
  `);
90899
91096
  }
90900
- var baseFile = (ws) => path24.join(ws.cwd, ".akb", "base.json");
91097
+ var baseFile = (ws) => path26.join(ws.cwd, ".akb", "base.json");
90901
91098
  function readBase(ws) {
90902
91099
  try {
90903
- const base = JSON.parse(fs21.readFileSync(baseFile(ws), "utf8"));
91100
+ const base = JSON.parse(fs22.readFileSync(baseFile(ws), "utf8"));
90904
91101
  if (base.layout === "workspace") return base;
90905
91102
  } catch {
90906
91103
  }
@@ -90908,25 +91105,25 @@ function readBase(ws) {
90908
91105
  }
90909
91106
  function writeBase(ws, base) {
90910
91107
  const file2 = baseFile(ws);
90911
- fs21.mkdirSync(path24.dirname(file2), { recursive: true });
90912
- fs21.writeFileSync(`${file2}.tmp`, JSON.stringify(base));
90913
- fs21.renameSync(`${file2}.tmp`, file2);
91108
+ fs22.mkdirSync(path26.dirname(file2), { recursive: true });
91109
+ fs22.writeFileSync(`${file2}.tmp`, JSON.stringify(base));
91110
+ fs22.renameSync(`${file2}.tmp`, file2);
90914
91111
  }
90915
- var hashOf = (bytes2) => crypto3.createHash("sha256").update(bytes2).digest("hex");
91112
+ var hashOf = (bytes2) => crypto4.createHash("sha256").update(bytes2).digest("hex");
90916
91113
  function hashFile(file2) {
90917
91114
  try {
90918
- return hashOf(fs21.readFileSync(file2));
91115
+ return hashOf(fs22.readFileSync(file2));
90919
91116
  } catch {
90920
91117
  return null;
90921
91118
  }
90922
91119
  }
90923
91120
  function write(file2, bytes2) {
90924
- fs21.mkdirSync(path24.dirname(file2), { recursive: true });
90925
- fs21.writeFileSync(file2, bytes2);
91121
+ fs22.mkdirSync(path26.dirname(file2), { recursive: true });
91122
+ fs22.writeFileSync(file2, bytes2);
90926
91123
  }
90927
91124
  function readText(file2) {
90928
91125
  try {
90929
- return fs21.readFileSync(file2, "utf8");
91126
+ return fs22.readFileSync(file2, "utf8");
90930
91127
  } catch {
90931
91128
  return null;
90932
91129
  }
@@ -90934,14 +91131,14 @@ function readText(file2) {
90934
91131
  function filesUnder(dir, base = dir) {
90935
91132
  let entries;
90936
91133
  try {
90937
- entries = fs21.readdirSync(dir, { withFileTypes: true });
91134
+ entries = fs22.readdirSync(dir, { withFileTypes: true });
90938
91135
  } catch {
90939
91136
  return [];
90940
91137
  }
90941
91138
  return entries.flatMap((e2) => {
90942
- const full = path24.join(dir, e2.name);
91139
+ const full = path26.join(dir, e2.name);
90943
91140
  if (e2.isDirectory()) return filesUnder(full, base);
90944
- return e2.isFile() ? [path24.relative(base, full).split(path24.sep).join("/")] : [];
91141
+ return e2.isFile() ? [path26.relative(base, full).split(path26.sep).join("/")] : [];
90945
91142
  });
90946
91143
  }
90947
91144
  var kept3 = isBoardPath;
@@ -90957,18 +91154,18 @@ function viewOf(ws, base, shared) {
90957
91154
  }
90958
91155
  function assetFiles(ws, list) {
90959
91156
  const card = cardFile(ws);
90960
- return new Set(Object.keys(assetsOf(list)).map((name) => assetPath(ws, name, card)).filter((f2) => !!f2).map((f2) => path24.relative(ws.board, f2).split(path24.sep).join("/")));
91157
+ return new Set(Object.keys(assetsOf(list)).map((name) => assetPath(ws, name, card)).filter((f2) => !!f2).map((f2) => path26.relative(ws.board, f2).split(path26.sep).join("/")));
90961
91158
  }
90962
91159
  var assetsListOf = (ws, base) => base.files[rootOf(ws) + assetsFile(ws.task)]?.content;
90963
91160
  var localFiles = (ws, base) => {
90964
- const assets = /* @__PURE__ */ new Set([...assetFiles(ws, assetsListOf(ws, base)), ...assetFiles(ws, readText(path24.join(ws.board, assetsFile(ws.task))))]);
91161
+ const assets = /* @__PURE__ */ new Set([...assetFiles(ws, assetsListOf(ws, base)), ...assetFiles(ws, readText(path26.join(ws.board, assetsFile(ws.task))))]);
90965
91162
  return filesUnder(ws.board).filter((p2) => kept3(p2) && !assets.has(p2));
90966
91163
  };
90967
91164
  var SKILL_PATH = /^skills\/([a-z0-9]+(?:-[a-z0-9]+)*)\/((?:[\w.-]+\/)*[\w.-]+)$/;
90968
91165
  function pullTools(ws, record, files) {
90969
91166
  const held4 = record.tools?.skills ?? {};
90970
91167
  const ours = new Set(Object.keys(held4).map((name) => name.split("/")[1]));
90971
- const theirs = (skill) => !ours.has(skill) && SKILL_ROOTS.some((root) => fs21.existsSync(path24.join(ws.cwd, root, skill)));
91168
+ const theirs = (skill) => !ours.has(skill) && SKILL_ROOTS.some((root) => fs22.existsSync(path26.join(ws.cwd, root, skill)));
90972
91169
  const kept4 = Object.keys(files).map((name) => SKILL_PATH.exec(name)?.[1]).filter((skill) => skill && !theirs(skill));
90973
91170
  const skills = {};
90974
91171
  for (const [name, text3] of Object.entries(files)) {
@@ -90976,7 +91173,7 @@ function pullTools(ws, record, files) {
90976
91173
  if (!at2 || at2[1] === "kanban" || !kept4.includes(at2[1]) || at2[2].split("/").includes("..")) continue;
90977
91174
  skills[name] = hashOf(text3);
90978
91175
  for (const root of SKILL_ROOTS) {
90979
- const file2 = path24.join(ws.cwd, root, at2[1], at2[2]);
91176
+ const file2 = path26.join(ws.cwd, root, at2[1], at2[2]);
90980
91177
  if (held4[name] !== skills[name] || hashFile(file2) !== skills[name]) write(file2, text3);
90981
91178
  }
90982
91179
  }
@@ -90985,8 +91182,8 @@ function pullTools(ws, record, files) {
90985
91182
  const [, skill, rest] = SKILL_PATH.exec(name) ?? [];
90986
91183
  if (!skill || !rest) continue;
90987
91184
  for (const root of SKILL_ROOTS) {
90988
- fs21.rmSync(path24.join(ws.cwd, root, skill, rest), { force: true });
90989
- if (!Object.keys(skills).some((n) => n.startsWith(`skills/${skill}/`))) fs21.rmSync(path24.join(ws.cwd, root, skill), { recursive: true, force: true });
91185
+ fs22.rmSync(path26.join(ws.cwd, root, skill, rest), { force: true });
91186
+ if (!Object.keys(skills).some((n) => n.startsWith(`skills/${skill}/`))) fs22.rmSync(path26.join(ws.cwd, root, skill), { recursive: true, force: true });
90990
91187
  }
90991
91188
  }
90992
91189
  const names2 = [...new Set(Object.keys(skills).map((name) => name.split("/")[1]))];
@@ -91014,7 +91211,7 @@ async function pullWorkflow(ws, record, base) {
91014
91211
  files = read2.value.files;
91015
91212
  found = true;
91016
91213
  if (!record.builtin) {
91017
- for (const [name, text3] of Object.entries(files)) if (isBoardPath(root + name)) write(path24.join(ws.board, root, name), text3);
91214
+ for (const [name, text3] of Object.entries(files)) if (isBoardPath(root + name)) write(path26.join(ws.board, root, name), text3);
91018
91215
  }
91019
91216
  }
91020
91217
  }
@@ -91022,14 +91219,14 @@ async function pullWorkflow(ws, record, base) {
91022
91219
  }
91023
91220
  pullAgents(ws, base, ws.workflow && !record.builtin ? files : {});
91024
91221
  const placed = readPlaced(ws);
91025
- for (const name of Object.keys(record.agents ?? {})) if (!placed[name]) fs21.rmSync(path24.join(ws.board, name), { force: true });
91222
+ for (const name of Object.keys(record.agents ?? {})) if (!placed[name]) fs22.rmSync(path26.join(ws.board, name), { force: true });
91026
91223
  record.agents = {};
91027
91224
  return { ok: true, value: void 0 };
91028
91225
  }
91029
- var agentsRecord = (ws) => path24.join(ws.board, ".sync", "agents.json");
91226
+ var agentsRecord = (ws) => path26.join(ws.board, ".sync", "agents.json");
91030
91227
  function readPlaced(ws) {
91031
91228
  try {
91032
- return JSON.parse(fs21.readFileSync(agentsRecord(ws), "utf8"));
91229
+ return JSON.parse(fs22.readFileSync(agentsRecord(ws), "utf8"));
91033
91230
  } catch {
91034
91231
  return {};
91035
91232
  }
@@ -91050,8 +91247,8 @@ function pullAgents(ws, base, own) {
91050
91247
  const names2 = /* @__PURE__ */ new Set();
91051
91248
  for (const [name, text3] of Object.entries(files)) {
91052
91249
  const agent = /^agents\/([^/]+)\//.exec(name)?.[1];
91053
- const file2 = path24.resolve(ws.board, name);
91054
- if (!agent || taken.has(agent) || !file2.startsWith(path24.join(ws.board, "agents") + path24.sep)) continue;
91250
+ const file2 = path26.resolve(ws.board, name);
91251
+ if (!agent || taken.has(agent) || !file2.startsWith(path26.join(ws.board, "agents") + path26.sep)) continue;
91055
91252
  names2.add(agent);
91056
91253
  agents[name] = text3;
91057
91254
  }
@@ -91061,51 +91258,51 @@ function pullAgents(ws, base, own) {
91061
91258
  const hashes = {};
91062
91259
  for (const [name, text3] of Object.entries(agents)) {
91063
91260
  hashes[name] = hashOf(text3);
91064
- if (hashFile(path24.join(ws.board, name)) !== hashes[name]) write(path24.join(ws.board, name), text3);
91261
+ if (hashFile(path26.join(ws.board, name)) !== hashes[name]) write(path26.join(ws.board, name), text3);
91065
91262
  }
91066
- for (const name of Object.keys(before)) if (!hashes[name]) fs21.rmSync(path24.join(ws.board, name), { force: true });
91263
+ for (const name of Object.keys(before)) if (!hashes[name]) fs22.rmSync(path26.join(ws.board, name), { force: true });
91067
91264
  write(agentsRecord(ws), `${JSON.stringify(hashes, null, 2)}
91068
91265
  `);
91069
91266
  }
91070
91267
  function pullDraftAgents(ws, record) {
91071
91268
  if (ws.workflow !== BUILDER) return;
91072
- const root = path24.join(ws.board, "workflows", draftFolder(ws.task), "agents");
91269
+ const root = path26.join(ws.board, "workflows", draftFolder(ws.task), "agents");
91073
91270
  record.agents ??= {};
91074
91271
  for (const name of filesUnder(root)) {
91075
- const text3 = fs21.readFileSync(path24.join(root, name));
91272
+ const text3 = fs22.readFileSync(path26.join(root, name));
91076
91273
  const at2 = `agents/${name}`;
91077
91274
  record.agents[at2] = hashOf(text3);
91078
- if (hashFile(path24.join(ws.board, at2)) !== record.agents[at2]) write(path24.join(ws.board, at2), text3);
91275
+ if (hashFile(path26.join(ws.board, at2)) !== record.agents[at2]) write(path26.join(ws.board, at2), text3);
91079
91276
  }
91080
91277
  }
91081
91278
  function workflowFile(ws) {
91082
91279
  if (!ws.workflow || readRecord(ws).builtin) return null;
91083
- const file2 = path24.join(ws.board, "workflows", workflowFolder(ws.workflow), "WORKFLOW.md");
91084
- return fs21.existsSync(file2) ? file2 : null;
91280
+ const file2 = path26.join(ws.board, "workflows", workflowFolder(ws.workflow), "WORKFLOW.md");
91281
+ return fs22.existsSync(file2) ? file2 : null;
91085
91282
  }
91086
91283
  function assetPath(ws, name, owner) {
91087
91284
  if (/^[a-z][\w+.-]*:/i.test(name) || name.startsWith("#") || name.startsWith("//")) return null;
91088
- if (path24.isAbsolute(name)) throw new Error("\u8D44\u6E90\u8DEF\u5F84\u4E0D\u80FD\u662F\u7EDD\u5BF9\u8DEF\u5F84");
91285
+ if (path26.isAbsolute(name)) throw new Error("\u8D44\u6E90\u8DEF\u5F84\u4E0D\u80FD\u662F\u7EDD\u5BF9\u8DEF\u5F84");
91089
91286
  const held4 = /^\.(assets|mockups)\//.exec(name);
91090
91287
  const state = stateDir(ws);
91091
- const root = held4 && state ? path24.join(state, held4[1]) : ws.board;
91092
- const file2 = held4 && state ? path24.resolve(root, name.slice(held4[0].length)) : path24.resolve(path24.dirname(owner), name);
91093
- const roots = [ws.board, ...state ? ["assets", "mockups"].map((folder) => path24.join(state, folder, ...ws.number ? [String(ws.number)] : [])) : []];
91094
- const inside = (file3, root2) => file3.startsWith(root2 + path24.sep);
91288
+ const root = held4 && state ? path26.join(state, held4[1]) : ws.board;
91289
+ const file2 = held4 && state ? path26.resolve(root, name.slice(held4[0].length)) : path26.resolve(path26.dirname(owner), name);
91290
+ const roots = [ws.board, ...state ? ["assets", "mockups"].map((folder) => path26.join(state, folder, ...ws.number ? [String(ws.number)] : [])) : []];
91291
+ const inside = (file3, root2) => file3.startsWith(root2 + path26.sep);
91095
91292
  if (!roots.some((root2) => inside(file2, root2))) throw new Error("\u8D44\u6E90\u8DEF\u5F84\u8D8A\u754C");
91096
91293
  let existing = file2;
91097
- while (!fs21.existsSync(existing) && path24.dirname(existing) !== existing) existing = path24.dirname(existing);
91098
- const real = fs21.realpathSync(existing);
91294
+ while (!fs22.existsSync(existing) && path26.dirname(existing) !== existing) existing = path26.dirname(existing);
91295
+ const real = fs22.realpathSync(existing);
91099
91296
  let stateParent = state;
91100
- while (stateParent && !fs21.existsSync(stateParent) && path24.dirname(stateParent) !== stateParent) stateParent = path24.dirname(stateParent);
91101
- const realState = state && stateParent ? path24.resolve(fs21.realpathSync(stateParent), path24.relative(stateParent, state)) : null;
91102
- const realRoots = [fs21.realpathSync(ws.board), ...realState ? ["assets", "mockups"].map((folder) => path24.join(realState, folder, ...ws.number ? [String(ws.number)] : [])) : []];
91297
+ while (stateParent && !fs22.existsSync(stateParent) && path26.dirname(stateParent) !== stateParent) stateParent = path26.dirname(stateParent);
91298
+ const realState = state && stateParent ? path26.resolve(fs22.realpathSync(stateParent), path26.relative(stateParent, state)) : null;
91299
+ const realRoots = [fs22.realpathSync(ws.board), ...realState ? ["assets", "mockups"].map((folder) => path26.join(realState, folder, ...ws.number ? [String(ws.number)] : [])) : []];
91103
91300
  if (!realRoots.some((root2) => real === root2 || inside(real, root2))) throw new Error("\u7B26\u53F7\u94FE\u63A5\u8D8A\u754C");
91104
91301
  return file2;
91105
91302
  }
91106
91303
  function cardAssetsDir(ws, id) {
91107
91304
  const state = stateDir(ws);
91108
- return state && path24.join(state, "assets", String(id));
91305
+ return state && path26.join(state, "assets", String(id));
91109
91306
  }
91110
91307
  function stateDir(ws) {
91111
91308
  try {
@@ -91144,13 +91341,13 @@ var pullChanges = (ws) => inFolder(ws.cwd, async () => {
91144
91341
  const p2 = f2.path.startsWith(root) ? f2.path.slice(root.length) : f2.path;
91145
91342
  const isShared = p2.startsWith(MEMORY2) && shared(p2.slice(MEMORY2.length));
91146
91343
  if (kept3(p2) && isShared === !f2.path.startsWith(root)) {
91147
- const file2 = path24.join(ws.board, p2);
91344
+ const file2 = path26.join(ws.board, p2);
91148
91345
  const here = readText(file2);
91149
91346
  if (here !== f2.content && here !== (base.files[f2.path]?.content ?? null)) {
91150
91347
  skipped = true;
91151
91348
  continue;
91152
91349
  }
91153
- if (f2.content === null) fs21.rmSync(file2, { force: true });
91350
+ if (f2.content === null) fs22.rmSync(file2, { force: true });
91154
91351
  else if (here !== f2.content) write(file2, f2.content);
91155
91352
  }
91156
91353
  if (f2.content === null) delete base.files[f2.path];
@@ -91181,13 +91378,13 @@ async function readCloud(ws) {
91181
91378
  writeBase(ws, base);
91182
91379
  const reset = (view2) => {
91183
91380
  for (const [p2, content] of view2) {
91184
- const file2 = path24.join(ws.board, p2);
91381
+ const file2 = path26.join(ws.board, p2);
91185
91382
  if (kept3(p2) && readText(file2) !== content) write(file2, content);
91186
91383
  }
91187
91384
  };
91188
91385
  const view = viewOf(ws, base, sharedMemory(ws.board));
91189
91386
  const first = (p2) => isSettingsPath(p2) && !known2.has(rootOf(ws) + p2);
91190
- for (const p2 of localFiles(ws, base)) if (!view.has(p2) && !first(p2)) fs21.rmSync(path24.join(ws.board, p2), { force: true });
91387
+ for (const p2 of localFiles(ws, base)) if (!view.has(p2) && !first(p2)) fs22.rmSync(path26.join(ws.board, p2), { force: true });
91191
91388
  reset(view);
91192
91389
  const record = readRecord(ws);
91193
91390
  const workflow = await pullWorkflow(ws, record, base);
@@ -91201,18 +91398,18 @@ async function readCloud(ws) {
91201
91398
  return { ok: true, value: void 0 };
91202
91399
  }
91203
91400
  function writeIndex(board) {
91204
- const todo = path24.join(board, "todo");
91401
+ const todo = path26.join(board, "todo");
91205
91402
  const cards = [];
91206
91403
  let entries = [];
91207
91404
  try {
91208
- entries = fs21.readdirSync(todo, { withFileTypes: true });
91405
+ entries = fs22.readdirSync(todo, { withFileTypes: true });
91209
91406
  } catch {
91210
91407
  }
91211
91408
  for (const e2 of entries) {
91212
91409
  const id = /^(\d+)-/.exec(e2.name)?.[1];
91213
91410
  if (!id) continue;
91214
91411
  const link = e2.isDirectory() ? `${e2.name}/root.md` : e2.name.endsWith(".md") ? e2.name : null;
91215
- const text4 = link && readText(path24.join(todo, link));
91412
+ const text4 = link && readText(path26.join(todo, link));
91216
91413
  if (text4 === null || !link) continue;
91217
91414
  cards.push({ id: Number(id), title: cardFront(text4).title ?? e2.name.replace(/\.md$/, ""), link });
91218
91415
  }
@@ -91227,7 +91424,7 @@ the number at the front of a filename is the task id.
91227
91424
 
91228
91425
  ${list}
91229
91426
  `;
91230
- if (readText(path24.join(todo, "README.md")) !== text3) write(path24.join(todo, "README.md"), text3);
91427
+ if (readText(path26.join(todo, "README.md")) !== text3) write(path26.join(todo, "README.md"), text3);
91231
91428
  }
91232
91429
  var workspaceOf = (ws) => readBase(ws).workspace ?? null;
91233
91430
  async function pullAssets(ws, record, assets) {
@@ -91235,51 +91432,74 @@ async function pullAssets(ws, record, assets) {
91235
91432
  record.task = ws.cloudTask;
91236
91433
  record.number = ws.number;
91237
91434
  }
91238
- const isCompare = (value) => !!value && typeof value === "object" && "a" in value && "b" in value;
91239
91435
  const file2 = cardFile(ws);
91240
91436
  const out = {};
91241
91437
  for (const [name, ref] of Object.entries(assets)) {
91242
91438
  const target = assetPath(ws, name, file2);
91243
91439
  if (!target) continue;
91440
+ const held4 = record.assets[name];
91441
+ let kind = held4?.artifact === ref.artifact ? held4.kind : void 0;
91244
91442
  let version = ref.version;
91245
- if (version === void 0) {
91443
+ const localHash = hashFile(target);
91444
+ const current = held4?.artifact === ref.artifact && held4.version === version && localHash === (held4.localHash ?? held4.hash);
91445
+ if (version === void 0 || !kind || !current && kind !== "html") {
91246
91446
  const latest = await readArtifact(ref.artifact);
91247
91447
  if (!latest.ok) return latest;
91248
- version = latest.value.latest_version ?? 0;
91448
+ version ??= latest.value.latest_version ?? 0;
91449
+ kind = latest.value.type;
91450
+ if (!kind) return { ok: false, code: "bad_request", error: `${name}: \u8D44\u6E90\u7C7B\u578B\u7F3A\u5931` };
91249
91451
  }
91250
- const held4 = record.assets[name];
91251
- if (held4?.kind === "html" && held4.artifact === ref.artifact) {
91252
- out[name] = { ...held4, version };
91452
+ if (kind === "html" && held4?.artifact === ref.artifact) {
91453
+ out[name] = { ...held4, kind, version };
91253
91454
  continue;
91254
91455
  }
91255
- if (held4?.artifact === ref.artifact && held4.version === version && hashFile(target) === (held4.localHash ?? held4.hash)) {
91256
- out[name] = held4;
91456
+ if (held4?.artifact === ref.artifact && held4.version === version && current) {
91457
+ out[name] = { ...held4, kind };
91257
91458
  continue;
91258
91459
  }
91259
91460
  const bytes2 = await readAsset(ref.artifact, version);
91260
91461
  if (!bytes2.ok) return bytes2;
91261
91462
  let local = bytes2.value;
91262
- let kind = held4?.kind;
91263
91463
  const dependencies = [];
91264
- if (/\.json$/i.test(target)) {
91464
+ if (kind === "storyboard" || kind === "compare") {
91465
+ let data;
91265
91466
  try {
91266
- const data = JSON.parse(Buffer.from(local).toString());
91467
+ data = JSON.parse(Buffer.from(local).toString());
91468
+ } catch {
91469
+ }
91470
+ if (data !== void 0) {
91471
+ let changed = false;
91267
91472
  const restore = (src) => {
91268
91473
  const name2 = Object.entries(assets).find(([, r2]) => r2.artifact === src)?.[0];
91269
- if (name2) dependencies.push(name2);
91270
91474
  if (!name2) return src;
91271
- if (/^\.(assets|mockups)\//.test(name2)) return name2;
91272
91475
  const child = assetPath(ws, name2, file2);
91273
- return child ? path24.relative(path24.dirname(target), child).split(path24.sep).join("/") : src;
91476
+ if (!child) return src;
91477
+ dependencies.push(name2);
91478
+ const restored2 = /^\.(assets|mockups)\//.test(name2) ? name2 : path26.relative(path26.dirname(target), child).split(path26.sep).join("/");
91479
+ if (restored2 !== src) changed = true;
91480
+ return restored2;
91274
91481
  };
91275
- const restored = mapReferences(mapReferences(data, "storyboard", restore), "compare", restore);
91276
- if (dependencies.length) kind = isCompare(data) ? "compare" : "storyboard";
91277
- local = Buffer.from(JSON.stringify(restored));
91278
- } catch {
91482
+ const restored = mapReferences(data, kind, restore);
91483
+ if (changed) local = Buffer.from(JSON.stringify(restored));
91484
+ }
91485
+ }
91486
+ if (held4?.artifact === ref.artifact && held4.version === version && !held4.localHash && (kind === "storyboard" || kind === "compare")) {
91487
+ const source = readText(target);
91488
+ if (source !== null) {
91489
+ let same = false;
91490
+ try {
91491
+ same = JSON.stringify(JSON.parse(source)) === JSON.stringify(JSON.parse(Buffer.from(local).toString()));
91492
+ } catch {
91493
+ }
91494
+ if (!same) {
91495
+ out[name] = { ...held4, kind };
91496
+ continue;
91497
+ }
91498
+ local = Buffer.from(source);
91279
91499
  }
91280
91500
  }
91281
91501
  write(target, local);
91282
- out[name] = { ...held4, kind, dependencies: dependencies.length ? [...new Set(dependencies)] : held4?.dependencies, artifact: ref.artifact, version, hash: hashOf(bytes2.value), localHash: hashOf(local) };
91502
+ out[name] = { ...held4, kind, dependencies: [...new Set(dependencies)], artifact: ref.artifact, version, hash: hashOf(bytes2.value), localHash: hashOf(local) };
91283
91503
  }
91284
91504
  record.assets = out;
91285
91505
  return { ok: true, value: void 0 };
@@ -91292,14 +91512,14 @@ async function readAsset(artifact, version) {
91292
91512
  return { ok: true, value: Buffer.from(typeof content === "string" ? content : JSON.stringify(content)) };
91293
91513
  }
91294
91514
  async function sentOf(file2) {
91295
- const ext = path24.extname(file2).toLowerCase();
91515
+ const ext = path26.extname(file2).toLowerCase();
91296
91516
  const kind = kindOf(ext);
91297
- if (kind !== "html") return { bytes: fs21.readFileSync(file2), type: TYPES[ext] ?? "application/octet-stream", kind };
91517
+ if (kind !== "html") return { bytes: fs22.readFileSync(file2), type: TYPES[ext] ?? "application/octet-stream", kind };
91298
91518
  let page;
91299
91519
  try {
91300
91520
  page = await (await Promise.resolve().then(() => (init_mockup(), mockup_exports))).drawMockup(file2);
91301
91521
  } catch (e2) {
91302
- console.error(`runner: ${path24.basename(file2)} could not be drawn: ${e2 instanceof Error ? e2.message : String(e2)}`);
91522
+ console.error(`runner: ${path26.basename(file2)} could not be drawn: ${e2 instanceof Error ? e2.message : String(e2)}`);
91303
91523
  page = UNDRAWN;
91304
91524
  }
91305
91525
  return { bytes: Buffer.from(page), type: "text/html", kind };
@@ -91324,14 +91544,14 @@ async function pushAssets(ws, record, before) {
91324
91544
  if (body === null) return { ok: true, value: void 0 };
91325
91545
  const refs = {};
91326
91546
  const canonical = (target) => {
91327
- const real = (file3) => fs21.existsSync(file3) ? fs21.realpathSync(file3) : file3;
91547
+ const real = (file3) => fs22.existsSync(file3) ? fs22.realpathSync(file3) : file3;
91328
91548
  target = real(target);
91329
91549
  const state = stateDir(ws);
91330
91550
  for (const folder of ["assets", "mockups"]) {
91331
- const root = state && real(path24.join(state, folder));
91332
- if (root && target.startsWith(root + path24.sep)) return `.${folder}/${path24.relative(root, target).split(path24.sep).join("/")}`;
91551
+ const root = state && real(path26.join(state, folder));
91552
+ if (root && target.startsWith(root + path26.sep)) return `.${folder}/${path26.relative(root, target).split(path26.sep).join("/")}`;
91333
91553
  }
91334
- return path24.relative(real(path24.dirname(file2)), target).split(path24.sep).join("/");
91554
+ return path26.relative(real(path26.dirname(file2)), target).split(path26.sep).join("/");
91335
91555
  };
91336
91556
  try {
91337
91557
  const graph = collect(body, file2, {
@@ -91341,13 +91561,13 @@ async function pushAssets(ws, record, before) {
91341
91561
  const target = assetPath(ws, src, owner);
91342
91562
  if (!target) return null;
91343
91563
  const key = owner === file2 && before[src] ? src : canonical(target);
91344
- if (!fs21.statSync(target, { throwIfNoEntry: false })?.isFile()) {
91564
+ if (!fs22.statSync(target, { throwIfNoEntry: false })?.isFile()) {
91345
91565
  if (before[key]) return { key, file: null };
91346
91566
  throw new Error("\u660E\u786E\u5F15\u7528\u7684\u8D44\u6E90\u6587\u4EF6\u4E0D\u5B58\u5728");
91347
91567
  }
91348
- return { key: canonical(fs21.realpathSync(target)), file: target };
91568
+ return { key: canonical(fs22.realpathSync(target)), file: target };
91349
91569
  },
91350
- readJSON: (target) => JSON.parse(fs21.readFileSync(target, "utf8")),
91570
+ readJSON: (target) => JSON.parse(fs22.readFileSync(target, "utf8")),
91351
91571
  retained: (key) => (record.assets[key]?.dependencies ?? []).map((src) => {
91352
91572
  const kind = record.assets[src]?.kind;
91353
91573
  return { src, purpose: kind === "storyboard" || kind === "compare" ? kind : "asset" };
@@ -91368,6 +91588,13 @@ async function pushAssets(ws, record, before) {
91368
91588
  }
91369
91589
  continue;
91370
91590
  }
91591
+ const kind = node.kind === "asset" ? kindOf(path26.extname(node.file).toLowerCase()) : node.kind;
91592
+ if (previous && previous.kind !== kind) {
91593
+ const artifact = await readArtifact(previous.artifact);
91594
+ if (!artifact.ok) return artifact;
91595
+ if (!artifact.value.type) return { ok: false, code: "bad_request", error: `${node.key}: \u8D44\u6E90\u7C7B\u578B\u7F3A\u5931` };
91596
+ previous.kind = artifact.value.type;
91597
+ }
91371
91598
  let out = await sentOf(node.file);
91372
91599
  if (node.kind !== "asset") {
91373
91600
  const data = mapReferences(node.data, node.kind, (src) => {
@@ -91378,9 +91605,12 @@ async function pushAssets(ws, record, before) {
91378
91605
  }
91379
91606
  const hash = hashOf(out.bytes);
91380
91607
  let entry = previous;
91381
- if (!entry || entry.hash !== hash || entry.kind && entry.kind !== out.kind) {
91608
+ const localHash = hashFile(node.file);
91609
+ const restored = node.kind !== "asset" || out.kind === "html" && previous?.hash === localHash;
91610
+ const unchanged = restored && previous && (previous.kind ?? out.kind) === out.kind && localHash === (previous.localHash ?? previous.hash) && [...node.dependencies.values()].every((key) => refs[key]?.artifact === before[key]?.artifact);
91611
+ if (!entry || !unchanged && entry.hash !== hash || entry.kind && entry.kind !== out.kind) {
91382
91612
  if (!ws.cloudTask) continue;
91383
- let artifact = previous && (previous.kind ?? kindOf(path24.extname(node.file).toLowerCase())) === out.kind ? previous.artifact : void 0;
91613
+ let artifact = previous && (previous.kind ?? kindOf(path26.extname(node.file).toLowerCase())) === out.kind ? previous.artifact : void 0;
91384
91614
  if (!artifact) {
91385
91615
  const made = await createArtifact(ws.cloudTask, node.key.slice(0, 200), out.kind);
91386
91616
  if (!made.ok) return { ...made, error: `${node.key}: ${made.error}` };
@@ -91390,7 +91620,7 @@ async function pushAssets(ws, record, before) {
91390
91620
  if (!sent.ok) return { ...sent, error: `${node.key}: ${sent.error}` };
91391
91621
  entry = { artifact, version: sent.value, hash, kind: out.kind };
91392
91622
  }
91393
- entry = { ...entry, localHash: hashFile(node.file) ?? void 0, dependencies: [...node.dependencies.values()] };
91623
+ entry = { ...entry, localHash: localHash ?? void 0, dependencies: [...node.dependencies.values()] };
91394
91624
  for (const alias of node.aliases) {
91395
91625
  record.assets[alias] = entry;
91396
91626
  refs[alias] = { artifact: entry.artifact, version: entry.version };
@@ -91400,24 +91630,24 @@ async function pushAssets(ws, record, before) {
91400
91630
  } catch (error) {
91401
91631
  return { ok: false, code: "bad_request", error: error instanceof Error ? error.message : String(error) };
91402
91632
  }
91403
- const list = path24.join(ws.board, assetsFile(ws.task));
91404
- if (Object.keys(refs).length || fs21.existsSync(list)) {
91633
+ const list = path26.join(ws.board, assetsFile(ws.task));
91634
+ if (Object.keys(refs).length || fs22.existsSync(list)) {
91405
91635
  if (JSON.stringify(assetsOf(readText(list))) !== JSON.stringify(refs)) write(list, assetsText(refs));
91406
91636
  }
91407
91637
  return { ok: true, value: void 0 };
91408
91638
  }
91409
91639
  function resetSorted(ws) {
91410
- for (const sub of ["dismissed", "archived"]) fs21.rmSync(path24.join(ws.board, "triage", sub), { recursive: true, force: true });
91640
+ for (const sub of ["dismissed", "archived"]) fs22.rmSync(path26.join(ws.board, "triage", sub), { recursive: true, force: true });
91411
91641
  for (const [p2, content] of viewOf(ws, readBase(ws), sharedMemory(ws.board))) {
91412
- if (/^triage\/(?:dismissed|archived)\//.test(p2)) write(path24.join(ws.board, p2), content);
91642
+ if (/^triage\/(?:dismissed|archived)\//.test(p2)) write(path26.join(ws.board, p2), content);
91413
91643
  }
91414
91644
  }
91415
91645
  function proposeItems(ws, base) {
91416
91646
  const root = rootOf(ws);
91417
91647
  for (const p2 of localFiles(ws, base)) {
91418
91648
  if (itemAt(p2)?.state !== "open" || base.files[root + p2]) continue;
91419
- const file2 = path24.join(ws.board, p2);
91420
- const content = fs21.readFileSync(file2, "utf8");
91649
+ const file2 = path26.join(ws.board, p2);
91650
+ const content = fs22.readFileSync(file2, "utf8");
91421
91651
  const said = (key) => new RegExp(`^${key}:`, "m").test(content.split(/\n---/)[0] ?? "");
91422
91652
  const fields = {
91423
91653
  ...ws.cloudTask && !said("source_task") ? { source_task: ws.cloudTask } : {},
@@ -91457,9 +91687,9 @@ async function send2(ws, job) {
91457
91687
  const record = readRecord(ws);
91458
91688
  const base = readBase(ws);
91459
91689
  const fail = (error, conflict = false, code) => ({ ok: false, conflict, error, ...code ? {} : { offline: true } });
91460
- const tasks = ws.cloudTask ? [{ folder: ws, record }] : filesUnder(path24.join(ws.board, ".sync")).filter((name) => name.endsWith(".json")).flatMap((name) => {
91690
+ const tasks = ws.cloudTask ? [{ folder: ws, record }] : filesUnder(path26.join(ws.board, ".sync")).filter((name) => name.endsWith(".json")).flatMap((name) => {
91461
91691
  try {
91462
- const held4 = JSON.parse(fs21.readFileSync(path24.join(ws.board, ".sync", name), "utf8"));
91692
+ const held4 = JSON.parse(fs22.readFileSync(path26.join(ws.board, ".sync", name), "utf8"));
91463
91693
  if (!held4.task || !TASK_ID.test(held4.task) || !held4.number) return [];
91464
91694
  return [{ folder: { ...ws, task: held4.task, cloudTask: held4.task, number: held4.number }, record: held4 }];
91465
91695
  } catch {
@@ -91479,7 +91709,7 @@ async function send2(ws, job) {
91479
91709
  const owed = (p2) => !job.id && busy(ws.cwd) && itemAt(p2)?.state === "open" && !base.files[rootOf(ws) + p2];
91480
91710
  for (const p2 of local) {
91481
91711
  if (owed(p2)) continue;
91482
- const content = fs21.readFileSync(path24.join(ws.board, p2), "utf8");
91712
+ const content = fs22.readFileSync(path26.join(ws.board, p2), "utf8");
91483
91713
  const remote = remoteOf(ws, shared, p2);
91484
91714
  localOf.set(remote, p2);
91485
91715
  const held4 = base.files[remote];
@@ -91511,15 +91741,15 @@ async function send2(ws, job) {
91511
91741
  changes.splice(at2, 1);
91512
91742
  delete base.files[theirs.path];
91513
91743
  writeBase(ws, base);
91514
- fs21.rmSync(path24.join(ws.board, p2), { force: true });
91744
+ fs22.rmSync(path26.join(ws.board, p2), { force: true });
91515
91745
  writeIndex(ws.board);
91516
91746
  continue;
91517
91747
  }
91518
91748
  if (at2 < 0) continue;
91519
91749
  const merged = itemAt(p2) ? { content: theirs.content } : mergeFile(base.files[theirs.path]?.content ?? null, changes[at2].content, theirs.content);
91520
91750
  changes[at2] = { path: theirs.path, content: merged.content, base_seq: theirs.seq };
91521
- if (merged.content === null) fs21.rmSync(path24.join(ws.board, p2), { force: true });
91522
- else write(path24.join(ws.board, p2), merged.content);
91751
+ if (merged.content === null) fs22.rmSync(path26.join(ws.board, p2), { force: true });
91752
+ else write(path26.join(ws.board, p2), merged.content);
91523
91753
  }
91524
91754
  if (!changes.length) return { ok: true, changed: false };
91525
91755
  sent = await commitBoard(ws.project, job.id, job.machineId, changes);
@@ -91541,7 +91771,7 @@ var BUSY_MS = 3e4;
91541
91771
  function keptFolders() {
91542
91772
  let cached2 = [];
91543
91773
  try {
91544
- cached2 = fs22.readdirSync(cacheRoot()).map((name) => path25.join(cacheRoot(), name));
91774
+ cached2 = fs23.readdirSync(cacheRoot()).map((name) => path27.join(cacheRoot(), name));
91545
91775
  } catch {
91546
91776
  }
91547
91777
  return [.../* @__PURE__ */ new Set([...allowedProjects(), ...cached2])].flatMap((dir) => [keptBoard(dir)].filter((ws) => !!ws));
@@ -91577,8 +91807,8 @@ function watchBoards(machineId2, ms, lookMs = LOOK_MS, pullMs = PULL_MS, busyMs
91577
91807
  const watch = (ws) => {
91578
91808
  let watcher;
91579
91809
  try {
91580
- watcher = fs22.watch(ws.board, { recursive: true }, (_event, name) => {
91581
- const p2 = name && String(name).split(path25.sep).join("/");
91810
+ watcher = fs23.watch(ws.board, { recursive: true }, (_event, name) => {
91811
+ const p2 = name && String(name).split(path27.sep).join("/");
91582
91812
  const held4 = watched.get(ws.cwd);
91583
91813
  if (closed || !p2 || !isBoardPath(p2) || !held4) return;
91584
91814
  const job = busy(ws.cwd);
@@ -91641,8 +91871,8 @@ function watchBoards(machineId2, ms, lookMs = LOOK_MS, pullMs = PULL_MS, busyMs
91641
91871
 
91642
91872
  // src/diff.ts
91643
91873
  import { execFile as execFile2 } from "node:child_process";
91644
- import fs23 from "node:fs";
91645
- import path26 from "node:path";
91874
+ import fs24 from "node:fs";
91875
+ import path28 from "node:path";
91646
91876
  var FILE_BYTES = 256 * 1024;
91647
91877
  var TOTAL_BYTES = 1024 * 1024;
91648
91878
  var EMPTY_TREE = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
@@ -91659,7 +91889,7 @@ var git2 = (dir, args, maxBuffer = 4 * TOTAL_BYTES) => new Promise(
91659
91889
  function projectDir(placed, project) {
91660
91890
  if (placed) {
91661
91891
  const real = realpath3(placed);
91662
- return real && allowedProjects().some((root) => real === root || real.startsWith(root + path26.sep)) ? real : null;
91892
+ return real && allowedProjects().some((root) => real === root || real.startsWith(root + path28.sep)) ? real : null;
91663
91893
  }
91664
91894
  let cached2;
91665
91895
  try {
@@ -91667,11 +91897,11 @@ function projectDir(placed, project) {
91667
91897
  } catch {
91668
91898
  return null;
91669
91899
  }
91670
- return fs23.existsSync(path26.join(cached2, ".git")) ? cached2 : null;
91900
+ return fs24.existsSync(path28.join(cached2, ".git")) ? cached2 : null;
91671
91901
  }
91672
91902
  function realpath3(p2) {
91673
91903
  try {
91674
- return fs23.realpathSync(p2);
91904
+ return fs24.realpathSync(p2);
91675
91905
  } catch {
91676
91906
  return null;
91677
91907
  }
@@ -91717,18 +91947,21 @@ async function answerHint(machineId2, hint2) {
91717
91947
 
91718
91948
  // ../cli/src/lib/agent/stop.ts
91719
91949
  import { spawnSync as spawnSync5 } from "node:child_process";
91720
- import fs24 from "node:fs";
91950
+ import { randomUUID as randomUUID2 } from "node:crypto";
91951
+ import fs25 from "node:fs";
91721
91952
  var runMark = (sessionId) => ({ name: RUN_ENV, value: sessionId });
91953
+ var stopMark = () => ({ name: STOP_ENV, value: randomUUID2() });
91954
+ var markEnv = (env2, mark) => ({ ...env2, [mark.name]: mark.value });
91722
91955
  var WINDOWS3 = process.platform === "win32";
91723
91956
  function markedInProc(entry, strict = false) {
91724
91957
  const pids = [];
91725
- for (const name of fs24.readdirSync("/proc")) {
91958
+ for (const name of fs25.readdirSync("/proc")) {
91726
91959
  if (!/^\d+$/.test(name)) continue;
91727
91960
  try {
91728
- if (fs24.readFileSync(`/proc/${name}/environ`, "utf8").split("\0").includes(entry)) pids.push(Number(name));
91961
+ if (fs25.readFileSync(`/proc/${name}/environ`, "utf8").split("\0").includes(entry)) pids.push(Number(name));
91729
91962
  } catch (error) {
91730
91963
  if (strict && !["ENOENT", "ESRCH"].includes(error.code ?? "")) {
91731
- const stat = fs24.statSync(`/proc/${name}`, { throwIfNoEntry: false });
91964
+ const stat = fs25.statSync(`/proc/${name}`, { throwIfNoEntry: false });
91732
91965
  if (stat?.uid === process.getuid?.()) throw error;
91733
91966
  }
91734
91967
  }
@@ -91761,6 +91994,24 @@ function markedInPs(entry, roots) {
91761
91994
  }
91762
91995
  return [...found];
91763
91996
  }
91997
+ function marked(mark, roots = []) {
91998
+ if (WINDOWS3 || !mark.value) return [];
91999
+ const entry = `${mark.name}=${mark.value}`;
92000
+ try {
92001
+ const pids = process.platform === "linux" ? markedInProc(entry) : markedInPs(entry, roots);
92002
+ return pids.filter((pid) => pid !== process.pid);
92003
+ } catch {
92004
+ return [];
92005
+ }
92006
+ }
92007
+ function signal(pids, sig) {
92008
+ for (const pid of pids) {
92009
+ try {
92010
+ process.kill(pid, sig);
92011
+ } catch {
92012
+ }
92013
+ }
92014
+ }
91764
92015
  function startedUnder(list, root, since) {
91765
92016
  const self2 = list.procs.find((p2) => p2.pid === root);
91766
92017
  const from = since ?? self2?.startedAt;
@@ -91804,6 +92055,21 @@ function procsOnWindows() {
91804
92055
  });
91805
92056
  return ps.status === 0 && ps.stdout ? readProcList(ps.stdout) : void 0;
91806
92057
  }
92058
+ function killUnderOnWindows(pid, since) {
92059
+ if (!WINDOWS3 || !pid) return;
92060
+ const list = procsOnWindows();
92061
+ if (!list) return;
92062
+ const pids = startedUnder(list, pid, since).filter((p2) => p2 !== process.pid);
92063
+ if (!pids.length) return;
92064
+ spawnSync5("taskkill", ["/F", ...pids.flatMap((p2) => ["/PID", String(p2)])], { stdio: "ignore", windowsHide: true, timeout: 1e4 });
92065
+ }
92066
+ function killMarked(mark, agent) {
92067
+ if (WINDOWS3) {
92068
+ if (agent) killUnderOnWindows(agent.pid, agent.since);
92069
+ return;
92070
+ }
92071
+ signal(marked(mark), "SIGKILL");
92072
+ }
91807
92073
  function processesStopped(mark, root) {
91808
92074
  try {
91809
92075
  if (WINDOWS3) {
@@ -91821,8 +92087,8 @@ function processesStopped(mark, root) {
91821
92087
  }
91822
92088
 
91823
92089
  // src/flow.ts
91824
- import fs29 from "node:fs";
91825
- import path31 from "node:path";
92090
+ import fs30 from "node:fs";
92091
+ import path33 from "node:path";
91826
92092
 
91827
92093
  // ../cli/src/lib/question-block.ts
91828
92094
  var MODES = ["single", "multi"];
@@ -91980,13 +92246,13 @@ function reviewOf(meta) {
91980
92246
  }
91981
92247
 
91982
92248
  // src/triage.ts
91983
- import fs25 from "node:fs";
91984
- import path27 from "node:path";
92249
+ import fs26 from "node:fs";
92250
+ import path29 from "node:path";
91985
92251
 
91986
92252
  // ../cli/src/lib/signals/identity.ts
91987
- import { createHash } from "node:crypto";
92253
+ import { createHash as createHash2 } from "node:crypto";
91988
92254
  var DERIVED = "derived-";
91989
- var derivedSourceId = (seed) => `${DERIVED}${createHash("sha256").update(seed).digest("hex").slice(0, 16)}`;
92255
+ var derivedSourceId = (seed) => `${DERIVED}${createHash2("sha256").update(seed).digest("hex").slice(0, 16)}`;
91990
92256
 
91991
92257
  // ../cli/src/lib/slug.ts
91992
92258
  function slugify(s) {
@@ -91995,8 +92261,8 @@ function slugify(s) {
91995
92261
  }
91996
92262
 
91997
92263
  // src/triage.ts
91998
- var triageDir = (board) => path27.join(board, "triage");
91999
- var rejectedDir = (board) => path27.join(board, ".archive", REJECTIONS_TO_REVIEW);
92264
+ var triageDir = (board) => path29.join(board, "triage");
92265
+ var rejectedDir = (board) => path29.join(board, ".archive", REJECTIONS_TO_REVIEW);
92000
92266
  var SCRATCH = ["dismissed", "archived"];
92001
92267
  var stamp = (at2) => formatStamp(at2 ? new Date(at2) : /* @__PURE__ */ new Date());
92002
92268
  function slugOf(title) {
@@ -92005,7 +92271,7 @@ function slugOf(title) {
92005
92271
  function freeName(dir, title) {
92006
92272
  const stem = slugOf(title);
92007
92273
  let name = `${stem}.md`;
92008
- for (let n = 2; fs25.existsSync(path27.join(dir, name)); n++) name = `${stem}-${n}.md`;
92274
+ for (let n = 2; fs26.existsSync(path29.join(dir, name)); n++) name = `${stem}-${n}.md`;
92009
92275
  return name;
92010
92276
  }
92011
92277
  function itemText(item, fields = {}) {
@@ -92025,17 +92291,17 @@ ${item.text.trim()}
92025
92291
  `;
92026
92292
  }
92027
92293
  function writeItem(dir, item, fields = {}) {
92028
- fs25.mkdirSync(dir, { recursive: true });
92294
+ fs26.mkdirSync(dir, { recursive: true });
92029
92295
  const name = freeName(dir, item.title);
92030
- fs25.writeFileSync(path27.join(dir, name), itemText(item, item.workflow ? { workflow: workflowName(item.workflow), ...fields } : fields));
92296
+ fs26.writeFileSync(path29.join(dir, name), itemText(item, item.workflow ? { workflow: workflowName(item.workflow), ...fields } : fields));
92031
92297
  return name;
92032
92298
  }
92033
92299
  function layOut(board, rejections) {
92034
92300
  clearLaid(board);
92035
92301
  const dir = rejectedDir(board);
92036
- fs25.mkdirSync(dir, { recursive: true });
92302
+ fs26.mkdirSync(dir, { recursive: true });
92037
92303
  for (const t2 of rejections.tasks) {
92038
- fs25.writeFileSync(path27.join(dir, `${t2.number}-${slugify(t2.title)}.md`), [
92304
+ fs26.writeFileSync(path29.join(dir, `${t2.number}-${slugify(t2.title)}.md`), [
92039
92305
  "---",
92040
92306
  `title: ${yamlScalar(t2.title)}`,
92041
92307
  "status: todo",
@@ -92050,20 +92316,20 @@ function layOut(board, rejections) {
92050
92316
  ].join("\n"));
92051
92317
  }
92052
92318
  for (const item of rejections.triage) {
92053
- const sub = path27.join(triageDir(board), item.state === "dismissed" ? "dismissed" : "archived");
92319
+ const sub = path29.join(triageDir(board), item.state === "dismissed" ? "dismissed" : "archived");
92054
92320
  const fields = item.state === "dismissed" ? { dismissed_at: stamp(item.dismissed_at), dismissed_by: "user", ...item.dismissed_reason ? { dismissed_reason: item.dismissed_reason } : {} } : {};
92055
92321
  writeItem(sub, item, fields);
92056
92322
  }
92057
92323
  return { tasks: rejections.tasks.map((t2) => t2.id), triage: rejections.triage.map((i) => i.id) };
92058
92324
  }
92059
92325
  function clearLaid(board) {
92060
- fs25.rmSync(rejectedDir(board), { recursive: true, force: true });
92061
- for (const sub of SCRATCH) fs25.rmSync(path27.join(triageDir(board), sub), { recursive: true, force: true });
92326
+ fs26.rmSync(rejectedDir(board), { recursive: true, force: true });
92327
+ for (const sub of SCRATCH) fs26.rmSync(path29.join(triageDir(board), sub), { recursive: true, force: true });
92062
92328
  }
92063
92329
 
92064
92330
  // src/kanban-skill.ts
92065
- import fs26 from "node:fs";
92066
- import path28 from "node:path";
92331
+ import fs27 from "node:fs";
92332
+ import path30 from "node:path";
92067
92333
 
92068
92334
  // ../skill/SKILL.md
92069
92335
  var SKILL_default = '---\nname: kanban\ndescription: Manage the file-based task board with akb. Use for creating and planning tasks, revising or implementing cards, and managing background runs; also for "what\'s running".\n---\n\n# Kanban board\n\nThe board is worked only through `akb`. Find the command for the job in `akb help` and run\nit; never do its work by hand or from memory.\n\n- **`--print` does it here**: `akb card revise 12 --print "drop the export"` prints the whole\n flow for that card on this board; follow it to its closing steps. Without `--print` the\n same command starts a separate agent.\n- **Keys**: never read or write API keys; the user sets them with `akb agent set apiKey`.\n';
@@ -92076,24 +92342,24 @@ var CONTENT = `${SKILL_default.trimEnd()}
92076
92342
  var MANAGED = /^<!-- ai4kanban \S+ -->$/m;
92077
92343
  function prepareKanbanSkill(root) {
92078
92344
  for (const folder of SKILL_FOLDERS) {
92079
- const dir = path28.join(root, folder);
92080
- const file2 = path28.join(dir, "SKILL.md");
92345
+ const dir = path30.join(root, folder);
92346
+ const file2 = path30.join(dir, "SKILL.md");
92081
92347
  try {
92082
92348
  let linked = false;
92083
92349
  let at2 = root;
92084
92350
  for (const name of `${folder}/SKILL.md`.split("/")) {
92085
- at2 = path28.join(at2, name);
92086
- if (fs26.lstatSync(at2, { throwIfNoEntry: false })?.isSymbolicLink()) linked = true;
92351
+ at2 = path30.join(at2, name);
92352
+ if (fs27.lstatSync(at2, { throwIfNoEntry: false })?.isSymbolicLink()) linked = true;
92087
92353
  }
92088
- const held4 = fs26.existsSync(file2) ? fs26.readFileSync(file2, "utf8") : null;
92089
- const exists = fs26.lstatSync(dir, { throwIfNoEntry: false }) !== void 0;
92354
+ const held4 = fs27.existsSync(file2) ? fs27.readFileSync(file2, "utf8") : null;
92355
+ const exists = fs27.lstatSync(dir, { throwIfNoEntry: false }) !== void 0;
92090
92356
  if (linked || exists && !MANAGED.test(held4 ?? "")) {
92091
92357
  if (!held4?.trim()) throw new Error("\u7528\u6237\u81EA\u6709\u76EE\u5F55\u6216\u7B26\u53F7\u94FE\u63A5\u4E2D\u7F3A\u5C11\u53EF\u8BFB\u7684 SKILL.md");
92092
92358
  continue;
92093
92359
  }
92094
92360
  if (held4 !== CONTENT) {
92095
- fs26.mkdirSync(dir, { recursive: true });
92096
- fs26.writeFileSync(file2, CONTENT);
92361
+ fs27.mkdirSync(dir, { recursive: true });
92362
+ fs27.writeFileSync(file2, CONTENT);
92097
92363
  }
92098
92364
  } catch (e2) {
92099
92365
  throw new Error(`\u65E0\u6CD5\u51C6\u5907 ${folder}\uFF1A${e2 instanceof Error ? e2.message : String(e2)}`);
@@ -92103,27 +92369,18 @@ function prepareKanbanSkill(root) {
92103
92369
 
92104
92370
  // ../cli/src/lib/skill/hook.ts
92105
92371
  import { spawnSync as spawnSync6 } from "node:child_process";
92106
- import fs27 from "node:fs";
92107
- import path29 from "node:path";
92108
-
92109
- // ../cli/src/lib/agent/landing-lock.ts
92110
- var landingLimits = { staleMs: 5 * 6e4 };
92111
-
92112
- // ../cli/src/lib/skill/hook.ts
92372
+ import fs28 from "node:fs";
92373
+ import path31 from "node:path";
92113
92374
  var MARKER = "# ai4kanban commit guard";
92114
92375
  var MARKER_LINE = new RegExp(`^${MARKER}\\b`, "m");
92115
92376
  var CHECK = [
92116
92377
  "try{",
92117
92378
  'const[top,branch]=require("child_process")',
92118
- '.execFileSync("git",["rev-parse","--show-toplevel","--abbrev-ref","HEAD"],{encoding:"utf8",timeout:3000,killSignal:"SIGKILL"}).trim().split("\\n");',
92379
+ '.execFileSync("git",["rev-parse","--show-toplevel","--abbrev-ref","HEAD"],{encoding:"utf8"}).trim().split("\\n");',
92119
92380
  'if(/\\/\\.akb\\/worktrees\\//.test(top+"/"))process.exit(0);',
92120
92381
  'const d=(JSON.parse(require("fs").readFileSync(process.argv[1],"utf8")).deliveries||[])',
92121
- '.find((x)=>x&&x.status==="active"&&x.commitMode==="auto"&&x.targetBranch===branch&&x.landing&&x.landing.status==="landing");',
92382
+ '.find((x)=>x&&x.status==="active"&&x.commitMode==="auto"&&x.targetBranch===branch&&(!x.landing||x.landing.status!=="landed"));',
92122
92383
  "if(!d)process.exit(0);",
92123
- 'const fs=require("fs"),lock=process.argv[2],entries=fs.readdirSync(lock);',
92124
- `if(Date.now()-fs.statSync(lock).mtimeMs>${landingLimits.staleMs})process.exit(0);`,
92125
- "if(entries.length!==1||!/^\\d+-[a-f0-9-]{36}$/.test(entries[0]))process.exit(0);",
92126
- 'try{process.kill(Number(entries[0].split("-")[0]),0)}catch(e){if(e.code!=="EPERM")process.exit(0)}',
92127
92384
  "process.stderr.write(",
92128
92385
  '"ai4kanban: delivery "+d.deliveryId+" is landing #"+d.cardId+" on "+branch+", so a commit here moves the target under it\\n"',
92129
92386
  '+" \u2014 commit on another branch, or `git commit --no-verify` to commit anyway.\\n");',
@@ -92131,7 +92388,7 @@ var CHECK = [
92131
92388
  "}catch(e){process.exit(0)}"
92132
92389
  ].join("");
92133
92390
  var quoted = (p2) => `"${p2.replace(/(["$`\\])/g, "\\$1")}"`;
92134
- var guardLine = (sessions) => `if command -v node >/dev/null 2>&1; then node -e '${CHECK}' ${quoted(sessions)} ${quoted(path29.join(path29.dirname(sessions), SESSIONS_FOLDER, ".landing.lock"))} || exit 1; fi`;
92391
+ var guardLine = (sessions) => `if command -v node >/dev/null 2>&1; then node -e '${CHECK}' ${quoted(sessions)} || exit 1; fi`;
92135
92392
  function hookScript(sessions) {
92136
92393
  return [
92137
92394
  "#!/bin/sh",
@@ -92147,7 +92404,7 @@ function hookScript(sessions) {
92147
92404
  }
92148
92405
  var read = (file2) => {
92149
92406
  try {
92150
- return fs27.readFileSync(file2, "utf8");
92407
+ return fs28.readFileSync(file2, "utf8");
92151
92408
  } catch {
92152
92409
  return null;
92153
92410
  }
@@ -92159,7 +92416,7 @@ function hooksDir(root) {
92159
92416
  windowsHide: true
92160
92417
  });
92161
92418
  if (out.error || out.status !== 0 || !out.stdout.trim()) return null;
92162
- return path29.resolve(root, out.stdout.trim());
92419
+ return path31.resolve(root, out.stdout.trim());
92163
92420
  }
92164
92421
  function hasOwnHooksPath(root) {
92165
92422
  const out = spawnSync6("git", ["config", "--get", "core.hooksPath"], {
@@ -92169,21 +92426,21 @@ function hasOwnHooksPath(root) {
92169
92426
  });
92170
92427
  return !out.error && out.status === 0 && !!out.stdout.trim();
92171
92428
  }
92172
- var sessionsPath = (root, board) => path29.join(projectStateDir(board, root), SESSIONS_FILE);
92173
- function readCommitHook(root, board = path29.join(root, "docs", "kanban")) {
92429
+ var sessionsPath = (root, board) => path31.join(projectStateDir(board, root), SESSIONS_FILE);
92430
+ function readCommitHook(root, board = path31.join(root, "docs", "kanban")) {
92174
92431
  const dir = hooksDir(root);
92175
92432
  if (!dir) return { state: "no-git" };
92176
- const where = shown(root, path29.join(dir, "pre-commit"));
92433
+ const where = shown(root, path31.join(dir, "pre-commit"));
92177
92434
  const line = guardLine(sessionsPath(root, board));
92178
92435
  if (hasOwnHooksPath(root)) return { state: "hooks-path", path: where, line };
92179
- const file2 = path29.join(dir, "pre-commit");
92180
- if (fs27.lstatSync(file2, { throwIfNoEntry: false })?.isSymbolicLink()) return { state: "foreign", path: where, line };
92436
+ const file2 = path31.join(dir, "pre-commit");
92437
+ if (fs28.lstatSync(file2, { throwIfNoEntry: false })?.isSymbolicLink()) return { state: "foreign", path: where, line };
92181
92438
  const text3 = read(file2);
92182
92439
  if (text3 === null) return { state: "absent", path: where };
92183
92440
  return MARKER_LINE.test(text3) ? { state: "ours", path: where } : { state: "foreign", path: where, line };
92184
92441
  }
92185
- var shown = (root, p2) => (path29.relative(root, p2) || p2).split(path29.sep).join("/");
92186
- function installCommitHook(root, board = path29.join(root, "docs", "kanban")) {
92442
+ var shown = (root, p2) => (path31.relative(root, p2) || p2).split(path31.sep).join("/");
92443
+ function installCommitHook(root, board = path31.join(root, "docs", "kanban")) {
92187
92444
  try {
92188
92445
  return placeCommitHook(root, board);
92189
92446
  } catch (e2) {
@@ -92200,12 +92457,12 @@ function placeCommitHook(root, board) {
92200
92457
  ${hook.line}`
92201
92458
  };
92202
92459
  }
92203
- const file2 = path29.join(root, hook.path);
92460
+ const file2 = path31.join(root, hook.path);
92204
92461
  try {
92205
- fs27.mkdirSync(path29.dirname(file2), { recursive: true });
92462
+ fs28.mkdirSync(path31.dirname(file2), { recursive: true });
92206
92463
  const text3 = hookScript(sessionsPath(root, board));
92207
- if (read(file2) !== text3) fs27.writeFileSync(file2, text3, { mode: 493 });
92208
- fs27.chmodSync(file2, 493);
92464
+ if (read(file2) !== text3) fs28.writeFileSync(file2, text3, { mode: 493 });
92465
+ fs28.chmodSync(file2, 493);
92209
92466
  } catch (e2) {
92210
92467
  return { note: `${hook.path} could not be written \u2014 ${e2 instanceof Error ? e2.message : String(e2)}` };
92211
92468
  }
@@ -92213,8 +92470,8 @@ ${hook.line}`
92213
92470
  }
92214
92471
 
92215
92472
  // src/built.ts
92216
- import fs28 from "node:fs";
92217
- import path30 from "node:path";
92473
+ import fs29 from "node:fs";
92474
+ import path32 from "node:path";
92218
92475
 
92219
92476
  // ../cli/src/lib/spec-agent-names.ts
92220
92477
  var LEGACY_SPEC_AGENT_NAMES = {
@@ -92390,12 +92647,12 @@ function checkWorkflowFiles(value, official = false) {
92390
92647
 
92391
92648
  // src/built.ts
92392
92649
  var isBuilder = (ws) => ws.workflow === BUILDER;
92393
- var draftDir = (ws) => path30.join(ws.board, "workflows", draftFolder(ws.task));
92394
- var draftLine = (ws) => `<!-- workflow folder: ${path30.relative(ws.cwd, draftDir(ws)).split(path30.sep).join("/")}/ -->`;
92650
+ var draftDir = (ws) => path32.join(ws.board, "workflows", draftFolder(ws.task));
92651
+ var draftLine = (ws) => `<!-- workflow folder: ${path32.relative(ws.cwd, draftDir(ws)).split(path32.sep).join("/")}/ -->`;
92395
92652
  var skeleton = (name) => ["---", `name: ${/\s#/.test(name) ? JSON.stringify(name) : yamlScalar(name)}`, "needsArtifact: false", "---", ""].join("\n");
92396
92653
  async function placeDraft(ws, read2) {
92397
92654
  const dir = draftDir(ws);
92398
- if (fs28.existsSync(path30.join(dir, WORKFLOW_FILE))) return { ok: true, value: void 0 };
92655
+ if (fs29.existsSync(path32.join(dir, WORKFLOW_FILE))) return { ok: true, value: void 0 };
92399
92656
  const task = await read2.readTask(ws.task);
92400
92657
  if (!task.ok) return task;
92401
92658
  let files = { [WORKFLOW_FILE]: skeleton(task.value.title.trim() || "Untitled") };
@@ -92406,10 +92663,10 @@ async function placeDraft(ws, read2) {
92406
92663
  files = held4.value.files;
92407
92664
  }
92408
92665
  for (const [name, text3] of Object.entries(files)) {
92409
- const file2 = path30.resolve(dir, name);
92410
- if (!file2.startsWith(dir + path30.sep)) continue;
92411
- fs28.mkdirSync(path30.dirname(file2), { recursive: true });
92412
- fs28.writeFileSync(file2, text3);
92666
+ const file2 = path32.resolve(dir, name);
92667
+ if (!file2.startsWith(dir + path32.sep)) continue;
92668
+ fs29.mkdirSync(path32.dirname(file2), { recursive: true });
92669
+ fs29.writeFileSync(file2, text3);
92413
92670
  }
92414
92671
  return { ok: true, value: void 0 };
92415
92672
  }
@@ -92421,19 +92678,19 @@ async function builtWorkflow(ws, akb) {
92421
92678
  const dir = draftDir(ws);
92422
92679
  let source;
92423
92680
  try {
92424
- source = fs28.readFileSync(path30.join(dir, WORKFLOW_FILE), "utf8");
92681
+ source = fs29.readFileSync(path32.join(dir, WORKFLOW_FILE), "utf8");
92425
92682
  } catch {
92426
92683
  return fail(`workflows/${id}/${WORKFLOW_FILE} is missing.`);
92427
92684
  }
92428
92685
  const read2 = parseWorkflowFile(id, source, `workflows/${id}/${WORKFLOW_FILE}`);
92429
92686
  if ("problem" in read2) return fail(read2.problem);
92430
92687
  const names2 = named(read2.def);
92431
- fs28.rmSync(path30.join(dir, "agents"), { recursive: true, force: true });
92688
+ fs29.rmSync(path32.join(dir, "agents"), { recursive: true, force: true });
92432
92689
  for (const name of names2) {
92433
- const from = path30.join(ws.board, "agents", name);
92434
- if (fs28.existsSync(from)) fs28.cpSync(from, path30.join(dir, "agents", name), { recursive: true });
92690
+ const from = path32.join(ws.board, "agents", name);
92691
+ if (fs29.existsSync(from)) fs29.cpSync(from, path32.join(dir, "agents", name), { recursive: true });
92435
92692
  }
92436
- const files = Object.fromEntries(filesUnder(dir).map((f2) => [f2, fs28.readFileSync(path30.join(dir, f2), "utf8")]));
92693
+ const files = Object.fromEntries(filesUnder(dir).map((f2) => [f2, fs29.readFileSync(path32.join(dir, f2), "utf8")]));
92437
92694
  const checked = checkWorkflowFiles(files);
92438
92695
  if (!checked.ok) return fail(`${checked.file} ${checked.reason}.`);
92439
92696
  const run2 = async (args) => answerOf2(await runAkb(akb, [...args, "--json", "--board", ws.board], { cwd: ws.cwd, board: ws.board }));
@@ -92468,7 +92725,7 @@ function spentBy(runs) {
92468
92725
  }
92469
92726
  function reviewOf2(file2) {
92470
92727
  try {
92471
- const meta = parseFrontmatter(fs29.readFileSync(file2, "utf8")).meta;
92728
+ const meta = parseFrontmatter(fs30.readFileSync(file2, "utf8")).meta;
92472
92729
  return meta ? reviewOf(meta) : null;
92473
92730
  } catch {
92474
92731
  return null;
@@ -92476,8 +92733,8 @@ function reviewOf2(file2) {
92476
92733
  }
92477
92734
  function mcpConfig(servers, file2) {
92478
92735
  if (!Object.keys(servers).length) return null;
92479
- fs29.mkdirSync(path31.dirname(file2), { recursive: true });
92480
- fs29.writeFileSync(file2, `${JSON.stringify({ mcpServers: servers }, null, 2)}
92736
+ fs30.mkdirSync(path33.dirname(file2), { recursive: true });
92737
+ fs30.writeFileSync(file2, `${JSON.stringify({ mcpServers: servers }, null, 2)}
92481
92738
  `);
92482
92739
  return file2;
92483
92740
  }
@@ -92516,7 +92773,7 @@ function deliveryEnding(ws, id) {
92516
92773
  if (!id) return null;
92517
92774
  let held4;
92518
92775
  try {
92519
- held4 = JSON.parse(fs29.readFileSync(path31.join(ws.board, "deliveries", `${path31.basename(id)}.json`), "utf8"));
92776
+ held4 = JSON.parse(fs30.readFileSync(path33.join(ws.board, "deliveries", `${path33.basename(id)}.json`), "utf8"));
92520
92777
  } catch {
92521
92778
  return null;
92522
92779
  }
@@ -92528,16 +92785,16 @@ function deliveryEnding(ws, id) {
92528
92785
  return null;
92529
92786
  }
92530
92787
  function checkoutsOf(ws, id) {
92531
- const dir = path31.join(ws.board, "deliveries");
92788
+ const dir = path33.join(ws.board, "deliveries");
92532
92789
  let names2;
92533
92790
  try {
92534
- names2 = fs29.readdirSync(dir).filter((n) => n.endsWith(".json"));
92791
+ names2 = fs30.readdirSync(dir).filter((n) => n.endsWith(".json"));
92535
92792
  } catch {
92536
92793
  return [];
92537
92794
  }
92538
92795
  return names2.flatMap((n) => {
92539
92796
  try {
92540
- const held4 = JSON.parse(fs29.readFileSync(path31.join(dir, n), "utf8"));
92797
+ const held4 = JSON.parse(fs30.readFileSync(path33.join(dir, n), "utf8"));
92541
92798
  return held4.cardId === id && held4.worktree && held4.deliveryId ? [held4.deliveryId] : [];
92542
92799
  } catch {
92543
92800
  return [];
@@ -92591,7 +92848,7 @@ function boardAkb(job, ws, deps, io, task) {
92591
92848
  const at2 = args.includes("--") ? args.indexOf("--") : args.length;
92592
92849
  const full = [...args.slice(0, at2), "--board", ws.board, ...args.slice(at2)];
92593
92850
  const log = show ? logLines(io.show, io.event) : void 0;
92594
- const ran = await runAkb(deps.akb, full, { cwd: ws.cwd, board: ws.board, task, line: job.languageLine ?? "", env: { ...env2, AI4KANBAN_EXECUTION: JSON.stringify({ job: job.id, machine: deps.machineId }) }, show: log?.push, track: io.track });
92851
+ const ran = await runAkb(deps.akb, full, { cwd: ws.cwd, board: ws.board, task, language: cloudLanguage(job), env: { ...env2, AI4KANBAN_EXECUTION: JSON.stringify({ job: job.id, machine: deps.machineId }) }, show: log?.push, track: io.track });
92595
92852
  log?.end();
92596
92853
  return ran;
92597
92854
  };
@@ -92601,7 +92858,7 @@ async function setUp(job, ws, deps, io) {
92601
92858
  const runtime = job.runtime;
92602
92859
  const missing = unavailable(runtime, await deps.runtimes());
92603
92860
  if (missing) return missing;
92604
- if (!fs29.existsSync(path31.join(ws.board, "config.md"))) {
92861
+ if (!fs30.existsSync(path33.join(ws.board, "config.md"))) {
92605
92862
  const init = await akb(["raw", "init"]);
92606
92863
  if (init.code !== 0) return refusal(init);
92607
92864
  }
@@ -92618,7 +92875,7 @@ async function setUp(job, ws, deps, io) {
92618
92875
  const used = await akb(["agent", "use", runtime]);
92619
92876
  if (used.code !== 0) return refusal(used);
92620
92877
  const servers = mcpServersOf(ws);
92621
- const mcpFile = path31.join(ws.board, ".sync", `${ws.task}.mcp.json`);
92878
+ const mcpFile = path33.join(ws.board, ".sync", `${ws.task}.mcp.json`);
92622
92879
  const takes = new Set(settingKeys(runtime));
92623
92880
  const given = job.settings ?? {};
92624
92881
  const values = { ...given, model: job.model ?? "" };
@@ -92676,8 +92933,8 @@ async function reviewRejections(job, ws, deps, io) {
92676
92933
  if (ran.code !== 0) return { runs, failure: refusal(ran) };
92677
92934
  const sent = await push2({ id: job.id, machineId: deps.machineId });
92678
92935
  if (!sent.ok) return { runs, failure: sent.error };
92679
- const marked = await deps.api.markReviewed(laid.tasks, laid.triage);
92680
- return marked.ok ? { runs } : { runs, failure: marked.error };
92936
+ const marked2 = await deps.api.markReviewed(laid.tasks, laid.triage);
92937
+ return marked2.ok ? { runs } : { runs, failure: marked2.error };
92681
92938
  });
92682
92939
  }
92683
92940
  async function learnRejections(job, ws, deps, io) {
@@ -92718,19 +92975,19 @@ async function runAgent(job, ws, deps, io) {
92718
92975
  }
92719
92976
  function writeTranscript(job, dir) {
92720
92977
  if (!job.transcript) return "";
92721
- const file2 = path31.join(dir, "discussion.md");
92722
- fs29.mkdirSync(dir, { recursive: true });
92723
- fs29.writeFileSync(file2, `${job.transcript}
92978
+ const file2 = path33.join(dir, "discussion.md");
92979
+ fs30.mkdirSync(dir, { recursive: true });
92980
+ fs30.writeFileSync(file2, `${job.transcript}
92724
92981
  `);
92725
92982
  return file2;
92726
92983
  }
92727
92984
  function pictures(job, ws, id) {
92728
92985
  const dir = cardAssetsDir(ws, id);
92729
92986
  if (!job.attachments.length || !dir) return "";
92730
- fs29.mkdirSync(dir, { recursive: true });
92987
+ fs30.mkdirSync(dir, { recursive: true });
92731
92988
  return job.attachments.map((a3, i) => {
92732
- const file2 = `${i + 1}-${path31.basename(a3.name).replace(/[^\w.-]+/g, "-")}`;
92733
- fs29.writeFileSync(path31.join(dir, file2), Buffer.from(a3.content, "base64"));
92989
+ const file2 = `${i + 1}-${path33.basename(a3.name).replace(/[^\w.-]+/g, "-")}`;
92990
+ fs30.writeFileSync(path33.join(dir, file2), Buffer.from(a3.content, "base64"));
92734
92991
  return `
92735
92992
  <Asset src=".assets/${id}/${file2}" label="${a3.name.replace(/["<>]/g, "") || file2}" />
92736
92993
  `;
@@ -92738,7 +92995,7 @@ function pictures(job, ws, id) {
92738
92995
  }
92739
92996
  function cardFlags(ws, fields) {
92740
92997
  if (!fields) return [];
92741
- const open = (keys) => (keys ?? []).map((k) => Number(/(\d+)$/.exec(k)?.[1])).filter((n) => n > 0 && n !== ws.number && findCard(ws.board, n)?.startsWith(path31.join(ws.board, "todo") + path31.sep));
92998
+ const open = (keys) => (keys ?? []).map((k) => Number(/(\d+)$/.exec(k)?.[1])).filter((n) => n > 0 && n !== ws.number && findCard(ws.board, n)?.startsWith(path33.join(ws.board, "todo") + path33.sep));
92742
92999
  const lists = [["--modules", fields.modules ?? []], ["--related", open(fields.related)], ["--blocked-by", open(fields.blocked_by)]];
92743
93000
  return [
92744
93001
  ...fields.priority ? ["--priority", fields.priority] : [],
@@ -92772,10 +93029,10 @@ async function runFlow(job, ws, deps, io) {
92772
93029
  const placed = await placeDraft(ws, deps.api);
92773
93030
  if (!placed.ok) return fail(placed.error);
92774
93031
  }
92775
- const body = path31.join(ws.board, ".sync", `${ws.task}.request.md`);
92776
- fs29.mkdirSync(path31.dirname(body), { recursive: true });
93032
+ const body = path33.join(ws.board, ".sync", `${ws.task}.request.md`);
93033
+ fs30.mkdirSync(path33.dirname(body), { recursive: true });
92777
93034
  if (!ws.number) return fail("This task has no number yet.");
92778
- fs29.writeFileSync(body, `${said.request || title}
93035
+ fs30.writeFileSync(body, `${said.request || title}
92779
93036
  ${isBuilder(ws) ? `
92780
93037
  ${draftLine(ws)}
92781
93038
  ` : ""}${pictures(job, ws, ws.number)}`);
@@ -92793,7 +93050,7 @@ ${draftLine(ws)}
92793
93050
  ...cardFlags(ws, flow.metadata),
92794
93051
  "--json"
92795
93052
  ]));
92796
- fs29.rmSync(body, { force: true });
93053
+ fs30.rmSync(body, { force: true });
92797
93054
  if (!created.ok) return fail(created.error);
92798
93055
  id = created.value;
92799
93056
  }
@@ -92809,7 +93066,7 @@ ${draftLine(ws)}
92809
93066
  if (io.lost()) return fail("");
92810
93067
  return await workOn(card);
92811
93068
  } finally {
92812
- fs29.rmSync(path31.join(ws.board, ".sync", `${ws.task}.discussion`), { recursive: true, force: true });
93069
+ fs30.rmSync(path33.join(ws.board, ".sync", `${ws.task}.discussion`), { recursive: true, force: true });
92813
93070
  const left = working.get(key) - 1;
92814
93071
  if (left) working.set(key, left);
92815
93072
  else working.delete(key);
@@ -92826,31 +93083,18 @@ ${draftLine(ws)}
92826
93083
  }
92827
93084
  if (verb === "revise" && !text3) return fail("Say what to change.");
92828
93085
  let note = verb === "resolve" || verb === "revise" ? text3 : "";
92829
- let continuation;
92830
- let expectedDelivery;
92831
93086
  if (verb === "implement" && flow.resume) {
92832
- const restored = await akb(["delivery", "resume", String(id2), "--json"]);
92833
- const resumed = answerOf2(restored);
93087
+ const resumed = answerOf2(await akb(["delivery", "resume", String(id2), "--json"]));
92834
93088
  if (io.lost()) return fail("");
92835
93089
  if (resumed?.landed) return { ok: true, report: { card: id2 } };
92836
- if (restored.code !== 0 && resumed?.error?.reason !== "deliveryActive") return fail(resumed?.error?.message ?? refusal(restored));
92837
- const deliveryId = resumed?.deliveryId ?? resumed?.error?.args?.id;
92838
- 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");
92839
- expectedDelivery = deliveryId;
92840
- 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];
92841
- 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");
92842
- continuation = previous.status === "done" ? ["run", "log", previous.sessionId] : ["run", "resume", previous.sessionId, "--require-session"];
92843
93090
  } else if (verb === "implement" && text3) {
92844
93091
  const resolved = await akb(["card", "resolve", String(id2), "--follow", "--events", "--json", "--", text3], true);
92845
93092
  if (io.lost()) return fail("");
92846
93093
  if (resolved.code !== 0) note = text3;
92847
93094
  }
92848
- const ran = await akb(continuation ? [...continuation, "--follow", "--events", "--json"] : ["card", verb, String(id2), "--follow", "--events", "--json", ...carryArgs(verb), ...note ? ["--", note] : []], true);
93095
+ const ran = await akb(["card", verb, String(id2), "--follow", "--events", "--json", ...carryArgs(verb), ...note ? ["--", note] : []], true);
92849
93096
  if (io.lost()) return fail("");
92850
93097
  const answer = answerOf2(ran);
92851
- if (expectedDelivery && answer?.delivery?.id && answer.delivery.id !== expectedDelivery) {
92852
- return fail("\u7EED\u8DD1\u8FD4\u56DE\u4E86\u5176\u4ED6\u4EA4\u4ED8\u7684\u7ED3\u679C\uFF0C\u539F\u4EA4\u4ED8\u4FDD\u6301\u672A\u5B8C\u6210\u3002");
92853
- }
92854
93098
  if (verb === "implement") {
92855
93099
  const ending = deliveryEnding(ws, answer?.delivery?.id ?? answer?.error?.delivery?.id);
92856
93100
  if (ending) return ending;
@@ -92882,7 +93126,7 @@ ${draftLine(ws)}
92882
93126
  }
92883
93127
  function carryArgs(verb) {
92884
93128
  if (!["refine", "resolve", "revise", "implement"].includes(verb)) return [];
92885
- const transcript = writeTranscript(job, path31.join(ws.board, ".sync", `${ws.task}.discussion`));
93129
+ const transcript = writeTranscript(job, path33.join(ws.board, ".sync", `${ws.task}.discussion`));
92886
93130
  return [
92887
93131
  ...job.resume ? ["--session", job.resume, ...job.fork ? ["--fork"] : []] : [],
92888
93132
  ...transcript ? ["--transcript", transcript] : []
@@ -92901,15 +93145,15 @@ async function confirmFlowStopped(ws, job, deps) {
92901
93145
  }
92902
93146
 
92903
93147
  // src/recovery.ts
92904
- import fs30 from "node:fs";
92905
- import path32 from "node:path";
93148
+ import fs31 from "node:fs";
93149
+ import path34 from "node:path";
92906
93150
  var PREPARE_REASON = "Runner update prepare.";
92907
93151
  var UPDATE_REASON = "Runner update checkpoint.";
92908
93152
  var UNCERTAIN = "\u66F4\u65B0\u4E2D\u65AD\u65F6\u6709\u64CD\u4F5C\u7ED3\u679C\u5C1A\u672A\u786E\u8BA4\uFF0C\u8BF7\u68C0\u67E5\u5DF2\u6709\u7ED3\u679C\u540E\u518D\u7EED\u8DD1\u3002";
92909
- var fileOf = (id) => path32.join(runnerHome(), "checkpoints", `${encodeURIComponent(id)}.json`);
93153
+ var fileOf = (id) => path34.join(runnerHome(), "checkpoints", `${encodeURIComponent(id)}.json`);
92910
93154
  function readCheckpoint(id) {
92911
93155
  try {
92912
- const held4 = JSON.parse(fs30.readFileSync(fileOf(id), "utf8"));
93156
+ const held4 = JSON.parse(fs31.readFileSync(fileOf(id), "utf8"));
92913
93157
  if (!held4 || !Array.isArray(held4.pending) || !held4.pending.every((id2) => typeof id2 === "string")) throw new Error("\u8FDB\u5EA6\u683C\u5F0F\u9519\u8BEF");
92914
93158
  return held4;
92915
93159
  } catch (e2) {
@@ -92919,12 +93163,12 @@ function readCheckpoint(id) {
92919
93163
  }
92920
93164
  function saveCheckpoint(id, checkpoint) {
92921
93165
  const file2 = fileOf(id);
92922
- fs30.mkdirSync(path32.dirname(file2), { recursive: true, mode: 448 });
92923
- fs30.writeFileSync(`${file2}.tmp`, JSON.stringify(checkpoint), { mode: 384 });
92924
- fs30.renameSync(`${file2}.tmp`, file2);
93166
+ fs31.mkdirSync(path34.dirname(file2), { recursive: true, mode: 448 });
93167
+ fs31.writeFileSync(`${file2}.tmp`, JSON.stringify(checkpoint), { mode: 384 });
93168
+ fs31.renameSync(`${file2}.tmp`, file2);
92925
93169
  }
92926
93170
  function clearCheckpoint(id) {
92927
- fs30.rmSync(fileOf(id), { force: true });
93171
+ fs31.rmSync(fileOf(id), { force: true });
92928
93172
  }
92929
93173
  function checkpointEvent(checkpoint, event2) {
92930
93174
  if (event2.kind === "tool_call") {
@@ -92936,19 +93180,30 @@ function checkpointEvent(checkpoint, event2) {
92936
93180
  checkpoint.pending = checkpoint.pending.filter((id) => id !== event2.data.toolCallId);
92937
93181
  }
92938
93182
  }
93183
+ async function stopReply(id, timeout) {
93184
+ const checkpoint = readCheckpoint(id);
93185
+ if (!checkpoint?.mark) return checkpoint?.started === false;
93186
+ killMarked(checkpoint.mark, checkpoint.process);
93187
+ const until = Date.now() + timeout;
93188
+ while (!processesStopped(checkpoint.mark, checkpoint.process)) {
93189
+ if (Date.now() >= until) return false;
93190
+ await new Promise((resolve2) => setTimeout(resolve2, 50));
93191
+ }
93192
+ return true;
93193
+ }
92939
93194
 
92940
93195
  // src/lock.ts
92941
- import crypto4 from "node:crypto";
92942
- import fs31 from "node:fs";
93196
+ import crypto5 from "node:crypto";
93197
+ import fs32 from "node:fs";
92943
93198
  import net from "node:net";
92944
- import path33 from "node:path";
93199
+ import path35 from "node:path";
92945
93200
  var RETRY_MS = 5e3;
92946
93201
  var KIND_MS = 1e3;
92947
93202
  var HOLDERS = ["claude-code", "codex", "terminal"];
92948
93203
  function lockPath() {
92949
93204
  const home4 = runnerHome();
92950
- if (process.platform === "win32") return `\\\\.\\pipe\\wildcrane-${crypto4.createHash("sha256").update(home4).digest("hex").slice(0, 16)}`;
92951
- return path33.join(home4, "runner.sock");
93205
+ if (process.platform === "win32") return `\\\\.\\pipe\\wildcrane-${crypto5.createHash("sha256").update(home4).digest("hex").slice(0, 16)}`;
93206
+ return path35.join(home4, "runner.sock");
92952
93207
  }
92953
93208
  function holdMachine(kind, onHeld, onWaiting) {
92954
93209
  const where = lockPath();
@@ -92963,12 +93218,12 @@ function holdMachine(kind, onHeld, onWaiting) {
92963
93218
  const attempt = () => {
92964
93219
  timer = null;
92965
93220
  if (closed) return;
92966
- if (process.platform !== "win32") fs31.mkdirSync(path33.dirname(where), { recursive: true, mode: 448 });
93221
+ if (process.platform !== "win32") fs32.mkdirSync(path35.dirname(where), { recursive: true, mode: 448 });
92967
93222
  const s = net.createServer((peer) => {
92968
93223
  peers.add(peer);
92969
93224
  peer.on("error", () => {
92970
93225
  }).on("close", () => peers.delete(peer));
92971
- peer.write(`${JSON.stringify({ kind })}
93226
+ peer.write(`${JSON.stringify({ kind, settings: 1 })}
92972
93227
  `);
92973
93228
  });
92974
93229
  s.once("error", (e2) => {
@@ -93011,7 +93266,7 @@ function holdMachine(kind, onHeld, onWaiting) {
93011
93266
  later(0);
93012
93267
  });
93013
93268
  removeIfStill.once("error", () => {
93014
- fs31.rmSync(where, { force: true });
93269
+ fs32.rmSync(where, { force: true });
93015
93270
  later(50 + Math.random() * 200);
93016
93271
  });
93017
93272
  return;
@@ -93040,17 +93295,17 @@ function holdMachine(kind, onHeld, onWaiting) {
93040
93295
  }
93041
93296
 
93042
93297
  // src/handoff.ts
93043
- import crypto5 from "node:crypto";
93044
- import fs32 from "node:fs";
93045
- import path34 from "node:path";
93046
- import { execFileSync } from "node:child_process";
93047
- var digest = (value) => crypto5.createHash("sha256").update(value).digest("hex");
93048
- var git3 = (cwd, ...args) => execFileSync("git", ["-C", cwd, ...args], { encoding: "utf8", timeout: 15e3, maxBuffer: 16 * 1024 * 1024, stdio: ["ignore", "pipe", "ignore"] });
93298
+ import crypto6 from "node:crypto";
93299
+ import fs33 from "node:fs";
93300
+ import path36 from "node:path";
93301
+ import { execFileSync as execFileSync2 } from "node:child_process";
93302
+ var digest = (value) => crypto6.createHash("sha256").update(value).digest("hex");
93303
+ var git3 = (cwd, ...args) => execFileSync2("git", ["-C", cwd, ...args], { encoding: "utf8", timeout: 15e3, maxBuffer: 16 * 1024 * 1024, stdio: ["ignore", "pipe", "ignore"] });
93049
93304
  function authorizedFolder(folder) {
93050
93305
  if (!folder) return null;
93051
93306
  try {
93052
- const real = fs32.realpathSync(folder);
93053
- return allowedProjects().some((root) => real === root || real.startsWith(root + path34.sep)) ? real : null;
93307
+ const real = fs33.realpathSync(folder);
93308
+ return allowedProjects().some((root) => real === root || real.startsWith(root + path36.sep)) ? real : null;
93054
93309
  } catch {
93055
93310
  return null;
93056
93311
  }
@@ -93060,9 +93315,9 @@ function progressFolder(job, folder) {
93060
93315
  if (!token) return folder;
93061
93316
  if (!/^[a-zA-Z0-9-]{1,80}$/.test(token)) return null;
93062
93317
  try {
93063
- const dir = fs32.realpathSync(path34.join(folder, ".akb", "handoffs", token));
93064
- if (!dir.startsWith(fs32.realpathSync(folder) + path34.sep)) return null;
93065
- const marker = JSON.parse(fs32.readFileSync(path34.join(dir, ".akb", "handoff.json"), "utf8"));
93318
+ const dir = fs33.realpathSync(path36.join(folder, ".akb", "handoffs", token));
93319
+ if (!dir.startsWith(fs33.realpathSync(folder) + path36.sep)) return null;
93320
+ const marker = JSON.parse(fs33.readFileSync(path36.join(dir, ".akb", "handoff.json"), "utf8"));
93066
93321
  return marker.task === job.task && marker.isolation === token ? dir : null;
93067
93322
  } catch {
93068
93323
  return null;
@@ -93070,24 +93325,24 @@ function progressFolder(job, folder) {
93070
93325
  }
93071
93326
  function progressEvidence(job, folder) {
93072
93327
  try {
93073
- const board = path34.join(folder, ".akb", "kanban");
93074
- const deliveries = path34.join(board, "deliveries");
93075
- const rows = fs32.readdirSync(deliveries).filter((name) => name.endsWith(".json")).map((name) => JSON.parse(fs32.readFileSync(path34.join(deliveries, name), "utf8"))).filter((row2) => row2.cardId === job.number).sort((a3, b2) => (b2.startedAt ?? 0) - (a3.startedAt ?? 0));
93328
+ const board = path36.join(folder, ".akb", "kanban");
93329
+ const deliveries = path36.join(board, "deliveries");
93330
+ const rows = fs33.readdirSync(deliveries).filter((name) => name.endsWith(".json")).map((name) => JSON.parse(fs33.readFileSync(path36.join(deliveries, name), "utf8"))).filter((row2) => row2.cardId === job.number).sort((a3, b2) => (b2.startedAt ?? 0) - (a3.startedAt ?? 0));
93076
93331
  const row = rows[0];
93077
93332
  if (!row?.deliveryId || !row.base || !row.branch || !row.worktree || row.commitMode !== "auto") return null;
93078
- const tree = fs32.realpathSync(path34.resolve(folder, row.worktree));
93079
- if (!tree.startsWith(fs32.realpathSync(folder) + path34.sep)) return null;
93333
+ const tree = fs33.realpathSync(path36.resolve(folder, row.worktree));
93334
+ if (!tree.startsWith(fs33.realpathSync(folder) + path36.sep)) return null;
93080
93335
  if (git3(tree, "rev-parse", "--show-toplevel").trim() !== tree) return null;
93081
93336
  if (git3(tree, "branch", "--show-current").trim() !== row.branch) return null;
93082
93337
  git3(tree, "cat-file", "-e", `${row.base}^{commit}`);
93083
93338
  const changed = git3(tree, "ls-files", "-z", "--cached", "--others", "--exclude-standard").split("\0").filter(Boolean).sort();
93084
93339
  const files = changed.map((name) => {
93085
- const file2 = path34.join(tree, name);
93340
+ const file2 = path36.join(tree, name);
93086
93341
  try {
93087
- const stat = fs32.lstatSync(file2);
93088
- if (stat.isSymbolicLink()) return [name, "link", digest(fs32.readlinkSync(file2))];
93342
+ const stat = fs33.lstatSync(file2);
93343
+ if (stat.isSymbolicLink()) return [name, "link", digest(fs33.readlinkSync(file2))];
93089
93344
  if (!stat.isFile()) throw new Error("\u65E0\u6CD5\u9A8C\u8BC1\u6587\u4EF6\u7C7B\u578B");
93090
- return [name, stat.mode & 511, digest(fs32.readFileSync(file2))];
93345
+ return [name, stat.mode & 511, digest(fs33.readFileSync(file2))];
93091
93346
  } catch (e2) {
93092
93347
  if (e2.code === "ENOENT") return [name, "deleted"];
93093
93348
  throw e2;
@@ -93112,56 +93367,56 @@ function progressEvidence(job, folder) {
93112
93367
  function restartFolder(job, folder) {
93113
93368
  const token = job.handoff?.isolation ?? job.id;
93114
93369
  if (!/^[a-zA-Z0-9-]{1,80}$/.test(token)) throw new Error("\u9694\u79BB\u76EE\u5F55\u7F16\u53F7\u65E0\u6548\u3002");
93115
- const dir = path34.join(folder, ".akb", "handoffs", token);
93116
- const marker = path34.join(dir, ".akb", "handoff.json");
93117
- for (const parent of [path34.join(folder, ".akb"), path34.dirname(dir), dir]) {
93118
- if (fs32.lstatSync(parent, { throwIfNoEntry: false })?.isSymbolicLink()) throw new Error("\u9694\u79BB\u76EE\u5F55\u4E0D\u80FD\u901A\u8FC7\u7B26\u53F7\u94FE\u63A5\u521B\u5EFA\u3002");
93370
+ const dir = path36.join(folder, ".akb", "handoffs", token);
93371
+ const marker = path36.join(dir, ".akb", "handoff.json");
93372
+ for (const parent of [path36.join(folder, ".akb"), path36.dirname(dir), dir]) {
93373
+ if (fs33.lstatSync(parent, { throwIfNoEntry: false })?.isSymbolicLink()) throw new Error("\u9694\u79BB\u76EE\u5F55\u4E0D\u80FD\u901A\u8FC7\u7B26\u53F7\u94FE\u63A5\u521B\u5EFA\u3002");
93119
93374
  }
93120
- if (fs32.existsSync(dir)) {
93375
+ if (fs33.existsSync(dir)) {
93121
93376
  if (job.handoff?.recovering) {
93122
93377
  try {
93123
- const saved = JSON.parse(fs32.readFileSync(marker, "utf8"));
93124
- if (saved.task === job.task && saved.isolation === token && git3(dir, "rev-parse", "--show-toplevel").trim() === fs32.realpathSync(dir)) return dir;
93378
+ const saved = JSON.parse(fs33.readFileSync(marker, "utf8"));
93379
+ if (saved.task === job.task && saved.isolation === token && git3(dir, "rev-parse", "--show-toplevel").trim() === fs33.realpathSync(dir)) return dir;
93125
93380
  } catch {
93126
93381
  }
93127
93382
  }
93128
93383
  throw new Error("\u91CD\u542F\u76EE\u5F55\u5DF2\u5B58\u5728\uFF0C\u8BF7\u91CD\u65B0\u68C0\u67E5\u3002");
93129
93384
  }
93130
- fs32.mkdirSync(path34.dirname(dir), { recursive: true });
93385
+ fs33.mkdirSync(path36.dirname(dir), { recursive: true });
93131
93386
  git3(folder, "worktree", "add", "--detach", dir, "HEAD");
93132
- if (fs32.lstatSync(path34.dirname(marker), { throwIfNoEntry: false })?.isSymbolicLink()) throw new Error("\u9694\u79BB\u6807\u8BB0\u76EE\u5F55\u65E0\u6548\u3002");
93133
- fs32.mkdirSync(path34.dirname(marker), { recursive: true });
93134
- fs32.writeFileSync(marker, JSON.stringify({ task: job.task, isolation: token }), { flag: "wx" });
93387
+ if (fs33.lstatSync(path36.dirname(marker), { throwIfNoEntry: false })?.isSymbolicLink()) throw new Error("\u9694\u79BB\u6807\u8BB0\u76EE\u5F55\u65E0\u6548\u3002");
93388
+ fs33.mkdirSync(path36.dirname(marker), { recursive: true });
93389
+ fs33.writeFileSync(marker, JSON.stringify({ task: job.task, isolation: token }), { flag: "wx" });
93135
93390
  return dir;
93136
93391
  }
93137
93392
 
93138
93393
  // src/jobs.ts
93139
93394
  import { spawn as spawn4 } from "node:child_process";
93140
- import fs34 from "node:fs";
93141
- import path36 from "node:path";
93395
+ import fs35 from "node:fs";
93396
+ import path38 from "node:path";
93142
93397
 
93143
93398
  // ../cli/src/lib/agent/catalog.ts
93144
- import fs33 from "node:fs";
93145
- import path35 from "node:path";
93399
+ import fs34 from "node:fs";
93400
+ import path37 from "node:path";
93146
93401
  var CATALOGUE = "https://models.dev/api.json";
93147
93402
  var FRESH_FOR_MS = 24 * 60 * 6e4;
93148
93403
  var ANSWER_BY_MS = 2e4;
93149
93404
  function cacheFile() {
93150
- return path35.join(machineHome(), "models-dev.json");
93405
+ return path37.join(machineHome(), "models-dev.json");
93151
93406
  }
93152
93407
  var held2;
93153
93408
  function readCache() {
93154
93409
  const file2 = cacheFile();
93155
93410
  let stamp2;
93156
93411
  try {
93157
- const stat = fs33.statSync(file2);
93412
+ const stat = fs34.statSync(file2);
93158
93413
  stamp2 = `${stat.mtimeMs}:${stat.size}`;
93159
93414
  } catch {
93160
93415
  return void 0;
93161
93416
  }
93162
93417
  if (held2?.stamp === stamp2) return held2.cached;
93163
93418
  try {
93164
- const data = JSON.parse(fs33.readFileSync(file2, "utf8"));
93419
+ const data = JSON.parse(fs34.readFileSync(file2, "utf8"));
93165
93420
  if (!data || typeof data.limits !== "object" || !data.limits) return void 0;
93166
93421
  const cached2 = {
93167
93422
  fetchedAt: typeof data.fetchedAt === "number" ? data.fetchedAt : 0,
@@ -93200,8 +93455,8 @@ function refreshCatalog() {
93200
93455
  const limits = limitsIn(await answer.json());
93201
93456
  if (Object.keys(limits).length === 0) return;
93202
93457
  const file2 = cacheFile();
93203
- fs33.mkdirSync(path35.dirname(file2), { recursive: true });
93204
- fs33.writeFileSync(file2, JSON.stringify({ fetchedAt: Date.now(), limits }));
93458
+ fs34.mkdirSync(path37.dirname(file2), { recursive: true });
93459
+ fs34.writeFileSync(file2, JSON.stringify({ fetchedAt: Date.now(), limits }));
93205
93460
  } catch {
93206
93461
  }
93207
93462
  })();
@@ -93276,32 +93531,32 @@ var defaultDeps = (machineId2) => ({
93276
93531
  akb: currentAkb,
93277
93532
  runtimes: detectRuntimes
93278
93533
  });
93279
- var ownFolder = () => path36.join(runnerHome(), "work");
93534
+ var ownFolder = () => path38.join(runnerHome(), "work");
93280
93535
  function folderFor(job) {
93281
93536
  if (!job.projectDir) {
93282
- const cwd = path36.join(ownFolder(), job.id);
93283
- fs34.mkdirSync(cwd, { recursive: true });
93537
+ const cwd = path38.join(ownFolder(), job.id);
93538
+ fs35.mkdirSync(cwd, { recursive: true });
93284
93539
  return { cwd };
93285
93540
  }
93286
93541
  const real = realpath4(job.projectDir);
93287
- if (real && allowedProjects().some((root) => real === root || real.startsWith(root + path36.sep))) return { cwd: real };
93542
+ if (real && allowedProjects().some((root) => real === root || real.startsWith(root + path38.sep))) return { cwd: real };
93288
93543
  return { refused: `This Runner is not allowed to work in ${job.projectDir}.` };
93289
93544
  }
93290
93545
  function realpath4(p2) {
93291
93546
  try {
93292
- return fs34.realpathSync(p2);
93547
+ return fs35.realpathSync(p2);
93293
93548
  } catch {
93294
93549
  return null;
93295
93550
  }
93296
93551
  }
93297
- var attachmentsOf = (job) => path36.join(runnerHome(), "attachments", job.id);
93552
+ var attachmentsOf = (job) => path38.join(runnerHome(), "attachments", job.id);
93298
93553
  function writeAttachments(job) {
93299
93554
  if (!job.attachments.length) return "";
93300
93555
  const dir = attachmentsOf(job);
93301
- fs34.mkdirSync(dir, { recursive: true });
93556
+ fs35.mkdirSync(dir, { recursive: true });
93302
93557
  const files = job.attachments.map((a3) => {
93303
- const file2 = path36.join(dir, path36.basename(a3.name));
93304
- fs34.writeFileSync(file2, Buffer.from(a3.content, "base64"));
93558
+ const file2 = path38.join(dir, path38.basename(a3.name));
93559
+ fs35.writeFileSync(file2, Buffer.from(a3.content, "base64"));
93305
93560
  return file2;
93306
93561
  });
93307
93562
  return `
@@ -93568,24 +93823,32 @@ async function runJob(id, deps, track = () => {
93568
93823
  const claim = await deps.api.claimJob(deps.machineId, id);
93569
93824
  if (!claim.ok || !claim.value.claimed || stopped2() || !held3(deps, lease)) return;
93570
93825
  const job = claim.value.job;
93826
+ if (deps.authorize && !await deps.authorize(job)) {
93827
+ await deps.api.finishJob(deps.machineId, id, "failed", "\u9879\u76EE\u76EE\u5F55\u6388\u6743\u5DF2\u64A4\u9500\u6216\u6682\u65F6\u65E0\u6CD5\u9A8C\u8BC1\uFF0C\u8BF7\u91CD\u65B0\u786E\u8BA4\u540E\u91CD\u8BD5\u3002");
93828
+ return;
93829
+ }
93571
93830
  const releases = [];
93572
93831
  try {
93573
93832
  await runClaimed(job, { ...deps, akb: deps.akb() }, track, (dir) => releases.push(hold(dir)), lease);
93574
93833
  } finally {
93575
93834
  for (const release2 of releases) release2();
93576
- fs34.rmSync(attachmentsOf(job), { recursive: true, force: true });
93835
+ fs35.rmSync(attachmentsOf(job), { recursive: true, force: true });
93577
93836
  }
93578
93837
  }
93579
93838
  async function runClaimed(job, deps, track, keep2, lease) {
93580
93839
  const id = job.id;
93581
- const checkpoint = readCheckpoint(id) ?? { pending: [] };
93582
- const recovering = checkpoint.updating === true;
93840
+ const checkpoint = readCheckpoint(id) ?? (job.recoveryOf ? readCheckpoint(job.recoveryOf) : null) ?? { pending: [], started: false };
93841
+ const recovering = checkpoint.updating === true || !!job.recoveryOf;
93583
93842
  const persist = () => {
93584
93843
  checkpoint.updating ||= readCheckpoint(id)?.updating;
93585
93844
  saveCheckpoint(id, checkpoint);
93586
93845
  };
93587
- if (recovering && !checkpoint.completed && (checkpoint.pending.length || checkpoint.opaque || !job.flow && checkpoint.started && !checkpoint.session)) {
93588
- await deps.api.finishJob(deps.machineId, id, "failed", UNCERTAIN);
93846
+ const manual = job.manualRecovery === true;
93847
+ if (manual && checkpoint.completed?.outcome === "failed") delete checkpoint.completed;
93848
+ checkpoint.session ??= job.resume ?? void 0;
93849
+ if (recovering && !checkpoint.completed && (!manual && (checkpoint.pending.length || checkpoint.opaque) || !job.flow && checkpoint.started && !checkpoint.session)) {
93850
+ saveCheckpoint(id, checkpoint);
93851
+ await deps.api.finishJob(deps.machineId, id, "failed", job.recoveryOf ? "recovery_failed" : UNCERTAIN);
93589
93852
  return;
93590
93853
  }
93591
93854
  if (recovering && checkpoint.session) job = { ...job, resume: checkpoint.session, fork: false };
@@ -93653,7 +93916,7 @@ async function runClaimed(job, deps, track, keep2, lease) {
93653
93916
  discussed = board.board;
93654
93917
  }
93655
93918
  if (job.discussion) {
93656
- const wrote = recovering && fs34.existsSync(goalsFileOf(job)) ? { file: goalsFileOf(job) } : await writeGoals({ ...job, discussion: job.discussion }, deps.api.listWorkflows);
93919
+ const wrote = recovering && fs35.existsSync(goalsFileOf(job)) ? { file: goalsFileOf(job) } : await writeGoals({ ...job, discussion: job.discussion }, deps.api.listWorkflows);
93657
93920
  if ("error" in wrote) throw new Error(wrote.error);
93658
93921
  goalFile = wrote.file;
93659
93922
  }
@@ -93666,7 +93929,7 @@ async function runClaimed(job, deps, track, keep2, lease) {
93666
93929
  This task came out of a discussion. Read it for what the card leaves out: ${file2}` : "";
93667
93930
  const promptOf = (said2) => {
93668
93931
  const lines = (head2 + said2).trim();
93669
- const prompt = recovering && checkpoint.started ? "Runner \u66F4\u65B0\u540E\u7EE7\u7EED\u4E4B\u524D\u4E2D\u65AD\u7684\u4EFB\u52A1\u3002\u5148\u6838\u5BF9\u5DF2\u6709\u8FDB\u5EA6\u548C\u7ED3\u679C\uFF0C\u4FDD\u7559\u5B8C\u6210\u7684\u5DE5\u4F5C\uFF0C\u4E0D\u8981\u91CD\u590D\u5DF2\u7ECF\u6267\u884C\u7684\u64CD\u4F5C\u3002" : job.prompt;
93932
+ const prompt = recovering && (checkpoint.started || job.recoveryOf) ? "\u8FDE\u63A5\u6062\u590D\u540E\u7EE7\u7EED\u4E4B\u524D\u4E2D\u65AD\u7684\u56DE\u590D\u3002\u5148\u6838\u5BF9\u5DF2\u6709\u8FDB\u5EA6\u548C\u7ED3\u679C\uFF0C\u4FDD\u7559\u5B8C\u6210\u7684\u5DE5\u4F5C\uFF0C\u4E0D\u8981\u91CD\u590D\u5DF2\u7ECF\u6267\u884C\u7684\u64CD\u4F5C\u3002" : cloudPrompt(job);
93670
93933
  return lines ? `${lines}
93671
93934
 
93672
93935
  ---
@@ -93674,9 +93937,9 @@ This task came out of a discussion. Read it for what the card leaves out: ${file
93674
93937
  ${prompt}` : prompt;
93675
93938
  };
93676
93939
  const planned = (resume, fork, said2 = "") => {
93677
- let p2 = deps.plan(job.runtime, promptOf(said2), cwd, resume, job.model, settingsOf(job), fork, job.languageLine ?? "");
93678
- if (ws) p2 = { ...p2, env: { ...p2.env, ...akbEnv(deps.akb, ws.board, ws.task, job.languageLine ?? "") } };
93679
- if (goalFile) p2 = { ...p2, env: { ...p2.env, ...akbEnv(deps.akb, discussed, void 0, job.languageLine ?? ""), KANBAN_GOALS: goalFile, KANBAN_IDEAS: goalFile } };
93940
+ let p2 = deps.plan(job.runtime, promptOf(said2), cwd, resume, job.model, settingsOf(job), fork, cloudLanguage(job));
93941
+ if (ws) p2 = { ...p2, env: akbEnv(deps.akb, ws.board, ws.task, cloudLanguage(job), p2.env) };
93942
+ if (goalFile) p2 = { ...p2, env: { ...akbEnv(deps.akb, discussed, void 0, cloudLanguage(job), p2.env), KANBAN_GOALS: goalFile, KANBAN_IDEAS: goalFile } };
93680
93943
  if (job.chat || job.discussion) {
93681
93944
  const { CLAUDE_CODE_MAX_RETRIES: _2, ...env2 } = p2.env;
93682
93945
  p2 = { ...p2, env: env2 };
@@ -93695,9 +93958,14 @@ ${prompt}` : prompt;
93695
93958
  await deps.api.finishJob(deps.machineId, id, "failed", e2 instanceof Error ? e2.message : String(e2));
93696
93959
  return;
93697
93960
  }
93961
+ if (deps.authorize && !await deps.authorize(job)) return finish(deps, id, lease, "failed", "\u9879\u76EE\u76EE\u5F55\u6388\u6743\u5DF2\u53D8\u5316\uFF0C\u8BF7\u91CD\u65B0\u786E\u8BA4\u540E\u91CD\u8BD5\u3002");
93698
93962
  if (!held3(deps, lease)) return;
93699
93963
  const stream = streamOut(deps, id, lease);
93964
+ if (run2?.startNote) stream.out(`${run2.startNote}
93965
+ `);
93966
+ let replyProgress = false;
93700
93967
  const remember = (event2) => {
93968
+ if (["message", "tool_call", "tool_call_update"].includes(event2.kind)) replyProgress = true;
93701
93969
  if (stream.lost()) return;
93702
93970
  checkpointEvent(checkpoint, event2);
93703
93971
  const session = run2?.session();
@@ -93758,6 +94026,7 @@ ${prompt}` : prompt;
93758
94026
  if (!ended3.ok) return finish(deps, id, lease, "failed", ended3.reason, proof);
93759
94027
  return sendBack(deps, id, lease, ws, { ...ended3.report, ...proof }, () => keepChat(job, ended3.report.reply));
93760
94028
  }
94029
+ checkpoint.mark = stopMark();
93761
94030
  checkpoint.started = true;
93762
94031
  checkpoint.opaque = !run2.converse && !run2.renderer?.events;
93763
94032
  checkpoint.session = run2.session() ?? checkpoint.session;
@@ -93765,7 +94034,11 @@ ${prompt}` : prompt;
93765
94034
  if (run2.converse) {
93766
94035
  const plan3 = run2;
93767
94036
  const converse = run2.converse;
93768
- const child = spawn4(plan3.command, plan3.args, { cwd, env: plan3.env, detached: process.platform !== "win32", stdio: ["pipe", "pipe", "pipe"] });
94037
+ const child = spawn4(plan3.command, plan3.args, { cwd, env: markEnv(plan3.env, checkpoint.mark), detached: process.platform !== "win32", stdio: ["pipe", "pipe", "pipe"] });
94038
+ if (child.pid) {
94039
+ checkpoint.process = { pid: child.pid, since: Date.now() };
94040
+ persist();
94041
+ }
93769
94042
  stream.adopt(child);
93770
94043
  child.stdin.on("error", () => {
93771
94044
  });
@@ -93773,22 +94046,33 @@ ${prompt}` : prompt;
93773
94046
  child.stderr.on("data", (chunk) => stream.out(quietLines(plan3, chunk)));
93774
94047
  const spawned = new Promise((resolve2) => child.on("error", (e2) => resolve2(e2.message)));
93775
94048
  const end = await Promise.race([
93776
- converse(child, remember),
94049
+ converse(child, remember, false),
93777
94050
  spawned.then((error) => ({ ok: false, error })),
93778
94051
  // Killed, the turn ends with what it said so far; one that never does is not waited on.
93779
94052
  stream.whenAsked.then(() => wait2(KILL_GRACE_MS * 2)).then(() => ({ ok: true }))
93780
94053
  ]);
94054
+ if (!end.ok && !recovering && job.resume && (job.chat || job.discussion) && sessionMissing(end.error ?? "") && !replyProgress && !checkpoint.pending.length && !stream.asked() && !stream.lost()) {
94055
+ stop(child);
94056
+ await stream.end();
94057
+ if (!await stream.confirmed()) return finish(deps, id, lease, "failed", "recovery_failed");
94058
+ clearCheckpoint(id);
94059
+ return runClaimed({ ...job, resume: null, fork: false, sessionFallback: true }, deps, track, keep2, lease);
94060
+ }
93781
94061
  if (!stream.asked()) complete(end.ok ? "done" : "failed", told(report(job, plan3, end)), end.ok ? void 0 : end.error);
93782
94062
  stop(child);
93783
94063
  await stream.end();
93784
94064
  if (stream.lost()) return;
93785
94065
  const ok = end.ok || stream.asked();
93786
94066
  const said2 = told(stream.asked() ? cutShort(report(job, plan3, end), stream.said()) : report(job, plan3, end));
93787
- if (!ok || !ws) return finish(deps, id, lease, ok ? "done" : "failed", ok ? "" : end.error ?? "", said2);
94067
+ if (!ok || !ws) return finish(deps, id, lease, ok ? "done" : "failed", ok ? "" : replyReason(end.ok ? void 0 : end.error, job), said2);
93788
94068
  return sendBack(deps, id, lease, ws, said2, () => keepChat(job, said2.reply));
93789
94069
  }
93790
94070
  const printed = async (plan3) => {
93791
- const child = spawn4(plan3.command, plan3.args, { cwd, env: plan3.env, detached: process.platform !== "win32", stdio: ["pipe", "pipe", "pipe"] });
94071
+ const child = spawn4(plan3.command, plan3.args, { cwd, env: markEnv(plan3.env, checkpoint.mark), detached: process.platform !== "win32", stdio: ["pipe", "pipe", "pipe"] });
94072
+ if (child.pid) {
94073
+ checkpoint.process = { pid: child.pid, since: Date.now() };
94074
+ persist();
94075
+ }
93792
94076
  stream.adopt(child);
93793
94077
  child.stdin.on("error", () => {
93794
94078
  });
@@ -93830,17 +94114,18 @@ ${prompt}` : prompt;
93830
94114
  if (fresh && ended2.code !== 0 && plan2.renderer.result() === void 0 && !ended2.acted && (!missingSessionOnly || sessionMissing(`${ended2.stderr}
93831
94115
  ${plan2.renderer.failure?.() ?? ""}`)) && !stream.asked() && !stream.lost()) {
93832
94116
  plan2 = fresh();
94117
+ job = { ...job, sessionFallback: missingSessionOnly };
93833
94118
  run2 = plan2;
93834
94119
  ended2 = await printed(plan2);
93835
94120
  }
93836
94121
  const renderer = plan2.renderer;
93837
94122
  if (!stream.asked()) {
93838
- const reason = ended2.error ?? renderer.failure?.() ?? (ended2.code === 0 ? void 0 : `Exited with code ${ended2.code}.`);
94123
+ const reason = replyReason(ended2.error ?? renderer.failure?.() ?? (ended2.code === 0 ? void 0 : `Exited with code ${ended2.code}.`), job);
93839
94124
  complete(reason ? "failed" : "done", told(report(job, plan2)), reason);
93840
94125
  }
93841
94126
  await stream.end();
93842
94127
  if (stream.lost()) return;
93843
- const failure = stream.asked() ? void 0 : ended2.error ?? renderer.failure?.() ?? (ended2.code === 0 ? void 0 : `Exited with code ${ended2.code}.`);
94128
+ const failure = stream.asked() ? void 0 : replyReason(ended2.error ?? renderer.failure?.() ?? (ended2.code === 0 ? void 0 : `Exited with code ${ended2.code}.`), job);
93844
94129
  const said = told(stream.asked() ? cutShort(report(job, plan2), stream.said()) : report(job, plan2));
93845
94130
  if (failure || !ws) return finish(deps, id, lease, failure ? "failed" : "done", failure, said);
93846
94131
  return sendBack(deps, id, lease, ws, said, () => keepChat(job, said.reply));
@@ -93880,18 +94165,24 @@ async function runAgentJob(job, deps, track, keep2, lease, checkpoint, persist)
93880
94165
  }
93881
94166
  var quietLines = (plan2, chunk) => chunk.split("\n").filter((line) => line && !plan2.quiet(line)).map((line) => `${line}
93882
94167
  `).join("");
93883
- var sessionMissing = (text3) => /\b(?:session|conversation|thread)\b[^\n]*(?:\bnot found\b|\bdoes not exist\b)/i.test(text3) || /\bno (?:conversation|session|thread) found\b/i.test(text3);
93884
- function signalTree(child, signal) {
94168
+ var replyReason = (reason, job) => {
94169
+ if (!reason) return reason;
94170
+ if (job.recoveryOf) return "recovery_failed";
94171
+ if (job.sessionFallback && !/auth|login|log.in|permission|directory|ENOENT|not installed|rate.limit|network|connect|登录|权限|目录/i.test(reason)) return "session_unavailable";
94172
+ return reason;
94173
+ };
94174
+ var sessionMissing = (text3) => !/auth|unauthorized|forbidden|login|log.in|登录|权限/i.test(text3) && (/\b(?:session|conversation|thread)\b[^\n]*(?:\bnot found\b|\bdoes not exist\b)/i.test(text3) || /\bno (?:conversation|session|thread) found\b/i.test(text3));
94175
+ function signalTree(child, signal2) {
93885
94176
  if (!child.pid) return;
93886
94177
  if (process.platform === "win32") {
93887
94178
  const kill = spawn4("taskkill", ["/PID", String(child.pid), "/T", "/F"], { stdio: "ignore" });
93888
- kill.on("error", () => child.kill(signal));
94179
+ kill.on("error", () => child.kill(signal2));
93889
94180
  return;
93890
94181
  }
93891
94182
  try {
93892
- process.kill(-child.pid, signal);
94183
+ process.kill(-child.pid, signal2);
93893
94184
  } catch {
93894
- child.kill(signal);
94185
+ child.kill(signal2);
93895
94186
  }
93896
94187
  }
93897
94188
  var stop = (child) => {
@@ -93964,8 +94255,8 @@ async function runTest(job, deps, lease) {
93964
94255
  const report2 = (await deps.runtimes()).find((r2) => r2.name === job.runtime);
93965
94256
  if (!report2?.installed) return finish2("failed", "not_installed");
93966
94257
  if (report2.loggedIn === false) return finish2("failed", "signed_out");
93967
- const cwd = path36.join(ownFolder(), "test");
93968
- fs34.mkdirSync(cwd, { recursive: true });
94258
+ const cwd = path38.join(ownFolder(), "test");
94259
+ fs35.mkdirSync(cwd, { recursive: true });
93969
94260
  const run2 = deps.plan(job.runtime, job.prompt, cwd, null, job.model, settingsOf(job));
93970
94261
  const startedAt = Date.now();
93971
94262
  if (run2.converse) {
@@ -94120,9 +94411,15 @@ var POLL_MS = 6e4;
94120
94411
  var BACKOFF_MS3 = [1e3, 2e3, 5e3, 1e4, 3e4];
94121
94412
  var LOOK_LATE_MS = 6e4;
94122
94413
  function startRunner(options) {
94414
+ adoptLegacy();
94415
+ const account = readSession()?.subject;
94416
+ const generation = accountGeneration();
94417
+ const releaseRecord = executorRecord();
94123
94418
  let registration = null;
94124
94419
  let connected = false;
94125
94420
  let closed = false;
94421
+ let ownsExecution = false;
94422
+ let redetect = false;
94126
94423
  let preparing = false;
94127
94424
  let attempts = 0;
94128
94425
  let live = null;
@@ -94140,7 +94437,12 @@ function startRunner(options) {
94140
94437
  const stopped2 = new Promise((resolve2) => stop2 = resolve2);
94141
94438
  const deps = () => {
94142
94439
  const base = options.deps ?? defaultDeps(registration.machineId);
94143
- return { ...base, runtimes: () => base.runtimes().then(redetected) };
94440
+ return { ...base, ...options.deps ? {} : { authorize: async (job) => {
94441
+ if (!validAccount()) return false;
94442
+ if (!job.projectDir) return true;
94443
+ const folders2 = await listFolders(registration.machineId);
94444
+ return validAccount() && folders2.ok && folders2.value.folders.some((f2) => f2.project === job.project && f2.path === job.projectDir);
94445
+ } }, runtimes: () => base.runtimes().then(redetected) };
94144
94446
  };
94145
94447
  const register2 = async () => {
94146
94448
  const answer = await register(registration);
@@ -94155,7 +94457,7 @@ function startRunner(options) {
94155
94457
  };
94156
94458
  const idle2 = () => running.size ? t.running(running.size) : t.connected(registration.machineName);
94157
94459
  const schedule = (ms) => {
94158
- if (closed) return;
94460
+ if (closed || !ownsExecution) return;
94159
94461
  if (timer) clearTimeout(timer);
94160
94462
  timer = setTimeout(tick, ms);
94161
94463
  };
@@ -94203,9 +94505,14 @@ function startRunner(options) {
94203
94505
  await close(false);
94204
94506
  stop2(s);
94205
94507
  };
94508
+ const validAccount = () => readSession()?.subject === account && accountGeneration() === generation;
94206
94509
  const tick = async () => {
94207
- if (!registration) registration = await options.registration();
94208
- else {
94510
+ if (closed || !ownsExecution) return;
94511
+ if (!validAccount()) return finish2({ reason: "refused", message: "\u8D26\u53F7\u5DF2\u9000\u51FA\u6216\u5207\u6362\u3002" });
94512
+ if (!registration || redetect) {
94513
+ redetect = false;
94514
+ registration = await options.registration();
94515
+ } else {
94209
94516
  const was = registration.runtimes;
94210
94517
  const runtimes = await refreshModels(was);
94211
94518
  if (registration.runtimes === was) registration = { ...registration, runtimes };
@@ -94283,15 +94590,17 @@ function startRunner(options) {
94283
94590
  for (const id of attempted) if (!listed2.has(id) && !running.has(id)) attempted.delete(id);
94284
94591
  for (const job of list.value.jobs) {
94285
94592
  if (closed || preparing) break;
94286
- if (job.state === "claimed" && !running.has(job.id) && !attempted.has(job.id)) {
94593
+ if ((job.state === "claimed" || job.state === "interrupted") && !running.has(job.id) && (!attempted.has(job.id) || !job.flow && !!(job.chat || job.discussion))) {
94287
94594
  const failure = await stopLeftOn(job);
94288
94595
  if (closed || preparing) break;
94289
94596
  const checkpoint = readCheckpoint(job.id);
94290
- const uncertain = checkpoint?.updating && !checkpoint.completed && (checkpoint.pending.length > 0 || checkpoint.opaque || !job.flow && checkpoint.started && !checkpoint.session);
94597
+ const reply = !job.flow && !!(job.chat || job.discussion);
94598
+ const processesStopped2 = reply ? await stopReply(job.id, deps().stopMs) : false;
94599
+ const uncertain = !!checkpoint && (checkpoint.updating || reply) && !checkpoint.completed && (checkpoint.pending.length > 0 || checkpoint.opaque || !job.flow && checkpoint.started && !checkpoint.session);
94291
94600
  if (checkpoint?.updating) status(uncertain ? UNCERTAIN : "\u6B63\u5728\u6062\u590D\u66F4\u65B0\u524D\u7684\u4EFB\u52A1\u2026");
94292
- const reason = failure ?? (uncertain ? UNCERTAIN : checkpoint?.updating ? UPDATE_REASON : "The Runner restarted while this job was running.");
94293
- const recovered = await finishJob(registration.machineId, job.id, "failed", reason, checkpoint?.session ? { session: checkpoint.session } : void 0);
94294
- if (recovered.ok && reason === UPDATE_REASON) readAgain = true;
94601
+ const reason = failure ?? (checkpoint?.updating ? uncertain ? UNCERTAIN : UPDATE_REASON : "The Runner restarted while this job was running.");
94602
+ const recovered = await finishJob(registration.machineId, job.id, "failed", reason, { ...checkpoint?.session ? { session: checkpoint.session } : {}, ...processesStopped2 ? { processesStopped: true } : {} });
94603
+ if (recovered.ok && (reason === UPDATE_REASON || processesStopped2 && recovered.value.finished)) readAgain = true;
94295
94604
  continue;
94296
94605
  }
94297
94606
  if (job.state !== "waiting" || running.has(job.id)) continue;
@@ -94381,20 +94690,42 @@ function startRunner(options) {
94381
94690
  else await Promise.race([stops, new Promise((resolve2) => timeout = setTimeout(resolve2, (options.deps?.stopMs ?? STOP_MS) + 1e3))]);
94382
94691
  clearTimeout(timeout);
94383
94692
  if (release2 && !lock.waited() && registration) await release(registration.machineId);
94693
+ clearInterval(accountWatch);
94384
94694
  lock.release();
94695
+ releaseRecord();
94385
94696
  };
94697
+ let refresh2 = "";
94698
+ const accountWatch = setInterval(() => {
94699
+ try {
94700
+ const value = fs36.readFileSync(path39.join(runnerHome(), "settings-refresh"), "utf8");
94701
+ if (value !== refresh2) {
94702
+ refresh2 = value;
94703
+ redetect = true;
94704
+ if (!closed) schedule(0);
94705
+ }
94706
+ } catch {
94707
+ }
94708
+ if (!closed && !validAccount()) void finish2({ reason: "refused", message: "\u8D26\u53F7\u5DF2\u9000\u51FA\u6216\u5207\u6362\u3002" });
94709
+ }, 200);
94710
+ accountWatch.unref();
94386
94711
  removeLegacy();
94387
94712
  pruneChats();
94388
- const lock = holdMachine(options.kind, () => void tick(), (holder) => {
94713
+ const lock = holdMachine(options.kind, () => {
94714
+ ownsExecution = true;
94715
+ void tick();
94716
+ }, (holder) => {
94389
94717
  status(t.waitingHere(holder));
94390
94718
  options.onWaiting?.(holder);
94391
94719
  });
94392
- return { stopped: stopped2, close: () => close(true), update: () => close(false, true), renew: () => schedule(0) };
94720
+ return { stopped: stopped2, close: () => close(true), update: () => close(false, true), renew: () => {
94721
+ redetect = true;
94722
+ schedule(0);
94723
+ } };
94393
94724
  }
94394
94725
 
94395
94726
  // src/signin.ts
94396
94727
  import { spawn as spawn5 } from "node:child_process";
94397
- import crypto6 from "node:crypto";
94728
+ import crypto7 from "node:crypto";
94398
94729
  import http from "node:http";
94399
94730
  var WAIT_MS = 10 * 60 * 1e3;
94400
94731
  var CRANE = "M2 55.75C2 55.69 2.69 55.09 3.55 54.37L5.09 53.1L6.61 53.1L8.13 53.1L12.49 49.87C14.9 48.07 16.83 46.58 16.77 46.53C16.75 46.47 15.56 46.64 14.15 46.89C12.74 47.13 11.55 47.3 11.53 47.24C11.47 47.19 12.02 46.22 12.71 45.06L14.01 42.96L18.21 41.34C20.53 40.45 22.41 39.65 22.41 39.57C22.41 39.49 21.27 38.55 19.92 37.5C15.92 34.4 13.13 31.31 10.86 27.47L10.01 26.01L10.53 26.18C10.84 26.26 12.96 27.2 15.28 28.25C17.6 29.32 19.53 30.12 19.59 30.07C19.64 30.01 17.68 28.69 15.25 27.11C12.8 25.57 10.56 23.97 10.31 23.58C9.15 21.95 7.25 17.5 7.25 16.46C7.25 16.26 10.01 17.95 13.38 20.18C16.77 22.45 19.73 24.38 19.95 24.49C20.42 24.74 20.25 24.57 13.9 19.02L9.18 14.88L8.6 13.36C7.72 10.96 6.97 7.54 6.97 5.77L6.97 4.14L9.4 6.46C12.66 9.61 15.56 12.01 23.57 18.25C27.32 21.18 30.5 23.72 30.64 23.91C30.8 24.08 31.68 26.51 32.6 29.3L34.28 34.35L35.72 35.65C37.54 37.3 37.98 37.47 36.85 36.09L35.96 35.01L37.12 34.71C39.11 34.21 40.16 33.52 42.54 31.12L44.8 28.8L46.02 28.96C46.71 29.07 47.56 29.07 47.95 28.96L48.67 28.8L48.67 28.25L48.67 27.69L49.27 27.69C49.63 27.69 50.1 27.58 50.32 27.42L50.71 27.17L51.01 27.42C51.18 27.56 52.78 27.86 54.58 28.08C56.37 28.3 57.86 28.52 57.94 28.58C58 28.63 56.73 28.85 55.13 29.05C53.53 29.24 50.96 29.77 49.44 30.21C47.92 30.65 46.57 31.01 46.43 31.01C46.29 31.01 44.22 32.97 41.85 35.37C37.57 39.62 34.42 42.14 30.83 44.15L29.14 45.09L25.97 45.73L22.77 46.39L14.59 51.11L6.42 55.86L4.21 55.86C2.99 55.86 2 55.8 2 55.75Z";
@@ -94419,8 +94750,9 @@ var PAGE = (outcome, lang) => {
94419
94750
  return `<!doctype html><html lang="${lang === "zh" ? "zh-CN" : "en"}"><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>${title} \xB7 WildCrane</title><style>*{margin:0;box-sizing:border-box}body{display:flex;flex-direction:column;min-height:100dvh;background:#fff;color:#24231f;font-family:ui-sans-serif,-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Helvetica,Arial,sans-serif}header{padding:16px 36px 0}main{flex:1;display:flex;align-items:center;justify-content:center;padding:0 36px 64px;text-align:center}.icon{display:flex;margin:0 auto;width:44px;height:44px;border-radius:50%;align-items:center;justify-content:center;background:${ok ? "#e4f3ea" : "#f7ddce"};color:${ok ? "#2f6b46" : "#b83a12"}}h1{margin-top:16px;font-size:24px;font-weight:850;line-height:1.25;letter-spacing:-0.02em}p{margin:8px auto 0;max-width:38ch;font-size:13px;line-height:19px;color:#565550}</style><header><svg viewBox="2 4 56 52" width="23.7" height="22" aria-hidden="true"><path d="${CRANE}" fill="#24231f"/><path d="${CREST}" fill="#dd4f1e"/></svg></header><main><div><span class="icon"><svg viewBox="0 0 24 24" width="22" height="22" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">${icon}</svg></span><h1>${title}</h1><p>${body}</p></div></main></html>`;
94420
94751
  };
94421
94752
  async function signIn(options = {}) {
94422
- const verifier = base64url(crypto6.randomBytes(32));
94423
- const challenge = base64url(crypto6.createHash("sha256").update(verifier).digest());
94753
+ const generation = accountGeneration();
94754
+ const verifier = base64url(crypto7.randomBytes(32));
94755
+ const challenge = base64url(crypto7.createHash("sha256").update(verifier).digest());
94424
94756
  let finish2 = () => {
94425
94757
  };
94426
94758
  const answered = new Promise((resolve2) => finish2 = resolve2);
@@ -94435,7 +94767,7 @@ async function signIn(options = {}) {
94435
94767
  const params = asked.searchParams;
94436
94768
  const code = params.get("code");
94437
94769
  const error = params.get("error");
94438
- const failure2 = code ? await exchange(code, verifier) : {
94770
+ const failure2 = code ? await exchange(code, verifier, generation, options.signal) : {
94439
94771
  why: error === "access_denied" ? "denied" : "other",
94440
94772
  detail: params.get("error_description") || error || "no code came back"
94441
94773
  };
@@ -94465,7 +94797,7 @@ async function signIn(options = {}) {
94465
94797
  server.close();
94466
94798
  return failure;
94467
94799
  }
94468
- async function exchange(code, verifier) {
94800
+ async function exchange(code, verifier, generation, signal2) {
94469
94801
  const { supabaseUrl, anonKey } = cloudEndpoints();
94470
94802
  let response;
94471
94803
  try {
@@ -94479,6 +94811,7 @@ async function exchange(code, verifier) {
94479
94811
  }
94480
94812
  const session = response.ok ? sessionFrom(await response.json().catch(() => ({}))) : null;
94481
94813
  if (!session) return { why: "other", detail: `Cloud answered ${response.status}` };
94814
+ if (signal2?.aborted || accountGeneration() !== generation) return { why: "cancelled", detail: "cancelled" };
94482
94815
  writeSession(session);
94483
94816
  return null;
94484
94817
  }
@@ -94523,8 +94856,8 @@ async function main() {
94523
94856
  tell({ type: "update-deferred" });
94524
94857
  });
94525
94858
  });
94526
- for (const signal of ["SIGINT", "SIGTERM"]) {
94527
- process.on(signal, async () => {
94859
+ for (const signal2 of ["SIGINT", "SIGTERM"]) {
94860
+ process.on(signal2, async () => {
94528
94861
  await runner.close();
94529
94862
  status(t.stopped());
94530
94863
  process.exit(0);