@brainervirus/workit-claude-code 8.32.0 → 8.34.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/dist/workit-hook.js +101 -100
- package/dist/workit.js +806 -523
- package/package.json +3 -3
package/dist/workit.js
CHANGED
|
@@ -9286,7 +9286,7 @@ var package_default;
|
|
|
9286
9286
|
var init_package = __esm(() => {
|
|
9287
9287
|
package_default = {
|
|
9288
9288
|
name: "@brainervirus/workit-cli",
|
|
9289
|
-
version: "8.
|
|
9289
|
+
version: "8.34.0",
|
|
9290
9290
|
private: false,
|
|
9291
9291
|
description: "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
|
|
9292
9292
|
keywords: [
|
|
@@ -9324,13 +9324,13 @@ var init_package = __esm(() => {
|
|
|
9324
9324
|
},
|
|
9325
9325
|
dependencies: {
|
|
9326
9326
|
"@babel/parser": "7.29.9",
|
|
9327
|
-
"@brainervirus/workit-cursor": "^8.
|
|
9327
|
+
"@brainervirus/workit-cursor": "^8.34.0",
|
|
9328
9328
|
"@inkjs/ui": "2.0.0",
|
|
9329
9329
|
ink: "7.1.1",
|
|
9330
9330
|
react: "19.2.8"
|
|
9331
9331
|
},
|
|
9332
9332
|
devDependencies: {
|
|
9333
|
-
"@brainervirus/workit-core": "^8.
|
|
9333
|
+
"@brainervirus/workit-core": "^8.34.0"
|
|
9334
9334
|
},
|
|
9335
9335
|
engines: {
|
|
9336
9336
|
node: ">=24"
|
|
@@ -66607,6 +66607,35 @@ var init_heavy_words = __esm(() => {
|
|
|
66607
66607
|
HEAVY_WORDS = new Set(("npm npx pnpm pnpx yarn bun bunx deno corepack make gmake docker podman nerdctl " + "python python3 py uv poetry pdm pipenv hatch rye bundle rake nx " + "jest vitest mocha ava tap karma jasmine nyc c8 tsc vue-tsc svelte-check eslint stylelint " + "tslint webpack webpack-cli rollup parcel tsup vite next nuxt nuxi astro ng react-scripts " + "playwright cypress wdio testcafe turbo lerna sonar-scanner sonarless sonarless-mcp go " + "golangci-lint gotestsum staticcheck cargo mvn mvnw gradle gradlew ant sbt bazel bazelisk " + "buck2 dotnet msbuild pytest py.test tox nox mypy pyright pylint coverage maturin pip pip3 " + "rspec rails phpunit pest phpstan psalm composer mix swift xcodebuild flutter dart pod cmake " + "ninja meson ctest scons docker-compose buildah earthly").split(" "));
|
|
66608
66608
|
});
|
|
66609
66609
|
|
|
66610
|
+
// packages/workit-core/src/hooks/hook-runs.ts
|
|
66611
|
+
import { mkdirSync as mkdirSync6, readdirSync as readdirSync8, readFileSync as readFileSync15, writeFileSync as writeFileSync7 } from "node:fs";
|
|
66612
|
+
import path37 from "node:path";
|
|
66613
|
+
var HOOK_RUNS_DIR = "hook-runs", readHookRuns = (dir) => {
|
|
66614
|
+
const runs = [];
|
|
66615
|
+
let names = [];
|
|
66616
|
+
try {
|
|
66617
|
+
names = readdirSync8(path37.join(dir, HOOK_RUNS_DIR));
|
|
66618
|
+
} catch {
|
|
66619
|
+
return runs;
|
|
66620
|
+
}
|
|
66621
|
+
for (const name of names) {
|
|
66622
|
+
try {
|
|
66623
|
+
const row = JSON.parse(readFileSync15(path37.join(dir, HOOK_RUNS_DIR, name), "utf8"));
|
|
66624
|
+
if (typeof row.host === "string" && typeof row.event === "string" && typeof row.at === "string" && typeof row.count === "number")
|
|
66625
|
+
runs.push({
|
|
66626
|
+
host: row.host,
|
|
66627
|
+
event: row.event,
|
|
66628
|
+
at: row.at,
|
|
66629
|
+
count: row.count
|
|
66630
|
+
});
|
|
66631
|
+
} catch {}
|
|
66632
|
+
}
|
|
66633
|
+
return runs;
|
|
66634
|
+
};
|
|
66635
|
+
var init_hook_runs = __esm(() => {
|
|
66636
|
+
init_heavy_words();
|
|
66637
|
+
});
|
|
66638
|
+
|
|
66610
66639
|
// packages/workit-core/src/hooks/delivery-verbs.ts
|
|
66611
66640
|
var WORKIT_ALLOWED_VERBS, ALLOWED;
|
|
66612
66641
|
var init_delivery_verbs = __esm(() => {
|
|
@@ -66635,14 +66664,15 @@ var init_delivery_verbs = __esm(() => {
|
|
|
66635
66664
|
import {
|
|
66636
66665
|
copyFileSync as copyFileSync4,
|
|
66637
66666
|
existsSync as existsSync15,
|
|
66638
|
-
|
|
66639
|
-
|
|
66667
|
+
readdirSync as readdirSync9,
|
|
66668
|
+
mkdirSync as mkdirSync7,
|
|
66669
|
+
readFileSync as readFileSync16,
|
|
66640
66670
|
realpathSync as realpathSync7,
|
|
66641
66671
|
rmSync as rmSync3,
|
|
66642
66672
|
statSync as statSync5
|
|
66643
66673
|
} from "node:fs";
|
|
66644
66674
|
import os11 from "node:os";
|
|
66645
|
-
import
|
|
66675
|
+
import path38 from "node:path";
|
|
66646
66676
|
function mergeClaudeSettings(settings, shell, skip = {}) {
|
|
66647
66677
|
const config = clone4(settings);
|
|
66648
66678
|
const owned = emptyOwned();
|
|
@@ -66652,7 +66682,11 @@ function mergeClaudeSettings(settings, shell, skip = {}) {
|
|
|
66652
66682
|
if (shell) {
|
|
66653
66683
|
const env = objectAt(config, ["env"], owned);
|
|
66654
66684
|
if (!env)
|
|
66655
|
-
return {
|
|
66685
|
+
return {
|
|
66686
|
+
config: settings,
|
|
66687
|
+
owned: emptyOwned(),
|
|
66688
|
+
error: "env is not an object"
|
|
66689
|
+
};
|
|
66656
66690
|
if (env.CLAUDE_CODE_SHELL === undefined) {
|
|
66657
66691
|
env.CLAUDE_CODE_SHELL = shell;
|
|
66658
66692
|
owned.env.CLAUDE_CODE_SHELL = shell;
|
|
@@ -66758,7 +66792,7 @@ function planHostPermissions(options) {
|
|
|
66758
66792
|
plan.blocked.push(`${target.file} is not a JSON object; left untouched`);
|
|
66759
66793
|
continue;
|
|
66760
66794
|
}
|
|
66761
|
-
const shellWanted = host === "claude-code" && options.shell !== false &&
|
|
66795
|
+
const shellWanted = host === "claude-code" && options.shell !== false && path38.basename(paths.env.SHELL ?? "") === "zsh";
|
|
66762
66796
|
const bash = shellWanted ? options.bash === undefined ? findBash(paths.env) : options.bash : null;
|
|
66763
66797
|
const merged = host === "claude-code" ? mergeClaudeSettings(parsed, bash, skip) : mergeCursorCliConfig(parsed, skip);
|
|
66764
66798
|
if (merged.error) {
|
|
@@ -66858,11 +66892,11 @@ function applyHostPermissions(plan, options = {}) {
|
|
|
66858
66892
|
try {
|
|
66859
66893
|
const target = change.before === null ? change.file : realpathSync7(change.file);
|
|
66860
66894
|
if (change.before !== null) {
|
|
66861
|
-
const backups =
|
|
66862
|
-
|
|
66863
|
-
copyFileSync4(target,
|
|
66895
|
+
const backups = path38.join(paths.stateDir, "host-permissions-backup");
|
|
66896
|
+
mkdirSync7(backups, { recursive: true, mode: 448 });
|
|
66897
|
+
copyFileSync4(target, path38.join(backups, `${new Date().toISOString().replaceAll(":", "-")}-${change.host}-${path38.basename(change.file)}`));
|
|
66864
66898
|
}
|
|
66865
|
-
|
|
66899
|
+
mkdirSync7(path38.dirname(target), { recursive: true });
|
|
66866
66900
|
writeFileAtomic(target, change.after);
|
|
66867
66901
|
const previous = record.hosts[change.host];
|
|
66868
66902
|
record.hosts[change.host] = {
|
|
@@ -66892,7 +66926,10 @@ function permissionHealth(host, options = {}) {
|
|
|
66892
66926
|
if (host === "codex") {
|
|
66893
66927
|
if (text === null)
|
|
66894
66928
|
return { state: "absent" };
|
|
66895
|
-
return text === codexRulesText() ? { state: "ok" } : {
|
|
66929
|
+
return text === codexRulesText() ? { state: "ok" } : {
|
|
66930
|
+
state: "drift",
|
|
66931
|
+
detail: `${target.file} differs from this Workit version's rules`
|
|
66932
|
+
};
|
|
66896
66933
|
}
|
|
66897
66934
|
if (text === null)
|
|
66898
66935
|
return { state: "absent" };
|
|
@@ -66915,7 +66952,37 @@ function permissionHealth(host, options = {}) {
|
|
|
66915
66952
|
detail: `${target.file} lacks ${missing.length} Workit entr${missing.length === 1 ? "y" : "ies"} (${missing[0]}${missing.length > 1 ? ", …" : ""})`
|
|
66916
66953
|
};
|
|
66917
66954
|
}
|
|
66918
|
-
|
|
66955
|
+
function permissionCoverage(host, commands, options = {}) {
|
|
66956
|
+
const target = permissionTarget(host, options);
|
|
66957
|
+
if (!existsSync15(target.hostDir))
|
|
66958
|
+
return { state: "no-host" };
|
|
66959
|
+
const cwd = options.cwd ?? process.cwd();
|
|
66960
|
+
let missing;
|
|
66961
|
+
if (host === "codex") {
|
|
66962
|
+
const patterns = codexAllowPatterns(path38.dirname(target.file));
|
|
66963
|
+
missing = commands.filter((command) => {
|
|
66964
|
+
const words = command.split(" ");
|
|
66965
|
+
return !patterns.some((p) => p.every((word, i) => words[i] === word));
|
|
66966
|
+
});
|
|
66967
|
+
} else if (host === "cursor") {
|
|
66968
|
+
const rules = [target.file, path38.join(cwd, ".cursor", "cli.json")].flatMap((file) => stringList(valueFrom(readRecord(file), "permissions", "allow")));
|
|
66969
|
+
missing = commands.filter((command) => !rules.some((rule) => cursorRuleMatches(rule, command)));
|
|
66970
|
+
} else {
|
|
66971
|
+
const files = [
|
|
66972
|
+
target.file,
|
|
66973
|
+
path38.join(cwd, ".claude", "settings.json"),
|
|
66974
|
+
path38.join(cwd, ".claude", "settings.local.json")
|
|
66975
|
+
].map(readRecord);
|
|
66976
|
+
const rules = files.flatMap((file) => stringList(valueFrom(file, "permissions", "allow")));
|
|
66977
|
+
missing = commands.filter((command) => !rules.some((rule) => claudeRuleMatches(rule, command)));
|
|
66978
|
+
const delivery = commands.some((command) => !LEASE_COMMANDS.includes(command));
|
|
66979
|
+
const auto = files.flatMap((file) => stringList(valueFrom(file, "autoMode", "allow")));
|
|
66980
|
+
if (delivery && !auto.some((line) => /\bworkit\b/iu.test(line)))
|
|
66981
|
+
missing.push("autoMode.allow line naming workit");
|
|
66982
|
+
}
|
|
66983
|
+
return missing.length === 0 ? { state: "ok" } : { state: "missing", file: target.file, missing };
|
|
66984
|
+
}
|
|
66985
|
+
var PERMISSION_HOSTS, CHECK_NAMES, LOCK_VERBS, LEASE_PREFIXES, CLAUDE_ALLOW, CLAUDE_ASK, AUTO_MODE_ENVIRONMENT = "Org-specific CLIs: workit — the user's delivery CLI. Its push, pr merge, release and PR-thread verbs run only under per-workspace grants and non-author verdicts the user configured in ~/.config/workit, outside the agent's reach.", AUTO_MODE_ALLOW = "Workit-gated delivery: `workit pr merge`, `workit git push --force-with-lease` on the session's own branch, `workit release` and `workit pr reply/resolve` on the session's repo are authorized by the user's standing Workit grants; not Merge Without Review, Git Destructive or External System Writes. Does NOT cover `--unverified`, `--admin` or any bypass flag.", DEFAULTS2 = "$defaults", CURSOR_ALLOW, CODEX_HEADER, codexRulesText = () => {
|
|
66919
66986
|
const rules = [...WORKIT_ALLOWED_VERBS, "--version"].map((verb) => {
|
|
66920
66987
|
const examples = verb === "git" ? `
|
|
66921
66988
|
match = [["workit", "git", "push", "--cwd", "/w"]],
|
|
@@ -67007,30 +67074,34 @@ ${[...rules, ...lease, grant].join(`
|
|
|
67007
67074
|
}, resolvePaths = (options) => {
|
|
67008
67075
|
const env = options.env ?? process.env;
|
|
67009
67076
|
const home = options.home ?? env.HOME ?? os11.homedir();
|
|
67010
|
-
return {
|
|
67077
|
+
return {
|
|
67078
|
+
home,
|
|
67079
|
+
env,
|
|
67080
|
+
stateDir: options.stateDir ?? stateDir({ ...env, HOME: home })
|
|
67081
|
+
};
|
|
67011
67082
|
}, permissionTarget = (host, options = {}) => {
|
|
67012
67083
|
const { home, env } = resolvePaths(options);
|
|
67013
67084
|
if (host === "claude-code") {
|
|
67014
67085
|
const dir = claudeConfigDir(home, env);
|
|
67015
|
-
return { file:
|
|
67086
|
+
return { file: path38.join(dir, "settings.json"), hostDir: dir };
|
|
67016
67087
|
}
|
|
67017
67088
|
if (host === "codex") {
|
|
67018
|
-
const dir = env.CODEX_HOME ||
|
|
67019
|
-
return { file:
|
|
67089
|
+
const dir = env.CODEX_HOME || path38.join(home, ".codex");
|
|
67090
|
+
return { file: path38.join(dir, "rules", "workit.rules"), hostDir: dir };
|
|
67020
67091
|
}
|
|
67021
|
-
const dir =
|
|
67022
|
-
return { file:
|
|
67092
|
+
const dir = path38.join(home, ".cursor");
|
|
67093
|
+
return { file: path38.join(dir, "cli-config.json"), hostDir: dir };
|
|
67023
67094
|
}, AGENT_SESSION_VARS, agentSessionVar = (env) => AGENT_SESSION_VARS.find((name) => (env[name] ?? "") !== "") ?? null, RECORD_FILE = "host-permissions.json", readOwnership = (options = {}) => {
|
|
67024
67095
|
const { stateDir } = resolvePaths(options);
|
|
67025
67096
|
try {
|
|
67026
|
-
const value = JSON.parse(
|
|
67097
|
+
const value = JSON.parse(readFileSync16(path38.join(stateDir, RECORD_FILE), "utf8"));
|
|
67027
67098
|
if (isRecord5(value) && isRecord5(value.hosts))
|
|
67028
67099
|
return { version: 1, hosts: value.hosts };
|
|
67029
67100
|
} catch {}
|
|
67030
67101
|
return { version: 1, hosts: {} };
|
|
67031
67102
|
}, writeOwnership = (record, stateDir) => {
|
|
67032
|
-
|
|
67033
|
-
writeFileAtomic(
|
|
67103
|
+
mkdirSync7(stateDir, { recursive: true });
|
|
67104
|
+
writeFileAtomic(path38.join(stateDir, RECORD_FILE), JSON.stringify(record, null, 2) + `
|
|
67034
67105
|
`, 384);
|
|
67035
67106
|
}, unionLists = (a, b) => {
|
|
67036
67107
|
const lists = { ...a };
|
|
@@ -67052,14 +67123,14 @@ ${[...rules, ...lease, grant].join(`
|
|
|
67052
67123
|
writeOwnership(record, paths.stateDir);
|
|
67053
67124
|
}, readText4 = (file) => {
|
|
67054
67125
|
try {
|
|
67055
|
-
return
|
|
67126
|
+
return readFileSync16(file, "utf8");
|
|
67056
67127
|
} catch {
|
|
67057
67128
|
return null;
|
|
67058
67129
|
}
|
|
67059
67130
|
}, findBash = (env) => {
|
|
67060
|
-
const dirs = ["/usr/bin", "/bin", ...(env.PATH ?? "").split(
|
|
67131
|
+
const dirs = ["/usr/bin", "/bin", ...(env.PATH ?? "").split(path38.delimiter).filter(Boolean)];
|
|
67061
67132
|
for (const dir of dirs) {
|
|
67062
|
-
const candidate =
|
|
67133
|
+
const candidate = path38.join(dir, "bash");
|
|
67063
67134
|
try {
|
|
67064
67135
|
if (statSync5(candidate).isFile())
|
|
67065
67136
|
return candidate;
|
|
@@ -67068,10 +67139,60 @@ ${[...rules, ...lease, grant].join(`
|
|
|
67068
67139
|
return null;
|
|
67069
67140
|
}, setupCommand = (hosts) => `workit setup --hosts=${hosts.join(",")}`, removeCodexRules = (file, options = {}) => {
|
|
67070
67141
|
const expected = permissionTarget("codex", options).file;
|
|
67071
|
-
if (
|
|
67142
|
+
if (path38.resolve(file) !== path38.resolve(expected) || !existsSync15(expected))
|
|
67072
67143
|
return false;
|
|
67073
67144
|
rmSync3(expected);
|
|
67074
67145
|
return true;
|
|
67146
|
+
}, GRANT_COMMANDS, LEASE_COMMANDS, grantedCommands = (kinds) => [
|
|
67147
|
+
...kinds.flatMap((kind) => GRANT_COMMANDS[kind] ?? []),
|
|
67148
|
+
...LEASE_COMMANDS
|
|
67149
|
+
], claudeRuleMatches = (rule, command) => {
|
|
67150
|
+
const body = /^Bash\((.*)\)$/u.exec(rule)?.[1];
|
|
67151
|
+
if (rule === "Bash" || body === "*" || body === "")
|
|
67152
|
+
return true;
|
|
67153
|
+
if (body === undefined)
|
|
67154
|
+
return false;
|
|
67155
|
+
if (body.endsWith(":*") && !body.slice(0, -2).includes("*")) {
|
|
67156
|
+
const prefix = body.slice(0, -2);
|
|
67157
|
+
return command === prefix || command.startsWith(`${prefix} `);
|
|
67158
|
+
}
|
|
67159
|
+
const escaped = body.split("*").map((part) => part.replace(/[.+?^${}()|[\]\\]/gu, "\\$&")).join(".*");
|
|
67160
|
+
const pattern = body.endsWith(" *") ? escaped.replace(/ \.\*$/u, "(?: .*)?") : escaped;
|
|
67161
|
+
return new RegExp(`^${pattern}$`, "u").test(command);
|
|
67162
|
+
}, cursorRuleMatches = (rule, command) => {
|
|
67163
|
+
const full = /^Shell\((.*)\)$/u.exec(rule)?.[1];
|
|
67164
|
+
return full !== undefined && (command === full || command.startsWith(`${full} `));
|
|
67165
|
+
}, stringList = (value) => Array.isArray(value) ? value.filter((entry) => typeof entry === "string") : [], readRecord = (file) => {
|
|
67166
|
+
const text = readText4(file);
|
|
67167
|
+
if (text === null)
|
|
67168
|
+
return null;
|
|
67169
|
+
try {
|
|
67170
|
+
const value = JSON.parse(text);
|
|
67171
|
+
return isRecord5(value) ? value : null;
|
|
67172
|
+
} catch {
|
|
67173
|
+
return null;
|
|
67174
|
+
}
|
|
67175
|
+
}, codexAllowPatterns = (dir) => {
|
|
67176
|
+
const patterns = [];
|
|
67177
|
+
let names = [];
|
|
67178
|
+
try {
|
|
67179
|
+
names = readdirSync9(dir).filter((name) => name.endsWith(".rules"));
|
|
67180
|
+
} catch {
|
|
67181
|
+
return patterns;
|
|
67182
|
+
}
|
|
67183
|
+
for (const name of names)
|
|
67184
|
+
for (const m of (readText4(path38.join(dir, name)) ?? "").matchAll(/pattern\s*=\s*(\[[^\]]*\])\s*,\s*decision\s*=\s*"allow"/gu))
|
|
67185
|
+
try {
|
|
67186
|
+
const words = JSON.parse(m[1]);
|
|
67187
|
+
if (Array.isArray(words))
|
|
67188
|
+
patterns.push(words.map(String));
|
|
67189
|
+
} catch {}
|
|
67190
|
+
return patterns;
|
|
67191
|
+
}, valueFrom = (root, ...keys) => {
|
|
67192
|
+
let node = root;
|
|
67193
|
+
for (const key of keys)
|
|
67194
|
+
node = isRecord5(node) ? node[key] : undefined;
|
|
67195
|
+
return node;
|
|
67075
67196
|
};
|
|
67076
67197
|
var init_host_permissions = __esm(() => {
|
|
67077
67198
|
init_heavy_words();
|
|
@@ -67083,20 +67204,21 @@ var init_host_permissions = __esm(() => {
|
|
|
67083
67204
|
"codex",
|
|
67084
67205
|
"cursor"
|
|
67085
67206
|
]);
|
|
67207
|
+
CHECK_NAMES = ["test", "lint", "typecheck", "build", "format", "docs"];
|
|
67208
|
+
LOCK_VERBS = ["status", "wait"];
|
|
67209
|
+
LEASE_PREFIXES = [
|
|
67210
|
+
...CHECK_NAMES.map((name) => ["check", name]),
|
|
67211
|
+
...LOCK_VERBS.map((verb) => ["lock", verb])
|
|
67212
|
+
];
|
|
67086
67213
|
CLAUDE_ALLOW = [
|
|
67087
67214
|
...WORKIT_ALLOWED_VERBS.map((verb) => `Bash(workit ${verb} *)`),
|
|
67215
|
+
...LEASE_PREFIXES.map((rest) => `Bash(workit ${rest.join(" ")} *)`),
|
|
67088
67216
|
"Bash(workit --version)"
|
|
67089
67217
|
];
|
|
67090
67218
|
CLAUDE_ASK = [
|
|
67091
67219
|
"Bash(workit * --unverified*)",
|
|
67092
67220
|
"Bash(workit * --overwrite-unintegrated*)"
|
|
67093
67221
|
];
|
|
67094
|
-
CHECK_NAMES = ["test", "lint", "typecheck", "build", "format", "docs"];
|
|
67095
|
-
LOCK_VERBS = ["status", "wait"];
|
|
67096
|
-
LEASE_PREFIXES = [
|
|
67097
|
-
...CHECK_NAMES.map((name) => ["check", name]),
|
|
67098
|
-
...LOCK_VERBS.map((verb) => ["lock", verb])
|
|
67099
|
-
];
|
|
67100
67222
|
CURSOR_ALLOW = [
|
|
67101
67223
|
...WORKIT_ALLOWED_VERBS.map((verb) => `Shell(workit ${verb})`),
|
|
67102
67224
|
...LEASE_PREFIXES.map((rest) => `Shell(workit ${rest.join(" ")})`),
|
|
@@ -67115,7 +67237,11 @@ var init_host_permissions = __esm(() => {
|
|
|
67115
67237
|
created: [],
|
|
67116
67238
|
env: {}
|
|
67117
67239
|
},
|
|
67118
|
-
cursor: {
|
|
67240
|
+
cursor: {
|
|
67241
|
+
lists: { "permissions.allow": [...CURSOR_ALLOW] },
|
|
67242
|
+
created: [],
|
|
67243
|
+
env: {}
|
|
67244
|
+
}
|
|
67119
67245
|
};
|
|
67120
67246
|
PRIOR_ENTRIES = {
|
|
67121
67247
|
"claude-code": {},
|
|
@@ -67142,6 +67268,12 @@ var init_host_permissions = __esm(() => {
|
|
|
67142
67268
|
"PI_SESSION_ID",
|
|
67143
67269
|
"CURSOR_AGENT"
|
|
67144
67270
|
];
|
|
67271
|
+
GRANT_COMMANDS = {
|
|
67272
|
+
push: ["workit git push"],
|
|
67273
|
+
pr: ["workit pr create"],
|
|
67274
|
+
merge: ["workit pr merge"]
|
|
67275
|
+
};
|
|
67276
|
+
LEASE_COMMANDS = LEASE_PREFIXES.map((rest) => `workit ${rest.join(" ")}`);
|
|
67145
67277
|
});
|
|
67146
67278
|
|
|
67147
67279
|
// packages/workit-cli/src/admin/doctor.ts
|
|
@@ -67150,31 +67282,34 @@ import { createHash as createHash14 } from "node:crypto";
|
|
|
67150
67282
|
import {
|
|
67151
67283
|
existsSync as existsSync16,
|
|
67152
67284
|
lstatSync as lstatSync5,
|
|
67153
|
-
mkdirSync as
|
|
67285
|
+
mkdirSync as mkdirSync8,
|
|
67154
67286
|
mkdtempSync,
|
|
67155
|
-
readdirSync as
|
|
67156
|
-
readFileSync as
|
|
67287
|
+
readdirSync as readdirSync10,
|
|
67288
|
+
readFileSync as readFileSync17,
|
|
67157
67289
|
readlinkSync as readlinkSync2,
|
|
67158
67290
|
renameSync as renameSync4,
|
|
67159
67291
|
rmSync as rmSync4,
|
|
67160
67292
|
statSync as statSync6,
|
|
67161
67293
|
unlinkSync as unlinkSync3,
|
|
67162
|
-
writeFileSync as
|
|
67294
|
+
writeFileSync as writeFileSync8
|
|
67163
67295
|
} from "node:fs";
|
|
67164
67296
|
import os12 from "node:os";
|
|
67165
|
-
import
|
|
67297
|
+
import path39 from "node:path";
|
|
67166
67298
|
var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
67167
|
-
let dir =
|
|
67299
|
+
let dir = path39.resolve(cwd);
|
|
67168
67300
|
while (true) {
|
|
67169
|
-
if (existsSync16(
|
|
67301
|
+
if (existsSync16(path39.join(dir, "packages", "workit-core", "package.json")))
|
|
67170
67302
|
return dir;
|
|
67171
|
-
const parent =
|
|
67303
|
+
const parent = path39.dirname(dir);
|
|
67172
67304
|
if (parent === dir)
|
|
67173
67305
|
return null;
|
|
67174
67306
|
dir = parent;
|
|
67175
67307
|
}
|
|
67176
67308
|
}, listClaudeProcesses = () => {
|
|
67177
|
-
const r = spawnSync16("ps", ["-eo", "pid=,lstart=,args="], {
|
|
67309
|
+
const r = spawnSync16("ps", ["-eo", "pid=,lstart=,args="], {
|
|
67310
|
+
encoding: "utf8",
|
|
67311
|
+
timeout: 5000
|
|
67312
|
+
});
|
|
67178
67313
|
if (r.status !== 0 || typeof r.stdout !== "string")
|
|
67179
67314
|
return null;
|
|
67180
67315
|
const found = [];
|
|
@@ -67191,8 +67326,8 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67191
67326
|
}, resolve = (options) => {
|
|
67192
67327
|
const env = options.env ?? process.env;
|
|
67193
67328
|
const home = options.home ?? env.HOME ?? os12.homedir();
|
|
67194
|
-
const configDir = options.configDir ?? env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ??
|
|
67195
|
-
const stateDir = options.stateDir ?? env.WORKFLOW_TOOLKIT_STATE ??
|
|
67329
|
+
const configDir = options.configDir ?? env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path39.join(home, ".config", "workit");
|
|
67330
|
+
const stateDir = options.stateDir ?? env.WORKFLOW_TOOLKIT_STATE ?? path39.join(home, ".local", "state", "workit");
|
|
67196
67331
|
const cwd = options.cwd ?? process.cwd();
|
|
67197
67332
|
const dev = options.dev?.trim() || env.WORKFLOW_TOOLKIT_DEV?.trim() || findDevFromCwd(cwd);
|
|
67198
67333
|
return {
|
|
@@ -67203,11 +67338,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67203
67338
|
cwd,
|
|
67204
67339
|
workspaceRoot: options.workspaceRoot ?? env.WORKFLOW_WORKSPACE_ROOT ?? cwd,
|
|
67205
67340
|
dev,
|
|
67206
|
-
opencodeConfig: options.opencodeConfig ??
|
|
67341
|
+
opencodeConfig: options.opencodeConfig ?? path39.join(home, ".config", "opencode", "opencode.json"),
|
|
67207
67342
|
opencodePackageCacheDir: options.opencodePackageCacheDir ?? null,
|
|
67208
|
-
cursorSettings: options.cursorSettings ??
|
|
67209
|
-
cursorMcp: options.cursorMcp ??
|
|
67210
|
-
cursorPluginDir: options.cursorPluginDir ??
|
|
67343
|
+
cursorSettings: options.cursorSettings ?? path39.join(home, ".cursor", "settings.json"),
|
|
67344
|
+
cursorMcp: options.cursorMcp ?? path39.join(home, ".cursor", "mcp.json"),
|
|
67345
|
+
cursorPluginDir: options.cursorPluginDir ?? path39.join(home, ".cursor", "plugins", "local", "workit"),
|
|
67211
67346
|
cursorHeartbeatDir: options.stateDir ?? (env.WORKFLOW_TOOLKIT_STATE || resolveStateDir()),
|
|
67212
67347
|
hookStateDir: options.stateDir ?? (env.WORKFLOW_TOOLKIT_STATE || resolveStateDir()),
|
|
67213
67348
|
codexHome: options.codexHome,
|
|
@@ -67220,14 +67355,14 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67220
67355
|
};
|
|
67221
67356
|
}, readJson = (p) => {
|
|
67222
67357
|
try {
|
|
67223
|
-
const parsed = JSON.parse(
|
|
67358
|
+
const parsed = JSON.parse(readFileSync17(p, "utf8"));
|
|
67224
67359
|
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
67225
67360
|
} catch {
|
|
67226
67361
|
return null;
|
|
67227
67362
|
}
|
|
67228
67363
|
}, parsesAsConfigObject = (p) => {
|
|
67229
67364
|
try {
|
|
67230
|
-
return isConfigObject(JSON.parse(
|
|
67365
|
+
return isConfigObject(JSON.parse(readFileSync17(p, "utf8")));
|
|
67231
67366
|
} catch {
|
|
67232
67367
|
return false;
|
|
67233
67368
|
}
|
|
@@ -67237,12 +67372,12 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67237
67372
|
...new Set(entries.filter((entry) => typeof entry === "string" && isWorkitPlugin(entry)))
|
|
67238
67373
|
];
|
|
67239
67374
|
}, commandOnPath = (name, env) => findOnPath(process.platform === "win32" ? [name, `${name}.exe`] : [name], env) !== null, pathextNames = (name, env) => process.platform === "win32" ? (env.PATHEXT ?? process.env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").filter(Boolean).map((ext) => `${name}${ext.toLowerCase()}`) : [name], findOnPath = (names, env) => {
|
|
67240
|
-
const dirs = (env.PATH ?? process.env.PATH ?? "").split(
|
|
67375
|
+
const dirs = (env.PATH ?? process.env.PATH ?? "").split(path39.delimiter);
|
|
67241
67376
|
for (const dir of dirs) {
|
|
67242
67377
|
if (!dir)
|
|
67243
67378
|
continue;
|
|
67244
67379
|
for (const candidateName of names) {
|
|
67245
|
-
const candidate =
|
|
67380
|
+
const candidate = path39.join(dir, candidateName);
|
|
67246
67381
|
try {
|
|
67247
67382
|
const st = statSync6(candidate);
|
|
67248
67383
|
if (process.platform !== "win32" && (st.mode & 73) === 0)
|
|
@@ -67271,7 +67406,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67271
67406
|
if (env.BUN && existsSync16(env.BUN))
|
|
67272
67407
|
return env.BUN;
|
|
67273
67408
|
for (const candidate of [
|
|
67274
|
-
|
|
67409
|
+
path39.join(env.HOME || os12.homedir(), ".bun/bin/bun"),
|
|
67275
67410
|
"/usr/local/bin/bun",
|
|
67276
67411
|
"/usr/bin/bun"
|
|
67277
67412
|
]) {
|
|
@@ -67326,7 +67461,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67326
67461
|
detail: "installed package, not a dev checkout — version parity applies to checkouts only"
|
|
67327
67462
|
};
|
|
67328
67463
|
}
|
|
67329
|
-
const corePkg = readJson(
|
|
67464
|
+
const corePkg = readJson(path39.join(res.dev, "packages/workit-core/package.json"));
|
|
67330
67465
|
if (!corePkg) {
|
|
67331
67466
|
return {
|
|
67332
67467
|
id: "versions",
|
|
@@ -67336,7 +67471,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67336
67471
|
}
|
|
67337
67472
|
const refs = new Set;
|
|
67338
67473
|
for (const name of ["workit-opencode", "workit-cursor", "workit-cli"]) {
|
|
67339
|
-
const pkg = readJson(
|
|
67474
|
+
const pkg = readJson(path39.join(res.dev, "packages", name, "package.json"));
|
|
67340
67475
|
const dep = pkg?.dependencies?.["@brainervirus/workit-core"] ?? pkg?.devDependencies?.["@brainervirus/workit-core"];
|
|
67341
67476
|
if (typeof dep === "string")
|
|
67342
67477
|
refs.add(dep);
|
|
@@ -67352,7 +67487,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67352
67487
|
if (refs.size > 1) {
|
|
67353
67488
|
problems.push(`adapters pin different core versions: ${[...refs].join(", ")}`);
|
|
67354
67489
|
}
|
|
67355
|
-
const opencodePkg = readJson(
|
|
67490
|
+
const opencodePkg = readJson(path39.join(res.dev, "packages/workit-opencode/package.json"));
|
|
67356
67491
|
const sdk = opencodePkg?.dependencies?.["@opencode/plugin"] ?? opencodePkg?.devDependencies?.["@opencode/plugin"];
|
|
67357
67492
|
const sdkVersion = typeof sdk === "string" ? (sdk.match(/^\d+(?:\.\d+){0,2}/) ?? [])[0] : null;
|
|
67358
67493
|
if (sdkVersion && !semverAtLeast(sdkVersion, SUPPORT_MATRIX.opencode.minimum)) {
|
|
@@ -67379,14 +67514,14 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67379
67514
|
status: "pass",
|
|
67380
67515
|
detail: "opencode CLI not on PATH — skipping version check"
|
|
67381
67516
|
};
|
|
67382
|
-
const scratch = mkdtempSync(
|
|
67517
|
+
const scratch = mkdtempSync(path39.join(os12.tmpdir(), "workit-doctor-opencode-"));
|
|
67383
67518
|
let raw;
|
|
67384
67519
|
try {
|
|
67385
67520
|
raw = versionOf("opencode", {
|
|
67386
67521
|
...res.env,
|
|
67387
|
-
XDG_DATA_HOME:
|
|
67388
|
-
XDG_STATE_HOME:
|
|
67389
|
-
XDG_CACHE_HOME:
|
|
67522
|
+
XDG_DATA_HOME: path39.join(scratch, "data"),
|
|
67523
|
+
XDG_STATE_HOME: path39.join(scratch, "state"),
|
|
67524
|
+
XDG_CACHE_HOME: path39.join(scratch, "cache")
|
|
67390
67525
|
}, 5000);
|
|
67391
67526
|
} finally {
|
|
67392
67527
|
rmSync4(scratch, { recursive: true, force: true });
|
|
@@ -67450,7 +67585,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67450
67585
|
const tables = new Map;
|
|
67451
67586
|
let text;
|
|
67452
67587
|
try {
|
|
67453
|
-
text =
|
|
67588
|
+
text = readFileSync17(file, "utf8");
|
|
67454
67589
|
} catch {
|
|
67455
67590
|
return tables;
|
|
67456
67591
|
}
|
|
@@ -67488,19 +67623,19 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67488
67623
|
current[unquote(pair[1])] = value === "true" ? true : value === "false" ? false : unquote(value);
|
|
67489
67624
|
}
|
|
67490
67625
|
return tables;
|
|
67491
|
-
}, codexHomeOf = (res) => res.codexHome ?? (res.env.CODEX_HOME ||
|
|
67626
|
+
}, codexHomeOf = (res) => res.codexHome ?? (res.env.CODEX_HOME || path39.join(res.home, ".codex")), codexWorkitInstalls = (res) => {
|
|
67492
67627
|
const codexHome = codexHomeOf(res);
|
|
67493
|
-
const configFile =
|
|
67628
|
+
const configFile = path39.join(codexHome, "config.toml");
|
|
67494
67629
|
const installs = [];
|
|
67495
67630
|
for (const [key, table] of readTomlTables(configFile)) {
|
|
67496
67631
|
const [kind, id, ...rest] = key.split("\x00");
|
|
67497
67632
|
if (kind !== "plugins" || rest.length > 0 || !id?.startsWith("workit@") || table.enabled === false)
|
|
67498
67633
|
continue;
|
|
67499
67634
|
const marketplace = id.slice("workit@".length);
|
|
67500
|
-
const dir =
|
|
67635
|
+
const dir = path39.join(codexHome, "plugins", "cache", marketplace, "workit");
|
|
67501
67636
|
let versions = [];
|
|
67502
67637
|
try {
|
|
67503
|
-
versions =
|
|
67638
|
+
versions = readdirSync10(dir).filter((v) => existsSync16(path39.join(dir, v, ".codex-plugin")));
|
|
67504
67639
|
} catch {
|
|
67505
67640
|
versions = [];
|
|
67506
67641
|
}
|
|
@@ -67508,7 +67643,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67508
67643
|
installs.push({
|
|
67509
67644
|
id,
|
|
67510
67645
|
marketplace,
|
|
67511
|
-
root: version ?
|
|
67646
|
+
root: version ? path39.join(dir, version) : null,
|
|
67512
67647
|
version,
|
|
67513
67648
|
configFile
|
|
67514
67649
|
});
|
|
@@ -67530,7 +67665,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67530
67665
|
};
|
|
67531
67666
|
return `sha256:${createHash14("sha256").update(JSON.stringify(body)).digest("hex")}`;
|
|
67532
67667
|
}, codexHookTrust = (install, tables) => {
|
|
67533
|
-
const hooks = install.root ? readJson(
|
|
67668
|
+
const hooks = install.root ? readJson(path39.join(install.root, "hooks", "hooks.json"))?.hooks : null;
|
|
67534
67669
|
if (!hooks || typeof hooks !== "object")
|
|
67535
67670
|
return null;
|
|
67536
67671
|
const result = [];
|
|
@@ -67603,25 +67738,25 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67603
67738
|
status: "pass",
|
|
67604
67739
|
detail: "no Workit Codex plugin enabled — skipping"
|
|
67605
67740
|
};
|
|
67606
|
-
const agentsDir =
|
|
67741
|
+
const agentsDir = path39.join(codexHomeOf(res), "agents");
|
|
67607
67742
|
const problems = [];
|
|
67608
67743
|
const fixes = [];
|
|
67609
67744
|
const installed = [];
|
|
67610
67745
|
for (const install of installs) {
|
|
67611
|
-
const source = install.root ?
|
|
67612
|
-
const files = source && existsSync16(source) ?
|
|
67746
|
+
const source = install.root ? path39.join(install.root, "agents") : null;
|
|
67747
|
+
const files = source && existsSync16(source) ? readdirSync10(source).filter((f) => f.endsWith(".toml")).toSorted() : [];
|
|
67613
67748
|
if (files.length === 0) {
|
|
67614
67749
|
problems.push(`${install.id} ${install.version ?? "?"} bundles no agents`);
|
|
67615
67750
|
fixes.push(`codex plugin remove ${install.id} && codex plugin add ${install.id}`);
|
|
67616
67751
|
continue;
|
|
67617
67752
|
}
|
|
67618
|
-
const install_fix = `node ${JSON.stringify(
|
|
67619
|
-
const pluginVersion = readJson(
|
|
67753
|
+
const install_fix = `node ${JSON.stringify(path39.join(install.root, "dist", "launch-mcp.js"))} --install-agents, then start a new Codex session`;
|
|
67754
|
+
const pluginVersion = readJson(path39.join(install.root, "package.json"))?.version;
|
|
67620
67755
|
const version = typeof pluginVersion === "string" ? pluginVersion.match(SEMVER)?.[0] ?? null : null;
|
|
67621
67756
|
let stale = false;
|
|
67622
67757
|
for (const file of files) {
|
|
67623
|
-
const dest =
|
|
67624
|
-
const want = stampCodexAgent(
|
|
67758
|
+
const dest = path39.join(agentsDir, file);
|
|
67759
|
+
const want = stampCodexAgent(readFileSync17(path39.join(source, file), "utf8"), version);
|
|
67625
67760
|
let link = false;
|
|
67626
67761
|
try {
|
|
67627
67762
|
link = lstatSync5(dest).isSymbolicLink();
|
|
@@ -67635,7 +67770,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67635
67770
|
}
|
|
67636
67771
|
let have = null;
|
|
67637
67772
|
try {
|
|
67638
|
-
have =
|
|
67773
|
+
have = readFileSync17(dest, "utf8");
|
|
67639
67774
|
} catch {
|
|
67640
67775
|
have = null;
|
|
67641
67776
|
}
|
|
@@ -67674,7 +67809,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67674
67809
|
const env = res.env.PI_CODING_AGENT_DIR;
|
|
67675
67810
|
if (env)
|
|
67676
67811
|
return env === "~" ? res.home : env.replace(/^~(?=\/|\\)/, res.home);
|
|
67677
|
-
return
|
|
67812
|
+
return path39.join(res.home, ".pi", "agent");
|
|
67678
67813
|
}, npmSpecName = (spec) => {
|
|
67679
67814
|
const at = spec.indexOf("@", spec.startsWith("@") ? 1 : 0);
|
|
67680
67815
|
return at > 0 ? { name: spec.slice(0, at), pinned: true } : { name: spec, pinned: false };
|
|
@@ -67682,10 +67817,14 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67682
67817
|
const scopes = [
|
|
67683
67818
|
{
|
|
67684
67819
|
scope: "project",
|
|
67685
|
-
settingsFile:
|
|
67686
|
-
base:
|
|
67820
|
+
settingsFile: path39.join(res.cwd, ".pi", "settings.json"),
|
|
67821
|
+
base: path39.join(res.cwd, ".pi")
|
|
67687
67822
|
},
|
|
67688
|
-
{
|
|
67823
|
+
{
|
|
67824
|
+
scope: "user",
|
|
67825
|
+
settingsFile: path39.join(agentDir, "settings.json"),
|
|
67826
|
+
base: agentDir
|
|
67827
|
+
}
|
|
67689
67828
|
];
|
|
67690
67829
|
for (const { scope, settingsFile, base } of scopes) {
|
|
67691
67830
|
const packages = readJson(settingsFile)?.packages;
|
|
@@ -67700,13 +67839,20 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67700
67839
|
const spec = npmSpecName(source.slice(4).trim());
|
|
67701
67840
|
if (spec.name !== PI_PACKAGE)
|
|
67702
67841
|
continue;
|
|
67703
|
-
const root =
|
|
67704
|
-
return {
|
|
67842
|
+
const root = path39.join(base, "npm", "node_modules", ...PI_PACKAGE.split("/"));
|
|
67843
|
+
return {
|
|
67844
|
+
scope,
|
|
67845
|
+
settingsFile,
|
|
67846
|
+
source,
|
|
67847
|
+
filter,
|
|
67848
|
+
root,
|
|
67849
|
+
npm: { pinned: spec.pinned }
|
|
67850
|
+
};
|
|
67705
67851
|
}
|
|
67706
67852
|
if (/^(git:|https?:|ssh:|git@)/.test(source))
|
|
67707
67853
|
continue;
|
|
67708
|
-
const local =
|
|
67709
|
-
if (readJson(
|
|
67854
|
+
const local = path39.resolve(base, source.replace(/^~(?=\/|\\)/, res.home));
|
|
67855
|
+
if (readJson(path39.join(local, "package.json"))?.name === PI_PACKAGE)
|
|
67710
67856
|
return { scope, settingsFile, source, filter, root: local, npm: null };
|
|
67711
67857
|
}
|
|
67712
67858
|
}
|
|
@@ -67717,7 +67863,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67717
67863
|
const list = patterns.filter((p) => typeof p === "string");
|
|
67718
67864
|
if (list.length === 0)
|
|
67719
67865
|
return false;
|
|
67720
|
-
const name =
|
|
67866
|
+
const name = path39.posix.basename(file);
|
|
67721
67867
|
const matches = (p) => {
|
|
67722
67868
|
const re = globToRegExp3(p);
|
|
67723
67869
|
return re.test(file) || re.test(name);
|
|
@@ -67735,19 +67881,23 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67735
67881
|
}, checkPiExtension = (res) => {
|
|
67736
67882
|
const agentDir = piAgentDirOf(res);
|
|
67737
67883
|
if (!existsSync16(agentDir) && !commandOnPath("pi", res.env))
|
|
67738
|
-
return {
|
|
67884
|
+
return {
|
|
67885
|
+
id: "pi_extension",
|
|
67886
|
+
status: "pass",
|
|
67887
|
+
detail: "Pi not installed — skipping"
|
|
67888
|
+
};
|
|
67739
67889
|
const installCmd = (scope, spec = `npm:${PI_PACKAGE}`) => `pi install ${spec}${scope === "project" ? " -l" : ""}`;
|
|
67740
67890
|
const entry = findPiEntry(res, agentDir);
|
|
67741
67891
|
if (!entry)
|
|
67742
67892
|
return {
|
|
67743
67893
|
id: "pi_extension",
|
|
67744
67894
|
status: "warn",
|
|
67745
|
-
detail: `Workit Pi extension missing: no ${PI_PACKAGE} entry in ${
|
|
67895
|
+
detail: `Workit Pi extension missing: no ${PI_PACKAGE} entry in ${path39.join(agentDir, "settings.json")} or ${path39.join(res.cwd, ".pi", "settings.json")}`,
|
|
67746
67896
|
fix: installCmd("user")
|
|
67747
67897
|
};
|
|
67748
67898
|
const where = `${entry.source} (${entry.scope}, ${entry.settingsFile})`;
|
|
67749
67899
|
const rebuild = `cd ${JSON.stringify(entry.root)} && bun run build`;
|
|
67750
|
-
const pkg = readJson(
|
|
67900
|
+
const pkg = readJson(path39.join(entry.root, "package.json"));
|
|
67751
67901
|
if (!pkg)
|
|
67752
67902
|
return {
|
|
67753
67903
|
id: "pi_extension",
|
|
@@ -67756,7 +67906,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67756
67906
|
fix: entry.npm ? installCmd(entry.scope, entry.source) : `restore ${entry.root}, then ${rebuild}`
|
|
67757
67907
|
};
|
|
67758
67908
|
const declared = Array.isArray(pkg.pi?.extensions) ? pkg.pi.extensions.some((e) => typeof e === "string" && e.replace(/^\.\//, "") === PI_EXTENSION) : false;
|
|
67759
|
-
if (!declared || !existsSync16(
|
|
67909
|
+
if (!declared || !existsSync16(path39.join(entry.root, PI_EXTENSION)))
|
|
67760
67910
|
return {
|
|
67761
67911
|
id: "pi_extension",
|
|
67762
67912
|
status: "warn",
|
|
@@ -67809,21 +67959,21 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67809
67959
|
detail: `Workit Pi extension ${version ?? "?"} from ${where} loads ${PI_EXTENSION}`
|
|
67810
67960
|
};
|
|
67811
67961
|
}, assetPathsFor = (host, dev) => {
|
|
67812
|
-
const pkg =
|
|
67962
|
+
const pkg = path39.join(dev, "packages", `workit-${host}`);
|
|
67813
67963
|
switch (host) {
|
|
67814
67964
|
case "opencode": {
|
|
67815
|
-
const packaged =
|
|
67816
|
-
const root = existsSync16(packaged) ? packaged :
|
|
67817
|
-
return WORKIT_METHOD_SKILLS.map((skill) =>
|
|
67965
|
+
const packaged = path39.join(pkg, "assets", "skills");
|
|
67966
|
+
const root = existsSync16(packaged) ? packaged : path39.join(dev, "packages", "workit-core", "skills");
|
|
67967
|
+
return WORKIT_METHOD_SKILLS.map((skill) => path39.join(root, skill, "SKILL.md"));
|
|
67818
67968
|
}
|
|
67819
67969
|
case "cursor":
|
|
67820
67970
|
return [
|
|
67821
|
-
|
|
67822
|
-
|
|
67823
|
-
|
|
67971
|
+
path39.join(pkg, "assets", "templates", "workit-contract.md"),
|
|
67972
|
+
path39.join(pkg, "mcp.json"),
|
|
67973
|
+
path39.join(pkg, ".cursor-plugin")
|
|
67824
67974
|
];
|
|
67825
67975
|
case "cli":
|
|
67826
|
-
return [
|
|
67976
|
+
return [path39.join(pkg, "assets", "templates", "spec-template.md")];
|
|
67827
67977
|
}
|
|
67828
67978
|
}, hostsFor = (host) => host === "cli" ? ["opencode", "cursor", "cli"] : [host], checkAssets = (res) => {
|
|
67829
67979
|
const dev = res.dev;
|
|
@@ -67854,22 +68004,22 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67854
68004
|
fix: "Reinstall or rebuild the workit package (missing assets under packages/workit-<host>)"
|
|
67855
68005
|
};
|
|
67856
68006
|
}, launcherSlotsFor = (host, dev) => {
|
|
67857
|
-
const pkg =
|
|
68007
|
+
const pkg = path39.join(dev, "packages", `workit-${host}`);
|
|
67858
68008
|
switch (host) {
|
|
67859
68009
|
case "opencode":
|
|
67860
|
-
return [[
|
|
68010
|
+
return [[path39.join(pkg, "src", "plugin.ts"), path39.join(pkg, "dist", "plugin.js")]];
|
|
67861
68011
|
case "cursor":
|
|
67862
68012
|
return [
|
|
67863
|
-
[
|
|
67864
|
-
[
|
|
68013
|
+
[path39.join(pkg, "dist", "mcp-server.js")],
|
|
68014
|
+
[path39.join(pkg, "dist", "cursor-session-start.js")]
|
|
67865
68015
|
];
|
|
67866
68016
|
case "cli":
|
|
67867
|
-
return [[
|
|
68017
|
+
return [[path39.join(pkg, "src", "index.tsx"), path39.join(pkg, "dist", "index.js")]];
|
|
67868
68018
|
}
|
|
67869
68019
|
}, validNodeEntry = (entry, runtime, env) => {
|
|
67870
68020
|
try {
|
|
67871
68021
|
const stat = statSync6(entry);
|
|
67872
|
-
if (!stat.isFile() || stat.size === 0 || !
|
|
68022
|
+
if (!stat.isFile() || stat.size === 0 || !readFileSync17(entry, "utf8").startsWith(`#!/usr/bin/env node
|
|
67873
68023
|
`)) {
|
|
67874
68024
|
return false;
|
|
67875
68025
|
}
|
|
@@ -67891,7 +68041,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67891
68041
|
if (typeof command !== "string" || !Array.isArray(args) || typeof args[0] !== "string") {
|
|
67892
68042
|
return "invalid";
|
|
67893
68043
|
}
|
|
67894
|
-
const executable =
|
|
68044
|
+
const executable = path39.basename(command).toLowerCase();
|
|
67895
68045
|
const canonical = cursorMcpServerEntry("").args;
|
|
67896
68046
|
if (executable === "npx" || executable === "npx.exe" || executable === "npx.cmd") {
|
|
67897
68047
|
if (args.length !== canonical.length || args.some((a, i) => a !== canonical[i]))
|
|
@@ -67903,10 +68053,10 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67903
68053
|
return {
|
|
67904
68054
|
kind: "node",
|
|
67905
68055
|
runtime: command,
|
|
67906
|
-
entry:
|
|
68056
|
+
entry: path39.isAbsolute(args[0]) ? args[0] : path39.resolve(path39.dirname(res.cursorMcp), args[0])
|
|
67907
68057
|
};
|
|
67908
68058
|
}, canonicalCursorHook, isCanonicalCursorHook = (command, res) => command === canonicalCursorHook || command === cursorHooksEntry(res.cursorPluginDir).command, registeredCursorHook = (res) => {
|
|
67909
|
-
const hooksFile =
|
|
68059
|
+
const hooksFile = path39.join(res.cursorPluginDir, "hooks", "hooks-cursor.json");
|
|
67910
68060
|
if (!existsSync16(hooksFile))
|
|
67911
68061
|
return "invalid";
|
|
67912
68062
|
const config = readJson(hooksFile);
|
|
@@ -67924,9 +68074,9 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67924
68074
|
if (!m)
|
|
67925
68075
|
return false;
|
|
67926
68076
|
const entry = m[1].trim();
|
|
67927
|
-
if (!
|
|
68077
|
+
if (!path39.isAbsolute(entry))
|
|
67928
68078
|
return false;
|
|
67929
|
-
if (
|
|
68079
|
+
if (path39.resolve(entry) !== path39.resolve(path39.join(res.cursorPluginDir, "dist", "cursor-session-start.js"))) {
|
|
67930
68080
|
return false;
|
|
67931
68081
|
}
|
|
67932
68082
|
return validNodeEntry(entry, "node", res.env);
|
|
@@ -67935,7 +68085,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67935
68085
|
const hosts = hostsFor(res.host);
|
|
67936
68086
|
const registered = hosts.includes("cursor") ? registeredCursorLauncher(res) : null;
|
|
67937
68087
|
const runtime = registered && registered !== "invalid" && registered.kind === "node" ? registered.runtime : "node";
|
|
67938
|
-
const missing = hosts.includes("cursor") ? ["dist/mcp-server.js", "dist/cursor-session-start.js"].map((rel) =>
|
|
68088
|
+
const missing = hosts.includes("cursor") ? ["dist/mcp-server.js", "dist/cursor-session-start.js"].map((rel) => path39.join(res.cursorPluginDir, rel)).filter((p) => !validNodeEntry(p, runtime, res.env)).map((p) => `cursor: ${p}`) : [];
|
|
67939
68089
|
if (hosts.includes("cursor")) {
|
|
67940
68090
|
if (registered === "invalid") {
|
|
67941
68091
|
missing.push(`cursor: canonical workit MCP launcher in ${res.cursorMcp}`);
|
|
@@ -67944,9 +68094,9 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67944
68094
|
}
|
|
67945
68095
|
const hook = registeredCursorHook(res);
|
|
67946
68096
|
if (hook === "invalid") {
|
|
67947
|
-
missing.push(`cursor: canonical session-start hook in ${
|
|
68097
|
+
missing.push(`cursor: canonical session-start hook in ${path39.join(res.cursorPluginDir, "hooks", "hooks-cursor.json")}`);
|
|
67948
68098
|
} else if (hook !== null && !isCanonicalCursorHook(hook, res) && !validLocalDistHook(hook, res)) {
|
|
67949
|
-
missing.push(`cursor: canonical session-start hook in ${
|
|
68099
|
+
missing.push(`cursor: canonical session-start hook in ${path39.join(res.cursorPluginDir, "hooks", "hooks-cursor.json")} (registered ${hook})`);
|
|
67950
68100
|
}
|
|
67951
68101
|
}
|
|
67952
68102
|
if (dev) {
|
|
@@ -67982,10 +68132,10 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
67982
68132
|
const normal = entry.replaceAll("\\", "/").replace(/\/+$/, "");
|
|
67983
68133
|
if (!normal.endsWith("local/workit") && !normal.endsWith("local/workflow-toolkit"))
|
|
67984
68134
|
continue;
|
|
67985
|
-
const dir = entry.startsWith("~") ?
|
|
68135
|
+
const dir = entry.startsWith("~") ? path39.join(res.home, entry.slice(1)) : entry;
|
|
67986
68136
|
let state = null;
|
|
67987
68137
|
try {
|
|
67988
|
-
state =
|
|
68138
|
+
state = readdirSync10(dir).length === 0 ? "empty" : null;
|
|
67989
68139
|
} catch {
|
|
67990
68140
|
state = "missing";
|
|
67991
68141
|
}
|
|
@@ -68007,17 +68157,26 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
68007
68157
|
status: "pass",
|
|
68008
68158
|
detail: "no registered Workit host plugin is missing its files"
|
|
68009
68159
|
};
|
|
68010
|
-
return {
|
|
68160
|
+
return {
|
|
68161
|
+
id: "plugin_files",
|
|
68162
|
+
status: "warn",
|
|
68163
|
+
detail: problems.join("; "),
|
|
68164
|
+
fix: fixes.join("; ")
|
|
68165
|
+
};
|
|
68011
68166
|
}, CURSOR_HOOK_FIX = "Run `workit init` and select Cursor to install the bundled hook", checkCursorHook = (res) => {
|
|
68012
68167
|
if (!hostsFor(res.host).includes("cursor"))
|
|
68013
|
-
return {
|
|
68168
|
+
return {
|
|
68169
|
+
id: "cursor_hook",
|
|
68170
|
+
status: "pass",
|
|
68171
|
+
detail: "cursor hook not inspected on this host"
|
|
68172
|
+
};
|
|
68014
68173
|
if (!existsSync16(res.cursorPluginDir))
|
|
68015
68174
|
return {
|
|
68016
68175
|
id: "cursor_hook",
|
|
68017
68176
|
status: "pass",
|
|
68018
68177
|
detail: "no Cursor plugin install — hook launcher not inspected"
|
|
68019
68178
|
};
|
|
68020
|
-
const launcher =
|
|
68179
|
+
const launcher = path39.join(res.cursorPluginDir, "hooks", "launch.mjs");
|
|
68021
68180
|
if (!existsSync16(launcher))
|
|
68022
68181
|
return {
|
|
68023
68182
|
id: "cursor_hook",
|
|
@@ -68025,7 +68184,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
68025
68184
|
detail: `cursor hook launcher mode: missing — ${launcher} is absent (an install from before the pinned launcher)`,
|
|
68026
68185
|
fix: CURSOR_HOOK_FIX
|
|
68027
68186
|
};
|
|
68028
|
-
const hooksFile =
|
|
68187
|
+
const hooksFile = path39.join(res.cursorPluginDir, "hooks", "hooks-cursor.json");
|
|
68029
68188
|
const registered = readJson(hooksFile);
|
|
68030
68189
|
const sessionCommand = registered?.hooks?.sessionStart?.[0]?.command;
|
|
68031
68190
|
const offLauncher = [
|
|
@@ -68084,7 +68243,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
68084
68243
|
detail: `${label}; probe ${ms} ms; ${silent}`,
|
|
68085
68244
|
fix: "Open a Cursor agent chat, then re-run `workit doctor`; if this persists, re-run `workit init` with Cursor (it writes absolute hook paths)"
|
|
68086
68245
|
};
|
|
68087
|
-
return {
|
|
68246
|
+
return {
|
|
68247
|
+
id: "cursor_hook",
|
|
68248
|
+
status: "pass",
|
|
68249
|
+
detail: `${label}; probe ${ms} ms`
|
|
68250
|
+
};
|
|
68088
68251
|
}, SILENT_HOOK_GRACE_MS, mtimeMs = (file) => {
|
|
68089
68252
|
try {
|
|
68090
68253
|
return statSync6(file).mtimeMs;
|
|
@@ -68092,10 +68255,10 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
68092
68255
|
return null;
|
|
68093
68256
|
}
|
|
68094
68257
|
}, silentCursorHooks = (res) => {
|
|
68095
|
-
const session = mtimeMs(
|
|
68258
|
+
const session = mtimeMs(path39.join(res.cursorHeartbeatDir, "cursor-session-last-start"));
|
|
68096
68259
|
if (session === null || Date.now() - session < SILENT_HOOK_GRACE_MS)
|
|
68097
68260
|
return null;
|
|
68098
|
-
const hook = mtimeMs(
|
|
68261
|
+
const hook = mtimeMs(path39.join(res.cursorHeartbeatDir, "cursor-hook-last-run"));
|
|
68099
68262
|
if (hook !== null && hook >= session)
|
|
68100
68263
|
return null;
|
|
68101
68264
|
return `Cursor started the Workit MCP server at ${new Date(session).toISOString()} but no Workit hook has run since${hook === null ? " (none ever)" : ""} — if the agent ran in that window, Cursor is not running the plugin hooks and Workit enforcement is off`;
|
|
@@ -68191,7 +68354,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
68191
68354
|
}
|
|
68192
68355
|
return { id: "stale_pin", status: "pass", detail: "opencode pin resolves" };
|
|
68193
68356
|
}, pluginMcpSelectors = (res) => {
|
|
68194
|
-
const p =
|
|
68357
|
+
const p = path39.join(res.cursorPluginDir, "mcp.json");
|
|
68195
68358
|
if (!existsSync16(p))
|
|
68196
68359
|
return null;
|
|
68197
68360
|
const cfg = readJson(p);
|
|
@@ -68225,19 +68388,19 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
68225
68388
|
return null;
|
|
68226
68389
|
}
|
|
68227
68390
|
}, installedPluginVersion = (res) => {
|
|
68228
|
-
const pkg = readJson(
|
|
68391
|
+
const pkg = readJson(path39.join(res.cursorPluginDir, "package.json"));
|
|
68229
68392
|
return typeof pkg?.version === "string" && pkg.version ? pkg.version : null;
|
|
68230
68393
|
}, installedOpenCodeCache = (res) => {
|
|
68231
68394
|
if (res.opencodePackageCacheDir !== null) {
|
|
68232
|
-
const pkg = readJson(
|
|
68395
|
+
const pkg = readJson(path39.join(res.opencodePackageCacheDir, "node_modules", "@brainervirus", "workit-opencode", "package.json"));
|
|
68233
68396
|
return typeof pkg?.version === "string" && pkg.version ? { version: pkg.version, dir: res.opencodePackageCacheDir } : null;
|
|
68234
68397
|
}
|
|
68235
68398
|
const found = openCodeInstalledPlugin(res.home, res.env);
|
|
68236
68399
|
if (!found)
|
|
68237
68400
|
return null;
|
|
68238
|
-
let dir =
|
|
68239
|
-
if (
|
|
68240
|
-
dir =
|
|
68401
|
+
let dir = path39.dirname(path39.dirname(path39.dirname(found.root)));
|
|
68402
|
+
if (path39.basename(dir) !== "workit-opencode@latest")
|
|
68403
|
+
dir = path39.dirname(dir);
|
|
68241
68404
|
return { version: found.version, dir };
|
|
68242
68405
|
}, checkOpenCodePackageCache = (res) => {
|
|
68243
68406
|
if (!existsSync16(res.opencodeConfig)) {
|
|
@@ -68341,7 +68504,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
68341
68504
|
fix: "Re-run install-cursor-plugin.sh — it rewrites the workit MCP entry to the canonical @latest selector"
|
|
68342
68505
|
};
|
|
68343
68506
|
}
|
|
68344
|
-
const hooksFile =
|
|
68507
|
+
const hooksFile = path39.join(res.cursorPluginDir, "hooks", "hooks-cursor.json");
|
|
68345
68508
|
const hookCmd = readJson(hooksFile)?.hooks?.sessionStart?.[0]?.command ?? null;
|
|
68346
68509
|
const canonicalHook = canonicalCursorHook;
|
|
68347
68510
|
const staleHook = hookCmd !== null && !isCanonicalCursorHook(hookCmd, res) && !hookCmd.startsWith("node ") && hookCmd.includes("@brainervirus/workit-cursor@");
|
|
@@ -68363,7 +68526,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
68363
68526
|
};
|
|
68364
68527
|
}
|
|
68365
68528
|
const installed = installedPluginVersion(res);
|
|
68366
|
-
const source = res.dev ? readJson(
|
|
68529
|
+
const source = res.dev ? readJson(path39.join(res.dev, "packages/workit-cursor/package.json"))?.version ?? null : readJson(path39.join(packageRoot(), "package.json"))?.version ?? null;
|
|
68367
68530
|
const localDist = mcpSelectors === null && hookCmd !== null && !isCanonicalCursorHook(hookCmd, res) && hookCmd.startsWith("node ");
|
|
68368
68531
|
if (localDist && installed !== null && source !== null && !semverAtLeast(installed, source)) {
|
|
68369
68532
|
return {
|
|
@@ -68375,7 +68538,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
68375
68538
|
}
|
|
68376
68539
|
if (localDist && installed !== null && source !== null && res.dev) {
|
|
68377
68540
|
const entry = /^node\s+(.+)$/.exec((hookCmd ?? "").trim())?.[1]?.trim() ?? "";
|
|
68378
|
-
const sourceBundle = entry &&
|
|
68541
|
+
const sourceBundle = entry && path39.isAbsolute(entry) ? path39.join(res.dev, "packages", "workit-cursor", "dist", path39.basename(entry)) : "";
|
|
68379
68542
|
if (entry && sourceBundle) {
|
|
68380
68543
|
const installedHash = bundleHashOfFile(entry);
|
|
68381
68544
|
const sourceHash = bundleHashOfFile(sourceBundle);
|
|
@@ -68383,7 +68546,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
68383
68546
|
return {
|
|
68384
68547
|
id: "stale_install",
|
|
68385
68548
|
status: "fail",
|
|
68386
|
-
detail: `stale_install: installed workit-cursor ${installed} runs different bytes than the current runtime build (${
|
|
68549
|
+
detail: `stale_install: installed workit-cursor ${installed} runs different bytes than the current runtime build (${path39.basename(entry)} hash mismatch)`,
|
|
68387
68550
|
fix: "Re-run install-cursor-plugin.sh — it refreshes the plugin directory with the current build"
|
|
68388
68551
|
};
|
|
68389
68552
|
}
|
|
@@ -68483,7 +68646,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
68483
68646
|
}, checkMalformedConfig = (res) => {
|
|
68484
68647
|
const files = [];
|
|
68485
68648
|
for (const name of ["config.json", "youtrack.json", "vcs.json", "workspaces.json"]) {
|
|
68486
|
-
const p =
|
|
68649
|
+
const p = path39.join(res.configDir, name);
|
|
68487
68650
|
if (existsSync16(p))
|
|
68488
68651
|
files.push(p);
|
|
68489
68652
|
}
|
|
@@ -68608,7 +68771,10 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
68608
68771
|
const slot = `${SESSION_HOOK_NAME} hook`;
|
|
68609
68772
|
switch (hook.state) {
|
|
68610
68773
|
case "not_git":
|
|
68611
|
-
return {
|
|
68774
|
+
return {
|
|
68775
|
+
status: "pass",
|
|
68776
|
+
detail: `not inside a git work tree — skipping the ${slot}`
|
|
68777
|
+
};
|
|
68612
68778
|
case "installed":
|
|
68613
68779
|
return {
|
|
68614
68780
|
status: "pass",
|
|
@@ -68701,17 +68867,17 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
68701
68867
|
return { ...installSessionHook(res.cwd, res.env), workspace: workspace.name };
|
|
68702
68868
|
}, isPlaceholder = (p) => {
|
|
68703
68869
|
try {
|
|
68704
|
-
return
|
|
68870
|
+
return readFileSync17(p, "utf8").trim() === TOKEN_PLACEHOLDER2;
|
|
68705
68871
|
} catch {
|
|
68706
68872
|
return false;
|
|
68707
68873
|
}
|
|
68708
68874
|
}, checkCredentialMetadata = (res) => {
|
|
68709
68875
|
const tokenPaths = [];
|
|
68710
|
-
const youtrackJson = readJson(
|
|
68876
|
+
const youtrackJson = readJson(path39.join(res.configDir, "youtrack.json"));
|
|
68711
68877
|
if (youtrackJson) {
|
|
68712
|
-
tokenPaths.push(typeof youtrackJson.tokenFile === "string" ? youtrackJson.tokenFile :
|
|
68713
|
-
} else if (existsSync16(
|
|
68714
|
-
tokenPaths.push(
|
|
68878
|
+
tokenPaths.push(typeof youtrackJson.tokenFile === "string" ? youtrackJson.tokenFile : path39.join(res.configDir, "youtrack.token"));
|
|
68879
|
+
} else if (existsSync16(path39.join(res.configDir, "youtrack.token"))) {
|
|
68880
|
+
tokenPaths.push(path39.join(res.configDir, "youtrack.token"));
|
|
68715
68881
|
}
|
|
68716
68882
|
if (tokenPaths.length === 0) {
|
|
68717
68883
|
return {
|
|
@@ -68722,7 +68888,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
68722
68888
|
}
|
|
68723
68889
|
const problems = [];
|
|
68724
68890
|
for (const raw of tokenPaths) {
|
|
68725
|
-
const p =
|
|
68891
|
+
const p = path39.isAbsolute(raw) ? raw : path39.resolve(res.configDir, raw);
|
|
68726
68892
|
if (!existsSync16(p)) {
|
|
68727
68893
|
problems.push(`${p} is missing`);
|
|
68728
68894
|
continue;
|
|
@@ -68802,7 +68968,10 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
68802
68968
|
},
|
|
68803
68969
|
ghLogin: (e) => {
|
|
68804
68970
|
try {
|
|
68805
|
-
const out = spawnSync16("gh", ["api", "user", "--jq", ".login"], {
|
|
68971
|
+
const out = spawnSync16("gh", ["api", "user", "--jq", ".login"], {
|
|
68972
|
+
encoding: "utf8",
|
|
68973
|
+
env: e
|
|
68974
|
+
});
|
|
68806
68975
|
const login = (out.stdout ?? "").trim();
|
|
68807
68976
|
return out.status === 0 && login ? login : null;
|
|
68808
68977
|
} catch {
|
|
@@ -68837,8 +69006,12 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
68837
69006
|
}), checkGithubIdentity = (res, probes = defaultIdentityProbes(res.env)) => {
|
|
68838
69007
|
const remoteHost = githubHostFromRemote(probes.origin(res.cwd) ?? "");
|
|
68839
69008
|
if (!remoteHost)
|
|
68840
|
-
return {
|
|
68841
|
-
|
|
69009
|
+
return {
|
|
69010
|
+
id: "github_identity",
|
|
69011
|
+
status: "pass",
|
|
69012
|
+
detail: "no GitHub remote configured"
|
|
69013
|
+
};
|
|
69014
|
+
const vcsJson = readJson(res.env.WORKFLOW_VCS_CONFIG ?? path39.join(res.configDir, "vcs.json"));
|
|
68842
69015
|
const workspace = workspaceProviderForIdentity(res.cwd, res.configDir, res.env);
|
|
68843
69016
|
if (workspace.error)
|
|
68844
69017
|
return {
|
|
@@ -68849,7 +69022,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
68849
69022
|
};
|
|
68850
69023
|
const provider = identityProvider(remoteHost, vcsJson, workspace.provider);
|
|
68851
69024
|
if (provider !== "github")
|
|
68852
|
-
return {
|
|
69025
|
+
return {
|
|
69026
|
+
id: "github_identity",
|
|
69027
|
+
status: "pass",
|
|
69028
|
+
detail: "no GitHub remote configured"
|
|
69029
|
+
};
|
|
68853
69030
|
const cliHost = String(vcsJson?.github?.host ?? "github.com").toLowerCase();
|
|
68854
69031
|
const cliLogin = probes.ghLogin({ ...res.env, GH_HOST: cliHost });
|
|
68855
69032
|
if (!cliLogin)
|
|
@@ -68865,8 +69042,12 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
68865
69042
|
}, checkGitLabIdentity = (res, probes = defaultIdentityProbes(res.env)) => {
|
|
68866
69043
|
const remoteHost = githubHostFromRemote(probes.origin(res.cwd) ?? "");
|
|
68867
69044
|
if (!remoteHost)
|
|
68868
|
-
return {
|
|
68869
|
-
|
|
69045
|
+
return {
|
|
69046
|
+
id: "gitlab_identity",
|
|
69047
|
+
status: "pass",
|
|
69048
|
+
detail: "no GitLab remote configured"
|
|
69049
|
+
};
|
|
69050
|
+
const vcsJson = readJson(res.env.WORKFLOW_VCS_CONFIG ?? path39.join(res.configDir, "vcs.json"));
|
|
68870
69051
|
const workspace = workspaceProviderForIdentity(res.cwd, res.configDir, res.env);
|
|
68871
69052
|
if (workspace.error)
|
|
68872
69053
|
return {
|
|
@@ -68877,7 +69058,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
68877
69058
|
};
|
|
68878
69059
|
const provider = identityProvider(remoteHost, vcsJson, workspace.provider);
|
|
68879
69060
|
if (provider !== "gitlab")
|
|
68880
|
-
return {
|
|
69061
|
+
return {
|
|
69062
|
+
id: "gitlab_identity",
|
|
69063
|
+
status: "pass",
|
|
69064
|
+
detail: "no GitLab remote configured"
|
|
69065
|
+
};
|
|
68881
69066
|
const cliHost = String(vcsJson?.gitlab?.host ?? "gitlab.com").toLowerCase();
|
|
68882
69067
|
const cliLogin = probes.glabLogin?.({ ...res.env, GITLAB_HOST: cliHost }) ?? null;
|
|
68883
69068
|
if (!cliLogin)
|
|
@@ -68892,11 +69077,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
68892
69077
|
{ surface: "SSH", login: probes.sshLogin(remoteHost) }
|
|
68893
69078
|
]);
|
|
68894
69079
|
}, checkLogWritable = (res) => {
|
|
68895
|
-
const logsDir =
|
|
68896
|
-
const probe =
|
|
69080
|
+
const logsDir = path39.join(res.stateDir, "logs");
|
|
69081
|
+
const probe = path39.join(logsDir, "doctor-probe.tmp");
|
|
68897
69082
|
try {
|
|
68898
|
-
|
|
68899
|
-
|
|
69083
|
+
mkdirSync8(logsDir, { recursive: true, mode: 448 });
|
|
69084
|
+
writeFileSync8(probe, `{"probe":true}
|
|
68900
69085
|
`, { mode: 384 });
|
|
68901
69086
|
return {
|
|
68902
69087
|
id: "log_writable",
|
|
@@ -68926,7 +69111,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
68926
69111
|
fix
|
|
68927
69112
|
};
|
|
68928
69113
|
if (lock.state === "absent")
|
|
68929
|
-
return {
|
|
69114
|
+
return {
|
|
69115
|
+
id: "workspace_lock",
|
|
69116
|
+
status: "pass",
|
|
69117
|
+
detail: "no metadata lock held"
|
|
69118
|
+
};
|
|
68930
69119
|
if (lock.state === "stale")
|
|
68931
69120
|
return {
|
|
68932
69121
|
id: "workspace_lock",
|
|
@@ -68971,7 +69160,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
68971
69160
|
const counts = { skip: 0, late: 0 };
|
|
68972
69161
|
let text = "";
|
|
68973
69162
|
try {
|
|
68974
|
-
text =
|
|
69163
|
+
text = readFileSync17(path39.join(stateDir, HOOK_SKIPS_FILE), "utf8");
|
|
68975
69164
|
} catch {
|
|
68976
69165
|
return counts;
|
|
68977
69166
|
}
|
|
@@ -68989,7 +69178,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
68989
69178
|
}
|
|
68990
69179
|
return counts;
|
|
68991
69180
|
}, checkHookDeadline = (res) => {
|
|
68992
|
-
const file =
|
|
69181
|
+
const file = path39.join(res.hookStateDir, HOOK_SKIPS_FILE);
|
|
68993
69182
|
const { skip, late } = countHookSkips(res.hookStateDir, Date.now() - DAY_MS);
|
|
68994
69183
|
const lateText = late > 0 ? `; ${late} answered past it in full` : "";
|
|
68995
69184
|
if (skip > 0)
|
|
@@ -69020,11 +69209,15 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
69020
69209
|
status: "warn",
|
|
69021
69210
|
detail: line.split("; ")[0],
|
|
69022
69211
|
fix: line.split("; ")[1]
|
|
69023
|
-
} : {
|
|
69212
|
+
} : {
|
|
69213
|
+
id: "grant_endpoint",
|
|
69214
|
+
status: "pass",
|
|
69215
|
+
detail: "grants and default endpoint agree"
|
|
69216
|
+
};
|
|
69024
69217
|
}, checkChecksConfig = (res) => {
|
|
69025
69218
|
const root = checkRoot(res.cwd);
|
|
69026
|
-
const current = existsSync16(
|
|
69027
|
-
const legacy = existsSync16(
|
|
69219
|
+
const current = existsSync16(path39.join(root, CHECKS_FILE));
|
|
69220
|
+
const legacy = existsSync16(path39.join(root, LEGACY_CHECKS_FILE));
|
|
69028
69221
|
if (!legacy)
|
|
69029
69222
|
return {
|
|
69030
69223
|
id: "checks_config",
|
|
@@ -69039,8 +69232,8 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
69039
69232
|
};
|
|
69040
69233
|
}, fixChecksConfig = (options = {}) => {
|
|
69041
69234
|
const root = checkRoot(resolve(options).cwd);
|
|
69042
|
-
const from =
|
|
69043
|
-
const to =
|
|
69235
|
+
const from = path39.join(root, LEGACY_CHECKS_FILE);
|
|
69236
|
+
const to = path39.join(root, CHECKS_FILE);
|
|
69044
69237
|
if (!existsSync16(from))
|
|
69045
69238
|
return { action: "none", detail: `no ${LEGACY_CHECKS_FILE} at ${root}` };
|
|
69046
69239
|
if (existsSync16(to))
|
|
@@ -69100,7 +69293,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
69100
69293
|
status: "info",
|
|
69101
69294
|
detail: "no Workit Claude Code plugin install recorded — skipping"
|
|
69102
69295
|
};
|
|
69103
|
-
const registry = readJson(
|
|
69296
|
+
const registry = readJson(path39.join(claudeConfigDir(res.home, res.env), "plugins", "installed_plugins.json"));
|
|
69104
69297
|
const recorded = (install) => {
|
|
69105
69298
|
const entries = registry?.plugins?.[install.id];
|
|
69106
69299
|
const entry = Array.isArray(entries) ? entries.find((e) => e?.installPath === install.installPath) : null;
|
|
@@ -69150,7 +69343,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
69150
69343
|
}, HOOK_ISSUED_MARKER = "workit-issued-sessions/3", hookRecordsIssued = (root) => {
|
|
69151
69344
|
let files;
|
|
69152
69345
|
try {
|
|
69153
|
-
files =
|
|
69346
|
+
files = readdirSync10(path39.join(root, "dist")).filter((f) => f.endsWith(".js"));
|
|
69154
69347
|
} catch {
|
|
69155
69348
|
return null;
|
|
69156
69349
|
}
|
|
@@ -69158,7 +69351,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
69158
69351
|
return null;
|
|
69159
69352
|
return files.some((file) => {
|
|
69160
69353
|
try {
|
|
69161
|
-
return
|
|
69354
|
+
return readFileSync17(path39.join(root, "dist", file), "utf8").includes(HOOK_ISSUED_MARKER);
|
|
69162
69355
|
} catch {
|
|
69163
69356
|
return false;
|
|
69164
69357
|
}
|
|
@@ -69214,7 +69407,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
69214
69407
|
env,
|
|
69215
69408
|
timeout: WORKIT_PROBE_TIMEOUT_MS,
|
|
69216
69409
|
shell: true
|
|
69217
|
-
}) : spawnSync16(bin, ["--version"], {
|
|
69410
|
+
}) : spawnSync16(bin, ["--version"], {
|
|
69411
|
+
encoding: "utf8",
|
|
69412
|
+
env,
|
|
69413
|
+
timeout: WORKIT_PROBE_TIMEOUT_MS
|
|
69414
|
+
});
|
|
69218
69415
|
const timedOut = r.error !== undefined && "code" in r.error && r.error.code === "ETIMEDOUT";
|
|
69219
69416
|
const version = r.status === 0 ? (r.stdout ?? "").match(SEMVER)?.[0] ?? null : null;
|
|
69220
69417
|
const probe = { version: timedOut ? null : version, timedOut };
|
|
@@ -69227,14 +69424,22 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
69227
69424
|
version: i.version
|
|
69228
69425
|
})),
|
|
69229
69426
|
{ label: "Cursor plugin", version: installedPluginVersion(res) },
|
|
69230
|
-
{
|
|
69427
|
+
{
|
|
69428
|
+
label: "OpenCode plugin",
|
|
69429
|
+
version: installedOpenCodeCache(res)?.version ?? null
|
|
69430
|
+
}
|
|
69231
69431
|
].filter((p) => p.version !== null);
|
|
69232
69432
|
const newest = plugins.reduce((best, p) => best && semverAtLeast(best.version, p.version) ? best : p, null);
|
|
69233
69433
|
const target = newest?.version ?? "latest";
|
|
69234
69434
|
const fix = `npm i -g ${CLI_PACKAGE}@${target} (or run it without a global install: npx -y ${CLI_PACKAGE}@${target} <command>)`;
|
|
69235
69435
|
const bin = findOnPath(pathextNames("workit", res.env), res.env);
|
|
69236
69436
|
if (!bin) {
|
|
69237
|
-
return {
|
|
69437
|
+
return {
|
|
69438
|
+
id: "workit_on_path",
|
|
69439
|
+
status: "warn",
|
|
69440
|
+
detail: "no workit on PATH",
|
|
69441
|
+
fix
|
|
69442
|
+
};
|
|
69238
69443
|
}
|
|
69239
69444
|
const { version, timedOut } = workitVersionAt(bin, res.env);
|
|
69240
69445
|
if (!version) {
|
|
@@ -69269,7 +69474,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
69269
69474
|
const file = permissionTarget(host, paths).file;
|
|
69270
69475
|
switch (health.state) {
|
|
69271
69476
|
case "no-host":
|
|
69272
|
-
return {
|
|
69477
|
+
return {
|
|
69478
|
+
id,
|
|
69479
|
+
status: "info",
|
|
69480
|
+
detail: `${host} not found; no permission block needed`
|
|
69481
|
+
};
|
|
69273
69482
|
case "absent":
|
|
69274
69483
|
return {
|
|
69275
69484
|
id,
|
|
@@ -69277,10 +69486,79 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
69277
69486
|
detail: `no Workit permission block in ${file} (optional: \`${fix}\` lets agents run Workit's delivery verbs without a prompt)`
|
|
69278
69487
|
};
|
|
69279
69488
|
case "ok":
|
|
69280
|
-
return {
|
|
69489
|
+
return {
|
|
69490
|
+
id,
|
|
69491
|
+
status: "pass",
|
|
69492
|
+
detail: `Workit's permission block is current in ${file}`
|
|
69493
|
+
};
|
|
69281
69494
|
default:
|
|
69282
69495
|
return { id, status: "warn", detail: health.detail, fix };
|
|
69283
69496
|
}
|
|
69497
|
+
}, checkGrantRules = (host, id) => (res) => {
|
|
69498
|
+
const paths = {
|
|
69499
|
+
home: res.home,
|
|
69500
|
+
env: res.codexHome ? { ...res.env, CODEX_HOME: res.codexHome } : res.env,
|
|
69501
|
+
stateDir: res.stateDir,
|
|
69502
|
+
cwd: res.cwd
|
|
69503
|
+
};
|
|
69504
|
+
let entry = null;
|
|
69505
|
+
try {
|
|
69506
|
+
entry = resolveWorkspaceFrom(res.cwd, res.configDir);
|
|
69507
|
+
} catch {}
|
|
69508
|
+
if (!entry)
|
|
69509
|
+
return {
|
|
69510
|
+
id,
|
|
69511
|
+
status: "info",
|
|
69512
|
+
detail: "no Workit workspace here; no grants to cover"
|
|
69513
|
+
};
|
|
69514
|
+
const { grants } = configuredGrants(entry);
|
|
69515
|
+
const granted = ["push", "pr", "merge"].filter((kind) => kind === "merge" ? Boolean(grants.merge) : grants[kind] !== false);
|
|
69516
|
+
const coverage = permissionCoverage(host, grantedCommands(granted), paths);
|
|
69517
|
+
if (coverage.state === "no-host")
|
|
69518
|
+
return {
|
|
69519
|
+
id,
|
|
69520
|
+
status: "info",
|
|
69521
|
+
detail: `${host} not found; no rules to check`
|
|
69522
|
+
};
|
|
69523
|
+
if (coverage.state === "ok")
|
|
69524
|
+
return {
|
|
69525
|
+
id,
|
|
69526
|
+
status: "pass",
|
|
69527
|
+
detail: `${host} rules cover the granted Workit verbs (${granted.join(", ") || "none"}) and the check and lock verbs`
|
|
69528
|
+
};
|
|
69529
|
+
const shown = coverage.missing.slice(0, 4).join(", ");
|
|
69530
|
+
return {
|
|
69531
|
+
id,
|
|
69532
|
+
status: "warn",
|
|
69533
|
+
detail: `${host} rules in ${coverage.file} do not cover ${shown}${coverage.missing.length > 4 ? ", …" : ""}${existsSync16(coverage.file) ? "" : ` (${coverage.file} does not exist yet; \`workit setup\` writes it)`}: agents get a prompt (or an auto-mode denial) on verbs the workspace grants`,
|
|
69534
|
+
fix: `workit setup --hosts=${host}`
|
|
69535
|
+
};
|
|
69536
|
+
}, ago = (ms) => {
|
|
69537
|
+
const minutes = Math.max(0, Math.round(ms / 60000));
|
|
69538
|
+
if (minutes < 1)
|
|
69539
|
+
return "just now";
|
|
69540
|
+
if (minutes < 60)
|
|
69541
|
+
return `${minutes} min ago`;
|
|
69542
|
+
const hours = Math.round(minutes / 60);
|
|
69543
|
+
return hours < 48 ? `${hours} h ago` : `${Math.round(hours / 24)} d ago`;
|
|
69544
|
+
}, checkHookRuns = (res) => {
|
|
69545
|
+
const runs = readHookRuns(res.hookStateDir).filter((run) => run.event === "PreToolUse" || run.event === "SessionStart");
|
|
69546
|
+
if (runs.length === 0)
|
|
69547
|
+
return {
|
|
69548
|
+
id: "hook_runs",
|
|
69549
|
+
status: "info",
|
|
69550
|
+
detail: "no host hook run recorded yet (counted from this Workit version on; Claude Code launcher fast-path answers and Codex PostToolUse are not counted; start an agent session, then re-run `workit doctor`)"
|
|
69551
|
+
};
|
|
69552
|
+
const now = Date.now();
|
|
69553
|
+
const hosts = [...new Set(runs.map((run) => run.host))].toSorted();
|
|
69554
|
+
const parts = hosts.map((host) => {
|
|
69555
|
+
const seen = ["SessionStart", "PreToolUse"].map((event) => {
|
|
69556
|
+
const run = runs.find((r) => r.host === host && r.event === event);
|
|
69557
|
+
return `${event} ${run ? `${ago(now - Date.parse(run.at))} (${run.count})` : "never"}`;
|
|
69558
|
+
});
|
|
69559
|
+
return `${host}: ${seen.join(", ")}`;
|
|
69560
|
+
});
|
|
69561
|
+
return { id: "hook_runs", status: "pass", detail: parts.join("; ") };
|
|
69284
69562
|
}, RUN_CHECKS, INSTALLER_REQUIRED, runDoctor = (options = {}) => {
|
|
69285
69563
|
const res = resolve(options);
|
|
69286
69564
|
const raw = RUN_CHECKS.map((fn) => fn(res));
|
|
@@ -69332,6 +69610,7 @@ var init_doctor = __esm(() => {
|
|
|
69332
69610
|
init_host_install();
|
|
69333
69611
|
init_skill_manifests();
|
|
69334
69612
|
init_session_hook();
|
|
69613
|
+
init_hook_runs();
|
|
69335
69614
|
init_host_permissions();
|
|
69336
69615
|
OPENCODE_V1_FIX = `OpenCode < ${SUPPORT_MATRIX.opencode.minimum} cannot load Workit 3 (V2 plugin API only): upgrade OpenCode to ${SUPPORT_MATRIX.opencode.minimum}+, or stay on Workit 2.x by pinning "@brainervirus/workit-opencode@2" in the opencode.json "plugin" array`;
|
|
69337
69616
|
AGENT_MARKER_VERSION = /^# Generated by Workit (\d+\.\d+\.\d+)\b/;
|
|
@@ -69371,10 +69650,14 @@ var init_doctor = __esm(() => {
|
|
|
69371
69650
|
checkHeavyScope,
|
|
69372
69651
|
checkHookDeadline,
|
|
69373
69652
|
checkGrantEndpoint,
|
|
69653
|
+
checkHookRuns,
|
|
69374
69654
|
checkChecksConfig,
|
|
69375
69655
|
checkHostPermissions("claude-code", "claude_permissions"),
|
|
69376
69656
|
checkHostPermissions("codex", "codex_permissions"),
|
|
69377
|
-
checkHostPermissions("cursor", "cursor_permissions")
|
|
69657
|
+
checkHostPermissions("cursor", "cursor_permissions"),
|
|
69658
|
+
checkGrantRules("claude-code", "claude_grant_rules"),
|
|
69659
|
+
checkGrantRules("codex", "codex_grant_rules"),
|
|
69660
|
+
checkGrantRules("cursor", "cursor_grant_rules")
|
|
69378
69661
|
];
|
|
69379
69662
|
INSTALLER_REQUIRED = new Set([
|
|
69380
69663
|
"runtime",
|
|
@@ -69394,19 +69677,19 @@ import {
|
|
|
69394
69677
|
cpSync as cpSync4,
|
|
69395
69678
|
existsSync as existsSync17,
|
|
69396
69679
|
lstatSync as lstatSync6,
|
|
69397
|
-
mkdirSync as
|
|
69680
|
+
mkdirSync as mkdirSync9,
|
|
69398
69681
|
mkdtempSync as mkdtempSync2,
|
|
69399
|
-
readFileSync as
|
|
69400
|
-
readdirSync as
|
|
69682
|
+
readFileSync as readFileSync18,
|
|
69683
|
+
readdirSync as readdirSync11,
|
|
69401
69684
|
realpathSync as realpathSync8,
|
|
69402
69685
|
renameSync as renameSync5,
|
|
69403
69686
|
rmSync as rmSync5,
|
|
69404
69687
|
statSync as statSync7,
|
|
69405
|
-
writeFileSync as
|
|
69688
|
+
writeFileSync as writeFileSync9
|
|
69406
69689
|
} from "node:fs";
|
|
69407
69690
|
import { createRequire as createRequire2 } from "node:module";
|
|
69408
69691
|
import os13 from "node:os";
|
|
69409
|
-
import
|
|
69692
|
+
import path40 from "node:path";
|
|
69410
69693
|
import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
|
|
69411
69694
|
function parseList(raw) {
|
|
69412
69695
|
return raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
@@ -69451,7 +69734,7 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
69451
69734
|
const current = readConfigFromDir(state.configDir);
|
|
69452
69735
|
mutations.push({
|
|
69453
69736
|
type: "merge-json",
|
|
69454
|
-
path:
|
|
69737
|
+
path: path40.join(state.configDir, "config.json"),
|
|
69455
69738
|
value: {
|
|
69456
69739
|
locale: values.locale,
|
|
69457
69740
|
localeOptions: current.localeOptions,
|
|
@@ -69477,17 +69760,17 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
69477
69760
|
if (blocked.length === 0) {
|
|
69478
69761
|
mutations.push({
|
|
69479
69762
|
type: "update-workspaces",
|
|
69480
|
-
path:
|
|
69763
|
+
path: path40.join(state.configDir, "workspaces.json"),
|
|
69481
69764
|
entries: values.workspaces,
|
|
69482
69765
|
expectedRevision: diskWorkspaceResult.revision
|
|
69483
69766
|
});
|
|
69484
69767
|
}
|
|
69485
69768
|
}
|
|
69486
69769
|
if (values.baseUrl.trim()) {
|
|
69487
|
-
const ytPath =
|
|
69770
|
+
const ytPath = path40.join(state.configDir, "youtrack.json");
|
|
69488
69771
|
const ytExisting = readConfigRecord(ytPath);
|
|
69489
69772
|
const ytConfigured = configuredTokenPath(ytExisting, "tokenFile");
|
|
69490
|
-
const tokenPath = resolveTokenPath(ytConfigured,
|
|
69773
|
+
const tokenPath = resolveTokenPath(ytConfigured, path40.join(state.configDir, "youtrack.token"), values.tokenPaths?.youtrack);
|
|
69491
69774
|
const draft = youtrackDraft(values, tokenPath);
|
|
69492
69775
|
if (ytConfigured !== null && tokenPath !== ytConfigured) {
|
|
69493
69776
|
delete draft.tokenFile;
|
|
@@ -69515,7 +69798,7 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
69515
69798
|
});
|
|
69516
69799
|
}
|
|
69517
69800
|
if (values.vcsProvider !== "skip") {
|
|
69518
|
-
const vcsPath =
|
|
69801
|
+
const vcsPath = path40.join(state.configDir, "vcs.json");
|
|
69519
69802
|
mutations.push({
|
|
69520
69803
|
type: "merge-json",
|
|
69521
69804
|
path: vcsPath,
|
|
@@ -69544,7 +69827,7 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
69544
69827
|
mutations.push({
|
|
69545
69828
|
type: "install-host",
|
|
69546
69829
|
platform: "cursor",
|
|
69547
|
-
path:
|
|
69830
|
+
path: path40.join(paths.home, ".cursor", "plugins", "local", ".workit-package-bootstrap"),
|
|
69548
69831
|
commands
|
|
69549
69832
|
});
|
|
69550
69833
|
}
|
|
@@ -69557,7 +69840,7 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
69557
69840
|
mutations.push({
|
|
69558
69841
|
type: "install-host",
|
|
69559
69842
|
platform,
|
|
69560
|
-
path: platform === "claude-code" ? claudeInstallRecord(paths.home, env) : platform === "codex" ?
|
|
69843
|
+
path: platform === "claude-code" ? claudeInstallRecord(paths.home, env) : platform === "codex" ? path40.join(env.CODEX_HOME ?? path40.join(paths.home, ".codex"), "plugins", "cache", "workflow-toolkit", "workit") : path40.join(env.PI_CODING_AGENT_DIR ?? path40.join(paths.home, ".pi", "agent"), "settings.json"),
|
|
69561
69844
|
commands
|
|
69562
69845
|
});
|
|
69563
69846
|
}
|
|
@@ -69569,8 +69852,8 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
69569
69852
|
projectRefused = target.refused;
|
|
69570
69853
|
if (target?.ok) {
|
|
69571
69854
|
const root = target.root;
|
|
69572
|
-
const gitignorePath =
|
|
69573
|
-
const existing = existsSync17(gitignorePath) ?
|
|
69855
|
+
const gitignorePath = path40.join(root, ".gitignore");
|
|
69856
|
+
const existing = existsSync17(gitignorePath) ? readFileSync18(gitignorePath, "utf8") : "";
|
|
69574
69857
|
const existingLines = new Set(existing.split(`
|
|
69575
69858
|
`).map((l) => l.trim()).filter(Boolean));
|
|
69576
69859
|
const entries = GITIGNORE_ENTRIES.filter((e) => e.trim() !== "" && !existingLines.has(e.trim()));
|
|
@@ -69607,10 +69890,10 @@ function deepMerge(base, patch) {
|
|
|
69607
69890
|
return out;
|
|
69608
69891
|
}
|
|
69609
69892
|
function applyMutation(m) {
|
|
69610
|
-
const dir =
|
|
69893
|
+
const dir = path40.dirname(m.path);
|
|
69611
69894
|
switch (m.type) {
|
|
69612
69895
|
case "create-file": {
|
|
69613
|
-
|
|
69896
|
+
mkdirSync9(dir, { recursive: true });
|
|
69614
69897
|
const res = writeFileExclusive(m.path, m.content, m.mode);
|
|
69615
69898
|
return res === "created" ? { platform: "core", file: m.path, status: "Installed" } : {
|
|
69616
69899
|
platform: "core",
|
|
@@ -69633,8 +69916,8 @@ function applyMutation(m) {
|
|
|
69633
69916
|
if (existing.kind === "record" && JSON.stringify(existing.value) === JSON.stringify(merged)) {
|
|
69634
69917
|
return { platform: "core", file: m.path, status: "Skipped", detail: "already configured" };
|
|
69635
69918
|
}
|
|
69636
|
-
|
|
69637
|
-
|
|
69919
|
+
mkdirSync9(dir, { recursive: true });
|
|
69920
|
+
writeFileSync9(m.path, JSON.stringify(merged, null, 2) + `
|
|
69638
69921
|
`, "utf8");
|
|
69639
69922
|
return existing.kind === "record" ? { platform: "core", file: m.path, status: "Configured" } : { platform: "core", file: m.path, status: "Installed" };
|
|
69640
69923
|
}
|
|
@@ -69675,10 +69958,10 @@ function applyMutation(m) {
|
|
|
69675
69958
|
`;
|
|
69676
69959
|
if (prev === next)
|
|
69677
69960
|
return { platform: "core", file: m.path, status: "Skipped", detail: "already configured" };
|
|
69678
|
-
|
|
69961
|
+
mkdirSync9(dir, { recursive: true });
|
|
69679
69962
|
const tmp = `${m.path}.${process.pid}.tmp`;
|
|
69680
69963
|
try {
|
|
69681
|
-
|
|
69964
|
+
writeFileSync9(tmp, next, "utf8");
|
|
69682
69965
|
if (workspacesRevision(readFileSafe(m.path)) !== m.expectedRevision) {
|
|
69683
69966
|
rmSync5(tmp, { force: true });
|
|
69684
69967
|
return {
|
|
@@ -69713,11 +69996,11 @@ function applyMutation(m) {
|
|
|
69713
69996
|
detail: "all entries already present"
|
|
69714
69997
|
};
|
|
69715
69998
|
}
|
|
69716
|
-
|
|
69999
|
+
mkdirSync9(dir, { recursive: true });
|
|
69717
70000
|
const separator = existing && !existing.endsWith(`
|
|
69718
70001
|
`) ? `
|
|
69719
70002
|
` : "";
|
|
69720
|
-
|
|
70003
|
+
writeFileSync9(m.path, existing + separator + (existing ? `
|
|
69721
70004
|
` : "") + add.join(`
|
|
69722
70005
|
`) + `
|
|
69723
70006
|
`, "utf8");
|
|
@@ -69756,8 +70039,8 @@ function applyMutation(m) {
|
|
|
69756
70039
|
detail: "already configured"
|
|
69757
70040
|
};
|
|
69758
70041
|
}
|
|
69759
|
-
|
|
69760
|
-
|
|
70042
|
+
mkdirSync9(path40.dirname(m.path), { recursive: true });
|
|
70043
|
+
writeFileSync9(m.path, JSON.stringify(merged, null, 2) + `
|
|
69761
70044
|
`, "utf8");
|
|
69762
70045
|
return existing.kind === "record" ? { platform: "core", file: m.path, status: "Configured" } : { platform: "core", file: m.path, status: "Installed" };
|
|
69763
70046
|
}
|
|
@@ -69765,11 +70048,11 @@ function applyMutation(m) {
|
|
|
69765
70048
|
}
|
|
69766
70049
|
function adapterRoot(platform, res, preferInstalledAdapter = false) {
|
|
69767
70050
|
const candidates = [];
|
|
69768
|
-
const stagedCursor =
|
|
70051
|
+
const stagedCursor = path40.join(res.home, ".cursor", "plugins", "local", ".workit-package-bootstrap", "node_modules", "@brainervirus", "workit-cursor");
|
|
69769
70052
|
if (platform === "cursor" && preferInstalledAdapter)
|
|
69770
70053
|
candidates.push(stagedCursor);
|
|
69771
70054
|
if (res.dev) {
|
|
69772
|
-
candidates.push(
|
|
70055
|
+
candidates.push(path40.join(res.dev, "packages", `workit-${platform}`));
|
|
69773
70056
|
} else {
|
|
69774
70057
|
candidates.push(...nodeResolvedAdapters(platform));
|
|
69775
70058
|
if (platform === "cursor")
|
|
@@ -69779,10 +70062,10 @@ function adapterRoot(platform, res, preferInstalledAdapter = false) {
|
|
|
69779
70062
|
if (cached)
|
|
69780
70063
|
candidates.push(cached.root);
|
|
69781
70064
|
}
|
|
69782
|
-
let dir =
|
|
70065
|
+
let dir = path40.resolve(res.cwd);
|
|
69783
70066
|
while (true) {
|
|
69784
|
-
candidates.push(
|
|
69785
|
-
const parent =
|
|
70067
|
+
candidates.push(path40.join(dir, "packages", `workit-${platform}`));
|
|
70068
|
+
const parent = path40.dirname(dir);
|
|
69786
70069
|
if (parent === dir)
|
|
69787
70070
|
break;
|
|
69788
70071
|
dir = parent;
|
|
@@ -69804,7 +70087,7 @@ function applyOpenCode(root, res) {
|
|
|
69804
70087
|
detail: "workit-opencode package has no loadable plugin entry (src/plugin.ts or dist/plugin.js)"
|
|
69805
70088
|
};
|
|
69806
70089
|
}
|
|
69807
|
-
|
|
70090
|
+
mkdirSync9(path40.dirname(res.opencodeConfig), { recursive: true });
|
|
69808
70091
|
const existing = readExisting(res.opencodeConfig);
|
|
69809
70092
|
if (existing.kind === "malformed") {
|
|
69810
70093
|
return {
|
|
@@ -69833,7 +70116,7 @@ function applyOpenCode(root, res) {
|
|
|
69833
70116
|
detail: "already registered"
|
|
69834
70117
|
};
|
|
69835
70118
|
}
|
|
69836
|
-
|
|
70119
|
+
writeFileSync9(res.opencodeConfig, JSON.stringify(merged.config, null, 2) + `
|
|
69837
70120
|
`, "utf8");
|
|
69838
70121
|
return existing.kind === "record" ? {
|
|
69839
70122
|
platform: "opencode",
|
|
@@ -69849,31 +70132,31 @@ function applyOpenCode(root, res) {
|
|
|
69849
70132
|
}
|
|
69850
70133
|
function copyPluginDir(src, dest) {
|
|
69851
70134
|
const realSrc = realpathSync8(src);
|
|
69852
|
-
const marker =
|
|
70135
|
+
const marker = path40.join(dest, ".workit-root");
|
|
69853
70136
|
const destIsLink = existsSync17(dest) && lstatSync6(dest).isSymbolicLink();
|
|
69854
70137
|
const synced = !destIsLink && readFileSafe(marker)?.trim() === realSrc && samePluginContent(realSrc, dest, dest);
|
|
69855
70138
|
if (synced)
|
|
69856
70139
|
return "Skipped";
|
|
69857
70140
|
const hadDir = existsSync17(dest);
|
|
69858
70141
|
const rules = preservedCursorRules(realSrc, dest);
|
|
69859
|
-
const parent =
|
|
69860
|
-
|
|
69861
|
-
const swap = mkdtempSync2(
|
|
69862
|
-
const stage =
|
|
69863
|
-
const backup =
|
|
70142
|
+
const parent = path40.dirname(dest);
|
|
70143
|
+
mkdirSync9(parent, { recursive: true });
|
|
70144
|
+
const swap = mkdtempSync2(path40.join(parent, `.${path40.basename(dest)}.swap-`));
|
|
70145
|
+
const stage = path40.join(swap, "stage");
|
|
70146
|
+
const backup = path40.join(swap, "backup");
|
|
69864
70147
|
try {
|
|
69865
70148
|
cpSync4(realSrc, stage, {
|
|
69866
70149
|
recursive: true,
|
|
69867
|
-
filter: (entry) => !
|
|
70150
|
+
filter: (entry) => !path40.relative(realSrc, entry).split(path40.sep).includes("node_modules")
|
|
69868
70151
|
});
|
|
69869
|
-
const stagedHooks =
|
|
70152
|
+
const stagedHooks = path40.join(stage, CURSOR_HOOKS_FILE);
|
|
69870
70153
|
if (existsSync17(stagedHooks))
|
|
69871
|
-
|
|
70154
|
+
writeFileSync9(stagedHooks, localizedCursorHooks(readFileSync18(stagedHooks), dest));
|
|
69872
70155
|
for (const [name, content] of rules) {
|
|
69873
|
-
|
|
69874
|
-
|
|
70156
|
+
mkdirSync9(path40.join(stage, "rules"), { recursive: true });
|
|
70157
|
+
writeFileSync9(path40.join(stage, "rules", name), content);
|
|
69875
70158
|
}
|
|
69876
|
-
|
|
70159
|
+
writeFileSync9(path40.join(stage, ".workit-root"), realSrc + `
|
|
69877
70160
|
`, "utf8");
|
|
69878
70161
|
if (!samePluginContent(realSrc, stage, dest))
|
|
69879
70162
|
throw new Error("staged adapter content is incomplete");
|
|
@@ -69896,7 +70179,7 @@ function copyPluginDir(src, dest) {
|
|
|
69896
70179
|
return hadDir ? "Configured" : "Installed";
|
|
69897
70180
|
}
|
|
69898
70181
|
function applyCursorSettings(root, res) {
|
|
69899
|
-
|
|
70182
|
+
mkdirSync9(path40.dirname(res.cursorSettings), { recursive: true });
|
|
69900
70183
|
const settingsExisting = readExisting(res.cursorSettings);
|
|
69901
70184
|
if (settingsExisting.kind === "malformed") {
|
|
69902
70185
|
return {
|
|
@@ -69915,7 +70198,7 @@ function applyCursorSettings(root, res) {
|
|
|
69915
70198
|
detail: "already registered"
|
|
69916
70199
|
};
|
|
69917
70200
|
}
|
|
69918
|
-
|
|
70201
|
+
writeFileSync9(res.cursorSettings, JSON.stringify(settings.config, null, 2) + `
|
|
69919
70202
|
`, "utf8");
|
|
69920
70203
|
return {
|
|
69921
70204
|
platform: "cursor",
|
|
@@ -69924,7 +70207,7 @@ function applyCursorSettings(root, res) {
|
|
|
69924
70207
|
};
|
|
69925
70208
|
}
|
|
69926
70209
|
function applyCursorMcp(root, res) {
|
|
69927
|
-
|
|
70210
|
+
mkdirSync9(path40.dirname(res.cursorMcp), { recursive: true });
|
|
69928
70211
|
const mcpExisting = readExisting(res.cursorMcp);
|
|
69929
70212
|
if (mcpExisting.kind === "malformed") {
|
|
69930
70213
|
return {
|
|
@@ -69954,7 +70237,7 @@ function applyCursorMcp(root, res) {
|
|
|
69954
70237
|
detail: "already registered"
|
|
69955
70238
|
};
|
|
69956
70239
|
}
|
|
69957
|
-
|
|
70240
|
+
writeFileSync9(res.cursorMcp, JSON.stringify(mcp.config, null, 2) + `
|
|
69958
70241
|
`, "utf8");
|
|
69959
70242
|
return {
|
|
69960
70243
|
platform: "cursor",
|
|
@@ -70030,7 +70313,7 @@ function applySetupPreview(preview, options = {}) {
|
|
|
70030
70313
|
let cursorCopyOk = false;
|
|
70031
70314
|
for (const mutation of preview.mutations) {
|
|
70032
70315
|
if (mutation.type === "install-host") {
|
|
70033
|
-
const expectedPath = mutation.platform === "cursor" ?
|
|
70316
|
+
const expectedPath = mutation.platform === "cursor" ? path40.join(res.home, ".cursor", "plugins", "local", ".workit-package-bootstrap") : mutation.platform === "codex" ? path40.join(res.env.CODEX_HOME ?? path40.join(res.home, ".codex"), "plugins", "cache", "workflow-toolkit", "workit") : mutation.platform === "pi" ? path40.join(res.env.PI_CODING_AGENT_DIR ?? path40.join(res.home, ".pi", "agent"), "settings.json") : mutation.platform === "claude-code" ? claudeInstallRecord(res.home, res.env) : "";
|
|
70034
70317
|
if (mutation.path !== expectedPath) {
|
|
70035
70318
|
entries.push({
|
|
70036
70319
|
platform: mutation.platform,
|
|
@@ -70142,7 +70425,7 @@ function applySetupPreview(preview, options = {}) {
|
|
|
70142
70425
|
if (preview.projectRefused) {
|
|
70143
70426
|
entries.push({
|
|
70144
70427
|
platform: "core",
|
|
70145
|
-
file:
|
|
70428
|
+
file: path40.resolve(res.cwd),
|
|
70146
70429
|
status: "Skipped",
|
|
70147
70430
|
detail: preview.projectRefused
|
|
70148
70431
|
});
|
|
@@ -70223,12 +70506,12 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
70223
70506
|
return configured ?? fallback;
|
|
70224
70507
|
}, readConfigRecord = (file) => {
|
|
70225
70508
|
try {
|
|
70226
|
-
const value = JSON.parse(
|
|
70509
|
+
const value = JSON.parse(readFileSync18(file, "utf8"));
|
|
70227
70510
|
return isRecord6(value) ? value : null;
|
|
70228
70511
|
} catch {
|
|
70229
70512
|
return null;
|
|
70230
70513
|
}
|
|
70231
|
-
}, claudeInstallRecord = (home, env) =>
|
|
70514
|
+
}, claudeInstallRecord = (home, env) => path40.join(claudeConfigDir(home, env), "plugins", "installed_plugins.json"), resolveSetupPaths = (options, resolvedConfigDir) => {
|
|
70232
70515
|
const env = options.env ?? process.env;
|
|
70233
70516
|
const home = options.home ?? env.HOME ?? os13.homedir();
|
|
70234
70517
|
return {
|
|
@@ -70236,15 +70519,15 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
70236
70519
|
configDir: resolvedConfigDir,
|
|
70237
70520
|
cwd: options.cwd ?? process.cwd(),
|
|
70238
70521
|
env,
|
|
70239
|
-
opencodeConfig: options.opencodeConfig ??
|
|
70240
|
-
cursorSettings: options.cursorSettings ??
|
|
70241
|
-
cursorMcp: options.cursorMcp ??
|
|
70242
|
-
cursorPluginDir: options.cursorPluginDir ??
|
|
70522
|
+
opencodeConfig: options.opencodeConfig ?? path40.join(home, ".config", "opencode", "opencode.json"),
|
|
70523
|
+
cursorSettings: options.cursorSettings ?? path40.join(home, ".cursor", "settings.json"),
|
|
70524
|
+
cursorMcp: options.cursorMcp ?? path40.join(home, ".cursor", "mcp.json"),
|
|
70525
|
+
cursorPluginDir: options.cursorPluginDir ?? path40.join(home, ".cursor", "plugins", "local", "workit")
|
|
70243
70526
|
};
|
|
70244
70527
|
}, isRecord6 = (v) => v !== null && typeof v === "object" && !Array.isArray(v), readExisting = (p) => {
|
|
70245
70528
|
let raw;
|
|
70246
70529
|
try {
|
|
70247
|
-
raw =
|
|
70530
|
+
raw = readFileSync18(p, "utf8");
|
|
70248
70531
|
} catch {
|
|
70249
70532
|
if (existsSync17(p))
|
|
70250
70533
|
return { kind: "malformed", error: `${p} is not readable` };
|
|
@@ -70261,7 +70544,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
70261
70544
|
return { kind: "malformed", error: `${p} is not a JSON object` };
|
|
70262
70545
|
}, readFileSafe = (p) => {
|
|
70263
70546
|
try {
|
|
70264
|
-
return
|
|
70547
|
+
return readFileSync18(p, "utf8");
|
|
70265
70548
|
} catch {
|
|
70266
70549
|
return null;
|
|
70267
70550
|
}
|
|
@@ -70276,15 +70559,15 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
70276
70559
|
}
|
|
70277
70560
|
}, isAdapter = (root, platform) => {
|
|
70278
70561
|
try {
|
|
70279
|
-
const pkg = JSON.parse(
|
|
70562
|
+
const pkg = JSON.parse(readFileSync18(path40.join(root, "package.json"), "utf8"));
|
|
70280
70563
|
return pkg.name === `@brainervirus/workit-${platform}`;
|
|
70281
70564
|
} catch {
|
|
70282
70565
|
return false;
|
|
70283
70566
|
}
|
|
70284
70567
|
}, nodeResolvedAdapters = (platform) => {
|
|
70285
70568
|
const name = `@brainervirus/workit-${platform}`;
|
|
70286
|
-
const require2 = createRequire2(
|
|
70287
|
-
return (require2.resolve.paths(name) ?? []).map((dir) =>
|
|
70569
|
+
const require2 = createRequire2(path40.join(packageRoot(), "package.json"));
|
|
70570
|
+
return (require2.resolve.paths(name) ?? []).map((dir) => path40.join(dir, name));
|
|
70288
70571
|
}, realRoot = (root) => {
|
|
70289
70572
|
try {
|
|
70290
70573
|
return realpathSync8(root);
|
|
@@ -70300,7 +70583,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
70300
70583
|
if (!isDevOpenCodeAdapterRoot(root, opts.dev))
|
|
70301
70584
|
return OPENCODE_NPM_PIN;
|
|
70302
70585
|
for (const rel of ["src/plugin.ts", "dist/plugin.js"]) {
|
|
70303
|
-
const entry =
|
|
70586
|
+
const entry = path40.join(root, rel);
|
|
70304
70587
|
if (existsSync17(entry))
|
|
70305
70588
|
return `file://${entry}`;
|
|
70306
70589
|
}
|
|
@@ -70315,25 +70598,25 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
70315
70598
|
}
|
|
70316
70599
|
}, samePluginContent = (src, dest, pluginDir, relative = "") => {
|
|
70317
70600
|
try {
|
|
70318
|
-
for (const entry of
|
|
70601
|
+
for (const entry of readdirSync11(src, { withFileTypes: true })) {
|
|
70319
70602
|
if (entry.name === "node_modules")
|
|
70320
70603
|
continue;
|
|
70321
|
-
const source =
|
|
70322
|
-
const installed =
|
|
70323
|
-
const rel =
|
|
70604
|
+
const source = path40.join(src, entry.name);
|
|
70605
|
+
const installed = path40.join(dest, entry.name);
|
|
70606
|
+
const rel = path40.join(relative, entry.name);
|
|
70324
70607
|
if (entry.isDirectory()) {
|
|
70325
70608
|
if (!statSync7(installed).isDirectory() || !samePluginContent(source, installed, pluginDir, rel))
|
|
70326
70609
|
return false;
|
|
70327
70610
|
} else {
|
|
70328
|
-
const expected = rel === CURSOR_HOOKS_FILE ? localizedCursorHooks(
|
|
70329
|
-
if (!expected.equals(
|
|
70611
|
+
const expected = rel === CURSOR_HOOKS_FILE ? localizedCursorHooks(readFileSync18(source), pluginDir) : readFileSync18(source);
|
|
70612
|
+
if (!expected.equals(readFileSync18(installed)))
|
|
70330
70613
|
return false;
|
|
70331
70614
|
}
|
|
70332
70615
|
}
|
|
70333
|
-
for (const entry of
|
|
70334
|
-
if (existsSync17(
|
|
70616
|
+
for (const entry of readdirSync11(dest, { withFileTypes: true })) {
|
|
70617
|
+
if (existsSync17(path40.join(src, entry.name)))
|
|
70335
70618
|
continue;
|
|
70336
|
-
const rel =
|
|
70619
|
+
const rel = path40.join(relative, entry.name);
|
|
70337
70620
|
if (rel === ".workit-root")
|
|
70338
70621
|
continue;
|
|
70339
70622
|
if (relative === "rules" && entry.isFile() && entry.name.endsWith(".mdc"))
|
|
@@ -70346,32 +70629,32 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
70346
70629
|
}
|
|
70347
70630
|
}, preservedCursorRules = (src, dest) => {
|
|
70348
70631
|
const preserved = new Map;
|
|
70349
|
-
const sourceRules =
|
|
70350
|
-
const installedRules =
|
|
70632
|
+
const sourceRules = path40.join(src, "rules");
|
|
70633
|
+
const installedRules = path40.join(dest, "rules");
|
|
70351
70634
|
try {
|
|
70352
|
-
for (const entry of
|
|
70635
|
+
for (const entry of readdirSync11(installedRules, { withFileTypes: true })) {
|
|
70353
70636
|
if (!entry.isFile() || !entry.name.endsWith(".mdc"))
|
|
70354
70637
|
continue;
|
|
70355
|
-
if (existsSync17(
|
|
70638
|
+
if (existsSync17(path40.join(sourceRules, entry.name)))
|
|
70356
70639
|
continue;
|
|
70357
|
-
preserved.set(entry.name,
|
|
70640
|
+
preserved.set(entry.name, readFileSync18(path40.join(installedRules, entry.name)));
|
|
70358
70641
|
}
|
|
70359
70642
|
} catch {}
|
|
70360
70643
|
return preserved;
|
|
70361
70644
|
}, removeLegacyCursorDir = (res) => {
|
|
70362
|
-
const legacy =
|
|
70645
|
+
const legacy = path40.join(res.home, ".cursor", "plugins", "local", "workflow-toolkit");
|
|
70363
70646
|
if (legacy === res.cursorPluginDir || !existsSync17(legacy))
|
|
70364
70647
|
return;
|
|
70365
|
-
const legacyRules =
|
|
70648
|
+
const legacyRules = path40.join(legacy, "rules");
|
|
70366
70649
|
if (existsSync17(legacyRules)) {
|
|
70367
70650
|
try {
|
|
70368
|
-
|
|
70369
|
-
for (const entry of
|
|
70651
|
+
mkdirSync9(path40.join(res.cursorPluginDir, "rules"), { recursive: true });
|
|
70652
|
+
for (const entry of readdirSync11(legacyRules, { withFileTypes: true })) {
|
|
70370
70653
|
if (!entry.isFile() || !entry.name.endsWith(".mdc"))
|
|
70371
70654
|
continue;
|
|
70372
|
-
const target =
|
|
70655
|
+
const target = path40.join(res.cursorPluginDir, "rules", entry.name);
|
|
70373
70656
|
if (!existsSync17(target))
|
|
70374
|
-
copyFileSync5(
|
|
70657
|
+
copyFileSync5(path40.join(legacyRules, entry.name), target);
|
|
70375
70658
|
}
|
|
70376
70659
|
} catch {}
|
|
70377
70660
|
}
|
|
@@ -70405,16 +70688,16 @@ var init_setup = __esm(() => {
|
|
|
70405
70688
|
{ envKey: "WORKFLOW_GITHUB_HOST", affects: "vcs.json github.host" }
|
|
70406
70689
|
];
|
|
70407
70690
|
SETUP_OVERRIDES = [...YT_OVERRIDES, ...VCS_OVERRIDES];
|
|
70408
|
-
CURSOR_HOOKS_FILE =
|
|
70691
|
+
CURSOR_HOOKS_FILE = path40.join("hooks", "hooks-cursor.json");
|
|
70409
70692
|
});
|
|
70410
70693
|
|
|
70411
70694
|
// packages/workit-core/src/core/workspace-branch-policy.ts
|
|
70412
|
-
import { mkdirSync as
|
|
70413
|
-
import
|
|
70695
|
+
import { mkdirSync as mkdirSync10, readFileSync as readFileSync19, renameSync as renameSync6, rmSync as rmSync6, writeFileSync as writeFileSync10 } from "node:fs";
|
|
70696
|
+
import path41 from "node:path";
|
|
70414
70697
|
import { isDeepStrictEqual as isDeepStrictEqual3 } from "node:util";
|
|
70415
70698
|
function applyWorkspaceBranchPolicy(opts) {
|
|
70416
70699
|
const { workspace_root, env = process.env } = opts;
|
|
70417
|
-
const dir =
|
|
70700
|
+
const dir = path41.join(env.WORKFLOW_TOOLKIT_CONFIG ?? configDir());
|
|
70418
70701
|
const {
|
|
70419
70702
|
status,
|
|
70420
70703
|
path: wsPath,
|
|
@@ -70426,7 +70709,7 @@ function applyWorkspaceBranchPolicy(opts) {
|
|
|
70426
70709
|
if (status === "malformed" || status === "invalid")
|
|
70427
70710
|
return { ok: false, error: workspacesError ?? `invalid workspaces.json: ${wsPath}` };
|
|
70428
70711
|
const detection = detectBranchPolicy(workspace_root);
|
|
70429
|
-
const name = String(env.WORKFLOW_BP_NAME ??
|
|
70712
|
+
const name = String(env.WORKFLOW_BP_NAME ?? path41.basename(workspace_root));
|
|
70430
70713
|
const integration = env.WORKFLOW_BP_INTEGRATION ?? detection.integration;
|
|
70431
70714
|
const policy = {
|
|
70432
70715
|
preset: detection.preset,
|
|
@@ -70475,10 +70758,10 @@ function applyWorkspaceBranchPolicy(opts) {
|
|
|
70475
70758
|
ok: false,
|
|
70476
70759
|
error: `workspaces.json changed while applying the branch policy: ${wsPath}`
|
|
70477
70760
|
};
|
|
70478
|
-
|
|
70761
|
+
mkdirSync10(path41.dirname(wsPath), { recursive: true });
|
|
70479
70762
|
const tmp = `${wsPath}.${process.pid}.tmp`;
|
|
70480
70763
|
try {
|
|
70481
|
-
|
|
70764
|
+
writeFileSync10(tmp, JSON.stringify({ ...document2, workspaces: next }, null, 2) + `
|
|
70482
70765
|
`, "utf8");
|
|
70483
70766
|
if (workspacesRevision(readFileSafe2(wsPath)) !== revision) {
|
|
70484
70767
|
rmSync6(tmp, { force: true });
|
|
@@ -70507,7 +70790,7 @@ function applyWorkspaceBranchPolicy(opts) {
|
|
|
70507
70790
|
}
|
|
70508
70791
|
var readFileSafe2 = (p) => {
|
|
70509
70792
|
try {
|
|
70510
|
-
return
|
|
70793
|
+
return readFileSync19(p, "utf8");
|
|
70511
70794
|
} catch {
|
|
70512
70795
|
return null;
|
|
70513
70796
|
}
|
|
@@ -70760,7 +71043,7 @@ var init_logic = __esm(() => {
|
|
|
70760
71043
|
|
|
70761
71044
|
// packages/workit-cli/src/wizard-state.ts
|
|
70762
71045
|
import { existsSync as existsSync18, statSync as statSync8 } from "node:fs";
|
|
70763
|
-
import
|
|
71046
|
+
import path42 from "node:path";
|
|
70764
71047
|
import { isDeepStrictEqual as isDeepStrictEqual4 } from "node:util";
|
|
70765
71048
|
function resolveBasePath(values, env = process.env) {
|
|
70766
71049
|
return env.WORKFLOW_WORKSPACE_ROOT?.trim() || values.basePath.trim();
|
|
@@ -71287,8 +71570,8 @@ var NEXT, PREV, skipsCustomBranch = (screen, preset) => (screen === "branchAllow
|
|
|
71287
71570
|
const p = value.trim();
|
|
71288
71571
|
if (!p)
|
|
71289
71572
|
return "workspace root path is required";
|
|
71290
|
-
return !
|
|
71291
|
-
}, skipsBranchPolicy = (screen, basePath) => (screen === "branchPolicy" || screen === "branchPolicyDevelop") && !existsSync18(
|
|
71573
|
+
return !path42.isAbsolute(p) || !isDirectory(p) ? `invalid workspace root "${p}" — enter an existing absolute directory` : null;
|
|
71574
|
+
}, skipsBranchPolicy = (screen, basePath) => (screen === "branchPolicy" || screen === "branchPolicyDevelop") && !existsSync18(path42.join(basePath, ".git")), decodeBranchPreset = (value, fallback) => value === "gitflow" || value === "github-flow" || value === "trunk-based" || value === "custom" ? value : fallback, decodeVcsProvider = (value, fallback) => value === "gitlab" || value === "github" || value === "skip" ? value : fallback, decodeIssueTracker = (value, fallback) => value === "youtrack" || value === "github" || value === "gitlab" || value === "none" ? value : fallback, GITHUB_ISSUES, withGithubIssues = (draft, tracker) => tracker === "github" ? { ...draft, issues: { ...GITHUB_ISSUES } } : draft;
|
|
71292
71575
|
var init_wizard_state = __esm(() => {
|
|
71293
71576
|
init_config();
|
|
71294
71577
|
init_workspaces();
|
|
@@ -71347,9 +71630,9 @@ var init_wizard_state = __esm(() => {
|
|
|
71347
71630
|
});
|
|
71348
71631
|
|
|
71349
71632
|
// packages/workit-cli/src/admin/uninstall.ts
|
|
71350
|
-
import { existsSync as existsSync19, readFileSync as
|
|
71633
|
+
import { existsSync as existsSync19, readFileSync as readFileSync20, realpathSync as realpathSync9, rmSync as rmSync7, writeFileSync as writeFileSync11 } from "node:fs";
|
|
71351
71634
|
import os14 from "node:os";
|
|
71352
|
-
import
|
|
71635
|
+
import path43 from "node:path";
|
|
71353
71636
|
function cleanCursorSettings(settings, pluginDir) {
|
|
71354
71637
|
const next = { ...settings };
|
|
71355
71638
|
let changed = false;
|
|
@@ -71522,7 +71805,7 @@ function planUninstall(paths = {}) {
|
|
|
71522
71805
|
plan.actions.push({
|
|
71523
71806
|
kind: "edit-json-remove",
|
|
71524
71807
|
path: file,
|
|
71525
|
-
detail: `remove Workit's permission block from ${
|
|
71808
|
+
detail: `remove Workit's permission block from ${path43.basename(file)}`
|
|
71526
71809
|
});
|
|
71527
71810
|
}
|
|
71528
71811
|
if (existsSync19(res.codexRules))
|
|
@@ -71556,8 +71839,8 @@ function applyUninstall(plan, paths = {}) {
|
|
|
71556
71839
|
status = outcome.status;
|
|
71557
71840
|
detail = outcome.detail;
|
|
71558
71841
|
} else if (action.kind === "remove-dir") {
|
|
71559
|
-
const resolved =
|
|
71560
|
-
const allowed = canonicalRemoveDirAllowed(resolved, res) || resolved ===
|
|
71842
|
+
const resolved = path43.resolve(action.path);
|
|
71843
|
+
const allowed = canonicalRemoveDirAllowed(resolved, res) || resolved === path43.resolve(res.codexPluginDir) && path43.basename(resolved) === "workit" && path43.basename(path43.dirname(resolved)) === "plugins";
|
|
71561
71844
|
if (!allowed) {
|
|
71562
71845
|
status = "failed";
|
|
71563
71846
|
detail = `refusing to remove non-canonical plugin directory: ${resolved}`;
|
|
@@ -71599,17 +71882,17 @@ var resolveUninstallPaths = (options = {}) => {
|
|
|
71599
71882
|
claudeSettings: permissionTarget("claude-code", permissionPaths).file,
|
|
71600
71883
|
cursorCliConfig: permissionTarget("cursor", permissionPaths).file,
|
|
71601
71884
|
codexRules: permissionTarget("codex", permissionPaths).file,
|
|
71602
|
-
opencodeConfig: options.opencodeConfig ??
|
|
71603
|
-
cursorSettings: options.cursorSettings ??
|
|
71604
|
-
cursorMcp: options.cursorMcp ??
|
|
71605
|
-
cursorPluginDir: options.cursorPluginDir ??
|
|
71606
|
-
codexPluginDir:
|
|
71607
|
-
piConfig:
|
|
71885
|
+
opencodeConfig: options.opencodeConfig ?? path43.join(home, ".config", "opencode", "opencode.json"),
|
|
71886
|
+
cursorSettings: options.cursorSettings ?? path43.join(home, ".cursor", "settings.json"),
|
|
71887
|
+
cursorMcp: options.cursorMcp ?? path43.join(home, ".cursor", "mcp.json"),
|
|
71888
|
+
cursorPluginDir: options.cursorPluginDir ?? path43.join(home, ".cursor", "plugins", "local", "workit"),
|
|
71889
|
+
codexPluginDir: path43.join(home, ".codex", "plugins", "workit"),
|
|
71890
|
+
piConfig: path43.join(home, ".pi", "config.json")
|
|
71608
71891
|
};
|
|
71609
71892
|
}, isRecord7 = (v) => v !== null && typeof v === "object" && !Array.isArray(v), readJsonRecord = (file) => {
|
|
71610
71893
|
let raw;
|
|
71611
71894
|
try {
|
|
71612
|
-
raw =
|
|
71895
|
+
raw = readFileSync20(file, "utf8");
|
|
71613
71896
|
} catch {
|
|
71614
71897
|
if (existsSync19(file))
|
|
71615
71898
|
return { kind: "malformed", error: `${file} is not readable` };
|
|
@@ -71622,8 +71905,8 @@ var resolveUninstallPaths = (options = {}) => {
|
|
|
71622
71905
|
return { kind: "malformed", error: `${file} is not valid JSON` };
|
|
71623
71906
|
}
|
|
71624
71907
|
}, stripTrailingSep = (p) => {
|
|
71625
|
-
const j =
|
|
71626
|
-
return
|
|
71908
|
+
const j = path43.join(p);
|
|
71909
|
+
return path43.dirname(j) === j ? j : j.replace(/[\\/]+$/, "");
|
|
71627
71910
|
}, CURSOR_LEGACY_IDENTITIES, permissionPathsOf = (paths) => {
|
|
71628
71911
|
const env = paths.env ?? process.env;
|
|
71629
71912
|
return {
|
|
@@ -71650,8 +71933,8 @@ var resolveUninstallPaths = (options = {}) => {
|
|
|
71650
71933
|
return cleanPiConfig;
|
|
71651
71934
|
return null;
|
|
71652
71935
|
}, canonicalRemoveDirAllowed = (actionPath, res) => {
|
|
71653
|
-
const expected =
|
|
71654
|
-
if (!(actionPath === expected &&
|
|
71936
|
+
const expected = path43.resolve(res.cursorPluginDir);
|
|
71937
|
+
if (!(actionPath === expected && path43.basename(expected) === "workit" && path43.basename(path43.dirname(expected)) === "local" && path43.basename(path43.dirname(path43.dirname(expected))) === "plugins")) {
|
|
71655
71938
|
return false;
|
|
71656
71939
|
}
|
|
71657
71940
|
try {
|
|
@@ -71674,7 +71957,7 @@ var resolveUninstallPaths = (options = {}) => {
|
|
|
71674
71957
|
`;
|
|
71675
71958
|
let current;
|
|
71676
71959
|
try {
|
|
71677
|
-
current =
|
|
71960
|
+
current = readFileSync20(target, "utf8");
|
|
71678
71961
|
} catch (error) {
|
|
71679
71962
|
return {
|
|
71680
71963
|
status: "failed",
|
|
@@ -71685,7 +71968,7 @@ var resolveUninstallPaths = (options = {}) => {
|
|
|
71685
71968
|
return { status: "skipped", detail: "already clean" };
|
|
71686
71969
|
}
|
|
71687
71970
|
try {
|
|
71688
|
-
|
|
71971
|
+
writeFileSync11(target, serialized, "utf8");
|
|
71689
71972
|
} catch (error) {
|
|
71690
71973
|
return {
|
|
71691
71974
|
status: "failed",
|
|
@@ -71703,7 +71986,7 @@ var resolveUninstallPaths = (options = {}) => {
|
|
|
71703
71986
|
};
|
|
71704
71987
|
const home = paths.home ?? paths.env?.HOME ?? os14.homedir();
|
|
71705
71988
|
const env = paths.env ?? process.env;
|
|
71706
|
-
const recorded = claudeWorkitInstalls(home, env, action.cwd).some((install) => install.id === id && install.scope === scope && (install.projectPath === null ? action.cwd === null :
|
|
71989
|
+
const recorded = claudeWorkitInstalls(home, env, action.cwd).some((install) => install.id === id && install.scope === scope && (install.projectPath === null ? action.cwd === null : path43.resolve(install.projectPath) === path43.resolve(action.cwd ?? "")));
|
|
71707
71990
|
if (!recorded)
|
|
71708
71991
|
return { status: "skipped", detail: `${id} (${scope} scope) is no longer installed` };
|
|
71709
71992
|
const executable = findHostExecutable("claude", { home, env });
|
|
@@ -74465,14 +74748,14 @@ import {
|
|
|
74465
74748
|
existsSync as existsSync20,
|
|
74466
74749
|
mkdtempSync as mkdtempSync3,
|
|
74467
74750
|
rmSync as rmSync8,
|
|
74468
|
-
readFileSync as
|
|
74469
|
-
mkdirSync as
|
|
74751
|
+
readFileSync as readFileSync21,
|
|
74752
|
+
mkdirSync as mkdirSync11,
|
|
74470
74753
|
copyFileSync as copyFileSync6,
|
|
74471
74754
|
chmodSync as chmodSync2,
|
|
74472
74755
|
cpSync as cpSync5,
|
|
74473
74756
|
lstatSync as lstatSync7
|
|
74474
74757
|
} from "node:fs";
|
|
74475
|
-
import
|
|
74758
|
+
import path44 from "node:path";
|
|
74476
74759
|
import os16 from "node:os";
|
|
74477
74760
|
import { createHash as createHash15 } from "node:crypto";
|
|
74478
74761
|
function previewUpgrade(hosts = HOSTS2, deps = {}) {
|
|
@@ -74496,9 +74779,9 @@ function previewUpgrade(hosts = HOSTS2, deps = {}) {
|
|
|
74496
74779
|
for (const file of [
|
|
74497
74780
|
paths.opencodeConfig,
|
|
74498
74781
|
paths.opencodeConfig + "c",
|
|
74499
|
-
|
|
74500
|
-
|
|
74501
|
-
|
|
74782
|
+
path44.join(home, ".cursor/settings.json"),
|
|
74783
|
+
path44.join(home, ".cursor/mcp.json"),
|
|
74784
|
+
path44.join(home, ".cursor/plugins/local/workit/package.json"),
|
|
74502
74785
|
paths.codexConfig,
|
|
74503
74786
|
paths.piSettings
|
|
74504
74787
|
])
|
|
@@ -74513,16 +74796,16 @@ function previewUpgrade(hosts = HOSTS2, deps = {}) {
|
|
|
74513
74796
|
});
|
|
74514
74797
|
const installedSources = sources(paths, run, hosts);
|
|
74515
74798
|
if (installedSources.some((source) => source.host === "opencode")) {
|
|
74516
|
-
const scratch = mkdtempSync3(
|
|
74799
|
+
const scratch = mkdtempSync3(path44.join(os16.tmpdir(), "workit-upgrade-opencode-"));
|
|
74517
74800
|
let probe;
|
|
74518
74801
|
try {
|
|
74519
74802
|
probe = runner({
|
|
74520
74803
|
...deps,
|
|
74521
74804
|
env: {
|
|
74522
74805
|
...deps.env,
|
|
74523
|
-
XDG_DATA_HOME:
|
|
74524
|
-
XDG_STATE_HOME:
|
|
74525
|
-
XDG_CACHE_HOME:
|
|
74806
|
+
XDG_DATA_HOME: path44.join(scratch, "data"),
|
|
74807
|
+
XDG_STATE_HOME: path44.join(scratch, "state"),
|
|
74808
|
+
XDG_CACHE_HOME: path44.join(scratch, "cache")
|
|
74526
74809
|
}
|
|
74527
74810
|
})("opencode", ["--version"]);
|
|
74528
74811
|
} finally {
|
|
@@ -74568,7 +74851,7 @@ function previewUpgrade(hosts = HOSTS2, deps = {}) {
|
|
|
74568
74851
|
env: deps.env,
|
|
74569
74852
|
cwd: home,
|
|
74570
74853
|
packageVersion: latest.stdout.trim(),
|
|
74571
|
-
targetDir:
|
|
74854
|
+
targetDir: path44.join(home, ".cursor/plugins/local/workit")
|
|
74572
74855
|
});
|
|
74573
74856
|
plan.entries.push({
|
|
74574
74857
|
host: source.host,
|
|
@@ -74598,11 +74881,11 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
74598
74881
|
ok: false,
|
|
74599
74882
|
error: "Stop the selected running hosts before upgrading their loaded plugins"
|
|
74600
74883
|
};
|
|
74601
|
-
const backup =
|
|
74602
|
-
|
|
74884
|
+
const backup = path44.join(home, ".local/state/workit/upgrades", new Date().toISOString().replaceAll(":", "-"));
|
|
74885
|
+
mkdirSync11(backup, { recursive: true, mode: 448 });
|
|
74603
74886
|
for (const file of Object.keys(plan.configDigests))
|
|
74604
74887
|
if (existsSync20(file)) {
|
|
74605
|
-
const target =
|
|
74888
|
+
const target = path44.join(backup, createHash15("sha256").update(file).digest("hex").slice(0, 12) + "-" + path44.basename(file));
|
|
74606
74889
|
copyFileSync6(file, target);
|
|
74607
74890
|
chmodSync2(target, 384);
|
|
74608
74891
|
}
|
|
@@ -74619,9 +74902,9 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
74619
74902
|
`, 384);
|
|
74620
74903
|
}
|
|
74621
74904
|
const run = runner(deps);
|
|
74622
|
-
const cursorRoot =
|
|
74905
|
+
const cursorRoot = path44.join(home, ".cursor/plugins/local/workit");
|
|
74623
74906
|
if (plan.entries.some((entry) => entry.host === "cursor") && existsSync20(cursorRoot))
|
|
74624
|
-
cpSync5(cursorRoot,
|
|
74907
|
+
cpSync5(cursorRoot, path44.join(backup, "cursor-package"), { recursive: true });
|
|
74625
74908
|
for (const entry of plan.entries) {
|
|
74626
74909
|
if (entry.host === "opencode")
|
|
74627
74910
|
return {
|
|
@@ -74641,7 +74924,7 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
74641
74924
|
{
|
|
74642
74925
|
type: "install-host",
|
|
74643
74926
|
platform: "cursor",
|
|
74644
|
-
path:
|
|
74927
|
+
path: path44.join(home, ".cursor/plugins/local/.workit-package-bootstrap"),
|
|
74645
74928
|
commands: entry.commands.map((command) => ({
|
|
74646
74929
|
...command,
|
|
74647
74930
|
purpose: command.purpose ?? "Upgrade Cursor"
|
|
@@ -74650,7 +74933,7 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
74650
74933
|
{
|
|
74651
74934
|
type: "install-adapter",
|
|
74652
74935
|
platform: "cursor",
|
|
74653
|
-
path:
|
|
74936
|
+
path: path44.join(home, ".cursor/plugins/local/workit")
|
|
74654
74937
|
}
|
|
74655
74938
|
]
|
|
74656
74939
|
};
|
|
@@ -74664,7 +74947,7 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
74664
74947
|
return { exitCode: outcome.status ?? 1, stdout: outcome.stdout, stderr: "" };
|
|
74665
74948
|
}
|
|
74666
74949
|
});
|
|
74667
|
-
const pkg = object2(
|
|
74950
|
+
const pkg = object2(path44.join(home, ".cursor/plugins/local/workit/package.json"));
|
|
74668
74951
|
if (!result.ok || pkg?.version !== entry.latest)
|
|
74669
74952
|
return {
|
|
74670
74953
|
ok: false,
|
|
@@ -74698,15 +74981,15 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
74698
74981
|
const currentRoot = run("npm", ["root", "--global"]);
|
|
74699
74982
|
if (currentRoot.status !== 0 || currentRoot.stdout.trim() !== plan.cli.root)
|
|
74700
74983
|
return { ok: false, backup, error: "Global npm location changed; preview again" };
|
|
74701
|
-
const cliBackup =
|
|
74702
|
-
cpSync5(
|
|
74984
|
+
const cliBackup = path44.join(backup, "cli-package");
|
|
74985
|
+
cpSync5(path44.join(plan.cli.root, "@brainervirus/workit-cli"), cliBackup, { recursive: true });
|
|
74703
74986
|
if (run("npm", ["install", "--global", `@brainervirus/workit-cli@${plan.cli.latest}`]).status !== 0)
|
|
74704
74987
|
return {
|
|
74705
74988
|
ok: false,
|
|
74706
74989
|
backup,
|
|
74707
|
-
error: `CLI update failed; preserved package at ${cliBackup}; use npm to repair or run node ${
|
|
74990
|
+
error: `CLI update failed; preserved package at ${cliBackup}; use npm to repair or run node ${path44.join(cliBackup, "dist/index.js")}`
|
|
74708
74991
|
};
|
|
74709
|
-
const installed = object2(
|
|
74992
|
+
const installed = object2(path44.join(plan.cli.root, "@brainervirus/workit-cli/package.json"));
|
|
74710
74993
|
if (installed?.name !== "@brainervirus/workit-cli" || installed.version !== plan.cli.latest)
|
|
74711
74994
|
return {
|
|
74712
74995
|
ok: false,
|
|
@@ -74731,12 +75014,12 @@ async function runUpgradeCommand(argv, deps = {}) {
|
|
|
74731
75014
|
if (flags.has("--cli")) {
|
|
74732
75015
|
const run = runner(deps);
|
|
74733
75016
|
const root = run("npm", ["root", "--global"]);
|
|
74734
|
-
if (root.status !== 0 || !
|
|
75017
|
+
if (root.status !== 0 || !path44.isAbsolute(root.stdout.trim())) {
|
|
74735
75018
|
plan.blocked.push("Global npm location could not be verified");
|
|
74736
75019
|
} else {
|
|
74737
|
-
const packageFile =
|
|
75020
|
+
const packageFile = path44.join(root.stdout.trim(), "@brainervirus/workit-cli/package.json");
|
|
74738
75021
|
const pkg = object2(packageFile);
|
|
74739
|
-
if (pkg?.name !== "@brainervirus/workit-cli" || lstatSync7(
|
|
75022
|
+
if (pkg?.name !== "@brainervirus/workit-cli" || lstatSync7(path44.dirname(packageFile)).isSymbolicLink()) {
|
|
74740
75023
|
plan.skipped.push({
|
|
74741
75024
|
host: "cli",
|
|
74742
75025
|
reason: "No managed global CLI install (local links preserved); use npx @brainervirus/workit-cli@latest"
|
|
@@ -74859,37 +75142,37 @@ var HOSTS2, upgradePaths = (deps) => {
|
|
|
74859
75142
|
...process.env,
|
|
74860
75143
|
...deps.home || deps.env?.HOME ? {
|
|
74861
75144
|
HOME: home,
|
|
74862
|
-
CODEX_HOME:
|
|
74863
|
-
PI_CODING_AGENT_DIR:
|
|
74864
|
-
XDG_CONFIG_HOME:
|
|
75145
|
+
CODEX_HOME: path44.join(home, ".codex"),
|
|
75146
|
+
PI_CODING_AGENT_DIR: path44.join(home, ".pi/agent"),
|
|
75147
|
+
XDG_CONFIG_HOME: path44.join(home, ".config"),
|
|
74865
75148
|
WORKFLOW_TOOLKIT_CONFIG: undefined,
|
|
74866
75149
|
WORKFLOW_TOOLKIT_CONFIG_DIR: undefined
|
|
74867
75150
|
} : {},
|
|
74868
75151
|
...deps.env,
|
|
74869
75152
|
HOME: home
|
|
74870
75153
|
};
|
|
74871
|
-
const xdg = env.XDG_CONFIG_HOME ||
|
|
75154
|
+
const xdg = env.XDG_CONFIG_HOME || path44.join(home, ".config");
|
|
74872
75155
|
return {
|
|
74873
75156
|
home,
|
|
74874
75157
|
env,
|
|
74875
|
-
configDir: env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ??
|
|
74876
|
-
opencodeConfig:
|
|
74877
|
-
piSettings:
|
|
74878
|
-
codexConfig:
|
|
75158
|
+
configDir: env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path44.join(xdg, "workit"),
|
|
75159
|
+
opencodeConfig: path44.join(xdg, "opencode/opencode.json"),
|
|
75160
|
+
piSettings: path44.join(env.PI_CODING_AGENT_DIR ?? path44.join(home, ".pi/agent"), "settings.json"),
|
|
75161
|
+
codexConfig: path44.join(env.CODEX_HOME ?? path44.join(home, ".codex"), "config.toml")
|
|
74879
75162
|
};
|
|
74880
75163
|
}, object2 = (file) => {
|
|
74881
75164
|
if (!existsSync20(file))
|
|
74882
75165
|
return null;
|
|
74883
75166
|
let data;
|
|
74884
75167
|
try {
|
|
74885
|
-
data = JSON.parse(
|
|
75168
|
+
data = JSON.parse(readFileSync21(file, "utf8"));
|
|
74886
75169
|
} catch {
|
|
74887
75170
|
throw new Error(`${file} is not valid JSON; use the native host to inspect JSONC settings`);
|
|
74888
75171
|
}
|
|
74889
75172
|
if (!data || typeof data !== "object" || Array.isArray(data))
|
|
74890
75173
|
throw new Error(`${file} is not a configuration object`);
|
|
74891
75174
|
return data;
|
|
74892
|
-
}, digest2 = (file) => existsSync20(file) ? createHash15("sha256").update(
|
|
75175
|
+
}, digest2 = (file) => existsSync20(file) ? createHash15("sha256").update(readFileSync21(file)).digest("hex") : "missing", runner = (deps) => deps.run ?? ((command, args) => {
|
|
74893
75176
|
const { home, env } = upgradePaths(deps);
|
|
74894
75177
|
let step;
|
|
74895
75178
|
try {
|
|
@@ -74915,9 +75198,9 @@ var HOSTS2, upgradePaths = (deps) => {
|
|
|
74915
75198
|
for (const pin of plugins)
|
|
74916
75199
|
if (typeof pin === "string" && isWorkitPlugin(pin))
|
|
74917
75200
|
result.push(classify("opencode", pin));
|
|
74918
|
-
const cursor = hosts.includes("cursor") ? object2(
|
|
75201
|
+
const cursor = hosts.includes("cursor") ? object2(path44.join(home, ".cursor/plugins/local/workit/package.json")) : null;
|
|
74919
75202
|
if (cursor?.name === "@brainervirus/workit-cursor") {
|
|
74920
|
-
const mcp = object2(
|
|
75203
|
+
const mcp = object2(path44.join(home, ".cursor/mcp.json"));
|
|
74921
75204
|
const args = mcp?.mcpServers?.workit?.args ?? [];
|
|
74922
75205
|
const selector = args.find((arg) => typeof arg === "string" && arg.startsWith("--package="));
|
|
74923
75206
|
result.push(classify("cursor", typeof selector === "string" ? selector.slice(10) : "local"));
|
|
@@ -74930,7 +75213,7 @@ var HOSTS2, upgradePaths = (deps) => {
|
|
|
74930
75213
|
if (typeof source !== "string")
|
|
74931
75214
|
continue;
|
|
74932
75215
|
const npm = /^(?:npm:)?@brainervirus\/workit-pi(?:@[^/]+)?$/.test(source);
|
|
74933
|
-
const local =
|
|
75216
|
+
const local = path44.isAbsolute(source) && source.replaceAll("\\", "/").endsWith("/packages/workit-pi") && object2(path44.join(source, "package.json"))?.name === "@brainervirus/workit-pi";
|
|
74934
75217
|
if (npm || local)
|
|
74935
75218
|
result.push(classify("pi", source));
|
|
74936
75219
|
}
|
|
@@ -74977,9 +75260,9 @@ var HOSTS2, upgradePaths = (deps) => {
|
|
|
74977
75260
|
}, piInstalledVersion = (listing, selector) => {
|
|
74978
75261
|
const lines = listing.split(/\r?\n/).map((line) => line.trim());
|
|
74979
75262
|
const index = lines.indexOf(selector);
|
|
74980
|
-
if (index < 0 || !lines[index + 1] || !
|
|
75263
|
+
if (index < 0 || !lines[index + 1] || !path44.isAbsolute(lines[index + 1]))
|
|
74981
75264
|
return;
|
|
74982
|
-
const pkg = object2(
|
|
75265
|
+
const pkg = object2(path44.join(lines[index + 1], "package.json"));
|
|
74983
75266
|
return pkg?.name === "@brainervirus/workit-pi" ? pkg.version : undefined;
|
|
74984
75267
|
}, versionAtLeast = (installed, latest) => {
|
|
74985
75268
|
if (!/^\d+\.\d+\.\d+$/.test(installed))
|
|
@@ -75033,7 +75316,7 @@ var init_launch = __esm(() => {
|
|
|
75033
75316
|
// packages/workit-core/src/knowledge.ts
|
|
75034
75317
|
import { spawnSync as spawnSync18 } from "node:child_process";
|
|
75035
75318
|
import fs20 from "node:fs";
|
|
75036
|
-
import
|
|
75319
|
+
import path45 from "node:path";
|
|
75037
75320
|
function lintKnowledge(root) {
|
|
75038
75321
|
const seen = new Set;
|
|
75039
75322
|
const unreadable = [];
|
|
@@ -75137,7 +75420,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
|
|
|
75137
75420
|
const end = lines.indexOf("---", 1);
|
|
75138
75421
|
return end === -1 ? lines : [...lines.slice(0, end + 1).map(() => ""), ...lines.slice(end + 1)];
|
|
75139
75422
|
}, read = (root, file) => {
|
|
75140
|
-
const full =
|
|
75423
|
+
const full = path45.join(root, file);
|
|
75141
75424
|
try {
|
|
75142
75425
|
fs20.lstatSync(full);
|
|
75143
75426
|
} catch {
|
|
@@ -75178,7 +75461,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
|
|
|
75178
75461
|
}
|
|
75179
75462
|
}, brokenLinks = (root, doc, tracked) => {
|
|
75180
75463
|
const findings = [];
|
|
75181
|
-
const base =
|
|
75464
|
+
const base = path45.dirname(path45.join(root, doc.file));
|
|
75182
75465
|
const missing = (target, line, how) => findings.push({
|
|
75183
75466
|
rule: "broken-link",
|
|
75184
75467
|
file: doc.file,
|
|
@@ -75197,7 +75480,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
|
|
|
75197
75480
|
const local = localTarget(target);
|
|
75198
75481
|
if (!local)
|
|
75199
75482
|
continue;
|
|
75200
|
-
const resolved = local.startsWith("/") ?
|
|
75483
|
+
const resolved = local.startsWith("/") ? path45.join(root, local) : path45.resolve(base, local);
|
|
75201
75484
|
if (!exists2(resolved))
|
|
75202
75485
|
missing(target, index + 1, "link");
|
|
75203
75486
|
}
|
|
@@ -75207,9 +75490,9 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
|
|
|
75207
75490
|
continue;
|
|
75208
75491
|
const relative = /^\.\.?\//.test(candidate);
|
|
75209
75492
|
const first = candidate.split("/")[0];
|
|
75210
|
-
if (!relative && !(tracked ? tracked.has(first) : exists2(
|
|
75493
|
+
if (!relative && !(tracked ? tracked.has(first) : exists2(path45.join(root, first))))
|
|
75211
75494
|
continue;
|
|
75212
|
-
const resolved = relative ?
|
|
75495
|
+
const resolved = relative ? path45.resolve(base, candidate) : path45.join(root, candidate);
|
|
75213
75496
|
if (!exists2(resolved))
|
|
75214
75497
|
missing(span, index + 1, "pointer");
|
|
75215
75498
|
}
|
|
@@ -75535,7 +75818,7 @@ import { spawn, spawnSync as spawnSync19 } from "node:child_process";
|
|
|
75535
75818
|
import { createHash as createHash16 } from "node:crypto";
|
|
75536
75819
|
import fs21 from "node:fs";
|
|
75537
75820
|
import os17 from "node:os";
|
|
75538
|
-
import
|
|
75821
|
+
import path46 from "node:path";
|
|
75539
75822
|
import { StringDecoder } from "node:string_decoder";
|
|
75540
75823
|
function tailLines(text, lines = TAIL_LINES) {
|
|
75541
75824
|
const all = text.replace(/\r\n?/gu, `
|
|
@@ -75655,7 +75938,7 @@ function planSpawn(argv, options) {
|
|
|
75655
75938
|
return { file: argv[0], args: [], verbatim: false, shell: true };
|
|
75656
75939
|
if (options.platform !== "win32")
|
|
75657
75940
|
return { file: argv[0], args: argv.slice(1), verbatim: false, shell: false };
|
|
75658
|
-
const win =
|
|
75941
|
+
const win = path46.win32;
|
|
75659
75942
|
const isFile = options.isFile ?? ((file) => {
|
|
75660
75943
|
try {
|
|
75661
75944
|
return fs21.statSync(file).isFile();
|
|
@@ -75817,10 +76100,10 @@ function runCheckCommand(argv, options) {
|
|
|
75817
76100
|
function storeLog(storeRoot, log) {
|
|
75818
76101
|
const digest = logDigest(log);
|
|
75819
76102
|
const ref = `blobs/logs/${digest.slice("sha256:".length)}.log`;
|
|
75820
|
-
const file =
|
|
76103
|
+
const file = path46.join(storeRoot, ref);
|
|
75821
76104
|
try {
|
|
75822
76105
|
if (!fs21.existsSync(file)) {
|
|
75823
|
-
fs21.mkdirSync(
|
|
76106
|
+
fs21.mkdirSync(path46.dirname(file), { recursive: true });
|
|
75824
76107
|
const temp = `${file}.${process.pid}.${Date.now()}.tmp`;
|
|
75825
76108
|
fs21.writeFileSync(temp, log, { mode: 384 });
|
|
75826
76109
|
fs21.renameSync(temp, file);
|
|
@@ -75833,7 +76116,7 @@ function storeLog(storeRoot, log) {
|
|
|
75833
76116
|
function pruneCheckLogs(storeRoot, options = {}) {
|
|
75834
76117
|
const limits = { ...LOG_RETENTION, ...options.retention };
|
|
75835
76118
|
const now = options.now ?? Date.now();
|
|
75836
|
-
const dir =
|
|
76119
|
+
const dir = path46.join(storeRoot, "blobs", "logs");
|
|
75837
76120
|
const report = { removed: 0, removedBytes: 0, kept: 0 };
|
|
75838
76121
|
let names;
|
|
75839
76122
|
try {
|
|
@@ -75843,7 +76126,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
|
|
|
75843
76126
|
}
|
|
75844
76127
|
const files = names.flatMap((name) => {
|
|
75845
76128
|
try {
|
|
75846
|
-
const stat = fs21.statSync(
|
|
76129
|
+
const stat = fs21.statSync(path46.join(dir, name));
|
|
75847
76130
|
return stat.isFile() ? [{ name, size: stat.size, mtimeMs: stat.mtimeMs }] : [];
|
|
75848
76131
|
} catch {
|
|
75849
76132
|
return [];
|
|
@@ -75862,7 +76145,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
|
|
|
75862
76145
|
continue;
|
|
75863
76146
|
if (!options.dryRun)
|
|
75864
76147
|
try {
|
|
75865
|
-
fs21.rmSync(
|
|
76148
|
+
fs21.rmSync(path46.join(dir, file.name), { force: true });
|
|
75866
76149
|
} catch {
|
|
75867
76150
|
continue;
|
|
75868
76151
|
}
|
|
@@ -76413,12 +76696,12 @@ var init_workspace = __esm(() => {
|
|
|
76413
76696
|
|
|
76414
76697
|
// packages/workit-core/src/core/heavy-rules.ts
|
|
76415
76698
|
import fs22 from "node:fs";
|
|
76416
|
-
import
|
|
76699
|
+
import path47 from "node:path";
|
|
76417
76700
|
function gitTop(cwd) {
|
|
76418
|
-
for (let dir =
|
|
76419
|
-
if (fs22.existsSync(
|
|
76701
|
+
for (let dir = path47.resolve(cwd);; dir = path47.dirname(dir)) {
|
|
76702
|
+
if (fs22.existsSync(path47.join(dir, ".git")))
|
|
76420
76703
|
return dir;
|
|
76421
|
-
if (
|
|
76704
|
+
if (path47.dirname(dir) === dir)
|
|
76422
76705
|
return null;
|
|
76423
76706
|
}
|
|
76424
76707
|
}
|
|
@@ -76460,18 +76743,18 @@ var init_heavy_rules = () => {};
|
|
|
76460
76743
|
// packages/workit-core/src/core/heavy.ts
|
|
76461
76744
|
import fs23 from "node:fs";
|
|
76462
76745
|
import os18 from "node:os";
|
|
76463
|
-
import
|
|
76746
|
+
import path48 from "node:path";
|
|
76464
76747
|
function stateDir2(env, platform = process.platform) {
|
|
76465
76748
|
if (env.WORKFLOW_TOOLKIT_STATE)
|
|
76466
76749
|
return env.WORKFLOW_TOOLKIT_STATE;
|
|
76467
76750
|
if (env.XDG_STATE_HOME)
|
|
76468
|
-
return
|
|
76751
|
+
return path48.join(env.XDG_STATE_HOME, "workit");
|
|
76469
76752
|
const home = env.HOME || os18.homedir();
|
|
76470
76753
|
if (platform === "darwin")
|
|
76471
|
-
return
|
|
76754
|
+
return path48.join(home, "Library", "Application Support", "workit");
|
|
76472
76755
|
if (platform === "win32")
|
|
76473
|
-
return
|
|
76474
|
-
return
|
|
76756
|
+
return path48.join(env.LOCALAPPDATA ?? path48.join(home, "AppData", "Local"), "workit");
|
|
76757
|
+
return path48.join(home, ".local", "state", "workit");
|
|
76475
76758
|
}
|
|
76476
76759
|
function positional(words, from, values = PM_VALUES) {
|
|
76477
76760
|
let index = from;
|
|
@@ -76608,10 +76891,10 @@ function parsePattern(pattern) {
|
|
|
76608
76891
|
}
|
|
76609
76892
|
function machinePatterns(env) {
|
|
76610
76893
|
const value = readJson2(heavyCommandsFile(env));
|
|
76611
|
-
return isRecord8(value) ?
|
|
76894
|
+
return isRecord8(value) ? stringList2(value.patterns) : [];
|
|
76612
76895
|
}
|
|
76613
76896
|
function repoPatterns(cwd) {
|
|
76614
|
-
return repoHeavyCommands(gitTop(cwd) ??
|
|
76897
|
+
return repoHeavyCommands(gitTop(cwd) ?? path48.resolve(cwd));
|
|
76615
76898
|
}
|
|
76616
76899
|
function heavyLines(lines, options) {
|
|
76617
76900
|
const found = [];
|
|
@@ -76690,13 +76973,13 @@ function leaseRewrite(command) {
|
|
|
76690
76973
|
return null;
|
|
76691
76974
|
return `${prefix}workit check --heavy -- ${rest}`;
|
|
76692
76975
|
}
|
|
76693
|
-
var HEAVY_COMMANDS_FILE = "heavy-commands.json", heavyCommandsFile = (env) =>
|
|
76976
|
+
var HEAVY_COMMANDS_FILE = "heavy-commands.json", heavyCommandsFile = (env) => path48.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) => {
|
|
76694
76977
|
try {
|
|
76695
76978
|
return JSON.parse(fs23.readFileSync(file, "utf8"));
|
|
76696
76979
|
} catch {
|
|
76697
76980
|
return;
|
|
76698
76981
|
}
|
|
76699
|
-
}, isRecord8 = (value) => typeof value === "object" && value !== null && !Array.isArray(value),
|
|
76982
|
+
}, isRecord8 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), stringList2 = (value) => Array.isArray(value) ? value.filter((item) => typeof item === "string") : [], linesOf = (command, dialect) => {
|
|
76700
76983
|
try {
|
|
76701
76984
|
return commandLines(command, dialect);
|
|
76702
76985
|
} catch {
|
|
@@ -76837,7 +77120,7 @@ var init_heavy = __esm(() => {
|
|
|
76837
77120
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
76838
77121
|
import fs24 from "node:fs";
|
|
76839
77122
|
import os19 from "node:os";
|
|
76840
|
-
import
|
|
77123
|
+
import path49 from "node:path";
|
|
76841
77124
|
function memoryValue(value, host) {
|
|
76842
77125
|
const text = typeof value === "number" ? String(value) : typeof value === "string" ? value : "";
|
|
76843
77126
|
const percent = PERCENT.exec(text.trim());
|
|
@@ -77018,7 +77301,7 @@ function tryOnce(options, record, reclaimed) {
|
|
|
77018
77301
|
const text = `${JSON.stringify(record)}
|
|
77019
77302
|
`;
|
|
77020
77303
|
for (let slot = 0;slot < options.slots; slot += 1) {
|
|
77021
|
-
const file =
|
|
77304
|
+
const file = path49.join(options.dir, `slot-${slot}.json`);
|
|
77022
77305
|
for (let attempt = 0;attempt < 2; attempt += 1) {
|
|
77023
77306
|
try {
|
|
77024
77307
|
const fd = fs24.openSync(file, "wx", 384);
|
|
@@ -77143,7 +77426,7 @@ function heldLease(dir, id, options = {}) {
|
|
|
77143
77426
|
for (const name of names) {
|
|
77144
77427
|
if (!/^slot-\d+\.json$/u.test(name))
|
|
77145
77428
|
continue;
|
|
77146
|
-
const lease = parseLease(readText5(
|
|
77429
|
+
const lease = parseLease(readText5(path49.join(dir, name)));
|
|
77147
77430
|
if (lease?.id === id && !staleReason(lease, options.probe) && (options.ancestor ?? isAncestor)(lease.pid))
|
|
77148
77431
|
return lease;
|
|
77149
77432
|
}
|
|
@@ -77198,10 +77481,10 @@ async function runScoped(run, wrapper, sinks) {
|
|
|
77198
77481
|
}
|
|
77199
77482
|
function firstNotice(env, session, key, now = Date.now()) {
|
|
77200
77483
|
const id = (session ?? `ppid-${process.ppid}`).replace(/[^A-Za-z0-9_.-]/gu, "_").slice(0, 120);
|
|
77201
|
-
const dir =
|
|
77484
|
+
const dir = path49.join(stateDir2(env), "notices");
|
|
77202
77485
|
try {
|
|
77203
77486
|
fs24.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
77204
|
-
fs24.writeFileSync(
|
|
77487
|
+
fs24.writeFileSync(path49.join(dir, `${key}-${id}`), `${new Date(now).toISOString()}
|
|
77205
77488
|
`, {
|
|
77206
77489
|
flag: "wx",
|
|
77207
77490
|
mode: 384
|
|
@@ -77211,7 +77494,7 @@ function firstNotice(env, session, key, now = Date.now()) {
|
|
|
77211
77494
|
}
|
|
77212
77495
|
try {
|
|
77213
77496
|
for (const name of fs24.readdirSync(dir)) {
|
|
77214
|
-
const file =
|
|
77497
|
+
const file = path49.join(dir, name);
|
|
77215
77498
|
if (now - fs24.statSync(file).mtimeMs > NOTICE_TTL_MS)
|
|
77216
77499
|
fs24.rmSync(file, { force: true });
|
|
77217
77500
|
}
|
|
@@ -77221,7 +77504,7 @@ function firstNotice(env, session, key, now = Date.now()) {
|
|
|
77221
77504
|
function leaseSlots(dir, slots, probe = {}) {
|
|
77222
77505
|
const states = [];
|
|
77223
77506
|
for (let slot = 0;slot < slots; slot += 1) {
|
|
77224
|
-
const lease = parseLease(readText5(
|
|
77507
|
+
const lease = parseLease(readText5(path49.join(dir, `slot-${slot}.json`)));
|
|
77225
77508
|
states.push({
|
|
77226
77509
|
slot,
|
|
77227
77510
|
holder: lease ? holderOf(lease) : null,
|
|
@@ -77233,7 +77516,7 @@ function leaseSlots(dir, slots, probe = {}) {
|
|
|
77233
77516
|
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 = () => ({
|
|
77234
77517
|
totalMemBytes: os19.totalmem(),
|
|
77235
77518
|
cpus: Math.max(1, os19.availableParallelism?.() ?? os19.cpus().length)
|
|
77236
|
-
}), isRecord9 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), SIZE, PERCENT, UNITS, leaseDir = (env) =>
|
|
77519
|
+
}), isRecord9 = (value) => typeof value === "object" && value !== null && !Array.isArray(value), SIZE, PERCENT, UNITS, leaseDir = (env) => path49.join(stateDir2(env), "leases"), readText5 = (file) => {
|
|
77237
77520
|
try {
|
|
77238
77521
|
return fs24.readFileSync(file, "utf8");
|
|
77239
77522
|
} catch {
|
|
@@ -77288,7 +77571,7 @@ __export(exports_check, {
|
|
|
77288
77571
|
workspaceResources: () => workspaceResources
|
|
77289
77572
|
});
|
|
77290
77573
|
import os20 from "node:os";
|
|
77291
|
-
import
|
|
77574
|
+
import path50 from "node:path";
|
|
77292
77575
|
function parse6(argv) {
|
|
77293
77576
|
const split = argv.indexOf("--");
|
|
77294
77577
|
const head = split >= 0 ? argv.slice(0, split) : [...argv];
|
|
@@ -77486,7 +77769,7 @@ function hostToolWaitCapMs(env) {
|
|
|
77486
77769
|
}
|
|
77487
77770
|
async function workspaceResources(io) {
|
|
77488
77771
|
const env = io.env;
|
|
77489
|
-
const dir = env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ??
|
|
77772
|
+
const dir = env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path50.join(env.XDG_CONFIG_HOME || path50.join(env.HOME || os20.homedir(), ".config"), "workit");
|
|
77490
77773
|
try {
|
|
77491
77774
|
await Promise.resolve().then(() => init_workspaces());
|
|
77492
77775
|
const workspace = resolveWorkspaceFrom(io.cwd, dir, env.WORKFLOW_WORKSPACE_NAME?.trim() || undefined);
|
|
@@ -77605,7 +77888,7 @@ async function run12(argv, io) {
|
|
|
77605
77888
|
if (options.shell && command.length !== 1)
|
|
77606
77889
|
return emit(io, fail2("invalid_input", '--shell takes the command as one string: workit check --shell -- "<cmd>"'));
|
|
77607
77890
|
}
|
|
77608
|
-
const relCwd = posix(
|
|
77891
|
+
const relCwd = posix(path50.relative(top, runCwd));
|
|
77609
77892
|
const configured = !options.shell && matchesNamedCheck(config, name, command, relCwd);
|
|
77610
77893
|
const shadowed = !configured && name !== null ? config.checks.find((item) => item.name === name) : undefined;
|
|
77611
77894
|
if (shadowed)
|
|
@@ -77667,7 +77950,7 @@ async function run12(argv, io) {
|
|
|
77667
77950
|
const modifiedWorktree = key.tree !== null && treeAfter !== key.tree;
|
|
77668
77951
|
const store = storeRoot(io.cwd);
|
|
77669
77952
|
const blob = store.ok ? storeLog(store.value.root, result.log) : null;
|
|
77670
|
-
const logPath = store.ok && blob ?
|
|
77953
|
+
const logPath = store.ok && blob ? path50.join(store.value.root, blob.ref) : null;
|
|
77671
77954
|
const tail = tailLines(result.log, TAIL_LINES);
|
|
77672
77955
|
const passed = result.exitCode === 0 && !result.timedOut;
|
|
77673
77956
|
const bounded = boundedArgv(command);
|
|
@@ -77780,7 +78063,7 @@ async function run12(argv, io) {
|
|
|
77780
78063
|
return recordError.code === "busy" ? 4 : recordError.code === "invalid_input" ? 2 : 5;
|
|
77781
78064
|
return 0;
|
|
77782
78065
|
}
|
|
77783
|
-
var USAGE5 = '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(
|
|
78066
|
+
var USAGE5 = '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(path50.sep).join("/") || ".", ENGINE_CODES2, FINGERPRINT_VARS, HOST_TOOL_WAIT_CAP_MS = 1e5;
|
|
77784
78067
|
var init_check = __esm(() => {
|
|
77785
78068
|
init_check_config();
|
|
77786
78069
|
init_checks3();
|
|
@@ -77806,7 +78089,7 @@ __export(exports_lock, {
|
|
|
77806
78089
|
run: () => run13
|
|
77807
78090
|
});
|
|
77808
78091
|
import fs25 from "node:fs";
|
|
77809
|
-
import
|
|
78092
|
+
import path51 from "node:path";
|
|
77810
78093
|
async function settingsFor(io) {
|
|
77811
78094
|
const workspace = await workspaceResources(io);
|
|
77812
78095
|
const config = loadCheckConfig(io.cwd);
|
|
@@ -77888,7 +78171,7 @@ function readPatterns(file) {
|
|
|
77888
78171
|
return { patterns: [] };
|
|
77889
78172
|
}
|
|
77890
78173
|
function writePatterns(file, value) {
|
|
77891
|
-
fs25.mkdirSync(
|
|
78174
|
+
fs25.mkdirSync(path51.dirname(file), { recursive: true, mode: 448 });
|
|
77892
78175
|
const temp = `${file}.${process.pid}.tmp`;
|
|
77893
78176
|
fs25.writeFileSync(temp, `${JSON.stringify(value, null, 2)}
|
|
77894
78177
|
`, { mode: 384 });
|
|
@@ -77974,9 +78257,9 @@ var exports_models = {};
|
|
|
77974
78257
|
__export(exports_models, {
|
|
77975
78258
|
run: () => run14
|
|
77976
78259
|
});
|
|
77977
|
-
import { existsSync as existsSync22, readdirSync as
|
|
78260
|
+
import { existsSync as existsSync22, readdirSync as readdirSync12, readFileSync as readFileSync22, statSync as statSync9 } from "node:fs";
|
|
77978
78261
|
import os21 from "node:os";
|
|
77979
|
-
import
|
|
78262
|
+
import path52 from "node:path";
|
|
77980
78263
|
async function run14(argv, io) {
|
|
77981
78264
|
const [sub, ...args] = argv.filter((arg) => arg !== "--json");
|
|
77982
78265
|
if (sub !== "show")
|
|
@@ -78037,7 +78320,7 @@ var USAGE7 = "workit models show [--role <role>] [--tier <tier>] [--host <host>]
|
|
|
78037
78320
|
const found = new Set;
|
|
78038
78321
|
let text = "";
|
|
78039
78322
|
try {
|
|
78040
|
-
text =
|
|
78323
|
+
text = readFileSync22(file, "utf8");
|
|
78041
78324
|
} catch {
|
|
78042
78325
|
return found;
|
|
78043
78326
|
}
|
|
@@ -78051,24 +78334,24 @@ var USAGE7 = "workit models show [--role <role>] [--tier <tier>] [--host <host>]
|
|
|
78051
78334
|
} catch {}
|
|
78052
78335
|
return found;
|
|
78053
78336
|
}, matches3 = (ran, configured) => ran.toLowerCase().includes(configured.toLowerCase()), usageReport = (cwd, env, days) => {
|
|
78054
|
-
const projects =
|
|
78337
|
+
const projects = path52.join(env.CLAUDE_CONFIG_DIR || path52.join(env.HOME || os21.homedir(), ".claude"), "projects");
|
|
78055
78338
|
const since = Date.now() - days * 86400000;
|
|
78056
78339
|
const types = {};
|
|
78057
78340
|
let agents = 0;
|
|
78058
78341
|
const dirs = (dir) => {
|
|
78059
78342
|
try {
|
|
78060
|
-
return
|
|
78343
|
+
return readdirSync12(dir).map((name) => path52.join(dir, name));
|
|
78061
78344
|
} catch {
|
|
78062
78345
|
return [];
|
|
78063
78346
|
}
|
|
78064
78347
|
};
|
|
78065
78348
|
for (const project of dirs(projects))
|
|
78066
78349
|
for (const session of dirs(project))
|
|
78067
|
-
for (const meta of dirs(
|
|
78350
|
+
for (const meta of dirs(path52.join(session, "subagents")).filter((f) => f.endsWith(".meta.json"))) {
|
|
78068
78351
|
try {
|
|
78069
78352
|
if (statSync9(meta).mtimeMs < since)
|
|
78070
78353
|
continue;
|
|
78071
|
-
const agentType = JSON.parse(
|
|
78354
|
+
const agentType = JSON.parse(readFileSync22(meta, "utf8")).agentType;
|
|
78072
78355
|
const transcript = meta.replace(/\.meta\.json$/, ".jsonl");
|
|
78073
78356
|
if (typeof agentType !== "string" || !existsSync22(transcript))
|
|
78074
78357
|
continue;
|
|
@@ -78209,8 +78492,8 @@ var success2 = (data) => ({ ok: true, data }), failure3 = (code, error, unblock)
|
|
|
78209
78492
|
|
|
78210
78493
|
// packages/workit-core/src/git/ops.ts
|
|
78211
78494
|
import { spawnSync as spawnSync20 } from "node:child_process";
|
|
78212
|
-
import { existsSync as existsSync23, readFileSync as
|
|
78213
|
-
import
|
|
78495
|
+
import { existsSync as existsSync23, readFileSync as readFileSync23 } from "node:fs";
|
|
78496
|
+
import path53 from "node:path";
|
|
78214
78497
|
function operationInProgress(cwd) {
|
|
78215
78498
|
const markers = [
|
|
78216
78499
|
["rebase-merge", "rebase"],
|
|
@@ -78223,18 +78506,18 @@ function operationInProgress(cwd) {
|
|
|
78223
78506
|
if (!run.ok)
|
|
78224
78507
|
return null;
|
|
78225
78508
|
const found = run.stdout.split(`
|
|
78226
|
-
`).map((line) =>
|
|
78509
|
+
`).map((line) => path53.resolve(cwd, line.trim()));
|
|
78227
78510
|
const conflicted = () => git5(cwd, ["ls-files", "-u"]).stdout.trim() !== "";
|
|
78228
78511
|
for (const [index, [, operation]] of markers.entries()) {
|
|
78229
78512
|
const marker = found[index];
|
|
78230
78513
|
if (!marker || !existsSync23(marker))
|
|
78231
78514
|
continue;
|
|
78232
|
-
if (index === 1 && existsSync23(
|
|
78515
|
+
if (index === 1 && existsSync23(path53.join(marker, "applying")))
|
|
78233
78516
|
return { operation: "am", commitAllowed: false, branch: null };
|
|
78234
|
-
if (index === 0 && existsSync23(
|
|
78517
|
+
if (index === 0 && existsSync23(path53.join(marker, "amend")) && !conflicted()) {
|
|
78235
78518
|
let headName = "";
|
|
78236
78519
|
try {
|
|
78237
|
-
headName =
|
|
78520
|
+
headName = readFileSync23(path53.join(marker, "head-name"), "utf8").trim();
|
|
78238
78521
|
} catch {}
|
|
78239
78522
|
const branch = headName.startsWith("refs/heads/") ? headName.slice("refs/heads/".length) : null;
|
|
78240
78523
|
return { operation, commitAllowed: branch !== null, branch };
|
|
@@ -78562,7 +78845,7 @@ function gitCommit(cwd, input) {
|
|
|
78562
78845
|
if (paths.some((value) => value.startsWith("-") || !value.trim()))
|
|
78563
78846
|
return failure3("invalid_input", "paths must not be empty or start with -");
|
|
78564
78847
|
const tracked = new Set(nulList(git5(cwd, ["ls-files", "-z", "--", ...paths]).stdout));
|
|
78565
|
-
const addable = paths.filter((value) => existsSync23(
|
|
78848
|
+
const addable = paths.filter((value) => existsSync23(path53.resolve(cwd, value)) || [...tracked].some((file) => file === value || file.startsWith(`${value}/`)));
|
|
78566
78849
|
if (addable.length) {
|
|
78567
78850
|
const added = git5(cwd, ["add", "-A", "--", ...addable]);
|
|
78568
78851
|
if (!added.ok)
|
|
@@ -79101,12 +79384,12 @@ var init_ops = __esm(() => {
|
|
|
79101
79384
|
|
|
79102
79385
|
// packages/workit-core/src/verdict-cover.ts
|
|
79103
79386
|
import fs26 from "node:fs";
|
|
79104
|
-
import
|
|
79387
|
+
import path54 from "node:path";
|
|
79105
79388
|
function chainsAbove(cwd, branch) {
|
|
79106
79389
|
const root = storeRoot(cwd);
|
|
79107
79390
|
if (!root.ok)
|
|
79108
79391
|
return [];
|
|
79109
|
-
const dir =
|
|
79392
|
+
const dir = path54.join(root.value.root, "stacks");
|
|
79110
79393
|
let names = [];
|
|
79111
79394
|
try {
|
|
79112
79395
|
names = fs26.readdirSync(dir).filter((name) => name.endsWith(".json"));
|
|
@@ -79117,7 +79400,7 @@ function chainsAbove(cwd, branch) {
|
|
|
79117
79400
|
for (const name of names.toSorted()) {
|
|
79118
79401
|
let parsed;
|
|
79119
79402
|
try {
|
|
79120
|
-
parsed = JSON.parse(fs26.readFileSync(
|
|
79403
|
+
parsed = JSON.parse(fs26.readFileSync(path54.join(dir, name), "utf8"));
|
|
79121
79404
|
} catch {
|
|
79122
79405
|
continue;
|
|
79123
79406
|
}
|
|
@@ -79212,10 +79495,10 @@ var init_pr_lane = __esm(() => {
|
|
|
79212
79495
|
|
|
79213
79496
|
// packages/workit-core/src/forge/reruns.ts
|
|
79214
79497
|
import fs27 from "node:fs";
|
|
79215
|
-
import
|
|
79498
|
+
import path55 from "node:path";
|
|
79216
79499
|
function rerunLogPath(cwd) {
|
|
79217
79500
|
const common = gitCommonDir(cwd);
|
|
79218
|
-
return common ?
|
|
79501
|
+
return common ? path55.join(common, "workit", "ci-reruns.jsonl") : null;
|
|
79219
79502
|
}
|
|
79220
79503
|
function rerunCounts(cwd, key) {
|
|
79221
79504
|
const counts = new Map;
|
|
@@ -79250,7 +79533,7 @@ function recordReruns(cwd, rows) {
|
|
|
79250
79533
|
if (!file)
|
|
79251
79534
|
return false;
|
|
79252
79535
|
try {
|
|
79253
|
-
fs27.mkdirSync(
|
|
79536
|
+
fs27.mkdirSync(path55.dirname(file), { recursive: true });
|
|
79254
79537
|
fs27.appendFileSync(file, rows.map((row) => `${JSON.stringify(row)}
|
|
79255
79538
|
`).join(""));
|
|
79256
79539
|
return true;
|
|
@@ -79263,7 +79546,7 @@ function withRerunLock(cwd, fn) {
|
|
|
79263
79546
|
if (!file)
|
|
79264
79547
|
return fn();
|
|
79265
79548
|
const lock = `${file.slice(0, -".jsonl".length)}.lock`;
|
|
79266
|
-
fs27.mkdirSync(
|
|
79549
|
+
fs27.mkdirSync(path55.dirname(lock), { recursive: true });
|
|
79267
79550
|
const until = Date.now() + LOCK_WAIT_MS2;
|
|
79268
79551
|
for (;; ) {
|
|
79269
79552
|
try {
|
|
@@ -80210,7 +80493,7 @@ var init_pr_ops = __esm(() => {
|
|
|
80210
80493
|
import { spawnSync as spawnSync22 } from "node:child_process";
|
|
80211
80494
|
import { createHash as createHash17, randomBytes as randomBytes4 } from "node:crypto";
|
|
80212
80495
|
import fs28 from "node:fs";
|
|
80213
|
-
import
|
|
80496
|
+
import path56 from "node:path";
|
|
80214
80497
|
function worktreeOf(cwd, branch) {
|
|
80215
80498
|
const list = gitRun3(cwd, ["worktree", "list", "--porcelain"]);
|
|
80216
80499
|
if (!list.ok)
|
|
@@ -80254,7 +80537,7 @@ function gitRestack(cwd, input) {
|
|
|
80254
80537
|
if (!scratch)
|
|
80255
80538
|
return { ok: false, conflict: false, worktree: cwd, error: "no store root" };
|
|
80256
80539
|
fs28.mkdirSync(scratch, { recursive: true });
|
|
80257
|
-
dir =
|
|
80540
|
+
dir = path56.join(scratch, `${input.branch.replace(/[^A-Za-z0-9._-]+/gu, "_").slice(0, 40)}-${randomBytes4(4).toString("hex")}`);
|
|
80258
80541
|
const added = gitRun3(cwd, ["worktree", "add", "-q", dir, input.branch], GIT_TIMEOUTS.worktree);
|
|
80259
80542
|
if (!added.ok)
|
|
80260
80543
|
return { ok: false, conflict: false, worktree: cwd, error: firstLine(added) };
|
|
@@ -80295,7 +80578,7 @@ function pruneScratch(cwd) {
|
|
|
80295
80578
|
if (!scratch || !fs28.existsSync(scratch))
|
|
80296
80579
|
return;
|
|
80297
80580
|
for (const name of fs28.readdirSync(scratch)) {
|
|
80298
|
-
const dir =
|
|
80581
|
+
const dir = path56.join(scratch, name);
|
|
80299
80582
|
if (!rebaseInProgress(dir) && !trackedDirt(dir))
|
|
80300
80583
|
gitRun3(cwd, ["worktree", "remove", "--force", dir]);
|
|
80301
80584
|
}
|
|
@@ -80305,7 +80588,7 @@ function stacksDir(cwd) {
|
|
|
80305
80588
|
const root = storeRoot(cwd);
|
|
80306
80589
|
if (!root.ok)
|
|
80307
80590
|
return stackFail(root.code, root.error, root.unblock);
|
|
80308
|
-
return { ok: true, data:
|
|
80591
|
+
return { ok: true, data: path56.join(root.value.root, "stacks") };
|
|
80309
80592
|
}
|
|
80310
80593
|
function parseStack(raw) {
|
|
80311
80594
|
if (!isRecord12(raw) || !Array.isArray(raw.branches))
|
|
@@ -80357,7 +80640,7 @@ function readStack(cwd, name) {
|
|
|
80357
80640
|
const dir = stacksDir(cwd);
|
|
80358
80641
|
if (!dir.ok)
|
|
80359
80642
|
return dir;
|
|
80360
|
-
const file =
|
|
80643
|
+
const file = path56.join(dir.data, fileFor(name));
|
|
80361
80644
|
let text;
|
|
80362
80645
|
try {
|
|
80363
80646
|
text = fs28.readFileSync(file, "utf8");
|
|
@@ -80378,7 +80661,7 @@ function writeStack(cwd, stack, now = new Date) {
|
|
|
80378
80661
|
const dir = stacksDir(cwd);
|
|
80379
80662
|
if (!dir.ok)
|
|
80380
80663
|
return dir;
|
|
80381
|
-
const file =
|
|
80664
|
+
const file = path56.join(dir.data, fileFor(stack.name));
|
|
80382
80665
|
const temp = `${file}.${process.pid}.tmp`;
|
|
80383
80666
|
try {
|
|
80384
80667
|
fs28.mkdirSync(dir.data, { recursive: true });
|
|
@@ -80406,7 +80689,7 @@ function listStacks(cwd) {
|
|
|
80406
80689
|
for (const name of names) {
|
|
80407
80690
|
let parsed = null;
|
|
80408
80691
|
try {
|
|
80409
|
-
parsed = parseStack(JSON.parse(fs28.readFileSync(
|
|
80692
|
+
parsed = parseStack(JSON.parse(fs28.readFileSync(path56.join(dir.data, name), "utf8")));
|
|
80410
80693
|
} catch {
|
|
80411
80694
|
parsed = null;
|
|
80412
80695
|
}
|
|
@@ -80465,7 +80748,7 @@ function takeLock(lock) {
|
|
|
80465
80748
|
host: localLockHost(),
|
|
80466
80749
|
nonce: randomBytes4(8).toString("hex")
|
|
80467
80750
|
};
|
|
80468
|
-
fs28.writeFileSync(
|
|
80751
|
+
fs28.writeFileSync(path56.join(lock, OWNER), JSON.stringify(owner));
|
|
80469
80752
|
return owner;
|
|
80470
80753
|
}
|
|
80471
80754
|
function reapLock(lock, observed) {
|
|
@@ -80502,7 +80785,7 @@ async function withStackLock(cwd, name, fn, waitMs = LOCK_WAIT_MS3) {
|
|
|
80502
80785
|
return dir;
|
|
80503
80786
|
if (!validName(name))
|
|
80504
80787
|
return stackFail("invalid_input", "a stack name must be 1-200 printable characters");
|
|
80505
|
-
const lock =
|
|
80788
|
+
const lock = path56.join(dir.data, `${fileFor(name)}.lock`);
|
|
80506
80789
|
try {
|
|
80507
80790
|
fs28.mkdirSync(dir.data, { recursive: true });
|
|
80508
80791
|
} catch (error) {
|
|
@@ -80532,7 +80815,7 @@ async function withStackLock(cwd, name, fn, waitMs = LOCK_WAIT_MS3) {
|
|
|
80532
80815
|
const touch = () => {
|
|
80533
80816
|
try {
|
|
80534
80817
|
const now = new Date;
|
|
80535
|
-
fs28.utimesSync(
|
|
80818
|
+
fs28.utimesSync(path56.join(lock, OWNER), now, now);
|
|
80536
80819
|
} catch {}
|
|
80537
80820
|
};
|
|
80538
80821
|
const beat = setInterval(touch, HEARTBEAT_MS);
|
|
@@ -81383,7 +81666,7 @@ var STACK_VERSION = 1, stackFail = (code, error, unblock, data) => ({
|
|
|
81383
81666
|
return !status.ok || status.stdout.trim() !== "";
|
|
81384
81667
|
}, scratchDir = (cwd) => {
|
|
81385
81668
|
const dir = stacksDir(cwd);
|
|
81386
|
-
return dir.ok ?
|
|
81669
|
+
return dir.ok ? path56.join(dir.data, "worktrees") : null;
|
|
81387
81670
|
}, firstLine = (run) => (`${run.stderr}
|
|
81388
81671
|
${run.stdout}`.split(`
|
|
81389
81672
|
`).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()}-${createHash17("sha256").update(name).digest("hex").slice(0, 12)}.json`, fileFor, validName = (name) => {
|
|
@@ -81398,12 +81681,12 @@ ${run.stdout}`.split(`
|
|
|
81398
81681
|
}, 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) => {
|
|
81399
81682
|
let raw = null;
|
|
81400
81683
|
try {
|
|
81401
|
-
raw = fs28.readFileSync(
|
|
81684
|
+
raw = fs28.readFileSync(path56.join(lock, OWNER), "utf8");
|
|
81402
81685
|
} catch {
|
|
81403
81686
|
raw = null;
|
|
81404
81687
|
}
|
|
81405
81688
|
let age = null;
|
|
81406
|
-
for (const target of [
|
|
81689
|
+
for (const target of [path56.join(lock, OWNER), lock])
|
|
81407
81690
|
try {
|
|
81408
81691
|
age = Date.now() - fs28.statSync(target).mtimeMs;
|
|
81409
81692
|
break;
|
|
@@ -81446,7 +81729,7 @@ var init_stack = __esm(() => {
|
|
|
81446
81729
|
import { spawnSync as spawnSync23 } from "node:child_process";
|
|
81447
81730
|
import { createHash as createHash18 } from "node:crypto";
|
|
81448
81731
|
import fs29 from "node:fs";
|
|
81449
|
-
import
|
|
81732
|
+
import path57 from "node:path";
|
|
81450
81733
|
function expandBraces2(pattern, limit = 64) {
|
|
81451
81734
|
for (let index = 0;index < pattern.length; index += 1) {
|
|
81452
81735
|
if (pattern[index] === "\\") {
|
|
@@ -81692,7 +81975,7 @@ function parsePlan(raw, defaults, name) {
|
|
|
81692
81975
|
id,
|
|
81693
81976
|
branch,
|
|
81694
81977
|
base: optional("base") ?? "",
|
|
81695
|
-
worktree:
|
|
81978
|
+
worktree: path57.resolve(defaults.root, optional("worktree") ?? path57.join(defaults.worktreeRoot, id)),
|
|
81696
81979
|
tier,
|
|
81697
81980
|
reason,
|
|
81698
81981
|
dependsOn: [...new Set(dependsOn ?? [])],
|
|
@@ -81821,12 +82104,12 @@ function regeneratedFiles(root, tracked) {
|
|
|
81821
82104
|
const found = new Map;
|
|
81822
82105
|
let scripts;
|
|
81823
82106
|
try {
|
|
81824
|
-
const manifest = JSON.parse(fs29.readFileSync(
|
|
82107
|
+
const manifest = JSON.parse(fs29.readFileSync(path57.join(root, "package.json"), "utf8"));
|
|
81825
82108
|
scripts = manifest.scripts ?? {};
|
|
81826
82109
|
} catch {
|
|
81827
82110
|
return found;
|
|
81828
82111
|
}
|
|
81829
|
-
const runner = fs29.existsSync(
|
|
82112
|
+
const runner = fs29.existsSync(path57.join(root, "bun.lock")) ? "bun run" : fs29.existsSync(path57.join(root, "pnpm-lock.yaml")) ? "pnpm run" : fs29.existsSync(path57.join(root, "yarn.lock")) ? "yarn run" : "npm run";
|
|
81830
82113
|
const outputs = tracked.filter((file) => !CODE.test(file));
|
|
81831
82114
|
for (const [name, command] of Object.entries(scripts)) {
|
|
81832
82115
|
if (!name.startsWith("write:") || typeof command !== "string")
|
|
@@ -81834,7 +82117,7 @@ function regeneratedFiles(root, tracked) {
|
|
|
81834
82117
|
for (const file of command.match(/[\w./-]+\.[cm]?[jt]s\b/gu) ?? []) {
|
|
81835
82118
|
let source;
|
|
81836
82119
|
try {
|
|
81837
|
-
source = fs29.readFileSync(
|
|
82120
|
+
source = fs29.readFileSync(path57.join(root, file), "utf8");
|
|
81838
82121
|
} catch {
|
|
81839
82122
|
continue;
|
|
81840
82123
|
}
|
|
@@ -81956,11 +82239,11 @@ function defaultTrunk(cwd) {
|
|
|
81956
82239
|
}
|
|
81957
82240
|
function mainCheckout(cwd) {
|
|
81958
82241
|
const common = gitCommonDir(cwd);
|
|
81959
|
-
return common &&
|
|
82242
|
+
return common && path57.basename(common) === ".git" ? path57.dirname(common) : path57.resolve(cwd);
|
|
81960
82243
|
}
|
|
81961
82244
|
function worktreeRoot(cwd) {
|
|
81962
82245
|
const main = mainCheckout(cwd);
|
|
81963
|
-
return
|
|
82246
|
+
return path57.join(path57.dirname(main), `${path57.basename(main)}-wt`);
|
|
81964
82247
|
}
|
|
81965
82248
|
function sliceHash(slice) {
|
|
81966
82249
|
const {
|
|
@@ -81980,7 +82263,7 @@ function fanoutsDir(cwd) {
|
|
|
81980
82263
|
const root = storeRoot(cwd);
|
|
81981
82264
|
if (!root.ok)
|
|
81982
82265
|
return fanoutFail(root.code, root.error, root.unblock);
|
|
81983
|
-
return { ok: true, data:
|
|
82266
|
+
return { ok: true, data: path57.join(root.value.root, "fanouts") };
|
|
81984
82267
|
}
|
|
81985
82268
|
function parseStored(raw) {
|
|
81986
82269
|
if (!isRecord13(raw) || typeof raw.name !== "string" || typeof raw.trunk !== "string")
|
|
@@ -82048,7 +82331,7 @@ function readFanout(cwd, name) {
|
|
|
82048
82331
|
const dir = fanoutsDir(cwd);
|
|
82049
82332
|
if (!dir.ok)
|
|
82050
82333
|
return dir;
|
|
82051
|
-
const file =
|
|
82334
|
+
const file = path57.join(dir.data, stackFileName(name));
|
|
82052
82335
|
let parsed = null;
|
|
82053
82336
|
try {
|
|
82054
82337
|
parsed = parseStored(JSON.parse(fs29.readFileSync(file, "utf8")));
|
|
@@ -82073,7 +82356,7 @@ function listFanouts(cwd) {
|
|
|
82073
82356
|
for (const entry of names) {
|
|
82074
82357
|
let parsed = null;
|
|
82075
82358
|
try {
|
|
82076
|
-
parsed = parseStored(JSON.parse(fs29.readFileSync(
|
|
82359
|
+
parsed = parseStored(JSON.parse(fs29.readFileSync(path57.join(dir.data, entry), "utf8")));
|
|
82077
82360
|
} catch {
|
|
82078
82361
|
parsed = null;
|
|
82079
82362
|
}
|
|
@@ -82112,7 +82395,7 @@ function writeFanout(cwd, plan) {
|
|
|
82112
82395
|
const dir = fanoutsDir(cwd);
|
|
82113
82396
|
if (!dir.ok)
|
|
82114
82397
|
return dir;
|
|
82115
|
-
const file =
|
|
82398
|
+
const file = path57.join(dir.data, stackFileName(plan.name));
|
|
82116
82399
|
const temp = `${file}.${process.pid}.tmp`;
|
|
82117
82400
|
try {
|
|
82118
82401
|
fs29.mkdirSync(dir.data, { recursive: true });
|
|
@@ -82323,13 +82606,13 @@ var init_fanout = __esm(() => {
|
|
|
82323
82606
|
// packages/workit-core/src/forge/exec.ts
|
|
82324
82607
|
import { spawnSync as spawnSync24 } from "node:child_process";
|
|
82325
82608
|
import fs30 from "node:fs";
|
|
82326
|
-
import
|
|
82609
|
+
import path58 from "node:path";
|
|
82327
82610
|
function findExecutable(bin, env) {
|
|
82328
|
-
const dirs = (env.PATH ?? env.Path ?? "").split(
|
|
82611
|
+
const dirs = (env.PATH ?? env.Path ?? "").split(path58.delimiter).filter(Boolean);
|
|
82329
82612
|
const exts = process.platform === "win32" ? [".exe"] : [""];
|
|
82330
82613
|
for (const dir of dirs)
|
|
82331
82614
|
for (const ext of exts) {
|
|
82332
|
-
const candidate =
|
|
82615
|
+
const candidate = path58.join(dir, `${bin}${ext}`);
|
|
82333
82616
|
try {
|
|
82334
82617
|
const stat = fs30.statSync(candidate);
|
|
82335
82618
|
if (stat.isFile())
|
|
@@ -83839,7 +84122,7 @@ var init_live_session = __esm(() => {
|
|
|
83839
84122
|
});
|
|
83840
84123
|
|
|
83841
84124
|
// packages/workit-core/src/hooks/write-gate.ts
|
|
83842
|
-
import
|
|
84125
|
+
import path59 from "node:path";
|
|
83843
84126
|
var CASE_INSENSITIVE, PREFIXES2, SCRIPT_SHELLS, cache3, MUTATING_GIT, DRY_N, MUTATING_WORKIT_GIT, CD2, PUSHD2, POPD2, UNKNOWN_DIR;
|
|
83844
84127
|
var init_write_gate = __esm(() => {
|
|
83845
84128
|
init_task_store();
|
|
@@ -83879,7 +84162,7 @@ var init_write_gate = __esm(() => {
|
|
|
83879
84162
|
CD2 = new Set(["cd", "chdir", "set-location", "sl"]);
|
|
83880
84163
|
PUSHD2 = new Set(["pushd", "push-location"]);
|
|
83881
84164
|
POPD2 = new Set(["popd", "pop-location"]);
|
|
83882
|
-
UNKNOWN_DIR =
|
|
84165
|
+
UNKNOWN_DIR = path59.resolve(path59.parse(process.cwd()).root, ".workit-unknown-dir");
|
|
83883
84166
|
});
|
|
83884
84167
|
|
|
83885
84168
|
// packages/workit-core/src/hooks/worktree-confine.ts
|
|
@@ -83904,20 +84187,20 @@ var init_worktree_confine = __esm(() => {
|
|
|
83904
84187
|
|
|
83905
84188
|
// packages/workit-core/src/worktree-deps.ts
|
|
83906
84189
|
import fs31 from "node:fs";
|
|
83907
|
-
import
|
|
84190
|
+
import path60 from "node:path";
|
|
83908
84191
|
function moduleDirs(main) {
|
|
83909
84192
|
const out = [];
|
|
83910
84193
|
const walk = (relative, depth) => {
|
|
83911
84194
|
let entries;
|
|
83912
84195
|
try {
|
|
83913
|
-
entries = fs31.readdirSync(
|
|
84196
|
+
entries = fs31.readdirSync(path60.join(main, relative), { withFileTypes: true });
|
|
83914
84197
|
} catch {
|
|
83915
84198
|
return;
|
|
83916
84199
|
}
|
|
83917
84200
|
for (const entry of entries) {
|
|
83918
84201
|
if (!entry.isDirectory())
|
|
83919
84202
|
continue;
|
|
83920
|
-
const child =
|
|
84203
|
+
const child = path60.join(relative, entry.name);
|
|
83921
84204
|
if (entry.name === MODULES)
|
|
83922
84205
|
out.push(child);
|
|
83923
84206
|
else if (depth < MAX_DEPTH2 && !entry.name.startsWith("."))
|
|
@@ -83931,8 +84214,8 @@ function linkEntry(main, worktree, source, target) {
|
|
|
83931
84214
|
const stat = fs31.lstatSync(source);
|
|
83932
84215
|
if (stat.isSymbolicLink()) {
|
|
83933
84216
|
const link = fs31.readlinkSync(source);
|
|
83934
|
-
const outside =
|
|
83935
|
-
const to = outside ?
|
|
84217
|
+
const outside = path60.isAbsolute(link) && within(link, main) && !path60.relative(main, link).split(path60.sep).includes(MODULES);
|
|
84218
|
+
const to = outside ? path60.join(worktree, path60.relative(main, link)) : link;
|
|
83936
84219
|
fs31.symlinkSync(to, target, process.platform === "win32" ? "junction" : undefined);
|
|
83937
84220
|
return;
|
|
83938
84221
|
}
|
|
@@ -83942,8 +84225,8 @@ function mirror(main, worktree, source, target, top) {
|
|
|
83942
84225
|
fs31.mkdirSync(target);
|
|
83943
84226
|
let count = 0;
|
|
83944
84227
|
for (const entry of fs31.readdirSync(source, { withFileTypes: true })) {
|
|
83945
|
-
const from =
|
|
83946
|
-
const to =
|
|
84228
|
+
const from = path60.join(source, entry.name);
|
|
84229
|
+
const to = path60.join(target, entry.name);
|
|
83947
84230
|
if (top && entry.isDirectory() && (entry.name.startsWith("@") || entry.name === ".bin"))
|
|
83948
84231
|
count += mirror(main, worktree, from, to, false);
|
|
83949
84232
|
else {
|
|
@@ -83959,16 +84242,16 @@ function linkWorktreeDependencies(main, worktree) {
|
|
|
83959
84242
|
const dirs = [];
|
|
83960
84243
|
let entries = 0;
|
|
83961
84244
|
for (const relative of moduleDirs(main)) {
|
|
83962
|
-
const target =
|
|
83963
|
-
if (!fs31.existsSync(
|
|
84245
|
+
const target = path60.join(worktree, relative);
|
|
84246
|
+
if (!fs31.existsSync(path60.dirname(target)) || fs31.existsSync(target))
|
|
83964
84247
|
continue;
|
|
83965
|
-
if (!gitRun4(worktree, ["check-ignore", "-q", `${relative.split(
|
|
83966
|
-
notes.push(`${relative.split(
|
|
84248
|
+
if (!gitRun4(worktree, ["check-ignore", "-q", `${relative.split(path60.sep).join("/")}/`]).ok) {
|
|
84249
|
+
notes.push(`${relative.split(path60.sep).join("/")} is not ignored by git, so it was not linked from ${main}; install dependencies in the worktree yourself`);
|
|
83967
84250
|
continue;
|
|
83968
84251
|
}
|
|
83969
84252
|
try {
|
|
83970
|
-
entries += mirror(main, worktree,
|
|
83971
|
-
dirs.push(relative.split(
|
|
84253
|
+
entries += mirror(main, worktree, path60.join(main, relative), target, true);
|
|
84254
|
+
dirs.push(relative.split(path60.sep).join("/"));
|
|
83972
84255
|
} catch (error) {
|
|
83973
84256
|
fs31.rmSync(target, { recursive: true, force: true });
|
|
83974
84257
|
notes.push(`could not link ${relative} from ${main} (${error.message}); install dependencies in the worktree yourself`);
|
|
@@ -83981,8 +84264,8 @@ function linkWorktreeDependencies(main, worktree) {
|
|
|
83981
84264
|
return { linked: { from: main, dirs, entries, ms }, notes };
|
|
83982
84265
|
}
|
|
83983
84266
|
var MODULES = "node_modules", MAX_DEPTH2 = 2, within = (child, parent) => {
|
|
83984
|
-
const relative =
|
|
83985
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
84267
|
+
const relative = path60.relative(parent, child);
|
|
84268
|
+
return relative === "" || !relative.startsWith("..") && !path60.isAbsolute(relative);
|
|
83986
84269
|
};
|
|
83987
84270
|
var init_worktree_deps = __esm(() => {
|
|
83988
84271
|
init_fanout();
|
|
@@ -83991,7 +84274,7 @@ var init_worktree_deps = __esm(() => {
|
|
|
83991
84274
|
// packages/workit-core/src/fanout-worktree.ts
|
|
83992
84275
|
import { randomBytes as randomBytes5 } from "node:crypto";
|
|
83993
84276
|
import fs32 from "node:fs";
|
|
83994
|
-
import
|
|
84277
|
+
import path61 from "node:path";
|
|
83995
84278
|
function rowSample(lines) {
|
|
83996
84279
|
const out = [];
|
|
83997
84280
|
let bytes = 0;
|
|
@@ -84051,7 +84334,7 @@ function adminDir(worktree) {
|
|
|
84051
84334
|
const file = dir.stdout.trim();
|
|
84052
84335
|
let token = null;
|
|
84053
84336
|
try {
|
|
84054
|
-
token = fs32.readFileSync(
|
|
84337
|
+
token = fs32.readFileSync(path61.join(file, FANOUT_TOKEN_FILE), "utf8").trim() || null;
|
|
84055
84338
|
} catch {
|
|
84056
84339
|
token = null;
|
|
84057
84340
|
}
|
|
@@ -84059,7 +84342,7 @@ function adminDir(worktree) {
|
|
|
84059
84342
|
const stat = worktreeDeps.stat(file);
|
|
84060
84343
|
return {
|
|
84061
84344
|
path: file,
|
|
84062
|
-
id:
|
|
84345
|
+
id: path61.basename(file),
|
|
84063
84346
|
ino: stat.ino.toString(),
|
|
84064
84347
|
token,
|
|
84065
84348
|
birthMs: stat.birthtimeNs > 0n ? Number(stat.birthtimeMs) : null,
|
|
@@ -84075,7 +84358,7 @@ function markAdminDir(worktree) {
|
|
|
84075
84358
|
return null;
|
|
84076
84359
|
const token = randomBytes5(16).toString("hex");
|
|
84077
84360
|
try {
|
|
84078
|
-
fs32.writeFileSync(
|
|
84361
|
+
fs32.writeFileSync(path61.join(admin.path, FANOUT_TOKEN_FILE), `${token}
|
|
84079
84362
|
`);
|
|
84080
84363
|
} catch {
|
|
84081
84364
|
return null;
|
|
@@ -84090,7 +84373,7 @@ function excludeScratch(cwd) {
|
|
|
84090
84373
|
const common = gitCommonDir(cwd);
|
|
84091
84374
|
if (!common)
|
|
84092
84375
|
return;
|
|
84093
|
-
const file =
|
|
84376
|
+
const file = path61.join(common, "info", "exclude");
|
|
84094
84377
|
let text = "";
|
|
84095
84378
|
try {
|
|
84096
84379
|
text = fs32.readFileSync(file, "utf8");
|
|
@@ -84099,7 +84382,7 @@ function excludeScratch(cwd) {
|
|
|
84099
84382
|
}
|
|
84100
84383
|
if (text.split(/\r?\n/u).includes(EXCLUDE_LINE))
|
|
84101
84384
|
return;
|
|
84102
|
-
fs32.mkdirSync(
|
|
84385
|
+
fs32.mkdirSync(path61.dirname(file), { recursive: true });
|
|
84103
84386
|
fs32.appendFileSync(file, `${text && !text.endsWith(`
|
|
84104
84387
|
`) ? `
|
|
84105
84388
|
` : ""}# workit fanout: per-worker scratch dirs
|
|
@@ -84108,13 +84391,13 @@ ${EXCLUDE_LINE}
|
|
|
84108
84391
|
}
|
|
84109
84392
|
function worktreeDependencies(main, worktree) {
|
|
84110
84393
|
for (const [name, install] of LOCKFILES2) {
|
|
84111
|
-
const ours = readBytes(
|
|
84112
|
-
const theirs = readBytes(
|
|
84394
|
+
const ours = readBytes(path61.join(main, name));
|
|
84395
|
+
const theirs = readBytes(path61.join(worktree, name));
|
|
84113
84396
|
if (ours === null && theirs === null)
|
|
84114
84397
|
continue;
|
|
84115
84398
|
if (ours !== null && theirs !== null && ours.equals(theirs))
|
|
84116
84399
|
continue;
|
|
84117
|
-
if (fs32.existsSync(
|
|
84400
|
+
if (fs32.existsSync(path61.join(worktree, "node_modules")))
|
|
84118
84401
|
break;
|
|
84119
84402
|
const command = install(worktree);
|
|
84120
84403
|
return {
|
|
@@ -84128,7 +84411,7 @@ function worktreeDependencies(main, worktree) {
|
|
|
84128
84411
|
return { ...linkWorktreeDependencies(main, worktree), install: null };
|
|
84129
84412
|
}
|
|
84130
84413
|
function ensureScratch(worktree) {
|
|
84131
|
-
const scratch =
|
|
84414
|
+
const scratch = path61.join(worktree, SCRATCH_DIR);
|
|
84132
84415
|
fs32.mkdirSync(scratch, { recursive: true });
|
|
84133
84416
|
return scratch;
|
|
84134
84417
|
}
|
|
@@ -84367,7 +84650,7 @@ function unpushedCount(cwd, branch) {
|
|
|
84367
84650
|
return count.ok ? Number(count.stdout.trim()) : null;
|
|
84368
84651
|
}
|
|
84369
84652
|
function removeScratch(worktree) {
|
|
84370
|
-
const scratch =
|
|
84653
|
+
const scratch = path61.join(worktree, SCRATCH_DIR);
|
|
84371
84654
|
let stat;
|
|
84372
84655
|
try {
|
|
84373
84656
|
stat = fs32.lstatSync(scratch);
|
|
@@ -84383,16 +84666,16 @@ var SLOW, SCRATCH_DIR = ".workit-scratch", EXCLUDE_LINE, DIRTY_ROW_BYTES = 2000,
|
|
|
84383
84666
|
try {
|
|
84384
84667
|
return fs32.realpathSync.native(target);
|
|
84385
84668
|
} catch {
|
|
84386
|
-
return
|
|
84669
|
+
return path61.resolve(target);
|
|
84387
84670
|
}
|
|
84388
84671
|
}, samePath = (a, b) => {
|
|
84389
84672
|
const left = canonical2(a);
|
|
84390
84673
|
const right = canonical2(b);
|
|
84391
84674
|
return process.platform === "win32" || process.platform === "darwin" ? left.toLowerCase() === right.toLowerCase() : left === right;
|
|
84392
84675
|
}, inside3 = (child, parent) => {
|
|
84393
|
-
const relative =
|
|
84394
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
84395
|
-
}, slicePath = (cwd, slice) =>
|
|
84676
|
+
const relative = path61.relative(canonical2(parent), canonical2(child));
|
|
84677
|
+
return relative === "" || !relative.startsWith("..") && !path61.isAbsolute(relative);
|
|
84678
|
+
}, slicePath = (cwd, slice) => path61.isAbsolute(slice.worktree) ? slice.worktree : path61.resolve(mainCheckout(cwd), slice.worktree), CLOCK_SLACK_MS = 2000, worktreeDeps, LOCKFILES2, readBytes = (file) => {
|
|
84396
84679
|
try {
|
|
84397
84680
|
return fs32.readFileSync(file);
|
|
84398
84681
|
} catch {
|
|
@@ -84423,7 +84706,7 @@ var init_fanout_worktree = __esm(() => {
|
|
|
84423
84706
|
|
|
84424
84707
|
// packages/workit-core/src/forge/merge-cleanup.ts
|
|
84425
84708
|
import fs33 from "node:fs";
|
|
84426
|
-
import
|
|
84709
|
+
import path62 from "node:path";
|
|
84427
84710
|
function cleanupMergedBranch(cwd, branch, mergedHead) {
|
|
84428
84711
|
const out = { branchDeleted: false, worktreeRemoved: null, notes: [] };
|
|
84429
84712
|
if (!branch || branch.startsWith("-"))
|
|
@@ -84483,13 +84766,13 @@ var SLOW2, isFanoutWorktree = (worktree) => {
|
|
|
84483
84766
|
if (!dir.ok)
|
|
84484
84767
|
return false;
|
|
84485
84768
|
try {
|
|
84486
|
-
return fs33.readFileSync(
|
|
84769
|
+
return fs33.readFileSync(path62.join(dir.stdout.trim(), FANOUT_TOKEN_FILE), "utf8").trim() !== "";
|
|
84487
84770
|
} catch {
|
|
84488
84771
|
return false;
|
|
84489
84772
|
}
|
|
84490
84773
|
}, inside4 = (child, parent) => {
|
|
84491
|
-
const relative =
|
|
84492
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
84774
|
+
const relative = path62.relative(fs33.realpathSync.native(parent), fs33.realpathSync.native(child));
|
|
84775
|
+
return relative === "" || !relative.startsWith("..") && !path62.isAbsolute(relative);
|
|
84493
84776
|
};
|
|
84494
84777
|
var init_merge_cleanup = __esm(() => {
|
|
84495
84778
|
init_fanout();
|
|
@@ -84770,7 +85053,7 @@ var init_duration = __esm(() => {
|
|
|
84770
85053
|
});
|
|
84771
85054
|
|
|
84772
85055
|
// packages/workit-cli/src/verbs/forge-common.ts
|
|
84773
|
-
import { readFileSync as
|
|
85056
|
+
import { readFileSync as readFileSync24 } from "node:fs";
|
|
84774
85057
|
function parseFlags(argv, spec) {
|
|
84775
85058
|
const parsed = { values: {}, booleans: new Set, lists: {}, positionals: [] };
|
|
84776
85059
|
for (let index = 0;index < argv.length; index += 1) {
|
|
@@ -84925,7 +85208,7 @@ var init_forge_common = __esm(() => {
|
|
|
84925
85208
|
forgeDeps = {
|
|
84926
85209
|
runner: undefined,
|
|
84927
85210
|
npm: undefined,
|
|
84928
|
-
readStdin: () =>
|
|
85211
|
+
readStdin: () => readFileSync24(0, "utf8"),
|
|
84929
85212
|
sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
|
|
84930
85213
|
now: () => Date.now()
|
|
84931
85214
|
};
|
|
@@ -84936,12 +85219,12 @@ var exports_pr = {};
|
|
|
84936
85219
|
__export(exports_pr, {
|
|
84937
85220
|
run: () => run15
|
|
84938
85221
|
});
|
|
84939
|
-
import { readFileSync as
|
|
84940
|
-
import
|
|
85222
|
+
import { readFileSync as readFileSync25 } from "node:fs";
|
|
85223
|
+
import path63 from "node:path";
|
|
84941
85224
|
function readBodyFile(io, file) {
|
|
84942
85225
|
try {
|
|
84943
85226
|
return {
|
|
84944
|
-
body: file === "-" ? forgeDeps.readStdin() :
|
|
85227
|
+
body: file === "-" ? forgeDeps.readStdin() : readFileSync25(path63.resolve(io.cwd, file), "utf8")
|
|
84945
85228
|
};
|
|
84946
85229
|
} catch {
|
|
84947
85230
|
return `cannot read --body-file ${file}`;
|
|
@@ -85730,8 +86013,8 @@ var exports_git = {};
|
|
|
85730
86013
|
__export(exports_git, {
|
|
85731
86014
|
run: () => run17
|
|
85732
86015
|
});
|
|
85733
|
-
import { readFileSync as
|
|
85734
|
-
import
|
|
86016
|
+
import { readFileSync as readFileSync26 } from "node:fs";
|
|
86017
|
+
import path64 from "node:path";
|
|
85735
86018
|
function kindHint(cwd, kind) {
|
|
85736
86019
|
let kinds = [...BRANCH_KINDS];
|
|
85737
86020
|
try {
|
|
@@ -85835,7 +86118,7 @@ function commitMessage(parsed, io) {
|
|
|
85835
86118
|
|
|
85836
86119
|
`);
|
|
85837
86120
|
try {
|
|
85838
|
-
return file === "-" ?
|
|
86121
|
+
return file === "-" ? readFileSync26(0, "utf8") : readFileSync26(path64.resolve(io.cwd, file), "utf8");
|
|
85839
86122
|
} catch (error) {
|
|
85840
86123
|
return {
|
|
85841
86124
|
error: `cannot read -F ${file}: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -87245,7 +87528,7 @@ var init_stack2 = __esm(() => {
|
|
|
87245
87528
|
// packages/workit-core/src/fanout-brief.ts
|
|
87246
87529
|
import { createHash as createHash19 } from "node:crypto";
|
|
87247
87530
|
import fs35 from "node:fs";
|
|
87248
|
-
import
|
|
87531
|
+
import path65 from "node:path";
|
|
87249
87532
|
function workerSession(lead, slice, attempt) {
|
|
87250
87533
|
const tail = attempt === null ? "" : `+try${attempt}`;
|
|
87251
87534
|
const full = `${lead}-w-${slice}${tail}`;
|
|
@@ -87327,7 +87610,7 @@ function renderBrief(cwd, plan, input) {
|
|
|
87327
87610
|
"STANDING:",
|
|
87328
87611
|
...standing.length ? standing.map((order) => ` - ${order.what}`) : [" - none recorded beyond this brief"],
|
|
87329
87612
|
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)`,
|
|
87330
|
-
...exists && typeof made?.install === "string" && !fs35.existsSync(
|
|
87613
|
+
...exists && typeof made?.install === "string" && !fs35.existsSync(path65.join(planned, "node_modules")) ? [`INSTALL: \`${made.install}\` first: the main checkout's node_modules was not linked here`] : [],
|
|
87331
87614
|
...identityLines(identity, minted),
|
|
87332
87615
|
...rules(mode, branch, slice.base, exists ? planned : null)
|
|
87333
87616
|
];
|
|
@@ -88068,7 +88351,7 @@ __export(exports_fanout, {
|
|
|
88068
88351
|
run: () => run21
|
|
88069
88352
|
});
|
|
88070
88353
|
import fs36 from "node:fs";
|
|
88071
|
-
import
|
|
88354
|
+
import path66 from "node:path";
|
|
88072
88355
|
function forgeFor(io, offline) {
|
|
88073
88356
|
if (offline)
|
|
88074
88357
|
return { forge: null, error: "--offline" };
|
|
@@ -88129,7 +88412,7 @@ function plan2(argv, io) {
|
|
|
88129
88412
|
return usage4(io, "pass --trunk or --track, not both (--track picks the trunk)", PLAN_USAGE2);
|
|
88130
88413
|
if (flags.positionals.length !== 1)
|
|
88131
88414
|
return usage4(io, flags.positionals.length ? `unexpected argument ${flags.positionals[1]}` : "missing <plan.json>", PLAN_USAGE2);
|
|
88132
|
-
const file =
|
|
88415
|
+
const file = path66.resolve(io.cwd, flags.positionals[0]);
|
|
88133
88416
|
let raw;
|
|
88134
88417
|
try {
|
|
88135
88418
|
raw = JSON.parse(fs36.readFileSync(file, "utf8"));
|
|
@@ -103670,7 +103953,7 @@ var init_ast = __esm(() => {
|
|
|
103670
103953
|
|
|
103671
103954
|
// packages/workit-cli/src/test-audit/rules.ts
|
|
103672
103955
|
import { builtinModules } from "node:module";
|
|
103673
|
-
import
|
|
103956
|
+
import path67 from "node:path";
|
|
103674
103957
|
function testCallee(call) {
|
|
103675
103958
|
let callee = call.callee;
|
|
103676
103959
|
if (callee.type === "CallExpression")
|
|
@@ -104163,12 +104446,12 @@ function checkConstantsOnly(ctx, emit) {
|
|
|
104163
104446
|
}
|
|
104164
104447
|
function checkOverMocking(ctx, emit) {
|
|
104165
104448
|
const { program } = ctx.parsed;
|
|
104166
|
-
const unit =
|
|
104449
|
+
const unit = path67.basename(ctx.file).replace(/\.(?:[cm]?[jt]sx?)$/, "").replace(/\.(?:test|spec)$/, "");
|
|
104167
104450
|
const mocked = find2(program, (node) => node.type === "CallExpression" && MODULE_MOCK.test(calleeName(node.callee) ?? "") && node.arguments[0]?.type === "StringLiteral");
|
|
104168
104451
|
const internal = mocked.filter((call) => /^(?:\.|@\/|~\/)/.test(call.arguments[0].value));
|
|
104169
104452
|
for (const call of mocked) {
|
|
104170
104453
|
const spec = call.arguments[0].value;
|
|
104171
|
-
const base =
|
|
104454
|
+
const base = path67.basename(spec.replace(/\/index(?:\.[cm]?[jt]sx?)?$/, "")).replace(/\.(?:[cm]?[jt]sx?)$/, "");
|
|
104172
104455
|
if (base === unit)
|
|
104173
104456
|
emit({
|
|
104174
104457
|
rule: "over-mocking",
|
|
@@ -104557,8 +104840,8 @@ var init_rules = __esm(() => {
|
|
|
104557
104840
|
|
|
104558
104841
|
// packages/workit-cli/src/test-audit/audit.ts
|
|
104559
104842
|
import { spawnSync as spawnSync29 } from "node:child_process";
|
|
104560
|
-
import { existsSync as existsSync24, readdirSync as
|
|
104561
|
-
import
|
|
104843
|
+
import { existsSync as existsSync24, readdirSync as readdirSync13, readFileSync as readFileSync27, statSync as statSync10 } from "node:fs";
|
|
104844
|
+
import path68 from "node:path";
|
|
104562
104845
|
function git7(cwd, args) {
|
|
104563
104846
|
const run = spawnSync29("git", ["-c", "core.quotepath=off", ...args], {
|
|
104564
104847
|
cwd,
|
|
@@ -104568,10 +104851,10 @@ function git7(cwd, args) {
|
|
|
104568
104851
|
return { ok: run.status === 0, stdout: run.stdout ?? "" };
|
|
104569
104852
|
}
|
|
104570
104853
|
function walkTests(dir, out) {
|
|
104571
|
-
for (const entry of
|
|
104854
|
+
for (const entry of readdirSync13(dir, { withFileTypes: true })) {
|
|
104572
104855
|
if (entry.name.startsWith(".") && entry.name !== "." && entry.isDirectory())
|
|
104573
104856
|
continue;
|
|
104574
|
-
const full =
|
|
104857
|
+
const full = path68.join(dir, entry.name);
|
|
104575
104858
|
if (entry.isDirectory()) {
|
|
104576
104859
|
if (!SKIP_DIRS.has(entry.name))
|
|
104577
104860
|
walkTests(full, out);
|
|
@@ -104583,7 +104866,7 @@ function expandPaths(cwd, inputs) {
|
|
|
104583
104866
|
const files = [];
|
|
104584
104867
|
const missing = [];
|
|
104585
104868
|
for (const input of inputs.length > 0 ? inputs : ["."]) {
|
|
104586
|
-
const full =
|
|
104869
|
+
const full = path68.resolve(cwd, input);
|
|
104587
104870
|
if (!existsSync24(full))
|
|
104588
104871
|
missing.push(input);
|
|
104589
104872
|
else if (statSync10(full).isDirectory())
|
|
@@ -104620,11 +104903,11 @@ function changedLines(cwd, base) {
|
|
|
104620
104903
|
for (let offset = 0;offset < count; offset += 1)
|
|
104621
104904
|
lines.add(start + offset);
|
|
104622
104905
|
}
|
|
104623
|
-
changed.set(
|
|
104906
|
+
changed.set(path68.join(root, file), lines);
|
|
104624
104907
|
}
|
|
104625
104908
|
const untracked = git7(root, ["ls-files", "--others", "--exclude-standard", "-z"]);
|
|
104626
104909
|
for (const file of untracked.stdout.split("\x00").filter(Boolean))
|
|
104627
|
-
changed.set(
|
|
104910
|
+
changed.set(path68.join(root, file), "all");
|
|
104628
104911
|
return changed;
|
|
104629
104912
|
}
|
|
104630
104913
|
function auditFiles(files, display) {
|
|
@@ -104637,7 +104920,7 @@ function auditFiles(files, display) {
|
|
|
104637
104920
|
const shown = display(file);
|
|
104638
104921
|
let parsed;
|
|
104639
104922
|
try {
|
|
104640
|
-
parsed = parseSource(
|
|
104923
|
+
parsed = parseSource(readFileSync27(file, "utf8"), file);
|
|
104641
104924
|
} catch (error) {
|
|
104642
104925
|
parseErrors.push({
|
|
104643
104926
|
file: shown,
|
|
@@ -104686,7 +104969,7 @@ function auditFiles(files, display) {
|
|
|
104686
104969
|
durationMs: Math.round(performance.now() - started)
|
|
104687
104970
|
};
|
|
104688
104971
|
}
|
|
104689
|
-
var TEST_FILE, CODE_FILE, SKIP_DIRS, toPosix = (file) => file.split(
|
|
104972
|
+
var TEST_FILE, CODE_FILE, SKIP_DIRS, toPosix = (file) => file.split(path68.sep).join("/"), SEVERITY_ORDER, ruleIds;
|
|
104690
104973
|
var init_audit = __esm(() => {
|
|
104691
104974
|
init_ast();
|
|
104692
104975
|
init_rules();
|
|
@@ -104702,21 +104985,21 @@ import { spawn as spawn2 } from "node:child_process";
|
|
|
104702
104985
|
import {
|
|
104703
104986
|
existsSync as existsSync25,
|
|
104704
104987
|
lstatSync as lstatSync8,
|
|
104705
|
-
mkdirSync as
|
|
104988
|
+
mkdirSync as mkdirSync12,
|
|
104706
104989
|
mkdtempSync as mkdtempSync4,
|
|
104707
|
-
readdirSync as
|
|
104708
|
-
readFileSync as
|
|
104990
|
+
readdirSync as readdirSync14,
|
|
104991
|
+
readFileSync as readFileSync28,
|
|
104709
104992
|
readlinkSync as readlinkSync3,
|
|
104710
104993
|
realpathSync as realpathSync10,
|
|
104711
104994
|
renameSync as renameSync7,
|
|
104712
104995
|
rmSync as rmSync9,
|
|
104713
104996
|
statSync as statSync11,
|
|
104714
104997
|
symlinkSync,
|
|
104715
|
-
writeFileSync as
|
|
104998
|
+
writeFileSync as writeFileSync12,
|
|
104716
104999
|
copyFileSync as copyFileSync8
|
|
104717
105000
|
} from "node:fs";
|
|
104718
105001
|
import os22 from "node:os";
|
|
104719
|
-
import
|
|
105002
|
+
import path69 from "node:path";
|
|
104720
105003
|
function mutantsFor(source, file, lines) {
|
|
104721
105004
|
const parsed = parseSource(source, file);
|
|
104722
105005
|
const out = [];
|
|
@@ -104789,7 +105072,7 @@ function relatedTests(source, testFiles) {
|
|
|
104789
105072
|
for (const match of text.matchAll(SPECIFIER)) {
|
|
104790
105073
|
const spec = match[1];
|
|
104791
105074
|
if (spec.startsWith(".")) {
|
|
104792
|
-
if (stripExt(
|
|
105075
|
+
if (stripExt(path69.posix.join(path69.posix.dirname(file), spec)) === target)
|
|
104793
105076
|
return true;
|
|
104794
105077
|
} else if (spec.includes("/") && stripExt(spec).split("/").slice(-2).join("/") === tail)
|
|
104795
105078
|
return true;
|
|
@@ -104801,7 +105084,7 @@ function removeStaleCopies(tmp = os22.tmpdir()) {
|
|
|
104801
105084
|
let removed = 0;
|
|
104802
105085
|
let names = [];
|
|
104803
105086
|
try {
|
|
104804
|
-
names =
|
|
105087
|
+
names = readdirSync14(tmp);
|
|
104805
105088
|
} catch {
|
|
104806
105089
|
return 0;
|
|
104807
105090
|
}
|
|
@@ -104809,12 +105092,12 @@ function removeStaleCopies(tmp = os22.tmpdir()) {
|
|
|
104809
105092
|
for (const name of names) {
|
|
104810
105093
|
if (!name.startsWith(TEMP_PREFIX))
|
|
104811
105094
|
continue;
|
|
104812
|
-
const dir =
|
|
105095
|
+
const dir = path69.join(tmp, name);
|
|
104813
105096
|
try {
|
|
104814
105097
|
const stat = lstatSync8(dir);
|
|
104815
105098
|
if (!stat.isDirectory() || uid !== undefined && stat.uid !== uid)
|
|
104816
105099
|
continue;
|
|
104817
|
-
const pid = Number(
|
|
105100
|
+
const pid = Number(readFileSync28(path69.join(dir, PID_FILE), "utf8"));
|
|
104818
105101
|
if (Number.isInteger(pid) && pid > 0 && alive(pid))
|
|
104819
105102
|
continue;
|
|
104820
105103
|
} catch (error) {
|
|
@@ -104829,16 +105112,16 @@ function removeStaleCopies(tmp = os22.tmpdir()) {
|
|
|
104829
105112
|
return removed;
|
|
104830
105113
|
}
|
|
104831
105114
|
function linkNodeModules(origin, target, repo, copy) {
|
|
104832
|
-
|
|
104833
|
-
for (const entry of
|
|
104834
|
-
const from =
|
|
104835
|
-
const to =
|
|
105115
|
+
mkdirSync12(target, { recursive: true });
|
|
105116
|
+
for (const entry of readdirSync14(origin, { withFileTypes: true })) {
|
|
105117
|
+
const from = path69.join(origin, entry.name);
|
|
105118
|
+
const to = path69.join(target, entry.name);
|
|
104836
105119
|
if (entry.name.startsWith("@") && entry.isDirectory()) {
|
|
104837
105120
|
linkNodeModules(from, to, repo, copy);
|
|
104838
105121
|
continue;
|
|
104839
105122
|
}
|
|
104840
105123
|
if (entry.name.startsWith(".") && entry.name !== ".bin" && entry.isDirectory()) {
|
|
104841
|
-
|
|
105124
|
+
mkdirSync12(to, { recursive: true });
|
|
104842
105125
|
continue;
|
|
104843
105126
|
}
|
|
104844
105127
|
if (entry.isSymbolicLink()) {
|
|
@@ -104848,9 +105131,9 @@ function linkNodeModules(origin, target, repo, copy) {
|
|
|
104848
105131
|
} catch {
|
|
104849
105132
|
continue;
|
|
104850
105133
|
}
|
|
104851
|
-
const relative =
|
|
104852
|
-
if (!relative.startsWith("..") && !
|
|
104853
|
-
symlinkSync(
|
|
105134
|
+
const relative = path69.relative(repo, real);
|
|
105135
|
+
if (!relative.startsWith("..") && !path69.isAbsolute(relative) && !relative.split(path69.sep).includes("node_modules")) {
|
|
105136
|
+
symlinkSync(path69.join(copy, relative), to, "junction");
|
|
104854
105137
|
continue;
|
|
104855
105138
|
}
|
|
104856
105139
|
}
|
|
@@ -104866,7 +105149,7 @@ function copySymlink(repo, tree, from, to) {
|
|
|
104866
105149
|
}
|
|
104867
105150
|
const realRepo = realpathSync10(repo);
|
|
104868
105151
|
if (real && inside5(realRepo, real)) {
|
|
104869
|
-
symlinkSync(
|
|
105152
|
+
symlinkSync(path69.relative(path69.dirname(to), path69.join(tree, path69.relative(realRepo, real))), to);
|
|
104870
105153
|
return;
|
|
104871
105154
|
}
|
|
104872
105155
|
if (real && statSync11(real).isFile())
|
|
@@ -104875,23 +105158,23 @@ function copySymlink(repo, tree, from, to) {
|
|
|
104875
105158
|
symlinkSync(readlinkSync3(from), to);
|
|
104876
105159
|
}
|
|
104877
105160
|
function writeInside(copy, file, content) {
|
|
104878
|
-
const target =
|
|
105161
|
+
const target = path69.join(copy, file);
|
|
104879
105162
|
try {
|
|
104880
105163
|
const stat = lstatSync8(target);
|
|
104881
|
-
if (!stat.isFile() || !inside5(realpathSync10(copy), realpathSync10(
|
|
105164
|
+
if (!stat.isFile() || !inside5(realpathSync10(copy), realpathSync10(path69.dirname(target))))
|
|
104882
105165
|
return false;
|
|
104883
105166
|
} catch {
|
|
104884
105167
|
return false;
|
|
104885
105168
|
}
|
|
104886
105169
|
const temp = `${target}.workit-mutant-${process.pid}`;
|
|
104887
|
-
|
|
105170
|
+
writeFileSync12(temp, content);
|
|
104888
105171
|
renameSync7(temp, target);
|
|
104889
105172
|
return true;
|
|
104890
105173
|
}
|
|
104891
105174
|
function copyWorkingTree(repo) {
|
|
104892
|
-
const dir = mkdtempSync4(
|
|
104893
|
-
|
|
104894
|
-
const tree =
|
|
105175
|
+
const dir = mkdtempSync4(path69.join(os22.tmpdir(), TEMP_PREFIX));
|
|
105176
|
+
writeFileSync12(path69.join(dir, PID_FILE), String(process.pid));
|
|
105177
|
+
const tree = path69.join(dir, "tree");
|
|
104895
105178
|
const head = git7(repo, ["rev-parse", "--verify", "--quiet", "HEAD"]).stdout.trim();
|
|
104896
105179
|
if (head && git7(dir, ["clone", "-q", "--shared", "--no-checkout", repo, tree]).ok) {
|
|
104897
105180
|
const branch = git7(repo, ["symbolic-ref", "--quiet", "--short", "HEAD"]).stdout.trim();
|
|
@@ -104902,35 +105185,35 @@ function copyWorkingTree(repo) {
|
|
|
104902
105185
|
git7(tree, ["update-ref", "--no-deref", "HEAD", head]);
|
|
104903
105186
|
git7(tree, ["reset", "-q"]);
|
|
104904
105187
|
} else
|
|
104905
|
-
|
|
105188
|
+
mkdirSync12(tree, { recursive: true });
|
|
104906
105189
|
const listed = git7(repo, ["ls-files", "-co", "--exclude-standard", "-z"]).stdout.split("\x00");
|
|
104907
105190
|
const dirs = new Set([""]);
|
|
104908
105191
|
for (const relative of listed) {
|
|
104909
105192
|
if (!relative)
|
|
104910
105193
|
continue;
|
|
104911
|
-
const from =
|
|
105194
|
+
const from = path69.join(repo, relative);
|
|
104912
105195
|
let stat;
|
|
104913
105196
|
try {
|
|
104914
105197
|
stat = lstatSync8(from);
|
|
104915
105198
|
} catch {
|
|
104916
105199
|
continue;
|
|
104917
105200
|
}
|
|
104918
|
-
const to =
|
|
104919
|
-
|
|
105201
|
+
const to = path69.join(tree, relative);
|
|
105202
|
+
mkdirSync12(path69.dirname(to), { recursive: true });
|
|
104920
105203
|
if (stat.isSymbolicLink())
|
|
104921
105204
|
copySymlink(repo, tree, from, to);
|
|
104922
105205
|
else if (stat.isFile())
|
|
104923
105206
|
copyFileSync8(from, to);
|
|
104924
|
-
let parent =
|
|
105207
|
+
let parent = path69.dirname(relative);
|
|
104925
105208
|
while (parent !== "." && !dirs.has(parent)) {
|
|
104926
105209
|
dirs.add(parent);
|
|
104927
|
-
parent =
|
|
105210
|
+
parent = path69.dirname(parent);
|
|
104928
105211
|
}
|
|
104929
105212
|
}
|
|
104930
105213
|
for (const parent of dirs) {
|
|
104931
|
-
const modules =
|
|
104932
|
-
if (existsSync25(modules) && !existsSync25(
|
|
104933
|
-
linkNodeModules(modules,
|
|
105214
|
+
const modules = path69.join(repo, parent, "node_modules");
|
|
105215
|
+
if (existsSync25(modules) && !existsSync25(path69.join(tree, parent, "node_modules")))
|
|
105216
|
+
linkNodeModules(modules, path69.join(tree, parent, "node_modules"), repo, tree);
|
|
104934
105217
|
}
|
|
104935
105218
|
return { dir, tree };
|
|
104936
105219
|
}
|
|
@@ -104969,20 +105252,20 @@ async function runMutation(options) {
|
|
|
104969
105252
|
const tracked = git7(repo, ["ls-files", "-co", "--exclude-standard", "-z"]).stdout.split("\x00").filter(Boolean);
|
|
104970
105253
|
const testFiles = tracked.filter((file) => TEST_FILE.test(file)).map((file) => {
|
|
104971
105254
|
try {
|
|
104972
|
-
return { file, text:
|
|
105255
|
+
return { file, text: readFileSync28(path69.join(repo, file), "utf8") };
|
|
104973
105256
|
} catch {
|
|
104974
105257
|
return { file, text: "" };
|
|
104975
105258
|
}
|
|
104976
105259
|
});
|
|
104977
105260
|
const candidates = [];
|
|
104978
105261
|
for (const [absolute, lines] of [...options.changed].toSorted(([a], [b]) => a.localeCompare(b))) {
|
|
104979
|
-
const relative = toPosix(
|
|
105262
|
+
const relative = toPosix(path69.relative(repo, absolute));
|
|
104980
105263
|
if (!CODE_FILE.test(relative) || TEST_FILE.test(relative) || relative.endsWith(".d.ts"))
|
|
104981
105264
|
continue;
|
|
104982
105265
|
if (NOT_SOURCE.test(relative) || !existsSync25(absolute))
|
|
104983
105266
|
continue;
|
|
104984
105267
|
try {
|
|
104985
|
-
candidates.push(...mutantsFor(
|
|
105268
|
+
candidates.push(...mutantsFor(readFileSync28(absolute, "utf8"), relative, lines));
|
|
104986
105269
|
} catch {}
|
|
104987
105270
|
}
|
|
104988
105271
|
const mutants = candidates.map((mutant, index) => ({ ...mutant, id: index + 1 }));
|
|
@@ -104990,9 +105273,9 @@ async function runMutation(options) {
|
|
|
104990
105273
|
for (const mutant of mutants)
|
|
104991
105274
|
if (!related.has(mutant.file))
|
|
104992
105275
|
related.set(mutant.file, relatedTests(mutant.file, testFiles));
|
|
104993
|
-
const cwdRelative =
|
|
105276
|
+
const cwdRelative = path69.relative(repo, options.cwd);
|
|
104994
105277
|
const asArg = (file) => {
|
|
104995
|
-
const relative = toPosix(
|
|
105278
|
+
const relative = toPosix(path69.relative(cwdRelative, file));
|
|
104996
105279
|
return shellQuote(relative.startsWith(".") ? relative : `./${relative}`);
|
|
104997
105280
|
};
|
|
104998
105281
|
const commandFor = (tests) => options.command.replaceAll("{files}", () => tests.map(asArg).join(" "));
|
|
@@ -105028,7 +105311,7 @@ async function runMutation(options) {
|
|
|
105028
105311
|
return finish3(options, 0, results, counts, started);
|
|
105029
105312
|
removeStaleCopies();
|
|
105030
105313
|
const { dir: copyDir, tree: copy } = copyWorkingTree(repo);
|
|
105031
|
-
const copyCwd =
|
|
105314
|
+
const copyCwd = path69.join(copy, cwdRelative);
|
|
105032
105315
|
let current = null;
|
|
105033
105316
|
const restore = () => {
|
|
105034
105317
|
if (current)
|
|
@@ -105063,7 +105346,7 @@ async function runMutation(options) {
|
|
|
105063
105346
|
record({ ...mutant, status: "skipped", durationMs: 0, tests, reason: "budget" });
|
|
105064
105347
|
continue;
|
|
105065
105348
|
}
|
|
105066
|
-
const original =
|
|
105349
|
+
const original = readFileSync28(path69.join(copy, mutant.file), "utf8");
|
|
105067
105350
|
const mutated = original.slice(0, mutant.start) + mutant.replacement + original.slice(mutant.end);
|
|
105068
105351
|
current = { file: mutant.file, original };
|
|
105069
105352
|
if (!writeInside(copy, mutant.file, mutated)) {
|
|
@@ -105120,8 +105403,8 @@ var NOT_SOURCE, FLIPS, isStringy = (node) => node.type === "StringLiteral" || no
|
|
|
105120
105403
|
return error.code === "EPERM";
|
|
105121
105404
|
}
|
|
105122
105405
|
}, inside5 = (root, file) => {
|
|
105123
|
-
const relative =
|
|
105124
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
105406
|
+
const relative = path69.relative(root, file);
|
|
105407
|
+
return relative === "" || !relative.startsWith("..") && !path69.isAbsolute(relative);
|
|
105125
105408
|
}, active, killTree = (child) => {
|
|
105126
105409
|
try {
|
|
105127
105410
|
if (child.pid && process.platform !== "win32")
|
|
@@ -105170,7 +105453,7 @@ __export(exports_test_audit, {
|
|
|
105170
105453
|
run: () => run23
|
|
105171
105454
|
});
|
|
105172
105455
|
import { existsSync as existsSync26 } from "node:fs";
|
|
105173
|
-
import
|
|
105456
|
+
import path70 from "node:path";
|
|
105174
105457
|
function parse8(argv) {
|
|
105175
105458
|
const options = {
|
|
105176
105459
|
paths: [],
|
|
@@ -105275,8 +105558,8 @@ async function run23(argv, io) {
|
|
|
105275
105558
|
return emit(io, fail2("invalid_input", `${options}
|
|
105276
105559
|
usage: ${USAGE15}`));
|
|
105277
105560
|
const top = git7(io.cwd, ["rev-parse", "--show-toplevel"]);
|
|
105278
|
-
const repo = top.ok ?
|
|
105279
|
-
const display = (file) => toPosix(
|
|
105561
|
+
const repo = top.ok ? path70.resolve(top.stdout.trim()) : null;
|
|
105562
|
+
const display = (file) => toPosix(path70.relative(io.cwd, file) || file);
|
|
105280
105563
|
let base = null;
|
|
105281
105564
|
let changed = null;
|
|
105282
105565
|
if (options.diff || options.mutate) {
|
|
@@ -105414,8 +105697,8 @@ var exports_youtrack = {};
|
|
|
105414
105697
|
__export(exports_youtrack, {
|
|
105415
105698
|
run: () => run25
|
|
105416
105699
|
});
|
|
105417
|
-
import { readFileSync as
|
|
105418
|
-
import
|
|
105700
|
+
import { readFileSync as readFileSync29 } from "node:fs";
|
|
105701
|
+
import path71 from "node:path";
|
|
105419
105702
|
async function run25(argv, io) {
|
|
105420
105703
|
const [sub, ...rest] = argv;
|
|
105421
105704
|
if (sub !== "note" && sub !== "time" && sub !== "meeting")
|
|
@@ -105461,7 +105744,7 @@ async function run25(argv, io) {
|
|
|
105461
105744
|
let markdown = flags.values.markdown ?? "";
|
|
105462
105745
|
if (flags.values.file)
|
|
105463
105746
|
try {
|
|
105464
|
-
markdown =
|
|
105747
|
+
markdown = readFileSync29(path71.resolve(io.cwd, flags.values.file), "utf8");
|
|
105465
105748
|
} catch (error) {
|
|
105466
105749
|
return usage4(io, `cannot read ${flags.values.file}: ${String(error)}`, USAGE17);
|
|
105467
105750
|
}
|
|
@@ -105529,8 +105812,8 @@ var exports_changelog = {};
|
|
|
105529
105812
|
__export(exports_changelog, {
|
|
105530
105813
|
run: () => run26
|
|
105531
105814
|
});
|
|
105532
|
-
import { readFileSync as
|
|
105533
|
-
import
|
|
105815
|
+
import { readFileSync as readFileSync30 } from "node:fs";
|
|
105816
|
+
import path72 from "node:path";
|
|
105534
105817
|
async function run26(argv, io) {
|
|
105535
105818
|
const [sub, ...rest] = argv;
|
|
105536
105819
|
if (sub !== "apply")
|
|
@@ -105576,7 +105859,7 @@ async function run26(argv, io) {
|
|
|
105576
105859
|
]);
|
|
105577
105860
|
}
|
|
105578
105861
|
var USAGE18 = "workit changelog apply (--entries <JSON|@file|-> | --normalize-only) [--path CHANGELOG.md] [--preview]", readEntries = (raw, cwd) => {
|
|
105579
|
-
const text = raw === "-" ?
|
|
105862
|
+
const text = raw === "-" ? readFileSync30(0, "utf8") : raw.startsWith("@") ? readFileSync30(path72.resolve(cwd, raw.slice(1)), "utf8") : raw;
|
|
105580
105863
|
return JSON.parse(text);
|
|
105581
105864
|
};
|
|
105582
105865
|
var init_changelog2 = __esm(() => {
|
|
@@ -105592,7 +105875,7 @@ __export(exports_handoff, {
|
|
|
105592
105875
|
run: () => run27
|
|
105593
105876
|
});
|
|
105594
105877
|
import fs37 from "node:fs";
|
|
105595
|
-
import
|
|
105878
|
+
import path73 from "node:path";
|
|
105596
105879
|
import { parseArgs as parseArgs2 } from "node:util";
|
|
105597
105880
|
function render3(brief) {
|
|
105598
105881
|
const lines = [
|
|
@@ -105632,9 +105915,9 @@ function bounded(brief, cwd) {
|
|
|
105632
105915
|
let file = null;
|
|
105633
105916
|
if (store.ok)
|
|
105634
105917
|
try {
|
|
105635
|
-
const dir =
|
|
105918
|
+
const dir = path73.join(store.value.root, "handoff");
|
|
105636
105919
|
fs37.mkdirSync(dir, { recursive: true });
|
|
105637
|
-
file =
|
|
105920
|
+
file = path73.join(dir, `${(brief.branch ?? "detached").replaceAll(/[^\w.-]+/gu, "-")}.txt`);
|
|
105638
105921
|
fs37.writeFileSync(file, `${[...body, ...tail].join(`
|
|
105639
105922
|
`)}
|
|
105640
105923
|
`, { mode: 384 });
|
|
@@ -105706,7 +105989,7 @@ var init_handoff = __esm(() => {
|
|
|
105706
105989
|
// packages/workit-cli/src/main.ts
|
|
105707
105990
|
init_host_session();
|
|
105708
105991
|
init_package();
|
|
105709
|
-
import
|
|
105992
|
+
import path74 from "node:path";
|
|
105710
105993
|
|
|
105711
105994
|
// packages/workit-cli/src/verbs/registry.ts
|
|
105712
105995
|
var TASK_FAMILY_NAMES = [
|
|
@@ -106612,7 +106895,7 @@ var defaultIo = (json) => ({
|
|
|
106612
106895
|
});
|
|
106613
106896
|
async function main(argv, overrides = {}, options = {}) {
|
|
106614
106897
|
const parsed = parseGlobals(argv);
|
|
106615
|
-
const cwd =
|
|
106898
|
+
const cwd = path74.resolve(overrides.cwd ?? process.cwd(), parsed.cwd ?? ".");
|
|
106616
106899
|
const io = { ...defaultIo(parsed.json), ...overrides, json: parsed.json, cwd };
|
|
106617
106900
|
if (parsed.error)
|
|
106618
106901
|
return emit(io, fail2("invalid_input", parsed.error));
|