@brainervirus/workit-opencode 0.8.6 → 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.
Files changed (2) hide show
  1. package/dist/plugin.js +183 -22
  2. package/package.json +2 -2
package/dist/plugin.js CHANGED
@@ -1132,10 +1132,22 @@ function isWorkitPlugin(value) {
1132
1132
  const pkgPath = s.includes("/packages/workit-opencode/") || s.includes("/packages/workit-cursor/") || s.includes("/node_modules/@brainervirus/workit-opencode/") || s.includes("/node_modules/@brainervirus/workit-cursor/");
1133
1133
  return named(s, "workflow-toolkit") || named(s, "workflow-toolkit-opencode") || named(s, "local/workflow-toolkit") || named(s, "workit") || named(s, "local/workit") || named(s, "@brainervirus/workit-opencode") || named(s, "@brainervirus/workit-cursor") || url && pkgPath || s.startsWith("git+file://") && s.includes("workflow-toolkit");
1134
1134
  }
1135
- var CURSOR_RUNTIME_PACKAGE = "@brainervirus/workit-cursor@0.8.5";
1135
+ var CURSOR_RUNTIME_PACKAGE = "@brainervirus/workit-cursor@latest";
1136
+ function cursorMcpServerEntry(_packageDir) {
1137
+ return {
1138
+ command: "npx",
1139
+ args: [
1140
+ "-y",
1141
+ "--prefer-online",
1142
+ `--package=${CURSOR_RUNTIME_PACKAGE}`,
1143
+ "workit-cursor-mcp",
1144
+ "${workspaceFolder}"
1145
+ ]
1146
+ };
1147
+ }
1136
1148
  function cursorHooksEntry(_packageDir) {
1137
1149
  return {
1138
- command: `npx -y --package=${CURSOR_RUNTIME_PACKAGE} workit-cursor-session-start`,
1150
+ command: `npx -y --prefer-online --package=${CURSOR_RUNTIME_PACKAGE} workit-cursor-session-start`,
1139
1151
  args: []
1140
1152
  };
1141
1153
  }
@@ -1505,12 +1517,9 @@ var registeredCursorLauncher = (res) => {
1505
1517
  return "invalid";
1506
1518
  }
1507
1519
  const executable = path10.basename(command).toLowerCase();
1520
+ const canonical = cursorMcpServerEntry("").args;
1508
1521
  if (executable === "npx" || executable === "npx.exe" || executable === "npx.cmd") {
1509
- if (args[0] !== "-y")
1510
- return "invalid";
1511
- if (args[1] !== `--package=${CURSOR_RUNTIME_PACKAGE}`)
1512
- return "invalid";
1513
- if (args[2] !== "workit-cursor-mcp")
1522
+ if (args.length !== canonical.length || args.some((a, i) => a !== canonical[i]))
1514
1523
  return "invalid";
1515
1524
  return { kind: "npx" };
1516
1525
  }
@@ -1587,7 +1596,11 @@ var checkLauncher = (res) => {
1587
1596
  detail: "no dev checkout found (WORKFLOW_TOOLKIT_DEV) — skipping non-Cursor launcher checks"
1588
1597
  };
1589
1598
  }
1590
- return { id: "launcher", status: "pass", detail: `${res.host} launcher/hook entries present` };
1599
+ return {
1600
+ id: "launcher",
1601
+ status: "pass",
1602
+ detail: `${res.host} launcher/hook entries present`
1603
+ };
1591
1604
  };
1592
1605
  var checkUtility = (res) => {
1593
1606
  const git = commandOnPath("git", res.env);
@@ -1607,7 +1620,11 @@ var checkUtility = (res) => {
1607
1620
  fix: "Install util-linux (flock)"
1608
1621
  };
1609
1622
  }
1610
- return { id: "utility", status: "pass", detail: "git (and flock where required) on PATH" };
1623
+ return {
1624
+ id: "utility",
1625
+ status: "pass",
1626
+ detail: "git (and flock where required) on PATH"
1627
+ };
1611
1628
  };
1612
1629
  var staleEntry = (entry) => {
1613
1630
  if (!entry)
@@ -1629,7 +1646,11 @@ var checkStalePin = (res) => {
1629
1646
  };
1630
1647
  }
1631
1648
  if (!existsSync7(res.opencodeConfig)) {
1632
- return { id: "stale_pin", status: "pass", detail: "no opencode config — not registered" };
1649
+ return {
1650
+ id: "stale_pin",
1651
+ status: "pass",
1652
+ detail: "no opencode config — not registered"
1653
+ };
1633
1654
  }
