wildcrane-runner 0.6.5 → 0.6.8
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/README.md +10 -14
- package/dist/akb/bin/ai4kanban.mjs +2 -21
- package/dist/akb/dist/kanban.mjs +2092 -2313
- package/dist/akb/package.json +1 -1
- package/dist/launcher.mjs +69 -34
- package/dist/runner.mjs +743 -672
- package/package.json +1 -1
package/dist/runner.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// wildcrane-runner 0.6.
|
|
1
|
+
// wildcrane-runner 0.6.8 — 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;
|
|
@@ -7572,13 +7572,13 @@ var require_react_dom_server_node_production = __commonJS({
|
|
|
7572
7572
|
var target = currentView;
|
|
7573
7573
|
0 < writtenBytes && (target = currentView.subarray(writtenBytes));
|
|
7574
7574
|
target = textEncoder.encodeInto(chunk, target);
|
|
7575
|
-
var
|
|
7575
|
+
var read2 = target.read;
|
|
7576
7576
|
writtenBytes += target.written;
|
|
7577
|
-
|
|
7577
|
+
read2 < chunk.length && (writeToDestination(
|
|
7578
7578
|
destination,
|
|
7579
7579
|
currentView.subarray(0, writtenBytes)
|
|
7580
7580
|
), currentView = new Uint8Array(4096), writtenBytes = textEncoder.encodeInto(
|
|
7581
|
-
chunk.slice(
|
|
7581
|
+
chunk.slice(read2),
|
|
7582
7582
|
currentView
|
|
7583
7583
|
).written);
|
|
7584
7584
|
4096 === writtenBytes && (writeToDestination(destination, currentView), currentView = new Uint8Array(4096), writtenBytes = 0);
|
|
@@ -21328,13 +21328,13 @@ var require_react_dom_server_node_development = __commonJS({
|
|
|
21328
21328
|
var target = currentView;
|
|
21329
21329
|
0 < writtenBytes && (target = currentView.subarray(writtenBytes));
|
|
21330
21330
|
target = textEncoder.encodeInto(chunk, target);
|
|
21331
|
-
var
|
|
21331
|
+
var read2 = target.read;
|
|
21332
21332
|
writtenBytes += target.written;
|
|
21333
|
-
|
|
21333
|
+
read2 < chunk.length && (writeToDestination(
|
|
21334
21334
|
destination,
|
|
21335
21335
|
currentView.subarray(0, writtenBytes)
|
|
21336
21336
|
), currentView = new Uint8Array(4096), writtenBytes = textEncoder.encodeInto(
|
|
21337
|
-
chunk.slice(
|
|
21337
|
+
chunk.slice(read2),
|
|
21338
21338
|
currentView
|
|
21339
21339
|
).written);
|
|
21340
21340
|
4096 === writtenBytes && (writeToDestination(destination, currentView), currentView = new Uint8Array(4096), writtenBytes = 0);
|
|
@@ -41256,8 +41256,8 @@ var require_JSXTransformer = __commonJS({
|
|
|
41256
41256
|
}
|
|
41257
41257
|
if (this.isAutomaticRuntime) {
|
|
41258
41258
|
if (this.importProcessor) {
|
|
41259
|
-
for (const [
|
|
41260
|
-
prefix += `var ${resolvedName} = require("${
|
|
41259
|
+
for (const [path36, resolvedName] of Object.entries(this.cjsAutomaticModuleNameResolutions)) {
|
|
41260
|
+
prefix += `var ${resolvedName} = require("${path36}");`;
|
|
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
|
|
41454
|
-
if (!this.cjsAutomaticModuleNameResolutions[
|
|
41455
|
-
this.cjsAutomaticModuleNameResolutions[
|
|
41453
|
+
const path36 = this.jsxImportSource + importPathSuffix;
|
|
41454
|
+
if (!this.cjsAutomaticModuleNameResolutions[path36]) {
|
|
41455
|
+
this.cjsAutomaticModuleNameResolutions[path36] = this.importProcessor.getFreeIdentifierForPath(path36);
|
|
41456
41456
|
}
|
|
41457
|
-
return `${this.cjsAutomaticModuleNameResolutions[
|
|
41457
|
+
return `${this.cjsAutomaticModuleNameResolutions[path36]}.${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 [
|
|
41893
|
+
for (const [path36, 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(
|
|
41903
|
+
this.importsToReplace.set(path36, "");
|
|
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 [
|
|
41911
|
+
for (const [path36, 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(
|
|
41921
|
+
this.importsToReplace.set(path36, `require('${path36}');`);
|
|
41922
41922
|
continue;
|
|
41923
41923
|
}
|
|
41924
|
-
const primaryImportName = this.getFreeIdentifierForPath(
|
|
41924
|
+
const primaryImportName = this.getFreeIdentifierForPath(path36);
|
|
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(
|
|
41929
|
+
secondaryImportName = wildcardNames.length > 0 ? wildcardNames[0] : this.getFreeIdentifierForPath(path36);
|
|
41930
41930
|
}
|
|
41931
|
-
let requireCode = `var ${primaryImportName} = require('${
|
|
41931
|
+
let requireCode = `var ${primaryImportName} = require('${path36}');`;
|
|
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(
|
|
41959
|
+
this.importsToReplace.set(path36, 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(
|
|
41969
|
-
const components =
|
|
41968
|
+
getFreeIdentifierForPath(path36) {
|
|
41969
|
+
const components = path36.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
|
|
42015
|
-
const importInfo = this.getImportInfo(
|
|
42014
|
+
const path36 = this.tokens.stringValueAtIndex(index);
|
|
42015
|
+
const importInfo = this.getImportInfo(path36);
|
|
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
|
|
42083
|
-
const importInfo = this.getImportInfo(
|
|
42082
|
+
const path36 = this.tokens.stringValueAtIndex(index);
|
|
42083
|
+
const importInfo = this.getImportInfo(path36);
|
|
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
|
|
42099
|
-
const importInfo = this.getImportInfo(
|
|
42098
|
+
const path36 = this.tokens.stringValueAtIndex(index);
|
|
42099
|
+
const importInfo = this.getImportInfo(path36);
|
|
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(
|
|
42140
|
-
const existingInfo = this.importInfoByPath.get(
|
|
42139
|
+
getImportInfo(path36) {
|
|
42140
|
+
const existingInfo = this.importInfoByPath.get(path36);
|
|
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(
|
|
42153
|
+
this.importInfoByPath.set(path36, 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
|
|
42734
|
-
return makeUrl("file:", "", match[1] || "", "", isAbsolutePath(
|
|
42733
|
+
const path36 = match[2];
|
|
42734
|
+
return makeUrl("file:", "", match[1] || "", "", isAbsolutePath(path36) ? path36 : "/" + path36, match[3] || "", match[4] || "");
|
|
42735
42735
|
}
|
|
42736
|
-
function makeUrl(scheme, user, host, port,
|
|
42736
|
+
function makeUrl(scheme, user, host, port, path36, query, hash) {
|
|
42737
42737
|
return {
|
|
42738
42738
|
scheme,
|
|
42739
42739
|
user,
|
|
42740
42740
|
host,
|
|
42741
42741
|
port,
|
|
42742
|
-
path:
|
|
42742
|
+
path: path36,
|
|
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(
|
|
42773
|
-
if (
|
|
42774
|
-
return
|
|
42775
|
-
const index =
|
|
42776
|
-
return
|
|
42772
|
+
function stripPathFilename(path36) {
|
|
42773
|
+
if (path36.endsWith("/.."))
|
|
42774
|
+
return path36;
|
|
42775
|
+
const index = path36.lastIndexOf("/");
|
|
42776
|
+
return path36.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
|
|
42814
|
+
let path36 = "";
|
|
42815
42815
|
for (let i = 1; i < pointer; i++) {
|
|
42816
|
-
|
|
42816
|
+
path36 += "/" + pieces[i];
|
|
42817
42817
|
}
|
|
42818
|
-
if (!
|
|
42819
|
-
|
|
42818
|
+
if (!path36 || addTrailingSlash && !path36.endsWith("/..")) {
|
|
42819
|
+
path36 += "/";
|
|
42820
42820
|
}
|
|
42821
|
-
url.path =
|
|
42821
|
+
url.path = path36;
|
|
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
|
|
42863
|
-
if (!
|
|
42862
|
+
const path36 = url.path.slice(1);
|
|
42863
|
+
if (!path36)
|
|
42864
42864
|
return queryHash || ".";
|
|
42865
|
-
if (isRelative(base || input) && !isRelative(
|
|
42866
|
-
return "./" +
|
|
42865
|
+
if (isRelative(base || input) && !isRelative(path36)) {
|
|
42866
|
+
return "./" + path36 + queryHash;
|
|
42867
42867
|
}
|
|
42868
|
-
return
|
|
42868
|
+
return path36 + 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(
|
|
42968
|
-
if (!
|
|
42969
|
-
const index =
|
|
42970
|
-
return
|
|
42967
|
+
function stripFilename(path36) {
|
|
42968
|
+
if (!path36) return "";
|
|
42969
|
+
const index = path36.lastIndexOf("/");
|
|
42970
|
+
return path36.slice(0, index + 1);
|
|
42971
42971
|
}
|
|
42972
42972
|
function resolver(mapUrl, sourceRoot) {
|
|
42973
42973
|
const from = stripFilename(mapUrl);
|
|
@@ -44175,9 +44175,9 @@ var require_util2 = __commonJS({
|
|
|
44175
44175
|
/** @class */
|
|
44176
44176
|
(function(_super) {
|
|
44177
44177
|
__extends(VError2, _super);
|
|
44178
|
-
function VError2(
|
|
44178
|
+
function VError2(path36, message) {
|
|
44179
44179
|
var _this = _super.call(this, message) || this;
|
|
44180
|
-
_this.path =
|
|
44180
|
+
_this.path = path36;
|
|
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(
|
|
44240
|
+
DetailContext2.prototype.getError = function(path36) {
|
|
44241
44241
|
var msgParts = [];
|
|
44242
44242
|
for (var i = this._propNames.length - 1; i >= 0; i--) {
|
|
44243
44243
|
var p2 = this._propNames[i];
|
|
44244
|
-
|
|
44244
|
+
path36 += typeof p2 === "number" ? "[" + p2 + "]" : p2 ? "." + p2 : "";
|
|
44245
44245
|
var m = this._messages[i];
|
|
44246
44246
|
if (m) {
|
|
44247
|
-
msgParts.push(
|
|
44247
|
+
msgParts.push(path36 + " " + m);
|
|
44248
44248
|
}
|
|
44249
44249
|
}
|
|
44250
|
-
return new VError(
|
|
44250
|
+
return new VError(path36, msgParts.join("; "));
|
|
44251
44251
|
};
|
|
44252
|
-
DetailContext2.prototype.getErrorDetail = function(
|
|
44252
|
+
DetailContext2.prototype.getErrorDetail = function(path36) {
|
|
44253
44253
|
var details = [];
|
|
44254
44254
|
for (var i = this._propNames.length - 1; i >= 0; i--) {
|
|
44255
44255
|
var p2 = this._propNames[i];
|
|
44256
|
-
|
|
44256
|
+
path36 += typeof p2 === "number" ? "[" + p2 + "]" : p2 ? "." + p2 : "";
|
|
44257
44257
|
var message = this._messages[i];
|
|
44258
44258
|
if (message) {
|
|
44259
|
-
details.push({ path:
|
|
44259
|
+
details.push({ path: path36, 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(
|
|
45073
|
-
this._path =
|
|
45072
|
+
Checker2.prototype.setReportedPath = function(path36) {
|
|
45073
|
+
this._path = path36;
|
|
45074
45074
|
};
|
|
45075
45075
|
Checker2.prototype.check = function(value) {
|
|
45076
45076
|
return this._doCheck(this.checkerPlain, value);
|
|
@@ -50503,9 +50503,9 @@ var require_CJSImportTransformer = __commonJS({
|
|
|
50503
50503
|
if (shouldElideImport) {
|
|
50504
50504
|
this.tokens.removeToken();
|
|
50505
50505
|
} else {
|
|
50506
|
-
const
|
|
50507
|
-
this.tokens.replaceTokenTrimmingLeftWhitespace(this.importProcessor.claimImportCode(
|
|
50508
|
-
this.tokens.appendCode(this.importProcessor.claimImportCode(
|
|
50506
|
+
const path36 = this.tokens.stringValue();
|
|
50507
|
+
this.tokens.replaceTokenTrimmingLeftWhitespace(this.importProcessor.claimImportCode(path36));
|
|
50508
|
+
this.tokens.appendCode(this.importProcessor.claimImportCode(path36));
|
|
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
|
|
51089
|
-
this.tokens.replaceTokenTrimmingLeftWhitespace(this.importProcessor.claimImportCode(
|
|
51088
|
+
const path36 = this.tokens.stringValue();
|
|
51089
|
+
this.tokens.replaceTokenTrimmingLeftWhitespace(this.importProcessor.claimImportCode(path36));
|
|
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
|
|
51104
|
-
this.tokens.replaceTokenTrimmingLeftWhitespace(this.importProcessor.claimImportCode(
|
|
51103
|
+
const path36 = this.tokens.stringValue();
|
|
51104
|
+
this.tokens.replaceTokenTrimmingLeftWhitespace(this.importProcessor.claimImportCode(path36));
|
|
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,
|
|
80748
|
+
getPart = (classPartObject, path36) => {
|
|
80749
80749
|
let current = classPartObject;
|
|
80750
|
-
const parts =
|
|
80750
|
+
const parts = path36.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];
|
|
@@ -84239,12 +84239,6 @@ function writeSession(session) {
|
|
|
84239
84239
|
`, { mode: 384 });
|
|
84240
84240
|
fs.renameSync(tmp, sessionFile());
|
|
84241
84241
|
}
|
|
84242
|
-
function clearSession() {
|
|
84243
|
-
try {
|
|
84244
|
-
fs.rmSync(sessionFile());
|
|
84245
|
-
} catch {
|
|
84246
|
-
}
|
|
84247
|
-
}
|
|
84248
84242
|
async function accessToken() {
|
|
84249
84243
|
const held4 = readSession();
|
|
84250
84244
|
if (!held4) return { ok: false, reason: "signed-out" };
|
|
@@ -84384,8 +84378,8 @@ function machineId() {
|
|
|
84384
84378
|
var machineName = () => os2.hostname().replace(/\.local$/, "");
|
|
84385
84379
|
|
|
84386
84380
|
// src/i18n.ts
|
|
84387
|
-
var ZH_HOLDER = { "claude-code": "Claude Code", codex: "Codex", terminal: "\u672C\u673A\u7EC8\u7AEF"
|
|
84388
|
-
var EN_HOLDER = { "claude-code": "Claude Code", codex: "Codex", terminal: "the terminal"
|
|
84381
|
+
var ZH_HOLDER = { "claude-code": "Claude Code", codex: "Codex", terminal: "\u672C\u673A\u7EC8\u7AEF" };
|
|
84382
|
+
var EN_HOLDER = { "claude-code": "Claude Code", codex: "Codex", terminal: "the terminal" };
|
|
84389
84383
|
var ZH = {
|
|
84390
84384
|
signIn: (url) => `\u8BF7\u5728\u6D4F\u89C8\u5668\u4E2D\u767B\u5F55 WildCrane\uFF1A
|
|
84391
84385
|
${url}`,
|
|
@@ -84404,13 +84398,7 @@ ${url}`,
|
|
|
84404
84398
|
const who = holder ? ZH_HOLDER[holder] : "\u672C\u673A\u53E6\u4E00\u4E2A\u7A0B\u5E8F";
|
|
84405
84399
|
return `${who}\u5DF2\u5728\u8FD0\u884C\u4E00\u4E2A WildCrane \u5B9E\u4F8B\uFF0C\u8D1F\u8D23\u63A5\u6536\u6240\u6709\u8FD0\u884C\u4EFB\u52A1\u3002\u5F53\u524D\u5B9E\u4F8B\u5DF2\u6682\u505C\uFF0C${who}\u5173\u95ED\u540E\u5C06\u7531\u5F53\u524D\u5B9E\u4F8B\u63A5\u66FF\u3002`;
|
|
84406
84400
|
},
|
|
84407
|
-
stopped: () => "\u5DF2\u505C\u6B62"
|
|
84408
|
-
reviewTitle: () => "\u5F85\u4F60\u5BA1\u6838",
|
|
84409
|
-
reviewBody: (task) => `\u300C${task}\u300D\u5F85\u5BA1\u6838`,
|
|
84410
|
-
doneTitle: () => "\u4EFB\u52A1\u5DF2\u5B8C\u6210",
|
|
84411
|
-
failedTitle: () => "\u4EFB\u52A1\u5931\u8D25",
|
|
84412
|
-
commentTitle: (task) => `\u300C${task}\u300D\u6709\u65B0\u8BC4\u8BBA`,
|
|
84413
|
-
commentBody: (who, text3) => `${who}\uFF1A${text3}`
|
|
84401
|
+
stopped: () => "\u5DF2\u505C\u6B62"
|
|
84414
84402
|
};
|
|
84415
84403
|
var EN = {
|
|
84416
84404
|
signIn: (url) => `Sign in to WildCrane in your browser:
|
|
@@ -84430,13 +84418,7 @@ ${url}`,
|
|
|
84430
84418
|
const who = holder ? EN_HOLDER[holder] : "another app on this computer";
|
|
84431
84419
|
return `${who[0].toUpperCase()}${who.slice(1)} is already running a WildCrane instance that takes all run tasks. This instance is paused and takes over when ${who} closes.`;
|
|
84432
84420
|
},
|
|
84433
|
-
stopped: () => "Stopped"
|
|
84434
|
-
reviewTitle: () => "Needs your review",
|
|
84435
|
-
reviewBody: (task) => `"${task}" is ready for review`,
|
|
84436
|
-
doneTitle: () => "Task finished",
|
|
84437
|
-
failedTitle: () => "Task failed",
|
|
84438
|
-
commentTitle: (task) => `New comment on ${task}`,
|
|
84439
|
-
commentBody: (who, text3) => `${who}: ${text3}`
|
|
84421
|
+
stopped: () => "Stopped"
|
|
84440
84422
|
};
|
|
84441
84423
|
function isChinese(env2 = process.env) {
|
|
84442
84424
|
const lang = env2.LC_ALL || env2.LC_MESSAGES || env2.LANG || Intl.DateTimeFormat().resolvedOptions().locale;
|
|
@@ -84453,11 +84435,12 @@ function status(line) {
|
|
|
84453
84435
|
}
|
|
84454
84436
|
|
|
84455
84437
|
// src/protocol.ts
|
|
84456
|
-
var VERSION = true ? "0.6.
|
|
84457
|
-
var AKB_VERSION = true ? "0.11.
|
|
84458
|
-
var AKB_CONTRACT = true ?
|
|
84438
|
+
var VERSION = true ? "0.6.8" : "0.0.0";
|
|
84439
|
+
var AKB_VERSION = true ? "0.11.7" : "0.0.0";
|
|
84440
|
+
var AKB_CONTRACT = true ? 3 : 0;
|
|
84459
84441
|
var EXIT_REFUSED = 10;
|
|
84460
84442
|
var EXIT_OUTDATED = 11;
|
|
84443
|
+
var EXIT_UPDATE = 12;
|
|
84461
84444
|
|
|
84462
84445
|
// src/runtimes.ts
|
|
84463
84446
|
import { spawn as spawn2 } from "node:child_process";
|
|
@@ -85309,10 +85292,10 @@ function findRollout(threadId) {
|
|
|
85309
85292
|
}
|
|
85310
85293
|
for (const name of names2) {
|
|
85311
85294
|
if (!name.startsWith("rollout-") || !name.endsWith(tail)) continue;
|
|
85312
|
-
const
|
|
85295
|
+
const path36 = join(dir, name);
|
|
85313
85296
|
try {
|
|
85314
|
-
const at2 = statSync(
|
|
85315
|
-
if (!newest2 || at2 > newest2.at) newest2 = { path:
|
|
85297
|
+
const at2 = statSync(path36).mtimeMs;
|
|
85298
|
+
if (!newest2 || at2 > newest2.at) newest2 = { path: path36, at: at2 };
|
|
85316
85299
|
} catch {
|
|
85317
85300
|
}
|
|
85318
85301
|
}
|
|
@@ -85320,11 +85303,11 @@ function findRollout(threadId) {
|
|
|
85320
85303
|
return newest2?.path;
|
|
85321
85304
|
}
|
|
85322
85305
|
function readCodexRunFacts(threadId) {
|
|
85323
|
-
const
|
|
85324
|
-
if (!
|
|
85306
|
+
const path36 = findRollout(threadId);
|
|
85307
|
+
if (!path36) return void 0;
|
|
85325
85308
|
let raw;
|
|
85326
85309
|
try {
|
|
85327
|
-
raw = readFileSync(
|
|
85310
|
+
raw = readFileSync(path36, "utf8");
|
|
85328
85311
|
} catch {
|
|
85329
85312
|
return void 0;
|
|
85330
85313
|
}
|
|
@@ -85432,8 +85415,8 @@ function renderCompleted(item) {
|
|
|
85432
85415
|
const changes = Array.isArray(item.changes) ? item.changes : [];
|
|
85433
85416
|
return changes.map((raw) => {
|
|
85434
85417
|
const change = obj(raw);
|
|
85435
|
-
const
|
|
85436
|
-
return
|
|
85418
|
+
const path36 = str(change.path);
|
|
85419
|
+
return path36 ? `\u23FA ${str(change.kind) || "change"}(${path36})
|
|
85437
85420
|
` : "";
|
|
85438
85421
|
}).join("");
|
|
85439
85422
|
}
|
|
@@ -85681,10 +85664,10 @@ function readKimiRunFacts(sessionId) {
|
|
|
85681
85664
|
const total = { input: 0, cacheCreation: 0, cacheRead: 0, output: 0 };
|
|
85682
85665
|
let model;
|
|
85683
85666
|
let holding = 0;
|
|
85684
|
-
for (const { path:
|
|
85667
|
+
for (const { path: path36, main: main2 } of wireFiles(entry.sessionDir)) {
|
|
85685
85668
|
let raw;
|
|
85686
85669
|
try {
|
|
85687
|
-
raw = readFileSync2(
|
|
85670
|
+
raw = readFileSync2(path36, "utf8");
|
|
85688
85671
|
} catch {
|
|
85689
85672
|
continue;
|
|
85690
85673
|
}
|
|
@@ -85940,8 +85923,8 @@ function createTail(log) {
|
|
|
85940
85923
|
// ../cli/package.json
|
|
85941
85924
|
var package_default = {
|
|
85942
85925
|
name: "wildcrane",
|
|
85943
|
-
version: "0.11.
|
|
85944
|
-
akbContract:
|
|
85926
|
+
version: "0.11.7",
|
|
85927
|
+
akbContract: 3,
|
|
85945
85928
|
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
85929
|
keywords: [
|
|
85947
85930
|
"kanban",
|
|
@@ -86002,8 +85985,8 @@ var CLIENT_CAPABILITIES = {
|
|
|
86002
85985
|
};
|
|
86003
85986
|
function whereHint(update2, title) {
|
|
86004
85987
|
const locations = Array.isArray(update2.locations) ? update2.locations : [];
|
|
86005
|
-
const
|
|
86006
|
-
return
|
|
85988
|
+
const path36 = str(obj(locations[0]).path);
|
|
85989
|
+
return path36 && !title.includes(path36) ? hint(path36) : "";
|
|
86007
85990
|
}
|
|
86008
85991
|
function saidBy(update2) {
|
|
86009
85992
|
const content = Array.isArray(update2.content) ? update2.content : [];
|
|
@@ -86090,7 +86073,7 @@ function createAcpClient(options = {}) {
|
|
|
86090
86073
|
async function oneTurn(io, options) {
|
|
86091
86074
|
const tail = createTail(io.log);
|
|
86092
86075
|
const events = createEventCollector();
|
|
86093
|
-
const
|
|
86076
|
+
const emit = () => {
|
|
86094
86077
|
for (const e2 of events.events()) io.event?.(e2);
|
|
86095
86078
|
};
|
|
86096
86079
|
let live = false;
|
|
@@ -86104,21 +86087,21 @@ async function oneTurn(io, options) {
|
|
|
86104
86087
|
if (live) {
|
|
86105
86088
|
update(obj(msg.params).update, tail, (usd) => costUsd = usd, (window2) => context = window2);
|
|
86106
86089
|
events.update(obj(msg.params).update);
|
|
86107
|
-
|
|
86090
|
+
emit();
|
|
86108
86091
|
}
|
|
86109
86092
|
return;
|
|
86110
86093
|
}
|
|
86111
86094
|
if (msg.id === void 0) return;
|
|
86112
86095
|
if (msg.method === "session/request_permission") {
|
|
86113
86096
|
rpc.reply(msg.id, decide(obj(msg.params), tail, events));
|
|
86114
|
-
|
|
86097
|
+
emit();
|
|
86115
86098
|
return;
|
|
86116
86099
|
}
|
|
86117
86100
|
if (msg.method === "cursor/update_todos") {
|
|
86118
86101
|
const params = obj(msg.params);
|
|
86119
86102
|
if (live) {
|
|
86120
86103
|
events.todos(params.todos, params.merge === true);
|
|
86121
|
-
|
|
86104
|
+
emit();
|
|
86122
86105
|
}
|
|
86123
86106
|
rpc.reply(msg.id, {});
|
|
86124
86107
|
return;
|
|
@@ -86149,7 +86132,7 @@ async function oneTurn(io, options) {
|
|
|
86149
86132
|
io.gotResumeId(sessionId, true);
|
|
86150
86133
|
io.log(RESTARTED);
|
|
86151
86134
|
events.log(RESTARTED);
|
|
86152
|
-
|
|
86135
|
+
emit();
|
|
86153
86136
|
}
|
|
86154
86137
|
} else {
|
|
86155
86138
|
const fresh = await newSession(rpc, io.cwd, mcpServers);
|
|
@@ -86181,10 +86164,10 @@ async function oneTurn(io, options) {
|
|
|
86181
86164
|
io.log(`[error] ${why}
|
|
86182
86165
|
`);
|
|
86183
86166
|
events.error(why);
|
|
86184
|
-
|
|
86167
|
+
emit();
|
|
86185
86168
|
return { ok: false, result, error: why, usage, context, costUsd };
|
|
86186
86169
|
}
|
|
86187
|
-
|
|
86170
|
+
emit();
|
|
86188
86171
|
return { ok: true, result, usage, context, costUsd };
|
|
86189
86172
|
} catch (e2) {
|
|
86190
86173
|
const error = e2 instanceof Error ? e2.message : String(e2);
|
|
@@ -86192,7 +86175,7 @@ async function oneTurn(io, options) {
|
|
|
86192
86175
|
io.log(`[error] ${error}
|
|
86193
86176
|
`);
|
|
86194
86177
|
events.error(error);
|
|
86195
|
-
|
|
86178
|
+
emit();
|
|
86196
86179
|
return { ok: false, result, error, usage: void 0, costUsd };
|
|
86197
86180
|
}
|
|
86198
86181
|
}
|
|
@@ -86473,8 +86456,8 @@ async function tokensOf(rpc, sessionId) {
|
|
|
86473
86456
|
}
|
|
86474
86457
|
async function contextOf(rpc, sessionId) {
|
|
86475
86458
|
try {
|
|
86476
|
-
const
|
|
86477
|
-
const state = obj(
|
|
86459
|
+
const read2 = await rpc.call("session/read", { sessionId, messageLimit: 1 });
|
|
86460
|
+
const state = obj(read2.projection);
|
|
86478
86461
|
const used = num(state.contextUsed);
|
|
86479
86462
|
const limit = num(state.contextWindow);
|
|
86480
86463
|
return used > 0 ? { used, limit: limit > 0 ? limit : void 0 } : void 0;
|
|
@@ -86895,15 +86878,15 @@ var SESSIONS_LOCK = "sessions.lock";
|
|
|
86895
86878
|
var INDEX_LOCK = "index.lock";
|
|
86896
86879
|
var UI_CONFIG_FILE = "ui.config.json";
|
|
86897
86880
|
function realPathOf(dir) {
|
|
86898
|
-
const
|
|
86881
|
+
const here = path8.resolve(dir);
|
|
86899
86882
|
const rest = [];
|
|
86900
|
-
let at2 =
|
|
86883
|
+
let at2 = here;
|
|
86901
86884
|
for (; ; ) {
|
|
86902
86885
|
try {
|
|
86903
86886
|
return path8.join(fs6.realpathSync(at2), ...rest);
|
|
86904
86887
|
} catch {
|
|
86905
86888
|
const up = path8.dirname(at2);
|
|
86906
|
-
if (up === at2) return
|
|
86889
|
+
if (up === at2) return here;
|
|
86907
86890
|
rest.unshift(path8.basename(at2));
|
|
86908
86891
|
at2 = up;
|
|
86909
86892
|
}
|
|
@@ -88165,7 +88148,6 @@ __export(api_exports, {
|
|
|
88165
88148
|
RUNTIMES: () => RUNTIMES,
|
|
88166
88149
|
addFolder: () => addFolder,
|
|
88167
88150
|
answerDiff: () => answerDiff,
|
|
88168
|
-
checkout: () => checkout,
|
|
88169
88151
|
claimJob: () => claimJob,
|
|
88170
88152
|
commitBoard: () => commitBoard,
|
|
88171
88153
|
createArtifact: () => createArtifact,
|
|
@@ -88175,7 +88157,6 @@ __export(api_exports, {
|
|
|
88175
88157
|
download: () => download,
|
|
88176
88158
|
dropIdea: () => dropIdea,
|
|
88177
88159
|
finishJob: () => finishJob,
|
|
88178
|
-
listAlerts: () => listAlerts,
|
|
88179
88160
|
listChats: () => listChats,
|
|
88180
88161
|
listElsewhere: () => listElsewhere,
|
|
88181
88162
|
listFolders: () => listFolders,
|
|
@@ -88188,15 +88169,11 @@ __export(api_exports, {
|
|
|
88188
88169
|
openPresence: () => openPresence,
|
|
88189
88170
|
presenceRoute: () => presenceRoute,
|
|
88190
88171
|
readAgents: () => readAgents,
|
|
88191
|
-
readAlert: () => readAlert,
|
|
88192
88172
|
readArtifact: () => readArtifact,
|
|
88193
88173
|
readBoard: () => readBoard,
|
|
88194
88174
|
readChat: () => readChat,
|
|
88195
88175
|
readDecisions: () => readDecisions,
|
|
88196
88176
|
readDiscussion: () => readDiscussion,
|
|
88197
|
-
readInbox: () => readInbox,
|
|
88198
|
-
readPlan: () => readPlan,
|
|
88199
|
-
readProfile: () => readProfile,
|
|
88200
88177
|
readProject: () => readProject,
|
|
88201
88178
|
readRejections: () => readRejections,
|
|
88202
88179
|
readRunner: () => readRunner,
|
|
@@ -88211,11 +88188,8 @@ __export(api_exports, {
|
|
|
88211
88188
|
request: () => request,
|
|
88212
88189
|
requestAgent: () => requestAgent,
|
|
88213
88190
|
saveDraft: () => saveDraft,
|
|
88214
|
-
setFolderNotify: () => setFolderNotify,
|
|
88215
88191
|
setIdeaWorkflow: () => setIdeaWorkflow,
|
|
88216
|
-
showAlert: () => showAlert,
|
|
88217
88192
|
startIdea: () => startIdea,
|
|
88218
|
-
startTrial: () => startTrial,
|
|
88219
88193
|
stopTask: () => stopTask,
|
|
88220
88194
|
targetVersion: () => targetVersion,
|
|
88221
88195
|
upload: () => upload
|
|
@@ -88336,21 +88310,12 @@ var readAgents = (machineId2, project) => request("GET", `/v1/runner/agents?mach
|
|
|
88336
88310
|
var requestAgent = (machineId2, project, agent, workflow, seen) => request("POST", "/v1/runner/jobs", { machineId: machineId2, project, agent, workflow, seen });
|
|
88337
88311
|
var targetVersion = (machineId2) => request("GET", `/v1/runner/version?machine=${encodeURIComponent(machineId2)}`, void 0, false);
|
|
88338
88312
|
var q = encodeURIComponent;
|
|
88339
|
-
var readProfile = () => request("GET", "/v1/session");
|
|
88340
|
-
var readInbox = () => request("GET", "/v1/runner/inbox");
|
|
88341
|
-
var listAlerts = (machineId2) => request("GET", `/v1/runner/alerts?machine=${q(machineId2)}&comments=1`);
|
|
88342
|
-
var showAlert = (machineId2, alert) => request("POST", `/v1/runner/alerts/${q(alert)}/shown`, { machineId: machineId2 });
|
|
88343
|
-
var readAlert = (alert) => request("POST", `/v1/alerts/${q(alert)}/read`, {});
|
|
88344
88313
|
var listFolders = (machineId2) => request("GET", `/v1/runner/folders?machine=${q(machineId2)}`);
|
|
88345
88314
|
var listElsewhere = (machineId2) => request("GET", `/v1/runner/folders?machine=${q(machineId2)}&elsewhere=1`);
|
|
88346
88315
|
var listMachineTasks = (machineId2) => request("GET", `/v1/runner/tasks?machine=${q(machineId2)}`);
|
|
88347
88316
|
var stopTask = (task, how) => request("POST", how === "chat" ? `/v1/tasks/${q(task)}/chat/stop` : `/v1/tasks/${q(task)}/stop`, {});
|
|
88348
|
-
var addFolder = (machineId2, name,
|
|
88317
|
+
var addFolder = (machineId2, name, path36, project) => request("POST", "/v1/runner/folders", { machineId: machineId2, name, path: path36, ...project ? { project } : {} });
|
|
88349
88318
|
var removeFolder = (machineId2, project) => request("POST", `/v1/runner/folders/${q(project)}/remove`, { machineId: machineId2 });
|
|
88350
|
-
var readPlan = () => request("GET", "/v1/billing");
|
|
88351
|
-
var startTrial = () => request("POST", "/v1/billing/trial", {});
|
|
88352
|
-
var checkout = (item) => request("POST", "/v1/billing/checkout", { item, period: "monthly", source: "desktop" });
|
|
88353
|
-
var setFolderNotify = (machineId2, project, on2) => request("POST", `/v1/runner/folders/${q(project)}/notify`, { machineId: machineId2, on: on2 });
|
|
88354
88319
|
var readBoard = (project, since) => request("GET", `/v1/projects/${q(project)}/board${since === null ? "" : `?since=${since}`}`);
|
|
88355
88320
|
async function commitBoard(project, job, machine, files) {
|
|
88356
88321
|
const sent = await send("POST", `/v1/projects/${q(project)}/board/commits`, { job, machine, files }, true, TIMEOUT_MS);
|
|
@@ -88427,6 +88392,7 @@ function plan(runtime, prompt, cwd, resume, model, given = {}, fork = false, lin
|
|
|
88427
88392
|
stdout: child.stdout,
|
|
88428
88393
|
stdin: child.stdin,
|
|
88429
88394
|
prompt,
|
|
88395
|
+
restartPrompt: prompt,
|
|
88430
88396
|
cwd,
|
|
88431
88397
|
resumeId: resume ?? void 0,
|
|
88432
88398
|
log: () => {
|
|
@@ -88869,9 +88835,9 @@ async function askDueAgents(machineId2, now = Date.now()) {
|
|
|
88869
88835
|
if (!folders2.ok) return false;
|
|
88870
88836
|
let started = false;
|
|
88871
88837
|
for (const { project } of folders2.value.folders) {
|
|
88872
|
-
const
|
|
88873
|
-
if (!
|
|
88874
|
-
for (const agent of
|
|
88838
|
+
const read2 = await readAgents(machineId2, project);
|
|
88839
|
+
if (!read2.ok) continue;
|
|
88840
|
+
for (const agent of read2.value.agents.filter((a3) => agentDue(a3, now))) {
|
|
88875
88841
|
const asked = await requestAgent(machineId2, project, agent.name, agent.workflow ?? null, agent.lastSuccess);
|
|
88876
88842
|
if (!asked.ok) console.error(`runner: ${agent.name} was not started on ${project}: ${asked.error}`);
|
|
88877
88843
|
else if (asked.value.job) started = true;
|
|
@@ -88973,7 +88939,6 @@ import path16 from "node:path";
|
|
|
88973
88939
|
|
|
88974
88940
|
// src/folders.ts
|
|
88975
88941
|
import fs12 from "node:fs";
|
|
88976
|
-
import os5 from "node:os";
|
|
88977
88942
|
import path15 from "node:path";
|
|
88978
88943
|
var projectsFile = () => path15.join(runnerHome(), "projects.json");
|
|
88979
88944
|
function realpath(p2) {
|
|
@@ -88991,53 +88956,9 @@ function readList() {
|
|
|
88991
88956
|
return [];
|
|
88992
88957
|
}
|
|
88993
88958
|
}
|
|
88994
|
-
function writeList(list) {
|
|
88995
|
-
fs12.mkdirSync(runnerHome(), { recursive: true, mode: 448 });
|
|
88996
|
-
fs12.writeFileSync(projectsFile(), `${JSON.stringify({ projects: [...new Set(list)] }, null, 2)}
|
|
88997
|
-
`);
|
|
88998
|
-
}
|
|
88999
88959
|
function allowedProjects() {
|
|
89000
88960
|
return readList().flatMap((p2) => [realpath(p2)].filter((r2) => !!r2));
|
|
89001
88961
|
}
|
|
89002
|
-
var allow = (dir) => writeList([...readList(), dir]);
|
|
89003
|
-
function disallow(dir) {
|
|
89004
|
-
const list = readList();
|
|
89005
|
-
if (!list.includes(dir)) return [];
|
|
89006
|
-
writeList(list.filter((p2) => p2 !== dir));
|
|
89007
|
-
return [dir];
|
|
89008
|
-
}
|
|
89009
|
-
function keepOnly(dirs) {
|
|
89010
|
-
const list = readList();
|
|
89011
|
-
const kept4 = list.filter((p2) => dirs.includes(p2));
|
|
89012
|
-
if (kept4.length !== list.length) writeList(kept4);
|
|
89013
|
-
return list.filter((p2) => !dirs.includes(p2));
|
|
89014
|
-
}
|
|
89015
|
-
var SYSTEM_MAC = ["/System", "/Library", "/Applications", "/usr", "/bin", "/sbin", "/etc", "/var", "/private", "/opt", "/cores", "/dev"];
|
|
89016
|
-
var SYSTEM_WIN = ["Windows", "Program Files", "Program Files (x86)", "ProgramData"];
|
|
89017
|
-
var here = () => ({ platform: process.platform, home: os5.homedir(), resolve: realpath });
|
|
89018
|
-
function refusal(picked, where = here()) {
|
|
89019
|
-
const win = where.platform === "win32";
|
|
89020
|
-
const p2 = win ? path15.win32 : path15.posix;
|
|
89021
|
-
const real = where.resolve(picked);
|
|
89022
|
-
if (!real || !p2.isAbsolute(real)) return "missing";
|
|
89023
|
-
const norm = (d2) => {
|
|
89024
|
-
const n = p2.normalize(d2).replace(/[\\/]+$/, "") || p2.sep;
|
|
89025
|
-
return win ? n.toLowerCase() : n;
|
|
89026
|
-
};
|
|
89027
|
-
const within = (dir, root) => {
|
|
89028
|
-
const [d2, r2] = [norm(dir), norm(root)];
|
|
89029
|
-
return d2 === r2 || d2.startsWith(r2.endsWith(p2.sep) ? r2 : r2 + p2.sep);
|
|
89030
|
-
};
|
|
89031
|
-
const forms = [picked, real];
|
|
89032
|
-
if (forms.some((f2) => norm(f2) === norm(where.home))) return "home";
|
|
89033
|
-
if (forms.some((f2) => norm(f2) === norm(p2.parse(f2).root)) || !win && forms.some((f2) => /^\/Volumes(\/[^/]+)?\/?$/.test(f2))) {
|
|
89034
|
-
return "disk";
|
|
89035
|
-
}
|
|
89036
|
-
if (forms.some((f2) => within(where.home, f2))) return "home";
|
|
89037
|
-
if (forms.some((f2) => within(f2, runnerHome()))) return "system";
|
|
89038
|
-
const system = win ? SYSTEM_WIN.map((s) => p2.join(p2.parse(real).root, s)) : SYSTEM_MAC;
|
|
89039
|
-
return forms.some((f2) => system.some((s) => within(f2, s))) ? "system" : null;
|
|
89040
|
-
}
|
|
89041
88962
|
|
|
89042
88963
|
// src/cache.ts
|
|
89043
88964
|
var IDLE_MS = 7 * 24 * 60 * 6e4;
|
|
@@ -89463,11 +89384,11 @@ function keepCloudChat(task, messages) {
|
|
|
89463
89384
|
fs17.writeFileSync(file2, lines.map((l2) => `${JSON.stringify(l2)}
|
|
89464
89385
|
`).join(""));
|
|
89465
89386
|
}
|
|
89466
|
-
async function keepDecisions(task,
|
|
89387
|
+
async function keepDecisions(task, read2) {
|
|
89467
89388
|
const comments = [];
|
|
89468
89389
|
let after = null;
|
|
89469
89390
|
do {
|
|
89470
|
-
const page = await
|
|
89391
|
+
const page = await read2(task, after);
|
|
89471
89392
|
if (!page.ok) return;
|
|
89472
89393
|
for (const d2 of page.value.data) {
|
|
89473
89394
|
if (d2.comment.trim()) comments.push({ id: d2.id, role: "user", text: d2.comment, at: Date.parse(d2.created_at) || Date.now() });
|
|
@@ -89541,22 +89462,22 @@ import path24 from "node:path";
|
|
|
89541
89462
|
// ../cloud/src/board-files.ts
|
|
89542
89463
|
var ROOTS = ["todo/", ".archive/", "memory/", "workflows/", "triage/", "assets/", "rules/"];
|
|
89543
89464
|
var SETTINGS = ["modules.md", "config.md"];
|
|
89544
|
-
var isSettingsPath = (
|
|
89465
|
+
var isSettingsPath = (path36) => SETTINGS.includes(path36) || /^rules\/(?:workflows\/)?[^/]+\.md$/.test(path36);
|
|
89545
89466
|
var BOARD_FILE_LIMIT = 256 * 1024;
|
|
89546
|
-
function isBoardPath(
|
|
89547
|
-
if (!
|
|
89548
|
-
if (
|
|
89549
|
-
if (
|
|
89550
|
-
if (
|
|
89551
|
-
if (SETTINGS.includes(
|
|
89552
|
-
if (
|
|
89553
|
-
if (
|
|
89554
|
-
return ROOTS.some((root) =>
|
|
89467
|
+
function isBoardPath(path36) {
|
|
89468
|
+
if (!path36 || path36.length > 500 || path36.startsWith("/") || path36.includes("\\") || path36.includes("\0")) return false;
|
|
89469
|
+
if (path36.split("/").some((part) => !part || part === "." || part === "..")) return false;
|
|
89470
|
+
if (path36 === "todo/README.md" || path36.split("/").includes(".sync")) return false;
|
|
89471
|
+
if (path36.startsWith("workflows/")) return true;
|
|
89472
|
+
if (SETTINGS.includes(path36)) return true;
|
|
89473
|
+
if (path36.startsWith("rules/")) return isSettingsPath(path36);
|
|
89474
|
+
if (path36.startsWith("assets/")) return path36.endsWith(".json");
|
|
89475
|
+
return ROOTS.some((root) => path36.startsWith(root)) && path36.endsWith(".md");
|
|
89555
89476
|
}
|
|
89556
89477
|
var CARD = /^(?:todo|\.archive)\/(?:[^/]+\/)*(\d+)-[^/]*\.md$/;
|
|
89557
89478
|
var ROOT = /^(?:todo|\.archive)\/(?:[^/]+\/)*(\d+)-[^/]+\/root\.md$/;
|
|
89558
|
-
function numberOfCard(
|
|
89559
|
-
const n = ROOT.exec(
|
|
89479
|
+
function numberOfCard(path36) {
|
|
89480
|
+
const n = ROOT.exec(path36)?.[1] ?? CARD.exec(path36)?.[1];
|
|
89560
89481
|
return n ? Number(n) : null;
|
|
89561
89482
|
}
|
|
89562
89483
|
var cardSlug = (task) => task.toLowerCase().replace(/_/g, "-");
|
|
@@ -89830,8 +89751,8 @@ function unquote2(v2) {
|
|
|
89830
89751
|
|
|
89831
89752
|
// ../cloud/src/triage-files.ts
|
|
89832
89753
|
var ITEM = /^triage\/(?:(dismissed|archived)\/)?([^/]+)\.md$/;
|
|
89833
|
-
function itemAt(
|
|
89834
|
-
const m = ITEM.exec(
|
|
89754
|
+
function itemAt(path36) {
|
|
89755
|
+
const m = ITEM.exec(path36);
|
|
89835
89756
|
if (!m) return null;
|
|
89836
89757
|
return { state: m[1] === "dismissed" ? "dismissed" : m[1] === "archived" ? "carded" : "open", name: m[2] };
|
|
89837
89758
|
}
|
|
@@ -90571,8 +90492,8 @@ function sharedMemory(board) {
|
|
|
90571
90492
|
const declared = /* @__PURE__ */ new Map();
|
|
90572
90493
|
const take = (folder, text3, builtIn) => {
|
|
90573
90494
|
if (text3 === null || declared.has(folder)) return;
|
|
90574
|
-
const
|
|
90575
|
-
if ("agent" in
|
|
90495
|
+
const read2 = parseSpecAgent(text3, folder, () => null, builtIn);
|
|
90496
|
+
if ("agent" in read2 && read2.agent.name === folder) declared.set(folder, read2.agent.memoryFiles.workspace);
|
|
90576
90497
|
};
|
|
90577
90498
|
for (const [key, text3] of Object.entries(BUNDLED_AGENT_FILES)) {
|
|
90578
90499
|
const at2 = /^([^/]+)\/AGENT\.md$/.exec(key);
|
|
@@ -90829,10 +90750,10 @@ async function pullWorkflow(ws, record, base) {
|
|
|
90829
90750
|
record.builtin = ws.workflow.startsWith("wf_builtin_");
|
|
90830
90751
|
let found = Object.keys(files).length > 0;
|
|
90831
90752
|
if (!found && ws.cloudTask) {
|
|
90832
|
-
const
|
|
90833
|
-
if (!
|
|
90834
|
-
if (
|
|
90835
|
-
files =
|
|
90753
|
+
const read2 = await readTaskWorkflow(ws.cloudTask);
|
|
90754
|
+
if (!read2.ok && read2.code !== "not_found") return read2;
|
|
90755
|
+
if (read2.ok) {
|
|
90756
|
+
files = read2.value.files;
|
|
90836
90757
|
found = true;
|
|
90837
90758
|
if (!record.builtin) {
|
|
90838
90759
|
for (const [name, text3] of Object.entries(files)) if (isBoardPath(root + name)) write(path23.join(ws.board, root, name), text3);
|
|
@@ -90947,28 +90868,28 @@ var readHead = (ws) => readBase(ws).head_seq;
|
|
|
90947
90868
|
var pullChanges = (ws) => inFolder(ws.cwd, async () => {
|
|
90948
90869
|
const base = readBase(ws);
|
|
90949
90870
|
if (base.head_seq === null) return { ok: true, value: void 0 };
|
|
90950
|
-
const
|
|
90951
|
-
if (!
|
|
90871
|
+
const read2 = await readBoard(ws.project, base.head_seq);
|
|
90872
|
+
if (!read2.ok) return read2;
|
|
90952
90873
|
const shared = sharedMemory(ws.board);
|
|
90953
90874
|
const root = rootOf(ws);
|
|
90954
90875
|
let skipped = false;
|
|
90955
|
-
for (const f2 of
|
|
90876
|
+
for (const f2 of read2.value.files) {
|
|
90956
90877
|
const p2 = f2.path.startsWith(root) ? f2.path.slice(root.length) : f2.path;
|
|
90957
90878
|
const isShared = p2.startsWith(MEMORY2) && shared(p2.slice(MEMORY2.length));
|
|
90958
90879
|
if (kept3(p2) && isShared === !f2.path.startsWith(root)) {
|
|
90959
90880
|
const file2 = path23.join(ws.board, p2);
|
|
90960
|
-
const
|
|
90961
|
-
if (
|
|
90881
|
+
const here = readText(file2);
|
|
90882
|
+
if (here !== f2.content && here !== (base.files[f2.path]?.content ?? null)) {
|
|
90962
90883
|
skipped = true;
|
|
90963
90884
|
continue;
|
|
90964
90885
|
}
|
|
90965
90886
|
if (f2.content === null) fs20.rmSync(file2, { force: true });
|
|
90966
|
-
else if (
|
|
90887
|
+
else if (here !== f2.content) write(file2, f2.content);
|
|
90967
90888
|
}
|
|
90968
90889
|
if (f2.content === null) delete base.files[f2.path];
|
|
90969
90890
|
else base.files[f2.path] = { seq: f2.seq, content: f2.content };
|
|
90970
90891
|
}
|
|
90971
|
-
if (!skipped) base.head_seq =
|
|
90892
|
+
if (!skipped) base.head_seq = read2.value.head_seq;
|
|
90972
90893
|
writeBase(ws, base);
|
|
90973
90894
|
writeIndex(ws.board);
|
|
90974
90895
|
return { ok: true, value: void 0 };
|
|
@@ -90981,14 +90902,14 @@ async function readCloud(ws) {
|
|
|
90981
90902
|
if (!project.ok) return project;
|
|
90982
90903
|
base.workspace = project.value.workspace ?? null;
|
|
90983
90904
|
}
|
|
90984
|
-
const
|
|
90985
|
-
if (!
|
|
90905
|
+
const read2 = await readBoard(ws.project, base.head_seq);
|
|
90906
|
+
if (!read2.ok) return read2;
|
|
90986
90907
|
if (base.head_seq === null) base.files = {};
|
|
90987
|
-
for (const f2 of
|
|
90908
|
+
for (const f2 of read2.value.files) {
|
|
90988
90909
|
if (f2.content === null) delete base.files[f2.path];
|
|
90989
90910
|
else base.files[f2.path] = { seq: f2.seq, content: f2.content };
|
|
90990
90911
|
}
|
|
90991
|
-
base.head_seq =
|
|
90912
|
+
base.head_seq = read2.value.head_seq;
|
|
90992
90913
|
base.project = ws.project;
|
|
90993
90914
|
writeBase(ws, base);
|
|
90994
90915
|
const reset = (view2) => {
|
|
@@ -91294,6 +91215,7 @@ async function send2(ws, job) {
|
|
|
91294
91215
|
// src/board-watch.ts
|
|
91295
91216
|
var LOOK_MS = 6e4;
|
|
91296
91217
|
var PULL_MS = 2e3;
|
|
91218
|
+
var BUSY_MS = 3e4;
|
|
91297
91219
|
function keptFolders() {
|
|
91298
91220
|
let cached2 = [];
|
|
91299
91221
|
try {
|
|
@@ -91302,7 +91224,7 @@ function keptFolders() {
|
|
|
91302
91224
|
}
|
|
91303
91225
|
return [.../* @__PURE__ */ new Set([...allowedProjects(), ...cached2])].flatMap((dir) => [keptBoard(dir)].filter((ws) => !!ws));
|
|
91304
91226
|
}
|
|
91305
|
-
function watchBoards(machineId2, ms, lookMs = LOOK_MS, pullMs = PULL_MS) {
|
|
91227
|
+
function watchBoards(machineId2, ms, lookMs = LOOK_MS, pullMs = PULL_MS, busyMs = BUSY_MS) {
|
|
91306
91228
|
const watched = /* @__PURE__ */ new Map();
|
|
91307
91229
|
const due = /* @__PURE__ */ new Map();
|
|
91308
91230
|
const afterJob = /* @__PURE__ */ new Set();
|
|
@@ -91311,12 +91233,24 @@ function watchBoards(machineId2, ms, lookMs = LOOK_MS, pullMs = PULL_MS) {
|
|
|
91311
91233
|
if (closed) return;
|
|
91312
91234
|
if (busy(ws.cwd)) return void afterJob.add(ws.cwd);
|
|
91313
91235
|
afterJob.delete(ws.cwd);
|
|
91314
|
-
const
|
|
91315
|
-
if (!
|
|
91236
|
+
const read2 = await pullChanges(ws);
|
|
91237
|
+
if (!read2.ok && read2.code) console.error(`runner: the board in ${ws.cwd} was not read: ${read2.error}`);
|
|
91316
91238
|
};
|
|
91317
91239
|
const send3 = async (ws) => {
|
|
91318
91240
|
const sent = await pushBoard(ws, machineId2);
|
|
91319
91241
|
if (!sent.ok && !sent.offline) console.error(`runner: the board in ${ws.cwd} was not sent: ${sent.error}`);
|
|
91242
|
+
return sent;
|
|
91243
|
+
};
|
|
91244
|
+
const flush = async (ws) => {
|
|
91245
|
+
const held4 = watched.get(ws.cwd);
|
|
91246
|
+
if (!held4) return void await send3(ws);
|
|
91247
|
+
clearTimeout(held4.timer);
|
|
91248
|
+
held4.timer = void 0;
|
|
91249
|
+
held4.spaced = false;
|
|
91250
|
+
const last2 = held4.sentAt;
|
|
91251
|
+
held4.sentAt = Date.now();
|
|
91252
|
+
const sent = await send3(ws);
|
|
91253
|
+
if (!sent.ok || !sent.changed) held4.sentAt = last2;
|
|
91320
91254
|
};
|
|
91321
91255
|
const watch = (ws) => {
|
|
91322
91256
|
let watcher;
|
|
@@ -91325,8 +91259,11 @@ function watchBoards(machineId2, ms, lookMs = LOOK_MS, pullMs = PULL_MS) {
|
|
|
91325
91259
|
const p2 = name && String(name).split(path24.sep).join("/");
|
|
91326
91260
|
const held4 = watched.get(ws.cwd);
|
|
91327
91261
|
if (closed || !p2 || !isBoardPath(p2) || !held4) return;
|
|
91262
|
+
const job = busy(ws.cwd);
|
|
91263
|
+
if (job && held4.spaced) return;
|
|
91328
91264
|
clearTimeout(held4.timer);
|
|
91329
|
-
held4.
|
|
91265
|
+
held4.spaced = job;
|
|
91266
|
+
held4.timer = setTimeout(() => void flush(ws), job ? Math.max(ms, held4.sentAt + busyMs - Date.now()) : ms);
|
|
91330
91267
|
});
|
|
91331
91268
|
} catch {
|
|
91332
91269
|
return false;
|
|
@@ -91336,14 +91273,15 @@ function watchBoards(machineId2, ms, lookMs = LOOK_MS, pullMs = PULL_MS) {
|
|
|
91336
91273
|
watcher.close();
|
|
91337
91274
|
watched.delete(ws.cwd);
|
|
91338
91275
|
});
|
|
91339
|
-
watched.set(ws.cwd, { watcher });
|
|
91276
|
+
watched.set(ws.cwd, { watcher, spaced: false, sentAt: 0 });
|
|
91340
91277
|
return true;
|
|
91341
91278
|
};
|
|
91342
91279
|
const look = () => {
|
|
91343
91280
|
if (closed) return;
|
|
91344
91281
|
for (const ws of keptFolders()) {
|
|
91345
91282
|
const fresh = !watched.has(ws.cwd) && watch(ws);
|
|
91346
|
-
|
|
91283
|
+
const jobOver = watched.get(ws.cwd)?.spaced && !busy(ws.cwd);
|
|
91284
|
+
if (fresh || jobOver || unsent(ws.cwd)) void flush(ws);
|
|
91347
91285
|
if (afterJob.has(ws.cwd) && !busy(ws.cwd)) void pull2(ws);
|
|
91348
91286
|
}
|
|
91349
91287
|
};
|
|
@@ -91456,8 +91394,8 @@ async function answerHint(machineId2, hint2) {
|
|
|
91456
91394
|
}
|
|
91457
91395
|
|
|
91458
91396
|
// src/flow.ts
|
|
91459
|
-
import
|
|
91460
|
-
import
|
|
91397
|
+
import fs27 from "node:fs";
|
|
91398
|
+
import path30 from "node:path";
|
|
91461
91399
|
|
|
91462
91400
|
// ../cli/src/lib/question-block.ts
|
|
91463
91401
|
var MODES = ["single", "multi"];
|
|
@@ -91602,6 +91540,18 @@ function parseFrontmatter(text3) {
|
|
|
91602
91540
|
return { meta, body: lines.slice(i + 1).join("\n") };
|
|
91603
91541
|
}
|
|
91604
91542
|
|
|
91543
|
+
// ../cli/src/lib/card-review.ts
|
|
91544
|
+
function reviewOf(meta) {
|
|
91545
|
+
const questions = meta.questions ?? [];
|
|
91546
|
+
let open = false;
|
|
91547
|
+
for (const [i, q3] of questions.entries()) {
|
|
91548
|
+
if (!openOf([q3]).length) continue;
|
|
91549
|
+
open = true;
|
|
91550
|
+
if (q3.options?.length) return { question: q3.text, options: q3.options.slice(0, 8), position: i + 1 };
|
|
91551
|
+
}
|
|
91552
|
+
return open || meta.status === "ready" || meta.status === "implementing" ? true : null;
|
|
91553
|
+
}
|
|
91554
|
+
|
|
91605
91555
|
// src/triage.ts
|
|
91606
91556
|
import fs23 from "node:fs";
|
|
91607
91557
|
import path26 from "node:path";
|
|
@@ -91684,10 +91634,152 @@ function clearLaid(board) {
|
|
|
91684
91634
|
for (const sub of SCRATCH) fs23.rmSync(path26.join(triageDir(board), sub), { recursive: true, force: true });
|
|
91685
91635
|
}
|
|
91686
91636
|
|
|
91687
|
-
// src/
|
|
91637
|
+
// src/kanban-skill.ts
|
|
91688
91638
|
import fs24 from "node:fs";
|
|
91689
91639
|
import path27 from "node:path";
|
|
91690
91640
|
|
|
91641
|
+
// ../skill/SKILL.md
|
|
91642
|
+
var SKILL_default = '---\nname: kanban\ndescription: Manage the file-based task board with akb. Use for creating and planning tasks, revising or implementing cards, and managing background runs; also for "what\'s running".\n---\n\n# Kanban board\n\nThe board is worked only through `akb`. Find the command for the job in `akb help` and run\nit; never do its work by hand or from memory.\n\n- **`--print` does it here**: `akb card revise 12 --print "drop the export"` prints the whole\n flow for that card on this board; follow it to its closing steps. Without `--print` the\n same command starts a separate agent.\n- **Keys**: never read or write API keys; the user sets them with `akb agent set apiKey`.\n';
|
|
91643
|
+
|
|
91644
|
+
// src/kanban-skill.ts
|
|
91645
|
+
var CONTENT = `${SKILL_default.trimEnd()}
|
|
91646
|
+
|
|
91647
|
+
<!-- ai4kanban managed -->
|
|
91648
|
+
`;
|
|
91649
|
+
var MANAGED = /^<!-- ai4kanban \S+ -->$/m;
|
|
91650
|
+
function prepareKanbanSkill(root) {
|
|
91651
|
+
for (const folder of SKILL_FOLDERS) {
|
|
91652
|
+
const dir = path27.join(root, folder);
|
|
91653
|
+
const file2 = path27.join(dir, "SKILL.md");
|
|
91654
|
+
try {
|
|
91655
|
+
let linked = false;
|
|
91656
|
+
let at2 = root;
|
|
91657
|
+
for (const name of `${folder}/SKILL.md`.split("/")) {
|
|
91658
|
+
at2 = path27.join(at2, name);
|
|
91659
|
+
if (fs24.lstatSync(at2, { throwIfNoEntry: false })?.isSymbolicLink()) linked = true;
|
|
91660
|
+
}
|
|
91661
|
+
const held4 = fs24.existsSync(file2) ? fs24.readFileSync(file2, "utf8") : null;
|
|
91662
|
+
const exists = fs24.lstatSync(dir, { throwIfNoEntry: false }) !== void 0;
|
|
91663
|
+
if (linked || exists && !MANAGED.test(held4 ?? "")) {
|
|
91664
|
+
if (!held4?.trim()) throw new Error("\u7528\u6237\u81EA\u6709\u76EE\u5F55\u6216\u7B26\u53F7\u94FE\u63A5\u4E2D\u7F3A\u5C11\u53EF\u8BFB\u7684 SKILL.md");
|
|
91665
|
+
continue;
|
|
91666
|
+
}
|
|
91667
|
+
if (held4 !== CONTENT) {
|
|
91668
|
+
fs24.mkdirSync(dir, { recursive: true });
|
|
91669
|
+
fs24.writeFileSync(file2, CONTENT);
|
|
91670
|
+
}
|
|
91671
|
+
} catch (e2) {
|
|
91672
|
+
throw new Error(`\u65E0\u6CD5\u51C6\u5907 ${folder}\uFF1A${e2 instanceof Error ? e2.message : String(e2)}`);
|
|
91673
|
+
}
|
|
91674
|
+
}
|
|
91675
|
+
}
|
|
91676
|
+
|
|
91677
|
+
// ../cli/src/lib/skill/hook.ts
|
|
91678
|
+
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
91679
|
+
import fs25 from "node:fs";
|
|
91680
|
+
import path28 from "node:path";
|
|
91681
|
+
var MARKER = "# ai4kanban commit guard";
|
|
91682
|
+
var MARKER_LINE = new RegExp(`^${MARKER}\\b`, "m");
|
|
91683
|
+
var CHECK = [
|
|
91684
|
+
"try{",
|
|
91685
|
+
'const[top,branch]=require("child_process")',
|
|
91686
|
+
'.execFileSync("git",["rev-parse","--show-toplevel","--abbrev-ref","HEAD"],{encoding:"utf8"}).trim().split("\\n");',
|
|
91687
|
+
'if(/\\/\\.akb\\/worktrees\\//.test(top+"/"))process.exit(0);',
|
|
91688
|
+
'const d=(JSON.parse(require("fs").readFileSync(process.argv[1],"utf8")).deliveries||[])',
|
|
91689
|
+
'.find((x)=>x&&x.status==="active"&&x.commitMode==="auto"&&x.targetBranch===branch&&(!x.landing||x.landing.status!=="landed"));',
|
|
91690
|
+
"if(!d)process.exit(0);",
|
|
91691
|
+
"process.stderr.write(",
|
|
91692
|
+
'"ai4kanban: delivery "+d.deliveryId+" is landing #"+d.cardId+" on "+branch+", so a commit here moves the target under it\\n"',
|
|
91693
|
+
'+" \u2014 commit on another branch, or `git commit --no-verify` to commit anyway.\\n");',
|
|
91694
|
+
"process.exit(1);",
|
|
91695
|
+
"}catch(e){process.exit(0)}"
|
|
91696
|
+
].join("");
|
|
91697
|
+
var quoted = (p2) => `"${p2.replace(/(["$`\\])/g, "\\$1")}"`;
|
|
91698
|
+
var guardLine = (sessions) => `if command -v node >/dev/null 2>&1; then node -e '${CHECK}' ${quoted(sessions)} || exit 1; fi`;
|
|
91699
|
+
function hookScript(sessions) {
|
|
91700
|
+
return [
|
|
91701
|
+
"#!/bin/sh",
|
|
91702
|
+
`${MARKER} ${SKILL_VERSION} \u2014 \u7531 Runner \u7BA1\u7406\uFF0C\u4FEE\u6539\u4F1A\u88AB\u8986\u76D6\u3002`,
|
|
91703
|
+
"#",
|
|
91704
|
+
"# Refuses a commit on the branch a delivery is landing on, and nothing else. Anything",
|
|
91705
|
+
"# it cannot judge lets the commit through. `git commit --no-verify` gets past it, and",
|
|
91706
|
+
"# deleting this file turns it off.",
|
|
91707
|
+
guardLine(sessions),
|
|
91708
|
+
"exit 0",
|
|
91709
|
+
""
|
|
91710
|
+
].join("\n");
|
|
91711
|
+
}
|
|
91712
|
+
var read = (file2) => {
|
|
91713
|
+
try {
|
|
91714
|
+
return fs25.readFileSync(file2, "utf8");
|
|
91715
|
+
} catch {
|
|
91716
|
+
return null;
|
|
91717
|
+
}
|
|
91718
|
+
};
|
|
91719
|
+
function hooksDir(root) {
|
|
91720
|
+
const out = spawnSync5("git", ["rev-parse", "--git-path", "hooks"], {
|
|
91721
|
+
cwd: root,
|
|
91722
|
+
encoding: "utf8",
|
|
91723
|
+
windowsHide: true
|
|
91724
|
+
});
|
|
91725
|
+
if (out.error || out.status !== 0 || !out.stdout.trim()) return null;
|
|
91726
|
+
return path28.resolve(root, out.stdout.trim());
|
|
91727
|
+
}
|
|
91728
|
+
function hasOwnHooksPath(root) {
|
|
91729
|
+
const out = spawnSync5("git", ["config", "--get", "core.hooksPath"], {
|
|
91730
|
+
cwd: root,
|
|
91731
|
+
encoding: "utf8",
|
|
91732
|
+
windowsHide: true
|
|
91733
|
+
});
|
|
91734
|
+
return !out.error && out.status === 0 && !!out.stdout.trim();
|
|
91735
|
+
}
|
|
91736
|
+
var sessionsPath = (root, board) => path28.join(projectStateDir(board, root), SESSIONS_FILE);
|
|
91737
|
+
function readCommitHook(root, board = path28.join(root, "docs", "kanban")) {
|
|
91738
|
+
const dir = hooksDir(root);
|
|
91739
|
+
if (!dir) return { state: "no-git" };
|
|
91740
|
+
const where = shown(root, path28.join(dir, "pre-commit"));
|
|
91741
|
+
const line = guardLine(sessionsPath(root, board));
|
|
91742
|
+
if (hasOwnHooksPath(root)) return { state: "hooks-path", path: where, line };
|
|
91743
|
+
const file2 = path28.join(dir, "pre-commit");
|
|
91744
|
+
if (fs25.lstatSync(file2, { throwIfNoEntry: false })?.isSymbolicLink()) return { state: "foreign", path: where, line };
|
|
91745
|
+
const text3 = read(file2);
|
|
91746
|
+
if (text3 === null) return { state: "absent", path: where };
|
|
91747
|
+
return MARKER_LINE.test(text3) ? { state: "ours", path: where } : { state: "foreign", path: where, line };
|
|
91748
|
+
}
|
|
91749
|
+
var shown = (root, p2) => (path28.relative(root, p2) || p2).split(path28.sep).join("/");
|
|
91750
|
+
function installCommitHook(root, board = path28.join(root, "docs", "kanban")) {
|
|
91751
|
+
try {
|
|
91752
|
+
return placeCommitHook(root, board);
|
|
91753
|
+
} catch (e2) {
|
|
91754
|
+
return { note: `\u63D0\u4EA4\u4FDD\u62A4\u65E0\u6CD5\u51C6\u5907\uFF1A${e2 instanceof Error ? e2.message : String(e2)}` };
|
|
91755
|
+
}
|
|
91756
|
+
}
|
|
91757
|
+
function placeCommitHook(root, board) {
|
|
91758
|
+
const hook = readCommitHook(root, board);
|
|
91759
|
+
if (hook.state === "no-git") return {};
|
|
91760
|
+
if (hook.state === "hooks-path" || hook.state === "foreign") {
|
|
91761
|
+
const why = hook.state === "foreign" ? `${hook.path} is a hook the board did not write, so no commit guard was installed` : `this repository runs its hooks from \`core.hooksPath\`, so no commit guard was installed`;
|
|
91762
|
+
return {
|
|
91763
|
+
note: `${why} \u2014 add this line to ${hook.path} to refuse a commit on the branch a delivery is landing on:
|
|
91764
|
+
${hook.line}`
|
|
91765
|
+
};
|
|
91766
|
+
}
|
|
91767
|
+
const file2 = path28.join(root, hook.path);
|
|
91768
|
+
try {
|
|
91769
|
+
fs25.mkdirSync(path28.dirname(file2), { recursive: true });
|
|
91770
|
+
const text3 = hookScript(sessionsPath(root, board));
|
|
91771
|
+
if (read(file2) !== text3) fs25.writeFileSync(file2, text3, { mode: 493 });
|
|
91772
|
+
fs25.chmodSync(file2, 493);
|
|
91773
|
+
} catch (e2) {
|
|
91774
|
+
return { note: `${hook.path} could not be written \u2014 ${e2 instanceof Error ? e2.message : String(e2)}` };
|
|
91775
|
+
}
|
|
91776
|
+
return { wrote: { path: hook.path, refreshed: hook.state === "ours" } };
|
|
91777
|
+
}
|
|
91778
|
+
|
|
91779
|
+
// src/built.ts
|
|
91780
|
+
import fs26 from "node:fs";
|
|
91781
|
+
import path29 from "node:path";
|
|
91782
|
+
|
|
91691
91783
|
// ../cli/src/lib/spec-agent-names.ts
|
|
91692
91784
|
var LEGACY_SPEC_AGENT_NAMES = {
|
|
91693
91785
|
"recommend-tech-stack": "tech-stack-advisor",
|
|
@@ -91783,13 +91875,13 @@ function folderPath(file2, top) {
|
|
|
91783
91875
|
return [parts[1], parts.slice(2).join("/")];
|
|
91784
91876
|
}
|
|
91785
91877
|
function mcpProblem(text3) {
|
|
91786
|
-
let
|
|
91878
|
+
let read2;
|
|
91787
91879
|
try {
|
|
91788
|
-
|
|
91880
|
+
read2 = JSON.parse(text3);
|
|
91789
91881
|
} catch {
|
|
91790
91882
|
return "is not JSON";
|
|
91791
91883
|
}
|
|
91792
|
-
const servers =
|
|
91884
|
+
const servers = read2?.mcpServers;
|
|
91793
91885
|
if (!servers || typeof servers !== "object" || Array.isArray(servers)) return "must hold `mcpServers`, an object of name \u2192 server";
|
|
91794
91886
|
for (const [name, server] of Object.entries(servers)) {
|
|
91795
91887
|
const { command, args, ...rest } = server ?? {};
|
|
@@ -91836,9 +91928,9 @@ function checkWorkflowFiles(value, official = false) {
|
|
|
91836
91928
|
}
|
|
91837
91929
|
const source = value[WORKFLOW_FILE];
|
|
91838
91930
|
if (source === void 0) return fail(WORKFLOW_FILE, "is missing");
|
|
91839
|
-
const
|
|
91840
|
-
if ("problem" in
|
|
91841
|
-
const def =
|
|
91931
|
+
const read2 = parseWorkflowFile("workflow", source, WORKFLOW_FILE);
|
|
91932
|
+
if ("problem" in read2) return fail(WORKFLOW_FILE, read2.problem.replace(`${WORKFLOW_FILE}: `, ""));
|
|
91933
|
+
const def = read2.def;
|
|
91842
91934
|
const agents = /* @__PURE__ */ new Map();
|
|
91843
91935
|
for (const [name, own] of folders2) {
|
|
91844
91936
|
const from = `agents/${name}/AGENT.md`;
|
|
@@ -91862,26 +91954,26 @@ function checkWorkflowFiles(value, official = false) {
|
|
|
91862
91954
|
|
|
91863
91955
|
// src/built.ts
|
|
91864
91956
|
var isBuilder = (ws) => ws.workflow === BUILDER;
|
|
91865
|
-
var draftDir = (ws) =>
|
|
91866
|
-
var draftLine = (ws) => `<!-- workflow folder: ${
|
|
91957
|
+
var draftDir = (ws) => path29.join(ws.board, "workflows", draftFolder(ws.task));
|
|
91958
|
+
var draftLine = (ws) => `<!-- workflow folder: ${path29.relative(ws.cwd, draftDir(ws)).split(path29.sep).join("/")}/ -->`;
|
|
91867
91959
|
var skeleton = (name) => ["---", `name: ${/\s#/.test(name) ? JSON.stringify(name) : yamlScalar(name)}`, "needsArtifact: false", "---", ""].join("\n");
|
|
91868
|
-
async function placeDraft(ws,
|
|
91960
|
+
async function placeDraft(ws, read2) {
|
|
91869
91961
|
const dir = draftDir(ws);
|
|
91870
|
-
if (
|
|
91871
|
-
const task = await
|
|
91962
|
+
if (fs26.existsSync(path29.join(dir, WORKFLOW_FILE))) return { ok: true, value: void 0 };
|
|
91963
|
+
const task = await read2.readTask(ws.task);
|
|
91872
91964
|
if (!task.ok) return task;
|
|
91873
91965
|
let files = { [WORKFLOW_FILE]: skeleton(task.value.title.trim() || "Untitled") };
|
|
91874
91966
|
const changes = task.value.context?.workflow;
|
|
91875
91967
|
if (changes) {
|
|
91876
|
-
const held4 = await
|
|
91968
|
+
const held4 = await read2.readWorkflow(changes);
|
|
91877
91969
|
if (!held4.ok) return held4;
|
|
91878
91970
|
files = held4.value.files;
|
|
91879
91971
|
}
|
|
91880
91972
|
for (const [name, text3] of Object.entries(files)) {
|
|
91881
|
-
const file2 =
|
|
91882
|
-
if (!file2.startsWith(dir +
|
|
91883
|
-
|
|
91884
|
-
|
|
91973
|
+
const file2 = path29.resolve(dir, name);
|
|
91974
|
+
if (!file2.startsWith(dir + path29.sep)) continue;
|
|
91975
|
+
fs26.mkdirSync(path29.dirname(file2), { recursive: true });
|
|
91976
|
+
fs26.writeFileSync(file2, text3);
|
|
91885
91977
|
}
|
|
91886
91978
|
return { ok: true, value: void 0 };
|
|
91887
91979
|
}
|
|
@@ -91893,19 +91985,19 @@ async function builtWorkflow(ws, akb) {
|
|
|
91893
91985
|
const dir = draftDir(ws);
|
|
91894
91986
|
let source;
|
|
91895
91987
|
try {
|
|
91896
|
-
source =
|
|
91988
|
+
source = fs26.readFileSync(path29.join(dir, WORKFLOW_FILE), "utf8");
|
|
91897
91989
|
} catch {
|
|
91898
91990
|
return fail(`workflows/${id}/${WORKFLOW_FILE} is missing.`);
|
|
91899
91991
|
}
|
|
91900
|
-
const
|
|
91901
|
-
if ("problem" in
|
|
91902
|
-
const names2 = named(
|
|
91903
|
-
|
|
91992
|
+
const read2 = parseWorkflowFile(id, source, `workflows/${id}/${WORKFLOW_FILE}`);
|
|
91993
|
+
if ("problem" in read2) return fail(read2.problem);
|
|
91994
|
+
const names2 = named(read2.def);
|
|
91995
|
+
fs26.rmSync(path29.join(dir, "agents"), { recursive: true, force: true });
|
|
91904
91996
|
for (const name of names2) {
|
|
91905
|
-
const from =
|
|
91906
|
-
if (
|
|
91997
|
+
const from = path29.join(ws.board, "agents", name);
|
|
91998
|
+
if (fs26.existsSync(from)) fs26.cpSync(from, path29.join(dir, "agents", name), { recursive: true });
|
|
91907
91999
|
}
|
|
91908
|
-
const files = Object.fromEntries(filesUnder(dir).map((f2) => [f2,
|
|
92000
|
+
const files = Object.fromEntries(filesUnder(dir).map((f2) => [f2, fs26.readFileSync(path29.join(dir, f2), "utf8")]));
|
|
91909
92001
|
const checked = checkWorkflowFiles(files);
|
|
91910
92002
|
if (!checked.ok) return fail(`${checked.file} ${checked.reason}.`);
|
|
91911
92003
|
const run2 = async (args) => answerOf2(await runAkb(akb, [...args, "--json", "--board", ws.board], { cwd: ws.cwd, board: ws.board }));
|
|
@@ -91938,25 +92030,18 @@ function spentBy(runs) {
|
|
|
91938
92030
|
...context ? { context: { used: context.used, limit: context.limit } } : {}
|
|
91939
92031
|
};
|
|
91940
92032
|
}
|
|
91941
|
-
function
|
|
91942
|
-
let text3;
|
|
92033
|
+
function reviewOf2(file2) {
|
|
91943
92034
|
try {
|
|
91944
|
-
|
|
92035
|
+
const meta = parseFrontmatter(fs27.readFileSync(file2, "utf8")).meta;
|
|
92036
|
+
return meta ? reviewOf(meta) : null;
|
|
91945
92037
|
} catch {
|
|
91946
|
-
return
|
|
91947
|
-
}
|
|
91948
|
-
const questions = parseFrontmatter(text3).meta?.questions ?? [];
|
|
91949
|
-
for (const [i, q3] of questions.entries()) {
|
|
91950
|
-
if (openOf([q3]).length && q3.options?.length) {
|
|
91951
|
-
return { question: q3.text, options: q3.options.slice(0, 8), position: i + 1 };
|
|
91952
|
-
}
|
|
92038
|
+
return null;
|
|
91953
92039
|
}
|
|
91954
|
-
return void 0;
|
|
91955
92040
|
}
|
|
91956
92041
|
function mcpConfig(servers, file2) {
|
|
91957
92042
|
if (!Object.keys(servers).length) return null;
|
|
91958
|
-
|
|
91959
|
-
|
|
92043
|
+
fs27.mkdirSync(path30.dirname(file2), { recursive: true });
|
|
92044
|
+
fs27.writeFileSync(file2, `${JSON.stringify({ mcpServers: servers }, null, 2)}
|
|
91960
92045
|
`);
|
|
91961
92046
|
return file2;
|
|
91962
92047
|
}
|
|
@@ -91977,21 +92062,25 @@ async function stopRuns(akb, ws, id, since, ms) {
|
|
|
91977
92062
|
while (Date.now() < until) {
|
|
91978
92063
|
const runs = answerOf2(await call(["run", "list", "--card", String(id), "--all", "--json"]))?.runs;
|
|
91979
92064
|
const live = (runs ?? []).filter((r2) => r2.status === "running" && (r2.startedAt ?? 0) >= since);
|
|
91980
|
-
if (!
|
|
92065
|
+
if (!runs) return false;
|
|
92066
|
+
if (!live.length) return true;
|
|
91981
92067
|
for (const r2 of live) await call(["run", "stop", r2.sessionId]);
|
|
91982
92068
|
await wait(250);
|
|
91983
92069
|
}
|
|
92070
|
+
return false;
|
|
91984
92071
|
}
|
|
91985
92072
|
var working = /* @__PURE__ */ new Map();
|
|
91986
92073
|
var workKey = (ws, id) => `${ws.board}#${id}`;
|
|
91987
92074
|
async function stopLeftBehind(akb, ws, id, ms) {
|
|
91988
|
-
if (!working.has(workKey(ws, id))
|
|
92075
|
+
if (!working.has(workKey(ws, id)) && !await stopRuns(akb, ws, id, 0, ms)) {
|
|
92076
|
+
throw new Error("\u672A\u80FD\u505C\u6B62\u4E0A\u6B21\u8FD0\u884C\uFF0C\u8BF7\u7B49\u5F85\u5176\u505C\u6B62\u540E\u7EED\u8DD1\u3002");
|
|
92077
|
+
}
|
|
91989
92078
|
}
|
|
91990
92079
|
function deliveryEnding(ws, id) {
|
|
91991
92080
|
if (!id) return null;
|
|
91992
92081
|
let held4;
|
|
91993
92082
|
try {
|
|
91994
|
-
held4 = JSON.parse(
|
|
92083
|
+
held4 = JSON.parse(fs27.readFileSync(path30.join(ws.board, "deliveries", `${path30.basename(id)}.json`), "utf8"));
|
|
91995
92084
|
} catch {
|
|
91996
92085
|
return null;
|
|
91997
92086
|
}
|
|
@@ -92003,23 +92092,23 @@ function deliveryEnding(ws, id) {
|
|
|
92003
92092
|
return null;
|
|
92004
92093
|
}
|
|
92005
92094
|
function checkoutsOf(ws, id) {
|
|
92006
|
-
const dir =
|
|
92095
|
+
const dir = path30.join(ws.board, "deliveries");
|
|
92007
92096
|
let names2;
|
|
92008
92097
|
try {
|
|
92009
|
-
names2 =
|
|
92098
|
+
names2 = fs27.readdirSync(dir).filter((n) => n.endsWith(".json"));
|
|
92010
92099
|
} catch {
|
|
92011
92100
|
return [];
|
|
92012
92101
|
}
|
|
92013
92102
|
return names2.flatMap((n) => {
|
|
92014
92103
|
try {
|
|
92015
|
-
const held4 = JSON.parse(
|
|
92104
|
+
const held4 = JSON.parse(fs27.readFileSync(path30.join(dir, n), "utf8"));
|
|
92016
92105
|
return held4.cardId === id && held4.worktree && held4.deliveryId ? [held4.deliveryId] : [];
|
|
92017
92106
|
} catch {
|
|
92018
92107
|
return [];
|
|
92019
92108
|
}
|
|
92020
92109
|
});
|
|
92021
92110
|
}
|
|
92022
|
-
var
|
|
92111
|
+
var refusal = (ran) => ran.last.replace(/^akb( raw)?: /, "").slice(0, 300) || "akb stopped with an error.";
|
|
92023
92112
|
var firstLine = (text3) => (text3 ?? "").split("\n").map((l2) => l2.trim()).find(Boolean)?.slice(0, 300);
|
|
92024
92113
|
function logLines(show, event2) {
|
|
92025
92114
|
let held4 = "";
|
|
@@ -92071,33 +92160,29 @@ function boardAkb(job, ws, deps, io, task) {
|
|
|
92071
92160
|
return ran;
|
|
92072
92161
|
};
|
|
92073
92162
|
}
|
|
92074
|
-
function skillStale(dir, version) {
|
|
92075
|
-
try {
|
|
92076
|
-
const text3 = fs25.readFileSync(path28.join(dir, "SKILL.md"), "utf8");
|
|
92077
|
-
return !fs25.lstatSync(dir).isSymbolicLink() && /<!-- ai4kanban (\S+) -->\s*$/.exec(text3)?.[1] !== version;
|
|
92078
|
-
} catch {
|
|
92079
|
-
return true;
|
|
92080
|
-
}
|
|
92081
|
-
}
|
|
92082
92163
|
async function setUp(job, ws, deps, io) {
|
|
92083
92164
|
const akb = boardAkb(job, ws, deps, io);
|
|
92084
92165
|
const runtime = job.runtime;
|
|
92085
92166
|
const missing = unavailable(runtime, await deps.runtimes());
|
|
92086
92167
|
if (missing) return missing;
|
|
92087
|
-
if (!
|
|
92168
|
+
if (!fs27.existsSync(path30.join(ws.board, "config.md"))) {
|
|
92088
92169
|
const init = await akb(["raw", "init"]);
|
|
92089
|
-
if (init.code !== 0) return
|
|
92170
|
+
if (init.code !== 0) return refusal(init);
|
|
92090
92171
|
}
|
|
92091
|
-
|
|
92092
|
-
|
|
92093
|
-
|
|
92172
|
+
try {
|
|
92173
|
+
prepareKanbanSkill(ws.cwd);
|
|
92174
|
+
} catch (e2) {
|
|
92175
|
+
return e2 instanceof Error ? e2.message : String(e2);
|
|
92094
92176
|
}
|
|
92177
|
+
const hook = installCommitHook(ws.cwd, ws.board);
|
|
92178
|
+
if (hook.note) io.show(`${hook.note}
|
|
92179
|
+
`);
|
|
92095
92180
|
const pulled = await pull(ws, deps.machineId);
|
|
92096
92181
|
if (!pulled.ok) return pulled.error;
|
|
92097
92182
|
const used = await akb(["agent", "use", runtime]);
|
|
92098
|
-
if (used.code !== 0) return
|
|
92183
|
+
if (used.code !== 0) return refusal(used);
|
|
92099
92184
|
const servers = mcpServersOf(ws);
|
|
92100
|
-
const mcpFile =
|
|
92185
|
+
const mcpFile = path30.join(ws.board, ".sync", `${ws.task}.mcp.json`);
|
|
92101
92186
|
const takes = new Set(settingKeys(runtime));
|
|
92102
92187
|
const given = job.settings ?? {};
|
|
92103
92188
|
const values = { ...given, model: job.model ?? "" };
|
|
@@ -92107,7 +92192,7 @@ async function setUp(job, ws, deps, io) {
|
|
|
92107
92192
|
const valueOf = (key) => (secretKeys(runtime).includes(key) ? secrets[key] : values[key]) ?? "";
|
|
92108
92193
|
const set = async (key, value) => {
|
|
92109
92194
|
const done = await akb(["agent", "set", key, ...value ? key === RAW_ARGS_KEY ? ["--", value] : [value] : []]);
|
|
92110
|
-
return done.code === 0 ? null :
|
|
92195
|
+
return done.code === 0 ? null : refusal(done);
|
|
92111
92196
|
};
|
|
92112
92197
|
const provider = providerKey(runtime);
|
|
92113
92198
|
const rest = [...takes].filter((k) => k !== provider);
|
|
@@ -92133,26 +92218,26 @@ async function runReview(job, ws, tasks, deps, io) {
|
|
|
92133
92218
|
const ran = await akb(["review-memory", "--task", ...tasks, "--follow", "--events", "--json"], true);
|
|
92134
92219
|
if (io.lost()) return { ok: false, reason: "" };
|
|
92135
92220
|
const answer = answerOf2(ran);
|
|
92136
|
-
if (ran.code !== 0) return { ok: false, reason: firstLine(answer?.error?.message?.replace(/^run \S+ ended \w+: /, "")) ??
|
|
92221
|
+
if (ran.code !== 0) return { ok: false, reason: firstLine(answer?.error?.message?.replace(/^run \S+ ended \w+: /, "")) ?? refusal(ran) };
|
|
92137
92222
|
const runs = answerOf2(await akb(["run", "list", "--all", "--json"]))?.runs ?? [];
|
|
92138
92223
|
return { ok: true, report: { ...answer?.result?.trim() ? { reply: answer.result.trim() } : {}, ...spentBy(runs.filter((r2) => (r2.startedAt ?? 0) >= since)) } };
|
|
92139
92224
|
}
|
|
92140
92225
|
async function reviewRejections(job, ws, deps, io) {
|
|
92141
92226
|
const workspace = workspaceOf(ws);
|
|
92142
92227
|
if (!workspace) return { runs: [] };
|
|
92143
|
-
const
|
|
92144
|
-
if (!
|
|
92145
|
-
if (!
|
|
92228
|
+
const read2 = await deps.api.readRejections(workspace);
|
|
92229
|
+
if (!read2.ok) return { runs: [], failure: read2.error };
|
|
92230
|
+
if (!read2.value.tasks.length && !read2.value.triage.length) return { runs: [] };
|
|
92146
92231
|
const since = Date.now();
|
|
92147
92232
|
const akb = boardAkb(job, ws, deps, io);
|
|
92148
92233
|
return withBoard(ws, async (push2) => {
|
|
92149
|
-
const laid = layOut(ws.board,
|
|
92234
|
+
const laid = layOut(ws.board, read2.value);
|
|
92150
92235
|
const ran = await akb(["review-dismissals", "--follow", "--events", "--json"], true);
|
|
92151
92236
|
clearLaid(ws.board);
|
|
92152
92237
|
resetSorted(ws);
|
|
92153
92238
|
const runs = (answerOf2(await akb(["run", "list", "--all", "--json"]))?.runs ?? []).filter((r2) => (r2.startedAt ?? 0) >= since);
|
|
92154
92239
|
if (io.lost()) return { runs };
|
|
92155
|
-
if (ran.code !== 0) return { runs, failure:
|
|
92240
|
+
if (ran.code !== 0) return { runs, failure: refusal(ran) };
|
|
92156
92241
|
const sent = await push2({ id: job.id, machineId: deps.machineId });
|
|
92157
92242
|
if (!sent.ok) return { runs, failure: sent.error };
|
|
92158
92243
|
const marked = await deps.api.markReviewed(laid.tasks, laid.triage);
|
|
@@ -92165,12 +92250,12 @@ async function learnRejections(job, ws, deps, io) {
|
|
|
92165
92250
|
return runs;
|
|
92166
92251
|
}
|
|
92167
92252
|
async function scheduledEnv(ws, deps) {
|
|
92168
|
-
const
|
|
92169
|
-
if (!
|
|
92170
|
-
console.error(`runner: scheduled agents not read: ${
|
|
92253
|
+
const read2 = await deps.api.readAgents(deps.machineId, ws.project);
|
|
92254
|
+
if (!read2.ok) {
|
|
92255
|
+
console.error(`runner: scheduled agents not read: ${read2.error}`);
|
|
92171
92256
|
return {};
|
|
92172
92257
|
}
|
|
92173
|
-
const names2 =
|
|
92258
|
+
const names2 = read2.value.agents.filter((a3) => a3.workflow).map((a3) => a3.name);
|
|
92174
92259
|
return { [SCHEDULED_AGENTS_ENV]: [...new Set(names2)].join(",") };
|
|
92175
92260
|
}
|
|
92176
92261
|
async function runAgent(job, ws, deps, io) {
|
|
@@ -92191,25 +92276,25 @@ async function runAgent(job, ws, deps, io) {
|
|
|
92191
92276
|
const ran = await akb([...args, "--follow", "--events", "--json"], true, env2);
|
|
92192
92277
|
if (io.lost()) return { ok: false, reason: "" };
|
|
92193
92278
|
const answer = answerOf2(ran);
|
|
92194
|
-
if (ran.code !== 0) return { ok: false, reason: firstLine(answer?.error?.message?.replace(/^run \S+ ended \w+: /, "")) ??
|
|
92279
|
+
if (ran.code !== 0) return { ok: false, reason: firstLine(answer?.error?.message?.replace(/^run \S+ ended \w+: /, "")) ?? refusal(ran) };
|
|
92195
92280
|
const runs = answerOf2(await akb(["run", "list", "--all", "--json"]))?.runs ?? [];
|
|
92196
92281
|
return { ok: true, report: { ...answer?.result?.trim() ? { reply: answer.result.trim() } : {}, ...spentBy(runs.filter((r2) => (r2.startedAt ?? 0) >= since)) } };
|
|
92197
92282
|
}
|
|
92198
92283
|
function writeTranscript(job, dir) {
|
|
92199
92284
|
if (!job.transcript) return "";
|
|
92200
|
-
const file2 =
|
|
92201
|
-
|
|
92202
|
-
|
|
92285
|
+
const file2 = path30.join(dir, "discussion.md");
|
|
92286
|
+
fs27.mkdirSync(dir, { recursive: true });
|
|
92287
|
+
fs27.writeFileSync(file2, `${job.transcript}
|
|
92203
92288
|
`);
|
|
92204
92289
|
return file2;
|
|
92205
92290
|
}
|
|
92206
92291
|
function pictures(job, ws, id) {
|
|
92207
92292
|
const dir = cardAssetsDir(ws, id);
|
|
92208
92293
|
if (!job.attachments.length || !dir) return "";
|
|
92209
|
-
|
|
92294
|
+
fs27.mkdirSync(dir, { recursive: true });
|
|
92210
92295
|
return job.attachments.map((a3, i) => {
|
|
92211
|
-
const file2 = `${i + 1}-${
|
|
92212
|
-
|
|
92296
|
+
const file2 = `${i + 1}-${path30.basename(a3.name).replace(/[^\w.-]+/g, "-")}`;
|
|
92297
|
+
fs27.writeFileSync(path30.join(dir, file2), Buffer.from(a3.content, "base64"));
|
|
92213
92298
|
return `
|
|
92214
92299
|
<Asset src=".assets/${id}/${file2}" label="${a3.name.replace(/["<>]/g, "") || file2}" />
|
|
92215
92300
|
`;
|
|
@@ -92217,7 +92302,7 @@ function pictures(job, ws, id) {
|
|
|
92217
92302
|
}
|
|
92218
92303
|
function cardFlags(ws, fields) {
|
|
92219
92304
|
if (!fields) return [];
|
|
92220
|
-
const open = (keys) => (keys ?? []).map((k) => Number(/(\d+)$/.exec(k)?.[1])).filter((n) => n > 0 && n !== ws.number && findCard(ws.board, n)?.startsWith(
|
|
92305
|
+
const open = (keys) => (keys ?? []).map((k) => Number(/(\d+)$/.exec(k)?.[1])).filter((n) => n > 0 && n !== ws.number && findCard(ws.board, n)?.startsWith(path30.join(ws.board, "todo") + path30.sep));
|
|
92221
92306
|
const lists = [["--modules", fields.modules ?? []], ["--related", open(fields.related)], ["--blocked-by", open(fields.blocked_by)]];
|
|
92222
92307
|
return [
|
|
92223
92308
|
...fields.priority ? ["--priority", fields.priority] : [],
|
|
@@ -92231,7 +92316,7 @@ async function runFlow(job, ws, deps, io) {
|
|
|
92231
92316
|
const akb = boardAkb(job, ws, deps, io, ws.task);
|
|
92232
92317
|
const made = (ran) => {
|
|
92233
92318
|
const answer = answerOf2(ran);
|
|
92234
|
-
return ran.code === 0 && answer?.id ? { ok: true, value: answer.id } : { ok: false, error: answer?.error?.message ??
|
|
92319
|
+
return ran.code === 0 && answer?.id ? { ok: true, value: answer.id } : { ok: false, error: answer?.error?.message ?? refusal(ran), code: answer?.error?.kind };
|
|
92235
92320
|
};
|
|
92236
92321
|
if (flow.verb === "discard") return discardBuilds();
|
|
92237
92322
|
const failed = await setUp(job, ws, deps, io);
|
|
@@ -92251,10 +92336,10 @@ async function runFlow(job, ws, deps, io) {
|
|
|
92251
92336
|
const placed = await placeDraft(ws, deps.api);
|
|
92252
92337
|
if (!placed.ok) return fail(placed.error);
|
|
92253
92338
|
}
|
|
92254
|
-
const body =
|
|
92255
|
-
|
|
92339
|
+
const body = path30.join(ws.board, ".sync", `${ws.task}.request.md`);
|
|
92340
|
+
fs27.mkdirSync(path30.dirname(body), { recursive: true });
|
|
92256
92341
|
if (!ws.number) return fail("This task has no number yet.");
|
|
92257
|
-
|
|
92342
|
+
fs27.writeFileSync(body, `${said.request || title}
|
|
92258
92343
|
${isBuilder(ws) ? `
|
|
92259
92344
|
${draftLine(ws)}
|
|
92260
92345
|
` : ""}${pictures(job, ws, ws.number)}`);
|
|
@@ -92272,7 +92357,7 @@ ${draftLine(ws)}
|
|
|
92272
92357
|
...cardFlags(ws, flow.metadata),
|
|
92273
92358
|
"--json"
|
|
92274
92359
|
]));
|
|
92275
|
-
|
|
92360
|
+
fs27.rmSync(body, { force: true });
|
|
92276
92361
|
if (!created.ok) return fail(created.error);
|
|
92277
92362
|
id = created.value;
|
|
92278
92363
|
}
|
|
@@ -92282,19 +92367,27 @@ ${draftLine(ws)}
|
|
|
92282
92367
|
const held4 = working.get(key) ?? 0;
|
|
92283
92368
|
working.set(key, held4 + 1);
|
|
92284
92369
|
try {
|
|
92285
|
-
if (!held4
|
|
92370
|
+
if (!held4 && !await stopRuns(deps.akb, ws, card, 0, deps.stopMs)) {
|
|
92371
|
+
return fail("\u672A\u80FD\u505C\u6B62\u4E0A\u6B21\u8FD0\u884C\uFF0C\u8BF7\u7B49\u5F85\u5176\u505C\u6B62\u540E\u7EED\u8DD1\u3002");
|
|
92372
|
+
}
|
|
92286
92373
|
if (io.lost()) return fail("");
|
|
92287
92374
|
return await workOn(card);
|
|
92288
92375
|
} finally {
|
|
92289
|
-
|
|
92376
|
+
fs27.rmSync(path30.join(ws.board, ".sync", `${ws.task}.discussion`), { recursive: true, force: true });
|
|
92290
92377
|
const left = working.get(key) - 1;
|
|
92291
92378
|
if (left) working.set(key, left);
|
|
92292
92379
|
else working.delete(key);
|
|
92293
92380
|
}
|
|
92294
92381
|
async function workOn(id2) {
|
|
92295
|
-
io.onStop(() =>
|
|
92382
|
+
io.onStop(async () => {
|
|
92383
|
+
await stopRuns(deps.akb, ws, id2, since, deps.stopMs);
|
|
92384
|
+
});
|
|
92296
92385
|
const verb = flow.verb === "create" ? flow.skip_plan ? "implement" : "refine" : flow.verb;
|
|
92297
92386
|
const text3 = flow.verb === "create" ? "" : (flow.text ?? "").trim();
|
|
92387
|
+
if (flow.resume && verb === "refine") {
|
|
92388
|
+
const review2 = reviewOf2(cardFile(ws));
|
|
92389
|
+
if (review2) return { ok: true, report: { card: id2, ...review2 === true ? {} : { review: review2 } } };
|
|
92390
|
+
}
|
|
92298
92391
|
if (verb === "revise" && !text3) return fail("Say what to change.");
|
|
92299
92392
|
let note = verb === "resolve" || verb === "revise" ? text3 : "";
|
|
92300
92393
|
if (verb === "implement" && flow.resume) {
|
|
@@ -92313,9 +92406,10 @@ ${draftLine(ws)}
|
|
|
92313
92406
|
const ending = deliveryEnding(ws, answer?.delivery?.id ?? answer?.error?.delivery?.id);
|
|
92314
92407
|
if (ending) return ending;
|
|
92315
92408
|
}
|
|
92316
|
-
const
|
|
92317
|
-
|
|
92318
|
-
|
|
92409
|
+
const waiting = reviewOf2(cardFile(ws));
|
|
92410
|
+
const review = waiting && waiting !== true ? waiting : void 0;
|
|
92411
|
+
if (ran.code !== 0 && !(verb === "refine" && waiting) && !(verb === "implement" && answer?.error && review)) {
|
|
92412
|
+
return fail(firstLine(answer?.error?.message?.replace(/^run \S+ ended \w+: /, "")) ?? refusal(ran));
|
|
92319
92413
|
}
|
|
92320
92414
|
const last2 = answer?.lastSessionId ?? answer?.error?.lastSessionId;
|
|
92321
92415
|
const runs = answerOf2(await akb(["run", "list", "--card", String(id2), "--all", "--json"]))?.runs ?? [];
|
|
@@ -92333,13 +92427,13 @@ ${draftLine(ws)}
|
|
|
92333
92427
|
if (!card2) return { ok: true, report: {} };
|
|
92334
92428
|
for (const delivery of checkoutsOf(ws, card2)) {
|
|
92335
92429
|
const ran = await akb(["delivery", "discard", delivery, "--yes", "--json"], true);
|
|
92336
|
-
if (ran.code !== 0) return fail(
|
|
92430
|
+
if (ran.code !== 0) return fail(refusal(ran));
|
|
92337
92431
|
}
|
|
92338
92432
|
return { ok: true, report: { card: card2 } };
|
|
92339
92433
|
}
|
|
92340
92434
|
function carryArgs(verb) {
|
|
92341
92435
|
if (!["refine", "resolve", "revise", "implement"].includes(verb)) return [];
|
|
92342
|
-
const transcript = writeTranscript(job,
|
|
92436
|
+
const transcript = writeTranscript(job, path30.join(ws.board, ".sync", `${ws.task}.discussion`));
|
|
92343
92437
|
return [
|
|
92344
92438
|
...job.resume ? ["--session", job.resume, ...job.fork ? ["--fork"] : []] : [],
|
|
92345
92439
|
...transcript ? ["--transcript", transcript] : []
|
|
@@ -92347,18 +92441,55 @@ ${draftLine(ws)}
|
|
|
92347
92441
|
}
|
|
92348
92442
|
}
|
|
92349
92443
|
|
|
92444
|
+
// src/recovery.ts
|
|
92445
|
+
import fs28 from "node:fs";
|
|
92446
|
+
import path31 from "node:path";
|
|
92447
|
+
var PREPARE_REASON = "Runner update prepare.";
|
|
92448
|
+
var UPDATE_REASON = "Runner update checkpoint.";
|
|
92449
|
+
var UNCERTAIN = "\u66F4\u65B0\u4E2D\u65AD\u65F6\u6709\u64CD\u4F5C\u7ED3\u679C\u5C1A\u672A\u786E\u8BA4\uFF0C\u8BF7\u68C0\u67E5\u5DF2\u6709\u7ED3\u679C\u540E\u518D\u7EED\u8DD1\u3002";
|
|
92450
|
+
var fileOf = (id) => path31.join(runnerHome(), "checkpoints", `${encodeURIComponent(id)}.json`);
|
|
92451
|
+
function readCheckpoint(id) {
|
|
92452
|
+
try {
|
|
92453
|
+
const held4 = JSON.parse(fs28.readFileSync(fileOf(id), "utf8"));
|
|
92454
|
+
if (!held4 || !Array.isArray(held4.pending) || !held4.pending.every((id2) => typeof id2 === "string")) throw new Error("\u8FDB\u5EA6\u683C\u5F0F\u9519\u8BEF");
|
|
92455
|
+
return held4;
|
|
92456
|
+
} catch (e2) {
|
|
92457
|
+
if (e2.code === "ENOENT") return null;
|
|
92458
|
+
return { updating: true, started: true, pending: ["unknown"] };
|
|
92459
|
+
}
|
|
92460
|
+
}
|
|
92461
|
+
function saveCheckpoint(id, checkpoint) {
|
|
92462
|
+
const file2 = fileOf(id);
|
|
92463
|
+
fs28.mkdirSync(path31.dirname(file2), { recursive: true, mode: 448 });
|
|
92464
|
+
fs28.writeFileSync(`${file2}.tmp`, JSON.stringify(checkpoint), { mode: 384 });
|
|
92465
|
+
fs28.renameSync(`${file2}.tmp`, file2);
|
|
92466
|
+
}
|
|
92467
|
+
function clearCheckpoint(id) {
|
|
92468
|
+
fs28.rmSync(fileOf(id), { force: true });
|
|
92469
|
+
}
|
|
92470
|
+
function checkpointEvent(checkpoint, event2) {
|
|
92471
|
+
if (event2.kind === "tool_call") {
|
|
92472
|
+
const { toolCallId, status: status2, kind } = event2.data;
|
|
92473
|
+
if (["completed", "failed"].includes(status2)) checkpoint.pending = checkpoint.pending.filter((id) => id !== toolCallId);
|
|
92474
|
+
if (!["read", "search", "fetch"].includes(kind) && !["completed", "failed"].includes(status2) && !checkpoint.pending.includes(toolCallId)) checkpoint.pending.push(toolCallId);
|
|
92475
|
+
}
|
|
92476
|
+
if (event2.kind === "tool_call_update" && ["completed", "failed"].includes(event2.data.status)) {
|
|
92477
|
+
checkpoint.pending = checkpoint.pending.filter((id) => id !== event2.data.toolCallId);
|
|
92478
|
+
}
|
|
92479
|
+
}
|
|
92480
|
+
|
|
92350
92481
|
// src/lock.ts
|
|
92351
92482
|
import crypto4 from "node:crypto";
|
|
92352
|
-
import
|
|
92483
|
+
import fs29 from "node:fs";
|
|
92353
92484
|
import net from "node:net";
|
|
92354
|
-
import
|
|
92485
|
+
import path32 from "node:path";
|
|
92355
92486
|
var RETRY_MS = 5e3;
|
|
92356
92487
|
var KIND_MS = 1e3;
|
|
92357
|
-
var HOLDERS = ["claude-code", "codex", "terminal"
|
|
92488
|
+
var HOLDERS = ["claude-code", "codex", "terminal"];
|
|
92358
92489
|
function lockPath() {
|
|
92359
92490
|
const home4 = runnerHome();
|
|
92360
92491
|
if (process.platform === "win32") return `\\\\.\\pipe\\wildcrane-${crypto4.createHash("sha256").update(home4).digest("hex").slice(0, 16)}`;
|
|
92361
|
-
return
|
|
92492
|
+
return path32.join(home4, "runner.sock");
|
|
92362
92493
|
}
|
|
92363
92494
|
function holdMachine(kind, onHeld, onWaiting) {
|
|
92364
92495
|
const where = lockPath();
|
|
@@ -92373,7 +92504,7 @@ function holdMachine(kind, onHeld, onWaiting) {
|
|
|
92373
92504
|
const attempt = () => {
|
|
92374
92505
|
timer = null;
|
|
92375
92506
|
if (closed) return;
|
|
92376
|
-
if (process.platform !== "win32")
|
|
92507
|
+
if (process.platform !== "win32") fs29.mkdirSync(path32.dirname(where), { recursive: true, mode: 448 });
|
|
92377
92508
|
const s = net.createServer((peer) => {
|
|
92378
92509
|
peers.add(peer);
|
|
92379
92510
|
peer.on("error", () => {
|
|
@@ -92421,7 +92552,7 @@ function holdMachine(kind, onHeld, onWaiting) {
|
|
|
92421
92552
|
later(0);
|
|
92422
92553
|
});
|
|
92423
92554
|
removeIfStill.once("error", () => {
|
|
92424
|
-
|
|
92555
|
+
fs29.rmSync(where, { force: true });
|
|
92425
92556
|
later(50 + Math.random() * 200);
|
|
92426
92557
|
});
|
|
92427
92558
|
return;
|
|
@@ -92437,6 +92568,7 @@ function holdMachine(kind, onHeld, onWaiting) {
|
|
|
92437
92568
|
};
|
|
92438
92569
|
attempt();
|
|
92439
92570
|
return {
|
|
92571
|
+
waited: () => peers.size > 0,
|
|
92440
92572
|
release() {
|
|
92441
92573
|
if (closed) return;
|
|
92442
92574
|
closed = true;
|
|
@@ -92450,31 +92582,31 @@ function holdMachine(kind, onHeld, onWaiting) {
|
|
|
92450
92582
|
|
|
92451
92583
|
// src/jobs.ts
|
|
92452
92584
|
import { spawn as spawn4 } from "node:child_process";
|
|
92453
|
-
import
|
|
92454
|
-
import
|
|
92585
|
+
import fs32 from "node:fs";
|
|
92586
|
+
import path35 from "node:path";
|
|
92455
92587
|
|
|
92456
92588
|
// ../cli/src/lib/agent/catalog.ts
|
|
92457
|
-
import
|
|
92458
|
-
import
|
|
92589
|
+
import fs30 from "node:fs";
|
|
92590
|
+
import path33 from "node:path";
|
|
92459
92591
|
var CATALOGUE = "https://models.dev/api.json";
|
|
92460
92592
|
var FRESH_FOR_MS = 24 * 60 * 6e4;
|
|
92461
92593
|
var ANSWER_BY_MS = 2e4;
|
|
92462
92594
|
function cacheFile() {
|
|
92463
|
-
return
|
|
92595
|
+
return path33.join(machineHome(), "models-dev.json");
|
|
92464
92596
|
}
|
|
92465
92597
|
var held2;
|
|
92466
92598
|
function readCache() {
|
|
92467
92599
|
const file2 = cacheFile();
|
|
92468
92600
|
let stamp2;
|
|
92469
92601
|
try {
|
|
92470
|
-
const stat =
|
|
92602
|
+
const stat = fs30.statSync(file2);
|
|
92471
92603
|
stamp2 = `${stat.mtimeMs}:${stat.size}`;
|
|
92472
92604
|
} catch {
|
|
92473
92605
|
return void 0;
|
|
92474
92606
|
}
|
|
92475
92607
|
if (held2?.stamp === stamp2) return held2.cached;
|
|
92476
92608
|
try {
|
|
92477
|
-
const data = JSON.parse(
|
|
92609
|
+
const data = JSON.parse(fs30.readFileSync(file2, "utf8"));
|
|
92478
92610
|
if (!data || typeof data.limits !== "object" || !data.limits) return void 0;
|
|
92479
92611
|
const cached2 = {
|
|
92480
92612
|
fetchedAt: typeof data.fetchedAt === "number" ? data.fetchedAt : 0,
|
|
@@ -92513,8 +92645,8 @@ function refreshCatalog() {
|
|
|
92513
92645
|
const limits = limitsIn(await answer.json());
|
|
92514
92646
|
if (Object.keys(limits).length === 0) return;
|
|
92515
92647
|
const file2 = cacheFile();
|
|
92516
|
-
|
|
92517
|
-
|
|
92648
|
+
fs30.mkdirSync(path33.dirname(file2), { recursive: true });
|
|
92649
|
+
fs30.writeFileSync(file2, JSON.stringify({ fetchedAt: Date.now(), limits }));
|
|
92518
92650
|
} catch {
|
|
92519
92651
|
}
|
|
92520
92652
|
})();
|
|
@@ -92558,9 +92690,9 @@ function contextLimit(harness, model) {
|
|
|
92558
92690
|
}
|
|
92559
92691
|
|
|
92560
92692
|
// src/ideas.ts
|
|
92561
|
-
import
|
|
92562
|
-
import
|
|
92563
|
-
var ideasFileOf = (job) =>
|
|
92693
|
+
import fs31 from "node:fs";
|
|
92694
|
+
import path34 from "node:path";
|
|
92695
|
+
var ideasFileOf = (job) => path34.join(runnerHome(), "ideas", `${job.id}.json`);
|
|
92564
92696
|
async function writeIdeas(job, list) {
|
|
92565
92697
|
const workflows = [];
|
|
92566
92698
|
let after = null;
|
|
@@ -92571,18 +92703,18 @@ async function writeIdeas(job, list) {
|
|
|
92571
92703
|
after = page.value.next;
|
|
92572
92704
|
} while (after);
|
|
92573
92705
|
const file2 = ideasFileOf(job);
|
|
92574
|
-
|
|
92575
|
-
|
|
92706
|
+
fs31.mkdirSync(path34.dirname(file2), { recursive: true });
|
|
92707
|
+
fs31.writeFileSync(file2, `${JSON.stringify({ workflows, ideas: job.discussion.ideas }, null, 2)}
|
|
92576
92708
|
`);
|
|
92577
92709
|
return { file: file2 };
|
|
92578
92710
|
}
|
|
92579
92711
|
function readIdeas(file2) {
|
|
92580
92712
|
try {
|
|
92581
|
-
return JSON.parse(
|
|
92713
|
+
return JSON.parse(fs31.readFileSync(file2, "utf8")).ideas;
|
|
92582
92714
|
} catch {
|
|
92583
92715
|
return void 0;
|
|
92584
92716
|
} finally {
|
|
92585
|
-
|
|
92717
|
+
fs31.rmSync(file2, { force: true });
|
|
92586
92718
|
}
|
|
92587
92719
|
}
|
|
92588
92720
|
|
|
@@ -92618,32 +92750,32 @@ var defaultDeps = (machineId2) => ({
|
|
|
92618
92750
|
akb: currentAkb,
|
|
92619
92751
|
runtimes: detectRuntimes
|
|
92620
92752
|
});
|
|
92621
|
-
var ownFolder = () =>
|
|
92753
|
+
var ownFolder = () => path35.join(runnerHome(), "work");
|
|
92622
92754
|
function folderFor(job) {
|
|
92623
92755
|
if (!job.projectDir) {
|
|
92624
|
-
const cwd =
|
|
92625
|
-
|
|
92756
|
+
const cwd = path35.join(ownFolder(), job.id);
|
|
92757
|
+
fs32.mkdirSync(cwd, { recursive: true });
|
|
92626
92758
|
return { cwd };
|
|
92627
92759
|
}
|
|
92628
92760
|
const real = realpath4(job.projectDir);
|
|
92629
|
-
if (real && allowedProjects().some((root) => real === root || real.startsWith(root +
|
|
92761
|
+
if (real && allowedProjects().some((root) => real === root || real.startsWith(root + path35.sep))) return { cwd: real };
|
|
92630
92762
|
return { refused: `This Runner is not allowed to work in ${job.projectDir}.` };
|
|
92631
92763
|
}
|
|
92632
92764
|
function realpath4(p2) {
|
|
92633
92765
|
try {
|
|
92634
|
-
return
|
|
92766
|
+
return fs32.realpathSync(p2);
|
|
92635
92767
|
} catch {
|
|
92636
92768
|
return null;
|
|
92637
92769
|
}
|
|
92638
92770
|
}
|
|
92639
|
-
var attachmentsOf = (job) =>
|
|
92771
|
+
var attachmentsOf = (job) => path35.join(runnerHome(), "attachments", job.id);
|
|
92640
92772
|
function writeAttachments(job) {
|
|
92641
92773
|
if (!job.attachments.length) return "";
|
|
92642
92774
|
const dir = attachmentsOf(job);
|
|
92643
|
-
|
|
92775
|
+
fs32.mkdirSync(dir, { recursive: true });
|
|
92644
92776
|
const files = job.attachments.map((a3) => {
|
|
92645
|
-
const file2 =
|
|
92646
|
-
|
|
92777
|
+
const file2 = path35.join(dir, path35.basename(a3.name));
|
|
92778
|
+
fs32.writeFileSync(file2, Buffer.from(a3.content, "base64"));
|
|
92647
92779
|
return file2;
|
|
92648
92780
|
});
|
|
92649
92781
|
return `
|
|
@@ -92672,8 +92804,10 @@ function toWire(events, first) {
|
|
|
92672
92804
|
endLog();
|
|
92673
92805
|
return out;
|
|
92674
92806
|
}
|
|
92807
|
+
var leaseNow = () => ({ at: Date.now(), monotonic: performance.now() });
|
|
92675
92808
|
function streamOut(deps, id, lease) {
|
|
92676
92809
|
const wire = [];
|
|
92810
|
+
let firstSeq = null;
|
|
92677
92811
|
let pending = [];
|
|
92678
92812
|
let size = 0;
|
|
92679
92813
|
let lost = false;
|
|
@@ -92685,10 +92819,16 @@ function streamOut(deps, id, lease) {
|
|
|
92685
92819
|
};
|
|
92686
92820
|
const stored = new Promise((resolve2) => ended2 = resolve2);
|
|
92687
92821
|
const children = /* @__PURE__ */ new Set();
|
|
92822
|
+
const killed = /* @__PURE__ */ new Set();
|
|
92688
92823
|
const kill = (child) => {
|
|
92689
92824
|
if (!child.pid) return;
|
|
92690
|
-
child.
|
|
92691
|
-
|
|
92825
|
+
const exited = new Promise((resolve2) => child.once("close", () => resolve2()));
|
|
92826
|
+
killed.add(exited);
|
|
92827
|
+
void exited.then(() => killed.delete(exited));
|
|
92828
|
+
signalTree(child, "SIGTERM");
|
|
92829
|
+
const timer = setTimeout(() => signalTree(child, "SIGKILL"), KILL_GRACE_MS);
|
|
92830
|
+
timer.unref();
|
|
92831
|
+
void exited.then(() => clearTimeout(timer));
|
|
92692
92832
|
};
|
|
92693
92833
|
let halt = null;
|
|
92694
92834
|
let stopping = Promise.resolve();
|
|
@@ -92707,11 +92847,18 @@ function streamOut(deps, id, lease) {
|
|
|
92707
92847
|
const loseLease = () => {
|
|
92708
92848
|
if (lost) return stopping;
|
|
92709
92849
|
lost = true;
|
|
92850
|
+
lease.lost = true;
|
|
92710
92851
|
for (const child of children) kill(child);
|
|
92711
|
-
|
|
92852
|
+
stopping = Promise.all([halt?.(), ...killed]).then(() => {
|
|
92853
|
+
});
|
|
92712
92854
|
return stopping;
|
|
92713
92855
|
};
|
|
92856
|
+
const valid = () => {
|
|
92857
|
+
if (!held3(deps, lease)) void loseLease();
|
|
92858
|
+
return !lost;
|
|
92859
|
+
};
|
|
92714
92860
|
const send3 = () => {
|
|
92861
|
+
if (!valid()) return;
|
|
92715
92862
|
const ws = log.ws;
|
|
92716
92863
|
if (!ws || ws.readyState !== WebSocket.OPEN || log.after === null) return;
|
|
92717
92864
|
const after = log.after;
|
|
@@ -92735,15 +92882,17 @@ function streamOut(deps, id, lease) {
|
|
|
92735
92882
|
};
|
|
92736
92883
|
const flush = () => {
|
|
92737
92884
|
flushedAt = Date.now();
|
|
92738
|
-
if (pending.length)
|
|
92739
|
-
|
|
92885
|
+
if (firstSeq !== null && pending.length) {
|
|
92886
|
+
wire.push(...toWire(pending, firstSeq + wire.length));
|
|
92887
|
+
pending = [];
|
|
92888
|
+
}
|
|
92740
92889
|
size = 0;
|
|
92741
92890
|
send3();
|
|
92742
92891
|
};
|
|
92743
92892
|
const connect2 = async () => {
|
|
92744
92893
|
log.retry = void 0;
|
|
92745
92894
|
const ws = await deps.api.openLog(deps.machineId, id).catch(() => null);
|
|
92746
|
-
if (closed) return ws?.close();
|
|
92895
|
+
if (closed || !valid()) return ws?.close();
|
|
92747
92896
|
if (!ws) return reconnect();
|
|
92748
92897
|
log.ws = ws;
|
|
92749
92898
|
log.heard = Date.now();
|
|
@@ -92758,6 +92907,7 @@ function streamOut(deps, id, lease) {
|
|
|
92758
92907
|
if (said.type === "hello") {
|
|
92759
92908
|
log.tries = 0;
|
|
92760
92909
|
log.after = Number.isInteger(said.after) ? said.after : -1;
|
|
92910
|
+
firstSeq ??= log.after + 1;
|
|
92761
92911
|
log.watched = said.watched === true;
|
|
92762
92912
|
flush();
|
|
92763
92913
|
} else if (said.type === "watched") {
|
|
@@ -92782,6 +92932,7 @@ function streamOut(deps, id, lease) {
|
|
|
92782
92932
|
};
|
|
92783
92933
|
void connect2();
|
|
92784
92934
|
const event2 = (e2) => {
|
|
92935
|
+
if (!valid()) return;
|
|
92785
92936
|
if (e2.kind === "message") messages.push(e2.data.text);
|
|
92786
92937
|
pending.push(e2);
|
|
92787
92938
|
size += JSON.stringify(e2.data).length;
|
|
@@ -92797,11 +92948,19 @@ function streamOut(deps, id, lease) {
|
|
|
92797
92948
|
drop(ws);
|
|
92798
92949
|
ws.close();
|
|
92799
92950
|
}, deps.logPingMs);
|
|
92951
|
+
const expiry = setInterval(valid, Math.min(1e3, deps.leaseMs));
|
|
92952
|
+
let renewing = false;
|
|
92800
92953
|
const renewer = setInterval(async () => {
|
|
92801
|
-
|
|
92954
|
+
if (renewing || !valid()) return;
|
|
92955
|
+
renewing = true;
|
|
92956
|
+
const requestedAt = leaseNow();
|
|
92957
|
+
const renewed = await deps.api.renewJob(deps.machineId, id).catch(() => null).finally(() => {
|
|
92958
|
+
renewing = false;
|
|
92959
|
+
});
|
|
92960
|
+
if (!valid() || closed || !renewed) return;
|
|
92802
92961
|
if (renewed.ok && !renewed.value.renewed) return void loseLease();
|
|
92803
92962
|
if (!renewed.ok) return;
|
|
92804
|
-
lease
|
|
92963
|
+
Object.assign(lease, requestedAt);
|
|
92805
92964
|
if (renewed.value.stop) ask();
|
|
92806
92965
|
if (log.ws?.readyState === WebSocket.OPEN) log.ws.send(JSON.stringify({ type: "alive" }));
|
|
92807
92966
|
}, deps.renewMs);
|
|
@@ -92811,7 +92970,7 @@ function streamOut(deps, id, lease) {
|
|
|
92811
92970
|
if (text3) event2({ kind: "log", data: { text: text3 } });
|
|
92812
92971
|
},
|
|
92813
92972
|
adopt: (child) => {
|
|
92814
|
-
if (
|
|
92973
|
+
if (!valid() || asked) return kill(child);
|
|
92815
92974
|
children.add(child);
|
|
92816
92975
|
child.on("close", () => children.delete(child));
|
|
92817
92976
|
},
|
|
@@ -92822,7 +92981,7 @@ function streamOut(deps, id, lease) {
|
|
|
92822
92981
|
/** What stopping the job's board runs is still doing. */
|
|
92823
92982
|
halted: () => stopping,
|
|
92824
92983
|
stop: loseLease,
|
|
92825
|
-
lost: () =>
|
|
92984
|
+
lost: () => !valid(),
|
|
92826
92985
|
asked: () => asked,
|
|
92827
92986
|
whenAsked: askedOnce,
|
|
92828
92987
|
/** The agent's messages so far. */
|
|
@@ -92832,6 +92991,7 @@ function streamOut(deps, id, lease) {
|
|
|
92832
92991
|
clearInterval(flusher);
|
|
92833
92992
|
clearInterval(pinger);
|
|
92834
92993
|
clearInterval(renewer);
|
|
92994
|
+
clearInterval(expiry);
|
|
92835
92995
|
ending = !lost;
|
|
92836
92996
|
flush();
|
|
92837
92997
|
if (ending) {
|
|
@@ -92844,27 +93004,41 @@ function streamOut(deps, id, lease) {
|
|
|
92844
93004
|
const ws = log.ws;
|
|
92845
93005
|
log.ws = null;
|
|
92846
93006
|
ws?.close();
|
|
93007
|
+
await stopping;
|
|
92847
93008
|
}
|
|
92848
93009
|
};
|
|
92849
93010
|
}
|
|
92850
93011
|
async function runJob(id, deps, track = () => {
|
|
92851
|
-
}) {
|
|
93012
|
+
}, stopped2 = () => false) {
|
|
93013
|
+
const lease = leaseNow();
|
|
92852
93014
|
const claim = await deps.api.claimJob(deps.machineId, id);
|
|
92853
|
-
if (!claim.ok || !claim.value.claimed) return;
|
|
93015
|
+
if (!claim.ok || !claim.value.claimed || stopped2() || !held3(deps, lease)) return;
|
|
92854
93016
|
const job = claim.value.job;
|
|
92855
|
-
const
|
|
93017
|
+
const releases = [];
|
|
92856
93018
|
try {
|
|
92857
|
-
await runClaimed(job, { ...deps, akb: deps.akb() }, track, (dir) =>
|
|
93019
|
+
await runClaimed(job, { ...deps, akb: deps.akb() }, track, (dir) => releases.push(hold(dir)), lease);
|
|
92858
93020
|
} finally {
|
|
92859
|
-
for (const release2 of
|
|
92860
|
-
|
|
93021
|
+
for (const release2 of releases) release2();
|
|
93022
|
+
fs32.rmSync(attachmentsOf(job), { recursive: true, force: true });
|
|
92861
93023
|
}
|
|
92862
93024
|
}
|
|
92863
|
-
async function runClaimed(job, deps, track, keep2) {
|
|
93025
|
+
async function runClaimed(job, deps, track, keep2, lease) {
|
|
92864
93026
|
const id = job.id;
|
|
93027
|
+
const checkpoint = readCheckpoint(id) ?? { pending: [] };
|
|
93028
|
+
const recovering = checkpoint.updating === true;
|
|
93029
|
+
const persist = () => {
|
|
93030
|
+
checkpoint.updating ||= readCheckpoint(id)?.updating;
|
|
93031
|
+
saveCheckpoint(id, checkpoint);
|
|
93032
|
+
};
|
|
93033
|
+
if (recovering && !checkpoint.completed && (checkpoint.pending.length || checkpoint.opaque || !job.flow && checkpoint.started && !checkpoint.session)) {
|
|
93034
|
+
await deps.api.finishJob(deps.machineId, id, "failed", UNCERTAIN);
|
|
93035
|
+
return;
|
|
93036
|
+
}
|
|
93037
|
+
if (recovering && checkpoint.session) job = { ...job, resume: checkpoint.session, fork: false };
|
|
93038
|
+
if (!recovering) persist();
|
|
92865
93039
|
if (job.secret) return runSecret(job, deps);
|
|
92866
93040
|
if (job.test) return runTest(job, deps);
|
|
92867
|
-
if (job.agent) return runAgentJob(job, deps, track, keep2);
|
|
93041
|
+
if (job.agent) return runAgentJob(job, deps, track, keep2, lease, checkpoint, persist);
|
|
92868
93042
|
const task = job.task ?? job.review?.tasks[0] ?? null;
|
|
92869
93043
|
const folder = task && !job.projectDir ? null : folderFor(job);
|
|
92870
93044
|
if (folder && "refused" in folder) {
|
|
@@ -92875,6 +93049,7 @@ async function runClaimed(job, deps, track, keep2) {
|
|
|
92875
93049
|
let cwd = folder?.cwd ?? "";
|
|
92876
93050
|
let run2 = null;
|
|
92877
93051
|
let fresh = null;
|
|
93052
|
+
let missingSessionOnly = false;
|
|
92878
93053
|
let ideas = null;
|
|
92879
93054
|
let discussed;
|
|
92880
93055
|
try {
|
|
@@ -92887,6 +93062,11 @@ async function runClaimed(job, deps, track, keep2) {
|
|
|
92887
93062
|
if (!pulled.ok) throw new Error(pulled.error);
|
|
92888
93063
|
}
|
|
92889
93064
|
}
|
|
93065
|
+
if (checkpoint.completed) {
|
|
93066
|
+
const done = checkpoint.completed;
|
|
93067
|
+
if (done.outcome === "failed" || !ws) return finish(deps, id, lease, done.outcome, done.reason, done.report);
|
|
93068
|
+
return sendBack(deps, id, lease, ws, done.report, () => keepChat(job, done.report.reply));
|
|
93069
|
+
}
|
|
92890
93070
|
if (job.flow && !ws) throw new Error("This job names no task.");
|
|
92891
93071
|
if (job.discussion && job.projectDir && folder) {
|
|
92892
93072
|
const board = openDiscussionFolder(job, folder.cwd);
|
|
@@ -92896,7 +93076,7 @@ async function runClaimed(job, deps, track, keep2) {
|
|
|
92896
93076
|
discussed = board.board;
|
|
92897
93077
|
}
|
|
92898
93078
|
if (job.discussion) {
|
|
92899
|
-
const wrote = await writeIdeas({ ...job, discussion: job.discussion }, deps.api.listWorkflows);
|
|
93079
|
+
const wrote = recovering && fs32.existsSync(ideasFileOf(job)) ? { file: ideasFileOf(job) } : await writeIdeas({ ...job, discussion: job.discussion }, deps.api.listWorkflows);
|
|
92900
93080
|
if ("error" in wrote) throw new Error(wrote.error);
|
|
92901
93081
|
ideas = wrote.file;
|
|
92902
93082
|
}
|
|
@@ -92909,32 +93089,61 @@ async function runClaimed(job, deps, track, keep2) {
|
|
|
92909
93089
|
This task came out of a discussion. Read it for what the card leaves out: ${file2}` : "";
|
|
92910
93090
|
const promptOf = (said2) => {
|
|
92911
93091
|
const lines = (head2 + said2).trim();
|
|
93092
|
+
const prompt = recovering && checkpoint.started ? "Runner \u66F4\u65B0\u540E\u7EE7\u7EED\u4E4B\u524D\u4E2D\u65AD\u7684\u4EFB\u52A1\u3002\u5148\u6838\u5BF9\u5DF2\u6709\u8FDB\u5EA6\u548C\u7ED3\u679C\uFF0C\u4FDD\u7559\u5B8C\u6210\u7684\u5DE5\u4F5C\uFF0C\u4E0D\u8981\u91CD\u590D\u5DF2\u7ECF\u6267\u884C\u7684\u64CD\u4F5C\u3002" : job.prompt;
|
|
92912
93093
|
return lines ? `${lines}
|
|
92913
93094
|
|
|
92914
93095
|
---
|
|
92915
93096
|
|
|
92916
|
-
${
|
|
93097
|
+
${prompt}` : prompt;
|
|
92917
93098
|
};
|
|
92918
93099
|
const planned = (resume, fork, said2 = "") => {
|
|
92919
93100
|
let p2 = deps.plan(job.runtime, promptOf(said2), cwd, resume, job.model, settingsOf(job), fork, job.languageLine ?? "");
|
|
92920
93101
|
if (ws) p2 = { ...p2, env: { ...p2.env, ...akbEnv(deps.akb, ws.board, ws.task, job.languageLine ?? "") } };
|
|
92921
93102
|
if (ideas) p2 = { ...p2, env: { ...p2.env, ...akbEnv(deps.akb, discussed, void 0, job.languageLine ?? ""), KANBAN_IDEAS: ideas } };
|
|
93103
|
+
if (job.chat || job.discussion) {
|
|
93104
|
+
const { CLAUDE_CODE_MAX_RETRIES: _2, ...env2 } = p2.env;
|
|
93105
|
+
p2 = { ...p2, env: env2 };
|
|
93106
|
+
}
|
|
92922
93107
|
return p2;
|
|
92923
93108
|
};
|
|
92924
93109
|
const carried = !!job.resume && (!job.fork || forks(job.runtime));
|
|
92925
93110
|
run2 = carried ? planned(job.resume, !!job.fork) : planned(null, false, transcript);
|
|
92926
|
-
if (carried && transcript) fresh = () => planned(null, false, transcript);
|
|
93111
|
+
if (!recovering && carried && transcript) fresh = () => planned(null, false, transcript);
|
|
93112
|
+
if (!recovering && carried && (job.chat || job.discussion)) {
|
|
93113
|
+
fresh = () => planned(null, false, transcript);
|
|
93114
|
+
missingSessionOnly = true;
|
|
93115
|
+
}
|
|
92927
93116
|
}
|
|
92928
93117
|
} catch (e2) {
|
|
92929
93118
|
await deps.api.finishJob(deps.machineId, id, "failed", e2 instanceof Error ? e2.message : String(e2));
|
|
92930
93119
|
return;
|
|
92931
93120
|
}
|
|
92932
|
-
|
|
93121
|
+
if (!held3(deps, lease)) return;
|
|
92933
93122
|
const stream = streamOut(deps, id, lease);
|
|
92934
|
-
const
|
|
93123
|
+
const remember = (event2) => {
|
|
93124
|
+
if (stream.lost()) return;
|
|
93125
|
+
checkpointEvent(checkpoint, event2);
|
|
93126
|
+
const session = run2?.session();
|
|
93127
|
+
if (session) checkpoint.session = session;
|
|
93128
|
+
persist();
|
|
93129
|
+
stream.event(event2);
|
|
93130
|
+
};
|
|
93131
|
+
const complete = (outcome, report2, reason) => {
|
|
93132
|
+
if (stream.lost()) return;
|
|
93133
|
+
checkpoint.completed = { outcome, report: report2, reason };
|
|
93134
|
+
checkpoint.session = report2.session ?? checkpoint.session;
|
|
93135
|
+
persist();
|
|
93136
|
+
};
|
|
93137
|
+
let savedIdeas;
|
|
93138
|
+
const told = (said2) => {
|
|
93139
|
+
if (ideas) savedIdeas ??= readIdeas(ideas);
|
|
93140
|
+
return savedIdeas ? { ...said2, ideas: savedIdeas } : said2;
|
|
93141
|
+
};
|
|
92935
93142
|
track(stream.stop);
|
|
92936
|
-
const io = { show: stream.out, event:
|
|
93143
|
+
const io = { show: stream.out, event: remember, track: stream.adopt, onStop: stream.onStop, lost: stream.lost };
|
|
92937
93144
|
if (job.review) {
|
|
93145
|
+
checkpoint.started = true;
|
|
93146
|
+
persist();
|
|
92938
93147
|
for (const task2 of job.review.tasks) {
|
|
92939
93148
|
const chat = await deps.api.readChat(task2);
|
|
92940
93149
|
if (chat.ok) keepCloudChat(task2, chat.value.messages);
|
|
@@ -92949,13 +93158,17 @@ ${job.prompt}` : job.prompt;
|
|
|
92949
93158
|
const marks = reviewMarks(tasks);
|
|
92950
93159
|
const refs = tasks.map((c2) => `${c2.task}:${c2.number}`);
|
|
92951
93160
|
const ended3 = refs.length ? await runReview(job, ws, refs, deps, io) : { ok: true, report: {} };
|
|
93161
|
+
if (ended3.ok) complete("done", ended3.report);
|
|
92952
93162
|
await stream.end();
|
|
92953
93163
|
if (stream.lost()) return;
|
|
92954
93164
|
if (!ended3.ok) return finish(deps, id, lease, "failed", ended3.reason);
|
|
92955
93165
|
return sendBack(deps, id, lease, ws, ended3.report, () => markReviewed2(marks));
|
|
92956
93166
|
}
|
|
92957
93167
|
if (!run2) {
|
|
93168
|
+
checkpoint.started = true;
|
|
93169
|
+
persist();
|
|
92958
93170
|
const ended3 = await runFlow(job, ws, deps, io);
|
|
93171
|
+
if (ended3.ok) complete("done", ended3.report);
|
|
92959
93172
|
const stopped2 = !ended3.ok && (stream.asked() || ended3.stopped === true);
|
|
92960
93173
|
if (stopped2 && stream.asked()) await stream.halted();
|
|
92961
93174
|
await stream.end();
|
|
@@ -92964,10 +93177,14 @@ ${job.prompt}` : job.prompt;
|
|
|
92964
93177
|
if (!ended3.ok) return finish(deps, id, lease, "failed", ended3.reason);
|
|
92965
93178
|
return sendBack(deps, id, lease, ws, ended3.report, () => keepChat(job, ended3.report.reply));
|
|
92966
93179
|
}
|
|
93180
|
+
checkpoint.started = true;
|
|
93181
|
+
checkpoint.opaque = !run2.converse && !run2.renderer?.events;
|
|
93182
|
+
checkpoint.session = run2.session() ?? checkpoint.session;
|
|
93183
|
+
persist();
|
|
92967
93184
|
if (run2.converse) {
|
|
92968
93185
|
const plan3 = run2;
|
|
92969
93186
|
const converse = run2.converse;
|
|
92970
|
-
const child = spawn4(plan3.command, plan3.args, { cwd, env: plan3.env, stdio: ["pipe", "pipe", "pipe"] });
|
|
93187
|
+
const child = spawn4(plan3.command, plan3.args, { cwd, env: plan3.env, detached: process.platform !== "win32", stdio: ["pipe", "pipe", "pipe"] });
|
|
92971
93188
|
stream.adopt(child);
|
|
92972
93189
|
child.stdin.on("error", () => {
|
|
92973
93190
|
});
|
|
@@ -92975,11 +93192,12 @@ ${job.prompt}` : job.prompt;
|
|
|
92975
93192
|
child.stderr.on("data", (chunk) => stream.out(quietLines(plan3, chunk)));
|
|
92976
93193
|
const spawned = new Promise((resolve2) => child.on("error", (e2) => resolve2(e2.message)));
|
|
92977
93194
|
const end = await Promise.race([
|
|
92978
|
-
converse(child,
|
|
93195
|
+
converse(child, remember),
|
|
92979
93196
|
spawned.then((error) => ({ ok: false, error })),
|
|
92980
93197
|
// Killed, the turn ends with what it said so far; one that never does is not waited on.
|
|
92981
93198
|
stream.whenAsked.then(() => wait2(KILL_GRACE_MS * 2)).then(() => ({ ok: true }))
|
|
92982
93199
|
]);
|
|
93200
|
+
if (!stream.asked()) complete(end.ok ? "done" : "failed", told(report(job, plan3, end)), end.ok ? void 0 : end.error);
|
|
92983
93201
|
stop(child);
|
|
92984
93202
|
await stream.end();
|
|
92985
93203
|
if (stream.lost()) return;
|
|
@@ -92989,7 +93207,7 @@ ${job.prompt}` : job.prompt;
|
|
|
92989
93207
|
return sendBack(deps, id, lease, ws, said2, () => keepChat(job, said2.reply));
|
|
92990
93208
|
}
|
|
92991
93209
|
const printed = async (plan3) => {
|
|
92992
|
-
const child = spawn4(plan3.command, plan3.args, { cwd, env: plan3.env, stdio: ["pipe", "pipe", "pipe"] });
|
|
93210
|
+
const child = spawn4(plan3.command, plan3.args, { cwd, env: plan3.env, detached: process.platform !== "win32", stdio: ["pipe", "pipe", "pipe"] });
|
|
92993
93211
|
stream.adopt(child);
|
|
92994
93212
|
child.stdin.on("error", () => {
|
|
92995
93213
|
});
|
|
@@ -92998,30 +93216,47 @@ ${job.prompt}` : job.prompt;
|
|
|
92998
93216
|
else child.stdin.end();
|
|
92999
93217
|
child.stdout.setEncoding("utf8");
|
|
93000
93218
|
const structured = !!renderer2.events;
|
|
93219
|
+
let stderr = "";
|
|
93220
|
+
let acted = false;
|
|
93001
93221
|
const fromAgent = (text3) => {
|
|
93002
|
-
if (!structured)
|
|
93003
|
-
|
|
93222
|
+
if (!structured) {
|
|
93223
|
+
if (text3.trim()) acted = true;
|
|
93224
|
+
stream.out(text3);
|
|
93225
|
+
}
|
|
93226
|
+
for (const e2 of renderer2.events?.() ?? []) {
|
|
93227
|
+
if (e2.kind === "message" || e2.kind === "tool_call" || e2.kind === "tool_call_update") acted = true;
|
|
93228
|
+
remember(e2);
|
|
93229
|
+
}
|
|
93004
93230
|
};
|
|
93005
93231
|
child.stdout.on("data", (chunk) => {
|
|
93006
93232
|
fromAgent(renderer2.push(chunk));
|
|
93007
93233
|
if (plan3.stdin && renderer2.result() !== void 0 && !child.stdin.writableEnded) child.stdin.end();
|
|
93008
93234
|
});
|
|
93009
93235
|
child.stderr.setEncoding("utf8");
|
|
93010
|
-
child.stderr.on("data", (chunk) =>
|
|
93236
|
+
child.stderr.on("data", (chunk) => {
|
|
93237
|
+
stderr = (stderr + chunk).slice(-EVENT_CHARS);
|
|
93238
|
+
stream.out(quietLines(plan3, chunk));
|
|
93239
|
+
});
|
|
93011
93240
|
const ended3 = await new Promise((resolve2) => {
|
|
93012
93241
|
child.on("error", (e2) => resolve2({ code: null, error: e2.message }));
|
|
93013
93242
|
child.on("close", (code) => resolve2({ code }));
|
|
93014
93243
|
});
|
|
93015
93244
|
fromAgent(renderer2.flush());
|
|
93016
|
-
return ended3;
|
|
93245
|
+
return { ...ended3, stderr, acted };
|
|
93017
93246
|
};
|
|
93018
93247
|
let plan2 = run2;
|
|
93019
93248
|
let ended2 = await printed(plan2);
|
|
93020
|
-
if (fresh && ended2.code !== 0 && plan2.renderer.result() === void 0 && !
|
|
93249
|
+
if (fresh && ended2.code !== 0 && plan2.renderer.result() === void 0 && !ended2.acted && (!missingSessionOnly || sessionMissing(`${ended2.stderr}
|
|
93250
|
+
${plan2.renderer.failure?.() ?? ""}`)) && !stream.asked() && !stream.lost()) {
|
|
93021
93251
|
plan2 = fresh();
|
|
93252
|
+
run2 = plan2;
|
|
93022
93253
|
ended2 = await printed(plan2);
|
|
93023
93254
|
}
|
|
93024
93255
|
const renderer = plan2.renderer;
|
|
93256
|
+
if (!stream.asked()) {
|
|
93257
|
+
const reason = ended2.error ?? renderer.failure?.() ?? (ended2.code === 0 ? void 0 : `Exited with code ${ended2.code}.`);
|
|
93258
|
+
complete(reason ? "failed" : "done", told(report(job, plan2)), reason);
|
|
93259
|
+
}
|
|
93025
93260
|
await stream.end();
|
|
93026
93261
|
if (stream.lost()) return;
|
|
93027
93262
|
const failure = stream.asked() ? void 0 : ended2.error ?? renderer.failure?.() ?? (ended2.code === 0 ? void 0 : `Exited with code ${ended2.code}.`);
|
|
@@ -93029,7 +93264,7 @@ ${job.prompt}` : job.prompt;
|
|
|
93029
93264
|
if (failure || !ws) return finish(deps, id, lease, failure ? "failed" : "done", failure, said);
|
|
93030
93265
|
return sendBack(deps, id, lease, ws, said, () => keepChat(job, said.reply));
|
|
93031
93266
|
}
|
|
93032
|
-
async function runAgentJob(job, deps, track, keep2) {
|
|
93267
|
+
async function runAgentJob(job, deps, track, keep2, lease, checkpoint, persist) {
|
|
93033
93268
|
const folder = job.projectDir ? folderFor(job) : { refused: "This project has no folder on this computer." };
|
|
93034
93269
|
let ws;
|
|
93035
93270
|
try {
|
|
@@ -93040,10 +93275,23 @@ async function runAgentJob(job, deps, track, keep2) {
|
|
|
93040
93275
|
await deps.api.finishJob(deps.machineId, job.id, "failed", e2 instanceof Error ? e2.message : String(e2));
|
|
93041
93276
|
return;
|
|
93042
93277
|
}
|
|
93043
|
-
|
|
93278
|
+
if (!held3(deps, lease)) return;
|
|
93279
|
+
if (checkpoint.completed) return sendBack(deps, job.id, lease, ws, checkpoint.completed.report, () => {
|
|
93280
|
+
});
|
|
93281
|
+
checkpoint.started = true;
|
|
93282
|
+
persist();
|
|
93044
93283
|
const stream = streamOut(deps, job.id, lease);
|
|
93045
93284
|
track(stream.stop);
|
|
93046
|
-
const ended2 = await runAgent(job, ws, deps, { show: stream.out, event:
|
|
93285
|
+
const ended2 = await runAgent(job, ws, deps, { show: stream.out, event: (event2) => {
|
|
93286
|
+
if (stream.lost()) return;
|
|
93287
|
+
checkpointEvent(checkpoint, event2);
|
|
93288
|
+
persist();
|
|
93289
|
+
stream.event(event2);
|
|
93290
|
+
}, track: stream.adopt, onStop: stream.onStop, lost: stream.lost });
|
|
93291
|
+
if (ended2.ok && !stream.lost()) {
|
|
93292
|
+
checkpoint.completed = { outcome: "done", report: ended2.report };
|
|
93293
|
+
persist();
|
|
93294
|
+
}
|
|
93047
93295
|
await stream.end();
|
|
93048
93296
|
if (stream.lost()) return;
|
|
93049
93297
|
if (!ended2.ok) return finish(deps, job.id, lease, "failed", ended2.reason);
|
|
@@ -93051,29 +93299,53 @@ async function runAgentJob(job, deps, track, keep2) {
|
|
|
93051
93299
|
}
|
|
93052
93300
|
var quietLines = (plan2, chunk) => chunk.split("\n").filter((line) => line && !plan2.quiet(line)).map((line) => `${line}
|
|
93053
93301
|
`).join("");
|
|
93302
|
+
var sessionMissing = (text3) => /\b(?:session|conversation|thread)\b[^\n]*(?:\bnot found\b|\bdoes not exist\b)/i.test(text3) || /\bno (?:conversation|session|thread) found\b/i.test(text3);
|
|
93303
|
+
function signalTree(child, signal) {
|
|
93304
|
+
if (!child.pid) return;
|
|
93305
|
+
if (process.platform === "win32") {
|
|
93306
|
+
const kill = spawn4("taskkill", ["/PID", String(child.pid), "/T", "/F"], { stdio: "ignore" });
|
|
93307
|
+
kill.on("error", () => child.kill(signal));
|
|
93308
|
+
return;
|
|
93309
|
+
}
|
|
93310
|
+
try {
|
|
93311
|
+
process.kill(-child.pid, signal);
|
|
93312
|
+
} catch {
|
|
93313
|
+
child.kill(signal);
|
|
93314
|
+
}
|
|
93315
|
+
}
|
|
93054
93316
|
var stop = (child) => {
|
|
93055
93317
|
if (!child.pid) return;
|
|
93056
|
-
child
|
|
93057
|
-
setTimeout(() => child
|
|
93318
|
+
signalTree(child, "SIGTERM");
|
|
93319
|
+
const timer = setTimeout(() => signalTree(child, "SIGKILL"), KILL_GRACE_MS);
|
|
93320
|
+
timer.unref();
|
|
93321
|
+
child.once("close", () => clearTimeout(timer));
|
|
93058
93322
|
};
|
|
93059
93323
|
var wait2 = (ms) => new Promise((resolve2) => setTimeout(resolve2, ms));
|
|
93060
|
-
var held3 = (deps, lease) =>
|
|
93324
|
+
var held3 = (deps, lease) => {
|
|
93325
|
+
if (Math.max(Date.now() - lease.at, performance.now() - lease.monotonic) >= deps.leaseMs) lease.lost = true;
|
|
93326
|
+
return !lease.lost;
|
|
93327
|
+
};
|
|
93061
93328
|
async function whileOffline(deps, id, lease, attempt) {
|
|
93062
|
-
|
|
93329
|
+
while (held3(deps, lease)) {
|
|
93063
93330
|
const out = await attempt();
|
|
93064
93331
|
if (!("offline" in out && out.offline) || !held3(deps, lease)) return out;
|
|
93065
93332
|
await wait2(deps.retryMs);
|
|
93333
|
+
if (!held3(deps, lease)) return null;
|
|
93334
|
+
const requestedAt = leaseNow();
|
|
93066
93335
|
const renewed = await deps.api.renewJob(deps.machineId, id);
|
|
93067
|
-
if (
|
|
93336
|
+
if (!held3(deps, lease)) return null;
|
|
93337
|
+
if (renewed.ok && renewed.value.renewed) Object.assign(lease, requestedAt);
|
|
93068
93338
|
if (renewed.ok && !renewed.value.renewed) return out;
|
|
93069
93339
|
}
|
|
93340
|
+
return null;
|
|
93070
93341
|
}
|
|
93071
93342
|
async function ended(deps, id, lease, outcome, reason = "", report2) {
|
|
93072
93343
|
const sent = await whileOffline(deps, id, lease, async () => {
|
|
93073
93344
|
const done = await deps.api.finishJob(deps.machineId, id, outcome, reason, report2);
|
|
93074
93345
|
return { offline: !done.ok && !done.code, finished: done.ok && done.value.finished };
|
|
93075
93346
|
});
|
|
93076
|
-
|
|
93347
|
+
if (sent?.finished) clearCheckpoint(id);
|
|
93348
|
+
return sent?.finished ?? false;
|
|
93077
93349
|
}
|
|
93078
93350
|
async function finish(deps, id, lease, outcome, reason = "", report2) {
|
|
93079
93351
|
await ended(deps, id, lease, outcome, reason, report2);
|
|
@@ -93084,6 +93356,7 @@ async function sendBack(deps, id, lease, ws, said, landed = () => {
|
|
|
93084
93356
|
if (built && !built.ok) return finish(deps, id, lease, "failed", built.reason, said);
|
|
93085
93357
|
const report2 = built ? { ...said, workflow: { files: built.files } } : said;
|
|
93086
93358
|
const pushed = await whileOffline(deps, id, lease, () => push(ws, { id, machineId: deps.machineId }));
|
|
93359
|
+
if (!pushed) return;
|
|
93087
93360
|
if (pushed.ok) {
|
|
93088
93361
|
if (await ended(deps, id, lease, "done", "", report2)) landed();
|
|
93089
93362
|
return;
|
|
@@ -93108,12 +93381,12 @@ async function runTest(job, deps) {
|
|
|
93108
93381
|
const report2 = (await deps.runtimes()).find((r2) => r2.name === job.runtime);
|
|
93109
93382
|
if (!report2?.installed) return finish2("failed", "not_installed");
|
|
93110
93383
|
if (report2.loggedIn === false) return finish2("failed", "signed_out");
|
|
93111
|
-
const cwd =
|
|
93112
|
-
|
|
93384
|
+
const cwd = path35.join(ownFolder(), "test");
|
|
93385
|
+
fs32.mkdirSync(cwd, { recursive: true });
|
|
93113
93386
|
const run2 = deps.plan(job.runtime, job.prompt, cwd, null, job.model, settingsOf(job));
|
|
93114
93387
|
const startedAt = Date.now();
|
|
93115
93388
|
if (run2.converse) {
|
|
93116
|
-
const child = spawn4(run2.command, run2.args, { cwd, env: run2.env, stdio: ["pipe", "pipe", "ignore"] });
|
|
93389
|
+
const child = spawn4(run2.command, run2.args, { cwd, env: run2.env, detached: process.platform !== "win32", stdio: ["pipe", "pipe", "ignore"] });
|
|
93117
93390
|
child.stdin.on("error", () => {
|
|
93118
93391
|
});
|
|
93119
93392
|
let timer;
|
|
@@ -93133,7 +93406,7 @@ async function runTest(job, deps) {
|
|
|
93133
93406
|
const renderer = run2.renderer;
|
|
93134
93407
|
const ended2 = await new Promise((resolve2) => {
|
|
93135
93408
|
let said = "";
|
|
93136
|
-
const child = spawn4(run2.command, run2.args, { cwd, env: run2.env, stdio: ["pipe", "pipe", "pipe"] });
|
|
93409
|
+
const child = spawn4(run2.command, run2.args, { cwd, env: run2.env, detached: process.platform !== "win32", stdio: ["pipe", "pipe", "pipe"] });
|
|
93137
93410
|
const timer = setTimeout(() => {
|
|
93138
93411
|
child.kill("SIGTERM");
|
|
93139
93412
|
setTimeout(() => child.kill("SIGKILL"), KILL_GRACE_MS).unref();
|
|
@@ -93267,6 +93540,7 @@ function startRunner(options) {
|
|
|
93267
93540
|
let registration = null;
|
|
93268
93541
|
let connected = false;
|
|
93269
93542
|
let closed = false;
|
|
93543
|
+
let preparing = false;
|
|
93270
93544
|
let attempts = 0;
|
|
93271
93545
|
let live = null;
|
|
93272
93546
|
let presence = null;
|
|
@@ -93274,7 +93548,10 @@ function startRunner(options) {
|
|
|
93274
93548
|
let timer = null;
|
|
93275
93549
|
let reading = false;
|
|
93276
93550
|
let readAgain = false;
|
|
93551
|
+
let readDone = Promise.resolve();
|
|
93552
|
+
const jobs = /* @__PURE__ */ new Set();
|
|
93277
93553
|
const running = /* @__PURE__ */ new Map();
|
|
93554
|
+
const attempted = /* @__PURE__ */ new Set();
|
|
93278
93555
|
let stop2 = () => {
|
|
93279
93556
|
};
|
|
93280
93557
|
const stopped2 = new Promise((resolve2) => stop2 = resolve2);
|
|
@@ -93283,7 +93560,7 @@ function startRunner(options) {
|
|
|
93283
93560
|
return { ...base, runtimes: () => base.runtimes().then(redetected) };
|
|
93284
93561
|
};
|
|
93285
93562
|
const register2 = async () => {
|
|
93286
|
-
const answer = await register(
|
|
93563
|
+
const answer = await register(registration);
|
|
93287
93564
|
if (answer.ok) void followAkb(answer.value.akb);
|
|
93288
93565
|
return answer;
|
|
93289
93566
|
};
|
|
@@ -93363,7 +93640,6 @@ function startRunner(options) {
|
|
|
93363
93640
|
}
|
|
93364
93641
|
if (answer.code === "runner_outdated") return finish2({ reason: "outdated" });
|
|
93365
93642
|
if (answer.code) return finish2({ reason: "refused", message: answer.error });
|
|
93366
|
-
if (connected) options.onDisconnected?.();
|
|
93367
93643
|
connected = false;
|
|
93368
93644
|
status(t.reconnecting());
|
|
93369
93645
|
return schedule(BACKOFF_MS3[Math.min(attempts++, BACKOFF_MS3.length - 1)]);
|
|
@@ -93400,29 +93676,39 @@ function startRunner(options) {
|
|
|
93400
93676
|
return;
|
|
93401
93677
|
}
|
|
93402
93678
|
if (payload.jobId || !(payload.alertId || payload.taskId)) void readJobs();
|
|
93403
|
-
options.onHint?.(payload);
|
|
93404
93679
|
},
|
|
93405
93680
|
onReady: () => {
|
|
93406
93681
|
void readJobs();
|
|
93407
93682
|
boards?.pullAll();
|
|
93408
|
-
options.onHint?.({});
|
|
93409
93683
|
}
|
|
93410
93684
|
});
|
|
93411
93685
|
};
|
|
93412
93686
|
const readJobs = async () => {
|
|
93413
|
-
if (closed || !registration) return;
|
|
93687
|
+
if (closed || preparing || !registration) return;
|
|
93414
93688
|
if (reading) {
|
|
93415
93689
|
readAgain = true;
|
|
93416
93690
|
return;
|
|
93417
93691
|
}
|
|
93418
93692
|
reading = true;
|
|
93693
|
+
let readEnded = () => {
|
|
93694
|
+
};
|
|
93695
|
+
readDone = new Promise((resolve2) => readEnded = resolve2);
|
|
93419
93696
|
try {
|
|
93420
93697
|
const list = await listJobs(registration.machineId);
|
|
93421
|
-
if (!list.ok) return;
|
|
93698
|
+
if (!list.ok || closed) return;
|
|
93699
|
+
const listed2 = new Set(list.value.jobs.map((job) => job.id));
|
|
93700
|
+
for (const id of attempted) if (!listed2.has(id) && !running.has(id)) attempted.delete(id);
|
|
93422
93701
|
for (const job of list.value.jobs) {
|
|
93423
|
-
if (
|
|
93424
|
-
|
|
93425
|
-
|
|
93702
|
+
if (closed || preparing) break;
|
|
93703
|
+
if (job.state === "claimed" && !running.has(job.id) && !attempted.has(job.id)) {
|
|
93704
|
+
const failure = await stopLeftOn(job);
|
|
93705
|
+
if (closed || preparing) break;
|
|
93706
|
+
const checkpoint = readCheckpoint(job.id);
|
|
93707
|
+
const uncertain = checkpoint?.updating && !checkpoint.completed && (checkpoint.pending.length > 0 || checkpoint.opaque || !job.flow && checkpoint.started && !checkpoint.session);
|
|
93708
|
+
if (checkpoint?.updating) status(uncertain ? UNCERTAIN : "\u6B63\u5728\u6062\u590D\u66F4\u65B0\u524D\u7684\u4EFB\u52A1\u2026");
|
|
93709
|
+
const reason = failure ?? (uncertain ? UNCERTAIN : checkpoint?.updating ? UPDATE_REASON : "The Runner restarted while this job was running.");
|
|
93710
|
+
const recovered = await finishJob(registration.machineId, job.id, "failed", reason, checkpoint?.session ? { session: checkpoint.session } : void 0);
|
|
93711
|
+
if (recovered.ok && reason === UPDATE_REASON) readAgain = true;
|
|
93426
93712
|
continue;
|
|
93427
93713
|
}
|
|
93428
93714
|
if (job.state !== "waiting" || running.has(job.id)) continue;
|
|
@@ -93430,6 +93716,7 @@ function startRunner(options) {
|
|
|
93430
93716
|
}
|
|
93431
93717
|
} finally {
|
|
93432
93718
|
reading = false;
|
|
93719
|
+
readEnded();
|
|
93433
93720
|
if (readAgain) {
|
|
93434
93721
|
readAgain = false;
|
|
93435
93722
|
void readJobs();
|
|
@@ -93440,12 +93727,12 @@ function startRunner(options) {
|
|
|
93440
93727
|
if (!job.flow || !job.task) return;
|
|
93441
93728
|
try {
|
|
93442
93729
|
const folder = job.projectDir ? folderFor(job) : null;
|
|
93443
|
-
if (folder && "refused" in folder) return;
|
|
93730
|
+
if (folder && "refused" in folder) return folder.refused;
|
|
93444
93731
|
const ws = openTaskFolder(job, folder?.cwd ?? null);
|
|
93445
93732
|
const card = akbCardOf(ws);
|
|
93446
93733
|
if (card) await stopLeftBehind(deps().akb(), ws, card, deps().stopMs);
|
|
93447
93734
|
} catch (e2) {
|
|
93448
|
-
|
|
93735
|
+
return e2 instanceof Error ? e2.message : String(e2);
|
|
93449
93736
|
}
|
|
93450
93737
|
};
|
|
93451
93738
|
let reviewing = false;
|
|
@@ -93461,32 +93748,57 @@ function startRunner(options) {
|
|
|
93461
93748
|
}
|
|
93462
93749
|
};
|
|
93463
93750
|
const start = (id) => {
|
|
93751
|
+
attempted.add(id);
|
|
93464
93752
|
running.set(id, null);
|
|
93465
93753
|
status(idle2());
|
|
93466
|
-
|
|
93754
|
+
const job = runJob(id, deps(), (halt) => {
|
|
93755
|
+
running.set(id, halt);
|
|
93756
|
+
if (closed) void halt();
|
|
93757
|
+
}, () => closed).catch(() => {
|
|
93467
93758
|
}).finally(() => {
|
|
93759
|
+
jobs.delete(job);
|
|
93468
93760
|
running.delete(id);
|
|
93469
93761
|
if (closed) return;
|
|
93470
93762
|
boards?.look();
|
|
93471
93763
|
status(idle2());
|
|
93472
93764
|
void readJobs();
|
|
93473
93765
|
});
|
|
93766
|
+
jobs.add(job);
|
|
93474
93767
|
};
|
|
93475
|
-
const close = async (release2 = true) => {
|
|
93768
|
+
const close = async (release2 = true, updating = false) => {
|
|
93476
93769
|
if (closed) return;
|
|
93770
|
+
if (updating) {
|
|
93771
|
+
preparing = true;
|
|
93772
|
+
await readDone;
|
|
93773
|
+
for (const id of running.keys()) {
|
|
93774
|
+
const prepared = await finishJob(registration.machineId, id, "failed", PREPARE_REASON);
|
|
93775
|
+
if (!prepared.ok || !prepared.value.prepared && !prepared.value.finished) {
|
|
93776
|
+
preparing = false;
|
|
93777
|
+
void readJobs();
|
|
93778
|
+
throw new Error("\u66F4\u65B0\u6682\u7F13\uFF1A\u672A\u80FD\u4FDD\u5B58\u4E91\u7AEF\u4EFB\u52A1\uFF0C\u7A0D\u540E\u91CD\u8BD5\u3002");
|
|
93779
|
+
}
|
|
93780
|
+
}
|
|
93781
|
+
}
|
|
93477
93782
|
closed = true;
|
|
93478
|
-
|
|
93783
|
+
if (updating) {
|
|
93784
|
+
for (const id of running.keys()) {
|
|
93785
|
+
const checkpoint = readCheckpoint(id) ?? { pending: [] };
|
|
93786
|
+
saveCheckpoint(id, { ...checkpoint, updating: true });
|
|
93787
|
+
}
|
|
93788
|
+
}
|
|
93479
93789
|
if (timer) clearTimeout(timer);
|
|
93480
93790
|
if (agentsTimer) clearTimeout(agentsTimer);
|
|
93481
93791
|
clearInterval(sweepTimer);
|
|
93482
93792
|
live?.close();
|
|
93483
93793
|
presence?.close();
|
|
93484
93794
|
boards?.close();
|
|
93485
|
-
const stops = Promise.all([...running.values()].map((halt) => halt?.()));
|
|
93795
|
+
const stops = Promise.all([readDone, ...jobs, ...[...running.values()].map((halt) => halt?.())]);
|
|
93486
93796
|
let timeout;
|
|
93487
|
-
|
|
93797
|
+
if (updating) await stops;
|
|
93798
|
+
else await Promise.race([stops, new Promise((resolve2) => timeout = setTimeout(resolve2, (options.deps?.stopMs ?? STOP_MS) + 1e3))]);
|
|
93488
93799
|
clearTimeout(timeout);
|
|
93489
|
-
if (release2 && registration) await release(registration.machineId);
|
|
93800
|
+
if (release2 && !lock.waited() && registration) await release(registration.machineId);
|
|
93801
|
+
lock.release();
|
|
93490
93802
|
};
|
|
93491
93803
|
removeLegacy();
|
|
93492
93804
|
pruneChats();
|
|
@@ -93494,15 +93806,9 @@ function startRunner(options) {
|
|
|
93494
93806
|
status(t.waitingHere(holder));
|
|
93495
93807
|
options.onWaiting?.(holder);
|
|
93496
93808
|
});
|
|
93497
|
-
return { stopped: stopped2, close: () => close(true), renew: () => schedule(0) };
|
|
93809
|
+
return { stopped: stopped2, close: () => close(true), update: () => close(false, true), renew: () => schedule(0) };
|
|
93498
93810
|
}
|
|
93499
93811
|
|
|
93500
|
-
// src/desktop.ts
|
|
93501
|
-
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
93502
|
-
import fs30 from "node:fs";
|
|
93503
|
-
import path33 from "node:path";
|
|
93504
|
-
import readline from "node:readline";
|
|
93505
|
-
|
|
93506
93812
|
// src/signin.ts
|
|
93507
93813
|
import { spawn as spawn5 } from "node:child_process";
|
|
93508
93814
|
import crypto5 from "node:crypto";
|
|
@@ -93603,254 +93909,10 @@ function openBrowser(url) {
|
|
|
93603
93909
|
}
|
|
93604
93910
|
var base64url = (bytes2) => bytes2.toString("base64").replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
93605
93911
|
|
|
93606
|
-
// src/desktop.ts
|
|
93607
|
-
var DESKTOP_PROTOCOL = 1;
|
|
93608
|
-
var POLL_MS2 = 6e4;
|
|
93609
|
-
var RETRY_MS3 = 6e4;
|
|
93610
|
-
var WEB_URL = () => (process.env.WILDCRANE_WEB_URL || "https://app.wildcrane.ai").replace(/\/+$/, "");
|
|
93611
|
-
var taskUrl = (task) => `${WEB_URL()}/tasks/${encodeURIComponent(task)}`;
|
|
93612
|
-
function emit(event2) {
|
|
93613
|
-
process.stdout.write(`${JSON.stringify(event2)}
|
|
93614
|
-
`);
|
|
93615
|
-
}
|
|
93616
|
-
var COMMENT_CHARS = 100;
|
|
93617
|
-
function notice(alert, lines = t) {
|
|
93618
|
-
if (alert.kind === "review") return { title: lines.reviewTitle(), body: lines.reviewBody(alert.task_title) };
|
|
93619
|
-
if (alert.kind === "comment") {
|
|
93620
|
-
const chars = Array.from((alert.comment?.body ?? "").replace(/\s+/g, " ").trim());
|
|
93621
|
-
const text3 = chars.length > COMMENT_CHARS ? `${chars.slice(0, COMMENT_CHARS).join("")}\u2026` : chars.join("");
|
|
93622
|
-
const who = alert.comment?.author.handle || alert.comment?.author.email || "";
|
|
93623
|
-
return { title: lines.commentTitle(alert.task_title), body: lines.commentBody(who, text3) };
|
|
93624
|
-
}
|
|
93625
|
-
return { title: alert.kind === "done" ? lines.doneTitle() : lines.failedTitle(), body: alert.task_title };
|
|
93626
|
-
}
|
|
93627
|
-
function loginPath() {
|
|
93628
|
-
if (process.platform !== "darwin") return;
|
|
93629
|
-
const shell = process.env.SHELL || "/bin/zsh";
|
|
93630
|
-
const got = spawnSync5(shell, ["-ilc", 'printf "\\n%s" "$PATH"'], { encoding: "utf8", timeout: 5e3 });
|
|
93631
|
-
const found = got.status === 0 ? got.stdout.split("\n").pop()?.trim() : "";
|
|
93632
|
-
if (found) process.env.PATH = [.../* @__PURE__ */ new Set([...found.split(":"), ...(process.env.PATH ?? "").split(":")])].filter(Boolean).join(":");
|
|
93633
|
-
}
|
|
93634
|
-
async function runDesktop(tell2) {
|
|
93635
|
-
loginPath();
|
|
93636
|
-
const id = machineId();
|
|
93637
|
-
emit({ type: "hello", protocol: DESKTOP_PROTOCOL, version: VERSION, lang: isChinese() ? "zh" : "en", web: WEB_URL() });
|
|
93638
|
-
let runner = null;
|
|
93639
|
-
let signing = null;
|
|
93640
|
-
let notify = false;
|
|
93641
|
-
let folders2 = [];
|
|
93642
|
-
let lastInbox = "";
|
|
93643
|
-
let inboxTimer = null;
|
|
93644
|
-
let poller = null;
|
|
93645
|
-
const shown = /* @__PURE__ */ new Set();
|
|
93646
|
-
let wake = () => {
|
|
93647
|
-
};
|
|
93648
|
-
const readInbox2 = () => {
|
|
93649
|
-
if (inboxTimer) clearTimeout(inboxTimer);
|
|
93650
|
-
inboxTimer = setTimeout(async () => {
|
|
93651
|
-
const inbox = await readInbox();
|
|
93652
|
-
if (!inbox.ok) return;
|
|
93653
|
-
const items = (list) => list.map((i) => ({ ...i, url: taskUrl(i.task) }));
|
|
93654
|
-
const next = JSON.stringify({ type: "inbox", review: items(inbox.value.review), running: items(inbox.value.running) });
|
|
93655
|
-
if (next === lastInbox) return;
|
|
93656
|
-
lastInbox = next;
|
|
93657
|
-
process.stdout.write(`${next}
|
|
93658
|
-
`);
|
|
93659
|
-
}, 200);
|
|
93660
|
-
};
|
|
93661
|
-
const readAlerts = async () => {
|
|
93662
|
-
const list = await listAlerts(id);
|
|
93663
|
-
if (!list.ok) return;
|
|
93664
|
-
for (const alert of list.value.alerts) {
|
|
93665
|
-
if (shown.has(alert.id)) continue;
|
|
93666
|
-
shown.add(alert.id);
|
|
93667
|
-
if (notify) emit({ type: "notify", id: alert.id, ...notice(alert), url: taskUrl(alert.task) });
|
|
93668
|
-
await showAlert(id, alert.id);
|
|
93669
|
-
}
|
|
93670
|
-
};
|
|
93671
|
-
const readFolders = async () => {
|
|
93672
|
-
const list = await listFolders(id);
|
|
93673
|
-
if (!list.ok) return;
|
|
93674
|
-
folders2 = list.value.folders;
|
|
93675
|
-
for (const dir of keepOnly(folders2.map((f2) => f2.path))) clearAkb(dir);
|
|
93676
|
-
emit({ type: "folders", folders: folders2 });
|
|
93677
|
-
const elsewhere = await listElsewhere(id);
|
|
93678
|
-
if (elsewhere.ok) emit({ type: "elsewhere", projects: elsewhere.value.projects });
|
|
93679
|
-
};
|
|
93680
|
-
const readProfile2 = async () => {
|
|
93681
|
-
const session = readSession();
|
|
93682
|
-
const profile = await readProfile();
|
|
93683
|
-
const held4 = profile.ok ? profile.value.session : {};
|
|
93684
|
-
emit({
|
|
93685
|
-
type: "account",
|
|
93686
|
-
name: held4.name || held4.handle || session?.name || session?.handle || "",
|
|
93687
|
-
email: held4.email || session?.email || "",
|
|
93688
|
-
avatar: held4.avatarUrl || session?.avatarUrl || ""
|
|
93689
|
-
});
|
|
93690
|
-
};
|
|
93691
|
-
const readPlan2 = async () => {
|
|
93692
|
-
const read = await readPlan();
|
|
93693
|
-
if (!read.ok) return;
|
|
93694
|
-
const { billing, quota } = read.value;
|
|
93695
|
-
const paying = billing.plan === "pro" && (!billing.trialEnd || !!billing.grantEnd || billing.state !== "free");
|
|
93696
|
-
emit({
|
|
93697
|
-
type: "plan",
|
|
93698
|
-
plan: billing.plan,
|
|
93699
|
-
paying,
|
|
93700
|
-
limits: quota.limits,
|
|
93701
|
-
used: quota.used,
|
|
93702
|
-
pricing: `${cloudEndpoints().api}/pricing?lang=${isChinese() ? "zh" : "en"}`
|
|
93703
|
-
});
|
|
93704
|
-
};
|
|
93705
|
-
const readAll2 = () => {
|
|
93706
|
-
void readProfile2();
|
|
93707
|
-
void readFolders();
|
|
93708
|
-
void readPlan2();
|
|
93709
|
-
void readAlerts();
|
|
93710
|
-
readInbox2();
|
|
93711
|
-
};
|
|
93712
|
-
const onConnected = () => {
|
|
93713
|
-
tell2({ type: "connected" });
|
|
93714
|
-
emit({ type: "connection", state: "connected", machine: machineName() });
|
|
93715
|
-
readAll2();
|
|
93716
|
-
};
|
|
93717
|
-
const onWaiting = (holder) => {
|
|
93718
|
-
tell2({ type: "waiting" });
|
|
93719
|
-
emit({ type: "connection", state: "paused", ...holder ? { holder } : {} });
|
|
93720
|
-
readAll2();
|
|
93721
|
-
};
|
|
93722
|
-
const handle = async (command) => {
|
|
93723
|
-
switch (command.cmd) {
|
|
93724
|
-
case "signIn": {
|
|
93725
|
-
if (signing || readSession()) return;
|
|
93726
|
-
signing = new AbortController();
|
|
93727
|
-
const failure = await signIn({ signal: signing.signal, onUrl: (url) => emit({ type: "signin", state: "waiting", url }) });
|
|
93728
|
-
signing = null;
|
|
93729
|
-
if (failure) emit({ type: "signin", state: failure.why === "cancelled" ? "needed" : "failed", why: failure.why });
|
|
93730
|
-
else {
|
|
93731
|
-
emit({ type: "signin", state: "done" });
|
|
93732
|
-
wake("again");
|
|
93733
|
-
}
|
|
93734
|
-
return;
|
|
93735
|
-
}
|
|
93736
|
-
case "cancelSignIn":
|
|
93737
|
-
return signing?.abort();
|
|
93738
|
-
case "signOut":
|
|
93739
|
-
await runner?.close();
|
|
93740
|
-
runner = null;
|
|
93741
|
-
clearSession();
|
|
93742
|
-
lastInbox = "";
|
|
93743
|
-
return wake("again");
|
|
93744
|
-
case "notify":
|
|
93745
|
-
notify = command.on;
|
|
93746
|
-
return runner?.renew();
|
|
93747
|
-
case "refresh":
|
|
93748
|
-
readInbox2();
|
|
93749
|
-
return void readAlerts();
|
|
93750
|
-
case "read":
|
|
93751
|
-
await readAlert(command.alert);
|
|
93752
|
-
return readInbox2();
|
|
93753
|
-
case "addFolder": {
|
|
93754
|
-
const project = command.project;
|
|
93755
|
-
const why = refusal(command.path);
|
|
93756
|
-
if (why) return emit({ type: "folderRefused", why, project });
|
|
93757
|
-
const real = fs30.realpathSync(command.path);
|
|
93758
|
-
const added = await addFolder(id, path33.basename(real) || real, real, project);
|
|
93759
|
-
if (!added.ok) {
|
|
93760
|
-
const taken = added.code === "folder_taken";
|
|
93761
|
-
return emit({ type: "folderRefused", why: taken ? "taken" : "failed", project, ...taken ? { taken: added.project } : {} });
|
|
93762
|
-
}
|
|
93763
|
-
allow(real);
|
|
93764
|
-
return readFolders();
|
|
93765
|
-
}
|
|
93766
|
-
case "removeFolder": {
|
|
93767
|
-
const held4 = folders2.find((f2) => f2.project === command.project);
|
|
93768
|
-
const removed = await removeFolder(id, command.project);
|
|
93769
|
-
if (removed.ok && held4) for (const dir of disallow(held4.path)) clearAkb(dir);
|
|
93770
|
-
return readFolders();
|
|
93771
|
-
}
|
|
93772
|
-
case "folderNotify":
|
|
93773
|
-
await setFolderNotify(id, command.project, command.on);
|
|
93774
|
-
return readFolders();
|
|
93775
|
-
case "plan":
|
|
93776
|
-
return readPlan2();
|
|
93777
|
-
case "checkout": {
|
|
93778
|
-
const plan2 = await readPlan();
|
|
93779
|
-
if (command.item === "pro" && plan2.ok && plan2.value.billing.mayTrial) {
|
|
93780
|
-
const started = await startTrial();
|
|
93781
|
-
if (!started.ok) return emit({ type: "checkout", failed: true });
|
|
93782
|
-
return readPlan2();
|
|
93783
|
-
}
|
|
93784
|
-
const opened = await checkout(command.item);
|
|
93785
|
-
return emit(opened.ok ? { type: "checkout", url: opened.value.url } : { type: "checkout", failed: true });
|
|
93786
|
-
}
|
|
93787
|
-
case "quit":
|
|
93788
|
-
await runner?.close();
|
|
93789
|
-
return wake("quit");
|
|
93790
|
-
}
|
|
93791
|
-
};
|
|
93792
|
-
readline.createInterface({ input: process.stdin }).on("line", (line) => {
|
|
93793
|
-
let command;
|
|
93794
|
-
try {
|
|
93795
|
-
command = JSON.parse(line);
|
|
93796
|
-
} catch {
|
|
93797
|
-
return;
|
|
93798
|
-
}
|
|
93799
|
-
void handle(command);
|
|
93800
|
-
});
|
|
93801
|
-
process.stdin.on("end", () => void handle({ cmd: "quit" }));
|
|
93802
|
-
for (const signal of ["SIGINT", "SIGTERM"]) process.on(signal, () => void handle({ cmd: "quit" }));
|
|
93803
|
-
for (; ; ) {
|
|
93804
|
-
const next = new Promise((resolve2) => wake = resolve2);
|
|
93805
|
-
if (!readSession()) {
|
|
93806
|
-
emit({ type: "signin", state: "needed" });
|
|
93807
|
-
const why2 = await next;
|
|
93808
|
-
if (why2 === "quit") return 0;
|
|
93809
|
-
continue;
|
|
93810
|
-
}
|
|
93811
|
-
tell2({ type: "started" });
|
|
93812
|
-
emit({ type: "connection", state: "connecting" });
|
|
93813
|
-
runner = startRunner({
|
|
93814
|
-
registration: async () => ({ machineId: id, machineName: machineName(), version: VERSION, runtimes: await detectRuntimes(true) }),
|
|
93815
|
-
kind: "desktop",
|
|
93816
|
-
notify: () => notify,
|
|
93817
|
-
onConnected,
|
|
93818
|
-
onWaiting,
|
|
93819
|
-
onDisconnected: () => emit({ type: "connection", state: "reconnecting" }),
|
|
93820
|
-
onHint: (payload) => {
|
|
93821
|
-
if (payload.alertId || !payload.taskId) void readAlerts();
|
|
93822
|
-
if (!payload.jobId) readInbox2();
|
|
93823
|
-
}
|
|
93824
|
-
});
|
|
93825
|
-
poller = setInterval(() => {
|
|
93826
|
-
readInbox2();
|
|
93827
|
-
void readAlerts();
|
|
93828
|
-
}, POLL_MS2);
|
|
93829
|
-
void runner.stopped.then(wake);
|
|
93830
|
-
const why = await next;
|
|
93831
|
-
if (poller) clearInterval(poller);
|
|
93832
|
-
if (why === "quit") return 0;
|
|
93833
|
-
if (why === "again") continue;
|
|
93834
|
-
runner = null;
|
|
93835
|
-
if (why.reason === "outdated") return EXIT_OUTDATED;
|
|
93836
|
-
emit({ type: "connection", state: why.reason, ...why.reason === "elsewhere" ? { machine: why.machine } : {} });
|
|
93837
|
-
const again = new Promise((resolve2) => wake = resolve2);
|
|
93838
|
-
const retry2 = setTimeout(() => wake("again"), RETRY_MS3);
|
|
93839
|
-
const after = await again;
|
|
93840
|
-
clearTimeout(retry2);
|
|
93841
|
-
if (after === "quit") return 0;
|
|
93842
|
-
}
|
|
93843
|
-
}
|
|
93844
|
-
|
|
93845
93912
|
// src/main.ts
|
|
93846
93913
|
var tell = (message) => process.send?.(message);
|
|
93847
93914
|
async function main() {
|
|
93848
93915
|
useRunnerHome();
|
|
93849
|
-
if (process.env.WILDCRANE_DESKTOP) {
|
|
93850
|
-
const code = await runDesktop(tell);
|
|
93851
|
-
status(t.stopped());
|
|
93852
|
-
process.exit(code);
|
|
93853
|
-
}
|
|
93854
93916
|
if (!readSession()) {
|
|
93855
93917
|
const failure = await signIn();
|
|
93856
93918
|
if (failure) {
|
|
@@ -93863,12 +93925,21 @@ async function main() {
|
|
|
93863
93925
|
const id = machineId();
|
|
93864
93926
|
const runner = startRunner({
|
|
93865
93927
|
registration: async () => ({ machineId: id, machineName: machineName(), version: VERSION, runtimes: await detectRuntimes(true) }),
|
|
93866
|
-
kind: "terminal",
|
|
93928
|
+
kind: process.env.WILDCRANE_RUNNER_KIND === "codex" ? "codex" : process.env.WILDCRANE_RUNNER_KIND === "claude-code" ? "claude-code" : "terminal",
|
|
93867
93929
|
onConnected: () => tell({ type: "connected" }),
|
|
93868
93930
|
onWaiting: () => tell({ type: "waiting" }),
|
|
93869
93931
|
// Tests shorten the job poll, which stands in when Realtime is out of reach.
|
|
93870
93932
|
pollMs: Number(process.env.WILDCRANE_POLL_MS) || void 0
|
|
93871
93933
|
});
|
|
93934
|
+
process.on("message", (message) => {
|
|
93935
|
+
if (message.type === "renew") return runner.renew();
|
|
93936
|
+
if (message.type !== "update") return;
|
|
93937
|
+
status("\u6B63\u5728\u66F4\u65B0 Runner\uFF0C\u91CD\u542F\u540E\u81EA\u52A8\u6062\u590D\u4EFB\u52A1\u2026");
|
|
93938
|
+
void runner.update().then(() => process.exit(EXIT_UPDATE)).catch((error) => {
|
|
93939
|
+
status(String(error));
|
|
93940
|
+
tell({ type: "update-deferred" });
|
|
93941
|
+
});
|
|
93942
|
+
});
|
|
93872
93943
|
for (const signal of ["SIGINT", "SIGTERM"]) {
|
|
93873
93944
|
process.on(signal, async () => {
|
|
93874
93945
|
await runner.close();
|