@brainervirus/workit-core 0.11.0 → 1.0.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.
Files changed (150) hide show
  1. package/README.md +5 -3
  2. package/package.json +8 -3
  3. package/scripts/analyze-release-scope.ts +4 -1
  4. package/scripts/doctor-check.ts +3 -1
  5. package/scripts/install-codex-plugin.sh +28 -0
  6. package/scripts/install-cursor-plugin.sh +1 -0
  7. package/scripts/install-opencode-plugin.sh +1 -0
  8. package/scripts/install-pi-package.sh +56 -0
  9. package/scripts/rewrite-workspace-deps.ts +22 -5
  10. package/scripts/sync-release-manifests.ts +8 -5
  11. package/scripts/sync-runtime.sh +7 -3
  12. package/scripts/validate-cursor-marketplace.ts +16 -62
  13. package/skills/workit-babysit/SKILL.md +33 -0
  14. package/skills/workit-behavioral-tdd/SKILL.md +53 -0
  15. package/skills/workit-blast-radius/SKILL.md +31 -0
  16. package/skills/workit-challenge/SKILL.md +62 -0
  17. package/skills/workit-debug/SKILL.md +61 -0
  18. package/skills/workit-deslop/SKILL.md +36 -0
  19. package/skills/workit-diagram/SKILL.md +32 -0
  20. package/skills/workit-green-run/SKILL.md +29 -0
  21. package/skills/workit-handoff/SKILL.md +43 -0
  22. package/skills/workit-implement/SKILL.md +46 -0
  23. package/skills/workit-mockup/SKILL.md +28 -0
  24. package/skills/workit-plan/SKILL.md +66 -0
  25. package/skills/workit-review/SKILL.md +60 -0
  26. package/skills/workit-steer/SKILL.md +32 -0
  27. package/src/core/authority.ts +918 -0
  28. package/src/core/boundary.ts +29 -0
  29. package/src/core/branch.ts +26 -255
  30. package/src/core/changelog.ts +95 -18
  31. package/src/core/commit-flavors.ts +65 -0
  32. package/src/core/config-conversion.ts +183 -0
  33. package/src/core/config.ts +42 -0
  34. package/src/core/cutover.ts +721 -0
  35. package/src/core/detect-hosts.ts +107 -0
  36. package/src/core/doctor.ts +428 -18
  37. package/src/core/external-action-effects.ts +1171 -0
  38. package/src/core/external-action.ts +541 -0
  39. package/src/core/init.ts +83 -32
  40. package/src/core/methods.ts +125 -0
  41. package/src/core/policy-resolver.ts +523 -0
  42. package/src/core/pr-create.ts +7 -1
  43. package/src/core/registration.ts +69 -4
  44. package/src/core/repo-context.ts +59 -1
  45. package/src/core/setup.ts +28 -0
  46. package/src/core/skill-manifests.ts +40 -42
  47. package/src/core/support-matrix.ts +8 -3
  48. package/src/core/sync-runtime.ts +15 -3
  49. package/src/core/task-context.ts +179 -0
  50. package/src/core/task-contract.ts +1136 -0
  51. package/src/core/task-engine.ts +2562 -0
  52. package/src/core/task-evaluation.ts +679 -0
  53. package/src/core/task-store.ts +1071 -0
  54. package/src/core/tracker-issues.ts +237 -0
  55. package/src/core/uninstall.ts +67 -3
  56. package/src/core/vcs-config.ts +53 -22
  57. package/src/core/workers.ts +166 -0
  58. package/src/core/workspaces.ts +3 -1
  59. package/src/core/youtrack-tools.ts +2 -0
  60. package/src/core/youtrack.ts +145 -10
  61. package/src/core.ts +126 -0
  62. package/templates/execution-contract.md +17 -50
  63. package/templates/plan-template.md +3 -3
  64. package/templates/spec-template.md +15 -3
  65. package/templates/workit-contract.md +12 -0
  66. package/commands/wk-changelog.md +0 -2
  67. package/commands/wk-commit.md +0 -2
  68. package/commands/wk-docs-refresh.md +0 -2
  69. package/commands/wk-handoff.md +0 -2
  70. package/commands/wk-implement.md +0 -2
  71. package/commands/wk-init.md +0 -2
  72. package/commands/wk-issue-update.md +0 -2
  73. package/commands/wk-meetings.md +0 -2
  74. package/commands/wk-pr.md +0 -2
  75. package/commands/wk-release-notes.md +0 -2
  76. package/commands/wk-status.md +0 -2
  77. package/commands/wk-verify.md +0 -2
  78. package/scripts/update-superpowers.sh +0 -82
  79. package/scripts/vendor-assets.ts +0 -37
  80. package/skills/wk-changelog/SKILL.md +0 -15
  81. package/skills/wk-commit/SKILL.md +0 -16
  82. package/skills/wk-docs-refresh/SKILL.md +0 -15
  83. package/skills/wk-handoff/SKILL.md +0 -20
  84. package/skills/wk-implement/SKILL.md +0 -47
  85. package/skills/wk-init/SKILL.md +0 -31
  86. package/skills/wk-issue-update/SKILL.md +0 -27
  87. package/skills/wk-issue-update/references/youtrack-update-style.md +0 -81
  88. package/skills/wk-meetings/SKILL.md +0 -17
  89. package/skills/wk-pr/SKILL.md +0 -27
  90. package/skills/wk-release-notes/SKILL.md +0 -15
  91. package/skills/wk-status/SKILL.md +0 -16
  92. package/skills/wk-verify/SKILL.md +0 -16
  93. package/src/core/detector.ts +0 -239
  94. package/src/core/flow-state.ts +0 -3308
  95. package/src/core/handoff-context.ts +0 -136
  96. package/src/core/handoff-tools.ts +0 -133
  97. package/src/core/menu.ts +0 -70
  98. package/src/core/plan-tasks.ts +0 -43
  99. package/src/core/reminder.ts +0 -124
  100. package/src/core/sdd.ts +0 -353
  101. package/src/state.ts +0 -22
  102. package/templates/superpowers-doc-contract.md +0 -75
  103. package/vendor/superpowers/skills/brainstorming/SKILL.md +0 -159
  104. package/vendor/superpowers/skills/brainstorming/scripts/frame-template.html +0 -213
  105. package/vendor/superpowers/skills/brainstorming/scripts/helper.js +0 -167
  106. package/vendor/superpowers/skills/brainstorming/scripts/server.cjs +0 -723
  107. package/vendor/superpowers/skills/brainstorming/scripts/start-server.sh +0 -209
  108. package/vendor/superpowers/skills/brainstorming/scripts/stop-server.sh +0 -120
  109. package/vendor/superpowers/skills/brainstorming/spec-document-reviewer-prompt.md +0 -49
  110. package/vendor/superpowers/skills/brainstorming/visual-companion.md +0 -291
  111. package/vendor/superpowers/skills/dispatching-parallel-agents/SKILL.md +0 -185
  112. package/vendor/superpowers/skills/executing-plans/SKILL.md +0 -70
  113. package/vendor/superpowers/skills/finishing-a-development-branch/SKILL.md +0 -241
  114. package/vendor/superpowers/skills/receiving-code-review/SKILL.md +0 -213
  115. package/vendor/superpowers/skills/requesting-code-review/SKILL.md +0 -103
  116. package/vendor/superpowers/skills/requesting-code-review/code-reviewer.md +0 -172
  117. package/vendor/superpowers/skills/subagent-driven-development/SKILL.md +0 -428
  118. package/vendor/superpowers/skills/subagent-driven-development/implementer-prompt.md +0 -139
  119. package/vendor/superpowers/skills/subagent-driven-development/scripts/review-package +0 -44
  120. package/vendor/superpowers/skills/subagent-driven-development/scripts/sdd-workspace +0 -22
  121. package/vendor/superpowers/skills/subagent-driven-development/scripts/task-brief +0 -40
  122. package/vendor/superpowers/skills/subagent-driven-development/task-reviewer-prompt.md +0 -188
  123. package/vendor/superpowers/skills/systematic-debugging/CREATION-LOG.md +0 -119
  124. package/vendor/superpowers/skills/systematic-debugging/SKILL.md +0 -296
  125. package/vendor/superpowers/skills/systematic-debugging/condition-based-waiting-example.ts +0 -158
  126. package/vendor/superpowers/skills/systematic-debugging/condition-based-waiting.md +0 -115
  127. package/vendor/superpowers/skills/systematic-debugging/defense-in-depth.md +0 -122
  128. package/vendor/superpowers/skills/systematic-debugging/find-polluter.sh +0 -63
  129. package/vendor/superpowers/skills/systematic-debugging/root-cause-tracing.md +0 -169
  130. package/vendor/superpowers/skills/systematic-debugging/test-academic.md +0 -14
  131. package/vendor/superpowers/skills/systematic-debugging/test-pressure-1.md +0 -58
  132. package/vendor/superpowers/skills/systematic-debugging/test-pressure-2.md +0 -68
  133. package/vendor/superpowers/skills/systematic-debugging/test-pressure-3.md +0 -69
  134. package/vendor/superpowers/skills/test-driven-development/SKILL.md +0 -371
  135. package/vendor/superpowers/skills/test-driven-development/testing-anti-patterns.md +0 -299
  136. package/vendor/superpowers/skills/using-git-worktrees/SKILL.md +0 -202
  137. package/vendor/superpowers/skills/using-superpowers/SKILL.md +0 -62
  138. package/vendor/superpowers/skills/using-superpowers/references/antigravity-tools.md +0 -23
  139. package/vendor/superpowers/skills/using-superpowers/references/codex-tools.md +0 -39
  140. package/vendor/superpowers/skills/using-superpowers/references/pi-tools.md +0 -16
  141. package/vendor/superpowers/skills/verification-before-completion/SKILL.md +0 -139
  142. package/vendor/superpowers/skills/writing-plans/SKILL.md +0 -174
  143. package/vendor/superpowers/skills/writing-plans/plan-document-reviewer-prompt.md +0 -49
  144. package/vendor/superpowers/skills/writing-skills/SKILL.md +0 -689
  145. package/vendor/superpowers/skills/writing-skills/anthropic-best-practices.md +0 -1150
  146. package/vendor/superpowers/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +0 -189
  147. package/vendor/superpowers/skills/writing-skills/graphviz-conventions.dot +0 -172
  148. package/vendor/superpowers/skills/writing-skills/persuasion-principles.md +0 -187
  149. package/vendor/superpowers/skills/writing-skills/render-graphs.js +0 -168
  150. package/vendor/superpowers/skills/writing-skills/testing-skills-with-subagents.md +0 -384
