halfcycle 0.7.1 → 0.8.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/.claude-plugin/plugin.json +1 -1
- package/bin/bin.bundle.mjs +1607 -634
- package/dist/bin.d.ts +5 -0
- package/dist/bin.d.ts.map +1 -1
- package/dist/bin.js +0 -0
- package/dist/cli-contract.d.ts +1 -1
- package/dist/cli-contract.d.ts.map +1 -1
- package/dist/cli.js +745 -374
- package/dist/cli.js.map +3 -3
- package/dist/close-phase.d.ts +5 -0
- package/dist/close-phase.d.ts.map +1 -1
- package/dist/index.js +8 -3
- package/dist/index.js.map +2 -2
- package/dist/install.d.ts.map +1 -1
- package/dist/pace.d.ts +4 -2
- package/dist/pace.d.ts.map +1 -1
- package/dist/request-shapes-verb.d.ts +36 -0
- package/dist/request-shapes-verb.d.ts.map +1 -0
- package/dist/request-shapes.d.ts +25 -0
- package/dist/request-shapes.d.ts.map +1 -0
- package/dist/route.d.ts +19 -18
- package/dist/route.d.ts.map +1 -1
- package/package.json +11 -11
package/bin/bin.bundle.mjs
CHANGED
|
@@ -5,14 +5,10 @@ var __export = (target, all) => {
|
|
|
5
5
|
__defProp(target, name, { get: all[name], enumerable: true });
|
|
6
6
|
};
|
|
7
7
|
|
|
8
|
-
// dist/
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
if (configured)
|
|
13
|
-
return { origin: configured.replace(/\/+$/, ""), source: "environment" };
|
|
14
|
-
return { origin: DEFAULT_GUARD_ORIGIN, source: "default" };
|
|
15
|
-
}
|
|
8
|
+
// dist/request-shapes.js
|
|
9
|
+
import { appendFileSync, existsSync } from "node:fs";
|
|
10
|
+
import { homedir } from "node:os";
|
|
11
|
+
import { join } from "node:path";
|
|
16
12
|
|
|
17
13
|
// ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.js
|
|
18
14
|
var external_exports = {};
|
|
@@ -3052,13 +3048,13 @@ var $ZodObject = /* @__PURE__ */ $constructor("$ZodObject", (inst, def) => {
|
|
|
3052
3048
|
}
|
|
3053
3049
|
return propValues;
|
|
3054
3050
|
});
|
|
3055
|
-
const
|
|
3051
|
+
const isObject3 = isObject;
|
|
3056
3052
|
const catchall = def.catchall;
|
|
3057
3053
|
let value;
|
|
3058
3054
|
inst._zod.parse = (payload, ctx) => {
|
|
3059
3055
|
value ?? (value = _normalized.value);
|
|
3060
3056
|
const input = payload.value;
|
|
3061
|
-
if (!
|
|
3057
|
+
if (!isObject3(input)) {
|
|
3062
3058
|
payload.issues.push({
|
|
3063
3059
|
expected: "object",
|
|
3064
3060
|
code: "invalid_type",
|
|
@@ -3185,7 +3181,7 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) =>
|
|
|
3185
3181
|
return (payload, ctx) => fn(shape, payload, ctx);
|
|
3186
3182
|
};
|
|
3187
3183
|
let fastpass;
|
|
3188
|
-
const
|
|
3184
|
+
const isObject3 = isObject;
|
|
3189
3185
|
const jit = !globalConfig.jitless;
|
|
3190
3186
|
const allowsEval2 = allowsEval;
|
|
3191
3187
|
const fastEnabled = jit && allowsEval2.value;
|
|
@@ -3194,7 +3190,7 @@ var $ZodObjectJIT = /* @__PURE__ */ $constructor("$ZodObjectJIT", (inst, def) =>
|
|
|
3194
3190
|
inst._zod.parse = (payload, ctx) => {
|
|
3195
3191
|
value ?? (value = _normalized.value);
|
|
3196
3192
|
const input = payload.value;
|
|
3197
|
-
if (!
|
|
3193
|
+
if (!isObject3(input)) {
|
|
3198
3194
|
payload.issues.push({
|
|
3199
3195
|
expected: "object",
|
|
3200
3196
|
code: "invalid_type",
|
|
@@ -15050,6 +15046,7 @@ var SIGN_IN_COMMAND = '"npx halfcycle"';
|
|
|
15050
15046
|
var HOOK_REMEDY = `Run ${SIGN_IN_COMMAND} in the project folder to sign in.`;
|
|
15051
15047
|
|
|
15052
15048
|
// ../core/dist/task-plan.js
|
|
15049
|
+
var TASK_PLAN_FILE = "docs/build-records/task-plan.json";
|
|
15053
15050
|
var AGENT_NAME_MAX = 32;
|
|
15054
15051
|
var TASK_PLAN_TASKS_MAX = 500;
|
|
15055
15052
|
var TASK_PLAN_ID_MAX = 64;
|
|
@@ -15262,6 +15259,262 @@ var WORKER_REPORT_LINES = Object.freeze({
|
|
|
15262
15259
|
clear: () => "The report is complete and names the commit it is about."
|
|
15263
15260
|
});
|
|
15264
15261
|
|
|
15262
|
+
// ../core/dist/request-shape.js
|
|
15263
|
+
var REQUEST_SHAPES_DIR_NAME = "debug";
|
|
15264
|
+
var REQUEST_SHAPES_SWITCH_FILENAME = "request-shapes.on";
|
|
15265
|
+
var REQUEST_SHAPES_LOG_FILENAME = "request-shapes.jsonl";
|
|
15266
|
+
var REQUEST_SHAPE_MAX_DEPTH = 8;
|
|
15267
|
+
var REQUEST_SHAPE_MAX_ARRAY_SHAPES = 10;
|
|
15268
|
+
var REQUEST_SHAPE_MAX_KEY_LENGTH = 64;
|
|
15269
|
+
var REQUEST_SHAPE_MAX_LINE_BYTES = 16 * 1024;
|
|
15270
|
+
var KEY_NAME = /^[A-Za-z][A-Za-z0-9_]*$/;
|
|
15271
|
+
var PATH_WORD = /^[a-z-]+$/;
|
|
15272
|
+
function byteLength(text) {
|
|
15273
|
+
return new TextEncoder().encode(text).length;
|
|
15274
|
+
}
|
|
15275
|
+
function keyOf(key) {
|
|
15276
|
+
return key.length <= REQUEST_SHAPE_MAX_KEY_LENGTH && KEY_NAME.test(key) ? key : "<key>";
|
|
15277
|
+
}
|
|
15278
|
+
function shapeOfValue(value, depth) {
|
|
15279
|
+
if (value === null)
|
|
15280
|
+
return "null";
|
|
15281
|
+
if (typeof value === "string")
|
|
15282
|
+
return "string";
|
|
15283
|
+
if (typeof value === "number")
|
|
15284
|
+
return "number";
|
|
15285
|
+
if (typeof value === "boolean")
|
|
15286
|
+
return "boolean";
|
|
15287
|
+
if (depth > REQUEST_SHAPE_MAX_DEPTH)
|
|
15288
|
+
return "\u2026";
|
|
15289
|
+
if (Array.isArray(value)) {
|
|
15290
|
+
const seen = [];
|
|
15291
|
+
for (const element of value) {
|
|
15292
|
+
if (seen.length >= REQUEST_SHAPE_MAX_ARRAY_SHAPES)
|
|
15293
|
+
break;
|
|
15294
|
+
const shape = shapeOfValue(element, depth + 1);
|
|
15295
|
+
if (!seen.includes(shape))
|
|
15296
|
+
seen.push(shape);
|
|
15297
|
+
}
|
|
15298
|
+
return `[${seen.join("|")}]`;
|
|
15299
|
+
}
|
|
15300
|
+
if (typeof value === "object") {
|
|
15301
|
+
const entries = Object.entries(value);
|
|
15302
|
+
if (entries.length === 0)
|
|
15303
|
+
return "{}";
|
|
15304
|
+
return `{ ${entries.map(([k, v]) => `${keyOf(k)}: ${shapeOfValue(v, depth + 1)}`).join(", ")} }`;
|
|
15305
|
+
}
|
|
15306
|
+
return "null";
|
|
15307
|
+
}
|
|
15308
|
+
function requestShapeOf(body) {
|
|
15309
|
+
let parsed;
|
|
15310
|
+
try {
|
|
15311
|
+
parsed = JSON.parse(body);
|
|
15312
|
+
} catch {
|
|
15313
|
+
return `text ${byteLength(body)} bytes`;
|
|
15314
|
+
}
|
|
15315
|
+
return shapeOfValue(parsed, 1);
|
|
15316
|
+
}
|
|
15317
|
+
function requestPathShapeOf(pathname) {
|
|
15318
|
+
return pathname.split("/").map((segment) => segment === "" || PATH_WORD.test(segment) ? segment : ":x").join("/");
|
|
15319
|
+
}
|
|
15320
|
+
function distinct(names) {
|
|
15321
|
+
const out = [];
|
|
15322
|
+
for (const name of names)
|
|
15323
|
+
if (!out.includes(name))
|
|
15324
|
+
out.push(name);
|
|
15325
|
+
return out;
|
|
15326
|
+
}
|
|
15327
|
+
function isObject2(value) {
|
|
15328
|
+
return typeof value === "object" && value !== null;
|
|
15329
|
+
}
|
|
15330
|
+
function isRequestLike(value) {
|
|
15331
|
+
return isObject2(value) && !(value instanceof URL) && typeof value["url"] === "string" && typeof value["method"] === "string";
|
|
15332
|
+
}
|
|
15333
|
+
function headerNamesOf(headers) {
|
|
15334
|
+
if (!isObject2(headers))
|
|
15335
|
+
return [];
|
|
15336
|
+
const names = [];
|
|
15337
|
+
if (Array.isArray(headers)) {
|
|
15338
|
+
for (const pair of headers)
|
|
15339
|
+
if (Array.isArray(pair) && typeof pair[0] === "string")
|
|
15340
|
+
names.push(pair[0].toLowerCase());
|
|
15341
|
+
return names;
|
|
15342
|
+
}
|
|
15343
|
+
const forEach = headers["forEach"];
|
|
15344
|
+
if (typeof forEach === "function") {
|
|
15345
|
+
forEach.call(headers, (_value, key) => {
|
|
15346
|
+
if (typeof key === "string")
|
|
15347
|
+
names.push(key.toLowerCase());
|
|
15348
|
+
});
|
|
15349
|
+
return names;
|
|
15350
|
+
}
|
|
15351
|
+
return Object.keys(headers).map((k) => k.toLowerCase());
|
|
15352
|
+
}
|
|
15353
|
+
function bytesShape(bytes) {
|
|
15354
|
+
let text;
|
|
15355
|
+
try {
|
|
15356
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(bytes);
|
|
15357
|
+
} catch {
|
|
15358
|
+
return `text ${bytes.byteLength} bytes`;
|
|
15359
|
+
}
|
|
15360
|
+
return requestShapeOf(text);
|
|
15361
|
+
}
|
|
15362
|
+
function bodyShapeOf(body) {
|
|
15363
|
+
if (body === void 0 || body === null)
|
|
15364
|
+
return null;
|
|
15365
|
+
if (typeof body === "string")
|
|
15366
|
+
return requestShapeOf(body);
|
|
15367
|
+
if (body instanceof URLSearchParams)
|
|
15368
|
+
return `text ${byteLength(body.toString())} bytes`;
|
|
15369
|
+
if (body instanceof ArrayBuffer)
|
|
15370
|
+
return bytesShape(new Uint8Array(body));
|
|
15371
|
+
if (ArrayBuffer.isView(body))
|
|
15372
|
+
return bytesShape(new Uint8Array(body.buffer, body.byteOffset, body.byteLength));
|
|
15373
|
+
if (isObject2(body) && typeof body["size"] === "number" && typeof body["arrayBuffer"] === "function") {
|
|
15374
|
+
return `text ${body["size"]} bytes`;
|
|
15375
|
+
}
|
|
15376
|
+
return "stream";
|
|
15377
|
+
}
|
|
15378
|
+
function requestLineOf(input, init) {
|
|
15379
|
+
const request = isRequestLike(input) ? input : void 0;
|
|
15380
|
+
const address = request !== void 0 ? request.url : input instanceof URL ? input.href : String(input);
|
|
15381
|
+
let url2;
|
|
15382
|
+
try {
|
|
15383
|
+
url2 = new URL(address);
|
|
15384
|
+
} catch {
|
|
15385
|
+
url2 = void 0;
|
|
15386
|
+
}
|
|
15387
|
+
const options = isObject2(init) ? init : {};
|
|
15388
|
+
const method = (typeof options["method"] === "string" ? options["method"] : request?.method ?? "GET").toUpperCase();
|
|
15389
|
+
const headers = distinct([
|
|
15390
|
+
...request !== void 0 ? headerNamesOf(request.headers) : [],
|
|
15391
|
+
...headerNamesOf(options["headers"])
|
|
15392
|
+
]);
|
|
15393
|
+
const shape = options["body"] !== void 0 && options["body"] !== null ? bodyShapeOf(options["body"]) : request !== void 0 && request.body !== null && request.body !== void 0 ? "stream" : null;
|
|
15394
|
+
return {
|
|
15395
|
+
method,
|
|
15396
|
+
host: url2?.host ?? "",
|
|
15397
|
+
path: url2 !== void 0 ? requestPathShapeOf(url2.pathname) : ":x",
|
|
15398
|
+
query: url2 !== void 0 ? distinct([...url2.searchParams.keys()]) : [],
|
|
15399
|
+
headers,
|
|
15400
|
+
shape
|
|
15401
|
+
};
|
|
15402
|
+
}
|
|
15403
|
+
function requestShapeLineText(line2) {
|
|
15404
|
+
const ordered = (shape) => JSON.stringify({
|
|
15405
|
+
at: line2.at,
|
|
15406
|
+
process: line2.process,
|
|
15407
|
+
method: line2.method,
|
|
15408
|
+
host: line2.host,
|
|
15409
|
+
path: line2.path,
|
|
15410
|
+
query: line2.query,
|
|
15411
|
+
headers: line2.headers,
|
|
15412
|
+
shape,
|
|
15413
|
+
status: line2.status
|
|
15414
|
+
});
|
|
15415
|
+
const whole = ordered(line2.shape);
|
|
15416
|
+
if (byteLength(whole) <= REQUEST_SHAPE_MAX_LINE_BYTES || line2.shape === null)
|
|
15417
|
+
return whole;
|
|
15418
|
+
const room = REQUEST_SHAPE_MAX_LINE_BYTES - byteLength(ordered("")) - byteLength("\u2026");
|
|
15419
|
+
if (room <= 0)
|
|
15420
|
+
return ordered("\u2026");
|
|
15421
|
+
let end = Math.min(line2.shape.length, room);
|
|
15422
|
+
for (let over = byteLength(line2.shape.slice(0, end)) - room; over > 0; over = byteLength(line2.shape.slice(0, end)) - room) {
|
|
15423
|
+
end -= over;
|
|
15424
|
+
}
|
|
15425
|
+
const prefix = line2.shape.slice(0, Math.max(0, end));
|
|
15426
|
+
const cut = Math.max(prefix.lastIndexOf(", "), prefix.lastIndexOf("|"));
|
|
15427
|
+
return ordered(`${cut > 0 ? prefix.slice(0, cut) : ""}\u2026`);
|
|
15428
|
+
}
|
|
15429
|
+
|
|
15430
|
+
// dist/request-shapes.js
|
|
15431
|
+
var RUNNER_VERB_NAMES = [
|
|
15432
|
+
"ci",
|
|
15433
|
+
"refresh-credential",
|
|
15434
|
+
"observe",
|
|
15435
|
+
"time",
|
|
15436
|
+
"prove",
|
|
15437
|
+
"pace",
|
|
15438
|
+
"statusline",
|
|
15439
|
+
"check-connection",
|
|
15440
|
+
"mcp-headers",
|
|
15441
|
+
"resolve-engagement",
|
|
15442
|
+
"capture"
|
|
15443
|
+
];
|
|
15444
|
+
var RUNNER_HOOK_NAMES = [
|
|
15445
|
+
"post-tool-use",
|
|
15446
|
+
"stop",
|
|
15447
|
+
"subagent-stop",
|
|
15448
|
+
"pre-tool-use",
|
|
15449
|
+
"user-prompt-submit",
|
|
15450
|
+
"user-prompt-findings"
|
|
15451
|
+
];
|
|
15452
|
+
var folder = join(homedir(), HALFCYCLE_DIR_NAME, REQUEST_SHAPES_DIR_NAME);
|
|
15453
|
+
var logPath = join(folder, REQUEST_SHAPES_LOG_FILENAME);
|
|
15454
|
+
var switchedOn = existsSync(join(folder, REQUEST_SHAPES_SWITCH_FILENAME));
|
|
15455
|
+
function processName() {
|
|
15456
|
+
const [verb, hook] = process.argv.slice(2);
|
|
15457
|
+
if (verb === "hook" && hook !== void 0 && RUNNER_HOOK_NAMES.includes(hook))
|
|
15458
|
+
return `runner hook ${hook}`;
|
|
15459
|
+
if (verb !== void 0 && verb !== "hook" && RUNNER_VERB_NAMES.includes(verb))
|
|
15460
|
+
return `runner ${verb}`;
|
|
15461
|
+
return "runner other";
|
|
15462
|
+
}
|
|
15463
|
+
function write(call, status) {
|
|
15464
|
+
if (call === void 0)
|
|
15465
|
+
return;
|
|
15466
|
+
try {
|
|
15467
|
+
const text = requestShapeLineText({ at: (/* @__PURE__ */ new Date()).toISOString(), process: processName(), ...call, status });
|
|
15468
|
+
appendFileSync(logPath, `${text}
|
|
15469
|
+
`, { mode: 384 });
|
|
15470
|
+
} catch {
|
|
15471
|
+
}
|
|
15472
|
+
}
|
|
15473
|
+
function describe3(args2) {
|
|
15474
|
+
try {
|
|
15475
|
+
return requestLineOf(args2[0], args2[1]);
|
|
15476
|
+
} catch {
|
|
15477
|
+
return void 0;
|
|
15478
|
+
}
|
|
15479
|
+
}
|
|
15480
|
+
function recordChildRequest(address, headerNames, exitedOk) {
|
|
15481
|
+
if (!switchedOn)
|
|
15482
|
+
return;
|
|
15483
|
+
const call = describe3([address, { method: "GET", headers: headerNames.map((name) => [name, ""]) }]);
|
|
15484
|
+
write(call, exitedOk ? "child-ok" : "child-failed");
|
|
15485
|
+
}
|
|
15486
|
+
if (switchedOn) {
|
|
15487
|
+
const original = globalThis.fetch;
|
|
15488
|
+
if (typeof original === "function") {
|
|
15489
|
+
globalThis.fetch = function recordedFetch(...args2) {
|
|
15490
|
+
const call = describe3(args2);
|
|
15491
|
+
let answer;
|
|
15492
|
+
try {
|
|
15493
|
+
answer = original.apply(this, args2);
|
|
15494
|
+
} catch (err) {
|
|
15495
|
+
write(call, "unreachable");
|
|
15496
|
+
throw err;
|
|
15497
|
+
}
|
|
15498
|
+
return answer.then((res) => {
|
|
15499
|
+
write(call, res.status);
|
|
15500
|
+
return res;
|
|
15501
|
+
}, (err) => {
|
|
15502
|
+
write(call, "unreachable");
|
|
15503
|
+
throw err;
|
|
15504
|
+
});
|
|
15505
|
+
};
|
|
15506
|
+
}
|
|
15507
|
+
}
|
|
15508
|
+
|
|
15509
|
+
// dist/guard-origin.js
|
|
15510
|
+
var DEFAULT_GUARD_ORIGIN = "https://guard.halfcycle.ai";
|
|
15511
|
+
function resolveGuardOrigin(env) {
|
|
15512
|
+
const configured = env["GUARD_SERVICE_URL"]?.trim();
|
|
15513
|
+
if (configured)
|
|
15514
|
+
return { origin: configured.replace(/\/+$/, ""), source: "environment" };
|
|
15515
|
+
return { origin: DEFAULT_GUARD_ORIGIN, source: "default" };
|
|
15516
|
+
}
|
|
15517
|
+
|
|
15265
15518
|
// dist/control-origin.js
|
|
15266
15519
|
var DEFAULT_CONTROL_ORIGIN = "https://control.halfcycle.ai";
|
|
15267
15520
|
function resolveControlOrigin(env) {
|
|
@@ -18842,6 +19095,10 @@ var limitHeldSchema = external_exports.object({
|
|
|
18842
19095
|
raiseBy: external_exports.number().int().nonnegative(),
|
|
18843
19096
|
working: external_exports.number().int().nonnegative()
|
|
18844
19097
|
}).strict();
|
|
19098
|
+
var paceUsageSchema = external_exports.object({
|
|
19099
|
+
used: external_exports.number().int().nonnegative(),
|
|
19100
|
+
limit: external_exports.number().int().positive()
|
|
19101
|
+
}).strict();
|
|
18845
19102
|
var paceRunResultSchema = external_exports.discriminatedUnion("outcome", [
|
|
18846
19103
|
external_exports.object({
|
|
18847
19104
|
outcome: external_exports.literal("paced"),
|
|
@@ -18853,7 +19110,8 @@ var paceRunResultSchema = external_exports.discriminatedUnion("outcome", [
|
|
|
18853
19110
|
keepFreePercent: keepFreePercentSchema.optional(),
|
|
18854
19111
|
suggestion: paceSuggestionSchema.optional(),
|
|
18855
19112
|
limit: external_exports.literal("reached").optional(),
|
|
18856
|
-
limitHeld: limitHeldSchema.optional()
|
|
19113
|
+
limitHeld: limitHeldSchema.optional(),
|
|
19114
|
+
usage: paceUsageSchema.optional()
|
|
18857
19115
|
}).strict(),
|
|
18858
19116
|
external_exports.object({ outcome: external_exports.literal("not-paced"), reason: external_exports.enum(PACE_NOT_PACED_REASONS) }).strict()
|
|
18859
19117
|
]);
|
|
@@ -19232,6 +19490,7 @@ var relayedChoicesFileSchema = external_exports.object({
|
|
|
19232
19490
|
}).strict();
|
|
19233
19491
|
|
|
19234
19492
|
// ../events/dist/tier-figures.js
|
|
19493
|
+
var ROUTING_FILENAME = "routing.json";
|
|
19235
19494
|
var routingRecordSchema = external_exports.object({
|
|
19236
19495
|
phase: external_exports.string().min(1).max(200),
|
|
19237
19496
|
cheapStarted: external_exports.array(external_exports.string().min(1).max(200)).max(2e3)
|
|
@@ -19784,7 +20043,7 @@ async function attempt(url2, token, request, fetchFn, retry) {
|
|
|
19784
20043
|
|
|
19785
20044
|
// dist/git.js
|
|
19786
20045
|
import { spawnSync } from "node:child_process";
|
|
19787
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
20046
|
+
import { existsSync as existsSync2, readFileSync } from "node:fs";
|
|
19788
20047
|
import { relative } from "node:path";
|
|
19789
20048
|
var COLOR_AWARE_SUBCOMMANDS = /* @__PURE__ */ new Set(["diff", "show", "log"]);
|
|
19790
20049
|
function spawnGit(args2, cwd, timeoutMs, extra) {
|
|
@@ -19801,7 +20060,7 @@ function spawnGit(args2, cwd, timeoutMs, extra) {
|
|
|
19801
20060
|
function git(args2, cwd, timeoutMs, extra) {
|
|
19802
20061
|
const result = spawnGit(args2, cwd, timeoutMs, extra);
|
|
19803
20062
|
if (result.error) {
|
|
19804
|
-
const missing = result.error.code === "ENOENT" &&
|
|
20063
|
+
const missing = result.error.code === "ENOENT" && existsSync2(cwd);
|
|
19805
20064
|
return { ok: false, message: `git error: ${result.error.message}`, ...missing ? { gitMissing: true } : {} };
|
|
19806
20065
|
}
|
|
19807
20066
|
if (result.status !== 0) {
|
|
@@ -20315,14 +20574,14 @@ function stripComments(code) {
|
|
|
20315
20574
|
function extractSqlWrites(diffContent) {
|
|
20316
20575
|
const writes = [];
|
|
20317
20576
|
const seen = /* @__PURE__ */ new Set();
|
|
20318
|
-
const push = (
|
|
20319
|
-
if (!
|
|
20577
|
+
const push = (write2) => {
|
|
20578
|
+
if (!write2)
|
|
20320
20579
|
return;
|
|
20321
|
-
const key = `${
|
|
20580
|
+
const key = `${write2.kind}:${write2.table}`;
|
|
20322
20581
|
if (seen.has(key))
|
|
20323
20582
|
return;
|
|
20324
20583
|
seen.add(key);
|
|
20325
|
-
writes.push(
|
|
20584
|
+
writes.push(write2);
|
|
20326
20585
|
};
|
|
20327
20586
|
for (const line2 of diffContent.split("\n")) {
|
|
20328
20587
|
if (isRemovedLine(line2) || isContextLine(line2) || isDiffHeader(line2))
|
|
@@ -20633,7 +20892,7 @@ function detectBlastRadiusMarkers(filePath, diffContent) {
|
|
|
20633
20892
|
|
|
20634
20893
|
// dist/extract/numeric-columns.js
|
|
20635
20894
|
import { readFileSync as readFileSync2, readdirSync } from "node:fs";
|
|
20636
|
-
import { join } from "node:path";
|
|
20895
|
+
import { join as join2 } from "node:path";
|
|
20637
20896
|
function extractNumericColumns(diffContent, context = {}) {
|
|
20638
20897
|
const addedLines = [];
|
|
20639
20898
|
for (const line2 of diffContent.split("\n")) {
|
|
@@ -20700,12 +20959,12 @@ function walkForRegistrations(dir, repoRoot, acc) {
|
|
|
20700
20959
|
if (entry.isDirectory()) {
|
|
20701
20960
|
if (EXCLUDED_DIRS.has(entry.name))
|
|
20702
20961
|
continue;
|
|
20703
|
-
walkForRegistrations(
|
|
20962
|
+
walkForRegistrations(join2(dir, entry.name), repoRoot, acc);
|
|
20704
20963
|
continue;
|
|
20705
20964
|
}
|
|
20706
20965
|
if (!entry.isFile())
|
|
20707
20966
|
continue;
|
|
20708
|
-
const absPath =
|
|
20967
|
+
const absPath = join2(dir, entry.name);
|
|
20709
20968
|
if (!isCodeFile(absPath))
|
|
20710
20969
|
continue;
|
|
20711
20970
|
let content;
|
|
@@ -20847,13 +21106,13 @@ function resolveWireFields(lines2, decls) {
|
|
|
20847
21106
|
}
|
|
20848
21107
|
|
|
20849
21108
|
// dist/fixtures-manifest.js
|
|
20850
|
-
import { existsSync as
|
|
20851
|
-
import { dirname, join as
|
|
21109
|
+
import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
21110
|
+
import { dirname, join as join3 } from "node:path";
|
|
20852
21111
|
function manifestPath(repoRoot) {
|
|
20853
|
-
return
|
|
21112
|
+
return join3(repoRoot, "test", "fixtures", "captured", "manifest.json");
|
|
20854
21113
|
}
|
|
20855
21114
|
function fixturePath(repoRoot, provider, slug) {
|
|
20856
|
-
return
|
|
21115
|
+
return join3(repoRoot, "test", "fixtures", "captured", provider, `${slug}.json`);
|
|
20857
21116
|
}
|
|
20858
21117
|
function loadManifest(repoRoot) {
|
|
20859
21118
|
if (!repoRoot)
|
|
@@ -20886,7 +21145,7 @@ function upsertManifest(repoRoot, entry) {
|
|
|
20886
21145
|
}
|
|
20887
21146
|
function removeFixtureIfExists(path) {
|
|
20888
21147
|
try {
|
|
20889
|
-
if (
|
|
21148
|
+
if (existsSync3(path))
|
|
20890
21149
|
unlinkSync(path);
|
|
20891
21150
|
} catch {
|
|
20892
21151
|
}
|
|
@@ -21134,7 +21393,7 @@ function toAstShapes(markers) {
|
|
|
21134
21393
|
|
|
21135
21394
|
// dist/extract/context.js
|
|
21136
21395
|
import { readFileSync as readFileSync4, readdirSync as readdirSync2 } from "node:fs";
|
|
21137
|
-
import { join as
|
|
21396
|
+
import { join as join4, relative as relative2, sep } from "node:path";
|
|
21138
21397
|
var EXCLUDED_DIRS2 = /* @__PURE__ */ new Set([
|
|
21139
21398
|
"node_modules",
|
|
21140
21399
|
".git",
|
|
@@ -21168,7 +21427,7 @@ function walk(dir, repoRoot, acc) {
|
|
|
21168
21427
|
if (entry.isDirectory()) {
|
|
21169
21428
|
if (EXCLUDED_DIRS2.has(entry.name))
|
|
21170
21429
|
continue;
|
|
21171
|
-
walk(
|
|
21430
|
+
walk(join4(dir, entry.name), repoRoot, acc);
|
|
21172
21431
|
continue;
|
|
21173
21432
|
}
|
|
21174
21433
|
if (!entry.isFile())
|
|
@@ -21176,7 +21435,7 @@ function walk(dir, repoRoot, acc) {
|
|
|
21176
21435
|
const kind = classifyFile(entry.name);
|
|
21177
21436
|
if (!kind)
|
|
21178
21437
|
continue;
|
|
21179
|
-
const absPath =
|
|
21438
|
+
const absPath = join4(dir, entry.name);
|
|
21180
21439
|
let content;
|
|
21181
21440
|
try {
|
|
21182
21441
|
content = readFileSync4(absPath, "utf-8");
|
|
@@ -21199,9 +21458,9 @@ function loadChangeSetContext(repoRoot) {
|
|
|
21199
21458
|
}
|
|
21200
21459
|
|
|
21201
21460
|
// dist/telemetry/emit.js
|
|
21202
|
-
import { appendFileSync, mkdirSync as mkdirSync2 } from "node:fs";
|
|
21203
|
-
import { join as
|
|
21204
|
-
import { homedir } from "node:os";
|
|
21461
|
+
import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync2 } from "node:fs";
|
|
21462
|
+
import { join as join5, dirname as dirname2 } from "node:path";
|
|
21463
|
+
import { homedir as homedir2 } from "node:os";
|
|
21205
21464
|
import { randomUUID } from "node:crypto";
|
|
21206
21465
|
var TELEMETRY_TIMEOUT_MS = 5e3;
|
|
21207
21466
|
async function emitTelemetry(run, config2, logger, fetchFn = globalThis.fetch) {
|
|
@@ -21211,23 +21470,23 @@ async function emitTelemetry(run, config2, logger, fetchFn = globalThis.fetch) {
|
|
|
21211
21470
|
}
|
|
21212
21471
|
}
|
|
21213
21472
|
function localLogPath(run, config2) {
|
|
21214
|
-
const logDir = config2.guardEvalLogDir ??
|
|
21473
|
+
const logDir = config2.guardEvalLogDir ?? join5(homedir2(), ".halfcycle", "guard-eval-log");
|
|
21215
21474
|
const phase = run.phase;
|
|
21216
21475
|
const fileName = phase === void 0 || phase === "" ? "unphased.jsonl" : `${renderPhaseSegment(phase)}.jsonl`;
|
|
21217
|
-
return
|
|
21476
|
+
return join5(logDir, fileName);
|
|
21218
21477
|
}
|
|
21219
21478
|
function appendToLocalLog(run, config2, logger) {
|
|
21220
|
-
let
|
|
21479
|
+
let logPath2;
|
|
21221
21480
|
try {
|
|
21222
|
-
|
|
21481
|
+
logPath2 = localLogPath(run, config2);
|
|
21223
21482
|
} catch (err) {
|
|
21224
21483
|
const msg = err instanceof Error ? err.message : String(err);
|
|
21225
21484
|
logger.warn(`[Halfcycle telemetry] Phase name refused, nothing written (dropped): ${msg}`);
|
|
21226
21485
|
return;
|
|
21227
21486
|
}
|
|
21228
21487
|
try {
|
|
21229
|
-
mkdirSync2(dirname2(
|
|
21230
|
-
|
|
21488
|
+
mkdirSync2(dirname2(logPath2), { recursive: true });
|
|
21489
|
+
appendFileSync2(logPath2, JSON.stringify(run) + "\n", "utf-8");
|
|
21231
21490
|
} catch (err) {
|
|
21232
21491
|
const msg = err instanceof Error ? err.message : String(err);
|
|
21233
21492
|
logger.warn(`[Halfcycle telemetry] Local guard-eval log write failed (dropped): ${msg}`);
|
|
@@ -21536,21 +21795,21 @@ function projectFolder(env = process.env) {
|
|
|
21536
21795
|
}
|
|
21537
21796
|
|
|
21538
21797
|
// dist/credential-store.js
|
|
21539
|
-
import { chmodSync, existsSync as
|
|
21540
|
-
import { homedir as
|
|
21541
|
-
import { dirname as dirname3, join as
|
|
21798
|
+
import { chmodSync, existsSync as existsSync4, readFileSync as readFileSync6, renameSync as renameSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2, realpathSync } from "node:fs";
|
|
21799
|
+
import { homedir as homedir3, platform } from "node:os";
|
|
21800
|
+
import { dirname as dirname3, join as join6 } from "node:path";
|
|
21542
21801
|
var REFRESHED_TOKEN_KEYS = ["HALFCYCLE_TOKEN", "GUARD_SERVICE_TOKEN"];
|
|
21543
21802
|
var TOKEN_READ_KEY = "GUARD_SERVICE_TOKEN";
|
|
21544
21803
|
function composeEngagementEnvPath(engagementId, home) {
|
|
21545
|
-
return
|
|
21804
|
+
return join6(home ?? homedir3(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, ENGAGEMENT_ENV_FILENAME);
|
|
21546
21805
|
}
|
|
21547
21806
|
function hasNotThisAccountMarker(engagementId, home) {
|
|
21548
|
-
return
|
|
21807
|
+
return existsSync4(join6(home ?? homedir3(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, NOT_THIS_ACCOUNT_MARKER_FILENAME));
|
|
21549
21808
|
}
|
|
21550
21809
|
function readAccountCredential(controlOrigin, home) {
|
|
21551
21810
|
let raw;
|
|
21552
21811
|
try {
|
|
21553
|
-
raw = readFileSync6(
|
|
21812
|
+
raw = readFileSync6(join6(home ?? homedir3(), HALFCYCLE_DIR_NAME, ACCOUNT_STORE_FILENAME), "utf-8");
|
|
21554
21813
|
} catch {
|
|
21555
21814
|
return void 0;
|
|
21556
21815
|
}
|
|
@@ -21602,7 +21861,7 @@ function writeRefreshedToken(opts) {
|
|
|
21602
21861
|
existing = null;
|
|
21603
21862
|
}
|
|
21604
21863
|
const body = reconcileEnvText(existing, { HALFCYCLE_TOKEN: opts.token, GUARD_SERVICE_TOKEN: opts.token }, REFRESHED_TOKEN_KEYS);
|
|
21605
|
-
const temp =
|
|
21864
|
+
const temp = join6(dirname3(declaredReal), `.${ENGAGEMENT_ENV_FILENAME}.${process.pid}.tmp`);
|
|
21606
21865
|
try {
|
|
21607
21866
|
writeFileSync2(temp, body, { mode: 384 });
|
|
21608
21867
|
if (platform() !== "win32")
|
|
@@ -21703,15 +21962,15 @@ async function refreshEngagementCredential(opts) {
|
|
|
21703
21962
|
const minted = await mintThroughJoin(controlOrigin, opts.engagementId, accountCredential, opts.fetchFn ?? globalThis.fetch);
|
|
21704
21963
|
if (!minted.ok)
|
|
21705
21964
|
return minted;
|
|
21706
|
-
const
|
|
21965
|
+
const write2 = writeRefreshedToken({
|
|
21707
21966
|
envFilePath,
|
|
21708
21967
|
engagementId: opts.engagementId,
|
|
21709
21968
|
token: minted.token,
|
|
21710
21969
|
home: opts.home
|
|
21711
21970
|
});
|
|
21712
|
-
if (!
|
|
21971
|
+
if (!write2.written) {
|
|
21713
21972
|
const warn = opts.warn ?? ((message) => process.stderr.write(message));
|
|
21714
|
-
warn(`[Halfcycle] This engagement's credential was renewed for this run only \u2014 ${
|
|
21973
|
+
warn(`[Halfcycle] This engagement's credential was renewed for this run only \u2014 ${write2.reason}.
|
|
21715
21974
|
`);
|
|
21716
21975
|
}
|
|
21717
21976
|
return minted;
|
|
@@ -21740,9 +21999,9 @@ async function evaluateWithRefresh(opts) {
|
|
|
21740
21999
|
|
|
21741
22000
|
// dist/hooks/marker.js
|
|
21742
22001
|
import { createHash } from "node:crypto";
|
|
21743
|
-
import { existsSync as
|
|
22002
|
+
import { existsSync as existsSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync3, unlinkSync as unlinkSync3, readdirSync as readdirSync3, rmdirSync, statSync } from "node:fs";
|
|
21744
22003
|
import { tmpdir } from "node:os";
|
|
21745
|
-
import { join as
|
|
22004
|
+
import { join as join7 } from "node:path";
|
|
21746
22005
|
var MARKER_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
21747
22006
|
var MARKER_PREFIX = "halfcycle-session-";
|
|
21748
22007
|
var MARKER_SUFFIX = ".ref";
|
|
@@ -21756,18 +22015,21 @@ var FINDINGS_ID = new RegExp(FINDINGS_ID_SOURCE);
|
|
|
21756
22015
|
function findingsPath(sessionId) {
|
|
21757
22016
|
if (typeof sessionId !== "string" || !FINDINGS_ID.test(sessionId))
|
|
21758
22017
|
return null;
|
|
21759
|
-
return
|
|
22018
|
+
return join7(markerDir(), `${FINDINGS_PREFIX}${sessionId}${FINDINGS_SUFFIX}`);
|
|
21760
22019
|
}
|
|
21761
22020
|
var HELD_STEP_PREFIX = "halfcycle-held-";
|
|
21762
22021
|
var ALLOW_PREFIX = "halfcycle-allow-";
|
|
22022
|
+
var STEP_NUMBERS_PREFIX = "halfcycle-step-numbers-";
|
|
21763
22023
|
var ALLOW_ONCE_SUFFIX = ".json";
|
|
22024
|
+
var STEP_NUMBERS_LOCK_SUFFIX = ".lock";
|
|
21764
22025
|
function allowOncePaths(sessionId, dir) {
|
|
21765
22026
|
if (typeof sessionId !== "string" || !FINDINGS_ID.test(sessionId))
|
|
21766
22027
|
return null;
|
|
21767
22028
|
const base = dir ?? markerDir();
|
|
21768
22029
|
return {
|
|
21769
|
-
held:
|
|
21770
|
-
allow:
|
|
22030
|
+
held: join7(base, `${HELD_STEP_PREFIX}${sessionId}${ALLOW_ONCE_SUFFIX}`),
|
|
22031
|
+
allow: join7(base, `${ALLOW_PREFIX}${sessionId}${ALLOW_ONCE_SUFFIX}`),
|
|
22032
|
+
numbers: join7(base, `${STEP_NUMBERS_PREFIX}${sessionId}${ALLOW_ONCE_SUFFIX}`)
|
|
21771
22033
|
};
|
|
21772
22034
|
}
|
|
21773
22035
|
function markerDir() {
|
|
@@ -21783,16 +22045,16 @@ function markerFileName(repoRoot, sessionId) {
|
|
|
21783
22045
|
return `${MARKER_PREFIX}${key}${MARKER_SUFFIX}`;
|
|
21784
22046
|
}
|
|
21785
22047
|
function markerPath(repoRoot, sessionId) {
|
|
21786
|
-
return
|
|
22048
|
+
return join7(markerDir(), markerFileName(repoRoot, sessionId));
|
|
21787
22049
|
}
|
|
21788
22050
|
function dedupePath(repoRoot, sessionId) {
|
|
21789
22051
|
const hash2 = repoHash(repoRoot);
|
|
21790
22052
|
const key = sessionId && sessionId.length > 0 ? `${hash2}-${sessionId}` : hash2;
|
|
21791
|
-
return
|
|
22053
|
+
return join7(markerDir(), `${MARKER_PREFIX}${key}${DEDUPE_SUFFIX}`);
|
|
21792
22054
|
}
|
|
21793
22055
|
function readMarker(repoRoot, sessionId) {
|
|
21794
22056
|
const path = markerPath(repoRoot, sessionId);
|
|
21795
|
-
if (!
|
|
22057
|
+
if (!existsSync5(path))
|
|
21796
22058
|
return null;
|
|
21797
22059
|
try {
|
|
21798
22060
|
return readFileSync7(path, "utf-8").trim() || null;
|
|
@@ -21803,7 +22065,7 @@ function readMarker(repoRoot, sessionId) {
|
|
|
21803
22065
|
function deleteMarker(repoRoot, sessionId) {
|
|
21804
22066
|
for (const path of [markerPath(repoRoot, sessionId), dedupePath(repoRoot, sessionId)]) {
|
|
21805
22067
|
try {
|
|
21806
|
-
if (
|
|
22068
|
+
if (existsSync5(path))
|
|
21807
22069
|
unlinkSync3(path);
|
|
21808
22070
|
} catch {
|
|
21809
22071
|
}
|
|
@@ -21820,11 +22082,11 @@ var SESSION_NOTICE_SUFFIX = {
|
|
|
21820
22082
|
"pre-tool-use-unreadable": ".pretool-unreadable",
|
|
21821
22083
|
"outside-own-copy-unknown": ".owncopy-unknown"
|
|
21822
22084
|
};
|
|
21823
|
-
function firstNoticeThisSession(notice,
|
|
22085
|
+
function firstNoticeThisSession(notice, folder2, sessionId, dir = markerDir()) {
|
|
21824
22086
|
if (!sessionId)
|
|
21825
22087
|
return true;
|
|
21826
22088
|
const suffix = SESSION_NOTICE_SUFFIX[notice];
|
|
21827
|
-
const path =
|
|
22089
|
+
const path = join7(dir, `${MARKER_PREFIX}${repoHash(folder2)}-${sessionId}${suffix}`);
|
|
21828
22090
|
try {
|
|
21829
22091
|
writeFileSync3(path, "", { encoding: "utf-8", flag: "wx" });
|
|
21830
22092
|
return true;
|
|
@@ -21832,18 +22094,18 @@ function firstNoticeThisSession(notice, folder, sessionId, dir = markerDir()) {
|
|
|
21832
22094
|
return err.code !== "EEXIST";
|
|
21833
22095
|
}
|
|
21834
22096
|
}
|
|
21835
|
-
function warnOnceThisSession(notice,
|
|
22097
|
+
function warnOnceThisSession(notice, folder2, sessionId) {
|
|
21836
22098
|
return (message) => {
|
|
21837
|
-
if (firstNoticeThisSession(notice,
|
|
22099
|
+
if (firstNoticeThisSession(notice, folder2, sessionId))
|
|
21838
22100
|
process.stderr.write(message);
|
|
21839
22101
|
};
|
|
21840
22102
|
}
|
|
21841
|
-
function firstNoRepoNoticeThisSession(
|
|
21842
|
-
return firstNoticeThisSession("no-repository",
|
|
22103
|
+
function firstNoRepoNoticeThisSession(folder2, sessionId) {
|
|
22104
|
+
return firstNoticeThisSession("no-repository", folder2, sessionId);
|
|
21843
22105
|
}
|
|
21844
22106
|
function readDedupe(repoRoot, sessionId) {
|
|
21845
22107
|
const path = dedupePath(repoRoot, sessionId);
|
|
21846
|
-
if (!
|
|
22108
|
+
if (!existsSync5(path))
|
|
21847
22109
|
return null;
|
|
21848
22110
|
try {
|
|
21849
22111
|
const parsed = JSON.parse(readFileSync7(path, "utf-8"));
|
|
@@ -21891,7 +22153,7 @@ function orphanSweep(repoRoot, refKnown, keepSessionId, now = Date.now(), livene
|
|
|
21891
22153
|
continue;
|
|
21892
22154
|
if (name === keepName)
|
|
21893
22155
|
continue;
|
|
21894
|
-
const full =
|
|
22156
|
+
const full = join7(dir, name);
|
|
21895
22157
|
let unusable = false;
|
|
21896
22158
|
try {
|
|
21897
22159
|
const ref = readFileSync7(full, "utf-8").trim();
|
|
@@ -21928,7 +22190,9 @@ function sweepSessionFiles(keepSessionId, now) {
|
|
|
21928
22190
|
[FINDINGS_PREFIX, FINDINGS_SUFFIX],
|
|
21929
22191
|
[OWN_WORK_PREFIX, OWN_WORK_SUFFIX],
|
|
21930
22192
|
[HELD_STEP_PREFIX, ALLOW_ONCE_SUFFIX],
|
|
21931
|
-
[ALLOW_PREFIX, ALLOW_ONCE_SUFFIX]
|
|
22193
|
+
[ALLOW_PREFIX, ALLOW_ONCE_SUFFIX],
|
|
22194
|
+
[STEP_NUMBERS_PREFIX, ALLOW_ONCE_SUFFIX],
|
|
22195
|
+
[STEP_NUMBERS_PREFIX, `${ALLOW_ONCE_SUFFIX}${STEP_NUMBERS_LOCK_SUFFIX}`]
|
|
21932
22196
|
];
|
|
21933
22197
|
for (const name of names) {
|
|
21934
22198
|
for (const [prefix, suffix] of kinds) {
|
|
@@ -21936,7 +22200,7 @@ function sweepSessionFiles(keepSessionId, now) {
|
|
|
21936
22200
|
continue;
|
|
21937
22201
|
if (keepSessionId !== void 0 && name === `${prefix}${keepSessionId}${suffix}`)
|
|
21938
22202
|
continue;
|
|
21939
|
-
const full =
|
|
22203
|
+
const full = join7(dir, name);
|
|
21940
22204
|
try {
|
|
21941
22205
|
if (now - statSync(full).mtimeMs > MARKER_TTL_MS)
|
|
21942
22206
|
unlinkSync3(full);
|
|
@@ -21945,13 +22209,13 @@ function sweepSessionFiles(keepSessionId, now) {
|
|
|
21945
22209
|
}
|
|
21946
22210
|
}
|
|
21947
22211
|
}
|
|
21948
|
-
function observeThrottlePath(
|
|
21949
|
-
return
|
|
22212
|
+
function observeThrottlePath(folder2) {
|
|
22213
|
+
return join7(markerDir(), `${MARKER_PREFIX}${repoHash(folder2)}.observe-throttle`);
|
|
21950
22214
|
}
|
|
21951
|
-
function observeNoticesPath(
|
|
22215
|
+
function observeNoticesPath(folder2, sessionId) {
|
|
21952
22216
|
if (!sessionId)
|
|
21953
22217
|
return null;
|
|
21954
|
-
return
|
|
22218
|
+
return join7(markerDir(), `${MARKER_PREFIX}${repoHash(folder2)}-${sessionId}.observe-said`);
|
|
21955
22219
|
}
|
|
21956
22220
|
var LIVENESS_SUFFIX = ".live";
|
|
21957
22221
|
var LIVENESS_NO_REPOSITORY_KEY = "norepository";
|
|
@@ -22005,7 +22269,7 @@ function sweepLiveness(common, now) {
|
|
|
22005
22269
|
const parsed = parseLivenessFileName(name);
|
|
22006
22270
|
if (parsed === null || !keys.has(parsed.key))
|
|
22007
22271
|
continue;
|
|
22008
|
-
const full =
|
|
22272
|
+
const full = join7(dir, name);
|
|
22009
22273
|
try {
|
|
22010
22274
|
if (now - statSync(full).mtimeMs > MARKER_TTL_MS) {
|
|
22011
22275
|
unlinkSync3(full);
|
|
@@ -22016,22 +22280,22 @@ function sweepLiveness(common, now) {
|
|
|
22016
22280
|
}
|
|
22017
22281
|
}
|
|
22018
22282
|
function removeLivenessIndexEntry(dir, sessionId, name) {
|
|
22019
|
-
const
|
|
22283
|
+
const folder2 = join7(dir, livenessIndexDirName(sessionId));
|
|
22020
22284
|
try {
|
|
22021
|
-
unlinkSync3(
|
|
22285
|
+
unlinkSync3(join7(folder2, name));
|
|
22022
22286
|
} catch {
|
|
22023
22287
|
return;
|
|
22024
22288
|
}
|
|
22025
22289
|
try {
|
|
22026
|
-
rmdirSync(
|
|
22290
|
+
rmdirSync(folder2);
|
|
22027
22291
|
} catch {
|
|
22028
22292
|
}
|
|
22029
22293
|
}
|
|
22030
22294
|
|
|
22031
22295
|
// dist/seat-configuration.js
|
|
22032
|
-
import { existsSync as
|
|
22033
|
-
import { homedir as
|
|
22034
|
-
import { join as
|
|
22296
|
+
import { existsSync as existsSync6, readFileSync as readFileSync8, realpathSync as realpathSync2 } from "node:fs";
|
|
22297
|
+
import { homedir as homedir4 } from "node:os";
|
|
22298
|
+
import { join as join8, relative as relative3, resolve as resolve2 } from "node:path";
|
|
22035
22299
|
function gatherSeatConfiguration(repoRoot, read = readSeatConfiguration, profile = AGENT_PROFILES["claude-code"]) {
|
|
22036
22300
|
try {
|
|
22037
22301
|
const facts = read(repoRoot, profile);
|
|
@@ -22046,7 +22310,7 @@ function gatherSeatConfiguration(repoRoot, read = readSeatConfiguration, profile
|
|
|
22046
22310
|
function readSeatConfiguration(repoRoot, profile = AGENT_PROFILES["claude-code"]) {
|
|
22047
22311
|
const given = profile.projectRoot === "git-toplevel" ? resolve2(repoRoot) : resolve2(process.env["CLAUDE_PROJECT_DIR"] || process.cwd());
|
|
22048
22312
|
const projectDir = realpathSync2.native(given);
|
|
22049
|
-
const home =
|
|
22313
|
+
const home = homedir4();
|
|
22050
22314
|
let realHome = home;
|
|
22051
22315
|
try {
|
|
22052
22316
|
realHome = realpathSync2.native(home);
|
|
@@ -22067,7 +22331,7 @@ function isPlainObject3(value) {
|
|
|
22067
22331
|
function readSettingsFile(projectDir, rel, ours) {
|
|
22068
22332
|
let raw;
|
|
22069
22333
|
try {
|
|
22070
|
-
raw = readFileSync8(
|
|
22334
|
+
raw = readFileSync8(join8(projectDir, rel), "utf-8");
|
|
22071
22335
|
} catch (err) {
|
|
22072
22336
|
const code = err.code;
|
|
22073
22337
|
const state = code === "ENOENT" || code === "ENOTDIR" ? "absent" : "unreadable";
|
|
@@ -22139,7 +22403,7 @@ function readPathStates(projectDir, repoRoot, wiringPaths) {
|
|
|
22139
22403
|
const status = getWiringStatus(wiringPaths, projectDir);
|
|
22140
22404
|
if (!status.ok)
|
|
22141
22405
|
return unknown2();
|
|
22142
|
-
const mapped = mapWiringStatus(status.value, prefix, wiringPaths, (rel) =>
|
|
22406
|
+
const mapped = mapWiringStatus(status.value, prefix, wiringPaths, (rel) => existsSync6(join8(projectDir, rel)));
|
|
22143
22407
|
return mapped ?? unknown2();
|
|
22144
22408
|
}
|
|
22145
22409
|
function mapWiringStatus(output, prefix, paths, onDisk) {
|
|
@@ -22182,28 +22446,28 @@ function mapWiringStatus(output, prefix, paths, onDisk) {
|
|
|
22182
22446
|
|
|
22183
22447
|
// dist/time-record.js
|
|
22184
22448
|
import { createHash as createHash3 } from "node:crypto";
|
|
22185
|
-
import { appendFileSync as
|
|
22186
|
-
import { homedir as
|
|
22187
|
-
import { dirname as dirname4, join as
|
|
22449
|
+
import { appendFileSync as appendFileSync3, closeSync as closeSync3, fstatSync as fstatSync2, mkdirSync as mkdirSync6, openSync as openSync3, readdirSync as readdirSync6, readFileSync as readFileSync15, readSync as readSync3, renameSync as renameSync6, unlinkSync as unlinkSync5, writeFileSync as writeFileSync8 } from "node:fs";
|
|
22450
|
+
import { homedir as homedir8 } from "node:os";
|
|
22451
|
+
import { dirname as dirname4, join as join11 } from "node:path";
|
|
22188
22452
|
|
|
22189
22453
|
// dist/codex-usage.js
|
|
22190
22454
|
import { closeSync, fstatSync, lstatSync, openSync, readdirSync as readdirSync4, readFileSync as readFileSync9, readSync, realpathSync as realpathSync3 } from "node:fs";
|
|
22191
|
-
import { homedir as
|
|
22192
|
-
import { basename, isAbsolute, join as
|
|
22455
|
+
import { homedir as homedir5 } from "node:os";
|
|
22456
|
+
import { basename, isAbsolute, join as join9, relative as relative4, resolve as resolve3, sep as sep2 } from "node:path";
|
|
22193
22457
|
var CODEX_WINDOW_FRESH_MS = 10 * 60 * 1e3;
|
|
22194
22458
|
var CODEX_DAYS_BACK = 7;
|
|
22195
22459
|
var CODEX_FILES_MAX = 20;
|
|
22196
22460
|
var CODEX_TAIL_BYTES = 256 * 1024;
|
|
22197
22461
|
var CODEX_SAME_RESET_SECONDS = 60;
|
|
22198
22462
|
var ROLLOUT_NAME = /^rollout-.+\.jsonl$/;
|
|
22199
|
-
function codexHomeOf(env = process.env, home =
|
|
22463
|
+
function codexHomeOf(env = process.env, home = homedir5()) {
|
|
22200
22464
|
const set2 = env["CODEX_HOME"];
|
|
22201
|
-
const
|
|
22202
|
-
if (
|
|
22465
|
+
const folder2 = typeof set2 === "string" && set2 !== "" ? set2 : join9(home, ".codex");
|
|
22466
|
+
if (folder2 === "~")
|
|
22203
22467
|
return resolve3(home);
|
|
22204
|
-
if (
|
|
22205
|
-
return resolve3(
|
|
22206
|
-
return resolve3(
|
|
22468
|
+
if (folder2.startsWith("~/") || folder2.startsWith("~\\"))
|
|
22469
|
+
return resolve3(join9(home, folder2.slice(2)));
|
|
22470
|
+
return resolve3(folder2);
|
|
22207
22471
|
}
|
|
22208
22472
|
function objectOf(v) {
|
|
22209
22473
|
return typeof v === "object" && v !== null && !Array.isArray(v) ? v : null;
|
|
@@ -22287,20 +22551,20 @@ function dayFolders(sessions, now) {
|
|
|
22287
22551
|
const out = [];
|
|
22288
22552
|
for (let back = 0; back < CODEX_DAYS_BACK; back++) {
|
|
22289
22553
|
const d = new Date(now.getFullYear(), now.getMonth(), now.getDate() - back);
|
|
22290
|
-
out.push(
|
|
22554
|
+
out.push(join9(sessions, String(d.getFullYear()), twoDigits(d.getMonth() + 1), twoDigits(d.getDate())));
|
|
22291
22555
|
}
|
|
22292
22556
|
return out;
|
|
22293
22557
|
}
|
|
22294
22558
|
function recentRollouts(sessions, now) {
|
|
22295
22559
|
const found2 = [];
|
|
22296
|
-
for (const
|
|
22560
|
+
for (const folder2 of dayFolders(sessions, now)) {
|
|
22297
22561
|
try {
|
|
22298
|
-
if (!lstatSync(
|
|
22562
|
+
if (!lstatSync(folder2).isDirectory())
|
|
22299
22563
|
continue;
|
|
22300
|
-
for (const name of readdirSync4(
|
|
22564
|
+
for (const name of readdirSync4(folder2)) {
|
|
22301
22565
|
if (!ROLLOUT_NAME.test(name))
|
|
22302
22566
|
continue;
|
|
22303
|
-
const path =
|
|
22567
|
+
const path = join9(folder2, name);
|
|
22304
22568
|
try {
|
|
22305
22569
|
const st = lstatSync(path);
|
|
22306
22570
|
if (!st.isFile())
|
|
@@ -22319,7 +22583,7 @@ function recentRollouts(sessions, now) {
|
|
|
22319
22583
|
function readCodexWindows(codexHome, now) {
|
|
22320
22584
|
try {
|
|
22321
22585
|
const candidates = [];
|
|
22322
|
-
for (const path of recentRollouts(
|
|
22586
|
+
for (const path of recentRollouts(join9(codexHome, "sessions"), now)) {
|
|
22323
22587
|
try {
|
|
22324
22588
|
candidates.push(...newestWindowsIn(path, now));
|
|
22325
22589
|
} catch {
|
|
@@ -22349,7 +22613,7 @@ function isCodexSessionFile(path, codexHome) {
|
|
|
22349
22613
|
return false;
|
|
22350
22614
|
if (!lstatSync(path).isFile())
|
|
22351
22615
|
return false;
|
|
22352
|
-
const rel = relative4(realpathSync3(
|
|
22616
|
+
const rel = relative4(realpathSync3(join9(codexHome, "sessions")), realpathSync3(path));
|
|
22353
22617
|
return rel !== "" && rel !== ".." && !rel.startsWith(`..${sep2}`) && !isAbsolute(rel);
|
|
22354
22618
|
} catch {
|
|
22355
22619
|
return false;
|
|
@@ -22444,18 +22708,18 @@ function firstLine(text) {
|
|
|
22444
22708
|
const line2 = text.split("\n", 1)[0]?.replace(/[ \t\r]+$/, "") ?? "";
|
|
22445
22709
|
return line2 === "" ? null : line2;
|
|
22446
22710
|
}
|
|
22447
|
-
function whichCopy(
|
|
22711
|
+
function whichCopy(folder2, deps = {}) {
|
|
22448
22712
|
try {
|
|
22449
22713
|
const rules = deps.rules ?? machineRules();
|
|
22450
22714
|
const p = pathsFor(rules);
|
|
22451
22715
|
const files = deps.files ?? DISK_FILES;
|
|
22452
22716
|
const realpath = deps.realpath ?? ((x) => realpathSync4.native(x));
|
|
22453
22717
|
const oneForm = rules === "windows" ? (x) => x.toLowerCase() : (x) => x;
|
|
22454
|
-
if (!p.isAbsolute(
|
|
22718
|
+
if (!p.isAbsolute(folder2))
|
|
22455
22719
|
return null;
|
|
22456
|
-
if (files.kind(p.resolve(
|
|
22720
|
+
if (files.kind(p.resolve(folder2)) !== "folder")
|
|
22457
22721
|
return null;
|
|
22458
|
-
let dir = realpath(p.resolve(
|
|
22722
|
+
let dir = realpath(p.resolve(folder2));
|
|
22459
22723
|
for (; ; ) {
|
|
22460
22724
|
const dotGit = p.join(dir, ".git");
|
|
22461
22725
|
const found2 = files.kind(dotGit);
|
|
@@ -22530,7 +22794,7 @@ function copyHolding(file2, deps = {}) {
|
|
|
22530
22794
|
|
|
22531
22795
|
// dist/observed.js
|
|
22532
22796
|
import { readFileSync as readFileSync11, writeFileSync as writeFileSync4 } from "node:fs";
|
|
22533
|
-
import { join as
|
|
22797
|
+
import { join as join10 } from "node:path";
|
|
22534
22798
|
function emptyTally() {
|
|
22535
22799
|
return { added: 0, changed: 0, removed: 0, testFilesAdded: 0 };
|
|
22536
22800
|
}
|
|
@@ -22662,9 +22926,9 @@ async function attemptObservation(opts) {
|
|
|
22662
22926
|
return { outcome: "not-sent", reason: "refused" };
|
|
22663
22927
|
return answer.data.outcome === "kept" ? { outcome: "kept" } : { outcome: "recorded", answer: answer.data };
|
|
22664
22928
|
}
|
|
22665
|
-
function readThrottle(
|
|
22929
|
+
function readThrottle(folder2) {
|
|
22666
22930
|
try {
|
|
22667
|
-
const parsed = JSON.parse(readFileSync11(observeThrottlePath(
|
|
22931
|
+
const parsed = JSON.parse(readFileSync11(observeThrottlePath(folder2), "utf-8"));
|
|
22668
22932
|
if (typeof parsed !== "object" || parsed === null)
|
|
22669
22933
|
return null;
|
|
22670
22934
|
const { attemptedAt, accepted } = parsed;
|
|
@@ -22677,9 +22941,9 @@ function readThrottle(folder) {
|
|
|
22677
22941
|
return null;
|
|
22678
22942
|
}
|
|
22679
22943
|
}
|
|
22680
|
-
function writeThrottle(
|
|
22944
|
+
function writeThrottle(folder2, state) {
|
|
22681
22945
|
try {
|
|
22682
|
-
writeFileSync4(observeThrottlePath(
|
|
22946
|
+
writeFileSync4(observeThrottlePath(folder2), JSON.stringify(state), "utf-8");
|
|
22683
22947
|
} catch {
|
|
22684
22948
|
}
|
|
22685
22949
|
}
|
|
@@ -22700,9 +22964,9 @@ function locate(cwd) {
|
|
|
22700
22964
|
const read = repoRoot === null ? null : headCommit(repoRoot);
|
|
22701
22965
|
return { repoRoot, folder: repoRoot ?? cwd, head: read !== null && read.ok ? read.value : null };
|
|
22702
22966
|
}
|
|
22703
|
-
function recordAttempt(
|
|
22967
|
+
function recordAttempt(folder2, prior, head, at, attempt2) {
|
|
22704
22968
|
const accepted = (attempt2.outcome === "recorded" || attempt2.outcome === "kept") && head !== null ? { head, at } : prior?.accepted ?? null;
|
|
22705
|
-
writeThrottle(
|
|
22969
|
+
writeThrottle(folder2, { attemptedAt: at, accepted });
|
|
22706
22970
|
}
|
|
22707
22971
|
async function runObserve(deps = {}) {
|
|
22708
22972
|
let result;
|
|
@@ -22731,7 +22995,7 @@ async function runObserve(deps = {}) {
|
|
|
22731
22995
|
}
|
|
22732
22996
|
function readLocalSystemDescription(repoRoot) {
|
|
22733
22997
|
try {
|
|
22734
|
-
const raw = JSON.parse(readFileSync11(
|
|
22998
|
+
const raw = JSON.parse(readFileSync11(join10(repoRoot, SYSTEM_DESCRIPTION_REL), "utf-8"));
|
|
22735
22999
|
const checked = checkSystemDescription(raw);
|
|
22736
23000
|
return checked.ok ? checked.description : null;
|
|
22737
23001
|
} catch {
|
|
@@ -22905,23 +23169,23 @@ function writeSaid(path, state) {
|
|
|
22905
23169
|
function reasonsOf(entry) {
|
|
22906
23170
|
return entry.said.filter((task) => task.whyOutsidePlan !== void 0).map((task) => `${task.title}\0${task.whyOutsidePlan}`);
|
|
22907
23171
|
}
|
|
22908
|
-
function noticesFor(attempt2,
|
|
23172
|
+
function noticesFor(attempt2, folder2, sessionId) {
|
|
22909
23173
|
if (attempt2.outcome === "not-sent") {
|
|
22910
23174
|
if (attempt2.reason === "start-not-here") {
|
|
22911
|
-
return firstNoticeThisSession("observe-no-start-here",
|
|
23175
|
+
return firstNoticeThisSession("observe-no-start-here", folder2, sessionId) ? [R1_START_NOT_HERE] : [];
|
|
22912
23176
|
}
|
|
22913
23177
|
if (attempt2.reason === "start-not-on-branch") {
|
|
22914
|
-
return firstNoticeThisSession("observe-not-on-branch",
|
|
23178
|
+
return firstNoticeThisSession("observe-not-on-branch", folder2, sessionId) ? [R2_START_NOT_ON_BRANCH] : [];
|
|
22915
23179
|
}
|
|
22916
23180
|
if (attempt2.reason === "cannot-count" && attempt2.phase !== void 0) {
|
|
22917
|
-
return firstNoticeThisSession("observe-no-start-recorded",
|
|
23181
|
+
return firstNoticeThisSession("observe-no-start-recorded", folder2, sessionId) ? [r3NoStartRecorded(attempt2.phase)] : [];
|
|
22918
23182
|
}
|
|
22919
23183
|
return [];
|
|
22920
23184
|
}
|
|
22921
23185
|
if (attempt2.outcome === "kept")
|
|
22922
23186
|
return [];
|
|
22923
23187
|
const { notInPlan, outside } = attempt2.answer;
|
|
22924
|
-
const path = observeNoticesPath(
|
|
23188
|
+
const path = observeNoticesPath(folder2, sessionId);
|
|
22925
23189
|
const prior = readSaid(path);
|
|
22926
23190
|
const notices = [];
|
|
22927
23191
|
const parts = {};
|
|
@@ -22949,7 +23213,7 @@ function noticesFor(attempt2, folder, sessionId) {
|
|
|
22949
23213
|
// dist/pacing.js
|
|
22950
23214
|
import { createHash as createHash2 } from "node:crypto";
|
|
22951
23215
|
import { closeSync as closeSync2, mkdirSync as mkdirSync3, openSync as openSync2, readdirSync as readdirSync5, readFileSync as readFileSync12, readSync as readSync2, realpathSync as realpathSync5, renameSync as renameSync3, statSync as statSync3, writeFileSync as writeFileSync5 } from "node:fs";
|
|
22952
|
-
import { homedir as
|
|
23216
|
+
import { homedir as homedir6 } from "node:os";
|
|
22953
23217
|
import nodePath from "node:path";
|
|
22954
23218
|
var DEFAULT_CONFIG_FOLDER_NAME = ".claude";
|
|
22955
23219
|
var CODEX_DEFAULT_FOLDER_NAME = ".codex";
|
|
@@ -22967,10 +23231,10 @@ function hookInputForRule(input, rule) {
|
|
|
22967
23231
|
delete copy["rollout_path"];
|
|
22968
23232
|
return copy;
|
|
22969
23233
|
}
|
|
22970
|
-
function normaliseFolder(
|
|
23234
|
+
function normaliseFolder(folder2, input = {}) {
|
|
22971
23235
|
const p = input.path ?? nodePath;
|
|
22972
|
-
const home = input.home ??
|
|
22973
|
-
let f =
|
|
23236
|
+
const home = input.home ?? homedir6();
|
|
23237
|
+
let f = folder2;
|
|
22974
23238
|
if (f === "~")
|
|
22975
23239
|
f = home;
|
|
22976
23240
|
else if (f.startsWith("~/") || f.startsWith("~\\"))
|
|
@@ -22984,7 +23248,7 @@ function configFolderKey(input = {}) {
|
|
|
22984
23248
|
const codexHome = env["CODEX_HOME"];
|
|
22985
23249
|
if (typeof codexHome === "string" && codexHome !== "")
|
|
22986
23250
|
return normaliseFolder(codexHome, input);
|
|
22987
|
-
return normaliseFolder(p.join(input.home ??
|
|
23251
|
+
return normaliseFolder(p.join(input.home ?? homedir6(), CODEX_DEFAULT_FOLDER_NAME), input);
|
|
22988
23252
|
}
|
|
22989
23253
|
const fromEnv = env["CLAUDE_CONFIG_DIR"];
|
|
22990
23254
|
if (typeof fromEnv === "string" && fromEnv !== "")
|
|
@@ -22993,7 +23257,7 @@ function configFolderKey(input = {}) {
|
|
|
22993
23257
|
if (typeof transcript === "string" && transcript !== "") {
|
|
22994
23258
|
return normaliseFolder(p.dirname(p.dirname(p.dirname(normaliseFolder(transcript, input)))), input);
|
|
22995
23259
|
}
|
|
22996
|
-
return normaliseFolder(p.join(input.home ??
|
|
23260
|
+
return normaliseFolder(p.join(input.home ?? homedir6(), DEFAULT_CONFIG_FOLDER_NAME), input);
|
|
22997
23261
|
}
|
|
22998
23262
|
function recordsFolderOf(key, path = nodePath) {
|
|
22999
23263
|
return path.join(key, RECORDS_FOLDER_NAME);
|
|
@@ -23013,7 +23277,7 @@ var PACING_DIR_NAME = "pacing";
|
|
|
23013
23277
|
var LEARNED_FILENAME = "learned.json";
|
|
23014
23278
|
var REPORTED_FILENAME = "reported.json";
|
|
23015
23279
|
function pacingDir(home) {
|
|
23016
|
-
return nodePath.join(home ??
|
|
23280
|
+
return nodePath.join(home ?? homedir6(), HALFCYCLE_DIR_NAME, PACING_DIR_NAME);
|
|
23017
23281
|
}
|
|
23018
23282
|
function readJsonObject(path) {
|
|
23019
23283
|
try {
|
|
@@ -23435,7 +23699,7 @@ function resolvedRecords(key, path) {
|
|
|
23435
23699
|
}
|
|
23436
23700
|
}
|
|
23437
23701
|
function timeLogTranscripts(home) {
|
|
23438
|
-
const engagements = nodePath.join(home ??
|
|
23702
|
+
const engagements = nodePath.join(home ?? homedir6(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME);
|
|
23439
23703
|
const out = [];
|
|
23440
23704
|
for (const e of dirents(engagements)) {
|
|
23441
23705
|
if (!e.isDirectory())
|
|
@@ -23454,7 +23718,7 @@ function timeLogTranscripts(home) {
|
|
|
23454
23718
|
}
|
|
23455
23719
|
function teacherOf(key, deps = {}) {
|
|
23456
23720
|
const path = deps.path ?? nodePath;
|
|
23457
|
-
const home = deps.home ??
|
|
23721
|
+
const home = deps.home ?? homedir6();
|
|
23458
23722
|
const ours = resolvedRecords(key, path);
|
|
23459
23723
|
if (ours === null)
|
|
23460
23724
|
return { shared: false, teaches: () => false };
|
|
@@ -23624,13 +23888,13 @@ function knownWindowOf(learned, reported, now) {
|
|
|
23624
23888
|
|
|
23625
23889
|
// dist/phase-limit.js
|
|
23626
23890
|
import { mkdirSync as mkdirSync4, readFileSync as readFileSync13, renameSync as renameSync4, rmSync, writeFileSync as writeFileSync6 } from "node:fs";
|
|
23627
|
-
import { homedir as
|
|
23891
|
+
import { homedir as homedir7 } from "node:os";
|
|
23628
23892
|
import nodePath2 from "node:path";
|
|
23629
23893
|
var PHASE_USAGE_FILENAME = "phase-usage.json";
|
|
23630
23894
|
function phaseLimitDir(engagementId, home) {
|
|
23631
23895
|
if (!isEngagementId(engagementId))
|
|
23632
23896
|
return null;
|
|
23633
|
-
return nodePath2.join(home ??
|
|
23897
|
+
return nodePath2.join(home ?? homedir7(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, PACING_DIR_NAME);
|
|
23634
23898
|
}
|
|
23635
23899
|
function readJsonFile(path) {
|
|
23636
23900
|
try {
|
|
@@ -23678,16 +23942,14 @@ function readPhaseUsage(dir, phase, openedAt = null) {
|
|
|
23678
23942
|
return 0;
|
|
23679
23943
|
return parsed.data.tokens;
|
|
23680
23944
|
}
|
|
23945
|
+
function readPhaseUsageFile(dir) {
|
|
23946
|
+
const parsed = phaseUsageFileSchema.safeParse(readJsonFile(nodePath2.join(dir, PHASE_USAGE_FILENAME)));
|
|
23947
|
+
return parsed.success ? parsed.data : null;
|
|
23948
|
+
}
|
|
23681
23949
|
function writePhaseUsage(dir, file2) {
|
|
23682
23950
|
if (!phaseUsageFileSchema.safeParse(file2).success)
|
|
23683
|
-
return;
|
|
23684
|
-
writeWhole(nodePath2.join(dir, PHASE_USAGE_FILENAME), file2);
|
|
23685
|
-
}
|
|
23686
|
-
function phaseTokensOf(buckets) {
|
|
23687
|
-
let total = 0;
|
|
23688
|
-
for (const b of buckets)
|
|
23689
|
-
total += b.inputTokens + b.outputTokens + b.cacheWriteTokens + b.cacheReadTokens;
|
|
23690
|
-
return Math.max(0, Math.round(total));
|
|
23951
|
+
return false;
|
|
23952
|
+
return writeWhole(nodePath2.join(dir, PHASE_USAGE_FILENAME), file2);
|
|
23691
23953
|
}
|
|
23692
23954
|
function roundTokens(n) {
|
|
23693
23955
|
return Math.max(LIMIT_ROUND_TOKENS, Math.round(n / LIMIT_ROUND_TOKENS) * LIMIT_ROUND_TOKENS);
|
|
@@ -23865,6 +24127,164 @@ function setLimit(file2, limit, multiple, used, by, at) {
|
|
|
23865
24127
|
};
|
|
23866
24128
|
}
|
|
23867
24129
|
|
|
24130
|
+
// dist/scan-lock.js
|
|
24131
|
+
import { spawn } from "node:child_process";
|
|
24132
|
+
import { linkSync, mkdirSync as mkdirSync5, readFileSync as readFileSync14, renameSync as renameSync5, unlinkSync as unlinkSync4, writeFileSync as writeFileSync7 } from "node:fs";
|
|
24133
|
+
import nodePath3 from "node:path";
|
|
24134
|
+
var SCAN_LOCK_FILENAME = "scan.lock";
|
|
24135
|
+
var SCAN_LOCK_STALE_MS = 15 * 60 * 1e3;
|
|
24136
|
+
var SCAN_LOCK_POLL_MS = 100;
|
|
24137
|
+
function scanLockPath(home) {
|
|
24138
|
+
return nodePath3.join(pacingDir(home), SCAN_LOCK_FILENAME);
|
|
24139
|
+
}
|
|
24140
|
+
function readLockBody(path) {
|
|
24141
|
+
let text;
|
|
24142
|
+
try {
|
|
24143
|
+
text = readFileSync14(path, "utf-8");
|
|
24144
|
+
} catch (err) {
|
|
24145
|
+
return err.code === "ENOENT" ? "missing" : null;
|
|
24146
|
+
}
|
|
24147
|
+
try {
|
|
24148
|
+
const v = JSON.parse(text);
|
|
24149
|
+
return typeof v["pid"] === "number" && typeof v["at"] === "number" ? { pid: v["pid"], at: v["at"] } : null;
|
|
24150
|
+
} catch {
|
|
24151
|
+
return null;
|
|
24152
|
+
}
|
|
24153
|
+
}
|
|
24154
|
+
function processAlive(pid) {
|
|
24155
|
+
if (!Number.isInteger(pid) || pid <= 0)
|
|
24156
|
+
return false;
|
|
24157
|
+
try {
|
|
24158
|
+
process.kill(pid, 0);
|
|
24159
|
+
return true;
|
|
24160
|
+
} catch (err) {
|
|
24161
|
+
return err.code === "EPERM";
|
|
24162
|
+
}
|
|
24163
|
+
}
|
|
24164
|
+
function isStale(body, staleMs, deps) {
|
|
24165
|
+
if (body === null)
|
|
24166
|
+
return true;
|
|
24167
|
+
const now = (deps.clock ?? Date.now)();
|
|
24168
|
+
if (Math.abs(now - body.at) > staleMs)
|
|
24169
|
+
return true;
|
|
24170
|
+
return !(deps.alive ?? processAlive)(body.pid);
|
|
24171
|
+
}
|
|
24172
|
+
function writeLock(path, pid, deps, flag) {
|
|
24173
|
+
writeFileSync7(path, JSON.stringify({ pid, at: (deps.clock ?? Date.now)() }), { flag, mode: 384 });
|
|
24174
|
+
}
|
|
24175
|
+
function tryTakeScanLock(deps = {}) {
|
|
24176
|
+
return tryTakeLockFile(scanLockPath(deps.home), SCAN_LOCK_STALE_MS, deps);
|
|
24177
|
+
}
|
|
24178
|
+
function tryTakeLockFile(path, staleMs, deps = {}) {
|
|
24179
|
+
const pid = deps.pid ?? process.pid;
|
|
24180
|
+
try {
|
|
24181
|
+
mkdirSync5(nodePath3.dirname(path), { recursive: true, mode: 448 });
|
|
24182
|
+
} catch {
|
|
24183
|
+
return false;
|
|
24184
|
+
}
|
|
24185
|
+
for (let attempt2 = 0; attempt2 < 2; attempt2++) {
|
|
24186
|
+
try {
|
|
24187
|
+
writeLock(path, pid, deps, "wx");
|
|
24188
|
+
return true;
|
|
24189
|
+
} catch (err) {
|
|
24190
|
+
if (err.code !== "EEXIST")
|
|
24191
|
+
return false;
|
|
24192
|
+
}
|
|
24193
|
+
const seen = readLockBody(path);
|
|
24194
|
+
if (seen === "missing")
|
|
24195
|
+
continue;
|
|
24196
|
+
if (!isStale(seen, staleMs, deps))
|
|
24197
|
+
return false;
|
|
24198
|
+
const aside = `${path}.${String(pid)}.${String((deps.clock ?? Date.now)())}.stale`;
|
|
24199
|
+
try {
|
|
24200
|
+
renameSync5(path, aside);
|
|
24201
|
+
} catch {
|
|
24202
|
+
continue;
|
|
24203
|
+
}
|
|
24204
|
+
const taken = readLockBody(aside);
|
|
24205
|
+
const same = taken !== "missing" && (seen === null ? taken === null : taken !== null && taken.pid === seen.pid && taken.at === seen.at);
|
|
24206
|
+
if (!same && taken !== "missing" && !isStale(taken, staleMs, deps)) {
|
|
24207
|
+
try {
|
|
24208
|
+
linkSync(aside, path);
|
|
24209
|
+
} catch {
|
|
24210
|
+
}
|
|
24211
|
+
try {
|
|
24212
|
+
unlinkSync4(aside);
|
|
24213
|
+
} catch {
|
|
24214
|
+
}
|
|
24215
|
+
return false;
|
|
24216
|
+
}
|
|
24217
|
+
try {
|
|
24218
|
+
unlinkSync4(aside);
|
|
24219
|
+
} catch {
|
|
24220
|
+
}
|
|
24221
|
+
}
|
|
24222
|
+
return false;
|
|
24223
|
+
}
|
|
24224
|
+
function releaseLockFile(path, pid = process.pid) {
|
|
24225
|
+
const body = readLockBody(path);
|
|
24226
|
+
if (body === "missing" || body === null || body.pid !== pid)
|
|
24227
|
+
return;
|
|
24228
|
+
try {
|
|
24229
|
+
unlinkSync4(path);
|
|
24230
|
+
} catch {
|
|
24231
|
+
}
|
|
24232
|
+
}
|
|
24233
|
+
function releaseScanLock(deps = {}) {
|
|
24234
|
+
releaseLockFile(scanLockPath(deps.home), deps.pid ?? process.pid);
|
|
24235
|
+
}
|
|
24236
|
+
function sleepSync(ms) {
|
|
24237
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
24238
|
+
}
|
|
24239
|
+
function scanUnderLock(key, deps = {}, waitMs = 0) {
|
|
24240
|
+
const clock = deps.clock ?? Date.now;
|
|
24241
|
+
const giveUpAt = clock() + waitMs;
|
|
24242
|
+
while (!tryTakeScanLock(deps)) {
|
|
24243
|
+
if (clock() >= giveUpAt)
|
|
24244
|
+
return null;
|
|
24245
|
+
sleepSync(SCAN_LOCK_POLL_MS);
|
|
24246
|
+
}
|
|
24247
|
+
try {
|
|
24248
|
+
return scanRecords(key, deps);
|
|
24249
|
+
} finally {
|
|
24250
|
+
releaseScanLock(deps);
|
|
24251
|
+
}
|
|
24252
|
+
}
|
|
24253
|
+
var spawnDetachedReal = (command, args2) => {
|
|
24254
|
+
const child = spawn(command, [...args2], { detached: true, stdio: "ignore", windowsHide: true });
|
|
24255
|
+
child.on("error", () => void 0);
|
|
24256
|
+
child.unref();
|
|
24257
|
+
return child.pid;
|
|
24258
|
+
};
|
|
24259
|
+
function startScanChild(key, binaryPath, deps = {}) {
|
|
24260
|
+
if (!tryTakeScanLock(deps))
|
|
24261
|
+
return false;
|
|
24262
|
+
let childPid;
|
|
24263
|
+
try {
|
|
24264
|
+
childPid = (deps.spawnDetached ?? spawnDetachedReal)(deps.nodePath ?? process.execPath, [
|
|
24265
|
+
binaryPath,
|
|
24266
|
+
"pace",
|
|
24267
|
+
"--scan",
|
|
24268
|
+
"--config-folder",
|
|
24269
|
+
key,
|
|
24270
|
+
"--lock-held"
|
|
24271
|
+
]);
|
|
24272
|
+
} catch {
|
|
24273
|
+
childPid = void 0;
|
|
24274
|
+
}
|
|
24275
|
+
if (childPid === void 0) {
|
|
24276
|
+
releaseScanLock(deps);
|
|
24277
|
+
return false;
|
|
24278
|
+
}
|
|
24279
|
+
try {
|
|
24280
|
+
writeLock(scanLockPath(deps.home), childPid, deps, "w");
|
|
24281
|
+
} catch {
|
|
24282
|
+
releaseScanLock(deps);
|
|
24283
|
+
return false;
|
|
24284
|
+
}
|
|
24285
|
+
return true;
|
|
24286
|
+
}
|
|
24287
|
+
|
|
23868
24288
|
// dist/time-record.js
|
|
23869
24289
|
var TIME_EVENT_KINDS = ["action", "asked", "edit", "turn-end", "lock-wait-start", "lock-wait-end"];
|
|
23870
24290
|
function isLockWaitEvent(event) {
|
|
@@ -23878,25 +24298,25 @@ function inputString(input, key) {
|
|
|
23878
24298
|
const value = input[key];
|
|
23879
24299
|
return typeof value === "string" && value !== "" ? value : null;
|
|
23880
24300
|
}
|
|
23881
|
-
function readBranch(
|
|
23882
|
-
const copy = whichCopy(
|
|
24301
|
+
function readBranch(folder2, deps = {}) {
|
|
24302
|
+
const copy = whichCopy(folder2, deps);
|
|
23883
24303
|
return copy === null ? null : copyBranch(copy, deps);
|
|
23884
24304
|
}
|
|
23885
24305
|
function timeLogPath(engagementId, home) {
|
|
23886
24306
|
if (!isEngagementId(engagementId))
|
|
23887
24307
|
return null;
|
|
23888
|
-
return
|
|
24308
|
+
return join11(home ?? homedir8(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, TIME_LOG_DIR_NAME, TIME_LOG_FILENAME);
|
|
23889
24309
|
}
|
|
23890
24310
|
function timeEventLine(event, input, deps = {}) {
|
|
23891
24311
|
const at = (deps.now ?? (() => /* @__PURE__ */ new Date()))().toISOString();
|
|
23892
|
-
const
|
|
24312
|
+
const folder2 = inputString(input, "cwd") ?? (deps.cwd ?? (() => process.cwd()))();
|
|
23893
24313
|
return {
|
|
23894
24314
|
at,
|
|
23895
24315
|
event,
|
|
23896
24316
|
session: inputString(input, "session_id"),
|
|
23897
24317
|
agent: inputString(input, "agent_id"),
|
|
23898
|
-
folder,
|
|
23899
|
-
branch: readBranch(
|
|
24318
|
+
folder: folder2,
|
|
24319
|
+
branch: readBranch(folder2),
|
|
23900
24320
|
transcript: inputString(input, "transcript_path"),
|
|
23901
24321
|
toolUse: inputString(input, "tool_use_id"),
|
|
23902
24322
|
rollout: inputString(input, "rollout_path")
|
|
@@ -23914,12 +24334,12 @@ function recordTimeEvent(event, input, deps = {}) {
|
|
|
23914
24334
|
const text = `${JSON.stringify(line2)}
|
|
23915
24335
|
`;
|
|
23916
24336
|
try {
|
|
23917
|
-
|
|
24337
|
+
appendFileSync3(path, text, { mode: 384 });
|
|
23918
24338
|
} catch (err) {
|
|
23919
24339
|
if (err.code !== "ENOENT")
|
|
23920
24340
|
return;
|
|
23921
|
-
|
|
23922
|
-
|
|
24341
|
+
mkdirSync6(dirname4(path), { recursive: true, mode: 448 });
|
|
24342
|
+
appendFileSync3(path, text, { mode: 384 });
|
|
23923
24343
|
}
|
|
23924
24344
|
} catch {
|
|
23925
24345
|
}
|
|
@@ -23978,7 +24398,7 @@ function readSessionTimeLines(sessionId, deps = {}) {
|
|
|
23978
24398
|
if (path === null)
|
|
23979
24399
|
return [];
|
|
23980
24400
|
const needle = JSON.stringify(sessionId);
|
|
23981
|
-
const kept =
|
|
24401
|
+
const kept = readFileSync15(path, "utf-8").split("\n").filter((raw) => raw.includes(needle));
|
|
23982
24402
|
return parseTimeLog(kept.join("\n")).filter((line2) => line2.session === sessionId);
|
|
23983
24403
|
} catch {
|
|
23984
24404
|
return [];
|
|
@@ -24005,8 +24425,8 @@ function separatorOf(path) {
|
|
|
24005
24425
|
function subagentsFolderOf(transcript) {
|
|
24006
24426
|
if (!transcript.endsWith(".jsonl") || transcript.length === ".jsonl".length)
|
|
24007
24427
|
return null;
|
|
24008
|
-
const
|
|
24009
|
-
return `${transcript.slice(0, -".jsonl".length)}${
|
|
24428
|
+
const sep8 = separatorOf(transcript);
|
|
24429
|
+
return `${transcript.slice(0, -".jsonl".length)}${sep8}subagents`;
|
|
24010
24430
|
}
|
|
24011
24431
|
function subagentRecordName(agentId) {
|
|
24012
24432
|
return /^[A-Za-z0-9_-]+$/.test(agentId) ? `agent-${agentId}.jsonl` : null;
|
|
@@ -24014,12 +24434,12 @@ function subagentRecordName(agentId) {
|
|
|
24014
24434
|
function subagentRecordPath(transcript, agentId) {
|
|
24015
24435
|
if (transcript === null)
|
|
24016
24436
|
return null;
|
|
24017
|
-
const
|
|
24437
|
+
const folder2 = subagentsFolderOf(transcript);
|
|
24018
24438
|
const name = subagentRecordName(agentId);
|
|
24019
|
-
return
|
|
24439
|
+
return folder2 === null || name === null ? null : `${folder2}${separatorOf(transcript)}${name}`;
|
|
24020
24440
|
}
|
|
24021
|
-
function folderParts(
|
|
24022
|
-
return
|
|
24441
|
+
function folderParts(folder2) {
|
|
24442
|
+
return folder2.split(/[\\/]+/).filter((part, i) => part !== "" || i === 0);
|
|
24023
24443
|
}
|
|
24024
24444
|
function folderHolds(outer, inner) {
|
|
24025
24445
|
const o = folderParts(outer);
|
|
@@ -24072,15 +24492,52 @@ function buildLanes(events, taskIds) {
|
|
|
24072
24492
|
});
|
|
24073
24493
|
}
|
|
24074
24494
|
var UNREADABLE2 = { readable: false, lines: [] };
|
|
24075
|
-
function
|
|
24076
|
-
|
|
24077
|
-
|
|
24078
|
-
|
|
24079
|
-
|
|
24080
|
-
|
|
24081
|
-
|
|
24082
|
-
|
|
24495
|
+
function plainObject(v) {
|
|
24496
|
+
return typeof v === "object" && v !== null && !Array.isArray(v) ? v : null;
|
|
24497
|
+
}
|
|
24498
|
+
var USAGE_KEYS = ["input_tokens", "output_tokens", "cache_creation_input_tokens", "cache_read_input_tokens"];
|
|
24499
|
+
function reducedLine(o) {
|
|
24500
|
+
const out = { type: o["type"] };
|
|
24501
|
+
if (typeof o["timestamp"] === "string")
|
|
24502
|
+
out["timestamp"] = o["timestamp"];
|
|
24503
|
+
if (typeof o["gitBranch"] === "string")
|
|
24504
|
+
out["gitBranch"] = o["gitBranch"];
|
|
24505
|
+
if ("toolUseResult" in o)
|
|
24506
|
+
out["toolUseResult"] = true;
|
|
24507
|
+
if (o["isApiErrorMessage"] === true)
|
|
24508
|
+
out["isApiErrorMessage"] = true;
|
|
24509
|
+
if (typeof o["error"] === "string")
|
|
24510
|
+
out["error"] = o["error"];
|
|
24511
|
+
const message = plainObject(o["message"]);
|
|
24512
|
+
if (message !== null) {
|
|
24513
|
+
const m = {};
|
|
24514
|
+
if (typeof message["id"] === "string")
|
|
24515
|
+
m["id"] = message["id"];
|
|
24516
|
+
if (typeof message["model"] === "string")
|
|
24517
|
+
m["model"] = message["model"];
|
|
24518
|
+
const usage = plainObject(message["usage"]);
|
|
24519
|
+
if (usage !== null) {
|
|
24520
|
+
const u = {};
|
|
24521
|
+
for (const key of USAGE_KEYS)
|
|
24522
|
+
if (key in usage)
|
|
24523
|
+
u[key] = usage[key];
|
|
24524
|
+
m["usage"] = u;
|
|
24525
|
+
}
|
|
24526
|
+
const content = message["content"];
|
|
24527
|
+
if (Array.isArray(content) && content.some((block) => plainObject(block)?.["type"] === "tool_result"))
|
|
24528
|
+
m["content"] = [{ type: "tool_result" }];
|
|
24529
|
+
out["message"] = m;
|
|
24083
24530
|
}
|
|
24531
|
+
return out;
|
|
24532
|
+
}
|
|
24533
|
+
function recordLineOfValue(value) {
|
|
24534
|
+
const o = plainObject(value);
|
|
24535
|
+
if (o === null || typeof o["type"] !== "string")
|
|
24536
|
+
return null;
|
|
24537
|
+
const t = typeof o["timestamp"] === "string" ? Date.parse(o["timestamp"]) : NaN;
|
|
24538
|
+
return { value: o, t: Number.isNaN(t) ? null : t };
|
|
24539
|
+
}
|
|
24540
|
+
function recordLinesOf(text) {
|
|
24084
24541
|
const lines2 = [];
|
|
24085
24542
|
for (const raw of text.split("\n")) {
|
|
24086
24543
|
if (raw.trim() === "")
|
|
@@ -24091,29 +24548,129 @@ function viewRecord(path, deps) {
|
|
|
24091
24548
|
} catch {
|
|
24092
24549
|
continue;
|
|
24093
24550
|
}
|
|
24094
|
-
|
|
24551
|
+
const o = plainObject(value);
|
|
24552
|
+
if (o === null || typeof o["type"] !== "string")
|
|
24095
24553
|
continue;
|
|
24096
|
-
|
|
24097
|
-
|
|
24098
|
-
|
|
24099
|
-
|
|
24100
|
-
|
|
24554
|
+
lines2.push(recordLineOfValue(reducedLine(o)));
|
|
24555
|
+
}
|
|
24556
|
+
return lines2;
|
|
24557
|
+
}
|
|
24558
|
+
function viewRecord(path, deps) {
|
|
24559
|
+
let text;
|
|
24560
|
+
try {
|
|
24561
|
+
text = (deps.readFile ?? ((p) => readFileSync15(p, "utf-8")))(path);
|
|
24562
|
+
} catch {
|
|
24563
|
+
return UNREADABLE2;
|
|
24101
24564
|
}
|
|
24565
|
+
const lines2 = recordLinesOf(text);
|
|
24102
24566
|
return lines2.length === 0 ? UNREADABLE2 : { readable: true, lines: lines2 };
|
|
24103
24567
|
}
|
|
24568
|
+
function readFileFrom(path, offset) {
|
|
24569
|
+
const fd = openSync3(path, "r");
|
|
24570
|
+
try {
|
|
24571
|
+
const size = fstatSync2(fd).size;
|
|
24572
|
+
if (size < offset)
|
|
24573
|
+
return null;
|
|
24574
|
+
const buf = Buffer.alloc(size - offset);
|
|
24575
|
+
let got = 0;
|
|
24576
|
+
while (got < buf.length) {
|
|
24577
|
+
const n = readSync3(fd, buf, got, buf.length - got, offset + got);
|
|
24578
|
+
if (n === 0)
|
|
24579
|
+
break;
|
|
24580
|
+
got += n;
|
|
24581
|
+
}
|
|
24582
|
+
return buf.subarray(0, got);
|
|
24583
|
+
} finally {
|
|
24584
|
+
closeSync3(fd);
|
|
24585
|
+
}
|
|
24586
|
+
}
|
|
24587
|
+
function readFromOf(deps) {
|
|
24588
|
+
if (deps.readFrom !== void 0)
|
|
24589
|
+
return deps.readFrom;
|
|
24590
|
+
const readFile = deps.readFile;
|
|
24591
|
+
if (readFile === void 0)
|
|
24592
|
+
return readFileFrom;
|
|
24593
|
+
return (path, offset) => {
|
|
24594
|
+
const bytes = Buffer.from(readFile(path), "utf-8");
|
|
24595
|
+
return bytes.length < offset ? null : bytes.subarray(offset);
|
|
24596
|
+
};
|
|
24597
|
+
}
|
|
24598
|
+
function viewRecordFrom(path, deps, offsets) {
|
|
24599
|
+
const readFrom = readFromOf(deps);
|
|
24600
|
+
const stored = offsets.files.get(path);
|
|
24601
|
+
let start = stored?.offset ?? 0;
|
|
24602
|
+
let prior = stored?.lines ?? [];
|
|
24603
|
+
let bytes;
|
|
24604
|
+
try {
|
|
24605
|
+
bytes = readFrom(path, start);
|
|
24606
|
+
if (bytes === null && start > 0) {
|
|
24607
|
+
start = 0;
|
|
24608
|
+
prior = [];
|
|
24609
|
+
bytes = readFrom(path, 0);
|
|
24610
|
+
}
|
|
24611
|
+
} catch {
|
|
24612
|
+
return UNREADABLE2;
|
|
24613
|
+
}
|
|
24614
|
+
if (bytes === null)
|
|
24615
|
+
return UNREADABLE2;
|
|
24616
|
+
const buf = Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
24617
|
+
const end = buf.lastIndexOf(10) + 1;
|
|
24618
|
+
const fresh = end === 0 ? [] : recordLinesOf(buf.subarray(0, end).toString("utf-8"));
|
|
24619
|
+
const values = [...prior, ...fresh.map((l) => l.value)];
|
|
24620
|
+
offsets.files.set(path, { offset: start + end, lines: values });
|
|
24621
|
+
const lines2 = values.map((v) => recordLineOfValue(v));
|
|
24622
|
+
return lines2.length === 0 ? UNREADABLE2 : { readable: true, lines: lines2 };
|
|
24623
|
+
}
|
|
24624
|
+
var viewsOfOffsets = /* @__PURE__ */ new WeakMap();
|
|
24104
24625
|
function recordReader(deps) {
|
|
24105
|
-
|
|
24626
|
+
let cache2 = /* @__PURE__ */ new Map();
|
|
24627
|
+
if (deps.offsets !== void 0) {
|
|
24628
|
+
cache2 = viewsOfOffsets.get(deps.offsets) ?? /* @__PURE__ */ new Map();
|
|
24629
|
+
viewsOfOffsets.set(deps.offsets, cache2);
|
|
24630
|
+
}
|
|
24106
24631
|
return (path) => {
|
|
24107
24632
|
if (path === null)
|
|
24108
24633
|
return UNREADABLE2;
|
|
24109
24634
|
const hit = cache2.get(path);
|
|
24110
24635
|
if (hit !== void 0)
|
|
24111
24636
|
return hit;
|
|
24112
|
-
const view = viewRecord(path, deps);
|
|
24637
|
+
const view = deps.offsets === void 0 ? viewRecord(path, deps) : viewRecordFrom(path, deps, deps.offsets);
|
|
24113
24638
|
cache2.set(path, view);
|
|
24114
24639
|
return view;
|
|
24115
24640
|
};
|
|
24116
24641
|
}
|
|
24642
|
+
var TIME_READ_OFFSETS_FILENAME = "read-offsets.json";
|
|
24643
|
+
function loadReadOffsets(dir, phase, openedAt) {
|
|
24644
|
+
const fresh = { phase, openedAt, files: /* @__PURE__ */ new Map() };
|
|
24645
|
+
try {
|
|
24646
|
+
const o = plainObject(JSON.parse(readFileSync15(join11(dir, TIME_READ_OFFSETS_FILENAME), "utf-8")));
|
|
24647
|
+
if (o === null || o["phase"] !== phase || o["openedAt"] !== openedAt)
|
|
24648
|
+
return fresh;
|
|
24649
|
+
const files = plainObject(o["files"]);
|
|
24650
|
+
if (files === null)
|
|
24651
|
+
return fresh;
|
|
24652
|
+
const out = /* @__PURE__ */ new Map();
|
|
24653
|
+
for (const [path, entry] of Object.entries(files)) {
|
|
24654
|
+
const e = plainObject(entry);
|
|
24655
|
+
const offset = e?.["offset"];
|
|
24656
|
+
const lines2 = e?.["lines"];
|
|
24657
|
+
if (typeof offset !== "number" || !Number.isSafeInteger(offset) || offset < 0 || !Array.isArray(lines2))
|
|
24658
|
+
return fresh;
|
|
24659
|
+
if (!lines2.every((line2) => recordLineOfValue(line2) !== null))
|
|
24660
|
+
return fresh;
|
|
24661
|
+
out.set(path, { offset, lines: lines2.map((line2) => reducedLine(line2)) });
|
|
24662
|
+
}
|
|
24663
|
+
return { phase, openedAt, files: out };
|
|
24664
|
+
} catch {
|
|
24665
|
+
return fresh;
|
|
24666
|
+
}
|
|
24667
|
+
}
|
|
24668
|
+
function saveReadOffsets(dir, offsets) {
|
|
24669
|
+
try {
|
|
24670
|
+
writeJsonFile(join11(dir, TIME_READ_OFFSETS_FILENAME), { phase: offsets.phase, openedAt: offsets.openedAt, files: Object.fromEntries(offsets.files) });
|
|
24671
|
+
} catch {
|
|
24672
|
+
}
|
|
24673
|
+
}
|
|
24117
24674
|
function isPrompt(line2) {
|
|
24118
24675
|
const o = line2.value;
|
|
24119
24676
|
if (o["type"] !== "user" || line2.t === null || "toolUseResult" in o)
|
|
@@ -24304,23 +24861,76 @@ function tokensOf(usage) {
|
|
|
24304
24861
|
}
|
|
24305
24862
|
return out;
|
|
24306
24863
|
}
|
|
24307
|
-
|
|
24864
|
+
var TIME_SETTLED_FILENAME = "settled.json";
|
|
24865
|
+
function taskNamedIn(text, taskIds) {
|
|
24866
|
+
let named = null;
|
|
24867
|
+
for (const id of new Set(taskIds)) {
|
|
24868
|
+
if (id === "")
|
|
24869
|
+
continue;
|
|
24870
|
+
const escaped = id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
24871
|
+
if (!new RegExp(`(?<![A-Za-z0-9_-])${escaped}(?![A-Za-z0-9_-])`).test(text))
|
|
24872
|
+
continue;
|
|
24873
|
+
if (named !== null)
|
|
24874
|
+
return null;
|
|
24875
|
+
named = id;
|
|
24876
|
+
}
|
|
24877
|
+
return named;
|
|
24878
|
+
}
|
|
24879
|
+
function spawnDescriptionOf(recordPath, deps) {
|
|
24880
|
+
if (!recordPath.endsWith(".jsonl"))
|
|
24881
|
+
return null;
|
|
24882
|
+
try {
|
|
24883
|
+
const text = (deps.readFile ?? ((p) => readFileSync15(p, "utf-8")))(`${recordPath.slice(0, -".jsonl".length)}.meta.json`);
|
|
24884
|
+
const value = JSON.parse(text);
|
|
24885
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
24886
|
+
return null;
|
|
24887
|
+
const description = value["description"];
|
|
24888
|
+
return typeof description === "string" ? description : null;
|
|
24889
|
+
} catch {
|
|
24890
|
+
return null;
|
|
24891
|
+
}
|
|
24892
|
+
}
|
|
24893
|
+
function sameFolder(a, b) {
|
|
24894
|
+
const pa = folderParts(a);
|
|
24895
|
+
const pb = folderParts(b);
|
|
24896
|
+
return pa.length === pb.length && pa.every((part, k) => part === pb[k]);
|
|
24897
|
+
}
|
|
24898
|
+
function nextTaskOf(own, t) {
|
|
24308
24899
|
let next;
|
|
24309
|
-
let last;
|
|
24310
24900
|
for (const lane of own) {
|
|
24311
24901
|
if (lane.task === null)
|
|
24312
24902
|
continue;
|
|
24313
|
-
const
|
|
24314
|
-
const after = times.find((at) => at > t);
|
|
24903
|
+
const after = lane.events.map((e) => msOf(e.at)).find((at) => at > t);
|
|
24315
24904
|
if (after !== void 0 && (next === void 0 || after < next.t))
|
|
24316
24905
|
next = { task: lane.task, t: after };
|
|
24317
|
-
|
|
24906
|
+
}
|
|
24907
|
+
return next?.task ?? null;
|
|
24908
|
+
}
|
|
24909
|
+
function lastTaskOf(own, t) {
|
|
24910
|
+
let last;
|
|
24911
|
+
for (const lane of own) {
|
|
24912
|
+
if (lane.task === null)
|
|
24913
|
+
continue;
|
|
24914
|
+
const before = lastAtOrBefore(lane.events.map((e) => msOf(e.at)), t);
|
|
24318
24915
|
if (before !== void 0 && (last === void 0 || before >= last.t))
|
|
24319
24916
|
last = { task: lane.task, t: before };
|
|
24320
24917
|
}
|
|
24321
|
-
return
|
|
24918
|
+
return last?.task ?? null;
|
|
24919
|
+
}
|
|
24920
|
+
function nextTaskInFolderOf(lanes, folder2, t) {
|
|
24921
|
+
let next;
|
|
24922
|
+
for (const lane of lanes) {
|
|
24923
|
+
if (lane.task === null)
|
|
24924
|
+
continue;
|
|
24925
|
+
for (const e of lane.events) {
|
|
24926
|
+
const at = msOf(e.at);
|
|
24927
|
+
if (at > t && sameFolder(e.folder, folder2) && (next === void 0 || at < next.t))
|
|
24928
|
+
next = { task: lane.task, t: at };
|
|
24929
|
+
}
|
|
24930
|
+
}
|
|
24931
|
+
return next?.task ?? null;
|
|
24322
24932
|
}
|
|
24323
|
-
function readUsage(lanes, window, deps = {}, models) {
|
|
24933
|
+
function readUsage(lanes, window, deps = {}, models, settling = {}) {
|
|
24324
24934
|
const from = Date.parse(window.from);
|
|
24325
24935
|
const to = window.to === void 0 || window.to === null ? Infinity : Date.parse(window.to);
|
|
24326
24936
|
const inWindow = (t) => t >= from && t <= to;
|
|
@@ -24336,7 +24946,29 @@ function readUsage(lanes, window, deps = {}, models) {
|
|
|
24336
24946
|
return buckets.get(key) ?? buckets.set(key, { source, task, readable, messages: 0, inputTokens: 0, outputTokens: 0, cacheWriteTokens: 0, cacheReadTokens: 0 }).get(key);
|
|
24337
24947
|
};
|
|
24338
24948
|
const seen = /* @__PURE__ */ new Set();
|
|
24339
|
-
const
|
|
24949
|
+
const held = /* @__PURE__ */ new Set();
|
|
24950
|
+
const settled2 = settling.settled ?? /* @__PURE__ */ new Map();
|
|
24951
|
+
const final = settling.final === true;
|
|
24952
|
+
const figureIds = /* @__PURE__ */ new Set();
|
|
24953
|
+
const addToFigure = (view) => {
|
|
24954
|
+
const figure = settling.figure;
|
|
24955
|
+
if (figure === void 0)
|
|
24956
|
+
return;
|
|
24957
|
+
for (const line2 of view.lines) {
|
|
24958
|
+
if (line2.value["type"] !== "assistant" || line2.t === null || !inWindow(line2.t))
|
|
24959
|
+
continue;
|
|
24960
|
+
const message = plainObject(line2.value["message"]);
|
|
24961
|
+
const id = message?.["id"];
|
|
24962
|
+
if (typeof id !== "string" || id === "" || figureIds.has(id))
|
|
24963
|
+
continue;
|
|
24964
|
+
const tokens = tokensOf(message["usage"]);
|
|
24965
|
+
if (tokens === null)
|
|
24966
|
+
continue;
|
|
24967
|
+
figureIds.add(id);
|
|
24968
|
+
figure.claudeCode += tokens[0] + tokens[1] + tokens[2] + tokens[3];
|
|
24969
|
+
}
|
|
24970
|
+
};
|
|
24971
|
+
const count = (path, view, taskAt) => {
|
|
24340
24972
|
const source = recordSourceOf(path);
|
|
24341
24973
|
for (const line2 of view.lines) {
|
|
24342
24974
|
const o = line2.value;
|
|
@@ -24346,19 +24978,22 @@ function readUsage(lanes, window, deps = {}, models) {
|
|
|
24346
24978
|
if (typeof message !== "object" || message === null)
|
|
24347
24979
|
continue;
|
|
24348
24980
|
const id = message["id"];
|
|
24349
|
-
if (typeof id !== "string" || id === "" || seen.has(id))
|
|
24981
|
+
if (typeof id !== "string" || id === "" || seen.has(id) || held.has(id))
|
|
24350
24982
|
continue;
|
|
24351
24983
|
const tokens = tokensOf(message["usage"]);
|
|
24352
24984
|
if (tokens === null)
|
|
24353
24985
|
continue;
|
|
24986
|
+
const task = taskAt(line2, id);
|
|
24987
|
+
if (task === void 0) {
|
|
24988
|
+
held.add(id);
|
|
24989
|
+
continue;
|
|
24990
|
+
}
|
|
24354
24991
|
seen.add(id);
|
|
24355
|
-
const task = taskAt(line2);
|
|
24356
24992
|
const bucket = bucketFor(source, task, true);
|
|
24357
24993
|
bucket.messages += 1;
|
|
24358
24994
|
const model = message["model"];
|
|
24359
|
-
|
|
24360
|
-
|
|
24361
|
-
const ofTask = models.get(modelTask) ?? models.set(modelTask, /* @__PURE__ */ new Map()).get(modelTask);
|
|
24995
|
+
if (models !== void 0 && task !== null && isTalliedModel(model)) {
|
|
24996
|
+
const ofTask = models.get(task) ?? models.set(task, /* @__PURE__ */ new Map()).get(task);
|
|
24362
24997
|
ofTask.set(model, (ofTask.get(model) ?? 0) + 1);
|
|
24363
24998
|
}
|
|
24364
24999
|
bucket.inputTokens += tokens[0];
|
|
@@ -24369,42 +25004,77 @@ function readUsage(lanes, window, deps = {}, models) {
|
|
|
24369
25004
|
};
|
|
24370
25005
|
for (const main2 of mains) {
|
|
24371
25006
|
const view = read(main2);
|
|
25007
|
+
addToFigure(view);
|
|
24372
25008
|
if (view.readable) {
|
|
25009
|
+
let coordinatingFrom = Infinity;
|
|
25010
|
+
for (const lane of lanes) {
|
|
25011
|
+
if (lane.agent === MAIN_AGENT || lane.transcript !== main2)
|
|
25012
|
+
continue;
|
|
25013
|
+
for (const e of lane.events)
|
|
25014
|
+
coordinatingFrom = Math.min(coordinatingFrom, msOf(e.at));
|
|
25015
|
+
}
|
|
24373
25016
|
count(main2, view, (line2) => {
|
|
25017
|
+
if (line2.t >= coordinatingFrom)
|
|
25018
|
+
return null;
|
|
24374
25019
|
const branch = line2.value["gitBranch"];
|
|
24375
25020
|
return taskOfBranch(typeof branch === "string" ? branch : null, window.taskIds);
|
|
24376
25021
|
});
|
|
24377
25022
|
}
|
|
24378
|
-
const
|
|
24379
|
-
if (
|
|
25023
|
+
const folder2 = subagentsFolderOf(main2);
|
|
25024
|
+
if (folder2 === null)
|
|
24380
25025
|
continue;
|
|
24381
25026
|
let names;
|
|
24382
25027
|
try {
|
|
24383
|
-
names = listDir(
|
|
25028
|
+
names = listDir(folder2).filter((name) => /^agent-[A-Za-z0-9_-]+\.jsonl$/.test(name)).sort();
|
|
24384
25029
|
} catch {
|
|
24385
25030
|
continue;
|
|
24386
25031
|
}
|
|
24387
25032
|
for (const name of names) {
|
|
24388
|
-
const path = `${
|
|
25033
|
+
const path = `${folder2}${separatorOf(main2)}${name}`;
|
|
24389
25034
|
const view2 = read(path);
|
|
25035
|
+
addToFigure(view2);
|
|
24390
25036
|
if (!view2.readable)
|
|
24391
25037
|
continue;
|
|
24392
25038
|
const agent = name.slice("agent-".length, -".jsonl".length);
|
|
24393
25039
|
const own = active.filter((lane) => lane.agent === agent && lane.transcript === main2);
|
|
24394
25040
|
if (own.length === 0)
|
|
24395
25041
|
continue;
|
|
24396
|
-
|
|
25042
|
+
const ownAll = lanes.filter((lane) => lane.agent === agent && lane.transcript === main2);
|
|
25043
|
+
let description;
|
|
25044
|
+
count(path, view2, (line2, id) => {
|
|
25045
|
+
const t = line2.t;
|
|
24397
25046
|
let best;
|
|
24398
|
-
for (const
|
|
24399
|
-
const latest = lastAtOrBefore(
|
|
25047
|
+
for (const lane2 of own) {
|
|
25048
|
+
const latest = lastAtOrBefore(lane2.events.map((e) => msOf(e.at)), t);
|
|
24400
25049
|
if (latest !== void 0 && (best === void 0 || latest >= best.t))
|
|
24401
|
-
best = { lane, t: latest };
|
|
25050
|
+
best = { lane: lane2, t: latest };
|
|
25051
|
+
}
|
|
25052
|
+
const lane = best?.lane ?? [...own].sort((a, b) => msOf(a.events[0].at) - msOf(b.events[0].at))[0];
|
|
25053
|
+
if (lane.task !== null)
|
|
25054
|
+
return lane.task;
|
|
25055
|
+
if (settled2.has(id)) {
|
|
25056
|
+
const task2 = settled2.get(id);
|
|
25057
|
+
return task2 !== null && window.taskIds.includes(task2) ? task2 : null;
|
|
25058
|
+
}
|
|
25059
|
+
const next = nextTaskOf(ownAll, t);
|
|
25060
|
+
if (next !== null)
|
|
25061
|
+
return next;
|
|
25062
|
+
if (!final)
|
|
25063
|
+
return void 0;
|
|
25064
|
+
const before = lane.events.filter((e) => msOf(e.at) <= t);
|
|
25065
|
+
const folder3 = (before[before.length - 1] ?? lane.events[0]).folder;
|
|
25066
|
+
let task = nextTaskInFolderOf(lanes, folder3, t);
|
|
25067
|
+
if (task === null) {
|
|
25068
|
+
if (description === void 0)
|
|
25069
|
+
description = spawnDescriptionOf(path, deps);
|
|
25070
|
+
if (description !== null)
|
|
25071
|
+
task = taskNamedIn(description, window.taskIds);
|
|
24402
25072
|
}
|
|
24403
|
-
if (
|
|
24404
|
-
|
|
24405
|
-
|
|
24406
|
-
return
|
|
24407
|
-
}
|
|
25073
|
+
if (task === null)
|
|
25074
|
+
task = lastTaskOf(ownAll, t);
|
|
25075
|
+
settled2.set(id, task);
|
|
25076
|
+
return task;
|
|
25077
|
+
});
|
|
24408
25078
|
}
|
|
24409
25079
|
}
|
|
24410
25080
|
const codexLanes = active.filter((lane) => lane.rollout !== null && lane.transcript === null);
|
|
@@ -24426,6 +25096,8 @@ function readUsage(lanes, window, deps = {}, models) {
|
|
|
24426
25096
|
best = { lane, t: latest };
|
|
24427
25097
|
}
|
|
24428
25098
|
const bucket = bucketFor(source, (best?.lane ?? first)?.task ?? null, true);
|
|
25099
|
+
if (settling.figure !== void 0)
|
|
25100
|
+
settling.figure.codex += step.inputTokens + step.outputTokens + step.cacheWriteTokens + step.cacheReadTokens;
|
|
24429
25101
|
bucket.messages += 1;
|
|
24430
25102
|
bucket.inputTokens += step.inputTokens;
|
|
24431
25103
|
bucket.outputTokens += step.outputTokens;
|
|
@@ -24446,13 +25118,13 @@ var PHASE_MODELS_FILENAME = "phase-models.json";
|
|
|
24446
25118
|
function phaseModelsPath(engagementId, home) {
|
|
24447
25119
|
if (!isEngagementId(engagementId))
|
|
24448
25120
|
return null;
|
|
24449
|
-
return
|
|
25121
|
+
return join11(home ?? homedir8(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, PACING_DIR_NAME, PHASE_MODELS_FILENAME);
|
|
24450
25122
|
}
|
|
24451
25123
|
function writePhaseModels(path, phase, openedAt, tally) {
|
|
24452
25124
|
try {
|
|
24453
25125
|
let tasks = {};
|
|
24454
25126
|
try {
|
|
24455
|
-
const prior = phaseModelsFileSchema.safeParse(JSON.parse(
|
|
25127
|
+
const prior = phaseModelsFileSchema.safeParse(JSON.parse(readFileSync15(path, "utf-8")));
|
|
24456
25128
|
if (prior.success && prior.data.phase === phase && prior.data.openedAt === openedAt)
|
|
24457
25129
|
tasks = prior.data.tasks;
|
|
24458
25130
|
} catch {
|
|
@@ -24480,14 +25152,14 @@ function timeLogDir(engagementId, home) {
|
|
|
24480
25152
|
return path === null ? null : dirname4(path);
|
|
24481
25153
|
}
|
|
24482
25154
|
function writeJsonFile(path, value) {
|
|
24483
|
-
|
|
25155
|
+
mkdirSync6(dirname4(path), { recursive: true, mode: 448 });
|
|
24484
25156
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
24485
|
-
|
|
24486
|
-
|
|
25157
|
+
writeFileSync8(tmp, JSON.stringify(value), { mode: 384 });
|
|
25158
|
+
renameSync6(tmp, path);
|
|
24487
25159
|
}
|
|
24488
25160
|
function readAttemptedAt(dir) {
|
|
24489
25161
|
try {
|
|
24490
|
-
const parsed = JSON.parse(
|
|
25162
|
+
const parsed = JSON.parse(readFileSync15(join11(dir, TIME_THROTTLE_FILENAME), "utf-8"));
|
|
24491
25163
|
return typeof parsed.attemptedAt === "number" ? parsed.attemptedAt : null;
|
|
24492
25164
|
} catch {
|
|
24493
25165
|
return null;
|
|
@@ -24495,7 +25167,7 @@ function readAttemptedAt(dir) {
|
|
|
24495
25167
|
}
|
|
24496
25168
|
function writeAttemptedAt(dir, at) {
|
|
24497
25169
|
try {
|
|
24498
|
-
writeJsonFile(
|
|
25170
|
+
writeJsonFile(join11(dir, TIME_THROTTLE_FILENAME), { attemptedAt: at });
|
|
24499
25171
|
} catch {
|
|
24500
25172
|
}
|
|
24501
25173
|
}
|
|
@@ -24513,7 +25185,7 @@ function stringRecord(value) {
|
|
|
24513
25185
|
function readTimeCursor(dir, phase, openedAt) {
|
|
24514
25186
|
const fresh = { phase, openedAt, sentThrough: null, sentIds: {}, usage: {} };
|
|
24515
25187
|
try {
|
|
24516
|
-
const o = JSON.parse(
|
|
25188
|
+
const o = JSON.parse(readFileSync15(join11(dir, TIME_CURSOR_FILENAME), "utf-8"));
|
|
24517
25189
|
if (o["phase"] !== phase || o["openedAt"] !== openedAt)
|
|
24518
25190
|
return fresh;
|
|
24519
25191
|
const sentThrough = o["sentThrough"];
|
|
@@ -24526,6 +25198,29 @@ function readTimeCursor(dir, phase, openedAt) {
|
|
|
24526
25198
|
return fresh;
|
|
24527
25199
|
}
|
|
24528
25200
|
}
|
|
25201
|
+
function readSettled(dir, phase, openedAt) {
|
|
25202
|
+
const out = /* @__PURE__ */ new Map();
|
|
25203
|
+
try {
|
|
25204
|
+
const o = JSON.parse(readFileSync15(join11(dir, TIME_SETTLED_FILENAME), "utf-8"));
|
|
25205
|
+
if (o["phase"] !== phase || o["openedAt"] !== openedAt)
|
|
25206
|
+
return out;
|
|
25207
|
+
const tasks = o["tasks"];
|
|
25208
|
+
if (typeof tasks !== "object" || tasks === null || Array.isArray(tasks))
|
|
25209
|
+
return out;
|
|
25210
|
+
for (const [id, task] of Object.entries(tasks)) {
|
|
25211
|
+
if (task === null || typeof task === "string")
|
|
25212
|
+
out.set(id, task);
|
|
25213
|
+
}
|
|
25214
|
+
} catch {
|
|
25215
|
+
}
|
|
25216
|
+
return out;
|
|
25217
|
+
}
|
|
25218
|
+
function writeSettled(dir, phase, openedAt, settled2) {
|
|
25219
|
+
try {
|
|
25220
|
+
writeJsonFile(join11(dir, TIME_SETTLED_FILENAME), { phase, openedAt, tasks: Object.fromEntries(settled2) });
|
|
25221
|
+
} catch {
|
|
25222
|
+
}
|
|
25223
|
+
}
|
|
24529
25224
|
function usageKey(bucket) {
|
|
24530
25225
|
return `${bucket.source}\0${bucket.task ?? ""}`;
|
|
24531
25226
|
}
|
|
@@ -24612,33 +25307,33 @@ var PRUNE_SETTLE_MS = 50;
|
|
|
24612
25307
|
async function pruneTimeLog(path, openedAt) {
|
|
24613
25308
|
const aside = `${path}.prune-${process.pid}`;
|
|
24614
25309
|
try {
|
|
24615
|
-
|
|
25310
|
+
renameSync6(path, aside);
|
|
24616
25311
|
} catch {
|
|
24617
25312
|
return;
|
|
24618
25313
|
}
|
|
24619
25314
|
let text = "";
|
|
24620
25315
|
let written = false;
|
|
24621
25316
|
try {
|
|
24622
|
-
text =
|
|
25317
|
+
text = readFileSync15(aside, "utf-8");
|
|
24623
25318
|
const { kept } = prunedTimeLog(text, openedAt);
|
|
24624
25319
|
if (kept !== "")
|
|
24625
|
-
|
|
25320
|
+
appendFileSync3(path, kept, { mode: 384 });
|
|
24626
25321
|
written = true;
|
|
24627
25322
|
let seen = Buffer.byteLength(text, "utf-8");
|
|
24628
25323
|
for (; ; ) {
|
|
24629
|
-
await new Promise((
|
|
24630
|
-
const after =
|
|
25324
|
+
await new Promise((resolve12) => setTimeout(resolve12, PRUNE_SETTLE_MS));
|
|
25325
|
+
const after = readFileSync15(aside);
|
|
24631
25326
|
if (after.length <= seen)
|
|
24632
25327
|
break;
|
|
24633
|
-
|
|
25328
|
+
appendFileSync3(path, after.subarray(seen), { mode: 384 });
|
|
24634
25329
|
seen = after.length;
|
|
24635
25330
|
}
|
|
24636
|
-
|
|
25331
|
+
unlinkSync5(aside);
|
|
24637
25332
|
} catch {
|
|
24638
25333
|
try {
|
|
24639
25334
|
if (!written) {
|
|
24640
|
-
|
|
24641
|
-
|
|
25335
|
+
appendFileSync3(path, readFileSync15(aside, "utf-8"), { mode: 384 });
|
|
25336
|
+
unlinkSync5(aside);
|
|
24642
25337
|
}
|
|
24643
25338
|
} catch {
|
|
24644
25339
|
}
|
|
@@ -24653,7 +25348,17 @@ function conflictReason(body) {
|
|
|
24653
25348
|
const error51 = body.error;
|
|
24654
25349
|
return error51 === "basis-moved" || error51 === "phase-closed" ? error51 : null;
|
|
24655
25350
|
}
|
|
24656
|
-
async function attemptTimeRecord(config2, controlOrigin, deps = {}) {
|
|
25351
|
+
async function attemptTimeRecord(config2, controlOrigin, deps = {}, options = {}) {
|
|
25352
|
+
return (await attemptAndTell(config2, controlOrigin, deps, options)).result;
|
|
25353
|
+
}
|
|
25354
|
+
async function attemptAndTell(config2, controlOrigin, deps, options) {
|
|
25355
|
+
let wroteFigure = false;
|
|
25356
|
+
const result = await attemptOnce(config2, controlOrigin, deps, options, () => {
|
|
25357
|
+
wroteFigure = true;
|
|
25358
|
+
});
|
|
25359
|
+
return { result, wroteFigure };
|
|
25360
|
+
}
|
|
25361
|
+
async function attemptOnce(config2, controlOrigin, deps, options, onFigureWritten) {
|
|
24657
25362
|
const fetchFn = deps.fetchFn ?? globalThis.fetch;
|
|
24658
25363
|
const base = `${controlOrigin}/engagements/${encodeURIComponent(config2.guardEngagementId)}/time`;
|
|
24659
25364
|
const authorization = `Bearer ${config2.guardServiceToken}`;
|
|
@@ -24671,25 +25376,38 @@ async function attemptTimeRecord(config2, controlOrigin, deps = {}) {
|
|
|
24671
25376
|
const basis = parsedBasis.data;
|
|
24672
25377
|
if (basis.outcome === "nothing-to-record")
|
|
24673
25378
|
return { outcome: "not-sent", reason: "nothing-to-record" };
|
|
24674
|
-
const
|
|
25379
|
+
const logPath2 = join11(dir, TIME_LOG_FILENAME);
|
|
24675
25380
|
let text = "";
|
|
24676
25381
|
try {
|
|
24677
|
-
text =
|
|
25382
|
+
text = readFileSync15(logPath2, "utf-8");
|
|
24678
25383
|
} catch {
|
|
24679
25384
|
text = "";
|
|
24680
25385
|
}
|
|
24681
25386
|
const lanes = buildLanes(parseTimeLog(text), basis.taskIds);
|
|
24682
|
-
const
|
|
25387
|
+
const offsets = loadReadOffsets(dir, basis.phase, basis.openedAt);
|
|
25388
|
+
const readDeps = { ...deps, offsets };
|
|
25389
|
+
const intervals = buildIntervals(lanes, readDeps);
|
|
24683
25390
|
const models = /* @__PURE__ */ new Map();
|
|
24684
|
-
const
|
|
25391
|
+
const settled2 = readSettled(dir, basis.phase, basis.openedAt);
|
|
25392
|
+
const figure = { claudeCode: 0, codex: 0 };
|
|
25393
|
+
const final = options.final === true;
|
|
25394
|
+
const usage = readUsage(lanes, { from: basis.openedAt, taskIds: basis.taskIds }, readDeps, models, { final, settled: settled2, figure });
|
|
25395
|
+
saveReadOffsets(dir, offsets);
|
|
25396
|
+
const routing = routingFilePath(config2.guardEngagementId, deps.home);
|
|
25397
|
+
if (routing !== null)
|
|
25398
|
+
addCheapStarted(routing, basis.phase, tasksBuiltIn(lanes, usage, { from: basis.openedAt, taskIds: basis.taskIds }));
|
|
25399
|
+
if (final)
|
|
25400
|
+
writeSettled(dir, basis.phase, basis.openedAt, settled2);
|
|
24685
25401
|
const limitDir = phaseLimitDir(config2.guardEngagementId, deps.home);
|
|
24686
25402
|
if (limitDir !== null) {
|
|
24687
|
-
writePhaseUsage(limitDir, {
|
|
25403
|
+
const wrote = writePhaseUsage(limitDir, {
|
|
24688
25404
|
phase: basis.phase,
|
|
24689
25405
|
openedAt: basis.openedAt,
|
|
24690
|
-
tokens:
|
|
25406
|
+
tokens: figureOf(figure, options.agent),
|
|
24691
25407
|
at: new Date((deps.now ?? Date.now)()).toISOString()
|
|
24692
25408
|
});
|
|
25409
|
+
if (wrote)
|
|
25410
|
+
onFigureWritten();
|
|
24693
25411
|
}
|
|
24694
25412
|
const modelsPath = phaseModelsPath(config2.guardEngagementId, deps.home);
|
|
24695
25413
|
if (modelsPath !== null)
|
|
@@ -24698,7 +25416,7 @@ async function attemptTimeRecord(config2, controlOrigin, deps = {}) {
|
|
|
24698
25416
|
const selected = selectTimeReport(cursor, intervals, usage);
|
|
24699
25417
|
if (selected.intervals.length === 0 && selected.usage.length === 0) {
|
|
24700
25418
|
if (wouldPrune(text, basis.openedAt))
|
|
24701
|
-
await pruneTimeLog(
|
|
25419
|
+
await pruneTimeLog(logPath2, basis.openedAt);
|
|
24702
25420
|
return { outcome: "recorded" };
|
|
24703
25421
|
}
|
|
24704
25422
|
const report = { phase: basis.phase, openedAt: basis.openedAt, ...selected };
|
|
@@ -24714,14 +25432,14 @@ async function attemptTimeRecord(config2, controlOrigin, deps = {}) {
|
|
|
24714
25432
|
if (!timeReportResultSchema.safeParse(sent.body).success)
|
|
24715
25433
|
return { outcome: "not-sent", reason: "refused" };
|
|
24716
25434
|
try {
|
|
24717
|
-
writeJsonFile(
|
|
25435
|
+
writeJsonFile(join11(dir, TIME_CURSOR_FILENAME), advanceTimeCursor(cursor, selected));
|
|
24718
25436
|
} catch {
|
|
24719
25437
|
}
|
|
24720
25438
|
if (wouldPrune(text, basis.openedAt))
|
|
24721
|
-
await pruneTimeLog(
|
|
25439
|
+
await pruneTimeLog(logPath2, basis.openedAt);
|
|
24722
25440
|
return { outcome: "recorded" };
|
|
24723
25441
|
}
|
|
24724
|
-
async function runTimeVerb(deps = {}) {
|
|
25442
|
+
async function runTimeVerb(deps = {}, options = {}) {
|
|
24725
25443
|
let result;
|
|
24726
25444
|
try {
|
|
24727
25445
|
const env = deps.env ?? process.env;
|
|
@@ -24731,14 +25449,14 @@ async function runTimeVerb(deps = {}) {
|
|
|
24731
25449
|
result = { outcome: "not-sent", reason: "not-configured" };
|
|
24732
25450
|
} else {
|
|
24733
25451
|
writeAttemptedAt(dir, (deps.now ?? Date.now)());
|
|
24734
|
-
result = await attemptTimeRecord(configured.config, readControlOrigin(env).origin, deps);
|
|
25452
|
+
result = await attemptTimeRecord(configured.config, readControlOrigin(env).origin, deps, options);
|
|
24735
25453
|
}
|
|
24736
25454
|
} catch {
|
|
24737
25455
|
result = { outcome: "not-sent", reason: "unreachable" };
|
|
24738
25456
|
}
|
|
24739
25457
|
return timeRunResultSchema.parse(result);
|
|
24740
25458
|
}
|
|
24741
|
-
async function sendTimeRecord(deps = {}) {
|
|
25459
|
+
async function sendTimeRecord(deps = {}, options = {}) {
|
|
24742
25460
|
try {
|
|
24743
25461
|
const env = deps.env ?? process.env;
|
|
24744
25462
|
const configured = readConfig(env);
|
|
@@ -24749,17 +25467,170 @@ async function sendTimeRecord(deps = {}) {
|
|
|
24749
25467
|
return;
|
|
24750
25468
|
const now = (deps.now ?? Date.now)();
|
|
24751
25469
|
const last = readAttemptedAt(dir);
|
|
24752
|
-
|
|
24753
|
-
|
|
24754
|
-
|
|
24755
|
-
|
|
25470
|
+
let wroteFigure = false;
|
|
25471
|
+
if (!(last !== null && now - last < TIME_MIN_INTERVAL_MS && now >= last)) {
|
|
25472
|
+
writeAttemptedAt(dir, now);
|
|
25473
|
+
wroteFigure = (await attemptAndTell(configured.config, readControlOrigin(env).origin, deps, { agent: options.agent })).wroteFigure;
|
|
25474
|
+
}
|
|
25475
|
+
if (!wroteFigure)
|
|
25476
|
+
recountPhaseUsage(configured.config, deps, options);
|
|
25477
|
+
} catch {
|
|
25478
|
+
}
|
|
25479
|
+
}
|
|
25480
|
+
function recountPhaseUsage(config2, deps = {}, options = {}) {
|
|
25481
|
+
try {
|
|
25482
|
+
const limitDir = phaseLimitDir(config2.guardEngagementId, deps.home);
|
|
25483
|
+
const dir = timeLogDir(config2.guardEngagementId, deps.home);
|
|
25484
|
+
if (limitDir === null || dir === null)
|
|
25485
|
+
return false;
|
|
25486
|
+
const last = readPhaseUsageFile(limitDir);
|
|
25487
|
+
if (last === null)
|
|
25488
|
+
return false;
|
|
25489
|
+
let text = "";
|
|
25490
|
+
try {
|
|
25491
|
+
text = readFileSync15(join11(dir, TIME_LOG_FILENAME), "utf-8");
|
|
25492
|
+
} catch {
|
|
25493
|
+
text = "";
|
|
25494
|
+
}
|
|
25495
|
+
const lanes = buildLanes(parseTimeLog(text), []);
|
|
25496
|
+
const offsets = loadReadOffsets(dir, last.phase, last.openedAt);
|
|
25497
|
+
const figure = { claudeCode: 0, codex: 0 };
|
|
25498
|
+
readUsage(lanes, { from: last.openedAt, taskIds: [] }, { ...deps, offsets }, void 0, { figure });
|
|
25499
|
+
saveReadOffsets(dir, offsets);
|
|
25500
|
+
return writePhaseUsage(limitDir, {
|
|
25501
|
+
phase: last.phase,
|
|
25502
|
+
openedAt: last.openedAt,
|
|
25503
|
+
tokens: figureOf(figure, options.agent),
|
|
25504
|
+
at: new Date((deps.now ?? Date.now)()).toISOString()
|
|
25505
|
+
});
|
|
25506
|
+
} catch {
|
|
25507
|
+
return false;
|
|
25508
|
+
}
|
|
25509
|
+
}
|
|
25510
|
+
function figureOf(figure, agent) {
|
|
25511
|
+
return Math.max(0, Math.round(agent === "codex" ? figure.codex : figure.claudeCode));
|
|
25512
|
+
}
|
|
25513
|
+
var ROUTING_LOCK_FILENAME = "routing.lock";
|
|
25514
|
+
var ROUTING_LOCK_GIVE_UP_MS = 50;
|
|
25515
|
+
var ROUTING_LOCK_STALE_MS = 5 * 1e3;
|
|
25516
|
+
var ROUTING_LOCK_POLL_MS = 2;
|
|
25517
|
+
function routingFilePath(engagementId, home) {
|
|
25518
|
+
if (!isEngagementId(engagementId))
|
|
25519
|
+
return null;
|
|
25520
|
+
return join11(home ?? homedir8(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, ROUTING_FILENAME);
|
|
25521
|
+
}
|
|
25522
|
+
function sleepSync2(ms) {
|
|
25523
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
25524
|
+
}
|
|
25525
|
+
function addCheapStarted(path, phase, tasks, giveUpMs = ROUTING_LOCK_GIVE_UP_MS) {
|
|
25526
|
+
if (tasks.length === 0)
|
|
25527
|
+
return true;
|
|
25528
|
+
try {
|
|
25529
|
+
const lock = join11(dirname4(path), ROUTING_LOCK_FILENAME);
|
|
25530
|
+
const giveUpAt = Date.now() + giveUpMs;
|
|
25531
|
+
while (!tryTakeLockFile(lock, ROUTING_LOCK_STALE_MS)) {
|
|
25532
|
+
if (Date.now() >= giveUpAt)
|
|
25533
|
+
return false;
|
|
25534
|
+
sleepSync2(ROUTING_LOCK_POLL_MS);
|
|
25535
|
+
}
|
|
25536
|
+
try {
|
|
25537
|
+
let started = [];
|
|
25538
|
+
try {
|
|
25539
|
+
const parsed = routingRecordSchema.safeParse(JSON.parse(readFileSync15(path, "utf-8")));
|
|
25540
|
+
if (parsed.success && parsed.data.phase === phase)
|
|
25541
|
+
started = [...parsed.data.cheapStarted];
|
|
25542
|
+
} catch {
|
|
25543
|
+
started = [];
|
|
25544
|
+
}
|
|
25545
|
+
const added = tasks.filter((t, i) => !started.includes(t) && tasks.indexOf(t) === i);
|
|
25546
|
+
if (added.length === 0)
|
|
25547
|
+
return true;
|
|
25548
|
+
const record2 = { phase, cheapStarted: [...started, ...added] };
|
|
25549
|
+
if (!routingRecordSchema.safeParse(record2).success)
|
|
25550
|
+
return false;
|
|
25551
|
+
writeJsonFile(path, record2);
|
|
25552
|
+
return true;
|
|
25553
|
+
} finally {
|
|
25554
|
+
releaseLockFile(lock);
|
|
25555
|
+
}
|
|
25556
|
+
} catch {
|
|
25557
|
+
return false;
|
|
25558
|
+
}
|
|
25559
|
+
}
|
|
25560
|
+
function recordSpawnedTask(toolInput, deps) {
|
|
25561
|
+
try {
|
|
25562
|
+
if (typeof toolInput !== "object" || toolInput === null || Array.isArray(toolInput))
|
|
25563
|
+
return null;
|
|
25564
|
+
const engagementId = readConfig(deps.env ?? process.env).config?.guardEngagementId;
|
|
25565
|
+
if (engagementId === void 0)
|
|
25566
|
+
return null;
|
|
25567
|
+
const path = routingFilePath(engagementId, deps.home);
|
|
25568
|
+
if (path === null)
|
|
25569
|
+
return null;
|
|
25570
|
+
const parsed = taskPlanSchema.safeParse(JSON.parse(readFileSync15(join11(deps.projectDir, TASK_PLAN_FILE), "utf-8")));
|
|
25571
|
+
if (!parsed.success)
|
|
25572
|
+
return null;
|
|
25573
|
+
const plan = parsed.data;
|
|
25574
|
+
const ids = plan.tasks.map((t) => t.id);
|
|
25575
|
+
const textOf = (key) => {
|
|
25576
|
+
const v = toolInput[key];
|
|
25577
|
+
return typeof v === "string" ? v : null;
|
|
25578
|
+
};
|
|
25579
|
+
const description = textOf("description");
|
|
25580
|
+
const prompt = textOf("prompt");
|
|
25581
|
+
const named = (description === null ? null : taskNamedIn(description, ids)) ?? (prompt === null ? null : taskNamedIn(prompt, ids));
|
|
25582
|
+
if (named === null)
|
|
25583
|
+
return null;
|
|
25584
|
+
const task = plan.tasks.find((t) => t.id === named);
|
|
25585
|
+
if (task === void 0 || task.kind !== "build" || task.cheapFirst !== true)
|
|
25586
|
+
return null;
|
|
25587
|
+
return addCheapStarted(path, plan.phase, [named]) ? named : null;
|
|
24756
25588
|
} catch {
|
|
25589
|
+
return null;
|
|
25590
|
+
}
|
|
25591
|
+
}
|
|
25592
|
+
function tasksBuiltIn(lanes, usage, window) {
|
|
25593
|
+
const from = Date.parse(window.from);
|
|
25594
|
+
const to = window.to === void 0 || window.to === null ? Infinity : Date.parse(window.to);
|
|
25595
|
+
const inWindow = (t) => t >= from && t <= to;
|
|
25596
|
+
const out = [];
|
|
25597
|
+
const add = (task) => {
|
|
25598
|
+
if (task !== null && window.taskIds.includes(task) && !out.includes(task))
|
|
25599
|
+
out.push(task);
|
|
25600
|
+
};
|
|
25601
|
+
for (const bucket of usage)
|
|
25602
|
+
if (bucket.messages > 0)
|
|
25603
|
+
add(bucket.task);
|
|
25604
|
+
for (const lane of lanes) {
|
|
25605
|
+
if (lane.task === null)
|
|
25606
|
+
continue;
|
|
25607
|
+
const times = lane.events.map((e) => msOf(e.at)).filter(inWindow);
|
|
25608
|
+
if (times.length === 0)
|
|
25609
|
+
continue;
|
|
25610
|
+
const codex = lane.rollout !== null && lane.transcript === null;
|
|
25611
|
+
if (lane.agent !== MAIN_AGENT || codex) {
|
|
25612
|
+
add(lane.task);
|
|
25613
|
+
continue;
|
|
25614
|
+
}
|
|
25615
|
+
let coordinatingFrom = Infinity;
|
|
25616
|
+
for (const other of lanes) {
|
|
25617
|
+
if (other.agent === MAIN_AGENT)
|
|
25618
|
+
continue;
|
|
25619
|
+
const sameSession = lane.session !== null ? other.session === lane.session : lane.transcript !== null && other.transcript === lane.transcript;
|
|
25620
|
+
if (!sameSession)
|
|
25621
|
+
continue;
|
|
25622
|
+
for (const e of other.events)
|
|
25623
|
+
coordinatingFrom = Math.min(coordinatingFrom, msOf(e.at));
|
|
25624
|
+
}
|
|
25625
|
+
if (times.some((t) => t < coordinatingFrom))
|
|
25626
|
+
add(lane.task);
|
|
24757
25627
|
}
|
|
25628
|
+
return out;
|
|
24758
25629
|
}
|
|
24759
25630
|
|
|
24760
25631
|
// dist/own-work.js
|
|
24761
|
-
import { appendFileSync as
|
|
24762
|
-
import { basename as basename2, dirname as dirname5, isAbsolute as isAbsolute2, join as
|
|
25632
|
+
import { appendFileSync as appendFileSync4, lstatSync as lstatSync2, readFileSync as readFileSync16, realpathSync as realpathSync6 } from "node:fs";
|
|
25633
|
+
import { basename as basename2, dirname as dirname5, isAbsolute as isAbsolute2, join as join12, relative as relative5, resolve as resolve4, sep as sep3 } from "node:path";
|
|
24763
25634
|
|
|
24764
25635
|
// dist/risky/types.js
|
|
24765
25636
|
var RISKY_ACTION_TYPES = [
|
|
@@ -24793,7 +25664,7 @@ function ownWorkFileName(sessionId) {
|
|
|
24793
25664
|
function ownWorkPath(sessionId, dir) {
|
|
24794
25665
|
if (typeof sessionId !== "string" || !livenessIdOk(sessionId))
|
|
24795
25666
|
return null;
|
|
24796
|
-
return
|
|
25667
|
+
return join12(dir ?? markerDir(), ownWorkFileName(sessionId));
|
|
24797
25668
|
}
|
|
24798
25669
|
function inputString2(input, key) {
|
|
24799
25670
|
if (typeof input !== "object" || input === null)
|
|
@@ -24811,7 +25682,7 @@ function append(sessionId, line2, dir) {
|
|
|
24811
25682
|
const path = ownWorkPath(sessionId, dir);
|
|
24812
25683
|
if (path === null)
|
|
24813
25684
|
return;
|
|
24814
|
-
|
|
25685
|
+
appendFileSync4(path, `${JSON.stringify(line2)}
|
|
24815
25686
|
`, { mode: 384 });
|
|
24816
25687
|
}
|
|
24817
25688
|
function recordOwnShell(input, at, deps = {}) {
|
|
@@ -24857,7 +25728,7 @@ function readOwnWork(sessionId, dir) {
|
|
|
24857
25728
|
const path = ownWorkPath(sessionId, dir);
|
|
24858
25729
|
if (path === null)
|
|
24859
25730
|
return [];
|
|
24860
|
-
return parseOwnWork(
|
|
25731
|
+
return parseOwnWork(readFileSync16(path, "utf-8"));
|
|
24861
25732
|
} catch {
|
|
24862
25733
|
return [];
|
|
24863
25734
|
}
|
|
@@ -24892,7 +25763,7 @@ function realPathOf(path) {
|
|
|
24892
25763
|
let at = resolve4(path);
|
|
24893
25764
|
for (; ; ) {
|
|
24894
25765
|
try {
|
|
24895
|
-
return
|
|
25766
|
+
return join12(realpathSync6.native(at), ...missing.reverse());
|
|
24896
25767
|
} catch {
|
|
24897
25768
|
const parent = dirname5(at);
|
|
24898
25769
|
if (parent === at)
|
|
@@ -24952,7 +25823,7 @@ function ownChangedFiles(repoRoot, files, sessionId, deps = {}) {
|
|
|
24952
25823
|
};
|
|
24953
25824
|
const root = resolve4(repoRoot);
|
|
24954
25825
|
return files.filter((rel) => {
|
|
24955
|
-
const abs =
|
|
25826
|
+
const abs = join12(root, rel);
|
|
24956
25827
|
if (edited.has(realPathOf(abs)))
|
|
24957
25828
|
return true;
|
|
24958
25829
|
if (windows.length === 0)
|
|
@@ -24966,7 +25837,7 @@ function ownChangedFiles(repoRoot, files, sessionId, deps = {}) {
|
|
|
24966
25837
|
|
|
24967
25838
|
// dist/hooks/findings.js
|
|
24968
25839
|
import { createHash as createHash4, randomUUID as randomUUID2 } from "node:crypto";
|
|
24969
|
-
import { closeSync as
|
|
25840
|
+
import { closeSync as closeSync4, existsSync as existsSync7, openSync as openSync4, readFileSync as readFileSync17, renameSync as renameSync7, statSync as statSync4, unlinkSync as unlinkSync6, writeFileSync as writeFileSync9 } from "node:fs";
|
|
24970
25841
|
function findingKey(firing) {
|
|
24971
25842
|
return createHash4("sha256").update(`${firing.guardId}
|
|
24972
25843
|
${firing.path ?? ""}
|
|
@@ -25009,7 +25880,7 @@ function readFindings(sessionId) {
|
|
|
25009
25880
|
return null;
|
|
25010
25881
|
const session = sessionId;
|
|
25011
25882
|
try {
|
|
25012
|
-
const parsed = JSON.parse(
|
|
25883
|
+
const parsed = JSON.parse(readFileSync17(path, "utf-8"));
|
|
25013
25884
|
if (parsed["version"] !== 1 || !Array.isArray(parsed["findings"]))
|
|
25014
25885
|
return emptyFindings(session);
|
|
25015
25886
|
const findings = [];
|
|
@@ -25029,12 +25900,12 @@ function writeFindings(file2) {
|
|
|
25029
25900
|
return;
|
|
25030
25901
|
const temp = `${path.slice(0, -".json".length)}.${process.pid}.tmp.json`;
|
|
25031
25902
|
try {
|
|
25032
|
-
|
|
25903
|
+
writeFileSync9(temp, `${JSON.stringify(file2)}
|
|
25033
25904
|
`, { mode: 384 });
|
|
25034
|
-
|
|
25905
|
+
renameSync7(temp, path);
|
|
25035
25906
|
} catch {
|
|
25036
25907
|
try {
|
|
25037
|
-
|
|
25908
|
+
unlinkSync6(temp);
|
|
25038
25909
|
} catch {
|
|
25039
25910
|
}
|
|
25040
25911
|
}
|
|
@@ -25050,7 +25921,7 @@ function pause(ms) {
|
|
|
25050
25921
|
function takeOverStaleLock(lock) {
|
|
25051
25922
|
const aside = `${lock}.${process.pid}.${randomUUID2()}.stale`;
|
|
25052
25923
|
try {
|
|
25053
|
-
|
|
25924
|
+
renameSync7(lock, aside);
|
|
25054
25925
|
} catch {
|
|
25055
25926
|
return false;
|
|
25056
25927
|
}
|
|
@@ -25062,17 +25933,17 @@ function takeOverStaleLock(lock) {
|
|
|
25062
25933
|
}
|
|
25063
25934
|
if (!staleIndeed) {
|
|
25064
25935
|
try {
|
|
25065
|
-
|
|
25936
|
+
renameSync7(aside, lock);
|
|
25066
25937
|
} catch {
|
|
25067
25938
|
try {
|
|
25068
|
-
|
|
25939
|
+
unlinkSync6(aside);
|
|
25069
25940
|
} catch {
|
|
25070
25941
|
}
|
|
25071
25942
|
}
|
|
25072
25943
|
return false;
|
|
25073
25944
|
}
|
|
25074
25945
|
try {
|
|
25075
|
-
|
|
25946
|
+
unlinkSync6(aside);
|
|
25076
25947
|
} catch {
|
|
25077
25948
|
}
|
|
25078
25949
|
return true;
|
|
@@ -25085,7 +25956,7 @@ function withFindingsLock(sessionId, body, waitMs = FINDINGS_LOCK_WAIT_MS) {
|
|
|
25085
25956
|
const deadline = Date.now() + waitMs;
|
|
25086
25957
|
for (; ; ) {
|
|
25087
25958
|
try {
|
|
25088
|
-
|
|
25959
|
+
closeSync4(openSync4(lock, "wx", 384));
|
|
25089
25960
|
break;
|
|
25090
25961
|
} catch (err) {
|
|
25091
25962
|
if (err.code !== "EEXIST")
|
|
@@ -25107,31 +25978,31 @@ function withFindingsLock(sessionId, body, waitMs = FINDINGS_LOCK_WAIT_MS) {
|
|
|
25107
25978
|
return body();
|
|
25108
25979
|
} finally {
|
|
25109
25980
|
try {
|
|
25110
|
-
|
|
25981
|
+
unlinkSync6(lock);
|
|
25111
25982
|
} catch {
|
|
25112
25983
|
}
|
|
25113
25984
|
}
|
|
25114
25985
|
}
|
|
25115
|
-
function takeUndelivered(file2,
|
|
25986
|
+
function takeUndelivered(file2, folder2) {
|
|
25116
25987
|
const taken = [];
|
|
25117
25988
|
const findings = file2.findings.map((f) => {
|
|
25118
|
-
if (f.delivered ||
|
|
25989
|
+
if (f.delivered || folder2 !== null && f.folder !== folder2)
|
|
25119
25990
|
return f;
|
|
25120
25991
|
taken.push(f);
|
|
25121
25992
|
return { ...f, delivered: true };
|
|
25122
25993
|
});
|
|
25123
25994
|
return { file: { ...file2, findings }, taken };
|
|
25124
25995
|
}
|
|
25125
|
-
function deliverFindings(sessionId,
|
|
25996
|
+
function deliverFindings(sessionId, folder2) {
|
|
25126
25997
|
const path = findingsPath(sessionId);
|
|
25127
|
-
if (path === null || !
|
|
25998
|
+
if (path === null || !existsSync7(path))
|
|
25128
25999
|
return [];
|
|
25129
26000
|
try {
|
|
25130
26001
|
const taken = withFindingsLock(sessionId, () => {
|
|
25131
26002
|
const before = readFindings(sessionId);
|
|
25132
26003
|
if (before === null)
|
|
25133
26004
|
return [];
|
|
25134
|
-
const { file: file2, taken: given } = takeUndelivered(before,
|
|
26005
|
+
const { file: file2, taken: given } = takeUndelivered(before, folder2);
|
|
25135
26006
|
if (given.length > 0)
|
|
25136
26007
|
writeFindings(file2);
|
|
25137
26008
|
return given;
|
|
@@ -25141,11 +26012,11 @@ function deliverFindings(sessionId, folder) {
|
|
|
25141
26012
|
return [];
|
|
25142
26013
|
}
|
|
25143
26014
|
}
|
|
25144
|
-
function turnEndBookkeeping(file2,
|
|
26015
|
+
function turnEndBookkeeping(file2, folder2, outcome, topLevel, now) {
|
|
25145
26016
|
const recorded = [...file2.findings];
|
|
25146
26017
|
const firing = /* @__PURE__ */ new Map();
|
|
25147
26018
|
const notRun = new Set(outcome.kind === "evaluated" ? outcome.notRun : []);
|
|
25148
|
-
const observed = (f) => f.folder ===
|
|
26019
|
+
const observed = (f) => f.folder === folder2 && !notRun.has(f.patternRef);
|
|
25149
26020
|
if (outcome.kind === "evaluated") {
|
|
25150
26021
|
for (const g of outcome.fired) {
|
|
25151
26022
|
if (g.severity === "block")
|
|
@@ -25161,13 +26032,13 @@ function turnEndBookkeeping(file2, folder, outcome, topLevel, now) {
|
|
|
25161
26032
|
const closes = observed(f) && (outcome.kind === "no-own-changes" || outcome.kind === "evaluated" && !firing.has(f.key));
|
|
25162
26033
|
(closes ? removed : kept).push(f);
|
|
25163
26034
|
}
|
|
25164
|
-
const known = new Set(kept.filter((f) => f.folder ===
|
|
26035
|
+
const known = new Set(kept.filter((f) => f.folder === folder2).map((f) => f.key));
|
|
25165
26036
|
for (const [key, g] of firing) {
|
|
25166
26037
|
if (known.has(key))
|
|
25167
26038
|
continue;
|
|
25168
26039
|
kept.push({
|
|
25169
26040
|
key,
|
|
25170
|
-
folder,
|
|
26041
|
+
folder: folder2,
|
|
25171
26042
|
guardId: g.guardId,
|
|
25172
26043
|
patternRef: g.patternRef,
|
|
25173
26044
|
severity: g.severity,
|
|
@@ -25362,7 +26233,7 @@ function patchHeaderPaths(patch) {
|
|
|
25362
26233
|
}
|
|
25363
26234
|
|
|
25364
26235
|
// dist/hooks/post-tool-use.js
|
|
25365
|
-
import { isAbsolute as isAbsolute3, join as
|
|
26236
|
+
import { isAbsolute as isAbsolute3, join as join13, relative as relative6, resolve as resolve5, sep as sep4 } from "node:path";
|
|
25366
26237
|
var HANDLED_EDIT_TOOLS = /* @__PURE__ */ new Set(["Edit", "Write", "MultiEdit", "NotebookEdit"]);
|
|
25367
26238
|
async function runPostToolUse(readSeat = readSeatConfiguration, profile = AGENT_PROFILES["claude-code"]) {
|
|
25368
26239
|
const reply = hookReply("PostToolUse", profile);
|
|
@@ -25549,7 +26420,7 @@ function insideRepository(path, repoRoot) {
|
|
|
25549
26420
|
const rel = relative6(realPathOf(repoRoot), realPathOf(path));
|
|
25550
26421
|
if (rel === "" || rel === ".." || rel.startsWith(`..${sep4}`) || isAbsolute3(rel))
|
|
25551
26422
|
return null;
|
|
25552
|
-
return
|
|
26423
|
+
return join13(repoRoot, rel);
|
|
25553
26424
|
}
|
|
25554
26425
|
function actOnEnvelope2(envelope, reply) {
|
|
25555
26426
|
const notRun = notRunReport(envelope.notRun);
|
|
@@ -25572,17 +26443,17 @@ ${guardLines}${notRunBlock}`);
|
|
|
25572
26443
|
}
|
|
25573
26444
|
}
|
|
25574
26445
|
function readStdin() {
|
|
25575
|
-
return new Promise((
|
|
26446
|
+
return new Promise((resolve12, reject) => {
|
|
25576
26447
|
const chunks = [];
|
|
25577
26448
|
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
25578
|
-
process.stdin.on("end", () =>
|
|
26449
|
+
process.stdin.on("end", () => resolve12(Buffer.concat(chunks).toString("utf-8")));
|
|
25579
26450
|
process.stdin.on("error", reject);
|
|
25580
26451
|
});
|
|
25581
26452
|
}
|
|
25582
26453
|
|
|
25583
26454
|
// dist/liveness.js
|
|
25584
|
-
import { closeSync as
|
|
25585
|
-
import { join as
|
|
26455
|
+
import { closeSync as closeSync5, mkdtempSync, openSync as openSync5, readdirSync as readdirSync7, readFileSync as readFileSync18, renameSync as renameSync8, rmSync as rmSync2, statSync as statSync5, unlinkSync as unlinkSync7, writeFileSync as writeFileSync10 } from "node:fs";
|
|
26456
|
+
import { join as join14 } from "node:path";
|
|
25586
26457
|
var LIVE_WINDOW_MS = 10 * 60 * 1e3;
|
|
25587
26458
|
function field(input, key) {
|
|
25588
26459
|
if (typeof input !== "object" || input === null)
|
|
@@ -25591,10 +26462,10 @@ function field(input, key) {
|
|
|
25591
26462
|
return typeof v === "string" && v !== "" ? v : null;
|
|
25592
26463
|
}
|
|
25593
26464
|
function indexEntry(dir, sessionId, name) {
|
|
25594
|
-
const
|
|
26465
|
+
const folder2 = join14(dir, livenessIndexDirName(sessionId));
|
|
25595
26466
|
for (let attempt2 = 0; attempt2 < 3; attempt2++) {
|
|
25596
26467
|
try {
|
|
25597
|
-
|
|
26468
|
+
closeSync5(openSync5(join14(folder2, name), "a", 384));
|
|
25598
26469
|
return true;
|
|
25599
26470
|
} catch (err) {
|
|
25600
26471
|
if (err.code !== "ENOENT")
|
|
@@ -25602,13 +26473,13 @@ function indexEntry(dir, sessionId, name) {
|
|
|
25602
26473
|
}
|
|
25603
26474
|
let tmp = null;
|
|
25604
26475
|
try {
|
|
25605
|
-
tmp = mkdtempSync(`${
|
|
26476
|
+
tmp = mkdtempSync(`${folder2}.`);
|
|
25606
26477
|
for (const existing of readdirSync7(dir)) {
|
|
25607
26478
|
if (parseLivenessFileName(existing)?.sessionId === sessionId)
|
|
25608
|
-
|
|
26479
|
+
closeSync5(openSync5(join14(tmp, existing), "a", 384));
|
|
25609
26480
|
}
|
|
25610
|
-
|
|
25611
|
-
|
|
26481
|
+
closeSync5(openSync5(join14(tmp, name), "a", 384));
|
|
26482
|
+
renameSync8(tmp, folder2);
|
|
25612
26483
|
return true;
|
|
25613
26484
|
} catch {
|
|
25614
26485
|
if (tmp !== null)
|
|
@@ -25633,18 +26504,18 @@ function recordLiveness(input, deps = {}) {
|
|
|
25633
26504
|
const name = livenessFileName(livenessKey(copy?.common ?? null), sessionId, agentId);
|
|
25634
26505
|
if (!indexEntry(dir, sessionId, name))
|
|
25635
26506
|
return null;
|
|
25636
|
-
const path =
|
|
26507
|
+
const path = join14(dir, name);
|
|
25637
26508
|
const text = `${cwd}
|
|
25638
26509
|
${copy?.top ?? ""}
|
|
25639
26510
|
`;
|
|
25640
26511
|
try {
|
|
25641
|
-
|
|
26512
|
+
writeFileSync10(path, text, { encoding: "utf-8", flag: "wx", mode: 384 });
|
|
25642
26513
|
return { firstSeen: true };
|
|
25643
26514
|
} catch (err) {
|
|
25644
26515
|
if (err.code !== "EEXIST")
|
|
25645
26516
|
return null;
|
|
25646
26517
|
}
|
|
25647
|
-
|
|
26518
|
+
writeFileSync10(path, text, { encoding: "utf-8", mode: 384 });
|
|
25648
26519
|
return { firstSeen: false };
|
|
25649
26520
|
} catch {
|
|
25650
26521
|
return null;
|
|
@@ -25663,7 +26534,7 @@ function clearLiveness(input, deps = {}) {
|
|
|
25663
26534
|
if (p === null || p.sessionId !== sessionId || p.agentId !== agentId)
|
|
25664
26535
|
continue;
|
|
25665
26536
|
try {
|
|
25666
|
-
|
|
26537
|
+
unlinkSync7(join14(dir, name));
|
|
25667
26538
|
removed += 1;
|
|
25668
26539
|
} catch {
|
|
25669
26540
|
}
|
|
@@ -25676,7 +26547,7 @@ function clearLiveness(input, deps = {}) {
|
|
|
25676
26547
|
}
|
|
25677
26548
|
function topOf(path) {
|
|
25678
26549
|
try {
|
|
25679
|
-
const top =
|
|
26550
|
+
const top = readFileSync18(path, "utf-8").split("\n")[1] ?? "";
|
|
25680
26551
|
return top === "" ? null : top;
|
|
25681
26552
|
} catch {
|
|
25682
26553
|
return null;
|
|
@@ -25698,7 +26569,7 @@ function readLiveness(sessionId, cwd, deps = {}) {
|
|
|
25698
26569
|
const p = parseLivenessFileName(name);
|
|
25699
26570
|
if (p === null || p.key !== key || p.sessionId !== sessionId)
|
|
25700
26571
|
continue;
|
|
25701
|
-
const full =
|
|
26572
|
+
const full = join14(dir, name);
|
|
25702
26573
|
let seenAt;
|
|
25703
26574
|
try {
|
|
25704
26575
|
seenAt = statSync5(full).mtimeMs;
|
|
@@ -25744,168 +26615,8 @@ import nodePath5 from "node:path";
|
|
|
25744
26615
|
|
|
25745
26616
|
// dist/pace-verb.js
|
|
25746
26617
|
import { mkdirSync as mkdirSync7, readdirSync as readdirSync8, readFileSync as readFileSync19, renameSync as renameSync9, statSync as statSync6, writeFileSync as writeFileSync11 } from "node:fs";
|
|
25747
|
-
import { homedir as
|
|
26618
|
+
import { homedir as homedir9 } from "node:os";
|
|
25748
26619
|
import nodePath4 from "node:path";
|
|
25749
|
-
|
|
25750
|
-
// dist/scan-lock.js
|
|
25751
|
-
import { spawn } from "node:child_process";
|
|
25752
|
-
import { linkSync, mkdirSync as mkdirSync6, readFileSync as readFileSync18, renameSync as renameSync8, unlinkSync as unlinkSync7, writeFileSync as writeFileSync10 } from "node:fs";
|
|
25753
|
-
import nodePath3 from "node:path";
|
|
25754
|
-
var SCAN_LOCK_FILENAME = "scan.lock";
|
|
25755
|
-
var SCAN_LOCK_STALE_MS = 15 * 60 * 1e3;
|
|
25756
|
-
var SCAN_LOCK_POLL_MS = 100;
|
|
25757
|
-
function scanLockPath(home) {
|
|
25758
|
-
return nodePath3.join(pacingDir(home), SCAN_LOCK_FILENAME);
|
|
25759
|
-
}
|
|
25760
|
-
function readLockBody(path) {
|
|
25761
|
-
let text;
|
|
25762
|
-
try {
|
|
25763
|
-
text = readFileSync18(path, "utf-8");
|
|
25764
|
-
} catch (err) {
|
|
25765
|
-
return err.code === "ENOENT" ? "missing" : null;
|
|
25766
|
-
}
|
|
25767
|
-
try {
|
|
25768
|
-
const v = JSON.parse(text);
|
|
25769
|
-
return typeof v["pid"] === "number" && typeof v["at"] === "number" ? { pid: v["pid"], at: v["at"] } : null;
|
|
25770
|
-
} catch {
|
|
25771
|
-
return null;
|
|
25772
|
-
}
|
|
25773
|
-
}
|
|
25774
|
-
function processAlive(pid) {
|
|
25775
|
-
if (!Number.isInteger(pid) || pid <= 0)
|
|
25776
|
-
return false;
|
|
25777
|
-
try {
|
|
25778
|
-
process.kill(pid, 0);
|
|
25779
|
-
return true;
|
|
25780
|
-
} catch (err) {
|
|
25781
|
-
return err.code === "EPERM";
|
|
25782
|
-
}
|
|
25783
|
-
}
|
|
25784
|
-
function isStale(body, staleMs, deps) {
|
|
25785
|
-
if (body === null)
|
|
25786
|
-
return true;
|
|
25787
|
-
const now = (deps.clock ?? Date.now)();
|
|
25788
|
-
if (Math.abs(now - body.at) > staleMs)
|
|
25789
|
-
return true;
|
|
25790
|
-
return !(deps.alive ?? processAlive)(body.pid);
|
|
25791
|
-
}
|
|
25792
|
-
function writeLock(path, pid, deps, flag) {
|
|
25793
|
-
writeFileSync10(path, JSON.stringify({ pid, at: (deps.clock ?? Date.now)() }), { flag, mode: 384 });
|
|
25794
|
-
}
|
|
25795
|
-
function tryTakeScanLock(deps = {}) {
|
|
25796
|
-
return tryTakeLockFile(scanLockPath(deps.home), SCAN_LOCK_STALE_MS, deps);
|
|
25797
|
-
}
|
|
25798
|
-
function tryTakeLockFile(path, staleMs, deps = {}) {
|
|
25799
|
-
const pid = deps.pid ?? process.pid;
|
|
25800
|
-
try {
|
|
25801
|
-
mkdirSync6(nodePath3.dirname(path), { recursive: true, mode: 448 });
|
|
25802
|
-
} catch {
|
|
25803
|
-
return false;
|
|
25804
|
-
}
|
|
25805
|
-
for (let attempt2 = 0; attempt2 < 2; attempt2++) {
|
|
25806
|
-
try {
|
|
25807
|
-
writeLock(path, pid, deps, "wx");
|
|
25808
|
-
return true;
|
|
25809
|
-
} catch (err) {
|
|
25810
|
-
if (err.code !== "EEXIST")
|
|
25811
|
-
return false;
|
|
25812
|
-
}
|
|
25813
|
-
const seen = readLockBody(path);
|
|
25814
|
-
if (seen === "missing")
|
|
25815
|
-
continue;
|
|
25816
|
-
if (!isStale(seen, staleMs, deps))
|
|
25817
|
-
return false;
|
|
25818
|
-
const aside = `${path}.${String(pid)}.${String((deps.clock ?? Date.now)())}.stale`;
|
|
25819
|
-
try {
|
|
25820
|
-
renameSync8(path, aside);
|
|
25821
|
-
} catch {
|
|
25822
|
-
continue;
|
|
25823
|
-
}
|
|
25824
|
-
const taken = readLockBody(aside);
|
|
25825
|
-
const same = taken !== "missing" && (seen === null ? taken === null : taken !== null && taken.pid === seen.pid && taken.at === seen.at);
|
|
25826
|
-
if (!same && taken !== "missing" && !isStale(taken, staleMs, deps)) {
|
|
25827
|
-
try {
|
|
25828
|
-
linkSync(aside, path);
|
|
25829
|
-
} catch {
|
|
25830
|
-
}
|
|
25831
|
-
try {
|
|
25832
|
-
unlinkSync7(aside);
|
|
25833
|
-
} catch {
|
|
25834
|
-
}
|
|
25835
|
-
return false;
|
|
25836
|
-
}
|
|
25837
|
-
try {
|
|
25838
|
-
unlinkSync7(aside);
|
|
25839
|
-
} catch {
|
|
25840
|
-
}
|
|
25841
|
-
}
|
|
25842
|
-
return false;
|
|
25843
|
-
}
|
|
25844
|
-
function releaseLockFile(path, pid = process.pid) {
|
|
25845
|
-
const body = readLockBody(path);
|
|
25846
|
-
if (body === "missing" || body === null || body.pid !== pid)
|
|
25847
|
-
return;
|
|
25848
|
-
try {
|
|
25849
|
-
unlinkSync7(path);
|
|
25850
|
-
} catch {
|
|
25851
|
-
}
|
|
25852
|
-
}
|
|
25853
|
-
function releaseScanLock(deps = {}) {
|
|
25854
|
-
releaseLockFile(scanLockPath(deps.home), deps.pid ?? process.pid);
|
|
25855
|
-
}
|
|
25856
|
-
function sleepSync(ms) {
|
|
25857
|
-
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
25858
|
-
}
|
|
25859
|
-
function scanUnderLock(key, deps = {}, waitMs = 0) {
|
|
25860
|
-
const clock = deps.clock ?? Date.now;
|
|
25861
|
-
const giveUpAt = clock() + waitMs;
|
|
25862
|
-
while (!tryTakeScanLock(deps)) {
|
|
25863
|
-
if (clock() >= giveUpAt)
|
|
25864
|
-
return null;
|
|
25865
|
-
sleepSync(SCAN_LOCK_POLL_MS);
|
|
25866
|
-
}
|
|
25867
|
-
try {
|
|
25868
|
-
return scanRecords(key, deps);
|
|
25869
|
-
} finally {
|
|
25870
|
-
releaseScanLock(deps);
|
|
25871
|
-
}
|
|
25872
|
-
}
|
|
25873
|
-
var spawnDetachedReal = (command, args2) => {
|
|
25874
|
-
const child = spawn(command, [...args2], { detached: true, stdio: "ignore", windowsHide: true });
|
|
25875
|
-
child.on("error", () => void 0);
|
|
25876
|
-
child.unref();
|
|
25877
|
-
return child.pid;
|
|
25878
|
-
};
|
|
25879
|
-
function startScanChild(key, binaryPath, deps = {}) {
|
|
25880
|
-
if (!tryTakeScanLock(deps))
|
|
25881
|
-
return false;
|
|
25882
|
-
let childPid;
|
|
25883
|
-
try {
|
|
25884
|
-
childPid = (deps.spawnDetached ?? spawnDetachedReal)(deps.nodePath ?? process.execPath, [
|
|
25885
|
-
binaryPath,
|
|
25886
|
-
"pace",
|
|
25887
|
-
"--scan",
|
|
25888
|
-
"--config-folder",
|
|
25889
|
-
key,
|
|
25890
|
-
"--lock-held"
|
|
25891
|
-
]);
|
|
25892
|
-
} catch {
|
|
25893
|
-
childPid = void 0;
|
|
25894
|
-
}
|
|
25895
|
-
if (childPid === void 0) {
|
|
25896
|
-
releaseScanLock(deps);
|
|
25897
|
-
return false;
|
|
25898
|
-
}
|
|
25899
|
-
try {
|
|
25900
|
-
writeLock(scanLockPath(deps.home), childPid, deps, "w");
|
|
25901
|
-
} catch {
|
|
25902
|
-
releaseScanLock(deps);
|
|
25903
|
-
return false;
|
|
25904
|
-
}
|
|
25905
|
-
return true;
|
|
25906
|
-
}
|
|
25907
|
-
|
|
25908
|
-
// dist/pace-verb.js
|
|
25909
26620
|
var PACE_DEFAULT_TASK_MINUTES = 30;
|
|
25910
26621
|
var PACE_DURATION_ROUND_MINUTES = 10;
|
|
25911
26622
|
var PACE_WINDOW_MINUTES = 300;
|
|
@@ -26027,7 +26738,7 @@ function suggestPace(input) {
|
|
|
26027
26738
|
function enginePacingDir(engagementId, home) {
|
|
26028
26739
|
if (!isEngagementId(engagementId))
|
|
26029
26740
|
return null;
|
|
26030
|
-
return nodePath4.join(home ??
|
|
26741
|
+
return nodePath4.join(home ?? homedir9(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, PACING_DIR_NAME);
|
|
26031
26742
|
}
|
|
26032
26743
|
function readBuildNumber(engagementId, home) {
|
|
26033
26744
|
const dir = enginePacingDir(engagementId, home);
|
|
@@ -26085,7 +26796,7 @@ var USAGE = "Usage: halfcycle-runner pace [--agent claude-code|codex] [--start <
|
|
|
26085
26796
|
function parsePaceArgs(args2) {
|
|
26086
26797
|
let scan = false;
|
|
26087
26798
|
let lockHeld = false;
|
|
26088
|
-
let
|
|
26799
|
+
let folder2 = null;
|
|
26089
26800
|
let phase = null;
|
|
26090
26801
|
let agents = null;
|
|
26091
26802
|
let agent = null;
|
|
@@ -26103,8 +26814,8 @@ function parsePaceArgs(args2) {
|
|
|
26103
26814
|
else if (a === "--lock-held")
|
|
26104
26815
|
lockHeld = true;
|
|
26105
26816
|
else if (a === "--config-folder") {
|
|
26106
|
-
|
|
26107
|
-
if (
|
|
26817
|
+
folder2 = value();
|
|
26818
|
+
if (folder2 === null)
|
|
26108
26819
|
return { kind: "usage", message: USAGE };
|
|
26109
26820
|
} else if (a === "--start") {
|
|
26110
26821
|
phase = value();
|
|
@@ -26125,9 +26836,9 @@ function parsePaceArgs(args2) {
|
|
|
26125
26836
|
if (scan) {
|
|
26126
26837
|
if (phase !== null || agents !== null || agent !== null)
|
|
26127
26838
|
return { kind: "usage", message: USAGE };
|
|
26128
|
-
return { kind: "scan", folder, lockHeld };
|
|
26839
|
+
return { kind: "scan", folder: folder2, lockHeld };
|
|
26129
26840
|
}
|
|
26130
|
-
if (
|
|
26841
|
+
if (folder2 !== null || lockHeld)
|
|
26131
26842
|
return { kind: "usage", message: USAGE };
|
|
26132
26843
|
if (phase === null)
|
|
26133
26844
|
return agents === null ? { kind: "now", agent: agent ?? "claude-code" } : { kind: "usage", message: USAGE };
|
|
@@ -26210,7 +26921,7 @@ async function runPaceVerb(args2, deps = {}) {
|
|
|
26210
26921
|
...deps.home === void 0 ? {} : { home: deps.home },
|
|
26211
26922
|
now: () => now.getTime(),
|
|
26212
26923
|
...deps.fetchFn === void 0 ? {} : { fetchFn: deps.fetchFn }
|
|
26213
|
-
});
|
|
26924
|
+
}, { agent: parsed.agent });
|
|
26214
26925
|
} catch {
|
|
26215
26926
|
}
|
|
26216
26927
|
const remembered = readPaceStateFile(pacingDir2).basis;
|
|
@@ -26298,6 +27009,7 @@ async function runPaceVerb(args2, deps = {}) {
|
|
|
26298
27009
|
...decision.until !== null ? { until: decision.until.toISOString() } : {},
|
|
26299
27010
|
keepFreePercent,
|
|
26300
27011
|
...suggestion !== void 0 ? { suggestion } : {},
|
|
27012
|
+
...limitFile !== null ? { usage: { used: readPhaseUsage(pacingDir2, limitFile.phase), limit: limitFile.limit } } : {},
|
|
26301
27013
|
...atLimit ? {
|
|
26302
27014
|
limit: "reached",
|
|
26303
27015
|
limitHeld: {
|
|
@@ -26445,10 +27157,10 @@ async function paceAtTurnEnd(input, reply, deps = {}) {
|
|
|
26445
27157
|
const basis = read !== null ? { phase: read.phase, keepFreePercent: read.keepFreePercent } : stored.basis;
|
|
26446
27158
|
if (basis === null)
|
|
26447
27159
|
return;
|
|
26448
|
-
const
|
|
27160
|
+
const write2 = deps.writeState ?? writePaceState;
|
|
26449
27161
|
if (basis.phase === null) {
|
|
26450
27162
|
if (before !== null || read !== null)
|
|
26451
|
-
|
|
27163
|
+
write2(dir, key, null, read !== null ? basis : null);
|
|
26452
27164
|
return;
|
|
26453
27165
|
}
|
|
26454
27166
|
const working = liveCount(readLiveness(field2(input, "session_id"), field2(input, "cwd") ?? process.cwd(), deps.liveness));
|
|
@@ -26475,7 +27187,8 @@ async function paceAtTurnEnd(input, reply, deps = {}) {
|
|
|
26475
27187
|
}
|
|
26476
27188
|
}
|
|
26477
27189
|
const reported = readReportedAccount(key, { home: deps.home });
|
|
26478
|
-
const
|
|
27190
|
+
const build = buildNumberFor(engagementId, basis.phase, deps.home);
|
|
27191
|
+
const number4 = build?.number ?? CAREFUL_START_AGENTS;
|
|
26479
27192
|
const decision = paceOf({ number: number4, keepFreePercent: basis.keepFreePercent, learned, reported, now });
|
|
26480
27193
|
const settled2 = {
|
|
26481
27194
|
pace: decision.pace,
|
|
@@ -26489,9 +27202,9 @@ async function paceAtTurnEnd(input, reply, deps = {}) {
|
|
|
26489
27202
|
};
|
|
26490
27203
|
const told = before === null || before.told === void 0 ? before : { ...before, ...before.told };
|
|
26491
27204
|
const text = paceChangeText(told, settled2, working, now, basis.keepFreePercent);
|
|
26492
|
-
const offer = text === null ? offerText(settled2, learned, reported, now, basis.keepFreePercent) : null;
|
|
27205
|
+
const offer = text === null && build !== null ? offerText(settled2, learned, reported, now, basis.keepFreePercent) : null;
|
|
26493
27206
|
const after = offer === null ? settled2 : { ...settled2, offeredFor: offeredForNow(settled2.offeredFor, offer.resetsAt, now) };
|
|
26494
|
-
|
|
27207
|
+
write2(dir, key, after, read !== null ? basis : null);
|
|
26495
27208
|
if (text !== null)
|
|
26496
27209
|
reply.notice(text);
|
|
26497
27210
|
else if (offer !== null)
|
|
@@ -26542,7 +27255,7 @@ function pruneStarts(file2, nowMs) {
|
|
|
26542
27255
|
}
|
|
26543
27256
|
return out;
|
|
26544
27257
|
}
|
|
26545
|
-
function
|
|
27258
|
+
function sleepSync3(ms) {
|
|
26546
27259
|
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
26547
27260
|
}
|
|
26548
27261
|
function underStartsLock(dir, giveUpMs, fn) {
|
|
@@ -26551,7 +27264,7 @@ function underStartsLock(dir, giveUpMs, fn) {
|
|
|
26551
27264
|
while (!tryTakeLockFile(lock, PACE_STARTS_LOCK_STALE_MS)) {
|
|
26552
27265
|
if (Date.now() >= giveUpAt)
|
|
26553
27266
|
return void 0;
|
|
26554
|
-
|
|
27267
|
+
sleepSync3(STARTS_LOCK_POLL_MS);
|
|
26555
27268
|
}
|
|
26556
27269
|
try {
|
|
26557
27270
|
return fn();
|
|
@@ -26646,9 +27359,9 @@ function paceHoldText(input, toolInput, deps = {}) {
|
|
|
26646
27359
|
}
|
|
26647
27360
|
|
|
26648
27361
|
// dist/risky/facts.js
|
|
26649
|
-
import { existsSync as
|
|
26650
|
-
import { homedir as
|
|
26651
|
-
import { basename as pathBasename, dirname as dirname6, isAbsolute as isAbsolute4, join as
|
|
27362
|
+
import { existsSync as existsSync8, lstatSync as lstatSync3, readdirSync as readdirSync9, readFileSync as readFileSync21, realpathSync as realpathSync7, statSync as statSync7 } from "node:fs";
|
|
27363
|
+
import { homedir as homedir10, tmpdir as tmpdir2 } from "node:os";
|
|
27364
|
+
import { basename as pathBasename, dirname as dirname6, isAbsolute as isAbsolute4, join as join15, relative as relative7, resolve as resolve6, sep as sep5 } from "node:path";
|
|
26652
27365
|
|
|
26653
27366
|
// dist/risky/shell.js
|
|
26654
27367
|
var MAX_DEPTH = 8;
|
|
@@ -27828,7 +28541,7 @@ function readLine(commands, vars, gitEnv, savedTrusted) {
|
|
|
27828
28541
|
}
|
|
27829
28542
|
vars.enter(own);
|
|
27830
28543
|
const simple = expandCommand(raw, vars);
|
|
27831
|
-
const
|
|
28544
|
+
const folder2 = folderIn(simple);
|
|
27832
28545
|
for (const m of recogniseSimple(simple)) {
|
|
27833
28546
|
const trusted = m.type === "shrink-record" && m.change.kind === "saved" && !savedTrusted ? { ...m, change: { kind: "emptied" } } : m;
|
|
27834
28547
|
let shown2 = trusted;
|
|
@@ -27844,7 +28557,7 @@ function readLine(commands, vars, gitEnv, savedTrusted) {
|
|
|
27844
28557
|
}
|
|
27845
28558
|
matches.push({
|
|
27846
28559
|
...shown2,
|
|
27847
|
-
...
|
|
28560
|
+
...folder2 === void 0 ? {} : { folder: folder2 },
|
|
27848
28561
|
...made.size === 0 ? {} : { made: new Map(made) },
|
|
27849
28562
|
...madeInChain.size === 0 ? {} : { madeInChain: new Set(madeInChain) },
|
|
27850
28563
|
...removedInChain.size === 0 ? {} : { removedInChain: new Set(removedInChain) },
|
|
@@ -27852,9 +28565,9 @@ function readLine(commands, vars, gitEnv, savedTrusted) {
|
|
|
27852
28565
|
...vars.stoppedIf.length === 0 ? {} : { stoppedIf: [...vars.stoppedIf] }
|
|
27853
28566
|
});
|
|
27854
28567
|
}
|
|
27855
|
-
if (surelyRuns(simple, own) && (
|
|
28568
|
+
if (surelyRuns(simple, own) && (folder2 === void 0 || folder2.known)) {
|
|
27856
28569
|
for (const p of pathsMade(simple)) {
|
|
27857
|
-
const key = madeKey(
|
|
28570
|
+
const key = madeKey(folder2?.dirs ?? [], p.word);
|
|
27858
28571
|
made.set(key, p.by);
|
|
27859
28572
|
if (simple.next === "&&")
|
|
27860
28573
|
madeInChain.add(key);
|
|
@@ -27862,12 +28575,12 @@ function readLine(commands, vars, gitEnv, savedTrusted) {
|
|
|
27862
28575
|
if (simple.next === "&&" && simple.words[0]?.text === "rmdir") {
|
|
27863
28576
|
for (const w of simple.words.slice(1))
|
|
27864
28577
|
if (w.literal && !w.text.startsWith("-"))
|
|
27865
|
-
removedInChain.add(madeKey(
|
|
28578
|
+
removedInChain.add(madeKey(folder2?.dirs ?? [], w));
|
|
27866
28579
|
}
|
|
27867
28580
|
}
|
|
27868
28581
|
const nextCmd = commands[i + 1];
|
|
27869
28582
|
const asJoined = simple.next !== void 0 && (nextCmd === void 0 || scopeKey(nextCmd) !== scopeKey(simple)) ? { ...simple, next: void 0 } : simple;
|
|
27870
|
-
const after = folderAfter(
|
|
28583
|
+
const after = folderAfter(folder2, asJoined, own);
|
|
27871
28584
|
folders.set(scopeKey(simple), after);
|
|
27872
28585
|
vars.guard = chainCds === null ? null : [...chainCds];
|
|
27873
28586
|
vars.update(raw, own);
|
|
@@ -28860,7 +29573,7 @@ var Env = class {
|
|
|
28860
29573
|
constructor(ctx) {
|
|
28861
29574
|
this.projectDir = realOrSelf(resolve6(ctx.projectDir));
|
|
28862
29575
|
this.cwd = realOrSelf(resolve6(this.projectDir, ctx.cwd));
|
|
28863
|
-
this.home = realOrSelf(resolve6(ctx.home ??
|
|
29576
|
+
this.home = realOrSelf(resolve6(ctx.home ?? homedir10()));
|
|
28864
29577
|
this.timeoutMs = ctx.gitTimeoutMs ?? FACTS_GIT_TIMEOUT_MS;
|
|
28865
29578
|
this.tempDir = realOrSelf(resolve6(ctx.tempDir ?? tmpdir2()));
|
|
28866
29579
|
const roots = ctx.tempRoots ?? [this.tempDir, tmpdir2(), ...TEMP_ROOTS];
|
|
@@ -28884,7 +29597,7 @@ var Env = class {
|
|
|
28884
29597
|
return this.description;
|
|
28885
29598
|
this.description = null;
|
|
28886
29599
|
try {
|
|
28887
|
-
const raw = JSON.parse(readFileSync21(
|
|
29600
|
+
const raw = JSON.parse(readFileSync21(join15(repoRoot, SYSTEM_DESCRIPTION_REL), "utf-8"));
|
|
28888
29601
|
const checked = checkSystemDescription(raw);
|
|
28889
29602
|
if (checked.ok)
|
|
28890
29603
|
this.description = checked.description;
|
|
@@ -28948,18 +29661,18 @@ function resolveHome(text, home, base) {
|
|
|
28948
29661
|
if (text === "~")
|
|
28949
29662
|
return home;
|
|
28950
29663
|
if (text.startsWith("~/"))
|
|
28951
|
-
return
|
|
29664
|
+
return join15(home, text.slice(2));
|
|
28952
29665
|
return resolve6(base, text);
|
|
28953
29666
|
}
|
|
28954
29667
|
function realTarget(abs) {
|
|
28955
29668
|
const parent = dirname6(abs);
|
|
28956
29669
|
if (parent === abs)
|
|
28957
29670
|
return abs;
|
|
28958
|
-
return
|
|
29671
|
+
return join15(realOrSelf(parent), pathBasename(abs));
|
|
28959
29672
|
}
|
|
28960
29673
|
function wordPath(word, base, env) {
|
|
28961
29674
|
if (word.temp !== void 0) {
|
|
28962
|
-
const root = word.temp.base === "mktemp" ?
|
|
29675
|
+
const root = word.temp.base === "mktemp" ? join15(env.tempDir, ".halfcycle-mktemp-new") : env.tempDir;
|
|
28963
29676
|
return resolve6(`${root}${word.temp.suffix}`);
|
|
28964
29677
|
}
|
|
28965
29678
|
return word.literal ? resolveHome(word.text, env.home, base) : null;
|
|
@@ -29105,7 +29818,7 @@ function globPath(abs) {
|
|
|
29105
29818
|
const next = [];
|
|
29106
29819
|
if (!/[*?[]/.test(segment)) {
|
|
29107
29820
|
for (const c of current)
|
|
29108
|
-
next.push(
|
|
29821
|
+
next.push(join15(c, segment));
|
|
29109
29822
|
} else {
|
|
29110
29823
|
const re = segmentPattern(segment);
|
|
29111
29824
|
for (const c of current) {
|
|
@@ -29119,7 +29832,7 @@ function globPath(abs) {
|
|
|
29119
29832
|
if (n.startsWith(".") && !segment.startsWith("."))
|
|
29120
29833
|
continue;
|
|
29121
29834
|
if (re.test(n))
|
|
29122
|
-
next.push(
|
|
29835
|
+
next.push(join15(c, n));
|
|
29123
29836
|
}
|
|
29124
29837
|
}
|
|
29125
29838
|
}
|
|
@@ -29247,7 +29960,7 @@ function findKeeps(filter, roots, repoRoot) {
|
|
|
29247
29960
|
const names = filter.names.map((n) => findPattern(n.pattern, n.fold, false));
|
|
29248
29961
|
const excluded = filter.excluded.map((p) => findPattern(p, false, true));
|
|
29249
29962
|
const steps = (rel) => {
|
|
29250
|
-
const abs =
|
|
29963
|
+
const abs = join15(repoRoot, rel);
|
|
29251
29964
|
const out = [];
|
|
29252
29965
|
for (const r of roots) {
|
|
29253
29966
|
if (!isInside(abs, r.abs))
|
|
@@ -29304,11 +30017,11 @@ function walkRoots(ignoredFolders, specs) {
|
|
|
29304
30017
|
const under2 = (child, parent) => parent === "." || child === parent || child.startsWith(`${parent}/`);
|
|
29305
30018
|
const roots = /* @__PURE__ */ new Set();
|
|
29306
30019
|
for (const raw of ignoredFolders) {
|
|
29307
|
-
const
|
|
30020
|
+
const folder2 = raw.replace(/\/+$/, "");
|
|
29308
30021
|
for (const spec of specs) {
|
|
29309
|
-
if (under2(
|
|
29310
|
-
roots.add(
|
|
29311
|
-
else if (under2(spec,
|
|
30022
|
+
if (under2(folder2, spec))
|
|
30023
|
+
roots.add(folder2);
|
|
30024
|
+
else if (under2(spec, folder2))
|
|
29312
30025
|
roots.add(spec);
|
|
29313
30026
|
}
|
|
29314
30027
|
}
|
|
@@ -29319,9 +30032,9 @@ function credentialFilesIn(folders, repoRoot, deadline, skip) {
|
|
|
29319
30032
|
const out = [];
|
|
29320
30033
|
const stack = [];
|
|
29321
30034
|
for (const f of folders) {
|
|
29322
|
-
if (isDirectory(
|
|
30035
|
+
if (isDirectory(join15(repoRoot, f)))
|
|
29323
30036
|
stack.push(f);
|
|
29324
|
-
else if (pathExists(
|
|
30037
|
+
else if (pathExists(join15(repoRoot, f)) && isCredentialPath(f))
|
|
29325
30038
|
out.push(f);
|
|
29326
30039
|
}
|
|
29327
30040
|
let seen = 0;
|
|
@@ -29329,7 +30042,7 @@ function credentialFilesIn(folders, repoRoot, deadline, skip) {
|
|
|
29329
30042
|
const rel = stack.pop();
|
|
29330
30043
|
let entries;
|
|
29331
30044
|
try {
|
|
29332
|
-
entries = readdirSync9(
|
|
30045
|
+
entries = readdirSync9(join15(repoRoot, rel), { withFileTypes: true });
|
|
29333
30046
|
} catch {
|
|
29334
30047
|
continue;
|
|
29335
30048
|
}
|
|
@@ -29487,7 +30200,7 @@ function closeFoldsAll(targets, env) {
|
|
|
29487
30200
|
return false;
|
|
29488
30201
|
let at = root;
|
|
29489
30202
|
for (const seg of rel.split("/")) {
|
|
29490
|
-
at =
|
|
30203
|
+
at = join15(at, seg);
|
|
29491
30204
|
try {
|
|
29492
30205
|
if (lstatSync3(at).isSymbolicLink())
|
|
29493
30206
|
return false;
|
|
@@ -29720,7 +30433,7 @@ function worktreeFiles(m, where, env) {
|
|
|
29720
30433
|
if (path === null)
|
|
29721
30434
|
return null;
|
|
29722
30435
|
const abs = realOrSelf(path);
|
|
29723
|
-
if (!
|
|
30436
|
+
if (!existsSync8(abs))
|
|
29724
30437
|
return [];
|
|
29725
30438
|
const top = env.repoRoot(abs);
|
|
29726
30439
|
if (top === null)
|
|
@@ -30070,7 +30783,7 @@ function publishFacts(m, env) {
|
|
|
30070
30783
|
const start = startFolder(m, env);
|
|
30071
30784
|
if (start !== null && PACKAGE_JSON_PROGRAMS.has(m.program)) {
|
|
30072
30785
|
try {
|
|
30073
|
-
const pkg = JSON.parse(readFileSync21(
|
|
30786
|
+
const pkg = JSON.parse(readFileSync21(join15(start, "package.json"), "utf-8"));
|
|
30074
30787
|
if (typeof pkg["name"] === "string" && typeof pkg["version"] === "string" && pkg["name"] !== "" && pkg["version"] !== "") {
|
|
30075
30788
|
name = pkg["name"];
|
|
30076
30789
|
version2 = pkg["version"];
|
|
@@ -30189,17 +30902,17 @@ function recordFileAt(abs, env) {
|
|
|
30189
30902
|
const row = recordPatternFor(rel);
|
|
30190
30903
|
return row !== void 0 && row.shrinkAsked !== false ? { abs, root, rel } : null;
|
|
30191
30904
|
}
|
|
30192
|
-
function recordFilesUnder(
|
|
30193
|
-
const root = recordRoot(
|
|
30905
|
+
function recordFilesUnder(folder2, env) {
|
|
30906
|
+
const root = recordRoot(folder2, env);
|
|
30194
30907
|
if (root === null)
|
|
30195
30908
|
return [];
|
|
30196
|
-
const relFolder = toSlash(relative7(root,
|
|
30909
|
+
const relFolder = toSlash(relative7(root, folder2));
|
|
30197
30910
|
const starts = /* @__PURE__ */ new Set();
|
|
30198
30911
|
for (const { pattern } of PROJECT_RECORD_PATTERNS) {
|
|
30199
30912
|
if (relFolder === "" || patternOwns(relFolder, pattern))
|
|
30200
|
-
starts.add(
|
|
30913
|
+
starts.add(join15(root, pattern));
|
|
30201
30914
|
else if (patternOwns(pattern, relFolder))
|
|
30202
|
-
starts.add(
|
|
30915
|
+
starts.add(folder2);
|
|
30203
30916
|
}
|
|
30204
30917
|
const out = [];
|
|
30205
30918
|
const stack = [...starts];
|
|
@@ -30223,7 +30936,7 @@ function recordFilesUnder(folder, env) {
|
|
|
30223
30936
|
continue;
|
|
30224
30937
|
}
|
|
30225
30938
|
for (const n of names)
|
|
30226
|
-
stack.push(
|
|
30939
|
+
stack.push(join15(p, n));
|
|
30227
30940
|
} else if (st.isFile()) {
|
|
30228
30941
|
const r = recordFileAt(p, env);
|
|
30229
30942
|
if (r !== null)
|
|
@@ -30306,7 +31019,11 @@ var PERSON_HOLD_LINE = "Halfcycle paused a risky step before it ran. Nothing cha
|
|
|
30306
31019
|
var HELD_STEP_OPENER = "The step was: ";
|
|
30307
31020
|
var PRECAUTION_OPENER = "It was stopped as a precaution: ";
|
|
30308
31021
|
var ALLOW_REPLY = "allow";
|
|
30309
|
-
|
|
31022
|
+
function holdAgentInstruction(stepNumber) {
|
|
31023
|
+
const reply = stepNumber === null ? ALLOW_REPLY : `${ALLOW_REPLY} ${String(stepNumber)}`;
|
|
31024
|
+
return `If the step is not needed, carry on without it; there is no need to mention it. If it is needed, ask the person in chat, in one plain sentence, whether to run it, and tell them to reply "${reply}" to run it once, or anything else to skip it. Do not try it again until they answer.`;
|
|
31025
|
+
}
|
|
31026
|
+
var HOLD_AGENT_INSTRUCTION = holdAgentInstruction(null);
|
|
30310
31027
|
var NOTHING_LOST_ON_NO = "Nothing is lost if you say no.";
|
|
30311
31028
|
var IF_YES = "If you say yes, ";
|
|
30312
31029
|
var DESCRIBED_TOOLS = /* @__PURE__ */ new Set(["Bash", "Agent"]);
|
|
@@ -30342,6 +31059,9 @@ function questionFor(facts, description) {
|
|
|
30342
31059
|
const shown2 = staked.slice(0, MAX_LISTED).map((f) => `${whatOf(f)} ${IF_YES}${lostOf(f)}`);
|
|
30343
31060
|
return `${PAUSED_OPENER.trimEnd().slice(0, -1)}. ${shown2.join(" ")}${moreLine(staked.length - shown2.length)} ${reason} ${NOTHING_LOST_ON_NO}`;
|
|
30344
31061
|
}
|
|
31062
|
+
function heldAgentText(held, stepNumber) {
|
|
31063
|
+
return `${held.facts} ${holdAgentInstruction(stepNumber)}`;
|
|
31064
|
+
}
|
|
30345
31065
|
function refusalFor(facts, description) {
|
|
30346
31066
|
const staked = orderedStaked(facts);
|
|
30347
31067
|
if (staked.length === 0)
|
|
@@ -30352,9 +31072,11 @@ function refusalFor(facts, description) {
|
|
|
30352
31072
|
return heldStep(steps, description, shown2.map(whyOf).join("; "));
|
|
30353
31073
|
}
|
|
30354
31074
|
function heldStep(steps, description, why) {
|
|
31075
|
+
const facts = `${HELD_STEP_OPENER}${steps}. ${reasonSentence(description)} ${PRECAUTION_OPENER}${why}.`;
|
|
30355
31076
|
return {
|
|
30356
31077
|
person: PERSON_HOLD_LINE,
|
|
30357
|
-
agent: `${
|
|
31078
|
+
agent: `${facts} ${HOLD_AGENT_INSTRUCTION}`,
|
|
31079
|
+
facts,
|
|
30358
31080
|
step: steps
|
|
30359
31081
|
};
|
|
30360
31082
|
}
|
|
@@ -30769,14 +31491,85 @@ function isOneCall(call) {
|
|
|
30769
31491
|
|
|
30770
31492
|
// dist/risky/allow-once.js
|
|
30771
31493
|
import { createHash as createHash5 } from "node:crypto";
|
|
30772
|
-
import { appendFileSync as
|
|
31494
|
+
import { appendFileSync as appendFileSync5, readFileSync as readFileSync22, realpathSync as realpathSync8, renameSync as renameSync11, statSync as statSync8, unlinkSync as unlinkSync9, writeFileSync as writeFileSync13 } from "node:fs";
|
|
31495
|
+
import { isAbsolute as isAbsolute5, relative as relative8, resolve as resolve7, sep as sep6 } from "node:path";
|
|
30773
31496
|
var ALLOW_ONCE_MS = 5 * 60 * 1e3;
|
|
30774
31497
|
var HELD_STEP_MAX_AGE_MS = 60 * 60 * 1e3;
|
|
31498
|
+
var NUMBERS_WAIT_MS = 50;
|
|
31499
|
+
var NUMBERS_LOCK_STALE_MS = 5e3;
|
|
31500
|
+
var NUMBERS_LOCK_POLL_MS = 2;
|
|
31501
|
+
var COPY_GIT_TIMEOUT_MS = 3e3;
|
|
31502
|
+
var ALLOW_NUMBER = new RegExp(`^${ALLOW_REPLY}(?: +([0-9]{1,4}))?$`);
|
|
30775
31503
|
var STEP_MAX_LENGTH = 1e3;
|
|
30776
|
-
function
|
|
30777
|
-
|
|
31504
|
+
function allowReplyOf(prompt) {
|
|
31505
|
+
if (typeof prompt !== "string")
|
|
31506
|
+
return null;
|
|
31507
|
+
const m = ALLOW_NUMBER.exec(prompt.trim().toLowerCase());
|
|
31508
|
+
if (m === null)
|
|
31509
|
+
return null;
|
|
31510
|
+
return { number: m[1] === void 0 ? null : Number(m[1]) };
|
|
31511
|
+
}
|
|
31512
|
+
var FOLDER_WORD = String.raw`(?:([^\s'"$\x60\\~*?\[{()<>|&;\-][^\s'"$\x60\\~*?\[{()<>|&;]*)|'([^'"$\x60\\\-][^'"$\x60\\]*)'|"([^'"$\x60\\\-][^'"$\x60\\]*)")`;
|
|
31513
|
+
var CD_PREFIX = new RegExp(String.raw`^\s*cd[ \t]+${FOLDER_WORD}[ \t]*(?:&&|;)`);
|
|
31514
|
+
var GIT_C_PREFIX = new RegExp(String.raw`^\s*git[ \t]+-C[ \t]+${FOLDER_WORD}[ \t]+`);
|
|
31515
|
+
function folderPrefixOf(command) {
|
|
31516
|
+
const cd = CD_PREFIX.exec(command);
|
|
31517
|
+
if (cd !== null) {
|
|
31518
|
+
const rest = command.slice(cd[0].length).replace(/^\s+/, "");
|
|
31519
|
+
const commands = commandsOf(rest);
|
|
31520
|
+
if (commands === null || commands.some((c) => FOLDER_CHANGERS.has(c.words[0]?.text ?? "")))
|
|
31521
|
+
return null;
|
|
31522
|
+
return { folder: folderOf(cd), command: rest };
|
|
31523
|
+
}
|
|
31524
|
+
const gitC = GIT_C_PREFIX.exec(command);
|
|
31525
|
+
if (gitC !== null) {
|
|
31526
|
+
const compared = `git ${command.slice(gitC[0].length)}`;
|
|
31527
|
+
const commands = commandsOf(compared);
|
|
31528
|
+
if (commands === null || commands.filter((c) => c.scope === void 0).length !== 1)
|
|
31529
|
+
return null;
|
|
31530
|
+
return { folder: folderOf(gitC), command: compared };
|
|
31531
|
+
}
|
|
31532
|
+
return null;
|
|
31533
|
+
}
|
|
31534
|
+
function commandsOf(text) {
|
|
31535
|
+
try {
|
|
31536
|
+
return splitCommand(text);
|
|
31537
|
+
} catch {
|
|
31538
|
+
return null;
|
|
31539
|
+
}
|
|
30778
31540
|
}
|
|
30779
|
-
function
|
|
31541
|
+
function folderOf(m) {
|
|
31542
|
+
return m[1] ?? m[2] ?? m[3] ?? "";
|
|
31543
|
+
}
|
|
31544
|
+
function actingFolderOf(toolName, cwd, rest) {
|
|
31545
|
+
const command = rest["command"];
|
|
31546
|
+
if (toolName !== "Bash" || typeof command !== "string")
|
|
31547
|
+
return cwd;
|
|
31548
|
+
const prefix = folderPrefixOf(command);
|
|
31549
|
+
if (prefix === null)
|
|
31550
|
+
return cwd;
|
|
31551
|
+
if (!isAbsolute5(prefix.folder) && !isAbsolute5(cwd))
|
|
31552
|
+
return cwd;
|
|
31553
|
+
const named = isAbsolute5(prefix.folder) ? prefix.folder : resolve7(cwd, prefix.folder);
|
|
31554
|
+
if (!isFolder2(named))
|
|
31555
|
+
return cwd;
|
|
31556
|
+
rest["command"] = prefix.command;
|
|
31557
|
+
return named;
|
|
31558
|
+
}
|
|
31559
|
+
function copyOf(folder2, timeoutMs) {
|
|
31560
|
+
if (folder2 === "")
|
|
31561
|
+
return { top: "", within: "" };
|
|
31562
|
+
const real = realOrSelf2(folder2);
|
|
31563
|
+
let top = real;
|
|
31564
|
+
if (isFolder2(real)) {
|
|
31565
|
+
const r = readGitForFacts(["rev-parse", "--show-toplevel"], real, timeoutMs);
|
|
31566
|
+
if (r.ok && r.value.trim() !== "")
|
|
31567
|
+
top = realOrSelf2(r.value.trim());
|
|
31568
|
+
}
|
|
31569
|
+
const within2 = relative8(top, real).split(sep6).join("/");
|
|
31570
|
+
return { top, within: within2 };
|
|
31571
|
+
}
|
|
31572
|
+
function stepKey(input, staked, deps = {}) {
|
|
30780
31573
|
const toolName = input["tool_name"];
|
|
30781
31574
|
const toolInput = input["tool_input"];
|
|
30782
31575
|
if (typeof toolName !== "string" || toolName === "")
|
|
@@ -30787,7 +31580,17 @@ function stepKey(input, staked) {
|
|
|
30787
31580
|
if (DESCRIBED_TOOLS.has(toolName))
|
|
30788
31581
|
delete rest["description"];
|
|
30789
31582
|
const cwd = typeof input["cwd"] === "string" ? input["cwd"] : "";
|
|
30790
|
-
|
|
31583
|
+
const acting = actingFolderOf(toolName, cwd, rest);
|
|
31584
|
+
const { top, within: within2 } = copyOf(acting, deps.gitTimeoutMs ?? COPY_GIT_TIMEOUT_MS);
|
|
31585
|
+
const facts = staked.map(withoutMatch);
|
|
31586
|
+
return createHash5("sha256").update(canonical([toolName, top, within2, rest, facts])).digest("hex");
|
|
31587
|
+
}
|
|
31588
|
+
function withoutMatch(fact) {
|
|
31589
|
+
if (typeof fact !== "object" || fact === null || Array.isArray(fact))
|
|
31590
|
+
return fact;
|
|
31591
|
+
const { match: _match, ...others } = fact;
|
|
31592
|
+
void _match;
|
|
31593
|
+
return others;
|
|
30791
31594
|
}
|
|
30792
31595
|
function canonical(value) {
|
|
30793
31596
|
if (Array.isArray(value))
|
|
@@ -30798,37 +31601,166 @@ function canonical(value) {
|
|
|
30798
31601
|
}
|
|
30799
31602
|
return JSON.stringify(value) ?? "null";
|
|
30800
31603
|
}
|
|
30801
|
-
function
|
|
31604
|
+
function isFolder2(path) {
|
|
31605
|
+
try {
|
|
31606
|
+
return statSync8(path).isDirectory();
|
|
31607
|
+
} catch {
|
|
31608
|
+
return false;
|
|
31609
|
+
}
|
|
31610
|
+
}
|
|
31611
|
+
function realOrSelf2(path) {
|
|
31612
|
+
try {
|
|
31613
|
+
return realpathSync8(path);
|
|
31614
|
+
} catch {
|
|
31615
|
+
return path;
|
|
31616
|
+
}
|
|
31617
|
+
}
|
|
31618
|
+
function numberStep(sessionId, key, deps = {}) {
|
|
31619
|
+
const paths = allowOncePaths(sessionId, deps.dir);
|
|
31620
|
+
if (paths === null)
|
|
31621
|
+
return null;
|
|
31622
|
+
const lock = `${paths.numbers}${STEP_NUMBERS_LOCK_SUFFIX}`;
|
|
31623
|
+
const giveUpAt = Date.now() + NUMBERS_WAIT_MS;
|
|
31624
|
+
while (!tryTakeLockFile(lock, NUMBERS_LOCK_STALE_MS)) {
|
|
31625
|
+
if (Date.now() >= giveUpAt)
|
|
31626
|
+
return null;
|
|
31627
|
+
sleepSync4(NUMBERS_LOCK_POLL_MS);
|
|
31628
|
+
}
|
|
31629
|
+
try {
|
|
31630
|
+
const numbers = readNumbers(paths.numbers);
|
|
31631
|
+
if (numbers === null)
|
|
31632
|
+
return null;
|
|
31633
|
+
const kept = numbers.steps.get(key);
|
|
31634
|
+
if (kept !== void 0)
|
|
31635
|
+
return kept;
|
|
31636
|
+
const n = numbers.next;
|
|
31637
|
+
const steps = new Map(numbers.steps).set(key, n);
|
|
31638
|
+
return writeNumbers(paths.numbers, { next: n + 1, steps }) ? n : null;
|
|
31639
|
+
} catch {
|
|
31640
|
+
return null;
|
|
31641
|
+
} finally {
|
|
31642
|
+
releaseLockFile(lock);
|
|
31643
|
+
}
|
|
31644
|
+
}
|
|
31645
|
+
function numberKept(path, key) {
|
|
31646
|
+
try {
|
|
31647
|
+
return readNumbers(path)?.steps.get(key) ?? null;
|
|
31648
|
+
} catch {
|
|
31649
|
+
return null;
|
|
31650
|
+
}
|
|
31651
|
+
}
|
|
31652
|
+
function readNumbers(path) {
|
|
31653
|
+
let text;
|
|
31654
|
+
try {
|
|
31655
|
+
text = readFileSync22(path, "utf8");
|
|
31656
|
+
} catch (err) {
|
|
31657
|
+
return err.code === "ENOENT" ? { next: 1, steps: /* @__PURE__ */ new Map() } : null;
|
|
31658
|
+
}
|
|
31659
|
+
let parsed;
|
|
31660
|
+
try {
|
|
31661
|
+
parsed = JSON.parse(text);
|
|
31662
|
+
} catch {
|
|
31663
|
+
return null;
|
|
31664
|
+
}
|
|
31665
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
31666
|
+
return null;
|
|
31667
|
+
const o = parsed;
|
|
31668
|
+
const next = o["next"];
|
|
31669
|
+
const steps = o["steps"];
|
|
31670
|
+
if (!isWholeNumber2(next) || typeof steps !== "object" || steps === null || Array.isArray(steps))
|
|
31671
|
+
return null;
|
|
31672
|
+
const out = /* @__PURE__ */ new Map();
|
|
31673
|
+
for (const [k, v] of Object.entries(steps)) {
|
|
31674
|
+
if (!/^[0-9a-f]{64}$/.test(k) || !isWholeNumber2(v) || v >= next)
|
|
31675
|
+
return null;
|
|
31676
|
+
out.set(k, v);
|
|
31677
|
+
}
|
|
31678
|
+
return { next, steps: out };
|
|
31679
|
+
}
|
|
31680
|
+
function writeNumbers(path, numbers) {
|
|
31681
|
+
const body = JSON.stringify({ next: numbers.next, steps: Object.fromEntries(numbers.steps) });
|
|
31682
|
+
return writeWhole2(path, body);
|
|
31683
|
+
}
|
|
31684
|
+
function isWholeNumber2(v) {
|
|
31685
|
+
return typeof v === "number" && Number.isSafeInteger(v) && v >= 1;
|
|
31686
|
+
}
|
|
31687
|
+
function sleepSync4(ms) {
|
|
31688
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
31689
|
+
}
|
|
31690
|
+
function recordHeld(sessionId, key, deps = {}, step = null, stepNumber = null) {
|
|
30802
31691
|
const paths = allowOncePaths(sessionId, deps.dir);
|
|
30803
31692
|
if (paths === null)
|
|
30804
31693
|
return;
|
|
30805
|
-
const record2 = {
|
|
31694
|
+
const record2 = {
|
|
31695
|
+
version: 1,
|
|
31696
|
+
session: sessionId,
|
|
31697
|
+
key,
|
|
31698
|
+
at: nowOf(deps),
|
|
31699
|
+
...isStep(step) ? { step } : {},
|
|
31700
|
+
...isWholeNumber2(stepNumber) ? { number: stepNumber } : {}
|
|
31701
|
+
};
|
|
30806
31702
|
try {
|
|
30807
|
-
|
|
31703
|
+
appendFileSync5(paths.held, `${JSON.stringify(record2)}
|
|
30808
31704
|
`, { mode: 384 });
|
|
30809
31705
|
} catch {
|
|
30810
31706
|
return;
|
|
30811
31707
|
}
|
|
30812
31708
|
}
|
|
30813
|
-
function armAllowStep(sessionId, deps = {}) {
|
|
31709
|
+
function armAllowStep(sessionId, deps = {}, stepNumber = null) {
|
|
31710
|
+
const none = (outcome) => ({ outcome, step: null, paused: [] });
|
|
30814
31711
|
try {
|
|
30815
31712
|
const paths = allowOncePaths(sessionId, deps.dir);
|
|
30816
31713
|
if (paths === null)
|
|
30817
|
-
return
|
|
31714
|
+
return none(stepNumber === null ? "nothing-held" : "not-paused");
|
|
31715
|
+
const session = sessionId;
|
|
30818
31716
|
const now = nowOf(deps);
|
|
30819
|
-
const held = claimHeld(paths.held,
|
|
30820
|
-
const
|
|
30821
|
-
|
|
30822
|
-
|
|
30823
|
-
|
|
30824
|
-
|
|
30825
|
-
|
|
30826
|
-
|
|
30827
|
-
|
|
31717
|
+
const held = claimHeld(paths.held, session, now);
|
|
31718
|
+
const steps = distinctSteps(held, paths.numbers);
|
|
31719
|
+
const arm = (key, step) => {
|
|
31720
|
+
const saved = writeRecord(paths.allow, { version: 1, session, key, at: now });
|
|
31721
|
+
if (!saved) {
|
|
31722
|
+
writeBack(paths.held, held);
|
|
31723
|
+
return none("not-saved");
|
|
31724
|
+
}
|
|
31725
|
+
writeBack(paths.held, held.filter((r) => r.key !== key));
|
|
31726
|
+
return { outcome: "armed", step, paused: [] };
|
|
31727
|
+
};
|
|
31728
|
+
if (stepNumber !== null) {
|
|
31729
|
+
const named = steps.find((s) => s.number === stepNumber);
|
|
31730
|
+
if (named === void 0) {
|
|
31731
|
+
writeBack(paths.held, held);
|
|
31732
|
+
return none("not-paused");
|
|
31733
|
+
}
|
|
31734
|
+
return arm(named.key, named.step);
|
|
31735
|
+
}
|
|
31736
|
+
if (steps.length === 0)
|
|
31737
|
+
return none("nothing-held");
|
|
31738
|
+
if (steps.length === 1)
|
|
31739
|
+
return arm(steps[0].key, steps[0].step);
|
|
31740
|
+
writeBack(paths.held, held);
|
|
31741
|
+
const paused = steps.map((s) => ({ number: s.number ?? numberStep(session, s.key, deps), step: s.step })).sort((a, b) => (a.number ?? Number.MAX_SAFE_INTEGER) - (b.number ?? Number.MAX_SAFE_INTEGER));
|
|
31742
|
+
return { outcome: "several-held", step: null, paused };
|
|
30828
31743
|
} catch {
|
|
30829
|
-
return
|
|
31744
|
+
return none("not-saved");
|
|
30830
31745
|
}
|
|
30831
31746
|
}
|
|
31747
|
+
function distinctSteps(held, numbersPath) {
|
|
31748
|
+
const order = [];
|
|
31749
|
+
const latest = /* @__PURE__ */ new Map();
|
|
31750
|
+
const numbered = /* @__PURE__ */ new Map();
|
|
31751
|
+
for (const r of held) {
|
|
31752
|
+
if (!latest.has(r.key))
|
|
31753
|
+
order.push(r.key);
|
|
31754
|
+
latest.set(r.key, r);
|
|
31755
|
+
if (r.number !== void 0)
|
|
31756
|
+
numbered.set(r.key, r.number);
|
|
31757
|
+
}
|
|
31758
|
+
return order.map((key) => ({
|
|
31759
|
+
key,
|
|
31760
|
+
number: numbered.get(key) ?? numberKept(numbersPath, key),
|
|
31761
|
+
step: latest.get(key).step ?? null
|
|
31762
|
+
}));
|
|
31763
|
+
}
|
|
30832
31764
|
function claimHeld(path, session, now) {
|
|
30833
31765
|
const claimed = `${path}.${process.pid}.${now}.claim`;
|
|
30834
31766
|
try {
|
|
@@ -30851,6 +31783,16 @@ function claimHeld(path, session, now) {
|
|
|
30851
31783
|
}
|
|
30852
31784
|
return records;
|
|
30853
31785
|
}
|
|
31786
|
+
function writeBack(path, records) {
|
|
31787
|
+
if (records.length === 0)
|
|
31788
|
+
return;
|
|
31789
|
+
try {
|
|
31790
|
+
appendFileSync5(path, records.map((r) => `${JSON.stringify(r)}
|
|
31791
|
+
`).join(""), { mode: 384 });
|
|
31792
|
+
} catch {
|
|
31793
|
+
return;
|
|
31794
|
+
}
|
|
31795
|
+
}
|
|
30854
31796
|
function isStep(v) {
|
|
30855
31797
|
return typeof v === "string" && v !== "" && v.length <= STEP_MAX_LENGTH;
|
|
30856
31798
|
}
|
|
@@ -30905,12 +31847,23 @@ function parseRecord(text, session) {
|
|
|
30905
31847
|
if (typeof r["at"] !== "number")
|
|
30906
31848
|
return null;
|
|
30907
31849
|
const step = r["step"];
|
|
30908
|
-
|
|
31850
|
+
const n = r["number"];
|
|
31851
|
+
return {
|
|
31852
|
+
version: 1,
|
|
31853
|
+
session,
|
|
31854
|
+
key: r["key"],
|
|
31855
|
+
at: r["at"],
|
|
31856
|
+
...isStep(step) ? { step } : {},
|
|
31857
|
+
...isWholeNumber2(n) ? { number: n } : {}
|
|
31858
|
+
};
|
|
30909
31859
|
}
|
|
30910
31860
|
function writeRecord(path, record2) {
|
|
31861
|
+
return writeWhole2(path, JSON.stringify(record2));
|
|
31862
|
+
}
|
|
31863
|
+
function writeWhole2(path, body) {
|
|
30911
31864
|
const tmp = `${path}.${process.pid}.${Date.now()}.tmp`;
|
|
30912
31865
|
try {
|
|
30913
|
-
writeFileSync13(tmp,
|
|
31866
|
+
writeFileSync13(tmp, body, { mode: 384 });
|
|
30914
31867
|
renameSync11(tmp, path);
|
|
30915
31868
|
return true;
|
|
30916
31869
|
} catch {
|
|
@@ -31008,7 +31961,7 @@ function decideAutonomous(facts, mayPublishNow) {
|
|
|
31008
31961
|
|
|
31009
31962
|
// dist/risky/own-copy.js
|
|
31010
31963
|
import { readFileSync as readFileSync23 } from "node:fs";
|
|
31011
|
-
import { join as
|
|
31964
|
+
import { join as join16, posix as posix2, win32 as win322 } from "node:path";
|
|
31012
31965
|
var OWN_COPY_START_TOOL = "Agent";
|
|
31013
31966
|
var OWN_COPY_WRITE_TOOLS = /* @__PURE__ */ new Set(["Write", "Edit", "MultiEdit", "NotebookEdit"]);
|
|
31014
31967
|
var OWN_COPY_ISOLATION = "worktree";
|
|
@@ -31069,7 +32022,7 @@ function typeCanChangeFiles(subagentType, deps) {
|
|
|
31069
32022
|
return true;
|
|
31070
32023
|
if (AGENT_FILE_NAME.test(type)) {
|
|
31071
32024
|
for (const base of [deps.projectDir, deps.home]) {
|
|
31072
|
-
const text = readOr(deps,
|
|
32025
|
+
const text = readOr(deps, join16(base, ".claude", "agents", `${type}.md`));
|
|
31073
32026
|
if (text === null)
|
|
31074
32027
|
continue;
|
|
31075
32028
|
const tools = frontmatterTools(text);
|
|
@@ -31175,31 +32128,31 @@ function judgeChange(input, call, deps) {
|
|
|
31175
32128
|
|
|
31176
32129
|
// dist/risky/save.js
|
|
31177
32130
|
import { randomBytes } from "node:crypto";
|
|
31178
|
-
import { chmodSync as chmodSync2, constants as fsConstants, copyFileSync, lstatSync as lstatSync4, mkdirSync as mkdirSync9, readdirSync as readdirSync10, readFileSync as readFileSync24, readlinkSync, realpathSync as
|
|
31179
|
-
import { homedir as
|
|
31180
|
-
import { dirname as dirname7, isAbsolute as
|
|
32131
|
+
import { chmodSync as chmodSync2, constants as fsConstants, copyFileSync, lstatSync as lstatSync4, mkdirSync as mkdirSync9, readdirSync as readdirSync10, readFileSync as readFileSync24, readlinkSync, realpathSync as realpathSync9, renameSync as renameSync12, rmSync as rmSync3, statSync as statSync9, symlinkSync, writeFileSync as writeFileSync14 } from "node:fs";
|
|
32132
|
+
import { homedir as homedir11 } from "node:os";
|
|
32133
|
+
import { dirname as dirname7, isAbsolute as isAbsolute6, join as join17, resolve as resolve8 } from "node:path";
|
|
31181
32134
|
var SAVE_LIMIT_BYTES = 2e8;
|
|
31182
32135
|
var SAVE_BUDGET_MS = 5e3;
|
|
31183
32136
|
function notSaved(reason) {
|
|
31184
32137
|
return { saved: false, reason };
|
|
31185
32138
|
}
|
|
31186
|
-
function savedFolderOf(engagementId, home =
|
|
32139
|
+
function savedFolderOf(engagementId, home = homedir11()) {
|
|
31187
32140
|
if (!isEngagementId(engagementId))
|
|
31188
32141
|
return null;
|
|
31189
|
-
return
|
|
32142
|
+
return join17(home, HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, SAVED_DIR_NAME);
|
|
31190
32143
|
}
|
|
31191
32144
|
function saveFirst(staked, ctx) {
|
|
31192
32145
|
const now = ctx.now ?? Date.now;
|
|
31193
32146
|
const deadline = now() + (ctx.budgetMs ?? SAVE_BUDGET_MS);
|
|
31194
|
-
const
|
|
31195
|
-
if (
|
|
32147
|
+
const folder2 = savedFolderOf(ctx.engagementId, ctx.home);
|
|
32148
|
+
if (folder2 === null)
|
|
31196
32149
|
return notSaved(AUTONOMY_SAVE_FAILED_REASON);
|
|
31197
32150
|
const plan = planOf(staked);
|
|
31198
32151
|
if (!plan.ok)
|
|
31199
32152
|
return notSaved(plan.reason);
|
|
31200
32153
|
const g = new SaveGit(plan.root, deadline, now);
|
|
31201
32154
|
const top = g.run(["rev-parse", "--show-toplevel"]);
|
|
31202
|
-
if (!top.ok ||
|
|
32155
|
+
if (!top.ok || realOrSelf3(top.value.trim()) !== plan.root)
|
|
31203
32156
|
return notSaved(AUTONOMY_SAVE_NOT_COVERED_REASON);
|
|
31204
32157
|
const head = g.run(["rev-parse", "--verify", "--quiet", "HEAD^{commit}"]);
|
|
31205
32158
|
const headCommit2 = head.ok ? head.value.trim() : "";
|
|
@@ -31214,23 +32167,23 @@ function saveFirst(staked, ctx) {
|
|
|
31214
32167
|
return notSaved(found2.reason);
|
|
31215
32168
|
let saveDir = null;
|
|
31216
32169
|
try {
|
|
31217
|
-
const id = freshId(
|
|
32170
|
+
const id = freshId(folder2, ctx.newId);
|
|
31218
32171
|
if (id === null)
|
|
31219
32172
|
return notSaved(AUTONOMY_SAVE_FAILED_REASON);
|
|
31220
|
-
saveDir =
|
|
32173
|
+
saveDir = join17(folder2, id);
|
|
31221
32174
|
const repository = repositoryOf(g);
|
|
31222
32175
|
if (repository === null)
|
|
31223
32176
|
return failed(saveDir);
|
|
31224
|
-
writeFileSync14(
|
|
32177
|
+
writeFileSync14(join17(saveDir, SAVED_REPOSITORY_FILE_NAME), `${repository}
|
|
31225
32178
|
`, { mode: 384 });
|
|
31226
|
-
const privateIndex =
|
|
32179
|
+
const privateIndex = join17(saveDir, PRIVATE_INDEX_NAME);
|
|
31227
32180
|
const commit = saveCommit(id, headCommit2, found2.tracked, plan.lines, privateIndex, g, now());
|
|
31228
32181
|
rmSync3(privateIndex, { force: true });
|
|
31229
32182
|
if (commit === null)
|
|
31230
32183
|
return failed(saveDir);
|
|
31231
|
-
const copiesDir =
|
|
32184
|
+
const copiesDir = join17(saveDir, SAVED_COPIES_DIR_NAME);
|
|
31232
32185
|
for (const rel of found2.copies) {
|
|
31233
|
-
if (now() > deadline || !copyOne(
|
|
32186
|
+
if (now() > deadline || !copyOne(join17(plan.root, rel), join17(copiesDir, rel)))
|
|
31234
32187
|
return failed(saveDir);
|
|
31235
32188
|
}
|
|
31236
32189
|
const description = savedSchema.safeParse({
|
|
@@ -31246,7 +32199,7 @@ function saveFirst(staked, ctx) {
|
|
|
31246
32199
|
});
|
|
31247
32200
|
if (!description.success)
|
|
31248
32201
|
return failed(saveDir);
|
|
31249
|
-
const file2 =
|
|
32202
|
+
const file2 = join17(saveDir, SAVED_FILE_NAME);
|
|
31250
32203
|
writeFileSync14(`${file2}.part`, `${JSON.stringify(description.data, null, 2)}
|
|
31251
32204
|
`, { mode: 384 });
|
|
31252
32205
|
renameSync12(`${file2}.part`, file2);
|
|
@@ -31277,7 +32230,7 @@ function planOf(staked) {
|
|
|
31277
32230
|
const t = f.save;
|
|
31278
32231
|
if (t === void 0)
|
|
31279
32232
|
return { ok: false, reason: f.cannotTell === void 0 ? AUTONOMY_SAVE_NOT_COVERED_REASON : AUTONOMY_COULD_NOT_TELL_REASON };
|
|
31280
|
-
const r =
|
|
32233
|
+
const r = realOrSelf3(resolve8(t.repoRoot));
|
|
31281
32234
|
if (root === null)
|
|
31282
32235
|
root = r;
|
|
31283
32236
|
else if (root !== r)
|
|
@@ -31296,7 +32249,7 @@ function planOf(staked) {
|
|
|
31296
32249
|
function isInsideRel(p) {
|
|
31297
32250
|
if (p === ".")
|
|
31298
32251
|
return true;
|
|
31299
|
-
if (p === "" ||
|
|
32252
|
+
if (p === "" || isAbsolute6(p) || p.includes("\\"))
|
|
31300
32253
|
return false;
|
|
31301
32254
|
return p.split("/").every((s) => s !== "" && s !== "." && s !== "..");
|
|
31302
32255
|
}
|
|
@@ -31326,7 +32279,7 @@ function filesOf(plan, g, deadline) {
|
|
|
31326
32279
|
trackedAll.add(path);
|
|
31327
32280
|
if (!reached(path, plan.specs))
|
|
31328
32281
|
continue;
|
|
31329
|
-
const st = lstatOrNull(
|
|
32282
|
+
const st = lstatOrNull(join17(plan.root, path));
|
|
31330
32283
|
if (st !== null && (st.isFile() || st.isSymbolicLink()))
|
|
31331
32284
|
tracked.add(path);
|
|
31332
32285
|
}
|
|
@@ -31338,7 +32291,7 @@ function filesOf(plan, g, deadline) {
|
|
|
31338
32291
|
const rel = stack.pop();
|
|
31339
32292
|
if (rel === ".git")
|
|
31340
32293
|
continue;
|
|
31341
|
-
const abs = rel === "." ? plan.root :
|
|
32294
|
+
const abs = rel === "." ? plan.root : join17(plan.root, rel);
|
|
31342
32295
|
const st = lstatOrNull(abs);
|
|
31343
32296
|
if (st === null)
|
|
31344
32297
|
continue;
|
|
@@ -31376,13 +32329,13 @@ function copyOne(src, dst) {
|
|
|
31376
32329
|
}
|
|
31377
32330
|
copyFileSync(src, dst, fsConstants.COPYFILE_EXCL | fsConstants.COPYFILE_FICLONE);
|
|
31378
32331
|
chmodSync2(dst, st.mode & 4095);
|
|
31379
|
-
return
|
|
32332
|
+
return statSync9(dst).size === st.size;
|
|
31380
32333
|
}
|
|
31381
32334
|
function saveCommit(id, head, tracked, lines2, privateIndex, g, at) {
|
|
31382
32335
|
const indexPath = g.run(["rev-parse", "--git-path", "index"]);
|
|
31383
32336
|
if (!indexPath.ok)
|
|
31384
32337
|
return null;
|
|
31385
|
-
const projectIndex =
|
|
32338
|
+
const projectIndex = resolve8(g.root, indexPath.value.trim());
|
|
31386
32339
|
const env = commitEnv(privateIndex, at);
|
|
31387
32340
|
if (lstatOrNull(projectIndex) !== null)
|
|
31388
32341
|
copyFileSync(projectIndex, privateIndex);
|
|
@@ -31444,14 +32397,14 @@ var SaveGit = class {
|
|
|
31444
32397
|
});
|
|
31445
32398
|
}
|
|
31446
32399
|
};
|
|
31447
|
-
function freshId(
|
|
31448
|
-
mkdirSync9(
|
|
32400
|
+
function freshId(folder2, newId) {
|
|
32401
|
+
mkdirSync9(folder2, { recursive: true, mode: 448 });
|
|
31449
32402
|
for (let i = 0; i < 5; i++) {
|
|
31450
32403
|
const id = newId?.() ?? defaultId();
|
|
31451
32404
|
if (!savedIdSchema.safeParse(id).success)
|
|
31452
32405
|
return null;
|
|
31453
32406
|
try {
|
|
31454
|
-
mkdirSync9(
|
|
32407
|
+
mkdirSync9(join17(folder2, id), { mode: 448 });
|
|
31455
32408
|
return id;
|
|
31456
32409
|
} catch (e) {
|
|
31457
32410
|
if (e.code !== "EEXIST")
|
|
@@ -31472,19 +32425,19 @@ function repositoryOf(g) {
|
|
|
31472
32425
|
if (!r.ok)
|
|
31473
32426
|
return null;
|
|
31474
32427
|
const dir = r.value.trim();
|
|
31475
|
-
return dir === "" ? null :
|
|
32428
|
+
return dir === "" ? null : realOrSelf3(resolve8(g.root, dir));
|
|
31476
32429
|
}
|
|
31477
32430
|
function markedRepository(dir) {
|
|
31478
32431
|
try {
|
|
31479
|
-
const text = readFileSync24(
|
|
32432
|
+
const text = readFileSync24(join17(dir, SAVED_REPOSITORY_FILE_NAME), "utf-8").trim();
|
|
31480
32433
|
return text === "" ? null : text;
|
|
31481
32434
|
} catch {
|
|
31482
32435
|
return null;
|
|
31483
32436
|
}
|
|
31484
32437
|
}
|
|
31485
32438
|
function pruneSaves(root, engagementId, ctx = {}) {
|
|
31486
|
-
const
|
|
31487
|
-
if (
|
|
32439
|
+
const folder2 = savedFolderOf(engagementId, ctx.home);
|
|
32440
|
+
if (folder2 === null)
|
|
31488
32441
|
return;
|
|
31489
32442
|
const now = ctx.now ?? Date.now;
|
|
31490
32443
|
const g = new SaveGit(root, ctx.deadline ?? now() + SAVE_BUDGET_MS, now);
|
|
@@ -31501,7 +32454,7 @@ function pruneSaves(root, engagementId, ctx = {}) {
|
|
|
31501
32454
|
const repository = repositoryOf(g);
|
|
31502
32455
|
let names = [];
|
|
31503
32456
|
try {
|
|
31504
|
-
names = readdirSync10(
|
|
32457
|
+
names = readdirSync10(folder2);
|
|
31505
32458
|
} catch {
|
|
31506
32459
|
names = [];
|
|
31507
32460
|
}
|
|
@@ -31510,7 +32463,7 @@ function pruneSaves(root, engagementId, ctx = {}) {
|
|
|
31510
32463
|
if (!savedIdSchema.safeParse(id).success)
|
|
31511
32464
|
continue;
|
|
31512
32465
|
here.add(id);
|
|
31513
|
-
const dir =
|
|
32466
|
+
const dir = join17(folder2, id);
|
|
31514
32467
|
const st = lstatOrNull(dir);
|
|
31515
32468
|
const answer = savedPruneAnswer({
|
|
31516
32469
|
refMadeAt: refs.get(id) ?? null,
|
|
@@ -31539,9 +32492,9 @@ function lstatOrNull(p) {
|
|
|
31539
32492
|
return null;
|
|
31540
32493
|
}
|
|
31541
32494
|
}
|
|
31542
|
-
function
|
|
32495
|
+
function realOrSelf3(p) {
|
|
31543
32496
|
try {
|
|
31544
|
-
return
|
|
32497
|
+
return realpathSync9(p);
|
|
31545
32498
|
} catch {
|
|
31546
32499
|
return p;
|
|
31547
32500
|
}
|
|
@@ -31550,12 +32503,12 @@ function realOrSelf2(p) {
|
|
|
31550
32503
|
// dist/autonomy-state.js
|
|
31551
32504
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
31552
32505
|
import { chmodSync as chmodSync3, mkdirSync as mkdirSync10, readFileSync as readFileSync25, renameSync as renameSync13, rmSync as rmSync4, writeFileSync as writeFileSync15 } from "node:fs";
|
|
31553
|
-
import { homedir as
|
|
31554
|
-
import { dirname as dirname8, join as
|
|
32506
|
+
import { homedir as homedir12, platform as platform2 } from "node:os";
|
|
32507
|
+
import { dirname as dirname8, join as join18 } from "node:path";
|
|
31555
32508
|
var AUTONOMY_STATE_FILENAME = "autonomy.json";
|
|
31556
32509
|
var AUTONOMY_STATE_DEADLINE_MS = 1500;
|
|
31557
32510
|
function autonomyStateFilePath(engagementId, home) {
|
|
31558
|
-
return
|
|
32511
|
+
return join18(home ?? homedir12(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, AUTONOMY_STATE_FILENAME);
|
|
31559
32512
|
}
|
|
31560
32513
|
function readCachedAutonomy(engagementId, nowMs, home) {
|
|
31561
32514
|
if (!isEngagementId(engagementId))
|
|
@@ -31583,6 +32536,7 @@ function confirmMayPublishNow(opts) {
|
|
|
31583
32536
|
timeout: opts.timeoutMs,
|
|
31584
32537
|
windowsHide: true
|
|
31585
32538
|
});
|
|
32539
|
+
recordChildRequest(url2, ["Authorization"], r.status === 0);
|
|
31586
32540
|
if (r.status !== 0 || typeof r.stdout !== "string")
|
|
31587
32541
|
return false;
|
|
31588
32542
|
const parsed = autonomyStateSchema.safeParse(JSON.parse(r.stdout));
|
|
@@ -31607,7 +32561,7 @@ function deleteAutonomyStateFile(engagementId, home) {
|
|
|
31607
32561
|
}
|
|
31608
32562
|
function writeAutonomyStateFile(engagementId, file2, home) {
|
|
31609
32563
|
const target = autonomyStateFilePath(engagementId, home);
|
|
31610
|
-
const temp =
|
|
32564
|
+
const temp = join18(dirname8(target), `.${AUTONOMY_STATE_FILENAME}.${process.pid}.tmp`);
|
|
31611
32565
|
try {
|
|
31612
32566
|
mkdirSync10(dirname8(target), { recursive: true, mode: 448 });
|
|
31613
32567
|
writeFileSync15(temp, `${JSON.stringify(file2)}
|
|
@@ -31669,7 +32623,7 @@ async function cacheAutonomySetting(opts) {
|
|
|
31669
32623
|
}
|
|
31670
32624
|
|
|
31671
32625
|
// dist/risky/patch-calls.js
|
|
31672
|
-
import { isAbsolute as
|
|
32626
|
+
import { isAbsolute as isAbsolute7, resolve as resolve9 } from "node:path";
|
|
31673
32627
|
var SHELL_TOOL = "Bash";
|
|
31674
32628
|
function toolCallsOf(input, profile) {
|
|
31675
32629
|
const toolName = input["tool_name"];
|
|
@@ -31692,7 +32646,7 @@ function toolCallsOf(input, profile) {
|
|
|
31692
32646
|
const ops = patchOperations(command);
|
|
31693
32647
|
if (ops === null || ops.length === 0)
|
|
31694
32648
|
return null;
|
|
31695
|
-
const cwd = typeof input["cwd"] === "string" &&
|
|
32649
|
+
const cwd = typeof input["cwd"] === "string" && isAbsolute7(input["cwd"]) ? input["cwd"] : null;
|
|
31696
32650
|
const calls = [];
|
|
31697
32651
|
for (const op of ops) {
|
|
31698
32652
|
const made = callsFor(op, cwd);
|
|
@@ -31730,9 +32684,9 @@ function callsFor(op, cwd) {
|
|
|
31730
32684
|
}
|
|
31731
32685
|
}
|
|
31732
32686
|
function placed(path, cwd) {
|
|
31733
|
-
if (
|
|
31734
|
-
return
|
|
31735
|
-
return cwd === null ? null :
|
|
32687
|
+
if (isAbsolute7(path))
|
|
32688
|
+
return resolve9(path);
|
|
32689
|
+
return cwd === null ? null : resolve9(cwd, path);
|
|
31736
32690
|
}
|
|
31737
32691
|
function shellWord(text) {
|
|
31738
32692
|
return `'${text.split("'").join("'\\''")}'`;
|
|
@@ -31740,7 +32694,7 @@ function shellWord(text) {
|
|
|
31740
32694
|
|
|
31741
32695
|
// dist/hooks/pre-tool-use.js
|
|
31742
32696
|
import { performance } from "node:perf_hooks";
|
|
31743
|
-
import { homedir as
|
|
32697
|
+
import { homedir as homedir13 } from "node:os";
|
|
31744
32698
|
var UNREADABLE_INPUT_NOTICE = "Halfcycle could not read what the coding agent was about to do, so that step went ahead without being checked for anything that cannot be undone. If this keeps happening, update Halfcycle.";
|
|
31745
32699
|
var PRE_TOOL_USE_LIMIT_MS = (HALFCYCLE_HOOK_WIRING.find((e) => e.event === "PreToolUse")?.timeout ?? 10) * 1e3;
|
|
31746
32700
|
var AUTONOMY_REPLY_MARGIN_MS = 1e3;
|
|
@@ -31811,6 +32765,11 @@ function runPreToolUse(deps) {
|
|
|
31811
32765
|
if (held !== null)
|
|
31812
32766
|
return `${preToolUseReplyText("refuse", held)}
|
|
31813
32767
|
`;
|
|
32768
|
+
recordSpawnedTask(call.toolInput, {
|
|
32769
|
+
projectDir: projectDirOf(deps),
|
|
32770
|
+
...deps.env === void 0 ? {} : { env: deps.env },
|
|
32771
|
+
...deps.home === void 0 ? {} : { home: deps.home }
|
|
32772
|
+
});
|
|
31814
32773
|
}
|
|
31815
32774
|
return own.kind === "unknown" ? ownCopyNotice(input, deps) : "";
|
|
31816
32775
|
}
|
|
@@ -31819,16 +32778,19 @@ function runPreToolUse(deps) {
|
|
|
31819
32778
|
return `${preToolUseReplyText("ask", answer.question)}
|
|
31820
32779
|
`;
|
|
31821
32780
|
}
|
|
32781
|
+
let agentText = answer.refusal.agent;
|
|
31822
32782
|
if (allowableByTyping(call, answer.staked)) {
|
|
31823
|
-
const key = stepKey(input, answer.staked);
|
|
32783
|
+
const key = stepKey(input, answer.staked, deps.gitTimeoutMs === void 0 ? {} : { gitTimeoutMs: deps.gitTimeoutMs });
|
|
31824
32784
|
if (key !== null) {
|
|
31825
32785
|
const allowOnce = { ...deps.liveness?.dir === void 0 ? {} : { dir: deps.liveness.dir }, now: () => at.getTime() };
|
|
31826
32786
|
if (spendAllow(input["session_id"], key, allowOnce))
|
|
31827
32787
|
return "";
|
|
31828
|
-
|
|
32788
|
+
const stepNumber = numberStep(input["session_id"], key, allowOnce);
|
|
32789
|
+
recordHeld(input["session_id"], key, allowOnce, answer.refusal.step, stepNumber);
|
|
32790
|
+
agentText = heldAgentText(answer.refusal, stepNumber);
|
|
31829
32791
|
}
|
|
31830
32792
|
}
|
|
31831
|
-
return `${preToolUseReplyText("refuse", answer.refusal.person,
|
|
32793
|
+
return `${preToolUseReplyText("refuse", answer.refusal.person, agentText)}
|
|
31832
32794
|
`;
|
|
31833
32795
|
} catch {
|
|
31834
32796
|
return "";
|
|
@@ -31956,7 +32918,7 @@ function ownCopyOf(input, call, deps) {
|
|
|
31956
32918
|
const walk2 = deps.walk ?? deps.liveness?.walk;
|
|
31957
32919
|
return judgeOwnCopy(input, call, {
|
|
31958
32920
|
projectDir: projectDirOf(deps),
|
|
31959
|
-
home: deps.home ??
|
|
32921
|
+
home: deps.home ?? homedir13(),
|
|
31960
32922
|
...walk2 === void 0 ? {} : { walk: walk2 },
|
|
31961
32923
|
...deps.liveness === void 0 ? {} : { liveness: deps.liveness }
|
|
31962
32924
|
});
|
|
@@ -31965,8 +32927,8 @@ function ownCopyOf(input, call, deps) {
|
|
|
31965
32927
|
}
|
|
31966
32928
|
}
|
|
31967
32929
|
function ownCopyNotice(input, deps) {
|
|
31968
|
-
const
|
|
31969
|
-
return firstNoticeThisSession("outside-own-copy-unknown",
|
|
32930
|
+
const folder2 = stringOf(input, "cwd") ?? projectDirOf(deps);
|
|
32931
|
+
return firstNoticeThisSession("outside-own-copy-unknown", folder2, stringOf(input, "session_id"), deps.liveness?.dir) ? `${preToolUseNoticeText(OWN_COPY_UNKNOWN_NOTICE)}
|
|
31970
32932
|
` : "";
|
|
31971
32933
|
}
|
|
31972
32934
|
function parseObject2(text) {
|
|
@@ -31983,14 +32945,14 @@ function stringOf(input, key) {
|
|
|
31983
32945
|
}
|
|
31984
32946
|
function unreadable(deps, input) {
|
|
31985
32947
|
const session = (input === null ? void 0 : stringOf(input, "session_id")) ?? /"session_id"\s*:\s*"([^"\\]+)"/.exec(deps.input)?.[1];
|
|
31986
|
-
const
|
|
31987
|
-
return firstNoticeThisSession("pre-tool-use-unreadable",
|
|
32948
|
+
const folder2 = (input === null ? void 0 : stringOf(input, "cwd")) ?? projectDirOf(deps);
|
|
32949
|
+
return firstNoticeThisSession("pre-tool-use-unreadable", folder2, session) ? `${preToolUseNoticeText(UNREADABLE_INPUT_NOTICE)}
|
|
31988
32950
|
` : "";
|
|
31989
32951
|
}
|
|
31990
32952
|
|
|
31991
32953
|
// dist/hooks/session-diff.js
|
|
31992
32954
|
import { unlinkSync as unlinkSync10 } from "node:fs";
|
|
31993
|
-
import { join as
|
|
32955
|
+
import { join as join19 } from "node:path";
|
|
31994
32956
|
var STOP_HOOK_EVENT = {
|
|
31995
32957
|
stop: "Stop",
|
|
31996
32958
|
"subagent-stop": "SubagentStop"
|
|
@@ -32042,7 +33004,7 @@ async function evaluateSession(input, kind, reply, readSeat, profile) {
|
|
|
32042
33004
|
}
|
|
32043
33005
|
const repoRoot = repoRootResult.value;
|
|
32044
33006
|
const sessionId = input.session_id;
|
|
32045
|
-
const
|
|
33007
|
+
const folder2 = realPathOf(repoRoot);
|
|
32046
33008
|
orphanSweep(repoRoot, (ref) => refExists(ref, repoRoot), sessionId, Date.now(), whichCopy(process.cwd())?.common ?? null);
|
|
32047
33009
|
const base = resolveDiffBase2(repoRoot, sessionId);
|
|
32048
33010
|
const diffBase = base.kind;
|
|
@@ -32055,12 +33017,12 @@ async function evaluateSession(input, kind, reply, readSeat, profile) {
|
|
|
32055
33017
|
const candidates = ownEditedFiles(repoRoot, sessionId).filter((relPath) => !tracked.has(relPath));
|
|
32056
33018
|
const untracked = getUntrackedFiles(repoRoot, candidates);
|
|
32057
33019
|
const created = untracked.ok ? untracked.value.filter((relPath) => !tracked.has(relPath)) : [];
|
|
32058
|
-
const getDiff = (relPath) => tracked.has(relPath) ? collected.getDiff(relPath) : getSingleFileDiff(
|
|
33020
|
+
const getDiff = (relPath) => tracked.has(relPath) ? collected.getDiff(relPath) : getSingleFileDiff(join19(repoRoot, relPath), repoRoot);
|
|
32059
33021
|
const { evaluated } = partitionInstallerOutput(collected.files);
|
|
32060
33022
|
const { evaluated: createdEvaluated } = partitionInstallerOutput(created);
|
|
32061
33023
|
const changedFiles2 = [...ownChangedFiles(repoRoot, evaluated, sessionId), ...createdEvaluated];
|
|
32062
33024
|
if (changedFiles2.length === 0) {
|
|
32063
|
-
queueTurnEnd(keepBooks(sessionId,
|
|
33025
|
+
queueTurnEnd(keepBooks(sessionId, folder2, { kind: "no-own-changes" }, kind === "stop"), reply);
|
|
32064
33026
|
return;
|
|
32065
33027
|
}
|
|
32066
33028
|
const fileDiffEntries = changedFiles2.map((relPath) => ({
|
|
@@ -32071,7 +33033,7 @@ async function evaluateSession(input, kind, reply, readSeat, profile) {
|
|
|
32071
33033
|
const digest = digestChangeState(baseKey, fileDiffEntries);
|
|
32072
33034
|
const prior = readDedupe(repoRoot, sessionId);
|
|
32073
33035
|
if (prior && prior.base === baseKey && prior.digest === digest) {
|
|
32074
|
-
queueTurnEnd(keepBooks(sessionId,
|
|
33036
|
+
queueTurnEnd(keepBooks(sessionId, folder2, { kind: "unchanged" }, kind === "stop"), reply);
|
|
32075
33037
|
return;
|
|
32076
33038
|
}
|
|
32077
33039
|
const context = loadChangeSetContext(repoRoot);
|
|
@@ -32151,12 +33113,12 @@ async function evaluateSession(input, kind, reply, readSeat, profile) {
|
|
|
32151
33113
|
warn: (msg) => process.stderr.write(msg + "\n")
|
|
32152
33114
|
});
|
|
32153
33115
|
writeDedupe(repoRoot, sessionId, { base: baseKey, digest });
|
|
32154
|
-
actOnEnvelope3(clientResult.envelope, kind, input.stop_hook_active === true, reply, sessionId,
|
|
33116
|
+
actOnEnvelope3(clientResult.envelope, kind, input.stop_hook_active === true, reply, sessionId, folder2);
|
|
32155
33117
|
}
|
|
32156
|
-
function keepBooks(sessionId,
|
|
33118
|
+
function keepBooks(sessionId, folder2, outcome, topLevel) {
|
|
32157
33119
|
const books = () => {
|
|
32158
33120
|
const before = readFindings(sessionId);
|
|
32159
|
-
const { file: file2, news } = turnEndBookkeeping(before ?? emptyFindings(""),
|
|
33121
|
+
const { file: file2, news } = turnEndBookkeeping(before ?? emptyFindings(""), folder2, outcome, topLevel, /* @__PURE__ */ new Date());
|
|
32160
33122
|
if (before !== null && JSON.stringify(before) !== JSON.stringify(file2)) {
|
|
32161
33123
|
if (file2.findings.length > 0)
|
|
32162
33124
|
writeFindings(file2);
|
|
@@ -32181,7 +33143,7 @@ function queueTurnEnd(words, reply) {
|
|
|
32181
33143
|
if (words !== null)
|
|
32182
33144
|
reply.notice(words);
|
|
32183
33145
|
}
|
|
32184
|
-
function actOnEnvelope3(envelope, kind, neverBlock, reply, sessionId,
|
|
33146
|
+
function actOnEnvelope3(envelope, kind, neverBlock, reply, sessionId, folder2) {
|
|
32185
33147
|
const notRun = notRunMessage((envelope.notRun ?? []).map((n) => n.reason));
|
|
32186
33148
|
const outcome = {
|
|
32187
33149
|
kind: "evaluated",
|
|
@@ -32190,7 +33152,7 @@ function actOnEnvelope3(envelope, kind, neverBlock, reply, sessionId, folder) {
|
|
|
32190
33152
|
};
|
|
32191
33153
|
const topLevel = kind === "stop";
|
|
32192
33154
|
if (envelope.blocking && !neverBlock) {
|
|
32193
|
-
keepBooks(sessionId,
|
|
33155
|
+
keepBooks(sessionId, folder2, outcome, false);
|
|
32194
33156
|
const reason = blockReason(envelope.guardsFired.map((g) => g.explanation));
|
|
32195
33157
|
reply.block(notRun ? `${reason}
|
|
32196
33158
|
${notRun}` : reason, stoppedMessage(blockingExplanations(envelope.guardsFired)));
|
|
@@ -32198,7 +33160,7 @@ ${notRun}` : reason, stoppedMessage(blockingExplanations(envelope.guardsFired)))
|
|
|
32198
33160
|
if (envelope.blocking && neverBlock) {
|
|
32199
33161
|
reply.notice(couldNotFixMessage(blockingExplanations(envelope.guardsFired)));
|
|
32200
33162
|
}
|
|
32201
|
-
queueTurnEnd(keepBooks(sessionId,
|
|
33163
|
+
queueTurnEnd(keepBooks(sessionId, folder2, outcome, topLevel), reply);
|
|
32202
33164
|
if (notRun)
|
|
32203
33165
|
reply.notice(notRun);
|
|
32204
33166
|
}
|
|
@@ -32219,9 +33181,9 @@ async function readHookStdin() {
|
|
|
32219
33181
|
}
|
|
32220
33182
|
}
|
|
32221
33183
|
function readStdin2() {
|
|
32222
|
-
return new Promise((
|
|
33184
|
+
return new Promise((resolve12) => {
|
|
32223
33185
|
if (process.stdin.isTTY) {
|
|
32224
|
-
|
|
33186
|
+
resolve12("");
|
|
32225
33187
|
return;
|
|
32226
33188
|
}
|
|
32227
33189
|
const chunks = [];
|
|
@@ -32231,7 +33193,7 @@ function readStdin2() {
|
|
|
32231
33193
|
return;
|
|
32232
33194
|
settled2 = true;
|
|
32233
33195
|
clearTimeout(timer);
|
|
32234
|
-
|
|
33196
|
+
resolve12(Buffer.concat(chunks).toString("utf-8"));
|
|
32235
33197
|
};
|
|
32236
33198
|
const timer = setTimeout(done, HOOK_STDIN_GRACE_MS);
|
|
32237
33199
|
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
@@ -32258,19 +33220,19 @@ async function runStop(observeDeps = {}, timeDeps = {}, paceDeps = {}, profile =
|
|
|
32258
33220
|
recordTimeEvent("turn-end", input);
|
|
32259
33221
|
await runSessionDiff(input, "stop", readSeatConfiguration, async (reply) => {
|
|
32260
33222
|
await observeChanges(input.session_id, reply, observeDeps);
|
|
32261
|
-
await sendTimeRecord(timeDeps);
|
|
33223
|
+
await sendTimeRecord(timeDeps, { agent: profile.id });
|
|
32262
33224
|
await paceAtTurnEnd(input, reply, { configFolder: profile.configFolder, ...paceDeps });
|
|
32263
33225
|
}, profile);
|
|
32264
33226
|
}
|
|
32265
33227
|
|
|
32266
33228
|
// dist/relayed-choices.js
|
|
32267
33229
|
import { mkdirSync as mkdirSync11, readFileSync as readFileSync26, renameSync as renameSync14, rmSync as rmSync5, writeFileSync as writeFileSync16 } from "node:fs";
|
|
32268
|
-
import { homedir as
|
|
32269
|
-
import { dirname as dirname9, join as
|
|
33230
|
+
import { homedir as homedir14 } from "node:os";
|
|
33231
|
+
import { dirname as dirname9, join as join20 } from "node:path";
|
|
32270
33232
|
function relayedChoicesFilePath(engagementId, home) {
|
|
32271
33233
|
if (!isEngagementId(engagementId))
|
|
32272
33234
|
return null;
|
|
32273
|
-
return
|
|
33235
|
+
return join20(home ?? homedir14(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, PACING_DIR_NAME, RELAYED_CHOICES_FILENAME);
|
|
32274
33236
|
}
|
|
32275
33237
|
function readRelayedChoices(engagementId, phase, home) {
|
|
32276
33238
|
const path = relayedChoicesFilePath(engagementId, home);
|
|
@@ -32306,7 +33268,7 @@ function recordRelayedChoice(opts) {
|
|
|
32306
33268
|
});
|
|
32307
33269
|
if (!file2.success)
|
|
32308
33270
|
return false;
|
|
32309
|
-
const temp =
|
|
33271
|
+
const temp = join20(dirname9(target), `.${RELAYED_CHOICES_FILENAME}.${process.pid}.tmp`);
|
|
32310
33272
|
try {
|
|
32311
33273
|
mkdirSync11(dirname9(target), { recursive: true, mode: 448 });
|
|
32312
33274
|
writeFileSync16(temp, `${JSON.stringify(file2.data)}
|
|
@@ -32535,19 +33497,19 @@ function matchReviewPhraseShape(shape, reviews) {
|
|
|
32535
33497
|
|
|
32536
33498
|
// dist/hooks/shown-record.js
|
|
32537
33499
|
import { chmodSync as chmodSync4, readFileSync as readFileSync27, renameSync as renameSync15, unlinkSync as unlinkSync11, writeFileSync as writeFileSync17 } from "node:fs";
|
|
32538
|
-
import { homedir as
|
|
32539
|
-
import { join as
|
|
33500
|
+
import { homedir as homedir15, platform as platform3 } from "node:os";
|
|
33501
|
+
import { join as join21 } from "node:path";
|
|
32540
33502
|
function recordDir(engagementId, home) {
|
|
32541
33503
|
if (!isEngagementId(engagementId))
|
|
32542
33504
|
return null;
|
|
32543
|
-
return
|
|
33505
|
+
return join21(home ?? homedir15(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId);
|
|
32544
33506
|
}
|
|
32545
33507
|
function readShownRecord(engagementId, home) {
|
|
32546
33508
|
const dir = recordDir(engagementId, home);
|
|
32547
33509
|
if (dir === null)
|
|
32548
33510
|
return { entries: [], reviews: [] };
|
|
32549
33511
|
try {
|
|
32550
|
-
return parseShownRecord(readFileSync27(
|
|
33512
|
+
return parseShownRecord(readFileSync27(join21(dir, SHOWN_PLANS_FILENAME), "utf-8"));
|
|
32551
33513
|
} catch {
|
|
32552
33514
|
return { entries: [], reviews: [] };
|
|
32553
33515
|
}
|
|
@@ -32568,7 +33530,7 @@ function moveListedReviewForward(engagementId, home, listed, reviewVersion, deci
|
|
|
32568
33530
|
const dir = recordDir(engagementId, home);
|
|
32569
33531
|
if (dir === null)
|
|
32570
33532
|
return false;
|
|
32571
|
-
const path =
|
|
33533
|
+
const path = join21(dir, SHOWN_PLANS_FILENAME);
|
|
32572
33534
|
const current = parseShownRecord(readFileSync27(path, "utf-8"));
|
|
32573
33535
|
const at = current.reviews.findIndex((r) => r.phase === listed.phase && r.shownAt === listed.shownAt && r.reviewVersion === listed.reviewVersion);
|
|
32574
33536
|
if (at === -1)
|
|
@@ -32576,7 +33538,7 @@ function moveListedReviewForward(engagementId, home, listed, reviewVersion, deci
|
|
|
32576
33538
|
const acts = new Map(decided.map((d) => [d.part, d.act]));
|
|
32577
33539
|
const reviews = current.reviews.map((review, i) => i === at ? { ...review, reviewVersion, parts: review.parts.map((p) => movedPart(p, acts.get(p.part))) } : review);
|
|
32578
33540
|
const body = serialiseShownRecord({ entries: current.entries, reviews });
|
|
32579
|
-
temp =
|
|
33541
|
+
temp = join21(dir, `.${SHOWN_PLANS_FILENAME}.${process.pid}.tmp`);
|
|
32580
33542
|
writeFileSync17(temp, body, { mode: 384 });
|
|
32581
33543
|
if (platform3() !== "win32")
|
|
32582
33544
|
chmodSync4(temp, 384);
|
|
@@ -32960,8 +33922,16 @@ function allowArmedLine(step = null) {
|
|
|
32960
33922
|
function allowNothingHeldLine() {
|
|
32961
33923
|
return line(`${NOTHING_ALLOWED}: no step is paused in this session.`);
|
|
32962
33924
|
}
|
|
32963
|
-
|
|
32964
|
-
|
|
33925
|
+
var UNNAMED_PAUSED_STEP = "a paused step";
|
|
33926
|
+
function allowSeveralHeldLine(paused) {
|
|
33927
|
+
const listed = paused.filter((p) => p.number !== null).map((p) => `${ALLOW_REPLY} ${String(p.number)} for ${p.step ?? UNNAMED_PAUSED_STEP}`).join("; ");
|
|
33928
|
+
if (listed === "") {
|
|
33929
|
+
return `${NOTHING_ALLOWED}: more than one step is paused, and Halfcycle could not number them on this computer. Nothing ran. ${SHOW_AS_WRITTEN}`;
|
|
33930
|
+
}
|
|
33931
|
+
return `${NOTHING_ALLOWED}: more than one step is paused. Type ${ALLOW_REPLY} and the step's number to run that one once: ${listed}. Nothing ran. ${SHOW_AS_WRITTEN}`;
|
|
33932
|
+
}
|
|
33933
|
+
function allowNotPausedLine(stepNumber) {
|
|
33934
|
+
return line(`${NOTHING_ALLOWED}: step ${String(stepNumber)} is not paused in this session.`);
|
|
32965
33935
|
}
|
|
32966
33936
|
function allowNotAttendedLine() {
|
|
32967
33937
|
return line(`${NOTHING_ALLOWED}: a paused step can be allowed by typing only when a person types it into an open session.`);
|
|
@@ -33047,8 +34017,8 @@ function waitLineForAnswer(context, answer) {
|
|
|
33047
34017
|
}
|
|
33048
34018
|
}
|
|
33049
34019
|
var PACE_NOTHING_CHANGED_OPENING = "Nothing changed";
|
|
33050
|
-
function paceAnswerLine(text,
|
|
33051
|
-
return
|
|
34020
|
+
function paceAnswerLine(text, _agent) {
|
|
34021
|
+
return codexLine(text);
|
|
33052
34022
|
}
|
|
33053
34023
|
function paceNumberDoneText(n, more) {
|
|
33054
34024
|
const head = `Done. This build now runs up to ${paceAgentsOf(n)} at once.`;
|
|
@@ -33156,8 +34126,9 @@ async function decideLine(opts) {
|
|
|
33156
34126
|
const review = { recognised: false };
|
|
33157
34127
|
try {
|
|
33158
34128
|
const prompt = promptOf(opts.input);
|
|
33159
|
-
|
|
33160
|
-
|
|
34129
|
+
const allowReply = allowReplyOf(prompt);
|
|
34130
|
+
if (allowReply !== null)
|
|
34131
|
+
return `${decideAllow(allowReply.number, opts)}
|
|
33161
34132
|
`;
|
|
33162
34133
|
const autonomyShape = autonomyPhraseShape(prompt);
|
|
33163
34134
|
if (autonomyShape !== null) {
|
|
@@ -33210,21 +34181,23 @@ async function decideLine(opts) {
|
|
|
33210
34181
|
`;
|
|
33211
34182
|
}
|
|
33212
34183
|
}
|
|
33213
|
-
function decideAllow(opts) {
|
|
34184
|
+
function decideAllow(stepNumber, opts) {
|
|
33214
34185
|
const env = opts.env ?? process.env;
|
|
33215
34186
|
if ((opts.agent ?? "claude-code") === "claude-code" && !readSessionAttended(env))
|
|
33216
34187
|
return allowNotAttendedLine();
|
|
33217
|
-
const { outcome, step } = armAllowStep(sessionIdOf(opts.input), {
|
|
34188
|
+
const { outcome, step, paused } = armAllowStep(sessionIdOf(opts.input), {
|
|
33218
34189
|
...opts.tempDir === void 0 ? {} : { dir: opts.tempDir },
|
|
33219
34190
|
...opts.now === void 0 ? {} : { now: opts.now }
|
|
33220
|
-
});
|
|
34191
|
+
}, stepNumber);
|
|
33221
34192
|
switch (outcome) {
|
|
33222
34193
|
case "armed":
|
|
33223
34194
|
return allowArmedLine(step);
|
|
33224
34195
|
case "nothing-held":
|
|
33225
34196
|
return allowNothingHeldLine();
|
|
34197
|
+
case "not-paused":
|
|
34198
|
+
return allowNotPausedLine(stepNumber ?? 0);
|
|
33226
34199
|
case "several-held":
|
|
33227
|
-
return allowSeveralHeldLine();
|
|
34200
|
+
return allowSeveralHeldLine(paused);
|
|
33228
34201
|
case "not-saved":
|
|
33229
34202
|
return allowNotSavedLine();
|
|
33230
34203
|
default: {
|
|
@@ -33751,14 +34724,14 @@ function runUserPromptFindings(opts) {
|
|
|
33751
34724
|
}
|
|
33752
34725
|
|
|
33753
34726
|
// dist/resolve-engagement.js
|
|
33754
|
-
import { existsSync as
|
|
33755
|
-
import { join as
|
|
33756
|
-
import { homedir as
|
|
34727
|
+
import { existsSync as existsSync9, readFileSync as readFileSync28, realpathSync as realpathSync10 } from "node:fs";
|
|
34728
|
+
import { join as join22, sep as sep7 } from "node:path";
|
|
34729
|
+
import { homedir as homedir16 } from "node:os";
|
|
33757
34730
|
function defaultRegistryPath() {
|
|
33758
|
-
return
|
|
34731
|
+
return join22(homedir16(), ".halfcycle", "registry.json");
|
|
33759
34732
|
}
|
|
33760
34733
|
function readRegistry(registryPath = defaultRegistryPath()) {
|
|
33761
|
-
if (!
|
|
34734
|
+
if (!existsSync9(registryPath))
|
|
33762
34735
|
return {};
|
|
33763
34736
|
try {
|
|
33764
34737
|
const parsed = JSON.parse(readFileSync28(registryPath, "utf-8"));
|
|
@@ -33776,7 +34749,7 @@ function readRegistry(registryPath = defaultRegistryPath()) {
|
|
|
33776
34749
|
}
|
|
33777
34750
|
function canonicalise(p) {
|
|
33778
34751
|
try {
|
|
33779
|
-
return
|
|
34752
|
+
return realpathSync10(p);
|
|
33780
34753
|
} catch {
|
|
33781
34754
|
return p;
|
|
33782
34755
|
}
|
|
@@ -33797,7 +34770,7 @@ function resolveEngagement(cwd, registry2) {
|
|
|
33797
34770
|
function isSelfOrAncestor(ancestor, target) {
|
|
33798
34771
|
if (ancestor === target)
|
|
33799
34772
|
return true;
|
|
33800
|
-
const withSep = ancestor.endsWith(
|
|
34773
|
+
const withSep = ancestor.endsWith(sep7) ? ancestor : ancestor + sep7;
|
|
33801
34774
|
return target.startsWith(withSep);
|
|
33802
34775
|
}
|
|
33803
34776
|
function runResolveEngagement(cwd, registryPath) {
|
|
@@ -33810,12 +34783,12 @@ function runResolveEngagement(cwd, registryPath) {
|
|
|
33810
34783
|
|
|
33811
34784
|
// dist/refresh-credential.js
|
|
33812
34785
|
import { readFileSync as readFileSync30 } from "node:fs";
|
|
33813
|
-
import { resolve as
|
|
34786
|
+
import { resolve as resolve11 } from "node:path";
|
|
33814
34787
|
|
|
33815
34788
|
// dist/mcp-headers.js
|
|
33816
34789
|
import { readFileSync as readFileSync29 } from "node:fs";
|
|
33817
|
-
import { homedir as
|
|
33818
|
-
import { dirname as dirname10, resolve as
|
|
34790
|
+
import { homedir as homedir17 } from "node:os";
|
|
34791
|
+
import { dirname as dirname10, resolve as resolve10 } from "node:path";
|
|
33819
34792
|
var URL_FLAG = "--url";
|
|
33820
34793
|
function urlFromArguments(rest) {
|
|
33821
34794
|
const at = [];
|
|
@@ -33842,12 +34815,12 @@ function headerLine(bearer, clientVersion) {
|
|
|
33842
34815
|
}
|
|
33843
34816
|
function projectRootFromBinary(binaryPath) {
|
|
33844
34817
|
const depth = VENDORED_BIN_REL.split("/").length - 1;
|
|
33845
|
-
return
|
|
34818
|
+
return resolve10(dirname10(binaryPath), ...Array(depth).fill(".."));
|
|
33846
34819
|
}
|
|
33847
34820
|
function readPinnedVersion(root) {
|
|
33848
34821
|
let raw;
|
|
33849
34822
|
try {
|
|
33850
|
-
raw = readFileSync29(
|
|
34823
|
+
raw = readFileSync29(resolve10(root, BUNDLE_PIN_REL), "utf-8");
|
|
33851
34824
|
} catch {
|
|
33852
34825
|
return void 0;
|
|
33853
34826
|
}
|
|
@@ -33889,7 +34862,7 @@ function sentences(lines2) {
|
|
|
33889
34862
|
}
|
|
33890
34863
|
function badIdSentence(root) {
|
|
33891
34864
|
return sentences([
|
|
33892
|
-
`${
|
|
34865
|
+
`${resolve10(root, BUNDLE_PIN_REL)} names an engagement id that is not a Halfcycle project id,`,
|
|
33893
34866
|
'so no credential was read. Delete that file and run "npx halfcycle" again: this repository',
|
|
33894
34867
|
"is then set up as a new Halfcycle project."
|
|
33895
34868
|
]);
|
|
@@ -33903,7 +34876,7 @@ function storeProblemSentence(problem, root, home, engagementId) {
|
|
|
33903
34876
|
]);
|
|
33904
34877
|
case "no-id":
|
|
33905
34878
|
return sentences([
|
|
33906
|
-
`${
|
|
34879
|
+
`${resolve10(root, BUNDLE_PIN_REL)} names no engagement id.`,
|
|
33907
34880
|
'run "npx halfcycle" here to rewrite it.'
|
|
33908
34881
|
]);
|
|
33909
34882
|
case "bad-id":
|
|
@@ -33920,7 +34893,7 @@ function storeProblemSentence(problem, root, home, engagementId) {
|
|
|
33920
34893
|
case "no-credential":
|
|
33921
34894
|
return sentences([
|
|
33922
34895
|
`this machine holds no credential for engagement ${engagementId ?? ""}.`,
|
|
33923
|
-
`run "npx halfcycle" in this repository \u2014 it will sign you in through your browser if needed, and write the credential to ${
|
|
34896
|
+
`run "npx halfcycle" in this repository \u2014 it will sign you in through your browser if needed, and write the credential to ${resolve10(home, HALFCYCLE_DIR_NAME)}, outside this repository.`
|
|
33924
34897
|
]);
|
|
33925
34898
|
}
|
|
33926
34899
|
}
|
|
@@ -33943,7 +34916,7 @@ async function refreshWithinDeadline(source, opts, writeErr) {
|
|
|
33943
34916
|
}
|
|
33944
34917
|
async function chooseBearer(opts) {
|
|
33945
34918
|
const writeErr = opts.writeErr ?? defaultWriteErr;
|
|
33946
|
-
const home = opts.home ??
|
|
34919
|
+
const home = opts.home ?? homedir17();
|
|
33947
34920
|
const root = projectRootFromBinary(opts.binaryPath);
|
|
33948
34921
|
const environmentToken = opts.environmentTokenFirst ? readEnvironmentToken() : void 0;
|
|
33949
34922
|
const store = resolveStore(root, home);
|
|
@@ -34086,8 +35059,8 @@ async function refreshCredentialToken(opts) {
|
|
|
34086
35059
|
source
|
|
34087
35060
|
});
|
|
34088
35061
|
if (!refreshed.ok) {
|
|
34089
|
-
const
|
|
34090
|
-
|
|
35062
|
+
const write2 = opts?.write ?? ((text) => process.stdout.write(text));
|
|
35063
|
+
write2(credentialRenewalFailedMessage(refreshed.remedy));
|
|
34091
35064
|
return { token: void 0 };
|
|
34092
35065
|
}
|
|
34093
35066
|
return { token: refreshed.token };
|
|
@@ -34109,7 +35082,7 @@ var SESSION_START_PROBE_ATTEMPTS = 2;
|
|
|
34109
35082
|
function registeredMcpUrl(projectRoot) {
|
|
34110
35083
|
let parsed;
|
|
34111
35084
|
try {
|
|
34112
|
-
parsed = JSON.parse(readFileSync30(
|
|
35085
|
+
parsed = JSON.parse(readFileSync30(resolve11(projectRoot, MCP_REGISTRATION_REL), "utf-8"));
|
|
34113
35086
|
} catch {
|
|
34114
35087
|
return void 0;
|
|
34115
35088
|
}
|
|
@@ -34358,7 +35331,7 @@ async function runRefreshCredential(opts) {
|
|
|
34358
35331
|
import { fileURLToPath } from "node:url";
|
|
34359
35332
|
|
|
34360
35333
|
// dist/capture.js
|
|
34361
|
-
import { readFileSync as readFileSync31, writeFileSync as writeFileSync18, mkdirSync as mkdirSync12, existsSync as
|
|
35334
|
+
import { readFileSync as readFileSync31, writeFileSync as writeFileSync18, mkdirSync as mkdirSync12, existsSync as existsSync10 } from "node:fs";
|
|
34362
35335
|
import { dirname as dirname11 } from "node:path";
|
|
34363
35336
|
function runCapture(provider, endpoint, opts = {}) {
|
|
34364
35337
|
const repoRoot = opts.repoRoot ?? process.cwd();
|
|
@@ -34440,8 +35413,8 @@ function relativeFixturePath(repoRoot, fixture) {
|
|
|
34440
35413
|
import { spawn as spawn2, spawnSync as spawnSync3 } from "node:child_process";
|
|
34441
35414
|
import { createHash as createHash6, randomUUID as randomUUID3 } from "node:crypto";
|
|
34442
35415
|
import { createWriteStream, mkdirSync as mkdirSync13, readdirSync as readdirSync11, readFileSync as readFileSync32, renameSync as renameSync16, unlinkSync as unlinkSync12, writeFileSync as writeFileSync19 } from "node:fs";
|
|
34443
|
-
import { homedir as
|
|
34444
|
-
import { dirname as dirname12, join as
|
|
35416
|
+
import { homedir as homedir18 } from "node:os";
|
|
35417
|
+
import { dirname as dirname12, join as join23 } from "node:path";
|
|
34445
35418
|
|
|
34446
35419
|
// dist/test-counts.js
|
|
34447
35420
|
function sum(values) {
|
|
@@ -34550,7 +35523,7 @@ function isProofTestPath(path) {
|
|
|
34550
35523
|
function testRunsDir(engagementId, home) {
|
|
34551
35524
|
if (!isEngagementId(engagementId))
|
|
34552
35525
|
return null;
|
|
34553
|
-
return
|
|
35526
|
+
return join23(home ?? homedir18(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, TEST_RUNS_DIR_NAME);
|
|
34554
35527
|
}
|
|
34555
35528
|
function commandIdOf(command) {
|
|
34556
35529
|
return createHash6("sha256").update(command, "utf8").digest("hex").slice(0, 16);
|
|
@@ -34646,7 +35619,7 @@ function subjectKey(subject) {
|
|
|
34646
35619
|
}
|
|
34647
35620
|
function keptCheckPath(dir, subject, label) {
|
|
34648
35621
|
const key = createHash6("sha256").update(JSON.stringify([...subjectKey(subject), label]), "utf8").digest("hex");
|
|
34649
|
-
return
|
|
35622
|
+
return join23(dir, COMMANDS_DIR_NAME, `${key.slice(0, 32)}.json`);
|
|
34650
35623
|
}
|
|
34651
35624
|
function readKeptCheck(dir, subject, label) {
|
|
34652
35625
|
try {
|
|
@@ -34661,18 +35634,18 @@ function readKeptCheck(dir, subject, label) {
|
|
|
34661
35634
|
}
|
|
34662
35635
|
}
|
|
34663
35636
|
function queuePath(dir, runId) {
|
|
34664
|
-
return
|
|
35637
|
+
return join23(dir, QUEUE_DIR_NAME, `${runId}.json`);
|
|
34665
35638
|
}
|
|
34666
35639
|
function readQueue(dir) {
|
|
34667
35640
|
let names;
|
|
34668
35641
|
try {
|
|
34669
|
-
names = readdirSync11(
|
|
35642
|
+
names = readdirSync11(join23(dir, QUEUE_DIR_NAME)).filter((n) => n.endsWith(".json"));
|
|
34670
35643
|
} catch {
|
|
34671
35644
|
return [];
|
|
34672
35645
|
}
|
|
34673
35646
|
const reports = [];
|
|
34674
35647
|
for (const name of names) {
|
|
34675
|
-
const path =
|
|
35648
|
+
const path = join23(dir, QUEUE_DIR_NAME, name);
|
|
34676
35649
|
let parsed = null;
|
|
34677
35650
|
try {
|
|
34678
35651
|
parsed = testRunReportSchema.safeParse(JSON.parse(readFileSync32(path, "utf-8")));
|
|
@@ -34745,17 +35718,17 @@ function killTree(child, platform4, signal) {
|
|
|
34745
35718
|
}
|
|
34746
35719
|
}
|
|
34747
35720
|
}
|
|
34748
|
-
function runCommand(command, repoRoot,
|
|
35721
|
+
function runCommand(command, repoRoot, logPath2, env, deps) {
|
|
34749
35722
|
const platform4 = deps.platform ?? process.platform;
|
|
34750
35723
|
const out = deps.stdout ?? process.stdout;
|
|
34751
35724
|
const err = deps.stderr ?? process.stderr;
|
|
34752
35725
|
const deadline = deps.deadlineMs ?? PROVE_RUN_DEADLINE_MS;
|
|
34753
35726
|
const childEnv = { ...env };
|
|
34754
35727
|
delete childEnv[SERVICE_TOKEN_VAR];
|
|
34755
|
-
mkdirSync13(dirname12(
|
|
34756
|
-
const log = createWriteStream(
|
|
35728
|
+
mkdirSync13(dirname12(logPath2), { recursive: true, mode: 448 });
|
|
35729
|
+
const log = createWriteStream(logPath2, { mode: 384 });
|
|
34757
35730
|
const began = process.hrtime.bigint();
|
|
34758
|
-
return new Promise((
|
|
35731
|
+
return new Promise((resolve12) => {
|
|
34759
35732
|
let timedOut = false;
|
|
34760
35733
|
let started = true;
|
|
34761
35734
|
let settled2 = false;
|
|
@@ -34790,7 +35763,7 @@ function runCommand(command, repoRoot, logPath, env, deps) {
|
|
|
34790
35763
|
process.off("SIGINT", onSignal);
|
|
34791
35764
|
process.off("SIGTERM", onSignal);
|
|
34792
35765
|
const durationMs = Number((process.hrtime.bigint() - began) / 1000000n);
|
|
34793
|
-
log.end(() =>
|
|
35766
|
+
log.end(() => resolve12({ exitCode: timedOut || !started ? null : code, timedOut, started, durationMs }));
|
|
34794
35767
|
};
|
|
34795
35768
|
child.on("error", (e) => {
|
|
34796
35769
|
started = false;
|
|
@@ -34912,13 +35885,13 @@ ${PROVE_USAGE}`);
|
|
|
34912
35885
|
if (request.when === "before" && changedOutsideTests > 0)
|
|
34913
35886
|
say(lateBeforeLine(changedOutsideTests));
|
|
34914
35887
|
const runId = randomUUID3();
|
|
34915
|
-
const
|
|
35888
|
+
const logPath2 = join23(dir, `${runId}.log`);
|
|
34916
35889
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
34917
35890
|
const deadline = deps.deadlineMs ?? PROVE_RUN_DEADLINE_MS;
|
|
34918
|
-
const end = await runCommand(command, repoRoot,
|
|
35891
|
+
const end = await runCommand(command, repoRoot, logPath2, env, deps);
|
|
34919
35892
|
let output = "";
|
|
34920
35893
|
try {
|
|
34921
|
-
output = readFileSync32(
|
|
35894
|
+
output = readFileSync32(logPath2, "utf-8");
|
|
34922
35895
|
} catch {
|
|
34923
35896
|
output = "";
|
|
34924
35897
|
}
|
|
@@ -34962,7 +35935,7 @@ ${PROVE_USAGE}`);
|
|
|
34962
35935
|
sendLine = mine.outcome === "recorded" ? RECORDED_LINE : mine.outcome === "kept" ? NOT_SENT_YET_LINE : refusedLine(mine.refusal);
|
|
34963
35936
|
}
|
|
34964
35937
|
say(`${line2} ${sendLine}`);
|
|
34965
|
-
say(`Its output is kept on this computer at ${
|
|
35938
|
+
say(`Its output is kept on this computer at ${logPath2}`);
|
|
34966
35939
|
return 0;
|
|
34967
35940
|
}
|
|
34968
35941
|
|
|
@@ -35030,14 +36003,14 @@ function personCommandEnv(env) {
|
|
|
35030
36003
|
}
|
|
35031
36004
|
return out;
|
|
35032
36005
|
}
|
|
35033
|
-
var runOwnCommandReal = (command, input, env) => new Promise((
|
|
36006
|
+
var runOwnCommandReal = (command, input, env) => new Promise((resolve12) => {
|
|
35034
36007
|
let out = "";
|
|
35035
36008
|
let settled2 = false;
|
|
35036
36009
|
const done = (v) => {
|
|
35037
36010
|
if (settled2)
|
|
35038
36011
|
return;
|
|
35039
36012
|
settled2 = true;
|
|
35040
|
-
|
|
36013
|
+
resolve12(v);
|
|
35041
36014
|
};
|
|
35042
36015
|
try {
|
|
35043
36016
|
const child = spawn3(command, {
|
|
@@ -35185,7 +36158,7 @@ async function main() {
|
|
|
35185
36158
|
if (cmd === "time") {
|
|
35186
36159
|
let line2;
|
|
35187
36160
|
try {
|
|
35188
|
-
line2 = JSON.stringify(await runTimeVerb());
|
|
36161
|
+
line2 = JSON.stringify(await runTimeVerb({}, { final: args.slice(1).includes("--final") }));
|
|
35189
36162
|
} catch {
|
|
35190
36163
|
line2 = JSON.stringify({ outcome: "not-sent", reason: "unreachable" });
|
|
35191
36164
|
}
|
|
@@ -35351,7 +36324,7 @@ function unknownCommand(name = args.join(" ")) {
|
|
|
35351
36324
|
halfcycle-runner mcp-headers [--url <address>]
|
|
35352
36325
|
halfcycle-runner observe
|
|
35353
36326
|
halfcycle-runner observe --change <sortingId>
|
|
35354
|
-
halfcycle-runner time
|
|
36327
|
+
halfcycle-runner time [--final]
|
|
35355
36328
|
halfcycle-runner prove <phase> <task> --label <label> --before|--after [-- <command>]
|
|
35356
36329
|
halfcycle-runner pace [--start <phase> [--agents <n>]]
|
|
35357
36330
|
halfcycle-runner pace --scan [--config-folder <dir>]
|
|
@@ -35362,10 +36335,10 @@ function unknownCommand(name = args.join(" ")) {
|
|
|
35362
36335
|
process.exit(1);
|
|
35363
36336
|
}
|
|
35364
36337
|
function readStdin3() {
|
|
35365
|
-
return new Promise((
|
|
36338
|
+
return new Promise((resolve12, reject) => {
|
|
35366
36339
|
const chunks = [];
|
|
35367
36340
|
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
35368
|
-
process.stdin.on("end", () =>
|
|
36341
|
+
process.stdin.on("end", () => resolve12(Buffer.concat(chunks).toString("utf-8")));
|
|
35369
36342
|
process.stdin.on("error", reject);
|
|
35370
36343
|
});
|
|
35371
36344
|
}
|