@brainervirus/workit-cli 8.8.0 → 8.9.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/dist/index.js +978 -567
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -65,7 +65,7 @@ var package_default;
|
|
|
65
65
|
var init_package = __esm(() => {
|
|
66
66
|
package_default = {
|
|
67
67
|
name: "@brainervirus/workit-cli",
|
|
68
|
-
version: "8.
|
|
68
|
+
version: "8.9.0",
|
|
69
69
|
private: false,
|
|
70
70
|
description: "Workit CLI — setup wizard, doctor, and task control for agentic coding workflows",
|
|
71
71
|
keywords: [
|
|
@@ -103,9 +103,9 @@ var init_package = __esm(() => {
|
|
|
103
103
|
},
|
|
104
104
|
dependencies: {
|
|
105
105
|
"@babel/parser": "7.29.9",
|
|
106
|
-
"@brainervirus/workit-core": "^8.
|
|
107
|
-
"@brainervirus/workit-cursor": "^8.
|
|
108
|
-
"@brainervirus/workit-opencode": "^8.
|
|
106
|
+
"@brainervirus/workit-core": "^8.9.0",
|
|
107
|
+
"@brainervirus/workit-cursor": "^8.9.0",
|
|
108
|
+
"@brainervirus/workit-opencode": "^8.9.0",
|
|
109
109
|
"@inkjs/ui": "2.0.0",
|
|
110
110
|
ink: "7.1.1",
|
|
111
111
|
react: "19.2.8"
|
|
@@ -63938,30 +63938,353 @@ var init_skill_manifests = __esm(() => {
|
|
|
63938
63938
|
if (false) {}
|
|
63939
63939
|
});
|
|
63940
63940
|
|
|
63941
|
-
// packages/workit-
|
|
63941
|
+
// packages/workit-core/src/git/session-hook.ts
|
|
63942
63942
|
import { spawnSync as spawnSync13 } from "node:child_process";
|
|
63943
|
-
import { createHash as createHash13 } from "node:crypto";
|
|
63944
63943
|
import {
|
|
63944
|
+
chmodSync,
|
|
63945
63945
|
existsSync as existsSync13,
|
|
63946
63946
|
lstatSync as lstatSync4,
|
|
63947
63947
|
mkdirSync as mkdirSync5,
|
|
63948
|
-
mkdtempSync,
|
|
63949
|
-
readdirSync as readdirSync7,
|
|
63950
63948
|
readFileSync as readFileSync13,
|
|
63951
|
-
|
|
63949
|
+
renameSync as renameSync3,
|
|
63952
63950
|
rmSync as rmSync2,
|
|
63953
63951
|
statSync as statSync4,
|
|
63954
|
-
unlinkSync as unlinkSync3,
|
|
63955
63952
|
writeFileSync as writeFileSync6
|
|
63956
63953
|
} from "node:fs";
|
|
63957
|
-
import os8 from "node:os";
|
|
63958
63954
|
import path30 from "node:path";
|
|
63955
|
+
function inspectSessionHook(cwd, env = process.env) {
|
|
63956
|
+
const none = { hooksDir: null, hookPath: null, helperPath: null, helperCurrent: false };
|
|
63957
|
+
if (!existsSync13(cwd))
|
|
63958
|
+
return { state: "not_git", ...none };
|
|
63959
|
+
const top = run2(cwd, ["rev-parse", "--show-toplevel"], env);
|
|
63960
|
+
if (!top.ok || !top.out)
|
|
63961
|
+
return { state: "not_git", ...none };
|
|
63962
|
+
const paths = run2(cwd, ["rev-parse", "--path-format=absolute", "--git-common-dir", "--git-path", "hooks"], env);
|
|
63963
|
+
const [commonDir, hooksDir] = paths.out.split(/\r?\n/);
|
|
63964
|
+
if (!paths.ok || !commonDir || !hooksDir)
|
|
63965
|
+
return { state: "not_git", ...none };
|
|
63966
|
+
const hookPath = path30.join(hooksDir, SESSION_HOOK_NAME);
|
|
63967
|
+
const helperPath = path30.join(commonDir, ...HELPER);
|
|
63968
|
+
const helperCurrent = readText(helperPath) === SESSION_TRAILER_SCRIPT;
|
|
63969
|
+
const leftover = leftoverOf(hooksDir);
|
|
63970
|
+
const base = { hooksDir, hookPath, helperPath, helperCurrent, ...leftover ? { leftover } : {} };
|
|
63971
|
+
const blocked = (reason, owner, text = "") => {
|
|
63972
|
+
const old = `${hookPath}.old`;
|
|
63973
|
+
const displaced = readText(old)?.includes(SESSION_HOOK_MARKER) ? old : null;
|
|
63974
|
+
const input = { owner, text, hooksDir, hookPath, top: top.out, displaced };
|
|
63975
|
+
const manualTarget = manualTargetOf(input);
|
|
63976
|
+
const owned = text ? { owner } : {};
|
|
63977
|
+
if (manualInPlace(input, manualTarget))
|
|
63978
|
+
return {
|
|
63979
|
+
state: "manual",
|
|
63980
|
+
...base,
|
|
63981
|
+
...owned,
|
|
63982
|
+
manualTarget,
|
|
63983
|
+
via: owner === "other" ? "existing hook" : owner
|
|
63984
|
+
};
|
|
63985
|
+
return {
|
|
63986
|
+
state: "blocked",
|
|
63987
|
+
...base,
|
|
63988
|
+
...owned,
|
|
63989
|
+
reason: displaced ? `${reason} (Workit's earlier hook was moved to ${old})` : reason,
|
|
63990
|
+
manual: manualFor(input),
|
|
63991
|
+
manualTarget
|
|
63992
|
+
};
|
|
63993
|
+
};
|
|
63994
|
+
if (!inside2(hooksDir, commonDir) && !inside2(hooksDir, top.out))
|
|
63995
|
+
return blocked(`core.hooksPath ${hooksDir} is outside the repository; a hook there runs in every repository that uses it`, "other");
|
|
63996
|
+
const text = exists(hookPath) ? readText(hookPath) ?? "" : null;
|
|
63997
|
+
if (text !== null) {
|
|
63998
|
+
if (text === SESSION_HOOK_SCRIPT)
|
|
63999
|
+
return { state: helperCurrent ? "installed" : "outdated", ...base };
|
|
64000
|
+
if (text.includes(SESSION_HOOK_MARKER))
|
|
64001
|
+
return { state: "outdated", ...base };
|
|
64002
|
+
const owner = ownerOf(text, hooksDir, top.out);
|
|
64003
|
+
return blocked(`${hookPath} belongs to ${owner === "other" ? "another hook" : owner}; Workit never replaces it`, owner, text);
|
|
64004
|
+
}
|
|
64005
|
+
if (!inside2(hooksDir, commonDir)) {
|
|
64006
|
+
const rel = path30.relative(top.out, hookPath).split(path30.sep).join("/");
|
|
64007
|
+
if (!run2(top.out, ["check-ignore", "-q", "--", rel], env).ok)
|
|
64008
|
+
return blocked(`${hooksDir} is in the working tree and not ignored; the hook would show up as a new file`, "other");
|
|
64009
|
+
}
|
|
64010
|
+
return { state: "missing", ...base };
|
|
64011
|
+
}
|
|
64012
|
+
function installSessionHook(cwd, env = process.env) {
|
|
64013
|
+
const status = inspectSessionHook(cwd, env);
|
|
64014
|
+
if (status.state === "not_git")
|
|
64015
|
+
return {
|
|
64016
|
+
action: "skipped",
|
|
64017
|
+
helperWritten: false,
|
|
64018
|
+
status,
|
|
64019
|
+
detail: "not inside a git work tree"
|
|
64020
|
+
};
|
|
64021
|
+
const helperWritten = !status.helperCurrent;
|
|
64022
|
+
if (helperWritten)
|
|
64023
|
+
writeExecutable(status.helperPath, SESSION_TRAILER_SCRIPT);
|
|
64024
|
+
const helper = helperWritten ? `; wrote ${status.helperPath}` : "";
|
|
64025
|
+
if (status.state === "installed")
|
|
64026
|
+
return {
|
|
64027
|
+
action: "unchanged",
|
|
64028
|
+
helperWritten,
|
|
64029
|
+
status,
|
|
64030
|
+
detail: `hook already at ${status.hookPath}`
|
|
64031
|
+
};
|
|
64032
|
+
if (status.state === "manual")
|
|
64033
|
+
return {
|
|
64034
|
+
action: "unchanged",
|
|
64035
|
+
helperWritten,
|
|
64036
|
+
status: inspectSessionHook(cwd, env),
|
|
64037
|
+
detail: `${status.manualTarget} already runs the helper (via ${status.via})${helper}`
|
|
64038
|
+
};
|
|
64039
|
+
if (status.state === "blocked")
|
|
64040
|
+
return {
|
|
64041
|
+
action: "skipped",
|
|
64042
|
+
helperWritten,
|
|
64043
|
+
status: inspectSessionHook(cwd, env),
|
|
64044
|
+
detail: `${status.reason}${helper}`
|
|
64045
|
+
};
|
|
64046
|
+
const fresh = status.state === "missing";
|
|
64047
|
+
const slotCurrent = readText(status.hookPath) === SESSION_HOOK_SCRIPT;
|
|
64048
|
+
if (!slotCurrent)
|
|
64049
|
+
writeExecutable(status.hookPath, SESSION_HOOK_SCRIPT);
|
|
64050
|
+
const verb = fresh ? "installed" : "updated";
|
|
64051
|
+
return {
|
|
64052
|
+
action: verb,
|
|
64053
|
+
helperWritten,
|
|
64054
|
+
status: inspectSessionHook(cwd, env),
|
|
64055
|
+
detail: `${verb} the Workit ${SESSION_HOOK_NAME} hook at ${status.hookPath}${helper}`
|
|
64056
|
+
};
|
|
64057
|
+
}
|
|
64058
|
+
var SESSION_HOOK_NAME = "prepare-commit-msg", SESSION_HOOK_MARKER = "# workit-session-trailer-hook", HELPER, LEGACY_CHAINED = "commit-msg.workit-chained", SESSION_TRAILER_SCRIPT = `#!/bin/sh
|
|
64059
|
+
# Workit (https://github.com/BrainerVirus/workit) wrote this file with
|
|
64060
|
+
# \`workit doctor --fix\`. A prepare-commit-msg hook runs it with its own
|
|
64061
|
+
# arguments to add a Workit-Session trailer to commits made in an agent session.
|
|
64062
|
+
# Not a hook itself; delete it together with the line that runs it.
|
|
64063
|
+
# lefthook passes a missing argument as its literal placeholder.
|
|
64064
|
+
case "\${2-}" in "" | "{2}" | template) exit 0 ;; esac
|
|
64065
|
+
gitdir=$(git rev-parse --git-dir) || exit 0
|
|
64066
|
+
if [ -d "$gitdir/rebase-merge" ] || [ -d "$gitdir/rebase-apply" ] || [ -f "$gitdir/CHERRY_PICK_HEAD" ]; then
|
|
64067
|
+
exit 0
|
|
64068
|
+
fi
|
|
64069
|
+
trim() { printf '%s' "$1" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//'; }
|
|
64070
|
+
inner=$(trim "\${OPENCODE_SESSION_ID-}"); inner_host=opencode
|
|
64071
|
+
if [ -z "$inner" ]; then inner=$(trim "\${PI_SESSION_ID-}"); inner_host=pi; fi
|
|
64072
|
+
if [ -z "$inner" ]; then inner=$(trim "\${CODEX_THREAD_ID-}"); inner_host=codex; fi
|
|
64073
|
+
[ -n "$inner" ] || inner_host=
|
|
64074
|
+
declared=$(trim "\${WORKIT_HOST-}")
|
|
64075
|
+
family=$(printf '%s' "$declared" | sed 's/_cli$//;s/_desktop$//')
|
|
64076
|
+
session=$inner
|
|
64077
|
+
if [ "\${WORKIT_SESSION_ID+set}" = set ]; then
|
|
64078
|
+
if [ -z "$inner" ] || [ -z "$declared" ] || [ "$family" = "$inner_host" ]; then
|
|
64079
|
+
session=$(trim "$WORKIT_SESSION_ID")
|
|
64080
|
+
fi
|
|
64081
|
+
fi
|
|
64082
|
+
[ -n "$session" ] || exit 0
|
|
64083
|
+
[ \${#session} -le 128 ] || exit 0
|
|
64084
|
+
case "$session" in *[!A-Za-z0-9_.:@/+-]*) exit 0 ;; esac
|
|
64085
|
+
add_trailer() {
|
|
64086
|
+
[ -f "$1" ] && [ -r "$1" ] || return 0
|
|
64087
|
+
body=$(sed '/^# -\\{24\\} >8 -\\{24\\}$/,$d' "$1" | git stripspace --strip-comments)
|
|
64088
|
+
[ -n "$body" ] || return 0
|
|
64089
|
+
# A merge message has no final newline; interpret-trailers would glue the
|
|
64090
|
+
# trailer to the subject line.
|
|
64091
|
+
[ -z "$(tail -c 1 "$1")" ] || printf '\\n' >> "$1"
|
|
64092
|
+
git -c trailer.separators=: -c trailer.where=end interpret-trailers --in-place \\
|
|
64093
|
+
--no-divider --if-exists addIfDifferent --trailer "Workit-Session: $session" "$1" || return 0
|
|
64094
|
+
}
|
|
64095
|
+
# $1 is the message file. lefthook cannot quote a path it pastes in, so its
|
|
64096
|
+
# job passes '' and the file is found here: git hands the hook COMMIT_EDITMSG,
|
|
64097
|
+
# except \`git merge\`, which hands it MERGE_MSG. With source "merge" both are
|
|
64098
|
+
# updated: the one git did not hand over is stale or removed after the commit.
|
|
64099
|
+
case "\${1-}" in "" | "{1}") ;; *) add_trailer "$1"; exit 0 ;; esac
|
|
64100
|
+
add_trailer "$(git rev-parse --git-path COMMIT_EDITMSG)"
|
|
64101
|
+
[ "$2" != merge ] || add_trailer "$(git rev-parse --git-path MERGE_MSG)"
|
|
64102
|
+
exit 0
|
|
64103
|
+
`, manualTrailerLine = () => `h="$(git rev-parse --git-common-dir 2>/dev/null)/${HELPER.join("/")}"; [ ! -f "$h" ] || sh "$h" "$@" || true`, lefthookTrailerRun = () => `set -f; IFS=; h=$(git rev-parse --git-common-dir 2>/dev/null)/${HELPER.join("/")}; [ ! -f $h ] || sh $h '' {2} {3} || true`, HELPER_REF, SESSION_HOOK_SCRIPT, run2 = (cwd, args, env) => {
|
|
64104
|
+
const r = spawnSync13("git", args, {
|
|
64105
|
+
cwd,
|
|
64106
|
+
encoding: "utf8",
|
|
64107
|
+
timeout: GIT_TIMEOUTS.local,
|
|
64108
|
+
windowsHide: true,
|
|
64109
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
64110
|
+
env: { ...env, GIT_TERMINAL_PROMPT: "0" }
|
|
64111
|
+
});
|
|
64112
|
+
return { ok: r.status === 0, out: (r.stdout ?? "").trim() };
|
|
64113
|
+
}, inside2 = (child, parent) => {
|
|
64114
|
+
const rel = path30.relative(path30.resolve(parent), path30.resolve(child));
|
|
64115
|
+
return rel === "" || !rel.startsWith("..") && !path30.isAbsolute(rel);
|
|
64116
|
+
}, readText = (file) => {
|
|
64117
|
+
try {
|
|
64118
|
+
return readFileSync13(file, "utf8");
|
|
64119
|
+
} catch {
|
|
64120
|
+
return null;
|
|
64121
|
+
}
|
|
64122
|
+
}, exists = (file) => {
|
|
64123
|
+
try {
|
|
64124
|
+
lstatSync4(file);
|
|
64125
|
+
return true;
|
|
64126
|
+
} catch {
|
|
64127
|
+
return false;
|
|
64128
|
+
}
|
|
64129
|
+
}, LEFTHOOK_CONFIGS, lefthookConfig = (top) => LEFTHOOK_CONFIGS.map((name) => path30.join(top, name)).find((file) => existsSync13(file)) ?? null, isComment = (line) => /^\s*#/.test(line), COMMAND_SH, DIRECT_CALL, VAR_CALL, runsHelperText = (text) => {
|
|
64130
|
+
const lines = text.split(/\r?\n/).filter((line) => !isComment(line));
|
|
64131
|
+
const assigned = lines.some((line) => /(?:^|[\s;])h=/.test(line) && line.includes(HELPER_REF));
|
|
64132
|
+
return lines.some((line) => DIRECT_CALL.test(line) || assigned && VAR_CALL.test(line));
|
|
64133
|
+
}, LEFTHOOK_YAML, indentOf = (line) => line.length - line.trimStart().length, lefthookRunsHelper = (text) => {
|
|
64134
|
+
const lines = text.split(/\r?\n/);
|
|
64135
|
+
const start = lines.findIndex((line) => /^prepare-commit-msg:\s*(?:#.*)?$/.test(line));
|
|
64136
|
+
if (start < 0)
|
|
64137
|
+
return false;
|
|
64138
|
+
const block = [];
|
|
64139
|
+
for (const line of lines.slice(start + 1)) {
|
|
64140
|
+
if (line.trim() && !isComment(line) && indentOf(line) === 0)
|
|
64141
|
+
break;
|
|
64142
|
+
block.push(line);
|
|
64143
|
+
}
|
|
64144
|
+
return block.some((line, i) => {
|
|
64145
|
+
if (isComment(line))
|
|
64146
|
+
return false;
|
|
64147
|
+
const runKey = /^(\s*)(?:-\s+)?run:\s*(.*)$/.exec(line);
|
|
64148
|
+
if (!runKey)
|
|
64149
|
+
return false;
|
|
64150
|
+
let value = runKey[2] ?? "";
|
|
64151
|
+
if (/^[|>][-+]?\s*$/.test(value)) {
|
|
64152
|
+
const body = [];
|
|
64153
|
+
for (const next of block.slice(i + 1)) {
|
|
64154
|
+
if (next.trim() && indentOf(next) <= indentOf(line))
|
|
64155
|
+
break;
|
|
64156
|
+
body.push(next);
|
|
64157
|
+
}
|
|
64158
|
+
value = body.join(`
|
|
64159
|
+
`);
|
|
64160
|
+
}
|
|
64161
|
+
return runsHelperText(value);
|
|
64162
|
+
});
|
|
64163
|
+
}, isExecutable = (file) => {
|
|
64164
|
+
if (process.platform === "win32")
|
|
64165
|
+
return true;
|
|
64166
|
+
try {
|
|
64167
|
+
return (statSync4(file).mode & 73) !== 0;
|
|
64168
|
+
} catch {
|
|
64169
|
+
return false;
|
|
64170
|
+
}
|
|
64171
|
+
}, manualInPlace = (input, target) => {
|
|
64172
|
+
if (input.owner === "lefthook")
|
|
64173
|
+
return LEFTHOOK_YAML.some((name) => {
|
|
64174
|
+
const text = readText(path30.join(input.top, name));
|
|
64175
|
+
return text !== null && lefthookRunsHelper(text);
|
|
64176
|
+
});
|
|
64177
|
+
const text = readText(target);
|
|
64178
|
+
if (text === null || !runsHelperText(text))
|
|
64179
|
+
return false;
|
|
64180
|
+
return input.owner === "husky" && target !== input.hookPath || isExecutable(target);
|
|
64181
|
+
}, isHuskyV9 = (text, hooksDir) => /\$\(dirname (?:-- )?"\$0"\)\/h"/.test(text) && existsSync13(path30.join(hooksDir, "h")), ownerOf = (text, hooksDir, top) => {
|
|
64182
|
+
if (text.includes("husky.sh") || isHuskyV9(text, hooksDir))
|
|
64183
|
+
return "husky";
|
|
64184
|
+
if (/lefthook/i.test(text) || lefthookConfig(top))
|
|
64185
|
+
return "lefthook";
|
|
64186
|
+
return "other";
|
|
64187
|
+
}, manualTargetOf = ({ owner, text, hooksDir, hookPath, top }) => {
|
|
64188
|
+
if (owner === "husky" && isHuskyV9(text, hooksDir))
|
|
64189
|
+
return path30.join(path30.dirname(hooksDir), SESSION_HOOK_NAME);
|
|
64190
|
+
if (owner === "lefthook")
|
|
64191
|
+
return lefthookConfig(top) ?? path30.join(top, "lefthook.yml");
|
|
64192
|
+
return hookPath;
|
|
64193
|
+
}, manualFor = (input) => {
|
|
64194
|
+
const { owner, displaced } = input;
|
|
64195
|
+
const target = manualTargetOf(input);
|
|
64196
|
+
const stale = displaced ? `; delete the stale ${displaced} (nothing runs it)` : "";
|
|
64197
|
+
if (owner === "husky")
|
|
64198
|
+
return `add this line to ${target} (create it if missing; husky runs it)${stale}: ${manualTrailerLine()}`;
|
|
64199
|
+
if (owner === "lefthook")
|
|
64200
|
+
return [
|
|
64201
|
+
`merge this job into ${target} (add it to an existing \`${SESSION_HOOK_NAME}:\` \`jobs:\` list rather than a second \`${SESSION_HOOK_NAME}:\` key), then run \`lefthook install\`${stale}:`,
|
|
64202
|
+
`${SESSION_HOOK_NAME}:`,
|
|
64203
|
+
" jobs:",
|
|
64204
|
+
" - name: workit-session",
|
|
64205
|
+
` run: ${lefthookTrailerRun()}`
|
|
64206
|
+
].join(`
|
|
64207
|
+
`);
|
|
64208
|
+
return `add this line to ${target} (a new file needs \`#!/bin/sh\` as its first line and \`chmod +x\`)${stale}: ${manualTrailerLine()}`;
|
|
64209
|
+
}, leftoverOf = (hooksDir) => {
|
|
64210
|
+
const chained = path30.join(hooksDir, LEGACY_CHAINED);
|
|
64211
|
+
const commitMsg = path30.join(hooksDir, "commit-msg");
|
|
64212
|
+
const oldOurs = readText(commitMsg)?.includes(SESSION_HOOK_MARKER) ?? false;
|
|
64213
|
+
if (exists(chained))
|
|
64214
|
+
return oldOurs ? `${chained} was left by an earlier Workit build: move it back to ${commitMsg} (replacing Workit's old hook there)` : `${chained} was left by an earlier Workit build and nothing runs it: if it is your original commit-msg hook, move it back to ${commitMsg}; otherwise delete it`;
|
|
64215
|
+
if (oldOurs)
|
|
64216
|
+
return `${commitMsg} is a hook from an earlier Workit build; delete it (the trailer now comes from ${SESSION_HOOK_NAME})`;
|
|
64217
|
+
return;
|
|
64218
|
+
}, writeExecutable = (file, content) => {
|
|
64219
|
+
mkdirSync5(path30.dirname(file), { recursive: true });
|
|
64220
|
+
const staged = `${file}.workit-new`;
|
|
64221
|
+
try {
|
|
64222
|
+
writeFileSync6(staged, content, { mode: 493 });
|
|
64223
|
+
chmodSync(staged, 493);
|
|
64224
|
+
renameSync3(staged, file);
|
|
64225
|
+
} finally {
|
|
64226
|
+
rmSync2(staged, { force: true });
|
|
64227
|
+
}
|
|
64228
|
+
};
|
|
64229
|
+
var init_session_hook = __esm(() => {
|
|
64230
|
+
init_rev();
|
|
64231
|
+
HELPER = ["workit", "session-trailer.sh"];
|
|
64232
|
+
HELPER_REF = HELPER.join("/");
|
|
64233
|
+
SESSION_HOOK_SCRIPT = `#!/bin/sh
|
|
64234
|
+
${SESSION_HOOK_MARKER} v4
|
|
64235
|
+
# Workit (https://github.com/BrainerVirus/workit) installed this hook with
|
|
64236
|
+
# \`workit doctor --fix\`: it runs Workit's session-trailer helper, which adds a
|
|
64237
|
+
# Workit-Session trailer to commits made in an agent session. To remove it,
|
|
64238
|
+
# delete this file.
|
|
64239
|
+
${manualTrailerLine()}
|
|
64240
|
+
`;
|
|
64241
|
+
LEFTHOOK_CONFIGS = [
|
|
64242
|
+
"lefthook.yml",
|
|
64243
|
+
"lefthook.yaml",
|
|
64244
|
+
".lefthook.yml",
|
|
64245
|
+
".lefthook.yaml",
|
|
64246
|
+
"lefthook.json",
|
|
64247
|
+
"lefthook.toml"
|
|
64248
|
+
];
|
|
64249
|
+
COMMAND_SH = String.raw`(?:^|[;&|(!]|\b(?:then|do|else)\s)\s*sh\s+`;
|
|
64250
|
+
DIRECT_CALL = new RegExp(String.raw`${COMMAND_SH}(?:"[^"]*|\S*)${HELPER_REF.replaceAll(".", String.raw`\.`)}`);
|
|
64251
|
+
VAR_CALL = new RegExp(String.raw`${COMMAND_SH}"?\$h\b`);
|
|
64252
|
+
LEFTHOOK_YAML = [
|
|
64253
|
+
"lefthook.yml",
|
|
64254
|
+
"lefthook.yaml",
|
|
64255
|
+
".lefthook.yml",
|
|
64256
|
+
".lefthook.yaml",
|
|
64257
|
+
"lefthook-local.yml",
|
|
64258
|
+
"lefthook-local.yaml",
|
|
64259
|
+
".lefthook-local.yml",
|
|
64260
|
+
".lefthook-local.yaml"
|
|
64261
|
+
];
|
|
64262
|
+
});
|
|
64263
|
+
|
|
64264
|
+
// packages/workit-cli/src/admin/doctor.ts
|
|
64265
|
+
import { spawnSync as spawnSync14 } from "node:child_process";
|
|
64266
|
+
import { createHash as createHash13 } from "node:crypto";
|
|
64267
|
+
import {
|
|
64268
|
+
existsSync as existsSync14,
|
|
64269
|
+
lstatSync as lstatSync5,
|
|
64270
|
+
mkdirSync as mkdirSync6,
|
|
64271
|
+
mkdtempSync,
|
|
64272
|
+
readdirSync as readdirSync7,
|
|
64273
|
+
readFileSync as readFileSync14,
|
|
64274
|
+
readlinkSync as readlinkSync2,
|
|
64275
|
+
rmSync as rmSync3,
|
|
64276
|
+
statSync as statSync5,
|
|
64277
|
+
unlinkSync as unlinkSync3,
|
|
64278
|
+
writeFileSync as writeFileSync7
|
|
64279
|
+
} from "node:fs";
|
|
64280
|
+
import os8 from "node:os";
|
|
64281
|
+
import path31 from "node:path";
|
|
63959
64282
|
var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
63960
|
-
let dir =
|
|
64283
|
+
let dir = path31.resolve(cwd);
|
|
63961
64284
|
while (true) {
|
|
63962
|
-
if (
|
|
64285
|
+
if (existsSync14(path31.join(dir, "packages", "workit-core", "package.json")))
|
|
63963
64286
|
return dir;
|
|
63964
|
-
const parent =
|
|
64287
|
+
const parent = path31.dirname(dir);
|
|
63965
64288
|
if (parent === dir)
|
|
63966
64289
|
return null;
|
|
63967
64290
|
dir = parent;
|
|
@@ -63969,8 +64292,8 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63969
64292
|
}, resolve = (options) => {
|
|
63970
64293
|
const env = options.env ?? process.env;
|
|
63971
64294
|
const home = options.home ?? env.HOME ?? os8.homedir();
|
|
63972
|
-
const configDir = options.configDir ?? env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ??
|
|
63973
|
-
const stateDir = options.stateDir ?? env.WORKFLOW_TOOLKIT_STATE ??
|
|
64295
|
+
const configDir = options.configDir ?? env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path31.join(home, ".config", "workit");
|
|
64296
|
+
const stateDir = options.stateDir ?? env.WORKFLOW_TOOLKIT_STATE ?? path31.join(home, ".local", "state", "workit");
|
|
63974
64297
|
const cwd = options.cwd ?? process.cwd();
|
|
63975
64298
|
const dev = options.dev ?? env.WORKFLOW_TOOLKIT_DEV ?? findDevFromCwd(cwd);
|
|
63976
64299
|
return {
|
|
@@ -63981,11 +64304,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63981
64304
|
cwd,
|
|
63982
64305
|
workspaceRoot: options.workspaceRoot ?? env.WORKFLOW_WORKSPACE_ROOT ?? cwd,
|
|
63983
64306
|
dev,
|
|
63984
|
-
opencodeConfig: options.opencodeConfig ??
|
|
63985
|
-
opencodePackageCacheDir: options.opencodePackageCacheDir ??
|
|
63986
|
-
cursorSettings: options.cursorSettings ??
|
|
63987
|
-
cursorMcp: options.cursorMcp ??
|
|
63988
|
-
cursorPluginDir: options.cursorPluginDir ??
|
|
64307
|
+
opencodeConfig: options.opencodeConfig ?? path31.join(home, ".config", "opencode", "opencode.json"),
|
|
64308
|
+
opencodePackageCacheDir: options.opencodePackageCacheDir ?? path31.join(home, ".cache", "opencode", "packages", "@brainervirus", "workit-opencode@latest"),
|
|
64309
|
+
cursorSettings: options.cursorSettings ?? path31.join(home, ".cursor", "settings.json"),
|
|
64310
|
+
cursorMcp: options.cursorMcp ?? path31.join(home, ".cursor", "mcp.json"),
|
|
64311
|
+
cursorPluginDir: options.cursorPluginDir ?? path31.join(home, ".cursor", "plugins", "local", "workit"),
|
|
63989
64312
|
cursorHeartbeatDir: options.stateDir ?? (env.WORKFLOW_TOOLKIT_STATE || resolveStateDir()),
|
|
63990
64313
|
codexHome: options.codexHome,
|
|
63991
64314
|
piAgentDir: options.piAgentDir,
|
|
@@ -63995,14 +64318,14 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63995
64318
|
};
|
|
63996
64319
|
}, readJson = (p) => {
|
|
63997
64320
|
try {
|
|
63998
|
-
const parsed = JSON.parse(
|
|
64321
|
+
const parsed = JSON.parse(readFileSync14(p, "utf8"));
|
|
63999
64322
|
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
64000
64323
|
} catch {
|
|
64001
64324
|
return null;
|
|
64002
64325
|
}
|
|
64003
64326
|
}, parsesAsConfigObject = (p) => {
|
|
64004
64327
|
try {
|
|
64005
|
-
return isConfigObject(JSON.parse(
|
|
64328
|
+
return isConfigObject(JSON.parse(readFileSync14(p, "utf8")));
|
|
64006
64329
|
} catch {
|
|
64007
64330
|
return false;
|
|
64008
64331
|
}
|
|
@@ -64012,14 +64335,14 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64012
64335
|
...new Set(entries.filter((entry) => typeof entry === "string" && isWorkitPlugin(entry)))
|
|
64013
64336
|
];
|
|
64014
64337
|
}, 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) => {
|
|
64015
|
-
const dirs = (env.PATH ?? process.env.PATH ?? "").split(
|
|
64338
|
+
const dirs = (env.PATH ?? process.env.PATH ?? "").split(path31.delimiter);
|
|
64016
64339
|
for (const dir of dirs) {
|
|
64017
64340
|
if (!dir)
|
|
64018
64341
|
continue;
|
|
64019
64342
|
for (const candidateName of names) {
|
|
64020
|
-
const candidate =
|
|
64343
|
+
const candidate = path31.join(dir, candidateName);
|
|
64021
64344
|
try {
|
|
64022
|
-
const st =
|
|
64345
|
+
const st = statSync5(candidate);
|
|
64023
64346
|
if (process.platform !== "win32" && (st.mode & 73) === 0)
|
|
64024
64347
|
continue;
|
|
64025
64348
|
return candidate;
|
|
@@ -64028,7 +64351,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64028
64351
|
}
|
|
64029
64352
|
return null;
|
|
64030
64353
|
}, versionOf = (bin, env, timeout) => {
|
|
64031
|
-
const r =
|
|
64354
|
+
const r = spawnSync14(bin, ["--version"], { encoding: "utf8", env, timeout });
|
|
64032
64355
|
if (r.error)
|
|
64033
64356
|
return null;
|
|
64034
64357
|
return (r.stdout ?? "").trim();
|
|
@@ -64043,14 +64366,14 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64043
64366
|
}
|
|
64044
64367
|
return true;
|
|
64045
64368
|
}, resolveBun = (env) => {
|
|
64046
|
-
if (env.BUN &&
|
|
64369
|
+
if (env.BUN && existsSync14(env.BUN))
|
|
64047
64370
|
return env.BUN;
|
|
64048
64371
|
for (const candidate of [
|
|
64049
|
-
|
|
64372
|
+
path31.join(os8.homedir(), ".bun/bin/bun"),
|
|
64050
64373
|
"/usr/local/bin/bun",
|
|
64051
64374
|
"/usr/bin/bun"
|
|
64052
64375
|
]) {
|
|
64053
|
-
if (
|
|
64376
|
+
if (existsSync14(candidate))
|
|
64054
64377
|
return candidate;
|
|
64055
64378
|
}
|
|
64056
64379
|
return commandOnPath("bun", env) ? "bun" : null;
|
|
@@ -64098,7 +64421,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64098
64421
|
detail: "no dev checkout found (WORKFLOW_TOOLKIT_DEV) — skipping version parity"
|
|
64099
64422
|
};
|
|
64100
64423
|
}
|
|
64101
|
-
const corePkg = readJson(
|
|
64424
|
+
const corePkg = readJson(path31.join(res.dev, "packages/workit-core/package.json"));
|
|
64102
64425
|
if (!corePkg) {
|
|
64103
64426
|
return {
|
|
64104
64427
|
id: "versions",
|
|
@@ -64108,7 +64431,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64108
64431
|
}
|
|
64109
64432
|
const refs = new Set;
|
|
64110
64433
|
for (const name of ["workit-opencode", "workit-cursor", "workit-cli"]) {
|
|
64111
|
-
const pkg = readJson(
|
|
64434
|
+
const pkg = readJson(path31.join(res.dev, "packages", name, "package.json"));
|
|
64112
64435
|
const dep = pkg?.dependencies?.["@brainervirus/workit-core"];
|
|
64113
64436
|
if (typeof dep === "string")
|
|
64114
64437
|
refs.add(dep);
|
|
@@ -64124,7 +64447,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64124
64447
|
if (refs.size > 1) {
|
|
64125
64448
|
problems.push(`adapters pin different core versions: ${[...refs].join(", ")}`);
|
|
64126
64449
|
}
|
|
64127
|
-
const opencodePkg = readJson(
|
|
64450
|
+
const opencodePkg = readJson(path31.join(res.dev, "packages/workit-opencode/package.json"));
|
|
64128
64451
|
const sdk = opencodePkg?.dependencies?.["@opencode/plugin"] ?? opencodePkg?.devDependencies?.["@opencode/plugin"];
|
|
64129
64452
|
const sdkVersion = typeof sdk === "string" ? (sdk.match(/^\d+(?:\.\d+){0,2}/) ?? [])[0] : null;
|
|
64130
64453
|
if (sdkVersion && !semverAtLeast(sdkVersion, SUPPORT_MATRIX.opencode.minimum)) {
|
|
@@ -64151,17 +64474,17 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64151
64474
|
status: "pass",
|
|
64152
64475
|
detail: "opencode CLI not on PATH — skipping version check"
|
|
64153
64476
|
};
|
|
64154
|
-
const scratch = mkdtempSync(
|
|
64477
|
+
const scratch = mkdtempSync(path31.join(os8.tmpdir(), "workit-doctor-opencode-"));
|
|
64155
64478
|
let raw;
|
|
64156
64479
|
try {
|
|
64157
64480
|
raw = versionOf("opencode", {
|
|
64158
64481
|
...res.env,
|
|
64159
|
-
XDG_DATA_HOME:
|
|
64160
|
-
XDG_STATE_HOME:
|
|
64161
|
-
XDG_CACHE_HOME:
|
|
64482
|
+
XDG_DATA_HOME: path31.join(scratch, "data"),
|
|
64483
|
+
XDG_STATE_HOME: path31.join(scratch, "state"),
|
|
64484
|
+
XDG_CACHE_HOME: path31.join(scratch, "cache")
|
|
64162
64485
|
}, 5000);
|
|
64163
64486
|
} finally {
|
|
64164
|
-
|
|
64487
|
+
rmSync3(scratch, { recursive: true, force: true });
|
|
64165
64488
|
}
|
|
64166
64489
|
const installed = raw ? (raw.match(/\d+\.\d+\.\d+/) ?? [])[0] ?? null : null;
|
|
64167
64490
|
if (installed === null)
|
|
@@ -64216,7 +64539,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64216
64539
|
const tables = new Map;
|
|
64217
64540
|
let text;
|
|
64218
64541
|
try {
|
|
64219
|
-
text =
|
|
64542
|
+
text = readFileSync14(file, "utf8");
|
|
64220
64543
|
} catch {
|
|
64221
64544
|
return tables;
|
|
64222
64545
|
}
|
|
@@ -64254,19 +64577,19 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64254
64577
|
current[unquote(pair[1])] = value === "true" ? true : value === "false" ? false : unquote(value);
|
|
64255
64578
|
}
|
|
64256
64579
|
return tables;
|
|
64257
|
-
}, codexHomeOf = (res) => res.codexHome ?? (res.env.CODEX_HOME ||
|
|
64580
|
+
}, codexHomeOf = (res) => res.codexHome ?? (res.env.CODEX_HOME || path31.join(res.home, ".codex")), codexWorkitInstalls = (res) => {
|
|
64258
64581
|
const codexHome = codexHomeOf(res);
|
|
64259
|
-
const configFile =
|
|
64582
|
+
const configFile = path31.join(codexHome, "config.toml");
|
|
64260
64583
|
const installs = [];
|
|
64261
64584
|
for (const [key, table] of readTomlTables(configFile)) {
|
|
64262
64585
|
const [kind, id, ...rest] = key.split("\x00");
|
|
64263
64586
|
if (kind !== "plugins" || rest.length > 0 || !id?.startsWith("workit@") || table.enabled === false)
|
|
64264
64587
|
continue;
|
|
64265
64588
|
const marketplace = id.slice("workit@".length);
|
|
64266
|
-
const dir =
|
|
64589
|
+
const dir = path31.join(codexHome, "plugins", "cache", marketplace, "workit");
|
|
64267
64590
|
let versions = [];
|
|
64268
64591
|
try {
|
|
64269
|
-
versions = readdirSync7(dir).filter((v) =>
|
|
64592
|
+
versions = readdirSync7(dir).filter((v) => existsSync14(path31.join(dir, v, ".codex-plugin")));
|
|
64270
64593
|
} catch {
|
|
64271
64594
|
versions = [];
|
|
64272
64595
|
}
|
|
@@ -64274,7 +64597,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64274
64597
|
installs.push({
|
|
64275
64598
|
id,
|
|
64276
64599
|
marketplace,
|
|
64277
|
-
root: version ?
|
|
64600
|
+
root: version ? path31.join(dir, version) : null,
|
|
64278
64601
|
version,
|
|
64279
64602
|
configFile
|
|
64280
64603
|
});
|
|
@@ -64296,7 +64619,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64296
64619
|
};
|
|
64297
64620
|
return `sha256:${createHash13("sha256").update(JSON.stringify(body)).digest("hex")}`;
|
|
64298
64621
|
}, codexHookTrust = (install, tables) => {
|
|
64299
|
-
const hooks = install.root ? readJson(
|
|
64622
|
+
const hooks = install.root ? readJson(path31.join(install.root, "hooks", "hooks.json"))?.hooks : null;
|
|
64300
64623
|
if (!hooks || typeof hooks !== "object")
|
|
64301
64624
|
return null;
|
|
64302
64625
|
const result = [];
|
|
@@ -64369,28 +64692,28 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64369
64692
|
status: "pass",
|
|
64370
64693
|
detail: "no Workit Codex plugin enabled — skipping"
|
|
64371
64694
|
};
|
|
64372
|
-
const agentsDir =
|
|
64695
|
+
const agentsDir = path31.join(codexHomeOf(res), "agents");
|
|
64373
64696
|
const problems = [];
|
|
64374
64697
|
const fixes = [];
|
|
64375
64698
|
const installed = [];
|
|
64376
64699
|
for (const install of installs) {
|
|
64377
|
-
const source = install.root ?
|
|
64378
|
-
const files = source &&
|
|
64700
|
+
const source = install.root ? path31.join(install.root, "agents") : null;
|
|
64701
|
+
const files = source && existsSync14(source) ? readdirSync7(source).filter((f) => f.endsWith(".toml")).toSorted() : [];
|
|
64379
64702
|
if (files.length === 0) {
|
|
64380
64703
|
problems.push(`${install.id} ${install.version ?? "?"} bundles no agents`);
|
|
64381
64704
|
fixes.push(`codex plugin remove ${install.id} && codex plugin add ${install.id}`);
|
|
64382
64705
|
continue;
|
|
64383
64706
|
}
|
|
64384
|
-
const install_fix = `node ${JSON.stringify(
|
|
64385
|
-
const pluginVersion = readJson(
|
|
64707
|
+
const install_fix = `node ${JSON.stringify(path31.join(install.root, "dist", "launch-mcp.js"))} --install-agents, then start a new Codex session`;
|
|
64708
|
+
const pluginVersion = readJson(path31.join(install.root, "package.json"))?.version;
|
|
64386
64709
|
const version = typeof pluginVersion === "string" ? pluginVersion.match(SEMVER)?.[0] ?? null : null;
|
|
64387
64710
|
let stale = false;
|
|
64388
64711
|
for (const file of files) {
|
|
64389
|
-
const dest =
|
|
64390
|
-
const want = stampCodexAgent(
|
|
64712
|
+
const dest = path31.join(agentsDir, file);
|
|
64713
|
+
const want = stampCodexAgent(readFileSync14(path31.join(source, file), "utf8"), version);
|
|
64391
64714
|
let link = false;
|
|
64392
64715
|
try {
|
|
64393
|
-
link =
|
|
64716
|
+
link = lstatSync5(dest).isSymbolicLink();
|
|
64394
64717
|
} catch {
|
|
64395
64718
|
link = false;
|
|
64396
64719
|
}
|
|
@@ -64401,7 +64724,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64401
64724
|
}
|
|
64402
64725
|
let have = null;
|
|
64403
64726
|
try {
|
|
64404
|
-
have =
|
|
64727
|
+
have = readFileSync14(dest, "utf8");
|
|
64405
64728
|
} catch {
|
|
64406
64729
|
have = null;
|
|
64407
64730
|
}
|
|
@@ -64440,7 +64763,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64440
64763
|
const env = res.env.PI_CODING_AGENT_DIR;
|
|
64441
64764
|
if (env)
|
|
64442
64765
|
return env === "~" ? res.home : env.replace(/^~(?=\/|\\)/, res.home);
|
|
64443
|
-
return
|
|
64766
|
+
return path31.join(res.home, ".pi", "agent");
|
|
64444
64767
|
}, npmSpecName = (spec) => {
|
|
64445
64768
|
const at = spec.indexOf("@", spec.startsWith("@") ? 1 : 0);
|
|
64446
64769
|
return at > 0 ? { name: spec.slice(0, at), pinned: true } : { name: spec, pinned: false };
|
|
@@ -64448,10 +64771,10 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64448
64771
|
const scopes = [
|
|
64449
64772
|
{
|
|
64450
64773
|
scope: "project",
|
|
64451
|
-
settingsFile:
|
|
64452
|
-
base:
|
|
64774
|
+
settingsFile: path31.join(res.cwd, ".pi", "settings.json"),
|
|
64775
|
+
base: path31.join(res.cwd, ".pi")
|
|
64453
64776
|
},
|
|
64454
|
-
{ scope: "user", settingsFile:
|
|
64777
|
+
{ scope: "user", settingsFile: path31.join(agentDir, "settings.json"), base: agentDir }
|
|
64455
64778
|
];
|
|
64456
64779
|
for (const { scope, settingsFile, base } of scopes) {
|
|
64457
64780
|
const packages = readJson(settingsFile)?.packages;
|
|
@@ -64466,13 +64789,13 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64466
64789
|
const spec = npmSpecName(source.slice(4).trim());
|
|
64467
64790
|
if (spec.name !== PI_PACKAGE)
|
|
64468
64791
|
continue;
|
|
64469
|
-
const root =
|
|
64792
|
+
const root = path31.join(base, "npm", "node_modules", ...PI_PACKAGE.split("/"));
|
|
64470
64793
|
return { scope, settingsFile, source, filter, root, npm: { pinned: spec.pinned } };
|
|
64471
64794
|
}
|
|
64472
64795
|
if (/^(git:|https?:|ssh:|git@)/.test(source))
|
|
64473
64796
|
continue;
|
|
64474
|
-
const local =
|
|
64475
|
-
if (readJson(
|
|
64797
|
+
const local = path31.resolve(base, source.replace(/^~(?=\/|\\)/, res.home));
|
|
64798
|
+
if (readJson(path31.join(local, "package.json"))?.name === PI_PACKAGE)
|
|
64476
64799
|
return { scope, settingsFile, source, filter, root: local, npm: null };
|
|
64477
64800
|
}
|
|
64478
64801
|
}
|
|
@@ -64483,7 +64806,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64483
64806
|
const list = patterns.filter((p) => typeof p === "string");
|
|
64484
64807
|
if (list.length === 0)
|
|
64485
64808
|
return false;
|
|
64486
|
-
const name =
|
|
64809
|
+
const name = path31.posix.basename(file);
|
|
64487
64810
|
const matches = (p) => {
|
|
64488
64811
|
const re = globToRegExp3(p);
|
|
64489
64812
|
return re.test(file) || re.test(name);
|
|
@@ -64500,7 +64823,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64500
64823
|
return kept;
|
|
64501
64824
|
}, checkPiExtension = (res) => {
|
|
64502
64825
|
const agentDir = piAgentDirOf(res);
|
|
64503
|
-
if (!
|
|
64826
|
+
if (!existsSync14(agentDir) && !commandOnPath("pi", res.env))
|
|
64504
64827
|
return { id: "pi_extension", status: "pass", detail: "Pi not installed — skipping" };
|
|
64505
64828
|
const installCmd = (scope, spec = `npm:${PI_PACKAGE}`) => `pi install ${spec}${scope === "project" ? " -l" : ""}`;
|
|
64506
64829
|
const entry = findPiEntry(res, agentDir);
|
|
@@ -64508,12 +64831,12 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64508
64831
|
return {
|
|
64509
64832
|
id: "pi_extension",
|
|
64510
64833
|
status: "warn",
|
|
64511
|
-
detail: `Workit Pi extension missing: no ${PI_PACKAGE} entry in ${
|
|
64834
|
+
detail: `Workit Pi extension missing: no ${PI_PACKAGE} entry in ${path31.join(agentDir, "settings.json")} or ${path31.join(res.cwd, ".pi", "settings.json")}`,
|
|
64512
64835
|
fix: installCmd("user")
|
|
64513
64836
|
};
|
|
64514
64837
|
const where = `${entry.source} (${entry.scope}, ${entry.settingsFile})`;
|
|
64515
64838
|
const rebuild = `cd ${JSON.stringify(entry.root)} && bun run build`;
|
|
64516
|
-
const pkg = readJson(
|
|
64839
|
+
const pkg = readJson(path31.join(entry.root, "package.json"));
|
|
64517
64840
|
if (!pkg)
|
|
64518
64841
|
return {
|
|
64519
64842
|
id: "pi_extension",
|
|
@@ -64522,7 +64845,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64522
64845
|
fix: entry.npm ? installCmd(entry.scope, entry.source) : `restore ${entry.root}, then ${rebuild}`
|
|
64523
64846
|
};
|
|
64524
64847
|
const declared = Array.isArray(pkg.pi?.extensions) ? pkg.pi.extensions.some((e) => typeof e === "string" && e.replace(/^\.\//, "") === PI_EXTENSION) : false;
|
|
64525
|
-
if (!declared || !
|
|
64848
|
+
if (!declared || !existsSync14(path31.join(entry.root, PI_EXTENSION)))
|
|
64526
64849
|
return {
|
|
64527
64850
|
id: "pi_extension",
|
|
64528
64851
|
status: "warn",
|
|
@@ -64575,25 +64898,25 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64575
64898
|
detail: `Workit Pi extension ${version ?? "?"} from ${where} loads ${PI_EXTENSION}`
|
|
64576
64899
|
};
|
|
64577
64900
|
}, assetPathsFor = (host, dev) => {
|
|
64578
|
-
const pkg =
|
|
64901
|
+
const pkg = path31.join(dev, "packages", `workit-${host}`);
|
|
64579
64902
|
switch (host) {
|
|
64580
64903
|
case "opencode": {
|
|
64581
|
-
const packaged =
|
|
64582
|
-
const root =
|
|
64583
|
-
return WORKIT_METHOD_SKILLS.map((skill) =>
|
|
64904
|
+
const packaged = path31.join(pkg, "assets", "skills");
|
|
64905
|
+
const root = existsSync14(packaged) ? packaged : path31.join(dev, "packages", "workit-core", "skills");
|
|
64906
|
+
return WORKIT_METHOD_SKILLS.map((skill) => path31.join(root, skill, "SKILL.md"));
|
|
64584
64907
|
}
|
|
64585
64908
|
case "cursor":
|
|
64586
64909
|
return [
|
|
64587
|
-
|
|
64588
|
-
|
|
64589
|
-
|
|
64910
|
+
path31.join(pkg, "assets", "templates", "workit-contract.md"),
|
|
64911
|
+
path31.join(pkg, "mcp.json"),
|
|
64912
|
+
path31.join(pkg, ".cursor-plugin")
|
|
64590
64913
|
];
|
|
64591
64914
|
case "cli":
|
|
64592
|
-
return [
|
|
64915
|
+
return [path31.join(pkg, "assets", "templates", "spec-template.md")];
|
|
64593
64916
|
}
|
|
64594
64917
|
}, hostsFor = (host) => host === "cli" ? ["opencode", "cursor", "cli"] : [host], checkAssets = (res) => {
|
|
64595
64918
|
const dev = res.dev;
|
|
64596
|
-
const missing = dev ? hostsFor(res.host).flatMap((h) => assetPathsFor(h, dev).filter((p) => !
|
|
64919
|
+
const missing = dev ? hostsFor(res.host).flatMap((h) => assetPathsFor(h, dev).filter((p) => !existsSync14(p)).map((p) => `${h}: ${p}`)) : [];
|
|
64597
64920
|
if (res.host === "cursor" || res.host === "cli") {
|
|
64598
64921
|
const cursorError = validateCursorSkills(res.cursorPluginDir, WORKIT_METHOD_SKILLS);
|
|
64599
64922
|
if (cursorError)
|
|
@@ -64620,31 +64943,31 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64620
64943
|
fix: "Reinstall or rebuild the workit package (missing assets under packages/workit-<host>)"
|
|
64621
64944
|
};
|
|
64622
64945
|
}, launcherSlotsFor = (host, dev) => {
|
|
64623
|
-
const pkg =
|
|
64946
|
+
const pkg = path31.join(dev, "packages", `workit-${host}`);
|
|
64624
64947
|
switch (host) {
|
|
64625
64948
|
case "opencode":
|
|
64626
|
-
return [[
|
|
64949
|
+
return [[path31.join(pkg, "src", "plugin.ts"), path31.join(pkg, "dist", "plugin.js")]];
|
|
64627
64950
|
case "cursor":
|
|
64628
64951
|
return [
|
|
64629
|
-
[
|
|
64630
|
-
[
|
|
64952
|
+
[path31.join(pkg, "dist", "mcp-server.js")],
|
|
64953
|
+
[path31.join(pkg, "dist", "cursor-session-start.js")]
|
|
64631
64954
|
];
|
|
64632
64955
|
case "cli":
|
|
64633
|
-
return [[
|
|
64956
|
+
return [[path31.join(pkg, "src", "index.tsx"), path31.join(pkg, "dist", "index.js")]];
|
|
64634
64957
|
}
|
|
64635
64958
|
}, validNodeEntry = (entry, runtime, env) => {
|
|
64636
64959
|
try {
|
|
64637
|
-
const stat =
|
|
64638
|
-
if (!stat.isFile() || stat.size === 0 || !
|
|
64960
|
+
const stat = statSync5(entry);
|
|
64961
|
+
if (!stat.isFile() || stat.size === 0 || !readFileSync14(entry, "utf8").startsWith(`#!/usr/bin/env node
|
|
64639
64962
|
`)) {
|
|
64640
64963
|
return false;
|
|
64641
64964
|
}
|
|
64642
|
-
return
|
|
64965
|
+
return spawnSync14(runtime, ["--check", entry], { encoding: "utf8", env }).status === 0;
|
|
64643
64966
|
} catch {
|
|
64644
64967
|
return false;
|
|
64645
64968
|
}
|
|
64646
64969
|
}, registeredCursorLauncher = (res) => {
|
|
64647
|
-
if (!
|
|
64970
|
+
if (!existsSync14(res.cursorMcp))
|
|
64648
64971
|
return "invalid";
|
|
64649
64972
|
const config = readJson(res.cursorMcp);
|
|
64650
64973
|
if (!config)
|
|
@@ -64657,7 +64980,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64657
64980
|
if (typeof command !== "string" || !Array.isArray(args) || typeof args[0] !== "string") {
|
|
64658
64981
|
return "invalid";
|
|
64659
64982
|
}
|
|
64660
|
-
const executable =
|
|
64983
|
+
const executable = path31.basename(command).toLowerCase();
|
|
64661
64984
|
const canonical = cursorMcpServerEntry("").args;
|
|
64662
64985
|
if (executable === "npx" || executable === "npx.exe" || executable === "npx.cmd") {
|
|
64663
64986
|
if (args.length !== canonical.length || args.some((a, i) => a !== canonical[i]))
|
|
@@ -64669,11 +64992,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64669
64992
|
return {
|
|
64670
64993
|
kind: "node",
|
|
64671
64994
|
runtime: command,
|
|
64672
|
-
entry:
|
|
64995
|
+
entry: path31.isAbsolute(args[0]) ? args[0] : path31.resolve(path31.dirname(res.cursorMcp), args[0])
|
|
64673
64996
|
};
|
|
64674
64997
|
}, canonicalCursorHook, isCanonicalCursorHook = (command, res) => command === canonicalCursorHook || command === cursorHooksEntry(res.cursorPluginDir).command, registeredCursorHook = (res) => {
|
|
64675
|
-
const hooksFile =
|
|
64676
|
-
if (!
|
|
64998
|
+
const hooksFile = path31.join(res.cursorPluginDir, "hooks", "hooks-cursor.json");
|
|
64999
|
+
if (!existsSync14(hooksFile))
|
|
64677
65000
|
return "invalid";
|
|
64678
65001
|
const config = readJson(hooksFile);
|
|
64679
65002
|
if (!config)
|
|
@@ -64690,9 +65013,9 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64690
65013
|
if (!m)
|
|
64691
65014
|
return false;
|
|
64692
65015
|
const entry = m[1].trim();
|
|
64693
|
-
if (!
|
|
65016
|
+
if (!path31.isAbsolute(entry))
|
|
64694
65017
|
return false;
|
|
64695
|
-
if (
|
|
65018
|
+
if (path31.resolve(entry) !== path31.resolve(path31.join(res.cursorPluginDir, "dist", "cursor-session-start.js"))) {
|
|
64696
65019
|
return false;
|
|
64697
65020
|
}
|
|
64698
65021
|
return validNodeEntry(entry, "node", res.env);
|
|
@@ -64701,7 +65024,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64701
65024
|
const hosts = hostsFor(res.host);
|
|
64702
65025
|
const registered = hosts.includes("cursor") ? registeredCursorLauncher(res) : null;
|
|
64703
65026
|
const runtime = registered && registered !== "invalid" && registered.kind === "node" ? registered.runtime : "node";
|
|
64704
|
-
const missing = hosts.includes("cursor") ? ["dist/mcp-server.js", "dist/cursor-session-start.js"].map((rel) =>
|
|
65027
|
+
const missing = hosts.includes("cursor") ? ["dist/mcp-server.js", "dist/cursor-session-start.js"].map((rel) => path31.join(res.cursorPluginDir, rel)).filter((p) => !validNodeEntry(p, runtime, res.env)).map((p) => `cursor: ${p}`) : [];
|
|
64705
65028
|
if (hosts.includes("cursor")) {
|
|
64706
65029
|
if (registered === "invalid") {
|
|
64707
65030
|
missing.push(`cursor: canonical workit MCP launcher in ${res.cursorMcp}`);
|
|
@@ -64710,13 +65033,13 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64710
65033
|
}
|
|
64711
65034
|
const hook = registeredCursorHook(res);
|
|
64712
65035
|
if (hook === "invalid") {
|
|
64713
|
-
missing.push(`cursor: canonical session-start hook in ${
|
|
65036
|
+
missing.push(`cursor: canonical session-start hook in ${path31.join(res.cursorPluginDir, "hooks", "hooks-cursor.json")}`);
|
|
64714
65037
|
} else if (hook !== null && !isCanonicalCursorHook(hook, res) && !validLocalDistHook(hook, res)) {
|
|
64715
|
-
missing.push(`cursor: canonical session-start hook in ${
|
|
65038
|
+
missing.push(`cursor: canonical session-start hook in ${path31.join(res.cursorPluginDir, "hooks", "hooks-cursor.json")} (registered ${hook})`);
|
|
64716
65039
|
}
|
|
64717
65040
|
}
|
|
64718
65041
|
if (dev) {
|
|
64719
|
-
missing.push(...hosts.filter((h) => h !== "cursor").flatMap((h) => launcherSlotsFor(h, dev).filter((slot) => !slot.some((p) =>
|
|
65042
|
+
missing.push(...hosts.filter((h) => h !== "cursor").flatMap((h) => launcherSlotsFor(h, dev).filter((slot) => !slot.some((p) => existsSync14(p))).map((slot) => `${h}: ${slot.join(" or ")}`)));
|
|
64720
65043
|
}
|
|
64721
65044
|
if (missing.length > 0) {
|
|
64722
65045
|
return {
|
|
@@ -64741,21 +65064,21 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64741
65064
|
}, CURSOR_HOOK_FIX = "Run `workit init` and select Cursor to install the bundled hook", checkCursorHook = (res) => {
|
|
64742
65065
|
if (!hostsFor(res.host).includes("cursor"))
|
|
64743
65066
|
return { id: "cursor_hook", status: "pass", detail: "cursor hook not inspected on this host" };
|
|
64744
|
-
if (!
|
|
65067
|
+
if (!existsSync14(res.cursorPluginDir))
|
|
64745
65068
|
return {
|
|
64746
65069
|
id: "cursor_hook",
|
|
64747
65070
|
status: "pass",
|
|
64748
65071
|
detail: "no Cursor plugin install — hook launcher not inspected"
|
|
64749
65072
|
};
|
|
64750
|
-
const launcher =
|
|
64751
|
-
if (!
|
|
65073
|
+
const launcher = path31.join(res.cursorPluginDir, "hooks", "launch.mjs");
|
|
65074
|
+
if (!existsSync14(launcher))
|
|
64752
65075
|
return {
|
|
64753
65076
|
id: "cursor_hook",
|
|
64754
65077
|
status: "warn",
|
|
64755
65078
|
detail: `cursor hook launcher mode: missing — ${launcher} is absent (an install from before the pinned launcher)`,
|
|
64756
65079
|
fix: CURSOR_HOOK_FIX
|
|
64757
65080
|
};
|
|
64758
|
-
const hooksFile =
|
|
65081
|
+
const hooksFile = path31.join(res.cursorPluginDir, "hooks", "hooks-cursor.json");
|
|
64759
65082
|
const registered = readJson(hooksFile);
|
|
64760
65083
|
const sessionCommand = registered?.hooks?.sessionStart?.[0]?.command;
|
|
64761
65084
|
const offLauncher = [
|
|
@@ -64770,7 +65093,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64770
65093
|
fix: "Re-run install-cursor-plugin.sh (or `workit init` with Cursor) to rewrite the hook entries"
|
|
64771
65094
|
};
|
|
64772
65095
|
const started = performance.now();
|
|
64773
|
-
const probe =
|
|
65096
|
+
const probe = spawnSync14("node", [launcher, "--probe", "workit-cursor-hook"], {
|
|
64774
65097
|
encoding: "utf8",
|
|
64775
65098
|
env: { ...res.env, WORKIT_CURSOR_HOOK_NPX_OFFLINE: "1" },
|
|
64776
65099
|
timeout: 40000,
|
|
@@ -64817,15 +65140,15 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64817
65140
|
return { id: "cursor_hook", status: "pass", detail: `${label}; probe ${ms} ms` };
|
|
64818
65141
|
}, SILENT_HOOK_GRACE_MS, mtimeMs = (file) => {
|
|
64819
65142
|
try {
|
|
64820
|
-
return
|
|
65143
|
+
return statSync5(file).mtimeMs;
|
|
64821
65144
|
} catch {
|
|
64822
65145
|
return null;
|
|
64823
65146
|
}
|
|
64824
65147
|
}, silentCursorHooks = (res) => {
|
|
64825
|
-
const session = mtimeMs(
|
|
65148
|
+
const session = mtimeMs(path31.join(res.cursorHeartbeatDir, "cursor-session-last-start"));
|
|
64826
65149
|
if (session === null || Date.now() - session < SILENT_HOOK_GRACE_MS)
|
|
64827
65150
|
return null;
|
|
64828
|
-
const hook = mtimeMs(
|
|
65151
|
+
const hook = mtimeMs(path31.join(res.cursorHeartbeatDir, "cursor-hook-last-run"));
|
|
64829
65152
|
if (hook !== null && hook >= session)
|
|
64830
65153
|
return null;
|
|
64831
65154
|
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`;
|
|
@@ -64866,7 +65189,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64866
65189
|
return "fragile-cache";
|
|
64867
65190
|
if (entry.startsWith("file:")) {
|
|
64868
65191
|
const target = entry.replace(/^file:\/\//, "").replace(/^file:/, "");
|
|
64869
|
-
return
|
|
65192
|
+
return existsSync14(target) ? "ok" : "missing-file";
|
|
64870
65193
|
}
|
|
64871
65194
|
return "ok";
|
|
64872
65195
|
}, checkStalePin = (res) => {
|
|
@@ -64877,7 +65200,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64877
65200
|
detail: "opencode pin not inspected on the cursor host"
|
|
64878
65201
|
};
|
|
64879
65202
|
}
|
|
64880
|
-
if (!
|
|
65203
|
+
if (!existsSync14(res.opencodeConfig)) {
|
|
64881
65204
|
return {
|
|
64882
65205
|
id: "stale_pin",
|
|
64883
65206
|
status: "pass",
|
|
@@ -64921,8 +65244,8 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64921
65244
|
}
|
|
64922
65245
|
return { id: "stale_pin", status: "pass", detail: "opencode pin resolves" };
|
|
64923
65246
|
}, pluginMcpSelectors = (res) => {
|
|
64924
|
-
const p =
|
|
64925
|
-
if (!
|
|
65247
|
+
const p = path31.join(res.cursorPluginDir, "mcp.json");
|
|
65248
|
+
if (!existsSync14(p))
|
|
64926
65249
|
return null;
|
|
64927
65250
|
const cfg = readJson(p);
|
|
64928
65251
|
const server = cfg?.mcpServers?.workit;
|
|
@@ -64944,7 +65267,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64944
65267
|
if (!cmd)
|
|
64945
65268
|
return null;
|
|
64946
65269
|
try {
|
|
64947
|
-
const r =
|
|
65270
|
+
const r = spawnSync14(cmd, ["view", pkgName, "version"], {
|
|
64948
65271
|
encoding: "utf8",
|
|
64949
65272
|
timeout: 20000,
|
|
64950
65273
|
env: res.env
|
|
@@ -64955,13 +65278,13 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64955
65278
|
return null;
|
|
64956
65279
|
}
|
|
64957
65280
|
}, installedPluginVersion = (res) => {
|
|
64958
|
-
const pkg = readJson(
|
|
65281
|
+
const pkg = readJson(path31.join(res.cursorPluginDir, "package.json"));
|
|
64959
65282
|
return typeof pkg?.version === "string" && pkg.version ? pkg.version : null;
|
|
64960
65283
|
}, installedOpenCodeCacheVersion = (res) => {
|
|
64961
|
-
const pkg = readJson(
|
|
65284
|
+
const pkg = readJson(path31.join(res.opencodePackageCacheDir, "node_modules", "@brainervirus", "workit-opencode", "package.json"));
|
|
64962
65285
|
return typeof pkg?.version === "string" && pkg.version ? pkg.version : null;
|
|
64963
65286
|
}, checkOpenCodePackageCache = (res) => {
|
|
64964
|
-
if (!
|
|
65287
|
+
if (!existsSync14(res.opencodeConfig)) {
|
|
64965
65288
|
return {
|
|
64966
65289
|
id: "stale_install",
|
|
64967
65290
|
status: "pass",
|
|
@@ -65035,7 +65358,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65035
65358
|
detail: "cursor plugin not inspected on this host"
|
|
65036
65359
|
};
|
|
65037
65360
|
}
|
|
65038
|
-
if (
|
|
65361
|
+
if (existsSync14(res.cursorPluginDir) && lstatSync5(res.cursorPluginDir).isSymbolicLink()) {
|
|
65039
65362
|
let target = "";
|
|
65040
65363
|
try {
|
|
65041
65364
|
target = readlinkSync2(res.cursorPluginDir);
|
|
@@ -65061,7 +65384,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65061
65384
|
fix: "Re-run install-cursor-plugin.sh — it rewrites the workit MCP entry to the canonical @latest selector"
|
|
65062
65385
|
};
|
|
65063
65386
|
}
|
|
65064
|
-
const hooksFile =
|
|
65387
|
+
const hooksFile = path31.join(res.cursorPluginDir, "hooks", "hooks-cursor.json");
|
|
65065
65388
|
const hookCmd = readJson(hooksFile)?.hooks?.sessionStart?.[0]?.command ?? null;
|
|
65066
65389
|
const canonicalHook = canonicalCursorHook;
|
|
65067
65390
|
const staleHook = hookCmd !== null && !isCanonicalCursorHook(hookCmd, res) && !hookCmd.startsWith("node ") && hookCmd.includes("@brainervirus/workit-cursor@");
|
|
@@ -65073,7 +65396,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65073
65396
|
fix: "Re-run install-cursor-plugin.sh — it rewrites the sessionStart hook to the canonical pinned launcher"
|
|
65074
65397
|
};
|
|
65075
65398
|
}
|
|
65076
|
-
const hookDrift =
|
|
65399
|
+
const hookDrift = existsSync14(hooksFile) ? cursorHookDrift(readJson(hooksFile), res.cursorPluginDir) : [];
|
|
65077
65400
|
if (hookDrift.length > 0) {
|
|
65078
65401
|
return {
|
|
65079
65402
|
id: "stale_install",
|
|
@@ -65083,7 +65406,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65083
65406
|
};
|
|
65084
65407
|
}
|
|
65085
65408
|
const installed = installedPluginVersion(res);
|
|
65086
|
-
const source = res.dev ? readJson(
|
|
65409
|
+
const source = res.dev ? readJson(path31.join(res.dev, "packages/workit-cursor/package.json"))?.version ?? null : readJson(path31.join(packageRoot(), "package.json"))?.version ?? null;
|
|
65087
65410
|
const localDist = mcpSelectors === null && hookCmd !== null && !isCanonicalCursorHook(hookCmd, res) && hookCmd.startsWith("node ");
|
|
65088
65411
|
if (localDist && installed !== null && source !== null && !semverAtLeast(installed, source)) {
|
|
65089
65412
|
return {
|
|
@@ -65095,7 +65418,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65095
65418
|
}
|
|
65096
65419
|
if (localDist && installed !== null && source !== null && res.dev) {
|
|
65097
65420
|
const entry = /^node\s+(.+)$/.exec((hookCmd ?? "").trim())?.[1]?.trim() ?? "";
|
|
65098
|
-
const sourceBundle = entry &&
|
|
65421
|
+
const sourceBundle = entry && path31.isAbsolute(entry) ? path31.join(res.dev, "packages", "workit-cursor", "dist", path31.basename(entry)) : "";
|
|
65099
65422
|
if (entry && sourceBundle) {
|
|
65100
65423
|
const installedHash = bundleHashOfFile(entry);
|
|
65101
65424
|
const sourceHash = bundleHashOfFile(sourceBundle);
|
|
@@ -65103,7 +65426,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65103
65426
|
return {
|
|
65104
65427
|
id: "stale_install",
|
|
65105
65428
|
status: "fail",
|
|
65106
|
-
detail: `stale_install: installed workit-cursor ${installed} runs different bytes than the current runtime build (${
|
|
65429
|
+
detail: `stale_install: installed workit-cursor ${installed} runs different bytes than the current runtime build (${path31.basename(entry)} hash mismatch)`,
|
|
65107
65430
|
fix: "Re-run install-cursor-plugin.sh — it refreshes the plugin directory with the current build"
|
|
65108
65431
|
};
|
|
65109
65432
|
}
|
|
@@ -65157,13 +65480,13 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65157
65480
|
const problems = [];
|
|
65158
65481
|
const opencodeHost = res.host !== "cursor";
|
|
65159
65482
|
const cursorHost = res.host !== "opencode";
|
|
65160
|
-
if (opencodeHost &&
|
|
65483
|
+
if (opencodeHost && existsSync14(res.opencodeConfig)) {
|
|
65161
65484
|
const cfg = readJson(res.opencodeConfig);
|
|
65162
65485
|
const entries = pluginEntries(cfg);
|
|
65163
65486
|
if (entries.length > 1)
|
|
65164
65487
|
problems.push(`opencode registers ${entries.length} workit plugin entries`);
|
|
65165
65488
|
}
|
|
65166
|
-
if (cursorHost &&
|
|
65489
|
+
if (cursorHost && existsSync14(res.cursorSettings)) {
|
|
65167
65490
|
const settings = readJson(res.cursorSettings);
|
|
65168
65491
|
const enabled = settings?.enabled_plugins;
|
|
65169
65492
|
if (enabled && typeof enabled === "object") {
|
|
@@ -65178,7 +65501,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65178
65501
|
if (dirs.length > 1)
|
|
65179
65502
|
problems.push(`cursor plugin_dirs has ${dirs.length} workit entries`);
|
|
65180
65503
|
}
|
|
65181
|
-
if (cursorHost &&
|
|
65504
|
+
if (cursorHost && existsSync14(res.cursorMcp)) {
|
|
65182
65505
|
const mcp = readJson(res.cursorMcp);
|
|
65183
65506
|
const servers = mcp?.mcpServers ?? {};
|
|
65184
65507
|
if (servers && typeof servers === "object") {
|
|
@@ -65203,17 +65526,17 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65203
65526
|
}, checkMalformedConfig = (res) => {
|
|
65204
65527
|
const files = [];
|
|
65205
65528
|
for (const name of ["config.json", "youtrack.json", "vcs.json", "workspaces.json"]) {
|
|
65206
|
-
const p =
|
|
65207
|
-
if (
|
|
65529
|
+
const p = path31.join(res.configDir, name);
|
|
65530
|
+
if (existsSync14(p))
|
|
65208
65531
|
files.push(p);
|
|
65209
65532
|
}
|
|
65210
65533
|
const opencodeHost = res.host !== "cursor";
|
|
65211
65534
|
const cursorHost = res.host !== "opencode";
|
|
65212
|
-
if (opencodeHost &&
|
|
65535
|
+
if (opencodeHost && existsSync14(res.opencodeConfig))
|
|
65213
65536
|
files.push(res.opencodeConfig);
|
|
65214
|
-
if (cursorHost &&
|
|
65537
|
+
if (cursorHost && existsSync14(res.cursorSettings))
|
|
65215
65538
|
files.push(res.cursorSettings);
|
|
65216
|
-
if (cursorHost &&
|
|
65539
|
+
if (cursorHost && existsSync14(res.cursorMcp))
|
|
65217
65540
|
files.push(res.cursorMcp);
|
|
65218
65541
|
const bad = files.filter((p) => !parsesAsConfigObject(p));
|
|
65219
65542
|
if (bad.length === 0)
|
|
@@ -65292,19 +65615,90 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65292
65615
|
detail: `current directory ${res.cwd} does not match any configured workspace`,
|
|
65293
65616
|
fix: `Add a workspace glob matching this directory to ${file} or run /wk-init`
|
|
65294
65617
|
};
|
|
65618
|
+
}, matchedWorkspace = (res) => {
|
|
65619
|
+
try {
|
|
65620
|
+
return resolveWorkspaceFrom(res.cwd, res.configDir, res.env.WORKFLOW_WORKSPACE_NAME?.trim() || undefined);
|
|
65621
|
+
} catch {
|
|
65622
|
+
return null;
|
|
65623
|
+
}
|
|
65624
|
+
}, SESSION_HOOK_FIX = "workit doctor --fix", sessionHookFinding = (hook) => {
|
|
65625
|
+
const slot = `${SESSION_HOOK_NAME} hook`;
|
|
65626
|
+
switch (hook.state) {
|
|
65627
|
+
case "not_git":
|
|
65628
|
+
return { status: "pass", detail: `not inside a git work tree — skipping the ${slot}` };
|
|
65629
|
+
case "installed":
|
|
65630
|
+
return {
|
|
65631
|
+
status: "pass",
|
|
65632
|
+
detail: `${slot} ${hook.hookPath} adds the Workit-Session trailer to plain git commits`
|
|
65633
|
+
};
|
|
65634
|
+
case "manual":
|
|
65635
|
+
return hook.helperCurrent ? {
|
|
65636
|
+
status: "pass",
|
|
65637
|
+
detail: `${hook.manualTarget} adds the Workit-Session trailer to plain git commits (via ${hook.via})`
|
|
65638
|
+
} : {
|
|
65639
|
+
status: "warn",
|
|
65640
|
+
detail: `${hook.manualTarget} runs the Workit helper (via ${hook.via}), but ${hook.helperPath} is missing or an older version`,
|
|
65641
|
+
fix: SESSION_HOOK_FIX
|
|
65642
|
+
};
|
|
65643
|
+
case "missing":
|
|
65644
|
+
return {
|
|
65645
|
+
status: "warn",
|
|
65646
|
+
detail: `no ${slot} at ${hook.hookPath}: plain git commits from an agent session get no Workit-Session trailer`,
|
|
65647
|
+
fix: SESSION_HOOK_FIX
|
|
65648
|
+
};
|
|
65649
|
+
case "outdated":
|
|
65650
|
+
return {
|
|
65651
|
+
status: "warn",
|
|
65652
|
+
detail: `the Workit ${slot} at ${hook.hookPath} or its helper ${hook.helperPath} is missing or an older version`,
|
|
65653
|
+
fix: SESSION_HOOK_FIX
|
|
65654
|
+
};
|
|
65655
|
+
case "blocked":
|
|
65656
|
+
return {
|
|
65657
|
+
status: "warn",
|
|
65658
|
+
detail: `plain git commits get no Workit-Session trailer and --fix will not install the ${slot}: ${hook.reason}`,
|
|
65659
|
+
fix: hook.helperCurrent ? hook.manual : `${SESSION_HOOK_FIX} (writes ${hook.helperPath}), then ${hook.manual}`
|
|
65660
|
+
};
|
|
65661
|
+
}
|
|
65662
|
+
}, checkSessionHook = (res) => {
|
|
65663
|
+
if (!matchedWorkspace(res))
|
|
65664
|
+
return {
|
|
65665
|
+
id: "session_hook",
|
|
65666
|
+
status: "pass",
|
|
65667
|
+
detail: `not in a Workit workspace — skipping the ${SESSION_HOOK_NAME} session hook`
|
|
65668
|
+
};
|
|
65669
|
+
const hook = inspectSessionHook(res.cwd, res.env);
|
|
65670
|
+
const finding = sessionHookFinding(hook);
|
|
65671
|
+
if (!hook.leftover)
|
|
65672
|
+
return { id: "session_hook", ...finding };
|
|
65673
|
+
return {
|
|
65674
|
+
id: "session_hook",
|
|
65675
|
+
status: "warn",
|
|
65676
|
+
detail: `${finding.detail}; ${hook.leftover}`,
|
|
65677
|
+
fix: finding.fix ? `${finding.fix}; ${hook.leftover}` : hook.leftover
|
|
65678
|
+
};
|
|
65679
|
+
}, fixSessionHook = (options = {}) => {
|
|
65680
|
+
const res = resolve(options);
|
|
65681
|
+
const workspace = matchedWorkspace(res);
|
|
65682
|
+
if (!workspace)
|
|
65683
|
+
return {
|
|
65684
|
+
action: "skipped",
|
|
65685
|
+
detail: `${res.cwd} is not in a Workit workspace; no hook installed`,
|
|
65686
|
+
workspace: null
|
|
65687
|
+
};
|
|
65688
|
+
return { ...installSessionHook(res.cwd, res.env), workspace: workspace.name };
|
|
65295
65689
|
}, isPlaceholder = (p) => {
|
|
65296
65690
|
try {
|
|
65297
|
-
return
|
|
65691
|
+
return readFileSync14(p, "utf8").trim() === TOKEN_PLACEHOLDER2;
|
|
65298
65692
|
} catch {
|
|
65299
65693
|
return false;
|
|
65300
65694
|
}
|
|
65301
65695
|
}, checkCredentialMetadata = (res) => {
|
|
65302
65696
|
const tokenPaths = [];
|
|
65303
|
-
const youtrackJson = readJson(
|
|
65697
|
+
const youtrackJson = readJson(path31.join(res.configDir, "youtrack.json"));
|
|
65304
65698
|
if (youtrackJson) {
|
|
65305
|
-
tokenPaths.push(typeof youtrackJson.tokenFile === "string" ? youtrackJson.tokenFile :
|
|
65306
|
-
} else if (
|
|
65307
|
-
tokenPaths.push(
|
|
65699
|
+
tokenPaths.push(typeof youtrackJson.tokenFile === "string" ? youtrackJson.tokenFile : path31.join(res.configDir, "youtrack.token"));
|
|
65700
|
+
} else if (existsSync14(path31.join(res.configDir, "youtrack.token"))) {
|
|
65701
|
+
tokenPaths.push(path31.join(res.configDir, "youtrack.token"));
|
|
65308
65702
|
}
|
|
65309
65703
|
if (tokenPaths.length === 0) {
|
|
65310
65704
|
return {
|
|
@@ -65315,13 +65709,13 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65315
65709
|
}
|
|
65316
65710
|
const problems = [];
|
|
65317
65711
|
for (const raw of tokenPaths) {
|
|
65318
|
-
const p =
|
|
65319
|
-
if (!
|
|
65712
|
+
const p = path31.isAbsolute(raw) ? raw : path31.resolve(res.configDir, raw);
|
|
65713
|
+
if (!existsSync14(p)) {
|
|
65320
65714
|
problems.push(`${p} is missing`);
|
|
65321
65715
|
continue;
|
|
65322
65716
|
}
|
|
65323
65717
|
if (process.platform !== "win32") {
|
|
65324
|
-
const mode =
|
|
65718
|
+
const mode = statSync5(p).mode & 511;
|
|
65325
65719
|
if (mode !== 384)
|
|
65326
65720
|
problems.push(`${p} must be mode 0600 (found ${mode.toString(8)})`);
|
|
65327
65721
|
}
|
|
@@ -65383,7 +65777,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65383
65777
|
}, defaultIdentityProbes = (env) => ({
|
|
65384
65778
|
origin: (cwd) => {
|
|
65385
65779
|
try {
|
|
65386
|
-
const out =
|
|
65780
|
+
const out = spawnSync14("git", ["remote", "get-url", "origin"], {
|
|
65387
65781
|
cwd,
|
|
65388
65782
|
encoding: "utf8",
|
|
65389
65783
|
env
|
|
@@ -65395,7 +65789,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65395
65789
|
},
|
|
65396
65790
|
ghLogin: (e) => {
|
|
65397
65791
|
try {
|
|
65398
|
-
const out =
|
|
65792
|
+
const out = spawnSync14("gh", ["api", "user", "--jq", ".login"], { encoding: "utf8", env: e });
|
|
65399
65793
|
const login = (out.stdout ?? "").trim();
|
|
65400
65794
|
return out.status === 0 && login ? login : null;
|
|
65401
65795
|
} catch {
|
|
@@ -65404,7 +65798,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65404
65798
|
},
|
|
65405
65799
|
glabLogin: (e) => {
|
|
65406
65800
|
try {
|
|
65407
|
-
const out =
|
|
65801
|
+
const out = spawnSync14("glab", ["api", "user", "--jq", ".username"], {
|
|
65408
65802
|
encoding: "utf8",
|
|
65409
65803
|
env: e
|
|
65410
65804
|
});
|
|
@@ -65416,7 +65810,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65416
65810
|
},
|
|
65417
65811
|
sshLogin: (host) => {
|
|
65418
65812
|
try {
|
|
65419
|
-
const out =
|
|
65813
|
+
const out = spawnSync14("ssh", ["-o", "BatchMode=yes", "-o", "ConnectTimeout=5", "-T", `git@${host}`], {
|
|
65420
65814
|
encoding: "utf8",
|
|
65421
65815
|
env
|
|
65422
65816
|
});
|
|
@@ -65431,7 +65825,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65431
65825
|
const remoteHost = githubHostFromRemote(probes.origin(res.cwd) ?? "");
|
|
65432
65826
|
if (!remoteHost)
|
|
65433
65827
|
return { id: "github_identity", status: "pass", detail: "no GitHub remote configured" };
|
|
65434
|
-
const vcsJson = readJson(res.env.WORKFLOW_VCS_CONFIG ??
|
|
65828
|
+
const vcsJson = readJson(res.env.WORKFLOW_VCS_CONFIG ?? path31.join(res.configDir, "vcs.json"));
|
|
65435
65829
|
const workspace = workspaceProviderForIdentity(res.cwd, res.configDir, res.env);
|
|
65436
65830
|
if (workspace.error)
|
|
65437
65831
|
return {
|
|
@@ -65459,7 +65853,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65459
65853
|
const remoteHost = githubHostFromRemote(probes.origin(res.cwd) ?? "");
|
|
65460
65854
|
if (!remoteHost)
|
|
65461
65855
|
return { id: "gitlab_identity", status: "pass", detail: "no GitLab remote configured" };
|
|
65462
|
-
const vcsJson = readJson(res.env.WORKFLOW_VCS_CONFIG ??
|
|
65856
|
+
const vcsJson = readJson(res.env.WORKFLOW_VCS_CONFIG ?? path31.join(res.configDir, "vcs.json"));
|
|
65463
65857
|
const workspace = workspaceProviderForIdentity(res.cwd, res.configDir, res.env);
|
|
65464
65858
|
if (workspace.error)
|
|
65465
65859
|
return {
|
|
@@ -65485,11 +65879,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65485
65879
|
{ surface: "SSH", login: probes.sshLogin(remoteHost) }
|
|
65486
65880
|
]);
|
|
65487
65881
|
}, checkLogWritable = (res) => {
|
|
65488
|
-
const logsDir =
|
|
65489
|
-
const probe =
|
|
65882
|
+
const logsDir = path31.join(res.stateDir, "logs");
|
|
65883
|
+
const probe = path31.join(logsDir, "doctor-probe.tmp");
|
|
65490
65884
|
try {
|
|
65491
|
-
|
|
65492
|
-
|
|
65885
|
+
mkdirSync6(logsDir, { recursive: true, mode: 448 });
|
|
65886
|
+
writeFileSync7(probe, `{"probe":true}
|
|
65493
65887
|
`, { mode: 384 });
|
|
65494
65888
|
return {
|
|
65495
65889
|
id: "log_writable",
|
|
@@ -65576,7 +65970,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65576
65970
|
}, CLI_PACKAGE = "@brainervirus/workit-cli", SEMVER, WORKIT_PROBE_TIMEOUT_MS = 1e4, workitVersions, workitVersionAt = (bin, env) => {
|
|
65577
65971
|
let key;
|
|
65578
65972
|
try {
|
|
65579
|
-
const st =
|
|
65973
|
+
const st = statSync5(bin);
|
|
65580
65974
|
key = `${bin}:${st.ino}:${st.size}:${st.mtimeMs}`;
|
|
65581
65975
|
} catch {
|
|
65582
65976
|
return { version: null, timedOut: false };
|
|
@@ -65585,12 +65979,12 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65585
65979
|
if (cached)
|
|
65586
65980
|
return cached;
|
|
65587
65981
|
const viaShell = process.platform === "win32" && /\.(?:cmd|bat)$/i.test(bin);
|
|
65588
|
-
const r = viaShell ?
|
|
65982
|
+
const r = viaShell ? spawnSync14(`"${bin}" --version`, {
|
|
65589
65983
|
encoding: "utf8",
|
|
65590
65984
|
env,
|
|
65591
65985
|
timeout: WORKIT_PROBE_TIMEOUT_MS,
|
|
65592
65986
|
shell: true
|
|
65593
|
-
}) :
|
|
65987
|
+
}) : spawnSync14(bin, ["--version"], { encoding: "utf8", env, timeout: WORKIT_PROBE_TIMEOUT_MS });
|
|
65594
65988
|
const timedOut = r.error !== undefined && "code" in r.error && r.error.code === "ETIMEDOUT";
|
|
65595
65989
|
const version = r.status === 0 ? (r.stdout ?? "").match(SEMVER)?.[0] ?? null : null;
|
|
65596
65990
|
const probe = { version: timedOut ? null : version, timedOut };
|
|
@@ -65680,6 +66074,7 @@ var init_doctor = __esm(() => {
|
|
|
65680
66074
|
init_workspaces();
|
|
65681
66075
|
init_host_install();
|
|
65682
66076
|
init_skill_manifests();
|
|
66077
|
+
init_session_hook();
|
|
65683
66078
|
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`;
|
|
65684
66079
|
AGENT_MARKER_VERSION = /^# Generated by Workit (\d+\.\d+\.\d+)\b/;
|
|
65685
66080
|
canonicalCursorHook = cursorHooksEntry().command;
|
|
@@ -65706,6 +66101,7 @@ var init_doctor = __esm(() => {
|
|
|
65706
66101
|
checkMalformedConfig,
|
|
65707
66102
|
checkWorkspaceMismatch,
|
|
65708
66103
|
checkWorkspaceLock,
|
|
66104
|
+
checkSessionHook,
|
|
65709
66105
|
checkCredentialMetadata,
|
|
65710
66106
|
checkGithubIdentity,
|
|
65711
66107
|
checkGitLabIdentity,
|
|
@@ -65727,20 +66123,20 @@ var init_doctor = __esm(() => {
|
|
|
65727
66123
|
import {
|
|
65728
66124
|
copyFileSync as copyFileSync4,
|
|
65729
66125
|
cpSync as cpSync4,
|
|
65730
|
-
existsSync as
|
|
65731
|
-
lstatSync as
|
|
65732
|
-
mkdirSync as
|
|
66126
|
+
existsSync as existsSync15,
|
|
66127
|
+
lstatSync as lstatSync6,
|
|
66128
|
+
mkdirSync as mkdirSync7,
|
|
65733
66129
|
mkdtempSync as mkdtempSync2,
|
|
65734
|
-
readFileSync as
|
|
66130
|
+
readFileSync as readFileSync15,
|
|
65735
66131
|
readdirSync as readdirSync8,
|
|
65736
66132
|
realpathSync as realpathSync7,
|
|
65737
|
-
renameSync as
|
|
65738
|
-
rmSync as
|
|
65739
|
-
statSync as
|
|
65740
|
-
writeFileSync as
|
|
66133
|
+
renameSync as renameSync4,
|
|
66134
|
+
rmSync as rmSync4,
|
|
66135
|
+
statSync as statSync6,
|
|
66136
|
+
writeFileSync as writeFileSync8
|
|
65741
66137
|
} from "node:fs";
|
|
65742
66138
|
import os9 from "node:os";
|
|
65743
|
-
import
|
|
66139
|
+
import path32 from "node:path";
|
|
65744
66140
|
import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
|
|
65745
66141
|
function parseList(raw) {
|
|
65746
66142
|
return raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
@@ -65784,7 +66180,7 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
65784
66180
|
const current = readConfigFromDir(state.configDir);
|
|
65785
66181
|
mutations.push({
|
|
65786
66182
|
type: "merge-json",
|
|
65787
|
-
path:
|
|
66183
|
+
path: path32.join(state.configDir, "config.json"),
|
|
65788
66184
|
value: {
|
|
65789
66185
|
locale: values.locale,
|
|
65790
66186
|
localeOptions: current.localeOptions,
|
|
@@ -65810,17 +66206,17 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
65810
66206
|
if (blocked.length === 0) {
|
|
65811
66207
|
mutations.push({
|
|
65812
66208
|
type: "update-workspaces",
|
|
65813
|
-
path:
|
|
66209
|
+
path: path32.join(state.configDir, "workspaces.json"),
|
|
65814
66210
|
entries: values.workspaces,
|
|
65815
66211
|
expectedRevision: diskWorkspaceResult.revision
|
|
65816
66212
|
});
|
|
65817
66213
|
}
|
|
65818
66214
|
}
|
|
65819
66215
|
if (values.baseUrl.trim()) {
|
|
65820
|
-
const ytPath =
|
|
66216
|
+
const ytPath = path32.join(state.configDir, "youtrack.json");
|
|
65821
66217
|
const ytExisting = readConfigRecord(ytPath);
|
|
65822
66218
|
const ytConfigured = configuredTokenPath(ytExisting, "tokenFile");
|
|
65823
|
-
const tokenPath = resolveTokenPath(ytConfigured,
|
|
66219
|
+
const tokenPath = resolveTokenPath(ytConfigured, path32.join(state.configDir, "youtrack.token"), values.tokenPaths?.youtrack);
|
|
65824
66220
|
const draft = youtrackDraft(values, tokenPath);
|
|
65825
66221
|
if (ytConfigured !== null && tokenPath !== ytConfigured) {
|
|
65826
66222
|
delete draft.tokenFile;
|
|
@@ -65836,7 +66232,7 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
65836
66232
|
path: ytPath,
|
|
65837
66233
|
value: draft
|
|
65838
66234
|
});
|
|
65839
|
-
if (
|
|
66235
|
+
if (existsSync15(tokenPath))
|
|
65840
66236
|
preserved.push(tokenPath);
|
|
65841
66237
|
else
|
|
65842
66238
|
mutations.push({
|
|
@@ -65848,7 +66244,7 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
65848
66244
|
});
|
|
65849
66245
|
}
|
|
65850
66246
|
if (values.vcsProvider !== "skip") {
|
|
65851
|
-
const vcsPath =
|
|
66247
|
+
const vcsPath = path32.join(state.configDir, "vcs.json");
|
|
65852
66248
|
mutations.push({
|
|
65853
66249
|
type: "merge-json",
|
|
65854
66250
|
path: vcsPath,
|
|
@@ -65877,7 +66273,7 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
65877
66273
|
mutations.push({
|
|
65878
66274
|
type: "install-host",
|
|
65879
66275
|
platform: "cursor",
|
|
65880
|
-
path:
|
|
66276
|
+
path: path32.join(paths.home, ".cursor", "plugins", "local", ".workit-package-bootstrap"),
|
|
65881
66277
|
commands
|
|
65882
66278
|
});
|
|
65883
66279
|
}
|
|
@@ -65890,7 +66286,7 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
65890
66286
|
mutations.push({
|
|
65891
66287
|
type: "install-host",
|
|
65892
66288
|
platform,
|
|
65893
|
-
path: platform === "claude-code" ? claudeInstallRecord(paths.home, env) : platform === "codex" ?
|
|
66289
|
+
path: platform === "claude-code" ? claudeInstallRecord(paths.home, env) : platform === "codex" ? path32.join(env.CODEX_HOME ?? path32.join(paths.home, ".codex"), "plugins", "cache", "workflow-toolkit", "workit") : path32.join(env.PI_CODING_AGENT_DIR ?? path32.join(paths.home, ".pi", "agent"), "settings.json"),
|
|
65894
66290
|
commands
|
|
65895
66291
|
});
|
|
65896
66292
|
}
|
|
@@ -65898,9 +66294,9 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
65898
66294
|
}
|
|
65899
66295
|
}
|
|
65900
66296
|
if (values.applyProject) {
|
|
65901
|
-
const root =
|
|
65902
|
-
const gitignorePath =
|
|
65903
|
-
const existing =
|
|
66297
|
+
const root = path32.resolve(opts.cwd ?? process.cwd());
|
|
66298
|
+
const gitignorePath = path32.join(root, ".gitignore");
|
|
66299
|
+
const existing = existsSync15(gitignorePath) ? readFileSync15(gitignorePath, "utf8") : "";
|
|
65904
66300
|
const existingLines = new Set(existing.split(`
|
|
65905
66301
|
`).map((l) => l.trim()).filter(Boolean));
|
|
65906
66302
|
const entries = GITIGNORE_ENTRIES.filter((e) => e.trim() !== "" && !existingLines.has(e.trim()));
|
|
@@ -65936,10 +66332,10 @@ function deepMerge(base, patch) {
|
|
|
65936
66332
|
return out;
|
|
65937
66333
|
}
|
|
65938
66334
|
function applyMutation(m) {
|
|
65939
|
-
const dir =
|
|
66335
|
+
const dir = path32.dirname(m.path);
|
|
65940
66336
|
switch (m.type) {
|
|
65941
66337
|
case "create-file": {
|
|
65942
|
-
|
|
66338
|
+
mkdirSync7(dir, { recursive: true });
|
|
65943
66339
|
const res = writeFileExclusive(m.path, m.content, m.mode);
|
|
65944
66340
|
return res === "created" ? { platform: "core", file: m.path, status: "Installed" } : {
|
|
65945
66341
|
platform: "core",
|
|
@@ -65962,8 +66358,8 @@ function applyMutation(m) {
|
|
|
65962
66358
|
if (existing.kind === "record" && JSON.stringify(existing.value) === JSON.stringify(merged)) {
|
|
65963
66359
|
return { platform: "core", file: m.path, status: "Skipped", detail: "already configured" };
|
|
65964
66360
|
}
|
|
65965
|
-
|
|
65966
|
-
|
|
66361
|
+
mkdirSync7(dir, { recursive: true });
|
|
66362
|
+
writeFileSync8(m.path, JSON.stringify(merged, null, 2) + `
|
|
65967
66363
|
`, "utf8");
|
|
65968
66364
|
return existing.kind === "record" ? { platform: "core", file: m.path, status: "Configured" } : { platform: "core", file: m.path, status: "Installed" };
|
|
65969
66365
|
}
|
|
@@ -66004,12 +66400,12 @@ function applyMutation(m) {
|
|
|
66004
66400
|
`;
|
|
66005
66401
|
if (prev === next)
|
|
66006
66402
|
return { platform: "core", file: m.path, status: "Skipped", detail: "already configured" };
|
|
66007
|
-
|
|
66403
|
+
mkdirSync7(dir, { recursive: true });
|
|
66008
66404
|
const tmp = `${m.path}.${process.pid}.tmp`;
|
|
66009
66405
|
try {
|
|
66010
|
-
|
|
66406
|
+
writeFileSync8(tmp, next, "utf8");
|
|
66011
66407
|
if (workspacesRevision(readFileSafe(m.path)) !== m.expectedRevision) {
|
|
66012
|
-
|
|
66408
|
+
rmSync4(tmp, { force: true });
|
|
66013
66409
|
return {
|
|
66014
66410
|
platform: "core",
|
|
66015
66411
|
file: m.path,
|
|
@@ -66017,9 +66413,9 @@ function applyMutation(m) {
|
|
|
66017
66413
|
detail: "workspace config changed while applying the preview; rebuild and review it"
|
|
66018
66414
|
};
|
|
66019
66415
|
}
|
|
66020
|
-
|
|
66416
|
+
renameSync4(tmp, m.path);
|
|
66021
66417
|
} catch (error) {
|
|
66022
|
-
|
|
66418
|
+
rmSync4(tmp, { force: true });
|
|
66023
66419
|
return {
|
|
66024
66420
|
platform: "core",
|
|
66025
66421
|
file: m.path,
|
|
@@ -66042,11 +66438,11 @@ function applyMutation(m) {
|
|
|
66042
66438
|
detail: "all entries already present"
|
|
66043
66439
|
};
|
|
66044
66440
|
}
|
|
66045
|
-
|
|
66441
|
+
mkdirSync7(dir, { recursive: true });
|
|
66046
66442
|
const separator = existing && !existing.endsWith(`
|
|
66047
66443
|
`) ? `
|
|
66048
66444
|
` : "";
|
|
66049
|
-
|
|
66445
|
+
writeFileSync8(m.path, existing + separator + (existing ? `
|
|
66050
66446
|
` : "") + add.join(`
|
|
66051
66447
|
`) + `
|
|
66052
66448
|
`, "utf8");
|
|
@@ -66085,8 +66481,8 @@ function applyMutation(m) {
|
|
|
66085
66481
|
detail: "already configured"
|
|
66086
66482
|
};
|
|
66087
66483
|
}
|
|
66088
|
-
|
|
66089
|
-
|
|
66484
|
+
mkdirSync7(path32.dirname(m.path), { recursive: true });
|
|
66485
|
+
writeFileSync8(m.path, JSON.stringify(merged, null, 2) + `
|
|
66090
66486
|
`, "utf8");
|
|
66091
66487
|
return existing.kind === "record" ? { platform: "core", file: m.path, status: "Configured" } : { platform: "core", file: m.path, status: "Installed" };
|
|
66092
66488
|
}
|
|
@@ -66094,23 +66490,23 @@ function applyMutation(m) {
|
|
|
66094
66490
|
}
|
|
66095
66491
|
function adapterRoot(platform, res, preferInstalledAdapter = false) {
|
|
66096
66492
|
const candidates = [];
|
|
66097
|
-
const stagedCursor =
|
|
66493
|
+
const stagedCursor = path32.join(res.home, ".cursor", "plugins", "local", ".workit-package-bootstrap", "node_modules", "@brainervirus", "workit-cursor");
|
|
66098
66494
|
if (platform === "cursor" && preferInstalledAdapter)
|
|
66099
66495
|
candidates.push(stagedCursor);
|
|
66100
66496
|
if (res.dev) {
|
|
66101
|
-
candidates.push(
|
|
66497
|
+
candidates.push(path32.join(res.dev, "packages", `workit-${platform}`));
|
|
66102
66498
|
} else {
|
|
66103
|
-
candidates.push(
|
|
66104
|
-
let dir =
|
|
66499
|
+
candidates.push(path32.join(packageRoot(), "..", `workit-${platform}`));
|
|
66500
|
+
let dir = path32.resolve(res.cwd);
|
|
66105
66501
|
while (true) {
|
|
66106
|
-
candidates.push(
|
|
66107
|
-
const parent =
|
|
66502
|
+
candidates.push(path32.join(dir, "packages", `workit-${platform}`));
|
|
66503
|
+
const parent = path32.dirname(dir);
|
|
66108
66504
|
if (parent === dir)
|
|
66109
66505
|
break;
|
|
66110
66506
|
dir = parent;
|
|
66111
66507
|
}
|
|
66112
66508
|
}
|
|
66113
|
-
candidates.push(
|
|
66509
|
+
candidates.push(path32.join(res.home, ".local", "share", "workit", "packages", `workit-${platform}`));
|
|
66114
66510
|
if (platform === "cursor")
|
|
66115
66511
|
candidates.push(stagedCursor);
|
|
66116
66512
|
for (const candidate of candidates) {
|
|
@@ -66129,7 +66525,7 @@ function applyOpenCode(root, res) {
|
|
|
66129
66525
|
detail: "workit-opencode package has no loadable plugin entry (src/plugin.ts or dist/plugin.js)"
|
|
66130
66526
|
};
|
|
66131
66527
|
}
|
|
66132
|
-
|
|
66528
|
+
mkdirSync7(path32.dirname(res.opencodeConfig), { recursive: true });
|
|
66133
66529
|
const existing = readExisting(res.opencodeConfig);
|
|
66134
66530
|
if (existing.kind === "malformed") {
|
|
66135
66531
|
return {
|
|
@@ -66158,7 +66554,7 @@ function applyOpenCode(root, res) {
|
|
|
66158
66554
|
detail: "already registered"
|
|
66159
66555
|
};
|
|
66160
66556
|
}
|
|
66161
|
-
|
|
66557
|
+
writeFileSync8(res.opencodeConfig, JSON.stringify(merged.config, null, 2) + `
|
|
66162
66558
|
`, "utf8");
|
|
66163
66559
|
return existing.kind === "record" ? {
|
|
66164
66560
|
platform: "opencode",
|
|
@@ -66174,54 +66570,54 @@ function applyOpenCode(root, res) {
|
|
|
66174
66570
|
}
|
|
66175
66571
|
function copyPluginDir(src, dest) {
|
|
66176
66572
|
const realSrc = realpathSync7(src);
|
|
66177
|
-
const marker =
|
|
66178
|
-
const destIsLink =
|
|
66573
|
+
const marker = path32.join(dest, ".workit-root");
|
|
66574
|
+
const destIsLink = existsSync15(dest) && lstatSync6(dest).isSymbolicLink();
|
|
66179
66575
|
const synced = !destIsLink && readFileSafe(marker)?.trim() === realSrc && samePluginContent(realSrc, dest, dest);
|
|
66180
66576
|
if (synced)
|
|
66181
66577
|
return "Skipped";
|
|
66182
|
-
const hadDir =
|
|
66578
|
+
const hadDir = existsSync15(dest);
|
|
66183
66579
|
const rules = preservedCursorRules(realSrc, dest);
|
|
66184
|
-
const parent =
|
|
66185
|
-
|
|
66186
|
-
const swap = mkdtempSync2(
|
|
66187
|
-
const stage =
|
|
66188
|
-
const backup =
|
|
66580
|
+
const parent = path32.dirname(dest);
|
|
66581
|
+
mkdirSync7(parent, { recursive: true });
|
|
66582
|
+
const swap = mkdtempSync2(path32.join(parent, `.${path32.basename(dest)}.swap-`));
|
|
66583
|
+
const stage = path32.join(swap, "stage");
|
|
66584
|
+
const backup = path32.join(swap, "backup");
|
|
66189
66585
|
try {
|
|
66190
66586
|
cpSync4(realSrc, stage, {
|
|
66191
66587
|
recursive: true,
|
|
66192
|
-
filter: (entry) => !
|
|
66588
|
+
filter: (entry) => !path32.relative(realSrc, entry).split(path32.sep).includes("node_modules")
|
|
66193
66589
|
});
|
|
66194
|
-
const stagedHooks =
|
|
66195
|
-
if (
|
|
66196
|
-
|
|
66590
|
+
const stagedHooks = path32.join(stage, CURSOR_HOOKS_FILE);
|
|
66591
|
+
if (existsSync15(stagedHooks))
|
|
66592
|
+
writeFileSync8(stagedHooks, localizedCursorHooks(readFileSync15(stagedHooks), dest));
|
|
66197
66593
|
for (const [name, content] of rules) {
|
|
66198
|
-
|
|
66199
|
-
|
|
66594
|
+
mkdirSync7(path32.join(stage, "rules"), { recursive: true });
|
|
66595
|
+
writeFileSync8(path32.join(stage, "rules", name), content);
|
|
66200
66596
|
}
|
|
66201
|
-
|
|
66597
|
+
writeFileSync8(path32.join(stage, ".workit-root"), realSrc + `
|
|
66202
66598
|
`, "utf8");
|
|
66203
66599
|
if (!samePluginContent(realSrc, stage, dest))
|
|
66204
66600
|
throw new Error("staged adapter content is incomplete");
|
|
66205
|
-
if (
|
|
66601
|
+
if (lstatSync6(stage).isSymbolicLink()) {
|
|
66206
66602
|
throw new Error("staged adapter resolved to a symlink — refusing fragile cache install");
|
|
66207
66603
|
}
|
|
66208
66604
|
if (hadDir)
|
|
66209
|
-
|
|
66605
|
+
renameSync4(dest, backup);
|
|
66210
66606
|
try {
|
|
66211
|
-
|
|
66607
|
+
renameSync4(stage, dest);
|
|
66212
66608
|
} catch (error) {
|
|
66213
|
-
if (hadDir && !
|
|
66214
|
-
|
|
66609
|
+
if (hadDir && !existsSync15(dest))
|
|
66610
|
+
renameSync4(backup, dest);
|
|
66215
66611
|
throw error;
|
|
66216
66612
|
}
|
|
66217
|
-
|
|
66613
|
+
rmSync4(backup, { recursive: true, force: true });
|
|
66218
66614
|
} finally {
|
|
66219
|
-
|
|
66615
|
+
rmSync4(swap, { recursive: true, force: true });
|
|
66220
66616
|
}
|
|
66221
66617
|
return hadDir ? "Configured" : "Installed";
|
|
66222
66618
|
}
|
|
66223
66619
|
function applyCursorSettings(root, res) {
|
|
66224
|
-
|
|
66620
|
+
mkdirSync7(path32.dirname(res.cursorSettings), { recursive: true });
|
|
66225
66621
|
const settingsExisting = readExisting(res.cursorSettings);
|
|
66226
66622
|
if (settingsExisting.kind === "malformed") {
|
|
66227
66623
|
return {
|
|
@@ -66240,7 +66636,7 @@ function applyCursorSettings(root, res) {
|
|
|
66240
66636
|
detail: "already registered"
|
|
66241
66637
|
};
|
|
66242
66638
|
}
|
|
66243
|
-
|
|
66639
|
+
writeFileSync8(res.cursorSettings, JSON.stringify(settings.config, null, 2) + `
|
|
66244
66640
|
`, "utf8");
|
|
66245
66641
|
return {
|
|
66246
66642
|
platform: "cursor",
|
|
@@ -66249,7 +66645,7 @@ function applyCursorSettings(root, res) {
|
|
|
66249
66645
|
};
|
|
66250
66646
|
}
|
|
66251
66647
|
function applyCursorMcp(root, res) {
|
|
66252
|
-
|
|
66648
|
+
mkdirSync7(path32.dirname(res.cursorMcp), { recursive: true });
|
|
66253
66649
|
const mcpExisting = readExisting(res.cursorMcp);
|
|
66254
66650
|
if (mcpExisting.kind === "malformed") {
|
|
66255
66651
|
return {
|
|
@@ -66279,7 +66675,7 @@ function applyCursorMcp(root, res) {
|
|
|
66279
66675
|
detail: "already registered"
|
|
66280
66676
|
};
|
|
66281
66677
|
}
|
|
66282
|
-
|
|
66678
|
+
writeFileSync8(res.cursorMcp, JSON.stringify(mcp.config, null, 2) + `
|
|
66283
66679
|
`, "utf8");
|
|
66284
66680
|
return {
|
|
66285
66681
|
platform: "cursor",
|
|
@@ -66288,9 +66684,9 @@ function applyCursorMcp(root, res) {
|
|
|
66288
66684
|
};
|
|
66289
66685
|
}
|
|
66290
66686
|
function verifyPlatform(platform, res) {
|
|
66291
|
-
if (platform === "opencode" && !
|
|
66687
|
+
if (platform === "opencode" && !existsSync15(res.opencodeConfig))
|
|
66292
66688
|
return null;
|
|
66293
|
-
if (platform === "cursor" && !
|
|
66689
|
+
if (platform === "cursor" && !existsSync15(res.cursorSettings) && !existsSync15(res.cursorMcp)) {
|
|
66294
66690
|
return null;
|
|
66295
66691
|
}
|
|
66296
66692
|
return runDoctor({
|
|
@@ -66355,7 +66751,7 @@ function applySetupPreview(preview, options = {}) {
|
|
|
66355
66751
|
let cursorCopyOk = false;
|
|
66356
66752
|
for (const mutation of preview.mutations) {
|
|
66357
66753
|
if (mutation.type === "install-host") {
|
|
66358
|
-
const expectedPath = mutation.platform === "cursor" ?
|
|
66754
|
+
const expectedPath = mutation.platform === "cursor" ? path32.join(res.home, ".cursor", "plugins", "local", ".workit-package-bootstrap") : mutation.platform === "codex" ? path32.join(res.env.CODEX_HOME ?? path32.join(res.home, ".codex"), "plugins", "cache", "workflow-toolkit", "workit") : mutation.platform === "pi" ? path32.join(res.env.PI_CODING_AGENT_DIR ?? path32.join(res.home, ".pi", "agent"), "settings.json") : mutation.platform === "claude-code" ? claudeInstallRecord(res.home, res.env) : "";
|
|
66359
66755
|
if (mutation.path !== expectedPath) {
|
|
66360
66756
|
entries.push({
|
|
66361
66757
|
platform: mutation.platform,
|
|
@@ -66536,12 +66932,12 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66536
66932
|
return configured ?? fallback;
|
|
66537
66933
|
}, readConfigRecord = (file) => {
|
|
66538
66934
|
try {
|
|
66539
|
-
const value = JSON.parse(
|
|
66935
|
+
const value = JSON.parse(readFileSync15(file, "utf8"));
|
|
66540
66936
|
return isRecord5(value) ? value : null;
|
|
66541
66937
|
} catch {
|
|
66542
66938
|
return null;
|
|
66543
66939
|
}
|
|
66544
|
-
}, claudeInstallRecord = (home, env) =>
|
|
66940
|
+
}, claudeInstallRecord = (home, env) => path32.join(claudeConfigDir(home, env), "plugins", "installed_plugins.json"), resolveSetupPaths = (options, resolvedConfigDir) => {
|
|
66545
66941
|
const env = options.env ?? process.env;
|
|
66546
66942
|
const home = options.home ?? env.HOME ?? os9.homedir();
|
|
66547
66943
|
return {
|
|
@@ -66549,17 +66945,17 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66549
66945
|
configDir: resolvedConfigDir,
|
|
66550
66946
|
cwd: options.cwd ?? process.cwd(),
|
|
66551
66947
|
env,
|
|
66552
|
-
opencodeConfig: options.opencodeConfig ??
|
|
66553
|
-
cursorSettings: options.cursorSettings ??
|
|
66554
|
-
cursorMcp: options.cursorMcp ??
|
|
66555
|
-
cursorPluginDir: options.cursorPluginDir ??
|
|
66948
|
+
opencodeConfig: options.opencodeConfig ?? path32.join(home, ".config", "opencode", "opencode.json"),
|
|
66949
|
+
cursorSettings: options.cursorSettings ?? path32.join(home, ".cursor", "settings.json"),
|
|
66950
|
+
cursorMcp: options.cursorMcp ?? path32.join(home, ".cursor", "mcp.json"),
|
|
66951
|
+
cursorPluginDir: options.cursorPluginDir ?? path32.join(home, ".cursor", "plugins", "local", "workit")
|
|
66556
66952
|
};
|
|
66557
66953
|
}, isRecord5 = (v) => v !== null && typeof v === "object" && !Array.isArray(v), readExisting = (p) => {
|
|
66558
66954
|
let raw;
|
|
66559
66955
|
try {
|
|
66560
|
-
raw =
|
|
66956
|
+
raw = readFileSync15(p, "utf8");
|
|
66561
66957
|
} catch {
|
|
66562
|
-
if (
|
|
66958
|
+
if (existsSync15(p))
|
|
66563
66959
|
return { kind: "malformed", error: `${p} is not readable` };
|
|
66564
66960
|
return { kind: "missing" };
|
|
66565
66961
|
}
|
|
@@ -66574,7 +66970,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66574
66970
|
return { kind: "malformed", error: `${p} is not a JSON object` };
|
|
66575
66971
|
}, readFileSafe = (p) => {
|
|
66576
66972
|
try {
|
|
66577
|
-
return
|
|
66973
|
+
return readFileSync15(p, "utf8");
|
|
66578
66974
|
} catch {
|
|
66579
66975
|
return null;
|
|
66580
66976
|
}
|
|
@@ -66589,7 +66985,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66589
66985
|
}
|
|
66590
66986
|
}, isAdapter = (root, platform) => {
|
|
66591
66987
|
try {
|
|
66592
|
-
const pkg = JSON.parse(
|
|
66988
|
+
const pkg = JSON.parse(readFileSync15(path32.join(root, "package.json"), "utf8"));
|
|
66593
66989
|
return pkg.name === `@brainervirus/workit-${platform}`;
|
|
66594
66990
|
} catch {
|
|
66595
66991
|
return false;
|
|
@@ -66603,8 +66999,8 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66603
66999
|
if (!isDevOpenCodeAdapterRoot(root, opts.dev))
|
|
66604
67000
|
return OPENCODE_NPM_PIN;
|
|
66605
67001
|
for (const rel of ["src/plugin.ts", "dist/plugin.js"]) {
|
|
66606
|
-
const entry =
|
|
66607
|
-
if (
|
|
67002
|
+
const entry = path32.join(root, rel);
|
|
67003
|
+
if (existsSync15(entry))
|
|
66608
67004
|
return `file://${entry}`;
|
|
66609
67005
|
}
|
|
66610
67006
|
return null;
|
|
@@ -66621,22 +67017,22 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66621
67017
|
for (const entry of readdirSync8(src, { withFileTypes: true })) {
|
|
66622
67018
|
if (entry.name === "node_modules")
|
|
66623
67019
|
continue;
|
|
66624
|
-
const source =
|
|
66625
|
-
const installed =
|
|
66626
|
-
const rel =
|
|
67020
|
+
const source = path32.join(src, entry.name);
|
|
67021
|
+
const installed = path32.join(dest, entry.name);
|
|
67022
|
+
const rel = path32.join(relative, entry.name);
|
|
66627
67023
|
if (entry.isDirectory()) {
|
|
66628
|
-
if (!
|
|
67024
|
+
if (!statSync6(installed).isDirectory() || !samePluginContent(source, installed, pluginDir, rel))
|
|
66629
67025
|
return false;
|
|
66630
67026
|
} else {
|
|
66631
|
-
const expected = rel === CURSOR_HOOKS_FILE ? localizedCursorHooks(
|
|
66632
|
-
if (!expected.equals(
|
|
67027
|
+
const expected = rel === CURSOR_HOOKS_FILE ? localizedCursorHooks(readFileSync15(source), pluginDir) : readFileSync15(source);
|
|
67028
|
+
if (!expected.equals(readFileSync15(installed)))
|
|
66633
67029
|
return false;
|
|
66634
67030
|
}
|
|
66635
67031
|
}
|
|
66636
67032
|
for (const entry of readdirSync8(dest, { withFileTypes: true })) {
|
|
66637
|
-
if (
|
|
67033
|
+
if (existsSync15(path32.join(src, entry.name)))
|
|
66638
67034
|
continue;
|
|
66639
|
-
const rel =
|
|
67035
|
+
const rel = path32.join(relative, entry.name);
|
|
66640
67036
|
if (rel === ".workit-root")
|
|
66641
67037
|
continue;
|
|
66642
67038
|
if (relative === "rules" && entry.isFile() && entry.name.endsWith(".mdc"))
|
|
@@ -66649,36 +67045,36 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66649
67045
|
}
|
|
66650
67046
|
}, preservedCursorRules = (src, dest) => {
|
|
66651
67047
|
const preserved = new Map;
|
|
66652
|
-
const sourceRules =
|
|
66653
|
-
const installedRules =
|
|
67048
|
+
const sourceRules = path32.join(src, "rules");
|
|
67049
|
+
const installedRules = path32.join(dest, "rules");
|
|
66654
67050
|
try {
|
|
66655
67051
|
for (const entry of readdirSync8(installedRules, { withFileTypes: true })) {
|
|
66656
67052
|
if (!entry.isFile() || !entry.name.endsWith(".mdc"))
|
|
66657
67053
|
continue;
|
|
66658
|
-
if (
|
|
67054
|
+
if (existsSync15(path32.join(sourceRules, entry.name)))
|
|
66659
67055
|
continue;
|
|
66660
|
-
preserved.set(entry.name,
|
|
67056
|
+
preserved.set(entry.name, readFileSync15(path32.join(installedRules, entry.name)));
|
|
66661
67057
|
}
|
|
66662
67058
|
} catch {}
|
|
66663
67059
|
return preserved;
|
|
66664
67060
|
}, removeLegacyCursorDir = (res) => {
|
|
66665
|
-
const legacy =
|
|
66666
|
-
if (legacy === res.cursorPluginDir || !
|
|
67061
|
+
const legacy = path32.join(res.home, ".cursor", "plugins", "local", "workflow-toolkit");
|
|
67062
|
+
if (legacy === res.cursorPluginDir || !existsSync15(legacy))
|
|
66667
67063
|
return;
|
|
66668
|
-
const legacyRules =
|
|
66669
|
-
if (
|
|
67064
|
+
const legacyRules = path32.join(legacy, "rules");
|
|
67065
|
+
if (existsSync15(legacyRules)) {
|
|
66670
67066
|
try {
|
|
66671
|
-
|
|
67067
|
+
mkdirSync7(path32.join(res.cursorPluginDir, "rules"), { recursive: true });
|
|
66672
67068
|
for (const entry of readdirSync8(legacyRules, { withFileTypes: true })) {
|
|
66673
67069
|
if (!entry.isFile() || !entry.name.endsWith(".mdc"))
|
|
66674
67070
|
continue;
|
|
66675
|
-
const target =
|
|
66676
|
-
if (!
|
|
66677
|
-
copyFileSync4(
|
|
67071
|
+
const target = path32.join(res.cursorPluginDir, "rules", entry.name);
|
|
67072
|
+
if (!existsSync15(target))
|
|
67073
|
+
copyFileSync4(path32.join(legacyRules, entry.name), target);
|
|
66678
67074
|
}
|
|
66679
67075
|
} catch {}
|
|
66680
67076
|
}
|
|
66681
|
-
|
|
67077
|
+
rmSync4(legacy, { recursive: true, force: true });
|
|
66682
67078
|
}, failedDetail = (report) => report.checks.filter((c) => c.status === "fail").map((c) => `${c.id}: ${c.detail}`).join("; "), setupCompletionGuidance = () => [
|
|
66683
67079
|
"Run `workit doctor` to verify your installation.",
|
|
66684
67080
|
"Run /wk-status in OpenCode to review token setup steps."
|
|
@@ -66708,16 +67104,16 @@ var init_setup = __esm(() => {
|
|
|
66708
67104
|
{ envKey: "WORKFLOW_GITHUB_HOST", affects: "vcs.json github.host" }
|
|
66709
67105
|
];
|
|
66710
67106
|
SETUP_OVERRIDES = [...YT_OVERRIDES, ...VCS_OVERRIDES];
|
|
66711
|
-
CURSOR_HOOKS_FILE =
|
|
67107
|
+
CURSOR_HOOKS_FILE = path32.join("hooks", "hooks-cursor.json");
|
|
66712
67108
|
});
|
|
66713
67109
|
|
|
66714
67110
|
// packages/workit-core/src/core/workspace-branch-policy.ts
|
|
66715
|
-
import { mkdirSync as
|
|
66716
|
-
import
|
|
67111
|
+
import { mkdirSync as mkdirSync8, readFileSync as readFileSync16, renameSync as renameSync5, rmSync as rmSync5, writeFileSync as writeFileSync9 } from "node:fs";
|
|
67112
|
+
import path33 from "node:path";
|
|
66717
67113
|
import { isDeepStrictEqual as isDeepStrictEqual3 } from "node:util";
|
|
66718
67114
|
function applyWorkspaceBranchPolicy(opts) {
|
|
66719
67115
|
const { workspace_root, env = process.env } = opts;
|
|
66720
|
-
const dir =
|
|
67116
|
+
const dir = path33.join(env.WORKFLOW_TOOLKIT_CONFIG ?? configDir());
|
|
66721
67117
|
const {
|
|
66722
67118
|
status,
|
|
66723
67119
|
path: wsPath,
|
|
@@ -66729,7 +67125,7 @@ function applyWorkspaceBranchPolicy(opts) {
|
|
|
66729
67125
|
if (status === "malformed" || status === "invalid")
|
|
66730
67126
|
return { ok: false, error: workspacesError ?? `invalid workspaces.json: ${wsPath}` };
|
|
66731
67127
|
const detection = detectBranchPolicy(workspace_root);
|
|
66732
|
-
const name = String(env.WORKFLOW_BP_NAME ??
|
|
67128
|
+
const name = String(env.WORKFLOW_BP_NAME ?? path33.basename(workspace_root));
|
|
66733
67129
|
const integration = env.WORKFLOW_BP_INTEGRATION ?? detection.integration;
|
|
66734
67130
|
const policy = {
|
|
66735
67131
|
preset: detection.preset,
|
|
@@ -66778,22 +67174,22 @@ function applyWorkspaceBranchPolicy(opts) {
|
|
|
66778
67174
|
ok: false,
|
|
66779
67175
|
error: `workspaces.json changed while applying the branch policy: ${wsPath}`
|
|
66780
67176
|
};
|
|
66781
|
-
|
|
67177
|
+
mkdirSync8(path33.dirname(wsPath), { recursive: true });
|
|
66782
67178
|
const tmp = `${wsPath}.${process.pid}.tmp`;
|
|
66783
67179
|
try {
|
|
66784
|
-
|
|
67180
|
+
writeFileSync9(tmp, JSON.stringify({ ...document2, workspaces: next }, null, 2) + `
|
|
66785
67181
|
`, "utf8");
|
|
66786
67182
|
if (workspacesRevision(readFileSafe2(wsPath)) !== revision) {
|
|
66787
|
-
|
|
67183
|
+
rmSync5(tmp, { force: true });
|
|
66788
67184
|
return {
|
|
66789
67185
|
ok: false,
|
|
66790
67186
|
error: `workspaces.json changed while applying the branch policy: ${wsPath}`
|
|
66791
67187
|
};
|
|
66792
67188
|
}
|
|
66793
|
-
|
|
67189
|
+
renameSync5(tmp, wsPath);
|
|
66794
67190
|
} catch (error) {
|
|
66795
67191
|
try {
|
|
66796
|
-
|
|
67192
|
+
rmSync5(tmp, { force: true });
|
|
66797
67193
|
} catch {}
|
|
66798
67194
|
return {
|
|
66799
67195
|
ok: false,
|
|
@@ -66810,7 +67206,7 @@ function applyWorkspaceBranchPolicy(opts) {
|
|
|
66810
67206
|
}
|
|
66811
67207
|
var readFileSafe2 = (p) => {
|
|
66812
67208
|
try {
|
|
66813
|
-
return
|
|
67209
|
+
return readFileSync16(p, "utf8");
|
|
66814
67210
|
} catch {
|
|
66815
67211
|
return null;
|
|
66816
67212
|
}
|
|
@@ -67062,8 +67458,8 @@ var init_logic = __esm(() => {
|
|
|
67062
67458
|
});
|
|
67063
67459
|
|
|
67064
67460
|
// packages/workit-cli/src/wizard-state.ts
|
|
67065
|
-
import { existsSync as
|
|
67066
|
-
import
|
|
67461
|
+
import { existsSync as existsSync16, statSync as statSync7 } from "node:fs";
|
|
67462
|
+
import path34 from "node:path";
|
|
67067
67463
|
import { isDeepStrictEqual as isDeepStrictEqual4 } from "node:util";
|
|
67068
67464
|
function resolveBasePath(values, env = process.env) {
|
|
67069
67465
|
return env.WORKFLOW_WORKSPACE_ROOT?.trim() || values.basePath.trim();
|
|
@@ -67582,7 +67978,7 @@ function workspaceDraftText(draft, field, value) {
|
|
|
67582
67978
|
}
|
|
67583
67979
|
var NEXT, PREV, skipsCustomBranch = (screen, preset) => (screen === "branchAllowed" || screen === "branchProtected") && preset !== "custom", skipsYoutrack = (screen, tracker) => screen === "youtrack" && tracker !== "youtrack", skipsBasePath = (screen, basePath) => screen === "basePath" && basePath !== "", isDirectory = (p) => {
|
|
67584
67980
|
try {
|
|
67585
|
-
return
|
|
67981
|
+
return statSync7(p).isDirectory();
|
|
67586
67982
|
} catch {
|
|
67587
67983
|
return false;
|
|
67588
67984
|
}
|
|
@@ -67590,8 +67986,8 @@ var NEXT, PREV, skipsCustomBranch = (screen, preset) => (screen === "branchAllow
|
|
|
67590
67986
|
const p = value.trim();
|
|
67591
67987
|
if (!p)
|
|
67592
67988
|
return "workspace root path is required";
|
|
67593
|
-
return !
|
|
67594
|
-
}, skipsBranchPolicy = (screen, basePath) => (screen === "branchPolicy" || screen === "branchPolicyDevelop") && !
|
|
67989
|
+
return !path34.isAbsolute(p) || !isDirectory(p) ? `invalid workspace root "${p}" — enter an existing absolute directory` : null;
|
|
67990
|
+
}, skipsBranchPolicy = (screen, basePath) => (screen === "branchPolicy" || screen === "branchPolicyDevelop") && !existsSync16(path34.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;
|
|
67595
67991
|
var init_wizard_state = __esm(() => {
|
|
67596
67992
|
init_config();
|
|
67597
67993
|
init_workspaces();
|
|
@@ -67650,9 +68046,9 @@ var init_wizard_state = __esm(() => {
|
|
|
67650
68046
|
});
|
|
67651
68047
|
|
|
67652
68048
|
// packages/workit-cli/src/admin/uninstall.ts
|
|
67653
|
-
import { existsSync as
|
|
68049
|
+
import { existsSync as existsSync17, readFileSync as readFileSync17, realpathSync as realpathSync8, rmSync as rmSync6, writeFileSync as writeFileSync10 } from "node:fs";
|
|
67654
68050
|
import os10 from "node:os";
|
|
67655
|
-
import
|
|
68051
|
+
import path35 from "node:path";
|
|
67656
68052
|
function cleanCursorSettings(settings, pluginDir) {
|
|
67657
68053
|
const next = { ...settings };
|
|
67658
68054
|
let changed = false;
|
|
@@ -67752,7 +68148,7 @@ function planUninstall(paths = {}) {
|
|
|
67752
68148
|
const mcpExisting = readJsonRecord(res.cursorMcp);
|
|
67753
68149
|
const settingsDirty = settingsExisting.kind === "malformed" || settingsExisting.kind === "record" && cleanCursorSettings(settingsExisting.value, res.cursorPluginDir).changed;
|
|
67754
68150
|
const mcpDirty = mcpExisting.kind === "malformed" || mcpExisting.kind === "record" && cleanCursorMcp(mcpExisting.value).changed;
|
|
67755
|
-
const dirExists =
|
|
68151
|
+
const dirExists = existsSync17(res.cursorPluginDir);
|
|
67756
68152
|
const actions = [];
|
|
67757
68153
|
if (settingsDirty) {
|
|
67758
68154
|
actions.push({
|
|
@@ -67780,7 +68176,7 @@ function planUninstall(paths = {}) {
|
|
|
67780
68176
|
installed: settingsDirty || mcpDirty || dirExists,
|
|
67781
68177
|
actions
|
|
67782
68178
|
};
|
|
67783
|
-
const codexInstalled =
|
|
68179
|
+
const codexInstalled = existsSync17(res.codexPluginDir);
|
|
67784
68180
|
const codex = {
|
|
67785
68181
|
host: "codex",
|
|
67786
68182
|
installed: codexInstalled,
|
|
@@ -67827,17 +68223,17 @@ function applyUninstall(plan, paths = {}) {
|
|
|
67827
68223
|
status = outcome.status;
|
|
67828
68224
|
detail = outcome.detail;
|
|
67829
68225
|
} else if (action.kind === "remove-dir") {
|
|
67830
|
-
const resolved =
|
|
67831
|
-
const allowed = canonicalRemoveDirAllowed(resolved, res) || resolved ===
|
|
68226
|
+
const resolved = path35.resolve(action.path);
|
|
68227
|
+
const allowed = canonicalRemoveDirAllowed(resolved, res) || resolved === path35.resolve(res.codexPluginDir) && path35.basename(resolved) === "workit" && path35.basename(path35.dirname(resolved)) === "plugins";
|
|
67832
68228
|
if (!allowed) {
|
|
67833
68229
|
status = "failed";
|
|
67834
68230
|
detail = `refusing to remove non-canonical plugin directory: ${resolved}`;
|
|
67835
|
-
} else if (!
|
|
68231
|
+
} else if (!existsSync17(resolved)) {
|
|
67836
68232
|
status = "skipped";
|
|
67837
68233
|
detail = "directory already absent";
|
|
67838
68234
|
} else {
|
|
67839
68235
|
try {
|
|
67840
|
-
|
|
68236
|
+
rmSync6(resolved, { recursive: true, force: true });
|
|
67841
68237
|
status = "removed";
|
|
67842
68238
|
} catch (error) {
|
|
67843
68239
|
status = "failed";
|
|
@@ -67863,19 +68259,19 @@ function applyUninstall(plan, paths = {}) {
|
|
|
67863
68259
|
var resolveUninstallPaths = (options = {}) => {
|
|
67864
68260
|
const home = options.home ?? options.env?.HOME ?? os10.homedir();
|
|
67865
68261
|
return {
|
|
67866
|
-
opencodeConfig: options.opencodeConfig ??
|
|
67867
|
-
cursorSettings: options.cursorSettings ??
|
|
67868
|
-
cursorMcp: options.cursorMcp ??
|
|
67869
|
-
cursorPluginDir: options.cursorPluginDir ??
|
|
67870
|
-
codexPluginDir:
|
|
67871
|
-
piConfig:
|
|
68262
|
+
opencodeConfig: options.opencodeConfig ?? path35.join(home, ".config", "opencode", "opencode.json"),
|
|
68263
|
+
cursorSettings: options.cursorSettings ?? path35.join(home, ".cursor", "settings.json"),
|
|
68264
|
+
cursorMcp: options.cursorMcp ?? path35.join(home, ".cursor", "mcp.json"),
|
|
68265
|
+
cursorPluginDir: options.cursorPluginDir ?? path35.join(home, ".cursor", "plugins", "local", "workit"),
|
|
68266
|
+
codexPluginDir: path35.join(home, ".codex", "plugins", "workit"),
|
|
68267
|
+
piConfig: path35.join(home, ".pi", "config.json")
|
|
67872
68268
|
};
|
|
67873
68269
|
}, isRecord6 = (v) => v !== null && typeof v === "object" && !Array.isArray(v), readJsonRecord = (file) => {
|
|
67874
68270
|
let raw;
|
|
67875
68271
|
try {
|
|
67876
|
-
raw =
|
|
68272
|
+
raw = readFileSync17(file, "utf8");
|
|
67877
68273
|
} catch {
|
|
67878
|
-
if (
|
|
68274
|
+
if (existsSync17(file))
|
|
67879
68275
|
return { kind: "malformed", error: `${file} is not readable` };
|
|
67880
68276
|
return { kind: "missing" };
|
|
67881
68277
|
}
|
|
@@ -67886,8 +68282,8 @@ var resolveUninstallPaths = (options = {}) => {
|
|
|
67886
68282
|
return { kind: "malformed", error: `${file} is not valid JSON` };
|
|
67887
68283
|
}
|
|
67888
68284
|
}, stripTrailingSep = (p) => {
|
|
67889
|
-
const j =
|
|
67890
|
-
return
|
|
68285
|
+
const j = path35.join(p);
|
|
68286
|
+
return path35.dirname(j) === j ? j : j.replace(/[\\/]+$/, "");
|
|
67891
68287
|
}, CURSOR_LEGACY_IDENTITIES, jsonCleanerFor = (target, res) => {
|
|
67892
68288
|
if (target === res.opencodeConfig)
|
|
67893
68289
|
return cleanOpenCodeConfig;
|
|
@@ -67899,8 +68295,8 @@ var resolveUninstallPaths = (options = {}) => {
|
|
|
67899
68295
|
return cleanPiConfig;
|
|
67900
68296
|
return null;
|
|
67901
68297
|
}, canonicalRemoveDirAllowed = (actionPath, res) => {
|
|
67902
|
-
const expected =
|
|
67903
|
-
if (!(actionPath === expected &&
|
|
68298
|
+
const expected = path35.resolve(res.cursorPluginDir);
|
|
68299
|
+
if (!(actionPath === expected && path35.basename(expected) === "workit" && path35.basename(path35.dirname(expected)) === "local" && path35.basename(path35.dirname(path35.dirname(expected))) === "plugins")) {
|
|
67904
68300
|
return false;
|
|
67905
68301
|
}
|
|
67906
68302
|
try {
|
|
@@ -67923,7 +68319,7 @@ var resolveUninstallPaths = (options = {}) => {
|
|
|
67923
68319
|
`;
|
|
67924
68320
|
let current;
|
|
67925
68321
|
try {
|
|
67926
|
-
current =
|
|
68322
|
+
current = readFileSync17(target, "utf8");
|
|
67927
68323
|
} catch (error) {
|
|
67928
68324
|
return {
|
|
67929
68325
|
status: "failed",
|
|
@@ -67934,7 +68330,7 @@ var resolveUninstallPaths = (options = {}) => {
|
|
|
67934
68330
|
return { status: "skipped", detail: "already clean" };
|
|
67935
68331
|
}
|
|
67936
68332
|
try {
|
|
67937
|
-
|
|
68333
|
+
writeFileSync10(target, serialized, "utf8");
|
|
67938
68334
|
} catch (error) {
|
|
67939
68335
|
return {
|
|
67940
68336
|
status: "failed",
|
|
@@ -67952,7 +68348,7 @@ var resolveUninstallPaths = (options = {}) => {
|
|
|
67952
68348
|
};
|
|
67953
68349
|
const home = paths.home ?? paths.env?.HOME ?? os10.homedir();
|
|
67954
68350
|
const env = paths.env ?? process.env;
|
|
67955
|
-
const recorded = claudeWorkitInstalls(home, env, action.cwd).some((install) => install.id === id && install.scope === scope && (install.projectPath === null ? action.cwd === null :
|
|
68351
|
+
const recorded = claudeWorkitInstalls(home, env, action.cwd).some((install) => install.id === id && install.scope === scope && (install.projectPath === null ? action.cwd === null : path35.resolve(install.projectPath) === path35.resolve(action.cwd ?? "")));
|
|
67956
68352
|
if (!recorded)
|
|
67957
68353
|
return { status: "skipped", detail: `${id} (${scope} scope) is no longer installed` };
|
|
67958
68354
|
const executable = findHostExecutable("claude", { home, env });
|
|
@@ -70431,9 +70827,9 @@ var init_src2 = __esm(async () => {
|
|
|
70431
70827
|
// packages/workit-cli/src/verbs/init.ts
|
|
70432
70828
|
var exports_init = {};
|
|
70433
70829
|
__export(exports_init, {
|
|
70434
|
-
run: () =>
|
|
70830
|
+
run: () => run3
|
|
70435
70831
|
});
|
|
70436
|
-
async function
|
|
70832
|
+
async function run3(_argv, io) {
|
|
70437
70833
|
if (io.json)
|
|
70438
70834
|
return emit(io, fail("invalid_input", "workit init is an interactive wizard and has no --json output", {
|
|
70439
70835
|
unblock: "run `workit init` in a terminal without --json"
|
|
@@ -70447,19 +70843,19 @@ var init_init = __esm(() => {
|
|
|
70447
70843
|
});
|
|
70448
70844
|
|
|
70449
70845
|
// packages/workit-cli/src/upgrade.ts
|
|
70450
|
-
import { spawnSync as
|
|
70846
|
+
import { spawnSync as spawnSync15 } from "node:child_process";
|
|
70451
70847
|
import {
|
|
70452
|
-
existsSync as
|
|
70848
|
+
existsSync as existsSync18,
|
|
70453
70849
|
mkdtempSync as mkdtempSync3,
|
|
70454
|
-
rmSync as
|
|
70455
|
-
readFileSync as
|
|
70456
|
-
mkdirSync as
|
|
70850
|
+
rmSync as rmSync7,
|
|
70851
|
+
readFileSync as readFileSync18,
|
|
70852
|
+
mkdirSync as mkdirSync9,
|
|
70457
70853
|
copyFileSync as copyFileSync5,
|
|
70458
|
-
chmodSync,
|
|
70854
|
+
chmodSync as chmodSync2,
|
|
70459
70855
|
cpSync as cpSync5,
|
|
70460
|
-
lstatSync as
|
|
70856
|
+
lstatSync as lstatSync7
|
|
70461
70857
|
} from "node:fs";
|
|
70462
|
-
import
|
|
70858
|
+
import path36 from "node:path";
|
|
70463
70859
|
import os12 from "node:os";
|
|
70464
70860
|
import { createHash as createHash14 } from "node:crypto";
|
|
70465
70861
|
function previewUpgrade(hosts = HOSTS2, deps = {}) {
|
|
@@ -70483,9 +70879,9 @@ function previewUpgrade(hosts = HOSTS2, deps = {}) {
|
|
|
70483
70879
|
for (const file of [
|
|
70484
70880
|
paths.opencodeConfig,
|
|
70485
70881
|
paths.opencodeConfig + "c",
|
|
70486
|
-
|
|
70487
|
-
|
|
70488
|
-
|
|
70882
|
+
path36.join(home, ".cursor/settings.json"),
|
|
70883
|
+
path36.join(home, ".cursor/mcp.json"),
|
|
70884
|
+
path36.join(home, ".cursor/plugins/local/workit/package.json"),
|
|
70489
70885
|
paths.codexConfig,
|
|
70490
70886
|
paths.piSettings
|
|
70491
70887
|
])
|
|
@@ -70500,20 +70896,20 @@ function previewUpgrade(hosts = HOSTS2, deps = {}) {
|
|
|
70500
70896
|
});
|
|
70501
70897
|
const installedSources = sources(paths, run, hosts);
|
|
70502
70898
|
if (installedSources.some((source) => source.host === "opencode")) {
|
|
70503
|
-
const scratch = mkdtempSync3(
|
|
70899
|
+
const scratch = mkdtempSync3(path36.join(os12.tmpdir(), "workit-upgrade-opencode-"));
|
|
70504
70900
|
let probe;
|
|
70505
70901
|
try {
|
|
70506
70902
|
probe = runner({
|
|
70507
70903
|
...deps,
|
|
70508
70904
|
env: {
|
|
70509
70905
|
...deps.env,
|
|
70510
|
-
XDG_DATA_HOME:
|
|
70511
|
-
XDG_STATE_HOME:
|
|
70512
|
-
XDG_CACHE_HOME:
|
|
70906
|
+
XDG_DATA_HOME: path36.join(scratch, "data"),
|
|
70907
|
+
XDG_STATE_HOME: path36.join(scratch, "state"),
|
|
70908
|
+
XDG_CACHE_HOME: path36.join(scratch, "cache")
|
|
70513
70909
|
}
|
|
70514
70910
|
})("opencode", ["--version"]);
|
|
70515
70911
|
} finally {
|
|
70516
|
-
|
|
70912
|
+
rmSync7(scratch, { recursive: true, force: true });
|
|
70517
70913
|
}
|
|
70518
70914
|
const installed = probe.status === 0 ? probe.stdout.match(/\d+\.\d+\.\d+/)?.[0] : undefined;
|
|
70519
70915
|
if (installed && !versionAtLeast(installed, SUPPORT_MATRIX.opencode.minimum))
|
|
@@ -70555,7 +70951,7 @@ function previewUpgrade(hosts = HOSTS2, deps = {}) {
|
|
|
70555
70951
|
env: deps.env,
|
|
70556
70952
|
cwd: home,
|
|
70557
70953
|
packageVersion: latest.stdout.trim(),
|
|
70558
|
-
targetDir:
|
|
70954
|
+
targetDir: path36.join(home, ".cursor/plugins/local/workit")
|
|
70559
70955
|
});
|
|
70560
70956
|
plan.entries.push({
|
|
70561
70957
|
host: source.host,
|
|
@@ -70585,13 +70981,13 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
70585
70981
|
ok: false,
|
|
70586
70982
|
error: "Stop the selected running hosts before upgrading their loaded plugins"
|
|
70587
70983
|
};
|
|
70588
|
-
const backup =
|
|
70589
|
-
|
|
70984
|
+
const backup = path36.join(home, ".local/state/workit/upgrades", new Date().toISOString().replaceAll(":", "-"));
|
|
70985
|
+
mkdirSync9(backup, { recursive: true, mode: 448 });
|
|
70590
70986
|
for (const file of Object.keys(plan.configDigests))
|
|
70591
|
-
if (
|
|
70592
|
-
const target =
|
|
70987
|
+
if (existsSync18(file)) {
|
|
70988
|
+
const target = path36.join(backup, createHash14("sha256").update(file).digest("hex").slice(0, 12) + "-" + path36.basename(file));
|
|
70593
70989
|
copyFileSync5(file, target);
|
|
70594
|
-
|
|
70990
|
+
chmodSync2(target, 384);
|
|
70595
70991
|
}
|
|
70596
70992
|
for (const migration of plan.migrations) {
|
|
70597
70993
|
const value = object2(migration.file);
|
|
@@ -70606,9 +71002,9 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
70606
71002
|
`, 384);
|
|
70607
71003
|
}
|
|
70608
71004
|
const run = runner(deps);
|
|
70609
|
-
const cursorRoot =
|
|
70610
|
-
if (plan.entries.some((entry) => entry.host === "cursor") &&
|
|
70611
|
-
cpSync5(cursorRoot,
|
|
71005
|
+
const cursorRoot = path36.join(home, ".cursor/plugins/local/workit");
|
|
71006
|
+
if (plan.entries.some((entry) => entry.host === "cursor") && existsSync18(cursorRoot))
|
|
71007
|
+
cpSync5(cursorRoot, path36.join(backup, "cursor-package"), { recursive: true });
|
|
70612
71008
|
for (const entry of plan.entries) {
|
|
70613
71009
|
if (entry.host === "opencode")
|
|
70614
71010
|
return {
|
|
@@ -70628,7 +71024,7 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
70628
71024
|
{
|
|
70629
71025
|
type: "install-host",
|
|
70630
71026
|
platform: "cursor",
|
|
70631
|
-
path:
|
|
71027
|
+
path: path36.join(home, ".cursor/plugins/local/.workit-package-bootstrap"),
|
|
70632
71028
|
commands: entry.commands.map((command) => ({
|
|
70633
71029
|
...command,
|
|
70634
71030
|
purpose: command.purpose ?? "Upgrade Cursor"
|
|
@@ -70637,7 +71033,7 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
70637
71033
|
{
|
|
70638
71034
|
type: "install-adapter",
|
|
70639
71035
|
platform: "cursor",
|
|
70640
|
-
path:
|
|
71036
|
+
path: path36.join(home, ".cursor/plugins/local/workit")
|
|
70641
71037
|
}
|
|
70642
71038
|
]
|
|
70643
71039
|
};
|
|
@@ -70651,7 +71047,7 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
70651
71047
|
return { exitCode: outcome.status ?? 1, stdout: outcome.stdout, stderr: "" };
|
|
70652
71048
|
}
|
|
70653
71049
|
});
|
|
70654
|
-
const pkg = object2(
|
|
71050
|
+
const pkg = object2(path36.join(home, ".cursor/plugins/local/workit/package.json"));
|
|
70655
71051
|
if (!result.ok || pkg?.version !== entry.latest)
|
|
70656
71052
|
return {
|
|
70657
71053
|
ok: false,
|
|
@@ -70685,15 +71081,15 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
70685
71081
|
const currentRoot = run("npm", ["root", "--global"]);
|
|
70686
71082
|
if (currentRoot.status !== 0 || currentRoot.stdout.trim() !== plan.cli.root)
|
|
70687
71083
|
return { ok: false, backup, error: "Global npm location changed; preview again" };
|
|
70688
|
-
const cliBackup =
|
|
70689
|
-
cpSync5(
|
|
71084
|
+
const cliBackup = path36.join(backup, "cli-package");
|
|
71085
|
+
cpSync5(path36.join(plan.cli.root, "@brainervirus/workit-cli"), cliBackup, { recursive: true });
|
|
70690
71086
|
if (run("npm", ["install", "--global", `@brainervirus/workit-cli@${plan.cli.latest}`]).status !== 0)
|
|
70691
71087
|
return {
|
|
70692
71088
|
ok: false,
|
|
70693
71089
|
backup,
|
|
70694
|
-
error: `CLI update failed; preserved package at ${cliBackup}; use npm to repair or run node ${
|
|
71090
|
+
error: `CLI update failed; preserved package at ${cliBackup}; use npm to repair or run node ${path36.join(cliBackup, "dist/index.js")}`
|
|
70695
71091
|
};
|
|
70696
|
-
const installed = object2(
|
|
71092
|
+
const installed = object2(path36.join(plan.cli.root, "@brainervirus/workit-cli/package.json"));
|
|
70697
71093
|
if (installed?.name !== "@brainervirus/workit-cli" || installed.version !== plan.cli.latest)
|
|
70698
71094
|
return {
|
|
70699
71095
|
ok: false,
|
|
@@ -70718,12 +71114,12 @@ async function runUpgradeCommand(argv, deps = {}) {
|
|
|
70718
71114
|
if (flags.has("--cli")) {
|
|
70719
71115
|
const run = runner(deps);
|
|
70720
71116
|
const root = run("npm", ["root", "--global"]);
|
|
70721
|
-
if (root.status !== 0 || !
|
|
71117
|
+
if (root.status !== 0 || !path36.isAbsolute(root.stdout.trim())) {
|
|
70722
71118
|
plan.blocked.push("Global npm location could not be verified");
|
|
70723
71119
|
} else {
|
|
70724
|
-
const packageFile =
|
|
71120
|
+
const packageFile = path36.join(root.stdout.trim(), "@brainervirus/workit-cli/package.json");
|
|
70725
71121
|
const pkg = object2(packageFile);
|
|
70726
|
-
if (pkg?.name !== "@brainervirus/workit-cli" ||
|
|
71122
|
+
if (pkg?.name !== "@brainervirus/workit-cli" || lstatSync7(path36.dirname(packageFile)).isSymbolicLink()) {
|
|
70727
71123
|
plan.skipped.push({
|
|
70728
71124
|
host: "cli",
|
|
70729
71125
|
reason: "No managed global CLI install (local links preserved); use npx @brainervirus/workit-cli@latest"
|
|
@@ -70803,7 +71199,7 @@ async function runLaunchCommand(argv, deps = {}) {
|
|
|
70803
71199
|
}
|
|
70804
71200
|
if (deps.run)
|
|
70805
71201
|
return deps.run(host, hostArgs).status ?? 1;
|
|
70806
|
-
return
|
|
71202
|
+
return spawnSync15(launch.command, launch.args, {
|
|
70807
71203
|
stdio: "inherit",
|
|
70808
71204
|
env
|
|
70809
71205
|
}).status ?? 1;
|
|
@@ -70814,37 +71210,37 @@ var HOSTS2, upgradePaths = (deps) => {
|
|
|
70814
71210
|
...process.env,
|
|
70815
71211
|
...deps.home || deps.env?.HOME ? {
|
|
70816
71212
|
HOME: home,
|
|
70817
|
-
CODEX_HOME:
|
|
70818
|
-
PI_CODING_AGENT_DIR:
|
|
70819
|
-
XDG_CONFIG_HOME:
|
|
71213
|
+
CODEX_HOME: path36.join(home, ".codex"),
|
|
71214
|
+
PI_CODING_AGENT_DIR: path36.join(home, ".pi/agent"),
|
|
71215
|
+
XDG_CONFIG_HOME: path36.join(home, ".config"),
|
|
70820
71216
|
WORKFLOW_TOOLKIT_CONFIG: undefined,
|
|
70821
71217
|
WORKFLOW_TOOLKIT_CONFIG_DIR: undefined
|
|
70822
71218
|
} : {},
|
|
70823
71219
|
...deps.env,
|
|
70824
71220
|
HOME: home
|
|
70825
71221
|
};
|
|
70826
|
-
const xdg = env.XDG_CONFIG_HOME ||
|
|
71222
|
+
const xdg = env.XDG_CONFIG_HOME || path36.join(home, ".config");
|
|
70827
71223
|
return {
|
|
70828
71224
|
home,
|
|
70829
71225
|
env,
|
|
70830
|
-
configDir: env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ??
|
|
70831
|
-
opencodeConfig:
|
|
70832
|
-
piSettings:
|
|
70833
|
-
codexConfig:
|
|
71226
|
+
configDir: env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path36.join(xdg, "workit"),
|
|
71227
|
+
opencodeConfig: path36.join(xdg, "opencode/opencode.json"),
|
|
71228
|
+
piSettings: path36.join(env.PI_CODING_AGENT_DIR ?? path36.join(home, ".pi/agent"), "settings.json"),
|
|
71229
|
+
codexConfig: path36.join(env.CODEX_HOME ?? path36.join(home, ".codex"), "config.toml")
|
|
70834
71230
|
};
|
|
70835
71231
|
}, object2 = (file) => {
|
|
70836
|
-
if (!
|
|
71232
|
+
if (!existsSync18(file))
|
|
70837
71233
|
return null;
|
|
70838
71234
|
let data;
|
|
70839
71235
|
try {
|
|
70840
|
-
data = JSON.parse(
|
|
71236
|
+
data = JSON.parse(readFileSync18(file, "utf8"));
|
|
70841
71237
|
} catch {
|
|
70842
71238
|
throw new Error(`${file} is not valid JSON; use the native host to inspect JSONC settings`);
|
|
70843
71239
|
}
|
|
70844
71240
|
if (!data || typeof data !== "object" || Array.isArray(data))
|
|
70845
71241
|
throw new Error(`${file} is not a configuration object`);
|
|
70846
71242
|
return data;
|
|
70847
|
-
}, digest2 = (file) =>
|
|
71243
|
+
}, digest2 = (file) => existsSync18(file) ? createHash14("sha256").update(readFileSync18(file)).digest("hex") : "missing", runner = (deps) => deps.run ?? ((command, args) => {
|
|
70848
71244
|
const { home, env } = upgradePaths(deps);
|
|
70849
71245
|
let step;
|
|
70850
71246
|
try {
|
|
@@ -70861,7 +71257,7 @@ var HOSTS2, upgradePaths = (deps) => {
|
|
|
70861
71257
|
}), sources = (paths, run, hosts) => {
|
|
70862
71258
|
const { home, opencodeConfig, piSettings } = paths;
|
|
70863
71259
|
const result = [];
|
|
70864
|
-
if (hosts.includes("opencode") &&
|
|
71260
|
+
if (hosts.includes("opencode") && existsSync18(opencodeConfig + "c"))
|
|
70865
71261
|
throw new Error("OpenCode JSONC config is present; inspect effective native configuration before updating");
|
|
70866
71262
|
const oc = hosts.includes("opencode") ? object2(opencodeConfig) : null;
|
|
70867
71263
|
if (oc && [oc.plugins, oc.plugin].some((value) => value !== undefined && !Array.isArray(value)))
|
|
@@ -70870,9 +71266,9 @@ var HOSTS2, upgradePaths = (deps) => {
|
|
|
70870
71266
|
for (const pin of plugins)
|
|
70871
71267
|
if (typeof pin === "string" && isWorkitPlugin(pin))
|
|
70872
71268
|
result.push(classify("opencode", pin));
|
|
70873
|
-
const cursor = hosts.includes("cursor") ? object2(
|
|
71269
|
+
const cursor = hosts.includes("cursor") ? object2(path36.join(home, ".cursor/plugins/local/workit/package.json")) : null;
|
|
70874
71270
|
if (cursor?.name === "@brainervirus/workit-cursor") {
|
|
70875
|
-
const mcp = object2(
|
|
71271
|
+
const mcp = object2(path36.join(home, ".cursor/mcp.json"));
|
|
70876
71272
|
const args = mcp?.mcpServers?.workit?.args ?? [];
|
|
70877
71273
|
const selector = args.find((arg) => typeof arg === "string" && arg.startsWith("--package="));
|
|
70878
71274
|
result.push(classify("cursor", typeof selector === "string" ? selector.slice(10) : "local"));
|
|
@@ -70885,7 +71281,7 @@ var HOSTS2, upgradePaths = (deps) => {
|
|
|
70885
71281
|
if (typeof source !== "string")
|
|
70886
71282
|
continue;
|
|
70887
71283
|
const npm = /^(?:npm:)?@brainervirus\/workit-pi(?:@[^/]+)?$/.test(source);
|
|
70888
|
-
const local =
|
|
71284
|
+
const local = path36.isAbsolute(source) && source.replaceAll("\\", "/").endsWith("/packages/workit-pi") && object2(path36.join(source, "package.json"))?.name === "@brainervirus/workit-pi";
|
|
70889
71285
|
if (npm || local)
|
|
70890
71286
|
result.push(classify("pi", source));
|
|
70891
71287
|
}
|
|
@@ -70896,7 +71292,7 @@ var HOSTS2, upgradePaths = (deps) => {
|
|
|
70896
71292
|
hostCommand("codex", [], { home, env: paths.env });
|
|
70897
71293
|
available = true;
|
|
70898
71294
|
} catch {}
|
|
70899
|
-
if (available ||
|
|
71295
|
+
if (available || existsSync18(paths.codexConfig))
|
|
70900
71296
|
throw new Error("Codex plugin inventory failed; inspect the native host before upgrading");
|
|
70901
71297
|
}
|
|
70902
71298
|
if (listing.status === 0) {
|
|
@@ -70932,9 +71328,9 @@ var HOSTS2, upgradePaths = (deps) => {
|
|
|
70932
71328
|
}, piInstalledVersion = (listing, selector) => {
|
|
70933
71329
|
const lines = listing.split(/\r?\n/).map((line) => line.trim());
|
|
70934
71330
|
const index = lines.indexOf(selector);
|
|
70935
|
-
if (index < 0 || !lines[index + 1] || !
|
|
71331
|
+
if (index < 0 || !lines[index + 1] || !path36.isAbsolute(lines[index + 1]))
|
|
70936
71332
|
return;
|
|
70937
|
-
const pkg = object2(
|
|
71333
|
+
const pkg = object2(path36.join(lines[index + 1], "package.json"));
|
|
70938
71334
|
return pkg?.name === "@brainervirus/workit-pi" ? pkg.version : undefined;
|
|
70939
71335
|
}, versionAtLeast = (installed, latest) => {
|
|
70940
71336
|
if (!/^\d+\.\d+\.\d+$/.test(installed))
|
|
@@ -70967,9 +71363,9 @@ var init_upgrade = __esm(() => {
|
|
|
70967
71363
|
// packages/workit-cli/src/verbs/upgrade.ts
|
|
70968
71364
|
var exports_upgrade = {};
|
|
70969
71365
|
__export(exports_upgrade, {
|
|
70970
|
-
run: () =>
|
|
71366
|
+
run: () => run4
|
|
70971
71367
|
});
|
|
70972
|
-
var
|
|
71368
|
+
var run4 = (argv) => runUpgradeCommand(argv);
|
|
70973
71369
|
var init_upgrade2 = __esm(() => {
|
|
70974
71370
|
init_upgrade();
|
|
70975
71371
|
});
|
|
@@ -70977,17 +71373,17 @@ var init_upgrade2 = __esm(() => {
|
|
|
70977
71373
|
// packages/workit-cli/src/verbs/launch.ts
|
|
70978
71374
|
var exports_launch = {};
|
|
70979
71375
|
__export(exports_launch, {
|
|
70980
|
-
run: () =>
|
|
71376
|
+
run: () => run5
|
|
70981
71377
|
});
|
|
70982
|
-
var
|
|
71378
|
+
var run5 = (argv) => runLaunchCommand(argv);
|
|
70983
71379
|
var init_launch = __esm(() => {
|
|
70984
71380
|
init_upgrade();
|
|
70985
71381
|
});
|
|
70986
71382
|
|
|
70987
71383
|
// packages/workit-core/src/knowledge.ts
|
|
70988
|
-
import { spawnSync as
|
|
71384
|
+
import { spawnSync as spawnSync16 } from "node:child_process";
|
|
70989
71385
|
import fs17 from "node:fs";
|
|
70990
|
-
import
|
|
71386
|
+
import path37 from "node:path";
|
|
70991
71387
|
function lintKnowledge(root) {
|
|
70992
71388
|
const seen = new Set;
|
|
70993
71389
|
const unreadable = [];
|
|
@@ -71091,7 +71487,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
|
|
|
71091
71487
|
const end = lines.indexOf("---", 1);
|
|
71092
71488
|
return end === -1 ? lines : [...lines.slice(0, end + 1).map(() => ""), ...lines.slice(end + 1)];
|
|
71093
71489
|
}, read = (root, file) => {
|
|
71094
|
-
const full =
|
|
71490
|
+
const full = path37.join(root, file);
|
|
71095
71491
|
try {
|
|
71096
71492
|
fs17.lstatSync(full);
|
|
71097
71493
|
} catch {
|
|
@@ -71106,7 +71502,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
|
|
|
71106
71502
|
return "unreadable";
|
|
71107
71503
|
}
|
|
71108
71504
|
}, trackedTopLevel = (root) => {
|
|
71109
|
-
const run =
|
|
71505
|
+
const run = spawnSync16("git", ["ls-files", "-z", "--cached"], {
|
|
71110
71506
|
cwd: root,
|
|
71111
71507
|
encoding: "utf8",
|
|
71112
71508
|
maxBuffer: 256 * 1024 * 1024,
|
|
@@ -71116,7 +71512,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
|
|
|
71116
71512
|
if (run.status !== 0)
|
|
71117
71513
|
return null;
|
|
71118
71514
|
return new Set(run.stdout.split("\x00").filter(Boolean).map((file) => file.split("/")[0]));
|
|
71119
|
-
},
|
|
71515
|
+
}, exists2 = (target) => {
|
|
71120
71516
|
try {
|
|
71121
71517
|
fs17.statSync(target);
|
|
71122
71518
|
return true;
|
|
@@ -71132,7 +71528,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
|
|
|
71132
71528
|
}
|
|
71133
71529
|
}, brokenLinks = (root, doc, tracked) => {
|
|
71134
71530
|
const findings = [];
|
|
71135
|
-
const base =
|
|
71531
|
+
const base = path37.dirname(path37.join(root, doc.file));
|
|
71136
71532
|
const missing = (target, line, how) => findings.push({
|
|
71137
71533
|
rule: "broken-link",
|
|
71138
71534
|
file: doc.file,
|
|
@@ -71151,8 +71547,8 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
|
|
|
71151
71547
|
const local = localTarget(target);
|
|
71152
71548
|
if (!local)
|
|
71153
71549
|
continue;
|
|
71154
|
-
const resolved = local.startsWith("/") ?
|
|
71155
|
-
if (!
|
|
71550
|
+
const resolved = local.startsWith("/") ? path37.join(root, local) : path37.resolve(base, local);
|
|
71551
|
+
if (!exists2(resolved))
|
|
71156
71552
|
missing(target, index + 1, "link");
|
|
71157
71553
|
}
|
|
71158
71554
|
for (const [, span] of text.matchAll(CODE_SPAN)) {
|
|
@@ -71161,10 +71557,10 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
|
|
|
71161
71557
|
continue;
|
|
71162
71558
|
const relative = /^\.\.?\//.test(candidate);
|
|
71163
71559
|
const first = candidate.split("/")[0];
|
|
71164
|
-
if (!relative && !(tracked ? tracked.has(first) :
|
|
71560
|
+
if (!relative && !(tracked ? tracked.has(first) : exists2(path37.join(root, first))))
|
|
71165
71561
|
continue;
|
|
71166
|
-
const resolved = relative ?
|
|
71167
|
-
if (!
|
|
71562
|
+
const resolved = relative ? path37.resolve(base, candidate) : path37.join(root, candidate);
|
|
71563
|
+
if (!exists2(resolved))
|
|
71168
71564
|
missing(span, index + 1, "pointer");
|
|
71169
71565
|
}
|
|
71170
71566
|
}
|
|
@@ -71289,7 +71685,7 @@ var init_prompt = () => {};
|
|
|
71289
71685
|
// packages/workit-cli/src/verbs/doctor.ts
|
|
71290
71686
|
var exports_doctor = {};
|
|
71291
71687
|
__export(exports_doctor, {
|
|
71292
|
-
run: () =>
|
|
71688
|
+
run: () => run6
|
|
71293
71689
|
});
|
|
71294
71690
|
async function confirmForcedLockClear(root, args, io) {
|
|
71295
71691
|
const lock = inspectMetadataLock(root);
|
|
@@ -71312,7 +71708,7 @@ async function confirmForcedLockClear(root, args, io) {
|
|
|
71312
71708
|
return "cancelled";
|
|
71313
71709
|
return /^y(es)?$/i.test(answer.trim());
|
|
71314
71710
|
}
|
|
71315
|
-
async function
|
|
71711
|
+
async function run6(argv, io) {
|
|
71316
71712
|
const root = workspaceRootFor();
|
|
71317
71713
|
const force = argv.includes("--force");
|
|
71318
71714
|
let fixLock = null;
|
|
@@ -71330,6 +71726,18 @@ async function run5(argv, io) {
|
|
|
71330
71726
|
}
|
|
71331
71727
|
fixLock = clearStaleMetadataLock(root, { force });
|
|
71332
71728
|
}
|
|
71729
|
+
let sessionHook = null;
|
|
71730
|
+
if (argv.includes("--fix")) {
|
|
71731
|
+
try {
|
|
71732
|
+
const fixed = fixSessionHook({ host: "cli", cwd: io.cwd, workspaceRoot: root });
|
|
71733
|
+
sessionHook = { action: fixed.action, detail: fixed.detail };
|
|
71734
|
+
} catch (error) {
|
|
71735
|
+
sessionHook = {
|
|
71736
|
+
action: "failed",
|
|
71737
|
+
detail: error instanceof Error ? error.message : String(error)
|
|
71738
|
+
};
|
|
71739
|
+
}
|
|
71740
|
+
}
|
|
71333
71741
|
const report = runDoctor({
|
|
71334
71742
|
host: "cli",
|
|
71335
71743
|
cwd: io.cwd,
|
|
@@ -71352,7 +71760,7 @@ async function run5(argv, io) {
|
|
|
71352
71760
|
budget: knowledge.budget,
|
|
71353
71761
|
findings: knowledge.findings.length
|
|
71354
71762
|
} : { unavailable: true };
|
|
71355
|
-
io.stdout(`${JSON.stringify({ ...report, ...fixLock ? { fixLock } : {}, knowledge: summary }, null, 2)}
|
|
71763
|
+
io.stdout(`${JSON.stringify({ ...report, ...fixLock ? { fixLock } : {}, ...sessionHook ? { sessionHook } : {}, knowledge: summary }, null, 2)}
|
|
71356
71764
|
`);
|
|
71357
71765
|
return report.exitCode;
|
|
71358
71766
|
}
|
|
@@ -71361,6 +71769,9 @@ async function run5(argv, io) {
|
|
|
71361
71769
|
io.stdout(`fix-lock: ${what}${fixLock.guardCleared ? "; removed abandoned reclaim guard" : ""}
|
|
71362
71770
|
`);
|
|
71363
71771
|
}
|
|
71772
|
+
if (sessionHook)
|
|
71773
|
+
io.stdout(`fix: session hook ${sessionHook.action}: ${sessionHook.detail}
|
|
71774
|
+
`);
|
|
71364
71775
|
io.stdout(`workit doctor — ${report.ok ? "healthy" : "problems found"} (${report.offline ? "offline" : "online"})
|
|
71365
71776
|
`);
|
|
71366
71777
|
for (const check of report.checks) {
|
|
@@ -71493,11 +71904,11 @@ var init_redact = __esm(() => {
|
|
|
71493
71904
|
});
|
|
71494
71905
|
|
|
71495
71906
|
// packages/workit-core/src/checks.ts
|
|
71496
|
-
import { spawn, spawnSync as
|
|
71907
|
+
import { spawn, spawnSync as spawnSync17 } from "node:child_process";
|
|
71497
71908
|
import { createHash as createHash15 } from "node:crypto";
|
|
71498
71909
|
import fs18 from "node:fs";
|
|
71499
71910
|
import os13 from "node:os";
|
|
71500
|
-
import
|
|
71911
|
+
import path38 from "node:path";
|
|
71501
71912
|
import { StringDecoder } from "node:string_decoder";
|
|
71502
71913
|
function tailLines(text, lines = TAIL_LINES) {
|
|
71503
71914
|
const all = text.replace(/\r\n?/gu, `
|
|
@@ -71617,7 +72028,7 @@ function planSpawn(argv, options) {
|
|
|
71617
72028
|
return { file: argv[0], args: [], verbatim: false, shell: true };
|
|
71618
72029
|
if (options.platform !== "win32")
|
|
71619
72030
|
return { file: argv[0], args: argv.slice(1), verbatim: false, shell: false };
|
|
71620
|
-
const win =
|
|
72031
|
+
const win = path38.win32;
|
|
71621
72032
|
const isFile = options.isFile ?? ((file) => {
|
|
71622
72033
|
try {
|
|
71623
72034
|
return fs18.statSync(file).isFile();
|
|
@@ -71672,7 +72083,7 @@ function runCheckCommand(argv, options) {
|
|
|
71672
72083
|
if (!child?.pid)
|
|
71673
72084
|
return;
|
|
71674
72085
|
if (windows)
|
|
71675
|
-
|
|
72086
|
+
spawnSync17("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
|
|
71676
72087
|
stdio: "ignore",
|
|
71677
72088
|
windowsHide: true
|
|
71678
72089
|
});
|
|
@@ -71774,10 +72185,10 @@ function runCheckCommand(argv, options) {
|
|
|
71774
72185
|
function storeLog(storeRoot, log) {
|
|
71775
72186
|
const digest = logDigest(log);
|
|
71776
72187
|
const ref = `blobs/logs/${digest.slice("sha256:".length)}.log`;
|
|
71777
|
-
const file =
|
|
72188
|
+
const file = path38.join(storeRoot, ref);
|
|
71778
72189
|
try {
|
|
71779
72190
|
if (!fs18.existsSync(file)) {
|
|
71780
|
-
fs18.mkdirSync(
|
|
72191
|
+
fs18.mkdirSync(path38.dirname(file), { recursive: true });
|
|
71781
72192
|
const temp = `${file}.${process.pid}.${Date.now()}.tmp`;
|
|
71782
72193
|
fs18.writeFileSync(temp, log, { mode: 384 });
|
|
71783
72194
|
fs18.renameSync(temp, file);
|
|
@@ -71790,7 +72201,7 @@ function storeLog(storeRoot, log) {
|
|
|
71790
72201
|
function pruneCheckLogs(storeRoot, options = {}) {
|
|
71791
72202
|
const limits = { ...LOG_RETENTION, ...options.retention };
|
|
71792
72203
|
const now = options.now ?? Date.now();
|
|
71793
|
-
const dir =
|
|
72204
|
+
const dir = path38.join(storeRoot, "blobs", "logs");
|
|
71794
72205
|
const report = { removed: 0, removedBytes: 0, kept: 0 };
|
|
71795
72206
|
let names;
|
|
71796
72207
|
try {
|
|
@@ -71800,7 +72211,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
|
|
|
71800
72211
|
}
|
|
71801
72212
|
const files = names.flatMap((name) => {
|
|
71802
72213
|
try {
|
|
71803
|
-
const stat = fs18.statSync(
|
|
72214
|
+
const stat = fs18.statSync(path38.join(dir, name));
|
|
71804
72215
|
return stat.isFile() ? [{ name, size: stat.size, mtimeMs: stat.mtimeMs }] : [];
|
|
71805
72216
|
} catch {
|
|
71806
72217
|
return [];
|
|
@@ -71819,7 +72230,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
|
|
|
71819
72230
|
continue;
|
|
71820
72231
|
if (!options.dryRun)
|
|
71821
72232
|
try {
|
|
71822
|
-
fs18.rmSync(
|
|
72233
|
+
fs18.rmSync(path38.join(dir, file.name), { force: true });
|
|
71823
72234
|
} catch {
|
|
71824
72235
|
continue;
|
|
71825
72236
|
}
|
|
@@ -71850,9 +72261,9 @@ var init_checks3 = __esm(() => {
|
|
|
71850
72261
|
// packages/workit-cli/src/verbs/gc.ts
|
|
71851
72262
|
var exports_gc = {};
|
|
71852
72263
|
__export(exports_gc, {
|
|
71853
|
-
run: () =>
|
|
72264
|
+
run: () => run7
|
|
71854
72265
|
});
|
|
71855
|
-
async function
|
|
72266
|
+
async function run7(argv, io) {
|
|
71856
72267
|
const dryRun = argv.includes("--dry-run");
|
|
71857
72268
|
const pruneRecovery = argv.includes("--prune-recovery");
|
|
71858
72269
|
if (pruneRecovery && !dryRun && !argv.includes("--yes"))
|
|
@@ -71896,9 +72307,9 @@ var init_gc = __esm(() => {
|
|
|
71896
72307
|
// packages/workit-cli/src/verbs/uninstall.ts
|
|
71897
72308
|
var exports_uninstall = {};
|
|
71898
72309
|
__export(exports_uninstall, {
|
|
71899
|
-
run: () =>
|
|
72310
|
+
run: () => run8
|
|
71900
72311
|
});
|
|
71901
|
-
async function
|
|
72312
|
+
async function run8(_argv, io) {
|
|
71902
72313
|
if (io.json)
|
|
71903
72314
|
return emit(io, fail("invalid_input", "workit uninstall is interactive and has no --json output", {
|
|
71904
72315
|
unblock: "run `workit uninstall` in a terminal without --json"
|
|
@@ -71914,7 +72325,7 @@ var init_uninstall2 = __esm(() => {
|
|
|
71914
72325
|
// packages/workit-cli/src/verbs/grant.ts
|
|
71915
72326
|
var exports_grant = {};
|
|
71916
72327
|
__export(exports_grant, {
|
|
71917
|
-
run: () =>
|
|
72328
|
+
run: () => run9,
|
|
71918
72329
|
runGrant: () => runGrant
|
|
71919
72330
|
});
|
|
71920
72331
|
function show(argv, io) {
|
|
@@ -72035,7 +72446,7 @@ var USAGE2 = "workit grant show [<workspace>] [--all] | grant set <workspace> <k
|
|
|
72035
72446
|
...endpoint.endpointIssue ? [` note: ${endpoint.endpointIssue}`] : [],
|
|
72036
72447
|
` verification: ${verification} (${verification === "independent" ? "a normal-risk behavior change needs a non-author verdict" : "a normal-risk behavior change needs a passing check and the author's --self verdict, shown as self-reviewed"})`
|
|
72037
72448
|
], usage2 = (io, message) => emit(io, fail("invalid_input", `${message}
|
|
72038
|
-
usage: ${USAGE2}`)),
|
|
72449
|
+
usage: ${USAGE2}`)), run9 = (argv, io) => runGrant(argv, io);
|
|
72039
72450
|
var init_grant = __esm(() => {
|
|
72040
72451
|
init_autonomy();
|
|
72041
72452
|
init_release_tracks();
|
|
@@ -72064,9 +72475,9 @@ var init_grant = __esm(() => {
|
|
|
72064
72475
|
// packages/workit-cli/src/verbs/check.ts
|
|
72065
72476
|
var exports_check = {};
|
|
72066
72477
|
__export(exports_check, {
|
|
72067
|
-
run: () =>
|
|
72478
|
+
run: () => run10
|
|
72068
72479
|
});
|
|
72069
|
-
import
|
|
72480
|
+
import path39 from "node:path";
|
|
72070
72481
|
function parse5(argv) {
|
|
72071
72482
|
const split = argv.indexOf("--");
|
|
72072
72483
|
const head = split >= 0 ? argv.slice(0, split) : [...argv];
|
|
@@ -72215,7 +72626,7 @@ function boundedArgv(argv) {
|
|
|
72215
72626
|
const truncated = cut.length !== argv.length || cut.some((item, index) => item !== argv[index]);
|
|
72216
72627
|
return { argv: cut, truncated };
|
|
72217
72628
|
}
|
|
72218
|
-
async function
|
|
72629
|
+
async function run10(argv, io) {
|
|
72219
72630
|
const options = parse5(argv);
|
|
72220
72631
|
if (options instanceof Error)
|
|
72221
72632
|
return emit(io, fail("invalid_input", options.message, { unblock: USAGE3 }));
|
|
@@ -72249,7 +72660,7 @@ async function run9(argv, io) {
|
|
|
72249
72660
|
if (options.shell && command.length !== 1)
|
|
72250
72661
|
return emit(io, fail("invalid_input", '--shell takes the command as one string: workit check --shell -- "<cmd>"'));
|
|
72251
72662
|
}
|
|
72252
|
-
const relCwd = posix(
|
|
72663
|
+
const relCwd = posix(path39.relative(top, runCwd));
|
|
72253
72664
|
const configured = !options.shell && matchesNamedCheck(config, name, command, relCwd);
|
|
72254
72665
|
const actor = actorFromEnv(io.env);
|
|
72255
72666
|
const branchKey = codeKey(io.cwd, { base: options.base });
|
|
@@ -72373,7 +72784,7 @@ async function run9(argv, io) {
|
|
|
72373
72784
|
return recordError.code === "busy" ? 4 : recordError.code === "invalid_input" ? 2 : 5;
|
|
72374
72785
|
return 0;
|
|
72375
72786
|
}
|
|
72376
|
-
var USAGE3 = "workit check <name> | workit check [--name <n>] [--shell] [--timeout <s>] [--task <id>] [--json] -- <cmd…>", RECORD_TAIL_LINES = 20, RECORD_TAIL_CHARS = 200, posix = (value) => value.split(
|
|
72787
|
+
var USAGE3 = "workit check <name> | workit check [--name <n>] [--shell] [--timeout <s>] [--task <id>] [--json] -- <cmd…>", RECORD_TAIL_LINES = 20, RECORD_TAIL_CHARS = 200, posix = (value) => value.split(path39.sep).join("/") || ".", ENGINE_CODES2, FINGERPRINT_VARS;
|
|
72377
72788
|
var init_check = __esm(() => {
|
|
72378
72789
|
init_check_config();
|
|
72379
72790
|
init_checks3();
|
|
@@ -72395,9 +72806,9 @@ var init_check = __esm(() => {
|
|
|
72395
72806
|
var success2 = (data) => ({ ok: true, data }), failure3 = (code, error, unblock) => ({ ok: false, code, error, ...unblock ? { unblock } : {} });
|
|
72396
72807
|
|
|
72397
72808
|
// packages/workit-core/src/git/ops.ts
|
|
72398
|
-
import { spawnSync as
|
|
72399
|
-
import { existsSync as
|
|
72400
|
-
import
|
|
72809
|
+
import { spawnSync as spawnSync18 } from "node:child_process";
|
|
72810
|
+
import { existsSync as existsSync19, readFileSync as readFileSync19 } from "node:fs";
|
|
72811
|
+
import path40 from "node:path";
|
|
72401
72812
|
function operationInProgress(cwd) {
|
|
72402
72813
|
const markers = [
|
|
72403
72814
|
["rebase-merge", "rebase"],
|
|
@@ -72410,18 +72821,18 @@ function operationInProgress(cwd) {
|
|
|
72410
72821
|
if (!run.ok)
|
|
72411
72822
|
return null;
|
|
72412
72823
|
const found = run.stdout.split(`
|
|
72413
|
-
`).map((line) =>
|
|
72824
|
+
`).map((line) => path40.resolve(cwd, line.trim()));
|
|
72414
72825
|
const conflicted = () => git5(cwd, ["ls-files", "-u"]).stdout.trim() !== "";
|
|
72415
72826
|
for (const [index, [, operation]] of markers.entries()) {
|
|
72416
72827
|
const marker = found[index];
|
|
72417
|
-
if (!marker || !
|
|
72828
|
+
if (!marker || !existsSync19(marker))
|
|
72418
72829
|
continue;
|
|
72419
|
-
if (index === 1 &&
|
|
72830
|
+
if (index === 1 && existsSync19(path40.join(marker, "applying")))
|
|
72420
72831
|
return { operation: "am", commitAllowed: false, branch: null };
|
|
72421
|
-
if (index === 0 &&
|
|
72832
|
+
if (index === 0 && existsSync19(path40.join(marker, "amend")) && !conflicted()) {
|
|
72422
72833
|
let headName = "";
|
|
72423
72834
|
try {
|
|
72424
|
-
headName =
|
|
72835
|
+
headName = readFileSync19(path40.join(marker, "head-name"), "utf8").trim();
|
|
72425
72836
|
} catch {}
|
|
72426
72837
|
const branch = headName.startsWith("refs/heads/") ? headName.slice("refs/heads/".length) : null;
|
|
72427
72838
|
return { operation, commitAllowed: branch !== null, branch };
|
|
@@ -72671,7 +73082,7 @@ function gitCommit(cwd, input) {
|
|
|
72671
73082
|
if (paths.some((value) => value.startsWith("-") || !value.trim()))
|
|
72672
73083
|
return failure3("invalid_input", "paths must not be empty or start with -");
|
|
72673
73084
|
const tracked = new Set(nulList(git5(cwd, ["ls-files", "-z", "--", ...paths]).stdout));
|
|
72674
|
-
const addable = paths.filter((value) =>
|
|
73085
|
+
const addable = paths.filter((value) => existsSync19(path40.resolve(cwd, value)) || [...tracked].some((file) => file === value || file.startsWith(`${value}/`)));
|
|
72675
73086
|
if (addable.length) {
|
|
72676
73087
|
const added = git5(cwd, ["add", "-A", "--", ...addable]);
|
|
72677
73088
|
if (!added.ok)
|
|
@@ -72950,7 +73361,7 @@ ${run.stdout}`;
|
|
|
72950
73361
|
} : { ok: false, lease: false, error: gitError(run) };
|
|
72951
73362
|
}
|
|
72952
73363
|
var COMMIT_TIMEOUT_MS, PUSH_TIMEOUT_MS = 120000, git5 = (cwd, args, options = {}) => {
|
|
72953
|
-
const result =
|
|
73364
|
+
const result = spawnSync18("git", args, {
|
|
72954
73365
|
cwd,
|
|
72955
73366
|
encoding: "utf8",
|
|
72956
73367
|
env: { ...options.env ?? process.env, GIT_TERMINAL_PROMPT: "0" },
|
|
@@ -73004,10 +73415,10 @@ var init_ops = __esm(() => {
|
|
|
73004
73415
|
|
|
73005
73416
|
// packages/workit-core/src/forge/reruns.ts
|
|
73006
73417
|
import fs19 from "node:fs";
|
|
73007
|
-
import
|
|
73418
|
+
import path41 from "node:path";
|
|
73008
73419
|
function rerunLogPath(cwd) {
|
|
73009
73420
|
const common = gitCommonDir(cwd);
|
|
73010
|
-
return common ?
|
|
73421
|
+
return common ? path41.join(common, "workit", "ci-reruns.jsonl") : null;
|
|
73011
73422
|
}
|
|
73012
73423
|
function rerunCounts(cwd, key) {
|
|
73013
73424
|
const counts = new Map;
|
|
@@ -73042,7 +73453,7 @@ function recordReruns(cwd, rows) {
|
|
|
73042
73453
|
if (!file)
|
|
73043
73454
|
return false;
|
|
73044
73455
|
try {
|
|
73045
|
-
fs19.mkdirSync(
|
|
73456
|
+
fs19.mkdirSync(path41.dirname(file), { recursive: true });
|
|
73046
73457
|
fs19.appendFileSync(file, rows.map((row) => `${JSON.stringify(row)}
|
|
73047
73458
|
`).join(""));
|
|
73048
73459
|
return true;
|
|
@@ -73055,7 +73466,7 @@ function withRerunLock(cwd, fn) {
|
|
|
73055
73466
|
if (!file)
|
|
73056
73467
|
return fn();
|
|
73057
73468
|
const lock = `${file.slice(0, -".jsonl".length)}.lock`;
|
|
73058
|
-
fs19.mkdirSync(
|
|
73469
|
+
fs19.mkdirSync(path41.dirname(lock), { recursive: true });
|
|
73059
73470
|
const until = Date.now() + LOCK_WAIT_MS2;
|
|
73060
73471
|
for (;; ) {
|
|
73061
73472
|
try {
|
|
@@ -73478,7 +73889,7 @@ var init_report = __esm(() => {
|
|
|
73478
73889
|
});
|
|
73479
73890
|
|
|
73480
73891
|
// packages/workit-core/src/forge/pr-ops.ts
|
|
73481
|
-
import { spawnSync as
|
|
73892
|
+
import { spawnSync as spawnSync19 } from "node:child_process";
|
|
73482
73893
|
function fillFromCommits(cwd, resolved, base) {
|
|
73483
73894
|
const tracking = `refs/remotes/${resolved.baseRemote}/${base}`;
|
|
73484
73895
|
if (!base.startsWith("-"))
|
|
@@ -73486,7 +73897,7 @@ function fillFromCommits(cwd, resolved, base) {
|
|
|
73486
73897
|
const from = resolveRef(cwd, tracking) ?? resolveRef(cwd, `refs/heads/${base}`);
|
|
73487
73898
|
if (!from)
|
|
73488
73899
|
return failure3("not_found", `base ${base} is not available locally`, `git fetch ${resolved.baseRemote} ${base}`);
|
|
73489
|
-
const log =
|
|
73900
|
+
const log = spawnSync19("git", ["log", "--reverse", "--no-merges", "--format=%s%x1f%b%x1e", `${from}..HEAD`], {
|
|
73490
73901
|
cwd,
|
|
73491
73902
|
encoding: "utf8",
|
|
73492
73903
|
timeout: GIT_TIMEOUTS.local,
|
|
@@ -73842,10 +74253,10 @@ var init_pr_ops = __esm(() => {
|
|
|
73842
74253
|
});
|
|
73843
74254
|
|
|
73844
74255
|
// packages/workit-core/src/stack.ts
|
|
73845
|
-
import { spawnSync as
|
|
74256
|
+
import { spawnSync as spawnSync20 } from "node:child_process";
|
|
73846
74257
|
import { createHash as createHash16, randomBytes as randomBytes3 } from "node:crypto";
|
|
73847
74258
|
import fs20 from "node:fs";
|
|
73848
|
-
import
|
|
74259
|
+
import path42 from "node:path";
|
|
73849
74260
|
function worktreeOf(cwd, branch) {
|
|
73850
74261
|
const list = gitRun3(cwd, ["worktree", "list", "--porcelain"]);
|
|
73851
74262
|
if (!list.ok)
|
|
@@ -73889,7 +74300,7 @@ function gitRestack(cwd, input) {
|
|
|
73889
74300
|
if (!scratch)
|
|
73890
74301
|
return { ok: false, conflict: false, worktree: cwd, error: "no store root" };
|
|
73891
74302
|
fs20.mkdirSync(scratch, { recursive: true });
|
|
73892
|
-
dir =
|
|
74303
|
+
dir = path42.join(scratch, `${input.branch.replace(/[^A-Za-z0-9._-]+/gu, "_").slice(0, 40)}-${randomBytes3(4).toString("hex")}`);
|
|
73893
74304
|
const added = gitRun3(cwd, ["worktree", "add", "-q", dir, input.branch], GIT_TIMEOUTS.worktree);
|
|
73894
74305
|
if (!added.ok)
|
|
73895
74306
|
return { ok: false, conflict: false, worktree: cwd, error: firstLine(added) };
|
|
@@ -73930,7 +74341,7 @@ function pruneScratch(cwd) {
|
|
|
73930
74341
|
if (!scratch || !fs20.existsSync(scratch))
|
|
73931
74342
|
return;
|
|
73932
74343
|
for (const name of fs20.readdirSync(scratch)) {
|
|
73933
|
-
const dir =
|
|
74344
|
+
const dir = path42.join(scratch, name);
|
|
73934
74345
|
if (!rebaseInProgress(dir) && !trackedDirt(dir))
|
|
73935
74346
|
gitRun3(cwd, ["worktree", "remove", "--force", dir]);
|
|
73936
74347
|
}
|
|
@@ -73940,7 +74351,7 @@ function stacksDir(cwd) {
|
|
|
73940
74351
|
const root = storeRoot(cwd);
|
|
73941
74352
|
if (!root.ok)
|
|
73942
74353
|
return stackFail(root.code, root.error, root.unblock);
|
|
73943
|
-
return { ok: true, data:
|
|
74354
|
+
return { ok: true, data: path42.join(root.value.root, "stacks") };
|
|
73944
74355
|
}
|
|
73945
74356
|
function parseStack(raw) {
|
|
73946
74357
|
if (!isRecord7(raw) || !Array.isArray(raw.branches))
|
|
@@ -73992,7 +74403,7 @@ function readStack(cwd, name) {
|
|
|
73992
74403
|
const dir = stacksDir(cwd);
|
|
73993
74404
|
if (!dir.ok)
|
|
73994
74405
|
return dir;
|
|
73995
|
-
const file =
|
|
74406
|
+
const file = path42.join(dir.data, fileFor(name));
|
|
73996
74407
|
let text;
|
|
73997
74408
|
try {
|
|
73998
74409
|
text = fs20.readFileSync(file, "utf8");
|
|
@@ -74013,7 +74424,7 @@ function writeStack(cwd, stack, now = new Date) {
|
|
|
74013
74424
|
const dir = stacksDir(cwd);
|
|
74014
74425
|
if (!dir.ok)
|
|
74015
74426
|
return dir;
|
|
74016
|
-
const file =
|
|
74427
|
+
const file = path42.join(dir.data, fileFor(stack.name));
|
|
74017
74428
|
const temp = `${file}.${process.pid}.tmp`;
|
|
74018
74429
|
try {
|
|
74019
74430
|
fs20.mkdirSync(dir.data, { recursive: true });
|
|
@@ -74041,7 +74452,7 @@ function listStacks(cwd) {
|
|
|
74041
74452
|
for (const name of names) {
|
|
74042
74453
|
let parsed = null;
|
|
74043
74454
|
try {
|
|
74044
|
-
parsed = parseStack(JSON.parse(fs20.readFileSync(
|
|
74455
|
+
parsed = parseStack(JSON.parse(fs20.readFileSync(path42.join(dir.data, name), "utf8")));
|
|
74045
74456
|
} catch {
|
|
74046
74457
|
parsed = null;
|
|
74047
74458
|
}
|
|
@@ -74100,7 +74511,7 @@ function takeLock(lock) {
|
|
|
74100
74511
|
host: localLockHost(),
|
|
74101
74512
|
nonce: randomBytes3(8).toString("hex")
|
|
74102
74513
|
};
|
|
74103
|
-
fs20.writeFileSync(
|
|
74514
|
+
fs20.writeFileSync(path42.join(lock, OWNER), JSON.stringify(owner));
|
|
74104
74515
|
return owner;
|
|
74105
74516
|
}
|
|
74106
74517
|
function reapLock(lock, observed) {
|
|
@@ -74137,7 +74548,7 @@ async function withStackLock(cwd, name, fn, waitMs = LOCK_WAIT_MS3) {
|
|
|
74137
74548
|
return dir;
|
|
74138
74549
|
if (!validName(name))
|
|
74139
74550
|
return stackFail("invalid_input", "a stack name must be 1-200 printable characters");
|
|
74140
|
-
const lock =
|
|
74551
|
+
const lock = path42.join(dir.data, `${fileFor(name)}.lock`);
|
|
74141
74552
|
try {
|
|
74142
74553
|
fs20.mkdirSync(dir.data, { recursive: true });
|
|
74143
74554
|
} catch (error) {
|
|
@@ -74167,7 +74578,7 @@ async function withStackLock(cwd, name, fn, waitMs = LOCK_WAIT_MS3) {
|
|
|
74167
74578
|
const touch = () => {
|
|
74168
74579
|
try {
|
|
74169
74580
|
const now = new Date;
|
|
74170
|
-
fs20.utimesSync(
|
|
74581
|
+
fs20.utimesSync(path42.join(lock, OWNER), now, now);
|
|
74171
74582
|
} catch {}
|
|
74172
74583
|
};
|
|
74173
74584
|
const beat = setInterval(touch, HEARTBEAT_MS);
|
|
@@ -74355,7 +74766,7 @@ function commitKeys(cwd, range) {
|
|
|
74355
74766
|
const patches = new Map;
|
|
74356
74767
|
const diff = gitRun3(cwd, ["log", "--no-merges", "-p", "--format=commit %H", range]);
|
|
74357
74768
|
if (diff.ok && diff.stdout.trim()) {
|
|
74358
|
-
const ids =
|
|
74769
|
+
const ids = spawnSync20("git", ["patch-id", "--stable"], {
|
|
74359
74770
|
cwd,
|
|
74360
74771
|
input: diff.stdout,
|
|
74361
74772
|
encoding: "utf8",
|
|
@@ -74979,7 +75390,7 @@ var STACK_VERSION = 1, stackFail = (code, error, unblock, data) => ({
|
|
|
74979
75390
|
...unblock ? { unblock } : {},
|
|
74980
75391
|
...data ? { data } : {}
|
|
74981
75392
|
}), fromForge = (result) => stackFail(result.code, result.error, result.unblock), stackDeps, gitRun3 = (cwd, args, timeoutMs = GIT_TIMEOUTS.local) => {
|
|
74982
|
-
const run =
|
|
75393
|
+
const run = spawnSync20("git", args, {
|
|
74983
75394
|
cwd,
|
|
74984
75395
|
encoding: "utf8",
|
|
74985
75396
|
timeout: timeoutMs,
|
|
@@ -75007,7 +75418,7 @@ var STACK_VERSION = 1, stackFail = (code, error, unblock, data) => ({
|
|
|
75007
75418
|
return !status.ok || status.stdout.trim() !== "";
|
|
75008
75419
|
}, scratchDir = (cwd) => {
|
|
75009
75420
|
const dir = stacksDir(cwd);
|
|
75010
|
-
return dir.ok ?
|
|
75421
|
+
return dir.ok ? path42.join(dir.data, "worktrees") : null;
|
|
75011
75422
|
}, firstLine = (run) => (`${run.stderr}
|
|
75012
75423
|
${run.stdout}`.split(`
|
|
75013
75424
|
`).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()}-${createHash16("sha256").update(name).digest("hex").slice(0, 12)}.json`, fileFor, validName = (name) => {
|
|
@@ -75022,12 +75433,12 @@ ${run.stdout}`.split(`
|
|
|
75022
75433
|
}, isRecord7 = (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) => {
|
|
75023
75434
|
let raw = null;
|
|
75024
75435
|
try {
|
|
75025
|
-
raw = fs20.readFileSync(
|
|
75436
|
+
raw = fs20.readFileSync(path42.join(lock, OWNER), "utf8");
|
|
75026
75437
|
} catch {
|
|
75027
75438
|
raw = null;
|
|
75028
75439
|
}
|
|
75029
75440
|
let age = null;
|
|
75030
|
-
for (const target of [
|
|
75441
|
+
for (const target of [path42.join(lock, OWNER), lock])
|
|
75031
75442
|
try {
|
|
75032
75443
|
age = Date.now() - fs20.statSync(target).mtimeMs;
|
|
75033
75444
|
break;
|
|
@@ -75060,7 +75471,7 @@ var init_stack = __esm(() => {
|
|
|
75060
75471
|
});
|
|
75061
75472
|
|
|
75062
75473
|
// packages/workit-core/src/forge/pr-edit.ts
|
|
75063
|
-
import { spawnSync as
|
|
75474
|
+
import { spawnSync as spawnSync21 } from "node:child_process";
|
|
75064
75475
|
function openPr(cwd, resolved, pr) {
|
|
75065
75476
|
const grant = requireGrant(cwd, "pr");
|
|
75066
75477
|
if (!grant.allowed)
|
|
@@ -75225,7 +75636,7 @@ function replyToThread(cwd, resolved, input) {
|
|
|
75225
75636
|
});
|
|
75226
75637
|
}
|
|
75227
75638
|
var label = (resolved, number) => `${resolved.forge.kind === "github" ? "PR #" : "MR !"}${number}`, git6 = (cwd, args) => {
|
|
75228
|
-
const run =
|
|
75639
|
+
const run = spawnSync21("git", args, {
|
|
75229
75640
|
cwd,
|
|
75230
75641
|
encoding: "utf8",
|
|
75231
75642
|
timeout: GIT_TIMEOUTS.local,
|
|
@@ -75245,15 +75656,15 @@ var init_pr_edit = __esm(() => {
|
|
|
75245
75656
|
});
|
|
75246
75657
|
|
|
75247
75658
|
// packages/workit-core/src/forge/exec.ts
|
|
75248
|
-
import { spawnSync as
|
|
75659
|
+
import { spawnSync as spawnSync22 } from "node:child_process";
|
|
75249
75660
|
import fs21 from "node:fs";
|
|
75250
|
-
import
|
|
75661
|
+
import path43 from "node:path";
|
|
75251
75662
|
function findExecutable(bin, env) {
|
|
75252
|
-
const dirs = (env.PATH ?? env.Path ?? "").split(
|
|
75663
|
+
const dirs = (env.PATH ?? env.Path ?? "").split(path43.delimiter).filter(Boolean);
|
|
75253
75664
|
const exts = process.platform === "win32" ? [".exe"] : [""];
|
|
75254
75665
|
for (const dir of dirs)
|
|
75255
75666
|
for (const ext of exts) {
|
|
75256
|
-
const candidate =
|
|
75667
|
+
const candidate = path43.join(dir, `${bin}${ext}`);
|
|
75257
75668
|
try {
|
|
75258
75669
|
const stat = fs21.statSync(candidate);
|
|
75259
75670
|
if (stat.isFile())
|
|
@@ -75280,7 +75691,7 @@ function systemRunner(kind, apiHost, env = process.env) {
|
|
|
75280
75691
|
if (!exe)
|
|
75281
75692
|
return { status: null, stdout: "", stderr: "", timedOut: false, missing: true };
|
|
75282
75693
|
const token = options.token ? kind === "github" ? { GH_TOKEN: options.token, GH_ENTERPRISE_TOKEN: options.token } : { GITLAB_TOKEN: options.token } : {};
|
|
75283
|
-
const result =
|
|
75694
|
+
const result = spawnSync22(exe, [...args], {
|
|
75284
75695
|
encoding: "utf8",
|
|
75285
75696
|
env: { ...childEnv, ...token },
|
|
75286
75697
|
maxBuffer: MAX_BUFFER2,
|
|
@@ -76444,7 +76855,7 @@ var init_duration = __esm(() => {
|
|
|
76444
76855
|
});
|
|
76445
76856
|
|
|
76446
76857
|
// packages/workit-cli/src/verbs/forge-common.ts
|
|
76447
|
-
import { readFileSync as
|
|
76858
|
+
import { readFileSync as readFileSync20 } from "node:fs";
|
|
76448
76859
|
function parseFlags(argv, spec) {
|
|
76449
76860
|
const parsed = { values: {}, booleans: new Set, lists: {}, positionals: [] };
|
|
76450
76861
|
for (let index = 0;index < argv.length; index += 1) {
|
|
@@ -76588,7 +76999,7 @@ var init_forge_common = __esm(() => {
|
|
|
76588
76999
|
forgeDeps = {
|
|
76589
77000
|
runner: undefined,
|
|
76590
77001
|
npm: undefined,
|
|
76591
|
-
readStdin: () =>
|
|
77002
|
+
readStdin: () => readFileSync20(0, "utf8"),
|
|
76592
77003
|
sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
|
|
76593
77004
|
now: () => Date.now()
|
|
76594
77005
|
};
|
|
@@ -76597,14 +77008,14 @@ var init_forge_common = __esm(() => {
|
|
|
76597
77008
|
// packages/workit-cli/src/verbs/pr.ts
|
|
76598
77009
|
var exports_pr = {};
|
|
76599
77010
|
__export(exports_pr, {
|
|
76600
|
-
run: () =>
|
|
77011
|
+
run: () => run11
|
|
76601
77012
|
});
|
|
76602
|
-
import { readFileSync as
|
|
76603
|
-
import
|
|
77013
|
+
import { readFileSync as readFileSync21 } from "node:fs";
|
|
77014
|
+
import path44 from "node:path";
|
|
76604
77015
|
function readBodyFile(io, file) {
|
|
76605
77016
|
try {
|
|
76606
77017
|
return {
|
|
76607
|
-
body: file === "-" ? forgeDeps.readStdin() :
|
|
77018
|
+
body: file === "-" ? forgeDeps.readStdin() : readFileSync21(path44.resolve(io.cwd, file), "utf8")
|
|
76608
77019
|
};
|
|
76609
77020
|
} catch {
|
|
76610
77021
|
return `cannot read --body-file ${file}`;
|
|
@@ -76931,7 +77342,7 @@ async function reply(argv, io) {
|
|
|
76931
77342
|
`${[data.replied ? "replied to" : null, data.resolved ? "resolved" : null].filter(Boolean).join(" and ")} thread ${data.thread} on ${prLabel(kind, data.number)}${data.replyUrl ? ` ${data.replyUrl}` : ""}`
|
|
76932
77343
|
]);
|
|
76933
77344
|
}
|
|
76934
|
-
async function
|
|
77345
|
+
async function run11(argv, io) {
|
|
76935
77346
|
const [sub, ...rest] = argv;
|
|
76936
77347
|
if (sub === "status")
|
|
76937
77348
|
return status(rest, io);
|
|
@@ -76966,7 +77377,7 @@ var init_pr = __esm(() => {
|
|
|
76966
77377
|
// packages/workit-cli/src/verbs/ci.ts
|
|
76967
77378
|
var exports_ci = {};
|
|
76968
77379
|
__export(exports_ci, {
|
|
76969
|
-
run: () =>
|
|
77380
|
+
run: () => run12
|
|
76970
77381
|
});
|
|
76971
77382
|
async function wait(argv, io) {
|
|
76972
77383
|
const flags = parseFlags(argv, {
|
|
@@ -77135,7 +77546,7 @@ async function rerun(argv, io) {
|
|
|
77135
77546
|
"next: workit ci wait"
|
|
77136
77547
|
]);
|
|
77137
77548
|
}
|
|
77138
|
-
async function
|
|
77549
|
+
async function run12(argv, io) {
|
|
77139
77550
|
const [sub, ...rest] = argv;
|
|
77140
77551
|
if (sub === "wait")
|
|
77141
77552
|
return wait(rest, io);
|
|
@@ -77183,10 +77594,10 @@ var init_implicit_task = __esm(() => {
|
|
|
77183
77594
|
// packages/workit-cli/src/verbs/git.ts
|
|
77184
77595
|
var exports_git = {};
|
|
77185
77596
|
__export(exports_git, {
|
|
77186
|
-
run: () =>
|
|
77597
|
+
run: () => run13
|
|
77187
77598
|
});
|
|
77188
|
-
import { readFileSync as
|
|
77189
|
-
import
|
|
77599
|
+
import { readFileSync as readFileSync22 } from "node:fs";
|
|
77600
|
+
import path45 from "node:path";
|
|
77190
77601
|
async function branch(argv, io) {
|
|
77191
77602
|
const flags = parseFlags(argv, {
|
|
77192
77603
|
base: "value",
|
|
@@ -77277,7 +77688,7 @@ function commitMessage(parsed, io) {
|
|
|
77277
77688
|
|
|
77278
77689
|
`);
|
|
77279
77690
|
try {
|
|
77280
|
-
return file === "-" ?
|
|
77691
|
+
return file === "-" ? readFileSync22(0, "utf8") : readFileSync22(path45.resolve(io.cwd, file), "utf8");
|
|
77281
77692
|
} catch (error) {
|
|
77282
77693
|
return {
|
|
77283
77694
|
error: `cannot read -F ${file}: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -77380,7 +77791,7 @@ async function push(argv, io) {
|
|
|
77380
77791
|
...data.upstream ? [`upstream: ${data.remote}/${data.branch}`] : []
|
|
77381
77792
|
]);
|
|
77382
77793
|
}
|
|
77383
|
-
async function
|
|
77794
|
+
async function run13(argv, io) {
|
|
77384
77795
|
const [sub, ...rest] = argv;
|
|
77385
77796
|
if (sub === "branch")
|
|
77386
77797
|
return branch(rest, io);
|
|
@@ -77408,7 +77819,7 @@ var init_git2 = __esm(() => {
|
|
|
77408
77819
|
});
|
|
77409
77820
|
|
|
77410
77821
|
// packages/workit-core/src/forge/verify.ts
|
|
77411
|
-
import { spawnSync as
|
|
77822
|
+
import { spawnSync as spawnSync23 } from "node:child_process";
|
|
77412
77823
|
function finish(cwd, report, actor) {
|
|
77413
77824
|
const delivered = report.observations.length > 0 && report.observations.every((entry) => entry.ok);
|
|
77414
77825
|
const out = { ...report, delivered };
|
|
@@ -77621,7 +78032,7 @@ var NPM_NAME, SEMVER2, SAFE_ARG, systemNpm = (args) => {
|
|
|
77621
78032
|
};
|
|
77622
78033
|
const found = process.platform === "win32" ? findExecutable("npm.cmd", process.env) : null;
|
|
77623
78034
|
const npmCmd = found && !/["%!^]/u.test(found) ? `"${found}"` : "npm.cmd";
|
|
77624
|
-
const result = process.platform === "win32" ?
|
|
78035
|
+
const result = process.platform === "win32" ? spawnSync23(`${npmCmd} ${args.join(" ")}`, { ...options, shell: true }) : spawnSync23("npm", [...args], options);
|
|
77625
78036
|
return { status: result.status, stdout: result.stdout ?? "", stderr: result.stderr ?? "" };
|
|
77626
78037
|
}, short3 = (sha) => sha ? sha.slice(0, 12) : "(absent)", npmView = (stdout) => {
|
|
77627
78038
|
try {
|
|
@@ -77646,9 +78057,9 @@ var init_verify = __esm(() => {
|
|
|
77646
78057
|
// packages/workit-cli/src/verbs/verify-delivery.ts
|
|
77647
78058
|
var exports_verify_delivery = {};
|
|
77648
78059
|
__export(exports_verify_delivery, {
|
|
77649
|
-
run: () =>
|
|
78060
|
+
run: () => run14
|
|
77650
78061
|
});
|
|
77651
|
-
async function
|
|
78062
|
+
async function run14(argv, io) {
|
|
77652
78063
|
const flags = parseFlags(argv, {
|
|
77653
78064
|
expect: "value",
|
|
77654
78065
|
branch: "value",
|
|
@@ -77730,7 +78141,7 @@ var init_verify_delivery = __esm(() => {
|
|
|
77730
78141
|
// packages/workit-cli/src/verbs/stack.ts
|
|
77731
78142
|
var exports_stack = {};
|
|
77732
78143
|
__export(exports_stack, {
|
|
77733
|
-
run: () =>
|
|
78144
|
+
run: () => run15
|
|
77734
78145
|
});
|
|
77735
78146
|
async function plan(argv, io) {
|
|
77736
78147
|
const flags = parseFlags(argv, { name: "value", trunk: "value", track: "value" });
|
|
@@ -77912,7 +78323,7 @@ async function land(argv, io) {
|
|
|
77912
78323
|
unblock: ${data.stoppedAt.unblock}` : data.complete ? "stack complete" : ""
|
|
77913
78324
|
].filter(Boolean));
|
|
77914
78325
|
}
|
|
77915
|
-
async function
|
|
78326
|
+
async function run15(argv, io) {
|
|
77916
78327
|
const [sub, ...rest] = argv.filter((arg) => arg !== "--json");
|
|
77917
78328
|
if (sub === "plan")
|
|
77918
78329
|
return plan(rest, io);
|
|
@@ -77942,10 +78353,10 @@ var init_stack2 = __esm(() => {
|
|
|
77942
78353
|
});
|
|
77943
78354
|
|
|
77944
78355
|
// packages/workit-core/src/fanout.ts
|
|
77945
|
-
import { spawnSync as
|
|
78356
|
+
import { spawnSync as spawnSync24 } from "node:child_process";
|
|
77946
78357
|
import { createHash as createHash17 } from "node:crypto";
|
|
77947
78358
|
import fs23 from "node:fs";
|
|
77948
|
-
import
|
|
78359
|
+
import path46 from "node:path";
|
|
77949
78360
|
function expandBraces(pattern, limit = 64) {
|
|
77950
78361
|
for (let index = 0;index < pattern.length; index += 1) {
|
|
77951
78362
|
if (pattern[index] === "\\") {
|
|
@@ -78179,7 +78590,7 @@ function parsePlan(raw, defaults, name) {
|
|
|
78179
78590
|
id,
|
|
78180
78591
|
branch,
|
|
78181
78592
|
base: optional("base") ?? "",
|
|
78182
|
-
worktree:
|
|
78593
|
+
worktree: path46.resolve(defaults.root, optional("worktree") ?? path46.join(defaults.worktreeRoot, id)),
|
|
78183
78594
|
tier,
|
|
78184
78595
|
dependsOn: [...new Set(dependsOn ?? [])],
|
|
78185
78596
|
scope,
|
|
@@ -78408,11 +78819,11 @@ function defaultTrunk(cwd) {
|
|
|
78408
78819
|
}
|
|
78409
78820
|
function mainCheckout(cwd) {
|
|
78410
78821
|
const common = gitCommonDir(cwd);
|
|
78411
|
-
return common &&
|
|
78822
|
+
return common && path46.basename(common) === ".git" ? path46.dirname(common) : path46.resolve(cwd);
|
|
78412
78823
|
}
|
|
78413
78824
|
function worktreeRoot(cwd) {
|
|
78414
78825
|
const main = mainCheckout(cwd);
|
|
78415
|
-
return
|
|
78826
|
+
return path46.join(path46.dirname(main), `${path46.basename(main)}-wt`);
|
|
78416
78827
|
}
|
|
78417
78828
|
function sliceHash(slice) {
|
|
78418
78829
|
const {
|
|
@@ -78430,7 +78841,7 @@ function fanoutsDir(cwd) {
|
|
|
78430
78841
|
const root = storeRoot(cwd);
|
|
78431
78842
|
if (!root.ok)
|
|
78432
78843
|
return fanoutFail(root.code, root.error, root.unblock);
|
|
78433
|
-
return { ok: true, data:
|
|
78844
|
+
return { ok: true, data: path46.join(root.value.root, "fanouts") };
|
|
78434
78845
|
}
|
|
78435
78846
|
function parseStored(raw) {
|
|
78436
78847
|
if (!isRecord8(raw) || typeof raw.name !== "string" || typeof raw.trunk !== "string")
|
|
@@ -78496,7 +78907,7 @@ function readFanout(cwd, name) {
|
|
|
78496
78907
|
const dir = fanoutsDir(cwd);
|
|
78497
78908
|
if (!dir.ok)
|
|
78498
78909
|
return dir;
|
|
78499
|
-
const file =
|
|
78910
|
+
const file = path46.join(dir.data, stackFileName(name));
|
|
78500
78911
|
let parsed = null;
|
|
78501
78912
|
try {
|
|
78502
78913
|
parsed = parseStored(JSON.parse(fs23.readFileSync(file, "utf8")));
|
|
@@ -78521,7 +78932,7 @@ function listFanouts(cwd) {
|
|
|
78521
78932
|
for (const entry of names) {
|
|
78522
78933
|
let parsed = null;
|
|
78523
78934
|
try {
|
|
78524
|
-
parsed = parseStored(JSON.parse(fs23.readFileSync(
|
|
78935
|
+
parsed = parseStored(JSON.parse(fs23.readFileSync(path46.join(dir.data, entry), "utf8")));
|
|
78525
78936
|
} catch {
|
|
78526
78937
|
parsed = null;
|
|
78527
78938
|
}
|
|
@@ -78551,7 +78962,7 @@ function writeFanout(cwd, plan) {
|
|
|
78551
78962
|
const dir = fanoutsDir(cwd);
|
|
78552
78963
|
if (!dir.ok)
|
|
78553
78964
|
return dir;
|
|
78554
|
-
const file =
|
|
78965
|
+
const file = path46.join(dir.data, stackFileName(plan.name));
|
|
78555
78966
|
const temp = `${file}.${process.pid}.tmp`;
|
|
78556
78967
|
try {
|
|
78557
78968
|
fs23.mkdirSync(dir.data, { recursive: true });
|
|
@@ -78715,7 +79126,7 @@ var FANOUT_VERSION = 1, TIERS, FAN_IN_MODES, fanoutFail = (code, error, unblock,
|
|
|
78715
79126
|
text: edges.map((edge) => `add "${edge.dependsOn}" to "dependsOn" of slice ${edge.slice}`).join("; ")
|
|
78716
79127
|
};
|
|
78717
79128
|
}, gitRun4 = (cwd, args, timeoutMs = GIT_TIMEOUTS.local) => {
|
|
78718
|
-
const run =
|
|
79129
|
+
const run = spawnSync24("git", args, {
|
|
78719
79130
|
cwd,
|
|
78720
79131
|
encoding: "utf8",
|
|
78721
79132
|
timeout: timeoutMs,
|
|
@@ -78755,7 +79166,7 @@ var init_fanout = __esm(() => {
|
|
|
78755
79166
|
// packages/workit-core/src/fanout-worktree.ts
|
|
78756
79167
|
import { randomBytes as randomBytes4 } from "node:crypto";
|
|
78757
79168
|
import fs24 from "node:fs";
|
|
78758
|
-
import
|
|
79169
|
+
import path47 from "node:path";
|
|
78759
79170
|
function rowSample(lines) {
|
|
78760
79171
|
const out = [];
|
|
78761
79172
|
let bytes = 0;
|
|
@@ -78815,7 +79226,7 @@ function adminDir(worktree) {
|
|
|
78815
79226
|
const file = dir.stdout.trim();
|
|
78816
79227
|
let token = null;
|
|
78817
79228
|
try {
|
|
78818
|
-
token = fs24.readFileSync(
|
|
79229
|
+
token = fs24.readFileSync(path47.join(file, TOKEN_FILE), "utf8").trim() || null;
|
|
78819
79230
|
} catch {
|
|
78820
79231
|
token = null;
|
|
78821
79232
|
}
|
|
@@ -78823,7 +79234,7 @@ function adminDir(worktree) {
|
|
|
78823
79234
|
const stat = worktreeDeps.stat(file);
|
|
78824
79235
|
return {
|
|
78825
79236
|
path: file,
|
|
78826
|
-
id:
|
|
79237
|
+
id: path47.basename(file),
|
|
78827
79238
|
ino: stat.ino.toString(),
|
|
78828
79239
|
token,
|
|
78829
79240
|
birthMs: stat.birthtimeNs > 0n ? Number(stat.birthtimeMs) : null,
|
|
@@ -78839,7 +79250,7 @@ function markAdminDir(worktree) {
|
|
|
78839
79250
|
return null;
|
|
78840
79251
|
const token = randomBytes4(16).toString("hex");
|
|
78841
79252
|
try {
|
|
78842
|
-
fs24.writeFileSync(
|
|
79253
|
+
fs24.writeFileSync(path47.join(admin.path, TOKEN_FILE), `${token}
|
|
78843
79254
|
`);
|
|
78844
79255
|
} catch {
|
|
78845
79256
|
return null;
|
|
@@ -78854,7 +79265,7 @@ function excludeScratch(cwd) {
|
|
|
78854
79265
|
const common = gitCommonDir(cwd);
|
|
78855
79266
|
if (!common)
|
|
78856
79267
|
return;
|
|
78857
|
-
const file =
|
|
79268
|
+
const file = path47.join(common, "info", "exclude");
|
|
78858
79269
|
let text = "";
|
|
78859
79270
|
try {
|
|
78860
79271
|
text = fs24.readFileSync(file, "utf8");
|
|
@@ -78863,7 +79274,7 @@ function excludeScratch(cwd) {
|
|
|
78863
79274
|
}
|
|
78864
79275
|
if (text.split(/\r?\n/u).includes(EXCLUDE_LINE))
|
|
78865
79276
|
return;
|
|
78866
|
-
fs24.mkdirSync(
|
|
79277
|
+
fs24.mkdirSync(path47.dirname(file), { recursive: true });
|
|
78867
79278
|
fs24.appendFileSync(file, `${text && !text.endsWith(`
|
|
78868
79279
|
`) ? `
|
|
78869
79280
|
` : ""}# workit fanout: per-worker scratch dirs
|
|
@@ -78871,7 +79282,7 @@ ${EXCLUDE_LINE}
|
|
|
78871
79282
|
`);
|
|
78872
79283
|
}
|
|
78873
79284
|
function ensureScratch(worktree) {
|
|
78874
|
-
const scratch =
|
|
79285
|
+
const scratch = path47.join(worktree, SCRATCH_DIR);
|
|
78875
79286
|
fs24.mkdirSync(scratch, { recursive: true });
|
|
78876
79287
|
return scratch;
|
|
78877
79288
|
}
|
|
@@ -79007,7 +79418,7 @@ function releaseSliceWorktree(cwd, plan, input) {
|
|
|
79007
79418
|
const entry = worktrees[index];
|
|
79008
79419
|
if (index === 0)
|
|
79009
79420
|
return fanoutFail("blocked", `${target} is the main checkout; it is never released`);
|
|
79010
|
-
if (
|
|
79421
|
+
if (inside3(cwd, entry.path))
|
|
79011
79422
|
return fanoutFail("blocked", `this command runs inside ${entry.path}`, `run it from the main checkout: workit --cwd <main checkout> fanout worktree release ${slice.id}`);
|
|
79012
79423
|
if (entry.branch !== null && entry.branch !== `refs/heads/${slice.branch}`)
|
|
79013
79424
|
return fanoutFail("blocked", `${entry.path} is on ${entry.branch.replace(/^refs\/heads\//u, "")}, not slice ${slice.id}'s ${slice.branch}; nothing was removed`);
|
|
@@ -79089,7 +79500,7 @@ function unpushedCount(cwd, branch) {
|
|
|
79089
79500
|
return count.ok ? Number(count.stdout.trim()) : null;
|
|
79090
79501
|
}
|
|
79091
79502
|
function removeScratch(worktree) {
|
|
79092
|
-
const scratch =
|
|
79503
|
+
const scratch = path47.join(worktree, SCRATCH_DIR);
|
|
79093
79504
|
let stat;
|
|
79094
79505
|
try {
|
|
79095
79506
|
stat = fs24.lstatSync(scratch);
|
|
@@ -79105,16 +79516,16 @@ var SLOW, SCRATCH_DIR = ".workit-scratch", EXCLUDE_LINE, DIRTY_ROW_BYTES = 2000,
|
|
|
79105
79516
|
try {
|
|
79106
79517
|
return fs24.realpathSync.native(target);
|
|
79107
79518
|
} catch {
|
|
79108
|
-
return
|
|
79519
|
+
return path47.resolve(target);
|
|
79109
79520
|
}
|
|
79110
79521
|
}, samePath = (a, b) => {
|
|
79111
79522
|
const left = canonical2(a);
|
|
79112
79523
|
const right = canonical2(b);
|
|
79113
79524
|
return process.platform === "win32" || process.platform === "darwin" ? left.toLowerCase() === right.toLowerCase() : left === right;
|
|
79114
|
-
},
|
|
79115
|
-
const relative =
|
|
79116
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
79117
|
-
}, slicePath = (cwd, slice) =>
|
|
79525
|
+
}, inside3 = (child, parent) => {
|
|
79526
|
+
const relative = path47.relative(canonical2(parent), canonical2(child));
|
|
79527
|
+
return relative === "" || !relative.startsWith("..") && !path47.isAbsolute(relative);
|
|
79528
|
+
}, slicePath = (cwd, slice) => path47.isAbsolute(slice.worktree) ? slice.worktree : path47.resolve(mainCheckout(cwd), slice.worktree), CLOCK_SLACK_MS = 2000, TOKEN_FILE = "workit-fanout-token", worktreeDeps, worktreeFailed = (stderr) => fanoutFail("failed", `git worktree add failed: ${stderr.trim().split(`
|
|
79118
79529
|
`)[0] || "unknown error"}`);
|
|
79119
79530
|
var init_fanout_worktree = __esm(() => {
|
|
79120
79531
|
init_ops();
|
|
@@ -79235,7 +79646,7 @@ var init_fanout_brief = __esm(() => {
|
|
|
79235
79646
|
});
|
|
79236
79647
|
|
|
79237
79648
|
// packages/workit-core/src/fanout-landed.ts
|
|
79238
|
-
import { spawnSync as
|
|
79649
|
+
import { spawnSync as spawnSync25 } from "node:child_process";
|
|
79239
79650
|
function forgeBreaker(resolved) {
|
|
79240
79651
|
if (!resolved)
|
|
79241
79652
|
return { forge: null, down: () => null };
|
|
@@ -79326,7 +79737,7 @@ function trunkPatchIds(ctx, fork) {
|
|
|
79326
79737
|
"--"
|
|
79327
79738
|
]);
|
|
79328
79739
|
if (log.ok && log.stdout.trim()) {
|
|
79329
|
-
const run =
|
|
79740
|
+
const run = spawnSync25("git", ["patch-id", "--stable"], {
|
|
79330
79741
|
cwd: ctx.cwd,
|
|
79331
79742
|
input: log.stdout,
|
|
79332
79743
|
encoding: "utf8",
|
|
@@ -79887,10 +80298,10 @@ var init_fanout_status = __esm(() => {
|
|
|
79887
80298
|
// packages/workit-cli/src/verbs/fanout.ts
|
|
79888
80299
|
var exports_fanout = {};
|
|
79889
80300
|
__export(exports_fanout, {
|
|
79890
|
-
run: () =>
|
|
80301
|
+
run: () => run16
|
|
79891
80302
|
});
|
|
79892
80303
|
import fs25 from "node:fs";
|
|
79893
|
-
import
|
|
80304
|
+
import path48 from "node:path";
|
|
79894
80305
|
function forgeFor(io, offline) {
|
|
79895
80306
|
if (offline)
|
|
79896
80307
|
return { forge: null, error: "--offline" };
|
|
@@ -79951,7 +80362,7 @@ function plan2(argv, io) {
|
|
|
79951
80362
|
return usage3(io, "pass --trunk or --track, not both (--track picks the trunk)", PLAN_USAGE2);
|
|
79952
80363
|
if (flags.positionals.length !== 1)
|
|
79953
80364
|
return usage3(io, flags.positionals.length ? `unexpected argument ${flags.positionals[1]}` : "missing <plan.json>", PLAN_USAGE2);
|
|
79954
|
-
const file =
|
|
80365
|
+
const file = path48.resolve(io.cwd, flags.positionals[0]);
|
|
79955
80366
|
let raw;
|
|
79956
80367
|
try {
|
|
79957
80368
|
raw = JSON.parse(fs25.readFileSync(file, "utf8"));
|
|
@@ -80107,7 +80518,7 @@ function worktree(argv, io) {
|
|
|
80107
80518
|
...data.notes.map((note) => `note: ${note}`)
|
|
80108
80519
|
]);
|
|
80109
80520
|
}
|
|
80110
|
-
async function
|
|
80521
|
+
async function run16(argv, io) {
|
|
80111
80522
|
const [sub, ...rest] = argv.filter((arg) => arg !== "--json");
|
|
80112
80523
|
if (sub === "plan")
|
|
80113
80524
|
return plan2(rest, io);
|
|
@@ -80173,7 +80584,7 @@ var init_fanout2 = __esm(() => {
|
|
|
80173
80584
|
// packages/workit-cli/src/verbs/ledger.ts
|
|
80174
80585
|
var exports_ledger = {};
|
|
80175
80586
|
__export(exports_ledger, {
|
|
80176
|
-
run: () =>
|
|
80587
|
+
run: () => run17
|
|
80177
80588
|
});
|
|
80178
80589
|
import { randomBytes as randomBytes5 } from "node:crypto";
|
|
80179
80590
|
import { parseArgs } from "node:util";
|
|
@@ -80197,7 +80608,7 @@ function targetBranch(io, rows, branch, pr) {
|
|
|
80197
80608
|
}
|
|
80198
80609
|
return { ok: true, value: branch ?? null };
|
|
80199
80610
|
}
|
|
80200
|
-
async function
|
|
80611
|
+
async function run17(argv, io) {
|
|
80201
80612
|
let parsed;
|
|
80202
80613
|
try {
|
|
80203
80614
|
parsed = parseArgs({ args: argv, options: OPTIONS, allowPositionals: true, strict: true });
|
|
@@ -95434,7 +95845,7 @@ var init_ast = __esm(() => {
|
|
|
95434
95845
|
|
|
95435
95846
|
// packages/workit-cli/src/test-audit/rules.ts
|
|
95436
95847
|
import { builtinModules } from "node:module";
|
|
95437
|
-
import
|
|
95848
|
+
import path49 from "node:path";
|
|
95438
95849
|
function testCallee(call) {
|
|
95439
95850
|
let callee = call.callee;
|
|
95440
95851
|
if (callee.type === "CallExpression")
|
|
@@ -95927,12 +96338,12 @@ function checkConstantsOnly(ctx, emit) {
|
|
|
95927
96338
|
}
|
|
95928
96339
|
function checkOverMocking(ctx, emit) {
|
|
95929
96340
|
const { program } = ctx.parsed;
|
|
95930
|
-
const unit =
|
|
96341
|
+
const unit = path49.basename(ctx.file).replace(/\.(?:[cm]?[jt]sx?)$/, "").replace(/\.(?:test|spec)$/, "");
|
|
95931
96342
|
const mocked = find2(program, (node) => node.type === "CallExpression" && MODULE_MOCK.test(calleeName(node.callee) ?? "") && node.arguments[0]?.type === "StringLiteral");
|
|
95932
96343
|
const internal = mocked.filter((call) => /^(?:\.|@\/|~\/)/.test(call.arguments[0].value));
|
|
95933
96344
|
for (const call of mocked) {
|
|
95934
96345
|
const spec = call.arguments[0].value;
|
|
95935
|
-
const base =
|
|
96346
|
+
const base = path49.basename(spec.replace(/\/index(?:\.[cm]?[jt]sx?)?$/, "")).replace(/\.(?:[cm]?[jt]sx?)$/, "");
|
|
95936
96347
|
if (base === unit)
|
|
95937
96348
|
emit({
|
|
95938
96349
|
rule: "over-mocking",
|
|
@@ -96320,11 +96731,11 @@ var init_rules = __esm(() => {
|
|
|
96320
96731
|
});
|
|
96321
96732
|
|
|
96322
96733
|
// packages/workit-cli/src/test-audit/audit.ts
|
|
96323
|
-
import { spawnSync as
|
|
96324
|
-
import { existsSync as
|
|
96325
|
-
import
|
|
96734
|
+
import { spawnSync as spawnSync26 } from "node:child_process";
|
|
96735
|
+
import { existsSync as existsSync20, readdirSync as readdirSync9, readFileSync as readFileSync23, statSync as statSync8 } from "node:fs";
|
|
96736
|
+
import path50 from "node:path";
|
|
96326
96737
|
function git7(cwd, args) {
|
|
96327
|
-
const run =
|
|
96738
|
+
const run = spawnSync26("git", ["-c", "core.quotepath=off", ...args], {
|
|
96328
96739
|
cwd,
|
|
96329
96740
|
encoding: "utf8",
|
|
96330
96741
|
maxBuffer: 64 * 1024 * 1024
|
|
@@ -96335,7 +96746,7 @@ function walkTests(dir, out) {
|
|
|
96335
96746
|
for (const entry of readdirSync9(dir, { withFileTypes: true })) {
|
|
96336
96747
|
if (entry.name.startsWith(".") && entry.name !== "." && entry.isDirectory())
|
|
96337
96748
|
continue;
|
|
96338
|
-
const full =
|
|
96749
|
+
const full = path50.join(dir, entry.name);
|
|
96339
96750
|
if (entry.isDirectory()) {
|
|
96340
96751
|
if (!SKIP_DIRS.has(entry.name))
|
|
96341
96752
|
walkTests(full, out);
|
|
@@ -96347,10 +96758,10 @@ function expandPaths(cwd, inputs) {
|
|
|
96347
96758
|
const files = [];
|
|
96348
96759
|
const missing = [];
|
|
96349
96760
|
for (const input of inputs.length > 0 ? inputs : ["."]) {
|
|
96350
|
-
const full =
|
|
96351
|
-
if (!
|
|
96761
|
+
const full = path50.resolve(cwd, input);
|
|
96762
|
+
if (!existsSync20(full))
|
|
96352
96763
|
missing.push(input);
|
|
96353
|
-
else if (
|
|
96764
|
+
else if (statSync8(full).isDirectory())
|
|
96354
96765
|
walkTests(full, files);
|
|
96355
96766
|
else
|
|
96356
96767
|
files.push(full);
|
|
@@ -96384,11 +96795,11 @@ function changedLines(cwd, base) {
|
|
|
96384
96795
|
for (let offset = 0;offset < count; offset += 1)
|
|
96385
96796
|
lines.add(start + offset);
|
|
96386
96797
|
}
|
|
96387
|
-
changed.set(
|
|
96798
|
+
changed.set(path50.join(root, file), lines);
|
|
96388
96799
|
}
|
|
96389
96800
|
const untracked = git7(root, ["ls-files", "--others", "--exclude-standard", "-z"]);
|
|
96390
96801
|
for (const file of untracked.stdout.split("\x00").filter(Boolean))
|
|
96391
|
-
changed.set(
|
|
96802
|
+
changed.set(path50.join(root, file), "all");
|
|
96392
96803
|
return changed;
|
|
96393
96804
|
}
|
|
96394
96805
|
function auditFiles(files, display) {
|
|
@@ -96401,7 +96812,7 @@ function auditFiles(files, display) {
|
|
|
96401
96812
|
const shown = display(file);
|
|
96402
96813
|
let parsed;
|
|
96403
96814
|
try {
|
|
96404
|
-
parsed = parseSource(
|
|
96815
|
+
parsed = parseSource(readFileSync23(file, "utf8"), file);
|
|
96405
96816
|
} catch (error) {
|
|
96406
96817
|
parseErrors.push({
|
|
96407
96818
|
file: shown,
|
|
@@ -96450,7 +96861,7 @@ function auditFiles(files, display) {
|
|
|
96450
96861
|
durationMs: Math.round(performance.now() - started)
|
|
96451
96862
|
};
|
|
96452
96863
|
}
|
|
96453
|
-
var TEST_FILE, CODE_FILE, SKIP_DIRS, toPosix = (file) => file.split(
|
|
96864
|
+
var TEST_FILE, CODE_FILE, SKIP_DIRS, toPosix = (file) => file.split(path50.sep).join("/"), SEVERITY_ORDER, ruleIds;
|
|
96454
96865
|
var init_audit = __esm(() => {
|
|
96455
96866
|
init_ast();
|
|
96456
96867
|
init_rules();
|
|
@@ -96464,23 +96875,23 @@ var init_audit = __esm(() => {
|
|
|
96464
96875
|
// packages/workit-cli/src/test-audit/mutate.ts
|
|
96465
96876
|
import { spawn as spawn2 } from "node:child_process";
|
|
96466
96877
|
import {
|
|
96467
|
-
existsSync as
|
|
96468
|
-
lstatSync as
|
|
96469
|
-
mkdirSync as
|
|
96878
|
+
existsSync as existsSync21,
|
|
96879
|
+
lstatSync as lstatSync8,
|
|
96880
|
+
mkdirSync as mkdirSync10,
|
|
96470
96881
|
mkdtempSync as mkdtempSync4,
|
|
96471
96882
|
readdirSync as readdirSync10,
|
|
96472
|
-
readFileSync as
|
|
96883
|
+
readFileSync as readFileSync24,
|
|
96473
96884
|
readlinkSync as readlinkSync3,
|
|
96474
96885
|
realpathSync as realpathSync9,
|
|
96475
|
-
renameSync as
|
|
96476
|
-
rmSync as
|
|
96477
|
-
statSync as
|
|
96886
|
+
renameSync as renameSync6,
|
|
96887
|
+
rmSync as rmSync8,
|
|
96888
|
+
statSync as statSync9,
|
|
96478
96889
|
symlinkSync,
|
|
96479
|
-
writeFileSync as
|
|
96890
|
+
writeFileSync as writeFileSync11,
|
|
96480
96891
|
copyFileSync as copyFileSync6
|
|
96481
96892
|
} from "node:fs";
|
|
96482
96893
|
import os14 from "node:os";
|
|
96483
|
-
import
|
|
96894
|
+
import path51 from "node:path";
|
|
96484
96895
|
function mutantsFor(source, file, lines) {
|
|
96485
96896
|
const parsed = parseSource(source, file);
|
|
96486
96897
|
const out = [];
|
|
@@ -96553,7 +96964,7 @@ function relatedTests(source, testFiles) {
|
|
|
96553
96964
|
for (const match of text.matchAll(SPECIFIER)) {
|
|
96554
96965
|
const spec = match[1];
|
|
96555
96966
|
if (spec.startsWith(".")) {
|
|
96556
|
-
if (stripExt(
|
|
96967
|
+
if (stripExt(path51.posix.join(path51.posix.dirname(file), spec)) === target)
|
|
96557
96968
|
return true;
|
|
96558
96969
|
} else if (spec.includes("/") && stripExt(spec).split("/").slice(-2).join("/") === tail)
|
|
96559
96970
|
return true;
|
|
@@ -96573,12 +96984,12 @@ function removeStaleCopies(tmp = os14.tmpdir()) {
|
|
|
96573
96984
|
for (const name of names) {
|
|
96574
96985
|
if (!name.startsWith(TEMP_PREFIX))
|
|
96575
96986
|
continue;
|
|
96576
|
-
const dir =
|
|
96987
|
+
const dir = path51.join(tmp, name);
|
|
96577
96988
|
try {
|
|
96578
|
-
const stat =
|
|
96989
|
+
const stat = lstatSync8(dir);
|
|
96579
96990
|
if (!stat.isDirectory() || uid !== undefined && stat.uid !== uid)
|
|
96580
96991
|
continue;
|
|
96581
|
-
const pid = Number(
|
|
96992
|
+
const pid = Number(readFileSync24(path51.join(dir, PID_FILE), "utf8"));
|
|
96582
96993
|
if (Number.isInteger(pid) && pid > 0 && alive(pid))
|
|
96583
96994
|
continue;
|
|
96584
96995
|
} catch (error) {
|
|
@@ -96586,23 +96997,23 @@ function removeStaleCopies(tmp = os14.tmpdir()) {
|
|
|
96586
96997
|
continue;
|
|
96587
96998
|
}
|
|
96588
96999
|
try {
|
|
96589
|
-
|
|
97000
|
+
rmSync8(dir, { recursive: true, force: true });
|
|
96590
97001
|
removed += 1;
|
|
96591
97002
|
} catch {}
|
|
96592
97003
|
}
|
|
96593
97004
|
return removed;
|
|
96594
97005
|
}
|
|
96595
97006
|
function linkNodeModules(origin, target, repo, copy) {
|
|
96596
|
-
|
|
97007
|
+
mkdirSync10(target, { recursive: true });
|
|
96597
97008
|
for (const entry of readdirSync10(origin, { withFileTypes: true })) {
|
|
96598
|
-
const from =
|
|
96599
|
-
const to =
|
|
97009
|
+
const from = path51.join(origin, entry.name);
|
|
97010
|
+
const to = path51.join(target, entry.name);
|
|
96600
97011
|
if (entry.name.startsWith("@") && entry.isDirectory()) {
|
|
96601
97012
|
linkNodeModules(from, to, repo, copy);
|
|
96602
97013
|
continue;
|
|
96603
97014
|
}
|
|
96604
97015
|
if (entry.name.startsWith(".") && entry.name !== ".bin" && entry.isDirectory()) {
|
|
96605
|
-
|
|
97016
|
+
mkdirSync10(to, { recursive: true });
|
|
96606
97017
|
continue;
|
|
96607
97018
|
}
|
|
96608
97019
|
if (entry.isSymbolicLink()) {
|
|
@@ -96612,9 +97023,9 @@ function linkNodeModules(origin, target, repo, copy) {
|
|
|
96612
97023
|
} catch {
|
|
96613
97024
|
continue;
|
|
96614
97025
|
}
|
|
96615
|
-
const relative =
|
|
96616
|
-
if (!relative.startsWith("..") && !
|
|
96617
|
-
symlinkSync(
|
|
97026
|
+
const relative = path51.relative(repo, real);
|
|
97027
|
+
if (!relative.startsWith("..") && !path51.isAbsolute(relative) && !relative.split(path51.sep).includes("node_modules")) {
|
|
97028
|
+
symlinkSync(path51.join(copy, relative), to, "junction");
|
|
96618
97029
|
continue;
|
|
96619
97030
|
}
|
|
96620
97031
|
}
|
|
@@ -96629,33 +97040,33 @@ function copySymlink(repo, tree, from, to) {
|
|
|
96629
97040
|
real = null;
|
|
96630
97041
|
}
|
|
96631
97042
|
const realRepo = realpathSync9(repo);
|
|
96632
|
-
if (real &&
|
|
96633
|
-
symlinkSync(
|
|
97043
|
+
if (real && inside4(realRepo, real)) {
|
|
97044
|
+
symlinkSync(path51.relative(path51.dirname(to), path51.join(tree, path51.relative(realRepo, real))), to);
|
|
96634
97045
|
return;
|
|
96635
97046
|
}
|
|
96636
|
-
if (real &&
|
|
97047
|
+
if (real && statSync9(real).isFile())
|
|
96637
97048
|
copyFileSync6(real, to);
|
|
96638
97049
|
else
|
|
96639
97050
|
symlinkSync(readlinkSync3(from), to);
|
|
96640
97051
|
}
|
|
96641
97052
|
function writeInside(copy, file, content) {
|
|
96642
|
-
const target =
|
|
97053
|
+
const target = path51.join(copy, file);
|
|
96643
97054
|
try {
|
|
96644
|
-
const stat =
|
|
96645
|
-
if (!stat.isFile() || !
|
|
97055
|
+
const stat = lstatSync8(target);
|
|
97056
|
+
if (!stat.isFile() || !inside4(realpathSync9(copy), realpathSync9(path51.dirname(target))))
|
|
96646
97057
|
return false;
|
|
96647
97058
|
} catch {
|
|
96648
97059
|
return false;
|
|
96649
97060
|
}
|
|
96650
97061
|
const temp = `${target}.workit-mutant-${process.pid}`;
|
|
96651
|
-
|
|
96652
|
-
|
|
97062
|
+
writeFileSync11(temp, content);
|
|
97063
|
+
renameSync6(temp, target);
|
|
96653
97064
|
return true;
|
|
96654
97065
|
}
|
|
96655
97066
|
function copyWorkingTree(repo) {
|
|
96656
|
-
const dir = mkdtempSync4(
|
|
96657
|
-
|
|
96658
|
-
const tree =
|
|
97067
|
+
const dir = mkdtempSync4(path51.join(os14.tmpdir(), TEMP_PREFIX));
|
|
97068
|
+
writeFileSync11(path51.join(dir, PID_FILE), String(process.pid));
|
|
97069
|
+
const tree = path51.join(dir, "tree");
|
|
96659
97070
|
const head = git7(repo, ["rev-parse", "--verify", "--quiet", "HEAD"]).stdout.trim();
|
|
96660
97071
|
if (head && git7(dir, ["clone", "-q", "--shared", "--no-checkout", repo, tree]).ok) {
|
|
96661
97072
|
const branch = git7(repo, ["symbolic-ref", "--quiet", "--short", "HEAD"]).stdout.trim();
|
|
@@ -96666,35 +97077,35 @@ function copyWorkingTree(repo) {
|
|
|
96666
97077
|
git7(tree, ["update-ref", "--no-deref", "HEAD", head]);
|
|
96667
97078
|
git7(tree, ["reset", "-q"]);
|
|
96668
97079
|
} else
|
|
96669
|
-
|
|
97080
|
+
mkdirSync10(tree, { recursive: true });
|
|
96670
97081
|
const listed = git7(repo, ["ls-files", "-co", "--exclude-standard", "-z"]).stdout.split("\x00");
|
|
96671
97082
|
const dirs = new Set([""]);
|
|
96672
97083
|
for (const relative of listed) {
|
|
96673
97084
|
if (!relative)
|
|
96674
97085
|
continue;
|
|
96675
|
-
const from =
|
|
97086
|
+
const from = path51.join(repo, relative);
|
|
96676
97087
|
let stat;
|
|
96677
97088
|
try {
|
|
96678
|
-
stat =
|
|
97089
|
+
stat = lstatSync8(from);
|
|
96679
97090
|
} catch {
|
|
96680
97091
|
continue;
|
|
96681
97092
|
}
|
|
96682
|
-
const to =
|
|
96683
|
-
|
|
97093
|
+
const to = path51.join(tree, relative);
|
|
97094
|
+
mkdirSync10(path51.dirname(to), { recursive: true });
|
|
96684
97095
|
if (stat.isSymbolicLink())
|
|
96685
97096
|
copySymlink(repo, tree, from, to);
|
|
96686
97097
|
else if (stat.isFile())
|
|
96687
97098
|
copyFileSync6(from, to);
|
|
96688
|
-
let parent =
|
|
97099
|
+
let parent = path51.dirname(relative);
|
|
96689
97100
|
while (parent !== "." && !dirs.has(parent)) {
|
|
96690
97101
|
dirs.add(parent);
|
|
96691
|
-
parent =
|
|
97102
|
+
parent = path51.dirname(parent);
|
|
96692
97103
|
}
|
|
96693
97104
|
}
|
|
96694
97105
|
for (const parent of dirs) {
|
|
96695
|
-
const modules =
|
|
96696
|
-
if (
|
|
96697
|
-
linkNodeModules(modules,
|
|
97106
|
+
const modules = path51.join(repo, parent, "node_modules");
|
|
97107
|
+
if (existsSync21(modules) && !existsSync21(path51.join(tree, parent, "node_modules")))
|
|
97108
|
+
linkNodeModules(modules, path51.join(tree, parent, "node_modules"), repo, tree);
|
|
96698
97109
|
}
|
|
96699
97110
|
return { dir, tree };
|
|
96700
97111
|
}
|
|
@@ -96733,20 +97144,20 @@ async function runMutation(options) {
|
|
|
96733
97144
|
const tracked = git7(repo, ["ls-files", "-co", "--exclude-standard", "-z"]).stdout.split("\x00").filter(Boolean);
|
|
96734
97145
|
const testFiles = tracked.filter((file) => TEST_FILE.test(file)).map((file) => {
|
|
96735
97146
|
try {
|
|
96736
|
-
return { file, text:
|
|
97147
|
+
return { file, text: readFileSync24(path51.join(repo, file), "utf8") };
|
|
96737
97148
|
} catch {
|
|
96738
97149
|
return { file, text: "" };
|
|
96739
97150
|
}
|
|
96740
97151
|
});
|
|
96741
97152
|
const candidates = [];
|
|
96742
97153
|
for (const [absolute, lines] of [...options.changed].toSorted(([a], [b]) => a.localeCompare(b))) {
|
|
96743
|
-
const relative = toPosix(
|
|
97154
|
+
const relative = toPosix(path51.relative(repo, absolute));
|
|
96744
97155
|
if (!CODE_FILE.test(relative) || TEST_FILE.test(relative) || relative.endsWith(".d.ts"))
|
|
96745
97156
|
continue;
|
|
96746
|
-
if (NOT_SOURCE.test(relative) || !
|
|
97157
|
+
if (NOT_SOURCE.test(relative) || !existsSync21(absolute))
|
|
96747
97158
|
continue;
|
|
96748
97159
|
try {
|
|
96749
|
-
candidates.push(...mutantsFor(
|
|
97160
|
+
candidates.push(...mutantsFor(readFileSync24(absolute, "utf8"), relative, lines));
|
|
96750
97161
|
} catch {}
|
|
96751
97162
|
}
|
|
96752
97163
|
const mutants = candidates.map((mutant, index) => ({ ...mutant, id: index + 1 }));
|
|
@@ -96754,9 +97165,9 @@ async function runMutation(options) {
|
|
|
96754
97165
|
for (const mutant of mutants)
|
|
96755
97166
|
if (!related.has(mutant.file))
|
|
96756
97167
|
related.set(mutant.file, relatedTests(mutant.file, testFiles));
|
|
96757
|
-
const cwdRelative =
|
|
97168
|
+
const cwdRelative = path51.relative(repo, options.cwd);
|
|
96758
97169
|
const asArg = (file) => {
|
|
96759
|
-
const relative = toPosix(
|
|
97170
|
+
const relative = toPosix(path51.relative(cwdRelative, file));
|
|
96760
97171
|
return shellQuote(relative.startsWith(".") ? relative : `./${relative}`);
|
|
96761
97172
|
};
|
|
96762
97173
|
const commandFor = (tests) => options.command.replaceAll("{files}", () => tests.map(asArg).join(" "));
|
|
@@ -96791,7 +97202,7 @@ async function runMutation(options) {
|
|
|
96791
97202
|
return finish2(options, 0, results, counts, started);
|
|
96792
97203
|
removeStaleCopies();
|
|
96793
97204
|
const { dir: copyDir, tree: copy } = copyWorkingTree(repo);
|
|
96794
|
-
const copyCwd =
|
|
97205
|
+
const copyCwd = path51.join(copy, cwdRelative);
|
|
96795
97206
|
let current = null;
|
|
96796
97207
|
const restore = () => {
|
|
96797
97208
|
if (current)
|
|
@@ -96802,7 +97213,7 @@ async function runMutation(options) {
|
|
|
96802
97213
|
for (const child of active)
|
|
96803
97214
|
killTree(child);
|
|
96804
97215
|
restore();
|
|
96805
|
-
|
|
97216
|
+
rmSync8(copyDir, { recursive: true, force: true });
|
|
96806
97217
|
};
|
|
96807
97218
|
const onSignal = (signal) => {
|
|
96808
97219
|
cleanup();
|
|
@@ -96826,7 +97237,7 @@ async function runMutation(options) {
|
|
|
96826
97237
|
record({ ...mutant, status: "skipped", durationMs: 0, tests, reason: "budget" });
|
|
96827
97238
|
continue;
|
|
96828
97239
|
}
|
|
96829
|
-
const original =
|
|
97240
|
+
const original = readFileSync24(path51.join(copy, mutant.file), "utf8");
|
|
96830
97241
|
const mutated = original.slice(0, mutant.start) + mutant.replacement + original.slice(mutant.end);
|
|
96831
97242
|
current = { file: mutant.file, original };
|
|
96832
97243
|
if (!writeInside(copy, mutant.file, mutated)) {
|
|
@@ -96882,9 +97293,9 @@ var NOT_SOURCE, FLIPS, isStringy = (node) => node.type === "StringLiteral" || no
|
|
|
96882
97293
|
} catch (error) {
|
|
96883
97294
|
return error.code === "EPERM";
|
|
96884
97295
|
}
|
|
96885
|
-
},
|
|
96886
|
-
const relative =
|
|
96887
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
97296
|
+
}, inside4 = (root, file) => {
|
|
97297
|
+
const relative = path51.relative(root, file);
|
|
97298
|
+
return relative === "" || !relative.startsWith("..") && !path51.isAbsolute(relative);
|
|
96888
97299
|
}, active, killTree = (child) => {
|
|
96889
97300
|
try {
|
|
96890
97301
|
if (child.pid && process.platform !== "win32")
|
|
@@ -96930,10 +97341,10 @@ var init_mutate = __esm(() => {
|
|
|
96930
97341
|
// packages/workit-cli/src/verbs/test-audit.ts
|
|
96931
97342
|
var exports_test_audit = {};
|
|
96932
97343
|
__export(exports_test_audit, {
|
|
96933
|
-
run: () =>
|
|
97344
|
+
run: () => run18
|
|
96934
97345
|
});
|
|
96935
|
-
import { existsSync as
|
|
96936
|
-
import
|
|
97346
|
+
import { existsSync as existsSync22 } from "node:fs";
|
|
97347
|
+
import path52 from "node:path";
|
|
96937
97348
|
function parse7(argv) {
|
|
96938
97349
|
const options = {
|
|
96939
97350
|
paths: [],
|
|
@@ -97031,14 +97442,14 @@ function human(data) {
|
|
|
97031
97442
|
}
|
|
97032
97443
|
return lines;
|
|
97033
97444
|
}
|
|
97034
|
-
async function
|
|
97445
|
+
async function run18(argv, io) {
|
|
97035
97446
|
const options = parse7(argv);
|
|
97036
97447
|
if (typeof options === "string")
|
|
97037
97448
|
return emit(io, fail("invalid_input", `${options}
|
|
97038
97449
|
usage: ${USAGE10}`));
|
|
97039
97450
|
const top = git7(io.cwd, ["rev-parse", "--show-toplevel"]);
|
|
97040
|
-
const repo = top.ok ?
|
|
97041
|
-
const display = (file) => toPosix(
|
|
97451
|
+
const repo = top.ok ? path52.resolve(top.stdout.trim()) : null;
|
|
97452
|
+
const display = (file) => toPosix(path52.relative(io.cwd, file) || file);
|
|
97042
97453
|
let base = null;
|
|
97043
97454
|
let changed = null;
|
|
97044
97455
|
if (options.diff || options.mutate) {
|
|
@@ -97055,7 +97466,7 @@ usage: ${USAGE10}`));
|
|
|
97055
97466
|
}
|
|
97056
97467
|
let files;
|
|
97057
97468
|
if (options.diff && changed)
|
|
97058
|
-
files = [...changed.keys()].filter((file) => TEST_FILE.test(toPosix(file)) &&
|
|
97469
|
+
files = [...changed.keys()].filter((file) => TEST_FILE.test(toPosix(file)) && existsSync22(file)).toSorted();
|
|
97059
97470
|
else {
|
|
97060
97471
|
const expanded = expandPaths(io.cwd, options.paths);
|
|
97061
97472
|
if (expanded.missing.length > 0)
|
|
@@ -97142,9 +97553,9 @@ var init_test_audit = __esm(() => {
|
|
|
97142
97553
|
// packages/workit-cli/src/verbs/knowledge.ts
|
|
97143
97554
|
var exports_knowledge = {};
|
|
97144
97555
|
__export(exports_knowledge, {
|
|
97145
|
-
run: () =>
|
|
97556
|
+
run: () => run19
|
|
97146
97557
|
});
|
|
97147
|
-
async function
|
|
97558
|
+
async function run19(argv, io) {
|
|
97148
97559
|
const [sub, ...rest] = argv.filter((arg) => arg !== "--json");
|
|
97149
97560
|
if (sub !== "lint" || rest.length > 0)
|
|
97150
97561
|
return emit(io, fail("invalid_input", `usage: ${USAGE11}`));
|
|
@@ -97278,11 +97689,11 @@ var init_youtrack_writes = __esm(() => {
|
|
|
97278
97689
|
// packages/workit-cli/src/verbs/youtrack.ts
|
|
97279
97690
|
var exports_youtrack = {};
|
|
97280
97691
|
__export(exports_youtrack, {
|
|
97281
|
-
run: () =>
|
|
97692
|
+
run: () => run20
|
|
97282
97693
|
});
|
|
97283
|
-
import { readFileSync as
|
|
97284
|
-
import
|
|
97285
|
-
async function
|
|
97694
|
+
import { readFileSync as readFileSync25 } from "node:fs";
|
|
97695
|
+
import path53 from "node:path";
|
|
97696
|
+
async function run20(argv, io) {
|
|
97286
97697
|
const [sub, ...rest] = argv;
|
|
97287
97698
|
if (sub !== "note" && sub !== "time" && sub !== "meeting")
|
|
97288
97699
|
return usage3(io, `unknown subcommand "${sub ?? ""}"`, USAGE12);
|
|
@@ -97327,7 +97738,7 @@ async function run19(argv, io) {
|
|
|
97327
97738
|
let markdown = flags.values.markdown ?? "";
|
|
97328
97739
|
if (flags.values.file)
|
|
97329
97740
|
try {
|
|
97330
|
-
markdown =
|
|
97741
|
+
markdown = readFileSync25(path53.resolve(io.cwd, flags.values.file), "utf8");
|
|
97331
97742
|
} catch (error) {
|
|
97332
97743
|
return usage3(io, `cannot read ${flags.values.file}: ${String(error)}`, USAGE12);
|
|
97333
97744
|
}
|
|
@@ -97393,11 +97804,11 @@ var init_youtrack2 = __esm(() => {
|
|
|
97393
97804
|
// packages/workit-cli/src/verbs/changelog.ts
|
|
97394
97805
|
var exports_changelog = {};
|
|
97395
97806
|
__export(exports_changelog, {
|
|
97396
|
-
run: () =>
|
|
97807
|
+
run: () => run21
|
|
97397
97808
|
});
|
|
97398
|
-
import { readFileSync as
|
|
97399
|
-
import
|
|
97400
|
-
async function
|
|
97809
|
+
import { readFileSync as readFileSync26 } from "node:fs";
|
|
97810
|
+
import path54 from "node:path";
|
|
97811
|
+
async function run21(argv, io) {
|
|
97401
97812
|
const [sub, ...rest] = argv;
|
|
97402
97813
|
if (sub !== "apply")
|
|
97403
97814
|
return usage3(io, `unknown subcommand "${sub ?? ""}"`, USAGE13);
|
|
@@ -97442,7 +97853,7 @@ async function run20(argv, io) {
|
|
|
97442
97853
|
]);
|
|
97443
97854
|
}
|
|
97444
97855
|
var USAGE13 = "workit changelog apply (--entries <JSON|@file|-> | --normalize-only) [--path CHANGELOG.md] [--preview]", readEntries = (raw, cwd) => {
|
|
97445
|
-
const text = raw === "-" ?
|
|
97856
|
+
const text = raw === "-" ? readFileSync26(0, "utf8") : raw.startsWith("@") ? readFileSync26(path54.resolve(cwd, raw.slice(1)), "utf8") : raw;
|
|
97446
97857
|
return JSON.parse(text);
|
|
97447
97858
|
};
|
|
97448
97859
|
var init_changelog2 = __esm(() => {
|
|
@@ -97454,7 +97865,7 @@ var init_changelog2 = __esm(() => {
|
|
|
97454
97865
|
// packages/workit-cli/src/verbs/handoff.ts
|
|
97455
97866
|
var exports_handoff = {};
|
|
97456
97867
|
__export(exports_handoff, {
|
|
97457
|
-
run: () =>
|
|
97868
|
+
run: () => run22
|
|
97458
97869
|
});
|
|
97459
97870
|
import { parseArgs as parseArgs2 } from "node:util";
|
|
97460
97871
|
function human2(brief) {
|
|
@@ -97524,7 +97935,7 @@ async function resumeBrief(argv, io) {
|
|
|
97524
97935
|
}
|
|
97525
97936
|
return emit(io, ok({ ...data, recorded }), human2);
|
|
97526
97937
|
}
|
|
97527
|
-
async function
|
|
97938
|
+
async function run22(argv, io) {
|
|
97528
97939
|
if (!argv.some((arg) => arg === "--task" || arg.startsWith("--task=")))
|
|
97529
97940
|
return resumeBrief(argv, io);
|
|
97530
97941
|
await Promise.resolve().then(() => init_task());
|
|
@@ -97538,7 +97949,7 @@ var init_handoff = __esm(() => {
|
|
|
97538
97949
|
|
|
97539
97950
|
// packages/workit-cli/src/main.ts
|
|
97540
97951
|
init_package();
|
|
97541
|
-
import
|
|
97952
|
+
import path55 from "node:path";
|
|
97542
97953
|
|
|
97543
97954
|
// packages/workit-cli/src/help.ts
|
|
97544
97955
|
var HELP_FLAGS = new Set(["--help", "-h"]);
|
|
@@ -97757,8 +98168,8 @@ var VERBS = [
|
|
|
97757
98168
|
{
|
|
97758
98169
|
name: "doctor",
|
|
97759
98170
|
group: "setup",
|
|
97760
|
-
usage: "workit doctor [--fix-lock [--force [--yes]]]",
|
|
97761
|
-
summary: "Verify the offline installation health (--fix-lock clears a stale workit store lock)",
|
|
98171
|
+
usage: "workit doctor [--fix] [--fix-lock [--force [--yes]]]",
|
|
98172
|
+
summary: "Verify the offline installation health (--fix installs the session trailer hook; --fix-lock clears a stale workit store lock)",
|
|
97762
98173
|
load: () => Promise.resolve().then(() => (init_doctor2(), exports_doctor))
|
|
97763
98174
|
},
|
|
97764
98175
|
{
|
|
@@ -98184,7 +98595,7 @@ var defaultIo = (json) => ({
|
|
|
98184
98595
|
});
|
|
98185
98596
|
async function main(argv, overrides = {}, options = {}) {
|
|
98186
98597
|
const parsed = parseGlobals(argv);
|
|
98187
|
-
const cwd =
|
|
98598
|
+
const cwd = path55.resolve(overrides.cwd ?? process.cwd(), parsed.cwd ?? ".");
|
|
98188
98599
|
const io = { ...defaultIo(parsed.json), ...overrides, json: parsed.json, cwd };
|
|
98189
98600
|
if (parsed.error)
|
|
98190
98601
|
return emit(io, fail("invalid_input", parsed.error));
|