1634
1655
  const cfg = readJson(res.opencodeConfig);
1635
1656
  const entries = pluginEntries(cfg);
@@ -1660,6 +1681,118 @@ var checkStalePin = (res) => {
1660
1681
  }
1661
1682
  return { id: "stale_pin", status: "pass", detail: "opencode pin resolves" };
1662
1683
  };
1684
+ var pluginMcpSelectors = (res) => {
1685
+ const p = path10.join(res.cursorPluginDir, "mcp.json");
1686
+ if (!existsSync7(p))
1687
+ return null;
1688
+ const cfg = readJson(p);
1689
+ const server = cfg?.mcpServers?.workit;
1690
+ if (!server || typeof server !== "object" || Array.isArray(server))
1691
+ return null;
1692
+ const args = server.args;
1693
+ if (!Array.isArray(args))
1694
+ return null;
1695
+ return args.map(String).filter((a) => a.startsWith("--package="));
1696
+ };
1697
+ var registryLatestVersion = (res) => {
1698
+ const seam = res.env.WORKIT_DOCTOR_STALE_REGISTRY_VERSION;
1699
+ if (typeof seam === "string" && seam) {
1700
+ return /^\d+(?:\.\d+){1,2}$/.test(seam) ? seam : null;
1701
+ }
1702
+ const cmd = res.env.WORKIT_DOCTOR_STALE_REGISTRY_CMD ?? (commandOnPath("npm", res.env) ? "npm" : null);
1703
+ if (!cmd)
1704
+ return null;
1705
+ try {
1706
+ const r = spawnSync2(cmd, ["view", CURSOR_RUNTIME_PACKAGE, "version"], {
1707
+ encoding: "utf8",
1708
+ timeout: 20000,
1709
+ env: res.env
1710
+ });
1711
+ const v = (r.stdout ?? "").trim().split(/\s+/)[0];
1712
+ return r.status === 0 && /^\d+(?:\.\d+){1,2}$/.test(v) ? v : null;
1713
+ } catch {
1714
+ return null;
1715
+ }
1716
+ };
1717
+ var installedPluginVersion = (res) => {
1718
+ const pkg = readJson(path10.join(res.cursorPluginDir, "package.json"));
1719
+ return typeof pkg?.version === "string" && pkg.version ? pkg.version : null;
1720
+ };
1721
+ var checkStaleInstall = (res) => {
1722
+ if (res.host !== "cursor" && res.host !== "cli") {
1723
+ return {
1724
+ id: "stale_install",
1725
+ status: "pass",
1726
+ detail: "cursor plugin not inspected on the opencode host"
1727
+ };
1728
+ }
1729
+ const canonicalMcp = cursorMcpServerEntry("").args.find((a) => a.startsWith("--package="));
1730
+ const mcpSelectors = pluginMcpSelectors(res);
1731
+ const legacyPin = (mcpSelectors ?? []).find((s) => s !== canonicalMcp && s.includes("@brainervirus/workit-cursor@"));
1732
+ if (legacyPin) {
1733
+ return {
1734
+ id: "stale_install",
1735
+ status: "fail",
1736
+ detail: `stale_install: plugin mcp.json pins a legacy selector ${legacyPin} (canonical: ${canonicalMcp})`,
1737
+ fix: "Re-run install-cursor-plugin.sh — it rewrites the workit MCP entry to the canonical @latest selector"
1738
+ };
1739
+ }
1740
+ const hooksFile = path10.join(res.cursorPluginDir, "hooks", "hooks-cursor.json");
1741
+ const hookCmd = readJson(hooksFile)?.hooks?.sessionStart?.[0]?.command ?? null;
1742
+ const canonicalHook = canonicalCursorHook;
1743
+ const staleHook = hookCmd !== null && hookCmd !== canonicalHook && !hookCmd.startsWith("node ") && hookCmd.includes("@brainervirus/workit-cursor@");
1744
+ if (staleHook) {
1745
+ return {
1746
+ id: "stale_install",
1747
+ status: "fail",
1748
+ detail: `stale_install: sessionStart hook runs a legacy selector (canonical: ${canonicalHook})`,
1749
+ fix: "Re-run install-cursor-plugin.sh — it rewrites the sessionStart hook to the canonical @latest selector"
1750
+ };
1751
+ }
1752
+ const installed = installedPluginVersion(res);
1753
+ const source = res.dev ? readJson(path10.join(res.dev, "packages/workit-cursor/package.json"))?.version ?? null : readJson(path10.join(packageRoot(), "package.json"))?.version ?? null;
1754
+ const localDist = mcpSelectors === null && hookCmd !== null && hookCmd.startsWith("node ");
1755
+ if (localDist && installed !== null && source !== null && !semverAtLeast(installed, source)) {
1756
+ return {
1757
+ id: "stale_install",
1758
+ status: "fail",
1759
+ detail: `stale_install: installed workit-cursor ${installed} is behind the current runtime ${source}`,
1760
+ fix: "Re-run install-cursor-plugin.sh — it refreshes the plugin directory and rewrites the workit MCP/hook entries"
1761
+ };
1762
+ }
1763
+ if (installed !== null && localDist) {
1764
+ const expected = registryLatestVersion(res);
1765
+ if (expected === null) {
1766
+ return {
1767
+ id: "registry_unreachable",
1768
+ status: "warn",
1769
+ registryProbed: true,
1770
+ detail: "registry_unreachable: cannot compare installed workit-cursor against the published runtime",
1771
+ fix: "Retry when the npm registry is reachable, or re-run install-cursor-plugin.sh to refresh the install"
1772
+ };
1773
+ }
1774
+ if (!semverAtLeast(installed, expected)) {
1775
+ return {
1776
+ id: "stale_install",
1777
+ status: "fail",
1778
+ registryProbed: true,
1779
+ detail: `stale_install: local-dist workit-cursor ${installed} is behind the published runtime ${expected}`,
1780
+ fix: "Re-run install-cursor-plugin.sh — it refreshes the plugin directory with the current build"
1781
+ };
1782
+ }
1783
+ return {
1784
+ id: "stale_install",
1785
+ status: "pass",
1786
+ registryProbed: true,
1787
+ detail: `installed local-dist workit-cursor ${installed} matches the published runtime ${expected}`
1788
+ };
1789
+ }
1790
+ return {
1791
+ id: "stale_install",
1792
+ status: "pass",
1793
+ detail: installed === null ? "installed workit-cursor selectors are canonical" : `installed workit-cursor ${installed} is metadata on the canonical @latest install (fresh at launch)`
1794
+ };
1795
+ };
1663
1796
  var checkDuplicateRegistration = (res) => {
1664
1797
  const problems = [];
1665
1798
  const opencodeHost = res.host !== "cursor";
@@ -1695,7 +1828,11 @@ var checkDuplicateRegistration = (res) => {
1695
1828
  }
1696
1829
  }
