halfcycle 0.7.1 → 0.8.1
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 +1628 -637
- 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 +769 -378
- 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/doctor.d.ts +9 -0
- package/dist/doctor.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)
|
|
@@ -19248,6 +19507,17 @@ var phaseModelsFileSchema = external_exports.object({
|
|
|
19248
19507
|
tasks: external_exports.record(external_exports.string().min(1).max(200), external_exports.record(external_exports.string().min(1).max(PHASE_MODEL_NAME_MAX), external_exports.number().int().min(0)))
|
|
19249
19508
|
}).strict();
|
|
19250
19509
|
|
|
19510
|
+
// ../events/dist/checks-report-words.js
|
|
19511
|
+
var CHECKS_NO_REPORT_YET_STATE = "Set up, no report yet";
|
|
19512
|
+
var CHECKS_GONE_QUIET = "Halfcycle's checks have not reported from this machine lately.";
|
|
19513
|
+
function checksReportOfInstructions(text) {
|
|
19514
|
+
if (text.startsWith(CHECKS_NO_REPORT_YET_STATE))
|
|
19515
|
+
return "no-report-yet";
|
|
19516
|
+
if (text.startsWith(CHECKS_GONE_QUIET))
|
|
19517
|
+
return "gone-quiet";
|
|
19518
|
+
return "none";
|
|
19519
|
+
}
|
|
19520
|
+
|
|
19251
19521
|
// dist/hook-protocol.js
|
|
19252
19522
|
import { writeSync } from "node:fs";
|
|
19253
19523
|
|
|
@@ -19784,7 +20054,7 @@ async function attempt(url2, token, request, fetchFn, retry) {
|
|
|
19784
20054
|
|
|
19785
20055
|
// dist/git.js
|
|
19786
20056
|
import { spawnSync } from "node:child_process";
|
|
19787
|
-
import { existsSync, readFileSync } from "node:fs";
|
|
20057
|
+
import { existsSync as existsSync2, readFileSync } from "node:fs";
|
|
19788
20058
|
import { relative } from "node:path";
|
|
19789
20059
|
var COLOR_AWARE_SUBCOMMANDS = /* @__PURE__ */ new Set(["diff", "show", "log"]);
|
|
19790
20060
|
function spawnGit(args2, cwd, timeoutMs, extra) {
|
|
@@ -19801,7 +20071,7 @@ function spawnGit(args2, cwd, timeoutMs, extra) {
|
|
|
19801
20071
|
function git(args2, cwd, timeoutMs, extra) {
|
|
19802
20072
|
const result = spawnGit(args2, cwd, timeoutMs, extra);
|
|
19803
20073
|
if (result.error) {
|
|
19804
|
-
const missing = result.error.code === "ENOENT" &&
|
|
20074
|
+
const missing = result.error.code === "ENOENT" && existsSync2(cwd);
|
|
19805
20075
|
return { ok: false, message: `git error: ${result.error.message}`, ...missing ? { gitMissing: true } : {} };
|
|
19806
20076
|
}
|
|
19807
20077
|
if (result.status !== 0) {
|
|
@@ -20315,14 +20585,14 @@ function stripComments(code) {
|
|
|
20315
20585
|
function extractSqlWrites(diffContent) {
|
|
20316
20586
|
const writes = [];
|
|
20317
20587
|
const seen = /* @__PURE__ */ new Set();
|
|
20318
|
-
const push = (
|
|
20319
|
-
if (!
|
|
20588
|
+
const push = (write2) => {
|
|
20589
|
+
if (!write2)
|
|
20320
20590
|
return;
|
|
20321
|
-
const key = `${
|
|
20591
|
+
const key = `${write2.kind}:${write2.table}`;
|
|
20322
20592
|
if (seen.has(key))
|
|
20323
20593
|
return;
|
|
20324
20594
|
seen.add(key);
|
|
20325
|
-
writes.push(
|
|
20595
|
+
writes.push(write2);
|
|
20326
20596
|
};
|
|
20327
20597
|
for (const line2 of diffContent.split("\n")) {
|
|
20328
20598
|
if (isRemovedLine(line2) || isContextLine(line2) || isDiffHeader(line2))
|
|
@@ -20633,7 +20903,7 @@ function detectBlastRadiusMarkers(filePath, diffContent) {
|
|
|
20633
20903
|
|
|
20634
20904
|
// dist/extract/numeric-columns.js
|
|
20635
20905
|
import { readFileSync as readFileSync2, readdirSync } from "node:fs";
|
|
20636
|
-
import { join } from "node:path";
|
|
20906
|
+
import { join as join2 } from "node:path";
|
|
20637
20907
|
function extractNumericColumns(diffContent, context = {}) {
|
|
20638
20908
|
const addedLines = [];
|
|
20639
20909
|
for (const line2 of diffContent.split("\n")) {
|
|
@@ -20700,12 +20970,12 @@ function walkForRegistrations(dir, repoRoot, acc) {
|
|
|
20700
20970
|
if (entry.isDirectory()) {
|
|
20701
20971
|
if (EXCLUDED_DIRS.has(entry.name))
|
|
20702
20972
|
continue;
|
|
20703
|
-
walkForRegistrations(
|
|
20973
|
+
walkForRegistrations(join2(dir, entry.name), repoRoot, acc);
|
|
20704
20974
|
continue;
|
|
20705
20975
|
}
|
|
20706
20976
|
if (!entry.isFile())
|
|
20707
20977
|
continue;
|
|
20708
|
-
const absPath =
|
|
20978
|
+
const absPath = join2(dir, entry.name);
|
|
20709
20979
|
if (!isCodeFile(absPath))
|
|
20710
20980
|
continue;
|
|
20711
20981
|
let content;
|
|
@@ -20847,13 +21117,13 @@ function resolveWireFields(lines2, decls) {
|
|
|
20847
21117
|
}
|
|
20848
21118
|
|
|
20849
21119
|
// dist/fixtures-manifest.js
|
|
20850
|
-
import { existsSync as
|
|
20851
|
-
import { dirname, join as
|
|
21120
|
+
import { existsSync as existsSync3, mkdirSync, readFileSync as readFileSync3, renameSync, unlinkSync, writeFileSync } from "node:fs";
|
|
21121
|
+
import { dirname, join as join3 } from "node:path";
|
|
20852
21122
|
function manifestPath(repoRoot) {
|
|
20853
|
-
return
|
|
21123
|
+
return join3(repoRoot, "test", "fixtures", "captured", "manifest.json");
|
|
20854
21124
|
}
|
|
20855
21125
|
function fixturePath(repoRoot, provider, slug) {
|
|
20856
|
-
return
|
|
21126
|
+
return join3(repoRoot, "test", "fixtures", "captured", provider, `${slug}.json`);
|
|
20857
21127
|
}
|
|
20858
21128
|
function loadManifest(repoRoot) {
|
|
20859
21129
|
if (!repoRoot)
|
|
@@ -20886,7 +21156,7 @@ function upsertManifest(repoRoot, entry) {
|
|
|
20886
21156
|
}
|
|
20887
21157
|
function removeFixtureIfExists(path) {
|
|
20888
21158
|
try {
|
|
20889
|
-
if (
|
|
21159
|
+
if (existsSync3(path))
|
|
20890
21160
|
unlinkSync(path);
|
|
20891
21161
|
} catch {
|
|
20892
21162
|
}
|
|
@@ -21134,7 +21404,7 @@ function toAstShapes(markers) {
|
|
|
21134
21404
|
|
|
21135
21405
|
// dist/extract/context.js
|
|
21136
21406
|
import { readFileSync as readFileSync4, readdirSync as readdirSync2 } from "node:fs";
|
|
21137
|
-
import { join as
|
|
21407
|
+
import { join as join4, relative as relative2, sep } from "node:path";
|
|
21138
21408
|
var EXCLUDED_DIRS2 = /* @__PURE__ */ new Set([
|
|
21139
21409
|
"node_modules",
|
|
21140
21410
|
".git",
|
|
@@ -21168,7 +21438,7 @@ function walk(dir, repoRoot, acc) {
|
|
|
21168
21438
|
if (entry.isDirectory()) {
|
|
21169
21439
|
if (EXCLUDED_DIRS2.has(entry.name))
|
|
21170
21440
|
continue;
|
|
21171
|
-
walk(
|
|
21441
|
+
walk(join4(dir, entry.name), repoRoot, acc);
|
|
21172
21442
|
continue;
|
|
21173
21443
|
}
|
|
21174
21444
|
if (!entry.isFile())
|
|
@@ -21176,7 +21446,7 @@ function walk(dir, repoRoot, acc) {
|
|
|
21176
21446
|
const kind = classifyFile(entry.name);
|
|
21177
21447
|
if (!kind)
|
|
21178
21448
|
continue;
|
|
21179
|
-
const absPath =
|
|
21449
|
+
const absPath = join4(dir, entry.name);
|
|
21180
21450
|
let content;
|
|
21181
21451
|
try {
|
|
21182
21452
|
content = readFileSync4(absPath, "utf-8");
|
|
@@ -21199,9 +21469,9 @@ function loadChangeSetContext(repoRoot) {
|
|
|
21199
21469
|
}
|
|
21200
21470
|
|
|
21201
21471
|
// dist/telemetry/emit.js
|
|
21202
|
-
import { appendFileSync, mkdirSync as mkdirSync2 } from "node:fs";
|
|
21203
|
-
import { join as
|
|
21204
|
-
import { homedir } from "node:os";
|
|
21472
|
+
import { appendFileSync as appendFileSync2, mkdirSync as mkdirSync2 } from "node:fs";
|
|
21473
|
+
import { join as join5, dirname as dirname2 } from "node:path";
|
|
21474
|
+
import { homedir as homedir2 } from "node:os";
|
|
21205
21475
|
import { randomUUID } from "node:crypto";
|
|
21206
21476
|
var TELEMETRY_TIMEOUT_MS = 5e3;
|
|
21207
21477
|
async function emitTelemetry(run, config2, logger, fetchFn = globalThis.fetch) {
|
|
@@ -21211,23 +21481,23 @@ async function emitTelemetry(run, config2, logger, fetchFn = globalThis.fetch) {
|
|
|
21211
21481
|
}
|
|
21212
21482
|
}
|
|
21213
21483
|
function localLogPath(run, config2) {
|
|
21214
|
-
const logDir = config2.guardEvalLogDir ??
|
|
21484
|
+
const logDir = config2.guardEvalLogDir ?? join5(homedir2(), ".halfcycle", "guard-eval-log");
|
|
21215
21485
|
const phase = run.phase;
|
|
21216
21486
|
const fileName = phase === void 0 || phase === "" ? "unphased.jsonl" : `${renderPhaseSegment(phase)}.jsonl`;
|
|
21217
|
-
return
|
|
21487
|
+
return join5(logDir, fileName);
|
|
21218
21488
|
}
|
|
21219
21489
|
function appendToLocalLog(run, config2, logger) {
|
|
21220
|
-
let
|
|
21490
|
+
let logPath2;
|
|
21221
21491
|
try {
|
|
21222
|
-
|
|
21492
|
+
logPath2 = localLogPath(run, config2);
|
|
21223
21493
|
} catch (err) {
|
|
21224
21494
|
const msg = err instanceof Error ? err.message : String(err);
|
|
21225
21495
|
logger.warn(`[Halfcycle telemetry] Phase name refused, nothing written (dropped): ${msg}`);
|
|
21226
21496
|
return;
|
|
21227
21497
|
}
|
|
21228
21498
|
try {
|
|
21229
|
-
mkdirSync2(dirname2(
|
|
21230
|
-
|
|
21499
|
+
mkdirSync2(dirname2(logPath2), { recursive: true });
|
|
21500
|
+
appendFileSync2(logPath2, JSON.stringify(run) + "\n", "utf-8");
|
|
21231
21501
|
} catch (err) {
|
|
21232
21502
|
const msg = err instanceof Error ? err.message : String(err);
|
|
21233
21503
|
logger.warn(`[Halfcycle telemetry] Local guard-eval log write failed (dropped): ${msg}`);
|
|
@@ -21536,21 +21806,21 @@ function projectFolder(env = process.env) {
|
|
|
21536
21806
|
}
|
|
21537
21807
|
|
|
21538
21808
|
// dist/credential-store.js
|
|
21539
|
-
import { chmodSync, existsSync as
|
|
21540
|
-
import { homedir as
|
|
21541
|
-
import { dirname as dirname3, join as
|
|
21809
|
+
import { chmodSync, existsSync as existsSync4, readFileSync as readFileSync6, renameSync as renameSync2, unlinkSync as unlinkSync2, writeFileSync as writeFileSync2, realpathSync } from "node:fs";
|
|
21810
|
+
import { homedir as homedir3, platform } from "node:os";
|
|
21811
|
+
import { dirname as dirname3, join as join6 } from "node:path";
|
|
21542
21812
|
var REFRESHED_TOKEN_KEYS = ["HALFCYCLE_TOKEN", "GUARD_SERVICE_TOKEN"];
|
|
21543
21813
|
var TOKEN_READ_KEY = "GUARD_SERVICE_TOKEN";
|
|
21544
21814
|
function composeEngagementEnvPath(engagementId, home) {
|
|
21545
|
-
return
|
|
21815
|
+
return join6(home ?? homedir3(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, ENGAGEMENT_ENV_FILENAME);
|
|
21546
21816
|
}
|
|
21547
21817
|
function hasNotThisAccountMarker(engagementId, home) {
|
|
21548
|
-
return
|
|
21818
|
+
return existsSync4(join6(home ?? homedir3(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, NOT_THIS_ACCOUNT_MARKER_FILENAME));
|
|
21549
21819
|
}
|
|
21550
21820
|
function readAccountCredential(controlOrigin, home) {
|
|
21551
21821
|
let raw;
|
|
21552
21822
|
try {
|
|
21553
|
-
raw = readFileSync6(
|
|
21823
|
+
raw = readFileSync6(join6(home ?? homedir3(), HALFCYCLE_DIR_NAME, ACCOUNT_STORE_FILENAME), "utf-8");
|
|
21554
21824
|
} catch {
|
|
21555
21825
|
return void 0;
|
|
21556
21826
|
}
|
|
@@ -21602,7 +21872,7 @@ function writeRefreshedToken(opts) {
|
|
|
21602
21872
|
existing = null;
|
|
21603
21873
|
}
|
|
21604
21874
|
const body = reconcileEnvText(existing, { HALFCYCLE_TOKEN: opts.token, GUARD_SERVICE_TOKEN: opts.token }, REFRESHED_TOKEN_KEYS);
|
|
21605
|
-
const temp =
|
|
21875
|
+
const temp = join6(dirname3(declaredReal), `.${ENGAGEMENT_ENV_FILENAME}.${process.pid}.tmp`);
|
|
21606
21876
|
try {
|
|
21607
21877
|
writeFileSync2(temp, body, { mode: 384 });
|
|
21608
21878
|
if (platform() !== "win32")
|
|
@@ -21703,15 +21973,15 @@ async function refreshEngagementCredential(opts) {
|
|
|
21703
21973
|
const minted = await mintThroughJoin(controlOrigin, opts.engagementId, accountCredential, opts.fetchFn ?? globalThis.fetch);
|
|
21704
21974
|
if (!minted.ok)
|
|
21705
21975
|
return minted;
|
|
21706
|
-
const
|
|
21976
|
+
const write2 = writeRefreshedToken({
|
|
21707
21977
|
envFilePath,
|
|
21708
21978
|
engagementId: opts.engagementId,
|
|
21709
21979
|
token: minted.token,
|
|
21710
21980
|
home: opts.home
|
|
21711
21981
|
});
|
|
21712
|
-
if (!
|
|
21982
|
+
if (!write2.written) {
|
|
21713
21983
|
const warn = opts.warn ?? ((message) => process.stderr.write(message));
|
|
21714
|
-
warn(`[Halfcycle] This engagement's credential was renewed for this run only \u2014 ${
|
|
21984
|
+
warn(`[Halfcycle] This engagement's credential was renewed for this run only \u2014 ${write2.reason}.
|
|
21715
21985
|
`);
|
|
21716
21986
|
}
|
|
21717
21987
|
return minted;
|
|
@@ -21740,9 +22010,9 @@ async function evaluateWithRefresh(opts) {
|
|
|
21740
22010
|
|
|
21741
22011
|
// dist/hooks/marker.js
|
|
21742
22012
|
import { createHash } from "node:crypto";
|
|
21743
|
-
import { existsSync as
|
|
22013
|
+
import { existsSync as existsSync5, readFileSync as readFileSync7, writeFileSync as writeFileSync3, unlinkSync as unlinkSync3, readdirSync as readdirSync3, rmdirSync, statSync } from "node:fs";
|
|
21744
22014
|
import { tmpdir } from "node:os";
|
|
21745
|
-
import { join as
|
|
22015
|
+
import { join as join7 } from "node:path";
|
|
21746
22016
|
var MARKER_TTL_MS = 24 * 60 * 60 * 1e3;
|
|
21747
22017
|
var MARKER_PREFIX = "halfcycle-session-";
|
|
21748
22018
|
var MARKER_SUFFIX = ".ref";
|
|
@@ -21756,18 +22026,21 @@ var FINDINGS_ID = new RegExp(FINDINGS_ID_SOURCE);
|
|
|
21756
22026
|
function findingsPath(sessionId) {
|
|
21757
22027
|
if (typeof sessionId !== "string" || !FINDINGS_ID.test(sessionId))
|
|
21758
22028
|
return null;
|
|
21759
|
-
return
|
|
22029
|
+
return join7(markerDir(), `${FINDINGS_PREFIX}${sessionId}${FINDINGS_SUFFIX}`);
|
|
21760
22030
|
}
|
|
21761
22031
|
var HELD_STEP_PREFIX = "halfcycle-held-";
|
|
21762
22032
|
var ALLOW_PREFIX = "halfcycle-allow-";
|
|
22033
|
+
var STEP_NUMBERS_PREFIX = "halfcycle-step-numbers-";
|
|
21763
22034
|
var ALLOW_ONCE_SUFFIX = ".json";
|
|
22035
|
+
var STEP_NUMBERS_LOCK_SUFFIX = ".lock";
|
|
21764
22036
|
function allowOncePaths(sessionId, dir) {
|
|
21765
22037
|
if (typeof sessionId !== "string" || !FINDINGS_ID.test(sessionId))
|
|
21766
22038
|
return null;
|
|
21767
22039
|
const base = dir ?? markerDir();
|
|
21768
22040
|
return {
|
|
21769
|
-
held:
|
|
21770
|
-
allow:
|
|
22041
|
+
held: join7(base, `${HELD_STEP_PREFIX}${sessionId}${ALLOW_ONCE_SUFFIX}`),
|
|
22042
|
+
allow: join7(base, `${ALLOW_PREFIX}${sessionId}${ALLOW_ONCE_SUFFIX}`),
|
|
22043
|
+
numbers: join7(base, `${STEP_NUMBERS_PREFIX}${sessionId}${ALLOW_ONCE_SUFFIX}`)
|
|
21771
22044
|
};
|
|
21772
22045
|
}
|
|
21773
22046
|
function markerDir() {
|
|
@@ -21783,16 +22056,16 @@ function markerFileName(repoRoot, sessionId) {
|
|
|
21783
22056
|
return `${MARKER_PREFIX}${key}${MARKER_SUFFIX}`;
|
|
21784
22057
|
}
|
|
21785
22058
|
function markerPath(repoRoot, sessionId) {
|
|
21786
|
-
return
|
|
22059
|
+
return join7(markerDir(), markerFileName(repoRoot, sessionId));
|
|
21787
22060
|
}
|
|
21788
22061
|
function dedupePath(repoRoot, sessionId) {
|
|
21789
22062
|
const hash2 = repoHash(repoRoot);
|
|
21790
22063
|
const key = sessionId && sessionId.length > 0 ? `${hash2}-${sessionId}` : hash2;
|
|
21791
|
-
return
|
|
22064
|
+
return join7(markerDir(), `${MARKER_PREFIX}${key}${DEDUPE_SUFFIX}`);
|
|
21792
22065
|
}
|
|
21793
22066
|
function readMarker(repoRoot, sessionId) {
|
|
21794
22067
|
const path = markerPath(repoRoot, sessionId);
|
|
21795
|
-
if (!
|
|
22068
|
+
if (!existsSync5(path))
|
|
21796
22069
|
return null;
|
|
21797
22070
|
try {
|
|
21798
22071
|
return readFileSync7(path, "utf-8").trim() || null;
|
|
@@ -21803,7 +22076,7 @@ function readMarker(repoRoot, sessionId) {
|
|
|
21803
22076
|
function deleteMarker(repoRoot, sessionId) {
|
|
21804
22077
|
for (const path of [markerPath(repoRoot, sessionId), dedupePath(repoRoot, sessionId)]) {
|
|
21805
22078
|
try {
|
|
21806
|
-
if (
|
|
22079
|
+
if (existsSync5(path))
|
|
21807
22080
|
unlinkSync3(path);
|
|
21808
22081
|
} catch {
|
|
21809
22082
|
}
|
|
@@ -21820,11 +22093,11 @@ var SESSION_NOTICE_SUFFIX = {
|
|
|
21820
22093
|
"pre-tool-use-unreadable": ".pretool-unreadable",
|
|
21821
22094
|
"outside-own-copy-unknown": ".owncopy-unknown"
|
|
21822
22095
|
};
|
|
21823
|
-
function firstNoticeThisSession(notice,
|
|
22096
|
+
function firstNoticeThisSession(notice, folder2, sessionId, dir = markerDir()) {
|
|
21824
22097
|
if (!sessionId)
|
|
21825
22098
|
return true;
|
|
21826
22099
|
const suffix = SESSION_NOTICE_SUFFIX[notice];
|
|
21827
|
-
const path =
|
|
22100
|
+
const path = join7(dir, `${MARKER_PREFIX}${repoHash(folder2)}-${sessionId}${suffix}`);
|
|
21828
22101
|
try {
|
|
21829
22102
|
writeFileSync3(path, "", { encoding: "utf-8", flag: "wx" });
|
|
21830
22103
|
return true;
|
|
@@ -21832,18 +22105,18 @@ function firstNoticeThisSession(notice, folder, sessionId, dir = markerDir()) {
|
|
|
21832
22105
|
return err.code !== "EEXIST";
|
|
21833
22106
|
}
|
|
21834
22107
|
}
|
|
21835
|
-
function warnOnceThisSession(notice,
|
|
22108
|
+
function warnOnceThisSession(notice, folder2, sessionId) {
|
|
21836
22109
|
return (message) => {
|
|
21837
|
-
if (firstNoticeThisSession(notice,
|
|
22110
|
+
if (firstNoticeThisSession(notice, folder2, sessionId))
|
|
21838
22111
|
process.stderr.write(message);
|
|
21839
22112
|
};
|
|
21840
22113
|
}
|
|
21841
|
-
function firstNoRepoNoticeThisSession(
|
|
21842
|
-
return firstNoticeThisSession("no-repository",
|
|
22114
|
+
function firstNoRepoNoticeThisSession(folder2, sessionId) {
|
|
22115
|
+
return firstNoticeThisSession("no-repository", folder2, sessionId);
|
|
21843
22116
|
}
|
|
21844
22117
|
function readDedupe(repoRoot, sessionId) {
|
|
21845
22118
|
const path = dedupePath(repoRoot, sessionId);
|
|
21846
|
-
if (!
|
|
22119
|
+
if (!existsSync5(path))
|
|
21847
22120
|
return null;
|
|
21848
22121
|
try {
|
|
21849
22122
|
const parsed = JSON.parse(readFileSync7(path, "utf-8"));
|
|
@@ -21891,7 +22164,7 @@ function orphanSweep(repoRoot, refKnown, keepSessionId, now = Date.now(), livene
|
|
|
21891
22164
|
continue;
|
|
21892
22165
|
if (name === keepName)
|
|
21893
22166
|
continue;
|
|
21894
|
-
const full =
|
|
22167
|
+
const full = join7(dir, name);
|
|
21895
22168
|
let unusable = false;
|
|
21896
22169
|
try {
|
|
21897
22170
|
const ref = readFileSync7(full, "utf-8").trim();
|
|
@@ -21928,7 +22201,9 @@ function sweepSessionFiles(keepSessionId, now) {
|
|
|
21928
22201
|
[FINDINGS_PREFIX, FINDINGS_SUFFIX],
|
|
21929
22202
|
[OWN_WORK_PREFIX, OWN_WORK_SUFFIX],
|
|
21930
22203
|
[HELD_STEP_PREFIX, ALLOW_ONCE_SUFFIX],
|
|
21931
|
-
[ALLOW_PREFIX, ALLOW_ONCE_SUFFIX]
|
|
22204
|
+
[ALLOW_PREFIX, ALLOW_ONCE_SUFFIX],
|
|
22205
|
+
[STEP_NUMBERS_PREFIX, ALLOW_ONCE_SUFFIX],
|
|
22206
|
+
[STEP_NUMBERS_PREFIX, `${ALLOW_ONCE_SUFFIX}${STEP_NUMBERS_LOCK_SUFFIX}`]
|
|
21932
22207
|
];
|
|
21933
22208
|
for (const name of names) {
|
|
21934
22209
|
for (const [prefix, suffix] of kinds) {
|
|
@@ -21936,7 +22211,7 @@ function sweepSessionFiles(keepSessionId, now) {
|
|
|
21936
22211
|
continue;
|
|
21937
22212
|
if (keepSessionId !== void 0 && name === `${prefix}${keepSessionId}${suffix}`)
|
|
21938
22213
|
continue;
|
|
21939
|
-
const full =
|
|
22214
|
+
const full = join7(dir, name);
|
|
21940
22215
|
try {
|
|
21941
22216
|
if (now - statSync(full).mtimeMs > MARKER_TTL_MS)
|
|
21942
22217
|
unlinkSync3(full);
|
|
@@ -21945,13 +22220,13 @@ function sweepSessionFiles(keepSessionId, now) {
|
|
|
21945
22220
|
}
|
|
21946
22221
|
}
|
|
21947
22222
|
}
|
|
21948
|
-
function observeThrottlePath(
|
|
21949
|
-
return
|
|
22223
|
+
function observeThrottlePath(folder2) {
|
|
22224
|
+
return join7(markerDir(), `${MARKER_PREFIX}${repoHash(folder2)}.observe-throttle`);
|
|
21950
22225
|
}
|
|
21951
|
-
function observeNoticesPath(
|
|
22226
|
+
function observeNoticesPath(folder2, sessionId) {
|
|
21952
22227
|
if (!sessionId)
|
|
21953
22228
|
return null;
|
|
21954
|
-
return
|
|
22229
|
+
return join7(markerDir(), `${MARKER_PREFIX}${repoHash(folder2)}-${sessionId}.observe-said`);
|
|
21955
22230
|
}
|
|
21956
22231
|
var LIVENESS_SUFFIX = ".live";
|
|
21957
22232
|
var LIVENESS_NO_REPOSITORY_KEY = "norepository";
|
|
@@ -22005,7 +22280,7 @@ function sweepLiveness(common, now) {
|
|
|
22005
22280
|
const parsed = parseLivenessFileName(name);
|
|
22006
22281
|
if (parsed === null || !keys.has(parsed.key))
|
|
22007
22282
|
continue;
|
|
22008
|
-
const full =
|
|
22283
|
+
const full = join7(dir, name);
|
|
22009
22284
|
try {
|
|
22010
22285
|
if (now - statSync(full).mtimeMs > MARKER_TTL_MS) {
|
|
22011
22286
|
unlinkSync3(full);
|
|
@@ -22016,22 +22291,22 @@ function sweepLiveness(common, now) {
|
|
|
22016
22291
|
}
|
|
22017
22292
|
}
|
|
22018
22293
|
function removeLivenessIndexEntry(dir, sessionId, name) {
|
|
22019
|
-
const
|
|
22294
|
+
const folder2 = join7(dir, livenessIndexDirName(sessionId));
|
|
22020
22295
|
try {
|
|
22021
|
-
unlinkSync3(
|
|
22296
|
+
unlinkSync3(join7(folder2, name));
|
|
22022
22297
|
} catch {
|
|
22023
22298
|
return;
|
|
22024
22299
|
}
|
|
22025
22300
|
try {
|
|
22026
|
-
rmdirSync(
|
|
22301
|
+
rmdirSync(folder2);
|
|
22027
22302
|
} catch {
|
|
22028
22303
|
}
|
|
22029
22304
|
}
|
|
22030
22305
|
|
|
22031
22306
|
// dist/seat-configuration.js
|
|
22032
|
-
import { existsSync as
|
|
22033
|
-
import { homedir as
|
|
22034
|
-
import { join as
|
|
22307
|
+
import { existsSync as existsSync6, readFileSync as readFileSync8, realpathSync as realpathSync2 } from "node:fs";
|
|
22308
|
+
import { homedir as homedir4 } from "node:os";
|
|
22309
|
+
import { join as join8, relative as relative3, resolve as resolve2 } from "node:path";
|
|
22035
22310
|
function gatherSeatConfiguration(repoRoot, read = readSeatConfiguration, profile = AGENT_PROFILES["claude-code"]) {
|
|
22036
22311
|
try {
|
|
22037
22312
|
const facts = read(repoRoot, profile);
|
|
@@ -22046,7 +22321,7 @@ function gatherSeatConfiguration(repoRoot, read = readSeatConfiguration, profile
|
|
|
22046
22321
|
function readSeatConfiguration(repoRoot, profile = AGENT_PROFILES["claude-code"]) {
|
|
22047
22322
|
const given = profile.projectRoot === "git-toplevel" ? resolve2(repoRoot) : resolve2(process.env["CLAUDE_PROJECT_DIR"] || process.cwd());
|
|
22048
22323
|
const projectDir = realpathSync2.native(given);
|
|
22049
|
-
const home =
|
|
22324
|
+
const home = homedir4();
|
|
22050
22325
|
let realHome = home;
|
|
22051
22326
|
try {
|
|
22052
22327
|
realHome = realpathSync2.native(home);
|
|
@@ -22067,7 +22342,7 @@ function isPlainObject3(value) {
|
|
|
22067
22342
|
function readSettingsFile(projectDir, rel, ours) {
|
|
22068
22343
|
let raw;
|
|
22069
22344
|
try {
|
|
22070
|
-
raw = readFileSync8(
|
|
22345
|
+
raw = readFileSync8(join8(projectDir, rel), "utf-8");
|
|
22071
22346
|
} catch (err) {
|
|
22072
22347
|
const code = err.code;
|
|
22073
22348
|
const state = code === "ENOENT" || code === "ENOTDIR" ? "absent" : "unreadable";
|
|
@@ -22139,7 +22414,7 @@ function readPathStates(projectDir, repoRoot, wiringPaths) {
|
|
|
22139
22414
|
const status = getWiringStatus(wiringPaths, projectDir);
|
|
22140
22415
|
if (!status.ok)
|
|
22141
22416
|
return unknown2();
|
|
22142
|
-
const mapped = mapWiringStatus(status.value, prefix, wiringPaths, (rel) =>
|
|
22417
|
+
const mapped = mapWiringStatus(status.value, prefix, wiringPaths, (rel) => existsSync6(join8(projectDir, rel)));
|
|
22143
22418
|
return mapped ?? unknown2();
|
|
22144
22419
|
}
|
|
22145
22420
|
function mapWiringStatus(output, prefix, paths, onDisk) {
|
|
@@ -22182,28 +22457,28 @@ function mapWiringStatus(output, prefix, paths, onDisk) {
|
|
|
22182
22457
|
|
|
22183
22458
|
// dist/time-record.js
|
|
22184
22459
|
import { createHash as createHash3 } from "node:crypto";
|
|
22185
|
-
import { appendFileSync as
|
|
22186
|
-
import { homedir as
|
|
22187
|
-
import { dirname as dirname4, join as
|
|
22460
|
+
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";
|
|
22461
|
+
import { homedir as homedir8 } from "node:os";
|
|
22462
|
+
import { dirname as dirname4, join as join11 } from "node:path";
|
|
22188
22463
|
|
|
22189
22464
|
// dist/codex-usage.js
|
|
22190
22465
|
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
|
|
22466
|
+
import { homedir as homedir5 } from "node:os";
|
|
22467
|
+
import { basename, isAbsolute, join as join9, relative as relative4, resolve as resolve3, sep as sep2 } from "node:path";
|
|
22193
22468
|
var CODEX_WINDOW_FRESH_MS = 10 * 60 * 1e3;
|
|
22194
22469
|
var CODEX_DAYS_BACK = 7;
|
|
22195
22470
|
var CODEX_FILES_MAX = 20;
|
|
22196
22471
|
var CODEX_TAIL_BYTES = 256 * 1024;
|
|
22197
22472
|
var CODEX_SAME_RESET_SECONDS = 60;
|
|
22198
22473
|
var ROLLOUT_NAME = /^rollout-.+\.jsonl$/;
|
|
22199
|
-
function codexHomeOf(env = process.env, home =
|
|
22474
|
+
function codexHomeOf(env = process.env, home = homedir5()) {
|
|
22200
22475
|
const set2 = env["CODEX_HOME"];
|
|
22201
|
-
const
|
|
22202
|
-
if (
|
|
22476
|
+
const folder2 = typeof set2 === "string" && set2 !== "" ? set2 : join9(home, ".codex");
|
|
22477
|
+
if (folder2 === "~")
|
|
22203
22478
|
return resolve3(home);
|
|
22204
|
-
if (
|
|
22205
|
-
return resolve3(
|
|
22206
|
-
return resolve3(
|
|
22479
|
+
if (folder2.startsWith("~/") || folder2.startsWith("~\\"))
|
|
22480
|
+
return resolve3(join9(home, folder2.slice(2)));
|
|
22481
|
+
return resolve3(folder2);
|
|
22207
22482
|
}
|
|
22208
22483
|
function objectOf(v) {
|
|
22209
22484
|
return typeof v === "object" && v !== null && !Array.isArray(v) ? v : null;
|
|
@@ -22287,20 +22562,20 @@ function dayFolders(sessions, now) {
|
|
|
22287
22562
|
const out = [];
|
|
22288
22563
|
for (let back = 0; back < CODEX_DAYS_BACK; back++) {
|
|
22289
22564
|
const d = new Date(now.getFullYear(), now.getMonth(), now.getDate() - back);
|
|
22290
|
-
out.push(
|
|
22565
|
+
out.push(join9(sessions, String(d.getFullYear()), twoDigits(d.getMonth() + 1), twoDigits(d.getDate())));
|
|
22291
22566
|
}
|
|
22292
22567
|
return out;
|
|
22293
22568
|
}
|
|
22294
22569
|
function recentRollouts(sessions, now) {
|
|
22295
22570
|
const found2 = [];
|
|
22296
|
-
for (const
|
|
22571
|
+
for (const folder2 of dayFolders(sessions, now)) {
|
|
22297
22572
|
try {
|
|
22298
|
-
if (!lstatSync(
|
|
22573
|
+
if (!lstatSync(folder2).isDirectory())
|
|
22299
22574
|
continue;
|
|
22300
|
-
for (const name of readdirSync4(
|
|
22575
|
+
for (const name of readdirSync4(folder2)) {
|
|
22301
22576
|
if (!ROLLOUT_NAME.test(name))
|
|
22302
22577
|
continue;
|
|
22303
|
-
const path =
|
|
22578
|
+
const path = join9(folder2, name);
|
|
22304
22579
|
try {
|
|
22305
22580
|
const st = lstatSync(path);
|
|
22306
22581
|
if (!st.isFile())
|
|
@@ -22319,7 +22594,7 @@ function recentRollouts(sessions, now) {
|
|
|
22319
22594
|
function readCodexWindows(codexHome, now) {
|
|
22320
22595
|
try {
|
|
22321
22596
|
const candidates = [];
|
|
22322
|
-
for (const path of recentRollouts(
|
|
22597
|
+
for (const path of recentRollouts(join9(codexHome, "sessions"), now)) {
|
|
22323
22598
|
try {
|
|
22324
22599
|
candidates.push(...newestWindowsIn(path, now));
|
|
22325
22600
|
} catch {
|
|
@@ -22349,7 +22624,7 @@ function isCodexSessionFile(path, codexHome) {
|
|
|
22349
22624
|
return false;
|
|
22350
22625
|
if (!lstatSync(path).isFile())
|
|
22351
22626
|
return false;
|
|
22352
|
-
const rel = relative4(realpathSync3(
|
|
22627
|
+
const rel = relative4(realpathSync3(join9(codexHome, "sessions")), realpathSync3(path));
|
|
22353
22628
|
return rel !== "" && rel !== ".." && !rel.startsWith(`..${sep2}`) && !isAbsolute(rel);
|
|
22354
22629
|
} catch {
|
|
22355
22630
|
return false;
|
|
@@ -22444,18 +22719,18 @@ function firstLine(text) {
|
|
|
22444
22719
|
const line2 = text.split("\n", 1)[0]?.replace(/[ \t\r]+$/, "") ?? "";
|
|
22445
22720
|
return line2 === "" ? null : line2;
|
|
22446
22721
|
}
|
|
22447
|
-
function whichCopy(
|
|
22722
|
+
function whichCopy(folder2, deps = {}) {
|
|
22448
22723
|
try {
|
|
22449
22724
|
const rules = deps.rules ?? machineRules();
|
|
22450
22725
|
const p = pathsFor(rules);
|
|
22451
22726
|
const files = deps.files ?? DISK_FILES;
|
|
22452
22727
|
const realpath = deps.realpath ?? ((x) => realpathSync4.native(x));
|
|
22453
22728
|
const oneForm = rules === "windows" ? (x) => x.toLowerCase() : (x) => x;
|
|
22454
|
-
if (!p.isAbsolute(
|
|
22729
|
+
if (!p.isAbsolute(folder2))
|
|
22455
22730
|
return null;
|
|
22456
|
-
if (files.kind(p.resolve(
|
|
22731
|
+
if (files.kind(p.resolve(folder2)) !== "folder")
|
|
22457
22732
|
return null;
|
|
22458
|
-
let dir = realpath(p.resolve(
|
|
22733
|
+
let dir = realpath(p.resolve(folder2));
|
|
22459
22734
|
for (; ; ) {
|
|
22460
22735
|
const dotGit = p.join(dir, ".git");
|
|
22461
22736
|
const found2 = files.kind(dotGit);
|
|
@@ -22530,7 +22805,7 @@ function copyHolding(file2, deps = {}) {
|
|
|
22530
22805
|
|
|
22531
22806
|
// dist/observed.js
|
|
22532
22807
|
import { readFileSync as readFileSync11, writeFileSync as writeFileSync4 } from "node:fs";
|
|
22533
|
-
import { join as
|
|
22808
|
+
import { join as join10 } from "node:path";
|
|
22534
22809
|
function emptyTally() {
|
|
22535
22810
|
return { added: 0, changed: 0, removed: 0, testFilesAdded: 0 };
|
|
22536
22811
|
}
|
|
@@ -22662,9 +22937,9 @@ async function attemptObservation(opts) {
|
|
|
22662
22937
|
return { outcome: "not-sent", reason: "refused" };
|
|
22663
22938
|
return answer.data.outcome === "kept" ? { outcome: "kept" } : { outcome: "recorded", answer: answer.data };
|
|
22664
22939
|
}
|
|
22665
|
-
function readThrottle(
|
|
22940
|
+
function readThrottle(folder2) {
|
|
22666
22941
|
try {
|
|
22667
|
-
const parsed = JSON.parse(readFileSync11(observeThrottlePath(
|
|
22942
|
+
const parsed = JSON.parse(readFileSync11(observeThrottlePath(folder2), "utf-8"));
|
|
22668
22943
|
if (typeof parsed !== "object" || parsed === null)
|
|
22669
22944
|
return null;
|
|
22670
22945
|
const { attemptedAt, accepted } = parsed;
|
|
@@ -22677,9 +22952,9 @@ function readThrottle(folder) {
|
|
|
22677
22952
|
return null;
|
|
22678
22953
|
}
|
|
22679
22954
|
}
|
|
22680
|
-
function writeThrottle(
|
|
22955
|
+
function writeThrottle(folder2, state) {
|
|
22681
22956
|
try {
|
|
22682
|
-
writeFileSync4(observeThrottlePath(
|
|
22957
|
+
writeFileSync4(observeThrottlePath(folder2), JSON.stringify(state), "utf-8");
|
|
22683
22958
|
} catch {
|
|
22684
22959
|
}
|
|
22685
22960
|
}
|
|
@@ -22700,9 +22975,9 @@ function locate(cwd) {
|
|
|
22700
22975
|
const read = repoRoot === null ? null : headCommit(repoRoot);
|
|
22701
22976
|
return { repoRoot, folder: repoRoot ?? cwd, head: read !== null && read.ok ? read.value : null };
|
|
22702
22977
|
}
|
|
22703
|
-
function recordAttempt(
|
|
22978
|
+
function recordAttempt(folder2, prior, head, at, attempt2) {
|
|
22704
22979
|
const accepted = (attempt2.outcome === "recorded" || attempt2.outcome === "kept") && head !== null ? { head, at } : prior?.accepted ?? null;
|
|
22705
|
-
writeThrottle(
|
|
22980
|
+
writeThrottle(folder2, { attemptedAt: at, accepted });
|
|
22706
22981
|
}
|
|
22707
22982
|
async function runObserve(deps = {}) {
|
|
22708
22983
|
let result;
|
|
@@ -22731,7 +23006,7 @@ async function runObserve(deps = {}) {
|
|
|
22731
23006
|
}
|
|
22732
23007
|
function readLocalSystemDescription(repoRoot) {
|
|
22733
23008
|
try {
|
|
22734
|
-
const raw = JSON.parse(readFileSync11(
|
|
23009
|
+
const raw = JSON.parse(readFileSync11(join10(repoRoot, SYSTEM_DESCRIPTION_REL), "utf-8"));
|
|
22735
23010
|
const checked = checkSystemDescription(raw);
|
|
22736
23011
|
return checked.ok ? checked.description : null;
|
|
22737
23012
|
} catch {
|
|
@@ -22905,23 +23180,23 @@ function writeSaid(path, state) {
|
|
|
22905
23180
|
function reasonsOf(entry) {
|
|
22906
23181
|
return entry.said.filter((task) => task.whyOutsidePlan !== void 0).map((task) => `${task.title}\0${task.whyOutsidePlan}`);
|
|
22907
23182
|
}
|
|
22908
|
-
function noticesFor(attempt2,
|
|
23183
|
+
function noticesFor(attempt2, folder2, sessionId) {
|
|
22909
23184
|
if (attempt2.outcome === "not-sent") {
|
|
22910
23185
|
if (attempt2.reason === "start-not-here") {
|
|
22911
|
-
return firstNoticeThisSession("observe-no-start-here",
|
|
23186
|
+
return firstNoticeThisSession("observe-no-start-here", folder2, sessionId) ? [R1_START_NOT_HERE] : [];
|
|
22912
23187
|
}
|
|
22913
23188
|
if (attempt2.reason === "start-not-on-branch") {
|
|
22914
|
-
return firstNoticeThisSession("observe-not-on-branch",
|
|
23189
|
+
return firstNoticeThisSession("observe-not-on-branch", folder2, sessionId) ? [R2_START_NOT_ON_BRANCH] : [];
|
|
22915
23190
|
}
|
|
22916
23191
|
if (attempt2.reason === "cannot-count" && attempt2.phase !== void 0) {
|
|
22917
|
-
return firstNoticeThisSession("observe-no-start-recorded",
|
|
23192
|
+
return firstNoticeThisSession("observe-no-start-recorded", folder2, sessionId) ? [r3NoStartRecorded(attempt2.phase)] : [];
|
|
22918
23193
|
}
|
|
22919
23194
|
return [];
|
|
22920
23195
|
}
|
|
22921
23196
|
if (attempt2.outcome === "kept")
|
|
22922
23197
|
return [];
|
|
22923
23198
|
const { notInPlan, outside } = attempt2.answer;
|
|
22924
|
-
const path = observeNoticesPath(
|
|
23199
|
+
const path = observeNoticesPath(folder2, sessionId);
|
|
22925
23200
|
const prior = readSaid(path);
|
|
22926
23201
|
const notices = [];
|
|
22927
23202
|
const parts = {};
|
|
@@ -22949,7 +23224,7 @@ function noticesFor(attempt2, folder, sessionId) {
|
|
|
22949
23224
|
// dist/pacing.js
|
|
22950
23225
|
import { createHash as createHash2 } from "node:crypto";
|
|
22951
23226
|
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
|
|
23227
|
+
import { homedir as homedir6 } from "node:os";
|
|
22953
23228
|
import nodePath from "node:path";
|
|
22954
23229
|
var DEFAULT_CONFIG_FOLDER_NAME = ".claude";
|
|
22955
23230
|
var CODEX_DEFAULT_FOLDER_NAME = ".codex";
|
|
@@ -22967,10 +23242,10 @@ function hookInputForRule(input, rule) {
|
|
|
22967
23242
|
delete copy["rollout_path"];
|
|
22968
23243
|
return copy;
|
|
22969
23244
|
}
|
|
22970
|
-
function normaliseFolder(
|
|
23245
|
+
function normaliseFolder(folder2, input = {}) {
|
|
22971
23246
|
const p = input.path ?? nodePath;
|
|
22972
|
-
const home = input.home ??
|
|
22973
|
-
let f =
|
|
23247
|
+
const home = input.home ?? homedir6();
|
|
23248
|
+
let f = folder2;
|
|
22974
23249
|
if (f === "~")
|
|
22975
23250
|
f = home;
|
|
22976
23251
|
else if (f.startsWith("~/") || f.startsWith("~\\"))
|
|
@@ -22984,7 +23259,7 @@ function configFolderKey(input = {}) {
|
|
|
22984
23259
|
const codexHome = env["CODEX_HOME"];
|
|
22985
23260
|
if (typeof codexHome === "string" && codexHome !== "")
|
|
22986
23261
|
return normaliseFolder(codexHome, input);
|
|
22987
|
-
return normaliseFolder(p.join(input.home ??
|
|
23262
|
+
return normaliseFolder(p.join(input.home ?? homedir6(), CODEX_DEFAULT_FOLDER_NAME), input);
|
|
22988
23263
|
}
|
|
22989
23264
|
const fromEnv = env["CLAUDE_CONFIG_DIR"];
|
|
22990
23265
|
if (typeof fromEnv === "string" && fromEnv !== "")
|
|
@@ -22993,7 +23268,7 @@ function configFolderKey(input = {}) {
|
|
|
22993
23268
|
if (typeof transcript === "string" && transcript !== "") {
|
|
22994
23269
|
return normaliseFolder(p.dirname(p.dirname(p.dirname(normaliseFolder(transcript, input)))), input);
|
|
22995
23270
|
}
|
|
22996
|
-
return normaliseFolder(p.join(input.home ??
|
|
23271
|
+
return normaliseFolder(p.join(input.home ?? homedir6(), DEFAULT_CONFIG_FOLDER_NAME), input);
|
|
22997
23272
|
}
|
|
22998
23273
|
function recordsFolderOf(key, path = nodePath) {
|
|
22999
23274
|
return path.join(key, RECORDS_FOLDER_NAME);
|
|
@@ -23013,7 +23288,7 @@ var PACING_DIR_NAME = "pacing";
|
|
|
23013
23288
|
var LEARNED_FILENAME = "learned.json";
|
|
23014
23289
|
var REPORTED_FILENAME = "reported.json";
|
|
23015
23290
|
function pacingDir(home) {
|
|
23016
|
-
return nodePath.join(home ??
|
|
23291
|
+
return nodePath.join(home ?? homedir6(), HALFCYCLE_DIR_NAME, PACING_DIR_NAME);
|
|
23017
23292
|
}
|
|
23018
23293
|
function readJsonObject(path) {
|
|
23019
23294
|
try {
|
|
@@ -23435,7 +23710,7 @@ function resolvedRecords(key, path) {
|
|
|
23435
23710
|
}
|
|
23436
23711
|
}
|
|
23437
23712
|
function timeLogTranscripts(home) {
|
|
23438
|
-
const engagements = nodePath.join(home ??
|
|
23713
|
+
const engagements = nodePath.join(home ?? homedir6(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME);
|
|
23439
23714
|
const out = [];
|
|
23440
23715
|
for (const e of dirents(engagements)) {
|
|
23441
23716
|
if (!e.isDirectory())
|
|
@@ -23454,7 +23729,7 @@ function timeLogTranscripts(home) {
|
|
|
23454
23729
|
}
|
|
23455
23730
|
function teacherOf(key, deps = {}) {
|
|
23456
23731
|
const path = deps.path ?? nodePath;
|
|
23457
|
-
const home = deps.home ??
|
|
23732
|
+
const home = deps.home ?? homedir6();
|
|
23458
23733
|
const ours = resolvedRecords(key, path);
|
|
23459
23734
|
if (ours === null)
|
|
23460
23735
|
return { shared: false, teaches: () => false };
|
|
@@ -23624,13 +23899,13 @@ function knownWindowOf(learned, reported, now) {
|
|
|
23624
23899
|
|
|
23625
23900
|
// dist/phase-limit.js
|
|
23626
23901
|
import { mkdirSync as mkdirSync4, readFileSync as readFileSync13, renameSync as renameSync4, rmSync, writeFileSync as writeFileSync6 } from "node:fs";
|
|
23627
|
-
import { homedir as
|
|
23902
|
+
import { homedir as homedir7 } from "node:os";
|
|
23628
23903
|
import nodePath2 from "node:path";
|
|
23629
23904
|
var PHASE_USAGE_FILENAME = "phase-usage.json";
|
|
23630
23905
|
function phaseLimitDir(engagementId, home) {
|
|
23631
23906
|
if (!isEngagementId(engagementId))
|
|
23632
23907
|
return null;
|
|
23633
|
-
return nodePath2.join(home ??
|
|
23908
|
+
return nodePath2.join(home ?? homedir7(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, PACING_DIR_NAME);
|
|
23634
23909
|
}
|
|
23635
23910
|
function readJsonFile(path) {
|
|
23636
23911
|
try {
|
|
@@ -23678,16 +23953,14 @@ function readPhaseUsage(dir, phase, openedAt = null) {
|
|
|
23678
23953
|
return 0;
|
|
23679
23954
|
return parsed.data.tokens;
|
|
23680
23955
|
}
|
|
23956
|
+
function readPhaseUsageFile(dir) {
|
|
23957
|
+
const parsed = phaseUsageFileSchema.safeParse(readJsonFile(nodePath2.join(dir, PHASE_USAGE_FILENAME)));
|
|
23958
|
+
return parsed.success ? parsed.data : null;
|
|
23959
|
+
}
|
|
23681
23960
|
function writePhaseUsage(dir, file2) {
|
|
23682
23961
|
if (!phaseUsageFileSchema.safeParse(file2).success)
|
|
23683
|
-
return;
|
|
23684
|
-
writeWhole(nodePath2.join(dir, PHASE_USAGE_FILENAME), file2);
|
|
23685
|
-
}
|
|
23686
|
-
function phaseTokensOf(buckets) {
|
|
23687
|
-
let total = 0;
|
|
23688
|
-
for (const b of buckets)
|
|
23689
|
-
total += b.inputTokens + b.outputTokens + b.cacheWriteTokens + b.cacheReadTokens;
|
|
23690
|
-
return Math.max(0, Math.round(total));
|
|
23962
|
+
return false;
|
|
23963
|
+
return writeWhole(nodePath2.join(dir, PHASE_USAGE_FILENAME), file2);
|
|
23691
23964
|
}
|
|
23692
23965
|
function roundTokens(n) {
|
|
23693
23966
|
return Math.max(LIMIT_ROUND_TOKENS, Math.round(n / LIMIT_ROUND_TOKENS) * LIMIT_ROUND_TOKENS);
|
|
@@ -23865,6 +24138,164 @@ function setLimit(file2, limit, multiple, used, by, at) {
|
|
|
23865
24138
|
};
|
|
23866
24139
|
}
|
|
23867
24140
|
|
|
24141
|
+
// dist/scan-lock.js
|
|
24142
|
+
import { spawn } from "node:child_process";
|
|
24143
|
+
import { linkSync, mkdirSync as mkdirSync5, readFileSync as readFileSync14, renameSync as renameSync5, unlinkSync as unlinkSync4, writeFileSync as writeFileSync7 } from "node:fs";
|
|
24144
|
+
import nodePath3 from "node:path";
|
|
24145
|
+
var SCAN_LOCK_FILENAME = "scan.lock";
|
|
24146
|
+
var SCAN_LOCK_STALE_MS = 15 * 60 * 1e3;
|
|
24147
|
+
var SCAN_LOCK_POLL_MS = 100;
|
|
24148
|
+
function scanLockPath(home) {
|
|
24149
|
+
return nodePath3.join(pacingDir(home), SCAN_LOCK_FILENAME);
|
|
24150
|
+
}
|
|
24151
|
+
function readLockBody(path) {
|
|
24152
|
+
let text;
|
|
24153
|
+
try {
|
|
24154
|
+
text = readFileSync14(path, "utf-8");
|
|
24155
|
+
} catch (err) {
|
|
24156
|
+
return err.code === "ENOENT" ? "missing" : null;
|
|
24157
|
+
}
|
|
24158
|
+
try {
|
|
24159
|
+
const v = JSON.parse(text);
|
|
24160
|
+
return typeof v["pid"] === "number" && typeof v["at"] === "number" ? { pid: v["pid"], at: v["at"] } : null;
|
|
24161
|
+
} catch {
|
|
24162
|
+
return null;
|
|
24163
|
+
}
|
|
24164
|
+
}
|
|
24165
|
+
function processAlive(pid) {
|
|
24166
|
+
if (!Number.isInteger(pid) || pid <= 0)
|
|
24167
|
+
return false;
|
|
24168
|
+
try {
|
|
24169
|
+
process.kill(pid, 0);
|
|
24170
|
+
return true;
|
|
24171
|
+
} catch (err) {
|
|
24172
|
+
return err.code === "EPERM";
|
|
24173
|
+
}
|
|
24174
|
+
}
|
|
24175
|
+
function isStale(body, staleMs, deps) {
|
|
24176
|
+
if (body === null)
|
|
24177
|
+
return true;
|
|
24178
|
+
const now = (deps.clock ?? Date.now)();
|
|
24179
|
+
if (Math.abs(now - body.at) > staleMs)
|
|
24180
|
+
return true;
|
|
24181
|
+
return !(deps.alive ?? processAlive)(body.pid);
|
|
24182
|
+
}
|
|
24183
|
+
function writeLock(path, pid, deps, flag) {
|
|
24184
|
+
writeFileSync7(path, JSON.stringify({ pid, at: (deps.clock ?? Date.now)() }), { flag, mode: 384 });
|
|
24185
|
+
}
|
|
24186
|
+
function tryTakeScanLock(deps = {}) {
|
|
24187
|
+
return tryTakeLockFile(scanLockPath(deps.home), SCAN_LOCK_STALE_MS, deps);
|
|
24188
|
+
}
|
|
24189
|
+
function tryTakeLockFile(path, staleMs, deps = {}) {
|
|
24190
|
+
const pid = deps.pid ?? process.pid;
|
|
24191
|
+
try {
|
|
24192
|
+
mkdirSync5(nodePath3.dirname(path), { recursive: true, mode: 448 });
|
|
24193
|
+
} catch {
|
|
24194
|
+
return false;
|
|
24195
|
+
}
|
|
24196
|
+
for (let attempt2 = 0; attempt2 < 2; attempt2++) {
|
|
24197
|
+
try {
|
|
24198
|
+
writeLock(path, pid, deps, "wx");
|
|
24199
|
+
return true;
|
|
24200
|
+
} catch (err) {
|
|
24201
|
+
if (err.code !== "EEXIST")
|
|
24202
|
+
return false;
|
|
24203
|
+
}
|
|
24204
|
+
const seen = readLockBody(path);
|
|
24205
|
+
if (seen === "missing")
|
|
24206
|
+
continue;
|
|
24207
|
+
if (!isStale(seen, staleMs, deps))
|
|
24208
|
+
return false;
|
|
24209
|
+
const aside = `${path}.${String(pid)}.${String((deps.clock ?? Date.now)())}.stale`;
|
|
24210
|
+
try {
|
|
24211
|
+
renameSync5(path, aside);
|
|
24212
|
+
} catch {
|
|
24213
|
+
continue;
|
|
24214
|
+
}
|
|
24215
|
+
const taken = readLockBody(aside);
|
|
24216
|
+
const same = taken !== "missing" && (seen === null ? taken === null : taken !== null && taken.pid === seen.pid && taken.at === seen.at);
|
|
24217
|
+
if (!same && taken !== "missing" && !isStale(taken, staleMs, deps)) {
|
|
24218
|
+
try {
|
|
24219
|
+
linkSync(aside, path);
|
|
24220
|
+
} catch {
|
|
24221
|
+
}
|
|
24222
|
+
try {
|
|
24223
|
+
unlinkSync4(aside);
|
|
24224
|
+
} catch {
|
|
24225
|
+
}
|
|
24226
|
+
return false;
|
|
24227
|
+
}
|
|
24228
|
+
try {
|
|
24229
|
+
unlinkSync4(aside);
|
|
24230
|
+
} catch {
|
|
24231
|
+
}
|
|
24232
|
+
}
|
|
24233
|
+
return false;
|
|
24234
|
+
}
|
|
24235
|
+
function releaseLockFile(path, pid = process.pid) {
|
|
24236
|
+
const body = readLockBody(path);
|
|
24237
|
+
if (body === "missing" || body === null || body.pid !== pid)
|
|
24238
|
+
return;
|
|
24239
|
+
try {
|
|
24240
|
+
unlinkSync4(path);
|
|
24241
|
+
} catch {
|
|
24242
|
+
}
|
|
24243
|
+
}
|
|
24244
|
+
function releaseScanLock(deps = {}) {
|
|
24245
|
+
releaseLockFile(scanLockPath(deps.home), deps.pid ?? process.pid);
|
|
24246
|
+
}
|
|
24247
|
+
function sleepSync(ms) {
|
|
24248
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
24249
|
+
}
|
|
24250
|
+
function scanUnderLock(key, deps = {}, waitMs = 0) {
|
|
24251
|
+
const clock = deps.clock ?? Date.now;
|
|
24252
|
+
const giveUpAt = clock() + waitMs;
|
|
24253
|
+
while (!tryTakeScanLock(deps)) {
|
|
24254
|
+
if (clock() >= giveUpAt)
|
|
24255
|
+
return null;
|
|
24256
|
+
sleepSync(SCAN_LOCK_POLL_MS);
|
|
24257
|
+
}
|
|
24258
|
+
try {
|
|
24259
|
+
return scanRecords(key, deps);
|
|
24260
|
+
} finally {
|
|
24261
|
+
releaseScanLock(deps);
|
|
24262
|
+
}
|
|
24263
|
+
}
|
|
24264
|
+
var spawnDetachedReal = (command, args2) => {
|
|
24265
|
+
const child = spawn(command, [...args2], { detached: true, stdio: "ignore", windowsHide: true });
|
|
24266
|
+
child.on("error", () => void 0);
|
|
24267
|
+
child.unref();
|
|
24268
|
+
return child.pid;
|
|
24269
|
+
};
|
|
24270
|
+
function startScanChild(key, binaryPath, deps = {}) {
|
|
24271
|
+
if (!tryTakeScanLock(deps))
|
|
24272
|
+
return false;
|
|
24273
|
+
let childPid;
|
|
24274
|
+
try {
|
|
24275
|
+
childPid = (deps.spawnDetached ?? spawnDetachedReal)(deps.nodePath ?? process.execPath, [
|
|
24276
|
+
binaryPath,
|
|
24277
|
+
"pace",
|
|
24278
|
+
"--scan",
|
|
24279
|
+
"--config-folder",
|
|
24280
|
+
key,
|
|
24281
|
+
"--lock-held"
|
|
24282
|
+
]);
|
|
24283
|
+
} catch {
|
|
24284
|
+
childPid = void 0;
|
|
24285
|
+
}
|
|
24286
|
+
if (childPid === void 0) {
|
|
24287
|
+
releaseScanLock(deps);
|
|
24288
|
+
return false;
|
|
24289
|
+
}
|
|
24290
|
+
try {
|
|
24291
|
+
writeLock(scanLockPath(deps.home), childPid, deps, "w");
|
|
24292
|
+
} catch {
|
|
24293
|
+
releaseScanLock(deps);
|
|
24294
|
+
return false;
|
|
24295
|
+
}
|
|
24296
|
+
return true;
|
|
24297
|
+
}
|
|
24298
|
+
|
|
23868
24299
|
// dist/time-record.js
|
|
23869
24300
|
var TIME_EVENT_KINDS = ["action", "asked", "edit", "turn-end", "lock-wait-start", "lock-wait-end"];
|
|
23870
24301
|
function isLockWaitEvent(event) {
|
|
@@ -23878,25 +24309,25 @@ function inputString(input, key) {
|
|
|
23878
24309
|
const value = input[key];
|
|
23879
24310
|
return typeof value === "string" && value !== "" ? value : null;
|
|
23880
24311
|
}
|
|
23881
|
-
function readBranch(
|
|
23882
|
-
const copy = whichCopy(
|
|
24312
|
+
function readBranch(folder2, deps = {}) {
|
|
24313
|
+
const copy = whichCopy(folder2, deps);
|
|
23883
24314
|
return copy === null ? null : copyBranch(copy, deps);
|
|
23884
24315
|
}
|
|
23885
24316
|
function timeLogPath(engagementId, home) {
|
|
23886
24317
|
if (!isEngagementId(engagementId))
|
|
23887
24318
|
return null;
|
|
23888
|
-
return
|
|
24319
|
+
return join11(home ?? homedir8(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, TIME_LOG_DIR_NAME, TIME_LOG_FILENAME);
|
|
23889
24320
|
}
|
|
23890
24321
|
function timeEventLine(event, input, deps = {}) {
|
|
23891
24322
|
const at = (deps.now ?? (() => /* @__PURE__ */ new Date()))().toISOString();
|
|
23892
|
-
const
|
|
24323
|
+
const folder2 = inputString(input, "cwd") ?? (deps.cwd ?? (() => process.cwd()))();
|
|
23893
24324
|
return {
|
|
23894
24325
|
at,
|
|
23895
24326
|
event,
|
|
23896
24327
|
session: inputString(input, "session_id"),
|
|
23897
24328
|
agent: inputString(input, "agent_id"),
|
|
23898
|
-
folder,
|
|
23899
|
-
branch: readBranch(
|
|
24329
|
+
folder: folder2,
|
|
24330
|
+
branch: readBranch(folder2),
|
|
23900
24331
|
transcript: inputString(input, "transcript_path"),
|
|
23901
24332
|
toolUse: inputString(input, "tool_use_id"),
|
|
23902
24333
|
rollout: inputString(input, "rollout_path")
|
|
@@ -23914,12 +24345,12 @@ function recordTimeEvent(event, input, deps = {}) {
|
|
|
23914
24345
|
const text = `${JSON.stringify(line2)}
|
|
23915
24346
|
`;
|
|
23916
24347
|
try {
|
|
23917
|
-
|
|
24348
|
+
appendFileSync3(path, text, { mode: 384 });
|
|
23918
24349
|
} catch (err) {
|
|
23919
24350
|
if (err.code !== "ENOENT")
|
|
23920
24351
|
return;
|
|
23921
|
-
|
|
23922
|
-
|
|
24352
|
+
mkdirSync6(dirname4(path), { recursive: true, mode: 448 });
|
|
24353
|
+
appendFileSync3(path, text, { mode: 384 });
|
|
23923
24354
|
}
|
|
23924
24355
|
} catch {
|
|
23925
24356
|
}
|
|
@@ -23978,7 +24409,7 @@ function readSessionTimeLines(sessionId, deps = {}) {
|
|
|
23978
24409
|
if (path === null)
|
|
23979
24410
|
return [];
|
|
23980
24411
|
const needle = JSON.stringify(sessionId);
|
|
23981
|
-
const kept =
|
|
24412
|
+
const kept = readFileSync15(path, "utf-8").split("\n").filter((raw) => raw.includes(needle));
|
|
23982
24413
|
return parseTimeLog(kept.join("\n")).filter((line2) => line2.session === sessionId);
|
|
23983
24414
|
} catch {
|
|
23984
24415
|
return [];
|
|
@@ -24005,8 +24436,8 @@ function separatorOf(path) {
|
|
|
24005
24436
|
function subagentsFolderOf(transcript) {
|
|
24006
24437
|
if (!transcript.endsWith(".jsonl") || transcript.length === ".jsonl".length)
|
|
24007
24438
|
return null;
|
|
24008
|
-
const
|
|
24009
|
-
return `${transcript.slice(0, -".jsonl".length)}${
|
|
24439
|
+
const sep8 = separatorOf(transcript);
|
|
24440
|
+
return `${transcript.slice(0, -".jsonl".length)}${sep8}subagents`;
|
|
24010
24441
|
}
|
|
24011
24442
|
function subagentRecordName(agentId) {
|
|
24012
24443
|
return /^[A-Za-z0-9_-]+$/.test(agentId) ? `agent-${agentId}.jsonl` : null;
|
|
@@ -24014,12 +24445,12 @@ function subagentRecordName(agentId) {
|
|
|
24014
24445
|
function subagentRecordPath(transcript, agentId) {
|
|
24015
24446
|
if (transcript === null)
|
|
24016
24447
|
return null;
|
|
24017
|
-
const
|
|
24448
|
+
const folder2 = subagentsFolderOf(transcript);
|
|
24018
24449
|
const name = subagentRecordName(agentId);
|
|
24019
|
-
return
|
|
24450
|
+
return folder2 === null || name === null ? null : `${folder2}${separatorOf(transcript)}${name}`;
|
|
24020
24451
|
}
|
|
24021
|
-
function folderParts(
|
|
24022
|
-
return
|
|
24452
|
+
function folderParts(folder2) {
|
|
24453
|
+
return folder2.split(/[\\/]+/).filter((part, i) => part !== "" || i === 0);
|
|
24023
24454
|
}
|
|
24024
24455
|
function folderHolds(outer, inner) {
|
|
24025
24456
|
const o = folderParts(outer);
|
|
@@ -24072,15 +24503,52 @@ function buildLanes(events, taskIds) {
|
|
|
24072
24503
|
});
|
|
24073
24504
|
}
|
|
24074
24505
|
var UNREADABLE2 = { readable: false, lines: [] };
|
|
24075
|
-
function
|
|
24076
|
-
|
|
24077
|
-
|
|
24078
|
-
|
|
24079
|
-
|
|
24080
|
-
|
|
24081
|
-
|
|
24082
|
-
|
|
24506
|
+
function plainObject(v) {
|
|
24507
|
+
return typeof v === "object" && v !== null && !Array.isArray(v) ? v : null;
|
|
24508
|
+
}
|
|
24509
|
+
var USAGE_KEYS = ["input_tokens", "output_tokens", "cache_creation_input_tokens", "cache_read_input_tokens"];
|
|
24510
|
+
function reducedLine(o) {
|
|
24511
|
+
const out = { type: o["type"] };
|
|
24512
|
+
if (typeof o["timestamp"] === "string")
|
|
24513
|
+
out["timestamp"] = o["timestamp"];
|
|
24514
|
+
if (typeof o["gitBranch"] === "string")
|
|
24515
|
+
out["gitBranch"] = o["gitBranch"];
|
|
24516
|
+
if ("toolUseResult" in o)
|
|
24517
|
+
out["toolUseResult"] = true;
|
|
24518
|
+
if (o["isApiErrorMessage"] === true)
|
|
24519
|
+
out["isApiErrorMessage"] = true;
|
|
24520
|
+
if (typeof o["error"] === "string")
|
|
24521
|
+
out["error"] = o["error"];
|
|
24522
|
+
const message = plainObject(o["message"]);
|
|
24523
|
+
if (message !== null) {
|
|
24524
|
+
const m = {};
|
|
24525
|
+
if (typeof message["id"] === "string")
|
|
24526
|
+
m["id"] = message["id"];
|
|
24527
|
+
if (typeof message["model"] === "string")
|
|
24528
|
+
m["model"] = message["model"];
|
|
24529
|
+
const usage = plainObject(message["usage"]);
|
|
24530
|
+
if (usage !== null) {
|
|
24531
|
+
const u = {};
|
|
24532
|
+
for (const key of USAGE_KEYS)
|
|
24533
|
+
if (key in usage)
|
|
24534
|
+
u[key] = usage[key];
|
|
24535
|
+
m["usage"] = u;
|
|
24536
|
+
}
|
|
24537
|
+
const content = message["content"];
|
|
24538
|
+
if (Array.isArray(content) && content.some((block) => plainObject(block)?.["type"] === "tool_result"))
|
|
24539
|
+
m["content"] = [{ type: "tool_result" }];
|
|
24540
|
+
out["message"] = m;
|
|
24083
24541
|
}
|
|
24542
|
+
return out;
|
|
24543
|
+
}
|
|
24544
|
+
function recordLineOfValue(value) {
|
|
24545
|
+
const o = plainObject(value);
|
|
24546
|
+
if (o === null || typeof o["type"] !== "string")
|
|
24547
|
+
return null;
|
|
24548
|
+
const t = typeof o["timestamp"] === "string" ? Date.parse(o["timestamp"]) : NaN;
|
|
24549
|
+
return { value: o, t: Number.isNaN(t) ? null : t };
|
|
24550
|
+
}
|
|
24551
|
+
function recordLinesOf(text) {
|
|
24084
24552
|
const lines2 = [];
|
|
24085
24553
|
for (const raw of text.split("\n")) {
|
|
24086
24554
|
if (raw.trim() === "")
|
|
@@ -24091,29 +24559,129 @@ function viewRecord(path, deps) {
|
|
|
24091
24559
|
} catch {
|
|
24092
24560
|
continue;
|
|
24093
24561
|
}
|
|
24094
|
-
|
|
24562
|
+
const o = plainObject(value);
|
|
24563
|
+
if (o === null || typeof o["type"] !== "string")
|
|
24095
24564
|
continue;
|
|
24096
|
-
|
|
24097
|
-
|
|
24098
|
-
|
|
24099
|
-
|
|
24100
|
-
|
|
24565
|
+
lines2.push(recordLineOfValue(reducedLine(o)));
|
|
24566
|
+
}
|
|
24567
|
+
return lines2;
|
|
24568
|
+
}
|
|
24569
|
+
function viewRecord(path, deps) {
|
|
24570
|
+
let text;
|
|
24571
|
+
try {
|
|
24572
|
+
text = (deps.readFile ?? ((p) => readFileSync15(p, "utf-8")))(path);
|
|
24573
|
+
} catch {
|
|
24574
|
+
return UNREADABLE2;
|
|
24101
24575
|
}
|
|
24576
|
+
const lines2 = recordLinesOf(text);
|
|
24102
24577
|
return lines2.length === 0 ? UNREADABLE2 : { readable: true, lines: lines2 };
|
|
24103
24578
|
}
|
|
24579
|
+
function readFileFrom(path, offset) {
|
|
24580
|
+
const fd = openSync3(path, "r");
|
|
24581
|
+
try {
|
|
24582
|
+
const size = fstatSync2(fd).size;
|
|
24583
|
+
if (size < offset)
|
|
24584
|
+
return null;
|
|
24585
|
+
const buf = Buffer.alloc(size - offset);
|
|
24586
|
+
let got = 0;
|
|
24587
|
+
while (got < buf.length) {
|
|
24588
|
+
const n = readSync3(fd, buf, got, buf.length - got, offset + got);
|
|
24589
|
+
if (n === 0)
|
|
24590
|
+
break;
|
|
24591
|
+
got += n;
|
|
24592
|
+
}
|
|
24593
|
+
return buf.subarray(0, got);
|
|
24594
|
+
} finally {
|
|
24595
|
+
closeSync3(fd);
|
|
24596
|
+
}
|
|
24597
|
+
}
|
|
24598
|
+
function readFromOf(deps) {
|
|
24599
|
+
if (deps.readFrom !== void 0)
|
|
24600
|
+
return deps.readFrom;
|
|
24601
|
+
const readFile = deps.readFile;
|
|
24602
|
+
if (readFile === void 0)
|
|
24603
|
+
return readFileFrom;
|
|
24604
|
+
return (path, offset) => {
|
|
24605
|
+
const bytes = Buffer.from(readFile(path), "utf-8");
|
|
24606
|
+
return bytes.length < offset ? null : bytes.subarray(offset);
|
|
24607
|
+
};
|
|
24608
|
+
}
|
|
24609
|
+
function viewRecordFrom(path, deps, offsets) {
|
|
24610
|
+
const readFrom = readFromOf(deps);
|
|
24611
|
+
const stored = offsets.files.get(path);
|
|
24612
|
+
let start = stored?.offset ?? 0;
|
|
24613
|
+
let prior = stored?.lines ?? [];
|
|
24614
|
+
let bytes;
|
|
24615
|
+
try {
|
|
24616
|
+
bytes = readFrom(path, start);
|
|
24617
|
+
if (bytes === null && start > 0) {
|
|
24618
|
+
start = 0;
|
|
24619
|
+
prior = [];
|
|
24620
|
+
bytes = readFrom(path, 0);
|
|
24621
|
+
}
|
|
24622
|
+
} catch {
|
|
24623
|
+
return UNREADABLE2;
|
|
24624
|
+
}
|
|
24625
|
+
if (bytes === null)
|
|
24626
|
+
return UNREADABLE2;
|
|
24627
|
+
const buf = Buffer.from(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
24628
|
+
const end = buf.lastIndexOf(10) + 1;
|
|
24629
|
+
const fresh = end === 0 ? [] : recordLinesOf(buf.subarray(0, end).toString("utf-8"));
|
|
24630
|
+
const values = [...prior, ...fresh.map((l) => l.value)];
|
|
24631
|
+
offsets.files.set(path, { offset: start + end, lines: values });
|
|
24632
|
+
const lines2 = values.map((v) => recordLineOfValue(v));
|
|
24633
|
+
return lines2.length === 0 ? UNREADABLE2 : { readable: true, lines: lines2 };
|
|
24634
|
+
}
|
|
24635
|
+
var viewsOfOffsets = /* @__PURE__ */ new WeakMap();
|
|
24104
24636
|
function recordReader(deps) {
|
|
24105
|
-
|
|
24637
|
+
let cache2 = /* @__PURE__ */ new Map();
|
|
24638
|
+
if (deps.offsets !== void 0) {
|
|
24639
|
+
cache2 = viewsOfOffsets.get(deps.offsets) ?? /* @__PURE__ */ new Map();
|
|
24640
|
+
viewsOfOffsets.set(deps.offsets, cache2);
|
|
24641
|
+
}
|
|
24106
24642
|
return (path) => {
|
|
24107
24643
|
if (path === null)
|
|
24108
24644
|
return UNREADABLE2;
|
|
24109
24645
|
const hit = cache2.get(path);
|
|
24110
24646
|
if (hit !== void 0)
|
|
24111
24647
|
return hit;
|
|
24112
|
-
const view = viewRecord(path, deps);
|
|
24648
|
+
const view = deps.offsets === void 0 ? viewRecord(path, deps) : viewRecordFrom(path, deps, deps.offsets);
|
|
24113
24649
|
cache2.set(path, view);
|
|
24114
24650
|
return view;
|
|
24115
24651
|
};
|
|
24116
24652
|
}
|
|
24653
|
+
var TIME_READ_OFFSETS_FILENAME = "read-offsets.json";
|
|
24654
|
+
function loadReadOffsets(dir, phase, openedAt) {
|
|
24655
|
+
const fresh = { phase, openedAt, files: /* @__PURE__ */ new Map() };
|
|
24656
|
+
try {
|
|
24657
|
+
const o = plainObject(JSON.parse(readFileSync15(join11(dir, TIME_READ_OFFSETS_FILENAME), "utf-8")));
|
|
24658
|
+
if (o === null || o["phase"] !== phase || o["openedAt"] !== openedAt)
|
|
24659
|
+
return fresh;
|
|
24660
|
+
const files = plainObject(o["files"]);
|
|
24661
|
+
if (files === null)
|
|
24662
|
+
return fresh;
|
|
24663
|
+
const out = /* @__PURE__ */ new Map();
|
|
24664
|
+
for (const [path, entry] of Object.entries(files)) {
|
|
24665
|
+
const e = plainObject(entry);
|
|
24666
|
+
const offset = e?.["offset"];
|
|
24667
|
+
const lines2 = e?.["lines"];
|
|
24668
|
+
if (typeof offset !== "number" || !Number.isSafeInteger(offset) || offset < 0 || !Array.isArray(lines2))
|
|
24669
|
+
return fresh;
|
|
24670
|
+
if (!lines2.every((line2) => recordLineOfValue(line2) !== null))
|
|
24671
|
+
return fresh;
|
|
24672
|
+
out.set(path, { offset, lines: lines2.map((line2) => reducedLine(line2)) });
|
|
24673
|
+
}
|
|
24674
|
+
return { phase, openedAt, files: out };
|
|
24675
|
+
} catch {
|
|
24676
|
+
return fresh;
|
|
24677
|
+
}
|
|
24678
|
+
}
|
|
24679
|
+
function saveReadOffsets(dir, offsets) {
|
|
24680
|
+
try {
|
|
24681
|
+
writeJsonFile(join11(dir, TIME_READ_OFFSETS_FILENAME), { phase: offsets.phase, openedAt: offsets.openedAt, files: Object.fromEntries(offsets.files) });
|
|
24682
|
+
} catch {
|
|
24683
|
+
}
|
|
24684
|
+
}
|
|
24117
24685
|
function isPrompt(line2) {
|
|
24118
24686
|
const o = line2.value;
|
|
24119
24687
|
if (o["type"] !== "user" || line2.t === null || "toolUseResult" in o)
|
|
@@ -24304,23 +24872,76 @@ function tokensOf(usage) {
|
|
|
24304
24872
|
}
|
|
24305
24873
|
return out;
|
|
24306
24874
|
}
|
|
24307
|
-
|
|
24875
|
+
var TIME_SETTLED_FILENAME = "settled.json";
|
|
24876
|
+
function taskNamedIn(text, taskIds) {
|
|
24877
|
+
let named = null;
|
|
24878
|
+
for (const id of new Set(taskIds)) {
|
|
24879
|
+
if (id === "")
|
|
24880
|
+
continue;
|
|
24881
|
+
const escaped = id.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
24882
|
+
if (!new RegExp(`(?<![A-Za-z0-9_-])${escaped}(?![A-Za-z0-9_-])`).test(text))
|
|
24883
|
+
continue;
|
|
24884
|
+
if (named !== null)
|
|
24885
|
+
return null;
|
|
24886
|
+
named = id;
|
|
24887
|
+
}
|
|
24888
|
+
return named;
|
|
24889
|
+
}
|
|
24890
|
+
function spawnDescriptionOf(recordPath, deps) {
|
|
24891
|
+
if (!recordPath.endsWith(".jsonl"))
|
|
24892
|
+
return null;
|
|
24893
|
+
try {
|
|
24894
|
+
const text = (deps.readFile ?? ((p) => readFileSync15(p, "utf-8")))(`${recordPath.slice(0, -".jsonl".length)}.meta.json`);
|
|
24895
|
+
const value = JSON.parse(text);
|
|
24896
|
+
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
24897
|
+
return null;
|
|
24898
|
+
const description = value["description"];
|
|
24899
|
+
return typeof description === "string" ? description : null;
|
|
24900
|
+
} catch {
|
|
24901
|
+
return null;
|
|
24902
|
+
}
|
|
24903
|
+
}
|
|
24904
|
+
function sameFolder(a, b) {
|
|
24905
|
+
const pa = folderParts(a);
|
|
24906
|
+
const pb = folderParts(b);
|
|
24907
|
+
return pa.length === pb.length && pa.every((part, k) => part === pb[k]);
|
|
24908
|
+
}
|
|
24909
|
+
function nextTaskOf(own, t) {
|
|
24308
24910
|
let next;
|
|
24309
|
-
let last;
|
|
24310
24911
|
for (const lane of own) {
|
|
24311
24912
|
if (lane.task === null)
|
|
24312
24913
|
continue;
|
|
24313
|
-
const
|
|
24314
|
-
const after = times.find((at) => at > t);
|
|
24914
|
+
const after = lane.events.map((e) => msOf(e.at)).find((at) => at > t);
|
|
24315
24915
|
if (after !== void 0 && (next === void 0 || after < next.t))
|
|
24316
24916
|
next = { task: lane.task, t: after };
|
|
24317
|
-
|
|
24917
|
+
}
|
|
24918
|
+
return next?.task ?? null;
|
|
24919
|
+
}
|
|
24920
|
+
function lastTaskOf(own, t) {
|
|
24921
|
+
let last;
|
|
24922
|
+
for (const lane of own) {
|
|
24923
|
+
if (lane.task === null)
|
|
24924
|
+
continue;
|
|
24925
|
+
const before = lastAtOrBefore(lane.events.map((e) => msOf(e.at)), t);
|
|
24318
24926
|
if (before !== void 0 && (last === void 0 || before >= last.t))
|
|
24319
24927
|
last = { task: lane.task, t: before };
|
|
24320
24928
|
}
|
|
24321
|
-
return
|
|
24929
|
+
return last?.task ?? null;
|
|
24322
24930
|
}
|
|
24323
|
-
function
|
|
24931
|
+
function nextTaskInFolderOf(lanes, folder2, t) {
|
|
24932
|
+
let next;
|
|
24933
|
+
for (const lane of lanes) {
|
|
24934
|
+
if (lane.task === null)
|
|
24935
|
+
continue;
|
|
24936
|
+
for (const e of lane.events) {
|
|
24937
|
+
const at = msOf(e.at);
|
|
24938
|
+
if (at > t && sameFolder(e.folder, folder2) && (next === void 0 || at < next.t))
|
|
24939
|
+
next = { task: lane.task, t: at };
|
|
24940
|
+
}
|
|
24941
|
+
}
|
|
24942
|
+
return next?.task ?? null;
|
|
24943
|
+
}
|
|
24944
|
+
function readUsage(lanes, window, deps = {}, models, settling = {}) {
|
|
24324
24945
|
const from = Date.parse(window.from);
|
|
24325
24946
|
const to = window.to === void 0 || window.to === null ? Infinity : Date.parse(window.to);
|
|
24326
24947
|
const inWindow = (t) => t >= from && t <= to;
|
|
@@ -24336,7 +24957,29 @@ function readUsage(lanes, window, deps = {}, models) {
|
|
|
24336
24957
|
return buckets.get(key) ?? buckets.set(key, { source, task, readable, messages: 0, inputTokens: 0, outputTokens: 0, cacheWriteTokens: 0, cacheReadTokens: 0 }).get(key);
|
|
24337
24958
|
};
|
|
24338
24959
|
const seen = /* @__PURE__ */ new Set();
|
|
24339
|
-
const
|
|
24960
|
+
const held = /* @__PURE__ */ new Set();
|
|
24961
|
+
const settled2 = settling.settled ?? /* @__PURE__ */ new Map();
|
|
24962
|
+
const final = settling.final === true;
|
|
24963
|
+
const figureIds = /* @__PURE__ */ new Set();
|
|
24964
|
+
const addToFigure = (view) => {
|
|
24965
|
+
const figure = settling.figure;
|
|
24966
|
+
if (figure === void 0)
|
|
24967
|
+
return;
|
|
24968
|
+
for (const line2 of view.lines) {
|
|
24969
|
+
if (line2.value["type"] !== "assistant" || line2.t === null || !inWindow(line2.t))
|
|
24970
|
+
continue;
|
|
24971
|
+
const message = plainObject(line2.value["message"]);
|
|
24972
|
+
const id = message?.["id"];
|
|
24973
|
+
if (typeof id !== "string" || id === "" || figureIds.has(id))
|
|
24974
|
+
continue;
|
|
24975
|
+
const tokens = tokensOf(message["usage"]);
|
|
24976
|
+
if (tokens === null)
|
|
24977
|
+
continue;
|
|
24978
|
+
figureIds.add(id);
|
|
24979
|
+
figure.claudeCode += tokens[0] + tokens[1] + tokens[2] + tokens[3];
|
|
24980
|
+
}
|
|
24981
|
+
};
|
|
24982
|
+
const count = (path, view, taskAt) => {
|
|
24340
24983
|
const source = recordSourceOf(path);
|
|
24341
24984
|
for (const line2 of view.lines) {
|
|
24342
24985
|
const o = line2.value;
|
|
@@ -24346,19 +24989,22 @@ function readUsage(lanes, window, deps = {}, models) {
|
|
|
24346
24989
|
if (typeof message !== "object" || message === null)
|
|
24347
24990
|
continue;
|
|
24348
24991
|
const id = message["id"];
|
|
24349
|
-
if (typeof id !== "string" || id === "" || seen.has(id))
|
|
24992
|
+
if (typeof id !== "string" || id === "" || seen.has(id) || held.has(id))
|
|
24350
24993
|
continue;
|
|
24351
24994
|
const tokens = tokensOf(message["usage"]);
|
|
24352
24995
|
if (tokens === null)
|
|
24353
24996
|
continue;
|
|
24997
|
+
const task = taskAt(line2, id);
|
|
24998
|
+
if (task === void 0) {
|
|
24999
|
+
held.add(id);
|
|
25000
|
+
continue;
|
|
25001
|
+
}
|
|
24354
25002
|
seen.add(id);
|
|
24355
|
-
const task = taskAt(line2);
|
|
24356
25003
|
const bucket = bucketFor(source, task, true);
|
|
24357
25004
|
bucket.messages += 1;
|
|
24358
25005
|
const model = message["model"];
|
|
24359
|
-
|
|
24360
|
-
|
|
24361
|
-
const ofTask = models.get(modelTask) ?? models.set(modelTask, /* @__PURE__ */ new Map()).get(modelTask);
|
|
25006
|
+
if (models !== void 0 && task !== null && isTalliedModel(model)) {
|
|
25007
|
+
const ofTask = models.get(task) ?? models.set(task, /* @__PURE__ */ new Map()).get(task);
|
|
24362
25008
|
ofTask.set(model, (ofTask.get(model) ?? 0) + 1);
|
|
24363
25009
|
}
|
|
24364
25010
|
bucket.inputTokens += tokens[0];
|
|
@@ -24369,42 +25015,77 @@ function readUsage(lanes, window, deps = {}, models) {
|
|
|
24369
25015
|
};
|
|
24370
25016
|
for (const main2 of mains) {
|
|
24371
25017
|
const view = read(main2);
|
|
25018
|
+
addToFigure(view);
|
|
24372
25019
|
if (view.readable) {
|
|
25020
|
+
let coordinatingFrom = Infinity;
|
|
25021
|
+
for (const lane of lanes) {
|
|
25022
|
+
if (lane.agent === MAIN_AGENT || lane.transcript !== main2)
|
|
25023
|
+
continue;
|
|
25024
|
+
for (const e of lane.events)
|
|
25025
|
+
coordinatingFrom = Math.min(coordinatingFrom, msOf(e.at));
|
|
25026
|
+
}
|
|
24373
25027
|
count(main2, view, (line2) => {
|
|
25028
|
+
if (line2.t >= coordinatingFrom)
|
|
25029
|
+
return null;
|
|
24374
25030
|
const branch = line2.value["gitBranch"];
|
|
24375
25031
|
return taskOfBranch(typeof branch === "string" ? branch : null, window.taskIds);
|
|
24376
25032
|
});
|
|
24377
25033
|
}
|
|
24378
|
-
const
|
|
24379
|
-
if (
|
|
25034
|
+
const folder2 = subagentsFolderOf(main2);
|
|
25035
|
+
if (folder2 === null)
|
|
24380
25036
|
continue;
|
|
24381
25037
|
let names;
|
|
24382
25038
|
try {
|
|
24383
|
-
names = listDir(
|
|
25039
|
+
names = listDir(folder2).filter((name) => /^agent-[A-Za-z0-9_-]+\.jsonl$/.test(name)).sort();
|
|
24384
25040
|
} catch {
|
|
24385
25041
|
continue;
|
|
24386
25042
|
}
|
|
24387
25043
|
for (const name of names) {
|
|
24388
|
-
const path = `${
|
|
25044
|
+
const path = `${folder2}${separatorOf(main2)}${name}`;
|
|
24389
25045
|
const view2 = read(path);
|
|
25046
|
+
addToFigure(view2);
|
|
24390
25047
|
if (!view2.readable)
|
|
24391
25048
|
continue;
|
|
24392
25049
|
const agent = name.slice("agent-".length, -".jsonl".length);
|
|
24393
25050
|
const own = active.filter((lane) => lane.agent === agent && lane.transcript === main2);
|
|
24394
25051
|
if (own.length === 0)
|
|
24395
25052
|
continue;
|
|
24396
|
-
|
|
25053
|
+
const ownAll = lanes.filter((lane) => lane.agent === agent && lane.transcript === main2);
|
|
25054
|
+
let description;
|
|
25055
|
+
count(path, view2, (line2, id) => {
|
|
25056
|
+
const t = line2.t;
|
|
24397
25057
|
let best;
|
|
24398
|
-
for (const
|
|
24399
|
-
const latest = lastAtOrBefore(
|
|
25058
|
+
for (const lane2 of own) {
|
|
25059
|
+
const latest = lastAtOrBefore(lane2.events.map((e) => msOf(e.at)), t);
|
|
24400
25060
|
if (latest !== void 0 && (best === void 0 || latest >= best.t))
|
|
24401
|
-
best = { lane, t: latest };
|
|
25061
|
+
best = { lane: lane2, t: latest };
|
|
24402
25062
|
}
|
|
24403
|
-
|
|
24404
|
-
|
|
24405
|
-
|
|
24406
|
-
|
|
24407
|
-
|
|
25063
|
+
const lane = best?.lane ?? [...own].sort((a, b) => msOf(a.events[0].at) - msOf(b.events[0].at))[0];
|
|
25064
|
+
if (lane.task !== null)
|
|
25065
|
+
return lane.task;
|
|
25066
|
+
if (settled2.has(id)) {
|
|
25067
|
+
const task2 = settled2.get(id);
|
|
25068
|
+
return task2 !== null && window.taskIds.includes(task2) ? task2 : null;
|
|
25069
|
+
}
|
|
25070
|
+
const next = nextTaskOf(ownAll, t);
|
|
25071
|
+
if (next !== null)
|
|
25072
|
+
return next;
|
|
25073
|
+
if (!final)
|
|
25074
|
+
return void 0;
|
|
25075
|
+
const before = lane.events.filter((e) => msOf(e.at) <= t);
|
|
25076
|
+
const folder3 = (before[before.length - 1] ?? lane.events[0]).folder;
|
|
25077
|
+
let task = nextTaskInFolderOf(lanes, folder3, t);
|
|
25078
|
+
if (task === null) {
|
|
25079
|
+
if (description === void 0)
|
|
25080
|
+
description = spawnDescriptionOf(path, deps);
|
|
25081
|
+
if (description !== null)
|
|
25082
|
+
task = taskNamedIn(description, window.taskIds);
|
|
25083
|
+
}
|
|
25084
|
+
if (task === null)
|
|
25085
|
+
task = lastTaskOf(ownAll, t);
|
|
25086
|
+
settled2.set(id, task);
|
|
25087
|
+
return task;
|
|
25088
|
+
});
|
|
24408
25089
|
}
|
|
24409
25090
|
}
|
|
24410
25091
|
const codexLanes = active.filter((lane) => lane.rollout !== null && lane.transcript === null);
|
|
@@ -24426,6 +25107,8 @@ function readUsage(lanes, window, deps = {}, models) {
|
|
|
24426
25107
|
best = { lane, t: latest };
|
|
24427
25108
|
}
|
|
24428
25109
|
const bucket = bucketFor(source, (best?.lane ?? first)?.task ?? null, true);
|
|
25110
|
+
if (settling.figure !== void 0)
|
|
25111
|
+
settling.figure.codex += step.inputTokens + step.outputTokens + step.cacheWriteTokens + step.cacheReadTokens;
|
|
24429
25112
|
bucket.messages += 1;
|
|
24430
25113
|
bucket.inputTokens += step.inputTokens;
|
|
24431
25114
|
bucket.outputTokens += step.outputTokens;
|
|
@@ -24446,13 +25129,13 @@ var PHASE_MODELS_FILENAME = "phase-models.json";
|
|
|
24446
25129
|
function phaseModelsPath(engagementId, home) {
|
|
24447
25130
|
if (!isEngagementId(engagementId))
|
|
24448
25131
|
return null;
|
|
24449
|
-
return
|
|
25132
|
+
return join11(home ?? homedir8(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, PACING_DIR_NAME, PHASE_MODELS_FILENAME);
|
|
24450
25133
|
}
|
|
24451
25134
|
function writePhaseModels(path, phase, openedAt, tally) {
|
|
24452
25135
|
try {
|
|
24453
25136
|
let tasks = {};
|
|
24454
25137
|
try {
|
|
24455
|
-
const prior = phaseModelsFileSchema.safeParse(JSON.parse(
|
|
25138
|
+
const prior = phaseModelsFileSchema.safeParse(JSON.parse(readFileSync15(path, "utf-8")));
|
|
24456
25139
|
if (prior.success && prior.data.phase === phase && prior.data.openedAt === openedAt)
|
|
24457
25140
|
tasks = prior.data.tasks;
|
|
24458
25141
|
} catch {
|
|
@@ -24480,14 +25163,14 @@ function timeLogDir(engagementId, home) {
|
|
|
24480
25163
|
return path === null ? null : dirname4(path);
|
|
24481
25164
|
}
|
|
24482
25165
|
function writeJsonFile(path, value) {
|
|
24483
|
-
|
|
25166
|
+
mkdirSync6(dirname4(path), { recursive: true, mode: 448 });
|
|
24484
25167
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
24485
|
-
|
|
24486
|
-
|
|
25168
|
+
writeFileSync8(tmp, JSON.stringify(value), { mode: 384 });
|
|
25169
|
+
renameSync6(tmp, path);
|
|
24487
25170
|
}
|
|
24488
25171
|
function readAttemptedAt(dir) {
|
|
24489
25172
|
try {
|
|
24490
|
-
const parsed = JSON.parse(
|
|
25173
|
+
const parsed = JSON.parse(readFileSync15(join11(dir, TIME_THROTTLE_FILENAME), "utf-8"));
|
|
24491
25174
|
return typeof parsed.attemptedAt === "number" ? parsed.attemptedAt : null;
|
|
24492
25175
|
} catch {
|
|
24493
25176
|
return null;
|
|
@@ -24495,7 +25178,7 @@ function readAttemptedAt(dir) {
|
|
|
24495
25178
|
}
|
|
24496
25179
|
function writeAttemptedAt(dir, at) {
|
|
24497
25180
|
try {
|
|
24498
|
-
writeJsonFile(
|
|
25181
|
+
writeJsonFile(join11(dir, TIME_THROTTLE_FILENAME), { attemptedAt: at });
|
|
24499
25182
|
} catch {
|
|
24500
25183
|
}
|
|
24501
25184
|
}
|
|
@@ -24513,7 +25196,7 @@ function stringRecord(value) {
|
|
|
24513
25196
|
function readTimeCursor(dir, phase, openedAt) {
|
|
24514
25197
|
const fresh = { phase, openedAt, sentThrough: null, sentIds: {}, usage: {} };
|
|
24515
25198
|
try {
|
|
24516
|
-
const o = JSON.parse(
|
|
25199
|
+
const o = JSON.parse(readFileSync15(join11(dir, TIME_CURSOR_FILENAME), "utf-8"));
|
|
24517
25200
|
if (o["phase"] !== phase || o["openedAt"] !== openedAt)
|
|
24518
25201
|
return fresh;
|
|
24519
25202
|
const sentThrough = o["sentThrough"];
|
|
@@ -24526,6 +25209,29 @@ function readTimeCursor(dir, phase, openedAt) {
|
|
|
24526
25209
|
return fresh;
|
|
24527
25210
|
}
|
|
24528
25211
|
}
|
|
25212
|
+
function readSettled(dir, phase, openedAt) {
|
|
25213
|
+
const out = /* @__PURE__ */ new Map();
|
|
25214
|
+
try {
|
|
25215
|
+
const o = JSON.parse(readFileSync15(join11(dir, TIME_SETTLED_FILENAME), "utf-8"));
|
|
25216
|
+
if (o["phase"] !== phase || o["openedAt"] !== openedAt)
|
|
25217
|
+
return out;
|
|
25218
|
+
const tasks = o["tasks"];
|
|
25219
|
+
if (typeof tasks !== "object" || tasks === null || Array.isArray(tasks))
|
|
25220
|
+
return out;
|
|
25221
|
+
for (const [id, task] of Object.entries(tasks)) {
|
|
25222
|
+
if (task === null || typeof task === "string")
|
|
25223
|
+
out.set(id, task);
|
|
25224
|
+
}
|
|
25225
|
+
} catch {
|
|
25226
|
+
}
|
|
25227
|
+
return out;
|
|
25228
|
+
}
|
|
25229
|
+
function writeSettled(dir, phase, openedAt, settled2) {
|
|
25230
|
+
try {
|
|
25231
|
+
writeJsonFile(join11(dir, TIME_SETTLED_FILENAME), { phase, openedAt, tasks: Object.fromEntries(settled2) });
|
|
25232
|
+
} catch {
|
|
25233
|
+
}
|
|
25234
|
+
}
|
|
24529
25235
|
function usageKey(bucket) {
|
|
24530
25236
|
return `${bucket.source}\0${bucket.task ?? ""}`;
|
|
24531
25237
|
}
|
|
@@ -24612,33 +25318,33 @@ var PRUNE_SETTLE_MS = 50;
|
|
|
24612
25318
|
async function pruneTimeLog(path, openedAt) {
|
|
24613
25319
|
const aside = `${path}.prune-${process.pid}`;
|
|
24614
25320
|
try {
|
|
24615
|
-
|
|
25321
|
+
renameSync6(path, aside);
|
|
24616
25322
|
} catch {
|
|
24617
25323
|
return;
|
|
24618
25324
|
}
|
|
24619
25325
|
let text = "";
|
|
24620
25326
|
let written = false;
|
|
24621
25327
|
try {
|
|
24622
|
-
text =
|
|
25328
|
+
text = readFileSync15(aside, "utf-8");
|
|
24623
25329
|
const { kept } = prunedTimeLog(text, openedAt);
|
|
24624
25330
|
if (kept !== "")
|
|
24625
|
-
|
|
25331
|
+
appendFileSync3(path, kept, { mode: 384 });
|
|
24626
25332
|
written = true;
|
|
24627
25333
|
let seen = Buffer.byteLength(text, "utf-8");
|
|
24628
25334
|
for (; ; ) {
|
|
24629
|
-
await new Promise((
|
|
24630
|
-
const after =
|
|
25335
|
+
await new Promise((resolve12) => setTimeout(resolve12, PRUNE_SETTLE_MS));
|
|
25336
|
+
const after = readFileSync15(aside);
|
|
24631
25337
|
if (after.length <= seen)
|
|
24632
25338
|
break;
|
|
24633
|
-
|
|
25339
|
+
appendFileSync3(path, after.subarray(seen), { mode: 384 });
|
|
24634
25340
|
seen = after.length;
|
|
24635
25341
|
}
|
|
24636
|
-
|
|
25342
|
+
unlinkSync5(aside);
|
|
24637
25343
|
} catch {
|
|
24638
25344
|
try {
|
|
24639
25345
|
if (!written) {
|
|
24640
|
-
|
|
24641
|
-
|
|
25346
|
+
appendFileSync3(path, readFileSync15(aside, "utf-8"), { mode: 384 });
|
|
25347
|
+
unlinkSync5(aside);
|
|
24642
25348
|
}
|
|
24643
25349
|
} catch {
|
|
24644
25350
|
}
|
|
@@ -24653,7 +25359,17 @@ function conflictReason(body) {
|
|
|
24653
25359
|
const error51 = body.error;
|
|
24654
25360
|
return error51 === "basis-moved" || error51 === "phase-closed" ? error51 : null;
|
|
24655
25361
|
}
|
|
24656
|
-
async function attemptTimeRecord(config2, controlOrigin, deps = {}) {
|
|
25362
|
+
async function attemptTimeRecord(config2, controlOrigin, deps = {}, options = {}) {
|
|
25363
|
+
return (await attemptAndTell(config2, controlOrigin, deps, options)).result;
|
|
25364
|
+
}
|
|
25365
|
+
async function attemptAndTell(config2, controlOrigin, deps, options) {
|
|
25366
|
+
let wroteFigure = false;
|
|
25367
|
+
const result = await attemptOnce(config2, controlOrigin, deps, options, () => {
|
|
25368
|
+
wroteFigure = true;
|
|
25369
|
+
});
|
|
25370
|
+
return { result, wroteFigure };
|
|
25371
|
+
}
|
|
25372
|
+
async function attemptOnce(config2, controlOrigin, deps, options, onFigureWritten) {
|
|
24657
25373
|
const fetchFn = deps.fetchFn ?? globalThis.fetch;
|
|
24658
25374
|
const base = `${controlOrigin}/engagements/${encodeURIComponent(config2.guardEngagementId)}/time`;
|
|
24659
25375
|
const authorization = `Bearer ${config2.guardServiceToken}`;
|
|
@@ -24671,25 +25387,38 @@ async function attemptTimeRecord(config2, controlOrigin, deps = {}) {
|
|
|
24671
25387
|
const basis = parsedBasis.data;
|
|
24672
25388
|
if (basis.outcome === "nothing-to-record")
|
|
24673
25389
|
return { outcome: "not-sent", reason: "nothing-to-record" };
|
|
24674
|
-
const
|
|
25390
|
+
const logPath2 = join11(dir, TIME_LOG_FILENAME);
|
|
24675
25391
|
let text = "";
|
|
24676
25392
|
try {
|
|
24677
|
-
text =
|
|
25393
|
+
text = readFileSync15(logPath2, "utf-8");
|
|
24678
25394
|
} catch {
|
|
24679
25395
|
text = "";
|
|
24680
25396
|
}
|
|
24681
25397
|
const lanes = buildLanes(parseTimeLog(text), basis.taskIds);
|
|
24682
|
-
const
|
|
25398
|
+
const offsets = loadReadOffsets(dir, basis.phase, basis.openedAt);
|
|
25399
|
+
const readDeps = { ...deps, offsets };
|
|
25400
|
+
const intervals = buildIntervals(lanes, readDeps);
|
|
24683
25401
|
const models = /* @__PURE__ */ new Map();
|
|
24684
|
-
const
|
|
25402
|
+
const settled2 = readSettled(dir, basis.phase, basis.openedAt);
|
|
25403
|
+
const figure = { claudeCode: 0, codex: 0 };
|
|
25404
|
+
const final = options.final === true;
|
|
25405
|
+
const usage = readUsage(lanes, { from: basis.openedAt, taskIds: basis.taskIds }, readDeps, models, { final, settled: settled2, figure });
|
|
25406
|
+
saveReadOffsets(dir, offsets);
|
|
25407
|
+
const routing = routingFilePath(config2.guardEngagementId, deps.home);
|
|
25408
|
+
if (routing !== null)
|
|
25409
|
+
addCheapStarted(routing, basis.phase, tasksBuiltIn(lanes, usage, { from: basis.openedAt, taskIds: basis.taskIds }));
|
|
25410
|
+
if (final)
|
|
25411
|
+
writeSettled(dir, basis.phase, basis.openedAt, settled2);
|
|
24685
25412
|
const limitDir = phaseLimitDir(config2.guardEngagementId, deps.home);
|
|
24686
25413
|
if (limitDir !== null) {
|
|
24687
|
-
writePhaseUsage(limitDir, {
|
|
25414
|
+
const wrote = writePhaseUsage(limitDir, {
|
|
24688
25415
|
phase: basis.phase,
|
|
24689
25416
|
openedAt: basis.openedAt,
|
|
24690
|
-
tokens:
|
|
25417
|
+
tokens: figureOf(figure, options.agent),
|
|
24691
25418
|
at: new Date((deps.now ?? Date.now)()).toISOString()
|
|
24692
25419
|
});
|
|
25420
|
+
if (wrote)
|
|
25421
|
+
onFigureWritten();
|
|
24693
25422
|
}
|
|
24694
25423
|
const modelsPath = phaseModelsPath(config2.guardEngagementId, deps.home);
|
|
24695
25424
|
if (modelsPath !== null)
|
|
@@ -24698,7 +25427,7 @@ async function attemptTimeRecord(config2, controlOrigin, deps = {}) {
|
|
|
24698
25427
|
const selected = selectTimeReport(cursor, intervals, usage);
|
|
24699
25428
|
if (selected.intervals.length === 0 && selected.usage.length === 0) {
|
|
24700
25429
|
if (wouldPrune(text, basis.openedAt))
|
|
24701
|
-
await pruneTimeLog(
|
|
25430
|
+
await pruneTimeLog(logPath2, basis.openedAt);
|
|
24702
25431
|
return { outcome: "recorded" };
|
|
24703
25432
|
}
|
|
24704
25433
|
const report = { phase: basis.phase, openedAt: basis.openedAt, ...selected };
|
|
@@ -24714,14 +25443,14 @@ async function attemptTimeRecord(config2, controlOrigin, deps = {}) {
|
|
|
24714
25443
|
if (!timeReportResultSchema.safeParse(sent.body).success)
|
|
24715
25444
|
return { outcome: "not-sent", reason: "refused" };
|
|
24716
25445
|
try {
|
|
24717
|
-
writeJsonFile(
|
|
25446
|
+
writeJsonFile(join11(dir, TIME_CURSOR_FILENAME), advanceTimeCursor(cursor, selected));
|
|
24718
25447
|
} catch {
|
|
24719
25448
|
}
|
|
24720
25449
|
if (wouldPrune(text, basis.openedAt))
|
|
24721
|
-
await pruneTimeLog(
|
|
25450
|
+
await pruneTimeLog(logPath2, basis.openedAt);
|
|
24722
25451
|
return { outcome: "recorded" };
|
|
24723
25452
|
}
|
|
24724
|
-
async function runTimeVerb(deps = {}) {
|
|
25453
|
+
async function runTimeVerb(deps = {}, options = {}) {
|
|
24725
25454
|
let result;
|
|
24726
25455
|
try {
|
|
24727
25456
|
const env = deps.env ?? process.env;
|
|
@@ -24731,14 +25460,14 @@ async function runTimeVerb(deps = {}) {
|
|
|
24731
25460
|
result = { outcome: "not-sent", reason: "not-configured" };
|
|
24732
25461
|
} else {
|
|
24733
25462
|
writeAttemptedAt(dir, (deps.now ?? Date.now)());
|
|
24734
|
-
result = await attemptTimeRecord(configured.config, readControlOrigin(env).origin, deps);
|
|
25463
|
+
result = await attemptTimeRecord(configured.config, readControlOrigin(env).origin, deps, options);
|
|
24735
25464
|
}
|
|
24736
25465
|
} catch {
|
|
24737
25466
|
result = { outcome: "not-sent", reason: "unreachable" };
|
|
24738
25467
|
}
|
|
24739
25468
|
return timeRunResultSchema.parse(result);
|
|
24740
25469
|
}
|
|
24741
|
-
async function sendTimeRecord(deps = {}) {
|
|
25470
|
+
async function sendTimeRecord(deps = {}, options = {}) {
|
|
24742
25471
|
try {
|
|
24743
25472
|
const env = deps.env ?? process.env;
|
|
24744
25473
|
const configured = readConfig(env);
|
|
@@ -24749,17 +25478,170 @@ async function sendTimeRecord(deps = {}) {
|
|
|
24749
25478
|
return;
|
|
24750
25479
|
const now = (deps.now ?? Date.now)();
|
|
24751
25480
|
const last = readAttemptedAt(dir);
|
|
24752
|
-
|
|
24753
|
-
|
|
24754
|
-
|
|
24755
|
-
|
|
25481
|
+
let wroteFigure = false;
|
|
25482
|
+
if (!(last !== null && now - last < TIME_MIN_INTERVAL_MS && now >= last)) {
|
|
25483
|
+
writeAttemptedAt(dir, now);
|
|
25484
|
+
wroteFigure = (await attemptAndTell(configured.config, readControlOrigin(env).origin, deps, { agent: options.agent })).wroteFigure;
|
|
25485
|
+
}
|
|
25486
|
+
if (!wroteFigure)
|
|
25487
|
+
recountPhaseUsage(configured.config, deps, options);
|
|
25488
|
+
} catch {
|
|
25489
|
+
}
|
|
25490
|
+
}
|
|
25491
|
+
function recountPhaseUsage(config2, deps = {}, options = {}) {
|
|
25492
|
+
try {
|
|
25493
|
+
const limitDir = phaseLimitDir(config2.guardEngagementId, deps.home);
|
|
25494
|
+
const dir = timeLogDir(config2.guardEngagementId, deps.home);
|
|
25495
|
+
if (limitDir === null || dir === null)
|
|
25496
|
+
return false;
|
|
25497
|
+
const last = readPhaseUsageFile(limitDir);
|
|
25498
|
+
if (last === null)
|
|
25499
|
+
return false;
|
|
25500
|
+
let text = "";
|
|
25501
|
+
try {
|
|
25502
|
+
text = readFileSync15(join11(dir, TIME_LOG_FILENAME), "utf-8");
|
|
25503
|
+
} catch {
|
|
25504
|
+
text = "";
|
|
25505
|
+
}
|
|
25506
|
+
const lanes = buildLanes(parseTimeLog(text), []);
|
|
25507
|
+
const offsets = loadReadOffsets(dir, last.phase, last.openedAt);
|
|
25508
|
+
const figure = { claudeCode: 0, codex: 0 };
|
|
25509
|
+
readUsage(lanes, { from: last.openedAt, taskIds: [] }, { ...deps, offsets }, void 0, { figure });
|
|
25510
|
+
saveReadOffsets(dir, offsets);
|
|
25511
|
+
return writePhaseUsage(limitDir, {
|
|
25512
|
+
phase: last.phase,
|
|
25513
|
+
openedAt: last.openedAt,
|
|
25514
|
+
tokens: figureOf(figure, options.agent),
|
|
25515
|
+
at: new Date((deps.now ?? Date.now)()).toISOString()
|
|
25516
|
+
});
|
|
24756
25517
|
} catch {
|
|
25518
|
+
return false;
|
|
24757
25519
|
}
|
|
24758
25520
|
}
|
|
25521
|
+
function figureOf(figure, agent) {
|
|
25522
|
+
return Math.max(0, Math.round(agent === "codex" ? figure.codex : figure.claudeCode));
|
|
25523
|
+
}
|
|
25524
|
+
var ROUTING_LOCK_FILENAME = "routing.lock";
|
|
25525
|
+
var ROUTING_LOCK_GIVE_UP_MS = 50;
|
|
25526
|
+
var ROUTING_LOCK_STALE_MS = 5 * 1e3;
|
|
25527
|
+
var ROUTING_LOCK_POLL_MS = 2;
|
|
25528
|
+
function routingFilePath(engagementId, home) {
|
|
25529
|
+
if (!isEngagementId(engagementId))
|
|
25530
|
+
return null;
|
|
25531
|
+
return join11(home ?? homedir8(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, ROUTING_FILENAME);
|
|
25532
|
+
}
|
|
25533
|
+
function sleepSync2(ms) {
|
|
25534
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
25535
|
+
}
|
|
25536
|
+
function addCheapStarted(path, phase, tasks, giveUpMs = ROUTING_LOCK_GIVE_UP_MS) {
|
|
25537
|
+
if (tasks.length === 0)
|
|
25538
|
+
return true;
|
|
25539
|
+
try {
|
|
25540
|
+
const lock = join11(dirname4(path), ROUTING_LOCK_FILENAME);
|
|
25541
|
+
const giveUpAt = Date.now() + giveUpMs;
|
|
25542
|
+
while (!tryTakeLockFile(lock, ROUTING_LOCK_STALE_MS)) {
|
|
25543
|
+
if (Date.now() >= giveUpAt)
|
|
25544
|
+
return false;
|
|
25545
|
+
sleepSync2(ROUTING_LOCK_POLL_MS);
|
|
25546
|
+
}
|
|
25547
|
+
try {
|
|
25548
|
+
let started = [];
|
|
25549
|
+
try {
|
|
25550
|
+
const parsed = routingRecordSchema.safeParse(JSON.parse(readFileSync15(path, "utf-8")));
|
|
25551
|
+
if (parsed.success && parsed.data.phase === phase)
|
|
25552
|
+
started = [...parsed.data.cheapStarted];
|
|
25553
|
+
} catch {
|
|
25554
|
+
started = [];
|
|
25555
|
+
}
|
|
25556
|
+
const added = tasks.filter((t, i) => !started.includes(t) && tasks.indexOf(t) === i);
|
|
25557
|
+
if (added.length === 0)
|
|
25558
|
+
return true;
|
|
25559
|
+
const record2 = { phase, cheapStarted: [...started, ...added] };
|
|
25560
|
+
if (!routingRecordSchema.safeParse(record2).success)
|
|
25561
|
+
return false;
|
|
25562
|
+
writeJsonFile(path, record2);
|
|
25563
|
+
return true;
|
|
25564
|
+
} finally {
|
|
25565
|
+
releaseLockFile(lock);
|
|
25566
|
+
}
|
|
25567
|
+
} catch {
|
|
25568
|
+
return false;
|
|
25569
|
+
}
|
|
25570
|
+
}
|
|
25571
|
+
function recordSpawnedTask(toolInput, deps) {
|
|
25572
|
+
try {
|
|
25573
|
+
if (typeof toolInput !== "object" || toolInput === null || Array.isArray(toolInput))
|
|
25574
|
+
return null;
|
|
25575
|
+
const engagementId = readConfig(deps.env ?? process.env).config?.guardEngagementId;
|
|
25576
|
+
if (engagementId === void 0)
|
|
25577
|
+
return null;
|
|
25578
|
+
const path = routingFilePath(engagementId, deps.home);
|
|
25579
|
+
if (path === null)
|
|
25580
|
+
return null;
|
|
25581
|
+
const parsed = taskPlanSchema.safeParse(JSON.parse(readFileSync15(join11(deps.projectDir, TASK_PLAN_FILE), "utf-8")));
|
|
25582
|
+
if (!parsed.success)
|
|
25583
|
+
return null;
|
|
25584
|
+
const plan = parsed.data;
|
|
25585
|
+
const ids = plan.tasks.map((t) => t.id);
|
|
25586
|
+
const textOf = (key) => {
|
|
25587
|
+
const v = toolInput[key];
|
|
25588
|
+
return typeof v === "string" ? v : null;
|
|
25589
|
+
};
|
|
25590
|
+
const description = textOf("description");
|
|
25591
|
+
const prompt = textOf("prompt");
|
|
25592
|
+
const named = (description === null ? null : taskNamedIn(description, ids)) ?? (prompt === null ? null : taskNamedIn(prompt, ids));
|
|
25593
|
+
if (named === null)
|
|
25594
|
+
return null;
|
|
25595
|
+
const task = plan.tasks.find((t) => t.id === named);
|
|
25596
|
+
if (task === void 0 || task.kind !== "build" || task.cheapFirst !== true)
|
|
25597
|
+
return null;
|
|
25598
|
+
return addCheapStarted(path, plan.phase, [named]) ? named : null;
|
|
25599
|
+
} catch {
|
|
25600
|
+
return null;
|
|
25601
|
+
}
|
|
25602
|
+
}
|
|
25603
|
+
function tasksBuiltIn(lanes, usage, window) {
|
|
25604
|
+
const from = Date.parse(window.from);
|
|
25605
|
+
const to = window.to === void 0 || window.to === null ? Infinity : Date.parse(window.to);
|
|
25606
|
+
const inWindow = (t) => t >= from && t <= to;
|
|
25607
|
+
const out = [];
|
|
25608
|
+
const add = (task) => {
|
|
25609
|
+
if (task !== null && window.taskIds.includes(task) && !out.includes(task))
|
|
25610
|
+
out.push(task);
|
|
25611
|
+
};
|
|
25612
|
+
for (const bucket of usage)
|
|
25613
|
+
if (bucket.messages > 0)
|
|
25614
|
+
add(bucket.task);
|
|
25615
|
+
for (const lane of lanes) {
|
|
25616
|
+
if (lane.task === null)
|
|
25617
|
+
continue;
|
|
25618
|
+
const times = lane.events.map((e) => msOf(e.at)).filter(inWindow);
|
|
25619
|
+
if (times.length === 0)
|
|
25620
|
+
continue;
|
|
25621
|
+
const codex = lane.rollout !== null && lane.transcript === null;
|
|
25622
|
+
if (lane.agent !== MAIN_AGENT || codex) {
|
|
25623
|
+
add(lane.task);
|
|
25624
|
+
continue;
|
|
25625
|
+
}
|
|
25626
|
+
let coordinatingFrom = Infinity;
|
|
25627
|
+
for (const other of lanes) {
|
|
25628
|
+
if (other.agent === MAIN_AGENT)
|
|
25629
|
+
continue;
|
|
25630
|
+
const sameSession = lane.session !== null ? other.session === lane.session : lane.transcript !== null && other.transcript === lane.transcript;
|
|
25631
|
+
if (!sameSession)
|
|
25632
|
+
continue;
|
|
25633
|
+
for (const e of other.events)
|
|
25634
|
+
coordinatingFrom = Math.min(coordinatingFrom, msOf(e.at));
|
|
25635
|
+
}
|
|
25636
|
+
if (times.some((t) => t < coordinatingFrom))
|
|
25637
|
+
add(lane.task);
|
|
25638
|
+
}
|
|
25639
|
+
return out;
|
|
25640
|
+
}
|
|
24759
25641
|
|
|
24760
25642
|
// dist/own-work.js
|
|
24761
|
-
import { appendFileSync as
|
|
24762
|
-
import { basename as basename2, dirname as dirname5, isAbsolute as isAbsolute2, join as
|
|
25643
|
+
import { appendFileSync as appendFileSync4, lstatSync as lstatSync2, readFileSync as readFileSync16, realpathSync as realpathSync6 } from "node:fs";
|
|
25644
|
+
import { basename as basename2, dirname as dirname5, isAbsolute as isAbsolute2, join as join12, relative as relative5, resolve as resolve4, sep as sep3 } from "node:path";
|
|
24763
25645
|
|
|
24764
25646
|
// dist/risky/types.js
|
|
24765
25647
|
var RISKY_ACTION_TYPES = [
|
|
@@ -24793,7 +25675,7 @@ function ownWorkFileName(sessionId) {
|
|
|
24793
25675
|
function ownWorkPath(sessionId, dir) {
|
|
24794
25676
|
if (typeof sessionId !== "string" || !livenessIdOk(sessionId))
|
|
24795
25677
|
return null;
|
|
24796
|
-
return
|
|
25678
|
+
return join12(dir ?? markerDir(), ownWorkFileName(sessionId));
|
|
24797
25679
|
}
|
|
24798
25680
|
function inputString2(input, key) {
|
|
24799
25681
|
if (typeof input !== "object" || input === null)
|
|
@@ -24811,7 +25693,7 @@ function append(sessionId, line2, dir) {
|
|
|
24811
25693
|
const path = ownWorkPath(sessionId, dir);
|
|
24812
25694
|
if (path === null)
|
|
24813
25695
|
return;
|
|
24814
|
-
|
|
25696
|
+
appendFileSync4(path, `${JSON.stringify(line2)}
|
|
24815
25697
|
`, { mode: 384 });
|
|
24816
25698
|
}
|
|
24817
25699
|
function recordOwnShell(input, at, deps = {}) {
|
|
@@ -24857,7 +25739,7 @@ function readOwnWork(sessionId, dir) {
|
|
|
24857
25739
|
const path = ownWorkPath(sessionId, dir);
|
|
24858
25740
|
if (path === null)
|
|
24859
25741
|
return [];
|
|
24860
|
-
return parseOwnWork(
|
|
25742
|
+
return parseOwnWork(readFileSync16(path, "utf-8"));
|
|
24861
25743
|
} catch {
|
|
24862
25744
|
return [];
|
|
24863
25745
|
}
|
|
@@ -24892,7 +25774,7 @@ function realPathOf(path) {
|
|
|
24892
25774
|
let at = resolve4(path);
|
|
24893
25775
|
for (; ; ) {
|
|
24894
25776
|
try {
|
|
24895
|
-
return
|
|
25777
|
+
return join12(realpathSync6.native(at), ...missing.reverse());
|
|
24896
25778
|
} catch {
|
|
24897
25779
|
const parent = dirname5(at);
|
|
24898
25780
|
if (parent === at)
|
|
@@ -24952,7 +25834,7 @@ function ownChangedFiles(repoRoot, files, sessionId, deps = {}) {
|
|
|
24952
25834
|
};
|
|
24953
25835
|
const root = resolve4(repoRoot);
|
|
24954
25836
|
return files.filter((rel) => {
|
|
24955
|
-
const abs =
|
|
25837
|
+
const abs = join12(root, rel);
|
|
24956
25838
|
if (edited.has(realPathOf(abs)))
|
|
24957
25839
|
return true;
|
|
24958
25840
|
if (windows.length === 0)
|
|
@@ -24966,7 +25848,7 @@ function ownChangedFiles(repoRoot, files, sessionId, deps = {}) {
|
|
|
24966
25848
|
|
|
24967
25849
|
// dist/hooks/findings.js
|
|
24968
25850
|
import { createHash as createHash4, randomUUID as randomUUID2 } from "node:crypto";
|
|
24969
|
-
import { closeSync as
|
|
25851
|
+
import { closeSync as closeSync4, existsSync as existsSync7, openSync as openSync4, readFileSync as readFileSync17, renameSync as renameSync7, statSync as statSync4, unlinkSync as unlinkSync6, writeFileSync as writeFileSync9 } from "node:fs";
|
|
24970
25852
|
function findingKey(firing) {
|
|
24971
25853
|
return createHash4("sha256").update(`${firing.guardId}
|
|
24972
25854
|
${firing.path ?? ""}
|
|
@@ -25009,7 +25891,7 @@ function readFindings(sessionId) {
|
|
|
25009
25891
|
return null;
|
|
25010
25892
|
const session = sessionId;
|
|
25011
25893
|
try {
|
|
25012
|
-
const parsed = JSON.parse(
|
|
25894
|
+
const parsed = JSON.parse(readFileSync17(path, "utf-8"));
|
|
25013
25895
|
if (parsed["version"] !== 1 || !Array.isArray(parsed["findings"]))
|
|
25014
25896
|
return emptyFindings(session);
|
|
25015
25897
|
const findings = [];
|
|
@@ -25029,12 +25911,12 @@ function writeFindings(file2) {
|
|
|
25029
25911
|
return;
|
|
25030
25912
|
const temp = `${path.slice(0, -".json".length)}.${process.pid}.tmp.json`;
|
|
25031
25913
|
try {
|
|
25032
|
-
|
|
25914
|
+
writeFileSync9(temp, `${JSON.stringify(file2)}
|
|
25033
25915
|
`, { mode: 384 });
|
|
25034
|
-
|
|
25916
|
+
renameSync7(temp, path);
|
|
25035
25917
|
} catch {
|
|
25036
25918
|
try {
|
|
25037
|
-
|
|
25919
|
+
unlinkSync6(temp);
|
|
25038
25920
|
} catch {
|
|
25039
25921
|
}
|
|
25040
25922
|
}
|
|
@@ -25050,7 +25932,7 @@ function pause(ms) {
|
|
|
25050
25932
|
function takeOverStaleLock(lock) {
|
|
25051
25933
|
const aside = `${lock}.${process.pid}.${randomUUID2()}.stale`;
|
|
25052
25934
|
try {
|
|
25053
|
-
|
|
25935
|
+
renameSync7(lock, aside);
|
|
25054
25936
|
} catch {
|
|
25055
25937
|
return false;
|
|
25056
25938
|
}
|
|
@@ -25062,17 +25944,17 @@ function takeOverStaleLock(lock) {
|
|
|
25062
25944
|
}
|
|
25063
25945
|
if (!staleIndeed) {
|
|
25064
25946
|
try {
|
|
25065
|
-
|
|
25947
|
+
renameSync7(aside, lock);
|
|
25066
25948
|
} catch {
|
|
25067
25949
|
try {
|
|
25068
|
-
|
|
25950
|
+
unlinkSync6(aside);
|
|
25069
25951
|
} catch {
|
|
25070
25952
|
}
|
|
25071
25953
|
}
|
|
25072
25954
|
return false;
|
|
25073
25955
|
}
|
|
25074
25956
|
try {
|
|
25075
|
-
|
|
25957
|
+
unlinkSync6(aside);
|
|
25076
25958
|
} catch {
|
|
25077
25959
|
}
|
|
25078
25960
|
return true;
|
|
@@ -25085,7 +25967,7 @@ function withFindingsLock(sessionId, body, waitMs = FINDINGS_LOCK_WAIT_MS) {
|
|
|
25085
25967
|
const deadline = Date.now() + waitMs;
|
|
25086
25968
|
for (; ; ) {
|
|
25087
25969
|
try {
|
|
25088
|
-
|
|
25970
|
+
closeSync4(openSync4(lock, "wx", 384));
|
|
25089
25971
|
break;
|
|
25090
25972
|
} catch (err) {
|
|
25091
25973
|
if (err.code !== "EEXIST")
|
|
@@ -25107,31 +25989,31 @@ function withFindingsLock(sessionId, body, waitMs = FINDINGS_LOCK_WAIT_MS) {
|
|
|
25107
25989
|
return body();
|
|
25108
25990
|
} finally {
|
|
25109
25991
|
try {
|
|
25110
|
-
|
|
25992
|
+
unlinkSync6(lock);
|
|
25111
25993
|
} catch {
|
|
25112
25994
|
}
|
|
25113
25995
|
}
|
|
25114
25996
|
}
|
|
25115
|
-
function takeUndelivered(file2,
|
|
25997
|
+
function takeUndelivered(file2, folder2) {
|
|
25116
25998
|
const taken = [];
|
|
25117
25999
|
const findings = file2.findings.map((f) => {
|
|
25118
|
-
if (f.delivered ||
|
|
26000
|
+
if (f.delivered || folder2 !== null && f.folder !== folder2)
|
|
25119
26001
|
return f;
|
|
25120
26002
|
taken.push(f);
|
|
25121
26003
|
return { ...f, delivered: true };
|
|
25122
26004
|
});
|
|
25123
26005
|
return { file: { ...file2, findings }, taken };
|
|
25124
26006
|
}
|
|
25125
|
-
function deliverFindings(sessionId,
|
|
26007
|
+
function deliverFindings(sessionId, folder2) {
|
|
25126
26008
|
const path = findingsPath(sessionId);
|
|
25127
|
-
if (path === null || !
|
|
26009
|
+
if (path === null || !existsSync7(path))
|
|
25128
26010
|
return [];
|
|
25129
26011
|
try {
|
|
25130
26012
|
const taken = withFindingsLock(sessionId, () => {
|
|
25131
26013
|
const before = readFindings(sessionId);
|
|
25132
26014
|
if (before === null)
|
|
25133
26015
|
return [];
|
|
25134
|
-
const { file: file2, taken: given } = takeUndelivered(before,
|
|
26016
|
+
const { file: file2, taken: given } = takeUndelivered(before, folder2);
|
|
25135
26017
|
if (given.length > 0)
|
|
25136
26018
|
writeFindings(file2);
|
|
25137
26019
|
return given;
|
|
@@ -25141,11 +26023,11 @@ function deliverFindings(sessionId, folder) {
|
|
|
25141
26023
|
return [];
|
|
25142
26024
|
}
|
|
25143
26025
|
}
|
|
25144
|
-
function turnEndBookkeeping(file2,
|
|
26026
|
+
function turnEndBookkeeping(file2, folder2, outcome, topLevel, now) {
|
|
25145
26027
|
const recorded = [...file2.findings];
|
|
25146
26028
|
const firing = /* @__PURE__ */ new Map();
|
|
25147
26029
|
const notRun = new Set(outcome.kind === "evaluated" ? outcome.notRun : []);
|
|
25148
|
-
const observed = (f) => f.folder ===
|
|
26030
|
+
const observed = (f) => f.folder === folder2 && !notRun.has(f.patternRef);
|
|
25149
26031
|
if (outcome.kind === "evaluated") {
|
|
25150
26032
|
for (const g of outcome.fired) {
|
|
25151
26033
|
if (g.severity === "block")
|
|
@@ -25161,13 +26043,13 @@ function turnEndBookkeeping(file2, folder, outcome, topLevel, now) {
|
|
|
25161
26043
|
const closes = observed(f) && (outcome.kind === "no-own-changes" || outcome.kind === "evaluated" && !firing.has(f.key));
|
|
25162
26044
|
(closes ? removed : kept).push(f);
|
|
25163
26045
|
}
|
|
25164
|
-
const known = new Set(kept.filter((f) => f.folder ===
|
|
26046
|
+
const known = new Set(kept.filter((f) => f.folder === folder2).map((f) => f.key));
|
|
25165
26047
|
for (const [key, g] of firing) {
|
|
25166
26048
|
if (known.has(key))
|
|
25167
26049
|
continue;
|
|
25168
26050
|
kept.push({
|
|
25169
26051
|
key,
|
|
25170
|
-
folder,
|
|
26052
|
+
folder: folder2,
|
|
25171
26053
|
guardId: g.guardId,
|
|
25172
26054
|
patternRef: g.patternRef,
|
|
25173
26055
|
severity: g.severity,
|
|
@@ -25362,7 +26244,7 @@ function patchHeaderPaths(patch) {
|
|
|
25362
26244
|
}
|
|
25363
26245
|
|
|
25364
26246
|
// dist/hooks/post-tool-use.js
|
|
25365
|
-
import { isAbsolute as isAbsolute3, join as
|
|
26247
|
+
import { isAbsolute as isAbsolute3, join as join13, relative as relative6, resolve as resolve5, sep as sep4 } from "node:path";
|
|
25366
26248
|
var HANDLED_EDIT_TOOLS = /* @__PURE__ */ new Set(["Edit", "Write", "MultiEdit", "NotebookEdit"]);
|
|
25367
26249
|
async function runPostToolUse(readSeat = readSeatConfiguration, profile = AGENT_PROFILES["claude-code"]) {
|
|
25368
26250
|
const reply = hookReply("PostToolUse", profile);
|
|
@@ -25549,7 +26431,7 @@ function insideRepository(path, repoRoot) {
|
|
|
25549
26431
|
const rel = relative6(realPathOf(repoRoot), realPathOf(path));
|
|
25550
26432
|
if (rel === "" || rel === ".." || rel.startsWith(`..${sep4}`) || isAbsolute3(rel))
|
|
25551
26433
|
return null;
|
|
25552
|
-
return
|
|
26434
|
+
return join13(repoRoot, rel);
|
|
25553
26435
|
}
|
|
25554
26436
|
function actOnEnvelope2(envelope, reply) {
|
|
25555
26437
|
const notRun = notRunReport(envelope.notRun);
|
|
@@ -25572,17 +26454,17 @@ ${guardLines}${notRunBlock}`);
|
|
|
25572
26454
|
}
|
|
25573
26455
|
}
|
|
25574
26456
|
function readStdin() {
|
|
25575
|
-
return new Promise((
|
|
26457
|
+
return new Promise((resolve12, reject) => {
|
|
25576
26458
|
const chunks = [];
|
|
25577
26459
|
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
25578
|
-
process.stdin.on("end", () =>
|
|
26460
|
+
process.stdin.on("end", () => resolve12(Buffer.concat(chunks).toString("utf-8")));
|
|
25579
26461
|
process.stdin.on("error", reject);
|
|
25580
26462
|
});
|
|
25581
26463
|
}
|
|
25582
26464
|
|
|
25583
26465
|
// dist/liveness.js
|
|
25584
|
-
import { closeSync as
|
|
25585
|
-
import { join as
|
|
26466
|
+
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";
|
|
26467
|
+
import { join as join14 } from "node:path";
|
|
25586
26468
|
var LIVE_WINDOW_MS = 10 * 60 * 1e3;
|
|
25587
26469
|
function field(input, key) {
|
|
25588
26470
|
if (typeof input !== "object" || input === null)
|
|
@@ -25591,10 +26473,10 @@ function field(input, key) {
|
|
|
25591
26473
|
return typeof v === "string" && v !== "" ? v : null;
|
|
25592
26474
|
}
|
|
25593
26475
|
function indexEntry(dir, sessionId, name) {
|
|
25594
|
-
const
|
|
26476
|
+
const folder2 = join14(dir, livenessIndexDirName(sessionId));
|
|
25595
26477
|
for (let attempt2 = 0; attempt2 < 3; attempt2++) {
|
|
25596
26478
|
try {
|
|
25597
|
-
|
|
26479
|
+
closeSync5(openSync5(join14(folder2, name), "a", 384));
|
|
25598
26480
|
return true;
|
|
25599
26481
|
} catch (err) {
|
|
25600
26482
|
if (err.code !== "ENOENT")
|
|
@@ -25602,13 +26484,13 @@ function indexEntry(dir, sessionId, name) {
|
|
|
25602
26484
|
}
|
|
25603
26485
|
let tmp = null;
|
|
25604
26486
|
try {
|
|
25605
|
-
tmp = mkdtempSync(`${
|
|
26487
|
+
tmp = mkdtempSync(`${folder2}.`);
|
|
25606
26488
|
for (const existing of readdirSync7(dir)) {
|
|
25607
26489
|
if (parseLivenessFileName(existing)?.sessionId === sessionId)
|
|
25608
|
-
|
|
26490
|
+
closeSync5(openSync5(join14(tmp, existing), "a", 384));
|
|
25609
26491
|
}
|
|
25610
|
-
|
|
25611
|
-
|
|
26492
|
+
closeSync5(openSync5(join14(tmp, name), "a", 384));
|
|
26493
|
+
renameSync8(tmp, folder2);
|
|
25612
26494
|
return true;
|
|
25613
26495
|
} catch {
|
|
25614
26496
|
if (tmp !== null)
|
|
@@ -25633,18 +26515,18 @@ function recordLiveness(input, deps = {}) {
|
|
|
25633
26515
|
const name = livenessFileName(livenessKey(copy?.common ?? null), sessionId, agentId);
|
|
25634
26516
|
if (!indexEntry(dir, sessionId, name))
|
|
25635
26517
|
return null;
|
|
25636
|
-
const path =
|
|
26518
|
+
const path = join14(dir, name);
|
|
25637
26519
|
const text = `${cwd}
|
|
25638
26520
|
${copy?.top ?? ""}
|
|
25639
26521
|
`;
|
|
25640
26522
|
try {
|
|
25641
|
-
|
|
26523
|
+
writeFileSync10(path, text, { encoding: "utf-8", flag: "wx", mode: 384 });
|
|
25642
26524
|
return { firstSeen: true };
|
|
25643
26525
|
} catch (err) {
|
|
25644
26526
|
if (err.code !== "EEXIST")
|
|
25645
26527
|
return null;
|
|
25646
26528
|
}
|
|
25647
|
-
|
|
26529
|
+
writeFileSync10(path, text, { encoding: "utf-8", mode: 384 });
|
|
25648
26530
|
return { firstSeen: false };
|
|
25649
26531
|
} catch {
|
|
25650
26532
|
return null;
|
|
@@ -25663,7 +26545,7 @@ function clearLiveness(input, deps = {}) {
|
|
|
25663
26545
|
if (p === null || p.sessionId !== sessionId || p.agentId !== agentId)
|
|
25664
26546
|
continue;
|
|
25665
26547
|
try {
|
|
25666
|
-
|
|
26548
|
+
unlinkSync7(join14(dir, name));
|
|
25667
26549
|
removed += 1;
|
|
25668
26550
|
} catch {
|
|
25669
26551
|
}
|
|
@@ -25676,7 +26558,7 @@ function clearLiveness(input, deps = {}) {
|
|
|
25676
26558
|
}
|
|
25677
26559
|
function topOf(path) {
|
|
25678
26560
|
try {
|
|
25679
|
-
const top =
|
|
26561
|
+
const top = readFileSync18(path, "utf-8").split("\n")[1] ?? "";
|
|
25680
26562
|
return top === "" ? null : top;
|
|
25681
26563
|
} catch {
|
|
25682
26564
|
return null;
|
|
@@ -25698,7 +26580,7 @@ function readLiveness(sessionId, cwd, deps = {}) {
|
|
|
25698
26580
|
const p = parseLivenessFileName(name);
|
|
25699
26581
|
if (p === null || p.key !== key || p.sessionId !== sessionId)
|
|
25700
26582
|
continue;
|
|
25701
|
-
const full =
|
|
26583
|
+
const full = join14(dir, name);
|
|
25702
26584
|
let seenAt;
|
|
25703
26585
|
try {
|
|
25704
26586
|
seenAt = statSync5(full).mtimeMs;
|
|
@@ -25744,168 +26626,8 @@ import nodePath5 from "node:path";
|
|
|
25744
26626
|
|
|
25745
26627
|
// dist/pace-verb.js
|
|
25746
26628
|
import { mkdirSync as mkdirSync7, readdirSync as readdirSync8, readFileSync as readFileSync19, renameSync as renameSync9, statSync as statSync6, writeFileSync as writeFileSync11 } from "node:fs";
|
|
25747
|
-
import { homedir as
|
|
26629
|
+
import { homedir as homedir9 } from "node:os";
|
|
25748
26630
|
import nodePath4 from "node:path";
|
|
25749
|
-
|
|
25750
|
-
// dist/scan-lock.js
|
|
25751
|
-
import { spawn } from "node:child_process";
|
|
25752
|
-
import { linkSync, mkdirSync as mkdirSync6, readFileSync as readFileSync18, renameSync as renameSync8, unlinkSync as unlinkSync7, writeFileSync as writeFileSync10 } from "node:fs";
|
|
25753
|
-
import nodePath3 from "node:path";
|
|
25754
|
-
var SCAN_LOCK_FILENAME = "scan.lock";
|
|
25755
|
-
var SCAN_LOCK_STALE_MS = 15 * 60 * 1e3;
|
|
25756
|
-
var SCAN_LOCK_POLL_MS = 100;
|
|
25757
|
-
function scanLockPath(home) {
|
|
25758
|
-
return nodePath3.join(pacingDir(home), SCAN_LOCK_FILENAME);
|
|
25759
|
-
}
|
|
25760
|
-
function readLockBody(path) {
|
|
25761
|
-
let text;
|
|
25762
|
-
try {
|
|
25763
|
-
text = readFileSync18(path, "utf-8");
|
|
25764
|
-
} catch (err) {
|
|
25765
|
-
return err.code === "ENOENT" ? "missing" : null;
|
|
25766
|
-
}
|
|
25767
|
-
try {
|
|
25768
|
-
const v = JSON.parse(text);
|
|
25769
|
-
return typeof v["pid"] === "number" && typeof v["at"] === "number" ? { pid: v["pid"], at: v["at"] } : null;
|
|
25770
|
-
} catch {
|
|
25771
|
-
return null;
|
|
25772
|
-
}
|
|
25773
|
-
}
|
|
25774
|
-
function processAlive(pid) {
|
|
25775
|
-
if (!Number.isInteger(pid) || pid <= 0)
|
|
25776
|
-
return false;
|
|
25777
|
-
try {
|
|
25778
|
-
process.kill(pid, 0);
|
|
25779
|
-
return true;
|
|
25780
|
-
} catch (err) {
|
|
25781
|
-
return err.code === "EPERM";
|
|
25782
|
-
}
|
|
25783
|
-
}
|
|
25784
|
-
function isStale(body, staleMs, deps) {
|
|
25785
|
-
if (body === null)
|
|
25786
|
-
return true;
|
|
25787
|
-
const now = (deps.clock ?? Date.now)();
|
|
25788
|
-
if (Math.abs(now - body.at) > staleMs)
|
|
25789
|
-
return true;
|
|
25790
|
-
return !(deps.alive ?? processAlive)(body.pid);
|
|
25791
|
-
}
|
|
25792
|
-
function writeLock(path, pid, deps, flag) {
|
|
25793
|
-
writeFileSync10(path, JSON.stringify({ pid, at: (deps.clock ?? Date.now)() }), { flag, mode: 384 });
|
|
25794
|
-
}
|
|
25795
|
-
function tryTakeScanLock(deps = {}) {
|
|
25796
|
-
return tryTakeLockFile(scanLockPath(deps.home), SCAN_LOCK_STALE_MS, deps);
|
|
25797
|
-
}
|
|
25798
|
-
function tryTakeLockFile(path, staleMs, deps = {}) {
|
|
25799
|
-
const pid = deps.pid ?? process.pid;
|
|
25800
|
-
try {
|
|
25801
|
-
mkdirSync6(nodePath3.dirname(path), { recursive: true, mode: 448 });
|
|
25802
|
-
} catch {
|
|
25803
|
-
return false;
|
|
25804
|
-
}
|
|
25805
|
-
for (let attempt2 = 0; attempt2 < 2; attempt2++) {
|
|
25806
|
-
try {
|
|
25807
|
-
writeLock(path, pid, deps, "wx");
|
|
25808
|
-
return true;
|
|
25809
|
-
} catch (err) {
|
|
25810
|
-
if (err.code !== "EEXIST")
|
|
25811
|
-
return false;
|
|
25812
|
-
}
|
|
25813
|
-
const seen = readLockBody(path);
|
|
25814
|
-
if (seen === "missing")
|
|
25815
|
-
continue;
|
|
25816
|
-
if (!isStale(seen, staleMs, deps))
|
|
25817
|
-
return false;
|
|
25818
|
-
const aside = `${path}.${String(pid)}.${String((deps.clock ?? Date.now)())}.stale`;
|
|
25819
|
-
try {
|
|
25820
|
-
renameSync8(path, aside);
|
|
25821
|
-
} catch {
|
|
25822
|
-
continue;
|
|
25823
|
-
}
|
|
25824
|
-
const taken = readLockBody(aside);
|
|
25825
|
-
const same = taken !== "missing" && (seen === null ? taken === null : taken !== null && taken.pid === seen.pid && taken.at === seen.at);
|
|
25826
|
-
if (!same && taken !== "missing" && !isStale(taken, staleMs, deps)) {
|
|
25827
|
-
try {
|
|
25828
|
-
linkSync(aside, path);
|
|
25829
|
-
} catch {
|
|
25830
|
-
}
|
|
25831
|
-
try {
|
|
25832
|
-
unlinkSync7(aside);
|
|
25833
|
-
} catch {
|
|
25834
|
-
}
|
|
25835
|
-
return false;
|
|
25836
|
-
}
|
|
25837
|
-
try {
|
|
25838
|
-
unlinkSync7(aside);
|
|
25839
|
-
} catch {
|
|
25840
|
-
}
|
|
25841
|
-
}
|
|
25842
|
-
return false;
|
|
25843
|
-
}
|
|
25844
|
-
function releaseLockFile(path, pid = process.pid) {
|
|
25845
|
-
const body = readLockBody(path);
|
|
25846
|
-
if (body === "missing" || body === null || body.pid !== pid)
|
|
25847
|
-
return;
|
|
25848
|
-
try {
|
|
25849
|
-
unlinkSync7(path);
|
|
25850
|
-
} catch {
|
|
25851
|
-
}
|
|
25852
|
-
}
|
|
25853
|
-
function releaseScanLock(deps = {}) {
|
|
25854
|
-
releaseLockFile(scanLockPath(deps.home), deps.pid ?? process.pid);
|
|
25855
|
-
}
|
|
25856
|
-
function sleepSync(ms) {
|
|
25857
|
-
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
25858
|
-
}
|
|
25859
|
-
function scanUnderLock(key, deps = {}, waitMs = 0) {
|
|
25860
|
-
const clock = deps.clock ?? Date.now;
|
|
25861
|
-
const giveUpAt = clock() + waitMs;
|
|
25862
|
-
while (!tryTakeScanLock(deps)) {
|
|
25863
|
-
if (clock() >= giveUpAt)
|
|
25864
|
-
return null;
|
|
25865
|
-
sleepSync(SCAN_LOCK_POLL_MS);
|
|
25866
|
-
}
|
|
25867
|
-
try {
|
|
25868
|
-
return scanRecords(key, deps);
|
|
25869
|
-
} finally {
|
|
25870
|
-
releaseScanLock(deps);
|
|
25871
|
-
}
|
|
25872
|
-
}
|
|
25873
|
-
var spawnDetachedReal = (command, args2) => {
|
|
25874
|
-
const child = spawn(command, [...args2], { detached: true, stdio: "ignore", windowsHide: true });
|
|
25875
|
-
child.on("error", () => void 0);
|
|
25876
|
-
child.unref();
|
|
25877
|
-
return child.pid;
|
|
25878
|
-
};
|
|
25879
|
-
function startScanChild(key, binaryPath, deps = {}) {
|
|
25880
|
-
if (!tryTakeScanLock(deps))
|
|
25881
|
-
return false;
|
|
25882
|
-
let childPid;
|
|
25883
|
-
try {
|
|
25884
|
-
childPid = (deps.spawnDetached ?? spawnDetachedReal)(deps.nodePath ?? process.execPath, [
|
|
25885
|
-
binaryPath,
|
|
25886
|
-
"pace",
|
|
25887
|
-
"--scan",
|
|
25888
|
-
"--config-folder",
|
|
25889
|
-
key,
|
|
25890
|
-
"--lock-held"
|
|
25891
|
-
]);
|
|
25892
|
-
} catch {
|
|
25893
|
-
childPid = void 0;
|
|
25894
|
-
}
|
|
25895
|
-
if (childPid === void 0) {
|
|
25896
|
-
releaseScanLock(deps);
|
|
25897
|
-
return false;
|
|
25898
|
-
}
|
|
25899
|
-
try {
|
|
25900
|
-
writeLock(scanLockPath(deps.home), childPid, deps, "w");
|
|
25901
|
-
} catch {
|
|
25902
|
-
releaseScanLock(deps);
|
|
25903
|
-
return false;
|
|
25904
|
-
}
|
|
25905
|
-
return true;
|
|
25906
|
-
}
|
|
25907
|
-
|
|
25908
|
-
// dist/pace-verb.js
|
|
25909
26631
|
var PACE_DEFAULT_TASK_MINUTES = 30;
|
|
25910
26632
|
var PACE_DURATION_ROUND_MINUTES = 10;
|
|
25911
26633
|
var PACE_WINDOW_MINUTES = 300;
|
|
@@ -26027,7 +26749,7 @@ function suggestPace(input) {
|
|
|
26027
26749
|
function enginePacingDir(engagementId, home) {
|
|
26028
26750
|
if (!isEngagementId(engagementId))
|
|
26029
26751
|
return null;
|
|
26030
|
-
return nodePath4.join(home ??
|
|
26752
|
+
return nodePath4.join(home ?? homedir9(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, PACING_DIR_NAME);
|
|
26031
26753
|
}
|
|
26032
26754
|
function readBuildNumber(engagementId, home) {
|
|
26033
26755
|
const dir = enginePacingDir(engagementId, home);
|
|
@@ -26085,7 +26807,7 @@ var USAGE = "Usage: halfcycle-runner pace [--agent claude-code|codex] [--start <
|
|
|
26085
26807
|
function parsePaceArgs(args2) {
|
|
26086
26808
|
let scan = false;
|
|
26087
26809
|
let lockHeld = false;
|
|
26088
|
-
let
|
|
26810
|
+
let folder2 = null;
|
|
26089
26811
|
let phase = null;
|
|
26090
26812
|
let agents = null;
|
|
26091
26813
|
let agent = null;
|
|
@@ -26103,8 +26825,8 @@ function parsePaceArgs(args2) {
|
|
|
26103
26825
|
else if (a === "--lock-held")
|
|
26104
26826
|
lockHeld = true;
|
|
26105
26827
|
else if (a === "--config-folder") {
|
|
26106
|
-
|
|
26107
|
-
if (
|
|
26828
|
+
folder2 = value();
|
|
26829
|
+
if (folder2 === null)
|
|
26108
26830
|
return { kind: "usage", message: USAGE };
|
|
26109
26831
|
} else if (a === "--start") {
|
|
26110
26832
|
phase = value();
|
|
@@ -26125,9 +26847,9 @@ function parsePaceArgs(args2) {
|
|
|
26125
26847
|
if (scan) {
|
|
26126
26848
|
if (phase !== null || agents !== null || agent !== null)
|
|
26127
26849
|
return { kind: "usage", message: USAGE };
|
|
26128
|
-
return { kind: "scan", folder, lockHeld };
|
|
26850
|
+
return { kind: "scan", folder: folder2, lockHeld };
|
|
26129
26851
|
}
|
|
26130
|
-
if (
|
|
26852
|
+
if (folder2 !== null || lockHeld)
|
|
26131
26853
|
return { kind: "usage", message: USAGE };
|
|
26132
26854
|
if (phase === null)
|
|
26133
26855
|
return agents === null ? { kind: "now", agent: agent ?? "claude-code" } : { kind: "usage", message: USAGE };
|
|
@@ -26210,7 +26932,7 @@ async function runPaceVerb(args2, deps = {}) {
|
|
|
26210
26932
|
...deps.home === void 0 ? {} : { home: deps.home },
|
|
26211
26933
|
now: () => now.getTime(),
|
|
26212
26934
|
...deps.fetchFn === void 0 ? {} : { fetchFn: deps.fetchFn }
|
|
26213
|
-
});
|
|
26935
|
+
}, { agent: parsed.agent });
|
|
26214
26936
|
} catch {
|
|
26215
26937
|
}
|
|
26216
26938
|
const remembered = readPaceStateFile(pacingDir2).basis;
|
|
@@ -26298,6 +27020,7 @@ async function runPaceVerb(args2, deps = {}) {
|
|
|
26298
27020
|
...decision.until !== null ? { until: decision.until.toISOString() } : {},
|
|
26299
27021
|
keepFreePercent,
|
|
26300
27022
|
...suggestion !== void 0 ? { suggestion } : {},
|
|
27023
|
+
...limitFile !== null ? { usage: { used: readPhaseUsage(pacingDir2, limitFile.phase), limit: limitFile.limit } } : {},
|
|
26301
27024
|
...atLimit ? {
|
|
26302
27025
|
limit: "reached",
|
|
26303
27026
|
limitHeld: {
|
|
@@ -26445,10 +27168,10 @@ async function paceAtTurnEnd(input, reply, deps = {}) {
|
|
|
26445
27168
|
const basis = read !== null ? { phase: read.phase, keepFreePercent: read.keepFreePercent } : stored.basis;
|
|
26446
27169
|
if (basis === null)
|
|
26447
27170
|
return;
|
|
26448
|
-
const
|
|
27171
|
+
const write2 = deps.writeState ?? writePaceState;
|
|
26449
27172
|
if (basis.phase === null) {
|
|
26450
27173
|
if (before !== null || read !== null)
|
|
26451
|
-
|
|
27174
|
+
write2(dir, key, null, read !== null ? basis : null);
|
|
26452
27175
|
return;
|
|
26453
27176
|
}
|
|
26454
27177
|
const working = liveCount(readLiveness(field2(input, "session_id"), field2(input, "cwd") ?? process.cwd(), deps.liveness));
|
|
@@ -26475,7 +27198,8 @@ async function paceAtTurnEnd(input, reply, deps = {}) {
|
|
|
26475
27198
|
}
|
|
26476
27199
|
}
|
|
26477
27200
|
const reported = readReportedAccount(key, { home: deps.home });
|
|
26478
|
-
const
|
|
27201
|
+
const build = buildNumberFor(engagementId, basis.phase, deps.home);
|
|
27202
|
+
const number4 = build?.number ?? CAREFUL_START_AGENTS;
|
|
26479
27203
|
const decision = paceOf({ number: number4, keepFreePercent: basis.keepFreePercent, learned, reported, now });
|
|
26480
27204
|
const settled2 = {
|
|
26481
27205
|
pace: decision.pace,
|
|
@@ -26489,9 +27213,9 @@ async function paceAtTurnEnd(input, reply, deps = {}) {
|
|
|
26489
27213
|
};
|
|
26490
27214
|
const told = before === null || before.told === void 0 ? before : { ...before, ...before.told };
|
|
26491
27215
|
const text = paceChangeText(told, settled2, working, now, basis.keepFreePercent);
|
|
26492
|
-
const offer = text === null ? offerText(settled2, learned, reported, now, basis.keepFreePercent) : null;
|
|
27216
|
+
const offer = text === null && build !== null ? offerText(settled2, learned, reported, now, basis.keepFreePercent) : null;
|
|
26493
27217
|
const after = offer === null ? settled2 : { ...settled2, offeredFor: offeredForNow(settled2.offeredFor, offer.resetsAt, now) };
|
|
26494
|
-
|
|
27218
|
+
write2(dir, key, after, read !== null ? basis : null);
|
|
26495
27219
|
if (text !== null)
|
|
26496
27220
|
reply.notice(text);
|
|
26497
27221
|
else if (offer !== null)
|
|
@@ -26542,7 +27266,7 @@ function pruneStarts(file2, nowMs) {
|
|
|
26542
27266
|
}
|
|
26543
27267
|
return out;
|
|
26544
27268
|
}
|
|
26545
|
-
function
|
|
27269
|
+
function sleepSync3(ms) {
|
|
26546
27270
|
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
26547
27271
|
}
|
|
26548
27272
|
function underStartsLock(dir, giveUpMs, fn) {
|
|
@@ -26551,7 +27275,7 @@ function underStartsLock(dir, giveUpMs, fn) {
|
|
|
26551
27275
|
while (!tryTakeLockFile(lock, PACE_STARTS_LOCK_STALE_MS)) {
|
|
26552
27276
|
if (Date.now() >= giveUpAt)
|
|
26553
27277
|
return void 0;
|
|
26554
|
-
|
|
27278
|
+
sleepSync3(STARTS_LOCK_POLL_MS);
|
|
26555
27279
|
}
|
|
26556
27280
|
try {
|
|
26557
27281
|
return fn();
|
|
@@ -26646,9 +27370,9 @@ function paceHoldText(input, toolInput, deps = {}) {
|
|
|
26646
27370
|
}
|
|
26647
27371
|
|
|
26648
27372
|
// dist/risky/facts.js
|
|
26649
|
-
import { existsSync as
|
|
26650
|
-
import { homedir as
|
|
26651
|
-
import { basename as pathBasename, dirname as dirname6, isAbsolute as isAbsolute4, join as
|
|
27373
|
+
import { existsSync as existsSync8, lstatSync as lstatSync3, readdirSync as readdirSync9, readFileSync as readFileSync21, realpathSync as realpathSync7, statSync as statSync7 } from "node:fs";
|
|
27374
|
+
import { homedir as homedir10, tmpdir as tmpdir2 } from "node:os";
|
|
27375
|
+
import { basename as pathBasename, dirname as dirname6, isAbsolute as isAbsolute4, join as join15, relative as relative7, resolve as resolve6, sep as sep5 } from "node:path";
|
|
26652
27376
|
|
|
26653
27377
|
// dist/risky/shell.js
|
|
26654
27378
|
var MAX_DEPTH = 8;
|
|
@@ -27828,7 +28552,7 @@ function readLine(commands, vars, gitEnv, savedTrusted) {
|
|
|
27828
28552
|
}
|
|
27829
28553
|
vars.enter(own);
|
|
27830
28554
|
const simple = expandCommand(raw, vars);
|
|
27831
|
-
const
|
|
28555
|
+
const folder2 = folderIn(simple);
|
|
27832
28556
|
for (const m of recogniseSimple(simple)) {
|
|
27833
28557
|
const trusted = m.type === "shrink-record" && m.change.kind === "saved" && !savedTrusted ? { ...m, change: { kind: "emptied" } } : m;
|
|
27834
28558
|
let shown2 = trusted;
|
|
@@ -27844,7 +28568,7 @@ function readLine(commands, vars, gitEnv, savedTrusted) {
|
|
|
27844
28568
|
}
|
|
27845
28569
|
matches.push({
|
|
27846
28570
|
...shown2,
|
|
27847
|
-
...
|
|
28571
|
+
...folder2 === void 0 ? {} : { folder: folder2 },
|
|
27848
28572
|
...made.size === 0 ? {} : { made: new Map(made) },
|
|
27849
28573
|
...madeInChain.size === 0 ? {} : { madeInChain: new Set(madeInChain) },
|
|
27850
28574
|
...removedInChain.size === 0 ? {} : { removedInChain: new Set(removedInChain) },
|
|
@@ -27852,9 +28576,9 @@ function readLine(commands, vars, gitEnv, savedTrusted) {
|
|
|
27852
28576
|
...vars.stoppedIf.length === 0 ? {} : { stoppedIf: [...vars.stoppedIf] }
|
|
27853
28577
|
});
|
|
27854
28578
|
}
|
|
27855
|
-
if (surelyRuns(simple, own) && (
|
|
28579
|
+
if (surelyRuns(simple, own) && (folder2 === void 0 || folder2.known)) {
|
|
27856
28580
|
for (const p of pathsMade(simple)) {
|
|
27857
|
-
const key = madeKey(
|
|
28581
|
+
const key = madeKey(folder2?.dirs ?? [], p.word);
|
|
27858
28582
|
made.set(key, p.by);
|
|
27859
28583
|
if (simple.next === "&&")
|
|
27860
28584
|
madeInChain.add(key);
|
|
@@ -27862,12 +28586,12 @@ function readLine(commands, vars, gitEnv, savedTrusted) {
|
|
|
27862
28586
|
if (simple.next === "&&" && simple.words[0]?.text === "rmdir") {
|
|
27863
28587
|
for (const w of simple.words.slice(1))
|
|
27864
28588
|
if (w.literal && !w.text.startsWith("-"))
|
|
27865
|
-
removedInChain.add(madeKey(
|
|
28589
|
+
removedInChain.add(madeKey(folder2?.dirs ?? [], w));
|
|
27866
28590
|
}
|
|
27867
28591
|
}
|
|
27868
28592
|
const nextCmd = commands[i + 1];
|
|
27869
28593
|
const asJoined = simple.next !== void 0 && (nextCmd === void 0 || scopeKey(nextCmd) !== scopeKey(simple)) ? { ...simple, next: void 0 } : simple;
|
|
27870
|
-
const after = folderAfter(
|
|
28594
|
+
const after = folderAfter(folder2, asJoined, own);
|
|
27871
28595
|
folders.set(scopeKey(simple), after);
|
|
27872
28596
|
vars.guard = chainCds === null ? null : [...chainCds];
|
|
27873
28597
|
vars.update(raw, own);
|
|
@@ -28860,7 +29584,7 @@ var Env = class {
|
|
|
28860
29584
|
constructor(ctx) {
|
|
28861
29585
|
this.projectDir = realOrSelf(resolve6(ctx.projectDir));
|
|
28862
29586
|
this.cwd = realOrSelf(resolve6(this.projectDir, ctx.cwd));
|
|
28863
|
-
this.home = realOrSelf(resolve6(ctx.home ??
|
|
29587
|
+
this.home = realOrSelf(resolve6(ctx.home ?? homedir10()));
|
|
28864
29588
|
this.timeoutMs = ctx.gitTimeoutMs ?? FACTS_GIT_TIMEOUT_MS;
|
|
28865
29589
|
this.tempDir = realOrSelf(resolve6(ctx.tempDir ?? tmpdir2()));
|
|
28866
29590
|
const roots = ctx.tempRoots ?? [this.tempDir, tmpdir2(), ...TEMP_ROOTS];
|
|
@@ -28884,7 +29608,7 @@ var Env = class {
|
|
|
28884
29608
|
return this.description;
|
|
28885
29609
|
this.description = null;
|
|
28886
29610
|
try {
|
|
28887
|
-
const raw = JSON.parse(readFileSync21(
|
|
29611
|
+
const raw = JSON.parse(readFileSync21(join15(repoRoot, SYSTEM_DESCRIPTION_REL), "utf-8"));
|
|
28888
29612
|
const checked = checkSystemDescription(raw);
|
|
28889
29613
|
if (checked.ok)
|
|
28890
29614
|
this.description = checked.description;
|
|
@@ -28948,18 +29672,18 @@ function resolveHome(text, home, base) {
|
|
|
28948
29672
|
if (text === "~")
|
|
28949
29673
|
return home;
|
|
28950
29674
|
if (text.startsWith("~/"))
|
|
28951
|
-
return
|
|
29675
|
+
return join15(home, text.slice(2));
|
|
28952
29676
|
return resolve6(base, text);
|
|
28953
29677
|
}
|
|
28954
29678
|
function realTarget(abs) {
|
|
28955
29679
|
const parent = dirname6(abs);
|
|
28956
29680
|
if (parent === abs)
|
|
28957
29681
|
return abs;
|
|
28958
|
-
return
|
|
29682
|
+
return join15(realOrSelf(parent), pathBasename(abs));
|
|
28959
29683
|
}
|
|
28960
29684
|
function wordPath(word, base, env) {
|
|
28961
29685
|
if (word.temp !== void 0) {
|
|
28962
|
-
const root = word.temp.base === "mktemp" ?
|
|
29686
|
+
const root = word.temp.base === "mktemp" ? join15(env.tempDir, ".halfcycle-mktemp-new") : env.tempDir;
|
|
28963
29687
|
return resolve6(`${root}${word.temp.suffix}`);
|
|
28964
29688
|
}
|
|
28965
29689
|
return word.literal ? resolveHome(word.text, env.home, base) : null;
|
|
@@ -29105,7 +29829,7 @@ function globPath(abs) {
|
|
|
29105
29829
|
const next = [];
|
|
29106
29830
|
if (!/[*?[]/.test(segment)) {
|
|
29107
29831
|
for (const c of current)
|
|
29108
|
-
next.push(
|
|
29832
|
+
next.push(join15(c, segment));
|
|
29109
29833
|
} else {
|
|
29110
29834
|
const re = segmentPattern(segment);
|
|
29111
29835
|
for (const c of current) {
|
|
@@ -29119,7 +29843,7 @@ function globPath(abs) {
|
|
|
29119
29843
|
if (n.startsWith(".") && !segment.startsWith("."))
|
|
29120
29844
|
continue;
|
|
29121
29845
|
if (re.test(n))
|
|
29122
|
-
next.push(
|
|
29846
|
+
next.push(join15(c, n));
|
|
29123
29847
|
}
|
|
29124
29848
|
}
|
|
29125
29849
|
}
|
|
@@ -29247,7 +29971,7 @@ function findKeeps(filter, roots, repoRoot) {
|
|
|
29247
29971
|
const names = filter.names.map((n) => findPattern(n.pattern, n.fold, false));
|
|
29248
29972
|
const excluded = filter.excluded.map((p) => findPattern(p, false, true));
|
|
29249
29973
|
const steps = (rel) => {
|
|
29250
|
-
const abs =
|
|
29974
|
+
const abs = join15(repoRoot, rel);
|
|
29251
29975
|
const out = [];
|
|
29252
29976
|
for (const r of roots) {
|
|
29253
29977
|
if (!isInside(abs, r.abs))
|
|
@@ -29304,11 +30028,11 @@ function walkRoots(ignoredFolders, specs) {
|
|
|
29304
30028
|
const under2 = (child, parent) => parent === "." || child === parent || child.startsWith(`${parent}/`);
|
|
29305
30029
|
const roots = /* @__PURE__ */ new Set();
|
|
29306
30030
|
for (const raw of ignoredFolders) {
|
|
29307
|
-
const
|
|
30031
|
+
const folder2 = raw.replace(/\/+$/, "");
|
|
29308
30032
|
for (const spec of specs) {
|
|
29309
|
-
if (under2(
|
|
29310
|
-
roots.add(
|
|
29311
|
-
else if (under2(spec,
|
|
30033
|
+
if (under2(folder2, spec))
|
|
30034
|
+
roots.add(folder2);
|
|
30035
|
+
else if (under2(spec, folder2))
|
|
29312
30036
|
roots.add(spec);
|
|
29313
30037
|
}
|
|
29314
30038
|
}
|
|
@@ -29319,9 +30043,9 @@ function credentialFilesIn(folders, repoRoot, deadline, skip) {
|
|
|
29319
30043
|
const out = [];
|
|
29320
30044
|
const stack = [];
|
|
29321
30045
|
for (const f of folders) {
|
|
29322
|
-
if (isDirectory(
|
|
30046
|
+
if (isDirectory(join15(repoRoot, f)))
|
|
29323
30047
|
stack.push(f);
|
|
29324
|
-
else if (pathExists(
|
|
30048
|
+
else if (pathExists(join15(repoRoot, f)) && isCredentialPath(f))
|
|
29325
30049
|
out.push(f);
|
|
29326
30050
|
}
|
|
29327
30051
|
let seen = 0;
|
|
@@ -29329,7 +30053,7 @@ function credentialFilesIn(folders, repoRoot, deadline, skip) {
|
|
|
29329
30053
|
const rel = stack.pop();
|
|
29330
30054
|
let entries;
|
|
29331
30055
|
try {
|
|
29332
|
-
entries = readdirSync9(
|
|
30056
|
+
entries = readdirSync9(join15(repoRoot, rel), { withFileTypes: true });
|
|
29333
30057
|
} catch {
|
|
29334
30058
|
continue;
|
|
29335
30059
|
}
|
|
@@ -29487,7 +30211,7 @@ function closeFoldsAll(targets, env) {
|
|
|
29487
30211
|
return false;
|
|
29488
30212
|
let at = root;
|
|
29489
30213
|
for (const seg of rel.split("/")) {
|
|
29490
|
-
at =
|
|
30214
|
+
at = join15(at, seg);
|
|
29491
30215
|
try {
|
|
29492
30216
|
if (lstatSync3(at).isSymbolicLink())
|
|
29493
30217
|
return false;
|
|
@@ -29720,7 +30444,7 @@ function worktreeFiles(m, where, env) {
|
|
|
29720
30444
|
if (path === null)
|
|
29721
30445
|
return null;
|
|
29722
30446
|
const abs = realOrSelf(path);
|
|
29723
|
-
if (!
|
|
30447
|
+
if (!existsSync8(abs))
|
|
29724
30448
|
return [];
|
|
29725
30449
|
const top = env.repoRoot(abs);
|
|
29726
30450
|
if (top === null)
|
|
@@ -30070,7 +30794,7 @@ function publishFacts(m, env) {
|
|
|
30070
30794
|
const start = startFolder(m, env);
|
|
30071
30795
|
if (start !== null && PACKAGE_JSON_PROGRAMS.has(m.program)) {
|
|
30072
30796
|
try {
|
|
30073
|
-
const pkg = JSON.parse(readFileSync21(
|
|
30797
|
+
const pkg = JSON.parse(readFileSync21(join15(start, "package.json"), "utf-8"));
|
|
30074
30798
|
if (typeof pkg["name"] === "string" && typeof pkg["version"] === "string" && pkg["name"] !== "" && pkg["version"] !== "") {
|
|
30075
30799
|
name = pkg["name"];
|
|
30076
30800
|
version2 = pkg["version"];
|
|
@@ -30189,17 +30913,17 @@ function recordFileAt(abs, env) {
|
|
|
30189
30913
|
const row = recordPatternFor(rel);
|
|
30190
30914
|
return row !== void 0 && row.shrinkAsked !== false ? { abs, root, rel } : null;
|
|
30191
30915
|
}
|
|
30192
|
-
function recordFilesUnder(
|
|
30193
|
-
const root = recordRoot(
|
|
30916
|
+
function recordFilesUnder(folder2, env) {
|
|
30917
|
+
const root = recordRoot(folder2, env);
|
|
30194
30918
|
if (root === null)
|
|
30195
30919
|
return [];
|
|
30196
|
-
const relFolder = toSlash(relative7(root,
|
|
30920
|
+
const relFolder = toSlash(relative7(root, folder2));
|
|
30197
30921
|
const starts = /* @__PURE__ */ new Set();
|
|
30198
30922
|
for (const { pattern } of PROJECT_RECORD_PATTERNS) {
|
|
30199
30923
|
if (relFolder === "" || patternOwns(relFolder, pattern))
|
|
30200
|
-
starts.add(
|
|
30924
|
+
starts.add(join15(root, pattern));
|
|
30201
30925
|
else if (patternOwns(pattern, relFolder))
|
|
30202
|
-
starts.add(
|
|
30926
|
+
starts.add(folder2);
|
|
30203
30927
|
}
|
|
30204
30928
|
const out = [];
|
|
30205
30929
|
const stack = [...starts];
|
|
@@ -30223,7 +30947,7 @@ function recordFilesUnder(folder, env) {
|
|
|
30223
30947
|
continue;
|
|
30224
30948
|
}
|
|
30225
30949
|
for (const n of names)
|
|
30226
|
-
stack.push(
|
|
30950
|
+
stack.push(join15(p, n));
|
|
30227
30951
|
} else if (st.isFile()) {
|
|
30228
30952
|
const r = recordFileAt(p, env);
|
|
30229
30953
|
if (r !== null)
|
|
@@ -30306,7 +31030,11 @@ var PERSON_HOLD_LINE = "Halfcycle paused a risky step before it ran. Nothing cha
|
|
|
30306
31030
|
var HELD_STEP_OPENER = "The step was: ";
|
|
30307
31031
|
var PRECAUTION_OPENER = "It was stopped as a precaution: ";
|
|
30308
31032
|
var ALLOW_REPLY = "allow";
|
|
30309
|
-
|
|
31033
|
+
function holdAgentInstruction(stepNumber) {
|
|
31034
|
+
const reply = stepNumber === null ? ALLOW_REPLY : `${ALLOW_REPLY} ${String(stepNumber)}`;
|
|
31035
|
+
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.`;
|
|
31036
|
+
}
|
|
31037
|
+
var HOLD_AGENT_INSTRUCTION = holdAgentInstruction(null);
|
|
30310
31038
|
var NOTHING_LOST_ON_NO = "Nothing is lost if you say no.";
|
|
30311
31039
|
var IF_YES = "If you say yes, ";
|
|
30312
31040
|
var DESCRIBED_TOOLS = /* @__PURE__ */ new Set(["Bash", "Agent"]);
|
|
@@ -30342,6 +31070,9 @@ function questionFor(facts, description) {
|
|
|
30342
31070
|
const shown2 = staked.slice(0, MAX_LISTED).map((f) => `${whatOf(f)} ${IF_YES}${lostOf(f)}`);
|
|
30343
31071
|
return `${PAUSED_OPENER.trimEnd().slice(0, -1)}. ${shown2.join(" ")}${moreLine(staked.length - shown2.length)} ${reason} ${NOTHING_LOST_ON_NO}`;
|
|
30344
31072
|
}
|
|
31073
|
+
function heldAgentText(held, stepNumber) {
|
|
31074
|
+
return `${held.facts} ${holdAgentInstruction(stepNumber)}`;
|
|
31075
|
+
}
|
|
30345
31076
|
function refusalFor(facts, description) {
|
|
30346
31077
|
const staked = orderedStaked(facts);
|
|
30347
31078
|
if (staked.length === 0)
|
|
@@ -30352,9 +31083,11 @@ function refusalFor(facts, description) {
|
|
|
30352
31083
|
return heldStep(steps, description, shown2.map(whyOf).join("; "));
|
|
30353
31084
|
}
|
|
30354
31085
|
function heldStep(steps, description, why) {
|
|
31086
|
+
const facts = `${HELD_STEP_OPENER}${steps}. ${reasonSentence(description)} ${PRECAUTION_OPENER}${why}.`;
|
|
30355
31087
|
return {
|
|
30356
31088
|
person: PERSON_HOLD_LINE,
|
|
30357
|
-
agent: `${
|
|
31089
|
+
agent: `${facts} ${HOLD_AGENT_INSTRUCTION}`,
|
|
31090
|
+
facts,
|
|
30358
31091
|
step: steps
|
|
30359
31092
|
};
|
|
30360
31093
|
}
|
|
@@ -30769,14 +31502,85 @@ function isOneCall(call) {
|
|
|
30769
31502
|
|
|
30770
31503
|
// dist/risky/allow-once.js
|
|
30771
31504
|
import { createHash as createHash5 } from "node:crypto";
|
|
30772
|
-
import { appendFileSync as
|
|
31505
|
+
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";
|
|
31506
|
+
import { isAbsolute as isAbsolute5, relative as relative8, resolve as resolve7, sep as sep6 } from "node:path";
|
|
30773
31507
|
var ALLOW_ONCE_MS = 5 * 60 * 1e3;
|
|
30774
31508
|
var HELD_STEP_MAX_AGE_MS = 60 * 60 * 1e3;
|
|
31509
|
+
var NUMBERS_WAIT_MS = 50;
|
|
31510
|
+
var NUMBERS_LOCK_STALE_MS = 5e3;
|
|
31511
|
+
var NUMBERS_LOCK_POLL_MS = 2;
|
|
31512
|
+
var COPY_GIT_TIMEOUT_MS = 3e3;
|
|
31513
|
+
var ALLOW_NUMBER = new RegExp(`^${ALLOW_REPLY}(?: +([0-9]{1,4}))?$`);
|
|
30775
31514
|
var STEP_MAX_LENGTH = 1e3;
|
|
30776
|
-
function
|
|
30777
|
-
|
|
31515
|
+
function allowReplyOf(prompt) {
|
|
31516
|
+
if (typeof prompt !== "string")
|
|
31517
|
+
return null;
|
|
31518
|
+
const m = ALLOW_NUMBER.exec(prompt.trim().toLowerCase());
|
|
31519
|
+
if (m === null)
|
|
31520
|
+
return null;
|
|
31521
|
+
return { number: m[1] === void 0 ? null : Number(m[1]) };
|
|
31522
|
+
}
|
|
31523
|
+
var FOLDER_WORD = String.raw`(?:([^\s'"$\x60\\~*?\[{()<>|&;\-][^\s'"$\x60\\~*?\[{()<>|&;]*)|'([^'"$\x60\\\-][^'"$\x60\\]*)'|"([^'"$\x60\\\-][^'"$\x60\\]*)")`;
|
|
31524
|
+
var CD_PREFIX = new RegExp(String.raw`^\s*cd[ \t]+${FOLDER_WORD}[ \t]*(?:&&|;)`);
|
|
31525
|
+
var GIT_C_PREFIX = new RegExp(String.raw`^\s*git[ \t]+-C[ \t]+${FOLDER_WORD}[ \t]+`);
|
|
31526
|
+
function folderPrefixOf(command) {
|
|
31527
|
+
const cd = CD_PREFIX.exec(command);
|
|
31528
|
+
if (cd !== null) {
|
|
31529
|
+
const rest = command.slice(cd[0].length).replace(/^\s+/, "");
|
|
31530
|
+
const commands = commandsOf(rest);
|
|
31531
|
+
if (commands === null || commands.some((c) => FOLDER_CHANGERS.has(c.words[0]?.text ?? "")))
|
|
31532
|
+
return null;
|
|
31533
|
+
return { folder: folderOf(cd), command: rest };
|
|
31534
|
+
}
|
|
31535
|
+
const gitC = GIT_C_PREFIX.exec(command);
|
|
31536
|
+
if (gitC !== null) {
|
|
31537
|
+
const compared = `git ${command.slice(gitC[0].length)}`;
|
|
31538
|
+
const commands = commandsOf(compared);
|
|
31539
|
+
if (commands === null || commands.filter((c) => c.scope === void 0).length !== 1)
|
|
31540
|
+
return null;
|
|
31541
|
+
return { folder: folderOf(gitC), command: compared };
|
|
31542
|
+
}
|
|
31543
|
+
return null;
|
|
30778
31544
|
}
|
|
30779
|
-
function
|
|
31545
|
+
function commandsOf(text) {
|
|
31546
|
+
try {
|
|
31547
|
+
return splitCommand(text);
|
|
31548
|
+
} catch {
|
|
31549
|
+
return null;
|
|
31550
|
+
}
|
|
31551
|
+
}
|
|
31552
|
+
function folderOf(m) {
|
|
31553
|
+
return m[1] ?? m[2] ?? m[3] ?? "";
|
|
31554
|
+
}
|
|
31555
|
+
function actingFolderOf(toolName, cwd, rest) {
|
|
31556
|
+
const command = rest["command"];
|
|
31557
|
+
if (toolName !== "Bash" || typeof command !== "string")
|
|
31558
|
+
return cwd;
|
|
31559
|
+
const prefix = folderPrefixOf(command);
|
|
31560
|
+
if (prefix === null)
|
|
31561
|
+
return cwd;
|
|
31562
|
+
if (!isAbsolute5(prefix.folder) && !isAbsolute5(cwd))
|
|
31563
|
+
return cwd;
|
|
31564
|
+
const named = isAbsolute5(prefix.folder) ? prefix.folder : resolve7(cwd, prefix.folder);
|
|
31565
|
+
if (!isFolder2(named))
|
|
31566
|
+
return cwd;
|
|
31567
|
+
rest["command"] = prefix.command;
|
|
31568
|
+
return named;
|
|
31569
|
+
}
|
|
31570
|
+
function copyOf(folder2, timeoutMs) {
|
|
31571
|
+
if (folder2 === "")
|
|
31572
|
+
return { top: "", within: "" };
|
|
31573
|
+
const real = realOrSelf2(folder2);
|
|
31574
|
+
let top = real;
|
|
31575
|
+
if (isFolder2(real)) {
|
|
31576
|
+
const r = readGitForFacts(["rev-parse", "--show-toplevel"], real, timeoutMs);
|
|
31577
|
+
if (r.ok && r.value.trim() !== "")
|
|
31578
|
+
top = realOrSelf2(r.value.trim());
|
|
31579
|
+
}
|
|
31580
|
+
const within2 = relative8(top, real).split(sep6).join("/");
|
|
31581
|
+
return { top, within: within2 };
|
|
31582
|
+
}
|
|
31583
|
+
function stepKey(input, staked, deps = {}) {
|
|
30780
31584
|
const toolName = input["tool_name"];
|
|
30781
31585
|
const toolInput = input["tool_input"];
|
|
30782
31586
|
if (typeof toolName !== "string" || toolName === "")
|
|
@@ -30787,7 +31591,17 @@ function stepKey(input, staked) {
|
|
|
30787
31591
|
if (DESCRIBED_TOOLS.has(toolName))
|
|
30788
31592
|
delete rest["description"];
|
|
30789
31593
|
const cwd = typeof input["cwd"] === "string" ? input["cwd"] : "";
|
|
30790
|
-
|
|
31594
|
+
const acting = actingFolderOf(toolName, cwd, rest);
|
|
31595
|
+
const { top, within: within2 } = copyOf(acting, deps.gitTimeoutMs ?? COPY_GIT_TIMEOUT_MS);
|
|
31596
|
+
const facts = staked.map(withoutMatch);
|
|
31597
|
+
return createHash5("sha256").update(canonical([toolName, top, within2, rest, facts])).digest("hex");
|
|
31598
|
+
}
|
|
31599
|
+
function withoutMatch(fact) {
|
|
31600
|
+
if (typeof fact !== "object" || fact === null || Array.isArray(fact))
|
|
31601
|
+
return fact;
|
|
31602
|
+
const { match: _match, ...others } = fact;
|
|
31603
|
+
void _match;
|
|
31604
|
+
return others;
|
|
30791
31605
|
}
|
|
30792
31606
|
function canonical(value) {
|
|
30793
31607
|
if (Array.isArray(value))
|
|
@@ -30798,37 +31612,166 @@ function canonical(value) {
|
|
|
30798
31612
|
}
|
|
30799
31613
|
return JSON.stringify(value) ?? "null";
|
|
30800
31614
|
}
|
|
30801
|
-
function
|
|
31615
|
+
function isFolder2(path) {
|
|
31616
|
+
try {
|
|
31617
|
+
return statSync8(path).isDirectory();
|
|
31618
|
+
} catch {
|
|
31619
|
+
return false;
|
|
31620
|
+
}
|
|
31621
|
+
}
|
|
31622
|
+
function realOrSelf2(path) {
|
|
31623
|
+
try {
|
|
31624
|
+
return realpathSync8(path);
|
|
31625
|
+
} catch {
|
|
31626
|
+
return path;
|
|
31627
|
+
}
|
|
31628
|
+
}
|
|
31629
|
+
function numberStep(sessionId, key, deps = {}) {
|
|
31630
|
+
const paths = allowOncePaths(sessionId, deps.dir);
|
|
31631
|
+
if (paths === null)
|
|
31632
|
+
return null;
|
|
31633
|
+
const lock = `${paths.numbers}${STEP_NUMBERS_LOCK_SUFFIX}`;
|
|
31634
|
+
const giveUpAt = Date.now() + NUMBERS_WAIT_MS;
|
|
31635
|
+
while (!tryTakeLockFile(lock, NUMBERS_LOCK_STALE_MS)) {
|
|
31636
|
+
if (Date.now() >= giveUpAt)
|
|
31637
|
+
return null;
|
|
31638
|
+
sleepSync4(NUMBERS_LOCK_POLL_MS);
|
|
31639
|
+
}
|
|
31640
|
+
try {
|
|
31641
|
+
const numbers = readNumbers(paths.numbers);
|
|
31642
|
+
if (numbers === null)
|
|
31643
|
+
return null;
|
|
31644
|
+
const kept = numbers.steps.get(key);
|
|
31645
|
+
if (kept !== void 0)
|
|
31646
|
+
return kept;
|
|
31647
|
+
const n = numbers.next;
|
|
31648
|
+
const steps = new Map(numbers.steps).set(key, n);
|
|
31649
|
+
return writeNumbers(paths.numbers, { next: n + 1, steps }) ? n : null;
|
|
31650
|
+
} catch {
|
|
31651
|
+
return null;
|
|
31652
|
+
} finally {
|
|
31653
|
+
releaseLockFile(lock);
|
|
31654
|
+
}
|
|
31655
|
+
}
|
|
31656
|
+
function numberKept(path, key) {
|
|
31657
|
+
try {
|
|
31658
|
+
return readNumbers(path)?.steps.get(key) ?? null;
|
|
31659
|
+
} catch {
|
|
31660
|
+
return null;
|
|
31661
|
+
}
|
|
31662
|
+
}
|
|
31663
|
+
function readNumbers(path) {
|
|
31664
|
+
let text;
|
|
31665
|
+
try {
|
|
31666
|
+
text = readFileSync22(path, "utf8");
|
|
31667
|
+
} catch (err) {
|
|
31668
|
+
return err.code === "ENOENT" ? { next: 1, steps: /* @__PURE__ */ new Map() } : null;
|
|
31669
|
+
}
|
|
31670
|
+
let parsed;
|
|
31671
|
+
try {
|
|
31672
|
+
parsed = JSON.parse(text);
|
|
31673
|
+
} catch {
|
|
31674
|
+
return null;
|
|
31675
|
+
}
|
|
31676
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
31677
|
+
return null;
|
|
31678
|
+
const o = parsed;
|
|
31679
|
+
const next = o["next"];
|
|
31680
|
+
const steps = o["steps"];
|
|
31681
|
+
if (!isWholeNumber2(next) || typeof steps !== "object" || steps === null || Array.isArray(steps))
|
|
31682
|
+
return null;
|
|
31683
|
+
const out = /* @__PURE__ */ new Map();
|
|
31684
|
+
for (const [k, v] of Object.entries(steps)) {
|
|
31685
|
+
if (!/^[0-9a-f]{64}$/.test(k) || !isWholeNumber2(v) || v >= next)
|
|
31686
|
+
return null;
|
|
31687
|
+
out.set(k, v);
|
|
31688
|
+
}
|
|
31689
|
+
return { next, steps: out };
|
|
31690
|
+
}
|
|
31691
|
+
function writeNumbers(path, numbers) {
|
|
31692
|
+
const body = JSON.stringify({ next: numbers.next, steps: Object.fromEntries(numbers.steps) });
|
|
31693
|
+
return writeWhole2(path, body);
|
|
31694
|
+
}
|
|
31695
|
+
function isWholeNumber2(v) {
|
|
31696
|
+
return typeof v === "number" && Number.isSafeInteger(v) && v >= 1;
|
|
31697
|
+
}
|
|
31698
|
+
function sleepSync4(ms) {
|
|
31699
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
31700
|
+
}
|
|
31701
|
+
function recordHeld(sessionId, key, deps = {}, step = null, stepNumber = null) {
|
|
30802
31702
|
const paths = allowOncePaths(sessionId, deps.dir);
|
|
30803
31703
|
if (paths === null)
|
|
30804
31704
|
return;
|
|
30805
|
-
const record2 = {
|
|
31705
|
+
const record2 = {
|
|
31706
|
+
version: 1,
|
|
31707
|
+
session: sessionId,
|
|
31708
|
+
key,
|
|
31709
|
+
at: nowOf(deps),
|
|
31710
|
+
...isStep(step) ? { step } : {},
|
|
31711
|
+
...isWholeNumber2(stepNumber) ? { number: stepNumber } : {}
|
|
31712
|
+
};
|
|
30806
31713
|
try {
|
|
30807
|
-
|
|
31714
|
+
appendFileSync5(paths.held, `${JSON.stringify(record2)}
|
|
30808
31715
|
`, { mode: 384 });
|
|
30809
31716
|
} catch {
|
|
30810
31717
|
return;
|
|
30811
31718
|
}
|
|
30812
31719
|
}
|
|
30813
|
-
function armAllowStep(sessionId, deps = {}) {
|
|
31720
|
+
function armAllowStep(sessionId, deps = {}, stepNumber = null) {
|
|
31721
|
+
const none = (outcome) => ({ outcome, step: null, paused: [] });
|
|
30814
31722
|
try {
|
|
30815
31723
|
const paths = allowOncePaths(sessionId, deps.dir);
|
|
30816
31724
|
if (paths === null)
|
|
30817
|
-
return
|
|
31725
|
+
return none(stepNumber === null ? "nothing-held" : "not-paused");
|
|
31726
|
+
const session = sessionId;
|
|
30818
31727
|
const now = nowOf(deps);
|
|
30819
|
-
const held = claimHeld(paths.held,
|
|
30820
|
-
const
|
|
30821
|
-
|
|
30822
|
-
|
|
30823
|
-
|
|
30824
|
-
|
|
30825
|
-
|
|
30826
|
-
|
|
30827
|
-
|
|
31728
|
+
const held = claimHeld(paths.held, session, now);
|
|
31729
|
+
const steps = distinctSteps(held, paths.numbers);
|
|
31730
|
+
const arm = (key, step) => {
|
|
31731
|
+
const saved = writeRecord(paths.allow, { version: 1, session, key, at: now });
|
|
31732
|
+
if (!saved) {
|
|
31733
|
+
writeBack(paths.held, held);
|
|
31734
|
+
return none("not-saved");
|
|
31735
|
+
}
|
|
31736
|
+
writeBack(paths.held, held.filter((r) => r.key !== key));
|
|
31737
|
+
return { outcome: "armed", step, paused: [] };
|
|
31738
|
+
};
|
|
31739
|
+
if (stepNumber !== null) {
|
|
31740
|
+
const named = steps.find((s) => s.number === stepNumber);
|
|
31741
|
+
if (named === void 0) {
|
|
31742
|
+
writeBack(paths.held, held);
|
|
31743
|
+
return none("not-paused");
|
|
31744
|
+
}
|
|
31745
|
+
return arm(named.key, named.step);
|
|
31746
|
+
}
|
|
31747
|
+
if (steps.length === 0)
|
|
31748
|
+
return none("nothing-held");
|
|
31749
|
+
if (steps.length === 1)
|
|
31750
|
+
return arm(steps[0].key, steps[0].step);
|
|
31751
|
+
writeBack(paths.held, held);
|
|
31752
|
+
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));
|
|
31753
|
+
return { outcome: "several-held", step: null, paused };
|
|
30828
31754
|
} catch {
|
|
30829
|
-
return
|
|
31755
|
+
return none("not-saved");
|
|
30830
31756
|
}
|
|
30831
31757
|
}
|
|
31758
|
+
function distinctSteps(held, numbersPath) {
|
|
31759
|
+
const order = [];
|
|
31760
|
+
const latest = /* @__PURE__ */ new Map();
|
|
31761
|
+
const numbered = /* @__PURE__ */ new Map();
|
|
31762
|
+
for (const r of held) {
|
|
31763
|
+
if (!latest.has(r.key))
|
|
31764
|
+
order.push(r.key);
|
|
31765
|
+
latest.set(r.key, r);
|
|
31766
|
+
if (r.number !== void 0)
|
|
31767
|
+
numbered.set(r.key, r.number);
|
|
31768
|
+
}
|
|
31769
|
+
return order.map((key) => ({
|
|
31770
|
+
key,
|
|
31771
|
+
number: numbered.get(key) ?? numberKept(numbersPath, key),
|
|
31772
|
+
step: latest.get(key).step ?? null
|
|
31773
|
+
}));
|
|
31774
|
+
}
|
|
30832
31775
|
function claimHeld(path, session, now) {
|
|
30833
31776
|
const claimed = `${path}.${process.pid}.${now}.claim`;
|
|
30834
31777
|
try {
|
|
@@ -30851,6 +31794,16 @@ function claimHeld(path, session, now) {
|
|
|
30851
31794
|
}
|
|
30852
31795
|
return records;
|
|
30853
31796
|
}
|
|
31797
|
+
function writeBack(path, records) {
|
|
31798
|
+
if (records.length === 0)
|
|
31799
|
+
return;
|
|
31800
|
+
try {
|
|
31801
|
+
appendFileSync5(path, records.map((r) => `${JSON.stringify(r)}
|
|
31802
|
+
`).join(""), { mode: 384 });
|
|
31803
|
+
} catch {
|
|
31804
|
+
return;
|
|
31805
|
+
}
|
|
31806
|
+
}
|
|
30854
31807
|
function isStep(v) {
|
|
30855
31808
|
return typeof v === "string" && v !== "" && v.length <= STEP_MAX_LENGTH;
|
|
30856
31809
|
}
|
|
@@ -30905,12 +31858,23 @@ function parseRecord(text, session) {
|
|
|
30905
31858
|
if (typeof r["at"] !== "number")
|
|
30906
31859
|
return null;
|
|
30907
31860
|
const step = r["step"];
|
|
30908
|
-
|
|
31861
|
+
const n = r["number"];
|
|
31862
|
+
return {
|
|
31863
|
+
version: 1,
|
|
31864
|
+
session,
|
|
31865
|
+
key: r["key"],
|
|
31866
|
+
at: r["at"],
|
|
31867
|
+
...isStep(step) ? { step } : {},
|
|
31868
|
+
...isWholeNumber2(n) ? { number: n } : {}
|
|
31869
|
+
};
|
|
30909
31870
|
}
|
|
30910
31871
|
function writeRecord(path, record2) {
|
|
31872
|
+
return writeWhole2(path, JSON.stringify(record2));
|
|
31873
|
+
}
|
|
31874
|
+
function writeWhole2(path, body) {
|
|
30911
31875
|
const tmp = `${path}.${process.pid}.${Date.now()}.tmp`;
|
|
30912
31876
|
try {
|
|
30913
|
-
writeFileSync13(tmp,
|
|
31877
|
+
writeFileSync13(tmp, body, { mode: 384 });
|
|
30914
31878
|
renameSync11(tmp, path);
|
|
30915
31879
|
return true;
|
|
30916
31880
|
} catch {
|
|
@@ -31008,7 +31972,7 @@ function decideAutonomous(facts, mayPublishNow) {
|
|
|
31008
31972
|
|
|
31009
31973
|
// dist/risky/own-copy.js
|
|
31010
31974
|
import { readFileSync as readFileSync23 } from "node:fs";
|
|
31011
|
-
import { join as
|
|
31975
|
+
import { join as join16, posix as posix2, win32 as win322 } from "node:path";
|
|
31012
31976
|
var OWN_COPY_START_TOOL = "Agent";
|
|
31013
31977
|
var OWN_COPY_WRITE_TOOLS = /* @__PURE__ */ new Set(["Write", "Edit", "MultiEdit", "NotebookEdit"]);
|
|
31014
31978
|
var OWN_COPY_ISOLATION = "worktree";
|
|
@@ -31069,7 +32033,7 @@ function typeCanChangeFiles(subagentType, deps) {
|
|
|
31069
32033
|
return true;
|
|
31070
32034
|
if (AGENT_FILE_NAME.test(type)) {
|
|
31071
32035
|
for (const base of [deps.projectDir, deps.home]) {
|
|
31072
|
-
const text = readOr(deps,
|
|
32036
|
+
const text = readOr(deps, join16(base, ".claude", "agents", `${type}.md`));
|
|
31073
32037
|
if (text === null)
|
|
31074
32038
|
continue;
|
|
31075
32039
|
const tools = frontmatterTools(text);
|
|
@@ -31175,31 +32139,31 @@ function judgeChange(input, call, deps) {
|
|
|
31175
32139
|
|
|
31176
32140
|
// dist/risky/save.js
|
|
31177
32141
|
import { randomBytes } from "node:crypto";
|
|
31178
|
-
import { chmodSync as chmodSync2, constants as fsConstants, copyFileSync, lstatSync as lstatSync4, mkdirSync as mkdirSync9, readdirSync as readdirSync10, readFileSync as readFileSync24, readlinkSync, realpathSync as
|
|
31179
|
-
import { homedir as
|
|
31180
|
-
import { dirname as dirname7, isAbsolute as
|
|
32142
|
+
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";
|
|
32143
|
+
import { homedir as homedir11 } from "node:os";
|
|
32144
|
+
import { dirname as dirname7, isAbsolute as isAbsolute6, join as join17, resolve as resolve8 } from "node:path";
|
|
31181
32145
|
var SAVE_LIMIT_BYTES = 2e8;
|
|
31182
32146
|
var SAVE_BUDGET_MS = 5e3;
|
|
31183
32147
|
function notSaved(reason) {
|
|
31184
32148
|
return { saved: false, reason };
|
|
31185
32149
|
}
|
|
31186
|
-
function savedFolderOf(engagementId, home =
|
|
32150
|
+
function savedFolderOf(engagementId, home = homedir11()) {
|
|
31187
32151
|
if (!isEngagementId(engagementId))
|
|
31188
32152
|
return null;
|
|
31189
|
-
return
|
|
32153
|
+
return join17(home, HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, SAVED_DIR_NAME);
|
|
31190
32154
|
}
|
|
31191
32155
|
function saveFirst(staked, ctx) {
|
|
31192
32156
|
const now = ctx.now ?? Date.now;
|
|
31193
32157
|
const deadline = now() + (ctx.budgetMs ?? SAVE_BUDGET_MS);
|
|
31194
|
-
const
|
|
31195
|
-
if (
|
|
32158
|
+
const folder2 = savedFolderOf(ctx.engagementId, ctx.home);
|
|
32159
|
+
if (folder2 === null)
|
|
31196
32160
|
return notSaved(AUTONOMY_SAVE_FAILED_REASON);
|
|
31197
32161
|
const plan = planOf(staked);
|
|
31198
32162
|
if (!plan.ok)
|
|
31199
32163
|
return notSaved(plan.reason);
|
|
31200
32164
|
const g = new SaveGit(plan.root, deadline, now);
|
|
31201
32165
|
const top = g.run(["rev-parse", "--show-toplevel"]);
|
|
31202
|
-
if (!top.ok ||
|
|
32166
|
+
if (!top.ok || realOrSelf3(top.value.trim()) !== plan.root)
|
|
31203
32167
|
return notSaved(AUTONOMY_SAVE_NOT_COVERED_REASON);
|
|
31204
32168
|
const head = g.run(["rev-parse", "--verify", "--quiet", "HEAD^{commit}"]);
|
|
31205
32169
|
const headCommit2 = head.ok ? head.value.trim() : "";
|
|
@@ -31214,23 +32178,23 @@ function saveFirst(staked, ctx) {
|
|
|
31214
32178
|
return notSaved(found2.reason);
|
|
31215
32179
|
let saveDir = null;
|
|
31216
32180
|
try {
|
|
31217
|
-
const id = freshId(
|
|
32181
|
+
const id = freshId(folder2, ctx.newId);
|
|
31218
32182
|
if (id === null)
|
|
31219
32183
|
return notSaved(AUTONOMY_SAVE_FAILED_REASON);
|
|
31220
|
-
saveDir =
|
|
32184
|
+
saveDir = join17(folder2, id);
|
|
31221
32185
|
const repository = repositoryOf(g);
|
|
31222
32186
|
if (repository === null)
|
|
31223
32187
|
return failed(saveDir);
|
|
31224
|
-
writeFileSync14(
|
|
32188
|
+
writeFileSync14(join17(saveDir, SAVED_REPOSITORY_FILE_NAME), `${repository}
|
|
31225
32189
|
`, { mode: 384 });
|
|
31226
|
-
const privateIndex =
|
|
32190
|
+
const privateIndex = join17(saveDir, PRIVATE_INDEX_NAME);
|
|
31227
32191
|
const commit = saveCommit(id, headCommit2, found2.tracked, plan.lines, privateIndex, g, now());
|
|
31228
32192
|
rmSync3(privateIndex, { force: true });
|
|
31229
32193
|
if (commit === null)
|
|
31230
32194
|
return failed(saveDir);
|
|
31231
|
-
const copiesDir =
|
|
32195
|
+
const copiesDir = join17(saveDir, SAVED_COPIES_DIR_NAME);
|
|
31232
32196
|
for (const rel of found2.copies) {
|
|
31233
|
-
if (now() > deadline || !copyOne(
|
|
32197
|
+
if (now() > deadline || !copyOne(join17(plan.root, rel), join17(copiesDir, rel)))
|
|
31234
32198
|
return failed(saveDir);
|
|
31235
32199
|
}
|
|
31236
32200
|
const description = savedSchema.safeParse({
|
|
@@ -31246,7 +32210,7 @@ function saveFirst(staked, ctx) {
|
|
|
31246
32210
|
});
|
|
31247
32211
|
if (!description.success)
|
|
31248
32212
|
return failed(saveDir);
|
|
31249
|
-
const file2 =
|
|
32213
|
+
const file2 = join17(saveDir, SAVED_FILE_NAME);
|
|
31250
32214
|
writeFileSync14(`${file2}.part`, `${JSON.stringify(description.data, null, 2)}
|
|
31251
32215
|
`, { mode: 384 });
|
|
31252
32216
|
renameSync12(`${file2}.part`, file2);
|
|
@@ -31277,7 +32241,7 @@ function planOf(staked) {
|
|
|
31277
32241
|
const t = f.save;
|
|
31278
32242
|
if (t === void 0)
|
|
31279
32243
|
return { ok: false, reason: f.cannotTell === void 0 ? AUTONOMY_SAVE_NOT_COVERED_REASON : AUTONOMY_COULD_NOT_TELL_REASON };
|
|
31280
|
-
const r =
|
|
32244
|
+
const r = realOrSelf3(resolve8(t.repoRoot));
|
|
31281
32245
|
if (root === null)
|
|
31282
32246
|
root = r;
|
|
31283
32247
|
else if (root !== r)
|
|
@@ -31296,7 +32260,7 @@ function planOf(staked) {
|
|
|
31296
32260
|
function isInsideRel(p) {
|
|
31297
32261
|
if (p === ".")
|
|
31298
32262
|
return true;
|
|
31299
|
-
if (p === "" ||
|
|
32263
|
+
if (p === "" || isAbsolute6(p) || p.includes("\\"))
|
|
31300
32264
|
return false;
|
|
31301
32265
|
return p.split("/").every((s) => s !== "" && s !== "." && s !== "..");
|
|
31302
32266
|
}
|
|
@@ -31326,7 +32290,7 @@ function filesOf(plan, g, deadline) {
|
|
|
31326
32290
|
trackedAll.add(path);
|
|
31327
32291
|
if (!reached(path, plan.specs))
|
|
31328
32292
|
continue;
|
|
31329
|
-
const st = lstatOrNull(
|
|
32293
|
+
const st = lstatOrNull(join17(plan.root, path));
|
|
31330
32294
|
if (st !== null && (st.isFile() || st.isSymbolicLink()))
|
|
31331
32295
|
tracked.add(path);
|
|
31332
32296
|
}
|
|
@@ -31338,7 +32302,7 @@ function filesOf(plan, g, deadline) {
|
|
|
31338
32302
|
const rel = stack.pop();
|
|
31339
32303
|
if (rel === ".git")
|
|
31340
32304
|
continue;
|
|
31341
|
-
const abs = rel === "." ? plan.root :
|
|
32305
|
+
const abs = rel === "." ? plan.root : join17(plan.root, rel);
|
|
31342
32306
|
const st = lstatOrNull(abs);
|
|
31343
32307
|
if (st === null)
|
|
31344
32308
|
continue;
|
|
@@ -31376,13 +32340,13 @@ function copyOne(src, dst) {
|
|
|
31376
32340
|
}
|
|
31377
32341
|
copyFileSync(src, dst, fsConstants.COPYFILE_EXCL | fsConstants.COPYFILE_FICLONE);
|
|
31378
32342
|
chmodSync2(dst, st.mode & 4095);
|
|
31379
|
-
return
|
|
32343
|
+
return statSync9(dst).size === st.size;
|
|
31380
32344
|
}
|
|
31381
32345
|
function saveCommit(id, head, tracked, lines2, privateIndex, g, at) {
|
|
31382
32346
|
const indexPath = g.run(["rev-parse", "--git-path", "index"]);
|
|
31383
32347
|
if (!indexPath.ok)
|
|
31384
32348
|
return null;
|
|
31385
|
-
const projectIndex =
|
|
32349
|
+
const projectIndex = resolve8(g.root, indexPath.value.trim());
|
|
31386
32350
|
const env = commitEnv(privateIndex, at);
|
|
31387
32351
|
if (lstatOrNull(projectIndex) !== null)
|
|
31388
32352
|
copyFileSync(projectIndex, privateIndex);
|
|
@@ -31444,14 +32408,14 @@ var SaveGit = class {
|
|
|
31444
32408
|
});
|
|
31445
32409
|
}
|
|
31446
32410
|
};
|
|
31447
|
-
function freshId(
|
|
31448
|
-
mkdirSync9(
|
|
32411
|
+
function freshId(folder2, newId) {
|
|
32412
|
+
mkdirSync9(folder2, { recursive: true, mode: 448 });
|
|
31449
32413
|
for (let i = 0; i < 5; i++) {
|
|
31450
32414
|
const id = newId?.() ?? defaultId();
|
|
31451
32415
|
if (!savedIdSchema.safeParse(id).success)
|
|
31452
32416
|
return null;
|
|
31453
32417
|
try {
|
|
31454
|
-
mkdirSync9(
|
|
32418
|
+
mkdirSync9(join17(folder2, id), { mode: 448 });
|
|
31455
32419
|
return id;
|
|
31456
32420
|
} catch (e) {
|
|
31457
32421
|
if (e.code !== "EEXIST")
|
|
@@ -31472,19 +32436,19 @@ function repositoryOf(g) {
|
|
|
31472
32436
|
if (!r.ok)
|
|
31473
32437
|
return null;
|
|
31474
32438
|
const dir = r.value.trim();
|
|
31475
|
-
return dir === "" ? null :
|
|
32439
|
+
return dir === "" ? null : realOrSelf3(resolve8(g.root, dir));
|
|
31476
32440
|
}
|
|
31477
32441
|
function markedRepository(dir) {
|
|
31478
32442
|
try {
|
|
31479
|
-
const text = readFileSync24(
|
|
32443
|
+
const text = readFileSync24(join17(dir, SAVED_REPOSITORY_FILE_NAME), "utf-8").trim();
|
|
31480
32444
|
return text === "" ? null : text;
|
|
31481
32445
|
} catch {
|
|
31482
32446
|
return null;
|
|
31483
32447
|
}
|
|
31484
32448
|
}
|
|
31485
32449
|
function pruneSaves(root, engagementId, ctx = {}) {
|
|
31486
|
-
const
|
|
31487
|
-
if (
|
|
32450
|
+
const folder2 = savedFolderOf(engagementId, ctx.home);
|
|
32451
|
+
if (folder2 === null)
|
|
31488
32452
|
return;
|
|
31489
32453
|
const now = ctx.now ?? Date.now;
|
|
31490
32454
|
const g = new SaveGit(root, ctx.deadline ?? now() + SAVE_BUDGET_MS, now);
|
|
@@ -31501,7 +32465,7 @@ function pruneSaves(root, engagementId, ctx = {}) {
|
|
|
31501
32465
|
const repository = repositoryOf(g);
|
|
31502
32466
|
let names = [];
|
|
31503
32467
|
try {
|
|
31504
|
-
names = readdirSync10(
|
|
32468
|
+
names = readdirSync10(folder2);
|
|
31505
32469
|
} catch {
|
|
31506
32470
|
names = [];
|
|
31507
32471
|
}
|
|
@@ -31510,7 +32474,7 @@ function pruneSaves(root, engagementId, ctx = {}) {
|
|
|
31510
32474
|
if (!savedIdSchema.safeParse(id).success)
|
|
31511
32475
|
continue;
|
|
31512
32476
|
here.add(id);
|
|
31513
|
-
const dir =
|
|
32477
|
+
const dir = join17(folder2, id);
|
|
31514
32478
|
const st = lstatOrNull(dir);
|
|
31515
32479
|
const answer = savedPruneAnswer({
|
|
31516
32480
|
refMadeAt: refs.get(id) ?? null,
|
|
@@ -31539,9 +32503,9 @@ function lstatOrNull(p) {
|
|
|
31539
32503
|
return null;
|
|
31540
32504
|
}
|
|
31541
32505
|
}
|
|
31542
|
-
function
|
|
32506
|
+
function realOrSelf3(p) {
|
|
31543
32507
|
try {
|
|
31544
|
-
return
|
|
32508
|
+
return realpathSync9(p);
|
|
31545
32509
|
} catch {
|
|
31546
32510
|
return p;
|
|
31547
32511
|
}
|
|
@@ -31550,12 +32514,12 @@ function realOrSelf2(p) {
|
|
|
31550
32514
|
// dist/autonomy-state.js
|
|
31551
32515
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
31552
32516
|
import { chmodSync as chmodSync3, mkdirSync as mkdirSync10, readFileSync as readFileSync25, renameSync as renameSync13, rmSync as rmSync4, writeFileSync as writeFileSync15 } from "node:fs";
|
|
31553
|
-
import { homedir as
|
|
31554
|
-
import { dirname as dirname8, join as
|
|
32517
|
+
import { homedir as homedir12, platform as platform2 } from "node:os";
|
|
32518
|
+
import { dirname as dirname8, join as join18 } from "node:path";
|
|
31555
32519
|
var AUTONOMY_STATE_FILENAME = "autonomy.json";
|
|
31556
32520
|
var AUTONOMY_STATE_DEADLINE_MS = 1500;
|
|
31557
32521
|
function autonomyStateFilePath(engagementId, home) {
|
|
31558
|
-
return
|
|
32522
|
+
return join18(home ?? homedir12(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, AUTONOMY_STATE_FILENAME);
|
|
31559
32523
|
}
|
|
31560
32524
|
function readCachedAutonomy(engagementId, nowMs, home) {
|
|
31561
32525
|
if (!isEngagementId(engagementId))
|
|
@@ -31583,6 +32547,7 @@ function confirmMayPublishNow(opts) {
|
|
|
31583
32547
|
timeout: opts.timeoutMs,
|
|
31584
32548
|
windowsHide: true
|
|
31585
32549
|
});
|
|
32550
|
+
recordChildRequest(url2, ["Authorization"], r.status === 0);
|
|
31586
32551
|
if (r.status !== 0 || typeof r.stdout !== "string")
|
|
31587
32552
|
return false;
|
|
31588
32553
|
const parsed = autonomyStateSchema.safeParse(JSON.parse(r.stdout));
|
|
@@ -31607,7 +32572,7 @@ function deleteAutonomyStateFile(engagementId, home) {
|
|
|
31607
32572
|
}
|
|
31608
32573
|
function writeAutonomyStateFile(engagementId, file2, home) {
|
|
31609
32574
|
const target = autonomyStateFilePath(engagementId, home);
|
|
31610
|
-
const temp =
|
|
32575
|
+
const temp = join18(dirname8(target), `.${AUTONOMY_STATE_FILENAME}.${process.pid}.tmp`);
|
|
31611
32576
|
try {
|
|
31612
32577
|
mkdirSync10(dirname8(target), { recursive: true, mode: 448 });
|
|
31613
32578
|
writeFileSync15(temp, `${JSON.stringify(file2)}
|
|
@@ -31669,7 +32634,7 @@ async function cacheAutonomySetting(opts) {
|
|
|
31669
32634
|
}
|
|
31670
32635
|
|
|
31671
32636
|
// dist/risky/patch-calls.js
|
|
31672
|
-
import { isAbsolute as
|
|
32637
|
+
import { isAbsolute as isAbsolute7, resolve as resolve9 } from "node:path";
|
|
31673
32638
|
var SHELL_TOOL = "Bash";
|
|
31674
32639
|
function toolCallsOf(input, profile) {
|
|
31675
32640
|
const toolName = input["tool_name"];
|
|
@@ -31692,7 +32657,7 @@ function toolCallsOf(input, profile) {
|
|
|
31692
32657
|
const ops = patchOperations(command);
|
|
31693
32658
|
if (ops === null || ops.length === 0)
|
|
31694
32659
|
return null;
|
|
31695
|
-
const cwd = typeof input["cwd"] === "string" &&
|
|
32660
|
+
const cwd = typeof input["cwd"] === "string" && isAbsolute7(input["cwd"]) ? input["cwd"] : null;
|
|
31696
32661
|
const calls = [];
|
|
31697
32662
|
for (const op of ops) {
|
|
31698
32663
|
const made = callsFor(op, cwd);
|
|
@@ -31730,9 +32695,9 @@ function callsFor(op, cwd) {
|
|
|
31730
32695
|
}
|
|
31731
32696
|
}
|
|
31732
32697
|
function placed(path, cwd) {
|
|
31733
|
-
if (
|
|
31734
|
-
return
|
|
31735
|
-
return cwd === null ? null :
|
|
32698
|
+
if (isAbsolute7(path))
|
|
32699
|
+
return resolve9(path);
|
|
32700
|
+
return cwd === null ? null : resolve9(cwd, path);
|
|
31736
32701
|
}
|
|
31737
32702
|
function shellWord(text) {
|
|
31738
32703
|
return `'${text.split("'").join("'\\''")}'`;
|
|
@@ -31740,7 +32705,7 @@ function shellWord(text) {
|
|
|
31740
32705
|
|
|
31741
32706
|
// dist/hooks/pre-tool-use.js
|
|
31742
32707
|
import { performance } from "node:perf_hooks";
|
|
31743
|
-
import { homedir as
|
|
32708
|
+
import { homedir as homedir13 } from "node:os";
|
|
31744
32709
|
var UNREADABLE_INPUT_NOTICE = "Halfcycle could not read what the coding agent was about to do, so that step went ahead without being checked for anything that cannot be undone. If this keeps happening, update Halfcycle.";
|
|
31745
32710
|
var PRE_TOOL_USE_LIMIT_MS = (HALFCYCLE_HOOK_WIRING.find((e) => e.event === "PreToolUse")?.timeout ?? 10) * 1e3;
|
|
31746
32711
|
var AUTONOMY_REPLY_MARGIN_MS = 1e3;
|
|
@@ -31811,6 +32776,11 @@ function runPreToolUse(deps) {
|
|
|
31811
32776
|
if (held !== null)
|
|
31812
32777
|
return `${preToolUseReplyText("refuse", held)}
|
|
31813
32778
|
`;
|
|
32779
|
+
recordSpawnedTask(call.toolInput, {
|
|
32780
|
+
projectDir: projectDirOf(deps),
|
|
32781
|
+
...deps.env === void 0 ? {} : { env: deps.env },
|
|
32782
|
+
...deps.home === void 0 ? {} : { home: deps.home }
|
|
32783
|
+
});
|
|
31814
32784
|
}
|
|
31815
32785
|
return own.kind === "unknown" ? ownCopyNotice(input, deps) : "";
|
|
31816
32786
|
}
|
|
@@ -31819,16 +32789,19 @@ function runPreToolUse(deps) {
|
|
|
31819
32789
|
return `${preToolUseReplyText("ask", answer.question)}
|
|
31820
32790
|
`;
|
|
31821
32791
|
}
|
|
32792
|
+
let agentText = answer.refusal.agent;
|
|
31822
32793
|
if (allowableByTyping(call, answer.staked)) {
|
|
31823
|
-
const key = stepKey(input, answer.staked);
|
|
32794
|
+
const key = stepKey(input, answer.staked, deps.gitTimeoutMs === void 0 ? {} : { gitTimeoutMs: deps.gitTimeoutMs });
|
|
31824
32795
|
if (key !== null) {
|
|
31825
32796
|
const allowOnce = { ...deps.liveness?.dir === void 0 ? {} : { dir: deps.liveness.dir }, now: () => at.getTime() };
|
|
31826
32797
|
if (spendAllow(input["session_id"], key, allowOnce))
|
|
31827
32798
|
return "";
|
|
31828
|
-
|
|
32799
|
+
const stepNumber = numberStep(input["session_id"], key, allowOnce);
|
|
32800
|
+
recordHeld(input["session_id"], key, allowOnce, answer.refusal.step, stepNumber);
|
|
32801
|
+
agentText = heldAgentText(answer.refusal, stepNumber);
|
|
31829
32802
|
}
|
|
31830
32803
|
}
|
|
31831
|
-
return `${preToolUseReplyText("refuse", answer.refusal.person,
|
|
32804
|
+
return `${preToolUseReplyText("refuse", answer.refusal.person, agentText)}
|
|
31832
32805
|
`;
|
|
31833
32806
|
} catch {
|
|
31834
32807
|
return "";
|
|
@@ -31956,7 +32929,7 @@ function ownCopyOf(input, call, deps) {
|
|
|
31956
32929
|
const walk2 = deps.walk ?? deps.liveness?.walk;
|
|
31957
32930
|
return judgeOwnCopy(input, call, {
|
|
31958
32931
|
projectDir: projectDirOf(deps),
|
|
31959
|
-
home: deps.home ??
|
|
32932
|
+
home: deps.home ?? homedir13(),
|
|
31960
32933
|
...walk2 === void 0 ? {} : { walk: walk2 },
|
|
31961
32934
|
...deps.liveness === void 0 ? {} : { liveness: deps.liveness }
|
|
31962
32935
|
});
|
|
@@ -31965,8 +32938,8 @@ function ownCopyOf(input, call, deps) {
|
|
|
31965
32938
|
}
|
|
31966
32939
|
}
|
|
31967
32940
|
function ownCopyNotice(input, deps) {
|
|
31968
|
-
const
|
|
31969
|
-
return firstNoticeThisSession("outside-own-copy-unknown",
|
|
32941
|
+
const folder2 = stringOf(input, "cwd") ?? projectDirOf(deps);
|
|
32942
|
+
return firstNoticeThisSession("outside-own-copy-unknown", folder2, stringOf(input, "session_id"), deps.liveness?.dir) ? `${preToolUseNoticeText(OWN_COPY_UNKNOWN_NOTICE)}
|
|
31970
32943
|
` : "";
|
|
31971
32944
|
}
|
|
31972
32945
|
function parseObject2(text) {
|
|
@@ -31983,14 +32956,14 @@ function stringOf(input, key) {
|
|
|
31983
32956
|
}
|
|
31984
32957
|
function unreadable(deps, input) {
|
|
31985
32958
|
const session = (input === null ? void 0 : stringOf(input, "session_id")) ?? /"session_id"\s*:\s*"([^"\\]+)"/.exec(deps.input)?.[1];
|
|
31986
|
-
const
|
|
31987
|
-
return firstNoticeThisSession("pre-tool-use-unreadable",
|
|
32959
|
+
const folder2 = (input === null ? void 0 : stringOf(input, "cwd")) ?? projectDirOf(deps);
|
|
32960
|
+
return firstNoticeThisSession("pre-tool-use-unreadable", folder2, session) ? `${preToolUseNoticeText(UNREADABLE_INPUT_NOTICE)}
|
|
31988
32961
|
` : "";
|
|
31989
32962
|
}
|
|
31990
32963
|
|
|
31991
32964
|
// dist/hooks/session-diff.js
|
|
31992
32965
|
import { unlinkSync as unlinkSync10 } from "node:fs";
|
|
31993
|
-
import { join as
|
|
32966
|
+
import { join as join19 } from "node:path";
|
|
31994
32967
|
var STOP_HOOK_EVENT = {
|
|
31995
32968
|
stop: "Stop",
|
|
31996
32969
|
"subagent-stop": "SubagentStop"
|
|
@@ -32042,7 +33015,7 @@ async function evaluateSession(input, kind, reply, readSeat, profile) {
|
|
|
32042
33015
|
}
|
|
32043
33016
|
const repoRoot = repoRootResult.value;
|
|
32044
33017
|
const sessionId = input.session_id;
|
|
32045
|
-
const
|
|
33018
|
+
const folder2 = realPathOf(repoRoot);
|
|
32046
33019
|
orphanSweep(repoRoot, (ref) => refExists(ref, repoRoot), sessionId, Date.now(), whichCopy(process.cwd())?.common ?? null);
|
|
32047
33020
|
const base = resolveDiffBase2(repoRoot, sessionId);
|
|
32048
33021
|
const diffBase = base.kind;
|
|
@@ -32055,12 +33028,12 @@ async function evaluateSession(input, kind, reply, readSeat, profile) {
|
|
|
32055
33028
|
const candidates = ownEditedFiles(repoRoot, sessionId).filter((relPath) => !tracked.has(relPath));
|
|
32056
33029
|
const untracked = getUntrackedFiles(repoRoot, candidates);
|
|
32057
33030
|
const created = untracked.ok ? untracked.value.filter((relPath) => !tracked.has(relPath)) : [];
|
|
32058
|
-
const getDiff = (relPath) => tracked.has(relPath) ? collected.getDiff(relPath) : getSingleFileDiff(
|
|
33031
|
+
const getDiff = (relPath) => tracked.has(relPath) ? collected.getDiff(relPath) : getSingleFileDiff(join19(repoRoot, relPath), repoRoot);
|
|
32059
33032
|
const { evaluated } = partitionInstallerOutput(collected.files);
|
|
32060
33033
|
const { evaluated: createdEvaluated } = partitionInstallerOutput(created);
|
|
32061
33034
|
const changedFiles2 = [...ownChangedFiles(repoRoot, evaluated, sessionId), ...createdEvaluated];
|
|
32062
33035
|
if (changedFiles2.length === 0) {
|
|
32063
|
-
queueTurnEnd(keepBooks(sessionId,
|
|
33036
|
+
queueTurnEnd(keepBooks(sessionId, folder2, { kind: "no-own-changes" }, kind === "stop"), reply);
|
|
32064
33037
|
return;
|
|
32065
33038
|
}
|
|
32066
33039
|
const fileDiffEntries = changedFiles2.map((relPath) => ({
|
|
@@ -32071,7 +33044,7 @@ async function evaluateSession(input, kind, reply, readSeat, profile) {
|
|
|
32071
33044
|
const digest = digestChangeState(baseKey, fileDiffEntries);
|
|
32072
33045
|
const prior = readDedupe(repoRoot, sessionId);
|
|
32073
33046
|
if (prior && prior.base === baseKey && prior.digest === digest) {
|
|
32074
|
-
queueTurnEnd(keepBooks(sessionId,
|
|
33047
|
+
queueTurnEnd(keepBooks(sessionId, folder2, { kind: "unchanged" }, kind === "stop"), reply);
|
|
32075
33048
|
return;
|
|
32076
33049
|
}
|
|
32077
33050
|
const context = loadChangeSetContext(repoRoot);
|
|
@@ -32151,12 +33124,12 @@ async function evaluateSession(input, kind, reply, readSeat, profile) {
|
|
|
32151
33124
|
warn: (msg) => process.stderr.write(msg + "\n")
|
|
32152
33125
|
});
|
|
32153
33126
|
writeDedupe(repoRoot, sessionId, { base: baseKey, digest });
|
|
32154
|
-
actOnEnvelope3(clientResult.envelope, kind, input.stop_hook_active === true, reply, sessionId,
|
|
33127
|
+
actOnEnvelope3(clientResult.envelope, kind, input.stop_hook_active === true, reply, sessionId, folder2);
|
|
32155
33128
|
}
|
|
32156
|
-
function keepBooks(sessionId,
|
|
33129
|
+
function keepBooks(sessionId, folder2, outcome, topLevel) {
|
|
32157
33130
|
const books = () => {
|
|
32158
33131
|
const before = readFindings(sessionId);
|
|
32159
|
-
const { file: file2, news } = turnEndBookkeeping(before ?? emptyFindings(""),
|
|
33132
|
+
const { file: file2, news } = turnEndBookkeeping(before ?? emptyFindings(""), folder2, outcome, topLevel, /* @__PURE__ */ new Date());
|
|
32160
33133
|
if (before !== null && JSON.stringify(before) !== JSON.stringify(file2)) {
|
|
32161
33134
|
if (file2.findings.length > 0)
|
|
32162
33135
|
writeFindings(file2);
|
|
@@ -32181,7 +33154,7 @@ function queueTurnEnd(words, reply) {
|
|
|
32181
33154
|
if (words !== null)
|
|
32182
33155
|
reply.notice(words);
|
|
32183
33156
|
}
|
|
32184
|
-
function actOnEnvelope3(envelope, kind, neverBlock, reply, sessionId,
|
|
33157
|
+
function actOnEnvelope3(envelope, kind, neverBlock, reply, sessionId, folder2) {
|
|
32185
33158
|
const notRun = notRunMessage((envelope.notRun ?? []).map((n) => n.reason));
|
|
32186
33159
|
const outcome = {
|
|
32187
33160
|
kind: "evaluated",
|
|
@@ -32190,7 +33163,7 @@ function actOnEnvelope3(envelope, kind, neverBlock, reply, sessionId, folder) {
|
|
|
32190
33163
|
};
|
|
32191
33164
|
const topLevel = kind === "stop";
|
|
32192
33165
|
if (envelope.blocking && !neverBlock) {
|
|
32193
|
-
keepBooks(sessionId,
|
|
33166
|
+
keepBooks(sessionId, folder2, outcome, false);
|
|
32194
33167
|
const reason = blockReason(envelope.guardsFired.map((g) => g.explanation));
|
|
32195
33168
|
reply.block(notRun ? `${reason}
|
|
32196
33169
|
${notRun}` : reason, stoppedMessage(blockingExplanations(envelope.guardsFired)));
|
|
@@ -32198,7 +33171,7 @@ ${notRun}` : reason, stoppedMessage(blockingExplanations(envelope.guardsFired)))
|
|
|
32198
33171
|
if (envelope.blocking && neverBlock) {
|
|
32199
33172
|
reply.notice(couldNotFixMessage(blockingExplanations(envelope.guardsFired)));
|
|
32200
33173
|
}
|
|
32201
|
-
queueTurnEnd(keepBooks(sessionId,
|
|
33174
|
+
queueTurnEnd(keepBooks(sessionId, folder2, outcome, topLevel), reply);
|
|
32202
33175
|
if (notRun)
|
|
32203
33176
|
reply.notice(notRun);
|
|
32204
33177
|
}
|
|
@@ -32219,9 +33192,9 @@ async function readHookStdin() {
|
|
|
32219
33192
|
}
|
|
32220
33193
|
}
|
|
32221
33194
|
function readStdin2() {
|
|
32222
|
-
return new Promise((
|
|
33195
|
+
return new Promise((resolve12) => {
|
|
32223
33196
|
if (process.stdin.isTTY) {
|
|
32224
|
-
|
|
33197
|
+
resolve12("");
|
|
32225
33198
|
return;
|
|
32226
33199
|
}
|
|
32227
33200
|
const chunks = [];
|
|
@@ -32231,7 +33204,7 @@ function readStdin2() {
|
|
|
32231
33204
|
return;
|
|
32232
33205
|
settled2 = true;
|
|
32233
33206
|
clearTimeout(timer);
|
|
32234
|
-
|
|
33207
|
+
resolve12(Buffer.concat(chunks).toString("utf-8"));
|
|
32235
33208
|
};
|
|
32236
33209
|
const timer = setTimeout(done, HOOK_STDIN_GRACE_MS);
|
|
32237
33210
|
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
@@ -32258,19 +33231,19 @@ async function runStop(observeDeps = {}, timeDeps = {}, paceDeps = {}, profile =
|
|
|
32258
33231
|
recordTimeEvent("turn-end", input);
|
|
32259
33232
|
await runSessionDiff(input, "stop", readSeatConfiguration, async (reply) => {
|
|
32260
33233
|
await observeChanges(input.session_id, reply, observeDeps);
|
|
32261
|
-
await sendTimeRecord(timeDeps);
|
|
33234
|
+
await sendTimeRecord(timeDeps, { agent: profile.id });
|
|
32262
33235
|
await paceAtTurnEnd(input, reply, { configFolder: profile.configFolder, ...paceDeps });
|
|
32263
33236
|
}, profile);
|
|
32264
33237
|
}
|
|
32265
33238
|
|
|
32266
33239
|
// dist/relayed-choices.js
|
|
32267
33240
|
import { mkdirSync as mkdirSync11, readFileSync as readFileSync26, renameSync as renameSync14, rmSync as rmSync5, writeFileSync as writeFileSync16 } from "node:fs";
|
|
32268
|
-
import { homedir as
|
|
32269
|
-
import { dirname as dirname9, join as
|
|
33241
|
+
import { homedir as homedir14 } from "node:os";
|
|
33242
|
+
import { dirname as dirname9, join as join20 } from "node:path";
|
|
32270
33243
|
function relayedChoicesFilePath(engagementId, home) {
|
|
32271
33244
|
if (!isEngagementId(engagementId))
|
|
32272
33245
|
return null;
|
|
32273
|
-
return
|
|
33246
|
+
return join20(home ?? homedir14(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, PACING_DIR_NAME, RELAYED_CHOICES_FILENAME);
|
|
32274
33247
|
}
|
|
32275
33248
|
function readRelayedChoices(engagementId, phase, home) {
|
|
32276
33249
|
const path = relayedChoicesFilePath(engagementId, home);
|
|
@@ -32306,7 +33279,7 @@ function recordRelayedChoice(opts) {
|
|
|
32306
33279
|
});
|
|
32307
33280
|
if (!file2.success)
|
|
32308
33281
|
return false;
|
|
32309
|
-
const temp =
|
|
33282
|
+
const temp = join20(dirname9(target), `.${RELAYED_CHOICES_FILENAME}.${process.pid}.tmp`);
|
|
32310
33283
|
try {
|
|
32311
33284
|
mkdirSync11(dirname9(target), { recursive: true, mode: 448 });
|
|
32312
33285
|
writeFileSync16(temp, `${JSON.stringify(file2.data)}
|
|
@@ -32535,19 +33508,19 @@ function matchReviewPhraseShape(shape, reviews) {
|
|
|
32535
33508
|
|
|
32536
33509
|
// dist/hooks/shown-record.js
|
|
32537
33510
|
import { chmodSync as chmodSync4, readFileSync as readFileSync27, renameSync as renameSync15, unlinkSync as unlinkSync11, writeFileSync as writeFileSync17 } from "node:fs";
|
|
32538
|
-
import { homedir as
|
|
32539
|
-
import { join as
|
|
33511
|
+
import { homedir as homedir15, platform as platform3 } from "node:os";
|
|
33512
|
+
import { join as join21 } from "node:path";
|
|
32540
33513
|
function recordDir(engagementId, home) {
|
|
32541
33514
|
if (!isEngagementId(engagementId))
|
|
32542
33515
|
return null;
|
|
32543
|
-
return
|
|
33516
|
+
return join21(home ?? homedir15(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId);
|
|
32544
33517
|
}
|
|
32545
33518
|
function readShownRecord(engagementId, home) {
|
|
32546
33519
|
const dir = recordDir(engagementId, home);
|
|
32547
33520
|
if (dir === null)
|
|
32548
33521
|
return { entries: [], reviews: [] };
|
|
32549
33522
|
try {
|
|
32550
|
-
return parseShownRecord(readFileSync27(
|
|
33523
|
+
return parseShownRecord(readFileSync27(join21(dir, SHOWN_PLANS_FILENAME), "utf-8"));
|
|
32551
33524
|
} catch {
|
|
32552
33525
|
return { entries: [], reviews: [] };
|
|
32553
33526
|
}
|
|
@@ -32568,7 +33541,7 @@ function moveListedReviewForward(engagementId, home, listed, reviewVersion, deci
|
|
|
32568
33541
|
const dir = recordDir(engagementId, home);
|
|
32569
33542
|
if (dir === null)
|
|
32570
33543
|
return false;
|
|
32571
|
-
const path =
|
|
33544
|
+
const path = join21(dir, SHOWN_PLANS_FILENAME);
|
|
32572
33545
|
const current = parseShownRecord(readFileSync27(path, "utf-8"));
|
|
32573
33546
|
const at = current.reviews.findIndex((r) => r.phase === listed.phase && r.shownAt === listed.shownAt && r.reviewVersion === listed.reviewVersion);
|
|
32574
33547
|
if (at === -1)
|
|
@@ -32576,7 +33549,7 @@ function moveListedReviewForward(engagementId, home, listed, reviewVersion, deci
|
|
|
32576
33549
|
const acts = new Map(decided.map((d) => [d.part, d.act]));
|
|
32577
33550
|
const reviews = current.reviews.map((review, i) => i === at ? { ...review, reviewVersion, parts: review.parts.map((p) => movedPart(p, acts.get(p.part))) } : review);
|
|
32578
33551
|
const body = serialiseShownRecord({ entries: current.entries, reviews });
|
|
32579
|
-
temp =
|
|
33552
|
+
temp = join21(dir, `.${SHOWN_PLANS_FILENAME}.${process.pid}.tmp`);
|
|
32580
33553
|
writeFileSync17(temp, body, { mode: 384 });
|
|
32581
33554
|
if (platform3() !== "win32")
|
|
32582
33555
|
chmodSync4(temp, 384);
|
|
@@ -32960,8 +33933,16 @@ function allowArmedLine(step = null) {
|
|
|
32960
33933
|
function allowNothingHeldLine() {
|
|
32961
33934
|
return line(`${NOTHING_ALLOWED}: no step is paused in this session.`);
|
|
32962
33935
|
}
|
|
32963
|
-
|
|
32964
|
-
|
|
33936
|
+
var UNNAMED_PAUSED_STEP = "a paused step";
|
|
33937
|
+
function allowSeveralHeldLine(paused) {
|
|
33938
|
+
const listed = paused.filter((p) => p.number !== null).map((p) => `${ALLOW_REPLY} ${String(p.number)} for ${p.step ?? UNNAMED_PAUSED_STEP}`).join("; ");
|
|
33939
|
+
if (listed === "") {
|
|
33940
|
+
return `${NOTHING_ALLOWED}: more than one step is paused, and Halfcycle could not number them on this computer. Nothing ran. ${SHOW_AS_WRITTEN}`;
|
|
33941
|
+
}
|
|
33942
|
+
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}`;
|
|
33943
|
+
}
|
|
33944
|
+
function allowNotPausedLine(stepNumber) {
|
|
33945
|
+
return line(`${NOTHING_ALLOWED}: step ${String(stepNumber)} is not paused in this session.`);
|
|
32965
33946
|
}
|
|
32966
33947
|
function allowNotAttendedLine() {
|
|
32967
33948
|
return line(`${NOTHING_ALLOWED}: a paused step can be allowed by typing only when a person types it into an open session.`);
|
|
@@ -33047,8 +34028,8 @@ function waitLineForAnswer(context, answer) {
|
|
|
33047
34028
|
}
|
|
33048
34029
|
}
|
|
33049
34030
|
var PACE_NOTHING_CHANGED_OPENING = "Nothing changed";
|
|
33050
|
-
function paceAnswerLine(text,
|
|
33051
|
-
return
|
|
34031
|
+
function paceAnswerLine(text, _agent) {
|
|
34032
|
+
return codexLine(text);
|
|
33052
34033
|
}
|
|
33053
34034
|
function paceNumberDoneText(n, more) {
|
|
33054
34035
|
const head = `Done. This build now runs up to ${paceAgentsOf(n)} at once.`;
|
|
@@ -33156,8 +34137,9 @@ async function decideLine(opts) {
|
|
|
33156
34137
|
const review = { recognised: false };
|
|
33157
34138
|
try {
|
|
33158
34139
|
const prompt = promptOf(opts.input);
|
|
33159
|
-
|
|
33160
|
-
|
|
34140
|
+
const allowReply = allowReplyOf(prompt);
|
|
34141
|
+
if (allowReply !== null)
|
|
34142
|
+
return `${decideAllow(allowReply.number, opts)}
|
|
33161
34143
|
`;
|
|
33162
34144
|
const autonomyShape = autonomyPhraseShape(prompt);
|
|
33163
34145
|
if (autonomyShape !== null) {
|
|
@@ -33210,21 +34192,23 @@ async function decideLine(opts) {
|
|
|
33210
34192
|
`;
|
|
33211
34193
|
}
|
|
33212
34194
|
}
|
|
33213
|
-
function decideAllow(opts) {
|
|
34195
|
+
function decideAllow(stepNumber, opts) {
|
|
33214
34196
|
const env = opts.env ?? process.env;
|
|
33215
34197
|
if ((opts.agent ?? "claude-code") === "claude-code" && !readSessionAttended(env))
|
|
33216
34198
|
return allowNotAttendedLine();
|
|
33217
|
-
const { outcome, step } = armAllowStep(sessionIdOf(opts.input), {
|
|
34199
|
+
const { outcome, step, paused } = armAllowStep(sessionIdOf(opts.input), {
|
|
33218
34200
|
...opts.tempDir === void 0 ? {} : { dir: opts.tempDir },
|
|
33219
34201
|
...opts.now === void 0 ? {} : { now: opts.now }
|
|
33220
|
-
});
|
|
34202
|
+
}, stepNumber);
|
|
33221
34203
|
switch (outcome) {
|
|
33222
34204
|
case "armed":
|
|
33223
34205
|
return allowArmedLine(step);
|
|
33224
34206
|
case "nothing-held":
|
|
33225
34207
|
return allowNothingHeldLine();
|
|
34208
|
+
case "not-paused":
|
|
34209
|
+
return allowNotPausedLine(stepNumber ?? 0);
|
|
33226
34210
|
case "several-held":
|
|
33227
|
-
return allowSeveralHeldLine();
|
|
34211
|
+
return allowSeveralHeldLine(paused);
|
|
33228
34212
|
case "not-saved":
|
|
33229
34213
|
return allowNotSavedLine();
|
|
33230
34214
|
default: {
|
|
@@ -33751,14 +34735,14 @@ function runUserPromptFindings(opts) {
|
|
|
33751
34735
|
}
|
|
33752
34736
|
|
|
33753
34737
|
// dist/resolve-engagement.js
|
|
33754
|
-
import { existsSync as
|
|
33755
|
-
import { join as
|
|
33756
|
-
import { homedir as
|
|
34738
|
+
import { existsSync as existsSync9, readFileSync as readFileSync28, realpathSync as realpathSync10 } from "node:fs";
|
|
34739
|
+
import { join as join22, sep as sep7 } from "node:path";
|
|
34740
|
+
import { homedir as homedir16 } from "node:os";
|
|
33757
34741
|
function defaultRegistryPath() {
|
|
33758
|
-
return
|
|
34742
|
+
return join22(homedir16(), ".halfcycle", "registry.json");
|
|
33759
34743
|
}
|
|
33760
34744
|
function readRegistry(registryPath = defaultRegistryPath()) {
|
|
33761
|
-
if (!
|
|
34745
|
+
if (!existsSync9(registryPath))
|
|
33762
34746
|
return {};
|
|
33763
34747
|
try {
|
|
33764
34748
|
const parsed = JSON.parse(readFileSync28(registryPath, "utf-8"));
|
|
@@ -33776,7 +34760,7 @@ function readRegistry(registryPath = defaultRegistryPath()) {
|
|
|
33776
34760
|
}
|
|
33777
34761
|
function canonicalise(p) {
|
|
33778
34762
|
try {
|
|
33779
|
-
return
|
|
34763
|
+
return realpathSync10(p);
|
|
33780
34764
|
} catch {
|
|
33781
34765
|
return p;
|
|
33782
34766
|
}
|
|
@@ -33797,7 +34781,7 @@ function resolveEngagement(cwd, registry2) {
|
|
|
33797
34781
|
function isSelfOrAncestor(ancestor, target) {
|
|
33798
34782
|
if (ancestor === target)
|
|
33799
34783
|
return true;
|
|
33800
|
-
const withSep = ancestor.endsWith(
|
|
34784
|
+
const withSep = ancestor.endsWith(sep7) ? ancestor : ancestor + sep7;
|
|
33801
34785
|
return target.startsWith(withSep);
|
|
33802
34786
|
}
|
|
33803
34787
|
function runResolveEngagement(cwd, registryPath) {
|
|
@@ -33810,12 +34794,12 @@ function runResolveEngagement(cwd, registryPath) {
|
|
|
33810
34794
|
|
|
33811
34795
|
// dist/refresh-credential.js
|
|
33812
34796
|
import { readFileSync as readFileSync30 } from "node:fs";
|
|
33813
|
-
import { resolve as
|
|
34797
|
+
import { resolve as resolve11 } from "node:path";
|
|
33814
34798
|
|
|
33815
34799
|
// dist/mcp-headers.js
|
|
33816
34800
|
import { readFileSync as readFileSync29 } from "node:fs";
|
|
33817
|
-
import { homedir as
|
|
33818
|
-
import { dirname as dirname10, resolve as
|
|
34801
|
+
import { homedir as homedir17 } from "node:os";
|
|
34802
|
+
import { dirname as dirname10, resolve as resolve10 } from "node:path";
|
|
33819
34803
|
var URL_FLAG = "--url";
|
|
33820
34804
|
function urlFromArguments(rest) {
|
|
33821
34805
|
const at = [];
|
|
@@ -33842,12 +34826,12 @@ function headerLine(bearer, clientVersion) {
|
|
|
33842
34826
|
}
|
|
33843
34827
|
function projectRootFromBinary(binaryPath) {
|
|
33844
34828
|
const depth = VENDORED_BIN_REL.split("/").length - 1;
|
|
33845
|
-
return
|
|
34829
|
+
return resolve10(dirname10(binaryPath), ...Array(depth).fill(".."));
|
|
33846
34830
|
}
|
|
33847
34831
|
function readPinnedVersion(root) {
|
|
33848
34832
|
let raw;
|
|
33849
34833
|
try {
|
|
33850
|
-
raw = readFileSync29(
|
|
34834
|
+
raw = readFileSync29(resolve10(root, BUNDLE_PIN_REL), "utf-8");
|
|
33851
34835
|
} catch {
|
|
33852
34836
|
return void 0;
|
|
33853
34837
|
}
|
|
@@ -33889,7 +34873,7 @@ function sentences(lines2) {
|
|
|
33889
34873
|
}
|
|
33890
34874
|
function badIdSentence(root) {
|
|
33891
34875
|
return sentences([
|
|
33892
|
-
`${
|
|
34876
|
+
`${resolve10(root, BUNDLE_PIN_REL)} names an engagement id that is not a Halfcycle project id,`,
|
|
33893
34877
|
'so no credential was read. Delete that file and run "npx halfcycle" again: this repository',
|
|
33894
34878
|
"is then set up as a new Halfcycle project."
|
|
33895
34879
|
]);
|
|
@@ -33903,7 +34887,7 @@ function storeProblemSentence(problem, root, home, engagementId) {
|
|
|
33903
34887
|
]);
|
|
33904
34888
|
case "no-id":
|
|
33905
34889
|
return sentences([
|
|
33906
|
-
`${
|
|
34890
|
+
`${resolve10(root, BUNDLE_PIN_REL)} names no engagement id.`,
|
|
33907
34891
|
'run "npx halfcycle" here to rewrite it.'
|
|
33908
34892
|
]);
|
|
33909
34893
|
case "bad-id":
|
|
@@ -33920,7 +34904,7 @@ function storeProblemSentence(problem, root, home, engagementId) {
|
|
|
33920
34904
|
case "no-credential":
|
|
33921
34905
|
return sentences([
|
|
33922
34906
|
`this machine holds no credential for engagement ${engagementId ?? ""}.`,
|
|
33923
|
-
`run "npx halfcycle" in this repository \u2014 it will sign you in through your browser if needed, and write the credential to ${
|
|
34907
|
+
`run "npx halfcycle" in this repository \u2014 it will sign you in through your browser if needed, and write the credential to ${resolve10(home, HALFCYCLE_DIR_NAME)}, outside this repository.`
|
|
33924
34908
|
]);
|
|
33925
34909
|
}
|
|
33926
34910
|
}
|
|
@@ -33943,7 +34927,7 @@ async function refreshWithinDeadline(source, opts, writeErr) {
|
|
|
33943
34927
|
}
|
|
33944
34928
|
async function chooseBearer(opts) {
|
|
33945
34929
|
const writeErr = opts.writeErr ?? defaultWriteErr;
|
|
33946
|
-
const home = opts.home ??
|
|
34930
|
+
const home = opts.home ?? homedir17();
|
|
33947
34931
|
const root = projectRootFromBinary(opts.binaryPath);
|
|
33948
34932
|
const environmentToken = opts.environmentTokenFirst ? readEnvironmentToken() : void 0;
|
|
33949
34933
|
const store = resolveStore(root, home);
|
|
@@ -34086,8 +35070,8 @@ async function refreshCredentialToken(opts) {
|
|
|
34086
35070
|
source
|
|
34087
35071
|
});
|
|
34088
35072
|
if (!refreshed.ok) {
|
|
34089
|
-
const
|
|
34090
|
-
|
|
35073
|
+
const write2 = opts?.write ?? ((text) => process.stdout.write(text));
|
|
35074
|
+
write2(credentialRenewalFailedMessage(refreshed.remedy));
|
|
34091
35075
|
return { token: void 0 };
|
|
34092
35076
|
}
|
|
34093
35077
|
return { token: refreshed.token };
|
|
@@ -34109,7 +35093,7 @@ var SESSION_START_PROBE_ATTEMPTS = 2;
|
|
|
34109
35093
|
function registeredMcpUrl(projectRoot) {
|
|
34110
35094
|
let parsed;
|
|
34111
35095
|
try {
|
|
34112
|
-
parsed = JSON.parse(readFileSync30(
|
|
35096
|
+
parsed = JSON.parse(readFileSync30(resolve11(projectRoot, MCP_REGISTRATION_REL), "utf-8"));
|
|
34113
35097
|
} catch {
|
|
34114
35098
|
return void 0;
|
|
34115
35099
|
}
|
|
@@ -34140,6 +35124,10 @@ function discardBody(res) {
|
|
|
34140
35124
|
res.body?.cancel().catch(() => void 0);
|
|
34141
35125
|
}
|
|
34142
35126
|
var CUT_OFF = /* @__PURE__ */ Symbol("cut-off");
|
|
35127
|
+
function reportOf(body) {
|
|
35128
|
+
const instructions = body["result"]["instructions"];
|
|
35129
|
+
return typeof instructions === "string" ? checksReportOfInstructions(instructions) : "none";
|
|
35130
|
+
}
|
|
34143
35131
|
async function postInitialize(url2, bearer, fetchFn, signal) {
|
|
34144
35132
|
let res;
|
|
34145
35133
|
try {
|
|
@@ -34173,7 +35161,7 @@ async function postInitialize(url2, bearer, fetchFn, signal) {
|
|
|
34173
35161
|
} catch {
|
|
34174
35162
|
return SERVICE_PROBLEM_SENTENCE;
|
|
34175
35163
|
}
|
|
34176
|
-
return namesItsServer(body) ?
|
|
35164
|
+
return namesItsServer(body) ? { report: reportOf(body) } : SERVICE_PROBLEM_SENTENCE;
|
|
34177
35165
|
}
|
|
34178
35166
|
async function probeDelivery(url2, bearer, fetchFn, deadlineMs, maxAttempts) {
|
|
34179
35167
|
const controller = new AbortController();
|
|
@@ -34207,7 +35195,9 @@ async function checkConnection(renewedToken, opts) {
|
|
|
34207
35195
|
return { sentence: PLACEHOLDER_SENTENCES[bearer], url: url2, bearer, connected: false };
|
|
34208
35196
|
}
|
|
34209
35197
|
const outcome = await probeDelivery(url2, bearer, opts.fetchFn ?? globalThis.fetch, opts.checkDeadlineMs ?? CONNECTION_CHECK_DEADLINE_MS, opts.maxAttempts ?? SESSION_START_PROBE_ATTEMPTS);
|
|
34210
|
-
|
|
35198
|
+
if (typeof outcome === "string")
|
|
35199
|
+
return { sentence: outcome, url: url2, bearer, connected: false };
|
|
35200
|
+
return { sentence: connectedSentenceFor(profile), url: url2, bearer, connected: true, report: outcome.report };
|
|
34211
35201
|
}
|
|
34212
35202
|
function positionRequestBody(engagementId) {
|
|
34213
35203
|
return JSON.stringify({
|
|
@@ -34358,7 +35348,7 @@ async function runRefreshCredential(opts) {
|
|
|
34358
35348
|
import { fileURLToPath } from "node:url";
|
|
34359
35349
|
|
|
34360
35350
|
// dist/capture.js
|
|
34361
|
-
import { readFileSync as readFileSync31, writeFileSync as writeFileSync18, mkdirSync as mkdirSync12, existsSync as
|
|
35351
|
+
import { readFileSync as readFileSync31, writeFileSync as writeFileSync18, mkdirSync as mkdirSync12, existsSync as existsSync10 } from "node:fs";
|
|
34362
35352
|
import { dirname as dirname11 } from "node:path";
|
|
34363
35353
|
function runCapture(provider, endpoint, opts = {}) {
|
|
34364
35354
|
const repoRoot = opts.repoRoot ?? process.cwd();
|
|
@@ -34440,8 +35430,8 @@ function relativeFixturePath(repoRoot, fixture) {
|
|
|
34440
35430
|
import { spawn as spawn2, spawnSync as spawnSync3 } from "node:child_process";
|
|
34441
35431
|
import { createHash as createHash6, randomUUID as randomUUID3 } from "node:crypto";
|
|
34442
35432
|
import { createWriteStream, mkdirSync as mkdirSync13, readdirSync as readdirSync11, readFileSync as readFileSync32, renameSync as renameSync16, unlinkSync as unlinkSync12, writeFileSync as writeFileSync19 } from "node:fs";
|
|
34443
|
-
import { homedir as
|
|
34444
|
-
import { dirname as dirname12, join as
|
|
35433
|
+
import { homedir as homedir18 } from "node:os";
|
|
35434
|
+
import { dirname as dirname12, join as join23 } from "node:path";
|
|
34445
35435
|
|
|
34446
35436
|
// dist/test-counts.js
|
|
34447
35437
|
function sum(values) {
|
|
@@ -34550,7 +35540,7 @@ function isProofTestPath(path) {
|
|
|
34550
35540
|
function testRunsDir(engagementId, home) {
|
|
34551
35541
|
if (!isEngagementId(engagementId))
|
|
34552
35542
|
return null;
|
|
34553
|
-
return
|
|
35543
|
+
return join23(home ?? homedir18(), HALFCYCLE_DIR_NAME, ENGAGEMENTS_DIR_NAME, engagementId, TEST_RUNS_DIR_NAME);
|
|
34554
35544
|
}
|
|
34555
35545
|
function commandIdOf(command) {
|
|
34556
35546
|
return createHash6("sha256").update(command, "utf8").digest("hex").slice(0, 16);
|
|
@@ -34646,7 +35636,7 @@ function subjectKey(subject) {
|
|
|
34646
35636
|
}
|
|
34647
35637
|
function keptCheckPath(dir, subject, label) {
|
|
34648
35638
|
const key = createHash6("sha256").update(JSON.stringify([...subjectKey(subject), label]), "utf8").digest("hex");
|
|
34649
|
-
return
|
|
35639
|
+
return join23(dir, COMMANDS_DIR_NAME, `${key.slice(0, 32)}.json`);
|
|
34650
35640
|
}
|
|
34651
35641
|
function readKeptCheck(dir, subject, label) {
|
|
34652
35642
|
try {
|
|
@@ -34661,18 +35651,18 @@ function readKeptCheck(dir, subject, label) {
|
|
|
34661
35651
|
}
|
|
34662
35652
|
}
|
|
34663
35653
|
function queuePath(dir, runId) {
|
|
34664
|
-
return
|
|
35654
|
+
return join23(dir, QUEUE_DIR_NAME, `${runId}.json`);
|
|
34665
35655
|
}
|
|
34666
35656
|
function readQueue(dir) {
|
|
34667
35657
|
let names;
|
|
34668
35658
|
try {
|
|
34669
|
-
names = readdirSync11(
|
|
35659
|
+
names = readdirSync11(join23(dir, QUEUE_DIR_NAME)).filter((n) => n.endsWith(".json"));
|
|
34670
35660
|
} catch {
|
|
34671
35661
|
return [];
|
|
34672
35662
|
}
|
|
34673
35663
|
const reports = [];
|
|
34674
35664
|
for (const name of names) {
|
|
34675
|
-
const path =
|
|
35665
|
+
const path = join23(dir, QUEUE_DIR_NAME, name);
|
|
34676
35666
|
let parsed = null;
|
|
34677
35667
|
try {
|
|
34678
35668
|
parsed = testRunReportSchema.safeParse(JSON.parse(readFileSync32(path, "utf-8")));
|
|
@@ -34745,17 +35735,17 @@ function killTree(child, platform4, signal) {
|
|
|
34745
35735
|
}
|
|
34746
35736
|
}
|
|
34747
35737
|
}
|
|
34748
|
-
function runCommand(command, repoRoot,
|
|
35738
|
+
function runCommand(command, repoRoot, logPath2, env, deps) {
|
|
34749
35739
|
const platform4 = deps.platform ?? process.platform;
|
|
34750
35740
|
const out = deps.stdout ?? process.stdout;
|
|
34751
35741
|
const err = deps.stderr ?? process.stderr;
|
|
34752
35742
|
const deadline = deps.deadlineMs ?? PROVE_RUN_DEADLINE_MS;
|
|
34753
35743
|
const childEnv = { ...env };
|
|
34754
35744
|
delete childEnv[SERVICE_TOKEN_VAR];
|
|
34755
|
-
mkdirSync13(dirname12(
|
|
34756
|
-
const log = createWriteStream(
|
|
35745
|
+
mkdirSync13(dirname12(logPath2), { recursive: true, mode: 448 });
|
|
35746
|
+
const log = createWriteStream(logPath2, { mode: 384 });
|
|
34757
35747
|
const began = process.hrtime.bigint();
|
|
34758
|
-
return new Promise((
|
|
35748
|
+
return new Promise((resolve12) => {
|
|
34759
35749
|
let timedOut = false;
|
|
34760
35750
|
let started = true;
|
|
34761
35751
|
let settled2 = false;
|
|
@@ -34790,7 +35780,7 @@ function runCommand(command, repoRoot, logPath, env, deps) {
|
|
|
34790
35780
|
process.off("SIGINT", onSignal);
|
|
34791
35781
|
process.off("SIGTERM", onSignal);
|
|
34792
35782
|
const durationMs = Number((process.hrtime.bigint() - began) / 1000000n);
|
|
34793
|
-
log.end(() =>
|
|
35783
|
+
log.end(() => resolve12({ exitCode: timedOut || !started ? null : code, timedOut, started, durationMs }));
|
|
34794
35784
|
};
|
|
34795
35785
|
child.on("error", (e) => {
|
|
34796
35786
|
started = false;
|
|
@@ -34912,13 +35902,13 @@ ${PROVE_USAGE}`);
|
|
|
34912
35902
|
if (request.when === "before" && changedOutsideTests > 0)
|
|
34913
35903
|
say(lateBeforeLine(changedOutsideTests));
|
|
34914
35904
|
const runId = randomUUID3();
|
|
34915
|
-
const
|
|
35905
|
+
const logPath2 = join23(dir, `${runId}.log`);
|
|
34916
35906
|
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
34917
35907
|
const deadline = deps.deadlineMs ?? PROVE_RUN_DEADLINE_MS;
|
|
34918
|
-
const end = await runCommand(command, repoRoot,
|
|
35908
|
+
const end = await runCommand(command, repoRoot, logPath2, env, deps);
|
|
34919
35909
|
let output = "";
|
|
34920
35910
|
try {
|
|
34921
|
-
output = readFileSync32(
|
|
35911
|
+
output = readFileSync32(logPath2, "utf-8");
|
|
34922
35912
|
} catch {
|
|
34923
35913
|
output = "";
|
|
34924
35914
|
}
|
|
@@ -34962,7 +35952,7 @@ ${PROVE_USAGE}`);
|
|
|
34962
35952
|
sendLine = mine.outcome === "recorded" ? RECORDED_LINE : mine.outcome === "kept" ? NOT_SENT_YET_LINE : refusedLine(mine.refusal);
|
|
34963
35953
|
}
|
|
34964
35954
|
say(`${line2} ${sendLine}`);
|
|
34965
|
-
say(`Its output is kept on this computer at ${
|
|
35955
|
+
say(`Its output is kept on this computer at ${logPath2}`);
|
|
34966
35956
|
return 0;
|
|
34967
35957
|
}
|
|
34968
35958
|
|
|
@@ -35030,14 +36020,14 @@ function personCommandEnv(env) {
|
|
|
35030
36020
|
}
|
|
35031
36021
|
return out;
|
|
35032
36022
|
}
|
|
35033
|
-
var runOwnCommandReal = (command, input, env) => new Promise((
|
|
36023
|
+
var runOwnCommandReal = (command, input, env) => new Promise((resolve12) => {
|
|
35034
36024
|
let out = "";
|
|
35035
36025
|
let settled2 = false;
|
|
35036
36026
|
const done = (v) => {
|
|
35037
36027
|
if (settled2)
|
|
35038
36028
|
return;
|
|
35039
36029
|
settled2 = true;
|
|
35040
|
-
|
|
36030
|
+
resolve12(v);
|
|
35041
36031
|
};
|
|
35042
36032
|
try {
|
|
35043
36033
|
const child = spawn3(command, {
|
|
@@ -35126,7 +36116,8 @@ async function checkConnectionLine(opts) {
|
|
|
35126
36116
|
});
|
|
35127
36117
|
if (result === void 0)
|
|
35128
36118
|
return { kind: "not-registered", sentence: null };
|
|
35129
|
-
|
|
36119
|
+
const line2 = { kind: connectionKind(result.bearer, result.sentence), sentence: result.sentence };
|
|
36120
|
+
return result.report === void 0 || result.report === "none" ? line2 : { ...line2, report: result.report };
|
|
35130
36121
|
}
|
|
35131
36122
|
async function runCheckConnection(opts) {
|
|
35132
36123
|
const line2 = await checkConnectionLine(opts);
|
|
@@ -35185,7 +36176,7 @@ async function main() {
|
|
|
35185
36176
|
if (cmd === "time") {
|
|
35186
36177
|
let line2;
|
|
35187
36178
|
try {
|
|
35188
|
-
line2 = JSON.stringify(await runTimeVerb());
|
|
36179
|
+
line2 = JSON.stringify(await runTimeVerb({}, { final: args.slice(1).includes("--final") }));
|
|
35189
36180
|
} catch {
|
|
35190
36181
|
line2 = JSON.stringify({ outcome: "not-sent", reason: "unreachable" });
|
|
35191
36182
|
}
|
|
@@ -35351,7 +36342,7 @@ function unknownCommand(name = args.join(" ")) {
|
|
|
35351
36342
|
halfcycle-runner mcp-headers [--url <address>]
|
|
35352
36343
|
halfcycle-runner observe
|
|
35353
36344
|
halfcycle-runner observe --change <sortingId>
|
|
35354
|
-
halfcycle-runner time
|
|
36345
|
+
halfcycle-runner time [--final]
|
|
35355
36346
|
halfcycle-runner prove <phase> <task> --label <label> --before|--after [-- <command>]
|
|
35356
36347
|
halfcycle-runner pace [--start <phase> [--agents <n>]]
|
|
35357
36348
|
halfcycle-runner pace --scan [--config-folder <dir>]
|
|
@@ -35362,10 +36353,10 @@ function unknownCommand(name = args.join(" ")) {
|
|
|
35362
36353
|
process.exit(1);
|
|
35363
36354
|
}
|
|
35364
36355
|
function readStdin3() {
|
|
35365
|
-
return new Promise((
|
|
36356
|
+
return new Promise((resolve12, reject) => {
|
|
35366
36357
|
const chunks = [];
|
|
35367
36358
|
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
35368
|
-
process.stdin.on("end", () =>
|
|
36359
|
+
process.stdin.on("end", () => resolve12(Buffer.concat(chunks).toString("utf-8")));
|
|
35369
36360
|
process.stdin.on("error", reject);
|
|
35370
36361
|
});
|
|
35371
36362
|
}
|