package/README.md CHANGED
@@ -1,5 +1,9 @@
1
1
  # @brainervirus/workit-core
2
2
 
3
+ [![CI](https://github.com/BrainerVirus/workit/actions/workflows/ci.yml/badge.svg)](https://github.com/BrainerVirus/workit/actions/workflows/ci.yml)
4
+ [![npm version](https://img.shields.io/npm/v/@brainervirus/workit-core.svg)](https://www.npmjs.com/package/@brainervirus/workit-core)
5
+ [![license: MIT](https://img.shields.io/badge/license-MIT-green.svg)](../../LICENSE)
6
+
3
7
  Shared core for the workit plugins — the single source of workflow logic that the OpenCode, Cursor, and CLI packages adapt to their native surfaces.
4
8
 
5
9
  ## When you need it directly
@@ -17,11 +21,9 @@ You consume `@brainervirus/workit-core` directly only when:
17
21
  | --- | --- |
18
22
  | `src/core/` | Shared TS logic (setup, registration, doctor, logger, branch, PR, changelog, YouTrack, presentation, docs, SDD, support matrix). |
19
23
  | `src/core.ts` | Package entry; adapters import `@brainervirus/workit-core/src/*`. |
20
- | `skills/` | 12 OpenCode-native `wk-*` skills. |
21
- | `commands/` | 12 OpenCode `wk-*` command prompts. |
24
+ | `skills/` | 14 `workit-*` method skills (single source; adapters ship byte-identical copies). |
22
25
  | `scripts/` | Shared shell installers/launchers and the release-time workspace-dep rewrite. |
23
26
  | `templates/` | Execution and Superpowers contract templates. |
24
- | `vendor/superpowers/skills/` | 14 vendored Superpowers skills. |
25
27
 
26
28
  Adapters map host-native surfaces to `src/core/`; they never re-implement core logic. Keep shared behavior here and host-specific presentation in each adapter.
27
29
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@brainervirus/workit-core",
3
- "version": "0.11.0",
3
+ "version": "1.0.0",
4
4
  "private": false,
5
5
  "description": "Workit — workflow rails for agentic coding: specs, plans, YouTrack, CI-gated commits (shared core)",
6
6
  "keywords": [
@@ -23,8 +23,6 @@
23
23
  "src/",
24
24
  "scripts/",
25
25
  "skills/",
26
- "commands/",
27
- "vendor/superpowers/skills/",
28
26
  "templates/",
29
27
  "README.md",
30
28
  "LICENSE",
@@ -42,5 +40,12 @@
42
40
  },
43
41
  "scripts": {
44
42
  "typecheck": "tsc --noEmit"
43
+ },
44
+ "dependencies": {
45
+ "@openclaw/fs-safe": "0.8.1",
46
+ "zod": "4.5.4"
47
+ },
48
+ "engines": {
49
+ "node": ">=24"
45
50
  }
46
51
  }
@@ -7,9 +7,12 @@ import { resolve } from "node:path";
7
7
 
8
8
  export const RELEASE_PACKAGES = [
9
9
  "workit-core",
10
+ "workit-mcp",
11
+ "workit-cli",
10
12
  "workit-opencode",
11
13
  "workit-cursor",
12
- "workit-cli",
14
+ "workit-codex",
15
+ "workit-pi",
13
16
  ] as const;
14
17
 
15
18
  const g = (root: string, args: string[]): string =>
@@ -10,7 +10,9 @@
10
10
  // failures are left to the post-install gate.
11
11
  import { runDoctor } from "../src/core/doctor";
12
12
 
13
- const host = process.argv[2] === "cursor" ? "cursor" : "opencode";
13
+ const hostArg = process.argv[2];
14
+ const host =
15
+ hostArg === "cursor" ? "cursor" : hostArg === "cli" ? "cli" : "opencode";
14
16
  const staleOnly = process.argv.includes("--stale");
15
17
  const report = runDoctor({ host, installer: true });
16
18
 
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env bash
2
+ # Install / refresh the Codex workit plugin from the local checkout or share clone.
3
+ set -euo pipefail
4
+
5
+ SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
6
+ ROOT="$(CDPATH= cd -- "$SCRIPT_DIR/../../.." && pwd)"
7
+ SHARE="${HOME}/.local/share/workit"
8
+ DEV="${WORKFLOW_TOOLKIT_DEV:-$ROOT}"
9
+ PLUGIN_DIR="${HOME}/.codex/plugins/workit"
10
+
11
+ chmod +x "$ROOT/packages/workit-core/scripts/sync-runtime.sh"
12
+ WORKFLOW_TOOLKIT_DEV="$ROOT" "$ROOT/packages/workit-core/scripts/sync-runtime.sh"
13
+
14
+ SOURCE="$DEV"
15
+ if [ ! -d "$SOURCE/packages/workit-codex/.codex-plugin" ] && [ -d "$SHARE/packages/workit-codex/.codex-plugin" ]; then
16
+ SOURCE="$SHARE"
17
+ fi
18
+
19
+ mkdir -p "$PLUGIN_DIR"
20
+ rsync -a --delete "$SOURCE/packages/workit-codex/" "$PLUGIN_DIR/"
21
+
22
+ if ! bun "$ROOT/packages/workit-core/scripts/doctor-check.ts" cli; then
23
+ echo "FATAL: post-install doctor found problems after Codex plugin sync" >&2
24
+ exit 1
25
+ fi
26
+
27
+ echo "Codex plugin installed at $PLUGIN_DIR"
28
+ echo "Complete an explicit v1 cutover before treating this as a generation switch."
@@ -140,5 +140,6 @@ if [ -d "$LEGACY_PLUGIN_DIR" ] && [ "$LEGACY_PLUGIN_DIR" != "$PLUGIN_DIR" ]; the
140
140
  fi
141
141
 
142
142
  echo "Cursor plugin installed + auto-sync enabled (sessionStart)."
143
+ echo "Generation switches require an explicit cutover preview/apply — install alone is not a cutover."
143
144
  echo "Share: $SHARE"
144
145
  ls "$HOME/.cursor/plugins/local/workit/skills" | grep '^wk-' || true
@@ -77,3 +77,4 @@ if ! bun "$ROOT/packages/workit-core/scripts/doctor-check.ts" opencode; then
77
77
  fi
78
78
 
79
79
  echo "OpenCode install done. Fully quit all opencode processes, then restart."
80
+ echo "Generation switches require an explicit cutover preview/apply — install alone is not a cutover."
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env bash
2
+ # Register the Pi workit extension and skills from the local checkout or share clone.
3
+ set -euo pipefail
4
+
5
+ SCRIPT_DIR="$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)"
6
+ ROOT="$(CDPATH= cd -- "$SCRIPT_DIR/../../.." && pwd)"
7
+ SHARE="${HOME}/.local/share/workit"
8
+ DEV="${WORKFLOW_TOOLKIT_DEV:-$ROOT}"
9
+ PI_CONFIG="${HOME}/.pi/config.json"
10
+
11
+ chmod +x "$ROOT/packages/workit-core/scripts/sync-runtime.sh"
12
+ WORKFLOW_TOOLKIT_DEV="$ROOT" "$ROOT/packages/workit-core/scripts/sync-runtime.sh"
13
+
14
+ SOURCE="$DEV"
15
+ if [ ! -f "$SOURCE/packages/workit-pi/dist/workit.js" ] && [ -f "$SHARE/packages/workit-pi/dist/workit.js" ]; then
16
+ SOURCE="$SHARE"
17
+ fi
18
+
19
+ # pi 0.85.1 loads extensions from the settings `packages` list, not from
20
+ # ~/.pi/config.json below. Register the absolute package dir there (honoring
21
+ # PI_CODING_AGENT_DIR) so `pi list` picks it up; the config.json write stays
22
+ # because uninstall/cutover/detection still key pi state off it — migrating
23
+ # those three off config.json is a separate contract change.
24
+ AGENT_DIR="${PI_CODING_AGENT_DIR:-$HOME/.pi/agent}"
25
+ SETTINGS="$AGENT_DIR/settings.json"
26
+ mkdir -p "$AGENT_DIR"
27
+ PI_SETTINGS="$SETTINGS" EXT="$SOURCE/packages/workit-pi" bun -e '
28
+ import fs from "node:fs";
29
+ const path = process.env.PI_SETTINGS!;
30
+ const ext = process.env.EXT!;
31
+ const current = fs.existsSync(path) ? JSON.parse(fs.readFileSync(path, "utf8")) : {};
32
+ const packages = Array.isArray(current.packages) ? [...current.packages] : [];
33
+ const next = {
34
+ ...current,
35
+ packages: [...packages.filter((p) => !String(p).includes("workit")), ext],
36
+ };
37
+ fs.writeFileSync(path, JSON.stringify(next, null, 2) + "\n");
38
+ console.log("Registered Pi package:", ext);
39
+ '
40
+
41
+ mkdir -p "$(dirname "$PI_CONFIG")"
42
+ PI_CONFIG="$PI_CONFIG" EXT="$SOURCE/packages/workit-pi/dist/workit.js" SKILLS="$SOURCE/packages/workit-pi/skills" bun -e '
43
+ import fs from "node:fs";
44
+ const path = process.env.PI_CONFIG!;
45
+ const current = fs.existsSync(path) ? JSON.parse(fs.readFileSync(path, "utf8")) : {};
46
+ const next = {
47
+ ...current,
48
+ extensions: [process.env.EXT!],
49
+ skills: [process.env.SKILLS!],
50
+ };
51
+ fs.writeFileSync(path, JSON.stringify(next, null, 2) + "\n");
52
+ console.log("Registered Pi extension:", process.env.EXT);
53
+ '
54
+
55
+ echo "Pi package registered in $SETTINGS (and legacy $PI_CONFIG)"
56
+ echo "Complete an explicit v1 cutover before treating this as a generation switch."
@@ -9,12 +9,23 @@
9
9
  import { readFileSync, writeFileSync } from "node:fs";
10
10
  import { resolve } from "node:path";
11
11
 
12
- const root = process.argv[2] ? resolve(process.argv[2]) : resolve(import.meta.dir, "..", "..", "..");
12
+ const root = process.argv[2]
13
+ ? resolve(process.argv[2])
14
+ : resolve(import.meta.dir, "..", "..", "..");
13
15
  const core = JSON.parse(readFileSync(resolve(root, "packages/workit-core/package.json"), "utf8"));
14
16
  if (!core.version || typeof core.version !== "string") {
15
- throw new Error(`workit-core version missing in ${resolve(root, "packages/workit-core/package.json")}`);
17
+ throw new Error(
18
+ `workit-core version missing in ${resolve(root, "packages/workit-core/package.json")}`,
19
+ );
16
20
  }
17
- for (const pkg of ["workit-opencode", "workit-cursor", "workit-cli"]) {
21
+ for (const pkg of [
22
+ "workit-mcp",
23
+ "workit-cli",
24
+ "workit-opencode",
25
+ "workit-cursor",
26
+ "workit-codex",
27
+ "workit-pi",
28
+ ]) {
18
29
  const file = resolve(root, `packages/${pkg}/package.json`);
19
30
  const data = JSON.parse(readFileSync(file, "utf8"));
20
31
  const deps = data.dependencies;
@@ -28,10 +39,16 @@ for (const pkg of ["workit-opencode", "workit-cursor", "workit-cli"]) {
28
39
  // plugin manifest is versioned at release time.
29
40
  for (const file of [
30
41
  resolve(root, "packages/workit-cursor/.cursor-plugin/plugin.json"),
42
+ resolve(root, "packages/workit-codex/.codex-plugin/plugin.json"),
31
43
  ]) {
32
44
  const data = JSON.parse(readFileSync(file, "utf8"));
33
45
  data.version = core.version;
34
- if (data.homepage) data.homepage = data.homepage.replace("BrainerVirus/workflow-toolkit", "BrainerVirus/workit");
35
- if (data.repository) data.repository = data.repository.replace("BrainerVirus/workflow-toolkit", "BrainerVirus/workit");
46
+ if (data.homepage)
47
+ data.homepage = data.homepage.replace("BrainerVirus/workflow-toolkit", "BrainerVirus/workit");
48
+ if (data.repository)
49
+ data.repository = data.repository.replace(
50
+ "BrainerVirus/workflow-toolkit",
51
+ "BrainerVirus/workit",
52
+ );
36
53
  writeFileSync(file, `${JSON.stringify(data, null, 2)}\n`);
37
54
  }
@@ -9,14 +9,18 @@ import { execFileSync } from "node:child_process";
9
9
  import { readFileSync, writeFileSync } from "node:fs";
10
10
  import { resolve } from "node:path";
11
11
 
12
- export const SYNC_MANIFEST_PATHS = [
12
+ const SYNC_MANIFEST_PATHS = [
13
13
  "package.json",
14
14
  "packages/workit-core/package.json",
15
+ "packages/workit-mcp/package.json",
16
+ "packages/workit-cli/package.json",
15
17
  "packages/workit-opencode/package.json",
16
18
  "packages/workit-cursor/package.json",
17
- "packages/workit-cli/package.json",
19
+ "packages/workit-codex/package.json",
20
+ "packages/workit-pi/package.json",
18
21
  // Kept in lockstep with packages/workit-core/package.json by contract test.
19
22
  "packages/workit-cursor/.cursor-plugin/plugin.json",
23
+ "packages/workit-codex/.codex-plugin/plugin.json",
20
24
  ];
21
25
 
22
26
  export type ManifestSyncResult = { version: string; changed: string[] };
@@ -27,8 +31,7 @@ export type ManifestSyncResult = { version: string; changed: string[] };
27
31
  * are left byte-untouched and omitted from `changed`. Throws on a value that
28
32
  * is not a plain release version (`latest`, branches, ranges).
29
33
  */
30
- export function syncManifests(root: string, tagOrVersion: string): ManifestSyncResult {
31
- const match = /^v?(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)$/.exec(tagOrVersion.trim());
34
+ export function syncManifests(root: string, tagOrVersion: string): ManifestSyncResult { const match = /^v?(\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?)$/.exec(tagOrVersion.trim());
32
35
  if (!match) throw new Error(`invalid version tag: ${JSON.stringify(tagOrVersion)}`);
33
36
  const version = match[1];
34
37
  const changed: string[] = [];
@@ -44,7 +47,7 @@ export function syncManifests(root: string, tagOrVersion: string): ManifestSyncR
44
47
  }
45
48
 
46
49
  /** The newest `v*` tag by descending semver refname order (empty repo throws). */
47
- export function latestReleaseTag(cwd?: string): string {
50
+ function latestReleaseTag(cwd?: string): string {
48
51
  const out = execFileSync("git", ["tag", "--list", "v*", "--sort=-v:refname"], {
49
52
  cwd,
50
53
  encoding: "utf8",
@@ -69,7 +69,7 @@ else
69
69
  exit 1
70
70
  fi
71
71
 
72
- for DEP in @brainervirus/workit-core @modelcontextprotocol/sdk zod; do
72
+ for DEP in @brainervirus/workit-core @brainervirus/workit-mcp @modelcontextprotocol/sdk zod; do
73
73
  if [ ! -e "$SRC/node_modules/$DEP" ]; then
74
74
  if [ ! -f "$SRC/bun.lock" ]; then
75
75
  echo "FATAL: dependency install requires $SRC/bun.lock" >&2
@@ -83,11 +83,15 @@ for DEP in @brainervirus/workit-core @modelcontextprotocol/sdk zod; do
83
83
  fi
84
84
  done
85
85
 
86
+ if ! (cd "$SRC" && PATH="$(dirname "$BUN_BIN"):$PATH" "$BUN_BIN" "$SRC/packages/workit-mcp/scripts/build.ts"); then
87
+ echo "FATAL: shared MCP build failed in $SRC" >&2
88
+ exit 1
89
+ fi
86
90
  if ! (cd "$SRC" && PATH="$(dirname "$BUN_BIN"):$PATH" "$BUN_BIN" "$CURSOR_SRC/scripts/build.ts"); then
87
91
  echo "FATAL: Cursor adapter build failed in $CURSOR_SRC" >&2
88
92
  exit 1
89
93
  fi
90
- for ENTRY in mcp-server.js cursor-session-start.js; do
94
+ for ENTRY in mcp-server.js cursor-session-start.js workit-hook.js; do
91
95
  DIST_ENTRY="$CURSOR_SRC/dist/$ENTRY"
92
96
  if [ ! -f "$DIST_ENTRY" ] || [ ! -s "$DIST_ENTRY" ] || [ "$(IFS= read -r LINE <"$DIST_ENTRY"; printf '%s' "$LINE")" != '#!/usr/bin/env node' ]; then
93
97
  echo "FATAL: Cursor adapter invalid dist entry: $DIST_ENTRY" >&2
@@ -153,7 +157,7 @@ import fs from "node:fs";
153
157
  const path = process.env.PKG_PATH!;
154
158
  const data = JSON.parse(fs.readFileSync(path, "utf8"));
155
159
  data.dependencies = data.dependencies ?? {};
156
- data.dependencies["@opencode-ai/plugin"] = data.dependencies["@opencode-ai/plugin"] ?? "1.17.7";
160
+ data.dependencies["@opencode-ai/plugin"] = data.dependencies["@opencode-ai/plugin"] ?? "1.18.30";
157
161
  fs.writeFileSync(path, JSON.stringify(data, null, 2) + "\n");
158
162
  ' || true
159
163
  fi
@@ -20,20 +20,12 @@
20
20
  // `continual-learning` and `third_party/gmail` with no `../` prefix, even though
21
21
  // `.cursor-plugin/` is a sibling of those directories. Therefore
22
22
  // `source: "packages/workit-cursor"` is correct and kept verbatim.
23
- import {
24
- existsSync,
25
- mkdtempSync,
26
- readFileSync,
27
- readdirSync,
28
- rmSync,
29
- } from "node:fs";
30
- import os from "node:os";
23
+ import { existsSync, readFileSync, readdirSync } from "node:fs";
31
24
  import path from "node:path";
32
25
  import { fileURLToPath } from "node:url";
33
26
  import Ajv from "ajv";
34
27
  import addFormats from "ajv-formats";
35
- import { CANONICAL_SKILLS, validateSkillManifests } from "../src/core/skill-manifests";
36
- import { copySanitizedVendor } from "./vendor-assets";
28
+ import { WORKIT_METHOD_SKILLS, validateSkillManifests } from "../src/core/skill-manifests";
37
29
 
38
30
  const scriptDir = path.dirname(fileURLToPath(import.meta.url));
39
31
  const repoRoot = path.resolve(scriptDir, "..", "..", "..");
@@ -54,30 +46,6 @@ const frontmatterKeys = (file: string): Set<string> => {
54
46
  return keys;
55
47
  };
56
48
 
57
- const treesEqual = (a: string, b: string): string[] => {
58
- const diffs: string[] = [];
59
- // Thread the tree root so each file is keyed by its ROOT-relative path —
60
- // otherwise every `SKILL.md` collapses to one map entry and only the
61
- // last-read (readdir-order-dependent) skill is actually compared.
62
- const walk = (rootDir: string, dir: string, into: Map<string, string>): void => {
63
- for (const entry of readdirSync(dir, { withFileTypes: true })) {
64
- const p = path.join(dir, entry.name);
65
- if (entry.isDirectory()) walk(rootDir, p, into);
66
- else into.set(path.relative(rootDir, p).split(path.sep).join("/"), readFileSync(p, "utf8"));
67
- }
68
- };
69
- const left = new Map<string, string>();
70
- const right = new Map<string, string>();
71
- walk(a, a, left);
72
- walk(b, b, right);
73
- for (const [rel, content] of left) {
74
- if (!right.has(rel)) diffs.push(`missing in rebuilt: ${rel}`);
75
- else if (right.get(rel) !== content) diffs.push(`content drift: ${rel}`);
76
- }
77
- for (const rel of right.keys()) if (!left.has(rel)) diffs.push(`extra in rebuilt: ${rel}`);
78
- return diffs;
79
- };
80
-
81
49
  export const validateMarketplace = (rootArg: string): string[] => {
82
50
  const errors: string[] = [];
83
51
 
@@ -90,9 +58,7 @@ export const validateMarketplace = (rootArg: string): string[] => {
90
58
  const validate = new Ajv({ strict: true, allErrors: true });
91
59
  addFormats(validate);
92
60
  const schemaDir = path.join(rootArg, "test/fixtures/cursor-schemas");
93
- const pluginSchema = JSON.parse(
94
- readFileSync(path.join(schemaDir, "plugin.schema.json"), "utf8"),
95
- );
61
+ const pluginSchema = JSON.parse(readFileSync(path.join(schemaDir, "plugin.schema.json"), "utf8"));
96
62
  const marketSchema = JSON.parse(
97
63
  readFileSync(path.join(schemaDir, "marketplace.schema.json"), "utf8"),
98
64
  );
@@ -106,12 +72,13 @@ export const validateMarketplace = (rootArg: string): string[] => {
106
72
  // 2. Resolve each plugin source relative to the repo root; name must match.
107
73
  for (const entry of (market.plugins ?? []) as { name: string; source: string }[]) {
108
74
  const pluginDir = path.join(rootArg, entry.source);
109
- const manifestRel = path.join(entry.source, ".cursor-plugin/plugin.json");
110
75
  if (!existsSync(path.join(pluginDir, ".cursor-plugin/plugin.json"))) {
111
76
  errors.push(`plugin ${entry.name}: source ${entry.source} has no .cursor-plugin/plugin.json`);
112
77
  continue;
113
78
  }
114
- const plugin = JSON.parse(readFileSync(path.join(pluginDir, ".cursor-plugin/plugin.json"), "utf8"));
79
+ const plugin = JSON.parse(
80
+ readFileSync(path.join(pluginDir, ".cursor-plugin/plugin.json"), "utf8"),
81
+ );
115
82
  if (!validate.validate(pluginSchema, plugin)) {
116
83
  errors.push(
117
84
  `plugin ${entry.name} plugin.json invalid: ${(validate.errors ?? []).map((e) => e.message).join("; ")}`,
@@ -155,23 +122,25 @@ export const validateMarketplace = (rootArg: string): string[] => {
155
122
 
156
123
  // 5. Skills and rules carry valid frontmatter.
157
124
  const skillRoots: [string, readonly string[]][] = [
158
- [path.join(pluginDir, "skills"), CANONICAL_SKILLS.workit],
159
- [path.join(pluginDir, "vendor/superpowers/skills"), CANONICAL_SKILLS.superpowers],
125
+ [path.join(pluginDir, "skills"), WORKIT_METHOD_SKILLS],
160
126
  ];
161
127
  for (const [dir, expected] of skillRoots) {
162
128
  const mismatch = validateSkillManifests(dir, expected, "skills");
163
129
  if (mismatch) errors.push(`plugin ${entry.name}: ${mismatch}`);
164
130
  for (const skill of expected) {
165
131
  const keys = frontmatterKeys(path.join(dir, skill, "SKILL.md"));
166
- if (!keys.has("name")) errors.push(`plugin ${entry.name}: ${skill}/SKILL.md missing frontmatter name`);
167
- if (!keys.has("description")) errors.push(`plugin ${entry.name}: ${skill}/SKILL.md missing frontmatter description`);
132
+ if (!keys.has("name"))
133
+ errors.push(`plugin ${entry.name}: ${skill}/SKILL.md missing frontmatter name`);
134
+ if (!keys.has("description"))
135
+ errors.push(`plugin ${entry.name}: ${skill}/SKILL.md missing frontmatter description`);
168
136
  }
169
137
  }
170
138
  const rulesDir = path.join(pluginDir, "rules");
171
139
  if (existsSync(rulesDir)) {
172
140
  for (const rule of readdirSync(rulesDir).filter((f) => f.endsWith(".mdc"))) {
173
141
  const keys = frontmatterKeys(path.join(rulesDir, rule));
174
- if (!keys.has("description")) errors.push(`plugin ${entry.name}: ${rule} missing frontmatter description`);
142
+ if (!keys.has("description"))
143
+ errors.push(`plugin ${entry.name}: ${rule} missing frontmatter description`);
175
144
  }
176
145
  }
177
146
 
@@ -184,23 +153,6 @@ export const validateMarketplace = (rootArg: string): string[] => {
184
153
  errors.push(`plugin ${entry.name}: ${rel} references ignored runtime output`);
185
154
  }
186
155
  }
187
-
188
- // 7. Rebuilding the sanitized vendor tree yields no diff.
189
- const sourceVendor = path.join(rootArg, "packages/workit-core/vendor/superpowers/skills");
190
- const trackedVendor = path.join(pluginDir, "vendor/superpowers/skills");
191
- if (existsSync(sourceVendor) && existsSync(trackedVendor)) {
192
- const rebuilt = mkdtempSync(path.join(os.tmpdir(), "wk-vendor-rebuild-"));
193
- try {
194
- copySanitizedVendor(sourceVendor, rebuilt);
195
- for (const diff of treesEqual(rebuilt, trackedVendor)) {
196
- errors.push(`plugin ${entry.name}: vendor drift: ${diff}`);
197
- }
198
- } finally {
199
- rmSync(rebuilt, { recursive: true, force: true });
200
- }
201
- } else {
202
- errors.push(`plugin ${entry.name}: missing vendor source or tracked tree`);
203
- }
204
156
  }
205
157
 
206
158
  return errors;
@@ -210,7 +162,9 @@ if (import.meta.main) {
210
162
  const errors = validateMarketplace(root);
211
163
  if (errors.length > 0) {
212
164
  for (const e of errors) process.stderr.write(`${e}\n`);
213
- process.stderr.write(`marketplace validation FAILED (${errors.length} error${errors.length === 1 ? "" : "s"})\n`);
165
+ process.stderr.write(
166
+ `marketplace validation FAILED (${errors.length} error${errors.length === 1 ? "" : "s"})\n`,
167
+ );
214
168
  process.exit(1);
215
169
  }
216
170
  console.log(`marketplace validation passed (root: ${root})`);
@@ -0,0 +1,33 @@
1
+ ---
2
+ name: workit-babysit
3
+ description: Use when a PR needs driving to merge-ready, CI is red, or the user says babysit
4
+ ---
5
+
6
+ # Babysit a PR to merge-ready
7
+
8
+ Babysit starts automatically on PR creation unless declined (`--no-babysit`).
9
+ One babysitter per PR; never mutate PR topology (no rebase strategy changes,
10
+ no force-push).
11
+
12
+ ## Before method work
13
+
14
+ If there is no active or paused task, run shared `task.start` then `policy.assess`
15
+ before relying on selected policy rules or other product mutations. Assessment
16
+ selects requirements; do not wait for a rule that can only exist after assess.
17
+
18
+ ## Method
19
+
20
+ 1. Declare mode: drive (fix + merge), watch (report only), or threads-only.
21
+ 2. Work the merge frontier in order: conflicts → review threads → CI.
22
+ 3. Classify CI before retry: flake (rerun once) vs stale base (verify with
23
+ `git merge-base --is-ancestor` before updating) vs real failure (fix).
24
+ 4. Triage bot findings skeptically: reproduce or quote code before acting;
25
+ invalid bots get a reasoned dismissal, never silent ignore.
26
+ 5. Batch fixes into one push wave; re-verify green after every push.
27
+ 6. Merge only when green and approved, honoring `pr` settings (squash +
28
+ delete branch). Stop at the human's line: never merge on explicit hold.
29
+
30
+ ## Completion
31
+
32
+ PR merged per settings, or a status brief (frontier state, next action) when
33
+ blocked on the human. Record evidence for fixes, findings for blockers.
@@ -0,0 +1,53 @@
1
+ ---
2
+ name: workit-behavioral-tdd
3
+ description: Use when policy identifies behavior, side effects, permissions, or data handling that may change and a regression boundary is needed
4
+ ---
5
+
6
+ # Behavioral TDD
7
+
8
+ Test the observable behavior at a stable boundary, not the implementation shape.
9
+ Use this method when assessment selects the `testing` dimension.
10
+
11
+ ## Before method work
12
+
13
+ If there is no active or paused task, run shared `task.start` then `policy.assess`
14
+ before relying on selected policy rules or other product mutations. Assessment
15
+ selects requirements; do not wait for a rule that can only exist after assess.
16
+
17
+ ## Method
18
+
19
+ 1. Inspect the task requirement, current candidate, intended behavior, and real
20
+ verification entry point with shared `task`, `policy`, and `evidence` operations.
21
+ 2. State one behavior and its observable result. Choose the narrowest stable
22
+ boundary a caller or user depends on; avoid private helpers and incidental
23
+ representations.
24
+ 3. Write one vertical RED slice that fails for the missing behavior, run it, and
25
+ preserve the actual failure as evidence. Implement the smallest change, then
26
+ run the same slice GREEN and record its result. Close enforces the order: a
27
+ testing requirement with GREEN but no preceding RED evidence stays unsatisfied.
28
+ 4. Add only another slice for a distinct behavior or risk. Reconcile stale
29
+ evidence if the candidate changes.
30
+
31
+ ## Reject noisy tests
32
+
33
+ - A dependency/version-pin assertion is not behavioral evidence.
34
+ - A test that mirrors branches, private calls, or exact implementation structure
35
+ is coupled to internals; replace it with the public effect.
36
+ - Duplicate assertions and tests that add no distinct failure signal are noise;
37
+ delete them.
38
+ - Do not claim a passing test satisfies a different requirement.
39
+ - Banned: tautologies (asserts what the code says, not what it must do),
40
+ ghost loops (assert inside a possibly-empty loop), smoke-only renders,
41
+ type-only or CSS-class coupling. If the test still passes when every
42
+ imported function returns undefined, rewrite the assertion or delete it.
43
+
44
+ Use shared `evidence` operations for RED/GREEN results. Do not add a second
45
+ lifecycle, approval chain, or test workflow outside the current task state.
46
+
47
+ ## Common mistakes
48
+
49
+ | Mistake | Correction |
50
+ | --- | --- |
51
+ | "The pin changed, so assert the new string" | Exercise the affected consumer behavior. |
52
+ | "The code is obvious" | A small vertical slice still proves the contract. |
53
+ | Keeping a passing test after the boundary moved | Mark it stale and retest the current candidate. |
@@ -0,0 +1,31 @@
1
+ ---
2
+ name: workit-blast-radius
3
+ description: Use when a small-looking change could break something else, before close or merge
4
+ ---
5
+
6
+ # Blast radius beyond the diff
7
+
8
+ A small diff is not a small risk. Prove the one fact it is safe because of,
9
+ with runnable proof — not assertion.
10
+
11
+ ## Before method work
12
+
13
+ If there is no active or paused task, run shared `task.start` then `policy.assess`
14
+ before relying on selected policy rules or other product mutations. Assessment
15
+ selects requirements; do not wait for a rule that can only exist after assess.
16
+
17
+ ## Method
18
+
19
+ 1. List what the change touches: callers, shared state, contracts, config,
20
+ migrations. Grep every caller of each touched function.
21
+ 2. For each: state the one fact it is safe because of (type boundary,
22
+ existing test, unreachable path) plus how to run the proof.
23
+ 3. Run the proofs. Unproven claims stay labeled UNPROVEN in findings —
24
+ never silently treated as safe.
25
+ 4. Fix at the shared root (one guard where all callers route through),
26
+ not per caller.
27
+
28
+ ## Completion
29
+
30
+ Blast-radius note in evidence or review: each risk with fact + proof
31
+ command, or an UNPROVEN finding for what could not be proven.
@@ -0,0 +1,62 @@
1
+ ---
2
+ name: workit-challenge
3
+ description: Use when a proposal is ambiguous, consequential, disputed, or may hide assumptions, coupling, failure modes, or a simpler solution
4
+ ---
5
+
6
+ # Challenge a proposal with a grounded grill
7
+
8
+ Treat the proposal as a hypothesis. Facts are the agent's job; decisions are
9
+ the user's. Use this method when assessment selects the `challenge` or
10
+ `decisions` dimension.
11
+
12
+ ## Before method work
13
+
14
+ If there is no active or paused task, run shared `task.start` then `policy.assess`
15
+ before relying on selected policy rules or other product mutations. Assessment
16
+ selects requirements; do not wait for a rule that can only exist after assess.
17
+
18
+ ## Method
19
+
20
+ 1. Ground first: inspect the task, policy, candidate, evidence, decisions, and
21
+ the repo docs that exist. Never ask what code or docs can answer.
22
+ 2. Diverge once, bounded: when the approach is unknown, offer 3-5 candidate
23
+ directions with evidence and tradeoffs in one advisory burst, without
24
+ critique. Record the burst as artifact evidence when it matters; the user
25
+ steers or mixes.
26
+ 3. Grill one question at a time: each question carries your recommended answer,
27
+ the facts behind it, and at least one rejected alternative. Resolve
28
+ dependency order and recompute after every answer — a wall of questions is
29
+ not an interview.
30
+ 4. Funnel every resolution: the moment a consequential choice settles, bind it
31
+ with a receipt-shaped question (header `Workit decision: <purpose>`, exactly
32
+ `approved`/`rejected`, the approved description carrying the exact content).
33
+ If the user already stated the choice in conversation and no receipt can be
34
+ minted, record it in task progress and reassess so the settled requirement
35
+ retires — never re-ask to mint a receipt, and never leave it for close to
36
+ demand.
37
+ 5. Durability: write or refresh the spec under `docs/<slug>/` only when the
38
+ `durable-spec` requirement fires. No glossary, no second lifecycle.
39
+ 6. Counter-case: each material recommendation carries one strongest
40
+ counter-case (hidden assumption, failure mode, coupling, simpler
41
+ alternative). Stop when a counter-case adds no new constraint.
42
+
43
+ Stop at an empty frontier or three rounds; the cap is the bound. Say directly
44
+ when the proposal is weak, overcomplicated, or solves the wrong problem.
45
+
46
+ ## Guardrails
47
+
48
+ - Do not create a universal spec, plan, approval chain, or second lifecycle.
49
+ - Unknowns that affect the dependent action remain unresolved until evidence or a
50
+ user decision closes them.
51
+ - Use the shared operations for state and provenance; never write task metadata
52
+ directly.
53
+ - An in-session counter-case is never fresh-context review; claim only what it is.
54
+
55
+ ## Common mistakes
56
+
57
+ | Mistake | Correction |
58
+ | --- | --- |
59
+ | Asking what the code or docs already answer | Ground first; the user owns choices, not lookups. |
60
+ | Listing every hypothetical objection | One strongest counter-case, then stop. |
61
+ | Asking "what do you think?" without a recommendation | Recommend an option and explain the tradeoff. |
62
+ | Leaving a settled choice for close to confirm | Funnel it when it resolves; progress plus reassessment if no receipt. |