@brainervirus/workit-pi 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/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,
|
|
@@ -12422,7 +12515,7 @@ function loadCheckConfig(cwd) {
|
|
|
12422
12515
|
gates[gate] = names;
|
|
12423
12516
|
}
|
|
12424
12517
|
}
|
|
12425
|
-
return { source: CHECKS_FILE, root, checks, gates, error: null };
|
|
12518
|
+
return { source: CHECKS_FILE, root, checks, gates, error: null, resources: parsed.resources };
|
|
12426
12519
|
}
|
|
12427
12520
|
var sameArgv = (left, right) => left.length === right.length && left.every((item, index) => item === right[index]);
|
|
12428
12521
|
function matchesNamedCheck(config, name, argv, cwd) {
|
|
@@ -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"],
|
|
@@ -13006,6 +13099,7 @@ var workspaceConfigSchema = object({
|
|
|
13006
13099
|
autoApprove: union([boolean2(), array(nonBlank)]).optional(),
|
|
13007
13100
|
defaultEndpoint: unknown().optional(),
|
|
13008
13101
|
verification: _enum(["self", "independent"]).optional(),
|
|
13102
|
+
trailers: boolean2().optional(),
|
|
13009
13103
|
autonomy: object(Object.fromEntries(["push", "pr", "merge", "release", "rerun"].map((kind) => [
|
|
13010
13104
|
kind,
|
|
13011
13105
|
union([boolean2(), literal("verified")]).optional()
|
|
@@ -13084,7 +13178,7 @@ var validateWorkspacesDocument = (parsed, file) => {
|
|
|
13084
13178
|
};
|
|
13085
13179
|
};
|
|
13086
13180
|
var readWorkspacesResult = (dir = configDir()) => {
|
|
13087
|
-
const file =
|
|
13181
|
+
const file = path12.join(dir, "workspaces.json");
|
|
13088
13182
|
let raw;
|
|
13089
13183
|
try {
|
|
13090
13184
|
raw = readFileSync3(file, "utf8");
|
|
@@ -13195,9 +13289,9 @@ var mainCheckoutOf = (cwd) => {
|
|
|
13195
13289
|
let main = null;
|
|
13196
13290
|
const dirs = git(["rev-parse", "--path-format=absolute", "--git-dir", "--git-common-dir"]);
|
|
13197
13291
|
const [gitDir, common] = (dirs ?? "").trim().split(/\r?\n/u);
|
|
13198
|
-
if (gitDir && common &&
|
|
13292
|
+
if (gitDir && common && path12.resolve(gitDir) !== path12.resolve(common)) {
|
|
13199
13293
|
const listed = /^worktree (.+)$/mu.exec(git(["worktree", "list", "--porcelain"]) ?? "")?.[1];
|
|
13200
|
-
main = listed?.trim() || (
|
|
13294
|
+
main = listed?.trim() || (path12.basename(common) === ".git" ? path12.dirname(common) : common);
|
|
13201
13295
|
}
|
|
13202
13296
|
mainCheckouts.set(cwd, main);
|
|
13203
13297
|
return main;
|
|
@@ -13287,8 +13381,8 @@ var resolveRuntimeWorkspaceVcs = (cwd) => resolveRuntimeWorkspaceCandidate(cwd,
|
|
|
13287
13381
|
var runtimeWorkspaceIndexSchema = object({
|
|
13288
13382
|
workspaces: array(object({ name: nonBlank, glob: nonBlank }).passthrough()).optional()
|
|
13289
13383
|
}).passthrough();
|
|
13290
|
-
var matchRuntimeWorkspace = (cwd) => {
|
|
13291
|
-
const file =
|
|
13384
|
+
var matchRuntimeWorkspace = (cwd, dir = configDir()) => {
|
|
13385
|
+
const file = path12.join(dir, "workspaces.json");
|
|
13292
13386
|
let raw;
|
|
13293
13387
|
try {
|
|
13294
13388
|
raw = readFileSync3(file, "utf8");
|
|
@@ -13317,12 +13411,30 @@ var matchRuntimeWorkspace = (cwd) => {
|
|
|
13317
13411
|
const matches = matchingEntries(cwd, entries ?? []);
|
|
13318
13412
|
const workspaceName = process.env.WORKFLOW_WORKSPACE_NAME?.trim() || undefined;
|
|
13319
13413
|
const selected = selectWorkspaceMatch(matches, cwd, workspaceName);
|
|
13320
|
-
return selected ? { file, selected } : null;
|
|
13414
|
+
return selected ? { file, selected, matches } : null;
|
|
13321
13415
|
};
|
|
13322
13416
|
var resolveRuntimeReleaseTracks = (cwd) => {
|
|
13323
13417
|
const matched = matchRuntimeWorkspace(cwd);
|
|
13324
13418
|
return matched ? { workspace: matched.selected.name, releaseTracks: matched.selected.releaseTracks } : null;
|
|
13325
13419
|
};
|
|
13420
|
+
var workspaceTrailers = (cwd, dir) => {
|
|
13421
|
+
let matched;
|
|
13422
|
+
try {
|
|
13423
|
+
matched = matchRuntimeWorkspace(cwd, dir);
|
|
13424
|
+
} catch {
|
|
13425
|
+
return { enabled: true, workspace: null, from: null };
|
|
13426
|
+
}
|
|
13427
|
+
if (!matched)
|
|
13428
|
+
return { enabled: true, workspace: null, from: null };
|
|
13429
|
+
const { selected, matches } = matched;
|
|
13430
|
+
const enclosing = matches.filter((entry) => entry !== selected).toSorted((a, b) => globSpecificity(b.glob) - globSpecificity(a.glob));
|
|
13431
|
+
const source = [selected, ...enclosing].find((entry) => typeof entry.trailers === "boolean");
|
|
13432
|
+
return {
|
|
13433
|
+
enabled: source?.trailers !== false,
|
|
13434
|
+
workspace: selected.name,
|
|
13435
|
+
from: source?.name ?? null
|
|
13436
|
+
};
|
|
13437
|
+
};
|
|
13326
13438
|
var resolveRuntimeWorkspaceCandidate = (cwd, kind) => {
|
|
13327
13439
|
const matched = matchRuntimeWorkspace(cwd);
|
|
13328
13440
|
if (!matched)
|
|
@@ -13659,7 +13771,7 @@ var git3 = (cwd, args) => {
|
|
|
13659
13771
|
return run.status === 0 ? (run.stdout ?? "").trim() : null;
|
|
13660
13772
|
};
|
|
13661
13773
|
var recordedBaseKey = (branch) => `branch.${branch}.workitBase`;
|
|
13662
|
-
var
|
|
13774
|
+
var escapeRegExp2 = (text) => text.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&");
|
|
13663
13775
|
var reflog = (cwd, ref) => (git3(cwd, ["log", "-g", "--date=unix", "--format=%H%x09%gd%x09%gs", ref, "--"]) ?? "").split(`
|
|
13664
13776
|
`).map((line) => {
|
|
13665
13777
|
const [sha = "", selector = "", ...subject] = line.split("\t");
|
|
@@ -13691,7 +13803,7 @@ function gitTrackProbe(cwd) {
|
|
|
13691
13803
|
const created = own.at(-1);
|
|
13692
13804
|
if (!created || created.subject !== "branch: Created from HEAD")
|
|
13693
13805
|
return null;
|
|
13694
|
-
const pattern = new RegExp(`^checkout: moving from (\\S+) to ${
|
|
13806
|
+
const pattern = new RegExp(`^checkout: moving from (\\S+) to ${escapeRegExp2(branch)}$`, "u");
|
|
13695
13807
|
const entry = reflog(cwd, "HEAD").findLast((item) => item.time >= created.time && item.sha === created.sha && pattern.test(item.subject));
|
|
13696
13808
|
return entry ? pattern.exec(entry.subject)?.[1] ?? null : null;
|
|
13697
13809
|
},
|
|
@@ -13761,7 +13873,7 @@ function resolveTrackFor(cwd, options) {
|
|
|
13761
13873
|
}
|
|
13762
13874
|
|
|
13763
13875
|
// packages/workit-core/src/core/vcs-config.ts
|
|
13764
|
-
var workspacesPath = () =>
|
|
13876
|
+
var workspacesPath = () => path13.join(configDir(), "workspaces.json");
|
|
13765
13877
|
var vcsCwd = (cwd) => cwd ?? process.env.WORKFLOW_WORKSPACE_ROOT ?? process.cwd();
|
|
13766
13878
|
var remoteProvider = (cwd) => {
|
|
13767
13879
|
const r = spawnSync8("git", ["remote", "get-url", "origin"], { cwd, encoding: "utf8" });
|
|
@@ -13936,7 +14048,7 @@ function vcsConfig(mode, cwd, options = {}) {
|
|
|
13936
14048
|
const prov = cfg[provider] ?? {};
|
|
13937
14049
|
const out = {
|
|
13938
14050
|
ok: true,
|
|
13939
|
-
configPath:
|
|
14051
|
+
configPath: path13.resolve(cfgPath),
|
|
13940
14052
|
provider,
|
|
13941
14053
|
defaultTargetBranch: workspaceDefault,
|
|
13942
14054
|
pr: cfg.pr ?? {},
|
|
@@ -14159,14 +14271,14 @@ function diffHash(cwd, base, head) {
|
|
|
14159
14271
|
return `sha256:${hash.digest("hex")}`;
|
|
14160
14272
|
}
|
|
14161
14273
|
function storeRoot(cwd) {
|
|
14162
|
-
const location = resolveStore(
|
|
14274
|
+
const location = resolveStore(path14.resolve(cwd));
|
|
14163
14275
|
if (location instanceof Error)
|
|
14164
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");
|
|
14165
14277
|
return { ok: true, value: { root: location.dir, shared: location.shared } };
|
|
14166
14278
|
}
|
|
14167
14279
|
function ledgerPath(cwd) {
|
|
14168
14280
|
const root = storeRoot(cwd);
|
|
14169
|
-
return root.ok ? { ok: true, value:
|
|
14281
|
+
return root.ok ? { ok: true, value: path14.join(root.value.root, "ledger", "ledger.jsonl") } : root;
|
|
14170
14282
|
}
|
|
14171
14283
|
var newId2 = () => `${Date.now().toString(36)}-${randomBytes2(6).toString("hex")}`;
|
|
14172
14284
|
var NETWORK_FS_TYPES = new Set([
|
|
@@ -14196,13 +14308,13 @@ var LOCK_STALE_MS = 30000;
|
|
|
14196
14308
|
var LOCK_OWNER = "owner";
|
|
14197
14309
|
var lockToken = (lock) => {
|
|
14198
14310
|
try {
|
|
14199
|
-
return fs12.readFileSync(
|
|
14311
|
+
return fs12.readFileSync(path14.join(lock, LOCK_OWNER), "utf8");
|
|
14200
14312
|
} catch {
|
|
14201
14313
|
return null;
|
|
14202
14314
|
}
|
|
14203
14315
|
};
|
|
14204
14316
|
var lockAgeMs = (lock) => {
|
|
14205
|
-
for (const target of [
|
|
14317
|
+
for (const target of [path14.join(lock, LOCK_OWNER), lock]) {
|
|
14206
14318
|
try {
|
|
14207
14319
|
return Date.now() - fs12.statSync(target).mtimeMs;
|
|
14208
14320
|
} catch {}
|
|
@@ -14219,7 +14331,7 @@ var ledgerLock = {
|
|
|
14219
14331
|
throw error;
|
|
14220
14332
|
}
|
|
14221
14333
|
const token = `${process.pid}-${randomBytes2(8).toString("hex")}`;
|
|
14222
|
-
fs12.writeFileSync(
|
|
14334
|
+
fs12.writeFileSync(path14.join(lock, LOCK_OWNER), token);
|
|
14223
14335
|
return token;
|
|
14224
14336
|
},
|
|
14225
14337
|
release(lock, token) {
|
|
@@ -14344,8 +14456,8 @@ function appendLine(file, build, options) {
|
|
|
14344
14456
|
}
|
|
14345
14457
|
};
|
|
14346
14458
|
try {
|
|
14347
|
-
fs12.mkdirSync(
|
|
14348
|
-
if (!options.forceLock && !onNetworkFs(
|
|
14459
|
+
fs12.mkdirSync(path14.dirname(file), { recursive: true });
|
|
14460
|
+
if (!options.forceLock && !onNetworkFs(path14.dirname(file)))
|
|
14349
14461
|
return write();
|
|
14350
14462
|
const locked = withLedgerLock(file, write);
|
|
14351
14463
|
return locked ?? err("busy", `ledger lock ${file}.lock is held`, "retry; remove the .lock directory if no workit process is running");
|
|
@@ -14908,7 +15020,7 @@ var productDecision = (task, ledger) => {
|
|
|
14908
15020
|
};
|
|
14909
15021
|
};
|
|
14910
15022
|
var planRecorded = (task, root) => {
|
|
14911
|
-
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)));
|
|
14912
15024
|
if (cited)
|
|
14913
15025
|
return {
|
|
14914
15026
|
met: true,
|
|
@@ -14968,14 +15080,14 @@ function writeBlockers(task, root) {
|
|
|
14968
15080
|
|
|
14969
15081
|
// packages/workit-core/src/core/task-evaluation.ts
|
|
14970
15082
|
var digestBytes = (value) => createHash10("sha256").update(value).digest("hex");
|
|
14971
|
-
var inside = (root, candidate) => candidate === root || candidate.startsWith(`${root}${
|
|
14972
|
-
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("/") || ".";
|
|
14973
15085
|
var canonicalPath = (value) => {
|
|
14974
15086
|
if (typeof value !== "string" || !value)
|
|
14975
15087
|
return null;
|
|
14976
15088
|
if (value.includes("\\") || value.split("/").includes(".."))
|
|
14977
15089
|
return null;
|
|
14978
|
-
const normalized =
|
|
15090
|
+
const normalized = path16.posix.normalize(value);
|
|
14979
15091
|
if (normalized === ".." || normalized.startsWith("../") || normalized.startsWith("/"))
|
|
14980
15092
|
return null;
|
|
14981
15093
|
return normalized === "." ? "." : normalized.replace(/\/$/, "");
|
|
@@ -15023,14 +15135,14 @@ var gitPaths = (root) => {
|
|
|
15023
15135
|
git: !/not a git repository/i.test(stderr)
|
|
15024
15136
|
};
|
|
15025
15137
|
}
|
|
15026
|
-
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("/")) : [];
|
|
15027
15139
|
const stagedDeleted = spawnSync10("git", ["diff", "--cached", "--name-only", "--diff-filter=D", "-z"], { cwd: root, encoding: "buffer" });
|
|
15028
15140
|
if (stagedDeleted.status !== 0) {
|
|
15029
15141
|
const stderr = stagedDeleted.stderr?.toString("utf8") ?? "";
|
|
15030
15142
|
if (!/not a git repository/i.test(stderr))
|
|
15031
15143
|
return { paths, uncertain: true, git: true };
|
|
15032
15144
|
} else if (stagedDeleted.stdout) {
|
|
15033
|
-
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("/")));
|
|
15034
15146
|
}
|
|
15035
15147
|
return { paths: [...new Set(paths)], uncertain: false, git: true };
|
|
15036
15148
|
};
|
|
@@ -15045,7 +15157,7 @@ var walk = (root, directory, output) => {
|
|
|
15045
15157
|
for (const name of names) {
|
|
15046
15158
|
if (name === ".git" || name === ".workit")
|
|
15047
15159
|
continue;
|
|
15048
|
-
const target =
|
|
15160
|
+
const target = path16.join(directory, name);
|
|
15049
15161
|
let stat;
|
|
15050
15162
|
try {
|
|
15051
15163
|
stat = fs13.lstatSync(target);
|
|
@@ -15063,12 +15175,12 @@ var walk = (root, directory, output) => {
|
|
|
15063
15175
|
var scopeRoots = (root, scope) => {
|
|
15064
15176
|
const roots = [];
|
|
15065
15177
|
for (const item of scope.paths.length ? scope.paths : ["."]) {
|
|
15066
|
-
const target =
|
|
15178
|
+
const target = path16.resolve(root, item);
|
|
15067
15179
|
if (!inside(root, target))
|
|
15068
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` }] });
|
|
15069
15181
|
let ancestor = target;
|
|
15070
15182
|
while (!fs13.existsSync(ancestor) && ancestor !== root)
|
|
15071
|
-
ancestor =
|
|
15183
|
+
ancestor = path16.dirname(ancestor);
|
|
15072
15184
|
try {
|
|
15073
15185
|
if (!inside(root, fs13.realpathSync(ancestor)))
|
|
15074
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` }] });
|
|
@@ -15120,7 +15232,7 @@ function captureCandidate(root, scope, environment = []) {
|
|
|
15120
15232
|
for (const item of [...names].toSorted()) {
|
|
15121
15233
|
if (!scopeMatches(item, normalizedScope))
|
|
15122
15234
|
continue;
|
|
15123
|
-
const target =
|
|
15235
|
+
const target = path16.join(checkout, item);
|
|
15124
15236
|
try {
|
|
15125
15237
|
const stat = fs13.lstatSync(target);
|
|
15126
15238
|
if (stat.isSymbolicLink()) {
|
|
@@ -15304,23 +15416,23 @@ var verifyDecisionContentAtRoot = (checkoutRoot, binding) => {
|
|
|
15304
15416
|
continue;
|
|
15305
15417
|
if (!reference.digest)
|
|
15306
15418
|
return failure2("invalid_input", "document references require a byte digest");
|
|
15307
|
-
const target =
|
|
15308
|
-
if (target !== root && !target.startsWith(`${root}${
|
|
15419
|
+
const target = path16.resolve(root, reference.path);
|
|
15420
|
+
if (target !== root && !target.startsWith(`${root}${path16.sep}`))
|
|
15309
15421
|
return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
|
|
15310
15422
|
fields: [
|
|
15311
15423
|
{ path: "contentRefs.path", reason: `${reference.path} is outside the checkout` }
|
|
15312
15424
|
]
|
|
15313
15425
|
});
|
|
15314
15426
|
try {
|
|
15315
|
-
const below =
|
|
15427
|
+
const below = path16.relative(root, target);
|
|
15316
15428
|
let current = root;
|
|
15317
|
-
for (const segment of below.split(
|
|
15429
|
+
for (const segment of below.split(path16.sep)) {
|
|
15318
15430
|
if (!segment)
|
|
15319
15431
|
continue;
|
|
15320
|
-
current =
|
|
15432
|
+
current = path16.join(current, segment);
|
|
15321
15433
|
const stat = fs13.lstatSync(current);
|
|
15322
15434
|
const real = fs13.realpathSync(current);
|
|
15323
|
-
if (real !== root && !real.startsWith(`${root}${
|
|
15435
|
+
if (real !== root && !real.startsWith(`${root}${path16.sep}`))
|
|
15324
15436
|
return failure2("invalid_input", "document reference escapes checkout; cite it as an external file:// reference instead", {
|
|
15325
15437
|
fields: [
|
|
15326
15438
|
{
|
|
@@ -15695,9 +15807,9 @@ Autonomy contract:
|
|
|
15695
15807
|
ship), go to the effective endpoint in \`workit grant show\`: \`pr\` opens
|
|
15696
15808
|
the PR; \`green\` babysits it without asking (workit-ship) to merge-ready,
|
|
15697
15809
|
never merging; \`merged\` also lands it with \`workit pr merge\`.
|
|
15698
|
-
Merge and release need a workspace grant
|
|
15699
|
-
|
|
15700
|
-
|
|
15810
|
+
Merge and release need a workspace grant only the user raises from their
|
|
15811
|
+
own terminal (a blocked verb names how); never edit workspaces.json or route
|
|
15812
|
+
around a grant_required.
|
|
15701
15813
|
- Ask only for a product or preference choice, or for authority you lack, with
|
|
15702
15814
|
your recommended answer. Facts are yours: read, run or prototype.
|
|
15703
15815
|
- Label claims measured (run and seen this session), inferred, or guess.
|
|
@@ -15706,17 +15818,19 @@ Autonomy contract:
|
|
|
15706
15818
|
- Author is not verifier: your own verdict is \`--self\`, shown as
|
|
15707
15819
|
self-reviewed, never verified. High risk, \`verification: independent\` and
|
|
15708
15820
|
merge need a verifier with its own host-derived session (a subagent's
|
|
15709
|
-
\`<lead>:<child
|
|
15821
|
+
\`<lead>:<child>\`); never hand-mint one (\`<lead>-v1\`).
|
|
15710
15822
|
- A local-commit endpoint does not imply PR readiness, and a local commit alone
|
|
15711
15823
|
is not evidence of a requested remote push. Before reporting delivery,
|
|
15712
15824
|
reconcile every requested item and observe it (\`workit verify-delivery\`).
|
|
15713
15825
|
|
|
15714
15826
|
CLI first: if a step has one right answer, use the \`workit\` verb instead of
|
|
15715
15827
|
hand-running git, gh or glab (\`workit git|pr|ci|check\`; \`workit help\` lists
|
|
15716
|
-
the rest;
|
|
15828
|
+
the rest; lacking \`workit\`, \`npx -y @brainervirus/workit-cli\`).
|
|
15829
|
+
Add Co-Authored-By via \`workit git commit --trailer "K: v" -- <paths>\`, never
|
|
15830
|
+
an amend.
|
|
15717
15831
|
The task families (task, policy, evidence, finding, decision, worker, state)
|
|
15718
15832
|
are optional continuity for tracked work; each branch has one implicit task,
|
|
15719
|
-
|
|
15833
|
+
and a solo edit needs no task. A decision
|
|
15720
15834
|
records a user choice; it never authorizes an effect. Judge work once with
|
|
15721
15835
|
\`workit policy assess --judge risk= behavior= product-choice= plan=\`.
|
|
15722
15836
|
Across repositories, bind each item to its checkout, branch and endpoint,
|
|
@@ -15865,14 +15979,14 @@ var exportDigest = (bundle) => sha256({
|
|
|
15865
15979
|
// packages/workit-core/src/core/route-intent.ts
|
|
15866
15980
|
import { spawnSync as spawnSync12 } from "node:child_process";
|
|
15867
15981
|
import { existsSync as existsSync6 } from "node:fs";
|
|
15868
|
-
import
|
|
15982
|
+
import path19 from "node:path";
|
|
15869
15983
|
|
|
15870
15984
|
// packages/workit-core/src/hooks/raw-git.ts
|
|
15871
15985
|
import { spawnSync as spawnSync11 } from "node:child_process";
|
|
15872
15986
|
import { createHash as createHash13 } from "node:crypto";
|
|
15873
15987
|
import fs15 from "node:fs";
|
|
15874
|
-
import
|
|
15875
|
-
import
|
|
15988
|
+
import os4 from "node:os";
|
|
15989
|
+
import path18 from "node:path";
|
|
15876
15990
|
|
|
15877
15991
|
// packages/workit-core/src/core/branch.ts
|
|
15878
15992
|
import { createHash as createHash11 } from "node:crypto";
|
|
@@ -16155,7 +16269,7 @@ var globOf = (pattern) => pattern.source.replace(/^\^|\$$/gu, "").replaceAll(".*
|
|
|
16155
16269
|
// packages/workit-core/src/hooks/session-marker.ts
|
|
16156
16270
|
import { createHash as createHash12 } from "node:crypto";
|
|
16157
16271
|
import fs14 from "node:fs";
|
|
16158
|
-
import
|
|
16272
|
+
import path17 from "node:path";
|
|
16159
16273
|
var sessionMarkerFile = (input, session, store) => {
|
|
16160
16274
|
let dir = store;
|
|
16161
16275
|
if (dir === undefined) {
|
|
@@ -16165,7 +16279,7 @@ var sessionMarkerFile = (input, session, store) => {
|
|
|
16165
16279
|
dir = location.dir;
|
|
16166
16280
|
}
|
|
16167
16281
|
const name = createHash12("sha256").update(`${input.host}\x00${session}`).digest("hex").slice(0, 32);
|
|
16168
|
-
return
|
|
16282
|
+
return path17.join(dir, "hooks", `skills-${name}.json`);
|
|
16169
16283
|
};
|
|
16170
16284
|
var list2 = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [];
|
|
16171
16285
|
var readSessionMarker = (file) => {
|
|
@@ -16178,7 +16292,7 @@ var readSessionMarker = (file) => {
|
|
|
16178
16292
|
};
|
|
16179
16293
|
var writeSessionMarker = (file, marker) => {
|
|
16180
16294
|
try {
|
|
16181
|
-
fs14.mkdirSync(
|
|
16295
|
+
fs14.mkdirSync(path17.dirname(file), { recursive: true });
|
|
16182
16296
|
fs14.writeFileSync(file, JSON.stringify(marker));
|
|
16183
16297
|
} catch {}
|
|
16184
16298
|
};
|
|
@@ -16323,12 +16437,12 @@ var GIT_VALUE_OPTIONS = new Set([
|
|
|
16323
16437
|
"--config-env",
|
|
16324
16438
|
"--super-prefix"
|
|
16325
16439
|
]);
|
|
16326
|
-
var isAbsolute = (value) =>
|
|
16440
|
+
var isAbsolute = (value) => path18.isAbsolute(value) || /^[A-Za-z]:[\\/]/.test(value) || value.startsWith("\\\\");
|
|
16327
16441
|
var joinDir = (base, next) => {
|
|
16328
16442
|
if (base === undefined || /[$`*?]/.test(next) || next === "-")
|
|
16329
16443
|
return;
|
|
16330
|
-
const expanded = next === "~" || next.startsWith("~/") ?
|
|
16331
|
-
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);
|
|
16332
16446
|
};
|
|
16333
16447
|
var cdTarget = (words) => {
|
|
16334
16448
|
const args = words.slice(1);
|
|
@@ -16379,7 +16493,7 @@ function rawInvocations(command, dialect = "posix", depth = 0) {
|
|
|
16379
16493
|
const name = commandName(words[0]);
|
|
16380
16494
|
if (CD.has(name)) {
|
|
16381
16495
|
const target = cdTarget(words);
|
|
16382
|
-
dir = target === null ?
|
|
16496
|
+
dir = target === null ? os4.homedir() : joinDir(dir, target);
|
|
16383
16497
|
continue;
|
|
16384
16498
|
}
|
|
16385
16499
|
if (PUSHD.has(name)) {
|
|
@@ -16637,17 +16751,17 @@ var headSha2 = (repo) => {
|
|
|
16637
16751
|
if (!git || git.reftable)
|
|
16638
16752
|
return null;
|
|
16639
16753
|
try {
|
|
16640
|
-
const head = fs15.readFileSync(
|
|
16754
|
+
const head = fs15.readFileSync(path18.join(git.gitDir, "HEAD"), "utf8").trim();
|
|
16641
16755
|
if (/^[0-9a-f]{40,64}$/.test(head))
|
|
16642
16756
|
return head;
|
|
16643
16757
|
const ref = /^ref: (refs\/.+)$/.exec(head)?.[1];
|
|
16644
16758
|
if (!ref)
|
|
16645
16759
|
return null;
|
|
16646
|
-
const common =
|
|
16760
|
+
const common = path18.dirname(repo.location.dir);
|
|
16647
16761
|
try {
|
|
16648
|
-
return fs15.readFileSync(
|
|
16762
|
+
return fs15.readFileSync(path18.join(common, ref), "utf8").trim() || null;
|
|
16649
16763
|
} catch {}
|
|
16650
|
-
const packed = fs15.readFileSync(
|
|
16764
|
+
const packed = fs15.readFileSync(path18.join(common, "packed-refs"), "utf8");
|
|
16651
16765
|
return new RegExp(`^([0-9a-f]{40,64}) ${ref.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}$`, "m").exec(packed)?.[1] ?? null;
|
|
16652
16766
|
} catch {
|
|
16653
16767
|
return null;
|
|
@@ -16736,7 +16850,7 @@ var actionsIn = (cwd, command, dialect) => {
|
|
|
16736
16850
|
const action = rawAction(invocation);
|
|
16737
16851
|
if (!action)
|
|
16738
16852
|
continue;
|
|
16739
|
-
const dir =
|
|
16853
|
+
const dir = path18.resolve(cwd, invocation.dir ?? ".");
|
|
16740
16854
|
if (!repos.has(dir)) {
|
|
16741
16855
|
const repo = repoAt(dir);
|
|
16742
16856
|
repos.set(dir, repo && isWorkitWorkspace(repo) ? repo : null);
|
|
@@ -16816,7 +16930,7 @@ function rawGitPre(input, command, options = {}) {
|
|
|
16816
16930
|
var deny = (reason) => ({ kind: "deny", reason, unblock: null });
|
|
16817
16931
|
var NEXT_COMMAND = "next";
|
|
16818
16932
|
var MARKER_TTL_SECONDS = 3600;
|
|
16819
|
-
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`);
|
|
16820
16934
|
var callKey = (toolUseId, command) => toolUseId ?? `cmd:${createHash13("sha256").update(command).digest("hex")}`;
|
|
16821
16935
|
function noteRawCommit(input, command, key) {
|
|
16822
16936
|
try {
|
|
@@ -16827,7 +16941,7 @@ function noteRawCommit(input, command, key) {
|
|
|
16827
16941
|
if (action.kind !== "commit")
|
|
16828
16942
|
continue;
|
|
16829
16943
|
const file = markerFile(repo, input.session.id, key);
|
|
16830
|
-
fs15.mkdirSync(
|
|
16944
|
+
fs15.mkdirSync(path18.dirname(file), { recursive: true });
|
|
16831
16945
|
fs15.writeFileSync(file, `${JSON.stringify({ head: headSha2(repo), at })}
|
|
16832
16946
|
`);
|
|
16833
16947
|
}
|
|
@@ -17000,7 +17114,7 @@ var shellBranchPolicyViolation = (root, command, dialect = "posix") => {
|
|
|
17000
17114
|
for (const target of shellBranchTargets(command, dialect)) {
|
|
17001
17115
|
if (target.dir === undefined)
|
|
17002
17116
|
continue;
|
|
17003
|
-
const dir = target.dir === null ? root :
|
|
17117
|
+
const dir = target.dir === null ? root : path19.resolve(root, target.dir);
|
|
17004
17118
|
if (target.dir !== null && (!existsSync6(dir) || !inWorkitWorkspace(dir)))
|
|
17005
17119
|
continue;
|
|
17006
17120
|
if (localBranchExists(dir, target.branch))
|
|
@@ -17226,20 +17340,20 @@ var judgeInputSummary = (raw) => {
|
|
|
17226
17340
|
};
|
|
17227
17341
|
|
|
17228
17342
|
// packages/workit-core/src/autonomy.ts
|
|
17229
|
-
import
|
|
17230
|
-
import
|
|
17343
|
+
import os5 from "node:os";
|
|
17344
|
+
import path20 from "node:path";
|
|
17231
17345
|
var accountHome = () => {
|
|
17232
17346
|
try {
|
|
17233
|
-
return
|
|
17347
|
+
return os5.userInfo().homedir;
|
|
17234
17348
|
} catch {
|
|
17235
|
-
return
|
|
17349
|
+
return os5.homedir();
|
|
17236
17350
|
}
|
|
17237
17351
|
};
|
|
17238
17352
|
var grantsHome = { resolve: accountHome };
|
|
17239
|
-
var grantsDir = () =>
|
|
17353
|
+
var grantsDir = () => path20.join(grantsHome.resolve(), ".config", "workit");
|
|
17240
17354
|
var grantsOverride = () => {
|
|
17241
|
-
const configured =
|
|
17242
|
-
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`;
|
|
17243
17357
|
};
|
|
17244
17358
|
var GRANT_KINDS = ["push", "pr", "merge", "release", "rerun"];
|
|
17245
17359
|
var DEFAULT_GRANTS = Object.freeze({
|
|
@@ -19011,7 +19125,7 @@ class WorkitCore {
|
|
|
19011
19125
|
// packages/workit-core/src/core/repo-context.ts
|
|
19012
19126
|
import { spawnSync as spawnSync13 } from "node:child_process";
|
|
19013
19127
|
import { existsSync as existsSync7, readFileSync as readFileSync5, readdirSync as readdirSync4 } from "node:fs";
|
|
19014
|
-
import
|
|
19128
|
+
import path21 from "node:path";
|
|
19015
19129
|
var isSafeContextRange = (value) => value.length <= 4096 && (() => {
|
|
19016
19130
|
try {
|
|
19017
19131
|
gitRevisionParts(value);
|
|
@@ -19145,7 +19259,7 @@ var findPrTemplate = (cwd) => {
|
|
|
19145
19259
|
]) {
|
|
19146
19260
|
const parts = rel.split("/");
|
|
19147
19261
|
const base = parts[parts.length - 1];
|
|
19148
|
-
const dir = parts.length > 1 ?
|
|
19262
|
+
const dir = parts.length > 1 ? path21.join(cwd, ...parts.slice(0, -1)) : cwd;
|
|
19149
19263
|
const actual = probeCaseInsensitive(dir, base);
|
|
19150
19264
|
if (actual)
|
|
19151
19265
|
return [...parts.slice(0, -1), actual].join("/");
|
|
@@ -19176,7 +19290,7 @@ var diffStatForRange = (cwd, range) => {
|
|
|
19176
19290
|
return runGit(cwd, ["diff", "--stat", "--"]).stdout;
|
|
19177
19291
|
};
|
|
19178
19292
|
var packageScripts = (cwd, keys) => {
|
|
19179
|
-
const pkgPath =
|
|
19293
|
+
const pkgPath = path21.join(cwd, "package.json");
|
|
19180
19294
|
if (!existsSync7(pkgPath))
|
|
19181
19295
|
return [];
|
|
19182
19296
|
try {
|
|
@@ -19202,9 +19316,9 @@ var documentationFiles = (cwd) => {
|
|
|
19202
19316
|
if (entry.isDirectory()) {
|
|
19203
19317
|
if (excluded.has(entry.name))
|
|
19204
19318
|
continue;
|
|
19205
|
-
walk(
|
|
19319
|
+
walk(path21.join(dir, entry.name), depth + 1);
|
|
19206
19320
|
} else if (entry.isFile() && (entry.name === "README.md" || entry.name.endsWith(".md"))) {
|
|
19207
|
-
matches.push("./" +
|
|
19321
|
+
matches.push("./" + path21.relative(cwd, path21.join(dir, entry.name)).replaceAll("\\", "/"));
|
|
19208
19322
|
}
|
|
19209
19323
|
}
|
|
19210
19324
|
};
|
|
@@ -19220,7 +19334,7 @@ var readTrimmed2 = (file, maxLines) => {
|
|
|
19220
19334
|
`);
|
|
19221
19335
|
};
|
|
19222
19336
|
function prReadyContext(root, range) {
|
|
19223
|
-
const cwd =
|
|
19337
|
+
const cwd = path21.resolve(repoRoot(root));
|
|
19224
19338
|
if (range !== undefined && !isResolvableContextRange(cwd, range))
|
|
19225
19339
|
return invalidRange(cwd);
|
|
19226
19340
|
let stdout = "";
|
|
@@ -19278,7 +19392,7 @@ ${status.stderr}` : "");
|
|
|
19278
19392
|
stdout += `template_path: ${template}
|
|
19279
19393
|
|
|
19280
19394
|
`;
|
|
19281
|
-
stdout += readTrimmed2(
|
|
19395
|
+
stdout += readTrimmed2(path21.join(cwd, template), 220);
|
|
19282
19396
|
} else {
|
|
19283
19397
|
stdout += `template_path: none
|
|
19284
19398
|
|
|
@@ -19288,7 +19402,7 @@ ${status.stderr}` : "");
|
|
|
19288
19402
|
stdout += `
|
|
19289
19403
|
`;
|
|
19290
19404
|
stdout += printSection("Recent Validation Signals");
|
|
19291
|
-
if (existsSync7(
|
|
19405
|
+
if (existsSync7(path21.join(cwd, "package.json"))) {
|
|
19292
19406
|
stdout += `package.json detected. Common scripts:
|
|
19293
19407
|
`;
|
|
19294
19408
|
const found = packageScripts(cwd, ["lint", "format:check", "test", "build"]);
|
|
@@ -19297,7 +19411,7 @@ ${status.stderr}` : "");
|
|
|
19297
19411
|
`) + `
|
|
19298
19412
|
`;
|
|
19299
19413
|
}
|
|
19300
|
-
if (existsSync7(
|
|
19414
|
+
if (existsSync7(path21.join(cwd, "Cargo.toml")) || existsSync7(path21.join(cwd, "src-tauri/Cargo.toml"))) {
|
|
19301
19415
|
stdout += `Rust project detected.
|
|
19302
19416
|
`;
|
|
19303
19417
|
}
|
|
@@ -19330,7 +19444,7 @@ var CHANGELOG_RULES = `- Use an [Unreleased] section.
|
|
|
19330
19444
|
- Apply with the host-native editor, preserving the repository changelog conventions.
|
|
19331
19445
|
- If Unreleased already has duplicate category headings, normalize_only first.`;
|
|
19332
19446
|
function changelogContext(root, range) {
|
|
19333
|
-
const cwd =
|
|
19447
|
+
const cwd = path21.resolve(repoRoot(root));
|
|
19334
19448
|
if (range !== undefined && !isResolvableContextRange(cwd, range))
|
|
19335
19449
|
return invalidRange(cwd);
|
|
19336
19450
|
const resolvedRange = rangeArgOrDefault(range, cwd);
|
|
@@ -19348,7 +19462,7 @@ function changelogContext(root, range) {
|
|
|
19348
19462
|
stdout += CHANGELOG_RULES + `
|
|
19349
19463
|
`;
|
|
19350
19464
|
stdout += printSection("Existing CHANGELOG.md");
|
|
19351
|
-
const changelogPath =
|
|
19465
|
+
const changelogPath = path21.join(cwd, "CHANGELOG.md");
|
|
19352
19466
|
if (existsSync7(changelogPath)) {
|
|
19353
19467
|
stdout += readTrimmed2(changelogPath, 260) + `
|
|
19354
19468
|
`;
|
|
@@ -19368,7 +19482,7 @@ function changelogContext(root, range) {
|
|
|
19368
19482
|
return { stdout, stderr: "", exitCode: 0, cwd };
|
|
19369
19483
|
}
|
|
19370
19484
|
function docsRefreshContext(root, range) {
|
|
19371
|
-
const cwd =
|
|
19485
|
+
const cwd = path21.resolve(repoRoot(root));
|
|
19372
19486
|
if (range !== undefined && !isResolvableContextRange(cwd, range))
|
|
19373
19487
|
return invalidRange(cwd);
|
|
19374
19488
|
const resolvedRange = rangeArgOrDefault(range, cwd);
|
|
@@ -19390,7 +19504,7 @@ function docsRefreshContext(root, range) {
|
|
|
19390
19504
|
`) + `
|
|
19391
19505
|
`;
|
|
19392
19506
|
stdout += printSection("README Preview");
|
|
19393
|
-
const readme =
|
|
19507
|
+
const readme = path21.join(cwd, "README.md");
|
|
19394
19508
|
if (existsSync7(readme)) {
|
|
19395
19509
|
stdout += readTrimmed2(readme, 220) + `
|
|
19396
19510
|
`;
|
|
@@ -19399,7 +19513,7 @@ function docsRefreshContext(root, range) {
|
|
|
19399
19513
|
`;
|
|
19400
19514
|
}
|
|
19401
19515
|
stdout += printSection("Package Scripts");
|
|
19402
|
-
const pkgPath =
|
|
19516
|
+
const pkgPath = path21.join(cwd, "package.json");
|
|
19403
19517
|
if (existsSync7(pkgPath)) {
|
|
19404
19518
|
try {
|
|
19405
19519
|
const pkg = JSON.parse(readFileSync5(pkgPath, "utf8"));
|
|
@@ -19413,7 +19527,7 @@ function docsRefreshContext(root, range) {
|
|
|
19413
19527
|
return { stdout, stderr: "", exitCode: 0, cwd };
|
|
19414
19528
|
}
|
|
19415
19529
|
function releaseNotesContext(root, rangeOrTag) {
|
|
19416
|
-
const cwd =
|
|
19530
|
+
const cwd = path21.resolve(repoRoot(root));
|
|
19417
19531
|
if (!rangeOrTag) {
|
|
19418
19532
|
return { stdout: "", stderr: `ERROR: release tag or range required
|
|
19419
19533
|
`, exitCode: 1, cwd };
|
|
@@ -19451,7 +19565,7 @@ function releaseNotesContext(root, rangeOrTag) {
|
|
|
19451
19565
|
`;
|
|
19452
19566
|
stdout += printSection("Existing Release Files");
|
|
19453
19567
|
for (const rel of ["CHANGELOG.md", "RELEASE_NOTES.md", ".github/releases.md"]) {
|
|
19454
|
-
if (existsSync7(
|
|
19568
|
+
if (existsSync7(path21.join(cwd, rel)))
|
|
19455
19569
|
stdout += rel + `
|
|
19456
19570
|
`;
|
|
19457
19571
|
}
|
|
@@ -19483,7 +19597,7 @@ import { spawnSync as spawnSync15 } from "node:child_process";
|
|
|
19483
19597
|
|
|
19484
19598
|
// packages/workit-core/src/core/pr-create.ts
|
|
19485
19599
|
import fs16 from "node:fs";
|
|
19486
|
-
import
|
|
19600
|
+
import path22 from "node:path";
|
|
19487
19601
|
import { spawnSync as spawnSync14 } from "node:child_process";
|
|
19488
19602
|
// packages/workit-core/src/forge/pr-body.ts
|
|
19489
19603
|
function parseGhIssue(value) {
|
|
@@ -19494,11 +19608,11 @@ function parseGhIssue(value) {
|
|
|
19494
19608
|
// packages/workit-core/src/core/pr-create.ts
|
|
19495
19609
|
function whichOnPath(tool) {
|
|
19496
19610
|
const names = process.platform === "win32" ? [tool, `${tool}.exe`, `${tool}.cmd`] : [tool];
|
|
19497
|
-
for (const dir of (process.env.PATH ?? "").split(
|
|
19611
|
+
for (const dir of (process.env.PATH ?? "").split(path22.delimiter)) {
|
|
19498
19612
|
if (!dir)
|
|
19499
19613
|
continue;
|
|
19500
19614
|
for (const name of names) {
|
|
19501
|
-
const candidate =
|
|
19615
|
+
const candidate = path22.join(dir, name);
|
|
19502
19616
|
try {
|
|
19503
19617
|
fs16.accessSync(candidate, fs16.constants.X_OK);
|
|
19504
19618
|
return candidate;
|
|
@@ -19619,7 +19733,7 @@ var fetchGitLabIssueBody = async (ref, root, deps = {}) => {
|
|
|
19619
19733
|
|
|
19620
19734
|
// packages/workit-core/src/core/youtrack.ts
|
|
19621
19735
|
import fs17 from "node:fs";
|
|
19622
|
-
import
|
|
19736
|
+
import path23 from "node:path";
|
|
19623
19737
|
|
|
19624
19738
|
// packages/workit-core/src/core/templates.ts
|
|
19625
19739
|
var repoRoot2 = assetRoot();
|
|
@@ -19632,8 +19746,8 @@ var resolveWorkspaceRoot = (explicit) => explicit || process.cwd();
|
|
|
19632
19746
|
// packages/workit-core/src/core/youtrack.ts
|
|
19633
19747
|
var ISSUE_RE = /^[A-Z]+-\d+$/;
|
|
19634
19748
|
var TOKEN_PLACEHOLDER = "YOUR_TOKEN_HERE";
|
|
19635
|
-
var youTrackConfigPath = () => process.env.WORKFLOW_YOUTRACK_CONFIG ??
|
|
19636
|
-
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");
|
|
19637
19751
|
var youTrackTokenModeOk = (p) => {
|
|
19638
19752
|
if (process.platform === "win32")
|
|
19639
19753
|
return true;
|
|
@@ -19701,7 +19815,7 @@ var youTrackToken = () => {
|
|
|
19701
19815
|
if ("error" in loaded)
|
|
19702
19816
|
return loaded;
|
|
19703
19817
|
const tokenFile = String(loaded.config.tokenFile ?? "");
|
|
19704
|
-
const tokenPath = tokenFile ?
|
|
19818
|
+
const tokenPath = tokenFile ? path23.isAbsolute(tokenFile) ? path23.resolve(tokenFile) : path23.resolve(process.cwd(), tokenFile) : "";
|
|
19705
19819
|
if (!tokenPath || !fs17.existsSync(tokenPath))
|
|
19706
19820
|
return { error: "missing youtrack.token" };
|
|
19707
19821
|
if (!youTrackTokenModeOk(tokenPath))
|
|
@@ -20058,15 +20172,15 @@ function resolveGitRevision(root, value) {
|
|
|
20058
20172
|
}
|
|
20059
20173
|
function resolveInside(root, candidate) {
|
|
20060
20174
|
const base = realpathSync5(root);
|
|
20061
|
-
const target =
|
|
20062
|
-
if (target !== base && !target.startsWith(base +
|
|
20175
|
+
const target = path24.resolve(base, candidate);
|
|
20176
|
+
if (target !== base && !target.startsWith(base + path24.sep)) {
|
|
20063
20177
|
throw new Error("path must stay inside repository root");
|
|
20064
20178
|
}
|
|
20065
20179
|
let ancestor = target;
|
|
20066
20180
|
while (!existsSync8(ancestor))
|
|
20067
|
-
ancestor =
|
|
20181
|
+
ancestor = path24.dirname(ancestor);
|
|
20068
20182
|
const canonicalAncestor = realpathSync5(ancestor);
|
|
20069
|
-
if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base +
|
|
20183
|
+
if (canonicalAncestor !== base && !canonicalAncestor.startsWith(base + path24.sep)) {
|
|
20070
20184
|
throw new Error("path must stay inside repository root");
|
|
20071
20185
|
}
|
|
20072
20186
|
return target;
|
|
@@ -20112,7 +20226,7 @@ var capabilitiesFor = (descriptor, observed = {}) => descriptor.capabilities.map
|
|
|
20112
20226
|
// packages/workit-core/src/hooks/context.ts
|
|
20113
20227
|
import { createHash as createHash14 } from "node:crypto";
|
|
20114
20228
|
import fs18 from "node:fs";
|
|
20115
|
-
import
|
|
20229
|
+
import path25 from "node:path";
|
|
20116
20230
|
var MIGRATION_PENDING_NOTE = "workit migration pending — run `workit task status`";
|
|
20117
20231
|
var migrationPending = (result) => !result.ok && result.code === "needs_input" && (result.error ?? "").startsWith(MIGRATION_PENDING);
|
|
20118
20232
|
var boundTo = (entry, session) => entry.sessions.some((item) => item.host === session.host && item.handle === session.handle);
|
|
@@ -20197,7 +20311,7 @@ function entryCompactContext(store, entry, session, context) {
|
|
|
20197
20311
|
return null;
|
|
20198
20312
|
const freshness = { mode: "signal", current: () => recentSignal(store.root) };
|
|
20199
20313
|
const observed = task?.data.evidence.some(isObservedCheck) ?? false;
|
|
20200
|
-
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)] : []));
|
|
20201
20315
|
const observedFiles = filesKey(files);
|
|
20202
20316
|
const compact = new WorkitCore(store, context).compactContext(entry?.id ?? null, freshness, origin && { origin: origin.origin, taskId: origin.entry.id });
|
|
20203
20317
|
if (!compact.ok || !compact.data)
|
|
@@ -20275,14 +20389,14 @@ var turnMarker = (input) => {
|
|
|
20275
20389
|
if (location instanceof Error)
|
|
20276
20390
|
return null;
|
|
20277
20391
|
const session = [input.host, input.session.id, input.session.agentId ?? ""].join("\x00");
|
|
20278
|
-
return
|
|
20392
|
+
return path25.join(location.dir, "hooks", `turn-${digestOf(session).slice(0, 32)}.json`);
|
|
20279
20393
|
} catch {
|
|
20280
20394
|
return null;
|
|
20281
20395
|
}
|
|
20282
20396
|
};
|
|
20283
20397
|
var writeTurnDigest = (file, digest) => {
|
|
20284
20398
|
try {
|
|
20285
|
-
fs18.mkdirSync(
|
|
20399
|
+
fs18.mkdirSync(path25.dirname(file), { recursive: true });
|
|
20286
20400
|
fs18.writeFileSync(file, `${JSON.stringify({ digest })}
|
|
20287
20401
|
`);
|
|
20288
20402
|
} catch {}
|
|
@@ -20297,7 +20411,7 @@ var pruneTurnDigests = (dir, now) => {
|
|
|
20297
20411
|
for (const name of fs18.readdirSync(dir)) {
|
|
20298
20412
|
if (!name.startsWith("turn-"))
|
|
20299
20413
|
continue;
|
|
20300
|
-
const file =
|
|
20414
|
+
const file = path25.join(dir, name);
|
|
20301
20415
|
try {
|
|
20302
20416
|
if (now - fs18.statSync(file).mtimeMs > TURN_TTL_MS)
|
|
20303
20417
|
fs18.rmSync(file, { force: true });
|
|
@@ -20327,7 +20441,7 @@ var seedTurnContext = (input, descriptor, text = turnContextText(input, descript
|
|
|
20327
20441
|
const file = turnMarker(input);
|
|
20328
20442
|
if (!file)
|
|
20329
20443
|
return;
|
|
20330
|
-
pruneTurnDigests(
|
|
20444
|
+
pruneTurnDigests(path25.dirname(file), Date.now());
|
|
20331
20445
|
if (text)
|
|
20332
20446
|
writeTurnDigest(file, digestOf(text));
|
|
20333
20447
|
else
|
|
@@ -20340,27 +20454,27 @@ var shellPolicy = (cwd, command, dialect = "posix") => {
|
|
|
20340
20454
|
};
|
|
20341
20455
|
// packages/workit-core/src/hooks/write-gate.ts
|
|
20342
20456
|
import { realpathSync as realpathSync6 } from "node:fs";
|
|
20343
|
-
import
|
|
20457
|
+
import path26 from "node:path";
|
|
20344
20458
|
var NONE3 = { kind: "none" };
|
|
20345
20459
|
var CASE_INSENSITIVE = process.platform === "darwin" || process.platform === "win32";
|
|
20346
20460
|
var canonical2 = (file) => {
|
|
20347
20461
|
let rest = "";
|
|
20348
|
-
for (let dir =
|
|
20462
|
+
for (let dir = path26.resolve(file);; dir = path26.dirname(dir)) {
|
|
20349
20463
|
try {
|
|
20350
|
-
return
|
|
20464
|
+
return path26.join(realpathSync6(dir), rest);
|
|
20351
20465
|
} catch {
|
|
20352
|
-
if (
|
|
20353
|
-
return
|
|
20354
|
-
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);
|
|
20355
20469
|
}
|
|
20356
20470
|
}
|
|
20357
20471
|
};
|
|
20358
20472
|
var exempt = (cwd, root, file, plans) => {
|
|
20359
20473
|
const fold = (value) => CASE_INSENSITIVE ? value.toLowerCase() : value;
|
|
20360
|
-
const relative =
|
|
20361
|
-
if (relative.startsWith("..") ||
|
|
20474
|
+
const relative = path26.relative(fold(canonical2(root)), fold(canonical2(path26.resolve(cwd, file))));
|
|
20475
|
+
if (relative.startsWith("..") || path26.isAbsolute(relative))
|
|
20362
20476
|
return true;
|
|
20363
|
-
const posix = relative.split(
|
|
20477
|
+
const posix = relative.split(path26.sep).join("/");
|
|
20364
20478
|
const segments = posix.split("/");
|
|
20365
20479
|
return /\.mdx?$/i.test(posix) || segments[0] === "docs" || segments.includes("plans") || [...plans].some((plan) => fold(plan) === posix);
|
|
20366
20480
|
};
|
|
@@ -20458,7 +20572,7 @@ var shellWrites = (command) => {
|
|
|
20458
20572
|
return { writes: true, targets: unknown ? null : targets };
|
|
20459
20573
|
};
|
|
20460
20574
|
var cache2 = new Map;
|
|
20461
|
-
var planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(
|
|
20575
|
+
var planKeyOf = (root, plans) => [...plans].map((file) => fileSignature(path26.resolve(root, file)) ?? "-").join("\x00");
|
|
20462
20576
|
var gateFor = (cwd) => {
|
|
20463
20577
|
const store = new TaskStore(cwd);
|
|
20464
20578
|
const listed = store.listTaskIndex();
|
|
@@ -20950,7 +21064,7 @@ var workitRole = (descriptor, agentType) => {
|
|
|
20950
21064
|
};
|
|
20951
21065
|
var subagentSession = (session, agentId) => [session, agentId].filter((part) => Boolean(part)).join(":").replace(/[^A-Za-z0-9_.:@/+-]/g, "-").slice(0, 128);
|
|
20952
21066
|
var CLAUDE_WORKTREE = /[\\/]\.claude[\\/]worktrees[\\/]/;
|
|
20953
|
-
var
|
|
21067
|
+
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\`).`;
|
|
20954
21068
|
var subagentStartText = (input, descriptor, event) => {
|
|
20955
21069
|
const session = input.session.id ?? null;
|
|
20956
21070
|
const role = workitRole(descriptor, event.agentType);
|
|
@@ -20958,9 +21072,9 @@ var subagentStartText = (input, descriptor, event) => {
|
|
|
20958
21072
|
const isolated = descriptor.subagents.worktreeIsolation === "native" && (role === "implementer" || CLAUDE_WORKTREE.test(input.cwd));
|
|
20959
21073
|
const guide = role === "implementer" ? branchGuidance(input.cwd) : null;
|
|
20960
21074
|
if (role === "implementer" && isolated)
|
|
20961
|
-
return `Workit observed ${who} working in its own git worktree: it may edit and commit there, within its brief's scope. ${
|
|
21075
|
+
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.`;
|
|
20962
21076
|
if (isolated)
|
|
20963
|
-
return `${
|
|
21077
|
+
return `${isolatedGit(input.cwd)}
|
|
20964
21078
|
${subagentStartText({ ...input, cwd: "" }, descriptor, event)}`;
|
|
20965
21079
|
if (role === "implementer")
|
|
20966
21080
|
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.`;
|
|
@@ -21330,13 +21444,13 @@ var skillPromptNudge = (prompt, ctx) => process.env.WORKIT_PI_WORKER_SESSION ? n
|
|
|
21330
21444
|
|
|
21331
21445
|
// packages/workit-pi/src/launches.ts
|
|
21332
21446
|
import { mkdirSync as mkdirSync3, readFileSync as readFileSync6, readdirSync as readdirSync5, rmSync as rmSync2, writeFileSync as writeFileSync3 } from "node:fs";
|
|
21333
|
-
import
|
|
21334
|
-
import
|
|
21447
|
+
import os6 from "node:os";
|
|
21448
|
+
import path27 from "node:path";
|
|
21335
21449
|
var launchDir = (root) => {
|
|
21336
21450
|
const location = resolveStore(root);
|
|
21337
|
-
return location instanceof Error ? null :
|
|
21451
|
+
return location instanceof Error ? null : path27.join(location.dir, "pi-launches");
|
|
21338
21452
|
};
|
|
21339
|
-
var fileFor = (dir, workerId) =>
|
|
21453
|
+
var fileFor = (dir, workerId) => path27.join(dir, `${workerId.replace(/[^A-Za-z0-9-]/g, "_")}.json`);
|
|
21340
21454
|
var recordLaunch = (root, attempt) => {
|
|
21341
21455
|
const dir = launchDir(root);
|
|
21342
21456
|
if (!dir)
|
|
@@ -21346,7 +21460,7 @@ var recordLaunch = (root, attempt) => {
|
|
|
21346
21460
|
writeFileSync3(fileFor(dir, attempt.workerId), JSON.stringify({
|
|
21347
21461
|
...attempt,
|
|
21348
21462
|
pid: process.pid,
|
|
21349
|
-
host:
|
|
21463
|
+
host: os6.hostname(),
|
|
21350
21464
|
at: new Date().toISOString()
|
|
21351
21465
|
}), { flag: "wx" });
|
|
21352
21466
|
return true;
|
|
@@ -21360,7 +21474,7 @@ var clearLaunch = (root, workerId) => {
|
|
|
21360
21474
|
rmSync2(fileFor(dir, workerId), { force: true });
|
|
21361
21475
|
};
|
|
21362
21476
|
var alive = (attempt) => {
|
|
21363
|
-
if (attempt.host !==
|
|
21477
|
+
if (attempt.host !== os6.hostname())
|
|
21364
21478
|
return true;
|
|
21365
21479
|
try {
|
|
21366
21480
|
process.kill(attempt.pid, 0);
|
|
@@ -21382,7 +21496,7 @@ var abandonedLaunches = (root) => {
|
|
|
21382
21496
|
const found = [];
|
|
21383
21497
|
for (const name of names) {
|
|
21384
21498
|
try {
|
|
21385
|
-
const attempt = JSON.parse(readFileSync6(
|
|
21499
|
+
const attempt = JSON.parse(readFileSync6(path27.join(dir, name), "utf8"));
|
|
21386
21500
|
if (typeof attempt.workerId === "string" && typeof attempt.session === "string") {
|
|
21387
21501
|
if (!alive(attempt))
|
|
21388
21502
|
found.push(attempt);
|