@brainervirus/workit-cursor 8.9.1 → 8.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor-plugin/plugin.json +1 -1
- package/dist/cursor-session-start.js +424 -386
- package/dist/mcp-server.js +85 -77
- package/dist/workit-hook.js +430 -385
- package/package.json +3 -3
- package/rules/workit-contract.mdc +4 -1
- package/skills/workit-fanout/references/brief.md +1 -1
- package/skills/workit-fanout/references/orchestration.md +16 -6
- package/skills/workit-implement/SKILL.md +3 -2
- package/skills/workit-review/SKILL.md +4 -2
package/dist/workit-hook.js
CHANGED
|
@@ -8377,7 +8377,7 @@ import { realpathSync as realpathSync4 } from "node:fs";
|
|
|
8377
8377
|
|
|
8378
8378
|
// packages/workit-core/src/core/policy/derive.ts
|
|
8379
8379
|
import { existsSync as existsSync2 } from "node:fs";
|
|
8380
|
-
import
|
|
8380
|
+
import path8 from "node:path";
|
|
8381
8381
|
|
|
8382
8382
|
// packages/workit-core/src/git/rev.ts
|
|
8383
8383
|
import { spawnSync } from "node:child_process";
|
|
@@ -8562,9 +8562,9 @@ function pushRemoteName(cwd, branch) {
|
|
|
8562
8562
|
|
|
8563
8563
|
// packages/workit-core/src/ledger.ts
|
|
8564
8564
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
8565
|
-
import { createHash as
|
|
8566
|
-
import
|
|
8567
|
-
import
|
|
8565
|
+
import { createHash as createHash7, randomBytes } from "node:crypto";
|
|
8566
|
+
import fs5 from "node:fs";
|
|
8567
|
+
import path7 from "node:path";
|
|
8568
8568
|
|
|
8569
8569
|
// packages/workit-core/src/core/vcs-config.ts
|
|
8570
8570
|
import fs2 from "node:fs";
|
|
@@ -9799,33 +9799,9 @@ function vcsConfig(mode, cwd, options = {}) {
|
|
|
9799
9799
|
}
|
|
9800
9800
|
|
|
9801
9801
|
// packages/workit-core/src/host-session.ts
|
|
9802
|
-
|
|
9803
|
-
|
|
9804
|
-
|
|
9805
|
-
[
|
|
9806
|
-
"CODEX_THREAD_ID",
|
|
9807
|
-
(env) => env.CODEX_INTERNAL_ORIGINATOR_OVERRIDE === "Codex Desktop" || env.CODEX_ELECTRON_RESOURCES_PATH ? "codex_desktop" : "codex_cli"
|
|
9808
|
-
]
|
|
9809
|
-
];
|
|
9810
|
-
var family = (host) => host?.replace(/_(?:cli|desktop)$/, "") ?? null;
|
|
9811
|
-
function hostSessionFromEnv(env) {
|
|
9812
|
-
const value = (key) => env[key]?.trim() || null;
|
|
9813
|
-
let inner = null;
|
|
9814
|
-
for (const [key, host] of HOST_SESSION_VARS) {
|
|
9815
|
-
const session = value(key);
|
|
9816
|
-
if (session) {
|
|
9817
|
-
inner = { host: host(env), session };
|
|
9818
|
-
break;
|
|
9819
|
-
}
|
|
9820
|
-
}
|
|
9821
|
-
const declared = value("WORKIT_HOST");
|
|
9822
|
-
if (env.WORKIT_SESSION_ID !== undefined) {
|
|
9823
|
-
const inherited = inner !== null && declared !== null && family(declared) !== family(inner.host);
|
|
9824
|
-
if (!inherited)
|
|
9825
|
-
return { host: declared, session: value("WORKIT_SESSION_ID") };
|
|
9826
|
-
}
|
|
9827
|
-
return inner ? { host: inner.host, session: inner.session } : { host: declared, session: null };
|
|
9828
|
-
}
|
|
9802
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
9803
|
+
import fs4 from "node:fs";
|
|
9804
|
+
import path6 from "node:path";
|
|
9829
9805
|
|
|
9830
9806
|
// packages/workit-core/src/store/paths.ts
|
|
9831
9807
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
@@ -10107,6 +10083,63 @@ var checkoutSlug = (root) => {
|
|
|
10107
10083
|
return `${base}-${shortHash(canonical)}`;
|
|
10108
10084
|
};
|
|
10109
10085
|
|
|
10086
|
+
// packages/workit-core/src/host-session.ts
|
|
10087
|
+
var HOST_SESSION_VARS = [
|
|
10088
|
+
["OPENCODE_SESSION_ID", () => "opencode"],
|
|
10089
|
+
["PI_SESSION_ID", () => "pi"],
|
|
10090
|
+
[
|
|
10091
|
+
"CODEX_THREAD_ID",
|
|
10092
|
+
(env) => env.CODEX_INTERNAL_ORIGINATOR_OVERRIDE === "Codex Desktop" || env.CODEX_ELECTRON_RESOURCES_PATH ? "codex_desktop" : "codex_cli"
|
|
10093
|
+
]
|
|
10094
|
+
];
|
|
10095
|
+
var family = (host) => host?.replace(/_(?:cli|desktop)$/, "") ?? null;
|
|
10096
|
+
function hostSessionFromEnv(env) {
|
|
10097
|
+
const value = (key) => env[key]?.trim() || null;
|
|
10098
|
+
let inner = null;
|
|
10099
|
+
for (const [key, host] of HOST_SESSION_VARS) {
|
|
10100
|
+
const session = value(key);
|
|
10101
|
+
if (session) {
|
|
10102
|
+
inner = { host: host(env), session };
|
|
10103
|
+
break;
|
|
10104
|
+
}
|
|
10105
|
+
}
|
|
10106
|
+
const declared = value("WORKIT_HOST");
|
|
10107
|
+
if (env.WORKIT_SESSION_ID !== undefined) {
|
|
10108
|
+
const inherited = inner !== null && declared !== null && family(declared) !== family(inner.host);
|
|
10109
|
+
if (!inherited)
|
|
10110
|
+
return { host: declared, session: value("WORKIT_SESSION_ID") };
|
|
10111
|
+
}
|
|
10112
|
+
return inner ? { host: inner.host, session: inner.session } : { host: declared, session: null };
|
|
10113
|
+
}
|
|
10114
|
+
var ISSUED_PER_LEAD = 64;
|
|
10115
|
+
var ISSUED_SESSIONS_MARKER = "workit-issued-sessions/1";
|
|
10116
|
+
var hash = (value) => createHash6("sha256").update(value).digest("hex").slice(0, 32);
|
|
10117
|
+
var issuedRoot = (cwd) => {
|
|
10118
|
+
const location = resolveStore(cwd);
|
|
10119
|
+
return location instanceof Error ? null : path6.join(location.dir, "hooks", "issued");
|
|
10120
|
+
};
|
|
10121
|
+
var issuedDir = (cwd, lead) => {
|
|
10122
|
+
const root = issuedRoot(cwd);
|
|
10123
|
+
return root === null ? null : path6.join(root, hash(lead));
|
|
10124
|
+
};
|
|
10125
|
+
function recordIssuedSession(cwd, lead, issued) {
|
|
10126
|
+
try {
|
|
10127
|
+
const dir = issuedDir(cwd, lead);
|
|
10128
|
+
if (!dir)
|
|
10129
|
+
return;
|
|
10130
|
+
fs4.mkdirSync(dir, { recursive: true });
|
|
10131
|
+
const own = hash(issued);
|
|
10132
|
+
fs4.writeFileSync(path6.join(dir, own), ISSUED_SESSIONS_MARKER);
|
|
10133
|
+
const entries = fs4.readdirSync(dir);
|
|
10134
|
+
if (entries.length <= ISSUED_PER_LEAD)
|
|
10135
|
+
return;
|
|
10136
|
+
const byAge = entries.filter((name) => name !== own).map((name) => ({ name, at: fs4.statSync(path6.join(dir, name)).mtimeMs })).toSorted((a, b) => a.at - b.at);
|
|
10137
|
+
for (const { name } of byAge.slice(0, entries.length - ISSUED_PER_LEAD))
|
|
10138
|
+
fs4.rmSync(path6.join(dir, name), { force: true });
|
|
10139
|
+
} catch {}
|
|
10140
|
+
}
|
|
10141
|
+
var OWN_CHILD_SHELL = new Set(["opencode", "pi"]);
|
|
10142
|
+
|
|
10110
10143
|
// packages/workit-core/src/ledger.ts
|
|
10111
10144
|
var LEDGER_VERSION = 1;
|
|
10112
10145
|
var MAX_LINE_BYTES = 4096;
|
|
@@ -10212,7 +10245,7 @@ function diffHash(cwd, base, head) {
|
|
|
10212
10245
|
], GIT_TIMEOUTS.worktree);
|
|
10213
10246
|
if (!diff.ok || !diff.stdout)
|
|
10214
10247
|
return null;
|
|
10215
|
-
const hash =
|
|
10248
|
+
const hash = createHash7("sha256");
|
|
10216
10249
|
for (const line of diff.stdout.split(`
|
|
10217
10250
|
`)) {
|
|
10218
10251
|
if (line.startsWith("index "))
|
|
@@ -10224,14 +10257,14 @@ function diffHash(cwd, base, head) {
|
|
|
10224
10257
|
return `sha256:${hash.digest("hex")}`;
|
|
10225
10258
|
}
|
|
10226
10259
|
function storeRoot(cwd) {
|
|
10227
|
-
const location = resolveStore(
|
|
10260
|
+
const location = resolveStore(path7.resolve(cwd));
|
|
10228
10261
|
if (location instanceof Error)
|
|
10229
10262
|
return err("unavailable", location.message.replace(/; fix the repository.*$/u, ""), "fix the repository (git status should work here) or run from a non-git directory");
|
|
10230
10263
|
return { ok: true, value: { root: location.dir, shared: location.shared } };
|
|
10231
10264
|
}
|
|
10232
10265
|
function ledgerPath(cwd) {
|
|
10233
10266
|
const root = storeRoot(cwd);
|
|
10234
|
-
return root.ok ? { ok: true, value:
|
|
10267
|
+
return root.ok ? { ok: true, value: path7.join(root.value.root, "ledger", "ledger.jsonl") } : root;
|
|
10235
10268
|
}
|
|
10236
10269
|
var newId2 = () => `${Date.now().toString(36)}-${randomBytes(6).toString("hex")}`;
|
|
10237
10270
|
var NETWORK_FS_TYPES = new Set([
|
|
@@ -10251,7 +10284,7 @@ var onNetworkFs = (dir) => {
|
|
|
10251
10284
|
if (process.platform !== "linux")
|
|
10252
10285
|
return false;
|
|
10253
10286
|
try {
|
|
10254
|
-
return isNetworkFsType(
|
|
10287
|
+
return isNetworkFsType(fs5.statfsSync(dir).type);
|
|
10255
10288
|
} catch {
|
|
10256
10289
|
return false;
|
|
10257
10290
|
}
|
|
@@ -10261,15 +10294,15 @@ var LOCK_STALE_MS = 30000;
|
|
|
10261
10294
|
var LOCK_OWNER = "owner";
|
|
10262
10295
|
var lockToken = (lock) => {
|
|
10263
10296
|
try {
|
|
10264
|
-
return
|
|
10297
|
+
return fs5.readFileSync(path7.join(lock, LOCK_OWNER), "utf8");
|
|
10265
10298
|
} catch {
|
|
10266
10299
|
return null;
|
|
10267
10300
|
}
|
|
10268
10301
|
};
|
|
10269
10302
|
var lockAgeMs = (lock) => {
|
|
10270
|
-
for (const target of [
|
|
10303
|
+
for (const target of [path7.join(lock, LOCK_OWNER), lock]) {
|
|
10271
10304
|
try {
|
|
10272
|
-
return Date.now() -
|
|
10305
|
+
return Date.now() - fs5.statSync(target).mtimeMs;
|
|
10273
10306
|
} catch {}
|
|
10274
10307
|
}
|
|
10275
10308
|
return null;
|
|
@@ -10277,14 +10310,14 @@ var lockAgeMs = (lock) => {
|
|
|
10277
10310
|
var ledgerLock = {
|
|
10278
10311
|
acquire(lock) {
|
|
10279
10312
|
try {
|
|
10280
|
-
|
|
10313
|
+
fs5.mkdirSync(lock);
|
|
10281
10314
|
} catch (error) {
|
|
10282
10315
|
if (error.code === "EEXIST")
|
|
10283
10316
|
return null;
|
|
10284
10317
|
throw error;
|
|
10285
10318
|
}
|
|
10286
10319
|
const token = `${process.pid}-${randomBytes(8).toString("hex")}`;
|
|
10287
|
-
|
|
10320
|
+
fs5.writeFileSync(path7.join(lock, LOCK_OWNER), token);
|
|
10288
10321
|
return token;
|
|
10289
10322
|
},
|
|
10290
10323
|
release(lock, token) {
|
|
@@ -10292,35 +10325,35 @@ var ledgerLock = {
|
|
|
10292
10325
|
return false;
|
|
10293
10326
|
const tomb = `${lock}.release-${randomBytes(6).toString("hex")}`;
|
|
10294
10327
|
try {
|
|
10295
|
-
|
|
10328
|
+
fs5.renameSync(lock, tomb);
|
|
10296
10329
|
} catch {
|
|
10297
10330
|
return false;
|
|
10298
10331
|
}
|
|
10299
10332
|
if (lockToken(tomb) !== token) {
|
|
10300
10333
|
try {
|
|
10301
|
-
|
|
10334
|
+
fs5.renameSync(tomb, lock);
|
|
10302
10335
|
} catch {}
|
|
10303
10336
|
return false;
|
|
10304
10337
|
}
|
|
10305
|
-
|
|
10338
|
+
fs5.rmSync(tomb, { recursive: true, force: true });
|
|
10306
10339
|
return true;
|
|
10307
10340
|
},
|
|
10308
10341
|
token: lockToken,
|
|
10309
10342
|
reap(lock, observed) {
|
|
10310
10343
|
const tomb = `${lock}.reap-${randomBytes(6).toString("hex")}`;
|
|
10311
10344
|
try {
|
|
10312
|
-
|
|
10345
|
+
fs5.renameSync(lock, tomb);
|
|
10313
10346
|
} catch {
|
|
10314
10347
|
return false;
|
|
10315
10348
|
}
|
|
10316
10349
|
if (lockToken(tomb) === observed) {
|
|
10317
|
-
|
|
10350
|
+
fs5.rmSync(tomb, { recursive: true, force: true });
|
|
10318
10351
|
return true;
|
|
10319
10352
|
}
|
|
10320
10353
|
try {
|
|
10321
|
-
|
|
10354
|
+
fs5.renameSync(tomb, lock);
|
|
10322
10355
|
} catch {
|
|
10323
|
-
|
|
10356
|
+
fs5.rmSync(tomb, { recursive: true, force: true });
|
|
10324
10357
|
}
|
|
10325
10358
|
return false;
|
|
10326
10359
|
}
|
|
@@ -10347,14 +10380,14 @@ function withLedgerLock(file, fn, waitMs = LOCK_WAIT_MS) {
|
|
|
10347
10380
|
ledgerLock.release(lock, token);
|
|
10348
10381
|
}
|
|
10349
10382
|
}
|
|
10350
|
-
var sha2562 = (text) =>
|
|
10383
|
+
var sha2562 = (text) => createHash7("sha256").update(text).digest("hex");
|
|
10351
10384
|
var chainHash = (prevHash, body) => sha2562(`${prevHash ?? ""}
|
|
10352
10385
|
${body}`);
|
|
10353
10386
|
var TAIL_BYTES = 64 * 1024;
|
|
10354
10387
|
var lastLine = (fd, size) => {
|
|
10355
10388
|
for (let span = Math.min(size, TAIL_BYTES);span > 0; span = Math.min(size, span * 2)) {
|
|
10356
10389
|
const buffer = Buffer.alloc(span);
|
|
10357
|
-
|
|
10390
|
+
fs5.readSync(fd, buffer, 0, span, size - span);
|
|
10358
10391
|
const end = buffer.lastIndexOf(10);
|
|
10359
10392
|
if (end < 0) {
|
|
10360
10393
|
if (span === size)
|
|
@@ -10385,13 +10418,13 @@ var lastLine = (fd, size) => {
|
|
|
10385
10418
|
};
|
|
10386
10419
|
function appendLine(file, build, options) {
|
|
10387
10420
|
const write = () => {
|
|
10388
|
-
const fd =
|
|
10421
|
+
const fd = fs5.openSync(file, "a+");
|
|
10389
10422
|
try {
|
|
10390
|
-
const size =
|
|
10423
|
+
const size = fs5.fstatSync(fd).size;
|
|
10391
10424
|
let fence = "";
|
|
10392
10425
|
if (size > 0) {
|
|
10393
10426
|
const last = Buffer.alloc(1);
|
|
10394
|
-
|
|
10427
|
+
fs5.readSync(fd, last, 0, 1, size - 1);
|
|
10395
10428
|
if (last[0] !== 10)
|
|
10396
10429
|
fence = `
|
|
10397
10430
|
`;
|
|
@@ -10400,17 +10433,17 @@ function appendLine(file, build, options) {
|
|
|
10400
10433
|
if (!line.ok)
|
|
10401
10434
|
return line;
|
|
10402
10435
|
const bytes = Buffer.from(fence + line.value);
|
|
10403
|
-
const written =
|
|
10436
|
+
const written = fs5.writeSync(fd, bytes);
|
|
10404
10437
|
if (written !== bytes.length)
|
|
10405
10438
|
return err("unavailable", `short write to ${file}: ${written} of ${bytes.length} bytes; the row is torn and will be skipped`);
|
|
10406
10439
|
return { ok: true, value: undefined };
|
|
10407
10440
|
} finally {
|
|
10408
|
-
|
|
10441
|
+
fs5.closeSync(fd);
|
|
10409
10442
|
}
|
|
10410
10443
|
};
|
|
10411
10444
|
try {
|
|
10412
|
-
|
|
10413
|
-
if (!options.forceLock && !onNetworkFs(
|
|
10445
|
+
fs5.mkdirSync(path7.dirname(file), { recursive: true });
|
|
10446
|
+
if (!options.forceLock && !onNetworkFs(path7.dirname(file)))
|
|
10414
10447
|
return write();
|
|
10415
10448
|
const locked = withLedgerLock(file, write);
|
|
10416
10449
|
return locked ?? err("busy", `ledger lock ${file}.lock is held`, "retry; remove the .lock directory if no workit process is running");
|
|
@@ -10482,7 +10515,7 @@ function readLedger(cwd, options = {}) {
|
|
|
10482
10515
|
return file;
|
|
10483
10516
|
let text = "";
|
|
10484
10517
|
try {
|
|
10485
|
-
text =
|
|
10518
|
+
text = fs5.readFileSync(file.value, "utf8");
|
|
10486
10519
|
} catch (error) {
|
|
10487
10520
|
if (error.code === "ENOENT")
|
|
10488
10521
|
return {
|
|
@@ -10676,11 +10709,20 @@ function authorSessions(cwd, rows, branch, range = { base: null, head: null }, s
|
|
|
10676
10709
|
sessions.add(session);
|
|
10677
10710
|
return sessions;
|
|
10678
10711
|
}
|
|
10712
|
+
var derivesFrom = (derived, bare) => !bare.includes(":") && derived.endsWith(`:${bare}`);
|
|
10713
|
+
var authoredBy = (authors, session) => {
|
|
10714
|
+
if (authors.has(session))
|
|
10715
|
+
return true;
|
|
10716
|
+
for (const author of authors)
|
|
10717
|
+
if (derivesFrom(author, session) || derivesFrom(session, author))
|
|
10718
|
+
return true;
|
|
10719
|
+
return false;
|
|
10720
|
+
};
|
|
10679
10721
|
var independenceReasons = (row, authors) => {
|
|
10680
10722
|
const reasons = [];
|
|
10681
10723
|
if (!row.actor.session)
|
|
10682
10724
|
reasons.push("no_session");
|
|
10683
|
-
else if (authors
|
|
10725
|
+
else if (authoredBy(authors, row.actor.session))
|
|
10684
10726
|
reasons.push("author_session");
|
|
10685
10727
|
if (row.self === true && !reasons.includes("no_session"))
|
|
10686
10728
|
reasons.push("self");
|
|
@@ -10964,7 +11006,7 @@ var productDecision = (task, ledger) => {
|
|
|
10964
11006
|
};
|
|
10965
11007
|
};
|
|
10966
11008
|
var planRecorded = (task, root) => {
|
|
10967
|
-
const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync2(
|
|
11009
|
+
const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync2(path8.resolve(root, ref.path)));
|
|
10968
11010
|
if (cited)
|
|
10969
11011
|
return {
|
|
10970
11012
|
met: true,
|
|
@@ -11580,7 +11622,7 @@ var judgeInputSummary = (raw) => {
|
|
|
11580
11622
|
|
|
11581
11623
|
// packages/workit-core/src/autonomy.ts
|
|
11582
11624
|
import os3 from "node:os";
|
|
11583
|
-
import
|
|
11625
|
+
import path9 from "node:path";
|
|
11584
11626
|
var accountHome = () => {
|
|
11585
11627
|
try {
|
|
11586
11628
|
return os3.userInfo().homedir;
|
|
@@ -11589,10 +11631,10 @@ var accountHome = () => {
|
|
|
11589
11631
|
}
|
|
11590
11632
|
};
|
|
11591
11633
|
var grantsHome = { resolve: accountHome };
|
|
11592
|
-
var grantsDir = () =>
|
|
11634
|
+
var grantsDir = () => path9.join(grantsHome.resolve(), ".config", "workit");
|
|
11593
11635
|
var grantsOverride = () => {
|
|
11594
|
-
const configured =
|
|
11595
|
-
return configured ===
|
|
11636
|
+
const configured = path9.resolve(resolveConfigDir());
|
|
11637
|
+
return configured === path9.resolve(grantsDir()) ? null : `the config directory is redirected to ${configured} (WORKFLOW_TOOLKIT_CONFIG, WORKFLOW_TOOLKIT_CONFIG_DIR or XDG_CONFIG_HOME); grants are read only from ${path9.join(grantsDir(), "workspaces.json")}, so the D4 defaults apply`;
|
|
11596
11638
|
};
|
|
11597
11639
|
var GRANT_KINDS = ["push", "pr", "merge", "release", "rerun"];
|
|
11598
11640
|
var DEFAULT_GRANTS = Object.freeze({
|
|
@@ -11716,9 +11758,9 @@ var suggested = (kind) => kind === "merge" ? "verified" : "true";
|
|
|
11716
11758
|
var grantHint = (workspace, kind) => `ask the user to run, in their own terminal: workit grant set ${workspace ?? "<workspace>"} ${kind}=${suggested(kind)}`;
|
|
11717
11759
|
|
|
11718
11760
|
// packages/workit-core/src/core/task-store.ts
|
|
11719
|
-
import { createHash as
|
|
11720
|
-
import * as
|
|
11721
|
-
import
|
|
11761
|
+
import { createHash as createHash9, randomUUID as randomUUID3 } from "node:crypto";
|
|
11762
|
+
import * as fs11 from "node:fs";
|
|
11763
|
+
import path14 from "node:path";
|
|
11722
11764
|
|
|
11723
11765
|
// node_modules/@openclaw/fs-safe/dist/errors.js
|
|
11724
11766
|
var OPERATIONAL_CODES = new Set([
|
|
@@ -11769,10 +11811,10 @@ function sameFileIdentity(left, right, platform = process.platform) {
|
|
|
11769
11811
|
// node_modules/@openclaw/fs-safe/dist/sidecar-lock-reclaim.js
|
|
11770
11812
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
11771
11813
|
import fsSync from "node:fs";
|
|
11772
|
-
import
|
|
11814
|
+
import path10 from "node:path";
|
|
11773
11815
|
|
|
11774
11816
|
// node_modules/@openclaw/fs-safe/dist/bounded-read.js
|
|
11775
|
-
import
|
|
11817
|
+
import fs6 from "node:fs";
|
|
11776
11818
|
|
|
11777
11819
|
// node_modules/@openclaw/fs-safe/dist/byte-budget.js
|
|
11778
11820
|
function normalizeMaxBytes(value, options = {}) {
|
|
@@ -11809,7 +11851,7 @@ function readFileDescriptorBoundedSync(fd, maxBytes) {
|
|
|
11809
11851
|
let total = 0;
|
|
11810
11852
|
while (true) {
|
|
11811
11853
|
const length = nextReadLength(total, maxBytes, scratch.length);
|
|
11812
|
-
const bytesRead =
|
|
11854
|
+
const bytesRead = fs6.readSync(fd, scratch, 0, length, null);
|
|
11813
11855
|
if (bytesRead === 0) {
|
|
11814
11856
|
return Buffer.concat(chunks, total);
|
|
11815
11857
|
}
|
|
@@ -11818,9 +11860,9 @@ function readFileDescriptorBoundedSync(fd, maxBytes) {
|
|
|
11818
11860
|
}
|
|
11819
11861
|
|
|
11820
11862
|
// node_modules/@openclaw/fs-safe/dist/read-open-flags.js
|
|
11821
|
-
import
|
|
11863
|
+
import fs7 from "node:fs";
|
|
11822
11864
|
function resolveReadOpenFlags(options) {
|
|
11823
|
-
const constants = options?.constants ??
|
|
11865
|
+
const constants = options?.constants ?? fs7.constants;
|
|
11824
11866
|
const noFollow = process.platform !== "win32" && options?.followSymlinks !== true && typeof constants.O_NOFOLLOW === "number" ? constants.O_NOFOLLOW : 0;
|
|
11825
11867
|
const nonBlocking = process.platform !== "win32" && typeof constants.O_NONBLOCK === "number" ? constants.O_NONBLOCK : 0;
|
|
11826
11868
|
return constants.O_RDONLY | noFollow | nonBlocking;
|
|
@@ -11859,13 +11901,13 @@ ${ownershipToken}
|
|
|
11859
11901
|
return { raw, ownershipToken };
|
|
11860
11902
|
}
|
|
11861
11903
|
function relativeSidecarLockPath(lockRoot, lockPath) {
|
|
11862
|
-
const resolved =
|
|
11863
|
-
const lexicalRelative =
|
|
11864
|
-
const relative = lexicalRelative !== ".." && !lexicalRelative.startsWith(`..${
|
|
11865
|
-
if (!relative || relative === ".." || relative.startsWith(`..${
|
|
11904
|
+
const resolved = path10.resolve(lockPath);
|
|
11905
|
+
const lexicalRelative = path10.relative(lockRoot.rootDir, resolved);
|
|
11906
|
+
const relative = lexicalRelative !== ".." && !lexicalRelative.startsWith(`..${path10.sep}`) && !path10.isAbsolute(lexicalRelative) ? lexicalRelative : path10.relative(lockRoot.rootReal, resolved);
|
|
11907
|
+
if (!relative || relative === ".." || relative.startsWith(`..${path10.sep}`) || path10.isAbsolute(relative)) {
|
|
11866
11908
|
throw new FsSafeError("outside-workspace", "sidecar lock path is outside lockRoot");
|
|
11867
11909
|
}
|
|
11868
|
-
return relative.split(
|
|
11910
|
+
return relative.split(path10.sep).join(path10.posix.sep);
|
|
11869
11911
|
}
|
|
11870
11912
|
function parseSidecarLockPayload(raw, parser) {
|
|
11871
11913
|
if (parser) {
|
|
@@ -12011,8 +12053,8 @@ function getFsSafeLockConfig() {
|
|
|
12011
12053
|
}
|
|
12012
12054
|
|
|
12013
12055
|
// node_modules/@openclaw/fs-safe/dist/file-lock-sync.js
|
|
12014
|
-
import
|
|
12015
|
-
import
|
|
12056
|
+
import fs8 from "node:fs";
|
|
12057
|
+
import path11 from "node:path";
|
|
12016
12058
|
|
|
12017
12059
|
// node_modules/@openclaw/fs-safe/dist/timing.js
|
|
12018
12060
|
function sleepSync(ms) {
|
|
@@ -12042,7 +12084,7 @@ function releaseAllSyncHeldLocks() {
|
|
|
12042
12084
|
}
|
|
12043
12085
|
try {
|
|
12044
12086
|
if (held.fd !== undefined)
|
|
12045
|
-
|
|
12087
|
+
fs8.closeSync(held.fd);
|
|
12046
12088
|
} catch {}
|
|
12047
12089
|
try {
|
|
12048
12090
|
removeSidecarLockIfUnchangedSync(held.lockPath, held.snapshot);
|
|
@@ -12077,7 +12119,7 @@ function releaseSyncHeldLock(held) {
|
|
|
12077
12119
|
if (held.fd !== undefined) {
|
|
12078
12120
|
const fd = held.fd;
|
|
12079
12121
|
held.fd = undefined;
|
|
12080
|
-
|
|
12122
|
+
fs8.closeSync(fd);
|
|
12081
12123
|
}
|
|
12082
12124
|
removeSidecarLockIfUnchangedSync(held.lockPath, held.snapshot);
|
|
12083
12125
|
heldLocks.delete(held.normalizedTargetPath);
|
|
@@ -12100,29 +12142,29 @@ function createSyncHeldLockHandle(held) {
|
|
|
12100
12142
|
};
|
|
12101
12143
|
}
|
|
12102
12144
|
function canonicalLockParentSync(parent) {
|
|
12103
|
-
return process.platform === "win32" ?
|
|
12145
|
+
return process.platform === "win32" ? fs8.realpathSync.native(parent) : fs8.realpathSync(parent);
|
|
12104
12146
|
}
|
|
12105
12147
|
function normalizeTargetPath(targetPath) {
|
|
12106
|
-
const resolved =
|
|
12107
|
-
|
|
12148
|
+
const resolved = path11.resolve(targetPath);
|
|
12149
|
+
fs8.mkdirSync(path11.dirname(resolved), { recursive: true });
|
|
12108
12150
|
try {
|
|
12109
|
-
return
|
|
12151
|
+
return path11.join(canonicalLockParentSync(path11.dirname(resolved)), path11.basename(resolved));
|
|
12110
12152
|
} catch {
|
|
12111
12153
|
return resolved;
|
|
12112
12154
|
}
|
|
12113
12155
|
}
|
|
12114
12156
|
function boundedLockPath(lockPath, lockRoot) {
|
|
12115
|
-
const resolved =
|
|
12157
|
+
const resolved = path11.resolve(lockPath);
|
|
12116
12158
|
if (!lockRoot)
|
|
12117
12159
|
return resolved;
|
|
12118
12160
|
relativeSidecarLockPath(lockRoot, resolved);
|
|
12119
|
-
const parent =
|
|
12161
|
+
const parent = path11.dirname(resolved);
|
|
12120
12162
|
const parentReal = canonicalLockParentSync(parent);
|
|
12121
|
-
const parentRelative =
|
|
12122
|
-
if (parentRelative === ".." || parentRelative.startsWith(`..${
|
|
12163
|
+
const parentRelative = path11.relative(lockRoot.rootReal, parentReal);
|
|
12164
|
+
if (parentRelative === ".." || parentRelative.startsWith(`..${path11.sep}`) || path11.isAbsolute(parentRelative)) {
|
|
12123
12165
|
throw new FsSafeError("outside-workspace", "sidecar lock parent is outside lockRoot");
|
|
12124
12166
|
}
|
|
12125
|
-
return
|
|
12167
|
+
return path11.join(parentReal, path11.basename(resolved));
|
|
12126
12168
|
}
|
|
12127
12169
|
function defaultShouldReclaim(snapshot, staleMs, nowMs) {
|
|
12128
12170
|
const createdAtMs = sidecarLockPayloadCreatedAtMs(snapshot.payload);
|
|
@@ -12132,7 +12174,7 @@ function defaultShouldReclaim(snapshot, staleMs, nowMs) {
|
|
|
12132
12174
|
}
|
|
12133
12175
|
function reclaimGuardExists(reclaimGuardPath) {
|
|
12134
12176
|
try {
|
|
12135
|
-
|
|
12177
|
+
fs8.lstatSync(reclaimGuardPath);
|
|
12136
12178
|
return true;
|
|
12137
12179
|
} catch (error) {
|
|
12138
12180
|
if (error.code === "ENOENT")
|
|
@@ -12196,19 +12238,19 @@ function acquireFileLockSync(targetPath, options) {
|
|
|
12196
12238
|
const { raw, ownershipToken } = serializeSidecarLockPayload(payload);
|
|
12197
12239
|
let lockFileCreateDenied = false;
|
|
12198
12240
|
try {
|
|
12199
|
-
const noFollow = process.platform !== "win32" && typeof
|
|
12241
|
+
const noFollow = process.platform !== "win32" && typeof fs8.constants.O_NOFOLLOW === "number" ? fs8.constants.O_NOFOLLOW : 0;
|
|
12200
12242
|
try {
|
|
12201
|
-
fd =
|
|
12243
|
+
fd = fs8.openSync(lockPath, fs8.constants.O_WRONLY | fs8.constants.O_CREAT | fs8.constants.O_EXCL | noFollow, 384);
|
|
12202
12244
|
} catch (error) {
|
|
12203
12245
|
lockFileCreateDenied = isTransientLockFileDenial(error, lockPath);
|
|
12204
12246
|
throw error;
|
|
12205
12247
|
}
|
|
12206
|
-
|
|
12207
|
-
|
|
12248
|
+
fs8.writeFileSync(fd, raw, "utf8");
|
|
12249
|
+
fs8.fsyncSync(fd);
|
|
12208
12250
|
const snapshot = {
|
|
12209
12251
|
raw,
|
|
12210
12252
|
payload,
|
|
12211
|
-
stat:
|
|
12253
|
+
stat: fs8.fstatSync(fd),
|
|
12212
12254
|
ownershipToken
|
|
12213
12255
|
};
|
|
12214
12256
|
const createdHeld = {
|
|
@@ -12243,8 +12285,8 @@ function acquireFileLockSync(targetPath, options) {
|
|
|
12243
12285
|
return returnedHandle;
|
|
12244
12286
|
} catch (error) {
|
|
12245
12287
|
if (fd !== undefined) {
|
|
12246
|
-
const failed = { payload: null, stat:
|
|
12247
|
-
|
|
12288
|
+
const failed = { payload: null, stat: fs8.fstatSync(fd) };
|
|
12289
|
+
fs8.closeSync(fd);
|
|
12248
12290
|
fd = undefined;
|
|
12249
12291
|
removeSidecarLockIfUnchangedSync(lockPath, failed);
|
|
12250
12292
|
}
|
|
@@ -12293,7 +12335,7 @@ function acquireFileLockSync(targetPath, options) {
|
|
|
12293
12335
|
})) {
|
|
12294
12336
|
let ownsReclaimGuard = false;
|
|
12295
12337
|
try {
|
|
12296
|
-
|
|
12338
|
+
fs8.mkdirSync(reclaimGuardPath);
|
|
12297
12339
|
ownsReclaimGuard = true;
|
|
12298
12340
|
if (removeSidecarLockIfUnchangedSync(lockPath, snapshot))
|
|
12299
12341
|
continue;
|
|
@@ -12306,7 +12348,7 @@ function acquireFileLockSync(targetPath, options) {
|
|
|
12306
12348
|
} finally {
|
|
12307
12349
|
if (ownsReclaimGuard) {
|
|
12308
12350
|
try {
|
|
12309
|
-
|
|
12351
|
+
fs8.rmdirSync(reclaimGuardPath);
|
|
12310
12352
|
} catch {}
|
|
12311
12353
|
}
|
|
12312
12354
|
}
|
|
@@ -12323,13 +12365,13 @@ function acquireFileLockSync(targetPath, options) {
|
|
|
12323
12365
|
}
|
|
12324
12366
|
// packages/workit-core/src/core/package-root.ts
|
|
12325
12367
|
import { existsSync as existsSync3 } from "node:fs";
|
|
12326
|
-
import
|
|
12368
|
+
import path12 from "node:path";
|
|
12327
12369
|
import { fileURLToPath } from "node:url";
|
|
12328
12370
|
var packageRoot = () => {
|
|
12329
|
-
let dir =
|
|
12371
|
+
let dir = path12.dirname(fileURLToPath(import.meta.url));
|
|
12330
12372
|
while (true) {
|
|
12331
|
-
const parent =
|
|
12332
|
-
if (existsSync3(
|
|
12373
|
+
const parent = path12.dirname(dir);
|
|
12374
|
+
if (existsSync3(path12.join(dir, "package.json")) || parent === dir)
|
|
12333
12375
|
return dir;
|
|
12334
12376
|
dir = parent;
|
|
12335
12377
|
}
|
|
@@ -12337,7 +12379,7 @@ var packageRoot = () => {
|
|
|
12337
12379
|
|
|
12338
12380
|
// packages/workit-core/src/core/store-lock.ts
|
|
12339
12381
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
12340
|
-
import
|
|
12382
|
+
import fs9 from "node:fs";
|
|
12341
12383
|
import { hostname } from "node:os";
|
|
12342
12384
|
var metadataLockSchema = object({
|
|
12343
12385
|
pid: number2().int().nonnegative().safe(),
|
|
@@ -12379,7 +12421,7 @@ var parseProcStatStart = (stat) => {
|
|
|
12379
12421
|
var processStartOf = (pid) => {
|
|
12380
12422
|
if (process.platform === "linux") {
|
|
12381
12423
|
try {
|
|
12382
|
-
return parseProcStatStart(
|
|
12424
|
+
return parseProcStatStart(fs9.readFileSync(`/proc/${pid}/stat`, "utf8"));
|
|
12383
12425
|
} catch {
|
|
12384
12426
|
return null;
|
|
12385
12427
|
}
|
|
@@ -12400,7 +12442,7 @@ var processStartOf = (pid) => {
|
|
|
12400
12442
|
};
|
|
12401
12443
|
var readTrimmed = (file) => {
|
|
12402
12444
|
try {
|
|
12403
|
-
return
|
|
12445
|
+
return fs9.readFileSync(file, "utf8").trim() || null;
|
|
12404
12446
|
} catch {
|
|
12405
12447
|
return null;
|
|
12406
12448
|
}
|
|
@@ -12411,7 +12453,7 @@ var localLockHost = () => {
|
|
|
12411
12453
|
return cachedLockHost;
|
|
12412
12454
|
let pidns = null;
|
|
12413
12455
|
try {
|
|
12414
|
-
pidns = /\[(\d+)\]/.exec(
|
|
12456
|
+
pidns = /\[(\d+)\]/.exec(fs9.readlinkSync("/proc/self/ns/pid"))?.[1] ?? null;
|
|
12415
12457
|
} catch {}
|
|
12416
12458
|
const boot = readTrimmed("/proc/sys/kernel/random/boot_id");
|
|
12417
12459
|
cachedLockHost = pidns || boot ? `${hostname()}#${pidns ?? "?"}:${boot ?? "?"}` : hostname();
|
|
@@ -12457,7 +12499,7 @@ var classifyLockOwner = (payload, ageMs, localHost = localLockHost(), options =
|
|
|
12457
12499
|
};
|
|
12458
12500
|
var ageOf = (file, nowMs) => {
|
|
12459
12501
|
try {
|
|
12460
|
-
return nowMs -
|
|
12502
|
+
return nowMs - fs9.lstatSync(file).mtimeMs;
|
|
12461
12503
|
} catch {
|
|
12462
12504
|
return null;
|
|
12463
12505
|
}
|
|
@@ -12468,7 +12510,7 @@ var clearAbandonedReclaimGuard = (lockPath, nowMs = Date.now()) => {
|
|
|
12468
12510
|
if (age === null || age <= RECLAIM_GUARD_TTL_MS)
|
|
12469
12511
|
return false;
|
|
12470
12512
|
try {
|
|
12471
|
-
|
|
12513
|
+
fs9.rmdirSync(guard);
|
|
12472
12514
|
return true;
|
|
12473
12515
|
} catch {
|
|
12474
12516
|
return false;
|
|
@@ -12477,8 +12519,8 @@ var clearAbandonedReclaimGuard = (lockPath, nowMs = Date.now()) => {
|
|
|
12477
12519
|
|
|
12478
12520
|
// packages/workit-core/src/store/event-log.ts
|
|
12479
12521
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
12480
|
-
import
|
|
12481
|
-
import
|
|
12522
|
+
import fs10 from "node:fs";
|
|
12523
|
+
import path13 from "node:path";
|
|
12482
12524
|
var EVENT_VERSION = 1;
|
|
12483
12525
|
|
|
12484
12526
|
class LogDamage extends Error {
|
|
@@ -12507,7 +12549,7 @@ var parseEvent = (line, file, offset) => {
|
|
|
12507
12549
|
function readLog(file, from = 0, expectSeq = null) {
|
|
12508
12550
|
let fd;
|
|
12509
12551
|
try {
|
|
12510
|
-
fd =
|
|
12552
|
+
fd = fs10.openSync(file, "r");
|
|
12511
12553
|
} catch (error) {
|
|
12512
12554
|
if (error.code === "ENOENT")
|
|
12513
12555
|
return null;
|
|
@@ -12516,13 +12558,13 @@ function readLog(file, from = 0, expectSeq = null) {
|
|
|
12516
12558
|
let bytes;
|
|
12517
12559
|
let size;
|
|
12518
12560
|
try {
|
|
12519
|
-
size =
|
|
12561
|
+
size = fs10.fstatSync(fd).size;
|
|
12520
12562
|
if (from > size)
|
|
12521
12563
|
throw new LogDamage(`${file}: shorter than its snapshot`);
|
|
12522
12564
|
bytes = Buffer.alloc(size - from);
|
|
12523
12565
|
let read = 0;
|
|
12524
12566
|
while (read < bytes.length) {
|
|
12525
|
-
const got =
|
|
12567
|
+
const got = fs10.readSync(fd, bytes, read, bytes.length - read, from + read);
|
|
12526
12568
|
if (got === 0)
|
|
12527
12569
|
break;
|
|
12528
12570
|
read += got;
|
|
@@ -12530,7 +12572,7 @@ function readLog(file, from = 0, expectSeq = null) {
|
|
|
12530
12572
|
bytes = bytes.subarray(0, read);
|
|
12531
12573
|
size = from + read;
|
|
12532
12574
|
} finally {
|
|
12533
|
-
|
|
12575
|
+
fs10.closeSync(fd);
|
|
12534
12576
|
}
|
|
12535
12577
|
const events = [];
|
|
12536
12578
|
let start = 0;
|
|
@@ -12555,11 +12597,11 @@ function readLog(file, from = 0, expectSeq = null) {
|
|
|
12555
12597
|
}
|
|
12556
12598
|
var fsyncDirectory = (dir) => {
|
|
12557
12599
|
try {
|
|
12558
|
-
const fd =
|
|
12600
|
+
const fd = fs10.openSync(dir, "r");
|
|
12559
12601
|
try {
|
|
12560
|
-
|
|
12602
|
+
fs10.fsyncSync(fd);
|
|
12561
12603
|
} finally {
|
|
12562
|
-
|
|
12604
|
+
fs10.closeSync(fd);
|
|
12563
12605
|
}
|
|
12564
12606
|
} catch (error) {
|
|
12565
12607
|
if (process.platform !== "win32")
|
|
@@ -12569,46 +12611,46 @@ var fsyncDirectory = (dir) => {
|
|
|
12569
12611
|
function appendEvent(file, event, validEnd) {
|
|
12570
12612
|
const line = Buffer.from(`${JSON.stringify(event)}
|
|
12571
12613
|
`, "utf8");
|
|
12572
|
-
const created = !
|
|
12573
|
-
if (!created &&
|
|
12574
|
-
const cut =
|
|
12614
|
+
const created = !fs10.existsSync(file);
|
|
12615
|
+
if (!created && fs10.statSync(file).size !== validEnd) {
|
|
12616
|
+
const cut = fs10.openSync(file, "r+");
|
|
12575
12617
|
try {
|
|
12576
|
-
|
|
12577
|
-
|
|
12618
|
+
fs10.ftruncateSync(cut, validEnd);
|
|
12619
|
+
fs10.fsyncSync(cut);
|
|
12578
12620
|
} finally {
|
|
12579
|
-
|
|
12621
|
+
fs10.closeSync(cut);
|
|
12580
12622
|
}
|
|
12581
12623
|
}
|
|
12582
|
-
const fd =
|
|
12624
|
+
const fd = fs10.openSync(file, "a", 384);
|
|
12583
12625
|
try {
|
|
12584
12626
|
let written = 0;
|
|
12585
12627
|
while (written < line.length)
|
|
12586
|
-
written +=
|
|
12587
|
-
|
|
12628
|
+
written += fs10.writeSync(fd, line, written, line.length - written);
|
|
12629
|
+
fs10.fsyncSync(fd);
|
|
12588
12630
|
} finally {
|
|
12589
|
-
|
|
12631
|
+
fs10.closeSync(fd);
|
|
12590
12632
|
}
|
|
12591
12633
|
if (created)
|
|
12592
|
-
fsyncDirectory(
|
|
12634
|
+
fsyncDirectory(path13.dirname(file));
|
|
12593
12635
|
return validEnd;
|
|
12594
12636
|
}
|
|
12595
12637
|
function replaceFile(file, bytes, durable) {
|
|
12596
12638
|
const temporary = `${file}.${process.pid}.${randomUUID2()}.tmp`;
|
|
12597
12639
|
try {
|
|
12598
|
-
const fd =
|
|
12640
|
+
const fd = fs10.openSync(temporary, "wx", 384);
|
|
12599
12641
|
try {
|
|
12600
|
-
|
|
12642
|
+
fs10.writeSync(fd, bytes);
|
|
12601
12643
|
if (durable)
|
|
12602
|
-
|
|
12644
|
+
fs10.fsyncSync(fd);
|
|
12603
12645
|
} finally {
|
|
12604
|
-
|
|
12646
|
+
fs10.closeSync(fd);
|
|
12605
12647
|
}
|
|
12606
12648
|
renameWithRetry(temporary, file);
|
|
12607
12649
|
if (durable)
|
|
12608
|
-
fsyncDirectory(
|
|
12650
|
+
fsyncDirectory(path13.dirname(file));
|
|
12609
12651
|
} catch (error) {
|
|
12610
12652
|
try {
|
|
12611
|
-
|
|
12653
|
+
fs10.unlinkSync(temporary);
|
|
12612
12654
|
} catch {}
|
|
12613
12655
|
throw error;
|
|
12614
12656
|
}
|
|
@@ -12633,7 +12675,7 @@ var retryTransient = (run) => {
|
|
|
12633
12675
|
}
|
|
12634
12676
|
}
|
|
12635
12677
|
};
|
|
12636
|
-
var renameWithRetry = (from, to) => retryTransient(() =>
|
|
12678
|
+
var renameWithRetry = (from, to) => retryTransient(() => fs10.renameSync(from, to));
|
|
12637
12679
|
|
|
12638
12680
|
// packages/workit-core/src/store/patch.ts
|
|
12639
12681
|
var isPlainObject2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -12746,7 +12788,7 @@ var isPatch = (value) => Array.isArray(value) && value.every((op) => {
|
|
|
12746
12788
|
});
|
|
12747
12789
|
|
|
12748
12790
|
// packages/workit-core/src/store/reduce.ts
|
|
12749
|
-
import { createHash as
|
|
12791
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
12750
12792
|
var OPENING_TYPES = new Set([
|
|
12751
12793
|
"task.opened",
|
|
12752
12794
|
"task.imported",
|
|
@@ -12775,7 +12817,7 @@ var isObject5 = (value) => typeof value === "object" && value !== null && !Array
|
|
|
12775
12817
|
var isKey = (value) => isObject5(value) && typeof value.key === "string" && (value.kind === "branch" || value.kind === "detached" || value.kind === "dir") && (value.branch === null || typeof value.branch === "string");
|
|
12776
12818
|
var BLOB_REF = "$blob";
|
|
12777
12819
|
var blobRef = (value) => isObject5(value) && Object.keys(value).length === 1 && typeof value[BLOB_REF] === "string" && /^[0-9a-f]{64}$/.test(value[BLOB_REF]) ? value[BLOB_REF] : null;
|
|
12778
|
-
var blobDigest = (value) =>
|
|
12820
|
+
var blobDigest = (value) => createHash8("sha256").update(JSON.stringify(value)).digest("hex");
|
|
12779
12821
|
var toBlob = (value, blobs) => {
|
|
12780
12822
|
if (!isObject5(value))
|
|
12781
12823
|
return value;
|
|
@@ -12930,7 +12972,7 @@ var indexEntry = (task, key, legacy, file) => {
|
|
|
12930
12972
|
};
|
|
12931
12973
|
var fileSignature = (file) => {
|
|
12932
12974
|
try {
|
|
12933
|
-
const stat =
|
|
12975
|
+
const stat = fs11.statSync(file, { bigint: true });
|
|
12934
12976
|
return `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeNs}:${stat.ctimeNs}`;
|
|
12935
12977
|
} catch {
|
|
12936
12978
|
return null;
|
|
@@ -12948,7 +12990,7 @@ var cachedRuntimeVersion = null;
|
|
|
12948
12990
|
var runtimeVersion = () => {
|
|
12949
12991
|
if (cachedRuntimeVersion === null) {
|
|
12950
12992
|
try {
|
|
12951
|
-
const pkg = JSON.parse(
|
|
12993
|
+
const pkg = JSON.parse(fs11.readFileSync(path14.join(packageRoot(), "package.json"), "utf8"));
|
|
12952
12994
|
cachedRuntimeVersion = typeof pkg.version === "string" && pkg.version ? pkg.version : "0.0.0";
|
|
12953
12995
|
} catch {
|
|
12954
12996
|
cachedRuntimeVersion = "0.0.0";
|
|
@@ -12974,14 +13016,14 @@ var isNewerVersion = (candidate, current) => {
|
|
|
12974
13016
|
var validId = (value) => /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(value);
|
|
12975
13017
|
var readText = (file) => {
|
|
12976
13018
|
try {
|
|
12977
|
-
return
|
|
13019
|
+
return fs11.readFileSync(file, "utf8");
|
|
12978
13020
|
} catch {
|
|
12979
13021
|
return "";
|
|
12980
13022
|
}
|
|
12981
13023
|
};
|
|
12982
13024
|
var REFLOG_LINE = /^[0-9a-f]+ ([0-9a-f]+) .* (\d+) [+-]\d{4}\t(.*)$/u;
|
|
12983
13025
|
var branchStart = (location, branch, aliases) => {
|
|
12984
|
-
const first = readText(
|
|
13026
|
+
const first = readText(path14.join(path14.dirname(location.dir), "logs", "refs", "heads", branch)).split(`
|
|
12985
13027
|
`, 1)[0];
|
|
12986
13028
|
const created = REFLOG_LINE.exec(first);
|
|
12987
13029
|
const start = created && /^branch: Created from (\S+)$/u.exec(created[3])?.[1];
|
|
@@ -12991,7 +13033,7 @@ var branchStart = (location, branch, aliases) => {
|
|
|
12991
13033
|
return start;
|
|
12992
13034
|
if (!location.git)
|
|
12993
13035
|
return null;
|
|
12994
|
-
for (const line of readText(
|
|
13036
|
+
for (const line of readText(path14.join(location.git.gitDir, "logs", "HEAD")).split(`
|
|
12995
13037
|
`)) {
|
|
12996
13038
|
const entry = REFLOG_LINE.exec(line);
|
|
12997
13039
|
const moved = entry && /^checkout: moving from (\S+) to (\S+)$/u.exec(entry[3]);
|
|
@@ -13001,23 +13043,23 @@ var branchStart = (location, branch, aliases) => {
|
|
|
13001
13043
|
}
|
|
13002
13044
|
return null;
|
|
13003
13045
|
};
|
|
13004
|
-
var refExists = (common, ref) =>
|
|
13046
|
+
var refExists = (common, ref) => fs11.existsSync(path14.join(common, ref)) || readText(path14.join(common, "packed-refs")).includes(` ${ref}
|
|
13005
13047
|
`);
|
|
13006
13048
|
var origins = new Map;
|
|
13007
13049
|
var sameDirectoryIdentity = (left, right) => {
|
|
13008
|
-
if (!
|
|
13050
|
+
if (!path14.isAbsolute(left) || !path14.isAbsolute(right))
|
|
13009
13051
|
return false;
|
|
13010
|
-
const normalizedLeft =
|
|
13011
|
-
const normalizedRight =
|
|
13052
|
+
const normalizedLeft = path14.resolve(left);
|
|
13053
|
+
const normalizedRight = path14.resolve(right);
|
|
13012
13054
|
try {
|
|
13013
|
-
const a =
|
|
13014
|
-
const b =
|
|
13055
|
+
const a = fs11.statSync(normalizedLeft, { bigint: true });
|
|
13056
|
+
const b = fs11.statSync(normalizedRight, { bigint: true });
|
|
13015
13057
|
if (!a.isDirectory() || !b.isDirectory())
|
|
13016
13058
|
return false;
|
|
13017
13059
|
if (process.platform === "win32" ? normalizedLeft.toLowerCase() === normalizedRight.toLowerCase() : normalizedLeft === normalizedRight)
|
|
13018
13060
|
return true;
|
|
13019
|
-
const canonicalLeft =
|
|
13020
|
-
const canonicalRight =
|
|
13061
|
+
const canonicalLeft = fs11.realpathSync(normalizedLeft);
|
|
13062
|
+
const canonicalRight = fs11.realpathSync(normalizedRight);
|
|
13021
13063
|
if (process.platform === "win32" ? canonicalLeft.toLowerCase() === canonicalRight.toLowerCase() : canonicalLeft === canonicalRight)
|
|
13022
13064
|
return true;
|
|
13023
13065
|
return a.dev === b.dev && a.ino !== 0n && a.ino === b.ino;
|
|
@@ -13054,8 +13096,8 @@ class TaskStore {
|
|
|
13054
13096
|
migrationChecked = false;
|
|
13055
13097
|
compactDue = new Set;
|
|
13056
13098
|
constructor(root, options = {}) {
|
|
13057
|
-
const resolved =
|
|
13058
|
-
this.origin =
|
|
13099
|
+
const resolved = path14.resolve(root);
|
|
13100
|
+
this.origin = fs11.existsSync(resolved) ? fs11.realpathSync(resolved) : resolved;
|
|
13059
13101
|
this.located = resolveStore(this.origin);
|
|
13060
13102
|
this.root = checkoutRootOf(this.origin, this.located);
|
|
13061
13103
|
this.lockTimeoutMs = options.lockTimeoutMs ?? defaultLockTimeout();
|
|
@@ -13063,7 +13105,7 @@ class TaskStore {
|
|
|
13063
13105
|
this.migrateOnRead = options.migrateOnRead;
|
|
13064
13106
|
}
|
|
13065
13107
|
location() {
|
|
13066
|
-
if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared &&
|
|
13108
|
+
if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared && fs11.existsSync(path14.join(this.root, ".git"))) {
|
|
13067
13109
|
this.located = undefined;
|
|
13068
13110
|
this.migrationChecked = false;
|
|
13069
13111
|
}
|
|
@@ -13127,7 +13169,7 @@ class TaskStore {
|
|
|
13127
13169
|
const tasksDir = this.paths().tasks;
|
|
13128
13170
|
let names;
|
|
13129
13171
|
try {
|
|
13130
|
-
names =
|
|
13172
|
+
names = fs11.existsSync(tasksDir) ? fs11.readdirSync(tasksDir).filter((name) => validId(name)) : [];
|
|
13131
13173
|
} catch (error) {
|
|
13132
13174
|
return failure2("storage_error", `unable to list tasks: ${String(error)}`, {
|
|
13133
13175
|
path: tasksDir
|
|
@@ -13168,7 +13210,7 @@ class TaskStore {
|
|
|
13168
13210
|
const file = this.paths().workspace;
|
|
13169
13211
|
let bytes;
|
|
13170
13212
|
try {
|
|
13171
|
-
bytes = retryTransient(() =>
|
|
13213
|
+
bytes = retryTransient(() => fs11.readFileSync(file, "utf8"));
|
|
13172
13214
|
} catch (error) {
|
|
13173
13215
|
if (error.code === "ENOENT")
|
|
13174
13216
|
return success(null, null, null);
|
|
@@ -13219,7 +13261,7 @@ class TaskStore {
|
|
|
13219
13261
|
const moved = this.bindLocked(again.data.id, key, input.now);
|
|
13220
13262
|
return moved.ok ? success(moved.data.revision, null, { task: moved.data, created: false, key }) : moved;
|
|
13221
13263
|
}
|
|
13222
|
-
const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" :
|
|
13264
|
+
const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" : path14.basename(this.root) || this.root;
|
|
13223
13265
|
const intent = {
|
|
13224
13266
|
objective: input.objective?.trim() || `Work on ${label}`,
|
|
13225
13267
|
scope: { description: `the checkout (${label})`, paths: ["."], exclusions: [] },
|
|
@@ -13279,14 +13321,14 @@ class TaskStore {
|
|
|
13279
13321
|
const branch = key.ok ? key.data.branch : null;
|
|
13280
13322
|
if (!branch || !location.ok)
|
|
13281
13323
|
return success(null, null, null);
|
|
13282
|
-
const common =
|
|
13283
|
-
const heads =
|
|
13284
|
-
const headLog = location.data.git ?
|
|
13324
|
+
const common = path14.dirname(location.data.dir);
|
|
13325
|
+
const heads = path14.join(common, "logs", "refs", "heads");
|
|
13326
|
+
const headLog = location.data.git ? path14.join(location.data.git.gitDir, "logs", "HEAD") : "";
|
|
13285
13327
|
const signatures = [
|
|
13286
|
-
|
|
13328
|
+
path14.join(heads, branch),
|
|
13287
13329
|
headLog,
|
|
13288
13330
|
heads,
|
|
13289
|
-
|
|
13331
|
+
path14.join(common, "packed-refs")
|
|
13290
13332
|
].map((file) => fileSignature(file) ?? "-");
|
|
13291
13333
|
const slot = `${location.data.dir}\x00${headLog}\x00${branch}`;
|
|
13292
13334
|
let resolved = origins.get(slot);
|
|
@@ -13298,7 +13340,7 @@ class TaskStore {
|
|
|
13298
13340
|
aliases.push(rename.from);
|
|
13299
13341
|
const start = branchStart(location.data, branch, aliases);
|
|
13300
13342
|
const slash = start?.indexOf("/") ?? -1;
|
|
13301
|
-
const remote = slash > 0 && !refExists(common, `refs/heads/${start}`) && (refExists(common, `refs/remotes/${start}`) || readText(
|
|
13343
|
+
const remote = slash > 0 && !refExists(common, `refs/heads/${start}`) && (refExists(common, `refs/remotes/${start}`) || readText(path14.join(common, "config")).includes(`[remote "${start.slice(0, slash)}"]`));
|
|
13302
13344
|
const name = start && (remote ? start.slice(slash + 1) : start);
|
|
13303
13345
|
resolved = {
|
|
13304
13346
|
signature: signatures.join("|"),
|
|
@@ -13536,13 +13578,13 @@ class TaskStore {
|
|
|
13536
13578
|
if (!ready.ok)
|
|
13537
13579
|
return ready;
|
|
13538
13580
|
const dirs = this.paths();
|
|
13539
|
-
const recovery =
|
|
13540
|
-
if (
|
|
13581
|
+
const recovery = path14.join(this.root, ".workit", "recovery");
|
|
13582
|
+
if (fs11.existsSync(recovery)) {
|
|
13541
13583
|
let files = 0;
|
|
13542
13584
|
let bytes = 0;
|
|
13543
13585
|
try {
|
|
13544
|
-
for (const name of
|
|
13545
|
-
const stat =
|
|
13586
|
+
for (const name of fs11.readdirSync(recovery)) {
|
|
13587
|
+
const stat = fs11.lstatSync(path14.join(recovery, name));
|
|
13546
13588
|
if (!stat.isFile())
|
|
13547
13589
|
continue;
|
|
13548
13590
|
files += 1;
|
|
@@ -13551,17 +13593,17 @@ class TaskStore {
|
|
|
13551
13593
|
} catch {}
|
|
13552
13594
|
const remove = options.pruneRecovery === true && !dryRun;
|
|
13553
13595
|
if (remove)
|
|
13554
|
-
|
|
13596
|
+
fs11.rmSync(recovery, { recursive: true, force: true });
|
|
13555
13597
|
report.legacyRecovery = { path: recovery, files, bytes, removed: remove };
|
|
13556
13598
|
}
|
|
13557
|
-
if (!
|
|
13599
|
+
if (!fs11.existsSync(dirs.tasks))
|
|
13558
13600
|
return success(null, null, report);
|
|
13559
|
-
const names =
|
|
13601
|
+
const names = fs11.readdirSync(dirs.tasks).filter((name) => validId(name));
|
|
13560
13602
|
for (const name of names) {
|
|
13561
13603
|
const file = this.eventsPath(name);
|
|
13562
13604
|
let size = 0;
|
|
13563
13605
|
try {
|
|
13564
|
-
size =
|
|
13606
|
+
size = fs11.statSync(file).size;
|
|
13565
13607
|
} catch {
|
|
13566
13608
|
continue;
|
|
13567
13609
|
}
|
|
@@ -13589,16 +13631,16 @@ class TaskStore {
|
|
|
13589
13631
|
const references = new Set;
|
|
13590
13632
|
for (const name of names)
|
|
13591
13633
|
try {
|
|
13592
|
-
for (const match of
|
|
13634
|
+
for (const match of fs11.readFileSync(this.eventsPath(name), "utf8").matchAll(/"\$blob":"([0-9a-f]{64})"/g))
|
|
13593
13635
|
references.add(match[1]);
|
|
13594
13636
|
} catch {}
|
|
13595
|
-
if (
|
|
13596
|
-
for (const name of
|
|
13637
|
+
if (fs11.existsSync(dirs.blobs))
|
|
13638
|
+
for (const name of fs11.readdirSync(dirs.blobs)) {
|
|
13597
13639
|
const digest = name.replace(/\.json$/, "");
|
|
13598
|
-
const file =
|
|
13640
|
+
const file = path14.join(dirs.blobs, name);
|
|
13599
13641
|
let stat;
|
|
13600
13642
|
try {
|
|
13601
|
-
stat =
|
|
13643
|
+
stat = fs11.lstatSync(file);
|
|
13602
13644
|
} catch {
|
|
13603
13645
|
continue;
|
|
13604
13646
|
}
|
|
@@ -13609,11 +13651,11 @@ class TaskStore {
|
|
|
13609
13651
|
report.blobs.removed += 1;
|
|
13610
13652
|
report.blobs.removedBytes += stat.size;
|
|
13611
13653
|
if (!dryRun)
|
|
13612
|
-
|
|
13654
|
+
fs11.rmSync(file, { force: true });
|
|
13613
13655
|
}
|
|
13614
13656
|
return success(null, null, null);
|
|
13615
13657
|
};
|
|
13616
|
-
const swept = dryRun ? sweep() : this.withLock(
|
|
13658
|
+
const swept = dryRun ? sweep() : this.withLock(path14.join(dirs.dir, "gc.lock"), sweep);
|
|
13617
13659
|
if (!swept.ok)
|
|
13618
13660
|
return swept;
|
|
13619
13661
|
const temporaryDirs = [
|
|
@@ -13621,17 +13663,17 @@ class TaskStore {
|
|
|
13621
13663
|
dirs.tasks,
|
|
13622
13664
|
dirs.blobs,
|
|
13623
13665
|
dirs.checkout,
|
|
13624
|
-
...names.map((name) =>
|
|
13666
|
+
...names.map((name) => path14.join(dirs.tasks, name))
|
|
13625
13667
|
];
|
|
13626
13668
|
for (const directory of temporaryDirs) {
|
|
13627
|
-
if (!
|
|
13669
|
+
if (!fs11.existsSync(directory))
|
|
13628
13670
|
continue;
|
|
13629
|
-
for (const name of
|
|
13671
|
+
for (const name of fs11.readdirSync(directory)) {
|
|
13630
13672
|
if (!name.endsWith(".tmp") && !name.endsWith(".probe"))
|
|
13631
13673
|
continue;
|
|
13632
|
-
const file =
|
|
13674
|
+
const file = path14.join(directory, name);
|
|
13633
13675
|
try {
|
|
13634
|
-
const stat =
|
|
13676
|
+
const stat = fs11.lstatSync(file);
|
|
13635
13677
|
if (!stat.isFile() || nowMs - stat.mtimeMs <= STALE_TEMPORARY_MS)
|
|
13636
13678
|
continue;
|
|
13637
13679
|
} catch {
|
|
@@ -13639,37 +13681,37 @@ class TaskStore {
|
|
|
13639
13681
|
}
|
|
13640
13682
|
report.temporary.removed += 1;
|
|
13641
13683
|
if (!dryRun)
|
|
13642
|
-
|
|
13684
|
+
fs11.rmSync(file, { force: true });
|
|
13643
13685
|
}
|
|
13644
13686
|
}
|
|
13645
13687
|
return success(null, null, report);
|
|
13646
13688
|
}
|
|
13647
13689
|
paths() {
|
|
13648
13690
|
const location = this.location();
|
|
13649
|
-
const dir = location.ok ? location.data.dir :
|
|
13650
|
-
const checkout =
|
|
13691
|
+
const dir = location.ok ? location.data.dir : path14.join(this.root, ".workit");
|
|
13692
|
+
const checkout = path14.join(dir, "checkouts", checkoutSlug(this.root));
|
|
13651
13693
|
return {
|
|
13652
13694
|
dir,
|
|
13653
13695
|
shared: location.ok ? location.data.shared : false,
|
|
13654
|
-
marker:
|
|
13696
|
+
marker: path14.join(dir, "store.json"),
|
|
13655
13697
|
checkout,
|
|
13656
|
-
workspace:
|
|
13657
|
-
checkoutLock:
|
|
13658
|
-
tasks:
|
|
13659
|
-
index:
|
|
13660
|
-
blobs:
|
|
13661
|
-
legacy:
|
|
13662
|
-
v2:
|
|
13698
|
+
workspace: path14.join(checkout, "workspace.json"),
|
|
13699
|
+
checkoutLock: path14.join(checkout, "metadata.lock"),
|
|
13700
|
+
tasks: path14.join(dir, "tasks"),
|
|
13701
|
+
index: path14.join(dir, "task-index.json"),
|
|
13702
|
+
blobs: path14.join(dir, "blobs", "candidates"),
|
|
13703
|
+
legacy: path14.join(dir, "legacy", checkoutSlug(this.root), "v2"),
|
|
13704
|
+
v2: path14.join(this.root, ".workit")
|
|
13663
13705
|
};
|
|
13664
13706
|
}
|
|
13665
13707
|
eventsPath(taskId) {
|
|
13666
|
-
return
|
|
13708
|
+
return path14.join(this.paths().tasks, taskId, "events.jsonl");
|
|
13667
13709
|
}
|
|
13668
13710
|
snapshotPath(taskId) {
|
|
13669
|
-
return
|
|
13711
|
+
return path14.join(this.paths().tasks, taskId, "snapshot.json");
|
|
13670
13712
|
}
|
|
13671
13713
|
taskLockPath(taskId) {
|
|
13672
|
-
return
|
|
13714
|
+
return path14.join(this.paths().tasks, taskId, "lock");
|
|
13673
13715
|
}
|
|
13674
13716
|
ready(write = false) {
|
|
13675
13717
|
const location = this.location();
|
|
@@ -13679,7 +13721,7 @@ class TaskStore {
|
|
|
13679
13721
|
return success(null, null, null);
|
|
13680
13722
|
const dirs = this.paths();
|
|
13681
13723
|
try {
|
|
13682
|
-
const marker = JSON.parse(
|
|
13724
|
+
const marker = JSON.parse(fs11.readFileSync(dirs.marker, "utf8"));
|
|
13683
13725
|
if (typeof marker.version === "number" && marker.version > STORE_FORMAT)
|
|
13684
13726
|
return failure2("recovery_required", `the workit store at ${dirs.dir} has format ${marker.version}; upgrade Workit to use it`, { path: dirs.marker });
|
|
13685
13727
|
} catch {}
|
|
@@ -13708,21 +13750,21 @@ class TaskStore {
|
|
|
13708
13750
|
return {
|
|
13709
13751
|
read: (digest) => {
|
|
13710
13752
|
try {
|
|
13711
|
-
return JSON.parse(
|
|
13753
|
+
return JSON.parse(fs11.readFileSync(path14.join(dir, `${digest}.json`), "utf8"));
|
|
13712
13754
|
} catch (error) {
|
|
13713
13755
|
throw new LogDamage(`stored candidate ${digest} is missing or unreadable: ${String(error)}`);
|
|
13714
13756
|
}
|
|
13715
13757
|
},
|
|
13716
13758
|
write: (digest, value) => {
|
|
13717
|
-
const file =
|
|
13718
|
-
if (
|
|
13759
|
+
const file = path14.join(dir, `${digest}.json`);
|
|
13760
|
+
if (fs11.existsSync(file)) {
|
|
13719
13761
|
const stamp = new Date;
|
|
13720
13762
|
try {
|
|
13721
|
-
|
|
13763
|
+
fs11.utimesSync(file, stamp, stamp);
|
|
13722
13764
|
return;
|
|
13723
13765
|
} catch {}
|
|
13724
13766
|
}
|
|
13725
|
-
|
|
13767
|
+
fs11.mkdirSync(dir, { recursive: true });
|
|
13726
13768
|
replaceFile(file, JSON.stringify(value), true);
|
|
13727
13769
|
}
|
|
13728
13770
|
};
|
|
@@ -13804,7 +13846,7 @@ class TaskStore {
|
|
|
13804
13846
|
}
|
|
13805
13847
|
readSnapshot(taskId) {
|
|
13806
13848
|
try {
|
|
13807
|
-
const value = JSON.parse(
|
|
13849
|
+
const value = JSON.parse(fs11.readFileSync(this.snapshotPath(taskId), "utf8"));
|
|
13808
13850
|
if (!isObject6(value) || value.v !== 1 || value.task !== taskId || typeof value.seq !== "number" || typeof value.lastId !== "string" || typeof value.lastStart !== "number" || typeof value.end !== "number" || !isObject6(value.record))
|
|
13809
13851
|
return null;
|
|
13810
13852
|
return value;
|
|
@@ -13906,8 +13948,8 @@ class TaskStore {
|
|
|
13906
13948
|
}
|
|
13907
13949
|
}
|
|
13908
13950
|
openTask(record, type, key, legacy = null) {
|
|
13909
|
-
const dir =
|
|
13910
|
-
|
|
13951
|
+
const dir = path14.join(this.paths().tasks, record.id);
|
|
13952
|
+
fs11.mkdirSync(dir, { recursive: true });
|
|
13911
13953
|
const blobs = this.blobStore();
|
|
13912
13954
|
const bound = key ? { ...key, boundAt: key.boundAt ?? new Date().toISOString() } : null;
|
|
13913
13955
|
const event = this.event(record.id, 1, type, {
|
|
@@ -13959,11 +14001,11 @@ class TaskStore {
|
|
|
13959
14001
|
} catch {}
|
|
13960
14002
|
if (!latest || latest.events[0]?.id !== last.id)
|
|
13961
14003
|
return failure2("busy", "the task log changed during compaction; retry", { taskId });
|
|
13962
|
-
const appended =
|
|
14004
|
+
const appended = fs11.readFileSync(file).subarray(log.end, latest.end);
|
|
13963
14005
|
const bytes = Buffer.concat([Buffer.from(prefix, "utf8"), appended]);
|
|
13964
14006
|
replaceFile(file, bytes.toString("utf8"), true);
|
|
13965
14007
|
try {
|
|
13966
|
-
|
|
14008
|
+
fs11.rmSync(this.snapshotPath(taskId), { force: true });
|
|
13967
14009
|
} catch {}
|
|
13968
14010
|
const reloaded = this.load(taskId);
|
|
13969
14011
|
if (reloaded.ok && reloaded.data)
|
|
@@ -13976,7 +14018,7 @@ class TaskStore {
|
|
|
13976
14018
|
}
|
|
13977
14019
|
countEvents(file) {
|
|
13978
14020
|
try {
|
|
13979
|
-
const bytes =
|
|
14021
|
+
const bytes = fs11.readFileSync(file);
|
|
13980
14022
|
let count = 0;
|
|
13981
14023
|
for (let index = bytes.indexOf(10);index >= 0; index = bytes.indexOf(10, index + 1))
|
|
13982
14024
|
count += 1;
|
|
@@ -13998,8 +14040,8 @@ class TaskStore {
|
|
|
13998
14040
|
return bound.ok ? success(null, null, bound.data[0] ?? null) : bound;
|
|
13999
14041
|
}
|
|
14000
14042
|
withKeyLock(key, operation) {
|
|
14001
|
-
const digest =
|
|
14002
|
-
return this.withLock(
|
|
14043
|
+
const digest = createHash9("sha256").update(key).digest("hex").slice(0, 32);
|
|
14044
|
+
return this.withLock(path14.join(this.paths().dir, "keys", `${digest}.lock`), operation);
|
|
14003
14045
|
}
|
|
14004
14046
|
bindLocked(taskId, key, timestamp) {
|
|
14005
14047
|
const current = this.readWorkspace();
|
|
@@ -14140,7 +14182,7 @@ class TaskStore {
|
|
|
14140
14182
|
writeWorkspace(record) {
|
|
14141
14183
|
const file = this.paths().workspace;
|
|
14142
14184
|
try {
|
|
14143
|
-
|
|
14185
|
+
fs11.mkdirSync(path14.dirname(file), { recursive: true });
|
|
14144
14186
|
replaceFile(file, `${canonicalJson(record)}
|
|
14145
14187
|
`, true);
|
|
14146
14188
|
return success(null, null, null);
|
|
@@ -14150,7 +14192,7 @@ class TaskStore {
|
|
|
14150
14192
|
}
|
|
14151
14193
|
readIndex() {
|
|
14152
14194
|
try {
|
|
14153
|
-
const value = JSON.parse(
|
|
14195
|
+
const value = JSON.parse(fs11.readFileSync(this.paths().index, "utf8"));
|
|
14154
14196
|
if (!isObject6(value) || value.version !== INDEX_VERSION || !isObject6(value.tasks))
|
|
14155
14197
|
return {};
|
|
14156
14198
|
const tasks = {};
|
|
@@ -14164,7 +14206,7 @@ class TaskStore {
|
|
|
14164
14206
|
}
|
|
14165
14207
|
writeIndex(entries) {
|
|
14166
14208
|
try {
|
|
14167
|
-
|
|
14209
|
+
fs11.mkdirSync(this.paths().tasks, { recursive: true });
|
|
14168
14210
|
replaceFile(this.paths().index, JSON.stringify({
|
|
14169
14211
|
version: INDEX_VERSION,
|
|
14170
14212
|
tasks: Object.fromEntries(entries.map((entry) => [entry.id, entry]))
|
|
@@ -14218,23 +14260,23 @@ class TaskStore {
|
|
|
14218
14260
|
return failure2("revision_conflict", "workspace revision does not match; omit expectedWorkspaceRevision to use the current record", { expectedWorkspaceRevision: expected, actualWorkspaceRevision: actual });
|
|
14219
14261
|
}
|
|
14220
14262
|
v2Dirs() {
|
|
14221
|
-
return [...new Set([this.root, this.origin])].map((dir) =>
|
|
14263
|
+
return [...new Set([this.root, this.origin])].map((dir) => path14.join(dir, ".workit"));
|
|
14222
14264
|
}
|
|
14223
14265
|
pendingMigrations() {
|
|
14224
14266
|
return this.v2Dirs().filter((dir) => {
|
|
14225
|
-
const raw = this.readV2Workspace(
|
|
14267
|
+
const raw = this.readV2Workspace(path14.join(dir, "workspace.json"));
|
|
14226
14268
|
return raw !== null && raw !== TOMBSTONE;
|
|
14227
14269
|
});
|
|
14228
14270
|
}
|
|
14229
14271
|
migrateV2(v2) {
|
|
14230
14272
|
const dirs = this.paths();
|
|
14231
|
-
const v2Workspace =
|
|
14232
|
-
const v2Tasks =
|
|
14233
|
-
const legacy =
|
|
14273
|
+
const v2Workspace = path14.join(v2, "workspace.json");
|
|
14274
|
+
const v2Tasks = path14.join(v2, "tasks");
|
|
14275
|
+
const legacy = path14.join(dirs.dir, "legacy", checkoutSlug(path14.dirname(v2)), "v2");
|
|
14234
14276
|
const raw = this.readV2Workspace(v2Workspace);
|
|
14235
14277
|
if (raw === null || raw === TOMBSTONE)
|
|
14236
14278
|
return success(null, null, null);
|
|
14237
|
-
return this.withLock(dirs.checkoutLock, () => this.withLock(
|
|
14279
|
+
return this.withLock(dirs.checkoutLock, () => this.withLock(path14.join(v2, "metadata.lock"), () => {
|
|
14238
14280
|
const workspace = this.readV2Workspace(v2Workspace);
|
|
14239
14281
|
if (workspace === null || workspace === TOMBSTONE)
|
|
14240
14282
|
return success(null, null, null);
|
|
@@ -14243,7 +14285,7 @@ class TaskStore {
|
|
|
14243
14285
|
return failure2("recovery_required", `cannot migrate the 2.x store at ${v2}: ${parsedWorkspace.error}; move it aside to start fresh`, { path: v2Workspace });
|
|
14244
14286
|
let files = [];
|
|
14245
14287
|
try {
|
|
14246
|
-
files =
|
|
14288
|
+
files = fs11.readdirSync(v2Tasks).filter((name) => name.endsWith(".json") && validId(name.slice(0, -5))).filter((name) => !this.isStub(path14.join(v2Tasks, name)));
|
|
14247
14289
|
} catch {}
|
|
14248
14290
|
const current = this.readWorkspace();
|
|
14249
14291
|
if (!current.ok)
|
|
@@ -14261,22 +14303,22 @@ class TaskStore {
|
|
|
14261
14303
|
let skipped = 0;
|
|
14262
14304
|
const done = new Map;
|
|
14263
14305
|
try {
|
|
14264
|
-
|
|
14306
|
+
fs11.mkdirSync(path14.join(legacy, "tasks"), { recursive: true });
|
|
14265
14307
|
for (const name of ["workspace.json", "index.json"])
|
|
14266
|
-
if (
|
|
14267
|
-
|
|
14308
|
+
if (fs11.existsSync(path14.join(v2, name)))
|
|
14309
|
+
fs11.copyFileSync(path14.join(v2, name), path14.join(legacy, name));
|
|
14268
14310
|
for (const name of files) {
|
|
14269
14311
|
const id = name.slice(0, -5);
|
|
14270
|
-
const file =
|
|
14271
|
-
const bytes =
|
|
14312
|
+
const file = path14.join(v2Tasks, name);
|
|
14313
|
+
const bytes = fs11.readFileSync(file, "utf8");
|
|
14272
14314
|
const digest = sha256(bytes);
|
|
14273
|
-
|
|
14315
|
+
fs11.writeFileSync(path14.join(legacy, "tasks", name), bytes);
|
|
14274
14316
|
const parsed = this.parseRecord(bytes, taskRecordSchema, "2.x task");
|
|
14275
14317
|
if (!parsed.ok || parsed.data.id !== id)
|
|
14276
14318
|
return failure2("recovery_required", `cannot migrate 2.x task ${id}: ${parsed.ok ? "file name and record ID differ" : parsed.error}; move ${file} aside to continue`, { path: file });
|
|
14277
14319
|
const record = { ...parsed.data, workspaceId: target.id };
|
|
14278
|
-
const origin = { path:
|
|
14279
|
-
if (!
|
|
14320
|
+
const origin = { path: path14.join(legacy, "tasks", name), digest };
|
|
14321
|
+
if (!fs11.existsSync(this.eventsPath(id))) {
|
|
14280
14322
|
this.openTask(record, "migrated.from_v2", null, origin);
|
|
14281
14323
|
migrated += 1;
|
|
14282
14324
|
} else {
|
|
@@ -14311,8 +14353,8 @@ class TaskStore {
|
|
|
14311
14353
|
try {
|
|
14312
14354
|
let complete = true;
|
|
14313
14355
|
for (const [name, digest] of done) {
|
|
14314
|
-
const file =
|
|
14315
|
-
if (sha256(
|
|
14356
|
+
const file = path14.join(v2Tasks, name);
|
|
14357
|
+
if (sha256(fs11.readFileSync(file, "utf8")) !== digest) {
|
|
14316
14358
|
complete = false;
|
|
14317
14359
|
continue;
|
|
14318
14360
|
}
|
|
@@ -14322,7 +14364,7 @@ class TaskStore {
|
|
|
14322
14364
|
return failure2("busy", `the 2.x store at ${v2} changed during migration; retry`, {
|
|
14323
14365
|
path: v2
|
|
14324
14366
|
});
|
|
14325
|
-
|
|
14367
|
+
fs11.rmSync(path14.join(v2, "index.json"), { force: true });
|
|
14326
14368
|
this.writeTombstone(v2, target.id);
|
|
14327
14369
|
} catch (error) {
|
|
14328
14370
|
return failure2("storage_error", `cannot finish the 2.x migration: ${String(error)}`, {
|
|
@@ -14342,45 +14384,45 @@ class TaskStore {
|
|
|
14342
14384
|
}
|
|
14343
14385
|
adoptLocalStore() {
|
|
14344
14386
|
const dirs = this.paths();
|
|
14345
|
-
const marker =
|
|
14346
|
-
if (!dirs.shared || !
|
|
14387
|
+
const marker = path14.join(dirs.v2, "store.json");
|
|
14388
|
+
if (!dirs.shared || !fs11.existsSync(marker))
|
|
14347
14389
|
return success(null, null, null);
|
|
14348
14390
|
return this.withLock(dirs.checkoutLock, () => {
|
|
14349
|
-
if (!
|
|
14391
|
+
if (!fs11.existsSync(marker))
|
|
14350
14392
|
return success(null, null, null);
|
|
14351
14393
|
let tasks = 0;
|
|
14352
14394
|
try {
|
|
14353
14395
|
const merge = (from, to) => {
|
|
14354
|
-
if (!
|
|
14355
|
-
|
|
14396
|
+
if (!fs11.existsSync(to)) {
|
|
14397
|
+
fs11.mkdirSync(path14.dirname(to), { recursive: true });
|
|
14356
14398
|
try {
|
|
14357
|
-
|
|
14399
|
+
fs11.renameSync(from, to);
|
|
14358
14400
|
} catch {
|
|
14359
|
-
|
|
14360
|
-
|
|
14401
|
+
fs11.cpSync(from, to, { recursive: true, errorOnExist: true, force: false });
|
|
14402
|
+
fs11.rmSync(from, { recursive: true, force: true });
|
|
14361
14403
|
}
|
|
14362
14404
|
return;
|
|
14363
14405
|
}
|
|
14364
|
-
if (
|
|
14365
|
-
for (const name of
|
|
14366
|
-
merge(
|
|
14406
|
+
if (fs11.lstatSync(from).isDirectory() && fs11.lstatSync(to).isDirectory())
|
|
14407
|
+
for (const name of fs11.readdirSync(from))
|
|
14408
|
+
merge(path14.join(from, name), path14.join(to, name));
|
|
14367
14409
|
};
|
|
14368
14410
|
for (const sub of ["tasks", "checkouts", "blobs", "legacy"]) {
|
|
14369
|
-
const from =
|
|
14370
|
-
if (!
|
|
14411
|
+
const from = path14.join(dirs.v2, sub);
|
|
14412
|
+
if (!fs11.existsSync(from))
|
|
14371
14413
|
continue;
|
|
14372
14414
|
if (sub === "tasks") {
|
|
14373
|
-
for (const name of
|
|
14374
|
-
if (validId(name) && !
|
|
14415
|
+
for (const name of fs11.readdirSync(from))
|
|
14416
|
+
if (validId(name) && !fs11.existsSync(path14.join(dirs.dir, sub, name)))
|
|
14375
14417
|
tasks += 1;
|
|
14376
14418
|
}
|
|
14377
|
-
merge(from,
|
|
14419
|
+
merge(from, path14.join(dirs.dir, sub));
|
|
14378
14420
|
}
|
|
14379
|
-
const ledger =
|
|
14380
|
-
if (
|
|
14381
|
-
merge(ledger,
|
|
14382
|
-
|
|
14383
|
-
|
|
14421
|
+
const ledger = path14.join(dirs.v2, "ledger");
|
|
14422
|
+
if (fs11.existsSync(ledger) && !fs11.existsSync(path14.join(dirs.dir, "ledger")))
|
|
14423
|
+
merge(ledger, path14.join(dirs.dir, "ledger"));
|
|
14424
|
+
fs11.rmSync(path14.join(dirs.v2, "task-index.json"), { force: true });
|
|
14425
|
+
fs11.renameSync(marker, path14.join(dirs.v2, "store.moved.json"));
|
|
14384
14426
|
} catch (error) {
|
|
14385
14427
|
return failure2("storage_error", `cannot move ${dirs.v2} into ${dirs.dir}: ${String(error)}`, {
|
|
14386
14428
|
path: dirs.v2
|
|
@@ -14400,7 +14442,7 @@ class TaskStore {
|
|
|
14400
14442
|
readV2Workspace(file) {
|
|
14401
14443
|
let bytes;
|
|
14402
14444
|
try {
|
|
14403
|
-
bytes =
|
|
14445
|
+
bytes = fs11.readFileSync(file, "utf8");
|
|
14404
14446
|
} catch {
|
|
14405
14447
|
return null;
|
|
14406
14448
|
}
|
|
@@ -14418,7 +14460,7 @@ class TaskStore {
|
|
|
14418
14460
|
schemaVersion: SCHEMA_VERSION,
|
|
14419
14461
|
id: workspaceId ?? newId(),
|
|
14420
14462
|
revision: newRevision(),
|
|
14421
|
-
root:
|
|
14463
|
+
root: path14.dirname(v2),
|
|
14422
14464
|
runtime: { createdWith: version, updatedWith: version },
|
|
14423
14465
|
writer: null,
|
|
14424
14466
|
store: {
|
|
@@ -14429,12 +14471,12 @@ class TaskStore {
|
|
|
14429
14471
|
},
|
|
14430
14472
|
critical: ["store"]
|
|
14431
14473
|
};
|
|
14432
|
-
|
|
14433
|
-
const ignore =
|
|
14434
|
-
if (!
|
|
14435
|
-
|
|
14474
|
+
fs11.mkdirSync(v2, { recursive: true });
|
|
14475
|
+
const ignore = path14.join(v2, ".gitignore");
|
|
14476
|
+
if (!fs11.existsSync(ignore))
|
|
14477
|
+
fs11.writeFileSync(ignore, `*
|
|
14436
14478
|
`);
|
|
14437
|
-
replaceFile(
|
|
14479
|
+
replaceFile(path14.join(v2, "workspace.json"), `${JSON.stringify(marker, null, 2)}
|
|
14438
14480
|
`, true);
|
|
14439
14481
|
}
|
|
14440
14482
|
stubFor(taskId) {
|
|
@@ -14450,7 +14492,7 @@ class TaskStore {
|
|
|
14450
14492
|
}
|
|
14451
14493
|
isStub(file) {
|
|
14452
14494
|
try {
|
|
14453
|
-
const value = JSON.parse(
|
|
14495
|
+
const value = JSON.parse(fs11.readFileSync(file, "utf8"));
|
|
14454
14496
|
return isObject6(value) && isObject6(value.store) && value.store.format === "workit-store";
|
|
14455
14497
|
} catch {
|
|
14456
14498
|
return false;
|
|
@@ -14458,32 +14500,32 @@ class TaskStore {
|
|
|
14458
14500
|
}
|
|
14459
14501
|
writeTombstoneIfMissing() {
|
|
14460
14502
|
try {
|
|
14461
|
-
const v2 =
|
|
14462
|
-
if (
|
|
14503
|
+
const v2 = path14.join(this.root, ".workit");
|
|
14504
|
+
if (fs11.existsSync(path14.join(v2, "workspace.json")))
|
|
14463
14505
|
return;
|
|
14464
14506
|
let id = null;
|
|
14465
14507
|
try {
|
|
14466
|
-
id = JSON.parse(
|
|
14508
|
+
id = JSON.parse(fs11.readFileSync(this.paths().workspace, "utf8")).id ?? null;
|
|
14467
14509
|
} catch {}
|
|
14468
14510
|
this.writeTombstone(v2, id);
|
|
14469
14511
|
} catch {}
|
|
14470
14512
|
}
|
|
14471
14513
|
initializeStorage() {
|
|
14472
14514
|
const dirs = this.paths();
|
|
14473
|
-
retryTransient(() =>
|
|
14474
|
-
retryTransient(() =>
|
|
14475
|
-
if (!
|
|
14515
|
+
retryTransient(() => fs11.mkdirSync(dirs.checkout, { recursive: true }));
|
|
14516
|
+
retryTransient(() => fs11.mkdirSync(dirs.tasks, { recursive: true }));
|
|
14517
|
+
if (!fs11.existsSync(dirs.marker))
|
|
14476
14518
|
replaceFile(dirs.marker, `${JSON.stringify({ format: "workit-store", version: STORE_FORMAT, createdWith: runtimeVersion() })}
|
|
14477
14519
|
`, false);
|
|
14478
14520
|
if (!dirs.shared) {
|
|
14479
|
-
const ignore =
|
|
14521
|
+
const ignore = path14.join(dirs.dir, ".gitignore");
|
|
14480
14522
|
let current = null;
|
|
14481
14523
|
try {
|
|
14482
|
-
current =
|
|
14524
|
+
current = fs11.readFileSync(ignore, "utf8");
|
|
14483
14525
|
} catch {}
|
|
14484
14526
|
if (current !== `*
|
|
14485
14527
|
`)
|
|
14486
|
-
retryTransient(() =>
|
|
14528
|
+
retryTransient(() => fs11.writeFileSync(ignore, `*
|
|
14487
14529
|
`));
|
|
14488
14530
|
}
|
|
14489
14531
|
this.writeTombstoneIfMissing();
|
|
@@ -14499,7 +14541,7 @@ class TaskStore {
|
|
|
14499
14541
|
shouldReclaim: ({ payload, nowMs }) => {
|
|
14500
14542
|
let ageMs = null;
|
|
14501
14543
|
try {
|
|
14502
|
-
ageMs = nowMs -
|
|
14544
|
+
ageMs = nowMs - fs11.lstatSync(lockPath).mtimeMs;
|
|
14503
14545
|
} catch {}
|
|
14504
14546
|
return classifyLockOwner(payload, ageMs, localLockHost(), TASK_STORE_LOCK).state === "stale";
|
|
14505
14547
|
},
|
|
@@ -14536,7 +14578,7 @@ class TaskStore {
|
|
|
14536
14578
|
withLock(lockPath, operation) {
|
|
14537
14579
|
try {
|
|
14538
14580
|
this.initializeStorage();
|
|
14539
|
-
|
|
14581
|
+
fs11.mkdirSync(path14.dirname(lockPath), { recursive: true });
|
|
14540
14582
|
} catch (error) {
|
|
14541
14583
|
return failure2("storage_error", `unable to initialize store: ${String(error)}`, {
|
|
14542
14584
|
path: this.paths().dir
|
|
@@ -14576,18 +14618,18 @@ class TaskStore {
|
|
|
14576
14618
|
lockDirWritable(lockPath) {
|
|
14577
14619
|
const probe = `${lockPath}.${process.pid}.${randomUUID3()}.probe`;
|
|
14578
14620
|
try {
|
|
14579
|
-
|
|
14621
|
+
fs11.closeSync(fs11.openSync(probe, "wx", 384));
|
|
14580
14622
|
} catch {
|
|
14581
14623
|
return false;
|
|
14582
14624
|
}
|
|
14583
14625
|
try {
|
|
14584
|
-
|
|
14626
|
+
fs11.rmSync(probe, { force: true });
|
|
14585
14627
|
} catch {}
|
|
14586
14628
|
return true;
|
|
14587
14629
|
}
|
|
14588
14630
|
lockHolderPresent(lockPath) {
|
|
14589
14631
|
try {
|
|
14590
|
-
|
|
14632
|
+
fs11.lstatSync(lockPath);
|
|
14591
14633
|
return true;
|
|
14592
14634
|
} catch (error) {
|
|
14593
14635
|
return error?.code !== "ENOENT";
|
|
@@ -14599,12 +14641,12 @@ class TaskStore {
|
|
|
14599
14641
|
if (isTransientWindowsError(error) && !this.lockHolderPresent(lockPath) && !this.lockDirWritable(lockPath))
|
|
14600
14642
|
return failure2("storage_error", `cannot create the workit lock (${code}); no other Workit call holds it`, {
|
|
14601
14643
|
path: lockPath,
|
|
14602
|
-
guidance: `Check permissions and the read-only attribute on ${
|
|
14644
|
+
guidance: `Check permissions and the read-only attribute on ${path14.dirname(lockPath)}.`
|
|
14603
14645
|
});
|
|
14604
14646
|
if (code === "EEXIST" || code === "file_lock_timeout" || code === "file_lock_stale" || isTransientWindowsError(error)) {
|
|
14605
14647
|
let lock = null;
|
|
14606
14648
|
try {
|
|
14607
|
-
lock = parseMetadataLockOrNull(
|
|
14649
|
+
lock = parseMetadataLockOrNull(fs11.readFileSync(lockPath, "utf8"));
|
|
14608
14650
|
} catch {}
|
|
14609
14651
|
return failure2("busy", `workit lock is held by another Workit call${lock ? ` (pid ${lock.pid} on ${lock.host})` : ""}; retry shortly`, {
|
|
14610
14652
|
outcome: "not_started",
|
|
@@ -14623,15 +14665,15 @@ var isUncertainWorker = (state) => UNCERTAIN_WORKER_STATES.includes(state);
|
|
|
14623
14665
|
var workerBlocksTransition = (transition, state) => transition === "pause" ? false : isUncertainWorker(state);
|
|
14624
14666
|
|
|
14625
14667
|
// packages/workit-core/src/core/task-evaluation.ts
|
|
14626
|
-
import { createHash as
|
|
14627
|
-
import * as
|
|
14668
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
14669
|
+
import * as fs13 from "node:fs";
|
|
14628
14670
|
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
14629
|
-
import
|
|
14671
|
+
import path16 from "node:path";
|
|
14630
14672
|
|
|
14631
14673
|
// packages/workit-core/src/check-config.ts
|
|
14632
14674
|
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
14633
|
-
import
|
|
14634
|
-
import
|
|
14675
|
+
import fs12 from "node:fs";
|
|
14676
|
+
import path15 from "node:path";
|
|
14635
14677
|
var SCRIPT_CHECKS = ["test", "lint", "typecheck", "check"];
|
|
14636
14678
|
var CHECKS_FILE = "workit.checks.json";
|
|
14637
14679
|
var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -14684,10 +14726,10 @@ var git4 = (cwd, args) => {
|
|
|
14684
14726
|
return value || null;
|
|
14685
14727
|
};
|
|
14686
14728
|
function checkRoot(cwd) {
|
|
14687
|
-
return
|
|
14729
|
+
return path15.resolve(git4(cwd, ["rev-parse", "--show-toplevel"]) ?? cwd);
|
|
14688
14730
|
}
|
|
14689
14731
|
var packageManager = (root) => {
|
|
14690
|
-
const has = (file) =>
|
|
14732
|
+
const has = (file) => fs12.existsSync(path15.join(root, file));
|
|
14691
14733
|
if (has("bun.lock") || has("bun.lockb"))
|
|
14692
14734
|
return "bun";
|
|
14693
14735
|
if (has("pnpm-lock.yaml"))
|
|
@@ -14707,7 +14749,7 @@ var CHECK_NAME = /^[a-z0-9][a-z0-9:._-]{0,63}$/u;
|
|
|
14707
14749
|
function detectedChecks(root) {
|
|
14708
14750
|
const read = (file) => {
|
|
14709
14751
|
try {
|
|
14710
|
-
return
|
|
14752
|
+
return fs12.readFileSync(path15.join(root, file), "utf8");
|
|
14711
14753
|
} catch {
|
|
14712
14754
|
return null;
|
|
14713
14755
|
}
|
|
@@ -14746,7 +14788,7 @@ function detectedChecks(root) {
|
|
|
14746
14788
|
var GATES = ["testing", "verification"];
|
|
14747
14789
|
function loadCheckConfig(cwd) {
|
|
14748
14790
|
const root = checkRoot(cwd);
|
|
14749
|
-
const file =
|
|
14791
|
+
const file = path15.join(root, CHECKS_FILE);
|
|
14750
14792
|
const none = (error = null) => ({
|
|
14751
14793
|
source: error ? CHECKS_FILE : "none",
|
|
14752
14794
|
root,
|
|
@@ -14756,7 +14798,7 @@ function loadCheckConfig(cwd) {
|
|
|
14756
14798
|
});
|
|
14757
14799
|
let text = null;
|
|
14758
14800
|
try {
|
|
14759
|
-
text =
|
|
14801
|
+
text = fs12.readFileSync(file, "utf8");
|
|
14760
14802
|
} catch (error) {
|
|
14761
14803
|
if (error.code !== "ENOENT")
|
|
14762
14804
|
return none(`cannot read ${CHECKS_FILE}: ${error.message}`);
|
|
@@ -14819,10 +14861,10 @@ function workitAvailable(env = process.env) {
|
|
|
14819
14861
|
return workitOnPath;
|
|
14820
14862
|
const windows = process.platform === "win32";
|
|
14821
14863
|
const exts = windows ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
|
|
14822
|
-
const dirs = (env.PATH ?? env.Path ?? "").split(
|
|
14864
|
+
const dirs = (env.PATH ?? env.Path ?? "").split(path15.delimiter).filter(Boolean);
|
|
14823
14865
|
workitOnPath = dirs.some((dir) => exts.some((ext) => {
|
|
14824
14866
|
try {
|
|
14825
|
-
return
|
|
14867
|
+
return fs12.statSync(path15.join(dir, `workit${ext}`)).isFile();
|
|
14826
14868
|
} catch {
|
|
14827
14869
|
return false;
|
|
14828
14870
|
}
|
|
@@ -14834,15 +14876,15 @@ function checkCommand(args, version, onPath = workitAvailable()) {
|
|
|
14834
14876
|
}
|
|
14835
14877
|
|
|
14836
14878
|
// packages/workit-core/src/core/task-evaluation.ts
|
|
14837
|
-
var digestBytes = (value) =>
|
|
14838
|
-
var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${
|
|
14839
|
-
var relative = (root, candidate) =>
|
|
14879
|
+
var digestBytes = (value) => createHash10("sha256").update(value).digest("hex");
|
|
14880
|
+
var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path16.sep}`);
|
|
14881
|
+
var relative = (root, candidate) => path16.relative(root, candidate).split(path16.sep).join("/") || ".";
|
|
14840
14882
|
var canonicalPath = (value) => {
|
|
14841
14883
|
if (typeof value !== "string" || !value)
|
|
14842
14884
|
return null;
|
|
14843
14885
|
if (value.includes("\\") || value.split("/").includes(".."))
|
|
14844
14886
|
return null;
|
|
14845
|
-
const normalized =
|
|
14887
|
+
const normalized = path16.posix.normalize(value);
|
|
14846
14888
|
if (normalized === ".." || normalized.startsWith("../") || normalized.startsWith("/"))
|
|
14847
14889
|
return null;
|
|
14848
14890
|
return normalized === "." ? "." : normalized.replace(/\/$/, "");
|
|
@@ -14890,21 +14932,21 @@ var gitPaths = (root) => {
|
|
|
14890
14932
|
git: !/not a git repository/i.test(stderr)
|
|
14891
14933
|
};
|
|
14892
14934
|
}
|
|
14893
|
-
const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(
|
|
14935
|
+
const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path16.sep).join("/")) : [];
|
|
14894
14936
|
const stagedDeleted = spawnSync10("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
|
|
14895
14937
|
if (stagedDeleted.status !== 0) {
|
|
14896
14938
|
const stderr = stagedDeleted.stderr?.toString("utf8") ?? "";
|
|
14897
14939
|
if (!/not a git repository/i.test(stderr))
|
|
14898
14940
|
return { paths, uncertain: true, git: true };
|
|
14899
14941
|
} else if (stagedDeleted.stdout) {
|
|
14900
|
-
paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(
|
|
14942
|
+
paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path16.sep).join("/")));
|
|
14901
14943
|
}
|
|
14902
14944
|
return { paths: [...new Set(paths)], uncertain: false, git: true };
|
|
14903
14945
|
};
|
|
14904
14946
|
var walk = (root, directory, output) => {
|
|
14905
14947
|
let names;
|
|
14906
14948
|
try {
|
|
14907
|
-
names =
|
|
14949
|
+
names = fs13.readdirSync(directory);
|
|
14908
14950
|
} catch {
|
|
14909
14951
|
return true;
|
|
14910
14952
|
}
|
|
@@ -14912,10 +14954,10 @@ var walk = (root, directory, output) => {
|
|
|
14912
14954
|
for (const name of names) {
|
|
14913
14955
|
if (name === ".git" || name === ".workit")
|
|
14914
14956
|
continue;
|
|
14915
|
-
const target =
|
|
14957
|
+
const target = path16.join(directory, name);
|
|
14916
14958
|
let stat;
|
|
14917
14959
|
try {
|
|
14918
|
-
stat =
|
|
14960
|
+
stat = fs13.lstatSync(target);
|
|
14919
14961
|
} catch {
|
|
14920
14962
|
uncertain = true;
|
|
14921
14963
|
continue;
|
|
@@ -14930,14 +14972,14 @@ var walk = (root, directory, output) => {
|
|
|
14930
14972
|
var scopeRoots = (root, scope) => {
|
|
14931
14973
|
const roots = [];
|
|
14932
14974
|
for (const item of scope.paths.length ? scope.paths : ["."]) {
|
|
14933
|
-
const target =
|
|
14975
|
+
const target = path16.resolve(root, item);
|
|
14934
14976
|
if (!inside(root, target))
|
|
14935
14977
|
return failure2("invalid_input", `candidate scope escapes checkout: ${item} — keep one task per repository and coordinate a separate linked task in the other checkout`, { fields: [{ path: "scope.paths", reason: `${item} is outside the checkout` }] });
|
|
14936
14978
|
let ancestor = target;
|
|
14937
|
-
while (!
|
|
14938
|
-
ancestor =
|
|
14979
|
+
while (!fs13.existsSync(ancestor) && ancestor !== root)
|
|
14980
|
+
ancestor = path16.dirname(ancestor);
|
|
14939
14981
|
try {
|
|
14940
|
-
if (!inside(root,
|
|
14982
|
+
if (!inside(root, fs13.realpathSync(ancestor)))
|
|
14941
14983
|
return failure2("invalid_input", `candidate scope escapes checkout through a symlink: ${item} — keep one task per repository and coordinate a separate linked task in the other checkout`, { fields: [{ path: "scope.paths", reason: `${item} resolves outside the checkout` }] });
|
|
14942
14984
|
} catch {
|
|
14943
14985
|
return failure2("invalid_input", `candidate scope cannot be inspected: ${item}`);
|
|
@@ -14949,7 +14991,7 @@ var scopeRoots = (root, scope) => {
|
|
|
14949
14991
|
function captureCandidate(root, scope, environment = []) {
|
|
14950
14992
|
let checkout;
|
|
14951
14993
|
try {
|
|
14952
|
-
checkout =
|
|
14994
|
+
checkout = fs13.realpathSync(root);
|
|
14953
14995
|
} catch {
|
|
14954
14996
|
return failure2("invalid_input", "candidate root does not exist");
|
|
14955
14997
|
}
|
|
@@ -14967,11 +15009,11 @@ function captureCandidate(root, scope, environment = []) {
|
|
|
14967
15009
|
if (item === ".git" || item === ".workit")
|
|
14968
15010
|
continue;
|
|
14969
15011
|
names.add(item);
|
|
14970
|
-
if (!
|
|
15012
|
+
if (!fs13.existsSync(target))
|
|
14971
15013
|
continue;
|
|
14972
15014
|
let stat;
|
|
14973
15015
|
try {
|
|
14974
|
-
stat =
|
|
15016
|
+
stat = fs13.lstatSync(target);
|
|
14975
15017
|
} catch {
|
|
14976
15018
|
uncertain = true;
|
|
14977
15019
|
continue;
|
|
@@ -14987,17 +15029,17 @@ function captureCandidate(root, scope, environment = []) {
|
|
|
14987
15029
|
for (const item of [...names].toSorted()) {
|
|
14988
15030
|
if (!scopeMatches(item, normalizedScope))
|
|
14989
15031
|
continue;
|
|
14990
|
-
const target =
|
|
15032
|
+
const target = path16.join(checkout, item);
|
|
14991
15033
|
try {
|
|
14992
|
-
const stat =
|
|
15034
|
+
const stat = fs13.lstatSync(target);
|
|
14993
15035
|
if (stat.isSymbolicLink()) {
|
|
14994
|
-
const link =
|
|
15036
|
+
const link = fs13.readlinkSync(target);
|
|
14995
15037
|
files.push({ path: item, kind: "symlink", digest: digestBytes(link), executable: null });
|
|
14996
15038
|
} else if (stat.isFile()) {
|
|
14997
15039
|
files.push({
|
|
14998
15040
|
path: item,
|
|
14999
15041
|
kind: "file",
|
|
15000
|
-
digest: digestBytes(
|
|
15042
|
+
digest: digestBytes(fs13.readFileSync(target)),
|
|
15001
15043
|
executable: (stat.mode & 73) !== 0
|
|
15002
15044
|
});
|
|
15003
15045
|
} else if (!stat.isDirectory()) {
|
|
@@ -15162,7 +15204,7 @@ var findingVerificationPasses = (findingCandidateId, evidence) => evidence.statu
|
|
|
15162
15204
|
var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
15163
15205
|
let root;
|
|
15164
15206
|
try {
|
|
15165
|
-
root =
|
|
15207
|
+
root = fs13.realpathSync(checkoutRoot);
|
|
15166
15208
|
} catch {
|
|
15167
15209
|
return failure2("permission_denied", "checkout root is unavailable");
|
|
15168
15210
|
}
|
|
@@ -15171,23 +15213,23 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
|
15171
15213
|
continue;
|
|
15172
15214
|
if (!reference.digest)
|
|
15173
15215
|
return failure2("invalid_input", "document references require a byte digest");
|
|
15174
|
-
const target =
|
|
15175
|
-
if (target !== root && !target.startsWith(`${root}${
|
|
15216
|
+
const target = path16.resolve(root, reference.path);
|
|
15217
|
+
if (target !== root && !target.startsWith(`${root}${path16.sep}`))
|
|
15176
15218
|
return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
|
|
15177
15219
|
fields: [
|
|
15178
15220
|
{ path: "contentRefs.path", reason: `${reference.path} is outside the checkout` }
|
|
15179
15221
|
]
|
|
15180
15222
|
});
|
|
15181
15223
|
try {
|
|
15182
|
-
const below =
|
|
15224
|
+
const below = path16.relative(root, target);
|
|
15183
15225
|
let current = root;
|
|
15184
|
-
for (const segment of below.split(
|
|
15226
|
+
for (const segment of below.split(path16.sep)) {
|
|
15185
15227
|
if (!segment)
|
|
15186
15228
|
continue;
|
|
15187
|
-
current =
|
|
15188
|
-
const stat =
|
|
15189
|
-
const real =
|
|
15190
|
-
if (real !== root && !real.startsWith(`${root}${
|
|
15229
|
+
current = path16.join(current, segment);
|
|
15230
|
+
const stat = fs13.lstatSync(current);
|
|
15231
|
+
const real = fs13.realpathSync(current);
|
|
15232
|
+
if (real !== root && !real.startsWith(`${root}${path16.sep}`))
|
|
15191
15233
|
return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
|
|
15192
15234
|
fields: [
|
|
15193
15235
|
{
|
|
@@ -15203,7 +15245,7 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
|
15203
15245
|
if (current !== target && !stat.isDirectory())
|
|
15204
15246
|
return failure2("invalid_input", "document reference ancestor is not a directory");
|
|
15205
15247
|
}
|
|
15206
|
-
if (digestBytes(
|
|
15248
|
+
if (digestBytes(fs13.readFileSync(target)) !== reference.digest)
|
|
15207
15249
|
return failure2("permission_denied", "decision document bytes have changed");
|
|
15208
15250
|
} catch {
|
|
15209
15251
|
return failure2("invalid_input", "decision document is unavailable");
|
|
@@ -15572,7 +15614,8 @@ Autonomy contract:
|
|
|
15572
15614
|
satisfies a gate; an ad-hoc \`workit check -- <cmd>\` never does.
|
|
15573
15615
|
- Author is not verifier: your own verdict is \`--self\`, shown as
|
|
15574
15616
|
self-reviewed, never verified. High risk, \`verification: independent\` and
|
|
15575
|
-
merge need a verifier with its own session (
|
|
15617
|
+
merge need a verifier with its own host-derived session (a subagent's
|
|
15618
|
+
\`<lead>:<child>\`, set by the host); never hand-mint one such as \`<lead>-v1\`.
|
|
15576
15619
|
- A local-commit endpoint does not imply PR readiness, and a local commit alone
|
|
15577
15620
|
is not evidence of a requested remote push. Before reporting delivery,
|
|
15578
15621
|
reconcile every requested item and observe it (\`workit verify-delivery\`).
|
|
@@ -17400,9 +17443,9 @@ var capabilitiesFor = (descriptor, observed = {}) => descriptor.capabilities.map
|
|
|
17400
17443
|
};
|
|
17401
17444
|
});
|
|
17402
17445
|
// packages/workit-core/src/hooks/context.ts
|
|
17403
|
-
import { createHash as
|
|
17404
|
-
import
|
|
17405
|
-
import
|
|
17446
|
+
import { createHash as createHash11 } from "node:crypto";
|
|
17447
|
+
import fs14 from "node:fs";
|
|
17448
|
+
import path17 from "node:path";
|
|
17406
17449
|
var MIGRATION_PENDING_NOTE = "workit migration pending — run `workit task status`";
|
|
17407
17450
|
var migrationPending = (result) => !result.ok && result.code === "needs_input" && (result.error ?? "").startsWith(MIGRATION_PENDING);
|
|
17408
17451
|
var boundTo = (entry, session) => entry.sessions.some((item) => item.host === session.host && item.handle === session.handle);
|
|
@@ -17487,7 +17530,7 @@ function entryCompactContext(store, entry, session, context) {
|
|
|
17487
17530
|
return null;
|
|
17488
17531
|
const freshness = { mode: "signal", current: () => recentSignal(store.root) };
|
|
17489
17532
|
const observed = task?.data.evidence.some(isObservedCheck) ?? false;
|
|
17490
|
-
const files = (task?.data.decisions ?? []).flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [
|
|
17533
|
+
const files = (task?.data.decisions ?? []).flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [path17.resolve(store.root, ref.path)] : []));
|
|
17491
17534
|
const observedFiles = filesKey(files);
|
|
17492
17535
|
const compact = new WorkitCore(store, context).compactContext(entry?.id ?? null, freshness, origin && { origin: origin.origin, taskId: origin.entry.id });
|
|
17493
17536
|
if (!compact.ok || !compact.data)
|
|
@@ -17556,7 +17599,7 @@ var turnContextText = (input, descriptor) => {
|
|
|
17556
17599
|
}
|
|
17557
17600
|
};
|
|
17558
17601
|
var TURN_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
17559
|
-
var digestOf = (text) =>
|
|
17602
|
+
var digestOf = (text) => createHash11("sha256").update(text).digest("hex");
|
|
17560
17603
|
var turnMarker = (input) => {
|
|
17561
17604
|
if (!input.session.id)
|
|
17562
17605
|
return null;
|
|
@@ -17565,32 +17608,32 @@ var turnMarker = (input) => {
|
|
|
17565
17608
|
if (location instanceof Error)
|
|
17566
17609
|
return null;
|
|
17567
17610
|
const session = [input.host, input.session.id, input.session.agentId ?? ""].join("\x00");
|
|
17568
|
-
return
|
|
17611
|
+
return path17.join(location.dir, "hooks", `turn-${digestOf(session).slice(0, 32)}.json`);
|
|
17569
17612
|
} catch {
|
|
17570
17613
|
return null;
|
|
17571
17614
|
}
|
|
17572
17615
|
};
|
|
17573
17616
|
var writeTurnDigest = (file, digest) => {
|
|
17574
17617
|
try {
|
|
17575
|
-
|
|
17576
|
-
|
|
17618
|
+
fs14.mkdirSync(path17.dirname(file), { recursive: true });
|
|
17619
|
+
fs14.writeFileSync(file, `${JSON.stringify({ digest })}
|
|
17577
17620
|
`);
|
|
17578
17621
|
} catch {}
|
|
17579
17622
|
};
|
|
17580
17623
|
var clearTurnDigest = (file) => {
|
|
17581
17624
|
try {
|
|
17582
|
-
|
|
17625
|
+
fs14.rmSync(file, { force: true });
|
|
17583
17626
|
} catch {}
|
|
17584
17627
|
};
|
|
17585
17628
|
var pruneTurnDigests = (dir, now) => {
|
|
17586
17629
|
try {
|
|
17587
|
-
for (const name of
|
|
17630
|
+
for (const name of fs14.readdirSync(dir)) {
|
|
17588
17631
|
if (!name.startsWith("turn-"))
|
|
17589
17632
|
continue;
|
|
17590
|
-
const file =
|
|
17633
|
+
const file = path17.join(dir, name);
|
|
17591
17634
|
try {
|
|
17592
|
-
if (now -
|
|
17593
|
-
|
|
17635
|
+
if (now - fs14.statSync(file).mtimeMs > TURN_TTL_MS)
|
|
17636
|
+
fs14.rmSync(file, { force: true });
|
|
17594
17637
|
} catch {}
|
|
17595
17638
|
}
|
|
17596
17639
|
} catch {}
|
|
@@ -17606,7 +17649,7 @@ var changedTurnContext = (input, text) => {
|
|
|
17606
17649
|
return text;
|
|
17607
17650
|
const digest = digestOf(text);
|
|
17608
17651
|
try {
|
|
17609
|
-
const previous = JSON.parse(
|
|
17652
|
+
const previous = JSON.parse(fs14.readFileSync(file, "utf8"));
|
|
17610
17653
|
if (previous.digest === digest)
|
|
17611
17654
|
return null;
|
|
17612
17655
|
} catch {}
|
|
@@ -17617,14 +17660,14 @@ var seedTurnContext = (input, descriptor, text = turnContextText(input, descript
|
|
|
17617
17660
|
const file = turnMarker(input);
|
|
17618
17661
|
if (!file)
|
|
17619
17662
|
return;
|
|
17620
|
-
pruneTurnDigests(
|
|
17663
|
+
pruneTurnDigests(path17.dirname(file), Date.now());
|
|
17621
17664
|
if (text)
|
|
17622
17665
|
writeTurnDigest(file, digestOf(text));
|
|
17623
17666
|
else
|
|
17624
17667
|
clearTurnDigest(file);
|
|
17625
17668
|
};
|
|
17626
17669
|
// packages/workit-core/src/core/branch.ts
|
|
17627
|
-
import { createHash as
|
|
17670
|
+
import { createHash as createHash12 } from "node:crypto";
|
|
17628
17671
|
var withReleaseTracks = (workspaceRoot, policy) => {
|
|
17629
17672
|
const read = workspaceReleaseTracks(workspaceRoot);
|
|
17630
17673
|
if (read.error)
|
|
@@ -17692,7 +17735,7 @@ var branchPolicySnapshotFor = (workspaceRoot) => {
|
|
|
17692
17735
|
const source = resolved.provenance.branchPolicy;
|
|
17693
17736
|
const allowed = branchPolicy.allowed.map((pattern) => `${pattern.source}/${pattern.flags}`).toSorted();
|
|
17694
17737
|
const protectedRefs = [...branchPolicy.protected].map((name) => name.toLowerCase()).toSorted();
|
|
17695
|
-
const fingerprint =
|
|
17738
|
+
const fingerprint = createHash12("sha256").update(JSON.stringify({ allowed, protectedRefs, source })).digest("hex");
|
|
17696
17739
|
return {
|
|
17697
17740
|
branchPolicy,
|
|
17698
17741
|
namePolicy: { allowed: branchPolicy.allowed, protected: branchPolicy.protected },
|
|
@@ -17741,7 +17784,7 @@ var shellPolicy = (cwd, command) => {
|
|
|
17741
17784
|
};
|
|
17742
17785
|
// packages/workit-core/src/hooks/write-gate.ts
|
|
17743
17786
|
import { realpathSync as realpathSync5 } from "node:fs";
|
|
17744
|
-
import
|
|
17787
|
+
import path18 from "node:path";
|
|
17745
17788
|
|
|
17746
17789
|
// packages/workit-core/src/hooks/shell-words.ts
|
|
17747
17790
|
var closingQuote = (command, start, dialect) => {
|
|
@@ -17871,22 +17914,22 @@ var NONE2 = { kind: "none" };
|
|
|
17871
17914
|
var CASE_INSENSITIVE = process.platform === "darwin" || process.platform === "win32";
|
|
17872
17915
|
var canonical2 = (file) => {
|
|
17873
17916
|
let rest = "";
|
|
17874
|
-
for (let dir =
|
|
17917
|
+
for (let dir = path18.resolve(file);; dir = path18.dirname(dir)) {
|
|
17875
17918
|
try {
|
|
17876
|
-
return
|
|
17919
|
+
return path18.join(realpathSync5(dir), rest);
|
|
17877
17920
|
} catch {
|
|
17878
|
-
if (
|
|
17879
|
-
return
|
|
17880
|
-
rest = rest ?
|
|
17921
|
+
if (path18.dirname(dir) === dir)
|
|
17922
|
+
return path18.resolve(file);
|
|
17923
|
+
rest = rest ? path18.join(path18.basename(dir), rest) : path18.basename(dir);
|
|
17881
17924
|
}
|
|
17882
17925
|
}
|
|
17883
17926
|
};
|
|
17884
17927
|
var exempt = (cwd, root, file, plans) => {
|
|
17885
17928
|
const fold = (value) => CASE_INSENSITIVE ? value.toLowerCase() : value;
|
|
17886
|
-
const relative =
|
|
17887
|
-
if (relative.startsWith("..") ||
|
|
17929
|
+
const relative = path18.relative(fold(canonical2(root)), fold(canonical2(path18.resolve(cwd, file))));
|
|
17930
|
+
if (relative.startsWith("..") || path18.isAbsolute(relative))
|
|
17888
17931
|
return true;
|
|
17889
|
-
const posix = relative.split(
|
|
17932
|
+
const posix = relative.split(path18.sep).join("/");
|
|
17890
17933
|
const segments = posix.split("/");
|
|
17891
17934
|
return /\.mdx?$/i.test(posix) || segments[0] === "docs" || segments.includes("plans") || [...plans].some((plan) => fold(plan) === posix);
|
|
17892
17935
|
};
|
|
@@ -17984,7 +18027,7 @@ var shellWrites = (command) => {
|
|
|
17984
18027
|
return { writes: true, targets: unknown ? null : targets };
|
|
17985
18028
|
};
|
|
17986
18029
|
var cache2 = new Map;
|
|
17987
|
-
var planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(
|
|
18030
|
+
var planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(path18.resolve(root, file)) ?? "-").join("\x00");
|
|
17988
18031
|
var gateFor = (cwd) => {
|
|
17989
18032
|
const store = new TaskStore(cwd);
|
|
17990
18033
|
const listed = store.listTaskIndex();
|
|
@@ -18044,15 +18087,15 @@ import { spawnSync as spawnSync12 } from "node:child_process";
|
|
|
18044
18087
|
|
|
18045
18088
|
// packages/workit-core/src/hooks/raw-git.ts
|
|
18046
18089
|
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
18047
|
-
import { createHash as
|
|
18048
|
-
import
|
|
18090
|
+
import { createHash as createHash14 } from "node:crypto";
|
|
18091
|
+
import fs16 from "node:fs";
|
|
18049
18092
|
import os4 from "node:os";
|
|
18050
|
-
import
|
|
18093
|
+
import path20 from "node:path";
|
|
18051
18094
|
|
|
18052
18095
|
// packages/workit-core/src/hooks/session-marker.ts
|
|
18053
|
-
import { createHash as
|
|
18054
|
-
import
|
|
18055
|
-
import
|
|
18096
|
+
import { createHash as createHash13 } from "node:crypto";
|
|
18097
|
+
import fs15 from "node:fs";
|
|
18098
|
+
import path19 from "node:path";
|
|
18056
18099
|
var sessionMarkerFile = (input, session, store) => {
|
|
18057
18100
|
let dir = store;
|
|
18058
18101
|
if (dir === undefined) {
|
|
@@ -18061,13 +18104,13 @@ var sessionMarkerFile = (input, session, store) => {
|
|
|
18061
18104
|
return null;
|
|
18062
18105
|
dir = location.dir;
|
|
18063
18106
|
}
|
|
18064
|
-
const name =
|
|
18065
|
-
return
|
|
18107
|
+
const name = createHash13("sha256").update(`${input.host}\x00${session}`).digest("hex").slice(0, 32);
|
|
18108
|
+
return path19.join(dir, "hooks", `skills-${name}.json`);
|
|
18066
18109
|
};
|
|
18067
18110
|
var list2 = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
18068
18111
|
var readSessionMarker = (file) => {
|
|
18069
18112
|
try {
|
|
18070
|
-
const value = JSON.parse(
|
|
18113
|
+
const value = JSON.parse(fs15.readFileSync(file, "utf8"));
|
|
18071
18114
|
return { nudged: list2(value.nudged), loaded: list2(value.loaded), raw: list2(value.raw) };
|
|
18072
18115
|
} catch {
|
|
18073
18116
|
return { nudged: [], loaded: [], raw: [] };
|
|
@@ -18075,8 +18118,8 @@ var readSessionMarker = (file) => {
|
|
|
18075
18118
|
};
|
|
18076
18119
|
var writeSessionMarker = (file, marker) => {
|
|
18077
18120
|
try {
|
|
18078
|
-
|
|
18079
|
-
|
|
18121
|
+
fs15.mkdirSync(path19.dirname(file), { recursive: true });
|
|
18122
|
+
fs15.writeFileSync(file, JSON.stringify(marker));
|
|
18080
18123
|
} catch {}
|
|
18081
18124
|
};
|
|
18082
18125
|
|
|
@@ -18097,12 +18140,12 @@ var GIT_VALUE_OPTIONS = new Set([
|
|
|
18097
18140
|
"--config-env",
|
|
18098
18141
|
"--super-prefix"
|
|
18099
18142
|
]);
|
|
18100
|
-
var isAbsolute = (value) =>
|
|
18143
|
+
var isAbsolute = (value) => path20.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\");
|
|
18101
18144
|
var joinDir = (base, next) => {
|
|
18102
18145
|
if (base === undefined || /[$`*?]/.test(next) || next === "-")
|
|
18103
18146
|
return;
|
|
18104
|
-
const expanded = next === "~" || next.startsWith("~/") ?
|
|
18105
|
-
return base === null || isAbsolute(expanded) ? expanded :
|
|
18147
|
+
const expanded = next === "~" || next.startsWith("~/") ? path20.join(os4.homedir(), next.slice(1)) : next;
|
|
18148
|
+
return base === null || isAbsolute(expanded) ? expanded : path20.join(base, expanded);
|
|
18106
18149
|
};
|
|
18107
18150
|
var cdTarget = (words) => {
|
|
18108
18151
|
const args = words.slice(1);
|
|
@@ -18355,7 +18398,7 @@ var repoAt = (dir) => {
|
|
|
18355
18398
|
return { location, dir, branch: resolveTaskKey(dir, location).branch };
|
|
18356
18399
|
};
|
|
18357
18400
|
var isWorkitWorkspace = (repo) => {
|
|
18358
|
-
if (
|
|
18401
|
+
if (fs16.existsSync(repo.location.dir))
|
|
18359
18402
|
return true;
|
|
18360
18403
|
try {
|
|
18361
18404
|
return resolveRuntimeWorkspaceVcs(repo.location.top ?? repo.dir) !== null;
|
|
@@ -18386,17 +18429,17 @@ var headSha2 = (repo) => {
|
|
|
18386
18429
|
if (!git || git.reftable)
|
|
18387
18430
|
return null;
|
|
18388
18431
|
try {
|
|
18389
|
-
const head =
|
|
18432
|
+
const head = fs16.readFileSync(path20.join(git.gitDir, "HEAD"), "utf8").trim();
|
|
18390
18433
|
if (/^[0-9a-f]{40,64}$/.test(head))
|
|
18391
18434
|
return head;
|
|
18392
18435
|
const ref = /^ref: (refs\/.+)$/.exec(head)?.[1];
|
|
18393
18436
|
if (!ref)
|
|
18394
18437
|
return null;
|
|
18395
|
-
const common =
|
|
18438
|
+
const common = path20.dirname(repo.location.dir);
|
|
18396
18439
|
try {
|
|
18397
|
-
return
|
|
18440
|
+
return fs16.readFileSync(path20.join(common, ref), "utf8").trim() || null;
|
|
18398
18441
|
} catch {}
|
|
18399
|
-
const packed =
|
|
18442
|
+
const packed = fs16.readFileSync(path20.join(common, "packed-refs"), "utf8");
|
|
18400
18443
|
return new RegExp(`^([0-9a-f]{40,64}) ${ref.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`, "m").exec(packed)?.[1] ?? null;
|
|
18401
18444
|
} catch {
|
|
18402
18445
|
return null;
|
|
@@ -18433,7 +18476,7 @@ var actionsIn = (cwd, command, dialect) => {
|
|
|
18433
18476
|
const action = rawAction(invocation);
|
|
18434
18477
|
if (!action)
|
|
18435
18478
|
continue;
|
|
18436
|
-
const dir =
|
|
18479
|
+
const dir = path20.resolve(cwd, invocation.dir ?? ".");
|
|
18437
18480
|
if (!repos.has(dir)) {
|
|
18438
18481
|
const repo = repoAt(dir);
|
|
18439
18482
|
repos.set(dir, repo && isWorkitWorkspace(repo) ? repo : null);
|
|
@@ -18502,8 +18545,8 @@ function rawGitPre(input, command, options = {}) {
|
|
|
18502
18545
|
var deny = (reason) => ({ kind: "deny", reason, unblock: null });
|
|
18503
18546
|
var NEXT_COMMAND = "next";
|
|
18504
18547
|
var MARKER_TTL_SECONDS = 3600;
|
|
18505
|
-
var markerFile = (repo, session, key) =>
|
|
18506
|
-
var callKey = (toolUseId, command) => toolUseId ?? `cmd:${
|
|
18548
|
+
var markerFile = (repo, session, key) => path20.join(repo.location.dir, "hooks", `commit-${createHash14("sha256").update(`${session}\x00${key}`).digest("hex").slice(0, 32)}.json`);
|
|
18549
|
+
var callKey = (toolUseId, command) => toolUseId ?? `cmd:${createHash14("sha256").update(command).digest("hex")}`;
|
|
18507
18550
|
function noteRawCommit(input, command, key) {
|
|
18508
18551
|
try {
|
|
18509
18552
|
if (!input.session.id || !/\bcommit\b/.test(command))
|
|
@@ -18513,8 +18556,8 @@ function noteRawCommit(input, command, key) {
|
|
|
18513
18556
|
if (action.kind !== "commit")
|
|
18514
18557
|
continue;
|
|
18515
18558
|
const file = markerFile(repo, input.session.id, key);
|
|
18516
|
-
|
|
18517
|
-
|
|
18559
|
+
fs16.mkdirSync(path20.dirname(file), { recursive: true });
|
|
18560
|
+
fs16.writeFileSync(file, `${JSON.stringify({ head: headSha2(repo), at })}
|
|
18518
18561
|
`);
|
|
18519
18562
|
}
|
|
18520
18563
|
} catch {}
|
|
@@ -18537,11 +18580,11 @@ var headCommit = (dir) => {
|
|
|
18537
18580
|
var settle2 = (input, repo, file) => {
|
|
18538
18581
|
let marker;
|
|
18539
18582
|
try {
|
|
18540
|
-
marker = JSON.parse(
|
|
18583
|
+
marker = JSON.parse(fs16.readFileSync(file, "utf8"));
|
|
18541
18584
|
} catch {
|
|
18542
18585
|
return;
|
|
18543
18586
|
}
|
|
18544
|
-
|
|
18587
|
+
fs16.rmSync(file, { force: true });
|
|
18545
18588
|
const session = input.session.id;
|
|
18546
18589
|
const now = Date.now() / 1000;
|
|
18547
18590
|
if (typeof marker.at !== "number" || now - marker.at > MARKER_TTL_SECONDS)
|
|
@@ -18590,7 +18633,7 @@ function settlePendingCommit(input) {
|
|
|
18590
18633
|
if (!repo)
|
|
18591
18634
|
return;
|
|
18592
18635
|
const file = markerFile(repo, input.session.id, NEXT_COMMAND);
|
|
18593
|
-
if (
|
|
18636
|
+
if (fs16.existsSync(file))
|
|
18594
18637
|
settle2(input, repo, file);
|
|
18595
18638
|
} catch {}
|
|
18596
18639
|
}
|
|
@@ -18980,12 +19023,12 @@ ${line}` };
|
|
|
18980
19023
|
};
|
|
18981
19024
|
// packages/workit-core/src/hooks/hosts/fields.ts
|
|
18982
19025
|
import { existsSync as existsSync6, realpathSync as realpathSync6, statSync as statSync2 } from "node:fs";
|
|
18983
|
-
import
|
|
19026
|
+
import path21 from "node:path";
|
|
18984
19027
|
var isRecord4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
18985
19028
|
var nonEmpty2 = (value) => typeof value === "string" && value.trim() !== "";
|
|
18986
19029
|
var optionalText = (value) => typeof value === "string" ? value : null;
|
|
18987
19030
|
var existingDirectory = (value) => {
|
|
18988
|
-
if (!nonEmpty2(value) || !
|
|
19031
|
+
if (!nonEmpty2(value) || !path21.isAbsolute(value) || !existsSync6(value))
|
|
18989
19032
|
return null;
|
|
18990
19033
|
try {
|
|
18991
19034
|
return statSync2(value).isDirectory() ? realpathSync6(value) : null;
|
|
@@ -19085,6 +19128,8 @@ ${subagentStartText({ ...input, cwd: "" }, descriptor, event)}`;
|
|
|
19085
19128
|
if (role !== "judge" || !event.agentId)
|
|
19086
19129
|
return readOnly;
|
|
19087
19130
|
const own = subagentSession(session, event.agentId);
|
|
19131
|
+
if (session)
|
|
19132
|
+
recordIssuedSession(input.cwd || process.cwd(), session, own);
|
|
19088
19133
|
return `${readOnly} Its own Workit session is ${own}: record verdicts with \`workit ledger verdict <result> --session ${own} ...\` so the ledger tells it apart from the author.`;
|
|
19089
19134
|
};
|
|
19090
19135
|
function handleHook(input, deps) {
|
|
@@ -19716,12 +19761,12 @@ var codexAdapter = {
|
|
|
19716
19761
|
};
|
|
19717
19762
|
},
|
|
19718
19763
|
render: render2,
|
|
19719
|
-
addendum: (input) => `<workit-codex-mutations>Codex MCP is read-only: unattested callers cannot mutate. Run workit verbs with the workit CLI on the shell (node_modules/.bin/workit, or npx -y @brainervirus/workit-cli): check, git branch|commit|push, pr, ci, stack, ledger, handoff; task-family mutations take --json${input.session.id ? ` --actor ${input.session.id}` : ""}. workit acts as this thread (CODEX_THREAD_ID${input.session.id ? `=${input.session.id}` : ""}) unless WORKIT_SESSION_ID is set. A verifier or reviewer records workit ledger verdict under its own session, never the author's: a workit-verifier or workit-reviewer agent uses the --session its SubagentStart context names; any other
|
|
19764
|
+
addendum: (input) => `<workit-codex-mutations>Codex MCP is read-only: unattested callers cannot mutate. Run workit verbs with the workit CLI on the shell (node_modules/.bin/workit, or npx -y @brainervirus/workit-cli): check, git branch|commit|push, pr, ci, stack, ledger, handoff; task-family mutations take --json${input.session.id ? ` --actor ${input.session.id}` : ""}. workit acts as this thread (CODEX_THREAD_ID${input.session.id ? `=${input.session.id}` : ""}) unless WORKIT_SESSION_ID is set. A verifier or reviewer records workit ledger verdict under its own session, never the author's: a workit-verifier or workit-reviewer agent uses the --session its SubagentStart context names; any other passes --as verifier (an id derived from its own thread). A hand-minted id such as <lead>-v1 is refused as forged_session. Merge and release need a workspace grant (workit grant show); a question answer is not host permission.</workit-codex-mutations>`
|
|
19720
19765
|
};
|
|
19721
19766
|
|
|
19722
19767
|
// packages/workit-core/src/hooks/hosts/cursor.ts
|
|
19723
|
-
import
|
|
19724
|
-
import
|
|
19768
|
+
import fs17 from "node:fs";
|
|
19769
|
+
import path22 from "node:path";
|
|
19725
19770
|
var undocumented = { support: "undocumented", native: null };
|
|
19726
19771
|
var none = { support: "none", native: null };
|
|
19727
19772
|
var CURSOR_DESCRIPTOR = {
|
|
@@ -19918,17 +19963,17 @@ var protocolEvent2 = (input) => {
|
|
|
19918
19963
|
};
|
|
19919
19964
|
var TRANSCRIPT_TAIL_BYTES = 256 * 1024;
|
|
19920
19965
|
var lastAssistantText = (file) => {
|
|
19921
|
-
if (!file || !
|
|
19966
|
+
if (!file || !path22.isAbsolute(file))
|
|
19922
19967
|
return null;
|
|
19923
19968
|
try {
|
|
19924
|
-
const size =
|
|
19969
|
+
const size = fs17.statSync(file).size;
|
|
19925
19970
|
const start = Math.max(0, size - TRANSCRIPT_TAIL_BYTES);
|
|
19926
19971
|
const buffer = Buffer.alloc(size - start);
|
|
19927
|
-
const fd =
|
|
19972
|
+
const fd = fs17.openSync(file, "r");
|
|
19928
19973
|
try {
|
|
19929
|
-
|
|
19974
|
+
fs17.readSync(fd, buffer, 0, buffer.length, start);
|
|
19930
19975
|
} finally {
|
|
19931
|
-
|
|
19976
|
+
fs17.closeSync(fd);
|
|
19932
19977
|
}
|
|
19933
19978
|
const lines = buffer.toString("utf8").split(`
|
|
19934
19979
|
`);
|
|
@@ -19955,7 +20000,7 @@ var lastAssistantText = (file) => {
|
|
|
19955
20000
|
return null;
|
|
19956
20001
|
}
|
|
19957
20002
|
};
|
|
19958
|
-
var within = (root, dir) => dir === root || dir.startsWith(root.endsWith(
|
|
20003
|
+
var within = (root, dir) => dir === root || dir.startsWith(root.endsWith(path22.sep) ? root : `${root}${path22.sep}`);
|
|
19959
20004
|
var hookCwd = (input) => {
|
|
19960
20005
|
const cwd = existingDirectory(input.cwd);
|
|
19961
20006
|
if (cwd && input.hook_event_name === "beforeShellExecution")
|