@brainervirus/workit-cli 8.7.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 +1023 -570
- 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"
|
|
@@ -15136,6 +15136,9 @@ function summarizeRow(row) {
|
|
|
15136
15136
|
case "pr.created":
|
|
15137
15137
|
summary = `#${row.pr ?? "?"} -> ${text("base")} at ${(row.head ?? "?").slice(0, 12)}${row.created === false ? " (existing)" : ""}`;
|
|
15138
15138
|
break;
|
|
15139
|
+
case "pr.status":
|
|
15140
|
+
summary = `#${row.pr ?? "?"} ${text("state") && text("state") !== "open" ? `${text("state")} ` : ""}checks ${text("checks") || "?"} at ${(row.head ?? "?").slice(0, 12)}`;
|
|
15141
|
+
break;
|
|
15139
15142
|
case "pr.merged":
|
|
15140
15143
|
summary = `#${row.pr ?? "?"} ${text("method")} at ${(row.head ?? "?").slice(0, 12)}${text("mergeSha") ? ` -> ${text("mergeSha").slice(0, 12)}` : ""}`;
|
|
15141
15144
|
break;
|
|
@@ -63192,7 +63195,7 @@ function cursorHookDrift(installed, pluginDir) {
|
|
|
63192
63195
|
if (pluginDir)
|
|
63193
63196
|
commands.push(canonicalHookEntry(event, pluginDir).command);
|
|
63194
63197
|
const entry = Array.isArray(list) ? list[0] : undefined;
|
|
63195
|
-
if (!isRecord4(entry) || !commands.includes(entry.command) || entry.failClosed === true || event === "preToolUse" && entry.matcher !== canonical.matcher)
|
|
63198
|
+
if (!isRecord4(entry) || !commands.includes(entry.command) || entry.failClosed === true || event === "stop" && entry.loop_limit !== canonical.loop_limit || event === "preToolUse" && entry.matcher !== canonical.matcher)
|
|
63196
63199
|
drift.push(event);
|
|
63197
63200
|
}
|
|
63198
63201
|
return drift;
|
|
@@ -63215,7 +63218,11 @@ function cursorHooksEntry(pluginDir) {
|
|
|
63215
63218
|
}
|
|
63216
63219
|
var OPENCODE_NPM_PIN = "@brainervirus/workit-opencode", isRecord4 = (v) => v !== null && typeof v === "object" && !Array.isArray(v), named = (s, name) => s === name || s.startsWith(`${name}@`), CURSOR_RUNTIME_PACKAGE = "@brainervirus/workit-cursor@latest", cursorHookLauncher = (pluginDir) => pluginDir ? `node "${shellQuotedPath(path26.join(pluginDir, "hooks", "launch.mjs"))}"` : 'node "${CURSOR_PLUGIN_ROOT}/hooks/launch.mjs"', shellQuotedPath = (file) => path26.sep === "\\" ? file : file.replace(/([$`"\\])/g, "\\$1"), CURSOR_HOOK_RUN_COMMAND, CURSOR_PRETOOLUSE_MATCHER = "Write|Edit|Delete|Shell|Remove|ApplyPatch|Apply_Patch|Patch|Rename|Mkdir|Mv|Cp|Touch", CURSOR_HOOK_EVENTS, canonicalHookEntry = (event, pluginDir) => {
|
|
63217
63220
|
const command = `${cursorHookLauncher(pluginDir)} workit-cursor-hook`;
|
|
63218
|
-
|
|
63221
|
+
if (event === "preToolUse")
|
|
63222
|
+
return { command, matcher: CURSOR_PRETOOLUSE_MATCHER, failClosed: false };
|
|
63223
|
+
if (event === "stop")
|
|
63224
|
+
return { command, loop_limit: 1, failClosed: false };
|
|
63225
|
+
return { command, failClosed: false };
|
|
63219
63226
|
};
|
|
63220
63227
|
var init_registration = __esm(() => {
|
|
63221
63228
|
CURSOR_HOOK_RUN_COMMAND = `${cursorHookLauncher()} workit-cursor-hook`;
|
|
@@ -63224,6 +63231,7 @@ var init_registration = __esm(() => {
|
|
|
63224
63231
|
"beforeShellExecution",
|
|
63225
63232
|
"subagentStart",
|
|
63226
63233
|
"subagentStop",
|
|
63234
|
+
"stop",
|
|
63227
63235
|
"preCompact"
|
|
63228
63236
|
];
|
|
63229
63237
|
});
|
|
@@ -63930,30 +63938,353 @@ var init_skill_manifests = __esm(() => {
|
|
|
63930
63938
|
if (false) {}
|
|
63931
63939
|
});
|
|
63932
63940
|
|
|
63933
|
-
// packages/workit-
|
|
63941
|
+
// packages/workit-core/src/git/session-hook.ts
|
|
63934
63942
|
import { spawnSync as spawnSync13 } from "node:child_process";
|
|
63935
|
-
import { createHash as createHash13 } from "node:crypto";
|
|
63936
63943
|
import {
|
|
63944
|
+
chmodSync,
|
|
63937
63945
|
existsSync as existsSync13,
|
|
63938
63946
|
lstatSync as lstatSync4,
|
|
63939
63947
|
mkdirSync as mkdirSync5,
|
|
63940
|
-
mkdtempSync,
|
|
63941
|
-
readdirSync as readdirSync7,
|
|
63942
63948
|
readFileSync as readFileSync13,
|
|
63943
|
-
|
|
63949
|
+
renameSync as renameSync3,
|
|
63944
63950
|
rmSync as rmSync2,
|
|
63945
63951
|
statSync as statSync4,
|
|
63946
|
-
unlinkSync as unlinkSync3,
|
|
63947
63952
|
writeFileSync as writeFileSync6
|
|
63948
63953
|
} from "node:fs";
|
|
63949
|
-
import os8 from "node:os";
|
|
63950
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";
|
|
63951
64282
|
var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
63952
|
-
let dir =
|
|
64283
|
+
let dir = path31.resolve(cwd);
|
|
63953
64284
|
while (true) {
|
|
63954
|
-
if (
|
|
64285
|
+
if (existsSync14(path31.join(dir, "packages", "workit-core", "package.json")))
|
|
63955
64286
|
return dir;
|
|
63956
|
-
const parent =
|
|
64287
|
+
const parent = path31.dirname(dir);
|
|
63957
64288
|
if (parent === dir)
|
|
63958
64289
|
return null;
|
|
63959
64290
|
dir = parent;
|
|
@@ -63961,8 +64292,8 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63961
64292
|
}, resolve = (options) => {
|
|
63962
64293
|
const env = options.env ?? process.env;
|
|
63963
64294
|
const home = options.home ?? env.HOME ?? os8.homedir();
|
|
63964
|
-
const configDir = options.configDir ?? env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ??
|
|
63965
|
-
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");
|
|
63966
64297
|
const cwd = options.cwd ?? process.cwd();
|
|
63967
64298
|
const dev = options.dev ?? env.WORKFLOW_TOOLKIT_DEV ?? findDevFromCwd(cwd);
|
|
63968
64299
|
return {
|
|
@@ -63973,11 +64304,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63973
64304
|
cwd,
|
|
63974
64305
|
workspaceRoot: options.workspaceRoot ?? env.WORKFLOW_WORKSPACE_ROOT ?? cwd,
|
|
63975
64306
|
dev,
|
|
63976
|
-
opencodeConfig: options.opencodeConfig ??
|
|
63977
|
-
opencodePackageCacheDir: options.opencodePackageCacheDir ??
|
|
63978
|
-
cursorSettings: options.cursorSettings ??
|
|
63979
|
-
cursorMcp: options.cursorMcp ??
|
|
63980
|
-
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"),
|
|
63981
64312
|
cursorHeartbeatDir: options.stateDir ?? (env.WORKFLOW_TOOLKIT_STATE || resolveStateDir()),
|
|
63982
64313
|
codexHome: options.codexHome,
|
|
63983
64314
|
piAgentDir: options.piAgentDir,
|
|
@@ -63987,14 +64318,14 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
63987
64318
|
};
|
|
63988
64319
|
}, readJson = (p) => {
|
|
63989
64320
|
try {
|
|
63990
|
-
const parsed = JSON.parse(
|
|
64321
|
+
const parsed = JSON.parse(readFileSync14(p, "utf8"));
|
|
63991
64322
|
return parsed !== null && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : null;
|
|
63992
64323
|
} catch {
|
|
63993
64324
|
return null;
|
|
63994
64325
|
}
|
|
63995
64326
|
}, parsesAsConfigObject = (p) => {
|
|
63996
64327
|
try {
|
|
63997
|
-
return isConfigObject(JSON.parse(
|
|
64328
|
+
return isConfigObject(JSON.parse(readFileSync14(p, "utf8")));
|
|
63998
64329
|
} catch {
|
|
63999
64330
|
return false;
|
|
64000
64331
|
}
|
|
@@ -64004,14 +64335,14 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64004
64335
|
...new Set(entries.filter((entry) => typeof entry === "string" && isWorkitPlugin(entry)))
|
|
64005
64336
|
];
|
|
64006
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) => {
|
|
64007
|
-
const dirs = (env.PATH ?? process.env.PATH ?? "").split(
|
|
64338
|
+
const dirs = (env.PATH ?? process.env.PATH ?? "").split(path31.delimiter);
|
|
64008
64339
|
for (const dir of dirs) {
|
|
64009
64340
|
if (!dir)
|
|
64010
64341
|
continue;
|
|
64011
64342
|
for (const candidateName of names) {
|
|
64012
|
-
const candidate =
|
|
64343
|
+
const candidate = path31.join(dir, candidateName);
|
|
64013
64344
|
try {
|
|
64014
|
-
const st =
|
|
64345
|
+
const st = statSync5(candidate);
|
|
64015
64346
|
if (process.platform !== "win32" && (st.mode & 73) === 0)
|
|
64016
64347
|
continue;
|
|
64017
64348
|
return candidate;
|
|
@@ -64020,7 +64351,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64020
64351
|
}
|
|
64021
64352
|
return null;
|
|
64022
64353
|
}, versionOf = (bin, env, timeout) => {
|
|
64023
|
-
const r =
|
|
64354
|
+
const r = spawnSync14(bin, ["--version"], { encoding: "utf8", env, timeout });
|
|
64024
64355
|
if (r.error)
|
|
64025
64356
|
return null;
|
|
64026
64357
|
return (r.stdout ?? "").trim();
|
|
@@ -64035,14 +64366,14 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64035
64366
|
}
|
|
64036
64367
|
return true;
|
|
64037
64368
|
}, resolveBun = (env) => {
|
|
64038
|
-
if (env.BUN &&
|
|
64369
|
+
if (env.BUN && existsSync14(env.BUN))
|
|
64039
64370
|
return env.BUN;
|
|
64040
64371
|
for (const candidate of [
|
|
64041
|
-
|
|
64372
|
+
path31.join(os8.homedir(), ".bun/bin/bun"),
|
|
64042
64373
|
"/usr/local/bin/bun",
|
|
64043
64374
|
"/usr/bin/bun"
|
|
64044
64375
|
]) {
|
|
64045
|
-
if (
|
|
64376
|
+
if (existsSync14(candidate))
|
|
64046
64377
|
return candidate;
|
|
64047
64378
|
}
|
|
64048
64379
|
return commandOnPath("bun", env) ? "bun" : null;
|
|
@@ -64090,7 +64421,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64090
64421
|
detail: "no dev checkout found (WORKFLOW_TOOLKIT_DEV) — skipping version parity"
|
|
64091
64422
|
};
|
|
64092
64423
|
}
|
|
64093
|
-
const corePkg = readJson(
|
|
64424
|
+
const corePkg = readJson(path31.join(res.dev, "packages/workit-core/package.json"));
|
|
64094
64425
|
if (!corePkg) {
|
|
64095
64426
|
return {
|
|
64096
64427
|
id: "versions",
|
|
@@ -64100,7 +64431,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64100
64431
|
}
|
|
64101
64432
|
const refs = new Set;
|
|
64102
64433
|
for (const name of ["workit-opencode", "workit-cursor", "workit-cli"]) {
|
|
64103
|
-
const pkg = readJson(
|
|
64434
|
+
const pkg = readJson(path31.join(res.dev, "packages", name, "package.json"));
|
|
64104
64435
|
const dep = pkg?.dependencies?.["@brainervirus/workit-core"];
|
|
64105
64436
|
if (typeof dep === "string")
|
|
64106
64437
|
refs.add(dep);
|
|
@@ -64116,7 +64447,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64116
64447
|
if (refs.size > 1) {
|
|
64117
64448
|
problems.push(`adapters pin different core versions: ${[...refs].join(", ")}`);
|
|
64118
64449
|
}
|
|
64119
|
-
const opencodePkg = readJson(
|
|
64450
|
+
const opencodePkg = readJson(path31.join(res.dev, "packages/workit-opencode/package.json"));
|
|
64120
64451
|
const sdk = opencodePkg?.dependencies?.["@opencode/plugin"] ?? opencodePkg?.devDependencies?.["@opencode/plugin"];
|
|
64121
64452
|
const sdkVersion = typeof sdk === "string" ? (sdk.match(/^\d+(?:\.\d+){0,2}/) ?? [])[0] : null;
|
|
64122
64453
|
if (sdkVersion && !semverAtLeast(sdkVersion, SUPPORT_MATRIX.opencode.minimum)) {
|
|
@@ -64143,17 +64474,17 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64143
64474
|
status: "pass",
|
|
64144
64475
|
detail: "opencode CLI not on PATH — skipping version check"
|
|
64145
64476
|
};
|
|
64146
|
-
const scratch = mkdtempSync(
|
|
64477
|
+
const scratch = mkdtempSync(path31.join(os8.tmpdir(), "workit-doctor-opencode-"));
|
|
64147
64478
|
let raw;
|
|
64148
64479
|
try {
|
|
64149
64480
|
raw = versionOf("opencode", {
|
|
64150
64481
|
...res.env,
|
|
64151
|
-
XDG_DATA_HOME:
|
|
64152
|
-
XDG_STATE_HOME:
|
|
64153
|
-
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")
|
|
64154
64485
|
}, 5000);
|
|
64155
64486
|
} finally {
|
|
64156
|
-
|
|
64487
|
+
rmSync3(scratch, { recursive: true, force: true });
|
|
64157
64488
|
}
|
|
64158
64489
|
const installed = raw ? (raw.match(/\d+\.\d+\.\d+/) ?? [])[0] ?? null : null;
|
|
64159
64490
|
if (installed === null)
|
|
@@ -64208,7 +64539,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64208
64539
|
const tables = new Map;
|
|
64209
64540
|
let text;
|
|
64210
64541
|
try {
|
|
64211
|
-
text =
|
|
64542
|
+
text = readFileSync14(file, "utf8");
|
|
64212
64543
|
} catch {
|
|
64213
64544
|
return tables;
|
|
64214
64545
|
}
|
|
@@ -64246,19 +64577,19 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64246
64577
|
current[unquote(pair[1])] = value === "true" ? true : value === "false" ? false : unquote(value);
|
|
64247
64578
|
}
|
|
64248
64579
|
return tables;
|
|
64249
|
-
}, codexHomeOf = (res) => res.codexHome ?? (res.env.CODEX_HOME ||
|
|
64580
|
+
}, codexHomeOf = (res) => res.codexHome ?? (res.env.CODEX_HOME || path31.join(res.home, ".codex")), codexWorkitInstalls = (res) => {
|
|
64250
64581
|
const codexHome = codexHomeOf(res);
|
|
64251
|
-
const configFile =
|
|
64582
|
+
const configFile = path31.join(codexHome, "config.toml");
|
|
64252
64583
|
const installs = [];
|
|
64253
64584
|
for (const [key, table] of readTomlTables(configFile)) {
|
|
64254
64585
|
const [kind, id, ...rest] = key.split("\x00");
|
|
64255
64586
|
if (kind !== "plugins" || rest.length > 0 || !id?.startsWith("workit@") || table.enabled === false)
|
|
64256
64587
|
continue;
|
|
64257
64588
|
const marketplace = id.slice("workit@".length);
|
|
64258
|
-
const dir =
|
|
64589
|
+
const dir = path31.join(codexHome, "plugins", "cache", marketplace, "workit");
|
|
64259
64590
|
let versions = [];
|
|
64260
64591
|
try {
|
|
64261
|
-
versions = readdirSync7(dir).filter((v) =>
|
|
64592
|
+
versions = readdirSync7(dir).filter((v) => existsSync14(path31.join(dir, v, ".codex-plugin")));
|
|
64262
64593
|
} catch {
|
|
64263
64594
|
versions = [];
|
|
64264
64595
|
}
|
|
@@ -64266,7 +64597,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64266
64597
|
installs.push({
|
|
64267
64598
|
id,
|
|
64268
64599
|
marketplace,
|
|
64269
|
-
root: version ?
|
|
64600
|
+
root: version ? path31.join(dir, version) : null,
|
|
64270
64601
|
version,
|
|
64271
64602
|
configFile
|
|
64272
64603
|
});
|
|
@@ -64288,7 +64619,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64288
64619
|
};
|
|
64289
64620
|
return `sha256:${createHash13("sha256").update(JSON.stringify(body)).digest("hex")}`;
|
|
64290
64621
|
}, codexHookTrust = (install, tables) => {
|
|
64291
|
-
const hooks = install.root ? readJson(
|
|
64622
|
+
const hooks = install.root ? readJson(path31.join(install.root, "hooks", "hooks.json"))?.hooks : null;
|
|
64292
64623
|
if (!hooks || typeof hooks !== "object")
|
|
64293
64624
|
return null;
|
|
64294
64625
|
const result = [];
|
|
@@ -64361,28 +64692,28 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64361
64692
|
status: "pass",
|
|
64362
64693
|
detail: "no Workit Codex plugin enabled — skipping"
|
|
64363
64694
|
};
|
|
64364
|
-
const agentsDir =
|
|
64695
|
+
const agentsDir = path31.join(codexHomeOf(res), "agents");
|
|
64365
64696
|
const problems = [];
|
|
64366
64697
|
const fixes = [];
|
|
64367
64698
|
const installed = [];
|
|
64368
64699
|
for (const install of installs) {
|
|
64369
|
-
const source = install.root ?
|
|
64370
|
-
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() : [];
|
|
64371
64702
|
if (files.length === 0) {
|
|
64372
64703
|
problems.push(`${install.id} ${install.version ?? "?"} bundles no agents`);
|
|
64373
64704
|
fixes.push(`codex plugin remove ${install.id} && codex plugin add ${install.id}`);
|
|
64374
64705
|
continue;
|
|
64375
64706
|
}
|
|
64376
|
-
const install_fix = `node ${JSON.stringify(
|
|
64377
|
-
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;
|
|
64378
64709
|
const version = typeof pluginVersion === "string" ? pluginVersion.match(SEMVER)?.[0] ?? null : null;
|
|
64379
64710
|
let stale = false;
|
|
64380
64711
|
for (const file of files) {
|
|
64381
|
-
const dest =
|
|
64382
|
-
const want = stampCodexAgent(
|
|
64712
|
+
const dest = path31.join(agentsDir, file);
|
|
64713
|
+
const want = stampCodexAgent(readFileSync14(path31.join(source, file), "utf8"), version);
|
|
64383
64714
|
let link = false;
|
|
64384
64715
|
try {
|
|
64385
|
-
link =
|
|
64716
|
+
link = lstatSync5(dest).isSymbolicLink();
|
|
64386
64717
|
} catch {
|
|
64387
64718
|
link = false;
|
|
64388
64719
|
}
|
|
@@ -64393,7 +64724,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64393
64724
|
}
|
|
64394
64725
|
let have = null;
|
|
64395
64726
|
try {
|
|
64396
|
-
have =
|
|
64727
|
+
have = readFileSync14(dest, "utf8");
|
|
64397
64728
|
} catch {
|
|
64398
64729
|
have = null;
|
|
64399
64730
|
}
|
|
@@ -64432,7 +64763,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64432
64763
|
const env = res.env.PI_CODING_AGENT_DIR;
|
|
64433
64764
|
if (env)
|
|
64434
64765
|
return env === "~" ? res.home : env.replace(/^~(?=\/|\\)/, res.home);
|
|
64435
|
-
return
|
|
64766
|
+
return path31.join(res.home, ".pi", "agent");
|
|
64436
64767
|
}, npmSpecName = (spec) => {
|
|
64437
64768
|
const at = spec.indexOf("@", spec.startsWith("@") ? 1 : 0);
|
|
64438
64769
|
return at > 0 ? { name: spec.slice(0, at), pinned: true } : { name: spec, pinned: false };
|
|
@@ -64440,10 +64771,10 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64440
64771
|
const scopes = [
|
|
64441
64772
|
{
|
|
64442
64773
|
scope: "project",
|
|
64443
|
-
settingsFile:
|
|
64444
|
-
base:
|
|
64774
|
+
settingsFile: path31.join(res.cwd, ".pi", "settings.json"),
|
|
64775
|
+
base: path31.join(res.cwd, ".pi")
|
|
64445
64776
|
},
|
|
64446
|
-
{ scope: "user", settingsFile:
|
|
64777
|
+
{ scope: "user", settingsFile: path31.join(agentDir, "settings.json"), base: agentDir }
|
|
64447
64778
|
];
|
|
64448
64779
|
for (const { scope, settingsFile, base } of scopes) {
|
|
64449
64780
|
const packages = readJson(settingsFile)?.packages;
|
|
@@ -64458,13 +64789,13 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64458
64789
|
const spec = npmSpecName(source.slice(4).trim());
|
|
64459
64790
|
if (spec.name !== PI_PACKAGE)
|
|
64460
64791
|
continue;
|
|
64461
|
-
const root =
|
|
64792
|
+
const root = path31.join(base, "npm", "node_modules", ...PI_PACKAGE.split("/"));
|
|
64462
64793
|
return { scope, settingsFile, source, filter, root, npm: { pinned: spec.pinned } };
|
|
64463
64794
|
}
|
|
64464
64795
|
if (/^(git:|https?:|ssh:|git@)/.test(source))
|
|
64465
64796
|
continue;
|
|
64466
|
-
const local =
|
|
64467
|
-
if (readJson(
|
|
64797
|
+
const local = path31.resolve(base, source.replace(/^~(?=\/|\\)/, res.home));
|
|
64798
|
+
if (readJson(path31.join(local, "package.json"))?.name === PI_PACKAGE)
|
|
64468
64799
|
return { scope, settingsFile, source, filter, root: local, npm: null };
|
|
64469
64800
|
}
|
|
64470
64801
|
}
|
|
@@ -64475,7 +64806,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64475
64806
|
const list = patterns.filter((p) => typeof p === "string");
|
|
64476
64807
|
if (list.length === 0)
|
|
64477
64808
|
return false;
|
|
64478
|
-
const name =
|
|
64809
|
+
const name = path31.posix.basename(file);
|
|
64479
64810
|
const matches = (p) => {
|
|
64480
64811
|
const re = globToRegExp3(p);
|
|
64481
64812
|
return re.test(file) || re.test(name);
|
|
@@ -64492,7 +64823,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64492
64823
|
return kept;
|
|
64493
64824
|
}, checkPiExtension = (res) => {
|
|
64494
64825
|
const agentDir = piAgentDirOf(res);
|
|
64495
|
-
if (!
|
|
64826
|
+
if (!existsSync14(agentDir) && !commandOnPath("pi", res.env))
|
|
64496
64827
|
return { id: "pi_extension", status: "pass", detail: "Pi not installed — skipping" };
|
|
64497
64828
|
const installCmd = (scope, spec = `npm:${PI_PACKAGE}`) => `pi install ${spec}${scope === "project" ? " -l" : ""}`;
|
|
64498
64829
|
const entry = findPiEntry(res, agentDir);
|
|
@@ -64500,12 +64831,12 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64500
64831
|
return {
|
|
64501
64832
|
id: "pi_extension",
|
|
64502
64833
|
status: "warn",
|
|
64503
|
-
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")}`,
|
|
64504
64835
|
fix: installCmd("user")
|
|
64505
64836
|
};
|
|
64506
64837
|
const where = `${entry.source} (${entry.scope}, ${entry.settingsFile})`;
|
|
64507
64838
|
const rebuild = `cd ${JSON.stringify(entry.root)} && bun run build`;
|
|
64508
|
-
const pkg = readJson(
|
|
64839
|
+
const pkg = readJson(path31.join(entry.root, "package.json"));
|
|
64509
64840
|
if (!pkg)
|
|
64510
64841
|
return {
|
|
64511
64842
|
id: "pi_extension",
|
|
@@ -64514,7 +64845,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64514
64845
|
fix: entry.npm ? installCmd(entry.scope, entry.source) : `restore ${entry.root}, then ${rebuild}`
|
|
64515
64846
|
};
|
|
64516
64847
|
const declared = Array.isArray(pkg.pi?.extensions) ? pkg.pi.extensions.some((e) => typeof e === "string" && e.replace(/^\.\//, "") === PI_EXTENSION) : false;
|
|
64517
|
-
if (!declared || !
|
|
64848
|
+
if (!declared || !existsSync14(path31.join(entry.root, PI_EXTENSION)))
|
|
64518
64849
|
return {
|
|
64519
64850
|
id: "pi_extension",
|
|
64520
64851
|
status: "warn",
|
|
@@ -64567,25 +64898,25 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64567
64898
|
detail: `Workit Pi extension ${version ?? "?"} from ${where} loads ${PI_EXTENSION}`
|
|
64568
64899
|
};
|
|
64569
64900
|
}, assetPathsFor = (host, dev) => {
|
|
64570
|
-
const pkg =
|
|
64901
|
+
const pkg = path31.join(dev, "packages", `workit-${host}`);
|
|
64571
64902
|
switch (host) {
|
|
64572
64903
|
case "opencode": {
|
|
64573
|
-
const packaged =
|
|
64574
|
-
const root =
|
|
64575
|
-
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"));
|
|
64576
64907
|
}
|
|
64577
64908
|
case "cursor":
|
|
64578
64909
|
return [
|
|
64579
|
-
|
|
64580
|
-
|
|
64581
|
-
|
|
64910
|
+
path31.join(pkg, "assets", "templates", "workit-contract.md"),
|
|
64911
|
+
path31.join(pkg, "mcp.json"),
|
|
64912
|
+
path31.join(pkg, ".cursor-plugin")
|
|
64582
64913
|
];
|
|
64583
64914
|
case "cli":
|
|
64584
|
-
return [
|
|
64915
|
+
return [path31.join(pkg, "assets", "templates", "spec-template.md")];
|
|
64585
64916
|
}
|
|
64586
64917
|
}, hostsFor = (host) => host === "cli" ? ["opencode", "cursor", "cli"] : [host], checkAssets = (res) => {
|
|
64587
64918
|
const dev = res.dev;
|
|
64588
|
-
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}`)) : [];
|
|
64589
64920
|
if (res.host === "cursor" || res.host === "cli") {
|
|
64590
64921
|
const cursorError = validateCursorSkills(res.cursorPluginDir, WORKIT_METHOD_SKILLS);
|
|
64591
64922
|
if (cursorError)
|
|
@@ -64612,31 +64943,31 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64612
64943
|
fix: "Reinstall or rebuild the workit package (missing assets under packages/workit-<host>)"
|
|
64613
64944
|
};
|
|
64614
64945
|
}, launcherSlotsFor = (host, dev) => {
|
|
64615
|
-
const pkg =
|
|
64946
|
+
const pkg = path31.join(dev, "packages", `workit-${host}`);
|
|
64616
64947
|
switch (host) {
|
|
64617
64948
|
case "opencode":
|
|
64618
|
-
return [[
|
|
64949
|
+
return [[path31.join(pkg, "src", "plugin.ts"), path31.join(pkg, "dist", "plugin.js")]];
|
|
64619
64950
|
case "cursor":
|
|
64620
64951
|
return [
|
|
64621
|
-
[
|
|
64622
|
-
[
|
|
64952
|
+
[path31.join(pkg, "dist", "mcp-server.js")],
|
|
64953
|
+
[path31.join(pkg, "dist", "cursor-session-start.js")]
|
|
64623
64954
|
];
|
|
64624
64955
|
case "cli":
|
|
64625
|
-
return [[
|
|
64956
|
+
return [[path31.join(pkg, "src", "index.tsx"), path31.join(pkg, "dist", "index.js")]];
|
|
64626
64957
|
}
|
|
64627
64958
|
}, validNodeEntry = (entry, runtime, env) => {
|
|
64628
64959
|
try {
|
|
64629
|
-
const stat =
|
|
64630
|
-
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
|
|
64631
64962
|
`)) {
|
|
64632
64963
|
return false;
|
|
64633
64964
|
}
|
|
64634
|
-
return
|
|
64965
|
+
return spawnSync14(runtime, ["--check", entry], { encoding: "utf8", env }).status === 0;
|
|
64635
64966
|
} catch {
|
|
64636
64967
|
return false;
|
|
64637
64968
|
}
|
|
64638
64969
|
}, registeredCursorLauncher = (res) => {
|
|
64639
|
-
if (!
|
|
64970
|
+
if (!existsSync14(res.cursorMcp))
|
|
64640
64971
|
return "invalid";
|
|
64641
64972
|
const config = readJson(res.cursorMcp);
|
|
64642
64973
|
if (!config)
|
|
@@ -64649,7 +64980,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64649
64980
|
if (typeof command !== "string" || !Array.isArray(args) || typeof args[0] !== "string") {
|
|
64650
64981
|
return "invalid";
|
|
64651
64982
|
}
|
|
64652
|
-
const executable =
|
|
64983
|
+
const executable = path31.basename(command).toLowerCase();
|
|
64653
64984
|
const canonical = cursorMcpServerEntry("").args;
|
|
64654
64985
|
if (executable === "npx" || executable === "npx.exe" || executable === "npx.cmd") {
|
|
64655
64986
|
if (args.length !== canonical.length || args.some((a, i) => a !== canonical[i]))
|
|
@@ -64661,11 +64992,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64661
64992
|
return {
|
|
64662
64993
|
kind: "node",
|
|
64663
64994
|
runtime: command,
|
|
64664
|
-
entry:
|
|
64995
|
+
entry: path31.isAbsolute(args[0]) ? args[0] : path31.resolve(path31.dirname(res.cursorMcp), args[0])
|
|
64665
64996
|
};
|
|
64666
64997
|
}, canonicalCursorHook, isCanonicalCursorHook = (command, res) => command === canonicalCursorHook || command === cursorHooksEntry(res.cursorPluginDir).command, registeredCursorHook = (res) => {
|
|
64667
|
-
const hooksFile =
|
|
64668
|
-
if (!
|
|
64998
|
+
const hooksFile = path31.join(res.cursorPluginDir, "hooks", "hooks-cursor.json");
|
|
64999
|
+
if (!existsSync14(hooksFile))
|
|
64669
65000
|
return "invalid";
|
|
64670
65001
|
const config = readJson(hooksFile);
|
|
64671
65002
|
if (!config)
|
|
@@ -64682,9 +65013,9 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64682
65013
|
if (!m)
|
|
64683
65014
|
return false;
|
|
64684
65015
|
const entry = m[1].trim();
|
|
64685
|
-
if (!
|
|
65016
|
+
if (!path31.isAbsolute(entry))
|
|
64686
65017
|
return false;
|
|
64687
|
-
if (
|
|
65018
|
+
if (path31.resolve(entry) !== path31.resolve(path31.join(res.cursorPluginDir, "dist", "cursor-session-start.js"))) {
|
|
64688
65019
|
return false;
|
|
64689
65020
|
}
|
|
64690
65021
|
return validNodeEntry(entry, "node", res.env);
|
|
@@ -64693,7 +65024,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64693
65024
|
const hosts = hostsFor(res.host);
|
|
64694
65025
|
const registered = hosts.includes("cursor") ? registeredCursorLauncher(res) : null;
|
|
64695
65026
|
const runtime = registered && registered !== "invalid" && registered.kind === "node" ? registered.runtime : "node";
|
|
64696
|
-
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}`) : [];
|
|
64697
65028
|
if (hosts.includes("cursor")) {
|
|
64698
65029
|
if (registered === "invalid") {
|
|
64699
65030
|
missing.push(`cursor: canonical workit MCP launcher in ${res.cursorMcp}`);
|
|
@@ -64702,13 +65033,13 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64702
65033
|
}
|
|
64703
65034
|
const hook = registeredCursorHook(res);
|
|
64704
65035
|
if (hook === "invalid") {
|
|
64705
|
-
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")}`);
|
|
64706
65037
|
} else if (hook !== null && !isCanonicalCursorHook(hook, res) && !validLocalDistHook(hook, res)) {
|
|
64707
|
-
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})`);
|
|
64708
65039
|
}
|
|
64709
65040
|
}
|
|
64710
65041
|
if (dev) {
|
|
64711
|
-
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 ")}`)));
|
|
64712
65043
|
}
|
|
64713
65044
|
if (missing.length > 0) {
|
|
64714
65045
|
return {
|
|
@@ -64733,21 +65064,21 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64733
65064
|
}, CURSOR_HOOK_FIX = "Run `workit init` and select Cursor to install the bundled hook", checkCursorHook = (res) => {
|
|
64734
65065
|
if (!hostsFor(res.host).includes("cursor"))
|
|
64735
65066
|
return { id: "cursor_hook", status: "pass", detail: "cursor hook not inspected on this host" };
|
|
64736
|
-
if (!
|
|
65067
|
+
if (!existsSync14(res.cursorPluginDir))
|
|
64737
65068
|
return {
|
|
64738
65069
|
id: "cursor_hook",
|
|
64739
65070
|
status: "pass",
|
|
64740
65071
|
detail: "no Cursor plugin install — hook launcher not inspected"
|
|
64741
65072
|
};
|
|
64742
|
-
const launcher =
|
|
64743
|
-
if (!
|
|
65073
|
+
const launcher = path31.join(res.cursorPluginDir, "hooks", "launch.mjs");
|
|
65074
|
+
if (!existsSync14(launcher))
|
|
64744
65075
|
return {
|
|
64745
65076
|
id: "cursor_hook",
|
|
64746
65077
|
status: "warn",
|
|
64747
65078
|
detail: `cursor hook launcher mode: missing — ${launcher} is absent (an install from before the pinned launcher)`,
|
|
64748
65079
|
fix: CURSOR_HOOK_FIX
|
|
64749
65080
|
};
|
|
64750
|
-
const hooksFile =
|
|
65081
|
+
const hooksFile = path31.join(res.cursorPluginDir, "hooks", "hooks-cursor.json");
|
|
64751
65082
|
const registered = readJson(hooksFile);
|
|
64752
65083
|
const sessionCommand = registered?.hooks?.sessionStart?.[0]?.command;
|
|
64753
65084
|
const offLauncher = [
|
|
@@ -64762,7 +65093,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64762
65093
|
fix: "Re-run install-cursor-plugin.sh (or `workit init` with Cursor) to rewrite the hook entries"
|
|
64763
65094
|
};
|
|
64764
65095
|
const started = performance.now();
|
|
64765
|
-
const probe =
|
|
65096
|
+
const probe = spawnSync14("node", [launcher, "--probe", "workit-cursor-hook"], {
|
|
64766
65097
|
encoding: "utf8",
|
|
64767
65098
|
env: { ...res.env, WORKIT_CURSOR_HOOK_NPX_OFFLINE: "1" },
|
|
64768
65099
|
timeout: 40000,
|
|
@@ -64809,15 +65140,15 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64809
65140
|
return { id: "cursor_hook", status: "pass", detail: `${label}; probe ${ms} ms` };
|
|
64810
65141
|
}, SILENT_HOOK_GRACE_MS, mtimeMs = (file) => {
|
|
64811
65142
|
try {
|
|
64812
|
-
return
|
|
65143
|
+
return statSync5(file).mtimeMs;
|
|
64813
65144
|
} catch {
|
|
64814
65145
|
return null;
|
|
64815
65146
|
}
|
|
64816
65147
|
}, silentCursorHooks = (res) => {
|
|
64817
|
-
const session = mtimeMs(
|
|
65148
|
+
const session = mtimeMs(path31.join(res.cursorHeartbeatDir, "cursor-session-last-start"));
|
|
64818
65149
|
if (session === null || Date.now() - session < SILENT_HOOK_GRACE_MS)
|
|
64819
65150
|
return null;
|
|
64820
|
-
const hook = mtimeMs(
|
|
65151
|
+
const hook = mtimeMs(path31.join(res.cursorHeartbeatDir, "cursor-hook-last-run"));
|
|
64821
65152
|
if (hook !== null && hook >= session)
|
|
64822
65153
|
return null;
|
|
64823
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`;
|
|
@@ -64858,7 +65189,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64858
65189
|
return "fragile-cache";
|
|
64859
65190
|
if (entry.startsWith("file:")) {
|
|
64860
65191
|
const target = entry.replace(/^file:\/\//, "").replace(/^file:/, "");
|
|
64861
|
-
return
|
|
65192
|
+
return existsSync14(target) ? "ok" : "missing-file";
|
|
64862
65193
|
}
|
|
64863
65194
|
return "ok";
|
|
64864
65195
|
}, checkStalePin = (res) => {
|
|
@@ -64869,7 +65200,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64869
65200
|
detail: "opencode pin not inspected on the cursor host"
|
|
64870
65201
|
};
|
|
64871
65202
|
}
|
|
64872
|
-
if (!
|
|
65203
|
+
if (!existsSync14(res.opencodeConfig)) {
|
|
64873
65204
|
return {
|
|
64874
65205
|
id: "stale_pin",
|
|
64875
65206
|
status: "pass",
|
|
@@ -64913,8 +65244,8 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64913
65244
|
}
|
|
64914
65245
|
return { id: "stale_pin", status: "pass", detail: "opencode pin resolves" };
|
|
64915
65246
|
}, pluginMcpSelectors = (res) => {
|
|
64916
|
-
const p =
|
|
64917
|
-
if (!
|
|
65247
|
+
const p = path31.join(res.cursorPluginDir, "mcp.json");
|
|
65248
|
+
if (!existsSync14(p))
|
|
64918
65249
|
return null;
|
|
64919
65250
|
const cfg = readJson(p);
|
|
64920
65251
|
const server = cfg?.mcpServers?.workit;
|
|
@@ -64936,7 +65267,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64936
65267
|
if (!cmd)
|
|
64937
65268
|
return null;
|
|
64938
65269
|
try {
|
|
64939
|
-
const r =
|
|
65270
|
+
const r = spawnSync14(cmd, ["view", pkgName, "version"], {
|
|
64940
65271
|
encoding: "utf8",
|
|
64941
65272
|
timeout: 20000,
|
|
64942
65273
|
env: res.env
|
|
@@ -64947,13 +65278,13 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
64947
65278
|
return null;
|
|
64948
65279
|
}
|
|
64949
65280
|
}, installedPluginVersion = (res) => {
|
|
64950
|
-
const pkg = readJson(
|
|
65281
|
+
const pkg = readJson(path31.join(res.cursorPluginDir, "package.json"));
|
|
64951
65282
|
return typeof pkg?.version === "string" && pkg.version ? pkg.version : null;
|
|
64952
65283
|
}, installedOpenCodeCacheVersion = (res) => {
|
|
64953
|
-
const pkg = readJson(
|
|
65284
|
+
const pkg = readJson(path31.join(res.opencodePackageCacheDir, "node_modules", "@brainervirus", "workit-opencode", "package.json"));
|
|
64954
65285
|
return typeof pkg?.version === "string" && pkg.version ? pkg.version : null;
|
|
64955
65286
|
}, checkOpenCodePackageCache = (res) => {
|
|
64956
|
-
if (!
|
|
65287
|
+
if (!existsSync14(res.opencodeConfig)) {
|
|
64957
65288
|
return {
|
|
64958
65289
|
id: "stale_install",
|
|
64959
65290
|
status: "pass",
|
|
@@ -65027,7 +65358,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65027
65358
|
detail: "cursor plugin not inspected on this host"
|
|
65028
65359
|
};
|
|
65029
65360
|
}
|
|
65030
|
-
if (
|
|
65361
|
+
if (existsSync14(res.cursorPluginDir) && lstatSync5(res.cursorPluginDir).isSymbolicLink()) {
|
|
65031
65362
|
let target = "";
|
|
65032
65363
|
try {
|
|
65033
65364
|
target = readlinkSync2(res.cursorPluginDir);
|
|
@@ -65053,7 +65384,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65053
65384
|
fix: "Re-run install-cursor-plugin.sh — it rewrites the workit MCP entry to the canonical @latest selector"
|
|
65054
65385
|
};
|
|
65055
65386
|
}
|
|
65056
|
-
const hooksFile =
|
|
65387
|
+
const hooksFile = path31.join(res.cursorPluginDir, "hooks", "hooks-cursor.json");
|
|
65057
65388
|
const hookCmd = readJson(hooksFile)?.hooks?.sessionStart?.[0]?.command ?? null;
|
|
65058
65389
|
const canonicalHook = canonicalCursorHook;
|
|
65059
65390
|
const staleHook = hookCmd !== null && !isCanonicalCursorHook(hookCmd, res) && !hookCmd.startsWith("node ") && hookCmd.includes("@brainervirus/workit-cursor@");
|
|
@@ -65065,7 +65396,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65065
65396
|
fix: "Re-run install-cursor-plugin.sh — it rewrites the sessionStart hook to the canonical pinned launcher"
|
|
65066
65397
|
};
|
|
65067
65398
|
}
|
|
65068
|
-
const hookDrift =
|
|
65399
|
+
const hookDrift = existsSync14(hooksFile) ? cursorHookDrift(readJson(hooksFile), res.cursorPluginDir) : [];
|
|
65069
65400
|
if (hookDrift.length > 0) {
|
|
65070
65401
|
return {
|
|
65071
65402
|
id: "stale_install",
|
|
@@ -65075,7 +65406,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65075
65406
|
};
|
|
65076
65407
|
}
|
|
65077
65408
|
const installed = installedPluginVersion(res);
|
|
65078
|
-
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;
|
|
65079
65410
|
const localDist = mcpSelectors === null && hookCmd !== null && !isCanonicalCursorHook(hookCmd, res) && hookCmd.startsWith("node ");
|
|
65080
65411
|
if (localDist && installed !== null && source !== null && !semverAtLeast(installed, source)) {
|
|
65081
65412
|
return {
|
|
@@ -65087,7 +65418,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65087
65418
|
}
|
|
65088
65419
|
if (localDist && installed !== null && source !== null && res.dev) {
|
|
65089
65420
|
const entry = /^node\s+(.+)$/.exec((hookCmd ?? "").trim())?.[1]?.trim() ?? "";
|
|
65090
|
-
const sourceBundle = entry &&
|
|
65421
|
+
const sourceBundle = entry && path31.isAbsolute(entry) ? path31.join(res.dev, "packages", "workit-cursor", "dist", path31.basename(entry)) : "";
|
|
65091
65422
|
if (entry && sourceBundle) {
|
|
65092
65423
|
const installedHash = bundleHashOfFile(entry);
|
|
65093
65424
|
const sourceHash = bundleHashOfFile(sourceBundle);
|
|
@@ -65095,7 +65426,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65095
65426
|
return {
|
|
65096
65427
|
id: "stale_install",
|
|
65097
65428
|
status: "fail",
|
|
65098
|
-
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)`,
|
|
65099
65430
|
fix: "Re-run install-cursor-plugin.sh — it refreshes the plugin directory with the current build"
|
|
65100
65431
|
};
|
|
65101
65432
|
}
|
|
@@ -65149,13 +65480,13 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65149
65480
|
const problems = [];
|
|
65150
65481
|
const opencodeHost = res.host !== "cursor";
|
|
65151
65482
|
const cursorHost = res.host !== "opencode";
|
|
65152
|
-
if (opencodeHost &&
|
|
65483
|
+
if (opencodeHost && existsSync14(res.opencodeConfig)) {
|
|
65153
65484
|
const cfg = readJson(res.opencodeConfig);
|
|
65154
65485
|
const entries = pluginEntries(cfg);
|
|
65155
65486
|
if (entries.length > 1)
|
|
65156
65487
|
problems.push(`opencode registers ${entries.length} workit plugin entries`);
|
|
65157
65488
|
}
|
|
65158
|
-
if (cursorHost &&
|
|
65489
|
+
if (cursorHost && existsSync14(res.cursorSettings)) {
|
|
65159
65490
|
const settings = readJson(res.cursorSettings);
|
|
65160
65491
|
const enabled = settings?.enabled_plugins;
|
|
65161
65492
|
if (enabled && typeof enabled === "object") {
|
|
@@ -65170,7 +65501,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65170
65501
|
if (dirs.length > 1)
|
|
65171
65502
|
problems.push(`cursor plugin_dirs has ${dirs.length} workit entries`);
|
|
65172
65503
|
}
|
|
65173
|
-
if (cursorHost &&
|
|
65504
|
+
if (cursorHost && existsSync14(res.cursorMcp)) {
|
|
65174
65505
|
const mcp = readJson(res.cursorMcp);
|
|
65175
65506
|
const servers = mcp?.mcpServers ?? {};
|
|
65176
65507
|
if (servers && typeof servers === "object") {
|
|
@@ -65195,17 +65526,17 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65195
65526
|
}, checkMalformedConfig = (res) => {
|
|
65196
65527
|
const files = [];
|
|
65197
65528
|
for (const name of ["config.json", "youtrack.json", "vcs.json", "workspaces.json"]) {
|
|
65198
|
-
const p =
|
|
65199
|
-
if (
|
|
65529
|
+
const p = path31.join(res.configDir, name);
|
|
65530
|
+
if (existsSync14(p))
|
|
65200
65531
|
files.push(p);
|
|
65201
65532
|
}
|
|
65202
65533
|
const opencodeHost = res.host !== "cursor";
|
|
65203
65534
|
const cursorHost = res.host !== "opencode";
|
|
65204
|
-
if (opencodeHost &&
|
|
65535
|
+
if (opencodeHost && existsSync14(res.opencodeConfig))
|
|
65205
65536
|
files.push(res.opencodeConfig);
|
|
65206
|
-
if (cursorHost &&
|
|
65537
|
+
if (cursorHost && existsSync14(res.cursorSettings))
|
|
65207
65538
|
files.push(res.cursorSettings);
|
|
65208
|
-
if (cursorHost &&
|
|
65539
|
+
if (cursorHost && existsSync14(res.cursorMcp))
|
|
65209
65540
|
files.push(res.cursorMcp);
|
|
65210
65541
|
const bad = files.filter((p) => !parsesAsConfigObject(p));
|
|
65211
65542
|
if (bad.length === 0)
|
|
@@ -65284,19 +65615,90 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65284
65615
|
detail: `current directory ${res.cwd} does not match any configured workspace`,
|
|
65285
65616
|
fix: `Add a workspace glob matching this directory to ${file} or run /wk-init`
|
|
65286
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 };
|
|
65287
65689
|
}, isPlaceholder = (p) => {
|
|
65288
65690
|
try {
|
|
65289
|
-
return
|
|
65691
|
+
return readFileSync14(p, "utf8").trim() === TOKEN_PLACEHOLDER2;
|
|
65290
65692
|
} catch {
|
|
65291
65693
|
return false;
|
|
65292
65694
|
}
|
|
65293
65695
|
}, checkCredentialMetadata = (res) => {
|
|
65294
65696
|
const tokenPaths = [];
|
|
65295
|
-
const youtrackJson = readJson(
|
|
65697
|
+
const youtrackJson = readJson(path31.join(res.configDir, "youtrack.json"));
|
|
65296
65698
|
if (youtrackJson) {
|
|
65297
|
-
tokenPaths.push(typeof youtrackJson.tokenFile === "string" ? youtrackJson.tokenFile :
|
|
65298
|
-
} else if (
|
|
65299
|
-
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"));
|
|
65300
65702
|
}
|
|
65301
65703
|
if (tokenPaths.length === 0) {
|
|
65302
65704
|
return {
|
|
@@ -65307,13 +65709,13 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65307
65709
|
}
|
|
65308
65710
|
const problems = [];
|
|
65309
65711
|
for (const raw of tokenPaths) {
|
|
65310
|
-
const p =
|
|
65311
|
-
if (!
|
|
65712
|
+
const p = path31.isAbsolute(raw) ? raw : path31.resolve(res.configDir, raw);
|
|
65713
|
+
if (!existsSync14(p)) {
|
|
65312
65714
|
problems.push(`${p} is missing`);
|
|
65313
65715
|
continue;
|
|
65314
65716
|
}
|
|
65315
65717
|
if (process.platform !== "win32") {
|
|
65316
|
-
const mode =
|
|
65718
|
+
const mode = statSync5(p).mode & 511;
|
|
65317
65719
|
if (mode !== 384)
|
|
65318
65720
|
problems.push(`${p} must be mode 0600 (found ${mode.toString(8)})`);
|
|
65319
65721
|
}
|
|
@@ -65375,7 +65777,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65375
65777
|
}, defaultIdentityProbes = (env) => ({
|
|
65376
65778
|
origin: (cwd) => {
|
|
65377
65779
|
try {
|
|
65378
|
-
const out =
|
|
65780
|
+
const out = spawnSync14("git", ["remote", "get-url", "origin"], {
|
|
65379
65781
|
cwd,
|
|
65380
65782
|
encoding: "utf8",
|
|
65381
65783
|
env
|
|
@@ -65387,7 +65789,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65387
65789
|
},
|
|
65388
65790
|
ghLogin: (e) => {
|
|
65389
65791
|
try {
|
|
65390
|
-
const out =
|
|
65792
|
+
const out = spawnSync14("gh", ["api", "user", "--jq", ".login"], { encoding: "utf8", env: e });
|
|
65391
65793
|
const login = (out.stdout ?? "").trim();
|
|
65392
65794
|
return out.status === 0 && login ? login : null;
|
|
65393
65795
|
} catch {
|
|
@@ -65396,7 +65798,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65396
65798
|
},
|
|
65397
65799
|
glabLogin: (e) => {
|
|
65398
65800
|
try {
|
|
65399
|
-
const out =
|
|
65801
|
+
const out = spawnSync14("glab", ["api", "user", "--jq", ".username"], {
|
|
65400
65802
|
encoding: "utf8",
|
|
65401
65803
|
env: e
|
|
65402
65804
|
});
|
|
@@ -65408,7 +65810,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65408
65810
|
},
|
|
65409
65811
|
sshLogin: (host) => {
|
|
65410
65812
|
try {
|
|
65411
|
-
const out =
|
|
65813
|
+
const out = spawnSync14("ssh", ["-o", "BatchMode=yes", "-o", "ConnectTimeout=5", "-T", `git@${host}`], {
|
|
65412
65814
|
encoding: "utf8",
|
|
65413
65815
|
env
|
|
65414
65816
|
});
|
|
@@ -65423,7 +65825,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65423
65825
|
const remoteHost = githubHostFromRemote(probes.origin(res.cwd) ?? "");
|
|
65424
65826
|
if (!remoteHost)
|
|
65425
65827
|
return { id: "github_identity", status: "pass", detail: "no GitHub remote configured" };
|
|
65426
|
-
const vcsJson = readJson(res.env.WORKFLOW_VCS_CONFIG ??
|
|
65828
|
+
const vcsJson = readJson(res.env.WORKFLOW_VCS_CONFIG ?? path31.join(res.configDir, "vcs.json"));
|
|
65427
65829
|
const workspace = workspaceProviderForIdentity(res.cwd, res.configDir, res.env);
|
|
65428
65830
|
if (workspace.error)
|
|
65429
65831
|
return {
|
|
@@ -65451,7 +65853,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65451
65853
|
const remoteHost = githubHostFromRemote(probes.origin(res.cwd) ?? "");
|
|
65452
65854
|
if (!remoteHost)
|
|
65453
65855
|
return { id: "gitlab_identity", status: "pass", detail: "no GitLab remote configured" };
|
|
65454
|
-
const vcsJson = readJson(res.env.WORKFLOW_VCS_CONFIG ??
|
|
65856
|
+
const vcsJson = readJson(res.env.WORKFLOW_VCS_CONFIG ?? path31.join(res.configDir, "vcs.json"));
|
|
65455
65857
|
const workspace = workspaceProviderForIdentity(res.cwd, res.configDir, res.env);
|
|
65456
65858
|
if (workspace.error)
|
|
65457
65859
|
return {
|
|
@@ -65477,11 +65879,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65477
65879
|
{ surface: "SSH", login: probes.sshLogin(remoteHost) }
|
|
65478
65880
|
]);
|
|
65479
65881
|
}, checkLogWritable = (res) => {
|
|
65480
|
-
const logsDir =
|
|
65481
|
-
const probe =
|
|
65882
|
+
const logsDir = path31.join(res.stateDir, "logs");
|
|
65883
|
+
const probe = path31.join(logsDir, "doctor-probe.tmp");
|
|
65482
65884
|
try {
|
|
65483
|
-
|
|
65484
|
-
|
|
65885
|
+
mkdirSync6(logsDir, { recursive: true, mode: 448 });
|
|
65886
|
+
writeFileSync7(probe, `{"probe":true}
|
|
65485
65887
|
`, { mode: 384 });
|
|
65486
65888
|
return {
|
|
65487
65889
|
id: "log_writable",
|
|
@@ -65568,7 +65970,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65568
65970
|
}, CLI_PACKAGE = "@brainervirus/workit-cli", SEMVER, WORKIT_PROBE_TIMEOUT_MS = 1e4, workitVersions, workitVersionAt = (bin, env) => {
|
|
65569
65971
|
let key;
|
|
65570
65972
|
try {
|
|
65571
|
-
const st =
|
|
65973
|
+
const st = statSync5(bin);
|
|
65572
65974
|
key = `${bin}:${st.ino}:${st.size}:${st.mtimeMs}`;
|
|
65573
65975
|
} catch {
|
|
65574
65976
|
return { version: null, timedOut: false };
|
|
@@ -65577,12 +65979,12 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
65577
65979
|
if (cached)
|
|
65578
65980
|
return cached;
|
|
65579
65981
|
const viaShell = process.platform === "win32" && /\.(?:cmd|bat)$/i.test(bin);
|
|
65580
|
-
const r = viaShell ?
|
|
65982
|
+
const r = viaShell ? spawnSync14(`"${bin}" --version`, {
|
|
65581
65983
|
encoding: "utf8",
|
|
65582
65984
|
env,
|
|
65583
65985
|
timeout: WORKIT_PROBE_TIMEOUT_MS,
|
|
65584
65986
|
shell: true
|
|
65585
|
-
}) :
|
|
65987
|
+
}) : spawnSync14(bin, ["--version"], { encoding: "utf8", env, timeout: WORKIT_PROBE_TIMEOUT_MS });
|
|
65586
65988
|
const timedOut = r.error !== undefined && "code" in r.error && r.error.code === "ETIMEDOUT";
|
|
65587
65989
|
const version = r.status === 0 ? (r.stdout ?? "").match(SEMVER)?.[0] ?? null : null;
|
|
65588
65990
|
const probe = { version: timedOut ? null : version, timedOut };
|
|
@@ -65672,6 +66074,7 @@ var init_doctor = __esm(() => {
|
|
|
65672
66074
|
init_workspaces();
|
|
65673
66075
|
init_host_install();
|
|
65674
66076
|
init_skill_manifests();
|
|
66077
|
+
init_session_hook();
|
|
65675
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`;
|
|
65676
66079
|
AGENT_MARKER_VERSION = /^# Generated by Workit (\d+\.\d+\.\d+)\b/;
|
|
65677
66080
|
canonicalCursorHook = cursorHooksEntry().command;
|
|
@@ -65698,6 +66101,7 @@ var init_doctor = __esm(() => {
|
|
|
65698
66101
|
checkMalformedConfig,
|
|
65699
66102
|
checkWorkspaceMismatch,
|
|
65700
66103
|
checkWorkspaceLock,
|
|
66104
|
+
checkSessionHook,
|
|
65701
66105
|
checkCredentialMetadata,
|
|
65702
66106
|
checkGithubIdentity,
|
|
65703
66107
|
checkGitLabIdentity,
|
|
@@ -65719,20 +66123,20 @@ var init_doctor = __esm(() => {
|
|
|
65719
66123
|
import {
|
|
65720
66124
|
copyFileSync as copyFileSync4,
|
|
65721
66125
|
cpSync as cpSync4,
|
|
65722
|
-
existsSync as
|
|
65723
|
-
lstatSync as
|
|
65724
|
-
mkdirSync as
|
|
66126
|
+
existsSync as existsSync15,
|
|
66127
|
+
lstatSync as lstatSync6,
|
|
66128
|
+
mkdirSync as mkdirSync7,
|
|
65725
66129
|
mkdtempSync as mkdtempSync2,
|
|
65726
|
-
readFileSync as
|
|
66130
|
+
readFileSync as readFileSync15,
|
|
65727
66131
|
readdirSync as readdirSync8,
|
|
65728
66132
|
realpathSync as realpathSync7,
|
|
65729
|
-
renameSync as
|
|
65730
|
-
rmSync as
|
|
65731
|
-
statSync as
|
|
65732
|
-
writeFileSync as
|
|
66133
|
+
renameSync as renameSync4,
|
|
66134
|
+
rmSync as rmSync4,
|
|
66135
|
+
statSync as statSync6,
|
|
66136
|
+
writeFileSync as writeFileSync8
|
|
65733
66137
|
} from "node:fs";
|
|
65734
66138
|
import os9 from "node:os";
|
|
65735
|
-
import
|
|
66139
|
+
import path32 from "node:path";
|
|
65736
66140
|
import { isDeepStrictEqual as isDeepStrictEqual2 } from "node:util";
|
|
65737
66141
|
function parseList(raw) {
|
|
65738
66142
|
return raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
@@ -65776,7 +66180,7 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
65776
66180
|
const current = readConfigFromDir(state.configDir);
|
|
65777
66181
|
mutations.push({
|
|
65778
66182
|
type: "merge-json",
|
|
65779
|
-
path:
|
|
66183
|
+
path: path32.join(state.configDir, "config.json"),
|
|
65780
66184
|
value: {
|
|
65781
66185
|
locale: values.locale,
|
|
65782
66186
|
localeOptions: current.localeOptions,
|
|
@@ -65802,17 +66206,17 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
65802
66206
|
if (blocked.length === 0) {
|
|
65803
66207
|
mutations.push({
|
|
65804
66208
|
type: "update-workspaces",
|
|
65805
|
-
path:
|
|
66209
|
+
path: path32.join(state.configDir, "workspaces.json"),
|
|
65806
66210
|
entries: values.workspaces,
|
|
65807
66211
|
expectedRevision: diskWorkspaceResult.revision
|
|
65808
66212
|
});
|
|
65809
66213
|
}
|
|
65810
66214
|
}
|
|
65811
66215
|
if (values.baseUrl.trim()) {
|
|
65812
|
-
const ytPath =
|
|
66216
|
+
const ytPath = path32.join(state.configDir, "youtrack.json");
|
|
65813
66217
|
const ytExisting = readConfigRecord(ytPath);
|
|
65814
66218
|
const ytConfigured = configuredTokenPath(ytExisting, "tokenFile");
|
|
65815
|
-
const tokenPath = resolveTokenPath(ytConfigured,
|
|
66219
|
+
const tokenPath = resolveTokenPath(ytConfigured, path32.join(state.configDir, "youtrack.token"), values.tokenPaths?.youtrack);
|
|
65816
66220
|
const draft = youtrackDraft(values, tokenPath);
|
|
65817
66221
|
if (ytConfigured !== null && tokenPath !== ytConfigured) {
|
|
65818
66222
|
delete draft.tokenFile;
|
|
@@ -65828,7 +66232,7 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
65828
66232
|
path: ytPath,
|
|
65829
66233
|
value: draft
|
|
65830
66234
|
});
|
|
65831
|
-
if (
|
|
66235
|
+
if (existsSync15(tokenPath))
|
|
65832
66236
|
preserved.push(tokenPath);
|
|
65833
66237
|
else
|
|
65834
66238
|
mutations.push({
|
|
@@ -65840,7 +66244,7 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
65840
66244
|
});
|
|
65841
66245
|
}
|
|
65842
66246
|
if (values.vcsProvider !== "skip") {
|
|
65843
|
-
const vcsPath =
|
|
66247
|
+
const vcsPath = path32.join(state.configDir, "vcs.json");
|
|
65844
66248
|
mutations.push({
|
|
65845
66249
|
type: "merge-json",
|
|
65846
66250
|
path: vcsPath,
|
|
@@ -65869,7 +66273,7 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
65869
66273
|
mutations.push({
|
|
65870
66274
|
type: "install-host",
|
|
65871
66275
|
platform: "cursor",
|
|
65872
|
-
path:
|
|
66276
|
+
path: path32.join(paths.home, ".cursor", "plugins", "local", ".workit-package-bootstrap"),
|
|
65873
66277
|
commands
|
|
65874
66278
|
});
|
|
65875
66279
|
}
|
|
@@ -65882,7 +66286,7 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
65882
66286
|
mutations.push({
|
|
65883
66287
|
type: "install-host",
|
|
65884
66288
|
platform,
|
|
65885
|
-
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"),
|
|
65886
66290
|
commands
|
|
65887
66291
|
});
|
|
65888
66292
|
}
|
|
@@ -65890,9 +66294,9 @@ function buildSetupPreview(values, opts = {}) {
|
|
|
65890
66294
|
}
|
|
65891
66295
|
}
|
|
65892
66296
|
if (values.applyProject) {
|
|
65893
|
-
const root =
|
|
65894
|
-
const gitignorePath =
|
|
65895
|
-
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") : "";
|
|
65896
66300
|
const existingLines = new Set(existing.split(`
|
|
65897
66301
|
`).map((l) => l.trim()).filter(Boolean));
|
|
65898
66302
|
const entries = GITIGNORE_ENTRIES.filter((e) => e.trim() !== "" && !existingLines.has(e.trim()));
|
|
@@ -65928,10 +66332,10 @@ function deepMerge(base, patch) {
|
|
|
65928
66332
|
return out;
|
|
65929
66333
|
}
|
|
65930
66334
|
function applyMutation(m) {
|
|
65931
|
-
const dir =
|
|
66335
|
+
const dir = path32.dirname(m.path);
|
|
65932
66336
|
switch (m.type) {
|
|
65933
66337
|
case "create-file": {
|
|
65934
|
-
|
|
66338
|
+
mkdirSync7(dir, { recursive: true });
|
|
65935
66339
|
const res = writeFileExclusive(m.path, m.content, m.mode);
|
|
65936
66340
|
return res === "created" ? { platform: "core", file: m.path, status: "Installed" } : {
|
|
65937
66341
|
platform: "core",
|
|
@@ -65954,8 +66358,8 @@ function applyMutation(m) {
|
|
|
65954
66358
|
if (existing.kind === "record" && JSON.stringify(existing.value) === JSON.stringify(merged)) {
|
|
65955
66359
|
return { platform: "core", file: m.path, status: "Skipped", detail: "already configured" };
|
|
65956
66360
|
}
|
|
65957
|
-
|
|
65958
|
-
|
|
66361
|
+
mkdirSync7(dir, { recursive: true });
|
|
66362
|
+
writeFileSync8(m.path, JSON.stringify(merged, null, 2) + `
|
|
65959
66363
|
`, "utf8");
|
|
65960
66364
|
return existing.kind === "record" ? { platform: "core", file: m.path, status: "Configured" } : { platform: "core", file: m.path, status: "Installed" };
|
|
65961
66365
|
}
|
|
@@ -65996,12 +66400,12 @@ function applyMutation(m) {
|
|
|
65996
66400
|
`;
|
|
65997
66401
|
if (prev === next)
|
|
65998
66402
|
return { platform: "core", file: m.path, status: "Skipped", detail: "already configured" };
|
|
65999
|
-
|
|
66403
|
+
mkdirSync7(dir, { recursive: true });
|
|
66000
66404
|
const tmp = `${m.path}.${process.pid}.tmp`;
|
|
66001
66405
|
try {
|
|
66002
|
-
|
|
66406
|
+
writeFileSync8(tmp, next, "utf8");
|
|
66003
66407
|
if (workspacesRevision(readFileSafe(m.path)) !== m.expectedRevision) {
|
|
66004
|
-
|
|
66408
|
+
rmSync4(tmp, { force: true });
|
|
66005
66409
|
return {
|
|
66006
66410
|
platform: "core",
|
|
66007
66411
|
file: m.path,
|
|
@@ -66009,9 +66413,9 @@ function applyMutation(m) {
|
|
|
66009
66413
|
detail: "workspace config changed while applying the preview; rebuild and review it"
|
|
66010
66414
|
};
|
|
66011
66415
|
}
|
|
66012
|
-
|
|
66416
|
+
renameSync4(tmp, m.path);
|
|
66013
66417
|
} catch (error) {
|
|
66014
|
-
|
|
66418
|
+
rmSync4(tmp, { force: true });
|
|
66015
66419
|
return {
|
|
66016
66420
|
platform: "core",
|
|
66017
66421
|
file: m.path,
|
|
@@ -66034,11 +66438,11 @@ function applyMutation(m) {
|
|
|
66034
66438
|
detail: "all entries already present"
|
|
66035
66439
|
};
|
|
66036
66440
|
}
|
|
66037
|
-
|
|
66441
|
+
mkdirSync7(dir, { recursive: true });
|
|
66038
66442
|
const separator = existing && !existing.endsWith(`
|
|
66039
66443
|
`) ? `
|
|
66040
66444
|
` : "";
|
|
66041
|
-
|
|
66445
|
+
writeFileSync8(m.path, existing + separator + (existing ? `
|
|
66042
66446
|
` : "") + add.join(`
|
|
66043
66447
|
`) + `
|
|
66044
66448
|
`, "utf8");
|
|
@@ -66077,8 +66481,8 @@ function applyMutation(m) {
|
|
|
66077
66481
|
detail: "already configured"
|
|
66078
66482
|
};
|
|
66079
66483
|
}
|
|
66080
|
-
|
|
66081
|
-
|
|
66484
|
+
mkdirSync7(path32.dirname(m.path), { recursive: true });
|
|
66485
|
+
writeFileSync8(m.path, JSON.stringify(merged, null, 2) + `
|
|
66082
66486
|
`, "utf8");
|
|
66083
66487
|
return existing.kind === "record" ? { platform: "core", file: m.path, status: "Configured" } : { platform: "core", file: m.path, status: "Installed" };
|
|
66084
66488
|
}
|
|
@@ -66086,23 +66490,23 @@ function applyMutation(m) {
|
|
|
66086
66490
|
}
|
|
66087
66491
|
function adapterRoot(platform, res, preferInstalledAdapter = false) {
|
|
66088
66492
|
const candidates = [];
|
|
66089
|
-
const stagedCursor =
|
|
66493
|
+
const stagedCursor = path32.join(res.home, ".cursor", "plugins", "local", ".workit-package-bootstrap", "node_modules", "@brainervirus", "workit-cursor");
|
|
66090
66494
|
if (platform === "cursor" && preferInstalledAdapter)
|
|
66091
66495
|
candidates.push(stagedCursor);
|
|
66092
66496
|
if (res.dev) {
|
|
66093
|
-
candidates.push(
|
|
66497
|
+
candidates.push(path32.join(res.dev, "packages", `workit-${platform}`));
|
|
66094
66498
|
} else {
|
|
66095
|
-
candidates.push(
|
|
66096
|
-
let dir =
|
|
66499
|
+
candidates.push(path32.join(packageRoot(), "..", `workit-${platform}`));
|
|
66500
|
+
let dir = path32.resolve(res.cwd);
|
|
66097
66501
|
while (true) {
|
|
66098
|
-
candidates.push(
|
|
66099
|
-
const parent =
|
|
66502
|
+
candidates.push(path32.join(dir, "packages", `workit-${platform}`));
|
|
66503
|
+
const parent = path32.dirname(dir);
|
|
66100
66504
|
if (parent === dir)
|
|
66101
66505
|
break;
|
|
66102
66506
|
dir = parent;
|
|
66103
66507
|
}
|
|
66104
66508
|
}
|
|
66105
|
-
candidates.push(
|
|
66509
|
+
candidates.push(path32.join(res.home, ".local", "share", "workit", "packages", `workit-${platform}`));
|
|
66106
66510
|
if (platform === "cursor")
|
|
66107
66511
|
candidates.push(stagedCursor);
|
|
66108
66512
|
for (const candidate of candidates) {
|
|
@@ -66121,7 +66525,7 @@ function applyOpenCode(root, res) {
|
|
|
66121
66525
|
detail: "workit-opencode package has no loadable plugin entry (src/plugin.ts or dist/plugin.js)"
|
|
66122
66526
|
};
|
|
66123
66527
|
}
|
|
66124
|
-
|
|
66528
|
+
mkdirSync7(path32.dirname(res.opencodeConfig), { recursive: true });
|
|
66125
66529
|
const existing = readExisting(res.opencodeConfig);
|
|
66126
66530
|
if (existing.kind === "malformed") {
|
|
66127
66531
|
return {
|
|
@@ -66150,7 +66554,7 @@ function applyOpenCode(root, res) {
|
|
|
66150
66554
|
detail: "already registered"
|
|
66151
66555
|
};
|
|
66152
66556
|
}
|
|
66153
|
-
|
|
66557
|
+
writeFileSync8(res.opencodeConfig, JSON.stringify(merged.config, null, 2) + `
|
|
66154
66558
|
`, "utf8");
|
|
66155
66559
|
return existing.kind === "record" ? {
|
|
66156
66560
|
platform: "opencode",
|
|
@@ -66166,54 +66570,54 @@ function applyOpenCode(root, res) {
|
|
|
66166
66570
|
}
|
|
66167
66571
|
function copyPluginDir(src, dest) {
|
|
66168
66572
|
const realSrc = realpathSync7(src);
|
|
66169
|
-
const marker =
|
|
66170
|
-
const destIsLink =
|
|
66573
|
+
const marker = path32.join(dest, ".workit-root");
|
|
66574
|
+
const destIsLink = existsSync15(dest) && lstatSync6(dest).isSymbolicLink();
|
|
66171
66575
|
const synced = !destIsLink && readFileSafe(marker)?.trim() === realSrc && samePluginContent(realSrc, dest, dest);
|
|
66172
66576
|
if (synced)
|
|
66173
66577
|
return "Skipped";
|
|
66174
|
-
const hadDir =
|
|
66578
|
+
const hadDir = existsSync15(dest);
|
|
66175
66579
|
const rules = preservedCursorRules(realSrc, dest);
|
|
66176
|
-
const parent =
|
|
66177
|
-
|
|
66178
|
-
const swap = mkdtempSync2(
|
|
66179
|
-
const stage =
|
|
66180
|
-
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");
|
|
66181
66585
|
try {
|
|
66182
66586
|
cpSync4(realSrc, stage, {
|
|
66183
66587
|
recursive: true,
|
|
66184
|
-
filter: (entry) => !
|
|
66588
|
+
filter: (entry) => !path32.relative(realSrc, entry).split(path32.sep).includes("node_modules")
|
|
66185
66589
|
});
|
|
66186
|
-
const stagedHooks =
|
|
66187
|
-
if (
|
|
66188
|
-
|
|
66590
|
+
const stagedHooks = path32.join(stage, CURSOR_HOOKS_FILE);
|
|
66591
|
+
if (existsSync15(stagedHooks))
|
|
66592
|
+
writeFileSync8(stagedHooks, localizedCursorHooks(readFileSync15(stagedHooks), dest));
|
|
66189
66593
|
for (const [name, content] of rules) {
|
|
66190
|
-
|
|
66191
|
-
|
|
66594
|
+
mkdirSync7(path32.join(stage, "rules"), { recursive: true });
|
|
66595
|
+
writeFileSync8(path32.join(stage, "rules", name), content);
|
|
66192
66596
|
}
|
|
66193
|
-
|
|
66597
|
+
writeFileSync8(path32.join(stage, ".workit-root"), realSrc + `
|
|
66194
66598
|
`, "utf8");
|
|
66195
66599
|
if (!samePluginContent(realSrc, stage, dest))
|
|
66196
66600
|
throw new Error("staged adapter content is incomplete");
|
|
66197
|
-
if (
|
|
66601
|
+
if (lstatSync6(stage).isSymbolicLink()) {
|
|
66198
66602
|
throw new Error("staged adapter resolved to a symlink — refusing fragile cache install");
|
|
66199
66603
|
}
|
|
66200
66604
|
if (hadDir)
|
|
66201
|
-
|
|
66605
|
+
renameSync4(dest, backup);
|
|
66202
66606
|
try {
|
|
66203
|
-
|
|
66607
|
+
renameSync4(stage, dest);
|
|
66204
66608
|
} catch (error) {
|
|
66205
|
-
if (hadDir && !
|
|
66206
|
-
|
|
66609
|
+
if (hadDir && !existsSync15(dest))
|
|
66610
|
+
renameSync4(backup, dest);
|
|
66207
66611
|
throw error;
|
|
66208
66612
|
}
|
|
66209
|
-
|
|
66613
|
+
rmSync4(backup, { recursive: true, force: true });
|
|
66210
66614
|
} finally {
|
|
66211
|
-
|
|
66615
|
+
rmSync4(swap, { recursive: true, force: true });
|
|
66212
66616
|
}
|
|
66213
66617
|
return hadDir ? "Configured" : "Installed";
|
|
66214
66618
|
}
|
|
66215
66619
|
function applyCursorSettings(root, res) {
|
|
66216
|
-
|
|
66620
|
+
mkdirSync7(path32.dirname(res.cursorSettings), { recursive: true });
|
|
66217
66621
|
const settingsExisting = readExisting(res.cursorSettings);
|
|
66218
66622
|
if (settingsExisting.kind === "malformed") {
|
|
66219
66623
|
return {
|
|
@@ -66232,7 +66636,7 @@ function applyCursorSettings(root, res) {
|
|
|
66232
66636
|
detail: "already registered"
|
|
66233
66637
|
};
|
|
66234
66638
|
}
|
|
66235
|
-
|
|
66639
|
+
writeFileSync8(res.cursorSettings, JSON.stringify(settings.config, null, 2) + `
|
|
66236
66640
|
`, "utf8");
|
|
66237
66641
|
return {
|
|
66238
66642
|
platform: "cursor",
|
|
@@ -66241,7 +66645,7 @@ function applyCursorSettings(root, res) {
|
|
|
66241
66645
|
};
|
|
66242
66646
|
}
|
|
66243
66647
|
function applyCursorMcp(root, res) {
|
|
66244
|
-
|
|
66648
|
+
mkdirSync7(path32.dirname(res.cursorMcp), { recursive: true });
|
|
66245
66649
|
const mcpExisting = readExisting(res.cursorMcp);
|
|
66246
66650
|
if (mcpExisting.kind === "malformed") {
|
|
66247
66651
|
return {
|
|
@@ -66271,7 +66675,7 @@ function applyCursorMcp(root, res) {
|
|
|
66271
66675
|
detail: "already registered"
|
|
66272
66676
|
};
|
|
66273
66677
|
}
|
|
66274
|
-
|
|
66678
|
+
writeFileSync8(res.cursorMcp, JSON.stringify(mcp.config, null, 2) + `
|
|
66275
66679
|
`, "utf8");
|
|
66276
66680
|
return {
|
|
66277
66681
|
platform: "cursor",
|
|
@@ -66280,9 +66684,9 @@ function applyCursorMcp(root, res) {
|
|
|
66280
66684
|
};
|
|
66281
66685
|
}
|
|
66282
66686
|
function verifyPlatform(platform, res) {
|
|
66283
|
-
if (platform === "opencode" && !
|
|
66687
|
+
if (platform === "opencode" && !existsSync15(res.opencodeConfig))
|
|
66284
66688
|
return null;
|
|
66285
|
-
if (platform === "cursor" && !
|
|
66689
|
+
if (platform === "cursor" && !existsSync15(res.cursorSettings) && !existsSync15(res.cursorMcp)) {
|
|
66286
66690
|
return null;
|
|
66287
66691
|
}
|
|
66288
66692
|
return runDoctor({
|
|
@@ -66347,7 +66751,7 @@ function applySetupPreview(preview, options = {}) {
|
|
|
66347
66751
|
let cursorCopyOk = false;
|
|
66348
66752
|
for (const mutation of preview.mutations) {
|
|
66349
66753
|
if (mutation.type === "install-host") {
|
|
66350
|
-
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) : "";
|
|
66351
66755
|
if (mutation.path !== expectedPath) {
|
|
66352
66756
|
entries.push({
|
|
66353
66757
|
platform: mutation.platform,
|
|
@@ -66528,12 +66932,12 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66528
66932
|
return configured ?? fallback;
|
|
66529
66933
|
}, readConfigRecord = (file) => {
|
|
66530
66934
|
try {
|
|
66531
|
-
const value = JSON.parse(
|
|
66935
|
+
const value = JSON.parse(readFileSync15(file, "utf8"));
|
|
66532
66936
|
return isRecord5(value) ? value : null;
|
|
66533
66937
|
} catch {
|
|
66534
66938
|
return null;
|
|
66535
66939
|
}
|
|
66536
|
-
}, claudeInstallRecord = (home, env) =>
|
|
66940
|
+
}, claudeInstallRecord = (home, env) => path32.join(claudeConfigDir(home, env), "plugins", "installed_plugins.json"), resolveSetupPaths = (options, resolvedConfigDir) => {
|
|
66537
66941
|
const env = options.env ?? process.env;
|
|
66538
66942
|
const home = options.home ?? env.HOME ?? os9.homedir();
|
|
66539
66943
|
return {
|
|
@@ -66541,17 +66945,17 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66541
66945
|
configDir: resolvedConfigDir,
|
|
66542
66946
|
cwd: options.cwd ?? process.cwd(),
|
|
66543
66947
|
env,
|
|
66544
|
-
opencodeConfig: options.opencodeConfig ??
|
|
66545
|
-
cursorSettings: options.cursorSettings ??
|
|
66546
|
-
cursorMcp: options.cursorMcp ??
|
|
66547
|
-
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")
|
|
66548
66952
|
};
|
|
66549
66953
|
}, isRecord5 = (v) => v !== null && typeof v === "object" && !Array.isArray(v), readExisting = (p) => {
|
|
66550
66954
|
let raw;
|
|
66551
66955
|
try {
|
|
66552
|
-
raw =
|
|
66956
|
+
raw = readFileSync15(p, "utf8");
|
|
66553
66957
|
} catch {
|
|
66554
|
-
if (
|
|
66958
|
+
if (existsSync15(p))
|
|
66555
66959
|
return { kind: "malformed", error: `${p} is not readable` };
|
|
66556
66960
|
return { kind: "missing" };
|
|
66557
66961
|
}
|
|
@@ -66566,7 +66970,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66566
66970
|
return { kind: "malformed", error: `${p} is not a JSON object` };
|
|
66567
66971
|
}, readFileSafe = (p) => {
|
|
66568
66972
|
try {
|
|
66569
|
-
return
|
|
66973
|
+
return readFileSync15(p, "utf8");
|
|
66570
66974
|
} catch {
|
|
66571
66975
|
return null;
|
|
66572
66976
|
}
|
|
@@ -66581,7 +66985,7 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66581
66985
|
}
|
|
66582
66986
|
}, isAdapter = (root, platform) => {
|
|
66583
66987
|
try {
|
|
66584
|
-
const pkg = JSON.parse(
|
|
66988
|
+
const pkg = JSON.parse(readFileSync15(path32.join(root, "package.json"), "utf8"));
|
|
66585
66989
|
return pkg.name === `@brainervirus/workit-${platform}`;
|
|
66586
66990
|
} catch {
|
|
66587
66991
|
return false;
|
|
@@ -66595,8 +66999,8 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66595
66999
|
if (!isDevOpenCodeAdapterRoot(root, opts.dev))
|
|
66596
67000
|
return OPENCODE_NPM_PIN;
|
|
66597
67001
|
for (const rel of ["src/plugin.ts", "dist/plugin.js"]) {
|
|
66598
|
-
const entry =
|
|
66599
|
-
if (
|
|
67002
|
+
const entry = path32.join(root, rel);
|
|
67003
|
+
if (existsSync15(entry))
|
|
66600
67004
|
return `file://${entry}`;
|
|
66601
67005
|
}
|
|
66602
67006
|
return null;
|
|
@@ -66613,22 +67017,22 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66613
67017
|
for (const entry of readdirSync8(src, { withFileTypes: true })) {
|
|
66614
67018
|
if (entry.name === "node_modules")
|
|
66615
67019
|
continue;
|
|
66616
|
-
const source =
|
|
66617
|
-
const installed =
|
|
66618
|
-
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);
|
|
66619
67023
|
if (entry.isDirectory()) {
|
|
66620
|
-
if (!
|
|
67024
|
+
if (!statSync6(installed).isDirectory() || !samePluginContent(source, installed, pluginDir, rel))
|
|
66621
67025
|
return false;
|
|
66622
67026
|
} else {
|
|
66623
|
-
const expected = rel === CURSOR_HOOKS_FILE ? localizedCursorHooks(
|
|
66624
|
-
if (!expected.equals(
|
|
67027
|
+
const expected = rel === CURSOR_HOOKS_FILE ? localizedCursorHooks(readFileSync15(source), pluginDir) : readFileSync15(source);
|
|
67028
|
+
if (!expected.equals(readFileSync15(installed)))
|
|
66625
67029
|
return false;
|
|
66626
67030
|
}
|
|
66627
67031
|
}
|
|
66628
67032
|
for (const entry of readdirSync8(dest, { withFileTypes: true })) {
|
|
66629
|
-
if (
|
|
67033
|
+
if (existsSync15(path32.join(src, entry.name)))
|
|
66630
67034
|
continue;
|
|
66631
|
-
const rel =
|
|
67035
|
+
const rel = path32.join(relative, entry.name);
|
|
66632
67036
|
if (rel === ".workit-root")
|
|
66633
67037
|
continue;
|
|
66634
67038
|
if (relative === "rules" && entry.isFile() && entry.name.endsWith(".mdc"))
|
|
@@ -66641,36 +67045,36 @@ var TOKEN_PLACEHOLDER3 = "YOUR_TOKEN_HERE", YT_OVERRIDES, VCS_OVERRIDES, SETUP_O
|
|
|
66641
67045
|
}
|
|
66642
67046
|
}, preservedCursorRules = (src, dest) => {
|
|
66643
67047
|
const preserved = new Map;
|
|
66644
|
-
const sourceRules =
|
|
66645
|
-
const installedRules =
|
|
67048
|
+
const sourceRules = path32.join(src, "rules");
|
|
67049
|
+
const installedRules = path32.join(dest, "rules");
|
|
66646
67050
|
try {
|
|
66647
67051
|
for (const entry of readdirSync8(installedRules, { withFileTypes: true })) {
|
|
66648
67052
|
if (!entry.isFile() || !entry.name.endsWith(".mdc"))
|
|
66649
67053
|
continue;
|
|
66650
|
-
if (
|
|
67054
|
+
if (existsSync15(path32.join(sourceRules, entry.name)))
|
|
66651
67055
|
continue;
|
|
66652
|
-
preserved.set(entry.name,
|
|
67056
|
+
preserved.set(entry.name, readFileSync15(path32.join(installedRules, entry.name)));
|
|
66653
67057
|
}
|
|
66654
67058
|
} catch {}
|
|
66655
67059
|
return preserved;
|
|
66656
67060
|
}, removeLegacyCursorDir = (res) => {
|
|
66657
|
-
const legacy =
|
|
66658
|
-
if (legacy === res.cursorPluginDir || !
|
|
67061
|
+
const legacy = path32.join(res.home, ".cursor", "plugins", "local", "workflow-toolkit");
|
|
67062
|
+
if (legacy === res.cursorPluginDir || !existsSync15(legacy))
|
|
66659
67063
|
return;
|
|
66660
|
-
const legacyRules =
|
|
66661
|
-
if (
|
|
67064
|
+
const legacyRules = path32.join(legacy, "rules");
|
|
67065
|
+
if (existsSync15(legacyRules)) {
|
|
66662
67066
|
try {
|
|
66663
|
-
|
|
67067
|
+
mkdirSync7(path32.join(res.cursorPluginDir, "rules"), { recursive: true });
|
|
66664
67068
|
for (const entry of readdirSync8(legacyRules, { withFileTypes: true })) {
|
|
66665
67069
|
if (!entry.isFile() || !entry.name.endsWith(".mdc"))
|
|
66666
67070
|
continue;
|
|
66667
|
-
const target =
|
|
66668
|
-
if (!
|
|
66669
|
-
copyFileSync4(
|
|
67071
|
+
const target = path32.join(res.cursorPluginDir, "rules", entry.name);
|
|
67072
|
+
if (!existsSync15(target))
|
|
67073
|
+
copyFileSync4(path32.join(legacyRules, entry.name), target);
|
|
66670
67074
|
}
|
|
66671
67075
|
} catch {}
|
|
66672
67076
|
}
|
|
66673
|
-
|
|
67077
|
+
rmSync4(legacy, { recursive: true, force: true });
|
|
66674
67078
|
}, failedDetail = (report) => report.checks.filter((c) => c.status === "fail").map((c) => `${c.id}: ${c.detail}`).join("; "), setupCompletionGuidance = () => [
|
|
66675
67079
|
"Run `workit doctor` to verify your installation.",
|
|
66676
67080
|
"Run /wk-status in OpenCode to review token setup steps."
|
|
@@ -66700,16 +67104,16 @@ var init_setup = __esm(() => {
|
|
|
66700
67104
|
{ envKey: "WORKFLOW_GITHUB_HOST", affects: "vcs.json github.host" }
|
|
66701
67105
|
];
|
|
66702
67106
|
SETUP_OVERRIDES = [...YT_OVERRIDES, ...VCS_OVERRIDES];
|
|
66703
|
-
CURSOR_HOOKS_FILE =
|
|
67107
|
+
CURSOR_HOOKS_FILE = path32.join("hooks", "hooks-cursor.json");
|
|
66704
67108
|
});
|
|
66705
67109
|
|
|
66706
67110
|
// packages/workit-core/src/core/workspace-branch-policy.ts
|
|
66707
|
-
import { mkdirSync as
|
|
66708
|
-
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";
|
|
66709
67113
|
import { isDeepStrictEqual as isDeepStrictEqual3 } from "node:util";
|
|
66710
67114
|
function applyWorkspaceBranchPolicy(opts) {
|
|
66711
67115
|
const { workspace_root, env = process.env } = opts;
|
|
66712
|
-
const dir =
|
|
67116
|
+
const dir = path33.join(env.WORKFLOW_TOOLKIT_CONFIG ?? configDir());
|
|
66713
67117
|
const {
|
|
66714
67118
|
status,
|
|
66715
67119
|
path: wsPath,
|
|
@@ -66721,7 +67125,7 @@ function applyWorkspaceBranchPolicy(opts) {
|
|
|
66721
67125
|
if (status === "malformed" || status === "invalid")
|
|
66722
67126
|
return { ok: false, error: workspacesError ?? `invalid workspaces.json: ${wsPath}` };
|
|
66723
67127
|
const detection = detectBranchPolicy(workspace_root);
|
|
66724
|
-
const name = String(env.WORKFLOW_BP_NAME ??
|
|
67128
|
+
const name = String(env.WORKFLOW_BP_NAME ?? path33.basename(workspace_root));
|
|
66725
67129
|
const integration = env.WORKFLOW_BP_INTEGRATION ?? detection.integration;
|
|
66726
67130
|
const policy = {
|
|
66727
67131
|
preset: detection.preset,
|
|
@@ -66770,22 +67174,22 @@ function applyWorkspaceBranchPolicy(opts) {
|
|
|
66770
67174
|
ok: false,
|
|
66771
67175
|
error: `workspaces.json changed while applying the branch policy: ${wsPath}`
|
|
66772
67176
|
};
|
|
66773
|
-
|
|
67177
|
+
mkdirSync8(path33.dirname(wsPath), { recursive: true });
|
|
66774
67178
|
const tmp = `${wsPath}.${process.pid}.tmp`;
|
|
66775
67179
|
try {
|
|
66776
|
-
|
|
67180
|
+
writeFileSync9(tmp, JSON.stringify({ ...document2, workspaces: next }, null, 2) + `
|
|
66777
67181
|
`, "utf8");
|
|
66778
67182
|
if (workspacesRevision(readFileSafe2(wsPath)) !== revision) {
|
|
66779
|
-
|
|
67183
|
+
rmSync5(tmp, { force: true });
|
|
66780
67184
|
return {
|
|
66781
67185
|
ok: false,
|
|
66782
67186
|
error: `workspaces.json changed while applying the branch policy: ${wsPath}`
|
|
66783
67187
|
};
|
|
66784
67188
|
}
|
|
66785
|
-
|
|
67189
|
+
renameSync5(tmp, wsPath);
|
|
66786
67190
|
} catch (error) {
|
|
66787
67191
|
try {
|
|
66788
|
-
|
|
67192
|
+
rmSync5(tmp, { force: true });
|
|
66789
67193
|
} catch {}
|
|
66790
67194
|
return {
|
|
66791
67195
|
ok: false,
|
|
@@ -66802,7 +67206,7 @@ function applyWorkspaceBranchPolicy(opts) {
|
|
|
66802
67206
|
}
|
|
66803
67207
|
var readFileSafe2 = (p) => {
|
|
66804
67208
|
try {
|
|
66805
|
-
return
|
|
67209
|
+
return readFileSync16(p, "utf8");
|
|
66806
67210
|
} catch {
|
|
66807
67211
|
return null;
|
|
66808
67212
|
}
|
|
@@ -67054,8 +67458,8 @@ var init_logic = __esm(() => {
|
|
|
67054
67458
|
});
|
|
67055
67459
|
|
|
67056
67460
|
// packages/workit-cli/src/wizard-state.ts
|
|
67057
|
-
import { existsSync as
|
|
67058
|
-
import
|
|
67461
|
+
import { existsSync as existsSync16, statSync as statSync7 } from "node:fs";
|
|
67462
|
+
import path34 from "node:path";
|
|
67059
67463
|
import { isDeepStrictEqual as isDeepStrictEqual4 } from "node:util";
|
|
67060
67464
|
function resolveBasePath(values, env = process.env) {
|
|
67061
67465
|
return env.WORKFLOW_WORKSPACE_ROOT?.trim() || values.basePath.trim();
|
|
@@ -67574,7 +67978,7 @@ function workspaceDraftText(draft, field, value) {
|
|
|
67574
67978
|
}
|
|
67575
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) => {
|
|
67576
67980
|
try {
|
|
67577
|
-
return
|
|
67981
|
+
return statSync7(p).isDirectory();
|
|
67578
67982
|
} catch {
|
|
67579
67983
|
return false;
|
|
67580
67984
|
}
|
|
@@ -67582,8 +67986,8 @@ var NEXT, PREV, skipsCustomBranch = (screen, preset) => (screen === "branchAllow
|
|
|
67582
67986
|
const p = value.trim();
|
|
67583
67987
|
if (!p)
|
|
67584
67988
|
return "workspace root path is required";
|
|
67585
|
-
return !
|
|
67586
|
-
}, 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;
|
|
67587
67991
|
var init_wizard_state = __esm(() => {
|
|
67588
67992
|
init_config();
|
|
67589
67993
|
init_workspaces();
|
|
@@ -67642,9 +68046,9 @@ var init_wizard_state = __esm(() => {
|
|
|
67642
68046
|
});
|
|
67643
68047
|
|
|
67644
68048
|
// packages/workit-cli/src/admin/uninstall.ts
|
|
67645
|
-
import { existsSync as
|
|
68049
|
+
import { existsSync as existsSync17, readFileSync as readFileSync17, realpathSync as realpathSync8, rmSync as rmSync6, writeFileSync as writeFileSync10 } from "node:fs";
|
|
67646
68050
|
import os10 from "node:os";
|
|
67647
|
-
import
|
|
68051
|
+
import path35 from "node:path";
|
|
67648
68052
|
function cleanCursorSettings(settings, pluginDir) {
|
|
67649
68053
|
const next = { ...settings };
|
|
67650
68054
|
let changed = false;
|
|
@@ -67744,7 +68148,7 @@ function planUninstall(paths = {}) {
|
|
|
67744
68148
|
const mcpExisting = readJsonRecord(res.cursorMcp);
|
|
67745
68149
|
const settingsDirty = settingsExisting.kind === "malformed" || settingsExisting.kind === "record" && cleanCursorSettings(settingsExisting.value, res.cursorPluginDir).changed;
|
|
67746
68150
|
const mcpDirty = mcpExisting.kind === "malformed" || mcpExisting.kind === "record" && cleanCursorMcp(mcpExisting.value).changed;
|
|
67747
|
-
const dirExists =
|
|
68151
|
+
const dirExists = existsSync17(res.cursorPluginDir);
|
|
67748
68152
|
const actions = [];
|
|
67749
68153
|
if (settingsDirty) {
|
|
67750
68154
|
actions.push({
|
|
@@ -67772,7 +68176,7 @@ function planUninstall(paths = {}) {
|
|
|
67772
68176
|
installed: settingsDirty || mcpDirty || dirExists,
|
|
67773
68177
|
actions
|
|
67774
68178
|
};
|
|
67775
|
-
const codexInstalled =
|
|
68179
|
+
const codexInstalled = existsSync17(res.codexPluginDir);
|
|
67776
68180
|
const codex = {
|
|
67777
68181
|
host: "codex",
|
|
67778
68182
|
installed: codexInstalled,
|
|
@@ -67819,17 +68223,17 @@ function applyUninstall(plan, paths = {}) {
|
|
|
67819
68223
|
status = outcome.status;
|
|
67820
68224
|
detail = outcome.detail;
|
|
67821
68225
|
} else if (action.kind === "remove-dir") {
|
|
67822
|
-
const resolved =
|
|
67823
|
-
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";
|
|
67824
68228
|
if (!allowed) {
|
|
67825
68229
|
status = "failed";
|
|
67826
68230
|
detail = `refusing to remove non-canonical plugin directory: ${resolved}`;
|
|
67827
|
-
} else if (!
|
|
68231
|
+
} else if (!existsSync17(resolved)) {
|
|
67828
68232
|
status = "skipped";
|
|
67829
68233
|
detail = "directory already absent";
|
|
67830
68234
|
} else {
|
|
67831
68235
|
try {
|
|
67832
|
-
|
|
68236
|
+
rmSync6(resolved, { recursive: true, force: true });
|
|
67833
68237
|
status = "removed";
|
|
67834
68238
|
} catch (error) {
|
|
67835
68239
|
status = "failed";
|
|
@@ -67855,19 +68259,19 @@ function applyUninstall(plan, paths = {}) {
|
|
|
67855
68259
|
var resolveUninstallPaths = (options = {}) => {
|
|
67856
68260
|
const home = options.home ?? options.env?.HOME ?? os10.homedir();
|
|
67857
68261
|
return {
|
|
67858
|
-
opencodeConfig: options.opencodeConfig ??
|
|
67859
|
-
cursorSettings: options.cursorSettings ??
|
|
67860
|
-
cursorMcp: options.cursorMcp ??
|
|
67861
|
-
cursorPluginDir: options.cursorPluginDir ??
|
|
67862
|
-
codexPluginDir:
|
|
67863
|
-
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")
|
|
67864
68268
|
};
|
|
67865
68269
|
}, isRecord6 = (v) => v !== null && typeof v === "object" && !Array.isArray(v), readJsonRecord = (file) => {
|
|
67866
68270
|
let raw;
|
|
67867
68271
|
try {
|
|
67868
|
-
raw =
|
|
68272
|
+
raw = readFileSync17(file, "utf8");
|
|
67869
68273
|
} catch {
|
|
67870
|
-
if (
|
|
68274
|
+
if (existsSync17(file))
|
|
67871
68275
|
return { kind: "malformed", error: `${file} is not readable` };
|
|
67872
68276
|
return { kind: "missing" };
|
|
67873
68277
|
}
|
|
@@ -67878,8 +68282,8 @@ var resolveUninstallPaths = (options = {}) => {
|
|
|
67878
68282
|
return { kind: "malformed", error: `${file} is not valid JSON` };
|
|
67879
68283
|
}
|
|
67880
68284
|
}, stripTrailingSep = (p) => {
|
|
67881
|
-
const j =
|
|
67882
|
-
return
|
|
68285
|
+
const j = path35.join(p);
|
|
68286
|
+
return path35.dirname(j) === j ? j : j.replace(/[\\/]+$/, "");
|
|
67883
68287
|
}, CURSOR_LEGACY_IDENTITIES, jsonCleanerFor = (target, res) => {
|
|
67884
68288
|
if (target === res.opencodeConfig)
|
|
67885
68289
|
return cleanOpenCodeConfig;
|
|
@@ -67891,8 +68295,8 @@ var resolveUninstallPaths = (options = {}) => {
|
|
|
67891
68295
|
return cleanPiConfig;
|
|
67892
68296
|
return null;
|
|
67893
68297
|
}, canonicalRemoveDirAllowed = (actionPath, res) => {
|
|
67894
|
-
const expected =
|
|
67895
|
-
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")) {
|
|
67896
68300
|
return false;
|
|
67897
68301
|
}
|
|
67898
68302
|
try {
|
|
@@ -67915,7 +68319,7 @@ var resolveUninstallPaths = (options = {}) => {
|
|
|
67915
68319
|
`;
|
|
67916
68320
|
let current;
|
|
67917
68321
|
try {
|
|
67918
|
-
current =
|
|
68322
|
+
current = readFileSync17(target, "utf8");
|
|
67919
68323
|
} catch (error) {
|
|
67920
68324
|
return {
|
|
67921
68325
|
status: "failed",
|
|
@@ -67926,7 +68330,7 @@ var resolveUninstallPaths = (options = {}) => {
|
|
|
67926
68330
|
return { status: "skipped", detail: "already clean" };
|
|
67927
68331
|
}
|
|
67928
68332
|
try {
|
|
67929
|
-
|
|
68333
|
+
writeFileSync10(target, serialized, "utf8");
|
|
67930
68334
|
} catch (error) {
|
|
67931
68335
|
return {
|
|
67932
68336
|
status: "failed",
|
|
@@ -67944,7 +68348,7 @@ var resolveUninstallPaths = (options = {}) => {
|
|
|
67944
68348
|
};
|
|
67945
68349
|
const home = paths.home ?? paths.env?.HOME ?? os10.homedir();
|
|
67946
68350
|
const env = paths.env ?? process.env;
|
|
67947
|
-
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 ?? "")));
|
|
67948
68352
|
if (!recorded)
|
|
67949
68353
|
return { status: "skipped", detail: `${id} (${scope} scope) is no longer installed` };
|
|
67950
68354
|
const executable = findHostExecutable("claude", { home, env });
|
|
@@ -70423,9 +70827,9 @@ var init_src2 = __esm(async () => {
|
|
|
70423
70827
|
// packages/workit-cli/src/verbs/init.ts
|
|
70424
70828
|
var exports_init = {};
|
|
70425
70829
|
__export(exports_init, {
|
|
70426
|
-
run: () =>
|
|
70830
|
+
run: () => run3
|
|
70427
70831
|
});
|
|
70428
|
-
async function
|
|
70832
|
+
async function run3(_argv, io) {
|
|
70429
70833
|
if (io.json)
|
|
70430
70834
|
return emit(io, fail("invalid_input", "workit init is an interactive wizard and has no --json output", {
|
|
70431
70835
|
unblock: "run `workit init` in a terminal without --json"
|
|
@@ -70439,19 +70843,19 @@ var init_init = __esm(() => {
|
|
|
70439
70843
|
});
|
|
70440
70844
|
|
|
70441
70845
|
// packages/workit-cli/src/upgrade.ts
|
|
70442
|
-
import { spawnSync as
|
|
70846
|
+
import { spawnSync as spawnSync15 } from "node:child_process";
|
|
70443
70847
|
import {
|
|
70444
|
-
existsSync as
|
|
70848
|
+
existsSync as existsSync18,
|
|
70445
70849
|
mkdtempSync as mkdtempSync3,
|
|
70446
|
-
rmSync as
|
|
70447
|
-
readFileSync as
|
|
70448
|
-
mkdirSync as
|
|
70850
|
+
rmSync as rmSync7,
|
|
70851
|
+
readFileSync as readFileSync18,
|
|
70852
|
+
mkdirSync as mkdirSync9,
|
|
70449
70853
|
copyFileSync as copyFileSync5,
|
|
70450
|
-
chmodSync,
|
|
70854
|
+
chmodSync as chmodSync2,
|
|
70451
70855
|
cpSync as cpSync5,
|
|
70452
|
-
lstatSync as
|
|
70856
|
+
lstatSync as lstatSync7
|
|
70453
70857
|
} from "node:fs";
|
|
70454
|
-
import
|
|
70858
|
+
import path36 from "node:path";
|
|
70455
70859
|
import os12 from "node:os";
|
|
70456
70860
|
import { createHash as createHash14 } from "node:crypto";
|
|
70457
70861
|
function previewUpgrade(hosts = HOSTS2, deps = {}) {
|
|
@@ -70475,9 +70879,9 @@ function previewUpgrade(hosts = HOSTS2, deps = {}) {
|
|
|
70475
70879
|
for (const file of [
|
|
70476
70880
|
paths.opencodeConfig,
|
|
70477
70881
|
paths.opencodeConfig + "c",
|
|
70478
|
-
|
|
70479
|
-
|
|
70480
|
-
|
|
70882
|
+
path36.join(home, ".cursor/settings.json"),
|
|
70883
|
+
path36.join(home, ".cursor/mcp.json"),
|
|
70884
|
+
path36.join(home, ".cursor/plugins/local/workit/package.json"),
|
|
70481
70885
|
paths.codexConfig,
|
|
70482
70886
|
paths.piSettings
|
|
70483
70887
|
])
|
|
@@ -70492,20 +70896,20 @@ function previewUpgrade(hosts = HOSTS2, deps = {}) {
|
|
|
70492
70896
|
});
|
|
70493
70897
|
const installedSources = sources(paths, run, hosts);
|
|
70494
70898
|
if (installedSources.some((source) => source.host === "opencode")) {
|
|
70495
|
-
const scratch = mkdtempSync3(
|
|
70899
|
+
const scratch = mkdtempSync3(path36.join(os12.tmpdir(), "workit-upgrade-opencode-"));
|
|
70496
70900
|
let probe;
|
|
70497
70901
|
try {
|
|
70498
70902
|
probe = runner({
|
|
70499
70903
|
...deps,
|
|
70500
70904
|
env: {
|
|
70501
70905
|
...deps.env,
|
|
70502
|
-
XDG_DATA_HOME:
|
|
70503
|
-
XDG_STATE_HOME:
|
|
70504
|
-
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")
|
|
70505
70909
|
}
|
|
70506
70910
|
})("opencode", ["--version"]);
|
|
70507
70911
|
} finally {
|
|
70508
|
-
|
|
70912
|
+
rmSync7(scratch, { recursive: true, force: true });
|
|
70509
70913
|
}
|
|
70510
70914
|
const installed = probe.status === 0 ? probe.stdout.match(/\d+\.\d+\.\d+/)?.[0] : undefined;
|
|
70511
70915
|
if (installed && !versionAtLeast(installed, SUPPORT_MATRIX.opencode.minimum))
|
|
@@ -70547,7 +70951,7 @@ function previewUpgrade(hosts = HOSTS2, deps = {}) {
|
|
|
70547
70951
|
env: deps.env,
|
|
70548
70952
|
cwd: home,
|
|
70549
70953
|
packageVersion: latest.stdout.trim(),
|
|
70550
|
-
targetDir:
|
|
70954
|
+
targetDir: path36.join(home, ".cursor/plugins/local/workit")
|
|
70551
70955
|
});
|
|
70552
70956
|
plan.entries.push({
|
|
70553
70957
|
host: source.host,
|
|
@@ -70577,13 +70981,13 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
70577
70981
|
ok: false,
|
|
70578
70982
|
error: "Stop the selected running hosts before upgrading their loaded plugins"
|
|
70579
70983
|
};
|
|
70580
|
-
const backup =
|
|
70581
|
-
|
|
70984
|
+
const backup = path36.join(home, ".local/state/workit/upgrades", new Date().toISOString().replaceAll(":", "-"));
|
|
70985
|
+
mkdirSync9(backup, { recursive: true, mode: 448 });
|
|
70582
70986
|
for (const file of Object.keys(plan.configDigests))
|
|
70583
|
-
if (
|
|
70584
|
-
const target =
|
|
70987
|
+
if (existsSync18(file)) {
|
|
70988
|
+
const target = path36.join(backup, createHash14("sha256").update(file).digest("hex").slice(0, 12) + "-" + path36.basename(file));
|
|
70585
70989
|
copyFileSync5(file, target);
|
|
70586
|
-
|
|
70990
|
+
chmodSync2(target, 384);
|
|
70587
70991
|
}
|
|
70588
70992
|
for (const migration of plan.migrations) {
|
|
70589
70993
|
const value = object2(migration.file);
|
|
@@ -70598,9 +71002,9 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
70598
71002
|
`, 384);
|
|
70599
71003
|
}
|
|
70600
71004
|
const run = runner(deps);
|
|
70601
|
-
const cursorRoot =
|
|
70602
|
-
if (plan.entries.some((entry) => entry.host === "cursor") &&
|
|
70603
|
-
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 });
|
|
70604
71008
|
for (const entry of plan.entries) {
|
|
70605
71009
|
if (entry.host === "opencode")
|
|
70606
71010
|
return {
|
|
@@ -70620,7 +71024,7 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
70620
71024
|
{
|
|
70621
71025
|
type: "install-host",
|
|
70622
71026
|
platform: "cursor",
|
|
70623
|
-
path:
|
|
71027
|
+
path: path36.join(home, ".cursor/plugins/local/.workit-package-bootstrap"),
|
|
70624
71028
|
commands: entry.commands.map((command) => ({
|
|
70625
71029
|
...command,
|
|
70626
71030
|
purpose: command.purpose ?? "Upgrade Cursor"
|
|
@@ -70629,7 +71033,7 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
70629
71033
|
{
|
|
70630
71034
|
type: "install-adapter",
|
|
70631
71035
|
platform: "cursor",
|
|
70632
|
-
path:
|
|
71036
|
+
path: path36.join(home, ".cursor/plugins/local/workit")
|
|
70633
71037
|
}
|
|
70634
71038
|
]
|
|
70635
71039
|
};
|
|
@@ -70643,7 +71047,7 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
70643
71047
|
return { exitCode: outcome.status ?? 1, stdout: outcome.stdout, stderr: "" };
|
|
70644
71048
|
}
|
|
70645
71049
|
});
|
|
70646
|
-
const pkg = object2(
|
|
71050
|
+
const pkg = object2(path36.join(home, ".cursor/plugins/local/workit/package.json"));
|
|
70647
71051
|
if (!result.ok || pkg?.version !== entry.latest)
|
|
70648
71052
|
return {
|
|
70649
71053
|
ok: false,
|
|
@@ -70677,15 +71081,15 @@ function applyUpgrade(plan, deps = {}) {
|
|
|
70677
71081
|
const currentRoot = run("npm", ["root", "--global"]);
|
|
70678
71082
|
if (currentRoot.status !== 0 || currentRoot.stdout.trim() !== plan.cli.root)
|
|
70679
71083
|
return { ok: false, backup, error: "Global npm location changed; preview again" };
|
|
70680
|
-
const cliBackup =
|
|
70681
|
-
cpSync5(
|
|
71084
|
+
const cliBackup = path36.join(backup, "cli-package");
|
|
71085
|
+
cpSync5(path36.join(plan.cli.root, "@brainervirus/workit-cli"), cliBackup, { recursive: true });
|
|
70682
71086
|
if (run("npm", ["install", "--global", `@brainervirus/workit-cli@${plan.cli.latest}`]).status !== 0)
|
|
70683
71087
|
return {
|
|
70684
71088
|
ok: false,
|
|
70685
71089
|
backup,
|
|
70686
|
-
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")}`
|
|
70687
71091
|
};
|
|
70688
|
-
const installed = object2(
|
|
71092
|
+
const installed = object2(path36.join(plan.cli.root, "@brainervirus/workit-cli/package.json"));
|
|
70689
71093
|
if (installed?.name !== "@brainervirus/workit-cli" || installed.version !== plan.cli.latest)
|
|
70690
71094
|
return {
|
|
70691
71095
|
ok: false,
|
|
@@ -70710,12 +71114,12 @@ async function runUpgradeCommand(argv, deps = {}) {
|
|
|
70710
71114
|
if (flags.has("--cli")) {
|
|
70711
71115
|
const run = runner(deps);
|
|
70712
71116
|
const root = run("npm", ["root", "--global"]);
|
|
70713
|
-
if (root.status !== 0 || !
|
|
71117
|
+
if (root.status !== 0 || !path36.isAbsolute(root.stdout.trim())) {
|
|
70714
71118
|
plan.blocked.push("Global npm location could not be verified");
|
|
70715
71119
|
} else {
|
|
70716
|
-
const packageFile =
|
|
71120
|
+
const packageFile = path36.join(root.stdout.trim(), "@brainervirus/workit-cli/package.json");
|
|
70717
71121
|
const pkg = object2(packageFile);
|
|
70718
|
-
if (pkg?.name !== "@brainervirus/workit-cli" ||
|
|
71122
|
+
if (pkg?.name !== "@brainervirus/workit-cli" || lstatSync7(path36.dirname(packageFile)).isSymbolicLink()) {
|
|
70719
71123
|
plan.skipped.push({
|
|
70720
71124
|
host: "cli",
|
|
70721
71125
|
reason: "No managed global CLI install (local links preserved); use npx @brainervirus/workit-cli@latest"
|
|
@@ -70795,7 +71199,7 @@ async function runLaunchCommand(argv, deps = {}) {
|
|
|
70795
71199
|
}
|
|
70796
71200
|
if (deps.run)
|
|
70797
71201
|
return deps.run(host, hostArgs).status ?? 1;
|
|
70798
|
-
return
|
|
71202
|
+
return spawnSync15(launch.command, launch.args, {
|
|
70799
71203
|
stdio: "inherit",
|
|
70800
71204
|
env
|
|
70801
71205
|
}).status ?? 1;
|
|
@@ -70806,37 +71210,37 @@ var HOSTS2, upgradePaths = (deps) => {
|
|
|
70806
71210
|
...process.env,
|
|
70807
71211
|
...deps.home || deps.env?.HOME ? {
|
|
70808
71212
|
HOME: home,
|
|
70809
|
-
CODEX_HOME:
|
|
70810
|
-
PI_CODING_AGENT_DIR:
|
|
70811
|
-
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"),
|
|
70812
71216
|
WORKFLOW_TOOLKIT_CONFIG: undefined,
|
|
70813
71217
|
WORKFLOW_TOOLKIT_CONFIG_DIR: undefined
|
|
70814
71218
|
} : {},
|
|
70815
71219
|
...deps.env,
|
|
70816
71220
|
HOME: home
|
|
70817
71221
|
};
|
|
70818
|
-
const xdg = env.XDG_CONFIG_HOME ||
|
|
71222
|
+
const xdg = env.XDG_CONFIG_HOME || path36.join(home, ".config");
|
|
70819
71223
|
return {
|
|
70820
71224
|
home,
|
|
70821
71225
|
env,
|
|
70822
|
-
configDir: env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ??
|
|
70823
|
-
opencodeConfig:
|
|
70824
|
-
piSettings:
|
|
70825
|
-
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")
|
|
70826
71230
|
};
|
|
70827
71231
|
}, object2 = (file) => {
|
|
70828
|
-
if (!
|
|
71232
|
+
if (!existsSync18(file))
|
|
70829
71233
|
return null;
|
|
70830
71234
|
let data;
|
|
70831
71235
|
try {
|
|
70832
|
-
data = JSON.parse(
|
|
71236
|
+
data = JSON.parse(readFileSync18(file, "utf8"));
|
|
70833
71237
|
} catch {
|
|
70834
71238
|
throw new Error(`${file} is not valid JSON; use the native host to inspect JSONC settings`);
|
|
70835
71239
|
}
|
|
70836
71240
|
if (!data || typeof data !== "object" || Array.isArray(data))
|
|
70837
71241
|
throw new Error(`${file} is not a configuration object`);
|
|
70838
71242
|
return data;
|
|
70839
|
-
}, digest2 = (file) =>
|
|
71243
|
+
}, digest2 = (file) => existsSync18(file) ? createHash14("sha256").update(readFileSync18(file)).digest("hex") : "missing", runner = (deps) => deps.run ?? ((command, args) => {
|
|
70840
71244
|
const { home, env } = upgradePaths(deps);
|
|
70841
71245
|
let step;
|
|
70842
71246
|
try {
|
|
@@ -70853,7 +71257,7 @@ var HOSTS2, upgradePaths = (deps) => {
|
|
|
70853
71257
|
}), sources = (paths, run, hosts) => {
|
|
70854
71258
|
const { home, opencodeConfig, piSettings } = paths;
|
|
70855
71259
|
const result = [];
|
|
70856
|
-
if (hosts.includes("opencode") &&
|
|
71260
|
+
if (hosts.includes("opencode") && existsSync18(opencodeConfig + "c"))
|
|
70857
71261
|
throw new Error("OpenCode JSONC config is present; inspect effective native configuration before updating");
|
|
70858
71262
|
const oc = hosts.includes("opencode") ? object2(opencodeConfig) : null;
|
|
70859
71263
|
if (oc && [oc.plugins, oc.plugin].some((value) => value !== undefined && !Array.isArray(value)))
|
|
@@ -70862,9 +71266,9 @@ var HOSTS2, upgradePaths = (deps) => {
|
|
|
70862
71266
|
for (const pin of plugins)
|
|
70863
71267
|
if (typeof pin === "string" && isWorkitPlugin(pin))
|
|
70864
71268
|
result.push(classify("opencode", pin));
|
|
70865
|
-
const cursor = hosts.includes("cursor") ? object2(
|
|
71269
|
+
const cursor = hosts.includes("cursor") ? object2(path36.join(home, ".cursor/plugins/local/workit/package.json")) : null;
|
|
70866
71270
|
if (cursor?.name === "@brainervirus/workit-cursor") {
|
|
70867
|
-
const mcp = object2(
|
|
71271
|
+
const mcp = object2(path36.join(home, ".cursor/mcp.json"));
|
|
70868
71272
|
const args = mcp?.mcpServers?.workit?.args ?? [];
|
|
70869
71273
|
const selector = args.find((arg) => typeof arg === "string" && arg.startsWith("--package="));
|
|
70870
71274
|
result.push(classify("cursor", typeof selector === "string" ? selector.slice(10) : "local"));
|
|
@@ -70877,7 +71281,7 @@ var HOSTS2, upgradePaths = (deps) => {
|
|
|
70877
71281
|
if (typeof source !== "string")
|
|
70878
71282
|
continue;
|
|
70879
71283
|
const npm = /^(?:npm:)?@brainervirus\/workit-pi(?:@[^/]+)?$/.test(source);
|
|
70880
|
-
const local =
|
|
71284
|
+
const local = path36.isAbsolute(source) && source.replaceAll("\\", "/").endsWith("/packages/workit-pi") && object2(path36.join(source, "package.json"))?.name === "@brainervirus/workit-pi";
|
|
70881
71285
|
if (npm || local)
|
|
70882
71286
|
result.push(classify("pi", source));
|
|
70883
71287
|
}
|
|
@@ -70888,7 +71292,7 @@ var HOSTS2, upgradePaths = (deps) => {
|
|
|
70888
71292
|
hostCommand("codex", [], { home, env: paths.env });
|
|
70889
71293
|
available = true;
|
|
70890
71294
|
} catch {}
|
|
70891
|
-
if (available ||
|
|
71295
|
+
if (available || existsSync18(paths.codexConfig))
|
|
70892
71296
|
throw new Error("Codex plugin inventory failed; inspect the native host before upgrading");
|
|
70893
71297
|
}
|
|
70894
71298
|
if (listing.status === 0) {
|
|
@@ -70924,9 +71328,9 @@ var HOSTS2, upgradePaths = (deps) => {
|
|
|
70924
71328
|
}, piInstalledVersion = (listing, selector) => {
|
|
70925
71329
|
const lines = listing.split(/\r?\n/).map((line) => line.trim());
|
|
70926
71330
|
const index = lines.indexOf(selector);
|
|
70927
|
-
if (index < 0 || !lines[index + 1] || !
|
|
71331
|
+
if (index < 0 || !lines[index + 1] || !path36.isAbsolute(lines[index + 1]))
|
|
70928
71332
|
return;
|
|
70929
|
-
const pkg = object2(
|
|
71333
|
+
const pkg = object2(path36.join(lines[index + 1], "package.json"));
|
|
70930
71334
|
return pkg?.name === "@brainervirus/workit-pi" ? pkg.version : undefined;
|
|
70931
71335
|
}, versionAtLeast = (installed, latest) => {
|
|
70932
71336
|
if (!/^\d+\.\d+\.\d+$/.test(installed))
|
|
@@ -70959,9 +71363,9 @@ var init_upgrade = __esm(() => {
|
|
|
70959
71363
|
// packages/workit-cli/src/verbs/upgrade.ts
|
|
70960
71364
|
var exports_upgrade = {};
|
|
70961
71365
|
__export(exports_upgrade, {
|
|
70962
|
-
run: () =>
|
|
71366
|
+
run: () => run4
|
|
70963
71367
|
});
|
|
70964
|
-
var
|
|
71368
|
+
var run4 = (argv) => runUpgradeCommand(argv);
|
|
70965
71369
|
var init_upgrade2 = __esm(() => {
|
|
70966
71370
|
init_upgrade();
|
|
70967
71371
|
});
|
|
@@ -70969,17 +71373,17 @@ var init_upgrade2 = __esm(() => {
|
|
|
70969
71373
|
// packages/workit-cli/src/verbs/launch.ts
|
|
70970
71374
|
var exports_launch = {};
|
|
70971
71375
|
__export(exports_launch, {
|
|
70972
|
-
run: () =>
|
|
71376
|
+
run: () => run5
|
|
70973
71377
|
});
|
|
70974
|
-
var
|
|
71378
|
+
var run5 = (argv) => runLaunchCommand(argv);
|
|
70975
71379
|
var init_launch = __esm(() => {
|
|
70976
71380
|
init_upgrade();
|
|
70977
71381
|
});
|
|
70978
71382
|
|
|
70979
71383
|
// packages/workit-core/src/knowledge.ts
|
|
70980
|
-
import { spawnSync as
|
|
71384
|
+
import { spawnSync as spawnSync16 } from "node:child_process";
|
|
70981
71385
|
import fs17 from "node:fs";
|
|
70982
|
-
import
|
|
71386
|
+
import path37 from "node:path";
|
|
70983
71387
|
function lintKnowledge(root) {
|
|
70984
71388
|
const seen = new Set;
|
|
70985
71389
|
const unreadable = [];
|
|
@@ -71083,7 +71487,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
|
|
|
71083
71487
|
const end = lines.indexOf("---", 1);
|
|
71084
71488
|
return end === -1 ? lines : [...lines.slice(0, end + 1).map(() => ""), ...lines.slice(end + 1)];
|
|
71085
71489
|
}, read = (root, file) => {
|
|
71086
|
-
const full =
|
|
71490
|
+
const full = path37.join(root, file);
|
|
71087
71491
|
try {
|
|
71088
71492
|
fs17.lstatSync(full);
|
|
71089
71493
|
} catch {
|
|
@@ -71098,7 +71502,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
|
|
|
71098
71502
|
return "unreadable";
|
|
71099
71503
|
}
|
|
71100
71504
|
}, trackedTopLevel = (root) => {
|
|
71101
|
-
const run =
|
|
71505
|
+
const run = spawnSync16("git", ["ls-files", "-z", "--cached"], {
|
|
71102
71506
|
cwd: root,
|
|
71103
71507
|
encoding: "utf8",
|
|
71104
71508
|
maxBuffer: 256 * 1024 * 1024,
|
|
@@ -71108,7 +71512,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
|
|
|
71108
71512
|
if (run.status !== 0)
|
|
71109
71513
|
return null;
|
|
71110
71514
|
return new Set(run.stdout.split("\x00").filter(Boolean).map((file) => file.split("/")[0]));
|
|
71111
|
-
},
|
|
71515
|
+
}, exists2 = (target) => {
|
|
71112
71516
|
try {
|
|
71113
71517
|
fs17.statSync(target);
|
|
71114
71518
|
return true;
|
|
@@ -71124,7 +71528,7 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
|
|
|
71124
71528
|
}
|
|
71125
71529
|
}, brokenLinks = (root, doc, tracked) => {
|
|
71126
71530
|
const findings = [];
|
|
71127
|
-
const base =
|
|
71531
|
+
const base = path37.dirname(path37.join(root, doc.file));
|
|
71128
71532
|
const missing = (target, line, how) => findings.push({
|
|
71129
71533
|
rule: "broken-link",
|
|
71130
71534
|
file: doc.file,
|
|
@@ -71143,8 +71547,8 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
|
|
|
71143
71547
|
const local = localTarget(target);
|
|
71144
71548
|
if (!local)
|
|
71145
71549
|
continue;
|
|
71146
|
-
const resolved = local.startsWith("/") ?
|
|
71147
|
-
if (!
|
|
71550
|
+
const resolved = local.startsWith("/") ? path37.join(root, local) : path37.resolve(base, local);
|
|
71551
|
+
if (!exists2(resolved))
|
|
71148
71552
|
missing(target, index + 1, "link");
|
|
71149
71553
|
}
|
|
71150
71554
|
for (const [, span] of text.matchAll(CODE_SPAN)) {
|
|
@@ -71153,10 +71557,10 @@ var AGENTS_BYTE_BUDGET, STEERING_FILES, NEED_BASED_FILES, STANDARDS_FILE = "CODI
|
|
|
71153
71557
|
continue;
|
|
71154
71558
|
const relative = /^\.\.?\//.test(candidate);
|
|
71155
71559
|
const first = candidate.split("/")[0];
|
|
71156
|
-
if (!relative && !(tracked ? tracked.has(first) :
|
|
71560
|
+
if (!relative && !(tracked ? tracked.has(first) : exists2(path37.join(root, first))))
|
|
71157
71561
|
continue;
|
|
71158
|
-
const resolved = relative ?
|
|
71159
|
-
if (!
|
|
71562
|
+
const resolved = relative ? path37.resolve(base, candidate) : path37.join(root, candidate);
|
|
71563
|
+
if (!exists2(resolved))
|
|
71160
71564
|
missing(span, index + 1, "pointer");
|
|
71161
71565
|
}
|
|
71162
71566
|
}
|
|
@@ -71281,7 +71685,7 @@ var init_prompt = () => {};
|
|
|
71281
71685
|
// packages/workit-cli/src/verbs/doctor.ts
|
|
71282
71686
|
var exports_doctor = {};
|
|
71283
71687
|
__export(exports_doctor, {
|
|
71284
|
-
run: () =>
|
|
71688
|
+
run: () => run6
|
|
71285
71689
|
});
|
|
71286
71690
|
async function confirmForcedLockClear(root, args, io) {
|
|
71287
71691
|
const lock = inspectMetadataLock(root);
|
|
@@ -71304,7 +71708,7 @@ async function confirmForcedLockClear(root, args, io) {
|
|
|
71304
71708
|
return "cancelled";
|
|
71305
71709
|
return /^y(es)?$/i.test(answer.trim());
|
|
71306
71710
|
}
|
|
71307
|
-
async function
|
|
71711
|
+
async function run6(argv, io) {
|
|
71308
71712
|
const root = workspaceRootFor();
|
|
71309
71713
|
const force = argv.includes("--force");
|
|
71310
71714
|
let fixLock = null;
|
|
@@ -71322,6 +71726,18 @@ async function run5(argv, io) {
|
|
|
71322
71726
|
}
|
|
71323
71727
|
fixLock = clearStaleMetadataLock(root, { force });
|
|
71324
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
|
+
}
|
|
71325
71741
|
const report = runDoctor({
|
|
71326
71742
|
host: "cli",
|
|
71327
71743
|
cwd: io.cwd,
|
|
@@ -71344,7 +71760,7 @@ async function run5(argv, io) {
|
|
|
71344
71760
|
budget: knowledge.budget,
|
|
71345
71761
|
findings: knowledge.findings.length
|
|
71346
71762
|
} : { unavailable: true };
|
|
71347
|
-
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)}
|
|
71348
71764
|
`);
|
|
71349
71765
|
return report.exitCode;
|
|
71350
71766
|
}
|
|
@@ -71353,6 +71769,9 @@ async function run5(argv, io) {
|
|
|
71353
71769
|
io.stdout(`fix-lock: ${what}${fixLock.guardCleared ? "; removed abandoned reclaim guard" : ""}
|
|
71354
71770
|
`);
|
|
71355
71771
|
}
|
|
71772
|
+
if (sessionHook)
|
|
71773
|
+
io.stdout(`fix: session hook ${sessionHook.action}: ${sessionHook.detail}
|
|
71774
|
+
`);
|
|
71356
71775
|
io.stdout(`workit doctor — ${report.ok ? "healthy" : "problems found"} (${report.offline ? "offline" : "online"})
|
|
71357
71776
|
`);
|
|
71358
71777
|
for (const check of report.checks) {
|
|
@@ -71485,11 +71904,11 @@ var init_redact = __esm(() => {
|
|
|
71485
71904
|
});
|
|
71486
71905
|
|
|
71487
71906
|
// packages/workit-core/src/checks.ts
|
|
71488
|
-
import { spawn, spawnSync as
|
|
71907
|
+
import { spawn, spawnSync as spawnSync17 } from "node:child_process";
|
|
71489
71908
|
import { createHash as createHash15 } from "node:crypto";
|
|
71490
71909
|
import fs18 from "node:fs";
|
|
71491
71910
|
import os13 from "node:os";
|
|
71492
|
-
import
|
|
71911
|
+
import path38 from "node:path";
|
|
71493
71912
|
import { StringDecoder } from "node:string_decoder";
|
|
71494
71913
|
function tailLines(text, lines = TAIL_LINES) {
|
|
71495
71914
|
const all = text.replace(/\r\n?/gu, `
|
|
@@ -71609,7 +72028,7 @@ function planSpawn(argv, options) {
|
|
|
71609
72028
|
return { file: argv[0], args: [], verbatim: false, shell: true };
|
|
71610
72029
|
if (options.platform !== "win32")
|
|
71611
72030
|
return { file: argv[0], args: argv.slice(1), verbatim: false, shell: false };
|
|
71612
|
-
const win =
|
|
72031
|
+
const win = path38.win32;
|
|
71613
72032
|
const isFile = options.isFile ?? ((file) => {
|
|
71614
72033
|
try {
|
|
71615
72034
|
return fs18.statSync(file).isFile();
|
|
@@ -71664,7 +72083,7 @@ function runCheckCommand(argv, options) {
|
|
|
71664
72083
|
if (!child?.pid)
|
|
71665
72084
|
return;
|
|
71666
72085
|
if (windows)
|
|
71667
|
-
|
|
72086
|
+
spawnSync17("taskkill", ["/pid", String(child.pid), "/T", "/F"], {
|
|
71668
72087
|
stdio: "ignore",
|
|
71669
72088
|
windowsHide: true
|
|
71670
72089
|
});
|
|
@@ -71766,10 +72185,10 @@ function runCheckCommand(argv, options) {
|
|
|
71766
72185
|
function storeLog(storeRoot, log) {
|
|
71767
72186
|
const digest = logDigest(log);
|
|
71768
72187
|
const ref = `blobs/logs/${digest.slice("sha256:".length)}.log`;
|
|
71769
|
-
const file =
|
|
72188
|
+
const file = path38.join(storeRoot, ref);
|
|
71770
72189
|
try {
|
|
71771
72190
|
if (!fs18.existsSync(file)) {
|
|
71772
|
-
fs18.mkdirSync(
|
|
72191
|
+
fs18.mkdirSync(path38.dirname(file), { recursive: true });
|
|
71773
72192
|
const temp = `${file}.${process.pid}.${Date.now()}.tmp`;
|
|
71774
72193
|
fs18.writeFileSync(temp, log, { mode: 384 });
|
|
71775
72194
|
fs18.renameSync(temp, file);
|
|
@@ -71782,7 +72201,7 @@ function storeLog(storeRoot, log) {
|
|
|
71782
72201
|
function pruneCheckLogs(storeRoot, options = {}) {
|
|
71783
72202
|
const limits = { ...LOG_RETENTION, ...options.retention };
|
|
71784
72203
|
const now = options.now ?? Date.now();
|
|
71785
|
-
const dir =
|
|
72204
|
+
const dir = path38.join(storeRoot, "blobs", "logs");
|
|
71786
72205
|
const report = { removed: 0, removedBytes: 0, kept: 0 };
|
|
71787
72206
|
let names;
|
|
71788
72207
|
try {
|
|
@@ -71792,7 +72211,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
|
|
|
71792
72211
|
}
|
|
71793
72212
|
const files = names.flatMap((name) => {
|
|
71794
72213
|
try {
|
|
71795
|
-
const stat = fs18.statSync(
|
|
72214
|
+
const stat = fs18.statSync(path38.join(dir, name));
|
|
71796
72215
|
return stat.isFile() ? [{ name, size: stat.size, mtimeMs: stat.mtimeMs }] : [];
|
|
71797
72216
|
} catch {
|
|
71798
72217
|
return [];
|
|
@@ -71811,7 +72230,7 @@ function pruneCheckLogs(storeRoot, options = {}) {
|
|
|
71811
72230
|
continue;
|
|
71812
72231
|
if (!options.dryRun)
|
|
71813
72232
|
try {
|
|
71814
|
-
fs18.rmSync(
|
|
72233
|
+
fs18.rmSync(path38.join(dir, file.name), { force: true });
|
|
71815
72234
|
} catch {
|
|
71816
72235
|
continue;
|
|
71817
72236
|
}
|
|
@@ -71842,9 +72261,9 @@ var init_checks3 = __esm(() => {
|
|
|
71842
72261
|
// packages/workit-cli/src/verbs/gc.ts
|
|
71843
72262
|
var exports_gc = {};
|
|
71844
72263
|
__export(exports_gc, {
|
|
71845
|
-
run: () =>
|
|
72264
|
+
run: () => run7
|
|
71846
72265
|
});
|
|
71847
|
-
async function
|
|
72266
|
+
async function run7(argv, io) {
|
|
71848
72267
|
const dryRun = argv.includes("--dry-run");
|
|
71849
72268
|
const pruneRecovery = argv.includes("--prune-recovery");
|
|
71850
72269
|
if (pruneRecovery && !dryRun && !argv.includes("--yes"))
|
|
@@ -71888,9 +72307,9 @@ var init_gc = __esm(() => {
|
|
|
71888
72307
|
// packages/workit-cli/src/verbs/uninstall.ts
|
|
71889
72308
|
var exports_uninstall = {};
|
|
71890
72309
|
__export(exports_uninstall, {
|
|
71891
|
-
run: () =>
|
|
72310
|
+
run: () => run8
|
|
71892
72311
|
});
|
|
71893
|
-
async function
|
|
72312
|
+
async function run8(_argv, io) {
|
|
71894
72313
|
if (io.json)
|
|
71895
72314
|
return emit(io, fail("invalid_input", "workit uninstall is interactive and has no --json output", {
|
|
71896
72315
|
unblock: "run `workit uninstall` in a terminal without --json"
|
|
@@ -71906,7 +72325,7 @@ var init_uninstall2 = __esm(() => {
|
|
|
71906
72325
|
// packages/workit-cli/src/verbs/grant.ts
|
|
71907
72326
|
var exports_grant = {};
|
|
71908
72327
|
__export(exports_grant, {
|
|
71909
|
-
run: () =>
|
|
72328
|
+
run: () => run9,
|
|
71910
72329
|
runGrant: () => runGrant
|
|
71911
72330
|
});
|
|
71912
72331
|
function show(argv, io) {
|
|
@@ -72027,7 +72446,7 @@ var USAGE2 = "workit grant show [<workspace>] [--all] | grant set <workspace> <k
|
|
|
72027
72446
|
...endpoint.endpointIssue ? [` note: ${endpoint.endpointIssue}`] : [],
|
|
72028
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"})`
|
|
72029
72448
|
], usage2 = (io, message) => emit(io, fail("invalid_input", `${message}
|
|
72030
|
-
usage: ${USAGE2}`)),
|
|
72449
|
+
usage: ${USAGE2}`)), run9 = (argv, io) => runGrant(argv, io);
|
|
72031
72450
|
var init_grant = __esm(() => {
|
|
72032
72451
|
init_autonomy();
|
|
72033
72452
|
init_release_tracks();
|
|
@@ -72056,9 +72475,9 @@ var init_grant = __esm(() => {
|
|
|
72056
72475
|
// packages/workit-cli/src/verbs/check.ts
|
|
72057
72476
|
var exports_check = {};
|
|
72058
72477
|
__export(exports_check, {
|
|
72059
|
-
run: () =>
|
|
72478
|
+
run: () => run10
|
|
72060
72479
|
});
|
|
72061
|
-
import
|
|
72480
|
+
import path39 from "node:path";
|
|
72062
72481
|
function parse5(argv) {
|
|
72063
72482
|
const split = argv.indexOf("--");
|
|
72064
72483
|
const head = split >= 0 ? argv.slice(0, split) : [...argv];
|
|
@@ -72207,7 +72626,7 @@ function boundedArgv(argv) {
|
|
|
72207
72626
|
const truncated = cut.length !== argv.length || cut.some((item, index) => item !== argv[index]);
|
|
72208
72627
|
return { argv: cut, truncated };
|
|
72209
72628
|
}
|
|
72210
|
-
async function
|
|
72629
|
+
async function run10(argv, io) {
|
|
72211
72630
|
const options = parse5(argv);
|
|
72212
72631
|
if (options instanceof Error)
|
|
72213
72632
|
return emit(io, fail("invalid_input", options.message, { unblock: USAGE3 }));
|
|
@@ -72241,7 +72660,7 @@ async function run9(argv, io) {
|
|
|
72241
72660
|
if (options.shell && command.length !== 1)
|
|
72242
72661
|
return emit(io, fail("invalid_input", '--shell takes the command as one string: workit check --shell -- "<cmd>"'));
|
|
72243
72662
|
}
|
|
72244
|
-
const relCwd = posix(
|
|
72663
|
+
const relCwd = posix(path39.relative(top, runCwd));
|
|
72245
72664
|
const configured = !options.shell && matchesNamedCheck(config, name, command, relCwd);
|
|
72246
72665
|
const actor = actorFromEnv(io.env);
|
|
72247
72666
|
const branchKey = codeKey(io.cwd, { base: options.base });
|
|
@@ -72365,7 +72784,7 @@ async function run9(argv, io) {
|
|
|
72365
72784
|
return recordError.code === "busy" ? 4 : recordError.code === "invalid_input" ? 2 : 5;
|
|
72366
72785
|
return 0;
|
|
72367
72786
|
}
|
|
72368
|
-
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;
|
|
72369
72788
|
var init_check = __esm(() => {
|
|
72370
72789
|
init_check_config();
|
|
72371
72790
|
init_checks3();
|
|
@@ -72387,9 +72806,9 @@ var init_check = __esm(() => {
|
|
|
72387
72806
|
var success2 = (data) => ({ ok: true, data }), failure3 = (code, error, unblock) => ({ ok: false, code, error, ...unblock ? { unblock } : {} });
|
|
72388
72807
|
|
|
72389
72808
|
// packages/workit-core/src/git/ops.ts
|
|
72390
|
-
import { spawnSync as
|
|
72391
|
-
import { existsSync as
|
|
72392
|
-
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";
|
|
72393
72812
|
function operationInProgress(cwd) {
|
|
72394
72813
|
const markers = [
|
|
72395
72814
|
["rebase-merge", "rebase"],
|
|
@@ -72402,18 +72821,18 @@ function operationInProgress(cwd) {
|
|
|
72402
72821
|
if (!run.ok)
|
|
72403
72822
|
return null;
|
|
72404
72823
|
const found = run.stdout.split(`
|
|
72405
|
-
`).map((line) =>
|
|
72824
|
+
`).map((line) => path40.resolve(cwd, line.trim()));
|
|
72406
72825
|
const conflicted = () => git5(cwd, ["ls-files", "-u"]).stdout.trim() !== "";
|
|
72407
72826
|
for (const [index, [, operation]] of markers.entries()) {
|
|
72408
72827
|
const marker = found[index];
|
|
72409
|
-
if (!marker || !
|
|
72828
|
+
if (!marker || !existsSync19(marker))
|
|
72410
72829
|
continue;
|
|
72411
|
-
if (index === 1 &&
|
|
72830
|
+
if (index === 1 && existsSync19(path40.join(marker, "applying")))
|
|
72412
72831
|
return { operation: "am", commitAllowed: false, branch: null };
|
|
72413
|
-
if (index === 0 &&
|
|
72832
|
+
if (index === 0 && existsSync19(path40.join(marker, "amend")) && !conflicted()) {
|
|
72414
72833
|
let headName = "";
|
|
72415
72834
|
try {
|
|
72416
|
-
headName =
|
|
72835
|
+
headName = readFileSync19(path40.join(marker, "head-name"), "utf8").trim();
|
|
72417
72836
|
} catch {}
|
|
72418
72837
|
const branch = headName.startsWith("refs/heads/") ? headName.slice("refs/heads/".length) : null;
|
|
72419
72838
|
return { operation, commitAllowed: branch !== null, branch };
|
|
@@ -72663,7 +73082,7 @@ function gitCommit(cwd, input) {
|
|
|
72663
73082
|
if (paths.some((value) => value.startsWith("-") || !value.trim()))
|
|
72664
73083
|
return failure3("invalid_input", "paths must not be empty or start with -");
|
|
72665
73084
|
const tracked = new Set(nulList(git5(cwd, ["ls-files", "-z", "--", ...paths]).stdout));
|
|
72666
|
-
const addable = paths.filter((value) =>
|
|
73085
|
+
const addable = paths.filter((value) => existsSync19(path40.resolve(cwd, value)) || [...tracked].some((file) => file === value || file.startsWith(`${value}/`)));
|
|
72667
73086
|
if (addable.length) {
|
|
72668
73087
|
const added = git5(cwd, ["add", "-A", "--", ...addable]);
|
|
72669
73088
|
if (!added.ok)
|
|
@@ -72942,7 +73361,7 @@ ${run.stdout}`;
|
|
|
72942
73361
|
} : { ok: false, lease: false, error: gitError(run) };
|
|
72943
73362
|
}
|
|
72944
73363
|
var COMMIT_TIMEOUT_MS, PUSH_TIMEOUT_MS = 120000, git5 = (cwd, args, options = {}) => {
|
|
72945
|
-
const result =
|
|
73364
|
+
const result = spawnSync18("git", args, {
|
|
72946
73365
|
cwd,
|
|
72947
73366
|
encoding: "utf8",
|
|
72948
73367
|
env: { ...options.env ?? process.env, GIT_TERMINAL_PROMPT: "0" },
|
|
@@ -72996,10 +73415,10 @@ var init_ops = __esm(() => {
|
|
|
72996
73415
|
|
|
72997
73416
|
// packages/workit-core/src/forge/reruns.ts
|
|
72998
73417
|
import fs19 from "node:fs";
|
|
72999
|
-
import
|
|
73418
|
+
import path41 from "node:path";
|
|
73000
73419
|
function rerunLogPath(cwd) {
|
|
73001
73420
|
const common = gitCommonDir(cwd);
|
|
73002
|
-
return common ?
|
|
73421
|
+
return common ? path41.join(common, "workit", "ci-reruns.jsonl") : null;
|
|
73003
73422
|
}
|
|
73004
73423
|
function rerunCounts(cwd, key) {
|
|
73005
73424
|
const counts = new Map;
|
|
@@ -73034,7 +73453,7 @@ function recordReruns(cwd, rows) {
|
|
|
73034
73453
|
if (!file)
|
|
73035
73454
|
return false;
|
|
73036
73455
|
try {
|
|
73037
|
-
fs19.mkdirSync(
|
|
73456
|
+
fs19.mkdirSync(path41.dirname(file), { recursive: true });
|
|
73038
73457
|
fs19.appendFileSync(file, rows.map((row) => `${JSON.stringify(row)}
|
|
73039
73458
|
`).join(""));
|
|
73040
73459
|
return true;
|
|
@@ -73047,7 +73466,7 @@ function withRerunLock(cwd, fn) {
|
|
|
73047
73466
|
if (!file)
|
|
73048
73467
|
return fn();
|
|
73049
73468
|
const lock = `${file.slice(0, -".jsonl".length)}.lock`;
|
|
73050
|
-
fs19.mkdirSync(
|
|
73469
|
+
fs19.mkdirSync(path41.dirname(lock), { recursive: true });
|
|
73051
73470
|
const until = Date.now() + LOCK_WAIT_MS2;
|
|
73052
73471
|
for (;; ) {
|
|
73053
73472
|
try {
|
|
@@ -73295,6 +73714,33 @@ function buildStatusDoc(cwd, resolved, status, options) {
|
|
|
73295
73714
|
babysit: babysitAction(blockers[0]?.next ?? "READY", blockers[0]?.reason ?? null, status.draft || blockers.some((blocker) => blocker.next === "MARK_READY"))
|
|
73296
73715
|
});
|
|
73297
73716
|
}
|
|
73717
|
+
function recordPrStatus(cwd, doc, actor) {
|
|
73718
|
+
const checks = doc.checks.state;
|
|
73719
|
+
const state = doc.state;
|
|
73720
|
+
if (state !== "open" && state !== "merged" && state !== "closed")
|
|
73721
|
+
return;
|
|
73722
|
+
if (state === "open" && checks !== "passing" && checks !== "failing" && checks !== "pending")
|
|
73723
|
+
return;
|
|
73724
|
+
try {
|
|
73725
|
+
const ledger = readLedger(cwd);
|
|
73726
|
+
if (!ledger.ok)
|
|
73727
|
+
return;
|
|
73728
|
+
const last = ledger.value.rows.findLast((row) => row.type === "pr.status" && row.observer === "workit_cli" && row.pr === doc.number && row.repo === doc.repo);
|
|
73729
|
+
if (last && last.head === doc.head.sha && last.checks === checks && (last.state ?? "open") === state)
|
|
73730
|
+
return;
|
|
73731
|
+
appendObserved(cwd, {
|
|
73732
|
+
type: "pr.status",
|
|
73733
|
+
actor,
|
|
73734
|
+
branch: doc.head.branch,
|
|
73735
|
+
head: doc.head.sha,
|
|
73736
|
+
pr: doc.number,
|
|
73737
|
+
repo: doc.repo,
|
|
73738
|
+
forge: doc.forge,
|
|
73739
|
+
state,
|
|
73740
|
+
checks
|
|
73741
|
+
});
|
|
73742
|
+
} catch {}
|
|
73743
|
+
}
|
|
73298
73744
|
function prStatusReport(cwd, resolved, options = {}) {
|
|
73299
73745
|
const number = selectPr(cwd, resolved, options);
|
|
73300
73746
|
if (!number.ok)
|
|
@@ -73309,6 +73755,8 @@ function prStatusReport(cwd, resolved, options = {}) {
|
|
|
73309
73755
|
});
|
|
73310
73756
|
if (!doc.ok)
|
|
73311
73757
|
return doc;
|
|
73758
|
+
if (options.actor)
|
|
73759
|
+
recordPrStatus(cwd, doc.data, options.actor);
|
|
73312
73760
|
return success2({ doc: doc.data, raw: status.data });
|
|
73313
73761
|
}
|
|
73314
73762
|
function waitVerdict(doc, options) {
|
|
@@ -73434,13 +73882,14 @@ function recordAccepted(cwd, resolved, status, accepted, options) {
|
|
|
73434
73882
|
var MAX_LOG_TAILS = 5, GITLAB_MERGEABLE, GITHUB_MERGEABLE, NO_CHECKS_GRACE_MS = 90000;
|
|
73435
73883
|
var init_report = __esm(() => {
|
|
73436
73884
|
init_rev();
|
|
73885
|
+
init_ledger();
|
|
73437
73886
|
init_reruns();
|
|
73438
73887
|
GITLAB_MERGEABLE = new Set(["mergeable"]);
|
|
73439
73888
|
GITHUB_MERGEABLE = new Set(["clean", "unstable", "has_hooks"]);
|
|
73440
73889
|
});
|
|
73441
73890
|
|
|
73442
73891
|
// packages/workit-core/src/forge/pr-ops.ts
|
|
73443
|
-
import { spawnSync as
|
|
73892
|
+
import { spawnSync as spawnSync19 } from "node:child_process";
|
|
73444
73893
|
function fillFromCommits(cwd, resolved, base) {
|
|
73445
73894
|
const tracking = `refs/remotes/${resolved.baseRemote}/${base}`;
|
|
73446
73895
|
if (!base.startsWith("-"))
|
|
@@ -73448,7 +73897,7 @@ function fillFromCommits(cwd, resolved, base) {
|
|
|
73448
73897
|
const from = resolveRef(cwd, tracking) ?? resolveRef(cwd, `refs/heads/${base}`);
|
|
73449
73898
|
if (!from)
|
|
73450
73899
|
return failure3("not_found", `base ${base} is not available locally`, `git fetch ${resolved.baseRemote} ${base}`);
|
|
73451
|
-
const log =
|
|
73900
|
+
const log = spawnSync19("git", ["log", "--reverse", "--no-merges", "--format=%s%x1f%b%x1e", `${from}..HEAD`], {
|
|
73452
73901
|
cwd,
|
|
73453
73902
|
encoding: "utf8",
|
|
73454
73903
|
timeout: GIT_TIMEOUTS.local,
|
|
@@ -73804,10 +74253,10 @@ var init_pr_ops = __esm(() => {
|
|
|
73804
74253
|
});
|
|
73805
74254
|
|
|
73806
74255
|
// packages/workit-core/src/stack.ts
|
|
73807
|
-
import { spawnSync as
|
|
74256
|
+
import { spawnSync as spawnSync20 } from "node:child_process";
|
|
73808
74257
|
import { createHash as createHash16, randomBytes as randomBytes3 } from "node:crypto";
|
|
73809
74258
|
import fs20 from "node:fs";
|
|
73810
|
-
import
|
|
74259
|
+
import path42 from "node:path";
|
|
73811
74260
|
function worktreeOf(cwd, branch) {
|
|
73812
74261
|
const list = gitRun3(cwd, ["worktree", "list", "--porcelain"]);
|
|
73813
74262
|
if (!list.ok)
|
|
@@ -73851,7 +74300,7 @@ function gitRestack(cwd, input) {
|
|
|
73851
74300
|
if (!scratch)
|
|
73852
74301
|
return { ok: false, conflict: false, worktree: cwd, error: "no store root" };
|
|
73853
74302
|
fs20.mkdirSync(scratch, { recursive: true });
|
|
73854
|
-
dir =
|
|
74303
|
+
dir = path42.join(scratch, `${input.branch.replace(/[^A-Za-z0-9._-]+/gu, "_").slice(0, 40)}-${randomBytes3(4).toString("hex")}`);
|
|
73855
74304
|
const added = gitRun3(cwd, ["worktree", "add", "-q", dir, input.branch], GIT_TIMEOUTS.worktree);
|
|
73856
74305
|
if (!added.ok)
|
|
73857
74306
|
return { ok: false, conflict: false, worktree: cwd, error: firstLine(added) };
|
|
@@ -73892,7 +74341,7 @@ function pruneScratch(cwd) {
|
|
|
73892
74341
|
if (!scratch || !fs20.existsSync(scratch))
|
|
73893
74342
|
return;
|
|
73894
74343
|
for (const name of fs20.readdirSync(scratch)) {
|
|
73895
|
-
const dir =
|
|
74344
|
+
const dir = path42.join(scratch, name);
|
|
73896
74345
|
if (!rebaseInProgress(dir) && !trackedDirt(dir))
|
|
73897
74346
|
gitRun3(cwd, ["worktree", "remove", "--force", dir]);
|
|
73898
74347
|
}
|
|
@@ -73902,7 +74351,7 @@ function stacksDir(cwd) {
|
|
|
73902
74351
|
const root = storeRoot(cwd);
|
|
73903
74352
|
if (!root.ok)
|
|
73904
74353
|
return stackFail(root.code, root.error, root.unblock);
|
|
73905
|
-
return { ok: true, data:
|
|
74354
|
+
return { ok: true, data: path42.join(root.value.root, "stacks") };
|
|
73906
74355
|
}
|
|
73907
74356
|
function parseStack(raw) {
|
|
73908
74357
|
if (!isRecord7(raw) || !Array.isArray(raw.branches))
|
|
@@ -73954,7 +74403,7 @@ function readStack(cwd, name) {
|
|
|
73954
74403
|
const dir = stacksDir(cwd);
|
|
73955
74404
|
if (!dir.ok)
|
|
73956
74405
|
return dir;
|
|
73957
|
-
const file =
|
|
74406
|
+
const file = path42.join(dir.data, fileFor(name));
|
|
73958
74407
|
let text;
|
|
73959
74408
|
try {
|
|
73960
74409
|
text = fs20.readFileSync(file, "utf8");
|
|
@@ -73975,7 +74424,7 @@ function writeStack(cwd, stack, now = new Date) {
|
|
|
73975
74424
|
const dir = stacksDir(cwd);
|
|
73976
74425
|
if (!dir.ok)
|
|
73977
74426
|
return dir;
|
|
73978
|
-
const file =
|
|
74427
|
+
const file = path42.join(dir.data, fileFor(stack.name));
|
|
73979
74428
|
const temp = `${file}.${process.pid}.tmp`;
|
|
73980
74429
|
try {
|
|
73981
74430
|
fs20.mkdirSync(dir.data, { recursive: true });
|
|
@@ -74003,7 +74452,7 @@ function listStacks(cwd) {
|
|
|
74003
74452
|
for (const name of names) {
|
|
74004
74453
|
let parsed = null;
|
|
74005
74454
|
try {
|
|
74006
|
-
parsed = parseStack(JSON.parse(fs20.readFileSync(
|
|
74455
|
+
parsed = parseStack(JSON.parse(fs20.readFileSync(path42.join(dir.data, name), "utf8")));
|
|
74007
74456
|
} catch {
|
|
74008
74457
|
parsed = null;
|
|
74009
74458
|
}
|
|
@@ -74062,7 +74511,7 @@ function takeLock(lock) {
|
|
|
74062
74511
|
host: localLockHost(),
|
|
74063
74512
|
nonce: randomBytes3(8).toString("hex")
|
|
74064
74513
|
};
|
|
74065
|
-
fs20.writeFileSync(
|
|
74514
|
+
fs20.writeFileSync(path42.join(lock, OWNER), JSON.stringify(owner));
|
|
74066
74515
|
return owner;
|
|
74067
74516
|
}
|
|
74068
74517
|
function reapLock(lock, observed) {
|
|
@@ -74099,7 +74548,7 @@ async function withStackLock(cwd, name, fn, waitMs = LOCK_WAIT_MS3) {
|
|
|
74099
74548
|
return dir;
|
|
74100
74549
|
if (!validName(name))
|
|
74101
74550
|
return stackFail("invalid_input", "a stack name must be 1-200 printable characters");
|
|
74102
|
-
const lock =
|
|
74551
|
+
const lock = path42.join(dir.data, `${fileFor(name)}.lock`);
|
|
74103
74552
|
try {
|
|
74104
74553
|
fs20.mkdirSync(dir.data, { recursive: true });
|
|
74105
74554
|
} catch (error) {
|
|
@@ -74129,7 +74578,7 @@ async function withStackLock(cwd, name, fn, waitMs = LOCK_WAIT_MS3) {
|
|
|
74129
74578
|
const touch = () => {
|
|
74130
74579
|
try {
|
|
74131
74580
|
const now = new Date;
|
|
74132
|
-
fs20.utimesSync(
|
|
74581
|
+
fs20.utimesSync(path42.join(lock, OWNER), now, now);
|
|
74133
74582
|
} catch {}
|
|
74134
74583
|
};
|
|
74135
74584
|
const beat = setInterval(touch, HEARTBEAT_MS);
|
|
@@ -74317,7 +74766,7 @@ function commitKeys(cwd, range) {
|
|
|
74317
74766
|
const patches = new Map;
|
|
74318
74767
|
const diff = gitRun3(cwd, ["log", "--no-merges", "-p", "--format=commit %H", range]);
|
|
74319
74768
|
if (diff.ok && diff.stdout.trim()) {
|
|
74320
|
-
const ids =
|
|
74769
|
+
const ids = spawnSync20("git", ["patch-id", "--stable"], {
|
|
74321
74770
|
cwd,
|
|
74322
74771
|
input: diff.stdout,
|
|
74323
74772
|
encoding: "utf8",
|
|
@@ -74941,7 +75390,7 @@ var STACK_VERSION = 1, stackFail = (code, error, unblock, data) => ({
|
|
|
74941
75390
|
...unblock ? { unblock } : {},
|
|
74942
75391
|
...data ? { data } : {}
|
|
74943
75392
|
}), fromForge = (result) => stackFail(result.code, result.error, result.unblock), stackDeps, gitRun3 = (cwd, args, timeoutMs = GIT_TIMEOUTS.local) => {
|
|
74944
|
-
const run =
|
|
75393
|
+
const run = spawnSync20("git", args, {
|
|
74945
75394
|
cwd,
|
|
74946
75395
|
encoding: "utf8",
|
|
74947
75396
|
timeout: timeoutMs,
|
|
@@ -74969,7 +75418,7 @@ var STACK_VERSION = 1, stackFail = (code, error, unblock, data) => ({
|
|
|
74969
75418
|
return !status.ok || status.stdout.trim() !== "";
|
|
74970
75419
|
}, scratchDir = (cwd) => {
|
|
74971
75420
|
const dir = stacksDir(cwd);
|
|
74972
|
-
return dir.ok ?
|
|
75421
|
+
return dir.ok ? path42.join(dir.data, "worktrees") : null;
|
|
74973
75422
|
}, firstLine = (run) => (`${run.stderr}
|
|
74974
75423
|
${run.stdout}`.split(`
|
|
74975
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) => {
|
|
@@ -74984,12 +75433,12 @@ ${run.stdout}`.split(`
|
|
|
74984
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) => {
|
|
74985
75434
|
let raw = null;
|
|
74986
75435
|
try {
|
|
74987
|
-
raw = fs20.readFileSync(
|
|
75436
|
+
raw = fs20.readFileSync(path42.join(lock, OWNER), "utf8");
|
|
74988
75437
|
} catch {
|
|
74989
75438
|
raw = null;
|
|
74990
75439
|
}
|
|
74991
75440
|
let age = null;
|
|
74992
|
-
for (const target of [
|
|
75441
|
+
for (const target of [path42.join(lock, OWNER), lock])
|
|
74993
75442
|
try {
|
|
74994
75443
|
age = Date.now() - fs20.statSync(target).mtimeMs;
|
|
74995
75444
|
break;
|
|
@@ -75022,7 +75471,7 @@ var init_stack = __esm(() => {
|
|
|
75022
75471
|
});
|
|
75023
75472
|
|
|
75024
75473
|
// packages/workit-core/src/forge/pr-edit.ts
|
|
75025
|
-
import { spawnSync as
|
|
75474
|
+
import { spawnSync as spawnSync21 } from "node:child_process";
|
|
75026
75475
|
function openPr(cwd, resolved, pr) {
|
|
75027
75476
|
const grant = requireGrant(cwd, "pr");
|
|
75028
75477
|
if (!grant.allowed)
|
|
@@ -75187,7 +75636,7 @@ function replyToThread(cwd, resolved, input) {
|
|
|
75187
75636
|
});
|
|
75188
75637
|
}
|
|
75189
75638
|
var label = (resolved, number) => `${resolved.forge.kind === "github" ? "PR #" : "MR !"}${number}`, git6 = (cwd, args) => {
|
|
75190
|
-
const run =
|
|
75639
|
+
const run = spawnSync21("git", args, {
|
|
75191
75640
|
cwd,
|
|
75192
75641
|
encoding: "utf8",
|
|
75193
75642
|
timeout: GIT_TIMEOUTS.local,
|
|
@@ -75207,15 +75656,15 @@ var init_pr_edit = __esm(() => {
|
|
|
75207
75656
|
});
|
|
75208
75657
|
|
|
75209
75658
|
// packages/workit-core/src/forge/exec.ts
|
|
75210
|
-
import { spawnSync as
|
|
75659
|
+
import { spawnSync as spawnSync22 } from "node:child_process";
|
|
75211
75660
|
import fs21 from "node:fs";
|
|
75212
|
-
import
|
|
75661
|
+
import path43 from "node:path";
|
|
75213
75662
|
function findExecutable(bin, env) {
|
|
75214
|
-
const dirs = (env.PATH ?? env.Path ?? "").split(
|
|
75663
|
+
const dirs = (env.PATH ?? env.Path ?? "").split(path43.delimiter).filter(Boolean);
|
|
75215
75664
|
const exts = process.platform === "win32" ? [".exe"] : [""];
|
|
75216
75665
|
for (const dir of dirs)
|
|
75217
75666
|
for (const ext of exts) {
|
|
75218
|
-
const candidate =
|
|
75667
|
+
const candidate = path43.join(dir, `${bin}${ext}`);
|
|
75219
75668
|
try {
|
|
75220
75669
|
const stat = fs21.statSync(candidate);
|
|
75221
75670
|
if (stat.isFile())
|
|
@@ -75242,7 +75691,7 @@ function systemRunner(kind, apiHost, env = process.env) {
|
|
|
75242
75691
|
if (!exe)
|
|
75243
75692
|
return { status: null, stdout: "", stderr: "", timedOut: false, missing: true };
|
|
75244
75693
|
const token = options.token ? kind === "github" ? { GH_TOKEN: options.token, GH_ENTERPRISE_TOKEN: options.token } : { GITLAB_TOKEN: options.token } : {};
|
|
75245
|
-
const result =
|
|
75694
|
+
const result = spawnSync22(exe, [...args], {
|
|
75246
75695
|
encoding: "utf8",
|
|
75247
75696
|
env: { ...childEnv, ...token },
|
|
75248
75697
|
maxBuffer: MAX_BUFFER2,
|
|
@@ -76406,7 +76855,7 @@ var init_duration = __esm(() => {
|
|
|
76406
76855
|
});
|
|
76407
76856
|
|
|
76408
76857
|
// packages/workit-cli/src/verbs/forge-common.ts
|
|
76409
|
-
import { readFileSync as
|
|
76858
|
+
import { readFileSync as readFileSync20 } from "node:fs";
|
|
76410
76859
|
function parseFlags(argv, spec) {
|
|
76411
76860
|
const parsed = { values: {}, booleans: new Set, lists: {}, positionals: [] };
|
|
76412
76861
|
for (let index = 0;index < argv.length; index += 1) {
|
|
@@ -76550,7 +76999,7 @@ var init_forge_common = __esm(() => {
|
|
|
76550
76999
|
forgeDeps = {
|
|
76551
77000
|
runner: undefined,
|
|
76552
77001
|
npm: undefined,
|
|
76553
|
-
readStdin: () =>
|
|
77002
|
+
readStdin: () => readFileSync20(0, "utf8"),
|
|
76554
77003
|
sleep: (ms) => new Promise((resolve) => setTimeout(resolve, ms)),
|
|
76555
77004
|
now: () => Date.now()
|
|
76556
77005
|
};
|
|
@@ -76559,14 +77008,14 @@ var init_forge_common = __esm(() => {
|
|
|
76559
77008
|
// packages/workit-cli/src/verbs/pr.ts
|
|
76560
77009
|
var exports_pr = {};
|
|
76561
77010
|
__export(exports_pr, {
|
|
76562
|
-
run: () =>
|
|
77011
|
+
run: () => run11
|
|
76563
77012
|
});
|
|
76564
|
-
import { readFileSync as
|
|
76565
|
-
import
|
|
77013
|
+
import { readFileSync as readFileSync21 } from "node:fs";
|
|
77014
|
+
import path44 from "node:path";
|
|
76566
77015
|
function readBodyFile(io, file) {
|
|
76567
77016
|
try {
|
|
76568
77017
|
return {
|
|
76569
|
-
body: file === "-" ? forgeDeps.readStdin() :
|
|
77018
|
+
body: file === "-" ? forgeDeps.readStdin() : readFileSync21(path44.resolve(io.cwd, file), "utf8")
|
|
76570
77019
|
};
|
|
76571
77020
|
} catch {
|
|
76572
77021
|
return `cannot read --body-file ${file}`;
|
|
@@ -76595,7 +77044,8 @@ async function status(argv, io) {
|
|
|
76595
77044
|
pr,
|
|
76596
77045
|
branch: flags.values.branch ?? null,
|
|
76597
77046
|
logLines: logLines ?? 60,
|
|
76598
|
-
identity: connected.data.identity
|
|
77047
|
+
identity: connected.data.identity,
|
|
77048
|
+
actor: actorFromEnv(io.env)
|
|
76599
77049
|
});
|
|
76600
77050
|
if (!report.ok)
|
|
76601
77051
|
return forgeFail(io, report);
|
|
@@ -76892,7 +77342,7 @@ async function reply(argv, io) {
|
|
|
76892
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}` : ""}`
|
|
76893
77343
|
]);
|
|
76894
77344
|
}
|
|
76895
|
-
async function
|
|
77345
|
+
async function run11(argv, io) {
|
|
76896
77346
|
const [sub, ...rest] = argv;
|
|
76897
77347
|
if (sub === "status")
|
|
76898
77348
|
return status(rest, io);
|
|
@@ -76927,7 +77377,7 @@ var init_pr = __esm(() => {
|
|
|
76927
77377
|
// packages/workit-cli/src/verbs/ci.ts
|
|
76928
77378
|
var exports_ci = {};
|
|
76929
77379
|
__export(exports_ci, {
|
|
76930
|
-
run: () =>
|
|
77380
|
+
run: () => run12
|
|
76931
77381
|
});
|
|
76932
77382
|
async function wait(argv, io) {
|
|
76933
77383
|
const flags = parseFlags(argv, {
|
|
@@ -76966,6 +77416,7 @@ async function wait(argv, io) {
|
|
|
76966
77416
|
const number = selectPr(io.cwd, resolved, { pr, branch: flags.values.branch ?? null });
|
|
76967
77417
|
if (!number.ok)
|
|
76968
77418
|
return forgeFail(io, number);
|
|
77419
|
+
const actor = actorFromEnv(io.env);
|
|
76969
77420
|
let polls = 0;
|
|
76970
77421
|
let errors = 0;
|
|
76971
77422
|
let status = null;
|
|
@@ -76980,6 +77431,7 @@ async function wait(argv, io) {
|
|
|
76980
77431
|
const doc = buildStatusDoc(io.cwd, resolved, status, { logLines: 0, behind: false });
|
|
76981
77432
|
if (!doc.ok)
|
|
76982
77433
|
return forgeFail(io, doc);
|
|
77434
|
+
recordPrStatus(io.cwd, doc.data, actor);
|
|
76983
77435
|
verdict = waitVerdict(doc.data, { head, elapsedMs });
|
|
76984
77436
|
if (verdict.state !== "waiting")
|
|
76985
77437
|
break;
|
|
@@ -77094,7 +77546,7 @@ async function rerun(argv, io) {
|
|
|
77094
77546
|
"next: workit ci wait"
|
|
77095
77547
|
]);
|
|
77096
77548
|
}
|
|
77097
|
-
async function
|
|
77549
|
+
async function run12(argv, io) {
|
|
77098
77550
|
const [sub, ...rest] = argv;
|
|
77099
77551
|
if (sub === "wait")
|
|
77100
77552
|
return wait(rest, io);
|
|
@@ -77106,6 +77558,7 @@ async function run11(argv, io) {
|
|
|
77106
77558
|
var WAIT_USAGE = "workit ci wait [--pr <n> | --branch <b>] [--head <sha>] [--timeout 20m] [--interval 30s] [--json]", RERUN_USAGE = "workit ci rerun [--pr <n> | --branch <b>] [--check <name>… | --failed] --reason flake|infra [--force] [--json]", ONE_POLL_MS = 20000, MAX_POLL_ERRORS = 3, seconds = (ms) => `${Math.round(ms / 1000)}s`;
|
|
77107
77559
|
var init_ci = __esm(() => {
|
|
77108
77560
|
init_report();
|
|
77561
|
+
init_ledger();
|
|
77109
77562
|
init_autonomy();
|
|
77110
77563
|
init_output();
|
|
77111
77564
|
init_forge_common();
|
|
@@ -77141,10 +77594,10 @@ var init_implicit_task = __esm(() => {
|
|
|
77141
77594
|
// packages/workit-cli/src/verbs/git.ts
|
|
77142
77595
|
var exports_git = {};
|
|
77143
77596
|
__export(exports_git, {
|
|
77144
|
-
run: () =>
|
|
77597
|
+
run: () => run13
|
|
77145
77598
|
});
|
|
77146
|
-
import { readFileSync as
|
|
77147
|
-
import
|
|
77599
|
+
import { readFileSync as readFileSync22 } from "node:fs";
|
|
77600
|
+
import path45 from "node:path";
|
|
77148
77601
|
async function branch(argv, io) {
|
|
77149
77602
|
const flags = parseFlags(argv, {
|
|
77150
77603
|
base: "value",
|
|
@@ -77235,7 +77688,7 @@ function commitMessage(parsed, io) {
|
|
|
77235
77688
|
|
|
77236
77689
|
`);
|
|
77237
77690
|
try {
|
|
77238
|
-
return file === "-" ?
|
|
77691
|
+
return file === "-" ? readFileSync22(0, "utf8") : readFileSync22(path45.resolve(io.cwd, file), "utf8");
|
|
77239
77692
|
} catch (error) {
|
|
77240
77693
|
return {
|
|
77241
77694
|
error: `cannot read -F ${file}: ${error instanceof Error ? error.message : String(error)}`
|
|
@@ -77338,7 +77791,7 @@ async function push(argv, io) {
|
|
|
77338
77791
|
...data.upstream ? [`upstream: ${data.remote}/${data.branch}`] : []
|
|
77339
77792
|
]);
|
|
77340
77793
|
}
|
|
77341
|
-
async function
|
|
77794
|
+
async function run13(argv, io) {
|
|
77342
77795
|
const [sub, ...rest] = argv;
|
|
77343
77796
|
if (sub === "branch")
|
|
77344
77797
|
return branch(rest, io);
|
|
@@ -77366,7 +77819,7 @@ var init_git2 = __esm(() => {
|
|
|
77366
77819
|
});
|
|
77367
77820
|
|
|
77368
77821
|
// packages/workit-core/src/forge/verify.ts
|
|
77369
|
-
import { spawnSync as
|
|
77822
|
+
import { spawnSync as spawnSync23 } from "node:child_process";
|
|
77370
77823
|
function finish(cwd, report, actor) {
|
|
77371
77824
|
const delivered = report.observations.length > 0 && report.observations.every((entry) => entry.ok);
|
|
77372
77825
|
const out = { ...report, delivered };
|
|
@@ -77579,7 +78032,7 @@ var NPM_NAME, SEMVER2, SAFE_ARG, systemNpm = (args) => {
|
|
|
77579
78032
|
};
|
|
77580
78033
|
const found = process.platform === "win32" ? findExecutable("npm.cmd", process.env) : null;
|
|
77581
78034
|
const npmCmd = found && !/["%!^]/u.test(found) ? `"${found}"` : "npm.cmd";
|
|
77582
|
-
const result = process.platform === "win32" ?
|
|
78035
|
+
const result = process.platform === "win32" ? spawnSync23(`${npmCmd} ${args.join(" ")}`, { ...options, shell: true }) : spawnSync23("npm", [...args], options);
|
|
77583
78036
|
return { status: result.status, stdout: result.stdout ?? "", stderr: result.stderr ?? "" };
|
|
77584
78037
|
}, short3 = (sha) => sha ? sha.slice(0, 12) : "(absent)", npmView = (stdout) => {
|
|
77585
78038
|
try {
|
|
@@ -77604,9 +78057,9 @@ var init_verify = __esm(() => {
|
|
|
77604
78057
|
// packages/workit-cli/src/verbs/verify-delivery.ts
|
|
77605
78058
|
var exports_verify_delivery = {};
|
|
77606
78059
|
__export(exports_verify_delivery, {
|
|
77607
|
-
run: () =>
|
|
78060
|
+
run: () => run14
|
|
77608
78061
|
});
|
|
77609
|
-
async function
|
|
78062
|
+
async function run14(argv, io) {
|
|
77610
78063
|
const flags = parseFlags(argv, {
|
|
77611
78064
|
expect: "value",
|
|
77612
78065
|
branch: "value",
|
|
@@ -77688,7 +78141,7 @@ var init_verify_delivery = __esm(() => {
|
|
|
77688
78141
|
// packages/workit-cli/src/verbs/stack.ts
|
|
77689
78142
|
var exports_stack = {};
|
|
77690
78143
|
__export(exports_stack, {
|
|
77691
|
-
run: () =>
|
|
78144
|
+
run: () => run15
|
|
77692
78145
|
});
|
|
77693
78146
|
async function plan(argv, io) {
|
|
77694
78147
|
const flags = parseFlags(argv, { name: "value", trunk: "value", track: "value" });
|
|
@@ -77870,7 +78323,7 @@ async function land(argv, io) {
|
|
|
77870
78323
|
unblock: ${data.stoppedAt.unblock}` : data.complete ? "stack complete" : ""
|
|
77871
78324
|
].filter(Boolean));
|
|
77872
78325
|
}
|
|
77873
|
-
async function
|
|
78326
|
+
async function run15(argv, io) {
|
|
77874
78327
|
const [sub, ...rest] = argv.filter((arg) => arg !== "--json");
|
|
77875
78328
|
if (sub === "plan")
|
|
77876
78329
|
return plan(rest, io);
|
|
@@ -77900,10 +78353,10 @@ var init_stack2 = __esm(() => {
|
|
|
77900
78353
|
});
|
|
77901
78354
|
|
|
77902
78355
|
// packages/workit-core/src/fanout.ts
|
|
77903
|
-
import { spawnSync as
|
|
78356
|
+
import { spawnSync as spawnSync24 } from "node:child_process";
|
|
77904
78357
|
import { createHash as createHash17 } from "node:crypto";
|
|
77905
78358
|
import fs23 from "node:fs";
|
|
77906
|
-
import
|
|
78359
|
+
import path46 from "node:path";
|
|
77907
78360
|
function expandBraces(pattern, limit = 64) {
|
|
77908
78361
|
for (let index = 0;index < pattern.length; index += 1) {
|
|
77909
78362
|
if (pattern[index] === "\\") {
|
|
@@ -78137,7 +78590,7 @@ function parsePlan(raw, defaults, name) {
|
|
|
78137
78590
|
id,
|
|
78138
78591
|
branch,
|
|
78139
78592
|
base: optional("base") ?? "",
|
|
78140
|
-
worktree:
|
|
78593
|
+
worktree: path46.resolve(defaults.root, optional("worktree") ?? path46.join(defaults.worktreeRoot, id)),
|
|
78141
78594
|
tier,
|
|
78142
78595
|
dependsOn: [...new Set(dependsOn ?? [])],
|
|
78143
78596
|
scope,
|
|
@@ -78366,11 +78819,11 @@ function defaultTrunk(cwd) {
|
|
|
78366
78819
|
}
|
|
78367
78820
|
function mainCheckout(cwd) {
|
|
78368
78821
|
const common = gitCommonDir(cwd);
|
|
78369
|
-
return common &&
|
|
78822
|
+
return common && path46.basename(common) === ".git" ? path46.dirname(common) : path46.resolve(cwd);
|
|
78370
78823
|
}
|
|
78371
78824
|
function worktreeRoot(cwd) {
|
|
78372
78825
|
const main = mainCheckout(cwd);
|
|
78373
|
-
return
|
|
78826
|
+
return path46.join(path46.dirname(main), `${path46.basename(main)}-wt`);
|
|
78374
78827
|
}
|
|
78375
78828
|
function sliceHash(slice) {
|
|
78376
78829
|
const {
|
|
@@ -78388,7 +78841,7 @@ function fanoutsDir(cwd) {
|
|
|
78388
78841
|
const root = storeRoot(cwd);
|
|
78389
78842
|
if (!root.ok)
|
|
78390
78843
|
return fanoutFail(root.code, root.error, root.unblock);
|
|
78391
|
-
return { ok: true, data:
|
|
78844
|
+
return { ok: true, data: path46.join(root.value.root, "fanouts") };
|
|
78392
78845
|
}
|
|
78393
78846
|
function parseStored(raw) {
|
|
78394
78847
|
if (!isRecord8(raw) || typeof raw.name !== "string" || typeof raw.trunk !== "string")
|
|
@@ -78454,7 +78907,7 @@ function readFanout(cwd, name) {
|
|
|
78454
78907
|
const dir = fanoutsDir(cwd);
|
|
78455
78908
|
if (!dir.ok)
|
|
78456
78909
|
return dir;
|
|
78457
|
-
const file =
|
|
78910
|
+
const file = path46.join(dir.data, stackFileName(name));
|
|
78458
78911
|
let parsed = null;
|
|
78459
78912
|
try {
|
|
78460
78913
|
parsed = parseStored(JSON.parse(fs23.readFileSync(file, "utf8")));
|
|
@@ -78479,7 +78932,7 @@ function listFanouts(cwd) {
|
|
|
78479
78932
|
for (const entry of names) {
|
|
78480
78933
|
let parsed = null;
|
|
78481
78934
|
try {
|
|
78482
|
-
parsed = parseStored(JSON.parse(fs23.readFileSync(
|
|
78935
|
+
parsed = parseStored(JSON.parse(fs23.readFileSync(path46.join(dir.data, entry), "utf8")));
|
|
78483
78936
|
} catch {
|
|
78484
78937
|
parsed = null;
|
|
78485
78938
|
}
|
|
@@ -78509,7 +78962,7 @@ function writeFanout(cwd, plan) {
|
|
|
78509
78962
|
const dir = fanoutsDir(cwd);
|
|
78510
78963
|
if (!dir.ok)
|
|
78511
78964
|
return dir;
|
|
78512
|
-
const file =
|
|
78965
|
+
const file = path46.join(dir.data, stackFileName(plan.name));
|
|
78513
78966
|
const temp = `${file}.${process.pid}.tmp`;
|
|
78514
78967
|
try {
|
|
78515
78968
|
fs23.mkdirSync(dir.data, { recursive: true });
|
|
@@ -78673,7 +79126,7 @@ var FANOUT_VERSION = 1, TIERS, FAN_IN_MODES, fanoutFail = (code, error, unblock,
|
|
|
78673
79126
|
text: edges.map((edge) => `add "${edge.dependsOn}" to "dependsOn" of slice ${edge.slice}`).join("; ")
|
|
78674
79127
|
};
|
|
78675
79128
|
}, gitRun4 = (cwd, args, timeoutMs = GIT_TIMEOUTS.local) => {
|
|
78676
|
-
const run =
|
|
79129
|
+
const run = spawnSync24("git", args, {
|
|
78677
79130
|
cwd,
|
|
78678
79131
|
encoding: "utf8",
|
|
78679
79132
|
timeout: timeoutMs,
|
|
@@ -78713,7 +79166,7 @@ var init_fanout = __esm(() => {
|
|
|
78713
79166
|
// packages/workit-core/src/fanout-worktree.ts
|
|
78714
79167
|
import { randomBytes as randomBytes4 } from "node:crypto";
|
|
78715
79168
|
import fs24 from "node:fs";
|
|
78716
|
-
import
|
|
79169
|
+
import path47 from "node:path";
|
|
78717
79170
|
function rowSample(lines) {
|
|
78718
79171
|
const out = [];
|
|
78719
79172
|
let bytes = 0;
|
|
@@ -78773,7 +79226,7 @@ function adminDir(worktree) {
|
|
|
78773
79226
|
const file = dir.stdout.trim();
|
|
78774
79227
|
let token = null;
|
|
78775
79228
|
try {
|
|
78776
|
-
token = fs24.readFileSync(
|
|
79229
|
+
token = fs24.readFileSync(path47.join(file, TOKEN_FILE), "utf8").trim() || null;
|
|
78777
79230
|
} catch {
|
|
78778
79231
|
token = null;
|
|
78779
79232
|
}
|
|
@@ -78781,7 +79234,7 @@ function adminDir(worktree) {
|
|
|
78781
79234
|
const stat = worktreeDeps.stat(file);
|
|
78782
79235
|
return {
|
|
78783
79236
|
path: file,
|
|
78784
|
-
id:
|
|
79237
|
+
id: path47.basename(file),
|
|
78785
79238
|
ino: stat.ino.toString(),
|
|
78786
79239
|
token,
|
|
78787
79240
|
birthMs: stat.birthtimeNs > 0n ? Number(stat.birthtimeMs) : null,
|
|
@@ -78797,7 +79250,7 @@ function markAdminDir(worktree) {
|
|
|
78797
79250
|
return null;
|
|
78798
79251
|
const token = randomBytes4(16).toString("hex");
|
|
78799
79252
|
try {
|
|
78800
|
-
fs24.writeFileSync(
|
|
79253
|
+
fs24.writeFileSync(path47.join(admin.path, TOKEN_FILE), `${token}
|
|
78801
79254
|
`);
|
|
78802
79255
|
} catch {
|
|
78803
79256
|
return null;
|
|
@@ -78812,7 +79265,7 @@ function excludeScratch(cwd) {
|
|
|
78812
79265
|
const common = gitCommonDir(cwd);
|
|
78813
79266
|
if (!common)
|
|
78814
79267
|
return;
|
|
78815
|
-
const file =
|
|
79268
|
+
const file = path47.join(common, "info", "exclude");
|
|
78816
79269
|
let text = "";
|
|
78817
79270
|
try {
|
|
78818
79271
|
text = fs24.readFileSync(file, "utf8");
|
|
@@ -78821,7 +79274,7 @@ function excludeScratch(cwd) {
|
|
|
78821
79274
|
}
|
|
78822
79275
|
if (text.split(/\r?\n/u).includes(EXCLUDE_LINE))
|
|
78823
79276
|
return;
|
|
78824
|
-
fs24.mkdirSync(
|
|
79277
|
+
fs24.mkdirSync(path47.dirname(file), { recursive: true });
|
|
78825
79278
|
fs24.appendFileSync(file, `${text && !text.endsWith(`
|
|
78826
79279
|
`) ? `
|
|
78827
79280
|
` : ""}# workit fanout: per-worker scratch dirs
|
|
@@ -78829,7 +79282,7 @@ ${EXCLUDE_LINE}
|
|
|
78829
79282
|
`);
|
|
78830
79283
|
}
|
|
78831
79284
|
function ensureScratch(worktree) {
|
|
78832
|
-
const scratch =
|
|
79285
|
+
const scratch = path47.join(worktree, SCRATCH_DIR);
|
|
78833
79286
|
fs24.mkdirSync(scratch, { recursive: true });
|
|
78834
79287
|
return scratch;
|
|
78835
79288
|
}
|
|
@@ -78965,7 +79418,7 @@ function releaseSliceWorktree(cwd, plan, input) {
|
|
|
78965
79418
|
const entry = worktrees[index];
|
|
78966
79419
|
if (index === 0)
|
|
78967
79420
|
return fanoutFail("blocked", `${target} is the main checkout; it is never released`);
|
|
78968
|
-
if (
|
|
79421
|
+
if (inside3(cwd, entry.path))
|
|
78969
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}`);
|
|
78970
79423
|
if (entry.branch !== null && entry.branch !== `refs/heads/${slice.branch}`)
|
|
78971
79424
|
return fanoutFail("blocked", `${entry.path} is on ${entry.branch.replace(/^refs\/heads\//u, "")}, not slice ${slice.id}'s ${slice.branch}; nothing was removed`);
|
|
@@ -79047,7 +79500,7 @@ function unpushedCount(cwd, branch) {
|
|
|
79047
79500
|
return count.ok ? Number(count.stdout.trim()) : null;
|
|
79048
79501
|
}
|
|
79049
79502
|
function removeScratch(worktree) {
|
|
79050
|
-
const scratch =
|
|
79503
|
+
const scratch = path47.join(worktree, SCRATCH_DIR);
|
|
79051
79504
|
let stat;
|
|
79052
79505
|
try {
|
|
79053
79506
|
stat = fs24.lstatSync(scratch);
|
|
@@ -79063,16 +79516,16 @@ var SLOW, SCRATCH_DIR = ".workit-scratch", EXCLUDE_LINE, DIRTY_ROW_BYTES = 2000,
|
|
|
79063
79516
|
try {
|
|
79064
79517
|
return fs24.realpathSync.native(target);
|
|
79065
79518
|
} catch {
|
|
79066
|
-
return
|
|
79519
|
+
return path47.resolve(target);
|
|
79067
79520
|
}
|
|
79068
79521
|
}, samePath = (a, b) => {
|
|
79069
79522
|
const left = canonical2(a);
|
|
79070
79523
|
const right = canonical2(b);
|
|
79071
79524
|
return process.platform === "win32" || process.platform === "darwin" ? left.toLowerCase() === right.toLowerCase() : left === right;
|
|
79072
|
-
},
|
|
79073
|
-
const relative =
|
|
79074
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
79075
|
-
}, 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(`
|
|
79076
79529
|
`)[0] || "unknown error"}`);
|
|
79077
79530
|
var init_fanout_worktree = __esm(() => {
|
|
79078
79531
|
init_ops();
|
|
@@ -79193,7 +79646,7 @@ var init_fanout_brief = __esm(() => {
|
|
|
79193
79646
|
});
|
|
79194
79647
|
|
|
79195
79648
|
// packages/workit-core/src/fanout-landed.ts
|
|
79196
|
-
import { spawnSync as
|
|
79649
|
+
import { spawnSync as spawnSync25 } from "node:child_process";
|
|
79197
79650
|
function forgeBreaker(resolved) {
|
|
79198
79651
|
if (!resolved)
|
|
79199
79652
|
return { forge: null, down: () => null };
|
|
@@ -79284,7 +79737,7 @@ function trunkPatchIds(ctx, fork) {
|
|
|
79284
79737
|
"--"
|
|
79285
79738
|
]);
|
|
79286
79739
|
if (log.ok && log.stdout.trim()) {
|
|
79287
|
-
const run =
|
|
79740
|
+
const run = spawnSync25("git", ["patch-id", "--stable"], {
|
|
79288
79741
|
cwd: ctx.cwd,
|
|
79289
79742
|
input: log.stdout,
|
|
79290
79743
|
encoding: "utf8",
|
|
@@ -79845,10 +80298,10 @@ var init_fanout_status = __esm(() => {
|
|
|
79845
80298
|
// packages/workit-cli/src/verbs/fanout.ts
|
|
79846
80299
|
var exports_fanout = {};
|
|
79847
80300
|
__export(exports_fanout, {
|
|
79848
|
-
run: () =>
|
|
80301
|
+
run: () => run16
|
|
79849
80302
|
});
|
|
79850
80303
|
import fs25 from "node:fs";
|
|
79851
|
-
import
|
|
80304
|
+
import path48 from "node:path";
|
|
79852
80305
|
function forgeFor(io, offline) {
|
|
79853
80306
|
if (offline)
|
|
79854
80307
|
return { forge: null, error: "--offline" };
|
|
@@ -79909,7 +80362,7 @@ function plan2(argv, io) {
|
|
|
79909
80362
|
return usage3(io, "pass --trunk or --track, not both (--track picks the trunk)", PLAN_USAGE2);
|
|
79910
80363
|
if (flags.positionals.length !== 1)
|
|
79911
80364
|
return usage3(io, flags.positionals.length ? `unexpected argument ${flags.positionals[1]}` : "missing <plan.json>", PLAN_USAGE2);
|
|
79912
|
-
const file =
|
|
80365
|
+
const file = path48.resolve(io.cwd, flags.positionals[0]);
|
|
79913
80366
|
let raw;
|
|
79914
80367
|
try {
|
|
79915
80368
|
raw = JSON.parse(fs25.readFileSync(file, "utf8"));
|
|
@@ -80065,7 +80518,7 @@ function worktree(argv, io) {
|
|
|
80065
80518
|
...data.notes.map((note) => `note: ${note}`)
|
|
80066
80519
|
]);
|
|
80067
80520
|
}
|
|
80068
|
-
async function
|
|
80521
|
+
async function run16(argv, io) {
|
|
80069
80522
|
const [sub, ...rest] = argv.filter((arg) => arg !== "--json");
|
|
80070
80523
|
if (sub === "plan")
|
|
80071
80524
|
return plan2(rest, io);
|
|
@@ -80131,7 +80584,7 @@ var init_fanout2 = __esm(() => {
|
|
|
80131
80584
|
// packages/workit-cli/src/verbs/ledger.ts
|
|
80132
80585
|
var exports_ledger = {};
|
|
80133
80586
|
__export(exports_ledger, {
|
|
80134
|
-
run: () =>
|
|
80587
|
+
run: () => run17
|
|
80135
80588
|
});
|
|
80136
80589
|
import { randomBytes as randomBytes5 } from "node:crypto";
|
|
80137
80590
|
import { parseArgs } from "node:util";
|
|
@@ -80155,7 +80608,7 @@ function targetBranch(io, rows, branch, pr) {
|
|
|
80155
80608
|
}
|
|
80156
80609
|
return { ok: true, value: branch ?? null };
|
|
80157
80610
|
}
|
|
80158
|
-
async function
|
|
80611
|
+
async function run17(argv, io) {
|
|
80159
80612
|
let parsed;
|
|
80160
80613
|
try {
|
|
80161
80614
|
parsed = parseArgs({ args: argv, options: OPTIONS, allowPositionals: true, strict: true });
|
|
@@ -95392,7 +95845,7 @@ var init_ast = __esm(() => {
|
|
|
95392
95845
|
|
|
95393
95846
|
// packages/workit-cli/src/test-audit/rules.ts
|
|
95394
95847
|
import { builtinModules } from "node:module";
|
|
95395
|
-
import
|
|
95848
|
+
import path49 from "node:path";
|
|
95396
95849
|
function testCallee(call) {
|
|
95397
95850
|
let callee = call.callee;
|
|
95398
95851
|
if (callee.type === "CallExpression")
|
|
@@ -95885,12 +96338,12 @@ function checkConstantsOnly(ctx, emit) {
|
|
|
95885
96338
|
}
|
|
95886
96339
|
function checkOverMocking(ctx, emit) {
|
|
95887
96340
|
const { program } = ctx.parsed;
|
|
95888
|
-
const unit =
|
|
96341
|
+
const unit = path49.basename(ctx.file).replace(/\.(?:[cm]?[jt]sx?)$/, "").replace(/\.(?:test|spec)$/, "");
|
|
95889
96342
|
const mocked = find2(program, (node) => node.type === "CallExpression" && MODULE_MOCK.test(calleeName(node.callee) ?? "") && node.arguments[0]?.type === "StringLiteral");
|
|
95890
96343
|
const internal = mocked.filter((call) => /^(?:\.|@\/|~\/)/.test(call.arguments[0].value));
|
|
95891
96344
|
for (const call of mocked) {
|
|
95892
96345
|
const spec = call.arguments[0].value;
|
|
95893
|
-
const base =
|
|
96346
|
+
const base = path49.basename(spec.replace(/\/index(?:\.[cm]?[jt]sx?)?$/, "")).replace(/\.(?:[cm]?[jt]sx?)$/, "");
|
|
95894
96347
|
if (base === unit)
|
|
95895
96348
|
emit({
|
|
95896
96349
|
rule: "over-mocking",
|
|
@@ -96278,11 +96731,11 @@ var init_rules = __esm(() => {
|
|
|
96278
96731
|
});
|
|
96279
96732
|
|
|
96280
96733
|
// packages/workit-cli/src/test-audit/audit.ts
|
|
96281
|
-
import { spawnSync as
|
|
96282
|
-
import { existsSync as
|
|
96283
|
-
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";
|
|
96284
96737
|
function git7(cwd, args) {
|
|
96285
|
-
const run =
|
|
96738
|
+
const run = spawnSync26("git", ["-c", "core.quotepath=off", ...args], {
|
|
96286
96739
|
cwd,
|
|
96287
96740
|
encoding: "utf8",
|
|
96288
96741
|
maxBuffer: 64 * 1024 * 1024
|
|
@@ -96293,7 +96746,7 @@ function walkTests(dir, out) {
|
|
|
96293
96746
|
for (const entry of readdirSync9(dir, { withFileTypes: true })) {
|
|
96294
96747
|
if (entry.name.startsWith(".") && entry.name !== "." && entry.isDirectory())
|
|
96295
96748
|
continue;
|
|
96296
|
-
const full =
|
|
96749
|
+
const full = path50.join(dir, entry.name);
|
|
96297
96750
|
if (entry.isDirectory()) {
|
|
96298
96751
|
if (!SKIP_DIRS.has(entry.name))
|
|
96299
96752
|
walkTests(full, out);
|
|
@@ -96305,10 +96758,10 @@ function expandPaths(cwd, inputs) {
|
|
|
96305
96758
|
const files = [];
|
|
96306
96759
|
const missing = [];
|
|
96307
96760
|
for (const input of inputs.length > 0 ? inputs : ["."]) {
|
|
96308
|
-
const full =
|
|
96309
|
-
if (!
|
|
96761
|
+
const full = path50.resolve(cwd, input);
|
|
96762
|
+
if (!existsSync20(full))
|
|
96310
96763
|
missing.push(input);
|
|
96311
|
-
else if (
|
|
96764
|
+
else if (statSync8(full).isDirectory())
|
|
96312
96765
|
walkTests(full, files);
|
|
96313
96766
|
else
|
|
96314
96767
|
files.push(full);
|
|
@@ -96342,11 +96795,11 @@ function changedLines(cwd, base) {
|
|
|
96342
96795
|
for (let offset = 0;offset < count; offset += 1)
|
|
96343
96796
|
lines.add(start + offset);
|
|
96344
96797
|
}
|
|
96345
|
-
changed.set(
|
|
96798
|
+
changed.set(path50.join(root, file), lines);
|
|
96346
96799
|
}
|
|
96347
96800
|
const untracked = git7(root, ["ls-files", "--others", "--exclude-standard", "-z"]);
|
|
96348
96801
|
for (const file of untracked.stdout.split("\x00").filter(Boolean))
|
|
96349
|
-
changed.set(
|
|
96802
|
+
changed.set(path50.join(root, file), "all");
|
|
96350
96803
|
return changed;
|
|
96351
96804
|
}
|
|
96352
96805
|
function auditFiles(files, display) {
|
|
@@ -96359,7 +96812,7 @@ function auditFiles(files, display) {
|
|
|
96359
96812
|
const shown = display(file);
|
|
96360
96813
|
let parsed;
|
|
96361
96814
|
try {
|
|
96362
|
-
parsed = parseSource(
|
|
96815
|
+
parsed = parseSource(readFileSync23(file, "utf8"), file);
|
|
96363
96816
|
} catch (error) {
|
|
96364
96817
|
parseErrors.push({
|
|
96365
96818
|
file: shown,
|
|
@@ -96408,7 +96861,7 @@ function auditFiles(files, display) {
|
|
|
96408
96861
|
durationMs: Math.round(performance.now() - started)
|
|
96409
96862
|
};
|
|
96410
96863
|
}
|
|
96411
|
-
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;
|
|
96412
96865
|
var init_audit = __esm(() => {
|
|
96413
96866
|
init_ast();
|
|
96414
96867
|
init_rules();
|
|
@@ -96422,23 +96875,23 @@ var init_audit = __esm(() => {
|
|
|
96422
96875
|
// packages/workit-cli/src/test-audit/mutate.ts
|
|
96423
96876
|
import { spawn as spawn2 } from "node:child_process";
|
|
96424
96877
|
import {
|
|
96425
|
-
existsSync as
|
|
96426
|
-
lstatSync as
|
|
96427
|
-
mkdirSync as
|
|
96878
|
+
existsSync as existsSync21,
|
|
96879
|
+
lstatSync as lstatSync8,
|
|
96880
|
+
mkdirSync as mkdirSync10,
|
|
96428
96881
|
mkdtempSync as mkdtempSync4,
|
|
96429
96882
|
readdirSync as readdirSync10,
|
|
96430
|
-
readFileSync as
|
|
96883
|
+
readFileSync as readFileSync24,
|
|
96431
96884
|
readlinkSync as readlinkSync3,
|
|
96432
96885
|
realpathSync as realpathSync9,
|
|
96433
|
-
renameSync as
|
|
96434
|
-
rmSync as
|
|
96435
|
-
statSync as
|
|
96886
|
+
renameSync as renameSync6,
|
|
96887
|
+
rmSync as rmSync8,
|
|
96888
|
+
statSync as statSync9,
|
|
96436
96889
|
symlinkSync,
|
|
96437
|
-
writeFileSync as
|
|
96890
|
+
writeFileSync as writeFileSync11,
|
|
96438
96891
|
copyFileSync as copyFileSync6
|
|
96439
96892
|
} from "node:fs";
|
|
96440
96893
|
import os14 from "node:os";
|
|
96441
|
-
import
|
|
96894
|
+
import path51 from "node:path";
|
|
96442
96895
|
function mutantsFor(source, file, lines) {
|
|
96443
96896
|
const parsed = parseSource(source, file);
|
|
96444
96897
|
const out = [];
|
|
@@ -96511,7 +96964,7 @@ function relatedTests(source, testFiles) {
|
|
|
96511
96964
|
for (const match of text.matchAll(SPECIFIER)) {
|
|
96512
96965
|
const spec = match[1];
|
|
96513
96966
|
if (spec.startsWith(".")) {
|
|
96514
|
-
if (stripExt(
|
|
96967
|
+
if (stripExt(path51.posix.join(path51.posix.dirname(file), spec)) === target)
|
|
96515
96968
|
return true;
|
|
96516
96969
|
} else if (spec.includes("/") && stripExt(spec).split("/").slice(-2).join("/") === tail)
|
|
96517
96970
|
return true;
|
|
@@ -96531,12 +96984,12 @@ function removeStaleCopies(tmp = os14.tmpdir()) {
|
|
|
96531
96984
|
for (const name of names) {
|
|
96532
96985
|
if (!name.startsWith(TEMP_PREFIX))
|
|
96533
96986
|
continue;
|
|
96534
|
-
const dir =
|
|
96987
|
+
const dir = path51.join(tmp, name);
|
|
96535
96988
|
try {
|
|
96536
|
-
const stat =
|
|
96989
|
+
const stat = lstatSync8(dir);
|
|
96537
96990
|
if (!stat.isDirectory() || uid !== undefined && stat.uid !== uid)
|
|
96538
96991
|
continue;
|
|
96539
|
-
const pid = Number(
|
|
96992
|
+
const pid = Number(readFileSync24(path51.join(dir, PID_FILE), "utf8"));
|
|
96540
96993
|
if (Number.isInteger(pid) && pid > 0 && alive(pid))
|
|
96541
96994
|
continue;
|
|
96542
96995
|
} catch (error) {
|
|
@@ -96544,23 +96997,23 @@ function removeStaleCopies(tmp = os14.tmpdir()) {
|
|
|
96544
96997
|
continue;
|
|
96545
96998
|
}
|
|
96546
96999
|
try {
|
|
96547
|
-
|
|
97000
|
+
rmSync8(dir, { recursive: true, force: true });
|
|
96548
97001
|
removed += 1;
|
|
96549
97002
|
} catch {}
|
|
96550
97003
|
}
|
|
96551
97004
|
return removed;
|
|
96552
97005
|
}
|
|
96553
97006
|
function linkNodeModules(origin, target, repo, copy) {
|
|
96554
|
-
|
|
97007
|
+
mkdirSync10(target, { recursive: true });
|
|
96555
97008
|
for (const entry of readdirSync10(origin, { withFileTypes: true })) {
|
|
96556
|
-
const from =
|
|
96557
|
-
const to =
|
|
97009
|
+
const from = path51.join(origin, entry.name);
|
|
97010
|
+
const to = path51.join(target, entry.name);
|
|
96558
97011
|
if (entry.name.startsWith("@") && entry.isDirectory()) {
|
|
96559
97012
|
linkNodeModules(from, to, repo, copy);
|
|
96560
97013
|
continue;
|
|
96561
97014
|
}
|
|
96562
97015
|
if (entry.name.startsWith(".") && entry.name !== ".bin" && entry.isDirectory()) {
|
|
96563
|
-
|
|
97016
|
+
mkdirSync10(to, { recursive: true });
|
|
96564
97017
|
continue;
|
|
96565
97018
|
}
|
|
96566
97019
|
if (entry.isSymbolicLink()) {
|
|
@@ -96570,9 +97023,9 @@ function linkNodeModules(origin, target, repo, copy) {
|
|
|
96570
97023
|
} catch {
|
|
96571
97024
|
continue;
|
|
96572
97025
|
}
|
|
96573
|
-
const relative =
|
|
96574
|
-
if (!relative.startsWith("..") && !
|
|
96575
|
-
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");
|
|
96576
97029
|
continue;
|
|
96577
97030
|
}
|
|
96578
97031
|
}
|
|
@@ -96587,33 +97040,33 @@ function copySymlink(repo, tree, from, to) {
|
|
|
96587
97040
|
real = null;
|
|
96588
97041
|
}
|
|
96589
97042
|
const realRepo = realpathSync9(repo);
|
|
96590
|
-
if (real &&
|
|
96591
|
-
symlinkSync(
|
|
97043
|
+
if (real && inside4(realRepo, real)) {
|
|
97044
|
+
symlinkSync(path51.relative(path51.dirname(to), path51.join(tree, path51.relative(realRepo, real))), to);
|
|
96592
97045
|
return;
|
|
96593
97046
|
}
|
|
96594
|
-
if (real &&
|
|
97047
|
+
if (real && statSync9(real).isFile())
|
|
96595
97048
|
copyFileSync6(real, to);
|
|
96596
97049
|
else
|
|
96597
97050
|
symlinkSync(readlinkSync3(from), to);
|
|
96598
97051
|
}
|
|
96599
97052
|
function writeInside(copy, file, content) {
|
|
96600
|
-
const target =
|
|
97053
|
+
const target = path51.join(copy, file);
|
|
96601
97054
|
try {
|
|
96602
|
-
const stat =
|
|
96603
|
-
if (!stat.isFile() || !
|
|
97055
|
+
const stat = lstatSync8(target);
|
|
97056
|
+
if (!stat.isFile() || !inside4(realpathSync9(copy), realpathSync9(path51.dirname(target))))
|
|
96604
97057
|
return false;
|
|
96605
97058
|
} catch {
|
|
96606
97059
|
return false;
|
|
96607
97060
|
}
|
|
96608
97061
|
const temp = `${target}.workit-mutant-${process.pid}`;
|
|
96609
|
-
|
|
96610
|
-
|
|
97062
|
+
writeFileSync11(temp, content);
|
|
97063
|
+
renameSync6(temp, target);
|
|
96611
97064
|
return true;
|
|
96612
97065
|
}
|
|
96613
97066
|
function copyWorkingTree(repo) {
|
|
96614
|
-
const dir = mkdtempSync4(
|
|
96615
|
-
|
|
96616
|
-
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");
|
|
96617
97070
|
const head = git7(repo, ["rev-parse", "--verify", "--quiet", "HEAD"]).stdout.trim();
|
|
96618
97071
|
if (head && git7(dir, ["clone", "-q", "--shared", "--no-checkout", repo, tree]).ok) {
|
|
96619
97072
|
const branch = git7(repo, ["symbolic-ref", "--quiet", "--short", "HEAD"]).stdout.trim();
|
|
@@ -96624,35 +97077,35 @@ function copyWorkingTree(repo) {
|
|
|
96624
97077
|
git7(tree, ["update-ref", "--no-deref", "HEAD", head]);
|
|
96625
97078
|
git7(tree, ["reset", "-q"]);
|
|
96626
97079
|
} else
|
|
96627
|
-
|
|
97080
|
+
mkdirSync10(tree, { recursive: true });
|
|
96628
97081
|
const listed = git7(repo, ["ls-files", "-co", "--exclude-standard", "-z"]).stdout.split("\x00");
|
|
96629
97082
|
const dirs = new Set([""]);
|
|
96630
97083
|
for (const relative of listed) {
|
|
96631
97084
|
if (!relative)
|
|
96632
97085
|
continue;
|
|
96633
|
-
const from =
|
|
97086
|
+
const from = path51.join(repo, relative);
|
|
96634
97087
|
let stat;
|
|
96635
97088
|
try {
|
|
96636
|
-
stat =
|
|
97089
|
+
stat = lstatSync8(from);
|
|
96637
97090
|
} catch {
|
|
96638
97091
|
continue;
|
|
96639
97092
|
}
|
|
96640
|
-
const to =
|
|
96641
|
-
|
|
97093
|
+
const to = path51.join(tree, relative);
|
|
97094
|
+
mkdirSync10(path51.dirname(to), { recursive: true });
|
|
96642
97095
|
if (stat.isSymbolicLink())
|
|
96643
97096
|
copySymlink(repo, tree, from, to);
|
|
96644
97097
|
else if (stat.isFile())
|
|
96645
97098
|
copyFileSync6(from, to);
|
|
96646
|
-
let parent =
|
|
97099
|
+
let parent = path51.dirname(relative);
|
|
96647
97100
|
while (parent !== "." && !dirs.has(parent)) {
|
|
96648
97101
|
dirs.add(parent);
|
|
96649
|
-
parent =
|
|
97102
|
+
parent = path51.dirname(parent);
|
|
96650
97103
|
}
|
|
96651
97104
|
}
|
|
96652
97105
|
for (const parent of dirs) {
|
|
96653
|
-
const modules =
|
|
96654
|
-
if (
|
|
96655
|
-
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);
|
|
96656
97109
|
}
|
|
96657
97110
|
return { dir, tree };
|
|
96658
97111
|
}
|
|
@@ -96691,20 +97144,20 @@ async function runMutation(options) {
|
|
|
96691
97144
|
const tracked = git7(repo, ["ls-files", "-co", "--exclude-standard", "-z"]).stdout.split("\x00").filter(Boolean);
|
|
96692
97145
|
const testFiles = tracked.filter((file) => TEST_FILE.test(file)).map((file) => {
|
|
96693
97146
|
try {
|
|
96694
|
-
return { file, text:
|
|
97147
|
+
return { file, text: readFileSync24(path51.join(repo, file), "utf8") };
|
|
96695
97148
|
} catch {
|
|
96696
97149
|
return { file, text: "" };
|
|
96697
97150
|
}
|
|
96698
97151
|
});
|
|
96699
97152
|
const candidates = [];
|
|
96700
97153
|
for (const [absolute, lines] of [...options.changed].toSorted(([a], [b]) => a.localeCompare(b))) {
|
|
96701
|
-
const relative = toPosix(
|
|
97154
|
+
const relative = toPosix(path51.relative(repo, absolute));
|
|
96702
97155
|
if (!CODE_FILE.test(relative) || TEST_FILE.test(relative) || relative.endsWith(".d.ts"))
|
|
96703
97156
|
continue;
|
|
96704
|
-
if (NOT_SOURCE.test(relative) || !
|
|
97157
|
+
if (NOT_SOURCE.test(relative) || !existsSync21(absolute))
|
|
96705
97158
|
continue;
|
|
96706
97159
|
try {
|
|
96707
|
-
candidates.push(...mutantsFor(
|
|
97160
|
+
candidates.push(...mutantsFor(readFileSync24(absolute, "utf8"), relative, lines));
|
|
96708
97161
|
} catch {}
|
|
96709
97162
|
}
|
|
96710
97163
|
const mutants = candidates.map((mutant, index) => ({ ...mutant, id: index + 1 }));
|
|
@@ -96712,9 +97165,9 @@ async function runMutation(options) {
|
|
|
96712
97165
|
for (const mutant of mutants)
|
|
96713
97166
|
if (!related.has(mutant.file))
|
|
96714
97167
|
related.set(mutant.file, relatedTests(mutant.file, testFiles));
|
|
96715
|
-
const cwdRelative =
|
|
97168
|
+
const cwdRelative = path51.relative(repo, options.cwd);
|
|
96716
97169
|
const asArg = (file) => {
|
|
96717
|
-
const relative = toPosix(
|
|
97170
|
+
const relative = toPosix(path51.relative(cwdRelative, file));
|
|
96718
97171
|
return shellQuote(relative.startsWith(".") ? relative : `./${relative}`);
|
|
96719
97172
|
};
|
|
96720
97173
|
const commandFor = (tests) => options.command.replaceAll("{files}", () => tests.map(asArg).join(" "));
|
|
@@ -96749,7 +97202,7 @@ async function runMutation(options) {
|
|
|
96749
97202
|
return finish2(options, 0, results, counts, started);
|
|
96750
97203
|
removeStaleCopies();
|
|
96751
97204
|
const { dir: copyDir, tree: copy } = copyWorkingTree(repo);
|
|
96752
|
-
const copyCwd =
|
|
97205
|
+
const copyCwd = path51.join(copy, cwdRelative);
|
|
96753
97206
|
let current = null;
|
|
96754
97207
|
const restore = () => {
|
|
96755
97208
|
if (current)
|
|
@@ -96760,7 +97213,7 @@ async function runMutation(options) {
|
|
|
96760
97213
|
for (const child of active)
|
|
96761
97214
|
killTree(child);
|
|
96762
97215
|
restore();
|
|
96763
|
-
|
|
97216
|
+
rmSync8(copyDir, { recursive: true, force: true });
|
|
96764
97217
|
};
|
|
96765
97218
|
const onSignal = (signal) => {
|
|
96766
97219
|
cleanup();
|
|
@@ -96784,7 +97237,7 @@ async function runMutation(options) {
|
|
|
96784
97237
|
record({ ...mutant, status: "skipped", durationMs: 0, tests, reason: "budget" });
|
|
96785
97238
|
continue;
|
|
96786
97239
|
}
|
|
96787
|
-
const original =
|
|
97240
|
+
const original = readFileSync24(path51.join(copy, mutant.file), "utf8");
|
|
96788
97241
|
const mutated = original.slice(0, mutant.start) + mutant.replacement + original.slice(mutant.end);
|
|
96789
97242
|
current = { file: mutant.file, original };
|
|
96790
97243
|
if (!writeInside(copy, mutant.file, mutated)) {
|
|
@@ -96840,9 +97293,9 @@ var NOT_SOURCE, FLIPS, isStringy = (node) => node.type === "StringLiteral" || no
|
|
|
96840
97293
|
} catch (error) {
|
|
96841
97294
|
return error.code === "EPERM";
|
|
96842
97295
|
}
|
|
96843
|
-
},
|
|
96844
|
-
const relative =
|
|
96845
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
97296
|
+
}, inside4 = (root, file) => {
|
|
97297
|
+
const relative = path51.relative(root, file);
|
|
97298
|
+
return relative === "" || !relative.startsWith("..") && !path51.isAbsolute(relative);
|
|
96846
97299
|
}, active, killTree = (child) => {
|
|
96847
97300
|
try {
|
|
96848
97301
|
if (child.pid && process.platform !== "win32")
|
|
@@ -96888,10 +97341,10 @@ var init_mutate = __esm(() => {
|
|
|
96888
97341
|
// packages/workit-cli/src/verbs/test-audit.ts
|
|
96889
97342
|
var exports_test_audit = {};
|
|
96890
97343
|
__export(exports_test_audit, {
|
|
96891
|
-
run: () =>
|
|
97344
|
+
run: () => run18
|
|
96892
97345
|
});
|
|
96893
|
-
import { existsSync as
|
|
96894
|
-
import
|
|
97346
|
+
import { existsSync as existsSync22 } from "node:fs";
|
|
97347
|
+
import path52 from "node:path";
|
|
96895
97348
|
function parse7(argv) {
|
|
96896
97349
|
const options = {
|
|
96897
97350
|
paths: [],
|
|
@@ -96989,14 +97442,14 @@ function human(data) {
|
|
|
96989
97442
|
}
|
|
96990
97443
|
return lines;
|
|
96991
97444
|
}
|
|
96992
|
-
async function
|
|
97445
|
+
async function run18(argv, io) {
|
|
96993
97446
|
const options = parse7(argv);
|
|
96994
97447
|
if (typeof options === "string")
|
|
96995
97448
|
return emit(io, fail("invalid_input", `${options}
|
|
96996
97449
|
usage: ${USAGE10}`));
|
|
96997
97450
|
const top = git7(io.cwd, ["rev-parse", "--show-toplevel"]);
|
|
96998
|
-
const repo = top.ok ?
|
|
96999
|
-
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);
|
|
97000
97453
|
let base = null;
|
|
97001
97454
|
let changed = null;
|
|
97002
97455
|
if (options.diff || options.mutate) {
|
|
@@ -97013,7 +97466,7 @@ usage: ${USAGE10}`));
|
|
|
97013
97466
|
}
|
|
97014
97467
|
let files;
|
|
97015
97468
|
if (options.diff && changed)
|
|
97016
|
-
files = [...changed.keys()].filter((file) => TEST_FILE.test(toPosix(file)) &&
|
|
97469
|
+
files = [...changed.keys()].filter((file) => TEST_FILE.test(toPosix(file)) && existsSync22(file)).toSorted();
|
|
97017
97470
|
else {
|
|
97018
97471
|
const expanded = expandPaths(io.cwd, options.paths);
|
|
97019
97472
|
if (expanded.missing.length > 0)
|
|
@@ -97100,9 +97553,9 @@ var init_test_audit = __esm(() => {
|
|
|
97100
97553
|
// packages/workit-cli/src/verbs/knowledge.ts
|
|
97101
97554
|
var exports_knowledge = {};
|
|
97102
97555
|
__export(exports_knowledge, {
|
|
97103
|
-
run: () =>
|
|
97556
|
+
run: () => run19
|
|
97104
97557
|
});
|
|
97105
|
-
async function
|
|
97558
|
+
async function run19(argv, io) {
|
|
97106
97559
|
const [sub, ...rest] = argv.filter((arg) => arg !== "--json");
|
|
97107
97560
|
if (sub !== "lint" || rest.length > 0)
|
|
97108
97561
|
return emit(io, fail("invalid_input", `usage: ${USAGE11}`));
|
|
@@ -97236,11 +97689,11 @@ var init_youtrack_writes = __esm(() => {
|
|
|
97236
97689
|
// packages/workit-cli/src/verbs/youtrack.ts
|
|
97237
97690
|
var exports_youtrack = {};
|
|
97238
97691
|
__export(exports_youtrack, {
|
|
97239
|
-
run: () =>
|
|
97692
|
+
run: () => run20
|
|
97240
97693
|
});
|
|
97241
|
-
import { readFileSync as
|
|
97242
|
-
import
|
|
97243
|
-
async function
|
|
97694
|
+
import { readFileSync as readFileSync25 } from "node:fs";
|
|
97695
|
+
import path53 from "node:path";
|
|
97696
|
+
async function run20(argv, io) {
|
|
97244
97697
|
const [sub, ...rest] = argv;
|
|
97245
97698
|
if (sub !== "note" && sub !== "time" && sub !== "meeting")
|
|
97246
97699
|
return usage3(io, `unknown subcommand "${sub ?? ""}"`, USAGE12);
|
|
@@ -97285,7 +97738,7 @@ async function run19(argv, io) {
|
|
|
97285
97738
|
let markdown = flags.values.markdown ?? "";
|
|
97286
97739
|
if (flags.values.file)
|
|
97287
97740
|
try {
|
|
97288
|
-
markdown =
|
|
97741
|
+
markdown = readFileSync25(path53.resolve(io.cwd, flags.values.file), "utf8");
|
|
97289
97742
|
} catch (error) {
|
|
97290
97743
|
return usage3(io, `cannot read ${flags.values.file}: ${String(error)}`, USAGE12);
|
|
97291
97744
|
}
|
|
@@ -97351,11 +97804,11 @@ var init_youtrack2 = __esm(() => {
|
|
|
97351
97804
|
// packages/workit-cli/src/verbs/changelog.ts
|
|
97352
97805
|
var exports_changelog = {};
|
|
97353
97806
|
__export(exports_changelog, {
|
|
97354
|
-
run: () =>
|
|
97807
|
+
run: () => run21
|
|
97355
97808
|
});
|
|
97356
|
-
import { readFileSync as
|
|
97357
|
-
import
|
|
97358
|
-
async function
|
|
97809
|
+
import { readFileSync as readFileSync26 } from "node:fs";
|
|
97810
|
+
import path54 from "node:path";
|
|
97811
|
+
async function run21(argv, io) {
|
|
97359
97812
|
const [sub, ...rest] = argv;
|
|
97360
97813
|
if (sub !== "apply")
|
|
97361
97814
|
return usage3(io, `unknown subcommand "${sub ?? ""}"`, USAGE13);
|
|
@@ -97400,7 +97853,7 @@ async function run20(argv, io) {
|
|
|
97400
97853
|
]);
|
|
97401
97854
|
}
|
|
97402
97855
|
var USAGE13 = "workit changelog apply (--entries <JSON|@file|-> | --normalize-only) [--path CHANGELOG.md] [--preview]", readEntries = (raw, cwd) => {
|
|
97403
|
-
const text = raw === "-" ?
|
|
97856
|
+
const text = raw === "-" ? readFileSync26(0, "utf8") : raw.startsWith("@") ? readFileSync26(path54.resolve(cwd, raw.slice(1)), "utf8") : raw;
|
|
97404
97857
|
return JSON.parse(text);
|
|
97405
97858
|
};
|
|
97406
97859
|
var init_changelog2 = __esm(() => {
|
|
@@ -97412,7 +97865,7 @@ var init_changelog2 = __esm(() => {
|
|
|
97412
97865
|
// packages/workit-cli/src/verbs/handoff.ts
|
|
97413
97866
|
var exports_handoff = {};
|
|
97414
97867
|
__export(exports_handoff, {
|
|
97415
|
-
run: () =>
|
|
97868
|
+
run: () => run22
|
|
97416
97869
|
});
|
|
97417
97870
|
import { parseArgs as parseArgs2 } from "node:util";
|
|
97418
97871
|
function human2(brief) {
|
|
@@ -97482,7 +97935,7 @@ async function resumeBrief(argv, io) {
|
|
|
97482
97935
|
}
|
|
97483
97936
|
return emit(io, ok({ ...data, recorded }), human2);
|
|
97484
97937
|
}
|
|
97485
|
-
async function
|
|
97938
|
+
async function run22(argv, io) {
|
|
97486
97939
|
if (!argv.some((arg) => arg === "--task" || arg.startsWith("--task=")))
|
|
97487
97940
|
return resumeBrief(argv, io);
|
|
97488
97941
|
await Promise.resolve().then(() => init_task());
|
|
@@ -97496,7 +97949,7 @@ var init_handoff = __esm(() => {
|
|
|
97496
97949
|
|
|
97497
97950
|
// packages/workit-cli/src/main.ts
|
|
97498
97951
|
init_package();
|
|
97499
|
-
import
|
|
97952
|
+
import path55 from "node:path";
|
|
97500
97953
|
|
|
97501
97954
|
// packages/workit-cli/src/help.ts
|
|
97502
97955
|
var HELP_FLAGS = new Set(["--help", "-h"]);
|
|
@@ -97715,8 +98168,8 @@ var VERBS = [
|
|
|
97715
98168
|
{
|
|
97716
98169
|
name: "doctor",
|
|
97717
98170
|
group: "setup",
|
|
97718
|
-
usage: "workit doctor [--fix-lock [--force [--yes]]]",
|
|
97719
|
-
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)",
|
|
97720
98173
|
load: () => Promise.resolve().then(() => (init_doctor2(), exports_doctor))
|
|
97721
98174
|
},
|
|
97722
98175
|
{
|
|
@@ -98142,7 +98595,7 @@ var defaultIo = (json) => ({
|
|
|
98142
98595
|
});
|
|
98143
98596
|
async function main(argv, overrides = {}, options = {}) {
|
|
98144
98597
|
const parsed = parseGlobals(argv);
|
|
98145
|
-
const cwd =
|
|
98598
|
+
const cwd = path55.resolve(overrides.cwd ?? process.cwd(), parsed.cwd ?? ".");
|
|
98146
98599
|
const io = { ...defaultIo(parsed.json), ...overrides, json: parsed.json, cwd };
|
|
98147
98600
|
if (parsed.error)
|
|
98148
98601
|
return emit(io, fail("invalid_input", parsed.error));
|