@brainervirus/workit-cursor 0.8.7 → 0.8.8

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.
@@ -2,7 +2,7 @@
2
2
  "name": "workit",
3
3
  "displayName": "Workit",
4
4
  "description": "OpenCode-style verify, PR, changelog, commit, and session handoff for Cursor",
5
- "version": "0.8.7",
5
+ "version": "0.8.8",
6
6
  "author": {
7
7
  "name": "Cristhofer Pincetti"
8
8
  },
package/README.md CHANGED
@@ -100,6 +100,14 @@ The repository root carries `.cursor-plugin/marketplace.json`, indexing `package
100
100
  - **Update review** — Git plugin metadata (manifest, rules, skills, assets) is reviewed by Cursor on Marketplace updates, while the npm runtime runs from `@latest` with `--prefer-online`. The selector is shared across `mcp.json`, `hooks-cursor.json`, and `run-cursor-mcp.sh`, and a stale `latest` resolution is prevented by the mandatory `--prefer-online` flag.
101
101
  - **Troubleshooting** — `workit doctor` (or the `workflow_doctor` tool) reports installation health including runtime, token, VCS/YouTrack, and log-writability checks; it exits nonzero on failure. An MCP/hook startup failure with no network is an `npx`/registry reachability issue, not a Workit defect.
102
102
 
103
+ ## Auto-load repair
104
+
105
+ Workit self-heals stale Cursor plugin installs so the workflow features never silently drop out of auto-load (CA-01/CA-04):
106
+
107
+ - **Detection** — the doctor's `stale_install` finding reads the installed `~/.cursor/plugins/local/workit` directory and fails on a legacy `--package=` pin in the plugin's own `mcp.json`, a sessionStart hook running a legacy selector, or a local-dist install behind the current/published runtime; each finding carries the exact repair step.
108
+ - **Self-heal** — `install-cursor-plugin.sh` runs `doctor-check.ts cursor --stale` as a pre-check: exit 2 (stale) triggers a refresh of the plugin directory plus a rewrite of the workit MCP/hook entries to the canonical `@latest` + `--prefer-online` selector, preserving unrelated MCP servers; a healthy install is byte-untouched.
109
+ - **Fail-open** — the one network probe (the npm registry version comparison for local-dist installs) never blocks an install: an unreachable registry warns as `registry_unreachable`, never `stale_install` and never a failure. Canonical `@latest` installs skip the probe entirely — the selector resolves fresh at launch, so the installed `package.json` version is metadata, not a freshness signal.
110
+
103
111
  ## Docs
104
112
 
105
113
  Full usage: https://github.com/BrainerVirus/workit#readme
@@ -21835,6 +21835,25 @@ var init_support_matrix = __esm(() => {
21835
21835
  };
21836
21836
  });
21837
21837
 
21838
+ // packages/workit-core/src/core/package-root.ts
21839
+ import { existsSync as existsSync4 } from "node:fs";
21840
+ import path8 from "node:path";
21841
+ import { fileURLToPath } from "node:url";
21842
+ var packageRoot = () => {
21843
+ let dir = path8.dirname(fileURLToPath(import.meta.url));
21844
+ while (true) {
21845
+ const parent = path8.dirname(dir);
21846
+ if (existsSync4(path8.join(dir, "package.json")) || parent === dir)
21847
+ return dir;
21848
+ dir = parent;
21849
+ }
21850
+ }, assetRoot = () => {
21851
+ const root = packageRoot();
21852
+ const assets = path8.join(root, "assets");
21853
+ return existsSync4(assets) ? assets : root;
21854
+ };
21855
+ var init_package_root = () => {};
21856
+
21838
21857
  // packages/workit-core/src/core/registration.ts
21839
21858
  function isWorkitPlugin(value) {
21840
21859
  const s = String(value).replaceAll("\\", "/");
@@ -21864,18 +21883,18 @@ var named = (s, name) => s === name || s.startsWith(`${name}@`), CURSOR_RUNTIME_
21864
21883
  var init_registration = () => {};
21865
21884
 
21866
21885
  // packages/workit-core/src/core/skill-manifests.ts
21867
- import { existsSync as existsSync4, readFileSync as readFileSync6, readdirSync as readdirSync4, statSync as statSync2 } from "node:fs";
21868
- import path8 from "node:path";
21869
- var CANONICAL_SKILLS, skillManifestNames = (root) => existsSync4(root) ? readdirSync4(root).filter((name) => existsSync4(path8.join(root, name, "SKILL.md"))).sort() : [], validateSkillManifests = (root, expected, label) => {
21886
+ import { existsSync as existsSync5, readFileSync as readFileSync6, readdirSync as readdirSync4, statSync as statSync2 } from "node:fs";
21887
+ import path9 from "node:path";
21888
+ var CANONICAL_SKILLS, skillManifestNames = (root) => existsSync5(root) ? readdirSync4(root).filter((name) => existsSync5(path9.join(root, name, "SKILL.md"))).sort() : [], validateSkillManifests = (root, expected, label) => {
21870
21889
  const actual = skillManifestNames(root);
21871
21890
  const missing = expected.filter((name) => !actual.includes(name));
21872
21891
  const extra = actual.filter((name) => !expected.includes(name));
21873
21892
  return missing.length === 0 && extra.length === 0 ? null : `${label} mismatch at ${root} (missing: ${missing.join(", ") || "none"}; extra: ${extra.join(", ") || "none"})`;
21874
21893
  }, validateCursorSkills = (pluginDir) => {
21875
- const workit = validateSkillManifests(path8.join(pluginDir, "skills"), CANONICAL_SKILLS.workit, "Cursor Workit skills");
21894
+ const workit = validateSkillManifests(path9.join(pluginDir, "skills"), CANONICAL_SKILLS.workit, "Cursor Workit skills");
21876
21895
  if (workit)
21877
21896
  return workit;
21878
- const vendor = path8.join(pluginDir, "vendor/superpowers/skills");
21897
+ const vendor = path9.join(pluginDir, "vendor/superpowers/skills");
21879
21898
  const superpowers = validateSkillManifests(vendor, CANONICAL_SKILLS.superpowers, "Cursor Superpowers skills");
21880
21899
  if (superpowers)
21881
21900
  return superpowers;
@@ -21883,7 +21902,7 @@ var CANONICAL_SKILLS, skillManifestNames = (root) => existsSync4(root) ? readdir
21883
21902
  while (pending.length > 0) {
21884
21903
  const dir = pending.pop();
21885
21904
  for (const entry of readdirSync4(dir, { withFileTypes: true })) {
21886
- const file = path8.join(dir, entry.name);
21905
+ const file = path9.join(dir, entry.name);
21887
21906
  if (entry.isDirectory())
21888
21907
  pending.push(file);
21889
21908
  else if ((statSync2(file).mode & 73) !== 0 || readFileSync6(file).subarray(0, 2).toString("latin1") === "#!") {
@@ -21931,15 +21950,15 @@ var init_skill_manifests = __esm(() => {
21931
21950
 
21932
21951
  // packages/workit-core/src/core/doctor.ts
21933
21952
  import { spawnSync as spawnSync4 } from "node:child_process";
21934
- import { existsSync as existsSync5, mkdirSync as mkdirSync4, readFileSync as readFileSync7, statSync as statSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "node:fs";
21953
+ import { existsSync as existsSync6, mkdirSync as mkdirSync4, readFileSync as readFileSync7, statSync as statSync3, unlinkSync as unlinkSync2, writeFileSync as writeFileSync3 } from "node:fs";
21935
21954
  import os3 from "node:os";
21936
- import path9 from "node:path";
21955
+ import path10 from "node:path";
21937
21956
  var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
21938
- let dir = path9.resolve(cwd);
21957
+ let dir = path10.resolve(cwd);
21939
21958
  while (true) {
21940
- if (existsSync5(path9.join(dir, "packages", "workit-core", "package.json")))
21959
+ if (existsSync6(path10.join(dir, "packages", "workit-core", "package.json")))
21941
21960
  return dir;
21942
- const parent = path9.dirname(dir);
21961
+ const parent = path10.dirname(dir);
21943
21962
  if (parent === dir)
21944
21963
  return null;
21945
21964
  dir = parent;
@@ -21947,8 +21966,8 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
21947
21966
  }, resolve = (options) => {
21948
21967
  const env = options.env ?? process.env;
21949
21968
  const home = options.home ?? env.HOME ?? os3.homedir();
21950
- const configDir2 = options.configDir ?? env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path9.join(home, ".config", "workit");
21951
- const stateDir = options.stateDir ?? env.WORKFLOW_TOOLKIT_STATE ?? path9.join(home, ".local", "state", "workit");
21969
+ const configDir2 = options.configDir ?? env.WORKFLOW_TOOLKIT_CONFIG ?? env.WORKFLOW_TOOLKIT_CONFIG_DIR ?? path10.join(home, ".config", "workit");
21970
+ const stateDir = options.stateDir ?? env.WORKFLOW_TOOLKIT_STATE ?? path10.join(home, ".local", "state", "workit");
21952
21971
  const cwd = options.cwd ?? process.cwd();
21953
21972
  const dev = options.dev ?? env.WORKFLOW_TOOLKIT_DEV ?? findDevFromCwd(cwd);
21954
21973
  return {
@@ -21958,10 +21977,10 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
21958
21977
  stateDir,
21959
21978
  cwd,
21960
21979
  dev,
21961
- opencodeConfig: options.opencodeConfig ?? path9.join(home, ".config", "opencode", "opencode.json"),
21962
- cursorSettings: options.cursorSettings ?? path9.join(home, ".cursor", "settings.json"),
21963
- cursorMcp: options.cursorMcp ?? path9.join(home, ".cursor", "mcp.json"),
21964
- cursorPluginDir: options.cursorPluginDir ?? path9.join(home, ".cursor", "plugins", "local", "workit"),
21980
+ opencodeConfig: options.opencodeConfig ?? path10.join(home, ".config", "opencode", "opencode.json"),
21981
+ cursorSettings: options.cursorSettings ?? path10.join(home, ".cursor", "settings.json"),
21982
+ cursorMcp: options.cursorMcp ?? path10.join(home, ".cursor", "mcp.json"),
21983
+ cursorPluginDir: options.cursorPluginDir ?? path10.join(home, ".cursor", "plugins", "local", "workit"),
21965
21984
  env,
21966
21985
  installer: options.installer ?? false
21967
21986
  };
@@ -21983,13 +22002,13 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
21983
22002
  const list = Array.isArray(plugin) ? plugin : typeof plugin === "string" ? [plugin] : [];
21984
22003
  return list.map(String).filter(isWorkitPlugin);
21985
22004
  }, commandOnPath2 = (name, env) => {
21986
- const dirs = (env.PATH ?? process.env.PATH ?? "").split(path9.delimiter);
22005
+ const dirs = (env.PATH ?? process.env.PATH ?? "").split(path10.delimiter);
21987
22006
  const names = process.platform === "win32" ? [name, `${name}.exe`] : [name];
21988
22007
  for (const dir of dirs) {
21989
22008
  if (!dir)
21990
22009
  continue;
21991
22010
  for (const candidateName of names) {
21992
- const candidate = path9.join(dir, candidateName);
22011
+ const candidate = path10.join(dir, candidateName);
21993
22012
  try {
21994
22013
  const st = statSync3(candidate);
21995
22014
  if (process.platform !== "win32" && (st.mode & 73) === 0)
@@ -22015,14 +22034,14 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
22015
22034
  }
22016
22035
  return true;
22017
22036
  }, resolveBun = (env) => {
22018
- if (env.BUN && existsSync5(env.BUN))
22037
+ if (env.BUN && existsSync6(env.BUN))
22019
22038
  return env.BUN;
22020
22039
  for (const candidate of [
22021
- path9.join(os3.homedir(), ".bun/bin/bun"),
22040
+ path10.join(os3.homedir(), ".bun/bin/bun"),
22022
22041
  "/usr/local/bin/bun",
22023
22042
  "/usr/bin/bun"
22024
22043
  ]) {
22025
- if (existsSync5(candidate))
22044
+ if (existsSync6(candidate))
22026
22045
  return candidate;
22027
22046
  }
22028
22047
  return commandOnPath2("bun", env) ? "bun" : null;
@@ -22070,7 +22089,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
22070
22089
  detail: "no dev checkout found (WORKFLOW_TOOLKIT_DEV) — skipping version parity"
22071
22090
  };
22072
22091
  }
22073
- const corePkg = readJson(path9.join(res.dev, "packages/workit-core/package.json"));
22092
+ const corePkg = readJson(path10.join(res.dev, "packages/workit-core/package.json"));
22074
22093
  if (!corePkg) {
22075
22094
  return {
22076
22095
  id: "versions",
@@ -22080,7 +22099,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
22080
22099
  }
22081
22100
  const refs = new Set;
22082
22101
  for (const name of ["workit-opencode", "workit-cursor", "workit-cli"]) {
22083
- const pkg = readJson(path9.join(res.dev, "packages", name, "package.json"));
22102
+ const pkg = readJson(path10.join(res.dev, "packages", name, "package.json"));
22084
22103
  const dep = pkg?.dependencies?.["@brainervirus/workit-core"];
22085
22104
  if (typeof dep === "string")
22086
22105
  refs.add(dep);
@@ -22096,7 +22115,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
22096
22115
  if (refs.size > 1) {
22097
22116
  problems.push(`adapters pin different core versions: ${[...refs].join(", ")}`);
22098
22117
  }
22099
- const opencodePkg = readJson(path9.join(res.dev, "packages/workit-opencode/package.json"));
22118
+ const opencodePkg = readJson(path10.join(res.dev, "packages/workit-opencode/package.json"));
22100
22119
  const sdk = opencodePkg?.dependencies?.["@opencode-ai/plugin"];
22101
22120
  const sdkVersion = typeof sdk === "string" ? (sdk.match(/^\d+(?:\.\d+){0,2}/) ?? [])[0] : null;
22102
22121
  if (sdkVersion && !semverAtLeast(sdkVersion, SUPPORT_MATRIX.opencode.minimum)) {
@@ -22116,27 +22135,27 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
22116
22135
  fix: "Align every adapter to the same @brainervirus/workit-core version (rewrite-workspace-deps.ts) or reinstall"
22117
22136
  };
22118
22137
  }, assetPathsFor = (host, dev) => {
22119
- const pkg = path9.join(dev, "packages", `workit-${host}`);
22138
+ const pkg = path10.join(dev, "packages", `workit-${host}`);
22120
22139
  switch (host) {
22121
22140
  case "opencode":
22122
22141
  return [
22123
- path9.join(pkg, "assets", "commands", "wk-init.md"),
22124
- path9.join(pkg, "assets", "skills", "wk-init", "SKILL.md"),
22125
- path9.join(pkg, "assets", "templates", "spec-template.md"),
22126
- path9.join(pkg, "assets", "vendor", "superpowers", "skills", "brainstorming", "SKILL.md")
22142
+ path10.join(pkg, "assets", "commands", "wk-init.md"),
22143
+ path10.join(pkg, "assets", "skills", "wk-init", "SKILL.md"),
22144
+ path10.join(pkg, "assets", "templates", "spec-template.md"),
22145
+ path10.join(pkg, "assets", "vendor", "superpowers", "skills", "brainstorming", "SKILL.md")
22127
22146
  ];
22128
22147
  case "cursor":
22129
22148
  return [
22130
- path9.join(pkg, "assets", "templates", "spec-template.md"),
22131
- path9.join(pkg, "mcp.json"),
22132
- path9.join(pkg, ".cursor-plugin")
22149
+ path10.join(pkg, "assets", "templates", "spec-template.md"),
22150
+ path10.join(pkg, "mcp.json"),
22151
+ path10.join(pkg, ".cursor-plugin")
22133
22152
  ];
22134
22153
  case "cli":
22135
- return [path9.join(pkg, "assets", "templates", "spec-template.md")];
22154
+ return [path10.join(pkg, "assets", "templates", "spec-template.md")];
22136
22155
  }
22137
22156
  }, hostsFor = (host) => host === "cli" ? ["opencode", "cursor", "cli"] : [host], checkAssets = (res) => {
22138
22157
  const dev = res.dev;
22139
- const missing = dev ? hostsFor(res.host).flatMap((h) => assetPathsFor(h, dev).filter((p) => !existsSync5(p)).map((p) => `${h}: ${p}`)) : [];
22158
+ const missing = dev ? hostsFor(res.host).flatMap((h) => assetPathsFor(h, dev).filter((p) => !existsSync6(p)).map((p) => `${h}: ${p}`)) : [];
22140
22159
  if (res.host === "cursor" || res.host === "cli") {
22141
22160
  const cursorError = validateCursorSkills(res.cursorPluginDir);
22142
22161
  if (cursorError)
@@ -22163,17 +22182,17 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
22163
22182
  fix: "Reinstall or rebuild the workit package (missing assets under packages/workit-<host>)"
22164
22183
  };
22165
22184
  }, launcherSlotsFor = (host, dev) => {
22166
- const pkg = path9.join(dev, "packages", `workit-${host}`);
22185
+ const pkg = path10.join(dev, "packages", `workit-${host}`);
22167
22186
  switch (host) {
22168
22187
  case "opencode":
22169
- return [[path9.join(pkg, "src", "plugin.ts"), path9.join(pkg, "dist", "plugin.js")]];
22188
+ return [[path10.join(pkg, "src", "plugin.ts"), path10.join(pkg, "dist", "plugin.js")]];
22170
22189
  case "cursor":
22171
22190
  return [
22172
- [path9.join(pkg, "dist", "mcp-server.js")],
22173
- [path9.join(pkg, "dist", "cursor-session-start.js")]
22191
+ [path10.join(pkg, "dist", "mcp-server.js")],
22192
+ [path10.join(pkg, "dist", "cursor-session-start.js")]
22174
22193
  ];
22175
22194
  case "cli":
22176
- return [[path9.join(pkg, "src", "index.tsx"), path9.join(pkg, "dist", "index.js")]];
22195
+ return [[path10.join(pkg, "src", "index.tsx"), path10.join(pkg, "dist", "index.js")]];
22177
22196
  }
22178
22197
  }, validNodeEntry = (entry, runtime, env) => {
22179
22198
  try {
@@ -22187,7 +22206,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
22187
22206
  return false;
22188
22207
  }
22189
22208
  }, registeredCursorLauncher = (res) => {
22190
- if (!existsSync5(res.cursorMcp))
22209
+ if (!existsSync6(res.cursorMcp))
22191
22210
  return "invalid";
22192
22211
  const config2 = readJson(res.cursorMcp);
22193
22212
  if (!config2)
@@ -22200,7 +22219,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
22200
22219
  if (typeof command !== "string" || !Array.isArray(args) || typeof args[0] !== "string") {
22201
22220
  return "invalid";
22202
22221
  }
22203
- const executable = path9.basename(command).toLowerCase();
22222
+ const executable = path10.basename(command).toLowerCase();
22204
22223
  const canonical = cursorMcpServerEntry("").args;
22205
22224
  if (executable === "npx" || executable === "npx.exe" || executable === "npx.cmd") {
22206
22225
  if (args.length !== canonical.length || args.some((a, i) => a !== canonical[i]))
@@ -22212,11 +22231,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
22212
22231
  return {
22213
22232
  kind: "node",
22214
22233
  runtime: command,
22215
- entry: path9.isAbsolute(args[0]) ? args[0] : path9.resolve(path9.dirname(res.cursorMcp), args[0])
22234
+ entry: path10.isAbsolute(args[0]) ? args[0] : path10.resolve(path10.dirname(res.cursorMcp), args[0])
22216
22235
  };
22217
22236
  }, canonicalCursorHook, registeredCursorHook = (res) => {
22218
- const hooksFile = path9.join(res.cursorPluginDir, "hooks", "hooks-cursor.json");
22219
- if (!existsSync5(hooksFile))
22237
+ const hooksFile = path10.join(res.cursorPluginDir, "hooks", "hooks-cursor.json");
22238
+ if (!existsSync6(hooksFile))
22220
22239
  return "invalid";
22221
22240
  const config2 = readJson(hooksFile);
22222
22241
  if (!config2)
@@ -22233,9 +22252,9 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
22233
22252
  if (!m)
22234
22253
  return false;
22235
22254
  const entry = m[1].trim();
22236
- if (!path9.isAbsolute(entry))
22255
+ if (!path10.isAbsolute(entry))
22237
22256
  return false;
22238
- if (path9.resolve(entry) !== path9.resolve(path9.join(res.cursorPluginDir, "dist", "cursor-session-start.js"))) {
22257
+ if (path10.resolve(entry) !== path10.resolve(path10.join(res.cursorPluginDir, "dist", "cursor-session-start.js"))) {
22239
22258
  return false;
22240
22259
  }
22241
22260
  return validNodeEntry(entry, "node", res.env);
@@ -22244,7 +22263,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
22244
22263
  const hosts = hostsFor(res.host);
22245
22264
  const registered = hosts.includes("cursor") ? registeredCursorLauncher(res) : null;
22246
22265
  const runtime = registered && registered !== "invalid" && registered.kind === "node" ? registered.runtime : "node";
22247
- const missing = hosts.includes("cursor") ? ["dist/mcp-server.js", "dist/cursor-session-start.js"].map((rel) => path9.join(res.cursorPluginDir, rel)).filter((p) => !validNodeEntry(p, runtime, res.env)).map((p) => `cursor: ${p}`) : [];
22266
+ const missing = hosts.includes("cursor") ? ["dist/mcp-server.js", "dist/cursor-session-start.js"].map((rel) => path10.join(res.cursorPluginDir, rel)).filter((p) => !validNodeEntry(p, runtime, res.env)).map((p) => `cursor: ${p}`) : [];
22248
22267
  if (hosts.includes("cursor")) {
22249
22268
  if (registered === "invalid") {
22250
22269
  missing.push(`cursor: canonical workit MCP launcher in ${res.cursorMcp}`);
@@ -22253,13 +22272,13 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
22253
22272
  }
22254
22273
  const hook = registeredCursorHook(res);
22255
22274
  if (hook === "invalid") {
22256
- missing.push(`cursor: canonical session-start hook in ${path9.join(res.cursorPluginDir, "hooks", "hooks-cursor.json")}`);
22275
+ missing.push(`cursor: canonical session-start hook in ${path10.join(res.cursorPluginDir, "hooks", "hooks-cursor.json")}`);
22257
22276
  } else if (hook !== null && hook !== canonicalCursorHook && !validLocalDistHook(hook, res)) {
22258
- missing.push(`cursor: canonical session-start hook in ${path9.join(res.cursorPluginDir, "hooks", "hooks-cursor.json")} (registered ${hook})`);
22277
+ missing.push(`cursor: canonical session-start hook in ${path10.join(res.cursorPluginDir, "hooks", "hooks-cursor.json")} (registered ${hook})`);
22259
22278
  }
22260
22279
  }
22261
22280
  if (dev) {
22262
- missing.push(...hosts.filter((h) => h !== "cursor").flatMap((h) => launcherSlotsFor(h, dev).filter((slot) => !slot.some((p) => existsSync5(p))).map((slot) => `${h}: ${slot.join(" or ")}`)));
22281
+ missing.push(...hosts.filter((h) => h !== "cursor").flatMap((h) => launcherSlotsFor(h, dev).filter((slot) => !slot.some((p) => existsSync6(p))).map((slot) => `${h}: ${slot.join(" or ")}`)));
22263
22282
  }
22264
22283
  if (missing.length > 0) {
22265
22284
  return {
@@ -22276,7 +22295,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
22276
22295
  detail: "no dev checkout found (WORKFLOW_TOOLKIT_DEV) — skipping non-Cursor launcher checks"
22277
22296
  };
22278
22297
  }
22279
- return { id: "launcher", status: "pass", detail: `${res.host} launcher/hook entries present` };
22298
+ return {
22299
+ id: "launcher",
22300
+ status: "pass",
22301
+ detail: `${res.host} launcher/hook entries present`
22302
+ };
22280
22303
  }, checkUtility = (res) => {
22281
22304
  const git = commandOnPath2("git", res.env);
22282
22305
  if (!git) {
@@ -22295,7 +22318,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
22295
22318
  fix: "Install util-linux (flock)"
22296
22319
  };
22297
22320
  }
22298
- return { id: "utility", status: "pass", detail: "git (and flock where required) on PATH" };
22321
+ return {
22322
+ id: "utility",
22323
+ status: "pass",
22324
+ detail: "git (and flock where required) on PATH"
22325
+ };
22299
22326
  }, staleEntry = (entry) => {
22300
22327
  if (!entry)
22301
22328
  return "stale";
@@ -22303,7 +22330,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
22303
22330
  return "stale";
22304
22331
  if (entry.startsWith("file:")) {
22305
22332
  const target = entry.replace(/^file:\/\//, "").replace(/^file:/, "");
22306
- return existsSync5(target) ? "ok" : "missing-file";
22333
+ return existsSync6(target) ? "ok" : "missing-file";
22307
22334
  }
22308
22335
  return "ok";
22309
22336
  }, checkStalePin = (res) => {
@@ -22314,8 +22341,12 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
22314
22341
  detail: "opencode pin not inspected on the cursor host"
22315
22342
  };
22316
22343
  }
22317
- if (!existsSync5(res.opencodeConfig)) {
22318
- return { id: "stale_pin", status: "pass", detail: "no opencode config — not registered" };
22344
+ if (!existsSync6(res.opencodeConfig)) {
22345
+ return {
22346
+ id: "stale_pin",
22347
+ status: "pass",
22348
+ detail: "no opencode config — not registered"
22349
+ };
22319
22350
  }
22320
22351
  const cfg = readJson(res.opencodeConfig);
22321
22352
  const entries = pluginEntries(cfg);
@@ -22345,17 +22376,125 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
22345
22376
  };
22346
22377
  }
22347
22378
  return { id: "stale_pin", status: "pass", detail: "opencode pin resolves" };
22379
+ }, pluginMcpSelectors = (res) => {
22380
+ const p = path10.join(res.cursorPluginDir, "mcp.json");
22381
+ if (!existsSync6(p))
22382
+ return null;
22383
+ const cfg = readJson(p);
22384
+ const server = cfg?.mcpServers?.workit;
22385
+ if (!server || typeof server !== "object" || Array.isArray(server))
22386
+ return null;
22387
+ const args = server.args;
22388
+ if (!Array.isArray(args))
22389
+ return null;
22390
+ return args.map(String).filter((a) => a.startsWith("--package="));
22391
+ }, registryLatestVersion = (res) => {
22392
+ const seam = res.env.WORKIT_DOCTOR_STALE_REGISTRY_VERSION;
22393
+ if (typeof seam === "string" && seam) {
22394
+ return /^\d+(?:\.\d+){1,2}$/.test(seam) ? seam : null;
22395
+ }
22396
+ const cmd = res.env.WORKIT_DOCTOR_STALE_REGISTRY_CMD ?? (commandOnPath2("npm", res.env) ? "npm" : null);
22397
+ if (!cmd)
22398
+ return null;
22399
+ try {
22400
+ const r = spawnSync4(cmd, ["view", CURSOR_RUNTIME_PACKAGE, "version"], {
22401
+ encoding: "utf8",
22402
+ timeout: 20000,
22403
+ env: res.env
22404
+ });
22405
+ const v = (r.stdout ?? "").trim().split(/\s+/)[0];
22406
+ return r.status === 0 && /^\d+(?:\.\d+){1,2}$/.test(v) ? v : null;
22407
+ } catch {
22408
+ return null;
22409
+ }
22410
+ }, installedPluginVersion = (res) => {
22411
+ const pkg = readJson(path10.join(res.cursorPluginDir, "package.json"));
22412
+ return typeof pkg?.version === "string" && pkg.version ? pkg.version : null;
22413
+ }, checkStaleInstall = (res) => {
22414
+ if (res.host !== "cursor" && res.host !== "cli") {
22415
+ return {
22416
+ id: "stale_install",
22417
+ status: "pass",
22418
+ detail: "cursor plugin not inspected on the opencode host"
22419
+ };
22420
+ }
22421
+ const canonicalMcp = cursorMcpServerEntry("").args.find((a) => a.startsWith("--package="));
22422
+ const mcpSelectors = pluginMcpSelectors(res);
22423
+ const legacyPin = (mcpSelectors ?? []).find((s) => s !== canonicalMcp && s.includes("@brainervirus/workit-cursor@"));
22424
+ if (legacyPin) {
22425
+ return {
22426
+ id: "stale_install",
22427
+ status: "fail",
22428
+ detail: `stale_install: plugin mcp.json pins a legacy selector ${legacyPin} (canonical: ${canonicalMcp})`,
22429
+ fix: "Re-run install-cursor-plugin.sh — it rewrites the workit MCP entry to the canonical @latest selector"
22430
+ };
22431
+ }
22432
+ const hooksFile = path10.join(res.cursorPluginDir, "hooks", "hooks-cursor.json");
22433
+ const hookCmd = readJson(hooksFile)?.hooks?.sessionStart?.[0]?.command ?? null;
22434
+ const canonicalHook = canonicalCursorHook;
22435
+ const staleHook = hookCmd !== null && hookCmd !== canonicalHook && !hookCmd.startsWith("node ") && hookCmd.includes("@brainervirus/workit-cursor@");
22436
+ if (staleHook) {
22437
+ return {
22438
+ id: "stale_install",
22439
+ status: "fail",
22440
+ detail: `stale_install: sessionStart hook runs a legacy selector (canonical: ${canonicalHook})`,
22441
+ fix: "Re-run install-cursor-plugin.sh — it rewrites the sessionStart hook to the canonical @latest selector"
22442
+ };
22443
+ }
22444
+ const installed = installedPluginVersion(res);
22445
+ const source = res.dev ? readJson(path10.join(res.dev, "packages/workit-cursor/package.json"))?.version ?? null : readJson(path10.join(packageRoot(), "package.json"))?.version ?? null;
22446
+ const localDist = mcpSelectors === null && hookCmd !== null && hookCmd.startsWith("node ");
22447
+ if (localDist && installed !== null && source !== null && !semverAtLeast(installed, source)) {
22448
+ return {
22449
+ id: "stale_install",
22450
+ status: "fail",
22451
+ detail: `stale_install: installed workit-cursor ${installed} is behind the current runtime ${source}`,
22452
+ fix: "Re-run install-cursor-plugin.sh — it refreshes the plugin directory and rewrites the workit MCP/hook entries"
22453
+ };
22454
+ }
22455
+ if (installed !== null && localDist) {
22456
+ const expected = registryLatestVersion(res);
22457
+ if (expected === null) {
22458
+ return {
22459
+ id: "registry_unreachable",
22460
+ status: "warn",
22461
+ registryProbed: true,
22462
+ detail: "registry_unreachable: cannot compare installed workit-cursor against the published runtime",
22463
+ fix: "Retry when the npm registry is reachable, or re-run install-cursor-plugin.sh to refresh the install"
22464
+ };
22465
+ }
22466
+ if (!semverAtLeast(installed, expected)) {
22467
+ return {
22468
+ id: "stale_install",
22469
+ status: "fail",
22470
+ registryProbed: true,
22471
+ detail: `stale_install: local-dist workit-cursor ${installed} is behind the published runtime ${expected}`,
22472
+ fix: "Re-run install-cursor-plugin.sh — it refreshes the plugin directory with the current build"
22473
+ };
22474
+ }
22475
+ return {
22476
+ id: "stale_install",
22477
+ status: "pass",
22478
+ registryProbed: true,
22479
+ detail: `installed local-dist workit-cursor ${installed} matches the published runtime ${expected}`
22480
+ };
22481
+ }
22482
+ return {
22483
+ id: "stale_install",
22484
+ status: "pass",
22485
+ detail: installed === null ? "installed workit-cursor selectors are canonical" : `installed workit-cursor ${installed} is metadata on the canonical @latest install (fresh at launch)`
22486
+ };
22348
22487
  }, checkDuplicateRegistration = (res) => {
22349
22488
  const problems = [];
22350
22489
  const opencodeHost = res.host !== "cursor";
22351
22490
  const cursorHost = res.host !== "opencode";
22352
- if (opencodeHost && existsSync5(res.opencodeConfig)) {
22491
+ if (opencodeHost && existsSync6(res.opencodeConfig)) {
22353
22492
  const cfg = readJson(res.opencodeConfig);
22354
22493
  const entries = pluginEntries(cfg);
22355
22494
  if (entries.length > 1)
22356
22495
  problems.push(`opencode registers ${entries.length} workit plugin entries`);
22357
22496
  }
22358
- if (cursorHost && existsSync5(res.cursorSettings)) {
22497
+ if (cursorHost && existsSync6(res.cursorSettings)) {
22359
22498
  const settings = readJson(res.cursorSettings);
22360
22499
  const enabled = settings?.enabled_plugins;
22361
22500
  if (enabled && typeof enabled === "object") {
@@ -22370,7 +22509,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
22370
22509
  if (dirs.length > 1)
22371
22510
  problems.push(`cursor plugin_dirs has ${dirs.length} workit entries`);
22372
22511
  }
22373
- if (cursorHost && existsSync5(res.cursorMcp)) {
22512
+ if (cursorHost && existsSync6(res.cursorMcp)) {
22374
22513
  const mcp = readJson(res.cursorMcp);
22375
22514
  const servers = mcp?.mcpServers ?? {};
22376
22515
  if (servers && typeof servers === "object") {
@@ -22380,7 +22519,11 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
22380
22519
  }
22381
22520
  }
22382
22521
  if (problems.length === 0) {
22383
- return { id: "duplicate_registration", status: "pass", detail: "no duplicate registrations" };
22522
+ return {
22523
+ id: "duplicate_registration",
22524
+ status: "pass",
22525
+ detail: "no duplicate registrations"
22526
+ };
22384
22527
  }
22385
22528
  return {
22386
22529
  id: "duplicate_registration",
@@ -22391,21 +22534,25 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
22391
22534
  }, checkMalformedConfig = (res) => {
22392
22535
  const files = [];
22393
22536
  for (const name of ["config.json", "youtrack.json", "vcs.json", "workspaces.json"]) {
22394
- const p = path9.join(res.configDir, name);
22395
- if (existsSync5(p))
22537
+ const p = path10.join(res.configDir, name);
22538
+ if (existsSync6(p))
22396
22539
  files.push(p);
22397
22540
  }
22398
22541
  const opencodeHost = res.host !== "cursor";
22399
22542
  const cursorHost = res.host !== "opencode";
22400
- if (opencodeHost && existsSync5(res.opencodeConfig))
22543
+ if (opencodeHost && existsSync6(res.opencodeConfig))
22401
22544
  files.push(res.opencodeConfig);
22402
- if (cursorHost && existsSync5(res.cursorSettings))
22545
+ if (cursorHost && existsSync6(res.cursorSettings))
22403
22546
  files.push(res.cursorSettings);
22404
- if (cursorHost && existsSync5(res.cursorMcp))
22547
+ if (cursorHost && existsSync6(res.cursorMcp))
22405
22548
  files.push(res.cursorMcp);
22406
22549
  const bad = files.filter((p) => !parsesAsConfigObject(p));
22407
22550
  if (bad.length === 0)
22408
- return { id: "malformed_config", status: "pass", detail: "config files parse" };
22551
+ return {
22552
+ id: "malformed_config",
22553
+ status: "pass",
22554
+ detail: "config files parse"
22555
+ };
22409
22556
  return {
22410
22557
  id: "malformed_config",
22411
22558
  status: "fail",
@@ -22413,12 +22560,20 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
22413
22560
  fix: `Repair the malformed config in ${bad[0]}`
22414
22561
  };
22415
22562
  }, checkWorkspaceMismatch = (res) => {
22416
- const file = path9.join(res.configDir, "workspaces.json");
22417
- if (!existsSync5(file))
22418
- return { id: "workspace_mismatch", status: "pass", detail: "no workspaces configured" };
22563
+ const file = path10.join(res.configDir, "workspaces.json");
22564
+ if (!existsSync6(file))
22565
+ return {
22566
+ id: "workspace_mismatch",
22567
+ status: "pass",
22568
+ detail: "no workspaces configured"
22569
+ };
22419
22570
  const ws = readJson(file);
22420
22571
  if (!Array.isArray(ws?.workspaces)) {
22421
- return { id: "workspace_mismatch", status: "pass", detail: "no workspaces configured" };
22572
+ return {
22573
+ id: "workspace_mismatch",
22574
+ status: "pass",
22575
+ detail: "no workspaces configured"
22576
+ };
22422
22577
  }
22423
22578
  const match = resolveWorkspaceFrom(res.cwd, res.configDir);
22424
22579
  if (match)
@@ -22441,29 +22596,33 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
22441
22596
  }
22442
22597
  }, checkCredentialMetadata = (res) => {
22443
22598
  const tokenPaths = [];
22444
- const youtrackJson = readJson(path9.join(res.configDir, "youtrack.json"));
22599
+ const youtrackJson = readJson(path10.join(res.configDir, "youtrack.json"));
22445
22600
  if (youtrackJson) {
22446
- tokenPaths.push(typeof youtrackJson.tokenFile === "string" ? youtrackJson.tokenFile : path9.join(res.configDir, "youtrack.token"));
22447
- } else if (existsSync5(path9.join(res.configDir, "youtrack.token"))) {
22448
- tokenPaths.push(path9.join(res.configDir, "youtrack.token"));
22601
+ tokenPaths.push(typeof youtrackJson.tokenFile === "string" ? youtrackJson.tokenFile : path10.join(res.configDir, "youtrack.token"));
22602
+ } else if (existsSync6(path10.join(res.configDir, "youtrack.token"))) {
22603
+ tokenPaths.push(path10.join(res.configDir, "youtrack.token"));
22449
22604
  }
22450
- const vcsJson = readJson(path9.join(res.configDir, "vcs.json"));
22605
+ const vcsJson = readJson(path10.join(res.configDir, "vcs.json"));
22451
22606
  for (const key of ["gitlab", "github"]) {
22452
22607
  const provider = vcsJson?.[key];
22453
22608
  if (provider && typeof provider === "object") {
22454
22609
  const tf = provider.tokenFile;
22455
- tokenPaths.push(typeof tf === "string" ? tf : path9.join(res.configDir, `${key}.token`));
22456
- } else if (!vcsJson && existsSync5(path9.join(res.configDir, `${key}.token`))) {
22457
- tokenPaths.push(path9.join(res.configDir, `${key}.token`));
22610
+ tokenPaths.push(typeof tf === "string" ? tf : path10.join(res.configDir, `${key}.token`));
22611
+ } else if (!vcsJson && existsSync6(path10.join(res.configDir, `${key}.token`))) {
22612
+ tokenPaths.push(path10.join(res.configDir, `${key}.token`));
22458
22613
  }
22459
22614
  }
22460
22615
  if (tokenPaths.length === 0) {
22461
- return { id: "credential_metadata", status: "pass", detail: "no credentials configured" };
22616
+ return {
22617
+ id: "credential_metadata",
22618
+ status: "pass",
22619
+ detail: "no credentials configured"
22620
+ };
22462
22621
  }
22463
22622
  const problems = [];
22464
22623
  for (const raw of tokenPaths) {
22465
- const p = path9.isAbsolute(raw) ? raw : path9.resolve(res.configDir, raw);
22466
- if (!existsSync5(p)) {
22624
+ const p = path10.isAbsolute(raw) ? raw : path10.resolve(res.configDir, raw);
22625
+ if (!existsSync6(p)) {
22467
22626
  problems.push(`${p} is missing`);
22468
22627
  continue;
22469
22628
  }
@@ -22489,13 +22648,17 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
22489
22648
  fix: "Create or fix the token file (mode 0600, real value) — see /wk-status for the exact path"
22490
22649
  };
22491
22650
  }, checkLogWritable = (res) => {
22492
- const logsDir = path9.join(res.stateDir, "logs");
22493
- const probe = path9.join(logsDir, "doctor-probe.tmp");
22651
+ const logsDir = path10.join(res.stateDir, "logs");
22652
+ const probe = path10.join(logsDir, "doctor-probe.tmp");
22494
22653
  try {
22495
22654
  mkdirSync4(logsDir, { recursive: true, mode: 448 });
22496
22655
  writeFileSync3(probe, `{"probe":true}
