@brainervirus/workit-cursor 0.9.0 → 0.10.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/.cursor-plugin/plugin.json +1 -1
- package/dist/mcp-server.js +436 -205
- package/package.json +2 -2
package/dist/mcp-server.js
CHANGED
|
@@ -20376,7 +20376,7 @@ var init_config = __esm(() => {
|
|
|
20376
20376
|
"trunk-based": { allowed: ["*"], protected: ["main"] },
|
|
20377
20377
|
custom: { allowed: [], protected: [] }
|
|
20378
20378
|
};
|
|
20379
|
-
LOCALE_RE = /^[a-z]{2,3}(-[A-Z]{2})?$/;
|
|
20379
|
+
LOCALE_RE = /^[a-z]{2,3}(-(?:[A-Z]{2}|[0-9]{3}))?$/;
|
|
20380
20380
|
DEFAULTS = {
|
|
20381
20381
|
locale: "en",
|
|
20382
20382
|
localeOptions: ["en", "es-CL", "es-MX", "es-AR", "pt-BR"],
|
|
@@ -20630,15 +20630,28 @@ var run = (cwd, args) => {
|
|
|
20630
20630
|
var init_git = () => {};
|
|
20631
20631
|
|
|
20632
20632
|
// packages/workit-core/src/core/branch.ts
|
|
20633
|
-
import {
|
|
20633
|
+
import {
|
|
20634
|
+
copyFileSync as copyFileSync2,
|
|
20635
|
+
cpSync as cpSync2,
|
|
20636
|
+
existsSync as existsSync2,
|
|
20637
|
+
mkdirSync as mkdirSync3,
|
|
20638
|
+
readFileSync as readFileSync3,
|
|
20639
|
+
readdirSync as readdirSync3,
|
|
20640
|
+
renameSync,
|
|
20641
|
+
rmSync,
|
|
20642
|
+
statSync,
|
|
20643
|
+
writeFileSync as writeFileSync2
|
|
20644
|
+
} from "node:fs";
|
|
20634
20645
|
import { execFileSync as execFileSync2 } from "node:child_process";
|
|
20646
|
+
import { createHash } from "node:crypto";
|
|
20647
|
+
import { tmpdir } from "node:os";
|
|
20635
20648
|
import path4 from "node:path";
|
|
20636
20649
|
var resolveBranchPolicyFor = (workspaceRoot) => resolveBranchPolicy(readConfig(), resolveWorkspace(workspaceRoot)), policy = (root) => resolveBranchPolicyFor(root), allowedBranch = (root, name) => policy(root).allowed.some((r) => r.test(name)), isProtected = (root, name) => policy(root).protected.has(name.toLowerCase()), baseBranch = (cwd) => {
|
|
20637
20650
|
const resolved = vcsConfig("resolve", cwd);
|
|
20638
20651
|
if (resolved.ok === false)
|
|
20639
20652
|
return { error: String(resolved.error) };
|
|
20640
20653
|
return { base: String(resolved.defaultTargetBranch ?? "develop") };
|
|
20641
|
-
}, DECLARE_RE, USE_CURRENT_RE, readSafe2 = (p) => {
|
|
20654
|
+
}, DECLARE_RE, USE_CURRENT_RE, toPosix = (p) => p.split(path4.sep).join("/"), readSafe2 = (p) => {
|
|
20642
20655
|
try {
|
|
20643
20656
|
return readFileSync3(p, "utf8");
|
|
20644
20657
|
} catch {
|
|
@@ -20767,10 +20780,7 @@ var resolveBranchPolicyFor = (workspaceRoot) => resolveBranchPolicy(readConfig()
|
|
|
20767
20780
|
};
|
|
20768
20781
|
}
|
|
20769
20782
|
return { error: `cannot resolve docs branch from HEAD ${JSON.stringify(current)}` };
|
|
20770
|
-
},
|
|
20771
|
-
const git = gitContext(cwd);
|
|
20772
|
-
if (!git.branch || git.branch === "unknown")
|
|
20773
|
-
return { ok: false, error: "not in a git repository" };
|
|
20783
|
+
}, originBaseReady = (cwd, base) => {
|
|
20774
20784
|
const run2 = (args) => execFileSync2("git", args, { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
|
|
20775
20785
|
try {
|
|
20776
20786
|
try {
|
|
@@ -20778,20 +20788,27 @@ var resolveBranchPolicyFor = (workspaceRoot) => resolveBranchPolicy(readConfig()
|
|
|
20778
20788
|
} catch {
|
|
20779
20789
|
run2(["fetch", "origin", "--prune"]);
|
|
20780
20790
|
}
|
|
20781
|
-
let hasOriginBase = true;
|
|
20782
20791
|
try {
|
|
20783
20792
|
execFileSync2("git", ["show-ref", "--verify", "--quiet", `refs/remotes/origin/${base}`], {
|
|
20784
20793
|
cwd,
|
|
20785
20794
|
stdio: "pipe"
|
|
20786
20795
|
});
|
|
20787
20796
|
} catch {
|
|
20788
|
-
hasOriginBase = false;
|
|
20789
|
-
}
|
|
20790
|
-
if (!hasOriginBase)
|
|
20791
20797
|
return {
|
|
20792
20798
|
ok: false,
|
|
20793
20799
|
error: `origin/${base} missing — push ${base} before creating feature/* or bugfix/* branches`
|
|
20794
20800
|
};
|
|
20801
|
+
}
|
|
20802
|
+
return { ok: true };
|
|
20803
|
+
} catch (error2) {
|
|
20804
|
+
return {
|
|
20805
|
+
ok: false,
|
|
20806
|
+
error: error2 instanceof Error ? error2.message : "ensure-base-branch failed"
|
|
20807
|
+
};
|
|
20808
|
+
}
|
|
20809
|
+
}, fastForwardBase = (cwd, base) => {
|
|
20810
|
+
const run2 = (args) => execFileSync2("git", args, { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
|
|
20811
|
+
try {
|
|
20795
20812
|
let hasLocalBase = true;
|
|
20796
20813
|
try {
|
|
20797
20814
|
execFileSync2("git", ["show-ref", "--verify", "--quiet", `refs/heads/${base}`], {
|
|
@@ -20816,12 +20833,91 @@ var resolveBranchPolicyFor = (workspaceRoot) => resolveBranchPolicy(readConfig()
|
|
|
20816
20833
|
error: error2 instanceof Error ? error2.message : "ensure-base-branch failed"
|
|
20817
20834
|
};
|
|
20818
20835
|
}
|
|
20836
|
+
}, ensureBaseBranch = (cwd, base) => {
|
|
20837
|
+
const git = gitContext(cwd);
|
|
20838
|
+
if (!git.branch || git.branch === "unknown")
|
|
20839
|
+
return { ok: false, error: "not in a git repository" };
|
|
20840
|
+
const ready = originBaseReady(cwd, base);
|
|
20841
|
+
if (!ready.ok)
|
|
20842
|
+
return ready;
|
|
20843
|
+
return fastForwardBase(cwd, base);
|
|
20844
|
+
}, purgeStaleFlowGuardRoots = (now) => {
|
|
20845
|
+
const cutoff = now - 24 * 3600000;
|
|
20846
|
+
let entries;
|
|
20847
|
+
try {
|
|
20848
|
+
entries = readdirSync3(tmpdir());
|
|
20849
|
+
} catch {
|
|
20850
|
+
return;
|
|
20851
|
+
}
|
|
20852
|
+
for (const entry of entries) {
|
|
20853
|
+
if (!entry.startsWith("workit-flow-guard-"))
|
|
20854
|
+
continue;
|
|
20855
|
+
try {
|
|
20856
|
+
if (statSync(path4.join(tmpdir(), entry)).mtimeMs < cutoff)
|
|
20857
|
+
rmSync(path4.join(tmpdir(), entry), { recursive: true, force: true });
|
|
20858
|
+
} catch {}
|
|
20859
|
+
}
|
|
20860
|
+
}, snapshotFlowState = (cwd) => {
|
|
20861
|
+
purgeStaleFlowGuardRoots(Date.now());
|
|
20862
|
+
const root = path4.join(tmpdir(), `workit-flow-guard-${createHash("sha256").update(path4.resolve(cwd)).digest("hex").slice(0, 16)}.${process.pid}.${process.hrtime.bigint()}`);
|
|
20863
|
+
mkdirSync3(root, { recursive: true });
|
|
20864
|
+
const docsDir = path4.join(path4.resolve(cwd), "docs");
|
|
20865
|
+
let slugs = [];
|
|
20866
|
+
try {
|
|
20867
|
+
slugs = readdirSync3(docsDir);
|
|
20868
|
+
} catch {
|
|
20869
|
+
return root;
|
|
20870
|
+
}
|
|
20871
|
+
for (const slug of slugs) {
|
|
20872
|
+
for (const rel of [["sdd", "flow.json"], ["spec.md"], ["plan.md"]]) {
|
|
20873
|
+
const src = path4.join(docsDir, slug, ...rel);
|
|
20874
|
+
try {
|
|
20875
|
+
if (!statSync(src).isFile())
|
|
20876
|
+
continue;
|
|
20877
|
+
} catch {
|
|
20878
|
+
continue;
|
|
20879
|
+
}
|
|
20880
|
+
const dest = path4.join(root, "docs", slug, ...rel);
|
|
20881
|
+
mkdirSync3(path4.dirname(dest), { recursive: true });
|
|
20882
|
+
cpSync2(src, dest);
|
|
20883
|
+
}
|
|
20884
|
+
}
|
|
20885
|
+
return root;
|
|
20886
|
+
}, restoreFlowSnapshot = (snapDir, cwd) => {
|
|
20887
|
+
const walk = (dir, rel) => readdirSync3(dir, { withFileTypes: true }).flatMap((entry) => entry.isDirectory() ? walk(path4.join(dir, entry.name), path4.join(rel, entry.name)) : [path4.join(rel, entry.name)]);
|
|
20888
|
+
const restored = [];
|
|
20889
|
+
try {
|
|
20890
|
+
const workspace = path4.resolve(cwd);
|
|
20891
|
+
for (const rel of walk(snapDir, "")) {
|
|
20892
|
+
const dest = path4.join(workspace, rel);
|
|
20893
|
+
if (existsSync2(dest))
|
|
20894
|
+
continue;
|
|
20895
|
+
mkdirSync3(path4.dirname(dest), { recursive: true });
|
|
20896
|
+
const tmpDest = `${dest}.tmp-${process.pid}`;
|
|
20897
|
+
try {
|
|
20898
|
+
copyFileSync2(path4.join(snapDir, rel), tmpDest);
|
|
20899
|
+
renameSync(tmpDest, dest);
|
|
20900
|
+
} catch (error2) {
|
|
20901
|
+
rmSync(tmpDest, { force: true });
|
|
20902
|
+
throw error2;
|
|
20903
|
+
}
|
|
20904
|
+
restored.push(toPosix(rel));
|
|
20905
|
+
}
|
|
20906
|
+
rmSync(snapDir, { recursive: true, force: true });
|
|
20907
|
+
return { restored };
|
|
20908
|
+
} catch (error2) {
|
|
20909
|
+
return {
|
|
20910
|
+
restored,
|
|
20911
|
+
warning: `flow state snapshot restore failed: ${error2 instanceof Error ? error2.message : String(error2)}`
|
|
20912
|
+
};
|
|
20913
|
+
}
|
|
20819
20914
|
}, branchSetup = ({
|
|
20820
20915
|
action,
|
|
20821
20916
|
sdd_dir,
|
|
20822
20917
|
target_branch,
|
|
20823
20918
|
stash,
|
|
20824
|
-
workspace_root
|
|
20919
|
+
workspace_root,
|
|
20920
|
+
log
|
|
20825
20921
|
}) => {
|
|
20826
20922
|
const cwd = path4.resolve(workspace_root);
|
|
20827
20923
|
const exec = (args) => execFileSync2("git", args, { cwd, encoding: "utf8", stdio: ["pipe", "pipe", "pipe"] });
|
|
@@ -20840,20 +20936,74 @@ var resolveBranchPolicyFor = (workspaceRoot) => resolveBranchPolicy(readConfig()
|
|
|
20840
20936
|
};
|
|
20841
20937
|
const writeManifest = (data) => writeFileSync2(manifestPath, JSON.stringify(data, null, 2) + `
|
|
20842
20938
|
`, "utf8");
|
|
20939
|
+
let snapDir = null;
|
|
20940
|
+
const journal = (message) => log?.(`flow-guard: ${message}`);
|
|
20941
|
+
const snapshotRelPaths = () => {
|
|
20942
|
+
const dir = snapDir;
|
|
20943
|
+
if (!dir)
|
|
20944
|
+
return [];
|
|
20945
|
+
try {
|
|
20946
|
+
const walk = (from, rel) => readdirSync3(from, { withFileTypes: true }).flatMap((entry) => entry.isDirectory() ? walk(path4.join(from, entry.name), path4.join(rel, entry.name)) : [path4.join(rel, entry.name)]);
|
|
20947
|
+
return walk(dir, "").map(toPosix);
|
|
20948
|
+
} catch {
|
|
20949
|
+
return [];
|
|
20950
|
+
}
|
|
20951
|
+
};
|
|
20952
|
+
const journalSnapshot = () => {
|
|
20953
|
+
const dir = snapDir;
|
|
20954
|
+
if (!dir || !log)
|
|
20955
|
+
return;
|
|
20956
|
+
const rels = snapshotRelPaths();
|
|
20957
|
+
journal(`snapshot: ${rels.length} file(s)`);
|
|
20958
|
+
for (const rel of rels) {
|
|
20959
|
+
let shortHash = "";
|
|
20960
|
+
try {
|
|
20961
|
+
shortHash = createHash("sha256").update(readFileSync3(path4.join(dir, rel))).digest("hex").slice(0, 8);
|
|
20962
|
+
} catch {}
|
|
20963
|
+
journal(`snapshot: ${rel} sha=${shortHash}`);
|
|
20964
|
+
}
|
|
20965
|
+
};
|
|
20966
|
+
const journalPresence = (phase) => {
|
|
20967
|
+
for (const rel of snapshotRelPaths()) {
|
|
20968
|
+
journal(`${phase}: ${rel} ${existsSync2(path4.join(cwd, rel)) ? "present" : "MISSING"}`);
|
|
20969
|
+
}
|
|
20970
|
+
};
|
|
20971
|
+
const restoreWithWarning = (dir) => {
|
|
20972
|
+
if (!dir)
|
|
20973
|
+
return { restored: [], warnings: [] };
|
|
20974
|
+
const total = log ? snapshotRelPaths().length : 0;
|
|
20975
|
+
const { restored, warning } = restoreFlowSnapshot(dir, cwd);
|
|
20976
|
+
if (log)
|
|
20977
|
+
journal(`restore: restored=${restored.length} skipped=${total - restored.length}${warning ? ` warning: ${warning}` : ""}`);
|
|
20978
|
+
else if (warning)
|
|
20979
|
+
journal(`restore warning: ${warning}`);
|
|
20980
|
+
return { restored, warnings: warning ? [warning] : [] };
|
|
20981
|
+
};
|
|
20843
20982
|
if (action === "reapply_stash") {
|
|
20844
|
-
const
|
|
20845
|
-
const ref =
|
|
20983
|
+
const manifest = readManifest();
|
|
20984
|
+
const ref = manifest.stash_ref;
|
|
20846
20985
|
if (!ref)
|
|
20847
20986
|
return { error: "no stash_ref in manifest" };
|
|
20987
|
+
snapDir = snapshotFlowState(cwd);
|
|
20988
|
+
journalSnapshot();
|
|
20989
|
+
journal(`pre-pop: ${String(ref)}`);
|
|
20848
20990
|
try {
|
|
20849
20991
|
exec(["stash", "pop", String(ref)]);
|
|
20850
20992
|
} catch (error2) {
|
|
20851
|
-
|
|
20993
|
+
journal("pop: failed");
|
|
20994
|
+
const {
|
|
20995
|
+
warnings: [warning]
|
|
20996
|
+
} = restoreWithWarning(snapDir);
|
|
20997
|
+
return {
|
|
20998
|
+
error: `${error2 instanceof Error ? error2.message : "stash pop failed"}${warning ? `; ${warning}` : ""}`
|
|
20999
|
+
};
|
|
20852
21000
|
}
|
|
20853
|
-
|
|
20854
|
-
delete
|
|
20855
|
-
|
|
20856
|
-
|
|
21001
|
+
journal("pop: ok");
|
|
21002
|
+
delete manifest.stash_ref;
|
|
21003
|
+
delete manifest.stash_created_at;
|
|
21004
|
+
writeManifest(manifest);
|
|
21005
|
+
const { warnings: warnings2 } = restoreWithWarning(snapDir);
|
|
21006
|
+
return { action: "reapply_stash", ok: true, ...warnings2.length > 0 ? { warnings: warnings2 } : {} };
|
|
20857
21007
|
}
|
|
20858
21008
|
const target = target_branch ?? "";
|
|
20859
21009
|
if (!target)
|
|
@@ -20862,61 +21012,141 @@ var resolveBranchPolicyFor = (workspaceRoot) => resolveBranchPolicy(readConfig()
|
|
|
20862
21012
|
return { error: `protected branch ${target}` };
|
|
20863
21013
|
if (!allowedBranch(cwd, target))
|
|
20864
21014
|
return { error: `target branch ${target} is not allowed by the branch policy` };
|
|
21015
|
+
let base;
|
|
21016
|
+
let targetExists = true;
|
|
21017
|
+
try {
|
|
21018
|
+
exec(["rev-parse", "--verify", "--quiet", `refs/heads/${target}`]);
|
|
21019
|
+
} catch {
|
|
21020
|
+
targetExists = false;
|
|
21021
|
+
}
|
|
21022
|
+
if (!targetExists) {
|
|
21023
|
+
const baseResolved = baseBranch(cwd);
|
|
21024
|
+
if ("error" in baseResolved)
|
|
21025
|
+
return { error: baseResolved.error };
|
|
21026
|
+
base = baseResolved.base;
|
|
21027
|
+
}
|
|
21028
|
+
journal(`entry: current=${current} target=${target} base=${base ?? "-"}`);
|
|
20865
21029
|
let stash_ref;
|
|
21030
|
+
const failAfterStash = (message) => {
|
|
21031
|
+
let suffix = "";
|
|
21032
|
+
if (stash_ref) {
|
|
21033
|
+
journal(`pre-pop: ${stash_ref}`);
|
|
21034
|
+
try {
|
|
21035
|
+
exec(["stash", "pop", stash_ref]);
|
|
21036
|
+
stash_ref = undefined;
|
|
21037
|
+
journal("pop: ok");
|
|
21038
|
+
} catch {
|
|
21039
|
+
journal("pop: failed");
|
|
21040
|
+
suffix = " (changes preserved in stash)";
|
|
21041
|
+
}
|
|
21042
|
+
}
|
|
21043
|
+
const {
|
|
21044
|
+
warnings: [warning]
|
|
21045
|
+
} = restoreWithWarning(snapDir);
|
|
21046
|
+
return { error: `${message}${suffix}${warning ? `; ${warning}` : ""}` };
|
|
21047
|
+
};
|
|
20866
21048
|
if (current !== target) {
|
|
20867
21049
|
const dirty = Boolean(gitContext(cwd).status_short.trim());
|
|
21050
|
+
if (dirty && stash !== "yes") {
|
|
21051
|
+
return {
|
|
21052
|
+
error: "dirty working tree — ask with native question, then call workit_branch_setup with stash=yes"
|
|
21053
|
+
};
|
|
21054
|
+
}
|
|
21055
|
+
let validatedBase;
|
|
21056
|
+
if (!targetExists && base !== undefined) {
|
|
21057
|
+
const ready = originBaseReady(cwd, base);
|
|
21058
|
+
if (!ready.ok)
|
|
21059
|
+
return { error: ready.error ?? "ensure-base-branch failed" };
|
|
21060
|
+
validatedBase = base;
|
|
21061
|
+
}
|
|
20868
21062
|
if (dirty) {
|
|
20869
|
-
if (stash !== "yes") {
|
|
20870
|
-
return {
|
|
20871
|
-
error: "dirty working tree — ask with native question, then call workit_branch_setup with stash=yes"
|
|
20872
|
-
};
|
|
20873
|
-
}
|
|
20874
21063
|
try {
|
|
21064
|
+
snapDir = snapshotFlowState(cwd);
|
|
21065
|
+
journalSnapshot();
|
|
20875
21066
|
exec(["stash", "push", "-u", "-m", `workit: pre-checkout ${target}`, "--", ":!docs/*/sdd"]);
|
|
20876
21067
|
} catch (error2) {
|
|
20877
21068
|
return { error: error2 instanceof Error ? error2.message : "stash push failed" };
|
|
20878
21069
|
}
|
|
20879
21070
|
stash_ref = "stash@{0}";
|
|
21071
|
+
journal(`stash push: ${stash_ref}`);
|
|
20880
21072
|
}
|
|
20881
21073
|
try {
|
|
20882
21074
|
exec(["checkout", target]);
|
|
21075
|
+
journalPresence("post-checkout");
|
|
20883
21076
|
} catch (error2) {
|
|
20884
21077
|
const message = error2 instanceof Error ? error2.message : "checkout failed";
|
|
20885
21078
|
if (/worktree/i.test(message)) {
|
|
20886
|
-
return {
|
|
20887
|
-
error: `branch ${target} is locked by an existing git worktree — remove it first (we do not use worktrees)`
|
|
20888
|
-
};
|
|
21079
|
+
return failAfterStash(`branch ${target} is locked by an existing git worktree — remove it first (we do not use worktrees)`);
|
|
20889
21080
|
}
|
|
20890
21081
|
try {
|
|
20891
|
-
|
|
20892
|
-
if (
|
|
20893
|
-
|
|
20894
|
-
|
|
21082
|
+
let effectiveBase = base;
|
|
21083
|
+
if (effectiveBase === undefined) {
|
|
21084
|
+
const lateResolved = baseBranch(cwd);
|
|
21085
|
+
if ("error" in lateResolved)
|
|
21086
|
+
return failAfterStash(lateResolved.error);
|
|
21087
|
+
effectiveBase = lateResolved.base;
|
|
21088
|
+
}
|
|
21089
|
+
const baseResult = validatedBase !== undefined ? fastForwardBase(cwd, effectiveBase) : ensureBaseBranch(cwd, effectiveBase);
|
|
20895
21090
|
if (!baseResult.ok)
|
|
20896
|
-
return
|
|
21091
|
+
return failAfterStash(baseResult.error ?? "ensure-base-branch failed");
|
|
20897
21092
|
exec(["checkout", "-b", target]);
|
|
21093
|
+
journalPresence("post-create");
|
|
20898
21094
|
} catch (createError) {
|
|
20899
|
-
return
|
|
20900
|
-
error: createError instanceof Error ? createError.message : "branch create failed"
|
|
20901
|
-
};
|
|
21095
|
+
return failAfterStash(createError instanceof Error ? createError.message : "branch create failed");
|
|
20902
21096
|
}
|
|
20903
21097
|
}
|
|
20904
21098
|
}
|
|
20905
|
-
|
|
20906
|
-
|
|
20907
|
-
|
|
20908
|
-
|
|
20909
|
-
|
|
20910
|
-
|
|
21099
|
+
try {
|
|
21100
|
+
const manifest = readManifest();
|
|
21101
|
+
manifest.branch = target;
|
|
21102
|
+
manifest.previous_branch = current;
|
|
21103
|
+
if (stash_ref) {
|
|
21104
|
+
manifest.stash_ref = stash_ref;
|
|
21105
|
+
manifest.stash_created_at = new Date().toISOString();
|
|
21106
|
+
}
|
|
21107
|
+
writeManifest(manifest);
|
|
21108
|
+
} catch (error2) {
|
|
21109
|
+
const result = failAfterStash(error2 instanceof Error ? `manifest update failed: ${error2.message}` : "manifest update failed");
|
|
21110
|
+
if (stash_ref === undefined && gitContext(cwd).branch !== current) {
|
|
21111
|
+
try {
|
|
21112
|
+
exec(["checkout", current]);
|
|
21113
|
+
} catch {}
|
|
21114
|
+
}
|
|
21115
|
+
return result;
|
|
21116
|
+
}
|
|
21117
|
+
const { restored: restoredRels, warnings } = restoreWithWarning(snapDir);
|
|
21118
|
+
if (stash_ref && snapDir && warnings.length === 0) {
|
|
21119
|
+
const covered = new Set(restoredRels.map(toPosix));
|
|
21120
|
+
try {
|
|
21121
|
+
const stashed = exec([
|
|
21122
|
+
"stash",
|
|
21123
|
+
"show",
|
|
21124
|
+
"--include-untracked",
|
|
21125
|
+
"--name-only",
|
|
21126
|
+
String(stash_ref)
|
|
21127
|
+
]).split(`
|
|
21128
|
+
`).map((line) => toPosix(line.trim())).filter(Boolean);
|
|
21129
|
+
if (stashed.length > 0 && stashed.every((p) => covered.has(p))) {
|
|
21130
|
+
exec(["stash", "drop", String(stash_ref)]);
|
|
21131
|
+
stash_ref = undefined;
|
|
21132
|
+
journal("dropped redundant stash (fully covered by snapshot restore)");
|
|
21133
|
+
const manifest = readManifest();
|
|
21134
|
+
delete manifest.stash_ref;
|
|
21135
|
+
delete manifest.stash_created_at;
|
|
21136
|
+
writeManifest(manifest);
|
|
21137
|
+
} else {
|
|
21138
|
+
journal(`kept stash ref ${stash_ref} (not fully covered by actual restores)`);
|
|
21139
|
+
}
|
|
21140
|
+
} catch {}
|
|
20911
21141
|
}
|
|
20912
|
-
writeManifest(manifest);
|
|
20913
21142
|
return {
|
|
20914
21143
|
action: "setup",
|
|
20915
21144
|
ok: true,
|
|
20916
21145
|
branch: target,
|
|
20917
21146
|
previous_branch: current,
|
|
20918
21147
|
stash_ref: stash_ref ?? null,
|
|
20919
|
-
manifest: manifestPath
|
|
21148
|
+
manifest: manifestPath,
|
|
21149
|
+
...warnings.length > 0 ? { warnings } : {}
|
|
20920
21150
|
};
|
|
20921
21151
|
};
|
|
20922
21152
|
var init_branch = __esm(() => {
|
|
@@ -21232,7 +21462,7 @@ var init_vcs_config = __esm(() => {
|
|
|
21232
21462
|
|
|
21233
21463
|
// packages/workit-core/src/core/repo-context.ts
|
|
21234
21464
|
import { spawnSync as spawnSync2 } from "node:child_process";
|
|
21235
|
-
import { existsSync as
|
|
21465
|
+
import { existsSync as existsSync3, readFileSync as readFileSync4, readdirSync as readdirSync4 } from "node:fs";
|
|
21236
21466
|
import path6 from "node:path";
|
|
21237
21467
|
function resolvePrBranchContext(cwd) {
|
|
21238
21468
|
const branch = currentBranch(cwd);
|
|
@@ -21350,7 +21580,7 @@ ${status.stderr}` : "");
|
|
|
21350
21580
|
stdout += `
|
|
21351
21581
|
`;
|
|
21352
21582
|
stdout += printSection("Recent Validation Signals");
|
|
21353
|
-
if (
|
|
21583
|
+
if (existsSync3(path6.join(cwd, "package.json"))) {
|
|
21354
21584
|
stdout += `package.json detected. Common scripts:
|
|
21355
21585
|
`;
|
|
21356
21586
|
const found = packageScripts(cwd, ["lint", "format:check", "test", "build"]);
|
|
@@ -21359,7 +21589,7 @@ ${status.stderr}` : "");
|
|
|
21359
21589
|
`) + `
|
|
21360
21590
|
`;
|
|
21361
21591
|
}
|
|
21362
|
-
if (
|
|
21592
|
+
if (existsSync3(path6.join(cwd, "Cargo.toml")) || existsSync3(path6.join(cwd, "src-tauri/Cargo.toml"))) {
|
|
21363
21593
|
stdout += `Rust project detected.
|
|
21364
21594
|
`;
|
|
21365
21595
|
}
|
|
@@ -21400,7 +21630,7 @@ function changelogContext(root, range) {
|
|
|
21400
21630
|
`;
|
|
21401
21631
|
stdout += printSection("Existing CHANGELOG.md");
|
|
21402
21632
|
const changelogPath = path6.join(cwd, "CHANGELOG.md");
|
|
21403
|
-
if (
|
|
21633
|
+
if (existsSync3(changelogPath)) {
|
|
21404
21634
|
stdout += readTrimmed(changelogPath, 260) + `
|
|
21405
21635
|
`;
|
|
21406
21636
|
} else {
|
|
@@ -21438,7 +21668,7 @@ function docsRefreshContext(root, range) {
|
|
|
21438
21668
|
`;
|
|
21439
21669
|
stdout += printSection("README Preview");
|
|
21440
21670
|
const readme = path6.join(cwd, "README.md");
|
|
21441
|
-
if (
|
|
21671
|
+
if (existsSync3(readme)) {
|
|
21442
21672
|
stdout += readTrimmed(readme, 220) + `
|
|
21443
21673
|
`;
|
|
21444
21674
|
} else {
|
|
@@ -21447,7 +21677,7 @@ function docsRefreshContext(root, range) {
|
|
|
21447
21677
|
}
|
|
21448
21678
|
stdout += printSection("Package Scripts");
|
|
21449
21679
|
const pkgPath = path6.join(cwd, "package.json");
|
|
21450
|
-
if (
|
|
21680
|
+
if (existsSync3(pkgPath)) {
|
|
21451
21681
|
try {
|
|
21452
21682
|
const pkg = JSON.parse(readFileSync4(pkgPath, "utf8"));
|
|
21453
21683
|
stdout += JSON.stringify({ name: pkg.name, version: pkg.version, scripts: pkg.scripts }, null, 2) + `
|
|
@@ -21494,7 +21724,7 @@ function releaseNotesContext(root, rangeOrTag) {
|
|
|
21494
21724
|
`;
|
|
21495
21725
|
stdout += printSection("Existing Release Files");
|
|
21496
21726
|
for (const rel of ["CHANGELOG.md", "RELEASE_NOTES.md", ".github/releases.md"]) {
|
|
21497
|
-
if (
|
|
21727
|
+
if (existsSync3(path6.join(cwd, rel)))
|
|
21498
21728
|
stdout += rel + `
|
|
21499
21729
|
`;
|
|
21500
21730
|
}
|
|
@@ -21531,7 +21761,7 @@ var runGit = (cwd, args) => {
|
|
|
21531
21761
|
|
|
21532
21762
|
`, probeCaseInsensitive = (dir, wanted) => {
|
|
21533
21763
|
try {
|
|
21534
|
-
for (const entry of
|
|
21764
|
+
for (const entry of readdirSync4(dir)) {
|
|
21535
21765
|
if (entry.toLowerCase() === wanted.toLowerCase())
|
|
21536
21766
|
return entry;
|
|
21537
21767
|
}
|
|
@@ -21577,7 +21807,7 @@ var runGit = (cwd, args) => {
|
|
|
21577
21807
|
return runGit(cwd, ["diff", "--stat", "--"]).stdout;
|
|
21578
21808
|
}, packageScripts = (cwd, keys) => {
|
|
21579
21809
|
const pkgPath = path6.join(cwd, "package.json");
|
|
21580
|
-
if (!
|
|
21810
|
+
if (!existsSync3(pkgPath))
|
|
21581
21811
|
return [];
|
|
21582
21812
|
try {
|
|
21583
21813
|
const pkg = JSON.parse(readFileSync4(pkgPath, "utf8"));
|
|
@@ -21593,7 +21823,7 @@ var runGit = (cwd, args) => {
|
|
|
21593
21823
|
return;
|
|
21594
21824
|
let entries;
|
|
21595
21825
|
try {
|
|
21596
|
-
entries =
|
|
21826
|
+
entries = readdirSync4(dir, { withFileTypes: true });
|
|
21597
21827
|
} catch {
|
|
21598
21828
|
return;
|
|
21599
21829
|
}
|
|
@@ -21610,7 +21840,7 @@ var runGit = (cwd, args) => {
|
|
|
21610
21840
|
walk(cwd, 1);
|
|
21611
21841
|
return matches.sort().slice(0, 200);
|
|
21612
21842
|
}, readTrimmed = (file, maxLines) => {
|
|
21613
|
-
if (!
|
|
21843
|
+
if (!existsSync3(file))
|
|
21614
21844
|
return "";
|
|
21615
21845
|
const lines = readFileSync4(file, "utf8").split(`
|
|
21616
21846
|
`);
|
|
@@ -21629,7 +21859,7 @@ var init_repo_context = __esm(() => {
|
|
|
21629
21859
|
|
|
21630
21860
|
// packages/workit-core/src/core/verify-project.ts
|
|
21631
21861
|
import { spawnSync as spawnSync3 } from "node:child_process";
|
|
21632
|
-
import { existsSync as
|
|
21862
|
+
import { existsSync as existsSync4, readFileSync as readFileSync5, statSync as statSync2 } from "node:fs";
|
|
21633
21863
|
import path7 from "node:path";
|
|
21634
21864
|
function runVerifyProject(root, dryRun = false) {
|
|
21635
21865
|
const cwd = repoRoot(root);
|
|
@@ -21688,7 +21918,7 @@ root: ${cwd}
|
|
|
21688
21918
|
lines.push(`dry_run: ${String(dryRun)}
|
|
21689
21919
|
`);
|
|
21690
21920
|
const pkgPath = path7.join(cwd, "package.json");
|
|
21691
|
-
if (
|
|
21921
|
+
if (existsSync4(pkgPath)) {
|
|
21692
21922
|
const runner = packageRunner(cwd);
|
|
21693
21923
|
for (const script of ["lint", "format:check", "test", "build"]) {
|
|
21694
21924
|
if (hasScript(cwd, script)) {
|
|
@@ -21703,7 +21933,7 @@ root: ${cwd}
|
|
|
21703
21933
|
} else {
|
|
21704
21934
|
skipCheck("javascript", "package.json not found");
|
|
21705
21935
|
}
|
|
21706
|
-
const cargoManifest =
|
|
21936
|
+
const cargoManifest = existsSync4(path7.join(cwd, "Cargo.toml")) ? "Cargo.toml" : existsSync4(path7.join(cwd, "src-tauri/Cargo.toml")) ? "src-tauri/Cargo.toml" : "";
|
|
21707
21937
|
if (cargoManifest) {
|
|
21708
21938
|
runCheck("cargo fmt", "cargo", ["fmt", "--manifest-path", cargoManifest, "--", "--check"]);
|
|
21709
21939
|
runCheck("cargo clippy", "cargo", [
|
|
@@ -21719,7 +21949,7 @@ root: ${cwd}
|
|
|
21719
21949
|
} else {
|
|
21720
21950
|
skipCheck("rust", "Cargo.toml not found");
|
|
21721
21951
|
}
|
|
21722
|
-
if (
|
|
21952
|
+
if (existsSync4(path7.join(cwd, "pyproject.toml")) || existsSync4(path7.join(cwd, "pytest.ini")) || existsSync4(path7.join(cwd, "tests"))) {
|
|
21723
21953
|
if (commandOnPath("pytest"))
|
|
21724
21954
|
runCheck("pytest", "pytest", []);
|
|
21725
21955
|
else
|
|
@@ -21741,7 +21971,7 @@ root: ${cwd}
|
|
|
21741
21971
|
lines.push(`status: skipped (dry run)
|
|
21742
21972
|
`);
|
|
21743
21973
|
skipped += 1;
|
|
21744
|
-
} else if (
|
|
21974
|
+
} else if (existsSync4(changelogPath)) {
|
|
21745
21975
|
if (/## \[Unreleased\]/i.test(readFileSync5(changelogPath, "utf8"))) {
|
|
21746
21976
|
lines.push(`status: pass
|
|
21747
21977
|
`);
|
|
@@ -21783,9 +22013,9 @@ var commandOnPath = (name) => {
|
|
|
21783
22013
|
for (const candidateName of names) {
|
|
21784
22014
|
const candidate = path7.join(dir, candidateName);
|
|
21785
22015
|
try {
|
|
21786
|
-
|
|
22016
|
+
statSync2(candidate);
|
|
21787
22017
|
if (process.platform !== "win32") {
|
|
21788
|
-
const mode =
|
|
22018
|
+
const mode = statSync2(candidate).mode & 73;
|
|
21789
22019
|
if (mode === 0)
|
|
21790
22020
|
continue;
|
|
21791
22021
|
}
|
|
@@ -21796,7 +22026,7 @@ var commandOnPath = (name) => {
|
|
|
21796
22026
|
return false;
|
|
21797
22027
|
}, hasScript = (cwd, name) => {
|
|
21798
22028
|
const pkgPath = path7.join(cwd, "package.json");
|
|
21799
|
-
if (!
|
|
22029
|
+
if (!existsSync4(pkgPath))
|
|
21800
22030
|
return false;
|
|
21801
22031
|
try {
|
|
21802
22032
|
const pkg = JSON.parse(readFileSync5(pkgPath, "utf8"));
|
|
@@ -21805,10 +22035,10 @@ var commandOnPath = (name) => {
|
|
|
21805
22035
|
return false;
|
|
21806
22036
|
}
|
|
21807
22037
|
}, packageRunner = (cwd) => {
|
|
21808
|
-
if (
|
|
22038
|
+
if (existsSync4(path7.join(cwd, "pnpm-lock.yaml")))
|
|
21809
22039
|
return "pnpm";
|
|
21810
22040
|
const pkgPath = path7.join(cwd, "package.json");
|
|
21811
|
-
if (
|
|
22041
|
+
if (existsSync4(pkgPath)) {
|
|
21812
22042
|
try {
|
|
21813
22043
|
const pkg = JSON.parse(readFileSync5(pkgPath, "utf8"));
|
|
21814
22044
|
if (typeof pkg.packageManager === "string" && pkg.packageManager.startsWith("pnpm")) {
|
|
@@ -21816,7 +22046,7 @@ var commandOnPath = (name) => {
|
|
|
21816
22046
|
}
|
|
21817
22047
|
} catch {}
|
|
21818
22048
|
}
|
|
21819
|
-
if (
|
|
22049
|
+
if (existsSync4(path7.join(cwd, "yarn.lock")))
|
|
21820
22050
|
return "yarn";
|
|
21821
22051
|
return "npm";
|
|
21822
22052
|
};
|
|
@@ -21836,21 +22066,21 @@ var init_support_matrix = __esm(() => {
|
|
|
21836
22066
|
});
|
|
21837
22067
|
|
|
21838
22068
|
// packages/workit-core/src/core/package-root.ts
|
|
21839
|
-
import { existsSync as
|
|
22069
|
+
import { existsSync as existsSync5 } from "node:fs";
|
|
21840
22070
|
import path8 from "node:path";
|
|
21841
22071
|
import { fileURLToPath } from "node:url";
|
|
21842
22072
|
var packageRoot = () => {
|
|
21843
22073
|
let dir = path8.dirname(fileURLToPath(import.meta.url));
|
|
21844
22074
|
while (true) {
|
|
21845
22075
|
const parent = path8.dirname(dir);
|
|
21846
|
-
if (
|
|
22076
|
+
if (existsSync5(path8.join(dir, "package.json")) || parent === dir)
|
|
21847
22077
|
return dir;
|
|
21848
22078
|
dir = parent;
|
|
21849
22079
|
}
|
|
21850
22080
|
}, assetRoot = () => {
|
|
21851
22081
|
const root = packageRoot();
|
|
21852
22082
|
const assets = path8.join(root, "assets");
|
|
21853
|
-
return
|
|
22083
|
+
return existsSync5(assets) ? assets : root;
|
|
21854
22084
|
};
|
|
21855
22085
|
var init_package_root = () => {};
|
|
21856
22086
|
|
|
@@ -21883,9 +22113,9 @@ var named = (s, name) => s === name || s.startsWith(`${name}@`), CURSOR_RUNTIME_
|
|
|
21883
22113
|
var init_registration = () => {};
|
|
21884
22114
|
|
|
21885
22115
|
// packages/workit-core/src/core/skill-manifests.ts
|
|
21886
|
-
import { existsSync as
|
|
22116
|
+
import { existsSync as existsSync6, readFileSync as readFileSync6, readdirSync as readdirSync5, statSync as statSync3 } from "node:fs";
|
|
21887
22117
|
import path9 from "node:path";
|
|
21888
|
-
var CANONICAL_SKILLS, skillManifestNames = (root) =>
|
|
22118
|
+
var CANONICAL_SKILLS, skillManifestNames = (root) => existsSync6(root) ? readdirSync5(root).filter((name) => existsSync6(path9.join(root, name, "SKILL.md"))).sort() : [], validateSkillManifests = (root, expected, label) => {
|
|
21889
22119
|
const actual = skillManifestNames(root);
|
|
21890
22120
|
const missing = expected.filter((name) => !actual.includes(name));
|
|
21891
22121
|
const extra = actual.filter((name) => !expected.includes(name));
|
|
@@ -21901,11 +22131,11 @@ var CANONICAL_SKILLS, skillManifestNames = (root) => existsSync5(root) ? readdir
|
|
|
21901
22131
|
const pending = [vendor];
|
|
21902
22132
|
while (pending.length > 0) {
|
|
21903
22133
|
const dir = pending.pop();
|
|
21904
|
-
for (const entry of
|
|
22134
|
+
for (const entry of readdirSync5(dir, { withFileTypes: true })) {
|
|
21905
22135
|
const file = path9.join(dir, entry.name);
|
|
21906
22136
|
if (entry.isDirectory())
|
|
21907
22137
|
pending.push(file);
|
|
21908
|
-
else if ((
|
|
22138
|
+
else if ((statSync3(file).mode & 73) !== 0 || readFileSync6(file).subarray(0, 2).toString("latin1") === "#!") {
|
|
21909
22139
|
return `Cursor vendor contains active file: ${file}`;
|
|
21910
22140
|
}
|
|
21911
22141
|
}
|
|
@@ -21950,13 +22180,13 @@ var init_skill_manifests = __esm(() => {
|
|
|
21950
22180
|
|
|
21951
22181
|
// packages/workit-core/src/core/doctor.ts
|
|
21952
22182
|
import { spawnSync as spawnSync4 } from "node:child_process";
|
|
21953
|
-
import { existsSync as
|
|
22183
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync7, statSync as statSync4, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "node:fs";
|
|
21954
22184
|
import os3 from "node:os";
|
|
21955
22185
|
import path10 from "node:path";
|
|
21956
22186
|
var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
21957
22187
|
let dir = path10.resolve(cwd);
|
|
21958
22188
|
while (true) {
|
|
21959
|
-
if (
|
|
22189
|
+
if (existsSync7(path10.join(dir, "packages", "workit-core", "package.json")))
|
|
21960
22190
|
return dir;
|
|
21961
22191
|
const parent = path10.dirname(dir);
|
|
21962
22192
|
if (parent === dir)
|
|
@@ -22010,7 +22240,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
22010
22240
|
for (const candidateName of names) {
|
|
22011
22241
|
const candidate = path10.join(dir, candidateName);
|
|
22012
22242
|
try {
|
|
22013
|
-
const st =
|
|
22243
|
+
const st = statSync4(candidate);
|
|
22014
22244
|
if (process.platform !== "win32" && (st.mode & 73) === 0)
|
|
22015
22245
|
continue;
|
|
22016
22246
|
return true;
|
|
@@ -22034,14 +22264,14 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
22034
22264
|
}
|
|
22035
22265
|
return true;
|
|
22036
22266
|
}, resolveBun = (env) => {
|
|
22037
|
-
if (env.BUN &&
|
|
22267
|
+
if (env.BUN && existsSync7(env.BUN))
|
|
22038
22268
|
return env.BUN;
|
|
22039
22269
|
for (const candidate of [
|
|
22040
22270
|
path10.join(os3.homedir(), ".bun/bin/bun"),
|
|
22041
22271
|
"/usr/local/bin/bun",
|
|
22042
22272
|
"/usr/bin/bun"
|
|
22043
22273
|
]) {
|
|
22044
|
-
if (
|
|
22274
|
+
if (existsSync7(candidate))
|
|
22045
22275
|
return candidate;
|
|
22046
22276
|
}
|
|
22047
22277
|
return commandOnPath2("bun", env) ? "bun" : null;
|
|
@@ -22155,7 +22385,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
22155
22385
|
}
|
|
22156
22386
|
}, hostsFor = (host) => host === "cli" ? ["opencode", "cursor", "cli"] : [host], checkAssets = (res) => {
|
|
22157
22387
|
const dev = res.dev;
|
|
22158
|
-
const missing = dev ? hostsFor(res.host).flatMap((h) => assetPathsFor(h, dev).filter((p) => !
|
|
22388
|
+
const missing = dev ? hostsFor(res.host).flatMap((h) => assetPathsFor(h, dev).filter((p) => !existsSync7(p)).map((p) => `${h}: ${p}`)) : [];
|
|
22159
22389
|
if (res.host === "cursor" || res.host === "cli") {
|
|
22160
22390
|
const cursorError = validateCursorSkills(res.cursorPluginDir);
|
|
22161
22391
|
if (cursorError)
|
|
@@ -22196,7 +22426,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
22196
22426
|
}
|
|
22197
22427
|
}, validNodeEntry = (entry, runtime, env) => {
|
|
22198
22428
|
try {
|
|
22199
|
-
const stat =
|
|
22429
|
+
const stat = statSync4(entry);
|
|
22200
22430
|
if (!stat.isFile() || stat.size === 0 || !readFileSync7(entry, "utf8").startsWith(`#!/usr/bin/env node
|
|
22201
22431
|
`)) {
|
|
22202
22432
|
return false;
|
|
@@ -22206,7 +22436,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
22206
22436
|
return false;
|
|
22207
22437
|
}
|
|
22208
22438
|
}, registeredCursorLauncher = (res) => {
|
|
22209
|
-
if (!
|
|
22439
|
+
if (!existsSync7(res.cursorMcp))
|
|
22210
22440
|
return "invalid";
|
|
22211
22441
|
const config2 = readJson(res.cursorMcp);
|
|
22212
22442
|
if (!config2)
|
|
@@ -22235,7 +22465,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
22235
22465
|
};
|
|
22236
22466
|
}, canonicalCursorHook, registeredCursorHook = (res) => {
|
|
22237
22467
|
const hooksFile = path10.join(res.cursorPluginDir, "hooks", "hooks-cursor.json");
|
|
22238
|
-
if (!
|
|
22468
|
+
if (!existsSync7(hooksFile))
|
|
22239
22469
|
return "invalid";
|
|
22240
22470
|
const config2 = readJson(hooksFile);
|
|
22241
22471
|
if (!config2)
|
|
@@ -22278,7 +22508,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
22278
22508
|
}
|
|
22279
22509
|
}
|
|
22280
22510
|
if (dev) {
|
|
22281
|
-
missing.push(...hosts.filter((h) => h !== "cursor").flatMap((h) => launcherSlotsFor(h, dev).filter((slot) => !slot.some((p) =>
|
|
22511
|
+
missing.push(...hosts.filter((h) => h !== "cursor").flatMap((h) => launcherSlotsFor(h, dev).filter((slot) => !slot.some((p) => existsSync7(p))).map((slot) => `${h}: ${slot.join(" or ")}`)));
|
|
22282
22512
|
}
|
|
22283
22513
|
if (missing.length > 0) {
|
|
22284
22514
|
return {
|
|
@@ -22330,7 +22560,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
22330
22560
|
return "stale";
|
|
22331
22561
|
if (entry.startsWith("file:")) {
|
|
22332
22562
|
const target = entry.replace(/^file:\/\//, "").replace(/^file:/, "");
|
|
22333
|
-
return
|
|
22563
|
+
return existsSync7(target) ? "ok" : "missing-file";
|
|
22334
22564
|
}
|
|
22335
22565
|
return "ok";
|
|
22336
22566
|
}, checkStalePin = (res) => {
|
|
@@ -22341,7 +22571,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
22341
22571
|
detail: "opencode pin not inspected on the cursor host"
|
|
22342
22572
|
};
|
|
22343
22573
|
}
|
|
22344
|
-
if (!
|
|
22574
|
+
if (!existsSync7(res.opencodeConfig)) {
|
|
22345
22575
|
return {
|
|
22346
22576
|
id: "stale_pin",
|
|
22347
22577
|
status: "pass",
|
|
@@ -22378,7 +22608,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
22378
22608
|
return { id: "stale_pin", status: "pass", detail: "opencode pin resolves" };
|
|
22379
22609
|
}, pluginMcpSelectors = (res) => {
|
|
22380
22610
|
const p = path10.join(res.cursorPluginDir, "mcp.json");
|
|
22381
|
-
if (!
|
|
22611
|
+
if (!existsSync7(p))
|
|
22382
22612
|
return null;
|
|
22383
22613
|
const cfg = readJson(p);
|
|
22384
22614
|
const server = cfg?.mcpServers?.workit;
|
|
@@ -22488,13 +22718,13 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
22488
22718
|
const problems = [];
|
|
22489
22719
|
const opencodeHost = res.host !== "cursor";
|
|
22490
22720
|
const cursorHost = res.host !== "opencode";
|
|
22491
|
-
if (opencodeHost &&
|
|
22721
|
+
if (opencodeHost && existsSync7(res.opencodeConfig)) {
|
|
22492
22722
|
const cfg = readJson(res.opencodeConfig);
|
|
22493
22723
|
const entries = pluginEntries(cfg);
|
|
22494
22724
|
if (entries.length > 1)
|
|
22495
22725
|
problems.push(`opencode registers ${entries.length} workit plugin entries`);
|
|
22496
22726
|
}
|
|
22497
|
-
if (cursorHost &&
|
|
22727
|
+
if (cursorHost && existsSync7(res.cursorSettings)) {
|
|
22498
22728
|
const settings = readJson(res.cursorSettings);
|
|
22499
22729
|
const enabled = settings?.enabled_plugins;
|
|
22500
22730
|
if (enabled && typeof enabled === "object") {
|
|
@@ -22509,7 +22739,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
22509
22739
|
if (dirs.length > 1)
|
|
22510
22740
|
problems.push(`cursor plugin_dirs has ${dirs.length} workit entries`);
|
|
22511
22741
|
}
|
|
22512
|
-
if (cursorHost &&
|
|
22742
|
+
if (cursorHost && existsSync7(res.cursorMcp)) {
|
|
22513
22743
|
const mcp = readJson(res.cursorMcp);
|
|
22514
22744
|
const servers = mcp?.mcpServers ?? {};
|
|
22515
22745
|
if (servers && typeof servers === "object") {
|
|
@@ -22535,16 +22765,16 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
22535
22765
|
const files = [];
|
|
22536
22766
|
for (const name of ["config.json", "youtrack.json", "vcs.json", "workspaces.json"]) {
|
|
22537
22767
|
const p = path10.join(res.configDir, name);
|
|
22538
|
-
if (
|
|
22768
|
+
if (existsSync7(p))
|
|
22539
22769
|
files.push(p);
|
|
22540
22770
|
}
|
|
22541
22771
|
const opencodeHost = res.host !== "cursor";
|
|
22542
22772
|
const cursorHost = res.host !== "opencode";
|
|
22543
|
-
if (opencodeHost &&
|
|
22773
|
+
if (opencodeHost && existsSync7(res.opencodeConfig))
|
|
22544
22774
|
files.push(res.opencodeConfig);
|
|
22545
|
-
if (cursorHost &&
|
|
22775
|
+
if (cursorHost && existsSync7(res.cursorSettings))
|
|
22546
22776
|
files.push(res.cursorSettings);
|
|
22547
|
-
if (cursorHost &&
|
|
22777
|
+
if (cursorHost && existsSync7(res.cursorMcp))
|
|
22548
22778
|
files.push(res.cursorMcp);
|
|
22549
22779
|
const bad = files.filter((p) => !parsesAsConfigObject(p));
|
|
22550
22780
|
if (bad.length === 0)
|
|
@@ -22561,7 +22791,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
22561
22791
|
};
|
|
22562
22792
|
}, checkWorkspaceMismatch = (res) => {
|
|
22563
22793
|
const file = path10.join(res.configDir, "workspaces.json");
|
|
22564
|
-
if (!
|
|
22794
|
+
if (!existsSync7(file))
|
|
22565
22795
|
return {
|
|
22566
22796
|
id: "workspace_mismatch",
|
|
22567
22797
|
status: "pass",
|
|
@@ -22599,7 +22829,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
22599
22829
|
const youtrackJson = readJson(path10.join(res.configDir, "youtrack.json"));
|
|
22600
22830
|
if (youtrackJson) {
|
|
22601
22831
|
tokenPaths.push(typeof youtrackJson.tokenFile === "string" ? youtrackJson.tokenFile : path10.join(res.configDir, "youtrack.token"));
|
|
22602
|
-
} else if (
|
|
22832
|
+
} else if (existsSync7(path10.join(res.configDir, "youtrack.token"))) {
|
|
22603
22833
|
tokenPaths.push(path10.join(res.configDir, "youtrack.token"));
|
|
22604
22834
|
}
|
|
22605
22835
|
const vcsJson = readJson(path10.join(res.configDir, "vcs.json"));
|
|
@@ -22608,7 +22838,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
22608
22838
|
if (provider && typeof provider === "object") {
|
|
22609
22839
|
const tf = provider.tokenFile;
|
|
22610
22840
|
tokenPaths.push(typeof tf === "string" ? tf : path10.join(res.configDir, `${key}.token`));
|
|
22611
|
-
} else if (!vcsJson &&
|
|
22841
|
+
} else if (!vcsJson && existsSync7(path10.join(res.configDir, `${key}.token`))) {
|
|
22612
22842
|
tokenPaths.push(path10.join(res.configDir, `${key}.token`));
|
|
22613
22843
|
}
|
|
22614
22844
|
}
|
|
@@ -22622,12 +22852,12 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
|
|
|
22622
22852
|
const problems = [];
|
|
22623
22853
|
for (const raw of tokenPaths) {
|
|
22624
22854
|
const p = path10.isAbsolute(raw) ? raw : path10.resolve(res.configDir, raw);
|
|
22625
|
-
if (!
|
|
22855
|
+
if (!existsSync7(p)) {
|
|
22626
22856
|
problems.push(`${p} is missing`);
|
|
22627
22857
|
continue;
|
|
22628
22858
|
}
|
|
22629
22859
|
if (process.platform !== "win32") {
|
|
22630
|
-
const mode =
|
|
22860
|
+
const mode = statSync4(p).mode & 511;
|
|
22631
22861
|
if (mode !== 384)
|
|
22632
22862
|
problems.push(`${p} must be mode 0600 (found ${mode.toString(8)})`);
|
|
22633
22863
|
}
|
|
@@ -23318,10 +23548,10 @@ var init_changelog = __esm(() => {
|
|
|
23318
23548
|
});
|
|
23319
23549
|
|
|
23320
23550
|
// packages/workit-core/src/core/hygiene.ts
|
|
23321
|
-
import { existsSync as
|
|
23551
|
+
import { existsSync as existsSync8, readFileSync as readFileSync8, writeFileSync as writeFileSync4 } from "node:fs";
|
|
23322
23552
|
import path13 from "node:path";
|
|
23323
23553
|
var repoRoot3, templatesDir = () => path13.join(repoRoot3, "templates", "hygiene"), packageJson = (root) => {
|
|
23324
|
-
if (!
|
|
23554
|
+
if (!existsSync8(path13.join(root, "package.json")))
|
|
23325
23555
|
return null;
|
|
23326
23556
|
try {
|
|
23327
23557
|
return JSON.parse(readFileSync8(path13.join(root, "package.json"), "utf8"));
|
|
@@ -23329,7 +23559,7 @@ var repoRoot3, templatesDir = () => path13.join(repoRoot3, "templates", "hygiene
|
|
|
23329
23559
|
return null;
|
|
23330
23560
|
}
|
|
23331
23561
|
}, isOpenSource = (root) => {
|
|
23332
|
-
if (
|
|
23562
|
+
if (existsSync8(path13.join(root, "LICENSE")))
|
|
23333
23563
|
return true;
|
|
23334
23564
|
const pkg = packageJson(root);
|
|
23335
23565
|
if (pkg && !pkg.private)
|
|
@@ -23360,10 +23590,10 @@ var repoRoot3, templatesDir = () => path13.join(repoRoot3, "templates", "hygiene
|
|
|
23360
23590
|
"CONTRIBUTING.md"
|
|
23361
23591
|
]) {
|
|
23362
23592
|
if (file === "LICENSE" || file === "CONTRIBUTING.md") {
|
|
23363
|
-
state[file] = openSource ?
|
|
23593
|
+
state[file] = openSource ? existsSync8(path13.join(root, file)) ? "ok" : "missing" : "skip";
|
|
23364
23594
|
continue;
|
|
23365
23595
|
}
|
|
23366
|
-
if (!
|
|
23596
|
+
if (!existsSync8(path13.join(root, file))) {
|
|
23367
23597
|
state[file] = "missing";
|
|
23368
23598
|
continue;
|
|
23369
23599
|
}
|
|
@@ -23382,10 +23612,10 @@ var repoRoot3, templatesDir = () => path13.join(repoRoot3, "templates", "hygiene
|
|
|
23382
23612
|
files.push("LICENSE", "CONTRIBUTING.md");
|
|
23383
23613
|
const planned = [];
|
|
23384
23614
|
for (const file of files) {
|
|
23385
|
-
if (
|
|
23615
|
+
if (existsSync8(path13.join(root, file)))
|
|
23386
23616
|
continue;
|
|
23387
23617
|
const tpl = path13.join(templatesDir(), file);
|
|
23388
|
-
if (!
|
|
23618
|
+
if (!existsSync8(tpl))
|
|
23389
23619
|
continue;
|
|
23390
23620
|
const content = readFileSync8(tpl, "utf8").replace(/<PROJECT>/g, path13.basename(root)).replace(/<YEAR>/g, String(new Date().getFullYear())).replace(/<HOLDER>\s*/g, licenseHolder(root));
|
|
23391
23621
|
planned.push({ path: path13.join(root, file), content });
|
|
@@ -23408,12 +23638,12 @@ var init_hygiene = __esm(() => {
|
|
|
23408
23638
|
});
|
|
23409
23639
|
|
|
23410
23640
|
// packages/workit-core/src/core/docs-layout.ts
|
|
23411
|
-
import { existsSync as
|
|
23641
|
+
import { existsSync as existsSync9, lstatSync, mkdirSync as mkdirSync5, realpathSync as realpathSync2, statSync as statSync5 } from "node:fs";
|
|
23412
23642
|
import path14 from "node:path";
|
|
23413
23643
|
var SLUG_RE, LEGACY_SLUG = "superpowers", posix = (p) => p.split(path14.sep).join("/"), canonicalize = (base, candidate) => {
|
|
23414
23644
|
const abs = path14.resolve(base, candidate);
|
|
23415
23645
|
let ancestor = abs;
|
|
23416
|
-
while (!
|
|
23646
|
+
while (!existsSync9(ancestor))
|
|
23417
23647
|
ancestor = path14.dirname(ancestor);
|
|
23418
23648
|
let real;
|
|
23419
23649
|
try {
|
|
@@ -23442,8 +23672,8 @@ var SLUG_RE, LEGACY_SLUG = "superpowers", posix = (p) => p.split(path14.sep).joi
|
|
|
23442
23672
|
sdd: path14.join(dir, "sdd")
|
|
23443
23673
|
};
|
|
23444
23674
|
}, probeLegacyDocs = (workspace) => ({
|
|
23445
|
-
legacy_sdd:
|
|
23446
|
-
superpowers_dir:
|
|
23675
|
+
legacy_sdd: existsSync9(path14.join(workspace, ".superpowers", "sdd")),
|
|
23676
|
+
superpowers_dir: existsSync9(path14.join(workspace, "docs", LEGACY_SLUG))
|
|
23447
23677
|
}), resolveCanonicalLayout = (input) => {
|
|
23448
23678
|
const { workspace_root, slug, spec_path, plan_path } = input;
|
|
23449
23679
|
if (!workspace_root)
|
|
@@ -23536,11 +23766,11 @@ var SLUG_RE, LEGACY_SLUG = "superpowers", posix = (p) => p.split(path14.sep).joi
|
|
|
23536
23766
|
const { layout } = resolved;
|
|
23537
23767
|
const created = [];
|
|
23538
23768
|
const ensure = (dir) => {
|
|
23539
|
-
if (!
|
|
23769
|
+
if (!existsSync9(dir)) {
|
|
23540
23770
|
mkdirSync5(dir, { recursive: true });
|
|
23541
23771
|
const rel = posix(path14.relative(layout.workspace, dir));
|
|
23542
23772
|
created.push(rel || ".");
|
|
23543
|
-
} else if (!
|
|
23773
|
+
} else if (!statSync5(dir).isDirectory()) {
|
|
23544
23774
|
throw new Error(`path exists but is not a directory: ${posix(path14.relative(layout.workspace, dir))}`);
|
|
23545
23775
|
}
|
|
23546
23776
|
};
|
|
@@ -23587,7 +23817,7 @@ var init_docs_layout = __esm(() => {
|
|
|
23587
23817
|
});
|
|
23588
23818
|
|
|
23589
23819
|
// packages/workit-core/src/core/docs-validate.ts
|
|
23590
|
-
import { existsSync as
|
|
23820
|
+
import { existsSync as existsSync10, readFileSync as readFileSync9 } from "node:fs";
|
|
23591
23821
|
import { execFileSync as execFileSync3 } from "node:child_process";
|
|
23592
23822
|
import path15 from "node:path";
|
|
23593
23823
|
var BRANCH_RE, SPEC_LINK_RE, TASK_RE, err = (code, message, path16) => {
|
|
@@ -23840,7 +24070,7 @@ var BRANCH_RE, SPEC_LINK_RE, TASK_RE, err = (code, message, path16) => {
|
|
|
23840
24070
|
return findings;
|
|
23841
24071
|
}, sddIgnored = (cwd, slug) => {
|
|
23842
24072
|
const sddDir = path15.join(cwd, "docs", slug, "sdd");
|
|
23843
|
-
if (!
|
|
24073
|
+
if (!existsSync10(sddDir))
|
|
23844
24074
|
return true;
|
|
23845
24075
|
try {
|
|
23846
24076
|
execFileSync3("git", ["-C", cwd, "rev-parse", "--is-inside-work-tree"], { stdio: "pipe" });
|
|
@@ -23920,11 +24150,11 @@ var init_plan_tasks = __esm(() => {
|
|
|
23920
24150
|
var init_core3 = () => {};
|
|
23921
24151
|
|
|
23922
24152
|
// packages/workit-core/src/core/handoff-context.ts
|
|
23923
|
-
import { existsSync as
|
|
24153
|
+
import { existsSync as existsSync11, readFileSync as readFileSync11, readdirSync as readdirSync6, statSync as statSync6 } from "node:fs";
|
|
23924
24154
|
import path17 from "node:path";
|
|
23925
24155
|
var DOC_RE, listMd = (dir) => {
|
|
23926
24156
|
try {
|
|
23927
|
-
return
|
|
24157
|
+
return readdirSync6(dir).filter((f) => f.endsWith(".md")).sort();
|
|
23928
24158
|
} catch {
|
|
23929
24159
|
return [];
|
|
23930
24160
|
}
|
|
@@ -23938,7 +24168,7 @@ var DOC_RE, listMd = (dir) => {
|
|
|
23938
24168
|
const slug = slugs[0];
|
|
23939
24169
|
const plan = `docs/${slug}/plan.md`;
|
|
23940
24170
|
const spec = `docs/${slug}/spec.md`;
|
|
23941
|
-
if (!
|
|
24171
|
+
if (!existsSync11(path17.join(root, plan)) || !existsSync11(path17.join(root, spec))) {
|
|
23942
24172
|
return { error: `docs/${slug}/ must contain both plan.md and spec.md` };
|
|
23943
24173
|
}
|
|
23944
24174
|
return { spec, plan, source: "message_paths" };
|
|
@@ -23947,7 +24177,7 @@ var DOC_RE, listMd = (dir) => {
|
|
|
23947
24177
|
let best = null;
|
|
23948
24178
|
let entries = [];
|
|
23949
24179
|
try {
|
|
23950
|
-
entries =
|
|
24180
|
+
entries = readdirSync6(docsDir);
|
|
23951
24181
|
} catch {
|
|
23952
24182
|
return { error: "no pair" };
|
|
23953
24183
|
}
|
|
@@ -23956,9 +24186,9 @@ var DOC_RE, listMd = (dir) => {
|
|
|
23956
24186
|
continue;
|
|
23957
24187
|
const plan = path17.join("docs", slug, "plan.md");
|
|
23958
24188
|
const spec = path17.join("docs", slug, "spec.md");
|
|
23959
|
-
if (!
|
|
24189
|
+
if (!existsSync11(path17.join(root, plan)) || !existsSync11(path17.join(root, spec)))
|
|
23960
24190
|
continue;
|
|
23961
|
-
const score = Math.max(
|
|
24191
|
+
const score = Math.max(statSync6(path17.join(root, spec)).mtimeMs, statSync6(path17.join(root, plan)).mtimeMs);
|
|
23962
24192
|
if (best === null || score > best.score || score === best.score && slug < best.spec.split("/")[1]) {
|
|
23963
24193
|
best = { score, spec, plan, source: "active_pair" };
|
|
23964
24194
|
}
|
|
@@ -23976,7 +24206,7 @@ var DOC_RE, listMd = (dir) => {
|
|
|
23976
24206
|
if (!("error" in active))
|
|
23977
24207
|
return active;
|
|
23978
24208
|
const docsDir = path17.join(root, "docs");
|
|
23979
|
-
if (!
|
|
24209
|
+
if (!existsSync11(docsDir) || listMd(docsDir).length === 0) {
|
|
23980
24210
|
return { error: "no docs/<slug>/ features found under docs/" };
|
|
23981
24211
|
}
|
|
23982
24212
|
return {
|
|
@@ -24051,10 +24281,10 @@ var init_handoff_tools = __esm(() => {
|
|
|
24051
24281
|
// packages/workit-core/src/core/sdd.ts
|
|
24052
24282
|
import {
|
|
24053
24283
|
appendFileSync as appendFileSync2,
|
|
24054
|
-
existsSync as
|
|
24284
|
+
existsSync as existsSync12,
|
|
24055
24285
|
mkdirSync as mkdirSync6,
|
|
24056
24286
|
readFileSync as readFileSync12,
|
|
24057
|
-
statSync as
|
|
24287
|
+
statSync as statSync7,
|
|
24058
24288
|
writeFileSync as writeFileSync5
|
|
24059
24289
|
} from "node:fs";
|
|
24060
24290
|
import { execFileSync as execFileSync4 } from "node:child_process";
|
|
@@ -24078,7 +24308,7 @@ function ledgerCompletion(root, slug) {
|
|
|
24078
24308
|
let started = false;
|
|
24079
24309
|
const completed = [];
|
|
24080
24310
|
const absProgress = path19.join(root, "docs", slug, "sdd", "progress.md");
|
|
24081
|
-
if (
|
|
24311
|
+
if (existsSync12(absProgress)) {
|
|
24082
24312
|
try {
|
|
24083
24313
|
for (const line of readFileSync12(absProgress, "utf8").split(`
|
|
24084
24314
|
`)) {
|
|
@@ -24094,7 +24324,7 @@ function ledgerCompletion(root, slug) {
|
|
|
24094
24324
|
const required2 = [];
|
|
24095
24325
|
try {
|
|
24096
24326
|
const absPlan = path19.join(root, "docs", slug, "plan.md");
|
|
24097
|
-
if (
|
|
24327
|
+
if (existsSync12(absPlan)) {
|
|
24098
24328
|
for (const task of parseTasksFromPlan(readFileSync12(absPlan, "utf8")))
|
|
24099
24329
|
required2.push(task.id);
|
|
24100
24330
|
}
|
|
@@ -24127,7 +24357,7 @@ function sddContext({
|
|
|
24127
24357
|
let progress_lines = [];
|
|
24128
24358
|
let completed_task_ids = [];
|
|
24129
24359
|
const absProgress = path19.join(resolved.layout.sdd, "progress.md");
|
|
24130
|
-
if (
|
|
24360
|
+
if (existsSync12(absProgress)) {
|
|
24131
24361
|
progress_lines = readFileSync12(absProgress, "utf8").split(`
|
|
24132
24362
|
`).map((ln) => ln.trim()).filter(Boolean);
|
|
24133
24363
|
const pat = /^Task\s+(\d+):\s+complete\b/i;
|
|
@@ -24135,7 +24365,7 @@ function sddContext({
|
|
|
24135
24365
|
}
|
|
24136
24366
|
let manifest = {};
|
|
24137
24367
|
const absManifest = path19.join(resolved.layout.sdd, "manifest.json");
|
|
24138
|
-
if (
|
|
24368
|
+
if (existsSync12(absManifest)) {
|
|
24139
24369
|
try {
|
|
24140
24370
|
manifest = JSON.parse(readFileSync12(absManifest, "utf8"));
|
|
24141
24371
|
} catch {
|
|
@@ -24143,7 +24373,7 @@ function sddContext({
|
|
|
24143
24373
|
}
|
|
24144
24374
|
}
|
|
24145
24375
|
const legacy_path = path19.join(cwd, ".superpowers/sdd");
|
|
24146
|
-
const legacy_exists =
|
|
24376
|
+
const legacy_exists = existsSync12(legacy_path);
|
|
24147
24377
|
let todos = [];
|
|
24148
24378
|
let task_count = 0;
|
|
24149
24379
|
if (plan_path) {
|
|
@@ -24174,7 +24404,7 @@ function sddContext({
|
|
|
24174
24404
|
progress_lines,
|
|
24175
24405
|
completed_task_ids,
|
|
24176
24406
|
manifest,
|
|
24177
|
-
created:
|
|
24407
|
+
created: existsSync12(path19.join(cwd, sdd_dir)),
|
|
24178
24408
|
forbidden_legacy_path: ".superpowers/sdd",
|
|
24179
24409
|
legacy_sdd_exists: legacy_exists,
|
|
24180
24410
|
warning: legacy_exists ? "Ignore .superpowers/sdd — use sdd_dir from this tool only" : undefined,
|
|
@@ -24257,7 +24487,7 @@ function sddAppendProgress({
|
|
|
24257
24487
|
if (!match || match[1].toLowerCase() === match[2].toLowerCase()) {
|
|
24258
24488
|
return { error: "invalid progress line format" };
|
|
24259
24489
|
}
|
|
24260
|
-
if (
|
|
24490
|
+
if (existsSync12(path_) && statSync7(path_).isDirectory()) {
|
|
24261
24491
|
return { error: `progress path is a directory: ${progress_path}` };
|
|
24262
24492
|
}
|
|
24263
24493
|
mkdirSync6(path19.dirname(path_), { recursive: true });
|
|
@@ -24305,7 +24535,7 @@ function sddAppendAdvisory({
|
|
|
24305
24535
|
if (!contained.ok)
|
|
24306
24536
|
return { error: contained.error, code: "advisory_path_invalid" };
|
|
24307
24537
|
const abs = contained.path;
|
|
24308
|
-
if (
|
|
24538
|
+
if (existsSync12(abs) && statSync7(abs).isDirectory()) {
|
|
24309
24539
|
return {
|
|
24310
24540
|
error: `advisory target is a directory: ${advisories_path}`,
|
|
24311
24541
|
code: "advisory_target_invalid"
|
|
@@ -24333,20 +24563,20 @@ var init_menu = () => {};
|
|
|
24333
24563
|
// packages/workit-core/src/core/flow-state.ts
|
|
24334
24564
|
import {
|
|
24335
24565
|
closeSync,
|
|
24336
|
-
existsSync as
|
|
24566
|
+
existsSync as existsSync13,
|
|
24337
24567
|
fstatSync,
|
|
24338
24568
|
fsyncSync,
|
|
24339
24569
|
mkdirSync as mkdirSync7,
|
|
24340
24570
|
openSync,
|
|
24341
|
-
readdirSync as
|
|
24571
|
+
readdirSync as readdirSync7,
|
|
24342
24572
|
readFileSync as readFileSync13,
|
|
24343
|
-
renameSync,
|
|
24344
|
-
rmSync,
|
|
24345
|
-
statSync as
|
|
24573
|
+
renameSync as renameSync2,
|
|
24574
|
+
rmSync as rmSync2,
|
|
24575
|
+
statSync as statSync8,
|
|
24346
24576
|
unlinkSync as unlinkSync3,
|
|
24347
24577
|
writeFileSync as writeFileSync6
|
|
24348
24578
|
} from "node:fs";
|
|
24349
|
-
import { createHash } from "node:crypto";
|
|
24579
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
24350
24580
|
import path20 from "node:path";
|
|
24351
24581
|
|
|
24352
24582
|
class HostReceiptStore {
|
|
@@ -24500,7 +24730,7 @@ var COORDINATOR_RECOVERY_TEXT, CURSOR_SUBAGENT_UNSUPPORTED_TEXT, MENU_CHOICES, e
|
|
|
24500
24730
|
updated_at: Date.now()
|
|
24501
24731
|
}), readFlowState = (root, slug) => {
|
|
24502
24732
|
const file = flowPath(root, slug);
|
|
24503
|
-
if (!
|
|
24733
|
+
if (!existsSync13(file))
|
|
24504
24734
|
return emptyState(slug);
|
|
24505
24735
|
try {
|
|
24506
24736
|
return normalizeState(JSON.parse(readFileSync13(file, "utf8")), slug);
|
|
@@ -24635,7 +24865,7 @@ var COORDINATOR_RECOVERY_TEXT, CURSOR_SUBAGENT_UNSUPPORTED_TEXT, MENU_CHOICES, e
|
|
|
24635
24865
|
}, readFlowStrict = (root, slug) => {
|
|
24636
24866
|
const file = flowPath(root, slug);
|
|
24637
24867
|
const rel = path20.posix.join("docs", slug, "sdd", "flow.json");
|
|
24638
|
-
if (!
|
|
24868
|
+
if (!existsSync13(file)) {
|
|
24639
24869
|
return err2("flow_not_activated", `flow not activated for ${slug} — run workit_flow_status first`);
|
|
24640
24870
|
}
|
|
24641
24871
|
let text;
|
|
@@ -24670,26 +24900,26 @@ var COORDINATOR_RECOVERY_TEXT, CURSOR_SUBAGENT_UNSUPPORTED_TEXT, MENU_CHOICES, e
|
|
|
24670
24900
|
fsyncSync(fd);
|
|
24671
24901
|
closeSync(fd);
|
|
24672
24902
|
fd = null;
|
|
24673
|
-
|
|
24903
|
+
renameSync2(tmp, file);
|
|
24674
24904
|
} finally {
|
|
24675
24905
|
try {
|
|
24676
24906
|
if (fd !== null)
|
|
24677
24907
|
closeSync(fd);
|
|
24678
24908
|
} catch {}
|
|
24679
24909
|
try {
|
|
24680
|
-
if (
|
|
24681
|
-
|
|
24910
|
+
if (existsSync13(tmp))
|
|
24911
|
+
rmSync2(tmp, { force: true });
|
|
24682
24912
|
} catch {}
|
|
24683
24913
|
}
|
|
24684
24914
|
}, MAX_WRITE_ATTEMPTS = 5, STALE_LOCK_MS = 1000, lockMtimeMs = (lock) => {
|
|
24685
24915
|
try {
|
|
24686
|
-
return
|
|
24916
|
+
return statSync8(lock).mtimeMs;
|
|
24687
24917
|
} catch {
|
|
24688
24918
|
return null;
|
|
24689
24919
|
}
|
|
24690
24920
|
}, lockOwnedBy = (fd, lock) => {
|
|
24691
24921
|
try {
|
|
24692
|
-
return fstatSync(fd).ino ===
|
|
24922
|
+
return fstatSync(fd).ino === statSync8(lock).ino;
|
|
24693
24923
|
} catch {
|
|
24694
24924
|
return false;
|
|
24695
24925
|
}
|
|
@@ -24704,7 +24934,7 @@ var COORDINATOR_RECOVERY_TEXT, CURSOR_SUBAGENT_UNSUPPORTED_TEXT, MENU_CHOICES, e
|
|
|
24704
24934
|
const tmp = uniqueTempPath(file);
|
|
24705
24935
|
let fd = null;
|
|
24706
24936
|
try {
|
|
24707
|
-
const currentText =
|
|
24937
|
+
const currentText = existsSync13(file) ? readFileSync13(file, "utf8") : null;
|
|
24708
24938
|
if (currentText !== expectedText)
|
|
24709
24939
|
return { ok: false, conflict: true };
|
|
24710
24940
|
mkdirSync7(path20.dirname(file), { recursive: true });
|
|
@@ -24713,10 +24943,10 @@ var COORDINATOR_RECOVERY_TEXT, CURSOR_SUBAGENT_UNSUPPORTED_TEXT, MENU_CHOICES, e
|
|
|
24713
24943
|
fsyncSync(fd);
|
|
24714
24944
|
closeSync(fd);
|
|
24715
24945
|
fd = null;
|
|
24716
|
-
const reRead =
|
|
24946
|
+
const reRead = existsSync13(file) ? readFileSync13(file, "utf8") : null;
|
|
24717
24947
|
if (reRead !== expectedText)
|
|
24718
24948
|
return { ok: false, conflict: true };
|
|
24719
|
-
|
|
24949
|
+
renameSync2(tmp, file);
|
|
24720
24950
|
return { ok: true };
|
|
24721
24951
|
} catch (error2) {
|
|
24722
24952
|
return { ok: false, io_error: error2 instanceof Error ? error2.message : String(error2) };
|
|
@@ -24726,8 +24956,8 @@ var COORDINATOR_RECOVERY_TEXT, CURSOR_SUBAGENT_UNSUPPORTED_TEXT, MENU_CHOICES, e
|
|
|
24726
24956
|
closeSync(fd);
|
|
24727
24957
|
} catch {}
|
|
24728
24958
|
try {
|
|
24729
|
-
if (
|
|
24730
|
-
|
|
24959
|
+
if (existsSync13(tmp))
|
|
24960
|
+
rmSync2(tmp, { force: true });
|
|
24731
24961
|
} catch {}
|
|
24732
24962
|
}
|
|
24733
24963
|
}, readCanonicalDigest = (root, rel) => {
|
|
@@ -24747,7 +24977,7 @@ var COORDINATOR_RECOVERY_TEXT, CURSOR_SUBAGENT_UNSUPPORTED_TEXT, MENU_CHOICES, e
|
|
|
24747
24977
|
} catch {
|
|
24748
24978
|
return { ok: false, code: "document_unreadable" };
|
|
24749
24979
|
}
|
|
24750
|
-
return { ok: true, text, digest:
|
|
24980
|
+
return { ok: true, text, digest: createHash2("sha256").update(bytes).digest("hex") };
|
|
24751
24981
|
}, resetForSpecDrift = (state) => ({
|
|
24752
24982
|
...state,
|
|
24753
24983
|
spec: { ...state.spec, status: "draft", evidence: null, approved_digest: null },
|
|
@@ -24816,11 +25046,11 @@ var COORDINATOR_RECOVERY_TEXT, CURSOR_SUBAGENT_UNSUPPORTED_TEXT, MENU_CHOICES, e
|
|
|
24816
25046
|
return { state, changed: false };
|
|
24817
25047
|
}, withFlowLock = (file, fn) => {
|
|
24818
25048
|
const lock = `${file}.lock`;
|
|
24819
|
-
if (!
|
|
25049
|
+
if (!existsSync13(path20.dirname(file)))
|
|
24820
25050
|
return { locked: true, value: fn() };
|
|
24821
25051
|
try {
|
|
24822
|
-
if (
|
|
24823
|
-
|
|
25052
|
+
if (existsSync13(`${lock}.stale`))
|
|
25053
|
+
rmSync2(`${lock}.stale`, { force: true });
|
|
24824
25054
|
} catch {}
|
|
24825
25055
|
const wait = new Int32Array(new SharedArrayBuffer(4));
|
|
24826
25056
|
let fd = null;
|
|
@@ -24839,7 +25069,7 @@ var COORDINATOR_RECOVERY_TEXT, CURSOR_SUBAGENT_UNSUPPORTED_TEXT, MENU_CHOICES, e
|
|
|
24839
25069
|
const mtime = lockMtimeMs(lock);
|
|
24840
25070
|
if (mtime !== null && Date.now() - mtime > STALE_LOCK_MS) {
|
|
24841
25071
|
try {
|
|
24842
|
-
|
|
25072
|
+
renameSync2(lock, `${lock}.stale`);
|
|
24843
25073
|
unlinkSync3(`${lock}.stale`);
|
|
24844
25074
|
} catch {}
|
|
24845
25075
|
try {
|
|
@@ -24875,7 +25105,7 @@ var COORDINATOR_RECOVERY_TEXT, CURSOR_SUBAGENT_UNSUPPORTED_TEXT, MENU_CHOICES, e
|
|
|
24875
25105
|
} finally {
|
|
24876
25106
|
try {
|
|
24877
25107
|
if (fd !== null && lockOwnedBy(fd, lock))
|
|
24878
|
-
|
|
25108
|
+
rmSync2(lock, { force: true });
|
|
24879
25109
|
} catch {}
|
|
24880
25110
|
try {
|
|
24881
25111
|
if (fd !== null)
|
|
@@ -25073,7 +25303,7 @@ var COORDINATOR_RECOVERY_TEXT, CURSOR_SUBAGENT_UNSUPPORTED_TEXT, MENU_CHOICES, e
|
|
|
25073
25303
|
const planPath = path20.posix.join("docs", slug, "plan.md");
|
|
25074
25304
|
const file = flowPath(root, slug);
|
|
25075
25305
|
const locked = withFlowLock(file, () => {
|
|
25076
|
-
if (!
|
|
25306
|
+
if (!existsSync13(file)) {
|
|
25077
25307
|
writeFlowFileAtomic(file, {
|
|
25078
25308
|
slug,
|
|
25079
25309
|
activated: true,
|
|
@@ -25113,7 +25343,7 @@ var COORDINATOR_RECOVERY_TEXT, CURSOR_SUBAGENT_UNSUPPORTED_TEXT, MENU_CHOICES, e
|
|
|
25113
25343
|
return err2("path_invalid", doc2.error);
|
|
25114
25344
|
const relPath = path20.posix.join("docs", slug, "spec.md");
|
|
25115
25345
|
return readModifyWrite(root, slug, (state) => {
|
|
25116
|
-
if (!
|
|
25346
|
+
if (!existsSync13(doc2.path))
|
|
25117
25347
|
return err2("spec_missing", `spec not found: ${specPath}`);
|
|
25118
25348
|
if (state.spec.status === "draft" || state.spec.status === "self_reviewed") {
|
|
25119
25349
|
const digest = readCanonicalDigest(root, relPath);
|
|
@@ -25157,7 +25387,7 @@ var COORDINATOR_RECOVERY_TEXT, CURSOR_SUBAGENT_UNSUPPORTED_TEXT, MENU_CHOICES, e
|
|
|
25157
25387
|
return err2("path_invalid", doc2.error);
|
|
25158
25388
|
const relPath = path20.posix.join("docs", slug, "plan.md");
|
|
25159
25389
|
return readModifyWrite(root, slug, (state) => {
|
|
25160
|
-
if (!
|
|
25390
|
+
if (!existsSync13(doc2.path))
|
|
25161
25391
|
return err2("plan_missing", `plan not found: ${planPath}`);
|
|
25162
25392
|
if (state.spec.status !== "approved") {
|
|
25163
25393
|
return err2("spec_not_approved", "spec must be approved before the plan can be approved");
|
|
@@ -25593,15 +25823,15 @@ var init_flow_evidence = __esm(() => {
|
|
|
25593
25823
|
// packages/workit-core/src/core/docs-migration.ts
|
|
25594
25824
|
import { execFileSync as execFileSync5 } from "node:child_process";
|
|
25595
25825
|
import {
|
|
25596
|
-
existsSync as
|
|
25826
|
+
existsSync as existsSync14,
|
|
25597
25827
|
lstatSync as lstatSync2,
|
|
25598
25828
|
mkdirSync as mkdirSync8,
|
|
25599
|
-
readdirSync as
|
|
25829
|
+
readdirSync as readdirSync8,
|
|
25600
25830
|
readFileSync as readFileSync14,
|
|
25601
25831
|
realpathSync as realpathSync3,
|
|
25602
|
-
renameSync as
|
|
25603
|
-
rmSync as
|
|
25604
|
-
statSync as
|
|
25832
|
+
renameSync as renameSync3,
|
|
25833
|
+
rmSync as rmSync3,
|
|
25834
|
+
statSync as statSync9,
|
|
25605
25835
|
writeFileSync as writeFileSync7
|
|
25606
25836
|
} from "node:fs";
|
|
25607
25837
|
import path21 from "node:path";
|
|
@@ -25640,14 +25870,14 @@ var LEGACY_DIR = "docs/superpowers", MIGRATION_CHOICES, SLUG_RE3, RESERVED_SLUG
|
|
|
25640
25870
|
}, detectLegacyDocs = (workspace_root) => {
|
|
25641
25871
|
const root = legacyRoot(workspace_root);
|
|
25642
25872
|
const raw = [];
|
|
25643
|
-
if (
|
|
25644
|
-
for (const entry of
|
|
25873
|
+
if (existsSync14(root)) {
|
|
25874
|
+
for (const entry of readdirSync8(root, { withFileTypes: true })) {
|
|
25645
25875
|
const abs = path21.join(root, entry.name);
|
|
25646
25876
|
const rel = posix3(path21.relative(workspace_root, abs));
|
|
25647
25877
|
if (entry.isDirectory()) {
|
|
25648
|
-
const hasSpec =
|
|
25649
|
-
const hasPlan =
|
|
25650
|
-
if (!hasSpec && !hasPlan && !
|
|
25878
|
+
const hasSpec = existsSync14(path21.join(abs, "spec.md"));
|
|
25879
|
+
const hasPlan = existsSync14(path21.join(abs, "plan.md"));
|
|
25880
|
+
if (!hasSpec && !hasPlan && !existsSync14(path21.join(abs, "sdd")))
|
|
25651
25881
|
continue;
|
|
25652
25882
|
const explicit = explicitTargetSlug(hasPlan ? readFileSafe(path21.join(abs, "plan.md")) : null);
|
|
25653
25883
|
raw.push({
|
|
@@ -25655,7 +25885,7 @@ var LEGACY_DIR = "docs/superpowers", MIGRATION_CHOICES, SLUG_RE3, RESERVED_SLUG
|
|
|
25655
25885
|
legacy_dir: rel,
|
|
25656
25886
|
spec: hasSpec ? posix3(path21.join(rel, "spec.md")) : null,
|
|
25657
25887
|
plan: hasPlan ? posix3(path21.join(rel, "plan.md")) : null,
|
|
25658
|
-
sdd:
|
|
25888
|
+
sdd: existsSync14(path21.join(abs, "sdd")),
|
|
25659
25889
|
explicit: explicit !== null
|
|
25660
25890
|
});
|
|
25661
25891
|
} else if (entry.name === "spec.md" || entry.name === "plan.md") {
|
|
@@ -25775,7 +26005,7 @@ var LEGACY_DIR = "docs/superpowers", MIGRATION_CHOICES, SLUG_RE3, RESERVED_SLUG
|
|
|
25775
26005
|
if (visits.has(real))
|
|
25776
26006
|
return { ok: true };
|
|
25777
26007
|
visits.add(real);
|
|
25778
|
-
for (const entry of
|
|
26008
|
+
for (const entry of readdirSync8(real, { withFileTypes: true })) {
|
|
25779
26009
|
const fromAbs = path21.join(real, entry.name);
|
|
25780
26010
|
const fromRel = posix3(path21.join(legacyRel, entry.name));
|
|
25781
26011
|
const toRel = posix3(path21.join(destRelRoot, entry.name));
|
|
@@ -25795,7 +26025,7 @@ var LEGACY_DIR = "docs/superpowers", MIGRATION_CHOICES, SLUG_RE3, RESERVED_SLUG
|
|
|
25795
26025
|
if (target !== workspaceReal && !target.startsWith(workspaceReal + path21.sep)) {
|
|
25796
26026
|
return { ok: false, error: `symlink escape refused: ${fromRel}` };
|
|
25797
26027
|
}
|
|
25798
|
-
if (
|
|
26028
|
+
if (statSync9(target).isDirectory()) {
|
|
25799
26029
|
const sub = planTree(workspace, fromAbs, fromRel, toRel, path21.join(destAbsRoot, entry.name), legacyName, slug, plan, visits);
|
|
25800
26030
|
if (!sub.ok)
|
|
25801
26031
|
return sub;
|
|
@@ -25898,7 +26128,7 @@ var LEGACY_DIR = "docs/superpowers", MIGRATION_CHOICES, SLUG_RE3, RESERVED_SLUG
|
|
|
25898
26128
|
}
|
|
25899
26129
|
const collisions = [];
|
|
25900
26130
|
for (const item of plan) {
|
|
25901
|
-
if (!
|
|
26131
|
+
if (!existsSync14(item.destAbs))
|
|
25902
26132
|
continue;
|
|
25903
26133
|
let identical = false;
|
|
25904
26134
|
try {
|
|
@@ -25939,10 +26169,10 @@ var LEGACY_DIR = "docs/superpowers", MIGRATION_CHOICES, SLUG_RE3, RESERVED_SLUG
|
|
|
25939
26169
|
try {
|
|
25940
26170
|
mkdirSync8(path21.dirname(item.destAbs), { recursive: true });
|
|
25941
26171
|
writeFileSync7(tmp, item.bytes);
|
|
25942
|
-
|
|
26172
|
+
renameSync3(tmp, item.destAbs);
|
|
25943
26173
|
} catch (error2) {
|
|
25944
26174
|
try {
|
|
25945
|
-
|
|
26175
|
+
rmSync3(tmp, { force: true });
|
|
25946
26176
|
} catch {}
|
|
25947
26177
|
return abort(`legacy migration retry required: failed to copy ${item.fromRel}: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
25948
26178
|
}
|
|
@@ -25964,7 +26194,7 @@ var init_docs_migration = __esm(() => {
|
|
|
25964
26194
|
});
|
|
25965
26195
|
|
|
25966
26196
|
// packages/workit-core/src/core/docs-repo.ts
|
|
25967
|
-
import { existsSync as
|
|
26197
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync9, readFileSync as readFileSync15, writeFileSync as writeFileSync8, readdirSync as readdirSync9 } from "node:fs";
|
|
25968
26198
|
import { execFileSync as execFileSync6 } from "node:child_process";
|
|
25969
26199
|
import path22 from "node:path";
|
|
25970
26200
|
var configPath = () => process.env.WORKFLOW_DOCS_REPO_CONFIG ?? path22.join(configDir(), "docs-repo.json"), readDocsRepoConfig = () => {
|
|
@@ -25980,7 +26210,7 @@ var configPath = () => process.env.WORKFLOW_DOCS_REPO_CONFIG ?? path22.join(conf
|
|
|
25980
26210
|
writeFileSync8(file, JSON.stringify({ path: docsPath }, null, 2) + `
|
|
25981
26211
|
`, "utf8");
|
|
25982
26212
|
}, docsRepoPath = () => readDocsRepoConfig()?.path ?? null, validateDocsRepo = (docsPath) => {
|
|
25983
|
-
if (!
|
|
26213
|
+
if (!existsSync15(docsPath))
|
|
25984
26214
|
return { ok: false, error: `docs repo path does not exist: ${docsPath}` };
|
|
25985
26215
|
try {
|
|
25986
26216
|
execFileSync6("git", ["-C", docsPath, "rev-parse", "--is-inside-work-tree"], { stdio: "pipe" });
|
|
@@ -25988,7 +26218,7 @@ var configPath = () => process.env.WORKFLOW_DOCS_REPO_CONFIG ?? path22.join(conf
|
|
|
25988
26218
|
return { ok: false, error: `docs repo is not a git repository: ${docsPath}` };
|
|
25989
26219
|
}
|
|
25990
26220
|
const featuresDir = path22.join(docsPath, "features");
|
|
25991
|
-
if (!
|
|
26221
|
+
if (!existsSync15(featuresDir))
|
|
25992
26222
|
mkdirSync9(featuresDir, { recursive: true });
|
|
25993
26223
|
return { ok: true };
|
|
25994
26224
|
}, linkDocsRepo = (docsPath, confirmed) => {
|
|
@@ -26003,19 +26233,19 @@ var configPath = () => process.env.WORKFLOW_DOCS_REPO_CONFIG ?? path22.join(conf
|
|
|
26003
26233
|
const repoPath = docsRepoPath();
|
|
26004
26234
|
const specs = [];
|
|
26005
26235
|
const docsDir = path22.join(workspaceRoot, "docs");
|
|
26006
|
-
if (
|
|
26007
|
-
for (const slug of
|
|
26236
|
+
if (existsSync15(docsDir)) {
|
|
26237
|
+
for (const slug of readdirSync9(docsDir)) {
|
|
26008
26238
|
if (slug.startsWith("."))
|
|
26009
26239
|
continue;
|
|
26010
26240
|
const spec = path22.posix.join("docs", slug, "spec.md");
|
|
26011
|
-
if (!
|
|
26241
|
+
if (!existsSync15(path22.join(workspaceRoot, spec)))
|
|
26012
26242
|
continue;
|
|
26013
26243
|
let promoted = false;
|
|
26014
26244
|
let target = null;
|
|
26015
26245
|
if (repoPath) {
|
|
26016
26246
|
const featuresDir = path22.join(repoPath, "features");
|
|
26017
|
-
if (
|
|
26018
|
-
const match =
|
|
26247
|
+
if (existsSync15(featuresDir)) {
|
|
26248
|
+
const match = readdirSync9(featuresDir).find((d) => new RegExp(`^20\\d{2}-\\d{2}-${slug}$`).test(d));
|
|
26019
26249
|
if (match) {
|
|
26020
26250
|
promoted = true;
|
|
26021
26251
|
target = path22.join(repoPath, "features", match);
|
|
@@ -26084,7 +26314,7 @@ var configPath = () => process.env.WORKFLOW_DOCS_REPO_CONFIG ?? path22.join(conf
|
|
|
26084
26314
|
}
|
|
26085
26315
|
if (!opts.force) {
|
|
26086
26316
|
const sddDir = path22.join(workspaceRootCanonical, "docs", slug, "sdd");
|
|
26087
|
-
if (
|
|
26317
|
+
if (existsSync15(sddDir)) {
|
|
26088
26318
|
try {
|
|
26089
26319
|
execFileSync6("git", [
|
|
26090
26320
|
"-C",
|
|
@@ -26102,7 +26332,7 @@ var configPath = () => process.env.WORKFLOW_DOCS_REPO_CONFIG ?? path22.join(conf
|
|
|
26102
26332
|
}
|
|
26103
26333
|
const prefix = monthPrefix();
|
|
26104
26334
|
const featuresDir = path22.join(repoPath, "features");
|
|
26105
|
-
const existing =
|
|
26335
|
+
const existing = existsSync15(featuresDir) ? readdirSync9(featuresDir).find((d) => new RegExp(`^20\\d{2}-\\d{2}-${slug}$`).test(d)) : undefined;
|
|
26106
26336
|
const targetDir = path22.join(featuresDir, existing ?? `${prefix}-${slug}`);
|
|
26107
26337
|
mkdirSync9(targetDir, { recursive: true });
|
|
26108
26338
|
const files = ["spec.md"];
|
|
@@ -26164,13 +26394,13 @@ var init_docs_repo = __esm(() => {
|
|
|
26164
26394
|
});
|
|
26165
26395
|
|
|
26166
26396
|
// packages/workit-core/src/core/gitignore.ts
|
|
26167
|
-
import { existsSync as
|
|
26397
|
+
import { existsSync as existsSync16, readFileSync as readFileSync16, writeFileSync as writeFileSync9 } from "node:fs";
|
|
26168
26398
|
import path23 from "node:path";
|
|
26169
26399
|
var GITIGNORE_ENTRIES, ensureProjectGitignore = (workspaceRoot, confirmed) => {
|
|
26170
26400
|
if (!confirmed)
|
|
26171
26401
|
return { ok: false, error: "confirmed: true required" };
|
|
26172
26402
|
const file = path23.join(workspaceRoot, ".gitignore");
|
|
26173
|
-
const existing =
|
|
26403
|
+
const existing = existsSync16(file) ? readFileSync16(file, "utf8") : "";
|
|
26174
26404
|
const existingLines = new Set(existing.split(`
|
|
26175
26405
|
`).map((l) => l.trim()).filter(Boolean));
|
|
26176
26406
|
const added = [];
|
|
@@ -26189,7 +26419,7 @@ var GITIGNORE_ENTRIES, ensureProjectGitignore = (workspaceRoot, confirmed) => {
|
|
|
26189
26419
|
` : "") + append.join(`
|
|
26190
26420
|
`) + `
|
|
26191
26421
|
`, "utf8");
|
|
26192
|
-
} else if (!
|
|
26422
|
+
} else if (!existsSync16(file)) {
|
|
26193
26423
|
writeFileSync9(file, "", "utf8");
|
|
26194
26424
|
}
|
|
26195
26425
|
return { ok: true, path: file, added };
|
|
@@ -26214,11 +26444,11 @@ var init_gitignore = __esm(() => {
|
|
|
26214
26444
|
});
|
|
26215
26445
|
|
|
26216
26446
|
// packages/workit-core/src/core/templates.ts
|
|
26217
|
-
import { existsSync as
|
|
26447
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync10, readFileSync as readFileSync17, writeFileSync as writeFileSync10 } from "node:fs";
|
|
26218
26448
|
import path24 from "node:path";
|
|
26219
26449
|
var repoRoot4, templatePath = (name) => path24.join(configDir(), "templates", `${name}.md`), readTemplate = (name) => {
|
|
26220
26450
|
const cfg = templatePath(name);
|
|
26221
|
-
if (
|
|
26451
|
+
if (existsSync17(cfg))
|
|
26222
26452
|
return { source: "config", content: readFileSync17(cfg, "utf8") };
|
|
26223
26453
|
return {
|
|
26224
26454
|
source: "repo",
|
|
@@ -26234,9 +26464,9 @@ var repoRoot4, templatePath = (name) => path24.join(configDir(), "templates", `$
|
|
|
26234
26464
|
}, listTemplates = () => ["issue-update", "greeting", "headers"].map((name) => {
|
|
26235
26465
|
const cfg = templatePath(name);
|
|
26236
26466
|
const repoFile = path24.join(repoRoot4, "templates", `${name}.md`);
|
|
26237
|
-
if (
|
|
26467
|
+
if (existsSync17(cfg))
|
|
26238
26468
|
return { name, source: "config", path: cfg };
|
|
26239
|
-
if (
|
|
26469
|
+
if (existsSync17(repoFile))
|
|
26240
26470
|
return { name, source: "repo", path: repoFile };
|
|
26241
26471
|
return { name, source: "missing", path: cfg };
|
|
26242
26472
|
});
|
|
@@ -26247,7 +26477,7 @@ var init_templates = __esm(() => {
|
|
|
26247
26477
|
});
|
|
26248
26478
|
|
|
26249
26479
|
// packages/workit-core/src/core/rules.ts
|
|
26250
|
-
import { existsSync as
|
|
26480
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync11, readFileSync as readFileSync18, readdirSync as readdirSync10, writeFileSync as writeFileSync11 } from "node:fs";
|
|
26251
26481
|
import path25 from "node:path";
|
|
26252
26482
|
var rulesDir = () => path25.join(configDir(), "rules"), parseRule = (markdown) => {
|
|
26253
26483
|
const fm = markdown.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/);
|
|
@@ -26276,10 +26506,10 @@ var rulesDir = () => path25.join(configDir(), "rules"), parseRule = (markdown) =
|
|
|
26276
26506
|
}, listRules = () => {
|
|
26277
26507
|
const result = [];
|
|
26278
26508
|
const dir = rulesDir();
|
|
26279
|
-
if (
|
|
26280
|
-
for (const entry of
|
|
26509
|
+
if (existsSync18(dir)) {
|
|
26510
|
+
for (const entry of readdirSync10(dir)) {
|
|
26281
26511
|
const file = path25.join(dir, entry, "rule.md");
|
|
26282
|
-
if (!
|
|
26512
|
+
if (!existsSync18(file))
|
|
26283
26513
|
continue;
|
|
26284
26514
|
const parsed = parseRule(readFileSync18(file, "utf8"));
|
|
26285
26515
|
if ("error" in parsed)
|
|
@@ -26394,16 +26624,16 @@ var init_setup_state = __esm(() => {
|
|
|
26394
26624
|
|
|
26395
26625
|
// packages/workit-core/src/core/setup.ts
|
|
26396
26626
|
import {
|
|
26397
|
-
copyFileSync as
|
|
26398
|
-
cpSync as
|
|
26399
|
-
existsSync as
|
|
26627
|
+
copyFileSync as copyFileSync3,
|
|
26628
|
+
cpSync as cpSync3,
|
|
26629
|
+
existsSync as existsSync19,
|
|
26400
26630
|
mkdirSync as mkdirSync12,
|
|
26401
26631
|
mkdtempSync,
|
|
26402
26632
|
readFileSync as readFileSync19,
|
|
26403
|
-
readdirSync as
|
|
26404
|
-
renameSync as
|
|
26405
|
-
rmSync as
|
|
26406
|
-
statSync as
|
|
26633
|
+
readdirSync as readdirSync11,
|
|
26634
|
+
renameSync as renameSync4,
|
|
26635
|
+
rmSync as rmSync4,
|
|
26636
|
+
statSync as statSync10,
|
|
26407
26637
|
writeFileSync as writeFileSync13
|
|
26408
26638
|
} from "node:fs";
|
|
26409
26639
|
import path26 from "node:path";
|
|
@@ -27999,7 +28229,8 @@ var init_server3 = __esm(async () => {
|
|
|
27999
28229
|
sdd_dir,
|
|
28000
28230
|
target_branch,
|
|
28001
28231
|
stash,
|
|
28002
|
-
workspace_root
|
|
28232
|
+
workspace_root,
|
|
28233
|
+
log: (message) => logger.info(message)
|
|
28003
28234
|
});
|
|
28004
28235
|
if (data.error)
|
|
28005
28236
|
return jsonResult({ error: data.error });
|
|
@@ -28348,7 +28579,7 @@ var init_server3 = __esm(async () => {
|
|
|
28348
28579
|
return jsonResult(result);
|
|
28349
28580
|
}
|
|
28350
28581
|
if (action === "config") {
|
|
28351
|
-
if (locale !== undefined && !/^[a-z]{2,3}(-[A-Z]{2})?$/.test(locale)) {
|
|
28582
|
+
if (locale !== undefined && !/^[a-z]{2,3}(-(?:[A-Z]{2}|[0-9]{3}))?$/.test(locale)) {
|
|
28352
28583
|
return jsonResult({
|
|
28353
28584
|
error: `invalid locale: ${JSON.stringify(locale)} — expected BCP-47 like en or es-CL`
|
|
28354
28585
|
});
|
|
@@ -28710,17 +28941,17 @@ var init_server3 = __esm(async () => {
|
|
|
28710
28941
|
});
|
|
28711
28942
|
|
|
28712
28943
|
// packages/workit-cursor/mcp/run-server.ts
|
|
28713
|
-
import { existsSync as
|
|
28944
|
+
import { existsSync as existsSync20, readFileSync as readFileSync21 } from "node:fs";
|
|
28714
28945
|
import path29 from "node:path";
|
|
28715
28946
|
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
28716
28947
|
var mcpDir = path29.dirname(fileURLToPath2(import.meta.url));
|
|
28717
28948
|
var pluginDir = path29.resolve(mcpDir, "..");
|
|
28718
28949
|
var marker = path29.join(pluginDir, ".workit-root");
|
|
28719
28950
|
var resolveRoot = () => {
|
|
28720
|
-
if (process.env.WORKFLOW_TOOLKIT_ROOT &&
|
|
28951
|
+
if (process.env.WORKFLOW_TOOLKIT_ROOT && existsSync20(path29.join(process.env.WORKFLOW_TOOLKIT_ROOT, "scripts"))) {
|
|
28721
28952
|
return process.env.WORKFLOW_TOOLKIT_ROOT;
|
|
28722
28953
|
}
|
|
28723
|
-
if (
|
|
28954
|
+
if (existsSync20(marker)) {
|
|
28724
28955
|
return readFileSync21(marker, "utf8").replace(/\n+$/, "");
|
|
28725
28956
|
}
|
|
28726
28957
|
return pluginDir;
|