@brainervirus/workit-opencode 8.36.0 → 8.37.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/dist/plugin.js +860 -725
- package/package.json +2 -2
package/dist/plugin.js
CHANGED
|
@@ -1,3 +1,181 @@
|
|
|
1
|
+
// packages/workit-core/src/hooks/budget-signal.ts
|
|
2
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
3
|
+
import fs2 from "node:fs";
|
|
4
|
+
import path2 from "node:path";
|
|
5
|
+
|
|
6
|
+
// packages/workit-core/src/hooks/standing-signal.ts
|
|
7
|
+
import { createHash } from "node:crypto";
|
|
8
|
+
import fs from "node:fs";
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
var gitStoreDir = (cwd) => {
|
|
11
|
+
try {
|
|
12
|
+
for (let dir = path.resolve(cwd);; dir = path.dirname(dir)) {
|
|
13
|
+
const dotGit = path.join(dir, ".git");
|
|
14
|
+
if (fs.existsSync(dotGit)) {
|
|
15
|
+
let gitDir = dotGit;
|
|
16
|
+
if (fs.statSync(dotGit).isFile()) {
|
|
17
|
+
const target = /^gitdir:\s*(.+)$/mu.exec(fs.readFileSync(dotGit, "utf8"))?.[1]?.trim();
|
|
18
|
+
if (!target)
|
|
19
|
+
return null;
|
|
20
|
+
gitDir = path.resolve(dir, target);
|
|
21
|
+
const common = path.join(gitDir, "commondir");
|
|
22
|
+
if (fs.existsSync(common))
|
|
23
|
+
gitDir = path.resolve(gitDir, fs.readFileSync(common, "utf8").trim());
|
|
24
|
+
}
|
|
25
|
+
return path.join(gitDir, "workit");
|
|
26
|
+
}
|
|
27
|
+
if (path.dirname(dir) === dir)
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
} catch {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
var standingRevFile = (store) => path.join(store, "standing", "rev");
|
|
35
|
+
var standingSeenFile = (store, session, agentId) => path.join(store, "standing", "seen", `${createHash("sha256").update(`${session}\x00${agentId ?? ""}`).digest("hex").slice(0, 32)}.json`);
|
|
36
|
+
var readStandingRev = (store) => {
|
|
37
|
+
try {
|
|
38
|
+
return fs.readFileSync(standingRevFile(store), "utf8").trim() || null;
|
|
39
|
+
} catch {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
var readStandingSeen = (file) => {
|
|
44
|
+
try {
|
|
45
|
+
const value = JSON.parse(fs.readFileSync(file, "utf8"));
|
|
46
|
+
return {
|
|
47
|
+
rev: typeof value.rev === "string" ? value.rev : null,
|
|
48
|
+
ids: Array.isArray(value.ids) ? value.ids.filter((id) => typeof id === "string") : []
|
|
49
|
+
};
|
|
50
|
+
} catch {
|
|
51
|
+
return { rev: null, ids: [] };
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
var writeStandingSeen = (file, seen) => {
|
|
55
|
+
try {
|
|
56
|
+
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
57
|
+
fs.writeFileSync(file, JSON.stringify(seen));
|
|
58
|
+
} catch {}
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
// packages/workit-core/src/hooks/budget-signal.ts
|
|
62
|
+
var hash = (text) => createHash2("sha256").update(text).digest("hex").slice(0, 32);
|
|
63
|
+
var budgetDir = (store) => path2.join(store, "budget");
|
|
64
|
+
var agentBase = (store, session, agentId) => path2.join(budgetDir(store), hash(`${session}\x00${agentId ?? ""}`));
|
|
65
|
+
var spawnsFile = (store, session) => path2.join(budgetDir(store), `spawns-${hash(session)}.jsonl`);
|
|
66
|
+
var spawnBudget = (prompt) => {
|
|
67
|
+
const found = /^TIMEBOX:[^\n]*?\b(\d+)\s+tool calls\b/mu.exec(prompt);
|
|
68
|
+
const n = found ? Number(found[1]) : NaN;
|
|
69
|
+
return Number.isInteger(n) && n > 0 ? n : null;
|
|
70
|
+
};
|
|
71
|
+
var noteSpawnBudget = (cwd, session, type, prompt) => {
|
|
72
|
+
try {
|
|
73
|
+
const store = session ? gitStoreDir(cwd) : null;
|
|
74
|
+
if (!store)
|
|
75
|
+
return;
|
|
76
|
+
fs2.mkdirSync(budgetDir(store), { recursive: true });
|
|
77
|
+
fs2.appendFileSync(spawnsFile(store, session), `${JSON.stringify({ type: type ?? "", n: spawnBudget(prompt) })}
|
|
78
|
+
`);
|
|
79
|
+
} catch {}
|
|
80
|
+
};
|
|
81
|
+
var readBudget = (file) => {
|
|
82
|
+
try {
|
|
83
|
+
const { limit, told } = JSON.parse(fs2.readFileSync(file, "utf8"));
|
|
84
|
+
return typeof limit === "number" && limit > 0 ? { limit, told: Number(told) || 0 } : null;
|
|
85
|
+
} catch {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
var claimSpawnBudget = (cwd, session, agentId, agentType) => {
|
|
90
|
+
try {
|
|
91
|
+
const store = session ? gitStoreDir(cwd) : null;
|
|
92
|
+
if (!store)
|
|
93
|
+
return null;
|
|
94
|
+
const file = spawnsFile(store, session);
|
|
95
|
+
const entries = fs2.readFileSync(file, "utf8").split(`
|
|
96
|
+
`).filter(Boolean).map((line) => JSON.parse(line));
|
|
97
|
+
const at = entries.findIndex((entry) => entry.type === (agentType ?? ""));
|
|
98
|
+
if (at < 0)
|
|
99
|
+
return null;
|
|
100
|
+
const [{ n }] = entries.splice(at, 1);
|
|
101
|
+
fs2.writeFileSync(file, entries.map((entry) => `${JSON.stringify(entry)}
|
|
102
|
+
`).join(""));
|
|
103
|
+
if (typeof n !== "number" || n <= 0)
|
|
104
|
+
return null;
|
|
105
|
+
startBudget(store, session, agentId, n);
|
|
106
|
+
return n;
|
|
107
|
+
} catch {
|
|
108
|
+
return null;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
var startBudget = (store, session, agentId, n) => {
|
|
112
|
+
const dir = budgetDir(store);
|
|
113
|
+
fs2.mkdirSync(dir, { recursive: true });
|
|
114
|
+
const cutoff = Date.now() - 604800000;
|
|
115
|
+
for (const name of fs2.readdirSync(dir))
|
|
116
|
+
try {
|
|
117
|
+
if (fs2.statSync(path2.join(dir, name)).mtimeMs < cutoff)
|
|
118
|
+
fs2.rmSync(path2.join(dir, name));
|
|
119
|
+
} catch {}
|
|
120
|
+
const base = agentBase(store, session, agentId);
|
|
121
|
+
fs2.writeFileSync(`${base}.json`, JSON.stringify({ limit: n, told: 0 }));
|
|
122
|
+
fs2.rmSync(`${base}.calls`, { force: true });
|
|
123
|
+
};
|
|
124
|
+
var tickBudget = (cwd, session, agentId) => {
|
|
125
|
+
try {
|
|
126
|
+
const store = session ? gitStoreDir(cwd) : null;
|
|
127
|
+
if (!store)
|
|
128
|
+
return false;
|
|
129
|
+
const base = agentBase(store, session, agentId);
|
|
130
|
+
const budget = readBudget(`${base}.json`);
|
|
131
|
+
if (!budget)
|
|
132
|
+
return false;
|
|
133
|
+
fs2.appendFileSync(`${base}.calls`, ".");
|
|
134
|
+
return fs2.statSync(`${base}.calls`).size >= budget.limit * (budget.told + 1);
|
|
135
|
+
} catch {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
};
|
|
139
|
+
var lineFor = (calls) => `Tool-call budget reached (${calls}): commit your work, write your report, stop.`;
|
|
140
|
+
var reachedOf = (cwd, session, agentId) => {
|
|
141
|
+
const store = session ? gitStoreDir(cwd) : null;
|
|
142
|
+
const base = store && agentBase(store, session, agentId);
|
|
143
|
+
const budget = base && readBudget(`${base}.json`);
|
|
144
|
+
if (!budget)
|
|
145
|
+
return null;
|
|
146
|
+
return { base, budget, reached: Math.floor(fs2.statSync(`${base}.calls`).size / budget.limit) };
|
|
147
|
+
};
|
|
148
|
+
var budgetStanding = (cwd, session, agentId) => {
|
|
149
|
+
try {
|
|
150
|
+
const at = reachedOf(cwd, session, agentId);
|
|
151
|
+
return at && at.reached > 0 ? lineFor(at.budget.limit * at.reached) : null;
|
|
152
|
+
} catch {
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
var CODEX_GATED = new Set(["bash", "unifiedexec", "shell", "applypatch", "edit", "write"]);
|
|
157
|
+
|
|
158
|
+
// packages/workit-opencode/src/v2/budget.ts
|
|
159
|
+
var claimed = new Set;
|
|
160
|
+
var observeBudget = (root, event, children) => {
|
|
161
|
+
try {
|
|
162
|
+
const parent = children.get(event.sessionID);
|
|
163
|
+
if (parent) {
|
|
164
|
+
if (!claimed.has(event.sessionID)) {
|
|
165
|
+
claimed.add(event.sessionID);
|
|
166
|
+
claimSpawnBudget(root, parent, event.sessionID, null);
|
|
167
|
+
}
|
|
168
|
+
tickBudget(root, parent, event.sessionID);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
if (event.tool !== "subagent")
|
|
172
|
+
return;
|
|
173
|
+
const fields = event.input && typeof event.input === "object" ? Object.values(event.input) : [];
|
|
174
|
+
const prompt = fields.find((field) => typeof field === "string" && field.includes("TIMEBOX:"));
|
|
175
|
+
noteSpawnBudget(root, event.sessionID, null, prompt ?? "");
|
|
176
|
+
} catch {}
|
|
177
|
+
};
|
|
178
|
+
|
|
1
179
|
// node_modules/@opencode/plugin/dist/promise/plugin.js
|
|
2
180
|
function define(plugin) {
|
|
3
181
|
return plugin;
|
|
@@ -6,10 +184,10 @@ function define(plugin) {
|
|
|
6
184
|
// packages/workit-core/src/core.ts
|
|
7
185
|
import { spawnSync as spawnSync16 } from "node:child_process";
|
|
8
186
|
import { existsSync as existsSync9, realpathSync as realpathSync5 } from "node:fs";
|
|
9
|
-
import
|
|
187
|
+
import path27 from "node:path";
|
|
10
188
|
|
|
11
189
|
// packages/workit-core/src/core/task-contract.ts
|
|
12
|
-
import { createHash, randomUUID } from "node:crypto";
|
|
190
|
+
import { createHash as createHash3, randomUUID } from "node:crypto";
|
|
13
191
|
|
|
14
192
|
// node_modules/zod/v4/core/util.js
|
|
15
193
|
function getEnumValues(entries) {
|
|
@@ -6920,7 +7098,7 @@ function canonicalJson(value) {
|
|
|
6920
7098
|
function sha256(value) {
|
|
6921
7099
|
if (typeof value === "string" && invalidUnicode(value))
|
|
6922
7100
|
throw new TypeError("invalid Unicode");
|
|
6923
|
-
return
|
|
7101
|
+
return createHash3("sha256").update(typeof value === "string" ? value : canonicalJson(value), "utf8").digest("hex");
|
|
6924
7102
|
}
|
|
6925
7103
|
function newId() {
|
|
6926
7104
|
return randomUUID().toLowerCase();
|
|
@@ -7453,9 +7631,9 @@ function parseAdvertisedOperation(family, input, host) {
|
|
|
7453
7631
|
return invalidOperation(family, request, parsed.error);
|
|
7454
7632
|
}
|
|
7455
7633
|
// packages/workit-core/src/core/task-store.ts
|
|
7456
|
-
import { createHash as
|
|
7457
|
-
import * as
|
|
7458
|
-
import
|
|
7634
|
+
import { createHash as createHash11, randomUUID as randomUUID3 } from "node:crypto";
|
|
7635
|
+
import * as fs12 from "node:fs";
|
|
7636
|
+
import path14 from "node:path";
|
|
7459
7637
|
|
|
7460
7638
|
// node_modules/@openclaw/fs-safe/dist/errors.js
|
|
7461
7639
|
var OPERATIONAL_CODES = new Set([
|
|
@@ -7506,10 +7684,10 @@ function sameFileIdentity(left, right, platform = process.platform) {
|
|
|
7506
7684
|
// node_modules/@openclaw/fs-safe/dist/sidecar-lock-reclaim.js
|
|
7507
7685
|
import { randomBytes } from "node:crypto";
|
|
7508
7686
|
import fsSync from "node:fs";
|
|
7509
|
-
import
|
|
7687
|
+
import path3 from "node:path";
|
|
7510
7688
|
|
|
7511
7689
|
// node_modules/@openclaw/fs-safe/dist/bounded-read.js
|
|
7512
|
-
import
|
|
7690
|
+
import fs3 from "node:fs";
|
|
7513
7691
|
|
|
7514
7692
|
// node_modules/@openclaw/fs-safe/dist/byte-budget.js
|
|
7515
7693
|
function normalizeMaxBytes(value, options = {}) {
|
|
@@ -7546,7 +7724,7 @@ function readFileDescriptorBoundedSync(fd, maxBytes) {
|
|
|
7546
7724
|
let total = 0;
|
|
7547
7725
|
while (true) {
|
|
7548
7726
|
const length = nextReadLength(total, maxBytes, scratch.length);
|
|
7549
|
-
const bytesRead =
|
|
7727
|
+
const bytesRead = fs3.readSync(fd, scratch, 0, length, null);
|
|
7550
7728
|
if (bytesRead === 0) {
|
|
7551
7729
|
return Buffer.concat(chunks, total);
|
|
7552
7730
|
}
|
|
@@ -7555,9 +7733,9 @@ function readFileDescriptorBoundedSync(fd, maxBytes) {
|
|
|
7555
7733
|
}
|
|
7556
7734
|
|
|
7557
7735
|
// node_modules/@openclaw/fs-safe/dist/read-open-flags.js
|
|
7558
|
-
import
|
|
7736
|
+
import fs4 from "node:fs";
|
|
7559
7737
|
function resolveReadOpenFlags(options) {
|
|
7560
|
-
const constants = options?.constants ??
|
|
7738
|
+
const constants = options?.constants ?? fs4.constants;
|
|
7561
7739
|
const noFollow = process.platform !== "win32" && options?.followSymlinks !== true && typeof constants.O_NOFOLLOW === "number" ? constants.O_NOFOLLOW : 0;
|
|
7562
7740
|
const nonBlocking = process.platform !== "win32" && typeof constants.O_NONBLOCK === "number" ? constants.O_NONBLOCK : 0;
|
|
7563
7741
|
return constants.O_RDONLY | noFollow | nonBlocking;
|
|
@@ -7596,13 +7774,13 @@ ${ownershipToken}
|
|
|
7596
7774
|
return { raw, ownershipToken };
|
|
7597
7775
|
}
|
|
7598
7776
|
function relativeSidecarLockPath(lockRoot, lockPath) {
|
|
7599
|
-
const resolved =
|
|
7600
|
-
const lexicalRelative =
|
|
7601
|
-
const relative = lexicalRelative !== ".." && !lexicalRelative.startsWith(`..${
|
|
7602
|
-
if (!relative || relative === ".." || relative.startsWith(`..${
|
|
7777
|
+
const resolved = path3.resolve(lockPath);
|
|
7778
|
+
const lexicalRelative = path3.relative(lockRoot.rootDir, resolved);
|
|
7779
|
+
const relative = lexicalRelative !== ".." && !lexicalRelative.startsWith(`..${path3.sep}`) && !path3.isAbsolute(lexicalRelative) ? lexicalRelative : path3.relative(lockRoot.rootReal, resolved);
|
|
7780
|
+
if (!relative || relative === ".." || relative.startsWith(`..${path3.sep}`) || path3.isAbsolute(relative)) {
|
|
7603
7781
|
throw new FsSafeError("outside-workspace", "sidecar lock path is outside lockRoot");
|
|
7604
7782
|
}
|
|
7605
|
-
return relative.split(
|
|
7783
|
+
return relative.split(path3.sep).join(path3.posix.sep);
|
|
7606
7784
|
}
|
|
7607
7785
|
function parseSidecarLockPayload(raw, parser) {
|
|
7608
7786
|
if (parser) {
|
|
@@ -7748,8 +7926,8 @@ function getFsSafeLockConfig() {
|
|
|
7748
7926
|
}
|
|
7749
7927
|
|
|
7750
7928
|
// node_modules/@openclaw/fs-safe/dist/file-lock-sync.js
|
|
7751
|
-
import
|
|
7752
|
-
import
|
|
7929
|
+
import fs5 from "node:fs";
|
|
7930
|
+
import path4 from "node:path";
|
|
7753
7931
|
|
|
7754
7932
|
// node_modules/@openclaw/fs-safe/dist/timing.js
|
|
7755
7933
|
function sleepSync(ms) {
|
|
@@ -7779,7 +7957,7 @@ function releaseAllSyncHeldLocks() {
|
|
|
7779
7957
|
}
|
|
7780
7958
|
try {
|
|
7781
7959
|
if (held.fd !== undefined)
|
|
7782
|
-
|
|
7960
|
+
fs5.closeSync(held.fd);
|
|
7783
7961
|
} catch {}
|
|
7784
7962
|
try {
|
|
7785
7963
|
removeSidecarLockIfUnchangedSync(held.lockPath, held.snapshot);
|
|
@@ -7814,7 +7992,7 @@ function releaseSyncHeldLock(held) {
|
|
|
7814
7992
|
if (held.fd !== undefined) {
|
|
7815
7993
|
const fd = held.fd;
|
|
7816
7994
|
held.fd = undefined;
|
|
7817
|
-
|
|
7995
|
+
fs5.closeSync(fd);
|
|
7818
7996
|
}
|
|
7819
7997
|
removeSidecarLockIfUnchangedSync(held.lockPath, held.snapshot);
|
|
7820
7998
|
heldLocks.delete(held.normalizedTargetPath);
|
|
@@ -7837,29 +8015,29 @@ function createSyncHeldLockHandle(held) {
|
|
|
7837
8015
|
};
|
|
7838
8016
|
}
|
|
7839
8017
|
function canonicalLockParentSync(parent) {
|
|
7840
|
-
return process.platform === "win32" ?
|
|
8018
|
+
return process.platform === "win32" ? fs5.realpathSync.native(parent) : fs5.realpathSync(parent);
|
|
7841
8019
|
}
|
|
7842
8020
|
function normalizeTargetPath(targetPath) {
|
|
7843
|
-
const resolved =
|
|
7844
|
-
|
|
8021
|
+
const resolved = path4.resolve(targetPath);
|
|
8022
|
+
fs5.mkdirSync(path4.dirname(resolved), { recursive: true });
|
|
7845
8023
|
try {
|
|
7846
|
-
return
|
|
8024
|
+
return path4.join(canonicalLockParentSync(path4.dirname(resolved)), path4.basename(resolved));
|
|
7847
8025
|
} catch {
|
|
7848
8026
|
return resolved;
|
|
7849
8027
|
}
|
|
7850
8028
|
}
|
|
7851
8029
|
function boundedLockPath(lockPath, lockRoot) {
|
|
7852
|
-
const resolved =
|
|
8030
|
+
const resolved = path4.resolve(lockPath);
|
|
7853
8031
|
if (!lockRoot)
|
|
7854
8032
|
return resolved;
|
|
7855
8033
|
relativeSidecarLockPath(lockRoot, resolved);
|
|
7856
|
-
const parent =
|
|
8034
|
+
const parent = path4.dirname(resolved);
|
|
7857
8035
|
const parentReal = canonicalLockParentSync(parent);
|
|
7858
|
-
const parentRelative =
|
|
7859
|
-
if (parentRelative === ".." || parentRelative.startsWith(`..${
|
|
8036
|
+
const parentRelative = path4.relative(lockRoot.rootReal, parentReal);
|
|
8037
|
+
if (parentRelative === ".." || parentRelative.startsWith(`..${path4.sep}`) || path4.isAbsolute(parentRelative)) {
|
|
7860
8038
|
throw new FsSafeError("outside-workspace", "sidecar lock parent is outside lockRoot");
|
|
7861
8039
|
}
|
|
7862
|
-
return
|
|
8040
|
+
return path4.join(parentReal, path4.basename(resolved));
|
|
7863
8041
|
}
|
|
7864
8042
|
function defaultShouldReclaim(snapshot, staleMs, nowMs) {
|
|
7865
8043
|
const createdAtMs = sidecarLockPayloadCreatedAtMs(snapshot.payload);
|
|
@@ -7869,7 +8047,7 @@ function defaultShouldReclaim(snapshot, staleMs, nowMs) {
|
|
|
7869
8047
|
}
|
|
7870
8048
|
function reclaimGuardExists(reclaimGuardPath) {
|
|
7871
8049
|
try {
|
|
7872
|
-
|
|
8050
|
+
fs5.lstatSync(reclaimGuardPath);
|
|
7873
8051
|
return true;
|
|
7874
8052
|
} catch (error) {
|
|
7875
8053
|
if (error.code === "ENOENT")
|
|
@@ -7933,19 +8111,19 @@ function acquireFileLockSync(targetPath, options) {
|
|
|
7933
8111
|
const { raw, ownershipToken } = serializeSidecarLockPayload(payload);
|
|
7934
8112
|
let lockFileCreateDenied = false;
|
|
7935
8113
|
try {
|
|
7936
|
-
const noFollow = process.platform !== "win32" && typeof
|
|
8114
|
+
const noFollow = process.platform !== "win32" && typeof fs5.constants.O_NOFOLLOW === "number" ? fs5.constants.O_NOFOLLOW : 0;
|
|
7937
8115
|
try {
|
|
7938
|
-
fd =
|
|
8116
|
+
fd = fs5.openSync(lockPath, fs5.constants.O_WRONLY | fs5.constants.O_CREAT | fs5.constants.O_EXCL | noFollow, 384);
|
|
7939
8117
|
} catch (error) {
|
|
7940
8118
|
lockFileCreateDenied = isTransientLockFileDenial(error, lockPath);
|
|
7941
8119
|
throw error;
|
|
7942
8120
|
}
|
|
7943
|
-
|
|
7944
|
-
|
|
8121
|
+
fs5.writeFileSync(fd, raw, "utf8");
|
|
8122
|
+
fs5.fsyncSync(fd);
|
|
7945
8123
|
const snapshot = {
|
|
7946
8124
|
raw,
|
|
7947
8125
|
payload,
|
|
7948
|
-
stat:
|
|
8126
|
+
stat: fs5.fstatSync(fd),
|
|
7949
8127
|
ownershipToken
|
|
7950
8128
|
};
|
|
7951
8129
|
const createdHeld = {
|
|
@@ -7980,8 +8158,8 @@ function acquireFileLockSync(targetPath, options) {
|
|
|
7980
8158
|
return returnedHandle;
|
|
7981
8159
|
} catch (error) {
|
|
7982
8160
|
if (fd !== undefined) {
|
|
7983
|
-
const failed = { payload: null, stat:
|
|
7984
|
-
|
|
8161
|
+
const failed = { payload: null, stat: fs5.fstatSync(fd) };
|
|
8162
|
+
fs5.closeSync(fd);
|
|
7985
8163
|
fd = undefined;
|
|
7986
8164
|
removeSidecarLockIfUnchangedSync(lockPath, failed);
|
|
7987
8165
|
}
|
|
@@ -8030,7 +8208,7 @@ function acquireFileLockSync(targetPath, options) {
|
|
|
8030
8208
|
})) {
|
|
8031
8209
|
let ownsReclaimGuard = false;
|
|
8032
8210
|
try {
|
|
8033
|
-
|
|
8211
|
+
fs5.mkdirSync(reclaimGuardPath);
|
|
8034
8212
|
ownsReclaimGuard = true;
|
|
8035
8213
|
if (removeSidecarLockIfUnchangedSync(lockPath, snapshot))
|
|
8036
8214
|
continue;
|
|
@@ -8043,7 +8221,7 @@ function acquireFileLockSync(targetPath, options) {
|
|
|
8043
8221
|
} finally {
|
|
8044
8222
|
if (ownsReclaimGuard) {
|
|
8045
8223
|
try {
|
|
8046
|
-
|
|
8224
|
+
fs5.rmdirSync(reclaimGuardPath);
|
|
8047
8225
|
} catch {}
|
|
8048
8226
|
}
|
|
8049
8227
|
}
|
|
@@ -8059,12 +8237,12 @@ function acquireFileLockSync(targetPath, options) {
|
|
|
8059
8237
|
}
|
|
8060
8238
|
}
|
|
8061
8239
|
// packages/workit-core/src/host-session.ts
|
|
8062
|
-
import { createHash as
|
|
8063
|
-
import
|
|
8064
|
-
import
|
|
8240
|
+
import { createHash as createHash9, randomBytes as randomBytes2, timingSafeEqual } from "node:crypto";
|
|
8241
|
+
import fs9 from "node:fs";
|
|
8242
|
+
import path11 from "node:path";
|
|
8065
8243
|
|
|
8066
8244
|
// packages/workit-core/src/core/branch.ts
|
|
8067
|
-
import { createHash as
|
|
8245
|
+
import { createHash as createHash7 } from "node:crypto";
|
|
8068
8246
|
|
|
8069
8247
|
// packages/workit-core/src/core/branch-policy.ts
|
|
8070
8248
|
import { spawnSync } from "node:child_process";
|
|
@@ -8080,7 +8258,7 @@ import {
|
|
|
8080
8258
|
writeFileSync
|
|
8081
8259
|
} from "node:fs";
|
|
8082
8260
|
import os from "node:os";
|
|
8083
|
-
import
|
|
8261
|
+
import path5 from "node:path";
|
|
8084
8262
|
|
|
8085
8263
|
// packages/workit-core/src/core/boundary.ts
|
|
8086
8264
|
import { statSync } from "node:fs";
|
|
@@ -8139,7 +8317,7 @@ var mergePreset = (preset, input = {}, current = {
|
|
|
8139
8317
|
protected: preset === "custom" ? input.protectedNames ?? current.branchPolicy.protected : [...defs.protected]
|
|
8140
8318
|
};
|
|
8141
8319
|
};
|
|
8142
|
-
var resolveConfigDir = () => process.env.WORKFLOW_TOOLKIT_CONFIG ?? process.env.WORKFLOW_TOOLKIT_CONFIG_DIR ??
|
|
8320
|
+
var resolveConfigDir = () => process.env.WORKFLOW_TOOLKIT_CONFIG ?? process.env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path5.join(process.env.XDG_CONFIG_HOME || path5.join(os.homedir(), ".config"), "workit");
|
|
8143
8321
|
var migratedDir = null;
|
|
8144
8322
|
var migrationFailed = false;
|
|
8145
8323
|
var ensureConfigDir = (dir = resolveConfigDir()) => {
|
|
@@ -8149,7 +8327,7 @@ var ensureConfigDir = (dir = resolveConfigDir()) => {
|
|
|
8149
8327
|
migratedDir = dir;
|
|
8150
8328
|
return dir;
|
|
8151
8329
|
}
|
|
8152
|
-
const legacy =
|
|
8330
|
+
const legacy = path5.join(process.env.XDG_CONFIG_HOME || path5.join(os.homedir(), ".config"), "workflow-toolkit");
|
|
8153
8331
|
if (!existsSync(legacy)) {
|
|
8154
8332
|
migratedDir = dir;
|
|
8155
8333
|
return dir;
|
|
@@ -8162,8 +8340,8 @@ var ensureConfigDir = (dir = resolveConfigDir()) => {
|
|
|
8162
8340
|
mkdirSync(dir, { recursive: true });
|
|
8163
8341
|
diagnosticLogger?.info(EVENT.migration, { from: legacy, to: dir });
|
|
8164
8342
|
for (const entry of readdirSync(legacy, { withFileTypes: true })) {
|
|
8165
|
-
const src =
|
|
8166
|
-
const dest =
|
|
8343
|
+
const src = path5.join(legacy, entry.name);
|
|
8344
|
+
const dest = path5.join(dir, entry.name);
|
|
8167
8345
|
if (existsSync(dest))
|
|
8168
8346
|
continue;
|
|
8169
8347
|
try {
|
|
@@ -8235,7 +8413,7 @@ var parseConfigResult = (raw, file) => {
|
|
|
8235
8413
|
return { status: "valid", path: file, config };
|
|
8236
8414
|
};
|
|
8237
8415
|
var readConfigTyped = (dir) => {
|
|
8238
|
-
const file =
|
|
8416
|
+
const file = path5.join(dir ?? configDir(), "config.json");
|
|
8239
8417
|
return parseConfigResult(readSafe(file), file);
|
|
8240
8418
|
};
|
|
8241
8419
|
var readConfig = () => {
|
|
@@ -8253,10 +8431,10 @@ var mergeConfigValues = (input, current) => ({
|
|
|
8253
8431
|
var writeConfig = (config) => {
|
|
8254
8432
|
const dir = configDir();
|
|
8255
8433
|
mkdirSync(dir, { recursive: true });
|
|
8256
|
-
writeFileSync(
|
|
8434
|
+
writeFileSync(path5.join(dir, "config.json"), JSON.stringify(config, null, 2) + `
|
|
8257
8435
|
`, "utf8");
|
|
8258
8436
|
};
|
|
8259
|
-
var vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ??
|
|
8437
|
+
var vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ?? path5.join(configDir(), "vcs.json");
|
|
8260
8438
|
var branchGlobPattern = (glob) => new RegExp(`^${glob.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")}$`, "i");
|
|
8261
8439
|
var resolveBranchPolicy = (config, workspace, repoPreset) => {
|
|
8262
8440
|
const wp = workspace?.branchPolicy ?? {};
|
|
@@ -8440,9 +8618,9 @@ var gitContext = (workspaceRoot, paths = []) => {
|
|
|
8440
8618
|
|
|
8441
8619
|
// packages/workit-core/src/core/workspaces.ts
|
|
8442
8620
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
8443
|
-
import { createHash as
|
|
8621
|
+
import { createHash as createHash4 } from "node:crypto";
|
|
8444
8622
|
import { readFileSync as readFileSync2, realpathSync } from "node:fs";
|
|
8445
|
-
import
|
|
8623
|
+
import path6 from "node:path";
|
|
8446
8624
|
var nonBlank = string2().refine((value) => value.trim().length > 0, "must not be blank");
|
|
8447
8625
|
var branchPreset = custom((value) => typeof value === "string" && Object.hasOwn(PRESETS, value), "unsupported branch preset");
|
|
8448
8626
|
var commitPreset = custom((value) => typeof value === "string" && COMMIT_PRESETS.includes(value), "unsupported commit preset");
|
|
@@ -8504,7 +8682,7 @@ var releaseTrackSchema = object({
|
|
|
8504
8682
|
});
|
|
8505
8683
|
}
|
|
8506
8684
|
}
|
|
8507
|
-
if (track.versionSource?.kind === "package-json" && (
|
|
8685
|
+
if (track.versionSource?.kind === "package-json" && (path6.posix.isAbsolute(track.versionSource.path.replaceAll("\\", "/")) || /^[A-Za-z]:\//u.test(track.versionSource.path.replaceAll("\\", "/")) || track.versionSource.path.replaceAll("\\", "/").split("/").includes(".."))) {
|
|
8508
8686
|
context.addIssue({
|
|
8509
8687
|
code: "custom",
|
|
8510
8688
|
path: ["versionSource", "path"],
|
|
@@ -8575,7 +8753,7 @@ var workspacesFileSchema = object({
|
|
|
8575
8753
|
names.add(workspace.name);
|
|
8576
8754
|
}
|
|
8577
8755
|
});
|
|
8578
|
-
var workspacesRevision = (contents) =>
|
|
8756
|
+
var workspacesRevision = (contents) => createHash4("sha256").update(contents ?? "<missing>").digest("hex");
|
|
8579
8757
|
var validateWorkspacesDocument = (parsed, file) => {
|
|
8580
8758
|
if (!isConfigObject(parsed)) {
|
|
8581
8759
|
return {
|
|
@@ -8621,7 +8799,7 @@ var validateWorkspacesDocument = (parsed, file) => {
|
|
|
8621
8799
|
};
|
|
8622
8800
|
};
|
|
8623
8801
|
var readWorkspacesResult = (dir = configDir()) => {
|
|
8624
|
-
const file =
|
|
8802
|
+
const file = path6.join(dir, "workspaces.json");
|
|
8625
8803
|
let raw;
|
|
8626
8804
|
try {
|
|
8627
8805
|
raw = readFileSync2(file, "utf8");
|
|
@@ -8740,9 +8918,9 @@ var mainCheckoutOf = (cwd) => {
|
|
|
8740
8918
|
let main = null;
|
|
8741
8919
|
const dirs = git(["rev-parse", "--path-format=absolute", "--git-dir", "--git-common-dir"]);
|
|
8742
8920
|
const [gitDir, common] = (dirs ?? "").trim().split(/\r?\n/u);
|
|
8743
|
-
if (gitDir && common &&
|
|
8921
|
+
if (gitDir && common && path6.resolve(gitDir) !== path6.resolve(common)) {
|
|
8744
8922
|
const listed = /^worktree (.+)$/mu.exec(git(["worktree", "list", "--porcelain"]) ?? "")?.[1];
|
|
8745
|
-
main = listed?.trim() || (
|
|
8923
|
+
main = listed?.trim() || (path6.basename(common) === ".git" ? path6.dirname(common) : common);
|
|
8746
8924
|
}
|
|
8747
8925
|
mainCheckouts.set(cwd, main);
|
|
8748
8926
|
return main;
|
|
@@ -8833,7 +9011,7 @@ var runtimeWorkspaceIndexSchema = object({
|
|
|
8833
9011
|
workspaces: array(object({ name: nonBlank, glob: nonBlank }).passthrough()).optional()
|
|
8834
9012
|
}).passthrough();
|
|
8835
9013
|
var matchRuntimeWorkspace = (cwd, dir = configDir()) => {
|
|
8836
|
-
const file =
|
|
9014
|
+
const file = path6.join(dir, "workspaces.json");
|
|
8837
9015
|
let raw;
|
|
8838
9016
|
try {
|
|
8839
9017
|
raw = readFileSync2(file, "utf8");
|
|
@@ -8939,20 +9117,20 @@ function workspaceDefaultTarget(cwd, globalDefault) {
|
|
|
8939
9117
|
}
|
|
8940
9118
|
|
|
8941
9119
|
// packages/workit-core/src/core/vcs-config.ts
|
|
8942
|
-
import
|
|
8943
|
-
import
|
|
9120
|
+
import fs7 from "node:fs";
|
|
9121
|
+
import path8 from "node:path";
|
|
8944
9122
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
8945
9123
|
|
|
8946
9124
|
// packages/workit-core/src/core/release-tracks.ts
|
|
8947
|
-
import { createHash as
|
|
9125
|
+
import { createHash as createHash6 } from "node:crypto";
|
|
8948
9126
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
8949
9127
|
|
|
8950
9128
|
// packages/workit-core/src/git/rev.ts
|
|
8951
9129
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
8952
|
-
import { createHash as
|
|
8953
|
-
import
|
|
9130
|
+
import { createHash as createHash5 } from "node:crypto";
|
|
9131
|
+
import fs6 from "node:fs";
|
|
8954
9132
|
import os2 from "node:os";
|
|
8955
|
-
import
|
|
9133
|
+
import path7 from "node:path";
|
|
8956
9134
|
var MAX_BUFFER = 256 * 1024 * 1024;
|
|
8957
9135
|
var GIT_TIMEOUTS = { local: 20000, worktree: 120000, network: 15000 };
|
|
8958
9136
|
var git = (cwd, args, options = {}) => {
|
|
@@ -9017,10 +9195,10 @@ function headSha(cwd) {
|
|
|
9017
9195
|
var emptyTree = (cwd) => line(git(cwd, ["mktree"], { input: "" }));
|
|
9018
9196
|
var MAX_UNTRACKED_BYTES = 5 * 1024 * 1024;
|
|
9019
9197
|
var seedIndex = (from, to) => {
|
|
9020
|
-
|
|
9021
|
-
const { atimeNs, mtimeNs } =
|
|
9198
|
+
fs6.copyFileSync(from, to);
|
|
9199
|
+
const { atimeNs, mtimeNs } = fs6.statSync(from, { bigint: true });
|
|
9022
9200
|
const seconds = (ns) => (Number(ns / 1000n) - 1) / 1e6;
|
|
9023
|
-
|
|
9201
|
+
fs6.utimesSync(to, seconds(atimeNs), seconds(mtimeNs));
|
|
9024
9202
|
};
|
|
9025
9203
|
function worktreeTree(cwd, options = {}) {
|
|
9026
9204
|
const top = line(git(cwd, ["rev-parse", "--show-toplevel"]));
|
|
@@ -9029,10 +9207,10 @@ function worktreeTree(cwd, options = {}) {
|
|
|
9029
9207
|
return null;
|
|
9030
9208
|
const cap = options.maxUntrackedBytes ?? MAX_UNTRACKED_BYTES;
|
|
9031
9209
|
const timeoutMs = options.timeoutMs ?? GIT_TIMEOUTS.worktree;
|
|
9032
|
-
const scratch =
|
|
9210
|
+
const scratch = fs6.mkdtempSync(path7.join(os2.tmpdir(), "workit-tree-"));
|
|
9033
9211
|
try {
|
|
9034
|
-
const tempIndex =
|
|
9035
|
-
if (
|
|
9212
|
+
const tempIndex = path7.join(scratch, "index");
|
|
9213
|
+
if (fs6.existsSync(indexPath))
|
|
9036
9214
|
seedIndex(indexPath, tempIndex);
|
|
9037
9215
|
const env = { ...process.env, GIT_INDEX_FILE: tempIndex };
|
|
9038
9216
|
const untracked = git(top, ["ls-files", "--others", "--exclude-standard", "-z"], {
|
|
@@ -9044,7 +9222,7 @@ function worktreeTree(cwd, options = {}) {
|
|
|
9044
9222
|
const skipped = [];
|
|
9045
9223
|
for (const file of untracked.stdout.split("\x00").filter(Boolean)) {
|
|
9046
9224
|
try {
|
|
9047
|
-
const stat =
|
|
9225
|
+
const stat = fs6.statSync(path7.join(top, file));
|
|
9048
9226
|
if (stat.isFile() && stat.size > cap)
|
|
9049
9227
|
skipped.push({ path: file, size: stat.size, mtimeMs: Math.trunc(stat.mtimeMs) });
|
|
9050
9228
|
} catch {}
|
|
@@ -9061,10 +9239,10 @@ function worktreeTree(cwd, options = {}) {
|
|
|
9061
9239
|
if (!tree)
|
|
9062
9240
|
return null;
|
|
9063
9241
|
const base = line(git(top, ["rev-parse", "--verify", "-q", "HEAD^{tree}"])) ?? emptyTree(top);
|
|
9064
|
-
const key = skipped.length ? `sha256:${
|
|
9242
|
+
const key = skipped.length ? `sha256:${createHash5("sha256").update(JSON.stringify({ tree, skipped })).digest("hex")}` : tree;
|
|
9065
9243
|
return { tree, key, dirty: tree !== base || skipped.length > 0, skipped };
|
|
9066
9244
|
} finally {
|
|
9067
|
-
|
|
9245
|
+
fs6.rmSync(scratch, { recursive: true, force: true });
|
|
9068
9246
|
}
|
|
9069
9247
|
}
|
|
9070
9248
|
function worktreeSignal(cwd, options = {}) {
|
|
@@ -9084,16 +9262,16 @@ function worktreeSignal(cwd, options = {}) {
|
|
|
9084
9262
|
});
|
|
9085
9263
|
if (!status.ok)
|
|
9086
9264
|
return null;
|
|
9087
|
-
const hash =
|
|
9265
|
+
const hash = createHash5("sha256");
|
|
9088
9266
|
hash.update(`${headSha(top) ?? "unborn"}\x00`);
|
|
9089
9267
|
for (const entry of status.stdout.split("\x00")) {
|
|
9090
9268
|
if (entry.length < 4)
|
|
9091
9269
|
continue;
|
|
9092
9270
|
const file = entry.slice(3);
|
|
9093
|
-
const absolute =
|
|
9271
|
+
const absolute = path7.join(top, file);
|
|
9094
9272
|
let stat = "-";
|
|
9095
9273
|
try {
|
|
9096
|
-
const info =
|
|
9274
|
+
const info = fs6.lstatSync(absolute, { bigint: true });
|
|
9097
9275
|
stat = `${info.mode.toString(8)}:${info.size}:${info.mtimeNs}`;
|
|
9098
9276
|
if (info.isDirectory())
|
|
9099
9277
|
stat += `:${headSha(absolute) ?? "-"}`;
|
|
@@ -9724,7 +9902,7 @@ function resolveTrackFor(cwd, options) {
|
|
|
9724
9902
|
]) ?? "",
|
|
9725
9903
|
git2(cwd, ["config", "--get", recordedBaseKey(branch)]) ?? ""
|
|
9726
9904
|
] : [];
|
|
9727
|
-
key =
|
|
9905
|
+
key = createHash6("sha256").update(JSON.stringify({ cwd, input, refs, head, own })).digest("hex");
|
|
9728
9906
|
const hit = memo2.get(key);
|
|
9729
9907
|
if (hit)
|
|
9730
9908
|
return hit;
|
|
@@ -9739,7 +9917,7 @@ function resolveTrackFor(cwd, options) {
|
|
|
9739
9917
|
}
|
|
9740
9918
|
|
|
9741
9919
|
// packages/workit-core/src/core/vcs-config.ts
|
|
9742
|
-
var workspacesPath = () =>
|
|
9920
|
+
var workspacesPath = () => path8.join(configDir(), "workspaces.json");
|
|
9743
9921
|
var vcsCwd = (cwd) => cwd ?? process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd();
|
|
9744
9922
|
var remoteProvider = (cwd) => {
|
|
9745
9923
|
const r = spawnSync5("git", ["remote", "get-url", "origin"], { cwd, encoding: "utf8" });
|
|
@@ -9829,7 +10007,7 @@ var readVcsConfig = () => {
|
|
|
9829
10007
|
const file = vcsConfigPath();
|
|
9830
10008
|
let raw;
|
|
9831
10009
|
try {
|
|
9832
|
-
raw =
|
|
10010
|
+
raw = fs7.readFileSync(file, "utf8");
|
|
9833
10011
|
} catch {
|
|
9834
10012
|
return { status: "missing", path: file, config: {} };
|
|
9835
10013
|
}
|
|
@@ -9954,7 +10132,7 @@ function vcsConfig(mode, cwd, options = {}) {
|
|
|
9954
10132
|
const prov = cfg[provider] ?? {};
|
|
9955
10133
|
const out = {
|
|
9956
10134
|
ok: true,
|
|
9957
|
-
configPath:
|
|
10135
|
+
configPath: path8.resolve(cfgPath),
|
|
9958
10136
|
provider,
|
|
9959
10137
|
defaultTargetBranch: workspaceDefault,
|
|
9960
10138
|
pr: cfg.pr ?? {},
|
|
@@ -10185,7 +10363,7 @@ var branchPolicySnapshotFor = (workspaceRoot) => {
|
|
|
10185
10363
|
const source = resolved.provenance.branchPolicy;
|
|
10186
10364
|
const allowed = branchPolicy.allowed.map((pattern) => `${pattern.source}/${pattern.flags}`).toSorted();
|
|
10187
10365
|
const protectedRefs = [...branchPolicy.protected].map((name) => name.toLowerCase()).toSorted();
|
|
10188
|
-
const fingerprint =
|
|
10366
|
+
const fingerprint = createHash7("sha256").update(JSON.stringify({ allowed, protectedRefs, source })).digest("hex");
|
|
10189
10367
|
return {
|
|
10190
10368
|
branchPolicy,
|
|
10191
10369
|
namePolicy: { allowed: branchPolicy.allowed, protected: branchPolicy.protected },
|
|
@@ -10254,7 +10432,7 @@ var isProtectedTarget = (root, name) => {
|
|
|
10254
10432
|
|
|
10255
10433
|
// packages/workit-core/src/core/logger.ts
|
|
10256
10434
|
import os3 from "node:os";
|
|
10257
|
-
import
|
|
10435
|
+
import path9 from "node:path";
|
|
10258
10436
|
var SENSITIVE_WORDS = new Set([
|
|
10259
10437
|
"token",
|
|
10260
10438
|
"secret",
|
|
@@ -10299,23 +10477,23 @@ var resolveStateDir = () => {
|
|
|
10299
10477
|
return override;
|
|
10300
10478
|
const home = os3.homedir();
|
|
10301
10479
|
if (process.env.XDG_STATE_HOME)
|
|
10302
|
-
return
|
|
10480
|
+
return path9.join(process.env.XDG_STATE_HOME, "workit");
|
|
10303
10481
|
switch (os3.platform()) {
|
|
10304
10482
|
case "darwin":
|
|
10305
|
-
return
|
|
10483
|
+
return path9.join(home, "Library", "Application Support", "workit");
|
|
10306
10484
|
case "win32":
|
|
10307
|
-
return
|
|
10485
|
+
return path9.join(process.env.LOCALAPPDATA ?? path9.join(home, "AppData", "Local"), "workit");
|
|
10308
10486
|
default:
|
|
10309
|
-
return
|
|
10487
|
+
return path9.join(process.env.HOME ?? home, ".local", "state", "workit");
|
|
10310
10488
|
}
|
|
10311
10489
|
};
|
|
10312
10490
|
var homePattern = new RegExp(`${escapeRegExp2(os3.homedir())}(?=[/\\\\]|$)|\\$HOME(?=[/\\\\]|$)`, "g");
|
|
10313
10491
|
|
|
10314
10492
|
// packages/workit-core/src/store/paths.ts
|
|
10315
10493
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
10316
|
-
import { createHash as
|
|
10317
|
-
import
|
|
10318
|
-
import
|
|
10494
|
+
import { createHash as createHash8 } from "node:crypto";
|
|
10495
|
+
import fs8 from "node:fs";
|
|
10496
|
+
import path10 from "node:path";
|
|
10319
10497
|
var NOT_A_REPO = /not a git repository \(or any (of the parent directories|parent up to)/u;
|
|
10320
10498
|
var gitRun = (cwd, args) => {
|
|
10321
10499
|
const run = spawnSync6("git", args, {
|
|
@@ -10340,10 +10518,10 @@ var gitRun = (cwd, args) => {
|
|
|
10340
10518
|
missing: error?.code === "ENOENT"
|
|
10341
10519
|
};
|
|
10342
10520
|
};
|
|
10343
|
-
var shortHash = (value) =>
|
|
10521
|
+
var shortHash = (value) => createHash8("sha256").update(value).digest("hex").slice(0, 12);
|
|
10344
10522
|
var real = (file) => {
|
|
10345
10523
|
try {
|
|
10346
|
-
return
|
|
10524
|
+
return fs8.realpathSync.native(file);
|
|
10347
10525
|
} catch {
|
|
10348
10526
|
return file;
|
|
10349
10527
|
}
|
|
@@ -10357,14 +10535,14 @@ var DISCOVERY_ENV = [
|
|
|
10357
10535
|
];
|
|
10358
10536
|
var isGitDir = (dir) => {
|
|
10359
10537
|
try {
|
|
10360
|
-
return
|
|
10538
|
+
return fs8.statSync(path10.join(dir, "HEAD")).isFile() && fs8.statSync(path10.join(dir, "objects")).isDirectory() && fs8.statSync(path10.join(dir, "refs")).isDirectory();
|
|
10361
10539
|
} catch {
|
|
10362
10540
|
return false;
|
|
10363
10541
|
}
|
|
10364
10542
|
};
|
|
10365
10543
|
var reftableRefs = (common) => {
|
|
10366
10544
|
try {
|
|
10367
|
-
return /^\s*refstorage\s*=\s*reftable\s*$/imu.test(
|
|
10545
|
+
return /^\s*refstorage\s*=\s*reftable\s*$/imu.test(fs8.readFileSync(path10.join(common, "config"), "utf8"));
|
|
10368
10546
|
} catch {
|
|
10369
10547
|
return false;
|
|
10370
10548
|
}
|
|
@@ -10377,17 +10555,17 @@ function fastGit(root) {
|
|
|
10377
10555
|
for (;; ) {
|
|
10378
10556
|
let stat;
|
|
10379
10557
|
try {
|
|
10380
|
-
stat =
|
|
10558
|
+
stat = fs8.statSync(dir);
|
|
10381
10559
|
} catch {
|
|
10382
10560
|
return null;
|
|
10383
10561
|
}
|
|
10384
10562
|
if (device !== null && stat.dev !== device)
|
|
10385
10563
|
return { kind: "none" };
|
|
10386
10564
|
device = stat.dev;
|
|
10387
|
-
const dotGit =
|
|
10565
|
+
const dotGit = path10.join(dir, ".git");
|
|
10388
10566
|
let entry = null;
|
|
10389
10567
|
try {
|
|
10390
|
-
entry =
|
|
10568
|
+
entry = fs8.statSync(dotGit);
|
|
10391
10569
|
} catch {}
|
|
10392
10570
|
let gitDir = null;
|
|
10393
10571
|
let top = null;
|
|
@@ -10398,26 +10576,26 @@ function fastGit(root) {
|
|
|
10398
10576
|
else if (entry.isFile()) {
|
|
10399
10577
|
let text = "";
|
|
10400
10578
|
try {
|
|
10401
|
-
text =
|
|
10579
|
+
text = fs8.readFileSync(dotGit, "utf8");
|
|
10402
10580
|
} catch {
|
|
10403
10581
|
return null;
|
|
10404
10582
|
}
|
|
10405
10583
|
const match = /^gitdir: (.+)$/mu.exec(text);
|
|
10406
10584
|
if (!match)
|
|
10407
10585
|
return null;
|
|
10408
|
-
gitDir =
|
|
10586
|
+
gitDir = path10.resolve(dir, match[1].trim());
|
|
10409
10587
|
} else
|
|
10410
10588
|
return null;
|
|
10411
|
-
if (!
|
|
10589
|
+
if (!fs8.existsSync(path10.join(gitDir, "HEAD")))
|
|
10412
10590
|
return null;
|
|
10413
10591
|
} else if (isGitDir(dir))
|
|
10414
10592
|
gitDir = dir;
|
|
10415
10593
|
if (gitDir) {
|
|
10416
10594
|
let common = gitDir;
|
|
10417
10595
|
try {
|
|
10418
|
-
common =
|
|
10596
|
+
common = path10.resolve(gitDir, fs8.readFileSync(path10.join(gitDir, "commondir"), "utf8").trim());
|
|
10419
10597
|
} catch {}
|
|
10420
|
-
if (!
|
|
10598
|
+
if (!fs8.existsSync(path10.join(common, "objects")))
|
|
10421
10599
|
return null;
|
|
10422
10600
|
return {
|
|
10423
10601
|
kind: "repo",
|
|
@@ -10427,26 +10605,26 @@ function fastGit(root) {
|
|
|
10427
10605
|
reftable: reftableRefs(common)
|
|
10428
10606
|
};
|
|
10429
10607
|
}
|
|
10430
|
-
const parent =
|
|
10608
|
+
const parent = path10.dirname(dir);
|
|
10431
10609
|
if (parent === dir)
|
|
10432
10610
|
return { kind: "none" };
|
|
10433
10611
|
dir = parent;
|
|
10434
10612
|
}
|
|
10435
10613
|
}
|
|
10436
10614
|
function resolveStore(root) {
|
|
10437
|
-
root =
|
|
10615
|
+
root = path10.resolve(root);
|
|
10438
10616
|
let directory = false;
|
|
10439
10617
|
try {
|
|
10440
|
-
directory =
|
|
10618
|
+
directory = fs8.statSync(root).isDirectory();
|
|
10441
10619
|
} catch {}
|
|
10442
10620
|
if (!directory)
|
|
10443
|
-
return { dir:
|
|
10621
|
+
return { dir: path10.join(root, ".workit"), shared: false, top: null };
|
|
10444
10622
|
const fast = fastGit(root);
|
|
10445
10623
|
if (fast?.kind === "none")
|
|
10446
|
-
return { dir:
|
|
10624
|
+
return { dir: path10.join(root, ".workit"), shared: false, top: null };
|
|
10447
10625
|
if (fast?.kind === "repo")
|
|
10448
10626
|
return {
|
|
10449
|
-
dir:
|
|
10627
|
+
dir: path10.join(fast.common, "workit"),
|
|
10450
10628
|
shared: true,
|
|
10451
10629
|
top: fast.top,
|
|
10452
10630
|
git: { gitDir: fast.gitDir, top: fast.top, reftable: fast.reftable }
|
|
@@ -10456,20 +10634,20 @@ function resolveStore(root) {
|
|
|
10456
10634
|
if (run.ok && common) {
|
|
10457
10635
|
const top = gitRun(root, ["rev-parse", "--path-format=absolute", "--show-toplevel"]);
|
|
10458
10636
|
return {
|
|
10459
|
-
dir:
|
|
10637
|
+
dir: path10.join(real(path10.resolve(root, common)), "workit"),
|
|
10460
10638
|
shared: true,
|
|
10461
10639
|
top: top.ok && top.stdout.trim() ? real(top.stdout.trim()) : null
|
|
10462
10640
|
};
|
|
10463
10641
|
}
|
|
10464
10642
|
if (run.missing || !run.ok && NOT_A_REPO.test(run.stderr))
|
|
10465
|
-
return { dir:
|
|
10643
|
+
return { dir: path10.join(root, ".workit"), shared: false, top: null };
|
|
10466
10644
|
return new Error(`cannot locate the workit store: git rev-parse failed (${run.stderr.trim().split(`
|
|
10467
10645
|
`)[0] || "no output"}); fix the repository (git status should work here)`);
|
|
10468
10646
|
}
|
|
10469
10647
|
var rebasingBranch = (gitDir) => {
|
|
10470
10648
|
for (const state of ["rebase-merge", "rebase-apply"]) {
|
|
10471
10649
|
try {
|
|
10472
|
-
const ref =
|
|
10650
|
+
const ref = fs8.readFileSync(path10.join(gitDir, state, "head-name"), "utf8").trim();
|
|
10473
10651
|
const match = /^refs\/heads\/(.+)$/u.exec(ref);
|
|
10474
10652
|
if (match)
|
|
10475
10653
|
return match[1];
|
|
@@ -10484,7 +10662,7 @@ function resolveTaskKey(root, location) {
|
|
|
10484
10662
|
if (location.git && !location.git.reftable) {
|
|
10485
10663
|
let head = "";
|
|
10486
10664
|
try {
|
|
10487
|
-
head =
|
|
10665
|
+
head = fs8.readFileSync(path10.join(location.git.gitDir, "HEAD"), "utf8").trim();
|
|
10488
10666
|
} catch {}
|
|
10489
10667
|
const ref = /^ref: refs\/heads\/(.+)$/u.exec(head);
|
|
10490
10668
|
if (ref && ref[1] !== ".invalid")
|
|
@@ -10515,10 +10693,10 @@ function resolveTaskKey(root, location) {
|
|
|
10515
10693
|
return { key: `detached-${shortHash(real(worktree))}`, kind: "detached", branch: null };
|
|
10516
10694
|
}
|
|
10517
10695
|
function checkoutRootOf(root, location) {
|
|
10518
|
-
const resolved =
|
|
10696
|
+
const resolved = path10.resolve(root);
|
|
10519
10697
|
let canonical = resolved;
|
|
10520
10698
|
try {
|
|
10521
|
-
canonical =
|
|
10699
|
+
canonical = fs8.realpathSync(resolved);
|
|
10522
10700
|
} catch {
|
|
10523
10701
|
return resolved;
|
|
10524
10702
|
}
|
|
@@ -10528,7 +10706,7 @@ function checkoutRootOf(root, location) {
|
|
|
10528
10706
|
if (real(canonical) === found.top)
|
|
10529
10707
|
return canonical;
|
|
10530
10708
|
try {
|
|
10531
|
-
return
|
|
10709
|
+
return fs8.realpathSync(found.top);
|
|
10532
10710
|
} catch {
|
|
10533
10711
|
return canonical;
|
|
10534
10712
|
}
|
|
@@ -10540,25 +10718,25 @@ function branchRenames(location) {
|
|
|
10540
10718
|
const walk = (dir) => {
|
|
10541
10719
|
let entries;
|
|
10542
10720
|
try {
|
|
10543
|
-
entries =
|
|
10721
|
+
entries = fs8.readdirSync(dir, { withFileTypes: true });
|
|
10544
10722
|
} catch {
|
|
10545
10723
|
return;
|
|
10546
10724
|
}
|
|
10547
10725
|
for (const entry of entries)
|
|
10548
10726
|
if (entry.isDirectory())
|
|
10549
|
-
walk(
|
|
10727
|
+
walk(path10.join(dir, entry.name));
|
|
10550
10728
|
else
|
|
10551
|
-
files.push(
|
|
10729
|
+
files.push(path10.join(dir, entry.name));
|
|
10552
10730
|
};
|
|
10553
|
-
walk(
|
|
10731
|
+
walk(path10.join(path10.dirname(location.dir), "logs", "refs", "heads"));
|
|
10554
10732
|
if (location.git)
|
|
10555
|
-
files.push(
|
|
10733
|
+
files.push(path10.join(location.git.gitDir, "logs", "HEAD"));
|
|
10556
10734
|
const seen = new Set;
|
|
10557
10735
|
const renames = [];
|
|
10558
10736
|
for (const file of files) {
|
|
10559
10737
|
let text = "";
|
|
10560
10738
|
try {
|
|
10561
|
-
text =
|
|
10739
|
+
text = fs8.readFileSync(file, "utf8");
|
|
10562
10740
|
} catch {
|
|
10563
10741
|
continue;
|
|
10564
10742
|
}
|
|
@@ -10587,7 +10765,7 @@ var checkoutSlug = (root) => {
|
|
|
10587
10765
|
let canonical = real(root);
|
|
10588
10766
|
if (process.platform === "win32")
|
|
10589
10767
|
canonical = canonical.toLowerCase();
|
|
10590
|
-
const base =
|
|
10768
|
+
const base = path10.basename(canonical).replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 40) || "root";
|
|
10591
10769
|
return `${base}-${shortHash(canonical)}`;
|
|
10592
10770
|
};
|
|
10593
10771
|
|
|
@@ -10619,9 +10797,9 @@ function hostSessionFromEnv(env) {
|
|
|
10619
10797
|
}
|
|
10620
10798
|
return inner ? { host: inner.host, session: inner.session } : { host: declared, session: null };
|
|
10621
10799
|
}
|
|
10622
|
-
var
|
|
10623
|
-
var userIssuedRoot = () =>
|
|
10624
|
-
var userTokenRoot = () =>
|
|
10800
|
+
var hash2 = (value) => createHash9("sha256").update(value).digest("hex").slice(0, 32);
|
|
10801
|
+
var userIssuedRoot = () => path11.join(resolveStateDir(), "issued");
|
|
10802
|
+
var userTokenRoot = () => path11.join(resolveStateDir(), "issued-tokens");
|
|
10625
10803
|
function migrateRepoIssued(cwd) {
|
|
10626
10804
|
if (cwd === undefined)
|
|
10627
10805
|
return;
|
|
@@ -10630,27 +10808,27 @@ function migrateRepoIssued(cwd) {
|
|
|
10630
10808
|
const location = resolveStore(cwd);
|
|
10631
10809
|
if (location instanceof Error)
|
|
10632
10810
|
return;
|
|
10633
|
-
old =
|
|
10634
|
-
if (!
|
|
10811
|
+
old = path11.join(location.dir, "hooks", "issued");
|
|
10812
|
+
if (!fs9.existsSync(old))
|
|
10635
10813
|
return;
|
|
10636
10814
|
} catch {
|
|
10637
10815
|
return;
|
|
10638
10816
|
}
|
|
10639
10817
|
for (const lead of safeList(old)) {
|
|
10640
10818
|
try {
|
|
10641
|
-
const from =
|
|
10642
|
-
if (!
|
|
10819
|
+
const from = path11.join(old, lead);
|
|
10820
|
+
if (!fs9.statSync(from).isDirectory())
|
|
10643
10821
|
continue;
|
|
10644
|
-
const to =
|
|
10645
|
-
|
|
10646
|
-
for (const id of
|
|
10822
|
+
const to = path11.join(userIssuedRoot(), lead);
|
|
10823
|
+
fs9.mkdirSync(to, { recursive: true, mode: 448 });
|
|
10824
|
+
for (const id of fs9.readdirSync(from)) {
|
|
10647
10825
|
try {
|
|
10648
|
-
|
|
10826
|
+
fs9.copyFileSync(path11.join(from, id), path11.join(to, id), fs9.constants.COPYFILE_EXCL);
|
|
10649
10827
|
} catch (error) {
|
|
10650
10828
|
if (error.code !== "EEXIST")
|
|
10651
10829
|
throw error;
|
|
10652
10830
|
}
|
|
10653
|
-
|
|
10831
|
+
fs9.rmSync(path11.join(from, id), { force: true });
|
|
10654
10832
|
}
|
|
10655
10833
|
removeIfEmpty(from);
|
|
10656
10834
|
} catch {}
|
|
@@ -10659,14 +10837,14 @@ function migrateRepoIssued(cwd) {
|
|
|
10659
10837
|
}
|
|
10660
10838
|
var safeList = (dir) => {
|
|
10661
10839
|
try {
|
|
10662
|
-
return
|
|
10840
|
+
return fs9.readdirSync(dir);
|
|
10663
10841
|
} catch {
|
|
10664
10842
|
return [];
|
|
10665
10843
|
}
|
|
10666
10844
|
};
|
|
10667
10845
|
var removeIfEmpty = (dir) => {
|
|
10668
10846
|
try {
|
|
10669
|
-
|
|
10847
|
+
fs9.rmdirSync(dir);
|
|
10670
10848
|
} catch {}
|
|
10671
10849
|
};
|
|
10672
10850
|
function judgeBranch(cwd) {
|
|
@@ -10690,7 +10868,7 @@ var issuedRecord = (cwd, claimed) => {
|
|
|
10690
10868
|
return null;
|
|
10691
10869
|
migrateRepoIssued(cwd);
|
|
10692
10870
|
try {
|
|
10693
|
-
return
|
|
10871
|
+
return fs9.readFileSync(path11.join(userIssuedRoot(), hash2(claimed.slice(0, cut)), hash2(claimed)), "utf8");
|
|
10694
10872
|
} catch {
|
|
10695
10873
|
return null;
|
|
10696
10874
|
}
|
|
@@ -10700,9 +10878,9 @@ var issuedToken = (claimed) => {
|
|
|
10700
10878
|
const cut = claimed.lastIndexOf(":");
|
|
10701
10879
|
if (cut <= 0)
|
|
10702
10880
|
return { stored: null, leadBound: false };
|
|
10703
|
-
const dir =
|
|
10881
|
+
const dir = path11.join(userTokenRoot(), hash2(claimed.slice(0, cut)));
|
|
10704
10882
|
try {
|
|
10705
|
-
const text =
|
|
10883
|
+
const text = fs9.readFileSync(path11.join(dir, hash2(claimed)), "utf8");
|
|
10706
10884
|
return { stored: TOKEN_HASH.exec(text)?.[1] ?? null, leadBound: true };
|
|
10707
10885
|
} catch {
|
|
10708
10886
|
return { stored: null, leadBound: safeList(dir).length > 0 };
|
|
@@ -10727,26 +10905,26 @@ function childSessionId(lead, child) {
|
|
|
10727
10905
|
|
|
10728
10906
|
// packages/workit-core/src/core/package-root.ts
|
|
10729
10907
|
import { existsSync as existsSync2 } from "node:fs";
|
|
10730
|
-
import
|
|
10908
|
+
import path12 from "node:path";
|
|
10731
10909
|
import { fileURLToPath } from "node:url";
|
|
10732
10910
|
var packageRoot = () => {
|
|
10733
|
-
let dir =
|
|
10911
|
+
let dir = path12.dirname(fileURLToPath(import.meta.url));
|
|
10734
10912
|
while (true) {
|
|
10735
|
-
const parent =
|
|
10736
|
-
if (existsSync2(
|
|
10913
|
+
const parent = path12.dirname(dir);
|
|
10914
|
+
if (existsSync2(path12.join(dir, "package.json")) || parent === dir)
|
|
10737
10915
|
return dir;
|
|
10738
10916
|
dir = parent;
|
|
10739
10917
|
}
|
|
10740
10918
|
};
|
|
10741
10919
|
var assetRoot = () => {
|
|
10742
10920
|
const root = packageRoot();
|
|
10743
|
-
const assets =
|
|
10921
|
+
const assets = path12.join(root, "assets");
|
|
10744
10922
|
return existsSync2(assets) ? assets : root;
|
|
10745
10923
|
};
|
|
10746
10924
|
|
|
10747
10925
|
// packages/workit-core/src/core/store-lock.ts
|
|
10748
10926
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
10749
|
-
import
|
|
10927
|
+
import fs10 from "node:fs";
|
|
10750
10928
|
import { hostname } from "node:os";
|
|
10751
10929
|
var metadataLockSchema = object({
|
|
10752
10930
|
pid: number2().int().nonnegative().safe(),
|
|
@@ -10790,7 +10968,7 @@ var parseProcStatStart = (stat) => {
|
|
|
10790
10968
|
var processStartOf = (pid) => {
|
|
10791
10969
|
if (process.platform === "linux") {
|
|
10792
10970
|
try {
|
|
10793
|
-
return parseProcStatStart(
|
|
10971
|
+
return parseProcStatStart(fs10.readFileSync(`/proc/${pid}/stat`, "utf8"));
|
|
10794
10972
|
} catch {
|
|
10795
10973
|
return null;
|
|
10796
10974
|
}
|
|
@@ -10811,7 +10989,7 @@ var processStartOf = (pid) => {
|
|
|
10811
10989
|
};
|
|
10812
10990
|
var readTrimmed = (file) => {
|
|
10813
10991
|
try {
|
|
10814
|
-
return
|
|
10992
|
+
return fs10.readFileSync(file, "utf8").trim() || null;
|
|
10815
10993
|
} catch {
|
|
10816
10994
|
return null;
|
|
10817
10995
|
}
|
|
@@ -10822,7 +11000,7 @@ var localLockHost = () => {
|
|
|
10822
11000
|
return cachedLockHost;
|
|
10823
11001
|
let pidns = null;
|
|
10824
11002
|
try {
|
|
10825
|
-
pidns = /\[(\d+)\]/.exec(
|
|
11003
|
+
pidns = /\[(\d+)\]/.exec(fs10.readlinkSync("/proc/self/ns/pid"))?.[1] ?? null;
|
|
10826
11004
|
} catch {}
|
|
10827
11005
|
const boot = readTrimmed("/proc/sys/kernel/random/boot_id");
|
|
10828
11006
|
cachedLockHost = pidns || boot ? `${hostname()}#${pidns ?? "?"}:${boot ?? "?"}` : hostname();
|
|
@@ -10868,7 +11046,7 @@ var classifyLockOwner = (payload, ageMs, localHost = localLockHost(), options =
|
|
|
10868
11046
|
};
|
|
10869
11047
|
var ageOf = (file, nowMs) => {
|
|
10870
11048
|
try {
|
|
10871
|
-
return nowMs -
|
|
11049
|
+
return nowMs - fs10.lstatSync(file).mtimeMs;
|
|
10872
11050
|
} catch {
|
|
10873
11051
|
return null;
|
|
10874
11052
|
}
|
|
@@ -10879,7 +11057,7 @@ var clearAbandonedReclaimGuard = (lockPath, nowMs = Date.now()) => {
|
|
|
10879
11057
|
if (age === null || age <= RECLAIM_GUARD_TTL_MS)
|
|
10880
11058
|
return false;
|
|
10881
11059
|
try {
|
|
10882
|
-
|
|
11060
|
+
fs10.rmdirSync(guard);
|
|
10883
11061
|
return true;
|
|
10884
11062
|
} catch {
|
|
10885
11063
|
return false;
|
|
@@ -10888,8 +11066,8 @@ var clearAbandonedReclaimGuard = (lockPath, nowMs = Date.now()) => {
|
|
|
10888
11066
|
|
|
10889
11067
|
// packages/workit-core/src/store/event-log.ts
|
|
10890
11068
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
10891
|
-
import
|
|
10892
|
-
import
|
|
11069
|
+
import fs11 from "node:fs";
|
|
11070
|
+
import path13 from "node:path";
|
|
10893
11071
|
var EVENT_VERSION = 1;
|
|
10894
11072
|
|
|
10895
11073
|
class LogDamage extends Error {
|
|
@@ -10918,7 +11096,7 @@ var parseEvent = (line, file, offset) => {
|
|
|
10918
11096
|
function readLog(file, from = 0, expectSeq = null) {
|
|
10919
11097
|
let fd;
|
|
10920
11098
|
try {
|
|
10921
|
-
fd =
|
|
11099
|
+
fd = fs11.openSync(file, "r");
|
|
10922
11100
|
} catch (error) {
|
|
10923
11101
|
if (error.code === "ENOENT")
|
|
10924
11102
|
return null;
|
|
@@ -10927,13 +11105,13 @@ function readLog(file, from = 0, expectSeq = null) {
|
|
|
10927
11105
|
let bytes;
|
|
10928
11106
|
let size;
|
|
10929
11107
|
try {
|
|
10930
|
-
size =
|
|
11108
|
+
size = fs11.fstatSync(fd).size;
|
|
10931
11109
|
if (from > size)
|
|
10932
11110
|
throw new LogDamage(`${file}: shorter than its snapshot`);
|
|
10933
11111
|
bytes = Buffer.alloc(size - from);
|
|
10934
11112
|
let read = 0;
|
|
10935
11113
|
while (read < bytes.length) {
|
|
10936
|
-
const got =
|
|
11114
|
+
const got = fs11.readSync(fd, bytes, read, bytes.length - read, from + read);
|
|
10937
11115
|
if (got === 0)
|
|
10938
11116
|
break;
|
|
10939
11117
|
read += got;
|
|
@@ -10941,7 +11119,7 @@ function readLog(file, from = 0, expectSeq = null) {
|
|
|
10941
11119
|
bytes = bytes.subarray(0, read);
|
|
10942
11120
|
size = from + read;
|
|
10943
11121
|
} finally {
|
|
10944
|
-
|
|
11122
|
+
fs11.closeSync(fd);
|
|
10945
11123
|
}
|
|
10946
11124
|
const events = [];
|
|
10947
11125
|
let start = 0;
|
|
@@ -10966,11 +11144,11 @@ function readLog(file, from = 0, expectSeq = null) {
|
|
|
10966
11144
|
}
|
|
10967
11145
|
var fsyncDirectory = (dir) => {
|
|
10968
11146
|
try {
|
|
10969
|
-
const fd =
|
|
11147
|
+
const fd = fs11.openSync(dir, "r");
|
|
10970
11148
|
try {
|
|
10971
|
-
|
|
11149
|
+
fs11.fsyncSync(fd);
|
|
10972
11150
|
} finally {
|
|
10973
|
-
|
|
11151
|
+
fs11.closeSync(fd);
|
|
10974
11152
|
}
|
|
10975
11153
|
} catch (error) {
|
|
10976
11154
|
if (process.platform !== "win32")
|
|
@@ -10980,46 +11158,46 @@ var fsyncDirectory = (dir) => {
|
|
|
10980
11158
|
function appendEvent(file, event, validEnd) {
|
|
10981
11159
|
const line = Buffer.from(`${JSON.stringify(event)}
|
|
10982
11160
|
`, "utf8");
|
|
10983
|
-
const created = !
|
|
10984
|
-
if (!created &&
|
|
10985
|
-
const cut =
|
|
11161
|
+
const created = !fs11.existsSync(file);
|
|
11162
|
+
if (!created && fs11.statSync(file).size !== validEnd) {
|
|
11163
|
+
const cut = fs11.openSync(file, "r+");
|
|
10986
11164
|
try {
|
|
10987
|
-
|
|
10988
|
-
|
|
11165
|
+
fs11.ftruncateSync(cut, validEnd);
|
|
11166
|
+
fs11.fsyncSync(cut);
|
|
10989
11167
|
} finally {
|
|
10990
|
-
|
|
11168
|
+
fs11.closeSync(cut);
|
|
10991
11169
|
}
|
|
10992
11170
|
}
|
|
10993
|
-
const fd =
|
|
11171
|
+
const fd = fs11.openSync(file, "a", 384);
|
|
10994
11172
|
try {
|
|
10995
11173
|
let written = 0;
|
|
10996
11174
|
while (written < line.length)
|
|
10997
|
-
written +=
|
|
10998
|
-
|
|
11175
|
+
written += fs11.writeSync(fd, line, written, line.length - written);
|
|
11176
|
+
fs11.fsyncSync(fd);
|
|
10999
11177
|
} finally {
|
|
11000
|
-
|
|
11178
|
+
fs11.closeSync(fd);
|
|
11001
11179
|
}
|
|
11002
11180
|
if (created)
|
|
11003
|
-
fsyncDirectory(
|
|
11181
|
+
fsyncDirectory(path13.dirname(file));
|
|
11004
11182
|
return validEnd;
|
|
11005
11183
|
}
|
|
11006
11184
|
function replaceFile(file, bytes, durable) {
|
|
11007
11185
|
const temporary = `${file}.${process.pid}.${randomUUID2()}.tmp`;
|
|
11008
11186
|
try {
|
|
11009
|
-
const fd =
|
|
11187
|
+
const fd = fs11.openSync(temporary, "wx", 384);
|
|
11010
11188
|
try {
|
|
11011
|
-
|
|
11189
|
+
fs11.writeSync(fd, bytes);
|
|
11012
11190
|
if (durable)
|
|
11013
|
-
|
|
11191
|
+
fs11.fsyncSync(fd);
|
|
11014
11192
|
} finally {
|
|
11015
|
-
|
|
11193
|
+
fs11.closeSync(fd);
|
|
11016
11194
|
}
|
|
11017
11195
|
renameWithRetry(temporary, file);
|
|
11018
11196
|
if (durable)
|
|
11019
|
-
fsyncDirectory(
|
|
11197
|
+
fsyncDirectory(path13.dirname(file));
|
|
11020
11198
|
} catch (error) {
|
|
11021
11199
|
try {
|
|
11022
|
-
|
|
11200
|
+
fs11.unlinkSync(temporary);
|
|
11023
11201
|
} catch {}
|
|
11024
11202
|
throw error;
|
|
11025
11203
|
}
|
|
@@ -11044,7 +11222,7 @@ var retryTransient = (run) => {
|
|
|
11044
11222
|
}
|
|
11045
11223
|
}
|
|
11046
11224
|
};
|
|
11047
|
-
var renameWithRetry = (from, to) => retryTransient(() =>
|
|
11225
|
+
var renameWithRetry = (from, to) => retryTransient(() => fs11.renameSync(from, to));
|
|
11048
11226
|
|
|
11049
11227
|
// packages/workit-core/src/store/patch.ts
|
|
11050
11228
|
var isPlainObject2 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -11157,7 +11335,7 @@ var isPatch = (value) => Array.isArray(value) && value.every((op) => {
|
|
|
11157
11335
|
});
|
|
11158
11336
|
|
|
11159
11337
|
// packages/workit-core/src/store/reduce.ts
|
|
11160
|
-
import { createHash as
|
|
11338
|
+
import { createHash as createHash10 } from "node:crypto";
|
|
11161
11339
|
var OPENING_TYPES = new Set([
|
|
11162
11340
|
"task.opened",
|
|
11163
11341
|
"task.imported",
|
|
@@ -11186,7 +11364,7 @@ var isObject4 = (value) => typeof value === "object" && value !== null && !Array
|
|
|
11186
11364
|
var isKey = (value) => isObject4(value) && typeof value.key === "string" && (value.kind === "branch" || value.kind === "detached" || value.kind === "dir") && (value.branch === null || typeof value.branch === "string");
|
|
11187
11365
|
var BLOB_REF = "$blob";
|
|
11188
11366
|
var blobRef = (value) => isObject4(value) && Object.keys(value).length === 1 && typeof value[BLOB_REF] === "string" && /^[0-9a-f]{64}$/.test(value[BLOB_REF]) ? value[BLOB_REF] : null;
|
|
11189
|
-
var blobDigest = (value) =>
|
|
11367
|
+
var blobDigest = (value) => createHash10("sha256").update(JSON.stringify(value)).digest("hex");
|
|
11190
11368
|
var toBlob = (value, blobs) => {
|
|
11191
11369
|
if (!isObject4(value))
|
|
11192
11370
|
return value;
|
|
@@ -11341,7 +11519,7 @@ var indexEntry = (task, key, legacy, file) => {
|
|
|
11341
11519
|
};
|
|
11342
11520
|
var fileSignature = (file) => {
|
|
11343
11521
|
try {
|
|
11344
|
-
const stat =
|
|
11522
|
+
const stat = fs12.statSync(file, { bigint: true });
|
|
11345
11523
|
return `${stat.dev}:${stat.ino}:${stat.size}:${stat.mtimeNs}:${stat.ctimeNs}`;
|
|
11346
11524
|
} catch {
|
|
11347
11525
|
return null;
|
|
@@ -11359,7 +11537,7 @@ var cachedRuntimeVersion = null;
|
|
|
11359
11537
|
var runtimeVersion = () => {
|
|
11360
11538
|
if (cachedRuntimeVersion === null) {
|
|
11361
11539
|
try {
|
|
11362
|
-
const pkg = JSON.parse(
|
|
11540
|
+
const pkg = JSON.parse(fs12.readFileSync(path14.join(packageRoot(), "package.json"), "utf8"));
|
|
11363
11541
|
cachedRuntimeVersion = typeof pkg.version === "string" && pkg.version ? pkg.version : "0.0.0";
|
|
11364
11542
|
} catch {
|
|
11365
11543
|
cachedRuntimeVersion = "0.0.0";
|
|
@@ -11385,14 +11563,14 @@ var isNewerVersion = (candidate, current) => {
|
|
|
11385
11563
|
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);
|
|
11386
11564
|
var readText = (file) => {
|
|
11387
11565
|
try {
|
|
11388
|
-
return
|
|
11566
|
+
return fs12.readFileSync(file, "utf8");
|
|
11389
11567
|
} catch {
|
|
11390
11568
|
return "";
|
|
11391
11569
|
}
|
|
11392
11570
|
};
|
|
11393
11571
|
var REFLOG_LINE = /^[0-9a-f]+ ([0-9a-f]+) .* (\d+) [+-]\d{4}\t(.*)$/u;
|
|
11394
11572
|
var branchStart = (location, branch, aliases) => {
|
|
11395
|
-
const first = readText(
|
|
11573
|
+
const first = readText(path14.join(path14.dirname(location.dir), "logs", "refs", "heads", branch)).split(`
|
|
11396
11574
|
`, 1)[0];
|
|
11397
11575
|
const created = REFLOG_LINE.exec(first);
|
|
11398
11576
|
const start = created && /^branch: Created from (\S+)$/u.exec(created[3])?.[1];
|
|
@@ -11402,7 +11580,7 @@ var branchStart = (location, branch, aliases) => {
|
|
|
11402
11580
|
return start;
|
|
11403
11581
|
if (!location.git)
|
|
11404
11582
|
return null;
|
|
11405
|
-
for (const line of readText(
|
|
11583
|
+
for (const line of readText(path14.join(location.git.gitDir, "logs", "HEAD")).split(`
|
|
11406
11584
|
`)) {
|
|
11407
11585
|
const entry = REFLOG_LINE.exec(line);
|
|
11408
11586
|
const moved = entry && /^checkout: moving from (\S+) to (\S+)$/u.exec(entry[3]);
|
|
@@ -11412,23 +11590,23 @@ var branchStart = (location, branch, aliases) => {
|
|
|
11412
11590
|
}
|
|
11413
11591
|
return null;
|
|
11414
11592
|
};
|
|
11415
|
-
var refExists = (common, ref) =>
|
|
11593
|
+
var refExists = (common, ref) => fs12.existsSync(path14.join(common, ref)) || readText(path14.join(common, "packed-refs")).includes(` ${ref}
|
|
11416
11594
|
`);
|
|
11417
11595
|
var origins = new Map;
|
|
11418
11596
|
var sameDirectoryIdentity = (left, right) => {
|
|
11419
|
-
if (!
|
|
11597
|
+
if (!path14.isAbsolute(left) || !path14.isAbsolute(right))
|
|
11420
11598
|
return false;
|
|
11421
|
-
const normalizedLeft =
|
|
11422
|
-
const normalizedRight =
|
|
11599
|
+
const normalizedLeft = path14.resolve(left);
|
|
11600
|
+
const normalizedRight = path14.resolve(right);
|
|
11423
11601
|
try {
|
|
11424
|
-
const a =
|
|
11425
|
-
const b =
|
|
11602
|
+
const a = fs12.statSync(normalizedLeft, { bigint: true });
|
|
11603
|
+
const b = fs12.statSync(normalizedRight, { bigint: true });
|
|
11426
11604
|
if (!a.isDirectory() || !b.isDirectory())
|
|
11427
11605
|
return false;
|
|
11428
11606
|
if (process.platform === "win32" ? normalizedLeft.toLowerCase() === normalizedRight.toLowerCase() : normalizedLeft === normalizedRight)
|
|
11429
11607
|
return true;
|
|
11430
|
-
const canonicalLeft =
|
|
11431
|
-
const canonicalRight =
|
|
11608
|
+
const canonicalLeft = fs12.realpathSync(normalizedLeft);
|
|
11609
|
+
const canonicalRight = fs12.realpathSync(normalizedRight);
|
|
11432
11610
|
if (process.platform === "win32" ? canonicalLeft.toLowerCase() === canonicalRight.toLowerCase() : canonicalLeft === canonicalRight)
|
|
11433
11611
|
return true;
|
|
11434
11612
|
return a.dev === b.dev && a.ino !== 0n && a.ino === b.ino;
|
|
@@ -11465,8 +11643,8 @@ class TaskStore {
|
|
|
11465
11643
|
migrationChecked = false;
|
|
11466
11644
|
compactDue = new Set;
|
|
11467
11645
|
constructor(root, options = {}) {
|
|
11468
|
-
const resolved =
|
|
11469
|
-
this.origin =
|
|
11646
|
+
const resolved = path14.resolve(root);
|
|
11647
|
+
this.origin = fs12.existsSync(resolved) ? fs12.realpathSync(resolved) : resolved;
|
|
11470
11648
|
this.located = resolveStore(this.origin);
|
|
11471
11649
|
this.root = checkoutRootOf(this.origin, this.located);
|
|
11472
11650
|
this.lockTimeoutMs = options.lockTimeoutMs ?? defaultLockTimeout();
|
|
@@ -11474,7 +11652,7 @@ class TaskStore {
|
|
|
11474
11652
|
this.migrateOnRead = options.migrateOnRead;
|
|
11475
11653
|
}
|
|
11476
11654
|
location() {
|
|
11477
|
-
if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared &&
|
|
11655
|
+
if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared && fs12.existsSync(path14.join(this.root, ".git"))) {
|
|
11478
11656
|
this.located = undefined;
|
|
11479
11657
|
this.migrationChecked = false;
|
|
11480
11658
|
}
|
|
@@ -11538,7 +11716,7 @@ class TaskStore {
|
|
|
11538
11716
|
const tasksDir = this.paths().tasks;
|
|
11539
11717
|
let names;
|
|
11540
11718
|
try {
|
|
11541
|
-
names =
|
|
11719
|
+
names = fs12.existsSync(tasksDir) ? fs12.readdirSync(tasksDir).filter((name) => validId(name)) : [];
|
|
11542
11720
|
} catch (error) {
|
|
11543
11721
|
return failure2("storage_error", `unable to list tasks: ${String(error)}`, {
|
|
11544
11722
|
path: tasksDir
|
|
@@ -11579,7 +11757,7 @@ class TaskStore {
|
|
|
11579
11757
|
const file = this.paths().workspace;
|
|
11580
11758
|
let bytes;
|
|
11581
11759
|
try {
|
|
11582
|
-
bytes = retryTransient(() =>
|
|
11760
|
+
bytes = retryTransient(() => fs12.readFileSync(file, "utf8"));
|
|
11583
11761
|
} catch (error) {
|
|
11584
11762
|
if (error.code === "ENOENT")
|
|
11585
11763
|
return success(null, null, null);
|
|
@@ -11630,7 +11808,7 @@ class TaskStore {
|
|
|
11630
11808
|
const moved = this.bindLocked(again.data.id, key, input.now);
|
|
11631
11809
|
return moved.ok ? success(moved.data.revision, null, { task: moved.data, created: false, key }) : moved;
|
|
11632
11810
|
}
|
|
11633
|
-
const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" :
|
|
11811
|
+
const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" : path14.basename(this.root) || this.root;
|
|
11634
11812
|
const intent = {
|
|
11635
11813
|
objective: input.objective?.trim() || `Work on ${label}`,
|
|
11636
11814
|
scope: { description: `the checkout (${label})`, paths: ["."], exclusions: [] },
|
|
@@ -11696,14 +11874,14 @@ class TaskStore {
|
|
|
11696
11874
|
const branch = key.ok ? key.data.branch : null;
|
|
11697
11875
|
if (!branch || !location.ok)
|
|
11698
11876
|
return success(null, null, null);
|
|
11699
|
-
const common =
|
|
11700
|
-
const heads =
|
|
11701
|
-
const headLog = location.data.git ?
|
|
11877
|
+
const common = path14.dirname(location.data.dir);
|
|
11878
|
+
const heads = path14.join(common, "logs", "refs", "heads");
|
|
11879
|
+
const headLog = location.data.git ? path14.join(location.data.git.gitDir, "logs", "HEAD") : "";
|
|
11702
11880
|
const signatures = [
|
|
11703
|
-
|
|
11881
|
+
path14.join(heads, branch),
|
|
11704
11882
|
headLog,
|
|
11705
11883
|
heads,
|
|
11706
|
-
|
|
11884
|
+
path14.join(common, "packed-refs")
|
|
11707
11885
|
].map((file) => fileSignature(file) ?? "-");
|
|
11708
11886
|
const slot = `${location.data.dir}\x00${headLog}\x00${branch}`;
|
|
11709
11887
|
let resolved = origins.get(slot);
|
|
@@ -11715,7 +11893,7 @@ class TaskStore {
|
|
|
11715
11893
|
aliases.push(rename.from);
|
|
11716
11894
|
const start = branchStart(location.data, branch, aliases);
|
|
11717
11895
|
const slash = start?.indexOf("/") ?? -1;
|
|
11718
|
-
const remote = slash > 0 && !refExists(common, `refs/heads/${start}`) && (refExists(common, `refs/remotes/${start}`) || readText(
|
|
11896
|
+
const remote = slash > 0 && !refExists(common, `refs/heads/${start}`) && (refExists(common, `refs/remotes/${start}`) || readText(path14.join(common, "config")).includes(`[remote "${start.slice(0, slash)}"]`));
|
|
11719
11897
|
const name = start && (remote ? start.slice(slash + 1) : start);
|
|
11720
11898
|
resolved = {
|
|
11721
11899
|
signature: signatures.join("|"),
|
|
@@ -11953,13 +12131,13 @@ class TaskStore {
|
|
|
11953
12131
|
if (!ready.ok)
|
|
11954
12132
|
return ready;
|
|
11955
12133
|
const dirs = this.paths();
|
|
11956
|
-
const recovery =
|
|
11957
|
-
if (
|
|
12134
|
+
const recovery = path14.join(this.root, ".workit", "recovery");
|
|
12135
|
+
if (fs12.existsSync(recovery)) {
|
|
11958
12136
|
let files = 0;
|
|
11959
12137
|
let bytes = 0;
|
|
11960
12138
|
try {
|
|
11961
|
-
for (const name of
|
|
11962
|
-
const stat =
|
|
12139
|
+
for (const name of fs12.readdirSync(recovery)) {
|
|
12140
|
+
const stat = fs12.lstatSync(path14.join(recovery, name));
|
|
11963
12141
|
if (!stat.isFile())
|
|
11964
12142
|
continue;
|
|
11965
12143
|
files += 1;
|
|
@@ -11968,17 +12146,17 @@ class TaskStore {
|
|
|
11968
12146
|
} catch {}
|
|
11969
12147
|
const remove = options.pruneRecovery === true && !dryRun;
|
|
11970
12148
|
if (remove)
|
|
11971
|
-
|
|
12149
|
+
fs12.rmSync(recovery, { recursive: true, force: true });
|
|
11972
12150
|
report.legacyRecovery = { path: recovery, files, bytes, removed: remove };
|
|
11973
12151
|
}
|
|
11974
|
-
if (!
|
|
12152
|
+
if (!fs12.existsSync(dirs.tasks))
|
|
11975
12153
|
return success(null, null, report);
|
|
11976
|
-
const names =
|
|
12154
|
+
const names = fs12.readdirSync(dirs.tasks).filter((name) => validId(name));
|
|
11977
12155
|
for (const name of names) {
|
|
11978
12156
|
const file = this.eventsPath(name);
|
|
11979
12157
|
let size = 0;
|
|
11980
12158
|
try {
|
|
11981
|
-
size =
|
|
12159
|
+
size = fs12.statSync(file).size;
|
|
11982
12160
|
} catch {
|
|
11983
12161
|
continue;
|
|
11984
12162
|
}
|
|
@@ -12006,16 +12184,16 @@ class TaskStore {
|
|
|
12006
12184
|
const references = new Set;
|
|
12007
12185
|
for (const name of names)
|
|
12008
12186
|
try {
|
|
12009
|
-
for (const match of
|
|
12187
|
+
for (const match of fs12.readFileSync(this.eventsPath(name), "utf8").matchAll(/"\$blob":"([0-9a-f]{64})"/g))
|
|
12010
12188
|
references.add(match[1]);
|
|
12011
12189
|
} catch {}
|
|
12012
|
-
if (
|
|
12013
|
-
for (const name of
|
|
12190
|
+
if (fs12.existsSync(dirs.blobs))
|
|
12191
|
+
for (const name of fs12.readdirSync(dirs.blobs)) {
|
|
12014
12192
|
const digest = name.replace(/\.json$/, "");
|
|
12015
|
-
const file =
|
|
12193
|
+
const file = path14.join(dirs.blobs, name);
|
|
12016
12194
|
let stat;
|
|
12017
12195
|
try {
|
|
12018
|
-
stat =
|
|
12196
|
+
stat = fs12.lstatSync(file);
|
|
12019
12197
|
} catch {
|
|
12020
12198
|
continue;
|
|
12021
12199
|
}
|
|
@@ -12026,11 +12204,11 @@ class TaskStore {
|
|
|
12026
12204
|
report.blobs.removed += 1;
|
|
12027
12205
|
report.blobs.removedBytes += stat.size;
|
|
12028
12206
|
if (!dryRun)
|
|
12029
|
-
|
|
12207
|
+
fs12.rmSync(file, { force: true });
|
|
12030
12208
|
}
|
|
12031
12209
|
return success(null, null, null);
|
|
12032
12210
|
};
|
|
12033
|
-
const swept = dryRun ? sweep() : this.withLock(
|
|
12211
|
+
const swept = dryRun ? sweep() : this.withLock(path14.join(dirs.dir, "gc.lock"), sweep);
|
|
12034
12212
|
if (!swept.ok)
|
|
12035
12213
|
return swept;
|
|
12036
12214
|
const temporaryDirs = [
|
|
@@ -12038,17 +12216,17 @@ class TaskStore {
|
|
|
12038
12216
|
dirs.tasks,
|
|
12039
12217
|
dirs.blobs,
|
|
12040
12218
|
dirs.checkout,
|
|
12041
|
-
...names.map((name) =>
|
|
12219
|
+
...names.map((name) => path14.join(dirs.tasks, name))
|
|
12042
12220
|
];
|
|
12043
12221
|
for (const directory of temporaryDirs) {
|
|
12044
|
-
if (!
|
|
12222
|
+
if (!fs12.existsSync(directory))
|
|
12045
12223
|
continue;
|
|
12046
|
-
for (const name of
|
|
12224
|
+
for (const name of fs12.readdirSync(directory)) {
|
|
12047
12225
|
if (!name.endsWith(".tmp") && !name.endsWith(".probe"))
|
|
12048
12226
|
continue;
|
|
12049
|
-
const file =
|
|
12227
|
+
const file = path14.join(directory, name);
|
|
12050
12228
|
try {
|
|
12051
|
-
const stat =
|
|
12229
|
+
const stat = fs12.lstatSync(file);
|
|
12052
12230
|
if (!stat.isFile() || nowMs - stat.mtimeMs <= STALE_TEMPORARY_MS)
|
|
12053
12231
|
continue;
|
|
12054
12232
|
} catch {
|
|
@@ -12056,37 +12234,37 @@ class TaskStore {
|
|
|
12056
12234
|
}
|
|
12057
12235
|
report.temporary.removed += 1;
|
|
12058
12236
|
if (!dryRun)
|
|
12059
|
-
|
|
12237
|
+
fs12.rmSync(file, { force: true });
|
|
12060
12238
|
}
|
|
12061
12239
|
}
|
|
12062
12240
|
return success(null, null, report);
|
|
12063
12241
|
}
|
|
12064
12242
|
paths() {
|
|
12065
12243
|
const location = this.location();
|
|
12066
|
-
const dir = location.ok ? location.data.dir :
|
|
12067
|
-
const checkout =
|
|
12244
|
+
const dir = location.ok ? location.data.dir : path14.join(this.root, ".workit");
|
|
12245
|
+
const checkout = path14.join(dir, "checkouts", checkoutSlug(this.root));
|
|
12068
12246
|
return {
|
|
12069
12247
|
dir,
|
|
12070
12248
|
shared: location.ok ? location.data.shared : false,
|
|
12071
|
-
marker:
|
|
12249
|
+
marker: path14.join(dir, "store.json"),
|
|
12072
12250
|
checkout,
|
|
12073
|
-
workspace:
|
|
12074
|
-
checkoutLock:
|
|
12075
|
-
tasks:
|
|
12076
|
-
index:
|
|
12077
|
-
blobs:
|
|
12078
|
-
legacy:
|
|
12079
|
-
v2:
|
|
12251
|
+
workspace: path14.join(checkout, "workspace.json"),
|
|
12252
|
+
checkoutLock: path14.join(checkout, "metadata.lock"),
|
|
12253
|
+
tasks: path14.join(dir, "tasks"),
|
|
12254
|
+
index: path14.join(dir, "task-index.json"),
|
|
12255
|
+
blobs: path14.join(dir, "blobs", "candidates"),
|
|
12256
|
+
legacy: path14.join(dir, "legacy", checkoutSlug(this.root), "v2"),
|
|
12257
|
+
v2: path14.join(this.root, ".workit")
|
|
12080
12258
|
};
|
|
12081
12259
|
}
|
|
12082
12260
|
eventsPath(taskId) {
|
|
12083
|
-
return
|
|
12261
|
+
return path14.join(this.paths().tasks, taskId, "events.jsonl");
|
|
12084
12262
|
}
|
|
12085
12263
|
snapshotPath(taskId) {
|
|
12086
|
-
return
|
|
12264
|
+
return path14.join(this.paths().tasks, taskId, "snapshot.json");
|
|
12087
12265
|
}
|
|
12088
12266
|
taskLockPath(taskId) {
|
|
12089
|
-
return
|
|
12267
|
+
return path14.join(this.paths().tasks, taskId, "lock");
|
|
12090
12268
|
}
|
|
12091
12269
|
ready(write = false) {
|
|
12092
12270
|
const location = this.location();
|
|
@@ -12096,7 +12274,7 @@ class TaskStore {
|
|
|
12096
12274
|
return success(null, null, null);
|
|
12097
12275
|
const dirs = this.paths();
|
|
12098
12276
|
try {
|
|
12099
|
-
const marker = JSON.parse(
|
|
12277
|
+
const marker = JSON.parse(fs12.readFileSync(dirs.marker, "utf8"));
|
|
12100
12278
|
if (typeof marker.version === "number" && marker.version > STORE_FORMAT)
|
|
12101
12279
|
return failure2("recovery_required", `the workit store at ${dirs.dir} has format ${marker.version}; upgrade Workit to use it`, { path: dirs.marker });
|
|
12102
12280
|
} catch {}
|
|
@@ -12125,21 +12303,21 @@ class TaskStore {
|
|
|
12125
12303
|
return {
|
|
12126
12304
|
read: (digest) => {
|
|
12127
12305
|
try {
|
|
12128
|
-
return JSON.parse(
|
|
12306
|
+
return JSON.parse(fs12.readFileSync(path14.join(dir, `${digest}.json`), "utf8"));
|
|
12129
12307
|
} catch (error) {
|
|
12130
12308
|
throw new LogDamage(`stored candidate ${digest} is missing or unreadable: ${String(error)}`);
|
|
12131
12309
|
}
|
|
12132
12310
|
},
|
|
12133
12311
|
write: (digest, value) => {
|
|
12134
|
-
const file =
|
|
12135
|
-
if (
|
|
12312
|
+
const file = path14.join(dir, `${digest}.json`);
|
|
12313
|
+
if (fs12.existsSync(file)) {
|
|
12136
12314
|
const stamp = new Date;
|
|
12137
12315
|
try {
|
|
12138
|
-
|
|
12316
|
+
fs12.utimesSync(file, stamp, stamp);
|
|
12139
12317
|
return;
|
|
12140
12318
|
} catch {}
|
|
12141
12319
|
}
|
|
12142
|
-
|
|
12320
|
+
fs12.mkdirSync(dir, { recursive: true });
|
|
12143
12321
|
replaceFile(file, JSON.stringify(value), true);
|
|
12144
12322
|
}
|
|
12145
12323
|
};
|
|
@@ -12221,7 +12399,7 @@ class TaskStore {
|
|
|
12221
12399
|
}
|
|
12222
12400
|
readSnapshot(taskId) {
|
|
12223
12401
|
try {
|
|
12224
|
-
const value = JSON.parse(
|
|
12402
|
+
const value = JSON.parse(fs12.readFileSync(this.snapshotPath(taskId), "utf8"));
|
|
12225
12403
|
if (!isObject5(value) || value.v !== 1 || value.task !== taskId || typeof value.seq !== "number" || typeof value.lastId !== "string" || typeof value.lastStart !== "number" || typeof value.end !== "number" || !isObject5(value.record))
|
|
12226
12404
|
return null;
|
|
12227
12405
|
return value;
|
|
@@ -12323,8 +12501,8 @@ class TaskStore {
|
|
|
12323
12501
|
}
|
|
12324
12502
|
}
|
|
12325
12503
|
openTask(record, type, key, legacy = null) {
|
|
12326
|
-
const dir =
|
|
12327
|
-
|
|
12504
|
+
const dir = path14.join(this.paths().tasks, record.id);
|
|
12505
|
+
fs12.mkdirSync(dir, { recursive: true });
|
|
12328
12506
|
const blobs = this.blobStore();
|
|
12329
12507
|
const bound = key ? { ...key, boundAt: key.boundAt ?? new Date().toISOString() } : null;
|
|
12330
12508
|
const event = this.event(record.id, 1, type, {
|
|
@@ -12376,11 +12554,11 @@ class TaskStore {
|
|
|
12376
12554
|
} catch {}
|
|
12377
12555
|
if (!latest || latest.events[0]?.id !== last.id)
|
|
12378
12556
|
return failure2("busy", "the task log changed during compaction; retry", { taskId });
|
|
12379
|
-
const appended =
|
|
12557
|
+
const appended = fs12.readFileSync(file).subarray(log.end, latest.end);
|
|
12380
12558
|
const bytes = Buffer.concat([Buffer.from(prefix, "utf8"), appended]);
|
|
12381
12559
|
replaceFile(file, bytes.toString("utf8"), true);
|
|
12382
12560
|
try {
|
|
12383
|
-
|
|
12561
|
+
fs12.rmSync(this.snapshotPath(taskId), { force: true });
|
|
12384
12562
|
} catch {}
|
|
12385
12563
|
const reloaded = this.load(taskId);
|
|
12386
12564
|
if (reloaded.ok && reloaded.data)
|
|
@@ -12393,7 +12571,7 @@ class TaskStore {
|
|
|
12393
12571
|
}
|
|
12394
12572
|
countEvents(file) {
|
|
12395
12573
|
try {
|
|
12396
|
-
const bytes =
|
|
12574
|
+
const bytes = fs12.readFileSync(file);
|
|
12397
12575
|
let count = 0;
|
|
12398
12576
|
for (let index = bytes.indexOf(10);index >= 0; index = bytes.indexOf(10, index + 1))
|
|
12399
12577
|
count += 1;
|
|
@@ -12415,8 +12593,8 @@ class TaskStore {
|
|
|
12415
12593
|
return bound.ok ? success(null, null, bound.data[0] ?? null) : bound;
|
|
12416
12594
|
}
|
|
12417
12595
|
withKeyLock(key, operation) {
|
|
12418
|
-
const digest =
|
|
12419
|
-
return this.withLock(
|
|
12596
|
+
const digest = createHash11("sha256").update(key).digest("hex").slice(0, 32);
|
|
12597
|
+
return this.withLock(path14.join(this.paths().dir, "keys", `${digest}.lock`), operation);
|
|
12420
12598
|
}
|
|
12421
12599
|
bindLocked(taskId, key, timestamp) {
|
|
12422
12600
|
const current = this.readWorkspace();
|
|
@@ -12557,7 +12735,7 @@ class TaskStore {
|
|
|
12557
12735
|
writeWorkspace(record) {
|
|
12558
12736
|
const file = this.paths().workspace;
|
|
12559
12737
|
try {
|
|
12560
|
-
|
|
12738
|
+
fs12.mkdirSync(path14.dirname(file), { recursive: true });
|
|
12561
12739
|
replaceFile(file, `${canonicalJson(record)}
|
|
12562
12740
|
`, true);
|
|
12563
12741
|
return success(null, null, null);
|
|
@@ -12567,7 +12745,7 @@ class TaskStore {
|
|
|
12567
12745
|
}
|
|
12568
12746
|
readIndex() {
|
|
12569
12747
|
try {
|
|
12570
|
-
const value = JSON.parse(
|
|
12748
|
+
const value = JSON.parse(fs12.readFileSync(this.paths().index, "utf8"));
|
|
12571
12749
|
if (!isObject5(value) || value.version !== INDEX_VERSION || !isObject5(value.tasks))
|
|
12572
12750
|
return {};
|
|
12573
12751
|
const tasks = {};
|
|
@@ -12581,7 +12759,7 @@ class TaskStore {
|
|
|
12581
12759
|
}
|
|
12582
12760
|
writeIndex(entries) {
|
|
12583
12761
|
try {
|
|
12584
|
-
|
|
12762
|
+
fs12.mkdirSync(this.paths().tasks, { recursive: true });
|
|
12585
12763
|
replaceFile(this.paths().index, JSON.stringify({
|
|
12586
12764
|
version: INDEX_VERSION,
|
|
12587
12765
|
tasks: Object.fromEntries(entries.map((entry) => [entry.id, entry]))
|
|
@@ -12635,23 +12813,23 @@ class TaskStore {
|
|
|
12635
12813
|
return failure2("revision_conflict", "workspace revision does not match; omit expectedWorkspaceRevision to use the current record", { expectedWorkspaceRevision: expected, actualWorkspaceRevision: actual });
|
|
12636
12814
|
}
|
|
12637
12815
|
v2Dirs() {
|
|
12638
|
-
return [...new Set([this.root, this.origin])].map((dir) =>
|
|
12816
|
+
return [...new Set([this.root, this.origin])].map((dir) => path14.join(dir, ".workit"));
|
|
12639
12817
|
}
|
|
12640
12818
|
pendingMigrations() {
|
|
12641
12819
|
return this.v2Dirs().filter((dir) => {
|
|
12642
|
-
const raw = this.readV2Workspace(
|
|
12820
|
+
const raw = this.readV2Workspace(path14.join(dir, "workspace.json"));
|
|
12643
12821
|
return raw !== null && raw !== TOMBSTONE;
|
|
12644
12822
|
});
|
|
12645
12823
|
}
|
|
12646
12824
|
migrateV2(v2) {
|
|
12647
12825
|
const dirs = this.paths();
|
|
12648
|
-
const v2Workspace =
|
|
12649
|
-
const v2Tasks =
|
|
12650
|
-
const legacy =
|
|
12826
|
+
const v2Workspace = path14.join(v2, "workspace.json");
|
|
12827
|
+
const v2Tasks = path14.join(v2, "tasks");
|
|
12828
|
+
const legacy = path14.join(dirs.dir, "legacy", checkoutSlug(path14.dirname(v2)), "v2");
|
|
12651
12829
|
const raw = this.readV2Workspace(v2Workspace);
|
|
12652
12830
|
if (raw === null || raw === TOMBSTONE)
|
|
12653
12831
|
return success(null, null, null);
|
|
12654
|
-
return this.withLock(dirs.checkoutLock, () => this.withLock(
|
|
12832
|
+
return this.withLock(dirs.checkoutLock, () => this.withLock(path14.join(v2, "metadata.lock"), () => {
|
|
12655
12833
|
const workspace = this.readV2Workspace(v2Workspace);
|
|
12656
12834
|
if (workspace === null || workspace === TOMBSTONE)
|
|
12657
12835
|
return success(null, null, null);
|
|
@@ -12660,7 +12838,7 @@ class TaskStore {
|
|
|
12660
12838
|
return failure2("recovery_required", `cannot migrate the 2.x store at ${v2}: ${parsedWorkspace.error}; move it aside to start fresh`, { path: v2Workspace });
|
|
12661
12839
|
let files = [];
|
|
12662
12840
|
try {
|
|
12663
|
-
files =
|
|
12841
|
+
files = fs12.readdirSync(v2Tasks).filter((name) => name.endsWith(".json") && validId(name.slice(0, -5))).filter((name) => !this.isStub(path14.join(v2Tasks, name)));
|
|
12664
12842
|
} catch {}
|
|
12665
12843
|
const current = this.readWorkspace();
|
|
12666
12844
|
if (!current.ok)
|
|
@@ -12678,22 +12856,22 @@ class TaskStore {
|
|
|
12678
12856
|
let skipped = 0;
|
|
12679
12857
|
const done = new Map;
|
|
12680
12858
|
try {
|
|
12681
|
-
|
|
12859
|
+
fs12.mkdirSync(path14.join(legacy, "tasks"), { recursive: true });
|
|
12682
12860
|
for (const name of ["workspace.json", "index.json"])
|
|
12683
|
-
if (
|
|
12684
|
-
|
|
12861
|
+
if (fs12.existsSync(path14.join(v2, name)))
|
|
12862
|
+
fs12.copyFileSync(path14.join(v2, name), path14.join(legacy, name));
|
|
12685
12863
|
for (const name of files) {
|
|
12686
12864
|
const id = name.slice(0, -5);
|
|
12687
|
-
const file =
|
|
12688
|
-
const bytes =
|
|
12865
|
+
const file = path14.join(v2Tasks, name);
|
|
12866
|
+
const bytes = fs12.readFileSync(file, "utf8");
|
|
12689
12867
|
const digest = sha256(bytes);
|
|
12690
|
-
|
|
12868
|
+
fs12.writeFileSync(path14.join(legacy, "tasks", name), bytes);
|
|
12691
12869
|
const parsed = this.parseRecord(bytes, taskRecordSchema, "2.x task");
|
|
12692
12870
|
if (!parsed.ok || parsed.data.id !== id)
|
|
12693
12871
|
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 });
|
|
12694
12872
|
const record = { ...parsed.data, workspaceId: target.id };
|
|
12695
|
-
const origin = { path:
|
|
12696
|
-
if (!
|
|
12873
|
+
const origin = { path: path14.join(legacy, "tasks", name), digest };
|
|
12874
|
+
if (!fs12.existsSync(this.eventsPath(id))) {
|
|
12697
12875
|
this.openTask(record, "migrated.from_v2", null, origin);
|
|
12698
12876
|
migrated += 1;
|
|
12699
12877
|
} else {
|
|
@@ -12728,8 +12906,8 @@ class TaskStore {
|
|
|
12728
12906
|
try {
|
|
12729
12907
|
let complete = true;
|
|
12730
12908
|
for (const [name, digest] of done) {
|
|
12731
|
-
const file =
|
|
12732
|
-
if (sha256(
|
|
12909
|
+
const file = path14.join(v2Tasks, name);
|
|
12910
|
+
if (sha256(fs12.readFileSync(file, "utf8")) !== digest) {
|
|
12733
12911
|
complete = false;
|
|
12734
12912
|
continue;
|
|
12735
12913
|
}
|
|
@@ -12739,7 +12917,7 @@ class TaskStore {
|
|
|
12739
12917
|
return failure2("busy", `the 2.x store at ${v2} changed during migration; retry`, {
|
|
12740
12918
|
path: v2
|
|
12741
12919
|
});
|
|
12742
|
-
|
|
12920
|
+
fs12.rmSync(path14.join(v2, "index.json"), { force: true });
|
|
12743
12921
|
this.writeTombstone(v2, target.id);
|
|
12744
12922
|
} catch (error) {
|
|
12745
12923
|
return failure2("storage_error", `cannot finish the 2.x migration: ${String(error)}`, {
|
|
@@ -12759,45 +12937,45 @@ class TaskStore {
|
|
|
12759
12937
|
}
|
|
12760
12938
|
adoptLocalStore() {
|
|
12761
12939
|
const dirs = this.paths();
|
|
12762
|
-
const marker =
|
|
12763
|
-
if (!dirs.shared || !
|
|
12940
|
+
const marker = path14.join(dirs.v2, "store.json");
|
|
12941
|
+
if (!dirs.shared || !fs12.existsSync(marker))
|
|
12764
12942
|
return success(null, null, null);
|
|
12765
12943
|
return this.withLock(dirs.checkoutLock, () => {
|
|
12766
|
-
if (!
|
|
12944
|
+
if (!fs12.existsSync(marker))
|
|
12767
12945
|
return success(null, null, null);
|
|
12768
12946
|
let tasks = 0;
|
|
12769
12947
|
try {
|
|
12770
12948
|
const merge = (from, to) => {
|
|
12771
|
-
if (!
|
|
12772
|
-
|
|
12949
|
+
if (!fs12.existsSync(to)) {
|
|
12950
|
+
fs12.mkdirSync(path14.dirname(to), { recursive: true });
|
|
12773
12951
|
try {
|
|
12774
|
-
|
|
12952
|
+
fs12.renameSync(from, to);
|
|
12775
12953
|
} catch {
|
|
12776
|
-
|
|
12777
|
-
|
|
12954
|
+
fs12.cpSync(from, to, { recursive: true, errorOnExist: true, force: false });
|
|
12955
|
+
fs12.rmSync(from, { recursive: true, force: true });
|
|
12778
12956
|
}
|
|
12779
12957
|
return;
|
|
12780
12958
|
}
|
|
12781
|
-
if (
|
|
12782
|
-
for (const name of
|
|
12783
|
-
merge(
|
|
12959
|
+
if (fs12.lstatSync(from).isDirectory() && fs12.lstatSync(to).isDirectory())
|
|
12960
|
+
for (const name of fs12.readdirSync(from))
|
|
12961
|
+
merge(path14.join(from, name), path14.join(to, name));
|
|
12784
12962
|
};
|
|
12785
12963
|
for (const sub of ["tasks", "checkouts", "blobs", "legacy"]) {
|
|
12786
|
-
const from =
|
|
12787
|
-
if (!
|
|
12964
|
+
const from = path14.join(dirs.v2, sub);
|
|
12965
|
+
if (!fs12.existsSync(from))
|
|
12788
12966
|
continue;
|
|
12789
12967
|
if (sub === "tasks") {
|
|
12790
|
-
for (const name of
|
|
12791
|
-
if (validId(name) && !
|
|
12968
|
+
for (const name of fs12.readdirSync(from))
|
|
12969
|
+
if (validId(name) && !fs12.existsSync(path14.join(dirs.dir, sub, name)))
|
|
12792
12970
|
tasks += 1;
|
|
12793
12971
|
}
|
|
12794
|
-
merge(from,
|
|
12972
|
+
merge(from, path14.join(dirs.dir, sub));
|
|
12795
12973
|
}
|
|
12796
|
-
const ledger =
|
|
12797
|
-
if (
|
|
12798
|
-
merge(ledger,
|
|
12799
|
-
|
|
12800
|
-
|
|
12974
|
+
const ledger = path14.join(dirs.v2, "ledger");
|
|
12975
|
+
if (fs12.existsSync(ledger) && !fs12.existsSync(path14.join(dirs.dir, "ledger")))
|
|
12976
|
+
merge(ledger, path14.join(dirs.dir, "ledger"));
|
|
12977
|
+
fs12.rmSync(path14.join(dirs.v2, "task-index.json"), { force: true });
|
|
12978
|
+
fs12.renameSync(marker, path14.join(dirs.v2, "store.moved.json"));
|
|
12801
12979
|
} catch (error) {
|
|
12802
12980
|
return failure2("storage_error", `cannot move ${dirs.v2} into ${dirs.dir}: ${String(error)}`, {
|
|
12803
12981
|
path: dirs.v2
|
|
@@ -12817,7 +12995,7 @@ class TaskStore {
|
|
|
12817
12995
|
readV2Workspace(file) {
|
|
12818
12996
|
let bytes;
|
|
12819
12997
|
try {
|
|
12820
|
-
bytes =
|
|
12998
|
+
bytes = fs12.readFileSync(file, "utf8");
|
|
12821
12999
|
} catch {
|
|
12822
13000
|
return null;
|
|
12823
13001
|
}
|
|
@@ -12835,7 +13013,7 @@ class TaskStore {
|
|
|
12835
13013
|
schemaVersion: SCHEMA_VERSION,
|
|
12836
13014
|
id: workspaceId ?? newId(),
|
|
12837
13015
|
revision: newRevision(),
|
|
12838
|
-
root:
|
|
13016
|
+
root: path14.dirname(v2),
|
|
12839
13017
|
runtime: { createdWith: version, updatedWith: version },
|
|
12840
13018
|
writer: null,
|
|
12841
13019
|
store: {
|
|
@@ -12846,12 +13024,12 @@ class TaskStore {
|
|
|
12846
13024
|
},
|
|
12847
13025
|
critical: ["store"]
|
|
12848
13026
|
};
|
|
12849
|
-
|
|
12850
|
-
const ignore =
|
|
12851
|
-
if (!
|
|
12852
|
-
|
|
13027
|
+
fs12.mkdirSync(v2, { recursive: true });
|
|
13028
|
+
const ignore = path14.join(v2, ".gitignore");
|
|
13029
|
+
if (!fs12.existsSync(ignore))
|
|
13030
|
+
fs12.writeFileSync(ignore, `*
|
|
12853
13031
|
`);
|
|
12854
|
-
replaceFile(
|
|
13032
|
+
replaceFile(path14.join(v2, "workspace.json"), `${JSON.stringify(marker, null, 2)}
|
|
12855
13033
|
`, true);
|
|
12856
13034
|
}
|
|
12857
13035
|
stubFor(taskId) {
|
|
@@ -12867,7 +13045,7 @@ class TaskStore {
|
|
|
12867
13045
|
}
|
|
12868
13046
|
isStub(file) {
|
|
12869
13047
|
try {
|
|
12870
|
-
const value = JSON.parse(
|
|
13048
|
+
const value = JSON.parse(fs12.readFileSync(file, "utf8"));
|
|
12871
13049
|
return isObject5(value) && isObject5(value.store) && value.store.format === "workit-store";
|
|
12872
13050
|
} catch {
|
|
12873
13051
|
return false;
|
|
@@ -12875,32 +13053,32 @@ class TaskStore {
|
|
|
12875
13053
|
}
|
|
12876
13054
|
writeTombstoneIfMissing() {
|
|
12877
13055
|
try {
|
|
12878
|
-
const v2 =
|
|
12879
|
-
if (
|
|
13056
|
+
const v2 = path14.join(this.root, ".workit");
|
|
13057
|
+
if (fs12.existsSync(path14.join(v2, "workspace.json")))
|
|
12880
13058
|
return;
|
|
12881
13059
|
let id = null;
|
|
12882
13060
|
try {
|
|
12883
|
-
id = JSON.parse(
|
|
13061
|
+
id = JSON.parse(fs12.readFileSync(this.paths().workspace, "utf8")).id ?? null;
|
|
12884
13062
|
} catch {}
|
|
12885
13063
|
this.writeTombstone(v2, id);
|
|
12886
13064
|
} catch {}
|
|
12887
13065
|
}
|
|
12888
13066
|
initializeStorage() {
|
|
12889
13067
|
const dirs = this.paths();
|
|
12890
|
-
retryTransient(() =>
|
|
12891
|
-
retryTransient(() =>
|
|
12892
|
-
if (!
|
|
13068
|
+
retryTransient(() => fs12.mkdirSync(dirs.checkout, { recursive: true }));
|
|
13069
|
+
retryTransient(() => fs12.mkdirSync(dirs.tasks, { recursive: true }));
|
|
13070
|
+
if (!fs12.existsSync(dirs.marker))
|
|
12893
13071
|
replaceFile(dirs.marker, `${JSON.stringify({ format: "workit-store", version: STORE_FORMAT, createdWith: runtimeVersion() })}
|
|
12894
13072
|
`, false);
|
|
12895
13073
|
if (!dirs.shared) {
|
|
12896
|
-
const ignore =
|
|
13074
|
+
const ignore = path14.join(dirs.dir, ".gitignore");
|
|
12897
13075
|
let current = null;
|
|
12898
13076
|
try {
|
|
12899
|
-
current =
|
|
13077
|
+
current = fs12.readFileSync(ignore, "utf8");
|
|
12900
13078
|
} catch {}
|
|
12901
13079
|
if (current !== `*
|
|
12902
13080
|
`)
|
|
12903
|
-
retryTransient(() =>
|
|
13081
|
+
retryTransient(() => fs12.writeFileSync(ignore, `*
|
|
12904
13082
|
`));
|
|
12905
13083
|
}
|
|
12906
13084
|
this.writeTombstoneIfMissing();
|
|
@@ -12916,7 +13094,7 @@ class TaskStore {
|
|
|
12916
13094
|
shouldReclaim: ({ payload, nowMs }) => {
|
|
12917
13095
|
let ageMs = null;
|
|
12918
13096
|
try {
|
|
12919
|
-
ageMs = nowMs -
|
|
13097
|
+
ageMs = nowMs - fs12.lstatSync(lockPath).mtimeMs;
|
|
12920
13098
|
} catch {}
|
|
12921
13099
|
return classifyLockOwner(payload, ageMs, localLockHost(), TASK_STORE_LOCK).state === "stale";
|
|
12922
13100
|
},
|
|
@@ -12953,7 +13131,7 @@ class TaskStore {
|
|
|
12953
13131
|
withLock(lockPath, operation) {
|
|
12954
13132
|
try {
|
|
12955
13133
|
this.initializeStorage();
|
|
12956
|
-
|
|
13134
|
+
fs12.mkdirSync(path14.dirname(lockPath), { recursive: true });
|
|
12957
13135
|
} catch (error) {
|
|
12958
13136
|
return failure2("storage_error", `unable to initialize store: ${String(error)}`, {
|
|
12959
13137
|
path: this.paths().dir
|
|
@@ -12993,18 +13171,18 @@ class TaskStore {
|
|
|
12993
13171
|
lockDirWritable(lockPath) {
|
|
12994
13172
|
const probe = `${lockPath}.${process.pid}.${randomUUID3()}.probe`;
|
|
12995
13173
|
try {
|
|
12996
|
-
|
|
13174
|
+
fs12.closeSync(fs12.openSync(probe, "wx", 384));
|
|
12997
13175
|
} catch {
|
|
12998
13176
|
return false;
|
|
12999
13177
|
}
|
|
13000
13178
|
try {
|
|
13001
|
-
|
|
13179
|
+
fs12.rmSync(probe, { force: true });
|
|
13002
13180
|
} catch {}
|
|
13003
13181
|
return true;
|
|
13004
13182
|
}
|
|
13005
13183
|
lockHolderPresent(lockPath) {
|
|
13006
13184
|
try {
|
|
13007
|
-
|
|
13185
|
+
fs12.lstatSync(lockPath);
|
|
13008
13186
|
return true;
|
|
13009
13187
|
} catch (error) {
|
|
13010
13188
|
return error?.code !== "ENOENT";
|
|
@@ -13016,12 +13194,12 @@ class TaskStore {
|
|
|
13016
13194
|
if (isTransientWindowsError(error) && !this.lockHolderPresent(lockPath) && !this.lockDirWritable(lockPath))
|
|
13017
13195
|
return failure2("storage_error", `cannot create the workit lock (${code}); no other Workit call holds it`, {
|
|
13018
13196
|
path: lockPath,
|
|
13019
|
-
guidance: `Check permissions and the read-only attribute on ${
|
|
13197
|
+
guidance: `Check permissions and the read-only attribute on ${path14.dirname(lockPath)}.`
|
|
13020
13198
|
});
|
|
13021
13199
|
if (code === "EEXIST" || code === "file_lock_timeout" || code === "file_lock_stale" || isTransientWindowsError(error)) {
|
|
13022
13200
|
let lock = null;
|
|
13023
13201
|
try {
|
|
13024
|
-
lock = parseMetadataLockOrNull(
|
|
13202
|
+
lock = parseMetadataLockOrNull(fs12.readFileSync(lockPath, "utf8"));
|
|
13025
13203
|
} catch {}
|
|
13026
13204
|
return failure2("busy", `workit lock is held by another Workit call${lock ? ` (pid ${lock.pid} on ${lock.host})` : ""}; retry shortly`, {
|
|
13027
13205
|
outcome: "not_started",
|
|
@@ -13040,26 +13218,26 @@ var workerBlocksTransition = (transition, state) => transition === "pause" ? fal
|
|
|
13040
13218
|
var holdsLiveState = (state, dirty) => state === "running" || dirty === true;
|
|
13041
13219
|
|
|
13042
13220
|
// packages/workit-core/src/core/task-evaluation.ts
|
|
13043
|
-
import { createHash as
|
|
13044
|
-
import * as
|
|
13221
|
+
import { createHash as createHash13 } from "node:crypto";
|
|
13222
|
+
import * as fs15 from "node:fs";
|
|
13045
13223
|
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
13046
|
-
import
|
|
13224
|
+
import path19 from "node:path";
|
|
13047
13225
|
|
|
13048
13226
|
// packages/workit-core/src/check-config.ts
|
|
13049
13227
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
13050
|
-
import
|
|
13051
|
-
import
|
|
13228
|
+
import fs13 from "node:fs";
|
|
13229
|
+
import path15 from "node:path";
|
|
13052
13230
|
var SCRIPT_CHECKS = ["test", "lint", "typecheck", "check"];
|
|
13053
13231
|
var CHECKS_FILE = ".workit/checks.json";
|
|
13054
13232
|
var LEGACY_CHECKS_FILE = "workit.checks.json";
|
|
13055
13233
|
function checksConfigFile(root) {
|
|
13056
|
-
const current =
|
|
13057
|
-
const legacy =
|
|
13058
|
-
return !
|
|
13234
|
+
const current = path15.join(root, CHECKS_FILE);
|
|
13235
|
+
const legacy = path15.join(root, LEGACY_CHECKS_FILE);
|
|
13236
|
+
return !fs13.existsSync(current) && fs13.existsSync(legacy) ? legacy : current;
|
|
13059
13237
|
}
|
|
13060
13238
|
function repoHeavyCommands(root) {
|
|
13061
13239
|
try {
|
|
13062
|
-
const value = JSON.parse(
|
|
13240
|
+
const value = JSON.parse(fs13.readFileSync(checksConfigFile(root), "utf8"));
|
|
13063
13241
|
const resources = isRecord2(value) ? value.resources : undefined;
|
|
13064
13242
|
const list = isRecord2(resources) ? resources.heavyCommands : undefined;
|
|
13065
13243
|
return Array.isArray(list) ? list.filter((item) => typeof item === "string") : [];
|
|
@@ -13117,10 +13295,10 @@ var git3 = (cwd, args) => {
|
|
|
13117
13295
|
return value || null;
|
|
13118
13296
|
};
|
|
13119
13297
|
function checkRoot(cwd) {
|
|
13120
|
-
return
|
|
13298
|
+
return path15.resolve(git3(cwd, ["rev-parse", "--show-toplevel"]) ?? cwd);
|
|
13121
13299
|
}
|
|
13122
13300
|
var packageManager = (root) => {
|
|
13123
|
-
const has = (file) =>
|
|
13301
|
+
const has = (file) => fs13.existsSync(path15.join(root, file));
|
|
13124
13302
|
if (has("bun.lock") || has("bun.lockb"))
|
|
13125
13303
|
return "bun";
|
|
13126
13304
|
if (has("pnpm-lock.yaml"))
|
|
@@ -13140,7 +13318,7 @@ var CHECK_NAME = /^[a-z0-9][a-z0-9:._-]{0,63}$/u;
|
|
|
13140
13318
|
function detectedChecks(root) {
|
|
13141
13319
|
const read = (file) => {
|
|
13142
13320
|
try {
|
|
13143
|
-
return
|
|
13321
|
+
return fs13.readFileSync(path15.join(root, file), "utf8");
|
|
13144
13322
|
} catch {
|
|
13145
13323
|
return null;
|
|
13146
13324
|
}
|
|
@@ -13179,21 +13357,21 @@ function detectedChecks(root) {
|
|
|
13179
13357
|
var GATES = ["testing", "verification"];
|
|
13180
13358
|
function configFileFor(root) {
|
|
13181
13359
|
const own = checksConfigFile(root);
|
|
13182
|
-
if (
|
|
13360
|
+
if (fs13.existsSync(own))
|
|
13183
13361
|
return own;
|
|
13184
13362
|
const common = git3(root, ["rev-parse", "--path-format=absolute", "--git-common-dir"]);
|
|
13185
|
-
if (!common ||
|
|
13363
|
+
if (!common || path15.basename(common) !== ".git")
|
|
13186
13364
|
return own;
|
|
13187
|
-
const main =
|
|
13188
|
-
if (
|
|
13365
|
+
const main = path15.dirname(common);
|
|
13366
|
+
if (path15.resolve(main) === path15.resolve(root))
|
|
13189
13367
|
return own;
|
|
13190
13368
|
const shared = checksConfigFile(main);
|
|
13191
|
-
return
|
|
13369
|
+
return fs13.existsSync(shared) ? shared : own;
|
|
13192
13370
|
}
|
|
13193
13371
|
function loadCheckConfig(cwd) {
|
|
13194
13372
|
const root = checkRoot(cwd);
|
|
13195
13373
|
const file = configFileFor(root);
|
|
13196
|
-
const legacy =
|
|
13374
|
+
const legacy = path15.basename(file) === LEGACY_CHECKS_FILE;
|
|
13197
13375
|
const label = legacy ? LEGACY_CHECKS_FILE : CHECKS_FILE;
|
|
13198
13376
|
const note = legacy ? {
|
|
13199
13377
|
note: `${LEGACY_CHECKS_FILE} is deprecated; move it to ${CHECKS_FILE} (workit doctor --fix)`
|
|
@@ -13208,7 +13386,7 @@ function loadCheckConfig(cwd) {
|
|
|
13208
13386
|
});
|
|
13209
13387
|
let text = null;
|
|
13210
13388
|
try {
|
|
13211
|
-
text =
|
|
13389
|
+
text = fs13.readFileSync(file, "utf8");
|
|
13212
13390
|
} catch (error) {
|
|
13213
13391
|
if (error.code !== "ENOENT")
|
|
13214
13392
|
return none(`cannot read ${label}: ${error.message}`);
|
|
@@ -13271,10 +13449,10 @@ function workitAvailable(env = process.env) {
|
|
|
13271
13449
|
return workitOnPath;
|
|
13272
13450
|
const windows = process.platform === "win32";
|
|
13273
13451
|
const exts = windows ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
|
|
13274
|
-
const dirs = (env.PATH ?? env.Path ?? "").split(
|
|
13452
|
+
const dirs = (env.PATH ?? env.Path ?? "").split(path15.delimiter).filter(Boolean);
|
|
13275
13453
|
workitOnPath = dirs.some((dir) => exts.some((ext) => {
|
|
13276
13454
|
try {
|
|
13277
|
-
return
|
|
13455
|
+
return fs13.statSync(path15.join(dir, `workit${ext}`)).isFile();
|
|
13278
13456
|
} catch {
|
|
13279
13457
|
return false;
|
|
13280
13458
|
}
|
|
@@ -13287,17 +13465,17 @@ function checkCommand(args, version, onPath = workitAvailable()) {
|
|
|
13287
13465
|
|
|
13288
13466
|
// packages/workit-core/src/core/policy/derive.ts
|
|
13289
13467
|
import { existsSync as existsSync5 } from "node:fs";
|
|
13290
|
-
import
|
|
13468
|
+
import path18 from "node:path";
|
|
13291
13469
|
|
|
13292
13470
|
// packages/workit-core/src/ledger.ts
|
|
13293
13471
|
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
13294
|
-
import { createHash as
|
|
13295
|
-
import
|
|
13296
|
-
import
|
|
13472
|
+
import { createHash as createHash12, randomBytes as randomBytes3 } from "node:crypto";
|
|
13473
|
+
import fs14 from "node:fs";
|
|
13474
|
+
import path17 from "node:path";
|
|
13297
13475
|
|
|
13298
13476
|
// packages/workit-core/src/core/policy/lane.ts
|
|
13299
13477
|
import { existsSync as existsSync4, readFileSync as readFileSync4 } from "node:fs";
|
|
13300
|
-
import
|
|
13478
|
+
import path16 from "node:path";
|
|
13301
13479
|
|
|
13302
13480
|
// packages/workit-core/src/git/default-base.ts
|
|
13303
13481
|
var safeRef = (value) => value.length > 0 && !value.startsWith("-");
|
|
@@ -13882,7 +14060,7 @@ function computeLane(input) {
|
|
|
13882
14060
|
}
|
|
13883
14061
|
function untrackedStat(cwd, file) {
|
|
13884
14062
|
try {
|
|
13885
|
-
const bytes = readFileSync4(
|
|
14063
|
+
const bytes = readFileSync4(path16.join(cwd, file));
|
|
13886
14064
|
if (bytes.includes(0))
|
|
13887
14065
|
return { path: file, added: 0, deleted: 0, binary: true };
|
|
13888
14066
|
const text = bytes.toString("utf8");
|
|
@@ -13913,7 +14091,7 @@ function cosmeticFiles(cwd, fork, head) {
|
|
|
13913
14091
|
let after = blobs.get(entry.newBlob);
|
|
13914
14092
|
if (!after && head === null && ABSENT.test(entry.newBlob))
|
|
13915
14093
|
try {
|
|
13916
|
-
after = readFileSync4(
|
|
14094
|
+
after = readFileSync4(path16.join(cwd, entry.path));
|
|
13917
14095
|
} catch {
|
|
13918
14096
|
after = undefined;
|
|
13919
14097
|
}
|
|
@@ -14036,61 +14214,6 @@ function verdictDrift(cwd, input) {
|
|
|
14036
14214
|
return stale(lane.reasons[0] ?? `lane ${lane.lane}`, paths, lane.lane === "self");
|
|
14037
14215
|
}
|
|
14038
14216
|
|
|
14039
|
-
// packages/workit-core/src/hooks/standing-signal.ts
|
|
14040
|
-
import { createHash as createHash10 } from "node:crypto";
|
|
14041
|
-
import fs12 from "node:fs";
|
|
14042
|
-
import path15 from "node:path";
|
|
14043
|
-
var gitStoreDir = (cwd) => {
|
|
14044
|
-
try {
|
|
14045
|
-
for (let dir = path15.resolve(cwd);; dir = path15.dirname(dir)) {
|
|
14046
|
-
const dotGit = path15.join(dir, ".git");
|
|
14047
|
-
if (fs12.existsSync(dotGit)) {
|
|
14048
|
-
let gitDir = dotGit;
|
|
14049
|
-
if (fs12.statSync(dotGit).isFile()) {
|
|
14050
|
-
const target = /^gitdir:\s*(.+)$/mu.exec(fs12.readFileSync(dotGit, "utf8"))?.[1]?.trim();
|
|
14051
|
-
if (!target)
|
|
14052
|
-
return null;
|
|
14053
|
-
gitDir = path15.resolve(dir, target);
|
|
14054
|
-
const common = path15.join(gitDir, "commondir");
|
|
14055
|
-
if (fs12.existsSync(common))
|
|
14056
|
-
gitDir = path15.resolve(gitDir, fs12.readFileSync(common, "utf8").trim());
|
|
14057
|
-
}
|
|
14058
|
-
return path15.join(gitDir, "workit");
|
|
14059
|
-
}
|
|
14060
|
-
if (path15.dirname(dir) === dir)
|
|
14061
|
-
return null;
|
|
14062
|
-
}
|
|
14063
|
-
} catch {
|
|
14064
|
-
return null;
|
|
14065
|
-
}
|
|
14066
|
-
};
|
|
14067
|
-
var standingRevFile = (store) => path15.join(store, "standing", "rev");
|
|
14068
|
-
var standingSeenFile = (store, session, agentId) => path15.join(store, "standing", "seen", `${createHash10("sha256").update(`${session}\x00${agentId ?? ""}`).digest("hex").slice(0, 32)}.json`);
|
|
14069
|
-
var readStandingRev = (store) => {
|
|
14070
|
-
try {
|
|
14071
|
-
return fs12.readFileSync(standingRevFile(store), "utf8").trim() || null;
|
|
14072
|
-
} catch {
|
|
14073
|
-
return null;
|
|
14074
|
-
}
|
|
14075
|
-
};
|
|
14076
|
-
var readStandingSeen = (file) => {
|
|
14077
|
-
try {
|
|
14078
|
-
const value = JSON.parse(fs12.readFileSync(file, "utf8"));
|
|
14079
|
-
return {
|
|
14080
|
-
rev: typeof value.rev === "string" ? value.rev : null,
|
|
14081
|
-
ids: Array.isArray(value.ids) ? value.ids.filter((id) => typeof id === "string") : []
|
|
14082
|
-
};
|
|
14083
|
-
} catch {
|
|
14084
|
-
return { rev: null, ids: [] };
|
|
14085
|
-
}
|
|
14086
|
-
};
|
|
14087
|
-
var writeStandingSeen = (file, seen) => {
|
|
14088
|
-
try {
|
|
14089
|
-
fs12.mkdirSync(path15.dirname(file), { recursive: true });
|
|
14090
|
-
fs12.writeFileSync(file, JSON.stringify(seen));
|
|
14091
|
-
} catch {}
|
|
14092
|
-
};
|
|
14093
|
-
|
|
14094
14217
|
// packages/workit-core/src/ledger.ts
|
|
14095
14218
|
var LEDGER_VERSION = 1;
|
|
14096
14219
|
var MAX_LINE_BYTES = 4096;
|
|
@@ -14168,7 +14291,7 @@ function diffHash(cwd, base, head) {
|
|
|
14168
14291
|
], GIT_TIMEOUTS.worktree);
|
|
14169
14292
|
if (!diff.ok || !diff.stdout)
|
|
14170
14293
|
return null;
|
|
14171
|
-
const hash =
|
|
14294
|
+
const hash = createHash12("sha256");
|
|
14172
14295
|
for (const line of diff.stdout.split(`
|
|
14173
14296
|
`)) {
|
|
14174
14297
|
if (line.startsWith("index "))
|
|
@@ -14192,14 +14315,14 @@ function cleanRebase(cwd, range) {
|
|
|
14192
14315
|
return Boolean(tree) && tree === git4(cwd, ["rev-parse", "--verify", "-q", `${range.to}^{tree}`]);
|
|
14193
14316
|
}
|
|
14194
14317
|
function storeRoot(cwd) {
|
|
14195
|
-
const location = resolveStore(
|
|
14318
|
+
const location = resolveStore(path17.resolve(cwd));
|
|
14196
14319
|
if (location instanceof Error)
|
|
14197
14320
|
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");
|
|
14198
14321
|
return { ok: true, value: { root: location.dir, shared: location.shared } };
|
|
14199
14322
|
}
|
|
14200
14323
|
function ledgerPath(cwd) {
|
|
14201
14324
|
const root = storeRoot(cwd);
|
|
14202
|
-
return root.ok ? { ok: true, value:
|
|
14325
|
+
return root.ok ? { ok: true, value: path17.join(root.value.root, "ledger", "ledger.jsonl") } : root;
|
|
14203
14326
|
}
|
|
14204
14327
|
var newId2 = () => `${Date.now().toString(36)}-${randomBytes3(6).toString("hex")}`;
|
|
14205
14328
|
var NETWORK_FS_TYPES = new Set([
|
|
@@ -14219,7 +14342,7 @@ var onNetworkFs = (dir) => {
|
|
|
14219
14342
|
if (process.platform !== "linux")
|
|
14220
14343
|
return false;
|
|
14221
14344
|
try {
|
|
14222
|
-
return isNetworkFsType(
|
|
14345
|
+
return isNetworkFsType(fs14.statfsSync(dir).type);
|
|
14223
14346
|
} catch {
|
|
14224
14347
|
return false;
|
|
14225
14348
|
}
|
|
@@ -14229,15 +14352,15 @@ var LOCK_STALE_MS = 30000;
|
|
|
14229
14352
|
var LOCK_OWNER = "owner";
|
|
14230
14353
|
var lockToken = (lock) => {
|
|
14231
14354
|
try {
|
|
14232
|
-
return
|
|
14355
|
+
return fs14.readFileSync(path17.join(lock, LOCK_OWNER), "utf8");
|
|
14233
14356
|
} catch {
|
|
14234
14357
|
return null;
|
|
14235
14358
|
}
|
|
14236
14359
|
};
|
|
14237
14360
|
var lockAgeMs = (lock) => {
|
|
14238
|
-
for (const target of [
|
|
14361
|
+
for (const target of [path17.join(lock, LOCK_OWNER), lock]) {
|
|
14239
14362
|
try {
|
|
14240
|
-
return Date.now() -
|
|
14363
|
+
return Date.now() - fs14.statSync(target).mtimeMs;
|
|
14241
14364
|
} catch {}
|
|
14242
14365
|
}
|
|
14243
14366
|
return null;
|
|
@@ -14245,14 +14368,14 @@ var lockAgeMs = (lock) => {
|
|
|
14245
14368
|
var ledgerLock = {
|
|
14246
14369
|
acquire(lock) {
|
|
14247
14370
|
try {
|
|
14248
|
-
|
|
14371
|
+
fs14.mkdirSync(lock);
|
|
14249
14372
|
} catch (error) {
|
|
14250
14373
|
if (error.code === "EEXIST")
|
|
14251
14374
|
return null;
|
|
14252
14375
|
throw error;
|
|
14253
14376
|
}
|
|
14254
14377
|
const token = `${process.pid}-${randomBytes3(8).toString("hex")}`;
|
|
14255
|
-
|
|
14378
|
+
fs14.writeFileSync(path17.join(lock, LOCK_OWNER), token);
|
|
14256
14379
|
return token;
|
|
14257
14380
|
},
|
|
14258
14381
|
release(lock, token) {
|
|
@@ -14260,35 +14383,35 @@ var ledgerLock = {
|
|
|
14260
14383
|
return false;
|
|
14261
14384
|
const tomb = `${lock}.release-${randomBytes3(6).toString("hex")}`;
|
|
14262
14385
|
try {
|
|
14263
|
-
|
|
14386
|
+
fs14.renameSync(lock, tomb);
|
|
14264
14387
|
} catch {
|
|
14265
14388
|
return false;
|
|
14266
14389
|
}
|
|
14267
14390
|
if (lockToken(tomb) !== token) {
|
|
14268
14391
|
try {
|
|
14269
|
-
|
|
14392
|
+
fs14.renameSync(tomb, lock);
|
|
14270
14393
|
} catch {}
|
|
14271
14394
|
return false;
|
|
14272
14395
|
}
|
|
14273
|
-
|
|
14396
|
+
fs14.rmSync(tomb, { recursive: true, force: true });
|
|
14274
14397
|
return true;
|
|
14275
14398
|
},
|
|
14276
14399
|
token: lockToken,
|
|
14277
14400
|
reap(lock, observed) {
|
|
14278
14401
|
const tomb = `${lock}.reap-${randomBytes3(6).toString("hex")}`;
|
|
14279
14402
|
try {
|
|
14280
|
-
|
|
14403
|
+
fs14.renameSync(lock, tomb);
|
|
14281
14404
|
} catch {
|
|
14282
14405
|
return false;
|
|
14283
14406
|
}
|
|
14284
14407
|
if (lockToken(tomb) === observed) {
|
|
14285
|
-
|
|
14408
|
+
fs14.rmSync(tomb, { recursive: true, force: true });
|
|
14286
14409
|
return true;
|
|
14287
14410
|
}
|
|
14288
14411
|
try {
|
|
14289
|
-
|
|
14412
|
+
fs14.renameSync(tomb, lock);
|
|
14290
14413
|
} catch {
|
|
14291
|
-
|
|
14414
|
+
fs14.rmSync(tomb, { recursive: true, force: true });
|
|
14292
14415
|
}
|
|
14293
14416
|
return false;
|
|
14294
14417
|
}
|
|
@@ -14315,14 +14438,14 @@ function withLedgerLock(file, fn, waitMs = hostAwareLockTimeout(LOCK_WAIT_MS)) {
|
|
|
14315
14438
|
ledgerLock.release(lock, token);
|
|
14316
14439
|
}
|
|
14317
14440
|
}
|
|
14318
|
-
var sha2562 = (text) =>
|
|
14441
|
+
var sha2562 = (text) => createHash12("sha256").update(text).digest("hex");
|
|
14319
14442
|
var chainHash = (prevHash, body) => sha2562(`${prevHash ?? ""}
|
|
14320
14443
|
${body}`);
|
|
14321
14444
|
var TAIL_BYTES = 64 * 1024;
|
|
14322
14445
|
var lastLine = (fd, size) => {
|
|
14323
14446
|
for (let span = Math.min(size, TAIL_BYTES);span > 0; span = Math.min(size, span * 2)) {
|
|
14324
14447
|
const buffer = Buffer.alloc(span);
|
|
14325
|
-
|
|
14448
|
+
fs14.readSync(fd, buffer, 0, span, size - span);
|
|
14326
14449
|
const end = buffer.lastIndexOf(10);
|
|
14327
14450
|
if (end < 0) {
|
|
14328
14451
|
if (span === size)
|
|
@@ -14353,21 +14476,21 @@ var lastLine = (fd, size) => {
|
|
|
14353
14476
|
};
|
|
14354
14477
|
var tighten = (fd) => {
|
|
14355
14478
|
try {
|
|
14356
|
-
if ((
|
|
14357
|
-
|
|
14479
|
+
if ((fs14.fstatSync(fd).mode & 63) !== 0)
|
|
14480
|
+
fs14.fchmodSync(fd, 384);
|
|
14358
14481
|
} catch {}
|
|
14359
14482
|
};
|
|
14360
14483
|
function appendLine(file, build, options) {
|
|
14361
14484
|
const write = () => {
|
|
14362
|
-
const fd =
|
|
14485
|
+
const fd = fs14.openSync(file, "a+", 384);
|
|
14363
14486
|
try {
|
|
14364
14487
|
if (process.platform !== "win32")
|
|
14365
14488
|
tighten(fd);
|
|
14366
|
-
const size =
|
|
14489
|
+
const size = fs14.fstatSync(fd).size;
|
|
14367
14490
|
let fence = "";
|
|
14368
14491
|
if (size > 0) {
|
|
14369
14492
|
const last = Buffer.alloc(1);
|
|
14370
|
-
|
|
14493
|
+
fs14.readSync(fd, last, 0, 1, size - 1);
|
|
14371
14494
|
if (last[0] !== 10)
|
|
14372
14495
|
fence = `
|
|
14373
14496
|
`;
|
|
@@ -14376,17 +14499,17 @@ function appendLine(file, build, options) {
|
|
|
14376
14499
|
if (!line.ok)
|
|
14377
14500
|
return line;
|
|
14378
14501
|
const bytes = Buffer.from(fence + line.value);
|
|
14379
|
-
const written =
|
|
14502
|
+
const written = fs14.writeSync(fd, bytes);
|
|
14380
14503
|
if (written !== bytes.length)
|
|
14381
14504
|
return err("unavailable", `short write to ${file}: ${written} of ${bytes.length} bytes; the row is torn and will be skipped`);
|
|
14382
14505
|
return { ok: true, value: undefined };
|
|
14383
14506
|
} finally {
|
|
14384
|
-
|
|
14507
|
+
fs14.closeSync(fd);
|
|
14385
14508
|
}
|
|
14386
14509
|
};
|
|
14387
14510
|
try {
|
|
14388
|
-
|
|
14389
|
-
if (!options.forceLock && !onNetworkFs(
|
|
14511
|
+
fs14.mkdirSync(path17.dirname(file), { recursive: true });
|
|
14512
|
+
if (!options.forceLock && !onNetworkFs(path17.dirname(file)))
|
|
14390
14513
|
return write();
|
|
14391
14514
|
const locked = withLedgerLock(file, write);
|
|
14392
14515
|
return locked ?? err("busy", `ledger lock ${file}.lock is held`, "retry; remove the .lock directory if no workit process is running");
|
|
@@ -14459,8 +14582,8 @@ function readLedger(cwd, options = {}) {
|
|
|
14459
14582
|
let text = "";
|
|
14460
14583
|
let stat = null;
|
|
14461
14584
|
try {
|
|
14462
|
-
stat =
|
|
14463
|
-
text =
|
|
14585
|
+
stat = fs14.statSync(file.value);
|
|
14586
|
+
text = fs14.readFileSync(file.value, "utf8");
|
|
14464
14587
|
} catch (error) {
|
|
14465
14588
|
if (error.code === "ENOENT")
|
|
14466
14589
|
return {
|
|
@@ -14600,7 +14723,7 @@ function ledgerTampering(cwd) {
|
|
|
14600
14723
|
if (!file.ok)
|
|
14601
14724
|
return [];
|
|
14602
14725
|
try {
|
|
14603
|
-
const stat =
|
|
14726
|
+
const stat = fs14.statSync(file.value);
|
|
14604
14727
|
const cached = tamperCache.get(file.value);
|
|
14605
14728
|
if (cached && cached.size === stat.size && cached.stamp === fileStamp(stat))
|
|
14606
14729
|
return cached.breaks;
|
|
@@ -15204,7 +15327,7 @@ var productDecision = (task, ledger) => {
|
|
|
15204
15327
|
};
|
|
15205
15328
|
};
|
|
15206
15329
|
var planRecorded = (task, root) => {
|
|
15207
|
-
const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync5(
|
|
15330
|
+
const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync5(path18.resolve(root, ref.path)));
|
|
15208
15331
|
if (cited)
|
|
15209
15332
|
return {
|
|
15210
15333
|
met: true,
|
|
@@ -15281,15 +15404,15 @@ function writeBlockers(task, root) {
|
|
|
15281
15404
|
}
|
|
15282
15405
|
|
|
15283
15406
|
// packages/workit-core/src/core/task-evaluation.ts
|
|
15284
|
-
var digestBytes = (value) =>
|
|
15285
|
-
var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${
|
|
15286
|
-
var relative = (root, candidate) =>
|
|
15407
|
+
var digestBytes = (value) => createHash13("sha256").update(value).digest("hex");
|
|
15408
|
+
var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path19.sep}`);
|
|
15409
|
+
var relative = (root, candidate) => path19.relative(root, candidate).split(path19.sep).join("/") || ".";
|
|
15287
15410
|
var canonicalPath = (value) => {
|
|
15288
15411
|
if (typeof value !== "string" || !value)
|
|
15289
15412
|
return null;
|
|
15290
15413
|
if (value.includes("\\") || value.split("/").includes(".."))
|
|
15291
15414
|
return null;
|
|
15292
|
-
const normalized =
|
|
15415
|
+
const normalized = path19.posix.normalize(value);
|
|
15293
15416
|
if (normalized === ".." || normalized.startsWith("../") || normalized.startsWith("/"))
|
|
15294
15417
|
return null;
|
|
15295
15418
|
return normalized === "." ? "." : normalized.replace(/\/$/, "");
|
|
@@ -15337,21 +15460,21 @@ var gitPaths = (root) => {
|
|
|
15337
15460
|
git: !/not a git repository/i.test(stderr)
|
|
15338
15461
|
};
|
|
15339
15462
|
}
|
|
15340
|
-
const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(
|
|
15463
|
+
const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path19.sep).join("/")) : [];
|
|
15341
15464
|
const stagedDeleted = spawnSync10("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
|
|
15342
15465
|
if (stagedDeleted.status !== 0) {
|
|
15343
15466
|
const stderr = stagedDeleted.stderr?.toString("utf8") ?? "";
|
|
15344
15467
|
if (!/not a git repository/i.test(stderr))
|
|
15345
15468
|
return { paths, uncertain: true, git: true };
|
|
15346
15469
|
} else if (stagedDeleted.stdout) {
|
|
15347
|
-
paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(
|
|
15470
|
+
paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path19.sep).join("/")));
|
|
15348
15471
|
}
|
|
15349
15472
|
return { paths: [...new Set(paths)], uncertain: false, git: true };
|
|
15350
15473
|
};
|
|
15351
15474
|
var walk = (root, directory, output) => {
|
|
15352
15475
|
let names;
|
|
15353
15476
|
try {
|
|
15354
|
-
names =
|
|
15477
|
+
names = fs15.readdirSync(directory);
|
|
15355
15478
|
} catch {
|
|
15356
15479
|
return true;
|
|
15357
15480
|
}
|
|
@@ -15359,10 +15482,10 @@ var walk = (root, directory, output) => {
|
|
|
15359
15482
|
for (const name of names) {
|
|
15360
15483
|
if (name === ".git" || name === ".workit")
|
|
15361
15484
|
continue;
|
|
15362
|
-
const target =
|
|
15485
|
+
const target = path19.join(directory, name);
|
|
15363
15486
|
let stat;
|
|
15364
15487
|
try {
|
|
15365
|
-
stat =
|
|
15488
|
+
stat = fs15.lstatSync(target);
|
|
15366
15489
|
} catch {
|
|
15367
15490
|
uncertain = true;
|
|
15368
15491
|
continue;
|
|
@@ -15377,14 +15500,14 @@ var walk = (root, directory, output) => {
|
|
|
15377
15500
|
var scopeRoots = (root, scope) => {
|
|
15378
15501
|
const roots = [];
|
|
15379
15502
|
for (const item of scope.paths.length ? scope.paths : ["."]) {
|
|
15380
|
-
const target =
|
|
15503
|
+
const target = path19.resolve(root, item);
|
|
15381
15504
|
if (!inside(root, target))
|
|
15382
15505
|
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` }] });
|
|
15383
15506
|
let ancestor = target;
|
|
15384
|
-
while (!
|
|
15385
|
-
ancestor =
|
|
15507
|
+
while (!fs15.existsSync(ancestor) && ancestor !== root)
|
|
15508
|
+
ancestor = path19.dirname(ancestor);
|
|
15386
15509
|
try {
|
|
15387
|
-
if (!inside(root,
|
|
15510
|
+
if (!inside(root, fs15.realpathSync(ancestor)))
|
|
15388
15511
|
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` }] });
|
|
15389
15512
|
} catch {
|
|
15390
15513
|
return failure2("invalid_input", `candidate scope cannot be inspected: ${item}`);
|
|
@@ -15396,7 +15519,7 @@ var scopeRoots = (root, scope) => {
|
|
|
15396
15519
|
function captureCandidate(root, scope, environment = []) {
|
|
15397
15520
|
let checkout;
|
|
15398
15521
|
try {
|
|
15399
|
-
checkout =
|
|
15522
|
+
checkout = fs15.realpathSync(root);
|
|
15400
15523
|
} catch {
|
|
15401
15524
|
return failure2("invalid_input", "candidate root does not exist");
|
|
15402
15525
|
}
|
|
@@ -15414,11 +15537,11 @@ function captureCandidate(root, scope, environment = []) {
|
|
|
15414
15537
|
if (item === ".git" || item === ".workit")
|
|
15415
15538
|
continue;
|
|
15416
15539
|
names.add(item);
|
|
15417
|
-
if (!
|
|
15540
|
+
if (!fs15.existsSync(target))
|
|
15418
15541
|
continue;
|
|
15419
15542
|
let stat;
|
|
15420
15543
|
try {
|
|
15421
|
-
stat =
|
|
15544
|
+
stat = fs15.lstatSync(target);
|
|
15422
15545
|
} catch {
|
|
15423
15546
|
uncertain = true;
|
|
15424
15547
|
continue;
|
|
@@ -15434,17 +15557,17 @@ function captureCandidate(root, scope, environment = []) {
|
|
|
15434
15557
|
for (const item of [...names].toSorted()) {
|
|
15435
15558
|
if (!scopeMatches(item, normalizedScope))
|
|
15436
15559
|
continue;
|
|
15437
|
-
const target =
|
|
15560
|
+
const target = path19.join(checkout, item);
|
|
15438
15561
|
try {
|
|
15439
|
-
const stat =
|
|
15562
|
+
const stat = fs15.lstatSync(target);
|
|
15440
15563
|
if (stat.isSymbolicLink()) {
|
|
15441
|
-
const link =
|
|
15564
|
+
const link = fs15.readlinkSync(target);
|
|
15442
15565
|
files.push({ path: item, kind: "symlink", digest: digestBytes(link), executable: null });
|
|
15443
15566
|
} else if (stat.isFile()) {
|
|
15444
15567
|
files.push({
|
|
15445
15568
|
path: item,
|
|
15446
15569
|
kind: "file",
|
|
15447
|
-
digest: digestBytes(
|
|
15570
|
+
digest: digestBytes(fs15.readFileSync(target)),
|
|
15448
15571
|
executable: (stat.mode & 73) !== 0
|
|
15449
15572
|
});
|
|
15450
15573
|
} else if (!stat.isDirectory()) {
|
|
@@ -15609,7 +15732,7 @@ var findingVerificationPasses = (findingCandidateId, evidence) => evidence.statu
|
|
|
15609
15732
|
var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
15610
15733
|
let root;
|
|
15611
15734
|
try {
|
|
15612
|
-
root =
|
|
15735
|
+
root = fs15.realpathSync(checkoutRoot);
|
|
15613
15736
|
} catch {
|
|
15614
15737
|
return failure2("permission_denied", "checkout root is unavailable");
|
|
15615
15738
|
}
|
|
@@ -15618,23 +15741,23 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
|
15618
15741
|
continue;
|
|
15619
15742
|
if (!reference.digest)
|
|
15620
15743
|
return failure2("invalid_input", "document references require a byte digest");
|
|
15621
|
-
const target =
|
|
15622
|
-
if (target !== root && !target.startsWith(`${root}${
|
|
15744
|
+
const target = path19.resolve(root, reference.path);
|
|
15745
|
+
if (target !== root && !target.startsWith(`${root}${path19.sep}`))
|
|
15623
15746
|
return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
|
|
15624
15747
|
fields: [
|
|
15625
15748
|
{ path: "contentRefs.path", reason: `${reference.path} is outside the checkout` }
|
|
15626
15749
|
]
|
|
15627
15750
|
});
|
|
15628
15751
|
try {
|
|
15629
|
-
const below =
|
|
15752
|
+
const below = path19.relative(root, target);
|
|
15630
15753
|
let current = root;
|
|
15631
|
-
for (const segment of below.split(
|
|
15754
|
+
for (const segment of below.split(path19.sep)) {
|
|
15632
15755
|
if (!segment)
|
|
15633
15756
|
continue;
|
|
15634
|
-
current =
|
|
15635
|
-
const stat =
|
|
15636
|
-
const real =
|
|
15637
|
-
if (real !== root && !real.startsWith(`${root}${
|
|
15757
|
+
current = path19.join(current, segment);
|
|
15758
|
+
const stat = fs15.lstatSync(current);
|
|
15759
|
+
const real = fs15.realpathSync(current);
|
|
15760
|
+
if (real !== root && !real.startsWith(`${root}${path19.sep}`))
|
|
15638
15761
|
return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
|
|
15639
15762
|
fields: [
|
|
15640
15763
|
{
|
|
@@ -15650,7 +15773,7 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
|
15650
15773
|
if (current !== target && !stat.isDirectory())
|
|
15651
15774
|
return failure2("invalid_input", "document reference ancestor is not a directory");
|
|
15652
15775
|
}
|
|
15653
|
-
if (digestBytes(
|
|
15776
|
+
if (digestBytes(fs15.readFileSync(target)) !== reference.digest)
|
|
15654
15777
|
return failure2("permission_denied", "decision document bytes have changed");
|
|
15655
15778
|
} catch {
|
|
15656
15779
|
return failure2("invalid_input", "decision document is unavailable");
|
|
@@ -16232,19 +16355,19 @@ var exportDigest = (bundle) => sha256({
|
|
|
16232
16355
|
// packages/workit-core/src/core/route-intent.ts
|
|
16233
16356
|
import { spawnSync as spawnSync12 } from "node:child_process";
|
|
16234
16357
|
import { existsSync as existsSync7 } from "node:fs";
|
|
16235
|
-
import
|
|
16358
|
+
import path22 from "node:path";
|
|
16236
16359
|
|
|
16237
16360
|
// packages/workit-core/src/hooks/raw-git.ts
|
|
16238
16361
|
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
16239
|
-
import { createHash as
|
|
16240
|
-
import
|
|
16362
|
+
import { createHash as createHash15 } from "node:crypto";
|
|
16363
|
+
import fs17 from "node:fs";
|
|
16241
16364
|
import os4 from "node:os";
|
|
16242
|
-
import
|
|
16365
|
+
import path21 from "node:path";
|
|
16243
16366
|
|
|
16244
16367
|
// packages/workit-core/src/hooks/session-marker.ts
|
|
16245
|
-
import { createHash as
|
|
16246
|
-
import
|
|
16247
|
-
import
|
|
16368
|
+
import { createHash as createHash14 } from "node:crypto";
|
|
16369
|
+
import fs16 from "node:fs";
|
|
16370
|
+
import path20 from "node:path";
|
|
16248
16371
|
var sessionMarkerFile = (input, session, store) => {
|
|
16249
16372
|
let dir = store;
|
|
16250
16373
|
if (dir === undefined) {
|
|
@@ -16253,8 +16376,8 @@ var sessionMarkerFile = (input, session, store) => {
|
|
|
16253
16376
|
return null;
|
|
16254
16377
|
dir = location.dir;
|
|
16255
16378
|
}
|
|
16256
|
-
const name =
|
|
16257
|
-
return
|
|
16379
|
+
const name = createHash14("sha256").update(`${input.host}\x00${session}`).digest("hex").slice(0, 32);
|
|
16380
|
+
return path20.join(dir, "hooks", `skills-${name}.json`);
|
|
16258
16381
|
};
|
|
16259
16382
|
var list2 = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
16260
16383
|
var EMPTY = {
|
|
@@ -16267,7 +16390,7 @@ var EMPTY = {
|
|
|
16267
16390
|
};
|
|
16268
16391
|
var readRaw = (file) => {
|
|
16269
16392
|
try {
|
|
16270
|
-
return
|
|
16393
|
+
return fs16.readFileSync(file, "utf8");
|
|
16271
16394
|
} catch {
|
|
16272
16395
|
return "";
|
|
16273
16396
|
}
|
|
@@ -16289,13 +16412,13 @@ var parseMarker = (text) => {
|
|
|
16289
16412
|
};
|
|
16290
16413
|
var readSessionMarker = (file) => parseMarker(readRaw(file));
|
|
16291
16414
|
var writeAtomic = (file, marker) => {
|
|
16292
|
-
|
|
16415
|
+
fs16.mkdirSync(path20.dirname(file), { recursive: true });
|
|
16293
16416
|
const temp = `${file}.${process.pid}.${Math.random().toString(36).slice(2)}.tmp`;
|
|
16294
16417
|
try {
|
|
16295
|
-
|
|
16296
|
-
|
|
16418
|
+
fs16.writeFileSync(temp, JSON.stringify(marker));
|
|
16419
|
+
fs16.renameSync(temp, file);
|
|
16297
16420
|
} catch (error) {
|
|
16298
|
-
|
|
16421
|
+
fs16.rmSync(temp, { force: true });
|
|
16299
16422
|
throw error;
|
|
16300
16423
|
}
|
|
16301
16424
|
};
|
|
@@ -16837,14 +16960,14 @@ var GIT_CONFIG_ENV = /^GIT_(?:CONFIG\w*|DIR|COMMON_DIR|WORK_TREE)$/;
|
|
|
16837
16960
|
var ASSIGNMENT = /^([A-Za-z_]\w*)=([\s\S]*)$/;
|
|
16838
16961
|
var MAX_DEPTH = 4;
|
|
16839
16962
|
var MAX_EXPANSIONS = 16;
|
|
16840
|
-
var isAbsolute = (value) =>
|
|
16963
|
+
var isAbsolute = (value) => path21.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\");
|
|
16841
16964
|
var HERE = /^(?:\$PWD|\$\{PWD\}|\$\(\s*pwd\s*\)|`pwd`|\$\(\s*git\s+rev-parse\s+--show-toplevel\s*\))(?=$|[\\/])/;
|
|
16842
16965
|
var joinDir = (base, raw) => {
|
|
16843
16966
|
const next = raw.replace(HERE, ".");
|
|
16844
16967
|
if (base === undefined || /[$`*?]/.test(next) || next === "-")
|
|
16845
16968
|
return;
|
|
16846
|
-
const expanded = next === "~" || next.startsWith("~/") ?
|
|
16847
|
-
return base === null || isAbsolute(expanded) ? expanded :
|
|
16969
|
+
const expanded = next === "~" || next.startsWith("~/") ? path21.join(os4.homedir(), next.slice(1)) : next;
|
|
16970
|
+
return base === null || isAbsolute(expanded) ? expanded : path21.join(base, expanded);
|
|
16848
16971
|
};
|
|
16849
16972
|
var rebase = (base, inner) => inner === null ? base : inner === undefined ? undefined : joinDir(base, inner);
|
|
16850
16973
|
var cdTarget = (words) => {
|
|
@@ -17702,7 +17825,7 @@ var repoAt = (dir) => {
|
|
|
17702
17825
|
return { location, dir, branch: resolveTaskKey(dir, location).branch };
|
|
17703
17826
|
};
|
|
17704
17827
|
var isWorkitWorkspace = (repo) => {
|
|
17705
|
-
if (
|
|
17828
|
+
if (fs17.existsSync(repo.location.dir))
|
|
17706
17829
|
return true;
|
|
17707
17830
|
try {
|
|
17708
17831
|
return resolveRuntimeWorkspaceVcs(repo.location.top ?? repo.dir) !== null;
|
|
@@ -17723,17 +17846,17 @@ var headSha2 = (repo) => {
|
|
|
17723
17846
|
if (!git || git.reftable)
|
|
17724
17847
|
return null;
|
|
17725
17848
|
try {
|
|
17726
|
-
const head =
|
|
17849
|
+
const head = fs17.readFileSync(path21.join(git.gitDir, "HEAD"), "utf8").trim();
|
|
17727
17850
|
if (/^[0-9a-f]{40,64}$/.test(head))
|
|
17728
17851
|
return head;
|
|
17729
17852
|
const ref = /^ref: (refs\/.+)$/.exec(head)?.[1];
|
|
17730
17853
|
if (!ref)
|
|
17731
17854
|
return null;
|
|
17732
|
-
const common =
|
|
17855
|
+
const common = path21.dirname(repo.location.dir);
|
|
17733
17856
|
try {
|
|
17734
|
-
return
|
|
17857
|
+
return fs17.readFileSync(path21.join(common, ref), "utf8").trim() || null;
|
|
17735
17858
|
} catch {}
|
|
17736
|
-
const packed =
|
|
17859
|
+
const packed = fs17.readFileSync(path21.join(common, "packed-refs"), "utf8");
|
|
17737
17860
|
return new RegExp(`^([0-9a-f]{40,64}) ${ref.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`, "m").exec(packed)?.[1] ?? null;
|
|
17738
17861
|
} catch {
|
|
17739
17862
|
return null;
|
|
@@ -17821,8 +17944,8 @@ var expandGitAliases = (root, invocation, cache = new Map, depth = 0) => {
|
|
|
17821
17944
|
const sub = invocation.args[0];
|
|
17822
17945
|
if (invocation.tool !== "git" || invocation.dir === undefined || !sub || sub.startsWith("-") || GIT_COMMANDS.has(sub) || depth >= MAX_DEPTH)
|
|
17823
17946
|
return [invocation];
|
|
17824
|
-
const dir =
|
|
17825
|
-
if (!
|
|
17947
|
+
const dir = path21.resolve(root, invocation.dir ?? ".");
|
|
17948
|
+
if (!fs17.existsSync(dir))
|
|
17826
17949
|
return [invocation];
|
|
17827
17950
|
const config = gitConfig(dir, invocation, cache);
|
|
17828
17951
|
const alias = configValue(config, `alias.${sub.toLowerCase()}`);
|
|
@@ -17844,11 +17967,11 @@ var expandGitAliases = (root, invocation, cache = new Map, depth = 0) => {
|
|
|
17844
17967
|
var normalizedUrl = (url, dir) => {
|
|
17845
17968
|
const trimmed = url.trim();
|
|
17846
17969
|
if (/^file:\/\//i.test(trimmed))
|
|
17847
|
-
return
|
|
17970
|
+
return path21.resolve(dir, trimmed.slice(7)).replace(/\/+$/, "").replace(/\.git$/, "");
|
|
17848
17971
|
const scheme = /^[a-z][a-z0-9+.-]*:\/\//i.exec(trimmed);
|
|
17849
17972
|
const scp = !scheme && /^(?:[^@/\\]+@)?[^/\\:]{2,}:/.test(trimmed);
|
|
17850
17973
|
if (!scheme && !scp)
|
|
17851
|
-
return
|
|
17974
|
+
return path21.resolve(dir, trimmed).replace(/\/+$/, "").replace(/\.git$/, "");
|
|
17852
17975
|
const value = scheme ? trimmed.slice(scheme[0].length).replace(/^[^@/]*@/, "").replace(/^([^/:]+):\d+(?=\/)/, "$1") : trimmed.replace(/^[^@/]*@/, "").replace(":", "/");
|
|
17853
17976
|
return value.toLowerCase().replace(/\/{2,}/g, "/").replace(/^www\./, "").replace(/\/+$/, "").replace(/\.git$/, "");
|
|
17854
17977
|
};
|
|
@@ -18071,7 +18194,7 @@ var actionsIn = (cwd, command, dialect, cache = new Map) => {
|
|
|
18071
18194
|
const out = [];
|
|
18072
18195
|
const repos = new Map;
|
|
18073
18196
|
const repoFor = (relative) => {
|
|
18074
|
-
const dir =
|
|
18197
|
+
const dir = path21.resolve(cwd, relative ?? ".");
|
|
18075
18198
|
if (!repos.has(dir)) {
|
|
18076
18199
|
const repo = repoAt(dir);
|
|
18077
18200
|
repos.set(dir, repo && isWorkitWorkspace(repo) ? repo : null);
|
|
@@ -18156,8 +18279,8 @@ var analysisDenial = (error) => ({
|
|
|
18156
18279
|
unblock: SPLIT_IT
|
|
18157
18280
|
});
|
|
18158
18281
|
var MARKER_TTL_SECONDS = 3600;
|
|
18159
|
-
var markerFile = (repo, session, key) =>
|
|
18160
|
-
var callKey = (toolUseId, command) => toolUseId ?? `cmd:${
|
|
18282
|
+
var markerFile = (repo, session, key) => path21.join(repo.location.dir, "hooks", `commit-${createHash15("sha256").update(`${session}\x00${key}`).digest("hex").slice(0, 32)}.json`);
|
|
18283
|
+
var callKey = (toolUseId, command) => toolUseId ?? `cmd:${createHash15("sha256").update(command).digest("hex")}`;
|
|
18161
18284
|
function noteRawCommit(input, command, key) {
|
|
18162
18285
|
try {
|
|
18163
18286
|
if (!input.session.id || !/\bcommit\b/.test(command))
|
|
@@ -18167,8 +18290,8 @@ function noteRawCommit(input, command, key) {
|
|
|
18167
18290
|
if (action.kind !== "commit")
|
|
18168
18291
|
continue;
|
|
18169
18292
|
const file = markerFile(repo, input.session.id, key);
|
|
18170
|
-
|
|
18171
|
-
|
|
18293
|
+
fs17.mkdirSync(path21.dirname(file), { recursive: true });
|
|
18294
|
+
fs17.writeFileSync(file, `${JSON.stringify({ head: headSha2(repo), at })}
|
|
18172
18295
|
`);
|
|
18173
18296
|
}
|
|
18174
18297
|
} catch {}
|
|
@@ -18191,11 +18314,11 @@ var headCommit = (dir) => {
|
|
|
18191
18314
|
var settle2 = (input, repo, file) => {
|
|
18192
18315
|
let marker;
|
|
18193
18316
|
try {
|
|
18194
|
-
marker = JSON.parse(
|
|
18317
|
+
marker = JSON.parse(fs17.readFileSync(file, "utf8"));
|
|
18195
18318
|
} catch {
|
|
18196
18319
|
return;
|
|
18197
18320
|
}
|
|
18198
|
-
|
|
18321
|
+
fs17.rmSync(file, { force: true });
|
|
18199
18322
|
const session = input.session.id;
|
|
18200
18323
|
const now = Date.now() / 1000;
|
|
18201
18324
|
if (typeof marker.at !== "number" || now - marker.at > MARKER_TTL_SECONDS)
|
|
@@ -18386,7 +18509,7 @@ var judgedDir = (root, dir) => {
|
|
|
18386
18509
|
return null;
|
|
18387
18510
|
if (dir === null)
|
|
18388
18511
|
return root;
|
|
18389
|
-
const resolved =
|
|
18512
|
+
const resolved = path22.resolve(root, dir);
|
|
18390
18513
|
return existsSync7(resolved) && inWorkitWorkspace(resolved) ? resolved : null;
|
|
18391
18514
|
};
|
|
18392
18515
|
var shellBranchPolicyViolation = (root, command, dialect = "posix") => {
|
|
@@ -18622,7 +18745,7 @@ var judgeInputSummary = (raw) => {
|
|
|
18622
18745
|
|
|
18623
18746
|
// packages/workit-core/src/autonomy.ts
|
|
18624
18747
|
import os5 from "node:os";
|
|
18625
|
-
import
|
|
18748
|
+
import path23 from "node:path";
|
|
18626
18749
|
|
|
18627
18750
|
// packages/workit-core/src/core/safe-write.ts
|
|
18628
18751
|
import {
|
|
@@ -18656,10 +18779,10 @@ var accountHome = () => {
|
|
|
18656
18779
|
}
|
|
18657
18780
|
};
|
|
18658
18781
|
var grantsHome = { resolve: accountHome };
|
|
18659
|
-
var grantsDir = () =>
|
|
18782
|
+
var grantsDir = () => path23.join(grantsHome.resolve(), ".config", "workit");
|
|
18660
18783
|
var grantsOverride = () => {
|
|
18661
|
-
const configured =
|
|
18662
|
-
return configured ===
|
|
18784
|
+
const configured = path23.resolve(resolveConfigDir());
|
|
18785
|
+
return configured === path23.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 ${path23.join(grantsDir(), "workspaces.json")}, so the D4 defaults apply`;
|
|
18663
18786
|
};
|
|
18664
18787
|
var GRANT_KINDS = ["push", "pr", "merge", "release", "rerun"];
|
|
18665
18788
|
var DEFAULT_GRANTS = Object.freeze({
|
|
@@ -20470,7 +20593,7 @@ class WorkitCore {
|
|
|
20470
20593
|
// packages/workit-core/src/core/repo-context.ts
|
|
20471
20594
|
import { spawnSync as spawnSync13 } from "node:child_process";
|
|
20472
20595
|
import { existsSync as existsSync8, readFileSync as readFileSync6, readdirSync as readdirSync4 } from "node:fs";
|
|
20473
|
-
import
|
|
20596
|
+
import path24 from "node:path";
|
|
20474
20597
|
var isSafeContextRange = (value) => value.length <= 4096 && (() => {
|
|
20475
20598
|
try {
|
|
20476
20599
|
gitRevisionParts(value);
|
|
@@ -20604,7 +20727,7 @@ var findPrTemplate = (cwd) => {
|
|
|
20604
20727
|
]) {
|
|
20605
20728
|
const parts = rel.split("/");
|
|
20606
20729
|
const base = parts[parts.length - 1];
|
|
20607
|
-
const dir = parts.length > 1 ?
|
|
20730
|
+
const dir = parts.length > 1 ? path24.join(cwd, ...parts.slice(0, -1)) : cwd;
|
|
20608
20731
|
const actual = probeCaseInsensitive(dir, base);
|
|
20609
20732
|
if (actual)
|
|
20610
20733
|
return [...parts.slice(0, -1), actual].join("/");
|
|
@@ -20635,7 +20758,7 @@ var diffStatForRange = (cwd, range) => {
|
|
|
20635
20758
|
return runGit(cwd, ["diff", "--stat", "--"]).stdout;
|
|
20636
20759
|
};
|
|
20637
20760
|
var packageScripts = (cwd, keys) => {
|
|
20638
|
-
const pkgPath =
|
|
20761
|
+
const pkgPath = path24.join(cwd, "package.json");
|
|
20639
20762
|
if (!existsSync8(pkgPath))
|
|
20640
20763
|
return [];
|
|
20641
20764
|
try {
|
|
@@ -20661,9 +20784,9 @@ var documentationFiles = (cwd) => {
|
|
|
20661
20784
|
if (entry.isDirectory()) {
|
|
20662
20785
|
if (excluded.has(entry.name))
|
|
20663
20786
|
continue;
|
|
20664
|
-
walk(
|
|
20787
|
+
walk(path24.join(dir, entry.name), depth + 1);
|
|
20665
20788
|
} else if (entry.isFile() && (entry.name === "README.md" || entry.name.endsWith(".md"))) {
|
|
20666
|
-
matches.push("./" +
|
|
20789
|
+
matches.push("./" + path24.relative(cwd, path24.join(dir, entry.name)).replaceAll("\\", "/"));
|
|
20667
20790
|
}
|
|
20668
20791
|
}
|
|
20669
20792
|
};
|
|
@@ -20679,7 +20802,7 @@ var readTrimmed2 = (file, maxLines) => {
|
|
|
20679
20802
|
`);
|
|
20680
20803
|
};
|
|
20681
20804
|
function prReadyContext(root, range) {
|
|
20682
|
-
const cwd =
|
|
20805
|
+
const cwd = path24.resolve(repoRoot(root));
|
|
20683
20806
|
if (range !== undefined && !isResolvableContextRange(cwd, range))
|
|
20684
20807
|
return invalidRange(cwd);
|
|
20685
20808
|
let stdout = "";
|
|
@@ -20737,7 +20860,7 @@ ${status.stderr}` : "");
|
|
|
20737
20860
|
stdout += `template_path: ${template}
|
|
20738
20861
|
|
|
20739
20862
|
`;
|
|
20740
|
-
stdout += readTrimmed2(
|
|
20863
|
+
stdout += readTrimmed2(path24.join(cwd, template), 220);
|
|
20741
20864
|
} else {
|
|
20742
20865
|
stdout += `template_path: none
|
|
20743
20866
|
|
|
@@ -20747,7 +20870,7 @@ ${status.stderr}` : "");
|
|
|
20747
20870
|
stdout += `
|
|
20748
20871
|
`;
|
|
20749
20872
|
stdout += printSection("Recent Validation Signals");
|
|
20750
|
-
if (existsSync8(
|
|
20873
|
+
if (existsSync8(path24.join(cwd, "package.json"))) {
|
|
20751
20874
|
stdout += `package.json detected. Common scripts:
|
|
20752
20875
|
`;
|
|
20753
20876
|
const found = packageScripts(cwd, ["lint", "format:check", "test", "build"]);
|
|
@@ -20756,7 +20879,7 @@ ${status.stderr}` : "");
|
|
|
20756
20879
|
`) + `
|
|
20757
20880
|
`;
|
|
20758
20881
|
}
|
|
20759
|
-
if (existsSync8(
|
|
20882
|
+
if (existsSync8(path24.join(cwd, "Cargo.toml")) || existsSync8(path24.join(cwd, "src-tauri/Cargo.toml"))) {
|
|
20760
20883
|
stdout += `Rust project detected.
|
|
20761
20884
|
`;
|
|
20762
20885
|
}
|
|
@@ -20789,7 +20912,7 @@ var CHANGELOG_RULES = `- Use an [Unreleased] section.
|
|
|
20789
20912
|
- Apply with the host-native editor, preserving the repository changelog conventions.
|
|
20790
20913
|
- If Unreleased already has duplicate category headings, normalize_only first.`;
|
|
20791
20914
|
function changelogContext(root, range) {
|
|
20792
|
-
const cwd =
|
|
20915
|
+
const cwd = path24.resolve(repoRoot(root));
|
|
20793
20916
|
if (range !== undefined && !isResolvableContextRange(cwd, range))
|
|
20794
20917
|
return invalidRange(cwd);
|
|
20795
20918
|
const resolvedRange = rangeArgOrDefault(range, cwd);
|
|
@@ -20807,7 +20930,7 @@ function changelogContext(root, range) {
|
|
|
20807
20930
|
stdout += CHANGELOG_RULES + `
|
|
20808
20931
|
`;
|
|
20809
20932
|
stdout += printSection("Existing CHANGELOG.md");
|
|
20810
|
-
const changelogPath =
|
|
20933
|
+
const changelogPath = path24.join(cwd, "CHANGELOG.md");
|
|
20811
20934
|
if (existsSync8(changelogPath)) {
|
|
20812
20935
|
stdout += readTrimmed2(changelogPath, 260) + `
|
|
20813
20936
|
`;
|
|
@@ -20827,7 +20950,7 @@ function changelogContext(root, range) {
|
|
|
20827
20950
|
return { stdout, stderr: "", exitCode: 0, cwd };
|
|
20828
20951
|
}
|
|
20829
20952
|
function docsRefreshContext(root, range) {
|
|
20830
|
-
const cwd =
|
|
20953
|
+
const cwd = path24.resolve(repoRoot(root));
|
|
20831
20954
|
if (range !== undefined && !isResolvableContextRange(cwd, range))
|
|
20832
20955
|
return invalidRange(cwd);
|
|
20833
20956
|
const resolvedRange = rangeArgOrDefault(range, cwd);
|
|
@@ -20849,7 +20972,7 @@ function docsRefreshContext(root, range) {
|
|
|
20849
20972
|
`) + `
|
|
20850
20973
|
`;
|
|
20851
20974
|
stdout += printSection("README Preview");
|
|
20852
|
-
const readme =
|
|
20975
|
+
const readme = path24.join(cwd, "README.md");
|
|
20853
20976
|
if (existsSync8(readme)) {
|
|
20854
20977
|
stdout += readTrimmed2(readme, 220) + `
|
|
20855
20978
|
`;
|
|
@@ -20858,7 +20981,7 @@ function docsRefreshContext(root, range) {
|
|
|
20858
20981
|
`;
|
|
20859
20982
|
}
|
|
20860
20983
|
stdout += printSection("Package Scripts");
|
|
20861
|
-
const pkgPath =
|
|
20984
|
+
const pkgPath = path24.join(cwd, "package.json");
|
|
20862
20985
|
if (existsSync8(pkgPath)) {
|
|
20863
20986
|
try {
|
|
20864
20987
|
const pkg = JSON.parse(readFileSync6(pkgPath, "utf8"));
|
|
@@ -20872,7 +20995,7 @@ function docsRefreshContext(root, range) {
|
|
|
20872
20995
|
return { stdout, stderr: "", exitCode: 0, cwd };
|
|
20873
20996
|
}
|
|
20874
20997
|
function releaseNotesContext(root, rangeOrTag) {
|
|
20875
|
-
const cwd =
|
|
20998
|
+
const cwd = path24.resolve(repoRoot(root));
|
|
20876
20999
|
if (!rangeOrTag) {
|
|
20877
21000
|
return { stdout: "", stderr: `ERROR: release tag or range required
|
|
20878
21001
|
`, exitCode: 1, cwd };
|
|
@@ -20910,7 +21033,7 @@ function releaseNotesContext(root, rangeOrTag) {
|
|
|
20910
21033
|
`;
|
|
20911
21034
|
stdout += printSection("Existing Release Files");
|
|
20912
21035
|
for (const rel of ["CHANGELOG.md", "RELEASE_NOTES.md", ".github/releases.md"]) {
|
|
20913
|
-
if (existsSync8(
|
|
21036
|
+
if (existsSync8(path24.join(cwd, rel)))
|
|
20914
21037
|
stdout += rel + `
|
|
20915
21038
|
`;
|
|
20916
21039
|
}
|
|
@@ -20941,8 +21064,8 @@ function releaseNotesContext(root, rangeOrTag) {
|
|
|
20941
21064
|
import { spawnSync as spawnSync15 } from "node:child_process";
|
|
20942
21065
|
|
|
20943
21066
|
// packages/workit-core/src/core/pr-create.ts
|
|
20944
|
-
import
|
|
20945
|
-
import
|
|
21067
|
+
import fs18 from "node:fs";
|
|
21068
|
+
import path25 from "node:path";
|
|
20946
21069
|
import { spawnSync as spawnSync14 } from "node:child_process";
|
|
20947
21070
|
import { pathToFileURL } from "node:url";
|
|
20948
21071
|
// packages/workit-core/src/forge/pr-body.ts
|
|
@@ -20954,13 +21077,13 @@ function parseGhIssue(value) {
|
|
|
20954
21077
|
// packages/workit-core/src/core/pr-create.ts
|
|
20955
21078
|
function whichOnPath(tool) {
|
|
20956
21079
|
const names = process.platform === "win32" ? [tool, `${tool}.exe`, `${tool}.cmd`] : [tool];
|
|
20957
|
-
for (const dir of (process.env.PATH ?? "").split(
|
|
21080
|
+
for (const dir of (process.env.PATH ?? "").split(path25.delimiter)) {
|
|
20958
21081
|
if (!dir)
|
|
20959
21082
|
continue;
|
|
20960
21083
|
for (const name of names) {
|
|
20961
|
-
const candidate =
|
|
21084
|
+
const candidate = path25.join(dir, name);
|
|
20962
21085
|
try {
|
|
20963
|
-
|
|
21086
|
+
fs18.accessSync(candidate, fs18.constants.X_OK);
|
|
20964
21087
|
return candidate;
|
|
20965
21088
|
} catch {}
|
|
20966
21089
|
}
|
|
@@ -20980,7 +21103,7 @@ var pushRemote = (cwd) => {
|
|
|
20980
21103
|
};
|
|
20981
21104
|
var safePushUrl = (remote) => {
|
|
20982
21105
|
const raw = remote.trim();
|
|
20983
|
-
if (
|
|
21106
|
+
if (path25.isAbsolute(raw))
|
|
20984
21107
|
return pathToFileURL(raw).href;
|
|
20985
21108
|
if (!raw.includes("://")) {
|
|
20986
21109
|
const scp = /^(?:([^@\s]+)@)?([^:]+):(.+)$/u.exec(raw);
|
|
@@ -21111,8 +21234,8 @@ var fetchGitLabIssueBody = async (ref, root, deps = {}) => {
|
|
|
21111
21234
|
};
|
|
21112
21235
|
|
|
21113
21236
|
// packages/workit-core/src/core/youtrack.ts
|
|
21114
|
-
import
|
|
21115
|
-
import
|
|
21237
|
+
import fs19 from "node:fs";
|
|
21238
|
+
import path26 from "node:path";
|
|
21116
21239
|
|
|
21117
21240
|
// packages/workit-core/src/core/templates.ts
|
|
21118
21241
|
var repoRoot2 = assetRoot();
|
|
@@ -21125,22 +21248,22 @@ var resolveWorkspaceRoot = (explicit) => explicit || process.cwd();
|
|
|
21125
21248
|
// packages/workit-core/src/core/youtrack.ts
|
|
21126
21249
|
var ISSUE_RE = /^[A-Z]+-\d+$/;
|
|
21127
21250
|
var TOKEN_PLACEHOLDER = "YOUR_TOKEN_HERE";
|
|
21128
|
-
var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ??
|
|
21129
|
-
var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ??
|
|
21251
|
+
var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path26.join(configDir(), "youtrack.json");
|
|
21252
|
+
var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path26.join(resolveConfigDir(), "youtrack.json");
|
|
21130
21253
|
var youTrackTokenModeOk = (p) => {
|
|
21131
21254
|
if (process.platform === "win32")
|
|
21132
21255
|
return true;
|
|
21133
|
-
const mode =
|
|
21256
|
+
const mode = fs19.statSync(p).mode & 511;
|
|
21134
21257
|
return mode === 384;
|
|
21135
21258
|
};
|
|
21136
21259
|
function readYouTrackConfig(required) {
|
|
21137
21260
|
const cfgPath = youTrackConfigPath();
|
|
21138
|
-
if (!
|
|
21261
|
+
if (!fs19.existsSync(cfgPath)) {
|
|
21139
21262
|
return required ? { error: "ERROR: missing youtrack.json", path: cfgPath } : { config: {}, path: cfgPath };
|
|
21140
21263
|
}
|
|
21141
21264
|
let parsed;
|
|
21142
21265
|
try {
|
|
21143
|
-
parsed = JSON.parse(
|
|
21266
|
+
parsed = JSON.parse(fs19.readFileSync(cfgPath, "utf8"));
|
|
21144
21267
|
} catch {
|
|
21145
21268
|
return { error: `${cfgPath} is not valid JSON`, path: cfgPath };
|
|
21146
21269
|
}
|
|
@@ -21151,11 +21274,11 @@ function readYouTrackConfig(required) {
|
|
|
21151
21274
|
}
|
|
21152
21275
|
var readYouTrackContextConfig = () => {
|
|
21153
21276
|
const cfgPath = youTrackReadOnlyConfigPath();
|
|
21154
|
-
if (!
|
|
21277
|
+
if (!fs19.existsSync(cfgPath))
|
|
21155
21278
|
return { data: {} };
|
|
21156
21279
|
let parsed;
|
|
21157
21280
|
try {
|
|
21158
|
-
parsed = JSON.parse(
|
|
21281
|
+
parsed = JSON.parse(fs19.readFileSync(cfgPath, "utf8"));
|
|
21159
21282
|
} catch {
|
|
21160
21283
|
return { error: "YouTrack configuration is unavailable" };
|
|
21161
21284
|
}
|
|
@@ -21194,12 +21317,12 @@ var youTrackToken = () => {
|
|
|
21194
21317
|
if ("error" in loaded)
|
|
21195
21318
|
return loaded;
|
|
21196
21319
|
const tokenFile = String(loaded.config.tokenFile ?? "");
|
|
21197
|
-
const tokenPath = tokenFile ?
|
|
21198
|
-
if (!tokenPath || !
|
|
21320
|
+
const tokenPath = tokenFile ? path26.isAbsolute(tokenFile) ? path26.resolve(tokenFile) : path26.resolve(process.cwd(), tokenFile) : "";
|
|
21321
|
+
if (!tokenPath || !fs19.existsSync(tokenPath))
|
|
21199
21322
|
return { error: "missing youtrack.token" };
|
|
21200
21323
|
if (!youTrackTokenModeOk(tokenPath))
|
|
21201
21324
|
return { error: "youtrack.token mode must be 0600" };
|
|
21202
|
-
const token =
|
|
21325
|
+
const token = fs19.readFileSync(tokenPath, "utf8").trim();
|
|
21203
21326
|
if (!token)
|
|
21204
21327
|
return { error: "empty token file" };
|
|
21205
21328
|
if (token === TOKEN_PLACEHOLDER || token.startsWith(TOKEN_PLACEHOLDER)) {
|
|
@@ -21245,7 +21368,7 @@ function youTrackTokenCreateUrl() {
|
|
|
21245
21368
|
const desc = String(defaults.description ?? "OpenCode workit — /wk-issue-update and /wk-meetings");
|
|
21246
21369
|
const scopes = Array.isArray(defaults.scopes) ? defaults.scopes : ["YouTrack"];
|
|
21247
21370
|
const base = String(config.baseUrl ?? "").replace(/\/+$/, "");
|
|
21248
|
-
const tokenFile = String(config.tokenFile ??
|
|
21371
|
+
const tokenFile = String(config.tokenFile ?? path26.join(path26.dirname(loaded.path), "youtrack.token"));
|
|
21249
21372
|
const tab = String(defaults.profileTab ?? "account-security");
|
|
21250
21373
|
const createUrl = base ? `${base}/users/me?${new URLSearchParams({ tab })}` : null;
|
|
21251
21374
|
const docsUrl = "https://www.jetbrains.com/help/youtrack/cloud/manage-permanent-token.html";
|
|
@@ -21254,7 +21377,7 @@ function youTrackTokenCreateUrl() {
|
|
|
21254
21377
|
tokenName: name,
|
|
21255
21378
|
tokenDescription: desc,
|
|
21256
21379
|
scopes,
|
|
21257
|
-
tokenFile:
|
|
21380
|
+
tokenFile: path26.resolve(tokenFile),
|
|
21258
21381
|
createUrl,
|
|
21259
21382
|
docsUrl,
|
|
21260
21383
|
prefillSupported: false,
|
|
@@ -21300,9 +21423,9 @@ function resolveYouTrackFromPaths(spec_path, plan_path, workspace_root) {
|
|
|
21300
21423
|
} catch {
|
|
21301
21424
|
continue;
|
|
21302
21425
|
}
|
|
21303
|
-
if (!
|
|
21426
|
+
if (!fs19.existsSync(full))
|
|
21304
21427
|
continue;
|
|
21305
|
-
const text =
|
|
21428
|
+
const text = fs19.readFileSync(full, "utf8");
|
|
21306
21429
|
const m = text.match(/^\*\*YouTrack:\*\*\s*`?([A-Z]+-\d+)`?/m);
|
|
21307
21430
|
if (m)
|
|
21308
21431
|
return m[1];
|
|
@@ -21594,15 +21717,15 @@ function resolveGitRevision(root, value) {
|
|
|
21594
21717
|
}
|
|
21595
21718
|
function resolveInside(root, candidate) {
|
|
21596
21719
|
const base = realpathSync5(root);
|
|
21597
|
-
const target =
|
|
21598
|
-
if (target !== base && !target.startsWith(base +
|
|
21720
|
+
const target = path27.resolve(base, candidate);
|
|
21721
|
+
if (target !== base && !target.startsWith(base + path27.sep)) {
|
|
21599
21722
|
throw new Error("path must stay inside repository root");
|
|
21600
21723
|
}
|
|
21601
21724
|
let ancestor = target;
|
|
21602
21725
|
while (!existsSync9(ancestor))
|
|
21603
|
-
ancestor =
|
|
21726
|
+
ancestor = path27.dirname(ancestor);
|
|
21604
21727
|
const canonicalAncestor = realpathSync5(ancestor);
|
|
21605
|
-
if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base +
|
|
21728
|
+
if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base + path27.sep)) {
|
|
21606
21729
|
throw new Error("path must stay inside repository root");
|
|
21607
21730
|
}
|
|
21608
21731
|
return target;
|
|
@@ -21646,7 +21769,7 @@ var capabilitiesFor = (descriptor, observed = {}) => descriptor.capabilities.map
|
|
|
21646
21769
|
};
|
|
21647
21770
|
});
|
|
21648
21771
|
// packages/workit-core/src/hooks/context.ts
|
|
21649
|
-
import
|
|
21772
|
+
import path28 from "node:path";
|
|
21650
21773
|
var MIGRATION_PENDING_NOTE = "workit migration pending — run `workit task status`";
|
|
21651
21774
|
var migrationPending = (result) => !result.ok && result.code === "needs_input" && (result.error ?? "").startsWith(MIGRATION_PENDING);
|
|
21652
21775
|
var boundTo = (entry, session) => entry.sessions.some((item) => item.host === session.host && item.handle === session.handle);
|
|
@@ -21734,7 +21857,7 @@ function entryCompactContext(store, entry, session, context) {
|
|
|
21734
21857
|
current: () => recentSignal(store.root)
|
|
21735
21858
|
};
|
|
21736
21859
|
const observed = task?.data.evidence.some(isObservedCheck) ?? false;
|
|
21737
|
-
const files = (task?.data.decisions ?? []).flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [
|
|
21860
|
+
const files = (task?.data.decisions ?? []).flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [path28.resolve(store.root, ref.path)] : []));
|
|
21738
21861
|
const observedFiles = filesKey(files);
|
|
21739
21862
|
const compact = new WorkitCore(store, context).compactContext(entry?.id ?? null, freshness, origin && { origin: origin.origin, taskId: origin.entry.id });
|
|
21740
21863
|
if (!compact.ok || !compact.data)
|
|
@@ -21816,13 +21939,13 @@ var isAllowedWorkitCommand = (command) => {
|
|
|
21816
21939
|
return segments.length > 0 && segments.every((s) => !s.unanalyzable && !s.group && !s.subs?.length && !s.stdin?.length && !s.redirects.length && isAllowedWorkitCall(s.words, s.expands));
|
|
21817
21940
|
};
|
|
21818
21941
|
// packages/workit-core/src/core/heavy-rules.ts
|
|
21819
|
-
import
|
|
21942
|
+
import fs20 from "node:fs";
|
|
21820
21943
|
import os6 from "node:os";
|
|
21821
|
-
import
|
|
21944
|
+
import path29 from "node:path";
|
|
21822
21945
|
var EMPTY2 = () => ({ deny: [], allow: [] });
|
|
21823
21946
|
var readText2 = (file) => {
|
|
21824
21947
|
try {
|
|
21825
|
-
return
|
|
21948
|
+
return fs20.readFileSync(file, "utf8");
|
|
21826
21949
|
} catch (error) {
|
|
21827
21950
|
if (error.code === "ENOENT")
|
|
21828
21951
|
return null;
|
|
@@ -21859,19 +21982,19 @@ function parseJsonc(text) {
|
|
|
21859
21982
|
return JSON.parse(out.replace(/,(\s*[}\]])/gu, "$1"));
|
|
21860
21983
|
}
|
|
21861
21984
|
function gitTop(cwd) {
|
|
21862
|
-
for (let dir =
|
|
21863
|
-
if (
|
|
21985
|
+
for (let dir = path29.resolve(cwd);; dir = path29.dirname(dir)) {
|
|
21986
|
+
if (fs20.existsSync(path29.join(dir, ".git")))
|
|
21864
21987
|
return dir;
|
|
21865
|
-
if (
|
|
21988
|
+
if (path29.dirname(dir) === dir)
|
|
21866
21989
|
return null;
|
|
21867
21990
|
}
|
|
21868
21991
|
}
|
|
21869
21992
|
var projectDirs = (cwd) => {
|
|
21870
21993
|
const top = gitTop(cwd);
|
|
21871
21994
|
const dirs = [];
|
|
21872
|
-
for (let dir =
|
|
21995
|
+
for (let dir = path29.resolve(cwd);; dir = path29.dirname(dir)) {
|
|
21873
21996
|
dirs.push(dir);
|
|
21874
|
-
if (!top || dir === top ||
|
|
21997
|
+
if (!top || dir === top || path29.dirname(dir) === dir)
|
|
21875
21998
|
return dirs;
|
|
21876
21999
|
}
|
|
21877
22000
|
};
|
|
@@ -21883,12 +22006,12 @@ var CLAUDE_MANAGED = {
|
|
|
21883
22006
|
};
|
|
21884
22007
|
function claudeSettingsFiles(cwd, env, platform = process.platform) {
|
|
21885
22008
|
const project = env.CLAUDE_PROJECT_DIR || gitTop(cwd) || cwd;
|
|
21886
|
-
const user = env.CLAUDE_CONFIG_DIR ||
|
|
22009
|
+
const user = env.CLAUDE_CONFIG_DIR || path29.join(homeOf(env), ".claude");
|
|
21887
22010
|
return [
|
|
21888
22011
|
...CLAUDE_MANAGED[platform] ? [CLAUDE_MANAGED[platform]] : [],
|
|
21889
|
-
|
|
21890
|
-
|
|
21891
|
-
|
|
22012
|
+
path29.join(user, "settings.json"),
|
|
22013
|
+
path29.join(project, ".claude", "settings.json"),
|
|
22014
|
+
path29.join(project, ".claude", "settings.local.json")
|
|
21892
22015
|
];
|
|
21893
22016
|
}
|
|
21894
22017
|
var bashPattern = (entry) => {
|
|
@@ -21978,10 +22101,10 @@ var opencodeConfig = (value, rules) => {
|
|
|
21978
22101
|
function opencodeRules(cwd, env = process.env) {
|
|
21979
22102
|
const rules = EMPTY2();
|
|
21980
22103
|
try {
|
|
21981
|
-
const config = env.XDG_CONFIG_HOME ||
|
|
22104
|
+
const config = env.XDG_CONFIG_HOME || path29.join(homeOf(env), ".config");
|
|
21982
22105
|
const files = [
|
|
21983
|
-
...OPENCODE_NAMES.map((name) =>
|
|
21984
|
-
...projectDirs(cwd).flatMap((dir) => OPENCODE_NAMES.flatMap((name) => [
|
|
22106
|
+
...OPENCODE_NAMES.map((name) => path29.join(config, "opencode", name)),
|
|
22107
|
+
...projectDirs(cwd).flatMap((dir) => OPENCODE_NAMES.flatMap((name) => [path29.join(dir, name), path29.join(dir, ".opencode", name)])),
|
|
21985
22108
|
...env.OPENCODE_CONFIG ? [env.OPENCODE_CONFIG] : []
|
|
21986
22109
|
];
|
|
21987
22110
|
for (const file of files) {
|
|
@@ -22025,19 +22148,19 @@ var codexRule = (body) => {
|
|
|
22025
22148
|
function codexRules(cwd, env = process.env) {
|
|
22026
22149
|
const rules = EMPTY2();
|
|
22027
22150
|
try {
|
|
22028
|
-
const home = env.CODEX_HOME ||
|
|
22151
|
+
const home = env.CODEX_HOME || path29.join(homeOf(env), ".codex");
|
|
22029
22152
|
const top = gitTop(cwd) ?? cwd;
|
|
22030
|
-
for (const dir of [
|
|
22153
|
+
for (const dir of [path29.join(home, "rules"), path29.join(top, ".codex", "rules")]) {
|
|
22031
22154
|
let files;
|
|
22032
22155
|
try {
|
|
22033
|
-
files =
|
|
22156
|
+
files = fs20.readdirSync(dir).filter((name) => name.endsWith(".rules"));
|
|
22034
22157
|
} catch (error) {
|
|
22035
22158
|
if (error.code === "ENOENT")
|
|
22036
22159
|
continue;
|
|
22037
22160
|
return "unreadable";
|
|
22038
22161
|
}
|
|
22039
22162
|
for (const name of files) {
|
|
22040
|
-
const text = readText2(
|
|
22163
|
+
const text = readText2(path29.join(dir, name)) ?? "";
|
|
22041
22164
|
for (const part of text.split(/\bprefix_rule\s*\(/u).slice(1)) {
|
|
22042
22165
|
const rule = codexRule(part);
|
|
22043
22166
|
if (!rule)
|
|
@@ -22056,8 +22179,8 @@ function cursorRules(cwd, env = process.env) {
|
|
|
22056
22179
|
try {
|
|
22057
22180
|
const top = gitTop(cwd) ?? cwd;
|
|
22058
22181
|
for (const file of [
|
|
22059
|
-
|
|
22060
|
-
|
|
22182
|
+
path29.join(homeOf(env), ".cursor", "cli-config.json"),
|
|
22183
|
+
path29.join(top, ".cursor", "cli.json")
|
|
22061
22184
|
]) {
|
|
22062
22185
|
const text = readText2(file);
|
|
22063
22186
|
if (text === null)
|
|
@@ -22131,23 +22254,23 @@ function wrapAllowed(read, words, command, options = {}) {
|
|
|
22131
22254
|
}
|
|
22132
22255
|
|
|
22133
22256
|
// packages/workit-core/src/core/heavy.ts
|
|
22134
|
-
import
|
|
22257
|
+
import fs21 from "node:fs";
|
|
22135
22258
|
import os7 from "node:os";
|
|
22136
|
-
import
|
|
22259
|
+
import path30 from "node:path";
|
|
22137
22260
|
function stateDir(env, platform = process.platform) {
|
|
22138
22261
|
if (env.WORKFLOW_TOOLKIT_STATE)
|
|
22139
22262
|
return env.WORKFLOW_TOOLKIT_STATE;
|
|
22140
22263
|
if (env.XDG_STATE_HOME)
|
|
22141
|
-
return
|
|
22264
|
+
return path30.join(env.XDG_STATE_HOME, "workit");
|
|
22142
22265
|
const home = env.HOME || os7.homedir();
|
|
22143
22266
|
if (platform === "darwin")
|
|
22144
|
-
return
|
|
22267
|
+
return path30.join(home, "Library", "Application Support", "workit");
|
|
22145
22268
|
if (platform === "win32")
|
|
22146
|
-
return
|
|
22147
|
-
return
|
|
22269
|
+
return path30.join(env.LOCALAPPDATA ?? path30.join(home, "AppData", "Local"), "workit");
|
|
22270
|
+
return path30.join(home, ".local", "state", "workit");
|
|
22148
22271
|
}
|
|
22149
22272
|
var HEAVY_COMMANDS_FILE = "heavy-commands.json";
|
|
22150
|
-
var heavyCommandsFile = (env) =>
|
|
22273
|
+
var heavyCommandsFile = (env) => path30.join(stateDir(env), HEAVY_COMMANDS_FILE);
|
|
22151
22274
|
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;
|
|
22152
22275
|
var INFO_FLAGS = new Set(["--version", "-v", "-V", "--help", "-h", "help", "version"]);
|
|
22153
22276
|
var WATCH_FLAG = /^(?:--watch(?:All)?(?:=.*)?|-w|--serve)$/u;
|
|
@@ -22410,7 +22533,7 @@ function parsePattern(pattern) {
|
|
|
22410
22533
|
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]));
|
|
22411
22534
|
var readJson = (file) => {
|
|
22412
22535
|
try {
|
|
22413
|
-
return JSON.parse(
|
|
22536
|
+
return JSON.parse(fs21.readFileSync(file, "utf8"));
|
|
22414
22537
|
} catch {
|
|
22415
22538
|
return;
|
|
22416
22539
|
}
|
|
@@ -22422,7 +22545,7 @@ function machinePatterns(env) {
|
|
|
22422
22545
|
return isRecord5(value) ? stringList(value.patterns) : [];
|
|
22423
22546
|
}
|
|
22424
22547
|
function repoPatterns(cwd) {
|
|
22425
|
-
return repoHeavyCommands(gitTop(cwd) ??
|
|
22548
|
+
return repoHeavyCommands(gitTop(cwd) ?? path30.resolve(cwd));
|
|
22426
22549
|
}
|
|
22427
22550
|
function heavyLines(lines, options) {
|
|
22428
22551
|
const found = [];
|
|
@@ -22500,12 +22623,12 @@ function heavyPlan(command, options) {
|
|
|
22500
22623
|
}
|
|
22501
22624
|
function workitOnPath2(env = process.env) {
|
|
22502
22625
|
const names = process.platform === "win32" ? ["workit.exe", "workit.cmd", "workit"] : ["workit"];
|
|
22503
|
-
for (const dir of (env.PATH ?? "").split(
|
|
22626
|
+
for (const dir of (env.PATH ?? "").split(path30.delimiter))
|
|
22504
22627
|
for (const name of names) {
|
|
22505
22628
|
if (!dir)
|
|
22506
22629
|
continue;
|
|
22507
22630
|
try {
|
|
22508
|
-
|
|
22631
|
+
fs21.accessSync(path30.join(dir, name), fs21.constants.X_OK);
|
|
22509
22632
|
return true;
|
|
22510
22633
|
} catch {}
|
|
22511
22634
|
}
|
|
@@ -22522,41 +22645,41 @@ function leaseRewrite(command) {
|
|
|
22522
22645
|
}
|
|
22523
22646
|
|
|
22524
22647
|
// packages/workit-core/src/core/heavy-words.ts
|
|
22525
|
-
import
|
|
22648
|
+
import fs22 from "node:fs";
|
|
22526
22649
|
import os8 from "node:os";
|
|
22527
|
-
import
|
|
22650
|
+
import path31 from "node:path";
|
|
22528
22651
|
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(" "));
|
|
22529
22652
|
var wordsOf = (command) => command.split(/[\s;&|()<>`'"]+/u).map((word) => (word.split(/[\\/]/u).at(-1) ?? "").toLowerCase().replace(/\.(?:exe|cmd|bat)$/u, "")).filter(Boolean);
|
|
22530
22653
|
var stateDir2 = (env) => {
|
|
22531
22654
|
if (env.WORKFLOW_TOOLKIT_STATE)
|
|
22532
22655
|
return env.WORKFLOW_TOOLKIT_STATE;
|
|
22533
22656
|
if (env.XDG_STATE_HOME)
|
|
22534
|
-
return
|
|
22657
|
+
return path31.join(env.XDG_STATE_HOME, "workit");
|
|
22535
22658
|
const home = env.HOME || os8.homedir();
|
|
22536
22659
|
if (process.platform === "darwin")
|
|
22537
|
-
return
|
|
22660
|
+
return path31.join(home, "Library", "Application Support", "workit");
|
|
22538
22661
|
if (process.platform === "win32")
|
|
22539
|
-
return
|
|
22540
|
-
return
|
|
22662
|
+
return path31.join(env.LOCALAPPDATA ?? path31.join(home, "AppData", "Local"), "workit");
|
|
22663
|
+
return path31.join(home, ".local", "state", "workit");
|
|
22541
22664
|
};
|
|
22542
22665
|
var readJson2 = (file) => {
|
|
22543
22666
|
try {
|
|
22544
|
-
return JSON.parse(
|
|
22667
|
+
return JSON.parse(fs22.readFileSync(file, "utf8"));
|
|
22545
22668
|
} catch {
|
|
22546
22669
|
return;
|
|
22547
22670
|
}
|
|
22548
22671
|
};
|
|
22549
22672
|
var patternWords = (cwd, env) => {
|
|
22550
22673
|
const patterns = [];
|
|
22551
|
-
const machine = readJson2(
|
|
22674
|
+
const machine = readJson2(path31.join(stateDir2(env), "heavy-commands.json"));
|
|
22552
22675
|
if (Array.isArray(machine?.patterns))
|
|
22553
22676
|
patterns.push(...machine.patterns);
|
|
22554
|
-
for (let dir =
|
|
22555
|
-
if (
|
|
22677
|
+
for (let dir = path31.resolve(cwd);; dir = path31.dirname(dir)) {
|
|
22678
|
+
if (fs22.existsSync(path31.join(dir, ".git"))) {
|
|
22556
22679
|
patterns.push(...repoHeavyCommands(dir));
|
|
22557
22680
|
break;
|
|
22558
22681
|
}
|
|
22559
|
-
if (
|
|
22682
|
+
if (path31.dirname(dir) === dir)
|
|
22560
22683
|
break;
|
|
22561
22684
|
}
|
|
22562
22685
|
const words = new Set;
|
|
@@ -22617,14 +22740,14 @@ function heavyGate(cwd, command, options) {
|
|
|
22617
22740
|
// packages/workit-core/src/hooks/write-gate.ts
|
|
22618
22741
|
import { existsSync as existsSync10, realpathSync as realpathSync6 } from "node:fs";
|
|
22619
22742
|
import os10 from "node:os";
|
|
22620
|
-
import
|
|
22743
|
+
import path33 from "node:path";
|
|
22621
22744
|
|
|
22622
22745
|
// packages/workit-core/src/core/live-session.ts
|
|
22623
22746
|
import { spawnSync as spawnSync17 } from "node:child_process";
|
|
22624
|
-
import { createHash as
|
|
22625
|
-
import
|
|
22747
|
+
import { createHash as createHash16 } from "node:crypto";
|
|
22748
|
+
import fs23 from "node:fs";
|
|
22626
22749
|
import os9 from "node:os";
|
|
22627
|
-
import
|
|
22750
|
+
import path32 from "node:path";
|
|
22628
22751
|
var LIVE_SESSION_TTL_MS = 15 * 60000;
|
|
22629
22752
|
var HEARTBEAT_EVERY_MS = 30000;
|
|
22630
22753
|
var liveProbe = {
|
|
@@ -22645,9 +22768,9 @@ var processAlive = (pid) => {
|
|
|
22645
22768
|
var processInfo = (pid) => {
|
|
22646
22769
|
try {
|
|
22647
22770
|
if (liveProbe.platform === "linux") {
|
|
22648
|
-
const stat =
|
|
22771
|
+
const stat = fs23.readFileSync(`/proc/${pid}/stat`, "utf8");
|
|
22649
22772
|
const ppid = Number(stat.slice(stat.lastIndexOf(")") + 2).split(" ")[1]);
|
|
22650
|
-
const command =
|
|
22773
|
+
const command = fs23.readFileSync(`/proc/${pid}/cmdline`, "utf8").replaceAll("\x00", " ");
|
|
22651
22774
|
return Number.isInteger(ppid) ? { ppid, command: command.trim() } : null;
|
|
22652
22775
|
}
|
|
22653
22776
|
if (liveProbe.platform === "win32")
|
|
@@ -22698,35 +22821,35 @@ var liveOwner = (input, transport, env = process.env) => {
|
|
|
22698
22821
|
};
|
|
22699
22822
|
};
|
|
22700
22823
|
var checkoutOf = (target) => {
|
|
22701
|
-
let dir =
|
|
22702
|
-
while (!
|
|
22703
|
-
dir =
|
|
22704
|
-
if (
|
|
22705
|
-
dir =
|
|
22706
|
-
const parts = dir.split(
|
|
22824
|
+
let dir = path32.resolve(target);
|
|
22825
|
+
while (!fs23.existsSync(dir) && path32.dirname(dir) !== dir)
|
|
22826
|
+
dir = path32.dirname(dir);
|
|
22827
|
+
if (fs23.existsSync(dir) && !fs23.statSync(dir).isDirectory())
|
|
22828
|
+
dir = path32.dirname(dir);
|
|
22829
|
+
const parts = dir.split(path32.sep);
|
|
22707
22830
|
const dotGit = parts.lastIndexOf(".git");
|
|
22708
22831
|
if (dotGit > 0)
|
|
22709
|
-
dir = parts.slice(0, dotGit).join(
|
|
22832
|
+
dir = parts.slice(0, dotGit).join(path32.sep) || path32.sep;
|
|
22710
22833
|
const location = resolveStore(dir);
|
|
22711
22834
|
if (location instanceof Error || !location.shared || !location.top)
|
|
22712
22835
|
return null;
|
|
22713
22836
|
let top = location.top;
|
|
22714
22837
|
try {
|
|
22715
|
-
top =
|
|
22838
|
+
top = fs23.realpathSync.native(top);
|
|
22716
22839
|
} catch {}
|
|
22717
22840
|
return top;
|
|
22718
22841
|
};
|
|
22719
|
-
var markerFile2 = (top) =>
|
|
22842
|
+
var markerFile2 = (top) => path32.join(resolveStateDir(), "live-sessions", `${createHash16("sha256").update(checkoutKey(top)).digest("hex").slice(0, 32)}.json`);
|
|
22720
22843
|
var checkoutKey = (top, platform = process.platform) => {
|
|
22721
|
-
let key =
|
|
22844
|
+
let key = path32.resolve(top);
|
|
22722
22845
|
try {
|
|
22723
|
-
key =
|
|
22846
|
+
key = fs23.realpathSync.native(key);
|
|
22724
22847
|
} catch {}
|
|
22725
22848
|
return platform === "win32" ? key.replaceAll("/", "\\").toLowerCase() : key;
|
|
22726
22849
|
};
|
|
22727
22850
|
var readMarker = (file) => {
|
|
22728
22851
|
try {
|
|
22729
|
-
const value = JSON.parse(
|
|
22852
|
+
const value = JSON.parse(fs23.readFileSync(file, "utf8"));
|
|
22730
22853
|
if (value?.version !== 1 || typeof value.session !== "string" || typeof value.host !== "string" || typeof value.heartbeatAt !== "string" || Number.isNaN(Date.parse(value.heartbeatAt)))
|
|
22731
22854
|
return null;
|
|
22732
22855
|
return {
|
|
@@ -22813,10 +22936,10 @@ var claimLiveSession = (target, owner, deps = {}) => {
|
|
|
22813
22936
|
checkout,
|
|
22814
22937
|
heartbeatAt: now.toISOString()
|
|
22815
22938
|
};
|
|
22816
|
-
|
|
22939
|
+
fs23.mkdirSync(path32.dirname(file), { recursive: true });
|
|
22817
22940
|
const temp = `${file}.${process.pid}.tmp`;
|
|
22818
|
-
|
|
22819
|
-
|
|
22941
|
+
fs23.writeFileSync(temp, JSON.stringify(marker));
|
|
22942
|
+
fs23.renameSync(temp, file);
|
|
22820
22943
|
} catch {}
|
|
22821
22944
|
};
|
|
22822
22945
|
|
|
@@ -22825,22 +22948,22 @@ var NONE3 = { kind: "none" };
|
|
|
22825
22948
|
var CASE_INSENSITIVE = process.platform === "darwin" || process.platform === "win32";
|
|
22826
22949
|
var canonical2 = (file) => {
|
|
22827
22950
|
let rest = "";
|
|
22828
|
-
for (let dir =
|
|
22951
|
+
for (let dir = path33.resolve(file);; dir = path33.dirname(dir)) {
|
|
22829
22952
|
try {
|
|
22830
|
-
return
|
|
22953
|
+
return path33.join(realpathSync6.native(dir), rest);
|
|
22831
22954
|
} catch {
|
|
22832
|
-
if (
|
|
22833
|
-
return
|
|
22834
|
-
rest = rest ?
|
|
22955
|
+
if (path33.dirname(dir) === dir)
|
|
22956
|
+
return path33.resolve(file);
|
|
22957
|
+
rest = rest ? path33.join(path33.basename(dir), rest) : path33.basename(dir);
|
|
22835
22958
|
}
|
|
22836
22959
|
}
|
|
22837
22960
|
};
|
|
22838
22961
|
var exempt = (cwd, root, file, plans) => {
|
|
22839
22962
|
const fold = (value) => CASE_INSENSITIVE ? value.toLowerCase() : value;
|
|
22840
|
-
const relative =
|
|
22841
|
-
if (relative.startsWith("..") ||
|
|
22963
|
+
const relative = path33.relative(fold(canonical2(root)), fold(canonical2(path33.resolve(cwd, file))));
|
|
22964
|
+
if (relative.startsWith("..") || path33.isAbsolute(relative))
|
|
22842
22965
|
return true;
|
|
22843
|
-
const posix = relative.split(
|
|
22966
|
+
const posix = relative.split(path33.sep).join("/");
|
|
22844
22967
|
const segments = posix.split("/");
|
|
22845
22968
|
return /\.mdx?$/i.test(posix) || segments[0] === "docs" || segments.includes("plans") || [...plans].some((plan) => fold(plan) === posix);
|
|
22846
22969
|
};
|
|
@@ -23017,10 +23140,10 @@ var linkSources = (args, at) => {
|
|
|
23017
23140
|
const sources = names.filter((name, index) => into >= 0 ? name !== dest : index < names.length - 1 || names.length === 1);
|
|
23018
23141
|
const target = dest === undefined ? null : at(dest);
|
|
23019
23142
|
const symbolic = args.some((arg) => /^-[a-zA-Z]*s|^--symbolic$/.test(arg));
|
|
23020
|
-
const base = target === null ? null : into >= 0 || sources.length > 1 || existsSync10(target) || /[\\/]$/.test(dest ?? "") ? target :
|
|
23143
|
+
const base = target === null ? null : into >= 0 || sources.length > 1 || existsSync10(target) || /[\\/]$/.test(dest ?? "") ? target : path33.dirname(target);
|
|
23021
23144
|
return sources.flatMap((source) => {
|
|
23022
|
-
if (symbolic && base !== null && !
|
|
23023
|
-
return [
|
|
23145
|
+
if (symbolic && base !== null && !path33.isAbsolute(homeExpanded(source)))
|
|
23146
|
+
return [path33.resolve(base, source)];
|
|
23024
23147
|
const resolved = at(source);
|
|
23025
23148
|
return resolved ? [resolved] : [];
|
|
23026
23149
|
});
|
|
@@ -23049,7 +23172,7 @@ var shellWrites = (command, depth = 0) => {
|
|
|
23049
23172
|
return { writes: true, targets: unknown ? null : targets };
|
|
23050
23173
|
};
|
|
23051
23174
|
var cache2 = new Map;
|
|
23052
|
-
var planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(
|
|
23175
|
+
var planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(path33.resolve(root, file)) ?? "-").join("\x00");
|
|
23053
23176
|
var gateFor = (cwd) => {
|
|
23054
23177
|
const store = new TaskStore(cwd);
|
|
23055
23178
|
const listed = store.listTaskIndex();
|
|
@@ -23128,13 +23251,13 @@ var gitMutationDirs = (cwd, command, dialect) => {
|
|
|
23128
23251
|
return [];
|
|
23129
23252
|
if (sub === "stash" && ["list", "show"].includes(rest[0] ?? ""))
|
|
23130
23253
|
return [];
|
|
23131
|
-
return [
|
|
23254
|
+
return [path33.resolve(cwd, invocation.dir ?? ".")];
|
|
23132
23255
|
});
|
|
23133
23256
|
};
|
|
23134
23257
|
var CD2 = new Set(["cd", "chdir", "set-location", "sl"]);
|
|
23135
23258
|
var PUSHD2 = new Set(["pushd", "push-location"]);
|
|
23136
23259
|
var POPD2 = new Set(["popd", "pop-location"]);
|
|
23137
|
-
var UNKNOWN_DIR =
|
|
23260
|
+
var UNKNOWN_DIR = path33.resolve(path33.parse(process.cwd()).root, ".workit-unknown-dir");
|
|
23138
23261
|
var cdInto = (dir, words, strict = false) => {
|
|
23139
23262
|
const lost = strict ? UNKNOWN_DIR : undefined;
|
|
23140
23263
|
const named = words.slice(1).find((word) => !word.startsWith("-") || word === "-");
|
|
@@ -23143,7 +23266,7 @@ var cdInto = (dir, words, strict = false) => {
|
|
|
23143
23266
|
return lost;
|
|
23144
23267
|
if (dir === undefined)
|
|
23145
23268
|
return lost;
|
|
23146
|
-
return target === undefined ? os10.homedir() :
|
|
23269
|
+
return target === undefined ? os10.homedir() : path33.resolve(dir, target);
|
|
23147
23270
|
};
|
|
23148
23271
|
var quoteWord2 = (word) => /^[\w@%+=:,./-]+$/.test(word) ? word : `'${word.replaceAll("'", "'\\''")}'`;
|
|
23149
23272
|
var homeExpanded = (file) => {
|
|
@@ -23157,7 +23280,7 @@ var segmentTargets = (cwd, command, dialect, depth = 0, strict = false) => {
|
|
|
23157
23280
|
const groups = [];
|
|
23158
23281
|
const at = (file) => {
|
|
23159
23282
|
const home = homeExpanded(file);
|
|
23160
|
-
return
|
|
23283
|
+
return path33.isAbsolute(home) ? home : dir === undefined ? null : path33.resolve(dir, home);
|
|
23161
23284
|
};
|
|
23162
23285
|
for (const segment of segmentsOf(command, dialect)) {
|
|
23163
23286
|
if (segment.group === "open") {
|
|
@@ -23197,7 +23320,7 @@ var segmentTargets = (cwd, command, dialect, depth = 0, strict = false) => {
|
|
|
23197
23320
|
for (const file of opaque ?? []) {
|
|
23198
23321
|
const resolved = at(file);
|
|
23199
23322
|
if (resolved)
|
|
23200
|
-
targets.push(file === "." ?
|
|
23323
|
+
targets.push(file === "." ? path33.join(resolved, DIR_TARGET) : resolved);
|
|
23201
23324
|
}
|
|
23202
23325
|
const ln = words.findIndex((word) => /^ln$/i.test(word.split(/[\\/]/).at(-1) ?? ""));
|
|
23203
23326
|
if (ln >= 0 && words.slice(0, ln).every((word) => PREFIXES2.has(word)))
|
|
@@ -23212,7 +23335,7 @@ var segmentTargets = (cwd, command, dialect, depth = 0, strict = false) => {
|
|
|
23212
23335
|
const edits = editsOf(segment.words);
|
|
23213
23336
|
if (edits === null) {
|
|
23214
23337
|
if (dir !== undefined)
|
|
23215
|
-
targets.push(
|
|
23338
|
+
targets.push(path33.join(dir, DIR_TARGET));
|
|
23216
23339
|
} else
|
|
23217
23340
|
for (const file of edits) {
|
|
23218
23341
|
const resolved = at(file);
|
|
@@ -23223,7 +23346,7 @@ var segmentTargets = (cwd, command, dialect, depth = 0, strict = false) => {
|
|
|
23223
23346
|
for (const invocation of workitInvocations(segment.words.map(quoteWord2).join(" "), "posix")) {
|
|
23224
23347
|
const { at: runsIn, args } = workitCwd(dir, invocation);
|
|
23225
23348
|
if (args[0] === "git" && MUTATING_WORKIT_GIT.has(args[1] ?? "") && !inert(args.slice(2), ""))
|
|
23226
|
-
targets.push(
|
|
23349
|
+
targets.push(path33.join(runsIn, DIR_TARGET));
|
|
23227
23350
|
}
|
|
23228
23351
|
}
|
|
23229
23352
|
return targets;
|
|
@@ -23238,13 +23361,13 @@ var workitRunDir = (dir, words) => {
|
|
|
23238
23361
|
};
|
|
23239
23362
|
var workitCwd = (dir, args) => {
|
|
23240
23363
|
const { rest, cwd } = skipWorkitGlobals(args);
|
|
23241
|
-
return { at: cwd === null ? dir :
|
|
23364
|
+
return { at: cwd === null ? dir : path33.resolve(dir, homeExpanded(cwd)), args: rest };
|
|
23242
23365
|
};
|
|
23243
23366
|
var shellMutationTargets = (cwd, command, dialect = "posix", strict = false) => {
|
|
23244
23367
|
try {
|
|
23245
23368
|
return [
|
|
23246
23369
|
...segmentTargets(cwd, command, dialect, 0, strict),
|
|
23247
|
-
...gitMutationDirs(cwd, command, dialect).map((dir) =>
|
|
23370
|
+
...gitMutationDirs(cwd, command, dialect).map((dir) => path33.join(dir, DIR_TARGET))
|
|
23248
23371
|
];
|
|
23249
23372
|
} catch {
|
|
23250
23373
|
return [];
|
|
@@ -23281,7 +23404,7 @@ var liveDeny = ({ marker, checkout, ageMs, file }) => {
|
|
|
23281
23404
|
var guarded = (targets) => {
|
|
23282
23405
|
const seen = new Set;
|
|
23283
23406
|
return targets.filter((target) => {
|
|
23284
|
-
const dir =
|
|
23407
|
+
const dir = path33.dirname(target);
|
|
23285
23408
|
if (seen.has(dir))
|
|
23286
23409
|
return false;
|
|
23287
23410
|
seen.add(dir);
|
|
@@ -23302,7 +23425,7 @@ var claimAll = (owner, targets, deps) => {
|
|
|
23302
23425
|
for (const target of guarded(targets))
|
|
23303
23426
|
claimLiveSession(target, owner, deps);
|
|
23304
23427
|
};
|
|
23305
|
-
var liveTargets = (cwd, paths) => paths?.length ? paths.map((file) =>
|
|
23428
|
+
var liveTargets = (cwd, paths) => paths?.length ? paths.map((file) => path33.resolve(cwd, file)) : [path33.join(cwd, DIR_TARGET)];
|
|
23306
23429
|
var issuedTarget = (cwd, targets) => {
|
|
23307
23430
|
const state = resolveStateDir();
|
|
23308
23431
|
const found = targets.find((target) => underIssued(state, cwd, homeExpanded(target), process.platform, canonical2));
|
|
@@ -23310,7 +23433,7 @@ var issuedTarget = (cwd, targets) => {
|
|
|
23310
23433
|
};
|
|
23311
23434
|
var underIssued = (state, cwd, target, platform = process.platform, real = (file) => file) => {
|
|
23312
23435
|
const win = platform === "win32";
|
|
23313
|
-
const p = win ?
|
|
23436
|
+
const p = win ? path33.win32 : path33.posix;
|
|
23314
23437
|
const fold = (value) => win || platform === "darwin" ? value.toLowerCase() : value;
|
|
23315
23438
|
const named = win ? target.replace(/^\/([a-zA-Z])(?=\/|$)/, "$1:") : target;
|
|
23316
23439
|
const relative = p.relative(fold(real(p.resolve(state))), fold(real(p.resolve(cwd, named))));
|
|
@@ -23852,20 +23975,20 @@ var WRITE_TOOLS = new Set([
|
|
|
23852
23975
|
"writefile"
|
|
23853
23976
|
]);
|
|
23854
23977
|
// packages/workit-core/src/hooks/standing.ts
|
|
23855
|
-
import
|
|
23856
|
-
import
|
|
23978
|
+
import fs24 from "node:fs";
|
|
23979
|
+
import path34 from "node:path";
|
|
23857
23980
|
var readPlans = (store) => {
|
|
23858
|
-
const dir =
|
|
23981
|
+
const dir = path34.join(store, "fanouts");
|
|
23859
23982
|
let names;
|
|
23860
23983
|
try {
|
|
23861
|
-
names =
|
|
23984
|
+
names = fs24.readdirSync(dir).filter((name) => name.endsWith(".json"));
|
|
23862
23985
|
} catch {
|
|
23863
23986
|
return [];
|
|
23864
23987
|
}
|
|
23865
23988
|
const plans = [];
|
|
23866
23989
|
for (const name of names) {
|
|
23867
23990
|
try {
|
|
23868
|
-
const raw = JSON.parse(
|
|
23991
|
+
const raw = JSON.parse(fs24.readFileSync(path34.join(dir, name), "utf8"));
|
|
23869
23992
|
if (typeof raw.name !== "string" || !Array.isArray(raw.slices))
|
|
23870
23993
|
continue;
|
|
23871
23994
|
const texts = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string" && item !== "") : [];
|
|
@@ -24103,11 +24226,11 @@ var OPENCODE_DESCRIPTOR = {
|
|
|
24103
24226
|
]
|
|
24104
24227
|
};
|
|
24105
24228
|
// packages/workit-opencode/src/shared/init-apply.ts
|
|
24106
|
-
import
|
|
24229
|
+
import path39 from "node:path";
|
|
24107
24230
|
|
|
24108
24231
|
// packages/workit-core/src/core/gitignore.ts
|
|
24109
24232
|
import { existsSync as existsSync11, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "node:fs";
|
|
24110
|
-
import
|
|
24233
|
+
import path35 from "node:path";
|
|
24111
24234
|
var GITIGNORE_ENTRIES = [
|
|
24112
24235
|
"# workit: SDD working state (never commit)",
|
|
24113
24236
|
"docs/*/sdd/",
|
|
@@ -24127,7 +24250,7 @@ var GITIGNORE_ENTRIES = [
|
|
|
24127
24250
|
var ensureProjectGitignore = (workspaceRoot, confirmed) => {
|
|
24128
24251
|
if (!confirmed)
|
|
24129
24252
|
return { ok: false, error: "confirmed: true required" };
|
|
24130
|
-
const file =
|
|
24253
|
+
const file = path35.join(workspaceRoot, ".gitignore");
|
|
24131
24254
|
const existing = existsSync11(file) ? readFileSync7(file, "utf8") : "";
|
|
24132
24255
|
const existingLines = new Set(existing.split(`
|
|
24133
24256
|
`).map((l) => l.trim()).filter(Boolean));
|
|
@@ -24155,25 +24278,25 @@ var ensureProjectGitignore = (workspaceRoot, confirmed) => {
|
|
|
24155
24278
|
|
|
24156
24279
|
// packages/workit-core/src/core/hygiene.ts
|
|
24157
24280
|
import { existsSync as existsSync12, readFileSync as readFileSync8, readdirSync as readdirSync5, writeFileSync as writeFileSync5 } from "node:fs";
|
|
24158
|
-
import
|
|
24281
|
+
import path36 from "node:path";
|
|
24159
24282
|
var repoRoot3 = assetRoot();
|
|
24160
|
-
var templatesDir = () =>
|
|
24283
|
+
var templatesDir = () => path36.join(repoRoot3, "templates", "hygiene");
|
|
24161
24284
|
var packageJson = (root) => {
|
|
24162
|
-
if (!existsSync12(
|
|
24285
|
+
if (!existsSync12(path36.join(root, "package.json")))
|
|
24163
24286
|
return null;
|
|
24164
24287
|
try {
|
|
24165
|
-
return JSON.parse(readFileSync8(
|
|
24288
|
+
return JSON.parse(readFileSync8(path36.join(root, "package.json"), "utf8"));
|
|
24166
24289
|
} catch {
|
|
24167
24290
|
return null;
|
|
24168
24291
|
}
|
|
24169
24292
|
};
|
|
24170
24293
|
var isOpenSource = (root) => {
|
|
24171
|
-
if (existsSync12(
|
|
24294
|
+
if (existsSync12(path36.join(root, "LICENSE")))
|
|
24172
24295
|
return true;
|
|
24173
24296
|
const pkg = packageJson(root);
|
|
24174
24297
|
if (pkg && !pkg.private)
|
|
24175
24298
|
return true;
|
|
24176
|
-
return
|
|
24299
|
+
return path36.basename(root) === "workflow-toolkit";
|
|
24177
24300
|
};
|
|
24178
24301
|
var licenseHolder = (root) => {
|
|
24179
24302
|
const pkg = packageJson(root);
|
|
@@ -24196,13 +24319,13 @@ var planHygieneFiles = (root, opts = {}) => {
|
|
|
24196
24319
|
files.push("LICENSE", "CONTRIBUTING.md");
|
|
24197
24320
|
const planned = [];
|
|
24198
24321
|
for (const file of files) {
|
|
24199
|
-
if (existsSync12(
|
|
24322
|
+
if (existsSync12(path36.join(root, file)))
|
|
24200
24323
|
continue;
|
|
24201
|
-
const tpl =
|
|
24324
|
+
const tpl = path36.join(templatesDir(), file);
|
|
24202
24325
|
if (!existsSync12(tpl))
|
|
24203
24326
|
continue;
|
|
24204
|
-
const content = readFileSync8(tpl, "utf8").replace(/<PROJECT>/g,
|
|
24205
|
-
planned.push({ path:
|
|
24327
|
+
const content = readFileSync8(tpl, "utf8").replace(/<PROJECT>/g, path36.basename(root)).replace(/<YEAR>/g, String(new Date().getFullYear())).replace(/<HOLDER>\s*/g, licenseHolder(root));
|
|
24328
|
+
planned.push({ path: path36.join(root, file), content });
|
|
24206
24329
|
}
|
|
24207
24330
|
return planned;
|
|
24208
24331
|
};
|
|
@@ -24212,19 +24335,19 @@ var ensureHygieneFiles = (root, opts) => {
|
|
|
24212
24335
|
const created = [];
|
|
24213
24336
|
for (const planned of planHygieneFiles(root, opts)) {
|
|
24214
24337
|
writeFileSync5(planned.path, planned.content, "utf8");
|
|
24215
|
-
created.push(
|
|
24338
|
+
created.push(path36.basename(planned.path));
|
|
24216
24339
|
}
|
|
24217
24340
|
return { ok: true, created };
|
|
24218
24341
|
};
|
|
24219
24342
|
|
|
24220
24343
|
// packages/workit-core/src/core/init.ts
|
|
24221
|
-
import
|
|
24222
|
-
import
|
|
24344
|
+
import fs25 from "node:fs";
|
|
24345
|
+
import path38 from "node:path";
|
|
24223
24346
|
import { spawnSync as spawnSync19 } from "node:child_process";
|
|
24224
24347
|
|
|
24225
24348
|
// packages/workit-core/src/core/workspace-branch-policy.ts
|
|
24226
24349
|
import { mkdirSync as mkdirSync4, readFileSync as readFileSync9, renameSync as renameSync3, rmSync as rmSync2, writeFileSync as writeFileSync6 } from "node:fs";
|
|
24227
|
-
import
|
|
24350
|
+
import path37 from "node:path";
|
|
24228
24351
|
import { isDeepStrictEqual } from "node:util";
|
|
24229
24352
|
var readFileSafe = (p) => {
|
|
24230
24353
|
try {
|
|
@@ -24235,7 +24358,7 @@ var readFileSafe = (p) => {
|
|
|
24235
24358
|
};
|
|
24236
24359
|
function applyWorkspaceBranchPolicy(opts) {
|
|
24237
24360
|
const { workspace_root, env = process.env } = opts;
|
|
24238
|
-
const dir =
|
|
24361
|
+
const dir = path37.join(env.WORKFLOW_TOOLKIT_CONFIG ?? configDir());
|
|
24239
24362
|
const {
|
|
24240
24363
|
status,
|
|
24241
24364
|
path: wsPath,
|
|
@@ -24247,7 +24370,7 @@ function applyWorkspaceBranchPolicy(opts) {
|
|
|
24247
24370
|
if (status === "malformed" || status === "invalid")
|
|
24248
24371
|
return { ok: false, error: workspacesError ?? `invalid workspaces.json: ${wsPath}` };
|
|
24249
24372
|
const detection = detectBranchPolicy(workspace_root);
|
|
24250
|
-
const name = String(env.WORKFLOW_BP_NAME ??
|
|
24373
|
+
const name = String(env.WORKFLOW_BP_NAME ?? path37.basename(workspace_root));
|
|
24251
24374
|
const integration = env.WORKFLOW_BP_INTEGRATION ?? detection.integration;
|
|
24252
24375
|
const policy = {
|
|
24253
24376
|
preset: detection.preset,
|
|
@@ -24296,7 +24419,7 @@ function applyWorkspaceBranchPolicy(opts) {
|
|
|
24296
24419
|
ok: false,
|
|
24297
24420
|
error: `workspaces.json changed while applying the branch policy: ${wsPath}`
|
|
24298
24421
|
};
|
|
24299
|
-
mkdirSync4(
|
|
24422
|
+
mkdirSync4(path37.dirname(wsPath), { recursive: true });
|
|
24300
24423
|
const tmp = `${wsPath}.${process.pid}.tmp`;
|
|
24301
24424
|
try {
|
|
24302
24425
|
writeFileSync6(tmp, JSON.stringify({ ...document, workspaces: next }, null, 2) + `
|
|
@@ -24331,7 +24454,7 @@ function applyWorkspaceBranchPolicy(opts) {
|
|
|
24331
24454
|
var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE";
|
|
24332
24455
|
var readJson3 = (p) => {
|
|
24333
24456
|
try {
|
|
24334
|
-
const parsed = JSON.parse(
|
|
24457
|
+
const parsed = JSON.parse(fs25.readFileSync(p, "utf8"));
|
|
24335
24458
|
return isConfigObject(parsed) ? parsed : null;
|
|
24336
24459
|
} catch {
|
|
24337
24460
|
return null;
|
|
@@ -24361,7 +24484,7 @@ var youtrackJsonContent = (dir) => {
|
|
|
24361
24484
|
const meetingIssue = process.env.WORKFLOW_YT_MEETING_ISSUE;
|
|
24362
24485
|
return {
|
|
24363
24486
|
baseUrl: process.env.WORKFLOW_YT_BASE_URL ?? "https://youtrack.example.com",
|
|
24364
|
-
tokenFile: process.env.WORKFLOW_YT_TOKEN_FILE ??
|
|
24487
|
+
tokenFile: process.env.WORKFLOW_YT_TOKEN_FILE ?? path38.join(dir, "youtrack.token"),
|
|
24365
24488
|
...meetingIssue ? {
|
|
24366
24489
|
meetingIssue,
|
|
24367
24490
|
meetingIssues: { general: { issue: meetingIssue, label: "General meetings" } }
|
|
@@ -24391,19 +24514,19 @@ var vcsJsonContent = () => {
|
|
|
24391
24514
|
};
|
|
24392
24515
|
function initApplyData(action, env = process.env) {
|
|
24393
24516
|
const dir = String(env.WORKFLOW_TOOLKIT_CONFIG ?? configDir());
|
|
24394
|
-
|
|
24517
|
+
fs25.mkdirSync(dir, { recursive: true });
|
|
24395
24518
|
switch (action) {
|
|
24396
24519
|
case "youtrack_json": {
|
|
24397
|
-
const out =
|
|
24398
|
-
|
|
24520
|
+
const out = path38.join(dir, "youtrack.json");
|
|
24521
|
+
fs25.writeFileSync(out, JSON.stringify(youtrackJsonContent(dir), null, 2) + `
|
|
24399
24522
|
`, "utf8");
|
|
24400
24523
|
return { action, ok: true, path: out };
|
|
24401
24524
|
}
|
|
24402
24525
|
case "youtrack_token_placeholder": {
|
|
24403
|
-
const p =
|
|
24526
|
+
const p = path38.join(dir, "youtrack.token");
|
|
24404
24527
|
const preserved = writeFileExclusive(p, TOKEN_PLACEHOLDER2 + `
|
|
24405
24528
|
`, 384) === "preserved";
|
|
24406
|
-
const abs =
|
|
24529
|
+
const abs = path38.resolve(p);
|
|
24407
24530
|
return {
|
|
24408
24531
|
action,
|
|
24409
24532
|
ok: true,
|
|
@@ -24415,14 +24538,14 @@ function initApplyData(action, env = process.env) {
|
|
|
24415
24538
|
};
|
|
24416
24539
|
}
|
|
24417
24540
|
case "youtrack_scaffold": {
|
|
24418
|
-
const jsonOut =
|
|
24419
|
-
const tokenOut =
|
|
24420
|
-
|
|
24541
|
+
const jsonOut = path38.join(dir, "youtrack.json");
|
|
24542
|
+
const tokenOut = path38.join(dir, "youtrack.token");
|
|
24543
|
+
fs25.writeFileSync(jsonOut, JSON.stringify(youtrackJsonContent(dir), null, 2) + `
|
|
24421
24544
|
`, "utf8");
|
|
24422
24545
|
const preserved = writeFileExclusive(tokenOut, TOKEN_PLACEHOLDER2 + `
|
|
24423
24546
|
`, 384) === "preserved";
|
|
24424
|
-
const configPath =
|
|
24425
|
-
const tokenPath =
|
|
24547
|
+
const configPath = path38.resolve(jsonOut);
|
|
24548
|
+
const tokenPath = path38.resolve(tokenOut);
|
|
24426
24549
|
const prev = process.env.WORKFLOW_YOUTRACK_CONFIG;
|
|
24427
24550
|
process.env.WORKFLOW_YOUTRACK_CONFIG = configPath;
|
|
24428
24551
|
let tokenCreate = {};
|
|
@@ -24474,10 +24597,10 @@ function initApplyData(action, env = process.env) {
|
|
|
24474
24597
|
}
|
|
24475
24598
|
}
|
|
24476
24599
|
case "vcs_scaffold": {
|
|
24477
|
-
const jsonOut =
|
|
24478
|
-
|
|
24600
|
+
const jsonOut = path38.join(dir, "vcs.json");
|
|
24601
|
+
fs25.writeFileSync(jsonOut, JSON.stringify(vcsJsonContent(), null, 2) + `
|
|
24479
24602
|
`, "utf8");
|
|
24480
|
-
const configPath =
|
|
24603
|
+
const configPath = path38.resolve(jsonOut);
|
|
24481
24604
|
const prev = process.env.WORKFLOW_VCS_CONFIG;
|
|
24482
24605
|
process.env.WORKFLOW_VCS_CONFIG = configPath;
|
|
24483
24606
|
try {
|
|
@@ -24596,7 +24719,7 @@ var executeInitApply = (args, directory, runtime) => {
|
|
|
24596
24719
|
protectedNames: args.branch_policy_protected
|
|
24597
24720
|
}, current);
|
|
24598
24721
|
writeConfig(next);
|
|
24599
|
-
return output(ok({ action: "config", path:
|
|
24722
|
+
return output(ok({ action: "config", path: path39.join(configDir(), "config.json"), ...next }));
|
|
24600
24723
|
}
|
|
24601
24724
|
const env = Object.fromEntries(Object.entries({
|
|
24602
24725
|
WORKFLOW_YT_BASE_URL: args.base_url,
|
|
@@ -24613,14 +24736,14 @@ var executeInitApply = (args, directory, runtime) => {
|
|
|
24613
24736
|
|
|
24614
24737
|
// packages/workit-opencode/src/shared/session.ts
|
|
24615
24738
|
import { realpathSync as realpathSync7 } from "node:fs";
|
|
24616
|
-
import
|
|
24739
|
+
import path40 from "node:path";
|
|
24617
24740
|
var sameWorkspace = (expected, observed) => {
|
|
24618
24741
|
if (typeof observed !== "string" || !observed)
|
|
24619
24742
|
return false;
|
|
24620
24743
|
try {
|
|
24621
24744
|
return realpathSync7(expected) === realpathSync7(observed);
|
|
24622
24745
|
} catch {
|
|
24623
|
-
return
|
|
24746
|
+
return path40.resolve(expected) === path40.resolve(observed);
|
|
24624
24747
|
}
|
|
24625
24748
|
};
|
|
24626
24749
|
|
|
@@ -24692,7 +24815,7 @@ var workitFamilyOf = (toolName) => {
|
|
|
24692
24815
|
|
|
24693
24816
|
// packages/workit-opencode/src/tools/context.ts
|
|
24694
24817
|
import { realpathSync as realpathSync8 } from "node:fs";
|
|
24695
|
-
import
|
|
24818
|
+
import path41 from "node:path";
|
|
24696
24819
|
var createContextTool = () => ({
|
|
24697
24820
|
description: "Read Git, pull request, YouTrack, issue, changelog, release, or affected-file context.",
|
|
24698
24821
|
execute: async (args, context) => {
|
|
@@ -24702,7 +24825,7 @@ var createContextTool = () => ({
|
|
|
24702
24825
|
let root;
|
|
24703
24826
|
try {
|
|
24704
24827
|
const cwd = parsed.data.cwd;
|
|
24705
|
-
root = realpathSync8(cwd ?
|
|
24828
|
+
root = realpathSync8(cwd ? path41.resolve(context.directory, cwd) : context.directory);
|
|
24706
24829
|
} catch {
|
|
24707
24830
|
return JSON.stringify(failure2("invalid_input", "context target directory cannot be resolved"), null, 2);
|
|
24708
24831
|
}
|
|
@@ -24732,20 +24855,20 @@ var workerCoordinatorFor = (task, worker) => {
|
|
|
24732
24855
|
};
|
|
24733
24856
|
|
|
24734
24857
|
// packages/workit-core/src/fanout.ts
|
|
24735
|
-
import { createHash as
|
|
24736
|
-
import
|
|
24737
|
-
import
|
|
24858
|
+
import { createHash as createHash18 } from "node:crypto";
|
|
24859
|
+
import fs27 from "node:fs";
|
|
24860
|
+
import path44 from "node:path";
|
|
24738
24861
|
|
|
24739
24862
|
// packages/workit-core/src/stack.ts
|
|
24740
24863
|
import { spawnSync as spawnSync21 } from "node:child_process";
|
|
24741
|
-
import { createHash as
|
|
24742
|
-
import
|
|
24743
|
-
import
|
|
24864
|
+
import { createHash as createHash17, randomBytes as randomBytes4 } from "node:crypto";
|
|
24865
|
+
import fs26 from "node:fs";
|
|
24866
|
+
import path43 from "node:path";
|
|
24744
24867
|
|
|
24745
24868
|
// packages/workit-core/src/git/ops.ts
|
|
24746
24869
|
import { spawnSync as spawnSync20 } from "node:child_process";
|
|
24747
24870
|
import { existsSync as existsSync13, readFileSync as readFileSync10 } from "node:fs";
|
|
24748
|
-
import
|
|
24871
|
+
import path42 from "node:path";
|
|
24749
24872
|
|
|
24750
24873
|
// packages/workit-core/src/forge/redact.ts
|
|
24751
24874
|
var KEY = String.raw`[A-Za-z0-9_.-]*?(?:token|secret|password|passwd|pwd|api[_-]?key|access[_-]?key|account[_-]?key|private[_-]?key|client[_-]?secret|credentials?|authorization|cookie|signature)[A-Za-z0-9_.-]*`;
|
|
@@ -24789,18 +24912,18 @@ function operationInProgress(cwd) {
|
|
|
24789
24912
|
if (!run.ok)
|
|
24790
24913
|
return null;
|
|
24791
24914
|
const found = run.stdout.split(`
|
|
24792
|
-
`).map((line) =>
|
|
24915
|
+
`).map((line) => path42.resolve(cwd, line.trim()));
|
|
24793
24916
|
const conflicted = () => git5(cwd, ["ls-files", "-u"]).stdout.trim() !== "";
|
|
24794
24917
|
for (const [index, [, operation]] of markers.entries()) {
|
|
24795
24918
|
const marker = found[index];
|
|
24796
24919
|
if (!marker || !existsSync13(marker))
|
|
24797
24920
|
continue;
|
|
24798
|
-
if (index === 1 && existsSync13(
|
|
24921
|
+
if (index === 1 && existsSync13(path42.join(marker, "applying")))
|
|
24799
24922
|
return { operation: "am", commitAllowed: false, branch: null };
|
|
24800
|
-
if (index === 0 && existsSync13(
|
|
24923
|
+
if (index === 0 && existsSync13(path42.join(marker, "amend")) && !conflicted()) {
|
|
24801
24924
|
let headName = "";
|
|
24802
24925
|
try {
|
|
24803
|
-
headName = readFileSync10(
|
|
24926
|
+
headName = readFileSync10(path42.join(marker, "head-name"), "utf8").trim();
|
|
24804
24927
|
} catch {}
|
|
24805
24928
|
const branch = headName.startsWith("refs/heads/") ? headName.slice("refs/heads/".length) : null;
|
|
24806
24929
|
return { operation, commitAllowed: branch !== null, branch };
|
|
@@ -24912,7 +25035,7 @@ function rebasingBranch2(dir) {
|
|
|
24912
25035
|
if (!found.ok)
|
|
24913
25036
|
continue;
|
|
24914
25037
|
try {
|
|
24915
|
-
return
|
|
25038
|
+
return fs26.readFileSync(found.stdout.trim(), "utf8").trim();
|
|
24916
25039
|
} catch {}
|
|
24917
25040
|
}
|
|
24918
25041
|
return null;
|
|
@@ -24920,14 +25043,14 @@ function rebasingBranch2(dir) {
|
|
|
24920
25043
|
function rebaseInProgress(dir) {
|
|
24921
25044
|
for (const name of ["rebase-merge", "rebase-apply"]) {
|
|
24922
25045
|
const found = gitRun3(dir, ["rev-parse", "--path-format=absolute", "--git-path", name]);
|
|
24923
|
-
if (found.ok &&
|
|
25046
|
+
if (found.ok && fs26.existsSync(found.stdout.trim()))
|
|
24924
25047
|
return true;
|
|
24925
25048
|
}
|
|
24926
25049
|
return false;
|
|
24927
25050
|
}
|
|
24928
25051
|
var scratchDir = (cwd) => {
|
|
24929
25052
|
const dir = stacksDir(cwd);
|
|
24930
|
-
return dir.ok ?
|
|
25053
|
+
return dir.ok ? path43.join(dir.data, "worktrees") : null;
|
|
24931
25054
|
};
|
|
24932
25055
|
function gitRestack(cwd, input) {
|
|
24933
25056
|
const owner = worktreeOf(cwd, input.branch);
|
|
@@ -24941,8 +25064,8 @@ function gitRestack(cwd, input) {
|
|
|
24941
25064
|
worktree: cwd,
|
|
24942
25065
|
error: "no store root"
|
|
24943
25066
|
};
|
|
24944
|
-
|
|
24945
|
-
dir =
|
|
25067
|
+
fs26.mkdirSync(scratch, { recursive: true });
|
|
25068
|
+
dir = path43.join(scratch, `${input.branch.replace(/[^A-Za-z0-9._-]+/gu, "_").slice(0, 40)}-${randomBytes4(4).toString("hex")}`);
|
|
24946
25069
|
const added = gitRun3(cwd, ["worktree", "add", "-q", dir, input.branch], GIT_TIMEOUTS.worktree);
|
|
24947
25070
|
if (!added.ok)
|
|
24948
25071
|
return {
|
|
@@ -24996,12 +25119,12 @@ function gitRestack(cwd, input) {
|
|
|
24996
25119
|
var firstLine = (run) => (`${run.stderr}
|
|
24997
25120
|
${run.stdout}`.split(`
|
|
24998
25121
|
`).find((line) => line.trim()) ?? "git failed").trim().slice(0, 300);
|
|
24999
|
-
var stackFileName = (name) => `${name.replace(/[^A-Za-z0-9._-]+/gu, "_").replace(/^[._]+/u, "").slice(0, 48).toLowerCase()}-${
|
|
25122
|
+
var stackFileName = (name) => `${name.replace(/[^A-Za-z0-9._-]+/gu, "_").replace(/^[._]+/u, "").slice(0, 48).toLowerCase()}-${createHash17("sha256").update(name).digest("hex").slice(0, 12)}.json`;
|
|
25000
25123
|
function stacksDir(cwd) {
|
|
25001
25124
|
const root = storeRoot(cwd);
|
|
25002
25125
|
if (!root.ok)
|
|
25003
25126
|
return stackFail(root.code, root.error, root.unblock);
|
|
25004
|
-
return { ok: true, data:
|
|
25127
|
+
return { ok: true, data: path43.join(root.value.root, "stacks") };
|
|
25005
25128
|
}
|
|
25006
25129
|
var HEARTBEAT_STALE_MS = 2 * 60000;
|
|
25007
25130
|
|
|
@@ -25106,13 +25229,13 @@ function sliceHash(slice) {
|
|
|
25106
25229
|
issues: _issues,
|
|
25107
25230
|
...definition
|
|
25108
25231
|
} = slice;
|
|
25109
|
-
return
|
|
25232
|
+
return createHash18("sha256").update(JSON.stringify(definition)).digest("hex").slice(0, 16);
|
|
25110
25233
|
}
|
|
25111
25234
|
function fanoutsDir(cwd) {
|
|
25112
25235
|
const root = storeRoot(cwd);
|
|
25113
25236
|
if (!root.ok)
|
|
25114
25237
|
return fanoutFail(root.code, root.error, root.unblock);
|
|
25115
|
-
return { ok: true, data:
|
|
25238
|
+
return { ok: true, data: path44.join(root.value.root, "fanouts") };
|
|
25116
25239
|
}
|
|
25117
25240
|
function parseStored(raw) {
|
|
25118
25241
|
if (!isRecord7(raw) || typeof raw.name !== "string" || typeof raw.trunk !== "string")
|
|
@@ -25180,10 +25303,10 @@ function readFanout(cwd, name) {
|
|
|
25180
25303
|
const dir = fanoutsDir(cwd);
|
|
25181
25304
|
if (!dir.ok)
|
|
25182
25305
|
return dir;
|
|
25183
|
-
const file =
|
|
25306
|
+
const file = path44.join(dir.data, stackFileName(name));
|
|
25184
25307
|
let parsed = null;
|
|
25185
25308
|
try {
|
|
25186
|
-
parsed = parseStored(JSON.parse(
|
|
25309
|
+
parsed = parseStored(JSON.parse(fs27.readFileSync(file, "utf8")));
|
|
25187
25310
|
} catch (error) {
|
|
25188
25311
|
if (error.code === "ENOENT")
|
|
25189
25312
|
return { ok: true, data: null };
|
|
@@ -25197,7 +25320,7 @@ function listFanouts(cwd) {
|
|
|
25197
25320
|
return dir;
|
|
25198
25321
|
let names = [];
|
|
25199
25322
|
try {
|
|
25200
|
-
names =
|
|
25323
|
+
names = fs27.readdirSync(dir.data).filter((entry) => entry.endsWith(".json"));
|
|
25201
25324
|
} catch {
|
|
25202
25325
|
return { ok: true, data: [] };
|
|
25203
25326
|
}
|
|
@@ -25205,7 +25328,7 @@ function listFanouts(cwd) {
|
|
|
25205
25328
|
for (const entry of names) {
|
|
25206
25329
|
let parsed = null;
|
|
25207
25330
|
try {
|
|
25208
|
-
parsed = parseStored(JSON.parse(
|
|
25331
|
+
parsed = parseStored(JSON.parse(fs27.readFileSync(path44.join(dir.data, entry), "utf8")));
|
|
25209
25332
|
} catch {
|
|
25210
25333
|
parsed = null;
|
|
25211
25334
|
}
|
|
@@ -25786,7 +25909,11 @@ var injectAgentContext = (root, session, directChildren, system) => {
|
|
|
25786
25909
|
const verdict = session.parentID ? judgeVerdictText(root, session, workerContext) : null;
|
|
25787
25910
|
if (verdict && !hasMarker(system, "<workit-verdict-line>"))
|
|
25788
25911
|
system.push(textPart(`<workit-verdict-line>${verdict}</workit-verdict-line>`));
|
|
25789
|
-
const standing = session.parentID ?
|
|
25912
|
+
const standing = session.parentID ? [
|
|
25913
|
+
standingFor2(root, session),
|
|
25914
|
+
budgetStanding(session.directory ?? root, session.parentID, session.id)
|
|
25915
|
+
].filter(Boolean).join(`
|
|
25916
|
+
`) || null : null;
|
|
25790
25917
|
if (standing && !hasMarker(system, "<workit-standing>"))
|
|
25791
25918
|
system.push(textPart(`<workit-standing>${standing}</workit-standing>`));
|
|
25792
25919
|
};
|
|
@@ -25915,14 +26042,14 @@ var childTaskMissing = (store, input) => {
|
|
|
25915
26042
|
var childDenial = (identity) => `OpenCode child session has no validated Workit worker: as ${identity} it may only inspect the task summary (workit_task action "inspect") or record evidence or findings (workit_evidence/workit_finding action "record") on an existing task; for anything else the lead assigns it a worker with workit_worker before launching it`;
|
|
25916
26043
|
|
|
25917
26044
|
// packages/workit-opencode/src/v2/shell.ts
|
|
25918
|
-
import
|
|
26045
|
+
import path45 from "node:path";
|
|
25919
26046
|
|
|
25920
26047
|
// packages/workit-core/src/hooks/repeat-failure.ts
|
|
25921
|
-
import { createHash as
|
|
26048
|
+
import { createHash as createHash19 } from "node:crypto";
|
|
25922
26049
|
var SAME_CALL_FAILED = "Same call failed twice:";
|
|
25923
26050
|
var MAX_SESSIONS = 256;
|
|
25924
26051
|
var stable = (value) => JSON.stringify(value, (_key, entry) => entry && typeof entry === "object" && !Array.isArray(entry) ? Object.fromEntries(Object.entries(entry).toSorted(([a], [b]) => a.localeCompare(b))) : entry) ?? "null";
|
|
25925
|
-
var hashOf = (call) =>
|
|
26052
|
+
var hashOf = (call) => createHash19("sha256").update(call).digest("hex").slice(0, 32);
|
|
25926
26053
|
var record3 = (memo, sessionId, call, failed, next) => {
|
|
25927
26054
|
const previous = memo.get(sessionId);
|
|
25928
26055
|
memo.delete(sessionId);
|
|
@@ -25978,7 +26105,7 @@ var commandOf = (input) => {
|
|
|
25978
26105
|
};
|
|
25979
26106
|
var hookInput = (root, sessionID, id, shell) => ({
|
|
25980
26107
|
host: "opencode",
|
|
25981
|
-
cwd: shell.workdir ?
|
|
26108
|
+
cwd: shell.workdir ? path45.resolve(root, shell.workdir) : root,
|
|
25982
26109
|
session: { id: sessionID, agentId: null, agentType: null, parentId: null },
|
|
25983
26110
|
permissionMode: null,
|
|
25984
26111
|
transcriptPath: null,
|
|
@@ -26187,37 +26314,37 @@ var createStopControl = (root, port) => {
|
|
|
26187
26314
|
|
|
26188
26315
|
// packages/workit-opencode/src/v2/registry.ts
|
|
26189
26316
|
import { existsSync as existsSync15, readFileSync as readFileSync11 } from "node:fs";
|
|
26190
|
-
import
|
|
26317
|
+
import path47 from "node:path";
|
|
26191
26318
|
|
|
26192
26319
|
// packages/workit-opencode/src/shared/assets.ts
|
|
26193
26320
|
import { existsSync as existsSync14, realpathSync as realpathSync9 } from "node:fs";
|
|
26194
|
-
import
|
|
26321
|
+
import path46 from "node:path";
|
|
26195
26322
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
26196
26323
|
var moduleDir = () => {
|
|
26197
26324
|
try {
|
|
26198
|
-
return realpathSync9(
|
|
26325
|
+
return realpathSync9(path46.dirname(fileURLToPath2(import.meta.url)));
|
|
26199
26326
|
} catch {
|
|
26200
|
-
return
|
|
26327
|
+
return path46.dirname(fileURLToPath2(import.meta.url));
|
|
26201
26328
|
}
|
|
26202
26329
|
};
|
|
26203
26330
|
var packageRoot2 = () => {
|
|
26204
26331
|
const dir = moduleDir();
|
|
26205
26332
|
for (const candidate of [
|
|
26206
|
-
|
|
26207
|
-
|
|
26208
|
-
|
|
26333
|
+
path46.resolve(dir, ".."),
|
|
26334
|
+
path46.resolve(dir, "..", ".."),
|
|
26335
|
+
path46.resolve(dir, "..", "..", "..")
|
|
26209
26336
|
]) {
|
|
26210
|
-
if (existsSync14(
|
|
26337
|
+
if (existsSync14(path46.join(candidate, "package.json")))
|
|
26211
26338
|
return candidate;
|
|
26212
26339
|
}
|
|
26213
|
-
return
|
|
26340
|
+
return path46.resolve(dir, "..");
|
|
26214
26341
|
};
|
|
26215
26342
|
var skillsRoot = () => {
|
|
26216
26343
|
const root = packageRoot2();
|
|
26217
|
-
const canonical =
|
|
26218
|
-
if (existsSync14(
|
|
26344
|
+
const canonical = path46.resolve(root, "..", "workit-core", "skills");
|
|
26345
|
+
if (existsSync14(path46.join(root, "src")) && existsSync14(canonical))
|
|
26219
26346
|
return canonical;
|
|
26220
|
-
return
|
|
26347
|
+
return path46.join(root, "assets", "skills");
|
|
26221
26348
|
};
|
|
26222
26349
|
|
|
26223
26350
|
// packages/workit-opencode/src/v2/registry.ts
|
|
@@ -26244,11 +26371,11 @@ var registerSkills = async (ctx) => {
|
|
|
26244
26371
|
if (!existsSync15(skillsDir))
|
|
26245
26372
|
return new Set;
|
|
26246
26373
|
const listed = await ctx.skill.list().catch(() => ({ data: [] }));
|
|
26247
|
-
const own = (skill) => typeof skill.path === "string" &&
|
|
26374
|
+
const own = (skill) => typeof skill.path === "string" && path47.resolve(skill.path).startsWith(skillsDir + path47.sep);
|
|
26248
26375
|
const userSkills = new Set((listed?.data ?? []).filter((skill) => !own(skill)).map((skill) => skill.id));
|
|
26249
26376
|
const packaged = new Map;
|
|
26250
26377
|
for (const id of WORKIT_METHOD_SKILLS) {
|
|
26251
|
-
const file =
|
|
26378
|
+
const file = path47.join(skillsDir, id, "SKILL.md");
|
|
26252
26379
|
if (!userSkills.has(id) && existsSync15(file))
|
|
26253
26380
|
packaged.set(id, file);
|
|
26254
26381
|
}
|
|
@@ -26296,22 +26423,22 @@ var registerCommands = async (ctx, registeredSkills) => {
|
|
|
26296
26423
|
|
|
26297
26424
|
// packages/workit-opencode/src/stale-sources.ts
|
|
26298
26425
|
import { existsSync as existsSync16, readdirSync as readdirSync6 } from "node:fs";
|
|
26299
|
-
import
|
|
26426
|
+
import path48 from "node:path";
|
|
26300
26427
|
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
26301
26428
|
var typescriptFiles = (directory) => {
|
|
26302
26429
|
if (!existsSync16(directory))
|
|
26303
26430
|
return [];
|
|
26304
26431
|
return readdirSync6(directory, { withFileTypes: true }).flatMap((entry) => {
|
|
26305
|
-
const file =
|
|
26432
|
+
const file = path48.join(directory, entry.name);
|
|
26306
26433
|
return entry.isDirectory() ? typescriptFiles(file) : entry.isFile() && file.endsWith(".ts") ? [file] : [];
|
|
26307
26434
|
});
|
|
26308
26435
|
};
|
|
26309
26436
|
var pluginSourceFiles = [
|
|
26310
26437
|
...new Set([
|
|
26311
26438
|
fileURLToPath3(import.meta.url),
|
|
26312
|
-
...typescriptFiles(
|
|
26313
|
-
|
|
26314
|
-
...typescriptFiles(
|
|
26439
|
+
...typescriptFiles(path48.join(packageRoot2(), "src")),
|
|
26440
|
+
path48.join(packageRoot2(), "..", "workit-core", "src", "core.ts"),
|
|
26441
|
+
...typescriptFiles(path48.join(packageRoot2(), "..", "workit-core", "src", "core"))
|
|
26315
26442
|
])
|
|
26316
26443
|
].filter((file) => existsSync16(file)).toSorted();
|
|
26317
26444
|
|
|
@@ -26452,6 +26579,13 @@ var setup = async (ctx) => {
|
|
|
26452
26579
|
const shellWorkdirs = new Map;
|
|
26453
26580
|
const pendingShells = new Map;
|
|
26454
26581
|
await ctx.tool.hook("execute.before", async (event) => {
|
|
26582
|
+
const budgetEvent = {
|
|
26583
|
+
tool: event.tool,
|
|
26584
|
+
sessionID: String(event.sessionID),
|
|
26585
|
+
input: event.input
|
|
26586
|
+
};
|
|
26587
|
+
if (event.tool !== "subagent")
|
|
26588
|
+
observeBudget(root, budgetEvent, lifecycle.directChildren);
|
|
26455
26589
|
if (event.tool === "shell") {
|
|
26456
26590
|
observeShellBefore(root, event, shellWorkdirs);
|
|
26457
26591
|
return noteShellCall(pendingShells, {
|
|
@@ -26469,6 +26603,7 @@ var setup = async (ctx) => {
|
|
|
26469
26603
|
id: String(event.id),
|
|
26470
26604
|
input: event.input
|
|
26471
26605
|
});
|
|
26606
|
+
observeBudget(root, budgetEvent, lifecycle.directChildren);
|
|
26472
26607
|
});
|
|
26473
26608
|
const shellDomain = ctx.shell;
|
|
26474
26609
|
if (shellDomain)
|