@brainervirus/workit-claude-code 8.38.1 → 8.38.3
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/.claude-plugin/plugin.json +1 -1
- package/dist/workit.js +946 -832
- package/package.json +3 -3
package/dist/workit.js
CHANGED
|
@@ -9317,7 +9317,7 @@ var package_default;
|
|
|
9317
9317
|
var init_package = __esm(() => {
|
|
9318
9318
|
package_default = {
|
|
9319
9319
|
name: "@brainervirus/workit-cli",
|
|
9320
|
-
version: "8.38.
|
|
9320
|
+
version: "8.38.3",
|
|
9321
9321
|
private: false,
|
|
9322
9322
|
description: "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
|
|
9323
9323
|
keywords: [
|
|
@@ -9355,13 +9355,13 @@ var init_package = __esm(() => {
|
|
|
9355
9355
|
},
|
|
9356
9356
|
dependencies: {
|
|
9357
9357
|
"@babel/parser": "7.29.9",
|
|
9358
|
-
"@brainervirus/workit-cursor": "^8.38.
|
|
9358
|
+
"@brainervirus/workit-cursor": "^8.38.3",
|
|
9359
9359
|
"@inkjs/ui": "2.0.0",
|
|
9360
9360
|
ink: "7.1.1",
|
|
9361
9361
|
react: "19.2.8"
|
|
9362
9362
|
},
|
|
9363
9363
|
devDependencies: {
|
|
9364
|
-
"@brainervirus/workit-core": "^8.38.
|
|
9364
|
+
"@brainervirus/workit-core": "^8.38.3"
|
|
9365
9365
|
},
|
|
9366
9366
|
engines: {
|
|
9367
9367
|
node: ">=24"
|
|
@@ -69625,8 +69625,8 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
69625
69625
|
return `${minutes} min ago`;
|
|
69626
69626
|
const hours = Math.round(minutes / 60);
|
|
69627
69627
|
return hours < 48 ? `${hours} h ago` : `${Math.round(hours / 24)} d ago`;
|
|
69628
|
-
}, checkHookRuns = (res) => {
|
|
69629
|
-
const runs = readHookRuns(res.hookStateDir)
|
|
69628
|
+
}, HOOK_RUN_BASELINE, checkHookRuns = (res) => {
|
|
69629
|
+
const runs = readHookRuns(res.hookStateDir);
|
|
69630
69630
|
if (runs.length === 0)
|
|
69631
69631
|
return {
|
|
69632
69632
|
id: "hook_runs",
|
|
@@ -69636,7 +69636,8 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
69636
69636
|
const now = Date.now();
|
|
69637
69637
|
const hosts = [...new Set(runs.map((run) => run.host))].toSorted();
|
|
69638
69638
|
const parts = hosts.map((host) => {
|
|
69639
|
-
const
|
|
69639
|
+
const others = runs.filter((run) => run.host === host && !HOOK_RUN_BASELINE.includes(run.event)).map((run) => run.event).toSorted();
|
|
69640
|
+
const seen = [...HOOK_RUN_BASELINE, ...new Set(others)].map((event) => {
|
|
69640
69641
|
const run = runs.find((r) => r.host === host && r.event === event);
|
|
69641
69642
|
return `${event} ${run ? `${ago(now - Date.parse(run.at))} (${run.count})` : "never"}`;
|
|
69642
69643
|
});
|
|
@@ -69703,6 +69704,7 @@ var init_doctor = __esm(() => {
|
|
|
69703
69704
|
DAY_MS = 24 * 60 * 60 * 1000;
|
|
69704
69705
|
SEMVER = /\d+\.\d+\.\d+/;
|
|
69705
69706
|
workitVersions = new Map;
|
|
69707
|
+
HOOK_RUN_BASELINE = ["SessionStart", "PreToolUse"];
|
|
69706
69708
|
RUN_CHECKS = [
|
|
69707
69709
|
checkRuntime,
|
|
69708
69710
|
checkVersions,
|
|
@@ -74836,171 +74838,156 @@ var init_setup2 = __esm(() => {
|
|
|
74836
74838
|
ALL_HOSTS = ["claude-code", "codex", "cursor", "opencode", "pi"];
|
|
74837
74839
|
});
|
|
74838
74840
|
|
|
74839
|
-
// packages/workit-cli/src/upgrade.ts
|
|
74840
|
-
import {
|
|
74841
|
-
import {
|
|
74842
|
-
existsSync as existsSync20,
|
|
74843
|
-
mkdtempSync as mkdtempSync3,
|
|
74844
|
-
rmSync as rmSync8,
|
|
74845
|
-
readFileSync as readFileSync21,
|
|
74846
|
-
readdirSync as readdirSync12,
|
|
74847
|
-
mkdirSync as mkdirSync11,
|
|
74848
|
-
copyFileSync as copyFileSync6,
|
|
74849
|
-
chmodSync as chmodSync2,
|
|
74850
|
-
cpSync as cpSync5,
|
|
74851
|
-
lstatSync as lstatSync7
|
|
74852
|
-
} from "node:fs";
|
|
74841
|
+
// packages/workit-cli/src/upgrade/shared.ts
|
|
74842
|
+
import { existsSync as existsSync20, readFileSync as readFileSync21 } from "node:fs";
|
|
74853
74843
|
import path44 from "node:path";
|
|
74854
74844
|
import os16 from "node:os";
|
|
74855
74845
|
import { createHash as createHash15 } from "node:crypto";
|
|
74856
|
-
|
|
74857
|
-
const
|
|
74858
|
-
const
|
|
74859
|
-
|
|
74860
|
-
|
|
74861
|
-
|
|
74862
|
-
|
|
74863
|
-
|
|
74864
|
-
|
|
74865
|
-
|
|
74866
|
-
|
|
74867
|
-
|
|
74868
|
-
|
|
74846
|
+
var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-opencode", OPENCODE_UPDATE, CODEX_MARKETPLACE = "workflow-toolkit", CLI_FIX = "npm install --global @brainervirus/workit-cli@latest", fixFor = (host, selector = "") => host === "pi" ? `pi update --extension ${selector || "npm:@brainervirus/workit-pi"}` : host === "codex" ? `codex plugin marketplace upgrade ${CODEX_MARKETPLACE} && codex plugin add workit@${CODEX_MARKETPLACE}` : host === "claude-code" ? "claude plugin marketplace update workit && claude plugin update workit@workit" : host === "opencode" ? OPENCODE_UPDATE : host === "cursor" ? "workit upgrade --hosts=cursor" : CLI_FIX, upgradePaths = (deps) => {
|
|
74847
|
+
const home = deps.home ?? deps.env?.HOME ?? os16.homedir();
|
|
74848
|
+
const env = {
|
|
74849
|
+
...process.env,
|
|
74850
|
+
...deps.home || deps.env?.HOME ? {
|
|
74851
|
+
HOME: home,
|
|
74852
|
+
CODEX_HOME: path44.join(home, ".codex"),
|
|
74853
|
+
CLAUDE_CONFIG_DIR: path44.join(home, ".claude"),
|
|
74854
|
+
PI_CODING_AGENT_DIR: path44.join(home, ".pi/agent"),
|
|
74855
|
+
XDG_CONFIG_HOME: path44.join(home, ".config"),
|
|
74856
|
+
WORKFLOW_TOOLKIT_CONFIG: undefined,
|
|
74857
|
+
WORKFLOW_TOOLKIT_CONFIG_DIR: undefined
|
|
74858
|
+
} : {},
|
|
74859
|
+
...deps.env,
|
|
74860
|
+
HOME: home
|
|
74869
74861
|
};
|
|
74870
|
-
|
|
74871
|
-
|
|
74872
|
-
|
|
74873
|
-
|
|
74862
|
+
const xdg = env.XDG_CONFIG_HOME || path44.join(home, ".config");
|
|
74863
|
+
const codexHome = env.CODEX_HOME ?? path44.join(home, ".codex");
|
|
74864
|
+
return {
|
|
74865
|
+
home,
|
|
74866
|
+
env,
|
|
74867
|
+
configDir: env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path44.join(xdg, "workit"),
|
|
74868
|
+
opencodeConfig: path44.join(xdg, "opencode/opencode.json"),
|
|
74869
|
+
piSettings: path44.join(env.PI_CODING_AGENT_DIR ?? path44.join(home, ".pi/agent"), "settings.json"),
|
|
74870
|
+
codexHome,
|
|
74871
|
+
codexConfig: path44.join(codexHome, "config.toml"),
|
|
74872
|
+
cursorRoot: path44.join(home, ".cursor/plugins/local/workit")
|
|
74873
|
+
};
|
|
74874
|
+
}, object2 = (file) => {
|
|
74875
|
+
if (!existsSync20(file))
|
|
74876
|
+
return null;
|
|
74877
|
+
let data;
|
|
74878
|
+
try {
|
|
74879
|
+
data = JSON.parse(readFileSync21(file, "utf8"));
|
|
74880
|
+
} catch {
|
|
74881
|
+
throw new Error(`${file} is not valid JSON; use the native host to inspect JSONC settings`);
|
|
74874
74882
|
}
|
|
74875
|
-
|
|
74876
|
-
|
|
74877
|
-
|
|
74878
|
-
|
|
74879
|
-
path44.join(home, ".cursor/mcp.json"),
|
|
74880
|
-
path44.join(paths.cursorRoot, "package.json"),
|
|
74881
|
-
paths.codexConfig,
|
|
74882
|
-
paths.piSettings
|
|
74883
|
-
])
|
|
74884
|
-
plan.configDigests[file] = digest2(file);
|
|
74883
|
+
if (!data || typeof data !== "object" || Array.isArray(data))
|
|
74884
|
+
throw new Error(`${file} is not a configuration object`);
|
|
74885
|
+
return data;
|
|
74886
|
+
}, objectOrNull = (file) => {
|
|
74885
74887
|
try {
|
|
74886
|
-
|
|
74887
|
-
|
|
74888
|
-
|
|
74889
|
-
id: "2.0-remove-ignored-trusted-paths",
|
|
74890
|
-
file: state.config.file,
|
|
74891
|
-
description: "Remove ignored Workit trustedPaths; native host permissions remain unchanged"
|
|
74892
|
-
});
|
|
74893
|
-
} catch (error) {
|
|
74894
|
-
plan.blocked.push(errorText(error));
|
|
74888
|
+
return object2(file);
|
|
74889
|
+
} catch {
|
|
74890
|
+
return null;
|
|
74895
74891
|
}
|
|
74896
|
-
|
|
74897
|
-
|
|
74898
|
-
|
|
74899
|
-
|
|
74900
|
-
|
|
74901
|
-
|
|
74902
|
-
|
|
74892
|
+
}, digest2 = (file) => existsSync20(file) ? createHash15("sha256").update(readFileSync21(file)).digest("hex") : "missing", runner = (deps) => deps.run ?? ((command, args) => {
|
|
74893
|
+
const { home, env } = upgradePaths(deps);
|
|
74894
|
+
let step;
|
|
74895
|
+
try {
|
|
74896
|
+
step = hostCommand(command, args, { home, env });
|
|
74897
|
+
} catch {
|
|
74898
|
+
return { status: 1, stdout: "" };
|
|
74903
74899
|
}
|
|
74904
|
-
|
|
74905
|
-
|
|
74906
|
-
|
|
74907
|
-
|
|
74908
|
-
|
|
74909
|
-
|
|
74910
|
-
|
|
74900
|
+
const result = runHostCommand(step, { home, env });
|
|
74901
|
+
return { status: result.exitCode, stdout: result.stdout };
|
|
74902
|
+
}), errorText = (error) => error instanceof Error ? error.message : "installed source could not be read", piInstalledVersion = (listing, selector) => {
|
|
74903
|
+
const lines = listing.split(/\r?\n/).map((line) => line.trim());
|
|
74904
|
+
const index = lines.indexOf(selector);
|
|
74905
|
+
if (index < 0 || !lines[index + 1] || !path44.isAbsolute(lines[index + 1]))
|
|
74906
|
+
return;
|
|
74907
|
+
const found = objectOrNull(path44.join(lines[index + 1], "package.json"));
|
|
74908
|
+
return found?.name === "@brainervirus/workit-pi" ? found.version : undefined;
|
|
74909
|
+
}, versionAtLeast = (installed, latest) => {
|
|
74910
|
+
if (!/^\d+\.\d+\.\d+$/.test(installed))
|
|
74911
|
+
return false;
|
|
74912
|
+
const current = installed.split(".").map(Number);
|
|
74913
|
+
const target = latest.split(".").map(Number);
|
|
74914
|
+
for (let index = 0;index < 3; index++) {
|
|
74915
|
+
if (current[index] !== target[index])
|
|
74916
|
+
return current[index] > target[index];
|
|
74911
74917
|
}
|
|
74912
|
-
|
|
74913
|
-
|
|
74914
|
-
|
|
74915
|
-
|
|
74916
|
-
|
|
74917
|
-
|
|
74918
|
-
|
|
74919
|
-
|
|
74920
|
-
|
|
74921
|
-
|
|
74922
|
-
|
|
74923
|
-
|
|
74924
|
-
|
|
74925
|
-
|
|
74926
|
-
|
|
74927
|
-
|
|
74928
|
-
|
|
74929
|
-
|
|
74930
|
-
|
|
74931
|
-
|
|
74932
|
-
|
|
74933
|
-
|
|
74934
|
-
|
|
74935
|
-
|
|
74936
|
-
|
|
74937
|
-
|
|
74938
|
-
|
|
74939
|
-
|
|
74940
|
-
|
|
74941
|
-
|
|
74942
|
-
|
|
74943
|
-
|
|
74944
|
-
|
|
74945
|
-
|
|
74946
|
-
|
|
74947
|
-
|
|
74948
|
-
|
|
74949
|
-
|
|
74950
|
-
|
|
74951
|
-
|
|
74952
|
-
|
|
74953
|
-
|
|
74954
|
-
|
|
74955
|
-
|
|
74956
|
-
|
|
74957
|
-
|
|
74958
|
-
|
|
74959
|
-
if (!latest) {
|
|
74960
|
-
plan.failed.push({
|
|
74961
|
-
host: source.host,
|
|
74962
|
-
status: "failed",
|
|
74963
|
-
reason: "registry version unavailable; existing installation preserved",
|
|
74964
|
-
fix: fixFor(source.host, source.selector)
|
|
74965
|
-
});
|
|
74966
|
-
continue;
|
|
74967
|
-
}
|
|
74968
|
-
if (source.installedVersion && versionAtLeast(source.installedVersion, latest)) {
|
|
74969
|
-
plan.skipped.push({
|
|
74970
|
-
host: source.host,
|
|
74971
|
-
reason: `already current (${source.installedVersion})`
|
|
74972
|
-
});
|
|
74973
|
-
continue;
|
|
74974
|
-
}
|
|
74975
|
-
const commands = source.host === "pi" ? [{ command: "pi", args: ["update", "--extension", source.selector] }] : source.host === "codex" ? [
|
|
74976
|
-
{
|
|
74977
|
-
command: "codex",
|
|
74978
|
-
args: ["plugin", "marketplace", "upgrade", CODEX_MARKETPLACE]
|
|
74979
|
-
},
|
|
74980
|
-
{
|
|
74981
|
-
command: "codex",
|
|
74982
|
-
args: ["plugin", "add", `workit@${CODEX_MARKETPLACE}`, "--json"]
|
|
74983
|
-
}
|
|
74984
|
-
] : planHostInstall("cursor", {
|
|
74985
|
-
home,
|
|
74986
|
-
env: deps.env,
|
|
74987
|
-
cwd: home,
|
|
74988
|
-
packageVersion: latest,
|
|
74989
|
-
targetDir: paths.cursorRoot
|
|
74990
|
-
});
|
|
74991
|
-
plan.entries.push({
|
|
74992
|
-
host: source.host,
|
|
74993
|
-
selector: source.selector,
|
|
74994
|
-
latest,
|
|
74995
|
-
commands,
|
|
74996
|
-
installedVersion: source.installedVersion,
|
|
74997
|
-
...source.kind === "repair" ? { repair: true } : {},
|
|
74998
|
-
fix: fixFor(source.host, source.selector)
|
|
74918
|
+
return true;
|
|
74919
|
+
}, registryVersion = (run, name) => {
|
|
74920
|
+
const latest = run("npm", ["view", name, "version"]);
|
|
74921
|
+
const version = latest.stdout.trim();
|
|
74922
|
+
return latest.status === 0 && /^\d+\.\d+\.\d+$/.test(version) ? version : undefined;
|
|
74923
|
+
};
|
|
74924
|
+
var init_shared = __esm(() => {
|
|
74925
|
+
init_host_install();
|
|
74926
|
+
LAUNCH_HOSTS = ["opencode", "cursor", "codex", "pi"];
|
|
74927
|
+
HOSTS2 = [...LAUNCH_HOSTS, "claude-code"];
|
|
74928
|
+
LIVE_HOSTS = new Set(["opencode", "claude-code"]);
|
|
74929
|
+
OPENCODE_UPDATE = `opencode plugin update ${OPENCODE_PACKAGE}`;
|
|
74930
|
+
});
|
|
74931
|
+
|
|
74932
|
+
// packages/workit-cli/src/upgrade/processes.ts
|
|
74933
|
+
import path45 from "node:path";
|
|
74934
|
+
var PROCESS_HOSTS, SCRIPT_RUNTIMES, classifyProcess = (proc) => {
|
|
74935
|
+
if (proc.state.startsWith("Z") || proc.args.includes("<defunct>"))
|
|
74936
|
+
return null;
|
|
74937
|
+
const argv0 = proc.args.trim().split(/\s+/)[0] ?? "";
|
|
74938
|
+
const baseName = (value) => path45.basename(value.replaceAll("\\", "/")).replace(/^\[|\]$/g, "").replace(/\.exe$/i, "").toLowerCase();
|
|
74939
|
+
let host = PROCESS_HOSTS[baseName(argv0)];
|
|
74940
|
+
if (!host && SCRIPT_RUNTIMES.has(baseName(argv0))) {
|
|
74941
|
+
const script = proc.args.trim().split(/\s+/).slice(1).find((arg) => !arg.startsWith("-"));
|
|
74942
|
+
if (script)
|
|
74943
|
+
host = PROCESS_HOSTS[baseName(script).replace(/\.(?:[cm]?js|ts)$/, "")];
|
|
74944
|
+
}
|
|
74945
|
+
if (!host)
|
|
74946
|
+
return null;
|
|
74947
|
+
if (host === "codex" && /\bapp-server\b/.test(proc.args))
|
|
74948
|
+
return /\bdaemon\s+pid-update-loop\b/.test(proc.args) ? null : { ...proc, host, kind: "daemon" };
|
|
74949
|
+
if (host === "opencode" && /\bserve\b/.test(proc.args))
|
|
74950
|
+
return { ...proc, host, kind: "daemon" };
|
|
74951
|
+
return { ...proc, host, kind: "session" };
|
|
74952
|
+
}, listProcesses = (deps) => {
|
|
74953
|
+
if (deps.processes)
|
|
74954
|
+
return deps.processes();
|
|
74955
|
+
if (deps.activeHosts)
|
|
74956
|
+
return deps.activeHosts().map((host) => ({ pid: 0, state: "S", args: host }));
|
|
74957
|
+
const run = runner(deps);
|
|
74958
|
+
if (process.platform === "win32") {
|
|
74959
|
+
const list = run("tasklist", ["/fo", "csv", "/nh"]);
|
|
74960
|
+
if (list.status !== 0)
|
|
74961
|
+
return null;
|
|
74962
|
+
return list.stdout.split(/\r?\n/).flatMap((line) => {
|
|
74963
|
+
const [image, pid] = line.split('","').map((cell) => cell.replaceAll('"', ""));
|
|
74964
|
+
return image && /^\d+$/.test(pid ?? "") ? [{ pid: Number(pid), state: "R", args: image }] : [];
|
|
74999
74965
|
});
|
|
75000
74966
|
}
|
|
75001
|
-
|
|
75002
|
-
|
|
75003
|
-
|
|
74967
|
+
const list = run("ps", ["-eo", "pid=,stat=,args="]);
|
|
74968
|
+
if (list.status !== 0)
|
|
74969
|
+
return null;
|
|
74970
|
+
return list.stdout.split(/\r?\n/).flatMap((line) => {
|
|
74971
|
+
const match = /^\s*(\d+)\s+(\S+)\s+(.+)$/.exec(line);
|
|
74972
|
+
return match ? [{ pid: Number(match[1]), state: match[2], args: match[3] }] : [];
|
|
74973
|
+
});
|
|
74974
|
+
}, describe2 = (proc) => `pid ${proc.pid}: ${proc.args.length > 120 ? `${proc.args.slice(0, 117)}...` : proc.args}`;
|
|
74975
|
+
var init_processes = __esm(() => {
|
|
74976
|
+
init_shared();
|
|
74977
|
+
PROCESS_HOSTS = {
|
|
74978
|
+
claude: "claude-code",
|
|
74979
|
+
codex: "codex",
|
|
74980
|
+
cursor: "cursor",
|
|
74981
|
+
opencode: "opencode",
|
|
74982
|
+
pi: "pi"
|
|
74983
|
+
};
|
|
74984
|
+
SCRIPT_RUNTIMES = new Set(["node", "nodejs", "bun"]);
|
|
74985
|
+
});
|
|
74986
|
+
|
|
74987
|
+
// packages/workit-cli/src/upgrade/apply.ts
|
|
74988
|
+
import { existsSync as existsSync21, readdirSync as readdirSync12, mkdirSync as mkdirSync11, copyFileSync as copyFileSync6, chmodSync as chmodSync2, cpSync as cpSync5 } from "node:fs";
|
|
74989
|
+
import path46 from "node:path";
|
|
74990
|
+
import { createHash as createHash16 } from "node:crypto";
|
|
75004
74991
|
function applyUpgrade(plan, deps = {}) {
|
|
75005
74992
|
const hosts = [...plan.failed];
|
|
75006
74993
|
const done = (backup) => {
|
|
@@ -75034,11 +75021,11 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
75034
75021
|
};
|
|
75035
75022
|
const paths = upgradePaths(deps);
|
|
75036
75023
|
const { home, configDir } = paths;
|
|
75037
|
-
const backup =
|
|
75024
|
+
const backup = path46.join(home, ".local/state/workit/upgrades", new Date().toISOString().replaceAll(":", "-"));
|
|
75038
75025
|
mkdirSync11(backup, { recursive: true, mode: 448 });
|
|
75039
75026
|
for (const file of Object.keys(plan.configDigests))
|
|
75040
|
-
if (
|
|
75041
|
-
const target =
|
|
75027
|
+
if (existsSync21(file)) {
|
|
75028
|
+
const target = path46.join(backup, createHash16("sha256").update(file).digest("hex").slice(0, 12) + "-" + path46.basename(file));
|
|
75042
75029
|
copyFileSync6(file, target);
|
|
75043
75030
|
chmodSync2(target, 384);
|
|
75044
75031
|
}
|
|
@@ -75057,9 +75044,11 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
75057
75044
|
}
|
|
75058
75045
|
const run = runner(deps);
|
|
75059
75046
|
let cursorBackupError = null;
|
|
75060
|
-
if (plan.entries.some((entry) => entry.host === "cursor") &&
|
|
75047
|
+
if (plan.entries.some((entry) => entry.host === "cursor") && existsSync21(paths.cursorRoot))
|
|
75061
75048
|
try {
|
|
75062
|
-
cpSync5(paths.cursorRoot,
|
|
75049
|
+
cpSync5(paths.cursorRoot, path46.join(backup, "cursor-package"), {
|
|
75050
|
+
recursive: true
|
|
75051
|
+
});
|
|
75063
75052
|
} catch (error) {
|
|
75064
75053
|
cursorBackupError = `could not back up the Cursor plugin: ${errorText(error)}`;
|
|
75065
75054
|
}
|
|
@@ -75067,7 +75056,12 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
75067
75056
|
const running = (listed ?? []).flatMap((entry) => classifyProcess(entry) ?? []);
|
|
75068
75057
|
for (const entry of plan.entries) {
|
|
75069
75058
|
if (entry.host === "cursor" && cursorBackupError) {
|
|
75070
|
-
hosts.push({
|
|
75059
|
+
hosts.push({
|
|
75060
|
+
host: "cursor",
|
|
75061
|
+
status: "failed",
|
|
75062
|
+
reason: cursorBackupError,
|
|
75063
|
+
fix: entry.fix
|
|
75064
|
+
});
|
|
75071
75065
|
continue;
|
|
75072
75066
|
}
|
|
75073
75067
|
if (!LIVE_HOSTS.has(entry.host)) {
|
|
@@ -75176,238 +75170,356 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
75176
75170
|
try {
|
|
75177
75171
|
hosts.push(applyCli(plan.cli, run, backup));
|
|
75178
75172
|
} catch (error) {
|
|
75179
|
-
hosts.push({
|
|
75173
|
+
hosts.push({
|
|
75174
|
+
host: "cli",
|
|
75175
|
+
status: "failed",
|
|
75176
|
+
reason: errorText(error),
|
|
75177
|
+
fix: CLI_FIX
|
|
75178
|
+
});
|
|
75180
75179
|
}
|
|
75181
75180
|
return done(backup);
|
|
75182
75181
|
}
|
|
75183
|
-
|
|
75184
|
-
const
|
|
75185
|
-
|
|
75186
|
-
|
|
75187
|
-
|
|
75188
|
-
|
|
75189
|
-
|
|
75190
|
-
out.write(USAGE3);
|
|
75191
|
-
return 2;
|
|
75182
|
+
var codexPluginRoot = (codexHome) => {
|
|
75183
|
+
const dir = path46.join(codexHome, "plugins", "cache", CODEX_MARKETPLACE, "workit");
|
|
75184
|
+
let versions = [];
|
|
75185
|
+
try {
|
|
75186
|
+
versions = readdirSync12(dir).filter((version) => /^\d+\.\d+\.\d+$/.test(version));
|
|
75187
|
+
} catch {
|
|
75188
|
+
return null;
|
|
75192
75189
|
}
|
|
75193
|
-
|
|
75194
|
-
|
|
75195
|
-
|
|
75196
|
-
|
|
75190
|
+
const newest = versions.reduce((best, version) => best && versionAtLeast(best, version) ? best : version, null);
|
|
75191
|
+
return newest ? path46.join(dir, newest) : null;
|
|
75192
|
+
}, opencodeVersion = (run) => {
|
|
75193
|
+
const listing = run("opencode", ["plugin", "list"]);
|
|
75194
|
+
if (listing.status !== 0)
|
|
75195
|
+
return;
|
|
75196
|
+
for (const line of listing.stdout.split(/\r?\n/)) {
|
|
75197
|
+
const fields = line.trim().split(/\s+/);
|
|
75198
|
+
if (fields.length < 3)
|
|
75199
|
+
continue;
|
|
75200
|
+
const source = fields[fields.length - 1].replace(/^file:\/\//, "");
|
|
75201
|
+
const version = fields[fields.length - 2];
|
|
75202
|
+
if (/^(?:npm:)?@brainervirus\/workit-opencode(?:@[^/\s]+)?$/.test(source) && /^\d+\.\d+\.\d+$/.test(version))
|
|
75203
|
+
return version;
|
|
75197
75204
|
}
|
|
75198
|
-
|
|
75199
|
-
|
|
75200
|
-
const run =
|
|
75201
|
-
const
|
|
75202
|
-
|
|
75203
|
-
|
|
75204
|
-
|
|
75205
|
-
|
|
75206
|
-
|
|
75207
|
-
hosts: raw,
|
|
75208
|
-
refreshOnly: true,
|
|
75209
|
-
shell: false,
|
|
75210
|
-
home,
|
|
75211
|
-
env
|
|
75205
|
+
return;
|
|
75206
|
+
}, applyEntry = (entry, context) => {
|
|
75207
|
+
const { run, paths, configDir } = context;
|
|
75208
|
+
const { home, env } = paths;
|
|
75209
|
+
const fail = (reason) => ({
|
|
75210
|
+
host: entry.host,
|
|
75211
|
+
status: "failed",
|
|
75212
|
+
reason,
|
|
75213
|
+
fix: entry.fix
|
|
75212
75214
|
});
|
|
75213
|
-
|
|
75214
|
-
|
|
75215
|
-
|
|
75216
|
-
|
|
75217
|
-
|
|
75218
|
-
|
|
75219
|
-
|
|
75220
|
-
|
|
75221
|
-
|
|
75222
|
-
|
|
75223
|
-
|
|
75224
|
-
|
|
75225
|
-
|
|
75226
|
-
|
|
75227
|
-
|
|
75228
|
-
|
|
75215
|
+
if (entry.host === "cursor") {
|
|
75216
|
+
const preview = {
|
|
75217
|
+
ok: true,
|
|
75218
|
+
blocked: [],
|
|
75219
|
+
preserved: [],
|
|
75220
|
+
overrides: [],
|
|
75221
|
+
platforms: ["cursor"],
|
|
75222
|
+
state: readSetupState(configDir),
|
|
75223
|
+
mutations: [
|
|
75224
|
+
{
|
|
75225
|
+
type: "install-host",
|
|
75226
|
+
platform: "cursor",
|
|
75227
|
+
path: path46.join(home, ".cursor/plugins/local/.workit-package-bootstrap"),
|
|
75228
|
+
commands: entry.commands.map((command) => ({
|
|
75229
|
+
...command,
|
|
75230
|
+
purpose: command.purpose ?? "Upgrade Cursor"
|
|
75231
|
+
}))
|
|
75232
|
+
},
|
|
75233
|
+
{ type: "install-adapter", platform: "cursor", path: paths.cursorRoot }
|
|
75234
|
+
]
|
|
75235
|
+
};
|
|
75236
|
+
const result = applySetupPreview(preview, {
|
|
75237
|
+
home,
|
|
75238
|
+
env,
|
|
75239
|
+
cwd: home,
|
|
75240
|
+
preferInstalledAdapter: true,
|
|
75241
|
+
runHostCommand: (command) => {
|
|
75242
|
+
const outcome = run(command.command, command.args);
|
|
75243
|
+
return {
|
|
75244
|
+
exitCode: outcome.status ?? 1,
|
|
75245
|
+
stdout: outcome.stdout,
|
|
75246
|
+
stderr: ""
|
|
75247
|
+
};
|
|
75248
|
+
}
|
|
75249
|
+
});
|
|
75250
|
+
const installed = objectOrNull(path46.join(paths.cursorRoot, "package.json"));
|
|
75251
|
+
if (!result.ok || installed?.version !== entry.latest)
|
|
75252
|
+
return fail("Cursor install did not verify the requested package version; inspect the installer before retrying");
|
|
75253
|
+
return {
|
|
75254
|
+
host: "cursor",
|
|
75255
|
+
status: "updated",
|
|
75256
|
+
reason: entry.repair ? `reinstalled missing plugin files (${entry.latest})` : `${entry.installedVersion ?? "?"} -> ${entry.latest}`
|
|
75257
|
+
};
|
|
75229
75258
|
}
|
|
75230
|
-
|
|
75231
|
-
|
|
75232
|
-
|
|
75233
|
-
|
|
75234
|
-
|
|
75259
|
+
const before = entry.host === "opencode" ? opencodeVersion(run) : undefined;
|
|
75260
|
+
for (const command of entry.commands)
|
|
75261
|
+
if (run(command.command, command.args).status !== 0)
|
|
75262
|
+
return fail(`\`${command.command} ${command.args.join(" ")}\` failed`);
|
|
75263
|
+
if (entry.host === "opencode") {
|
|
75264
|
+
const after = opencodeVersion(run);
|
|
75265
|
+
if (before && after)
|
|
75266
|
+
return after === before ? {
|
|
75267
|
+
host: "opencode",
|
|
75268
|
+
status: "current",
|
|
75269
|
+
reason: `already current (${after})`
|
|
75270
|
+
} : {
|
|
75271
|
+
host: "opencode",
|
|
75272
|
+
status: "updated",
|
|
75273
|
+
reason: `${before} -> ${after}; OpenCode V2 loads it live`
|
|
75274
|
+
};
|
|
75275
|
+
return {
|
|
75276
|
+
host: "opencode",
|
|
75277
|
+
status: "updated",
|
|
75278
|
+
reason: "scoped update ran; OpenCode V2 loads it live"
|
|
75279
|
+
};
|
|
75235
75280
|
}
|
|
75236
|
-
if (
|
|
75237
|
-
|
|
75238
|
-
|
|
75239
|
-
|
|
75240
|
-
|
|
75281
|
+
if (entry.host === "claude-code") {
|
|
75282
|
+
const after = claudeWorkitInstalls(home, env, null).find((install) => install.id === entry.selector)?.version;
|
|
75283
|
+
return after && after === entry.installedVersion ? {
|
|
75284
|
+
host: "claude-code",
|
|
75285
|
+
status: "current",
|
|
75286
|
+
reason: `already current (${after})`
|
|
75287
|
+
} : {
|
|
75288
|
+
host: "claude-code",
|
|
75289
|
+
status: "updated",
|
|
75290
|
+
reason: `${entry.installedVersion ?? "?"} -> ${after ?? "?"}; new sessions load it`
|
|
75291
|
+
};
|
|
75241
75292
|
}
|
|
75242
|
-
const
|
|
75243
|
-
if (
|
|
75244
|
-
|
|
75245
|
-
|
|
75246
|
-
|
|
75247
|
-
|
|
75248
|
-
|
|
75293
|
+
const verify = entry.host === "codex" ? run("codex", ["plugin", "list", "--json"]) : run("pi", ["list"]);
|
|
75294
|
+
if (verify.status !== 0)
|
|
75295
|
+
return fail("update verification failed");
|
|
75296
|
+
if (entry.host === "codex") {
|
|
75297
|
+
let installed = [];
|
|
75298
|
+
try {
|
|
75299
|
+
installed = JSON.parse(verify.stdout).installed ?? [];
|
|
75300
|
+
} catch {}
|
|
75301
|
+
if (!installed.some((plugin) => plugin.name === "workit" && plugin.marketplaceName === CODEX_MARKETPLACE && plugin.version === entry.latest))
|
|
75302
|
+
return fail("Codex did not report the requested Workit version");
|
|
75249
75303
|
}
|
|
75250
|
-
if (
|
|
75251
|
-
|
|
75252
|
-
|
|
75253
|
-
|
|
75254
|
-
|
|
75255
|
-
|
|
75256
|
-
|
|
75257
|
-
|
|
75258
|
-
|
|
75259
|
-
|
|
75260
|
-
|
|
75261
|
-
|
|
75262
|
-
|
|
75263
|
-
|
|
75264
|
-
|
|
75265
|
-
|
|
75304
|
+
if (entry.host === "pi" && piInstalledVersion(verify.stdout, entry.selector) !== entry.latest)
|
|
75305
|
+
return fail("Pi did not report the requested Workit package version");
|
|
75306
|
+
return {
|
|
75307
|
+
host: entry.host,
|
|
75308
|
+
status: "updated",
|
|
75309
|
+
reason: entry.repair ? `reinstalled missing plugin files (${entry.latest})` : `${entry.installedVersion ?? "?"} -> ${entry.latest}`
|
|
75310
|
+
};
|
|
75311
|
+
}, refreshCodexAgents = (run, codexHome) => {
|
|
75312
|
+
const root = codexPluginRoot(codexHome);
|
|
75313
|
+
const launcher = root && path46.join(root, "dist", "launch-mcp.js");
|
|
75314
|
+
if (!launcher || !existsSync21(launcher))
|
|
75315
|
+
return { ok: true, note: "" };
|
|
75316
|
+
const fix = `node ${JSON.stringify(launcher)} --install-agents`;
|
|
75317
|
+
return run("node", [launcher, "--install-agents"]).status === 0 ? { ok: true, note: "agents refreshed" } : { ok: false, note: "agent refresh failed", fix };
|
|
75318
|
+
}, applyCli = (cli, run, backup) => {
|
|
75319
|
+
const fail = (reason) => ({
|
|
75320
|
+
host: "cli",
|
|
75321
|
+
status: "failed",
|
|
75322
|
+
reason,
|
|
75323
|
+
fix: CLI_FIX
|
|
75324
|
+
});
|
|
75325
|
+
const currentRoot = run("npm", ["root", "--global"]);
|
|
75326
|
+
if (currentRoot.status !== 0 || currentRoot.stdout.trim() !== cli.root)
|
|
75327
|
+
return fail("Global npm location changed; preview again");
|
|
75328
|
+
const cliBackup = path46.join(backup, "cli-package");
|
|
75329
|
+
cpSync5(path46.join(cli.root, "@brainervirus/workit-cli"), cliBackup, {
|
|
75330
|
+
recursive: true
|
|
75331
|
+
});
|
|
75332
|
+
if (run("npm", ["install", "--global", `@brainervirus/workit-cli@${cli.latest}`]).status !== 0)
|
|
75333
|
+
return fail(`CLI update failed; preserved package at ${cliBackup}; use npm to repair or run node ${path46.join(cliBackup, "dist/index.js")}`);
|
|
75334
|
+
const installed = objectOrNull(path46.join(cli.root, "@brainervirus/workit-cli/package.json"));
|
|
75335
|
+
if (installed?.name !== "@brainervirus/workit-cli" || installed.version !== cli.latest)
|
|
75336
|
+
return fail(`CLI update did not verify the requested version; preserved package at ${cliBackup}`);
|
|
75337
|
+
return {
|
|
75338
|
+
host: "cli",
|
|
75339
|
+
status: "updated",
|
|
75340
|
+
reason: `${cli.installed} -> ${cli.latest}`
|
|
75341
|
+
};
|
|
75342
|
+
};
|
|
75343
|
+
var init_apply = __esm(() => {
|
|
75344
|
+
init_host_install();
|
|
75345
|
+
init_setup_state();
|
|
75346
|
+
init_setup();
|
|
75347
|
+
init_safe_write();
|
|
75348
|
+
init_processes();
|
|
75349
|
+
init_shared();
|
|
75350
|
+
});
|
|
75351
|
+
|
|
75352
|
+
// packages/workit-cli/src/upgrade/plan.ts
|
|
75353
|
+
import { existsSync as existsSync22, mkdtempSync as mkdtempSync3, rmSync as rmSync8, lstatSync as lstatSync7, readFileSync as readFileSync22 } from "node:fs";
|
|
75354
|
+
import path47 from "node:path";
|
|
75355
|
+
import os17 from "node:os";
|
|
75356
|
+
function previewUpgrade(hosts = HOSTS2, deps = {}) {
|
|
75357
|
+
const paths = upgradePaths(deps);
|
|
75358
|
+
const { home, configDir } = paths;
|
|
75359
|
+
const run = runner(deps);
|
|
75360
|
+
const state = readSetupState(configDir);
|
|
75361
|
+
const plan = {
|
|
75362
|
+
ok: true,
|
|
75363
|
+
blocked: [],
|
|
75364
|
+
failed: [],
|
|
75365
|
+
skipped: [],
|
|
75366
|
+
entries: [],
|
|
75367
|
+
configDigests: {},
|
|
75368
|
+
migrations: []
|
|
75369
|
+
};
|
|
75370
|
+
for (const file of [state.config, state.workspaces, state.youtrack, state.vcs]) {
|
|
75371
|
+
if (file.status === "malformed")
|
|
75372
|
+
plan.blocked.push(file.error ?? file.file);
|
|
75373
|
+
plan.configDigests[file.file] = digest2(file.file);
|
|
75374
|
+
}
|
|
75375
|
+
for (const file of [
|
|
75376
|
+
paths.opencodeConfig,
|
|
75377
|
+
paths.opencodeConfig + "c",
|
|
75378
|
+
path47.join(home, ".cursor/settings.json"),
|
|
75379
|
+
path47.join(home, ".cursor/mcp.json"),
|
|
75380
|
+
path47.join(paths.cursorRoot, "package.json"),
|
|
75381
|
+
paths.codexConfig,
|
|
75382
|
+
paths.piSettings
|
|
75383
|
+
])
|
|
75384
|
+
plan.configDigests[file] = digest2(file);
|
|
75385
|
+
try {
|
|
75386
|
+
const config = object2(state.config.file);
|
|
75387
|
+
if (config && Object.hasOwn(config, "trustedPaths"))
|
|
75388
|
+
plan.migrations.push({
|
|
75389
|
+
id: "2.0-remove-ignored-trusted-paths",
|
|
75390
|
+
file: state.config.file,
|
|
75391
|
+
description: "Remove ignored Workit trustedPaths; native host permissions remain unchanged"
|
|
75266
75392
|
});
|
|
75393
|
+
} catch (error) {
|
|
75394
|
+
plan.blocked.push(errorText(error));
|
|
75267
75395
|
}
|
|
75268
|
-
const
|
|
75269
|
-
|
|
75270
|
-
|
|
75271
|
-
|
|
75272
|
-
|
|
75273
|
-
|
|
75274
|
-
|
|
75275
|
-
ok: !failed,
|
|
75276
|
-
...written ? { permissions: { changes: permissionPreview.changes, written } } : permissions.refused ? { permissions: permissionPreview } : {},
|
|
75277
|
-
doctor: { clean: left.length === 0, left }
|
|
75278
|
-
}, null, 2) + `
|
|
75279
|
-
`);
|
|
75280
|
-
return failed ? 1 : 0;
|
|
75396
|
+
const installedSources = sources(paths, run, hosts, plan.failed);
|
|
75397
|
+
let opencodeHelp;
|
|
75398
|
+
if (installedSources.some((source) => source.host === "opencode")) {
|
|
75399
|
+
const probe = opencodeProbe(deps, ["--version"]);
|
|
75400
|
+
const installed = probe.status === 0 ? probe.stdout.match(/\d+\.\d+\.\d+/)?.[0] : undefined;
|
|
75401
|
+
if (installed && !versionAtLeast(installed, SUPPORT_MATRIX.opencode.minimum))
|
|
75402
|
+
(plan.warnings ??= []).push(`opencode ${installed}: ${OPENCODE_V1_FIX}`);
|
|
75281
75403
|
}
|
|
75282
|
-
|
|
75283
|
-
|
|
75284
|
-
|
|
75285
|
-
|
|
75286
|
-
|
|
75287
|
-
|
|
75288
|
-
|
|
75289
|
-
if (result.backup)
|
|
75290
|
-
out.write(`Backup: ${result.backup}
|
|
75291
|
-
`);
|
|
75292
|
-
out.write(left.length === 0 ? `Verified: workit doctor is clean for versions, assets, agents and permissions.
|
|
75293
|
-
` : `Left after upgrade (workit doctor):
|
|
75294
|
-
${left.map((check) => ` ${check.id}: ${check.detail}${check.fix ? `
|
|
75295
|
-
fix: ${check.fix}` : ""}`).join(`
|
|
75296
|
-
`)}
|
|
75297
|
-
`);
|
|
75298
|
-
return failed ? 1 : 0;
|
|
75299
|
-
}
|
|
75300
|
-
async function runLaunchCommand(argv, deps = {}) {
|
|
75301
|
-
const [host, ...args] = argv;
|
|
75302
|
-
if (!LAUNCH_HOSTS.includes(host)) {
|
|
75303
|
-
(deps.out ?? process.stdout).write(`Usage: workit launch <opencode|cursor|codex|pi> [--auto-upgrade] [-- host arguments]
|
|
75304
|
-
`);
|
|
75305
|
-
return 2;
|
|
75404
|
+
for (const host of ["opencode", "pi"]) {
|
|
75405
|
+
if (new Set(installedSources.filter((source) => source.host === host).map((source) => source.selector)).size > 1)
|
|
75406
|
+
plan.failed.push({
|
|
75407
|
+
host,
|
|
75408
|
+
status: "failed",
|
|
75409
|
+
reason: "conflicting Workit registrations; reconcile them in the native host before upgrading"
|
|
75410
|
+
});
|
|
75306
75411
|
}
|
|
75307
|
-
const
|
|
75308
|
-
const
|
|
75309
|
-
|
|
75310
|
-
|
|
75311
|
-
|
|
75312
|
-
|
|
75313
|
-
|
|
75314
|
-
|
|
75315
|
-
} catch (error) {
|
|
75316
|
-
(deps.out ?? process.stderr).write(`${error instanceof Error ? error.message : "Host executable unavailable"}
|
|
75317
|
-
`);
|
|
75318
|
-
return 1;
|
|
75412
|
+
const conflicted = new Set(plan.failed.map((entry) => entry.host));
|
|
75413
|
+
for (const source of installedSources.filter((candidate, index, list) => !conflicted.has(candidate.host) && list.findIndex((entry) => entry.host === candidate.host && entry.selector === candidate.selector) === index)) {
|
|
75414
|
+
if (source.kind === "pinned" || source.kind === "local") {
|
|
75415
|
+
plan.skipped.push({
|
|
75416
|
+
host: source.host,
|
|
75417
|
+
reason: `${source.kind} source preserved; change its source explicitly to upgrade`
|
|
75418
|
+
});
|
|
75419
|
+
continue;
|
|
75319
75420
|
}
|
|
75320
|
-
|
|
75321
|
-
|
|
75322
|
-
|
|
75323
|
-
|
|
75324
|
-
|
|
75325
|
-
|
|
75326
|
-
|
|
75327
|
-
|
|
75328
|
-
|
|
75329
|
-
|
|
75330
|
-
|
|
75331
|
-
|
|
75332
|
-
|
|
75421
|
+
if (source.host === "claude-code") {
|
|
75422
|
+
const [market] = source.selector.split("@").slice(1);
|
|
75423
|
+
plan.entries.push({
|
|
75424
|
+
host: "claude-code",
|
|
75425
|
+
selector: source.selector,
|
|
75426
|
+
latest: "",
|
|
75427
|
+
installedVersion: source.installedVersion,
|
|
75428
|
+
commands: [
|
|
75429
|
+
{
|
|
75430
|
+
command: "claude",
|
|
75431
|
+
args: ["plugin", "marketplace", "update", market ?? "workit"]
|
|
75432
|
+
},
|
|
75433
|
+
{ command: "claude", args: ["plugin", "update", source.selector] }
|
|
75434
|
+
],
|
|
75435
|
+
fix: `claude plugin marketplace update ${market ?? "workit"} && claude plugin update ${source.selector}`
|
|
75436
|
+
});
|
|
75437
|
+
continue;
|
|
75438
|
+
}
|
|
75439
|
+
if (source.host === "opencode") {
|
|
75440
|
+
opencodeHelp ??= opencodeProbe(deps, ["plugin", "--help"]).stdout;
|
|
75441
|
+
if (!/^\s*(?:opencode\s+plugin\s+)?update\b/m.test(opencodeHelp)) {
|
|
75442
|
+
plan.skipped.push({
|
|
75443
|
+
host: "opencode",
|
|
75444
|
+
reason: "this OpenCode has no `opencode plugin update`; upgrade OpenCode, then run the fix. Workit never updates unrelated plugins",
|
|
75445
|
+
fix: OPENCODE_UPDATE
|
|
75446
|
+
});
|
|
75447
|
+
continue;
|
|
75333
75448
|
}
|
|
75334
|
-
|
|
75335
|
-
|
|
75336
|
-
|
|
75337
|
-
|
|
75338
|
-
|
|
75339
|
-
|
|
75340
|
-
|
|
75449
|
+
plan.entries.push({
|
|
75450
|
+
host: "opencode",
|
|
75451
|
+
selector: source.selector,
|
|
75452
|
+
latest: "",
|
|
75453
|
+
commands: [{ command: "opencode", args: ["plugin", "update", OPENCODE_PACKAGE] }],
|
|
75454
|
+
fix: OPENCODE_UPDATE
|
|
75455
|
+
});
|
|
75456
|
+
continue;
|
|
75341
75457
|
}
|
|
75458
|
+
const latest = registryVersion(run, `@brainervirus/workit-${source.host}`);
|
|
75459
|
+
if (!latest) {
|
|
75460
|
+
plan.failed.push({
|
|
75461
|
+
host: source.host,
|
|
75462
|
+
status: "failed",
|
|
75463
|
+
reason: "registry version unavailable; existing installation preserved",
|
|
75464
|
+
fix: fixFor(source.host, source.selector)
|
|
75465
|
+
});
|
|
75466
|
+
continue;
|
|
75467
|
+
}
|
|
75468
|
+
if (source.installedVersion && versionAtLeast(source.installedVersion, latest)) {
|
|
75469
|
+
plan.skipped.push({
|
|
75470
|
+
host: source.host,
|
|
75471
|
+
reason: `already current (${source.installedVersion})`
|
|
75472
|
+
});
|
|
75473
|
+
continue;
|
|
75474
|
+
}
|
|
75475
|
+
const commands = source.host === "pi" ? [{ command: "pi", args: ["update", "--extension", source.selector] }] : source.host === "codex" ? [
|
|
75476
|
+
{
|
|
75477
|
+
command: "codex",
|
|
75478
|
+
args: ["plugin", "marketplace", "upgrade", CODEX_MARKETPLACE]
|
|
75479
|
+
},
|
|
75480
|
+
{
|
|
75481
|
+
command: "codex",
|
|
75482
|
+
args: ["plugin", "add", `workit@${CODEX_MARKETPLACE}`, "--json"]
|
|
75483
|
+
}
|
|
75484
|
+
] : planHostInstall("cursor", {
|
|
75485
|
+
home,
|
|
75486
|
+
env: deps.env,
|
|
75487
|
+
cwd: home,
|
|
75488
|
+
packageVersion: latest,
|
|
75489
|
+
targetDir: paths.cursorRoot
|
|
75490
|
+
});
|
|
75491
|
+
plan.entries.push({
|
|
75492
|
+
host: source.host,
|
|
75493
|
+
selector: source.selector,
|
|
75494
|
+
latest,
|
|
75495
|
+
commands,
|
|
75496
|
+
installedVersion: source.installedVersion,
|
|
75497
|
+
...source.kind === "repair" ? { repair: true } : {},
|
|
75498
|
+
fix: fixFor(source.host, source.selector)
|
|
75499
|
+
});
|
|
75342
75500
|
}
|
|
75343
|
-
|
|
75344
|
-
|
|
75345
|
-
return spawnSync17(launch.command, launch.args, {
|
|
75346
|
-
stdio: "inherit",
|
|
75347
|
-
env
|
|
75348
|
-
}).status ?? 1;
|
|
75501
|
+
plan.ok = plan.blocked.length === 0 && plan.failed.length === 0;
|
|
75502
|
+
return plan;
|
|
75349
75503
|
}
|
|
75350
|
-
var
|
|
75351
|
-
|
|
75352
|
-
const env = {
|
|
75353
|
-
...process.env,
|
|
75354
|
-
...deps.home || deps.env?.HOME ? {
|
|
75355
|
-
HOME: home,
|
|
75356
|
-
CODEX_HOME: path44.join(home, ".codex"),
|
|
75357
|
-
CLAUDE_CONFIG_DIR: path44.join(home, ".claude"),
|
|
75358
|
-
PI_CODING_AGENT_DIR: path44.join(home, ".pi/agent"),
|
|
75359
|
-
XDG_CONFIG_HOME: path44.join(home, ".config"),
|
|
75360
|
-
WORKFLOW_TOOLKIT_CONFIG: undefined,
|
|
75361
|
-
WORKFLOW_TOOLKIT_CONFIG_DIR: undefined
|
|
75362
|
-
} : {},
|
|
75363
|
-
...deps.env,
|
|
75364
|
-
HOME: home
|
|
75365
|
-
};
|
|
75366
|
-
const xdg = env.XDG_CONFIG_HOME || path44.join(home, ".config");
|
|
75367
|
-
const codexHome = env.CODEX_HOME ?? path44.join(home, ".codex");
|
|
75368
|
-
return {
|
|
75369
|
-
home,
|
|
75370
|
-
env,
|
|
75371
|
-
configDir: env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path44.join(xdg, "workit"),
|
|
75372
|
-
opencodeConfig: path44.join(xdg, "opencode/opencode.json"),
|
|
75373
|
-
piSettings: path44.join(env.PI_CODING_AGENT_DIR ?? path44.join(home, ".pi/agent"), "settings.json"),
|
|
75374
|
-
codexHome,
|
|
75375
|
-
codexConfig: path44.join(codexHome, "config.toml"),
|
|
75376
|
-
cursorRoot: path44.join(home, ".cursor/plugins/local/workit")
|
|
75377
|
-
};
|
|
75378
|
-
}, object2 = (file) => {
|
|
75379
|
-
if (!existsSync20(file))
|
|
75380
|
-
return null;
|
|
75381
|
-
let data;
|
|
75382
|
-
try {
|
|
75383
|
-
data = JSON.parse(readFileSync21(file, "utf8"));
|
|
75384
|
-
} catch {
|
|
75385
|
-
throw new Error(`${file} is not valid JSON; use the native host to inspect JSONC settings`);
|
|
75386
|
-
}
|
|
75387
|
-
if (!data || typeof data !== "object" || Array.isArray(data))
|
|
75388
|
-
throw new Error(`${file} is not a configuration object`);
|
|
75389
|
-
return data;
|
|
75390
|
-
}, objectOrNull = (file) => {
|
|
75391
|
-
try {
|
|
75392
|
-
return object2(file);
|
|
75393
|
-
} catch {
|
|
75394
|
-
return null;
|
|
75395
|
-
}
|
|
75396
|
-
}, digest2 = (file) => existsSync20(file) ? createHash15("sha256").update(readFileSync21(file)).digest("hex") : "missing", runner = (deps) => deps.run ?? ((command, args) => {
|
|
75397
|
-
const { home, env } = upgradePaths(deps);
|
|
75398
|
-
let step;
|
|
75504
|
+
var codexRegistered = (configFile) => {
|
|
75505
|
+
let text;
|
|
75399
75506
|
try {
|
|
75400
|
-
|
|
75507
|
+
text = readFileSync22(configFile, "utf8");
|
|
75401
75508
|
} catch {
|
|
75402
|
-
return
|
|
75509
|
+
return false;
|
|
75403
75510
|
}
|
|
75404
|
-
const
|
|
75405
|
-
|
|
75406
|
-
|
|
75511
|
+
const header = `[plugins."workit@${CODEX_MARKETPLACE}"]`;
|
|
75512
|
+
const start = text.split(/\r?\n/).findIndex((line) => line.trim() === header);
|
|
75513
|
+
if (start < 0)
|
|
75514
|
+
return false;
|
|
75515
|
+
const body = text.split(/\r?\n/).slice(start + 1).join(`
|
|
75516
|
+
`).split(/^\s*\[/m)[0];
|
|
75517
|
+
return !/^\s*enabled\s*=\s*false\b/m.test(body);
|
|
75518
|
+
}, classify = (host, selector) => ({
|
|
75407
75519
|
host,
|
|
75408
75520
|
selector,
|
|
75409
75521
|
kind: selector === `@brainervirus/workit-${host}` || selector === `@brainervirus/workit-${host}@latest` || selector === `npm:@brainervirus/workit-${host}` || selector === `npm:@brainervirus/workit-${host}@latest` ? "floating" : new RegExp(`^(?:npm:)?@brainervirus/workit-${host}@[^/]+$`).test(selector) ? "pinned" : "local"
|
|
75410
|
-
}),
|
|
75522
|
+
}), sources = (paths, run, hosts, failed) => {
|
|
75411
75523
|
const { home } = paths;
|
|
75412
75524
|
const result = [];
|
|
75413
75525
|
const guard = (host, read) => {
|
|
@@ -75425,7 +75537,7 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
|
|
|
75425
75537
|
}
|
|
75426
75538
|
};
|
|
75427
75539
|
guard("opencode", () => {
|
|
75428
|
-
if (
|
|
75540
|
+
if (existsSync22(paths.opencodeConfig + "c"))
|
|
75429
75541
|
throw new Error("OpenCode JSONC config is present; inspect effective native configuration before updating");
|
|
75430
75542
|
const oc = object2(paths.opencodeConfig);
|
|
75431
75543
|
if (oc && [oc.plugins, oc.plugin].some((value) => value !== undefined && !Array.isArray(value)))
|
|
@@ -75435,8 +75547,8 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
|
|
|
75435
75547
|
result.push(classify("opencode", pin));
|
|
75436
75548
|
});
|
|
75437
75549
|
guard("cursor", () => {
|
|
75438
|
-
const cursor = objectOrNull(
|
|
75439
|
-
const mcp = objectOrNull(
|
|
75550
|
+
const cursor = objectOrNull(path47.join(paths.cursorRoot, "package.json"));
|
|
75551
|
+
const mcp = objectOrNull(path47.join(home, ".cursor/mcp.json"));
|
|
75440
75552
|
const args = mcp?.mcpServers?.workit?.args ?? [];
|
|
75441
75553
|
const arg = args.find((value) => typeof value === "string" && value.startsWith("--package="));
|
|
75442
75554
|
const selector = typeof arg === "string" ? arg.slice(10) : "local";
|
|
@@ -75447,7 +75559,7 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
|
|
|
75447
75559
|
});
|
|
75448
75560
|
return;
|
|
75449
75561
|
}
|
|
75450
|
-
const settings = objectOrNull(
|
|
75562
|
+
const settings = objectOrNull(path47.join(home, ".cursor/settings.json"));
|
|
75451
75563
|
const dirs = Array.isArray(settings?.plugin_dirs) ? settings.plugin_dirs : [];
|
|
75452
75564
|
const registered = mcp?.mcpServers?.workit !== undefined || dirs.some((dir) => String(dir).replaceAll("\\", "/").replace(/\/+$/, "").endsWith("local/workit"));
|
|
75453
75565
|
if (registered)
|
|
@@ -75462,7 +75574,7 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
|
|
|
75462
75574
|
if (typeof source !== "string")
|
|
75463
75575
|
continue;
|
|
75464
75576
|
const npm = /^(?:npm:)?@brainervirus\/workit-pi(?:@[^/]+)?$/.test(source);
|
|
75465
|
-
const local =
|
|
75577
|
+
const local = path47.isAbsolute(source) && source.replaceAll("\\", "/").endsWith("/packages/workit-pi") && object2(path47.join(source, "package.json"))?.name === "@brainervirus/workit-pi";
|
|
75466
75578
|
if (!npm && !local)
|
|
75467
75579
|
continue;
|
|
75468
75580
|
const found = classify("pi", source);
|
|
@@ -75482,7 +75594,7 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
|
|
|
75482
75594
|
hostCommand("codex", [], { home, env: paths.env });
|
|
75483
75595
|
available = true;
|
|
75484
75596
|
} catch {}
|
|
75485
|
-
if (available ||
|
|
75597
|
+
if (available || existsSync22(paths.codexConfig))
|
|
75486
75598
|
throw new Error("Codex plugin inventory failed; inspect the native host before upgrading");
|
|
75487
75599
|
return;
|
|
75488
75600
|
}
|
|
@@ -75504,6 +75616,12 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
|
|
|
75504
75616
|
installedVersion: plugin.version
|
|
75505
75617
|
});
|
|
75506
75618
|
}
|
|
75619
|
+
if (!result.some((found) => found.host === "codex") && codexRegistered(paths.codexConfig))
|
|
75620
|
+
result.push({
|
|
75621
|
+
host: "codex",
|
|
75622
|
+
selector: "@brainervirus/workit-codex",
|
|
75623
|
+
kind: "repair"
|
|
75624
|
+
});
|
|
75507
75625
|
});
|
|
75508
75626
|
guard("claude-code", () => {
|
|
75509
75627
|
for (const install of claudeWorkitInstalls(home, paths.env, null))
|
|
@@ -75515,213 +75633,24 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
|
|
|
75515
75633
|
});
|
|
75516
75634
|
});
|
|
75517
75635
|
return result;
|
|
75518
|
-
}, piInstalledVersion = (listing, selector) => {
|
|
75519
|
-
const lines = listing.split(/\r?\n/).map((line) => line.trim());
|
|
75520
|
-
const index = lines.indexOf(selector);
|
|
75521
|
-
if (index < 0 || !lines[index + 1] || !path44.isAbsolute(lines[index + 1]))
|
|
75522
|
-
return;
|
|
75523
|
-
const found = objectOrNull(path44.join(lines[index + 1], "package.json"));
|
|
75524
|
-
return found?.name === "@brainervirus/workit-pi" ? found.version : undefined;
|
|
75525
|
-
}, versionAtLeast = (installed, latest) => {
|
|
75526
|
-
if (!/^\d+\.\d+\.\d+$/.test(installed))
|
|
75527
|
-
return false;
|
|
75528
|
-
const current = installed.split(".").map(Number);
|
|
75529
|
-
const target = latest.split(".").map(Number);
|
|
75530
|
-
for (let index = 0;index < 3; index++) {
|
|
75531
|
-
if (current[index] !== target[index])
|
|
75532
|
-
return current[index] > target[index];
|
|
75533
|
-
}
|
|
75534
|
-
return true;
|
|
75535
75636
|
}, opencodeProbe = (deps, args) => {
|
|
75536
|
-
const scratch = mkdtempSync3(
|
|
75637
|
+
const scratch = mkdtempSync3(path47.join(os17.tmpdir(), "workit-upgrade-opencode-"));
|
|
75537
75638
|
try {
|
|
75538
75639
|
return runner({
|
|
75539
75640
|
...deps,
|
|
75540
75641
|
env: {
|
|
75541
75642
|
...deps.env,
|
|
75542
|
-
XDG_DATA_HOME:
|
|
75543
|
-
XDG_STATE_HOME:
|
|
75544
|
-
XDG_CACHE_HOME:
|
|
75643
|
+
XDG_DATA_HOME: path47.join(scratch, "data"),
|
|
75644
|
+
XDG_STATE_HOME: path47.join(scratch, "state"),
|
|
75645
|
+
XDG_CACHE_HOME: path47.join(scratch, "cache")
|
|
75545
75646
|
}
|
|
75546
75647
|
})("opencode", args);
|
|
75547
75648
|
} finally {
|
|
75548
75649
|
rmSync8(scratch, { recursive: true, force: true });
|
|
75549
75650
|
}
|
|
75550
|
-
}, registryVersion = (run, name) => {
|
|
75551
|
-
const latest = run("npm", ["view", name, "version"]);
|
|
75552
|
-
const version = latest.stdout.trim();
|
|
75553
|
-
return latest.status === 0 && /^\d+\.\d+\.\d+$/.test(version) ? version : undefined;
|
|
75554
|
-
}, PROCESS_HOSTS, classifyProcess = (proc) => {
|
|
75555
|
-
if (proc.state.startsWith("Z") || proc.args.includes("<defunct>"))
|
|
75556
|
-
return null;
|
|
75557
|
-
const argv0 = proc.args.trim().split(/\s+/)[0] ?? "";
|
|
75558
|
-
const name = path44.basename(argv0.replaceAll("\\", "/")).replace(/^\[|\]$/g, "").replace(/\.exe$/i, "").toLowerCase();
|
|
75559
|
-
const host = PROCESS_HOSTS[name];
|
|
75560
|
-
if (!host)
|
|
75561
|
-
return null;
|
|
75562
|
-
if (host === "codex" && /\bapp-server\b/.test(proc.args))
|
|
75563
|
-
return /\bdaemon\s+pid-update-loop\b/.test(proc.args) ? null : { ...proc, host, kind: "daemon" };
|
|
75564
|
-
if (host === "opencode" && /\bserve\b/.test(proc.args))
|
|
75565
|
-
return { ...proc, host, kind: "daemon" };
|
|
75566
|
-
return { ...proc, host, kind: "session" };
|
|
75567
|
-
}, listProcesses = (deps) => {
|
|
75568
|
-
if (deps.processes)
|
|
75569
|
-
return deps.processes();
|
|
75570
|
-
if (deps.activeHosts)
|
|
75571
|
-
return deps.activeHosts().map((host) => ({ pid: 0, state: "S", args: host }));
|
|
75572
|
-
const run = runner(deps);
|
|
75573
|
-
if (process.platform === "win32") {
|
|
75574
|
-
const list = run("tasklist", ["/fo", "csv", "/nh"]);
|
|
75575
|
-
if (list.status !== 0)
|
|
75576
|
-
return null;
|
|
75577
|
-
return list.stdout.split(/\r?\n/).flatMap((line) => {
|
|
75578
|
-
const [image, pid] = line.split('","').map((cell) => cell.replaceAll('"', ""));
|
|
75579
|
-
return image && /^\d+$/.test(pid ?? "") ? [{ pid: Number(pid), state: "R", args: image }] : [];
|
|
75580
|
-
});
|
|
75581
|
-
}
|
|
75582
|
-
const list = run("ps", ["-eo", "pid=,stat=,args="]);
|
|
75583
|
-
if (list.status !== 0)
|
|
75584
|
-
return null;
|
|
75585
|
-
return list.stdout.split(/\r?\n/).flatMap((line) => {
|
|
75586
|
-
const match = /^\s*(\d+)\s+(\S+)\s+(.+)$/.exec(line);
|
|
75587
|
-
return match ? [{ pid: Number(match[1]), state: match[2], args: match[3] }] : [];
|
|
75588
|
-
});
|
|
75589
|
-
}, describe2 = (proc) => `pid ${proc.pid}: ${proc.args.length > 120 ? `${proc.args.slice(0, 117)}...` : proc.args}`, codexPluginRoot = (codexHome) => {
|
|
75590
|
-
const dir = path44.join(codexHome, "plugins", "cache", CODEX_MARKETPLACE, "workit");
|
|
75591
|
-
let versions = [];
|
|
75592
|
-
try {
|
|
75593
|
-
versions = readdirSync12(dir).filter((version) => /^\d+\.\d+\.\d+$/.test(version));
|
|
75594
|
-
} catch {
|
|
75595
|
-
return null;
|
|
75596
|
-
}
|
|
75597
|
-
const newest = versions.reduce((best, version) => best && versionAtLeast(best, version) ? best : version, null);
|
|
75598
|
-
return newest ? path44.join(dir, newest) : null;
|
|
75599
|
-
}, applyEntry = (entry, context) => {
|
|
75600
|
-
const { run, paths, configDir } = context;
|
|
75601
|
-
const { home, env } = paths;
|
|
75602
|
-
const fail = (reason) => ({
|
|
75603
|
-
host: entry.host,
|
|
75604
|
-
status: "failed",
|
|
75605
|
-
reason,
|
|
75606
|
-
fix: entry.fix
|
|
75607
|
-
});
|
|
75608
|
-
if (entry.host === "cursor") {
|
|
75609
|
-
const preview = {
|
|
75610
|
-
ok: true,
|
|
75611
|
-
blocked: [],
|
|
75612
|
-
preserved: [],
|
|
75613
|
-
overrides: [],
|
|
75614
|
-
platforms: ["cursor"],
|
|
75615
|
-
state: readSetupState(configDir),
|
|
75616
|
-
mutations: [
|
|
75617
|
-
{
|
|
75618
|
-
type: "install-host",
|
|
75619
|
-
platform: "cursor",
|
|
75620
|
-
path: path44.join(home, ".cursor/plugins/local/.workit-package-bootstrap"),
|
|
75621
|
-
commands: entry.commands.map((command) => ({
|
|
75622
|
-
...command,
|
|
75623
|
-
purpose: command.purpose ?? "Upgrade Cursor"
|
|
75624
|
-
}))
|
|
75625
|
-
},
|
|
75626
|
-
{ type: "install-adapter", platform: "cursor", path: paths.cursorRoot }
|
|
75627
|
-
]
|
|
75628
|
-
};
|
|
75629
|
-
const result = applySetupPreview(preview, {
|
|
75630
|
-
home,
|
|
75631
|
-
env,
|
|
75632
|
-
cwd: home,
|
|
75633
|
-
preferInstalledAdapter: true,
|
|
75634
|
-
runHostCommand: (command) => {
|
|
75635
|
-
const outcome = run(command.command, command.args);
|
|
75636
|
-
return {
|
|
75637
|
-
exitCode: outcome.status ?? 1,
|
|
75638
|
-
stdout: outcome.stdout,
|
|
75639
|
-
stderr: ""
|
|
75640
|
-
};
|
|
75641
|
-
}
|
|
75642
|
-
});
|
|
75643
|
-
const installed = objectOrNull(path44.join(paths.cursorRoot, "package.json"));
|
|
75644
|
-
if (!result.ok || installed?.version !== entry.latest)
|
|
75645
|
-
return fail("Cursor install did not verify the requested package version; inspect the installer before retrying");
|
|
75646
|
-
return {
|
|
75647
|
-
host: "cursor",
|
|
75648
|
-
status: "updated",
|
|
75649
|
-
reason: entry.repair ? `reinstalled missing plugin files (${entry.latest})` : `${entry.installedVersion ?? "?"} -> ${entry.latest}`
|
|
75650
|
-
};
|
|
75651
|
-
}
|
|
75652
|
-
for (const command of entry.commands)
|
|
75653
|
-
if (run(command.command, command.args).status !== 0)
|
|
75654
|
-
return fail(`\`${command.command} ${command.args.join(" ")}\` failed`);
|
|
75655
|
-
if (entry.host === "opencode")
|
|
75656
|
-
return {
|
|
75657
|
-
host: "opencode",
|
|
75658
|
-
status: "updated",
|
|
75659
|
-
reason: "scoped update ran; OpenCode V2 loads it live"
|
|
75660
|
-
};
|
|
75661
|
-
if (entry.host === "claude-code") {
|
|
75662
|
-
const after = claudeWorkitInstalls(home, env, null).find((install) => install.id === entry.selector)?.version;
|
|
75663
|
-
return after && after === entry.installedVersion ? {
|
|
75664
|
-
host: "claude-code",
|
|
75665
|
-
status: "current",
|
|
75666
|
-
reason: `already current (${after})`
|
|
75667
|
-
} : {
|
|
75668
|
-
host: "claude-code",
|
|
75669
|
-
status: "updated",
|
|
75670
|
-
reason: `${entry.installedVersion ?? "?"} -> ${after ?? "?"}; new sessions load it`
|
|
75671
|
-
};
|
|
75672
|
-
}
|
|
75673
|
-
const verify = entry.host === "codex" ? run("codex", ["plugin", "list", "--json"]) : run("pi", ["list"]);
|
|
75674
|
-
if (verify.status !== 0)
|
|
75675
|
-
return fail("update verification failed");
|
|
75676
|
-
if (entry.host === "codex") {
|
|
75677
|
-
let installed = [];
|
|
75678
|
-
try {
|
|
75679
|
-
installed = JSON.parse(verify.stdout).installed ?? [];
|
|
75680
|
-
} catch {}
|
|
75681
|
-
if (!installed.some((plugin) => plugin.name === "workit" && plugin.marketplaceName === CODEX_MARKETPLACE && plugin.version === entry.latest))
|
|
75682
|
-
return fail("Codex did not report the requested Workit version");
|
|
75683
|
-
}
|
|
75684
|
-
if (entry.host === "pi" && piInstalledVersion(verify.stdout, entry.selector) !== entry.latest)
|
|
75685
|
-
return fail("Pi did not report the requested Workit package version");
|
|
75686
|
-
return {
|
|
75687
|
-
host: entry.host,
|
|
75688
|
-
status: "updated",
|
|
75689
|
-
reason: `${entry.installedVersion ?? "?"} -> ${entry.latest}`
|
|
75690
|
-
};
|
|
75691
|
-
}, refreshCodexAgents = (run, codexHome) => {
|
|
75692
|
-
const root = codexPluginRoot(codexHome);
|
|
75693
|
-
const launcher = root && path44.join(root, "dist", "launch-mcp.js");
|
|
75694
|
-
if (!launcher || !existsSync20(launcher))
|
|
75695
|
-
return { ok: true, note: "" };
|
|
75696
|
-
const fix = `node ${JSON.stringify(launcher)} --install-agents`;
|
|
75697
|
-
return run("node", [launcher, "--install-agents"]).status === 0 ? { ok: true, note: "agents refreshed" } : { ok: false, note: "agent refresh failed", fix };
|
|
75698
|
-
}, applyCli = (cli, run, backup) => {
|
|
75699
|
-
const fail = (reason) => ({
|
|
75700
|
-
host: "cli",
|
|
75701
|
-
status: "failed",
|
|
75702
|
-
reason,
|
|
75703
|
-
fix: CLI_FIX
|
|
75704
|
-
});
|
|
75705
|
-
const currentRoot = run("npm", ["root", "--global"]);
|
|
75706
|
-
if (currentRoot.status !== 0 || currentRoot.stdout.trim() !== cli.root)
|
|
75707
|
-
return fail("Global npm location changed; preview again");
|
|
75708
|
-
const cliBackup = path44.join(backup, "cli-package");
|
|
75709
|
-
cpSync5(path44.join(cli.root, "@brainervirus/workit-cli"), cliBackup, {
|
|
75710
|
-
recursive: true
|
|
75711
|
-
});
|
|
75712
|
-
if (run("npm", ["install", "--global", `@brainervirus/workit-cli@${cli.latest}`]).status !== 0)
|
|
75713
|
-
return fail(`CLI update failed; preserved package at ${cliBackup}; use npm to repair or run node ${path44.join(cliBackup, "dist/index.js")}`);
|
|
75714
|
-
const installed = objectOrNull(path44.join(cli.root, "@brainervirus/workit-cli/package.json"));
|
|
75715
|
-
if (installed?.name !== "@brainervirus/workit-cli" || installed.version !== cli.latest)
|
|
75716
|
-
return fail(`CLI update did not verify the requested version; preserved package at ${cliBackup}`);
|
|
75717
|
-
return {
|
|
75718
|
-
host: "cli",
|
|
75719
|
-
status: "updated",
|
|
75720
|
-
reason: `${cli.installed} -> ${cli.latest}`
|
|
75721
|
-
};
|
|
75722
75651
|
}, planCli = (plan, run) => {
|
|
75723
75652
|
const root = run("npm", ["root", "--global"]);
|
|
75724
|
-
if (root.status !== 0 || !
|
|
75653
|
+
if (root.status !== 0 || !path47.isAbsolute(root.stdout.trim())) {
|
|
75725
75654
|
plan.skipped.push({
|
|
75726
75655
|
host: "cli",
|
|
75727
75656
|
reason: "global npm location could not be verified",
|
|
@@ -75729,9 +75658,9 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
|
|
|
75729
75658
|
});
|
|
75730
75659
|
return;
|
|
75731
75660
|
}
|
|
75732
|
-
const packageFile =
|
|
75661
|
+
const packageFile = path47.join(root.stdout.trim(), "@brainervirus/workit-cli/package.json");
|
|
75733
75662
|
const installed = objectOrNull(packageFile);
|
|
75734
|
-
if (installed?.name !== "@brainervirus/workit-cli" || lstatSync7(
|
|
75663
|
+
if (installed?.name !== "@brainervirus/workit-cli" || lstatSync7(path47.dirname(packageFile)).isSymbolicLink()) {
|
|
75735
75664
|
plan.skipped.push({
|
|
75736
75665
|
host: "cli",
|
|
75737
75666
|
reason: "no managed global CLI install (local links preserved); use npx @brainervirus/workit-cli@latest"
|
|
@@ -75758,7 +75687,18 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
|
|
|
75758
75687
|
host: "cli",
|
|
75759
75688
|
reason: `already current (${installed.version})`
|
|
75760
75689
|
});
|
|
75761
|
-
}
|
|
75690
|
+
};
|
|
75691
|
+
var init_plan = __esm(() => {
|
|
75692
|
+
init_registration();
|
|
75693
|
+
init_setup_state();
|
|
75694
|
+
init_host_install();
|
|
75695
|
+
init_doctor();
|
|
75696
|
+
init_support_matrix();
|
|
75697
|
+
init_shared();
|
|
75698
|
+
});
|
|
75699
|
+
|
|
75700
|
+
// packages/workit-cli/src/upgrade/report.ts
|
|
75701
|
+
var pad2 = (text) => text.padEnd(12), summary = (plan, permissions) => {
|
|
75762
75702
|
const lines = ["Workit upgrade plan:"];
|
|
75763
75703
|
if (plan.cli)
|
|
75764
75704
|
lines.push(` ${pad2("cli")}update ${plan.cli.installed} -> ${plan.cli.latest}`);
|
|
@@ -75795,29 +75735,8 @@ var LAUNCH_HOSTS, HOSTS2, LIVE_HOSTS, OPENCODE_PACKAGE = "@brainervirus/workit-o
|
|
|
75795
75735
|
}
|
|
75796
75736
|
await Promise.resolve().then(() => init_prompt());
|
|
75797
75737
|
return /^y(?:es)?$/i.test((await askLine(question)).trim());
|
|
75798
|
-
}
|
|
75799
|
-
|
|
75800
|
-
var init_upgrade = __esm(() => {
|
|
75801
|
-
init_package();
|
|
75802
|
-
init_registration();
|
|
75803
|
-
init_setup_state();
|
|
75804
|
-
init_host_install();
|
|
75805
|
-
init_setup();
|
|
75806
|
-
init_doctor();
|
|
75807
|
-
init_support_matrix();
|
|
75808
|
-
init_safe_write();
|
|
75809
|
-
init_host_permissions();
|
|
75810
|
-
LAUNCH_HOSTS = ["opencode", "cursor", "codex", "pi"];
|
|
75811
|
-
HOSTS2 = [...LAUNCH_HOSTS, "claude-code"];
|
|
75812
|
-
LIVE_HOSTS = new Set(["opencode", "claude-code"]);
|
|
75813
|
-
OPENCODE_UPDATE = `opencode plugin update ${OPENCODE_PACKAGE}`;
|
|
75814
|
-
PROCESS_HOSTS = {
|
|
75815
|
-
claude: "claude-code",
|
|
75816
|
-
codex: "codex",
|
|
75817
|
-
cursor: "cursor",
|
|
75818
|
-
opencode: "opencode",
|
|
75819
|
-
pi: "pi"
|
|
75820
|
-
};
|
|
75738
|
+
};
|
|
75739
|
+
var init_report = __esm(() => {
|
|
75821
75740
|
LABEL = {
|
|
75822
75741
|
updated: "updated",
|
|
75823
75742
|
current: "already current",
|
|
@@ -75826,6 +75745,191 @@ var init_upgrade = __esm(() => {
|
|
|
75826
75745
|
};
|
|
75827
75746
|
});
|
|
75828
75747
|
|
|
75748
|
+
// packages/workit-cli/src/upgrade.ts
|
|
75749
|
+
import { spawnSync as spawnSync17 } from "node:child_process";
|
|
75750
|
+
async function runUpgradeCommand(argv, deps = {}) {
|
|
75751
|
+
const out = deps.out ?? process.stdout;
|
|
75752
|
+
const flags = new Set(argv);
|
|
75753
|
+
const unknown = argv.filter((arg) => !["--apply", "--confirm", "--json", "--cli", "--preview", "--yes"].includes(arg) && !arg.startsWith("--hosts="));
|
|
75754
|
+
const hostFlag = argv.find((arg) => arg.startsWith("--hosts="))?.slice(8);
|
|
75755
|
+
const raw = hostFlag === "none" ? [] : hostFlag?.split(",") ?? HOSTS2;
|
|
75756
|
+
if (unknown.length || raw.some((host) => !HOSTS2.includes(host)) || flags.has("--preview") && (flags.has("--apply") || flags.has("--yes"))) {
|
|
75757
|
+
out.write(USAGE3);
|
|
75758
|
+
return 2;
|
|
75759
|
+
}
|
|
75760
|
+
if (flags.has("--apply") && !flags.has("--confirm")) {
|
|
75761
|
+
out.write(`Apply requires --confirm after reviewing the upgrade preview.
|
|
75762
|
+
`);
|
|
75763
|
+
return 2;
|
|
75764
|
+
}
|
|
75765
|
+
const legacy = flags.has("--apply");
|
|
75766
|
+
const json = flags.has("--json") || legacy;
|
|
75767
|
+
const run = runner(deps);
|
|
75768
|
+
const plan = previewUpgrade(raw, deps);
|
|
75769
|
+
if (hostFlag === undefined || flags.has("--cli"))
|
|
75770
|
+
planCli(plan, run);
|
|
75771
|
+
plan.ok = plan.blocked.length === 0 && plan.failed.length === 0;
|
|
75772
|
+
const { home, env } = upgradePaths(deps);
|
|
75773
|
+
const permissions = planHostPermissions({
|
|
75774
|
+
hosts: raw,
|
|
75775
|
+
refreshOnly: true,
|
|
75776
|
+
shell: false,
|
|
75777
|
+
home,
|
|
75778
|
+
env
|
|
75779
|
+
});
|
|
75780
|
+
const permissionPreview = {
|
|
75781
|
+
changes: permissions.changes.map((c) => ({
|
|
75782
|
+
host: c.host,
|
|
75783
|
+
file: c.file,
|
|
75784
|
+
diff: permissionDiff(c)
|
|
75785
|
+
})),
|
|
75786
|
+
...permissions.refused ? { refused: permissions.refused } : {}
|
|
75787
|
+
};
|
|
75788
|
+
const withPermissions = (value) => permissions.changes.length ? { ...value, permissions: permissionPreview } : value;
|
|
75789
|
+
const applyCommand = `workit upgrade ${[...hostFlag === undefined ? [] : [`--hosts=${hostFlag}`], ...flags.has("--cli") ? ["--cli"] : [], "--yes"].join(" ")}`;
|
|
75790
|
+
const nothingChanged = `preview only; nothing changed. Apply with: ${applyCommand}
|
|
75791
|
+
`;
|
|
75792
|
+
if (json && !legacy && !flags.has("--yes")) {
|
|
75793
|
+
out.write(JSON.stringify(withPermissions(plan), null, 2) + `
|
|
75794
|
+
`);
|
|
75795
|
+
return plan.blocked.length ? 1 : 0;
|
|
75796
|
+
}
|
|
75797
|
+
if (!json)
|
|
75798
|
+
out.write(summary(plan, permissions.changes));
|
|
75799
|
+
if (flags.has("--preview")) {
|
|
75800
|
+
out.write(nothingChanged);
|
|
75801
|
+
return plan.blocked.length ? 1 : 0;
|
|
75802
|
+
}
|
|
75803
|
+
if (plan.blocked.length) {
|
|
75804
|
+
out.write(`Upgrade blocked: ${plan.blocked.join("; ")}
|
|
75805
|
+
Nothing changed.
|
|
75806
|
+
`);
|
|
75807
|
+
return 1;
|
|
75808
|
+
}
|
|
75809
|
+
const work = plan.entries.length + plan.migrations.length + (plan.cli ? 1 : 0) + permissions.changes.length;
|
|
75810
|
+
if (work > 0 && !flags.has("--yes") && !legacy) {
|
|
75811
|
+
const confirmed = await (deps.confirm ?? ((q) => askConfirm(q, out)))("Apply this upgrade? [y/N] ");
|
|
75812
|
+
if (!confirmed) {
|
|
75813
|
+
out.write(nothingChanged);
|
|
75814
|
+
return 0;
|
|
75815
|
+
}
|
|
75816
|
+
}
|
|
75817
|
+
if (json)
|
|
75818
|
+
for (const warning of plan.warnings ?? [])
|
|
75819
|
+
out.write(`warning: ${warning}
|
|
75820
|
+
`);
|
|
75821
|
+
const result = applyUpgrade(plan, deps);
|
|
75822
|
+
let permissionsOk = true;
|
|
75823
|
+
let written;
|
|
75824
|
+
if (permissions.changes.length && !permissions.refused && !result.error?.startsWith("configuration changed")) {
|
|
75825
|
+
written = applyHostPermissions(permissions, { home, env });
|
|
75826
|
+
permissionsOk = written.every((entry) => entry.status === "written");
|
|
75827
|
+
for (const entry of written)
|
|
75828
|
+
result.hosts.push({
|
|
75829
|
+
host: entry.host,
|
|
75830
|
+
status: entry.status === "written" ? "updated" : "failed",
|
|
75831
|
+
reason: `permission block ${entry.status === "written" ? "refreshed" : entry.status} in ${entry.file}`,
|
|
75832
|
+
...entry.status === "written" ? {} : { fix: `workit setup --hosts=${entry.host}` }
|
|
75833
|
+
});
|
|
75834
|
+
}
|
|
75835
|
+
const failed = !result.ok || !permissionsOk;
|
|
75836
|
+
const cliVersion = result.hosts.some((h) => h.host === "cli" && h.status === "updated") ? plan.cli.latest : package_default.version;
|
|
75837
|
+
const report = (deps.doctor ?? ((version) => runDoctor({ home, env, cliVersion: version, only: "upgrade" })))(cliVersion);
|
|
75838
|
+
const left = report.checks.filter((check) => check.status === "warn" || check.status === "fail");
|
|
75839
|
+
if (json) {
|
|
75840
|
+
out.write(JSON.stringify({
|
|
75841
|
+
...result,
|
|
75842
|
+
ok: !failed,
|
|
75843
|
+
...written ? { permissions: { changes: permissionPreview.changes, written } } : permissions.refused ? { permissions: permissionPreview } : {},
|
|
75844
|
+
doctor: { clean: left.length === 0, left }
|
|
75845
|
+
}, null, 2) + `
|
|
75846
|
+
`);
|
|
75847
|
+
return failed ? 1 : 0;
|
|
75848
|
+
}
|
|
75849
|
+
if (result.error && result.hosts.every((h) => h.status !== "failed"))
|
|
75850
|
+
out.write(`Upgrade stopped: ${result.error}
|
|
75851
|
+
`);
|
|
75852
|
+
out.write(table(result.hosts));
|
|
75853
|
+
if (permissions.refused)
|
|
75854
|
+
out.write(`permissions: not refreshed: ${permissions.refused}
|
|
75855
|
+
`);
|
|
75856
|
+
if (result.backup)
|
|
75857
|
+
out.write(`Backup: ${result.backup}
|
|
75858
|
+
`);
|
|
75859
|
+
out.write(left.length === 0 ? `Verified: workit doctor is clean for versions, assets, agents and permissions.
|
|
75860
|
+
` : `Left after upgrade (workit doctor):
|
|
75861
|
+
${left.map((check) => ` ${check.id}: ${check.detail}${check.fix ? `
|
|
75862
|
+
fix: ${check.fix}` : ""}`).join(`
|
|
75863
|
+
`)}
|
|
75864
|
+
`);
|
|
75865
|
+
return failed ? 1 : 0;
|
|
75866
|
+
}
|
|
75867
|
+
async function runLaunchCommand(argv, deps = {}) {
|
|
75868
|
+
const [host, ...args] = argv;
|
|
75869
|
+
if (!LAUNCH_HOSTS.includes(host)) {
|
|
75870
|
+
(deps.out ?? process.stdout).write(`Usage: workit launch <opencode|cursor|codex|pi> [--auto-upgrade] [-- host arguments]
|
|
75871
|
+
`);
|
|
75872
|
+
return 2;
|
|
75873
|
+
}
|
|
75874
|
+
const auto = args[0] === "--auto-upgrade";
|
|
75875
|
+
const rest = auto ? args.slice(1) : args;
|
|
75876
|
+
const hostArgs = rest[0] === "--" ? rest.slice(1) : rest;
|
|
75877
|
+
const { home, env } = upgradePaths(deps);
|
|
75878
|
+
let launch;
|
|
75879
|
+
if (!deps.run) {
|
|
75880
|
+
try {
|
|
75881
|
+
launch = hostCommand(host, hostArgs, { home, env });
|
|
75882
|
+
} catch (error) {
|
|
75883
|
+
(deps.out ?? process.stderr).write(`${error instanceof Error ? error.message : "Host executable unavailable"}
|
|
75884
|
+
`);
|
|
75885
|
+
return 1;
|
|
75886
|
+
}
|
|
75887
|
+
}
|
|
75888
|
+
if (auto) {
|
|
75889
|
+
const plan = previewUpgrade([host], deps);
|
|
75890
|
+
const reasons = [...plan.blocked, ...plan.failed.map((entry) => entry.reason)];
|
|
75891
|
+
if (plan.ok) {
|
|
75892
|
+
for (const skipped of plan.skipped)
|
|
75893
|
+
(deps.out ?? process.stderr).write(`${skipped.host}: ${skipped.reason}${skipped.fix ? ` (run: ${skipped.fix})` : ""}
|
|
75894
|
+
`);
|
|
75895
|
+
const result = applyUpgrade(plan, deps);
|
|
75896
|
+
if (!result.ok) {
|
|
75897
|
+
(deps.out ?? process.stdout).write(`${result.error}
|
|
75898
|
+
`);
|
|
75899
|
+
return 1;
|
|
75900
|
+
}
|
|
75901
|
+
} else if (plan.blocked.length === 0 && reasons.every((reason) => reason.includes("registry version unavailable"))) {
|
|
75902
|
+
(deps.out ?? process.stderr).write(`Upgrade unavailable: ${reasons.join("; ")}. Starting the unchanged host.
|
|
75903
|
+
`);
|
|
75904
|
+
} else {
|
|
75905
|
+
(deps.out ?? process.stderr).write(`Upgrade blocked: ${reasons.join("; ")}
|
|
75906
|
+
`);
|
|
75907
|
+
return 1;
|
|
75908
|
+
}
|
|
75909
|
+
}
|
|
75910
|
+
if (deps.run)
|
|
75911
|
+
return deps.run(host, hostArgs).status ?? 1;
|
|
75912
|
+
return spawnSync17(launch.command, launch.args, {
|
|
75913
|
+
stdio: "inherit",
|
|
75914
|
+
env
|
|
75915
|
+
}).status ?? 1;
|
|
75916
|
+
}
|
|
75917
|
+
var USAGE3 = `Usage: workit upgrade [--hosts=opencode,cursor,codex,pi,claude-code|none] [--cli] [--preview | --yes | --apply --confirm] [--json]
|
|
75918
|
+
`;
|
|
75919
|
+
var init_upgrade = __esm(() => {
|
|
75920
|
+
init_package();
|
|
75921
|
+
init_host_install();
|
|
75922
|
+
init_doctor();
|
|
75923
|
+
init_host_permissions();
|
|
75924
|
+
init_apply();
|
|
75925
|
+
init_plan();
|
|
75926
|
+
init_report();
|
|
75927
|
+
init_shared();
|
|
75928
|
+
init_apply();
|
|
75929
|
+
init_plan();
|
|
75930
|
+
init_processes();
|
|
75931
|
+
});
|
|
75932
|
+
|
|
75829
75933
|
// packages/workit-cli/src/verbs/upgrade.ts
|
|
75830
75934
|
var exports_upgrade = {};
|
|
75831
75935
|
__export(exports_upgrade, {
|
|
@@ -75849,7 +75953,7 @@ var init_launch = __esm(() => {
|
|
|
75849
75953
|
// packages/workit-core/src/knowledge.ts
|
|
75850
75954
|
import { spawnSync as spawnSync18 } from "node:child_process";
|
|
75851
75955
|
import fs20 from "node:fs";
|
|
75852
|
-
import
|
|
75956
|
+
import path48 from "node:path";
|
|
75853
75957
|
function lintKnowledge(root) {
|
|
75854
75958
|
const seen = new Set;
|
|
75855
75959
|
const unreadable = [];
|
|
@@ -75953,7 +76057,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
|
|
|
75953
76057
|
const end = lines.indexOf("---", 1);
|
|
75954
76058
|
return end === -1 ? lines : [...lines.slice(0, end + 1).map(() => ""), ...lines.slice(end + 1)];
|
|
75955
76059
|
}, read = (root, file) => {
|
|
75956
|
-
const full =
|
|
76060
|
+
const full = path48.join(root, file);
|
|
75957
76061
|
try {
|
|
75958
76062
|
fs20.lstatSync(full);
|
|
75959
76063
|
} catch {
|
|
@@ -75994,7 +76098,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
|
|
|
75994
76098
|
}
|
|
75995
76099
|
}, brokenLinks = (root, doc, tracked) => {
|
|
75996
76100
|
const findings = [];
|
|
75997
|
-
const base =
|
|
76101
|
+
const base = path48.dirname(path48.join(root, doc.file));
|
|
75998
76102
|
const missing = (target, line, how) => findings.push({
|
|
75999
76103
|
rule: "broken-link",
|
|
76000
76104
|
file: doc.file,
|
|
@@ -76013,7 +76117,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
|
|
|
76013
76117
|
const local = localTarget(target);
|
|
76014
76118
|
if (!local)
|
|
76015
76119
|
continue;
|
|
76016
|
-
const resolved = local.startsWith("/") ?
|
|
76120
|
+
const resolved = local.startsWith("/") ? path48.join(root, local) : path48.resolve(base, local);
|
|
76017
76121
|
if (!exists2(resolved))
|
|
76018
76122
|
missing(target, index + 1, "link");
|
|
76019
76123
|
}
|
|
@@ -76023,9 +76127,9 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
|
|
|
76023
76127
|
continue;
|
|
76024
76128
|
const relative = /^\.\.?\//.test(candidate);
|
|
76025
76129
|
const first = candidate.split("/")[0];
|
|
76026
|
-
if (!relative && !(tracked ? tracked.has(first) : exists2(
|
|
76130
|
+
if (!relative && !(tracked ? tracked.has(first) : exists2(path48.join(root, first))))
|
|
76027
76131
|
continue;
|
|
76028
|
-
const resolved = relative ?
|
|
76132
|
+
const resolved = relative ? path48.resolve(base, candidate) : path48.join(root, candidate);
|
|
76029
76133
|
if (!exists2(resolved))
|
|
76030
76134
|
missing(span, index + 1, "pointer");
|
|
76031
76135
|
}
|
|
@@ -76348,10 +76452,10 @@ var init_redact = __esm(() => {
|
|
|
76348
76452
|
|
|
76349
76453
|
// packages/workit-core/src/checks.ts
|
|
76350
76454
|
import { spawn, spawnSync as spawnSync19 } from "node:child_process";
|
|
76351
|
-
import { createHash as
|
|
76455
|
+
import { createHash as createHash17 } from "node:crypto";
|
|
76352
76456
|
import fs21 from "node:fs";
|
|
76353
|
-
import
|
|
76354
|
-
import
|
|
76457
|
+
import os18 from "node:os";
|
|
76458
|
+
import path49 from "node:path";
|
|
76355
76459
|
import { StringDecoder } from "node:string_decoder";
|
|
76356
76460
|
function tailLines(text, lines = TAIL_LINES) {
|
|
76357
76461
|
const all = text.replace(/\r\n?/gu, `
|
|
@@ -76471,7 +76575,7 @@ function planSpawn(argv, options) {
|
|
|
76471
76575
|
return { file: argv[0], args: [], verbatim: false, shell: true };
|
|
76472
76576
|
if (options.platform !== "win32")
|
|
76473
76577
|
return { file: argv[0], args: argv.slice(1), verbatim: false, shell: false };
|
|
76474
|
-
const win =
|
|
76578
|
+
const win = path49.win32;
|
|
76475
76579
|
const isFile = options.isFile ?? ((file) => {
|
|
76476
76580
|
try {
|
|
76477
76581
|
return fs21.statSync(file).isFile();
|
|
@@ -76556,7 +76660,7 @@ function runCheckCommand(argv, options) {
|
|
|
76556
76660
|
`);
|
|
76557
76661
|
redactor.end();
|
|
76558
76662
|
resolve({
|
|
76559
|
-
exitCode: spawnError ? 127 : code !== null ? code : 128 + (signal ?
|
|
76663
|
+
exitCode: spawnError ? 127 : code !== null ? code : 128 + (signal ? os18.constants.signals[signal] ?? 1 : 1),
|
|
76560
76664
|
signal: signal ?? null,
|
|
76561
76665
|
timedOut,
|
|
76562
76666
|
durationMs: Date.now() - started,
|
|
@@ -76633,10 +76737,10 @@ function runCheckCommand(argv, options) {
|
|
|
76633
76737
|
function storeLog(storeRoot, log) {
|
|
76634
76738
|
const digest = logDigest(log);
|
|
76635
76739
|
const ref = `blobs/logs/${digest.slice("sha256:".length)}.log`;
|
|
76636
|
-
const file =
|
|
76740
|
+
const file = path49.join(storeRoot, ref);
|
|
76637
76741
|
try {
|
|
76638
76742
|
if (!fs21.existsSync(file)) {
|
|
76639
|
-
fs21.mkdirSync(
|
|
76743
|
+
fs21.mkdirSync(path49.dirname(file), { recursive: true });
|
|
76640
76744
|
const temp = `${file}.${process.pid}.${Date.now()}.tmp`;
|
|
76641
76745
|
fs21.writeFileSync(temp, log, { mode: 384 });
|
|
76642
76746
|
fs21.renameSync(temp, file);
|
|
@@ -76649,7 +76753,7 @@ function storeLog(storeRoot, log) {
|
|
|
76649
76753
|
function pruneCheckLogs(storeRoot, options = {}) {
|
|
76650
76754
|
const limits = { ...LOG_RETENTION, ...options.retention };
|
|
76651
76755
|
const now = options.now ?? Date.now();
|
|
76652
|
-
const dir =
|
|
76756
|
+
const dir = path49.join(storeRoot, "blobs", "logs");
|
|
76653
76757
|
const report = { removed: 0, removedBytes: 0, kept: 0 };
|
|
76654
76758
|
let names;
|
|
76655
76759
|
try {
|
|
@@ -76659,7 +76763,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
|
|
|
76659
76763
|
}
|
|
76660
76764
|
const files = names.flatMap((name) => {
|
|
76661
76765
|
try {
|
|
76662
|
-
const stat = fs21.statSync(
|
|
76766
|
+
const stat = fs21.statSync(path49.join(dir, name));
|
|
76663
76767
|
return stat.isFile() ? [{ name, size: stat.size, mtimeMs: stat.mtimeMs }] : [];
|
|
76664
76768
|
} catch {
|
|
76665
76769
|
return [];
|
|
@@ -76678,7 +76782,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
|
|
|
76678
76782
|
continue;
|
|
76679
76783
|
if (!options.dryRun)
|
|
76680
76784
|
try {
|
|
76681
|
-
fs21.rmSync(
|
|
76785
|
+
fs21.rmSync(path49.join(dir, file.name), { force: true });
|
|
76682
76786
|
} catch {
|
|
76683
76787
|
continue;
|
|
76684
76788
|
}
|
|
@@ -76687,7 +76791,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
|
|
|
76687
76791
|
}
|
|
76688
76792
|
return report;
|
|
76689
76793
|
}
|
|
76690
|
-
var MAX_LOG_BYTES, TAIL_LINES = 80, MAX_LINE_CHARS = 400, redactLog = (text) => redactText(text), PEM_BEGIN, PEM_END, BATCH_BYTES, MAX_PENDING, PEM_BODY, MAX_KEY_LINES = 4096, MAX_KEY_BYTES, CMD_META, DRAIN_MS = 250, FORWARDED_SIGNALS, logDigest = (log) => `sha256:${
|
|
76794
|
+
var MAX_LOG_BYTES, TAIL_LINES = 80, MAX_LINE_CHARS = 400, redactLog = (text) => redactText(text), PEM_BEGIN, PEM_END, BATCH_BYTES, MAX_PENDING, PEM_BODY, MAX_KEY_LINES = 4096, MAX_KEY_BYTES, CMD_META, DRAIN_MS = 250, FORWARDED_SIGNALS, logDigest = (log) => `sha256:${createHash17("sha256").update(log).digest("hex")}`, LOG_RETENTION;
|
|
76691
76795
|
var init_checks3 = __esm(() => {
|
|
76692
76796
|
init_redact();
|
|
76693
76797
|
MAX_LOG_BYTES = 2 * 1024 * 1024;
|
|
@@ -76951,7 +77055,7 @@ __export(exports_workspace, {
|
|
|
76951
77055
|
run: () => run11,
|
|
76952
77056
|
runWorkspace: () => runWorkspace
|
|
76953
77057
|
});
|
|
76954
|
-
import { copyFileSync as copyFileSync7, existsSync as
|
|
77058
|
+
import { copyFileSync as copyFileSync7, existsSync as existsSync23 } from "node:fs";
|
|
76955
77059
|
function list2(argv, io) {
|
|
76956
77060
|
if (argv.length)
|
|
76957
77061
|
return usage3(io, `unexpected argument ${argv[0]}`);
|
|
@@ -77161,7 +77265,7 @@ usage: ${USAGE5}`)), load = (io) => {
|
|
|
77161
77265
|
return { ok: false, error: `${current.path} changed; retry` };
|
|
77162
77266
|
let backup = null;
|
|
77163
77267
|
try {
|
|
77164
|
-
if (
|
|
77268
|
+
if (existsSync23(current.path)) {
|
|
77165
77269
|
backup = `${current.path}.bak`;
|
|
77166
77270
|
copyFileSync7(current.path, backup);
|
|
77167
77271
|
}
|
|
@@ -77229,12 +77333,12 @@ var init_workspace = __esm(() => {
|
|
|
77229
77333
|
|
|
77230
77334
|
// packages/workit-core/src/core/heavy-rules.ts
|
|
77231
77335
|
import fs22 from "node:fs";
|
|
77232
|
-
import
|
|
77336
|
+
import path50 from "node:path";
|
|
77233
77337
|
function gitTop(cwd) {
|
|
77234
|
-
for (let dir =
|
|
77235
|
-
if (fs22.existsSync(
|
|
77338
|
+
for (let dir = path50.resolve(cwd);; dir = path50.dirname(dir)) {
|
|
77339
|
+
if (fs22.existsSync(path50.join(dir, ".git")))
|
|
77236
77340
|
return dir;
|
|
77237
|
-
if (
|
|
77341
|
+
if (path50.dirname(dir) === dir)
|
|
77238
77342
|
return null;
|
|
77239
77343
|
}
|
|
77240
77344
|
}
|
|
@@ -77275,19 +77379,19 @@ var init_heavy_rules = () => {};
|
|
|
77275
77379
|
|
|
77276
77380
|
// packages/workit-core/src/core/heavy.ts
|
|
77277
77381
|
import fs23 from "node:fs";
|
|
77278
|
-
import
|
|
77279
|
-
import
|
|
77382
|
+
import os19 from "node:os";
|
|
77383
|
+
import path51 from "node:path";
|
|
77280
77384
|
function stateDir2(env, platform = process.platform) {
|
|
77281
77385
|
if (env.WORKFLOW_TOOLKIT_STATE)
|
|
77282
77386
|
return env.WORKFLOW_TOOLKIT_STATE;
|
|
77283
77387
|
if (env.XDG_STATE_HOME)
|
|
77284
|
-
return
|
|
77285
|
-
const home = env.HOME ||
|
|
77388
|
+
return path51.join(env.XDG_STATE_HOME, "workit");
|
|
77389
|
+
const home = env.HOME || os19.homedir();
|
|
77286
77390
|
if (platform === "darwin")
|
|
77287
|
-
return
|
|
77391
|
+
return path51.join(home, "Library", "Application Support", "workit");
|
|
77288
77392
|
if (platform === "win32")
|
|
77289
|
-
return
|
|
77290
|
-
return
|
|
77393
|
+
return path51.join(env.LOCALAPPDATA ?? path51.join(home, "AppData", "Local"), "workit");
|
|
77394
|
+
return path51.join(home, ".local", "state", "workit");
|
|
77291
77395
|
}
|
|
77292
77396
|
function positional(words, from, values = PM_VALUES) {
|
|
77293
77397
|
let index = from;
|
|
@@ -77427,7 +77531,7 @@ function machinePatterns(env) {
|
|
|
77427
77531
|
return isRecord8(value) ? stringList2(value.patterns) : [];
|
|
77428
77532
|
}
|
|
77429
77533
|
function repoPatterns(cwd) {
|
|
77430
|
-
return repoHeavyCommands(gitTop(cwd) ??
|
|
77534
|
+
return repoHeavyCommands(gitTop(cwd) ?? path51.resolve(cwd));
|
|
77431
77535
|
}
|
|
77432
77536
|
function heavyLines(lines, options) {
|
|
77433
77537
|
const found = [];
|
|
@@ -77506,7 +77610,7 @@ function leaseRewrite(command) {
|
|
|
77506
77610
|
return null;
|
|
77507
77611
|
return `${prefix}workit check --heavy -- ${rest}`;
|
|
77508
77612
|
}
|
|
77509
|
-
var HEAVY_COMMANDS_FILE = "heavy-commands.json", heavyCommandsFile = (env) =>
|
|
77613
|
+
var HEAVY_COMMANDS_FILE = "heavy-commands.json", heavyCommandsFile = (env) => path51.join(stateDir2(env), HEAVY_COMMANDS_FILE), HEAVY_SCRIPT, INFO_FLAGS, WATCH_FLAG, WATCH_SCRIPT, sub = (...names) => new Set(names), TOOLS, PM_VALUES, baseName2 = (word) => (word?.split(/[\\/]/u).at(-1) ?? "").toLowerCase().replace(/\.(?:exe|cmd|bat|ps1)$/u, ""), WORKIT, PYTHONS, NPM_INSTALL, NPM_RUN, NPM_TEST, EXEC, globWord = (word) => new RegExp(`^${word.replace(/[.+?^${}()|[\]\\]/gu, "\\$&").replaceAll("*", ".*")}$`, "u"), matches2 = (matchers, words) => matchers.length <= words.length && matchers.every((matcher, index) => index === 0 ? matcher.test(words[0]) || matcher.test(baseName2(words[0])) : matcher.test(words[index])), readJson2 = (file) => {
|
|
77510
77614
|
try {
|
|
77511
77615
|
return JSON.parse(fs23.readFileSync(file, "utf8"));
|
|
77512
77616
|
} catch {
|
|
@@ -77652,8 +77756,8 @@ var init_heavy = __esm(() => {
|
|
|
77652
77756
|
// packages/workit-core/src/core/resources.ts
|
|
77653
77757
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
77654
77758
|
import fs24 from "node:fs";
|
|
77655
|
-
import
|
|
77656
|
-
import
|
|
77759
|
+
import os20 from "node:os";
|
|
77760
|
+
import path52 from "node:path";
|
|
77657
77761
|
function memoryValue(value, host) {
|
|
77658
77762
|
const text = typeof value === "number" ? String(value) : typeof value === "string" ? value : "";
|
|
77659
77763
|
const percent = PERCENT.exec(text.trim());
|
|
@@ -77834,7 +77938,7 @@ function tryOnce(options, record, reclaimed) {
|
|
|
77834
77938
|
const text = `${JSON.stringify(record)}
|
|
77835
77939
|
`;
|
|
77836
77940
|
for (let slot = 0;slot < options.slots; slot += 1) {
|
|
77837
|
-
const file =
|
|
77941
|
+
const file = path52.join(options.dir, `slot-${slot}.json`);
|
|
77838
77942
|
for (let attempt = 0;attempt < 2; attempt += 1) {
|
|
77839
77943
|
try {
|
|
77840
77944
|
const fd = fs24.openSync(file, "wx", 384);
|
|
@@ -77959,7 +78063,7 @@ function heldLease(dir, id, options = {}) {
|
|
|
77959
78063
|
for (const name of names) {
|
|
77960
78064
|
if (!/^slot-\d+\.json$/u.test(name))
|
|
77961
78065
|
continue;
|
|
77962
|
-
const lease = parseLease(readText5(
|
|
78066
|
+
const lease = parseLease(readText5(path52.join(dir, name)));
|
|
77963
78067
|
if (lease?.id === id && !staleReason(lease, options.probe) && (options.ancestor ?? isAncestor)(lease.pid))
|
|
77964
78068
|
return lease;
|
|
77965
78069
|
}
|
|
@@ -78014,10 +78118,10 @@ async function runScoped(run, wrapper, sinks) {
|
|
|
78014
78118
|
}
|
|
78015
78119
|
function firstNotice(env, session, key, now = Date.now()) {
|
|
78016
78120
|
const id = (session ?? `ppid-${process.ppid}`).replace(/[^A-Za-z0-9_.-]/gu, "_").slice(0, 120);
|
|
78017
|
-
const dir =
|
|
78121
|
+
const dir = path52.join(stateDir2(env), "notices");
|
|
78018
78122
|
try {
|
|
78019
78123
|
fs24.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
78020
|
-
fs24.writeFileSync(
|
|
78124
|
+
fs24.writeFileSync(path52.join(dir, `${key}-${id}`), `${new Date(now).toISOString()}
|
|
78021
78125
|
`, {
|
|
78022
78126
|
flag: "wx",
|
|
78023
78127
|
mode: 384
|
|
@@ -78027,7 +78131,7 @@ function firstNotice(env, session, key, now = Date.now()) {
|
|
|
78027
78131
|
}
|
|
78028
78132
|
try {
|
|
78029
78133
|
for (const name of fs24.readdirSync(dir)) {
|
|
78030
|
-
const file =
|
|
78134
|
+
const file = path52.join(dir, name);
|
|
78031
78135
|
if (now - fs24.statSync(file).mtimeMs > NOTICE_TTL_MS)
|
|
78032
78136
|
fs24.rmSync(file, { force: true });
|
|
78033
78137
|
}
|
|
@@ -78037,7 +78141,7 @@ function firstNotice(env, session, key, now = Date.now()) {
|
|
|
78037
78141
|
function leaseSlots(dir, slots, probe = {}) {
|
|
78038
78142
|
const states = [];
|
|
78039
78143
|
for (let slot = 0;slot < slots; slot += 1) {
|
|
78040
|
-
const lease = parseLease(readText5(
|
|
78144
|
+
const lease = parseLease(readText5(path52.join(dir, `slot-${slot}.json`)));
|
|
78041
78145
|
states.push({
|
|
78042
78146
|
slot,
|
|
78043
78147
|
holder: lease ? holderOf(lease) : null,
|
|
@@ -78047,15 +78151,15 @@ function leaseSlots(dir, slots, probe = {}) {
|
|
|
78047
78151
|
return states;
|
|
78048
78152
|
}
|
|
78049
78153
|
var DEFAULT_HEAVY_CHECKS, DEFAULT_SLOTS = 1, DEFAULT_WAIT_S = 600, DEFAULT_MEMORY_SHARE = 0.4, DEFAULT_CPU_SHARE = 0.7, MAX_SLOTS = 64, UNREADABLE_TTL_MS = 30000, GUARD_TTL_MS = 30000, hostShape = () => ({
|
|
78050
|
-
totalMemBytes:
|
|
78051
|
-
cpus: Math.max(1,
|
|
78052
|
-
}), isRecord9 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), SIZE, PERCENT, UNITS, leaseDir = (env) =>
|
|
78154
|
+
totalMemBytes: os20.totalmem(),
|
|
78155
|
+
cpus: Math.max(1, os20.availableParallelism?.() ?? os20.cpus().length)
|
|
78156
|
+
}), isRecord9 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), SIZE, PERCENT, UNITS, leaseDir = (env) => path52.join(stateDir2(env), "leases"), readText5 = (file) => {
|
|
78053
78157
|
try {
|
|
78054
78158
|
return fs24.readFileSync(file, "utf8");
|
|
78055
78159
|
} catch {
|
|
78056
78160
|
return null;
|
|
78057
78161
|
}
|
|
78058
|
-
}, bootId = () => readText5("/proc/sys/kernel/random/boot_id")?.trim() || null, bootTime = () => Math.round((Date.now() -
|
|
78162
|
+
}, bootId = () => readText5("/proc/sys/kernel/random/boot_id")?.trim() || null, bootTime = () => Math.round((Date.now() - os20.uptime() * 1000) / 1000) * 1000, BOOT_SLACK_MS = 120000, statFields = (pid) => {
|
|
78059
78163
|
const stat = readText5(`/proc/${pid}/stat`);
|
|
78060
78164
|
return stat ? stat.slice(stat.lastIndexOf(")") + 2).split(" ") : null;
|
|
78061
78165
|
}, processStart = (pid) => statFields(pid)?.[19] ?? null, pidAlive2 = (pid) => {
|
|
@@ -78104,8 +78208,8 @@ __export(exports_check, {
|
|
|
78104
78208
|
run: () => run12,
|
|
78105
78209
|
workspaceResources: () => workspaceResources
|
|
78106
78210
|
});
|
|
78107
|
-
import
|
|
78108
|
-
import
|
|
78211
|
+
import os21 from "node:os";
|
|
78212
|
+
import path53 from "node:path";
|
|
78109
78213
|
function parse6(argv) {
|
|
78110
78214
|
const split = argv.indexOf("--");
|
|
78111
78215
|
const head = split >= 0 ? argv.slice(0, split) : [...argv];
|
|
@@ -78307,7 +78411,7 @@ function hostToolWaitCapMs(env) {
|
|
|
78307
78411
|
}
|
|
78308
78412
|
async function workspaceResources(io) {
|
|
78309
78413
|
const env = io.env;
|
|
78310
|
-
const dir = env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ??
|
|
78414
|
+
const dir = env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path53.join(env.XDG_CONFIG_HOME || path53.join(env.HOME || os21.homedir(), ".config"), "workit");
|
|
78311
78415
|
try {
|
|
78312
78416
|
await Promise.resolve().then(() => init_workspaces());
|
|
78313
78417
|
const workspace = resolveWorkspaceFrom(io.cwd, dir, env.WORKFLOW_WORKSPACE_NAME?.trim() || undefined);
|
|
@@ -78426,7 +78530,7 @@ async function run12(argv, io) {
|
|
|
78426
78530
|
if (options.shell && command.length !== 1)
|
|
78427
78531
|
return emit(io, fail2("invalid_input", '--shell takes the command as one string: workit check --shell -- "<cmd>"'));
|
|
78428
78532
|
}
|
|
78429
|
-
const relCwd = posix(
|
|
78533
|
+
const relCwd = posix(path53.relative(top, runCwd));
|
|
78430
78534
|
const configured = !options.shell && matchesNamedCheck(config, name, command, relCwd);
|
|
78431
78535
|
const shadowed = !configured && name !== null ? config.checks.find((item) => item.name === name) : undefined;
|
|
78432
78536
|
if (shadowed)
|
|
@@ -78488,7 +78592,7 @@ async function run12(argv, io) {
|
|
|
78488
78592
|
const modifiedWorktree = key.tree !== null && treeAfter !== key.tree;
|
|
78489
78593
|
const store = storeRoot(io.cwd);
|
|
78490
78594
|
const blob = store.ok ? storeLog(store.value.root, result.log) : null;
|
|
78491
|
-
const logPath = store.ok && blob ?
|
|
78595
|
+
const logPath = store.ok && blob ? path53.join(store.value.root, blob.ref) : null;
|
|
78492
78596
|
const tail = tailLines(result.log, TAIL_LINES);
|
|
78493
78597
|
const passed = result.exitCode === 0 && !result.timedOut;
|
|
78494
78598
|
const bounded = boundedArgv(command);
|
|
@@ -78603,7 +78707,7 @@ async function run12(argv, io) {
|
|
|
78603
78707
|
return recordError.code === "busy" ? 4 : recordError.code === "invalid_input" ? 2 : 5;
|
|
78604
78708
|
return 0;
|
|
78605
78709
|
}
|
|
78606
|
-
var USAGE6 = 'workit check <name> [--full] [--no-lease --reason "<why>"] | workit check [--name <n>] [--shell] [--heavy] [--full] [--wait <s>] [--timeout <s>] [--task <id>] [--json] -- <cmd…>', OUTPUT_LINES = 60, MAX_UNVERIFIED_RUN_MS, RECORD_TAIL_LINES = 20, RECORD_TAIL_CHARS = 200, posix = (value) => value.split(
|
|
78710
|
+
var USAGE6 = 'workit check <name> [--full] [--no-lease --reason "<why>"] | workit check [--name <n>] [--shell] [--heavy] [--full] [--wait <s>] [--timeout <s>] [--task <id>] [--json] -- <cmd…>', OUTPUT_LINES = 60, MAX_UNVERIFIED_RUN_MS, RECORD_TAIL_LINES = 20, RECORD_TAIL_CHARS = 200, posix = (value) => value.split(path53.sep).join("/") || ".", ENGINE_CODES2, FINGERPRINT_VARS, ANSI_COLOR, WARNING_LINE, NO_WARNINGS, HOST_TOOL_WAIT_CAP_MS = 1e5;
|
|
78607
78711
|
var init_check = __esm(() => {
|
|
78608
78712
|
init_check_config();
|
|
78609
78713
|
init_checks3();
|
|
@@ -78632,7 +78736,7 @@ __export(exports_lock, {
|
|
|
78632
78736
|
run: () => run13
|
|
78633
78737
|
});
|
|
78634
78738
|
import fs25 from "node:fs";
|
|
78635
|
-
import
|
|
78739
|
+
import path54 from "node:path";
|
|
78636
78740
|
async function settingsFor(io) {
|
|
78637
78741
|
const workspace = await workspaceResources(io);
|
|
78638
78742
|
const config = loadCheckConfig(io.cwd);
|
|
@@ -78714,7 +78818,7 @@ function readPatterns(file) {
|
|
|
78714
78818
|
return { patterns: [] };
|
|
78715
78819
|
}
|
|
78716
78820
|
function writePatterns(file, value) {
|
|
78717
|
-
fs25.mkdirSync(
|
|
78821
|
+
fs25.mkdirSync(path54.dirname(file), { recursive: true, mode: 448 });
|
|
78718
78822
|
const temp = `${file}.${process.pid}.tmp`;
|
|
78719
78823
|
fs25.writeFileSync(temp, `${JSON.stringify(value, null, 2)}
|
|
78720
78824
|
`, { mode: 384 });
|
|
@@ -78800,9 +78904,9 @@ var exports_models = {};
|
|
|
78800
78904
|
__export(exports_models, {
|
|
78801
78905
|
run: () => run14
|
|
78802
78906
|
});
|
|
78803
|
-
import { existsSync as
|
|
78804
|
-
import
|
|
78805
|
-
import
|
|
78907
|
+
import { existsSync as existsSync24, readdirSync as readdirSync13, readFileSync as readFileSync23, statSync as statSync9 } from "node:fs";
|
|
78908
|
+
import os22 from "node:os";
|
|
78909
|
+
import path55 from "node:path";
|
|
78806
78910
|
async function run14(argv, io) {
|
|
78807
78911
|
const [sub, ...args] = argv.filter((arg) => arg !== "--json");
|
|
78808
78912
|
if (sub !== "show")
|
|
@@ -78863,7 +78967,7 @@ var USAGE8 = "workit models show [--role <role>] [--tier <tier>] [--host <host>]
|
|
|
78863
78967
|
const found = new Set;
|
|
78864
78968
|
let text = "";
|
|
78865
78969
|
try {
|
|
78866
|
-
text =
|
|
78970
|
+
text = readFileSync23(file, "utf8");
|
|
78867
78971
|
} catch {
|
|
78868
78972
|
return found;
|
|
78869
78973
|
}
|
|
@@ -78877,26 +78981,26 @@ var USAGE8 = "workit models show [--role <role>] [--tier <tier>] [--host <host>]
|
|
|
78877
78981
|
} catch {}
|
|
78878
78982
|
return found;
|
|
78879
78983
|
}, matches3 = (ran, configured) => ran.toLowerCase().includes(configured.toLowerCase()), usageReport = (cwd, env, days) => {
|
|
78880
|
-
const projects =
|
|
78984
|
+
const projects = path55.join(env.CLAUDE_CONFIG_DIR || path55.join(env.HOME || os22.homedir(), ".claude"), "projects");
|
|
78881
78985
|
const since = Date.now() - days * 86400000;
|
|
78882
78986
|
const types = {};
|
|
78883
78987
|
let agents = 0;
|
|
78884
78988
|
const dirs = (dir) => {
|
|
78885
78989
|
try {
|
|
78886
|
-
return readdirSync13(dir).map((name) =>
|
|
78990
|
+
return readdirSync13(dir).map((name) => path55.join(dir, name));
|
|
78887
78991
|
} catch {
|
|
78888
78992
|
return [];
|
|
78889
78993
|
}
|
|
78890
78994
|
};
|
|
78891
78995
|
for (const project of dirs(projects))
|
|
78892
78996
|
for (const session of dirs(project))
|
|
78893
|
-
for (const meta of dirs(
|
|
78997
|
+
for (const meta of dirs(path55.join(session, "subagents")).filter((f) => f.endsWith(".meta.json"))) {
|
|
78894
78998
|
try {
|
|
78895
78999
|
if (statSync9(meta).mtimeMs < since)
|
|
78896
79000
|
continue;
|
|
78897
|
-
const agentType = JSON.parse(
|
|
79001
|
+
const agentType = JSON.parse(readFileSync23(meta, "utf8")).agentType;
|
|
78898
79002
|
const transcript = meta.replace(/\.meta\.json$/, ".jsonl");
|
|
78899
|
-
if (typeof agentType !== "string" || !
|
|
79003
|
+
if (typeof agentType !== "string" || !existsSync24(transcript))
|
|
78900
79004
|
continue;
|
|
78901
79005
|
const ran = modelsOf(transcript);
|
|
78902
79006
|
if (!ran.size)
|
|
@@ -79035,8 +79139,8 @@ var success2 = (data) => ({ ok: true, data }), failure3 = (code, error, unblock)
|
|
|
79035
79139
|
|
|
79036
79140
|
// packages/workit-core/src/git/ops.ts
|
|
79037
79141
|
import { spawnSync as spawnSync20 } from "node:child_process";
|
|
79038
|
-
import { existsSync as
|
|
79039
|
-
import
|
|
79142
|
+
import { existsSync as existsSync25, readFileSync as readFileSync24 } from "node:fs";
|
|
79143
|
+
import path56 from "node:path";
|
|
79040
79144
|
function operationInProgress(cwd) {
|
|
79041
79145
|
const markers = [
|
|
79042
79146
|
["rebase-merge", "rebase"],
|
|
@@ -79049,18 +79153,18 @@ function operationInProgress(cwd) {
|
|
|
79049
79153
|
if (!run.ok)
|
|
79050
79154
|
return null;
|
|
79051
79155
|
const found = run.stdout.split(`
|
|
79052
|
-
`).map((line) =>
|
|
79156
|
+
`).map((line) => path56.resolve(cwd, line.trim()));
|
|
79053
79157
|
const conflicted = () => git5(cwd, ["ls-files", "-u"]).stdout.trim() !== "";
|
|
79054
79158
|
for (const [index, [, operation]] of markers.entries()) {
|
|
79055
79159
|
const marker = found[index];
|
|
79056
|
-
if (!marker || !
|
|
79160
|
+
if (!marker || !existsSync25(marker))
|
|
79057
79161
|
continue;
|
|
79058
|
-
if (index === 1 &&
|
|
79162
|
+
if (index === 1 && existsSync25(path56.join(marker, "applying")))
|
|
79059
79163
|
return { operation: "am", commitAllowed: false, branch: null };
|
|
79060
|
-
if (index === 0 &&
|
|
79164
|
+
if (index === 0 && existsSync25(path56.join(marker, "amend")) && !conflicted()) {
|
|
79061
79165
|
let headName = "";
|
|
79062
79166
|
try {
|
|
79063
|
-
headName =
|
|
79167
|
+
headName = readFileSync24(path56.join(marker, "head-name"), "utf8").trim();
|
|
79064
79168
|
} catch {}
|
|
79065
79169
|
const branch = headName.startsWith("refs/heads/") ? headName.slice("refs/heads/".length) : null;
|
|
79066
79170
|
return { operation, commitAllowed: branch !== null, branch };
|
|
@@ -79388,7 +79492,7 @@ function gitCommit(cwd, input) {
|
|
|
79388
79492
|
if (paths.some((value) => value.startsWith("-") || !value.trim()))
|
|
79389
79493
|
return failure3("invalid_input", "paths must not be empty or start with -");
|
|
79390
79494
|
const tracked = new Set(nulList(git5(cwd, ["ls-files", "-z", "--", ...paths]).stdout));
|
|
79391
|
-
const addable = paths.filter((value) =>
|
|
79495
|
+
const addable = paths.filter((value) => existsSync25(path56.resolve(cwd, value)) || [...tracked].some((file) => file === value || file.startsWith(`${value}/`)));
|
|
79392
79496
|
if (addable.length) {
|
|
79393
79497
|
const added = git5(cwd, ["add", "-A", "--", ...addable]);
|
|
79394
79498
|
if (!added.ok)
|
|
@@ -79927,12 +80031,12 @@ var init_ops = __esm(() => {
|
|
|
79927
80031
|
|
|
79928
80032
|
// packages/workit-core/src/verdict-cover.ts
|
|
79929
80033
|
import fs26 from "node:fs";
|
|
79930
|
-
import
|
|
80034
|
+
import path57 from "node:path";
|
|
79931
80035
|
function chainsAbove(cwd, branch) {
|
|
79932
80036
|
const root = storeRoot(cwd);
|
|
79933
80037
|
if (!root.ok)
|
|
79934
80038
|
return [];
|
|
79935
|
-
const dir =
|
|
80039
|
+
const dir = path57.join(root.value.root, "stacks");
|
|
79936
80040
|
let names = [];
|
|
79937
80041
|
try {
|
|
79938
80042
|
names = fs26.readdirSync(dir).filter((name) => name.endsWith(".json"));
|
|
@@ -79943,7 +80047,7 @@ function chainsAbove(cwd, branch) {
|
|
|
79943
80047
|
for (const name of names.toSorted()) {
|
|
79944
80048
|
let parsed;
|
|
79945
80049
|
try {
|
|
79946
|
-
parsed = JSON.parse(fs26.readFileSync(
|
|
80050
|
+
parsed = JSON.parse(fs26.readFileSync(path57.join(dir, name), "utf8"));
|
|
79947
80051
|
} catch {
|
|
79948
80052
|
continue;
|
|
79949
80053
|
}
|
|
@@ -80038,10 +80142,10 @@ var init_pr_lane = __esm(() => {
|
|
|
80038
80142
|
|
|
80039
80143
|
// packages/workit-core/src/forge/reruns.ts
|
|
80040
80144
|
import fs27 from "node:fs";
|
|
80041
|
-
import
|
|
80145
|
+
import path58 from "node:path";
|
|
80042
80146
|
function rerunLogPath(cwd) {
|
|
80043
80147
|
const common = gitCommonDir(cwd);
|
|
80044
|
-
return common ?
|
|
80148
|
+
return common ? path58.join(common, "workit", "ci-reruns.jsonl") : null;
|
|
80045
80149
|
}
|
|
80046
80150
|
function rerunCounts(cwd, key) {
|
|
80047
80151
|
const counts = new Map;
|
|
@@ -80076,7 +80180,7 @@ function recordReruns(cwd, rows) {
|
|
|
80076
80180
|
if (!file)
|
|
80077
80181
|
return false;
|
|
80078
80182
|
try {
|
|
80079
|
-
fs27.mkdirSync(
|
|
80183
|
+
fs27.mkdirSync(path58.dirname(file), { recursive: true });
|
|
80080
80184
|
fs27.appendFileSync(file, rows.map((row) => `${JSON.stringify(row)}
|
|
80081
80185
|
`).join(""));
|
|
80082
80186
|
return true;
|
|
@@ -80089,7 +80193,7 @@ function withRerunLock(cwd, fn) {
|
|
|
80089
80193
|
if (!file)
|
|
80090
80194
|
return fn();
|
|
80091
80195
|
const lock = `${file.slice(0, -".jsonl".length)}.lock`;
|
|
80092
|
-
fs27.mkdirSync(
|
|
80196
|
+
fs27.mkdirSync(path58.dirname(lock), { recursive: true });
|
|
80093
80197
|
const until = Date.now() + LOCK_WAIT_MS2;
|
|
80094
80198
|
for (;; ) {
|
|
80095
80199
|
try {
|
|
@@ -80506,7 +80610,7 @@ function recordAccepted(cwd, resolved, status, accepted, options) {
|
|
|
80506
80610
|
return recordReruns(cwd, rows);
|
|
80507
80611
|
}
|
|
80508
80612
|
var MAX_LOG_TAILS = 5, GITLAB_MERGEABLE, GITHUB_MERGEABLE, NO_CHECKS_GRACE_MS = 90000;
|
|
80509
|
-
var
|
|
80613
|
+
var init_report2 = __esm(() => {
|
|
80510
80614
|
init_rev();
|
|
80511
80615
|
init_ledger();
|
|
80512
80616
|
init_reruns();
|
|
@@ -81055,7 +81159,7 @@ var init_pr_ops = __esm(() => {
|
|
|
81055
81159
|
init_ledger();
|
|
81056
81160
|
init_verdict_cover();
|
|
81057
81161
|
init_pr_lane();
|
|
81058
|
-
|
|
81162
|
+
init_report2();
|
|
81059
81163
|
VERIFY_DELAYS_MS = [1000, 2000, 4000];
|
|
81060
81164
|
AFTER_REVIEW = {
|
|
81061
81165
|
commit: "stop here; review comes when the user asks",
|
|
@@ -81068,9 +81172,9 @@ var init_pr_ops = __esm(() => {
|
|
|
81068
81172
|
|
|
81069
81173
|
// packages/workit-core/src/stack.ts
|
|
81070
81174
|
import { spawnSync as spawnSync22 } from "node:child_process";
|
|
81071
|
-
import { createHash as
|
|
81175
|
+
import { createHash as createHash18, randomBytes as randomBytes4 } from "node:crypto";
|
|
81072
81176
|
import fs28 from "node:fs";
|
|
81073
|
-
import
|
|
81177
|
+
import path59 from "node:path";
|
|
81074
81178
|
function worktreeOf(cwd, branch) {
|
|
81075
81179
|
const list = gitRun3(cwd, ["worktree", "list", "--porcelain"]);
|
|
81076
81180
|
if (!list.ok)
|
|
@@ -81119,7 +81223,7 @@ function gitRestack(cwd, input) {
|
|
|
81119
81223
|
error: "no store root"
|
|
81120
81224
|
};
|
|
81121
81225
|
fs28.mkdirSync(scratch, { recursive: true });
|
|
81122
|
-
dir =
|
|
81226
|
+
dir = path59.join(scratch, `${input.branch.replace(/[^A-Za-z0-9._-]+/gu, "_").slice(0, 40)}-${randomBytes4(4).toString("hex")}`);
|
|
81123
81227
|
const added = gitRun3(cwd, ["worktree", "add", "-q", dir, input.branch], GIT_TIMEOUTS.worktree);
|
|
81124
81228
|
if (!added.ok)
|
|
81125
81229
|
return {
|
|
@@ -81175,7 +81279,7 @@ function pruneScratch(cwd) {
|
|
|
81175
81279
|
if (!scratch || !fs28.existsSync(scratch))
|
|
81176
81280
|
return;
|
|
81177
81281
|
for (const name of fs28.readdirSync(scratch)) {
|
|
81178
|
-
const dir =
|
|
81282
|
+
const dir = path59.join(scratch, name);
|
|
81179
81283
|
if (!rebaseInProgress(dir) && !trackedDirt(dir))
|
|
81180
81284
|
gitRun3(cwd, ["worktree", "remove", "--force", dir]);
|
|
81181
81285
|
}
|
|
@@ -81185,7 +81289,7 @@ function stacksDir(cwd) {
|
|
|
81185
81289
|
const root = storeRoot(cwd);
|
|
81186
81290
|
if (!root.ok)
|
|
81187
81291
|
return stackFail(root.code, root.error, root.unblock);
|
|
81188
|
-
return { ok: true, data:
|
|
81292
|
+
return { ok: true, data: path59.join(root.value.root, "stacks") };
|
|
81189
81293
|
}
|
|
81190
81294
|
function parseStack(raw) {
|
|
81191
81295
|
if (!isRecord12(raw) || !Array.isArray(raw.branches))
|
|
@@ -81237,7 +81341,7 @@ function readStack(cwd, name) {
|
|
|
81237
81341
|
const dir = stacksDir(cwd);
|
|
81238
81342
|
if (!dir.ok)
|
|
81239
81343
|
return dir;
|
|
81240
|
-
const file =
|
|
81344
|
+
const file = path59.join(dir.data, fileFor(name));
|
|
81241
81345
|
let text;
|
|
81242
81346
|
try {
|
|
81243
81347
|
text = fs28.readFileSync(file, "utf8");
|
|
@@ -81258,7 +81362,7 @@ function writeStack(cwd, stack, now = new Date) {
|
|
|
81258
81362
|
const dir = stacksDir(cwd);
|
|
81259
81363
|
if (!dir.ok)
|
|
81260
81364
|
return dir;
|
|
81261
|
-
const file =
|
|
81365
|
+
const file = path59.join(dir.data, fileFor(stack.name));
|
|
81262
81366
|
const temp = `${file}.${process.pid}.tmp`;
|
|
81263
81367
|
try {
|
|
81264
81368
|
fs28.mkdirSync(dir.data, { recursive: true });
|
|
@@ -81286,7 +81390,7 @@ function listStacks(cwd) {
|
|
|
81286
81390
|
for (const name of names) {
|
|
81287
81391
|
let parsed = null;
|
|
81288
81392
|
try {
|
|
81289
|
-
parsed = parseStack(JSON.parse(fs28.readFileSync(
|
|
81393
|
+
parsed = parseStack(JSON.parse(fs28.readFileSync(path59.join(dir.data, name), "utf8")));
|
|
81290
81394
|
} catch {
|
|
81291
81395
|
parsed = null;
|
|
81292
81396
|
}
|
|
@@ -81348,7 +81452,7 @@ function takeLock(lock) {
|
|
|
81348
81452
|
host: localLockHost(),
|
|
81349
81453
|
nonce: randomBytes4(8).toString("hex")
|
|
81350
81454
|
};
|
|
81351
|
-
fs28.writeFileSync(
|
|
81455
|
+
fs28.writeFileSync(path59.join(lock, OWNER), JSON.stringify(owner));
|
|
81352
81456
|
return owner;
|
|
81353
81457
|
}
|
|
81354
81458
|
function reapLock(lock, observed) {
|
|
@@ -81385,7 +81489,7 @@ async function withStackLock(cwd, name, fn, waitMs = LOCK_WAIT_MS3) {
|
|
|
81385
81489
|
return dir;
|
|
81386
81490
|
if (!validName(name))
|
|
81387
81491
|
return stackFail("invalid_input", "a stack name must be 1-200 printable characters");
|
|
81388
|
-
const lock =
|
|
81492
|
+
const lock = path59.join(dir.data, `${fileFor(name)}.lock`);
|
|
81389
81493
|
try {
|
|
81390
81494
|
fs28.mkdirSync(dir.data, { recursive: true });
|
|
81391
81495
|
} catch (error) {
|
|
@@ -81415,7 +81519,7 @@ async function withStackLock(cwd, name, fn, waitMs = LOCK_WAIT_MS3) {
|
|
|
81415
81519
|
const touch = () => {
|
|
81416
81520
|
try {
|
|
81417
81521
|
const now = new Date;
|
|
81418
|
-
fs28.utimesSync(
|
|
81522
|
+
fs28.utimesSync(path59.join(lock, OWNER), now, now);
|
|
81419
81523
|
} catch {}
|
|
81420
81524
|
};
|
|
81421
81525
|
const beat = setInterval(touch, HEARTBEAT_MS);
|
|
@@ -82316,10 +82420,10 @@ var STACK_VERSION = 1, stackFail = (code, error, unblock, data) => ({
|
|
|
82316
82420
|
return !status.ok || status.stdout.trim() !== "";
|
|
82317
82421
|
}, scratchDir = (cwd) => {
|
|
82318
82422
|
const dir = stacksDir(cwd);
|
|
82319
|
-
return dir.ok ?
|
|
82423
|
+
return dir.ok ? path59.join(dir.data, "worktrees") : null;
|
|
82320
82424
|
}, firstLine = (run) => (`${run.stderr}
|
|
82321
82425
|
${run.stdout}`.split(`
|
|
82322
|
-
`).find((line) => line.trim()) ?? "git failed").trim().slice(0, 300), stackFileName = (name) => `${name.replace(/[^A-Za-z0-9._-]+/gu, "_").replace(/^[._]+/u, "").slice(0, 48).toLowerCase()}-${
|
|
82426
|
+
`).find((line) => line.trim()) ?? "git failed").trim().slice(0, 300), stackFileName = (name) => `${name.replace(/[^A-Za-z0-9._-]+/gu, "_").replace(/^[._]+/u, "").slice(0, 48).toLowerCase()}-${createHash18("sha256").update(name).digest("hex").slice(0, 12)}.json`, fileFor, validName = (name) => {
|
|
82323
82427
|
if (name.length === 0 || name.length > 200)
|
|
82324
82428
|
return false;
|
|
82325
82429
|
for (let index = 0;index < name.length; index += 1) {
|
|
@@ -82331,12 +82435,12 @@ ${run.stdout}`.split(`
|
|
|
82331
82435
|
}, isRecord12 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), str3 = (value) => typeof value === "string" && value ? value : null, LOCK_WAIT_MS3 = 2000, HEARTBEAT_MS = 20000, HEARTBEAT_STALE_MS, OWNERLESS_STALE_MS = 30000, OWNER = "owner", readOwner = (lock) => {
|
|
82332
82436
|
let raw = null;
|
|
82333
82437
|
try {
|
|
82334
|
-
raw = fs28.readFileSync(
|
|
82438
|
+
raw = fs28.readFileSync(path59.join(lock, OWNER), "utf8");
|
|
82335
82439
|
} catch {
|
|
82336
82440
|
raw = null;
|
|
82337
82441
|
}
|
|
82338
82442
|
let age = null;
|
|
82339
|
-
for (const target of [
|
|
82443
|
+
for (const target of [path59.join(lock, OWNER), lock])
|
|
82340
82444
|
try {
|
|
82341
82445
|
age = Date.now() - fs28.statSync(target).mtimeMs;
|
|
82342
82446
|
break;
|
|
@@ -82360,7 +82464,7 @@ var init_stack = __esm(() => {
|
|
|
82360
82464
|
init_autonomy();
|
|
82361
82465
|
init_store_lock();
|
|
82362
82466
|
init_pr_ops();
|
|
82363
|
-
|
|
82467
|
+
init_report2();
|
|
82364
82468
|
init_ops();
|
|
82365
82469
|
init_rev();
|
|
82366
82470
|
init_ledger();
|
|
@@ -82377,9 +82481,9 @@ var init_stack = __esm(() => {
|
|
|
82377
82481
|
|
|
82378
82482
|
// packages/workit-core/src/fanout.ts
|
|
82379
82483
|
import { spawnSync as spawnSync23 } from "node:child_process";
|
|
82380
|
-
import { createHash as
|
|
82484
|
+
import { createHash as createHash19 } from "node:crypto";
|
|
82381
82485
|
import fs29 from "node:fs";
|
|
82382
|
-
import
|
|
82486
|
+
import path60 from "node:path";
|
|
82383
82487
|
function expandBraces2(pattern, limit = 64) {
|
|
82384
82488
|
for (let index = 0;index < pattern.length; index += 1) {
|
|
82385
82489
|
if (pattern[index] === "\\") {
|
|
@@ -82625,7 +82729,7 @@ function parsePlan(raw, defaults, name) {
|
|
|
82625
82729
|
id,
|
|
82626
82730
|
branch,
|
|
82627
82731
|
base: optional("base") ?? "",
|
|
82628
|
-
worktree:
|
|
82732
|
+
worktree: path60.resolve(defaults.root, optional("worktree") ?? path60.join(defaults.worktreeRoot, id)),
|
|
82629
82733
|
tier,
|
|
82630
82734
|
reason,
|
|
82631
82735
|
dependsOn: [...new Set(dependsOn ?? [])],
|
|
@@ -82754,12 +82858,12 @@ function regeneratedFiles(root, tracked) {
|
|
|
82754
82858
|
const found = new Map;
|
|
82755
82859
|
let scripts;
|
|
82756
82860
|
try {
|
|
82757
|
-
const manifest = JSON.parse(fs29.readFileSync(
|
|
82861
|
+
const manifest = JSON.parse(fs29.readFileSync(path60.join(root, "package.json"), "utf8"));
|
|
82758
82862
|
scripts = manifest.scripts ?? {};
|
|
82759
82863
|
} catch {
|
|
82760
82864
|
return found;
|
|
82761
82865
|
}
|
|
82762
|
-
const runner = fs29.existsSync(
|
|
82866
|
+
const runner = fs29.existsSync(path60.join(root, "bun.lock")) ? "bun run" : fs29.existsSync(path60.join(root, "pnpm-lock.yaml")) ? "pnpm run" : fs29.existsSync(path60.join(root, "yarn.lock")) ? "yarn run" : "npm run";
|
|
82763
82867
|
const outputs = tracked.filter((file) => !CODE.test(file));
|
|
82764
82868
|
for (const [name, command] of Object.entries(scripts)) {
|
|
82765
82869
|
if (!name.startsWith("write:") || typeof command !== "string")
|
|
@@ -82767,7 +82871,7 @@ function regeneratedFiles(root, tracked) {
|
|
|
82767
82871
|
for (const file of command.match(/[\w./-]+\.[cm]?[jt]s\b/gu) ?? []) {
|
|
82768
82872
|
let source;
|
|
82769
82873
|
try {
|
|
82770
|
-
source = fs29.readFileSync(
|
|
82874
|
+
source = fs29.readFileSync(path60.join(root, file), "utf8");
|
|
82771
82875
|
} catch {
|
|
82772
82876
|
continue;
|
|
82773
82877
|
}
|
|
@@ -82889,11 +82993,11 @@ function defaultTrunk(cwd) {
|
|
|
82889
82993
|
}
|
|
82890
82994
|
function mainCheckout(cwd) {
|
|
82891
82995
|
const common = gitCommonDir(cwd);
|
|
82892
|
-
return common &&
|
|
82996
|
+
return common && path60.basename(common) === ".git" ? path60.dirname(common) : path60.resolve(cwd);
|
|
82893
82997
|
}
|
|
82894
82998
|
function worktreeRoot(cwd) {
|
|
82895
82999
|
const main = mainCheckout(cwd);
|
|
82896
|
-
return
|
|
83000
|
+
return path60.join(path60.dirname(main), `${path60.basename(main)}-wt`);
|
|
82897
83001
|
}
|
|
82898
83002
|
function sliceHash(slice) {
|
|
82899
83003
|
const {
|
|
@@ -82907,13 +83011,13 @@ function sliceHash(slice) {
|
|
|
82907
83011
|
issues: _issues,
|
|
82908
83012
|
...definition
|
|
82909
83013
|
} = slice;
|
|
82910
|
-
return
|
|
83014
|
+
return createHash19("sha256").update(JSON.stringify(definition)).digest("hex").slice(0, 16);
|
|
82911
83015
|
}
|
|
82912
83016
|
function fanoutsDir(cwd) {
|
|
82913
83017
|
const root = storeRoot(cwd);
|
|
82914
83018
|
if (!root.ok)
|
|
82915
83019
|
return fanoutFail(root.code, root.error, root.unblock);
|
|
82916
|
-
return { ok: true, data:
|
|
83020
|
+
return { ok: true, data: path60.join(root.value.root, "fanouts") };
|
|
82917
83021
|
}
|
|
82918
83022
|
function parseStored(raw) {
|
|
82919
83023
|
if (!isRecord13(raw) || typeof raw.name !== "string" || typeof raw.trunk !== "string")
|
|
@@ -82981,7 +83085,7 @@ function readFanout(cwd, name) {
|
|
|
82981
83085
|
const dir = fanoutsDir(cwd);
|
|
82982
83086
|
if (!dir.ok)
|
|
82983
83087
|
return dir;
|
|
82984
|
-
const file =
|
|
83088
|
+
const file = path60.join(dir.data, stackFileName(name));
|
|
82985
83089
|
let parsed = null;
|
|
82986
83090
|
try {
|
|
82987
83091
|
parsed = parseStored(JSON.parse(fs29.readFileSync(file, "utf8")));
|
|
@@ -83006,7 +83110,7 @@ function listFanouts(cwd) {
|
|
|
83006
83110
|
for (const entry of names) {
|
|
83007
83111
|
let parsed = null;
|
|
83008
83112
|
try {
|
|
83009
|
-
parsed = parseStored(JSON.parse(fs29.readFileSync(
|
|
83113
|
+
parsed = parseStored(JSON.parse(fs29.readFileSync(path60.join(dir.data, entry), "utf8")));
|
|
83010
83114
|
} catch {
|
|
83011
83115
|
parsed = null;
|
|
83012
83116
|
}
|
|
@@ -83045,7 +83149,7 @@ function writeFanout(cwd, plan) {
|
|
|
83045
83149
|
const dir = fanoutsDir(cwd);
|
|
83046
83150
|
if (!dir.ok)
|
|
83047
83151
|
return dir;
|
|
83048
|
-
const file =
|
|
83152
|
+
const file = path60.join(dir.data, stackFileName(plan.name));
|
|
83049
83153
|
const temp = `${file}.${process.pid}.tmp`;
|
|
83050
83154
|
try {
|
|
83051
83155
|
fs29.mkdirSync(dir.data, { recursive: true });
|
|
@@ -83256,13 +83360,13 @@ var init_fanout = __esm(() => {
|
|
|
83256
83360
|
// packages/workit-core/src/forge/exec.ts
|
|
83257
83361
|
import { spawnSync as spawnSync24 } from "node:child_process";
|
|
83258
83362
|
import fs30 from "node:fs";
|
|
83259
|
-
import
|
|
83363
|
+
import path61 from "node:path";
|
|
83260
83364
|
function findExecutable(bin, env) {
|
|
83261
|
-
const dirs = (env.PATH ?? env.Path ?? "").split(
|
|
83365
|
+
const dirs = (env.PATH ?? env.Path ?? "").split(path61.delimiter).filter(Boolean);
|
|
83262
83366
|
const exts = process.platform === "win32" ? [".exe"] : [""];
|
|
83263
83367
|
for (const dir of dirs)
|
|
83264
83368
|
for (const ext of exts) {
|
|
83265
|
-
const candidate =
|
|
83369
|
+
const candidate = path61.join(dir, `${bin}${ext}`);
|
|
83266
83370
|
try {
|
|
83267
83371
|
const stat = fs30.statSync(candidate);
|
|
83268
83372
|
if (stat.isFile())
|
|
@@ -84805,7 +84909,7 @@ var init_pr_edit = __esm(() => {
|
|
|
84805
84909
|
init_rev();
|
|
84806
84910
|
init_stack();
|
|
84807
84911
|
init_pr_ops();
|
|
84808
|
-
|
|
84912
|
+
init_report2();
|
|
84809
84913
|
});
|
|
84810
84914
|
|
|
84811
84915
|
// packages/workit-core/src/core/live-session.ts
|
|
@@ -84825,7 +84929,7 @@ var init_live_session = __esm(() => {
|
|
|
84825
84929
|
});
|
|
84826
84930
|
|
|
84827
84931
|
// packages/workit-core/src/hooks/write-gate.ts
|
|
84828
|
-
import
|
|
84932
|
+
import path62 from "node:path";
|
|
84829
84933
|
var CASE_INSENSITIVE, PREFIXES2, SCRIPT_SHELLS, cache3, MUTATING_GIT, DRY_N, MUTATING_WORKIT_GIT, CD2, PUSHD2, POPD2, UNKNOWN_DIR;
|
|
84830
84934
|
var init_write_gate = __esm(() => {
|
|
84831
84935
|
init_task_store();
|
|
@@ -84865,7 +84969,7 @@ var init_write_gate = __esm(() => {
|
|
|
84865
84969
|
CD2 = new Set(["cd", "chdir", "set-location", "sl"]);
|
|
84866
84970
|
PUSHD2 = new Set(["pushd", "push-location"]);
|
|
84867
84971
|
POPD2 = new Set(["popd", "pop-location"]);
|
|
84868
|
-
UNKNOWN_DIR =
|
|
84972
|
+
UNKNOWN_DIR = path62.resolve(path62.parse(process.cwd()).root, ".workit-unknown-dir");
|
|
84869
84973
|
});
|
|
84870
84974
|
|
|
84871
84975
|
// packages/workit-core/src/hooks/worktree-confine.ts
|
|
@@ -84890,20 +84994,20 @@ var init_worktree_confine = __esm(() => {
|
|
|
84890
84994
|
|
|
84891
84995
|
// packages/workit-core/src/worktree-deps.ts
|
|
84892
84996
|
import fs31 from "node:fs";
|
|
84893
|
-
import
|
|
84997
|
+
import path63 from "node:path";
|
|
84894
84998
|
function moduleDirs(main) {
|
|
84895
84999
|
const out = [];
|
|
84896
85000
|
const walk = (relative, depth) => {
|
|
84897
85001
|
let entries;
|
|
84898
85002
|
try {
|
|
84899
|
-
entries = fs31.readdirSync(
|
|
85003
|
+
entries = fs31.readdirSync(path63.join(main, relative), { withFileTypes: true });
|
|
84900
85004
|
} catch {
|
|
84901
85005
|
return;
|
|
84902
85006
|
}
|
|
84903
85007
|
for (const entry of entries) {
|
|
84904
85008
|
if (!entry.isDirectory())
|
|
84905
85009
|
continue;
|
|
84906
|
-
const child =
|
|
85010
|
+
const child = path63.join(relative, entry.name);
|
|
84907
85011
|
if (entry.name === MODULES)
|
|
84908
85012
|
out.push(child);
|
|
84909
85013
|
else if (depth < MAX_DEPTH2 && !entry.name.startsWith("."))
|
|
@@ -84917,8 +85021,8 @@ function linkEntry(main, worktree, source, target) {
|
|
|
84917
85021
|
const stat = fs31.lstatSync(source);
|
|
84918
85022
|
if (stat.isSymbolicLink()) {
|
|
84919
85023
|
const link = fs31.readlinkSync(source);
|
|
84920
|
-
const outside =
|
|
84921
|
-
const to = outside ?
|
|
85024
|
+
const outside = path63.isAbsolute(link) && within(link, main) && !path63.relative(main, link).split(path63.sep).includes(MODULES);
|
|
85025
|
+
const to = outside ? path63.join(worktree, path63.relative(main, link)) : link;
|
|
84922
85026
|
fs31.symlinkSync(to, target, process.platform === "win32" ? "junction" : undefined);
|
|
84923
85027
|
return;
|
|
84924
85028
|
}
|
|
@@ -84928,8 +85032,8 @@ function mirror(main, worktree, source, target, top) {
|
|
|
84928
85032
|
fs31.mkdirSync(target);
|
|
84929
85033
|
let count = 0;
|
|
84930
85034
|
for (const entry of fs31.readdirSync(source, { withFileTypes: true })) {
|
|
84931
|
-
const from =
|
|
84932
|
-
const to =
|
|
85035
|
+
const from = path63.join(source, entry.name);
|
|
85036
|
+
const to = path63.join(target, entry.name);
|
|
84933
85037
|
if (top && entry.isDirectory() && (entry.name.startsWith("@") || entry.name === ".bin"))
|
|
84934
85038
|
count += mirror(main, worktree, from, to, false);
|
|
84935
85039
|
else {
|
|
@@ -84945,16 +85049,16 @@ function linkWorktreeDependencies(main, worktree) {
|
|
|
84945
85049
|
const dirs = [];
|
|
84946
85050
|
let entries = 0;
|
|
84947
85051
|
for (const relative of moduleDirs(main)) {
|
|
84948
|
-
const target =
|
|
84949
|
-
if (!fs31.existsSync(
|
|
85052
|
+
const target = path63.join(worktree, relative);
|
|
85053
|
+
if (!fs31.existsSync(path63.dirname(target)) || fs31.existsSync(target))
|
|
84950
85054
|
continue;
|
|
84951
|
-
if (!gitRun4(worktree, ["check-ignore", "-q", `${relative.split(
|
|
84952
|
-
notes.push(`${relative.split(
|
|
85055
|
+
if (!gitRun4(worktree, ["check-ignore", "-q", `${relative.split(path63.sep).join("/")}/`]).ok) {
|
|
85056
|
+
notes.push(`${relative.split(path63.sep).join("/")} is not ignored by git, so it was not linked from ${main}; install dependencies in the worktree yourself`);
|
|
84953
85057
|
continue;
|
|
84954
85058
|
}
|
|
84955
85059
|
try {
|
|
84956
|
-
entries += mirror(main, worktree,
|
|
84957
|
-
dirs.push(relative.split(
|
|
85060
|
+
entries += mirror(main, worktree, path63.join(main, relative), target, true);
|
|
85061
|
+
dirs.push(relative.split(path63.sep).join("/"));
|
|
84958
85062
|
} catch (error) {
|
|
84959
85063
|
fs31.rmSync(target, { recursive: true, force: true });
|
|
84960
85064
|
notes.push(`could not link ${relative} from ${main} (${error.message}); install dependencies in the worktree yourself`);
|
|
@@ -84967,8 +85071,8 @@ function linkWorktreeDependencies(main, worktree) {
|
|
|
84967
85071
|
return { linked: { from: main, dirs, entries, ms }, notes };
|
|
84968
85072
|
}
|
|
84969
85073
|
var MODULES = "node_modules", MAX_DEPTH2 = 2, within = (child, parent) => {
|
|
84970
|
-
const relative =
|
|
84971
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
85074
|
+
const relative = path63.relative(parent, child);
|
|
85075
|
+
return relative === "" || !relative.startsWith("..") && !path63.isAbsolute(relative);
|
|
84972
85076
|
};
|
|
84973
85077
|
var init_worktree_deps = __esm(() => {
|
|
84974
85078
|
init_fanout();
|
|
@@ -84977,7 +85081,7 @@ var init_worktree_deps = __esm(() => {
|
|
|
84977
85081
|
// packages/workit-core/src/fanout-worktree.ts
|
|
84978
85082
|
import { randomBytes as randomBytes5 } from "node:crypto";
|
|
84979
85083
|
import fs32 from "node:fs";
|
|
84980
|
-
import
|
|
85084
|
+
import path64 from "node:path";
|
|
84981
85085
|
function rowSample(lines) {
|
|
84982
85086
|
const out = [];
|
|
84983
85087
|
let bytes = 0;
|
|
@@ -85037,7 +85141,7 @@ function adminDir(worktree) {
|
|
|
85037
85141
|
const file = dir.stdout.trim();
|
|
85038
85142
|
let token = null;
|
|
85039
85143
|
try {
|
|
85040
|
-
token = fs32.readFileSync(
|
|
85144
|
+
token = fs32.readFileSync(path64.join(file, FANOUT_TOKEN_FILE), "utf8").trim() || null;
|
|
85041
85145
|
} catch {
|
|
85042
85146
|
token = null;
|
|
85043
85147
|
}
|
|
@@ -85045,7 +85149,7 @@ function adminDir(worktree) {
|
|
|
85045
85149
|
const stat = worktreeDeps.stat(file);
|
|
85046
85150
|
return {
|
|
85047
85151
|
path: file,
|
|
85048
|
-
id:
|
|
85152
|
+
id: path64.basename(file),
|
|
85049
85153
|
ino: stat.ino.toString(),
|
|
85050
85154
|
token,
|
|
85051
85155
|
birthMs: stat.birthtimeNs > 0n ? Number(stat.birthtimeMs) : null,
|
|
@@ -85061,7 +85165,7 @@ function markAdminDir(worktree) {
|
|
|
85061
85165
|
return null;
|
|
85062
85166
|
const token = randomBytes5(16).toString("hex");
|
|
85063
85167
|
try {
|
|
85064
|
-
fs32.writeFileSync(
|
|
85168
|
+
fs32.writeFileSync(path64.join(admin.path, FANOUT_TOKEN_FILE), `${token}
|
|
85065
85169
|
`);
|
|
85066
85170
|
} catch {
|
|
85067
85171
|
return null;
|
|
@@ -85076,7 +85180,7 @@ function excludeScratch(cwd) {
|
|
|
85076
85180
|
const common = gitCommonDir(cwd);
|
|
85077
85181
|
if (!common)
|
|
85078
85182
|
return;
|
|
85079
|
-
const file =
|
|
85183
|
+
const file = path64.join(common, "info", "exclude");
|
|
85080
85184
|
let text = "";
|
|
85081
85185
|
try {
|
|
85082
85186
|
text = fs32.readFileSync(file, "utf8");
|
|
@@ -85085,7 +85189,7 @@ function excludeScratch(cwd) {
|
|
|
85085
85189
|
}
|
|
85086
85190
|
if (text.split(/\r?\n/u).includes(EXCLUDE_LINE))
|
|
85087
85191
|
return;
|
|
85088
|
-
fs32.mkdirSync(
|
|
85192
|
+
fs32.mkdirSync(path64.dirname(file), { recursive: true });
|
|
85089
85193
|
fs32.appendFileSync(file, `${text && !text.endsWith(`
|
|
85090
85194
|
`) ? `
|
|
85091
85195
|
` : ""}# workit fanout: per-worker scratch dirs
|
|
@@ -85094,13 +85198,13 @@ ${EXCLUDE_LINE}
|
|
|
85094
85198
|
}
|
|
85095
85199
|
function worktreeDependencies(main, worktree) {
|
|
85096
85200
|
for (const [name, install] of LOCKFILES2) {
|
|
85097
|
-
const ours = readBytes(
|
|
85098
|
-
const theirs = readBytes(
|
|
85201
|
+
const ours = readBytes(path64.join(main, name));
|
|
85202
|
+
const theirs = readBytes(path64.join(worktree, name));
|
|
85099
85203
|
if (ours === null && theirs === null)
|
|
85100
85204
|
continue;
|
|
85101
85205
|
if (ours !== null && theirs !== null && ours.equals(theirs))
|
|
85102
85206
|
continue;
|
|
85103
|
-
if (fs32.existsSync(
|
|
85207
|
+
if (fs32.existsSync(path64.join(worktree, "node_modules")))
|
|
85104
85208
|
break;
|
|
85105
85209
|
const command = install(worktree);
|
|
85106
85210
|
return {
|
|
@@ -85114,7 +85218,7 @@ function worktreeDependencies(main, worktree) {
|
|
|
85114
85218
|
return { ...linkWorktreeDependencies(main, worktree), install: null };
|
|
85115
85219
|
}
|
|
85116
85220
|
function ensureScratch(worktree) {
|
|
85117
|
-
const scratch =
|
|
85221
|
+
const scratch = path64.join(worktree, SCRATCH_DIR);
|
|
85118
85222
|
fs32.mkdirSync(scratch, { recursive: true });
|
|
85119
85223
|
return scratch;
|
|
85120
85224
|
}
|
|
@@ -85353,7 +85457,7 @@ function unpushedCount(cwd, branch) {
|
|
|
85353
85457
|
return count.ok ? Number(count.stdout.trim()) : null;
|
|
85354
85458
|
}
|
|
85355
85459
|
function removeScratch(worktree) {
|
|
85356
|
-
const scratch =
|
|
85460
|
+
const scratch = path64.join(worktree, SCRATCH_DIR);
|
|
85357
85461
|
let stat;
|
|
85358
85462
|
try {
|
|
85359
85463
|
stat = fs32.lstatSync(scratch);
|
|
@@ -85369,16 +85473,16 @@ var SLOW, SCRATCH_DIR = ".workit-scratch", EXCLUDE_LINE, DIRTY_ROW_BYTES = 2000,
|
|
|
85369
85473
|
try {
|
|
85370
85474
|
return fs32.realpathSync.native(target);
|
|
85371
85475
|
} catch {
|
|
85372
|
-
return
|
|
85476
|
+
return path64.resolve(target);
|
|
85373
85477
|
}
|
|
85374
85478
|
}, samePath = (a, b) => {
|
|
85375
85479
|
const left = canonical2(a);
|
|
85376
85480
|
const right = canonical2(b);
|
|
85377
85481
|
return process.platform === "win32" || process.platform === "darwin" ? left.toLowerCase() === right.toLowerCase() : left === right;
|
|
85378
85482
|
}, inside3 = (child, parent) => {
|
|
85379
|
-
const relative =
|
|
85380
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
85381
|
-
}, slicePath = (cwd, slice) =>
|
|
85483
|
+
const relative = path64.relative(canonical2(parent), canonical2(child));
|
|
85484
|
+
return relative === "" || !relative.startsWith("..") && !path64.isAbsolute(relative);
|
|
85485
|
+
}, slicePath = (cwd, slice) => path64.isAbsolute(slice.worktree) ? slice.worktree : path64.resolve(mainCheckout(cwd), slice.worktree), CLOCK_SLACK_MS = 2000, worktreeDeps, LOCKFILES2, readBytes = (file) => {
|
|
85382
85486
|
try {
|
|
85383
85487
|
return fs32.readFileSync(file);
|
|
85384
85488
|
} catch {
|
|
@@ -85409,7 +85513,7 @@ var init_fanout_worktree = __esm(() => {
|
|
|
85409
85513
|
|
|
85410
85514
|
// packages/workit-core/src/forge/merge-cleanup.ts
|
|
85411
85515
|
import fs33 from "node:fs";
|
|
85412
|
-
import
|
|
85516
|
+
import path65 from "node:path";
|
|
85413
85517
|
function cleanupMergedBranch(cwd, branch, mergedHead) {
|
|
85414
85518
|
const out = { branchDeleted: false, worktreeRemoved: null, notes: [] };
|
|
85415
85519
|
if (!branch || branch.startsWith("-"))
|
|
@@ -85469,13 +85573,13 @@ var SLOW2, isFanoutWorktree = (worktree) => {
|
|
|
85469
85573
|
if (!dir.ok)
|
|
85470
85574
|
return false;
|
|
85471
85575
|
try {
|
|
85472
|
-
return fs33.readFileSync(
|
|
85576
|
+
return fs33.readFileSync(path65.join(dir.stdout.trim(), FANOUT_TOKEN_FILE), "utf8").trim() !== "";
|
|
85473
85577
|
} catch {
|
|
85474
85578
|
return false;
|
|
85475
85579
|
}
|
|
85476
85580
|
}, inside4 = (child, parent) => {
|
|
85477
|
-
const relative =
|
|
85478
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
85581
|
+
const relative = path65.relative(fs33.realpathSync.native(parent), fs33.realpathSync.native(child));
|
|
85582
|
+
return relative === "" || !relative.startsWith("..") && !path65.isAbsolute(relative);
|
|
85479
85583
|
};
|
|
85480
85584
|
var init_merge_cleanup = __esm(() => {
|
|
85481
85585
|
init_fanout();
|
|
@@ -85756,7 +85860,7 @@ var init_duration = __esm(() => {
|
|
|
85756
85860
|
});
|
|
85757
85861
|
|
|
85758
85862
|
// packages/workit-cli/src/verbs/forge-common.ts
|
|
85759
|
-
import { readFileSync as
|
|
85863
|
+
import { readFileSync as readFileSync25 } from "node:fs";
|
|
85760
85864
|
function parseFlags(argv, spec) {
|
|
85761
85865
|
const parsed = { values: {}, booleans: new Set, lists: {}, positionals: [] };
|
|
85762
85866
|
for (let index = 0;index < argv.length; index += 1) {
|
|
@@ -85911,7 +86015,7 @@ var init_forge_common = __esm(() => {
|
|
|
85911
86015
|
forgeDeps = {
|
|
85912
86016
|
runner: undefined,
|
|
85913
86017
|
npm: undefined,
|
|
85914
|
-
readStdin: () =>
|
|
86018
|
+
readStdin: () => readFileSync25(0, "utf8"),
|
|
85915
86019
|
sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
|
|
85916
86020
|
now: () => Date.now()
|
|
85917
86021
|
};
|
|
@@ -85922,12 +86026,12 @@ var exports_pr = {};
|
|
|
85922
86026
|
__export(exports_pr, {
|
|
85923
86027
|
run: () => run15
|
|
85924
86028
|
});
|
|
85925
|
-
import { readFileSync as
|
|
85926
|
-
import
|
|
86029
|
+
import { readFileSync as readFileSync26 } from "node:fs";
|
|
86030
|
+
import path66 from "node:path";
|
|
85927
86031
|
function readBodyFile(io, file) {
|
|
85928
86032
|
try {
|
|
85929
86033
|
return {
|
|
85930
|
-
body: file === "-" ? forgeDeps.readStdin() :
|
|
86034
|
+
body: file === "-" ? forgeDeps.readStdin() : readFileSync26(path66.resolve(io.cwd, file), "utf8")
|
|
85931
86035
|
};
|
|
85932
86036
|
} catch {
|
|
85933
86037
|
return `cannot read --body-file ${file}`;
|
|
@@ -86256,7 +86360,7 @@ async function merge3(argv, io) {
|
|
|
86256
86360
|
const cleanup = result.data.deletedBranch === true ? cleanupMergedBranch(io.cwd, result.data.branch, result.data.head) : null;
|
|
86257
86361
|
return emit(io, ok2({ ...result.data, localCleanup: cleanup }), (data) => [
|
|
86258
86362
|
`merged ${connected.data.forge.kind === "github" ? "PR #" : "MR !"}${data.number} (${data.method}) at head ${data.head.slice(0, 12)}${data.mergeSha ? ` -> ${data.mergeSha.slice(0, 12)}` : ""}`,
|
|
86259
|
-
data.unverified ? `UNVERIFIED: merged without a verdict (--unverified: ${data.unverified.reason}); ledger ${data.unverified.recorded}` :
|
|
86363
|
+
data.unverified ? `UNVERIFIED: merged without a verdict (--unverified: ${data.unverified.reason}); ledger ${data.unverified.recorded}` : mergedOnLine(data.verdict),
|
|
86260
86364
|
...data.baseCi.note ? [data.baseCi.note] : [],
|
|
86261
86365
|
...data.mergeBack.length ? [
|
|
86262
86366
|
`merge back: ${data.base} is the ${data.mergeBackTrack} production branch; bring it into ${data.mergeBack.join(", ")}`
|
|
@@ -86424,13 +86528,21 @@ async function run15(argv, io) {
|
|
|
86424
86528
|
return reply(rest, io);
|
|
86425
86529
|
return usage4(io, sub && !sub.startsWith("-") ? `unknown pr subcommand "${sub}"` : "missing pr subcommand", USAGE9);
|
|
86426
86530
|
}
|
|
86427
|
-
var STATUS_USAGE = "workit pr status [--pr <n> | --branch <b>] [--log-lines 60] [--json]", CREATE_USAGE = "workit pr create [--base <b> | --track <t>] (--title <t> [--body <text> | --body-file <f|->] | --fill) [--issue <#n|ID|url>]… [--refs] [--label <l>]… [--reviewer <login>]… [--draft] [--json]", MERGE_USAGE = "workit pr merge [--pr <n>] [--squash|--merge|--rebase | --method squash|merge|rebase] [--subject <s>] [--body <b> | --body-file <f|->] [--delete-branch | --keep-branch] [--unverified --reason <why>] [--base-red-ok --reason <why>] [--json]", READY_USAGE = "workit pr ready [--pr <n>] [--undo] [--json]", EDIT_USAGE = "workit pr edit [--pr <n>] [--title <t>] [--body-file <f|->] [--add-label <l>]… [--remove-label <l>]… [--add-reviewer <login>]… [--base <b>] [--json]", THREADS_USAGE = "workit pr threads [--pr <n>] [--json]", REPLY_USAGE = "workit pr reply [--pr <n>] --thread <id> [--body-file <f|->] [--resolve] [--json]", USAGE9 = "workit pr status|create|merge|ready|edit|threads|reply ... (workit help pr)", prLabel = (kind, number) => `${kind === "github" ? "PR #" : "MR !"}${number}`, NEED_TEXT, mergedVerdictLine = (landed) => landed === "untracked" ? "merged outside workit (no merge record)" : landed.unverified ? `merged unverified at ${(landed.head ?? "?").slice(0, 12)} (recorded bypass)` : landed.lane === "none" && !landed.verdictId ? `merged at ${(landed.head ?? "?").slice(0, 12)} with no verdict (lane none)` : landed.review === "self-reviewed" ? `merged self-reviewed (lane self) with the author's verdict ${landed.verdictId ?? "?"} at ${(landed.head ?? "?").slice(0, 12)}` : `merged with accepted verdict ${landed.verdictId ?? "?"} at ${(landed.head ?? "?").slice(0, 12)}${landed.intentOnly ? " (merge intent recorded; the merge call itself failed)" : ""}`,
|
|
86531
|
+
var STATUS_USAGE = "workit pr status [--pr <n> | --branch <b>] [--log-lines 60] [--json]", CREATE_USAGE = "workit pr create [--base <b> | --track <t>] (--title <t> [--body <text> | --body-file <f|->] | --fill) [--issue <#n|ID|url>]… [--refs] [--label <l>]… [--reviewer <login>]… [--draft] [--json]", MERGE_USAGE = "workit pr merge [--pr <n>] [--squash|--merge|--rebase | --method squash|merge|rebase] [--subject <s>] [--body <b> | --body-file <f|->] [--delete-branch | --keep-branch] [--unverified --reason <why>] [--base-red-ok --reason <why>] [--json]", READY_USAGE = "workit pr ready [--pr <n>] [--undo] [--json]", EDIT_USAGE = "workit pr edit [--pr <n>] [--title <t>] [--body-file <f|->] [--add-label <l>]… [--remove-label <l>]… [--add-reviewer <login>]… [--base <b>] [--json]", THREADS_USAGE = "workit pr threads [--pr <n>] [--json]", REPLY_USAGE = "workit pr reply [--pr <n>] --thread <id> [--body-file <f|->] [--resolve] [--json]", USAGE9 = "workit pr status|create|merge|ready|edit|threads|reply ... (workit help pr)", prLabel = (kind, number) => `${kind === "github" ? "PR #" : "MR !"}${number}`, NEED_TEXT, mergedVerdictLine = (landed) => landed === "untracked" ? "merged outside workit (no merge record)" : landed.unverified ? `merged unverified at ${(landed.head ?? "?").slice(0, 12)} (recorded bypass)` : landed.lane === "none" && !landed.verdictId ? `merged at ${(landed.head ?? "?").slice(0, 12)} with no verdict (lane none)` : landed.review === "self-reviewed" ? `merged self-reviewed (lane self) with the author's verdict ${landed.verdictId ?? "?"} at ${(landed.head ?? "?").slice(0, 12)}` : `merged with accepted verdict ${landed.verdictId ?? "?"} at ${(landed.head ?? "?").slice(0, 12)}${landed.intentOnly ? " (merge intent recorded; the merge call itself failed)" : ""}`, mergedOnLine = (verdict) => {
|
|
86532
|
+
if (verdict.review === "self-reviewed")
|
|
86533
|
+
return `self-reviewed (lane ${verdict.lane}): the author's verdict ${verdict.verdictId ?? "?"}; no independent verdict accepted for that head`;
|
|
86534
|
+
if (!verdict.verdictId)
|
|
86535
|
+
return `no verdict required (lane ${verdict.lane})`;
|
|
86536
|
+
if (!verdict.accepted && !verdict.cover && !verdict.carry)
|
|
86537
|
+
return `verdict ${verdict.verdictId} satisfied lane ${verdict.lane}; not an accepted independent verdict for that head`;
|
|
86538
|
+
return `verdict ${verdict.verdictId} accepted for that head${verdict.cover ? ` (stack verdict on ${verdict.cover.branch} @ ${verdict.cover.head.slice(0, 12)})` : verdict.carry ? ` (${carryLabel(verdict.carry)})` : ""}`;
|
|
86539
|
+
}, acceptedHow = (verdict) => verdict.cover ? `stack verdict ${verdict.cover.verdictId} on ${verdict.cover.branch} @ ${verdict.cover.head.slice(0, 12)}` : verdict.carry ? carryLabel(verdict.carry) : verdict.basis, METHODS2;
|
|
86428
86540
|
var init_pr = __esm(() => {
|
|
86429
86541
|
init_autonomy();
|
|
86430
86542
|
init_issue_link();
|
|
86431
86543
|
init_pr_edit();
|
|
86432
86544
|
init_pr_ops();
|
|
86433
|
-
|
|
86545
|
+
init_report2();
|
|
86434
86546
|
init_rev();
|
|
86435
86547
|
init_workspaces();
|
|
86436
86548
|
init_merge_cleanup();
|
|
@@ -86684,7 +86796,7 @@ async function run16(argv, io) {
|
|
|
86684
86796
|
}
|
|
86685
86797
|
var WAIT_USAGE = "workit ci wait [--pr <n> | --branch <b>] [--head <sha>] [--timeout 20m] [--interval 30s] [--json]", RERUN_USAGE = "workit ci rerun [--pr <n> | --branch <b>] [--check <name>… | --failed] --reason flake|infra [--force] [--json]", LOGS_USAGE = "workit ci logs --failed [--pr <n> | --branch <b>] [--json]", LOG_LINES = 60, ONE_POLL_MS = 20000, MAX_POLL_ERRORS = 3, seconds = (ms) => `${Math.round(ms / 1000)}s`;
|
|
86686
86798
|
var init_ci = __esm(() => {
|
|
86687
|
-
|
|
86799
|
+
init_report2();
|
|
86688
86800
|
init_ledger();
|
|
86689
86801
|
init_autonomy();
|
|
86690
86802
|
init_output();
|
|
@@ -86723,8 +86835,8 @@ var exports_git = {};
|
|
|
86723
86835
|
__export(exports_git, {
|
|
86724
86836
|
run: () => run17
|
|
86725
86837
|
});
|
|
86726
|
-
import { readFileSync as
|
|
86727
|
-
import
|
|
86838
|
+
import { readFileSync as readFileSync27 } from "node:fs";
|
|
86839
|
+
import path67 from "node:path";
|
|
86728
86840
|
function kindHint(cwd, kind) {
|
|
86729
86841
|
let kinds = [...BRANCH_KINDS];
|
|
86730
86842
|
try {
|
|
@@ -86828,7 +86940,7 @@ function commitMessage(parsed, io) {
|
|
|
86828
86940
|
|
|
86829
86941
|
`);
|
|
86830
86942
|
try {
|
|
86831
|
-
return file === "-" ?
|
|
86943
|
+
return file === "-" ? readFileSync27(0, "utf8") : readFileSync27(path67.resolve(io.cwd, file), "utf8");
|
|
86832
86944
|
} catch (error) {
|
|
86833
86945
|
return {
|
|
86834
86946
|
error: `cannot read -F ${file}: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -87242,7 +87354,7 @@ var init_verify = __esm(() => {
|
|
|
87242
87354
|
init_exec();
|
|
87243
87355
|
init_rev();
|
|
87244
87356
|
init_ledger();
|
|
87245
|
-
|
|
87357
|
+
init_report2();
|
|
87246
87358
|
init_redact();
|
|
87247
87359
|
NPM_NAME = /^(?:@[A-Za-z0-9~][A-Za-z0-9-._~]*\/)?[A-Za-z0-9~][A-Za-z0-9-._~]*$/u;
|
|
87248
87360
|
SEMVER2 = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/u;
|
|
@@ -88261,15 +88373,15 @@ var init_stack2 = __esm(() => {
|
|
|
88261
88373
|
});
|
|
88262
88374
|
|
|
88263
88375
|
// packages/workit-core/src/fanout-brief.ts
|
|
88264
|
-
import { createHash as
|
|
88376
|
+
import { createHash as createHash20 } from "node:crypto";
|
|
88265
88377
|
import fs35 from "node:fs";
|
|
88266
|
-
import
|
|
88378
|
+
import path68 from "node:path";
|
|
88267
88379
|
function workerSession(lead, slice, attempt) {
|
|
88268
88380
|
const tail = attempt === null ? "" : `+try${attempt}`;
|
|
88269
88381
|
const full = `${lead}-w-${slice}${tail}`;
|
|
88270
88382
|
if (full.length <= SESSION_MAX)
|
|
88271
88383
|
return full;
|
|
88272
|
-
const digest =
|
|
88384
|
+
const digest = createHash20("sha256").update(slice).digest("hex").slice(0, 12);
|
|
88273
88385
|
return `${lead.slice(0, SESSION_MAX - 3 - digest.length - tail.length)}-w-${digest}${tail}`;
|
|
88274
88386
|
}
|
|
88275
88387
|
function renderBrief(cwd, plan, input) {
|
|
@@ -88345,7 +88457,7 @@ function renderBrief(cwd, plan, input) {
|
|
|
88345
88457
|
"STANDING:",
|
|
88346
88458
|
...standing.length ? standing.map((order) => ` - ${order.what}`) : [" - none recorded beyond this brief"],
|
|
88347
88459
|
exists ? `WORKTREE: ${planned} (made by \`workit fanout worktree create ${slice.id}\`; yours alone)` : `WORKTREE: ${planned} (not made yet: the lead runs \`workit fanout worktree create ${slice.id}\` before spawning, then renders this brief again)`,
|
|
88348
|
-
...exists && typeof made?.install === "string" && !fs35.existsSync(
|
|
88460
|
+
...exists && typeof made?.install === "string" && !fs35.existsSync(path68.join(planned, "node_modules")) ? [`INSTALL: \`${made.install}\` first: the main checkout's node_modules was not linked here`] : [],
|
|
88349
88461
|
...identityLines(identity, minted),
|
|
88350
88462
|
...rules(mode, branch, slice.base, exists ? planned : null)
|
|
88351
88463
|
];
|
|
@@ -89075,7 +89187,7 @@ var DEFAULT_STUCK_MS, isoOf = (seconds) => {
|
|
|
89075
89187
|
}, newest = (...values) => values.filter((value) => Boolean(value) && !Number.isNaN(Date.parse(value ?? ""))).reduce((best, value) => best === null || Date.parse(value) > Date.parse(best) ? value : best, null);
|
|
89076
89188
|
var init_fanout_status = __esm(() => {
|
|
89077
89189
|
init_duration();
|
|
89078
|
-
|
|
89190
|
+
init_report2();
|
|
89079
89191
|
init_role_models();
|
|
89080
89192
|
init_ledger();
|
|
89081
89193
|
init_fanout_check();
|
|
@@ -89090,7 +89202,7 @@ __export(exports_fanout, {
|
|
|
89090
89202
|
run: () => run21
|
|
89091
89203
|
});
|
|
89092
89204
|
import fs36 from "node:fs";
|
|
89093
|
-
import
|
|
89205
|
+
import path69 from "node:path";
|
|
89094
89206
|
function forgeFor(io, offline) {
|
|
89095
89207
|
if (offline)
|
|
89096
89208
|
return { forge: null, error: "--offline" };
|
|
@@ -89151,7 +89263,7 @@ function plan2(argv, io) {
|
|
|
89151
89263
|
return usage4(io, "pass --trunk or --track, not both (--track picks the trunk)", PLAN_USAGE2);
|
|
89152
89264
|
if (flags.positionals.length !== 1)
|
|
89153
89265
|
return usage4(io, flags.positionals.length ? `unexpected argument ${flags.positionals[1]}` : "missing <plan.json>", PLAN_USAGE2);
|
|
89154
|
-
const file =
|
|
89266
|
+
const file = path69.resolve(io.cwd, flags.positionals[0]);
|
|
89155
89267
|
let raw;
|
|
89156
89268
|
try {
|
|
89157
89269
|
raw = JSON.parse(fs36.readFileSync(file, "utf8"));
|
|
@@ -89527,6 +89639,8 @@ async function run22(argv, io) {
|
|
|
89527
89639
|
if (rest.length !== 1)
|
|
89528
89640
|
return usage5(io, `ledger verdict takes one result: ${VERDICT_RESULTS.join("|")}`);
|
|
89529
89641
|
const claimed = values.self === true ? null : claimedSession(acting);
|
|
89642
|
+
if (values.self !== true && claimed === null)
|
|
89643
|
+
return emit(io, fail2("blocked", NO_SESSION_ERROR, { unblock: NO_SESSION_UNBLOCK }));
|
|
89530
89644
|
const token = values.token ?? io.env.WORKIT_SESSION_TOKEN ?? null;
|
|
89531
89645
|
const refusal = claimed === null ? null : sessionClaimRefusal(io.env, claimed, io.cwd, { token, flag: acting.source === "flag" });
|
|
89532
89646
|
if (refusal)
|
|
@@ -89641,7 +89755,7 @@ var USAGE15 = "workit ledger decision|ruling|verdict|standing|list|check ... (wo
|
|
|
89641
89755
|
};
|
|
89642
89756
|
}
|
|
89643
89757
|
return { actor, source: "env" };
|
|
89644
|
-
}, claimedSession = (acting) => acting.source === "as" ? acting.derivedFrom ?? null : acting.actor.session, positiveInt2 = (value, flag) => {
|
|
89758
|
+
}, NO_SESSION_ERROR = "no_session: this verdict cannot bind a host session (WORKIT_SESSION_ID is unset or empty and no --session was named), so it would be stored as a self verdict that no gate accepts; nothing was recorded", NO_SESSION_UNBLOCK = "a Claude Code verifier or reviewer passes exactly the `--session <lead>:<agent id> --token=<token>` its SubagentStart hook put in its context; none there means that hook did not bind it (check `workit doctor`: hook_runs lists SubagentStart, hook_issued_sessions passes), so the lead spawns a fresh workit:verifier or workit:reviewer. On Codex, OpenCode and Pi record from the agent's own shell, where the host sets its session. The author records `--self` instead (never accepted as independent)", claimedSession = (acting) => acting.source === "as" ? acting.derivedFrom ?? null : acting.actor.session, positiveInt2 = (value, flag) => {
|
|
89645
89759
|
if (value === undefined)
|
|
89646
89760
|
return;
|
|
89647
89761
|
const parsed = Number(value);
|
|
@@ -104692,7 +104806,7 @@ var init_ast = __esm(() => {
|
|
|
104692
104806
|
|
|
104693
104807
|
// packages/workit-cli/src/test-audit/rules.ts
|
|
104694
104808
|
import { builtinModules } from "node:module";
|
|
104695
|
-
import
|
|
104809
|
+
import path70 from "node:path";
|
|
104696
104810
|
function testCallee(call) {
|
|
104697
104811
|
let callee = call.callee;
|
|
104698
104812
|
if (callee.type === "CallExpression")
|
|
@@ -105185,12 +105299,12 @@ function checkConstantsOnly(ctx, emit) {
|
|
|
105185
105299
|
}
|
|
105186
105300
|
function checkOverMocking(ctx, emit) {
|
|
105187
105301
|
const { program } = ctx.parsed;
|
|
105188
|
-
const unit =
|
|
105302
|
+
const unit = path70.basename(ctx.file).replace(/\.(?:[cm]?[jt]sx?)$/, "").replace(/\.(?:test|spec)$/, "");
|
|
105189
105303
|
const mocked = find2(program, (node) => node.type === "CallExpression" && MODULE_MOCK.test(calleeName(node.callee) ?? "") && node.arguments[0]?.type === "StringLiteral");
|
|
105190
105304
|
const internal = mocked.filter((call) => /^(?:\.|@\/|~\/)/.test(call.arguments[0].value));
|
|
105191
105305
|
for (const call of mocked) {
|
|
105192
105306
|
const spec = call.arguments[0].value;
|
|
105193
|
-
const base =
|
|
105307
|
+
const base = path70.basename(spec.replace(/\/index(?:\.[cm]?[jt]sx?)?$/, "")).replace(/\.(?:[cm]?[jt]sx?)$/, "");
|
|
105194
105308
|
if (base === unit)
|
|
105195
105309
|
emit({
|
|
105196
105310
|
rule: "over-mocking",
|
|
@@ -105579,8 +105693,8 @@ var init_rules = __esm(() => {
|
|
|
105579
105693
|
|
|
105580
105694
|
// packages/workit-cli/src/test-audit/audit.ts
|
|
105581
105695
|
import { spawnSync as spawnSync29 } from "node:child_process";
|
|
105582
|
-
import { existsSync as
|
|
105583
|
-
import
|
|
105696
|
+
import { existsSync as existsSync26, readdirSync as readdirSync14, readFileSync as readFileSync28, statSync as statSync10 } from "node:fs";
|
|
105697
|
+
import path71 from "node:path";
|
|
105584
105698
|
function git7(cwd, args) {
|
|
105585
105699
|
const run = spawnSync29("git", ["-c", "core.quotepath=off", ...args], {
|
|
105586
105700
|
cwd,
|
|
@@ -105593,7 +105707,7 @@ function walkTests(dir, out) {
|
|
|
105593
105707
|
for (const entry of readdirSync14(dir, { withFileTypes: true })) {
|
|
105594
105708
|
if (entry.name.startsWith(".") && entry.name !== "." && entry.isDirectory())
|
|
105595
105709
|
continue;
|
|
105596
|
-
const full =
|
|
105710
|
+
const full = path71.join(dir, entry.name);
|
|
105597
105711
|
if (entry.isDirectory()) {
|
|
105598
105712
|
if (!SKIP_DIRS.has(entry.name))
|
|
105599
105713
|
walkTests(full, out);
|
|
@@ -105605,8 +105719,8 @@ function expandPaths(cwd, inputs) {
|
|
|
105605
105719
|
const files = [];
|
|
105606
105720
|
const missing = [];
|
|
105607
105721
|
for (const input of inputs.length > 0 ? inputs : ["."]) {
|
|
105608
|
-
const full =
|
|
105609
|
-
if (!
|
|
105722
|
+
const full = path71.resolve(cwd, input);
|
|
105723
|
+
if (!existsSync26(full))
|
|
105610
105724
|
missing.push(input);
|
|
105611
105725
|
else if (statSync10(full).isDirectory())
|
|
105612
105726
|
walkTests(full, files);
|
|
@@ -105642,11 +105756,11 @@ function changedLines(cwd, base) {
|
|
|
105642
105756
|
for (let offset = 0;offset < count; offset += 1)
|
|
105643
105757
|
lines.add(start + offset);
|
|
105644
105758
|
}
|
|
105645
|
-
changed.set(
|
|
105759
|
+
changed.set(path71.join(root, file), lines);
|
|
105646
105760
|
}
|
|
105647
105761
|
const untracked = git7(root, ["ls-files", "--others", "--exclude-standard", "-z"]);
|
|
105648
105762
|
for (const file of untracked.stdout.split("\x00").filter(Boolean))
|
|
105649
|
-
changed.set(
|
|
105763
|
+
changed.set(path71.join(root, file), "all");
|
|
105650
105764
|
return changed;
|
|
105651
105765
|
}
|
|
105652
105766
|
function auditFiles(files, display) {
|
|
@@ -105659,7 +105773,7 @@ function auditFiles(files, display) {
|
|
|
105659
105773
|
const shown = display(file);
|
|
105660
105774
|
let parsed;
|
|
105661
105775
|
try {
|
|
105662
|
-
parsed = parseSource(
|
|
105776
|
+
parsed = parseSource(readFileSync28(file, "utf8"), file);
|
|
105663
105777
|
} catch (error) {
|
|
105664
105778
|
parseErrors.push({
|
|
105665
105779
|
file: shown,
|
|
@@ -105708,7 +105822,7 @@ function auditFiles(files, display) {
|
|
|
105708
105822
|
durationMs: Math.round(performance.now() - started)
|
|
105709
105823
|
};
|
|
105710
105824
|
}
|
|
105711
|
-
var TEST_FILE, CODE_FILE, SKIP_DIRS, toPosix = (file) => file.split(
|
|
105825
|
+
var TEST_FILE, CODE_FILE, SKIP_DIRS, toPosix = (file) => file.split(path71.sep).join("/"), SEVERITY_ORDER, ruleIds;
|
|
105712
105826
|
var init_audit = __esm(() => {
|
|
105713
105827
|
init_ast();
|
|
105714
105828
|
init_rules();
|
|
@@ -105722,12 +105836,12 @@ var init_audit = __esm(() => {
|
|
|
105722
105836
|
// packages/workit-cli/src/test-audit/mutate.ts
|
|
105723
105837
|
import { spawn as spawn2 } from "node:child_process";
|
|
105724
105838
|
import {
|
|
105725
|
-
existsSync as
|
|
105839
|
+
existsSync as existsSync27,
|
|
105726
105840
|
lstatSync as lstatSync8,
|
|
105727
105841
|
mkdirSync as mkdirSync12,
|
|
105728
105842
|
mkdtempSync as mkdtempSync4,
|
|
105729
105843
|
readdirSync as readdirSync15,
|
|
105730
|
-
readFileSync as
|
|
105844
|
+
readFileSync as readFileSync29,
|
|
105731
105845
|
readlinkSync as readlinkSync3,
|
|
105732
105846
|
realpathSync as realpathSync10,
|
|
105733
105847
|
renameSync as renameSync7,
|
|
@@ -105737,8 +105851,8 @@ import {
|
|
|
105737
105851
|
writeFileSync as writeFileSync12,
|
|
105738
105852
|
copyFileSync as copyFileSync8
|
|
105739
105853
|
} from "node:fs";
|
|
105740
|
-
import
|
|
105741
|
-
import
|
|
105854
|
+
import os23 from "node:os";
|
|
105855
|
+
import path72 from "node:path";
|
|
105742
105856
|
function mutantsFor(source, file, lines) {
|
|
105743
105857
|
const parsed = parseSource(source, file);
|
|
105744
105858
|
const out = [];
|
|
@@ -105811,7 +105925,7 @@ function relatedTests(source, testFiles) {
|
|
|
105811
105925
|
for (const match of text.matchAll(SPECIFIER)) {
|
|
105812
105926
|
const spec = match[1];
|
|
105813
105927
|
if (spec.startsWith(".")) {
|
|
105814
|
-
if (stripExt(
|
|
105928
|
+
if (stripExt(path72.posix.join(path72.posix.dirname(file), spec)) === target)
|
|
105815
105929
|
return true;
|
|
105816
105930
|
} else if (spec.includes("/") && stripExt(spec).split("/").slice(-2).join("/") === tail)
|
|
105817
105931
|
return true;
|
|
@@ -105819,7 +105933,7 @@ function relatedTests(source, testFiles) {
|
|
|
105819
105933
|
return false;
|
|
105820
105934
|
}).map((entry) => entry.file);
|
|
105821
105935
|
}
|
|
105822
|
-
function removeStaleCopies(tmp =
|
|
105936
|
+
function removeStaleCopies(tmp = os23.tmpdir()) {
|
|
105823
105937
|
let removed = 0;
|
|
105824
105938
|
let names = [];
|
|
105825
105939
|
try {
|
|
@@ -105831,12 +105945,12 @@ function removeStaleCopies(tmp = os22.tmpdir()) {
|
|
|
105831
105945
|
for (const name of names) {
|
|
105832
105946
|
if (!name.startsWith(TEMP_PREFIX))
|
|
105833
105947
|
continue;
|
|
105834
|
-
const dir =
|
|
105948
|
+
const dir = path72.join(tmp, name);
|
|
105835
105949
|
try {
|
|
105836
105950
|
const stat = lstatSync8(dir);
|
|
105837
105951
|
if (!stat.isDirectory() || uid !== undefined && stat.uid !== uid)
|
|
105838
105952
|
continue;
|
|
105839
|
-
const pid = Number(
|
|
105953
|
+
const pid = Number(readFileSync29(path72.join(dir, PID_FILE), "utf8"));
|
|
105840
105954
|
if (Number.isInteger(pid) && pid > 0 && alive(pid))
|
|
105841
105955
|
continue;
|
|
105842
105956
|
} catch (error) {
|
|
@@ -105853,8 +105967,8 @@ function removeStaleCopies(tmp = os22.tmpdir()) {
|
|
|
105853
105967
|
function linkNodeModules(origin, target, repo, copy) {
|
|
105854
105968
|
mkdirSync12(target, { recursive: true });
|
|
105855
105969
|
for (const entry of readdirSync15(origin, { withFileTypes: true })) {
|
|
105856
|
-
const from =
|
|
105857
|
-
const to =
|
|
105970
|
+
const from = path72.join(origin, entry.name);
|
|
105971
|
+
const to = path72.join(target, entry.name);
|
|
105858
105972
|
if (entry.name.startsWith("@") && entry.isDirectory()) {
|
|
105859
105973
|
linkNodeModules(from, to, repo, copy);
|
|
105860
105974
|
continue;
|
|
@@ -105870,9 +105984,9 @@ function linkNodeModules(origin, target, repo, copy) {
|
|
|
105870
105984
|
} catch {
|
|
105871
105985
|
continue;
|
|
105872
105986
|
}
|
|
105873
|
-
const relative =
|
|
105874
|
-
if (!relative.startsWith("..") && !
|
|
105875
|
-
symlinkSync(
|
|
105987
|
+
const relative = path72.relative(repo, real);
|
|
105988
|
+
if (!relative.startsWith("..") && !path72.isAbsolute(relative) && !relative.split(path72.sep).includes("node_modules")) {
|
|
105989
|
+
symlinkSync(path72.join(copy, relative), to, "junction");
|
|
105876
105990
|
continue;
|
|
105877
105991
|
}
|
|
105878
105992
|
}
|
|
@@ -105888,7 +106002,7 @@ function copySymlink(repo, tree, from, to) {
|
|
|
105888
106002
|
}
|
|
105889
106003
|
const realRepo = realpathSync10(repo);
|
|
105890
106004
|
if (real && inside5(realRepo, real)) {
|
|
105891
|
-
symlinkSync(
|
|
106005
|
+
symlinkSync(path72.relative(path72.dirname(to), path72.join(tree, path72.relative(realRepo, real))), to);
|
|
105892
106006
|
return;
|
|
105893
106007
|
}
|
|
105894
106008
|
if (real && statSync11(real).isFile())
|
|
@@ -105897,10 +106011,10 @@ function copySymlink(repo, tree, from, to) {
|
|
|
105897
106011
|
symlinkSync(readlinkSync3(from), to);
|
|
105898
106012
|
}
|
|
105899
106013
|
function writeInside(copy, file, content) {
|
|
105900
|
-
const target =
|
|
106014
|
+
const target = path72.join(copy, file);
|
|
105901
106015
|
try {
|
|
105902
106016
|
const stat = lstatSync8(target);
|
|
105903
|
-
if (!stat.isFile() || !inside5(realpathSync10(copy), realpathSync10(
|
|
106017
|
+
if (!stat.isFile() || !inside5(realpathSync10(copy), realpathSync10(path72.dirname(target))))
|
|
105904
106018
|
return false;
|
|
105905
106019
|
} catch {
|
|
105906
106020
|
return false;
|
|
@@ -105911,9 +106025,9 @@ function writeInside(copy, file, content) {
|
|
|
105911
106025
|
return true;
|
|
105912
106026
|
}
|
|
105913
106027
|
function copyWorkingTree(repo) {
|
|
105914
|
-
const dir = mkdtempSync4(
|
|
105915
|
-
writeFileSync12(
|
|
105916
|
-
const tree =
|
|
106028
|
+
const dir = mkdtempSync4(path72.join(os23.tmpdir(), TEMP_PREFIX));
|
|
106029
|
+
writeFileSync12(path72.join(dir, PID_FILE), String(process.pid));
|
|
106030
|
+
const tree = path72.join(dir, "tree");
|
|
105917
106031
|
const head = git7(repo, ["rev-parse", "--verify", "--quiet", "HEAD"]).stdout.trim();
|
|
105918
106032
|
if (head && git7(dir, ["clone", "-q", "--shared", "--no-checkout", repo, tree]).ok) {
|
|
105919
106033
|
const branch = git7(repo, ["symbolic-ref", "--quiet", "--short", "HEAD"]).stdout.trim();
|
|
@@ -105930,29 +106044,29 @@ function copyWorkingTree(repo) {
|
|
|
105930
106044
|
for (const relative of listed) {
|
|
105931
106045
|
if (!relative)
|
|
105932
106046
|
continue;
|
|
105933
|
-
const from =
|
|
106047
|
+
const from = path72.join(repo, relative);
|
|
105934
106048
|
let stat;
|
|
105935
106049
|
try {
|
|
105936
106050
|
stat = lstatSync8(from);
|
|
105937
106051
|
} catch {
|
|
105938
106052
|
continue;
|
|
105939
106053
|
}
|
|
105940
|
-
const to =
|
|
105941
|
-
mkdirSync12(
|
|
106054
|
+
const to = path72.join(tree, relative);
|
|
106055
|
+
mkdirSync12(path72.dirname(to), { recursive: true });
|
|
105942
106056
|
if (stat.isSymbolicLink())
|
|
105943
106057
|
copySymlink(repo, tree, from, to);
|
|
105944
106058
|
else if (stat.isFile())
|
|
105945
106059
|
copyFileSync8(from, to);
|
|
105946
|
-
let parent =
|
|
106060
|
+
let parent = path72.dirname(relative);
|
|
105947
106061
|
while (parent !== "." && !dirs.has(parent)) {
|
|
105948
106062
|
dirs.add(parent);
|
|
105949
|
-
parent =
|
|
106063
|
+
parent = path72.dirname(parent);
|
|
105950
106064
|
}
|
|
105951
106065
|
}
|
|
105952
106066
|
for (const parent of dirs) {
|
|
105953
|
-
const modules =
|
|
105954
|
-
if (
|
|
105955
|
-
linkNodeModules(modules,
|
|
106067
|
+
const modules = path72.join(repo, parent, "node_modules");
|
|
106068
|
+
if (existsSync27(modules) && !existsSync27(path72.join(tree, parent, "node_modules")))
|
|
106069
|
+
linkNodeModules(modules, path72.join(tree, parent, "node_modules"), repo, tree);
|
|
105956
106070
|
}
|
|
105957
106071
|
return { dir, tree };
|
|
105958
106072
|
}
|
|
@@ -105991,20 +106105,20 @@ async function runMutation(options) {
|
|
|
105991
106105
|
const tracked = git7(repo, ["ls-files", "-co", "--exclude-standard", "-z"]).stdout.split("\x00").filter(Boolean);
|
|
105992
106106
|
const testFiles = tracked.filter((file) => TEST_FILE.test(file)).map((file) => {
|
|
105993
106107
|
try {
|
|
105994
|
-
return { file, text:
|
|
106108
|
+
return { file, text: readFileSync29(path72.join(repo, file), "utf8") };
|
|
105995
106109
|
} catch {
|
|
105996
106110
|
return { file, text: "" };
|
|
105997
106111
|
}
|
|
105998
106112
|
});
|
|
105999
106113
|
const candidates = [];
|
|
106000
106114
|
for (const [absolute, lines] of [...options.changed].toSorted(([a], [b]) => a.localeCompare(b))) {
|
|
106001
|
-
const relative = toPosix(
|
|
106115
|
+
const relative = toPosix(path72.relative(repo, absolute));
|
|
106002
106116
|
if (!CODE_FILE.test(relative) || TEST_FILE.test(relative) || relative.endsWith(".d.ts"))
|
|
106003
106117
|
continue;
|
|
106004
|
-
if (NOT_SOURCE.test(relative) || !
|
|
106118
|
+
if (NOT_SOURCE.test(relative) || !existsSync27(absolute))
|
|
106005
106119
|
continue;
|
|
106006
106120
|
try {
|
|
106007
|
-
candidates.push(...mutantsFor(
|
|
106121
|
+
candidates.push(...mutantsFor(readFileSync29(absolute, "utf8"), relative, lines));
|
|
106008
106122
|
} catch {}
|
|
106009
106123
|
}
|
|
106010
106124
|
const mutants = candidates.map((mutant, index) => ({ ...mutant, id: index + 1 }));
|
|
@@ -106012,9 +106126,9 @@ async function runMutation(options) {
|
|
|
106012
106126
|
for (const mutant of mutants)
|
|
106013
106127
|
if (!related.has(mutant.file))
|
|
106014
106128
|
related.set(mutant.file, relatedTests(mutant.file, testFiles));
|
|
106015
|
-
const cwdRelative =
|
|
106129
|
+
const cwdRelative = path72.relative(repo, options.cwd);
|
|
106016
106130
|
const asArg = (file) => {
|
|
106017
|
-
const relative = toPosix(
|
|
106131
|
+
const relative = toPosix(path72.relative(cwdRelative, file));
|
|
106018
106132
|
return shellQuote(relative.startsWith(".") ? relative : `./${relative}`);
|
|
106019
106133
|
};
|
|
106020
106134
|
const commandFor = (tests) => options.command.replaceAll("{files}", () => tests.map(asArg).join(" "));
|
|
@@ -106050,7 +106164,7 @@ async function runMutation(options) {
|
|
|
106050
106164
|
return finish3(options, 0, results, counts, started);
|
|
106051
106165
|
removeStaleCopies();
|
|
106052
106166
|
const { dir: copyDir, tree: copy } = copyWorkingTree(repo);
|
|
106053
|
-
const copyCwd =
|
|
106167
|
+
const copyCwd = path72.join(copy, cwdRelative);
|
|
106054
106168
|
let current = null;
|
|
106055
106169
|
const restore = () => {
|
|
106056
106170
|
if (current)
|
|
@@ -106085,7 +106199,7 @@ async function runMutation(options) {
|
|
|
106085
106199
|
record({ ...mutant, status: "skipped", durationMs: 0, tests, reason: "budget" });
|
|
106086
106200
|
continue;
|
|
106087
106201
|
}
|
|
106088
|
-
const original =
|
|
106202
|
+
const original = readFileSync29(path72.join(copy, mutant.file), "utf8");
|
|
106089
106203
|
const mutated = original.slice(0, mutant.start) + mutant.replacement + original.slice(mutant.end);
|
|
106090
106204
|
current = { file: mutant.file, original };
|
|
106091
106205
|
if (!writeInside(copy, mutant.file, mutated)) {
|
|
@@ -106142,8 +106256,8 @@ var NOT_SOURCE, FLIPS, isStringy = (node) => node.type === "StringLiteral" || no
|
|
|
106142
106256
|
return error.code === "EPERM";
|
|
106143
106257
|
}
|
|
106144
106258
|
}, inside5 = (root, file) => {
|
|
106145
|
-
const relative =
|
|
106146
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
106259
|
+
const relative = path72.relative(root, file);
|
|
106260
|
+
return relative === "" || !relative.startsWith("..") && !path72.isAbsolute(relative);
|
|
106147
106261
|
}, active, killTree = (child) => {
|
|
106148
106262
|
try {
|
|
106149
106263
|
if (child.pid && process.platform !== "win32")
|
|
@@ -106191,8 +106305,8 @@ var exports_test_audit = {};
|
|
|
106191
106305
|
__export(exports_test_audit, {
|
|
106192
106306
|
run: () => run23
|
|
106193
106307
|
});
|
|
106194
|
-
import { existsSync as
|
|
106195
|
-
import
|
|
106308
|
+
import { existsSync as existsSync28 } from "node:fs";
|
|
106309
|
+
import path73 from "node:path";
|
|
106196
106310
|
function parse8(argv) {
|
|
106197
106311
|
const options = {
|
|
106198
106312
|
paths: [],
|
|
@@ -106297,8 +106411,8 @@ async function run23(argv, io) {
|
|
|
106297
106411
|
return emit(io, fail2("invalid_input", `${options}
|
|
106298
106412
|
usage: ${USAGE16}`));
|
|
106299
106413
|
const top = git7(io.cwd, ["rev-parse", "--show-toplevel"]);
|
|
106300
|
-
const repo = top.ok ?
|
|
106301
|
-
const display = (file) => toPosix(
|
|
106414
|
+
const repo = top.ok ? path73.resolve(top.stdout.trim()) : null;
|
|
106415
|
+
const display = (file) => toPosix(path73.relative(io.cwd, file) || file);
|
|
106302
106416
|
let base = null;
|
|
106303
106417
|
let changed = null;
|
|
106304
106418
|
if (options.diff || options.mutate) {
|
|
@@ -106315,7 +106429,7 @@ usage: ${USAGE16}`));
|
|
|
106315
106429
|
}
|
|
106316
106430
|
let files;
|
|
106317
106431
|
if (options.diff && changed)
|
|
106318
|
-
files = [...changed.keys()].filter((file) => TEST_FILE.test(toPosix(file)) &&
|
|
106432
|
+
files = [...changed.keys()].filter((file) => TEST_FILE.test(toPosix(file)) && existsSync28(file)).toSorted();
|
|
106319
106433
|
else {
|
|
106320
106434
|
const expanded = expandPaths(io.cwd, options.paths);
|
|
106321
106435
|
if (expanded.missing.length > 0)
|
|
@@ -106436,8 +106550,8 @@ var exports_youtrack = {};
|
|
|
106436
106550
|
__export(exports_youtrack, {
|
|
106437
106551
|
run: () => run25
|
|
106438
106552
|
});
|
|
106439
|
-
import { readFileSync as
|
|
106440
|
-
import
|
|
106553
|
+
import { readFileSync as readFileSync30 } from "node:fs";
|
|
106554
|
+
import path74 from "node:path";
|
|
106441
106555
|
async function run25(argv, io) {
|
|
106442
106556
|
const [sub, ...rest] = argv;
|
|
106443
106557
|
if (sub !== "note" && sub !== "time" && sub !== "meeting")
|
|
@@ -106483,7 +106597,7 @@ async function run25(argv, io) {
|
|
|
106483
106597
|
let markdown = flags.values.markdown ?? "";
|
|
106484
106598
|
if (flags.values.file)
|
|
106485
106599
|
try {
|
|
106486
|
-
markdown =
|
|
106600
|
+
markdown = readFileSync30(path74.resolve(io.cwd, flags.values.file), "utf8");
|
|
106487
106601
|
} catch (error) {
|
|
106488
106602
|
return usage4(io, `cannot read ${flags.values.file}: ${String(error)}`, USAGE18);
|
|
106489
106603
|
}
|
|
@@ -106551,8 +106665,8 @@ var exports_changelog = {};
|
|
|
106551
106665
|
__export(exports_changelog, {
|
|
106552
106666
|
run: () => run26
|
|
106553
106667
|
});
|
|
106554
|
-
import { readFileSync as
|
|
106555
|
-
import
|
|
106668
|
+
import { readFileSync as readFileSync31 } from "node:fs";
|
|
106669
|
+
import path75 from "node:path";
|
|
106556
106670
|
async function run26(argv, io) {
|
|
106557
106671
|
const [sub, ...rest] = argv;
|
|
106558
106672
|
if (sub !== "apply")
|
|
@@ -106598,7 +106712,7 @@ async function run26(argv, io) {
|
|
|
106598
106712
|
]);
|
|
106599
106713
|
}
|
|
106600
106714
|
var USAGE19 = "workit changelog apply (--entries <JSON|@file|-> | --normalize-only) [--path CHANGELOG.md] [--preview]", readEntries = (raw, cwd) => {
|
|
106601
|
-
const text = raw === "-" ?
|
|
106715
|
+
const text = raw === "-" ? readFileSync31(0, "utf8") : raw.startsWith("@") ? readFileSync31(path75.resolve(cwd, raw.slice(1)), "utf8") : raw;
|
|
106602
106716
|
return JSON.parse(text);
|
|
106603
106717
|
};
|
|
106604
106718
|
var init_changelog2 = __esm(() => {
|
|
@@ -106614,7 +106728,7 @@ __export(exports_handoff, {
|
|
|
106614
106728
|
run: () => run27
|
|
106615
106729
|
});
|
|
106616
106730
|
import fs37 from "node:fs";
|
|
106617
|
-
import
|
|
106731
|
+
import path76 from "node:path";
|
|
106618
106732
|
import { parseArgs as parseArgs2 } from "node:util";
|
|
106619
106733
|
function render3(brief) {
|
|
106620
106734
|
const lines = [
|
|
@@ -106654,9 +106768,9 @@ function bounded(brief, cwd) {
|
|
|
106654
106768
|
let file = null;
|
|
106655
106769
|
if (store.ok)
|
|
106656
106770
|
try {
|
|
106657
|
-
const dir =
|
|
106771
|
+
const dir = path76.join(store.value.root, "handoff");
|
|
106658
106772
|
fs37.mkdirSync(dir, { recursive: true });
|
|
106659
|
-
file =
|
|
106773
|
+
file = path76.join(dir, `${(brief.branch ?? "detached").replaceAll(/[^\w.-]+/gu, "-")}.txt`);
|
|
106660
106774
|
fs37.writeFileSync(file, `${[...body, ...tail].join(`
|
|
106661
106775
|
`)}
|
|
106662
106776
|
`, {
|
|
@@ -106733,7 +106847,7 @@ var init_handoff = __esm(() => {
|
|
|
106733
106847
|
// packages/workit-cli/src/main.ts
|
|
106734
106848
|
init_host_session();
|
|
106735
106849
|
init_package();
|
|
106736
|
-
import
|
|
106850
|
+
import path77 from "node:path";
|
|
106737
106851
|
|
|
106738
106852
|
// packages/workit-cli/src/verbs/registry.ts
|
|
106739
106853
|
var TASK_FAMILY_NAMES = [
|
|
@@ -107645,7 +107759,7 @@ var defaultIo = (json) => ({
|
|
|
107645
107759
|
});
|
|
107646
107760
|
async function main(argv, overrides = {}, options = {}) {
|
|
107647
107761
|
const parsed = parseGlobals(argv);
|
|
107648
|
-
const cwd =
|
|
107762
|
+
const cwd = path77.resolve(overrides.cwd ?? process.cwd(), parsed.cwd ?? ".");
|
|
107649
107763
|
const io = { ...defaultIo(parsed.json), ...overrides, json: parsed.json, cwd };
|
|
107650
107764
|
if (parsed.error)
|
|
107651
107765
|
return emit(io, fail2("invalid_input", parsed.error));
|