@brainervirus/workit-cursor 8.9.1 → 8.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor-plugin/plugin.json +1 -1
- package/dist/cursor-session-start.js +424 -386
- package/dist/mcp-server.js +85 -77
- package/dist/workit-hook.js +430 -385
- package/package.json +3 -3
- package/rules/workit-contract.mdc +4 -1
- package/skills/workit-fanout/references/brief.md +1 -1
- package/skills/workit-fanout/references/orchestration.md +16 -6
- package/skills/workit-implement/SKILL.md +3 -2
- package/skills/workit-review/SKILL.md +4 -2
|
@@ -9832,37 +9832,6 @@ var init_vcs_config = __esm(() => {
|
|
|
9832
9832
|
init_release_tracks();
|
|
9833
9833
|
});
|
|
9834
9834
|
|
|
9835
|
-
// packages/workit-core/src/host-session.ts
|
|
9836
|
-
function hostSessionFromEnv(env) {
|
|
9837
|
-
const value = (key) => env[key]?.trim() || null;
|
|
9838
|
-
let inner = null;
|
|
9839
|
-
for (const [key, host] of HOST_SESSION_VARS) {
|
|
9840
|
-
const session = value(key);
|
|
9841
|
-
if (session) {
|
|
9842
|
-
inner = { host: host(env), session };
|
|
9843
|
-
break;
|
|
9844
|
-
}
|
|
9845
|
-
}
|
|
9846
|
-
const declared = value("WORKIT_HOST");
|
|
9847
|
-
if (env.WORKIT_SESSION_ID !== undefined) {
|
|
9848
|
-
const inherited = inner !== null && declared !== null && family(declared) !== family(inner.host);
|
|
9849
|
-
if (!inherited)
|
|
9850
|
-
return { host: declared, session: value("WORKIT_SESSION_ID") };
|
|
9851
|
-
}
|
|
9852
|
-
return inner ? { host: inner.host, session: inner.session } : { host: declared, session: null };
|
|
9853
|
-
}
|
|
9854
|
-
var HOST_SESSION_VARS, family = (host) => host?.replace(/_(?:cli|desktop)$/, "") ?? null;
|
|
9855
|
-
var init_host_session = __esm(() => {
|
|
9856
|
-
HOST_SESSION_VARS = [
|
|
9857
|
-
["OPENCODE_SESSION_ID", () => "opencode"],
|
|
9858
|
-
["PI_SESSION_ID", () => "pi"],
|
|
9859
|
-
[
|
|
9860
|
-
"CODEX_THREAD_ID",
|
|
9861
|
-
(env) => env.CODEX_INTERNAL_ORIGINATOR_OVERRIDE === "Codex Desktop" || env.CODEX_ELECTRON_RESOURCES_PATH ? "codex_desktop" : "codex_cli"
|
|
9862
|
-
]
|
|
9863
|
-
];
|
|
9864
|
-
});
|
|
9865
|
-
|
|
9866
9835
|
// packages/workit-core/src/store/paths.ts
|
|
9867
9836
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
9868
9837
|
import { createHash as createHash5 } from "node:crypto";
|
|
@@ -10139,11 +10108,69 @@ var init_paths = __esm(() => {
|
|
|
10139
10108
|
];
|
|
10140
10109
|
});
|
|
10141
10110
|
|
|
10142
|
-
// packages/workit-core/src/
|
|
10143
|
-
import {
|
|
10144
|
-
import { createHash as createHash6, randomBytes } from "node:crypto";
|
|
10111
|
+
// packages/workit-core/src/host-session.ts
|
|
10112
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
10145
10113
|
import fs4 from "node:fs";
|
|
10146
10114
|
import path6 from "node:path";
|
|
10115
|
+
function hostSessionFromEnv(env) {
|
|
10116
|
+
const value = (key) => env[key]?.trim() || null;
|
|
10117
|
+
let inner = null;
|
|
10118
|
+
for (const [key, host] of HOST_SESSION_VARS) {
|
|
10119
|
+
const session = value(key);
|
|
10120
|
+
if (session) {
|
|
10121
|
+
inner = { host: host(env), session };
|
|
10122
|
+
break;
|
|
10123
|
+
}
|
|
10124
|
+
}
|
|
10125
|
+
const declared = value("WORKIT_HOST");
|
|
10126
|
+
if (env.WORKIT_SESSION_ID !== undefined) {
|
|
10127
|
+
const inherited = inner !== null && declared !== null && family(declared) !== family(inner.host);
|
|
10128
|
+
if (!inherited)
|
|
10129
|
+
return { host: declared, session: value("WORKIT_SESSION_ID") };
|
|
10130
|
+
}
|
|
10131
|
+
return inner ? { host: inner.host, session: inner.session } : { host: declared, session: null };
|
|
10132
|
+
}
|
|
10133
|
+
function recordIssuedSession(cwd, lead, issued) {
|
|
10134
|
+
try {
|
|
10135
|
+
const dir = issuedDir(cwd, lead);
|
|
10136
|
+
if (!dir)
|
|
10137
|
+
return;
|
|
10138
|
+
fs4.mkdirSync(dir, { recursive: true });
|
|
10139
|
+
const own = hash(issued);
|
|
10140
|
+
fs4.writeFileSync(path6.join(dir, own), ISSUED_SESSIONS_MARKER);
|
|
10141
|
+
const entries = fs4.readdirSync(dir);
|
|
10142
|
+
if (entries.length <= ISSUED_PER_LEAD)
|
|
10143
|
+
return;
|
|
10144
|
+
const byAge = entries.filter((name) => name !== own).map((name) => ({ name, at: fs4.statSync(path6.join(dir, name)).mtimeMs })).toSorted((a, b) => a.at - b.at);
|
|
10145
|
+
for (const { name } of byAge.slice(0, entries.length - ISSUED_PER_LEAD))
|
|
10146
|
+
fs4.rmSync(path6.join(dir, name), { force: true });
|
|
10147
|
+
} catch {}
|
|
10148
|
+
}
|
|
10149
|
+
var HOST_SESSION_VARS, family = (host) => host?.replace(/_(?:cli|desktop)$/, "") ?? null, ISSUED_PER_LEAD = 64, ISSUED_SESSIONS_MARKER = "workit-issued-sessions/1", hash = (value) => createHash6("sha256").update(value).digest("hex").slice(0, 32), issuedRoot = (cwd) => {
|
|
10150
|
+
const location = resolveStore(cwd);
|
|
10151
|
+
return location instanceof Error ? null : path6.join(location.dir, "hooks", "issued");
|
|
10152
|
+
}, issuedDir = (cwd, lead) => {
|
|
10153
|
+
const root = issuedRoot(cwd);
|
|
10154
|
+
return root === null ? null : path6.join(root, hash(lead));
|
|
10155
|
+
}, OWN_CHILD_SHELL;
|
|
10156
|
+
var init_host_session = __esm(() => {
|
|
10157
|
+
init_paths();
|
|
10158
|
+
HOST_SESSION_VARS = [
|
|
10159
|
+
["OPENCODE_SESSION_ID", () => "opencode"],
|
|
10160
|
+
["PI_SESSION_ID", () => "pi"],
|
|
10161
|
+
[
|
|
10162
|
+
"CODEX_THREAD_ID",
|
|
10163
|
+
(env) => env.CODEX_INTERNAL_ORIGINATOR_OVERRIDE === "Codex Desktop" || env.CODEX_ELECTRON_RESOURCES_PATH ? "codex_desktop" : "codex_cli"
|
|
10164
|
+
]
|
|
10165
|
+
];
|
|
10166
|
+
OWN_CHILD_SHELL = new Set(["opencode", "pi"]);
|
|
10167
|
+
});
|
|
10168
|
+
|
|
10169
|
+
// packages/workit-core/src/ledger.ts
|
|
10170
|
+
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
10171
|
+
import { createHash as createHash7, randomBytes } from "node:crypto";
|
|
10172
|
+
import fs5 from "node:fs";
|
|
10173
|
+
import path7 from "node:path";
|
|
10147
10174
|
function resolveCommit(cwd, ref) {
|
|
10148
10175
|
if (!safeRef(ref))
|
|
10149
10176
|
return null;
|
|
@@ -10197,7 +10224,7 @@ function diffHash(cwd, base, head) {
|
|
|
10197
10224
|
], GIT_TIMEOUTS.worktree);
|
|
10198
10225
|
if (!diff.ok || !diff.stdout)
|
|
10199
10226
|
return null;
|
|
10200
|
-
const hash =
|
|
10227
|
+
const hash = createHash7("sha256");
|
|
10201
10228
|
for (const line of diff.stdout.split(`
|
|
10202
10229
|
`)) {
|
|
10203
10230
|
if (line.startsWith("index "))
|
|
@@ -10209,14 +10236,14 @@ function diffHash(cwd, base, head) {
|
|
|
10209
10236
|
return `sha256:${hash.digest("hex")}`;
|
|
10210
10237
|
}
|
|
10211
10238
|
function storeRoot(cwd) {
|
|
10212
|
-
const location = resolveStore(
|
|
10239
|
+
const location = resolveStore(path7.resolve(cwd));
|
|
10213
10240
|
if (location instanceof Error)
|
|
10214
10241
|
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");
|
|
10215
10242
|
return { ok: true, value: { root: location.dir, shared: location.shared } };
|
|
10216
10243
|
}
|
|
10217
10244
|
function ledgerPath(cwd) {
|
|
10218
10245
|
const root = storeRoot(cwd);
|
|
10219
|
-
return root.ok ? { ok: true, value:
|
|
10246
|
+
return root.ok ? { ok: true, value: path7.join(root.value.root, "ledger", "ledger.jsonl") } : root;
|
|
10220
10247
|
}
|
|
10221
10248
|
function withLedgerLock(file, fn, waitMs = LOCK_WAIT_MS) {
|
|
10222
10249
|
const lock = `${file}.lock`;
|
|
@@ -10242,13 +10269,13 @@ function withLedgerLock(file, fn, waitMs = LOCK_WAIT_MS) {
|
|
|
10242
10269
|
}
|
|
10243
10270
|
function appendLine(file, build, options) {
|
|
10244
10271
|
const write = () => {
|
|
10245
|
-
const fd =
|
|
10272
|
+
const fd = fs5.openSync(file, "a+");
|
|
10246
10273
|
try {
|
|
10247
|
-
const size =
|
|
10274
|
+
const size = fs5.fstatSync(fd).size;
|
|
10248
10275
|
let fence = "";
|
|
10249
10276
|
if (size > 0) {
|
|
10250
10277
|
const last = Buffer.alloc(1);
|
|
10251
|
-
|
|
10278
|
+
fs5.readSync(fd, last, 0, 1, size - 1);
|
|
10252
10279
|
if (last[0] !== 10)
|
|
10253
10280
|
fence = `
|
|
10254
10281
|
`;
|
|
@@ -10257,17 +10284,17 @@ function appendLine(file, build, options) {
|
|
|
10257
10284
|
if (!line.ok)
|
|
10258
10285
|
return line;
|
|
10259
10286
|
const bytes = Buffer.from(fence + line.value);
|
|
10260
|
-
const written =
|
|
10287
|
+
const written = fs5.writeSync(fd, bytes);
|
|
10261
10288
|
if (written !== bytes.length)
|
|
10262
10289
|
return err("unavailable", `short write to ${file}: ${written} of ${bytes.length} bytes; the row is torn and will be skipped`);
|
|
10263
10290
|
return { ok: true, value: undefined };
|
|
10264
10291
|
} finally {
|
|
10265
|
-
|
|
10292
|
+
fs5.closeSync(fd);
|
|
10266
10293
|
}
|
|
10267
10294
|
};
|
|
10268
10295
|
try {
|
|
10269
|
-
|
|
10270
|
-
if (!options.forceLock && !onNetworkFs(
|
|
10296
|
+
fs5.mkdirSync(path7.dirname(file), { recursive: true });
|
|
10297
|
+
if (!options.forceLock && !onNetworkFs(path7.dirname(file)))
|
|
10271
10298
|
return write();
|
|
10272
10299
|
const locked = withLedgerLock(file, write);
|
|
10273
10300
|
return locked ?? err("busy", `ledger lock ${file}.lock is held`, "retry; remove the .lock directory if no workit process is running");
|
|
@@ -10321,7 +10348,7 @@ function readLedger(cwd, options = {}) {
|
|
|
10321
10348
|
return file;
|
|
10322
10349
|
let text = "";
|
|
10323
10350
|
try {
|
|
10324
|
-
text =
|
|
10351
|
+
text = fs5.readFileSync(file.value, "utf8");
|
|
10325
10352
|
} catch (error) {
|
|
10326
10353
|
if (error.code === "ENOENT")
|
|
10327
10354
|
return {
|
|
@@ -10676,28 +10703,28 @@ var LEDGER_VERSION = 1, MAX_LINE_BYTES = 4096, PASSING, FAILING, STRONG_RESULTS,
|
|
|
10676
10703
|
if (process.platform !== "linux")
|
|
10677
10704
|
return false;
|
|
10678
10705
|
try {
|
|
10679
|
-
return isNetworkFsType(
|
|
10706
|
+
return isNetworkFsType(fs5.statfsSync(dir).type);
|
|
10680
10707
|
} catch {
|
|
10681
10708
|
return false;
|
|
10682
10709
|
}
|
|
10683
10710
|
}, LOCK_WAIT_MS = 5000, LOCK_STALE_MS = 30000, LOCK_OWNER = "owner", lockToken = (lock) => {
|
|
10684
10711
|
try {
|
|
10685
|
-
return
|
|
10712
|
+
return fs5.readFileSync(path7.join(lock, LOCK_OWNER), "utf8");
|
|
10686
10713
|
} catch {
|
|
10687
10714
|
return null;
|
|
10688
10715
|
}
|
|
10689
10716
|
}, lockAgeMs = (lock) => {
|
|
10690
|
-
for (const target of [
|
|
10717
|
+
for (const target of [path7.join(lock, LOCK_OWNER), lock]) {
|
|
10691
10718
|
try {
|
|
10692
|
-
return Date.now() -
|
|
10719
|
+
return Date.now() - fs5.statSync(target).mtimeMs;
|
|
10693
10720
|
} catch {}
|
|
10694
10721
|
}
|
|
10695
10722
|
return null;
|
|
10696
|
-
}, ledgerLock, sha2562 = (text) =>
|
|
10723
|
+
}, ledgerLock, sha2562 = (text) => createHash7("sha256").update(text).digest("hex"), chainHash = (prevHash, body) => sha2562(`${prevHash ?? ""}
|
|
10697
10724
|
${body}`), TAIL_BYTES, lastLine = (fd, size) => {
|
|
10698
10725
|
for (let span = Math.min(size, TAIL_BYTES);span > 0; span = Math.min(size, span * 2)) {
|
|
10699
10726
|
const buffer = Buffer.alloc(span);
|
|
10700
|
-
|
|
10727
|
+
fs5.readSync(fd, buffer, 0, span, size - span);
|
|
10701
10728
|
const end = buffer.lastIndexOf(10);
|
|
10702
10729
|
if (end < 0) {
|
|
10703
10730
|
if (span === size)
|
|
@@ -10749,11 +10776,18 @@ ${body}`), TAIL_BYTES, lastLine = (fd, size) => {
|
|
|
10749
10776
|
return false;
|
|
10750
10777
|
return scopeOf(own)({ branch: theirs, at: target.at });
|
|
10751
10778
|
};
|
|
10779
|
+
}, derivesFrom = (derived, bare) => !bare.includes(":") && derived.endsWith(`:${bare}`), authoredBy = (authors, session) => {
|
|
10780
|
+
if (authors.has(session))
|
|
10781
|
+
return true;
|
|
10782
|
+
for (const author of authors)
|
|
10783
|
+
if (derivesFrom(author, session) || derivesFrom(session, author))
|
|
10784
|
+
return true;
|
|
10785
|
+
return false;
|
|
10752
10786
|
}, independenceReasons = (row, authors) => {
|
|
10753
10787
|
const reasons = [];
|
|
10754
10788
|
if (!row.actor.session)
|
|
10755
10789
|
reasons.push("no_session");
|
|
10756
|
-
else if (authors
|
|
10790
|
+
else if (authoredBy(authors, row.actor.session))
|
|
10757
10791
|
reasons.push("author_session");
|
|
10758
10792
|
if (row.self === true && !reasons.includes("no_session"))
|
|
10759
10793
|
reasons.push("self");
|
|
@@ -10783,14 +10817,14 @@ var init_ledger = __esm(() => {
|
|
|
10783
10817
|
ledgerLock = {
|
|
10784
10818
|
acquire(lock) {
|
|
10785
10819
|
try {
|
|
10786
|
-
|
|
10820
|
+
fs5.mkdirSync(lock);
|
|
10787
10821
|
} catch (error) {
|
|
10788
10822
|
if (error.code === "EEXIST")
|
|
10789
10823
|
return null;
|
|
10790
10824
|
throw error;
|
|
10791
10825
|
}
|
|
10792
10826
|
const token = `${process.pid}-${randomBytes(8).toString("hex")}`;
|
|
10793
|
-
|
|
10827
|
+
fs5.writeFileSync(path7.join(lock, LOCK_OWNER), token);
|
|
10794
10828
|
return token;
|
|
10795
10829
|
},
|
|
10796
10830
|
release(lock, token) {
|
|
@@ -10798,35 +10832,35 @@ var init_ledger = __esm(() => {
|
|
|
10798
10832
|
return false;
|
|
10799
10833
|
const tomb = `${lock}.release-${randomBytes(6).toString("hex")}`;
|
|
10800
10834
|
try {
|
|
10801
|
-
|
|
10835
|
+
fs5.renameSync(lock, tomb);
|
|
10802
10836
|
} catch {
|
|
10803
10837
|
return false;
|
|
10804
10838
|
}
|
|
10805
10839
|
if (lockToken(tomb) !== token) {
|
|
10806
10840
|
try {
|
|
10807
|
-
|
|
10841
|
+
fs5.renameSync(tomb, lock);
|
|
10808
10842
|
} catch {}
|
|
10809
10843
|
return false;
|
|
10810
10844
|
}
|
|
10811
|
-
|
|
10845
|
+
fs5.rmSync(tomb, { recursive: true, force: true });
|
|
10812
10846
|
return true;
|
|
10813
10847
|
},
|
|
10814
10848
|
token: lockToken,
|
|
10815
10849
|
reap(lock, observed) {
|
|
10816
10850
|
const tomb = `${lock}.reap-${randomBytes(6).toString("hex")}`;
|
|
10817
10851
|
try {
|
|
10818
|
-
|
|
10852
|
+
fs5.renameSync(lock, tomb);
|
|
10819
10853
|
} catch {
|
|
10820
10854
|
return false;
|
|
10821
10855
|
}
|
|
10822
10856
|
if (lockToken(tomb) === observed) {
|
|
10823
|
-
|
|
10857
|
+
fs5.rmSync(tomb, { recursive: true, force: true });
|
|
10824
10858
|
return true;
|
|
10825
10859
|
}
|
|
10826
10860
|
try {
|
|
10827
|
-
|
|
10861
|
+
fs5.renameSync(tomb, lock);
|
|
10828
10862
|
} catch {
|
|
10829
|
-
|
|
10863
|
+
fs5.rmSync(tomb, { recursive: true, force: true });
|
|
10830
10864
|
}
|
|
10831
10865
|
return false;
|
|
10832
10866
|
}
|
|
@@ -10843,7 +10877,7 @@ var init_ledger = __esm(() => {
|
|
|
10843
10877
|
|
|
10844
10878
|
// packages/workit-core/src/core/policy/derive.ts
|
|
10845
10879
|
import { existsSync as existsSync2 } from "node:fs";
|
|
10846
|
-
import
|
|
10880
|
+
import path8 from "node:path";
|
|
10847
10881
|
function deriveRequirements(judgment, scope, constraints, verification = "self") {
|
|
10848
10882
|
const out = [];
|
|
10849
10883
|
const base = { scope, dependentAction: null };
|
|
@@ -10995,7 +11029,7 @@ var RULES, derived2 = (spec) => ({
|
|
|
10995
11029
|
decisionIds: []
|
|
10996
11030
|
};
|
|
10997
11031
|
}, planRecorded = (task, root) => {
|
|
10998
|
-
const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync2(
|
|
11032
|
+
const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync2(path8.resolve(root, ref.path)));
|
|
10999
11033
|
if (cited)
|
|
11000
11034
|
return {
|
|
11001
11035
|
met: true,
|
|
@@ -11592,7 +11626,7 @@ var init_safe_write = () => {};
|
|
|
11592
11626
|
|
|
11593
11627
|
// packages/workit-core/src/autonomy.ts
|
|
11594
11628
|
import os3 from "node:os";
|
|
11595
|
-
import
|
|
11629
|
+
import path9 from "node:path";
|
|
11596
11630
|
function endpointOf(entry) {
|
|
11597
11631
|
const raw = entry?.defaultEndpoint;
|
|
11598
11632
|
if (raw === undefined)
|
|
@@ -11689,9 +11723,9 @@ var accountHome = () => {
|
|
|
11689
11723
|
} catch {
|
|
11690
11724
|
return os3.homedir();
|
|
11691
11725
|
}
|
|
11692
|
-
}, grantsHome, grantsDir = () =>
|
|
11693
|
-
const configured =
|
|
11694
|
-
return configured ===
|
|
11726
|
+
}, grantsHome, grantsDir = () => path9.join(grantsHome.resolve(), ".config", "workit"), grantsOverride = () => {
|
|
11727
|
+
const configured = path9.resolve(resolveConfigDir());
|
|
11728
|
+
return configured === path9.resolve(grantsDir()) ? null : `the config directory is redirected to ${configured} (WORKFLOW_TOOLKIT_CONFIG, WORKFLOW_TOOLKIT_CONFIG_DIR or XDG_CONFIG_HOME); grants are read only from ${path9.join(grantsDir(), "workspaces.json")}, so the D4 defaults apply`;
|
|
11695
11729
|
}, GRANT_KINDS, DEFAULT_GRANTS, DEFAULT_ENDPOINTS, DEFAULT_ENDPOINT = "commit", isDefaultEndpoint = (value) => typeof value === "string" && DEFAULT_ENDPOINTS.includes(value), DEFAULT_VERIFICATION = "self", verificationOf = (entry) => entry?.verification === "independent" ? "independent" : "self", isGrantValue = (value) => value === true || value === false || value === "verified", normalized = (kind, value) => value === "verified" && kind !== "merge" ? true : value, fromAutoApprove = (value) => {
|
|
11696
11730
|
if (value === true)
|
|
11697
11731
|
return { push: true, pr: true, merge: "verified" };
|
|
@@ -11782,7 +11816,7 @@ function normalizeMaxBytes(value, options = {}) {
|
|
|
11782
11816
|
}
|
|
11783
11817
|
|
|
11784
11818
|
// node_modules/@openclaw/fs-safe/dist/bounded-read.js
|
|
11785
|
-
import
|
|
11819
|
+
import fs6 from "node:fs";
|
|
11786
11820
|
function createScratchBuffer(maxBytes) {
|
|
11787
11821
|
const initialReadBytes = Number.isFinite(maxBytes) ? Math.min(READ_CHUNK_BYTES, maxBytes + 1) : READ_CHUNK_BYTES;
|
|
11788
11822
|
return Buffer.allocUnsafe(Math.max(1, initialReadBytes));
|
|
@@ -11805,7 +11839,7 @@ function readFileDescriptorBoundedSync(fd, maxBytes) {
|
|
|
11805
11839
|
let total = 0;
|
|
11806
11840
|
while (true) {
|
|
11807
11841
|
const length = nextReadLength(total, maxBytes, scratch.length);
|
|
11808
|
-
const bytesRead =
|
|
11842
|
+
const bytesRead = fs6.readSync(fd, scratch, 0, length, null);
|
|
11809
11843
|
if (bytesRead === 0) {
|
|
11810
11844
|
return Buffer.concat(chunks, total);
|
|
11811
11845
|
}
|
|
@@ -11819,9 +11853,9 @@ var init_bounded_read = __esm(() => {
|
|
|
11819
11853
|
});
|
|
11820
11854
|
|
|
11821
11855
|
// node_modules/@openclaw/fs-safe/dist/read-open-flags.js
|
|
11822
|
-
import
|
|
11856
|
+
import fs7 from "node:fs";
|
|
11823
11857
|
function resolveReadOpenFlags(options) {
|
|
11824
|
-
const constants = options?.constants ??
|
|
11858
|
+
const constants = options?.constants ?? fs7.constants;
|
|
11825
11859
|
const noFollow = process.platform !== "win32" && options?.followSymlinks !== true && typeof constants.O_NOFOLLOW === "number" ? constants.O_NOFOLLOW : 0;
|
|
11826
11860
|
const nonBlocking = process.platform !== "win32" && typeof constants.O_NONBLOCK === "number" ? constants.O_NONBLOCK : 0;
|
|
11827
11861
|
return constants.O_RDONLY | noFollow | nonBlocking;
|
|
@@ -11831,7 +11865,7 @@ var init_read_open_flags = () => {};
|
|
|
11831
11865
|
// node_modules/@openclaw/fs-safe/dist/sidecar-lock-reclaim.js
|
|
11832
11866
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
11833
11867
|
import fsSync from "node:fs";
|
|
11834
|
-
import
|
|
11868
|
+
import path10 from "node:path";
|
|
11835
11869
|
function parseSidecarLockSnapshot(snapshot, parser) {
|
|
11836
11870
|
return snapshot && { ...snapshot, payload: parseSidecarLockPayload(snapshot.raw, parser) };
|
|
11837
11871
|
}
|
|
@@ -11859,13 +11893,13 @@ ${ownershipToken}
|
|
|
11859
11893
|
return { raw, ownershipToken };
|
|
11860
11894
|
}
|
|
11861
11895
|
function relativeSidecarLockPath(lockRoot, lockPath) {
|
|
11862
|
-
const resolved =
|
|
11863
|
-
const lexicalRelative =
|
|
11864
|
-
const relative = lexicalRelative !== ".." && !lexicalRelative.startsWith(`..${
|
|
11865
|
-
if (!relative || relative === ".." || relative.startsWith(`..${
|
|
11896
|
+
const resolved = path10.resolve(lockPath);
|
|
11897
|
+
const lexicalRelative = path10.relative(lockRoot.rootDir, resolved);
|
|
11898
|
+
const relative = lexicalRelative !== ".." && !lexicalRelative.startsWith(`..${path10.sep}`) && !path10.isAbsolute(lexicalRelative) ? lexicalRelative : path10.relative(lockRoot.rootReal, resolved);
|
|
11899
|
+
if (!relative || relative === ".." || relative.startsWith(`..${path10.sep}`) || path10.isAbsolute(relative)) {
|
|
11866
11900
|
throw new FsSafeError("outside-workspace", "sidecar lock path is outside lockRoot");
|
|
11867
11901
|
}
|
|
11868
|
-
return relative.split(
|
|
11902
|
+
return relative.split(path10.sep).join(path10.posix.sep);
|
|
11869
11903
|
}
|
|
11870
11904
|
function parseSidecarLockPayload(raw, parser) {
|
|
11871
11905
|
if (parser) {
|
|
@@ -12034,8 +12068,8 @@ function sleepSync(ms) {
|
|
|
12034
12068
|
}
|
|
12035
12069
|
|
|
12036
12070
|
// node_modules/@openclaw/fs-safe/dist/file-lock-sync.js
|
|
12037
|
-
import
|
|
12038
|
-
import
|
|
12071
|
+
import fs8 from "node:fs";
|
|
12072
|
+
import path11 from "node:path";
|
|
12039
12073
|
function getSyncHeldLocks() {
|
|
12040
12074
|
const globalWithState = globalThis;
|
|
12041
12075
|
if (!globalWithState[SYNC_HELD_LOCKS_KEY]) {
|
|
@@ -12052,7 +12086,7 @@ function releaseAllSyncHeldLocks() {
|
|
|
12052
12086
|
}
|
|
12053
12087
|
try {
|
|
12054
12088
|
if (held.fd !== undefined)
|
|
12055
|
-
|
|
12089
|
+
fs8.closeSync(held.fd);
|
|
12056
12090
|
} catch {}
|
|
12057
12091
|
try {
|
|
12058
12092
|
removeSidecarLockIfUnchangedSync(held.lockPath, held.snapshot);
|
|
@@ -12087,7 +12121,7 @@ function releaseSyncHeldLock(held) {
|
|
|
12087
12121
|
if (held.fd !== undefined) {
|
|
12088
12122
|
const fd = held.fd;
|
|
12089
12123
|
held.fd = undefined;
|
|
12090
|
-
|
|
12124
|
+
fs8.closeSync(fd);
|
|
12091
12125
|
}
|
|
12092
12126
|
removeSidecarLockIfUnchangedSync(held.lockPath, held.snapshot);
|
|
12093
12127
|
heldLocks.delete(held.normalizedTargetPath);
|
|
@@ -12110,29 +12144,29 @@ function createSyncHeldLockHandle(held) {
|
|
|
12110
12144
|
};
|
|
12111
12145
|
}
|
|
12112
12146
|
function canonicalLockParentSync(parent) {
|
|
12113
|
-
return process.platform === "win32" ?
|
|
12147
|
+
return process.platform === "win32" ? fs8.realpathSync.native(parent) : fs8.realpathSync(parent);
|
|
12114
12148
|
}
|
|
12115
12149
|
function normalizeTargetPath(targetPath) {
|
|
12116
|
-
const resolved =
|
|
12117
|
-
|
|
12150
|
+
const resolved = path11.resolve(targetPath);
|
|
12151
|
+
fs8.mkdirSync(path11.dirname(resolved), { recursive: true });
|
|
12118
12152
|
try {
|
|
12119
|
-
return
|
|
12153
|
+
return path11.join(canonicalLockParentSync(path11.dirname(resolved)), path11.basename(resolved));
|
|
12120
12154
|
} catch {
|
|
12121
12155
|
return resolved;
|
|
12122
12156
|
}
|
|
12123
12157
|
}
|
|
12124
12158
|
function boundedLockPath(lockPath, lockRoot) {
|
|
12125
|
-
const resolved =
|
|
12159
|
+
const resolved = path11.resolve(lockPath);
|
|
12126
12160
|
if (!lockRoot)
|
|
12127
12161
|
return resolved;
|
|
12128
12162
|
relativeSidecarLockPath(lockRoot, resolved);
|
|
12129
|
-
const parent =
|
|
12163
|
+
const parent = path11.dirname(resolved);
|
|
12130
12164
|
const parentReal = canonicalLockParentSync(parent);
|
|
12131
|
-
const parentRelative =
|
|
12132
|
-
if (parentRelative === ".." || parentRelative.startsWith(`..${
|
|
12165
|
+
const parentRelative = path11.relative(lockRoot.rootReal, parentReal);
|
|
12166
|
+
if (parentRelative === ".." || parentRelative.startsWith(`..${path11.sep}`) || path11.isAbsolute(parentRelative)) {
|
|
12133
12167
|
throw new FsSafeError("outside-workspace", "sidecar lock parent is outside lockRoot");
|
|
12134
12168
|
}
|
|
12135
|
-
return
|
|
12169
|
+
return path11.join(parentReal, path11.basename(resolved));
|
|
12136
12170
|
}
|
|
12137
12171
|
function defaultShouldReclaim(snapshot, staleMs, nowMs) {
|
|
12138
12172
|
const createdAtMs = sidecarLockPayloadCreatedAtMs(snapshot.payload);
|
|
@@ -12142,7 +12176,7 @@ function defaultShouldReclaim(snapshot, staleMs, nowMs) {
|
|
|
12142
12176
|
}
|
|
12143
12177
|
function reclaimGuardExists(reclaimGuardPath) {
|
|
12144
12178
|
try {
|
|
12145
|
-
|
|
12179
|
+
fs8.lstatSync(reclaimGuardPath);
|
|
12146
12180
|
return true;
|
|
12147
12181
|
} catch (error) {
|
|
12148
12182
|
if (error.code === "ENOENT")
|
|
@@ -12206,19 +12240,19 @@ function acquireFileLockSync(targetPath, options) {
|
|
|
12206
12240
|
const { raw, ownershipToken } = serializeSidecarLockPayload(payload);
|
|
12207
12241
|
let lockFileCreateDenied = false;
|
|
12208
12242
|
try {
|
|
12209
|
-
const noFollow = process.platform !== "win32" && typeof
|
|
12243
|
+
const noFollow = process.platform !== "win32" && typeof fs8.constants.O_NOFOLLOW === "number" ? fs8.constants.O_NOFOLLOW : 0;
|
|
12210
12244
|
try {
|
|
12211
|
-
fd =
|
|
12245
|
+
fd = fs8.openSync(lockPath, fs8.constants.O_WRONLY | fs8.constants.O_CREAT | fs8.constants.O_EXCL | noFollow, 384);
|
|
12212
12246
|
} catch (error) {
|
|
12213
12247
|
lockFileCreateDenied = isTransientLockFileDenial(error, lockPath);
|
|
12214
12248
|
throw error;
|
|
12215
12249
|
}
|
|
12216
|
-
|
|
12217
|
-
|
|
12250
|
+
fs8.writeFileSync(fd, raw, "utf8");
|
|
12251
|
+
fs8.fsyncSync(fd);
|
|
12218
12252
|
const snapshot = {
|
|
12219
12253
|
raw,
|
|
12220
12254
|
payload,
|
|
12221
|
-
stat:
|
|
12255
|
+
stat: fs8.fstatSync(fd),
|
|
12222
12256
|
ownershipToken
|
|
12223
12257
|
};
|
|
12224
12258
|
const createdHeld = {
|
|
@@ -12253,8 +12287,8 @@ function acquireFileLockSync(targetPath, options) {
|
|
|
12253
12287
|
return returnedHandle;
|
|
12254
12288
|
} catch (error) {
|
|
12255
12289
|
if (fd !== undefined) {
|
|
12256
|
-
const failed = { payload: null, stat:
|
|
12257
|
-
|
|
12290
|
+
const failed = { payload: null, stat: fs8.fstatSync(fd) };
|
|
12291
|
+
fs8.closeSync(fd);
|
|
12258
12292
|
fd = undefined;
|
|
12259
12293
|
removeSidecarLockIfUnchangedSync(lockPath, failed);
|
|
12260
12294
|
}
|
|
@@ -12303,7 +12337,7 @@ function acquireFileLockSync(targetPath, options) {
|
|
|
12303
12337
|
})) {
|
|
12304
12338
|
let ownsReclaimGuard = false;
|
|
12305
12339
|
try {
|
|
12306
|
-
|
|
12340
|
+
fs8.mkdirSync(reclaimGuardPath);
|
|
12307
12341
|
ownsReclaimGuard = true;
|
|
12308
12342
|
if (removeSidecarLockIfUnchangedSync(lockPath, snapshot))
|
|
12309
12343
|
continue;
|
|
@@ -12316,7 +12350,7 @@ function acquireFileLockSync(targetPath, options) {
|
|
|
12316
12350
|
} finally {
|
|
12317
12351
|
if (ownsReclaimGuard) {
|
|
12318
12352
|
try {
|
|
12319
|
-
|
|
12353
|
+
fs8.rmdirSync(reclaimGuardPath);
|
|
12320
12354
|
} catch {}
|
|
12321
12355
|
}
|
|
12322
12356
|
}
|
|
@@ -12349,13 +12383,13 @@ var init_file_lock = __esm(() => {
|
|
|
12349
12383
|
|
|
12350
12384
|
// packages/workit-core/src/core/package-root.ts
|
|
12351
12385
|
import { existsSync as existsSync3 } from "node:fs";
|
|
12352
|
-
import
|
|
12386
|
+
import path12 from "node:path";
|
|
12353
12387
|
import { fileURLToPath } from "node:url";
|
|
12354
12388
|
var packageRoot = () => {
|
|
12355
|
-
let dir =
|
|
12389
|
+
let dir = path12.dirname(fileURLToPath(import.meta.url));
|
|
12356
12390
|
while (true) {
|
|
12357
|
-
const parent =
|
|
12358
|
-
if (existsSync3(
|
|
12391
|
+
const parent = path12.dirname(dir);
|
|
12392
|
+
if (existsSync3(path12.join(dir, "package.json")) || parent === dir)
|
|
12359
12393
|
return dir;
|
|
12360
12394
|
dir = parent;
|
|
12361
12395
|
}
|
|
@@ -12364,7 +12398,7 @@ var init_package_root = () => {};
|
|
|
12364
12398
|
|
|
12365
12399
|
// packages/workit-core/src/core/store-lock.ts
|
|
12366
12400
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
12367
|
-
import
|
|
12401
|
+
import fs9 from "node:fs";
|
|
12368
12402
|
import { hostname } from "node:os";
|
|
12369
12403
|
var metadataLockSchema, FOREIGN_LOCK_TTL_MS, UNREADABLE_LOCK_TTL_MS = 30000, RECLAIM_GUARD_TTL_MS = 30000, defaultLockTimeoutMs = 250, defaultLockTimeout = () => defaultLockTimeoutMs, parseMetadataLock = (raw) => {
|
|
12370
12404
|
let value;
|
|
@@ -12391,7 +12425,7 @@ var metadataLockSchema, FOREIGN_LOCK_TTL_MS, UNREADABLE_LOCK_TTL_MS = 30000, REC
|
|
|
12391
12425
|
}, processStartOf = (pid) => {
|
|
12392
12426
|
if (process.platform === "linux") {
|
|
12393
12427
|
try {
|
|
12394
|
-
return parseProcStatStart(
|
|
12428
|
+
return parseProcStatStart(fs9.readFileSync(`/proc/${pid}/stat`, "utf8"));
|
|
12395
12429
|
} catch {
|
|
12396
12430
|
return null;
|
|
12397
12431
|
}
|
|
@@ -12411,7 +12445,7 @@ var metadataLockSchema, FOREIGN_LOCK_TTL_MS, UNREADABLE_LOCK_TTL_MS = 30000, REC
|
|
|
12411
12445
|
return null;
|
|
12412
12446
|
}, readTrimmed = (file) => {
|
|
12413
12447
|
try {
|
|
12414
|
-
return
|
|
12448
|
+
return fs9.readFileSync(file, "utf8").trim() || null;
|
|
12415
12449
|
} catch {
|
|
12416
12450
|
return null;
|
|
12417
12451
|
}
|
|
@@ -12420,7 +12454,7 @@ var metadataLockSchema, FOREIGN_LOCK_TTL_MS, UNREADABLE_LOCK_TTL_MS = 30000, REC
|
|
|
12420
12454
|
return cachedLockHost;
|
|
12421
12455
|
let pidns = null;
|
|
12422
12456
|
try {
|
|
12423
|
-
pidns = /\[(\d+)\]/.exec(
|
|
12457
|
+
pidns = /\[(\d+)\]/.exec(fs9.readlinkSync("/proc/self/ns/pid"))?.[1] ?? null;
|
|
12424
12458
|
} catch {}
|
|
12425
12459
|
const boot = readTrimmed("/proc/sys/kernel/random/boot_id");
|
|
12426
12460
|
cachedLockHost = pidns || boot ? `${hostname()}#${pidns ?? "?"}:${boot ?? "?"}` : hostname();
|
|
@@ -12462,7 +12496,7 @@ var metadataLockSchema, FOREIGN_LOCK_TTL_MS, UNREADABLE_LOCK_TTL_MS = 30000, REC
|
|
|
12462
12496
|
return { state: "live", reason: `held by running pid ${pid}` };
|
|
12463
12497
|
}, ageOf = (file, nowMs) => {
|
|
12464
12498
|
try {
|
|
12465
|
-
return nowMs -
|
|
12499
|
+
return nowMs - fs9.lstatSync(file).mtimeMs;
|
|
12466
12500
|
} catch {
|
|
12467
12501
|
return null;
|
|
12468
12502
|
}
|
|
@@ -12472,7 +12506,7 @@ var metadataLockSchema, FOREIGN_LOCK_TTL_MS, UNREADABLE_LOCK_TTL_MS = 30000, REC
|
|
|
12472
12506
|
if (age === null || age <= RECLAIM_GUARD_TTL_MS)
|
|
12473
12507
|
return false;
|
|
12474
12508
|
try {
|
|
12475
|
-
|
|
12509
|
+
fs9.rmdirSync(guard);
|
|
12476
12510
|
return true;
|
|
12477
12511
|
} catch {
|
|
12478
12512
|
return false;
|
|
@@ -12495,12 +12529,12 @@ var init_store_lock = __esm(() => {
|
|
|
12495
12529
|
|
|
12496
12530
|
// packages/workit-core/src/store/event-log.ts
|
|
12497
12531
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
12498
|
-
import
|
|
12499
|
-
import
|
|
12532
|
+
import fs10 from "node:fs";
|
|
12533
|
+
import path13 from "node:path";
|
|
12500
12534
|
function readLog(file, from = 0, expectSeq = null) {
|
|
12501
12535
|
let fd;
|
|
12502
12536
|
try {
|
|
12503
|
-
fd =
|
|
12537
|
+
fd = fs10.openSync(file, "r");
|
|
12504
12538
|
} catch (error) {
|
|
12505
12539
|
if (error.code === "ENOENT")
|
|
12506
12540
|
return null;
|
|
@@ -12509,13 +12543,13 @@ function readLog(file, from = 0, expectSeq = null) {
|
|
|
12509
12543
|
let bytes;
|
|
12510
12544
|
let size;
|
|
12511
12545
|
try {
|
|
12512
|
-
size =
|
|
12546
|
+
size = fs10.fstatSync(fd).size;
|
|
12513
12547
|
if (from > size)
|
|
12514
12548
|
throw new LogDamage(`${file}: shorter than its snapshot`);
|
|
12515
12549
|
bytes = Buffer.alloc(size - from);
|
|
12516
12550
|
let read = 0;
|
|
12517
12551
|
while (read < bytes.length) {
|
|
12518
|
-
const got =
|
|
12552
|
+
const got = fs10.readSync(fd, bytes, read, bytes.length - read, from + read);
|
|
12519
12553
|
if (got === 0)
|
|
12520
12554
|
break;
|
|
12521
12555
|
read += got;
|
|
@@ -12523,7 +12557,7 @@ function readLog(file, from = 0, expectSeq = null) {
|
|
|
12523
12557
|
bytes = bytes.subarray(0, read);
|
|
12524
12558
|
size = from + read;
|
|
12525
12559
|
} finally {
|
|
12526
|
-
|
|
12560
|
+
fs10.closeSync(fd);
|
|
12527
12561
|
}
|
|
12528
12562
|
const events = [];
|
|
12529
12563
|
let start = 0;
|
|
@@ -12549,46 +12583,46 @@ function readLog(file, from = 0, expectSeq = null) {
|
|
|
12549
12583
|
function appendEvent(file, event, validEnd) {
|
|
12550
12584
|
const line = Buffer.from(`${JSON.stringify(event)}
|
|
12551
12585
|
`, "utf8");
|
|
12552
|
-
const created = !
|
|
12553
|
-
if (!created &&
|
|
12554
|
-
const cut =
|
|
12586
|
+
const created = !fs10.existsSync(file);
|
|
12587
|
+
if (!created && fs10.statSync(file).size !== validEnd) {
|
|
12588
|
+
const cut = fs10.openSync(file, "r+");
|
|
12555
12589
|
try {
|
|
12556
|
-
|
|
12557
|
-
|
|
12590
|
+
fs10.ftruncateSync(cut, validEnd);
|
|
12591
|
+
fs10.fsyncSync(cut);
|
|
12558
12592
|
} finally {
|
|
12559
|
-
|
|
12593
|
+
fs10.closeSync(cut);
|
|
12560
12594
|
}
|
|
12561
12595
|
}
|
|
12562
|
-
const fd =
|
|
12596
|
+
const fd = fs10.openSync(file, "a", 384);
|
|
12563
12597
|
try {
|
|
12564
12598
|
let written = 0;
|
|
12565
12599
|
while (written < line.length)
|
|
12566
|
-
written +=
|
|
12567
|
-
|
|
12600
|
+
written += fs10.writeSync(fd, line, written, line.length - written);
|
|
12601
|
+
fs10.fsyncSync(fd);
|
|
12568
12602
|
} finally {
|
|
12569
|
-
|
|
12603
|
+
fs10.closeSync(fd);
|
|
12570
12604
|
}
|
|
12571
12605
|
if (created)
|
|
12572
|
-
fsyncDirectory(
|
|
12606
|
+
fsyncDirectory(path13.dirname(file));
|
|
12573
12607
|
return validEnd;
|
|
12574
12608
|
}
|
|
12575
12609
|
function replaceFile(file, bytes, durable) {
|
|
12576
12610
|
const temporary = `${file}.${process.pid}.${randomUUID2()}.tmp`;
|
|
12577
12611
|
try {
|
|
12578
|
-
const fd =
|
|
12612
|
+
const fd = fs10.openSync(temporary, "wx", 384);
|
|
12579
12613
|
try {
|
|
12580
|
-
|
|
12614
|
+
fs10.writeSync(fd, bytes);
|
|
12581
12615
|
if (durable)
|
|
12582
|
-
|
|
12616
|
+
fs10.fsyncSync(fd);
|
|
12583
12617
|
} finally {
|
|
12584
|
-
|
|
12618
|
+
fs10.closeSync(fd);
|
|
12585
12619
|
}
|
|
12586
12620
|
renameWithRetry(temporary, file);
|
|
12587
12621
|
if (durable)
|
|
12588
|
-
fsyncDirectory(
|
|
12622
|
+
fsyncDirectory(path13.dirname(file));
|
|
12589
12623
|
} catch (error) {
|
|
12590
12624
|
try {
|
|
12591
|
-
|
|
12625
|
+
fs10.unlinkSync(temporary);
|
|
12592
12626
|
} catch {}
|
|
12593
12627
|
throw error;
|
|
12594
12628
|
}
|
|
@@ -12609,11 +12643,11 @@ var EVENT_VERSION = 1, LogDamage, isObject4 = (value) => typeof value === "objec
|
|
|
12609
12643
|
return value;
|
|
12610
12644
|
}, fsyncDirectory = (dir) => {
|
|
12611
12645
|
try {
|
|
12612
|
-
const fd =
|
|
12646
|
+
const fd = fs10.openSync(dir, "r");
|
|
12613
12647
|
try {
|
|
12614
|
-
|
|
12648
|
+
fs10.fsyncSync(fd);
|
|
12615
12649
|
} finally {
|
|
12616
|
-
|
|
12650
|
+
fs10.closeSync(fd);
|
|
12617
12651
|
}
|
|
12618
12652
|
} catch (error) {
|
|
12619
12653
|
if (process.platform !== "win32")
|
|
@@ -12636,7 +12670,7 @@ var EVENT_VERSION = 1, LogDamage, isObject4 = (value) => typeof value === "objec
|
|
|
12636
12670
|
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, 5 * (attempt + 1));
|
|
12637
12671
|
}
|
|
12638
12672
|
}
|
|
12639
|
-
}, renameWithRetry = (from, to) => retryTransient(() =>
|
|
12673
|
+
}, renameWithRetry = (from, to) => retryTransient(() => fs10.renameSync(from, to));
|
|
12640
12674
|
var init_event_log = __esm(() => {
|
|
12641
12675
|
LogDamage = class LogDamage extends Error {
|
|
12642
12676
|
upgrade;
|
|
@@ -12755,7 +12789,7 @@ var isPlainObject2 = (value) => typeof value === "object" && value !== null && !
|
|
|
12755
12789
|
});
|
|
12756
12790
|
|
|
12757
12791
|
// packages/workit-core/src/store/reduce.ts
|
|
12758
|
-
import { createHash as
|
|
12792
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
12759
12793
|
function reduce(state, event, blobs) {
|
|
12760
12794
|
const data = event.data;
|
|
12761
12795
|
const known = KNOWN_TYPES.has(event.type);
|
|
@@ -12822,7 +12856,7 @@ function eventType(before, after) {
|
|
|
12822
12856
|
return "task.noted";
|
|
12823
12857
|
return "task.updated";
|
|
12824
12858
|
}
|
|
12825
|
-
var OPENING_TYPES, KNOWN_TYPES, isObject5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), isKey = (value) => isObject5(value) && typeof value.key === "string" && (value.kind === "branch" || value.kind === "detached" || value.kind === "dir") && (value.branch === null || typeof value.branch === "string"), BLOB_REF = "$blob", blobRef = (value) => isObject5(value) && Object.keys(value).length === 1 && typeof value[BLOB_REF] === "string" && /^[0-9a-f]{64}$/.test(value[BLOB_REF]) ? value[BLOB_REF] : null, blobDigest = (value) =>
|
|
12859
|
+
var OPENING_TYPES, KNOWN_TYPES, isObject5 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), isKey = (value) => isObject5(value) && typeof value.key === "string" && (value.kind === "branch" || value.kind === "detached" || value.kind === "dir") && (value.branch === null || typeof value.branch === "string"), BLOB_REF = "$blob", blobRef = (value) => isObject5(value) && Object.keys(value).length === 1 && typeof value[BLOB_REF] === "string" && /^[0-9a-f]{64}$/.test(value[BLOB_REF]) ? value[BLOB_REF] : null, blobDigest = (value) => createHash8("sha256").update(JSON.stringify(value)).digest("hex"), toBlob = (value, blobs) => {
|
|
12826
12860
|
if (!isObject5(value))
|
|
12827
12861
|
return value;
|
|
12828
12862
|
const digest = blobDigest(value);
|
|
@@ -12893,9 +12927,9 @@ var init_notes = __esm(() => {
|
|
|
12893
12927
|
});
|
|
12894
12928
|
|
|
12895
12929
|
// packages/workit-core/src/core/task-store.ts
|
|
12896
|
-
import { createHash as
|
|
12897
|
-
import * as
|
|
12898
|
-
import
|
|
12930
|
+
import { createHash as createHash9, randomUUID as randomUUID3 } from "node:crypto";
|
|
12931
|
+
import * as fs11 from "node:fs";
|
|
12932
|
+
import path14 from "node:path";
|
|
12899
12933
|
|
|
12900
12934
|
class TaskStore {
|
|
12901
12935
|
root;
|
|
@@ -12907,8 +12941,8 @@ class TaskStore {
|
|
|
12907
12941
|
migrationChecked = false;
|
|
12908
12942
|
compactDue = new Set;
|
|
12909
12943
|
constructor(root, options = {}) {
|
|
12910
|
-
const resolved =
|
|
12911
|
-
this.origin =
|
|
12944
|
+
const resolved = path14.resolve(root);
|
|
12945
|
+
this.origin = fs11.existsSync(resolved) ? fs11.realpathSync(resolved) : resolved;
|
|
12912
12946
|
this.located = resolveStore(this.origin);
|
|
12913
12947
|
this.root = checkoutRootOf(this.origin, this.located);
|
|
12914
12948
|
this.lockTimeoutMs = options.lockTimeoutMs ?? defaultLockTimeout();
|
|
@@ -12916,7 +12950,7 @@ class TaskStore {
|
|
|
12916
12950
|
this.migrateOnRead = options.migrateOnRead;
|
|
12917
12951
|
}
|
|
12918
12952
|
location() {
|
|
12919
|
-
if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared &&
|
|
12953
|
+
if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared && fs11.existsSync(path14.join(this.root, ".git"))) {
|
|
12920
12954
|
this.located = undefined;
|
|
12921
12955
|
this.migrationChecked = false;
|
|
12922
12956
|
}
|
|
@@ -12980,7 +13014,7 @@ class TaskStore {
|
|
|
12980
13014
|
const tasksDir = this.paths().tasks;
|
|
12981
13015
|
let names;
|
|
12982
13016
|
try {
|
|
12983
|
-
names =
|
|
13017
|
+
names = fs11.existsSync(tasksDir) ? fs11.readdirSync(tasksDir).filter((name) => validId(name)) : [];
|
|
12984
13018
|
} catch (error) {
|
|
12985
13019
|
return failure2("storage_error", `unable to list tasks: ${String(error)}`, {
|
|
12986
13020
|
path: tasksDir
|
|
@@ -13021,7 +13055,7 @@ class TaskStore {
|
|
|
13021
13055
|
const file = this.paths().workspace;
|
|
13022
13056
|
let bytes;
|
|
13023
13057
|
try {
|
|
13024
|
-
bytes = retryTransient(() =>
|
|
13058
|
+
bytes = retryTransient(() => fs11.readFileSync(file, "utf8"));
|
|
13025
13059
|
} catch (error) {
|
|
13026
13060
|
if (error.code === "ENOENT")
|
|
13027
13061
|
return success(null, null, null);
|
|
@@ -13072,7 +13106,7 @@ class TaskStore {
|
|
|
13072
13106
|
const moved = this.bindLocked(again.data.id, key, input.now);
|
|
13073
13107
|
return moved.ok ? success(moved.data.revision, null, { task: moved.data, created: false, key }) : moved;
|
|
13074
13108
|
}
|
|
13075
|
-
const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" :
|
|
13109
|
+
const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" : path14.basename(this.root) || this.root;
|
|
13076
13110
|
const intent = {
|
|
13077
13111
|
objective: input.objective?.trim() || `Work on ${label}`,
|
|
13078
13112
|
scope: { description: `the checkout (${label})`, paths: ["."], exclusions: [] },
|
|
@@ -13132,14 +13166,14 @@ class TaskStore {
|
|
|
13132
13166
|
const branch = key.ok ? key.data.branch : null;
|
|
13133
13167
|
if (!branch || !location.ok)
|
|
13134
13168
|
return success(null, null, null);
|
|
13135
|
-
const common =
|
|
13136
|
-
const heads =
|
|
13137
|
-
const headLog = location.data.git ?
|
|
13169
|
+
const common = path14.dirname(location.data.dir);
|
|
13170
|
+
const heads = path14.join(common, "logs", "refs", "heads");
|
|
13171
|
+
const headLog = location.data.git ? path14.join(location.data.git.gitDir, "logs", "HEAD") : "";
|
|
13138
13172
|
const signatures = [
|
|
13139
|
-
|
|
13173
|
+
path14.join(heads, branch),
|
|
13140
13174
|
headLog,
|
|
13141
13175
|
heads,
|
|
13142
|
-
|
|
13176
|
+
path14.join(common, "packed-refs")
|
|
13143
13177
|
].map((file) => fileSignature(file) ?? "-");
|
|
13144
13178
|
const slot = `${location.data.dir}\x00${headLog}\x00${branch}`;
|
|
13145
13179
|
let resolved = origins.get(slot);
|
|
@@ -13151,7 +13185,7 @@ class TaskStore {
|
|
|
13151
13185
|
aliases.push(rename.from);
|
|
13152
13186
|
const start = branchStart(location.data, branch, aliases);
|
|
13153
13187
|
const slash = start?.indexOf("/") ?? -1;
|
|
13154
|
-
const remote = slash > 0 && !refExists(common, `refs/heads/${start}`) && (refExists(common, `refs/remotes/${start}`) || readText(
|
|
13188
|
+
const remote = slash > 0 && !refExists(common, `refs/heads/${start}`) && (refExists(common, `refs/remotes/${start}`) || readText(path14.join(common, "config")).includes(`[remote "${start.slice(0, slash)}"]`));
|
|
13155
13189
|
const name = start && (remote ? start.slice(slash + 1) : start);
|
|
13156
13190
|
resolved = {
|
|
13157
13191
|
signature: signatures.join("|"),
|
|
@@ -13389,13 +13423,13 @@ class TaskStore {
|
|
|
13389
13423
|
if (!ready.ok)
|
|
13390
13424
|
return ready;
|
|
13391
13425
|
const dirs = this.paths();
|
|
13392
|
-
const recovery =
|
|
13393
|
-
if (
|
|
13426
|
+
const recovery = path14.join(this.root, ".workit", "recovery");
|
|
13427
|
+
if (fs11.existsSync(recovery)) {
|
|
13394
13428
|
let files = 0;
|
|
13395
13429
|
let bytes = 0;
|
|
13396
13430
|
try {
|
|
13397
|
-
for (const name of
|
|
13398
|
-
const stat =
|
|
13431
|
+
for (const name of fs11.readdirSync(recovery)) {
|
|
13432
|
+
const stat = fs11.lstatSync(path14.join(recovery, name));
|
|
13399
13433
|
if (!stat.isFile())
|
|
13400
13434
|
continue;
|
|
13401
13435
|
files += 1;
|
|
@@ -13404,17 +13438,17 @@ class TaskStore {
|
|
|
13404
13438
|
} catch {}
|
|
13405
13439
|
const remove = options.pruneRecovery === true && !dryRun;
|
|
13406
13440
|
if (remove)
|
|
13407
|
-
|
|
13441
|
+
fs11.rmSync(recovery, { recursive: true, force: true });
|
|
13408
13442
|
report.legacyRecovery = { path: recovery, files, bytes, removed: remove };
|
|
13409
13443
|
}
|
|
13410
|
-
if (!
|
|
13444
|
+
if (!fs11.existsSync(dirs.tasks))
|
|
13411
13445
|
return success(null, null, report);
|
|
13412
|
-
const names =
|
|
13446
|
+
const names = fs11.readdirSync(dirs.tasks).filter((name) => validId(name));
|
|
13413
13447
|
for (const name of names) {
|
|
13414
13448
|
const file = this.eventsPath(name);
|
|
13415
13449
|
let size = 0;
|
|
13416
13450
|
try {
|
|
13417
|
-
size =
|
|
13451
|
+
size = fs11.statSync(file).size;
|
|
13418
13452
|
} catch {
|
|
13419
13453
|
continue;
|
|
13420
13454
|
}
|
|
@@ -13442,16 +13476,16 @@ class TaskStore {
|
|
|
13442
13476
|
const references = new Set;
|
|
13443
13477
|
for (const name of names)
|
|
13444
13478
|
try {
|
|
13445
|
-
for (const match of
|
|
13479
|
+
for (const match of fs11.readFileSync(this.eventsPath(name), "utf8").matchAll(/"\$blob":"([0-9a-f]{64})"/g))
|
|
13446
13480
|
references.add(match[1]);
|
|
13447
13481
|
} catch {}
|
|
13448
|
-
if (
|
|
13449
|
-
for (const name of
|
|
13482
|
+
if (fs11.existsSync(dirs.blobs))
|
|
13483
|
+
for (const name of fs11.readdirSync(dirs.blobs)) {
|
|
13450
13484
|
const digest = name.replace(/\.json$/, "");
|
|
13451
|
-
const file =
|
|
13485
|
+
const file = path14.join(dirs.blobs, name);
|
|
13452
13486
|
let stat;
|
|
13453
13487
|
try {
|
|
13454
|
-
stat =
|
|
13488
|
+
stat = fs11.lstatSync(file);
|
|
13455
13489
|
} catch {
|
|
13456
13490
|
continue;
|
|
13457
13491
|
}
|
|
@@ -13462,11 +13496,11 @@ class TaskStore {
|
|
|
13462
13496
|
report.blobs.removed += 1;
|
|
13463
13497
|
report.blobs.removedBytes += stat.size;
|
|
13464
13498
|
if (!dryRun)
|
|
13465
|
-
|
|
13499
|
+
fs11.rmSync(file, { force: true });
|
|
13466
13500
|
}
|
|
13467
13501
|
return success(null, null, null);
|
|
13468
13502
|
};
|
|
13469
|
-
const swept = dryRun ? sweep() : this.withLock(
|
|
13503
|
+
const swept = dryRun ? sweep() : this.withLock(path14.join(dirs.dir, "gc.lock"), sweep);
|
|
13470
13504
|
if (!swept.ok)
|
|
13471
13505
|
return swept;
|
|
13472
13506
|
const temporaryDirs = [
|
|
@@ -13474,17 +13508,17 @@ class TaskStore {
|
|
|
13474
13508
|
dirs.tasks,
|
|
13475
13509
|
dirs.blobs,
|
|
13476
13510
|
dirs.checkout,
|
|
13477
|
-
...names.map((name) =>
|
|
13511
|
+
...names.map((name) => path14.join(dirs.tasks, name))
|
|
13478
13512
|
];
|
|
13479
13513
|
for (const directory of temporaryDirs) {
|
|
13480
|
-
if (!
|
|
13514
|
+
if (!fs11.existsSync(directory))
|
|
13481
13515
|
continue;
|
|
13482
|
-
for (const name of
|
|
13516
|
+
for (const name of fs11.readdirSync(directory)) {
|
|
13483
13517
|
if (!name.endsWith(".tmp") && !name.endsWith(".probe"))
|
|
13484
13518
|
continue;
|
|
13485
|
-
const file =
|
|
13519
|
+
const file = path14.join(directory, name);
|
|
13486
13520
|
try {
|
|
13487
|
-
const stat =
|
|
13521
|
+
const stat = fs11.lstatSync(file);
|
|
13488
13522
|
if (!stat.isFile() || nowMs - stat.mtimeMs <= STALE_TEMPORARY_MS)
|
|
13489
13523
|
continue;
|
|
13490
13524
|
} catch {
|
|
@@ -13492,37 +13526,37 @@ class TaskStore {
|
|
|
13492
13526
|
}
|
|
13493
13527
|
report.temporary.removed += 1;
|
|
13494
13528
|
if (!dryRun)
|
|
13495
|
-
|
|
13529
|
+
fs11.rmSync(file, { force: true });
|
|
13496
13530
|
}
|
|
13497
13531
|
}
|
|
13498
13532
|
return success(null, null, report);
|
|
13499
13533
|
}
|
|
13500
13534
|
paths() {
|
|
13501
13535
|
const location = this.location();
|
|
13502
|
-
const dir = location.ok ? location.data.dir :
|
|
13503
|
-
const checkout =
|
|
13536
|
+
const dir = location.ok ? location.data.dir : path14.join(this.root, ".workit");
|
|
13537
|
+
const checkout = path14.join(dir, "checkouts", checkoutSlug(this.root));
|
|
13504
13538
|
return {
|
|
13505
13539
|
dir,
|
|
13506
13540
|
shared: location.ok ? location.data.shared : false,
|
|
13507
|
-
marker:
|
|
13541
|
+
marker: path14.join(dir, "store.json"),
|
|
13508
13542
|
checkout,
|
|
13509
|
-
workspace:
|
|
13510
|
-
checkoutLock:
|
|
13511
|
-
tasks:
|
|
13512
|
-
index:
|
|
13513
|
-
blobs:
|
|
13514
|
-
legacy:
|
|
13515
|
-
v2:
|
|
13543
|
+
workspace: path14.join(checkout, "workspace.json"),
|
|
13544
|
+
checkoutLock: path14.join(checkout, "metadata.lock"),
|
|
13545
|
+
tasks: path14.join(dir, "tasks"),
|
|
13546
|
+
index: path14.join(dir, "task-index.json"),
|
|
13547
|
+
blobs: path14.join(dir, "blobs", "candidates"),
|
|
13548
|
+
legacy: path14.join(dir, "legacy", checkoutSlug(this.root), "v2"),
|
|
13549
|
+
v2: path14.join(this.root, ".workit")
|
|
13516
13550
|
};
|
|
13517
13551
|
}
|
|
13518
13552
|
eventsPath(taskId) {
|
|
13519
|
-
return
|
|
13553
|
+
return path14.join(this.paths().tasks, taskId, "events.jsonl");
|
|
13520
13554
|
}
|
|
13521
13555
|
snapshotPath(taskId) {
|
|
13522
|
-
return
|
|
13556
|
+
return path14.join(this.paths().tasks, taskId, "snapshot.json");
|
|
13523
13557
|
}
|
|
13524
13558
|
taskLockPath(taskId) {
|
|
13525
|
-
return
|
|
13559
|
+
return path14.join(this.paths().tasks, taskId, "lock");
|
|
13526
13560
|
}
|
|
13527
13561
|
ready(write = false) {
|
|
13528
13562
|
const location = this.location();
|
|
@@ -13532,7 +13566,7 @@ class TaskStore {
|
|
|
13532
13566
|
return success(null, null, null);
|
|
13533
13567
|
const dirs = this.paths();
|
|
13534
13568
|
try {
|
|
13535
|
-
const marker = JSON.parse(
|
|
13569
|
+
const marker = JSON.parse(fs11.readFileSync(dirs.marker, "utf8"));
|
|
13536
13570
|
if (typeof marker.version === "number" && marker.version > STORE_FORMAT)
|
|
13537
13571
|
return failure2("recovery_required", `the workit store at ${dirs.dir} has format ${marker.version}; upgrade Workit to use it`, { path: dirs.marker });
|
|
13538
13572
|
} catch {}
|
|
@@ -13561,21 +13595,21 @@ class TaskStore {
|
|
|
13561
13595
|
return {
|
|
13562
13596
|
read: (digest) => {
|
|
13563
13597
|
try {
|
|
13564
|
-
return JSON.parse(
|
|
13598
|
+
return JSON.parse(fs11.readFileSync(path14.join(dir, `${digest}.json`), "utf8"));
|
|
13565
13599
|
} catch (error) {
|
|
13566
13600
|
throw new LogDamage(`stored candidate ${digest} is missing or unreadable: ${String(error)}`);
|
|
13567
13601
|
}
|
|
13568
13602
|
},
|
|
13569
13603
|
write: (digest, value) => {
|
|
13570
|
-
const file =
|
|
13571
|
-
if (
|
|
13604
|
+
const file = path14.join(dir, `${digest}.json`);
|
|
13605
|
+
if (fs11.existsSync(file)) {
|
|
13572
13606
|
const stamp = new Date;
|
|
13573
13607
|
try {
|
|
13574
|
-
|
|
13608
|
+
fs11.utimesSync(file, stamp, stamp);
|
|
13575
13609
|
return;
|
|
13576
13610
|
} catch {}
|
|
13577
13611
|
}
|
|
13578
|
-
|
|
13612
|
+
fs11.mkdirSync(dir, { recursive: true });
|
|
13579
13613
|
replaceFile(file, JSON.stringify(value), true);
|
|
13580
13614
|
}
|
|
13581
13615
|
};
|
|
@@ -13657,7 +13691,7 @@ class TaskStore {
|
|
|
13657
13691
|
}
|
|
13658
13692
|
readSnapshot(taskId) {
|
|
13659
13693
|
try {
|
|
13660
|
-
const value = JSON.parse(
|
|
13694
|
+
const value = JSON.parse(fs11.readFileSync(this.snapshotPath(taskId), "utf8"));
|
|
13661
13695
|
if (!isObject6(value) || value.v !== 1 || value.task !== taskId || typeof value.seq !== "number" || typeof value.lastId !== "string" || typeof value.lastStart !== "number" || typeof value.end !== "number" || !isObject6(value.record))
|
|
13662
13696
|
return null;
|
|
13663
13697
|
return value;
|
|
@@ -13759,8 +13793,8 @@ class TaskStore {
|
|
|
13759
13793
|
}
|
|
13760
13794
|
}
|
|
13761
13795
|
openTask(record, type, key, legacy = null) {
|
|
13762
|
-
const dir =
|
|
13763
|
-
|
|
13796
|
+
const dir = path14.join(this.paths().tasks, record.id);
|
|
13797
|
+
fs11.mkdirSync(dir, { recursive: true });
|
|
13764
13798
|
const blobs = this.blobStore();
|
|
13765
13799
|
const bound = key ? { ...key, boundAt: key.boundAt ?? new Date().toISOString() } : null;
|
|
13766
13800
|
const event = this.event(record.id, 1, type, {
|
|
@@ -13812,11 +13846,11 @@ class TaskStore {
|
|
|
13812
13846
|
} catch {}
|
|
13813
13847
|
if (!latest || latest.events[0]?.id !== last.id)
|
|
13814
13848
|
return failure2("busy", "the task log changed during compaction; retry", { taskId });
|
|
13815
|
-
const appended =
|
|
13849
|
+
const appended = fs11.readFileSync(file).subarray(log.end, latest.end);
|
|
13816
13850
|
const bytes = Buffer.concat([Buffer.from(prefix, "utf8"), appended]);
|
|
13817
13851
|
replaceFile(file, bytes.toString("utf8"), true);
|
|
13818
13852
|
try {
|
|
13819
|
-
|
|
13853
|
+
fs11.rmSync(this.snapshotPath(taskId), { force: true });
|
|
13820
13854
|
} catch {}
|
|
13821
13855
|
const reloaded = this.load(taskId);
|
|
13822
13856
|
if (reloaded.ok && reloaded.data)
|
|
@@ -13829,7 +13863,7 @@ class TaskStore {
|
|
|
13829
13863
|
}
|
|
13830
13864
|
countEvents(file) {
|
|
13831
13865
|
try {
|
|
13832
|
-
const bytes =
|
|
13866
|
+
const bytes = fs11.readFileSync(file);
|
|
13833
13867
|
let count = 0;
|
|
13834
13868
|
for (let index = bytes.indexOf(10);index >= 0; index = bytes.indexOf(10, index + 1))
|
|
13835
13869
|
count += 1;
|
|
@@ -13851,8 +13885,8 @@ class TaskStore {
|
|
|
13851
13885
|
return bound.ok ? success(null, null, bound.data[0] ?? null) : bound;
|
|
13852
13886
|
}
|
|
13853
13887
|
withKeyLock(key, operation) {
|
|
13854
|
-
const digest =
|
|
13855
|
-
return this.withLock(
|
|
13888
|
+
const digest = createHash9("sha256").update(key).digest("hex").slice(0, 32);
|
|
13889
|
+
return this.withLock(path14.join(this.paths().dir, "keys", `${digest}.lock`), operation);
|
|
13856
13890
|
}
|
|
13857
13891
|
bindLocked(taskId, key, timestamp) {
|
|
13858
13892
|
const current = this.readWorkspace();
|
|
@@ -13993,7 +14027,7 @@ class TaskStore {
|
|
|
13993
14027
|
writeWorkspace(record) {
|
|
13994
14028
|
const file = this.paths().workspace;
|
|
13995
14029
|
try {
|
|
13996
|
-
|
|
14030
|
+
fs11.mkdirSync(path14.dirname(file), { recursive: true });
|
|
13997
14031
|
replaceFile(file, `${canonicalJson(record)}
|
|
13998
14032
|
`, true);
|
|
13999
14033
|
return success(null, null, null);
|
|
@@ -14003,7 +14037,7 @@ class TaskStore {
|
|
|
14003
14037
|
}
|
|
14004
14038
|
readIndex() {
|
|
14005
14039
|
try {
|
|
14006
|
-
const value = JSON.parse(
|
|
14040
|
+
const value = JSON.parse(fs11.readFileSync(this.paths().index, "utf8"));
|
|
14007
14041
|
if (!isObject6(value) || value.version !== INDEX_VERSION || !isObject6(value.tasks))
|
|
14008
14042
|
return {};
|
|
14009
14043
|
const tasks = {};
|
|
@@ -14017,7 +14051,7 @@ class TaskStore {
|
|
|
14017
14051
|
}
|
|
14018
14052
|
writeIndex(entries) {
|
|
14019
14053
|
try {
|
|
14020
|
-
|
|
14054
|
+
fs11.mkdirSync(this.paths().tasks, { recursive: true });
|
|
14021
14055
|
replaceFile(this.paths().index, JSON.stringify({
|
|
14022
14056
|
version: INDEX_VERSION,
|
|
14023
14057
|
tasks: Object.fromEntries(entries.map((entry) => [entry.id, entry]))
|
|
@@ -14071,23 +14105,23 @@ class TaskStore {
|
|
|
14071
14105
|
return failure2("revision_conflict", "workspace revision does not match; omit expectedWorkspaceRevision to use the current record", { expectedWorkspaceRevision: expected, actualWorkspaceRevision: actual });
|
|
14072
14106
|
}
|
|
14073
14107
|
v2Dirs() {
|
|
14074
|
-
return [...new Set([this.root, this.origin])].map((dir) =>
|
|
14108
|
+
return [...new Set([this.root, this.origin])].map((dir) => path14.join(dir, ".workit"));
|
|
14075
14109
|
}
|
|
14076
14110
|
pendingMigrations() {
|
|
14077
14111
|
return this.v2Dirs().filter((dir) => {
|
|
14078
|
-
const raw = this.readV2Workspace(
|
|
14112
|
+
const raw = this.readV2Workspace(path14.join(dir, "workspace.json"));
|
|
14079
14113
|
return raw !== null && raw !== TOMBSTONE;
|
|
14080
14114
|
});
|
|
14081
14115
|
}
|
|
14082
14116
|
migrateV2(v2) {
|
|
14083
14117
|
const dirs = this.paths();
|
|
14084
|
-
const v2Workspace =
|
|
14085
|
-
const v2Tasks =
|
|
14086
|
-
const legacy =
|
|
14118
|
+
const v2Workspace = path14.join(v2, "workspace.json");
|
|
14119
|
+
const v2Tasks = path14.join(v2, "tasks");
|
|
14120
|
+
const legacy = path14.join(dirs.dir, "legacy", checkoutSlug(path14.dirname(v2)), "v2");
|
|
14087
14121
|
const raw = this.readV2Workspace(v2Workspace);
|
|
14088
14122
|
if (raw === null || raw === TOMBSTONE)
|
|
14089
14123
|
return success(null, null, null);
|
|
14090
|
-
return this.withLock(dirs.checkoutLock, () => this.withLock(
|
|
14124
|
+
return this.withLock(dirs.checkoutLock, () => this.withLock(path14.join(v2, "metadata.lock"), () => {
|
|
14091
14125
|
const workspace = this.readV2Workspace(v2Workspace);
|
|
14092
14126
|
if (workspace === null || workspace === TOMBSTONE)
|
|
14093
14127
|
return success(null, null, null);
|
|
@@ -14096,7 +14130,7 @@ class TaskStore {
|
|
|
14096
14130
|
return failure2("recovery_required", `cannot migrate the 2.x store at ${v2}: ${parsedWorkspace.error}; move it aside to start fresh`, { path: v2Workspace });
|
|
14097
14131
|
let files = [];
|
|
14098
14132
|
try {
|
|
14099
|
-
files =
|
|
14133
|
+
files = fs11.readdirSync(v2Tasks).filter((name) => name.endsWith(".json") && validId(name.slice(0, -5))).filter((name) => !this.isStub(path14.join(v2Tasks, name)));
|
|
14100
14134
|
} catch {}
|
|
14101
14135
|
const current = this.readWorkspace();
|
|
14102
14136
|
if (!current.ok)
|
|
@@ -14114,22 +14148,22 @@ class TaskStore {
|
|
|
14114
14148
|
let skipped = 0;
|
|
14115
14149
|
const done = new Map;
|
|
14116
14150
|
try {
|
|
14117
|
-
|
|
14151
|
+
fs11.mkdirSync(path14.join(legacy, "tasks"), { recursive: true });
|
|
14118
14152
|
for (const name of ["workspace.json", "index.json"])
|
|
14119
|
-
if (
|
|
14120
|
-
|
|
14153
|
+
if (fs11.existsSync(path14.join(v2, name)))
|
|
14154
|
+
fs11.copyFileSync(path14.join(v2, name), path14.join(legacy, name));
|
|
14121
14155
|
for (const name of files) {
|
|
14122
14156
|
const id = name.slice(0, -5);
|
|
14123
|
-
const file =
|
|
14124
|
-
const bytes =
|
|
14157
|
+
const file = path14.join(v2Tasks, name);
|
|
14158
|
+
const bytes = fs11.readFileSync(file, "utf8");
|
|
14125
14159
|
const digest = sha256(bytes);
|
|
14126
|
-
|
|
14160
|
+
fs11.writeFileSync(path14.join(legacy, "tasks", name), bytes);
|
|
14127
14161
|
const parsed = this.parseRecord(bytes, taskRecordSchema, "2.x task");
|
|
14128
14162
|
if (!parsed.ok || parsed.data.id !== id)
|
|
14129
14163
|
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 });
|
|
14130
14164
|
const record = { ...parsed.data, workspaceId: target.id };
|
|
14131
|
-
const origin = { path:
|
|
14132
|
-
if (!
|
|
14165
|
+
const origin = { path: path14.join(legacy, "tasks", name), digest };
|
|
14166
|
+
if (!fs11.existsSync(this.eventsPath(id))) {
|
|
14133
14167
|
this.openTask(record, "migrated.from_v2", null, origin);
|
|
14134
14168
|
migrated += 1;
|
|
14135
14169
|
} else {
|
|
@@ -14164,8 +14198,8 @@ class TaskStore {
|
|
|
14164
14198
|
try {
|
|
14165
14199
|
let complete = true;
|
|
14166
14200
|
for (const [name, digest] of done) {
|
|
14167
|
-
const file =
|
|
14168
|
-
if (sha256(
|
|
14201
|
+
const file = path14.join(v2Tasks, name);
|
|
14202
|
+
if (sha256(fs11.readFileSync(file, "utf8")) !== digest) {
|
|
14169
14203
|
complete = false;
|
|
14170
14204
|
continue;
|
|
14171
14205
|
}
|
|
@@ -14175,7 +14209,7 @@ class TaskStore {
|
|
|
14175
14209
|
return failure2("busy", `the 2.x store at ${v2} changed during migration; retry`, {
|
|
14176
14210
|
path: v2
|
|
14177
14211
|
});
|
|
14178
|
-
|
|
14212
|
+
fs11.rmSync(path14.join(v2, "index.json"), { force: true });
|
|
14179
14213
|
this.writeTombstone(v2, target.id);
|
|
14180
14214
|
} catch (error) {
|
|
14181
14215
|
return failure2("storage_error", `cannot finish the 2.x migration: ${String(error)}`, {
|
|
@@ -14195,45 +14229,45 @@ class TaskStore {
|
|
|
14195
14229
|
}
|
|
14196
14230
|
adoptLocalStore() {
|
|
14197
14231
|
const dirs = this.paths();
|
|
14198
|
-
const marker =
|
|
14199
|
-
if (!dirs.shared || !
|
|
14232
|
+
const marker = path14.join(dirs.v2, "store.json");
|
|
14233
|
+
if (!dirs.shared || !fs11.existsSync(marker))
|
|
14200
14234
|
return success(null, null, null);
|
|
14201
14235
|
return this.withLock(dirs.checkoutLock, () => {
|
|
14202
|
-
if (!
|
|
14236
|
+
if (!fs11.existsSync(marker))
|
|
14203
14237
|
return success(null, null, null);
|
|
14204
14238
|
let tasks = 0;
|
|
14205
14239
|
try {
|
|
14206
14240
|
const merge = (from, to) => {
|
|
14207
|
-
if (!
|
|
14208
|
-
|
|
14241
|
+
if (!fs11.existsSync(to)) {
|
|
14242
|
+
fs11.mkdirSync(path14.dirname(to), { recursive: true });
|
|
14209
14243
|
try {
|
|
14210
|
-
|
|
14244
|
+
fs11.renameSync(from, to);
|
|
14211
14245
|
} catch {
|
|
14212
|
-
|
|
14213
|
-
|
|
14246
|
+
fs11.cpSync(from, to, { recursive: true, errorOnExist: true, force: false });
|
|
14247
|
+
fs11.rmSync(from, { recursive: true, force: true });
|
|
14214
14248
|
}
|
|
14215
14249
|
return;
|
|
14216
14250
|
}
|
|
14217
|
-
if (
|
|
14218
|
-
for (const name of
|
|
14219
|
-
merge(
|
|
14251
|
+
if (fs11.lstatSync(from).isDirectory() && fs11.lstatSync(to).isDirectory())
|
|
14252
|
+
for (const name of fs11.readdirSync(from))
|
|
14253
|
+
merge(path14.join(from, name), path14.join(to, name));
|
|
14220
14254
|
};
|
|
14221
14255
|
for (const sub of ["tasks", "checkouts", "blobs", "legacy"]) {
|
|
14222
|
-
const from =
|
|
14223
|
-
if (!
|
|
14256
|
+
const from = path14.join(dirs.v2, sub);
|
|
14257
|
+
if (!fs11.existsSync(from))
|
|
14224
14258
|
continue;
|
|
14225
14259
|
if (sub === "tasks") {
|
|
14226
|
-
for (const name of
|
|
14227
|
-
if (validId(name) && !
|
|
14260
|
+
for (const name of fs11.readdirSync(from))
|
|
14261
|
+
if (validId(name) && !fs11.existsSync(path14.join(dirs.dir, sub, name)))
|
|
14228
14262
|
tasks += 1;
|
|
14229
14263
|
}
|
|
14230
|
-
merge(from,
|
|
14264
|
+
merge(from, path14.join(dirs.dir, sub));
|
|
14231
14265
|
}
|
|
14232
|
-
const ledger =
|
|
14233
|
-
if (
|
|
14234
|
-
merge(ledger,
|
|
14235
|
-
|
|
14236
|
-
|
|
14266
|
+
const ledger = path14.join(dirs.v2, "ledger");
|
|
14267
|
+
if (fs11.existsSync(ledger) && !fs11.existsSync(path14.join(dirs.dir, "ledger")))
|
|
14268
|
+
merge(ledger, path14.join(dirs.dir, "ledger"));
|
|
14269
|
+
fs11.rmSync(path14.join(dirs.v2, "task-index.json"), { force: true });
|
|
14270
|
+
fs11.renameSync(marker, path14.join(dirs.v2, "store.moved.json"));
|
|
14237
14271
|
} catch (error) {
|
|
14238
14272
|
return failure2("storage_error", `cannot move ${dirs.v2} into ${dirs.dir}: ${String(error)}`, {
|
|
14239
14273
|
path: dirs.v2
|
|
@@ -14253,7 +14287,7 @@ class TaskStore {
|
|
|
14253
14287
|
readV2Workspace(file) {
|
|
14254
14288
|
let bytes;
|
|
14255
14289
|
try {
|
|
14256
|
-
bytes =
|
|
14290
|
+
bytes = fs11.readFileSync(file, "utf8");
|
|
14257
14291
|
} catch {
|
|
14258
14292
|
return null;
|
|
14259
14293
|
}
|
|
@@ -14271,7 +14305,7 @@ class TaskStore {
|
|
|
14271
14305
|
schemaVersion: SCHEMA_VERSION,
|
|
14272
14306
|
id: workspaceId ?? newId(),
|
|
14273
14307
|
revision: newRevision(),
|
|
14274
|
-
root:
|
|
14308
|
+
root: path14.dirname(v2),
|
|
14275
14309
|
runtime: { createdWith: version, updatedWith: version },
|
|
14276
14310
|
writer: null,
|
|
14277
14311
|
store: {
|
|
@@ -14282,12 +14316,12 @@ class TaskStore {
|
|
|
14282
14316
|
},
|
|
14283
14317
|
critical: ["store"]
|
|
14284
14318
|
};
|
|
14285
|
-
|
|
14286
|
-
const ignore =
|
|
14287
|
-
if (!
|
|
14288
|
-
|
|
14319
|
+
fs11.mkdirSync(v2, { recursive: true });
|
|
14320
|
+
const ignore = path14.join(v2, ".gitignore");
|
|
14321
|
+
if (!fs11.existsSync(ignore))
|
|
14322
|
+
fs11.writeFileSync(ignore, `*
|
|
14289
14323
|
`);
|
|
14290
|
-
replaceFile(
|
|
14324
|
+
replaceFile(path14.join(v2, "workspace.json"), `${JSON.stringify(marker, null, 2)}
|
|
14291
14325
|
`, true);
|
|
14292
14326
|
}
|
|
14293
14327
|
stubFor(taskId) {
|
|
@@ -14303,7 +14337,7 @@ class TaskStore {
|
|
|
14303
14337
|
}
|
|
14304
14338
|
isStub(file) {
|
|
14305
14339
|
try {
|
|
14306
|
-
const value = JSON.parse(
|
|
14340
|
+
const value = JSON.parse(fs11.readFileSync(file, "utf8"));
|
|
14307
14341
|
return isObject6(value) && isObject6(value.store) && value.store.format === "workit-store";
|
|
14308
14342
|
} catch {
|
|
14309
14343
|
return false;
|
|
@@ -14311,32 +14345,32 @@ class TaskStore {
|
|
|
14311
14345
|
}
|
|
14312
14346
|
writeTombstoneIfMissing() {
|
|
14313
14347
|
try {
|
|
14314
|
-
const v2 =
|
|
14315
|
-
if (
|
|
14348
|
+
const v2 = path14.join(this.root, ".workit");
|
|
14349
|
+
if (fs11.existsSync(path14.join(v2, "workspace.json")))
|
|
14316
14350
|
return;
|
|
14317
14351
|
let id = null;
|
|
14318
14352
|
try {
|
|
14319
|
-
id = JSON.parse(
|
|
14353
|
+
id = JSON.parse(fs11.readFileSync(this.paths().workspace, "utf8")).id ?? null;
|
|
14320
14354
|
} catch {}
|
|
14321
14355
|
this.writeTombstone(v2, id);
|
|
14322
14356
|
} catch {}
|
|
14323
14357
|
}
|
|
14324
14358
|
initializeStorage() {
|
|
14325
14359
|
const dirs = this.paths();
|
|
14326
|
-
retryTransient(() =>
|
|
14327
|
-
retryTransient(() =>
|
|
14328
|
-
if (!
|
|
14360
|
+
retryTransient(() => fs11.mkdirSync(dirs.checkout, { recursive: true }));
|
|
14361
|
+
retryTransient(() => fs11.mkdirSync(dirs.tasks, { recursive: true }));
|
|
14362
|
+
if (!fs11.existsSync(dirs.marker))
|
|
14329
14363
|
replaceFile(dirs.marker, `${JSON.stringify({ format: "workit-store", version: STORE_FORMAT, createdWith: runtimeVersion() })}
|
|
14330
14364
|
`, false);
|
|
14331
14365
|
if (!dirs.shared) {
|
|
14332
|
-
const ignore =
|
|
14366
|
+
const ignore = path14.join(dirs.dir, ".gitignore");
|
|
14333
14367
|
let current = null;
|
|
14334
14368
|
try {
|
|
14335
|
-
current =
|
|
14369
|
+
current = fs11.readFileSync(ignore, "utf8");
|
|
14336
14370
|
} catch {}
|
|
14337
14371
|
if (current !== `*
|
|
14338
14372
|
`)
|
|
14339
|
-
retryTransient(() =>
|
|
14373
|
+
retryTransient(() => fs11.writeFileSync(ignore, `*
|
|
14340
14374
|
`));
|
|
14341
14375
|
}
|
|
14342
14376
|
this.writeTombstoneIfMissing();
|
|
@@ -14352,7 +14386,7 @@ class TaskStore {
|
|
|
14352
14386
|
shouldReclaim: ({ payload, nowMs }) => {
|
|
14353
14387
|
let ageMs = null;
|
|
14354
14388
|
try {
|
|
14355
|
-
ageMs = nowMs -
|
|
14389
|
+
ageMs = nowMs - fs11.lstatSync(lockPath).mtimeMs;
|
|
14356
14390
|
} catch {}
|
|
14357
14391
|
return classifyLockOwner(payload, ageMs, localLockHost(), TASK_STORE_LOCK).state === "stale";
|
|
14358
14392
|
},
|
|
@@ -14389,7 +14423,7 @@ class TaskStore {
|
|
|
14389
14423
|
withLock(lockPath, operation) {
|
|
14390
14424
|
try {
|
|
14391
14425
|
this.initializeStorage();
|
|
14392
|
-
|
|
14426
|
+
fs11.mkdirSync(path14.dirname(lockPath), { recursive: true });
|
|
14393
14427
|
} catch (error) {
|
|
14394
14428
|
return failure2("storage_error", `unable to initialize store: ${String(error)}`, {
|
|
14395
14429
|
path: this.paths().dir
|
|
@@ -14429,18 +14463,18 @@ class TaskStore {
|
|
|
14429
14463
|
lockDirWritable(lockPath) {
|
|
14430
14464
|
const probe = `${lockPath}.${process.pid}.${randomUUID3()}.probe`;
|
|
14431
14465
|
try {
|
|
14432
|
-
|
|
14466
|
+
fs11.closeSync(fs11.openSync(probe, "wx", 384));
|
|
14433
14467
|
} catch {
|
|
14434
14468
|
return false;
|
|
14435
14469
|
}
|
|
14436
14470
|
try {
|
|
14437
|
-
|
|
14471
|
+
fs11.rmSync(probe, { force: true });
|
|
14438
14472
|
} catch {}
|
|
14439
14473
|
return true;
|
|
14440
14474
|
}
|
|
14441
14475
|
lockHolderPresent(lockPath) {
|
|
14442
14476
|
try {
|
|
14443
|
-
|
|
14477
|
+
fs11.lstatSync(lockPath);
|
|
14444
14478
|
return true;
|
|
14445
14479
|
} catch (error) {
|
|
14446
14480
|
return error?.code !== "ENOENT";
|
|
@@ -14452,12 +14486,12 @@ class TaskStore {
|
|
|
14452
14486
|
if (isTransientWindowsError(error) && !this.lockHolderPresent(lockPath) && !this.lockDirWritable(lockPath))
|
|
14453
14487
|
return failure2("storage_error", `cannot create the workit lock (${code}); no other Workit call holds it`, {
|
|
14454
14488
|
path: lockPath,
|
|
14455
|
-
guidance: `Check permissions and the read-only attribute on ${
|
|
14489
|
+
guidance: `Check permissions and the read-only attribute on ${path14.dirname(lockPath)}.`
|
|
14456
14490
|
});
|
|
14457
14491
|
if (code === "EEXIST" || code === "file_lock_timeout" || code === "file_lock_stale" || isTransientWindowsError(error)) {
|
|
14458
14492
|
let lock = null;
|
|
14459
14493
|
try {
|
|
14460
|
-
lock = parseMetadataLockOrNull(
|
|
14494
|
+
lock = parseMetadataLockOrNull(fs11.readFileSync(lockPath, "utf8"));
|
|
14461
14495
|
} catch {}
|
|
14462
14496
|
return failure2("busy", `workit lock is held by another Workit call${lock ? ` (pid ${lock.pid} on ${lock.host})` : ""}; retry shortly`, {
|
|
14463
14497
|
outcome: "not_started",
|
|
@@ -14498,7 +14532,7 @@ var MIGRATION_PENDING = "workit migration pending", STORE_FORMAT = 3, STORE_MIN_
|
|
|
14498
14532
|
};
|
|
14499
14533
|
}, fileSignature = (file) => {
|
|
14500
14534
|
try {
|
|
14501
|
-
const stat =
|
|
14535
|
+
const stat = fs11.statSync(file, { bigint: true });
|
|
14502
14536
|
return `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeNs}:${stat.ctimeNs}`;
|
|
14503
14537
|
} catch {
|
|
14504
14538
|
return null;
|
|
@@ -14510,7 +14544,7 @@ var MIGRATION_PENDING = "workit migration pending", STORE_FORMAT = 3, STORE_MIN_
|
|
|
14510
14544
|
}, now = () => new Date().toISOString().replace(/\.\d{3}Z$/, "Z"), oldestFirst = (left, right) => left.createdAt.localeCompare(right.createdAt) || left.id.localeCompare(right.id), cachedRuntimeVersion = null, runtimeVersion = () => {
|
|
14511
14545
|
if (cachedRuntimeVersion === null) {
|
|
14512
14546
|
try {
|
|
14513
|
-
const pkg = JSON.parse(
|
|
14547
|
+
const pkg = JSON.parse(fs11.readFileSync(path14.join(packageRoot(), "package.json"), "utf8"));
|
|
14514
14548
|
cachedRuntimeVersion = typeof pkg.version === "string" && pkg.version ? pkg.version : "0.0.0";
|
|
14515
14549
|
} catch {
|
|
14516
14550
|
cachedRuntimeVersion = "0.0.0";
|
|
@@ -14532,12 +14566,12 @@ var MIGRATION_PENDING = "workit migration pending", STORE_FORMAT = 3, STORE_MIN_
|
|
|
14532
14566
|
return false;
|
|
14533
14567
|
}, 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), readText = (file) => {
|
|
14534
14568
|
try {
|
|
14535
|
-
return
|
|
14569
|
+
return fs11.readFileSync(file, "utf8");
|
|
14536
14570
|
} catch {
|
|
14537
14571
|
return "";
|
|
14538
14572
|
}
|
|
14539
14573
|
}, REFLOG_LINE, branchStart = (location, branch, aliases) => {
|
|
14540
|
-
const first = readText(
|
|
14574
|
+
const first = readText(path14.join(path14.dirname(location.dir), "logs", "refs", "heads", branch)).split(`
|
|
14541
14575
|
`, 1)[0];
|
|
14542
14576
|
const created = REFLOG_LINE.exec(first);
|
|
14543
14577
|
const start = created && /^branch: Created from (\S+)$/u.exec(created[3])?.[1];
|
|
@@ -14547,7 +14581,7 @@ var MIGRATION_PENDING = "workit migration pending", STORE_FORMAT = 3, STORE_MIN_
|
|
|
14547
14581
|
return start;
|
|
14548
14582
|
if (!location.git)
|
|
14549
14583
|
return null;
|
|
14550
|
-
for (const line of readText(
|
|
14584
|
+
for (const line of readText(path14.join(location.git.gitDir, "logs", "HEAD")).split(`
|
|
14551
14585
|
`)) {
|
|
14552
14586
|
const entry = REFLOG_LINE.exec(line);
|
|
14553
14587
|
const moved = entry && /^checkout: moving from (\S+) to (\S+)$/u.exec(entry[3]);
|
|
@@ -14556,21 +14590,21 @@ var MIGRATION_PENDING = "workit migration pending", STORE_FORMAT = 3, STORE_MIN_
|
|
|
14556
14590
|
return moved[1];
|
|
14557
14591
|
}
|
|
14558
14592
|
return null;
|
|
14559
|
-
}, refExists = (common, ref) =>
|
|
14593
|
+
}, refExists = (common, ref) => fs11.existsSync(path14.join(common, ref)) || readText(path14.join(common, "packed-refs")).includes(` ${ref}
|
|
14560
14594
|
`), origins, sameDirectoryIdentity = (left, right) => {
|
|
14561
|
-
if (!
|
|
14595
|
+
if (!path14.isAbsolute(left) || !path14.isAbsolute(right))
|
|
14562
14596
|
return false;
|
|
14563
|
-
const normalizedLeft =
|
|
14564
|
-
const normalizedRight =
|
|
14597
|
+
const normalizedLeft = path14.resolve(left);
|
|
14598
|
+
const normalizedRight = path14.resolve(right);
|
|
14565
14599
|
try {
|
|
14566
|
-
const a =
|
|
14567
|
-
const b =
|
|
14600
|
+
const a = fs11.statSync(normalizedLeft, { bigint: true });
|
|
14601
|
+
const b = fs11.statSync(normalizedRight, { bigint: true });
|
|
14568
14602
|
if (!a.isDirectory() || !b.isDirectory())
|
|
14569
14603
|
return false;
|
|
14570
14604
|
if (process.platform === "win32" ? normalizedLeft.toLowerCase() === normalizedRight.toLowerCase() : normalizedLeft === normalizedRight)
|
|
14571
14605
|
return true;
|
|
14572
|
-
const canonicalLeft =
|
|
14573
|
-
const canonicalRight =
|
|
14606
|
+
const canonicalLeft = fs11.realpathSync(normalizedLeft);
|
|
14607
|
+
const canonicalRight = fs11.realpathSync(normalizedRight);
|
|
14574
14608
|
if (process.platform === "win32" ? canonicalLeft.toLowerCase() === canonicalRight.toLowerCase() : canonicalLeft === canonicalRight)
|
|
14575
14609
|
return true;
|
|
14576
14610
|
return a.dev === b.dev && a.ino !== 0n && a.ino === b.ino;
|
|
@@ -14618,8 +14652,8 @@ var init_workers = __esm(() => {
|
|
|
14618
14652
|
|
|
14619
14653
|
// packages/workit-core/src/check-config.ts
|
|
14620
14654
|
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
14621
|
-
import
|
|
14622
|
-
import
|
|
14655
|
+
import fs12 from "node:fs";
|
|
14656
|
+
import path15 from "node:path";
|
|
14623
14657
|
function splitCommand(command) {
|
|
14624
14658
|
const argv = [];
|
|
14625
14659
|
let current = "";
|
|
@@ -14657,12 +14691,12 @@ function splitCommand(command) {
|
|
|
14657
14691
|
return argv.length ? argv : new Error("empty command");
|
|
14658
14692
|
}
|
|
14659
14693
|
function checkRoot(cwd) {
|
|
14660
|
-
return
|
|
14694
|
+
return path15.resolve(git4(cwd, ["rev-parse", "--show-toplevel"]) ?? cwd);
|
|
14661
14695
|
}
|
|
14662
14696
|
function detectedChecks(root) {
|
|
14663
14697
|
const read = (file) => {
|
|
14664
14698
|
try {
|
|
14665
|
-
return
|
|
14699
|
+
return fs12.readFileSync(path15.join(root, file), "utf8");
|
|
14666
14700
|
} catch {
|
|
14667
14701
|
return null;
|
|
14668
14702
|
}
|
|
@@ -14700,7 +14734,7 @@ function detectedChecks(root) {
|
|
|
14700
14734
|
}
|
|
14701
14735
|
function loadCheckConfig(cwd) {
|
|
14702
14736
|
const root = checkRoot(cwd);
|
|
14703
|
-
const file =
|
|
14737
|
+
const file = path15.join(root, CHECKS_FILE);
|
|
14704
14738
|
const none = (error = null) => ({
|
|
14705
14739
|
source: error ? CHECKS_FILE : "none",
|
|
14706
14740
|
root,
|
|
@@ -14710,7 +14744,7 @@ function loadCheckConfig(cwd) {
|
|
|
14710
14744
|
});
|
|
14711
14745
|
let text = null;
|
|
14712
14746
|
try {
|
|
14713
|
-
text =
|
|
14747
|
+
text = fs12.readFileSync(file, "utf8");
|
|
14714
14748
|
} catch (error) {
|
|
14715
14749
|
if (error.code !== "ENOENT")
|
|
14716
14750
|
return none(`cannot read ${CHECKS_FILE}: ${error.message}`);
|
|
@@ -14771,10 +14805,10 @@ function workitAvailable(env = process.env) {
|
|
|
14771
14805
|
return workitOnPath;
|
|
14772
14806
|
const windows = process.platform === "win32";
|
|
14773
14807
|
const exts = windows ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
|
|
14774
|
-
const dirs = (env.PATH ?? env.Path ?? "").split(
|
|
14808
|
+
const dirs = (env.PATH ?? env.Path ?? "").split(path15.delimiter).filter(Boolean);
|
|
14775
14809
|
workitOnPath = dirs.some((dir) => exts.some((ext) => {
|
|
14776
14810
|
try {
|
|
14777
|
-
return
|
|
14811
|
+
return fs12.statSync(path15.join(dir, `workit${ext}`)).isFile();
|
|
14778
14812
|
} catch {
|
|
14779
14813
|
return false;
|
|
14780
14814
|
}
|
|
@@ -14795,7 +14829,7 @@ var SCRIPT_CHECKS, CHECKS_FILE = "workit.checks.json", isRecord3 = (value) => ty
|
|
|
14795
14829
|
const value = run.status === 0 ? (run.stdout ?? "").trim() : "";
|
|
14796
14830
|
return value || null;
|
|
14797
14831
|
}, packageManager = (root) => {
|
|
14798
|
-
const has = (file) =>
|
|
14832
|
+
const has = (file) => fs12.existsSync(path15.join(root, file));
|
|
14799
14833
|
if (has("bun.lock") || has("bun.lockb"))
|
|
14800
14834
|
return "bun";
|
|
14801
14835
|
if (has("pnpm-lock.yaml"))
|
|
@@ -14818,14 +14852,14 @@ var init_check_config = __esm(() => {
|
|
|
14818
14852
|
});
|
|
14819
14853
|
|
|
14820
14854
|
// packages/workit-core/src/core/task-evaluation.ts
|
|
14821
|
-
import { createHash as
|
|
14822
|
-
import * as
|
|
14855
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
14856
|
+
import * as fs13 from "node:fs";
|
|
14823
14857
|
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
14824
|
-
import
|
|
14858
|
+
import path16 from "node:path";
|
|
14825
14859
|
function captureCandidate(root, scope, environment = []) {
|
|
14826
14860
|
let checkout;
|
|
14827
14861
|
try {
|
|
14828
|
-
checkout =
|
|
14862
|
+
checkout = fs13.realpathSync(root);
|
|
14829
14863
|
} catch {
|
|
14830
14864
|
return failure2("invalid_input", "candidate root does not exist");
|
|
14831
14865
|
}
|
|
@@ -14843,11 +14877,11 @@ function captureCandidate(root, scope, environment = []) {
|
|
|
14843
14877
|
if (item === ".git" || item === ".workit")
|
|
14844
14878
|
continue;
|
|
14845
14879
|
names.add(item);
|
|
14846
|
-
if (!
|
|
14880
|
+
if (!fs13.existsSync(target))
|
|
14847
14881
|
continue;
|
|
14848
14882
|
let stat;
|
|
14849
14883
|
try {
|
|
14850
|
-
stat =
|
|
14884
|
+
stat = fs13.lstatSync(target);
|
|
14851
14885
|
} catch {
|
|
14852
14886
|
uncertain = true;
|
|
14853
14887
|
continue;
|
|
@@ -14863,17 +14897,17 @@ function captureCandidate(root, scope, environment = []) {
|
|
|
14863
14897
|
for (const item of [...names].toSorted()) {
|
|
14864
14898
|
if (!scopeMatches(item, normalizedScope))
|
|
14865
14899
|
continue;
|
|
14866
|
-
const target =
|
|
14900
|
+
const target = path16.join(checkout, item);
|
|
14867
14901
|
try {
|
|
14868
|
-
const stat =
|
|
14902
|
+
const stat = fs13.lstatSync(target);
|
|
14869
14903
|
if (stat.isSymbolicLink()) {
|
|
14870
|
-
const link =
|
|
14904
|
+
const link = fs13.readlinkSync(target);
|
|
14871
14905
|
files.push({ path: item, kind: "symlink", digest: digestBytes(link), executable: null });
|
|
14872
14906
|
} else if (stat.isFile()) {
|
|
14873
14907
|
files.push({
|
|
14874
14908
|
path: item,
|
|
14875
14909
|
kind: "file",
|
|
14876
|
-
digest: digestBytes(
|
|
14910
|
+
digest: digestBytes(fs13.readFileSync(target)),
|
|
14877
14911
|
executable: (stat.mode & 73) !== 0
|
|
14878
14912
|
});
|
|
14879
14913
|
} else if (!stat.isDirectory()) {
|
|
@@ -15236,12 +15270,12 @@ function evaluateClosure(requestedOutcome, view) {
|
|
|
15236
15270
|
requirementIds: evaluations.map((item) => item.requirementId)
|
|
15237
15271
|
});
|
|
15238
15272
|
}
|
|
15239
|
-
var digestBytes = (value) =>
|
|
15273
|
+
var digestBytes = (value) => createHash10("sha256").update(value).digest("hex"), inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path16.sep}`), relative = (root, candidate) => path16.relative(root, candidate).split(path16.sep).join("/") || ".", canonicalPath = (value) => {
|
|
15240
15274
|
if (typeof value !== "string" || !value)
|
|
15241
15275
|
return null;
|
|
15242
15276
|
if (value.includes("\\") || value.split("/").includes(".."))
|
|
15243
15277
|
return null;
|
|
15244
|
-
const normalized =
|
|
15278
|
+
const normalized = path16.posix.normalize(value);
|
|
15245
15279
|
if (normalized === ".." || normalized.startsWith("../") || normalized.startsWith("/"))
|
|
15246
15280
|
return null;
|
|
15247
15281
|
return normalized === "." ? "." : normalized.replace(/\/$/, "");
|
|
@@ -15283,20 +15317,20 @@ var digestBytes = (value) => createHash9("sha256").update(value).digest("hex"),
|
|
|
15283
15317
|
git: !/not a git repository/i.test(stderr)
|
|
15284
15318
|
};
|
|
15285
15319
|
}
|
|
15286
|
-
const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(
|
|
15320
|
+
const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path16.sep).join("/")) : [];
|
|
15287
15321
|
const stagedDeleted = spawnSync10("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
|
|
15288
15322
|
if (stagedDeleted.status !== 0) {
|
|
15289
15323
|
const stderr = stagedDeleted.stderr?.toString("utf8") ?? "";
|
|
15290
15324
|
if (!/not a git repository/i.test(stderr))
|
|
15291
15325
|
return { paths, uncertain: true, git: true };
|
|
15292
15326
|
} else if (stagedDeleted.stdout) {
|
|
15293
|
-
paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(
|
|
15327
|
+
paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path16.sep).join("/")));
|
|
15294
15328
|
}
|
|
15295
15329
|
return { paths: [...new Set(paths)], uncertain: false, git: true };
|
|
15296
15330
|
}, walk = (root, directory, output) => {
|
|
15297
15331
|
let names;
|
|
15298
15332
|
try {
|
|
15299
|
-
names =
|
|
15333
|
+
names = fs13.readdirSync(directory);
|
|
15300
15334
|
} catch {
|
|
15301
15335
|
return true;
|
|
15302
15336
|
}
|
|
@@ -15304,10 +15338,10 @@ var digestBytes = (value) => createHash9("sha256").update(value).digest("hex"),
|
|
|
15304
15338
|
for (const name of names) {
|
|
15305
15339
|
if (name === ".git" || name === ".workit")
|
|
15306
15340
|
continue;
|
|
15307
|
-
const target =
|
|
15341
|
+
const target = path16.join(directory, name);
|
|
15308
15342
|
let stat;
|
|
15309
15343
|
try {
|
|
15310
|
-
stat =
|
|
15344
|
+
stat = fs13.lstatSync(target);
|
|
15311
15345
|
} catch {
|
|
15312
15346
|
uncertain = true;
|
|
15313
15347
|
continue;
|
|
@@ -15321,14 +15355,14 @@ var digestBytes = (value) => createHash9("sha256").update(value).digest("hex"),
|
|
|
15321
15355
|
}, scopeRoots = (root, scope) => {
|
|
15322
15356
|
const roots = [];
|
|
15323
15357
|
for (const item of scope.paths.length ? scope.paths : ["."]) {
|
|
15324
|
-
const target =
|
|
15358
|
+
const target = path16.resolve(root, item);
|
|
15325
15359
|
if (!inside(root, target))
|
|
15326
15360
|
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` }] });
|
|
15327
15361
|
let ancestor = target;
|
|
15328
|
-
while (!
|
|
15329
|
-
ancestor =
|
|
15362
|
+
while (!fs13.existsSync(ancestor) && ancestor !== root)
|
|
15363
|
+
ancestor = path16.dirname(ancestor);
|
|
15330
15364
|
try {
|
|
15331
|
-
if (!inside(root,
|
|
15365
|
+
if (!inside(root, fs13.realpathSync(ancestor)))
|
|
15332
15366
|
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` }] });
|
|
15333
15367
|
} catch {
|
|
15334
15368
|
return failure2("invalid_input", `candidate scope cannot be inspected: ${item}`);
|
|
@@ -15381,7 +15415,7 @@ var digestBytes = (value) => createHash9("sha256").update(value).digest("hex"),
|
|
|
15381
15415
|
}, findingVerificationPasses = (findingCandidateId, evidence) => evidence.status === "passed" && (evidence.kind === "check" || evidence.kind === "review") && ((findingCandidateId ?? null) === null || evidence.candidateId != null), verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
15382
15416
|
let root;
|
|
15383
15417
|
try {
|
|
15384
|
-
root =
|
|
15418
|
+
root = fs13.realpathSync(checkoutRoot);
|
|
15385
15419
|
} catch {
|
|
15386
15420
|
return failure2("permission_denied", "checkout root is unavailable");
|
|
15387
15421
|
}
|
|
@@ -15390,23 +15424,23 @@ var digestBytes = (value) => createHash9("sha256").update(value).digest("hex"),
|
|
|
15390
15424
|
continue;
|
|
15391
15425
|
if (!reference.digest)
|
|
15392
15426
|
return failure2("invalid_input", "document references require a byte digest");
|
|
15393
|
-
const target =
|
|
15394
|
-
if (target !== root && !target.startsWith(`${root}${
|
|
15427
|
+
const target = path16.resolve(root, reference.path);
|
|
15428
|
+
if (target !== root && !target.startsWith(`${root}${path16.sep}`))
|
|
15395
15429
|
return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
|
|
15396
15430
|
fields: [
|
|
15397
15431
|
{ path: "contentRefs.path", reason: `${reference.path} is outside the checkout` }
|
|
15398
15432
|
]
|
|
15399
15433
|
});
|
|
15400
15434
|
try {
|
|
15401
|
-
const below =
|
|
15435
|
+
const below = path16.relative(root, target);
|
|
15402
15436
|
let current = root;
|
|
15403
|
-
for (const segment of below.split(
|
|
15437
|
+
for (const segment of below.split(path16.sep)) {
|
|
15404
15438
|
if (!segment)
|
|
15405
15439
|
continue;
|
|
15406
|
-
current =
|
|
15407
|
-
const stat =
|
|
15408
|
-
const real =
|
|
15409
|
-
if (real !== root && !real.startsWith(`${root}${
|
|
15440
|
+
current = path16.join(current, segment);
|
|
15441
|
+
const stat = fs13.lstatSync(current);
|
|
15442
|
+
const real = fs13.realpathSync(current);
|
|
15443
|
+
if (real !== root && !real.startsWith(`${root}${path16.sep}`))
|
|
15410
15444
|
return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
|
|
15411
15445
|
fields: [
|
|
15412
15446
|
{
|
|
@@ -15422,7 +15456,7 @@ var digestBytes = (value) => createHash9("sha256").update(value).digest("hex"),
|
|
|
15422
15456
|
if (current !== target && !stat.isDirectory())
|
|
15423
15457
|
return failure2("invalid_input", "document reference ancestor is not a directory");
|
|
15424
15458
|
}
|
|
15425
|
-
if (digestBytes(
|
|
15459
|
+
if (digestBytes(fs13.readFileSync(target)) !== reference.digest)
|
|
15426
15460
|
return failure2("permission_denied", "decision document bytes have changed");
|
|
15427
15461
|
} catch {
|
|
15428
15462
|
return failure2("invalid_input", "decision document is unavailable");
|
|
@@ -15526,7 +15560,8 @@ Autonomy contract:
|
|
|
15526
15560
|
satisfies a gate; an ad-hoc \`workit check -- <cmd>\` never does.
|
|
15527
15561
|
- Author is not verifier: your own verdict is \`--self\`, shown as
|
|
15528
15562
|
self-reviewed, never verified. High risk, \`verification: independent\` and
|
|
15529
|
-
merge need a verifier with its own session (
|
|
15563
|
+
merge need a verifier with its own host-derived session (a subagent's
|
|
15564
|
+
\`<lead>:<child>\`, set by the host); never hand-mint one such as \`<lead>-v1\`.
|
|
15530
15565
|
- A local-commit endpoint does not imply PR readiness, and a local commit alone
|
|
15531
15566
|
is not evidence of a requested remote push. Before reporting delivery,
|
|
15532
15567
|
reconcile every requested item and observe it (\`workit verify-delivery\`).
|
|
@@ -17361,9 +17396,9 @@ var support = (descriptor, axis) => {
|
|
|
17361
17396
|
});
|
|
17362
17397
|
|
|
17363
17398
|
// packages/workit-core/src/hooks/context.ts
|
|
17364
|
-
import { createHash as
|
|
17365
|
-
import
|
|
17366
|
-
import
|
|
17399
|
+
import { createHash as createHash11 } from "node:crypto";
|
|
17400
|
+
import fs14 from "node:fs";
|
|
17401
|
+
import path17 from "node:path";
|
|
17367
17402
|
function sessionCompactContext(store, session, context, selection = "session-bound") {
|
|
17368
17403
|
const listed = store.listTaskIndex();
|
|
17369
17404
|
if (!listed.ok)
|
|
@@ -17398,7 +17433,7 @@ function entryCompactContext(store, entry, session, context) {
|
|
|
17398
17433
|
return null;
|
|
17399
17434
|
const freshness = { mode: "signal", current: () => recentSignal(store.root) };
|
|
17400
17435
|
const observed = task?.data.evidence.some(isObservedCheck) ?? false;
|
|
17401
|
-
const files = (task?.data.decisions ?? []).flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [
|
|
17436
|
+
const files = (task?.data.decisions ?? []).flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [path17.resolve(store.root, ref.path)] : []));
|
|
17402
17437
|
const observedFiles = filesKey(files);
|
|
17403
17438
|
const compact = new WorkitCore(store, context).compactContext(entry?.id ?? null, freshness, origin && { origin: origin.origin, taskId: origin.entry.id });
|
|
17404
17439
|
if (!compact.ok || !compact.data)
|
|
@@ -17496,7 +17531,7 @@ ${options.addendum}` : ""}
|
|
|
17496
17531
|
} catch {
|
|
17497
17532
|
return null;
|
|
17498
17533
|
}
|
|
17499
|
-
}, TURN_TTL_MS, digestOf = (text) =>
|
|
17534
|
+
}, TURN_TTL_MS, digestOf = (text) => createHash11("sha256").update(text).digest("hex"), turnMarker = (input) => {
|
|
17500
17535
|
if (!input.session.id)
|
|
17501
17536
|
return null;
|
|
17502
17537
|
try {
|
|
@@ -17504,29 +17539,29 @@ ${options.addendum}` : ""}
|
|
|
17504
17539
|
if (location instanceof Error)
|
|
17505
17540
|
return null;
|
|
17506
17541
|
const session = [input.host, input.session.id, input.session.agentId ?? ""].join("\x00");
|
|
17507
|
-
return
|
|
17542
|
+
return path17.join(location.dir, "hooks", `turn-${digestOf(session).slice(0, 32)}.json`);
|
|
17508
17543
|
} catch {
|
|
17509
17544
|
return null;
|
|
17510
17545
|
}
|
|
17511
17546
|
}, writeTurnDigest = (file, digest) => {
|
|
17512
17547
|
try {
|
|
17513
|
-
|
|
17514
|
-
|
|
17548
|
+
fs14.mkdirSync(path17.dirname(file), { recursive: true });
|
|
17549
|
+
fs14.writeFileSync(file, `${JSON.stringify({ digest })}
|
|
17515
17550
|
`);
|
|
17516
17551
|
} catch {}
|
|
17517
17552
|
}, clearTurnDigest = (file) => {
|
|
17518
17553
|
try {
|
|
17519
|
-
|
|
17554
|
+
fs14.rmSync(file, { force: true });
|
|
17520
17555
|
} catch {}
|
|
17521
17556
|
}, pruneTurnDigests = (dir, now) => {
|
|
17522
17557
|
try {
|
|
17523
|
-
for (const name of
|
|
17558
|
+
for (const name of fs14.readdirSync(dir)) {
|
|
17524
17559
|
if (!name.startsWith("turn-"))
|
|
17525
17560
|
continue;
|
|
17526
|
-
const file =
|
|
17561
|
+
const file = path17.join(dir, name);
|
|
17527
17562
|
try {
|
|
17528
|
-
if (now -
|
|
17529
|
-
|
|
17563
|
+
if (now - fs14.statSync(file).mtimeMs > TURN_TTL_MS)
|
|
17564
|
+
fs14.rmSync(file, { force: true });
|
|
17530
17565
|
} catch {}
|
|
17531
17566
|
}
|
|
17532
17567
|
} catch {}
|
|
@@ -17541,7 +17576,7 @@ ${options.addendum}` : ""}
|
|
|
17541
17576
|
return text;
|
|
17542
17577
|
const digest = digestOf(text);
|
|
17543
17578
|
try {
|
|
17544
|
-
const previous = JSON.parse(
|
|
17579
|
+
const previous = JSON.parse(fs14.readFileSync(file, "utf8"));
|
|
17545
17580
|
if (previous.digest === digest)
|
|
17546
17581
|
return null;
|
|
17547
17582
|
} catch {}
|
|
@@ -17551,7 +17586,7 @@ ${options.addendum}` : ""}
|
|
|
17551
17586
|
const file = turnMarker(input);
|
|
17552
17587
|
if (!file)
|
|
17553
17588
|
return;
|
|
17554
|
-
pruneTurnDigests(
|
|
17589
|
+
pruneTurnDigests(path17.dirname(file), Date.now());
|
|
17555
17590
|
if (text)
|
|
17556
17591
|
writeTurnDigest(file, digestOf(text));
|
|
17557
17592
|
else
|
|
@@ -17577,7 +17612,7 @@ var init_commit_flavors = () => {};
|
|
|
17577
17612
|
var init_git = () => {};
|
|
17578
17613
|
|
|
17579
17614
|
// packages/workit-core/src/core/branch.ts
|
|
17580
|
-
import { createHash as
|
|
17615
|
+
import { createHash as createHash12 } from "node:crypto";
|
|
17581
17616
|
function effectiveWorkspacePolicy(workspaceRoot, kind, profileName) {
|
|
17582
17617
|
const selected = resolveRuntimeWorkspacePolicy(workspaceRoot, kind, profileName?.trim() || process.env.WORKFLOW_PROFILE?.trim() || undefined);
|
|
17583
17618
|
const config = readConfig();
|
|
@@ -17643,7 +17678,7 @@ var withReleaseTracks = (workspaceRoot, policy) => {
|
|
|
17643
17678
|
const source = resolved.provenance.branchPolicy;
|
|
17644
17679
|
const allowed = branchPolicy.allowed.map((pattern) => `${pattern.source}/${pattern.flags}`).toSorted();
|
|
17645
17680
|
const protectedRefs = [...branchPolicy.protected].map((name) => name.toLowerCase()).toSorted();
|
|
17646
|
-
const fingerprint =
|
|
17681
|
+
const fingerprint = createHash12("sha256").update(JSON.stringify({ allowed, protectedRefs, source })).digest("hex");
|
|
17647
17682
|
return {
|
|
17648
17683
|
branchPolicy,
|
|
17649
17684
|
namePolicy: { allowed: branchPolicy.allowed, protected: branchPolicy.protected },
|
|
@@ -17826,7 +17861,7 @@ var closingQuote = (command, start, dialect) => {
|
|
|
17826
17861
|
|
|
17827
17862
|
// packages/workit-core/src/hooks/write-gate.ts
|
|
17828
17863
|
import { realpathSync as realpathSync5 } from "node:fs";
|
|
17829
|
-
import
|
|
17864
|
+
import path18 from "node:path";
|
|
17830
17865
|
function writeGate(cwd, paths) {
|
|
17831
17866
|
try {
|
|
17832
17867
|
const gate = gateFor(cwd);
|
|
@@ -17846,21 +17881,21 @@ function writeGate(cwd, paths) {
|
|
|
17846
17881
|
}
|
|
17847
17882
|
var NONE2, CASE_INSENSITIVE, canonical2 = (file) => {
|
|
17848
17883
|
let rest = "";
|
|
17849
|
-
for (let dir =
|
|
17884
|
+
for (let dir = path18.resolve(file);; dir = path18.dirname(dir)) {
|
|
17850
17885
|
try {
|
|
17851
|
-
return
|
|
17886
|
+
return path18.join(realpathSync5(dir), rest);
|
|
17852
17887
|
} catch {
|
|
17853
|
-
if (
|
|
17854
|
-
return
|
|
17855
|
-
rest = rest ?
|
|
17888
|
+
if (path18.dirname(dir) === dir)
|
|
17889
|
+
return path18.resolve(file);
|
|
17890
|
+
rest = rest ? path18.join(path18.basename(dir), rest) : path18.basename(dir);
|
|
17856
17891
|
}
|
|
17857
17892
|
}
|
|
17858
17893
|
}, exempt = (cwd, root, file, plans) => {
|
|
17859
17894
|
const fold = (value) => CASE_INSENSITIVE ? value.toLowerCase() : value;
|
|
17860
|
-
const relative =
|
|
17861
|
-
if (relative.startsWith("..") ||
|
|
17895
|
+
const relative = path18.relative(fold(canonical2(root)), fold(canonical2(path18.resolve(cwd, file))));
|
|
17896
|
+
if (relative.startsWith("..") || path18.isAbsolute(relative))
|
|
17862
17897
|
return true;
|
|
17863
|
-
const posix = relative.split(
|
|
17898
|
+
const posix = relative.split(path18.sep).join("/");
|
|
17864
17899
|
const segments = posix.split("/");
|
|
17865
17900
|
return /\.mdx?$/i.test(posix) || segments[0] === "docs" || segments.includes("plans") || [...plans].some((plan) => fold(plan) === posix);
|
|
17866
17901
|
}, PREFIXES2, operands = (words) => words.filter((item) => !item.startsWith("-")), editsOf = (input) => {
|
|
@@ -17952,7 +17987,7 @@ var NONE2, CASE_INSENSITIVE, canonical2 = (file) => {
|
|
|
17952
17987
|
if (!unknown && targets.length === 0)
|
|
17953
17988
|
return { writes: false, targets: null };
|
|
17954
17989
|
return { writes: true, targets: unknown ? null : targets };
|
|
17955
|
-
}, cache2, planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(
|
|
17990
|
+
}, cache2, planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(path18.resolve(root, file)) ?? "-").join("\x00"), gateFor = (cwd) => {
|
|
17956
17991
|
const store = new TaskStore(cwd);
|
|
17957
17992
|
const listed = store.listTaskIndex();
|
|
17958
17993
|
if (!listed.ok)
|
|
@@ -18001,9 +18036,9 @@ var init_write_gate = __esm(() => {
|
|
|
18001
18036
|
});
|
|
18002
18037
|
|
|
18003
18038
|
// packages/workit-core/src/hooks/session-marker.ts
|
|
18004
|
-
import { createHash as
|
|
18005
|
-
import
|
|
18006
|
-
import
|
|
18039
|
+
import { createHash as createHash13 } from "node:crypto";
|
|
18040
|
+
import fs15 from "node:fs";
|
|
18041
|
+
import path19 from "node:path";
|
|
18007
18042
|
var sessionMarkerFile = (input, session, store) => {
|
|
18008
18043
|
let dir = store;
|
|
18009
18044
|
if (dir === undefined) {
|
|
@@ -18012,19 +18047,19 @@ var sessionMarkerFile = (input, session, store) => {
|
|
|
18012
18047
|
return null;
|
|
18013
18048
|
dir = location.dir;
|
|
18014
18049
|
}
|
|
18015
|
-
const name =
|
|
18016
|
-
return
|
|
18050
|
+
const name = createHash13("sha256").update(`${input.host}\x00${session}`).digest("hex").slice(0, 32);
|
|
18051
|
+
return path19.join(dir, "hooks", `skills-${name}.json`);
|
|
18017
18052
|
}, list2 = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [], readSessionMarker = (file) => {
|
|
18018
18053
|
try {
|
|
18019
|
-
const value = JSON.parse(
|
|
18054
|
+
const value = JSON.parse(fs15.readFileSync(file, "utf8"));
|
|
18020
18055
|
return { nudged: list2(value.nudged), loaded: list2(value.loaded), raw: list2(value.raw) };
|
|
18021
18056
|
} catch {
|
|
18022
18057
|
return { nudged: [], loaded: [], raw: [] };
|
|
18023
18058
|
}
|
|
18024
18059
|
}, writeSessionMarker = (file, marker) => {
|
|
18025
18060
|
try {
|
|
18026
|
-
|
|
18027
|
-
|
|
18061
|
+
fs15.mkdirSync(path19.dirname(file), { recursive: true });
|
|
18062
|
+
fs15.writeFileSync(file, JSON.stringify(marker));
|
|
18028
18063
|
} catch {}
|
|
18029
18064
|
};
|
|
18030
18065
|
var init_session_marker = __esm(() => {
|
|
@@ -18033,10 +18068,10 @@ var init_session_marker = __esm(() => {
|
|
|
18033
18068
|
|
|
18034
18069
|
// packages/workit-core/src/hooks/raw-git.ts
|
|
18035
18070
|
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
18036
|
-
import { createHash as
|
|
18037
|
-
import
|
|
18071
|
+
import { createHash as createHash14 } from "node:crypto";
|
|
18072
|
+
import fs16 from "node:fs";
|
|
18038
18073
|
import os4 from "node:os";
|
|
18039
|
-
import
|
|
18074
|
+
import path20 from "node:path";
|
|
18040
18075
|
function rawInvocations(command, dialect = "posix", depth = 0) {
|
|
18041
18076
|
const found = [];
|
|
18042
18077
|
let dir = null;
|
|
@@ -18184,8 +18219,8 @@ function noteRawCommit(input, command, key) {
|
|
|
18184
18219
|
if (action.kind !== "commit")
|
|
18185
18220
|
continue;
|
|
18186
18221
|
const file = markerFile(repo, input.session.id, key);
|
|
18187
|
-
|
|
18188
|
-
|
|
18222
|
+
fs16.mkdirSync(path20.dirname(file), { recursive: true });
|
|
18223
|
+
fs16.writeFileSync(file, `${JSON.stringify({ head: headSha2(repo), at })}
|
|
18189
18224
|
`);
|
|
18190
18225
|
}
|
|
18191
18226
|
} catch {}
|
|
@@ -18207,15 +18242,15 @@ function settlePendingCommit(input) {
|
|
|
18207
18242
|
if (!repo)
|
|
18208
18243
|
return;
|
|
18209
18244
|
const file = markerFile(repo, input.session.id, NEXT_COMMAND);
|
|
18210
|
-
if (
|
|
18245
|
+
if (fs16.existsSync(file))
|
|
18211
18246
|
settle2(input, repo, file);
|
|
18212
18247
|
} catch {}
|
|
18213
18248
|
}
|
|
18214
|
-
var NONE3, SHELLS, PREFIXES3, SCRIPT_FLAG, CD, PUSHD, POPD, GIT_VALUE_OPTIONS, isAbsolute = (value) =>
|
|
18249
|
+
var NONE3, SHELLS, PREFIXES3, SCRIPT_FLAG, CD, PUSHD, POPD, GIT_VALUE_OPTIONS, isAbsolute = (value) => path20.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\"), joinDir = (base, next) => {
|
|
18215
18250
|
if (base === undefined || /[$`*?]/.test(next) || next === "-")
|
|
18216
18251
|
return;
|
|
18217
|
-
const expanded = next === "~" || next.startsWith("~/") ?
|
|
18218
|
-
return base === null || isAbsolute(expanded) ? expanded :
|
|
18252
|
+
const expanded = next === "~" || next.startsWith("~/") ? path20.join(os4.homedir(), next.slice(1)) : next;
|
|
18253
|
+
return base === null || isAbsolute(expanded) ? expanded : path20.join(base, expanded);
|
|
18219
18254
|
}, cdTarget = (words) => {
|
|
18220
18255
|
const args = words.slice(1);
|
|
18221
18256
|
const flag = args.findIndex((word) => /^-(?:literal)?path$/i.test(word));
|
|
@@ -18313,7 +18348,7 @@ var NONE3, SHELLS, PREFIXES3, SCRIPT_FLAG, CD, PUSHD, POPD, GIT_VALUE_OPTIONS, i
|
|
|
18313
18348
|
return null;
|
|
18314
18349
|
return { location, dir, branch: resolveTaskKey(dir, location).branch };
|
|
18315
18350
|
}, isWorkitWorkspace = (repo) => {
|
|
18316
|
-
if (
|
|
18351
|
+
if (fs16.existsSync(repo.location.dir))
|
|
18317
18352
|
return true;
|
|
18318
18353
|
try {
|
|
18319
18354
|
return resolveRuntimeWorkspaceVcs(repo.location.top ?? repo.dir) !== null;
|
|
@@ -18341,17 +18376,17 @@ var NONE3, SHELLS, PREFIXES3, SCRIPT_FLAG, CD, PUSHD, POPD, GIT_VALUE_OPTIONS, i
|
|
|
18341
18376
|
if (!git || git.reftable)
|
|
18342
18377
|
return null;
|
|
18343
18378
|
try {
|
|
18344
|
-
const head =
|
|
18379
|
+
const head = fs16.readFileSync(path20.join(git.gitDir, "HEAD"), "utf8").trim();
|
|
18345
18380
|
if (/^[0-9a-f]{40,64}$/.test(head))
|
|
18346
18381
|
return head;
|
|
18347
18382
|
const ref = /^ref: (refs\/.+)$/.exec(head)?.[1];
|
|
18348
18383
|
if (!ref)
|
|
18349
18384
|
return null;
|
|
18350
|
-
const common =
|
|
18385
|
+
const common = path20.dirname(repo.location.dir);
|
|
18351
18386
|
try {
|
|
18352
|
-
return
|
|
18387
|
+
return fs16.readFileSync(path20.join(common, ref), "utf8").trim() || null;
|
|
18353
18388
|
} catch {}
|
|
18354
|
-
const packed =
|
|
18389
|
+
const packed = fs16.readFileSync(path20.join(common, "packed-refs"), "utf8");
|
|
18355
18390
|
return new RegExp(`^([0-9a-f]{40,64}) ${ref.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`, "m").exec(packed)?.[1] ?? null;
|
|
18356
18391
|
} catch {
|
|
18357
18392
|
return null;
|
|
@@ -18384,7 +18419,7 @@ var NONE3, SHELLS, PREFIXES3, SCRIPT_FLAG, CD, PUSHD, POPD, GIT_VALUE_OPTIONS, i
|
|
|
18384
18419
|
const action = rawAction(invocation);
|
|
18385
18420
|
if (!action)
|
|
18386
18421
|
continue;
|
|
18387
|
-
const dir =
|
|
18422
|
+
const dir = path20.resolve(cwd, invocation.dir ?? ".");
|
|
18388
18423
|
if (!repos.has(dir)) {
|
|
18389
18424
|
const repo = repoAt(dir);
|
|
18390
18425
|
repos.set(dir, repo && isWorkitWorkspace(repo) ? repo : null);
|
|
@@ -18411,7 +18446,7 @@ var NONE3, SHELLS, PREFIXES3, SCRIPT_FLAG, CD, PUSHD, POPD, GIT_VALUE_OPTIONS, i
|
|
|
18411
18446
|
raw: [...marker.raw, ...fresh.map((kind) => agent + kind)]
|
|
18412
18447
|
});
|
|
18413
18448
|
return fresh.map((kind) => nudges.get(kind));
|
|
18414
|
-
}, deny = (reason) => ({ kind: "deny", reason, unblock: null }), NEXT_COMMAND = "next", MARKER_TTL_SECONDS = 3600, markerFile = (repo, session, key) =>
|
|
18449
|
+
}, deny = (reason) => ({ kind: "deny", reason, unblock: null }), NEXT_COMMAND = "next", MARKER_TTL_SECONDS = 3600, markerFile = (repo, session, key) => path20.join(repo.location.dir, "hooks", `commit-${createHash14("sha256").update(`${session}\x00${key}`).digest("hex").slice(0, 32)}.json`), callKey = (toolUseId, command) => toolUseId ?? `cmd:${createHash14("sha256").update(command).digest("hex")}`, headCommit = (dir) => {
|
|
18415
18450
|
const run = spawnSync11("git", [
|
|
18416
18451
|
"log",
|
|
18417
18452
|
"-1",
|
|
@@ -18428,11 +18463,11 @@ var NONE3, SHELLS, PREFIXES3, SCRIPT_FLAG, CD, PUSHD, POPD, GIT_VALUE_OPTIONS, i
|
|
|
18428
18463
|
}, settle2 = (input, repo, file) => {
|
|
18429
18464
|
let marker;
|
|
18430
18465
|
try {
|
|
18431
|
-
marker = JSON.parse(
|
|
18466
|
+
marker = JSON.parse(fs16.readFileSync(file, "utf8"));
|
|
18432
18467
|
} catch {
|
|
18433
18468
|
return;
|
|
18434
18469
|
}
|
|
18435
|
-
|
|
18470
|
+
fs16.rmSync(file, { force: true });
|
|
18436
18471
|
const session = input.session.id;
|
|
18437
18472
|
const now = Date.now() / 1000;
|
|
18438
18473
|
if (typeof marker.at !== "number" || now - marker.at > MARKER_TTL_SECONDS)
|
|
@@ -18907,9 +18942,9 @@ var init_skill_nudge = __esm(() => {
|
|
|
18907
18942
|
|
|
18908
18943
|
// packages/workit-core/src/hooks/hosts/fields.ts
|
|
18909
18944
|
import { existsSync as existsSync6, realpathSync as realpathSync6, statSync as statSync2 } from "node:fs";
|
|
18910
|
-
import
|
|
18945
|
+
import path21 from "node:path";
|
|
18911
18946
|
var isRecord4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value), nonEmpty2 = (value) => typeof value === "string" && value.trim() !== "", optionalText = (value) => typeof value === "string" ? value : null, existingDirectory = (value) => {
|
|
18912
|
-
if (!nonEmpty2(value) || !
|
|
18947
|
+
if (!nonEmpty2(value) || !path21.isAbsolute(value) || !existsSync6(value))
|
|
18913
18948
|
return null;
|
|
18914
18949
|
try {
|
|
18915
18950
|
return statSync2(value).isDirectory() ? realpathSync6(value) : null;
|
|
@@ -19070,6 +19105,8 @@ ${subagentStartText({ ...input, cwd: "" }, descriptor, event)}`;
|
|
|
19070
19105
|
if (role !== "judge" || !event.agentId)
|
|
19071
19106
|
return readOnly;
|
|
19072
19107
|
const own = subagentSession(session, event.agentId);
|
|
19108
|
+
if (session)
|
|
19109
|
+
recordIssuedSession(input.cwd || process.cwd(), session, own);
|
|
19073
19110
|
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.`;
|
|
19074
19111
|
}, failureDecision = (descriptor, event, error) => {
|
|
19075
19112
|
if (event === "shell.pre" || event === "tool.pre" || event === "write.pre")
|
|
@@ -19101,6 +19138,7 @@ ${subagentStartText({ ...input, cwd: "" }, descriptor, event)}`;
|
|
|
19101
19138
|
};
|
|
19102
19139
|
var init_handle = __esm(() => {
|
|
19103
19140
|
init_context();
|
|
19141
|
+
init_host_session();
|
|
19104
19142
|
init_policy();
|
|
19105
19143
|
init_raw_git();
|
|
19106
19144
|
init_skill_nudge();
|
|
@@ -19638,13 +19676,13 @@ var init_codex = __esm(() => {
|
|
|
19638
19676
|
};
|
|
19639
19677
|
},
|
|
19640
19678
|
render: render2,
|
|
19641
|
-
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
|
|
19679
|
+
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>`
|
|
19642
19680
|
};
|
|
19643
19681
|
});
|
|
19644
19682
|
|
|
19645
19683
|
// packages/workit-core/src/hooks/hosts/cursor.ts
|
|
19646
|
-
import
|
|
19647
|
-
import
|
|
19684
|
+
import fs17 from "node:fs";
|
|
19685
|
+
import path22 from "node:path";
|
|
19648
19686
|
var undocumented, none, CURSOR_DESCRIPTOR, EVENTS3, parseCursorHookInput = (value) => {
|
|
19649
19687
|
if (!isRecord4(value) || !Object.hasOwn(EVENTS3, String(value.hook_event_name)))
|
|
19650
19688
|
return { ok: false, error: "hook_event_name is required" };
|
|
@@ -19725,17 +19763,17 @@ var undocumented, none, CURSOR_DESCRIPTOR, EVENTS3, parseCursorHookInput = (valu
|
|
|
19725
19763
|
};
|
|
19726
19764
|
}
|
|
19727
19765
|
}, TRANSCRIPT_TAIL_BYTES, lastAssistantText = (file) => {
|
|
19728
|
-
if (!file || !
|
|
19766
|
+
if (!file || !path22.isAbsolute(file))
|
|
19729
19767
|
return null;
|
|
19730
19768
|
try {
|
|
19731
|
-
const size =
|
|
19769
|
+
const size = fs17.statSync(file).size;
|
|
19732
19770
|
const start = Math.max(0, size - TRANSCRIPT_TAIL_BYTES);
|
|
19733
19771
|
const buffer = Buffer.alloc(size - start);
|
|
19734
|
-
const fd =
|
|
19772
|
+
const fd = fs17.openSync(file, "r");
|
|
19735
19773
|
try {
|
|
19736
|
-
|
|
19774
|
+
fs17.readSync(fd, buffer, 0, buffer.length, start);
|
|
19737
19775
|
} finally {
|
|
19738
|
-
|
|
19776
|
+
fs17.closeSync(fd);
|
|
19739
19777
|
}
|
|
19740
19778
|
const lines = buffer.toString("utf8").split(`
|
|
19741
19779
|
`);
|
|
@@ -19761,7 +19799,7 @@ var undocumented, none, CURSOR_DESCRIPTOR, EVENTS3, parseCursorHookInput = (valu
|
|
|
19761
19799
|
} catch {
|
|
19762
19800
|
return null;
|
|
19763
19801
|
}
|
|
19764
|
-
}, within = (root, dir) => dir === root || dir.startsWith(root.endsWith(
|
|
19802
|
+
}, within = (root, dir) => dir === root || dir.startsWith(root.endsWith(path22.sep) ? root : `${root}${path22.sep}`), hookCwd = (input) => {
|
|
19765
19803
|
const cwd = existingDirectory(input.cwd);
|
|
19766
19804
|
if (cwd && input.hook_event_name === "beforeShellExecution")
|
|
19767
19805
|
return cwd;
|