22497
22656
  `, { mode: 384 });
22498
- return { id: "log_writable", status: "pass", detail: "log directory writable" };
22657
+ return {
22658
+ id: "log_writable",
22659
+ status: "pass",
22660
+ detail: "log directory writable"
22661
+ };
22499
22662
  } catch (err) {
22500
22663
  return {
22501
22664
  id: "log_writable",
@@ -22511,15 +22674,20 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
22511
22674
  }, RUN_CHECKS, INSTALLER_REQUIRED, runDoctor = (options = {}) => {
22512
22675
  const res = resolve(options);
22513
22676
  const raw = RUN_CHECKS.map((fn) => fn(res));
22514
- const checks4 = res.installer ? raw.map((c) => c.status === "fail" && !INSTALLER_REQUIRED.has(c.id) ? { ...c, status: "warn", detail: `${c.detail} (not enforced by installer)` } : c) : raw;
22677
+ const checks4 = res.installer ? raw.map((c) => c.status === "fail" && !INSTALLER_REQUIRED.has(c.id) ? {
22678
+ ...c,
22679
+ status: "warn",
22680
+ detail: `${c.detail} (not enforced by installer)`
22681
+ } : c) : raw;
22515
22682
  const failed = checks4.filter((c) => c.status === "fail").length;
22516
22683
  const warned = checks4.filter((c) => c.status === "warn").length;
22517
22684
  const passed = checks4.filter((c) => c.status === "pass").length;
22518
22685
  const exitCode = failed > 0 ? 1 : 0;
22686
+ const offline = !raw.some((c) => ("registryProbed" in c) && c.registryProbed);
22519
22687
  const report = {
22520
22688
  ok: failed === 0,
22521
22689
  exitCode,
22522
- offline: true,
22690
+ offline,
22523
22691
  host: res.host,
22524
22692
  checked_at: new Date().toISOString(),
22525
22693
  summary: { passed, warned, failed, total: checks4.length },
@@ -22529,7 +22697,7 @@ var TOKEN_PLACEHOLDER2 = "YOUR_TOKEN_HERE", findDevFromCwd = (cwd) => {
22529
22697
  getDiagnosticLogger()?.info(EVENT.doctor, {
22530
22698
  host: res.host,
22531
22699
  exit_code: exitCode,
22532
- offline: true,
22700
+ offline,
22533
22701
  failed: checks4.filter((c) => c.status === "fail").map((c) => c.id),
22534
22702
  total: checks4.length
22535
22703
  });
@@ -22539,6 +22707,7 @@ var init_doctor = __esm(() => {
22539
22707
  init_support_matrix();
22540
22708
  init_boundary();
22541
22709
  init_config();
22710
+ init_package_root();
22542
22711
  init_registration();
22543
22712
  init_workspaces();
22544
22713
  init_skill_manifests();
@@ -22550,6 +22719,7 @@ var init_doctor = __esm(() => {
22550
22719
  checkLauncher,
22551
22720
  checkUtility,
22552
22721
  checkStalePin,
22722
+ checkStaleInstall,
22553
22723
  checkDuplicateRegistration,
22554
22724
  checkMalformedConfig,
22555
22725
  checkWorkspaceMismatch,
@@ -22562,6 +22732,7 @@ var init_doctor = __esm(() => {
22562
22732
  "launcher",
22563
22733
  "utility",
22564
22734
  "stale_pin",
22735
+ "stale_install",
22565
22736
  "duplicate_registration",
22566
22737
  "malformed_config"
22567
22738
  ]);
@@ -22569,7 +22740,7 @@ var init_doctor = __esm(() => {
22569
22740
 
22570
22741
  // packages/workit-core/src/core/pr-create.ts
22571
22742
  import fs2 from "node:fs";
22572
- import path10 from "node:path";
22743
+ import path11 from "node:path";
22573
22744
  import { spawnSync as spawnSync5 } from "node:child_process";
22574
22745
  function parseGhRepo(remote) {
22575
22746
  remote = (remote || "").trim().replace(/\/+$/, "");
@@ -22634,11 +22805,11 @@ ${line}` : line;
22634
22805
  }
