@brainervirus/workit-pi 8.12.0 → 8.12.2
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/worker.js +42 -0
- package/dist/workit.js +348 -255
- package/package.json +1 -1
package/dist/workit.js
CHANGED
|
@@ -5,7 +5,7 @@ import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
|
5
5
|
// packages/workit-core/src/core.ts
|
|
6
6
|
import { spawnSync as spawnSync16 } from "node:child_process";
|
|
7
7
|
import { existsSync as existsSync8, realpathSync as realpathSync5 } from "node:fs";
|
|
8
|
-
import
|
|
8
|
+
import path24 from "node:path";
|
|
9
9
|
|
|
10
10
|
// packages/workit-core/src/core/task-contract.ts
|
|
11
11
|
import { createHash, randomUUID } from "node:crypto";
|
|
@@ -8993,7 +8993,7 @@ function parseAdvertisedOperation(family, input, host) {
|
|
|
8993
8993
|
// packages/workit-core/src/core/task-store.ts
|
|
8994
8994
|
import { createHash as createHash5, randomUUID as randomUUID3 } from "node:crypto";
|
|
8995
8995
|
import * as fs8 from "node:fs";
|
|
8996
|
-
import
|
|
8996
|
+
import path8 from "node:path";
|
|
8997
8997
|
|
|
8998
8998
|
// node_modules/@openclaw/fs-safe/dist/errors.js
|
|
8999
8999
|
var OPERATIONAL_CODES = new Set([
|
|
@@ -9599,13 +9599,72 @@ function acquireFileLockSync(targetPath, options) {
|
|
|
9599
9599
|
// packages/workit-core/src/host-session.ts
|
|
9600
9600
|
import { createHash as createHash3 } from "node:crypto";
|
|
9601
9601
|
import fs5 from "node:fs";
|
|
9602
|
-
import
|
|
9602
|
+
import path5 from "node:path";
|
|
9603
|
+
|
|
9604
|
+
// packages/workit-core/src/core/logger.ts
|
|
9605
|
+
import os from "node:os";
|
|
9606
|
+
import path3 from "node:path";
|
|
9607
|
+
var SENSITIVE_WORDS = new Set([
|
|
9608
|
+
"token",
|
|
9609
|
+
"secret",
|
|
9610
|
+
"password",
|
|
9611
|
+
"passwd",
|
|
9612
|
+
"authorization",
|
|
9613
|
+
"credential",
|
|
9614
|
+
"credentials",
|
|
9615
|
+
"cookie",
|
|
9616
|
+
"api",
|
|
9617
|
+
"apikey",
|
|
9618
|
+
"apitoken",
|
|
9619
|
+
"accesstoken",
|
|
9620
|
+
"clientsecret",
|
|
9621
|
+
"refreshtoken",
|
|
9622
|
+
"key",
|
|
9623
|
+
"bearer",
|
|
9624
|
+
"prompt",
|
|
9625
|
+
"message",
|
|
9626
|
+
"messages",
|
|
9627
|
+
"content",
|
|
9628
|
+
"body",
|
|
9629
|
+
"args",
|
|
9630
|
+
"argument",
|
|
9631
|
+
"result",
|
|
9632
|
+
"results",
|
|
9633
|
+
"output",
|
|
9634
|
+
"issue",
|
|
9635
|
+
"description",
|
|
9636
|
+
"summary",
|
|
9637
|
+
"payload",
|
|
9638
|
+
"script",
|
|
9639
|
+
"command",
|
|
9640
|
+
"text",
|
|
9641
|
+
"query"
|
|
9642
|
+
]);
|
|
9643
|
+
var STACK_WORDS = new Set(["stack", "stacktrace", "trace"]);
|
|
9644
|
+
var escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
9645
|
+
var resolveStateDir = () => {
|
|
9646
|
+
const override = process.env.WORKFLOW_TOOLKIT_STATE;
|
|
9647
|
+
if (override)
|
|
9648
|
+
return override;
|
|
9649
|
+
const home = os.homedir();
|
|
9650
|
+
if (process.env.XDG_STATE_HOME)
|
|
9651
|
+
return path3.join(process.env.XDG_STATE_HOME, "workit");
|
|
9652
|
+
switch (os.platform()) {
|
|
9653
|
+
case "darwin":
|
|
9654
|
+
return path3.join(home, "Library", "Application Support", "workit");
|
|
9655
|
+
case "win32":
|
|
9656
|
+
return path3.join(process.env.LOCALAPPDATA ?? path3.join(home, "AppData", "Local"), "workit");
|
|
9657
|
+
default:
|
|
9658
|
+
return path3.join(process.env.HOME ?? home, ".local", "state", "workit");
|
|
9659
|
+
}
|
|
9660
|
+
};
|
|
9661
|
+
var homePattern = new RegExp(`${escapeRegExp(os.homedir())}(?=[/\\\\]|$)|\\$HOME(?=[/\\\\]|$)`, "g");
|
|
9603
9662
|
|
|
9604
9663
|
// packages/workit-core/src/store/paths.ts
|
|
9605
9664
|
import { spawnSync } from "node:child_process";
|
|
9606
9665
|
import { createHash as createHash2 } from "node:crypto";
|
|
9607
9666
|
import fs4 from "node:fs";
|
|
9608
|
-
import
|
|
9667
|
+
import path4 from "node:path";
|
|
9609
9668
|
var NOT_A_REPO = /not a git repository \(or any (of the parent directories|parent up to)/u;
|
|
9610
9669
|
var gitRun = (cwd, args) => {
|
|
9611
9670
|
const run = spawnSync("git", args, {
|
|
@@ -9647,14 +9706,14 @@ var DISCOVERY_ENV = [
|
|
|
9647
9706
|
];
|
|
9648
9707
|
var isGitDir = (dir) => {
|
|
9649
9708
|
try {
|
|
9650
|
-
return fs4.statSync(
|
|
9709
|
+
return fs4.statSync(path4.join(dir, "HEAD")).isFile() && fs4.statSync(path4.join(dir, "objects")).isDirectory() && fs4.statSync(path4.join(dir, "refs")).isDirectory();
|
|
9651
9710
|
} catch {
|
|
9652
9711
|
return false;
|
|
9653
9712
|
}
|
|
9654
9713
|
};
|
|
9655
9714
|
var reftableRefs = (common) => {
|
|
9656
9715
|
try {
|
|
9657
|
-
return /^\s*refstorage\s*=\s*reftable\s*$/imu.test(fs4.readFileSync(
|
|
9716
|
+
return /^\s*refstorage\s*=\s*reftable\s*$/imu.test(fs4.readFileSync(path4.join(common, "config"), "utf8"));
|
|
9658
9717
|
} catch {
|
|
9659
9718
|
return false;
|
|
9660
9719
|
}
|
|
@@ -9674,7 +9733,7 @@ function fastGit(root) {
|
|
|
9674
9733
|
if (device !== null && stat.dev !== device)
|
|
9675
9734
|
return { kind: "none" };
|
|
9676
9735
|
device = stat.dev;
|
|
9677
|
-
const dotGit =
|
|
9736
|
+
const dotGit = path4.join(dir, ".git");
|
|
9678
9737
|
let entry = null;
|
|
9679
9738
|
try {
|
|
9680
9739
|
entry = fs4.statSync(dotGit);
|
|
@@ -9695,19 +9754,19 @@ function fastGit(root) {
|
|
|
9695
9754
|
const match = /^gitdir: (.+)$/mu.exec(text);
|
|
9696
9755
|
if (!match)
|
|
9697
9756
|
return null;
|
|
9698
|
-
gitDir =
|
|
9757
|
+
gitDir = path4.resolve(dir, match[1].trim());
|
|
9699
9758
|
} else
|
|
9700
9759
|
return null;
|
|
9701
|
-
if (!fs4.existsSync(
|
|
9760
|
+
if (!fs4.existsSync(path4.join(gitDir, "HEAD")))
|
|
9702
9761
|
return null;
|
|
9703
9762
|
} else if (isGitDir(dir))
|
|
9704
9763
|
gitDir = dir;
|
|
9705
9764
|
if (gitDir) {
|
|
9706
9765
|
let common = gitDir;
|
|
9707
9766
|
try {
|
|
9708
|
-
common =
|
|
9767
|
+
common = path4.resolve(gitDir, fs4.readFileSync(path4.join(gitDir, "commondir"), "utf8").trim());
|
|
9709
9768
|
} catch {}
|
|
9710
|
-
if (!fs4.existsSync(
|
|
9769
|
+
if (!fs4.existsSync(path4.join(common, "objects")))
|
|
9711
9770
|
return null;
|
|
9712
9771
|
return {
|
|
9713
9772
|
kind: "repo",
|
|
@@ -9717,26 +9776,26 @@ function fastGit(root) {
|
|
|
9717
9776
|
reftable: reftableRefs(common)
|
|
9718
9777
|
};
|
|
9719
9778
|
}
|
|
9720
|
-
const parent =
|
|
9779
|
+
const parent = path4.dirname(dir);
|
|
9721
9780
|
if (parent === dir)
|
|
9722
9781
|
return { kind: "none" };
|
|
9723
9782
|
dir = parent;
|
|
9724
9783
|
}
|
|
9725
9784
|
}
|
|
9726
9785
|
function resolveStore(root) {
|
|
9727
|
-
root =
|
|
9786
|
+
root = path4.resolve(root);
|
|
9728
9787
|
let directory = false;
|
|
9729
9788
|
try {
|
|
9730
9789
|
directory = fs4.statSync(root).isDirectory();
|
|
9731
9790
|
} catch {}
|
|
9732
9791
|
if (!directory)
|
|
9733
|
-
return { dir:
|
|
9792
|
+
return { dir: path4.join(root, ".workit"), shared: false, top: null };
|
|
9734
9793
|
const fast = fastGit(root);
|
|
9735
9794
|
if (fast?.kind === "none")
|
|
9736
|
-
return { dir:
|
|
9795
|
+
return { dir: path4.join(root, ".workit"), shared: false, top: null };
|
|
9737
9796
|
if (fast?.kind === "repo")
|
|
9738
9797
|
return {
|
|
9739
|
-
dir:
|
|
9798
|
+
dir: path4.join(fast.common, "workit"),
|
|
9740
9799
|
shared: true,
|
|
9741
9800
|
top: fast.top,
|
|
9742
9801
|
git: { gitDir: fast.gitDir, top: fast.top, reftable: fast.reftable }
|
|
@@ -9746,20 +9805,20 @@ function resolveStore(root) {
|
|
|
9746
9805
|
if (run.ok && common) {
|
|
9747
9806
|
const top = gitRun(root, ["rev-parse", "--path-format=absolute", "--show-toplevel"]);
|
|
9748
9807
|
return {
|
|
9749
|
-
dir:
|
|
9808
|
+
dir: path4.join(real(path4.resolve(root, common)), "workit"),
|
|
9750
9809
|
shared: true,
|
|
9751
9810
|
top: top.ok && top.stdout.trim() ? real(top.stdout.trim()) : null
|
|
9752
9811
|
};
|
|
9753
9812
|
}
|
|
9754
9813
|
if (run.missing || !run.ok && NOT_A_REPO.test(run.stderr))
|
|
9755
|
-
return { dir:
|
|
9814
|
+
return { dir: path4.join(root, ".workit"), shared: false, top: null };
|
|
9756
9815
|
return new Error(`cannot locate the workit store: git rev-parse failed (${run.stderr.trim().split(`
|
|
9757
9816
|
`)[0] || "no output"}); fix the repository (git status should work here)`);
|
|
9758
9817
|
}
|
|
9759
9818
|
var rebasingBranch = (gitDir) => {
|
|
9760
9819
|
for (const state of ["rebase-merge", "rebase-apply"]) {
|
|
9761
9820
|
try {
|
|
9762
|
-
const ref = fs4.readFileSync(
|
|
9821
|
+
const ref = fs4.readFileSync(path4.join(gitDir, state, "head-name"), "utf8").trim();
|
|
9763
9822
|
const match = /^refs\/heads\/(.+)$/u.exec(ref);
|
|
9764
9823
|
if (match)
|
|
9765
9824
|
return match[1];
|
|
@@ -9774,7 +9833,7 @@ function resolveTaskKey(root, location) {
|
|
|
9774
9833
|
if (location.git && !location.git.reftable) {
|
|
9775
9834
|
let head = "";
|
|
9776
9835
|
try {
|
|
9777
|
-
head = fs4.readFileSync(
|
|
9836
|
+
head = fs4.readFileSync(path4.join(location.git.gitDir, "HEAD"), "utf8").trim();
|
|
9778
9837
|
} catch {}
|
|
9779
9838
|
const ref = /^ref: refs\/heads\/(.+)$/u.exec(head);
|
|
9780
9839
|
if (ref && ref[1] !== ".invalid")
|
|
@@ -9805,7 +9864,7 @@ function resolveTaskKey(root, location) {
|
|
|
9805
9864
|
return { key: `detached-${shortHash(real(worktree))}`, kind: "detached", branch: null };
|
|
9806
9865
|
}
|
|
9807
9866
|
function checkoutRootOf(root, location) {
|
|
9808
|
-
const resolved =
|
|
9867
|
+
const resolved = path4.resolve(root);
|
|
9809
9868
|
let canonical = resolved;
|
|
9810
9869
|
try {
|
|
9811
9870
|
canonical = fs4.realpathSync(resolved);
|
|
@@ -9836,13 +9895,13 @@ function branchRenames(location) {
|
|
|
9836
9895
|
}
|
|
9837
9896
|
for (const entry of entries)
|
|
9838
9897
|
if (entry.isDirectory())
|
|
9839
|
-
walk(
|
|
9898
|
+
walk(path4.join(dir, entry.name));
|
|
9840
9899
|
else
|
|
9841
|
-
files.push(
|
|
9900
|
+
files.push(path4.join(dir, entry.name));
|
|
9842
9901
|
};
|
|
9843
|
-
walk(
|
|
9902
|
+
walk(path4.join(path4.dirname(location.dir), "logs", "refs", "heads"));
|
|
9844
9903
|
if (location.git)
|
|
9845
|
-
files.push(
|
|
9904
|
+
files.push(path4.join(location.git.gitDir, "logs", "HEAD"));
|
|
9846
9905
|
const seen = new Set;
|
|
9847
9906
|
const renames = [];
|
|
9848
9907
|
for (const file of files) {
|
|
@@ -9877,7 +9936,7 @@ var checkoutSlug = (root) => {
|
|
|
9877
9936
|
let canonical = real(root);
|
|
9878
9937
|
if (process.platform === "win32")
|
|
9879
9938
|
canonical = canonical.toLowerCase();
|
|
9880
|
-
const base =
|
|
9939
|
+
const base = path4.basename(canonical).replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 40) || "root";
|
|
9881
9940
|
return `${base}-${shortHash(canonical)}`;
|
|
9882
9941
|
};
|
|
9883
9942
|
|
|
@@ -9910,30 +9969,64 @@ function hostSessionFromEnv(env) {
|
|
|
9910
9969
|
return inner ? { host: inner.host, session: inner.session } : { host: declared, session: null };
|
|
9911
9970
|
}
|
|
9912
9971
|
var ISSUED_PER_LEAD = 64;
|
|
9913
|
-
var ISSUED_SESSIONS_MARKER = "workit-issued-sessions/
|
|
9972
|
+
var ISSUED_SESSIONS_MARKER = "workit-issued-sessions/2";
|
|
9914
9973
|
var hash = (value) => createHash3("sha256").update(value).digest("hex").slice(0, 32);
|
|
9915
|
-
var
|
|
9916
|
-
|
|
9917
|
-
|
|
9974
|
+
var userIssuedRoot = () => path5.join(resolveStateDir(), "issued");
|
|
9975
|
+
function migrateRepoIssued(cwd) {
|
|
9976
|
+
if (cwd === undefined)
|
|
9977
|
+
return;
|
|
9978
|
+
let old;
|
|
9979
|
+
try {
|
|
9980
|
+
const location = resolveStore(cwd);
|
|
9981
|
+
if (location instanceof Error)
|
|
9982
|
+
return;
|
|
9983
|
+
old = path5.join(location.dir, "hooks", "issued");
|
|
9984
|
+
if (!fs5.existsSync(old))
|
|
9985
|
+
return;
|
|
9986
|
+
} catch {
|
|
9987
|
+
return;
|
|
9988
|
+
}
|
|
9989
|
+
for (const lead of safeList(old)) {
|
|
9990
|
+
try {
|
|
9991
|
+
const from = path5.join(old, lead);
|
|
9992
|
+
if (!fs5.statSync(from).isDirectory())
|
|
9993
|
+
continue;
|
|
9994
|
+
const to = path5.join(userIssuedRoot(), lead);
|
|
9995
|
+
fs5.mkdirSync(to, { recursive: true, mode: 448 });
|
|
9996
|
+
for (const id of fs5.readdirSync(from)) {
|
|
9997
|
+
fs5.copyFileSync(path5.join(from, id), path5.join(to, id));
|
|
9998
|
+
fs5.rmSync(path5.join(from, id), { force: true });
|
|
9999
|
+
}
|
|
10000
|
+
removeIfEmpty(from);
|
|
10001
|
+
} catch {}
|
|
10002
|
+
}
|
|
10003
|
+
removeIfEmpty(old);
|
|
10004
|
+
}
|
|
10005
|
+
var safeList = (dir) => {
|
|
10006
|
+
try {
|
|
10007
|
+
return fs5.readdirSync(dir);
|
|
10008
|
+
} catch {
|
|
10009
|
+
return [];
|
|
10010
|
+
}
|
|
9918
10011
|
};
|
|
9919
|
-
var
|
|
9920
|
-
|
|
9921
|
-
|
|
10012
|
+
var removeIfEmpty = (dir) => {
|
|
10013
|
+
try {
|
|
10014
|
+
fs5.rmdirSync(dir);
|
|
10015
|
+
} catch {}
|
|
9922
10016
|
};
|
|
9923
10017
|
function recordIssuedSession(cwd, lead, issued) {
|
|
9924
10018
|
try {
|
|
9925
|
-
|
|
9926
|
-
|
|
9927
|
-
|
|
9928
|
-
fs5.mkdirSync(dir, { recursive: true });
|
|
10019
|
+
migrateRepoIssued(cwd);
|
|
10020
|
+
const dir = path5.join(userIssuedRoot(), hash(lead));
|
|
10021
|
+
fs5.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
9929
10022
|
const own = hash(issued);
|
|
9930
|
-
fs5.writeFileSync(
|
|
10023
|
+
fs5.writeFileSync(path5.join(dir, own), ISSUED_SESSIONS_MARKER);
|
|
9931
10024
|
const entries = fs5.readdirSync(dir);
|
|
9932
10025
|
if (entries.length <= ISSUED_PER_LEAD)
|
|
9933
10026
|
return;
|
|
9934
|
-
const byAge = entries.filter((name) => name !== own).map((name) => ({ name, at: fs5.statSync(
|
|
10027
|
+
const byAge = entries.filter((name) => name !== own).map((name) => ({ name, at: fs5.statSync(path5.join(dir, name)).mtimeMs })).toSorted((a, b) => a.at - b.at);
|
|
9935
10028
|
for (const { name } of byAge.slice(0, entries.length - ISSUED_PER_LEAD))
|
|
9936
|
-
fs5.rmSync(
|
|
10029
|
+
fs5.rmSync(path5.join(dir, name), { force: true });
|
|
9937
10030
|
} catch {}
|
|
9938
10031
|
}
|
|
9939
10032
|
var OWN_CHILD_SHELL = new Set(["opencode", "pi"]);
|
|
@@ -9946,20 +10039,20 @@ function childSessionId(lead, child) {
|
|
|
9946
10039
|
|
|
9947
10040
|
// packages/workit-core/src/core/package-root.ts
|
|
9948
10041
|
import { existsSync } from "node:fs";
|
|
9949
|
-
import
|
|
10042
|
+
import path6 from "node:path";
|
|
9950
10043
|
import { fileURLToPath } from "node:url";
|
|
9951
10044
|
var packageRoot = () => {
|
|
9952
|
-
let dir =
|
|
10045
|
+
let dir = path6.dirname(fileURLToPath(import.meta.url));
|
|
9953
10046
|
while (true) {
|
|
9954
|
-
const parent =
|
|
9955
|
-
if (existsSync(
|
|
10047
|
+
const parent = path6.dirname(dir);
|
|
10048
|
+
if (existsSync(path6.join(dir, "package.json")) || parent === dir)
|
|
9956
10049
|
return dir;
|
|
9957
10050
|
dir = parent;
|
|
9958
10051
|
}
|
|
9959
10052
|
};
|
|
9960
10053
|
var assetRoot = () => {
|
|
9961
10054
|
const root = packageRoot();
|
|
9962
|
-
const assets =
|
|
10055
|
+
const assets = path6.join(root, "assets");
|
|
9963
10056
|
return existsSync(assets) ? assets : root;
|
|
9964
10057
|
};
|
|
9965
10058
|
|
|
@@ -10106,7 +10199,7 @@ var clearAbandonedReclaimGuard = (lockPath, nowMs = Date.now()) => {
|
|
|
10106
10199
|
// packages/workit-core/src/store/event-log.ts
|
|
10107
10200
|
import { randomUUID as randomUUID2 } from "node:crypto";
|
|
10108
10201
|
import fs7 from "node:fs";
|
|
10109
|
-
import
|
|
10202
|
+
import path7 from "node:path";
|
|
10110
10203
|
var EVENT_VERSION = 1;
|
|
10111
10204
|
|
|
10112
10205
|
class LogDamage extends Error {
|
|
@@ -10217,7 +10310,7 @@ function appendEvent(file, event, validEnd) {
|
|
|
10217
10310
|
fs7.closeSync(fd);
|
|
10218
10311
|
}
|
|
10219
10312
|
if (created)
|
|
10220
|
-
fsyncDirectory(
|
|
10313
|
+
fsyncDirectory(path7.dirname(file));
|
|
10221
10314
|
return validEnd;
|
|
10222
10315
|
}
|
|
10223
10316
|
function replaceFile(file, bytes, durable) {
|
|
@@ -10233,7 +10326,7 @@ function replaceFile(file, bytes, durable) {
|
|
|
10233
10326
|
}
|
|
10234
10327
|
renameWithRetry(temporary, file);
|
|
10235
10328
|
if (durable)
|
|
10236
|
-
fsyncDirectory(
|
|
10329
|
+
fsyncDirectory(path7.dirname(file));
|
|
10237
10330
|
} catch (error) {
|
|
10238
10331
|
try {
|
|
10239
10332
|
fs7.unlinkSync(temporary);
|
|
@@ -10576,7 +10669,7 @@ var cachedRuntimeVersion = null;
|
|
|
10576
10669
|
var runtimeVersion = () => {
|
|
10577
10670
|
if (cachedRuntimeVersion === null) {
|
|
10578
10671
|
try {
|
|
10579
|
-
const pkg = JSON.parse(fs8.readFileSync(
|
|
10672
|
+
const pkg = JSON.parse(fs8.readFileSync(path8.join(packageRoot(), "package.json"), "utf8"));
|
|
10580
10673
|
cachedRuntimeVersion = typeof pkg.version === "string" && pkg.version ? pkg.version : "0.0.0";
|
|
10581
10674
|
} catch {
|
|
10582
10675
|
cachedRuntimeVersion = "0.0.0";
|
|
@@ -10609,7 +10702,7 @@ var readText = (file) => {
|
|
|
10609
10702
|
};
|
|
10610
10703
|
var REFLOG_LINE = /^[0-9a-f]+ ([0-9a-f]+) .* (\d+) [+-]\d{4}\t(.*)$/u;
|
|
10611
10704
|
var branchStart = (location, branch, aliases) => {
|
|
10612
|
-
const first = readText(
|
|
10705
|
+
const first = readText(path8.join(path8.dirname(location.dir), "logs", "refs", "heads", branch)).split(`
|
|
10613
10706
|
`, 1)[0];
|
|
10614
10707
|
const created = REFLOG_LINE.exec(first);
|
|
10615
10708
|
const start = created && /^branch: Created from (\S+)$/u.exec(created[3])?.[1];
|
|
@@ -10619,7 +10712,7 @@ var branchStart = (location, branch, aliases) => {
|
|
|
10619
10712
|
return start;
|
|
10620
10713
|
if (!location.git)
|
|
10621
10714
|
return null;
|
|
10622
|
-
for (const line of readText(
|
|
10715
|
+
for (const line of readText(path8.join(location.git.gitDir, "logs", "HEAD")).split(`
|
|
10623
10716
|
`)) {
|
|
10624
10717
|
const entry = REFLOG_LINE.exec(line);
|
|
10625
10718
|
const moved = entry && /^checkout: moving from (\S+) to (\S+)$/u.exec(entry[3]);
|
|
@@ -10629,14 +10722,14 @@ var branchStart = (location, branch, aliases) => {
|
|
|
10629
10722
|
}
|
|
10630
10723
|
return null;
|
|
10631
10724
|
};
|
|
10632
|
-
var refExists = (common, ref) => fs8.existsSync(
|
|
10725
|
+
var refExists = (common, ref) => fs8.existsSync(path8.join(common, ref)) || readText(path8.join(common, "packed-refs")).includes(` ${ref}
|
|
10633
10726
|
`);
|
|
10634
10727
|
var origins = new Map;
|
|
10635
10728
|
var sameDirectoryIdentity = (left, right) => {
|
|
10636
|
-
if (!
|
|
10729
|
+
if (!path8.isAbsolute(left) || !path8.isAbsolute(right))
|
|
10637
10730
|
return false;
|
|
10638
|
-
const normalizedLeft =
|
|
10639
|
-
const normalizedRight =
|
|
10731
|
+
const normalizedLeft = path8.resolve(left);
|
|
10732
|
+
const normalizedRight = path8.resolve(right);
|
|
10640
10733
|
try {
|
|
10641
10734
|
const a = fs8.statSync(normalizedLeft, { bigint: true });
|
|
10642
10735
|
const b = fs8.statSync(normalizedRight, { bigint: true });
|
|
@@ -10682,7 +10775,7 @@ class TaskStore {
|
|
|
10682
10775
|
migrationChecked = false;
|
|
10683
10776
|
compactDue = new Set;
|
|
10684
10777
|
constructor(root, options = {}) {
|
|
10685
|
-
const resolved =
|
|
10778
|
+
const resolved = path8.resolve(root);
|
|
10686
10779
|
this.origin = fs8.existsSync(resolved) ? fs8.realpathSync(resolved) : resolved;
|
|
10687
10780
|
this.located = resolveStore(this.origin);
|
|
10688
10781
|
this.root = checkoutRootOf(this.origin, this.located);
|
|
@@ -10691,7 +10784,7 @@ class TaskStore {
|
|
|
10691
10784
|
this.migrateOnRead = options.migrateOnRead;
|
|
10692
10785
|
}
|
|
10693
10786
|
location() {
|
|
10694
|
-
if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared && fs8.existsSync(
|
|
10787
|
+
if (this.located !== undefined && !(this.located instanceof Error) && !this.located.shared && fs8.existsSync(path8.join(this.root, ".git"))) {
|
|
10695
10788
|
this.located = undefined;
|
|
10696
10789
|
this.migrationChecked = false;
|
|
10697
10790
|
}
|
|
@@ -10847,7 +10940,7 @@ class TaskStore {
|
|
|
10847
10940
|
const moved = this.bindLocked(again.data.id, key, input.now);
|
|
10848
10941
|
return moved.ok ? success(moved.data.revision, null, { task: moved.data, created: false, key }) : moved;
|
|
10849
10942
|
}
|
|
10850
|
-
const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" :
|
|
10943
|
+
const label = key.kind === "branch" ? `branch ${key.branch}` : key.kind === "detached" ? "a detached HEAD" : path8.basename(this.root) || this.root;
|
|
10851
10944
|
const intent = {
|
|
10852
10945
|
objective: input.objective?.trim() || `Work on ${label}`,
|
|
10853
10946
|
scope: { description: `the checkout (${label})`, paths: ["."], exclusions: [] },
|
|
@@ -10907,14 +11000,14 @@ class TaskStore {
|
|
|
10907
11000
|
const branch = key.ok ? key.data.branch : null;
|
|
10908
11001
|
if (!branch || !location.ok)
|
|
10909
11002
|
return success(null, null, null);
|
|
10910
|
-
const common =
|
|
10911
|
-
const heads =
|
|
10912
|
-
const headLog = location.data.git ?
|
|
11003
|
+
const common = path8.dirname(location.data.dir);
|
|
11004
|
+
const heads = path8.join(common, "logs", "refs", "heads");
|
|
11005
|
+
const headLog = location.data.git ? path8.join(location.data.git.gitDir, "logs", "HEAD") : "";
|
|
10913
11006
|
const signatures = [
|
|
10914
|
-
|
|
11007
|
+
path8.join(heads, branch),
|
|
10915
11008
|
headLog,
|
|
10916
11009
|
heads,
|
|
10917
|
-
|
|
11010
|
+
path8.join(common, "packed-refs")
|
|
10918
11011
|
].map((file) => fileSignature(file) ?? "-");
|
|
10919
11012
|
const slot = `${location.data.dir}\x00${headLog}\x00${branch}`;
|
|
10920
11013
|
let resolved = origins.get(slot);
|
|
@@ -10926,7 +11019,7 @@ class TaskStore {
|
|
|
10926
11019
|
aliases.push(rename.from);
|
|
10927
11020
|
const start = branchStart(location.data, branch, aliases);
|
|
10928
11021
|
const slash = start?.indexOf("/") ?? -1;
|
|
10929
|
-
const remote = slash > 0 && !refExists(common, `refs/heads/${start}`) && (refExists(common, `refs/remotes/${start}`) || readText(
|
|
11022
|
+
const remote = slash > 0 && !refExists(common, `refs/heads/${start}`) && (refExists(common, `refs/remotes/${start}`) || readText(path8.join(common, "config")).includes(`[remote "${start.slice(0, slash)}"]`));
|
|
10930
11023
|
const name = start && (remote ? start.slice(slash + 1) : start);
|
|
10931
11024
|
resolved = {
|
|
10932
11025
|
signature: signatures.join("|"),
|
|
@@ -11164,13 +11257,13 @@ class TaskStore {
|
|
|
11164
11257
|
if (!ready.ok)
|
|
11165
11258
|
return ready;
|
|
11166
11259
|
const dirs = this.paths();
|
|
11167
|
-
const recovery =
|
|
11260
|
+
const recovery = path8.join(this.root, ".workit", "recovery");
|
|
11168
11261
|
if (fs8.existsSync(recovery)) {
|
|
11169
11262
|
let files = 0;
|
|
11170
11263
|
let bytes = 0;
|
|
11171
11264
|
try {
|
|
11172
11265
|
for (const name of fs8.readdirSync(recovery)) {
|
|
11173
|
-
const stat = fs8.lstatSync(
|
|
11266
|
+
const stat = fs8.lstatSync(path8.join(recovery, name));
|
|
11174
11267
|
if (!stat.isFile())
|
|
11175
11268
|
continue;
|
|
11176
11269
|
files += 1;
|
|
@@ -11223,7 +11316,7 @@ class TaskStore {
|
|
|
11223
11316
|
if (fs8.existsSync(dirs.blobs))
|
|
11224
11317
|
for (const name of fs8.readdirSync(dirs.blobs)) {
|
|
11225
11318
|
const digest = name.replace(/\.json$/, "");
|
|
11226
|
-
const file =
|
|
11319
|
+
const file = path8.join(dirs.blobs, name);
|
|
11227
11320
|
let stat;
|
|
11228
11321
|
try {
|
|
11229
11322
|
stat = fs8.lstatSync(file);
|
|
@@ -11241,7 +11334,7 @@ class TaskStore {
|
|
|
11241
11334
|
}
|
|
11242
11335
|
return success(null, null, null);
|
|
11243
11336
|
};
|
|
11244
|
-
const swept = dryRun ? sweep() : this.withLock(
|
|
11337
|
+
const swept = dryRun ? sweep() : this.withLock(path8.join(dirs.dir, "gc.lock"), sweep);
|
|
11245
11338
|
if (!swept.ok)
|
|
11246
11339
|
return swept;
|
|
11247
11340
|
const temporaryDirs = [
|
|
@@ -11249,7 +11342,7 @@ class TaskStore {
|
|
|
11249
11342
|
dirs.tasks,
|
|
11250
11343
|
dirs.blobs,
|
|
11251
11344
|
dirs.checkout,
|
|
11252
|
-
...names.map((name) =>
|
|
11345
|
+
...names.map((name) => path8.join(dirs.tasks, name))
|
|
11253
11346
|
];
|
|
11254
11347
|
for (const directory of temporaryDirs) {
|
|
11255
11348
|
if (!fs8.existsSync(directory))
|
|
@@ -11257,7 +11350,7 @@ class TaskStore {
|
|
|
11257
11350
|
for (const name of fs8.readdirSync(directory)) {
|
|
11258
11351
|
if (!name.endsWith(".tmp") && !name.endsWith(".probe"))
|
|
11259
11352
|
continue;
|
|
11260
|
-
const file =
|
|
11353
|
+
const file = path8.join(directory, name);
|
|
11261
11354
|
try {
|
|
11262
11355
|
const stat = fs8.lstatSync(file);
|
|
11263
11356
|
if (!stat.isFile() || nowMs - stat.mtimeMs <= STALE_TEMPORARY_MS)
|
|
@@ -11274,30 +11367,30 @@ class TaskStore {
|
|
|
11274
11367
|
}
|
|
11275
11368
|
paths() {
|
|
11276
11369
|
const location = this.location();
|
|
11277
|
-
const dir = location.ok ? location.data.dir :
|
|
11278
|
-
const checkout =
|
|
11370
|
+
const dir = location.ok ? location.data.dir : path8.join(this.root, ".workit");
|
|
11371
|
+
const checkout = path8.join(dir, "checkouts", checkoutSlug(this.root));
|
|
11279
11372
|
return {
|
|
11280
11373
|
dir,
|
|
11281
11374
|
shared: location.ok ? location.data.shared : false,
|
|
11282
|
-
marker:
|
|
11375
|
+
marker: path8.join(dir, "store.json"),
|
|
11283
11376
|
checkout,
|
|
11284
|
-
workspace:
|
|
11285
|
-
checkoutLock:
|
|
11286
|
-
tasks:
|
|
11287
|
-
index:
|
|
11288
|
-
blobs:
|
|
11289
|
-
legacy:
|
|
11290
|
-
v2:
|
|
11377
|
+
workspace: path8.join(checkout, "workspace.json"),
|
|
11378
|
+
checkoutLock: path8.join(checkout, "metadata.lock"),
|
|
11379
|
+
tasks: path8.join(dir, "tasks"),
|
|
11380
|
+
index: path8.join(dir, "task-index.json"),
|
|
11381
|
+
blobs: path8.join(dir, "blobs", "candidates"),
|
|
11382
|
+
legacy: path8.join(dir, "legacy", checkoutSlug(this.root), "v2"),
|
|
11383
|
+
v2: path8.join(this.root, ".workit")
|
|
11291
11384
|
};
|
|
11292
11385
|
}
|
|
11293
11386
|
eventsPath(taskId) {
|
|
11294
|
-
return
|
|
11387
|
+
return path8.join(this.paths().tasks, taskId, "events.jsonl");
|
|
11295
11388
|
}
|
|
11296
11389
|
snapshotPath(taskId) {
|
|
11297
|
-
return
|
|
11390
|
+
return path8.join(this.paths().tasks, taskId, "snapshot.json");
|
|
11298
11391
|
}
|
|
11299
11392
|
taskLockPath(taskId) {
|
|
11300
|
-
return
|
|
11393
|
+
return path8.join(this.paths().tasks, taskId, "lock");
|
|
11301
11394
|
}
|
|
11302
11395
|
ready(write = false) {
|
|
11303
11396
|
const location = this.location();
|
|
@@ -11336,13 +11429,13 @@ class TaskStore {
|
|
|
11336
11429
|
return {
|
|
11337
11430
|
read: (digest) => {
|
|
11338
11431
|
try {
|
|
11339
|
-
return JSON.parse(fs8.readFileSync(
|
|
11432
|
+
return JSON.parse(fs8.readFileSync(path8.join(dir, `${digest}.json`), "utf8"));
|
|
11340
11433
|
} catch (error) {
|
|
11341
11434
|
throw new LogDamage(`stored candidate ${digest} is missing or unreadable: ${String(error)}`);
|
|
11342
11435
|
}
|
|
11343
11436
|
},
|
|
11344
11437
|
write: (digest, value) => {
|
|
11345
|
-
const file =
|
|
11438
|
+
const file = path8.join(dir, `${digest}.json`);
|
|
11346
11439
|
if (fs8.existsSync(file)) {
|
|
11347
11440
|
const stamp = new Date;
|
|
11348
11441
|
try {
|
|
@@ -11534,7 +11627,7 @@ class TaskStore {
|
|
|
11534
11627
|
}
|
|
11535
11628
|
}
|
|
11536
11629
|
openTask(record, type, key, legacy = null) {
|
|
11537
|
-
const dir =
|
|
11630
|
+
const dir = path8.join(this.paths().tasks, record.id);
|
|
11538
11631
|
fs8.mkdirSync(dir, { recursive: true });
|
|
11539
11632
|
const blobs = this.blobStore();
|
|
11540
11633
|
const bound = key ? { ...key, boundAt: key.boundAt ?? new Date().toISOString() } : null;
|
|
@@ -11627,7 +11720,7 @@ class TaskStore {
|
|
|
11627
11720
|
}
|
|
11628
11721
|
withKeyLock(key, operation) {
|
|
11629
11722
|
const digest = createHash5("sha256").update(key).digest("hex").slice(0, 32);
|
|
11630
|
-
return this.withLock(
|
|
11723
|
+
return this.withLock(path8.join(this.paths().dir, "keys", `${digest}.lock`), operation);
|
|
11631
11724
|
}
|
|
11632
11725
|
bindLocked(taskId, key, timestamp) {
|
|
11633
11726
|
const current = this.readWorkspace();
|
|
@@ -11768,7 +11861,7 @@ class TaskStore {
|
|
|
11768
11861
|
writeWorkspace(record) {
|
|
11769
11862
|
const file = this.paths().workspace;
|
|
11770
11863
|
try {
|
|
11771
|
-
fs8.mkdirSync(
|
|
11864
|
+
fs8.mkdirSync(path8.dirname(file), { recursive: true });
|
|
11772
11865
|
replaceFile(file, `${canonicalJson(record)}
|
|
11773
11866
|
`, true);
|
|
11774
11867
|
return success(null, null, null);
|
|
@@ -11846,23 +11939,23 @@ class TaskStore {
|
|
|
11846
11939
|
return failure2("revision_conflict", "workspace revision does not match; omit expectedWorkspaceRevision to use the current record", { expectedWorkspaceRevision: expected, actualWorkspaceRevision: actual });
|
|
11847
11940
|
}
|
|
11848
11941
|
v2Dirs() {
|
|
11849
|
-
return [...new Set([this.root, this.origin])].map((dir) =>
|
|
11942
|
+
return [...new Set([this.root, this.origin])].map((dir) => path8.join(dir, ".workit"));
|
|
11850
11943
|
}
|
|
11851
11944
|
pendingMigrations() {
|
|
11852
11945
|
return this.v2Dirs().filter((dir) => {
|
|
11853
|
-
const raw = this.readV2Workspace(
|
|
11946
|
+
const raw = this.readV2Workspace(path8.join(dir, "workspace.json"));
|
|
11854
11947
|
return raw !== null && raw !== TOMBSTONE;
|
|
11855
11948
|
});
|
|
11856
11949
|
}
|
|
11857
11950
|
migrateV2(v2) {
|
|
11858
11951
|
const dirs = this.paths();
|
|
11859
|
-
const v2Workspace =
|
|
11860
|
-
const v2Tasks =
|
|
11861
|
-
const legacy =
|
|
11952
|
+
const v2Workspace = path8.join(v2, "workspace.json");
|
|
11953
|
+
const v2Tasks = path8.join(v2, "tasks");
|
|
11954
|
+
const legacy = path8.join(dirs.dir, "legacy", checkoutSlug(path8.dirname(v2)), "v2");
|
|
11862
11955
|
const raw = this.readV2Workspace(v2Workspace);
|
|
11863
11956
|
if (raw === null || raw === TOMBSTONE)
|
|
11864
11957
|
return success(null, null, null);
|
|
11865
|
-
return this.withLock(dirs.checkoutLock, () => this.withLock(
|
|
11958
|
+
return this.withLock(dirs.checkoutLock, () => this.withLock(path8.join(v2, "metadata.lock"), () => {
|
|
11866
11959
|
const workspace = this.readV2Workspace(v2Workspace);
|
|
11867
11960
|
if (workspace === null || workspace === TOMBSTONE)
|
|
11868
11961
|
return success(null, null, null);
|
|
@@ -11871,7 +11964,7 @@ class TaskStore {
|
|
|
11871
11964
|
return failure2("recovery_required", `cannot migrate the 2.x store at ${v2}: ${parsedWorkspace.error}; move it aside to start fresh`, { path: v2Workspace });
|
|
11872
11965
|
let files = [];
|
|
11873
11966
|
try {
|
|
11874
|
-
files = fs8.readdirSync(v2Tasks).filter((name) => name.endsWith(".json") && validId(name.slice(0, -5))).filter((name) => !this.isStub(
|
|
11967
|
+
files = fs8.readdirSync(v2Tasks).filter((name) => name.endsWith(".json") && validId(name.slice(0, -5))).filter((name) => !this.isStub(path8.join(v2Tasks, name)));
|
|
11875
11968
|
} catch {}
|
|
11876
11969
|
const current = this.readWorkspace();
|
|
11877
11970
|
if (!current.ok)
|
|
@@ -11889,21 +11982,21 @@ class TaskStore {
|
|
|
11889
11982
|
let skipped = 0;
|
|
11890
11983
|
const done = new Map;
|
|
11891
11984
|
try {
|
|
11892
|
-
fs8.mkdirSync(
|
|
11985
|
+
fs8.mkdirSync(path8.join(legacy, "tasks"), { recursive: true });
|
|
11893
11986
|
for (const name of ["workspace.json", "index.json"])
|
|
11894
|
-
if (fs8.existsSync(
|
|
11895
|
-
fs8.copyFileSync(
|
|
11987
|
+
if (fs8.existsSync(path8.join(v2, name)))
|
|
11988
|
+
fs8.copyFileSync(path8.join(v2, name), path8.join(legacy, name));
|
|
11896
11989
|
for (const name of files) {
|
|
11897
11990
|
const id = name.slice(0, -5);
|
|
11898
|
-
const file =
|
|
11991
|
+
const file = path8.join(v2Tasks, name);
|
|
11899
11992
|
const bytes = fs8.readFileSync(file, "utf8");
|
|
11900
11993
|
const digest = sha256(bytes);
|
|
11901
|
-
fs8.writeFileSync(
|
|
11994
|
+
fs8.writeFileSync(path8.join(legacy, "tasks", name), bytes);
|
|
11902
11995
|
const parsed = this.parseRecord(bytes, taskRecordSchema, "2.x task");
|
|
11903
11996
|
if (!parsed.ok || parsed.data.id !== id)
|
|
11904
11997
|
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 });
|
|
11905
11998
|
const record = { ...parsed.data, workspaceId: target.id };
|
|
11906
|
-
const origin = { path:
|
|
11999
|
+
const origin = { path: path8.join(legacy, "tasks", name), digest };
|
|
11907
12000
|
if (!fs8.existsSync(this.eventsPath(id))) {
|
|
11908
12001
|
this.openTask(record, "migrated.from_v2", null, origin);
|
|
11909
12002
|
migrated += 1;
|
|
@@ -11939,7 +12032,7 @@ class TaskStore {
|
|
|
11939
12032
|
try {
|
|
11940
12033
|
let complete = true;
|
|
11941
12034
|
for (const [name, digest] of done) {
|
|
11942
|
-
const file =
|
|
12035
|
+
const file = path8.join(v2Tasks, name);
|
|
11943
12036
|
if (sha256(fs8.readFileSync(file, "utf8")) !== digest) {
|
|
11944
12037
|
complete = false;
|
|
11945
12038
|
continue;
|
|
@@ -11950,7 +12043,7 @@ class TaskStore {
|
|
|
11950
12043
|
return failure2("busy", `the 2.x store at ${v2} changed during migration; retry`, {
|
|
11951
12044
|
path: v2
|
|
11952
12045
|
});
|
|
11953
|
-
fs8.rmSync(
|
|
12046
|
+
fs8.rmSync(path8.join(v2, "index.json"), { force: true });
|
|
11954
12047
|
this.writeTombstone(v2, target.id);
|
|
11955
12048
|
} catch (error) {
|
|
11956
12049
|
return failure2("storage_error", `cannot finish the 2.x migration: ${String(error)}`, {
|
|
@@ -11970,7 +12063,7 @@ class TaskStore {
|
|
|
11970
12063
|
}
|
|
11971
12064
|
adoptLocalStore() {
|
|
11972
12065
|
const dirs = this.paths();
|
|
11973
|
-
const marker =
|
|
12066
|
+
const marker = path8.join(dirs.v2, "store.json");
|
|
11974
12067
|
if (!dirs.shared || !fs8.existsSync(marker))
|
|
11975
12068
|
return success(null, null, null);
|
|
11976
12069
|
return this.withLock(dirs.checkoutLock, () => {
|
|
@@ -11980,7 +12073,7 @@ class TaskStore {
|
|
|
11980
12073
|
try {
|
|
11981
12074
|
const merge = (from, to) => {
|
|
11982
12075
|
if (!fs8.existsSync(to)) {
|
|
11983
|
-
fs8.mkdirSync(
|
|
12076
|
+
fs8.mkdirSync(path8.dirname(to), { recursive: true });
|
|
11984
12077
|
try {
|
|
11985
12078
|
fs8.renameSync(from, to);
|
|
11986
12079
|
} catch {
|
|
@@ -11991,24 +12084,24 @@ class TaskStore {
|
|
|
11991
12084
|
}
|
|
11992
12085
|
if (fs8.lstatSync(from).isDirectory() && fs8.lstatSync(to).isDirectory())
|
|
11993
12086
|
for (const name of fs8.readdirSync(from))
|
|
11994
|
-
merge(
|
|
12087
|
+
merge(path8.join(from, name), path8.join(to, name));
|
|
11995
12088
|
};
|
|
11996
12089
|
for (const sub of ["tasks", "checkouts", "blobs", "legacy"]) {
|
|
11997
|
-
const from =
|
|
12090
|
+
const from = path8.join(dirs.v2, sub);
|
|
11998
12091
|
if (!fs8.existsSync(from))
|
|
11999
12092
|
continue;
|
|
12000
12093
|
if (sub === "tasks") {
|
|
12001
12094
|
for (const name of fs8.readdirSync(from))
|
|
12002
|
-
if (validId(name) && !fs8.existsSync(
|
|
12095
|
+
if (validId(name) && !fs8.existsSync(path8.join(dirs.dir, sub, name)))
|
|
12003
12096
|
tasks += 1;
|
|
12004
12097
|
}
|
|
12005
|
-
merge(from,
|
|
12098
|
+
merge(from, path8.join(dirs.dir, sub));
|
|
12006
12099
|
}
|
|
12007
|
-
const ledger =
|
|
12008
|
-
if (fs8.existsSync(ledger) && !fs8.existsSync(
|
|
12009
|
-
merge(ledger,
|
|
12010
|
-
fs8.rmSync(
|
|
12011
|
-
fs8.renameSync(marker,
|
|
12100
|
+
const ledger = path8.join(dirs.v2, "ledger");
|
|
12101
|
+
if (fs8.existsSync(ledger) && !fs8.existsSync(path8.join(dirs.dir, "ledger")))
|
|
12102
|
+
merge(ledger, path8.join(dirs.dir, "ledger"));
|
|
12103
|
+
fs8.rmSync(path8.join(dirs.v2, "task-index.json"), { force: true });
|
|
12104
|
+
fs8.renameSync(marker, path8.join(dirs.v2, "store.moved.json"));
|
|
12012
12105
|
} catch (error) {
|
|
12013
12106
|
return failure2("storage_error", `cannot move ${dirs.v2} into ${dirs.dir}: ${String(error)}`, {
|
|
12014
12107
|
path: dirs.v2
|
|
@@ -12046,7 +12139,7 @@ class TaskStore {
|
|
|
12046
12139
|
schemaVersion: SCHEMA_VERSION,
|
|
12047
12140
|
id: workspaceId ?? newId(),
|
|
12048
12141
|
revision: newRevision(),
|
|
12049
|
-
root:
|
|
12142
|
+
root: path8.dirname(v2),
|
|
12050
12143
|
runtime: { createdWith: version, updatedWith: version },
|
|
12051
12144
|
writer: null,
|
|
12052
12145
|
store: {
|
|
@@ -12058,11 +12151,11 @@ class TaskStore {
|
|
|
12058
12151
|
critical: ["store"]
|
|
12059
12152
|
};
|
|
12060
12153
|
fs8.mkdirSync(v2, { recursive: true });
|
|
12061
|
-
const ignore =
|
|
12154
|
+
const ignore = path8.join(v2, ".gitignore");
|
|
12062
12155
|
if (!fs8.existsSync(ignore))
|
|
12063
12156
|
fs8.writeFileSync(ignore, `*
|
|
12064
12157
|
`);
|
|
12065
|
-
replaceFile(
|
|
12158
|
+
replaceFile(path8.join(v2, "workspace.json"), `${JSON.stringify(marker, null, 2)}
|
|
12066
12159
|
`, true);
|
|
12067
12160
|
}
|
|
12068
12161
|
stubFor(taskId) {
|
|
@@ -12086,8 +12179,8 @@ class TaskStore {
|
|
|
12086
12179
|
}
|
|
12087
12180
|
writeTombstoneIfMissing() {
|
|
12088
12181
|
try {
|
|
12089
|
-
const v2 =
|
|
12090
|
-
if (fs8.existsSync(
|
|
12182
|
+
const v2 = path8.join(this.root, ".workit");
|
|
12183
|
+
if (fs8.existsSync(path8.join(v2, "workspace.json")))
|
|
12091
12184
|
return;
|
|
12092
12185
|
let id = null;
|
|
12093
12186
|
try {
|
|
@@ -12104,7 +12197,7 @@ class TaskStore {
|
|
|
12104
12197
|
replaceFile(dirs.marker, `${JSON.stringify({ format: "workit-store", version: STORE_FORMAT, createdWith: runtimeVersion() })}
|
|
12105
12198
|
`, false);
|
|
12106
12199
|
if (!dirs.shared) {
|
|
12107
|
-
const ignore =
|
|
12200
|
+
const ignore = path8.join(dirs.dir, ".gitignore");
|
|
12108
12201
|
let current = null;
|
|
12109
12202
|
try {
|
|
12110
12203
|
current = fs8.readFileSync(ignore, "utf8");
|
|
@@ -12164,7 +12257,7 @@ class TaskStore {
|
|
|
12164
12257
|
withLock(lockPath, operation) {
|
|
12165
12258
|
try {
|
|
12166
12259
|
this.initializeStorage();
|
|
12167
|
-
fs8.mkdirSync(
|
|
12260
|
+
fs8.mkdirSync(path8.dirname(lockPath), { recursive: true });
|
|
12168
12261
|
} catch (error) {
|
|
12169
12262
|
return failure2("storage_error", `unable to initialize store: ${String(error)}`, {
|
|
12170
12263
|
path: this.paths().dir
|
|
@@ -12227,7 +12320,7 @@ class TaskStore {
|
|
|
12227
12320
|
if (isTransientWindowsError(error) && !this.lockHolderPresent(lockPath) && !this.lockDirWritable(lockPath))
|
|
12228
12321
|
return failure2("storage_error", `cannot create the workit lock (${code}); no other Workit call holds it`, {
|
|
12229
12322
|
path: lockPath,
|
|
12230
|
-
guidance: `Check permissions and the read-only attribute on ${
|
|
12323
|
+
guidance: `Check permissions and the read-only attribute on ${path8.dirname(lockPath)}.`
|
|
12231
12324
|
});
|
|
12232
12325
|
if (code === "EEXIST" || code === "file_lock_timeout" || code === "file_lock_stale" || isTransientWindowsError(error)) {
|
|
12233
12326
|
let lock = null;
|
|
@@ -12253,12 +12346,12 @@ var workerBlocksTransition = (transition, state) => transition === "pause" ? fal
|
|
|
12253
12346
|
import { createHash as createHash10 } from "node:crypto";
|
|
12254
12347
|
import * as fs13 from "node:fs";
|
|
12255
12348
|
import { spawnSync as spawnSync10 } from "node:child_process";
|
|
12256
|
-
import
|
|
12349
|
+
import path16 from "node:path";
|
|
12257
12350
|
|
|
12258
12351
|
// packages/workit-core/src/check-config.ts
|
|
12259
12352
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
12260
12353
|
import fs9 from "node:fs";
|
|
12261
|
-
import
|
|
12354
|
+
import path9 from "node:path";
|
|
12262
12355
|
var SCRIPT_CHECKS = ["test", "lint", "typecheck", "check"];
|
|
12263
12356
|
var CHECKS_FILE = "workit.checks.json";
|
|
12264
12357
|
var isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
@@ -12311,10 +12404,10 @@ var git = (cwd, args) => {
|
|
|
12311
12404
|
return value || null;
|
|
12312
12405
|
};
|
|
12313
12406
|
function checkRoot(cwd) {
|
|
12314
|
-
return
|
|
12407
|
+
return path9.resolve(git(cwd, ["rev-parse", "--show-toplevel"]) ?? cwd);
|
|
12315
12408
|
}
|
|
12316
12409
|
var packageManager = (root) => {
|
|
12317
|
-
const has = (file) => fs9.existsSync(
|
|
12410
|
+
const has = (file) => fs9.existsSync(path9.join(root, file));
|
|
12318
12411
|
if (has("bun.lock") || has("bun.lockb"))
|
|
12319
12412
|
return "bun";
|
|
12320
12413
|
if (has("pnpm-lock.yaml"))
|
|
@@ -12334,7 +12427,7 @@ var CHECK_NAME = /^[a-z0-9][a-z0-9:._-]{0,63}$/u;
|
|
|
12334
12427
|
function detectedChecks(root) {
|
|
12335
12428
|
const read = (file) => {
|
|
12336
12429
|
try {
|
|
12337
|
-
return fs9.readFileSync(
|
|
12430
|
+
return fs9.readFileSync(path9.join(root, file), "utf8");
|
|
12338
12431
|
} catch {
|
|
12339
12432
|
return null;
|
|
12340
12433
|
}
|
|
@@ -12373,7 +12466,7 @@ function detectedChecks(root) {
|
|
|
12373
12466
|
var GATES = ["testing", "verification"];
|
|
12374
12467
|
function loadCheckConfig(cwd) {
|
|
12375
12468
|
const root = checkRoot(cwd);
|
|
12376
|
-
const file =
|
|
12469
|
+
const file = path9.join(root, CHECKS_FILE);
|
|
12377
12470
|
const none = (error = null) => ({
|
|
12378
12471
|
source: error ? CHECKS_FILE : "none",
|
|
12379
12472
|
root,
|
|
@@ -12446,10 +12539,10 @@ function workitAvailable(env = process.env) {
|
|
|
12446
12539
|
return workitOnPath;
|
|
12447
12540
|
const windows = process.platform === "win32";
|
|
12448
12541
|
const exts = windows ? (env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean) : [""];
|
|
12449
|
-
const dirs = (env.PATH ?? env.Path ?? "").split(
|
|
12542
|
+
const dirs = (env.PATH ?? env.Path ?? "").split(path9.delimiter).filter(Boolean);
|
|
12450
12543
|
workitOnPath = dirs.some((dir) => exts.some((ext) => {
|
|
12451
12544
|
try {
|
|
12452
|
-
return fs9.statSync(
|
|
12545
|
+
return fs9.statSync(path9.join(dir, `workit${ext}`)).isFile();
|
|
12453
12546
|
} catch {
|
|
12454
12547
|
return false;
|
|
12455
12548
|
}
|
|
@@ -12464,8 +12557,8 @@ function checkCommand(args, version, onPath = workitAvailable()) {
|
|
|
12464
12557
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
12465
12558
|
import { createHash as createHash6 } from "node:crypto";
|
|
12466
12559
|
import fs10 from "node:fs";
|
|
12467
|
-
import
|
|
12468
|
-
import
|
|
12560
|
+
import os2 from "node:os";
|
|
12561
|
+
import path10 from "node:path";
|
|
12469
12562
|
var MAX_BUFFER = 256 * 1024 * 1024;
|
|
12470
12563
|
var GIT_TIMEOUTS = { local: 20000, worktree: 120000, network: 15000 };
|
|
12471
12564
|
var git2 = (cwd, args, options = {}) => {
|
|
@@ -12512,9 +12605,9 @@ function worktreeTree(cwd, options = {}) {
|
|
|
12512
12605
|
return null;
|
|
12513
12606
|
const cap = options.maxUntrackedBytes ?? MAX_UNTRACKED_BYTES;
|
|
12514
12607
|
const timeoutMs = options.timeoutMs ?? GIT_TIMEOUTS.worktree;
|
|
12515
|
-
const scratch = fs10.mkdtempSync(
|
|
12608
|
+
const scratch = fs10.mkdtempSync(path10.join(os2.tmpdir(), "workit-tree-"));
|
|
12516
12609
|
try {
|
|
12517
|
-
const tempIndex =
|
|
12610
|
+
const tempIndex = path10.join(scratch, "index");
|
|
12518
12611
|
if (fs10.existsSync(indexPath))
|
|
12519
12612
|
seedIndex(indexPath, tempIndex);
|
|
12520
12613
|
const env = { ...process.env, GIT_INDEX_FILE: tempIndex };
|
|
@@ -12527,7 +12620,7 @@ function worktreeTree(cwd, options = {}) {
|
|
|
12527
12620
|
const skipped = [];
|
|
12528
12621
|
for (const file of untracked.stdout.split("\x00").filter(Boolean)) {
|
|
12529
12622
|
try {
|
|
12530
|
-
const stat = fs10.statSync(
|
|
12623
|
+
const stat = fs10.statSync(path10.join(top, file));
|
|
12531
12624
|
if (stat.isFile() && stat.size > cap)
|
|
12532
12625
|
skipped.push({ path: file, size: stat.size, mtimeMs: Math.trunc(stat.mtimeMs) });
|
|
12533
12626
|
} catch {}
|
|
@@ -12573,7 +12666,7 @@ function worktreeSignal(cwd, options = {}) {
|
|
|
12573
12666
|
if (entry.length < 4)
|
|
12574
12667
|
continue;
|
|
12575
12668
|
const file = entry.slice(3);
|
|
12576
|
-
const absolute =
|
|
12669
|
+
const absolute = path10.join(top, file);
|
|
12577
12670
|
let stat = "-";
|
|
12578
12671
|
try {
|
|
12579
12672
|
const info = fs10.lstatSync(absolute, { bigint: true });
|
|
@@ -12643,17 +12736,17 @@ function pushRemoteName(cwd, branch) {
|
|
|
12643
12736
|
|
|
12644
12737
|
// packages/workit-core/src/core/policy/derive.ts
|
|
12645
12738
|
import { existsSync as existsSync4 } from "node:fs";
|
|
12646
|
-
import
|
|
12739
|
+
import path15 from "node:path";
|
|
12647
12740
|
|
|
12648
12741
|
// packages/workit-core/src/ledger.ts
|
|
12649
12742
|
import { spawnSync as spawnSync9 } from "node:child_process";
|
|
12650
12743
|
import { createHash as createHash9, randomBytes as randomBytes2 } from "node:crypto";
|
|
12651
12744
|
import fs12 from "node:fs";
|
|
12652
|
-
import
|
|
12745
|
+
import path14 from "node:path";
|
|
12653
12746
|
|
|
12654
12747
|
// packages/workit-core/src/core/vcs-config.ts
|
|
12655
12748
|
import fs11 from "node:fs";
|
|
12656
|
-
import
|
|
12749
|
+
import path13 from "node:path";
|
|
12657
12750
|
import { spawnSync as spawnSync8 } from "node:child_process";
|
|
12658
12751
|
|
|
12659
12752
|
// packages/workit-core/src/core/config.ts
|
|
@@ -12666,8 +12759,8 @@ import {
|
|
|
12666
12759
|
readdirSync as readdirSync2,
|
|
12667
12760
|
writeFileSync as writeFileSync2
|
|
12668
12761
|
} from "node:fs";
|
|
12669
|
-
import
|
|
12670
|
-
import
|
|
12762
|
+
import os3 from "node:os";
|
|
12763
|
+
import path11 from "node:path";
|
|
12671
12764
|
|
|
12672
12765
|
// packages/workit-core/src/core/boundary.ts
|
|
12673
12766
|
var EVENT = {
|
|
@@ -12711,7 +12804,7 @@ var mergePreset = (preset, input = {}, current = {
|
|
|
12711
12804
|
protected: preset === "custom" ? input.protectedNames ?? current.branchPolicy.protected : [...defs.protected]
|
|
12712
12805
|
};
|
|
12713
12806
|
};
|
|
12714
|
-
var resolveConfigDir = () => process.env.WORKFLOW_TOOLKIT_CONFIG ?? process.env.WORKFLOW_TOOLKIT_CONFIG_DIR ??
|
|
12807
|
+
var resolveConfigDir = () => process.env.WORKFLOW_TOOLKIT_CONFIG ?? process.env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path11.join(process.env.XDG_CONFIG_HOME || path11.join(os3.homedir(), ".config"), "workit");
|
|
12715
12808
|
var migratedDir = null;
|
|
12716
12809
|
var migrationFailed = false;
|
|
12717
12810
|
var ensureConfigDir = (dir = resolveConfigDir()) => {
|
|
@@ -12721,7 +12814,7 @@ var ensureConfigDir = (dir = resolveConfigDir()) => {
|
|
|
12721
12814
|
migratedDir = dir;
|
|
12722
12815
|
return dir;
|
|
12723
12816
|
}
|
|
12724
|
-
const legacy =
|
|
12817
|
+
const legacy = path11.join(process.env.XDG_CONFIG_HOME || path11.join(os3.homedir(), ".config"), "workflow-toolkit");
|
|
12725
12818
|
if (!existsSync3(legacy)) {
|
|
12726
12819
|
migratedDir = dir;
|
|
12727
12820
|
return dir;
|
|
@@ -12734,8 +12827,8 @@ var ensureConfigDir = (dir = resolveConfigDir()) => {
|
|
|
12734
12827
|
mkdirSync2(dir, { recursive: true });
|
|
12735
12828
|
diagnosticLogger?.info(EVENT.migration, { from: legacy, to: dir });
|
|
12736
12829
|
for (const entry of readdirSync2(legacy, { withFileTypes: true })) {
|
|
12737
|
-
const src =
|
|
12738
|
-
const dest =
|
|
12830
|
+
const src = path11.join(legacy, entry.name);
|
|
12831
|
+
const dest = path11.join(dir, entry.name);
|
|
12739
12832
|
if (existsSync3(dest))
|
|
12740
12833
|
continue;
|
|
12741
12834
|
try {
|
|
@@ -12807,7 +12900,7 @@ var parseConfigResult = (raw, file) => {
|
|
|
12807
12900
|
return { status: "valid", path: file, config };
|
|
12808
12901
|
};
|
|
12809
12902
|
var readConfigTyped = (dir) => {
|
|
12810
|
-
const file =
|
|
12903
|
+
const file = path11.join(dir ?? configDir(), "config.json");
|
|
12811
12904
|
return parseConfigResult(readSafe(file), file);
|
|
12812
12905
|
};
|
|
12813
12906
|
var readConfig = () => {
|
|
@@ -12816,7 +12909,7 @@ var readConfig = () => {
|
|
|
12816
12909
|
throw new Error(result.error);
|
|
12817
12910
|
return result.config ?? DEFAULTS;
|
|
12818
12911
|
};
|
|
12819
|
-
var vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ??
|
|
12912
|
+
var vcsConfigPath = () => process.env.WORKFLOW_VCS_CONFIG ?? path11.join(configDir(), "vcs.json");
|
|
12820
12913
|
var branchGlobPattern = (glob) => new RegExp(`^${glob.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")}$`, "i");
|
|
12821
12914
|
var resolveBranchPolicy = (config, workspace, repoPreset) => {
|
|
12822
12915
|
const wp = workspace?.branchPolicy ?? {};
|
|
@@ -12860,7 +12953,7 @@ var resolveCommitPolicy = (config, workspace) => {
|
|
|
12860
12953
|
import { spawnSync as spawnSync6 } from "node:child_process";
|
|
12861
12954
|
import { createHash as createHash7 } from "node:crypto";
|
|
12862
12955
|
import { readFileSync as readFileSync3, realpathSync as realpathSync2 } from "node:fs";
|
|
12863
|
-
import
|
|
12956
|
+
import path12 from "node:path";
|
|
12864
12957
|
|
|
12865
12958
|
// packages/workit-core/src/core/branch-policy.ts
|
|
12866
12959
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
@@ -12986,7 +13079,7 @@ var releaseTrackSchema = object({
|
|
|
12986
13079
|
context.addIssue({ code: "custom", path: [field], message: "entries must be unique" });
|
|
12987
13080
|
}
|
|
12988
13081
|
}
|
|
12989
|
-
if (track.versionSource?.kind === "package-json" && (
|
|
13082
|
+
if (track.versionSource?.kind === "package-json" && (path12.posix.isAbsolute(track.versionSource.path.replaceAll("\\", "/")) || /^[A-Za-z]:\//u.test(track.versionSource.path.replaceAll("\\", "/")) || track.versionSource.path.replaceAll("\\", "/").split("/").includes(".."))) {
|
|
12990
13083
|
context.addIssue({
|
|
12991
13084
|
code: "custom",
|
|
12992
13085
|
path: ["versionSource", "path"],
|
|
@@ -13085,7 +13178,7 @@ var validateWorkspacesDocument = (parsed, file) => {
|
|
|
13085
13178
|
};
|
|
13086
13179
|
};
|
|
13087
13180
|
var readWorkspacesResult = (dir = configDir()) => {
|
|
13088
|
-
const file =
|
|
13181
|
+
const file = path12.join(dir, "workspaces.json");
|
|
13089
13182
|
let raw;
|
|
13090
13183
|
try {
|
|
13091
13184
|
raw = readFileSync3(file, "utf8");
|
|
@@ -13196,9 +13289,9 @@ var mainCheckoutOf = (cwd) => {
|
|
|
13196
13289
|
let main = null;
|
|
13197
13290
|
const dirs = git(["rev-parse", "--path-format=absolute", "--git-dir", "--git-common-dir"]);
|
|
13198
13291
|
const [gitDir, common] = (dirs ?? "").trim().split(/\r?\n/u);
|
|
13199
|
-
if (gitDir && common &&
|
|
13292
|
+
if (gitDir && common && path12.resolve(gitDir) !== path12.resolve(common)) {
|
|
13200
13293
|
const listed = /^worktree (.+)$/mu.exec(git(["worktree", "list", "--porcelain"]) ?? "")?.[1];
|
|
13201
|
-
main = listed?.trim() || (
|
|
13294
|
+
main = listed?.trim() || (path12.basename(common) === ".git" ? path12.dirname(common) : common);
|
|
13202
13295
|
}
|
|
13203
13296
|
mainCheckouts.set(cwd, main);
|
|
13204
13297
|
return main;
|
|
@@ -13289,7 +13382,7 @@ var runtimeWorkspaceIndexSchema = object({
|
|
|
13289
13382
|
workspaces: array(object({ name: nonBlank, glob: nonBlank }).passthrough()).optional()
|
|
13290
13383
|
}).passthrough();
|
|
13291
13384
|
var matchRuntimeWorkspace = (cwd, dir = configDir()) => {
|
|
13292
|
-
const file =
|
|
13385
|
+
const file = path12.join(dir, "workspaces.json");
|
|
13293
13386
|
let raw;
|
|
13294
13387
|
try {
|
|
13295
13388
|
raw = readFileSync3(file, "utf8");
|
|
@@ -13678,7 +13771,7 @@ var git3 = (cwd, args) => {
|
|
|
13678
13771
|
return run.status === 0 ? (run.stdout ?? "").trim() : null;
|
|
13679
13772
|
};
|
|
13680
13773
|
var recordedBaseKey = (branch) => `branch.${branch}.workitBase`;
|
|
13681
|
-
var
|
|
13774
|
+
var escapeRegExp2 = (text) => text.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
13682
13775
|
var reflog = (cwd, ref) => (git3(cwd, ["log", "-g", "--date=unix", "--format=%H%x09%gd%x09%gs", ref, "--"]) ?? "").split(`
|
|
13683
13776
|
`).map((line) => {
|
|
13684
13777
|
const [sha = "", selector = "", ...subject] = line.split("\t");
|
|
@@ -13710,7 +13803,7 @@ function gitTrackProbe(cwd) {
|
|
|
13710
13803
|
const created = own.at(-1);
|
|
13711
13804
|
if (!created || created.subject !== "branch: Created from HEAD")
|
|
13712
13805
|
return null;
|
|
13713
|
-
const pattern = new RegExp(`^checkout: moving from (\\S+) to ${
|
|
13806
|
+
const pattern = new RegExp(`^checkout: moving from (\\S+) to ${escapeRegExp2(branch)}$`, "u");
|
|
13714
13807
|
const entry = reflog(cwd, "HEAD").findLast((item) => item.time >= created.time && item.sha === created.sha && pattern.test(item.subject));
|
|
13715
13808
|
return entry ? pattern.exec(entry.subject)?.[1] ?? null : null;
|
|
13716
13809
|
},
|
|
@@ -13780,7 +13873,7 @@ function resolveTrackFor(cwd, options) {
|
|
|
13780
13873
|
}
|
|
13781
13874
|
|
|
13782
13875
|
// packages/workit-core/src/core/vcs-config.ts
|
|
13783
|
-
var workspacesPath = () =>
|
|
13876
|
+
var workspacesPath = () => path13.join(configDir(), "workspaces.json");
|
|
13784
13877
|
var vcsCwd = (cwd) => cwd ?? process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd();
|
|
13785
13878
|
var remoteProvider = (cwd) => {
|
|
13786
13879
|
const r = spawnSync8("git", ["remote", "get-url", "origin"], { cwd, encoding: "utf8" });
|
|
@@ -13955,7 +14048,7 @@ function vcsConfig(mode, cwd, options = {}) {
|
|
|
13955
14048
|
const prov = cfg[provider] ?? {};
|
|
13956
14049
|
const out = {
|
|
13957
14050
|
ok: true,
|
|
13958
|
-
configPath:
|
|
14051
|
+
configPath: path13.resolve(cfgPath),
|
|
13959
14052
|
provider,
|
|
13960
14053
|
defaultTargetBranch: workspaceDefault,
|
|
13961
14054
|
pr: cfg.pr ?? {},
|
|
@@ -14178,14 +14271,14 @@ function diffHash(cwd, base, head) {
|
|
|
14178
14271
|
return `sha256:${hash.digest("hex")}`;
|
|
14179
14272
|
}
|
|
14180
14273
|
function storeRoot(cwd) {
|
|
14181
|
-
const location = resolveStore(
|
|
14274
|
+
const location = resolveStore(path14.resolve(cwd));
|
|
14182
14275
|
if (location instanceof Error)
|
|
14183
14276
|
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");
|
|
14184
14277
|
return { ok: true, value: { root: location.dir, shared: location.shared } };
|
|
14185
14278
|
}
|
|
14186
14279
|
function ledgerPath(cwd) {
|
|
14187
14280
|
const root = storeRoot(cwd);
|
|
14188
|
-
return root.ok ? { ok: true, value:
|
|
14281
|
+
return root.ok ? { ok: true, value: path14.join(root.value.root, "ledger", "ledger.jsonl") } : root;
|
|
14189
14282
|
}
|
|
14190
14283
|
var newId2 = () => `${Date.now().toString(36)}-${randomBytes2(6).toString("hex")}`;
|
|
14191
14284
|
var NETWORK_FS_TYPES = new Set([
|
|
@@ -14215,13 +14308,13 @@ var LOCK_STALE_MS = 30000;
|
|
|
14215
14308
|
var LOCK_OWNER = "owner";
|
|
14216
14309
|
var lockToken = (lock) => {
|
|
14217
14310
|
try {
|
|
14218
|
-
return fs12.readFileSync(
|
|
14311
|
+
return fs12.readFileSync(path14.join(lock, LOCK_OWNER), "utf8");
|
|
14219
14312
|
} catch {
|
|
14220
14313
|
return null;
|
|
14221
14314
|
}
|
|
14222
14315
|
};
|
|
14223
14316
|
var lockAgeMs = (lock) => {
|
|
14224
|
-
for (const target of [
|
|
14317
|
+
for (const target of [path14.join(lock, LOCK_OWNER), lock]) {
|
|
14225
14318
|
try {
|
|
14226
14319
|
return Date.now() - fs12.statSync(target).mtimeMs;
|
|
14227
14320
|
} catch {}
|
|
@@ -14238,7 +14331,7 @@ var ledgerLock = {
|
|
|
14238
14331
|
throw error;
|
|
14239
14332
|
}
|
|
14240
14333
|
const token = `${process.pid}-${randomBytes2(8).toString("hex")}`;
|
|
14241
|
-
fs12.writeFileSync(
|
|
14334
|
+
fs12.writeFileSync(path14.join(lock, LOCK_OWNER), token);
|
|
14242
14335
|
return token;
|
|
14243
14336
|
},
|
|
14244
14337
|
release(lock, token) {
|
|
@@ -14363,8 +14456,8 @@ function appendLine(file, build, options) {
|
|
|
14363
14456
|
}
|
|
14364
14457
|
};
|
|
14365
14458
|
try {
|
|
14366
|
-
fs12.mkdirSync(
|
|
14367
|
-
if (!options.forceLock && !onNetworkFs(
|
|
14459
|
+
fs12.mkdirSync(path14.dirname(file), { recursive: true });
|
|
14460
|
+
if (!options.forceLock && !onNetworkFs(path14.dirname(file)))
|
|
14368
14461
|
return write();
|
|
14369
14462
|
const locked = withLedgerLock(file, write);
|
|
14370
14463
|
return locked ?? err("busy", `ledger lock ${file}.lock is held`, "retry; remove the .lock directory if no workit process is running");
|
|
@@ -14927,7 +15020,7 @@ var productDecision = (task, ledger) => {
|
|
|
14927
15020
|
};
|
|
14928
15021
|
};
|
|
14929
15022
|
var planRecorded = (task, root) => {
|
|
14930
|
-
const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync4(
|
|
15023
|
+
const cited = (latestJudgment(task)?.refs ?? []).find((ref) => ref.kind === "external" || ref.kind === "file" && existsSync4(path15.resolve(root, ref.path)));
|
|
14931
15024
|
if (cited)
|
|
14932
15025
|
return {
|
|
14933
15026
|
met: true,
|
|
@@ -14987,14 +15080,14 @@ function writeBlockers(task, root) {
|
|
|
14987
15080
|
|
|
14988
15081
|
// packages/workit-core/src/core/task-evaluation.ts
|
|
14989
15082
|
var digestBytes = (value) => createHash10("sha256").update(value).digest("hex");
|
|
14990
|
-
var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${
|
|
14991
|
-
var relative = (root, candidate) =>
|
|
15083
|
+
var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${path16.sep}`);
|
|
15084
|
+
var relative = (root, candidate) => path16.relative(root, candidate).split(path16.sep).join("/") || ".";
|
|
14992
15085
|
var canonicalPath = (value) => {
|
|
14993
15086
|
if (typeof value !== "string" || !value)
|
|
14994
15087
|
return null;
|
|
14995
15088
|
if (value.includes("\\") || value.split("/").includes(".."))
|
|
14996
15089
|
return null;
|
|
14997
|
-
const normalized =
|
|
15090
|
+
const normalized = path16.posix.normalize(value);
|
|
14998
15091
|
if (normalized === ".." || normalized.startsWith("../") || normalized.startsWith("/"))
|
|
14999
15092
|
return null;
|
|
15000
15093
|
return normalized === "." ? "." : normalized.replace(/\/$/, "");
|
|
@@ -15042,14 +15135,14 @@ var gitPaths = (root) => {
|
|
|
15042
15135
|
git: !/not a git repository/i.test(stderr)
|
|
15043
15136
|
};
|
|
15044
15137
|
}
|
|
15045
|
-
const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(
|
|
15138
|
+
const paths = result.stdout ? result.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path16.sep).join("/")) : [];
|
|
15046
15139
|
const stagedDeleted = spawnSync10("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
|
|
15047
15140
|
if (stagedDeleted.status !== 0) {
|
|
15048
15141
|
const stderr = stagedDeleted.stderr?.toString("utf8") ?? "";
|
|
15049
15142
|
if (!/not a git repository/i.test(stderr))
|
|
15050
15143
|
return { paths, uncertain: true, git: true };
|
|
15051
15144
|
} else if (stagedDeleted.stdout) {
|
|
15052
|
-
paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(
|
|
15145
|
+
paths.push(...stagedDeleted.stdout.toString("utf8").split("\x00").filter(Boolean).map((item) => item.split(path16.sep).join("/")));
|
|
15053
15146
|
}
|
|
15054
15147
|
return { paths: [...new Set(paths)], uncertain: false, git: true };
|
|
15055
15148
|
};
|
|
@@ -15064,7 +15157,7 @@ var walk = (root, directory, output) => {
|
|
|
15064
15157
|
for (const name of names) {
|
|
15065
15158
|
if (name === ".git" || name === ".workit")
|
|
15066
15159
|
continue;
|
|
15067
|
-
const target =
|
|
15160
|
+
const target = path16.join(directory, name);
|
|
15068
15161
|
let stat;
|
|
15069
15162
|
try {
|
|
15070
15163
|
stat = fs13.lstatSync(target);
|
|
@@ -15082,12 +15175,12 @@ var walk = (root, directory, output) => {
|
|
|
15082
15175
|
var scopeRoots = (root, scope) => {
|
|
15083
15176
|
const roots = [];
|
|
15084
15177
|
for (const item of scope.paths.length ? scope.paths : ["."]) {
|
|
15085
|
-
const target =
|
|
15178
|
+
const target = path16.resolve(root, item);
|
|
15086
15179
|
if (!inside(root, target))
|
|
15087
15180
|
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` }] });
|
|
15088
15181
|
let ancestor = target;
|
|
15089
15182
|
while (!fs13.existsSync(ancestor) && ancestor !== root)
|
|
15090
|
-
ancestor =
|
|
15183
|
+
ancestor = path16.dirname(ancestor);
|
|
15091
15184
|
try {
|
|
15092
15185
|
if (!inside(root, fs13.realpathSync(ancestor)))
|
|
15093
15186
|
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` }] });
|
|
@@ -15139,7 +15232,7 @@ function captureCandidate(root, scope, environment = []) {
|
|
|
15139
15232
|
for (const item of [...names].toSorted()) {
|
|
15140
15233
|
if (!scopeMatches(item, normalizedScope))
|
|
15141
15234
|
continue;
|
|
15142
|
-
const target =
|
|
15235
|
+
const target = path16.join(checkout, item);
|
|
15143
15236
|
try {
|
|
15144
15237
|
const stat = fs13.lstatSync(target);
|
|
15145
15238
|
if (stat.isSymbolicLink()) {
|
|
@@ -15323,23 +15416,23 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
|
15323
15416
|
continue;
|
|
15324
15417
|
if (!reference.digest)
|
|
15325
15418
|
return failure2("invalid_input", "document references require a byte digest");
|
|
15326
|
-
const target =
|
|
15327
|
-
if (target !== root && !target.startsWith(`${root}${
|
|
15419
|
+
const target = path16.resolve(root, reference.path);
|
|
15420
|
+
if (target !== root && !target.startsWith(`${root}${path16.sep}`))
|
|
15328
15421
|
return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
|
|
15329
15422
|
fields: [
|
|
15330
15423
|
{ path: "contentRefs.path", reason: `${reference.path} is outside the checkout` }
|
|
15331
15424
|
]
|
|
15332
15425
|
});
|
|
15333
15426
|
try {
|
|
15334
|
-
const below =
|
|
15427
|
+
const below = path16.relative(root, target);
|
|
15335
15428
|
let current = root;
|
|
15336
|
-
for (const segment of below.split(
|
|
15429
|
+
for (const segment of below.split(path16.sep)) {
|
|
15337
15430
|
if (!segment)
|
|
15338
15431
|
continue;
|
|
15339
|
-
current =
|
|
15432
|
+
current = path16.join(current, segment);
|
|
15340
15433
|
const stat = fs13.lstatSync(current);
|
|
15341
15434
|
const real = fs13.realpathSync(current);
|
|
15342
|
-
if (real !== root && !real.startsWith(`${root}${
|
|
15435
|
+
if (real !== root && !real.startsWith(`${root}${path16.sep}`))
|
|
15343
15436
|
return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
|
|
15344
15437
|
fields: [
|
|
15345
15438
|
{
|
|
@@ -15886,14 +15979,14 @@ var exportDigest = (bundle) => sha256({
|
|
|
15886
15979
|
// packages/workit-core/src/core/route-intent.ts
|
|
15887
15980
|
import { spawnSync as spawnSync12 } from "node:child_process";
|
|
15888
15981
|
import { existsSync as existsSync6 } from "node:fs";
|
|
15889
|
-
import
|
|
15982
|
+
import path19 from "node:path";
|
|
15890
15983
|
|
|
15891
15984
|
// packages/workit-core/src/hooks/raw-git.ts
|
|
15892
15985
|
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
15893
15986
|
import { createHash as createHash13 } from "node:crypto";
|
|
15894
15987
|
import fs15 from "node:fs";
|
|
15895
|
-
import
|
|
15896
|
-
import
|
|
15988
|
+
import os4 from "node:os";
|
|
15989
|
+
import path18 from "node:path";
|
|
15897
15990
|
|
|
15898
15991
|
// packages/workit-core/src/core/branch.ts
|
|
15899
15992
|
import { createHash as createHash11 } from "node:crypto";
|
|
@@ -16176,7 +16269,7 @@ var globOf = (pattern) => pattern.source.replace(/^\^|\$$/gu, "").replaceAll(".*
|
|
|
16176
16269
|
// packages/workit-core/src/hooks/session-marker.ts
|
|
16177
16270
|
import { createHash as createHash12 } from "node:crypto";
|
|
16178
16271
|
import fs14 from "node:fs";
|
|
16179
|
-
import
|
|
16272
|
+
import path17 from "node:path";
|
|
16180
16273
|
var sessionMarkerFile = (input, session, store) => {
|
|
16181
16274
|
let dir = store;
|
|
16182
16275
|
if (dir === undefined) {
|
|
@@ -16186,7 +16279,7 @@ var sessionMarkerFile = (input, session, store) => {
|
|
|
16186
16279
|
dir = location.dir;
|
|
16187
16280
|
}
|
|
16188
16281
|
const name = createHash12("sha256").update(`${input.host}\x00${session}`).digest("hex").slice(0, 32);
|
|
16189
|
-
return
|
|
16282
|
+
return path17.join(dir, "hooks", `skills-${name}.json`);
|
|
16190
16283
|
};
|
|
16191
16284
|
var list2 = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
16192
16285
|
var readSessionMarker = (file) => {
|
|
@@ -16199,7 +16292,7 @@ var readSessionMarker = (file) => {
|
|
|
16199
16292
|
};
|
|
16200
16293
|
var writeSessionMarker = (file, marker) => {
|
|
16201
16294
|
try {
|
|
16202
|
-
fs14.mkdirSync(
|
|
16295
|
+
fs14.mkdirSync(path17.dirname(file), { recursive: true });
|
|
16203
16296
|
fs14.writeFileSync(file, JSON.stringify(marker));
|
|
16204
16297
|
} catch {}
|
|
16205
16298
|
};
|
|
@@ -16344,12 +16437,12 @@ var GIT_VALUE_OPTIONS = new Set([
|
|
|
16344
16437
|
"--config-env",
|
|
16345
16438
|
"--super-prefix"
|
|
16346
16439
|
]);
|
|
16347
|
-
var isAbsolute = (value) =>
|
|
16440
|
+
var isAbsolute = (value) => path18.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\");
|
|
16348
16441
|
var joinDir = (base, next) => {
|
|
16349
16442
|
if (base === undefined || /[$`*?]/.test(next) || next === "-")
|
|
16350
16443
|
return;
|
|
16351
|
-
const expanded = next === "~" || next.startsWith("~/") ?
|
|
16352
|
-
return base === null || isAbsolute(expanded) ? expanded :
|
|
16444
|
+
const expanded = next === "~" || next.startsWith("~/") ? path18.join(os4.homedir(), next.slice(1)) : next;
|
|
16445
|
+
return base === null || isAbsolute(expanded) ? expanded : path18.join(base, expanded);
|
|
16353
16446
|
};
|
|
16354
16447
|
var cdTarget = (words) => {
|
|
16355
16448
|
const args = words.slice(1);
|
|
@@ -16400,7 +16493,7 @@ function rawInvocations(command, dialect = "posix", depth = 0) {
|
|
|
16400
16493
|
const name = commandName(words[0]);
|
|
16401
16494
|
if (CD.has(name)) {
|
|
16402
16495
|
const target = cdTarget(words);
|
|
16403
|
-
dir = target === null ?
|
|
16496
|
+
dir = target === null ? os4.homedir() : joinDir(dir, target);
|
|
16404
16497
|
continue;
|
|
16405
16498
|
}
|
|
16406
16499
|
if (PUSHD.has(name)) {
|
|
@@ -16658,17 +16751,17 @@ var headSha2 = (repo) => {
|
|
|
16658
16751
|
if (!git || git.reftable)
|
|
16659
16752
|
return null;
|
|
16660
16753
|
try {
|
|
16661
|
-
const head = fs15.readFileSync(
|
|
16754
|
+
const head = fs15.readFileSync(path18.join(git.gitDir, "HEAD"), "utf8").trim();
|
|
16662
16755
|
if (/^[0-9a-f]{40,64}$/.test(head))
|
|
16663
16756
|
return head;
|
|
16664
16757
|
const ref = /^ref: (refs\/.+)$/.exec(head)?.[1];
|
|
16665
16758
|
if (!ref)
|
|
16666
16759
|
return null;
|
|
16667
|
-
const common =
|
|
16760
|
+
const common = path18.dirname(repo.location.dir);
|
|
16668
16761
|
try {
|
|
16669
|
-
return fs15.readFileSync(
|
|
16762
|
+
return fs15.readFileSync(path18.join(common, ref), "utf8").trim() || null;
|
|
16670
16763
|
} catch {}
|
|
16671
|
-
const packed = fs15.readFileSync(
|
|
16764
|
+
const packed = fs15.readFileSync(path18.join(common, "packed-refs"), "utf8");
|
|
16672
16765
|
return new RegExp(`^([0-9a-f]{40,64}) ${ref.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`, "m").exec(packed)?.[1] ?? null;
|
|
16673
16766
|
} catch {
|
|
16674
16767
|
return null;
|
|
@@ -16757,7 +16850,7 @@ var actionsIn = (cwd, command, dialect) => {
|
|
|
16757
16850
|
const action = rawAction(invocation);
|
|
16758
16851
|
if (!action)
|
|
16759
16852
|
continue;
|
|
16760
|
-
const dir =
|
|
16853
|
+
const dir = path18.resolve(cwd, invocation.dir ?? ".");
|
|
16761
16854
|
if (!repos.has(dir)) {
|
|
16762
16855
|
const repo = repoAt(dir);
|
|
16763
16856
|
repos.set(dir, repo && isWorkitWorkspace(repo) ? repo : null);
|
|
@@ -16837,7 +16930,7 @@ function rawGitPre(input, command, options = {}) {
|
|
|
16837
16930
|
var deny = (reason) => ({ kind: "deny", reason, unblock: null });
|
|
16838
16931
|
var NEXT_COMMAND = "next";
|
|
16839
16932
|
var MARKER_TTL_SECONDS = 3600;
|
|
16840
|
-
var markerFile = (repo, session, key) =>
|
|
16933
|
+
var markerFile = (repo, session, key) => path18.join(repo.location.dir, "hooks", `commit-${createHash13("sha256").update(`${session}\x00${key}`).digest("hex").slice(0, 32)}.json`);
|
|
16841
16934
|
var callKey = (toolUseId, command) => toolUseId ?? `cmd:${createHash13("sha256").update(command).digest("hex")}`;
|
|
16842
16935
|
function noteRawCommit(input, command, key) {
|
|
16843
16936
|
try {
|
|
@@ -16848,7 +16941,7 @@ function noteRawCommit(input, command, key) {
|
|
|
16848
16941
|
if (action.kind !== "commit")
|
|
16849
16942
|
continue;
|
|
16850
16943
|
const file = markerFile(repo, input.session.id, key);
|
|
16851
|
-
fs15.mkdirSync(
|
|
16944
|
+
fs15.mkdirSync(path18.dirname(file), { recursive: true });
|
|
16852
16945
|
fs15.writeFileSync(file, `${JSON.stringify({ head: headSha2(repo), at })}
|
|
16853
16946
|
`);
|
|
16854
16947
|
}
|
|
@@ -17021,7 +17114,7 @@ var shellBranchPolicyViolation = (root, command, dialect = "posix") => {
|
|
|
17021
17114
|
for (const target of shellBranchTargets(command, dialect)) {
|
|
17022
17115
|
if (target.dir === undefined)
|
|
17023
17116
|
continue;
|
|
17024
|
-
const dir = target.dir === null ? root :
|
|
17117
|
+
const dir = target.dir === null ? root : path19.resolve(root, target.dir);
|
|
17025
17118
|
if (target.dir !== null && (!existsSync6(dir) || !inWorkitWorkspace(dir)))
|
|
17026
17119
|
continue;
|
|
17027
17120
|
if (localBranchExists(dir, target.branch))
|
|
@@ -17247,20 +17340,20 @@ var judgeInputSummary = (raw) => {
|
|
|
17247
17340
|
};
|
|
17248
17341
|
|
|
17249
17342
|
// packages/workit-core/src/autonomy.ts
|
|
17250
|
-
import
|
|
17251
|
-
import
|
|
17343
|
+
import os5 from "node:os";
|
|
17344
|
+
import path20 from "node:path";
|
|
17252
17345
|
var accountHome = () => {
|
|
17253
17346
|
try {
|
|
17254
|
-
return
|
|
17347
|
+
return os5.userInfo().homedir;
|
|
17255
17348
|
} catch {
|
|
17256
|
-
return
|
|
17349
|
+
return os5.homedir();
|
|
17257
17350
|
}
|
|
17258
17351
|
};
|
|
17259
17352
|
var grantsHome = { resolve: accountHome };
|
|
17260
|
-
var grantsDir = () =>
|
|
17353
|
+
var grantsDir = () => path20.join(grantsHome.resolve(), ".config", "workit");
|
|
17261
17354
|
var grantsOverride = () => {
|
|
17262
|
-
const configured =
|
|
17263
|
-
return configured ===
|
|
17355
|
+
const configured = path20.resolve(resolveConfigDir());
|
|
17356
|
+
return configured === path20.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 ${path20.join(grantsDir(), "workspaces.json")}, so the D4 defaults apply`;
|
|
17264
17357
|
};
|
|
17265
17358
|
var GRANT_KINDS = ["push", "pr", "merge", "release", "rerun"];
|
|
17266
17359
|
var DEFAULT_GRANTS = Object.freeze({
|
|
@@ -19032,7 +19125,7 @@ class WorkitCore {
|
|
|
19032
19125
|
// packages/workit-core/src/core/repo-context.ts
|
|
19033
19126
|
import { spawnSync as spawnSync13 } from "node:child_process";
|
|
19034
19127
|
import { existsSync as existsSync7, readFileSync as readFileSync5, readdirSync as readdirSync4 } from "node:fs";
|
|
19035
|
-
import
|
|
19128
|
+
import path21 from "node:path";
|
|
19036
19129
|
var isSafeContextRange = (value) => value.length <= 4096 && (() => {
|
|
19037
19130
|
try {
|
|
19038
19131
|
gitRevisionParts(value);
|
|
@@ -19166,7 +19259,7 @@ var findPrTemplate = (cwd) => {
|
|
|
19166
19259
|
]) {
|
|
19167
19260
|
const parts = rel.split("/");
|
|
19168
19261
|
const base = parts[parts.length - 1];
|
|
19169
|
-
const dir = parts.length > 1 ?
|
|
19262
|
+
const dir = parts.length > 1 ? path21.join(cwd, ...parts.slice(0, -1)) : cwd;
|
|
19170
19263
|
const actual = probeCaseInsensitive(dir, base);
|
|
19171
19264
|
if (actual)
|
|
19172
19265
|
return [...parts.slice(0, -1), actual].join("/");
|
|
@@ -19197,7 +19290,7 @@ var diffStatForRange = (cwd, range) => {
|
|
|
19197
19290
|
return runGit(cwd, ["diff", "--stat", "--"]).stdout;
|
|
19198
19291
|
};
|
|
19199
19292
|
var packageScripts = (cwd, keys) => {
|
|
19200
|
-
const pkgPath =
|
|
19293
|
+
const pkgPath = path21.join(cwd, "package.json");
|
|
19201
19294
|
if (!existsSync7(pkgPath))
|
|
19202
19295
|
return [];
|
|
19203
19296
|
try {
|
|
@@ -19223,9 +19316,9 @@ var documentationFiles = (cwd) => {
|
|
|
19223
19316
|
if (entry.isDirectory()) {
|
|
19224
19317
|
if (excluded.has(entry.name))
|
|
19225
19318
|
continue;
|
|
19226
|
-
walk(
|
|
19319
|
+
walk(path21.join(dir, entry.name), depth + 1);
|
|
19227
19320
|
} else if (entry.isFile() && (entry.name === "README.md" || entry.name.endsWith(".md"))) {
|
|
19228
|
-
matches.push("./" +
|
|
19321
|
+
matches.push("./" + path21.relative(cwd, path21.join(dir, entry.name)).replaceAll("\\", "/"));
|
|
19229
19322
|
}
|
|
19230
19323
|
}
|
|
19231
19324
|
};
|
|
@@ -19241,7 +19334,7 @@ var readTrimmed2 = (file, maxLines) => {
|
|
|
19241
19334
|
`);
|
|
19242
19335
|
};
|
|
19243
19336
|
function prReadyContext(root, range) {
|
|
19244
|
-
const cwd =
|
|
19337
|
+
const cwd = path21.resolve(repoRoot(root));
|
|
19245
19338
|
if (range !== undefined && !isResolvableContextRange(cwd, range))
|
|
19246
19339
|
return invalidRange(cwd);
|
|
19247
19340
|
let stdout = "";
|
|
@@ -19299,7 +19392,7 @@ ${status.stderr}` : "");
|
|
|
19299
19392
|
stdout += `template_path: ${template}
|
|
19300
19393
|
|
|
19301
19394
|
`;
|
|
19302
|
-
stdout += readTrimmed2(
|
|
19395
|
+
stdout += readTrimmed2(path21.join(cwd, template), 220);
|
|
19303
19396
|
} else {
|
|
19304
19397
|
stdout += `template_path: none
|
|
19305
19398
|
|
|
@@ -19309,7 +19402,7 @@ ${status.stderr}` : "");
|
|
|
19309
19402
|
stdout += `
|
|
19310
19403
|
`;
|
|
19311
19404
|
stdout += printSection("Recent Validation Signals");
|
|
19312
|
-
if (existsSync7(
|
|
19405
|
+
if (existsSync7(path21.join(cwd, "package.json"))) {
|
|
19313
19406
|
stdout += `package.json detected. Common scripts:
|
|
19314
19407
|
`;
|
|
19315
19408
|
const found = packageScripts(cwd, ["lint", "format:check", "test", "build"]);
|
|
@@ -19318,7 +19411,7 @@ ${status.stderr}` : "");
|
|
|
19318
19411
|
`) + `
|
|
19319
19412
|
`;
|
|
19320
19413
|
}
|
|
19321
|
-
if (existsSync7(
|
|
19414
|
+
if (existsSync7(path21.join(cwd, "Cargo.toml")) || existsSync7(path21.join(cwd, "src-tauri/Cargo.toml"))) {
|
|
19322
19415
|
stdout += `Rust project detected.
|
|
19323
19416
|
`;
|
|
19324
19417
|
}
|
|
@@ -19351,7 +19444,7 @@ var CHANGELOG_RULES = `- Use an [Unreleased] section.
|
|
|
19351
19444
|
- Apply with the host-native editor, preserving the repository changelog conventions.
|
|
19352
19445
|
- If Unreleased already has duplicate category headings, normalize_only first.`;
|
|
19353
19446
|
function changelogContext(root, range) {
|
|
19354
|
-
const cwd =
|
|
19447
|
+
const cwd = path21.resolve(repoRoot(root));
|
|
19355
19448
|
if (range !== undefined && !isResolvableContextRange(cwd, range))
|
|
19356
19449
|
return invalidRange(cwd);
|
|
19357
19450
|
const resolvedRange = rangeArgOrDefault(range, cwd);
|
|
@@ -19369,7 +19462,7 @@ function changelogContext(root, range) {
|
|
|
19369
19462
|
stdout += CHANGELOG_RULES + `
|
|
19370
19463
|
`;
|
|
19371
19464
|
stdout += printSection("Existing CHANGELOG.md");
|
|
19372
|
-
const changelogPath =
|
|
19465
|
+
const changelogPath = path21.join(cwd, "CHANGELOG.md");
|
|
19373
19466
|
if (existsSync7(changelogPath)) {
|
|
19374
19467
|
stdout += readTrimmed2(changelogPath, 260) + `
|
|
19375
19468
|
`;
|
|
@@ -19389,7 +19482,7 @@ function changelogContext(root, range) {
|
|
|
19389
19482
|
return { stdout, stderr: "", exitCode: 0, cwd };
|
|
19390
19483
|
}
|
|
19391
19484
|
function docsRefreshContext(root, range) {
|
|
19392
|
-
const cwd =
|
|
19485
|
+
const cwd = path21.resolve(repoRoot(root));
|
|
19393
19486
|
if (range !== undefined && !isResolvableContextRange(cwd, range))
|
|
19394
19487
|
return invalidRange(cwd);
|
|
19395
19488
|
const resolvedRange = rangeArgOrDefault(range, cwd);
|
|
@@ -19411,7 +19504,7 @@ function docsRefreshContext(root, range) {
|
|
|
19411
19504
|
`) + `
|
|
19412
19505
|
`;
|
|
19413
19506
|
stdout += printSection("README Preview");
|
|
19414
|
-
const readme =
|
|
19507
|
+
const readme = path21.join(cwd, "README.md");
|
|
19415
19508
|
if (existsSync7(readme)) {
|
|
19416
19509
|
stdout += readTrimmed2(readme, 220) + `
|
|
19417
19510
|
`;
|
|
@@ -19420,7 +19513,7 @@ function docsRefreshContext(root, range) {
|
|
|
19420
19513
|
`;
|
|
19421
19514
|
}
|
|
19422
19515
|
stdout += printSection("Package Scripts");
|
|
19423
|
-
const pkgPath =
|
|
19516
|
+
const pkgPath = path21.join(cwd, "package.json");
|
|
19424
19517
|
if (existsSync7(pkgPath)) {
|
|
19425
19518
|
try {
|
|
19426
19519
|
const pkg = JSON.parse(readFileSync5(pkgPath, "utf8"));
|
|
@@ -19434,7 +19527,7 @@ function docsRefreshContext(root, range) {
|
|
|
19434
19527
|
return { stdout, stderr: "", exitCode: 0, cwd };
|
|
19435
19528
|
}
|
|
19436
19529
|
function releaseNotesContext(root, rangeOrTag) {
|
|
19437
|
-
const cwd =
|
|
19530
|
+
const cwd = path21.resolve(repoRoot(root));
|
|
19438
19531
|
if (!rangeOrTag) {
|
|
19439
19532
|
return { stdout: "", stderr: `ERROR: release tag or range required
|
|
19440
19533
|
`, exitCode: 1, cwd };
|
|
@@ -19472,7 +19565,7 @@ function releaseNotesContext(root, rangeOrTag) {
|
|
|
19472
19565
|
`;
|
|
19473
19566
|
stdout += printSection("Existing Release Files");
|
|
19474
19567
|
for (const rel of ["CHANGELOG.md", "RELEASE_NOTES.md", ".github/releases.md"]) {
|
|
19475
|
-
if (existsSync7(
|
|
19568
|
+
if (existsSync7(path21.join(cwd, rel)))
|
|
19476
19569
|
stdout += rel + `
|
|
19477
19570
|
`;
|
|
19478
19571
|
}
|
|
@@ -19504,7 +19597,7 @@ import { spawnSync as spawnSync15 } from "node:child_process";
|
|
|
19504
19597
|
|
|
19505
19598
|
// packages/workit-core/src/core/pr-create.ts
|
|
19506
19599
|
import fs16 from "node:fs";
|
|
19507
|
-
import
|
|
19600
|
+
import path22 from "node:path";
|
|
19508
19601
|
import { spawnSync as spawnSync14 } from "node:child_process";
|
|
19509
19602
|
// packages/workit-core/src/forge/pr-body.ts
|
|
19510
19603
|
function parseGhIssue(value) {
|
|
@@ -19515,11 +19608,11 @@ function parseGhIssue(value) {
|
|
|
19515
19608
|
// packages/workit-core/src/core/pr-create.ts
|
|
19516
19609
|
function whichOnPath(tool) {
|
|
19517
19610
|
const names = process.platform === "win32" ? [tool, `${tool}.exe`, `${tool}.cmd`] : [tool];
|
|
19518
|
-
for (const dir of (process.env.PATH ?? "").split(
|
|
19611
|
+
for (const dir of (process.env.PATH ?? "").split(path22.delimiter)) {
|
|
19519
19612
|
if (!dir)
|
|
19520
19613
|
continue;
|
|
19521
19614
|
for (const name of names) {
|
|
19522
|
-
const candidate =
|
|
19615
|
+
const candidate = path22.join(dir, name);
|
|
19523
19616
|
try {
|
|
19524
19617
|
fs16.accessSync(candidate, fs16.constants.X_OK);
|
|
19525
19618
|
return candidate;
|
|
@@ -19640,7 +19733,7 @@ var fetchGitLabIssueBody = async (ref, root, deps = {}) => {
|
|
|
19640
19733
|
|
|
19641
19734
|
// packages/workit-core/src/core/youtrack.ts
|
|
19642
19735
|
import fs17 from "node:fs";
|
|
19643
|
-
import
|
|
19736
|
+
import path23 from "node:path";
|
|
19644
19737
|
|
|
19645
19738
|
// packages/workit-core/src/core/templates.ts
|
|
19646
19739
|
var repoRoot2 = assetRoot();
|
|
@@ -19653,8 +19746,8 @@ var resolveWorkspaceRoot = (explicit) => explicit || process.cwd();
|
|
|
19653
19746
|
// packages/workit-core/src/core/youtrack.ts
|
|
19654
19747
|
var ISSUE_RE = /^[A-Z]+-\d+$/;
|
|
19655
19748
|
var TOKEN_PLACEHOLDER = "YOUR_TOKEN_HERE";
|
|
19656
|
-
var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ??
|
|
19657
|
-
var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ??
|
|
19749
|
+
var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path23.join(configDir(), "youtrack.json");
|
|
19750
|
+
var youTrackReadOnlyConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ?? path23.join(resolveConfigDir(), "youtrack.json");
|
|
19658
19751
|
var youTrackTokenModeOk = (p) => {
|
|
19659
19752
|
if (process.platform === "win32")
|
|
19660
19753
|
return true;
|
|
@@ -19722,7 +19815,7 @@ var youTrackToken = () => {
|
|
|
19722
19815
|
if ("error" in loaded)
|
|
19723
19816
|
return loaded;
|
|
19724
19817
|
const tokenFile = String(loaded.config.tokenFile ?? "");
|
|
19725
|
-
const tokenPath = tokenFile ?
|
|
19818
|
+
const tokenPath = tokenFile ? path23.isAbsolute(tokenFile) ? path23.resolve(tokenFile) : path23.resolve(process.cwd(), tokenFile) : "";
|
|
19726
19819
|
if (!tokenPath || !fs17.existsSync(tokenPath))
|
|
19727
19820
|
return { error: "missing youtrack.token" };
|
|
19728
19821
|
if (!youTrackTokenModeOk(tokenPath))
|
|
@@ -20079,15 +20172,15 @@ function resolveGitRevision(root, value) {
|
|
|
20079
20172
|
}
|
|
20080
20173
|
function resolveInside(root, candidate) {
|
|
20081
20174
|
const base = realpathSync5(root);
|
|
20082
|
-
const target =
|
|
20083
|
-
if (target !== base && !target.startsWith(base +
|
|
20175
|
+
const target = path24.resolve(base, candidate);
|
|
20176
|
+
if (target !== base && !target.startsWith(base + path24.sep)) {
|
|
20084
20177
|
throw new Error("path must stay inside repository root");
|
|
20085
20178
|
}
|
|
20086
20179
|
let ancestor = target;
|
|
20087
20180
|
while (!existsSync8(ancestor))
|
|
20088
|
-
ancestor =
|
|
20181
|
+
ancestor = path24.dirname(ancestor);
|
|
20089
20182
|
const canonicalAncestor = realpathSync5(ancestor);
|
|
20090
|
-
if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base +
|
|
20183
|
+
if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base + path24.sep)) {
|
|
20091
20184
|
throw new Error("path must stay inside repository root");
|
|
20092
20185
|
}
|
|
20093
20186
|
return target;
|
|
@@ -20133,7 +20226,7 @@ var capabilitiesFor = (descriptor, observed = {}) => descriptor.capabilities.map
|
|
|
20133
20226
|
// packages/workit-core/src/hooks/context.ts
|
|
20134
20227
|
import { createHash as createHash14 } from "node:crypto";
|
|
20135
20228
|
import fs18 from "node:fs";
|
|
20136
|
-
import
|
|
20229
|
+
import path25 from "node:path";
|
|
20137
20230
|
var MIGRATION_PENDING_NOTE = "workit migration pending — run `workit task status`";
|
|
20138
20231
|
var migrationPending = (result) => !result.ok && result.code === "needs_input" && (result.error ?? "").startsWith(MIGRATION_PENDING);
|
|
20139
20232
|
var boundTo = (entry, session) => entry.sessions.some((item) => item.host === session.host && item.handle === session.handle);
|
|
@@ -20218,7 +20311,7 @@ function entryCompactContext(store, entry, session, context) {
|
|
|
20218
20311
|
return null;
|
|
20219
20312
|
const freshness = { mode: "signal", current: () => recentSignal(store.root) };
|
|
20220
20313
|
const observed = task?.data.evidence.some(isObservedCheck) ?? false;
|
|
20221
|
-
const files = (task?.data.decisions ?? []).flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [
|
|
20314
|
+
const files = (task?.data.decisions ?? []).flatMap((decision) => decision.data.binding.contentRefs.flatMap((ref) => ref.kind === "file" ? [path25.resolve(store.root, ref.path)] : []));
|
|
20222
20315
|
const observedFiles = filesKey(files);
|
|
20223
20316
|
const compact = new WorkitCore(store, context).compactContext(entry?.id ?? null, freshness, origin && { origin: origin.origin, taskId: origin.entry.id });
|
|
20224
20317
|
if (!compact.ok || !compact.data)
|
|
@@ -20296,14 +20389,14 @@ var turnMarker = (input) => {
|
|
|
20296
20389
|
if (location instanceof Error)
|
|
20297
20390
|
return null;
|
|
20298
20391
|
const session = [input.host, input.session.id, input.session.agentId ?? ""].join("\x00");
|
|
20299
|
-
return
|
|
20392
|
+
return path25.join(location.dir, "hooks", `turn-${digestOf(session).slice(0, 32)}.json`);
|
|
20300
20393
|
} catch {
|
|
20301
20394
|
return null;
|
|
20302
20395
|
}
|
|
20303
20396
|
};
|
|
20304
20397
|
var writeTurnDigest = (file, digest) => {
|
|
20305
20398
|
try {
|
|
20306
|
-
fs18.mkdirSync(
|
|
20399
|
+
fs18.mkdirSync(path25.dirname(file), { recursive: true });
|
|
20307
20400
|
fs18.writeFileSync(file, `${JSON.stringify({ digest })}
|
|
20308
20401
|
`);
|
|
20309
20402
|
} catch {}
|
|
@@ -20318,7 +20411,7 @@ var pruneTurnDigests = (dir, now) => {
|
|
|
20318
20411
|
for (const name of fs18.readdirSync(dir)) {
|
|
20319
20412
|
if (!name.startsWith("turn-"))
|
|
20320
20413
|
continue;
|
|
20321
|
-
const file =
|
|
20414
|
+
const file = path25.join(dir, name);
|
|
20322
20415
|
try {
|
|
20323
20416
|
if (now - fs18.statSync(file).mtimeMs > TURN_TTL_MS)
|
|
20324
20417
|
fs18.rmSync(file, { force: true });
|
|
@@ -20348,7 +20441,7 @@ var seedTurnContext = (input, descriptor, text = turnContextText(input, descript
|
|
|
20348
20441
|
const file = turnMarker(input);
|
|
20349
20442
|
if (!file)
|
|
20350
20443
|
return;
|
|
20351
|
-
pruneTurnDigests(
|
|
20444
|
+
pruneTurnDigests(path25.dirname(file), Date.now());
|
|
20352
20445
|
if (text)
|
|
20353
20446
|
writeTurnDigest(file, digestOf(text));
|
|
20354
20447
|
else
|
|
@@ -20361,27 +20454,27 @@ var shellPolicy = (cwd, command, dialect = "posix") => {
|
|
|
20361
20454
|
};
|
|
20362
20455
|
// packages/workit-core/src/hooks/write-gate.ts
|
|
20363
20456
|
import { realpathSync as realpathSync6 } from "node:fs";
|
|
20364
|
-
import
|
|
20457
|
+
import path26 from "node:path";
|
|
20365
20458
|
var NONE3 = { kind: "none" };
|
|
20366
20459
|
var CASE_INSENSITIVE = process.platform === "darwin" || process.platform === "win32";
|
|
20367
20460
|
var canonical2 = (file) => {
|
|
20368
20461
|
let rest = "";
|
|
20369
|
-
for (let dir =
|
|
20462
|
+
for (let dir = path26.resolve(file);; dir = path26.dirname(dir)) {
|
|
20370
20463
|
try {
|
|
20371
|
-
return
|
|
20464
|
+
return path26.join(realpathSync6(dir), rest);
|
|
20372
20465
|
} catch {
|
|
20373
|
-
if (
|
|
20374
|
-
return
|
|
20375
|
-
rest = rest ?
|
|
20466
|
+
if (path26.dirname(dir) === dir)
|
|
20467
|
+
return path26.resolve(file);
|
|
20468
|
+
rest = rest ? path26.join(path26.basename(dir), rest) : path26.basename(dir);
|
|
20376
20469
|
}
|
|
20377
20470
|
}
|
|
20378
20471
|
};
|
|
20379
20472
|
var exempt = (cwd, root, file, plans) => {
|
|
20380
20473
|
const fold = (value) => CASE_INSENSITIVE ? value.toLowerCase() : value;
|
|
20381
|
-
const relative =
|
|
20382
|
-
if (relative.startsWith("..") ||
|
|
20474
|
+
const relative = path26.relative(fold(canonical2(root)), fold(canonical2(path26.resolve(cwd, file))));
|
|
20475
|
+
if (relative.startsWith("..") || path26.isAbsolute(relative))
|
|
20383
20476
|
return true;
|
|
20384
|
-
const posix = relative.split(
|
|
20477
|
+
const posix = relative.split(path26.sep).join("/");
|
|
20385
20478
|
const segments = posix.split("/");
|
|
20386
20479
|
return /\.mdx?$/i.test(posix) || segments[0] === "docs" || segments.includes("plans") || [...plans].some((plan) => fold(plan) === posix);
|
|
20387
20480
|
};
|
|
@@ -20479,7 +20572,7 @@ var shellWrites = (command) => {
|
|
|
20479
20572
|
return { writes: true, targets: unknown ? null : targets };
|
|
20480
20573
|
};
|
|
20481
20574
|
var cache2 = new Map;
|
|
20482
|
-
var planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(
|
|
20575
|
+
var planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(path26.resolve(root, file)) ?? "-").join("\x00");
|
|
20483
20576
|
var gateFor = (cwd) => {
|
|
20484
20577
|
const store = new TaskStore(cwd);
|
|
20485
20578
|
const listed = store.listTaskIndex();
|
|
@@ -21351,13 +21444,13 @@ var skillPromptNudge = (prompt, ctx) => process.env.WORKIT_PI_WORKER_SESSION ? n
|
|
|
21351
21444
|
|
|
21352
21445
|
// packages/workit-pi/src/launches.ts
|
|
21353
21446
|
import { mkdirSync as mkdirSync3, readFileSync as readFileSync6, readdirSync as readdirSync5, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "node:fs";
|
|
21354
|
-
import
|
|
21355
|
-
import
|
|
21447
|
+
import os6 from "node:os";
|
|
21448
|
+
import path27 from "node:path";
|
|
21356
21449
|
var launchDir = (root) => {
|
|
21357
21450
|
const location = resolveStore(root);
|
|
21358
|
-
return location instanceof Error ? null :
|
|
21451
|
+
return location instanceof Error ? null : path27.join(location.dir, "pi-launches");
|
|
21359
21452
|
};
|
|
21360
|
-
var fileFor = (dir, workerId) =>
|
|
21453
|
+
var fileFor = (dir, workerId) => path27.join(dir, `${workerId.replace(/[^A-Za-z0-9-]/g, "_")}.json`);
|
|
21361
21454
|
var recordLaunch = (root, attempt) => {
|
|
21362
21455
|
const dir = launchDir(root);
|
|
21363
21456
|
if (!dir)
|
|
@@ -21367,7 +21460,7 @@ var recordLaunch = (root, attempt) => {
|
|
|
21367
21460
|
writeFileSync3(fileFor(dir, attempt.workerId), JSON.stringify({
|
|
21368
21461
|
...attempt,
|
|
21369
21462
|
pid: process.pid,
|
|
21370
|
-
host:
|
|
21463
|
+
host: os6.hostname(),
|
|
21371
21464
|
at: new Date().toISOString()
|
|
21372
21465
|
}), { flag: "wx" });
|
|
21373
21466
|
return true;
|
|
@@ -21381,7 +21474,7 @@ var clearLaunch = (root, workerId) => {
|
|
|
21381
21474
|
rmSync2(fileFor(dir, workerId), { force: true });
|
|
21382
21475
|
};
|
|
21383
21476
|
var alive = (attempt) => {
|
|
21384
|
-
if (attempt.host !==
|
|
21477
|
+
if (attempt.host !== os6.hostname())
|
|
21385
21478
|
return true;
|
|
21386
21479
|
try {
|
|
21387
21480
|
process.kill(attempt.pid, 0);
|
|
@@ -21403,7 +21496,7 @@ var abandonedLaunches = (root) => {
|
|
|
21403
21496
|
const found = [];
|
|
21404
21497
|
for (const name of names) {
|
|
21405
21498
|
try {
|
|
21406
|
-
const attempt = JSON.parse(readFileSync6(
|
|
21499
|
+
const attempt = JSON.parse(readFileSync6(path27.join(dir, name), "utf8"));
|
|
21407
21500
|
if (typeof attempt.workerId === "string" && typeof attempt.session === "string") {
|
|
21408
21501
|
if (!alive(attempt))
|
|
21409
21502
|
found.push(attempt);
|