@brainervirus/workit-cursor 8.11.0 → 8.12.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.cursor-plugin/plugin.json +1 -1
- package/dist/cursor-session-start.js +340 -225
- package/dist/mcp-server.js +277 -276
- package/dist/workit-hook.js +341 -227
- package/package.json +3 -3
- package/skills/workit-fanout/references/brief.md +23 -8
- package/skills/workit-fanout/references/orchestration.md +9 -4
package/dist/workit-hook.js
CHANGED
|
@@ -8377,7 +8377,7 @@ import { realpathSync as realpathSync4 } from "node:fs";
|
|
|
8377
8377
|
|
|
8378
8378
|
// packages/workit-core/src/core/policy/derive.ts
|
|
8379
8379
|
import { existsSync as existsSync2 } from "node:fs";
|
|
8380
|
-
import
|
|
8380
|
+
import path9 from "node:path";
|
|
8381
8381
|
|
|
8382
8382
|
// packages/workit-core/src/git/rev.ts
|
|
8383
8383
|
import { spawnSync } from "node:child_process";
|
|
@@ -8564,7 +8564,7 @@ function pushRemoteName(cwd, branch) {
|
|
|
8564
8564
|
import { spawnSync as spawnSync7 } from "node:child_process";
|
|
8565
8565
|
import { createHash as createHash7, randomBytes } from "node:crypto";
|
|
8566
8566
|
import fs5 from "node:fs";
|
|
8567
|
-
import
|
|
8567
|
+
import path8 from "node:path";
|
|
8568
8568
|
|
|
8569
8569
|
// packages/workit-core/src/core/vcs-config.ts
|
|
8570
8570
|
import fs2 from "node:fs";
|
|
@@ -8921,6 +8921,7 @@ var workspaceConfigSchema = object({
|
|
|
8921
8921
|
autoApprove: union([boolean2(), array(nonBlank)]).optional(),
|
|
8922
8922
|
defaultEndpoint: unknown().optional(),
|
|
8923
8923
|
verification: _enum(["self", "independent"]).optional(),
|
|
8924
|
+
trailers: boolean2().optional(),
|
|
8924
8925
|
autonomy: object(Object.fromEntries(["push", "pr", "merge", "release", "rerun"].map((kind) => [
|
|
8925
8926
|
kind,
|
|
8926
8927
|
union([boolean2(), literal("verified")]).optional()
|
|
@@ -9202,8 +9203,8 @@ var resolveRuntimeWorkspaceVcs = (cwd) => resolveRuntimeWorkspaceCandidate(cwd,
|
|
|
9202
9203
|
var runtimeWorkspaceIndexSchema = object({
|
|
9203
9204
|
workspaces: array(object({ name: nonBlank, glob: nonBlank }).passthrough()).optional()
|
|
9204
9205
|
}).passthrough();
|
|
9205
|
-
var matchRuntimeWorkspace = (cwd) => {
|
|
9206
|
-
const file = path3.join(
|
|
9206
|
+
var matchRuntimeWorkspace = (cwd, dir = configDir()) => {
|
|
9207
|
+
const file = path3.join(dir, "workspaces.json");
|
|
9207
9208
|
let raw;
|
|
9208
9209
|
try {
|
|
9209
9210
|
raw = readFileSync2(file, "utf8");
|
|
@@ -9232,12 +9233,30 @@ var matchRuntimeWorkspace = (cwd) => {
|
|
|
9232
9233
|
const matches = matchingEntries(cwd, entries ?? []);
|
|
9233
9234
|
const workspaceName = process.env.WORKFLOW_WORKSPACE_NAME?.trim() || undefined;
|
|
9234
9235
|
const selected = selectWorkspaceMatch(matches, cwd, workspaceName);
|
|
9235
|
-
return selected ? { file, selected } : null;
|
|
9236
|
+
return selected ? { file, selected, matches } : null;
|
|
9236
9237
|
};
|
|
9237
9238
|
var resolveRuntimeReleaseTracks = (cwd) => {
|
|
9238
9239
|
const matched = matchRuntimeWorkspace(cwd);
|
|
9239
9240
|
return matched ? { workspace: matched.selected.name, releaseTracks: matched.selected.releaseTracks } : null;
|
|
9240
9241
|
};
|
|
9242
|
+
var workspaceTrailers = (cwd, dir) => {
|
|
9243
|
+
let matched;
|
|
9244
|
+
try {
|
|
9245
|
+
matched = matchRuntimeWorkspace(cwd, dir);
|
|
9246
|
+
} catch {
|
|
9247
|
+
return { enabled: true, workspace: null, from: null };
|
|
9248
|
+
}
|
|
9249
|
+
if (!matched)
|
|
9250
|
+
return { enabled: true, workspace: null, from: null };
|
|
9251
|
+
const { selected, matches } = matched;
|
|
9252
|
+
const enclosing = matches.filter((entry) => entry !== selected).toSorted((a, b) => globSpecificity(b.glob) - globSpecificity(a.glob));
|
|
9253
|
+
const source = [selected, ...enclosing].find((entry) => typeof entry.trailers === "boolean");
|
|
9254
|
+
return {
|
|
9255
|
+
enabled: source?.trailers !== false,
|
|
9256
|
+
workspace: selected.name,
|
|
9257
|
+
from: source?.name ?? null
|
|
9258
|
+
};
|
|
9259
|
+
};
|
|
9241
9260
|
var resolveRuntimeWorkspaceCandidate = (cwd, kind) => {
|
|
9242
9261
|
const matched = matchRuntimeWorkspace(cwd);
|
|
9243
9262
|
if (!matched)
|
|
@@ -9802,13 +9821,72 @@ function vcsConfig(mode, cwd, options = {}) {
|
|
|
9802
9821
|
// packages/workit-core/src/host-session.ts
|
|
9803
9822
|
import { createHash as createHash6 } from "node:crypto";
|
|
9804
9823
|
import fs4 from "node:fs";
|
|
9805
|
-
import
|
|
9824
|
+
import path7 from "node:path";
|
|
9825
|
+
|
|
9826
|
+
// packages/workit-core/src/core/logger.ts
|
|
9827
|
+
import os3 from "node:os";
|
|
9828
|
+
import path5 from "node:path";
|
|
9829
|
+
var SENSITIVE_WORDS = new Set([
|
|
9830
|
+
"token",
|
|
9831
|
+
"secret",
|
|
9832
|
+
"password",
|
|
9833
|
+
"passwd",
|
|
9834
|
+
"authorization",
|
|
9835
|
+
"credential",
|
|
9836
|
+
"credentials",
|
|
9837
|
+
"cookie",
|
|
9838
|
+
"api",
|
|
9839
|
+
"apikey",
|
|
9840
|
+
"apitoken",
|
|
9841
|
+
"accesstoken",
|
|
9842
|
+
"clientsecret",
|
|
9843
|
+
"refreshtoken",
|
|
9844
|
+
"key",
|
|
9845
|
+
"bearer",
|
|
9846
|
+
"prompt",
|
|
9847
|
+
"message",
|
|
9848
|
+
"messages",
|
|
9849
|
+
"content",
|
|
9850
|
+
"body",
|
|
9851
|
+
"args",
|
|
9852
|
+
"argument",
|
|
9853
|
+
"result",
|
|
9854
|
+
"results",
|
|
9855
|
+
"output",
|
|
9856
|
+
"issue",
|
|
9857
|
+
"description",
|
|
9858
|
+
"summary",
|
|
9859
|
+
"payload",
|
|
9860
|
+
"script",
|
|
9861
|
+
"command",
|
|
9862
|
+
"text",
|
|
9863
|
+
"query"
|
|
9864
|
+
]);
|
|
9865
|
+
var STACK_WORDS = new Set(["stack", "stacktrace", "trace"]);
|
|
9866
|
+
var escapeRegExp2 = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
9867
|
+
var resolveStateDir = () => {
|
|
9868
|
+
const override = process.env.WORKFLOW_TOOLKIT_STATE;
|
|
9869
|
+
if (override)
|
|
9870
|
+
return override;
|
|
9871
|
+
const home = os3.homedir();
|
|
9872
|
+
if (process.env.XDG_STATE_HOME)
|
|
9873
|
+
return path5.join(process.env.XDG_STATE_HOME, "workit");
|
|
9874
|
+
switch (os3.platform()) {
|
|
9875
|
+
case "darwin":
|
|
9876
|
+
return path5.join(home, "Library", "Application Support", "workit");
|
|
9877
|
+
case "win32":
|
|
9878
|
+
return path5.join(process.env.LOCALAPPDATA ?? path5.join(home, "AppData", "Local"), "workit");
|
|
9879
|
+
default:
|
|
9880
|
+
return path5.join(process.env.HOME ?? home, ".local", "state", "workit");
|
|
9881
|
+
}
|
|
9882
|
+
};
|
|
9883
|
+
var homePattern = new RegExp(`${escapeRegExp2(os3.homedir())}(?=[/\\\\]|$)|\\$HOME(?=[/\\\\]|$)`, "g");
|
|
9806
9884
|
|
|
9807
9885
|
// packages/workit-core/src/store/paths.ts
|
|
9808
9886
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
9809
9887
|
import { createHash as createHash5 } from "node:crypto";
|
|
9810
9888
|
import fs3 from "node:fs";
|
|
9811
|
-
import
|
|
9889
|
+
import path6 from "node:path";
|
|
9812
9890
|
var NOT_A_REPO = /not a git repository \(or any (of the parent directories|parent up to)/u;
|
|
9813
9891
|
var gitRun = (cwd, args) => {
|
|
9814
9892
|
const run = spawnSync6("git", args, {
|
|
@@ -9850,14 +9928,14 @@ var DISCOVERY_ENV = [
|
|
|
9850
9928
|
];
|
|
9851
9929
|
var isGitDir = (dir) => {
|
|
9852
9930
|
try {
|
|
9853
|
-
return fs3.statSync(
|
|
9931
|
+
return fs3.statSync(path6.join(dir, "HEAD")).isFile() && fs3.statSync(path6.join(dir, "objects")).isDirectory() && fs3.statSync(path6.join(dir, "refs")).isDirectory();
|
|
9854
9932
|
} catch {
|
|
9855
9933
|
return false;
|
|
9856
9934
|
}
|
|
9857
9935
|
};
|
|
9858
9936
|
var reftableRefs = (common) => {
|
|
9859
9937
|
try {
|
|
9860
|
-
return /^\s*refstorage\s*=\s*reftable\s*$/imu.test(fs3.readFileSync(
|
|
9938
|
+
return /^\s*refstorage\s*=\s*reftable\s*$/imu.test(fs3.readFileSync(path6.join(common, "config"), "utf8"));
|
|
9861
9939
|
} catch {
|
|
9862
9940
|
return false;
|
|
9863
9941
|
}
|
|
@@ -9877,7 +9955,7 @@ function fastGit(root) {
|
|
|
9877
9955
|
if (device !== null && stat.dev !== device)
|
|
9878
9956
|
return { kind: "none" };
|
|
9879
9957
|
device = stat.dev;
|
|
9880
|
-
const dotGit =
|
|
9958
|
+
const dotGit = path6.join(dir, ".git");
|
|
9881
9959
|
let entry = null;
|
|
9882
9960
|
try {
|
|
9883
9961
|
entry = fs3.statSync(dotGit);
|
|
@@ -9898,19 +9976,19 @@ function fastGit(root) {
|
|
|
9898
9976
|
const match = /^gitdir: (.+)$/mu.exec(text);
|
|
9899
9977
|
if (!match)
|
|
9900
9978
|
return null;
|
|
9901
|
-
gitDir =
|
|
9979
|
+
gitDir = path6.resolve(dir, match[1].trim());
|
|
9902
9980
|
} else
|
|
9903
9981
|
return null;
|
|
9904
|
-
if (!fs3.existsSync(
|
|
9982
|
+
if (!fs3.existsSync(path6.join(gitDir, "HEAD")))
|
|
9905
9983
|
return null;
|
|
9906
9984
|
} else if (isGitDir(dir))
|
|
9907
9985
|
gitDir = dir;
|
|
9908
9986
|
if (gitDir) {
|
|
9909
9987
|
let common = gitDir;
|
|
9910
9988
|
try {
|
|
9911
|
-
common =
|
|
9989
|
+
common = path6.resolve(gitDir, fs3.readFileSync(path6.join(gitDir, "commondir"), "utf8").trim());
|
|
9912
9990
|
} catch {}
|
|
9913
|
-
if (!fs3.existsSync(
|
|
9991
|
+
if (!fs3.existsSync(path6.join(common, "objects")))
|
|
9914
9992
|
return null;
|
|
9915
9993
|
return {
|
|
9916
9994
|
kind: "repo",
|
|
@@ -9920,26 +9998,26 @@ function fastGit(root) {
|
|
|
9920
9998
|
reftable: reftableRefs(common)
|
|
9921
9999
|
};
|
|
9922
10000
|
}
|
|
9923
|
-
const parent =
|
|
10001
|
+
const parent = path6.dirname(dir);
|
|
9924
10002
|
if (parent === dir)
|
|
9925
10003
|
return { kind: "none" };
|
|
9926
10004
|
dir = parent;
|
|
9927
10005
|
}
|
|
9928
10006
|
}
|
|
9929
10007
|
function resolveStore(root) {
|
|
9930
|
-
root =
|
|
10008
|
+
root = path6.resolve(root);
|
|
9931
10009
|
let directory = false;
|
|
9932
10010
|
try {
|
|
9933
10011
|
directory = fs3.statSync(root).isDirectory();
|
|
9934
10012
|
} catch {}
|
|
9935
10013
|
if (!directory)
|
|
9936
|
-
return { dir:
|
|
10014
|
+
return { dir: path6.join(root, ".workit"), shared: false, top: null };
|
|
9937
10015
|
const fast = fastGit(root);
|
|
9938
10016
|
if (fast?.kind === "none")
|
|
9939
|
-
return { dir:
|
|
10017
|
+
return { dir: path6.join(root, ".workit"), shared: false, top: null };
|
|
9940
10018
|
if (fast?.kind === "repo")
|
|
9941
10019
|
return {
|
|
9942
|
-
dir:
|
|
10020
|
+
dir: path6.join(fast.common, "workit"),
|
|
9943
10021
|
shared: true,
|
|
9944
10022
|
top: fast.top,
|
|
9945
10023
|
git: { gitDir: fast.gitDir, top: fast.top, reftable: fast.reftable }
|
|
@@ -9949,20 +10027,20 @@ function resolveStore(root) {
|
|
|
9949
10027
|
if (run.ok && common) {
|
|
9950
10028
|
const top = gitRun(root, ["rev-parse", "--path-format=absolute", "--show-toplevel"]);
|
|
9951
10029
|
return {
|
|
9952
|
-
dir:
|
|
10030
|
+
dir: path6.join(real(path6.resolve(root, common)), "workit"),
|
|
9953
10031
|
shared: true,
|
|
9954
10032
|
top: top.ok && top.stdout.trim() ? real(top.stdout.trim()) : null
|
|
9955
10033
|
};
|
|
9956
10034
|
}
|
|
9957
10035
|
if (run.missing || !run.ok && NOT_A_REPO.test(run.stderr))
|
|
9958
|
-
return { dir:
|
|
10036
|
+
return { dir: path6.join(root, ".workit"), shared: false, top: null };
|
|
9959
10037
|
return new Error(`cannot locate the workit store: git rev-parse failed (${run.stderr.trim().split(`
|
|
9960
10038
|
`)[0] || "no output"}); fix the repository (git status should work here)`);
|
|
9961
10039
|
}
|
|
9962
10040
|
var rebasingBranch = (gitDir) => {
|
|
9963
10041
|
for (const state of ["rebase-merge", "rebase-apply"]) {
|
|
9964
10042
|
try {
|
|
9965
|
-
const ref = fs3.readFileSync(
|
|
10043
|
+
const ref = fs3.readFileSync(path6.join(gitDir, state, "head-name"), "utf8").trim();
|
|
9966
10044
|
const match = /^refs\/heads\/(.+)$/u.exec(ref);
|
|
9967
10045
|
if (match)
|
|
9968
10046
|
return match[1];
|
|
@@ -9977,7 +10055,7 @@ function resolveTaskKey(root, location) {
|
|
|
9977
10055
|
if (location.git && !location.git.reftable) {
|
|
9978
10056
|
let head = "";
|
|
9979
10057
|
try {
|
|
9980
|
-
head = fs3.readFileSync(
|
|
10058
|
+
head = fs3.readFileSync(path6.join(location.git.gitDir, "HEAD"), "utf8").trim();
|
|
9981
10059
|
} catch {}
|
|
9982
10060
|
const ref = /^ref: refs\/heads\/(.+)$/u.exec(head);
|
|
9983
10061
|
if (ref && ref[1] !== ".invalid")
|
|
@@ -10008,7 +10086,7 @@ function resolveTaskKey(root, location) {
|
|
|
10008
10086
|
return { key: `detached-${shortHash(real(worktree))}`, kind: "detached", branch: null };
|
|
10009
10087
|
}
|
|
10010
10088
|
function checkoutRootOf(root, location) {
|
|
10011
|
-
const resolved =
|
|
10089
|
+
const resolved = path6.resolve(root);
|
|
10012
10090
|
let canonical = resolved;
|
|
10013
10091
|
try {
|
|
10014
10092
|
canonical = fs3.realpathSync(resolved);
|
|
@@ -10039,13 +10117,13 @@ function branchRenames(location) {
|
|
|
10039
10117
|
}
|
|
10040
10118
|
for (const entry of entries)
|
|
10041
10119
|
if (entry.isDirectory())
|
|
10042
|
-
walk(
|
|
10120
|
+
walk(path6.join(dir, entry.name));
|
|
10043
10121
|
else
|
|
10044
|
-
files.push(
|
|
10122
|
+
files.push(path6.join(dir, entry.name));
|
|
10045
10123
|
};
|
|
10046
|
-
walk(
|
|
10124
|
+
walk(path6.join(path6.dirname(location.dir), "logs", "refs", "heads"));
|
|
10047
10125
|
if (location.git)
|
|
10048
|
-
files.push(
|
|
10126
|
+
files.push(path6.join(location.git.gitDir, "logs", "HEAD"));
|
|
10049
10127
|
const seen = new Set;
|
|
10050
10128
|
const renames = [];
|
|
10051
10129
|
for (const file of files) {
|
|
@@ -10080,7 +10158,7 @@ var checkoutSlug = (root) => {
|
|
|
10080
10158
|
let canonical = real(root);
|
|
10081
10159
|
if (process.platform === "win32")
|
|
10082
10160
|
canonical = canonical.toLowerCase();
|
|
10083
|
-
const base =
|
|
10161
|
+
const base = path6.basename(canonical).replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 40) || "root";
|
|
10084
10162
|
return `${base}-${shortHash(canonical)}`;
|
|
10085
10163
|
};
|
|
10086
10164
|
|
|
@@ -10113,30 +10191,64 @@ function hostSessionFromEnv(env) {
|
|
|
10113
10191
|
return inner ? { host: inner.host, session: inner.session } : { host: declared, session: null };
|
|
10114
10192
|
}
|
|
10115
10193
|
var ISSUED_PER_LEAD = 64;
|
|
10116
|
-
var ISSUED_SESSIONS_MARKER = "workit-issued-sessions/
|
|
10194
|
+
var ISSUED_SESSIONS_MARKER = "workit-issued-sessions/2";
|
|
10117
10195
|
var hash = (value) => createHash6("sha256").update(value).digest("hex").slice(0, 32);
|
|
10118
|
-
var
|
|
10119
|
-
|
|
10120
|
-
|
|
10196
|
+
var userIssuedRoot = () => path7.join(resolveStateDir(), "issued");
|
|
10197
|
+
function migrateRepoIssued(cwd) {
|
|
10198
|
+
if (cwd === undefined)
|
|
10199
|
+
return;
|
|
10200
|
+
let old;
|
|
10201
|
+
try {
|
|
10202
|
+
const location = resolveStore(cwd);
|
|
10203
|
+
if (location instanceof Error)
|
|
10204
|
+
return;
|
|
10205
|
+
old = path7.join(location.dir, "hooks", "issued");
|
|
10206
|
+
if (!fs4.existsSync(old))
|
|
10207
|
+
return;
|
|
10208
|
+
} catch {
|
|
10209
|
+
return;
|
|
10210
|
+
}
|
|
10211
|
+
for (const lead of safeList(old)) {
|
|
10212
|
+
try {
|
|
10213
|
+
const from = path7.join(old, lead);
|
|
10214
|
+
if (!fs4.statSync(from).isDirectory())
|
|
10215
|
+
continue;
|
|
10216
|
+
const to = path7.join(userIssuedRoot(), lead);
|
|
10217
|
+
fs4.mkdirSync(to, { recursive: true, mode: 448 });
|
|
10218
|
+
for (const id of fs4.readdirSync(from)) {
|
|
10219
|
+
fs4.copyFileSync(path7.join(from, id), path7.join(to, id));
|
|
10220
|
+
fs4.rmSync(path7.join(from, id), { force: true });
|
|
10221
|
+
}
|
|
10222
|
+
removeIfEmpty(from);
|
|
10223
|
+
} catch {}
|
|
10224
|
+
}
|
|
10225
|
+
removeIfEmpty(old);
|
|
10226
|
+
}
|
|
10227
|
+
var safeList = (dir) => {
|
|
10228
|
+
try {
|
|
10229
|
+
return fs4.readdirSync(dir);
|
|
10230
|
+
} catch {
|
|
10231
|
+
return [];
|
|
10232
|
+
}
|
|
10121
10233
|
};
|
|
10122
|
-
var
|
|
10123
|
-
|
|
10124
|
-
|
|
10234
|
+
var removeIfEmpty = (dir) => {
|
|
10235
|
+
try {
|
|
10236
|
+
fs4.rmdirSync(dir);
|
|
10237
|
+
} catch {}
|
|
10125
10238
|
};
|
|
10126
10239
|
function recordIssuedSession(cwd, lead, issued) {
|
|
10127
10240
|
try {
|
|
10128
|
-
|
|
10129
|
-
|
|
10130
|
-
|
|
10131
|
-
fs4.mkdirSync(dir, { recursive: true });
|
|
10241
|
+
migrateRepoIssued(cwd);
|
|
10242
|
+
const dir = path7.join(userIssuedRoot(), hash(lead));
|
|
10243
|
+
fs4.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
10132
10244
|
const own = hash(issued);
|
|
10133
|
-
fs4.writeFileSync(
|
|
10245
|
+
fs4.writeFileSync(path7.join(dir, own), ISSUED_SESSIONS_MARKER);
|
|
10134
10246
|
const entries = fs4.readdirSync(dir);
|
|
10135
10247
|
if (entries.length <= ISSUED_PER_LEAD)
|
|
10136
10248
|
return;
|
|
10137
|
-
const byAge = entries.filter((name) => name !== own).map((name) => ({ name, at: fs4.statSync(
|
|
10249
|
+
const byAge = entries.filter((name) => name !== own).map((name) => ({ name, at: fs4.statSync(path7.join(dir, name)).mtimeMs })).toSorted((a, b) => a.at - b.at);
|
|
10138
10250
|
for (const { name } of byAge.slice(0, entries.length - ISSUED_PER_LEAD))
|
|
10139
|
-
fs4.rmSync(
|
|
10251
|
+
fs4.rmSync(path7.join(dir, name), { force: true });
|
|
10140
10252
|
} catch {}
|
|
10141
10253
|
}
|
|
10142
10254
|
var OWN_CHILD_SHELL = new Set(["opencode", "pi"]);
|
|
@@ -10258,14 +10370,14 @@ function diffHash(cwd, base, head) {
|
|
|
10258
10370
|
return `sha256:${hash.digest("hex")}`;
|
|
10259
10371
|
}
|
|
10260
10372
|
function storeRoot(cwd) {
|
|
10261
|
-
const location = resolveStore(
|
|
10373
|
+
const location = resolveStore(path8.resolve(cwd));
|
|
10262
10374
|
if (location instanceof Error)
|
|
10263
10375
|
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");
|
|
10264
10376
|
return { ok: true, value: { root: location.dir, shared: location.shared } };
|
|
10265
10377
|
}
|
|
10266
10378
|
function ledgerPath(cwd) {
|
|
10267
10379
|
const root = storeRoot(cwd);
|
|
10268
|
-
return root.ok ? { ok: true, value:
|
|
10380
|
+
return root.ok ? { ok: true, value: path8.join(root.value.root, "ledger", "ledger.jsonl") } : root;
|
|
10269
10381
|
}
|
|
10270
10382
|
var newId2 = () => `${Date.now().toString(36)}-${randomBytes(6).toString("hex")}`;
|
|
10271
10383
|
var NETWORK_FS_TYPES = new Set([
|
|
@@ -10295,13 +10407,13 @@ var LOCK_STALE_MS = 30000;
|
|
|
10295
10407
|
var LOCK_OWNER = "owner";
|
|
10296
10408
|
var lockToken = (lock) => {
|
|
10297
10409
|
try {
|
|
10298
|
-
return fs5.readFileSync(
|
|
10410
|
+
return fs5.readFileSync(path8.join(lock, LOCK_OWNER), "utf8");
|
|
10299
10411
|
} catch {
|
|
10300
10412
|
return null;
|
|
10301
10413
|
}
|
|
10302
10414
|
};
|
|
10303
10415
|
var lockAgeMs = (lock) => {
|
|
10304
|
-
for (const target of [
|
|
10416
|
+
for (const target of [path8.join(lock, LOCK_OWNER), lock]) {
|
|
10305
10417
|
try {
|
|
10306
10418
|
return Date.now() - fs5.statSync(target).mtimeMs;
|
|
10307
10419
|
} catch {}
|
|
@@ -10318,7 +10430,7 @@ var ledgerLock = {
|
|
|
10318
10430
|
throw error;
|
|
10319
10431
|
}
|
|
10320
10432
|
const token = `${process.pid}-${randomBytes(8).toString("hex")}`;
|
|
10321
|
-
fs5.writeFileSync(
|
|
10433
|
+
fs5.writeFileSync(path8.join(lock, LOCK_OWNER), token);
|
|
10322
10434
|
return token;
|
|
10323
10435
|
},
|
|
10324
10436
|
release(lock, token) {
|
|
@@ -10443,8 +10555,8 @@ function appendLine(file, build, options) {
|
|
|
10443
10555
|
}
|
|
10444
10556
|
};
|
|
10445
10557
|
try {
|
|
10446
|
-
fs5.mkdirSync(
|
|
10447
|
-
if (!options.forceLock && !onNetworkFs(
|
|
10558
|
+
fs5.mkdirSync(path8.dirname(file), { recursive: true });
|
|
10559
|
+
if (!options.forceLock && !onNetworkFs(path8.dirname(file)))
|
|
10448
10560
|
return write();
|
|
10449
10561
|
const locked = withLedgerLock(file, write);
|
|
10450
10562
|
return locked ?? err("busy", `ledger lock ${file}.lock is held`, "retry; remove the .lock directory if no workit process is running");
|
|
@@ -11007,7 +11119,7 @@ var productDecision = (task, ledger) => {
|
|
|
11007
11119
|
};
|
|
11008
11120
|
};
|
|
11009
11121
|
var planRecorded = (task, root) => {
|
|
11010
|
-
const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync2(
|
|
11122
|
+
const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync2(path9.resolve(root, ref.path)));
|
|
11011
11123
|
if (cited)
|
|
11012
11124
|
return {
|
|
11013
11125
|
met: true,
|
|
@@ -11622,20 +11734,20 @@ var judgeInputSummary = (raw) => {
|
|
|
11622
11734
|
};
|
|
11623
11735
|
|
|
11624
11736
|
// packages/workit-core/src/autonomy.ts
|
|
11625
|
-
import
|
|
11626
|
-
import
|
|
11737
|
+
import os4 from "node:os";
|
|
11738
|
+
import path10 from "node:path";
|
|
11627
11739
|
var accountHome = () => {
|
|
11628
11740
|
try {
|
|
11629
|
-
return
|
|
11741
|
+
return os4.userInfo().homedir;
|
|
11630
11742
|
} catch {
|
|
11631
|
-
return
|
|
11743
|
+
return os4.homedir();
|
|
11632
11744
|
}
|
|
11633
11745
|
};
|
|
11634
11746
|
var grantsHome = { resolve: accountHome };
|
|
11635
|
-
var grantsDir = () =>
|
|
11747
|
+
var grantsDir = () => path10.join(grantsHome.resolve(), ".config", "workit");
|
|
11636
11748
|
var grantsOverride = () => {
|
|
11637
|
-
const configured =
|
|
11638
|
-
return configured ===
|
|
11749
|
+
const configured = path10.resolve(resolveConfigDir());
|
|
11750
|
+
return configured === path10.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 ${path10.join(grantsDir(), "workspaces.json")}, so the D4 defaults apply`;
|
|
11639
11751
|
};
|
|
11640
11752
|
var GRANT_KINDS = ["push", "pr", "merge", "release", "rerun"];
|
|
11641
11753
|
var DEFAULT_GRANTS = Object.freeze({
|
|
@@ -11761,7 +11873,7 @@ var grantHint = (workspace, kind) => `ask the user to run, in their own terminal
|
|
|
11761
11873
|
// packages/workit-core/src/core/task-store.ts
|
|
11762
11874
|
import { createHash as createHash9, randomUUID as randomUUID3 } from "node:crypto";
|
|
11763
11875
|
import * as fs11 from "node:fs";
|
|
11764
|
-
import
|
|
11876
|
+
import path15 from "node:path";
|
|
11765
11877
|
|
|
11766
11878
|
// node_modules/@openclaw/fs-safe/dist/errors.js
|
|
11767
11879
|
var OPERATIONAL_CODES = new Set([
|
|
@@ -11812,7 +11924,7 @@ function sameFileIdentity(left, right, platform = process.platform) {
|
|
|
11812
11924
|
// node_modules/@openclaw/fs-safe/dist/sidecar-lock-reclaim.js
|
|
11813
11925
|
import { randomBytes as randomBytes2 } from "node:crypto";
|
|
11814
11926
|
import fsSync from "node:fs";
|
|
11815
|
-
import
|
|
11927
|
+
import path11 from "node:path";
|
|
11816
11928
|
|
|
11817
11929
|
// node_modules/@openclaw/fs-safe/dist/bounded-read.js
|
|
11818
11930
|
import fs6 from "node:fs";
|
|
@@ -11902,13 +12014,13 @@ ${ownershipToken}
|
|
|
11902
12014
|
return { raw, ownershipToken };
|
|
11903
12015
|
}
|
|
11904
12016
|
function relativeSidecarLockPath(lockRoot, lockPath) {
|
|
11905
|
-
const resolved =
|
|
11906
|
-
const lexicalRelative =
|
|
11907
|
-
const relative = lexicalRelative !== ".." && !lexicalRelative.startsWith(`..${
|
|
11908
|
-
if (!relative || relative === ".." || relative.startsWith(`..${
|
|
12017
|
+
const resolved = path11.resolve(lockPath);
|
|
12018
|
+
const lexicalRelative = path11.relative(lockRoot.rootDir, resolved);
|
|
12019
|
+
const relative = lexicalRelative !== ".." && !lexicalRelative.startsWith(`..${path11.sep}`) && !path11.isAbsolute(lexicalRelative) ? lexicalRelative : path11.relative(lockRoot.rootReal, resolved);
|
|
12020
|
+
if (!relative || relative === ".." || relative.startsWith(`..${path11.sep}`) || path11.isAbsolute(relative)) {
|
|
11909
12021
|
throw new FsSafeError("outside-workspace", "sidecar lock path is outside lockRoot");
|
|
11910
12022
|
}
|
|
11911
|
-
return relative.split(
|
|
12023
|
+
return relative.split(path11.sep).join(path11.posix.sep);
|
|
11912
12024
|
}
|
|
11913
12025
|
function parseSidecarLockPayload(raw, parser) {
|
|
11914
12026
|
if (parser) {
|
|
@@ -12055,7 +12167,7 @@ function getFsSafeLockConfig() {
|
|
|
12055
12167
|
|
|
12056
12168
|
// node_modules/@openclaw/fs-safe/dist/file-lock-sync.js
|
|
12057
12169
|
import fs8 from "node:fs";
|
|
12058
|
-
import
|
|
12170
|
+
import path12 from "node:path";
|
|
12059
12171
|
|
|
12060
12172
|
// node_modules/@openclaw/fs-safe/dist/timing.js
|
|
12061
12173
|
function sleepSync(ms) {
|
|
@@ -12146,26 +12258,26 @@ function canonicalLockParentSync(parent) {
|
|
|
12146
12258
|
return process.platform === "win32" ? fs8.realpathSync.native(parent) : fs8.realpathSync(parent);
|
|
12147
12259
|
}
|
|
12148
12260
|
function normalizeTargetPath(targetPath) {
|
|
12149
|
-
const resolved =
|
|
12150
|
-
fs8.mkdirSync(
|
|
12261
|
+
const resolved = path12.resolve(targetPath);
|
|
12262
|
+
fs8.mkdirSync(path12.dirname(resolved), { recursive: true });
|
|
12151
12263
|
try {
|
|
12152
|
-
return
|
|
12264
|
+
return path12.join(canonicalLockParentSync(path12.dirname(resolved)), path12.basename(resolved));
|
|
12153
12265
|
} catch {
|
|
12154
12266
|
return resolved;
|
|
12155
12267
|
}
|
|
12156
12268
|
}
|
|
12157
12269
|
function boundedLockPath(lockPath, lockRoot) {
|
|
12158
|
-
const resolved =
|
|
12270
|
+
const resolved = path12.resolve(lockPath);
|
|
12159
12271
|
if (!lockRoot)
|
|
12160
12272
|
return resolved;
|
|
12161
12273
|
relativeSidecarLockPath(lockRoot, resolved);
|
|
12162
|
-
const parent =
|
|
12274
|
+
const parent = path12.dirname(resolved);
|
|
12163
12275
|
const parentReal = canonicalLockParentSync(parent);
|
|
12164
|
-
const parentRelative =
|
|
12165
|
-
if (parentRelative === ".." || parentRelative.startsWith(`..${
|
|
12276
|
+
const parentRelative = path12.relative(lockRoot.rootReal, parentReal);
|
|
12277
|
+
if (parentRelative === ".." || parentRelative.startsWith(`..${path12.sep}`) || path12.isAbsolute(parentRelative)) {
|
|
12166
12278
|
throw new FsSafeError("outside-workspace", "sidecar lock parent is outside lockRoot");
|
|
12167
12279
|
}
|
|
12168
|
-
return
|
|
12280
|
+
return path12.join(parentReal, path12.basename(resolved));
|
|
12169
12281
|
}
|
|
12170
12282
|
function defaultShouldReclaim(snapshot, staleMs, nowMs) {
|
|
12171
12283
|
const createdAtMs = sidecarLockPayloadCreatedAtMs(snapshot.payload);
|
|
@@ -12366,13 +12478,13 @@ function acquireFileLockSync(targetPath, options) {
|
|
|
12366
12478
|
}
|
|
12367
12479
|
// packages/workit-core/src/core/package-root.ts
|
|
12368
12480
|
import { existsSync as existsSync3 } from "node:fs";
|
|
12369
|
-
import
|
|
12481
|
+
import path13 from "node:path";
|
|
12370
12482
|
import { fileURLToPath } from "node:url";
|
|
12371
12483
|
var packageRoot = () => {
|
|
12372
|
-
let dir =
|
|
12484
|
+
let dir = path13.dirname(fileURLToPath(import.meta.url));
|
|
12373
12485
|
while (true) {
|
|
12374
|
-
const parent =
|
|
12375
|
-
if (existsSync3(
|
|
12486
|
+
const parent = path13.dirname(dir);
|
|
12487
|
+
if (existsSync3(path13.join(dir, "package.json")) || parent === dir)
|
|
12376
12488
|
return dir;
|
|
12377
12489
|
dir = parent;
|
|
12378
12490
|
}
|
|
@@ -12521,7 +12633,7 @@ var clearAbandonedReclaimGuard = (lockPath, nowMs = Date.now()) => {
|
|
|
12521
12633
|
// packages/workit-core/src/store/event-log.ts
|
|
12522
12634
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
12523
12635
|
import fs10 from "node:fs";
|
|
12524
|
-
import
|
|
12636
|
+
import path14 from "node:path";
|
|
12525
12637
|
var EVENT_VERSION = 1;
|
|
12526
12638
|
|
|
12527
12639
|
class LogDamage extends Error {
|
|
@@ -12632,7 +12744,7 @@ function appendEvent(file, event, validEnd) {
|
|
|
12632
12744
|
fs10.closeSync(fd);
|
|
12633
12745
|
}
|
|
12634
12746
|
if (created)
|
|
12635
|
-
fsyncDirectory(
|
|
12747
|
+
fsyncDirectory(path14.dirname(file));
|
|
12636
12748
|
return validEnd;
|
|
12637
12749
|
}
|
|
12638
12750
|
function replaceFile(file, bytes, durable) {
|
|
@@ -12648,7 +12760,7 @@ function replaceFile(file, bytes, durable) {
|
|
|
12648
12760
|
}
|
|
12649
12761
|
renameWithRetry(temporary, file);
|
|
12650
12762
|
if (durable)
|
|
12651
|
-
fsyncDirectory(
|
|
12763
|
+
fsyncDirectory(path14.dirname(file));
|
|
12652
12764
|
} catch (error) {
|
|
12653
12765
|
try {
|
|
12654
12766
|
fs10.unlinkSync(temporary);
|
|
@@ -12991,7 +13103,7 @@ var cachedRuntimeVersion = null;
|
|
|
12991
13103
|
var runtimeVersion = () => {
|
|
12992
13104
|
if (cachedRuntimeVersion === null) {
|
|
12993
13105
|
try {
|
|
12994
|
-
const pkg = JSON.parse(fs11.readFileSync(
|
|
13106
|
+
const pkg = JSON.parse(fs11.readFileSync(path15.join(packageRoot(), "package.json"), "utf8"));
|
|
12995
13107
|
cachedRuntimeVersion = typeof pkg.version === "string" && pkg.version ? pkg.version : "0.0.0";
|
|
12996
13108
|
} catch {
|
|
12997
13109
|
cachedRuntimeVersion = "0.0.0";
|
|
@@ -13024,7 +13136,7 @@ var readText = (file) => {
|
|
|
13024
13136
|
};
|
|
13025
13137
|
var REFLOG_LINE = /^[0-9a-f]+ ([0-9a-f]+) .* (\d+) [+-]\d{4}\t(.*)$/u;
|
|
13026
13138
|
var branchStart = (location, branch, aliases) => {
|
|
13027
|
-
const first = readText(
|
|
13139
|
+
const first = readText(path15.join(path15.dirname(location.dir), "logs", "refs", "heads", branch)).split(`
|
|
13028
13140
|
`, 1)[0];
|
|
13029
13141
|
const created = REFLOG_LINE.exec(first);
|
|
13030
13142
|
const start = created && /^branch: Created from (\S+)$/u.exec(created[3])?.[1];
|
|
@@ -13034,7 +13146,7 @@ var branchStart = (location, branch, aliases) => {
|
|
|
13034
13146
|
return start;
|
|
13035
13147
|
if (!location.git)
|
|
13036
13148
|
return null;
|
|
13037
|
-
for (const line of readText(
|
|
13149
|
+
for (const line of readText(path15.join(location.git.gitDir, "logs", "HEAD")).split(`
|
|
13038
13150
|
`)) {
|
|
13039
13151
|
const entry = REFLOG_LINE.exec(line);
|
|
13040
13152
|
const moved = entry && /^checkout: moving from (\S+) to (\S+)$/u.exec(entry[3]);
|
|
@@ -13044,14 +13156,14 @@ var branchStart = (location, branch, aliases) => {
|
|
|
13044
13156
|
}
|
|
13045
13157
|
return null;
|
|
13046
13158
|
};
|
|
13047
|
-
var refExists = (common, ref) => fs11.existsSync(
|
|
13159
|
+
var refExists = (common, ref) => fs11.existsSync(path15.join(common, ref)) || readText(path15.join(common, "packed-refs")).includes(` ${ref}
|
|
13048
13160
|
`);
|
|
13049
13161
|
var origins = new Map;
|
|
13050
13162
|
var sameDirectoryIdentity = (left, right) => {
|
|
13051
|
-
if (!
|
|
13163
|
+
if (!path15.isAbsolute(left) || !path15.isAbsolute(right))
|
|
13052
13164
|
return false;
|
|
13053
|
-
const normalizedLeft =
|
|
13054
|
-
const normalizedRight =
|
|
13165
|
+
const normalizedLeft = path15.resolve(left);
|
|
13166
|
+
const normalizedRight = path15.resolve(right);
|
|
13055
13167
|
try {
|
|
13056
13168
|
const a = fs11.statSync(normalizedLeft, { bigint: true });
|
|
13057
13169
|
const b = fs11.statSync(normalizedRight, { bigint: true });
|
|
@@ -13097,7 +13209,7 @@ class TaskStore {
|
|
|
13097
13209
|
migrationChecked = false;
|
|
13098
13210
|
compactDue = new Set;
|
|
13099
13211
|
constructor(root, options = {}) {
|
|
13100
|
-
const resolved =
|
|
13212
|
+
const resolved = path15.resolve(root);
|
|
13101
13213
|
this.origin = fs11.existsSync(resolved) ? fs11.realpathSync(resolved) : resolved;
|
|
13102
13214
|
this.located = resolveStore(this.origin);
|
|
13103
13215
|
this.root = checkoutRootOf(this.origin, this.located);
|
|
@@ -13106,7 +13218,7 @@ class TaskStore {
|
|
|
13106
13218
|
this.migrateOnRead = options.migrateOnRead;
|
|
13107
13219
|
}
|
|
13108
13220
|
location() {
|
|
13109
|
-
if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared && fs11.existsSync(
|
|
13221
|
+
if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared && fs11.existsSync(path15.join(this.root, ".git"))) {
|
|
13110
13222
|
this.located = undefined;
|
|
13111
13223
|
this.migrationChecked = false;
|
|
13112
13224
|
}
|
|
@@ -13262,7 +13374,7 @@ class TaskStore {
|
|
|
13262
13374
|
const moved = this.bindLocked(again.data.id, key, input.now);
|
|
13263
13375
|
return moved.ok ? success(moved.data.revision, null, { task: moved.data, created: false, key }) : moved;
|
|
13264
13376
|
}
|
|
13265
|
-
const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" :
|
|
13377
|
+
const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" : path15.basename(this.root) || this.root;
|
|
13266
13378
|
const intent = {
|
|
13267
13379
|
objective: input.objective?.trim() || `Work on ${label}`,
|
|
13268
13380
|
scope: { description: `the checkout (${label})`, paths: ["."], exclusions: [] },
|
|
@@ -13322,14 +13434,14 @@ class TaskStore {
|
|
|
13322
13434
|
const branch = key.ok ? key.data.branch : null;
|
|
13323
13435
|
if (!branch || !location.ok)
|
|
13324
13436
|
return success(null, null, null);
|
|
13325
|
-
const common =
|
|
13326
|
-
const heads =
|
|
13327
|
-
const headLog = location.data.git ?
|
|
13437
|
+
const common = path15.dirname(location.data.dir);
|
|
13438
|
+
const heads = path15.join(common, "logs", "refs", "heads");
|
|
13439
|
+
const headLog = location.data.git ? path15.join(location.data.git.gitDir, "logs", "HEAD") : "";
|
|
13328
13440
|
const signatures = [
|
|
13329
|
-
|
|
13441
|
+
path15.join(heads, branch),
|
|
13330
13442
|
headLog,
|
|
13331
13443
|
heads,
|
|
13332
|
-
|
|
13444
|
+
path15.join(common, "packed-refs")
|
|
13333
13445
|
].map((file) => fileSignature(file) ?? "-");
|
|
13334
13446
|
const slot = `${location.data.dir}\x00${headLog}\x00${branch}`;
|
|
13335
13447
|
let resolved = origins.get(slot);
|
|
@@ -13341,7 +13453,7 @@ class TaskStore {
|
|
|
13341
13453
|
aliases.push(rename.from);
|
|
13342
13454
|
const start = branchStart(location.data, branch, aliases);
|
|
13343
13455
|
const slash = start?.indexOf("/") ?? -1;
|
|
13344
|
-
const remote = slash > 0 && !refExists(common, `refs/heads/${start}`) && (refExists(common, `refs/remotes/${start}`) || readText(
|
|
13456
|
+
const remote = slash > 0 && !refExists(common, `refs/heads/${start}`) && (refExists(common, `refs/remotes/${start}`) || readText(path15.join(common, "config")).includes(`[remote "${start.slice(0, slash)}"]`));
|
|
13345
13457
|
const name = start && (remote ? start.slice(slash + 1) : start);
|
|
13346
13458
|
resolved = {
|
|
13347
13459
|
signature: signatures.join("|"),
|
|
@@ -13579,13 +13691,13 @@ class TaskStore {
|
|
|
13579
13691
|
if (!ready.ok)
|
|
13580
13692
|
return ready;
|
|
13581
13693
|
const dirs = this.paths();
|
|
13582
|
-
const recovery =
|
|
13694
|
+
const recovery = path15.join(this.root, ".workit", "recovery");
|
|
13583
13695
|
if (fs11.existsSync(recovery)) {
|
|
13584
13696
|
let files = 0;
|
|
13585
13697
|
let bytes = 0;
|
|
13586
13698
|
try {
|
|
13587
13699
|
for (const name of fs11.readdirSync(recovery)) {
|
|
13588
|
-
const stat = fs11.lstatSync(
|
|
13700
|
+
const stat = fs11.lstatSync(path15.join(recovery, name));
|
|
13589
13701
|
if (!stat.isFile())
|
|
13590
13702
|
continue;
|
|
13591
13703
|
files += 1;
|
|
@@ -13638,7 +13750,7 @@ class TaskStore {
|
|
|
13638
13750
|
if (fs11.existsSync(dirs.blobs))
|
|
13639
13751
|
for (const name of fs11.readdirSync(dirs.blobs)) {
|
|
13640
13752
|
const digest = name.replace(/\.json$/, "");
|
|
13641
|
-
const file =
|
|
13753
|
+
const file = path15.join(dirs.blobs, name);
|
|
13642
13754
|
let stat;
|
|
13643
13755
|
try {
|
|
13644
13756
|
stat = fs11.lstatSync(file);
|
|
@@ -13656,7 +13768,7 @@ class TaskStore {
|
|
|
13656
13768
|
}
|
|
13657
13769
|
return success(null, null, null);
|
|
13658
13770
|
};
|
|
13659
|
-
const swept = dryRun ? sweep() : this.withLock(
|
|
13771
|
+
const swept = dryRun ? sweep() : this.withLock(path15.join(dirs.dir, "gc.lock"), sweep);
|
|
13660
13772
|
if (!swept.ok)
|
|
13661
13773
|
return swept;
|
|
13662
13774
|
const temporaryDirs = [
|
|
@@ -13664,7 +13776,7 @@ class TaskStore {
|
|
|
13664
13776
|
dirs.tasks,
|
|
13665
13777
|
dirs.blobs,
|
|
13666
13778
|
dirs.checkout,
|
|
13667
|
-
...names.map((name) =>
|
|
13779
|
+
...names.map((name) => path15.join(dirs.tasks, name))
|
|
13668
13780
|
];
|
|
13669
13781
|
for (const directory of temporaryDirs) {
|
|
13670
13782
|
if (!fs11.existsSync(directory))
|
|
@@ -13672,7 +13784,7 @@ class TaskStore {
|
|
|
13672
13784
|
for (const name of fs11.readdirSync(directory)) {
|
|
13673
13785
|
if (!name.endsWith(".tmp") && !name.endsWith(".probe"))
|
|
13674
13786
|
continue;
|
|
13675
|
-
const file =
|
|
13787
|
+
const file = path15.join(directory, name);
|
|
13676
13788
|
try {
|
|
13677
13789
|
const stat = fs11.lstatSync(file);
|
|
13678
13790
|
if (!stat.isFile() || nowMs - stat.mtimeMs <= STALE_TEMPORARY_MS)
|
|
@@ -13689,30 +13801,30 @@ class TaskStore {
|
|
|
13689
13801
|
}
|
|
13690
13802
|
paths() {
|
|
13691
13803
|
const location = this.location();
|
|
13692
|
-
const dir = location.ok ? location.data.dir :
|
|
13693
|
-
const checkout =
|
|
13804
|
+
const dir = location.ok ? location.data.dir : path15.join(this.root, ".workit");
|
|
13805
|
+
const checkout = path15.join(dir, "checkouts", checkoutSlug(this.root));
|
|
13694
13806
|
return {
|
|
13695
13807
|
dir,
|
|
13696
13808
|
shared: location.ok ? location.data.shared : false,
|
|
13697
|
-
marker:
|
|
13809
|
+
marker: path15.join(dir, "store.json"),
|
|
13698
13810
|
checkout,
|
|
13699
|
-
workspace:
|
|
13700
|
-
checkoutLock:
|
|
13701
|
-
tasks:
|
|
13702
|
-
index:
|
|
13703
|
-
blobs:
|
|
13704
|
-
legacy:
|
|
13705
|
-
v2:
|
|
13811
|
+
workspace: path15.join(checkout, "workspace.json"),
|
|
13812
|
+
checkoutLock: path15.join(checkout, "metadata.lock"),
|
|
13813
|
+
tasks: path15.join(dir, "tasks"),
|
|
13814
|
+
index: path15.join(dir, "task-index.json"),
|
|
13815
|
+
blobs: path15.join(dir, "blobs", "candidates"),
|
|
13816
|
+
legacy: path15.join(dir, "legacy", checkoutSlug(this.root), "v2"),
|
|
13817
|
+
v2: path15.join(this.root, ".workit")
|
|
13706
13818
|
};
|
|
13707
13819
|
}
|
|
13708
13820
|
eventsPath(taskId) {
|
|
13709
|
-
return
|
|
13821
|
+
return path15.join(this.paths().tasks, taskId, "events.jsonl");
|
|
13710
13822
|
}
|
|
13711
13823
|
snapshotPath(taskId) {
|
|
13712
|
-
return
|
|
13824
|
+
return path15.join(this.paths().tasks, taskId, "snapshot.json");
|
|
13713
13825
|
}
|
|
13714
13826
|
taskLockPath(taskId) {
|
|
13715
|
-
return
|
|
13827
|
+
return path15.join(this.paths().tasks, taskId, "lock");
|
|
13716
13828
|
}
|
|
13717
13829
|
ready(write = false) {
|
|
13718
13830
|
const location = this.location();
|
|
@@ -13751,13 +13863,13 @@ class TaskStore {
|
|
|
13751
13863
|
return {
|
|
13752
13864
|
read: (digest) => {
|
|
13753
13865
|
try {
|
|
13754
|
-
return JSON.parse(fs11.readFileSync(
|
|
13866
|
+
return JSON.parse(fs11.readFileSync(path15.join(dir, `${digest}.json`), "utf8"));
|
|
13755
13867
|
} catch (error) {
|
|
13756
13868
|
throw new LogDamage(`stored candidate ${digest} is missing or unreadable: ${String(error)}`);
|
|
13757
13869
|
}
|
|
13758
13870
|
},
|
|
13759
13871
|
write: (digest, value) => {
|
|
13760
|
-
const file =
|
|
13872
|
+
const file = path15.join(dir, `${digest}.json`);
|
|
13761
13873
|
if (fs11.existsSync(file)) {
|
|
13762
13874
|
const stamp = new Date;
|
|
13763
13875
|
try {
|
|
@@ -13949,7 +14061,7 @@ class TaskStore {
|
|
|
13949
14061
|
}
|
|
13950
14062
|
}
|
|
13951
14063
|
openTask(record, type, key, legacy = null) {
|
|
13952
|
-
const dir =
|
|
14064
|
+
const dir = path15.join(this.paths().tasks, record.id);
|
|
13953
14065
|
fs11.mkdirSync(dir, { recursive: true });
|
|
13954
14066
|
const blobs = this.blobStore();
|
|
13955
14067
|
const bound = key ? { ...key, boundAt: key.boundAt ?? new Date().toISOString() } : null;
|
|
@@ -14042,7 +14154,7 @@ class TaskStore {
|
|
|
14042
14154
|
}
|
|
14043
14155
|
withKeyLock(key, operation) {
|
|
14044
14156
|
const digest = createHash9("sha256").update(key).digest("hex").slice(0, 32);
|
|
14045
|
-
return this.withLock(
|
|
14157
|
+
return this.withLock(path15.join(this.paths().dir, "keys", `${digest}.lock`), operation);
|
|
14046
14158
|
}
|
|
14047
14159
|
bindLocked(taskId, key, timestamp) {
|
|
14048
14160
|
const current = this.readWorkspace();
|
|
@@ -14183,7 +14295,7 @@ class TaskStore {
|
|
|
14183
14295
|
writeWorkspace(record) {
|
|
14184
14296
|
const file = this.paths().workspace;
|
|
14185
14297
|
try {
|
|
14186
|
-
fs11.mkdirSync(
|
|
14298
|
+
fs11.mkdirSync(path15.dirname(file), { recursive: true });
|
|
14187
14299
|
replaceFile(file, `${canonicalJson(record)}
|
|
14188
14300
|
`, true);
|
|
14189
14301
|
return success(null, null, null);
|
|
@@ -14261,23 +14373,23 @@ class TaskStore {
|
|
|
14261
14373
|
return failure2("revision_conflict", "workspace revision does not match; omit expectedWorkspaceRevision to use the current record", { expectedWorkspaceRevision: expected, actualWorkspaceRevision: actual });
|
|
14262
14374
|
}
|
|
14263
14375
|
v2Dirs() {
|
|
14264
|
-
return [...new Set([this.root, this.origin])].map((dir) =>
|
|
14376
|
+
return [...new Set([this.root, this.origin])].map((dir) => path15.join(dir, ".workit"));
|
|
14265
14377
|
}
|
|
14266
14378
|
pendingMigrations() {
|
|
14267
14379
|
return this.v2Dirs().filter((dir) => {
|
|
14268
|
-
const raw = this.readV2Workspace(
|
|
14380
|
+
const raw = this.readV2Workspace(path15.join(dir, "workspace.json"));
|
|
14269
14381
|
return raw !== null && raw !== TOMBSTONE;
|
|
14270
14382
|
});
|
|
14271
14383
|
}
|
|
14272
14384
|
migrateV2(v2) {
|
|
14273
14385
|
const dirs = this.paths();
|
|
14274
|
-
const v2Workspace =
|
|
14275
|
-
const v2Tasks =
|
|
14276
|
-
const legacy =
|
|
14386
|
+
const v2Workspace = path15.join(v2, "workspace.json");
|
|
14387
|
+
const v2Tasks = path15.join(v2, "tasks");
|
|
14388
|
+
const legacy = path15.join(dirs.dir, "legacy", checkoutSlug(path15.dirname(v2)), "v2");
|
|
14277
14389
|
const raw = this.readV2Workspace(v2Workspace);
|
|
14278
14390
|
if (raw === null || raw === TOMBSTONE)
|
|
14279
14391
|
return success(null, null, null);
|
|
14280
|
-
return this.withLock(dirs.checkoutLock, () => this.withLock(
|
|
14392
|
+
return this.withLock(dirs.checkoutLock, () => this.withLock(path15.join(v2, "metadata.lock"), () => {
|
|
14281
14393
|
const workspace = this.readV2Workspace(v2Workspace);
|
|
14282
14394
|
if (workspace === null || workspace === TOMBSTONE)
|
|
14283
14395
|
return success(null, null, null);
|
|
@@ -14286,7 +14398,7 @@ class TaskStore {
|
|
|
14286
14398
|
return failure2("recovery_required", `cannot migrate the 2.x store at ${v2}: ${parsedWorkspace.error}; move it aside to start fresh`, { path: v2Workspace });
|
|
14287
14399
|
let files = [];
|
|
14288
14400
|
try {
|
|
14289
|
-
files = fs11.readdirSync(v2Tasks).filter((name) => name.endsWith(".json") && validId(name.slice(0, -5))).filter((name) => !this.isStub(
|
|
14401
|
+
files = fs11.readdirSync(v2Tasks).filter((name) => name.endsWith(".json") && validId(name.slice(0, -5))).filter((name) => !this.isStub(path15.join(v2Tasks, name)));
|
|
14290
14402
|
} catch {}
|
|
14291
14403
|
const current = this.readWorkspace();
|
|
14292
14404
|
if (!current.ok)
|
|
@@ -14304,21 +14416,21 @@ class TaskStore {
|
|
|
14304
14416
|
let skipped = 0;
|
|
14305
14417
|
const done = new Map;
|
|
14306
14418
|
try {
|
|
14307
|
-
fs11.mkdirSync(
|
|
14419
|
+
fs11.mkdirSync(path15.join(legacy, "tasks"), { recursive: true });
|
|
14308
14420
|
for (const name of ["workspace.json", "index.json"])
|
|
14309
|
-
if (fs11.existsSync(
|
|
14310
|
-
fs11.copyFileSync(
|
|
14421
|
+
if (fs11.existsSync(path15.join(v2, name)))
|
|
14422
|
+
fs11.copyFileSync(path15.join(v2, name), path15.join(legacy, name));
|
|
14311
14423
|
for (const name of files) {
|
|
14312
14424
|
const id = name.slice(0, -5);
|
|
14313
|
-
const file =
|
|
14425
|
+
const file = path15.join(v2Tasks, name);
|
|
14314
14426
|
const bytes = fs11.readFileSync(file, "utf8");
|
|
14315
14427
|
const digest = sha256(bytes);
|
|
14316
|
-
fs11.writeFileSync(
|
|
14428
|
+
fs11.writeFileSync(path15.join(legacy, "tasks", name), bytes);
|
|
14317
14429
|
const parsed = this.parseRecord(bytes, taskRecordSchema, "2.x task");
|
|
14318
14430
|
if (!parsed.ok || parsed.data.id !== id)
|
|
14319
14431
|
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 });
|
|
14320
14432
|
const record = { ...parsed.data, workspaceId: target.id };
|
|
14321
|
-
const origin = { path:
|
|
14433
|
+
const origin = { path: path15.join(legacy, "tasks", name), digest };
|
|
14322
14434
|
if (!fs11.existsSync(this.eventsPath(id))) {
|
|
14323
14435
|
this.openTask(record, "migrated.from_v2", null, origin);
|
|
14324
14436
|
migrated += 1;
|
|
@@ -14354,7 +14466,7 @@ class TaskStore {
|
|
|
14354
14466
|
try {
|
|
14355
14467
|
let complete = true;
|
|
14356
14468
|
for (const [name, digest] of done) {
|
|
14357
|
-
const file =
|
|
14469
|
+
const file = path15.join(v2Tasks, name);
|
|
14358
14470
|
if (sha256(fs11.readFileSync(file, "utf8")) !== digest) {
|
|
14359
14471
|
complete = false;
|
|
14360
14472
|
continue;
|
|
@@ -14365,7 +14477,7 @@ class TaskStore {
|
|
|
14365
14477
|
return failure2("busy", `the 2.x store at ${v2} changed during migration; retry`, {
|
|
14366
14478
|
path: v2
|
|
14367
14479
|
});
|
|
14368
|
-
fs11.rmSync(
|
|
14480
|
+
fs11.rmSync(path15.join(v2, "index.json"), { force: true });
|
|
14369
14481
|
this.writeTombstone(v2, target.id);
|
|
14370
14482
|
} catch (error) {
|
|
14371
14483
|
return failure2("storage_error", `cannot finish the 2.x migration: ${String(error)}`, {
|
|
@@ -14385,7 +14497,7 @@ class TaskStore {
|
|
|
14385
14497
|
}
|
|
14386
14498
|
adoptLocalStore() {
|
|
14387
14499
|
const dirs = this.paths();
|
|
14388
|
-
const marker =
|
|
14500
|
+
const marker = path15.join(dirs.v2, "store.json");
|
|
14389
14501
|
if (!dirs.shared || !fs11.existsSync(marker))
|
|
14390
14502
|
return success(null, null, null);
|
|
14391
14503
|
return this.withLock(dirs.checkoutLock, () => {
|
|
@@ -14395,7 +14507,7 @@ class TaskStore {
|
|
|
14395
14507
|
try {
|
|
14396
14508
|
const merge = (from, to) => {
|
|
14397
14509
|
if (!fs11.existsSync(to)) {
|
|
14398
|
-
fs11.mkdirSync(
|
|
14510
|
+
fs11.mkdirSync(path15.dirname(to), { recursive: true });
|
|
14399
14511
|
try {
|
|
14400
14512
|
fs11.renameSync(from, to);
|
|
14401
14513
|
} catch {
|
|
@@ -14406,24 +14518,24 @@ class TaskStore {
|
|
|
14406
14518
|
}
|
|
14407
14519
|
if (fs11.lstatSync(from).isDirectory() && fs11.lstatSync(to).isDirectory())
|
|
14408
14520
|
for (const name of fs11.readdirSync(from))
|
|
14409
|
-
merge(
|
|
14521
|
+
merge(path15.join(from, name), path15.join(to, name));
|
|
14410
14522
|
};
|
|
14411
14523
|
for (const sub of ["tasks", "checkouts", "blobs", "legacy"]) {
|
|
14412
|
-
const from =
|
|
14524
|
+
const from = path15.join(dirs.v2, sub);
|
|
14413
14525
|
if (!fs11.existsSync(from))
|
|
14414
14526
|
continue;
|
|
14415
14527
|
if (sub === "tasks") {
|
|
14416
14528
|
for (const name of fs11.readdirSync(from))
|
|
14417
|
-
if (validId(name) && !fs11.existsSync(
|
|
14529
|
+
if (validId(name) && !fs11.existsSync(path15.join(dirs.dir, sub, name)))
|
|
14418
14530
|
tasks += 1;
|
|
14419
14531
|
}
|
|
14420
|
-
merge(from,
|
|
14532
|
+
merge(from, path15.join(dirs.dir, sub));
|
|
14421
14533
|
}
|
|
14422
|
-
const ledger =
|
|
14423
|
-
if (fs11.existsSync(ledger) && !fs11.existsSync(
|
|
14424
|
-
merge(ledger,
|
|
14425
|
-
fs11.rmSync(
|
|
14426
|
-
fs11.renameSync(marker,
|
|
14534
|
+
const ledger = path15.join(dirs.v2, "ledger");
|
|
14535
|
+
if (fs11.existsSync(ledger) && !fs11.existsSync(path15.join(dirs.dir, "ledger")))
|
|
14536
|
+
merge(ledger, path15.join(dirs.dir, "ledger"));
|
|
14537
|
+
fs11.rmSync(path15.join(dirs.v2, "task-index.json"), { force: true });
|
|
14538
|
+
fs11.renameSync(marker, path15.join(dirs.v2, "store.moved.json"));
|
|
14427
14539
|
} catch (error) {
|
|
14428
14540
|
return failure2("storage_error", `cannot move ${dirs.v2} into ${dirs.dir}: ${String(error)}`, {
|
|
14429
14541
|
path: dirs.v2
|
|
@@ -14461,7 +14573,7 @@ class TaskStore {
|
|
|
14461
14573
|
schemaVersion: SCHEMA_VERSION,
|
|
14462
14574
|
id: workspaceId ?? newId(),
|
|
14463
14575
|
revision: newRevision(),
|
|
14464
|
-
root:
|
|
14576
|
+
root: path15.dirname(v2),
|
|
14465
14577
|
runtime: { createdWith: version, updatedWith: version },
|
|
14466
14578
|
writer: null,
|
|
14467
14579
|
store: {
|
|
@@ -14473,11 +14585,11 @@ class TaskStore {
|
|
|
14473
14585
|
critical: ["store"]
|
|
14474
14586
|
};
|
|
14475
14587
|
fs11.mkdirSync(v2, { recursive: true });
|
|
14476
|
-
const ignore =
|
|
14588
|
+
const ignore = path15.join(v2, ".gitignore");
|
|
14477
14589
|
if (!fs11.existsSync(ignore))
|
|
14478
14590
|
fs11.writeFileSync(ignore, `*
|
|
14479
14591
|
`);
|
|
14480
|
-
replaceFile(
|
|
14592
|
+
replaceFile(path15.join(v2, "workspace.json"), `${JSON.stringify(marker, null, 2)}
|
|
14481
14593
|
`, true);
|
|
14482
14594
|
}
|
|
14483
14595
|
stubFor(taskId) {
|
|
@@ -14501,8 +14613,8 @@ class TaskStore {
|
|
|
14501
14613
|
}
|
|
14502
14614
|
writeTombstoneIfMissing() {
|
|
14503
14615
|
try {
|
|
14504
|
-
const v2 =
|
|
14505
|
-
if (fs11.existsSync(
|
|
14616
|
+
const v2 = path15.join(this.root, ".workit");
|
|
14617
|
+
if (fs11.existsSync(path15.join(v2, "workspace.json")))
|
|
14506
14618
|
return;
|
|
14507
14619
|
let id = null;
|
|
14508
14620
|
try {
|
|
@@ -14519,7 +14631,7 @@ class TaskStore {
|
|
|
14519
14631
|
replaceFile(dirs.marker, `${JSON.stringify({ format: "workit-store", version: STORE_FORMAT, createdWith: runtimeVersion() })}
|
|
14520
14632
|
`, false);
|
|
14521
14633
|
if (!dirs.shared) {
|
|
14522
|
-
const ignore =
|
|
14634
|
+
const ignore = path15.join(dirs.dir, ".gitignore");
|
|
14523
14635
|
let current = null;
|
|
14524
14636
|
try {
|
|
14525
14637
|
current = fs11.readFileSync(ignore, "utf8");
|
|
@@ -14579,7 +14691,7 @@ class TaskStore {
|
|
|
14579
14691
|
withLock(lockPath, operation) {
|
|
14580
14692
|
try {
|
|
14581
14693
|
this.initializeStorage();
|
|
14582
|
-
fs11.mkdirSync(
|
|
14694
|
+
fs11.mkdirSync(path15.dirname(lockPath), { recursive: true });
|
|
14583
14695
|
} catch (error) {
|
|
14584
14696
|
return failure2("storage_error", `unable to initialize store: ${String(error)}`, {
|
|
14585
14697
|
path: this.paths().dir
|
|
@@ -14642,7 +14754,7 @@ class TaskStore {
|
|
|
14642
14754
|
if (isTransientWindowsError(error) && !this.lockHolderPresent(lockPath) && !this.lockDirWritable(lockPath))
|
|
14643
14755
|
return failure2("storage_error", `cannot create the workit lock (${code}); no other Workit call holds it`, {
|
|
14644
14756
|
path: lockPath,
|
|
14645
|
-
guidance: `Check permissions and the read-only attribute on ${
|
|
14757
|
+
guidance: `Check permissions and the read-only attribute on ${path15.dirname(lockPath)}.`
|
|
14646
14758
|
});
|
|
14647
14759
|
if (code === "EEXIST" || code === "file_lock_timeout" || code === "file_lock_stale" || isTransientWindowsError(error)) {
|
|
14648
14760
|
let lock = null;
|
|
@@ -14669,12 +14781,12 @@ var workerBlocksTransition = (transition, state) => transition === "pause" ? fal
|
|
|
14669
14781
|
import { createHash as createHash10 } from "node:crypto";
|
|
14670
14782
|
import * as fs13 from "node:fs";
|
|
14671
14783
|
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
14672
|
-
import
|
|
14784
|
+
import path17 from "node:path";
|
|
14673
14785
|
|
|
14674
14786
|
// packages/workit-core/src/check-config.ts
|
|
14675
14787
|
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
14676
14788
|
import fs12 from "node:fs";
|
|
14677
|
-
import
|
|
14789
|
+
import path16 from "node:path";
|
|
14678
14790
|
var SCRIPT_CHECKS = ["test", "lint", "typecheck", "check"];
|
|
14679
14791
|
var CHECKS_FILE = "workit.checks.json";
|
|
14680
14792
|
var isRecord3 = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -14727,10 +14839,10 @@ var git4 = (cwd, args) => {
|
|
|
14727
14839
|
return value || null;
|
|
14728
14840
|
};
|
|
14729
14841
|
function checkRoot(cwd) {
|
|
14730
|
-
return
|
|
14842
|
+
return path16.resolve(git4(cwd, ["rev-parse", "--show-toplevel"]) ?? cwd);
|
|
14731
14843
|
}
|
|
14732
14844
|
var packageManager = (root) => {
|
|
14733
|
-
const has = (file) => fs12.existsSync(
|
|
14845
|
+
const has = (file) => fs12.existsSync(path16.join(root, file));
|
|
14734
14846
|
if (has("bun.lock") || has("bun.lockb"))
|
|
14735
14847
|
return "bun";
|
|
14736
14848
|
if (has("pnpm-lock.yaml"))
|
|
@@ -14750,7 +14862,7 @@ var CHECK_NAME = /^[a-z0-9][a-z0-9:._-]{0,63}$/u;
|
|
|
14750
14862
|
function detectedChecks(root) {
|
|
14751
14863
|
const read = (file) => {
|
|
14752
14864
|
try {
|
|
14753
|
-
return fs12.readFileSync(
|
|
14865
|
+
return fs12.readFileSync(path16.join(root, file), "utf8");
|
|
14754
14866
|
} catch {
|
|
14755
14867
|
return null;
|
|
14756
14868
|
}
|
|
@@ -14789,7 +14901,7 @@ function detectedChecks(root) {
|
|
|
14789
14901
|
var GATES = ["testing", "verification"];
|
|
14790
14902
|
function loadCheckConfig(cwd) {
|
|
14791
14903
|
const root = checkRoot(cwd);
|
|
14792
|
-
const file =
|
|
14904
|
+
const file = path16.join(root, CHECKS_FILE);
|
|
14793
14905
|
const none = (error = null) => ({
|
|
14794
14906
|
source: error ? CHECKS_FILE : "none",
|
|
14795
14907
|
root,
|
|
@@ -14838,7 +14950,7 @@ function loadCheckConfig(cwd) {
|
|
|
14838
14950
|
gates[gate] = names;
|
|
14839
14951
|
}
|
|
14840
14952
|
}
|
|
14841
|
-
return { source: CHECKS_FILE, root, checks, gates, error: null };
|
|
14953
|
+
return { source: CHECKS_FILE, root, checks, gates, error: null, resources: parsed.resources };
|
|
14842
14954
|
}
|
|
14843
14955
|
var sameArgv = (left, right) => left.length === right.length && left.every((item, index) => item === right[index]);
|
|
14844
14956
|
function matchesNamedCheck(config, name, argv, cwd) {
|
|
@@ -14862,10 +14974,10 @@ function workitAvailable(env = process.env) {
|
|
|
14862
14974
|
return workitOnPath;
|
|
14863
14975
|
const windows = process.platform === "win32";
|
|
14864
14976
|
const exts = windows ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
|
|
14865
|
-
const dirs = (env.PATH ?? env.Path ?? "").split(
|
|
14977
|
+
const dirs = (env.PATH ?? env.Path ?? "").split(path16.delimiter).filter(Boolean);
|
|
14866
14978
|
workitOnPath = dirs.some((dir) => exts.some((ext) => {
|
|
14867
14979
|
try {
|
|
14868
|
-
return fs12.statSync(
|
|
14980
|
+
return fs12.statSync(path16.join(dir, `workit${ext}`)).isFile();
|
|
14869
14981
|
} catch {
|
|
14870
14982
|
return false;
|
|
14871
14983
|
}
|
|
@@ -14878,14 +14990,14 @@ function checkCommand(args, version, onPath = workitAvailable()) {
|
|
|
14878
14990
|
|
|
14879
14991
|
// packages/workit-core/src/core/task-evaluation.ts
|
|
14880
14992
|
var digestBytes = (value) => createHash10("sha256").update(value).digest("hex");
|
|
14881
|
-
var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${
|
|
14882
|
-
var relative = (root, candidate) =>
|
|
14993
|
+
var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path17.sep}`);
|
|
14994
|
+
var relative = (root, candidate) => path17.relative(root, candidate).split(path17.sep).join("/") || ".";
|
|
14883
14995
|
var canonicalPath = (value) => {
|
|
14884
14996
|
if (typeof value !== "string" || !value)
|
|
14885
14997
|
return null;
|
|
14886
14998
|
if (value.includes("\\") || value.split("/").includes(".."))
|
|
14887
14999
|
return null;
|
|
14888
|
-
const normalized =
|
|
15000
|
+
const normalized = path17.posix.normalize(value);
|
|
14889
15001
|
if (normalized === ".." || normalized.startsWith("../") || normalized.startsWith("/"))
|
|
14890
15002
|
return null;
|
|
14891
15003
|
return normalized === "." ? "." : normalized.replace(/\/$/, "");
|
|
@@ -14933,14 +15045,14 @@ var gitPaths = (root) => {
|
|
|
14933
15045
|
git: !/not a git repository/i.test(stderr)
|
|
14934
15046
|
};
|
|
14935
15047
|
}
|
|
14936
|
-
const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(
|
|
15048
|
+
const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path17.sep).join("/")) : [];
|
|
14937
15049
|
const stagedDeleted = spawnSync10("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
|
|
14938
15050
|
if (stagedDeleted.status !== 0) {
|
|
14939
15051
|
const stderr = stagedDeleted.stderr?.toString("utf8") ?? "";
|
|
14940
15052
|
if (!/not a git repository/i.test(stderr))
|
|
14941
15053
|
return { paths, uncertain: true, git: true };
|
|
14942
15054
|
} else if (stagedDeleted.stdout) {
|
|
14943
|
-
paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(
|
|
15055
|
+
paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path17.sep).join("/")));
|
|
14944
15056
|
}
|
|
14945
15057
|
return { paths: [...new Set(paths)], uncertain: false, git: true };
|
|
14946
15058
|
};
|
|
@@ -14955,7 +15067,7 @@ var walk = (root, directory, output) => {
|
|
|
14955
15067
|
for (const name of names) {
|
|
14956
15068
|
if (name === ".git" || name === ".workit")
|
|
14957
15069
|
continue;
|
|
14958
|
-
const target =
|
|
15070
|
+
const target = path17.join(directory, name);
|
|
14959
15071
|
let stat;
|
|
14960
15072
|
try {
|
|
14961
15073
|
stat = fs13.lstatSync(target);
|
|
@@ -14973,12 +15085,12 @@ var walk = (root, directory, output) => {
|
|
|
14973
15085
|
var scopeRoots = (root, scope) => {
|
|
14974
15086
|
const roots = [];
|
|
14975
15087
|
for (const item of scope.paths.length ? scope.paths : ["."]) {
|
|
14976
|
-
const target =
|
|
15088
|
+
const target = path17.resolve(root, item);
|
|
14977
15089
|
if (!inside(root, target))
|
|
14978
15090
|
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` }] });
|
|
14979
15091
|
let ancestor = target;
|
|
14980
15092
|
while (!fs13.existsSync(ancestor) && ancestor !== root)
|
|
14981
|
-
ancestor =
|
|
15093
|
+
ancestor = path17.dirname(ancestor);
|
|
14982
15094
|
try {
|
|
14983
15095
|
if (!inside(root, fs13.realpathSync(ancestor)))
|
|
14984
15096
|
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` }] });
|
|
@@ -15030,7 +15142,7 @@ function captureCandidate(root, scope, environment = []) {
|
|
|
15030
15142
|
for (const item of [...names].toSorted()) {
|
|
15031
15143
|
if (!scopeMatches(item, normalizedScope))
|
|
15032
15144
|
continue;
|
|
15033
|
-
const target =
|
|
15145
|
+
const target = path17.join(checkout, item);
|
|
15034
15146
|
try {
|
|
15035
15147
|
const stat = fs13.lstatSync(target);
|
|
15036
15148
|
if (stat.isSymbolicLink()) {
|
|
@@ -15214,23 +15326,23 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
|
15214
15326
|
continue;
|
|
15215
15327
|
if (!reference.digest)
|
|
15216
15328
|
return failure2("invalid_input", "document references require a byte digest");
|
|
15217
|
-
const target =
|
|
15218
|
-
if (target !== root && !target.startsWith(`${root}${
|
|
15329
|
+
const target = path17.resolve(root, reference.path);
|
|
15330
|
+
if (target !== root && !target.startsWith(`${root}${path17.sep}`))
|
|
15219
15331
|
return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
|
|
15220
15332
|
fields: [
|
|
15221
15333
|
{ path: "contentRefs.path", reason: `${reference.path} is outside the checkout` }
|
|
15222
15334
|
]
|
|
15223
15335
|
});
|
|
15224
15336
|
try {
|
|
15225
|
-
const below =
|
|
15337
|
+
const below = path17.relative(root, target);
|
|
15226
15338
|
let current = root;
|
|
15227
|
-
for (const segment of below.split(
|
|
15339
|
+
for (const segment of below.split(path17.sep)) {
|
|
15228
15340
|
if (!segment)
|
|
15229
15341
|
continue;
|
|
15230
|
-
current =
|
|
15342
|
+
current = path17.join(current, segment);
|
|
15231
15343
|
const stat = fs13.lstatSync(current);
|
|
15232
15344
|
const real = fs13.realpathSync(current);
|
|
15233
|
-
if (real !== root && !real.startsWith(`${root}${
|
|
15345
|
+
if (real !== root && !real.startsWith(`${root}${path17.sep}`))
|
|
15234
15346
|
return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
|
|
15235
15347
|
fields: [
|
|
15236
15348
|
{
|
|
@@ -15605,9 +15717,9 @@ Autonomy contract:
|
|
|
15605
15717
|
ship), go to the effective endpoint in \`workit grant show\`: \`pr\` opens
|
|
15606
15718
|
the PR; \`green\` babysits it without asking (workit-ship) to merge-ready,
|
|
15607
15719
|
never merging; \`merged\` also lands it with \`workit pr merge\`.
|
|
15608
|
-
Merge and release need a workspace grant
|
|
15609
|
-
|
|
15610
|
-
|
|
15720
|
+
Merge and release need a workspace grant only the user raises from their
|
|
15721
|
+
own terminal (a blocked verb names how); never edit workspaces.json or route
|
|
15722
|
+
around a grant_required.
|
|
15611
15723
|
- Ask only for a product or preference choice, or for authority you lack, with
|
|
15612
15724
|
your recommended answer. Facts are yours: read, run or prototype.
|
|
15613
15725
|
- Label claims measured (run and seen this session), inferred, or guess.
|
|
@@ -15616,17 +15728,19 @@ Autonomy contract:
|
|
|
15616
15728
|
- Author is not verifier: your own verdict is \`--self\`, shown as
|
|
15617
15729
|
self-reviewed, never verified. High risk, \`verification: independent\` and
|
|
15618
15730
|
merge need a verifier with its own host-derived session (a subagent's
|
|
15619
|
-
\`<lead>:<child
|
|
15731
|
+
\`<lead>:<child>\`); never hand-mint one (\`<lead>-v1\`).
|
|
15620
15732
|
- A local-commit endpoint does not imply PR readiness, and a local commit alone
|
|
15621
15733
|
is not evidence of a requested remote push. Before reporting delivery,
|
|
15622
15734
|
reconcile every requested item and observe it (\`workit verify-delivery\`).
|
|
15623
15735
|
|
|
15624
15736
|
CLI first: if a step has one right answer, use the \`workit\` verb instead of
|
|
15625
15737
|
hand-running git, gh or glab (\`workit git|pr|ci|check\`; \`workit help\` lists
|
|
15626
|
-
the rest;
|
|
15738
|
+
the rest; lacking \`workit\`, \`npx -y @brainervirus/workit-cli\`).
|
|
15739
|
+
Add Co-Authored-By via \`workit git commit --trailer "K: v" -- <paths>\`, never
|
|
15740
|
+
an amend.
|
|
15627
15741
|
The task families (task, policy, evidence, finding, decision, worker, state)
|
|
15628
15742
|
are optional continuity for tracked work; each branch has one implicit task,
|
|
15629
|
-
|
|
15743
|
+
and a solo edit needs no task. A decision
|
|
15630
15744
|
records a user choice; it never authorizes an effect. Judge work once with
|
|
15631
15745
|
\`workit policy assess --judge risk= behavior= product-choice= plan=\`.
|
|
15632
15746
|
Across repositories, bind each item to its checkout, branch and endpoint,
|
|
@@ -17446,7 +17560,7 @@ var capabilitiesFor = (descriptor, observed = {}) => descriptor.capabilities.map
|
|
|
17446
17560
|
// packages/workit-core/src/hooks/context.ts
|
|
17447
17561
|
import { createHash as createHash11 } from "node:crypto";
|
|
17448
17562
|
import fs14 from "node:fs";
|
|
17449
|
-
import
|
|
17563
|
+
import path18 from "node:path";
|
|
17450
17564
|
var MIGRATION_PENDING_NOTE = "workit migration pending — run `workit task status`";
|
|
17451
17565
|
var migrationPending = (result) => !result.ok && result.code === "needs_input" && (result.error ?? "").startsWith(MIGRATION_PENDING);
|
|
17452
17566
|
var boundTo = (entry, session) => entry.sessions.some((item) => item.host === session.host && item.handle === session.handle);
|
|
@@ -17531,7 +17645,7 @@ function entryCompactContext(store, entry, session, context) {
|
|
|
17531
17645
|
return null;
|
|
17532
17646
|
const freshness = { mode: "signal", current: () => recentSignal(store.root) };
|
|
17533
17647
|
const observed = task?.data.evidence.some(isObservedCheck) ?? false;
|
|
17534
|
-
const files = (task?.data.decisions ?? []).flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [
|
|
17648
|
+
const files = (task?.data.decisions ?? []).flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [path18.resolve(store.root, ref.path)] : []));
|
|
17535
17649
|
const observedFiles = filesKey(files);
|
|
17536
17650
|
const compact = new WorkitCore(store, context).compactContext(entry?.id ?? null, freshness, origin && { origin: origin.origin, taskId: origin.entry.id });
|
|
17537
17651
|
if (!compact.ok || !compact.data)
|
|
@@ -17609,14 +17723,14 @@ var turnMarker = (input) => {
|
|
|
17609
17723
|
if (location instanceof Error)
|
|
17610
17724
|
return null;
|
|
17611
17725
|
const session = [input.host, input.session.id, input.session.agentId ?? ""].join("\x00");
|
|
17612
|
-
return
|
|
17726
|
+
return path18.join(location.dir, "hooks", `turn-${digestOf(session).slice(0, 32)}.json`);
|
|
17613
17727
|
} catch {
|
|
17614
17728
|
return null;
|
|
17615
17729
|
}
|
|
17616
17730
|
};
|
|
17617
17731
|
var writeTurnDigest = (file, digest) => {
|
|
17618
17732
|
try {
|
|
17619
|
-
fs14.mkdirSync(
|
|
17733
|
+
fs14.mkdirSync(path18.dirname(file), { recursive: true });
|
|
17620
17734
|
fs14.writeFileSync(file, `${JSON.stringify({ digest })}
|
|
17621
17735
|
`);
|
|
17622
17736
|
} catch {}
|
|
@@ -17631,7 +17745,7 @@ var pruneTurnDigests = (dir, now) => {
|
|
|
17631
17745
|
for (const name of fs14.readdirSync(dir)) {
|
|
17632
17746
|
if (!name.startsWith("turn-"))
|
|
17633
17747
|
continue;
|
|
17634
|
-
const file =
|
|
17748
|
+
const file = path18.join(dir, name);
|
|
17635
17749
|
try {
|
|
17636
17750
|
if (now - fs14.statSync(file).mtimeMs > TURN_TTL_MS)
|
|
17637
17751
|
fs14.rmSync(file, { force: true });
|
|
@@ -17661,7 +17775,7 @@ var seedTurnContext = (input, descriptor, text = turnContextText(input, descript
|
|
|
17661
17775
|
const file = turnMarker(input);
|
|
17662
17776
|
if (!file)
|
|
17663
17777
|
return;
|
|
17664
|
-
pruneTurnDigests(
|
|
17778
|
+
pruneTurnDigests(path18.dirname(file), Date.now());
|
|
17665
17779
|
if (text)
|
|
17666
17780
|
writeTurnDigest(file, digestOf(text));
|
|
17667
17781
|
else
|
|
@@ -17670,14 +17784,14 @@ var seedTurnContext = (input, descriptor, text = turnContextText(input, descript
|
|
|
17670
17784
|
// packages/workit-core/src/core/route-intent.ts
|
|
17671
17785
|
import { spawnSync as spawnSync12 } from "node:child_process";
|
|
17672
17786
|
import { existsSync as existsSync6 } from "node:fs";
|
|
17673
|
-
import
|
|
17787
|
+
import path21 from "node:path";
|
|
17674
17788
|
|
|
17675
17789
|
// packages/workit-core/src/hooks/raw-git.ts
|
|
17676
17790
|
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
17677
17791
|
import { createHash as createHash14 } from "node:crypto";
|
|
17678
17792
|
import fs16 from "node:fs";
|
|
17679
|
-
import
|
|
17680
|
-
import
|
|
17793
|
+
import os5 from "node:os";
|
|
17794
|
+
import path20 from "node:path";
|
|
17681
17795
|
|
|
17682
17796
|
// packages/workit-core/src/core/branch.ts
|
|
17683
17797
|
import { createHash as createHash12 } from "node:crypto";
|
|
@@ -17890,7 +18004,7 @@ var globOf = (pattern) => pattern.source.replace(/^\^|\$$/gu, "").replaceAll(".*
|
|
|
17890
18004
|
// packages/workit-core/src/hooks/session-marker.ts
|
|
17891
18005
|
import { createHash as createHash13 } from "node:crypto";
|
|
17892
18006
|
import fs15 from "node:fs";
|
|
17893
|
-
import
|
|
18007
|
+
import path19 from "node:path";
|
|
17894
18008
|
var sessionMarkerFile = (input, session, store) => {
|
|
17895
18009
|
let dir = store;
|
|
17896
18010
|
if (dir === undefined) {
|
|
@@ -17900,7 +18014,7 @@ var sessionMarkerFile = (input, session, store) => {
|
|
|
17900
18014
|
dir = location.dir;
|
|
17901
18015
|
}
|
|
17902
18016
|
const name = createHash13("sha256").update(`${input.host}\x00${session}`).digest("hex").slice(0, 32);
|
|
17903
|
-
return
|
|
18017
|
+
return path19.join(dir, "hooks", `skills-${name}.json`);
|
|
17904
18018
|
};
|
|
17905
18019
|
var list2 = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
17906
18020
|
var readSessionMarker = (file) => {
|
|
@@ -17913,7 +18027,7 @@ var readSessionMarker = (file) => {
|
|
|
17913
18027
|
};
|
|
17914
18028
|
var writeSessionMarker = (file, marker) => {
|
|
17915
18029
|
try {
|
|
17916
|
-
fs15.mkdirSync(
|
|
18030
|
+
fs15.mkdirSync(path19.dirname(file), { recursive: true });
|
|
17917
18031
|
fs15.writeFileSync(file, JSON.stringify(marker));
|
|
17918
18032
|
} catch {}
|
|
17919
18033
|
};
|
|
@@ -18058,12 +18172,12 @@ var GIT_VALUE_OPTIONS = new Set([
|
|
|
18058
18172
|
"--config-env",
|
|
18059
18173
|
"--super-prefix"
|
|
18060
18174
|
]);
|
|
18061
|
-
var isAbsolute = (value) =>
|
|
18175
|
+
var isAbsolute = (value) => path20.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\");
|
|
18062
18176
|
var joinDir = (base, next) => {
|
|
18063
18177
|
if (base === undefined || /[$`*?]/.test(next) || next === "-")
|
|
18064
18178
|
return;
|
|
18065
|
-
const expanded = next === "~" || next.startsWith("~/") ?
|
|
18066
|
-
return base === null || isAbsolute(expanded) ? expanded :
|
|
18179
|
+
const expanded = next === "~" || next.startsWith("~/") ? path20.join(os5.homedir(), next.slice(1)) : next;
|
|
18180
|
+
return base === null || isAbsolute(expanded) ? expanded : path20.join(base, expanded);
|
|
18067
18181
|
};
|
|
18068
18182
|
var cdTarget = (words) => {
|
|
18069
18183
|
const args = words.slice(1);
|
|
@@ -18114,7 +18228,7 @@ function rawInvocations(command, dialect = "posix", depth = 0) {
|
|
|
18114
18228
|
const name = commandName(words[0]);
|
|
18115
18229
|
if (CD.has(name)) {
|
|
18116
18230
|
const target = cdTarget(words);
|
|
18117
|
-
dir = target === null ?
|
|
18231
|
+
dir = target === null ? os5.homedir() : joinDir(dir, target);
|
|
18118
18232
|
continue;
|
|
18119
18233
|
}
|
|
18120
18234
|
if (PUSHD.has(name)) {
|
|
@@ -18372,17 +18486,17 @@ var headSha2 = (repo) => {
|
|
|
18372
18486
|
if (!git || git.reftable)
|
|
18373
18487
|
return null;
|
|
18374
18488
|
try {
|
|
18375
|
-
const head = fs16.readFileSync(
|
|
18489
|
+
const head = fs16.readFileSync(path20.join(git.gitDir, "HEAD"), "utf8").trim();
|
|
18376
18490
|
if (/^[0-9a-f]{40,64}$/.test(head))
|
|
18377
18491
|
return head;
|
|
18378
18492
|
const ref = /^ref: (refs\/.+)$/.exec(head)?.[1];
|
|
18379
18493
|
if (!ref)
|
|
18380
18494
|
return null;
|
|
18381
|
-
const common =
|
|
18495
|
+
const common = path20.dirname(repo.location.dir);
|
|
18382
18496
|
try {
|
|
18383
|
-
return fs16.readFileSync(
|
|
18497
|
+
return fs16.readFileSync(path20.join(common, ref), "utf8").trim() || null;
|
|
18384
18498
|
} catch {}
|
|
18385
|
-
const packed = fs16.readFileSync(
|
|
18499
|
+
const packed = fs16.readFileSync(path20.join(common, "packed-refs"), "utf8");
|
|
18386
18500
|
return new RegExp(`^([0-9a-f]{40,64}) ${ref.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`, "m").exec(packed)?.[1] ?? null;
|
|
18387
18501
|
} catch {
|
|
18388
18502
|
return null;
|
|
@@ -18471,7 +18585,7 @@ var actionsIn = (cwd, command, dialect) => {
|
|
|
18471
18585
|
const action = rawAction(invocation);
|
|
18472
18586
|
if (!action)
|
|
18473
18587
|
continue;
|
|
18474
|
-
const dir =
|
|
18588
|
+
const dir = path20.resolve(cwd, invocation.dir ?? ".");
|
|
18475
18589
|
if (!repos.has(dir)) {
|
|
18476
18590
|
const repo = repoAt(dir);
|
|
18477
18591
|
repos.set(dir, repo && isWorkitWorkspace(repo) ? repo : null);
|
|
@@ -18551,7 +18665,7 @@ function rawGitPre(input, command, options = {}) {
|
|
|
18551
18665
|
var deny = (reason) => ({ kind: "deny", reason, unblock: null });
|
|
18552
18666
|
var NEXT_COMMAND = "next";
|
|
18553
18667
|
var MARKER_TTL_SECONDS = 3600;
|
|
18554
|
-
var markerFile = (repo, session, key) =>
|
|
18668
|
+
var markerFile = (repo, session, key) => path20.join(repo.location.dir, "hooks", `commit-${createHash14("sha256").update(`${session}\x00${key}`).digest("hex").slice(0, 32)}.json`);
|
|
18555
18669
|
var callKey = (toolUseId, command) => toolUseId ?? `cmd:${createHash14("sha256").update(command).digest("hex")}`;
|
|
18556
18670
|
function noteRawCommit(input, command, key) {
|
|
18557
18671
|
try {
|
|
@@ -18562,7 +18676,7 @@ function noteRawCommit(input, command, key) {
|
|
|
18562
18676
|
if (action.kind !== "commit")
|
|
18563
18677
|
continue;
|
|
18564
18678
|
const file = markerFile(repo, input.session.id, key);
|
|
18565
|
-
fs16.mkdirSync(
|
|
18679
|
+
fs16.mkdirSync(path20.dirname(file), { recursive: true });
|
|
18566
18680
|
fs16.writeFileSync(file, `${JSON.stringify({ head: headSha2(repo), at })}
|
|
18567
18681
|
`);
|
|
18568
18682
|
}
|
|
@@ -18735,7 +18849,7 @@ var shellBranchPolicyViolation = (root, command, dialect = "posix") => {
|
|
|
18735
18849
|
for (const target of shellBranchTargets(command, dialect)) {
|
|
18736
18850
|
if (target.dir === undefined)
|
|
18737
18851
|
continue;
|
|
18738
|
-
const dir = target.dir === null ? root :
|
|
18852
|
+
const dir = target.dir === null ? root : path21.resolve(root, target.dir);
|
|
18739
18853
|
if (target.dir !== null && (!existsSync6(dir) || !inWorkitWorkspace(dir)))
|
|
18740
18854
|
continue;
|
|
18741
18855
|
if (localBranchExists(dir, target.branch))
|
|
@@ -18755,27 +18869,27 @@ var shellPolicy = (cwd, command, dialect = "posix") => {
|
|
|
18755
18869
|
};
|
|
18756
18870
|
// packages/workit-core/src/hooks/write-gate.ts
|
|
18757
18871
|
import { realpathSync as realpathSync5 } from "node:fs";
|
|
18758
|
-
import
|
|
18872
|
+
import path22 from "node:path";
|
|
18759
18873
|
var NONE3 = { kind: "none" };
|
|
18760
18874
|
var CASE_INSENSITIVE = process.platform === "darwin" || process.platform === "win32";
|
|
18761
18875
|
var canonical2 = (file) => {
|
|
18762
18876
|
let rest = "";
|
|
18763
|
-
for (let dir =
|
|
18877
|
+
for (let dir = path22.resolve(file);; dir = path22.dirname(dir)) {
|
|
18764
18878
|
try {
|
|
18765
|
-
return
|
|
18879
|
+
return path22.join(realpathSync5(dir), rest);
|
|
18766
18880
|
} catch {
|
|
18767
|
-
if (
|
|
18768
|
-
return
|
|
18769
|
-
rest = rest ?
|
|
18881
|
+
if (path22.dirname(dir) === dir)
|
|
18882
|
+
return path22.resolve(file);
|
|
18883
|
+
rest = rest ? path22.join(path22.basename(dir), rest) : path22.basename(dir);
|
|
18770
18884
|
}
|
|
18771
18885
|
}
|
|
18772
18886
|
};
|
|
18773
18887
|
var exempt = (cwd, root, file, plans) => {
|
|
18774
18888
|
const fold = (value) => CASE_INSENSITIVE ? value.toLowerCase() : value;
|
|
18775
|
-
const relative =
|
|
18776
|
-
if (relative.startsWith("..") ||
|
|
18889
|
+
const relative = path22.relative(fold(canonical2(root)), fold(canonical2(path22.resolve(cwd, file))));
|
|
18890
|
+
if (relative.startsWith("..") || path22.isAbsolute(relative))
|
|
18777
18891
|
return true;
|
|
18778
|
-
const posix = relative.split(
|
|
18892
|
+
const posix = relative.split(path22.sep).join("/");
|
|
18779
18893
|
const segments = posix.split("/");
|
|
18780
18894
|
return /\.mdx?$/i.test(posix) || segments[0] === "docs" || segments.includes("plans") || [...plans].some((plan) => fold(plan) === posix);
|
|
18781
18895
|
};
|
|
@@ -18873,7 +18987,7 @@ var shellWrites = (command) => {
|
|
|
18873
18987
|
return { writes: true, targets: unknown ? null : targets };
|
|
18874
18988
|
};
|
|
18875
18989
|
var cache2 = new Map;
|
|
18876
|
-
var planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(
|
|
18990
|
+
var planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(path22.resolve(root, file)) ?? "-").join("\x00");
|
|
18877
18991
|
var gateFor = (cwd) => {
|
|
18878
18992
|
const store = new TaskStore(cwd);
|
|
18879
18993
|
const listed = store.listTaskIndex();
|
|
@@ -19314,12 +19428,12 @@ ${line}` };
|
|
|
19314
19428
|
};
|
|
19315
19429
|
// packages/workit-core/src/hooks/hosts/fields.ts
|
|
19316
19430
|
import { existsSync as existsSync7, realpathSync as realpathSync6, statSync as statSync2 } from "node:fs";
|
|
19317
|
-
import
|
|
19431
|
+
import path23 from "node:path";
|
|
19318
19432
|
var isRecord4 = (value) => value !== null && typeof value === "object" && !Array.isArray(value);
|
|
19319
19433
|
var nonEmpty2 = (value) => typeof value === "string" && value.trim() !== "";
|
|
19320
19434
|
var optionalText = (value) => typeof value === "string" ? value : null;
|
|
19321
19435
|
var existingDirectory = (value) => {
|
|
19322
|
-
if (!nonEmpty2(value) || !
|
|
19436
|
+
if (!nonEmpty2(value) || !path23.isAbsolute(value) || !existsSync7(value))
|
|
19323
19437
|
return null;
|
|
19324
19438
|
try {
|
|
19325
19439
|
return statSync2(value).isDirectory() ? realpathSync6(value) : null;
|
|
@@ -19402,7 +19516,7 @@ var workitRole = (descriptor, agentType) => {
|
|
|
19402
19516
|
};
|
|
19403
19517
|
var subagentSession = (session, agentId) => [session, agentId].filter((part) => Boolean(part)).join(":").replace(/[^A-Za-z0-9_.:@/+-]/g, "-").slice(0, 128);
|
|
19404
19518
|
var CLAUDE_WORKTREE = /[\\/]\.claude[\\/]worktrees[\\/]/;
|
|
19405
|
-
var
|
|
19519
|
+
var isolatedGit = (cwd) => `Run git as plain, separate commands inside your worktree (\`git switch -c <branch> <base>\`, ${workspaceTrailers(cwd).enabled ? '`git commit --trailer "Workit-Session=<your session>"`, `git push`; `workit doctor --fix` can install a prepare-commit-msg hook that adds the trailer' : "`git commit` (this workspace sets trailers: false: add no Workit-Session trailer), `git push`"}; add Co-Authored-By with \`git commit --trailer\` in the same commit, never by amending), never \`workit git …\`: Claude Code's worktree isolation refuses a command that wraps git and cannot be turned off (https://code.claude.com/docs/en/worktrees#how-claude-code-enforces-isolation). Never dodge that check by renaming or re-wrapping git. Use workit for the non-git verbs (\`workit check\`, \`workit ledger\`, \`workit pr\`).`;
|
|
19406
19520
|
var subagentStartText = (input, descriptor, event) => {
|
|
19407
19521
|
const session = input.session.id ?? null;
|
|
19408
19522
|
const role = workitRole(descriptor, event.agentType);
|
|
@@ -19410,9 +19524,9 @@ var subagentStartText = (input, descriptor, event) => {
|
|
|
19410
19524
|
const isolated = descriptor.subagents.worktreeIsolation === "native" && (role === "implementer" || CLAUDE_WORKTREE.test(input.cwd));
|
|
19411
19525
|
const guide = role === "implementer" ? branchGuidance(input.cwd) : null;
|
|
19412
19526
|
if (role === "implementer" && isolated)
|
|
19413
|
-
return `Workit observed ${who} working in its own git worktree: it may edit and commit there, within its brief's scope. ${
|
|
19527
|
+
return `Workit observed ${who} working in its own git worktree: it may edit and commit there, within its brief's scope. ${isolatedGit(input.cwd)} Plain git is expected here, and the branch name is still policy-checked: a raw \`git switch -c\`, \`git checkout -b\`, \`git branch\` or \`git worktree add -b\` onto a protected or non-compliant name is denied, so use a policy-compliant branch.${guide ? ` ${guide}` : " (e.g. feature/<slug>)"} Never record a verdict on your own work. Never push, open a PR, or merge unless the brief asks for it.`;
|
|
19414
19528
|
if (isolated)
|
|
19415
|
-
return `${
|
|
19529
|
+
return `${isolatedGit(input.cwd)}
|
|
19416
19530
|
${subagentStartText({ ...input, cwd: "" }, descriptor, event)}`;
|
|
19417
19531
|
if (role === "implementer")
|
|
19418
19532
|
return `Workit observed ${who} as an implementer: it edits and commits only in its own git worktree (the lead makes one with \`workit fanout worktree create <slice>\`), never in the lead's checkout, within its brief's scope. Before the first commit, switch to a policy-compliant branch with \`workit git branch <branch> --base <base>\` (or \`--kind <kind> --slug <slug>\`, which picks the base); branch policy hooks still deny protected or non-compliant branches, raw git included.${guide ? ` ${guide}` : " (e.g. feature/<slug>)"} Never record a verdict on your own work. Never push, open a PR, or merge unless the brief asks for it.`;
|
|
@@ -20058,7 +20172,7 @@ var codexAdapter = {
|
|
|
20058
20172
|
|
|
20059
20173
|
// packages/workit-core/src/hooks/hosts/cursor.ts
|
|
20060
20174
|
import fs17 from "node:fs";
|
|
20061
|
-
import
|
|
20175
|
+
import path24 from "node:path";
|
|
20062
20176
|
var undocumented = { support: "undocumented", native: null };
|
|
20063
20177
|
var none = { support: "none", native: null };
|
|
20064
20178
|
var CURSOR_DESCRIPTOR = {
|
|
@@ -20255,7 +20369,7 @@ var protocolEvent2 = (input) => {
|
|
|
20255
20369
|
};
|
|
20256
20370
|
var TRANSCRIPT_TAIL_BYTES = 256 * 1024;
|
|
20257
20371
|
var lastAssistantText = (file) => {
|
|
20258
|
-
if (!file || !
|
|
20372
|
+
if (!file || !path24.isAbsolute(file))
|
|
20259
20373
|
return null;
|
|
20260
20374
|
try {
|
|
20261
20375
|
const size = fs17.statSync(file).size;
|
|
@@ -20292,7 +20406,7 @@ var lastAssistantText = (file) => {
|
|
|
20292
20406
|
return null;
|
|
20293
20407
|
}
|
|
20294
20408
|
};
|
|
20295
|
-
var within = (root, dir) => dir === root || dir.startsWith(root.endsWith(
|
|
20409
|
+
var within = (root, dir) => dir === root || dir.startsWith(root.endsWith(path24.sep) ? root : `${root}${path24.sep}`);
|
|
20296
20410
|
var hookCwd = (input) => {
|
|
20297
20411
|
const cwd = existingDirectory(input.cwd);
|
|
20298
20412
|
if (cwd && input.hook_event_name === "beforeShellExecution")
|