@open-code-review/cli 2.2.0 → 2.3.0
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 +9 -0
- package/dist/dashboard/client/assets/{_basePickBy-BBPb8BJA.js → _basePickBy-CyrHyeyN.js} +1 -1
- package/dist/dashboard/client/assets/{_baseUniq-CFHdos6T.js → _baseUniq-Bg7NJSGS.js} +1 -1
- package/dist/dashboard/client/assets/{arc-BKGGWA2F.js → arc-zDGAKMur.js} +1 -1
- package/dist/dashboard/client/assets/{architectureDiagram-VXUJARFQ-B_ovNjX1.js → architectureDiagram-VXUJARFQ-BxlGxm0Q.js} +1 -1
- package/dist/dashboard/client/assets/{blockDiagram-VD42YOAC-C2M-avVp.js → blockDiagram-VD42YOAC-BskTNyX5.js} +1 -1
- package/dist/dashboard/client/assets/{c4Diagram-YG6GDRKO-BtOBpAzH.js → c4Diagram-YG6GDRKO-Dr9QQ-dn.js} +1 -1
- package/dist/dashboard/client/assets/channel-BUnm_-UQ.js +1 -0
- package/dist/dashboard/client/assets/{chunk-4BX2VUAB-Cz2EbHPl.js → chunk-4BX2VUAB-xq9xoCTv.js} +1 -1
- package/dist/dashboard/client/assets/{chunk-55IACEB6-C8xpXw9G.js → chunk-55IACEB6-DYdXYVh5.js} +1 -1
- package/dist/dashboard/client/assets/{chunk-B4BG7PRW-BSRfOovX.js → chunk-B4BG7PRW-BGAyFRFS.js} +1 -1
- package/dist/dashboard/client/assets/{chunk-DI55MBZ5-CEUbYQWn.js → chunk-DI55MBZ5-C5ul9stk.js} +1 -1
- package/dist/dashboard/client/assets/{chunk-FMBD7UC4-5xWP6GRj.js → chunk-FMBD7UC4-BSaPo2xa.js} +1 -1
- package/dist/dashboard/client/assets/{chunk-QN33PNHL-DfNCVcy8.js → chunk-QN33PNHL-CyzabUv0.js} +1 -1
- package/dist/dashboard/client/assets/{chunk-QZHKN3VN--OdToKKu.js → chunk-QZHKN3VN-CceRbxt_.js} +1 -1
- package/dist/dashboard/client/assets/{chunk-TZMSLE5B-B_0K0Qso.js → chunk-TZMSLE5B-Bjg9IoOQ.js} +1 -1
- package/dist/dashboard/client/assets/classDiagram-2ON5EDUG-D_fkmNvU.js +1 -0
- package/dist/dashboard/client/assets/classDiagram-v2-WZHVMYZB-D_fkmNvU.js +1 -0
- package/dist/dashboard/client/assets/clone-DTyrNOLZ.js +1 -0
- package/dist/dashboard/client/assets/{cose-bilkent-S5V4N54A-Cc_Dmnxz.js → cose-bilkent-S5V4N54A-DEdXBrCt.js} +1 -1
- package/dist/dashboard/client/assets/{dagre-6UL2VRFP-DaAfvUXU.js → dagre-6UL2VRFP-DRdIiP58.js} +1 -1
- package/dist/dashboard/client/assets/{diagram-PSM6KHXK-7idwN0rC.js → diagram-PSM6KHXK-Bo7Q2VlK.js} +1 -1
- package/dist/dashboard/client/assets/{diagram-QEK2KX5R-D9j9H13n.js → diagram-QEK2KX5R-2Fmc2o5x.js} +1 -1
- package/dist/dashboard/client/assets/{diagram-S2PKOQOG-SMF5SB0K.js → diagram-S2PKOQOG-5WE8f0p7.js} +1 -1
- package/dist/dashboard/client/assets/{erDiagram-Q2GNP2WA-EVJ4Qa2F.js → erDiagram-Q2GNP2WA-DD-iXWd_.js} +1 -1
- package/dist/dashboard/client/assets/{flowDiagram-NV44I4VS-tZ7SFE77.js → flowDiagram-NV44I4VS-CCWo8Ue9.js} +1 -1
- package/dist/dashboard/client/assets/{ganttDiagram-JELNMOA3-DFSqguY7.js → ganttDiagram-JELNMOA3-CNY4d5UK.js} +1 -1
- package/dist/dashboard/client/assets/{gitGraphDiagram-V2S2FVAM-CqHdP3HE.js → gitGraphDiagram-V2S2FVAM-Dq5SBEJJ.js} +1 -1
- package/dist/dashboard/client/assets/{graph-C0XnkNkk.js → graph-BTt9lokK.js} +1 -1
- package/dist/dashboard/client/assets/index-B0k81q2b.js +581 -0
- package/dist/dashboard/client/assets/index-Czwdh6UA.css +1 -0
- package/dist/dashboard/client/assets/{infoDiagram-HS3SLOUP-DlXZo9U2.js → infoDiagram-HS3SLOUP-AnKZja-G.js} +1 -1
- package/dist/dashboard/client/assets/{journeyDiagram-XKPGCS4Q-CgC8_7eN.js → journeyDiagram-XKPGCS4Q-nC-_WjPN.js} +1 -1
- package/dist/dashboard/client/assets/{kanban-definition-3W4ZIXB7-BMAw_jNp.js → kanban-definition-3W4ZIXB7-BEY73sWU.js} +1 -1
- package/dist/dashboard/client/assets/{layout-XjM3Q-ka.js → layout-D4DfNpzH.js} +1 -1
- package/dist/dashboard/client/assets/{linear-CMUrrr1X.js → linear-ZpGvKjeP.js} +1 -1
- package/dist/dashboard/client/assets/{mermaid-renderer-D2jYNs7K.js → mermaid-renderer-BCDxmS9g.js} +4 -4
- package/dist/dashboard/client/assets/{mindmap-definition-VGOIOE7T-CL4hv-vg.js → mindmap-definition-VGOIOE7T-MzAaKESA.js} +1 -1
- package/dist/dashboard/client/assets/{pieDiagram-ADFJNKIX-DTqv-1h1.js → pieDiagram-ADFJNKIX-B_X1kySF.js} +1 -1
- package/dist/dashboard/client/assets/{quadrantDiagram-AYHSOK5B-BpFlSW9N.js → quadrantDiagram-AYHSOK5B-CMoIEMLN.js} +1 -1
- package/dist/dashboard/client/assets/{requirementDiagram-UZGBJVZJ-BqYqqXL4.js → requirementDiagram-UZGBJVZJ-v4CRsn1w.js} +1 -1
- package/dist/dashboard/client/assets/{sankeyDiagram-TZEHDZUN-kEI9kntR.js → sankeyDiagram-TZEHDZUN-CPcyN8Jj.js} +1 -1
- package/dist/dashboard/client/assets/{sequenceDiagram-WL72ISMW-Cnu_1j-N.js → sequenceDiagram-WL72ISMW-CTg0Vx1H.js} +1 -1
- package/dist/dashboard/client/assets/{stateDiagram-FKZM4ZOC-BoC-rqoG.js → stateDiagram-FKZM4ZOC-BMWBN6Nq.js} +1 -1
- package/dist/dashboard/client/assets/stateDiagram-v2-4FDKWEC3-C9Jk1xd0.js +1 -0
- package/dist/dashboard/client/assets/{timeline-definition-IT6M3QCI-CXMWuzDL.js → timeline-definition-IT6M3QCI-B8xFcSGb.js} +1 -1
- package/dist/dashboard/client/assets/{treemap-GDKQZRPO-o9ZFgpbJ.js → treemap-GDKQZRPO-HQQuGl9w.js} +1 -1
- package/dist/dashboard/client/assets/{xychartDiagram-PRI3JC2R-CfIuUpeA.js → xychartDiagram-PRI3JC2R-Drz0SW3I.js} +1 -1
- package/dist/dashboard/client/index.html +2 -2
- package/dist/dashboard/server.js +1085 -632
- package/dist/index.js +1395 -383
- package/package.json +6 -39
- package/dist/dashboard/client/assets/channel-rgw7C1e7.js +0 -1
- package/dist/dashboard/client/assets/classDiagram-2ON5EDUG-DTGi7d9X.js +0 -1
- package/dist/dashboard/client/assets/classDiagram-v2-WZHVMYZB-DTGi7d9X.js +0 -1
- package/dist/dashboard/client/assets/clone-Cz7hswqi.js +0 -1
- package/dist/dashboard/client/assets/index-C3NEq704.js +0 -571
- package/dist/dashboard/client/assets/index-CzxeSSaQ.css +0 -1
- package/dist/dashboard/client/assets/stateDiagram-v2-4FDKWEC3-COR3QD3v.js +0 -1
- package/dist/lib/db/index.js +0 -2177
- package/dist/lib/models.js +0 -85
- package/dist/lib/runtime-config.js +0 -55
- package/dist/lib/state/index.js +0 -2196
- package/dist/lib/team-config.js +0 -175
- package/dist/lib/vendor-resume.js +0 -31
package/dist/index.js
CHANGED
|
@@ -39,7 +39,7 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
39
39
|
mod
|
|
40
40
|
));
|
|
41
41
|
|
|
42
|
-
// src/
|
|
42
|
+
// ../shared/persistence/src/runtime-checks.ts
|
|
43
43
|
function isSupportedNode(version) {
|
|
44
44
|
const [major = 0, minor = 0] = version.split(".").map((n) => Number.parseInt(n, 10) || 0);
|
|
45
45
|
return major > NODE_FLOOR.major || major === NODE_FLOOR.major && minor >= NODE_FLOOR.minor;
|
|
@@ -57,7 +57,7 @@ function isSuppressibleSqliteWarning(warning) {
|
|
|
57
57
|
}
|
|
58
58
|
var NODE_FLOOR;
|
|
59
59
|
var init_runtime_checks = __esm({
|
|
60
|
-
"src/
|
|
60
|
+
"../shared/persistence/src/runtime-checks.ts"() {
|
|
61
61
|
"use strict";
|
|
62
62
|
NODE_FLOOR = { major: 22, minor: 5 };
|
|
63
63
|
}
|
|
@@ -16017,29 +16017,688 @@ var require_emoji_regex2 = __commonJS({
|
|
|
16017
16017
|
}
|
|
16018
16018
|
});
|
|
16019
16019
|
|
|
16020
|
+
// ../../node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/windows.js
|
|
16021
|
+
var require_windows = __commonJS({
|
|
16022
|
+
"../../node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/windows.js"(exports, module) {
|
|
16023
|
+
"use strict";
|
|
16024
|
+
module.exports = isexe;
|
|
16025
|
+
isexe.sync = sync;
|
|
16026
|
+
var fs = __require("fs");
|
|
16027
|
+
function checkPathExt(path2, options) {
|
|
16028
|
+
var pathext = options.pathExt !== void 0 ? options.pathExt : process.env.PATHEXT;
|
|
16029
|
+
if (!pathext) {
|
|
16030
|
+
return true;
|
|
16031
|
+
}
|
|
16032
|
+
pathext = pathext.split(";");
|
|
16033
|
+
if (pathext.indexOf("") !== -1) {
|
|
16034
|
+
return true;
|
|
16035
|
+
}
|
|
16036
|
+
for (var i = 0; i < pathext.length; i++) {
|
|
16037
|
+
var p = pathext[i].toLowerCase();
|
|
16038
|
+
if (p && path2.substr(-p.length).toLowerCase() === p) {
|
|
16039
|
+
return true;
|
|
16040
|
+
}
|
|
16041
|
+
}
|
|
16042
|
+
return false;
|
|
16043
|
+
}
|
|
16044
|
+
function checkStat(stat4, path2, options) {
|
|
16045
|
+
if (!stat4.isSymbolicLink() && !stat4.isFile()) {
|
|
16046
|
+
return false;
|
|
16047
|
+
}
|
|
16048
|
+
return checkPathExt(path2, options);
|
|
16049
|
+
}
|
|
16050
|
+
function isexe(path2, options, cb) {
|
|
16051
|
+
fs.stat(path2, function(er, stat4) {
|
|
16052
|
+
cb(er, er ? false : checkStat(stat4, path2, options));
|
|
16053
|
+
});
|
|
16054
|
+
}
|
|
16055
|
+
function sync(path2, options) {
|
|
16056
|
+
return checkStat(fs.statSync(path2), path2, options);
|
|
16057
|
+
}
|
|
16058
|
+
}
|
|
16059
|
+
});
|
|
16060
|
+
|
|
16061
|
+
// ../../node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/mode.js
|
|
16062
|
+
var require_mode = __commonJS({
|
|
16063
|
+
"../../node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/mode.js"(exports, module) {
|
|
16064
|
+
"use strict";
|
|
16065
|
+
module.exports = isexe;
|
|
16066
|
+
isexe.sync = sync;
|
|
16067
|
+
var fs = __require("fs");
|
|
16068
|
+
function isexe(path2, options, cb) {
|
|
16069
|
+
fs.stat(path2, function(er, stat4) {
|
|
16070
|
+
cb(er, er ? false : checkStat(stat4, options));
|
|
16071
|
+
});
|
|
16072
|
+
}
|
|
16073
|
+
function sync(path2, options) {
|
|
16074
|
+
return checkStat(fs.statSync(path2), options);
|
|
16075
|
+
}
|
|
16076
|
+
function checkStat(stat4, options) {
|
|
16077
|
+
return stat4.isFile() && checkMode(stat4, options);
|
|
16078
|
+
}
|
|
16079
|
+
function checkMode(stat4, options) {
|
|
16080
|
+
var mod = stat4.mode;
|
|
16081
|
+
var uid = stat4.uid;
|
|
16082
|
+
var gid = stat4.gid;
|
|
16083
|
+
var myUid = options.uid !== void 0 ? options.uid : process.getuid && process.getuid();
|
|
16084
|
+
var myGid = options.gid !== void 0 ? options.gid : process.getgid && process.getgid();
|
|
16085
|
+
var u = parseInt("100", 8);
|
|
16086
|
+
var g = parseInt("010", 8);
|
|
16087
|
+
var o = parseInt("001", 8);
|
|
16088
|
+
var ug = u | g;
|
|
16089
|
+
var ret = mod & o || mod & g && gid === myGid || mod & u && uid === myUid || mod & ug && myUid === 0;
|
|
16090
|
+
return ret;
|
|
16091
|
+
}
|
|
16092
|
+
}
|
|
16093
|
+
});
|
|
16094
|
+
|
|
16095
|
+
// ../../node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/index.js
|
|
16096
|
+
var require_isexe = __commonJS({
|
|
16097
|
+
"../../node_modules/.pnpm/isexe@2.0.0/node_modules/isexe/index.js"(exports, module) {
|
|
16098
|
+
"use strict";
|
|
16099
|
+
var fs = __require("fs");
|
|
16100
|
+
var core;
|
|
16101
|
+
if (process.platform === "win32" || global.TESTING_WINDOWS) {
|
|
16102
|
+
core = require_windows();
|
|
16103
|
+
} else {
|
|
16104
|
+
core = require_mode();
|
|
16105
|
+
}
|
|
16106
|
+
module.exports = isexe;
|
|
16107
|
+
isexe.sync = sync;
|
|
16108
|
+
function isexe(path2, options, cb) {
|
|
16109
|
+
if (typeof options === "function") {
|
|
16110
|
+
cb = options;
|
|
16111
|
+
options = {};
|
|
16112
|
+
}
|
|
16113
|
+
if (!cb) {
|
|
16114
|
+
if (typeof Promise !== "function") {
|
|
16115
|
+
throw new TypeError("callback not provided");
|
|
16116
|
+
}
|
|
16117
|
+
return new Promise(function(resolve3, reject) {
|
|
16118
|
+
isexe(path2, options || {}, function(er, is) {
|
|
16119
|
+
if (er) {
|
|
16120
|
+
reject(er);
|
|
16121
|
+
} else {
|
|
16122
|
+
resolve3(is);
|
|
16123
|
+
}
|
|
16124
|
+
});
|
|
16125
|
+
});
|
|
16126
|
+
}
|
|
16127
|
+
core(path2, options || {}, function(er, is) {
|
|
16128
|
+
if (er) {
|
|
16129
|
+
if (er.code === "EACCES" || options && options.ignoreErrors) {
|
|
16130
|
+
er = null;
|
|
16131
|
+
is = false;
|
|
16132
|
+
}
|
|
16133
|
+
}
|
|
16134
|
+
cb(er, is);
|
|
16135
|
+
});
|
|
16136
|
+
}
|
|
16137
|
+
function sync(path2, options) {
|
|
16138
|
+
try {
|
|
16139
|
+
return core.sync(path2, options || {});
|
|
16140
|
+
} catch (er) {
|
|
16141
|
+
if (options && options.ignoreErrors || er.code === "EACCES") {
|
|
16142
|
+
return false;
|
|
16143
|
+
} else {
|
|
16144
|
+
throw er;
|
|
16145
|
+
}
|
|
16146
|
+
}
|
|
16147
|
+
}
|
|
16148
|
+
}
|
|
16149
|
+
});
|
|
16150
|
+
|
|
16151
|
+
// ../../node_modules/.pnpm/which@2.0.2/node_modules/which/which.js
|
|
16152
|
+
var require_which = __commonJS({
|
|
16153
|
+
"../../node_modules/.pnpm/which@2.0.2/node_modules/which/which.js"(exports, module) {
|
|
16154
|
+
"use strict";
|
|
16155
|
+
var isWindows5 = process.platform === "win32" || process.env.OSTYPE === "cygwin" || process.env.OSTYPE === "msys";
|
|
16156
|
+
var path2 = __require("path");
|
|
16157
|
+
var COLON = isWindows5 ? ";" : ":";
|
|
16158
|
+
var isexe = require_isexe();
|
|
16159
|
+
var getNotFoundError = (cmd) => Object.assign(new Error(`not found: ${cmd}`), { code: "ENOENT" });
|
|
16160
|
+
var getPathInfo = (cmd, opt) => {
|
|
16161
|
+
const colon = opt.colon || COLON;
|
|
16162
|
+
const pathEnv = cmd.match(/\//) || isWindows5 && cmd.match(/\\/) ? [""] : [
|
|
16163
|
+
// windows always checks the cwd first
|
|
16164
|
+
...isWindows5 ? [process.cwd()] : [],
|
|
16165
|
+
...(opt.path || process.env.PATH || /* istanbul ignore next: very unusual */
|
|
16166
|
+
"").split(colon)
|
|
16167
|
+
];
|
|
16168
|
+
const pathExtExe = isWindows5 ? opt.pathExt || process.env.PATHEXT || ".EXE;.CMD;.BAT;.COM" : "";
|
|
16169
|
+
const pathExt = isWindows5 ? pathExtExe.split(colon) : [""];
|
|
16170
|
+
if (isWindows5) {
|
|
16171
|
+
if (cmd.indexOf(".") !== -1 && pathExt[0] !== "")
|
|
16172
|
+
pathExt.unshift("");
|
|
16173
|
+
}
|
|
16174
|
+
return {
|
|
16175
|
+
pathEnv,
|
|
16176
|
+
pathExt,
|
|
16177
|
+
pathExtExe
|
|
16178
|
+
};
|
|
16179
|
+
};
|
|
16180
|
+
var which = (cmd, opt, cb) => {
|
|
16181
|
+
if (typeof opt === "function") {
|
|
16182
|
+
cb = opt;
|
|
16183
|
+
opt = {};
|
|
16184
|
+
}
|
|
16185
|
+
if (!opt)
|
|
16186
|
+
opt = {};
|
|
16187
|
+
const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
|
|
16188
|
+
const found = [];
|
|
16189
|
+
const step = (i) => new Promise((resolve3, reject) => {
|
|
16190
|
+
if (i === pathEnv.length)
|
|
16191
|
+
return opt.all && found.length ? resolve3(found) : reject(getNotFoundError(cmd));
|
|
16192
|
+
const ppRaw = pathEnv[i];
|
|
16193
|
+
const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
|
|
16194
|
+
const pCmd = path2.join(pathPart, cmd);
|
|
16195
|
+
const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
|
|
16196
|
+
resolve3(subStep(p, i, 0));
|
|
16197
|
+
});
|
|
16198
|
+
const subStep = (p, i, ii) => new Promise((resolve3, reject) => {
|
|
16199
|
+
if (ii === pathExt.length)
|
|
16200
|
+
return resolve3(step(i + 1));
|
|
16201
|
+
const ext = pathExt[ii];
|
|
16202
|
+
isexe(p + ext, { pathExt: pathExtExe }, (er, is) => {
|
|
16203
|
+
if (!er && is) {
|
|
16204
|
+
if (opt.all)
|
|
16205
|
+
found.push(p + ext);
|
|
16206
|
+
else
|
|
16207
|
+
return resolve3(p + ext);
|
|
16208
|
+
}
|
|
16209
|
+
return resolve3(subStep(p, i, ii + 1));
|
|
16210
|
+
});
|
|
16211
|
+
});
|
|
16212
|
+
return cb ? step(0).then((res) => cb(null, res), cb) : step(0);
|
|
16213
|
+
};
|
|
16214
|
+
var whichSync = (cmd, opt) => {
|
|
16215
|
+
opt = opt || {};
|
|
16216
|
+
const { pathEnv, pathExt, pathExtExe } = getPathInfo(cmd, opt);
|
|
16217
|
+
const found = [];
|
|
16218
|
+
for (let i = 0; i < pathEnv.length; i++) {
|
|
16219
|
+
const ppRaw = pathEnv[i];
|
|
16220
|
+
const pathPart = /^".*"$/.test(ppRaw) ? ppRaw.slice(1, -1) : ppRaw;
|
|
16221
|
+
const pCmd = path2.join(pathPart, cmd);
|
|
16222
|
+
const p = !pathPart && /^\.[\\\/]/.test(cmd) ? cmd.slice(0, 2) + pCmd : pCmd;
|
|
16223
|
+
for (let j = 0; j < pathExt.length; j++) {
|
|
16224
|
+
const cur = p + pathExt[j];
|
|
16225
|
+
try {
|
|
16226
|
+
const is = isexe.sync(cur, { pathExt: pathExtExe });
|
|
16227
|
+
if (is) {
|
|
16228
|
+
if (opt.all)
|
|
16229
|
+
found.push(cur);
|
|
16230
|
+
else
|
|
16231
|
+
return cur;
|
|
16232
|
+
}
|
|
16233
|
+
} catch (ex) {
|
|
16234
|
+
}
|
|
16235
|
+
}
|
|
16236
|
+
}
|
|
16237
|
+
if (opt.all && found.length)
|
|
16238
|
+
return found;
|
|
16239
|
+
if (opt.nothrow)
|
|
16240
|
+
return null;
|
|
16241
|
+
throw getNotFoundError(cmd);
|
|
16242
|
+
};
|
|
16243
|
+
module.exports = which;
|
|
16244
|
+
which.sync = whichSync;
|
|
16245
|
+
}
|
|
16246
|
+
});
|
|
16247
|
+
|
|
16248
|
+
// ../../node_modules/.pnpm/path-key@3.1.1/node_modules/path-key/index.js
|
|
16249
|
+
var require_path_key = __commonJS({
|
|
16250
|
+
"../../node_modules/.pnpm/path-key@3.1.1/node_modules/path-key/index.js"(exports, module) {
|
|
16251
|
+
"use strict";
|
|
16252
|
+
var pathKey = (options = {}) => {
|
|
16253
|
+
const environment = options.env || process.env;
|
|
16254
|
+
const platform2 = options.platform || process.platform;
|
|
16255
|
+
if (platform2 !== "win32") {
|
|
16256
|
+
return "PATH";
|
|
16257
|
+
}
|
|
16258
|
+
return Object.keys(environment).reverse().find((key) => key.toUpperCase() === "PATH") || "Path";
|
|
16259
|
+
};
|
|
16260
|
+
module.exports = pathKey;
|
|
16261
|
+
module.exports.default = pathKey;
|
|
16262
|
+
}
|
|
16263
|
+
});
|
|
16264
|
+
|
|
16265
|
+
// ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/resolveCommand.js
|
|
16266
|
+
var require_resolveCommand = __commonJS({
|
|
16267
|
+
"../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/resolveCommand.js"(exports, module) {
|
|
16268
|
+
"use strict";
|
|
16269
|
+
var path2 = __require("path");
|
|
16270
|
+
var which = require_which();
|
|
16271
|
+
var getPathKey = require_path_key();
|
|
16272
|
+
function resolveCommandAttempt(parsed, withoutPathExt) {
|
|
16273
|
+
const env2 = parsed.options.env || process.env;
|
|
16274
|
+
const cwd = process.cwd();
|
|
16275
|
+
const hasCustomCwd = parsed.options.cwd != null;
|
|
16276
|
+
const shouldSwitchCwd = hasCustomCwd && process.chdir !== void 0 && !process.chdir.disabled;
|
|
16277
|
+
if (shouldSwitchCwd) {
|
|
16278
|
+
try {
|
|
16279
|
+
process.chdir(parsed.options.cwd);
|
|
16280
|
+
} catch (err) {
|
|
16281
|
+
}
|
|
16282
|
+
}
|
|
16283
|
+
let resolved;
|
|
16284
|
+
try {
|
|
16285
|
+
resolved = which.sync(parsed.command, {
|
|
16286
|
+
path: env2[getPathKey({ env: env2 })],
|
|
16287
|
+
pathExt: withoutPathExt ? path2.delimiter : void 0
|
|
16288
|
+
});
|
|
16289
|
+
} catch (e) {
|
|
16290
|
+
} finally {
|
|
16291
|
+
if (shouldSwitchCwd) {
|
|
16292
|
+
process.chdir(cwd);
|
|
16293
|
+
}
|
|
16294
|
+
}
|
|
16295
|
+
if (resolved) {
|
|
16296
|
+
resolved = path2.resolve(hasCustomCwd ? parsed.options.cwd : "", resolved);
|
|
16297
|
+
}
|
|
16298
|
+
return resolved;
|
|
16299
|
+
}
|
|
16300
|
+
function resolveCommand(parsed) {
|
|
16301
|
+
return resolveCommandAttempt(parsed) || resolveCommandAttempt(parsed, true);
|
|
16302
|
+
}
|
|
16303
|
+
module.exports = resolveCommand;
|
|
16304
|
+
}
|
|
16305
|
+
});
|
|
16306
|
+
|
|
16307
|
+
// ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/escape.js
|
|
16308
|
+
var require_escape = __commonJS({
|
|
16309
|
+
"../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/escape.js"(exports, module) {
|
|
16310
|
+
"use strict";
|
|
16311
|
+
var metaCharsRegExp = /([()\][%!^"`<>&|;, *?])/g;
|
|
16312
|
+
function escapeCommand(arg) {
|
|
16313
|
+
arg = arg.replace(metaCharsRegExp, "^$1");
|
|
16314
|
+
return arg;
|
|
16315
|
+
}
|
|
16316
|
+
function escapeArgument(arg, doubleEscapeMetaChars) {
|
|
16317
|
+
arg = `${arg}`;
|
|
16318
|
+
arg = arg.replace(/(?=(\\+?)?)\1"/g, '$1$1\\"');
|
|
16319
|
+
arg = arg.replace(/(?=(\\+?)?)\1$/, "$1$1");
|
|
16320
|
+
arg = `"${arg}"`;
|
|
16321
|
+
arg = arg.replace(metaCharsRegExp, "^$1");
|
|
16322
|
+
if (doubleEscapeMetaChars) {
|
|
16323
|
+
arg = arg.replace(metaCharsRegExp, "^$1");
|
|
16324
|
+
}
|
|
16325
|
+
return arg;
|
|
16326
|
+
}
|
|
16327
|
+
module.exports.command = escapeCommand;
|
|
16328
|
+
module.exports.argument = escapeArgument;
|
|
16329
|
+
}
|
|
16330
|
+
});
|
|
16331
|
+
|
|
16332
|
+
// ../../node_modules/.pnpm/shebang-regex@3.0.0/node_modules/shebang-regex/index.js
|
|
16333
|
+
var require_shebang_regex = __commonJS({
|
|
16334
|
+
"../../node_modules/.pnpm/shebang-regex@3.0.0/node_modules/shebang-regex/index.js"(exports, module) {
|
|
16335
|
+
"use strict";
|
|
16336
|
+
module.exports = /^#!(.*)/;
|
|
16337
|
+
}
|
|
16338
|
+
});
|
|
16339
|
+
|
|
16340
|
+
// ../../node_modules/.pnpm/shebang-command@2.0.0/node_modules/shebang-command/index.js
|
|
16341
|
+
var require_shebang_command = __commonJS({
|
|
16342
|
+
"../../node_modules/.pnpm/shebang-command@2.0.0/node_modules/shebang-command/index.js"(exports, module) {
|
|
16343
|
+
"use strict";
|
|
16344
|
+
var shebangRegex = require_shebang_regex();
|
|
16345
|
+
module.exports = (string = "") => {
|
|
16346
|
+
const match = string.match(shebangRegex);
|
|
16347
|
+
if (!match) {
|
|
16348
|
+
return null;
|
|
16349
|
+
}
|
|
16350
|
+
const [path2, argument] = match[0].replace(/#! ?/, "").split(" ");
|
|
16351
|
+
const binary = path2.split("/").pop();
|
|
16352
|
+
if (binary === "env") {
|
|
16353
|
+
return argument;
|
|
16354
|
+
}
|
|
16355
|
+
return argument ? `${binary} ${argument}` : binary;
|
|
16356
|
+
};
|
|
16357
|
+
}
|
|
16358
|
+
});
|
|
16359
|
+
|
|
16360
|
+
// ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/readShebang.js
|
|
16361
|
+
var require_readShebang = __commonJS({
|
|
16362
|
+
"../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/util/readShebang.js"(exports, module) {
|
|
16363
|
+
"use strict";
|
|
16364
|
+
var fs = __require("fs");
|
|
16365
|
+
var shebangCommand = require_shebang_command();
|
|
16366
|
+
function readShebang(command) {
|
|
16367
|
+
const size = 150;
|
|
16368
|
+
const buffer = Buffer.alloc(size);
|
|
16369
|
+
let fd;
|
|
16370
|
+
try {
|
|
16371
|
+
fd = fs.openSync(command, "r");
|
|
16372
|
+
fs.readSync(fd, buffer, 0, size, 0);
|
|
16373
|
+
fs.closeSync(fd);
|
|
16374
|
+
} catch (e) {
|
|
16375
|
+
}
|
|
16376
|
+
return shebangCommand(buffer.toString());
|
|
16377
|
+
}
|
|
16378
|
+
module.exports = readShebang;
|
|
16379
|
+
}
|
|
16380
|
+
});
|
|
16381
|
+
|
|
16382
|
+
// ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/parse.js
|
|
16383
|
+
var require_parse = __commonJS({
|
|
16384
|
+
"../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/parse.js"(exports, module) {
|
|
16385
|
+
"use strict";
|
|
16386
|
+
var path2 = __require("path");
|
|
16387
|
+
var resolveCommand = require_resolveCommand();
|
|
16388
|
+
var escape = require_escape();
|
|
16389
|
+
var readShebang = require_readShebang();
|
|
16390
|
+
var isWin = process.platform === "win32";
|
|
16391
|
+
var isExecutableRegExp = /\.(?:com|exe)$/i;
|
|
16392
|
+
var isCmdShimRegExp = /node_modules[\\/].bin[\\/][^\\/]+\.cmd$/i;
|
|
16393
|
+
function detectShebang(parsed) {
|
|
16394
|
+
parsed.file = resolveCommand(parsed);
|
|
16395
|
+
const shebang = parsed.file && readShebang(parsed.file);
|
|
16396
|
+
if (shebang) {
|
|
16397
|
+
parsed.args.unshift(parsed.file);
|
|
16398
|
+
parsed.command = shebang;
|
|
16399
|
+
return resolveCommand(parsed);
|
|
16400
|
+
}
|
|
16401
|
+
return parsed.file;
|
|
16402
|
+
}
|
|
16403
|
+
function parseNonShell(parsed) {
|
|
16404
|
+
if (!isWin) {
|
|
16405
|
+
return parsed;
|
|
16406
|
+
}
|
|
16407
|
+
const commandFile = detectShebang(parsed);
|
|
16408
|
+
const needsShell = !isExecutableRegExp.test(commandFile);
|
|
16409
|
+
if (parsed.options.forceShell || needsShell) {
|
|
16410
|
+
const needsDoubleEscapeMetaChars = isCmdShimRegExp.test(commandFile);
|
|
16411
|
+
parsed.command = path2.normalize(parsed.command);
|
|
16412
|
+
parsed.command = escape.command(parsed.command);
|
|
16413
|
+
parsed.args = parsed.args.map((arg) => escape.argument(arg, needsDoubleEscapeMetaChars));
|
|
16414
|
+
const shellCommand = [parsed.command].concat(parsed.args).join(" ");
|
|
16415
|
+
parsed.args = ["/d", "/s", "/c", `"${shellCommand}"`];
|
|
16416
|
+
parsed.command = process.env.comspec || "cmd.exe";
|
|
16417
|
+
parsed.options.windowsVerbatimArguments = true;
|
|
16418
|
+
}
|
|
16419
|
+
return parsed;
|
|
16420
|
+
}
|
|
16421
|
+
function parse(command, args, options) {
|
|
16422
|
+
if (args && !Array.isArray(args)) {
|
|
16423
|
+
options = args;
|
|
16424
|
+
args = null;
|
|
16425
|
+
}
|
|
16426
|
+
args = args ? args.slice(0) : [];
|
|
16427
|
+
options = Object.assign({}, options);
|
|
16428
|
+
const parsed = {
|
|
16429
|
+
command,
|
|
16430
|
+
args,
|
|
16431
|
+
options,
|
|
16432
|
+
file: void 0,
|
|
16433
|
+
original: {
|
|
16434
|
+
command,
|
|
16435
|
+
args
|
|
16436
|
+
}
|
|
16437
|
+
};
|
|
16438
|
+
return options.shell ? parsed : parseNonShell(parsed);
|
|
16439
|
+
}
|
|
16440
|
+
module.exports = parse;
|
|
16441
|
+
}
|
|
16442
|
+
});
|
|
16443
|
+
|
|
16444
|
+
// ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/enoent.js
|
|
16445
|
+
var require_enoent = __commonJS({
|
|
16446
|
+
"../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/lib/enoent.js"(exports, module) {
|
|
16447
|
+
"use strict";
|
|
16448
|
+
var isWin = process.platform === "win32";
|
|
16449
|
+
function notFoundError(original, syscall) {
|
|
16450
|
+
return Object.assign(new Error(`${syscall} ${original.command} ENOENT`), {
|
|
16451
|
+
code: "ENOENT",
|
|
16452
|
+
errno: "ENOENT",
|
|
16453
|
+
syscall: `${syscall} ${original.command}`,
|
|
16454
|
+
path: original.command,
|
|
16455
|
+
spawnargs: original.args
|
|
16456
|
+
});
|
|
16457
|
+
}
|
|
16458
|
+
function hookChildProcess(cp, parsed) {
|
|
16459
|
+
if (!isWin) {
|
|
16460
|
+
return;
|
|
16461
|
+
}
|
|
16462
|
+
const originalEmit = cp.emit;
|
|
16463
|
+
cp.emit = function(name, arg1) {
|
|
16464
|
+
if (name === "exit") {
|
|
16465
|
+
const err = verifyENOENT(arg1, parsed);
|
|
16466
|
+
if (err) {
|
|
16467
|
+
return originalEmit.call(cp, "error", err);
|
|
16468
|
+
}
|
|
16469
|
+
}
|
|
16470
|
+
return originalEmit.apply(cp, arguments);
|
|
16471
|
+
};
|
|
16472
|
+
}
|
|
16473
|
+
function verifyENOENT(status, parsed) {
|
|
16474
|
+
if (isWin && status === 1 && !parsed.file) {
|
|
16475
|
+
return notFoundError(parsed.original, "spawn");
|
|
16476
|
+
}
|
|
16477
|
+
return null;
|
|
16478
|
+
}
|
|
16479
|
+
function verifyENOENTSync(status, parsed) {
|
|
16480
|
+
if (isWin && status === 1 && !parsed.file) {
|
|
16481
|
+
return notFoundError(parsed.original, "spawnSync");
|
|
16482
|
+
}
|
|
16483
|
+
return null;
|
|
16484
|
+
}
|
|
16485
|
+
module.exports = {
|
|
16486
|
+
hookChildProcess,
|
|
16487
|
+
verifyENOENT,
|
|
16488
|
+
verifyENOENTSync,
|
|
16489
|
+
notFoundError
|
|
16490
|
+
};
|
|
16491
|
+
}
|
|
16492
|
+
});
|
|
16493
|
+
|
|
16494
|
+
// ../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/index.js
|
|
16495
|
+
var require_cross_spawn = __commonJS({
|
|
16496
|
+
"../../node_modules/.pnpm/cross-spawn@7.0.6/node_modules/cross-spawn/index.js"(exports, module) {
|
|
16497
|
+
"use strict";
|
|
16498
|
+
var cp = __require("child_process");
|
|
16499
|
+
var parse = require_parse();
|
|
16500
|
+
var enoent = require_enoent();
|
|
16501
|
+
function spawn2(command, args, options) {
|
|
16502
|
+
const parsed = parse(command, args, options);
|
|
16503
|
+
const spawned = cp.spawn(parsed.command, parsed.args, parsed.options);
|
|
16504
|
+
enoent.hookChildProcess(spawned, parsed);
|
|
16505
|
+
return spawned;
|
|
16506
|
+
}
|
|
16507
|
+
function spawnSync2(command, args, options) {
|
|
16508
|
+
const parsed = parse(command, args, options);
|
|
16509
|
+
const result = cp.spawnSync(parsed.command, parsed.args, parsed.options);
|
|
16510
|
+
result.error = result.error || enoent.verifyENOENTSync(result.status, parsed);
|
|
16511
|
+
return result;
|
|
16512
|
+
}
|
|
16513
|
+
module.exports = spawn2;
|
|
16514
|
+
module.exports.spawn = spawn2;
|
|
16515
|
+
module.exports.sync = spawnSync2;
|
|
16516
|
+
module.exports._parse = parse;
|
|
16517
|
+
module.exports._enoent = enoent;
|
|
16518
|
+
}
|
|
16519
|
+
});
|
|
16520
|
+
|
|
16521
|
+
// ../shared/platform/src/spawn.ts
|
|
16522
|
+
function execBinary(binary, args, opts) {
|
|
16523
|
+
const result = import_cross_spawn.default.sync(binary, args, {
|
|
16524
|
+
maxBuffer: DEFAULT_MAX_BUFFER,
|
|
16525
|
+
...opts
|
|
16526
|
+
});
|
|
16527
|
+
if (result.error) throw result.error;
|
|
16528
|
+
if (result.status !== 0) {
|
|
16529
|
+
throw Object.assign(
|
|
16530
|
+
new Error(
|
|
16531
|
+
`Command failed: ${binary} ${args.join(" ")}
|
|
16532
|
+
${String(result.stderr ?? "")}`
|
|
16533
|
+
),
|
|
16534
|
+
{
|
|
16535
|
+
status: result.status,
|
|
16536
|
+
code: result.status,
|
|
16537
|
+
signal: result.signal,
|
|
16538
|
+
stdout: result.stdout,
|
|
16539
|
+
stderr: result.stderr,
|
|
16540
|
+
pid: result.pid
|
|
16541
|
+
}
|
|
16542
|
+
);
|
|
16543
|
+
}
|
|
16544
|
+
return result.stdout;
|
|
16545
|
+
}
|
|
16546
|
+
async function execBinaryAsync(binary, args, opts) {
|
|
16547
|
+
return new Promise((resolvePromise, rejectPromise) => {
|
|
16548
|
+
const child = (0, import_cross_spawn.default)(binary, args, {
|
|
16549
|
+
cwd: opts.cwd,
|
|
16550
|
+
env: opts.env,
|
|
16551
|
+
windowsHide: true
|
|
16552
|
+
});
|
|
16553
|
+
const maxBuffer = opts.maxBuffer ?? DEFAULT_MAX_BUFFER;
|
|
16554
|
+
let stdout = "";
|
|
16555
|
+
let stderr = "";
|
|
16556
|
+
let killed = false;
|
|
16557
|
+
let settled = false;
|
|
16558
|
+
const settle = (fn) => {
|
|
16559
|
+
if (settled) return;
|
|
16560
|
+
settled = true;
|
|
16561
|
+
if (timer) clearTimeout(timer);
|
|
16562
|
+
fn();
|
|
16563
|
+
};
|
|
16564
|
+
const overflow = () => {
|
|
16565
|
+
killed = true;
|
|
16566
|
+
child.kill();
|
|
16567
|
+
};
|
|
16568
|
+
child.stdout?.setEncoding(opts.encoding);
|
|
16569
|
+
child.stderr?.setEncoding(opts.encoding);
|
|
16570
|
+
child.stdout?.on("data", (chunk) => {
|
|
16571
|
+
stdout += chunk;
|
|
16572
|
+
if (stdout.length > maxBuffer) overflow();
|
|
16573
|
+
});
|
|
16574
|
+
child.stderr?.on("data", (chunk) => {
|
|
16575
|
+
stderr += chunk;
|
|
16576
|
+
if (stderr.length > maxBuffer) overflow();
|
|
16577
|
+
});
|
|
16578
|
+
const timer = opts.timeout ? setTimeout(() => {
|
|
16579
|
+
killed = true;
|
|
16580
|
+
child.kill();
|
|
16581
|
+
}, opts.timeout) : void 0;
|
|
16582
|
+
child.on("error", (err) => {
|
|
16583
|
+
settle(
|
|
16584
|
+
() => rejectPromise(Object.assign(err, { stdout, stderr, killed }))
|
|
16585
|
+
);
|
|
16586
|
+
});
|
|
16587
|
+
child.on("close", (code, signal) => {
|
|
16588
|
+
settle(() => {
|
|
16589
|
+
if (code === 0 && !killed) {
|
|
16590
|
+
resolvePromise({ stdout, stderr });
|
|
16591
|
+
return;
|
|
16592
|
+
}
|
|
16593
|
+
rejectPromise(
|
|
16594
|
+
Object.assign(
|
|
16595
|
+
new Error(
|
|
16596
|
+
`Command failed: ${binary} ${args.join(" ")}
|
|
16597
|
+
${stderr}`
|
|
16598
|
+
),
|
|
16599
|
+
{
|
|
16600
|
+
code: code ?? void 0,
|
|
16601
|
+
signal,
|
|
16602
|
+
stdout,
|
|
16603
|
+
stderr,
|
|
16604
|
+
killed
|
|
16605
|
+
}
|
|
16606
|
+
)
|
|
16607
|
+
);
|
|
16608
|
+
});
|
|
16609
|
+
});
|
|
16610
|
+
});
|
|
16611
|
+
}
|
|
16612
|
+
function spawnBinary(binary, args, opts) {
|
|
16613
|
+
return (0, import_cross_spawn.default)(binary, args, {
|
|
16614
|
+
...opts,
|
|
16615
|
+
windowsHide: true
|
|
16616
|
+
});
|
|
16617
|
+
}
|
|
16618
|
+
var import_cross_spawn, DEFAULT_MAX_BUFFER;
|
|
16619
|
+
var init_spawn = __esm({
|
|
16620
|
+
"../shared/platform/src/spawn.ts"() {
|
|
16621
|
+
"use strict";
|
|
16622
|
+
import_cross_spawn = __toESM(require_cross_spawn(), 1);
|
|
16623
|
+
DEFAULT_MAX_BUFFER = 1024 * 1024;
|
|
16624
|
+
}
|
|
16625
|
+
});
|
|
16626
|
+
|
|
16627
|
+
// ../shared/platform/src/verdict.ts
|
|
16628
|
+
function isCanonicalVerdict(v) {
|
|
16629
|
+
return VERDICT_SET.has(v);
|
|
16630
|
+
}
|
|
16631
|
+
var CANONICAL_VERDICTS, VERDICT_SET;
|
|
16632
|
+
var init_verdict = __esm({
|
|
16633
|
+
"../shared/platform/src/verdict.ts"() {
|
|
16634
|
+
"use strict";
|
|
16635
|
+
CANONICAL_VERDICTS = [
|
|
16636
|
+
"APPROVE",
|
|
16637
|
+
"REQUEST CHANGES",
|
|
16638
|
+
"NEEDS DISCUSSION"
|
|
16639
|
+
];
|
|
16640
|
+
VERDICT_SET = new Set(CANONICAL_VERDICTS);
|
|
16641
|
+
}
|
|
16642
|
+
});
|
|
16643
|
+
|
|
16644
|
+
// ../shared/platform/src/counts.ts
|
|
16645
|
+
function deriveCounts(findings) {
|
|
16646
|
+
const counts = {
|
|
16647
|
+
blocker: 0,
|
|
16648
|
+
should_fix: 0,
|
|
16649
|
+
suggestion: 0,
|
|
16650
|
+
style: 0
|
|
16651
|
+
};
|
|
16652
|
+
for (const finding of findings) {
|
|
16653
|
+
const category = finding?.category;
|
|
16654
|
+
if (category === "blocker" || category === "should_fix" || category === "suggestion" || category === "style") {
|
|
16655
|
+
counts[category]++;
|
|
16656
|
+
}
|
|
16657
|
+
}
|
|
16658
|
+
return counts;
|
|
16659
|
+
}
|
|
16660
|
+
function collectFindings(meta) {
|
|
16661
|
+
const all = [];
|
|
16662
|
+
for (const reviewer of meta.reviewers ?? []) {
|
|
16663
|
+
for (const finding of reviewer?.findings ?? []) all.push(finding);
|
|
16664
|
+
}
|
|
16665
|
+
return all;
|
|
16666
|
+
}
|
|
16667
|
+
function preferred(scValue, derivedValue) {
|
|
16668
|
+
return typeof scValue === "number" && Number.isFinite(scValue) ? scValue : derivedValue;
|
|
16669
|
+
}
|
|
16670
|
+
function resolveRoundCounts(meta) {
|
|
16671
|
+
const allFindings = collectFindings(meta);
|
|
16672
|
+
const derived = deriveCounts(allFindings);
|
|
16673
|
+
const sc = meta.synthesis_counts ?? void 0;
|
|
16674
|
+
return {
|
|
16675
|
+
blockerCount: sc ? preferred(sc.blockers, derived.blocker) : derived.blocker,
|
|
16676
|
+
shouldFixCount: sc ? preferred(sc.should_fix, derived.should_fix) : derived.should_fix,
|
|
16677
|
+
suggestionCount: sc ? preferred(sc.suggestions, derived.suggestion) : derived.suggestion,
|
|
16678
|
+
reviewerCount: (meta.reviewers ?? []).length,
|
|
16679
|
+
totalFindingCount: allFindings.length
|
|
16680
|
+
};
|
|
16681
|
+
}
|
|
16682
|
+
var init_counts = __esm({
|
|
16683
|
+
"../shared/platform/src/counts.ts"() {
|
|
16684
|
+
"use strict";
|
|
16685
|
+
}
|
|
16686
|
+
});
|
|
16687
|
+
|
|
16020
16688
|
// ../shared/platform/src/index.ts
|
|
16021
16689
|
import { pathToFileURL } from "node:url";
|
|
16022
|
-
import {
|
|
16023
|
-
execFile,
|
|
16024
|
-
execFileSync,
|
|
16025
|
-
spawn as spawn2
|
|
16026
|
-
} from "node:child_process";
|
|
16027
|
-
import { promisify } from "node:util";
|
|
16028
16690
|
async function importModule(absolutePath) {
|
|
16029
16691
|
return import(pathToFileURL(absolutePath).href);
|
|
16030
16692
|
}
|
|
16031
|
-
function
|
|
16032
|
-
return
|
|
16033
|
-
...opts,
|
|
16034
|
-
shell: isWindows
|
|
16035
|
-
});
|
|
16693
|
+
function killErrorMeansDead(err) {
|
|
16694
|
+
return err instanceof Error && "code" in err && err.code === "ESRCH";
|
|
16036
16695
|
}
|
|
16037
16696
|
function isProcessAlive(pid) {
|
|
16038
16697
|
try {
|
|
16039
16698
|
process.kill(pid, 0);
|
|
16040
16699
|
return true;
|
|
16041
16700
|
} catch (err) {
|
|
16042
|
-
return !(err
|
|
16701
|
+
return !killErrorMeansDead(err);
|
|
16043
16702
|
}
|
|
16044
16703
|
}
|
|
16045
16704
|
function defaultIconFor(id, tier) {
|
|
@@ -16048,11 +16707,13 @@ function defaultIconFor(id, tier) {
|
|
|
16048
16707
|
function hostCapabilitiesFor(vendor) {
|
|
16049
16708
|
return vendor && HOST_CAPABILITIES[vendor] || DEFAULT_HOST_CAPABILITIES;
|
|
16050
16709
|
}
|
|
16051
|
-
var
|
|
16710
|
+
var isWindows, BUILTIN_ICON_MAP, DEFAULT_HOST_CAPABILITIES, HOST_CAPABILITIES;
|
|
16052
16711
|
var init_src = __esm({
|
|
16053
16712
|
"../shared/platform/src/index.ts"() {
|
|
16054
16713
|
"use strict";
|
|
16055
|
-
|
|
16714
|
+
init_spawn();
|
|
16715
|
+
init_verdict();
|
|
16716
|
+
init_counts();
|
|
16056
16717
|
isWindows = process.platform === "win32";
|
|
16057
16718
|
BUILTIN_ICON_MAP = {
|
|
16058
16719
|
architect: "blocks",
|
|
@@ -23393,31 +24054,7 @@ var require_dist = __commonJS({
|
|
|
23393
24054
|
}
|
|
23394
24055
|
});
|
|
23395
24056
|
|
|
23396
|
-
// src/
|
|
23397
|
-
function resultToRows(result) {
|
|
23398
|
-
if (result.length === 0 || !result[0]) {
|
|
23399
|
-
return [];
|
|
23400
|
-
}
|
|
23401
|
-
const { columns, values } = result[0];
|
|
23402
|
-
return values.map((row) => {
|
|
23403
|
-
const obj = {};
|
|
23404
|
-
for (let i = 0; i < columns.length; i++) {
|
|
23405
|
-
obj[columns[i]] = row[i];
|
|
23406
|
-
}
|
|
23407
|
-
return obj;
|
|
23408
|
-
});
|
|
23409
|
-
}
|
|
23410
|
-
function resultToRow(result) {
|
|
23411
|
-
const rows = resultToRows(result);
|
|
23412
|
-
return rows[0];
|
|
23413
|
-
}
|
|
23414
|
-
var init_result_mapper = __esm({
|
|
23415
|
-
"src/lib/db/result-mapper.ts"() {
|
|
23416
|
-
"use strict";
|
|
23417
|
-
}
|
|
23418
|
-
});
|
|
23419
|
-
|
|
23420
|
-
// src/lib/db/engine.ts
|
|
24057
|
+
// ../shared/persistence/src/db/engine.ts
|
|
23421
24058
|
import { createRequire as createRequire2 } from "node:module";
|
|
23422
24059
|
function applyEnginePreconditions() {
|
|
23423
24060
|
if (_preconditionsApplied) return;
|
|
@@ -23471,7 +24108,7 @@ function openEngine(dbPath) {
|
|
|
23471
24108
|
}
|
|
23472
24109
|
var SQLITE_BUSY, SQLITE_BUSY_SNAPSHOT, BUSY_RETRY_ATTEMPTS, BUSY_RETRY_BACKOFF_MS, savepointName, nodeRequire, _preconditionsApplied, _DatabaseSyncCtor, SLEEP_BUF, NodeSqliteAdapter;
|
|
23473
24110
|
var init_engine = __esm({
|
|
23474
|
-
"src/
|
|
24111
|
+
"../shared/persistence/src/db/engine.ts"() {
|
|
23475
24112
|
"use strict";
|
|
23476
24113
|
init_runtime_checks();
|
|
23477
24114
|
SQLITE_BUSY = 5;
|
|
@@ -23598,7 +24235,7 @@ var init_engine = __esm({
|
|
|
23598
24235
|
}
|
|
23599
24236
|
});
|
|
23600
24237
|
|
|
23601
|
-
// src/
|
|
24238
|
+
// ../shared/persistence/src/db/migrations.ts
|
|
23602
24239
|
function columnExists(db, table, column) {
|
|
23603
24240
|
const result = db.exec(`PRAGMA table_info(${table})`);
|
|
23604
24241
|
const first = result[0];
|
|
@@ -23653,7 +24290,7 @@ function runMigrations(db) {
|
|
|
23653
24290
|
}
|
|
23654
24291
|
var MIGRATIONS;
|
|
23655
24292
|
var init_migrations = __esm({
|
|
23656
|
-
"src/
|
|
24293
|
+
"../shared/persistence/src/db/migrations.ts"() {
|
|
23657
24294
|
"use strict";
|
|
23658
24295
|
MIGRATIONS = [
|
|
23659
24296
|
{
|
|
@@ -24152,7 +24789,31 @@ var init_migrations = __esm({
|
|
|
24152
24789
|
}
|
|
24153
24790
|
});
|
|
24154
24791
|
|
|
24155
|
-
// src/
|
|
24792
|
+
// ../shared/persistence/src/db/result-mapper.ts
|
|
24793
|
+
function resultToRows(result) {
|
|
24794
|
+
if (result.length === 0 || !result[0]) {
|
|
24795
|
+
return [];
|
|
24796
|
+
}
|
|
24797
|
+
const { columns, values } = result[0];
|
|
24798
|
+
return values.map((row) => {
|
|
24799
|
+
const obj = {};
|
|
24800
|
+
for (let i = 0; i < columns.length; i++) {
|
|
24801
|
+
obj[columns[i]] = row[i];
|
|
24802
|
+
}
|
|
24803
|
+
return obj;
|
|
24804
|
+
});
|
|
24805
|
+
}
|
|
24806
|
+
function resultToRow(result) {
|
|
24807
|
+
const rows = resultToRows(result);
|
|
24808
|
+
return rows[0];
|
|
24809
|
+
}
|
|
24810
|
+
var init_result_mapper = __esm({
|
|
24811
|
+
"../shared/persistence/src/db/result-mapper.ts"() {
|
|
24812
|
+
"use strict";
|
|
24813
|
+
}
|
|
24814
|
+
});
|
|
24815
|
+
|
|
24816
|
+
// ../shared/persistence/src/db/queries.ts
|
|
24156
24817
|
function insertSession(db, params) {
|
|
24157
24818
|
const {
|
|
24158
24819
|
id,
|
|
@@ -24267,15 +24928,15 @@ function commitReasonClose(db, sessionId, reasonEvent, projectionUpdates) {
|
|
|
24267
24928
|
});
|
|
24268
24929
|
}
|
|
24269
24930
|
var init_queries = __esm({
|
|
24270
|
-
"src/
|
|
24931
|
+
"../shared/persistence/src/db/queries.ts"() {
|
|
24271
24932
|
"use strict";
|
|
24272
24933
|
init_result_mapper();
|
|
24273
24934
|
}
|
|
24274
24935
|
});
|
|
24275
24936
|
|
|
24276
|
-
// src/
|
|
24277
|
-
import { existsSync as
|
|
24278
|
-
import { isAbsolute as isAbsolute2, join as
|
|
24937
|
+
// ../shared/persistence/src/db/reconcile.ts
|
|
24938
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
24939
|
+
import { isAbsolute as isAbsolute2, join as join9, dirname as dirname5 } from "node:path";
|
|
24279
24940
|
function hasTerminalArtifactEvent(db, sessionId, workflowType, currentRound, currentMapRun) {
|
|
24280
24941
|
const eventType = workflowType === "map" ? "map_completed" : "round_completed";
|
|
24281
24942
|
const round = workflowType === "map" ? currentMapRun : currentRound;
|
|
@@ -24316,7 +24977,7 @@ function hasInFlightDependents(db, sessionId) {
|
|
|
24316
24977
|
function resolveSessionDir(ocrDir, sessionDir) {
|
|
24317
24978
|
if (!sessionDir) return null;
|
|
24318
24979
|
if (isAbsolute2(sessionDir)) return sessionDir;
|
|
24319
|
-
return
|
|
24980
|
+
return join9(dirname5(ocrDir), sessionDir);
|
|
24320
24981
|
}
|
|
24321
24982
|
function reconcileLegacyState(db, ocrDir, opts = {}) {
|
|
24322
24983
|
const dryRun = opts.dryRun ?? false;
|
|
@@ -24328,8 +24989,8 @@ function reconcileLegacyState(db, ocrDir, opts = {}) {
|
|
|
24328
24989
|
if (hasTerminalArtifactEvent(db, s.id, s.workflow_type, s.current_round, s.current_map_run) || hasReasonEvent(db, s.id)) {
|
|
24329
24990
|
continue;
|
|
24330
24991
|
}
|
|
24331
|
-
const reviewFinal = s.workflow_type === "review" && dir ?
|
|
24332
|
-
const mapFinal = s.workflow_type === "map" && dir ?
|
|
24992
|
+
const reviewFinal = s.workflow_type === "review" && dir ? existsSync7(join9(dir, "rounds", `round-${s.current_round}`, "final.md")) : false;
|
|
24993
|
+
const mapFinal = s.workflow_type === "map" && dir ? existsSync7(join9(dir, "map", "runs", `run-${s.current_map_run}`, "map.md")) : false;
|
|
24333
24994
|
if (reviewFinal) {
|
|
24334
24995
|
actions.push({
|
|
24335
24996
|
sessionId: s.id,
|
|
@@ -24405,20 +25066,20 @@ function reconcileLegacyState(db, ocrDir, opts = {}) {
|
|
|
24405
25066
|
}
|
|
24406
25067
|
var DEFAULT_STALE_THRESHOLD_SECONDS;
|
|
24407
25068
|
var init_reconcile = __esm({
|
|
24408
|
-
"src/
|
|
25069
|
+
"../shared/persistence/src/db/reconcile.ts"() {
|
|
24409
25070
|
"use strict";
|
|
24410
25071
|
init_queries();
|
|
24411
25072
|
DEFAULT_STALE_THRESHOLD_SECONDS = 7 * 24 * 60 * 60;
|
|
24412
25073
|
}
|
|
24413
25074
|
});
|
|
24414
25075
|
|
|
24415
|
-
// src/
|
|
25076
|
+
// ../shared/persistence/src/db/liveness.ts
|
|
24416
25077
|
function defaultIsAlive(pid) {
|
|
24417
25078
|
try {
|
|
24418
25079
|
process.kill(pid, 0);
|
|
24419
25080
|
return true;
|
|
24420
25081
|
} catch (err) {
|
|
24421
|
-
return !(err
|
|
25082
|
+
return !killErrorMeansDead(err);
|
|
24422
25083
|
}
|
|
24423
25084
|
}
|
|
24424
25085
|
function sqliteUtcMs(ts) {
|
|
@@ -24427,16 +25088,17 @@ function sqliteUtcMs(ts) {
|
|
|
24427
25088
|
}
|
|
24428
25089
|
var PID_REUSE_GUARD_MS;
|
|
24429
25090
|
var init_liveness = __esm({
|
|
24430
|
-
"src/
|
|
25091
|
+
"../shared/persistence/src/db/liveness.ts"() {
|
|
24431
25092
|
"use strict";
|
|
25093
|
+
init_src();
|
|
24432
25094
|
PID_REUSE_GUARD_MS = 24 * 60 * 60 * 1e3;
|
|
24433
25095
|
}
|
|
24434
25096
|
});
|
|
24435
25097
|
|
|
24436
|
-
// src/
|
|
25098
|
+
// ../shared/persistence/src/state/exit-codes.ts
|
|
24437
25099
|
var STATE_EXIT, StateError, CANCELLED_EXIT_CODE, ORPHAN_EXIT_CODE, CASCADE_CLOSE_EXIT_CODE, WATCHDOG_DEADLINE_EXIT_CODE;
|
|
24438
25100
|
var init_exit_codes = __esm({
|
|
24439
|
-
"src/
|
|
25101
|
+
"../shared/persistence/src/state/exit-codes.ts"() {
|
|
24440
25102
|
"use strict";
|
|
24441
25103
|
STATE_EXIT = {
|
|
24442
25104
|
OK: 0,
|
|
@@ -24463,7 +25125,7 @@ var init_exit_codes = __esm({
|
|
|
24463
25125
|
}
|
|
24464
25126
|
});
|
|
24465
25127
|
|
|
24466
|
-
// src/
|
|
25128
|
+
// ../shared/persistence/src/db/agent-sessions.ts
|
|
24467
25129
|
function cascadeTerminateExecutions(db, workflowId, exitCode, note) {
|
|
24468
25130
|
db.run(
|
|
24469
25131
|
`UPDATE command_executions
|
|
@@ -24634,6 +25296,9 @@ function bindVendorSessionIdOpportunistically(db, vendorSessionId) {
|
|
|
24634
25296
|
);
|
|
24635
25297
|
return candidate.uid ?? String(candidate.id);
|
|
24636
25298
|
}
|
|
25299
|
+
function isSafeVendorSessionId(id) {
|
|
25300
|
+
return SAFE_VENDOR_SESSION_ID.test(id);
|
|
25301
|
+
}
|
|
24637
25302
|
function recordVendorSessionIdForExecution(db, executionId, vendorSessionId) {
|
|
24638
25303
|
db.run(
|
|
24639
25304
|
`UPDATE command_executions
|
|
@@ -24829,9 +25494,9 @@ function sweepStaleSessions(db, thresholdSeconds) {
|
|
|
24829
25494
|
}
|
|
24830
25495
|
return { closedSessionIds: rows.map((r) => r.id) };
|
|
24831
25496
|
}
|
|
24832
|
-
var NOTE_ORPHAN_PREFIX, INSTANCE_COMMAND;
|
|
25497
|
+
var NOTE_ORPHAN_PREFIX, INSTANCE_COMMAND, SAFE_VENDOR_SESSION_ID;
|
|
24833
25498
|
var init_agent_sessions = __esm({
|
|
24834
|
-
"src/
|
|
25499
|
+
"../shared/persistence/src/db/agent-sessions.ts"() {
|
|
24835
25500
|
"use strict";
|
|
24836
25501
|
init_result_mapper();
|
|
24837
25502
|
init_queries();
|
|
@@ -24839,18 +25504,19 @@ var init_agent_sessions = __esm({
|
|
|
24839
25504
|
init_exit_codes();
|
|
24840
25505
|
NOTE_ORPHAN_PREFIX = "orphaned by liveness sweep";
|
|
24841
25506
|
INSTANCE_COMMAND = "session-instance";
|
|
25507
|
+
SAFE_VENDOR_SESSION_ID = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,255}$/;
|
|
24842
25508
|
}
|
|
24843
25509
|
});
|
|
24844
25510
|
|
|
24845
|
-
// src/
|
|
25511
|
+
// ../shared/persistence/src/db/maintenance.ts
|
|
24846
25512
|
import {
|
|
24847
|
-
existsSync as
|
|
24848
|
-
readdirSync as
|
|
25513
|
+
existsSync as existsSync8,
|
|
25514
|
+
readdirSync as readdirSync2,
|
|
24849
25515
|
statSync,
|
|
24850
25516
|
unlinkSync as unlinkSync3,
|
|
24851
25517
|
copyFileSync
|
|
24852
25518
|
} from "node:fs";
|
|
24853
|
-
import { dirname as dirname6, join as
|
|
25519
|
+
import { dirname as dirname6, join as join10, basename as basename3 } from "node:path";
|
|
24854
25520
|
function withForeignKeysDisabled(db, fn) {
|
|
24855
25521
|
db.pragma("foreign_keys = OFF");
|
|
24856
25522
|
try {
|
|
@@ -24877,7 +25543,7 @@ function foreignKeyViolationGroups(db) {
|
|
|
24877
25543
|
function scanOrphanTempFiles(dataDir) {
|
|
24878
25544
|
let entries;
|
|
24879
25545
|
try {
|
|
24880
|
-
entries =
|
|
25546
|
+
entries = readdirSync2(dataDir);
|
|
24881
25547
|
} catch {
|
|
24882
25548
|
return [];
|
|
24883
25549
|
}
|
|
@@ -24888,7 +25554,7 @@ function scanOrphanTempFiles(dataDir) {
|
|
|
24888
25554
|
const pid = Number(m[1]);
|
|
24889
25555
|
let ageMs = 0;
|
|
24890
25556
|
try {
|
|
24891
|
-
ageMs = Date.now() - statSync(
|
|
25557
|
+
ageMs = Date.now() - statSync(join10(dataDir, name)).mtimeMs;
|
|
24892
25558
|
} catch {
|
|
24893
25559
|
continue;
|
|
24894
25560
|
}
|
|
@@ -24907,7 +25573,7 @@ function scanOrphanTempFiles(dataDir) {
|
|
|
24907
25573
|
function scanBackupFiles(dataDir, dbBase) {
|
|
24908
25574
|
let entries;
|
|
24909
25575
|
try {
|
|
24910
|
-
entries =
|
|
25576
|
+
entries = readdirSync2(dataDir);
|
|
24911
25577
|
} catch {
|
|
24912
25578
|
return [];
|
|
24913
25579
|
}
|
|
@@ -24915,7 +25581,7 @@ function scanBackupFiles(dataDir, dbBase) {
|
|
|
24915
25581
|
for (const name of entries) {
|
|
24916
25582
|
if (!name.startsWith(`${dbBase}.bak`)) continue;
|
|
24917
25583
|
try {
|
|
24918
|
-
out.push({ name, sizeBytes: statSync(
|
|
25584
|
+
out.push({ name, sizeBytes: statSync(join10(dataDir, name)).size });
|
|
24919
25585
|
} catch {
|
|
24920
25586
|
}
|
|
24921
25587
|
}
|
|
@@ -24923,7 +25589,7 @@ function scanBackupFiles(dataDir, dbBase) {
|
|
|
24923
25589
|
}
|
|
24924
25590
|
function collectDbHealth(db, dbPath) {
|
|
24925
25591
|
const dataDir = dirname6(dbPath);
|
|
24926
|
-
const dbBase =
|
|
25592
|
+
const dbBase = basename3(dbPath);
|
|
24927
25593
|
const pageSize = scalarInt(db, "PRAGMA page_size");
|
|
24928
25594
|
const pageCount = scalarInt(db, "PRAGMA page_count");
|
|
24929
25595
|
const freelistCount = scalarInt(db, "PRAGMA freelist_count");
|
|
@@ -24935,7 +25601,7 @@ function collectDbHealth(db, dbPath) {
|
|
|
24935
25601
|
const protectedFkViolations = allGroups.filter(
|
|
24936
25602
|
(g) => PROTECTED_TABLES.has(g.table)
|
|
24937
25603
|
);
|
|
24938
|
-
const fileSizeBytes =
|
|
25604
|
+
const fileSizeBytes = existsSync8(dbPath) ? statSync(dbPath).size : 0;
|
|
24939
25605
|
return {
|
|
24940
25606
|
dbPath,
|
|
24941
25607
|
fileSizeBytes,
|
|
@@ -24963,7 +25629,7 @@ function collectDbHealth(db, dbPath) {
|
|
|
24963
25629
|
}
|
|
24964
25630
|
function snapshotDb(db, dbPath, label = "doctor") {
|
|
24965
25631
|
try {
|
|
24966
|
-
if (!
|
|
25632
|
+
if (!existsSync8(dbPath) || statSync(dbPath).size === 0) return null;
|
|
24967
25633
|
db.pragma("wal_checkpoint(TRUNCATE)");
|
|
24968
25634
|
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
24969
25635
|
const bakPath = `${dbPath}.bak.${label}.${ts}`;
|
|
@@ -24978,7 +25644,7 @@ function reapOrphanDbFiles(dataDir) {
|
|
|
24978
25644
|
for (const f of scanOrphanTempFiles(dataDir)) {
|
|
24979
25645
|
if (!f.reapable) continue;
|
|
24980
25646
|
try {
|
|
24981
|
-
unlinkSync3(
|
|
25647
|
+
unlinkSync3(join10(dataDir, f.name));
|
|
24982
25648
|
reaped.push(f.name);
|
|
24983
25649
|
} catch {
|
|
24984
25650
|
}
|
|
@@ -24988,7 +25654,7 @@ function reapOrphanDbFiles(dataDir) {
|
|
|
24988
25654
|
function reapStaleExecLogs(execLogsDir, maxAgeMs = SEVEN_DAYS_MS) {
|
|
24989
25655
|
let entries;
|
|
24990
25656
|
try {
|
|
24991
|
-
entries =
|
|
25657
|
+
entries = readdirSync2(execLogsDir);
|
|
24992
25658
|
} catch {
|
|
24993
25659
|
return [];
|
|
24994
25660
|
}
|
|
@@ -24996,7 +25662,7 @@ function reapStaleExecLogs(execLogsDir, maxAgeMs = SEVEN_DAYS_MS) {
|
|
|
24996
25662
|
const reaped = [];
|
|
24997
25663
|
for (const name of entries) {
|
|
24998
25664
|
if (!name.endsWith(".log")) continue;
|
|
24999
|
-
const full =
|
|
25665
|
+
const full = join10(execLogsDir, name);
|
|
25000
25666
|
try {
|
|
25001
25667
|
if (statSync(full).mtimeMs > cutoff) continue;
|
|
25002
25668
|
unlinkSync3(full);
|
|
@@ -25014,11 +25680,11 @@ function pruneBackups(dataDir, dbPath, opts = {}) {
|
|
|
25014
25680
|
);
|
|
25015
25681
|
}
|
|
25016
25682
|
const dryRun = opts.dryRun ?? false;
|
|
25017
|
-
const dbBase =
|
|
25683
|
+
const dbBase = basename3(dbPath);
|
|
25018
25684
|
const withMtime = [];
|
|
25019
25685
|
for (const file of scanBackupFiles(dataDir, dbBase)) {
|
|
25020
25686
|
try {
|
|
25021
|
-
withMtime.push({ file, mtimeMs: statSync(
|
|
25687
|
+
withMtime.push({ file, mtimeMs: statSync(join10(dataDir, file.name)).mtimeMs });
|
|
25022
25688
|
} catch {
|
|
25023
25689
|
}
|
|
25024
25690
|
}
|
|
@@ -25029,7 +25695,7 @@ function pruneBackups(dataDir, dbPath, opts = {}) {
|
|
|
25029
25695
|
if (!dryRun) {
|
|
25030
25696
|
for (const b of toDelete) {
|
|
25031
25697
|
try {
|
|
25032
|
-
unlinkSync3(
|
|
25698
|
+
unlinkSync3(join10(dataDir, b.name));
|
|
25033
25699
|
deleted.push(b);
|
|
25034
25700
|
} catch {
|
|
25035
25701
|
}
|
|
@@ -25045,7 +25711,7 @@ function pruneBackups(dataDir, dbPath, opts = {}) {
|
|
|
25045
25711
|
}
|
|
25046
25712
|
function fixDb(db, dbPath, opts = {}) {
|
|
25047
25713
|
const dataDir = dirname6(dbPath);
|
|
25048
|
-
const sizeBeforeBytes =
|
|
25714
|
+
const sizeBeforeBytes = existsSync8(dbPath) ? statSync(dbPath).size : 0;
|
|
25049
25715
|
const snapshotPath = opts.snapshot === false ? null : snapshotDb(db, dbPath, "doctor");
|
|
25050
25716
|
const fkOrphansDeleted = [];
|
|
25051
25717
|
withForeignKeysDisabled(db, () => {
|
|
@@ -25089,12 +25755,12 @@ function fixDb(db, dbPath, opts = {}) {
|
|
|
25089
25755
|
};
|
|
25090
25756
|
}
|
|
25091
25757
|
function vacuumDb(db, dbPath, opts = {}) {
|
|
25092
|
-
const sizeBeforeBytes =
|
|
25758
|
+
const sizeBeforeBytes = existsSync8(dbPath) ? statSync(dbPath).size : 0;
|
|
25093
25759
|
const snapshotPath = opts.snapshot === false ? null : snapshotDb(db, dbPath, "vacuum");
|
|
25094
25760
|
db.pragma("wal_checkpoint(TRUNCATE)");
|
|
25095
25761
|
db.run("VACUUM");
|
|
25096
25762
|
db.pragma("wal_checkpoint(TRUNCATE)");
|
|
25097
|
-
const sizeAfterBytes =
|
|
25763
|
+
const sizeAfterBytes = existsSync8(dbPath) ? statSync(dbPath).size : 0;
|
|
25098
25764
|
return {
|
|
25099
25765
|
snapshotPath,
|
|
25100
25766
|
sizeBeforeBytes,
|
|
@@ -25174,7 +25840,7 @@ function pruneDb(db, dbPath, opts = {}) {
|
|
|
25174
25840
|
}
|
|
25175
25841
|
var PROTECTED_TABLES, ORPHAN_SWEEPS, MARKDOWN_DEDUP_SQL, ONE_HOUR_MS, SEVEN_DAYS_MS;
|
|
25176
25842
|
var init_maintenance = __esm({
|
|
25177
|
-
"src/
|
|
25843
|
+
"../shared/persistence/src/db/maintenance.ts"() {
|
|
25178
25844
|
"use strict";
|
|
25179
25845
|
init_src();
|
|
25180
25846
|
PROTECTED_TABLES = /* @__PURE__ */ new Set([
|
|
@@ -25249,24 +25915,24 @@ var init_maintenance = __esm({
|
|
|
25249
25915
|
}
|
|
25250
25916
|
});
|
|
25251
25917
|
|
|
25252
|
-
// src/
|
|
25253
|
-
import { appendFileSync, existsSync as
|
|
25254
|
-
import { dirname as dirname7, join as
|
|
25918
|
+
// ../shared/persistence/src/db/command-log.ts
|
|
25919
|
+
import { appendFileSync, existsSync as existsSync9, mkdirSync as mkdirSync4, readFileSync as readFileSync7, renameSync, writeFileSync as writeFileSync6 } from "node:fs";
|
|
25920
|
+
import { dirname as dirname7, join as join11 } from "node:path";
|
|
25255
25921
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
25256
25922
|
function generateCommandUid() {
|
|
25257
25923
|
return randomUUID2();
|
|
25258
25924
|
}
|
|
25259
25925
|
function cacheDir(ocrDir) {
|
|
25260
|
-
return
|
|
25926
|
+
return join11(ocrDir, "data", CACHE_DIR);
|
|
25261
25927
|
}
|
|
25262
25928
|
function commandLogPath(ocrDir) {
|
|
25263
|
-
return
|
|
25929
|
+
return join11(cacheDir(ocrDir), FILENAME);
|
|
25264
25930
|
}
|
|
25265
25931
|
function appendCommandLog(ocrDir, entry) {
|
|
25266
25932
|
try {
|
|
25267
25933
|
const filePath = commandLogPath(ocrDir);
|
|
25268
25934
|
const dir = dirname7(filePath);
|
|
25269
|
-
if (!
|
|
25935
|
+
if (!existsSync9(dir)) mkdirSync4(dir, { recursive: true });
|
|
25270
25936
|
const line = JSON.stringify(entry) + "\n";
|
|
25271
25937
|
appendFileSync(filePath, line, { encoding: "utf-8" });
|
|
25272
25938
|
if (approxLineCount >= 0) approxLineCount++;
|
|
@@ -25276,8 +25942,8 @@ function appendCommandLog(ocrDir, entry) {
|
|
|
25276
25942
|
}
|
|
25277
25943
|
function readCommandLog(ocrDir) {
|
|
25278
25944
|
const filePath = commandLogPath(ocrDir);
|
|
25279
|
-
if (!
|
|
25280
|
-
const content =
|
|
25945
|
+
if (!existsSync9(filePath)) return [];
|
|
25946
|
+
const content = readFileSync7(filePath, "utf-8");
|
|
25281
25947
|
const entries = [];
|
|
25282
25948
|
for (const line of content.split("\n")) {
|
|
25283
25949
|
if (!line.trim()) continue;
|
|
@@ -25328,7 +25994,7 @@ function replayCommandLog(db, ocrDir) {
|
|
|
25328
25994
|
function rotateIfNeeded(filePath) {
|
|
25329
25995
|
try {
|
|
25330
25996
|
if (approxLineCount >= 0 && approxLineCount <= MAX_LINES) return;
|
|
25331
|
-
const content =
|
|
25997
|
+
const content = readFileSync7(filePath, "utf-8");
|
|
25332
25998
|
const lines = content.split("\n").filter((l) => l.trim());
|
|
25333
25999
|
approxLineCount = lines.length;
|
|
25334
26000
|
if (approxLineCount <= MAX_LINES) return;
|
|
@@ -25342,7 +26008,7 @@ function rotateIfNeeded(filePath) {
|
|
|
25342
26008
|
}
|
|
25343
26009
|
var CACHE_DIR, FILENAME, MAX_LINES, KEEP_LINES, approxLineCount;
|
|
25344
26010
|
var init_command_log = __esm({
|
|
25345
|
-
"src/
|
|
26011
|
+
"../shared/persistence/src/db/command-log.ts"() {
|
|
25346
26012
|
"use strict";
|
|
25347
26013
|
CACHE_DIR = ".cache";
|
|
25348
26014
|
FILENAME = "command-history.jsonl";
|
|
@@ -25352,7 +26018,7 @@ var init_command_log = __esm({
|
|
|
25352
26018
|
}
|
|
25353
26019
|
});
|
|
25354
26020
|
|
|
25355
|
-
// src/
|
|
26021
|
+
// ../shared/persistence/src/db/index.ts
|
|
25356
26022
|
var db_exports = {};
|
|
25357
26023
|
__export(db_exports, {
|
|
25358
26024
|
CANCELLED_EXIT_CODE: () => CANCELLED_EXIT_CODE,
|
|
@@ -25360,6 +26026,7 @@ __export(db_exports, {
|
|
|
25360
26026
|
MIGRATIONS: () => MIGRATIONS,
|
|
25361
26027
|
ORPHAN_EXIT_CODE: () => ORPHAN_EXIT_CODE,
|
|
25362
26028
|
PID_REUSE_GUARD_MS: () => PID_REUSE_GUARD_MS,
|
|
26029
|
+
SAFE_VENDOR_SESSION_ID: () => SAFE_VENDOR_SESSION_ID,
|
|
25363
26030
|
STATE_EXIT: () => STATE_EXIT,
|
|
25364
26031
|
StateError: () => StateError,
|
|
25365
26032
|
WATCHDOG_DEADLINE_EXIT_CODE: () => WATCHDOG_DEADLINE_EXIT_CODE,
|
|
@@ -25392,6 +26059,7 @@ __export(db_exports, {
|
|
|
25392
26059
|
insertEvent: () => insertEvent,
|
|
25393
26060
|
insertSession: () => insertSession,
|
|
25394
26061
|
isBusyError: () => isBusyError,
|
|
26062
|
+
isSafeVendorSessionId: () => isSafeVendorSessionId,
|
|
25395
26063
|
linkDashboardInvocationToWorkflow: () => linkDashboardInvocationToWorkflow,
|
|
25396
26064
|
listAgentSessionsForWorkflow: () => listAgentSessionsForWorkflow,
|
|
25397
26065
|
openDatabase: () => openDatabase,
|
|
@@ -25422,7 +26090,7 @@ __export(db_exports, {
|
|
|
25422
26090
|
withForeignKeysDisabled: () => withForeignKeysDisabled
|
|
25423
26091
|
});
|
|
25424
26092
|
import {
|
|
25425
|
-
existsSync as
|
|
26093
|
+
existsSync as existsSync10,
|
|
25426
26094
|
mkdirSync as mkdirSync5,
|
|
25427
26095
|
copyFileSync as copyFileSync2,
|
|
25428
26096
|
statSync as statSync2,
|
|
@@ -25430,13 +26098,13 @@ import {
|
|
|
25430
26098
|
rmSync
|
|
25431
26099
|
} from "node:fs";
|
|
25432
26100
|
import { tmpdir } from "node:os";
|
|
25433
|
-
import { dirname as dirname8, join as
|
|
26101
|
+
import { dirname as dirname8, join as join12 } from "node:path";
|
|
25434
26102
|
function maybeSnapshotBeforeUpgrade(db, dbPath, fromVersion) {
|
|
25435
26103
|
if (fromVersion < 1 || fromVersion >= V2_SCHEMA_VERSION) return null;
|
|
25436
26104
|
const bakPath = `${dbPath}.bak.v${fromVersion}`;
|
|
25437
|
-
if (
|
|
26105
|
+
if (existsSync10(bakPath)) return bakPath;
|
|
25438
26106
|
try {
|
|
25439
|
-
if (!
|
|
26107
|
+
if (!existsSync10(dbPath) || statSync2(dbPath).size === 0) return null;
|
|
25440
26108
|
db.pragma("wal_checkpoint(TRUNCATE)");
|
|
25441
26109
|
copyFileSync2(dbPath, bakPath);
|
|
25442
26110
|
return bakPath;
|
|
@@ -25472,7 +26140,7 @@ async function openDatabase(dbPath) {
|
|
|
25472
26140
|
return cached;
|
|
25473
26141
|
}
|
|
25474
26142
|
const dir = dirname8(dbPath);
|
|
25475
|
-
if (!
|
|
26143
|
+
if (!existsSync10(dir)) {
|
|
25476
26144
|
mkdirSync5(dir, { recursive: true });
|
|
25477
26145
|
}
|
|
25478
26146
|
const db = openEngine(dbPath);
|
|
@@ -25480,15 +26148,15 @@ async function openDatabase(dbPath) {
|
|
|
25480
26148
|
return db;
|
|
25481
26149
|
}
|
|
25482
26150
|
async function getDb(ocrDir) {
|
|
25483
|
-
const dbPath =
|
|
26151
|
+
const dbPath = join12(ocrDir, "data", "ocr.db");
|
|
25484
26152
|
return openDatabase(dbPath);
|
|
25485
26153
|
}
|
|
25486
26154
|
async function ensureDatabase(ocrDir) {
|
|
25487
|
-
const dataDir =
|
|
25488
|
-
if (!
|
|
26155
|
+
const dataDir = join12(ocrDir, "data");
|
|
26156
|
+
if (!existsSync10(dataDir)) {
|
|
25489
26157
|
mkdirSync5(dataDir, { recursive: true });
|
|
25490
26158
|
}
|
|
25491
|
-
const dbPath =
|
|
26159
|
+
const dbPath = join12(dataDir, "ocr.db");
|
|
25492
26160
|
const db = await openDatabase(dbPath);
|
|
25493
26161
|
let before = 0;
|
|
25494
26162
|
try {
|
|
@@ -25516,7 +26184,7 @@ async function ensureDatabase(ocrDir) {
|
|
|
25516
26184
|
return db;
|
|
25517
26185
|
}
|
|
25518
26186
|
function walCheckpointTruncate(dbPath) {
|
|
25519
|
-
if (!
|
|
26187
|
+
if (!existsSync10(dbPath)) {
|
|
25520
26188
|
return "skipped";
|
|
25521
26189
|
}
|
|
25522
26190
|
const cached = connections.get(dbPath);
|
|
@@ -25558,8 +26226,8 @@ function closeAllDatabases() {
|
|
|
25558
26226
|
function probeWrite() {
|
|
25559
26227
|
let dir;
|
|
25560
26228
|
try {
|
|
25561
|
-
dir = mkdtempSync(
|
|
25562
|
-
const db = openEngine(
|
|
26229
|
+
dir = mkdtempSync(join12(tmpdir(), "ocr-probe-"));
|
|
26230
|
+
const db = openEngine(join12(dir, "probe.db"));
|
|
25563
26231
|
try {
|
|
25564
26232
|
db.run("CREATE TABLE _probe_write (id INTEGER PRIMARY KEY, v TEXT)");
|
|
25565
26233
|
db.transaction(() => {
|
|
@@ -25592,7 +26260,7 @@ function rmDirBestEffort(dir) {
|
|
|
25592
26260
|
}
|
|
25593
26261
|
var V2_SCHEMA_VERSION, connections;
|
|
25594
26262
|
var init_db = __esm({
|
|
25595
|
-
"src/
|
|
26263
|
+
"../shared/persistence/src/db/index.ts"() {
|
|
25596
26264
|
"use strict";
|
|
25597
26265
|
init_engine();
|
|
25598
26266
|
init_migrations();
|
|
@@ -26361,7 +27029,7 @@ if (process.platform === "linux") {
|
|
|
26361
27029
|
// ../../node_modules/.pnpm/signal-exit@4.1.0/node_modules/signal-exit/dist/mjs/index.js
|
|
26362
27030
|
var processOk = (process13) => !!process13 && typeof process13 === "object" && typeof process13.removeListener === "function" && typeof process13.emit === "function" && typeof process13.reallyExit === "function" && typeof process13.listeners === "function" && typeof process13.kill === "function" && typeof process13.pid === "number" && typeof process13.on === "function";
|
|
26363
27031
|
var kExitEmitter = Symbol.for("signal-exit emitter");
|
|
26364
|
-
var
|
|
27032
|
+
var global2 = globalThis;
|
|
26365
27033
|
var ObjectDefineProperty = Object.defineProperty.bind(Object);
|
|
26366
27034
|
var Emitter = class {
|
|
26367
27035
|
emitted = {
|
|
@@ -26375,10 +27043,10 @@ var Emitter = class {
|
|
|
26375
27043
|
count = 0;
|
|
26376
27044
|
id = Math.random();
|
|
26377
27045
|
constructor() {
|
|
26378
|
-
if (
|
|
26379
|
-
return
|
|
27046
|
+
if (global2[kExitEmitter]) {
|
|
27047
|
+
return global2[kExitEmitter];
|
|
26380
27048
|
}
|
|
26381
|
-
ObjectDefineProperty(
|
|
27049
|
+
ObjectDefineProperty(global2, kExitEmitter, {
|
|
26382
27050
|
value: this,
|
|
26383
27051
|
writable: false,
|
|
26384
27052
|
enumerable: false,
|
|
@@ -29352,7 +30020,7 @@ function ensureGitignore(ocrDir) {
|
|
|
29352
30020
|
writeFileSync2(gitignorePath, content);
|
|
29353
30021
|
}
|
|
29354
30022
|
|
|
29355
|
-
// src/
|
|
30023
|
+
// ../shared/config/src/team-config.ts
|
|
29356
30024
|
var import_yaml = __toESM(require_dist(), 1);
|
|
29357
30025
|
import { existsSync as existsSync2, readFileSync as readFileSync3 } from "node:fs";
|
|
29358
30026
|
import { join as join2 } from "node:path";
|
|
@@ -29397,6 +30065,9 @@ function parseTeamConfigYaml(content) {
|
|
|
29397
30065
|
aliases,
|
|
29398
30066
|
defaultModel
|
|
29399
30067
|
);
|
|
30068
|
+
if (resolvedModel !== null) {
|
|
30069
|
+
assertSafeModelId(resolvedModel, `default_team.${persona}[${i}]`);
|
|
30070
|
+
}
|
|
29400
30071
|
team.push({
|
|
29401
30072
|
persona,
|
|
29402
30073
|
instance_index: i + 1,
|
|
@@ -29477,6 +30148,16 @@ function readOptionalString(obj, key, pathLabel) {
|
|
|
29477
30148
|
}
|
|
29478
30149
|
return value;
|
|
29479
30150
|
}
|
|
30151
|
+
var SAFE_MODEL_ID = /^[A-Za-z0-9][A-Za-z0-9._/:@[\]+-]{0,255}$/;
|
|
30152
|
+
function assertSafeModelId(value, pathLabel) {
|
|
30153
|
+
if (SAFE_MODEL_ID.test(value)) return;
|
|
30154
|
+
const allowed = /[A-Za-z0-9._/:@[\]+-]/;
|
|
30155
|
+
const offending = [...value].find((ch) => !allowed.test(ch));
|
|
30156
|
+
const detail = value.length === 0 ? "empty string" : value.length > 256 ? "longer than 256 characters" : offending !== void 0 ? `contains ${JSON.stringify(offending)}` : `starts with ${JSON.stringify(value[0])}`;
|
|
30157
|
+
throw new Error(
|
|
30158
|
+
`${pathLabel}: model id ${detail} \u2014 no vendor model id uses that. Allowed: letters and digits plus . _ / : @ [ ] + - (max 256 chars).`
|
|
30159
|
+
);
|
|
30160
|
+
}
|
|
29480
30161
|
function readAliases(root) {
|
|
29481
30162
|
const models = root["models"];
|
|
29482
30163
|
if (!models || typeof models !== "object" || Array.isArray(models)) return {};
|
|
@@ -29518,6 +30199,9 @@ function resolveTeamComposition(team, override) {
|
|
|
29518
30199
|
result.push(inst);
|
|
29519
30200
|
}
|
|
29520
30201
|
for (const inst of override) {
|
|
30202
|
+
if (inst.model !== null) {
|
|
30203
|
+
assertSafeModelId(inst.model, `override ${inst.persona}#${inst.instance_index}`);
|
|
30204
|
+
}
|
|
29521
30205
|
result.push(inst);
|
|
29522
30206
|
}
|
|
29523
30207
|
return result;
|
|
@@ -30086,7 +30770,7 @@ ${hint}
|
|
|
30086
30770
|
}
|
|
30087
30771
|
|
|
30088
30772
|
// src/lib/version.ts
|
|
30089
|
-
var CLI_VERSION = true ? "2.
|
|
30773
|
+
var CLI_VERSION = true ? "2.3.0" : createRequire(import.meta.url)("../../package.json").version;
|
|
30090
30774
|
|
|
30091
30775
|
// src/lib/deps.ts
|
|
30092
30776
|
init_src();
|
|
@@ -33020,12 +33704,12 @@ function getStrategy(workflowType) {
|
|
|
33020
33704
|
}
|
|
33021
33705
|
|
|
33022
33706
|
// src/lib/progress/detector.ts
|
|
33023
|
-
import { existsSync as
|
|
33024
|
-
import { join as
|
|
33707
|
+
import { existsSync as existsSync11, readdirSync as readdirSync3 } from "node:fs";
|
|
33708
|
+
import { join as join13, basename as basename5 } from "node:path";
|
|
33025
33709
|
|
|
33026
33710
|
// src/lib/progress/session-reader.ts
|
|
33027
|
-
|
|
33028
|
-
import { basename as
|
|
33711
|
+
init_db();
|
|
33712
|
+
import { basename as basename4 } from "node:path";
|
|
33029
33713
|
var cachedDb = null;
|
|
33030
33714
|
function setProgressDb(db) {
|
|
33031
33715
|
cachedDb = db;
|
|
@@ -33044,7 +33728,7 @@ function readSessionState(sessionPath) {
|
|
|
33044
33728
|
}
|
|
33045
33729
|
}
|
|
33046
33730
|
function readFromSqlite(sessionPath, db) {
|
|
33047
|
-
const sessionId =
|
|
33731
|
+
const sessionId = basename4(sessionPath);
|
|
33048
33732
|
let row = resultToRow(
|
|
33049
33733
|
db.exec("SELECT * FROM sessions WHERE id = ?", [sessionId])
|
|
33050
33734
|
);
|
|
@@ -33079,7 +33763,7 @@ function detectWorkflowType(sessionPath, explicitType) {
|
|
|
33079
33763
|
const db = getProgressDb();
|
|
33080
33764
|
if (db) {
|
|
33081
33765
|
try {
|
|
33082
|
-
const sessionId =
|
|
33766
|
+
const sessionId = basename5(sessionPath);
|
|
33083
33767
|
const result = db.exec(
|
|
33084
33768
|
"SELECT workflow_type FROM sessions WHERE id = ?",
|
|
33085
33769
|
[sessionId]
|
|
@@ -33092,8 +33776,8 @@ function detectWorkflowType(sessionPath, explicitType) {
|
|
|
33092
33776
|
} catch {
|
|
33093
33777
|
}
|
|
33094
33778
|
}
|
|
33095
|
-
const hasMapDir =
|
|
33096
|
-
const hasRoundsDir =
|
|
33779
|
+
const hasMapDir = existsSync11(join13(sessionPath, "map"));
|
|
33780
|
+
const hasRoundsDir = existsSync11(join13(sessionPath, "rounds"));
|
|
33097
33781
|
if (hasMapDir && !hasRoundsDir) {
|
|
33098
33782
|
return "map";
|
|
33099
33783
|
}
|
|
@@ -33103,7 +33787,7 @@ function detectWorkflowType(sessionPath, explicitType) {
|
|
|
33103
33787
|
if (hasMapDir && hasRoundsDir) {
|
|
33104
33788
|
if (db) {
|
|
33105
33789
|
try {
|
|
33106
|
-
const sessionId =
|
|
33790
|
+
const sessionId = basename5(sessionPath);
|
|
33107
33791
|
const result = db.exec(
|
|
33108
33792
|
"SELECT current_phase FROM sessions WHERE id = ?",
|
|
33109
33793
|
[sessionId]
|
|
@@ -33127,7 +33811,7 @@ function isSessionActive(sessionPath) {
|
|
|
33127
33811
|
const db = getProgressDb();
|
|
33128
33812
|
if (db) {
|
|
33129
33813
|
try {
|
|
33130
|
-
const sessionId =
|
|
33814
|
+
const sessionId = basename5(sessionPath);
|
|
33131
33815
|
const result = db.exec(
|
|
33132
33816
|
"SELECT status, current_phase FROM sessions WHERE id = ?",
|
|
33133
33817
|
[sessionId]
|
|
@@ -33149,28 +33833,28 @@ function isSessionActive(sessionPath) {
|
|
|
33149
33833
|
}
|
|
33150
33834
|
function detectActiveWorkflows(sessionPath) {
|
|
33151
33835
|
const activeWorkflows = [];
|
|
33152
|
-
const hasRoundsDir =
|
|
33836
|
+
const hasRoundsDir = existsSync11(join13(sessionPath, "rounds"));
|
|
33153
33837
|
if (hasRoundsDir) {
|
|
33154
|
-
const roundsDir =
|
|
33155
|
-
const rounds =
|
|
33838
|
+
const roundsDir = join13(sessionPath, "rounds");
|
|
33839
|
+
const rounds = existsSync11(roundsDir) ? readdirSync3(roundsDir).filter((d) => d.match(/^round-\d+$/)).sort() : [];
|
|
33156
33840
|
if (rounds.length > 0) {
|
|
33157
33841
|
const latestRound = rounds[rounds.length - 1];
|
|
33158
|
-
const finalPath =
|
|
33159
|
-
if (!
|
|
33842
|
+
const finalPath = join13(roundsDir, latestRound, "final.md");
|
|
33843
|
+
if (!existsSync11(finalPath)) {
|
|
33160
33844
|
activeWorkflows.push("review");
|
|
33161
33845
|
}
|
|
33162
33846
|
} else {
|
|
33163
33847
|
activeWorkflows.push("review");
|
|
33164
33848
|
}
|
|
33165
33849
|
}
|
|
33166
|
-
const hasMapDir =
|
|
33850
|
+
const hasMapDir = existsSync11(join13(sessionPath, "map"));
|
|
33167
33851
|
if (hasMapDir) {
|
|
33168
|
-
const runsDir =
|
|
33169
|
-
const runs =
|
|
33852
|
+
const runsDir = join13(sessionPath, "map", "runs");
|
|
33853
|
+
const runs = existsSync11(runsDir) ? readdirSync3(runsDir).filter((d) => d.match(/^run-\d+$/)).sort() : [];
|
|
33170
33854
|
if (runs.length > 0) {
|
|
33171
33855
|
const latestRun = runs[runs.length - 1];
|
|
33172
|
-
const mapPath =
|
|
33173
|
-
if (!
|
|
33856
|
+
const mapPath = join13(runsDir, latestRun, "map.md");
|
|
33857
|
+
if (!existsSync11(mapPath)) {
|
|
33174
33858
|
activeWorkflows.push("map");
|
|
33175
33859
|
}
|
|
33176
33860
|
} else {
|
|
@@ -33181,7 +33865,7 @@ function detectActiveWorkflows(sessionPath) {
|
|
|
33181
33865
|
const db = getProgressDb();
|
|
33182
33866
|
if (db) {
|
|
33183
33867
|
try {
|
|
33184
|
-
const sessionId =
|
|
33868
|
+
const sessionId = basename5(sessionPath);
|
|
33185
33869
|
const result = db.exec(
|
|
33186
33870
|
"SELECT workflow_type, current_phase FROM sessions WHERE id = ?",
|
|
33187
33871
|
[sessionId]
|
|
@@ -33249,8 +33933,8 @@ function padLines(lines) {
|
|
|
33249
33933
|
}
|
|
33250
33934
|
|
|
33251
33935
|
// src/lib/progress/review-strategy.ts
|
|
33252
|
-
import { existsSync as
|
|
33253
|
-
import { join as
|
|
33936
|
+
import { existsSync as existsSync12, readdirSync as readdirSync4, readFileSync as readFileSync8 } from "node:fs";
|
|
33937
|
+
import { join as join14, basename as basename6 } from "node:path";
|
|
33254
33938
|
var REVIEW_PHASES = [
|
|
33255
33939
|
{ key: "context", label: "Context Discovery" },
|
|
33256
33940
|
{ key: "change-context", label: "Change Context" },
|
|
@@ -33262,10 +33946,10 @@ var REVIEW_PHASES = [
|
|
|
33262
33946
|
{ key: "complete", label: "Complete" }
|
|
33263
33947
|
];
|
|
33264
33948
|
function countFindings(filePath) {
|
|
33265
|
-
if (!
|
|
33949
|
+
if (!existsSync12(filePath)) {
|
|
33266
33950
|
return 0;
|
|
33267
33951
|
}
|
|
33268
|
-
const content =
|
|
33952
|
+
const content = readFileSync8(filePath, "utf-8");
|
|
33269
33953
|
const findingMatches = content.match(/^##\s+(Finding|Issue|Suggestion)/gm);
|
|
33270
33954
|
return findingMatches?.length ?? 0;
|
|
33271
33955
|
}
|
|
@@ -33279,27 +33963,27 @@ function formatReviewerName(filename) {
|
|
|
33279
33963
|
return base.charAt(0).toUpperCase() + base.slice(1);
|
|
33280
33964
|
}
|
|
33281
33965
|
function deriveRoundsFromFilesystem(roundsDir) {
|
|
33282
|
-
if (!
|
|
33966
|
+
if (!existsSync12(roundsDir)) {
|
|
33283
33967
|
return [];
|
|
33284
33968
|
}
|
|
33285
|
-
const roundDirs =
|
|
33969
|
+
const roundDirs = readdirSync4(roundsDir).filter((d) => d.match(/^round-\d+$/)).sort((a, b) => {
|
|
33286
33970
|
const numA = parseInt(a.replace("round-", ""));
|
|
33287
33971
|
const numB = parseInt(b.replace("round-", ""));
|
|
33288
33972
|
return numA - numB;
|
|
33289
33973
|
});
|
|
33290
33974
|
return roundDirs.map((dir) => {
|
|
33291
33975
|
const roundNum = parseInt(dir.replace("round-", ""));
|
|
33292
|
-
const roundPath =
|
|
33293
|
-
const reviewsPath =
|
|
33294
|
-
const finalPath =
|
|
33976
|
+
const roundPath = join14(roundsDir, dir);
|
|
33977
|
+
const reviewsPath = join14(roundPath, "reviews");
|
|
33978
|
+
const finalPath = join14(roundPath, "final.md");
|
|
33295
33979
|
const reviewers = [];
|
|
33296
|
-
if (
|
|
33297
|
-
const files =
|
|
33980
|
+
if (existsSync12(reviewsPath)) {
|
|
33981
|
+
const files = readdirSync4(reviewsPath).filter((f) => f.endsWith(".md"));
|
|
33298
33982
|
reviewers.push(...files.map((f) => f.replace(".md", "")));
|
|
33299
33983
|
}
|
|
33300
33984
|
return {
|
|
33301
33985
|
round: roundNum,
|
|
33302
|
-
isComplete:
|
|
33986
|
+
isComplete: existsSync12(finalPath),
|
|
33303
33987
|
reviewers
|
|
33304
33988
|
};
|
|
33305
33989
|
});
|
|
@@ -33309,7 +33993,7 @@ var ReviewProgressStrategy = class {
|
|
|
33309
33993
|
phases = REVIEW_PHASES;
|
|
33310
33994
|
totalPhases = 8;
|
|
33311
33995
|
parseState(sessionPath, preservedStartTime) {
|
|
33312
|
-
const session =
|
|
33996
|
+
const session = basename6(sessionPath);
|
|
33313
33997
|
const state = readSessionState(sessionPath);
|
|
33314
33998
|
if (!state) {
|
|
33315
33999
|
return null;
|
|
@@ -33328,19 +34012,19 @@ var ReviewProgressStrategy = class {
|
|
|
33328
34012
|
parseFromState(session, state, sessionPath, preservedStartTime) {
|
|
33329
34013
|
const effectiveStartTime = state.round_started_at ?? state.started_at;
|
|
33330
34014
|
const startTime = preservedStartTime ?? (effectiveStartTime ? new Date(effectiveStartTime).getTime() : Date.now());
|
|
33331
|
-
const roundsDir =
|
|
34015
|
+
const roundsDir = join14(sessionPath, "rounds");
|
|
33332
34016
|
const rounds = deriveRoundsFromFilesystem(roundsDir);
|
|
33333
34017
|
const highestExistingRound = rounds.length > 0 ? Math.max(...rounds.map((r) => r.round)) : 1;
|
|
33334
34018
|
const stateRound = state.current_round ?? 1;
|
|
33335
34019
|
const currentRound = Math.min(stateRound, highestExistingRound);
|
|
33336
|
-
const currentRoundDir =
|
|
33337
|
-
const reviewsDir =
|
|
34020
|
+
const currentRoundDir = join14(roundsDir, `round-${currentRound}`);
|
|
34021
|
+
const reviewsDir = join14(currentRoundDir, "reviews");
|
|
33338
34022
|
const reviewers = [];
|
|
33339
|
-
if (
|
|
33340
|
-
const entries =
|
|
34023
|
+
if (existsSync12(reviewsDir)) {
|
|
34024
|
+
const entries = readdirSync4(reviewsDir);
|
|
33341
34025
|
const reviewFiles = entries.filter((f) => f.endsWith(".md"));
|
|
33342
34026
|
for (const file of reviewFiles) {
|
|
33343
|
-
const reviewPath =
|
|
34027
|
+
const reviewPath = join14(reviewsDir, file);
|
|
33344
34028
|
const findings = countFindings(reviewPath);
|
|
33345
34029
|
reviewers.push({
|
|
33346
34030
|
name: file.replace(".md", ""),
|
|
@@ -33350,14 +34034,14 @@ var ReviewProgressStrategy = class {
|
|
|
33350
34034
|
});
|
|
33351
34035
|
}
|
|
33352
34036
|
}
|
|
33353
|
-
const contextComplete =
|
|
33354
|
-
|
|
34037
|
+
const contextComplete = existsSync12(
|
|
34038
|
+
join14(sessionPath, "discovered-standards.md")
|
|
33355
34039
|
);
|
|
33356
|
-
const changeContextComplete =
|
|
34040
|
+
const changeContextComplete = existsSync12(join14(sessionPath, "context.md"));
|
|
33357
34041
|
const analysisComplete = changeContextComplete;
|
|
33358
34042
|
const reviewsComplete = state.phase_number > 4;
|
|
33359
|
-
const discourseComplete =
|
|
33360
|
-
const synthesisComplete =
|
|
34043
|
+
const discourseComplete = existsSync12(join14(currentRoundDir, "discourse.md"));
|
|
34044
|
+
const synthesisComplete = existsSync12(join14(currentRoundDir, "final.md"));
|
|
33361
34045
|
return {
|
|
33362
34046
|
workflowType: "review",
|
|
33363
34047
|
session,
|
|
@@ -33489,8 +34173,8 @@ var ReviewProgressStrategy = class {
|
|
|
33489
34173
|
var reviewStrategy = new ReviewProgressStrategy();
|
|
33490
34174
|
|
|
33491
34175
|
// src/lib/progress/map-strategy.ts
|
|
33492
|
-
import { existsSync as
|
|
33493
|
-
import { join as
|
|
34176
|
+
import { existsSync as existsSync13, readdirSync as readdirSync5, readFileSync as readFileSync9 } from "node:fs";
|
|
34177
|
+
import { join as join15, basename as basename7 } from "node:path";
|
|
33494
34178
|
var MAP_PHASES = [
|
|
33495
34179
|
{ key: "map-context", label: "Context Discovery" },
|
|
33496
34180
|
{ key: "topology", label: "Topology Analysis" },
|
|
@@ -33500,23 +34184,23 @@ var MAP_PHASES = [
|
|
|
33500
34184
|
{ key: "complete", label: "Complete" }
|
|
33501
34185
|
];
|
|
33502
34186
|
function deriveRunsFromFilesystem(mapDir) {
|
|
33503
|
-
const runsDir =
|
|
33504
|
-
if (!
|
|
34187
|
+
const runsDir = join15(mapDir, "runs");
|
|
34188
|
+
if (!existsSync13(runsDir)) {
|
|
33505
34189
|
return [];
|
|
33506
34190
|
}
|
|
33507
|
-
const runDirs =
|
|
34191
|
+
const runDirs = readdirSync5(runsDir).filter((d) => d.match(/^run-\d+$/)).sort((a, b) => {
|
|
33508
34192
|
const numA = parseInt(a.replace("run-", ""));
|
|
33509
34193
|
const numB = parseInt(b.replace("run-", ""));
|
|
33510
34194
|
return numA - numB;
|
|
33511
34195
|
});
|
|
33512
34196
|
return runDirs.map((dir) => {
|
|
33513
34197
|
const runNum = parseInt(dir.replace("run-", ""));
|
|
33514
|
-
const runPath =
|
|
33515
|
-
const mapPath =
|
|
34198
|
+
const runPath = join15(runsDir, dir);
|
|
34199
|
+
const mapPath = join15(runPath, "map.md");
|
|
33516
34200
|
let fileCount = 0;
|
|
33517
|
-
const topologyPath =
|
|
33518
|
-
if (
|
|
33519
|
-
const content =
|
|
34201
|
+
const topologyPath = join15(runPath, "topology.md");
|
|
34202
|
+
if (existsSync13(topologyPath)) {
|
|
34203
|
+
const content = readFileSync9(topologyPath, "utf-8");
|
|
33520
34204
|
const fileListMatch = content.match(
|
|
33521
34205
|
/## Canonical File List[\s\S]*?```([\s\S]*?)```/
|
|
33522
34206
|
);
|
|
@@ -33526,7 +34210,7 @@ function deriveRunsFromFilesystem(mapDir) {
|
|
|
33526
34210
|
}
|
|
33527
34211
|
return {
|
|
33528
34212
|
run: runNum,
|
|
33529
|
-
isComplete:
|
|
34213
|
+
isComplete: existsSync13(mapPath),
|
|
33530
34214
|
fileCount
|
|
33531
34215
|
};
|
|
33532
34216
|
});
|
|
@@ -33536,7 +34220,7 @@ var MapProgressStrategy = class {
|
|
|
33536
34220
|
phases = MAP_PHASES;
|
|
33537
34221
|
totalPhases = 6;
|
|
33538
34222
|
parseState(sessionPath, preservedStartTime) {
|
|
33539
|
-
const session =
|
|
34223
|
+
const session = basename7(sessionPath);
|
|
33540
34224
|
const state = readSessionState(sessionPath);
|
|
33541
34225
|
if (!state) {
|
|
33542
34226
|
return null;
|
|
@@ -33558,24 +34242,24 @@ var MapProgressStrategy = class {
|
|
|
33558
34242
|
parseFromState(session, state, sessionPath, preservedStartTime) {
|
|
33559
34243
|
const effectiveStartTime = state.map_started_at ?? state.started_at;
|
|
33560
34244
|
const startTime = preservedStartTime ?? (effectiveStartTime ? new Date(effectiveStartTime).getTime() : Date.now());
|
|
33561
|
-
const mapDir =
|
|
34245
|
+
const mapDir = join15(sessionPath, "map");
|
|
33562
34246
|
const runs = deriveRunsFromFilesystem(mapDir);
|
|
33563
34247
|
const highestExistingRun = runs.length > 0 ? Math.max(...runs.map((r) => r.run)) : 1;
|
|
33564
34248
|
const stateRun = state.current_map_run ?? 1;
|
|
33565
34249
|
const currentRun = Math.min(stateRun, highestExistingRun);
|
|
33566
|
-
const currentRunDir =
|
|
33567
|
-
const contextComplete =
|
|
33568
|
-
|
|
34250
|
+
const currentRunDir = join15(mapDir, "runs", `run-${currentRun}`);
|
|
34251
|
+
const contextComplete = existsSync13(
|
|
34252
|
+
join15(sessionPath, "discovered-standards.md")
|
|
33569
34253
|
);
|
|
33570
|
-
const topologyComplete =
|
|
33571
|
-
const flowAnalysisComplete =
|
|
33572
|
-
|
|
34254
|
+
const topologyComplete = existsSync13(join15(currentRunDir, "topology.md"));
|
|
34255
|
+
const flowAnalysisComplete = existsSync13(
|
|
34256
|
+
join15(currentRunDir, "flow-analysis.md")
|
|
33573
34257
|
);
|
|
33574
|
-
const requirementsMappingComplete =
|
|
33575
|
-
|
|
34258
|
+
const requirementsMappingComplete = existsSync13(
|
|
34259
|
+
join15(currentRunDir, "requirements-mapping.md")
|
|
33576
34260
|
);
|
|
33577
|
-
const synthesisComplete =
|
|
33578
|
-
const hasRequirements =
|
|
34261
|
+
const synthesisComplete = existsSync13(join15(currentRunDir, "map.md"));
|
|
34262
|
+
const hasRequirements = existsSync13(join15(sessionPath, "requirements.md"));
|
|
33579
34263
|
const flowAnalysts = flowAnalysisComplete ? [
|
|
33580
34264
|
{
|
|
33581
34265
|
name: "flow-analyst",
|
|
@@ -34030,10 +34714,10 @@ function renderCombinedProgress(sessionPath, preservedStartTimes, ocrDir) {
|
|
|
34030
34714
|
}
|
|
34031
34715
|
|
|
34032
34716
|
// src/commands/state.ts
|
|
34033
|
-
import { existsSync as
|
|
34034
|
-
import { join as
|
|
34717
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync7, readFileSync as readFileSync12, readdirSync as readdirSync8 } from "node:fs";
|
|
34718
|
+
import { join as join19 } from "node:path";
|
|
34035
34719
|
|
|
34036
|
-
// src/
|
|
34720
|
+
// ../shared/persistence/src/state/index.ts
|
|
34037
34721
|
init_db();
|
|
34038
34722
|
init_exit_codes();
|
|
34039
34723
|
import {
|
|
@@ -34046,7 +34730,7 @@ import {
|
|
|
34046
34730
|
} from "node:fs";
|
|
34047
34731
|
import { join as join17 } from "node:path";
|
|
34048
34732
|
|
|
34049
|
-
// src/
|
|
34733
|
+
// ../shared/persistence/src/state/phase-graph.ts
|
|
34050
34734
|
init_exit_codes();
|
|
34051
34735
|
var REVIEW_PHASE_NUMBERS = {
|
|
34052
34736
|
context: 1,
|
|
@@ -34128,7 +34812,7 @@ function validatePhaseTransition(workflowType, source, target, isRoundBoundary)
|
|
|
34128
34812
|
}
|
|
34129
34813
|
}
|
|
34130
34814
|
|
|
34131
|
-
// src/
|
|
34815
|
+
// ../shared/persistence/src/state/meta-util.ts
|
|
34132
34816
|
var DEFAULT_METADATA_MAX_LEN = 4096;
|
|
34133
34817
|
function sanitizeMetadataString(s, opts = {}) {
|
|
34134
34818
|
const maxLen = opts.maxLen ?? DEFAULT_METADATA_MAX_LEN;
|
|
@@ -34138,9 +34822,11 @@ function sanitizeMetadataString(s, opts = {}) {
|
|
|
34138
34822
|
return out;
|
|
34139
34823
|
}
|
|
34140
34824
|
|
|
34141
|
-
// src/
|
|
34825
|
+
// ../shared/persistence/src/state/round-meta.ts
|
|
34826
|
+
init_src();
|
|
34142
34827
|
var VALID_CATEGORIES = /* @__PURE__ */ new Set(["blocker", "should_fix", "suggestion", "style"]);
|
|
34143
34828
|
var VALID_SEVERITIES = /* @__PURE__ */ new Set(["critical", "high", "medium", "low", "info"]);
|
|
34829
|
+
var MIN_TITLE_LEN = 8;
|
|
34144
34830
|
function validateRoundMeta(meta) {
|
|
34145
34831
|
if (!meta || typeof meta !== "object") {
|
|
34146
34832
|
throw new Error("round-meta.json must be a JSON object");
|
|
@@ -34151,10 +34837,16 @@ function validateRoundMeta(meta) {
|
|
|
34151
34837
|
`Unsupported schema_version: ${String(obj.schema_version)}. Expected 1.`
|
|
34152
34838
|
);
|
|
34153
34839
|
}
|
|
34154
|
-
if (typeof obj.verdict !== "string"
|
|
34155
|
-
throw new Error("round-meta.json must contain a
|
|
34840
|
+
if (typeof obj.verdict !== "string") {
|
|
34841
|
+
throw new Error("round-meta.json must contain a verdict string");
|
|
34842
|
+
}
|
|
34843
|
+
const verdict = sanitizeMetadataString(obj.verdict).trim();
|
|
34844
|
+
if (!isCanonicalVerdict(verdict)) {
|
|
34845
|
+
throw new Error(
|
|
34846
|
+
`round-meta.json verdict "${String(obj.verdict)}" is not one of: ${CANONICAL_VERDICTS.join(", ")}`
|
|
34847
|
+
);
|
|
34156
34848
|
}
|
|
34157
|
-
obj.verdict =
|
|
34849
|
+
obj.verdict = verdict;
|
|
34158
34850
|
if (!Array.isArray(obj.reviewers)) {
|
|
34159
34851
|
throw new Error("round-meta.json must contain a reviewers array");
|
|
34160
34852
|
}
|
|
@@ -34177,8 +34869,10 @@ function validateRoundMeta(meta) {
|
|
|
34177
34869
|
throw new Error("Each finding must be an object");
|
|
34178
34870
|
}
|
|
34179
34871
|
const f = finding;
|
|
34180
|
-
if (typeof f.title !== "string" || f.title.trim().length
|
|
34181
|
-
throw new Error(
|
|
34872
|
+
if (typeof f.title !== "string" || f.title.trim().length < MIN_TITLE_LEN) {
|
|
34873
|
+
throw new Error(
|
|
34874
|
+
`Each finding title must be at least ${MIN_TITLE_LEN} characters; got "${String(f.title)}"`
|
|
34875
|
+
);
|
|
34182
34876
|
}
|
|
34183
34877
|
f.title = sanitizeMetadataString(f.title);
|
|
34184
34878
|
if (typeof f.category !== "string" || !VALID_CATEGORIES.has(f.category)) {
|
|
@@ -34223,25 +34917,144 @@ function validateRoundMeta(meta) {
|
|
|
34223
34917
|
if (typeof sc.suggestions !== "number" || sc.suggestions < 0) {
|
|
34224
34918
|
throw new Error("synthesis_counts.suggestions must be a non-negative number");
|
|
34225
34919
|
}
|
|
34920
|
+
const allFindings = obj.reviewers.flatMap((reviewer) => reviewer.findings);
|
|
34921
|
+
const derived = deriveCounts(allFindings);
|
|
34922
|
+
if (sc.blockers > derived.blocker) {
|
|
34923
|
+
throw new Error(
|
|
34924
|
+
`synthesis_counts.blockers (${sc.blockers}) exceeds the ${derived.blocker} blocker finding(s) present`
|
|
34925
|
+
);
|
|
34926
|
+
}
|
|
34927
|
+
if (sc.should_fix > derived.should_fix) {
|
|
34928
|
+
throw new Error(
|
|
34929
|
+
`synthesis_counts.should_fix (${sc.should_fix}) exceeds the ${derived.should_fix} should_fix finding(s) present`
|
|
34930
|
+
);
|
|
34931
|
+
}
|
|
34932
|
+
if (sc.suggestions > derived.suggestion) {
|
|
34933
|
+
throw new Error(
|
|
34934
|
+
`synthesis_counts.suggestions (${sc.suggestions}) exceeds the ${derived.suggestion} suggestion finding(s) present`
|
|
34935
|
+
);
|
|
34936
|
+
}
|
|
34937
|
+
}
|
|
34938
|
+
const { blockerCount } = resolveRoundCounts(obj);
|
|
34939
|
+
if (verdict === "APPROVE" && blockerCount > 0) {
|
|
34940
|
+
throw new Error(
|
|
34941
|
+
`round-meta.json verdict "APPROVE" is inconsistent with ${blockerCount} blocker finding(s); APPROVE requires zero blockers (use "REQUEST CHANGES", or carry residual work as should_fix/suggestion/style)`
|
|
34942
|
+
);
|
|
34943
|
+
}
|
|
34944
|
+
if (verdict === "REQUEST CHANGES" && blockerCount === 0) {
|
|
34945
|
+
throw new Error(
|
|
34946
|
+
`round-meta.json verdict "REQUEST CHANGES" requires at least one blocker finding; found ${blockerCount} (use "APPROVE" if there is nothing to block on, or "NEEDS DISCUSSION")`
|
|
34947
|
+
);
|
|
34226
34948
|
}
|
|
34227
34949
|
return meta;
|
|
34228
34950
|
}
|
|
34229
34951
|
function computeRoundCounts(meta) {
|
|
34230
|
-
|
|
34231
|
-
|
|
34232
|
-
|
|
34952
|
+
return resolveRoundCounts(meta);
|
|
34953
|
+
}
|
|
34954
|
+
|
|
34955
|
+
// ../shared/persistence/src/state/forward-resume.ts
|
|
34956
|
+
init_db();
|
|
34957
|
+
init_liveness();
|
|
34958
|
+
var FORWARD_RESUME_KIND = "forward_resume";
|
|
34959
|
+
var FORWARD_RESUME_EXHAUSTED_REASON = "forward_resume_exhausted";
|
|
34960
|
+
function parseLeaseMetadata(e) {
|
|
34961
|
+
if (e.event_type !== "session_resumed" || !e.metadata) return null;
|
|
34962
|
+
try {
|
|
34963
|
+
return JSON.parse(e.metadata);
|
|
34964
|
+
} catch {
|
|
34965
|
+
return null;
|
|
34966
|
+
}
|
|
34967
|
+
}
|
|
34968
|
+
function remainingPhasesAfter(workflowType, currentPhase) {
|
|
34969
|
+
const numbers = workflowType === "map" ? MAP_PHASE_NUMBERS : REVIEW_PHASE_NUMBERS;
|
|
34970
|
+
const cur = numbers[currentPhase];
|
|
34971
|
+
if (cur === void 0) return [];
|
|
34972
|
+
return Object.entries(numbers).filter(([, n]) => n > cur).sort((a, b) => a[1] - b[1]).map(([phase]) => phase);
|
|
34973
|
+
}
|
|
34974
|
+
function countForwardResumeLeases(events, round) {
|
|
34975
|
+
return events.filter((e) => parseLeaseMetadata(e)?.kind === FORWARD_RESUME_KIND && parseLeaseMetadata(e)?.round === round).length;
|
|
34976
|
+
}
|
|
34977
|
+
function forwardResumeLeaseState(events, round, leaseMs, nowMs) {
|
|
34978
|
+
const leases = events.filter(
|
|
34979
|
+
(e) => parseLeaseMetadata(e)?.kind === FORWARD_RESUME_KIND && parseLeaseMetadata(e)?.round === round
|
|
34980
|
+
);
|
|
34981
|
+
if (leases.length === 0) return { leaseCount: 0, activeLeaseHeld: false };
|
|
34982
|
+
const latestLease = leases[leases.length - 1];
|
|
34983
|
+
const latestLeaseMs = sqliteUtcMs(latestLease.created_at);
|
|
34984
|
+
let effectiveMs = latestLeaseMs;
|
|
34985
|
+
for (const e of events) {
|
|
34986
|
+
if (e.event_type === "phase_transition" && (e.round == null || e.round === round)) {
|
|
34987
|
+
const t = sqliteUtcMs(e.created_at);
|
|
34988
|
+
if (t >= latestLeaseMs && t > effectiveMs) effectiveMs = t;
|
|
34989
|
+
}
|
|
34233
34990
|
}
|
|
34234
|
-
const sc = meta.synthesis_counts;
|
|
34235
34991
|
return {
|
|
34236
|
-
|
|
34237
|
-
|
|
34238
|
-
suggestionCount: sc ? sc.suggestions : allFindings.filter((f) => f.category === "suggestion").length,
|
|
34239
|
-
reviewerCount: meta.reviewers.length,
|
|
34240
|
-
totalFindingCount: allFindings.length
|
|
34992
|
+
leaseCount: leases.length,
|
|
34993
|
+
activeLeaseHeld: nowMs - effectiveMs < leaseMs
|
|
34241
34994
|
};
|
|
34242
34995
|
}
|
|
34996
|
+
function tryAcquireForwardResumeLease(db, sessionId, round, opts) {
|
|
34997
|
+
const nowMs = opts.nowMs ?? Date.now();
|
|
34998
|
+
return db.transaction(() => {
|
|
34999
|
+
const events = getEventsForSession(db, sessionId);
|
|
35000
|
+
const { leaseCount, activeLeaseHeld } = forwardResumeLeaseState(
|
|
35001
|
+
events,
|
|
35002
|
+
round,
|
|
35003
|
+
opts.leaseMs,
|
|
35004
|
+
nowMs
|
|
35005
|
+
);
|
|
35006
|
+
if (leaseCount >= opts.maxAttempts) {
|
|
35007
|
+
return { acquired: false, reason: "cap_exhausted", attemptsUsed: leaseCount };
|
|
35008
|
+
}
|
|
35009
|
+
if (activeLeaseHeld) {
|
|
35010
|
+
return { acquired: false, reason: "lease_held", attemptsUsed: leaseCount };
|
|
35011
|
+
}
|
|
35012
|
+
insertEvent(db, {
|
|
35013
|
+
session_id: sessionId,
|
|
35014
|
+
event_type: "session_resumed",
|
|
35015
|
+
metadata: JSON.stringify({ kind: FORWARD_RESUME_KIND, round })
|
|
35016
|
+
});
|
|
35017
|
+
return { acquired: true, attemptsUsed: leaseCount + 1 };
|
|
35018
|
+
});
|
|
35019
|
+
}
|
|
35020
|
+
function hasLiveOwningTurn(db, sessionId, heartbeatMs, nowMs) {
|
|
35021
|
+
const instances = listAgentSessionsForWorkflow(db, sessionId);
|
|
35022
|
+
return instances.some(
|
|
35023
|
+
(s) => s.ended_at == null && nowMs - sqliteUtcMs(s.last_heartbeat_at) <= heartbeatMs
|
|
35024
|
+
);
|
|
35025
|
+
}
|
|
35026
|
+
function deriveStrandedStatus(db, session, cfg) {
|
|
35027
|
+
const nowMs = cfg.nowMs ?? Date.now();
|
|
35028
|
+
if (hasLiveOwningTurn(db, session.id, cfg.heartbeatMs, nowMs)) return null;
|
|
35029
|
+
return strandedActionByCap(db, session, cfg.maxAttempts);
|
|
35030
|
+
}
|
|
35031
|
+
function strandedActionByCap(db, session, maxAttempts) {
|
|
35032
|
+
const events = getEventsForSession(db, session.id);
|
|
35033
|
+
const leaseCount = countForwardResumeLeases(events, session.current_round);
|
|
35034
|
+
const workflowType = session.workflow_type === "map" ? "map" : "review";
|
|
35035
|
+
return {
|
|
35036
|
+
action: leaseCount >= maxAttempts ? "abort_or_fresh" : "forward_resume",
|
|
35037
|
+
remainingPhases: remainingPhasesAfter(workflowType, session.current_phase),
|
|
35038
|
+
attemptsRemaining: Math.max(0, maxAttempts - leaseCount)
|
|
35039
|
+
};
|
|
35040
|
+
}
|
|
35041
|
+
function closeForwardResumeExhausted(db, sessionId, attempts) {
|
|
35042
|
+
commitReasonClose(
|
|
35043
|
+
db,
|
|
35044
|
+
sessionId,
|
|
35045
|
+
{
|
|
35046
|
+
event_type: "session_auto_closed_stale",
|
|
35047
|
+
phase: "complete",
|
|
35048
|
+
metadata: JSON.stringify({
|
|
35049
|
+
reason: FORWARD_RESUME_EXHAUSTED_REASON,
|
|
35050
|
+
attempts
|
|
35051
|
+
})
|
|
35052
|
+
},
|
|
35053
|
+
{ status: "closed", current_phase: "complete" }
|
|
35054
|
+
);
|
|
35055
|
+
}
|
|
34243
35056
|
|
|
34244
|
-
// src/
|
|
35057
|
+
// ../shared/persistence/src/state/map-meta.ts
|
|
34245
35058
|
function validateMapMeta(meta) {
|
|
34246
35059
|
if (!meta || typeof meta !== "object") {
|
|
34247
35060
|
throw new Error("map-meta.json must be a JSON object");
|
|
@@ -34308,7 +35121,7 @@ function computeMapCounts(meta) {
|
|
|
34308
35121
|
};
|
|
34309
35122
|
}
|
|
34310
35123
|
|
|
34311
|
-
// src/
|
|
35124
|
+
// ../shared/persistence/src/state/projection.ts
|
|
34312
35125
|
init_db();
|
|
34313
35126
|
var REASON_EVENT_TYPES = [
|
|
34314
35127
|
"session_aborted",
|
|
@@ -34338,7 +35151,7 @@ function getCompletenessState(db, sessionId) {
|
|
|
34338
35151
|
return r[0]?.values[0]?.[0] ?? null;
|
|
34339
35152
|
}
|
|
34340
35153
|
|
|
34341
|
-
// src/
|
|
35154
|
+
// ../shared/persistence/src/state/index.ts
|
|
34342
35155
|
init_exit_codes();
|
|
34343
35156
|
function deriveNextRound(db, sessionId, fallbackRound) {
|
|
34344
35157
|
const result = db.exec(
|
|
@@ -34393,6 +35206,12 @@ async function stateInit(params) {
|
|
|
34393
35206
|
`Cannot re-open session ${sessionId} as workflow_type "${workflowType}": existing workflow_type is "${existing.workflow_type}". Maps and reviews have disjoint phase graphs.`
|
|
34394
35207
|
);
|
|
34395
35208
|
}
|
|
35209
|
+
if (existing.status === "active" && !hasCompletionInvariant(db, existing)) {
|
|
35210
|
+
throw new StateError(
|
|
35211
|
+
STATE_EXIT.INVARIANT_UNMET,
|
|
35212
|
+
`Session ${sessionId} is active and its current round is not complete \u2014 'begin' would reset it to "${initialPhaseFor(workflowType)}" and lose progress. Forward-resume instead: re-run the review (it continues from current_phase via 'ocr state status --json'), or 'ocr review --resume ${sessionId}'.`
|
|
35213
|
+
);
|
|
35214
|
+
}
|
|
34396
35215
|
const nextRound = deriveNextRound(db, sessionId, existing.current_round);
|
|
34397
35216
|
const initialPhase2 = workflowType === "map" ? "map-context" : "context";
|
|
34398
35217
|
db.transaction(() => {
|
|
@@ -34692,18 +35511,19 @@ async function stateCompleteRound(params) {
|
|
|
34692
35511
|
}
|
|
34693
35512
|
const resolved = resolveSession(db, params.sessionId);
|
|
34694
35513
|
const roundNumber = params.round ?? resolved.current_round;
|
|
34695
|
-
const
|
|
34696
|
-
|
|
34697
|
-
|
|
34698
|
-
|
|
34699
|
-
|
|
34700
|
-
|
|
35514
|
+
const roundDir = join17(resolved.session_dir, "rounds", `round-${roundNumber}`);
|
|
35515
|
+
const roundMetaPath = join17(roundDir, "round-meta.json");
|
|
35516
|
+
const materializeArtifact = () => {
|
|
35517
|
+
mkdirSync6(roundDir, { recursive: true });
|
|
35518
|
+
writeFileSync7(roundMetaPath, JSON.stringify(meta, null, 2));
|
|
35519
|
+
};
|
|
34701
35520
|
const already = db.exec(
|
|
34702
35521
|
`SELECT 1 FROM orchestration_events
|
|
34703
35522
|
WHERE session_id = ? AND event_type = 'round_completed' AND round = ? LIMIT 1`,
|
|
34704
35523
|
[resolved.id, roundNumber]
|
|
34705
35524
|
);
|
|
34706
35525
|
if ((already[0]?.values.length ?? 0) > 0) {
|
|
35526
|
+
if (!existsSync15(roundMetaPath)) materializeArtifact();
|
|
34707
35527
|
return { sessionId: resolved.id, round: roundNumber, metaPath: roundMetaPath, schema_version: 1 };
|
|
34708
35528
|
}
|
|
34709
35529
|
if (resolved.current_phase !== "synthesis") {
|
|
@@ -34713,7 +35533,7 @@ async function stateCompleteRound(params) {
|
|
|
34713
35533
|
);
|
|
34714
35534
|
}
|
|
34715
35535
|
if (params.requireFinal) {
|
|
34716
|
-
const finalPath = join17(
|
|
35536
|
+
const finalPath = join17(roundDir, "final.md");
|
|
34717
35537
|
if (!existsSync15(finalPath)) {
|
|
34718
35538
|
throw new StateError(
|
|
34719
35539
|
STATE_EXIT.INVARIANT_UNMET,
|
|
@@ -34721,13 +35541,8 @@ async function stateCompleteRound(params) {
|
|
|
34721
35541
|
);
|
|
34722
35542
|
}
|
|
34723
35543
|
}
|
|
34724
|
-
|
|
34725
|
-
|
|
34726
|
-
const roundDir = join17(resolved.session_dir, "rounds", `round-${roundNumber}`);
|
|
34727
|
-
mkdirSync6(roundDir, { recursive: true });
|
|
34728
|
-
metaPath = roundMetaPath;
|
|
34729
|
-
writeFileSync7(metaPath, JSON.stringify(meta, null, 2));
|
|
34730
|
-
}
|
|
35544
|
+
materializeArtifact();
|
|
35545
|
+
const metaPath = roundMetaPath;
|
|
34731
35546
|
db.transaction(() => {
|
|
34732
35547
|
insertEvent(db, {
|
|
34733
35548
|
session_id: resolved.id,
|
|
@@ -34778,19 +35593,19 @@ async function stateCompleteMap(params) {
|
|
|
34778
35593
|
}
|
|
34779
35594
|
const resolved = resolveSession(db, params.sessionId);
|
|
34780
35595
|
const mapRunNumber = params.mapRun ?? resolved.current_map_run;
|
|
34781
|
-
const
|
|
34782
|
-
|
|
34783
|
-
|
|
34784
|
-
|
|
34785
|
-
|
|
34786
|
-
|
|
34787
|
-
);
|
|
35596
|
+
const runDir = join17(resolved.session_dir, "map", "runs", `run-${mapRunNumber}`);
|
|
35597
|
+
const mapMetaPath = join17(runDir, "map-meta.json");
|
|
35598
|
+
const materializeArtifact = () => {
|
|
35599
|
+
mkdirSync6(runDir, { recursive: true });
|
|
35600
|
+
writeFileSync7(mapMetaPath, JSON.stringify(meta, null, 2));
|
|
35601
|
+
};
|
|
34788
35602
|
const already = db.exec(
|
|
34789
35603
|
`SELECT 1 FROM orchestration_events
|
|
34790
35604
|
WHERE session_id = ? AND event_type = 'map_completed' AND round = ? LIMIT 1`,
|
|
34791
35605
|
[resolved.id, mapRunNumber]
|
|
34792
35606
|
);
|
|
34793
35607
|
if ((already[0]?.values.length ?? 0) > 0) {
|
|
35608
|
+
if (!existsSync15(mapMetaPath)) materializeArtifact();
|
|
34794
35609
|
return { sessionId: resolved.id, mapRun: mapRunNumber, metaPath: mapMetaPath, schema_version: 1 };
|
|
34795
35610
|
}
|
|
34796
35611
|
if (resolved.current_phase !== "synthesis") {
|
|
@@ -34799,13 +35614,8 @@ async function stateCompleteMap(params) {
|
|
|
34799
35614
|
`Cannot complete map: workflow is at "${resolved.current_phase}", not "synthesis". Advance first.`
|
|
34800
35615
|
);
|
|
34801
35616
|
}
|
|
34802
|
-
|
|
34803
|
-
|
|
34804
|
-
const runDir = join17(resolved.session_dir, "map", "runs", `run-${mapRunNumber}`);
|
|
34805
|
-
mkdirSync6(runDir, { recursive: true });
|
|
34806
|
-
metaPath = mapMetaPath;
|
|
34807
|
-
writeFileSync7(metaPath, JSON.stringify(meta, null, 2));
|
|
34808
|
-
}
|
|
35617
|
+
materializeArtifact();
|
|
35618
|
+
const metaPath = mapMetaPath;
|
|
34809
35619
|
db.transaction(() => {
|
|
34810
35620
|
insertEvent(db, {
|
|
34811
35621
|
session_id: resolved.id,
|
|
@@ -34831,7 +35641,7 @@ async function stateCompleteMap(params) {
|
|
|
34831
35641
|
});
|
|
34832
35642
|
return { sessionId: resolved.id, mapRun: mapRunNumber, metaPath, schema_version: 1 };
|
|
34833
35643
|
}
|
|
34834
|
-
async function stateStatus(ocrDir, sessionId) {
|
|
35644
|
+
async function stateStatus(ocrDir, sessionId, forwardResume) {
|
|
34835
35645
|
const db = await ensureDatabase(ocrDir);
|
|
34836
35646
|
const resolved = resolveSession(db, sessionId);
|
|
34837
35647
|
const view = db.exec(
|
|
@@ -34844,6 +35654,8 @@ async function stateStatus(ocrDir, sessionId) {
|
|
|
34844
35654
|
const hasTerminalArtifact = row?.[1] === 1;
|
|
34845
35655
|
let nextAction;
|
|
34846
35656
|
let nextActionKind;
|
|
35657
|
+
let remainingPhases;
|
|
35658
|
+
let attemptsRemaining;
|
|
34847
35659
|
switch (completenessState) {
|
|
34848
35660
|
case "complete":
|
|
34849
35661
|
nextAction = "none \u2014 session is complete";
|
|
@@ -34861,12 +35673,25 @@ async function stateStatus(ocrDir, sessionId) {
|
|
|
34861
35673
|
if (hasTerminalArtifact) {
|
|
34862
35674
|
nextAction = "run 'ocr state finish' to close the workflow";
|
|
34863
35675
|
nextActionKind = "finish";
|
|
34864
|
-
} else if (resolved.current_phase === "synthesis") {
|
|
34865
|
-
nextAction = "pipe round metadata to 'ocr state complete-round --stdin'";
|
|
34866
|
-
nextActionKind = "complete_round";
|
|
34867
35676
|
} else {
|
|
34868
|
-
|
|
34869
|
-
|
|
35677
|
+
const stranded = forwardResume && resolved.status === "active" ? deriveStrandedStatus(db, resolved, forwardResume) : null;
|
|
35678
|
+
if (stranded) {
|
|
35679
|
+
remainingPhases = stranded.remainingPhases;
|
|
35680
|
+
attemptsRemaining = stranded.attemptsRemaining;
|
|
35681
|
+
if (stranded.action === "forward_resume") {
|
|
35682
|
+
nextAction = `forward-resume from '${resolved.current_phase}': re-run the review (it continues via 'ocr state status --json'), or 'ocr review --resume ${resolved.id}'`;
|
|
35683
|
+
nextActionKind = "forward_resume";
|
|
35684
|
+
} else {
|
|
35685
|
+
nextAction = "forward-resume attempts exhausted \u2014 abort with 'ocr state finish --abort' or start a fresh review";
|
|
35686
|
+
nextActionKind = "abort_or_fresh";
|
|
35687
|
+
}
|
|
35688
|
+
} else if (resolved.current_phase === "synthesis") {
|
|
35689
|
+
nextAction = "pipe round metadata to 'ocr state complete-round --stdin'";
|
|
35690
|
+
nextActionKind = "complete_round";
|
|
35691
|
+
} else {
|
|
35692
|
+
nextAction = "advance through the phases, then 'ocr state complete-round'";
|
|
35693
|
+
nextActionKind = "advance";
|
|
35694
|
+
}
|
|
34870
35695
|
}
|
|
34871
35696
|
}
|
|
34872
35697
|
return {
|
|
@@ -34882,7 +35707,9 @@ async function stateStatus(ocrDir, sessionId) {
|
|
|
34882
35707
|
marked_closed: row?.[2] === 1,
|
|
34883
35708
|
dependents_settled: row?.[3] === 1,
|
|
34884
35709
|
next_action: nextAction,
|
|
34885
|
-
next_action_kind: nextActionKind
|
|
35710
|
+
next_action_kind: nextActionKind,
|
|
35711
|
+
...remainingPhases ? { remaining_phases: remainingPhases } : {},
|
|
35712
|
+
...attemptsRemaining !== void 0 ? { forward_resume_attempts_remaining: attemptsRemaining } : {}
|
|
34886
35713
|
};
|
|
34887
35714
|
}
|
|
34888
35715
|
async function stateSync(ocrDir) {
|
|
@@ -34970,14 +35797,73 @@ async function stateSync(ocrDir) {
|
|
|
34970
35797
|
}
|
|
34971
35798
|
|
|
34972
35799
|
// src/commands/state.ts
|
|
34973
|
-
init_command_log();
|
|
34974
35800
|
init_db();
|
|
34975
35801
|
init_db();
|
|
34976
|
-
|
|
34977
|
-
|
|
35802
|
+
|
|
35803
|
+
// ../shared/config/src/runtime-config.ts
|
|
35804
|
+
import { existsSync as existsSync16, readFileSync as readFileSync11 } from "node:fs";
|
|
35805
|
+
import { join as join18 } from "node:path";
|
|
35806
|
+
var DEFAULT_AGENT_HEARTBEAT_SECONDS = 60;
|
|
35807
|
+
var DEFAULT_FORWARD_RESUME_MAX_ATTEMPTS = 2;
|
|
35808
|
+
var DEFAULT_FORWARD_RESUME_LEASE_SECONDS = 1800;
|
|
35809
|
+
function readRuntimePositiveInt(ocrDir, key, defaultValue) {
|
|
35810
|
+
const configPath = join18(ocrDir, "config.yaml");
|
|
35811
|
+
if (!existsSync16(configPath)) return defaultValue;
|
|
35812
|
+
let content;
|
|
35813
|
+
try {
|
|
35814
|
+
content = readFileSync11(configPath, "utf-8");
|
|
35815
|
+
} catch {
|
|
35816
|
+
return defaultValue;
|
|
35817
|
+
}
|
|
35818
|
+
const blockMatch = content.match(
|
|
35819
|
+
new RegExp(
|
|
35820
|
+
String.raw`^runtime:\s*\n(?:\s+[^\n]*\n)*?\s+${key}:\s*([^\s#\n]+)`,
|
|
35821
|
+
"m"
|
|
35822
|
+
)
|
|
35823
|
+
);
|
|
35824
|
+
const inlineMatch = content.match(
|
|
35825
|
+
new RegExp(String.raw`^runtime:\s*\{[^}]*\b${key}:\s*([^\s,}]+)`, "m")
|
|
35826
|
+
);
|
|
35827
|
+
const raw = blockMatch?.[1] ?? inlineMatch?.[1];
|
|
35828
|
+
if (!raw) return defaultValue;
|
|
35829
|
+
const parsed = Number(raw);
|
|
35830
|
+
if (!Number.isFinite(parsed) || parsed <= 0 || !Number.isInteger(parsed)) {
|
|
35831
|
+
process.stderr.write(
|
|
35832
|
+
`[ocr] runtime.${key} is not a positive integer (got "${raw}"); falling back to ${defaultValue}.
|
|
35833
|
+
`
|
|
35834
|
+
);
|
|
35835
|
+
return defaultValue;
|
|
35836
|
+
}
|
|
35837
|
+
return parsed;
|
|
35838
|
+
}
|
|
35839
|
+
function getAgentHeartbeatSeconds(ocrDir) {
|
|
35840
|
+
return readRuntimePositiveInt(
|
|
35841
|
+
ocrDir,
|
|
35842
|
+
"agent_heartbeat_seconds",
|
|
35843
|
+
DEFAULT_AGENT_HEARTBEAT_SECONDS
|
|
35844
|
+
);
|
|
35845
|
+
}
|
|
35846
|
+
function getForwardResumeMaxAttempts(ocrDir) {
|
|
35847
|
+
return readRuntimePositiveInt(
|
|
35848
|
+
ocrDir,
|
|
35849
|
+
"forward_resume_max_attempts",
|
|
35850
|
+
DEFAULT_FORWARD_RESUME_MAX_ATTEMPTS
|
|
35851
|
+
);
|
|
35852
|
+
}
|
|
35853
|
+
function getForwardResumeLeaseMs(ocrDir) {
|
|
35854
|
+
return readRuntimePositiveInt(
|
|
35855
|
+
ocrDir,
|
|
35856
|
+
"forward_resume_lease_seconds",
|
|
35857
|
+
DEFAULT_FORWARD_RESUME_LEASE_SECONDS
|
|
35858
|
+
) * 1e3;
|
|
35859
|
+
}
|
|
35860
|
+
|
|
35861
|
+
// src/commands/state.ts
|
|
35862
|
+
init_db();
|
|
35863
|
+
function readMarkerFile(path2) {
|
|
34978
35864
|
let raw;
|
|
34979
35865
|
try {
|
|
34980
|
-
raw =
|
|
35866
|
+
raw = readFileSync12(path2, "utf-8");
|
|
34981
35867
|
} catch {
|
|
34982
35868
|
return null;
|
|
34983
35869
|
}
|
|
@@ -34998,6 +35884,30 @@ function readDashboardSpawnMarker(ocrDir) {
|
|
|
34998
35884
|
}
|
|
34999
35885
|
return marker;
|
|
35000
35886
|
}
|
|
35887
|
+
function readDashboardSpawnMarker(ocrDir) {
|
|
35888
|
+
const dir = join19(ocrDir, "data", "dashboard-active-spawn");
|
|
35889
|
+
let entries = [];
|
|
35890
|
+
try {
|
|
35891
|
+
entries = readdirSync8(dir).filter((f) => f.endsWith(".json"));
|
|
35892
|
+
} catch {
|
|
35893
|
+
entries = [];
|
|
35894
|
+
}
|
|
35895
|
+
const live = [];
|
|
35896
|
+
for (const entry of entries) {
|
|
35897
|
+
const marker = readMarkerFile(join19(dir, entry));
|
|
35898
|
+
if (marker) live.push(marker);
|
|
35899
|
+
}
|
|
35900
|
+
if (live.length === 1) return live[0] ?? null;
|
|
35901
|
+
if (live.length > 1) {
|
|
35902
|
+
console.error(
|
|
35903
|
+
source_default.gray(
|
|
35904
|
+
`[state] ${live.length} concurrent dashboard spawns live; marker fallback is ambiguous \u2014 pass --dashboard-uid for linkage`
|
|
35905
|
+
)
|
|
35906
|
+
);
|
|
35907
|
+
return null;
|
|
35908
|
+
}
|
|
35909
|
+
return readMarkerFile(join19(ocrDir, "data", "dashboard-active-spawn.json"));
|
|
35910
|
+
}
|
|
35001
35911
|
async function readStdin() {
|
|
35002
35912
|
const chunks = [];
|
|
35003
35913
|
for await (const chunk of process.stdin) {
|
|
@@ -35039,7 +35949,7 @@ async function linkDashboardInvocation(ocrDir, sessionId, explicitUid, label) {
|
|
|
35039
35949
|
var showSubcommand = new Command("show").description("Show current session state").option("--session-id <id>", "Session ID (defaults to latest active)").option("--json", "Output as JSON").action(async (options) => {
|
|
35040
35950
|
const targetDir = process.cwd();
|
|
35041
35951
|
requireOcrSetup(targetDir);
|
|
35042
|
-
const ocrDir =
|
|
35952
|
+
const ocrDir = join19(targetDir, ".ocr");
|
|
35043
35953
|
try {
|
|
35044
35954
|
const result = await stateShow(ocrDir, options.sessionId);
|
|
35045
35955
|
if (!result) {
|
|
@@ -35108,7 +36018,7 @@ var showSubcommand = new Command("show").description("Show current session state
|
|
|
35108
36018
|
var syncSubcommand = new Command("sync").description("Rebuild session state from filesystem artifacts").action(async () => {
|
|
35109
36019
|
const targetDir = process.cwd();
|
|
35110
36020
|
requireOcrSetup(targetDir);
|
|
35111
|
-
const ocrDir =
|
|
36021
|
+
const ocrDir = join19(targetDir, ".ocr");
|
|
35112
36022
|
try {
|
|
35113
36023
|
const synced = await stateSync(ocrDir);
|
|
35114
36024
|
console.log(`Synced ${synced} session${synced !== 1 ? "s" : ""} from filesystem.`);
|
|
@@ -35135,7 +36045,7 @@ var reconcileSubcommand = new Command("reconcile").description(
|
|
|
35135
36045
|
).option("--dry-run", "Print the repair plan without writing anything").option("--json", "Output the result as JSON").action(async (options) => {
|
|
35136
36046
|
const targetDir = process.cwd();
|
|
35137
36047
|
requireOcrSetup(targetDir);
|
|
35138
|
-
const ocrDir =
|
|
36048
|
+
const ocrDir = join19(targetDir, ".ocr");
|
|
35139
36049
|
try {
|
|
35140
36050
|
const db = await ensureDatabase(ocrDir);
|
|
35141
36051
|
const result = reconcileLegacyState(db, ocrDir, { dryRun: options.dryRun });
|
|
@@ -35194,9 +36104,9 @@ var beginSubcommand = new Command("begin").description("Start or resume a workfl
|
|
|
35194
36104
|
async (options) => {
|
|
35195
36105
|
const targetDir = process.cwd();
|
|
35196
36106
|
requireOcrSetup(targetDir);
|
|
35197
|
-
const ocrDir =
|
|
35198
|
-
const sessionDir = options.sessionDir ??
|
|
35199
|
-
if (!
|
|
36107
|
+
const ocrDir = join19(targetDir, ".ocr");
|
|
36108
|
+
const sessionDir = options.sessionDir ?? join19(ocrDir, "sessions", options.sessionId);
|
|
36109
|
+
if (!existsSync17(sessionDir)) mkdirSync7(sessionDir, { recursive: true });
|
|
35200
36110
|
try {
|
|
35201
36111
|
const result = await stateBegin({
|
|
35202
36112
|
sessionId: options.sessionId,
|
|
@@ -35218,7 +36128,7 @@ var advanceSubcommand = new Command("advance").description("Advance the workflow
|
|
|
35218
36128
|
async (options) => {
|
|
35219
36129
|
const targetDir = process.cwd();
|
|
35220
36130
|
requireOcrSetup(targetDir);
|
|
35221
|
-
const ocrDir =
|
|
36131
|
+
const ocrDir = join19(targetDir, ".ocr");
|
|
35222
36132
|
try {
|
|
35223
36133
|
const { id: sessionId } = await resolveActiveSession(ocrDir, options.sessionId);
|
|
35224
36134
|
await stateAdvance({
|
|
@@ -35238,7 +36148,7 @@ var completeRoundSubcommand = new Command("complete-round").description("Atomica
|
|
|
35238
36148
|
async (options) => {
|
|
35239
36149
|
const targetDir = process.cwd();
|
|
35240
36150
|
requireOcrSetup(targetDir);
|
|
35241
|
-
const ocrDir =
|
|
36151
|
+
const ocrDir = join19(targetDir, ".ocr");
|
|
35242
36152
|
try {
|
|
35243
36153
|
const base = options.stdin ? { source: "stdin", data: await readStdin() } : options.file ? { source: "file", filePath: options.file } : (() => {
|
|
35244
36154
|
throw new StateError(STATE_EXIT.USAGE, "Provide --stdin or --file with round metadata");
|
|
@@ -35262,7 +36172,7 @@ var completeMapSubcommand = new Command("complete-map").description("Atomically
|
|
|
35262
36172
|
async (options) => {
|
|
35263
36173
|
const targetDir = process.cwd();
|
|
35264
36174
|
requireOcrSetup(targetDir);
|
|
35265
|
-
const ocrDir =
|
|
36175
|
+
const ocrDir = join19(targetDir, ".ocr");
|
|
35266
36176
|
try {
|
|
35267
36177
|
const base = options.stdin ? { source: "stdin", data: await readStdin() } : options.file ? { source: "file", filePath: options.file } : (() => {
|
|
35268
36178
|
throw new StateError(STATE_EXIT.USAGE, "Provide --stdin or --file with map metadata");
|
|
@@ -35284,7 +36194,7 @@ var completeMapSubcommand = new Command("complete-map").description("Atomically
|
|
|
35284
36194
|
var finishSubcommand = new Command("finish").description("Close a workflow (refuses unless the current round/run is complete)").option("--session-id <id>", "Session ID (auto-detects active if omitted)").option("--abort", "Abandon the session \u2014 records a distinct, non-success terminal").action(async (options) => {
|
|
35285
36195
|
const targetDir = process.cwd();
|
|
35286
36196
|
requireOcrSetup(targetDir);
|
|
35287
|
-
const ocrDir =
|
|
36197
|
+
const ocrDir = join19(targetDir, ".ocr");
|
|
35288
36198
|
try {
|
|
35289
36199
|
const { id: sessionId } = await resolveActiveSession(ocrDir, options.sessionId);
|
|
35290
36200
|
await stateClose({ sessionId, ocrDir, abort: options.abort });
|
|
@@ -35296,14 +36206,20 @@ var finishSubcommand = new Command("finish").description("Close a workflow (refu
|
|
|
35296
36206
|
var statusSubcommand = new Command("status").description("Report whether a session is complete and, if not, what's missing").option("--session-id <id>", "Session ID (auto-detects active if omitted)").option("--json", "Output the result as JSON").action(async (options) => {
|
|
35297
36207
|
const targetDir = process.cwd();
|
|
35298
36208
|
requireOcrSetup(targetDir);
|
|
35299
|
-
const ocrDir =
|
|
36209
|
+
const ocrDir = join19(targetDir, ".ocr");
|
|
35300
36210
|
try {
|
|
35301
|
-
const result = await stateStatus(ocrDir, options.sessionId
|
|
36211
|
+
const result = await stateStatus(ocrDir, options.sessionId, {
|
|
36212
|
+
maxAttempts: getForwardResumeMaxAttempts(ocrDir),
|
|
36213
|
+
heartbeatMs: getAgentHeartbeatSeconds(ocrDir) * 1e3
|
|
36214
|
+
});
|
|
35302
36215
|
if (options.json) {
|
|
35303
36216
|
console.log(JSON.stringify(result, null, 2));
|
|
35304
36217
|
} else {
|
|
35305
36218
|
console.log(`${result.session_id}: ${result.completeness_state}`);
|
|
35306
36219
|
console.log(source_default.dim(` next: ${result.next_action}`));
|
|
36220
|
+
if (result.remaining_phases?.length) {
|
|
36221
|
+
console.log(source_default.dim(` remaining: ${result.remaining_phases.join(" \u2192 ")}`));
|
|
36222
|
+
}
|
|
35307
36223
|
}
|
|
35308
36224
|
} catch (error) {
|
|
35309
36225
|
exitFromStateError(error, "Failed to read status");
|
|
@@ -35327,50 +36243,6 @@ var stateCommand = new Command("state").description("Manage OCR session state").
|
|
|
35327
36243
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
35328
36244
|
import { join as join20 } from "node:path";
|
|
35329
36245
|
init_db();
|
|
35330
|
-
|
|
35331
|
-
// src/lib/runtime-config.ts
|
|
35332
|
-
import { existsSync as existsSync17, readFileSync as readFileSync12 } from "node:fs";
|
|
35333
|
-
import { join as join19 } from "node:path";
|
|
35334
|
-
var DEFAULT_AGENT_HEARTBEAT_SECONDS = 60;
|
|
35335
|
-
function readRuntimePositiveInt(ocrDir, key, defaultValue) {
|
|
35336
|
-
const configPath = join19(ocrDir, "config.yaml");
|
|
35337
|
-
if (!existsSync17(configPath)) return defaultValue;
|
|
35338
|
-
let content;
|
|
35339
|
-
try {
|
|
35340
|
-
content = readFileSync12(configPath, "utf-8");
|
|
35341
|
-
} catch {
|
|
35342
|
-
return defaultValue;
|
|
35343
|
-
}
|
|
35344
|
-
const blockMatch = content.match(
|
|
35345
|
-
new RegExp(
|
|
35346
|
-
String.raw`^runtime:\s*\n(?:\s+[^\n]*\n)*?\s+${key}:\s*([^\s#\n]+)`,
|
|
35347
|
-
"m"
|
|
35348
|
-
)
|
|
35349
|
-
);
|
|
35350
|
-
const inlineMatch = content.match(
|
|
35351
|
-
new RegExp(String.raw`^runtime:\s*\{[^}]*\b${key}:\s*([^\s,}]+)`, "m")
|
|
35352
|
-
);
|
|
35353
|
-
const raw = blockMatch?.[1] ?? inlineMatch?.[1];
|
|
35354
|
-
if (!raw) return defaultValue;
|
|
35355
|
-
const parsed = Number(raw);
|
|
35356
|
-
if (!Number.isFinite(parsed) || parsed <= 0 || !Number.isInteger(parsed)) {
|
|
35357
|
-
process.stderr.write(
|
|
35358
|
-
`[ocr] runtime.${key} is not a positive integer (got "${raw}"); falling back to ${defaultValue}.
|
|
35359
|
-
`
|
|
35360
|
-
);
|
|
35361
|
-
return defaultValue;
|
|
35362
|
-
}
|
|
35363
|
-
return parsed;
|
|
35364
|
-
}
|
|
35365
|
-
function getAgentHeartbeatSeconds(ocrDir) {
|
|
35366
|
-
return readRuntimePositiveInt(
|
|
35367
|
-
ocrDir,
|
|
35368
|
-
"agent_heartbeat_seconds",
|
|
35369
|
-
DEFAULT_AGENT_HEARTBEAT_SECONDS
|
|
35370
|
-
);
|
|
35371
|
-
}
|
|
35372
|
-
|
|
35373
|
-
// src/commands/session.ts
|
|
35374
36246
|
var TERMINAL_STATUSES = /* @__PURE__ */ new Set([
|
|
35375
36247
|
"done",
|
|
35376
36248
|
"crashed",
|
|
@@ -35421,6 +36293,11 @@ var startInstanceSubcommand = new Command("start-instance").description("Journal
|
|
|
35421
36293
|
}
|
|
35422
36294
|
);
|
|
35423
36295
|
var bindVendorIdSubcommand = new Command("bind-vendor-id").description("Bind the underlying CLI's session id to an OCR agent session").argument("<agent-session-id>", "OCR agent session id").argument("<vendor-session-id>", "Underlying CLI's session id").action(async (agentId, vendorId) => {
|
|
36296
|
+
if (!SAFE_VENDOR_SESSION_ID.test(vendorId)) {
|
|
36297
|
+
fail(
|
|
36298
|
+
`vendor-session-id ${JSON.stringify(vendorId)} is not a plausible vendor session id (allowed: letters and digits plus . _ : - , max 256 chars). Nothing was bound \u2014 retry with the id the vendor CLI actually emitted.`
|
|
36299
|
+
);
|
|
36300
|
+
}
|
|
35424
36301
|
const { ocrDir } = await setup();
|
|
35425
36302
|
const db = await ensureDatabase(ocrDir);
|
|
35426
36303
|
try {
|
|
@@ -35518,25 +36395,64 @@ var listSubcommand = new Command("list").description("List agent sessions for a
|
|
|
35518
36395
|
});
|
|
35519
36396
|
var sessionCommand = new Command("session").description("Manage agent-CLI session lifecycle journal").addCommand(startInstanceSubcommand).addCommand(bindVendorIdSubcommand).addCommand(beatSubcommand).addCommand(endInstanceSubcommand).addCommand(listSubcommand);
|
|
35520
36397
|
|
|
35521
|
-
// src/
|
|
36398
|
+
// ../shared/config/src/models.ts
|
|
35522
36399
|
init_src();
|
|
35523
|
-
|
|
35524
|
-
|
|
35525
|
-
|
|
35526
|
-
|
|
35527
|
-
];
|
|
35528
|
-
|
|
35529
|
-
|
|
35530
|
-
|
|
35531
|
-
|
|
35532
|
-
|
|
35533
|
-
|
|
35534
|
-
|
|
36400
|
+
function parseOpenCodeModelList(stdout) {
|
|
36401
|
+
const models = [];
|
|
36402
|
+
for (const rawLine of stdout.split(/\r?\n/)) {
|
|
36403
|
+
const line = rawLine.trim();
|
|
36404
|
+
if (!/^[^\s:]+\/\S+$/.test(line)) continue;
|
|
36405
|
+
const provider = line.slice(0, line.indexOf("/"));
|
|
36406
|
+
models.push({ id: line, provider });
|
|
36407
|
+
}
|
|
36408
|
+
return models.length > 0 ? models : null;
|
|
36409
|
+
}
|
|
36410
|
+
var VENDOR_MODEL_STRATEGIES = {
|
|
36411
|
+
claude: {
|
|
36412
|
+
displayName: "Claude Code",
|
|
36413
|
+
native: {
|
|
36414
|
+
// Verified against Claude Code 2.1.x: the CLI has no model-listing
|
|
36415
|
+
// subcommand (`claude models --json` → "unknown option"). Revisit if
|
|
36416
|
+
// a future release adds one.
|
|
36417
|
+
unavailableReason: "Claude Code does not provide a model-listing command; showing its documented model aliases instead"
|
|
36418
|
+
},
|
|
36419
|
+
// Vendor-documented aliases that always track the latest generation —
|
|
36420
|
+
// dated ids here would go stale by construction (the exact bug class of
|
|
36421
|
+
// issue #39). Pinned dated ids remain available via free-text entry.
|
|
36422
|
+
bundled: [
|
|
36423
|
+
{ id: "opus", displayName: "Claude Opus (latest)" },
|
|
36424
|
+
{ id: "sonnet", displayName: "Claude Sonnet (latest)" },
|
|
36425
|
+
{ id: "haiku", displayName: "Claude Haiku (latest)" }
|
|
36426
|
+
]
|
|
36427
|
+
},
|
|
36428
|
+
opencode: {
|
|
36429
|
+
displayName: "OpenCode",
|
|
36430
|
+
native: {
|
|
36431
|
+
// Plain `opencode models` — newline-delimited ids. (`--json` is not a
|
|
36432
|
+
// real flag, and `--verbose` interleaves JSON metadata blocks that
|
|
36433
|
+
// defeat line parsing.)
|
|
36434
|
+
args: ["models"],
|
|
36435
|
+
parse: parseOpenCodeModelList
|
|
36436
|
+
},
|
|
36437
|
+
bundled: [
|
|
36438
|
+
{ id: "anthropic/claude-opus-4-8", provider: "anthropic" },
|
|
36439
|
+
{ id: "anthropic/claude-sonnet-4-6", provider: "anthropic" },
|
|
36440
|
+
{ id: "anthropic/claude-haiku-4-5", provider: "anthropic" }
|
|
36441
|
+
]
|
|
36442
|
+
}
|
|
36443
|
+
};
|
|
36444
|
+
var SUPPORTED_VENDORS = Object.keys(
|
|
36445
|
+
VENDOR_MODEL_STRATEGIES
|
|
36446
|
+
);
|
|
36447
|
+
function isModelVendor(value) {
|
|
36448
|
+
return Object.hasOwn(VENDOR_MODEL_STRATEGIES, value);
|
|
36449
|
+
}
|
|
36450
|
+
async function detectActiveVendor() {
|
|
36451
|
+
for (const vendor of SUPPORTED_VENDORS) {
|
|
35535
36452
|
try {
|
|
35536
|
-
|
|
36453
|
+
await execBinaryAsync(vendor, ["--version"], {
|
|
35537
36454
|
encoding: "utf-8",
|
|
35538
|
-
timeout: 3e3
|
|
35539
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
36455
|
+
timeout: 3e3
|
|
35540
36456
|
});
|
|
35541
36457
|
return vendor;
|
|
35542
36458
|
} catch {
|
|
@@ -35544,68 +36460,97 @@ function detectActiveVendor() {
|
|
|
35544
36460
|
}
|
|
35545
36461
|
return null;
|
|
35546
36462
|
}
|
|
35547
|
-
function
|
|
36463
|
+
function describeProbeFailure(vendor, args, err) {
|
|
36464
|
+
const command = `${vendor} ${args.join(" ")}`;
|
|
36465
|
+
const e = err;
|
|
36466
|
+
if (e.code === "ENOENT") {
|
|
36467
|
+
return `\`${vendor}\` is not installed or not on PATH`;
|
|
36468
|
+
}
|
|
36469
|
+
if (e.killed) {
|
|
36470
|
+
return `\`${command}\` timed out or exceeded output limits`;
|
|
36471
|
+
}
|
|
36472
|
+
const stderr = typeof e.stderr === "string" ? e.stderr.trim() : "";
|
|
36473
|
+
const firstLine = (stderr.split(/\r?\n/)[0] ?? "").replace(/\u001b\[[0-9;]*[A-Za-z]/g, "").replace(/[\u0000-\u001f\u007f]/g, "").slice(0, 200);
|
|
36474
|
+
const detail = firstLine ? `: ${firstLine}` : "";
|
|
36475
|
+
const exit = typeof e.code === "number" ? ` with exit code ${e.code}` : "";
|
|
36476
|
+
return `\`${command}\` failed${exit}${detail}`;
|
|
36477
|
+
}
|
|
36478
|
+
async function tryNativeEnumeration(vendor, probe) {
|
|
36479
|
+
let stdout;
|
|
35548
36480
|
try {
|
|
35549
|
-
const
|
|
36481
|
+
const result = await execBinaryAsync(vendor, probe.args, {
|
|
35550
36482
|
encoding: "utf-8",
|
|
35551
|
-
timeout: 5e3
|
|
35552
|
-
stdio: ["ignore", "pipe", "ignore"]
|
|
36483
|
+
timeout: 5e3
|
|
35553
36484
|
});
|
|
35554
|
-
|
|
35555
|
-
|
|
35556
|
-
|
|
35557
|
-
for (const item of parsed) {
|
|
35558
|
-
if (typeof item === "string") {
|
|
35559
|
-
models.push({ id: item });
|
|
35560
|
-
} else if (typeof item === "object" && item !== null && "id" in item && typeof item.id === "string") {
|
|
35561
|
-
const obj = item;
|
|
35562
|
-
const desc = { id: obj.id };
|
|
35563
|
-
if (typeof obj.displayName === "string") desc.displayName = obj.displayName;
|
|
35564
|
-
if (typeof obj.provider === "string") desc.provider = obj.provider;
|
|
35565
|
-
if (Array.isArray(obj.tags)) {
|
|
35566
|
-
desc.tags = obj.tags.filter((t) => typeof t === "string");
|
|
35567
|
-
}
|
|
35568
|
-
models.push(desc);
|
|
35569
|
-
}
|
|
35570
|
-
}
|
|
35571
|
-
return models.length > 0 ? models : null;
|
|
35572
|
-
} catch {
|
|
35573
|
-
return null;
|
|
36485
|
+
stdout = result.stdout;
|
|
36486
|
+
} catch (err) {
|
|
36487
|
+
return { models: null, reason: describeProbeFailure(vendor, probe.args, err) };
|
|
35574
36488
|
}
|
|
36489
|
+
const models = probe.parse(stdout);
|
|
36490
|
+
if (!models) {
|
|
36491
|
+
return {
|
|
36492
|
+
models: null,
|
|
36493
|
+
reason: `\`${vendor} ${probe.args.join(" ")}\` output did not contain any model identifiers`
|
|
36494
|
+
};
|
|
36495
|
+
}
|
|
36496
|
+
return { models };
|
|
35575
36497
|
}
|
|
35576
|
-
|
|
35577
|
-
|
|
35578
|
-
|
|
35579
|
-
|
|
35580
|
-
|
|
35581
|
-
|
|
35582
|
-
|
|
35583
|
-
|
|
36498
|
+
var SUCCESS_TTL_MS = 6e4;
|
|
36499
|
+
var FAILURE_TTL_MS = 1e4;
|
|
36500
|
+
var cache = /* @__PURE__ */ new Map();
|
|
36501
|
+
async function listModelsForVendor(vendor) {
|
|
36502
|
+
const cached = cache.get(vendor);
|
|
36503
|
+
if (cached && cached.expiresAt > Date.now()) {
|
|
36504
|
+
return cached.result;
|
|
36505
|
+
}
|
|
36506
|
+
const strategy = VENDOR_MODEL_STRATEGIES[vendor];
|
|
36507
|
+
if (!strategy) {
|
|
36508
|
+
throw new Error(`Unknown vendor: ${vendor}`);
|
|
35584
36509
|
}
|
|
35585
|
-
|
|
36510
|
+
let result;
|
|
36511
|
+
if ("unavailableReason" in strategy.native) {
|
|
36512
|
+
result = {
|
|
36513
|
+
vendor,
|
|
36514
|
+
source: "bundled",
|
|
36515
|
+
models: strategy.bundled,
|
|
36516
|
+
nativeUnavailableReason: strategy.native.unavailableReason
|
|
36517
|
+
};
|
|
36518
|
+
} else {
|
|
36519
|
+
const native = await tryNativeEnumeration(vendor, strategy.native);
|
|
36520
|
+
result = native.models ? { vendor, source: "native", models: native.models } : {
|
|
36521
|
+
vendor,
|
|
36522
|
+
source: "bundled",
|
|
36523
|
+
models: strategy.bundled,
|
|
36524
|
+
nativeUnavailableReason: native.reason
|
|
36525
|
+
};
|
|
36526
|
+
}
|
|
36527
|
+
const ttl = result.source === "native" ? SUCCESS_TTL_MS : FAILURE_TTL_MS;
|
|
36528
|
+
cache.set(vendor, { result, expiresAt: Date.now() + ttl });
|
|
36529
|
+
return result;
|
|
35586
36530
|
}
|
|
35587
36531
|
|
|
35588
36532
|
// src/commands/models.ts
|
|
35589
|
-
var
|
|
35590
|
-
|
|
35591
|
-
"Override autodetection (claude | opencode)"
|
|
35592
|
-
).option("--json", "Emit JSON for programmatic consumption").action(async (options) => {
|
|
36533
|
+
var vendorList = SUPPORTED_VENDORS.join(" | ");
|
|
36534
|
+
var listSubcommand2 = new Command("list").description("List models the active AI CLI is willing to accept").option("--vendor <vendor>", `Override autodetection (${vendorList})`).option("--json", "Emit JSON for programmatic consumption").action(async (options) => {
|
|
35593
36535
|
let vendor;
|
|
35594
36536
|
if (options.vendor) {
|
|
35595
|
-
|
|
36537
|
+
const requested = options.vendor.toLowerCase();
|
|
36538
|
+
if (!isModelVendor(requested)) {
|
|
35596
36539
|
console.error(
|
|
35597
36540
|
source_default.red(
|
|
35598
|
-
`Invalid --vendor: "${options.vendor}". Must be
|
|
36541
|
+
`Invalid --vendor: "${options.vendor}". Must be one of: ${vendorList}.`
|
|
35599
36542
|
)
|
|
35600
36543
|
);
|
|
35601
36544
|
process.exit(1);
|
|
35602
36545
|
}
|
|
35603
|
-
vendor =
|
|
36546
|
+
vendor = requested;
|
|
35604
36547
|
} else {
|
|
35605
|
-
vendor = detectActiveVendor();
|
|
36548
|
+
vendor = await detectActiveVendor();
|
|
35606
36549
|
if (!vendor) {
|
|
35607
36550
|
if (options.json) {
|
|
35608
|
-
console.log(
|
|
36551
|
+
console.log(
|
|
36552
|
+
JSON.stringify({ vendor: null, source: null, models: [] }, null, 2)
|
|
36553
|
+
);
|
|
35609
36554
|
return;
|
|
35610
36555
|
}
|
|
35611
36556
|
console.error(
|
|
@@ -35616,16 +36561,18 @@ var listSubcommand2 = new Command("list").description("List models the active AI
|
|
|
35616
36561
|
process.exit(1);
|
|
35617
36562
|
}
|
|
35618
36563
|
}
|
|
35619
|
-
const
|
|
36564
|
+
const result = await listModelsForVendor(vendor);
|
|
35620
36565
|
if (options.json) {
|
|
35621
|
-
console.log(JSON.stringify(
|
|
36566
|
+
console.log(JSON.stringify(result, null, 2));
|
|
35622
36567
|
return;
|
|
35623
36568
|
}
|
|
36569
|
+
const { source, models, nativeUnavailableReason } = result;
|
|
35624
36570
|
console.log(source_default.bold(`Models for ${vendor} (${source})`));
|
|
35625
36571
|
if (source === "bundled") {
|
|
36572
|
+
const reason = nativeUnavailableReason ? ` \u2014 ${nativeUnavailableReason}` : "";
|
|
35626
36573
|
console.log(
|
|
35627
36574
|
source_default.dim(
|
|
35628
|
-
|
|
36575
|
+
` Note: bundled fallback list${reason}. Free-text input is always accepted.`
|
|
35629
36576
|
)
|
|
35630
36577
|
);
|
|
35631
36578
|
}
|
|
@@ -35850,11 +36797,11 @@ function pairKey(pair) {
|
|
|
35850
36797
|
var teamCommand = new Command("team").description("Resolve and persist team composition").addCommand(resolveSubcommand).addCommand(setSubcommand);
|
|
35851
36798
|
|
|
35852
36799
|
// src/commands/review.ts
|
|
35853
|
-
|
|
36800
|
+
init_src();
|
|
35854
36801
|
import { join as join22 } from "node:path";
|
|
35855
36802
|
init_db();
|
|
35856
36803
|
|
|
35857
|
-
// src/
|
|
36804
|
+
// ../shared/persistence/src/vendor-resume.ts
|
|
35858
36805
|
var VENDOR_BINARIES = {
|
|
35859
36806
|
claude: "claude",
|
|
35860
36807
|
opencode: "opencode"
|
|
@@ -35876,6 +36823,7 @@ function fail3(message) {
|
|
|
35876
36823
|
console.error(source_default.red(`Error: ${message}`));
|
|
35877
36824
|
process.exit(1);
|
|
35878
36825
|
}
|
|
36826
|
+
var CONTROL_PROMPT = "Resume this OCR review: run `ocr state status --json` and act on `next_action`, continuing forward from `current_phase` without redoing completed phases.";
|
|
35879
36827
|
var reviewCommand = new Command("review").description("Run or resume an OCR review").option("--resume <workflow-id>", "Resume a prior review by its workflow session id").action(async (options) => {
|
|
35880
36828
|
if (!options.resume) {
|
|
35881
36829
|
console.error(
|
|
@@ -35892,21 +36840,89 @@ var reviewCommand = new Command("review").description("Run or resume an OCR revi
|
|
|
35892
36840
|
requireOcrSetup(targetDir);
|
|
35893
36841
|
const ocrDir = join22(targetDir, ".ocr");
|
|
35894
36842
|
const db = await ensureDatabase(ocrDir);
|
|
35895
|
-
const
|
|
36843
|
+
const workflowId = options.resume;
|
|
36844
|
+
const session = getSession(db, workflowId);
|
|
35896
36845
|
if (!session) {
|
|
35897
|
-
fail3(`Workflow session not found: ${
|
|
36846
|
+
fail3(`Workflow session not found: ${workflowId}`);
|
|
36847
|
+
}
|
|
36848
|
+
const maxAttempts = getForwardResumeMaxAttempts(ocrDir);
|
|
36849
|
+
const leaseMs = getForwardResumeLeaseMs(ocrDir);
|
|
36850
|
+
const heartbeatMs = getAgentHeartbeatSeconds(ocrDir) * 1e3;
|
|
36851
|
+
const status = await stateStatus(ocrDir, workflowId, {
|
|
36852
|
+
maxAttempts,
|
|
36853
|
+
heartbeatMs
|
|
36854
|
+
});
|
|
36855
|
+
switch (status.next_action_kind) {
|
|
36856
|
+
case "none":
|
|
36857
|
+
console.error(source_default.green(`Workflow ${workflowId} is already complete \u2014 nothing to resume.`));
|
|
36858
|
+
process.exit(0);
|
|
36859
|
+
break;
|
|
36860
|
+
case "finish":
|
|
36861
|
+
console.error(
|
|
36862
|
+
source_default.yellow(`Workflow ${workflowId}'s round is complete but the session is still open.`)
|
|
36863
|
+
);
|
|
36864
|
+
console.error(source_default.dim("Run `ocr state finish` to close it."));
|
|
36865
|
+
process.exit(0);
|
|
36866
|
+
break;
|
|
36867
|
+
case "abort_or_fresh": {
|
|
36868
|
+
closeForwardResumeExhausted(db, workflowId, maxAttempts);
|
|
36869
|
+
fail3(
|
|
36870
|
+
`Forward-resume attempts exhausted for workflow ${workflowId} (cap ${maxAttempts}). Closed non-success (artifacts preserved). Start a fresh review, or run \`ocr state finish --abort\` if it was already closed.`
|
|
36871
|
+
);
|
|
36872
|
+
break;
|
|
36873
|
+
}
|
|
36874
|
+
case "advance":
|
|
36875
|
+
case "complete_round":
|
|
36876
|
+
case "wait":
|
|
36877
|
+
console.error(
|
|
36878
|
+
source_default.yellow(
|
|
36879
|
+
`Workflow ${workflowId} appears to still be running (phase "${status.current_phase}"). Nothing to resume yet.`
|
|
36880
|
+
)
|
|
36881
|
+
);
|
|
36882
|
+
process.exit(0);
|
|
36883
|
+
break;
|
|
36884
|
+
case "reopen":
|
|
36885
|
+
console.error(
|
|
36886
|
+
source_default.yellow(`Workflow ${workflowId} was closed without a completed round.`)
|
|
36887
|
+
);
|
|
36888
|
+
console.error(source_default.dim("Re-invoke the review skill to finalize it."));
|
|
36889
|
+
process.exit(0);
|
|
36890
|
+
break;
|
|
35898
36891
|
}
|
|
35899
|
-
const
|
|
35900
|
-
|
|
36892
|
+
const lease = tryAcquireForwardResumeLease(db, workflowId, session.current_round, {
|
|
36893
|
+
leaseMs,
|
|
36894
|
+
maxAttempts
|
|
36895
|
+
});
|
|
36896
|
+
if (!lease.acquired) {
|
|
36897
|
+
if (lease.reason === "cap_exhausted") {
|
|
36898
|
+
closeForwardResumeExhausted(db, workflowId, lease.attemptsUsed);
|
|
36899
|
+
fail3(
|
|
36900
|
+
`Forward-resume attempts exhausted for workflow ${workflowId} (cap ${maxAttempts}). Closed non-success (artifacts preserved). Start a fresh review.`
|
|
36901
|
+
);
|
|
36902
|
+
}
|
|
35901
36903
|
fail3(
|
|
35902
|
-
`
|
|
36904
|
+
`A forward-resume is already in progress for workflow ${workflowId} (lease held). Wait for it to finish or retry after the lease expires.`
|
|
35903
36905
|
);
|
|
35904
36906
|
}
|
|
35905
|
-
|
|
35906
|
-
|
|
35907
|
-
|
|
35908
|
-
|
|
36907
|
+
console.error(
|
|
36908
|
+
source_default.dim(
|
|
36909
|
+
`Forward-resuming workflow ${session.id} on branch ${session.branch} from phase "${status.current_phase}" (${status.forward_resume_attempts_remaining ?? "?"} attempt(s) left).`
|
|
36910
|
+
)
|
|
36911
|
+
);
|
|
36912
|
+
const latest = getLatestAgentSessionWithVendorId(db, workflowId);
|
|
36913
|
+
const binary = latest?.vendor ? VENDOR_BINARIES[latest.vendor] : void 0;
|
|
36914
|
+
if (!latest || !latest.vendor_session_id || !binary) {
|
|
36915
|
+
console.error(
|
|
36916
|
+
source_default.yellow(
|
|
36917
|
+
`No resumable vendor session is captured for workflow ${workflowId}.`
|
|
36918
|
+
)
|
|
36919
|
+
);
|
|
36920
|
+
console.error(
|
|
36921
|
+
source_default.dim(
|
|
36922
|
+
`Continue it by re-invoking the review skill (\`/ocr-review\`) in your AI CLI \u2014 its Phase 0 reads \`ocr state status --json\` and continues forward from "${status.current_phase}". (${CONTROL_PROMPT})`
|
|
36923
|
+
)
|
|
35909
36924
|
);
|
|
36925
|
+
process.exit(0);
|
|
35910
36926
|
}
|
|
35911
36927
|
let args;
|
|
35912
36928
|
try {
|
|
@@ -35914,12 +36930,8 @@ var reviewCommand = new Command("review").description("Run or resume an OCR revi
|
|
|
35914
36930
|
} catch (err) {
|
|
35915
36931
|
fail3(err instanceof Error ? err.message : String(err));
|
|
35916
36932
|
}
|
|
35917
|
-
console.error(
|
|
35918
|
-
|
|
35919
|
-
`Resuming workflow ${session.id} on branch ${session.branch} via ${binary}\u2026`
|
|
35920
|
-
)
|
|
35921
|
-
);
|
|
35922
|
-
const child = spawn3(binary, args, {
|
|
36933
|
+
console.error(source_default.dim(`Resuming via ${binary} (continue forward from "${status.current_phase}")\u2026`));
|
|
36934
|
+
const child = spawnBinary(binary, args, {
|
|
35923
36935
|
stdio: "inherit",
|
|
35924
36936
|
cwd: targetDir
|
|
35925
36937
|
});
|
|
@@ -36844,10 +37856,10 @@ function readCache(cacheFile) {
|
|
|
36844
37856
|
return null;
|
|
36845
37857
|
}
|
|
36846
37858
|
}
|
|
36847
|
-
function writeCache(cacheFile,
|
|
37859
|
+
function writeCache(cacheFile, cache2) {
|
|
36848
37860
|
try {
|
|
36849
37861
|
mkdirSync8(join28(cacheFile, ".."), { recursive: true });
|
|
36850
|
-
writeFileSync10(cacheFile, JSON.stringify(
|
|
37862
|
+
writeFileSync10(cacheFile, JSON.stringify(cache2));
|
|
36851
37863
|
} catch {
|
|
36852
37864
|
}
|
|
36853
37865
|
}
|
|
@@ -36869,14 +37881,14 @@ async function checkForUpdate(currentVersion, options) {
|
|
|
36869
37881
|
}
|
|
36870
37882
|
const cacheFile = join28(options?.cacheDir ?? CACHE_DIR2, "update-check.json");
|
|
36871
37883
|
try {
|
|
36872
|
-
const
|
|
36873
|
-
if (
|
|
36874
|
-
if (!
|
|
36875
|
-
if (!isNewer(
|
|
37884
|
+
const cache2 = readCache(cacheFile);
|
|
37885
|
+
if (cache2 && Date.now() - cache2.lastCheck < CHECK_INTERVAL_MS) {
|
|
37886
|
+
if (!cache2.latestVersion) return null;
|
|
37887
|
+
if (!isNewer(cache2.latestVersion, currentVersion)) return null;
|
|
36876
37888
|
return {
|
|
36877
37889
|
updateAvailable: true,
|
|
36878
37890
|
currentVersion,
|
|
36879
|
-
latestVersion:
|
|
37891
|
+
latestVersion: cache2.latestVersion,
|
|
36880
37892
|
updateCommand: detectUpdateCommand()
|
|
36881
37893
|
};
|
|
36882
37894
|
}
|