halfcycle 0.7.0 → 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 +1649 -628
- 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 {
|
|
@@ -23048,6 +23312,19 @@ function accountKeysOf(path) {
|
|
|
23048
23312
|
return typeof accounts === "object" && accounts !== null && !Array.isArray(accounts) ? Object.keys(accounts) : [];
|
|
23049
23313
|
}
|
|
23050
23314
|
var PACE_STATE_FILENAME = "state.json";
|
|
23315
|
+
function toldOf(v) {
|
|
23316
|
+
if (typeof v !== "object" || v === null || Array.isArray(v))
|
|
23317
|
+
return null;
|
|
23318
|
+
const o = v;
|
|
23319
|
+
const pace = paceStateSchema.safeParse(o["pace"]);
|
|
23320
|
+
const kind = o["windowKind"] === null ? null : paceWindowKindSchema.safeParse(o["windowKind"]);
|
|
23321
|
+
const allowance = o["allowance"];
|
|
23322
|
+
if (!pace.success || kind !== null && !kind.success)
|
|
23323
|
+
return null;
|
|
23324
|
+
if (typeof allowance !== "number" || !Number.isInteger(allowance) || allowance < 0)
|
|
23325
|
+
return null;
|
|
23326
|
+
return { pace: pace.data, allowance, windowKind: kind === null ? null : kind.data };
|
|
23327
|
+
}
|
|
23051
23328
|
function paceStateEntryOf(v) {
|
|
23052
23329
|
if (typeof v !== "object" || v === null || Array.isArray(v))
|
|
23053
23330
|
return null;
|
|
@@ -23069,7 +23346,17 @@ function paceStateEntryOf(v) {
|
|
|
23069
23346
|
if (typeof at !== "string" || Number.isNaN(Date.parse(at)))
|
|
23070
23347
|
return null;
|
|
23071
23348
|
const offered = Array.isArray(o["offeredFor"]) ? o["offeredFor"].filter((t) => typeof t === "string" && !Number.isNaN(Date.parse(t))) : [];
|
|
23072
|
-
|
|
23349
|
+
const told = toldOf(o["told"]);
|
|
23350
|
+
return {
|
|
23351
|
+
pace: pace.data,
|
|
23352
|
+
allowance,
|
|
23353
|
+
number: number4,
|
|
23354
|
+
windowKind: kind === null ? null : kind.data,
|
|
23355
|
+
until,
|
|
23356
|
+
at,
|
|
23357
|
+
...offered.length > 0 ? { offeredFor: offered } : {},
|
|
23358
|
+
...told === null ? {} : { told }
|
|
23359
|
+
};
|
|
23073
23360
|
}
|
|
23074
23361
|
function rememberedBasisOf(v) {
|
|
23075
23362
|
if (typeof v !== "object" || v === null || Array.isArray(v))
|
|
@@ -23100,8 +23387,14 @@ function writePaceState(dir, key, entry, basis) {
|
|
|
23100
23387
|
if (entry === null)
|
|
23101
23388
|
delete accounts[key];
|
|
23102
23389
|
else {
|
|
23103
|
-
const
|
|
23104
|
-
|
|
23390
|
+
const last = current.accounts[key];
|
|
23391
|
+
const kept = entry.offeredFor ?? last?.offeredFor;
|
|
23392
|
+
const told = entry.told ?? last?.told ?? (last === void 0 ? { pace: "full", allowance: entry.allowance, windowKind: null } : void 0);
|
|
23393
|
+
accounts[key] = {
|
|
23394
|
+
...entry,
|
|
23395
|
+
...kept === void 0 ? {} : { offeredFor: kept },
|
|
23396
|
+
...told === void 0 ? {} : { told }
|
|
23397
|
+
};
|
|
23105
23398
|
}
|
|
23106
23399
|
writeJsonWhole(nodePath.join(dir, PACE_STATE_FILENAME), { accounts, basis: basis ?? current.basis });
|
|
23107
23400
|
}
|
|
@@ -23406,7 +23699,7 @@ function resolvedRecords(key, path) {
|
|
|
23406
23699
|
}
|
|
23407
23700
|
}
|
|
23408
23701
|
function timeLogTranscripts(home) {
|
|
23409
|
-
const engagements = nodePath.join(home ??
|
|
23702
|
+
const engagements = nodePath.join(home ?? homedir6(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME);
|
|
23410
23703
|
const out = [];
|
|
23411
23704
|
for (const e of dirents(engagements)) {
|
|
23412
23705
|
if (!e.isDirectory())
|
|
@@ -23425,7 +23718,7 @@ function timeLogTranscripts(home) {
|
|
|
23425
23718
|
}
|
|
23426
23719
|
function teacherOf(key, deps = {}) {
|
|
23427
23720
|
const path = deps.path ?? nodePath;
|
|
23428
|
-
const home = deps.home ??
|
|
23721
|
+
const home = deps.home ?? homedir6();
|
|
23429
23722
|
const ours = resolvedRecords(key, path);
|
|
23430
23723
|
if (ours === null)
|
|
23431
23724
|
return { shared: false, teaches: () => false };
|
|
@@ -23595,13 +23888,13 @@ function knownWindowOf(learned, reported, now) {
|
|
|
23595
23888
|
|
|
23596
23889
|
// dist/phase-limit.js
|
|
23597
23890
|
import { mkdirSync as mkdirSync4, readFileSync as readFileSync13, renameSync as renameSync4, rmSync, writeFileSync as writeFileSync6 } from "node:fs";
|
|
23598
|
-
import { homedir as
|
|
23891
|
+
import { homedir as homedir7 } from "node:os";
|
|
23599
23892
|
import nodePath2 from "node:path";
|
|
23600
23893
|
var PHASE_USAGE_FILENAME = "phase-usage.json";
|
|
23601
23894
|
function phaseLimitDir(engagementId, home) {
|
|
23602
23895
|
if (!isEngagementId(engagementId))
|
|
23603
23896
|
return null;
|
|
23604
|
-
return nodePath2.join(home ??
|
|
23897
|
+
return nodePath2.join(home ?? homedir7(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, PACING_DIR_NAME);
|
|
23605
23898
|
}
|
|
23606
23899
|
function readJsonFile(path) {
|
|
23607
23900
|
try {
|
|
@@ -23649,16 +23942,14 @@ function readPhaseUsage(dir, phase, openedAt = null) {
|
|
|
23649
23942
|
return 0;
|
|
23650
23943
|
return parsed.data.tokens;
|
|
23651
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
|
+
}
|
|
23652
23949
|
function writePhaseUsage(dir, file2) {
|
|
23653
23950
|
if (!phaseUsageFileSchema.safeParse(file2).success)
|
|
23654
|
-
return;
|
|
23655
|
-
writeWhole(nodePath2.join(dir, PHASE_USAGE_FILENAME), file2);
|
|
23656
|
-
}
|
|
23657
|
-
function phaseTokensOf(buckets) {
|
|
23658
|
-
let total = 0;
|
|
23659
|
-
for (const b of buckets)
|
|
23660
|
-
total += b.inputTokens + b.outputTokens + b.cacheWriteTokens + b.cacheReadTokens;
|
|
23661
|
-
return Math.max(0, Math.round(total));
|
|
23951
|
+
return false;
|
|
23952
|
+
return writeWhole(nodePath2.join(dir, PHASE_USAGE_FILENAME), file2);
|
|
23662
23953
|
}
|
|
23663
23954
|
function roundTokens(n) {
|
|
23664
23955
|
return Math.max(LIMIT_ROUND_TOKENS, Math.round(n / LIMIT_ROUND_TOKENS) * LIMIT_ROUND_TOKENS);
|
|
@@ -23836,6 +24127,164 @@ function setLimit(file2, limit, multiple, used, by, at) {
|
|
|
23836
24127
|
};
|
|
23837
24128
|
}
|
|
23838
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
|
+
|
|
23839
24288
|
// dist/time-record.js
|
|
23840
24289
|
var TIME_EVENT_KINDS = ["action", "asked", "edit", "turn-end", "lock-wait-start", "lock-wait-end"];
|
|
23841
24290
|
function isLockWaitEvent(event) {
|
|
@@ -23849,25 +24298,25 @@ function inputString(input, key) {
|
|
|
23849
24298
|
const value = input[key];
|
|
23850
24299
|
return typeof value === "string" && value !== "" ? value : null;
|
|
23851
24300
|
}
|
|
23852
|
-
function readBranch(
|
|
23853
|
-
const copy = whichCopy(
|
|
24301
|
+
function readBranch(folder2, deps = {}) {
|
|
24302
|
+
const copy = whichCopy(folder2, deps);
|
|
23854
24303
|
return copy === null ? null : copyBranch(copy, deps);
|
|
23855
24304
|
}
|
|
23856
24305
|
function timeLogPath(engagementId, home) {
|
|
23857
24306
|
if (!isEngagementId(engagementId))
|
|
23858
24307
|
return null;
|
|
23859
|
-
return
|
|
24308
|
+
return join11(home ?? homedir8(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, TIME_LOG_DIR_NAME, TIME_LOG_FILENAME);
|
|
23860
24309
|
}
|
|
23861
24310
|
function timeEventLine(event, input, deps = {}) {
|
|
23862
24311
|
const at = (deps.now ?? (() => /* @__PURE__ */ new Date()))().toISOString();
|
|
23863
|
-
const
|
|
24312
|
+
const folder2 = inputString(input, "cwd") ?? (deps.cwd ?? (() => process.cwd()))();
|
|
23864
24313
|
return {
|
|
23865
24314
|
at,
|
|
23866
24315
|
event,
|
|
23867
24316
|
session: inputString(input, "session_id"),
|
|
23868
24317
|
agent: inputString(input, "agent_id"),
|
|
23869
|
-
folder,
|
|
23870
|
-
branch: readBranch(
|
|
24318
|
+
folder: folder2,
|
|
24319
|
+
branch: readBranch(folder2),
|
|
23871
24320
|
transcript: inputString(input, "transcript_path"),
|
|
23872
24321
|
toolUse: inputString(input, "tool_use_id"),
|
|
23873
24322
|
rollout: inputString(input, "rollout_path")
|
|
@@ -23885,12 +24334,12 @@ function recordTimeEvent(event, input, deps = {}) {
|
|
|
23885
24334
|
const text = `${JSON.stringify(line2)}
|
|
23886
24335
|
`;
|
|
23887
24336
|
try {
|
|
23888
|
-
|
|
24337
|
+
appendFileSync3(path, text, { mode: 384 });
|
|
23889
24338
|
} catch (err) {
|
|
23890
24339
|
if (err.code !== "ENOENT")
|
|
23891
24340
|
return;
|
|
23892
|
-
|
|
23893
|
-
|
|
24341
|
+
mkdirSync6(dirname4(path), { recursive: true, mode: 448 });
|
|
24342
|
+
appendFileSync3(path, text, { mode: 384 });
|
|
23894
24343
|
}
|
|
23895
24344
|
} catch {
|
|
23896
24345
|
}
|
|
@@ -23949,7 +24398,7 @@ function readSessionTimeLines(sessionId, deps = {}) {
|
|
|
23949
24398
|
if (path === null)
|
|
23950
24399
|
return [];
|
|
23951
24400
|
const needle = JSON.stringify(sessionId);
|
|
23952
|
-
const kept =
|
|
24401
|
+
const kept = readFileSync15(path, "utf-8").split("\n").filter((raw) => raw.includes(needle));
|
|
23953
24402
|
return parseTimeLog(kept.join("\n")).filter((line2) => line2.session === sessionId);
|
|
23954
24403
|
} catch {
|
|
23955
24404
|
return [];
|
|
@@ -23976,8 +24425,8 @@ function separatorOf(path) {
|
|
|
23976
24425
|
function subagentsFolderOf(transcript) {
|
|
23977
24426
|
if (!transcript.endsWith(".jsonl") || transcript.length === ".jsonl".length)
|
|
23978
24427
|
return null;
|
|
23979
|
-
const
|
|
23980
|
-
return `${transcript.slice(0, -".jsonl".length)}${
|
|
24428
|
+
const sep8 = separatorOf(transcript);
|
|
24429
|
+
return `${transcript.slice(0, -".jsonl".length)}${sep8}subagents`;
|
|
23981
24430
|
}
|
|
23982
24431
|
function subagentRecordName(agentId) {
|
|
23983
24432
|
return /^[A-Za-z0-9_-]+$/.test(agentId) ? `agent-${agentId}.jsonl` : null;
|
|
@@ -23985,12 +24434,12 @@ function subagentRecordName(agentId) {
|
|
|
23985
24434
|
function subagentRecordPath(transcript, agentId) {
|
|
23986
24435
|
if (transcript === null)
|
|
23987
24436
|
return null;
|
|
23988
|
-
const
|
|
24437
|
+
const folder2 = subagentsFolderOf(transcript);
|
|
23989
24438
|
const name = subagentRecordName(agentId);
|
|
23990
|
-
return
|
|
24439
|
+
return folder2 === null || name === null ? null : `${folder2}${separatorOf(transcript)}${name}`;
|
|
23991
24440
|
}
|
|
23992
|
-
function folderParts(
|
|
23993
|
-
return
|
|
24441
|
+
function folderParts(folder2) {
|
|
24442
|
+
return folder2.split(/[\\/]+/).filter((part, i) => part !== "" || i === 0);
|
|
23994
24443
|
}
|
|
23995
24444
|
function folderHolds(outer, inner) {
|
|
23996
24445
|
const o = folderParts(outer);
|
|
@@ -24043,15 +24492,52 @@ function buildLanes(events, taskIds) {
|
|
|
24043
24492
|
});
|
|
24044
24493
|
}
|
|
24045
24494
|
var UNREADABLE2 = { readable: false, lines: [] };
|
|
24046
|
-
function
|
|
24047
|
-
|
|
24048
|
-
|
|
24049
|
-
|
|
24050
|
-
|
|
24051
|
-
|
|
24052
|
-
|
|
24053
|
-
|
|
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;
|
|
24054
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) {
|
|
24055
24541
|
const lines2 = [];
|
|
24056
24542
|
for (const raw of text.split("\n")) {
|
|
24057
24543
|
if (raw.trim() === "")
|
|
@@ -24062,29 +24548,129 @@ function viewRecord(path, deps) {
|
|
|
24062
24548
|
} catch {
|
|
24063
24549
|
continue;
|
|
24064
24550
|
}
|
|
24065
|
-
|
|
24066
|
-
|
|
24067
|
-
const o = value;
|
|
24068
|
-
if (typeof o["type"] !== "string")
|
|
24551
|
+
const o = plainObject(value);
|
|
24552
|
+
if (o === null || typeof o["type"] !== "string")
|
|
24069
24553
|
continue;
|
|
24070
|
-
|
|
24071
|
-
|
|
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;
|
|
24564
|
+
}
|
|
24565
|
+
const lines2 = recordLinesOf(text);
|
|
24566
|
+
return lines2.length === 0 ? UNREADABLE2 : { readable: true, lines: lines2 };
|
|
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;
|
|
24072
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));
|
|
24073
24622
|
return lines2.length === 0 ? UNREADABLE2 : { readable: true, lines: lines2 };
|
|
24074
24623
|
}
|
|
24624
|
+
var viewsOfOffsets = /* @__PURE__ */ new WeakMap();
|
|
24075
24625
|
function recordReader(deps) {
|
|
24076
|
-
|
|
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
|
+
}
|
|
24077
24631
|
return (path) => {
|
|
24078
24632
|
if (path === null)
|
|
24079
24633
|
return UNREADABLE2;
|
|
24080
24634
|
const hit = cache2.get(path);
|
|
24081
24635
|
if (hit !== void 0)
|
|
24082
24636
|
return hit;
|
|
24083
|
-
const view = viewRecord(path, deps);
|
|
24637
|
+
const view = deps.offsets === void 0 ? viewRecord(path, deps) : viewRecordFrom(path, deps, deps.offsets);
|
|
24084
24638
|
cache2.set(path, view);
|
|
24085
24639
|
return view;
|
|
24086
24640
|
};
|
|
24087
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
|
+
}
|
|
24088
24674
|
function isPrompt(line2) {
|
|
24089
24675
|
const o = line2.value;
|
|
24090
24676
|
if (o["type"] !== "user" || line2.t === null || "toolUseResult" in o)
|
|
@@ -24275,7 +24861,76 @@ function tokensOf(usage) {
|
|
|
24275
24861
|
}
|
|
24276
24862
|
return out;
|
|
24277
24863
|
}
|
|
24278
|
-
|
|
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) {
|
|
24899
|
+
let next;
|
|
24900
|
+
for (const lane of own) {
|
|
24901
|
+
if (lane.task === null)
|
|
24902
|
+
continue;
|
|
24903
|
+
const after = lane.events.map((e) => msOf(e.at)).find((at) => at > t);
|
|
24904
|
+
if (after !== void 0 && (next === void 0 || after < next.t))
|
|
24905
|
+
next = { task: lane.task, t: after };
|
|
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);
|
|
24915
|
+
if (before !== void 0 && (last === void 0 || before >= last.t))
|
|
24916
|
+
last = { task: lane.task, t: before };
|
|
24917
|
+
}
|
|
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;
|
|
24932
|
+
}
|
|
24933
|
+
function readUsage(lanes, window, deps = {}, models, settling = {}) {
|
|
24279
24934
|
const from = Date.parse(window.from);
|
|
24280
24935
|
const to = window.to === void 0 || window.to === null ? Infinity : Date.parse(window.to);
|
|
24281
24936
|
const inWindow = (t) => t >= from && t <= to;
|
|
@@ -24291,6 +24946,28 @@ function readUsage(lanes, window, deps = {}, models) {
|
|
|
24291
24946
|
return buckets.get(key) ?? buckets.set(key, { source, task, readable, messages: 0, inputTokens: 0, outputTokens: 0, cacheWriteTokens: 0, cacheReadTokens: 0 }).get(key);
|
|
24292
24947
|
};
|
|
24293
24948
|
const seen = /* @__PURE__ */ new Set();
|
|
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
|
+
};
|
|
24294
24971
|
const count = (path, view, taskAt) => {
|
|
24295
24972
|
const source = recordSourceOf(path);
|
|
24296
24973
|
for (const line2 of view.lines) {
|
|
@@ -24301,13 +24978,17 @@ function readUsage(lanes, window, deps = {}, models) {
|
|
|
24301
24978
|
if (typeof message !== "object" || message === null)
|
|
24302
24979
|
continue;
|
|
24303
24980
|
const id = message["id"];
|
|
24304
|
-
if (typeof id !== "string" || id === "" || seen.has(id))
|
|
24981
|
+
if (typeof id !== "string" || id === "" || seen.has(id) || held.has(id))
|
|
24305
24982
|
continue;
|
|
24306
24983
|
const tokens = tokensOf(message["usage"]);
|
|
24307
24984
|
if (tokens === null)
|
|
24308
24985
|
continue;
|
|
24986
|
+
const task = taskAt(line2, id);
|
|
24987
|
+
if (task === void 0) {
|
|
24988
|
+
held.add(id);
|
|
24989
|
+
continue;
|
|
24990
|
+
}
|
|
24309
24991
|
seen.add(id);
|
|
24310
|
-
const task = taskAt(line2);
|
|
24311
24992
|
const bucket = bucketFor(source, task, true);
|
|
24312
24993
|
bucket.messages += 1;
|
|
24313
24994
|
const model = message["model"];
|
|
@@ -24323,41 +25004,76 @@ function readUsage(lanes, window, deps = {}, models) {
|
|
|
24323
25004
|
};
|
|
24324
25005
|
for (const main2 of mains) {
|
|
24325
25006
|
const view = read(main2);
|
|
25007
|
+
addToFigure(view);
|
|
24326
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
|
+
}
|
|
24327
25016
|
count(main2, view, (line2) => {
|
|
25017
|
+
if (line2.t >= coordinatingFrom)
|
|
25018
|
+
return null;
|
|
24328
25019
|
const branch = line2.value["gitBranch"];
|
|
24329
25020
|
return taskOfBranch(typeof branch === "string" ? branch : null, window.taskIds);
|
|
24330
25021
|
});
|
|
24331
25022
|
}
|
|
24332
|
-
const
|
|
24333
|
-
if (
|
|
25023
|
+
const folder2 = subagentsFolderOf(main2);
|
|
25024
|
+
if (folder2 === null)
|
|
24334
25025
|
continue;
|
|
24335
25026
|
let names;
|
|
24336
25027
|
try {
|
|
24337
|
-
names = listDir(
|
|
25028
|
+
names = listDir(folder2).filter((name) => /^agent-[A-Za-z0-9_-]+\.jsonl$/.test(name)).sort();
|
|
24338
25029
|
} catch {
|
|
24339
25030
|
continue;
|
|
24340
25031
|
}
|
|
24341
25032
|
for (const name of names) {
|
|
24342
|
-
const path = `${
|
|
25033
|
+
const path = `${folder2}${separatorOf(main2)}${name}`;
|
|
24343
25034
|
const view2 = read(path);
|
|
25035
|
+
addToFigure(view2);
|
|
24344
25036
|
if (!view2.readable)
|
|
24345
25037
|
continue;
|
|
24346
25038
|
const agent = name.slice("agent-".length, -".jsonl".length);
|
|
24347
25039
|
const own = active.filter((lane) => lane.agent === agent && lane.transcript === main2);
|
|
24348
25040
|
if (own.length === 0)
|
|
24349
25041
|
continue;
|
|
24350
|
-
|
|
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;
|
|
24351
25046
|
let best;
|
|
24352
|
-
for (const
|
|
24353
|
-
const latest = lastAtOrBefore(
|
|
25047
|
+
for (const lane2 of own) {
|
|
25048
|
+
const latest = lastAtOrBefore(lane2.events.map((e) => msOf(e.at)), t);
|
|
24354
25049
|
if (latest !== void 0 && (best === void 0 || latest >= best.t))
|
|
24355
|
-
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);
|
|
24356
25072
|
}
|
|
24357
|
-
if (
|
|
24358
|
-
|
|
24359
|
-
|
|
24360
|
-
return
|
|
25073
|
+
if (task === null)
|
|
25074
|
+
task = lastTaskOf(ownAll, t);
|
|
25075
|
+
settled2.set(id, task);
|
|
25076
|
+
return task;
|
|
24361
25077
|
});
|
|
24362
25078
|
}
|
|
24363
25079
|
}
|
|
@@ -24380,6 +25096,8 @@ function readUsage(lanes, window, deps = {}, models) {
|
|
|
24380
25096
|
best = { lane, t: latest };
|
|
24381
25097
|
}
|
|
24382
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;
|
|
24383
25101
|
bucket.messages += 1;
|
|
24384
25102
|
bucket.inputTokens += step.inputTokens;
|
|
24385
25103
|
bucket.outputTokens += step.outputTokens;
|
|
@@ -24400,13 +25118,13 @@ var PHASE_MODELS_FILENAME = "phase-models.json";
|
|
|
24400
25118
|
function phaseModelsPath(engagementId, home) {
|
|
24401
25119
|
if (!isEngagementId(engagementId))
|
|
24402
25120
|
return null;
|
|
24403
|
-
return
|
|
25121
|
+
return join11(home ?? homedir8(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, PACING_DIR_NAME, PHASE_MODELS_FILENAME);
|
|
24404
25122
|
}
|
|
24405
25123
|
function writePhaseModels(path, phase, openedAt, tally) {
|
|
24406
25124
|
try {
|
|
24407
25125
|
let tasks = {};
|
|
24408
25126
|
try {
|
|
24409
|
-
const prior = phaseModelsFileSchema.safeParse(JSON.parse(
|
|
25127
|
+
const prior = phaseModelsFileSchema.safeParse(JSON.parse(readFileSync15(path, "utf-8")));
|
|
24410
25128
|
if (prior.success && prior.data.phase === phase && prior.data.openedAt === openedAt)
|
|
24411
25129
|
tasks = prior.data.tasks;
|
|
24412
25130
|
} catch {
|
|
@@ -24434,14 +25152,14 @@ function timeLogDir(engagementId, home) {
|
|
|
24434
25152
|
return path === null ? null : dirname4(path);
|
|
24435
25153
|
}
|
|
24436
25154
|
function writeJsonFile(path, value) {
|
|
24437
|
-
|
|
25155
|
+
mkdirSync6(dirname4(path), { recursive: true, mode: 448 });
|
|
24438
25156
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
24439
|
-
|
|
24440
|
-
|
|
25157
|
+
writeFileSync8(tmp, JSON.stringify(value), { mode: 384 });
|
|
25158
|
+
renameSync6(tmp, path);
|
|
24441
25159
|
}
|
|
24442
25160
|
function readAttemptedAt(dir) {
|
|
24443
25161
|
try {
|
|
24444
|
-
const parsed = JSON.parse(
|
|
25162
|
+
const parsed = JSON.parse(readFileSync15(join11(dir, TIME_THROTTLE_FILENAME), "utf-8"));
|
|
24445
25163
|
return typeof parsed.attemptedAt === "number" ? parsed.attemptedAt : null;
|
|
24446
25164
|
} catch {
|
|
24447
25165
|
return null;
|
|
@@ -24449,7 +25167,7 @@ function readAttemptedAt(dir) {
|
|
|
24449
25167
|
}
|
|
24450
25168
|
function writeAttemptedAt(dir, at) {
|
|
24451
25169
|
try {
|
|
24452
|
-
writeJsonFile(
|
|
25170
|
+
writeJsonFile(join11(dir, TIME_THROTTLE_FILENAME), { attemptedAt: at });
|
|
24453
25171
|
} catch {
|
|
24454
25172
|
}
|
|
24455
25173
|
}
|
|
@@ -24467,7 +25185,7 @@ function stringRecord(value) {
|
|
|
24467
25185
|
function readTimeCursor(dir, phase, openedAt) {
|
|
24468
25186
|
const fresh = { phase, openedAt, sentThrough: null, sentIds: {}, usage: {} };
|
|
24469
25187
|
try {
|
|
24470
|
-
const o = JSON.parse(
|
|
25188
|
+
const o = JSON.parse(readFileSync15(join11(dir, TIME_CURSOR_FILENAME), "utf-8"));
|
|
24471
25189
|
if (o["phase"] !== phase || o["openedAt"] !== openedAt)
|
|
24472
25190
|
return fresh;
|
|
24473
25191
|
const sentThrough = o["sentThrough"];
|
|
@@ -24480,6 +25198,29 @@ function readTimeCursor(dir, phase, openedAt) {
|
|
|
24480
25198
|
return fresh;
|
|
24481
25199
|
}
|
|
24482
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
|
+
}
|
|
24483
25224
|
function usageKey(bucket) {
|
|
24484
25225
|
return `${bucket.source}\0${bucket.task ?? ""}`;
|
|
24485
25226
|
}
|
|
@@ -24566,33 +25307,33 @@ var PRUNE_SETTLE_MS = 50;
|
|
|
24566
25307
|
async function pruneTimeLog(path, openedAt) {
|
|
24567
25308
|
const aside = `${path}.prune-${process.pid}`;
|
|
24568
25309
|
try {
|
|
24569
|
-
|
|
25310
|
+
renameSync6(path, aside);
|
|
24570
25311
|
} catch {
|
|
24571
25312
|
return;
|
|
24572
25313
|
}
|
|
24573
25314
|
let text = "";
|
|
24574
25315
|
let written = false;
|
|
24575
25316
|
try {
|
|
24576
|
-
text =
|
|
25317
|
+
text = readFileSync15(aside, "utf-8");
|
|
24577
25318
|
const { kept } = prunedTimeLog(text, openedAt);
|
|
24578
25319
|
if (kept !== "")
|
|
24579
|
-
|
|
25320
|
+
appendFileSync3(path, kept, { mode: 384 });
|
|
24580
25321
|
written = true;
|
|
24581
25322
|
let seen = Buffer.byteLength(text, "utf-8");
|
|
24582
25323
|
for (; ; ) {
|
|
24583
|
-
await new Promise((
|
|
24584
|
-
const after =
|
|
25324
|
+
await new Promise((resolve12) => setTimeout(resolve12, PRUNE_SETTLE_MS));
|
|
25325
|
+
const after = readFileSync15(aside);
|
|
24585
25326
|
if (after.length <= seen)
|
|
24586
25327
|
break;
|
|
24587
|
-
|
|
25328
|
+
appendFileSync3(path, after.subarray(seen), { mode: 384 });
|
|
24588
25329
|
seen = after.length;
|
|
24589
25330
|
}
|
|
24590
|
-
|
|
25331
|
+
unlinkSync5(aside);
|
|
24591
25332
|
} catch {
|
|
24592
25333
|
try {
|
|
24593
25334
|
if (!written) {
|
|
24594
|
-
|
|
24595
|
-
|
|
25335
|
+
appendFileSync3(path, readFileSync15(aside, "utf-8"), { mode: 384 });
|
|
25336
|
+
unlinkSync5(aside);
|
|
24596
25337
|
}
|
|
24597
25338
|
} catch {
|
|
24598
25339
|
}
|
|
@@ -24607,7 +25348,17 @@ function conflictReason(body) {
|
|
|
24607
25348
|
const error51 = body.error;
|
|
24608
25349
|
return error51 === "basis-moved" || error51 === "phase-closed" ? error51 : null;
|
|
24609
25350
|
}
|
|
24610
|
-
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) {
|
|
24611
25362
|
const fetchFn = deps.fetchFn ?? globalThis.fetch;
|
|
24612
25363
|
const base = `${controlOrigin}/engagements/${encodeURIComponent(config2.guardEngagementId)}/time`;
|
|
24613
25364
|
const authorization = `Bearer ${config2.guardServiceToken}`;
|
|
@@ -24625,25 +25376,38 @@ async function attemptTimeRecord(config2, controlOrigin, deps = {}) {
|
|
|
24625
25376
|
const basis = parsedBasis.data;
|
|
24626
25377
|
if (basis.outcome === "nothing-to-record")
|
|
24627
25378
|
return { outcome: "not-sent", reason: "nothing-to-record" };
|
|
24628
|
-
const
|
|
25379
|
+
const logPath2 = join11(dir, TIME_LOG_FILENAME);
|
|
24629
25380
|
let text = "";
|
|
24630
25381
|
try {
|
|
24631
|
-
text =
|
|
25382
|
+
text = readFileSync15(logPath2, "utf-8");
|
|
24632
25383
|
} catch {
|
|
24633
25384
|
text = "";
|
|
24634
25385
|
}
|
|
24635
25386
|
const lanes = buildLanes(parseTimeLog(text), basis.taskIds);
|
|
24636
|
-
const
|
|
25387
|
+
const offsets = loadReadOffsets(dir, basis.phase, basis.openedAt);
|
|
25388
|
+
const readDeps = { ...deps, offsets };
|
|
25389
|
+
const intervals = buildIntervals(lanes, readDeps);
|
|
24637
25390
|
const models = /* @__PURE__ */ new Map();
|
|
24638
|
-
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);
|
|
24639
25401
|
const limitDir = phaseLimitDir(config2.guardEngagementId, deps.home);
|
|
24640
25402
|
if (limitDir !== null) {
|
|
24641
|
-
writePhaseUsage(limitDir, {
|
|
25403
|
+
const wrote = writePhaseUsage(limitDir, {
|
|
24642
25404
|
phase: basis.phase,
|
|
24643
25405
|
openedAt: basis.openedAt,
|
|
24644
|
-
tokens:
|
|
25406
|
+
tokens: figureOf(figure, options.agent),
|
|
24645
25407
|
at: new Date((deps.now ?? Date.now)()).toISOString()
|
|
24646
25408
|
});
|
|
25409
|
+
if (wrote)
|
|
25410
|
+
onFigureWritten();
|
|
24647
25411
|
}
|
|
24648
25412
|
const modelsPath = phaseModelsPath(config2.guardEngagementId, deps.home);
|
|
24649
25413
|
if (modelsPath !== null)
|
|
@@ -24652,7 +25416,7 @@ async function attemptTimeRecord(config2, controlOrigin, deps = {}) {
|
|
|
24652
25416
|
const selected = selectTimeReport(cursor, intervals, usage);
|
|
24653
25417
|
if (selected.intervals.length === 0 && selected.usage.length === 0) {
|
|
24654
25418
|
if (wouldPrune(text, basis.openedAt))
|
|
24655
|
-
await pruneTimeLog(
|
|
25419
|
+
await pruneTimeLog(logPath2, basis.openedAt);
|
|
24656
25420
|
return { outcome: "recorded" };
|
|
24657
25421
|
}
|
|
24658
25422
|
const report = { phase: basis.phase, openedAt: basis.openedAt, ...selected };
|
|
@@ -24668,14 +25432,14 @@ async function attemptTimeRecord(config2, controlOrigin, deps = {}) {
|
|
|
24668
25432
|
if (!timeReportResultSchema.safeParse(sent.body).success)
|
|
24669
25433
|
return { outcome: "not-sent", reason: "refused" };
|
|
24670
25434
|
try {
|
|
24671
|
-
writeJsonFile(
|
|
25435
|
+
writeJsonFile(join11(dir, TIME_CURSOR_FILENAME), advanceTimeCursor(cursor, selected));
|
|
24672
25436
|
} catch {
|
|
24673
25437
|
}
|
|
24674
25438
|
if (wouldPrune(text, basis.openedAt))
|
|
24675
|
-
await pruneTimeLog(
|
|
25439
|
+
await pruneTimeLog(logPath2, basis.openedAt);
|
|
24676
25440
|
return { outcome: "recorded" };
|
|
24677
25441
|
}
|
|
24678
|
-
async function runTimeVerb(deps = {}) {
|
|
25442
|
+
async function runTimeVerb(deps = {}, options = {}) {
|
|
24679
25443
|
let result;
|
|
24680
25444
|
try {
|
|
24681
25445
|
const env = deps.env ?? process.env;
|
|
@@ -24685,14 +25449,14 @@ async function runTimeVerb(deps = {}) {
|
|
|
24685
25449
|
result = { outcome: "not-sent", reason: "not-configured" };
|
|
24686
25450
|
} else {
|
|
24687
25451
|
writeAttemptedAt(dir, (deps.now ?? Date.now)());
|
|
24688
|
-
result = await attemptTimeRecord(configured.config, readControlOrigin(env).origin, deps);
|
|
25452
|
+
result = await attemptTimeRecord(configured.config, readControlOrigin(env).origin, deps, options);
|
|
24689
25453
|
}
|
|
24690
25454
|
} catch {
|
|
24691
25455
|
result = { outcome: "not-sent", reason: "unreachable" };
|
|
24692
25456
|
}
|
|
24693
25457
|
return timeRunResultSchema.parse(result);
|
|
24694
25458
|
}
|
|
24695
|
-
async function sendTimeRecord(deps = {}) {
|
|
25459
|
+
async function sendTimeRecord(deps = {}, options = {}) {
|
|
24696
25460
|
try {
|
|
24697
25461
|
const env = deps.env ?? process.env;
|
|
24698
25462
|
const configured = readConfig(env);
|
|
@@ -24703,17 +25467,170 @@ async function sendTimeRecord(deps = {}) {
|
|
|
24703
25467
|
return;
|
|
24704
25468
|
const now = (deps.now ?? Date.now)();
|
|
24705
25469
|
const last = readAttemptedAt(dir);
|
|
24706
|
-
|
|
24707
|
-
|
|
24708
|
-
|
|
24709
|
-
|
|
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;
|
|
24710
25588
|
} catch {
|
|
25589
|
+
return null;
|
|
24711
25590
|
}
|
|
24712
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);
|
|
25627
|
+
}
|
|
25628
|
+
return out;
|
|
25629
|
+
}
|
|
24713
25630
|
|
|
24714
25631
|
// dist/own-work.js
|
|
24715
|
-
import { appendFileSync as
|
|
24716
|
-
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";
|
|
24717
25634
|
|
|
24718
25635
|
// dist/risky/types.js
|
|
24719
25636
|
var RISKY_ACTION_TYPES = [
|
|
@@ -24747,7 +25664,7 @@ function ownWorkFileName(sessionId) {
|
|
|
24747
25664
|
function ownWorkPath(sessionId, dir) {
|
|
24748
25665
|
if (typeof sessionId !== "string" || !livenessIdOk(sessionId))
|
|
24749
25666
|
return null;
|
|
24750
|
-
return
|
|
25667
|
+
return join12(dir ?? markerDir(), ownWorkFileName(sessionId));
|
|
24751
25668
|
}
|
|
24752
25669
|
function inputString2(input, key) {
|
|
24753
25670
|
if (typeof input !== "object" || input === null)
|
|
@@ -24765,7 +25682,7 @@ function append(sessionId, line2, dir) {
|
|
|
24765
25682
|
const path = ownWorkPath(sessionId, dir);
|
|
24766
25683
|
if (path === null)
|
|
24767
25684
|
return;
|
|
24768
|
-
|
|
25685
|
+
appendFileSync4(path, `${JSON.stringify(line2)}
|
|
24769
25686
|
`, { mode: 384 });
|
|
24770
25687
|
}
|
|
24771
25688
|
function recordOwnShell(input, at, deps = {}) {
|
|
@@ -24811,7 +25728,7 @@ function readOwnWork(sessionId, dir) {
|
|
|
24811
25728
|
const path = ownWorkPath(sessionId, dir);
|
|
24812
25729
|
if (path === null)
|
|
24813
25730
|
return [];
|
|
24814
|
-
return parseOwnWork(
|
|
25731
|
+
return parseOwnWork(readFileSync16(path, "utf-8"));
|
|
24815
25732
|
} catch {
|
|
24816
25733
|
return [];
|
|
24817
25734
|
}
|
|
@@ -24846,7 +25763,7 @@ function realPathOf(path) {
|
|
|
24846
25763
|
let at = resolve4(path);
|
|
24847
25764
|
for (; ; ) {
|
|
24848
25765
|
try {
|
|
24849
|
-
return
|
|
25766
|
+
return join12(realpathSync6.native(at), ...missing.reverse());
|
|
24850
25767
|
} catch {
|
|
24851
25768
|
const parent = dirname5(at);
|
|
24852
25769
|
if (parent === at)
|
|
@@ -24906,7 +25823,7 @@ function ownChangedFiles(repoRoot, files, sessionId, deps = {}) {
|
|
|
24906
25823
|
};
|
|
24907
25824
|
const root = resolve4(repoRoot);
|
|
24908
25825
|
return files.filter((rel) => {
|
|
24909
|
-
const abs =
|
|
25826
|
+
const abs = join12(root, rel);
|
|
24910
25827
|
if (edited.has(realPathOf(abs)))
|
|
24911
25828
|
return true;
|
|
24912
25829
|
if (windows.length === 0)
|
|
@@ -24920,7 +25837,7 @@ function ownChangedFiles(repoRoot, files, sessionId, deps = {}) {
|
|
|
24920
25837
|
|
|
24921
25838
|
// dist/hooks/findings.js
|
|
24922
25839
|
import { createHash as createHash4, randomUUID as randomUUID2 } from "node:crypto";
|
|
24923
|
-
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";
|
|
24924
25841
|
function findingKey(firing) {
|
|
24925
25842
|
return createHash4("sha256").update(`${firing.guardId}
|
|
24926
25843
|
${firing.path ?? ""}
|
|
@@ -24963,7 +25880,7 @@ function readFindings(sessionId) {
|
|
|
24963
25880
|
return null;
|
|
24964
25881
|
const session = sessionId;
|
|
24965
25882
|
try {
|
|
24966
|
-
const parsed = JSON.parse(
|
|
25883
|
+
const parsed = JSON.parse(readFileSync17(path, "utf-8"));
|
|
24967
25884
|
if (parsed["version"] !== 1 || !Array.isArray(parsed["findings"]))
|
|
24968
25885
|
return emptyFindings(session);
|
|
24969
25886
|
const findings = [];
|
|
@@ -24983,12 +25900,12 @@ function writeFindings(file2) {
|
|
|
24983
25900
|
return;
|
|
24984
25901
|
const temp = `${path.slice(0, -".json".length)}.${process.pid}.tmp.json`;
|
|
24985
25902
|
try {
|
|
24986
|
-
|
|
25903
|
+
writeFileSync9(temp, `${JSON.stringify(file2)}
|
|
24987
25904
|
`, { mode: 384 });
|
|
24988
|
-
|
|
25905
|
+
renameSync7(temp, path);
|
|
24989
25906
|
} catch {
|
|
24990
25907
|
try {
|
|
24991
|
-
|
|
25908
|
+
unlinkSync6(temp);
|
|
24992
25909
|
} catch {
|
|
24993
25910
|
}
|
|
24994
25911
|
}
|
|
@@ -25004,7 +25921,7 @@ function pause(ms) {
|
|
|
25004
25921
|
function takeOverStaleLock(lock) {
|
|
25005
25922
|
const aside = `${lock}.${process.pid}.${randomUUID2()}.stale`;
|
|
25006
25923
|
try {
|
|
25007
|
-
|
|
25924
|
+
renameSync7(lock, aside);
|
|
25008
25925
|
} catch {
|
|
25009
25926
|
return false;
|
|
25010
25927
|
}
|
|
@@ -25016,17 +25933,17 @@ function takeOverStaleLock(lock) {
|
|
|
25016
25933
|
}
|
|
25017
25934
|
if (!staleIndeed) {
|
|
25018
25935
|
try {
|
|
25019
|
-
|
|
25936
|
+
renameSync7(aside, lock);
|
|
25020
25937
|
} catch {
|
|
25021
25938
|
try {
|
|
25022
|
-
|
|
25939
|
+
unlinkSync6(aside);
|
|
25023
25940
|
} catch {
|
|
25024
25941
|
}
|
|
25025
25942
|
}
|
|
25026
25943
|
return false;
|
|
25027
25944
|
}
|
|
25028
25945
|
try {
|
|
25029
|
-
|
|
25946
|
+
unlinkSync6(aside);
|
|
25030
25947
|
} catch {
|
|
25031
25948
|
}
|
|
25032
25949
|
return true;
|
|
@@ -25039,7 +25956,7 @@ function withFindingsLock(sessionId, body, waitMs = FINDINGS_LOCK_WAIT_MS) {
|
|
|
25039
25956
|
const deadline = Date.now() + waitMs;
|
|
25040
25957
|
for (; ; ) {
|
|
25041
25958
|
try {
|
|
25042
|
-
|
|
25959
|
+
closeSync4(openSync4(lock, "wx", 384));
|
|
25043
25960
|
break;
|
|
25044
25961
|
} catch (err) {
|
|
25045
25962
|
if (err.code !== "EEXIST")
|
|
@@ -25061,31 +25978,31 @@ function withFindingsLock(sessionId, body, waitMs = FINDINGS_LOCK_WAIT_MS) {
|
|
|
25061
25978
|
return body();
|
|
25062
25979
|
} finally {
|
|
25063
25980
|
try {
|
|
25064
|
-
|
|
25981
|
+
unlinkSync6(lock);
|
|
25065
25982
|
} catch {
|
|
25066
25983
|
}
|
|
25067
25984
|
}
|
|
25068
25985
|
}
|
|
25069
|
-
function takeUndelivered(file2,
|
|
25986
|
+
function takeUndelivered(file2, folder2) {
|
|
25070
25987
|
const taken = [];
|
|
25071
25988
|
const findings = file2.findings.map((f) => {
|
|
25072
|
-
if (f.delivered ||
|
|
25989
|
+
if (f.delivered || folder2 !== null && f.folder !== folder2)
|
|
25073
25990
|
return f;
|
|
25074
25991
|
taken.push(f);
|
|
25075
25992
|
return { ...f, delivered: true };
|
|
25076
25993
|
});
|
|
25077
25994
|
return { file: { ...file2, findings }, taken };
|
|
25078
25995
|
}
|
|
25079
|
-
function deliverFindings(sessionId,
|
|
25996
|
+
function deliverFindings(sessionId, folder2) {
|
|
25080
25997
|
const path = findingsPath(sessionId);
|
|
25081
|
-
if (path === null || !
|
|
25998
|
+
if (path === null || !existsSync7(path))
|
|
25082
25999
|
return [];
|
|
25083
26000
|
try {
|
|
25084
26001
|
const taken = withFindingsLock(sessionId, () => {
|
|
25085
26002
|
const before = readFindings(sessionId);
|
|
25086
26003
|
if (before === null)
|
|
25087
26004
|
return [];
|
|
25088
|
-
const { file: file2, taken: given } = takeUndelivered(before,
|
|
26005
|
+
const { file: file2, taken: given } = takeUndelivered(before, folder2);
|
|
25089
26006
|
if (given.length > 0)
|
|
25090
26007
|
writeFindings(file2);
|
|
25091
26008
|
return given;
|
|
@@ -25095,11 +26012,11 @@ function deliverFindings(sessionId, folder) {
|
|
|
25095
26012
|
return [];
|
|
25096
26013
|
}
|
|
25097
26014
|
}
|
|
25098
|
-
function turnEndBookkeeping(file2,
|
|
26015
|
+
function turnEndBookkeeping(file2, folder2, outcome, topLevel, now) {
|
|
25099
26016
|
const recorded = [...file2.findings];
|
|
25100
26017
|
const firing = /* @__PURE__ */ new Map();
|
|
25101
26018
|
const notRun = new Set(outcome.kind === "evaluated" ? outcome.notRun : []);
|
|
25102
|
-
const observed = (f) => f.folder ===
|
|
26019
|
+
const observed = (f) => f.folder === folder2 && !notRun.has(f.patternRef);
|
|
25103
26020
|
if (outcome.kind === "evaluated") {
|
|
25104
26021
|
for (const g of outcome.fired) {
|
|
25105
26022
|
if (g.severity === "block")
|
|
@@ -25115,13 +26032,13 @@ function turnEndBookkeeping(file2, folder, outcome, topLevel, now) {
|
|
|
25115
26032
|
const closes = observed(f) && (outcome.kind === "no-own-changes" || outcome.kind === "evaluated" && !firing.has(f.key));
|
|
25116
26033
|
(closes ? removed : kept).push(f);
|
|
25117
26034
|
}
|
|
25118
|
-
const known = new Set(kept.filter((f) => f.folder ===
|
|
26035
|
+
const known = new Set(kept.filter((f) => f.folder === folder2).map((f) => f.key));
|
|
25119
26036
|
for (const [key, g] of firing) {
|
|
25120
26037
|
if (known.has(key))
|
|
25121
26038
|
continue;
|
|
25122
26039
|
kept.push({
|
|
25123
26040
|
key,
|
|
25124
|
-
folder,
|
|
26041
|
+
folder: folder2,
|
|
25125
26042
|
guardId: g.guardId,
|
|
25126
26043
|
patternRef: g.patternRef,
|
|
25127
26044
|
severity: g.severity,
|
|
@@ -25316,7 +26233,7 @@ function patchHeaderPaths(patch) {
|
|
|
25316
26233
|
}
|
|
25317
26234
|
|
|
25318
26235
|
// dist/hooks/post-tool-use.js
|
|
25319
|
-
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";
|
|
25320
26237
|
var HANDLED_EDIT_TOOLS = /* @__PURE__ */ new Set(["Edit", "Write", "MultiEdit", "NotebookEdit"]);
|
|
25321
26238
|
async function runPostToolUse(readSeat = readSeatConfiguration, profile = AGENT_PROFILES["claude-code"]) {
|
|
25322
26239
|
const reply = hookReply("PostToolUse", profile);
|
|
@@ -25503,7 +26420,7 @@ function insideRepository(path, repoRoot) {
|
|
|
25503
26420
|
const rel = relative6(realPathOf(repoRoot), realPathOf(path));
|
|
25504
26421
|
if (rel === "" || rel === ".." || rel.startsWith(`..${sep4}`) || isAbsolute3(rel))
|
|
25505
26422
|
return null;
|
|
25506
|
-
return
|
|
26423
|
+
return join13(repoRoot, rel);
|
|
25507
26424
|
}
|
|
25508
26425
|
function actOnEnvelope2(envelope, reply) {
|
|
25509
26426
|
const notRun = notRunReport(envelope.notRun);
|
|
@@ -25526,17 +26443,17 @@ ${guardLines}${notRunBlock}`);
|
|
|
25526
26443
|
}
|
|
25527
26444
|
}
|
|
25528
26445
|
function readStdin() {
|
|
25529
|
-
return new Promise((
|
|
26446
|
+
return new Promise((resolve12, reject) => {
|
|
25530
26447
|
const chunks = [];
|
|
25531
26448
|
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
25532
|
-
process.stdin.on("end", () =>
|
|
26449
|
+
process.stdin.on("end", () => resolve12(Buffer.concat(chunks).toString("utf-8")));
|
|
25533
26450
|
process.stdin.on("error", reject);
|
|
25534
26451
|
});
|
|
25535
26452
|
}
|
|
25536
26453
|
|
|
25537
26454
|
// dist/liveness.js
|
|
25538
|
-
import { closeSync as
|
|
25539
|
-
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";
|
|
25540
26457
|
var LIVE_WINDOW_MS = 10 * 60 * 1e3;
|
|
25541
26458
|
function field(input, key) {
|
|
25542
26459
|
if (typeof input !== "object" || input === null)
|
|
@@ -25545,10 +26462,10 @@ function field(input, key) {
|
|
|
25545
26462
|
return typeof v === "string" && v !== "" ? v : null;
|
|
25546
26463
|
}
|
|
25547
26464
|
function indexEntry(dir, sessionId, name) {
|
|
25548
|
-
const
|
|
26465
|
+
const folder2 = join14(dir, livenessIndexDirName(sessionId));
|
|
25549
26466
|
for (let attempt2 = 0; attempt2 < 3; attempt2++) {
|
|
25550
26467
|
try {
|
|
25551
|
-
|
|
26468
|
+
closeSync5(openSync5(join14(folder2, name), "a", 384));
|
|
25552
26469
|
return true;
|
|
25553
26470
|
} catch (err) {
|
|
25554
26471
|
if (err.code !== "ENOENT")
|
|
@@ -25556,13 +26473,13 @@ function indexEntry(dir, sessionId, name) {
|
|
|
25556
26473
|
}
|
|
25557
26474
|
let tmp = null;
|
|
25558
26475
|
try {
|
|
25559
|
-
tmp = mkdtempSync(`${
|
|
26476
|
+
tmp = mkdtempSync(`${folder2}.`);
|
|
25560
26477
|
for (const existing of readdirSync7(dir)) {
|
|
25561
26478
|
if (parseLivenessFileName(existing)?.sessionId === sessionId)
|
|
25562
|
-
|
|
26479
|
+
closeSync5(openSync5(join14(tmp, existing), "a", 384));
|
|
25563
26480
|
}
|
|
25564
|
-
|
|
25565
|
-
|
|
26481
|
+
closeSync5(openSync5(join14(tmp, name), "a", 384));
|
|
26482
|
+
renameSync8(tmp, folder2);
|
|
25566
26483
|
return true;
|
|
25567
26484
|
} catch {
|
|
25568
26485
|
if (tmp !== null)
|
|
@@ -25587,18 +26504,18 @@ function recordLiveness(input, deps = {}) {
|
|
|
25587
26504
|
const name = livenessFileName(livenessKey(copy?.common ?? null), sessionId, agentId);
|
|
25588
26505
|
if (!indexEntry(dir, sessionId, name))
|
|
25589
26506
|
return null;
|
|
25590
|
-
const path =
|
|
26507
|
+
const path = join14(dir, name);
|
|
25591
26508
|
const text = `${cwd}
|
|
25592
26509
|
${copy?.top ?? ""}
|
|
25593
26510
|
`;
|
|
25594
26511
|
try {
|
|
25595
|
-
|
|
26512
|
+
writeFileSync10(path, text, { encoding: "utf-8", flag: "wx", mode: 384 });
|
|
25596
26513
|
return { firstSeen: true };
|
|
25597
26514
|
} catch (err) {
|
|
25598
26515
|
if (err.code !== "EEXIST")
|
|
25599
26516
|
return null;
|
|
25600
26517
|
}
|
|
25601
|
-
|
|
26518
|
+
writeFileSync10(path, text, { encoding: "utf-8", mode: 384 });
|
|
25602
26519
|
return { firstSeen: false };
|
|
25603
26520
|
} catch {
|
|
25604
26521
|
return null;
|
|
@@ -25617,7 +26534,7 @@ function clearLiveness(input, deps = {}) {
|
|
|
25617
26534
|
if (p === null || p.sessionId !== sessionId || p.agentId !== agentId)
|
|
25618
26535
|
continue;
|
|
25619
26536
|
try {
|
|
25620
|
-
|
|
26537
|
+
unlinkSync7(join14(dir, name));
|
|
25621
26538
|
removed += 1;
|
|
25622
26539
|
} catch {
|
|
25623
26540
|
}
|
|
@@ -25630,7 +26547,7 @@ function clearLiveness(input, deps = {}) {
|
|
|
25630
26547
|
}
|
|
25631
26548
|
function topOf(path) {
|
|
25632
26549
|
try {
|
|
25633
|
-
const top =
|
|
26550
|
+
const top = readFileSync18(path, "utf-8").split("\n")[1] ?? "";
|
|
25634
26551
|
return top === "" ? null : top;
|
|
25635
26552
|
} catch {
|
|
25636
26553
|
return null;
|
|
@@ -25652,7 +26569,7 @@ function readLiveness(sessionId, cwd, deps = {}) {
|
|
|
25652
26569
|
const p = parseLivenessFileName(name);
|
|
25653
26570
|
if (p === null || p.key !== key || p.sessionId !== sessionId)
|
|
25654
26571
|
continue;
|
|
25655
|
-
const full =
|
|
26572
|
+
const full = join14(dir, name);
|
|
25656
26573
|
let seenAt;
|
|
25657
26574
|
try {
|
|
25658
26575
|
seenAt = statSync5(full).mtimeMs;
|
|
@@ -25698,168 +26615,8 @@ import nodePath5 from "node:path";
|
|
|
25698
26615
|
|
|
25699
26616
|
// dist/pace-verb.js
|
|
25700
26617
|
import { mkdirSync as mkdirSync7, readdirSync as readdirSync8, readFileSync as readFileSync19, renameSync as renameSync9, statSync as statSync6, writeFileSync as writeFileSync11 } from "node:fs";
|
|
25701
|
-
import { homedir as
|
|
26618
|
+
import { homedir as homedir9 } from "node:os";
|
|
25702
26619
|
import nodePath4 from "node:path";
|
|
25703
|
-
|
|
25704
|
-
// dist/scan-lock.js
|
|
25705
|
-
import { spawn } from "node:child_process";
|
|
25706
|
-
import { linkSync, mkdirSync as mkdirSync6, readFileSync as readFileSync18, renameSync as renameSync8, unlinkSync as unlinkSync7, writeFileSync as writeFileSync10 } from "node:fs";
|
|
25707
|
-
import nodePath3 from "node:path";
|
|
25708
|
-
var SCAN_LOCK_FILENAME = "scan.lock";
|
|
25709
|
-
var SCAN_LOCK_STALE_MS = 15 * 60 * 1e3;
|
|
25710
|
-
var SCAN_LOCK_POLL_MS = 100;
|
|
25711
|
-
function scanLockPath(home) {
|
|
25712
|
-
return nodePath3.join(pacingDir(home), SCAN_LOCK_FILENAME);
|
|
25713
|
-
}
|
|
25714
|
-
function readLockBody(path) {
|
|
25715
|
-
let text;
|
|
25716
|
-
try {
|
|
25717
|
-
text = readFileSync18(path, "utf-8");
|
|
25718
|
-
} catch (err) {
|
|
25719
|
-
return err.code === "ENOENT" ? "missing" : null;
|
|
25720
|
-
}
|
|
25721
|
-
try {
|
|
25722
|
-
const v = JSON.parse(text);
|
|
25723
|
-
return typeof v["pid"] === "number" && typeof v["at"] === "number" ? { pid: v["pid"], at: v["at"] } : null;
|
|
25724
|
-
} catch {
|
|
25725
|
-
return null;
|
|
25726
|
-
}
|
|
25727
|
-
}
|
|
25728
|
-
function processAlive(pid) {
|
|
25729
|
-
if (!Number.isInteger(pid) || pid <= 0)
|
|
25730
|
-
return false;
|
|
25731
|
-
try {
|
|
25732
|
-
process.kill(pid, 0);
|
|
25733
|
-
return true;
|
|
25734
|
-
} catch (err) {
|
|
25735
|
-
return err.code === "EPERM";
|
|
25736
|
-
}
|
|
25737
|
-
}
|
|
25738
|
-
function isStale(body, staleMs, deps) {
|
|
25739
|
-
if (body === null)
|
|
25740
|
-
return true;
|
|
25741
|
-
const now = (deps.clock ?? Date.now)();
|
|
25742
|
-
if (Math.abs(now - body.at) > staleMs)
|
|
25743
|
-
return true;
|
|
25744
|
-
return !(deps.alive ?? processAlive)(body.pid);
|
|
25745
|
-
}
|
|
25746
|
-
function writeLock(path, pid, deps, flag) {
|
|
25747
|
-
writeFileSync10(path, JSON.stringify({ pid, at: (deps.clock ?? Date.now)() }), { flag, mode: 384 });
|
|
25748
|
-
}
|
|
25749
|
-
function tryTakeScanLock(deps = {}) {
|
|
25750
|
-
return tryTakeLockFile(scanLockPath(deps.home), SCAN_LOCK_STALE_MS, deps);
|
|
25751
|
-
}
|
|
25752
|
-
function tryTakeLockFile(path, staleMs, deps = {}) {
|
|
25753
|
-
const pid = deps.pid ?? process.pid;
|
|
25754
|
-
try {
|
|
25755
|
-
mkdirSync6(nodePath3.dirname(path), { recursive: true, mode: 448 });
|
|
25756
|
-
} catch {
|
|
25757
|
-
return false;
|
|
25758
|
-
}
|
|
25759
|
-
for (let attempt2 = 0; attempt2 < 2; attempt2++) {
|
|
25760
|
-
try {
|
|
25761
|
-
writeLock(path, pid, deps, "wx");
|
|
25762
|
-
return true;
|
|
25763
|
-
} catch (err) {
|
|
25764
|
-
if (err.code !== "EEXIST")
|
|
25765
|
-
return false;
|
|
25766
|
-
}
|
|
25767
|
-
const seen = readLockBody(path);
|
|
25768
|
-
if (seen === "missing")
|
|
25769
|
-
continue;
|
|
25770
|
-
if (!isStale(seen, staleMs, deps))
|
|
25771
|
-
return false;
|
|
25772
|
-
const aside = `${path}.${String(pid)}.${String((deps.clock ?? Date.now)())}.stale`;
|
|
25773
|
-
try {
|
|
25774
|
-
renameSync8(path, aside);
|
|
25775
|
-
} catch {
|
|
25776
|
-
continue;
|
|
25777
|
-
}
|
|
25778
|
-
const taken = readLockBody(aside);
|
|
25779
|
-
const same = taken !== "missing" && (seen === null ? taken === null : taken !== null && taken.pid === seen.pid && taken.at === seen.at);
|
|
25780
|
-
if (!same && taken !== "missing" && !isStale(taken, staleMs, deps)) {
|
|
25781
|
-
try {
|
|
25782
|
-
linkSync(aside, path);
|
|
25783
|
-
} catch {
|
|
25784
|
-
}
|
|
25785
|
-
try {
|
|
25786
|
-
unlinkSync7(aside);
|
|
25787
|
-
} catch {
|
|
25788
|
-
}
|
|
25789
|
-
return false;
|
|
25790
|
-
}
|
|
25791
|
-
try {
|
|
25792
|
-
unlinkSync7(aside);
|
|
25793
|
-
} catch {
|
|
25794
|
-
}
|
|
25795
|
-
}
|
|
25796
|
-
return false;
|
|
25797
|
-
}
|
|
25798
|
-
function releaseLockFile(path, pid = process.pid) {
|
|
25799
|
-
const body = readLockBody(path);
|
|
25800
|
-
if (body === "missing" || body === null || body.pid !== pid)
|
|
25801
|
-
return;
|
|
25802
|
-
try {
|
|
25803
|
-
unlinkSync7(path);
|
|
25804
|
-
} catch {
|
|
25805
|
-
}
|
|
25806
|
-
}
|
|
25807
|
-
function releaseScanLock(deps = {}) {
|
|
25808
|
-
releaseLockFile(scanLockPath(deps.home), deps.pid ?? process.pid);
|
|
25809
|
-
}
|
|
25810
|
-
function sleepSync(ms) {
|
|
25811
|
-
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
25812
|
-
}
|
|
25813
|
-
function scanUnderLock(key, deps = {}, waitMs = 0) {
|
|
25814
|
-
const clock = deps.clock ?? Date.now;
|
|
25815
|
-
const giveUpAt = clock() + waitMs;
|
|
25816
|
-
while (!tryTakeScanLock(deps)) {
|
|
25817
|
-
if (clock() >= giveUpAt)
|
|
25818
|
-
return null;
|
|
25819
|
-
sleepSync(SCAN_LOCK_POLL_MS);
|
|
25820
|
-
}
|
|
25821
|
-
try {
|
|
25822
|
-
return scanRecords(key, deps);
|
|
25823
|
-
} finally {
|
|
25824
|
-
releaseScanLock(deps);
|
|
25825
|
-
}
|
|
25826
|
-
}
|
|
25827
|
-
var spawnDetachedReal = (command, args2) => {
|
|
25828
|
-
const child = spawn(command, [...args2], { detached: true, stdio: "ignore", windowsHide: true });
|
|
25829
|
-
child.on("error", () => void 0);
|
|
25830
|
-
child.unref();
|
|
25831
|
-
return child.pid;
|
|
25832
|
-
};
|
|
25833
|
-
function startScanChild(key, binaryPath, deps = {}) {
|
|
25834
|
-
if (!tryTakeScanLock(deps))
|
|
25835
|
-
return false;
|
|
25836
|
-
let childPid;
|
|
25837
|
-
try {
|
|
25838
|
-
childPid = (deps.spawnDetached ?? spawnDetachedReal)(deps.nodePath ?? process.execPath, [
|
|
25839
|
-
binaryPath,
|
|
25840
|
-
"pace",
|
|
25841
|
-
"--scan",
|
|
25842
|
-
"--config-folder",
|
|
25843
|
-
key,
|
|
25844
|
-
"--lock-held"
|
|
25845
|
-
]);
|
|
25846
|
-
} catch {
|
|
25847
|
-
childPid = void 0;
|
|
25848
|
-
}
|
|
25849
|
-
if (childPid === void 0) {
|
|
25850
|
-
releaseScanLock(deps);
|
|
25851
|
-
return false;
|
|
25852
|
-
}
|
|
25853
|
-
try {
|
|
25854
|
-
writeLock(scanLockPath(deps.home), childPid, deps, "w");
|
|
25855
|
-
} catch {
|
|
25856
|
-
releaseScanLock(deps);
|
|
25857
|
-
return false;
|
|
25858
|
-
}
|
|
25859
|
-
return true;
|
|
25860
|
-
}
|
|
25861
|
-
|
|
25862
|
-
// dist/pace-verb.js
|
|
25863
26620
|
var PACE_DEFAULT_TASK_MINUTES = 30;
|
|
25864
26621
|
var PACE_DURATION_ROUND_MINUTES = 10;
|
|
25865
26622
|
var PACE_WINDOW_MINUTES = 300;
|
|
@@ -25981,7 +26738,7 @@ function suggestPace(input) {
|
|
|
25981
26738
|
function enginePacingDir(engagementId, home) {
|
|
25982
26739
|
if (!isEngagementId(engagementId))
|
|
25983
26740
|
return null;
|
|
25984
|
-
return nodePath4.join(home ??
|
|
26741
|
+
return nodePath4.join(home ?? homedir9(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, PACING_DIR_NAME);
|
|
25985
26742
|
}
|
|
25986
26743
|
function readBuildNumber(engagementId, home) {
|
|
25987
26744
|
const dir = enginePacingDir(engagementId, home);
|
|
@@ -26039,7 +26796,7 @@ var USAGE = "Usage: halfcycle-runner pace [--agent claude-code|codex] [--start <
|
|
|
26039
26796
|
function parsePaceArgs(args2) {
|
|
26040
26797
|
let scan = false;
|
|
26041
26798
|
let lockHeld = false;
|
|
26042
|
-
let
|
|
26799
|
+
let folder2 = null;
|
|
26043
26800
|
let phase = null;
|
|
26044
26801
|
let agents = null;
|
|
26045
26802
|
let agent = null;
|
|
@@ -26057,8 +26814,8 @@ function parsePaceArgs(args2) {
|
|
|
26057
26814
|
else if (a === "--lock-held")
|
|
26058
26815
|
lockHeld = true;
|
|
26059
26816
|
else if (a === "--config-folder") {
|
|
26060
|
-
|
|
26061
|
-
if (
|
|
26817
|
+
folder2 = value();
|
|
26818
|
+
if (folder2 === null)
|
|
26062
26819
|
return { kind: "usage", message: USAGE };
|
|
26063
26820
|
} else if (a === "--start") {
|
|
26064
26821
|
phase = value();
|
|
@@ -26079,9 +26836,9 @@ function parsePaceArgs(args2) {
|
|
|
26079
26836
|
if (scan) {
|
|
26080
26837
|
if (phase !== null || agents !== null || agent !== null)
|
|
26081
26838
|
return { kind: "usage", message: USAGE };
|
|
26082
|
-
return { kind: "scan", folder, lockHeld };
|
|
26839
|
+
return { kind: "scan", folder: folder2, lockHeld };
|
|
26083
26840
|
}
|
|
26084
|
-
if (
|
|
26841
|
+
if (folder2 !== null || lockHeld)
|
|
26085
26842
|
return { kind: "usage", message: USAGE };
|
|
26086
26843
|
if (phase === null)
|
|
26087
26844
|
return agents === null ? { kind: "now", agent: agent ?? "claude-code" } : { kind: "usage", message: USAGE };
|
|
@@ -26164,7 +26921,7 @@ async function runPaceVerb(args2, deps = {}) {
|
|
|
26164
26921
|
...deps.home === void 0 ? {} : { home: deps.home },
|
|
26165
26922
|
now: () => now.getTime(),
|
|
26166
26923
|
...deps.fetchFn === void 0 ? {} : { fetchFn: deps.fetchFn }
|
|
26167
|
-
});
|
|
26924
|
+
}, { agent: parsed.agent });
|
|
26168
26925
|
} catch {
|
|
26169
26926
|
}
|
|
26170
26927
|
const remembered = readPaceStateFile(pacingDir2).basis;
|
|
@@ -26252,6 +27009,7 @@ async function runPaceVerb(args2, deps = {}) {
|
|
|
26252
27009
|
...decision.until !== null ? { until: decision.until.toISOString() } : {},
|
|
26253
27010
|
keepFreePercent,
|
|
26254
27011
|
...suggestion !== void 0 ? { suggestion } : {},
|
|
27012
|
+
...limitFile !== null ? { usage: { used: readPhaseUsage(pacingDir2, limitFile.phase), limit: limitFile.limit } } : {},
|
|
26255
27013
|
...atLimit ? {
|
|
26256
27014
|
limit: "reached",
|
|
26257
27015
|
limitHeld: {
|
|
@@ -26399,10 +27157,10 @@ async function paceAtTurnEnd(input, reply, deps = {}) {
|
|
|
26399
27157
|
const basis = read !== null ? { phase: read.phase, keepFreePercent: read.keepFreePercent } : stored.basis;
|
|
26400
27158
|
if (basis === null)
|
|
26401
27159
|
return;
|
|
26402
|
-
const
|
|
27160
|
+
const write2 = deps.writeState ?? writePaceState;
|
|
26403
27161
|
if (basis.phase === null) {
|
|
26404
27162
|
if (before !== null || read !== null)
|
|
26405
|
-
|
|
27163
|
+
write2(dir, key, null, read !== null ? basis : null);
|
|
26406
27164
|
return;
|
|
26407
27165
|
}
|
|
26408
27166
|
const working = liveCount(readLiveness(field2(input, "session_id"), field2(input, "cwd") ?? process.cwd(), deps.liveness));
|
|
@@ -26429,7 +27187,8 @@ async function paceAtTurnEnd(input, reply, deps = {}) {
|
|
|
26429
27187
|
}
|
|
26430
27188
|
}
|
|
26431
27189
|
const reported = readReportedAccount(key, { home: deps.home });
|
|
26432
|
-
const
|
|
27190
|
+
const build = buildNumberFor(engagementId, basis.phase, deps.home);
|
|
27191
|
+
const number4 = build?.number ?? CAREFUL_START_AGENTS;
|
|
26433
27192
|
const decision = paceOf({ number: number4, keepFreePercent: basis.keepFreePercent, learned, reported, now });
|
|
26434
27193
|
const settled2 = {
|
|
26435
27194
|
pace: decision.pace,
|
|
@@ -26438,12 +27197,14 @@ async function paceAtTurnEnd(input, reply, deps = {}) {
|
|
|
26438
27197
|
windowKind: decision.windowKind,
|
|
26439
27198
|
until: decision.until === null ? null : decision.until.toISOString(),
|
|
26440
27199
|
at: now.toISOString(),
|
|
26441
|
-
offeredFor: offeredForNow(stored.accounts[key]?.offeredFor, null, now)
|
|
27200
|
+
offeredFor: offeredForNow(stored.accounts[key]?.offeredFor, null, now),
|
|
27201
|
+
told: { pace: decision.pace, allowance: decision.allowance, windowKind: decision.windowKind }
|
|
26442
27202
|
};
|
|
26443
|
-
const
|
|
26444
|
-
const
|
|
27203
|
+
const told = before === null || before.told === void 0 ? before : { ...before, ...before.told };
|
|
27204
|
+
const text = paceChangeText(told, settled2, working, now, basis.keepFreePercent);
|
|
27205
|
+
const offer = text === null && build !== null ? offerText(settled2, learned, reported, now, basis.keepFreePercent) : null;
|
|
26445
27206
|
const after = offer === null ? settled2 : { ...settled2, offeredFor: offeredForNow(settled2.offeredFor, offer.resetsAt, now) };
|
|
26446
|
-
|
|
27207
|
+
write2(dir, key, after, read !== null ? basis : null);
|
|
26447
27208
|
if (text !== null)
|
|
26448
27209
|
reply.notice(text);
|
|
26449
27210
|
else if (offer !== null)
|
|
@@ -26494,7 +27255,7 @@ function pruneStarts(file2, nowMs) {
|
|
|
26494
27255
|
}
|
|
26495
27256
|
return out;
|
|
26496
27257
|
}
|
|
26497
|
-
function
|
|
27258
|
+
function sleepSync3(ms) {
|
|
26498
27259
|
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
26499
27260
|
}
|
|
26500
27261
|
function underStartsLock(dir, giveUpMs, fn) {
|
|
@@ -26503,7 +27264,7 @@ function underStartsLock(dir, giveUpMs, fn) {
|
|
|
26503
27264
|
while (!tryTakeLockFile(lock, PACE_STARTS_LOCK_STALE_MS)) {
|
|
26504
27265
|
if (Date.now() >= giveUpAt)
|
|
26505
27266
|
return void 0;
|
|
26506
|
-
|
|
27267
|
+
sleepSync3(STARTS_LOCK_POLL_MS);
|
|
26507
27268
|
}
|
|
26508
27269
|
try {
|
|
26509
27270
|
return fn();
|
|
@@ -26598,9 +27359,9 @@ function paceHoldText(input, toolInput, deps = {}) {
|
|
|
26598
27359
|
}
|
|
26599
27360
|
|
|
26600
27361
|
// dist/risky/facts.js
|
|
26601
|
-
import { existsSync as
|
|
26602
|
-
import { homedir as
|
|
26603
|
-
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";
|
|
26604
27365
|
|
|
26605
27366
|
// dist/risky/shell.js
|
|
26606
27367
|
var MAX_DEPTH = 8;
|
|
@@ -27780,7 +28541,7 @@ function readLine(commands, vars, gitEnv, savedTrusted) {
|
|
|
27780
28541
|
}
|
|
27781
28542
|
vars.enter(own);
|
|
27782
28543
|
const simple = expandCommand(raw, vars);
|
|
27783
|
-
const
|
|
28544
|
+
const folder2 = folderIn(simple);
|
|
27784
28545
|
for (const m of recogniseSimple(simple)) {
|
|
27785
28546
|
const trusted = m.type === "shrink-record" && m.change.kind === "saved" && !savedTrusted ? { ...m, change: { kind: "emptied" } } : m;
|
|
27786
28547
|
let shown2 = trusted;
|
|
@@ -27796,7 +28557,7 @@ function readLine(commands, vars, gitEnv, savedTrusted) {
|
|
|
27796
28557
|
}
|
|
27797
28558
|
matches.push({
|
|
27798
28559
|
...shown2,
|
|
27799
|
-
...
|
|
28560
|
+
...folder2 === void 0 ? {} : { folder: folder2 },
|
|
27800
28561
|
...made.size === 0 ? {} : { made: new Map(made) },
|
|
27801
28562
|
...madeInChain.size === 0 ? {} : { madeInChain: new Set(madeInChain) },
|
|
27802
28563
|
...removedInChain.size === 0 ? {} : { removedInChain: new Set(removedInChain) },
|
|
@@ -27804,9 +28565,9 @@ function readLine(commands, vars, gitEnv, savedTrusted) {
|
|
|
27804
28565
|
...vars.stoppedIf.length === 0 ? {} : { stoppedIf: [...vars.stoppedIf] }
|
|
27805
28566
|
});
|
|
27806
28567
|
}
|
|
27807
|
-
if (surelyRuns(simple, own) && (
|
|
28568
|
+
if (surelyRuns(simple, own) && (folder2 === void 0 || folder2.known)) {
|
|
27808
28569
|
for (const p of pathsMade(simple)) {
|
|
27809
|
-
const key = madeKey(
|
|
28570
|
+
const key = madeKey(folder2?.dirs ?? [], p.word);
|
|
27810
28571
|
made.set(key, p.by);
|
|
27811
28572
|
if (simple.next === "&&")
|
|
27812
28573
|
madeInChain.add(key);
|
|
@@ -27814,12 +28575,12 @@ function readLine(commands, vars, gitEnv, savedTrusted) {
|
|
|
27814
28575
|
if (simple.next === "&&" && simple.words[0]?.text === "rmdir") {
|
|
27815
28576
|
for (const w of simple.words.slice(1))
|
|
27816
28577
|
if (w.literal && !w.text.startsWith("-"))
|
|
27817
|
-
removedInChain.add(madeKey(
|
|
28578
|
+
removedInChain.add(madeKey(folder2?.dirs ?? [], w));
|
|
27818
28579
|
}
|
|
27819
28580
|
}
|
|
27820
28581
|
const nextCmd = commands[i + 1];
|
|
27821
28582
|
const asJoined = simple.next !== void 0 && (nextCmd === void 0 || scopeKey(nextCmd) !== scopeKey(simple)) ? { ...simple, next: void 0 } : simple;
|
|
27822
|
-
const after = folderAfter(
|
|
28583
|
+
const after = folderAfter(folder2, asJoined, own);
|
|
27823
28584
|
folders.set(scopeKey(simple), after);
|
|
27824
28585
|
vars.guard = chainCds === null ? null : [...chainCds];
|
|
27825
28586
|
vars.update(raw, own);
|
|
@@ -28812,7 +29573,7 @@ var Env = class {
|
|
|
28812
29573
|
constructor(ctx) {
|
|
28813
29574
|
this.projectDir = realOrSelf(resolve6(ctx.projectDir));
|
|
28814
29575
|
this.cwd = realOrSelf(resolve6(this.projectDir, ctx.cwd));
|
|
28815
|
-
this.home = realOrSelf(resolve6(ctx.home ??
|
|
29576
|
+
this.home = realOrSelf(resolve6(ctx.home ?? homedir10()));
|
|
28816
29577
|
this.timeoutMs = ctx.gitTimeoutMs ?? FACTS_GIT_TIMEOUT_MS;
|
|
28817
29578
|
this.tempDir = realOrSelf(resolve6(ctx.tempDir ?? tmpdir2()));
|
|
28818
29579
|
const roots = ctx.tempRoots ?? [this.tempDir, tmpdir2(), ...TEMP_ROOTS];
|
|
@@ -28836,7 +29597,7 @@ var Env = class {
|
|
|
28836
29597
|
return this.description;
|
|
28837
29598
|
this.description = null;
|
|
28838
29599
|
try {
|
|
28839
|
-
const raw = JSON.parse(readFileSync21(
|
|
29600
|
+
const raw = JSON.parse(readFileSync21(join15(repoRoot, SYSTEM_DESCRIPTION_REL), "utf-8"));
|
|
28840
29601
|
const checked = checkSystemDescription(raw);
|
|
28841
29602
|
if (checked.ok)
|
|
28842
29603
|
this.description = checked.description;
|
|
@@ -28900,18 +29661,18 @@ function resolveHome(text, home, base) {
|
|
|
28900
29661
|
if (text === "~")
|
|
28901
29662
|
return home;
|
|
28902
29663
|
if (text.startsWith("~/"))
|
|
28903
|
-
return
|
|
29664
|
+
return join15(home, text.slice(2));
|
|
28904
29665
|
return resolve6(base, text);
|
|
28905
29666
|
}
|
|
28906
29667
|
function realTarget(abs) {
|
|
28907
29668
|
const parent = dirname6(abs);
|
|
28908
29669
|
if (parent === abs)
|
|
28909
29670
|
return abs;
|
|
28910
|
-
return
|
|
29671
|
+
return join15(realOrSelf(parent), pathBasename(abs));
|
|
28911
29672
|
}
|
|
28912
29673
|
function wordPath(word, base, env) {
|
|
28913
29674
|
if (word.temp !== void 0) {
|
|
28914
|
-
const root = word.temp.base === "mktemp" ?
|
|
29675
|
+
const root = word.temp.base === "mktemp" ? join15(env.tempDir, ".halfcycle-mktemp-new") : env.tempDir;
|
|
28915
29676
|
return resolve6(`${root}${word.temp.suffix}`);
|
|
28916
29677
|
}
|
|
28917
29678
|
return word.literal ? resolveHome(word.text, env.home, base) : null;
|
|
@@ -29057,7 +29818,7 @@ function globPath(abs) {
|
|
|
29057
29818
|
const next = [];
|
|
29058
29819
|
if (!/[*?[]/.test(segment)) {
|
|
29059
29820
|
for (const c of current)
|
|
29060
|
-
next.push(
|
|
29821
|
+
next.push(join15(c, segment));
|
|
29061
29822
|
} else {
|
|
29062
29823
|
const re = segmentPattern(segment);
|
|
29063
29824
|
for (const c of current) {
|
|
@@ -29071,7 +29832,7 @@ function globPath(abs) {
|
|
|
29071
29832
|
if (n.startsWith(".") && !segment.startsWith("."))
|
|
29072
29833
|
continue;
|
|
29073
29834
|
if (re.test(n))
|
|
29074
|
-
next.push(
|
|
29835
|
+
next.push(join15(c, n));
|
|
29075
29836
|
}
|
|
29076
29837
|
}
|
|
29077
29838
|
}
|
|
@@ -29199,7 +29960,7 @@ function findKeeps(filter, roots, repoRoot) {
|
|
|
29199
29960
|
const names = filter.names.map((n) => findPattern(n.pattern, n.fold, false));
|
|
29200
29961
|
const excluded = filter.excluded.map((p) => findPattern(p, false, true));
|
|
29201
29962
|
const steps = (rel) => {
|
|
29202
|
-
const abs =
|
|
29963
|
+
const abs = join15(repoRoot, rel);
|
|
29203
29964
|
const out = [];
|
|
29204
29965
|
for (const r of roots) {
|
|
29205
29966
|
if (!isInside(abs, r.abs))
|
|
@@ -29256,11 +30017,11 @@ function walkRoots(ignoredFolders, specs) {
|
|
|
29256
30017
|
const under2 = (child, parent) => parent === "." || child === parent || child.startsWith(`${parent}/`);
|
|
29257
30018
|
const roots = /* @__PURE__ */ new Set();
|
|
29258
30019
|
for (const raw of ignoredFolders) {
|
|
29259
|
-
const
|
|
30020
|
+
const folder2 = raw.replace(/\/+$/, "");
|
|
29260
30021
|
for (const spec of specs) {
|
|
29261
|
-
if (under2(
|
|
29262
|
-
roots.add(
|
|
29263
|
-
else if (under2(spec,
|
|
30022
|
+
if (under2(folder2, spec))
|
|
30023
|
+
roots.add(folder2);
|
|
30024
|
+
else if (under2(spec, folder2))
|
|
29264
30025
|
roots.add(spec);
|
|
29265
30026
|
}
|
|
29266
30027
|
}
|
|
@@ -29271,9 +30032,9 @@ function credentialFilesIn(folders, repoRoot, deadline, skip) {
|
|
|
29271
30032
|
const out = [];
|
|
29272
30033
|
const stack = [];
|
|
29273
30034
|
for (const f of folders) {
|
|
29274
|
-
if (isDirectory(
|
|
30035
|
+
if (isDirectory(join15(repoRoot, f)))
|
|
29275
30036
|
stack.push(f);
|
|
29276
|
-
else if (pathExists(
|
|
30037
|
+
else if (pathExists(join15(repoRoot, f)) && isCredentialPath(f))
|
|
29277
30038
|
out.push(f);
|
|
29278
30039
|
}
|
|
29279
30040
|
let seen = 0;
|
|
@@ -29281,7 +30042,7 @@ function credentialFilesIn(folders, repoRoot, deadline, skip) {
|
|
|
29281
30042
|
const rel = stack.pop();
|
|
29282
30043
|
let entries;
|
|
29283
30044
|
try {
|
|
29284
|
-
entries = readdirSync9(
|
|
30045
|
+
entries = readdirSync9(join15(repoRoot, rel), { withFileTypes: true });
|
|
29285
30046
|
} catch {
|
|
29286
30047
|
continue;
|
|
29287
30048
|
}
|
|
@@ -29439,7 +30200,7 @@ function closeFoldsAll(targets, env) {
|
|
|
29439
30200
|
return false;
|
|
29440
30201
|
let at = root;
|
|
29441
30202
|
for (const seg of rel.split("/")) {
|
|
29442
|
-
at =
|
|
30203
|
+
at = join15(at, seg);
|
|
29443
30204
|
try {
|
|
29444
30205
|
if (lstatSync3(at).isSymbolicLink())
|
|
29445
30206
|
return false;
|
|
@@ -29672,7 +30433,7 @@ function worktreeFiles(m, where, env) {
|
|
|
29672
30433
|
if (path === null)
|
|
29673
30434
|
return null;
|
|
29674
30435
|
const abs = realOrSelf(path);
|
|
29675
|
-
if (!
|
|
30436
|
+
if (!existsSync8(abs))
|
|
29676
30437
|
return [];
|
|
29677
30438
|
const top = env.repoRoot(abs);
|
|
29678
30439
|
if (top === null)
|
|
@@ -30022,7 +30783,7 @@ function publishFacts(m, env) {
|
|
|
30022
30783
|
const start = startFolder(m, env);
|
|
30023
30784
|
if (start !== null && PACKAGE_JSON_PROGRAMS.has(m.program)) {
|
|
30024
30785
|
try {
|
|
30025
|
-
const pkg = JSON.parse(readFileSync21(
|
|
30786
|
+
const pkg = JSON.parse(readFileSync21(join15(start, "package.json"), "utf-8"));
|
|
30026
30787
|
if (typeof pkg["name"] === "string" && typeof pkg["version"] === "string" && pkg["name"] !== "" && pkg["version"] !== "") {
|
|
30027
30788
|
name = pkg["name"];
|
|
30028
30789
|
version2 = pkg["version"];
|
|
@@ -30141,17 +30902,17 @@ function recordFileAt(abs, env) {
|
|
|
30141
30902
|
const row = recordPatternFor(rel);
|
|
30142
30903
|
return row !== void 0 && row.shrinkAsked !== false ? { abs, root, rel } : null;
|
|
30143
30904
|
}
|
|
30144
|
-
function recordFilesUnder(
|
|
30145
|
-
const root = recordRoot(
|
|
30905
|
+
function recordFilesUnder(folder2, env) {
|
|
30906
|
+
const root = recordRoot(folder2, env);
|
|
30146
30907
|
if (root === null)
|
|
30147
30908
|
return [];
|
|
30148
|
-
const relFolder = toSlash(relative7(root,
|
|
30909
|
+
const relFolder = toSlash(relative7(root, folder2));
|
|
30149
30910
|
const starts = /* @__PURE__ */ new Set();
|
|
30150
30911
|
for (const { pattern } of PROJECT_RECORD_PATTERNS) {
|
|
30151
30912
|
if (relFolder === "" || patternOwns(relFolder, pattern))
|
|
30152
|
-
starts.add(
|
|
30913
|
+
starts.add(join15(root, pattern));
|
|
30153
30914
|
else if (patternOwns(pattern, relFolder))
|
|
30154
|
-
starts.add(
|
|
30915
|
+
starts.add(folder2);
|
|
30155
30916
|
}
|
|
30156
30917
|
const out = [];
|
|
30157
30918
|
const stack = [...starts];
|
|
@@ -30175,7 +30936,7 @@ function recordFilesUnder(folder, env) {
|
|
|
30175
30936
|
continue;
|
|
30176
30937
|
}
|
|
30177
30938
|
for (const n of names)
|
|
30178
|
-
stack.push(
|
|
30939
|
+
stack.push(join15(p, n));
|
|
30179
30940
|
} else if (st.isFile()) {
|
|
30180
30941
|
const r = recordFileAt(p, env);
|
|
30181
30942
|
if (r !== null)
|
|
@@ -30258,7 +31019,11 @@ var PERSON_HOLD_LINE = "Halfcycle paused a risky step before it ran. Nothing cha
|
|
|
30258
31019
|
var HELD_STEP_OPENER = "The step was: ";
|
|
30259
31020
|
var PRECAUTION_OPENER = "It was stopped as a precaution: ";
|
|
30260
31021
|
var ALLOW_REPLY = "allow";
|
|
30261
|
-
|
|
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);
|
|
30262
31027
|
var NOTHING_LOST_ON_NO = "Nothing is lost if you say no.";
|
|
30263
31028
|
var IF_YES = "If you say yes, ";
|
|
30264
31029
|
var DESCRIBED_TOOLS = /* @__PURE__ */ new Set(["Bash", "Agent"]);
|
|
@@ -30294,6 +31059,9 @@ function questionFor(facts, description) {
|
|
|
30294
31059
|
const shown2 = staked.slice(0, MAX_LISTED).map((f) => `${whatOf(f)} ${IF_YES}${lostOf(f)}`);
|
|
30295
31060
|
return `${PAUSED_OPENER.trimEnd().slice(0, -1)}. ${shown2.join(" ")}${moreLine(staked.length - shown2.length)} ${reason} ${NOTHING_LOST_ON_NO}`;
|
|
30296
31061
|
}
|
|
31062
|
+
function heldAgentText(held, stepNumber) {
|
|
31063
|
+
return `${held.facts} ${holdAgentInstruction(stepNumber)}`;
|
|
31064
|
+
}
|
|
30297
31065
|
function refusalFor(facts, description) {
|
|
30298
31066
|
const staked = orderedStaked(facts);
|
|
30299
31067
|
if (staked.length === 0)
|
|
@@ -30304,9 +31072,11 @@ function refusalFor(facts, description) {
|
|
|
30304
31072
|
return heldStep(steps, description, shown2.map(whyOf).join("; "));
|
|
30305
31073
|
}
|
|
30306
31074
|
function heldStep(steps, description, why) {
|
|
31075
|
+
const facts = `${HELD_STEP_OPENER}${steps}. ${reasonSentence(description)} ${PRECAUTION_OPENER}${why}.`;
|
|
30307
31076
|
return {
|
|
30308
31077
|
person: PERSON_HOLD_LINE,
|
|
30309
|
-
agent: `${
|
|
31078
|
+
agent: `${facts} ${HOLD_AGENT_INSTRUCTION}`,
|
|
31079
|
+
facts,
|
|
30310
31080
|
step: steps
|
|
30311
31081
|
};
|
|
30312
31082
|
}
|
|
@@ -30721,14 +31491,85 @@ function isOneCall(call) {
|
|
|
30721
31491
|
|
|
30722
31492
|
// dist/risky/allow-once.js
|
|
30723
31493
|
import { createHash as createHash5 } from "node:crypto";
|
|
30724
|
-
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";
|
|
30725
31496
|
var ALLOW_ONCE_MS = 5 * 60 * 1e3;
|
|
30726
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}))?$`);
|
|
30727
31503
|
var STEP_MAX_LENGTH = 1e3;
|
|
30728
|
-
function
|
|
30729
|
-
|
|
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
|
+
}
|
|
30730
31540
|
}
|
|
30731
|
-
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 = {}) {
|
|
30732
31573
|
const toolName = input["tool_name"];
|
|
30733
31574
|
const toolInput = input["tool_input"];
|
|
30734
31575
|
if (typeof toolName !== "string" || toolName === "")
|
|
@@ -30739,7 +31580,17 @@ function stepKey(input, staked) {
|
|
|
30739
31580
|
if (DESCRIBED_TOOLS.has(toolName))
|
|
30740
31581
|
delete rest["description"];
|
|
30741
31582
|
const cwd = typeof input["cwd"] === "string" ? input["cwd"] : "";
|
|
30742
|
-
|
|
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;
|
|
30743
31594
|
}
|
|
30744
31595
|
function canonical(value) {
|
|
30745
31596
|
if (Array.isArray(value))
|
|
@@ -30750,37 +31601,166 @@ function canonical(value) {
|
|
|
30750
31601
|
}
|
|
30751
31602
|
return JSON.stringify(value) ?? "null";
|
|
30752
31603
|
}
|
|
30753
|
-
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) {
|
|
30754
31691
|
const paths = allowOncePaths(sessionId, deps.dir);
|
|
30755
31692
|
if (paths === null)
|
|
30756
31693
|
return;
|
|
30757
|
-
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
|
+
};
|
|
30758
31702
|
try {
|
|
30759
|
-
|
|
31703
|
+
appendFileSync5(paths.held, `${JSON.stringify(record2)}
|
|
30760
31704
|
`, { mode: 384 });
|
|
30761
31705
|
} catch {
|
|
30762
31706
|
return;
|
|
30763
31707
|
}
|
|
30764
31708
|
}
|
|
30765
|
-
function armAllowStep(sessionId, deps = {}) {
|
|
31709
|
+
function armAllowStep(sessionId, deps = {}, stepNumber = null) {
|
|
31710
|
+
const none = (outcome) => ({ outcome, step: null, paused: [] });
|
|
30766
31711
|
try {
|
|
30767
31712
|
const paths = allowOncePaths(sessionId, deps.dir);
|
|
30768
31713
|
if (paths === null)
|
|
30769
|
-
return
|
|
31714
|
+
return none(stepNumber === null ? "nothing-held" : "not-paused");
|
|
31715
|
+
const session = sessionId;
|
|
30770
31716
|
const now = nowOf(deps);
|
|
30771
|
-
const held = claimHeld(paths.held,
|
|
30772
|
-
const
|
|
30773
|
-
|
|
30774
|
-
|
|
30775
|
-
|
|
30776
|
-
|
|
30777
|
-
|
|
30778
|
-
|
|
30779
|
-
|
|
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 };
|
|
30780
31743
|
} catch {
|
|
30781
|
-
return
|
|
31744
|
+
return none("not-saved");
|
|
30782
31745
|
}
|
|
30783
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
|
+
}
|
|
30784
31764
|
function claimHeld(path, session, now) {
|
|
30785
31765
|
const claimed = `${path}.${process.pid}.${now}.claim`;
|
|
30786
31766
|
try {
|
|
@@ -30803,6 +31783,16 @@ function claimHeld(path, session, now) {
|
|
|
30803
31783
|
}
|
|
30804
31784
|
return records;
|
|
30805
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
|
+
}
|
|
30806
31796
|
function isStep(v) {
|
|
30807
31797
|
return typeof v === "string" && v !== "" && v.length <= STEP_MAX_LENGTH;
|
|
30808
31798
|
}
|
|
@@ -30857,12 +31847,23 @@ function parseRecord(text, session) {
|
|
|
30857
31847
|
if (typeof r["at"] !== "number")
|
|
30858
31848
|
return null;
|
|
30859
31849
|
const step = r["step"];
|
|
30860
|
-
|
|
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
|
+
};
|
|
30861
31859
|
}
|
|
30862
31860
|
function writeRecord(path, record2) {
|
|
31861
|
+
return writeWhole2(path, JSON.stringify(record2));
|
|
31862
|
+
}
|
|
31863
|
+
function writeWhole2(path, body) {
|
|
30863
31864
|
const tmp = `${path}.${process.pid}.${Date.now()}.tmp`;
|
|
30864
31865
|
try {
|
|
30865
|
-
writeFileSync13(tmp,
|
|
31866
|
+
writeFileSync13(tmp, body, { mode: 384 });
|
|
30866
31867
|
renameSync11(tmp, path);
|
|
30867
31868
|
return true;
|
|
30868
31869
|
} catch {
|
|
@@ -30960,7 +31961,7 @@ function decideAutonomous(facts, mayPublishNow) {
|
|
|
30960
31961
|
|
|
30961
31962
|
// dist/risky/own-copy.js
|
|
30962
31963
|
import { readFileSync as readFileSync23 } from "node:fs";
|
|
30963
|
-
import { join as
|
|
31964
|
+
import { join as join16, posix as posix2, win32 as win322 } from "node:path";
|
|
30964
31965
|
var OWN_COPY_START_TOOL = "Agent";
|
|
30965
31966
|
var OWN_COPY_WRITE_TOOLS = /* @__PURE__ */ new Set(["Write", "Edit", "MultiEdit", "NotebookEdit"]);
|
|
30966
31967
|
var OWN_COPY_ISOLATION = "worktree";
|
|
@@ -31021,7 +32022,7 @@ function typeCanChangeFiles(subagentType, deps) {
|
|
|
31021
32022
|
return true;
|
|
31022
32023
|
if (AGENT_FILE_NAME.test(type)) {
|
|
31023
32024
|
for (const base of [deps.projectDir, deps.home]) {
|
|
31024
|
-
const text = readOr(deps,
|
|
32025
|
+
const text = readOr(deps, join16(base, ".claude", "agents", `${type}.md`));
|
|
31025
32026
|
if (text === null)
|
|
31026
32027
|
continue;
|
|
31027
32028
|
const tools = frontmatterTools(text);
|
|
@@ -31127,31 +32128,31 @@ function judgeChange(input, call, deps) {
|
|
|
31127
32128
|
|
|
31128
32129
|
// dist/risky/save.js
|
|
31129
32130
|
import { randomBytes } from "node:crypto";
|
|
31130
|
-
import { chmodSync as chmodSync2, constants as fsConstants, copyFileSync, lstatSync as lstatSync4, mkdirSync as mkdirSync9, readdirSync as readdirSync10, readFileSync as readFileSync24, readlinkSync, realpathSync as
|
|
31131
|
-
import { homedir as
|
|
31132
|
-
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";
|
|
31133
32134
|
var SAVE_LIMIT_BYTES = 2e8;
|
|
31134
32135
|
var SAVE_BUDGET_MS = 5e3;
|
|
31135
32136
|
function notSaved(reason) {
|
|
31136
32137
|
return { saved: false, reason };
|
|
31137
32138
|
}
|
|
31138
|
-
function savedFolderOf(engagementId, home =
|
|
32139
|
+
function savedFolderOf(engagementId, home = homedir11()) {
|
|
31139
32140
|
if (!isEngagementId(engagementId))
|
|
31140
32141
|
return null;
|
|
31141
|
-
return
|
|
32142
|
+
return join17(home, HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, SAVED_DIR_NAME);
|
|
31142
32143
|
}
|
|
31143
32144
|
function saveFirst(staked, ctx) {
|
|
31144
32145
|
const now = ctx.now ?? Date.now;
|
|
31145
32146
|
const deadline = now() + (ctx.budgetMs ?? SAVE_BUDGET_MS);
|
|
31146
|
-
const
|
|
31147
|
-
if (
|
|
32147
|
+
const folder2 = savedFolderOf(ctx.engagementId, ctx.home);
|
|
32148
|
+
if (folder2 === null)
|
|
31148
32149
|
return notSaved(AUTONOMY_SAVE_FAILED_REASON);
|
|
31149
32150
|
const plan = planOf(staked);
|
|
31150
32151
|
if (!plan.ok)
|
|
31151
32152
|
return notSaved(plan.reason);
|
|
31152
32153
|
const g = new SaveGit(plan.root, deadline, now);
|
|
31153
32154
|
const top = g.run(["rev-parse", "--show-toplevel"]);
|
|
31154
|
-
if (!top.ok ||
|
|
32155
|
+
if (!top.ok || realOrSelf3(top.value.trim()) !== plan.root)
|
|
31155
32156
|
return notSaved(AUTONOMY_SAVE_NOT_COVERED_REASON);
|
|
31156
32157
|
const head = g.run(["rev-parse", "--verify", "--quiet", "HEAD^{commit}"]);
|
|
31157
32158
|
const headCommit2 = head.ok ? head.value.trim() : "";
|
|
@@ -31166,23 +32167,23 @@ function saveFirst(staked, ctx) {
|
|
|
31166
32167
|
return notSaved(found2.reason);
|
|
31167
32168
|
let saveDir = null;
|
|
31168
32169
|
try {
|
|
31169
|
-
const id = freshId(
|
|
32170
|
+
const id = freshId(folder2, ctx.newId);
|
|
31170
32171
|
if (id === null)
|
|
31171
32172
|
return notSaved(AUTONOMY_SAVE_FAILED_REASON);
|
|
31172
|
-
saveDir =
|
|
32173
|
+
saveDir = join17(folder2, id);
|
|
31173
32174
|
const repository = repositoryOf(g);
|
|
31174
32175
|
if (repository === null)
|
|
31175
32176
|
return failed(saveDir);
|
|
31176
|
-
writeFileSync14(
|
|
32177
|
+
writeFileSync14(join17(saveDir, SAVED_REPOSITORY_FILE_NAME), `${repository}
|
|
31177
32178
|
`, { mode: 384 });
|
|
31178
|
-
const privateIndex =
|
|
32179
|
+
const privateIndex = join17(saveDir, PRIVATE_INDEX_NAME);
|
|
31179
32180
|
const commit = saveCommit(id, headCommit2, found2.tracked, plan.lines, privateIndex, g, now());
|
|
31180
32181
|
rmSync3(privateIndex, { force: true });
|
|
31181
32182
|
if (commit === null)
|
|
31182
32183
|
return failed(saveDir);
|
|
31183
|
-
const copiesDir =
|
|
32184
|
+
const copiesDir = join17(saveDir, SAVED_COPIES_DIR_NAME);
|
|
31184
32185
|
for (const rel of found2.copies) {
|
|
31185
|
-
if (now() > deadline || !copyOne(
|
|
32186
|
+
if (now() > deadline || !copyOne(join17(plan.root, rel), join17(copiesDir, rel)))
|
|
31186
32187
|
return failed(saveDir);
|
|
31187
32188
|
}
|
|
31188
32189
|
const description = savedSchema.safeParse({
|
|
@@ -31198,7 +32199,7 @@ function saveFirst(staked, ctx) {
|
|
|
31198
32199
|
});
|
|
31199
32200
|
if (!description.success)
|
|
31200
32201
|
return failed(saveDir);
|
|
31201
|
-
const file2 =
|
|
32202
|
+
const file2 = join17(saveDir, SAVED_FILE_NAME);
|
|
31202
32203
|
writeFileSync14(`${file2}.part`, `${JSON.stringify(description.data, null, 2)}
|
|
31203
32204
|
`, { mode: 384 });
|
|
31204
32205
|
renameSync12(`${file2}.part`, file2);
|
|
@@ -31229,7 +32230,7 @@ function planOf(staked) {
|
|
|
31229
32230
|
const t = f.save;
|
|
31230
32231
|
if (t === void 0)
|
|
31231
32232
|
return { ok: false, reason: f.cannotTell === void 0 ? AUTONOMY_SAVE_NOT_COVERED_REASON : AUTONOMY_COULD_NOT_TELL_REASON };
|
|
31232
|
-
const r =
|
|
32233
|
+
const r = realOrSelf3(resolve8(t.repoRoot));
|
|
31233
32234
|
if (root === null)
|
|
31234
32235
|
root = r;
|
|
31235
32236
|
else if (root !== r)
|
|
@@ -31248,7 +32249,7 @@ function planOf(staked) {
|
|
|
31248
32249
|
function isInsideRel(p) {
|
|
31249
32250
|
if (p === ".")
|
|
31250
32251
|
return true;
|
|
31251
|
-
if (p === "" ||
|
|
32252
|
+
if (p === "" || isAbsolute6(p) || p.includes("\\"))
|
|
31252
32253
|
return false;
|
|
31253
32254
|
return p.split("/").every((s) => s !== "" && s !== "." && s !== "..");
|
|
31254
32255
|
}
|
|
@@ -31278,7 +32279,7 @@ function filesOf(plan, g, deadline) {
|
|
|
31278
32279
|
trackedAll.add(path);
|
|
31279
32280
|
if (!reached(path, plan.specs))
|
|
31280
32281
|
continue;
|
|
31281
|
-
const st = lstatOrNull(
|
|
32282
|
+
const st = lstatOrNull(join17(plan.root, path));
|
|
31282
32283
|
if (st !== null && (st.isFile() || st.isSymbolicLink()))
|
|
31283
32284
|
tracked.add(path);
|
|
31284
32285
|
}
|
|
@@ -31290,7 +32291,7 @@ function filesOf(plan, g, deadline) {
|
|
|
31290
32291
|
const rel = stack.pop();
|
|
31291
32292
|
if (rel === ".git")
|
|
31292
32293
|
continue;
|
|
31293
|
-
const abs = rel === "." ? plan.root :
|
|
32294
|
+
const abs = rel === "." ? plan.root : join17(plan.root, rel);
|
|
31294
32295
|
const st = lstatOrNull(abs);
|
|
31295
32296
|
if (st === null)
|
|
31296
32297
|
continue;
|
|
@@ -31328,13 +32329,13 @@ function copyOne(src, dst) {
|
|
|
31328
32329
|
}
|
|
31329
32330
|
copyFileSync(src, dst, fsConstants.COPYFILE_EXCL | fsConstants.COPYFILE_FICLONE);
|
|
31330
32331
|
chmodSync2(dst, st.mode & 4095);
|
|
31331
|
-
return
|
|
32332
|
+
return statSync9(dst).size === st.size;
|
|
31332
32333
|
}
|
|
31333
32334
|
function saveCommit(id, head, tracked, lines2, privateIndex, g, at) {
|
|
31334
32335
|
const indexPath = g.run(["rev-parse", "--git-path", "index"]);
|
|
31335
32336
|
if (!indexPath.ok)
|
|
31336
32337
|
return null;
|
|
31337
|
-
const projectIndex =
|
|
32338
|
+
const projectIndex = resolve8(g.root, indexPath.value.trim());
|
|
31338
32339
|
const env = commitEnv(privateIndex, at);
|
|
31339
32340
|
if (lstatOrNull(projectIndex) !== null)
|
|
31340
32341
|
copyFileSync(projectIndex, privateIndex);
|
|
@@ -31396,14 +32397,14 @@ var SaveGit = class {
|
|
|
31396
32397
|
});
|
|
31397
32398
|
}
|
|
31398
32399
|
};
|
|
31399
|
-
function freshId(
|
|
31400
|
-
mkdirSync9(
|
|
32400
|
+
function freshId(folder2, newId) {
|
|
32401
|
+
mkdirSync9(folder2, { recursive: true, mode: 448 });
|
|
31401
32402
|
for (let i = 0; i < 5; i++) {
|
|
31402
32403
|
const id = newId?.() ?? defaultId();
|
|
31403
32404
|
if (!savedIdSchema.safeParse(id).success)
|
|
31404
32405
|
return null;
|
|
31405
32406
|
try {
|
|
31406
|
-
mkdirSync9(
|
|
32407
|
+
mkdirSync9(join17(folder2, id), { mode: 448 });
|
|
31407
32408
|
return id;
|
|
31408
32409
|
} catch (e) {
|
|
31409
32410
|
if (e.code !== "EEXIST")
|
|
@@ -31424,19 +32425,19 @@ function repositoryOf(g) {
|
|
|
31424
32425
|
if (!r.ok)
|
|
31425
32426
|
return null;
|
|
31426
32427
|
const dir = r.value.trim();
|
|
31427
|
-
return dir === "" ? null :
|
|
32428
|
+
return dir === "" ? null : realOrSelf3(resolve8(g.root, dir));
|
|
31428
32429
|
}
|
|
31429
32430
|
function markedRepository(dir) {
|
|
31430
32431
|
try {
|
|
31431
|
-
const text = readFileSync24(
|
|
32432
|
+
const text = readFileSync24(join17(dir, SAVED_REPOSITORY_FILE_NAME), "utf-8").trim();
|
|
31432
32433
|
return text === "" ? null : text;
|
|
31433
32434
|
} catch {
|
|
31434
32435
|
return null;
|
|
31435
32436
|
}
|
|
31436
32437
|
}
|
|
31437
32438
|
function pruneSaves(root, engagementId, ctx = {}) {
|
|
31438
|
-
const
|
|
31439
|
-
if (
|
|
32439
|
+
const folder2 = savedFolderOf(engagementId, ctx.home);
|
|
32440
|
+
if (folder2 === null)
|
|
31440
32441
|
return;
|
|
31441
32442
|
const now = ctx.now ?? Date.now;
|
|
31442
32443
|
const g = new SaveGit(root, ctx.deadline ?? now() + SAVE_BUDGET_MS, now);
|
|
@@ -31453,7 +32454,7 @@ function pruneSaves(root, engagementId, ctx = {}) {
|
|
|
31453
32454
|
const repository = repositoryOf(g);
|
|
31454
32455
|
let names = [];
|
|
31455
32456
|
try {
|
|
31456
|
-
names = readdirSync10(
|
|
32457
|
+
names = readdirSync10(folder2);
|
|
31457
32458
|
} catch {
|
|
31458
32459
|
names = [];
|
|
31459
32460
|
}
|
|
@@ -31462,7 +32463,7 @@ function pruneSaves(root, engagementId, ctx = {}) {
|
|
|
31462
32463
|
if (!savedIdSchema.safeParse(id).success)
|
|
31463
32464
|
continue;
|
|
31464
32465
|
here.add(id);
|
|
31465
|
-
const dir =
|
|
32466
|
+
const dir = join17(folder2, id);
|
|
31466
32467
|
const st = lstatOrNull(dir);
|
|
31467
32468
|
const answer = savedPruneAnswer({
|
|
31468
32469
|
refMadeAt: refs.get(id) ?? null,
|
|
@@ -31491,9 +32492,9 @@ function lstatOrNull(p) {
|
|
|
31491
32492
|
return null;
|
|
31492
32493
|
}
|
|
31493
32494
|
}
|
|
31494
|
-
function
|
|
32495
|
+
function realOrSelf3(p) {
|
|
31495
32496
|
try {
|
|
31496
|
-
return
|
|
32497
|
+
return realpathSync9(p);
|
|
31497
32498
|
} catch {
|
|
31498
32499
|
return p;
|
|
31499
32500
|
}
|
|
@@ -31502,12 +32503,12 @@ function realOrSelf2(p) {
|
|
|
31502
32503
|
// dist/autonomy-state.js
|
|
31503
32504
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
31504
32505
|
import { chmodSync as chmodSync3, mkdirSync as mkdirSync10, readFileSync as readFileSync25, renameSync as renameSync13, rmSync as rmSync4, writeFileSync as writeFileSync15 } from "node:fs";
|
|
31505
|
-
import { homedir as
|
|
31506
|
-
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";
|
|
31507
32508
|
var AUTONOMY_STATE_FILENAME = "autonomy.json";
|
|
31508
32509
|
var AUTONOMY_STATE_DEADLINE_MS = 1500;
|
|
31509
32510
|
function autonomyStateFilePath(engagementId, home) {
|
|
31510
|
-
return
|
|
32511
|
+
return join18(home ?? homedir12(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, AUTONOMY_STATE_FILENAME);
|
|
31511
32512
|
}
|
|
31512
32513
|
function readCachedAutonomy(engagementId, nowMs, home) {
|
|
31513
32514
|
if (!isEngagementId(engagementId))
|
|
@@ -31535,6 +32536,7 @@ function confirmMayPublishNow(opts) {
|
|
|
31535
32536
|
timeout: opts.timeoutMs,
|
|
31536
32537
|
windowsHide: true
|
|
31537
32538
|
});
|
|
32539
|
+
recordChildRequest(url2, ["Authorization"], r.status === 0);
|
|
31538
32540
|
if (r.status !== 0 || typeof r.stdout !== "string")
|
|
31539
32541
|
return false;
|
|
31540
32542
|
const parsed = autonomyStateSchema.safeParse(JSON.parse(r.stdout));
|
|
@@ -31559,7 +32561,7 @@ function deleteAutonomyStateFile(engagementId, home) {
|
|
|
31559
32561
|
}
|
|
31560
32562
|
function writeAutonomyStateFile(engagementId, file2, home) {
|
|
31561
32563
|
const target = autonomyStateFilePath(engagementId, home);
|
|
31562
|
-
const temp =
|
|
32564
|
+
const temp = join18(dirname8(target), `.${AUTONOMY_STATE_FILENAME}.${process.pid}.tmp`);
|
|
31563
32565
|
try {
|
|
31564
32566
|
mkdirSync10(dirname8(target), { recursive: true, mode: 448 });
|
|
31565
32567
|
writeFileSync15(temp, `${JSON.stringify(file2)}
|
|
@@ -31621,7 +32623,7 @@ async function cacheAutonomySetting(opts) {
|
|
|
31621
32623
|
}
|
|
31622
32624
|
|
|
31623
32625
|
// dist/risky/patch-calls.js
|
|
31624
|
-
import { isAbsolute as
|
|
32626
|
+
import { isAbsolute as isAbsolute7, resolve as resolve9 } from "node:path";
|
|
31625
32627
|
var SHELL_TOOL = "Bash";
|
|
31626
32628
|
function toolCallsOf(input, profile) {
|
|
31627
32629
|
const toolName = input["tool_name"];
|
|
@@ -31644,7 +32646,7 @@ function toolCallsOf(input, profile) {
|
|
|
31644
32646
|
const ops = patchOperations(command);
|
|
31645
32647
|
if (ops === null || ops.length === 0)
|
|
31646
32648
|
return null;
|
|
31647
|
-
const cwd = typeof input["cwd"] === "string" &&
|
|
32649
|
+
const cwd = typeof input["cwd"] === "string" && isAbsolute7(input["cwd"]) ? input["cwd"] : null;
|
|
31648
32650
|
const calls = [];
|
|
31649
32651
|
for (const op of ops) {
|
|
31650
32652
|
const made = callsFor(op, cwd);
|
|
@@ -31682,9 +32684,9 @@ function callsFor(op, cwd) {
|
|
|
31682
32684
|
}
|
|
31683
32685
|
}
|
|
31684
32686
|
function placed(path, cwd) {
|
|
31685
|
-
if (
|
|
31686
|
-
return
|
|
31687
|
-
return cwd === null ? null :
|
|
32687
|
+
if (isAbsolute7(path))
|
|
32688
|
+
return resolve9(path);
|
|
32689
|
+
return cwd === null ? null : resolve9(cwd, path);
|
|
31688
32690
|
}
|
|
31689
32691
|
function shellWord(text) {
|
|
31690
32692
|
return `'${text.split("'").join("'\\''")}'`;
|
|
@@ -31692,7 +32694,7 @@ function shellWord(text) {
|
|
|
31692
32694
|
|
|
31693
32695
|
// dist/hooks/pre-tool-use.js
|
|
31694
32696
|
import { performance } from "node:perf_hooks";
|
|
31695
|
-
import { homedir as
|
|
32697
|
+
import { homedir as homedir13 } from "node:os";
|
|
31696
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.";
|
|
31697
32699
|
var PRE_TOOL_USE_LIMIT_MS = (HALFCYCLE_HOOK_WIRING.find((e) => e.event === "PreToolUse")?.timeout ?? 10) * 1e3;
|
|
31698
32700
|
var AUTONOMY_REPLY_MARGIN_MS = 1e3;
|
|
@@ -31763,6 +32765,11 @@ function runPreToolUse(deps) {
|
|
|
31763
32765
|
if (held !== null)
|
|
31764
32766
|
return `${preToolUseReplyText("refuse", held)}
|
|
31765
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
|
+
});
|
|
31766
32773
|
}
|
|
31767
32774
|
return own.kind === "unknown" ? ownCopyNotice(input, deps) : "";
|
|
31768
32775
|
}
|
|
@@ -31771,16 +32778,19 @@ function runPreToolUse(deps) {
|
|
|
31771
32778
|
return `${preToolUseReplyText("ask", answer.question)}
|
|
31772
32779
|
`;
|
|
31773
32780
|
}
|
|
32781
|
+
let agentText = answer.refusal.agent;
|
|
31774
32782
|
if (allowableByTyping(call, answer.staked)) {
|
|
31775
|
-
const key = stepKey(input, answer.staked);
|
|
32783
|
+
const key = stepKey(input, answer.staked, deps.gitTimeoutMs === void 0 ? {} : { gitTimeoutMs: deps.gitTimeoutMs });
|
|
31776
32784
|
if (key !== null) {
|
|
31777
32785
|
const allowOnce = { ...deps.liveness?.dir === void 0 ? {} : { dir: deps.liveness.dir }, now: () => at.getTime() };
|
|
31778
32786
|
if (spendAllow(input["session_id"], key, allowOnce))
|
|
31779
32787
|
return "";
|
|
31780
|
-
|
|
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);
|
|
31781
32791
|
}
|
|
31782
32792
|
}
|
|
31783
|
-
return `${preToolUseReplyText("refuse", answer.refusal.person,
|
|
32793
|
+
return `${preToolUseReplyText("refuse", answer.refusal.person, agentText)}
|
|
31784
32794
|
`;
|
|
31785
32795
|
} catch {
|
|
31786
32796
|
return "";
|
|
@@ -31908,7 +32918,7 @@ function ownCopyOf(input, call, deps) {
|
|
|
31908
32918
|
const walk2 = deps.walk ?? deps.liveness?.walk;
|
|
31909
32919
|
return judgeOwnCopy(input, call, {
|
|
31910
32920
|
projectDir: projectDirOf(deps),
|
|
31911
|
-
home: deps.home ??
|
|
32921
|
+
home: deps.home ?? homedir13(),
|
|
31912
32922
|
...walk2 === void 0 ? {} : { walk: walk2 },
|
|
31913
32923
|
...deps.liveness === void 0 ? {} : { liveness: deps.liveness }
|
|
31914
32924
|
});
|
|
@@ -31917,8 +32927,8 @@ function ownCopyOf(input, call, deps) {
|
|
|
31917
32927
|
}
|
|
31918
32928
|
}
|
|
31919
32929
|
function ownCopyNotice(input, deps) {
|
|
31920
|
-
const
|
|
31921
|
-
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)}
|
|
31922
32932
|
` : "";
|
|
31923
32933
|
}
|
|
31924
32934
|
function parseObject2(text) {
|
|
@@ -31935,14 +32945,14 @@ function stringOf(input, key) {
|
|
|
31935
32945
|
}
|
|
31936
32946
|
function unreadable(deps, input) {
|
|
31937
32947
|
const session = (input === null ? void 0 : stringOf(input, "session_id")) ?? /"session_id"\s*:\s*"([^"\\]+)"/.exec(deps.input)?.[1];
|
|
31938
|
-
const
|
|
31939
|
-
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)}
|
|
31940
32950
|
` : "";
|
|
31941
32951
|
}
|
|
31942
32952
|
|
|
31943
32953
|
// dist/hooks/session-diff.js
|
|
31944
32954
|
import { unlinkSync as unlinkSync10 } from "node:fs";
|
|
31945
|
-
import { join as
|
|
32955
|
+
import { join as join19 } from "node:path";
|
|
31946
32956
|
var STOP_HOOK_EVENT = {
|
|
31947
32957
|
stop: "Stop",
|
|
31948
32958
|
"subagent-stop": "SubagentStop"
|
|
@@ -31994,7 +33004,7 @@ async function evaluateSession(input, kind, reply, readSeat, profile) {
|
|
|
31994
33004
|
}
|
|
31995
33005
|
const repoRoot = repoRootResult.value;
|
|
31996
33006
|
const sessionId = input.session_id;
|
|
31997
|
-
const
|
|
33007
|
+
const folder2 = realPathOf(repoRoot);
|
|
31998
33008
|
orphanSweep(repoRoot, (ref) => refExists(ref, repoRoot), sessionId, Date.now(), whichCopy(process.cwd())?.common ?? null);
|
|
31999
33009
|
const base = resolveDiffBase2(repoRoot, sessionId);
|
|
32000
33010
|
const diffBase = base.kind;
|
|
@@ -32007,12 +33017,12 @@ async function evaluateSession(input, kind, reply, readSeat, profile) {
|
|
|
32007
33017
|
const candidates = ownEditedFiles(repoRoot, sessionId).filter((relPath) => !tracked.has(relPath));
|
|
32008
33018
|
const untracked = getUntrackedFiles(repoRoot, candidates);
|
|
32009
33019
|
const created = untracked.ok ? untracked.value.filter((relPath) => !tracked.has(relPath)) : [];
|
|
32010
|
-
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);
|
|
32011
33021
|
const { evaluated } = partitionInstallerOutput(collected.files);
|
|
32012
33022
|
const { evaluated: createdEvaluated } = partitionInstallerOutput(created);
|
|
32013
33023
|
const changedFiles2 = [...ownChangedFiles(repoRoot, evaluated, sessionId), ...createdEvaluated];
|
|
32014
33024
|
if (changedFiles2.length === 0) {
|
|
32015
|
-
queueTurnEnd(keepBooks(sessionId,
|
|
33025
|
+
queueTurnEnd(keepBooks(sessionId, folder2, { kind: "no-own-changes" }, kind === "stop"), reply);
|
|
32016
33026
|
return;
|
|
32017
33027
|
}
|
|
32018
33028
|
const fileDiffEntries = changedFiles2.map((relPath) => ({
|
|
@@ -32023,7 +33033,7 @@ async function evaluateSession(input, kind, reply, readSeat, profile) {
|
|
|
32023
33033
|
const digest = digestChangeState(baseKey, fileDiffEntries);
|
|
32024
33034
|
const prior = readDedupe(repoRoot, sessionId);
|
|
32025
33035
|
if (prior && prior.base === baseKey && prior.digest === digest) {
|
|
32026
|
-
queueTurnEnd(keepBooks(sessionId,
|
|
33036
|
+
queueTurnEnd(keepBooks(sessionId, folder2, { kind: "unchanged" }, kind === "stop"), reply);
|
|
32027
33037
|
return;
|
|
32028
33038
|
}
|
|
32029
33039
|
const context = loadChangeSetContext(repoRoot);
|
|
@@ -32103,12 +33113,12 @@ async function evaluateSession(input, kind, reply, readSeat, profile) {
|
|
|
32103
33113
|
warn: (msg) => process.stderr.write(msg + "\n")
|
|
32104
33114
|
});
|
|
32105
33115
|
writeDedupe(repoRoot, sessionId, { base: baseKey, digest });
|
|
32106
|
-
actOnEnvelope3(clientResult.envelope, kind, input.stop_hook_active === true, reply, sessionId,
|
|
33116
|
+
actOnEnvelope3(clientResult.envelope, kind, input.stop_hook_active === true, reply, sessionId, folder2);
|
|
32107
33117
|
}
|
|
32108
|
-
function keepBooks(sessionId,
|
|
33118
|
+
function keepBooks(sessionId, folder2, outcome, topLevel) {
|
|
32109
33119
|
const books = () => {
|
|
32110
33120
|
const before = readFindings(sessionId);
|
|
32111
|
-
const { file: file2, news } = turnEndBookkeeping(before ?? emptyFindings(""),
|
|
33121
|
+
const { file: file2, news } = turnEndBookkeeping(before ?? emptyFindings(""), folder2, outcome, topLevel, /* @__PURE__ */ new Date());
|
|
32112
33122
|
if (before !== null && JSON.stringify(before) !== JSON.stringify(file2)) {
|
|
32113
33123
|
if (file2.findings.length > 0)
|
|
32114
33124
|
writeFindings(file2);
|
|
@@ -32133,7 +33143,7 @@ function queueTurnEnd(words, reply) {
|
|
|
32133
33143
|
if (words !== null)
|
|
32134
33144
|
reply.notice(words);
|
|
32135
33145
|
}
|
|
32136
|
-
function actOnEnvelope3(envelope, kind, neverBlock, reply, sessionId,
|
|
33146
|
+
function actOnEnvelope3(envelope, kind, neverBlock, reply, sessionId, folder2) {
|
|
32137
33147
|
const notRun = notRunMessage((envelope.notRun ?? []).map((n) => n.reason));
|
|
32138
33148
|
const outcome = {
|
|
32139
33149
|
kind: "evaluated",
|
|
@@ -32142,7 +33152,7 @@ function actOnEnvelope3(envelope, kind, neverBlock, reply, sessionId, folder) {
|
|
|
32142
33152
|
};
|
|
32143
33153
|
const topLevel = kind === "stop";
|
|
32144
33154
|
if (envelope.blocking && !neverBlock) {
|
|
32145
|
-
keepBooks(sessionId,
|
|
33155
|
+
keepBooks(sessionId, folder2, outcome, false);
|
|
32146
33156
|
const reason = blockReason(envelope.guardsFired.map((g) => g.explanation));
|
|
32147
33157
|
reply.block(notRun ? `${reason}
|
|
32148
33158
|
${notRun}` : reason, stoppedMessage(blockingExplanations(envelope.guardsFired)));
|
|
@@ -32150,7 +33160,7 @@ ${notRun}` : reason, stoppedMessage(blockingExplanations(envelope.guardsFired)))
|
|
|
32150
33160
|
if (envelope.blocking && neverBlock) {
|
|
32151
33161
|
reply.notice(couldNotFixMessage(blockingExplanations(envelope.guardsFired)));
|
|
32152
33162
|
}
|
|
32153
|
-
queueTurnEnd(keepBooks(sessionId,
|
|
33163
|
+
queueTurnEnd(keepBooks(sessionId, folder2, outcome, topLevel), reply);
|
|
32154
33164
|
if (notRun)
|
|
32155
33165
|
reply.notice(notRun);
|
|
32156
33166
|
}
|
|
@@ -32171,9 +33181,9 @@ async function readHookStdin() {
|
|
|
32171
33181
|
}
|
|
32172
33182
|
}
|
|
32173
33183
|
function readStdin2() {
|
|
32174
|
-
return new Promise((
|
|
33184
|
+
return new Promise((resolve12) => {
|
|
32175
33185
|
if (process.stdin.isTTY) {
|
|
32176
|
-
|
|
33186
|
+
resolve12("");
|
|
32177
33187
|
return;
|
|
32178
33188
|
}
|
|
32179
33189
|
const chunks = [];
|
|
@@ -32183,7 +33193,7 @@ function readStdin2() {
|
|
|
32183
33193
|
return;
|
|
32184
33194
|
settled2 = true;
|
|
32185
33195
|
clearTimeout(timer);
|
|
32186
|
-
|
|
33196
|
+
resolve12(Buffer.concat(chunks).toString("utf-8"));
|
|
32187
33197
|
};
|
|
32188
33198
|
const timer = setTimeout(done, HOOK_STDIN_GRACE_MS);
|
|
32189
33199
|
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
@@ -32210,19 +33220,19 @@ async function runStop(observeDeps = {}, timeDeps = {}, paceDeps = {}, profile =
|
|
|
32210
33220
|
recordTimeEvent("turn-end", input);
|
|
32211
33221
|
await runSessionDiff(input, "stop", readSeatConfiguration, async (reply) => {
|
|
32212
33222
|
await observeChanges(input.session_id, reply, observeDeps);
|
|
32213
|
-
await sendTimeRecord(timeDeps);
|
|
33223
|
+
await sendTimeRecord(timeDeps, { agent: profile.id });
|
|
32214
33224
|
await paceAtTurnEnd(input, reply, { configFolder: profile.configFolder, ...paceDeps });
|
|
32215
33225
|
}, profile);
|
|
32216
33226
|
}
|
|
32217
33227
|
|
|
32218
33228
|
// dist/relayed-choices.js
|
|
32219
33229
|
import { mkdirSync as mkdirSync11, readFileSync as readFileSync26, renameSync as renameSync14, rmSync as rmSync5, writeFileSync as writeFileSync16 } from "node:fs";
|
|
32220
|
-
import { homedir as
|
|
32221
|
-
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";
|
|
32222
33232
|
function relayedChoicesFilePath(engagementId, home) {
|
|
32223
33233
|
if (!isEngagementId(engagementId))
|
|
32224
33234
|
return null;
|
|
32225
|
-
return
|
|
33235
|
+
return join20(home ?? homedir14(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, PACING_DIR_NAME, RELAYED_CHOICES_FILENAME);
|
|
32226
33236
|
}
|
|
32227
33237
|
function readRelayedChoices(engagementId, phase, home) {
|
|
32228
33238
|
const path = relayedChoicesFilePath(engagementId, home);
|
|
@@ -32258,7 +33268,7 @@ function recordRelayedChoice(opts) {
|
|
|
32258
33268
|
});
|
|
32259
33269
|
if (!file2.success)
|
|
32260
33270
|
return false;
|
|
32261
|
-
const temp =
|
|
33271
|
+
const temp = join20(dirname9(target), `.${RELAYED_CHOICES_FILENAME}.${process.pid}.tmp`);
|
|
32262
33272
|
try {
|
|
32263
33273
|
mkdirSync11(dirname9(target), { recursive: true, mode: 448 });
|
|
32264
33274
|
writeFileSync16(temp, `${JSON.stringify(file2.data)}
|
|
@@ -32487,19 +33497,19 @@ function matchReviewPhraseShape(shape, reviews) {
|
|
|
32487
33497
|
|
|
32488
33498
|
// dist/hooks/shown-record.js
|
|
32489
33499
|
import { chmodSync as chmodSync4, readFileSync as readFileSync27, renameSync as renameSync15, unlinkSync as unlinkSync11, writeFileSync as writeFileSync17 } from "node:fs";
|
|
32490
|
-
import { homedir as
|
|
32491
|
-
import { join as
|
|
33500
|
+
import { homedir as homedir15, platform as platform3 } from "node:os";
|
|
33501
|
+
import { join as join21 } from "node:path";
|
|
32492
33502
|
function recordDir(engagementId, home) {
|
|
32493
33503
|
if (!isEngagementId(engagementId))
|
|
32494
33504
|
return null;
|
|
32495
|
-
return
|
|
33505
|
+
return join21(home ?? homedir15(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId);
|
|
32496
33506
|
}
|
|
32497
33507
|
function readShownRecord(engagementId, home) {
|
|
32498
33508
|
const dir = recordDir(engagementId, home);
|
|
32499
33509
|
if (dir === null)
|
|
32500
33510
|
return { entries: [], reviews: [] };
|
|
32501
33511
|
try {
|
|
32502
|
-
return parseShownRecord(readFileSync27(
|
|
33512
|
+
return parseShownRecord(readFileSync27(join21(dir, SHOWN_PLANS_FILENAME), "utf-8"));
|
|
32503
33513
|
} catch {
|
|
32504
33514
|
return { entries: [], reviews: [] };
|
|
32505
33515
|
}
|
|
@@ -32520,7 +33530,7 @@ function moveListedReviewForward(engagementId, home, listed, reviewVersion, deci
|
|
|
32520
33530
|
const dir = recordDir(engagementId, home);
|
|
32521
33531
|
if (dir === null)
|
|
32522
33532
|
return false;
|
|
32523
|
-
const path =
|
|
33533
|
+
const path = join21(dir, SHOWN_PLANS_FILENAME);
|
|
32524
33534
|
const current = parseShownRecord(readFileSync27(path, "utf-8"));
|
|
32525
33535
|
const at = current.reviews.findIndex((r) => r.phase === listed.phase && r.shownAt === listed.shownAt && r.reviewVersion === listed.reviewVersion);
|
|
32526
33536
|
if (at === -1)
|
|
@@ -32528,7 +33538,7 @@ function moveListedReviewForward(engagementId, home, listed, reviewVersion, deci
|
|
|
32528
33538
|
const acts = new Map(decided.map((d) => [d.part, d.act]));
|
|
32529
33539
|
const reviews = current.reviews.map((review, i) => i === at ? { ...review, reviewVersion, parts: review.parts.map((p) => movedPart(p, acts.get(p.part))) } : review);
|
|
32530
33540
|
const body = serialiseShownRecord({ entries: current.entries, reviews });
|
|
32531
|
-
temp =
|
|
33541
|
+
temp = join21(dir, `.${SHOWN_PLANS_FILENAME}.${process.pid}.tmp`);
|
|
32532
33542
|
writeFileSync17(temp, body, { mode: 384 });
|
|
32533
33543
|
if (platform3() !== "win32")
|
|
32534
33544
|
chmodSync4(temp, 384);
|
|
@@ -32912,8 +33922,16 @@ function allowArmedLine(step = null) {
|
|
|
32912
33922
|
function allowNothingHeldLine() {
|
|
32913
33923
|
return line(`${NOTHING_ALLOWED}: no step is paused in this session.`);
|
|
32914
33924
|
}
|
|
32915
|
-
|
|
32916
|
-
|
|
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.`);
|
|
32917
33935
|
}
|
|
32918
33936
|
function allowNotAttendedLine() {
|
|
32919
33937
|
return line(`${NOTHING_ALLOWED}: a paused step can be allowed by typing only when a person types it into an open session.`);
|
|
@@ -32999,8 +34017,8 @@ function waitLineForAnswer(context, answer) {
|
|
|
32999
34017
|
}
|
|
33000
34018
|
}
|
|
33001
34019
|
var PACE_NOTHING_CHANGED_OPENING = "Nothing changed";
|
|
33002
|
-
function paceAnswerLine(text,
|
|
33003
|
-
return
|
|
34020
|
+
function paceAnswerLine(text, _agent) {
|
|
34021
|
+
return codexLine(text);
|
|
33004
34022
|
}
|
|
33005
34023
|
function paceNumberDoneText(n, more) {
|
|
33006
34024
|
const head = `Done. This build now runs up to ${paceAgentsOf(n)} at once.`;
|
|
@@ -33108,8 +34126,9 @@ async function decideLine(opts) {
|
|
|
33108
34126
|
const review = { recognised: false };
|
|
33109
34127
|
try {
|
|
33110
34128
|
const prompt = promptOf(opts.input);
|
|
33111
|
-
|
|
33112
|
-
|
|
34129
|
+
const allowReply = allowReplyOf(prompt);
|
|
34130
|
+
if (allowReply !== null)
|
|
34131
|
+
return `${decideAllow(allowReply.number, opts)}
|
|
33113
34132
|
`;
|
|
33114
34133
|
const autonomyShape = autonomyPhraseShape(prompt);
|
|
33115
34134
|
if (autonomyShape !== null) {
|
|
@@ -33162,21 +34181,23 @@ async function decideLine(opts) {
|
|
|
33162
34181
|
`;
|
|
33163
34182
|
}
|
|
33164
34183
|
}
|
|
33165
|
-
function decideAllow(opts) {
|
|
34184
|
+
function decideAllow(stepNumber, opts) {
|
|
33166
34185
|
const env = opts.env ?? process.env;
|
|
33167
34186
|
if ((opts.agent ?? "claude-code") === "claude-code" && !readSessionAttended(env))
|
|
33168
34187
|
return allowNotAttendedLine();
|
|
33169
|
-
const { outcome, step } = armAllowStep(sessionIdOf(opts.input), {
|
|
34188
|
+
const { outcome, step, paused } = armAllowStep(sessionIdOf(opts.input), {
|
|
33170
34189
|
...opts.tempDir === void 0 ? {} : { dir: opts.tempDir },
|
|
33171
34190
|
...opts.now === void 0 ? {} : { now: opts.now }
|
|
33172
|
-
});
|
|
34191
|
+
}, stepNumber);
|
|
33173
34192
|
switch (outcome) {
|
|
33174
34193
|
case "armed":
|
|
33175
34194
|
return allowArmedLine(step);
|
|
33176
34195
|
case "nothing-held":
|
|
33177
34196
|
return allowNothingHeldLine();
|
|
34197
|
+
case "not-paused":
|
|
34198
|
+
return allowNotPausedLine(stepNumber ?? 0);
|
|
33178
34199
|
case "several-held":
|
|
33179
|
-
return allowSeveralHeldLine();
|
|
34200
|
+
return allowSeveralHeldLine(paused);
|
|
33180
34201
|
case "not-saved":
|
|
33181
34202
|
return allowNotSavedLine();
|
|
33182
34203
|
default: {
|
|
@@ -33703,14 +34724,14 @@ function runUserPromptFindings(opts) {
|
|
|
33703
34724
|
}
|
|
33704
34725
|
|
|
33705
34726
|
// dist/resolve-engagement.js
|
|
33706
|
-
import { existsSync as
|
|
33707
|
-
import { join as
|
|
33708
|
-
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";
|
|
33709
34730
|
function defaultRegistryPath() {
|
|
33710
|
-
return
|
|
34731
|
+
return join22(homedir16(), ".halfcycle", "registry.json");
|
|
33711
34732
|
}
|
|
33712
34733
|
function readRegistry(registryPath = defaultRegistryPath()) {
|
|
33713
|
-
if (!
|
|
34734
|
+
if (!existsSync9(registryPath))
|
|
33714
34735
|
return {};
|
|
33715
34736
|
try {
|
|
33716
34737
|
const parsed = JSON.parse(readFileSync28(registryPath, "utf-8"));
|
|
@@ -33728,7 +34749,7 @@ function readRegistry(registryPath = defaultRegistryPath()) {
|
|
|
33728
34749
|
}
|
|
33729
34750
|
function canonicalise(p) {
|
|
33730
34751
|
try {
|
|
33731
|
-
return
|
|
34752
|
+
return realpathSync10(p);
|
|
33732
34753
|
} catch {
|
|
33733
34754
|
return p;
|
|
33734
34755
|
}
|
|
@@ -33749,7 +34770,7 @@ function resolveEngagement(cwd, registry2) {
|
|
|
33749
34770
|
function isSelfOrAncestor(ancestor, target) {
|
|
33750
34771
|
if (ancestor === target)
|
|
33751
34772
|
return true;
|
|
33752
|
-
const withSep = ancestor.endsWith(
|
|
34773
|
+
const withSep = ancestor.endsWith(sep7) ? ancestor : ancestor + sep7;
|
|
33753
34774
|
return target.startsWith(withSep);
|
|
33754
34775
|
}
|
|
33755
34776
|
function runResolveEngagement(cwd, registryPath) {
|
|
@@ -33762,12 +34783,12 @@ function runResolveEngagement(cwd, registryPath) {
|
|
|
33762
34783
|
|
|
33763
34784
|
// dist/refresh-credential.js
|
|
33764
34785
|
import { readFileSync as readFileSync30 } from "node:fs";
|
|
33765
|
-
import { resolve as
|
|
34786
|
+
import { resolve as resolve11 } from "node:path";
|
|
33766
34787
|
|
|
33767
34788
|
// dist/mcp-headers.js
|
|
33768
34789
|
import { readFileSync as readFileSync29 } from "node:fs";
|
|
33769
|
-
import { homedir as
|
|
33770
|
-
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";
|
|
33771
34792
|
var URL_FLAG = "--url";
|
|
33772
34793
|
function urlFromArguments(rest) {
|
|
33773
34794
|
const at = [];
|
|
@@ -33794,12 +34815,12 @@ function headerLine(bearer, clientVersion) {
|
|
|
33794
34815
|
}
|
|
33795
34816
|
function projectRootFromBinary(binaryPath) {
|
|
33796
34817
|
const depth = VENDORED_BIN_REL.split("/").length - 1;
|
|
33797
|
-
return
|
|
34818
|
+
return resolve10(dirname10(binaryPath), ...Array(depth).fill(".."));
|
|
33798
34819
|
}
|
|
33799
34820
|
function readPinnedVersion(root) {
|
|
33800
34821
|
let raw;
|
|
33801
34822
|
try {
|
|
33802
|
-
raw = readFileSync29(
|
|
34823
|
+
raw = readFileSync29(resolve10(root, BUNDLE_PIN_REL), "utf-8");
|
|
33803
34824
|
} catch {
|
|
33804
34825
|
return void 0;
|
|
33805
34826
|
}
|
|
@@ -33841,7 +34862,7 @@ function sentences(lines2) {
|
|
|
33841
34862
|
}
|
|
33842
34863
|
function badIdSentence(root) {
|
|
33843
34864
|
return sentences([
|
|
33844
|
-
`${
|
|
34865
|
+
`${resolve10(root, BUNDLE_PIN_REL)} names an engagement id that is not a Halfcycle project id,`,
|
|
33845
34866
|
'so no credential was read. Delete that file and run "npx halfcycle" again: this repository',
|
|
33846
34867
|
"is then set up as a new Halfcycle project."
|
|
33847
34868
|
]);
|
|
@@ -33855,7 +34876,7 @@ function storeProblemSentence(problem, root, home, engagementId) {
|
|
|
33855
34876
|
]);
|
|
33856
34877
|
case "no-id":
|
|
33857
34878
|
return sentences([
|
|
33858
|
-
`${
|
|
34879
|
+
`${resolve10(root, BUNDLE_PIN_REL)} names no engagement id.`,
|
|
33859
34880
|
'run "npx halfcycle" here to rewrite it.'
|
|
33860
34881
|
]);
|
|
33861
34882
|
case "bad-id":
|
|
@@ -33872,7 +34893,7 @@ function storeProblemSentence(problem, root, home, engagementId) {
|
|
|
33872
34893
|
case "no-credential":
|
|
33873
34894
|
return sentences([
|
|
33874
34895
|
`this machine holds no credential for engagement ${engagementId ?? ""}.`,
|
|
33875
|
-
`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.`
|
|
33876
34897
|
]);
|
|
33877
34898
|
}
|
|
33878
34899
|
}
|
|
@@ -33895,7 +34916,7 @@ async function refreshWithinDeadline(source, opts, writeErr) {
|
|
|
33895
34916
|
}
|
|
33896
34917
|
async function chooseBearer(opts) {
|
|
33897
34918
|
const writeErr = opts.writeErr ?? defaultWriteErr;
|
|
33898
|
-
const home = opts.home ??
|
|
34919
|
+
const home = opts.home ?? homedir17();
|
|
33899
34920
|
const root = projectRootFromBinary(opts.binaryPath);
|
|
33900
34921
|
const environmentToken = opts.environmentTokenFirst ? readEnvironmentToken() : void 0;
|
|
33901
34922
|
const store = resolveStore(root, home);
|
|
@@ -34038,8 +35059,8 @@ async function refreshCredentialToken(opts) {
|
|
|
34038
35059
|
source
|
|
34039
35060
|
});
|
|
34040
35061
|
if (!refreshed.ok) {
|
|
34041
|
-
const
|
|
34042
|
-
|
|
35062
|
+
const write2 = opts?.write ?? ((text) => process.stdout.write(text));
|
|
35063
|
+
write2(credentialRenewalFailedMessage(refreshed.remedy));
|
|
34043
35064
|
return { token: void 0 };
|
|
34044
35065
|
}
|
|
34045
35066
|
return { token: refreshed.token };
|
|
@@ -34061,7 +35082,7 @@ var SESSION_START_PROBE_ATTEMPTS = 2;
|
|
|
34061
35082
|
function registeredMcpUrl(projectRoot) {
|
|
34062
35083
|
let parsed;
|
|
34063
35084
|
try {
|
|
34064
|
-
parsed = JSON.parse(readFileSync30(
|
|
35085
|
+
parsed = JSON.parse(readFileSync30(resolve11(projectRoot, MCP_REGISTRATION_REL), "utf-8"));
|
|
34065
35086
|
} catch {
|
|
34066
35087
|
return void 0;
|
|
34067
35088
|
}
|
|
@@ -34310,7 +35331,7 @@ async function runRefreshCredential(opts) {
|
|
|
34310
35331
|
import { fileURLToPath } from "node:url";
|
|
34311
35332
|
|
|
34312
35333
|
// dist/capture.js
|
|
34313
|
-
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";
|
|
34314
35335
|
import { dirname as dirname11 } from "node:path";
|
|
34315
35336
|
function runCapture(provider, endpoint, opts = {}) {
|
|
34316
35337
|
const repoRoot = opts.repoRoot ?? process.cwd();
|
|
@@ -34392,8 +35413,8 @@ function relativeFixturePath(repoRoot, fixture) {
|
|
|
34392
35413
|
import { spawn as spawn2, spawnSync as spawnSync3 } from "node:child_process";
|
|
34393
35414
|
import { createHash as createHash6, randomUUID as randomUUID3 } from "node:crypto";
|
|
34394
35415
|
import { createWriteStream, mkdirSync as mkdirSync13, readdirSync as readdirSync11, readFileSync as readFileSync32, renameSync as renameSync16, unlinkSync as unlinkSync12, writeFileSync as writeFileSync19 } from "node:fs";
|
|
34395
|
-
import { homedir as
|
|
34396
|
-
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";
|
|
34397
35418
|
|
|
34398
35419
|
// dist/test-counts.js
|
|
34399
35420
|
function sum(values) {
|
|
@@ -34502,7 +35523,7 @@ function isProofTestPath(path) {
|
|
|
34502
35523
|
function testRunsDir(engagementId, home) {
|
|
34503
35524
|
if (!isEngagementId(engagementId))
|
|
34504
35525
|
return null;
|
|
34505
|
-
return
|
|
35526
|
+
return join23(home ?? homedir18(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, TEST_RUNS_DIR_NAME);
|
|
34506
35527
|
}
|
|
34507
35528
|
function commandIdOf(command) {
|
|
34508
35529
|
return createHash6("sha256").update(command, "utf8").digest("hex").slice(0, 16);
|
|
@@ -34598,7 +35619,7 @@ function subjectKey(subject) {
|
|
|
34598
35619
|
}
|
|
34599
35620
|
function keptCheckPath(dir, subject, label) {
|
|
34600
35621
|
const key = createHash6("sha256").update(JSON.stringify([...subjectKey(subject), label]), "utf8").digest("hex");
|
|
34601
|
-
return
|
|
35622
|
+
return join23(dir, COMMANDS_DIR_NAME, `${key.slice(0, 32)}.json`);
|
|
34602
35623
|
}
|
|
34603
35624
|
function readKeptCheck(dir, subject, label) {
|
|
34604
35625
|
try {
|
|
@@ -34613,18 +35634,18 @@ function readKeptCheck(dir, subject, label) {
|
|
|
34613
35634
|
}
|
|
34614
35635
|
}
|
|
34615
35636
|
function queuePath(dir, runId) {
|
|
34616
|
-
return
|
|
35637
|
+
return join23(dir, QUEUE_DIR_NAME, `${runId}.json`);
|
|
34617
35638
|
}
|
|
34618
35639
|
function readQueue(dir) {
|
|
34619
35640
|
let names;
|
|
34620
35641
|
try {
|
|
34621
|
-
names = readdirSync11(
|
|
35642
|
+
names = readdirSync11(join23(dir, QUEUE_DIR_NAME)).filter((n) => n.endsWith(".json"));
|
|
34622
35643
|
} catch {
|
|
34623
35644
|
return [];
|
|
34624
35645
|
}
|
|
34625
35646
|
const reports = [];
|
|
34626
35647
|
for (const name of names) {
|
|
34627
|
-
const path =
|
|
35648
|
+
const path = join23(dir, QUEUE_DIR_NAME, name);
|
|
34628
35649
|
let parsed = null;
|
|
34629
35650
|
try {
|
|
34630
35651
|
parsed = testRunReportSchema.safeParse(JSON.parse(readFileSync32(path, "utf-8")));
|
|
@@ -34697,17 +35718,17 @@ function killTree(child, platform4, signal) {
|
|
|
34697
35718
|
}
|
|
34698
35719
|
}
|
|
34699
35720
|
}
|
|
34700
|
-
function runCommand(command, repoRoot,
|
|
35721
|
+
function runCommand(command, repoRoot, logPath2, env, deps) {
|
|
34701
35722
|
const platform4 = deps.platform ?? process.platform;
|
|
34702
35723
|
const out = deps.stdout ?? process.stdout;
|
|
34703
35724
|
const err = deps.stderr ?? process.stderr;
|
|
34704
35725
|
const deadline = deps.deadlineMs ?? PROVE_RUN_DEADLINE_MS;
|
|
34705
35726
|
const childEnv = { ...env };
|
|
34706
35727
|
delete childEnv[SERVICE_TOKEN_VAR];
|
|
34707
|
-
mkdirSync13(dirname12(
|
|
34708
|
-
const log = createWriteStream(
|
|
35728
|
+
mkdirSync13(dirname12(logPath2), { recursive: true, mode: 448 });
|
|
35729
|
+
const log = createWriteStream(logPath2, { mode: 384 });
|
|
34709
35730
|
const began = process.hrtime.bigint();
|
|
34710
|
-
return new Promise((
|
|
35731
|
+
return new Promise((resolve12) => {
|
|
34711
35732
|
let timedOut = false;
|
|
34712
35733
|
let started = true;
|
|
34713
35734
|
let settled2 = false;
|
|
@@ -34742,7 +35763,7 @@ function runCommand(command, repoRoot, logPath, env, deps) {
|
|
|
34742
35763
|
process.off("SIGINT", onSignal);
|
|
34743
35764
|
process.off("SIGTERM", onSignal);
|
|
34744
35765
|
const durationMs = Number((process.hrtime.bigint() - began) / 1000000n);
|
|
34745
|
-
log.end(() =>
|
|
35766
|
+
log.end(() => resolve12({ exitCode: timedOut || !started ? null : code, timedOut, started, durationMs }));
|
|
34746
35767
|
};
|
|
34747
35768
|
child.on("error", (e) => {
|
|
34748
35769
|
started = false;
|
|
@@ -34864,13 +35885,13 @@ ${PROVE_USAGE}`);
|
|
|
34864
35885
|
if (request.when === "before" && changedOutsideTests > 0)
|
|
34865
35886
|
say(lateBeforeLine(changedOutsideTests));
|
|
34866
35887
|
const runId = randomUUID3();
|
|
34867
|
-
const
|
|
35888
|
+
const logPath2 = join23(dir, `${runId}.log`);
|
|
34868
35889
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
34869
35890
|
const deadline = deps.deadlineMs ?? PROVE_RUN_DEADLINE_MS;
|
|
34870
|
-
const end = await runCommand(command, repoRoot,
|
|
35891
|
+
const end = await runCommand(command, repoRoot, logPath2, env, deps);
|
|
34871
35892
|
let output = "";
|
|
34872
35893
|
try {
|
|
34873
|
-
output = readFileSync32(
|
|
35894
|
+
output = readFileSync32(logPath2, "utf-8");
|
|
34874
35895
|
} catch {
|
|
34875
35896
|
output = "";
|
|
34876
35897
|
}
|
|
@@ -34914,7 +35935,7 @@ ${PROVE_USAGE}`);
|
|
|
34914
35935
|
sendLine = mine.outcome === "recorded" ? RECORDED_LINE : mine.outcome === "kept" ? NOT_SENT_YET_LINE : refusedLine(mine.refusal);
|
|
34915
35936
|
}
|
|
34916
35937
|
say(`${line2} ${sendLine}`);
|
|
34917
|
-
say(`Its output is kept on this computer at ${
|
|
35938
|
+
say(`Its output is kept on this computer at ${logPath2}`);
|
|
34918
35939
|
return 0;
|
|
34919
35940
|
}
|
|
34920
35941
|
|
|
@@ -34982,14 +36003,14 @@ function personCommandEnv(env) {
|
|
|
34982
36003
|
}
|
|
34983
36004
|
return out;
|
|
34984
36005
|
}
|
|
34985
|
-
var runOwnCommandReal = (command, input, env) => new Promise((
|
|
36006
|
+
var runOwnCommandReal = (command, input, env) => new Promise((resolve12) => {
|
|
34986
36007
|
let out = "";
|
|
34987
36008
|
let settled2 = false;
|
|
34988
36009
|
const done = (v) => {
|
|
34989
36010
|
if (settled2)
|
|
34990
36011
|
return;
|
|
34991
36012
|
settled2 = true;
|
|
34992
|
-
|
|
36013
|
+
resolve12(v);
|
|
34993
36014
|
};
|
|
34994
36015
|
try {
|
|
34995
36016
|
const child = spawn3(command, {
|
|
@@ -35137,7 +36158,7 @@ async function main() {
|
|
|
35137
36158
|
if (cmd === "time") {
|
|
35138
36159
|
let line2;
|
|
35139
36160
|
try {
|
|
35140
|
-
line2 = JSON.stringify(await runTimeVerb());
|
|
36161
|
+
line2 = JSON.stringify(await runTimeVerb({}, { final: args.slice(1).includes("--final") }));
|
|
35141
36162
|
} catch {
|
|
35142
36163
|
line2 = JSON.stringify({ outcome: "not-sent", reason: "unreachable" });
|
|
35143
36164
|
}
|
|
@@ -35303,7 +36324,7 @@ function unknownCommand(name = args.join(" ")) {
|
|
|
35303
36324
|
halfcycle-runner mcp-headers [--url <address>]
|
|
35304
36325
|
halfcycle-runner observe
|
|
35305
36326
|
halfcycle-runner observe --change <sortingId>
|
|
35306
|
-
halfcycle-runner time
|
|
36327
|
+
halfcycle-runner time [--final]
|
|
35307
36328
|
halfcycle-runner prove <phase> <task> --label <label> --before|--after [-- <command>]
|
|
35308
36329
|
halfcycle-runner pace [--start <phase> [--agents <n>]]
|
|
35309
36330
|
halfcycle-runner pace --scan [--config-folder <dir>]
|
|
@@ -35314,10 +36335,10 @@ function unknownCommand(name = args.join(" ")) {
|
|
|
35314
36335
|
process.exit(1);
|
|
35315
36336
|
}
|
|
35316
36337
|
function readStdin3() {
|
|
35317
|
-
return new Promise((
|
|
36338
|
+
return new Promise((resolve12, reject) => {
|
|
35318
36339
|
const chunks = [];
|
|
35319
36340
|
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
35320
|
-
process.stdin.on("end", () =>
|
|
36341
|
+
process.stdin.on("end", () => resolve12(Buffer.concat(chunks).toString("utf-8")));
|
|
35321
36342
|
process.stdin.on("error", reject);
|
|
35322
36343
|
});
|
|
35323
36344
|
}
|