@brainervirus/workit-cursor 8.19.2 → 8.21.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 +622 -434
- package/dist/mcp-server.js +3 -0
- package/dist/workit-hook.js +627 -435
- package/package.json +3 -3
package/dist/workit-hook.js
CHANGED
|
@@ -8389,7 +8389,7 @@ import { realpathSync as realpathSync4 } from "node:fs";
|
|
|
8389
8389
|
|
|
8390
8390
|
// packages/workit-core/src/core/policy/derive.ts
|
|
8391
8391
|
import { existsSync as existsSync2 } from "node:fs";
|
|
8392
|
-
import
|
|
8392
|
+
import path10 from "node:path";
|
|
8393
8393
|
|
|
8394
8394
|
// packages/workit-core/src/git/rev.ts
|
|
8395
8395
|
import { spawnSync } from "node:child_process";
|
|
@@ -8574,9 +8574,9 @@ function pushRemoteName(cwd, branch) {
|
|
|
8574
8574
|
|
|
8575
8575
|
// packages/workit-core/src/ledger.ts
|
|
8576
8576
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
8577
|
-
import { createHash as
|
|
8578
|
-
import
|
|
8579
|
-
import
|
|
8577
|
+
import { createHash as createHash9, randomBytes as randomBytes2 } from "node:crypto";
|
|
8578
|
+
import fs7 from "node:fs";
|
|
8579
|
+
import path9 from "node:path";
|
|
8580
8580
|
|
|
8581
8581
|
// packages/workit-core/src/core/store-lock.ts
|
|
8582
8582
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
@@ -10764,6 +10764,61 @@ function issuedBinding(cwd, claimed) {
|
|
|
10764
10764
|
}
|
|
10765
10765
|
var OWN_CHILD_SHELL = new Set(["opencode", "pi"]);
|
|
10766
10766
|
|
|
10767
|
+
// packages/workit-core/src/hooks/standing-signal.ts
|
|
10768
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
10769
|
+
import fs6 from "node:fs";
|
|
10770
|
+
import path8 from "node:path";
|
|
10771
|
+
var gitStoreDir = (cwd) => {
|
|
10772
|
+
try {
|
|
10773
|
+
for (let dir = path8.resolve(cwd);; dir = path8.dirname(dir)) {
|
|
10774
|
+
const dotGit = path8.join(dir, ".git");
|
|
10775
|
+
if (fs6.existsSync(dotGit)) {
|
|
10776
|
+
let gitDir = dotGit;
|
|
10777
|
+
if (fs6.statSync(dotGit).isFile()) {
|
|
10778
|
+
const target = /^gitdir:\s*(.+)$/mu.exec(fs6.readFileSync(dotGit, "utf8"))?.[1]?.trim();
|
|
10779
|
+
if (!target)
|
|
10780
|
+
return null;
|
|
10781
|
+
gitDir = path8.resolve(dir, target);
|
|
10782
|
+
const common = path8.join(gitDir, "commondir");
|
|
10783
|
+
if (fs6.existsSync(common))
|
|
10784
|
+
gitDir = path8.resolve(gitDir, fs6.readFileSync(common, "utf8").trim());
|
|
10785
|
+
}
|
|
10786
|
+
return path8.join(gitDir, "workit");
|
|
10787
|
+
}
|
|
10788
|
+
if (path8.dirname(dir) === dir)
|
|
10789
|
+
return null;
|
|
10790
|
+
}
|
|
10791
|
+
} catch {
|
|
10792
|
+
return null;
|
|
10793
|
+
}
|
|
10794
|
+
};
|
|
10795
|
+
var standingRevFile = (store) => path8.join(store, "standing", "rev");
|
|
10796
|
+
var standingSeenFile = (store, session, agentId) => path8.join(store, "standing", "seen", `${createHash8("sha256").update(`${session}\x00${agentId ?? ""}`).digest("hex").slice(0, 32)}.json`);
|
|
10797
|
+
var readStandingRev = (store) => {
|
|
10798
|
+
try {
|
|
10799
|
+
return fs6.readFileSync(standingRevFile(store), "utf8").trim() || null;
|
|
10800
|
+
} catch {
|
|
10801
|
+
return null;
|
|
10802
|
+
}
|
|
10803
|
+
};
|
|
10804
|
+
var readStandingSeen = (file) => {
|
|
10805
|
+
try {
|
|
10806
|
+
const value = JSON.parse(fs6.readFileSync(file, "utf8"));
|
|
10807
|
+
return {
|
|
10808
|
+
rev: typeof value.rev === "string" ? value.rev : null,
|
|
10809
|
+
ids: Array.isArray(value.ids) ? value.ids.filter((id) => typeof id === "string") : []
|
|
10810
|
+
};
|
|
10811
|
+
} catch {
|
|
10812
|
+
return { rev: null, ids: [] };
|
|
10813
|
+
}
|
|
10814
|
+
};
|
|
10815
|
+
var writeStandingSeen = (file, seen) => {
|
|
10816
|
+
try {
|
|
10817
|
+
fs6.mkdirSync(path8.dirname(file), { recursive: true });
|
|
10818
|
+
fs6.writeFileSync(file, JSON.stringify(seen));
|
|
10819
|
+
} catch {}
|
|
10820
|
+
};
|
|
10821
|
+
|
|
10767
10822
|
// packages/workit-core/src/ledger.ts
|
|
10768
10823
|
var LEDGER_VERSION = 1;
|
|
10769
10824
|
var MAX_LINE_BYTES = 4096;
|
|
@@ -10874,7 +10929,7 @@ function diffHash(cwd, base, head) {
|
|
|
10874
10929
|
], GIT_TIMEOUTS.worktree);
|
|
10875
10930
|
if (!diff.ok || !diff.stdout)
|
|
10876
10931
|
return null;
|
|
10877
|
-
const hash =
|
|
10932
|
+
const hash = createHash9("sha256");
|
|
10878
10933
|
for (const line of diff.stdout.split(`
|
|
10879
10934
|
`)) {
|
|
10880
10935
|
if (line.startsWith("index "))
|
|
@@ -10886,14 +10941,14 @@ function diffHash(cwd, base, head) {
|
|
|
10886
10941
|
return `sha256:${hash.digest("hex")}`;
|
|
10887
10942
|
}
|
|
10888
10943
|
function storeRoot(cwd) {
|
|
10889
|
-
const location = resolveStore(
|
|
10944
|
+
const location = resolveStore(path9.resolve(cwd));
|
|
10890
10945
|
if (location instanceof Error)
|
|
10891
10946
|
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");
|
|
10892
10947
|
return { ok: true, value: { root: location.dir, shared: location.shared } };
|
|
10893
10948
|
}
|
|
10894
10949
|
function ledgerPath(cwd) {
|
|
10895
10950
|
const root = storeRoot(cwd);
|
|
10896
|
-
return root.ok ? { ok: true, value:
|
|
10951
|
+
return root.ok ? { ok: true, value: path9.join(root.value.root, "ledger", "ledger.jsonl") } : root;
|
|
10897
10952
|
}
|
|
10898
10953
|
var newId2 = () => `${Date.now().toString(36)}-${randomBytes2(6).toString("hex")}`;
|
|
10899
10954
|
var NETWORK_FS_TYPES = new Set([
|
|
@@ -10913,7 +10968,7 @@ var onNetworkFs = (dir) => {
|
|
|
10913
10968
|
if (process.platform !== "linux")
|
|
10914
10969
|
return false;
|
|
10915
10970
|
try {
|
|
10916
|
-
return isNetworkFsType(
|
|
10971
|
+
return isNetworkFsType(fs7.statfsSync(dir).type);
|
|
10917
10972
|
} catch {
|
|
10918
10973
|
return false;
|
|
10919
10974
|
}
|
|
@@ -10923,15 +10978,15 @@ var LOCK_STALE_MS = 30000;
|
|
|
10923
10978
|
var LOCK_OWNER = "owner";
|
|
10924
10979
|
var lockToken = (lock) => {
|
|
10925
10980
|
try {
|
|
10926
|
-
return
|
|
10981
|
+
return fs7.readFileSync(path9.join(lock, LOCK_OWNER), "utf8");
|
|
10927
10982
|
} catch {
|
|
10928
10983
|
return null;
|
|
10929
10984
|
}
|
|
10930
10985
|
};
|
|
10931
10986
|
var lockAgeMs = (lock) => {
|
|
10932
|
-
for (const target of [
|
|
10987
|
+
for (const target of [path9.join(lock, LOCK_OWNER), lock]) {
|
|
10933
10988
|
try {
|
|
10934
|
-
return Date.now() -
|
|
10989
|
+
return Date.now() - fs7.statSync(target).mtimeMs;
|
|
10935
10990
|
} catch {}
|
|
10936
10991
|
}
|
|
10937
10992
|
return null;
|
|
@@ -10939,14 +10994,14 @@ var lockAgeMs = (lock) => {
|
|
|
10939
10994
|
var ledgerLock = {
|
|
10940
10995
|
acquire(lock) {
|
|
10941
10996
|
try {
|
|
10942
|
-
|
|
10997
|
+
fs7.mkdirSync(lock);
|
|
10943
10998
|
} catch (error) {
|
|
10944
10999
|
if (error.code === "EEXIST")
|
|
10945
11000
|
return null;
|
|
10946
11001
|
throw error;
|
|
10947
11002
|
}
|
|
10948
11003
|
const token = `${process.pid}-${randomBytes2(8).toString("hex")}`;
|
|
10949
|
-
|
|
11004
|
+
fs7.writeFileSync(path9.join(lock, LOCK_OWNER), token);
|
|
10950
11005
|
return token;
|
|
10951
11006
|
},
|
|
10952
11007
|
release(lock, token) {
|
|
@@ -10954,35 +11009,35 @@ var ledgerLock = {
|
|
|
10954
11009
|
return false;
|
|
10955
11010
|
const tomb = `${lock}.release-${randomBytes2(6).toString("hex")}`;
|
|
10956
11011
|
try {
|
|
10957
|
-
|
|
11012
|
+
fs7.renameSync(lock, tomb);
|
|
10958
11013
|
} catch {
|
|
10959
11014
|
return false;
|
|
10960
11015
|
}
|
|
10961
11016
|
if (lockToken(tomb) !== token) {
|
|
10962
11017
|
try {
|
|
10963
|
-
|
|
11018
|
+
fs7.renameSync(tomb, lock);
|
|
10964
11019
|
} catch {}
|
|
10965
11020
|
return false;
|
|
10966
11021
|
}
|
|
10967
|
-
|
|
11022
|
+
fs7.rmSync(tomb, { recursive: true, force: true });
|
|
10968
11023
|
return true;
|
|
10969
11024
|
},
|
|
10970
11025
|
token: lockToken,
|
|
10971
11026
|
reap(lock, observed) {
|
|
10972
11027
|
const tomb = `${lock}.reap-${randomBytes2(6).toString("hex")}`;
|
|
10973
11028
|
try {
|
|
10974
|
-
|
|
11029
|
+
fs7.renameSync(lock, tomb);
|
|
10975
11030
|
} catch {
|
|
10976
11031
|
return false;
|
|
10977
11032
|
}
|
|
10978
11033
|
if (lockToken(tomb) === observed) {
|
|
10979
|
-
|
|
11034
|
+
fs7.rmSync(tomb, { recursive: true, force: true });
|
|
10980
11035
|
return true;
|
|
10981
11036
|
}
|
|
10982
11037
|
try {
|
|
10983
|
-
|
|
11038
|
+
fs7.renameSync(tomb, lock);
|
|
10984
11039
|
} catch {
|
|
10985
|
-
|
|
11040
|
+
fs7.rmSync(tomb, { recursive: true, force: true });
|
|
10986
11041
|
}
|
|
10987
11042
|
return false;
|
|
10988
11043
|
}
|
|
@@ -11009,14 +11064,14 @@ function withLedgerLock(file, fn, waitMs = hostAwareLockTimeout(LOCK_WAIT_MS)) {
|
|
|
11009
11064
|
ledgerLock.release(lock, token);
|
|
11010
11065
|
}
|
|
11011
11066
|
}
|
|
11012
|
-
var sha2562 = (text) =>
|
|
11067
|
+
var sha2562 = (text) => createHash9("sha256").update(text).digest("hex");
|
|
11013
11068
|
var chainHash = (prevHash, body) => sha2562(`${prevHash ?? ""}
|
|
11014
11069
|
${body}`);
|
|
11015
11070
|
var TAIL_BYTES = 64 * 1024;
|
|
11016
11071
|
var lastLine = (fd, size) => {
|
|
11017
11072
|
for (let span = Math.min(size, TAIL_BYTES);span > 0; span = Math.min(size, span * 2)) {
|
|
11018
11073
|
const buffer = Buffer.alloc(span);
|
|
11019
|
-
|
|
11074
|
+
fs7.readSync(fd, buffer, 0, span, size - span);
|
|
11020
11075
|
const end = buffer.lastIndexOf(10);
|
|
11021
11076
|
if (end < 0) {
|
|
11022
11077
|
if (span === size)
|
|
@@ -11047,21 +11102,21 @@ var lastLine = (fd, size) => {
|
|
|
11047
11102
|
};
|
|
11048
11103
|
var tighten = (fd) => {
|
|
11049
11104
|
try {
|
|
11050
|
-
if ((
|
|
11051
|
-
|
|
11105
|
+
if ((fs7.fstatSync(fd).mode & 63) !== 0)
|
|
11106
|
+
fs7.fchmodSync(fd, 384);
|
|
11052
11107
|
} catch {}
|
|
11053
11108
|
};
|
|
11054
11109
|
function appendLine(file, build, options) {
|
|
11055
11110
|
const write = () => {
|
|
11056
|
-
const fd =
|
|
11111
|
+
const fd = fs7.openSync(file, "a+", 384);
|
|
11057
11112
|
try {
|
|
11058
11113
|
if (process.platform !== "win32")
|
|
11059
11114
|
tighten(fd);
|
|
11060
|
-
const size =
|
|
11115
|
+
const size = fs7.fstatSync(fd).size;
|
|
11061
11116
|
let fence = "";
|
|
11062
11117
|
if (size > 0) {
|
|
11063
11118
|
const last = Buffer.alloc(1);
|
|
11064
|
-
|
|
11119
|
+
fs7.readSync(fd, last, 0, 1, size - 1);
|
|
11065
11120
|
if (last[0] !== 10)
|
|
11066
11121
|
fence = `
|
|
11067
11122
|
`;
|
|
@@ -11070,17 +11125,17 @@ function appendLine(file, build, options) {
|
|
|
11070
11125
|
if (!line.ok)
|
|
11071
11126
|
return line;
|
|
11072
11127
|
const bytes = Buffer.from(fence + line.value);
|
|
11073
|
-
const written =
|
|
11128
|
+
const written = fs7.writeSync(fd, bytes);
|
|
11074
11129
|
if (written !== bytes.length)
|
|
11075
11130
|
return err("unavailable", `short write to ${file}: ${written} of ${bytes.length} bytes; the row is torn and will be skipped`);
|
|
11076
11131
|
return { ok: true, value: undefined };
|
|
11077
11132
|
} finally {
|
|
11078
|
-
|
|
11133
|
+
fs7.closeSync(fd);
|
|
11079
11134
|
}
|
|
11080
11135
|
};
|
|
11081
11136
|
try {
|
|
11082
|
-
|
|
11083
|
-
if (!options.forceLock && !onNetworkFs(
|
|
11137
|
+
fs7.mkdirSync(path9.dirname(file), { recursive: true });
|
|
11138
|
+
if (!options.forceLock && !onNetworkFs(path9.dirname(file)))
|
|
11084
11139
|
return write();
|
|
11085
11140
|
const locked = withLedgerLock(file, write);
|
|
11086
11141
|
return locked ?? err("busy", `ledger lock ${file}.lock is held`, "retry; remove the .lock directory if no workit process is running");
|
|
@@ -11153,8 +11208,8 @@ function readLedger(cwd, options = {}) {
|
|
|
11153
11208
|
let text = "";
|
|
11154
11209
|
let stat = null;
|
|
11155
11210
|
try {
|
|
11156
|
-
stat =
|
|
11157
|
-
text =
|
|
11211
|
+
stat = fs7.statSync(file.value);
|
|
11212
|
+
text = fs7.readFileSync(file.value, "utf8");
|
|
11158
11213
|
} catch (error) {
|
|
11159
11214
|
if (error.code === "ENOENT")
|
|
11160
11215
|
return {
|
|
@@ -11289,7 +11344,7 @@ function ledgerTampering(cwd) {
|
|
|
11289
11344
|
if (!file.ok)
|
|
11290
11345
|
return [];
|
|
11291
11346
|
try {
|
|
11292
|
-
const stat =
|
|
11347
|
+
const stat = fs7.statSync(file.value);
|
|
11293
11348
|
const cached = tamperCache.get(file.value);
|
|
11294
11349
|
if (cached && cached.size === stat.size && cached.stamp === fileStamp(stat))
|
|
11295
11350
|
return cached.breaks;
|
|
@@ -11620,6 +11675,28 @@ function checkVerdicts(cwd, branch, ledgerRows) {
|
|
|
11620
11675
|
warnings
|
|
11621
11676
|
};
|
|
11622
11677
|
}
|
|
11678
|
+
var fromLead = (row, leads) => leads === null || row.actor.session !== null && leads.includes(row.actor.session);
|
|
11679
|
+
function activeStanding(rows, fanout, leads = null) {
|
|
11680
|
+
const active = [];
|
|
11681
|
+
for (const row of rows) {
|
|
11682
|
+
if (row.fanout !== fanout || !fromLead(row, leads))
|
|
11683
|
+
continue;
|
|
11684
|
+
if (row.type === "standing" && typeof row.what === "string" && row.what.trim()) {
|
|
11685
|
+
if (!row.superseded)
|
|
11686
|
+
active.push(row);
|
|
11687
|
+
} else if (row.type === "standing.cleared") {
|
|
11688
|
+
const target = str(row.target);
|
|
11689
|
+
if (target === null)
|
|
11690
|
+
active.length = 0;
|
|
11691
|
+
else {
|
|
11692
|
+
const index = active.findIndex((order) => order.id === target);
|
|
11693
|
+
if (index >= 0)
|
|
11694
|
+
active.splice(index, 1);
|
|
11695
|
+
}
|
|
11696
|
+
}
|
|
11697
|
+
}
|
|
11698
|
+
return active;
|
|
11699
|
+
}
|
|
11623
11700
|
var OBSERVED_ONLY = new Set([
|
|
11624
11701
|
"check",
|
|
11625
11702
|
"merge.unverified",
|
|
@@ -11768,7 +11845,7 @@ var productDecision = (task, ledger) => {
|
|
|
11768
11845
|
};
|
|
11769
11846
|
};
|
|
11770
11847
|
var planRecorded = (task, root) => {
|
|
11771
|
-
const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync2(
|
|
11848
|
+
const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync2(path10.resolve(root, ref.path)));
|
|
11772
11849
|
if (cited)
|
|
11773
11850
|
return {
|
|
11774
11851
|
met: true,
|
|
@@ -12384,7 +12461,7 @@ var judgeInputSummary = (raw) => {
|
|
|
12384
12461
|
|
|
12385
12462
|
// packages/workit-core/src/autonomy.ts
|
|
12386
12463
|
import os4 from "node:os";
|
|
12387
|
-
import
|
|
12464
|
+
import path11 from "node:path";
|
|
12388
12465
|
var accountHome = () => {
|
|
12389
12466
|
try {
|
|
12390
12467
|
return os4.userInfo().homedir;
|
|
@@ -12393,10 +12470,10 @@ var accountHome = () => {
|
|
|
12393
12470
|
}
|
|
12394
12471
|
};
|
|
12395
12472
|
var grantsHome = { resolve: accountHome };
|
|
12396
|
-
var grantsDir = () =>
|
|
12473
|
+
var grantsDir = () => path11.join(grantsHome.resolve(), ".config", "workit");
|
|
12397
12474
|
var grantsOverride = () => {
|
|
12398
|
-
const configured =
|
|
12399
|
-
return configured ===
|
|
12475
|
+
const configured = path11.resolve(resolveConfigDir());
|
|
12476
|
+
return configured === path11.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 ${path11.join(grantsDir(), "workspaces.json")}, so the D4 defaults apply`;
|
|
12400
12477
|
};
|
|
12401
12478
|
var GRANT_KINDS = ["push", "pr", "merge", "release", "rerun"];
|
|
12402
12479
|
var DEFAULT_GRANTS = Object.freeze({
|
|
@@ -12520,9 +12597,9 @@ var suggested = (kind) => kind === "merge" ? "verified" : "true";
|
|
|
12520
12597
|
var grantHint = (workspace, kind) => `ask the user to run, in their own terminal: workit grant set ${workspace ?? "<workspace>"} ${kind}=${suggested(kind)}`;
|
|
12521
12598
|
|
|
12522
12599
|
// packages/workit-core/src/core/task-store.ts
|
|
12523
|
-
import { createHash as
|
|
12524
|
-
import * as
|
|
12525
|
-
import
|
|
12600
|
+
import { createHash as createHash11, randomUUID as randomUUID3 } from "node:crypto";
|
|
12601
|
+
import * as fs12 from "node:fs";
|
|
12602
|
+
import path16 from "node:path";
|
|
12526
12603
|
|
|
12527
12604
|
// node_modules/@openclaw/fs-safe/dist/errors.js
|
|
12528
12605
|
var OPERATIONAL_CODES = new Set([
|
|
@@ -12573,10 +12650,10 @@ function sameFileIdentity(left, right, platform = process.platform) {
|
|
|
12573
12650
|
// node_modules/@openclaw/fs-safe/dist/sidecar-lock-reclaim.js
|
|
12574
12651
|
import { randomBytes as randomBytes3 } from "node:crypto";
|
|
12575
12652
|
import fsSync from "node:fs";
|
|
12576
|
-
import
|
|
12653
|
+
import path12 from "node:path";
|
|
12577
12654
|
|
|
12578
12655
|
// node_modules/@openclaw/fs-safe/dist/bounded-read.js
|
|
12579
|
-
import
|
|
12656
|
+
import fs8 from "node:fs";
|
|
12580
12657
|
|
|
12581
12658
|
// node_modules/@openclaw/fs-safe/dist/byte-budget.js
|
|
12582
12659
|
function normalizeMaxBytes(value, options = {}) {
|
|
@@ -12613,7 +12690,7 @@ function readFileDescriptorBoundedSync(fd, maxBytes) {
|
|
|
12613
12690
|
let total = 0;
|
|
12614
12691
|
while (true) {
|
|
12615
12692
|
const length = nextReadLength(total, maxBytes, scratch.length);
|
|
12616
|
-
const bytesRead =
|
|
12693
|
+
const bytesRead = fs8.readSync(fd, scratch, 0, length, null);
|
|
12617
12694
|
if (bytesRead === 0) {
|
|
12618
12695
|
return Buffer.concat(chunks, total);
|
|
12619
12696
|
}
|
|
@@ -12622,9 +12699,9 @@ function readFileDescriptorBoundedSync(fd, maxBytes) {
|
|
|
12622
12699
|
}
|
|
12623
12700
|
|
|
12624
12701
|
// node_modules/@openclaw/fs-safe/dist/read-open-flags.js
|
|
12625
|
-
import
|
|
12702
|
+
import fs9 from "node:fs";
|
|
12626
12703
|
function resolveReadOpenFlags(options) {
|
|
12627
|
-
const constants = options?.constants ??
|
|
12704
|
+
const constants = options?.constants ?? fs9.constants;
|
|
12628
12705
|
const noFollow = process.platform !== "win32" && options?.followSymlinks !== true && typeof constants.O_NOFOLLOW === "number" ? constants.O_NOFOLLOW : 0;
|
|
12629
12706
|
const nonBlocking = process.platform !== "win32" && typeof constants.O_NONBLOCK === "number" ? constants.O_NONBLOCK : 0;
|
|
12630
12707
|
return constants.O_RDONLY | noFollow | nonBlocking;
|
|
@@ -12663,13 +12740,13 @@ ${ownershipToken}
|
|
|
12663
12740
|
return { raw, ownershipToken };
|
|
12664
12741
|
}
|
|
12665
12742
|
function relativeSidecarLockPath(lockRoot, lockPath) {
|
|
12666
|
-
const resolved =
|
|
12667
|
-
const lexicalRelative =
|
|
12668
|
-
const relative = lexicalRelative !== ".." && !lexicalRelative.startsWith(`..${
|
|
12669
|
-
if (!relative || relative === ".." || relative.startsWith(`..${
|
|
12743
|
+
const resolved = path12.resolve(lockPath);
|
|
12744
|
+
const lexicalRelative = path12.relative(lockRoot.rootDir, resolved);
|
|
12745
|
+
const relative = lexicalRelative !== ".." && !lexicalRelative.startsWith(`..${path12.sep}`) && !path12.isAbsolute(lexicalRelative) ? lexicalRelative : path12.relative(lockRoot.rootReal, resolved);
|
|
12746
|
+
if (!relative || relative === ".." || relative.startsWith(`..${path12.sep}`) || path12.isAbsolute(relative)) {
|
|
12670
12747
|
throw new FsSafeError("outside-workspace", "sidecar lock path is outside lockRoot");
|
|
12671
12748
|
}
|
|
12672
|
-
return relative.split(
|
|
12749
|
+
return relative.split(path12.sep).join(path12.posix.sep);
|
|
12673
12750
|
}
|
|
12674
12751
|
function parseSidecarLockPayload(raw, parser) {
|
|
12675
12752
|
if (parser) {
|
|
@@ -12815,8 +12892,8 @@ function getFsSafeLockConfig() {
|
|
|
12815
12892
|
}
|
|
12816
12893
|
|
|
12817
12894
|
// node_modules/@openclaw/fs-safe/dist/file-lock-sync.js
|
|
12818
|
-
import
|
|
12819
|
-
import
|
|
12895
|
+
import fs10 from "node:fs";
|
|
12896
|
+
import path13 from "node:path";
|
|
12820
12897
|
|
|
12821
12898
|
// node_modules/@openclaw/fs-safe/dist/timing.js
|
|
12822
12899
|
function sleepSync(ms) {
|
|
@@ -12846,7 +12923,7 @@ function releaseAllSyncHeldLocks() {
|
|
|
12846
12923
|
}
|
|
12847
12924
|
try {
|
|
12848
12925
|
if (held.fd !== undefined)
|
|
12849
|
-
|
|
12926
|
+
fs10.closeSync(held.fd);
|
|
12850
12927
|
} catch {}
|
|
12851
12928
|
try {
|
|
12852
12929
|
removeSidecarLockIfUnchangedSync(held.lockPath, held.snapshot);
|
|
@@ -12881,7 +12958,7 @@ function releaseSyncHeldLock(held) {
|
|
|
12881
12958
|
if (held.fd !== undefined) {
|
|
12882
12959
|
const fd = held.fd;
|
|
12883
12960
|
held.fd = undefined;
|
|
12884
|
-
|
|
12961
|
+
fs10.closeSync(fd);
|
|
12885
12962
|
}
|
|
12886
12963
|
removeSidecarLockIfUnchangedSync(held.lockPath, held.snapshot);
|
|
12887
12964
|
heldLocks.delete(held.normalizedTargetPath);
|
|
@@ -12904,29 +12981,29 @@ function createSyncHeldLockHandle(held) {
|
|
|
12904
12981
|
};
|
|
12905
12982
|
}
|
|
12906
12983
|
function canonicalLockParentSync(parent) {
|
|
12907
|
-
return process.platform === "win32" ?
|
|
12984
|
+
return process.platform === "win32" ? fs10.realpathSync.native(parent) : fs10.realpathSync(parent);
|
|
12908
12985
|
}
|
|
12909
12986
|
function normalizeTargetPath(targetPath) {
|
|
12910
|
-
const resolved =
|
|
12911
|
-
|
|
12987
|
+
const resolved = path13.resolve(targetPath);
|
|
12988
|
+
fs10.mkdirSync(path13.dirname(resolved), { recursive: true });
|
|
12912
12989
|
try {
|
|
12913
|
-
return
|
|
12990
|
+
return path13.join(canonicalLockParentSync(path13.dirname(resolved)), path13.basename(resolved));
|
|
12914
12991
|
} catch {
|
|
12915
12992
|
return resolved;
|
|
12916
12993
|
}
|
|
12917
12994
|
}
|
|
12918
12995
|
function boundedLockPath(lockPath, lockRoot) {
|
|
12919
|
-
const resolved =
|
|
12996
|
+
const resolved = path13.resolve(lockPath);
|
|
12920
12997
|
if (!lockRoot)
|
|
12921
12998
|
return resolved;
|
|
12922
12999
|
relativeSidecarLockPath(lockRoot, resolved);
|
|
12923
|
-
const parent =
|
|
13000
|
+
const parent = path13.dirname(resolved);
|
|
12924
13001
|
const parentReal = canonicalLockParentSync(parent);
|
|
12925
|
-
const parentRelative =
|
|
12926
|
-
if (parentRelative === ".." || parentRelative.startsWith(`..${
|
|
13002
|
+
const parentRelative = path13.relative(lockRoot.rootReal, parentReal);
|
|
13003
|
+
if (parentRelative === ".." || parentRelative.startsWith(`..${path13.sep}`) || path13.isAbsolute(parentRelative)) {
|
|
12927
13004
|
throw new FsSafeError("outside-workspace", "sidecar lock parent is outside lockRoot");
|
|
12928
13005
|
}
|
|
12929
|
-
return
|
|
13006
|
+
return path13.join(parentReal, path13.basename(resolved));
|
|
12930
13007
|
}
|
|
12931
13008
|
function defaultShouldReclaim(snapshot, staleMs, nowMs) {
|
|
12932
13009
|
const createdAtMs = sidecarLockPayloadCreatedAtMs(snapshot.payload);
|
|
@@ -12936,7 +13013,7 @@ function defaultShouldReclaim(snapshot, staleMs, nowMs) {
|
|
|
12936
13013
|
}
|
|
12937
13014
|
function reclaimGuardExists(reclaimGuardPath) {
|
|
12938
13015
|
try {
|
|
12939
|
-
|
|
13016
|
+
fs10.lstatSync(reclaimGuardPath);
|
|
12940
13017
|
return true;
|
|
12941
13018
|
} catch (error) {
|
|
12942
13019
|
if (error.code === "ENOENT")
|
|
@@ -13000,19 +13077,19 @@ function acquireFileLockSync(targetPath, options) {
|
|
|
13000
13077
|
const { raw, ownershipToken } = serializeSidecarLockPayload(payload);
|
|
13001
13078
|
let lockFileCreateDenied = false;
|
|
13002
13079
|
try {
|
|
13003
|
-
const noFollow = process.platform !== "win32" && typeof
|
|
13080
|
+
const noFollow = process.platform !== "win32" && typeof fs10.constants.O_NOFOLLOW === "number" ? fs10.constants.O_NOFOLLOW : 0;
|
|
13004
13081
|
try {
|
|
13005
|
-
fd =
|
|
13082
|
+
fd = fs10.openSync(lockPath, fs10.constants.O_WRONLY | fs10.constants.O_CREAT | fs10.constants.O_EXCL | noFollow, 384);
|
|
13006
13083
|
} catch (error) {
|
|
13007
13084
|
lockFileCreateDenied = isTransientLockFileDenial(error, lockPath);
|
|
13008
13085
|
throw error;
|
|
13009
13086
|
}
|
|
13010
|
-
|
|
13011
|
-
|
|
13087
|
+
fs10.writeFileSync(fd, raw, "utf8");
|
|
13088
|
+
fs10.fsyncSync(fd);
|
|
13012
13089
|
const snapshot = {
|
|
13013
13090
|
raw,
|
|
13014
13091
|
payload,
|
|
13015
|
-
stat:
|
|
13092
|
+
stat: fs10.fstatSync(fd),
|
|
13016
13093
|
ownershipToken
|
|
13017
13094
|
};
|
|
13018
13095
|
const createdHeld = {
|
|
@@ -13047,8 +13124,8 @@ function acquireFileLockSync(targetPath, options) {
|
|
|
13047
13124
|
return returnedHandle;
|
|
13048
13125
|
} catch (error) {
|
|
13049
13126
|
if (fd !== undefined) {
|
|
13050
|
-
const failed = { payload: null, stat:
|
|
13051
|
-
|
|
13127
|
+
const failed = { payload: null, stat: fs10.fstatSync(fd) };
|
|
13128
|
+
fs10.closeSync(fd);
|
|
13052
13129
|
fd = undefined;
|
|
13053
13130
|
removeSidecarLockIfUnchangedSync(lockPath, failed);
|
|
13054
13131
|
}
|
|
@@ -13097,7 +13174,7 @@ function acquireFileLockSync(targetPath, options) {
|
|
|
13097
13174
|
})) {
|
|
13098
13175
|
let ownsReclaimGuard = false;
|
|
13099
13176
|
try {
|
|
13100
|
-
|
|
13177
|
+
fs10.mkdirSync(reclaimGuardPath);
|
|
13101
13178
|
ownsReclaimGuard = true;
|
|
13102
13179
|
if (removeSidecarLockIfUnchangedSync(lockPath, snapshot))
|
|
13103
13180
|
continue;
|
|
@@ -13110,7 +13187,7 @@ function acquireFileLockSync(targetPath, options) {
|
|
|
13110
13187
|
} finally {
|
|
13111
13188
|
if (ownsReclaimGuard) {
|
|
13112
13189
|
try {
|
|
13113
|
-
|
|
13190
|
+
fs10.rmdirSync(reclaimGuardPath);
|
|
13114
13191
|
} catch {}
|
|
13115
13192
|
}
|
|
13116
13193
|
}
|
|
@@ -13127,13 +13204,13 @@ function acquireFileLockSync(targetPath, options) {
|
|
|
13127
13204
|
}
|
|
13128
13205
|
// packages/workit-core/src/core/package-root.ts
|
|
13129
13206
|
import { existsSync as existsSync3 } from "node:fs";
|
|
13130
|
-
import
|
|
13207
|
+
import path14 from "node:path";
|
|
13131
13208
|
import { fileURLToPath } from "node:url";
|
|
13132
13209
|
var packageRoot = () => {
|
|
13133
|
-
let dir =
|
|
13210
|
+
let dir = path14.dirname(fileURLToPath(import.meta.url));
|
|
13134
13211
|
while (true) {
|
|
13135
|
-
const parent =
|
|
13136
|
-
if (existsSync3(
|
|
13212
|
+
const parent = path14.dirname(dir);
|
|
13213
|
+
if (existsSync3(path14.join(dir, "package.json")) || parent === dir)
|
|
13137
13214
|
return dir;
|
|
13138
13215
|
dir = parent;
|
|
13139
13216
|
}
|
|
@@ -13141,8 +13218,8 @@ var packageRoot = () => {
|
|
|
13141
13218
|
|
|
13142
13219
|
// packages/workit-core/src/store/event-log.ts
|
|
13143
13220
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
13144
|
-
import
|
|
13145
|
-
import
|
|
13221
|
+
import fs11 from "node:fs";
|
|
13222
|
+
import path15 from "node:path";
|
|
13146
13223
|
var EVENT_VERSION = 1;
|
|
13147
13224
|
|
|
13148
13225
|
class LogDamage extends Error {
|
|
@@ -13171,7 +13248,7 @@ var parseEvent = (line, file, offset) => {
|
|
|
13171
13248
|
function readLog(file, from = 0, expectSeq = null) {
|
|
13172
13249
|
let fd;
|
|
13173
13250
|
try {
|
|
13174
|
-
fd =
|
|
13251
|
+
fd = fs11.openSync(file, "r");
|
|
13175
13252
|
} catch (error) {
|
|
13176
13253
|
if (error.code === "ENOENT")
|
|
13177
13254
|
return null;
|
|
@@ -13180,13 +13257,13 @@ function readLog(file, from = 0, expectSeq = null) {
|
|
|
13180
13257
|
let bytes;
|
|
13181
13258
|
let size;
|
|
13182
13259
|
try {
|
|
13183
|
-
size =
|
|
13260
|
+
size = fs11.fstatSync(fd).size;
|
|
13184
13261
|
if (from > size)
|
|
13185
13262
|
throw new LogDamage(`${file}: shorter than its snapshot`);
|
|
13186
13263
|
bytes = Buffer.alloc(size - from);
|
|
13187
13264
|
let read = 0;
|
|
13188
13265
|
while (read < bytes.length) {
|
|
13189
|
-
const got =
|
|
13266
|
+
const got = fs11.readSync(fd, bytes, read, bytes.length - read, from + read);
|
|
13190
13267
|
if (got === 0)
|
|
13191
13268
|
break;
|
|
13192
13269
|
read += got;
|
|
@@ -13194,7 +13271,7 @@ function readLog(file, from = 0, expectSeq = null) {
|
|
|
13194
13271
|
bytes = bytes.subarray(0, read);
|
|
13195
13272
|
size = from + read;
|
|
13196
13273
|
} finally {
|
|
13197
|
-
|
|
13274
|
+
fs11.closeSync(fd);
|
|
13198
13275
|
}
|
|
13199
13276
|
const events = [];
|
|
13200
13277
|
let start = 0;
|
|
@@ -13219,11 +13296,11 @@ function readLog(file, from = 0, expectSeq = null) {
|
|
|
13219
13296
|
}
|
|
13220
13297
|
var fsyncDirectory = (dir) => {
|
|
13221
13298
|
try {
|
|
13222
|
-
const fd =
|
|
13299
|
+
const fd = fs11.openSync(dir, "r");
|
|
13223
13300
|
try {
|
|
13224
|
-
|
|
13301
|
+
fs11.fsyncSync(fd);
|
|
13225
13302
|
} finally {
|
|
13226
|
-
|
|
13303
|
+
fs11.closeSync(fd);
|
|
13227
13304
|
}
|
|
13228
13305
|
} catch (error) {
|
|
13229
13306
|
if (process.platform !== "win32")
|
|
@@ -13233,46 +13310,46 @@ var fsyncDirectory = (dir) => {
|
|
|
13233
13310
|
function appendEvent(file, event, validEnd) {
|
|
13234
13311
|
const line = Buffer.from(`${JSON.stringify(event)}
|
|
13235
13312
|
`, "utf8");
|
|
13236
|
-
const created = !
|
|
13237
|
-
if (!created &&
|
|
13238
|
-
const cut =
|
|
13313
|
+
const created = !fs11.existsSync(file);
|
|
13314
|
+
if (!created && fs11.statSync(file).size !== validEnd) {
|
|
13315
|
+
const cut = fs11.openSync(file, "r+");
|
|
13239
13316
|
try {
|
|
13240
|
-
|
|
13241
|
-
|
|
13317
|
+
fs11.ftruncateSync(cut, validEnd);
|
|
13318
|
+
fs11.fsyncSync(cut);
|
|
13242
13319
|
} finally {
|
|
13243
|
-
|
|
13320
|
+
fs11.closeSync(cut);
|
|
13244
13321
|
}
|
|
13245
13322
|
}
|
|
13246
|
-
const fd =
|
|
13323
|
+
const fd = fs11.openSync(file, "a", 384);
|
|
13247
13324
|
try {
|
|
13248
13325
|
let written = 0;
|
|
13249
13326
|
while (written < line.length)
|
|
13250
|
-
written +=
|
|
13251
|
-
|
|
13327
|
+
written += fs11.writeSync(fd, line, written, line.length - written);
|
|
13328
|
+
fs11.fsyncSync(fd);
|
|
13252
13329
|
} finally {
|
|
13253
|
-
|
|
13330
|
+
fs11.closeSync(fd);
|
|
13254
13331
|
}
|
|
13255
13332
|
if (created)
|
|
13256
|
-
fsyncDirectory(
|
|
13333
|
+
fsyncDirectory(path15.dirname(file));
|
|
13257
13334
|
return validEnd;
|
|
13258
13335
|
}
|
|
13259
13336
|
function replaceFile(file, bytes, durable) {
|
|
13260
13337
|
const temporary = `${file}.${process.pid}.${randomUUID2()}.tmp`;
|
|
13261
13338
|
try {
|
|
13262
|
-
const fd =
|
|
13339
|
+
const fd = fs11.openSync(temporary, "wx", 384);
|
|
13263
13340
|
try {
|
|
13264
|
-
|
|
13341
|
+
fs11.writeSync(fd, bytes);
|
|
13265
13342
|
if (durable)
|
|
13266
|
-
|
|
13343
|
+
fs11.fsyncSync(fd);
|
|
13267
13344
|
} finally {
|
|
13268
|
-
|
|
13345
|
+
fs11.closeSync(fd);
|
|
13269
13346
|
}
|
|
13270
13347
|
renameWithRetry(temporary, file);
|
|
13271
13348
|
if (durable)
|
|
13272
|
-
fsyncDirectory(
|
|
13349
|
+
fsyncDirectory(path15.dirname(file));
|
|
13273
13350
|
} catch (error) {
|
|
13274
13351
|
try {
|
|
13275
|
-
|
|
13352
|
+
fs11.unlinkSync(temporary);
|
|
13276
13353
|
} catch {}
|
|
13277
13354
|
throw error;
|
|
13278
13355
|
}
|
|
@@ -13297,7 +13374,7 @@ var retryTransient = (run) => {
|
|
|
13297
13374
|
}
|
|
13298
13375
|
}
|
|
13299
13376
|
};
|
|
13300
|
-
var renameWithRetry = (from, to) => retryTransient(() =>
|
|
13377
|
+
var renameWithRetry = (from, to) => retryTransient(() => fs11.renameSync(from, to));
|
|
13301
13378
|
|
|
13302
13379
|
// packages/workit-core/src/store/patch.ts
|
|
13303
13380
|
var isPlainObject2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -13410,7 +13487,7 @@ var isPatch = (value) => Array.isArray(value) && value.every((op) => {
|
|
|
13410
13487
|
});
|
|
13411
13488
|
|
|
13412
13489
|
// packages/workit-core/src/store/reduce.ts
|
|
13413
|
-
import { createHash as
|
|
13490
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
13414
13491
|
var OPENING_TYPES = new Set([
|
|
13415
13492
|
"task.opened",
|
|
13416
13493
|
"task.imported",
|
|
@@ -13439,7 +13516,7 @@ var isObject5 = (value) => typeof value === "object" && value !== null && !Array
|
|
|
13439
13516
|
var isKey = (value) => isObject5(value) && typeof value.key === "string" && (value.kind === "branch" || value.kind === "detached" || value.kind === "dir") && (value.branch === null || typeof value.branch === "string");
|
|
13440
13517
|
var BLOB_REF = "$blob";
|
|
13441
13518
|
var blobRef = (value) => isObject5(value) && Object.keys(value).length === 1 && typeof value[BLOB_REF] === "string" && /^[0-9a-f]{64}$/.test(value[BLOB_REF]) ? value[BLOB_REF] : null;
|
|
13442
|
-
var blobDigest = (value) =>
|
|
13519
|
+
var blobDigest = (value) => createHash10("sha256").update(JSON.stringify(value)).digest("hex");
|
|
13443
13520
|
var toBlob = (value, blobs) => {
|
|
13444
13521
|
if (!isObject5(value))
|
|
13445
13522
|
return value;
|
|
@@ -13594,7 +13671,7 @@ var indexEntry = (task, key, legacy, file) => {
|
|
|
13594
13671
|
};
|
|
13595
13672
|
var fileSignature = (file) => {
|
|
13596
13673
|
try {
|
|
13597
|
-
const stat =
|
|
13674
|
+
const stat = fs12.statSync(file, { bigint: true });
|
|
13598
13675
|
return `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeNs}:${stat.ctimeNs}`;
|
|
13599
13676
|
} catch {
|
|
13600
13677
|
return null;
|
|
@@ -13612,7 +13689,7 @@ var cachedRuntimeVersion = null;
|
|
|
13612
13689
|
var runtimeVersion = () => {
|
|
13613
13690
|
if (cachedRuntimeVersion === null) {
|
|
13614
13691
|
try {
|
|
13615
|
-
const pkg = JSON.parse(
|
|
13692
|
+
const pkg = JSON.parse(fs12.readFileSync(path16.join(packageRoot(), "package.json"), "utf8"));
|
|
13616
13693
|
cachedRuntimeVersion = typeof pkg.version === "string" && pkg.version ? pkg.version : "0.0.0";
|
|
13617
13694
|
} catch {
|
|
13618
13695
|
cachedRuntimeVersion = "0.0.0";
|
|
@@ -13638,14 +13715,14 @@ var isNewerVersion = (candidate, current) => {
|
|
|
13638
13715
|
var validId = (value) => /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(value);
|
|
13639
13716
|
var readText = (file) => {
|
|
13640
13717
|
try {
|
|
13641
|
-
return
|
|
13718
|
+
return fs12.readFileSync(file, "utf8");
|
|
13642
13719
|
} catch {
|
|
13643
13720
|
return "";
|
|
13644
13721
|
}
|
|
13645
13722
|
};
|
|
13646
13723
|
var REFLOG_LINE = /^[0-9a-f]+ ([0-9a-f]+) .* (\d+) [+-]\d{4}\t(.*)$/u;
|
|
13647
13724
|
var branchStart = (location, branch, aliases) => {
|
|
13648
|
-
const first = readText(
|
|
13725
|
+
const first = readText(path16.join(path16.dirname(location.dir), "logs", "refs", "heads", branch)).split(`
|
|
13649
13726
|
`, 1)[0];
|
|
13650
13727
|
const created = REFLOG_LINE.exec(first);
|
|
13651
13728
|
const start = created && /^branch: Created from (\S+)$/u.exec(created[3])?.[1];
|
|
@@ -13655,7 +13732,7 @@ var branchStart = (location, branch, aliases) => {
|
|
|
13655
13732
|
return start;
|
|
13656
13733
|
if (!location.git)
|
|
13657
13734
|
return null;
|
|
13658
|
-
for (const line of readText(
|
|
13735
|
+
for (const line of readText(path16.join(location.git.gitDir, "logs", "HEAD")).split(`
|
|
13659
13736
|
`)) {
|
|
13660
13737
|
const entry = REFLOG_LINE.exec(line);
|
|
13661
13738
|
const moved = entry && /^checkout: moving from (\S+) to (\S+)$/u.exec(entry[3]);
|
|
@@ -13665,23 +13742,23 @@ var branchStart = (location, branch, aliases) => {
|
|
|
13665
13742
|
}
|
|
13666
13743
|
return null;
|
|
13667
13744
|
};
|
|
13668
|
-
var refExists = (common, ref) =>
|
|
13745
|
+
var refExists = (common, ref) => fs12.existsSync(path16.join(common, ref)) || readText(path16.join(common, "packed-refs")).includes(` ${ref}
|
|
13669
13746
|
`);
|
|
13670
13747
|
var origins = new Map;
|
|
13671
13748
|
var sameDirectoryIdentity = (left, right) => {
|
|
13672
|
-
if (!
|
|
13749
|
+
if (!path16.isAbsolute(left) || !path16.isAbsolute(right))
|
|
13673
13750
|
return false;
|
|
13674
|
-
const normalizedLeft =
|
|
13675
|
-
const normalizedRight =
|
|
13751
|
+
const normalizedLeft = path16.resolve(left);
|
|
13752
|
+
const normalizedRight = path16.resolve(right);
|
|
13676
13753
|
try {
|
|
13677
|
-
const a =
|
|
13678
|
-
const b =
|
|
13754
|
+
const a = fs12.statSync(normalizedLeft, { bigint: true });
|
|
13755
|
+
const b = fs12.statSync(normalizedRight, { bigint: true });
|
|
13679
13756
|
if (!a.isDirectory() || !b.isDirectory())
|
|
13680
13757
|
return false;
|
|
13681
13758
|
if (process.platform === "win32" ? normalizedLeft.toLowerCase() === normalizedRight.toLowerCase() : normalizedLeft === normalizedRight)
|
|
13682
13759
|
return true;
|
|
13683
|
-
const canonicalLeft =
|
|
13684
|
-
const canonicalRight =
|
|
13760
|
+
const canonicalLeft = fs12.realpathSync(normalizedLeft);
|
|
13761
|
+
const canonicalRight = fs12.realpathSync(normalizedRight);
|
|
13685
13762
|
if (process.platform === "win32" ? canonicalLeft.toLowerCase() === canonicalRight.toLowerCase() : canonicalLeft === canonicalRight)
|
|
13686
13763
|
return true;
|
|
13687
13764
|
return a.dev === b.dev && a.ino !== 0n && a.ino === b.ino;
|
|
@@ -13718,8 +13795,8 @@ class TaskStore {
|
|
|
13718
13795
|
migrationChecked = false;
|
|
13719
13796
|
compactDue = new Set;
|
|
13720
13797
|
constructor(root, options = {}) {
|
|
13721
|
-
const resolved =
|
|
13722
|
-
this.origin =
|
|
13798
|
+
const resolved = path16.resolve(root);
|
|
13799
|
+
this.origin = fs12.existsSync(resolved) ? fs12.realpathSync(resolved) : resolved;
|
|
13723
13800
|
this.located = resolveStore(this.origin);
|
|
13724
13801
|
this.root = checkoutRootOf(this.origin, this.located);
|
|
13725
13802
|
this.lockTimeoutMs = options.lockTimeoutMs ?? defaultLockTimeout();
|
|
@@ -13727,7 +13804,7 @@ class TaskStore {
|
|
|
13727
13804
|
this.migrateOnRead = options.migrateOnRead;
|
|
13728
13805
|
}
|
|
13729
13806
|
location() {
|
|
13730
|
-
if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared &&
|
|
13807
|
+
if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared && fs12.existsSync(path16.join(this.root, ".git"))) {
|
|
13731
13808
|
this.located = undefined;
|
|
13732
13809
|
this.migrationChecked = false;
|
|
13733
13810
|
}
|
|
@@ -13791,7 +13868,7 @@ class TaskStore {
|
|
|
13791
13868
|
const tasksDir = this.paths().tasks;
|
|
13792
13869
|
let names;
|
|
13793
13870
|
try {
|
|
13794
|
-
names =
|
|
13871
|
+
names = fs12.existsSync(tasksDir) ? fs12.readdirSync(tasksDir).filter((name) => validId(name)) : [];
|
|
13795
13872
|
} catch (error) {
|
|
13796
13873
|
return failure2("storage_error", `unable to list tasks: ${String(error)}`, {
|
|
13797
13874
|
path: tasksDir
|
|
@@ -13832,7 +13909,7 @@ class TaskStore {
|
|
|
13832
13909
|
const file = this.paths().workspace;
|
|
13833
13910
|
let bytes;
|
|
13834
13911
|
try {
|
|
13835
|
-
bytes = retryTransient(() =>
|
|
13912
|
+
bytes = retryTransient(() => fs12.readFileSync(file, "utf8"));
|
|
13836
13913
|
} catch (error) {
|
|
13837
13914
|
if (error.code === "ENOENT")
|
|
13838
13915
|
return success(null, null, null);
|
|
@@ -13883,7 +13960,7 @@ class TaskStore {
|
|
|
13883
13960
|
const moved = this.bindLocked(again.data.id, key, input.now);
|
|
13884
13961
|
return moved.ok ? success(moved.data.revision, null, { task: moved.data, created: false, key }) : moved;
|
|
13885
13962
|
}
|
|
13886
|
-
const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" :
|
|
13963
|
+
const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" : path16.basename(this.root) || this.root;
|
|
13887
13964
|
const intent = {
|
|
13888
13965
|
objective: input.objective?.trim() || `Work on ${label}`,
|
|
13889
13966
|
scope: { description: `the checkout (${label})`, paths: ["."], exclusions: [] },
|
|
@@ -13949,14 +14026,14 @@ class TaskStore {
|
|
|
13949
14026
|
const branch = key.ok ? key.data.branch : null;
|
|
13950
14027
|
if (!branch || !location.ok)
|
|
13951
14028
|
return success(null, null, null);
|
|
13952
|
-
const common =
|
|
13953
|
-
const heads =
|
|
13954
|
-
const headLog = location.data.git ?
|
|
14029
|
+
const common = path16.dirname(location.data.dir);
|
|
14030
|
+
const heads = path16.join(common, "logs", "refs", "heads");
|
|
14031
|
+
const headLog = location.data.git ? path16.join(location.data.git.gitDir, "logs", "HEAD") : "";
|
|
13955
14032
|
const signatures = [
|
|
13956
|
-
|
|
14033
|
+
path16.join(heads, branch),
|
|
13957
14034
|
headLog,
|
|
13958
14035
|
heads,
|
|
13959
|
-
|
|
14036
|
+
path16.join(common, "packed-refs")
|
|
13960
14037
|
].map((file) => fileSignature(file) ?? "-");
|
|
13961
14038
|
const slot = `${location.data.dir}\x00${headLog}\x00${branch}`;
|
|
13962
14039
|
let resolved = origins.get(slot);
|
|
@@ -13968,7 +14045,7 @@ class TaskStore {
|
|
|
13968
14045
|
aliases.push(rename.from);
|
|
13969
14046
|
const start = branchStart(location.data, branch, aliases);
|
|
13970
14047
|
const slash = start?.indexOf("/") ?? -1;
|
|
13971
|
-
const remote = slash > 0 && !refExists(common, `refs/heads/${start}`) && (refExists(common, `refs/remotes/${start}`) || readText(
|
|
14048
|
+
const remote = slash > 0 && !refExists(common, `refs/heads/${start}`) && (refExists(common, `refs/remotes/${start}`) || readText(path16.join(common, "config")).includes(`[remote "${start.slice(0, slash)}"]`));
|
|
13972
14049
|
const name = start && (remote ? start.slice(slash + 1) : start);
|
|
13973
14050
|
resolved = {
|
|
13974
14051
|
signature: signatures.join("|"),
|
|
@@ -14206,13 +14283,13 @@ class TaskStore {
|
|
|
14206
14283
|
if (!ready.ok)
|
|
14207
14284
|
return ready;
|
|
14208
14285
|
const dirs = this.paths();
|
|
14209
|
-
const recovery =
|
|
14210
|
-
if (
|
|
14286
|
+
const recovery = path16.join(this.root, ".workit", "recovery");
|
|
14287
|
+
if (fs12.existsSync(recovery)) {
|
|
14211
14288
|
let files = 0;
|
|
14212
14289
|
let bytes = 0;
|
|
14213
14290
|
try {
|
|
14214
|
-
for (const name of
|
|
14215
|
-
const stat =
|
|
14291
|
+
for (const name of fs12.readdirSync(recovery)) {
|
|
14292
|
+
const stat = fs12.lstatSync(path16.join(recovery, name));
|
|
14216
14293
|
if (!stat.isFile())
|
|
14217
14294
|
continue;
|
|
14218
14295
|
files += 1;
|
|
@@ -14221,17 +14298,17 @@ class TaskStore {
|
|
|
14221
14298
|
} catch {}
|
|
14222
14299
|
const remove = options.pruneRecovery === true && !dryRun;
|
|
14223
14300
|
if (remove)
|
|
14224
|
-
|
|
14301
|
+
fs12.rmSync(recovery, { recursive: true, force: true });
|
|
14225
14302
|
report.legacyRecovery = { path: recovery, files, bytes, removed: remove };
|
|
14226
14303
|
}
|
|
14227
|
-
if (!
|
|
14304
|
+
if (!fs12.existsSync(dirs.tasks))
|
|
14228
14305
|
return success(null, null, report);
|
|
14229
|
-
const names =
|
|
14306
|
+
const names = fs12.readdirSync(dirs.tasks).filter((name) => validId(name));
|
|
14230
14307
|
for (const name of names) {
|
|
14231
14308
|
const file = this.eventsPath(name);
|
|
14232
14309
|
let size = 0;
|
|
14233
14310
|
try {
|
|
14234
|
-
size =
|
|
14311
|
+
size = fs12.statSync(file).size;
|
|
14235
14312
|
} catch {
|
|
14236
14313
|
continue;
|
|
14237
14314
|
}
|
|
@@ -14259,16 +14336,16 @@ class TaskStore {
|
|
|
14259
14336
|
const references = new Set;
|
|
14260
14337
|
for (const name of names)
|
|
14261
14338
|
try {
|
|
14262
|
-
for (const match of
|
|
14339
|
+
for (const match of fs12.readFileSync(this.eventsPath(name), "utf8").matchAll(/"\$blob":"([0-9a-f]{64})"/g))
|
|
14263
14340
|
references.add(match[1]);
|
|
14264
14341
|
} catch {}
|
|
14265
|
-
if (
|
|
14266
|
-
for (const name of
|
|
14342
|
+
if (fs12.existsSync(dirs.blobs))
|
|
14343
|
+
for (const name of fs12.readdirSync(dirs.blobs)) {
|
|
14267
14344
|
const digest = name.replace(/\.json$/, "");
|
|
14268
|
-
const file =
|
|
14345
|
+
const file = path16.join(dirs.blobs, name);
|
|
14269
14346
|
let stat;
|
|
14270
14347
|
try {
|
|
14271
|
-
stat =
|
|
14348
|
+
stat = fs12.lstatSync(file);
|
|
14272
14349
|
} catch {
|
|
14273
14350
|
continue;
|
|
14274
14351
|
}
|
|
@@ -14279,11 +14356,11 @@ class TaskStore {
|
|
|
14279
14356
|
report.blobs.removed += 1;
|
|
14280
14357
|
report.blobs.removedBytes += stat.size;
|
|
14281
14358
|
if (!dryRun)
|
|
14282
|
-
|
|
14359
|
+
fs12.rmSync(file, { force: true });
|
|
14283
14360
|
}
|
|
14284
14361
|
return success(null, null, null);
|
|
14285
14362
|
};
|
|
14286
|
-
const swept = dryRun ? sweep() : this.withLock(
|
|
14363
|
+
const swept = dryRun ? sweep() : this.withLock(path16.join(dirs.dir, "gc.lock"), sweep);
|
|
14287
14364
|
if (!swept.ok)
|
|
14288
14365
|
return swept;
|
|
14289
14366
|
const temporaryDirs = [
|
|
@@ -14291,17 +14368,17 @@ class TaskStore {
|
|
|
14291
14368
|
dirs.tasks,
|
|
14292
14369
|
dirs.blobs,
|
|
14293
14370
|
dirs.checkout,
|
|
14294
|
-
...names.map((name) =>
|
|
14371
|
+
...names.map((name) => path16.join(dirs.tasks, name))
|
|
14295
14372
|
];
|
|
14296
14373
|
for (const directory of temporaryDirs) {
|
|
14297
|
-
if (!
|
|
14374
|
+
if (!fs12.existsSync(directory))
|
|
14298
14375
|
continue;
|
|
14299
|
-
for (const name of
|
|
14376
|
+
for (const name of fs12.readdirSync(directory)) {
|
|
14300
14377
|
if (!name.endsWith(".tmp") && !name.endsWith(".probe"))
|
|
14301
14378
|
continue;
|
|
14302
|
-
const file =
|
|
14379
|
+
const file = path16.join(directory, name);
|
|
14303
14380
|
try {
|
|
14304
|
-
const stat =
|
|
14381
|
+
const stat = fs12.lstatSync(file);
|
|
14305
14382
|
if (!stat.isFile() || nowMs - stat.mtimeMs <= STALE_TEMPORARY_MS)
|
|
14306
14383
|
continue;
|
|
14307
14384
|
} catch {
|
|
@@ -14309,37 +14386,37 @@ class TaskStore {
|
|
|
14309
14386
|
}
|
|
14310
14387
|
report.temporary.removed += 1;
|
|
14311
14388
|
if (!dryRun)
|
|
14312
|
-
|
|
14389
|
+
fs12.rmSync(file, { force: true });
|
|
14313
14390
|
}
|
|
14314
14391
|
}
|
|
14315
14392
|
return success(null, null, report);
|
|
14316
14393
|
}
|
|
14317
14394
|
paths() {
|
|
14318
14395
|
const location = this.location();
|
|
14319
|
-
const dir = location.ok ? location.data.dir :
|
|
14320
|
-
const checkout =
|
|
14396
|
+
const dir = location.ok ? location.data.dir : path16.join(this.root, ".workit");
|
|
14397
|
+
const checkout = path16.join(dir, "checkouts", checkoutSlug(this.root));
|
|
14321
14398
|
return {
|
|
14322
14399
|
dir,
|
|
14323
14400
|
shared: location.ok ? location.data.shared : false,
|
|
14324
|
-
marker:
|
|
14401
|
+
marker: path16.join(dir, "store.json"),
|
|
14325
14402
|
checkout,
|
|
14326
|
-
workspace:
|
|
14327
|
-
checkoutLock:
|
|
14328
|
-
tasks:
|
|
14329
|
-
index:
|
|
14330
|
-
blobs:
|
|
14331
|
-
legacy:
|
|
14332
|
-
v2:
|
|
14403
|
+
workspace: path16.join(checkout, "workspace.json"),
|
|
14404
|
+
checkoutLock: path16.join(checkout, "metadata.lock"),
|
|
14405
|
+
tasks: path16.join(dir, "tasks"),
|
|
14406
|
+
index: path16.join(dir, "task-index.json"),
|
|
14407
|
+
blobs: path16.join(dir, "blobs", "candidates"),
|
|
14408
|
+
legacy: path16.join(dir, "legacy", checkoutSlug(this.root), "v2"),
|
|
14409
|
+
v2: path16.join(this.root, ".workit")
|
|
14333
14410
|
};
|
|
14334
14411
|
}
|
|
14335
14412
|
eventsPath(taskId) {
|
|
14336
|
-
return
|
|
14413
|
+
return path16.join(this.paths().tasks, taskId, "events.jsonl");
|
|
14337
14414
|
}
|
|
14338
14415
|
snapshotPath(taskId) {
|
|
14339
|
-
return
|
|
14416
|
+
return path16.join(this.paths().tasks, taskId, "snapshot.json");
|
|
14340
14417
|
}
|
|
14341
14418
|
taskLockPath(taskId) {
|
|
14342
|
-
return
|
|
14419
|
+
return path16.join(this.paths().tasks, taskId, "lock");
|
|
14343
14420
|
}
|
|
14344
14421
|
ready(write = false) {
|
|
14345
14422
|
const location = this.location();
|
|
@@ -14349,7 +14426,7 @@ class TaskStore {
|
|
|
14349
14426
|
return success(null, null, null);
|
|
14350
14427
|
const dirs = this.paths();
|
|
14351
14428
|
try {
|
|
14352
|
-
const marker = JSON.parse(
|
|
14429
|
+
const marker = JSON.parse(fs12.readFileSync(dirs.marker, "utf8"));
|
|
14353
14430
|
if (typeof marker.version === "number" && marker.version > STORE_FORMAT)
|
|
14354
14431
|
return failure2("recovery_required", `the workit store at ${dirs.dir} has format ${marker.version}; upgrade Workit to use it`, { path: dirs.marker });
|
|
14355
14432
|
} catch {}
|
|
@@ -14378,21 +14455,21 @@ class TaskStore {
|
|
|
14378
14455
|
return {
|
|
14379
14456
|
read: (digest) => {
|
|
14380
14457
|
try {
|
|
14381
|
-
return JSON.parse(
|
|
14458
|
+
return JSON.parse(fs12.readFileSync(path16.join(dir, `${digest}.json`), "utf8"));
|
|
14382
14459
|
} catch (error) {
|
|
14383
14460
|
throw new LogDamage(`stored candidate ${digest} is missing or unreadable: ${String(error)}`);
|
|
14384
14461
|
}
|
|
14385
14462
|
},
|
|
14386
14463
|
write: (digest, value) => {
|
|
14387
|
-
const file =
|
|
14388
|
-
if (
|
|
14464
|
+
const file = path16.join(dir, `${digest}.json`);
|
|
14465
|
+
if (fs12.existsSync(file)) {
|
|
14389
14466
|
const stamp = new Date;
|
|
14390
14467
|
try {
|
|
14391
|
-
|
|
14468
|
+
fs12.utimesSync(file, stamp, stamp);
|
|
14392
14469
|
return;
|
|
14393
14470
|
} catch {}
|
|
14394
14471
|
}
|
|
14395
|
-
|
|
14472
|
+
fs12.mkdirSync(dir, { recursive: true });
|
|
14396
14473
|
replaceFile(file, JSON.stringify(value), true);
|
|
14397
14474
|
}
|
|
14398
14475
|
};
|
|
@@ -14474,7 +14551,7 @@ class TaskStore {
|
|
|
14474
14551
|
}
|
|
14475
14552
|
readSnapshot(taskId) {
|
|
14476
14553
|
try {
|
|
14477
|
-
const value = JSON.parse(
|
|
14554
|
+
const value = JSON.parse(fs12.readFileSync(this.snapshotPath(taskId), "utf8"));
|
|
14478
14555
|
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))
|
|
14479
14556
|
return null;
|
|
14480
14557
|
return value;
|
|
@@ -14576,8 +14653,8 @@ class TaskStore {
|
|
|
14576
14653
|
}
|
|
14577
14654
|
}
|
|
14578
14655
|
openTask(record, type, key, legacy = null) {
|
|
14579
|
-
const dir =
|
|
14580
|
-
|
|
14656
|
+
const dir = path16.join(this.paths().tasks, record.id);
|
|
14657
|
+
fs12.mkdirSync(dir, { recursive: true });
|
|
14581
14658
|
const blobs = this.blobStore();
|
|
14582
14659
|
const bound = key ? { ...key, boundAt: key.boundAt ?? new Date().toISOString() } : null;
|
|
14583
14660
|
const event = this.event(record.id, 1, type, {
|
|
@@ -14629,11 +14706,11 @@ class TaskStore {
|
|
|
14629
14706
|
} catch {}
|
|
14630
14707
|
if (!latest || latest.events[0]?.id !== last.id)
|
|
14631
14708
|
return failure2("busy", "the task log changed during compaction; retry", { taskId });
|
|
14632
|
-
const appended =
|
|
14709
|
+
const appended = fs12.readFileSync(file).subarray(log.end, latest.end);
|
|
14633
14710
|
const bytes = Buffer.concat([Buffer.from(prefix, "utf8"), appended]);
|
|
14634
14711
|
replaceFile(file, bytes.toString("utf8"), true);
|
|
14635
14712
|
try {
|
|
14636
|
-
|
|
14713
|
+
fs12.rmSync(this.snapshotPath(taskId), { force: true });
|
|
14637
14714
|
} catch {}
|
|
14638
14715
|
const reloaded = this.load(taskId);
|
|
14639
14716
|
if (reloaded.ok && reloaded.data)
|
|
@@ -14646,7 +14723,7 @@ class TaskStore {
|
|
|
14646
14723
|
}
|
|
14647
14724
|
countEvents(file) {
|
|
14648
14725
|
try {
|
|
14649
|
-
const bytes =
|
|
14726
|
+
const bytes = fs12.readFileSync(file);
|
|
14650
14727
|
let count = 0;
|
|
14651
14728
|
for (let index = bytes.indexOf(10);index >= 0; index = bytes.indexOf(10, index + 1))
|
|
14652
14729
|
count += 1;
|
|
@@ -14668,8 +14745,8 @@ class TaskStore {
|
|
|
14668
14745
|
return bound.ok ? success(null, null, bound.data[0] ?? null) : bound;
|
|
14669
14746
|
}
|
|
14670
14747
|
withKeyLock(key, operation) {
|
|
14671
|
-
const digest =
|
|
14672
|
-
return this.withLock(
|
|
14748
|
+
const digest = createHash11("sha256").update(key).digest("hex").slice(0, 32);
|
|
14749
|
+
return this.withLock(path16.join(this.paths().dir, "keys", `${digest}.lock`), operation);
|
|
14673
14750
|
}
|
|
14674
14751
|
bindLocked(taskId, key, timestamp) {
|
|
14675
14752
|
const current = this.readWorkspace();
|
|
@@ -14810,7 +14887,7 @@ class TaskStore {
|
|
|
14810
14887
|
writeWorkspace(record) {
|
|
14811
14888
|
const file = this.paths().workspace;
|
|
14812
14889
|
try {
|
|
14813
|
-
|
|
14890
|
+
fs12.mkdirSync(path16.dirname(file), { recursive: true });
|
|
14814
14891
|
replaceFile(file, `${canonicalJson(record)}
|
|
14815
14892
|
`, true);
|
|
14816
14893
|
return success(null, null, null);
|
|
@@ -14820,7 +14897,7 @@ class TaskStore {
|
|
|
14820
14897
|
}
|
|
14821
14898
|
readIndex() {
|
|
14822
14899
|
try {
|
|
14823
|
-
const value = JSON.parse(
|
|
14900
|
+
const value = JSON.parse(fs12.readFileSync(this.paths().index, "utf8"));
|
|
14824
14901
|
if (!isObject6(value) || value.version !== INDEX_VERSION || !isObject6(value.tasks))
|
|
14825
14902
|
return {};
|
|
14826
14903
|
const tasks = {};
|
|
@@ -14834,7 +14911,7 @@ class TaskStore {
|
|
|
14834
14911
|
}
|
|
14835
14912
|
writeIndex(entries) {
|
|
14836
14913
|
try {
|
|
14837
|
-
|
|
14914
|
+
fs12.mkdirSync(this.paths().tasks, { recursive: true });
|
|
14838
14915
|
replaceFile(this.paths().index, JSON.stringify({
|
|
14839
14916
|
version: INDEX_VERSION,
|
|
14840
14917
|
tasks: Object.fromEntries(entries.map((entry) => [entry.id, entry]))
|
|
@@ -14888,23 +14965,23 @@ class TaskStore {
|
|
|
14888
14965
|
return failure2("revision_conflict", "workspace revision does not match; omit expectedWorkspaceRevision to use the current record", { expectedWorkspaceRevision: expected, actualWorkspaceRevision: actual });
|
|
14889
14966
|
}
|
|
14890
14967
|
v2Dirs() {
|
|
14891
|
-
return [...new Set([this.root, this.origin])].map((dir) =>
|
|
14968
|
+
return [...new Set([this.root, this.origin])].map((dir) => path16.join(dir, ".workit"));
|
|
14892
14969
|
}
|
|
14893
14970
|
pendingMigrations() {
|
|
14894
14971
|
return this.v2Dirs().filter((dir) => {
|
|
14895
|
-
const raw = this.readV2Workspace(
|
|
14972
|
+
const raw = this.readV2Workspace(path16.join(dir, "workspace.json"));
|
|
14896
14973
|
return raw !== null && raw !== TOMBSTONE;
|
|
14897
14974
|
});
|
|
14898
14975
|
}
|
|
14899
14976
|
migrateV2(v2) {
|
|
14900
14977
|
const dirs = this.paths();
|
|
14901
|
-
const v2Workspace =
|
|
14902
|
-
const v2Tasks =
|
|
14903
|
-
const legacy =
|
|
14978
|
+
const v2Workspace = path16.join(v2, "workspace.json");
|
|
14979
|
+
const v2Tasks = path16.join(v2, "tasks");
|
|
14980
|
+
const legacy = path16.join(dirs.dir, "legacy", checkoutSlug(path16.dirname(v2)), "v2");
|
|
14904
14981
|
const raw = this.readV2Workspace(v2Workspace);
|
|
14905
14982
|
if (raw === null || raw === TOMBSTONE)
|
|
14906
14983
|
return success(null, null, null);
|
|
14907
|
-
return this.withLock(dirs.checkoutLock, () => this.withLock(
|
|
14984
|
+
return this.withLock(dirs.checkoutLock, () => this.withLock(path16.join(v2, "metadata.lock"), () => {
|
|
14908
14985
|
const workspace = this.readV2Workspace(v2Workspace);
|
|
14909
14986
|
if (workspace === null || workspace === TOMBSTONE)
|
|
14910
14987
|
return success(null, null, null);
|
|
@@ -14913,7 +14990,7 @@ class TaskStore {
|
|
|
14913
14990
|
return failure2("recovery_required", `cannot migrate the 2.x store at ${v2}: ${parsedWorkspace.error}; move it aside to start fresh`, { path: v2Workspace });
|
|
14914
14991
|
let files = [];
|
|
14915
14992
|
try {
|
|
14916
|
-
files =
|
|
14993
|
+
files = fs12.readdirSync(v2Tasks).filter((name) => name.endsWith(".json") && validId(name.slice(0, -5))).filter((name) => !this.isStub(path16.join(v2Tasks, name)));
|
|
14917
14994
|
} catch {}
|
|
14918
14995
|
const current = this.readWorkspace();
|
|
14919
14996
|
if (!current.ok)
|
|
@@ -14931,22 +15008,22 @@ class TaskStore {
|
|
|
14931
15008
|
let skipped = 0;
|
|
14932
15009
|
const done = new Map;
|
|
14933
15010
|
try {
|
|
14934
|
-
|
|
15011
|
+
fs12.mkdirSync(path16.join(legacy, "tasks"), { recursive: true });
|
|
14935
15012
|
for (const name of ["workspace.json", "index.json"])
|
|
14936
|
-
if (
|
|
14937
|
-
|
|
15013
|
+
if (fs12.existsSync(path16.join(v2, name)))
|
|
15014
|
+
fs12.copyFileSync(path16.join(v2, name), path16.join(legacy, name));
|
|
14938
15015
|
for (const name of files) {
|
|
14939
15016
|
const id = name.slice(0, -5);
|
|
14940
|
-
const file =
|
|
14941
|
-
const bytes =
|
|
15017
|
+
const file = path16.join(v2Tasks, name);
|
|
15018
|
+
const bytes = fs12.readFileSync(file, "utf8");
|
|
14942
15019
|
const digest = sha256(bytes);
|
|
14943
|
-
|
|
15020
|
+
fs12.writeFileSync(path16.join(legacy, "tasks", name), bytes);
|
|
14944
15021
|
const parsed = this.parseRecord(bytes, taskRecordSchema, "2.x task");
|
|
14945
15022
|
if (!parsed.ok || parsed.data.id !== id)
|
|
14946
15023
|
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 });
|
|
14947
15024
|
const record = { ...parsed.data, workspaceId: target.id };
|
|
14948
|
-
const origin = { path:
|
|
14949
|
-
if (!
|
|
15025
|
+
const origin = { path: path16.join(legacy, "tasks", name), digest };
|
|
15026
|
+
if (!fs12.existsSync(this.eventsPath(id))) {
|
|
14950
15027
|
this.openTask(record, "migrated.from_v2", null, origin);
|
|
14951
15028
|
migrated += 1;
|
|
14952
15029
|
} else {
|
|
@@ -14981,8 +15058,8 @@ class TaskStore {
|
|
|
14981
15058
|
try {
|
|
14982
15059
|
let complete = true;
|
|
14983
15060
|
for (const [name, digest] of done) {
|
|
14984
|
-
const file =
|
|
14985
|
-
if (sha256(
|
|
15061
|
+
const file = path16.join(v2Tasks, name);
|
|
15062
|
+
if (sha256(fs12.readFileSync(file, "utf8")) !== digest) {
|
|
14986
15063
|
complete = false;
|
|
14987
15064
|
continue;
|
|
14988
15065
|
}
|
|
@@ -14992,7 +15069,7 @@ class TaskStore {
|
|
|
14992
15069
|
return failure2("busy", `the 2.x store at ${v2} changed during migration; retry`, {
|
|
14993
15070
|
path: v2
|
|
14994
15071
|
});
|
|
14995
|
-
|
|
15072
|
+
fs12.rmSync(path16.join(v2, "index.json"), { force: true });
|
|
14996
15073
|
this.writeTombstone(v2, target.id);
|
|
14997
15074
|
} catch (error) {
|
|
14998
15075
|
return failure2("storage_error", `cannot finish the 2.x migration: ${String(error)}`, {
|
|
@@ -15012,45 +15089,45 @@ class TaskStore {
|
|
|
15012
15089
|
}
|
|
15013
15090
|
adoptLocalStore() {
|
|
15014
15091
|
const dirs = this.paths();
|
|
15015
|
-
const marker =
|
|
15016
|
-
if (!dirs.shared || !
|
|
15092
|
+
const marker = path16.join(dirs.v2, "store.json");
|
|
15093
|
+
if (!dirs.shared || !fs12.existsSync(marker))
|
|
15017
15094
|
return success(null, null, null);
|
|
15018
15095
|
return this.withLock(dirs.checkoutLock, () => {
|
|
15019
|
-
if (!
|
|
15096
|
+
if (!fs12.existsSync(marker))
|
|
15020
15097
|
return success(null, null, null);
|
|
15021
15098
|
let tasks = 0;
|
|
15022
15099
|
try {
|
|
15023
15100
|
const merge = (from, to) => {
|
|
15024
|
-
if (!
|
|
15025
|
-
|
|
15101
|
+
if (!fs12.existsSync(to)) {
|
|
15102
|
+
fs12.mkdirSync(path16.dirname(to), { recursive: true });
|
|
15026
15103
|
try {
|
|
15027
|
-
|
|
15104
|
+
fs12.renameSync(from, to);
|
|
15028
15105
|
} catch {
|
|
15029
|
-
|
|
15030
|
-
|
|
15106
|
+
fs12.cpSync(from, to, { recursive: true, errorOnExist: true, force: false });
|
|
15107
|
+
fs12.rmSync(from, { recursive: true, force: true });
|
|
15031
15108
|
}
|
|
15032
15109
|
return;
|
|
15033
15110
|
}
|
|
15034
|
-
if (
|
|
15035
|
-
for (const name of
|
|
15036
|
-
merge(
|
|
15111
|
+
if (fs12.lstatSync(from).isDirectory() && fs12.lstatSync(to).isDirectory())
|
|
15112
|
+
for (const name of fs12.readdirSync(from))
|
|
15113
|
+
merge(path16.join(from, name), path16.join(to, name));
|
|
15037
15114
|
};
|
|
15038
15115
|
for (const sub of ["tasks", "checkouts", "blobs", "legacy"]) {
|
|
15039
|
-
const from =
|
|
15040
|
-
if (!
|
|
15116
|
+
const from = path16.join(dirs.v2, sub);
|
|
15117
|
+
if (!fs12.existsSync(from))
|
|
15041
15118
|
continue;
|
|
15042
15119
|
if (sub === "tasks") {
|
|
15043
|
-
for (const name of
|
|
15044
|
-
if (validId(name) && !
|
|
15120
|
+
for (const name of fs12.readdirSync(from))
|
|
15121
|
+
if (validId(name) && !fs12.existsSync(path16.join(dirs.dir, sub, name)))
|
|
15045
15122
|
tasks += 1;
|
|
15046
15123
|
}
|
|
15047
|
-
merge(from,
|
|
15124
|
+
merge(from, path16.join(dirs.dir, sub));
|
|
15048
15125
|
}
|
|
15049
|
-
const ledger =
|
|
15050
|
-
if (
|
|
15051
|
-
merge(ledger,
|
|
15052
|
-
|
|
15053
|
-
|
|
15126
|
+
const ledger = path16.join(dirs.v2, "ledger");
|
|
15127
|
+
if (fs12.existsSync(ledger) && !fs12.existsSync(path16.join(dirs.dir, "ledger")))
|
|
15128
|
+
merge(ledger, path16.join(dirs.dir, "ledger"));
|
|
15129
|
+
fs12.rmSync(path16.join(dirs.v2, "task-index.json"), { force: true });
|
|
15130
|
+
fs12.renameSync(marker, path16.join(dirs.v2, "store.moved.json"));
|
|
15054
15131
|
} catch (error) {
|
|
15055
15132
|
return failure2("storage_error", `cannot move ${dirs.v2} into ${dirs.dir}: ${String(error)}`, {
|
|
15056
15133
|
path: dirs.v2
|
|
@@ -15070,7 +15147,7 @@ class TaskStore {
|
|
|
15070
15147
|
readV2Workspace(file) {
|
|
15071
15148
|
let bytes;
|
|
15072
15149
|
try {
|
|
15073
|
-
bytes =
|
|
15150
|
+
bytes = fs12.readFileSync(file, "utf8");
|
|
15074
15151
|
} catch {
|
|
15075
15152
|
return null;
|
|
15076
15153
|
}
|
|
@@ -15088,7 +15165,7 @@ class TaskStore {
|
|
|
15088
15165
|
schemaVersion: SCHEMA_VERSION,
|
|
15089
15166
|
id: workspaceId ?? newId(),
|
|
15090
15167
|
revision: newRevision(),
|
|
15091
|
-
root:
|
|
15168
|
+
root: path16.dirname(v2),
|
|
15092
15169
|
runtime: { createdWith: version, updatedWith: version },
|
|
15093
15170
|
writer: null,
|
|
15094
15171
|
store: {
|
|
@@ -15099,12 +15176,12 @@ class TaskStore {
|
|
|
15099
15176
|
},
|
|
15100
15177
|
critical: ["store"]
|
|
15101
15178
|
};
|
|
15102
|
-
|
|
15103
|
-
const ignore =
|
|
15104
|
-
if (!
|
|
15105
|
-
|
|
15179
|
+
fs12.mkdirSync(v2, { recursive: true });
|
|
15180
|
+
const ignore = path16.join(v2, ".gitignore");
|
|
15181
|
+
if (!fs12.existsSync(ignore))
|
|
15182
|
+
fs12.writeFileSync(ignore, `*
|
|
15106
15183
|
`);
|
|
15107
|
-
replaceFile(
|
|
15184
|
+
replaceFile(path16.join(v2, "workspace.json"), `${JSON.stringify(marker, null, 2)}
|
|
15108
15185
|
`, true);
|
|
15109
15186
|
}
|
|
15110
15187
|
stubFor(taskId) {
|
|
@@ -15120,7 +15197,7 @@ class TaskStore {
|
|
|
15120
15197
|
}
|
|
15121
15198
|
isStub(file) {
|
|
15122
15199
|
try {
|
|
15123
|
-
const value = JSON.parse(
|
|
15200
|
+
const value = JSON.parse(fs12.readFileSync(file, "utf8"));
|
|
15124
15201
|
return isObject6(value) && isObject6(value.store) && value.store.format === "workit-store";
|
|
15125
15202
|
} catch {
|
|
15126
15203
|
return false;
|
|
@@ -15128,32 +15205,32 @@ class TaskStore {
|
|
|
15128
15205
|
}
|
|
15129
15206
|
writeTombstoneIfMissing() {
|
|
15130
15207
|
try {
|
|
15131
|
-
const v2 =
|
|
15132
|
-
if (
|
|
15208
|
+
const v2 = path16.join(this.root, ".workit");
|
|
15209
|
+
if (fs12.existsSync(path16.join(v2, "workspace.json")))
|
|
15133
15210
|
return;
|
|
15134
15211
|
let id = null;
|
|
15135
15212
|
try {
|
|
15136
|
-
id = JSON.parse(
|
|
15213
|
+
id = JSON.parse(fs12.readFileSync(this.paths().workspace, "utf8")).id ?? null;
|
|
15137
15214
|
} catch {}
|
|
15138
15215
|
this.writeTombstone(v2, id);
|
|
15139
15216
|
} catch {}
|
|
15140
15217
|
}
|
|
15141
15218
|
initializeStorage() {
|
|
15142
15219
|
const dirs = this.paths();
|
|
15143
|
-
retryTransient(() =>
|
|
15144
|
-
retryTransient(() =>
|
|
15145
|
-
if (!
|
|
15220
|
+
retryTransient(() => fs12.mkdirSync(dirs.checkout, { recursive: true }));
|
|
15221
|
+
retryTransient(() => fs12.mkdirSync(dirs.tasks, { recursive: true }));
|
|
15222
|
+
if (!fs12.existsSync(dirs.marker))
|
|
15146
15223
|
replaceFile(dirs.marker, `${JSON.stringify({ format: "workit-store", version: STORE_FORMAT, createdWith: runtimeVersion() })}
|
|
15147
15224
|
`, false);
|
|
15148
15225
|
if (!dirs.shared) {
|
|
15149
|
-
const ignore =
|
|
15226
|
+
const ignore = path16.join(dirs.dir, ".gitignore");
|
|
15150
15227
|
let current = null;
|
|
15151
15228
|
try {
|
|
15152
|
-
current =
|
|
15229
|
+
current = fs12.readFileSync(ignore, "utf8");
|
|
15153
15230
|
} catch {}
|
|
15154
15231
|
if (current !== `*
|
|
15155
15232
|
`)
|
|
15156
|
-
retryTransient(() =>
|
|
15233
|
+
retryTransient(() => fs12.writeFileSync(ignore, `*
|
|
15157
15234
|
`));
|
|
15158
15235
|
}
|
|
15159
15236
|
this.writeTombstoneIfMissing();
|
|
@@ -15169,7 +15246,7 @@ class TaskStore {
|
|
|
15169
15246
|
shouldReclaim: ({ payload, nowMs }) => {
|
|
15170
15247
|
let ageMs = null;
|
|
15171
15248
|
try {
|
|
15172
|
-
ageMs = nowMs -
|
|
15249
|
+
ageMs = nowMs - fs12.lstatSync(lockPath).mtimeMs;
|
|
15173
15250
|
} catch {}
|
|
15174
15251
|
return classifyLockOwner(payload, ageMs, localLockHost(), TASK_STORE_LOCK).state === "stale";
|
|
15175
15252
|
},
|
|
@@ -15206,7 +15283,7 @@ class TaskStore {
|
|
|
15206
15283
|
withLock(lockPath, operation) {
|
|
15207
15284
|
try {
|
|
15208
15285
|
this.initializeStorage();
|
|
15209
|
-
|
|
15286
|
+
fs12.mkdirSync(path16.dirname(lockPath), { recursive: true });
|
|
15210
15287
|
} catch (error) {
|
|
15211
15288
|
return failure2("storage_error", `unable to initialize store: ${String(error)}`, {
|
|
15212
15289
|
path: this.paths().dir
|
|
@@ -15246,18 +15323,18 @@ class TaskStore {
|
|
|
15246
15323
|
lockDirWritable(lockPath) {
|
|
15247
15324
|
const probe = `${lockPath}.${process.pid}.${randomUUID3()}.probe`;
|
|
15248
15325
|
try {
|
|
15249
|
-
|
|
15326
|
+
fs12.closeSync(fs12.openSync(probe, "wx", 384));
|
|
15250
15327
|
} catch {
|
|
15251
15328
|
return false;
|
|
15252
15329
|
}
|
|
15253
15330
|
try {
|
|
15254
|
-
|
|
15331
|
+
fs12.rmSync(probe, { force: true });
|
|
15255
15332
|
} catch {}
|
|
15256
15333
|
return true;
|
|
15257
15334
|
}
|
|
15258
15335
|
lockHolderPresent(lockPath) {
|
|
15259
15336
|
try {
|
|
15260
|
-
|
|
15337
|
+
fs12.lstatSync(lockPath);
|
|
15261
15338
|
return true;
|
|
15262
15339
|
} catch (error) {
|
|
15263
15340
|
return error?.code !== "ENOENT";
|
|
@@ -15269,12 +15346,12 @@ class TaskStore {
|
|
|
15269
15346
|
if (isTransientWindowsError(error) && !this.lockHolderPresent(lockPath) && !this.lockDirWritable(lockPath))
|
|
15270
15347
|
return failure2("storage_error", `cannot create the workit lock (${code}); no other Workit call holds it`, {
|
|
15271
15348
|
path: lockPath,
|
|
15272
|
-
guidance: `Check permissions and the read-only attribute on ${
|
|
15349
|
+
guidance: `Check permissions and the read-only attribute on ${path16.dirname(lockPath)}.`
|
|
15273
15350
|
});
|
|
15274
15351
|
if (code === "EEXIST" || code === "file_lock_timeout" || code === "file_lock_stale" || isTransientWindowsError(error)) {
|
|
15275
15352
|
let lock = null;
|
|
15276
15353
|
try {
|
|
15277
|
-
lock = parseMetadataLockOrNull(
|
|
15354
|
+
lock = parseMetadataLockOrNull(fs12.readFileSync(lockPath, "utf8"));
|
|
15278
15355
|
} catch {}
|
|
15279
15356
|
return failure2("busy", `workit lock is held by another Workit call${lock ? ` (pid ${lock.pid} on ${lock.host})` : ""}; retry shortly`, {
|
|
15280
15357
|
outcome: "not_started",
|
|
@@ -15293,26 +15370,26 @@ var isUncertainWorker = (state) => UNCERTAIN_WORKER_STATES.includes(state);
|
|
|
15293
15370
|
var workerBlocksTransition = (transition, state) => transition === "pause" ? false : isUncertainWorker(state);
|
|
15294
15371
|
|
|
15295
15372
|
// packages/workit-core/src/core/task-evaluation.ts
|
|
15296
|
-
import { createHash as
|
|
15297
|
-
import * as
|
|
15373
|
+
import { createHash as createHash12 } from "node:crypto";
|
|
15374
|
+
import * as fs14 from "node:fs";
|
|
15298
15375
|
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
15299
|
-
import
|
|
15376
|
+
import path18 from "node:path";
|
|
15300
15377
|
|
|
15301
15378
|
// packages/workit-core/src/check-config.ts
|
|
15302
15379
|
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
15303
|
-
import
|
|
15304
|
-
import
|
|
15380
|
+
import fs13 from "node:fs";
|
|
15381
|
+
import path17 from "node:path";
|
|
15305
15382
|
var SCRIPT_CHECKS = ["test", "lint", "typecheck", "check"];
|
|
15306
15383
|
var CHECKS_FILE = ".workit/checks.json";
|
|
15307
15384
|
var LEGACY_CHECKS_FILE = "workit.checks.json";
|
|
15308
15385
|
function checksConfigFile(root) {
|
|
15309
|
-
const current =
|
|
15310
|
-
const legacy =
|
|
15311
|
-
return !
|
|
15386
|
+
const current = path17.join(root, CHECKS_FILE);
|
|
15387
|
+
const legacy = path17.join(root, LEGACY_CHECKS_FILE);
|
|
15388
|
+
return !fs13.existsSync(current) && fs13.existsSync(legacy) ? legacy : current;
|
|
15312
15389
|
}
|
|
15313
15390
|
function repoHeavyCommands(root) {
|
|
15314
15391
|
try {
|
|
15315
|
-
const value = JSON.parse(
|
|
15392
|
+
const value = JSON.parse(fs13.readFileSync(checksConfigFile(root), "utf8"));
|
|
15316
15393
|
const resources = isRecord3(value) ? value.resources : undefined;
|
|
15317
15394
|
const list = isRecord3(resources) ? resources.heavyCommands : undefined;
|
|
15318
15395
|
return Array.isArray(list) ? list.filter((item) => typeof item === "string") : [];
|
|
@@ -15370,10 +15447,10 @@ var git4 = (cwd, args) => {
|
|
|
15370
15447
|
return value || null;
|
|
15371
15448
|
};
|
|
15372
15449
|
function checkRoot(cwd) {
|
|
15373
|
-
return
|
|
15450
|
+
return path17.resolve(git4(cwd, ["rev-parse", "--show-toplevel"]) ?? cwd);
|
|
15374
15451
|
}
|
|
15375
15452
|
var packageManager = (root) => {
|
|
15376
|
-
const has = (file) =>
|
|
15453
|
+
const has = (file) => fs13.existsSync(path17.join(root, file));
|
|
15377
15454
|
if (has("bun.lock") || has("bun.lockb"))
|
|
15378
15455
|
return "bun";
|
|
15379
15456
|
if (has("pnpm-lock.yaml"))
|
|
@@ -15393,7 +15470,7 @@ var CHECK_NAME = /^[a-z0-9][a-z0-9:._-]{0,63}$/u;
|
|
|
15393
15470
|
function detectedChecks(root) {
|
|
15394
15471
|
const read = (file) => {
|
|
15395
15472
|
try {
|
|
15396
|
-
return
|
|
15473
|
+
return fs13.readFileSync(path17.join(root, file), "utf8");
|
|
15397
15474
|
} catch {
|
|
15398
15475
|
return null;
|
|
15399
15476
|
}
|
|
@@ -15433,7 +15510,7 @@ var GATES = ["testing", "verification"];
|
|
|
15433
15510
|
function loadCheckConfig(cwd) {
|
|
15434
15511
|
const root = checkRoot(cwd);
|
|
15435
15512
|
const file = checksConfigFile(root);
|
|
15436
|
-
const legacy =
|
|
15513
|
+
const legacy = path17.basename(file) === LEGACY_CHECKS_FILE;
|
|
15437
15514
|
const label = legacy ? LEGACY_CHECKS_FILE : CHECKS_FILE;
|
|
15438
15515
|
const note = legacy ? {
|
|
15439
15516
|
note: `${LEGACY_CHECKS_FILE} is deprecated; move it to ${CHECKS_FILE} (workit doctor --fix)`
|
|
@@ -15448,7 +15525,7 @@ function loadCheckConfig(cwd) {
|
|
|
15448
15525
|
});
|
|
15449
15526
|
let text = null;
|
|
15450
15527
|
try {
|
|
15451
|
-
text =
|
|
15528
|
+
text = fs13.readFileSync(file, "utf8");
|
|
15452
15529
|
} catch (error) {
|
|
15453
15530
|
if (error.code !== "ENOENT")
|
|
15454
15531
|
return none(`cannot read ${label}: ${error.message}`);
|
|
@@ -15511,10 +15588,10 @@ function workitAvailable(env = process.env) {
|
|
|
15511
15588
|
return workitOnPath;
|
|
15512
15589
|
const windows = process.platform === "win32";
|
|
15513
15590
|
const exts = windows ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
|
|
15514
|
-
const dirs = (env.PATH ?? env.Path ?? "").split(
|
|
15591
|
+
const dirs = (env.PATH ?? env.Path ?? "").split(path17.delimiter).filter(Boolean);
|
|
15515
15592
|
workitOnPath = dirs.some((dir) => exts.some((ext) => {
|
|
15516
15593
|
try {
|
|
15517
|
-
return
|
|
15594
|
+
return fs13.statSync(path17.join(dir, `workit${ext}`)).isFile();
|
|
15518
15595
|
} catch {
|
|
15519
15596
|
return false;
|
|
15520
15597
|
}
|
|
@@ -15526,15 +15603,15 @@ function checkCommand(args, version, onPath = workitAvailable()) {
|
|
|
15526
15603
|
}
|
|
15527
15604
|
|
|
15528
15605
|
// packages/workit-core/src/core/task-evaluation.ts
|
|
15529
|
-
var digestBytes = (value) =>
|
|
15530
|
-
var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${
|
|
15531
|
-
var relative = (root, candidate) =>
|
|
15606
|
+
var digestBytes = (value) => createHash12("sha256").update(value).digest("hex");
|
|
15607
|
+
var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path18.sep}`);
|
|
15608
|
+
var relative = (root, candidate) => path18.relative(root, candidate).split(path18.sep).join("/") || ".";
|
|
15532
15609
|
var canonicalPath = (value) => {
|
|
15533
15610
|
if (typeof value !== "string" || !value)
|
|
15534
15611
|
return null;
|
|
15535
15612
|
if (value.includes("\\") || value.split("/").includes(".."))
|
|
15536
15613
|
return null;
|
|
15537
|
-
const normalized =
|
|
15614
|
+
const normalized = path18.posix.normalize(value);
|
|
15538
15615
|
if (normalized === ".." || normalized.startsWith("../") || normalized.startsWith("/"))
|
|
15539
15616
|
return null;
|
|
15540
15617
|
return normalized === "." ? "." : normalized.replace(/\/$/, "");
|
|
@@ -15582,21 +15659,21 @@ var gitPaths = (root) => {
|
|
|
15582
15659
|
git: !/not a git repository/i.test(stderr)
|
|
15583
15660
|
};
|
|
15584
15661
|
}
|
|
15585
|
-
const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(
|
|
15662
|
+
const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path18.sep).join("/")) : [];
|
|
15586
15663
|
const stagedDeleted = spawnSync10("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
|
|
15587
15664
|
if (stagedDeleted.status !== 0) {
|
|
15588
15665
|
const stderr = stagedDeleted.stderr?.toString("utf8") ?? "";
|
|
15589
15666
|
if (!/not a git repository/i.test(stderr))
|
|
15590
15667
|
return { paths, uncertain: true, git: true };
|
|
15591
15668
|
} else if (stagedDeleted.stdout) {
|
|
15592
|
-
paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(
|
|
15669
|
+
paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path18.sep).join("/")));
|
|
15593
15670
|
}
|
|
15594
15671
|
return { paths: [...new Set(paths)], uncertain: false, git: true };
|
|
15595
15672
|
};
|
|
15596
15673
|
var walk = (root, directory, output) => {
|
|
15597
15674
|
let names;
|
|
15598
15675
|
try {
|
|
15599
|
-
names =
|
|
15676
|
+
names = fs14.readdirSync(directory);
|
|
15600
15677
|
} catch {
|
|
15601
15678
|
return true;
|
|
15602
15679
|
}
|
|
@@ -15604,10 +15681,10 @@ var walk = (root, directory, output) => {
|
|
|
15604
15681
|
for (const name of names) {
|
|
15605
15682
|
if (name === ".git" || name === ".workit")
|
|
15606
15683
|
continue;
|
|
15607
|
-
const target =
|
|
15684
|
+
const target = path18.join(directory, name);
|
|
15608
15685
|
let stat;
|
|
15609
15686
|
try {
|
|
15610
|
-
stat =
|
|
15687
|
+
stat = fs14.lstatSync(target);
|
|
15611
15688
|
} catch {
|
|
15612
15689
|
uncertain = true;
|
|
15613
15690
|
continue;
|
|
@@ -15622,14 +15699,14 @@ var walk = (root, directory, output) => {
|
|
|
15622
15699
|
var scopeRoots = (root, scope) => {
|
|
15623
15700
|
const roots = [];
|
|
15624
15701
|
for (const item of scope.paths.length ? scope.paths : ["."]) {
|
|
15625
|
-
const target =
|
|
15702
|
+
const target = path18.resolve(root, item);
|
|
15626
15703
|
if (!inside(root, target))
|
|
15627
15704
|
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` }] });
|
|
15628
15705
|
let ancestor = target;
|
|
15629
|
-
while (!
|
|
15630
|
-
ancestor =
|
|
15706
|
+
while (!fs14.existsSync(ancestor) && ancestor !== root)
|
|
15707
|
+
ancestor = path18.dirname(ancestor);
|
|
15631
15708
|
try {
|
|
15632
|
-
if (!inside(root,
|
|
15709
|
+
if (!inside(root, fs14.realpathSync(ancestor)))
|
|
15633
15710
|
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` }] });
|
|
15634
15711
|
} catch {
|
|
15635
15712
|
return failure2("invalid_input", `candidate scope cannot be inspected: ${item}`);
|
|
@@ -15641,7 +15718,7 @@ var scopeRoots = (root, scope) => {
|
|
|
15641
15718
|
function captureCandidate(root, scope, environment = []) {
|
|
15642
15719
|
let checkout;
|
|
15643
15720
|
try {
|
|
15644
|
-
checkout =
|
|
15721
|
+
checkout = fs14.realpathSync(root);
|
|
15645
15722
|
} catch {
|
|
15646
15723
|
return failure2("invalid_input", "candidate root does not exist");
|
|
15647
15724
|
}
|
|
@@ -15659,11 +15736,11 @@ function captureCandidate(root, scope, environment = []) {
|
|
|
15659
15736
|
if (item === ".git" || item === ".workit")
|
|
15660
15737
|
continue;
|
|
15661
15738
|
names.add(item);
|
|
15662
|
-
if (!
|
|
15739
|
+
if (!fs14.existsSync(target))
|
|
15663
15740
|
continue;
|
|
15664
15741
|
let stat;
|
|
15665
15742
|
try {
|
|
15666
|
-
stat =
|
|
15743
|
+
stat = fs14.lstatSync(target);
|
|
15667
15744
|
} catch {
|
|
15668
15745
|
uncertain = true;
|
|
15669
15746
|
continue;
|
|
@@ -15679,17 +15756,17 @@ function captureCandidate(root, scope, environment = []) {
|
|
|
15679
15756
|
for (const item of [...names].toSorted()) {
|
|
15680
15757
|
if (!scopeMatches(item, normalizedScope))
|
|
15681
15758
|
continue;
|
|
15682
|
-
const target =
|
|
15759
|
+
const target = path18.join(checkout, item);
|
|
15683
15760
|
try {
|
|
15684
|
-
const stat =
|
|
15761
|
+
const stat = fs14.lstatSync(target);
|
|
15685
15762
|
if (stat.isSymbolicLink()) {
|
|
15686
|
-
const link =
|
|
15763
|
+
const link = fs14.readlinkSync(target);
|
|
15687
15764
|
files.push({ path: item, kind: "symlink", digest: digestBytes(link), executable: null });
|
|
15688
15765
|
} else if (stat.isFile()) {
|
|
15689
15766
|
files.push({
|
|
15690
15767
|
path: item,
|
|
15691
15768
|
kind: "file",
|
|
15692
|
-
digest: digestBytes(
|
|
15769
|
+
digest: digestBytes(fs14.readFileSync(target)),
|
|
15693
15770
|
executable: (stat.mode & 73) !== 0
|
|
15694
15771
|
});
|
|
15695
15772
|
} else if (!stat.isDirectory()) {
|
|
@@ -15854,7 +15931,7 @@ var findingVerificationPasses = (findingCandidateId, evidence) => evidence.statu
|
|
|
15854
15931
|
var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
15855
15932
|
let root;
|
|
15856
15933
|
try {
|
|
15857
|
-
root =
|
|
15934
|
+
root = fs14.realpathSync(checkoutRoot);
|
|
15858
15935
|
} catch {
|
|
15859
15936
|
return failure2("permission_denied", "checkout root is unavailable");
|
|
15860
15937
|
}
|
|
@@ -15863,23 +15940,23 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
|
15863
15940
|
continue;
|
|
15864
15941
|
if (!reference.digest)
|
|
15865
15942
|
return failure2("invalid_input", "document references require a byte digest");
|
|
15866
|
-
const target =
|
|
15867
|
-
if (target !== root && !target.startsWith(`${root}${
|
|
15943
|
+
const target = path18.resolve(root, reference.path);
|
|
15944
|
+
if (target !== root && !target.startsWith(`${root}${path18.sep}`))
|
|
15868
15945
|
return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
|
|
15869
15946
|
fields: [
|
|
15870
15947
|
{ path: "contentRefs.path", reason: `${reference.path} is outside the checkout` }
|
|
15871
15948
|
]
|
|
15872
15949
|
});
|
|
15873
15950
|
try {
|
|
15874
|
-
const below =
|
|
15951
|
+
const below = path18.relative(root, target);
|
|
15875
15952
|
let current = root;
|
|
15876
|
-
for (const segment of below.split(
|
|
15953
|
+
for (const segment of below.split(path18.sep)) {
|
|
15877
15954
|
if (!segment)
|
|
15878
15955
|
continue;
|
|
15879
|
-
current =
|
|
15880
|
-
const stat =
|
|
15881
|
-
const real =
|
|
15882
|
-
if (real !== root && !real.startsWith(`${root}${
|
|
15956
|
+
current = path18.join(current, segment);
|
|
15957
|
+
const stat = fs14.lstatSync(current);
|
|
15958
|
+
const real = fs14.realpathSync(current);
|
|
15959
|
+
if (real !== root && !real.startsWith(`${root}${path18.sep}`))
|
|
15883
15960
|
return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
|
|
15884
15961
|
fields: [
|
|
15885
15962
|
{
|
|
@@ -15895,7 +15972,7 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
|
15895
15972
|
if (current !== target && !stat.isDirectory())
|
|
15896
15973
|
return failure2("invalid_input", "document reference ancestor is not a directory");
|
|
15897
15974
|
}
|
|
15898
|
-
if (digestBytes(
|
|
15975
|
+
if (digestBytes(fs14.readFileSync(target)) !== reference.digest)
|
|
15899
15976
|
return failure2("permission_denied", "decision document bytes have changed");
|
|
15900
15977
|
} catch {
|
|
15901
15978
|
return failure2("invalid_input", "decision document is unavailable");
|
|
@@ -18175,9 +18252,9 @@ var capabilitiesFor = (descriptor, observed = {}) => descriptor.capabilities.map
|
|
|
18175
18252
|
};
|
|
18176
18253
|
});
|
|
18177
18254
|
// packages/workit-core/src/hooks/context.ts
|
|
18178
|
-
import { createHash as
|
|
18179
|
-
import
|
|
18180
|
-
import
|
|
18255
|
+
import { createHash as createHash13 } from "node:crypto";
|
|
18256
|
+
import fs15 from "node:fs";
|
|
18257
|
+
import path19 from "node:path";
|
|
18181
18258
|
var MIGRATION_PENDING_NOTE = "workit migration pending — run `workit task status`";
|
|
18182
18259
|
var migrationPending = (result) => !result.ok && result.code === "needs_input" && (result.error ?? "").startsWith(MIGRATION_PENDING);
|
|
18183
18260
|
var boundTo = (entry, session) => entry.sessions.some((item) => item.host === session.host && item.handle === session.handle);
|
|
@@ -18262,7 +18339,7 @@ function entryCompactContext(store, entry, session, context) {
|
|
|
18262
18339
|
return null;
|
|
18263
18340
|
const freshness = { mode: "signal", current: () => recentSignal(store.root) };
|
|
18264
18341
|
const observed = task?.data.evidence.some(isObservedCheck) ?? false;
|
|
18265
|
-
const files = (task?.data.decisions ?? []).flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [
|
|
18342
|
+
const files = (task?.data.decisions ?? []).flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [path19.resolve(store.root, ref.path)] : []));
|
|
18266
18343
|
const observedFiles = filesKey(files);
|
|
18267
18344
|
const compact = new WorkitCore(store, context).compactContext(entry?.id ?? null, freshness, origin && { origin: origin.origin, taskId: origin.entry.id });
|
|
18268
18345
|
if (!compact.ok || !compact.data)
|
|
@@ -18331,7 +18408,7 @@ var turnContextText = (input, descriptor) => {
|
|
|
18331
18408
|
}
|
|
18332
18409
|
};
|
|
18333
18410
|
var TURN_TTL_MS = 7 * 24 * 60 * 60 * 1000;
|
|
18334
|
-
var digestOf = (text) =>
|
|
18411
|
+
var digestOf = (text) => createHash13("sha256").update(text).digest("hex");
|
|
18335
18412
|
var turnMarker = (input) => {
|
|
18336
18413
|
if (!input.session.id)
|
|
18337
18414
|
return null;
|
|
@@ -18340,32 +18417,32 @@ var turnMarker = (input) => {
|
|
|
18340
18417
|
if (location instanceof Error)
|
|
18341
18418
|
return null;
|
|
18342
18419
|
const session = [input.host, input.session.id, input.session.agentId ?? ""].join("\x00");
|
|
18343
|
-
return
|
|
18420
|
+
return path19.join(location.dir, "hooks", `turn-${digestOf(session).slice(0, 32)}.json`);
|
|
18344
18421
|
} catch {
|
|
18345
18422
|
return null;
|
|
18346
18423
|
}
|
|
18347
18424
|
};
|
|
18348
18425
|
var writeTurnDigest = (file, digest) => {
|
|
18349
18426
|
try {
|
|
18350
|
-
|
|
18351
|
-
|
|
18427
|
+
fs15.mkdirSync(path19.dirname(file), { recursive: true });
|
|
18428
|
+
fs15.writeFileSync(file, `${JSON.stringify({ digest })}
|
|
18352
18429
|
`);
|
|
18353
18430
|
} catch {}
|
|
18354
18431
|
};
|
|
18355
18432
|
var clearTurnDigest = (file) => {
|
|
18356
18433
|
try {
|
|
18357
|
-
|
|
18434
|
+
fs15.rmSync(file, { force: true });
|
|
18358
18435
|
} catch {}
|
|
18359
18436
|
};
|
|
18360
18437
|
var pruneTurnDigests = (dir, now) => {
|
|
18361
18438
|
try {
|
|
18362
|
-
for (const name of
|
|
18439
|
+
for (const name of fs15.readdirSync(dir)) {
|
|
18363
18440
|
if (!name.startsWith("turn-"))
|
|
18364
18441
|
continue;
|
|
18365
|
-
const file =
|
|
18442
|
+
const file = path19.join(dir, name);
|
|
18366
18443
|
try {
|
|
18367
|
-
if (now -
|
|
18368
|
-
|
|
18444
|
+
if (now - fs15.statSync(file).mtimeMs > TURN_TTL_MS)
|
|
18445
|
+
fs15.rmSync(file, { force: true });
|
|
18369
18446
|
} catch {}
|
|
18370
18447
|
}
|
|
18371
18448
|
} catch {}
|
|
@@ -18381,7 +18458,7 @@ var changedTurnContext = (input, text) => {
|
|
|
18381
18458
|
return text;
|
|
18382
18459
|
const digest = digestOf(text);
|
|
18383
18460
|
try {
|
|
18384
|
-
const previous = JSON.parse(
|
|
18461
|
+
const previous = JSON.parse(fs15.readFileSync(file, "utf8"));
|
|
18385
18462
|
if (previous.digest === digest)
|
|
18386
18463
|
return null;
|
|
18387
18464
|
} catch {}
|
|
@@ -18392,7 +18469,7 @@ var seedTurnContext = (input, descriptor, text = turnContextText(input, descript
|
|
|
18392
18469
|
const file = turnMarker(input);
|
|
18393
18470
|
if (!file)
|
|
18394
18471
|
return;
|
|
18395
|
-
pruneTurnDigests(
|
|
18472
|
+
pruneTurnDigests(path19.dirname(file), Date.now());
|
|
18396
18473
|
if (text)
|
|
18397
18474
|
writeTurnDigest(file, digestOf(text));
|
|
18398
18475
|
else
|
|
@@ -18401,19 +18478,19 @@ var seedTurnContext = (input, descriptor, text = turnContextText(input, descript
|
|
|
18401
18478
|
// packages/workit-core/src/core/route-intent.ts
|
|
18402
18479
|
import { spawnSync as spawnSync12 } from "node:child_process";
|
|
18403
18480
|
import { existsSync as existsSync6 } from "node:fs";
|
|
18404
|
-
import
|
|
18481
|
+
import path22 from "node:path";
|
|
18405
18482
|
|
|
18406
18483
|
// packages/workit-core/src/hooks/raw-git.ts
|
|
18407
18484
|
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
18408
|
-
import { createHash as
|
|
18409
|
-
import
|
|
18485
|
+
import { createHash as createHash15 } from "node:crypto";
|
|
18486
|
+
import fs17 from "node:fs";
|
|
18410
18487
|
import os5 from "node:os";
|
|
18411
|
-
import
|
|
18488
|
+
import path21 from "node:path";
|
|
18412
18489
|
|
|
18413
18490
|
// packages/workit-core/src/hooks/session-marker.ts
|
|
18414
|
-
import { createHash as
|
|
18415
|
-
import
|
|
18416
|
-
import
|
|
18491
|
+
import { createHash as createHash14 } from "node:crypto";
|
|
18492
|
+
import fs16 from "node:fs";
|
|
18493
|
+
import path20 from "node:path";
|
|
18417
18494
|
var sessionMarkerFile = (input, session, store) => {
|
|
18418
18495
|
let dir = store;
|
|
18419
18496
|
if (dir === undefined) {
|
|
@@ -18422,13 +18499,13 @@ var sessionMarkerFile = (input, session, store) => {
|
|
|
18422
18499
|
return null;
|
|
18423
18500
|
dir = location.dir;
|
|
18424
18501
|
}
|
|
18425
|
-
const name =
|
|
18426
|
-
return
|
|
18502
|
+
const name = createHash14("sha256").update(`${input.host}\x00${session}`).digest("hex").slice(0, 32);
|
|
18503
|
+
return path20.join(dir, "hooks", `skills-${name}.json`);
|
|
18427
18504
|
};
|
|
18428
18505
|
var list2 = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
18429
18506
|
var readSessionMarker = (file) => {
|
|
18430
18507
|
try {
|
|
18431
|
-
const value = JSON.parse(
|
|
18508
|
+
const value = JSON.parse(fs16.readFileSync(file, "utf8"));
|
|
18432
18509
|
return { nudged: list2(value.nudged), loaded: list2(value.loaded), raw: list2(value.raw) };
|
|
18433
18510
|
} catch {
|
|
18434
18511
|
return { nudged: [], loaded: [], raw: [] };
|
|
@@ -18436,8 +18513,8 @@ var readSessionMarker = (file) => {
|
|
|
18436
18513
|
};
|
|
18437
18514
|
var writeSessionMarker = (file, marker) => {
|
|
18438
18515
|
try {
|
|
18439
|
-
|
|
18440
|
-
|
|
18516
|
+
fs16.mkdirSync(path20.dirname(file), { recursive: true });
|
|
18517
|
+
fs16.writeFileSync(file, JSON.stringify(marker));
|
|
18441
18518
|
} catch {}
|
|
18442
18519
|
};
|
|
18443
18520
|
|
|
@@ -18934,14 +19011,14 @@ var GIT_CONFIG_ENV = /^GIT_(?:CONFIG\w*|DIR|COMMON_DIR|WORK_TREE)$/;
|
|
|
18934
19011
|
var ASSIGNMENT = /^([A-Za-z_]\w*)=([\s\S]*)$/;
|
|
18935
19012
|
var MAX_DEPTH = 4;
|
|
18936
19013
|
var MAX_EXPANSIONS = 16;
|
|
18937
|
-
var isAbsolute = (value) =>
|
|
19014
|
+
var isAbsolute = (value) => path21.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\");
|
|
18938
19015
|
var HERE = /^(?:\$PWD|\$\{PWD\}|\$\(\s*pwd\s*\)|`pwd`|\$\(\s*git\s+rev-parse\s+--show-toplevel\s*\))(?=$|[\\/])/;
|
|
18939
19016
|
var joinDir = (base, raw) => {
|
|
18940
19017
|
const next = raw.replace(HERE, ".");
|
|
18941
19018
|
if (base === undefined || /[$`*?]/.test(next) || next === "-")
|
|
18942
19019
|
return;
|
|
18943
|
-
const expanded = next === "~" || next.startsWith("~/") ?
|
|
18944
|
-
return base === null || isAbsolute(expanded) ? expanded :
|
|
19020
|
+
const expanded = next === "~" || next.startsWith("~/") ? path21.join(os5.homedir(), next.slice(1)) : next;
|
|
19021
|
+
return base === null || isAbsolute(expanded) ? expanded : path21.join(base, expanded);
|
|
18945
19022
|
};
|
|
18946
19023
|
var rebase = (base, inner) => inner === null ? base : inner === undefined ? undefined : joinDir(base, inner);
|
|
18947
19024
|
var cdTarget = (words) => {
|
|
@@ -19753,7 +19830,7 @@ var repoAt = (dir) => {
|
|
|
19753
19830
|
return { location, dir, branch: resolveTaskKey(dir, location).branch };
|
|
19754
19831
|
};
|
|
19755
19832
|
var isWorkitWorkspace = (repo) => {
|
|
19756
|
-
if (
|
|
19833
|
+
if (fs17.existsSync(repo.location.dir))
|
|
19757
19834
|
return true;
|
|
19758
19835
|
try {
|
|
19759
19836
|
return resolveRuntimeWorkspaceVcs(repo.location.top ?? repo.dir) !== null;
|
|
@@ -19774,17 +19851,17 @@ var headSha2 = (repo) => {
|
|
|
19774
19851
|
if (!git || git.reftable)
|
|
19775
19852
|
return null;
|
|
19776
19853
|
try {
|
|
19777
|
-
const head =
|
|
19854
|
+
const head = fs17.readFileSync(path21.join(git.gitDir, "HEAD"), "utf8").trim();
|
|
19778
19855
|
if (/^[0-9a-f]{40,64}$/.test(head))
|
|
19779
19856
|
return head;
|
|
19780
19857
|
const ref = /^ref: (refs\/.+)$/.exec(head)?.[1];
|
|
19781
19858
|
if (!ref)
|
|
19782
19859
|
return null;
|
|
19783
|
-
const common =
|
|
19860
|
+
const common = path21.dirname(repo.location.dir);
|
|
19784
19861
|
try {
|
|
19785
|
-
return
|
|
19862
|
+
return fs17.readFileSync(path21.join(common, ref), "utf8").trim() || null;
|
|
19786
19863
|
} catch {}
|
|
19787
|
-
const packed =
|
|
19864
|
+
const packed = fs17.readFileSync(path21.join(common, "packed-refs"), "utf8");
|
|
19788
19865
|
return new RegExp(`^([0-9a-f]{40,64}) ${ref.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`, "m").exec(packed)?.[1] ?? null;
|
|
19789
19866
|
} catch {
|
|
19790
19867
|
return null;
|
|
@@ -19872,8 +19949,8 @@ var expandGitAliases = (root, invocation, cache = new Map, depth = 0) => {
|
|
|
19872
19949
|
const sub = invocation.args[0];
|
|
19873
19950
|
if (invocation.tool !== "git" || invocation.dir === undefined || !sub || sub.startsWith("-") || GIT_COMMANDS.has(sub) || depth >= MAX_DEPTH)
|
|
19874
19951
|
return [invocation];
|
|
19875
|
-
const dir =
|
|
19876
|
-
if (!
|
|
19952
|
+
const dir = path21.resolve(root, invocation.dir ?? ".");
|
|
19953
|
+
if (!fs17.existsSync(dir))
|
|
19877
19954
|
return [invocation];
|
|
19878
19955
|
const config = gitConfig(dir, invocation, cache);
|
|
19879
19956
|
const alias = configValue(config, `alias.${sub.toLowerCase()}`);
|
|
@@ -19895,11 +19972,11 @@ var expandGitAliases = (root, invocation, cache = new Map, depth = 0) => {
|
|
|
19895
19972
|
var normalizedUrl = (url, dir) => {
|
|
19896
19973
|
const trimmed = url.trim();
|
|
19897
19974
|
if (/^file:\/\//i.test(trimmed))
|
|
19898
|
-
return
|
|
19975
|
+
return path21.resolve(dir, trimmed.slice(7)).replace(/\/+$/, "").replace(/\.git$/, "");
|
|
19899
19976
|
const scheme = /^[a-z][a-z0-9+.-]*:\/\//i.exec(trimmed);
|
|
19900
19977
|
const scp = !scheme && /^(?:[^@/\\]+@)?[^/\\:]{2,}:/.test(trimmed);
|
|
19901
19978
|
if (!scheme && !scp)
|
|
19902
|
-
return
|
|
19979
|
+
return path21.resolve(dir, trimmed).replace(/\/+$/, "").replace(/\.git$/, "");
|
|
19903
19980
|
const value = scheme ? trimmed.slice(scheme[0].length).replace(/^[^@/]*@/, "").replace(/^([^/:]+):\d+(?=\/)/, "$1") : trimmed.replace(/^[^@/]*@/, "").replace(":", "/");
|
|
19904
19981
|
return value.toLowerCase().replace(/\/{2,}/g, "/").replace(/^www\./, "").replace(/\/+$/, "").replace(/\.git$/, "");
|
|
19905
19982
|
};
|
|
@@ -20123,7 +20200,7 @@ var actionsIn = (cwd, command, dialect, cache = new Map) => {
|
|
|
20123
20200
|
const out = [];
|
|
20124
20201
|
const repos = new Map;
|
|
20125
20202
|
const repoFor = (relative) => {
|
|
20126
|
-
const dir =
|
|
20203
|
+
const dir = path21.resolve(cwd, relative ?? ".");
|
|
20127
20204
|
if (!repos.has(dir)) {
|
|
20128
20205
|
const repo = repoAt(dir);
|
|
20129
20206
|
repos.set(dir, repo && isWorkitWorkspace(repo) ? repo : null);
|
|
@@ -20209,8 +20286,8 @@ var analysisDenial = (error) => ({
|
|
|
20209
20286
|
});
|
|
20210
20287
|
var NEXT_COMMAND = "next";
|
|
20211
20288
|
var MARKER_TTL_SECONDS = 3600;
|
|
20212
|
-
var markerFile = (repo, session, key) =>
|
|
20213
|
-
var callKey = (toolUseId, command) => toolUseId ?? `cmd:${
|
|
20289
|
+
var markerFile = (repo, session, key) => path21.join(repo.location.dir, "hooks", `commit-${createHash15("sha256").update(`${session}\x00${key}`).digest("hex").slice(0, 32)}.json`);
|
|
20290
|
+
var callKey = (toolUseId, command) => toolUseId ?? `cmd:${createHash15("sha256").update(command).digest("hex")}`;
|
|
20214
20291
|
function noteRawCommit(input, command, key) {
|
|
20215
20292
|
try {
|
|
20216
20293
|
if (!input.session.id || !/\bcommit\b/.test(command))
|
|
@@ -20220,8 +20297,8 @@ function noteRawCommit(input, command, key) {
|
|
|
20220
20297
|
if (action.kind !== "commit")
|
|
20221
20298
|
continue;
|
|
20222
20299
|
const file = markerFile(repo, input.session.id, key);
|
|
20223
|
-
|
|
20224
|
-
|
|
20300
|
+
fs17.mkdirSync(path21.dirname(file), { recursive: true });
|
|
20301
|
+
fs17.writeFileSync(file, `${JSON.stringify({ head: headSha2(repo), at })}
|
|
20225
20302
|
`);
|
|
20226
20303
|
}
|
|
20227
20304
|
} catch {}
|
|
@@ -20244,11 +20321,11 @@ var headCommit = (dir) => {
|
|
|
20244
20321
|
var settle2 = (input, repo, file) => {
|
|
20245
20322
|
let marker;
|
|
20246
20323
|
try {
|
|
20247
|
-
marker = JSON.parse(
|
|
20324
|
+
marker = JSON.parse(fs17.readFileSync(file, "utf8"));
|
|
20248
20325
|
} catch {
|
|
20249
20326
|
return;
|
|
20250
20327
|
}
|
|
20251
|
-
|
|
20328
|
+
fs17.rmSync(file, { force: true });
|
|
20252
20329
|
const session = input.session.id;
|
|
20253
20330
|
const now = Date.now() / 1000;
|
|
20254
20331
|
if (typeof marker.at !== "number" || now - marker.at > MARKER_TTL_SECONDS)
|
|
@@ -20297,7 +20374,7 @@ function settlePendingCommit(input) {
|
|
|
20297
20374
|
if (!repo)
|
|
20298
20375
|
return;
|
|
20299
20376
|
const file = markerFile(repo, input.session.id, NEXT_COMMAND);
|
|
20300
|
-
if (
|
|
20377
|
+
if (fs17.existsSync(file))
|
|
20301
20378
|
settle2(input, repo, file);
|
|
20302
20379
|
} catch {}
|
|
20303
20380
|
}
|
|
@@ -20451,7 +20528,7 @@ var judgedDir = (root, dir) => {
|
|
|
20451
20528
|
return null;
|
|
20452
20529
|
if (dir === null)
|
|
20453
20530
|
return root;
|
|
20454
|
-
const resolved =
|
|
20531
|
+
const resolved = path22.resolve(root, dir);
|
|
20455
20532
|
return existsSync6(resolved) && inWorkitWorkspace(resolved) ? resolved : null;
|
|
20456
20533
|
};
|
|
20457
20534
|
var shellBranchPolicyViolation = (root, command, dialect = "posix") => {
|
|
@@ -20486,13 +20563,13 @@ var shellPolicy = (cwd, command, dialect = "posix") => {
|
|
|
20486
20563
|
return policy && !policy.ok ? { kind: "deny", reason: `branch_policy_denied: ${policy.error}`, unblock: null } : { kind: "none" };
|
|
20487
20564
|
};
|
|
20488
20565
|
// packages/workit-core/src/core/heavy-rules.ts
|
|
20489
|
-
import
|
|
20566
|
+
import fs18 from "node:fs";
|
|
20490
20567
|
import os6 from "node:os";
|
|
20491
|
-
import
|
|
20568
|
+
import path23 from "node:path";
|
|
20492
20569
|
var EMPTY = () => ({ deny: [], allow: [] });
|
|
20493
20570
|
var readText2 = (file) => {
|
|
20494
20571
|
try {
|
|
20495
|
-
return
|
|
20572
|
+
return fs18.readFileSync(file, "utf8");
|
|
20496
20573
|
} catch (error) {
|
|
20497
20574
|
if (error.code === "ENOENT")
|
|
20498
20575
|
return null;
|
|
@@ -20529,19 +20606,19 @@ function parseJsonc(text) {
|
|
|
20529
20606
|
return JSON.parse(out.replace(/,(\s*[}\]])/gu, "$1"));
|
|
20530
20607
|
}
|
|
20531
20608
|
function gitTop(cwd) {
|
|
20532
|
-
for (let dir =
|
|
20533
|
-
if (
|
|
20609
|
+
for (let dir = path23.resolve(cwd);; dir = path23.dirname(dir)) {
|
|
20610
|
+
if (fs18.existsSync(path23.join(dir, ".git")))
|
|
20534
20611
|
return dir;
|
|
20535
|
-
if (
|
|
20612
|
+
if (path23.dirname(dir) === dir)
|
|
20536
20613
|
return null;
|
|
20537
20614
|
}
|
|
20538
20615
|
}
|
|
20539
20616
|
var projectDirs = (cwd) => {
|
|
20540
20617
|
const top = gitTop(cwd);
|
|
20541
20618
|
const dirs = [];
|
|
20542
|
-
for (let dir =
|
|
20619
|
+
for (let dir = path23.resolve(cwd);; dir = path23.dirname(dir)) {
|
|
20543
20620
|
dirs.push(dir);
|
|
20544
|
-
if (!top || dir === top ||
|
|
20621
|
+
if (!top || dir === top || path23.dirname(dir) === dir)
|
|
20545
20622
|
return dirs;
|
|
20546
20623
|
}
|
|
20547
20624
|
};
|
|
@@ -20553,12 +20630,12 @@ var CLAUDE_MANAGED = {
|
|
|
20553
20630
|
};
|
|
20554
20631
|
function claudeSettingsFiles(cwd, env, platform = process.platform) {
|
|
20555
20632
|
const project = env.CLAUDE_PROJECT_DIR || gitTop(cwd) || cwd;
|
|
20556
|
-
const user = env.CLAUDE_CONFIG_DIR ||
|
|
20633
|
+
const user = env.CLAUDE_CONFIG_DIR || path23.join(homeOf(env), ".claude");
|
|
20557
20634
|
return [
|
|
20558
20635
|
...CLAUDE_MANAGED[platform] ? [CLAUDE_MANAGED[platform]] : [],
|
|
20559
|
-
|
|
20560
|
-
|
|
20561
|
-
|
|
20636
|
+
path23.join(user, "settings.json"),
|
|
20637
|
+
path23.join(project, ".claude", "settings.json"),
|
|
20638
|
+
path23.join(project, ".claude", "settings.local.json")
|
|
20562
20639
|
];
|
|
20563
20640
|
}
|
|
20564
20641
|
var bashPattern = (entry) => {
|
|
@@ -20648,10 +20725,10 @@ var opencodeConfig = (value, rules) => {
|
|
|
20648
20725
|
function opencodeRules(cwd, env = process.env) {
|
|
20649
20726
|
const rules = EMPTY();
|
|
20650
20727
|
try {
|
|
20651
|
-
const config = env.XDG_CONFIG_HOME ||
|
|
20728
|
+
const config = env.XDG_CONFIG_HOME || path23.join(homeOf(env), ".config");
|
|
20652
20729
|
const files = [
|
|
20653
|
-
...OPENCODE_NAMES.map((name) =>
|
|
20654
|
-
...projectDirs(cwd).flatMap((dir) => OPENCODE_NAMES.flatMap((name) => [
|
|
20730
|
+
...OPENCODE_NAMES.map((name) => path23.join(config, "opencode", name)),
|
|
20731
|
+
...projectDirs(cwd).flatMap((dir) => OPENCODE_NAMES.flatMap((name) => [path23.join(dir, name), path23.join(dir, ".opencode", name)])),
|
|
20655
20732
|
...env.OPENCODE_CONFIG ? [env.OPENCODE_CONFIG] : []
|
|
20656
20733
|
];
|
|
20657
20734
|
for (const file of files) {
|
|
@@ -20695,19 +20772,19 @@ var codexRule = (body) => {
|
|
|
20695
20772
|
function codexRules(cwd, env = process.env) {
|
|
20696
20773
|
const rules = EMPTY();
|
|
20697
20774
|
try {
|
|
20698
|
-
const home = env.CODEX_HOME ||
|
|
20775
|
+
const home = env.CODEX_HOME || path23.join(homeOf(env), ".codex");
|
|
20699
20776
|
const top = gitTop(cwd) ?? cwd;
|
|
20700
|
-
for (const dir of [
|
|
20777
|
+
for (const dir of [path23.join(home, "rules"), path23.join(top, ".codex", "rules")]) {
|
|
20701
20778
|
let files;
|
|
20702
20779
|
try {
|
|
20703
|
-
files =
|
|
20780
|
+
files = fs18.readdirSync(dir).filter((name) => name.endsWith(".rules"));
|
|
20704
20781
|
} catch (error) {
|
|
20705
20782
|
if (error.code === "ENOENT")
|
|
20706
20783
|
continue;
|
|
20707
20784
|
return "unreadable";
|
|
20708
20785
|
}
|
|
20709
20786
|
for (const name of files) {
|
|
20710
|
-
const text = readText2(
|
|
20787
|
+
const text = readText2(path23.join(dir, name)) ?? "";
|
|
20711
20788
|
for (const part of text.split(/\bprefix_rule\s*\(/u).slice(1)) {
|
|
20712
20789
|
const rule = codexRule(part);
|
|
20713
20790
|
if (!rule)
|
|
@@ -20726,8 +20803,8 @@ function cursorRules(cwd, env = process.env) {
|
|
|
20726
20803
|
try {
|
|
20727
20804
|
const top = gitTop(cwd) ?? cwd;
|
|
20728
20805
|
for (const file of [
|
|
20729
|
-
|
|
20730
|
-
|
|
20806
|
+
path23.join(homeOf(env), ".cursor", "cli-config.json"),
|
|
20807
|
+
path23.join(top, ".cursor", "cli.json")
|
|
20731
20808
|
]) {
|
|
20732
20809
|
const text = readText2(file);
|
|
20733
20810
|
if (text === null)
|
|
@@ -20801,23 +20878,23 @@ function wrapAllowed(read, words, command, options = {}) {
|
|
|
20801
20878
|
}
|
|
20802
20879
|
|
|
20803
20880
|
// packages/workit-core/src/core/heavy.ts
|
|
20804
|
-
import
|
|
20881
|
+
import fs19 from "node:fs";
|
|
20805
20882
|
import os7 from "node:os";
|
|
20806
|
-
import
|
|
20883
|
+
import path24 from "node:path";
|
|
20807
20884
|
function stateDir(env, platform = process.platform) {
|
|
20808
20885
|
if (env.WORKFLOW_TOOLKIT_STATE)
|
|
20809
20886
|
return env.WORKFLOW_TOOLKIT_STATE;
|
|
20810
20887
|
if (env.XDG_STATE_HOME)
|
|
20811
|
-
return
|
|
20888
|
+
return path24.join(env.XDG_STATE_HOME, "workit");
|
|
20812
20889
|
const home = env.HOME || os7.homedir();
|
|
20813
20890
|
if (platform === "darwin")
|
|
20814
|
-
return
|
|
20891
|
+
return path24.join(home, "Library", "Application Support", "workit");
|
|
20815
20892
|
if (platform === "win32")
|
|
20816
|
-
return
|
|
20817
|
-
return
|
|
20893
|
+
return path24.join(env.LOCALAPPDATA ?? path24.join(home, "AppData", "Local"), "workit");
|
|
20894
|
+
return path24.join(home, ".local", "state", "workit");
|
|
20818
20895
|
}
|
|
20819
20896
|
var HEAVY_COMMANDS_FILE = "heavy-commands.json";
|
|
20820
|
-
var heavyCommandsFile = (env) =>
|
|
20897
|
+
var heavyCommandsFile = (env) => path24.join(stateDir(env), HEAVY_COMMANDS_FILE);
|
|
20821
20898
|
var HEAVY_SCRIPT = /^(?:test|tests|t|tst|unit|integration|e2e|coverage|cov|lint|eslint|typecheck|type-check|types|tsc|check|verify|validate|build|compile|bundle|ci|sonar|cypress|playwright|jest|vitest|mocha|bench|benchmark|all)(?:$|[:_.-])/iu;
|
|
20822
20899
|
var INFO_FLAGS = new Set(["--version", "-v", "-V", "--help", "-h", "help", "version"]);
|
|
20823
20900
|
var WATCH_FLAG = /^(?:--watch(?:All)?(?:=.*)?|-w|--serve)$/u;
|
|
@@ -21080,7 +21157,7 @@ function parsePattern(pattern) {
|
|
|
21080
21157
|
var matches = (matchers, words) => matchers.length <= words.length && matchers.every((matcher, index) => index === 0 ? matcher.test(words[0]) || matcher.test(baseName2(words[0])) : matcher.test(words[index]));
|
|
21081
21158
|
var readJson = (file) => {
|
|
21082
21159
|
try {
|
|
21083
|
-
return JSON.parse(
|
|
21160
|
+
return JSON.parse(fs19.readFileSync(file, "utf8"));
|
|
21084
21161
|
} catch {
|
|
21085
21162
|
return;
|
|
21086
21163
|
}
|
|
@@ -21092,7 +21169,7 @@ function machinePatterns(env) {
|
|
|
21092
21169
|
return isRecord5(value) ? stringList(value.patterns) : [];
|
|
21093
21170
|
}
|
|
21094
21171
|
function repoPatterns(cwd) {
|
|
21095
|
-
return repoHeavyCommands(gitTop(cwd) ??
|
|
21172
|
+
return repoHeavyCommands(gitTop(cwd) ?? path24.resolve(cwd));
|
|
21096
21173
|
}
|
|
21097
21174
|
function heavyLines(lines, options) {
|
|
21098
21175
|
const found = [];
|
|
@@ -21170,12 +21247,12 @@ function heavyPlan(command, options) {
|
|
|
21170
21247
|
}
|
|
21171
21248
|
function workitOnPath2(env = process.env) {
|
|
21172
21249
|
const names = process.platform === "win32" ? ["workit.exe", "workit.cmd", "workit"] : ["workit"];
|
|
21173
|
-
for (const dir of (env.PATH ?? "").split(
|
|
21250
|
+
for (const dir of (env.PATH ?? "").split(path24.delimiter))
|
|
21174
21251
|
for (const name of names) {
|
|
21175
21252
|
if (!dir)
|
|
21176
21253
|
continue;
|
|
21177
21254
|
try {
|
|
21178
|
-
|
|
21255
|
+
fs19.accessSync(path24.join(dir, name), fs19.constants.X_OK);
|
|
21179
21256
|
return true;
|
|
21180
21257
|
} catch {}
|
|
21181
21258
|
}
|
|
@@ -21192,41 +21269,41 @@ function leaseRewrite(command) {
|
|
|
21192
21269
|
}
|
|
21193
21270
|
|
|
21194
21271
|
// packages/workit-core/src/core/heavy-words.ts
|
|
21195
|
-
import
|
|
21272
|
+
import fs20 from "node:fs";
|
|
21196
21273
|
import os8 from "node:os";
|
|
21197
|
-
import
|
|
21274
|
+
import path25 from "node:path";
|
|
21198
21275
|
var HEAVY_WORDS = new Set(("npm npx pnpm pnpx yarn bun bunx deno corepack make gmake docker podman nerdctl " + "python python3 py uv poetry pdm pipenv hatch rye bundle rake nx " + "jest vitest mocha ava tap karma jasmine nyc c8 tsc vue-tsc svelte-check eslint stylelint " + "tslint webpack webpack-cli rollup parcel tsup vite next nuxt nuxi astro ng react-scripts " + "playwright cypress wdio testcafe turbo lerna sonar-scanner sonarless sonarless-mcp go " + "golangci-lint gotestsum staticcheck cargo mvn mvnw gradle gradlew ant sbt bazel bazelisk " + "buck2 dotnet msbuild pytest py.test tox nox mypy pyright pylint coverage maturin pip pip3 " + "rspec rails phpunit pest phpstan psalm composer mix swift xcodebuild flutter dart pod cmake " + "ninja meson ctest scons docker-compose buildah earthly").split(" "));
|
|
21199
21276
|
var wordsOf = (command) => command.split(/[\s;&|()<>`'"]+/u).map((word) => (word.split(/[\\/]/u).at(-1) ?? "").toLowerCase().replace(/\.(?:exe|cmd|bat)$/u, "")).filter(Boolean);
|
|
21200
21277
|
var stateDir2 = (env) => {
|
|
21201
21278
|
if (env.WORKFLOW_TOOLKIT_STATE)
|
|
21202
21279
|
return env.WORKFLOW_TOOLKIT_STATE;
|
|
21203
21280
|
if (env.XDG_STATE_HOME)
|
|
21204
|
-
return
|
|
21281
|
+
return path25.join(env.XDG_STATE_HOME, "workit");
|
|
21205
21282
|
const home = env.HOME || os8.homedir();
|
|
21206
21283
|
if (process.platform === "darwin")
|
|
21207
|
-
return
|
|
21284
|
+
return path25.join(home, "Library", "Application Support", "workit");
|
|
21208
21285
|
if (process.platform === "win32")
|
|
21209
|
-
return
|
|
21210
|
-
return
|
|
21286
|
+
return path25.join(env.LOCALAPPDATA ?? path25.join(home, "AppData", "Local"), "workit");
|
|
21287
|
+
return path25.join(home, ".local", "state", "workit");
|
|
21211
21288
|
};
|
|
21212
21289
|
var readJson2 = (file) => {
|
|
21213
21290
|
try {
|
|
21214
|
-
return JSON.parse(
|
|
21291
|
+
return JSON.parse(fs20.readFileSync(file, "utf8"));
|
|
21215
21292
|
} catch {
|
|
21216
21293
|
return;
|
|
21217
21294
|
}
|
|
21218
21295
|
};
|
|
21219
21296
|
var patternWords = (cwd, env) => {
|
|
21220
21297
|
const patterns = [];
|
|
21221
|
-
const machine = readJson2(
|
|
21298
|
+
const machine = readJson2(path25.join(stateDir2(env), "heavy-commands.json"));
|
|
21222
21299
|
if (Array.isArray(machine?.patterns))
|
|
21223
21300
|
patterns.push(...machine.patterns);
|
|
21224
|
-
for (let dir =
|
|
21225
|
-
if (
|
|
21301
|
+
for (let dir = path25.resolve(cwd);; dir = path25.dirname(dir)) {
|
|
21302
|
+
if (fs20.existsSync(path25.join(dir, ".git"))) {
|
|
21226
21303
|
patterns.push(...repoHeavyCommands(dir));
|
|
21227
21304
|
break;
|
|
21228
21305
|
}
|
|
21229
|
-
if (
|
|
21306
|
+
if (path25.dirname(dir) === dir)
|
|
21230
21307
|
break;
|
|
21231
21308
|
}
|
|
21232
21309
|
const words = new Set;
|
|
@@ -21298,14 +21375,14 @@ var splitDenial = (plan) => ({
|
|
|
21298
21375
|
// packages/workit-core/src/hooks/write-gate.ts
|
|
21299
21376
|
import { realpathSync as realpathSync5 } from "node:fs";
|
|
21300
21377
|
import os10 from "node:os";
|
|
21301
|
-
import
|
|
21378
|
+
import path27 from "node:path";
|
|
21302
21379
|
|
|
21303
21380
|
// packages/workit-core/src/core/live-session.ts
|
|
21304
21381
|
import { spawnSync as spawnSync13 } from "node:child_process";
|
|
21305
|
-
import { createHash as
|
|
21306
|
-
import
|
|
21382
|
+
import { createHash as createHash16 } from "node:crypto";
|
|
21383
|
+
import fs21 from "node:fs";
|
|
21307
21384
|
import os9 from "node:os";
|
|
21308
|
-
import
|
|
21385
|
+
import path26 from "node:path";
|
|
21309
21386
|
var LIVE_SESSION_TTL_MS = 15 * 60000;
|
|
21310
21387
|
var HEARTBEAT_EVERY_MS = 30000;
|
|
21311
21388
|
var liveProbe = {
|
|
@@ -21326,9 +21403,9 @@ var processAlive = (pid) => {
|
|
|
21326
21403
|
var processInfo = (pid) => {
|
|
21327
21404
|
try {
|
|
21328
21405
|
if (liveProbe.platform === "linux") {
|
|
21329
|
-
const stat =
|
|
21406
|
+
const stat = fs21.readFileSync(`/proc/${pid}/stat`, "utf8");
|
|
21330
21407
|
const ppid = Number(stat.slice(stat.lastIndexOf(")") + 2).split(" ")[1]);
|
|
21331
|
-
const command =
|
|
21408
|
+
const command = fs21.readFileSync(`/proc/${pid}/cmdline`, "utf8").replaceAll("\x00", " ");
|
|
21332
21409
|
return Number.isInteger(ppid) ? { ppid, command: command.trim() } : null;
|
|
21333
21410
|
}
|
|
21334
21411
|
if (liveProbe.platform === "win32")
|
|
@@ -21379,35 +21456,35 @@ var liveOwner = (input, transport, env = process.env) => {
|
|
|
21379
21456
|
};
|
|
21380
21457
|
};
|
|
21381
21458
|
var checkoutOf = (target) => {
|
|
21382
|
-
let dir =
|
|
21383
|
-
while (!
|
|
21384
|
-
dir =
|
|
21385
|
-
if (
|
|
21386
|
-
dir =
|
|
21387
|
-
const parts = dir.split(
|
|
21459
|
+
let dir = path26.resolve(target);
|
|
21460
|
+
while (!fs21.existsSync(dir) && path26.dirname(dir) !== dir)
|
|
21461
|
+
dir = path26.dirname(dir);
|
|
21462
|
+
if (fs21.existsSync(dir) && !fs21.statSync(dir).isDirectory())
|
|
21463
|
+
dir = path26.dirname(dir);
|
|
21464
|
+
const parts = dir.split(path26.sep);
|
|
21388
21465
|
const dotGit = parts.lastIndexOf(".git");
|
|
21389
21466
|
if (dotGit > 0)
|
|
21390
|
-
dir = parts.slice(0, dotGit).join(
|
|
21467
|
+
dir = parts.slice(0, dotGit).join(path26.sep) || path26.sep;
|
|
21391
21468
|
const location = resolveStore(dir);
|
|
21392
21469
|
if (location instanceof Error || !location.shared || !location.top)
|
|
21393
21470
|
return null;
|
|
21394
21471
|
let top = location.top;
|
|
21395
21472
|
try {
|
|
21396
|
-
top =
|
|
21473
|
+
top = fs21.realpathSync.native(top);
|
|
21397
21474
|
} catch {}
|
|
21398
21475
|
return top;
|
|
21399
21476
|
};
|
|
21400
|
-
var markerFile2 = (top) =>
|
|
21477
|
+
var markerFile2 = (top) => path26.join(resolveStateDir(), "live-sessions", `${createHash16("sha256").update(checkoutKey(top)).digest("hex").slice(0, 32)}.json`);
|
|
21401
21478
|
var checkoutKey = (top, platform = process.platform) => {
|
|
21402
|
-
let key =
|
|
21479
|
+
let key = path26.resolve(top);
|
|
21403
21480
|
try {
|
|
21404
|
-
key =
|
|
21481
|
+
key = fs21.realpathSync.native(key);
|
|
21405
21482
|
} catch {}
|
|
21406
21483
|
return platform === "win32" ? key.replaceAll("/", "\\").toLowerCase() : key;
|
|
21407
21484
|
};
|
|
21408
21485
|
var readMarker = (file) => {
|
|
21409
21486
|
try {
|
|
21410
|
-
const value = JSON.parse(
|
|
21487
|
+
const value = JSON.parse(fs21.readFileSync(file, "utf8"));
|
|
21411
21488
|
if (value?.version !== 1 || typeof value.session !== "string" || typeof value.host !== "string" || typeof value.heartbeatAt !== "string" || Number.isNaN(Date.parse(value.heartbeatAt)))
|
|
21412
21489
|
return null;
|
|
21413
21490
|
return {
|
|
@@ -21494,10 +21571,10 @@ var claimLiveSession = (target, owner, deps = {}) => {
|
|
|
21494
21571
|
checkout,
|
|
21495
21572
|
heartbeatAt: now.toISOString()
|
|
21496
21573
|
};
|
|
21497
|
-
|
|
21574
|
+
fs21.mkdirSync(path26.dirname(file), { recursive: true });
|
|
21498
21575
|
const temp = `${file}.${process.pid}.tmp`;
|
|
21499
|
-
|
|
21500
|
-
|
|
21576
|
+
fs21.writeFileSync(temp, JSON.stringify(marker));
|
|
21577
|
+
fs21.renameSync(temp, file);
|
|
21501
21578
|
} catch {}
|
|
21502
21579
|
};
|
|
21503
21580
|
|
|
@@ -21506,22 +21583,22 @@ var NONE3 = { kind: "none" };
|
|
|
21506
21583
|
var CASE_INSENSITIVE = process.platform === "darwin" || process.platform === "win32";
|
|
21507
21584
|
var canonical2 = (file) => {
|
|
21508
21585
|
let rest = "";
|
|
21509
|
-
for (let dir =
|
|
21586
|
+
for (let dir = path27.resolve(file);; dir = path27.dirname(dir)) {
|
|
21510
21587
|
try {
|
|
21511
|
-
return
|
|
21588
|
+
return path27.join(realpathSync5.native(dir), rest);
|
|
21512
21589
|
} catch {
|
|
21513
|
-
if (
|
|
21514
|
-
return
|
|
21515
|
-
rest = rest ?
|
|
21590
|
+
if (path27.dirname(dir) === dir)
|
|
21591
|
+
return path27.resolve(file);
|
|
21592
|
+
rest = rest ? path27.join(path27.basename(dir), rest) : path27.basename(dir);
|
|
21516
21593
|
}
|
|
21517
21594
|
}
|
|
21518
21595
|
};
|
|
21519
21596
|
var exempt = (cwd, root, file, plans) => {
|
|
21520
21597
|
const fold = (value) => CASE_INSENSITIVE ? value.toLowerCase() : value;
|
|
21521
|
-
const relative =
|
|
21522
|
-
if (relative.startsWith("..") ||
|
|
21598
|
+
const relative = path27.relative(fold(canonical2(root)), fold(canonical2(path27.resolve(cwd, file))));
|
|
21599
|
+
if (relative.startsWith("..") || path27.isAbsolute(relative))
|
|
21523
21600
|
return true;
|
|
21524
|
-
const posix = relative.split(
|
|
21601
|
+
const posix = relative.split(path27.sep).join("/");
|
|
21525
21602
|
const segments = posix.split("/");
|
|
21526
21603
|
return /\.mdx?$/i.test(posix) || segments[0] === "docs" || segments.includes("plans") || [...plans].some((plan) => fold(plan) === posix);
|
|
21527
21604
|
};
|
|
@@ -21642,7 +21719,7 @@ var shellWrites = (command, depth = 0) => {
|
|
|
21642
21719
|
return { writes: true, targets: unknown ? null : targets };
|
|
21643
21720
|
};
|
|
21644
21721
|
var cache2 = new Map;
|
|
21645
|
-
var planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(
|
|
21722
|
+
var planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(path27.resolve(root, file)) ?? "-").join("\x00");
|
|
21646
21723
|
var gateFor = (cwd) => {
|
|
21647
21724
|
const store = new TaskStore(cwd);
|
|
21648
21725
|
const listed = store.listTaskIndex();
|
|
@@ -21721,7 +21798,7 @@ var gitMutationDirs = (cwd, command, dialect) => {
|
|
|
21721
21798
|
return [];
|
|
21722
21799
|
if (sub === "stash" && ["list", "show"].includes(rest[0] ?? ""))
|
|
21723
21800
|
return [];
|
|
21724
|
-
return [
|
|
21801
|
+
return [path27.resolve(cwd, invocation.dir ?? ".")];
|
|
21725
21802
|
});
|
|
21726
21803
|
};
|
|
21727
21804
|
var CD2 = new Set(["cd", "chdir", "set-location", "sl"]);
|
|
@@ -21732,7 +21809,7 @@ var cdInto = (dir, words) => {
|
|
|
21732
21809
|
const target = named === undefined ? undefined : homeExpanded(named);
|
|
21733
21810
|
if (dir === undefined || target === "-" || target && /^~|[$`*?]/.test(target))
|
|
21734
21811
|
return;
|
|
21735
|
-
return target === undefined ? os10.homedir() :
|
|
21812
|
+
return target === undefined ? os10.homedir() : path27.resolve(dir, target);
|
|
21736
21813
|
};
|
|
21737
21814
|
var quoteWord2 = (word) => /^[\w@%+=:,./-]+$/.test(word) ? word : `'${word.replaceAll("'", "'\\''")}'`;
|
|
21738
21815
|
var homeExpanded = (file) => {
|
|
@@ -21746,7 +21823,7 @@ var segmentTargets = (cwd, command, dialect, depth = 0) => {
|
|
|
21746
21823
|
const groups = [];
|
|
21747
21824
|
const at = (file) => {
|
|
21748
21825
|
const home = homeExpanded(file);
|
|
21749
|
-
return
|
|
21826
|
+
return path27.isAbsolute(home) ? home : dir === undefined ? null : path27.resolve(dir, home);
|
|
21750
21827
|
};
|
|
21751
21828
|
for (const segment of segmentsOf(command, dialect)) {
|
|
21752
21829
|
if (segment.group === "open") {
|
|
@@ -21787,7 +21864,7 @@ var segmentTargets = (cwd, command, dialect, depth = 0) => {
|
|
|
21787
21864
|
const edits = editsOf(segment.words);
|
|
21788
21865
|
if (edits === null) {
|
|
21789
21866
|
if (dir !== undefined)
|
|
21790
|
-
targets.push(
|
|
21867
|
+
targets.push(path27.join(dir, DIR_TARGET));
|
|
21791
21868
|
} else
|
|
21792
21869
|
for (const file of edits) {
|
|
21793
21870
|
const resolved = at(file);
|
|
@@ -21795,7 +21872,7 @@ var segmentTargets = (cwd, command, dialect, depth = 0) => {
|
|
|
21795
21872
|
targets.push(resolved);
|
|
21796
21873
|
}
|
|
21797
21874
|
if (dir !== undefined && workitInvocations(segment.words.map(quoteWord2).join(" "), "posix").some((args) => args[0] === "git" && MUTATING_WORKIT_GIT.has(args[1] ?? "") && !inert(args.slice(2), "")))
|
|
21798
|
-
targets.push(
|
|
21875
|
+
targets.push(path27.join(dir, DIR_TARGET));
|
|
21799
21876
|
}
|
|
21800
21877
|
return targets;
|
|
21801
21878
|
};
|
|
@@ -21830,7 +21907,7 @@ var liveDeny = ({ marker, checkout, ageMs, file }) => {
|
|
|
21830
21907
|
var guarded = (targets) => {
|
|
21831
21908
|
const seen = new Set;
|
|
21832
21909
|
return targets.filter((target) => {
|
|
21833
|
-
const dir =
|
|
21910
|
+
const dir = path27.dirname(target);
|
|
21834
21911
|
if (seen.has(dir))
|
|
21835
21912
|
return false;
|
|
21836
21913
|
seen.add(dir);
|
|
@@ -21851,7 +21928,7 @@ var claimAll = (owner, targets, deps) => {
|
|
|
21851
21928
|
for (const target of guarded(targets))
|
|
21852
21929
|
claimLiveSession(target, owner, deps);
|
|
21853
21930
|
};
|
|
21854
|
-
var liveTargets = (cwd, paths) => paths?.length ? paths.map((file) =>
|
|
21931
|
+
var liveTargets = (cwd, paths) => paths?.length ? paths.map((file) => path27.resolve(cwd, file)) : [path27.join(cwd, DIR_TARGET)];
|
|
21855
21932
|
var issuedTarget = (cwd, targets) => {
|
|
21856
21933
|
const state = resolveStateDir();
|
|
21857
21934
|
const found = targets.find((target) => underIssued(state, cwd, homeExpanded(target), process.platform, canonical2));
|
|
@@ -21859,7 +21936,7 @@ var issuedTarget = (cwd, targets) => {
|
|
|
21859
21936
|
};
|
|
21860
21937
|
var underIssued = (state, cwd, target, platform = process.platform, real = (file) => file) => {
|
|
21861
21938
|
const win = platform === "win32";
|
|
21862
|
-
const p = win ?
|
|
21939
|
+
const p = win ? path27.win32 : path27.posix;
|
|
21863
21940
|
const fold = (value) => win || platform === "darwin" ? value.toLowerCase() : value;
|
|
21864
21941
|
const named = win ? target.replace(/^\/([a-zA-Z])(?=\/|$)/, "$1:") : target;
|
|
21865
21942
|
const relative = p.relative(fold(real(p.resolve(state))), fold(real(p.resolve(cwd, named))));
|
|
@@ -21908,7 +21985,7 @@ function shellGate(cwd, command, owner, dialect = "posix", deps) {
|
|
|
21908
21985
|
try {
|
|
21909
21986
|
targets = [
|
|
21910
21987
|
...segmentTargets(cwd, command, dialect),
|
|
21911
|
-
...gitMutationDirs(cwd, command, dialect).map((dir) =>
|
|
21988
|
+
...gitMutationDirs(cwd, command, dialect).map((dir) => path27.join(dir, DIR_TARGET))
|
|
21912
21989
|
];
|
|
21913
21990
|
} catch {
|
|
21914
21991
|
targets = [];
|
|
@@ -22342,12 +22419,12 @@ ${line}` };
|
|
|
22342
22419
|
};
|
|
22343
22420
|
// packages/workit-core/src/hooks/hosts/fields.ts
|
|
22344
22421
|
import { existsSync as existsSync7, realpathSync as realpathSync6, statSync as statSync2 } from "node:fs";
|
|
22345
|
-
import
|
|
22422
|
+
import path28 from "node:path";
|
|
22346
22423
|
var isRecord6 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
22347
22424
|
var nonEmpty2 = (value) => typeof value === "string" && value.trim() !== "";
|
|
22348
22425
|
var optionalText = (value) => typeof value === "string" ? value : null;
|
|
22349
22426
|
var existingDirectory = (value) => {
|
|
22350
|
-
if (!nonEmpty2(value) || !
|
|
22427
|
+
if (!nonEmpty2(value) || !path28.isAbsolute(value) || !existsSync7(value))
|
|
22351
22428
|
return null;
|
|
22352
22429
|
try {
|
|
22353
22430
|
return statSync2(value).isDirectory() ? realpathSync6(value) : null;
|
|
@@ -22413,6 +22490,109 @@ var writeTargets = (input) => {
|
|
|
22413
22490
|
const paths = writePaths(input);
|
|
22414
22491
|
return paths.length > 0 ? paths : null;
|
|
22415
22492
|
};
|
|
22493
|
+
// packages/workit-core/src/hooks/standing.ts
|
|
22494
|
+
import fs22 from "node:fs";
|
|
22495
|
+
import path29 from "node:path";
|
|
22496
|
+
var readPlans = (store) => {
|
|
22497
|
+
const dir = path29.join(store, "fanouts");
|
|
22498
|
+
let names;
|
|
22499
|
+
try {
|
|
22500
|
+
names = fs22.readdirSync(dir).filter((name) => name.endsWith(".json"));
|
|
22501
|
+
} catch {
|
|
22502
|
+
return [];
|
|
22503
|
+
}
|
|
22504
|
+
const plans = [];
|
|
22505
|
+
for (const name of names) {
|
|
22506
|
+
try {
|
|
22507
|
+
const raw = JSON.parse(fs22.readFileSync(path29.join(dir, name), "utf8"));
|
|
22508
|
+
if (typeof raw.name !== "string" || !Array.isArray(raw.slices))
|
|
22509
|
+
continue;
|
|
22510
|
+
const texts = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string" && item !== "") : [];
|
|
22511
|
+
plans.push({
|
|
22512
|
+
name: raw.name,
|
|
22513
|
+
leads: texts([raw.leadSession, ...texts(raw.formerLeads)]),
|
|
22514
|
+
branches: texts(raw.slices.map((slice) => slice && typeof slice === "object" ? slice.branch : null))
|
|
22515
|
+
});
|
|
22516
|
+
} catch {}
|
|
22517
|
+
}
|
|
22518
|
+
return plans;
|
|
22519
|
+
};
|
|
22520
|
+
var leadOf2 = (input) => input.session.parentId ?? (input.session.agentId ? input.session.id : null) ?? (input.session.id.includes(":") ? input.session.id.split(":")[0] : null);
|
|
22521
|
+
var worksFor = (plan, input, branch) => {
|
|
22522
|
+
const session = input.session.id;
|
|
22523
|
+
if (plan.leads.includes(session) && !input.session.agentId)
|
|
22524
|
+
return false;
|
|
22525
|
+
const lead = leadOf2(input);
|
|
22526
|
+
if (lead && plan.leads.includes(lead))
|
|
22527
|
+
return true;
|
|
22528
|
+
if (plan.leads.some((each) => session.startsWith(`${each}-w-`)))
|
|
22529
|
+
return true;
|
|
22530
|
+
const current = branch();
|
|
22531
|
+
return current !== null && plan.branches.includes(current);
|
|
22532
|
+
};
|
|
22533
|
+
var standingFor = (input, store, rev) => {
|
|
22534
|
+
const orders = new Map;
|
|
22535
|
+
const ledger = readLedger(input.cwd);
|
|
22536
|
+
const rows = ledger.ok ? ledger.value.rows : [];
|
|
22537
|
+
let branch;
|
|
22538
|
+
const lazyBranch = () => branch === undefined ? branch = currentBranch(input.cwd) : branch;
|
|
22539
|
+
for (const plan of readPlans(store))
|
|
22540
|
+
if (worksFor(plan, input, lazyBranch))
|
|
22541
|
+
for (const row of activeStanding(rows, plan.name, plan.leads.length ? plan.leads : null))
|
|
22542
|
+
orders.set(row.id, row);
|
|
22543
|
+
return { rev, orders, rows };
|
|
22544
|
+
};
|
|
22545
|
+
var located = (input) => {
|
|
22546
|
+
const store = input.session.id ? gitStoreDir(input.cwd) : null;
|
|
22547
|
+
const rev = store ? readStandingRev(store) : null;
|
|
22548
|
+
if (!store || rev === null)
|
|
22549
|
+
return null;
|
|
22550
|
+
return { store, rev, file: standingSeenFile(store, input.session.id, input.session.agentId) };
|
|
22551
|
+
};
|
|
22552
|
+
var seedStanding = (input) => {
|
|
22553
|
+
try {
|
|
22554
|
+
const where = located(input);
|
|
22555
|
+
if (!where)
|
|
22556
|
+
return;
|
|
22557
|
+
const now = standingFor(input, where.store, where.rev);
|
|
22558
|
+
writeStandingSeen(where.file, { rev: where.rev, ids: [...now.orders.keys()] });
|
|
22559
|
+
} catch {}
|
|
22560
|
+
};
|
|
22561
|
+
var fanoutOf = (row) => typeof row.fanout === "string" ? row.fanout : "?";
|
|
22562
|
+
var changedSince = (now, ids) => {
|
|
22563
|
+
const known = new Set(ids);
|
|
22564
|
+
const added = [...now.orders.values()].filter((row) => !known.has(row.id));
|
|
22565
|
+
const byId = new Map(now.rows.map((row) => [row.id, row]));
|
|
22566
|
+
const dropped = ids.filter((id) => !now.orders.has(id)).map((id) => byId.get(id)).filter((row) => row !== undefined);
|
|
22567
|
+
if (!added.length && !dropped.length)
|
|
22568
|
+
return null;
|
|
22569
|
+
const fanouts = [...new Set([...added, ...dropped].map(fanoutOf))].join(", ");
|
|
22570
|
+
const lines = [
|
|
22571
|
+
`Workit: the lead changed the standing orders for fanout ${fanouts} while you run. They apply to you now and override your brief's STANDING list.`,
|
|
22572
|
+
...added.map((row) => ` - new: ${String(row.what)}`),
|
|
22573
|
+
...dropped.map((row) => ` - no longer in force: ${String(row.what)}${row.stop ? " (the stop is lifted: continue your brief)" : ""}`)
|
|
22574
|
+
];
|
|
22575
|
+
if (added.some((row) => row.stop === true))
|
|
22576
|
+
lines.push("Stop now: make no further changes, close what you opened, and report to the lead with your branch, head SHA, what is done and what is not.");
|
|
22577
|
+
return lines.join(`
|
|
22578
|
+
`);
|
|
22579
|
+
};
|
|
22580
|
+
var standingDelta = (input) => {
|
|
22581
|
+
try {
|
|
22582
|
+
const where = located(input);
|
|
22583
|
+
if (!where)
|
|
22584
|
+
return null;
|
|
22585
|
+
const seen = readStandingSeen(where.file);
|
|
22586
|
+
if (seen.rev === where.rev)
|
|
22587
|
+
return null;
|
|
22588
|
+
const now = standingFor(input, where.store, where.rev);
|
|
22589
|
+
writeStandingSeen(where.file, { rev: where.rev, ids: [...now.orders.keys()] });
|
|
22590
|
+
return changedSince(now, seen.ids);
|
|
22591
|
+
} catch {
|
|
22592
|
+
return null;
|
|
22593
|
+
}
|
|
22594
|
+
};
|
|
22595
|
+
var sinceStart = new Map;
|
|
22416
22596
|
// packages/workit-core/src/hooks/handle.ts
|
|
22417
22597
|
var usable2 = (value) => value === "native" || value === "partial";
|
|
22418
22598
|
var NONE5 = { kind: "none" };
|
|
@@ -22457,7 +22637,18 @@ ${subagentStartText({ ...input, cwd: "" }, descriptor, event)}`;
|
|
|
22457
22637
|
const pick = judge === "verifier" ? ", --kind live when you drove the real surface" : "";
|
|
22458
22638
|
return `${readOnly} Its own Workit session is ${own}, so the ledger tells its verdicts apart from the author's. Record the verdict with exactly this command (pick the result${pick}, name the candidate branch if it differs, say what you ran): \`${line}\`.${token ? " The token is this subagent's alone: never write it into a report, a file or a commit. --token needs a workit CLI at least as new as this plugin; if the CLI answers that --token is an unknown option, update the workit CLI (workit upgrade --cli) and record again." : ""}`;
|
|
22459
22639
|
};
|
|
22640
|
+
var PRE_TOOL = new Set(["shell.pre", "write.pre", "tool.pre"]);
|
|
22460
22641
|
function handleHook(input, deps) {
|
|
22642
|
+
const decision = decide(input, deps);
|
|
22643
|
+
if (deps.descriptor.transport !== "hook-process" || !PRE_TOOL.has(input.event.kind) || decision.kind === "deny")
|
|
22644
|
+
return decision;
|
|
22645
|
+
const delta = standingDelta(input);
|
|
22646
|
+
if (!delta)
|
|
22647
|
+
return decision;
|
|
22648
|
+
return decision.kind === "rewrite" ? { ...decision, text: [decision.text, delta].filter(Boolean).join(`
|
|
22649
|
+
`) } : withContextLine(decision, delta);
|
|
22650
|
+
}
|
|
22651
|
+
function decide(input, deps) {
|
|
22461
22652
|
const { descriptor } = deps;
|
|
22462
22653
|
const event = input.event;
|
|
22463
22654
|
switch (event.kind) {
|
|
@@ -22534,6 +22725,7 @@ function handleHook(input, deps) {
|
|
|
22534
22725
|
case "write.pre":
|
|
22535
22726
|
return usable2(descriptor.events["write.pre"].support) ? writeGate(input.cwd, event.paths, liveOwner(input, descriptor.transport)) : NONE5;
|
|
22536
22727
|
case "subagent.start":
|
|
22728
|
+
seedStanding({ ...input, session: { ...input.session, agentId: event.agentId } });
|
|
22537
22729
|
return {
|
|
22538
22730
|
kind: "context",
|
|
22539
22731
|
text: subagentStartText(input, descriptor, event)
|
|
@@ -22585,7 +22777,7 @@ var dispatchHook = (adapter, raw, env = process.env) => {
|
|
|
22585
22777
|
};
|
|
22586
22778
|
// packages/workit-core/src/hooks/deadline.ts
|
|
22587
22779
|
import { appendFileSync, mkdirSync as mkdirSync3 } from "node:fs";
|
|
22588
|
-
import
|
|
22780
|
+
import path30 from "node:path";
|
|
22589
22781
|
var HOOK_SKIP_TEXT = "workit context skipped: host under load";
|
|
22590
22782
|
var HOOK_DEADLINE_MS = 8000;
|
|
22591
22783
|
var HOST_DEADLINES = {
|
|
@@ -22603,7 +22795,7 @@ var hookDeadlineMs = (env, host = "", native) => {
|
|
|
22603
22795
|
const row = HOST_DEADLINES[host];
|
|
22604
22796
|
return override(env) ?? (row ? native === undefined ? Math.min(...Object.values(row)) : row[native] ?? row[""] : HOOK_DEADLINE_MS);
|
|
22605
22797
|
};
|
|
22606
|
-
var skipsFile = (stateDir) =>
|
|
22798
|
+
var skipsFile = (stateDir) => path30.join(stateDir, HOOK_SKIPS_FILE);
|
|
22607
22799
|
var recordHookSkip = (skip, stateDir = resolveStateDir()) => {
|
|
22608
22800
|
try {
|
|
22609
22801
|
mkdirSync3(stateDir, { recursive: true });
|
|
@@ -23247,8 +23439,8 @@ var codexAdapter = {
|
|
|
23247
23439
|
};
|
|
23248
23440
|
|
|
23249
23441
|
// packages/workit-core/src/hooks/hosts/cursor.ts
|
|
23250
|
-
import
|
|
23251
|
-
import
|
|
23442
|
+
import fs23 from "node:fs";
|
|
23443
|
+
import path31 from "node:path";
|
|
23252
23444
|
var undocumented = { support: "undocumented", native: null };
|
|
23253
23445
|
var none = { support: "none", native: null };
|
|
23254
23446
|
var CURSOR_DESCRIPTOR = {
|
|
@@ -23445,17 +23637,17 @@ var protocolEvent2 = (input) => {
|
|
|
23445
23637
|
};
|
|
23446
23638
|
var TRANSCRIPT_TAIL_BYTES = 256 * 1024;
|
|
23447
23639
|
var lastAssistantText = (file) => {
|
|
23448
|
-
if (!file || !
|
|
23640
|
+
if (!file || !path31.isAbsolute(file))
|
|
23449
23641
|
return null;
|
|
23450
23642
|
try {
|
|
23451
|
-
const size =
|
|
23643
|
+
const size = fs23.statSync(file).size;
|
|
23452
23644
|
const start = Math.max(0, size - TRANSCRIPT_TAIL_BYTES);
|
|
23453
23645
|
const buffer = Buffer.alloc(size - start);
|
|
23454
|
-
const fd =
|
|
23646
|
+
const fd = fs23.openSync(file, "r");
|
|
23455
23647
|
try {
|
|
23456
|
-
|
|
23648
|
+
fs23.readSync(fd, buffer, 0, buffer.length, start);
|
|
23457
23649
|
} finally {
|
|
23458
|
-
|
|
23650
|
+
fs23.closeSync(fd);
|
|
23459
23651
|
}
|
|
23460
23652
|
const lines = buffer.toString("utf8").split(`
|
|
23461
23653
|
`);
|
|
@@ -23482,7 +23674,7 @@ var lastAssistantText = (file) => {
|
|
|
23482
23674
|
return null;
|
|
23483
23675
|
}
|
|
23484
23676
|
};
|
|
23485
|
-
var within2 = (root, dir) => dir === root || dir.startsWith(root.endsWith(
|
|
23677
|
+
var within2 = (root, dir) => dir === root || dir.startsWith(root.endsWith(path31.sep) ? root : `${root}${path31.sep}`);
|
|
23486
23678
|
var hookCwd = (input) => {
|
|
23487
23679
|
const cwd = existingDirectory(input.cwd);
|
|
23488
23680
|
if (cwd && input.hook_event_name === "beforeShellExecution")
|