22635
22806
  function whichOnPath(tool) {
22636
22807
  const names = process.platform === "win32" ? [tool, `${tool}.exe`, `${tool}.cmd`] : [tool];
22637
- for (const dir of (process.env.PATH ?? "").split(path10.delimiter)) {
22808
+ for (const dir of (process.env.PATH ?? "").split(path11.delimiter)) {
22638
22809
  if (!dir)
22639
22810
  continue;
22640
22811
  for (const name of names) {
22641
- const candidate = path10.join(dir, name);
22812
+ const candidate = path11.join(dir, name);
22642
22813
  try {
22643
22814
  fs2.accessSync(candidate, fs2.constants.X_OK);
22644
22815
  return candidate;
@@ -22740,7 +22911,7 @@ function prCreate(env, cwd) {
22740
22911
  const draft = String(env.WF_PR_DRAFT ?? "false").toLowerCase() === "true";
22741
22912
  let baseUrl = cfg.youtrack_base_url;
22742
22913
  if (!baseUrl) {
22743
- const ytCfg = process.env.WORKFLOW_YOUTRACK_CONFIG ?? path10.join(path10.dirname(String(cfg.configPath)), "youtrack.json");
22914
+ const ytCfg = process.env.WORKFLOW_YOUTRACK_CONFIG ?? path11.join(path11.dirname(String(cfg.configPath)), "youtrack.json");
22744
22915
  try {
22745
22916
  const yt = JSON.parse(fs2.readFileSync(ytCfg, "utf8"));
22746
22917
  if (yt && typeof yt === "object")
@@ -22849,25 +23020,6 @@ var init_pr_create = __esm(() => {
22849
23020
  init_branch();
22850
23021
  });
22851
23022
 
22852
- // packages/workit-core/src/core/package-root.ts
22853
- import { existsSync as existsSync6 } from "node:fs";
22854
- import path11 from "node:path";
22855
- import { fileURLToPath } from "node:url";
22856
- var packageRoot = () => {
22857
- let dir = path11.dirname(fileURLToPath(import.meta.url));
22858
- while (true) {
22859
- const parent = path11.dirname(dir);
22860
- if (existsSync6(path11.join(dir, "package.json")) || parent === dir)
22861
- return dir;
22862
- dir = parent;
22863
- }
22864
- }, assetRoot = () => {
22865
- const root = packageRoot();
22866
- const assets = path11.join(root, "assets");
22867
- return existsSync6(assets) ? assets : root;
22868
- };
22869
- var init_package_root = () => {};
22870
-
22871
23023
  // packages/workit-core/src/core/scripts.ts
22872
23024
  var PLUGIN_ROOT, ASSET_ROOT, resolveWorkspaceRoot = (explicit) => explicit || process.cwd();
22873
23025
  var init_scripts = __esm(() => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-cursor",
3
- "version": "0.8.7",
3
+ "version": "0.8.8",
4
4
  "private": false,
5
5
  "description": "Workit Cursor plugin: MCP server, hooks, rules, marketplace manifest (thin over @brainervirus/workit-core)",
6
6
  "keywords": [
@@ -39,7 +39,7 @@
39
39
  "build": "bun scripts/build.ts"
40
40
  },
41
41
  "dependencies": {
42
- "@brainervirus/workit-core": "^0.8.7",
42
+ "@brainervirus/workit-core": "^0.8.8",
43
43
  "@modelcontextprotocol/sdk": "^1.12.0",
44
44
  "zod": "^3.24.0"
45
45
  },