@brainervirus/workit-codex 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/.codex-plugin/plugin.json +1 -1
- package/dist/launch-mcp.js +85 -77
- package/dist/{workit-hook-vjkepg0b.js → workit-hook-xhqhe7h0.js} +381 -338
- package/dist/workit-hook.js +1 -1
- package/package.json +3 -3
- 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
|
@@ -24,9 +24,9 @@ var capabilitiesFor = (descriptor, observed = {}) => descriptor.capabilities.map
|
|
|
24
24
|
};
|
|
25
25
|
});
|
|
26
26
|
// packages/workit-core/src/hooks/context.ts
|
|
27
|
-
import { createHash as
|
|
28
|
-
import
|
|
29
|
-
import
|
|
27
|
+
import { createHash as createHash11 } from "node:crypto";
|
|
28
|
+
import fs14 from "node:fs";
|
|
29
|
+
import path17 from "node:path";
|
|
30
30
|
|
|
31
31
|
// packages/workit-core/src/core/methods.ts
|
|
32
32
|
var METHODS = {
|
|
@@ -101,7 +101,8 @@ Autonomy contract:
|
|
|
101
101
|
satisfies a gate; an ad-hoc \`workit check -- <cmd>\` never does.
|
|
102
102
|
- Author is not verifier: your own verdict is \`--self\`, shown as
|
|
103
103
|
self-reviewed, never verified. High risk, \`verification: independent\` and
|
|
104
|
-
merge need a verifier with its own session (
|
|
104
|
+
merge need a verifier with its own host-derived session (a subagent's
|
|
105
|
+
\`<lead>:<child>\`, set by the host); never hand-mint one such as \`<lead>-v1\`.
|
|
105
106
|
- A local-commit endpoint does not imply PR readiness, and a local commit alone
|
|
106
107
|
is not evidence of a requested remote push. Before reporting delivery,
|
|
107
108
|
reconcile every requested item and observe it (\`workit verify-delivery\`).
|
|
@@ -8787,10 +8788,10 @@ function requirementId(input) {
|
|
|
8787
8788
|
}
|
|
8788
8789
|
|
|
8789
8790
|
// packages/workit-core/src/core/task-evaluation.ts
|
|
8790
|
-
import { createHash as
|
|
8791
|
-
import * as
|
|
8791
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
8792
|
+
import * as fs13 from "node:fs";
|
|
8792
8793
|
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
8793
|
-
import
|
|
8794
|
+
import path15 from "node:path";
|
|
8794
8795
|
|
|
8795
8796
|
// packages/workit-core/src/check-config.ts
|
|
8796
8797
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
@@ -9179,9 +9180,9 @@ function pushRemoteName(cwd, branch) {
|
|
|
9179
9180
|
}
|
|
9180
9181
|
|
|
9181
9182
|
// packages/workit-core/src/core/task-store.ts
|
|
9182
|
-
import { createHash as
|
|
9183
|
-
import * as
|
|
9184
|
-
import
|
|
9183
|
+
import { createHash as createHash6, randomUUID as randomUUID3 } from "node:crypto";
|
|
9184
|
+
import * as fs10 from "node:fs";
|
|
9185
|
+
import path9 from "node:path";
|
|
9185
9186
|
|
|
9186
9187
|
// node_modules/@openclaw/fs-safe/dist/errors.js
|
|
9187
9188
|
var OPERATIONAL_CODES = new Set([
|
|
@@ -9785,6 +9786,9 @@ function acquireFileLockSync(targetPath, options) {
|
|
|
9785
9786
|
}
|
|
9786
9787
|
}
|
|
9787
9788
|
// packages/workit-core/src/host-session.ts
|
|
9789
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
9790
|
+
import fs7 from "node:fs";
|
|
9791
|
+
import path6 from "node:path";
|
|
9788
9792
|
var HOST_SESSION_VARS = [
|
|
9789
9793
|
["OPENCODE_SESSION_ID", () => "opencode"],
|
|
9790
9794
|
["PI_SESSION_ID", () => "pi"],
|
|
@@ -9812,16 +9816,44 @@ function hostSessionFromEnv(env) {
|
|
|
9812
9816
|
}
|
|
9813
9817
|
return inner ? { host: inner.host, session: inner.session } : { host: declared, session: null };
|
|
9814
9818
|
}
|
|
9819
|
+
var ISSUED_PER_LEAD = 64;
|
|
9820
|
+
var ISSUED_SESSIONS_MARKER = "workit-issued-sessions/1";
|
|
9821
|
+
var hash = (value) => createHash4("sha256").update(value).digest("hex").slice(0, 32);
|
|
9822
|
+
var issuedRoot = (cwd) => {
|
|
9823
|
+
const location = resolveStore(cwd);
|
|
9824
|
+
return location instanceof Error ? null : path6.join(location.dir, "hooks", "issued");
|
|
9825
|
+
};
|
|
9826
|
+
var issuedDir = (cwd, lead) => {
|
|
9827
|
+
const root = issuedRoot(cwd);
|
|
9828
|
+
return root === null ? null : path6.join(root, hash(lead));
|
|
9829
|
+
};
|
|
9830
|
+
function recordIssuedSession(cwd, lead, issued) {
|
|
9831
|
+
try {
|
|
9832
|
+
const dir = issuedDir(cwd, lead);
|
|
9833
|
+
if (!dir)
|
|
9834
|
+
return;
|
|
9835
|
+
fs7.mkdirSync(dir, { recursive: true });
|
|
9836
|
+
const own = hash(issued);
|
|
9837
|
+
fs7.writeFileSync(path6.join(dir, own), ISSUED_SESSIONS_MARKER);
|
|
9838
|
+
const entries = fs7.readdirSync(dir);
|
|
9839
|
+
if (entries.length <= ISSUED_PER_LEAD)
|
|
9840
|
+
return;
|
|
9841
|
+
const byAge = entries.filter((name) => name !== own).map((name) => ({ name, at: fs7.statSync(path6.join(dir, name)).mtimeMs })).toSorted((a, b) => a.at - b.at);
|
|
9842
|
+
for (const { name } of byAge.slice(0, entries.length - ISSUED_PER_LEAD))
|
|
9843
|
+
fs7.rmSync(path6.join(dir, name), { force: true });
|
|
9844
|
+
} catch {}
|
|
9845
|
+
}
|
|
9846
|
+
var OWN_CHILD_SHELL = new Set(["opencode", "pi"]);
|
|
9815
9847
|
|
|
9816
9848
|
// packages/workit-core/src/core/package-root.ts
|
|
9817
9849
|
import { existsSync } from "node:fs";
|
|
9818
|
-
import
|
|
9850
|
+
import path7 from "node:path";
|
|
9819
9851
|
import { fileURLToPath } from "node:url";
|
|
9820
9852
|
var packageRoot = () => {
|
|
9821
|
-
let dir =
|
|
9853
|
+
let dir = path7.dirname(fileURLToPath(import.meta.url));
|
|
9822
9854
|
while (true) {
|
|
9823
|
-
const parent =
|
|
9824
|
-
if (existsSync(
|
|
9855
|
+
const parent = path7.dirname(dir);
|
|
9856
|
+
if (existsSync(path7.join(dir, "package.json")) || parent === dir)
|
|
9825
9857
|
return dir;
|
|
9826
9858
|
dir = parent;
|
|
9827
9859
|
}
|
|
@@ -9829,7 +9861,7 @@ var packageRoot = () => {
|
|
|
9829
9861
|
|
|
9830
9862
|
// packages/workit-core/src/core/store-lock.ts
|
|
9831
9863
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
9832
|
-
import
|
|
9864
|
+
import fs8 from "node:fs";
|
|
9833
9865
|
import { hostname } from "node:os";
|
|
9834
9866
|
var metadataLockSchema = object({
|
|
9835
9867
|
pid: number2().int().nonnegative().safe(),
|
|
@@ -9871,7 +9903,7 @@ var parseProcStatStart = (stat) => {
|
|
|
9871
9903
|
var processStartOf = (pid) => {
|
|
9872
9904
|
if (process.platform === "linux") {
|
|
9873
9905
|
try {
|
|
9874
|
-
return parseProcStatStart(
|
|
9906
|
+
return parseProcStatStart(fs8.readFileSync(`/proc/${pid}/stat`, "utf8"));
|
|
9875
9907
|
} catch {
|
|
9876
9908
|
return null;
|
|
9877
9909
|
}
|
|
@@ -9892,7 +9924,7 @@ var processStartOf = (pid) => {
|
|
|
9892
9924
|
};
|
|
9893
9925
|
var readTrimmed = (file) => {
|
|
9894
9926
|
try {
|
|
9895
|
-
return
|
|
9927
|
+
return fs8.readFileSync(file, "utf8").trim() || null;
|
|
9896
9928
|
} catch {
|
|
9897
9929
|
return null;
|
|
9898
9930
|
}
|
|
@@ -9903,7 +9935,7 @@ var localLockHost = () => {
|
|
|
9903
9935
|
return cachedLockHost;
|
|
9904
9936
|
let pidns = null;
|
|
9905
9937
|
try {
|
|
9906
|
-
pidns = /\[(\d+)\]/.exec(
|
|
9938
|
+
pidns = /\[(\d+)\]/.exec(fs8.readlinkSync("/proc/self/ns/pid"))?.[1] ?? null;
|
|
9907
9939
|
} catch {}
|
|
9908
9940
|
const boot = readTrimmed("/proc/sys/kernel/random/boot_id");
|
|
9909
9941
|
cachedLockHost = pidns || boot ? `${hostname()}#${pidns ?? "?"}:${boot ?? "?"}` : hostname();
|
|
@@ -9949,7 +9981,7 @@ var classifyLockOwner = (payload, ageMs, localHost = localLockHost(), options =
|
|
|
9949
9981
|
};
|
|
9950
9982
|
var ageOf = (file, nowMs) => {
|
|
9951
9983
|
try {
|
|
9952
|
-
return nowMs -
|
|
9984
|
+
return nowMs - fs8.lstatSync(file).mtimeMs;
|
|
9953
9985
|
} catch {
|
|
9954
9986
|
return null;
|
|
9955
9987
|
}
|
|
@@ -9960,7 +9992,7 @@ var clearAbandonedReclaimGuard = (lockPath, nowMs = Date.now()) => {
|
|
|
9960
9992
|
if (age === null || age <= RECLAIM_GUARD_TTL_MS)
|
|
9961
9993
|
return false;
|
|
9962
9994
|
try {
|
|
9963
|
-
|
|
9995
|
+
fs8.rmdirSync(guard);
|
|
9964
9996
|
return true;
|
|
9965
9997
|
} catch {
|
|
9966
9998
|
return false;
|
|
@@ -9969,8 +10001,8 @@ var clearAbandonedReclaimGuard = (lockPath, nowMs = Date.now()) => {
|
|
|
9969
10001
|
|
|
9970
10002
|
// packages/workit-core/src/store/event-log.ts
|
|
9971
10003
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
9972
|
-
import
|
|
9973
|
-
import
|
|
10004
|
+
import fs9 from "node:fs";
|
|
10005
|
+
import path8 from "node:path";
|
|
9974
10006
|
var EVENT_VERSION = 1;
|
|
9975
10007
|
|
|
9976
10008
|
class LogDamage extends Error {
|
|
@@ -9999,7 +10031,7 @@ var parseEvent = (line, file, offset) => {
|
|
|
9999
10031
|
function readLog(file, from = 0, expectSeq = null) {
|
|
10000
10032
|
let fd;
|
|
10001
10033
|
try {
|
|
10002
|
-
fd =
|
|
10034
|
+
fd = fs9.openSync(file, "r");
|
|
10003
10035
|
} catch (error) {
|
|
10004
10036
|
if (error.code === "ENOENT")
|
|
10005
10037
|
return null;
|
|
@@ -10008,13 +10040,13 @@ function readLog(file, from = 0, expectSeq = null) {
|
|
|
10008
10040
|
let bytes;
|
|
10009
10041
|
let size;
|
|
10010
10042
|
try {
|
|
10011
|
-
size =
|
|
10043
|
+
size = fs9.fstatSync(fd).size;
|
|
10012
10044
|
if (from > size)
|
|
10013
10045
|
throw new LogDamage(`${file}: shorter than its snapshot`);
|
|
10014
10046
|
bytes = Buffer.alloc(size - from);
|
|
10015
10047
|
let read = 0;
|
|
10016
10048
|
while (read < bytes.length) {
|
|
10017
|
-
const got =
|
|
10049
|
+
const got = fs9.readSync(fd, bytes, read, bytes.length - read, from + read);
|
|
10018
10050
|
if (got === 0)
|
|
10019
10051
|
break;
|
|
10020
10052
|
read += got;
|
|
@@ -10022,7 +10054,7 @@ function readLog(file, from = 0, expectSeq = null) {
|
|
|
10022
10054
|
bytes = bytes.subarray(0, read);
|
|
10023
10055
|
size = from + read;
|
|
10024
10056
|
} finally {
|
|
10025
|
-
|
|
10057
|
+
fs9.closeSync(fd);
|
|
10026
10058
|
}
|
|
10027
10059
|
const events = [];
|
|
10028
10060
|
let start = 0;
|
|
@@ -10047,11 +10079,11 @@ function readLog(file, from = 0, expectSeq = null) {
|
|
|
10047
10079
|
}
|
|
10048
10080
|
var fsyncDirectory = (dir) => {
|
|
10049
10081
|
try {
|
|
10050
|
-
const fd =
|
|
10082
|
+
const fd = fs9.openSync(dir, "r");
|
|
10051
10083
|
try {
|
|
10052
|
-
|
|
10084
|
+
fs9.fsyncSync(fd);
|
|
10053
10085
|
} finally {
|
|
10054
|
-
|
|
10086
|
+
fs9.closeSync(fd);
|
|
10055
10087
|
}
|
|
10056
10088
|
} catch (error) {
|
|
10057
10089
|
if (process.platform !== "win32")
|
|
@@ -10061,46 +10093,46 @@ var fsyncDirectory = (dir) => {
|
|
|
10061
10093
|
function appendEvent(file, event, validEnd) {
|
|
10062
10094
|
const line = Buffer.from(`${JSON.stringify(event)}
|
|
10063
10095
|
`, "utf8");
|
|
10064
|
-
const created = !
|
|
10065
|
-
if (!created &&
|
|
10066
|
-
const cut =
|
|
10096
|
+
const created = !fs9.existsSync(file);
|
|
10097
|
+
if (!created && fs9.statSync(file).size !== validEnd) {
|
|
10098
|
+
const cut = fs9.openSync(file, "r+");
|
|
10067
10099
|
try {
|
|
10068
|
-
|
|
10069
|
-
|
|
10100
|
+
fs9.ftruncateSync(cut, validEnd);
|
|
10101
|
+
fs9.fsyncSync(cut);
|
|
10070
10102
|
} finally {
|
|
10071
|
-
|
|
10103
|
+
fs9.closeSync(cut);
|
|
10072
10104
|
}
|
|
10073
10105
|
}
|
|
10074
|
-
const fd =
|
|
10106
|
+
const fd = fs9.openSync(file, "a", 384);
|
|
10075
10107
|
try {
|
|
10076
10108
|
let written = 0;
|
|
10077
10109
|
while (written < line.length)
|
|
10078
|
-
written +=
|
|
10079
|
-
|
|
10110
|
+
written += fs9.writeSync(fd, line, written, line.length - written);
|
|
10111
|
+
fs9.fsyncSync(fd);
|
|
10080
10112
|
} finally {
|
|
10081
|
-
|
|
10113
|
+
fs9.closeSync(fd);
|
|
10082
10114
|
}
|
|
10083
10115
|
if (created)
|
|
10084
|
-
fsyncDirectory(
|
|
10116
|
+
fsyncDirectory(path8.dirname(file));
|
|
10085
10117
|
return validEnd;
|
|
10086
10118
|
}
|
|
10087
10119
|
function replaceFile(file, bytes, durable) {
|
|
10088
10120
|
const temporary = `${file}.${process.pid}.${randomUUID2()}.tmp`;
|
|
10089
10121
|
try {
|
|
10090
|
-
const fd =
|
|
10122
|
+
const fd = fs9.openSync(temporary, "wx", 384);
|
|
10091
10123
|
try {
|
|
10092
|
-
|
|
10124
|
+
fs9.writeSync(fd, bytes);
|
|
10093
10125
|
if (durable)
|
|
10094
|
-
|
|
10126
|
+
fs9.fsyncSync(fd);
|
|
10095
10127
|
} finally {
|
|
10096
|
-
|
|
10128
|
+
fs9.closeSync(fd);
|
|
10097
10129
|
}
|
|
10098
10130
|
renameWithRetry(temporary, file);
|
|
10099
10131
|
if (durable)
|
|
10100
|
-
fsyncDirectory(
|
|
10132
|
+
fsyncDirectory(path8.dirname(file));
|
|
10101
10133
|
} catch (error) {
|
|
10102
10134
|
try {
|
|
10103
|
-
|
|
10135
|
+
fs9.unlinkSync(temporary);
|
|
10104
10136
|
} catch {}
|
|
10105
10137
|
throw error;
|
|
10106
10138
|
}
|
|
@@ -10125,7 +10157,7 @@ var retryTransient = (run) => {
|
|
|
10125
10157
|
}
|
|
10126
10158
|
}
|
|
10127
10159
|
};
|
|
10128
|
-
var renameWithRetry = (from, to) => retryTransient(() =>
|
|
10160
|
+
var renameWithRetry = (from, to) => retryTransient(() => fs9.renameSync(from, to));
|
|
10129
10161
|
|
|
10130
10162
|
// packages/workit-core/src/store/patch.ts
|
|
10131
10163
|
var isPlainObject2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -10238,7 +10270,7 @@ var isPatch = (value) => Array.isArray(value) && value.every((op) => {
|
|
|
10238
10270
|
});
|
|
10239
10271
|
|
|
10240
10272
|
// packages/workit-core/src/store/reduce.ts
|
|
10241
|
-
import { createHash as
|
|
10273
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
10242
10274
|
var OPENING_TYPES = new Set([
|
|
10243
10275
|
"task.opened",
|
|
10244
10276
|
"task.imported",
|
|
@@ -10267,7 +10299,7 @@ var isObject3 = (value) => typeof value === "object" && value !== null && !Array
|
|
|
10267
10299
|
var isKey = (value) => isObject3(value) && typeof value.key === "string" && (value.kind === "branch" || value.kind === "detached" || value.kind === "dir") && (value.branch === null || typeof value.branch === "string");
|
|
10268
10300
|
var BLOB_REF = "$blob";
|
|
10269
10301
|
var blobRef = (value) => isObject3(value) && Object.keys(value).length === 1 && typeof value[BLOB_REF] === "string" && /^[0-9a-f]{64}$/.test(value[BLOB_REF]) ? value[BLOB_REF] : null;
|
|
10270
|
-
var blobDigest = (value) =>
|
|
10302
|
+
var blobDigest = (value) => createHash5("sha256").update(JSON.stringify(value)).digest("hex");
|
|
10271
10303
|
var toBlob = (value, blobs) => {
|
|
10272
10304
|
if (!isObject3(value))
|
|
10273
10305
|
return value;
|
|
@@ -10422,7 +10454,7 @@ var indexEntry = (task, key, legacy, file) => {
|
|
|
10422
10454
|
};
|
|
10423
10455
|
var fileSignature = (file) => {
|
|
10424
10456
|
try {
|
|
10425
|
-
const stat =
|
|
10457
|
+
const stat = fs10.statSync(file, { bigint: true });
|
|
10426
10458
|
return `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeNs}:${stat.ctimeNs}`;
|
|
10427
10459
|
} catch {
|
|
10428
10460
|
return null;
|
|
@@ -10440,7 +10472,7 @@ var cachedRuntimeVersion = null;
|
|
|
10440
10472
|
var runtimeVersion = () => {
|
|
10441
10473
|
if (cachedRuntimeVersion === null) {
|
|
10442
10474
|
try {
|
|
10443
|
-
const pkg = JSON.parse(
|
|
10475
|
+
const pkg = JSON.parse(fs10.readFileSync(path9.join(packageRoot(), "package.json"), "utf8"));
|
|
10444
10476
|
cachedRuntimeVersion = typeof pkg.version === "string" && pkg.version ? pkg.version : "0.0.0";
|
|
10445
10477
|
} catch {
|
|
10446
10478
|
cachedRuntimeVersion = "0.0.0";
|
|
@@ -10466,14 +10498,14 @@ var isNewerVersion = (candidate, current) => {
|
|
|
10466
10498
|
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);
|
|
10467
10499
|
var readText = (file) => {
|
|
10468
10500
|
try {
|
|
10469
|
-
return
|
|
10501
|
+
return fs10.readFileSync(file, "utf8");
|
|
10470
10502
|
} catch {
|
|
10471
10503
|
return "";
|
|
10472
10504
|
}
|
|
10473
10505
|
};
|
|
10474
10506
|
var REFLOG_LINE = /^[0-9a-f]+ ([0-9a-f]+) .* (\d+) [+-]\d{4}\t(.*)$/u;
|
|
10475
10507
|
var branchStart = (location, branch, aliases) => {
|
|
10476
|
-
const first = readText(
|
|
10508
|
+
const first = readText(path9.join(path9.dirname(location.dir), "logs", "refs", "heads", branch)).split(`
|
|
10477
10509
|
`, 1)[0];
|
|
10478
10510
|
const created = REFLOG_LINE.exec(first);
|
|
10479
10511
|
const start = created && /^branch: Created from (\S+)$/u.exec(created[3])?.[1];
|
|
@@ -10483,7 +10515,7 @@ var branchStart = (location, branch, aliases) => {
|
|
|
10483
10515
|
return start;
|
|
10484
10516
|
if (!location.git)
|
|
10485
10517
|
return null;
|
|
10486
|
-
for (const line of readText(
|
|
10518
|
+
for (const line of readText(path9.join(location.git.gitDir, "logs", "HEAD")).split(`
|
|
10487
10519
|
`)) {
|
|
10488
10520
|
const entry = REFLOG_LINE.exec(line);
|
|
10489
10521
|
const moved = entry && /^checkout: moving from (\S+) to (\S+)$/u.exec(entry[3]);
|
|
@@ -10493,23 +10525,23 @@ var branchStart = (location, branch, aliases) => {
|
|
|
10493
10525
|
}
|
|
10494
10526
|
return null;
|
|
10495
10527
|
};
|
|
10496
|
-
var refExists = (common, ref) =>
|
|
10528
|
+
var refExists = (common, ref) => fs10.existsSync(path9.join(common, ref)) || readText(path9.join(common, "packed-refs")).includes(` ${ref}
|
|
10497
10529
|
`);
|
|
10498
10530
|
var origins = new Map;
|
|
10499
10531
|
var sameDirectoryIdentity = (left, right) => {
|
|
10500
|
-
if (!
|
|
10532
|
+
if (!path9.isAbsolute(left) || !path9.isAbsolute(right))
|
|
10501
10533
|
return false;
|
|
10502
|
-
const normalizedLeft =
|
|
10503
|
-
const normalizedRight =
|
|
10534
|
+
const normalizedLeft = path9.resolve(left);
|
|
10535
|
+
const normalizedRight = path9.resolve(right);
|
|
10504
10536
|
try {
|
|
10505
|
-
const a =
|
|
10506
|
-
const b =
|
|
10537
|
+
const a = fs10.statSync(normalizedLeft, { bigint: true });
|
|
10538
|
+
const b = fs10.statSync(normalizedRight, { bigint: true });
|
|
10507
10539
|
if (!a.isDirectory() || !b.isDirectory())
|
|
10508
10540
|
return false;
|
|
10509
10541
|
if (process.platform === "win32" ? normalizedLeft.toLowerCase() === normalizedRight.toLowerCase() : normalizedLeft === normalizedRight)
|
|
10510
10542
|
return true;
|
|
10511
|
-
const canonicalLeft =
|
|
10512
|
-
const canonicalRight =
|
|
10543
|
+
const canonicalLeft = fs10.realpathSync(normalizedLeft);
|
|
10544
|
+
const canonicalRight = fs10.realpathSync(normalizedRight);
|
|
10513
10545
|
if (process.platform === "win32" ? canonicalLeft.toLowerCase() === canonicalRight.toLowerCase() : canonicalLeft === canonicalRight)
|
|
10514
10546
|
return true;
|
|
10515
10547
|
return a.dev === b.dev && a.ino !== 0n && a.ino === b.ino;
|
|
@@ -10546,8 +10578,8 @@ class TaskStore {
|
|
|
10546
10578
|
migrationChecked = false;
|
|
10547
10579
|
compactDue = new Set;
|
|
10548
10580
|
constructor(root, options = {}) {
|
|
10549
|
-
const resolved =
|
|
10550
|
-
this.origin =
|
|
10581
|
+
const resolved = path9.resolve(root);
|
|
10582
|
+
this.origin = fs10.existsSync(resolved) ? fs10.realpathSync(resolved) : resolved;
|
|
10551
10583
|
this.located = resolveStore(this.origin);
|
|
10552
10584
|
this.root = checkoutRootOf(this.origin, this.located);
|
|
10553
10585
|
this.lockTimeoutMs = options.lockTimeoutMs ?? defaultLockTimeout();
|
|
@@ -10555,7 +10587,7 @@ class TaskStore {
|
|
|
10555
10587
|
this.migrateOnRead = options.migrateOnRead;
|
|
10556
10588
|
}
|
|
10557
10589
|
location() {
|
|
10558
|
-
if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared &&
|
|
10590
|
+
if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared && fs10.existsSync(path9.join(this.root, ".git"))) {
|
|
10559
10591
|
this.located = undefined;
|
|
10560
10592
|
this.migrationChecked = false;
|
|
10561
10593
|
}
|
|
@@ -10619,7 +10651,7 @@ class TaskStore {
|
|
|
10619
10651
|
const tasksDir = this.paths().tasks;
|
|
10620
10652
|
let names;
|
|
10621
10653
|
try {
|
|
10622
|
-
names =
|
|
10654
|
+
names = fs10.existsSync(tasksDir) ? fs10.readdirSync(tasksDir).filter((name) => validId(name)) : [];
|
|
10623
10655
|
} catch (error) {
|
|
10624
10656
|
return failure2("storage_error", `unable to list tasks: ${String(error)}`, {
|
|
10625
10657
|
path: tasksDir
|
|
@@ -10660,7 +10692,7 @@ class TaskStore {
|
|
|
10660
10692
|
const file = this.paths().workspace;
|
|
10661
10693
|
let bytes;
|
|
10662
10694
|
try {
|
|
10663
|
-
bytes = retryTransient(() =>
|
|
10695
|
+
bytes = retryTransient(() => fs10.readFileSync(file, "utf8"));
|
|
10664
10696
|
} catch (error) {
|
|
10665
10697
|
if (error.code === "ENOENT")
|
|
10666
10698
|
return success(null, null, null);
|
|
@@ -10711,7 +10743,7 @@ class TaskStore {
|
|
|
10711
10743
|
const moved = this.bindLocked(again.data.id, key, input.now);
|
|
10712
10744
|
return moved.ok ? success(moved.data.revision, null, { task: moved.data, created: false, key }) : moved;
|
|
10713
10745
|
}
|
|
10714
|
-
const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" :
|
|
10746
|
+
const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" : path9.basename(this.root) || this.root;
|
|
10715
10747
|
const intent = {
|
|
10716
10748
|
objective: input.objective?.trim() || `Work on ${label}`,
|
|
10717
10749
|
scope: { description: `the checkout (${label})`, paths: ["."], exclusions: [] },
|
|
@@ -10771,14 +10803,14 @@ class TaskStore {
|
|
|
10771
10803
|
const branch = key.ok ? key.data.branch : null;
|
|
10772
10804
|
if (!branch || !location.ok)
|
|
10773
10805
|
return success(null, null, null);
|
|
10774
|
-
const common =
|
|
10775
|
-
const heads =
|
|
10776
|
-
const headLog = location.data.git ?
|
|
10806
|
+
const common = path9.dirname(location.data.dir);
|
|
10807
|
+
const heads = path9.join(common, "logs", "refs", "heads");
|
|
10808
|
+
const headLog = location.data.git ? path9.join(location.data.git.gitDir, "logs", "HEAD") : "";
|
|
10777
10809
|
const signatures = [
|
|
10778
|
-
|
|
10810
|
+
path9.join(heads, branch),
|
|
10779
10811
|
headLog,
|
|
10780
10812
|
heads,
|
|
10781
|
-
|
|
10813
|
+
path9.join(common, "packed-refs")
|
|
10782
10814
|
].map((file) => fileSignature(file) ?? "-");
|
|
10783
10815
|
const slot = `${location.data.dir}\x00${headLog}\x00${branch}`;
|
|
10784
10816
|
let resolved = origins.get(slot);
|
|
@@ -10790,7 +10822,7 @@ class TaskStore {
|
|
|
10790
10822
|
aliases.push(rename.from);
|
|
10791
10823
|
const start = branchStart(location.data, branch, aliases);
|
|
10792
10824
|
const slash = start?.indexOf("/") ?? -1;
|
|
10793
|
-
const remote = slash > 0 && !refExists(common, `refs/heads/${start}`) && (refExists(common, `refs/remotes/${start}`) || readText(
|
|
10825
|
+
const remote = slash > 0 && !refExists(common, `refs/heads/${start}`) && (refExists(common, `refs/remotes/${start}`) || readText(path9.join(common, "config")).includes(`[remote "${start.slice(0, slash)}"]`));
|
|
10794
10826
|
const name = start && (remote ? start.slice(slash + 1) : start);
|
|
10795
10827
|
resolved = {
|
|
10796
10828
|
signature: signatures.join("|"),
|
|
@@ -11028,13 +11060,13 @@ class TaskStore {
|
|
|
11028
11060
|
if (!ready.ok)
|
|
11029
11061
|
return ready;
|
|
11030
11062
|
const dirs = this.paths();
|
|
11031
|
-
const recovery =
|
|
11032
|
-
if (
|
|
11063
|
+
const recovery = path9.join(this.root, ".workit", "recovery");
|
|
11064
|
+
if (fs10.existsSync(recovery)) {
|
|
11033
11065
|
let files = 0;
|
|
11034
11066
|
let bytes = 0;
|
|
11035
11067
|
try {
|
|
11036
|
-
for (const name of
|
|
11037
|
-
const stat =
|
|
11068
|
+
for (const name of fs10.readdirSync(recovery)) {
|
|
11069
|
+
const stat = fs10.lstatSync(path9.join(recovery, name));
|
|
11038
11070
|
if (!stat.isFile())
|
|
11039
11071
|
continue;
|
|
11040
11072
|
files += 1;
|
|
@@ -11043,17 +11075,17 @@ class TaskStore {
|
|
|
11043
11075
|
} catch {}
|
|
11044
11076
|
const remove = options.pruneRecovery === true && !dryRun;
|
|
11045
11077
|
if (remove)
|
|
11046
|
-
|
|
11078
|
+
fs10.rmSync(recovery, { recursive: true, force: true });
|
|
11047
11079
|
report.legacyRecovery = { path: recovery, files, bytes, removed: remove };
|
|
11048
11080
|
}
|
|
11049
|
-
if (!
|
|
11081
|
+
if (!fs10.existsSync(dirs.tasks))
|
|
11050
11082
|
return success(null, null, report);
|
|
11051
|
-
const names =
|
|
11083
|
+
const names = fs10.readdirSync(dirs.tasks).filter((name) => validId(name));
|
|
11052
11084
|
for (const name of names) {
|
|
11053
11085
|
const file = this.eventsPath(name);
|
|
11054
11086
|
let size = 0;
|
|
11055
11087
|
try {
|
|
11056
|
-
size =
|
|
11088
|
+
size = fs10.statSync(file).size;
|
|
11057
11089
|
} catch {
|
|
11058
11090
|
continue;
|
|
11059
11091
|
}
|
|
@@ -11081,16 +11113,16 @@ class TaskStore {
|
|
|
11081
11113
|
const references = new Set;
|
|
11082
11114
|
for (const name of names)
|
|
11083
11115
|
try {
|
|
11084
|
-
for (const match of
|
|
11116
|
+
for (const match of fs10.readFileSync(this.eventsPath(name), "utf8").matchAll(/"\$blob":"([0-9a-f]{64})"/g))
|
|
11085
11117
|
references.add(match[1]);
|
|
11086
11118
|
} catch {}
|
|
11087
|
-
if (
|
|
11088
|
-
for (const name of
|
|
11119
|
+
if (fs10.existsSync(dirs.blobs))
|
|
11120
|
+
for (const name of fs10.readdirSync(dirs.blobs)) {
|
|
11089
11121
|
const digest = name.replace(/\.json$/, "");
|
|
11090
|
-
const file =
|
|
11122
|
+
const file = path9.join(dirs.blobs, name);
|
|
11091
11123
|
let stat;
|
|
11092
11124
|
try {
|
|
11093
|
-
stat =
|
|
11125
|
+
stat = fs10.lstatSync(file);
|
|
11094
11126
|
} catch {
|
|
11095
11127
|
continue;
|
|
11096
11128
|
}
|
|
@@ -11101,11 +11133,11 @@ class TaskStore {
|
|
|
11101
11133
|
report.blobs.removed += 1;
|
|
11102
11134
|
report.blobs.removedBytes += stat.size;
|
|
11103
11135
|
if (!dryRun)
|
|
11104
|
-
|
|
11136
|
+
fs10.rmSync(file, { force: true });
|
|
11105
11137
|
}
|
|
11106
11138
|
return success(null, null, null);
|
|
11107
11139
|
};
|
|
11108
|
-
const swept = dryRun ? sweep() : this.withLock(
|
|
11140
|
+
const swept = dryRun ? sweep() : this.withLock(path9.join(dirs.dir, "gc.lock"), sweep);
|
|
11109
11141
|
if (!swept.ok)
|
|
11110
11142
|
return swept;
|
|
11111
11143
|
const temporaryDirs = [
|
|
@@ -11113,17 +11145,17 @@ class TaskStore {
|
|
|
11113
11145
|
dirs.tasks,
|
|
11114
11146
|
dirs.blobs,
|
|
11115
11147
|
dirs.checkout,
|
|
11116
|
-
...names.map((name) =>
|
|
11148
|
+
...names.map((name) => path9.join(dirs.tasks, name))
|
|
11117
11149
|
];
|
|
11118
11150
|
for (const directory of temporaryDirs) {
|
|
11119
|
-
if (!
|
|
11151
|
+
if (!fs10.existsSync(directory))
|
|
11120
11152
|
continue;
|
|
11121
|
-
for (const name of
|
|
11153
|
+
for (const name of fs10.readdirSync(directory)) {
|
|
11122
11154
|
if (!name.endsWith(".tmp") && !name.endsWith(".probe"))
|
|
11123
11155
|
continue;
|
|
11124
|
-
const file =
|
|
11156
|
+
const file = path9.join(directory, name);
|
|
11125
11157
|
try {
|
|
11126
|
-
const stat =
|
|
11158
|
+
const stat = fs10.lstatSync(file);
|
|
11127
11159
|
if (!stat.isFile() || nowMs - stat.mtimeMs <= STALE_TEMPORARY_MS)
|
|
11128
11160
|
continue;
|
|
11129
11161
|
} catch {
|
|
@@ -11131,37 +11163,37 @@ class TaskStore {
|
|
|
11131
11163
|
}
|
|
11132
11164
|
report.temporary.removed += 1;
|
|
11133
11165
|
if (!dryRun)
|
|
11134
|
-
|
|
11166
|
+
fs10.rmSync(file, { force: true });
|
|
11135
11167
|
}
|
|
11136
11168
|
}
|
|
11137
11169
|
return success(null, null, report);
|
|
11138
11170
|
}
|
|
11139
11171
|
paths() {
|
|
11140
11172
|
const location = this.location();
|
|
11141
|
-
const dir = location.ok ? location.data.dir :
|
|
11142
|
-
const checkout =
|
|
11173
|
+
const dir = location.ok ? location.data.dir : path9.join(this.root, ".workit");
|
|
11174
|
+
const checkout = path9.join(dir, "checkouts", checkoutSlug(this.root));
|
|
11143
11175
|
return {
|
|
11144
11176
|
dir,
|
|
11145
11177
|
shared: location.ok ? location.data.shared : false,
|
|
11146
|
-
marker:
|
|
11178
|
+
marker: path9.join(dir, "store.json"),
|
|
11147
11179
|
checkout,
|
|
11148
|
-
workspace:
|
|
11149
|
-
checkoutLock:
|
|
11150
|
-
tasks:
|
|
11151
|
-
index:
|
|
11152
|
-
blobs:
|
|
11153
|
-
legacy:
|
|
11154
|
-
v2:
|
|
11180
|
+
workspace: path9.join(checkout, "workspace.json"),
|
|
11181
|
+
checkoutLock: path9.join(checkout, "metadata.lock"),
|
|
11182
|
+
tasks: path9.join(dir, "tasks"),
|
|
11183
|
+
index: path9.join(dir, "task-index.json"),
|
|
11184
|
+
blobs: path9.join(dir, "blobs", "candidates"),
|
|
11185
|
+
legacy: path9.join(dir, "legacy", checkoutSlug(this.root), "v2"),
|
|
11186
|
+
v2: path9.join(this.root, ".workit")
|
|
11155
11187
|
};
|
|
11156
11188
|
}
|
|
11157
11189
|
eventsPath(taskId) {
|
|
11158
|
-
return
|
|
11190
|
+
return path9.join(this.paths().tasks, taskId, "events.jsonl");
|
|
11159
11191
|
}
|
|
11160
11192
|
snapshotPath(taskId) {
|
|
11161
|
-
return
|
|
11193
|
+
return path9.join(this.paths().tasks, taskId, "snapshot.json");
|
|
11162
11194
|
}
|
|
11163
11195
|
taskLockPath(taskId) {
|
|
11164
|
-
return
|
|
11196
|
+
return path9.join(this.paths().tasks, taskId, "lock");
|
|
11165
11197
|
}
|
|
11166
11198
|
ready(write = false) {
|
|
11167
11199
|
const location = this.location();
|
|
@@ -11171,7 +11203,7 @@ class TaskStore {
|
|
|
11171
11203
|
return success(null, null, null);
|
|
11172
11204
|
const dirs = this.paths();
|
|
11173
11205
|
try {
|
|
11174
|
-
const marker = JSON.parse(
|
|
11206
|
+
const marker = JSON.parse(fs10.readFileSync(dirs.marker, "utf8"));
|
|
11175
11207
|
if (typeof marker.version === "number" && marker.version > STORE_FORMAT)
|
|
11176
11208
|
return failure2("recovery_required", `the workit store at ${dirs.dir} has format ${marker.version}; upgrade Workit to use it`, { path: dirs.marker });
|
|
11177
11209
|
} catch {}
|
|
@@ -11200,21 +11232,21 @@ class TaskStore {
|
|
|
11200
11232
|
return {
|
|
11201
11233
|
read: (digest) => {
|
|
11202
11234
|
try {
|
|
11203
|
-
return JSON.parse(
|
|
11235
|
+
return JSON.parse(fs10.readFileSync(path9.join(dir, `${digest}.json`), "utf8"));
|
|
11204
11236
|
} catch (error) {
|
|
11205
11237
|
throw new LogDamage(`stored candidate ${digest} is missing or unreadable: ${String(error)}`);
|
|
11206
11238
|
}
|
|
11207
11239
|
},
|
|
11208
11240
|
write: (digest, value) => {
|
|
11209
|
-
const file =
|
|
11210
|
-
if (
|
|
11241
|
+
const file = path9.join(dir, `${digest}.json`);
|
|
11242
|
+
if (fs10.existsSync(file)) {
|
|
11211
11243
|
const stamp = new Date;
|
|
11212
11244
|
try {
|
|
11213
|
-
|
|
11245
|
+
fs10.utimesSync(file, stamp, stamp);
|
|
11214
11246
|
return;
|
|
11215
11247
|
} catch {}
|
|
11216
11248
|
}
|
|
11217
|
-
|
|
11249
|
+
fs10.mkdirSync(dir, { recursive: true });
|
|
11218
11250
|
replaceFile(file, JSON.stringify(value), true);
|
|
11219
11251
|
}
|
|
11220
11252
|
};
|
|
@@ -11296,7 +11328,7 @@ class TaskStore {
|
|
|
11296
11328
|
}
|
|
11297
11329
|
readSnapshot(taskId) {
|
|
11298
11330
|
try {
|
|
11299
|
-
const value = JSON.parse(
|
|
11331
|
+
const value = JSON.parse(fs10.readFileSync(this.snapshotPath(taskId), "utf8"));
|
|
11300
11332
|
if (!isObject4(value) || value.v !== 1 || value.task !== taskId || typeof value.seq !== "number" || typeof value.lastId !== "string" || typeof value.lastStart !== "number" || typeof value.end !== "number" || !isObject4(value.record))
|
|
11301
11333
|
return null;
|
|
11302
11334
|
return value;
|
|
@@ -11398,8 +11430,8 @@ class TaskStore {
|
|
|
11398
11430
|
}
|
|
11399
11431
|
}
|
|
11400
11432
|
openTask(record, type, key, legacy = null) {
|
|
11401
|
-
const dir =
|
|
11402
|
-
|
|
11433
|
+
const dir = path9.join(this.paths().tasks, record.id);
|
|
11434
|
+
fs10.mkdirSync(dir, { recursive: true });
|
|
11403
11435
|
const blobs = this.blobStore();
|
|
11404
11436
|
const bound = key ? { ...key, boundAt: key.boundAt ?? new Date().toISOString() } : null;
|
|
11405
11437
|
const event = this.event(record.id, 1, type, {
|
|
@@ -11451,11 +11483,11 @@ class TaskStore {
|
|
|
11451
11483
|
} catch {}
|
|
11452
11484
|
if (!latest || latest.events[0]?.id !== last.id)
|
|
11453
11485
|
return failure2("busy", "the task log changed during compaction; retry", { taskId });
|
|
11454
|
-
const appended =
|
|
11486
|
+
const appended = fs10.readFileSync(file).subarray(log.end, latest.end);
|
|
11455
11487
|
const bytes = Buffer.concat([Buffer.from(prefix, "utf8"), appended]);
|
|
11456
11488
|
replaceFile(file, bytes.toString("utf8"), true);
|
|
11457
11489
|
try {
|
|
11458
|
-
|
|
11490
|
+
fs10.rmSync(this.snapshotPath(taskId), { force: true });
|
|
11459
11491
|
} catch {}
|
|
11460
11492
|
const reloaded = this.load(taskId);
|
|
11461
11493
|
if (reloaded.ok && reloaded.data)
|
|
@@ -11468,7 +11500,7 @@ class TaskStore {
|
|
|
11468
11500
|
}
|
|
11469
11501
|
countEvents(file) {
|
|
11470
11502
|
try {
|
|
11471
|
-
const bytes =
|
|
11503
|
+
const bytes = fs10.readFileSync(file);
|
|
11472
11504
|
let count = 0;
|
|
11473
11505
|
for (let index = bytes.indexOf(10);index >= 0; index = bytes.indexOf(10, index + 1))
|
|
11474
11506
|
count += 1;
|
|
@@ -11490,8 +11522,8 @@ class TaskStore {
|
|
|
11490
11522
|
return bound.ok ? success(null, null, bound.data[0] ?? null) : bound;
|
|
11491
11523
|
}
|
|
11492
11524
|
withKeyLock(key, operation) {
|
|
11493
|
-
const digest =
|
|
11494
|
-
return this.withLock(
|
|
11525
|
+
const digest = createHash6("sha256").update(key).digest("hex").slice(0, 32);
|
|
11526
|
+
return this.withLock(path9.join(this.paths().dir, "keys", `${digest}.lock`), operation);
|
|
11495
11527
|
}
|
|
11496
11528
|
bindLocked(taskId, key, timestamp) {
|
|
11497
11529
|
const current = this.readWorkspace();
|
|
@@ -11632,7 +11664,7 @@ class TaskStore {
|
|
|
11632
11664
|
writeWorkspace(record) {
|
|
11633
11665
|
const file = this.paths().workspace;
|
|
11634
11666
|
try {
|
|
11635
|
-
|
|
11667
|
+
fs10.mkdirSync(path9.dirname(file), { recursive: true });
|
|
11636
11668
|
replaceFile(file, `${canonicalJson(record)}
|
|
11637
11669
|
`, true);
|
|
11638
11670
|
return success(null, null, null);
|
|
@@ -11642,7 +11674,7 @@ class TaskStore {
|
|
|
11642
11674
|
}
|
|
11643
11675
|
readIndex() {
|
|
11644
11676
|
try {
|
|
11645
|
-
const value = JSON.parse(
|
|
11677
|
+
const value = JSON.parse(fs10.readFileSync(this.paths().index, "utf8"));
|
|
11646
11678
|
if (!isObject4(value) || value.version !== INDEX_VERSION || !isObject4(value.tasks))
|
|
11647
11679
|
return {};
|
|
11648
11680
|
const tasks = {};
|
|
@@ -11656,7 +11688,7 @@ class TaskStore {
|
|
|
11656
11688
|
}
|
|
11657
11689
|
writeIndex(entries) {
|
|
11658
11690
|
try {
|
|
11659
|
-
|
|
11691
|
+
fs10.mkdirSync(this.paths().tasks, { recursive: true });
|
|
11660
11692
|
replaceFile(this.paths().index, JSON.stringify({
|
|
11661
11693
|
version: INDEX_VERSION,
|
|
11662
11694
|
tasks: Object.fromEntries(entries.map((entry) => [entry.id, entry]))
|
|
@@ -11710,23 +11742,23 @@ class TaskStore {
|
|
|
11710
11742
|
return failure2("revision_conflict", "workspace revision does not match; omit expectedWorkspaceRevision to use the current record", { expectedWorkspaceRevision: expected, actualWorkspaceRevision: actual });
|
|
11711
11743
|
}
|
|
11712
11744
|
v2Dirs() {
|
|
11713
|
-
return [...new Set([this.root, this.origin])].map((dir) =>
|
|
11745
|
+
return [...new Set([this.root, this.origin])].map((dir) => path9.join(dir, ".workit"));
|
|
11714
11746
|
}
|
|
11715
11747
|
pendingMigrations() {
|
|
11716
11748
|
return this.v2Dirs().filter((dir) => {
|
|
11717
|
-
const raw = this.readV2Workspace(
|
|
11749
|
+
const raw = this.readV2Workspace(path9.join(dir, "workspace.json"));
|
|
11718
11750
|
return raw !== null && raw !== TOMBSTONE;
|
|
11719
11751
|
});
|
|
11720
11752
|
}
|
|
11721
11753
|
migrateV2(v2) {
|
|
11722
11754
|
const dirs = this.paths();
|
|
11723
|
-
const v2Workspace =
|
|
11724
|
-
const v2Tasks =
|
|
11725
|
-
const legacy =
|
|
11755
|
+
const v2Workspace = path9.join(v2, "workspace.json");
|
|
11756
|
+
const v2Tasks = path9.join(v2, "tasks");
|
|
11757
|
+
const legacy = path9.join(dirs.dir, "legacy", checkoutSlug(path9.dirname(v2)), "v2");
|
|
11726
11758
|
const raw = this.readV2Workspace(v2Workspace);
|
|
11727
11759
|
if (raw === null || raw === TOMBSTONE)
|
|
11728
11760
|
return success(null, null, null);
|
|
11729
|
-
return this.withLock(dirs.checkoutLock, () => this.withLock(
|
|
11761
|
+
return this.withLock(dirs.checkoutLock, () => this.withLock(path9.join(v2, "metadata.lock"), () => {
|
|
11730
11762
|
const workspace = this.readV2Workspace(v2Workspace);
|
|
11731
11763
|
if (workspace === null || workspace === TOMBSTONE)
|
|
11732
11764
|
return success(null, null, null);
|
|
@@ -11735,7 +11767,7 @@ class TaskStore {
|
|
|
11735
11767
|
return failure2("recovery_required", `cannot migrate the 2.x store at ${v2}: ${parsedWorkspace.error}; move it aside to start fresh`, { path: v2Workspace });
|
|
11736
11768
|
let files = [];
|
|
11737
11769
|
try {
|
|
11738
|
-
files =
|
|
11770
|
+
files = fs10.readdirSync(v2Tasks).filter((name) => name.endsWith(".json") && validId(name.slice(0, -5))).filter((name) => !this.isStub(path9.join(v2Tasks, name)));
|
|
11739
11771
|
} catch {}
|
|
11740
11772
|
const current = this.readWorkspace();
|
|
11741
11773
|
if (!current.ok)
|
|
@@ -11753,22 +11785,22 @@ class TaskStore {
|
|
|
11753
11785
|
let skipped = 0;
|
|
11754
11786
|
const done = new Map;
|
|
11755
11787
|
try {
|
|
11756
|
-
|
|
11788
|
+
fs10.mkdirSync(path9.join(legacy, "tasks"), { recursive: true });
|
|
11757
11789
|
for (const name of ["workspace.json", "index.json"])
|
|
11758
|
-
if (
|
|
11759
|
-
|
|
11790
|
+
if (fs10.existsSync(path9.join(v2, name)))
|
|
11791
|
+
fs10.copyFileSync(path9.join(v2, name), path9.join(legacy, name));
|
|
11760
11792
|
for (const name of files) {
|
|
11761
11793
|
const id = name.slice(0, -5);
|
|
11762
|
-
const file =
|
|
11763
|
-
const bytes =
|
|
11794
|
+
const file = path9.join(v2Tasks, name);
|
|
11795
|
+
const bytes = fs10.readFileSync(file, "utf8");
|
|
11764
11796
|
const digest = sha256(bytes);
|
|
11765
|
-
|
|
11797
|
+
fs10.writeFileSync(path9.join(legacy, "tasks", name), bytes);
|
|
11766
11798
|
const parsed = this.parseRecord(bytes, taskRecordSchema, "2.x task");
|
|
11767
11799
|
if (!parsed.ok || parsed.data.id !== id)
|
|
11768
11800
|
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 });
|
|
11769
11801
|
const record = { ...parsed.data, workspaceId: target.id };
|
|
11770
|
-
const origin = { path:
|
|
11771
|
-
if (!
|
|
11802
|
+
const origin = { path: path9.join(legacy, "tasks", name), digest };
|
|
11803
|
+
if (!fs10.existsSync(this.eventsPath(id))) {
|
|
11772
11804
|
this.openTask(record, "migrated.from_v2", null, origin);
|
|
11773
11805
|
migrated += 1;
|
|
11774
11806
|
} else {
|
|
@@ -11803,8 +11835,8 @@ class TaskStore {
|
|
|
11803
11835
|
try {
|
|
11804
11836
|
let complete = true;
|
|
11805
11837
|
for (const [name, digest] of done) {
|
|
11806
|
-
const file =
|
|
11807
|
-
if (sha256(
|
|
11838
|
+
const file = path9.join(v2Tasks, name);
|
|
11839
|
+
if (sha256(fs10.readFileSync(file, "utf8")) !== digest) {
|
|
11808
11840
|
complete = false;
|
|
11809
11841
|
continue;
|
|
11810
11842
|
}
|
|
@@ -11814,7 +11846,7 @@ class TaskStore {
|
|
|
11814
11846
|
return failure2("busy", `the 2.x store at ${v2} changed during migration; retry`, {
|
|
11815
11847
|
path: v2
|
|
11816
11848
|
});
|
|
11817
|
-
|
|
11849
|
+
fs10.rmSync(path9.join(v2, "index.json"), { force: true });
|
|
11818
11850
|
this.writeTombstone(v2, target.id);
|
|
11819
11851
|
} catch (error) {
|
|
11820
11852
|
return failure2("storage_error", `cannot finish the 2.x migration: ${String(error)}`, {
|
|
@@ -11834,45 +11866,45 @@ class TaskStore {
|
|
|
11834
11866
|
}
|
|
11835
11867
|
adoptLocalStore() {
|
|
11836
11868
|
const dirs = this.paths();
|
|
11837
|
-
const marker =
|
|
11838
|
-
if (!dirs.shared || !
|
|
11869
|
+
const marker = path9.join(dirs.v2, "store.json");
|
|
11870
|
+
if (!dirs.shared || !fs10.existsSync(marker))
|
|
11839
11871
|
return success(null, null, null);
|
|
11840
11872
|
return this.withLock(dirs.checkoutLock, () => {
|
|
11841
|
-
if (!
|
|
11873
|
+
if (!fs10.existsSync(marker))
|
|
11842
11874
|
return success(null, null, null);
|
|
11843
11875
|
let tasks = 0;
|
|
11844
11876
|
try {
|
|
11845
11877
|
const merge = (from, to) => {
|
|
11846
|
-
if (!
|
|
11847
|
-
|
|
11878
|
+
if (!fs10.existsSync(to)) {
|
|
11879
|
+
fs10.mkdirSync(path9.dirname(to), { recursive: true });
|
|
11848
11880
|
try {
|
|
11849
|
-
|
|
11881
|
+
fs10.renameSync(from, to);
|
|
11850
11882
|
} catch {
|
|
11851
|
-
|
|
11852
|
-
|
|
11883
|
+
fs10.cpSync(from, to, { recursive: true, errorOnExist: true, force: false });
|
|
11884
|
+
fs10.rmSync(from, { recursive: true, force: true });
|
|
11853
11885
|
}
|
|
11854
11886
|
return;
|
|
11855
11887
|
}
|
|
11856
|
-
if (
|
|
11857
|
-
for (const name of
|
|
11858
|
-
merge(
|
|
11888
|
+
if (fs10.lstatSync(from).isDirectory() && fs10.lstatSync(to).isDirectory())
|
|
11889
|
+
for (const name of fs10.readdirSync(from))
|
|
11890
|
+
merge(path9.join(from, name), path9.join(to, name));
|
|
11859
11891
|
};
|
|
11860
11892
|
for (const sub of ["tasks", "checkouts", "blobs", "legacy"]) {
|
|
11861
|
-
const from =
|
|
11862
|
-
if (!
|
|
11893
|
+
const from = path9.join(dirs.v2, sub);
|
|
11894
|
+
if (!fs10.existsSync(from))
|
|
11863
11895
|
continue;
|
|
11864
11896
|
if (sub === "tasks") {
|
|
11865
|
-
for (const name of
|
|
11866
|
-
if (validId(name) && !
|
|
11897
|
+
for (const name of fs10.readdirSync(from))
|
|
11898
|
+
if (validId(name) && !fs10.existsSync(path9.join(dirs.dir, sub, name)))
|
|
11867
11899
|
tasks += 1;
|
|
11868
11900
|
}
|
|
11869
|
-
merge(from,
|
|
11901
|
+
merge(from, path9.join(dirs.dir, sub));
|
|
11870
11902
|
}
|
|
11871
|
-
const ledger =
|
|
11872
|
-
if (
|
|
11873
|
-
merge(ledger,
|
|
11874
|
-
|
|
11875
|
-
|
|
11903
|
+
const ledger = path9.join(dirs.v2, "ledger");
|
|
11904
|
+
if (fs10.existsSync(ledger) && !fs10.existsSync(path9.join(dirs.dir, "ledger")))
|
|
11905
|
+
merge(ledger, path9.join(dirs.dir, "ledger"));
|
|
11906
|
+
fs10.rmSync(path9.join(dirs.v2, "task-index.json"), { force: true });
|
|
11907
|
+
fs10.renameSync(marker, path9.join(dirs.v2, "store.moved.json"));
|
|
11876
11908
|
} catch (error) {
|
|
11877
11909
|
return failure2("storage_error", `cannot move ${dirs.v2} into ${dirs.dir}: ${String(error)}`, {
|
|
11878
11910
|
path: dirs.v2
|
|
@@ -11892,7 +11924,7 @@ class TaskStore {
|
|
|
11892
11924
|
readV2Workspace(file) {
|
|
11893
11925
|
let bytes;
|
|
11894
11926
|
try {
|
|
11895
|
-
bytes =
|
|
11927
|
+
bytes = fs10.readFileSync(file, "utf8");
|
|
11896
11928
|
} catch {
|
|
11897
11929
|
return null;
|
|
11898
11930
|
}
|
|
@@ -11910,7 +11942,7 @@ class TaskStore {
|
|
|
11910
11942
|
schemaVersion: SCHEMA_VERSION,
|
|
11911
11943
|
id: workspaceId ?? newId(),
|
|
11912
11944
|
revision: newRevision(),
|
|
11913
|
-
root:
|
|
11945
|
+
root: path9.dirname(v2),
|
|
11914
11946
|
runtime: { createdWith: version, updatedWith: version },
|
|
11915
11947
|
writer: null,
|
|
11916
11948
|
store: {
|
|
@@ -11921,12 +11953,12 @@ class TaskStore {
|
|
|
11921
11953
|
},
|
|
11922
11954
|
critical: ["store"]
|
|
11923
11955
|
};
|
|
11924
|
-
|
|
11925
|
-
const ignore =
|
|
11926
|
-
if (!
|
|
11927
|
-
|
|
11956
|
+
fs10.mkdirSync(v2, { recursive: true });
|
|
11957
|
+
const ignore = path9.join(v2, ".gitignore");
|
|
11958
|
+
if (!fs10.existsSync(ignore))
|
|
11959
|
+
fs10.writeFileSync(ignore, `*
|
|
11928
11960
|
`);
|
|
11929
|
-
replaceFile(
|
|
11961
|
+
replaceFile(path9.join(v2, "workspace.json"), `${JSON.stringify(marker, null, 2)}
|
|
11930
11962
|
`, true);
|
|
11931
11963
|
}
|
|
11932
11964
|
stubFor(taskId) {
|
|
@@ -11942,7 +11974,7 @@ class TaskStore {
|
|
|
11942
11974
|
}
|
|
11943
11975
|
isStub(file) {
|
|
11944
11976
|
try {
|
|
11945
|
-
const value = JSON.parse(
|
|
11977
|
+
const value = JSON.parse(fs10.readFileSync(file, "utf8"));
|
|
11946
11978
|
return isObject4(value) && isObject4(value.store) && value.store.format === "workit-store";
|
|
11947
11979
|
} catch {
|
|
11948
11980
|
return false;
|
|
@@ -11950,32 +11982,32 @@ class TaskStore {
|
|
|
11950
11982
|
}
|
|
11951
11983
|
writeTombstoneIfMissing() {
|
|
11952
11984
|
try {
|
|
11953
|
-
const v2 =
|
|
11954
|
-
if (
|
|
11985
|
+
const v2 = path9.join(this.root, ".workit");
|
|
11986
|
+
if (fs10.existsSync(path9.join(v2, "workspace.json")))
|
|
11955
11987
|
return;
|
|
11956
11988
|
let id = null;
|
|
11957
11989
|
try {
|
|
11958
|
-
id = JSON.parse(
|
|
11990
|
+
id = JSON.parse(fs10.readFileSync(this.paths().workspace, "utf8")).id ?? null;
|
|
11959
11991
|
} catch {}
|
|
11960
11992
|
this.writeTombstone(v2, id);
|
|
11961
11993
|
} catch {}
|
|
11962
11994
|
}
|
|
11963
11995
|
initializeStorage() {
|
|
11964
11996
|
const dirs = this.paths();
|
|
11965
|
-
retryTransient(() =>
|
|
11966
|
-
retryTransient(() =>
|
|
11967
|
-
if (!
|
|
11997
|
+
retryTransient(() => fs10.mkdirSync(dirs.checkout, { recursive: true }));
|
|
11998
|
+
retryTransient(() => fs10.mkdirSync(dirs.tasks, { recursive: true }));
|
|
11999
|
+
if (!fs10.existsSync(dirs.marker))
|
|
11968
12000
|
replaceFile(dirs.marker, `${JSON.stringify({ format: "workit-store", version: STORE_FORMAT, createdWith: runtimeVersion() })}
|
|
11969
12001
|
`, false);
|
|
11970
12002
|
if (!dirs.shared) {
|
|
11971
|
-
const ignore =
|
|
12003
|
+
const ignore = path9.join(dirs.dir, ".gitignore");
|
|
11972
12004
|
let current = null;
|
|
11973
12005
|
try {
|
|
11974
|
-
current =
|
|
12006
|
+
current = fs10.readFileSync(ignore, "utf8");
|
|
11975
12007
|
} catch {}
|
|
11976
12008
|
if (current !== `*
|
|
11977
12009
|
`)
|
|
11978
|
-
retryTransient(() =>
|
|
12010
|
+
retryTransient(() => fs10.writeFileSync(ignore, `*
|
|
11979
12011
|
`));
|
|
11980
12012
|
}
|
|
11981
12013
|
this.writeTombstoneIfMissing();
|
|
@@ -11991,7 +12023,7 @@ class TaskStore {
|
|
|
11991
12023
|
shouldReclaim: ({ payload, nowMs }) => {
|
|
11992
12024
|
let ageMs = null;
|
|
11993
12025
|
try {
|
|
11994
|
-
ageMs = nowMs -
|
|
12026
|
+
ageMs = nowMs - fs10.lstatSync(lockPath).mtimeMs;
|
|
11995
12027
|
} catch {}
|
|
11996
12028
|
return classifyLockOwner(payload, ageMs, localLockHost(), TASK_STORE_LOCK).state === "stale";
|
|
11997
12029
|
},
|
|
@@ -12028,7 +12060,7 @@ class TaskStore {
|
|
|
12028
12060
|
withLock(lockPath, operation) {
|
|
12029
12061
|
try {
|
|
12030
12062
|
this.initializeStorage();
|
|
12031
|
-
|
|
12063
|
+
fs10.mkdirSync(path9.dirname(lockPath), { recursive: true });
|
|
12032
12064
|
} catch (error) {
|
|
12033
12065
|
return failure2("storage_error", `unable to initialize store: ${String(error)}`, {
|
|
12034
12066
|
path: this.paths().dir
|
|
@@ -12068,18 +12100,18 @@ class TaskStore {
|
|
|
12068
12100
|
lockDirWritable(lockPath) {
|
|
12069
12101
|
const probe = `${lockPath}.${process.pid}.${randomUUID3()}.probe`;
|
|
12070
12102
|
try {
|
|
12071
|
-
|
|
12103
|
+
fs10.closeSync(fs10.openSync(probe, "wx", 384));
|
|
12072
12104
|
} catch {
|
|
12073
12105
|
return false;
|
|
12074
12106
|
}
|
|
12075
12107
|
try {
|
|
12076
|
-
|
|
12108
|
+
fs10.rmSync(probe, { force: true });
|
|
12077
12109
|
} catch {}
|
|
12078
12110
|
return true;
|
|
12079
12111
|
}
|
|
12080
12112
|
lockHolderPresent(lockPath) {
|
|
12081
12113
|
try {
|
|
12082
|
-
|
|
12114
|
+
fs10.lstatSync(lockPath);
|
|
12083
12115
|
return true;
|
|
12084
12116
|
} catch (error) {
|
|
12085
12117
|
return error?.code !== "ENOENT";
|
|
@@ -12091,12 +12123,12 @@ class TaskStore {
|
|
|
12091
12123
|
if (isTransientWindowsError(error) && !this.lockHolderPresent(lockPath) && !this.lockDirWritable(lockPath))
|
|
12092
12124
|
return failure2("storage_error", `cannot create the workit lock (${code}); no other Workit call holds it`, {
|
|
12093
12125
|
path: lockPath,
|
|
12094
|
-
guidance: `Check permissions and the read-only attribute on ${
|
|
12126
|
+
guidance: `Check permissions and the read-only attribute on ${path9.dirname(lockPath)}.`
|
|
12095
12127
|
});
|
|
12096
12128
|
if (code === "EEXIST" || code === "file_lock_timeout" || code === "file_lock_stale" || isTransientWindowsError(error)) {
|
|
12097
12129
|
let lock = null;
|
|
12098
12130
|
try {
|
|
12099
|
-
lock = parseMetadataLockOrNull(
|
|
12131
|
+
lock = parseMetadataLockOrNull(fs10.readFileSync(lockPath, "utf8"));
|
|
12100
12132
|
} catch {}
|
|
12101
12133
|
return failure2("busy", `workit lock is held by another Workit call${lock ? ` (pid ${lock.pid} on ${lock.host})` : ""}; retry shortly`, {
|
|
12102
12134
|
outcome: "not_started",
|
|
@@ -12111,17 +12143,17 @@ class TaskStore {
|
|
|
12111
12143
|
|
|
12112
12144
|
// packages/workit-core/src/core/policy/derive.ts
|
|
12113
12145
|
import { existsSync as existsSync4 } from "node:fs";
|
|
12114
|
-
import
|
|
12146
|
+
import path14 from "node:path";
|
|
12115
12147
|
|
|
12116
12148
|
// packages/workit-core/src/ledger.ts
|
|
12117
12149
|
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
12118
|
-
import { createHash as
|
|
12119
|
-
import
|
|
12120
|
-
import
|
|
12150
|
+
import { createHash as createHash9, randomBytes as randomBytes2 } from "node:crypto";
|
|
12151
|
+
import fs12 from "node:fs";
|
|
12152
|
+
import path13 from "node:path";
|
|
12121
12153
|
|
|
12122
12154
|
// packages/workit-core/src/core/vcs-config.ts
|
|
12123
|
-
import
|
|
12124
|
-
import
|
|
12155
|
+
import fs11 from "node:fs";
|
|
12156
|
+
import path12 from "node:path";
|
|
12125
12157
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
12126
12158
|
|
|
12127
12159
|
// packages/workit-core/src/core/config.ts
|
|
@@ -12135,7 +12167,7 @@ import {
|
|
|
12135
12167
|
writeFileSync as writeFileSync2
|
|
12136
12168
|
} from "node:fs";
|
|
12137
12169
|
import os2 from "node:os";
|
|
12138
|
-
import
|
|
12170
|
+
import path10 from "node:path";
|
|
12139
12171
|
|
|
12140
12172
|
// packages/workit-core/src/core/boundary.ts
|
|
12141
12173
|
var EVENT = {
|
|
@@ -12179,7 +12211,7 @@ var mergePreset = (preset, input = {}, current = {
|
|
|
12179
12211
|
protected: preset === "custom" ? input.protectedNames ?? current.branchPolicy.protected : [...defs.protected]
|
|
12180
12212
|
};
|
|
12181
12213
|
};
|
|
12182
|
-
var resolveConfigDir = () => process.env.WORKFLOW_TOOLKIT_CONFIG ?? process.env.WORKFLOW_TOOLKIT_CONFIG_DIR ??
|
|
12214
|
+
var resolveConfigDir = () => process.env.WORKFLOW_TOOLKIT_CONFIG ?? process.env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path10.join(process.env.XDG_CONFIG_HOME || path10.join(os2.homedir(), ".config"), "workit");
|
|
12183
12215
|
var migratedDir = null;
|
|
12184
12216
|
var migrationFailed = false;
|
|
12185
12217
|
var ensureConfigDir = (dir = resolveConfigDir()) => {
|
|
@@ -12189,7 +12221,7 @@ var ensureConfigDir = (dir = resolveConfigDir()) => {
|
|
|
12189
12221
|
migratedDir = dir;
|
|
12190
12222
|
return dir;
|
|
12191
12223
|
}
|
|
12192
|
-
const legacy =
|
|
12224
|
+
const legacy = path10.join(process.env.XDG_CONFIG_HOME || path10.join(os2.homedir(), ".config"), "workflow-toolkit");
|
|
12193
12225
|
if (!existsSync3(legacy)) {
|
|
12194
12226
|
migratedDir = dir;
|
|
12195
12227
|
return dir;
|
|
@@ -12202,8 +12234,8 @@ var ensureConfigDir = (dir = resolveConfigDir()) => {
|
|
|
12202
12234
|
mkdirSync2(dir, { recursive: true });
|
|
12203
12235
|
diagnosticLogger?.info(EVENT.migration, { from: legacy, to: dir });
|
|
12204
12236
|
for (const entry of readdirSync2(legacy, { withFileTypes: true })) {
|
|
12205
|
-
const src =
|
|
12206
|
-
const dest =
|
|
12237
|
+
const src = path10.join(legacy, entry.name);
|
|
12238
|
+
const dest = path10.join(dir, entry.name);
|
|
12207
12239
|
if (existsSync3(dest))
|
|
12208
12240
|
continue;
|
|
12209
12241
|
try {
|
|
@@ -12275,7 +12307,7 @@ var parseConfigResult = (raw, file) => {
|
|
|
12275
12307
|
return { status: "valid", path: file, config };
|
|
12276
12308
|
};
|
|
12277
12309
|
var readConfigTyped = (dir) => {
|
|
12278
|
-
const file =
|
|
12310
|
+
const file = path10.join(dir ?? configDir(), "config.json");
|
|
12279
12311
|
return parseConfigResult(readSafe(file), file);
|
|
12280
12312
|
};
|
|
12281
12313
|
var readConfig = () => {
|
|
@@ -12284,7 +12316,7 @@ var readConfig = () => {
|
|
|
12284
12316
|
throw new Error(result.error);
|
|
12285
12317
|
return result.config ?? DEFAULTS;
|
|
12286
12318
|
};
|
|
12287
|
-
var vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ??
|
|
12319
|
+
var vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ?? path10.join(configDir(), "vcs.json");
|
|
12288
12320
|
var branchGlobPattern = (glob) => new RegExp(`^${glob.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")}$`, "i");
|
|
12289
12321
|
var resolveBranchPolicy = (config, workspace, repoPreset) => {
|
|
12290
12322
|
const wp = workspace?.branchPolicy ?? {};
|
|
@@ -12326,9 +12358,9 @@ var resolveCommitPolicy = (config, workspace) => {
|
|
|
12326
12358
|
|
|
12327
12359
|
// packages/workit-core/src/core/workspaces.ts
|
|
12328
12360
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
12329
|
-
import { createHash as
|
|
12361
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
12330
12362
|
import { readFileSync as readFileSync3, realpathSync as realpathSync2 } from "node:fs";
|
|
12331
|
-
import
|
|
12363
|
+
import path11 from "node:path";
|
|
12332
12364
|
|
|
12333
12365
|
// packages/workit-core/src/core/branch-policy.ts
|
|
12334
12366
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
@@ -12453,7 +12485,7 @@ var releaseTrackSchema = object({
|
|
|
12453
12485
|
context.addIssue({ code: "custom", path: [field], message: "entries must be unique" });
|
|
12454
12486
|
}
|
|
12455
12487
|
}
|
|
12456
|
-
if (track.versionSource?.kind === "package-json" && (
|
|
12488
|
+
if (track.versionSource?.kind === "package-json" && (path11.posix.isAbsolute(track.versionSource.path.replaceAll("\\", "/")) || /^[A-Za-z]:\//u.test(track.versionSource.path.replaceAll("\\", "/")) || track.versionSource.path.replaceAll("\\", "/").split("/").includes(".."))) {
|
|
12457
12489
|
context.addIssue({
|
|
12458
12490
|
code: "custom",
|
|
12459
12491
|
path: ["versionSource", "path"],
|
|
@@ -12513,7 +12545,7 @@ var workspacesFileSchema = object({ workspaces: array(workspaceConfigSchema).opt
|
|
|
12513
12545
|
names.add(workspace.name);
|
|
12514
12546
|
}
|
|
12515
12547
|
});
|
|
12516
|
-
var workspacesRevision = (contents) =>
|
|
12548
|
+
var workspacesRevision = (contents) => createHash7("sha256").update(contents ?? "<missing>").digest("hex");
|
|
12517
12549
|
var validateWorkspacesDocument = (parsed, file) => {
|
|
12518
12550
|
if (!isConfigObject(parsed)) {
|
|
12519
12551
|
return { status: "malformed", path: file, entries: [], error: `${file} is not a JSON object` };
|
|
@@ -12551,7 +12583,7 @@ var validateWorkspacesDocument = (parsed, file) => {
|
|
|
12551
12583
|
};
|
|
12552
12584
|
};
|
|
12553
12585
|
var readWorkspacesResult = (dir = configDir()) => {
|
|
12554
|
-
const file =
|
|
12586
|
+
const file = path11.join(dir, "workspaces.json");
|
|
12555
12587
|
let raw;
|
|
12556
12588
|
try {
|
|
12557
12589
|
raw = readFileSync3(file, "utf8");
|
|
@@ -12662,9 +12694,9 @@ var mainCheckoutOf = (cwd) => {
|
|
|
12662
12694
|
let main = null;
|
|
12663
12695
|
const dirs = git(["rev-parse", "--path-format=absolute", "--git-dir", "--git-common-dir"]);
|
|
12664
12696
|
const [gitDir, common] = (dirs ?? "").trim().split(/\r?\n/u);
|
|
12665
|
-
if (gitDir && common &&
|
|
12697
|
+
if (gitDir && common && path11.resolve(gitDir) !== path11.resolve(common)) {
|
|
12666
12698
|
const listed = /^worktree (.+)$/mu.exec(git(["worktree", "list", "--porcelain"]) ?? "")?.[1];
|
|
12667
|
-
main = listed?.trim() || (
|
|
12699
|
+
main = listed?.trim() || (path11.basename(common) === ".git" ? path11.dirname(common) : common);
|
|
12668
12700
|
}
|
|
12669
12701
|
mainCheckouts.set(cwd, main);
|
|
12670
12702
|
return main;
|
|
@@ -12755,7 +12787,7 @@ var runtimeWorkspaceIndexSchema = object({
|
|
|
12755
12787
|
workspaces: array(object({ name: nonBlank, glob: nonBlank }).passthrough()).optional()
|
|
12756
12788
|
}).passthrough();
|
|
12757
12789
|
var matchRuntimeWorkspace = (cwd) => {
|
|
12758
|
-
const file =
|
|
12790
|
+
const file = path11.join(configDir(), "workspaces.json");
|
|
12759
12791
|
let raw;
|
|
12760
12792
|
try {
|
|
12761
12793
|
raw = readFileSync3(file, "utf8");
|
|
@@ -12830,7 +12862,7 @@ function workspaceDefaultTarget(cwd, globalDefault) {
|
|
|
12830
12862
|
}
|
|
12831
12863
|
|
|
12832
12864
|
// packages/workit-core/src/core/release-tracks.ts
|
|
12833
|
-
import { createHash as
|
|
12865
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
12834
12866
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
12835
12867
|
class ReleaseTrackError extends Error {
|
|
12836
12868
|
}
|
|
@@ -13213,7 +13245,7 @@ function resolveTrackFor(cwd, options) {
|
|
|
13213
13245
|
]) ?? "",
|
|
13214
13246
|
git3(cwd, ["config", "--get", recordedBaseKey(branch)]) ?? ""
|
|
13215
13247
|
] : [];
|
|
13216
|
-
key =
|
|
13248
|
+
key = createHash8("sha256").update(JSON.stringify({ cwd, input, refs, head, own })).digest("hex");
|
|
13217
13249
|
const hit = memo2.get(key);
|
|
13218
13250
|
if (hit)
|
|
13219
13251
|
return hit;
|
|
@@ -13228,7 +13260,7 @@ function resolveTrackFor(cwd, options) {
|
|
|
13228
13260
|
}
|
|
13229
13261
|
|
|
13230
13262
|
// packages/workit-core/src/core/vcs-config.ts
|
|
13231
|
-
var workspacesPath = () =>
|
|
13263
|
+
var workspacesPath = () => path12.join(configDir(), "workspaces.json");
|
|
13232
13264
|
var vcsCwd = (cwd) => cwd ?? process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd();
|
|
13233
13265
|
var remoteProvider = (cwd) => {
|
|
13234
13266
|
const r = spawnSync8("git", ["remote", "get-url", "origin"], { cwd, encoding: "utf8" });
|
|
@@ -13245,7 +13277,7 @@ var readVcsConfig = () => {
|
|
|
13245
13277
|
const file = vcsConfigPath();
|
|
13246
13278
|
let raw;
|
|
13247
13279
|
try {
|
|
13248
|
-
raw =
|
|
13280
|
+
raw = fs11.readFileSync(file, "utf8");
|
|
13249
13281
|
} catch {
|
|
13250
13282
|
return { status: "missing", path: file, config: {} };
|
|
13251
13283
|
}
|
|
@@ -13330,7 +13362,7 @@ function vcsConfig(mode, cwd, options = {}) {
|
|
|
13330
13362
|
const prov = cfg[provider] ?? {};
|
|
13331
13363
|
const out = {
|
|
13332
13364
|
ok: true,
|
|
13333
|
-
configPath:
|
|
13365
|
+
configPath: path12.resolve(cfgPath),
|
|
13334
13366
|
provider,
|
|
13335
13367
|
defaultTargetBranch: workspaceDefault,
|
|
13336
13368
|
pr: cfg.pr ?? {},
|
|
@@ -13456,7 +13488,7 @@ function diffHash(cwd, base, head) {
|
|
|
13456
13488
|
], GIT_TIMEOUTS.worktree);
|
|
13457
13489
|
if (!diff.ok || !diff.stdout)
|
|
13458
13490
|
return null;
|
|
13459
|
-
const hash =
|
|
13491
|
+
const hash = createHash9("sha256");
|
|
13460
13492
|
for (const line of diff.stdout.split(`
|
|
13461
13493
|
`)) {
|
|
13462
13494
|
if (line.startsWith("index "))
|
|
@@ -13468,14 +13500,14 @@ function diffHash(cwd, base, head) {
|
|
|
13468
13500
|
return `sha256:${hash.digest("hex")}`;
|
|
13469
13501
|
}
|
|
13470
13502
|
function storeRoot(cwd) {
|
|
13471
|
-
const location = resolveStore(
|
|
13503
|
+
const location = resolveStore(path13.resolve(cwd));
|
|
13472
13504
|
if (location instanceof Error)
|
|
13473
13505
|
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");
|
|
13474
13506
|
return { ok: true, value: { root: location.dir, shared: location.shared } };
|
|
13475
13507
|
}
|
|
13476
13508
|
function ledgerPath(cwd) {
|
|
13477
13509
|
const root = storeRoot(cwd);
|
|
13478
|
-
return root.ok ? { ok: true, value:
|
|
13510
|
+
return root.ok ? { ok: true, value: path13.join(root.value.root, "ledger", "ledger.jsonl") } : root;
|
|
13479
13511
|
}
|
|
13480
13512
|
var newId2 = () => `${Date.now().toString(36)}-${randomBytes2(6).toString("hex")}`;
|
|
13481
13513
|
var NETWORK_FS_TYPES = new Set([
|
|
@@ -13495,7 +13527,7 @@ var onNetworkFs = (dir) => {
|
|
|
13495
13527
|
if (process.platform !== "linux")
|
|
13496
13528
|
return false;
|
|
13497
13529
|
try {
|
|
13498
|
-
return isNetworkFsType(
|
|
13530
|
+
return isNetworkFsType(fs12.statfsSync(dir).type);
|
|
13499
13531
|
} catch {
|
|
13500
13532
|
return false;
|
|
13501
13533
|
}
|
|
@@ -13505,15 +13537,15 @@ var LOCK_STALE_MS = 30000;
|
|
|
13505
13537
|
var LOCK_OWNER = "owner";
|
|
13506
13538
|
var lockToken = (lock) => {
|
|
13507
13539
|
try {
|
|
13508
|
-
return
|
|
13540
|
+
return fs12.readFileSync(path13.join(lock, LOCK_OWNER), "utf8");
|
|
13509
13541
|
} catch {
|
|
13510
13542
|
return null;
|
|
13511
13543
|
}
|
|
13512
13544
|
};
|
|
13513
13545
|
var lockAgeMs = (lock) => {
|
|
13514
|
-
for (const target of [
|
|
13546
|
+
for (const target of [path13.join(lock, LOCK_OWNER), lock]) {
|
|
13515
13547
|
try {
|
|
13516
|
-
return Date.now() -
|
|
13548
|
+
return Date.now() - fs12.statSync(target).mtimeMs;
|
|
13517
13549
|
} catch {}
|
|
13518
13550
|
}
|
|
13519
13551
|
return null;
|
|
@@ -13521,14 +13553,14 @@ var lockAgeMs = (lock) => {
|
|
|
13521
13553
|
var ledgerLock = {
|
|
13522
13554
|
acquire(lock) {
|
|
13523
13555
|
try {
|
|
13524
|
-
|
|
13556
|
+
fs12.mkdirSync(lock);
|
|
13525
13557
|
} catch (error) {
|
|
13526
13558
|
if (error.code === "EEXIST")
|
|
13527
13559
|
return null;
|
|
13528
13560
|
throw error;
|
|
13529
13561
|
}
|
|
13530
13562
|
const token = `${process.pid}-${randomBytes2(8).toString("hex")}`;
|
|
13531
|
-
|
|
13563
|
+
fs12.writeFileSync(path13.join(lock, LOCK_OWNER), token);
|
|
13532
13564
|
return token;
|
|
13533
13565
|
},
|
|
13534
13566
|
release(lock, token) {
|
|
@@ -13536,35 +13568,35 @@ var ledgerLock = {
|
|
|
13536
13568
|
return false;
|
|
13537
13569
|
const tomb = `${lock}.release-${randomBytes2(6).toString("hex")}`;
|
|
13538
13570
|
try {
|
|
13539
|
-
|
|
13571
|
+
fs12.renameSync(lock, tomb);
|
|
13540
13572
|
} catch {
|
|
13541
13573
|
return false;
|
|
13542
13574
|
}
|
|
13543
13575
|
if (lockToken(tomb) !== token) {
|
|
13544
13576
|
try {
|
|
13545
|
-
|
|
13577
|
+
fs12.renameSync(tomb, lock);
|
|
13546
13578
|
} catch {}
|
|
13547
13579
|
return false;
|
|
13548
13580
|
}
|
|
13549
|
-
|
|
13581
|
+
fs12.rmSync(tomb, { recursive: true, force: true });
|
|
13550
13582
|
return true;
|
|
13551
13583
|
},
|
|
13552
13584
|
token: lockToken,
|
|
13553
13585
|
reap(lock, observed) {
|
|
13554
13586
|
const tomb = `${lock}.reap-${randomBytes2(6).toString("hex")}`;
|
|
13555
13587
|
try {
|
|
13556
|
-
|
|
13588
|
+
fs12.renameSync(lock, tomb);
|
|
13557
13589
|
} catch {
|
|
13558
13590
|
return false;
|
|
13559
13591
|
}
|
|
13560
13592
|
if (lockToken(tomb) === observed) {
|
|
13561
|
-
|
|
13593
|
+
fs12.rmSync(tomb, { recursive: true, force: true });
|
|
13562
13594
|
return true;
|
|
13563
13595
|
}
|
|
13564
13596
|
try {
|
|
13565
|
-
|
|
13597
|
+
fs12.renameSync(tomb, lock);
|
|
13566
13598
|
} catch {
|
|
13567
|
-
|
|
13599
|
+
fs12.rmSync(tomb, { recursive: true, force: true });
|
|
13568
13600
|
}
|
|
13569
13601
|
return false;
|
|
13570
13602
|
}
|
|
@@ -13591,14 +13623,14 @@ function withLedgerLock(file, fn, waitMs = LOCK_WAIT_MS) {
|
|
|
13591
13623
|
ledgerLock.release(lock, token);
|
|
13592
13624
|
}
|
|
13593
13625
|
}
|
|
13594
|
-
var sha2562 = (text) =>
|
|
13626
|
+
var sha2562 = (text) => createHash9("sha256").update(text).digest("hex");
|
|
13595
13627
|
var chainHash = (prevHash, body) => sha2562(`${prevHash ?? ""}
|
|
13596
13628
|
${body}`);
|
|
13597
13629
|
var TAIL_BYTES = 64 * 1024;
|
|
13598
13630
|
var lastLine = (fd, size) => {
|
|
13599
13631
|
for (let span = Math.min(size, TAIL_BYTES);span > 0; span = Math.min(size, span * 2)) {
|
|
13600
13632
|
const buffer = Buffer.alloc(span);
|
|
13601
|
-
|
|
13633
|
+
fs12.readSync(fd, buffer, 0, span, size - span);
|
|
13602
13634
|
const end = buffer.lastIndexOf(10);
|
|
13603
13635
|
if (end < 0) {
|
|
13604
13636
|
if (span === size)
|
|
@@ -13629,13 +13661,13 @@ var lastLine = (fd, size) => {
|
|
|
13629
13661
|
};
|
|
13630
13662
|
function appendLine(file, build, options) {
|
|
13631
13663
|
const write = () => {
|
|
13632
|
-
const fd =
|
|
13664
|
+
const fd = fs12.openSync(file, "a+");
|
|
13633
13665
|
try {
|
|
13634
|
-
const size =
|
|
13666
|
+
const size = fs12.fstatSync(fd).size;
|
|
13635
13667
|
let fence = "";
|
|
13636
13668
|
if (size > 0) {
|
|
13637
13669
|
const last = Buffer.alloc(1);
|
|
13638
|
-
|
|
13670
|
+
fs12.readSync(fd, last, 0, 1, size - 1);
|
|
13639
13671
|
if (last[0] !== 10)
|
|
13640
13672
|
fence = `
|
|
13641
13673
|
`;
|
|
@@ -13644,17 +13676,17 @@ function appendLine(file, build, options) {
|
|
|
13644
13676
|
if (!line.ok)
|
|
13645
13677
|
return line;
|
|
13646
13678
|
const bytes = Buffer.from(fence + line.value);
|
|
13647
|
-
const written =
|
|
13679
|
+
const written = fs12.writeSync(fd, bytes);
|
|
13648
13680
|
if (written !== bytes.length)
|
|
13649
13681
|
return err("unavailable", `short write to ${file}: ${written} of ${bytes.length} bytes; the row is torn and will be skipped`);
|
|
13650
13682
|
return { ok: true, value: undefined };
|
|
13651
13683
|
} finally {
|
|
13652
|
-
|
|
13684
|
+
fs12.closeSync(fd);
|
|
13653
13685
|
}
|
|
13654
13686
|
};
|
|
13655
13687
|
try {
|
|
13656
|
-
|
|
13657
|
-
if (!options.forceLock && !onNetworkFs(
|
|
13688
|
+
fs12.mkdirSync(path13.dirname(file), { recursive: true });
|
|
13689
|
+
if (!options.forceLock && !onNetworkFs(path13.dirname(file)))
|
|
13658
13690
|
return write();
|
|
13659
13691
|
const locked = withLedgerLock(file, write);
|
|
13660
13692
|
return locked ?? err("busy", `ledger lock ${file}.lock is held`, "retry; remove the .lock directory if no workit process is running");
|
|
@@ -13726,7 +13758,7 @@ function readLedger(cwd, options = {}) {
|
|
|
13726
13758
|
return file;
|
|
13727
13759
|
let text = "";
|
|
13728
13760
|
try {
|
|
13729
|
-
text =
|
|
13761
|
+
text = fs12.readFileSync(file.value, "utf8");
|
|
13730
13762
|
} catch (error) {
|
|
13731
13763
|
if (error.code === "ENOENT")
|
|
13732
13764
|
return {
|
|
@@ -13920,11 +13952,20 @@ function authorSessions(cwd, rows, branch, range = { base: null, head: null }, s
|
|
|
13920
13952
|
sessions.add(session);
|
|
13921
13953
|
return sessions;
|
|
13922
13954
|
}
|
|
13955
|
+
var derivesFrom = (derived, bare) => !bare.includes(":") && derived.endsWith(`:${bare}`);
|
|
13956
|
+
var authoredBy = (authors, session) => {
|
|
13957
|
+
if (authors.has(session))
|
|
13958
|
+
return true;
|
|
13959
|
+
for (const author of authors)
|
|
13960
|
+
if (derivesFrom(author, session) || derivesFrom(session, author))
|
|
13961
|
+
return true;
|
|
13962
|
+
return false;
|
|
13963
|
+
};
|
|
13923
13964
|
var independenceReasons = (row, authors) => {
|
|
13924
13965
|
const reasons = [];
|
|
13925
13966
|
if (!row.actor.session)
|
|
13926
13967
|
reasons.push("no_session");
|
|
13927
|
-
else if (authors
|
|
13968
|
+
else if (authoredBy(authors, row.actor.session))
|
|
13928
13969
|
reasons.push("author_session");
|
|
13929
13970
|
if (row.self === true && !reasons.includes("no_session"))
|
|
13930
13971
|
reasons.push("self");
|
|
@@ -14208,7 +14249,7 @@ var productDecision = (task, ledger) => {
|
|
|
14208
14249
|
};
|
|
14209
14250
|
};
|
|
14210
14251
|
var planRecorded = (task, root) => {
|
|
14211
|
-
const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync4(
|
|
14252
|
+
const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync4(path14.resolve(root, ref.path)));
|
|
14212
14253
|
if (cited)
|
|
14213
14254
|
return {
|
|
14214
14255
|
met: true,
|
|
@@ -14267,15 +14308,15 @@ function writeBlockers(task, root) {
|
|
|
14267
14308
|
}
|
|
14268
14309
|
|
|
14269
14310
|
// packages/workit-core/src/core/task-evaluation.ts
|
|
14270
|
-
var digestBytes = (value) =>
|
|
14271
|
-
var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${
|
|
14272
|
-
var relative = (root, candidate) =>
|
|
14311
|
+
var digestBytes = (value) => createHash10("sha256").update(value).digest("hex");
|
|
14312
|
+
var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path15.sep}`);
|
|
14313
|
+
var relative = (root, candidate) => path15.relative(root, candidate).split(path15.sep).join("/") || ".";
|
|
14273
14314
|
var canonicalPath = (value) => {
|
|
14274
14315
|
if (typeof value !== "string" || !value)
|
|
14275
14316
|
return null;
|
|
14276
14317
|
if (value.includes("\\") || value.split("/").includes(".."))
|
|
14277
14318
|
return null;
|
|
14278
|
-
const normalized =
|
|
14319
|
+
const normalized = path15.posix.normalize(value);
|
|
14279
14320
|
if (normalized === ".." || normalized.startsWith("../") || normalized.startsWith("/"))
|
|
14280
14321
|
return null;
|
|
14281
14322
|
return normalized === "." ? "." : normalized.replace(/\/$/, "");
|
|
@@ -14323,21 +14364,21 @@ var gitPaths = (root) => {
|
|
|
14323
14364
|
git: !/not a git repository/i.test(stderr)
|
|
14324
14365
|
};
|
|
14325
14366
|
}
|
|
14326
|
-
const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(
|
|
14367
|
+
const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path15.sep).join("/")) : [];
|
|
14327
14368
|
const stagedDeleted = spawnSync10("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
|
|
14328
14369
|
if (stagedDeleted.status !== 0) {
|
|
14329
14370
|
const stderr = stagedDeleted.stderr?.toString("utf8") ?? "";
|
|
14330
14371
|
if (!/not a git repository/i.test(stderr))
|
|
14331
14372
|
return { paths, uncertain: true, git: true };
|
|
14332
14373
|
} else if (stagedDeleted.stdout) {
|
|
14333
|
-
paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(
|
|
14374
|
+
paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path15.sep).join("/")));
|
|
14334
14375
|
}
|
|
14335
14376
|
return { paths: [...new Set(paths)], uncertain: false, git: true };
|
|
14336
14377
|
};
|
|
14337
14378
|
var walk = (root, directory, output) => {
|
|
14338
14379
|
let names;
|
|
14339
14380
|
try {
|
|
14340
|
-
names =
|
|
14381
|
+
names = fs13.readdirSync(directory);
|
|
14341
14382
|
} catch {
|
|
14342
14383
|
return true;
|
|
14343
14384
|
}
|
|
@@ -14345,10 +14386,10 @@ var walk = (root, directory, output) => {
|
|
|
14345
14386
|
for (const name of names) {
|
|
14346
14387
|
if (name === ".git" || name === ".workit")
|
|
14347
14388
|
continue;
|
|
14348
|
-
const target =
|
|
14389
|
+
const target = path15.join(directory, name);
|
|
14349
14390
|
let stat;
|
|
14350
14391
|
try {
|
|
14351
|
-
stat =
|
|
14392
|
+
stat = fs13.lstatSync(target);
|
|
14352
14393
|
} catch {
|
|
14353
14394
|
uncertain = true;
|
|
14354
14395
|
continue;
|
|
@@ -14363,14 +14404,14 @@ var walk = (root, directory, output) => {
|
|
|
14363
14404
|
var scopeRoots = (root, scope) => {
|
|
14364
14405
|
const roots = [];
|
|
14365
14406
|
for (const item of scope.paths.length ? scope.paths : ["."]) {
|
|
14366
|
-
const target =
|
|
14407
|
+
const target = path15.resolve(root, item);
|
|
14367
14408
|
if (!inside(root, target))
|
|
14368
14409
|
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` }] });
|
|
14369
14410
|
let ancestor = target;
|
|
14370
|
-
while (!
|
|
14371
|
-
ancestor =
|
|
14411
|
+
while (!fs13.existsSync(ancestor) && ancestor !== root)
|
|
14412
|
+
ancestor = path15.dirname(ancestor);
|
|
14372
14413
|
try {
|
|
14373
|
-
if (!inside(root,
|
|
14414
|
+
if (!inside(root, fs13.realpathSync(ancestor)))
|
|
14374
14415
|
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` }] });
|
|
14375
14416
|
} catch {
|
|
14376
14417
|
return failure2("invalid_input", `candidate scope cannot be inspected: ${item}`);
|
|
@@ -14382,7 +14423,7 @@ var scopeRoots = (root, scope) => {
|
|
|
14382
14423
|
function captureCandidate(root, scope, environment = []) {
|
|
14383
14424
|
let checkout;
|
|
14384
14425
|
try {
|
|
14385
|
-
checkout =
|
|
14426
|
+
checkout = fs13.realpathSync(root);
|
|
14386
14427
|
} catch {
|
|
14387
14428
|
return failure2("invalid_input", "candidate root does not exist");
|
|
14388
14429
|
}
|
|
@@ -14400,11 +14441,11 @@ function captureCandidate(root, scope, environment = []) {
|
|
|
14400
14441
|
if (item === ".git" || item === ".workit")
|
|
14401
14442
|
continue;
|
|
14402
14443
|
names.add(item);
|
|
14403
|
-
if (!
|
|
14444
|
+
if (!fs13.existsSync(target))
|
|
14404
14445
|
continue;
|
|
14405
14446
|
let stat;
|
|
14406
14447
|
try {
|
|
14407
|
-
stat =
|
|
14448
|
+
stat = fs13.lstatSync(target);
|
|
14408
14449
|
} catch {
|
|
14409
14450
|
uncertain = true;
|
|
14410
14451
|
continue;
|
|
@@ -14420,17 +14461,17 @@ function captureCandidate(root, scope, environment = []) {
|
|
|
14420
14461
|
for (const item of [...names].toSorted()) {
|
|
14421
14462
|
if (!scopeMatches(item, normalizedScope))
|
|
14422
14463
|
continue;
|
|
14423
|
-
const target =
|
|
14464
|
+
const target = path15.join(checkout, item);
|
|
14424
14465
|
try {
|
|
14425
|
-
const stat =
|
|
14466
|
+
const stat = fs13.lstatSync(target);
|
|
14426
14467
|
if (stat.isSymbolicLink()) {
|
|
14427
|
-
const link =
|
|
14468
|
+
const link = fs13.readlinkSync(target);
|
|
14428
14469
|
files.push({ path: item, kind: "symlink", digest: digestBytes(link), executable: null });
|
|
14429
14470
|
} else if (stat.isFile()) {
|
|
14430
14471
|
files.push({
|
|
14431
14472
|
path: item,
|
|
14432
14473
|
kind: "file",
|
|
14433
|
-
digest: digestBytes(
|
|
14474
|
+
digest: digestBytes(fs13.readFileSync(target)),
|
|
14434
14475
|
executable: (stat.mode & 73) !== 0
|
|
14435
14476
|
});
|
|
14436
14477
|
} else if (!stat.isDirectory()) {
|
|
@@ -14595,7 +14636,7 @@ var findingVerificationPasses = (findingCandidateId, evidence) => evidence.statu
|
|
|
14595
14636
|
var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
14596
14637
|
let root;
|
|
14597
14638
|
try {
|
|
14598
|
-
root =
|
|
14639
|
+
root = fs13.realpathSync(checkoutRoot);
|
|
14599
14640
|
} catch {
|
|
14600
14641
|
return failure2("permission_denied", "checkout root is unavailable");
|
|
14601
14642
|
}
|
|
@@ -14604,23 +14645,23 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
|
14604
14645
|
continue;
|
|
14605
14646
|
if (!reference.digest)
|
|
14606
14647
|
return failure2("invalid_input", "document references require a byte digest");
|
|
14607
|
-
const target =
|
|
14608
|
-
if (target !== root && !target.startsWith(`${root}${
|
|
14648
|
+
const target = path15.resolve(root, reference.path);
|
|
14649
|
+
if (target !== root && !target.startsWith(`${root}${path15.sep}`))
|
|
14609
14650
|
return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
|
|
14610
14651
|
fields: [
|
|
14611
14652
|
{ path: "contentRefs.path", reason: `${reference.path} is outside the checkout` }
|
|
14612
14653
|
]
|
|
14613
14654
|
});
|
|
14614
14655
|
try {
|
|
14615
|
-
const below =
|
|
14656
|
+
const below = path15.relative(root, target);
|
|
14616
14657
|
let current = root;
|
|
14617
|
-
for (const segment of below.split(
|
|
14658
|
+
for (const segment of below.split(path15.sep)) {
|
|
14618
14659
|
if (!segment)
|
|
14619
14660
|
continue;
|
|
14620
|
-
current =
|
|
14621
|
-
const stat =
|
|
14622
|
-
const real =
|
|
14623
|
-
if (real !== root && !real.startsWith(`${root}${
|
|
14661
|
+
current = path15.join(current, segment);
|
|
14662
|
+
const stat = fs13.lstatSync(current);
|
|
14663
|
+
const real = fs13.realpathSync(current);
|
|
14664
|
+
if (real !== root && !real.startsWith(`${root}${path15.sep}`))
|
|
14624
14665
|
return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
|
|
14625
14666
|
fields: [
|
|
14626
14667
|
{
|
|
@@ -14636,7 +14677,7 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
|
14636
14677
|
if (current !== target && !stat.isDirectory())
|
|
14637
14678
|
return failure2("invalid_input", "document reference ancestor is not a directory");
|
|
14638
14679
|
}
|
|
14639
|
-
if (digestBytes(
|
|
14680
|
+
if (digestBytes(fs13.readFileSync(target)) !== reference.digest)
|
|
14640
14681
|
return failure2("permission_denied", "decision document bytes have changed");
|
|
14641
14682
|
} catch {
|
|
14642
14683
|
return failure2("invalid_input", "decision document is unavailable");
|
|
@@ -15493,7 +15534,7 @@ var judgeInputSummary = (raw) => {
|
|
|
15493
15534
|
|
|
15494
15535
|
// packages/workit-core/src/autonomy.ts
|
|
15495
15536
|
import os3 from "node:os";
|
|
15496
|
-
import
|
|
15537
|
+
import path16 from "node:path";
|
|
15497
15538
|
var accountHome = () => {
|
|
15498
15539
|
try {
|
|
15499
15540
|
return os3.userInfo().homedir;
|
|
@@ -15502,10 +15543,10 @@ var accountHome = () => {
|
|
|
15502
15543
|
}
|
|
15503
15544
|
};
|
|
15504
15545
|
var grantsHome = { resolve: accountHome };
|
|
15505
|
-
var grantsDir = () =>
|
|
15546
|
+
var grantsDir = () => path16.join(grantsHome.resolve(), ".config", "workit");
|
|
15506
15547
|
var grantsOverride = () => {
|
|
15507
|
-
const configured =
|
|
15508
|
-
return configured ===
|
|
15548
|
+
const configured = path16.resolve(resolveConfigDir());
|
|
15549
|
+
return configured === path16.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 ${path16.join(grantsDir(), "workspaces.json")}, so the D4 defaults apply`;
|
|
15509
15550
|
};
|
|
15510
15551
|
var GRANT_KINDS = ["push", "pr", "merge", "release", "rerun"];
|
|
15511
15552
|
var DEFAULT_GRANTS = Object.freeze({
|
|
@@ -17487,7 +17528,7 @@ function entryCompactContext(store, entry, session, context) {
|
|
|
17487
17528
|
return null;
|
|
17488
17529
|
const freshness = { mode: "signal", current: () => recentSignal(store.root) };
|
|
17489
17530
|
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" ? [
|
|
17531
|
+
const files = (task?.data.decisions ?? []).flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [path17.resolve(store.root, ref.path)] : []));
|
|
17491
17532
|
const observedFiles = filesKey(files);
|
|
17492
17533
|
const compact = new WorkitCore(store, context).compactContext(entry?.id ?? null, freshness, origin && { origin: origin.origin, taskId: origin.entry.id });
|
|
17493
17534
|
if (!compact.ok || !compact.data)
|
|
@@ -17556,7 +17597,7 @@ var turnContextText = (input, descriptor) => {
|
|
|
17556
17597
|
}
|
|
17557
17598
|
};
|
|
17558
17599
|
var TURN_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
17559
|
-
var digestOf = (text) =>
|
|
17600
|
+
var digestOf = (text) => createHash11("sha256").update(text).digest("hex");
|
|
17560
17601
|
var turnMarker = (input) => {
|
|
17561
17602
|
if (!input.session.id)
|
|
17562
17603
|
return null;
|
|
@@ -17565,32 +17606,32 @@ var turnMarker = (input) => {
|
|
|
17565
17606
|
if (location instanceof Error)
|
|
17566
17607
|
return null;
|
|
17567
17608
|
const session = [input.host, input.session.id, input.session.agentId ?? ""].join("\x00");
|
|
17568
|
-
return
|
|
17609
|
+
return path17.join(location.dir, "hooks", `turn-${digestOf(session).slice(0, 32)}.json`);
|
|
17569
17610
|
} catch {
|
|
17570
17611
|
return null;
|
|
17571
17612
|
}
|
|
17572
17613
|
};
|
|
17573
17614
|
var writeTurnDigest = (file, digest) => {
|
|
17574
17615
|
try {
|
|
17575
|
-
|
|
17576
|
-
|
|
17616
|
+
fs14.mkdirSync(path17.dirname(file), { recursive: true });
|
|
17617
|
+
fs14.writeFileSync(file, `${JSON.stringify({ digest })}
|
|
17577
17618
|
`);
|
|
17578
17619
|
} catch {}
|
|
17579
17620
|
};
|
|
17580
17621
|
var clearTurnDigest = (file) => {
|
|
17581
17622
|
try {
|
|
17582
|
-
|
|
17623
|
+
fs14.rmSync(file, { force: true });
|
|
17583
17624
|
} catch {}
|
|
17584
17625
|
};
|
|
17585
17626
|
var pruneTurnDigests = (dir, now) => {
|
|
17586
17627
|
try {
|
|
17587
|
-
for (const name of
|
|
17628
|
+
for (const name of fs14.readdirSync(dir)) {
|
|
17588
17629
|
if (!name.startsWith("turn-"))
|
|
17589
17630
|
continue;
|
|
17590
|
-
const file =
|
|
17631
|
+
const file = path17.join(dir, name);
|
|
17591
17632
|
try {
|
|
17592
|
-
if (now -
|
|
17593
|
-
|
|
17633
|
+
if (now - fs14.statSync(file).mtimeMs > TURN_TTL_MS)
|
|
17634
|
+
fs14.rmSync(file, { force: true });
|
|
17594
17635
|
} catch {}
|
|
17595
17636
|
}
|
|
17596
17637
|
} catch {}
|
|
@@ -17606,7 +17647,7 @@ var changedTurnContext = (input, text) => {
|
|
|
17606
17647
|
return text;
|
|
17607
17648
|
const digest = digestOf(text);
|
|
17608
17649
|
try {
|
|
17609
|
-
const previous = JSON.parse(
|
|
17650
|
+
const previous = JSON.parse(fs14.readFileSync(file, "utf8"));
|
|
17610
17651
|
if (previous.digest === digest)
|
|
17611
17652
|
return null;
|
|
17612
17653
|
} catch {}
|
|
@@ -17617,14 +17658,14 @@ var seedTurnContext = (input, descriptor, text = turnContextText(input, descript
|
|
|
17617
17658
|
const file = turnMarker(input);
|
|
17618
17659
|
if (!file)
|
|
17619
17660
|
return;
|
|
17620
|
-
pruneTurnDigests(
|
|
17661
|
+
pruneTurnDigests(path17.dirname(file), Date.now());
|
|
17621
17662
|
if (text)
|
|
17622
17663
|
writeTurnDigest(file, digestOf(text));
|
|
17623
17664
|
else
|
|
17624
17665
|
clearTurnDigest(file);
|
|
17625
17666
|
};
|
|
17626
17667
|
// packages/workit-core/src/core/branch.ts
|
|
17627
|
-
import { createHash as
|
|
17668
|
+
import { createHash as createHash12 } from "node:crypto";
|
|
17628
17669
|
var withReleaseTracks = (workspaceRoot, policy) => {
|
|
17629
17670
|
const read = workspaceReleaseTracks(workspaceRoot);
|
|
17630
17671
|
if (read.error)
|
|
@@ -17692,7 +17733,7 @@ var branchPolicySnapshotFor = (workspaceRoot) => {
|
|
|
17692
17733
|
const source = resolved.provenance.branchPolicy;
|
|
17693
17734
|
const allowed = branchPolicy.allowed.map((pattern) => `${pattern.source}/${pattern.flags}`).toSorted();
|
|
17694
17735
|
const protectedRefs = [...branchPolicy.protected].map((name) => name.toLowerCase()).toSorted();
|
|
17695
|
-
const fingerprint =
|
|
17736
|
+
const fingerprint = createHash12("sha256").update(JSON.stringify({ allowed, protectedRefs, source })).digest("hex");
|
|
17696
17737
|
return {
|
|
17697
17738
|
branchPolicy,
|
|
17698
17739
|
namePolicy: { allowed: branchPolicy.allowed, protected: branchPolicy.protected },
|
|
@@ -17741,7 +17782,7 @@ var shellPolicy = (cwd, command) => {
|
|
|
17741
17782
|
};
|
|
17742
17783
|
// packages/workit-core/src/hooks/write-gate.ts
|
|
17743
17784
|
import { realpathSync as realpathSync5 } from "node:fs";
|
|
17744
|
-
import
|
|
17785
|
+
import path18 from "node:path";
|
|
17745
17786
|
|
|
17746
17787
|
// packages/workit-core/src/hooks/shell-words.ts
|
|
17747
17788
|
var closingQuote = (command, start, dialect) => {
|
|
@@ -17871,22 +17912,22 @@ var NONE2 = { kind: "none" };
|
|
|
17871
17912
|
var CASE_INSENSITIVE = process.platform === "darwin" || process.platform === "win32";
|
|
17872
17913
|
var canonical2 = (file) => {
|
|
17873
17914
|
let rest = "";
|
|
17874
|
-
for (let dir =
|
|
17915
|
+
for (let dir = path18.resolve(file);; dir = path18.dirname(dir)) {
|
|
17875
17916
|
try {
|
|
17876
|
-
return
|
|
17917
|
+
return path18.join(realpathSync5(dir), rest);
|
|
17877
17918
|
} catch {
|
|
17878
|
-
if (
|
|
17879
|
-
return
|
|
17880
|
-
rest = rest ?
|
|
17919
|
+
if (path18.dirname(dir) === dir)
|
|
17920
|
+
return path18.resolve(file);
|
|
17921
|
+
rest = rest ? path18.join(path18.basename(dir), rest) : path18.basename(dir);
|
|
17881
17922
|
}
|
|
17882
17923
|
}
|
|
17883
17924
|
};
|
|
17884
17925
|
var exempt = (cwd, root, file, plans) => {
|
|
17885
17926
|
const fold = (value) => CASE_INSENSITIVE ? value.toLowerCase() : value;
|
|
17886
|
-
const relative =
|
|
17887
|
-
if (relative.startsWith("..") ||
|
|
17927
|
+
const relative = path18.relative(fold(canonical2(root)), fold(canonical2(path18.resolve(cwd, file))));
|
|
17928
|
+
if (relative.startsWith("..") || path18.isAbsolute(relative))
|
|
17888
17929
|
return true;
|
|
17889
|
-
const posix = relative.split(
|
|
17930
|
+
const posix = relative.split(path18.sep).join("/");
|
|
17890
17931
|
const segments = posix.split("/");
|
|
17891
17932
|
return /\.mdx?$/i.test(posix) || segments[0] === "docs" || segments.includes("plans") || [...plans].some((plan) => fold(plan) === posix);
|
|
17892
17933
|
};
|
|
@@ -17984,7 +18025,7 @@ var shellWrites = (command) => {
|
|
|
17984
18025
|
return { writes: true, targets: unknown ? null : targets };
|
|
17985
18026
|
};
|
|
17986
18027
|
var cache2 = new Map;
|
|
17987
|
-
var planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(
|
|
18028
|
+
var planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(path18.resolve(root, file)) ?? "-").join("\x00");
|
|
17988
18029
|
var gateFor = (cwd) => {
|
|
17989
18030
|
const store = new TaskStore(cwd);
|
|
17990
18031
|
const listed = store.listTaskIndex();
|
|
@@ -18044,15 +18085,15 @@ import { spawnSync as spawnSync12 } from "node:child_process";
|
|
|
18044
18085
|
|
|
18045
18086
|
// packages/workit-core/src/hooks/raw-git.ts
|
|
18046
18087
|
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
18047
|
-
import { createHash as
|
|
18048
|
-
import
|
|
18088
|
+
import { createHash as createHash14 } from "node:crypto";
|
|
18089
|
+
import fs16 from "node:fs";
|
|
18049
18090
|
import os4 from "node:os";
|
|
18050
|
-
import
|
|
18091
|
+
import path20 from "node:path";
|
|
18051
18092
|
|
|
18052
18093
|
// packages/workit-core/src/hooks/session-marker.ts
|
|
18053
|
-
import { createHash as
|
|
18054
|
-
import
|
|
18055
|
-
import
|
|
18094
|
+
import { createHash as createHash13 } from "node:crypto";
|
|
18095
|
+
import fs15 from "node:fs";
|
|
18096
|
+
import path19 from "node:path";
|
|
18056
18097
|
var sessionMarkerFile = (input, session, store) => {
|
|
18057
18098
|
let dir = store;
|
|
18058
18099
|
if (dir === undefined) {
|
|
@@ -18061,13 +18102,13 @@ var sessionMarkerFile = (input, session, store) => {
|
|
|
18061
18102
|
return null;
|
|
18062
18103
|
dir = location.dir;
|
|
18063
18104
|
}
|
|
18064
|
-
const name =
|
|
18065
|
-
return
|
|
18105
|
+
const name = createHash13("sha256").update(`${input.host}\x00${session}`).digest("hex").slice(0, 32);
|
|
18106
|
+
return path19.join(dir, "hooks", `skills-${name}.json`);
|
|
18066
18107
|
};
|
|
18067
18108
|
var list2 = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
18068
18109
|
var readSessionMarker = (file) => {
|
|
18069
18110
|
try {
|
|
18070
|
-
const value = JSON.parse(
|
|
18111
|
+
const value = JSON.parse(fs15.readFileSync(file, "utf8"));
|
|
18071
18112
|
return { nudged: list2(value.nudged), loaded: list2(value.loaded), raw: list2(value.raw) };
|
|
18072
18113
|
} catch {
|
|
18073
18114
|
return { nudged: [], loaded: [], raw: [] };
|
|
@@ -18075,8 +18116,8 @@ var readSessionMarker = (file) => {
|
|
|
18075
18116
|
};
|
|
18076
18117
|
var writeSessionMarker = (file, marker) => {
|
|
18077
18118
|
try {
|
|
18078
|
-
|
|
18079
|
-
|
|
18119
|
+
fs15.mkdirSync(path19.dirname(file), { recursive: true });
|
|
18120
|
+
fs15.writeFileSync(file, JSON.stringify(marker));
|
|
18080
18121
|
} catch {}
|
|
18081
18122
|
};
|
|
18082
18123
|
|
|
@@ -18097,12 +18138,12 @@ var GIT_VALUE_OPTIONS = new Set([
|
|
|
18097
18138
|
"--config-env",
|
|
18098
18139
|
"--super-prefix"
|
|
18099
18140
|
]);
|
|
18100
|
-
var isAbsolute = (value) =>
|
|
18141
|
+
var isAbsolute = (value) => path20.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\");
|
|
18101
18142
|
var joinDir = (base, next) => {
|
|
18102
18143
|
if (base === undefined || /[$`*?]/.test(next) || next === "-")
|
|
18103
18144
|
return;
|
|
18104
|
-
const expanded = next === "~" || next.startsWith("~/") ?
|
|
18105
|
-
return base === null || isAbsolute(expanded) ? expanded :
|
|
18145
|
+
const expanded = next === "~" || next.startsWith("~/") ? path20.join(os4.homedir(), next.slice(1)) : next;
|
|
18146
|
+
return base === null || isAbsolute(expanded) ? expanded : path20.join(base, expanded);
|
|
18106
18147
|
};
|
|
18107
18148
|
var cdTarget = (words) => {
|
|
18108
18149
|
const args = words.slice(1);
|
|
@@ -18355,7 +18396,7 @@ var repoAt = (dir) => {
|
|
|
18355
18396
|
return { location, dir, branch: resolveTaskKey(dir, location).branch };
|
|
18356
18397
|
};
|
|
18357
18398
|
var isWorkitWorkspace = (repo) => {
|
|
18358
|
-
if (
|
|
18399
|
+
if (fs16.existsSync(repo.location.dir))
|
|
18359
18400
|
return true;
|
|
18360
18401
|
try {
|
|
18361
18402
|
return resolveRuntimeWorkspaceVcs(repo.location.top ?? repo.dir) !== null;
|
|
@@ -18386,17 +18427,17 @@ var headSha2 = (repo) => {
|
|
|
18386
18427
|
if (!git || git.reftable)
|
|
18387
18428
|
return null;
|
|
18388
18429
|
try {
|
|
18389
|
-
const head =
|
|
18430
|
+
const head = fs16.readFileSync(path20.join(git.gitDir, "HEAD"), "utf8").trim();
|
|
18390
18431
|
if (/^[0-9a-f]{40,64}$/.test(head))
|
|
18391
18432
|
return head;
|
|
18392
18433
|
const ref = /^ref: (refs\/.+)$/.exec(head)?.[1];
|
|
18393
18434
|
if (!ref)
|
|
18394
18435
|
return null;
|
|
18395
|
-
const common =
|
|
18436
|
+
const common = path20.dirname(repo.location.dir);
|
|
18396
18437
|
try {
|
|
18397
|
-
return
|
|
18438
|
+
return fs16.readFileSync(path20.join(common, ref), "utf8").trim() || null;
|
|
18398
18439
|
} catch {}
|
|
18399
|
-
const packed =
|
|
18440
|
+
const packed = fs16.readFileSync(path20.join(common, "packed-refs"), "utf8");
|
|
18400
18441
|
return new RegExp(`^([0-9a-f]{40,64}) ${ref.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`, "m").exec(packed)?.[1] ?? null;
|
|
18401
18442
|
} catch {
|
|
18402
18443
|
return null;
|
|
@@ -18433,7 +18474,7 @@ var actionsIn = (cwd, command, dialect) => {
|
|
|
18433
18474
|
const action = rawAction(invocation);
|
|
18434
18475
|
if (!action)
|
|
18435
18476
|
continue;
|
|
18436
|
-
const dir =
|
|
18477
|
+
const dir = path20.resolve(cwd, invocation.dir ?? ".");
|
|
18437
18478
|
if (!repos.has(dir)) {
|
|
18438
18479
|
const repo = repoAt(dir);
|
|
18439
18480
|
repos.set(dir, repo && isWorkitWorkspace(repo) ? repo : null);
|
|
@@ -18502,8 +18543,8 @@ function rawGitPre(input, command, options = {}) {
|
|
|
18502
18543
|
var deny = (reason) => ({ kind: "deny", reason, unblock: null });
|
|
18503
18544
|
var NEXT_COMMAND = "next";
|
|
18504
18545
|
var MARKER_TTL_SECONDS = 3600;
|
|
18505
|
-
var markerFile = (repo, session, key) =>
|
|
18506
|
-
var callKey = (toolUseId, command) => toolUseId ?? `cmd:${
|
|
18546
|
+
var markerFile = (repo, session, key) => path20.join(repo.location.dir, "hooks", `commit-${createHash14("sha256").update(`${session}\x00${key}`).digest("hex").slice(0, 32)}.json`);
|
|
18547
|
+
var callKey = (toolUseId, command) => toolUseId ?? `cmd:${createHash14("sha256").update(command).digest("hex")}`;
|
|
18507
18548
|
function noteRawCommit(input, command, key) {
|
|
18508
18549
|
try {
|
|
18509
18550
|
if (!input.session.id || !/\bcommit\b/.test(command))
|
|
@@ -18513,8 +18554,8 @@ function noteRawCommit(input, command, key) {
|
|
|
18513
18554
|
if (action.kind !== "commit")
|
|
18514
18555
|
continue;
|
|
18515
18556
|
const file = markerFile(repo, input.session.id, key);
|
|
18516
|
-
|
|
18517
|
-
|
|
18557
|
+
fs16.mkdirSync(path20.dirname(file), { recursive: true });
|
|
18558
|
+
fs16.writeFileSync(file, `${JSON.stringify({ head: headSha2(repo), at })}
|
|
18518
18559
|
`);
|
|
18519
18560
|
}
|
|
18520
18561
|
} catch {}
|
|
@@ -18537,11 +18578,11 @@ var headCommit = (dir) => {
|
|
|
18537
18578
|
var settle2 = (input, repo, file) => {
|
|
18538
18579
|
let marker;
|
|
18539
18580
|
try {
|
|
18540
|
-
marker = JSON.parse(
|
|
18581
|
+
marker = JSON.parse(fs16.readFileSync(file, "utf8"));
|
|
18541
18582
|
} catch {
|
|
18542
18583
|
return;
|
|
18543
18584
|
}
|
|
18544
|
-
|
|
18585
|
+
fs16.rmSync(file, { force: true });
|
|
18545
18586
|
const session = input.session.id;
|
|
18546
18587
|
const now = Date.now() / 1000;
|
|
18547
18588
|
if (typeof marker.at !== "number" || now - marker.at > MARKER_TTL_SECONDS)
|
|
@@ -18590,7 +18631,7 @@ function settlePendingCommit(input) {
|
|
|
18590
18631
|
if (!repo)
|
|
18591
18632
|
return;
|
|
18592
18633
|
const file = markerFile(repo, input.session.id, NEXT_COMMAND);
|
|
18593
|
-
if (
|
|
18634
|
+
if (fs16.existsSync(file))
|
|
18594
18635
|
settle2(input, repo, file);
|
|
18595
18636
|
} catch {}
|
|
18596
18637
|
}
|
|
@@ -18980,12 +19021,12 @@ ${line}` };
|
|
|
18980
19021
|
};
|
|
18981
19022
|
// packages/workit-core/src/hooks/hosts/fields.ts
|
|
18982
19023
|
import { existsSync as existsSync6, realpathSync as realpathSync6, statSync as statSync2 } from "node:fs";
|
|
18983
|
-
import
|
|
19024
|
+
import path21 from "node:path";
|
|
18984
19025
|
var isRecord4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
18985
19026
|
var nonEmpty2 = (value) => typeof value === "string" && value.trim() !== "";
|
|
18986
19027
|
var optionalText = (value) => typeof value === "string" ? value : null;
|
|
18987
19028
|
var existingDirectory = (value) => {
|
|
18988
|
-
if (!nonEmpty2(value) || !
|
|
19029
|
+
if (!nonEmpty2(value) || !path21.isAbsolute(value) || !existsSync6(value))
|
|
18989
19030
|
return null;
|
|
18990
19031
|
try {
|
|
18991
19032
|
return statSync2(value).isDirectory() ? realpathSync6(value) : null;
|
|
@@ -19085,6 +19126,8 @@ ${subagentStartText({ ...input, cwd: "" }, descriptor, event)}`;
|
|
|
19085
19126
|
if (role !== "judge" || !event.agentId)
|
|
19086
19127
|
return readOnly;
|
|
19087
19128
|
const own = subagentSession(session, event.agentId);
|
|
19129
|
+
if (session)
|
|
19130
|
+
recordIssuedSession(input.cwd || process.cwd(), session, own);
|
|
19088
19131
|
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
19132
|
};
|
|
19090
19133
|
function handleHook(input, deps) {
|
|
@@ -19716,12 +19759,12 @@ var codexAdapter = {
|
|
|
19716
19759
|
};
|
|
19717
19760
|
},
|
|
19718
19761
|
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
|
|
19762
|
+
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
19763
|
};
|
|
19721
19764
|
|
|
19722
19765
|
// packages/workit-core/src/hooks/hosts/cursor.ts
|
|
19723
|
-
import
|
|
19724
|
-
import
|
|
19766
|
+
import fs17 from "node:fs";
|
|
19767
|
+
import path22 from "node:path";
|
|
19725
19768
|
var undocumented = { support: "undocumented", native: null };
|
|
19726
19769
|
var none = { support: "none", native: null };
|
|
19727
19770
|
var CURSOR_DESCRIPTOR = {
|
|
@@ -19918,17 +19961,17 @@ var protocolEvent2 = (input) => {
|
|
|
19918
19961
|
};
|
|
19919
19962
|
var TRANSCRIPT_TAIL_BYTES = 256 * 1024;
|
|
19920
19963
|
var lastAssistantText = (file) => {
|
|
19921
|
-
if (!file || !
|
|
19964
|
+
if (!file || !path22.isAbsolute(file))
|
|
19922
19965
|
return null;
|
|
19923
19966
|
try {
|
|
19924
|
-
const size =
|
|
19967
|
+
const size = fs17.statSync(file).size;
|
|
19925
19968
|
const start = Math.max(0, size - TRANSCRIPT_TAIL_BYTES);
|
|
19926
19969
|
const buffer = Buffer.alloc(size - start);
|
|
19927
|
-
const fd =
|
|
19970
|
+
const fd = fs17.openSync(file, "r");
|
|
19928
19971
|
try {
|
|
19929
|
-
|
|
19972
|
+
fs17.readSync(fd, buffer, 0, buffer.length, start);
|
|
19930
19973
|
} finally {
|
|
19931
|
-
|
|
19974
|
+
fs17.closeSync(fd);
|
|
19932
19975
|
}
|
|
19933
19976
|
const lines = buffer.toString("utf8").split(`
|
|
19934
19977
|
`);
|
|
@@ -19955,7 +19998,7 @@ var lastAssistantText = (file) => {
|
|
|
19955
19998
|
return null;
|
|
19956
19999
|
}
|
|
19957
20000
|
};
|
|
19958
|
-
var within = (root, dir) => dir === root || dir.startsWith(root.endsWith(
|
|
20001
|
+
var within = (root, dir) => dir === root || dir.startsWith(root.endsWith(path22.sep) ? root : `${root}${path22.sep}`);
|
|
19959
20002
|
var hookCwd = (input) => {
|
|
19960
20003
|
const cwd = existingDirectory(input.cwd);
|
|
19961
20004
|
if (cwd && input.hook_event_name === "beforeShellExecution")
|