wildcrane-runner 0.6.3 → 0.6.4

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.3 — built by runner/scripts/build.mjs. Do not edit.
1
+ // wildcrane-runner 0.6.4 — 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;
@@ -426,19 +426,19 @@ var require_react_production = __commonJS({
426
426
  _init: lazyInitializer
427
427
  };
428
428
  };
429
- exports.memo = function(type, compare) {
429
+ exports.memo = function(type, compare2) {
430
430
  return {
431
431
  $$typeof: REACT_MEMO_TYPE,
432
432
  type,
433
- compare: void 0 === compare ? null : compare
433
+ compare: void 0 === compare2 ? null : compare2
434
434
  };
435
435
  };
436
436
  exports.startTransition = startTransition;
437
437
  exports.unstable_useCacheRefresh = function() {
438
438
  return ReactSharedInternals.H.useCacheRefresh();
439
439
  };
440
- exports.use = function(usable) {
441
- return ReactSharedInternals.H.use(usable);
440
+ exports.use = function(usable2) {
441
+ return ReactSharedInternals.H.use(usable2);
442
442
  };
443
443
  exports.useActionState = function(action, initialState, permalink) {
444
444
  return ReactSharedInternals.H.useActionState(action, initialState, permalink);
@@ -1386,18 +1386,18 @@ var require_react_development = __commonJS({
1386
1386
  lazyType._debugInfo = [{ awaited: ioInfo }];
1387
1387
  return lazyType;
1388
1388
  };
1389
- exports.memo = function(type, compare) {
1389
+ exports.memo = function(type, compare2) {
1390
1390
  null == type && console.error(
1391
1391
  "memo: The first argument must be a component. Instead received: %s",
1392
1392
  null === type ? "null" : typeof type
1393
1393
  );
1394
- compare = {
1394
+ compare2 = {
1395
1395
  $$typeof: REACT_MEMO_TYPE,
1396
1396
  type,
1397
- compare: void 0 === compare ? null : compare
1397
+ compare: void 0 === compare2 ? null : compare2
1398
1398
  };
1399
1399
  var ownName;
1400
- Object.defineProperty(compare, "displayName", {
1400
+ Object.defineProperty(compare2, "displayName", {
1401
1401
  enumerable: false,
1402
1402
  configurable: true,
1403
1403
  get: function() {
@@ -1408,14 +1408,14 @@ var require_react_development = __commonJS({
1408
1408
  type.name || type.displayName || (Object.defineProperty(type, "name", { value: name }), type.displayName = name);
1409
1409
  }
1410
1410
  });
1411
- return compare;
1411
+ return compare2;
1412
1412
  };
1413
1413
  exports.startTransition = startTransition;
1414
1414
  exports.unstable_useCacheRefresh = function() {
1415
1415
  return resolveDispatcher().useCacheRefresh();
1416
1416
  };
1417
- exports.use = function(usable) {
1418
- return resolveDispatcher().use(usable);
1417
+ exports.use = function(usable2) {
1418
+ return resolveDispatcher().use(usable2);
1419
1419
  };
1420
1420
  exports.useActionState = function(action, initialState, permalink) {
1421
1421
  return resolveDispatcher().useActionState(
@@ -4909,15 +4909,15 @@ var require_react_dom_server_legacy_node_production = __commonJS({
4909
4909
  readContext: function(context) {
4910
4910
  return context._currentValue2;
4911
4911
  },
4912
- use: function(usable) {
4913
- if (null !== usable && "object" === typeof usable) {
4914
- if ("function" === typeof usable.then) return unwrapThenable(usable);
4915
- if (usable.$$typeof === REACT_RECOVERABLE_TYPE)
4916
- throw createRecoverableError(usable);
4917
- if (usable.$$typeof === REACT_CONTEXT_TYPE)
4918
- return usable._currentValue2;
4919
- }
4920
- throw Error("An unsupported type was passed to use(): " + String(usable));
4912
+ use: function(usable2) {
4913
+ if (null !== usable2 && "object" === typeof usable2) {
4914
+ if ("function" === typeof usable2.then) return unwrapThenable(usable2);
4915
+ if (usable2.$$typeof === REACT_RECOVERABLE_TYPE)
4916
+ throw createRecoverableError(usable2);
4917
+ if (usable2.$$typeof === REACT_CONTEXT_TYPE)
4918
+ return usable2._currentValue2;
4919
+ }
4920
+ throw Error("An unsupported type was passed to use(): " + String(usable2));
4921
4921
  },
4922
4922
  useContext: function(context) {
4923
4923
  resolveCurrentlyRenderingComponent();
@@ -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 crypto5 = __require("crypto");
7520
+ var crypto6 = __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 = crypto5.createHash("md5");
10385
+ componentKeyPath = crypto6.createHash("md5");
10386
10386
  componentKeyPath.update(permalink);
10387
10387
  return "k" + componentKeyPath.digest("hex");
10388
10388
  }
@@ -10440,14 +10440,14 @@ var require_react_dom_server_node_production = __commonJS({
10440
10440
  readContext: function(context) {
10441
10441
  return context._currentValue;
10442
10442
  },
10443
- use: function(usable) {
10444
- if (null !== usable && "object" === typeof usable) {
10445
- if ("function" === typeof usable.then) return unwrapThenable(usable);
10446
- if (usable.$$typeof === REACT_RECOVERABLE_TYPE)
10447
- throw createRecoverableError(usable);
10448
- if (usable.$$typeof === REACT_CONTEXT_TYPE) return usable._currentValue;
10449
- }
10450
- throw Error("An unsupported type was passed to use(): " + String(usable));
10443
+ use: function(usable2) {
10444
+ if (null !== usable2 && "object" === typeof usable2) {
10445
+ if ("function" === typeof usable2.then) return unwrapThenable(usable2);
10446
+ if (usable2.$$typeof === REACT_RECOVERABLE_TYPE)
10447
+ throw createRecoverableError(usable2);
10448
+ if (usable2.$$typeof === REACT_CONTEXT_TYPE) return usable2._currentValue;
10449
+ }
10450
+ throw Error("An unsupported type was passed to use(): " + String(usable2));
10451
10451
  },
10452
10452
  useContext: function(context) {
10453
10453
  resolveCurrentlyRenderingComponent();
@@ -21050,17 +21050,17 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
21050
21050
  "Suspense Exception: This is not a real error! It's an implementation detail of `use` to interrupt the current render. You must either rethrow it immediately, or move the `use` call outside of the `try/catch` block. Capturing without rethrowing will lead to unexpected behavior.\n\nTo handle async errors, wrap your component in an error boundary, or call the promise's `.catch` method and pass the result to `use`."
21051
21051
  ), suspendedThenable = null, shouldCaptureSuspendedCallSite = false, suspendedCallSiteStack = null, suspendedCallSiteDebugTask = null, objectIs = "function" === typeof Object.is ? Object.is : is, currentlyRenderingComponent = null, currentlyRenderingTask = null, currentlyRenderingRequest = null, currentlyRenderingKeyPath = null, firstWorkInProgressHook = null, workInProgressHook = null, isReRender = false, didScheduleRenderPhaseUpdate = false, localIdCounter = 0, actionStateCounter = 0, actionStateMatchingIndex = -1, thenableIndexCounter = 0, thenableState = null, renderPhaseUpdates = null, numberOfReRenders = 0, isInHookUserCodeInDev = false, currentHookNameInDev, HooksDispatcher = {
21052
21052
  readContext,
21053
- use: function(usable) {
21054
- if (null !== usable && "object" === typeof usable) {
21055
- if ("function" === typeof usable.then)
21056
- return unwrapThenable(usable);
21057
- if (usable.$$typeof === REACT_RECOVERABLE_TYPE)
21058
- throw createRecoverableError(usable);
21059
- if (usable.$$typeof === REACT_CONTEXT_TYPE)
21060
- return readContext(usable);
21053
+ use: function(usable2) {
21054
+ if (null !== usable2 && "object" === typeof usable2) {
21055
+ if ("function" === typeof usable2.then)
21056
+ return unwrapThenable(usable2);
21057
+ if (usable2.$$typeof === REACT_RECOVERABLE_TYPE)
21058
+ throw createRecoverableError(usable2);
21059
+ if (usable2.$$typeof === REACT_CONTEXT_TYPE)
21060
+ return readContext(usable2);
21061
21061
  }
21062
21062
  throw Error(
21063
- "An unsupported type was passed to use(): " + String(usable)
21063
+ "An unsupported type was passed to use(): " + String(usable2)
21064
21064
  );
21065
21065
  },
21066
21066
  useContext: function(context) {
@@ -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 = crypto5.createHash("md5");
24379
+ componentKeyPath = crypto6.createHash("md5");
24380
24380
  componentKeyPath.update(permalink);
24381
24381
  return "k" + componentKeyPath.digest("hex");
24382
24382
  }
@@ -28038,7 +28038,7 @@ var require_react_dom_server_node_development = __commonJS({
28038
28038
  }
28039
28039
  };
28040
28040
  }
28041
- var util = __require("util"), crypto5 = __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"), crypto6 = __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(
@@ -28999,17 +28999,17 @@ A.finished.finally(function(){document.__reactViewTransition===A&&(document.__re
28999
28999
  "Suspense Exception: This is not a real error! It's an implementation detail of `use` to interrupt the current render. You must either rethrow it immediately, or move the `use` call outside of the `try/catch` block. Capturing without rethrowing will lead to unexpected behavior.\n\nTo handle async errors, wrap your component in an error boundary, or call the promise's `.catch` method and pass the result to `use`."
29000
29000
  ), suspendedThenable = null, shouldCaptureSuspendedCallSite = false, suspendedCallSiteStack = null, suspendedCallSiteDebugTask = null, objectIs = "function" === typeof Object.is ? Object.is : is, currentlyRenderingComponent = null, currentlyRenderingTask = null, currentlyRenderingRequest = null, currentlyRenderingKeyPath = null, firstWorkInProgressHook = null, workInProgressHook = null, isReRender = false, didScheduleRenderPhaseUpdate = false, localIdCounter = 0, actionStateCounter = 0, actionStateMatchingIndex = -1, thenableIndexCounter = 0, thenableState = null, renderPhaseUpdates = null, numberOfReRenders = 0, isInHookUserCodeInDev = false, currentHookNameInDev, HooksDispatcher = {
29001
29001
  readContext,
29002
- use: function(usable) {
29003
- if (null !== usable && "object" === typeof usable) {
29004
- if ("function" === typeof usable.then)
29005
- return unwrapThenable(usable);
29006
- if (usable.$$typeof === REACT_RECOVERABLE_TYPE)
29007
- throw createRecoverableError(usable);
29008
- if (usable.$$typeof === REACT_CONTEXT_TYPE)
29009
- return readContext(usable);
29002
+ use: function(usable2) {
29003
+ if (null !== usable2 && "object" === typeof usable2) {
29004
+ if ("function" === typeof usable2.then)
29005
+ return unwrapThenable(usable2);
29006
+ if (usable2.$$typeof === REACT_RECOVERABLE_TYPE)
29007
+ throw createRecoverableError(usable2);
29008
+ if (usable2.$$typeof === REACT_CONTEXT_TYPE)
29009
+ return readContext(usable2);
29010
29010
  }
29011
29011
  throw Error(
29012
- "An unsupported type was passed to use(): " + String(usable)
29012
+ "An unsupported type was passed to use(): " + String(usable2)
29013
29013
  );
29014
29014
  },
29015
29015
  useContext: function(context) {
@@ -41256,8 +41256,8 @@ var require_JSXTransformer = __commonJS({
41256
41256
  }
41257
41257
  if (this.isAutomaticRuntime) {
41258
41258
  if (this.importProcessor) {
41259
- for (const [path31, resolvedName] of Object.entries(this.cjsAutomaticModuleNameResolutions)) {
41260
- prefix += `var ${resolvedName} = require("${path31}");`;
41259
+ for (const [path34, resolvedName] of Object.entries(this.cjsAutomaticModuleNameResolutions)) {
41260
+ prefix += `var ${resolvedName} = require("${path34}");`;
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 path31 = this.jsxImportSource + importPathSuffix;
41454
- if (!this.cjsAutomaticModuleNameResolutions[path31]) {
41455
- this.cjsAutomaticModuleNameResolutions[path31] = this.importProcessor.getFreeIdentifierForPath(path31);
41453
+ const path34 = this.jsxImportSource + importPathSuffix;
41454
+ if (!this.cjsAutomaticModuleNameResolutions[path34]) {
41455
+ this.cjsAutomaticModuleNameResolutions[path34] = this.importProcessor.getFreeIdentifierForPath(path34);
41456
41456
  }
41457
- return `${this.cjsAutomaticModuleNameResolutions[path31]}.${funcName}`;
41457
+ return `${this.cjsAutomaticModuleNameResolutions[path34]}.${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 [path31, importInfo] of this.importInfoByPath.entries()) {
41893
+ for (const [path34, 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(path31, "");
41903
+ this.importsToReplace.set(path34, "");
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 [path31, importInfo] of this.importInfoByPath.entries()) {
41911
+ for (const [path34, 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(path31, `require('${path31}');`);
41921
+ this.importsToReplace.set(path34, `require('${path34}');`);
41922
41922
  continue;
41923
41923
  }
41924
- const primaryImportName = this.getFreeIdentifierForPath(path31);
41924
+ const primaryImportName = this.getFreeIdentifierForPath(path34);
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(path31);
41929
+ secondaryImportName = wildcardNames.length > 0 ? wildcardNames[0] : this.getFreeIdentifierForPath(path34);
41930
41930
  }
41931
- let requireCode = `var ${primaryImportName} = require('${path31}');`;
41931
+ let requireCode = `var ${primaryImportName} = require('${path34}');`;
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(path31, requireCode);
41959
+ this.importsToReplace.set(path34, 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(path31) {
41969
- const components = path31.split("/");
41968
+ getFreeIdentifierForPath(path34) {
41969
+ const components = path34.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 path31 = this.tokens.stringValueAtIndex(index);
42015
- const importInfo = this.getImportInfo(path31);
42014
+ const path34 = this.tokens.stringValueAtIndex(index);
42015
+ const importInfo = this.getImportInfo(path34);
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 path31 = this.tokens.stringValueAtIndex(index);
42083
- const importInfo = this.getImportInfo(path31);
42082
+ const path34 = this.tokens.stringValueAtIndex(index);
42083
+ const importInfo = this.getImportInfo(path34);
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 path31 = this.tokens.stringValueAtIndex(index);
42099
- const importInfo = this.getImportInfo(path31);
42098
+ const path34 = this.tokens.stringValueAtIndex(index);
42099
+ const importInfo = this.getImportInfo(path34);
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(path31) {
42140
- const existingInfo = this.importInfoByPath.get(path31);
42139
+ getImportInfo(path34) {
42140
+ const existingInfo = this.importInfoByPath.get(path34);
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(path31, newInfo);
42153
+ this.importInfoByPath.set(path34, 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 path31 = match[2];
42734
- return makeUrl("file:", "", match[1] || "", "", isAbsolutePath(path31) ? path31 : "/" + path31, match[3] || "", match[4] || "");
42733
+ const path34 = match[2];
42734
+ return makeUrl("file:", "", match[1] || "", "", isAbsolutePath(path34) ? path34 : "/" + path34, match[3] || "", match[4] || "");
42735
42735
  }
42736
- function makeUrl(scheme, user, host, port, path31, query, hash) {
42736
+ function makeUrl(scheme, user, host, port, path34, query, hash) {
42737
42737
  return {
42738
42738
  scheme,
42739
42739
  user,
42740
42740
  host,
42741
42741
  port,
42742
- path: path31,
42742
+ path: path34,
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(path31) {
42773
- if (path31.endsWith("/.."))
42774
- return path31;
42775
- const index = path31.lastIndexOf("/");
42776
- return path31.slice(0, index + 1);
42772
+ function stripPathFilename(path34) {
42773
+ if (path34.endsWith("/.."))
42774
+ return path34;
42775
+ const index = path34.lastIndexOf("/");
42776
+ return path34.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 path31 = "";
42814
+ let path34 = "";
42815
42815
  for (let i = 1; i < pointer; i++) {
42816
- path31 += "/" + pieces[i];
42816
+ path34 += "/" + pieces[i];
42817
42817
  }
42818
- if (!path31 || addTrailingSlash && !path31.endsWith("/..")) {
42819
- path31 += "/";
42818
+ if (!path34 || addTrailingSlash && !path34.endsWith("/..")) {
42819
+ path34 += "/";
42820
42820
  }
42821
- url.path = path31;
42821
+ url.path = path34;
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 path31 = url.path.slice(1);
42863
- if (!path31)
42862
+ const path34 = url.path.slice(1);
42863
+ if (!path34)
42864
42864
  return queryHash || ".";
42865
- if (isRelative(base || input) && !isRelative(path31)) {
42866
- return "./" + path31 + queryHash;
42865
+ if (isRelative(base || input) && !isRelative(path34)) {
42866
+ return "./" + path34 + queryHash;
42867
42867
  }
42868
- return path31 + queryHash;
42868
+ return path34 + 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(path31) {
42968
- if (!path31) return "";
42969
- const index = path31.lastIndexOf("/");
42970
- return path31.slice(0, index + 1);
42967
+ function stripFilename(path34) {
42968
+ if (!path34) return "";
42969
+ const index = path34.lastIndexOf("/");
42970
+ return path34.slice(0, index + 1);
42971
42971
  }
42972
42972
  function resolver(mapUrl, sourceRoot) {
42973
42973
  const from = stripFilename(mapUrl);
@@ -43091,11 +43091,11 @@ var require_trace_mapping_umd = __commonJS({
43091
43091
  state.lastNeedle = needle;
43092
43092
  return state.lastIndex = binarySearch(haystack, needle, low, high);
43093
43093
  }
43094
- function parse(map2) {
43094
+ function parse2(map2) {
43095
43095
  return typeof map2 === "string" ? JSON.parse(map2) : map2;
43096
43096
  }
43097
43097
  var FlattenMap = function(map2, mapUrl) {
43098
- const parsed = parse(map2);
43098
+ const parsed = parse2(map2);
43099
43099
  if (!("sections" in parsed)) {
43100
43100
  return new TraceMap(parsed, mapUrl);
43101
43101
  }
@@ -43159,7 +43159,7 @@ var require_trace_mapping_umd = __commonJS({
43159
43159
  }
43160
43160
  }
43161
43161
  function addSection(input, mapUrl, mappings, sources, sourcesContent, names2, ignoreList, lineOffset, columnOffset, stopLine, stopColumn) {
43162
- const parsed = parse(input);
43162
+ const parsed = parse2(input);
43163
43163
  if ("sections" in parsed) return recurse(...arguments);
43164
43164
  const map2 = new TraceMap(parsed, mapUrl);
43165
43165
  const sourcesOffset = sources.length;
@@ -43209,7 +43209,7 @@ var require_trace_mapping_umd = __commonJS({
43209
43209
  constructor(map2, mapUrl) {
43210
43210
  const isString = typeof map2 === "string";
43211
43211
  if (!isString && map2._decodedMemo) return map2;
43212
- const parsed = parse(map2);
43212
+ const parsed = parse2(map2);
43213
43213
  const { version, file: file2, names: names2, sourceRoot, sources, sourcesContent } = parsed;
43214
43214
  this.version = version;
43215
43215
  this.file = file2;
@@ -44175,9 +44175,9 @@ var require_util2 = __commonJS({
44175
44175
  /** @class */
44176
44176
  (function(_super) {
44177
44177
  __extends(VError2, _super);
44178
- function VError2(path31, message) {
44178
+ function VError2(path34, message) {
44179
44179
  var _this = _super.call(this, message) || this;
44180
- _this.path = path31;
44180
+ _this.path = path34;
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(path31) {
44240
+ DetailContext2.prototype.getError = function(path34) {
44241
44241
  var msgParts = [];
44242
44242
  for (var i = this._propNames.length - 1; i >= 0; i--) {
44243
44243
  var p2 = this._propNames[i];
44244
- path31 += typeof p2 === "number" ? "[" + p2 + "]" : p2 ? "." + p2 : "";
44244
+ path34 += typeof p2 === "number" ? "[" + p2 + "]" : p2 ? "." + p2 : "";
44245
44245
  var m = this._messages[i];
44246
44246
  if (m) {
44247
- msgParts.push(path31 + " " + m);
44247
+ msgParts.push(path34 + " " + m);
44248
44248
  }
44249
44249
  }
44250
- return new VError(path31, msgParts.join("; "));
44250
+ return new VError(path34, msgParts.join("; "));
44251
44251
  };
44252
- DetailContext2.prototype.getErrorDetail = function(path31) {
44252
+ DetailContext2.prototype.getErrorDetail = function(path34) {
44253
44253
  var details = [];
44254
44254
  for (var i = this._propNames.length - 1; i >= 0; i--) {
44255
44255
  var p2 = this._propNames[i];
44256
- path31 += typeof p2 === "number" ? "[" + p2 + "]" : p2 ? "." + p2 : "";
44256
+ path34 += typeof p2 === "number" ? "[" + p2 + "]" : p2 ? "." + p2 : "";
44257
44257
  var message = this._messages[i];
44258
44258
  if (message) {
44259
- details.push({ path: path31, message });
44259
+ details.push({ path: path34, 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(path31) {
45073
- this._path = path31;
45072
+ Checker2.prototype.setReportedPath = function(path34) {
45073
+ this._path = path34;
45074
45074
  };
45075
45075
  Checker2.prototype.check = function(value) {
45076
45076
  return this._doCheck(this.checkerPlain, value);
@@ -49654,7 +49654,7 @@ var require_parser = __commonJS({
49654
49654
  }
49655
49655
  };
49656
49656
  exports.File = File;
49657
- function parse(input, isJSXEnabled, isTypeScriptEnabled, isFlowEnabled) {
49657
+ function parse2(input, isJSXEnabled, isTypeScriptEnabled, isFlowEnabled) {
49658
49658
  if (isFlowEnabled && isTypeScriptEnabled) {
49659
49659
  throw new Error("Cannot combine flow and typescript plugins.");
49660
49660
  }
@@ -49665,7 +49665,7 @@ var require_parser = __commonJS({
49665
49665
  }
49666
49666
  return result;
49667
49667
  }
49668
- exports.parse = parse;
49668
+ exports.parse = parse2;
49669
49669
  }
49670
49670
  });
49671
49671
 
@@ -50503,9 +50503,9 @@ var require_CJSImportTransformer = __commonJS({
50503
50503
  if (shouldElideImport) {
50504
50504
  this.tokens.removeToken();
50505
50505
  } else {
50506
- const path31 = this.tokens.stringValue();
50507
- this.tokens.replaceTokenTrimmingLeftWhitespace(this.importProcessor.claimImportCode(path31));
50508
- this.tokens.appendCode(this.importProcessor.claimImportCode(path31));
50506
+ const path34 = this.tokens.stringValue();
50507
+ this.tokens.replaceTokenTrimmingLeftWhitespace(this.importProcessor.claimImportCode(path34));
50508
+ this.tokens.appendCode(this.importProcessor.claimImportCode(path34));
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 path31 = this.tokens.stringValue();
51089
- this.tokens.replaceTokenTrimmingLeftWhitespace(this.importProcessor.claimImportCode(path31));
51088
+ const path34 = this.tokens.stringValue();
51089
+ this.tokens.replaceTokenTrimmingLeftWhitespace(this.importProcessor.claimImportCode(path34));
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 path31 = this.tokens.stringValue();
51104
- this.tokens.replaceTokenTrimmingLeftWhitespace(this.importProcessor.claimImportCode(path31));
51103
+ const path34 = this.tokens.stringValue();
51104
+ this.tokens.replaceTokenTrimmingLeftWhitespace(this.importProcessor.claimImportCode(path34));
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, path31) => {
80748
+ getPart = (classPartObject, path34) => {
80749
80749
  let current = classPartObject;
80750
- const parts = path31.split(CLASS_PART_SEPARATOR);
80750
+ const parts = path34.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];
@@ -84001,8 +84001,8 @@ var mockup_exports = {};
84001
84001
  __export(mockup_exports, {
84002
84002
  drawMockup: () => drawMockup
84003
84003
  });
84004
- import fs16 from "node:fs";
84005
- import path19 from "node:path";
84004
+ import fs19 from "node:fs";
84005
+ import path22 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 = path19.resolve(path19.dirname(from), id);
84019
- if (at2 !== folder && !at2.startsWith(folder + path19.sep)) throw new Error(`${id} is outside the mockup's folder`);
84020
- const tries = path19.extname(at2) ? [at2] : [...CODE_EXTS.map((e2) => at2 + e2), ...CODE_EXTS.map((e2) => path19.join(at2, `index${e2}`))];
84021
- const file2 = tries.find((f2) => fs16.statSync(f2, { throwIfNoEntry: false })?.isFile());
84018
+ const at2 = path22.resolve(path22.dirname(from), id);
84019
+ if (at2 !== folder && !at2.startsWith(folder + path22.sep)) throw new Error(`${id} is outside the mockup's folder`);
84020
+ const tries = path22.extname(at2) ? [at2] : [...CODE_EXTS.map((e2) => at2 + e2), ...CODE_EXTS.map((e2) => path22.join(at2, `index${e2}`))];
84021
+ const file2 = tries.find((f2) => fs19.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 = path19.dirname(entry);
84026
+ const folder = path22.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)(fs16.readFileSync(file2, "utf8"), { transforms: ["typescript", "jsx", "imports"], jsxRuntime: "automatic", production: true, filePath: file2 }).code;
84031
+ const js = (0, import_sucrase.transform)(fs19.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: fs16.readFileSync(target, "utf8") });
84043
+ else if (!graph.sheets.some((s) => s.path === target)) graph.sheets.push({ path: target, content: fs19.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 ? path19.dirname(sheets[0].path) : "/",
84057
+ base: sheets.length ? path22.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 = path19.resolve(from, id);
84062
- return { path: at2, base: path19.dirname(at2), content: fs16.readFileSync(at2, "utf8") };
84061
+ const at2 = path22.resolve(from, id);
84062
+ return { path: at2, base: path22.dirname(at2), content: fs19.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 = path19.dirname(file2);
84070
- const html = fs16.readFileSync(file2, "utf8").replace(/<link\b[^>]*>/gi, (tag) => {
84069
+ const folder = path22.dirname(file2);
84070
+ const html = fs19.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 = path19.resolve(folder, href);
84074
- if (!at3.startsWith(folder + path19.sep) || !fs16.existsSync(at3)) return tag;
84075
- return `<style>${fs16.readFileSync(at3, "utf8").replace(/<\/style/gi, "<\\/style")}</style>`;
84073
+ const at3 = path22.resolve(folder, href);
84074
+ if (!at3.startsWith(folder + path22.sep) || !fs19.existsSync(at3)) return tag;
84075
+ return `<style>${fs19.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>`;
@@ -84224,10 +84224,10 @@ function readSession() {
84224
84224
  return null;
84225
84225
  }
84226
84226
  try {
84227
- const held3 = JSON.parse(raw);
84228
- if (!held3.accessToken || !held3.refreshToken || !held3.subject) return null;
84229
- if (held3.supabaseUrl !== cloudEndpoints().supabaseUrl) return null;
84230
- return { ...held3, version: 1, expiresAt: Number(held3.expiresAt) || 0 };
84227
+ const held4 = JSON.parse(raw);
84228
+ if (!held4.accessToken || !held4.refreshToken || !held4.subject) return null;
84229
+ if (held4.supabaseUrl !== cloudEndpoints().supabaseUrl) return null;
84230
+ return { ...held4, version: 1, expiresAt: Number(held4.expiresAt) || 0 };
84231
84231
  } catch {
84232
84232
  return null;
84233
84233
  }
@@ -84246,9 +84246,9 @@ function clearSession() {
84246
84246
  }
84247
84247
  }
84248
84248
  async function accessToken() {
84249
- const held3 = readSession();
84250
- if (!held3) return { ok: false, reason: "signed-out" };
84251
- if (!expiringSoon(held3)) return { ok: true, token: held3.accessToken, session: held3 };
84249
+ const held4 = readSession();
84250
+ if (!held4) return { ok: false, reason: "signed-out" };
84251
+ if (!expiringSoon(held4)) return { ok: true, token: held4.accessToken, session: held4 };
84252
84252
  return refresh();
84253
84253
  }
84254
84254
  var expiringSoon = (session) => session.expiresAt - REFRESH_MARGIN_MS <= Date.now();
@@ -84333,14 +84333,14 @@ async function takeLock() {
84333
84333
  }
84334
84334
  }
84335
84335
  function stale() {
84336
- let held3;
84336
+ let held4;
84337
84337
  try {
84338
84338
  const pid = Number(fs.readFileSync(lockOwner(), "utf8").trim());
84339
- held3 = Number.isInteger(pid) && pid > 0 ? pid : void 0;
84339
+ held4 = Number.isInteger(pid) && pid > 0 ? pid : void 0;
84340
84340
  } catch {
84341
- held3 = void 0;
84341
+ held4 = void 0;
84342
84342
  }
84343
- if (held3 !== void 0 && !alive(held3)) return true;
84343
+ if (held4 !== void 0 && !alive(held4)) return true;
84344
84344
  try {
84345
84345
  return Date.now() - fs.statSync(lockDir()).mtimeMs > LOCK_STALE_MS;
84346
84346
  } catch {
@@ -84371,8 +84371,8 @@ function useRunnerHome() {
84371
84371
  function machineId() {
84372
84372
  const file2 = path3.join(runnerHome(), "machine.json");
84373
84373
  try {
84374
- const held3 = JSON.parse(fs2.readFileSync(file2, "utf8"));
84375
- if (held3.id && /^[0-9a-f-]{36}$/i.test(held3.id)) return held3.id;
84374
+ const held4 = JSON.parse(fs2.readFileSync(file2, "utf8"));
84375
+ if (held4.id && /^[0-9a-f-]{36}$/i.test(held4.id)) return held4.id;
84376
84376
  } catch {
84377
84377
  }
84378
84378
  const id = crypto.randomUUID();
@@ -84453,7 +84453,9 @@ function status(line) {
84453
84453
  }
84454
84454
 
84455
84455
  // src/protocol.ts
84456
- var VERSION = true ? "0.6.3" : "0.0.0";
84456
+ var VERSION = true ? "0.6.4" : "0.0.0";
84457
+ var AKB_VERSION = true ? "0.11.3" : "0.0.0";
84458
+ var AKB_CONTRACT = true ? 1 : 0;
84457
84459
  var EXIT_REFUSED = 10;
84458
84460
  var EXIT_OUTDATED = 11;
84459
84461
 
@@ -84918,16 +84920,16 @@ function createEventCollector() {
84918
84920
  let queue = [];
84919
84921
  let said = "";
84920
84922
  const todoCalls = /* @__PURE__ */ new Set();
84921
- const held3 = /* @__PURE__ */ new Map();
84923
+ const held4 = /* @__PURE__ */ new Map();
84922
84924
  let todos = [];
84923
84925
  const close = () => {
84924
84926
  if (said.trim()) queue.push({ kind: "message", data: { text: said.trim() } });
84925
84927
  said = "";
84926
84928
  };
84927
84929
  const release2 = (id, target) => {
84928
- const call = held3.get(id);
84930
+ const call = held4.get(id);
84929
84931
  if (!call) return;
84930
- held3.delete(id);
84932
+ held4.delete(id);
84931
84933
  queue.push({ kind: "tool_call", data: { ...call, ...target ? { target } : {} } });
84932
84934
  };
84933
84935
  return {
@@ -84949,7 +84951,7 @@ function createEventCollector() {
84949
84951
  }
84950
84952
  const target = targetIn(u2);
84951
84953
  const data = { toolCallId: id, title: str(u2.title) || "tool", kind: toolKind(u2.kind), status: str(u2.status) || "pending", ...target ? { target } : {} };
84952
- if (u2.rawInput !== void 0 && !inputTarget(obj(u2.rawInput))) held3.set(id, data);
84954
+ if (u2.rawInput !== void 0 && !inputTarget(obj(u2.rawInput))) held4.set(id, data);
84953
84955
  else queue.push({ kind: "tool_call", data });
84954
84956
  return;
84955
84957
  }
@@ -85019,7 +85021,7 @@ function createEventCollector() {
85019
85021
  /** The turn is over: a half-held message is finished off. */
85020
85022
  end() {
85021
85023
  close();
85022
- for (const id of [...held3.keys()]) release2(id);
85024
+ for (const id of [...held4.keys()]) release2(id);
85023
85025
  },
85024
85026
  /** What arrived since the last call. */
85025
85027
  events() {
@@ -85115,12 +85117,19 @@ function promptSize(raw) {
85115
85117
  const size = num(u2.input_tokens) + num(u2.cache_creation_input_tokens) + num(u2.cache_read_input_tokens);
85116
85118
  return size > 0 ? size : void 0;
85117
85119
  }
85120
+ function windowOf(raw, model) {
85121
+ const entries = obj(raw);
85122
+ const names2 = Object.keys(entries);
85123
+ const name = model && names2.includes(model) ? model : names2.length === 1 ? names2[0] : void 0;
85124
+ return name ? num(obj(entries[name]).contextWindow) || void 0 : void 0;
85125
+ }
85118
85126
  function createStreamRenderer() {
85119
85127
  let final;
85120
85128
  let cost;
85121
85129
  let model;
85122
85130
  let usage;
85123
85131
  let context;
85132
+ let limit;
85124
85133
  let failure;
85125
85134
  let offStream;
85126
85135
  let background;
@@ -85175,6 +85184,7 @@ function createStreamRenderer() {
85175
85184
  }
85176
85185
  case "result": {
85177
85186
  if (typeof ev.result === "string") final = ev.result;
85187
+ limit = windowOf(ev.modelUsage, model) ?? limit;
85178
85188
  if (typeof ev.total_cost_usd === "number" && Number.isFinite(ev.total_cost_usd) && ev.total_cost_usd > 0) {
85179
85189
  cost = ev.total_cost_usd;
85180
85190
  }
@@ -85209,7 +85219,7 @@ function createStreamRenderer() {
85209
85219
  result: () => final,
85210
85220
  costUsd: () => cost,
85211
85221
  usage: () => usage,
85212
- context: () => context,
85222
+ context: () => context && limit ? { ...context, limit } : context,
85213
85223
  model: () => model,
85214
85224
  failure: () => failure,
85215
85225
  offStream: () => offStream,
@@ -85299,10 +85309,10 @@ function findRollout(threadId) {
85299
85309
  }
85300
85310
  for (const name of names2) {
85301
85311
  if (!name.startsWith("rollout-") || !name.endsWith(tail)) continue;
85302
- const path31 = join(dir, name);
85312
+ const path34 = join(dir, name);
85303
85313
  try {
85304
- const at2 = statSync(path31).mtimeMs;
85305
- if (!newest2 || at2 > newest2.at) newest2 = { path: path31, at: at2 };
85314
+ const at2 = statSync(path34).mtimeMs;
85315
+ if (!newest2 || at2 > newest2.at) newest2 = { path: path34, at: at2 };
85306
85316
  } catch {
85307
85317
  }
85308
85318
  }
@@ -85310,11 +85320,11 @@ function findRollout(threadId) {
85310
85320
  return newest2?.path;
85311
85321
  }
85312
85322
  function readCodexRunFacts(threadId) {
85313
- const path31 = findRollout(threadId);
85314
- if (!path31) return void 0;
85323
+ const path34 = findRollout(threadId);
85324
+ if (!path34) return void 0;
85315
85325
  let raw;
85316
85326
  try {
85317
- raw = readFileSync(path31, "utf8");
85327
+ raw = readFileSync(path34, "utf8");
85318
85328
  } catch {
85319
85329
  return void 0;
85320
85330
  }
@@ -85422,8 +85432,8 @@ function renderCompleted(item) {
85422
85432
  const changes = Array.isArray(item.changes) ? item.changes : [];
85423
85433
  return changes.map((raw) => {
85424
85434
  const change = obj(raw);
85425
- const path31 = str(change.path);
85426
- return path31 ? `\u23FA ${str(change.kind) || "change"}(${path31})
85435
+ const path34 = str(change.path);
85436
+ return path34 ? `\u23FA ${str(change.kind) || "change"}(${path34})
85427
85437
  ` : "";
85428
85438
  }).join("");
85429
85439
  }
@@ -85671,10 +85681,10 @@ function readKimiRunFacts(sessionId) {
85671
85681
  const total = { input: 0, cacheCreation: 0, cacheRead: 0, output: 0 };
85672
85682
  let model;
85673
85683
  let holding = 0;
85674
- for (const { path: path31, main: main2 } of wireFiles(entry.sessionDir)) {
85684
+ for (const { path: path34, main: main2 } of wireFiles(entry.sessionDir)) {
85675
85685
  let raw;
85676
85686
  try {
85677
- raw = readFileSync2(path31, "utf8");
85687
+ raw = readFileSync2(path34, "utf8");
85678
85688
  } catch {
85679
85689
  continue;
85680
85690
  }
@@ -85927,8 +85937,62 @@ function createTail(log) {
85927
85937
  };
85928
85938
  }
85929
85939
 
85940
+ // ../cli/package.json
85941
+ var package_default = {
85942
+ name: "wildcrane",
85943
+ version: "0.11.3",
85944
+ akbContract: 1,
85945
+ 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.",
85946
+ keywords: [
85947
+ "kanban",
85948
+ "claude",
85949
+ "claude-code",
85950
+ "codex",
85951
+ "agent",
85952
+ "skill",
85953
+ "markdown",
85954
+ "board"
85955
+ ],
85956
+ license: "FSL-1.1-ALv2",
85957
+ homepage: "https://wildcrane.ai/",
85958
+ repository: {
85959
+ type: "git",
85960
+ url: "git+https://github.com/ai4kanban/ai4kanban.git",
85961
+ directory: "cli"
85962
+ },
85963
+ type: "module",
85964
+ bin: {
85965
+ akb: "bin/ai4kanban.mjs",
85966
+ wildcrane: "bin/ai4kanban.mjs"
85967
+ },
85968
+ files: [
85969
+ "bin/",
85970
+ "dist/"
85971
+ ],
85972
+ engines: {
85973
+ node: ">=18.0.0"
85974
+ },
85975
+ scripts: {
85976
+ build: "node scripts/build.mjs",
85977
+ prepare: "node scripts/build.mjs",
85978
+ typecheck: "tsc -p tsconfig.json --noEmit",
85979
+ test: "node scripts/test.mjs",
85980
+ lint: "npm run typecheck",
85981
+ prepublishOnly: "npm run build",
85982
+ "eval:qa": "node scripts/qa-eval.mjs"
85983
+ },
85984
+ devDependencies: {
85985
+ "@types/node": "^22.20.1",
85986
+ esbuild: "^0.28.2",
85987
+ typescript: "^5.9.3"
85988
+ },
85989
+ dependencies: {
85990
+ commander: "^13.1.0"
85991
+ }
85992
+ };
85993
+
85930
85994
  // ../cli/src/version.ts
85931
- var SKILL_VERSION = "0.11.2";
85995
+ var SKILL_VERSION = package_default.version;
85932
85996
 
85933
85997
  // ../cli/src/lib/agent/wire/acp.ts
85934
85998
  var PROTOCOL_VERSION = 1;
@@ -85938,8 +86002,8 @@ var CLIENT_CAPABILITIES = {
85938
86002
  };
85939
86003
  function whereHint(update2, title) {
85940
86004
  const locations = Array.isArray(update2.locations) ? update2.locations : [];
85941
- const path31 = str(obj(locations[0]).path);
85942
- return path31 && !title.includes(path31) ? hint(path31) : "";
86005
+ const path34 = str(obj(locations[0]).path);
86006
+ return path34 && !title.includes(path34) ? hint(path34) : "";
85943
86007
  }
85944
86008
  function saidBy(update2) {
85945
86009
  const content = Array.isArray(update2.content) ? update2.content : [];
@@ -85967,9 +86031,9 @@ function modelsIn(answer) {
85967
86031
  return modelId ? [{ modelId, name: str(m.name) || modelId }] : [];
85968
86032
  });
85969
86033
  }
85970
- function pickedModel(answer, wanted) {
86034
+ function pickedModel(answer, wanted2) {
85971
86035
  const list = modelsIn(answer);
85972
- return list.find((m) => m.modelId === wanted) ?? list.find((m) => m.name === wanted || m.modelId.split("[")[0] === wanted);
86036
+ return list.find((m) => m.modelId === wanted2) ?? list.find((m) => m.name === wanted2 || m.modelId.split("[")[0] === wanted2);
85973
86037
  }
85974
86038
  function usageOf2(value, grossInput = false) {
85975
86039
  const usage = obj(value);
@@ -86370,9 +86434,9 @@ async function oneTurn2(io, options) {
86370
86434
  }
86371
86435
  let model = modelOf2(obj(opened.session).model);
86372
86436
  if (options.model) {
86373
- const wanted = options.model.includes("/") ? { providerId: options.model.split("/")[0], modelId: options.model.split("/").slice(1).join("/") } : { providerId: str(obj(obj(opened.session).model).providerId) || "zai", modelId: options.model };
86374
- await rpc.call("session/setModel", { sessionId, model: wanted });
86375
- model = modelOf2(wanted);
86437
+ const wanted2 = options.model.includes("/") ? { providerId: options.model.split("/")[0], modelId: options.model.split("/").slice(1).join("/") } : { providerId: str(obj(obj(opened.session).model).providerId) || "zai", modelId: options.model };
86438
+ await rpc.call("session/setModel", { sessionId, model: wanted2 });
86439
+ model = modelOf2(wanted2);
86376
86440
  }
86377
86441
  if (model) io.gotModel(model);
86378
86442
  await rpc.call("session/subscribe", {
@@ -86879,7 +86943,6 @@ var CONFIG = "";
86879
86943
  var KANBAN_GITIGNORE = "";
86880
86944
  var RELEASES = "";
86881
86945
  var RELEASE_SUMMARIES = "";
86882
- var SETUP_CHECKLIST = "";
86883
86946
  var AGENTS = "";
86884
86947
  var WORKFLOWS = "";
86885
86948
  var LEGACY_AGENTS = "";
@@ -86929,7 +86992,6 @@ function setBoard(kanban, root, flag) {
86929
86992
  KANBAN_GITIGNORE = path9.join(KANBAN, ".gitignore");
86930
86993
  RELEASES = path9.join(KANBAN, "releases.md");
86931
86994
  RELEASE_SUMMARIES = path9.join(KANBAN, ".release-summaries");
86932
- SETUP_CHECKLIST = path9.join(KANBAN, "setup-checklist.md");
86933
86995
  AGENTS = path9.join(KANBAN, "agents");
86934
86996
  WORKFLOWS = path9.join(KANBAN, "workflows");
86935
86997
  LEGACY_AGENTS = path9.join(KANBAN, "skills");
@@ -87777,7 +87839,7 @@ ${text3}
87777
87839
  // PROBE: on a machine that has `kimi`, run its login command's status form under a
87778
87840
  // throwaway HOME and under the real one. If it says which state it is in, declare it here.
87779
87841
  installs: () => [...process.env.KIMI_INSTALL_DIR ? [join5(process.env.KIMI_INSTALL_DIR, "bin", "kimi")] : [], home2(".kimi-code", "bin", "kimi")],
87780
- install: "curl -LsSf https://code.kimi.com/install.sh | bash"
87842
+ install: "curl -fsSL https://code.kimi.com/kimi-code/install.sh | bash"
87781
87843
  };
87782
87844
 
87783
87845
  // ../cli/src/lib/agent/harnesses/opencode.ts
@@ -88024,15 +88086,15 @@ function isFilled(harness, { values, secretsSet: secretsSet2 }) {
88024
88086
  return setting?.kind === "secret" ? secretsSet2.includes(key) : Boolean(values[key]);
88025
88087
  };
88026
88088
  }
88027
- function providerFor(harness, held3) {
88089
+ function providerFor(harness, held4) {
88028
88090
  const setting = providerSetting(harness.settings);
88029
88091
  if (!setting) return void 0;
88030
- return pickedProvider(setting, held3.values[setting.key] ?? "", isFilled(harness, held3));
88092
+ return pickedProvider(setting, held4.values[setting.key] ?? "", isFilled(harness, held4));
88031
88093
  }
88032
- function settingArgs(harness, held3) {
88033
- const { values } = held3;
88034
- const ignored = held3.ignored ?? [];
88035
- const picked = providerFor(harness, held3);
88094
+ function settingArgs(harness, held4) {
88095
+ const { values } = held4;
88096
+ const ignored = held4.ignored ?? [];
88097
+ const picked = providerFor(harness, held4);
88036
88098
  const list = providerSetting(harness.settings);
88037
88099
  const byHand = !!list && ignored.includes(list.key);
88038
88100
  const providerArgs = byHand ? [] : picked?.args ?? [];
@@ -88047,9 +88109,9 @@ function settingArgs(harness, held3) {
88047
88109
  });
88048
88110
  return [...providerArgs, ...flags, ...splitCommand(values[RAW_ARGS_KEY] ?? "")];
88049
88111
  }
88050
- function settingEnv(harness, held3, secrets, cwd) {
88051
- const { values } = held3;
88052
- const picked = providerFor(harness, held3);
88112
+ function settingEnv(harness, held4, secrets, cwd) {
88113
+ const { values } = held4;
88114
+ const picked = providerFor(harness, held4);
88053
88115
  const env2 = { ...harness.env() };
88054
88116
  for (const name of ownedVars(harness)) delete env2[name];
88055
88117
  for (const name of Object.values(SESSION_VARS)) delete env2[name];
@@ -88076,11 +88138,11 @@ function ownedVars(harness) {
88076
88138
  }
88077
88139
  return [...names2];
88078
88140
  }
88079
- function effectiveValues(harness, held3) {
88080
- const picked = providerFor(harness, held3);
88141
+ function effectiveValues(harness, held4) {
88142
+ const picked = providerFor(harness, held4);
88081
88143
  const out = {};
88082
88144
  for (const setting of harness.settings) {
88083
- const value = held3.values[setting.key];
88145
+ const value = held4.values[setting.key];
88084
88146
  if (!value || setting.kind === "secret") continue;
88085
88147
  if (!shownForProvider(harness.settings, setting.key, picked)) continue;
88086
88148
  out[setting.key] = value;
@@ -88128,6 +88190,7 @@ __export(api_exports, {
88128
88190
  readArtifact: () => readArtifact,
88129
88191
  readBoard: () => readBoard,
88130
88192
  readChat: () => readChat,
88193
+ readDecisions: () => readDecisions,
88131
88194
  readDiscussion: () => readDiscussion,
88132
88195
  readInbox: () => readInbox,
88133
88196
  readPlan: () => readPlan,
@@ -88162,8 +88225,8 @@ import path12 from "node:path";
88162
88225
  var file = () => path12.join(runnerHome(), "secrets.json");
88163
88226
  function readAll() {
88164
88227
  try {
88165
- const held3 = JSON.parse(fs9.readFileSync(file(), "utf8"));
88166
- return held3 && typeof held3 === "object" ? held3 : {};
88228
+ const held4 = JSON.parse(fs9.readFileSync(file(), "utf8"));
88229
+ return held4 && typeof held4 === "object" ? held4 : {};
88167
88230
  } catch {
88168
88231
  return {};
88169
88232
  }
@@ -88171,12 +88234,12 @@ function readAll() {
88171
88234
  var secretsOf = (runtime) => runtime ? readAll()[runtime] ?? {} : {};
88172
88235
  function keepSecrets(runtime, given) {
88173
88236
  const all = readAll();
88174
- const held3 = { ...all[runtime] };
88237
+ const held4 = { ...all[runtime] };
88175
88238
  for (const [key, value] of Object.entries(given)) {
88176
- if (value) held3[key] = value;
88177
- else delete held3[key];
88239
+ if (value) held4[key] = value;
88240
+ else delete held4[key];
88178
88241
  }
88179
- if (Object.keys(held3).length) all[runtime] = held3;
88242
+ if (Object.keys(held4).length) all[runtime] = held4;
88180
88243
  else delete all[runtime];
88181
88244
  fs9.mkdirSync(runnerHome(), { recursive: true, mode: 448 });
88182
88245
  const temp = `${file()}.${process.pid}.tmp`;
@@ -88242,7 +88305,7 @@ async function upload(route, bytes2, type) {
88242
88305
  const sent = await send("PUT", route, bytes2, true, FILE_TIMEOUT_MS, type);
88243
88306
  return sent.ok ? answerOf(sent.value) : sent;
88244
88307
  }
88245
- var register = (r2) => request("POST", "/v1/runner", { ...r2, secrets: secretsSet(), protocol: PROTOCOL });
88308
+ var register = (r2) => request("POST", "/v1/runner", { ...r2, secrets: secretsSet(), protocol: PROTOCOL, akbContract: AKB_CONTRACT });
88246
88309
  var readRunner = () => request("GET", "/v1/runner");
88247
88310
  var release = (machineId2) => request("POST", "/v1/runner/release", { machineId: machineId2 });
88248
88311
  var listJobs = (machineId2) => request("GET", `/v1/runner/jobs?machine=${encodeURIComponent(machineId2)}`);
@@ -88265,6 +88328,7 @@ var finishJob = (machineId2, job, outcome, reason = "", report2) => move(job, "f
88265
88328
  var answerDiff = (machineId2, id, answer) => request("POST", `/v1/runner/diffs/${encodeURIComponent(id)}`, { machineId: machineId2, ...answer });
88266
88329
  var listChats = (machineId2) => request("GET", `/v1/runner/chats?machine=${encodeURIComponent(machineId2)}`);
88267
88330
  var readChat = (task) => request("GET", `/v1/tasks/${encodeURIComponent(task)}/chat`);
88331
+ var readDecisions = (task, after) => request("GET", `/v1/tasks/${q(task)}/decisions?limit=100${after ? `&after=${q(after)}` : ""}`);
88268
88332
  var dispatchReview = (machineId2, project, tasks, runtime, model) => request("POST", "/v1/runner/reviews", { machineId: machineId2, project, tasks, runtime, model });
88269
88333
  var readAgents = (machineId2, project) => request("GET", `/v1/runner/agents?machine=${encodeURIComponent(machineId2)}&project=${encodeURIComponent(project)}`);
88270
88334
  var requestAgent = (machineId2, project, agent, workflow, seen) => request("POST", "/v1/runner/jobs", { machineId: machineId2, project, agent, workflow, seen });
@@ -88279,7 +88343,7 @@ var listFolders = (machineId2) => request("GET", `/v1/runner/folders?machine=${q
88279
88343
  var listElsewhere = (machineId2) => request("GET", `/v1/runner/folders?machine=${q(machineId2)}&elsewhere=1`);
88280
88344
  var listMachineTasks = (machineId2) => request("GET", `/v1/runner/tasks?machine=${q(machineId2)}`);
88281
88345
  var stopTask = (task, how) => request("POST", how === "chat" ? `/v1/tasks/${q(task)}/chat/stop` : `/v1/tasks/${q(task)}/stop`, {});
88282
- var addFolder = (machineId2, name, path31, project) => request("POST", "/v1/runner/folders", { machineId: machineId2, name, path: path31, ...project ? { project } : {} });
88346
+ var addFolder = (machineId2, name, path34, project) => request("POST", "/v1/runner/folders", { machineId: machineId2, name, path: path34, ...project ? { project } : {} });
88283
88347
  var removeFolder = (machineId2, project) => request("POST", `/v1/runner/folders/${q(project)}/remove`, { machineId: machineId2 });
88284
88348
  var readPlan = () => request("GET", "/v1/billing");
88285
88349
  var startTrial = () => request("POST", "/v1/billing/trial", {});
@@ -88352,6 +88416,7 @@ function plan(runtime, prompt, cwd, resume, model, given = {}, fork = false, lin
88352
88416
  if (harness.client) {
88353
88417
  const client = harness.client(effectiveValues(harness, values));
88354
88418
  let session;
88419
+ let named2;
88355
88420
  return {
88356
88421
  command: argv[0],
88357
88422
  args: argv.slice(1),
@@ -88367,12 +88432,12 @@ function plan(runtime, prompt, cwd, resume, model, given = {}, fork = false, lin
88367
88432
  gotResumeId: (got, restarted) => {
88368
88433
  if (restarted || !session) session = got;
88369
88434
  },
88370
- gotModel: () => {
88371
- },
88435
+ gotModel: (got) => named2 = got,
88372
88436
  event: event2
88373
88437
  }),
88374
88438
  quiet,
88375
- session: () => session ?? resume ?? void 0
88439
+ session: () => session ?? resume ?? void 0,
88440
+ model: () => named2
88376
88441
  };
88377
88442
  }
88378
88443
  const renderer = harness.renderer(cwd, argv[0], argv);
@@ -88384,7 +88449,8 @@ function plan(runtime, prompt, cwd, resume, model, given = {}, fork = false, lin
88384
88449
  stdin: toStdin?.(prompt),
88385
88450
  renderer,
88386
88451
  quiet,
88387
- session: () => renderer.resumeId?.() ?? resume ?? (harness.adoptsSessionId ? id : void 0)
88452
+ session: () => renderer.resumeId?.() ?? resume ?? (harness.adoptsSessionId ? id : void 0),
88453
+ model: () => renderer.model?.()
88388
88454
  };
88389
88455
  }
88390
88456
  function declOf(setting) {
@@ -88882,15 +88948,14 @@ function parseFrontmatter(text3) {
88882
88948
  if (!Array.isArray(meta.questions)) {
88883
88949
  meta.questions = meta.questions ? [normalizeQuestion(meta.questions)] : [];
88884
88950
  }
88885
- for (const key of ["priority", "roi"]) {
88886
- meta[key] = typeof meta[key] === "string" && meta[key].trim() ? meta[key].trim() : "";
88887
- }
88951
+ meta.priority = typeof meta.priority === "string" ? meta.priority.trim() : "";
88888
88952
  if (!Array.isArray(meta.modules)) meta.modules = [];
88889
88953
  delete meta.channels;
88890
88954
  delete meta.decided;
88891
88955
  delete meta.verify;
88892
88956
  delete meta.release;
88893
88957
  delete meta.schedule;
88958
+ delete meta.roi;
88894
88959
  meta.workflow = typeof meta.workflow === "string" && meta.workflow.trim() ? meta.workflow.trim() : "";
88895
88960
  meta.triage = typeof meta.triage === "string" ? meta.triage.trim() : "";
88896
88961
  meta.source = (Array.isArray(meta.source) ? meta.source : typeof meta.source === "string" ? [meta.source] : []).map((ref) => String(ref).trim()).filter(Boolean);
@@ -89036,34 +89101,120 @@ async function askDueAgents(machineId2, now = Date.now()) {
89036
89101
  return started;
89037
89102
  }
89038
89103
 
89104
+ // src/akb-version.ts
89105
+ import { execFile } from "node:child_process";
89106
+ import fs15 from "node:fs";
89107
+ import path18 from "node:path";
89108
+
89109
+ // src/akb.ts
89110
+ import { spawn as spawn3 } from "node:child_process";
89111
+ import fs11 from "node:fs";
89112
+ import path14 from "node:path";
89113
+ import { fileURLToPath } from "node:url";
89114
+ var akbHome = () => path14.join(runnerHome(), "bin", "akb");
89115
+ var BUNDLED_SHIM = `bundled-${AKB_VERSION}`;
89116
+ var bundledAkb = () => ({
89117
+ command: process.execPath,
89118
+ args: [path14.join(path14.dirname(fileURLToPath(import.meta.url)), "akb", "bin", "ai4kanban.mjs")],
89119
+ version: AKB_VERSION,
89120
+ shim: path14.join(akbHome(), BUNDLED_SHIM)
89121
+ });
89122
+ var quote = (s) => /^[\w./:@=-]+$/.test(s) ? s : `"${s}"`;
89123
+ function shimDir(akb) {
89124
+ const dir = akb.shim;
89125
+ const line = [akb.command, ...akb.args].map(quote).join(" ");
89126
+ const [file2, text3] = process.platform === "win32" ? [path14.join(dir, "akb.cmd"), `@${line} %*\r
89127
+ `] : [path14.join(dir, "akb"), `#!/bin/sh
89128
+ exec ${line} "$@"
89129
+ `];
89130
+ try {
89131
+ if (fs11.readFileSync(file2, "utf8") === text3) return dir;
89132
+ } catch {
89133
+ }
89134
+ fs11.mkdirSync(dir, { recursive: true });
89135
+ fs11.writeFileSync(file2, text3, { mode: 493 });
89136
+ return dir;
89137
+ }
89138
+ function akbEnv(akb, board, task, line) {
89139
+ const env2 = {};
89140
+ const dropped = ["AI4KANBAN_BOARD", "AI4KANBAN_TASK", LANGUAGE_LINE_ENV];
89141
+ for (const [k, v2] of Object.entries(process.env)) if (!k.startsWith("KANBAN_") && !dropped.includes(k)) env2[k] = v2;
89142
+ const key = Object.keys(env2).find((k) => k.toUpperCase() === "PATH") ?? "PATH";
89143
+ env2[key] = [shimDir(akb), env2[key]].filter(Boolean).join(path14.delimiter);
89144
+ env2.AI4KANBAN_COMMAND = "akb";
89145
+ if (board) env2.AI4KANBAN_BOARD = board;
89146
+ if (task) env2.AI4KANBAN_TASK = task;
89147
+ if (line !== void 0) env2[LANGUAGE_LINE_ENV] = line;
89148
+ return env2;
89149
+ }
89150
+ var KEEP = 256 * 1024;
89151
+ function runAkb(akb, args, opts) {
89152
+ return new Promise((resolve2) => {
89153
+ let out = "";
89154
+ let last2 = "";
89155
+ const note = (text3) => {
89156
+ const line = text3.split("\n").map((l2) => l2.trim()).filter(Boolean).at(-1);
89157
+ if (line) last2 = line;
89158
+ };
89159
+ let child;
89160
+ try {
89161
+ child = spawn3(akb.command, [...akb.args, ...args], { cwd: opts.cwd, env: akbEnv(akb, opts.board, opts.task, opts.line), stdio: ["ignore", "pipe", "pipe"] });
89162
+ } catch (e2) {
89163
+ return resolve2({ code: null, out: "", last: e2 instanceof Error ? e2.message : String(e2) });
89164
+ }
89165
+ opts.track?.(child);
89166
+ child.stdout.setEncoding("utf8");
89167
+ child.stderr.setEncoding("utf8");
89168
+ child.stdout.on("data", (chunk) => {
89169
+ out = (out + chunk).slice(-KEEP);
89170
+ note(chunk);
89171
+ opts.show?.(chunk);
89172
+ });
89173
+ child.stderr.on("data", (chunk) => {
89174
+ note(chunk);
89175
+ opts.show?.(chunk);
89176
+ });
89177
+ child.on("error", (e2) => resolve2({ code: null, out, last: e2.message }));
89178
+ child.on("close", (code) => resolve2({ code, out, last: last2 }));
89179
+ });
89180
+ }
89181
+ function answerOf2(ran) {
89182
+ const line = ran.out.trim().split("\n").at(-1) ?? "";
89183
+ try {
89184
+ return JSON.parse(line);
89185
+ } catch {
89186
+ return null;
89187
+ }
89188
+ }
89189
+
89039
89190
  // src/cache.ts
89040
89191
  import { spawnSync as spawnSync3 } from "node:child_process";
89041
- import fs12 from "node:fs";
89042
- import path15 from "node:path";
89192
+ import fs13 from "node:fs";
89193
+ import path16 from "node:path";
89043
89194
 
89044
89195
  // src/folders.ts
89045
- import fs11 from "node:fs";
89196
+ import fs12 from "node:fs";
89046
89197
  import os5 from "node:os";
89047
- import path14 from "node:path";
89048
- var projectsFile = () => path14.join(runnerHome(), "projects.json");
89198
+ import path15 from "node:path";
89199
+ var projectsFile = () => path15.join(runnerHome(), "projects.json");
89049
89200
  function realpath(p2) {
89050
89201
  try {
89051
- return fs11.realpathSync(p2);
89202
+ return fs12.realpathSync(p2);
89052
89203
  } catch {
89053
89204
  return null;
89054
89205
  }
89055
89206
  }
89056
89207
  function readList() {
89057
89208
  try {
89058
- const held3 = JSON.parse(fs11.readFileSync(projectsFile(), "utf8"));
89059
- return Array.isArray(held3.projects) ? held3.projects.filter((p2) => typeof p2 === "string") : [];
89209
+ const held4 = JSON.parse(fs12.readFileSync(projectsFile(), "utf8"));
89210
+ return Array.isArray(held4.projects) ? held4.projects.filter((p2) => typeof p2 === "string") : [];
89060
89211
  } catch {
89061
89212
  return [];
89062
89213
  }
89063
89214
  }
89064
89215
  function writeList(list) {
89065
- fs11.mkdirSync(runnerHome(), { recursive: true, mode: 448 });
89066
- fs11.writeFileSync(projectsFile(), `${JSON.stringify({ projects: [...new Set(list)] }, null, 2)}
89216
+ fs12.mkdirSync(runnerHome(), { recursive: true, mode: 448 });
89217
+ fs12.writeFileSync(projectsFile(), `${JSON.stringify({ projects: [...new Set(list)] }, null, 2)}
89067
89218
  `);
89068
89219
  }
89069
89220
  function allowedProjects() {
@@ -89087,7 +89238,7 @@ var SYSTEM_WIN = ["Windows", "Program Files", "Program Files (x86)", "ProgramDat
89087
89238
  var here = () => ({ platform: process.platform, home: os5.homedir(), resolve: realpath });
89088
89239
  function refusal(picked, where = here()) {
89089
89240
  const win = where.platform === "win32";
89090
- const p2 = win ? path14.win32 : path14.posix;
89241
+ const p2 = win ? path15.win32 : path15.posix;
89091
89242
  const real = where.resolve(picked);
89092
89243
  if (!real || !p2.isAbsolute(real)) return "missing";
89093
89244
  const norm = (d2) => {
@@ -89113,40 +89264,40 @@ function refusal(picked, where = here()) {
89113
89264
  var IDLE_MS = 7 * 24 * 60 * 6e4;
89114
89265
  var SWEEP_MS = 24 * 60 * 6e4;
89115
89266
  var PROJECT_ID = /^[\w-]{1,100}$/;
89116
- var cacheRoot = () => path15.join(runnerHome(), "cache");
89267
+ var cacheRoot = () => path16.join(runnerHome(), "cache");
89117
89268
  function cacheDir(project) {
89118
89269
  if (!PROJECT_ID.test(project)) throw new Error("This job names no project.");
89119
- return path15.join(cacheRoot(), project);
89270
+ return path16.join(cacheRoot(), project);
89120
89271
  }
89121
- var akbDir = (dir) => path15.join(dir, ".akb");
89122
- var usedFile = (dir) => path15.join(akbDir(dir), "used.json");
89123
- var unsentFile = (dir) => path15.join(akbDir(dir), "unsent");
89272
+ var akbDir = (dir) => path16.join(dir, ".akb");
89273
+ var usedFile = (dir) => path16.join(akbDir(dir), "used.json");
89274
+ var unsentFile = (dir) => path16.join(akbDir(dir), "unsent");
89124
89275
  function markUsed(dir, at2 = Date.now()) {
89125
- fs12.mkdirSync(akbDir(dir), { recursive: true });
89126
- fs12.writeFileSync(usedFile(dir), `${JSON.stringify({ at: at2 })}
89276
+ fs13.mkdirSync(akbDir(dir), { recursive: true });
89277
+ fs13.writeFileSync(usedFile(dir), `${JSON.stringify({ at: at2 })}
89127
89278
  `);
89128
89279
  }
89129
89280
  function usedAt(dir) {
89130
89281
  try {
89131
- const at2 = JSON.parse(fs12.readFileSync(usedFile(dir), "utf8")).at;
89282
+ const at2 = JSON.parse(fs13.readFileSync(usedFile(dir), "utf8")).at;
89132
89283
  return typeof at2 === "number" ? at2 : null;
89133
89284
  } catch {
89134
89285
  return null;
89135
89286
  }
89136
89287
  }
89137
- var unsent = (dir) => fs12.existsSync(unsentFile(dir));
89288
+ var unsent = (dir) => fs13.existsSync(unsentFile(dir));
89138
89289
  function markUnsent(dir, unsent2) {
89139
- if (!unsent2) return void fs12.rmSync(unsentFile(dir), { force: true });
89140
- fs12.mkdirSync(akbDir(dir), { recursive: true });
89141
- fs12.writeFileSync(unsentFile(dir), "");
89290
+ if (!unsent2) return void fs13.rmSync(unsentFile(dir), { force: true });
89291
+ fs13.mkdirSync(akbDir(dir), { recursive: true });
89292
+ fs13.writeFileSync(unsentFile(dir), "");
89142
89293
  }
89143
89294
  var holds = /* @__PURE__ */ new Map();
89144
89295
  function hold(dir) {
89145
89296
  holds.set(dir, (holds.get(dir) ?? 0) + 1);
89146
- let held3 = true;
89297
+ let held4 = true;
89147
89298
  return () => {
89148
- if (!held3) return;
89149
- held3 = false;
89299
+ if (!held4) return;
89300
+ held4 = false;
89150
89301
  const left = holds.get(dir) - 1;
89151
89302
  if (left) holds.set(dir, left);
89152
89303
  else holds.delete(dir);
@@ -89154,9 +89305,9 @@ function hold(dir) {
89154
89305
  }
89155
89306
  function paused(dir) {
89156
89307
  try {
89157
- const file2 = path15.join(projectStateDir(path15.join(akbDir(dir), "kanban")), SESSIONS_FILE);
89158
- const held3 = JSON.parse(fs12.readFileSync(file2, "utf8"));
89159
- return (held3.deliveries ?? []).some((d2) => d2.status === "active");
89308
+ const file2 = path16.join(projectStateDir(path16.join(akbDir(dir), "kanban")), SESSIONS_FILE);
89309
+ const held4 = JSON.parse(fs13.readFileSync(file2, "utf8"));
89310
+ return (held4.deliveries ?? []).some((d2) => d2.status === "active");
89160
89311
  } catch {
89161
89312
  return false;
89162
89313
  }
@@ -89168,11 +89319,11 @@ function clearAkb(dir) {
89168
89319
  if (kept2(dir)) return false;
89169
89320
  let entries;
89170
89321
  try {
89171
- entries = fs12.readdirSync(akbDir(dir));
89322
+ entries = fs13.readdirSync(akbDir(dir));
89172
89323
  } catch {
89173
89324
  return true;
89174
89325
  }
89175
- for (const name of entries) fs12.rmSync(path15.join(akbDir(dir), name), { recursive: true, force: true });
89326
+ for (const name of entries) fs13.rmSync(path16.join(akbDir(dir), name), { recursive: true, force: true });
89176
89327
  spawnSync3("git", ["-C", dir, "worktree", "prune"], { stdio: "ignore" });
89177
89328
  return true;
89178
89329
  }
@@ -89187,7 +89338,7 @@ async function readAccess(machineId2) {
89187
89338
  }
89188
89339
  function realpath2(p2) {
89189
89340
  try {
89190
- return fs12.realpathSync(p2);
89341
+ return fs13.realpathSync(p2);
89191
89342
  } catch {
89192
89343
  return p2;
89193
89344
  }
@@ -89202,25 +89353,25 @@ async function sweepCache(machineId2, now = Date.now()) {
89202
89353
  const swept = [];
89203
89354
  let cached2 = [];
89204
89355
  try {
89205
- cached2 = fs12.readdirSync(cacheRoot(), { withFileTypes: true });
89356
+ cached2 = fs13.readdirSync(cacheRoot(), { withFileTypes: true });
89206
89357
  } catch {
89207
89358
  }
89208
89359
  for (const e2 of cached2) {
89209
- const dir = path15.join(cacheRoot(), e2.name);
89360
+ const dir = path16.join(cacheRoot(), e2.name);
89210
89361
  if (!e2.isDirectory() || kept2(dir)) continue;
89211
89362
  const gone = access && !access.projects.has(e2.name);
89212
89363
  if (idle(dir, now) || gone) {
89213
- fs12.rmSync(dir, { recursive: true, force: true });
89364
+ fs13.rmSync(dir, { recursive: true, force: true });
89214
89365
  swept.push(dir);
89215
89366
  }
89216
89367
  }
89217
89368
  for (const dir of allowedProjects()) {
89218
- let held3 = [];
89369
+ let held4 = [];
89219
89370
  try {
89220
- held3 = fs12.readdirSync(akbDir(dir));
89371
+ held4 = fs13.readdirSync(akbDir(dir));
89221
89372
  } catch {
89222
89373
  }
89223
- if (!held3.length) continue;
89374
+ if (!held4.length) continue;
89224
89375
  const gone = access && !access.folders.has(dir);
89225
89376
  if ((idle(dir, now) || gone) && clearAkb(dir)) swept.push(dir);
89226
89377
  }
@@ -89228,24 +89379,231 @@ async function sweepCache(machineId2, now = Date.now()) {
89228
89379
  }
89229
89380
  function removeLegacy() {
89230
89381
  const home4 = runnerHome();
89231
- for (const name of ["boards", "akb-bin"]) fs12.rmSync(path15.join(home4, name), { recursive: true, force: true });
89382
+ for (const name of ["boards", "akb-bin"]) fs13.rmSync(path16.join(home4, name), { recursive: true, force: true });
89232
89383
  let entries = [];
89233
89384
  try {
89234
- entries = fs12.readdirSync(home4, { withFileTypes: true });
89385
+ entries = fs13.readdirSync(home4, { withFileTypes: true });
89235
89386
  } catch {
89236
89387
  return;
89237
89388
  }
89238
89389
  for (const e2 of entries) {
89239
- const account = path15.join(home4, e2.name);
89240
- if (!e2.isDirectory() || !fs12.existsSync(path15.join(account, "unfiled"))) continue;
89241
- fs12.rmSync(path15.join(account, "unfiled"), { recursive: true, force: true });
89242
- if (!fs12.readdirSync(account).length) fs12.rmdirSync(account);
89390
+ const account = path16.join(home4, e2.name);
89391
+ if (!e2.isDirectory() || !fs13.existsSync(path16.join(account, "unfiled"))) continue;
89392
+ fs13.rmSync(path16.join(account, "unfiled"), { recursive: true, force: true });
89393
+ if (!fs13.readdirSync(account).length) fs13.rmdirSync(account);
89243
89394
  }
89244
89395
  }
89245
89396
 
89246
- // src/chats.ts
89397
+ // src/update.ts
89398
+ import crypto2 from "node:crypto";
89247
89399
  import fs14 from "node:fs";
89248
89400
  import path17 from "node:path";
89401
+ import zlib from "node:zlib";
89402
+ var TIMEOUT_MS2 = 6e4;
89403
+ var registry = () => (process.env.npm_config_registry || "https://registry.npmjs.org").replace(/\/+$/, "");
89404
+ async function installPackage(pkg, version, nodeVersion = process.versions.node) {
89405
+ const dir = pkg.dirOf(version);
89406
+ if (fs14.existsSync(pkg.entryOf(dir))) return { ok: true, dir };
89407
+ let meta;
89408
+ let tarball;
89409
+ try {
89410
+ const answer = await fetch(`${registry()}/${pkg.name}/${encodeURIComponent(version)}`, { signal: AbortSignal.timeout(TIMEOUT_MS2) });
89411
+ if (!answer.ok) return { ok: false, why: "unreachable", detail: `registry answered ${answer.status}` };
89412
+ meta = await answer.json();
89413
+ const range = meta.engines?.node;
89414
+ if (range && !satisfies(nodeVersion, range)) return { ok: false, why: "node", detail: range };
89415
+ if (!meta.dist?.tarball) return { ok: false, why: "unreachable", detail: "no tarball" };
89416
+ const download2 = await fetch(meta.dist.tarball, { signal: AbortSignal.timeout(TIMEOUT_MS2) });
89417
+ if (!download2.ok) return { ok: false, why: "unreachable", detail: `download answered ${download2.status}` };
89418
+ tarball = Buffer.from(await download2.arrayBuffer());
89419
+ } catch (e2) {
89420
+ return { ok: false, why: "unreachable", detail: e2 instanceof Error ? e2.message : String(e2) };
89421
+ }
89422
+ const expected = /^sha512-(.+)$/.exec(meta.dist.integrity ?? "")?.[1];
89423
+ const actual = crypto2.createHash("sha512").update(tarball).digest("base64");
89424
+ if (!expected || expected !== actual) return { ok: false, why: "integrity", detail: "sha512 mismatch" };
89425
+ const staging = `${dir}.${process.pid}.tmp`;
89426
+ try {
89427
+ fs14.rmSync(staging, { recursive: true, force: true });
89428
+ extract(zlib.gunzipSync(tarball), staging);
89429
+ if (!fs14.existsSync(pkg.entryOf(staging))) throw new Error(`the package carries no ${path17.relative(staging, pkg.entryOf(staging))}`);
89430
+ fs14.rmSync(dir, { recursive: true, force: true });
89431
+ fs14.renameSync(staging, dir);
89432
+ } catch (e2) {
89433
+ fs14.rmSync(staging, { recursive: true, force: true });
89434
+ return { ok: false, why: "integrity", detail: e2 instanceof Error ? e2.message : String(e2) };
89435
+ }
89436
+ return { ok: true, dir };
89437
+ }
89438
+ function extract(tar, into) {
89439
+ let offset = 0;
89440
+ let longName = null;
89441
+ while (offset + 512 <= tar.length) {
89442
+ const header = tar.subarray(offset, offset + 512);
89443
+ if (header.every((b2) => b2 === 0)) break;
89444
+ const field = (start, length) => header.subarray(start, start + length).toString("utf8").replace(/\0.*$/s, "");
89445
+ const size = parseInt(field(124, 12).trim() || "0", 8);
89446
+ const type = field(156, 1) || "0";
89447
+ const body = tar.subarray(offset + 512, offset + 512 + size);
89448
+ offset += 512 + Math.ceil(size / 512) * 512;
89449
+ if (type === "x") {
89450
+ longName = /(?:^|\n)\d+ path=([^\n]*)\n/.exec(body.toString("utf8"))?.[1] ?? null;
89451
+ continue;
89452
+ }
89453
+ if (type === "L") {
89454
+ longName = body.toString("utf8").replace(/\0.*$/s, "");
89455
+ continue;
89456
+ }
89457
+ const prefix = field(345, 155);
89458
+ const name = longName ?? (prefix ? `${prefix}/${field(0, 100)}` : field(0, 100));
89459
+ longName = null;
89460
+ if (type !== "0" && type !== "5") continue;
89461
+ const relative = name.replace(/^[^/]+\//, "");
89462
+ if (!relative) continue;
89463
+ const target = path17.resolve(into, relative);
89464
+ if (!target.startsWith(path17.resolve(into) + path17.sep)) throw new Error(`refusing ${name}`);
89465
+ if (type === "5") fs14.mkdirSync(target, { recursive: true });
89466
+ else {
89467
+ fs14.mkdirSync(path17.dirname(target), { recursive: true });
89468
+ fs14.writeFileSync(target, body);
89469
+ }
89470
+ }
89471
+ }
89472
+ var parse = (v2) => {
89473
+ const m = /^v?(\d+)(?:\.(\d+|x|\*))?(?:\.(\d+|x|\*))?/.exec(v2.trim());
89474
+ return m ? [Number(m[1]), Number(m[2]) || 0, Number(m[3]) || 0] : null;
89475
+ };
89476
+ function compare(a3, b2) {
89477
+ const [x2, y2] = [parse(a3) ?? [0, 0, 0], parse(b2) ?? [0, 0, 0]];
89478
+ for (let i = 0; i < 3; i++) if (x2[i] !== y2[i]) return x2[i] - y2[i];
89479
+ return 0;
89480
+ }
89481
+ function satisfies(version, range) {
89482
+ return range.split("||").some((alternative) => {
89483
+ const parts = alternative.trim().split(/\s+/).filter(Boolean);
89484
+ return parts.length > 0 && parts.every((part) => meets(version, part));
89485
+ });
89486
+ }
89487
+ function meets(version, comparator) {
89488
+ const m = /^(>=|<=|>|<|=|\^|~)?\s*(.+)$/.exec(comparator);
89489
+ const bound = m && parse(m[2]);
89490
+ if (!m || !bound) return false;
89491
+ const v2 = parse(version);
89492
+ const c2 = compare(version, m[2]);
89493
+ switch (m[1]) {
89494
+ case ">=":
89495
+ return c2 >= 0;
89496
+ case ">":
89497
+ return c2 > 0;
89498
+ case "<=":
89499
+ return c2 <= 0;
89500
+ case "<":
89501
+ return c2 < 0;
89502
+ case "^":
89503
+ return c2 >= 0 && v2[0] === bound[0];
89504
+ case "~":
89505
+ return c2 >= 0 && v2[0] === bound[0] && v2[1] === bound[1];
89506
+ default: {
89507
+ const given = m[2].split(".").filter((p2) => /^\d+$/.test(p2)).length;
89508
+ return [0, 1, 2].slice(0, given).every((i) => v2[i] === bound[i]);
89509
+ }
89510
+ }
89511
+ }
89512
+
89513
+ // src/akb-version.ts
89514
+ var CHECK_MS2 = 1e4;
89515
+ var VERSION2 = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/;
89516
+ var stateFile = () => path18.join(akbHome(), "state.json");
89517
+ var akbVersionDir = (version) => path18.join(akbHome(), version);
89518
+ var entryOf = (dir) => path18.join(dir, "bin", "ai4kanban.mjs");
89519
+ var AKB = { name: "wildcrane", dirOf: akbVersionDir, entryOf };
89520
+ function readAkbState() {
89521
+ try {
89522
+ const held4 = JSON.parse(fs15.readFileSync(stateFile(), "utf8"));
89523
+ return { current: held4.current ?? null, bad: held4.bad ?? [] };
89524
+ } catch {
89525
+ return { current: null, bad: [] };
89526
+ }
89527
+ }
89528
+ function writeAkbState(state) {
89529
+ fs15.mkdirSync(akbHome(), { recursive: true });
89530
+ const staging = `${stateFile()}.${process.pid}.tmp`;
89531
+ fs15.writeFileSync(staging, `${JSON.stringify(state, null, 2)}
89532
+ `);
89533
+ fs15.renameSync(staging, stateFile());
89534
+ }
89535
+ function contractOf(dir) {
89536
+ try {
89537
+ return JSON.parse(fs15.readFileSync(path18.join(dir, "package.json"), "utf8")).akbContract ?? null;
89538
+ } catch {
89539
+ return null;
89540
+ }
89541
+ }
89542
+ var usable = (dir) => fs15.existsSync(entryOf(dir)) && contractOf(dir) === AKB_CONTRACT;
89543
+ function currentAkb() {
89544
+ const { current } = readAkbState();
89545
+ if (!current) return bundledAkb();
89546
+ const dir = akbVersionDir(current);
89547
+ if (!usable(dir)) return bundledAkb();
89548
+ try {
89549
+ const now = /* @__PURE__ */ new Date();
89550
+ fs15.utimesSync(dir, now, now);
89551
+ } catch {
89552
+ }
89553
+ return { command: process.execPath, args: [entryOf(dir)], version: current, shim: path18.join(dir, "shim") };
89554
+ }
89555
+ var answers2 = (dir, version) => new Promise((resolve2) => {
89556
+ execFile(process.execPath, [entryOf(dir), "--version"], { timeout: CHECK_MS2, killSignal: "SIGKILL" }, (error, stdout) => resolve2(!error && stdout.trim().split(/\s+/).at(-1) === version));
89557
+ });
89558
+ var wanted = null;
89559
+ var fetching = false;
89560
+ function useVersion(current) {
89561
+ const state = readAkbState();
89562
+ if (state.current !== current) writeAkbState({ ...state, current });
89563
+ }
89564
+ async function fetchVersion(version) {
89565
+ const got = await installPackage(AKB, version);
89566
+ if (!got.ok) return console.error(`runner: akb ${version} was not fetched: ${got.detail}`);
89567
+ if (contractOf(got.dir) !== AKB_CONTRACT || !await answers2(got.dir, version)) {
89568
+ console.error(`runner: akb ${version} failed its check and will not be used`);
89569
+ const state = readAkbState();
89570
+ return writeAkbState({ ...state, bad: [.../* @__PURE__ */ new Set([...state.bad, version])] });
89571
+ }
89572
+ if (wanted === version) useVersion(version);
89573
+ }
89574
+ async function followAkb(named2) {
89575
+ if (!named2) return;
89576
+ const { version } = named2;
89577
+ try {
89578
+ if (version !== null && !VERSION2.test(version)) return;
89579
+ wanted = version;
89580
+ if (version === null || version === AKB_VERSION) return useVersion(null);
89581
+ const state = readAkbState();
89582
+ if (fetching || state.bad.includes(version) || state.current === version && usable(akbVersionDir(version))) return;
89583
+ fetching = true;
89584
+ await fetchVersion(version).finally(() => fetching = false);
89585
+ } catch (e2) {
89586
+ console.error(`runner: the akb version was not followed: ${e2 instanceof Error ? e2.message : String(e2)}`);
89587
+ }
89588
+ }
89589
+ function sweepAkb(now = Date.now()) {
89590
+ const { current } = readAkbState();
89591
+ let entries = [];
89592
+ try {
89593
+ entries = fs15.readdirSync(akbHome(), { withFileTypes: true });
89594
+ } catch {
89595
+ return;
89596
+ }
89597
+ for (const e2 of entries) {
89598
+ if (!e2.isDirectory() || e2.name === current || e2.name === BUNDLED_SHIM) continue;
89599
+ const dir = path18.join(akbHome(), e2.name);
89600
+ if (now - fs15.statSync(dir).mtimeMs > IDLE_MS) fs15.rmSync(dir, { recursive: true, force: true });
89601
+ }
89602
+ }
89603
+
89604
+ // src/chats.ts
89605
+ import fs17 from "node:fs";
89606
+ import path20 from "node:path";
89249
89607
 
89250
89608
  // ../cloud/src/config.ts
89251
89609
  var CLAIM_LEASE_SECONDS = 15 * 60;
@@ -89261,18 +89619,18 @@ var CONTACT_ATTEMPT_WINDOW_SECONDS = 60 * 60;
89261
89619
  var CHAT_KEEP_DAYS = 30;
89262
89620
 
89263
89621
  // ../cli/src/lib/agent/task-chats.ts
89264
- import fs13 from "node:fs";
89265
- import path16 from "node:path";
89622
+ import fs16 from "node:fs";
89623
+ import path19 from "node:path";
89266
89624
  var TASK = /^[\w-]{1,100}$/;
89267
- var taskChatsDir = (home4 = machineHome()) => path16.join(home4, "chats");
89625
+ var taskChatsDir = (home4 = machineHome()) => path19.join(home4, "chats");
89268
89626
  function taskChatFile(task, home4) {
89269
89627
  if (!TASK.test(task)) throw new Error(`${task} is not a task id.`);
89270
- return path16.join(taskChatsDir(home4), `${task}.jsonl`);
89628
+ return path19.join(taskChatsDir(home4), `${task}.jsonl`);
89271
89629
  }
89272
89630
  function readTaskChat(task, home4) {
89273
89631
  let text3;
89274
89632
  try {
89275
- text3 = fs13.readFileSync(taskChatFile(task, home4), "utf8");
89633
+ text3 = fs16.readFileSync(taskChatFile(task, home4), "utf8");
89276
89634
  } catch {
89277
89635
  return [];
89278
89636
  }
@@ -89293,18 +89651,18 @@ var DAY_MS = 24 * 60 * 6e4;
89293
89651
  var REVIEW_EVERY_MS = DAY_MS;
89294
89652
  var KEEP_MS2 = CHAT_KEEP_DAYS * DAY_MS;
89295
89653
  var home3 = () => runnerHome();
89296
- var reviewedFile = () => path17.join(taskChatsDir(home3()), "reviewed.json");
89654
+ var reviewedFile = () => path20.join(taskChatsDir(home3()), "reviewed.json");
89297
89655
  function readReviewed() {
89298
89656
  try {
89299
- const held3 = JSON.parse(fs14.readFileSync(reviewedFile(), "utf8"));
89300
- return { checkedAt: Number(held3.checkedAt) || 0, tasks: held3.tasks ?? {} };
89657
+ const held4 = JSON.parse(fs17.readFileSync(reviewedFile(), "utf8"));
89658
+ return { checkedAt: Number(held4.checkedAt) || 0, tasks: held4.tasks ?? {} };
89301
89659
  } catch {
89302
89660
  return { checkedAt: 0, tasks: {} };
89303
89661
  }
89304
89662
  }
89305
89663
  function writeReviewed(reviewed) {
89306
- fs14.mkdirSync(path17.dirname(reviewedFile()), { recursive: true });
89307
- fs14.writeFileSync(reviewedFile(), `${JSON.stringify(reviewed, null, 2)}
89664
+ fs17.mkdirSync(path20.dirname(reviewedFile()), { recursive: true });
89665
+ fs17.writeFileSync(reviewedFile(), `${JSON.stringify(reviewed, null, 2)}
89308
89666
  `);
89309
89667
  }
89310
89668
  function keepChat(job, reply, at2 = Date.now()) {
@@ -89314,21 +89672,40 @@ function keepChat(job, reply, at2 = Date.now()) {
89314
89672
  { id: job.id, role: "agent", text: reply, at: at2, runtime: job.runtime, model: job.model ?? null }
89315
89673
  ];
89316
89674
  const file2 = taskChatFile(job.task, home3());
89317
- fs14.mkdirSync(path17.dirname(file2), { recursive: true });
89318
- fs14.appendFileSync(file2, lines.map((l2) => `${JSON.stringify(l2)}
89675
+ fs17.mkdirSync(path20.dirname(file2), { recursive: true });
89676
+ fs17.appendFileSync(file2, lines.map((l2) => `${JSON.stringify(l2)}
89319
89677
  `).join(""));
89320
89678
  }
89321
89679
  function keepCloudChat(task, messages) {
89322
89680
  const file2 = taskChatFile(task, home3());
89323
- if (!messages.length) return fs14.rmSync(file2, { force: true });
89681
+ if (!messages.length) return fs17.rmSync(file2, { force: true });
89324
89682
  const lines = messages.map((m) => ({ id: m.id, role: m.role, text: m.body, at: Date.parse(m.created_at) || Date.now() }));
89325
- fs14.mkdirSync(path17.dirname(file2), { recursive: true });
89326
- fs14.writeFileSync(file2, lines.map((l2) => `${JSON.stringify(l2)}
89683
+ fs17.mkdirSync(path20.dirname(file2), { recursive: true });
89684
+ fs17.writeFileSync(file2, lines.map((l2) => `${JSON.stringify(l2)}
89685
+ `).join(""));
89686
+ }
89687
+ async function keepDecisions(task, read) {
89688
+ const comments = [];
89689
+ let after = null;
89690
+ do {
89691
+ const page = await read(task, after);
89692
+ if (!page.ok) return;
89693
+ for (const d2 of page.value.data) {
89694
+ if (d2.comment.trim()) comments.push({ id: d2.id, role: "user", text: d2.comment, at: Date.parse(d2.created_at) || Date.now() });
89695
+ }
89696
+ after = page.value.next;
89697
+ } while (after);
89698
+ if (!comments.length) return;
89699
+ const ids = new Set(comments.map((c2) => c2.id));
89700
+ const lines = [...readTaskChat(task, home3()).filter((l2) => !ids.has(l2.id)), ...comments].sort((a3, b2) => a3.at - b2.at);
89701
+ const file2 = taskChatFile(task, home3());
89702
+ fs17.mkdirSync(path20.dirname(file2), { recursive: true });
89703
+ fs17.writeFileSync(file2, lines.map((l2) => `${JSON.stringify(l2)}
89327
89704
  `).join(""));
89328
89705
  }
89329
89706
  var tasksKept = () => {
89330
89707
  try {
89331
- return fs14.readdirSync(taskChatsDir(home3())).map((n) => /^([\w-]{1,100})\.jsonl$/.exec(n)?.[1]).filter((t2) => !!t2);
89708
+ return fs17.readdirSync(taskChatsDir(home3())).map((n) => /^([\w-]{1,100})\.jsonl$/.exec(n)?.[1]).filter((t2) => !!t2);
89332
89709
  } catch {
89333
89710
  return [];
89334
89711
  }
@@ -89339,9 +89716,9 @@ function pruneChats(now = Date.now()) {
89339
89716
  const kept4 = lines.filter((l2) => now - l2.at < KEEP_MS2);
89340
89717
  if (kept4.length === lines.length) continue;
89341
89718
  const file2 = taskChatFile(task, home3());
89342
- if (kept4.length) fs14.writeFileSync(file2, kept4.map((l2) => `${JSON.stringify(l2)}
89719
+ if (kept4.length) fs17.writeFileSync(file2, kept4.map((l2) => `${JSON.stringify(l2)}
89343
89720
  `).join(""));
89344
- else fs14.rmSync(file2, { force: true });
89721
+ else fs17.rmSync(file2, { force: true });
89345
89722
  }
89346
89723
  }
89347
89724
  var lastOf = (task) => readTaskChat(task, home3()).at(-1);
@@ -89374,33 +89751,33 @@ async function reviewChats(machineId2, runtimes, now = Date.now()) {
89374
89751
  if (!sent.ok) console.error(`runner: the chats of ${project} were not sent for review: ${sent.error}`);
89375
89752
  }
89376
89753
  const listed2 = new Set(owned.value.chats.map((c2) => c2.task));
89377
- const held3 = readReviewed();
89378
- writeReviewed({ checkedAt: now, tasks: Object.fromEntries(Object.entries(held3.tasks).filter(([t2]) => listed2.has(t2))) });
89754
+ const held4 = readReviewed();
89755
+ writeReviewed({ checkedAt: now, tasks: Object.fromEntries(Object.entries(held4.tasks).filter(([t2]) => listed2.has(t2))) });
89379
89756
  }
89380
89757
 
89381
89758
  // src/board-watch.ts
89382
- import fs18 from "node:fs";
89383
- import path21 from "node:path";
89759
+ import fs21 from "node:fs";
89760
+ import path24 from "node:path";
89384
89761
 
89385
89762
  // ../cloud/src/board-files.ts
89386
89763
  var ROOTS = ["todo/", ".archive/", "memory/", "workflows/", "triage/", "assets/", "rules/"];
89387
89764
  var SETTINGS = ["modules.md", "config.md"];
89388
- var isSettingsPath = (path31) => SETTINGS.includes(path31) || /^rules\/(?:workflows\/)?[^/]+\.md$/.test(path31);
89765
+ var isSettingsPath = (path34) => SETTINGS.includes(path34) || /^rules\/(?:workflows\/)?[^/]+\.md$/.test(path34);
89389
89766
  var BOARD_FILE_LIMIT = 256 * 1024;
89390
- function isBoardPath(path31) {
89391
- if (!path31 || path31.length > 500 || path31.startsWith("/") || path31.includes("\\") || path31.includes("\0")) return false;
89392
- if (path31.split("/").some((part) => !part || part === "." || part === "..")) return false;
89393
- if (path31 === "todo/README.md" || path31.split("/").includes(".sync")) return false;
89394
- if (path31.startsWith("workflows/")) return true;
89395
- if (SETTINGS.includes(path31)) return true;
89396
- if (path31.startsWith("rules/")) return isSettingsPath(path31);
89397
- if (path31.startsWith("assets/")) return path31.endsWith(".json");
89398
- return ROOTS.some((root) => path31.startsWith(root)) && path31.endsWith(".md");
89767
+ function isBoardPath(path34) {
89768
+ if (!path34 || path34.length > 500 || path34.startsWith("/") || path34.includes("\\") || path34.includes("\0")) return false;
89769
+ if (path34.split("/").some((part) => !part || part === "." || part === "..")) return false;
89770
+ if (path34 === "todo/README.md" || path34.split("/").includes(".sync")) return false;
89771
+ if (path34.startsWith("workflows/")) return true;
89772
+ if (SETTINGS.includes(path34)) return true;
89773
+ if (path34.startsWith("rules/")) return isSettingsPath(path34);
89774
+ if (path34.startsWith("assets/")) return path34.endsWith(".json");
89775
+ return ROOTS.some((root) => path34.startsWith(root)) && path34.endsWith(".md");
89399
89776
  }
89400
89777
  var CARD = /^(?:todo|\.archive)\/(?:[^/]+\/)*(\d+)-[^/]*\.md$/;
89401
89778
  var ROOT = /^(?:todo|\.archive)\/(?:[^/]+\/)*(\d+)-[^/]+\/root\.md$/;
89402
- function numberOfCard(path31) {
89403
- const n = ROOT.exec(path31)?.[1] ?? CARD.exec(path31)?.[1];
89779
+ function numberOfCard(path34) {
89780
+ const n = ROOT.exec(path34)?.[1] ?? CARD.exec(path34)?.[1];
89404
89781
  return n ? Number(n) : null;
89405
89782
  }
89406
89783
  var cardSlug = (task) => task.toLowerCase().replace(/_/g, "-");
@@ -89432,9 +89809,9 @@ function cardFront(body) {
89432
89809
 
89433
89810
  // src/task-folder.ts
89434
89811
  import { spawnSync as spawnSync4 } from "node:child_process";
89435
- import crypto2 from "node:crypto";
89436
- import fs17 from "node:fs";
89437
- import path20 from "node:path";
89812
+ import crypto3 from "node:crypto";
89813
+ import fs20 from "node:fs";
89814
+ import path23 from "node:path";
89438
89815
 
89439
89816
  // node_modules/node-diff3/dist/diff3.mjs
89440
89817
  function LCS(buffer1, buffer2) {
@@ -89651,8 +90028,8 @@ function diff3Merge(a3, o2, b2, options) {
89651
90028
 
89652
90029
  // ../cloud/src/triage-files.ts
89653
90030
  var ITEM = /^triage\/(?:(dismissed|archived)\/)?([^/]+)\.md$/;
89654
- function itemAt(path31) {
89655
- const m = ITEM.exec(path31);
90031
+ function itemAt(path34) {
90032
+ const m = ITEM.exec(path34);
89656
90033
  if (!m) return null;
89657
90034
  return { state: m[1] === "dismissed" ? "dismissed" : m[1] === "archived" ? "carded" : "open", name: m[2] };
89658
90035
  }
@@ -89669,8 +90046,8 @@ function stampItem(content, fields) {
89669
90046
  }
89670
90047
 
89671
90048
  // ../cli/src/lib/agents/shared-memory.ts
89672
- import fs15 from "node:fs";
89673
- import path18 from "node:path";
90049
+ import fs18 from "node:fs";
90050
+ import path21 from "node:path";
89674
90051
 
89675
90052
  // ../cli/src/agents/api-designer/AGENT.md
89676
90053
  var AGENT_default = "---\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";
@@ -90128,7 +90505,7 @@ var music_default = "# Music\n\nScore the clone with new music that follows the
90128
90505
  var AGENT_default24 = "---\nname: video-template-builder\ndescription: Builds a video clone's reusable beat-table template from its approved drafts, renders it once and checks it against the source beat by beat.\nakb:\n after: [video-cloner]\n session: new\n i18n:\n en:\n title: Video template\n zh:\n title: \u89C6\u9891\u6A21\u677F\n description: \u6309\u786E\u8BA4\u7684\u590D\u523B\u5206\u955C\u505A\u6210\u4FDD\u7559\u62CD\u6CD5\u3001\u53EF\u6362\u5185\u5BB9\u7684 beat \u8868\u6A21\u677F\uFF0C\u6E32\u67D3\u4E00\u652F\u5E76\u4E0E\u539F\u7247\u9010\u955C\u5BF9\u6BD4\u3002\n---\n\nBuild the template the approved drafts in ``## By `video-cloner` agent`` describe: it reproduces the source's craft and renders the user's content in place of the source's. You are done, with no further question, when the clone's comparison with the source and the render command are recorded on the card.\n\nFollow Terms, Deciding, Files and Memory in `akb raw agent-file video-cloner AGENT.md`; its memory folder is yours.\n\n## Steps\n\n- **Recipe**: write the format (size, frame rate, length, fonts, colours) to `recipe.md` in the files folder; it is your working file, never shown on the card.\n- **Template**: build a project that renders `clone.json` beat by beat, picking for each motion an animation library that fits its style; one project may combine several. The beat table and all content live in one file, holding the user's content from the start, so a beat can be removed or reordered and the content swapped without code changes; the code holds only craft and props. Its `template.md` states that the content in that file is to be replaced with the user's own and that the template reproduces only the source's craft.\n- **Cached clips**: render each beat to its own cached clip and splice the clips into the full video; a change re-renders only the clips it touches.\n- **Check**: render it once and compare it with the source beat by beat side by side on rhythm, motion and layout, and check every on-screen step makes sense to a viewer. A beat that misses the source's structure means the template is wrong: fix it and render again, never hand over the breakdown instead.\n- **Music**: in the template and check, also follow `akb raw agent-file video-cloner references/music.md`.\n- **Card**: under your section heading, show only the clone against the source as a `<Compare>` with `breakdown.json` as `shots`, and each difference left in one line, naming its beat id; append a ticked todo with the template folder's absolute path and, in backticks, its render command.\n- **Changes**: a change to a beat updates only that beat in the template.\n";
90129
90506
 
90130
90507
  // ../cli/src/agents/workflow-writer/AGENT.md
90131
- var AGENT_default25 = "---\nname: workflow-writer\ndescription: Writes a new workflow, or changes one of the user's own, as a `WORKFLOW.md` and the agents it names.\nakb:\n i18n:\n en:\n title: Workflow\n zh:\n title: \u5DE5\u4F5C\u6D41\n description: \u6309\u4F60\u7684\u63CF\u8FF0\u5199\u51FA\u4E00\u4E2A\u5DE5\u4F5C\u6D41\u53CA\u5176 agent\uFF0C\u6216\u4FEE\u6539\u4F60\u5DF2\u6709\u7684\u5DE5\u4F5C\u6D41\u3002\n---\n\nYou write a workflow from the user's request: a kind of work the user runs again and again, where each task shows a person previews to approve before the work goes on.\n\n## Read first\n\n- **The project**: when the board belongs to a project folder, read its README and agent instruction files (such as `AGENTS.md` or `CLAUDE.md`) for what it makes, and its existing outputs of this kind for their format and destination.\n- **This board**: run `akb workflow list` and read `docs/kanban/agents/`, so a new workflow does not repeat one the board already has.\n\n## What to write\n\n- **The workflow**: when the card names a workflow folder, the workflow is that folder: keep its id and change it in place. Otherwise create it with `akb workflow new`. Name it with `akb workflow rename`, and list its agents in its `WORKFLOW.md`: `previews` the agents whose drafts a person approves, `land` the agents that run unattended in order after the last approval, and `scheduled`. Its body is how a card of this kind is written.\n- **Its agents**: write each agent it names as `akb guide write-agent` says.\n- **Approvals**: default to previews a person approves once. Give an agent `after` only when its preview is too costly to make before another is approved, such as a video before its script; it then waits for that approval.\n- **Previews**: give each part a person must see its own agent, such as the screens of a UI change or the script of a video. Show only what the person decides on, and keep previews from overlapping: a UI preview already shows its text, so add no separate copy preview.\n- **Land**: add agents to `land` only for work that needs no review, such as building and merging an approved change; leave it empty when the last approved preview is the deliverable.\n- **Memory**: for each agent, decide whether a user's correction should change its next output, such as a writer's tone or a designer's look; if so, declare its memory as `akb guide write-agent` says, otherwise give it none.\n- **Changing a workflow**: edit its `WORKFLOW.md` and its agents under `docs/kanban/agents/` in place, and keep what the request does not ask to change.\n\n## Check it\n\nRun `akb spec` and `akb workflow list`, and fix every problem reported for this workflow or its agents before finishing.\n\n## Card\n\nUnder your section heading, say in a few lines, for a reader who has never seen a workflow file, what the workflow is for, what each approval shows, what runs after the last one, and what each agent remembers; then embed each file you wrote as an `<Asset>`.\n";
90508
+ var AGENT_default25 = "---\nname: workflow-writer\ndescription: Writes or changes a workflow, one of its preview agents or a scheduled agent, as a `WORKFLOW.md` and the agents it names.\nakb:\n i18n:\n en:\n title: Workflow\n zh:\n title: \u5DE5\u4F5C\u6D41\n description: \u6309\u4F60\u7684\u63CF\u8FF0\u5199\u51FA\u6216\u4FEE\u6539\u5DE5\u4F5C\u6D41\u53CA\u5176 Preview Agent\uFF0C\u6216\u628A\u91CD\u590D\u6027\u5DE5\u4F5C\u5199\u6210\u5B9A\u65F6 agent\u3002\n---\n\nYou write a workflow from the user's request: a kind of work the user runs again and again, where each task shows a person previews to approve before the work goes on. A request may also change one preview agent in a workflow, or ask for work that repeats on a schedule.\n\n## Read first\n\n- **The project**: when the board belongs to a project folder, read its README and agent instruction files (such as `AGENTS.md` or `CLAUDE.md`) for what it makes, and its existing outputs of this kind for their format and destination.\n- **This board**: run `akb workflow list` and read `docs/kanban/agents/`, so a new workflow does not repeat one the board already has.\n\n## What to write\n\n- **The workflow**: when the card names a workflow folder, the workflow is that folder: keep its id and change it in place. Otherwise create it with `akb workflow new`. Name it with `akb workflow rename`, and list its agents in its `WORKFLOW.md`: `previews` the agents whose drafts a person approves, `land` the agents that run unattended in order after the last approval, and `scheduled`. Its body is how a card of this kind is written.\n- **Its agents**: write each agent it names as `akb guide write-agent` says.\n- **Approvals**: default to previews a person approves once. Give an agent `after` only when its preview is too costly to make before another is approved, such as a video before its script; it then waits for that approval.\n- **Previews**: give each part a person must see its own agent, such as the screens of a UI change or the script of a video. Show only what the person decides on, and keep previews from overlapping: a UI preview already shows its text, so add no separate copy preview.\n- **Land**: add agents to `land` only for work that needs no review, such as building and merging an approved change; leave it empty when the last approved preview is the deliverable.\n- **Memory**: for each agent, decide whether a user's correction should change its next output, such as a writer's tone or a designer's look; if so, declare its memory as `akb guide write-agent` says, otherwise give it none.\n- **Changing a workflow**: edit its `WORKFLOW.md` and its agents under `docs/kanban/agents/` in place, and keep what the request does not ask to change.\n- **Preview agents it does not hold**: when the request changes a preview agent of a built-in or another workflow, run `akb workflow duplicate <id>` on that workflow and change the copy of that agent.\n- **Saving a copy**: when the card names a folder, move the copy's `WORKFLOW.md` over the one there and remove the copy's empty folder, because only that folder is saved. Never run `akb workflow delete` on the copy: it deletes the agents too.\n- **Copied schedules**: remove the copy's `scheduled` entries and their agents unless the request is about them, so that work does not run twice.\n- **Repeating work**: write a scheduled agent as `akb guide write-agent` says. It goes in this workflow, which may hold nothing else.\n\n## Check it\n\nRun `akb spec` and `akb workflow list`, and fix every problem reported for this workflow or its agents before finishing.\n\n## Card\n\nUnder your section heading, say in a few lines, for a reader who has never seen a workflow file, what the workflow is for, what each approval shows, what runs after the last one, what runs on a schedule, and what each agent remembers; then embed each file you wrote as an `<Asset>`. When the work is a copy, say that new tasks must pick the copy and that open cards stay on the original.\n";
90132
90509
 
90133
90510
  // ../cli/src/lib/agents/bundled.ts
90134
90511
  var BUNDLED_AGENT_FILES = {
@@ -90399,16 +90776,16 @@ function sharedMemory(board) {
90399
90776
  const at2 = /^([^/]+)\/AGENT\.md$/.exec(key);
90400
90777
  if (at2) take(at2[1], text3, true);
90401
90778
  }
90402
- const root = path18.join(board, "agents");
90779
+ const root = path21.join(board, "agents");
90403
90780
  let folders2 = [];
90404
90781
  try {
90405
- folders2 = fs15.readdirSync(root, { withFileTypes: true }).filter((e2) => e2.isDirectory() && !e2.name.startsWith(".")).map((e2) => e2.name);
90782
+ folders2 = fs18.readdirSync(root, { withFileTypes: true }).filter((e2) => e2.isDirectory() && !e2.name.startsWith(".")).map((e2) => e2.name);
90406
90783
  } catch {
90407
90784
  }
90408
90785
  for (const folder of folders2.sort()) {
90409
90786
  let text3 = null;
90410
90787
  try {
90411
- text3 = fs15.readFileSync(path18.join(root, folder, "AGENT.md"), "utf8");
90788
+ text3 = fs18.readFileSync(path21.join(root, folder, "AGENT.md"), "utf8");
90412
90789
  } catch {
90413
90790
  }
90414
90791
  take(folder, text3, false);
@@ -90432,16 +90809,16 @@ function openTaskFolder(job, projectDir2) {
90432
90809
  projectDir2 ??= openCached(job.project);
90433
90810
  keepOutOfGit(projectDir2);
90434
90811
  markUsed(projectDir2);
90435
- const board = path20.join(projectDir2, ".akb", "kanban");
90436
- fs17.mkdirSync(board, { recursive: true });
90812
+ const board = path23.join(projectDir2, ".akb", "kanban");
90813
+ fs20.mkdirSync(board, { recursive: true });
90437
90814
  return { task, cloudTask: task, board, cwd: projectDir2, project: job.project, number: job.number ?? null, workflow: job.workflow ?? job.flow?.workflow ?? null };
90438
90815
  }
90439
90816
  function openAgentFolder(job, projectDir2) {
90440
90817
  if (!job.project || !job.agent) throw new Error("This job names no project.");
90441
90818
  keepOutOfGit(projectDir2);
90442
90819
  markUsed(projectDir2);
90443
- const board = path20.join(projectDir2, ".akb", "kanban");
90444
- fs17.mkdirSync(board, { recursive: true });
90820
+ const board = path23.join(projectDir2, ".akb", "kanban");
90821
+ fs20.mkdirSync(board, { recursive: true });
90445
90822
  return {
90446
90823
  task: `agent-${safe(job.agent.workflow ? `${job.agent.workflow}-${job.agent.name}` : job.agent.name)}`,
90447
90824
  cloudTask: job.agent.tasks?.[0]?.id ?? null,
@@ -90456,13 +90833,13 @@ function openDiscussionFolder(job, projectDir2) {
90456
90833
  if (!job.project) throw new Error("This job names no project.");
90457
90834
  keepOutOfGit(projectDir2);
90458
90835
  markUsed(projectDir2);
90459
- const board = path20.join(projectDir2, ".akb", "kanban");
90460
- fs17.mkdirSync(board, { recursive: true });
90836
+ const board = path23.join(projectDir2, ".akb", "kanban");
90837
+ fs20.mkdirSync(board, { recursive: true });
90461
90838
  return { task: "discussion", cloudTask: null, board, cwd: projectDir2, project: job.project, number: null, workflow: null };
90462
90839
  }
90463
90840
  var boardFolder = (ws) => ({ task: "board", cloudTask: null, board: ws.board, cwd: ws.cwd, project: ws.project, number: null, workflow: null });
90464
90841
  function keptBoard(cwd) {
90465
- const board = path20.join(cwd, ".akb", "kanban");
90842
+ const board = path23.join(cwd, ".akb", "kanban");
90466
90843
  const base = readBase({ cwd });
90467
90844
  const project = base.project ?? /^projects\/([^/]+)\//.exec(Object.keys(base.files).find((p2) => p2.startsWith("projects/")) ?? "")?.[1];
90468
90845
  return base.head_seq === null || !project ? null : boardFolder({ board, cwd, project });
@@ -90470,17 +90847,17 @@ function keptBoard(cwd) {
90470
90847
  var turns = /* @__PURE__ */ new Map();
90471
90848
  function inFolder(dir, work) {
90472
90849
  const next = (turns.get(dir) ?? Promise.resolve()).then(work, work);
90473
- const held3 = next.catch(() => {
90850
+ const held4 = next.catch(() => {
90474
90851
  });
90475
- turns.set(dir, held3);
90476
- void held3.then(() => turns.get(dir) === held3 && turns.delete(dir));
90852
+ turns.set(dir, held4);
90853
+ void held4.then(() => turns.get(dir) === held4 && turns.delete(dir));
90477
90854
  return next;
90478
90855
  }
90479
90856
  var safe = (name) => name.replace(/[^\w.-]/g, "_") || "default";
90480
90857
  function openCached(project) {
90481
90858
  const dir = cacheDir(project);
90482
- if (fs17.existsSync(path20.join(dir, ".git"))) return dir;
90483
- fs17.mkdirSync(dir, { recursive: true });
90859
+ if (fs20.existsSync(path23.join(dir, ".git"))) return dir;
90860
+ fs20.mkdirSync(dir, { recursive: true });
90484
90861
  const git3 = (...args) => spawnSync4("git", ["-C", dir, ...args], { encoding: "utf8" }).status === 0;
90485
90862
  if (git3("init", "-q")) git3("-c", "user.name=WildCrane", "-c", "user.email=runner@wildcrane.ai", "commit", "-q", "--allow-empty", "-m", "general");
90486
90863
  return dir;
@@ -90493,56 +90870,56 @@ function keepOutOfGit(dir, folders2 = SKILL_FOLDERS) {
90493
90870
  if (inside.status !== 0) return;
90494
90871
  const missing = [".akb/", ...folders2.map((f2) => `${f2}/`)].filter((p2) => git3("check-ignore", "-q", p2).status !== 0);
90495
90872
  if (!missing.length) return;
90496
- const exclude = path20.resolve(dir, inside.stdout.trim());
90497
- fs17.mkdirSync(path20.dirname(exclude), { recursive: true });
90498
- const held3 = fs17.existsSync(exclude) ? fs17.readFileSync(exclude, "utf8") : "";
90499
- fs17.writeFileSync(exclude, `${held3}${held3 && !held3.endsWith("\n") ? "\n" : ""}${missing.join("\n")}
90873
+ const exclude = path23.resolve(dir, inside.stdout.trim());
90874
+ fs20.mkdirSync(path23.dirname(exclude), { recursive: true });
90875
+ const held4 = fs20.existsSync(exclude) ? fs20.readFileSync(exclude, "utf8") : "";
90876
+ fs20.writeFileSync(exclude, `${held4}${held4 && !held4.endsWith("\n") ? "\n" : ""}${missing.join("\n")}
90500
90877
  `);
90501
90878
  }
90502
- var cardFile = (ws) => (ws.number ? findCard(ws.board, ws.number) : null) ?? path20.join(ws.board, "todo", `${ws.number ?? 0}-task.md`);
90879
+ var cardFile = (ws) => (ws.number ? findCard(ws.board, ws.number) : null) ?? path23.join(ws.board, "todo", `${ws.number ?? 0}-task.md`);
90503
90880
  function findCard(board, number) {
90504
90881
  const named2 = new RegExp(`^${number}-`);
90505
90882
  const walk = (dir) => {
90506
90883
  let entries;
90507
90884
  try {
90508
- entries = fs17.readdirSync(dir, { withFileTypes: true });
90885
+ entries = fs20.readdirSync(dir, { withFileTypes: true });
90509
90886
  } catch {
90510
90887
  return null;
90511
90888
  }
90512
90889
  for (const e2 of entries) {
90513
90890
  if (!named2.test(e2.name)) continue;
90514
- if (e2.isFile() && e2.name.endsWith(".md")) return path20.join(dir, e2.name);
90515
- const root = path20.join(dir, e2.name, "root.md");
90516
- if (e2.isDirectory() && fs17.existsSync(root)) return root;
90891
+ if (e2.isFile() && e2.name.endsWith(".md")) return path23.join(dir, e2.name);
90892
+ const root = path23.join(dir, e2.name, "root.md");
90893
+ if (e2.isDirectory() && fs20.existsSync(root)) return root;
90517
90894
  }
90518
90895
  for (const e2 of entries) if (e2.isDirectory() && !e2.name.startsWith(".")) {
90519
- const hit = walk(path20.join(dir, e2.name));
90896
+ const hit = walk(path23.join(dir, e2.name));
90520
90897
  if (hit) return hit;
90521
90898
  }
90522
90899
  return null;
90523
90900
  };
90524
- return walk(path20.join(board, "todo")) ?? walk(path20.join(board, ".archive"));
90901
+ return walk(path23.join(board, "todo")) ?? walk(path23.join(board, ".archive"));
90525
90902
  }
90526
90903
  function akbCardOf(ws) {
90527
90904
  return ws.number && findCard(ws.board, ws.number) ? ws.number : void 0;
90528
90905
  }
90529
- var recordFile = (ws) => path20.join(ws.board, ".sync", `${ws.task}.json`);
90906
+ var recordFile = (ws) => path23.join(ws.board, ".sync", `${ws.task}.json`);
90530
90907
  function readRecord(ws) {
90531
90908
  try {
90532
- return { ...EMPTY, ...JSON.parse(fs17.readFileSync(recordFile(ws), "utf8")) };
90909
+ return { ...EMPTY, ...JSON.parse(fs20.readFileSync(recordFile(ws), "utf8")) };
90533
90910
  } catch {
90534
90911
  return structuredClone(EMPTY);
90535
90912
  }
90536
90913
  }
90537
90914
  function writeRecord(ws, record) {
90538
- fs17.mkdirSync(path20.dirname(recordFile(ws)), { recursive: true });
90539
- fs17.writeFileSync(recordFile(ws), `${JSON.stringify(record, null, 2)}
90915
+ fs20.mkdirSync(path23.dirname(recordFile(ws)), { recursive: true });
90916
+ fs20.writeFileSync(recordFile(ws), `${JSON.stringify(record, null, 2)}
90540
90917
  `);
90541
90918
  }
90542
- var baseFile = (ws) => path20.join(ws.cwd, ".akb", "base.json");
90919
+ var baseFile = (ws) => path23.join(ws.cwd, ".akb", "base.json");
90543
90920
  function readBase(ws) {
90544
90921
  try {
90545
- const base = JSON.parse(fs17.readFileSync(baseFile(ws), "utf8"));
90922
+ const base = JSON.parse(fs20.readFileSync(baseFile(ws), "utf8"));
90546
90923
  if (base.layout === "workspace") return base;
90547
90924
  } catch {
90548
90925
  }
@@ -90550,25 +90927,25 @@ function readBase(ws) {
90550
90927
  }
90551
90928
  function writeBase(ws, base) {
90552
90929
  const file2 = baseFile(ws);
90553
- fs17.mkdirSync(path20.dirname(file2), { recursive: true });
90554
- fs17.writeFileSync(`${file2}.tmp`, JSON.stringify(base));
90555
- fs17.renameSync(`${file2}.tmp`, file2);
90930
+ fs20.mkdirSync(path23.dirname(file2), { recursive: true });
90931
+ fs20.writeFileSync(`${file2}.tmp`, JSON.stringify(base));
90932
+ fs20.renameSync(`${file2}.tmp`, file2);
90556
90933
  }
90557
- var hashOf = (bytes2) => crypto2.createHash("sha256").update(bytes2).digest("hex");
90934
+ var hashOf = (bytes2) => crypto3.createHash("sha256").update(bytes2).digest("hex");
90558
90935
  function hashFile(file2) {
90559
90936
  try {
90560
- return hashOf(fs17.readFileSync(file2));
90937
+ return hashOf(fs20.readFileSync(file2));
90561
90938
  } catch {
90562
90939
  return null;
90563
90940
  }
90564
90941
  }
90565
90942
  function write(file2, bytes2) {
90566
- fs17.mkdirSync(path20.dirname(file2), { recursive: true });
90567
- fs17.writeFileSync(file2, bytes2);
90943
+ fs20.mkdirSync(path23.dirname(file2), { recursive: true });
90944
+ fs20.writeFileSync(file2, bytes2);
90568
90945
  }
90569
90946
  function readText(file2) {
90570
90947
  try {
90571
- return fs17.readFileSync(file2, "utf8");
90948
+ return fs20.readFileSync(file2, "utf8");
90572
90949
  } catch {
90573
90950
  return null;
90574
90951
  }
@@ -90576,14 +90953,14 @@ function readText(file2) {
90576
90953
  function filesUnder(dir, base = dir) {
90577
90954
  let entries;
90578
90955
  try {
90579
- entries = fs17.readdirSync(dir, { withFileTypes: true });
90956
+ entries = fs20.readdirSync(dir, { withFileTypes: true });
90580
90957
  } catch {
90581
90958
  return [];
90582
90959
  }
90583
90960
  return entries.flatMap((e2) => {
90584
- const full = path20.join(dir, e2.name);
90961
+ const full = path23.join(dir, e2.name);
90585
90962
  if (e2.isDirectory()) return filesUnder(full, base);
90586
- return e2.isFile() ? [path20.relative(base, full).split(path20.sep).join("/")] : [];
90963
+ return e2.isFile() ? [path23.relative(base, full).split(path23.sep).join("/")] : [];
90587
90964
  });
90588
90965
  }
90589
90966
  var kept3 = isBoardPath;
@@ -90599,7 +90976,7 @@ function viewOf(ws, base, shared) {
90599
90976
  }
90600
90977
  function assetFiles(ws, list) {
90601
90978
  const card = cardFile(ws);
90602
- return new Set(Object.keys(assetsOf(list)).map((name) => assetPath(ws, name, card)).filter((f2) => !!f2).map((f2) => path20.relative(ws.board, f2).split(path20.sep).join("/")));
90979
+ return new Set(Object.keys(assetsOf(list)).map((name) => assetPath(ws, name, card)).filter((f2) => !!f2).map((f2) => path23.relative(ws.board, f2).split(path23.sep).join("/")));
90603
90980
  }
90604
90981
  var assetsListOf = (ws, base) => base.files[rootOf(ws) + assetsFile(ws.task)]?.content;
90605
90982
  var localFiles = (ws, base) => {
@@ -90608,9 +90985,9 @@ var localFiles = (ws, base) => {
90608
90985
  };
90609
90986
  var SKILL_PATH = /^skills\/([a-z0-9]+(?:-[a-z0-9]+)*)\/((?:[\w.-]+\/)*[\w.-]+)$/;
90610
90987
  function pullTools(ws, record, files) {
90611
- const held3 = record.tools?.skills ?? {};
90612
- const ours = new Set(Object.keys(held3).map((name) => name.split("/")[1]));
90613
- const theirs = (skill) => !ours.has(skill) && SKILL_ROOTS.some((root) => fs17.existsSync(path20.join(ws.cwd, root, skill)));
90988
+ const held4 = record.tools?.skills ?? {};
90989
+ const ours = new Set(Object.keys(held4).map((name) => name.split("/")[1]));
90990
+ const theirs = (skill) => !ours.has(skill) && SKILL_ROOTS.some((root) => fs20.existsSync(path23.join(ws.cwd, root, skill)));
90614
90991
  const kept4 = Object.keys(files).map((name) => SKILL_PATH.exec(name)?.[1]).filter((skill) => skill && !theirs(skill));
90615
90992
  const skills = {};
90616
90993
  for (const [name, text3] of Object.entries(files)) {
@@ -90618,17 +90995,17 @@ function pullTools(ws, record, files) {
90618
90995
  if (!at2 || at2[1] === "kanban" || !kept4.includes(at2[1]) || at2[2].split("/").includes("..")) continue;
90619
90996
  skills[name] = hashOf(text3);
90620
90997
  for (const root of SKILL_ROOTS) {
90621
- const file2 = path20.join(ws.cwd, root, at2[1], at2[2]);
90622
- if (held3[name] !== skills[name] || hashFile(file2) !== skills[name]) write(file2, text3);
90998
+ const file2 = path23.join(ws.cwd, root, at2[1], at2[2]);
90999
+ if (held4[name] !== skills[name] || hashFile(file2) !== skills[name]) write(file2, text3);
90623
91000
  }
90624
91001
  }
90625
- for (const name of Object.keys(held3)) {
91002
+ for (const name of Object.keys(held4)) {
90626
91003
  if (skills[name]) continue;
90627
91004
  const [, skill, rest] = SKILL_PATH.exec(name) ?? [];
90628
91005
  if (!skill || !rest) continue;
90629
91006
  for (const root of SKILL_ROOTS) {
90630
- fs17.rmSync(path20.join(ws.cwd, root, skill, rest), { force: true });
90631
- if (!Object.keys(skills).some((n) => n.startsWith(`skills/${skill}/`))) fs17.rmSync(path20.join(ws.cwd, root, skill), { recursive: true, force: true });
91007
+ fs20.rmSync(path23.join(ws.cwd, root, skill, rest), { force: true });
91008
+ if (!Object.keys(skills).some((n) => n.startsWith(`skills/${skill}/`))) fs20.rmSync(path23.join(ws.cwd, root, skill), { recursive: true, force: true });
90632
91009
  }
90633
91010
  }
90634
91011
  const names2 = [...new Set(Object.keys(skills).map((name) => name.split("/")[1]))];
@@ -90645,8 +91022,8 @@ async function pullWorkflow(ws, record, base) {
90645
91022
  let files = {};
90646
91023
  if (ws.workflow) {
90647
91024
  const root = `workflows/${workflowFolder(ws.workflow)}/`;
90648
- const held3 = rootOf(ws) + root;
90649
- files = Object.fromEntries(Object.entries(base.files).filter(([p2]) => p2.startsWith(held3) && isBoardPath(p2.slice(rootOf(ws).length))).map(([p2, f2]) => [p2.slice(held3.length), f2.content]));
91025
+ const held4 = rootOf(ws) + root;
91026
+ files = Object.fromEntries(Object.entries(base.files).filter(([p2]) => p2.startsWith(held4) && isBoardPath(p2.slice(rootOf(ws).length))).map(([p2, f2]) => [p2.slice(held4.length), f2.content]));
90650
91027
  record.builtin = ws.workflow.startsWith("wf_builtin_");
90651
91028
  let found = Object.keys(files).length > 0;
90652
91029
  if (!found && ws.cloudTask) {
@@ -90656,7 +91033,7 @@ async function pullWorkflow(ws, record, base) {
90656
91033
  files = read.value.files;
90657
91034
  found = true;
90658
91035
  if (!record.builtin) {
90659
- for (const [name, text3] of Object.entries(files)) if (isBoardPath(root + name)) write(path20.join(ws.board, root, name), text3);
91036
+ for (const [name, text3] of Object.entries(files)) if (isBoardPath(root + name)) write(path23.join(ws.board, root, name), text3);
90660
91037
  }
90661
91038
  }
90662
91039
  }
@@ -90664,15 +91041,15 @@ async function pullWorkflow(ws, record, base) {
90664
91041
  }
90665
91042
  pullAgents(ws, base, ws.workflow && !record.builtin ? files : {});
90666
91043
  const placed = readPlaced(ws);
90667
- for (const name of Object.keys(record.agents ?? {})) if (!placed[name]) fs17.rmSync(path20.join(ws.board, name), { force: true });
91044
+ for (const name of Object.keys(record.agents ?? {})) if (!placed[name]) fs20.rmSync(path23.join(ws.board, name), { force: true });
90668
91045
  record.agents = {};
90669
91046
  return { ok: true, value: void 0 };
90670
91047
  }
90671
91048
  var OWN_FOLDER = /^wf-(?!builtin-)[a-z0-9-]+$/;
90672
- var agentsRecord = (ws) => path20.join(ws.board, ".sync", "agents.json");
91049
+ var agentsRecord = (ws) => path23.join(ws.board, ".sync", "agents.json");
90673
91050
  function readPlaced(ws) {
90674
91051
  try {
90675
- return JSON.parse(fs17.readFileSync(agentsRecord(ws), "utf8"));
91052
+ return JSON.parse(fs20.readFileSync(agentsRecord(ws), "utf8"));
90676
91053
  } catch {
90677
91054
  return {};
90678
91055
  }
@@ -90693,8 +91070,8 @@ function pullAgents(ws, base, own) {
90693
91070
  const names2 = /* @__PURE__ */ new Set();
90694
91071
  for (const [name, text3] of Object.entries(files)) {
90695
91072
  const agent = /^agents\/([^/]+)\//.exec(name)?.[1];
90696
- const file2 = path20.resolve(ws.board, name);
90697
- if (!agent || taken.has(agent) || !file2.startsWith(path20.join(ws.board, "agents") + path20.sep)) continue;
91073
+ const file2 = path23.resolve(ws.board, name);
91074
+ if (!agent || taken.has(agent) || !file2.startsWith(path23.join(ws.board, "agents") + path23.sep)) continue;
90698
91075
  names2.add(agent);
90699
91076
  agents[name] = text3;
90700
91077
  }
@@ -90704,42 +91081,42 @@ function pullAgents(ws, base, own) {
90704
91081
  const hashes = {};
90705
91082
  for (const [name, text3] of Object.entries(agents)) {
90706
91083
  hashes[name] = hashOf(text3);
90707
- if (hashFile(path20.join(ws.board, name)) !== hashes[name]) write(path20.join(ws.board, name), text3);
91084
+ if (hashFile(path23.join(ws.board, name)) !== hashes[name]) write(path23.join(ws.board, name), text3);
90708
91085
  }
90709
- for (const name of Object.keys(before)) if (!hashes[name]) fs17.rmSync(path20.join(ws.board, name), { force: true });
91086
+ for (const name of Object.keys(before)) if (!hashes[name]) fs20.rmSync(path23.join(ws.board, name), { force: true });
90710
91087
  write(agentsRecord(ws), `${JSON.stringify(hashes, null, 2)}
90711
91088
  `);
90712
91089
  }
90713
91090
  function pullDraftAgents(ws, record) {
90714
91091
  if (ws.workflow !== BUILDER) return;
90715
- const root = path20.join(ws.board, "workflows", draftFolder(ws.task), "agents");
91092
+ const root = path23.join(ws.board, "workflows", draftFolder(ws.task), "agents");
90716
91093
  record.agents ??= {};
90717
91094
  for (const name of filesUnder(root)) {
90718
- const text3 = fs17.readFileSync(path20.join(root, name));
91095
+ const text3 = fs20.readFileSync(path23.join(root, name));
90719
91096
  const at2 = `agents/${name}`;
90720
91097
  record.agents[at2] = hashOf(text3);
90721
- if (hashFile(path20.join(ws.board, at2)) !== record.agents[at2]) write(path20.join(ws.board, at2), text3);
91098
+ if (hashFile(path23.join(ws.board, at2)) !== record.agents[at2]) write(path23.join(ws.board, at2), text3);
90722
91099
  }
90723
91100
  }
90724
91101
  function workflowFile(ws) {
90725
91102
  if (!ws.workflow || readRecord(ws).builtin) return null;
90726
- const file2 = path20.join(ws.board, "workflows", workflowFolder(ws.workflow), "WORKFLOW.md");
90727
- return fs17.existsSync(file2) ? file2 : null;
91103
+ const file2 = path23.join(ws.board, "workflows", workflowFolder(ws.workflow), "WORKFLOW.md");
91104
+ return fs20.existsSync(file2) ? file2 : null;
90728
91105
  }
90729
91106
  function assetPath(ws, name, card) {
90730
91107
  if (/^[a-z][\w+.-]*:/i.test(name) || name.startsWith("/") || name.startsWith("#")) return null;
90731
- const held3 = /^\.(assets|mockups)\//.exec(name);
90732
- if (held3) {
91108
+ const held4 = /^\.(assets|mockups)\//.exec(name);
91109
+ if (held4) {
90733
91110
  const state = stateDir(ws);
90734
- const file3 = state && path20.resolve(state, held3[1], name.slice(held3[0].length));
90735
- return file3 && file3.startsWith(path20.join(state, held3[1]) + path20.sep) ? file3 : null;
91111
+ const file3 = state && path23.resolve(state, held4[1], name.slice(held4[0].length));
91112
+ return file3 && file3.startsWith(path23.join(state, held4[1]) + path23.sep) ? file3 : null;
90736
91113
  }
90737
- const file2 = path20.resolve(path20.dirname(card), name);
90738
- return file2.startsWith(ws.board + path20.sep) ? file2 : null;
91114
+ const file2 = path23.resolve(path23.dirname(card), name);
91115
+ return file2.startsWith(ws.board + path23.sep) ? file2 : null;
90739
91116
  }
90740
91117
  function cardAssetsDir(ws, id) {
90741
91118
  const state = stateDir(ws);
90742
- return state && path20.join(state, "assets", String(id));
91119
+ return state && path23.join(state, "assets", String(id));
90743
91120
  }
90744
91121
  function stateDir(ws) {
90745
91122
  try {
@@ -90750,8 +91127,8 @@ function stateDir(ws) {
90750
91127
  }
90751
91128
  function assetsOf(text3) {
90752
91129
  try {
90753
- const held3 = JSON.parse(text3 ?? "{}");
90754
- return held3 && typeof held3 === "object" && !Array.isArray(held3) ? held3 : {};
91130
+ const held4 = JSON.parse(text3 ?? "{}");
91131
+ return held4 && typeof held4 === "object" && !Array.isArray(held4) ? held4 : {};
90755
91132
  } catch {
90756
91133
  return {};
90757
91134
  }
@@ -90778,13 +91155,13 @@ var pullChanges = (ws) => inFolder(ws.cwd, async () => {
90778
91155
  const p2 = f2.path.startsWith(root) ? f2.path.slice(root.length) : f2.path;
90779
91156
  const isShared = p2.startsWith(MEMORY2) && shared(p2.slice(MEMORY2.length));
90780
91157
  if (kept3(p2) && isShared === !f2.path.startsWith(root)) {
90781
- const file2 = path20.join(ws.board, p2);
91158
+ const file2 = path23.join(ws.board, p2);
90782
91159
  const here2 = readText(file2);
90783
91160
  if (here2 !== f2.content && here2 !== (base.files[f2.path]?.content ?? null)) {
90784
91161
  skipped = true;
90785
91162
  continue;
90786
91163
  }
90787
- if (f2.content === null) fs17.rmSync(file2, { force: true });
91164
+ if (f2.content === null) fs20.rmSync(file2, { force: true });
90788
91165
  else if (here2 !== f2.content) write(file2, f2.content);
90789
91166
  }
90790
91167
  if (f2.content === null) delete base.files[f2.path];
@@ -90815,13 +91192,13 @@ async function readCloud(ws) {
90815
91192
  writeBase(ws, base);
90816
91193
  const reset = (view2) => {
90817
91194
  for (const [p2, content] of view2) {
90818
- const file2 = path20.join(ws.board, p2);
91195
+ const file2 = path23.join(ws.board, p2);
90819
91196
  if (kept3(p2) && readText(file2) !== content) write(file2, content);
90820
91197
  }
90821
91198
  };
90822
91199
  const view = viewOf(ws, base, sharedMemory(ws.board));
90823
91200
  const first = (p2) => isSettingsPath(p2) && !known2.has(rootOf(ws) + p2);
90824
- for (const p2 of localFiles(ws, base)) if (!view.has(p2) && !first(p2)) fs17.rmSync(path20.join(ws.board, p2), { force: true });
91201
+ for (const p2 of localFiles(ws, base)) if (!view.has(p2) && !first(p2)) fs20.rmSync(path23.join(ws.board, p2), { force: true });
90825
91202
  reset(view);
90826
91203
  const record = readRecord(ws);
90827
91204
  const workflow = await pullWorkflow(ws, record, base);
@@ -90835,18 +91212,18 @@ async function readCloud(ws) {
90835
91212
  return { ok: true, value: void 0 };
90836
91213
  }
90837
91214
  function writeIndex(board) {
90838
- const todo = path20.join(board, "todo");
91215
+ const todo = path23.join(board, "todo");
90839
91216
  const cards = [];
90840
91217
  let entries = [];
90841
91218
  try {
90842
- entries = fs17.readdirSync(todo, { withFileTypes: true });
91219
+ entries = fs20.readdirSync(todo, { withFileTypes: true });
90843
91220
  } catch {
90844
91221
  }
90845
91222
  for (const e2 of entries) {
90846
91223
  const id = /^(\d+)-/.exec(e2.name)?.[1];
90847
91224
  if (!id) continue;
90848
91225
  const link = e2.isDirectory() ? `${e2.name}/root.md` : e2.name.endsWith(".md") ? e2.name : null;
90849
- const text4 = link && readText(path20.join(todo, link));
91226
+ const text4 = link && readText(path23.join(todo, link));
90850
91227
  if (text4 === null || !link) continue;
90851
91228
  cards.push({ id: Number(id), title: cardFront(text4).title ?? e2.name.replace(/\.md$/, ""), link });
90852
91229
  }
@@ -90861,7 +91238,7 @@ the number at the front of a filename is the task id.
90861
91238
 
90862
91239
  ${list}
90863
91240
  `;
90864
- if (readText(path20.join(todo, "README.md")) !== text3) write(path20.join(todo, "README.md"), text3);
91241
+ if (readText(path23.join(todo, "README.md")) !== text3) write(path23.join(todo, "README.md"), text3);
90865
91242
  }
90866
91243
  var workspaceOf = (ws) => readBase(ws).workspace ?? null;
90867
91244
  async function pullAssets(ws, record, assets) {
@@ -90876,13 +91253,13 @@ async function pullAssets(ws, record, assets) {
90876
91253
  if (!latest.ok) return latest;
90877
91254
  version = latest.value.latest_version ?? 0;
90878
91255
  }
90879
- const held3 = record.assets[name];
90880
- if (held3?.kind === "html" && held3.artifact === ref.artifact) {
90881
- out[name] = { ...held3, version };
91256
+ const held4 = record.assets[name];
91257
+ if (held4?.kind === "html" && held4.artifact === ref.artifact) {
91258
+ out[name] = { ...held4, version };
90882
91259
  continue;
90883
91260
  }
90884
- if (held3?.artifact === ref.artifact && held3.version === version && hashFile(target) === held3.hash) {
90885
- out[name] = held3;
91261
+ if (held4?.artifact === ref.artifact && held4.version === version && hashFile(target) === held4.hash) {
91262
+ out[name] = held4;
90886
91263
  continue;
90887
91264
  }
90888
91265
  const bytes2 = await readAsset(ref.artifact, version);
@@ -90894,10 +91271,10 @@ async function pullAssets(ws, record, assets) {
90894
91271
  return { ok: true, value: void 0 };
90895
91272
  }
90896
91273
  async function readAsset(artifact, version) {
90897
- const held3 = await readVersion(artifact, version);
90898
- if (!held3.ok) return held3;
90899
- if (held3.value.file) return download(held3.value.file.url);
90900
- const content = held3.value.content;
91274
+ const held4 = await readVersion(artifact, version);
91275
+ if (!held4.ok) return held4;
91276
+ if (held4.value.file) return download(held4.value.file.url);
91277
+ const content = held4.value.content;
90901
91278
  return { ok: true, value: Buffer.from(typeof content === "string" ? content : JSON.stringify(content)) };
90902
91279
  }
90903
91280
  var TYPES = {
@@ -90928,14 +91305,14 @@ function kindOf(ext) {
90928
91305
  return type.startsWith("video/") || type.startsWith("audio/") ? "video" : "asset";
90929
91306
  }
90930
91307
  async function sentOf(file2) {
90931
- const ext = path20.extname(file2).toLowerCase();
91308
+ const ext = path23.extname(file2).toLowerCase();
90932
91309
  const kind = kindOf(ext);
90933
- if (kind !== "html") return { bytes: fs17.readFileSync(file2), type: TYPES[ext] ?? "application/octet-stream", kind };
91310
+ if (kind !== "html") return { bytes: fs20.readFileSync(file2), type: TYPES[ext] ?? "application/octet-stream", kind };
90934
91311
  let page;
90935
91312
  try {
90936
91313
  page = await (await Promise.resolve().then(() => (init_mockup(), mockup_exports))).drawMockup(file2);
90937
91314
  } catch (e2) {
90938
- console.error(`runner: ${path20.basename(file2)} could not be drawn: ${e2 instanceof Error ? e2.message : String(e2)}`);
91315
+ console.error(`runner: ${path23.basename(file2)} could not be drawn: ${e2 instanceof Error ? e2.message : String(e2)}`);
90939
91316
  page = UNDRAWN;
90940
91317
  }
90941
91318
  return { bytes: Buffer.from(page), type: "text/html", kind };
@@ -90963,23 +91340,23 @@ async function pushAssets(ws, record, before) {
90963
91340
  for (const [name, ref] of Object.entries(before)) {
90964
91341
  if (!body.includes(name)) continue;
90965
91342
  const target = assetPath(ws, name, file2);
90966
- const held3 = record.assets[name];
90967
- const out = target && held3 && fs17.existsSync(target) ? await sentOf(target) : null;
91343
+ const held4 = record.assets[name];
91344
+ const out = target && held4 && fs20.existsSync(target) ? await sentOf(target) : null;
90968
91345
  const hash = out && hashOf(out.bytes);
90969
- if (out && held3 && held3.kind === "html" !== (out.kind === "html")) continue;
90970
- if (held3 && out && hash !== held3.hash) {
90971
- const sent = await uploadAsset(held3.artifact, out);
91346
+ if (out && held4 && held4.kind === "html" !== (out.kind === "html")) continue;
91347
+ if (held4 && out && hash !== held4.hash) {
91348
+ const sent = await uploadAsset(held4.artifact, out);
90972
91349
  if (!sent.ok) return sent;
90973
- assets[name] = { artifact: held3.artifact, version: sent.value, hash, kind: out.kind };
90974
- refs[name] = { artifact: held3.artifact, version: sent.value };
91350
+ assets[name] = { artifact: held4.artifact, version: sent.value, hash, kind: out.kind };
91351
+ refs[name] = { artifact: held4.artifact, version: sent.value };
90975
91352
  } else {
90976
- if (held3) assets[name] = held3;
91353
+ if (held4) assets[name] = held4;
90977
91354
  refs[name] = ref;
90978
91355
  }
90979
91356
  }
90980
91357
  for (const name of namedFiles(body)) {
90981
91358
  const target = assetPath(ws, name, file2);
90982
- if (refs[name] || !target || !fs17.statSync(target, { throwIfNoEntry: false })?.isFile()) continue;
91359
+ if (refs[name] || !target || !fs20.statSync(target, { throwIfNoEntry: false })?.isFile()) continue;
90983
91360
  const out = await sentOf(target);
90984
91361
  if (!ws.cloudTask) continue;
90985
91362
  const made = await createArtifact(ws.cloudTask, name.slice(0, 200), out.kind);
@@ -90990,24 +91367,24 @@ async function pushAssets(ws, record, before) {
90990
91367
  refs[name] = { artifact: made.value.id, version: sent.value };
90991
91368
  }
90992
91369
  record.assets = assets;
90993
- const list = path20.join(ws.board, assetsFile(ws.task));
90994
- if (Object.keys(refs).length || fs17.existsSync(list)) {
91370
+ const list = path23.join(ws.board, assetsFile(ws.task));
91371
+ if (Object.keys(refs).length || fs20.existsSync(list)) {
90995
91372
  if (JSON.stringify(assetsOf(readText(list))) !== JSON.stringify(refs)) write(list, assetsText(refs));
90996
91373
  }
90997
91374
  return { ok: true, value: void 0 };
90998
91375
  }
90999
91376
  function resetSorted(ws) {
91000
- for (const sub of ["dismissed", "archived"]) fs17.rmSync(path20.join(ws.board, "triage", sub), { recursive: true, force: true });
91377
+ for (const sub of ["dismissed", "archived"]) fs20.rmSync(path23.join(ws.board, "triage", sub), { recursive: true, force: true });
91001
91378
  for (const [p2, content] of viewOf(ws, readBase(ws), sharedMemory(ws.board))) {
91002
- if (/^triage\/(?:dismissed|archived)\//.test(p2)) write(path20.join(ws.board, p2), content);
91379
+ if (/^triage\/(?:dismissed|archived)\//.test(p2)) write(path23.join(ws.board, p2), content);
91003
91380
  }
91004
91381
  }
91005
91382
  function proposeItems(ws, base) {
91006
91383
  const root = rootOf(ws);
91007
91384
  for (const p2 of localFiles(ws, base)) {
91008
91385
  if (itemAt(p2)?.state !== "open" || base.files[root + p2]) continue;
91009
- const file2 = path20.join(ws.board, p2);
91010
- const content = fs17.readFileSync(file2, "utf8");
91386
+ const file2 = path23.join(ws.board, p2);
91387
+ const content = fs20.readFileSync(file2, "utf8");
91011
91388
  const said = (key) => new RegExp(`^${key}:`, "m").test(content.split(/\n---/)[0] ?? "");
91012
91389
  const fields = {
91013
91390
  ...ws.cloudTask && !said("source_task") ? { source_task: ws.cloudTask } : {},
@@ -91058,13 +91435,13 @@ async function send2(ws, job) {
91058
91435
  const owed = (p2) => !job.id && busy(ws.cwd) && itemAt(p2)?.state === "open" && !base.files[rootOf(ws) + p2];
91059
91436
  for (const p2 of local) {
91060
91437
  if (owed(p2)) continue;
91061
- const content = fs17.readFileSync(path20.join(ws.board, p2), "utf8");
91438
+ const content = fs20.readFileSync(path23.join(ws.board, p2), "utf8");
91062
91439
  const remote = remoteOf(ws, shared, p2);
91063
91440
  localOf.set(remote, p2);
91064
- const held3 = base.files[remote];
91065
- if (held3?.content === content) continue;
91441
+ const held4 = base.files[remote];
91442
+ if (held4?.content === content) continue;
91066
91443
  if (Buffer.byteLength(content) > BOARD_FILE_LIMIT) return fail(`${p2} is over ${BOARD_FILE_LIMIT / 1024} KB; keep large files as assets.`, false, "too_large");
91067
- changes.push({ path: remote, content, base_seq: held3?.seq ?? 0 });
91444
+ changes.push({ path: remote, content, base_seq: held4?.seq ?? 0 });
91068
91445
  }
91069
91446
  for (const p2 of viewOf(ws, base, shared).keys()) {
91070
91447
  const remote = remoteOf(ws, shared, p2);
@@ -91090,15 +91467,15 @@ async function send2(ws, job) {
91090
91467
  changes.splice(at2, 1);
91091
91468
  delete base.files[theirs.path];
91092
91469
  writeBase(ws, base);
91093
- fs17.rmSync(path20.join(ws.board, p2), { force: true });
91470
+ fs20.rmSync(path23.join(ws.board, p2), { force: true });
91094
91471
  writeIndex(ws.board);
91095
91472
  continue;
91096
91473
  }
91097
91474
  if (at2 < 0) continue;
91098
91475
  const merged = itemAt(p2) ? { content: theirs.content } : mergeFile(base.files[theirs.path]?.content ?? null, changes[at2].content, theirs.content);
91099
91476
  changes[at2] = { path: theirs.path, content: merged.content, base_seq: theirs.seq };
91100
- if (merged.content === null) fs17.rmSync(path20.join(ws.board, p2), { force: true });
91101
- else write(path20.join(ws.board, p2), merged.content);
91477
+ if (merged.content === null) fs20.rmSync(path23.join(ws.board, p2), { force: true });
91478
+ else write(path23.join(ws.board, p2), merged.content);
91102
91479
  }
91103
91480
  if (!changes.length) return { ok: true, changed: false };
91104
91481
  sent = await commitBoard(ws.project, job.id, job.machineId, changes);
@@ -91119,7 +91496,7 @@ var PULL_MS = 2e3;
91119
91496
  function keptFolders() {
91120
91497
  let cached2 = [];
91121
91498
  try {
91122
- cached2 = fs18.readdirSync(cacheRoot()).map((name) => path21.join(cacheRoot(), name));
91499
+ cached2 = fs21.readdirSync(cacheRoot()).map((name) => path24.join(cacheRoot(), name));
91123
91500
  } catch {
91124
91501
  }
91125
91502
  return [.../* @__PURE__ */ new Set([...allowedProjects(), ...cached2])].flatMap((dir) => [keptBoard(dir)].filter((ws) => !!ws));
@@ -91143,12 +91520,12 @@ function watchBoards(machineId2, ms2, lookMs = LOOK_MS, pullMs = PULL_MS) {
91143
91520
  const watch = (ws) => {
91144
91521
  let watcher;
91145
91522
  try {
91146
- watcher = fs18.watch(ws.board, { recursive: true }, (_event, name) => {
91147
- const p2 = name && String(name).split(path21.sep).join("/");
91148
- const held3 = watched.get(ws.cwd);
91149
- if (closed || !p2 || !isBoardPath(p2) || !held3) return;
91150
- clearTimeout(held3.timer);
91151
- held3.timer = setTimeout(() => void send3(ws), ms2);
91523
+ watcher = fs21.watch(ws.board, { recursive: true }, (_event, name) => {
91524
+ const p2 = name && String(name).split(path24.sep).join("/");
91525
+ const held4 = watched.get(ws.cwd);
91526
+ if (closed || !p2 || !isBoardPath(p2) || !held4) return;
91527
+ clearTimeout(held4.timer);
91528
+ held4.timer = setTimeout(() => void send3(ws), ms2);
91152
91529
  });
91153
91530
  } catch {
91154
91531
  return false;
@@ -91192,9 +91569,9 @@ function watchBoards(machineId2, ms2, lookMs = LOOK_MS, pullMs = PULL_MS) {
91192
91569
  clearInterval(timer);
91193
91570
  for (const t2 of due.values()) clearTimeout(t2);
91194
91571
  due.clear();
91195
- for (const held3 of watched.values()) {
91196
- clearTimeout(held3.timer);
91197
- held3.watcher.close();
91572
+ for (const held4 of watched.values()) {
91573
+ clearTimeout(held4.timer);
91574
+ held4.watcher.close();
91198
91575
  }
91199
91576
  watched.clear();
91200
91577
  }
@@ -91202,16 +91579,16 @@ function watchBoards(machineId2, ms2, lookMs = LOOK_MS, pullMs = PULL_MS) {
91202
91579
  }
91203
91580
 
91204
91581
  // src/diff.ts
91205
- import { execFile } from "node:child_process";
91206
- import fs19 from "node:fs";
91207
- import path22 from "node:path";
91582
+ import { execFile as execFile2 } from "node:child_process";
91583
+ import fs22 from "node:fs";
91584
+ import path25 from "node:path";
91208
91585
  var FILE_BYTES = 256 * 1024;
91209
91586
  var TOTAL_BYTES = 1024 * 1024;
91210
91587
  var EMPTY_TREE = "4b825dc642cb6eb9a060e54bf8d69288fbee4904";
91211
91588
  var PATHS = ["--", ".", ":(exclude).akb"];
91212
91589
  var STATUS = { A: "added", D: "deleted" };
91213
91590
  var git2 = (dir, args, maxBuffer = 4 * TOTAL_BYTES) => new Promise(
91214
- (resolve2) => execFile(
91591
+ (resolve2) => execFile2(
91215
91592
  "git",
91216
91593
  ["-C", dir, "-c", "core.quotePath=false", ...args],
91217
91594
  { encoding: "utf8", maxBuffer },
@@ -91221,7 +91598,7 @@ var git2 = (dir, args, maxBuffer = 4 * TOTAL_BYTES) => new Promise(
91221
91598
  function projectDir(placed, project) {
91222
91599
  if (placed) {
91223
91600
  const real = realpath3(placed);
91224
- return real && allowedProjects().some((root) => real === root || real.startsWith(root + path22.sep)) ? real : null;
91601
+ return real && allowedProjects().some((root) => real === root || real.startsWith(root + path25.sep)) ? real : null;
91225
91602
  }
91226
91603
  let cached2;
91227
91604
  try {
@@ -91229,11 +91606,11 @@ function projectDir(placed, project) {
91229
91606
  } catch {
91230
91607
  return null;
91231
91608
  }
91232
- return fs19.existsSync(path22.join(cached2, ".git")) ? cached2 : null;
91609
+ return fs22.existsSync(path25.join(cached2, ".git")) ? cached2 : null;
91233
91610
  }
91234
91611
  function realpath3(p2) {
91235
91612
  try {
91236
- return fs19.realpathSync(p2);
91613
+ return fs22.realpathSync(p2);
91237
91614
  } catch {
91238
91615
  return null;
91239
91616
  }
@@ -91278,89 +91655,12 @@ async function answerHint(machineId2, hint2) {
91278
91655
  }
91279
91656
 
91280
91657
  // src/flow.ts
91281
- import fs23 from "node:fs";
91282
- import path26 from "node:path";
91283
-
91284
- // src/akb.ts
91285
- import { spawn as spawn3 } from "node:child_process";
91286
- import fs20 from "node:fs";
91287
- import path23 from "node:path";
91288
- import { fileURLToPath } from "node:url";
91289
- var bundledAkb = () => ({
91290
- command: process.execPath,
91291
- args: [path23.join(path23.dirname(fileURLToPath(import.meta.url)), "akb", "bin", "ai4kanban.mjs")]
91292
- });
91293
- var quote = (s) => /^[\w./:@=-]+$/.test(s) ? s : `"${s}"`;
91294
- function shimDir(akb) {
91295
- const dir = path23.join(runnerHome(), "bin", "akb");
91296
- const line = [akb.command, ...akb.args].map(quote).join(" ");
91297
- const [file2, text3] = process.platform === "win32" ? [path23.join(dir, "akb.cmd"), `@${line} %*\r
91298
- `] : [path23.join(dir, "akb"), `#!/bin/sh
91299
- exec ${line} "$@"
91300
- `];
91301
- try {
91302
- if (fs20.readFileSync(file2, "utf8") === text3) return dir;
91303
- } catch {
91304
- }
91305
- fs20.mkdirSync(dir, { recursive: true });
91306
- fs20.writeFileSync(file2, text3, { mode: 493 });
91307
- return dir;
91308
- }
91309
- function akbEnv(akb, board, task, line) {
91310
- const env2 = {};
91311
- const dropped = ["AI4KANBAN_BOARD", "AI4KANBAN_TASK", LANGUAGE_LINE_ENV];
91312
- for (const [k, v2] of Object.entries(process.env)) if (!k.startsWith("KANBAN_") && !dropped.includes(k)) env2[k] = v2;
91313
- const key = Object.keys(env2).find((k) => k.toUpperCase() === "PATH") ?? "PATH";
91314
- env2[key] = [shimDir(akb), env2[key]].filter(Boolean).join(path23.delimiter);
91315
- env2.AI4KANBAN_COMMAND = "akb";
91316
- if (board) env2.AI4KANBAN_BOARD = board;
91317
- if (task) env2.AI4KANBAN_TASK = task;
91318
- if (line !== void 0) env2[LANGUAGE_LINE_ENV] = line;
91319
- return env2;
91320
- }
91321
- var KEEP = 256 * 1024;
91322
- function runAkb(akb, args, opts) {
91323
- return new Promise((resolve2) => {
91324
- let out = "";
91325
- let last2 = "";
91326
- const note = (text3) => {
91327
- const line = text3.split("\n").map((l2) => l2.trim()).filter(Boolean).at(-1);
91328
- if (line) last2 = line;
91329
- };
91330
- let child;
91331
- try {
91332
- child = spawn3(akb.command, [...akb.args, ...args], { cwd: opts.cwd, env: akbEnv(akb, opts.board, opts.task, opts.line), stdio: ["ignore", "pipe", "pipe"] });
91333
- } catch (e2) {
91334
- return resolve2({ code: null, out: "", last: e2 instanceof Error ? e2.message : String(e2) });
91335
- }
91336
- opts.track?.(child);
91337
- child.stdout.setEncoding("utf8");
91338
- child.stderr.setEncoding("utf8");
91339
- child.stdout.on("data", (chunk) => {
91340
- out = (out + chunk).slice(-KEEP);
91341
- note(chunk);
91342
- opts.show?.(chunk);
91343
- });
91344
- child.stderr.on("data", (chunk) => {
91345
- note(chunk);
91346
- opts.show?.(chunk);
91347
- });
91348
- child.on("error", (e2) => resolve2({ code: null, out, last: e2.message }));
91349
- child.on("close", (code) => resolve2({ code, out, last: last2 }));
91350
- });
91351
- }
91352
- function answerOf2(ran) {
91353
- const line = ran.out.trim().split("\n").at(-1) ?? "";
91354
- try {
91355
- return JSON.parse(line);
91356
- } catch {
91357
- return null;
91358
- }
91359
- }
91658
+ import fs25 from "node:fs";
91659
+ import path28 from "node:path";
91360
91660
 
91361
91661
  // src/triage.ts
91362
- import fs21 from "node:fs";
91363
- import path24 from "node:path";
91662
+ import fs23 from "node:fs";
91663
+ import path26 from "node:path";
91364
91664
 
91365
91665
  // ../cli/src/lib/signals/identity.ts
91366
91666
  import { createHash } from "node:crypto";
@@ -91368,8 +91668,8 @@ var DERIVED = "derived-";
91368
91668
  var derivedSourceId = (seed) => `${DERIVED}${createHash("sha256").update(seed).digest("hex").slice(0, 16)}`;
91369
91669
 
91370
91670
  // src/triage.ts
91371
- var triageDir = (board) => path24.join(board, "triage");
91372
- var rejectedDir = (board) => path24.join(board, ".archive", ".sync");
91671
+ var triageDir = (board) => path26.join(board, "triage");
91672
+ var rejectedDir = (board) => path26.join(board, ".archive", ".sync");
91373
91673
  var SCRATCH = ["dismissed", "archived"];
91374
91674
  var stamp = (at2) => formatStamp(at2 ? new Date(at2) : /* @__PURE__ */ new Date());
91375
91675
  function slugOf(title) {
@@ -91378,7 +91678,7 @@ function slugOf(title) {
91378
91678
  function freeName(dir, title) {
91379
91679
  const stem = slugOf(title);
91380
91680
  let name = `${stem}.md`;
91381
- for (let n = 2; fs21.existsSync(path24.join(dir, name)); n++) name = `${stem}-${n}.md`;
91681
+ for (let n = 2; fs23.existsSync(path26.join(dir, name)); n++) name = `${stem}-${n}.md`;
91382
91682
  return name;
91383
91683
  }
91384
91684
  function itemText(item, fields = {}) {
@@ -91398,17 +91698,17 @@ ${item.text.trim()}
91398
91698
  `;
91399
91699
  }
91400
91700
  function writeItem(dir, item, fields = {}) {
91401
- fs21.mkdirSync(dir, { recursive: true });
91701
+ fs23.mkdirSync(dir, { recursive: true });
91402
91702
  const name = freeName(dir, item.title);
91403
- fs21.writeFileSync(path24.join(dir, name), itemText(item, item.workflow ? { workflow: workflowName(item.workflow), ...fields } : fields));
91703
+ fs23.writeFileSync(path26.join(dir, name), itemText(item, item.workflow ? { workflow: workflowName(item.workflow), ...fields } : fields));
91404
91704
  return name;
91405
91705
  }
91406
91706
  function layOut(board, rejections) {
91407
91707
  clearLaid(board);
91408
91708
  const dir = rejectedDir(board);
91409
- fs21.mkdirSync(dir, { recursive: true });
91709
+ fs23.mkdirSync(dir, { recursive: true });
91410
91710
  for (const t2 of rejections.tasks) {
91411
- fs21.writeFileSync(path24.join(dir, `${t2.number}-${slugify(t2.title)}.md`), [
91711
+ fs23.writeFileSync(path26.join(dir, `${t2.number}-${slugify(t2.title)}.md`), [
91412
91712
  "---",
91413
91713
  `title: ${yamlScalar(t2.title)}`,
91414
91714
  "status: todo",
@@ -91423,20 +91723,20 @@ function layOut(board, rejections) {
91423
91723
  ].join("\n"));
91424
91724
  }
91425
91725
  for (const item of rejections.triage) {
91426
- const sub = path24.join(triageDir(board), item.state === "dismissed" ? "dismissed" : "archived");
91726
+ const sub = path26.join(triageDir(board), item.state === "dismissed" ? "dismissed" : "archived");
91427
91727
  const fields = item.state === "dismissed" ? { dismissed_at: stamp(item.dismissed_at), dismissed_by: "user", ...item.dismissed_reason ? { dismissed_reason: item.dismissed_reason } : {} } : {};
91428
91728
  writeItem(sub, item, fields);
91429
91729
  }
91430
91730
  return { tasks: rejections.tasks.map((t2) => t2.id), triage: rejections.triage.map((i) => i.id) };
91431
91731
  }
91432
91732
  function clearLaid(board) {
91433
- fs21.rmSync(rejectedDir(board), { recursive: true, force: true });
91434
- for (const sub of SCRATCH) fs21.rmSync(path24.join(triageDir(board), sub), { recursive: true, force: true });
91733
+ fs23.rmSync(rejectedDir(board), { recursive: true, force: true });
91734
+ for (const sub of SCRATCH) fs23.rmSync(path26.join(triageDir(board), sub), { recursive: true, force: true });
91435
91735
  }
91436
91736
 
91437
91737
  // src/built.ts
91438
- import fs22 from "node:fs";
91439
- import path25 from "node:path";
91738
+ import fs24 from "node:fs";
91739
+ import path27 from "node:path";
91440
91740
 
91441
91741
  // ../cli/src/lib/agent/workflow-def.ts
91442
91742
  var WORKFLOW_ID = /^[a-z0-9]+(-[a-z0-9]+)*$/;
@@ -91594,26 +91894,26 @@ function checkWorkflowFiles(value, official = false) {
91594
91894
 
91595
91895
  // src/built.ts
91596
91896
  var isBuilder = (ws) => ws.workflow === BUILDER;
91597
- var draftDir = (ws) => path25.join(ws.board, "workflows", draftFolder(ws.task));
91598
- var draftLine = (ws) => `<!-- workflow folder: ${path25.relative(ws.cwd, draftDir(ws)).split(path25.sep).join("/")}/ -->`;
91897
+ var draftDir = (ws) => path27.join(ws.board, "workflows", draftFolder(ws.task));
91898
+ var draftLine = (ws) => `<!-- workflow folder: ${path27.relative(ws.cwd, draftDir(ws)).split(path27.sep).join("/")}/ -->`;
91599
91899
  var skeleton = (name) => ["---", `name: ${/\s#/.test(name) ? JSON.stringify(name) : yamlScalar(name)}`, "needsArtifact: false", "---", ""].join("\n");
91600
91900
  async function placeDraft(ws, read) {
91601
91901
  const dir = draftDir(ws);
91602
- if (fs22.existsSync(path25.join(dir, WORKFLOW_FILE))) return { ok: true, value: void 0 };
91902
+ if (fs24.existsSync(path27.join(dir, WORKFLOW_FILE))) return { ok: true, value: void 0 };
91603
91903
  const task = await read.readTask(ws.task);
91604
91904
  if (!task.ok) return task;
91605
91905
  let files = { [WORKFLOW_FILE]: skeleton(task.value.title.trim() || "Untitled") };
91606
91906
  const changes = task.value.context?.workflow;
91607
91907
  if (changes) {
91608
- const held3 = await read.readWorkflow(changes);
91609
- if (!held3.ok) return held3;
91610
- files = held3.value.files;
91908
+ const held4 = await read.readWorkflow(changes);
91909
+ if (!held4.ok) return held4;
91910
+ files = held4.value.files;
91611
91911
  }
91612
91912
  for (const [name, text3] of Object.entries(files)) {
91613
- const file2 = path25.resolve(dir, name);
91614
- if (!file2.startsWith(dir + path25.sep)) continue;
91615
- fs22.mkdirSync(path25.dirname(file2), { recursive: true });
91616
- fs22.writeFileSync(file2, text3);
91913
+ const file2 = path27.resolve(dir, name);
91914
+ if (!file2.startsWith(dir + path27.sep)) continue;
91915
+ fs24.mkdirSync(path27.dirname(file2), { recursive: true });
91916
+ fs24.writeFileSync(file2, text3);
91617
91917
  }
91618
91918
  return { ok: true, value: void 0 };
91619
91919
  }
@@ -91625,19 +91925,19 @@ async function builtWorkflow(ws, akb) {
91625
91925
  const dir = draftDir(ws);
91626
91926
  let source;
91627
91927
  try {
91628
- source = fs22.readFileSync(path25.join(dir, WORKFLOW_FILE), "utf8");
91928
+ source = fs24.readFileSync(path27.join(dir, WORKFLOW_FILE), "utf8");
91629
91929
  } catch {
91630
91930
  return fail(`workflows/${id}/${WORKFLOW_FILE} is missing.`);
91631
91931
  }
91632
91932
  const read = parseWorkflowFile(id, source, `workflows/${id}/${WORKFLOW_FILE}`);
91633
91933
  if ("problem" in read) return fail(read.problem);
91634
91934
  const names2 = named(read.def);
91635
- fs22.rmSync(path25.join(dir, "agents"), { recursive: true, force: true });
91935
+ fs24.rmSync(path27.join(dir, "agents"), { recursive: true, force: true });
91636
91936
  for (const name of names2) {
91637
- const from = path25.join(ws.board, "agents", name);
91638
- if (fs22.existsSync(from)) fs22.cpSync(from, path25.join(dir, "agents", name), { recursive: true });
91937
+ const from = path27.join(ws.board, "agents", name);
91938
+ if (fs24.existsSync(from)) fs24.cpSync(from, path27.join(dir, "agents", name), { recursive: true });
91639
91939
  }
91640
- const files = Object.fromEntries(filesUnder(dir).map((f2) => [f2, fs22.readFileSync(path25.join(dir, f2), "utf8")]));
91940
+ const files = Object.fromEntries(filesUnder(dir).map((f2) => [f2, fs24.readFileSync(path27.join(dir, f2), "utf8")]));
91641
91941
  const checked = checkWorkflowFiles(files);
91642
91942
  if (!checked.ok) return fail(`${checked.file} ${checked.reason}.`);
91643
91943
  const run2 = async (args) => answerOf2(await runAkb(akb, [...args, "--json", "--board", ws.board], { cwd: ws.cwd, board: ws.board }));
@@ -91653,10 +91953,10 @@ async function builtWorkflow(ws, akb) {
91653
91953
  }
91654
91954
 
91655
91955
  // src/flow.ts
91656
- function unavailable(wanted, reports) {
91657
- const report2 = reports.find((r2) => r2.name === wanted);
91658
- if (!report2?.installed) return `${LABELS[wanted]} is not installed on this computer.`;
91659
- if (report2.loggedIn === false) return `${LABELS[wanted]} is not signed in on this computer.`;
91956
+ function unavailable(wanted2, reports) {
91957
+ const report2 = reports.find((r2) => r2.name === wanted2);
91958
+ if (!report2?.installed) return `${LABELS[wanted2]} is not installed on this computer.`;
91959
+ if (report2.loggedIn === false) return `${LABELS[wanted2]} is not signed in on this computer.`;
91660
91960
  return null;
91661
91961
  }
91662
91962
  function spentBy(runs) {
@@ -91670,11 +91970,10 @@ function spentBy(runs) {
91670
91970
  ...context ? { context: { used: context.used, limit: context.limit } } : {}
91671
91971
  };
91672
91972
  }
91673
- var SETUP_STEPS = ["project", "agent", "decisions", "modules", "tasks"];
91674
91973
  function reviewOf(file2) {
91675
91974
  let text3;
91676
91975
  try {
91677
- text3 = fs23.readFileSync(file2, "utf8");
91976
+ text3 = fs25.readFileSync(file2, "utf8");
91678
91977
  } catch {
91679
91978
  return void 0;
91680
91979
  }
@@ -91688,8 +91987,8 @@ function reviewOf(file2) {
91688
91987
  }
91689
91988
  function mcpConfig(servers, file2) {
91690
91989
  if (!Object.keys(servers).length) return null;
91691
- fs23.mkdirSync(path26.dirname(file2), { recursive: true });
91692
- fs23.writeFileSync(file2, `${JSON.stringify({ mcpServers: servers }, null, 2)}
91990
+ fs25.mkdirSync(path28.dirname(file2), { recursive: true });
91991
+ fs25.writeFileSync(file2, `${JSON.stringify({ mcpServers: servers }, null, 2)}
91693
91992
  `);
91694
91993
  return file2;
91695
91994
  }
@@ -91722,31 +92021,31 @@ async function stopLeftBehind(akb, ws, id, ms2) {
91722
92021
  }
91723
92022
  function deliveryEnding(ws, id) {
91724
92023
  if (!id) return null;
91725
- let held3;
92024
+ let held4;
91726
92025
  try {
91727
- held3 = JSON.parse(fs23.readFileSync(path26.join(ws.board, "deliveries", `${path26.basename(id)}.json`), "utf8"));
92026
+ held4 = JSON.parse(fs25.readFileSync(path28.join(ws.board, "deliveries", `${path28.basename(id)}.json`), "utf8"));
91728
92027
  } catch {
91729
92028
  return null;
91730
92029
  }
91731
- const stopped2 = held3.review?.stopped;
91732
- if (held3.status === "cancelled") {
91733
- return held3.steps?.some((s) => s.step === "discarded") ? { ok: false, reason: "The build was discarded." } : { ok: false, reason: "", stopped: true };
92030
+ const stopped2 = held4.review?.stopped;
92031
+ if (held4.status === "cancelled") {
92032
+ return held4.steps?.some((s) => s.step === "discarded") ? { ok: false, reason: "The build was discarded." } : { ok: false, reason: "", stopped: true };
91734
92033
  }
91735
- if (held3.status === "active" && stopped2?.reason === "landing") return { ok: false, reason: firstLine(stopped2.why) ?? "The build could not land." };
92034
+ if (held4.status === "active" && stopped2?.reason === "landing") return { ok: false, reason: firstLine(stopped2.why) ?? "The build could not land." };
91736
92035
  return null;
91737
92036
  }
91738
92037
  function checkoutsOf(ws, id) {
91739
- const dir = path26.join(ws.board, "deliveries");
92038
+ const dir = path28.join(ws.board, "deliveries");
91740
92039
  let names2;
91741
92040
  try {
91742
- names2 = fs23.readdirSync(dir).filter((n) => n.endsWith(".json"));
92041
+ names2 = fs25.readdirSync(dir).filter((n) => n.endsWith(".json"));
91743
92042
  } catch {
91744
92043
  return [];
91745
92044
  }
91746
92045
  return names2.flatMap((n) => {
91747
92046
  try {
91748
- const held3 = JSON.parse(fs23.readFileSync(path26.join(dir, n), "utf8"));
91749
- return held3.cardId === id && held3.worktree && held3.deliveryId ? [held3.deliveryId] : [];
92047
+ const held4 = JSON.parse(fs25.readFileSync(path28.join(dir, n), "utf8"));
92048
+ return held4.cardId === id && held4.worktree && held4.deliveryId ? [held4.deliveryId] : [];
91750
92049
  } catch {
91751
92050
  return [];
91752
92051
  }
@@ -91755,7 +92054,7 @@ function checkoutsOf(ws, id) {
91755
92054
  var refusal2 = (ran) => ran.last.replace(/^akb( raw)?: /, "").slice(0, 300) || "akb stopped with an error.";
91756
92055
  var firstLine = (text3) => (text3 ?? "").split("\n").map((l2) => l2.trim()).find(Boolean)?.slice(0, 300);
91757
92056
  function logLines(show, event2) {
91758
- let held3 = "";
92057
+ let held4 = "";
91759
92058
  const said = (line) => {
91760
92059
  if (line.startsWith('{"kind":')) {
91761
92060
  let parsed;
@@ -91781,15 +92080,15 @@ function logLines(show, event2) {
91781
92080
  };
91782
92081
  return {
91783
92082
  push: (chunk) => {
91784
- const lines = (held3 + chunk).split("\n");
91785
- held3 = lines.pop();
92083
+ const lines = (held4 + chunk).split("\n");
92084
+ held4 = lines.pop();
91786
92085
  for (const line of lines) {
91787
92086
  const out = said(line);
91788
92087
  if (out) show(out);
91789
92088
  }
91790
92089
  },
91791
92090
  end: () => {
91792
- const out = held3 ? said(held3) : "";
92091
+ const out = held4 ? said(held4) : "";
91793
92092
  if (out) show(out);
91794
92093
  }
91795
92094
  };
@@ -91804,17 +92103,24 @@ function boardAkb(job, ws, deps, io, task) {
91804
92103
  return ran;
91805
92104
  };
91806
92105
  }
92106
+ function skillStale(dir, version) {
92107
+ try {
92108
+ const text3 = fs25.readFileSync(path28.join(dir, "SKILL.md"), "utf8");
92109
+ return !fs25.lstatSync(dir).isSymbolicLink() && /<!-- ai4kanban (\S+) -->\s*$/.exec(text3)?.[1] !== version;
92110
+ } catch {
92111
+ return true;
92112
+ }
92113
+ }
91807
92114
  async function setUp(job, ws, deps, io) {
91808
92115
  const akb = boardAkb(job, ws, deps, io);
91809
92116
  const runtime = job.runtime;
91810
92117
  const missing = unavailable(runtime, await deps.runtimes());
91811
92118
  if (missing) return missing;
91812
- if (!fs23.existsSync(path26.join(ws.board, "config.md"))) {
92119
+ if (!fs25.existsSync(path28.join(ws.board, "config.md"))) {
91813
92120
  const init = await akb(["raw", "init"]);
91814
92121
  if (init.code !== 0) return refusal2(init);
91815
- for (const step of SETUP_STEPS) await akb(["raw", "setup-done", step]);
91816
92122
  }
91817
- if (SKILL_FOLDERS.some((f2) => !fs23.existsSync(path26.join(ws.cwd, f2, "SKILL.md")))) {
92123
+ if (SKILL_FOLDERS.some((f2) => skillStale(path28.join(ws.cwd, f2), deps.akb.version))) {
91818
92124
  const skill = await runAkb(deps.akb, ["skill", "install", "--dir", ws.cwd], { cwd: ws.cwd, track: io.track });
91819
92125
  if (skill.code !== 0) return refusal2(skill);
91820
92126
  }
@@ -91823,7 +92129,7 @@ async function setUp(job, ws, deps, io) {
91823
92129
  const used = await akb(["agent", "use", runtime]);
91824
92130
  if (used.code !== 0) return refusal2(used);
91825
92131
  const servers = mcpServersOf(ws);
91826
- const mcpFile = path26.join(ws.board, ".sync", `${ws.task}.mcp.json`);
92132
+ const mcpFile = path28.join(ws.board, ".sync", `${ws.task}.mcp.json`);
91827
92133
  const takes = new Set(settingKeys(runtime));
91828
92134
  const given = job.settings ?? {};
91829
92135
  const values = { ...given, model: job.model ?? "" };
@@ -91913,19 +92219,19 @@ async function runAgent(job, ws, deps, io) {
91913
92219
  }
91914
92220
  function writeTranscript(job, dir) {
91915
92221
  if (!job.transcript) return "";
91916
- const file2 = path26.join(dir, "discussion.md");
91917
- fs23.mkdirSync(dir, { recursive: true });
91918
- fs23.writeFileSync(file2, `${job.transcript}
92222
+ const file2 = path28.join(dir, "discussion.md");
92223
+ fs25.mkdirSync(dir, { recursive: true });
92224
+ fs25.writeFileSync(file2, `${job.transcript}
91919
92225
  `);
91920
92226
  return file2;
91921
92227
  }
91922
92228
  function pictures(job, ws, id) {
91923
92229
  const dir = cardAssetsDir(ws, id);
91924
92230
  if (!job.attachments.length || !dir) return "";
91925
- fs23.mkdirSync(dir, { recursive: true });
92231
+ fs25.mkdirSync(dir, { recursive: true });
91926
92232
  return job.attachments.map((a3, i) => {
91927
- const file2 = `${i + 1}-${path26.basename(a3.name).replace(/[^\w.-]+/g, "-")}`;
91928
- fs23.writeFileSync(path26.join(dir, file2), Buffer.from(a3.content, "base64"));
92233
+ const file2 = `${i + 1}-${path28.basename(a3.name).replace(/[^\w.-]+/g, "-")}`;
92234
+ fs25.writeFileSync(path28.join(dir, file2), Buffer.from(a3.content, "base64"));
91929
92235
  return `
91930
92236
  <Asset src=".assets/${id}/${file2}" label="${a3.name.replace(/["<>]/g, "") || file2}" />
91931
92237
  `;
@@ -91933,11 +92239,10 @@ function pictures(job, ws, id) {
91933
92239
  }
91934
92240
  function cardFlags(ws, fields) {
91935
92241
  if (!fields) return [];
91936
- const open = (keys) => (keys ?? []).map((k) => Number(/(\d+)$/.exec(k)?.[1])).filter((n) => n > 0 && n !== ws.number && findCard(ws.board, n)?.startsWith(path26.join(ws.board, "todo") + path26.sep));
92242
+ const open = (keys) => (keys ?? []).map((k) => Number(/(\d+)$/.exec(k)?.[1])).filter((n) => n > 0 && n !== ws.number && findCard(ws.board, n)?.startsWith(path28.join(ws.board, "todo") + path28.sep));
91937
92243
  const lists = [["--modules", fields.modules ?? []], ["--related", open(fields.related)], ["--blocked-by", open(fields.blocked_by)]];
91938
92244
  return [
91939
92245
  ...fields.priority ? ["--priority", fields.priority] : [],
91940
- ...fields.roi ? ["--roi", fields.roi] : [],
91941
92246
  ...lists.flatMap(([flag, list]) => list.length ? [flag, list.join(",")] : [])
91942
92247
  ];
91943
92248
  }
@@ -91968,10 +92273,10 @@ async function runFlow(job, ws, deps, io) {
91968
92273
  const placed = await placeDraft(ws, deps.api);
91969
92274
  if (!placed.ok) return fail(placed.error);
91970
92275
  }
91971
- const body = path26.join(ws.board, ".sync", `${ws.task}.request.md`);
91972
- fs23.mkdirSync(path26.dirname(body), { recursive: true });
92276
+ const body = path28.join(ws.board, ".sync", `${ws.task}.request.md`);
92277
+ fs25.mkdirSync(path28.dirname(body), { recursive: true });
91973
92278
  if (!ws.number) return fail("This task has no number yet.");
91974
- fs23.writeFileSync(body, `${said.request || title}
92279
+ fs25.writeFileSync(body, `${said.request || title}
91975
92280
  ${isBuilder(ws) ? `
91976
92281
  ${draftLine(ws)}
91977
92282
  ` : ""}${pictures(job, ws, ws.number)}`);
@@ -91989,21 +92294,21 @@ ${draftLine(ws)}
91989
92294
  ...cardFlags(ws, flow.metadata),
91990
92295
  "--json"
91991
92296
  ]));
91992
- fs23.rmSync(body, { force: true });
92297
+ fs25.rmSync(body, { force: true });
91993
92298
  if (!created.ok) return fail(created.error);
91994
92299
  id = created.value;
91995
92300
  }
91996
92301
  if (!id) return fail("This task has no card on this computer.");
91997
92302
  const card = id;
91998
92303
  const key = workKey(ws, card);
91999
- const held3 = working.get(key) ?? 0;
92000
- working.set(key, held3 + 1);
92304
+ const held4 = working.get(key) ?? 0;
92305
+ working.set(key, held4 + 1);
92001
92306
  try {
92002
- if (!held3) await stopRuns(deps.akb, ws, card, 0, deps.stopMs);
92307
+ if (!held4) await stopRuns(deps.akb, ws, card, 0, deps.stopMs);
92003
92308
  if (io.lost()) return fail("");
92004
92309
  return await workOn(card);
92005
92310
  } finally {
92006
- fs23.rmSync(path26.join(ws.board, ".sync", `${ws.task}.discussion`), { recursive: true, force: true });
92311
+ fs25.rmSync(path28.join(ws.board, ".sync", `${ws.task}.discussion`), { recursive: true, force: true });
92007
92312
  const left = working.get(key) - 1;
92008
92313
  if (left) working.set(key, left);
92009
92314
  else working.delete(key);
@@ -92056,7 +92361,7 @@ ${draftLine(ws)}
92056
92361
  }
92057
92362
  function carryArgs(verb) {
92058
92363
  if (!["refine", "resolve", "revise"].includes(verb)) return [];
92059
- const transcript = writeTranscript(job, path26.join(ws.board, ".sync", `${ws.task}.discussion`));
92364
+ const transcript = writeTranscript(job, path28.join(ws.board, ".sync", `${ws.task}.discussion`));
92060
92365
  return [
92061
92366
  ...job.resume ? ["--session", job.resume, ...job.fork ? ["--fork"] : []] : [],
92062
92367
  ...transcript ? ["--transcript", transcript] : []
@@ -92065,17 +92370,17 @@ ${draftLine(ws)}
92065
92370
  }
92066
92371
 
92067
92372
  // src/lock.ts
92068
- import crypto3 from "node:crypto";
92069
- import fs24 from "node:fs";
92373
+ import crypto4 from "node:crypto";
92374
+ import fs26 from "node:fs";
92070
92375
  import net from "node:net";
92071
- import path27 from "node:path";
92376
+ import path29 from "node:path";
92072
92377
  var RETRY_MS = 5e3;
92073
92378
  var KIND_MS = 1e3;
92074
92379
  var HOLDERS = ["claude-code", "codex", "terminal", "desktop"];
92075
92380
  function lockPath() {
92076
92381
  const home4 = runnerHome();
92077
- if (process.platform === "win32") return `\\\\.\\pipe\\wildcrane-${crypto3.createHash("sha256").update(home4).digest("hex").slice(0, 16)}`;
92078
- return path27.join(home4, "runner.sock");
92382
+ if (process.platform === "win32") return `\\\\.\\pipe\\wildcrane-${crypto4.createHash("sha256").update(home4).digest("hex").slice(0, 16)}`;
92383
+ return path29.join(home4, "runner.sock");
92079
92384
  }
92080
92385
  function holdMachine(kind, onHeld, onWaiting) {
92081
92386
  const where = lockPath();
@@ -92090,7 +92395,7 @@ function holdMachine(kind, onHeld, onWaiting) {
92090
92395
  const attempt = () => {
92091
92396
  timer = null;
92092
92397
  if (closed) return;
92093
- if (process.platform !== "win32") fs24.mkdirSync(path27.dirname(where), { recursive: true, mode: 448 });
92398
+ if (process.platform !== "win32") fs26.mkdirSync(path29.dirname(where), { recursive: true, mode: 448 });
92094
92399
  const s = net.createServer((peer) => {
92095
92400
  peers.add(peer);
92096
92401
  peer.on("error", () => {
@@ -92138,7 +92443,7 @@ function holdMachine(kind, onHeld, onWaiting) {
92138
92443
  later(0);
92139
92444
  });
92140
92445
  removeIfStill.once("error", () => {
92141
- fs24.rmSync(where, { force: true });
92446
+ fs26.rmSync(where, { force: true });
92142
92447
  later(50 + Math.random() * 200);
92143
92448
  });
92144
92449
  return;
@@ -92167,13 +92472,117 @@ function holdMachine(kind, onHeld, onWaiting) {
92167
92472
 
92168
92473
  // src/jobs.ts
92169
92474
  import { spawn as spawn4 } from "node:child_process";
92170
- import fs26 from "node:fs";
92171
- import path29 from "node:path";
92475
+ import fs29 from "node:fs";
92476
+ import path32 from "node:path";
92477
+
92478
+ // ../cli/src/lib/agent/catalog.ts
92479
+ import fs27 from "node:fs";
92480
+ import path30 from "node:path";
92481
+ var CATALOGUE = "https://models.dev/api.json";
92482
+ var FRESH_FOR_MS = 24 * 60 * 6e4;
92483
+ var ANSWER_BY_MS = 2e4;
92484
+ function cacheFile() {
92485
+ return path30.join(machineHome(), "models-dev.json");
92486
+ }
92487
+ var held2;
92488
+ function readCache() {
92489
+ const file2 = cacheFile();
92490
+ let stamp2;
92491
+ try {
92492
+ const stat = fs27.statSync(file2);
92493
+ stamp2 = `${stat.mtimeMs}:${stat.size}`;
92494
+ } catch {
92495
+ return void 0;
92496
+ }
92497
+ if (held2?.stamp === stamp2) return held2.cached;
92498
+ try {
92499
+ const data = JSON.parse(fs27.readFileSync(file2, "utf8"));
92500
+ if (!data || typeof data.limits !== "object" || !data.limits) return void 0;
92501
+ const cached2 = {
92502
+ fetchedAt: typeof data.fetchedAt === "number" ? data.fetchedAt : 0,
92503
+ limits: data.limits
92504
+ };
92505
+ held2 = { stamp: stamp2, cached: cached2 };
92506
+ return cached2;
92507
+ } catch {
92508
+ return void 0;
92509
+ }
92510
+ }
92511
+ function limitsIn(data) {
92512
+ const limits = {};
92513
+ if (!data || typeof data !== "object") return limits;
92514
+ for (const [provider, raw] of Object.entries(data)) {
92515
+ const models = raw?.models;
92516
+ if (!models || typeof models !== "object") continue;
92517
+ for (const [model, entry] of Object.entries(models)) {
92518
+ const context = entry?.limit?.context;
92519
+ if (typeof context === "number" && Number.isFinite(context) && context > 0) {
92520
+ limits[`${provider}/${model}`] = context;
92521
+ }
92522
+ }
92523
+ }
92524
+ return limits;
92525
+ }
92526
+ var fetching2;
92527
+ function refreshCatalog() {
92528
+ if (fetching2) return fetching2;
92529
+ const cached2 = readCache();
92530
+ if (cached2 && Date.now() - cached2.fetchedAt < FRESH_FOR_MS) return Promise.resolve();
92531
+ fetching2 = (async () => {
92532
+ try {
92533
+ const answer = await fetch(CATALOGUE, { signal: AbortSignal.timeout(ANSWER_BY_MS) });
92534
+ if (!answer.ok) return;
92535
+ const limits = limitsIn(await answer.json());
92536
+ if (Object.keys(limits).length === 0) return;
92537
+ const file2 = cacheFile();
92538
+ fs27.mkdirSync(path30.dirname(file2), { recursive: true });
92539
+ fs27.writeFileSync(file2, JSON.stringify({ fetchedAt: Date.now(), limits }));
92540
+ } catch {
92541
+ }
92542
+ })();
92543
+ return fetching2;
92544
+ }
92545
+ var PROVIDERS = {
92546
+ "claude-code": ["anthropic"],
92547
+ zcode: ["zai", "zhipuai"],
92548
+ kimi: ["moonshotai", "moonshotai-cn"],
92549
+ opencode: ["opencode"]
92550
+ };
92551
+ function spellings(model) {
92552
+ const id = model.trim().toLowerCase();
92553
+ if (!id) return [];
92554
+ const undated = id.replace(/-\d{8}$/, "");
92555
+ return [.../* @__PURE__ */ new Set([id, undated])];
92556
+ }
92557
+ function contextLimit(harness, model) {
92558
+ if (!model?.trim()) return void 0;
92559
+ const limits = readCache()?.limits;
92560
+ if (!limits) return void 0;
92561
+ const cut2 = model.lastIndexOf("/");
92562
+ if (cut2 > 0) {
92563
+ const whole = model.trim().toLowerCase();
92564
+ if (limits[whole]) return limits[whole];
92565
+ }
92566
+ const bare = cut2 > 0 ? model.slice(cut2 + 1) : model;
92567
+ const ids = spellings(bare);
92568
+ for (const provider of PROVIDERS[harness] ?? []) {
92569
+ for (const id of ids) {
92570
+ const found = limits[`${provider}/${id}`];
92571
+ if (found) return found;
92572
+ }
92573
+ }
92574
+ let widest = 0;
92575
+ for (const [key, limit] of Object.entries(limits)) {
92576
+ const id = key.slice(key.indexOf("/") + 1);
92577
+ if (ids.includes(id) && limit > widest) widest = limit;
92578
+ }
92579
+ return widest || void 0;
92580
+ }
92172
92581
 
92173
92582
  // src/ideas.ts
92174
- import fs25 from "node:fs";
92175
- import path28 from "node:path";
92176
- var ideasFileOf = (job) => path28.join(runnerHome(), "ideas", `${job.id}.json`);
92583
+ import fs28 from "node:fs";
92584
+ import path31 from "node:path";
92585
+ var ideasFileOf = (job) => path31.join(runnerHome(), "ideas", `${job.id}.json`);
92177
92586
  async function writeIdeas(job, list) {
92178
92587
  const workflows = [];
92179
92588
  let after = null;
@@ -92184,24 +92593,23 @@ async function writeIdeas(job, list) {
92184
92593
  after = page.value.next;
92185
92594
  } while (after);
92186
92595
  const file2 = ideasFileOf(job);
92187
- fs25.mkdirSync(path28.dirname(file2), { recursive: true });
92188
- fs25.writeFileSync(file2, `${JSON.stringify({ workflows, ideas: job.discussion.ideas }, null, 2)}
92596
+ fs28.mkdirSync(path31.dirname(file2), { recursive: true });
92597
+ fs28.writeFileSync(file2, `${JSON.stringify({ workflows, ideas: job.discussion.ideas }, null, 2)}
92189
92598
  `);
92190
92599
  return { file: file2 };
92191
92600
  }
92192
92601
  function readIdeas(file2) {
92193
92602
  try {
92194
- return JSON.parse(fs25.readFileSync(file2, "utf8")).ideas;
92603
+ return JSON.parse(fs28.readFileSync(file2, "utf8")).ideas;
92195
92604
  } catch {
92196
92605
  return void 0;
92197
92606
  } finally {
92198
- fs25.rmSync(file2, { force: true });
92607
+ fs28.rmSync(file2, { force: true });
92199
92608
  }
92200
92609
  }
92201
92610
 
92202
92611
  // src/jobs.ts
92203
- var WATCHED_MS = 2e3;
92204
- var QUIET_MS = 15e3;
92612
+ var FLUSH_MS = 2e3;
92205
92613
  var FLUSH_CHARS = 32 * 1024;
92206
92614
  var BATCH_EVENTS = 500;
92207
92615
  var BATCH_CHARS = 512 * 1024;
@@ -92209,6 +92617,7 @@ var EVENT_CHARS = 64 * 1024;
92209
92617
  var END_MS = 1e4;
92210
92618
  var RECONNECT_MS = [1e3, 2e3, 5e3, 1e4, 3e4];
92211
92619
  var RENEW_MS = 5 * 6e4;
92620
+ var LOG_PING_MS = 3e4;
92212
92621
  var LEASE_MS = 15 * 6e4;
92213
92622
  var RETRY_MS2 = 3e4;
92214
92623
  var KILL_GRACE_MS = 5e3;
@@ -92219,7 +92628,8 @@ var defaultDeps = (machineId2) => ({
92219
92628
  machineId: machineId2,
92220
92629
  api: api_exports,
92221
92630
  plan,
92222
- flushMs: { watched: WATCHED_MS, quiet: QUIET_MS },
92631
+ flushMs: FLUSH_MS,
92632
+ logPingMs: LOG_PING_MS,
92223
92633
  endMs: END_MS,
92224
92634
  renewMs: RENEW_MS,
92225
92635
  leaseMs: LEASE_MS,
@@ -92227,35 +92637,35 @@ var defaultDeps = (machineId2) => ({
92227
92637
  testMs: TEST_MS,
92228
92638
  stopMs: STOP_MS,
92229
92639
  watchMs: WATCH_MS,
92230
- akb: bundledAkb(),
92640
+ akb: currentAkb,
92231
92641
  runtimes: detectRuntimes
92232
92642
  });
92233
- var ownFolder = () => path29.join(runnerHome(), "work");
92643
+ var ownFolder = () => path32.join(runnerHome(), "work");
92234
92644
  function folderFor(job) {
92235
92645
  if (!job.projectDir) {
92236
- const cwd = path29.join(ownFolder(), job.id);
92237
- fs26.mkdirSync(cwd, { recursive: true });
92646
+ const cwd = path32.join(ownFolder(), job.id);
92647
+ fs29.mkdirSync(cwd, { recursive: true });
92238
92648
  return { cwd };
92239
92649
  }
92240
92650
  const real = realpath4(job.projectDir);
92241
- if (real && allowedProjects().some((root) => real === root || real.startsWith(root + path29.sep))) return { cwd: real };
92651
+ if (real && allowedProjects().some((root) => real === root || real.startsWith(root + path32.sep))) return { cwd: real };
92242
92652
  return { refused: `This Runner is not allowed to work in ${job.projectDir}.` };
92243
92653
  }
92244
92654
  function realpath4(p2) {
92245
92655
  try {
92246
- return fs26.realpathSync(p2);
92656
+ return fs29.realpathSync(p2);
92247
92657
  } catch {
92248
92658
  return null;
92249
92659
  }
92250
92660
  }
92251
- var attachmentsOf = (job) => path29.join(runnerHome(), "attachments", job.id);
92661
+ var attachmentsOf = (job) => path32.join(runnerHome(), "attachments", job.id);
92252
92662
  function writeAttachments(job) {
92253
92663
  if (!job.attachments.length) return "";
92254
92664
  const dir = attachmentsOf(job);
92255
- fs26.mkdirSync(dir, { recursive: true });
92665
+ fs29.mkdirSync(dir, { recursive: true });
92256
92666
  const files = job.attachments.map((a3) => {
92257
- const file2 = path29.join(dir, path29.basename(a3.name));
92258
- fs26.writeFileSync(file2, Buffer.from(a3.content, "base64"));
92667
+ const file2 = path32.join(dir, path32.basename(a3.name));
92668
+ fs29.writeFileSync(file2, Buffer.from(a3.content, "base64"));
92259
92669
  return file2;
92260
92670
  });
92261
92671
  return `
@@ -92292,7 +92702,7 @@ function streamOut(deps, id, lease) {
92292
92702
  let ending = false;
92293
92703
  let closed = false;
92294
92704
  let flushedAt = Date.now();
92295
- const log = { ws: null, after: null, watched: false, tries: 0, retry: void 0 };
92705
+ const log = { ws: null, after: null, watched: false, heard: 0, tries: 0, retry: void 0 };
92296
92706
  let ended2 = () => {
92297
92707
  };
92298
92708
  const stored = new Promise((resolve2) => ended2 = resolve2);
@@ -92326,7 +92736,7 @@ function streamOut(deps, id, lease) {
92326
92736
  const ws = log.ws;
92327
92737
  if (!ws || ws.readyState !== WebSocket.OPEN || log.after === null) return;
92328
92738
  const after = log.after;
92329
- const unsent2 = wire.filter((e2) => e2.seq > after);
92739
+ const unsent2 = log.watched ? wire.filter((e2) => e2.seq > after) : [];
92330
92740
  let batch = [];
92331
92741
  let chars = 0;
92332
92742
  const out = () => {
@@ -92357,7 +92767,9 @@ function streamOut(deps, id, lease) {
92357
92767
  if (closed) return ws?.close();
92358
92768
  if (!ws) return reconnect();
92359
92769
  log.ws = ws;
92770
+ log.heard = Date.now();
92360
92771
  ws.addEventListener("message", (m) => {
92772
+ log.heard = Date.now();
92361
92773
  let said;
92362
92774
  try {
92363
92775
  said = JSON.parse(String(m.data));
@@ -92368,22 +92780,23 @@ function streamOut(deps, id, lease) {
92368
92780
  log.tries = 0;
92369
92781
  log.after = Number.isInteger(said.after) ? said.after : -1;
92370
92782
  log.watched = said.watched === true;
92371
- send3();
92783
+ flush();
92372
92784
  } else if (said.type === "watched") {
92373
92785
  log.watched = said.on === true;
92374
92786
  if (log.watched) flush();
92375
92787
  } else if (said.type === "ended") ended2();
92376
92788
  else if (said.type === "stop") ask();
92377
92789
  });
92378
- ws.addEventListener("close", () => {
92379
- if (log.ws !== ws) return;
92380
- log.ws = null;
92381
- log.after = null;
92382
- reconnect();
92383
- });
92790
+ ws.addEventListener("close", () => drop(ws));
92384
92791
  ws.addEventListener("error", () => {
92385
92792
  });
92386
92793
  };
92794
+ const drop = (ws) => {
92795
+ if (log.ws !== ws) return;
92796
+ log.ws = null;
92797
+ log.after = null;
92798
+ reconnect();
92799
+ };
92387
92800
  const reconnect = () => {
92388
92801
  if (log.retry || lost || closed) return;
92389
92802
  log.retry = setTimeout(() => void connect2(), RECONNECT_MS[Math.min(log.tries++, RECONNECT_MS.length - 1)]);
@@ -92393,12 +92806,18 @@ function streamOut(deps, id, lease) {
92393
92806
  if (e2.kind === "message") messages.push(e2.data.text);
92394
92807
  pending.push(e2);
92395
92808
  size += JSON.stringify(e2.data).length;
92396
- if (size >= FLUSH_CHARS) flush();
92809
+ if (log.watched && size >= FLUSH_CHARS) flush();
92397
92810
  };
92398
- const tick = Math.min(deps.flushMs.watched, 1e3);
92399
92811
  const flusher = setInterval(() => {
92400
- if (pending.length && Date.now() - flushedAt >= (log.watched ? deps.flushMs.watched : deps.flushMs.quiet)) flush();
92401
- }, tick);
92812
+ if (log.watched && pending.length && Date.now() - flushedAt >= deps.flushMs) flush();
92813
+ }, Math.min(deps.flushMs, 1e3));
92814
+ const pinger = setInterval(() => {
92815
+ const ws = log.ws;
92816
+ if (ws?.readyState !== WebSocket.OPEN) return;
92817
+ if (Date.now() - log.heard <= deps.logPingMs * 2) return ws.send("ping");
92818
+ drop(ws);
92819
+ ws.close();
92820
+ }, deps.logPingMs);
92402
92821
  const renewer = setInterval(async () => {
92403
92822
  const renewed = await deps.api.renewJob(deps.machineId, id);
92404
92823
  if (renewed.ok && !renewed.value.renewed) return void loseLease();
@@ -92432,6 +92851,7 @@ function streamOut(deps, id, lease) {
92432
92851
  /** The rest sent and the log stored, or given up on after a while: `finish` comes after. */
92433
92852
  end: async () => {
92434
92853
  clearInterval(flusher);
92854
+ clearInterval(pinger);
92435
92855
  clearInterval(renewer);
92436
92856
  ending = !lost;
92437
92857
  flush();
@@ -92453,12 +92873,12 @@ async function runJob(id, deps, track = () => {
92453
92873
  const claim = await deps.api.claimJob(deps.machineId, id);
92454
92874
  if (!claim.ok || !claim.value.claimed) return;
92455
92875
  const job = claim.value.job;
92456
- const held3 = [];
92876
+ const held4 = [];
92457
92877
  try {
92458
- await runClaimed(job, deps, track, (dir) => held3.push(hold(dir)));
92878
+ await runClaimed(job, { ...deps, akb: deps.akb() }, track, (dir) => held4.push(hold(dir)));
92459
92879
  } finally {
92460
- for (const release2 of held3) release2();
92461
- fs26.rmSync(attachmentsOf(job), { recursive: true, force: true });
92880
+ for (const release2 of held4) release2();
92881
+ fs29.rmSync(attachmentsOf(job), { recursive: true, force: true });
92462
92882
  }
92463
92883
  }
92464
92884
  async function runClaimed(job, deps, track, keep2) {
@@ -92502,6 +92922,7 @@ async function runClaimed(job, deps, track, keep2) {
92502
92922
  ideas = wrote.file;
92503
92923
  }
92504
92924
  if (!job.flow && !job.review) {
92925
+ void refreshCatalog();
92505
92926
  const head2 = folderLines(ws) + writeAttachments(job);
92506
92927
  const file2 = writeTranscript(job, attachmentsOf(job));
92507
92928
  const transcript = file2 ? `
@@ -92538,6 +92959,7 @@ ${job.prompt}` : job.prompt;
92538
92959
  for (const task2 of job.review.tasks) {
92539
92960
  const chat = await deps.api.readChat(task2);
92540
92961
  if (chat.ok) keepCloudChat(task2, chat.value.messages);
92962
+ await keepDecisions(task2, deps.api.readDecisions);
92541
92963
  }
92542
92964
  const listed2 = await deps.api.listChats(deps.machineId);
92543
92965
  if (!listed2.ok) {
@@ -92583,7 +93005,7 @@ ${job.prompt}` : job.prompt;
92583
93005
  await stream.end();
92584
93006
  if (stream.lost()) return;
92585
93007
  const ok = end.ok || stream.asked();
92586
- const said2 = told(stream.asked() ? cutShort(report(plan3, end), stream.said()) : report(plan3, end));
93008
+ const said2 = told(stream.asked() ? cutShort(report(job, plan3, end), stream.said()) : report(job, plan3, end));
92587
93009
  if (!ok || !ws) return finish(deps, id, lease, ok ? "done" : "failed", ok ? "" : end.error ?? "", said2);
92588
93010
  return sendBack(deps, id, lease, ws, said2, () => keepChat(job, said2.reply));
92589
93011
  }
@@ -92624,7 +93046,7 @@ ${job.prompt}` : job.prompt;
92624
93046
  await stream.end();
92625
93047
  if (stream.lost()) return;
92626
93048
  const failure = stream.asked() ? void 0 : ended2.error ?? renderer.failure?.() ?? (ended2.code === 0 ? void 0 : `Exited with code ${ended2.code}.`);
92627
- const said = told(stream.asked() ? cutShort(report(plan2), stream.said()) : report(plan2));
93049
+ const said = told(stream.asked() ? cutShort(report(job, plan2), stream.said()) : report(job, plan2));
92628
93050
  if (failure || !ws) return finish(deps, id, lease, failure ? "failed" : "done", failure, said);
92629
93051
  return sendBack(deps, id, lease, ws, said, () => keepChat(job, said.reply));
92630
93052
  }
@@ -92655,11 +93077,11 @@ var stop = (child) => {
92655
93077
  setTimeout(() => child.kill("SIGKILL"), KILL_GRACE_MS).unref();
92656
93078
  };
92657
93079
  var wait2 = (ms2) => new Promise((resolve2) => setTimeout(resolve2, ms2));
92658
- var held2 = (deps, lease) => Date.now() - lease.at < deps.leaseMs;
93080
+ var held3 = (deps, lease) => Date.now() - lease.at < deps.leaseMs;
92659
93081
  async function whileOffline(deps, id, lease, attempt) {
92660
93082
  for (; ; ) {
92661
93083
  const out = await attempt();
92662
- if (!("offline" in out && out.offline) || !held2(deps, lease)) return out;
93084
+ if (!("offline" in out && out.offline) || !held3(deps, lease)) return out;
92663
93085
  await wait2(deps.retryMs);
92664
93086
  const renewed = await deps.api.renewJob(deps.machineId, id);
92665
93087
  if (renewed.ok && renewed.value.renewed) lease.at = Date.now();
@@ -92706,8 +93128,8 @@ async function runTest(job, deps) {
92706
93128
  const report2 = (await deps.runtimes()).find((r2) => r2.name === job.runtime);
92707
93129
  if (!report2?.installed) return finish2("failed", "not_installed");
92708
93130
  if (report2.loggedIn === false) return finish2("failed", "signed_out");
92709
- const cwd = path29.join(ownFolder(), "test");
92710
- fs26.mkdirSync(cwd, { recursive: true });
93131
+ const cwd = path32.join(ownFolder(), "test");
93132
+ fs29.mkdirSync(cwd, { recursive: true });
92711
93133
  const run2 = deps.plan(job.runtime, job.prompt, cwd, null, job.model, settingsOf(job));
92712
93134
  const startedAt = Date.now();
92713
93135
  if (run2.converse) {
@@ -92768,8 +93190,9 @@ async function runTest(job, deps) {
92768
93190
  if (failure) return finish2("failed", failure.slice(0, 300), ms2);
92769
93191
  return finish2("done", "", ms2);
92770
93192
  }
92771
- function report(run2, turn) {
93193
+ function report(job, run2, turn) {
92772
93194
  const context = turn ? turn.context : run2.renderer?.context?.();
93195
+ const limit = context?.limit ?? contextLimit(job.runtime, run2.model?.() ?? job.model ?? void 0);
92773
93196
  const usage = turn ? turn.usage : run2.renderer?.usage?.();
92774
93197
  const costUsd = turn ? turn.costUsd : run2.renderer?.costUsd?.();
92775
93198
  return {
@@ -92777,7 +93200,7 @@ function report(run2, turn) {
92777
93200
  session: run2.session(),
92778
93201
  ...usage ? { usage } : {},
92779
93202
  ...costUsd !== void 0 ? { costUsd } : {},
92780
- ...context?.used !== void 0 && context.limit ? { context: { used: context.used, limit: context.limit } } : {}
93203
+ ...context?.used !== void 0 && limit ? { context: { used: context.used, limit } } : {}
92781
93204
  };
92782
93205
  }
92783
93206
  var cutShort = (said, text3) => ({ ...said, reply: said.reply || text3 || void 0, stopped: true });
@@ -92878,10 +93301,15 @@ function startRunner(options) {
92878
93301
  const base = options.deps ?? defaultDeps(registration.machineId);
92879
93302
  return { ...base, runtimes: () => base.runtimes().then(redetected) };
92880
93303
  };
93304
+ const register2 = async () => {
93305
+ const answer = await register(options.notify ? { ...registration, notify: options.notify() } : registration);
93306
+ if (answer.ok) void followAkb(answer.value.akb);
93307
+ return answer;
93308
+ };
92881
93309
  const redetected = async (found) => {
92882
93310
  if (closed || !registration || JSON.stringify(found) === JSON.stringify(registration.runtimes)) return found;
92883
93311
  registration = { ...registration, runtimes: found };
92884
- await register(options.notify ? { ...registration, notify: options.notify() } : registration);
93312
+ await register2();
92885
93313
  return found;
92886
93314
  };
92887
93315
  const idle2 = () => running.size ? t.running(running.size) : t.connected(registration.machineName);
@@ -92910,6 +93338,7 @@ function startRunner(options) {
92910
93338
  if (sweeping || closed || !registration) return;
92911
93339
  sweeping = true;
92912
93340
  try {
93341
+ sweepAkb();
92913
93342
  await sweepCache(registration.machineId);
92914
93343
  } catch (e2) {
92915
93344
  console.error(`runner: the cache was not cleaned: ${e2 instanceof Error ? e2.message : String(e2)}`);
@@ -92934,12 +93363,12 @@ function startRunner(options) {
92934
93363
  swept = true;
92935
93364
  void sweep();
92936
93365
  }
92937
- const answer = await register(options.notify ? { ...registration, notify: options.notify() } : registration);
93366
+ const answer = await register2();
92938
93367
  if (closed) return;
92939
93368
  if (!answer.ok) {
92940
93369
  if (answer.code === "runner_elsewhere") {
92941
- const held3 = await readRunner();
92942
- return finish2({ reason: "elsewhere", machine: held3.ok && held3.value.runner?.machineName || "?" });
93370
+ const held4 = await readRunner();
93371
+ return finish2({ reason: "elsewhere", machine: held4.ok && held4.value.runner?.machineName || "?" });
92943
93372
  }
92944
93373
  if (answer.code === "runner_outdated") return finish2({ reason: "outdated" });
92945
93374
  if (answer.code) return finish2({ reason: "refused", message: answer.error });
@@ -93024,7 +93453,7 @@ function startRunner(options) {
93024
93453
  if (folder && "refused" in folder) return;
93025
93454
  const ws = openTaskFolder(job, folder?.cwd ?? null);
93026
93455
  const card = akbCardOf(ws);
93027
- if (card) await stopLeftBehind(deps().akb, ws, card, deps().stopMs);
93456
+ if (card) await stopLeftBehind(deps().akb(), ws, card, deps().stopMs);
93028
93457
  } catch (e2) {
93029
93458
  console.error(`runner: the runs left on job ${job.id}'s card were not stopped: ${e2 instanceof Error ? e2.message : String(e2)}`);
93030
93459
  }
@@ -93080,13 +93509,13 @@ function startRunner(options) {
93080
93509
 
93081
93510
  // src/desktop.ts
93082
93511
  import { spawnSync as spawnSync5 } from "node:child_process";
93083
- import fs27 from "node:fs";
93084
- import path30 from "node:path";
93512
+ import fs30 from "node:fs";
93513
+ import path33 from "node:path";
93085
93514
  import readline from "node:readline";
93086
93515
 
93087
93516
  // src/signin.ts
93088
93517
  import { spawn as spawn5 } from "node:child_process";
93089
- import crypto4 from "node:crypto";
93518
+ import crypto5 from "node:crypto";
93090
93519
  import http from "node:http";
93091
93520
  var WAIT_MS = 10 * 60 * 1e3;
93092
93521
  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";
@@ -93111,8 +93540,8 @@ var PAGE = (outcome, lang) => {
93111
93540
  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>`;
93112
93541
  };
93113
93542
  async function signIn(options = {}) {
93114
- const verifier = base64url(crypto4.randomBytes(32));
93115
- const challenge = base64url(crypto4.createHash("sha256").update(verifier).digest());
93543
+ const verifier = base64url(crypto5.randomBytes(32));
93544
+ const challenge = base64url(crypto5.createHash("sha256").update(verifier).digest());
93116
93545
  let finish2 = () => {
93117
93546
  };
93118
93547
  const answered = new Promise((resolve2) => finish2 = resolve2);
@@ -93261,12 +93690,12 @@ async function runDesktop(tell2) {
93261
93690
  const readProfile2 = async () => {
93262
93691
  const session = readSession();
93263
93692
  const profile = await readProfile();
93264
- const held3 = profile.ok ? profile.value.session : {};
93693
+ const held4 = profile.ok ? profile.value.session : {};
93265
93694
  emit({
93266
93695
  type: "account",
93267
- name: held3.name || held3.handle || session?.name || session?.handle || "",
93268
- email: held3.email || session?.email || "",
93269
- avatar: held3.avatarUrl || session?.avatarUrl || ""
93696
+ name: held4.name || held4.handle || session?.name || session?.handle || "",
93697
+ email: held4.email || session?.email || "",
93698
+ avatar: held4.avatarUrl || session?.avatarUrl || ""
93270
93699
  });
93271
93700
  };
93272
93701
  const readPlan2 = async () => {
@@ -93335,8 +93764,8 @@ async function runDesktop(tell2) {
93335
93764
  const project = command.project;
93336
93765
  const why = refusal(command.path);
93337
93766
  if (why) return emit({ type: "folderRefused", why, project });
93338
- const real = fs27.realpathSync(command.path);
93339
- const added = await addFolder(id, path30.basename(real) || real, real, project);
93767
+ const real = fs30.realpathSync(command.path);
93768
+ const added = await addFolder(id, path33.basename(real) || real, real, project);
93340
93769
  if (!added.ok) {
93341
93770
  const taken = added.code === "folder_taken";
93342
93771
  return emit({ type: "folderRefused", why: taken ? "taken" : "failed", project, ...taken ? { taken: added.project } : {} });
@@ -93345,9 +93774,9 @@ async function runDesktop(tell2) {
93345
93774
  return readFolders();
93346
93775
  }
93347
93776
  case "removeFolder": {
93348
- const held3 = folders2.find((f2) => f2.project === command.project);
93777
+ const held4 = folders2.find((f2) => f2.project === command.project);
93349
93778
  const removed = await removeFolder(id, command.project);
93350
- if (removed.ok && held3) for (const dir of disallow(held3.path)) clearAkb(dir);
93779
+ if (removed.ok && held4) for (const dir of disallow(held4.path)) clearAkb(dir);
93351
93780
  return readFolders();
93352
93781
  }
93353
93782
  case "folderNotify":