1697
1830
  if (problems.length === 0) {
1698
- return { id: "duplicate_registration", status: "pass", detail: "no duplicate registrations" };
1831
+ return {
1832
+ id: "duplicate_registration",
1833
+ status: "pass",
1834
+ detail: "no duplicate registrations"
1835
+ };
1699
1836
  }
1700
1837
  return {
1701
1838
  id: "duplicate_registration",
@@ -1721,7 +1858,11 @@ var checkMalformedConfig = (res) => {
1721
1858
  files.push(res.cursorMcp);
1722
1859
  const bad = files.filter((p) => !parsesAsConfigObject(p));
1723
1860
  if (bad.length === 0)
1724
- return { id: "malformed_config", status: "pass", detail: "config files parse" };
1861
+ return {
1862
+ id: "malformed_config",
1863
+ status: "pass",
1864
+ detail: "config files parse"
1865
+ };
1725
1866
  return {
1726
1867
  id: "malformed_config",
1727
1868
  status: "fail",
@@ -1732,10 +1873,18 @@ var checkMalformedConfig = (res) => {
1732
1873
  var checkWorkspaceMismatch = (res) => {
1733
1874
  const file = path10.join(res.configDir, "workspaces.json");
1734
1875
  if (!existsSync7(file))
1735
- return { id: "workspace_mismatch", status: "pass", detail: "no workspaces configured" };
1876
+ return {
1877
+ id: "workspace_mismatch",
1878
+ status: "pass",
1879
+ detail: "no workspaces configured"
1880
+ };
1736
1881
  const ws = readJson(file);
1737
1882
  if (!Array.isArray(ws?.workspaces)) {
1738
- return { id: "workspace_mismatch", status: "pass", detail: "no workspaces configured" };
1883
+ return {
1884
+ id: "workspace_mismatch",
1885
+ status: "pass",
1886
+ detail: "no workspaces configured"
1887
+ };
1739
1888
  }
1740
1889
  const match = resolveWorkspaceFrom(res.cwd, res.configDir);
1741
1890
  if (match)
@@ -1777,7 +1926,11 @@ var checkCredentialMetadata = (res) => {
1777
1926
  }
1778
1927
  }
1779
1928
  if (tokenPaths.length === 0) {
1780
- return { id: "credential_metadata", status: "pass", detail: "no credentials configured" };
1929
+ return {
1930
+ id: "credential_metadata",
1931
+ status: "pass",
1932
+ detail: "no credentials configured"
1933
+ };
1781
1934
  }
1782
1935
  const problems = [];
1783
1936
  for (const raw of tokenPaths) {
@@ -1815,7 +1968,11 @@ var checkLogWritable = (res) => {
1815
1968
  mkdirSync3(logsDir, { recursive: true, mode: 448 });
1816
1969
  writeFileSync6(probe, `{"probe":true}
1817
1970
  `, { mode: 384 });
1818
- return { id: "log_writable", status: "pass", detail: "log directory writable" };
1971
+ return {
1972
+ id: "log_writable",
1973
+ status: "pass",
1974
+ detail: "log directory writable"
1975
+ };
1819
1976
  } catch (err) {
1820
1977
  return {
1821
1978
  id: "log_writable",
@@ -1836,6 +1993,7 @@ var RUN_CHECKS = [
1836
1993
  checkLauncher,
1837
1994
  checkUtility,
1838
1995
  checkStalePin,
1996
+ checkStaleInstall,
1839
1997
  checkDuplicateRegistration,
1840
1998
  checkMalformedConfig,
1841
1999
  checkWorkspaceMismatch,
@@ -1848,21 +2006,27 @@ var INSTALLER_REQUIRED = new Set([
1848
2006
  "launcher",
1849
2007
  "utility",
1850
2008
  "stale_pin",
2009
+ "stale_install",
1851
2010
  "duplicate_registration",
1852
2011
  "malformed_config"
1853
2012
  ]);
1854
2013
  var runDoctor = (options = {}) => {
1855
2014
  const res = resolve(options);
1856
2015
  const raw = RUN_CHECKS.map((fn) => fn(res));
1857
- const checks = 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;
2016
+ const checks = res.installer ? raw.map((c) => c.status === "fail" && !INSTALLER_REQUIRED.has(c.id) ? {
2017
+ ...c,
2018
+ status: "warn",
2019
+ detail: `${c.detail} (not enforced by installer)`
2020
+ } : c) : raw;
1858
2021
  const failed = checks.filter((c) => c.status === "fail").length;
1859
2022
  const warned = checks.filter((c) => c.status === "warn").length;
1860
2023
  const passed = checks.filter((c) => c.status === "pass").length;
1861
2024
  const exitCode = failed > 0 ? 1 : 0;
2025
+ const offline = !raw.some((c) => ("registryProbed" in c) && c.registryProbed);
1862
2026
  const report = {
1863
2027
  ok: failed === 0,
1864
2028
  exitCode,
1865
- offline: true,
2029
+ offline,
1866
2030
  host: res.host,
1867
2031
  checked_at: new Date().toISOString(),
1868
2032
  summary: { passed, warned, failed, total: checks.length },
@@ -1872,7 +2036,7 @@ var runDoctor = (options = {}) => {
1872
2036
  getDiagnosticLogger()?.info(EVENT.doctor, {
1873
2037
  host: res.host,
1874
2038
  exit_code: exitCode,
1875
- offline: true,
2039
+ offline,
1876
2040
  failed: checks.filter((c) => c.status === "fail").map((c) => c.id),
1877
2041
  total: checks.length
1878
2042
  });
@@ -5376,9 +5540,6 @@ var resetForSpecDrift = (state) => ({
5376
5540
  var resetForPlanDrift = (state) => ({
5377
5541
  ...state,
5378
5542
  plan: { ...state.plan, status: "draft", evidence: null, approved_digest: null },
5379
- menu: { presented: false, chosen: "", evidence: null },
5380
- execution: { status: "pending", mode: null, evidence: null },
5381
- handoff_destination: false,
5382
5543
  updated_at: Date.now()
5383
5544
  });
5384
5545
  var driftCodeFor = (root2, relPath, storedDigest) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-opencode",
3
- "version": "0.8.6",
3
+ "version": "0.8.8",
4
4
  "private": false,
5
5
  "description": "Workit OpenCode plugin (thin wrapper over @brainervirus/workit-core)",
6
6
  "keywords": [
@@ -34,7 +34,7 @@
34
34
  "typecheck": "tsc --noEmit"
35
35
  },
36
36
  "dependencies": {
37
- "@brainervirus/workit-core": "^0.8.6"
37
+ "@brainervirus/workit-core": "^0.8.8"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@opencode-ai/plugin": "1.17.7"