ultra-builder-pro-cli 0.25.1 → 0.26.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 (241) hide show
  1. package/.ultra-template/contexts/TEMPLATE.md +87 -0
  2. package/.ultra-template/decisions/.gitkeep +1 -0
  3. package/.ultra-template/evidence/.gitkeep +1 -0
  4. package/.ultra-template/north-star.md +46 -0
  5. package/.ultra-template/research/.gitkeep +1 -0
  6. package/.ultra-template/specs/discovery.md +2 -2
  7. package/.ultra-template/tasks.json +3 -0
  8. package/.ultra-template/test-report.json +27 -0
  9. package/CHANGELOG.md +40 -0
  10. package/README.md +217 -579
  11. package/adapters/_shared/delegate-profiles/kimi-read-only.md +15 -0
  12. package/adapters/_shared/delegate-profiles/kimi-write.md +17 -0
  13. package/adapters/_shared/file-ops.cjs +76 -2
  14. package/adapters/_shared/host-profile.cjs +97 -0
  15. package/adapters/_shared/plugin-core.cjs +204 -0
  16. package/adapters/_shared/runtime-assets.cjs +31 -96
  17. package/adapters/claude.js +92 -291
  18. package/adapters/codex.js +309 -842
  19. package/adapters/grok.js +143 -1469
  20. package/adapters/kimi.js +124 -1053
  21. package/adapters/opencode.js +230 -742
  22. package/bin/delegate-worker.cjs +323 -0
  23. package/bin/delegate.cjs +456 -0
  24. package/bin/install.js +38 -11
  25. package/docs/ARCHITECTURE.md +122 -216
  26. package/docs/ARTIFACT-AUTHORITY.md +90 -268
  27. package/docs/DECISIONS.md +75 -87
  28. package/docs/PHILOSOPHY.md +177 -0
  29. package/docs/PLUGIN-ISOLATION-CONTRACT.md +62 -39
  30. package/docs/RUNTIME-COMPAT-MATRIX.md +99 -156
  31. package/docs/SKILL-AUTHORING.md +94 -73
  32. package/docs/WORKFLOW-LIFECYCLE.md +93 -189
  33. package/hooks/README.md +17 -37
  34. package/hooks/_common.py +113 -0
  35. package/hooks/adapters/codex.py +9 -16
  36. package/hooks/adapters/grok.py +5 -5
  37. package/hooks/adapters/kimi.py +8 -14
  38. package/hooks/block_dangerous_commands.py +95 -0
  39. package/hooks/compact_context.py +65 -0
  40. package/hooks/mid_workflow_recall.py +25 -0
  41. package/hooks/post_edit_guard.py +105 -0
  42. package/hooks/session_context.py +30 -0
  43. package/package.json +17 -52
  44. package/skills/ultra-change/SKILL.md +97 -50
  45. package/skills/ultra-change/references/change-contract.md +40 -1
  46. package/skills/ultra-delegate/SKILL.md +82 -0
  47. package/skills/ultra-delegate/references/delegation-contract.md +51 -0
  48. package/skills/ultra-delegate/scripts/delegate_wait.py +86 -0
  49. package/skills/ultra-deliver/SKILL.md +61 -42
  50. package/skills/ultra-deliver/references/baseline-reconciliation.md +39 -20
  51. package/skills/ultra-dev/SKILL.md +96 -62
  52. package/skills/ultra-dev/references/debugging.md +22 -0
  53. package/skills/ultra-domain-modeling/SKILL.md +79 -0
  54. package/skills/ultra-grilling/SKILL.md +79 -0
  55. package/skills/ultra-init/SKILL.md +94 -37
  56. package/skills/ultra-init/references/brownfield-adoption.md +33 -83
  57. package/skills/ultra-init/scripts/init_project.cjs +84 -0
  58. package/skills/ultra-plan/SKILL.md +88 -68
  59. package/skills/ultra-research/SKILL.md +62 -48
  60. package/skills/ultra-research/references/00-problem-validation.md +5 -5
  61. package/skills/ultra-research/references/01-opportunity-discovery.md +3 -3
  62. package/skills/ultra-research/references/02-market-assessment.md +5 -4
  63. package/skills/ultra-research/references/03-competitive-landscape.md +3 -3
  64. package/skills/ultra-research/references/04-product-strategy.md +3 -3
  65. package/skills/ultra-research/references/05-assumptions-validation.md +5 -5
  66. package/skills/ultra-research/references/10-user-personas.md +3 -2
  67. package/skills/ultra-research/references/11-user-scenarios.md +3 -3
  68. package/skills/ultra-research/references/20-user-stories.md +4 -3
  69. package/skills/ultra-research/references/21-features-scope.md +3 -2
  70. package/skills/ultra-research/references/22-success-metrics.md +3 -3
  71. package/skills/ultra-research/references/30-architecture-context.md +3 -3
  72. package/skills/ultra-research/references/31-solution-strategy.md +3 -3
  73. package/skills/ultra-research/references/32-building-blocks.md +3 -3
  74. package/skills/ultra-research/references/40-deployment.md +3 -3
  75. package/skills/ultra-research/references/41-quality-risks.md +3 -3
  76. package/skills/ultra-research/references/99-synthesis.md +7 -7
  77. package/skills/ultra-review/SKILL.md +59 -32
  78. package/skills/ultra-review/references/code.md +17 -0
  79. package/skills/ultra-review/references/comments.md +12 -0
  80. package/skills/ultra-review/references/design.md +12 -0
  81. package/skills/ultra-review/references/errors.md +13 -0
  82. package/skills/ultra-review/references/spec.md +13 -0
  83. package/skills/ultra-review/references/tests.md +12 -0
  84. package/skills/ultra-review/references/worker-packet.md +40 -0
  85. package/skills/ultra-review/scripts/review_wait.py +26 -15
  86. package/skills/ultra-status/SKILL.md +61 -36
  87. package/skills/ultra-tdd/SKILL.md +81 -0
  88. package/skills/ultra-tdd/references/templates/README.md +20 -0
  89. package/skills/ultra-tdd/references/templates/feature-flag-default-audit.sh +79 -0
  90. package/skills/ultra-tdd/references/templates/persistence-real.ts +78 -0
  91. package/skills/ultra-tdd/references/templates/testcontainer-postgres.py +78 -0
  92. package/skills/ultra-tdd/references/templates/testcontainer-postgres.ts +73 -0
  93. package/skills/ultra-tdd/references/templates/vertical-slice.ts +66 -0
  94. package/skills/ultra-tdd/references/test-execution.md +18 -0
  95. package/skills/ultra-test/SKILL.md +70 -30
  96. package/skills/ultra-test/references/export-syntax.md +18 -0
  97. package/skills/ultra-test/scripts/worktree_digest.cjs +54 -0
  98. package/skills/ultra-think/SKILL.md +49 -27
  99. package/skills/ultra-think/references/autonomy-boundary.md +48 -0
  100. package/skills/ultra-think/references/interaction-boundary.md +18 -33
  101. package/.ultra-template/docs/research/README.md +0 -55
  102. package/.ultra-template/reports/templates/delivery-report.json +0 -17
  103. package/.ultra-template/reports/templates/test-report.json +0 -18
  104. package/.ultra-template/tasks/tasks.json +0 -15
  105. package/.ultra-template/templates/task-context.md +0 -19
  106. package/adapters/_shared/codex-assets.cjs +0 -725
  107. package/adapters/_shared/codex-ultra-tools-entry.cjs +0 -11
  108. package/adapters/_shared/interaction-contract.cjs +0 -129
  109. package/adapters/_shared/path-rewrite.cjs +0 -79
  110. package/adapters/_shared/runtime-native.cjs +0 -132
  111. package/adapters/_shared/settings-merge.cjs +0 -76
  112. package/agents/code-reviewer.md +0 -42
  113. package/agents/debugger.md +0 -40
  114. package/agents/review-code.md +0 -49
  115. package/agents/review-comments.md +0 -38
  116. package/agents/review-coordinator.md +0 -56
  117. package/agents/review-design.md +0 -40
  118. package/agents/review-errors.md +0 -43
  119. package/agents/review-spec.md +0 -39
  120. package/agents/review-tests.md +0 -40
  121. package/agents/tdd-runner.md +0 -38
  122. package/bin/orchestrator.js +0 -383
  123. package/commands/ultra-change.md +0 -10
  124. package/commands/ultra-deliver.md +0 -10
  125. package/commands/ultra-dev.md +0 -10
  126. package/commands/ultra-doctor.md +0 -10
  127. package/commands/ultra-init.md +0 -10
  128. package/commands/ultra-plan.md +0 -10
  129. package/commands/ultra-research.md +0 -10
  130. package/commands/ultra-review.md +0 -10
  131. package/commands/ultra-status.md +0 -10
  132. package/commands/ultra-test.md +0 -10
  133. package/commands/ultra-think.md +0 -10
  134. package/docs/AGENT-CONTEXT.md +0 -191
  135. package/docs/COMMIT-HASH-BACKFILL.md +0 -51
  136. package/docs/LEGACY-CLI-CROSSWALK.md +0 -175
  137. package/docs/ROADMAP.md +0 -101
  138. package/docs/STATE-DB-ACCESS-POLICY.md +0 -161
  139. package/hooks/active_task_context.py +0 -152
  140. package/hooks/context_envelope.py +0 -100
  141. package/hooks/health_check.py +0 -196
  142. package/hooks/pre_stop_check.py +0 -66
  143. package/hooks/runtime_paths.py +0 -396
  144. package/hooks/subagent_tracker.py +0 -88
  145. package/hooks/workflow_checkpoint.py +0 -76
  146. package/hooks/workflow_context.py +0 -48
  147. package/hooks/workflow_resume.py +0 -84
  148. package/mcp-server/hook-context.cjs +0 -38
  149. package/mcp-server/hook-event.cjs +0 -34
  150. package/mcp-server/lib/archive-journal.cjs +0 -1119
  151. package/mcp-server/lib/archive-mutation-worker.py +0 -365
  152. package/mcp-server/lib/artifact-registry.cjs +0 -1232
  153. package/mcp-server/lib/baseline-workflow.cjs +0 -1193
  154. package/mcp-server/lib/canonical-json.cjs +0 -19
  155. package/mcp-server/lib/change-authority.cjs +0 -26
  156. package/mcp-server/lib/change-packet.cjs +0 -790
  157. package/mcp-server/lib/change-workflow.cjs +0 -65
  158. package/mcp-server/lib/context-envelope.cjs +0 -581
  159. package/mcp-server/lib/context-paths.cjs +0 -142
  160. package/mcp-server/lib/decision-records.cjs +0 -423
  161. package/mcp-server/lib/delivery-transaction.cjs +0 -471
  162. package/mcp-server/lib/doctor-backup-worker.cjs +0 -328
  163. package/mcp-server/lib/doctor.cjs +0 -627
  164. package/mcp-server/lib/git-bootstrap.cjs +0 -651
  165. package/mcp-server/lib/init-project.cjs +0 -1021
  166. package/mcp-server/lib/kernel-change-workflow.cjs +0 -2029
  167. package/mcp-server/lib/legacy-change-workflow.cjs +0 -3032
  168. package/mcp-server/lib/managed-file-write.cjs +0 -172
  169. package/mcp-server/lib/plan-checkpoint.cjs +0 -177
  170. package/mcp-server/lib/plan-publication-worker.cjs +0 -830
  171. package/mcp-server/lib/plan-store.cjs +0 -794
  172. package/mcp-server/lib/prd-parser.cjs +0 -83
  173. package/mcp-server/lib/pricing.cjs +0 -44
  174. package/mcp-server/lib/project-context.cjs +0 -178
  175. package/mcp-server/lib/projector.cjs +0 -386
  176. package/mcp-server/lib/provider-refs.cjs +0 -42
  177. package/mcp-server/lib/runtime-paths.cjs +0 -1714
  178. package/mcp-server/lib/runtime-state.cjs +0 -222
  179. package/mcp-server/lib/safe-project-file.cjs +0 -385
  180. package/mcp-server/lib/stage-checkpoints.cjs +0 -463
  181. package/mcp-server/lib/state-authority.cjs +0 -95
  182. package/mcp-server/lib/state-db.cjs +0 -1580
  183. package/mcp-server/lib/state-ops.cjs +0 -1428
  184. package/mcp-server/lib/task-contract.cjs +0 -404
  185. package/mcp-server/lib/task-expander.cjs +0 -105
  186. package/mcp-server/lib/task-ledger.cjs +0 -1964
  187. package/mcp-server/lib/telemetry.cjs +0 -85
  188. package/mcp-server/lib/topo.cjs +0 -131
  189. package/mcp-server/lib/ultra-facade.cjs +0 -2684
  190. package/mcp-server/lib/worker-packet.cjs +0 -358
  191. package/mcp-server/server.cjs +0 -437
  192. package/orchestrator/auto-merge.cjs +0 -128
  193. package/orchestrator/daemon.cjs +0 -264
  194. package/orchestrator/dispatch-rules.cjs +0 -78
  195. package/orchestrator/parallel-orchestrator.cjs +0 -903
  196. package/orchestrator/planner/plan-builder.cjs +0 -125
  197. package/orchestrator/recovery.cjs +0 -188
  198. package/orchestrator/session-close-journal-worker.cjs +0 -5
  199. package/orchestrator/session-close-journal.cjs +0 -1014
  200. package/orchestrator/session-runner.cjs +0 -1153
  201. package/orchestrator/worktree-manager.cjs +0 -282
  202. package/settings.json +0 -7
  203. package/skills/cc-collab/SKILL.md +0 -42
  204. package/skills/code-review-expert/SKILL.md +0 -43
  205. package/skills/code-review-expert/references/correctness-reliability.md +0 -30
  206. package/skills/code-review-expert/references/design-boundaries.md +0 -26
  207. package/skills/code-review-expert/references/removal-plan.md +0 -24
  208. package/skills/codex-collab/SKILL.md +0 -49
  209. package/skills/codex-collab/evals/evals.json +0 -35
  210. package/skills/integration-rules/SKILL.md +0 -32
  211. package/skills/security-rules/SKILL.md +0 -38
  212. package/skills/testing-rules/SKILL.md +0 -32
  213. package/skills/ultra-doctor/SKILL.md +0 -41
  214. package/skills/ultra-plan/references/semantic-preflight.md +0 -20
  215. package/skills/ultra-verify/SKILL.md +0 -46
  216. package/skills/ultra-verify/evals/evals.json +0 -46
  217. package/skills/ultra-verify/references/cross-verify-modes.md +0 -28
  218. package/skills/ultra-verify/references/evidence-status.md +0 -21
  219. package/skills/ultra-verify/scripts/verify_wait.py +0 -94
  220. package/spec/cli-protocol.md +0 -102
  221. package/spec/mcp-tools.yaml +0 -312
  222. package/spec/schemas/baseline-reconciliation.v1.schema.json +0 -73
  223. package/spec/schemas/change-delta.v1.schema.json +0 -153
  224. package/spec/schemas/command-manifest.schema.json +0 -29
  225. package/spec/schemas/context-file.v4.5.schema.json +0 -54
  226. package/spec/schemas/delivery-report.v1.schema.json +0 -66
  227. package/spec/schemas/documentation-reconciliation.v1.schema.json +0 -106
  228. package/spec/schemas/mcp-tools.schema.json +0 -136
  229. package/spec/schemas/skill-manifest.schema.json +0 -24
  230. package/spec/schemas/state-db.sql +0 -641
  231. package/spec/schemas/task-ledger.v2.schema.json +0 -296
  232. package/spec/schemas/tasks.v4.5.schema.json +0 -96
  233. package/spec/schemas/test-report.v1.schema.json +0 -225
  234. package/ultra-tools/cli.cjs +0 -129
  235. package/ultra-tools/commands/db.cjs +0 -226
  236. package/ultra-tools/commands/legacy-memory.cjs +0 -159
  237. package/ultra-tools/commands/migrate.cjs +0 -1386
  238. package/ultra-tools/commands/session.cjs +0 -213
  239. package/ultra-tools/commands/status.cjs +0 -559
  240. package/ultra-tools/commands/system.cjs +0 -498
  241. package/ultra-tools/commands/task.cjs +0 -105
@@ -1,44 +1,32 @@
1
1
  'use strict';
2
2
 
3
- /** Build a Claude Code native Ultra Builder Pro plugin. */
4
-
5
3
  const fs = require('node:fs');
6
4
  const os = require('node:os');
7
5
  const path = require('node:path');
8
6
  const { spawnSync } = require('node:child_process');
9
7
 
10
8
  const {
11
- copyTree,
12
- ensureDir,
13
- isManaged,
9
+ copyHooks,
10
+ copySkills,
11
+ inspectPlugin,
14
12
  markManaged,
13
+ publishManagedTrees,
14
+ removeManaged,
15
+ writePluginProvenance,
16
+ } = require('./_shared/plugin-core.cjs');
17
+ const {
18
+ captureAbsent,
19
+ ensureDir,
20
+ managedMetadata,
21
+ pruneCreatedEmpty,
15
22
  removeTree,
16
23
  writeAtomic,
17
24
  } = require('./_shared/file-ops.cjs');
18
- const {
19
- applyNativeDoctor,
20
- buildMcpRuntime,
21
- mcpCommand,
22
- } = require('./_shared/codex-assets.cjs');
23
- const { parse: parseFrontmatter, serialize: serializeFrontmatter } = require('./_shared/frontmatter.cjs');
24
- const { adaptInteractionGuidance } = require('./_shared/interaction-contract.cjs');
25
- const provenance = require('./_shared/provenance.cjs');
26
- const {
27
- CORE_PUBLIC_SKILLS,
28
- WORKFLOW_HOOK_FILES,
29
- skillPolicy,
30
- skillsForRuntime,
31
- } = require('./_shared/runtime-assets.cjs');
32
25
 
33
26
  const PLUGIN_NAME = 'ultra-builder-pro';
34
- const MCP_SERVER_NAME = PLUGIN_NAME;
35
- const SOURCE_TAG = 'ubp';
36
- const SENTINEL_KEY = '_ubp_manifest';
37
- const COMMAND_NAMES = CORE_PUBLIC_SKILLS;
38
- const PROVENANCE_FILE = 'provenance.json';
39
27
 
40
28
  function resolveTarget(ctx = {}) {
41
- if (ctx.configDir) return ctx.configDir;
29
+ if (ctx.configDir) return path.resolve(ctx.configDir);
42
30
  if (ctx.scope === 'global') {
43
31
  return process.env.CLAUDE_CONFIG_DIR || path.join(ctx.homeDir || os.homedir(), '.claude');
44
32
  }
@@ -46,332 +34,145 @@ function resolveTarget(ctx = {}) {
46
34
  }
47
35
 
48
36
  function resolvePluginRoot(ctx = {}) {
49
- if (ctx.pluginRoot) return ctx.pluginRoot;
50
- return path.join(resolveTarget(ctx), 'skills', PLUGIN_NAME);
37
+ return ctx.pluginRoot || path.join(resolveTarget(ctx), 'skills', PLUGIN_NAME);
51
38
  }
52
39
 
53
40
  function resolveRepoRoot(ctx = {}) {
54
41
  return ctx.repoRoot || path.resolve(__dirname, '..');
55
42
  }
56
43
 
57
- function shouldRunHostCli(ctx = {}) {
58
- if (typeof ctx.runHostCli === 'boolean') return ctx.runHostCli;
59
- return ctx.scope === 'global' && !ctx.configDir;
60
- }
61
-
62
- function runClaudeCli(args, ctx = {}) {
63
- const result = spawnSync(ctx.claudeBin || 'claude', args, {
64
- encoding: 'utf8',
65
- timeout: ctx.hostCliTimeoutMs || 30000,
66
- killSignal: 'SIGKILL',
67
- stdio: ['ignore', 'pipe', 'pipe'],
68
- env: {
69
- ...process.env,
70
- CLAUDE_CONFIG_DIR: resolveTarget(ctx),
71
- },
72
- });
73
- if (result.error) {
74
- if (result.error.code === 'ETIMEDOUT') {
75
- const error = new Error(`claude ${args.join(' ')} timed out`);
76
- error.code = 'HOST_CLI_TIMEOUT';
77
- throw error;
78
- }
79
- throw result.error;
80
- }
81
- if (result.status !== 0) {
82
- const detail = (result.stderr || result.stdout || '').trim();
83
- throw new Error(`claude ${args.join(' ')} failed${detail ? `: ${detail}` : ''}`);
84
- }
85
- return result.stdout;
86
- }
87
-
88
- function claudeMcpRow(output, identity) {
89
- for (const rawLine of output.split(/\r?\n/)) {
90
- const line = rawLine.trim();
91
- if (line.slice(0, identity.length) !== identity) continue;
92
- if (line[identity.length] !== ':') continue;
93
- return line;
94
- }
95
- return '';
96
- }
97
-
98
- function inspectClaudeHost(ctx = {}) {
99
- const target = resolvePluginRoot(ctx);
100
- const manifest = JSON.parse(
101
- fs.readFileSync(path.join(target, '.claude-plugin', 'plugin.json'), 'utf8'),
102
- );
103
- const plugins = JSON.parse(runClaudeCli(['plugin', 'list', '--json'], ctx));
104
- if (!Array.isArray(plugins)) throw new Error('claude plugin list --json did not return an array');
105
- const plugin = plugins.find((entry) => entry?.id === `${PLUGIN_NAME}@skills-dir`);
106
- const pluginOk = !!plugin
107
- && plugin.enabled === true
108
- && plugin.version === manifest.version
109
- && path.resolve(plugin.installPath || '') === path.resolve(target);
110
- const mcpOutput = pluginOk
111
- ? runClaudeCli(['mcp', 'list'], ctx).replace(/\u001b\[[0-9;]*m/g, '')
112
- : '';
113
- const mcpLine = claudeMcpRow(
114
- mcpOutput,
115
- `plugin:${PLUGIN_NAME}:${MCP_SERVER_NAME}`,
116
- );
117
- const mcpOk = pluginOk
118
- && !!plugin.mcpServers?.[MCP_SERVER_NAME]
119
- && /\bConnected\b/i.test(mcpLine);
120
- let detailsOk = false;
121
- if (pluginOk) {
122
- runClaudeCli(['plugin', 'details', `${PLUGIN_NAME}@skills-dir`], ctx);
123
- detailsOk = true;
124
- }
125
- return { plugin, pluginOk, mcpOk, mcpOutput, detailsOk };
126
- }
127
-
128
- function copySkills(repoRoot, target, names) {
129
- const copied = [];
130
- for (const name of names) {
131
- const source = path.join(repoRoot, 'skills', name);
132
- if (!fs.existsSync(source)) throw new Error(`missing allowlisted Claude skill: ${name}`);
133
- const files = copyTree(source, path.join(target, 'skills', name), {
134
- transform(buf, rel) {
135
- if (rel !== 'SKILL.md') {
136
- return rel.endsWith('.md')
137
- ? Buffer.from(adaptInteractionGuidance(buf.toString('utf8'), 'claude'))
138
- : buf;
139
- }
140
- const { fm, body } = parseFrontmatter(buf.toString('utf8'));
141
- if (!fm) throw new Error(`missing frontmatter in Claude skill: ${name}`);
142
- let adaptedBody = adaptInteractionGuidance(body, 'claude');
143
- if (name === 'ultra-review') {
144
- adaptedBody = adaptedBody.replace(
145
- /(?:the current host's native|the host-native) bounded-worker\s+mechanism/g,
146
- 'Claude Code Task workers using the installed review agent definitions',
147
- );
148
- }
149
- const policy = skillPolicy(name);
150
- return Buffer.from(serializeFrontmatter({
151
- name,
152
- description: fm.description,
153
- 'user-invocable': policy.userInvocable,
154
- ...(policy.userInvocable ? { 'disable-model-invocation': true } : {}),
155
- }, adaptedBody));
156
- },
157
- });
158
- copied.push(...files.map((rel) => path.join(name, rel)));
159
- }
160
- return copied;
161
- }
162
-
163
- function copyCommands(repoRoot, target) {
164
- const commandRoot = path.join(target, 'commands');
165
- ensureDir(commandRoot);
166
- const copied = [];
167
- for (const name of COMMAND_NAMES) {
168
- const file = `${name}.md`;
169
- const source = path.join(repoRoot, 'commands', file);
170
- if (!fs.existsSync(source)) throw new Error(`missing allowlisted Claude command: ${file}`);
171
- fs.copyFileSync(source, path.join(commandRoot, file));
172
- copied.push(file);
173
- }
174
- return copied;
175
- }
176
-
177
- function hookCommand(name, ...args) {
44
+ function hookCommand(name) {
178
45
  return {
179
46
  type: 'command',
180
- command: [
181
- `python3 "\${CLAUDE_PLUGIN_ROOT}/hooks/${name}"`,
182
- ...args.map((arg) => JSON.stringify(arg)),
183
- ].join(' '),
47
+ command: `python3 "\${CLAUDE_PLUGIN_ROOT}/hooks/${name}"`,
184
48
  timeout: 10,
185
49
  };
186
50
  }
187
51
 
188
52
  function buildHooksManifest() {
189
53
  return {
190
- description: 'Ultra workflow lifecycle hooks; inactive outside projects with an active .ultra workflow.',
54
+ description: 'Ultra file-first context sensors and narrow effect protection.',
191
55
  hooks: {
192
56
  SessionStart: [
193
- {
194
- matcher: 'startup|resume|clear',
195
- hooks: [hookCommand('health_check.py'), hookCommand('workflow_context.py')],
196
- },
197
- { matcher: 'compact', hooks: [hookCommand('workflow_resume.py')] },
57
+ { matcher: 'startup|resume|clear', hooks: [hookCommand('session_context.py')] },
58
+ { matcher: 'compact', hooks: [hookCommand('compact_context.py')] },
198
59
  ],
199
60
  PreToolUse: [
200
- { matcher: 'Edit|Write', hooks: [hookCommand('active_task_context.py')] },
201
- ],
202
- PreCompact: [
203
- { hooks: [hookCommand('workflow_checkpoint.py')] },
61
+ { matcher: 'Write|Edit|Grep', hooks: [hookCommand('mid_workflow_recall.py')] },
62
+ { matcher: 'Bash', hooks: [hookCommand('block_dangerous_commands.py')] },
204
63
  ],
205
- Stop: [
206
- { hooks: [hookCommand('pre_stop_check.py')] },
207
- ],
208
- SubagentStart: [
209
- { hooks: [hookCommand('subagent_tracker.py', 'start')] },
210
- ],
211
- SubagentStop: [
212
- { hooks: [hookCommand('subagent_tracker.py', 'stop')] },
64
+ PostToolUse: [
65
+ { matcher: 'Write|Edit', hooks: [hookCommand('post_edit_guard.py')] },
213
66
  ],
67
+ PreCompact: [{ hooks: [hookCommand('compact_context.py')] }],
214
68
  },
215
69
  };
216
70
  }
217
71
 
218
- function buildStaging(repoRoot, staging, target) {
219
- const report = { target, copied: {}, config: { updated: false } };
220
- report.copied.commands = copyCommands(repoRoot, staging);
221
- report.copied.skills = copySkills(repoRoot, staging, skillsForRuntime('claude'));
222
- report.copied.agents = copyTree(path.join(repoRoot, 'agents'), path.join(staging, 'agents'));
223
-
224
- ensureDir(path.join(staging, 'hooks'));
225
- report.copied.hooks = [];
226
- for (const name of WORKFLOW_HOOK_FILES) {
227
- fs.copyFileSync(path.join(repoRoot, 'hooks', name), path.join(staging, 'hooks', name));
228
- report.copied.hooks.push(name);
229
- }
230
- writeAtomic(path.join(staging, 'hooks', 'hooks.json'), JSON.stringify(buildHooksManifest(), null, 2) + '\n');
231
-
232
- buildMcpRuntime(repoRoot, staging, { runtime: 'claude' });
233
- const command = mcpCommand(path.join(target, 'runtime', 'launch.cjs'));
234
- writeAtomic(path.join(staging, '.mcp.json'), JSON.stringify({
235
- mcpServers: {
236
- [MCP_SERVER_NAME]: {
237
- command: command.command,
238
- args: command.args,
239
- },
240
- },
241
- }, null, 2) + '\n');
242
-
72
+ function buildStaging(repoRoot, staging, publishedRoot) {
73
+ const skillRoot = path.join(staging, 'skills');
74
+ const hookRoot = path.join(staging, 'hooks');
75
+ const hooks = buildHooksManifest();
76
+ const skills = copySkills({ runtime: 'claude', repoRoot, skillRoot });
77
+ copyHooks({ runtime: 'claude', repoRoot, hookRoot, hooksManifest: hooks });
243
78
  const pkg = JSON.parse(fs.readFileSync(path.join(repoRoot, 'package.json'), 'utf8'));
244
- writeAtomic(path.join(staging, '.claude-plugin', 'plugin.json'), JSON.stringify({
79
+ writeAtomic(path.join(staging, '.claude-plugin', 'plugin.json'), `${JSON.stringify({
245
80
  name: PLUGIN_NAME,
246
81
  version: pkg.version,
247
- description: 'Claude Code native Ultra Builder Pro workflows with a persistent safety kernel.',
248
- author: { name: typeof pkg.author === 'string' ? pkg.author : 'Ultra Builder Pro contributors' },
82
+ description: 'File-first Ultra Builder Pro workflows for Claude Code.',
83
+ author: { name: pkg.author },
249
84
  repository: pkg.homepage,
250
- license: pkg.license || 'MIT',
251
- }, null, 2) + '\n');
252
- markManaged(staging, { adapter: 'claude', plugin: PLUGIN_NAME });
253
- const source = provenance.packageSource(repoRoot);
254
- const provenanceFile = path.join(staging, PROVENANCE_FILE);
255
- report.provenance = provenance.writeProvenance({
256
- file: provenanceFile,
257
- adapter: 'claude',
258
- ...source,
259
- roots: { plugin: target },
260
- assetRoots: { plugin: staging },
261
- assets: provenance.assetRefsForTree('plugin', staging, {
262
- exclude: ['.ubp-managed', PROVENANCE_FILE],
263
- }),
85
+ license: pkg.license,
86
+ }, null, 2)}\n`);
87
+ markManaged(staging, { adapter: 'claude', plugin: PLUGIN_NAME, version: pkg.version });
88
+ writePluginProvenance({
89
+ adapter: 'claude', repoRoot, stagingRoot: staging, publishedRoot,
264
90
  contracts: {
265
91
  plugin_manifest: { root: 'plugin', path: '.claude-plugin/plugin.json' },
266
- mcp_registration: { root: 'plugin', path: '.mcp.json' },
267
- mcp_launcher: { root: 'plugin', path: 'runtime/launch.cjs' },
268
- native_runtime: { root: 'plugin', path: 'runtime/native-runtime.json' },
269
- context_envelope_helper: { root: 'plugin', path: 'runtime/hook-context.cjs' },
270
- hook_event_helper: { root: 'plugin', path: 'runtime/hook-event.cjs' },
271
92
  hooks_manifest: { root: 'plugin', path: 'hooks/hooks.json' },
272
- checkpoint_hook: { root: 'plugin', path: 'hooks/workflow_checkpoint.py' },
273
- resume_hook: { root: 'plugin', path: 'hooks/workflow_resume.py' },
274
93
  },
275
94
  });
276
- report.provenance.file = path.join(target, PROVENANCE_FILE);
277
- return report;
95
+ return { skills };
278
96
  }
279
97
 
280
98
  function install(ctx = {}) {
281
- const target = resolvePluginRoot(ctx);
282
99
  const repoRoot = resolveRepoRoot(ctx);
283
- if (fs.existsSync(target)) {
284
- const entries = fs.readdirSync(target);
285
- if (entries.length > 0 && !isManaged(target)) {
286
- throw new Error(`refusing to replace unmanaged Claude plugin: ${target}`);
287
- }
288
- }
289
- ensureDir(path.dirname(target));
290
- const staging = fs.mkdtempSync(path.join(path.dirname(target), `.${PLUGIN_NAME}-staging-`));
291
- const backup = `${staging}-previous`;
292
- let movedPrevious = false;
293
- let published = false;
100
+ const pluginRoot = resolvePluginRoot(ctx);
101
+ const target = resolveTarget(ctx);
102
+ const cleanupAbsent = managedMetadata(pluginRoot)?.cleanup_absent
103
+ || captureAbsent(target, ['.', 'skills']);
104
+ ensureDir(path.dirname(pluginRoot));
105
+ const staging = fs.mkdtempSync(path.join(path.dirname(pluginRoot), `.${PLUGIN_NAME}-staging-`));
294
106
  try {
295
- const report = buildStaging(repoRoot, staging, target);
296
- if (fs.existsSync(target)) {
297
- fs.renameSync(target, backup);
298
- movedPrevious = true;
299
- }
300
- fs.renameSync(staging, target);
301
- published = true;
302
- if (movedPrevious) removeTree(backup);
303
- return report;
107
+ const copied = buildStaging(repoRoot, staging, pluginRoot);
108
+ markManaged(staging, { cleanup_absent: cleanupAbsent });
109
+ publishManagedTrees([{ source: staging, target: pluginRoot, label: 'Claude plugin' }]);
110
+ return {
111
+ target: pluginRoot,
112
+ pluginRoot,
113
+ skillRoot: path.join(pluginRoot, 'skills'),
114
+ hookRoot: path.join(pluginRoot, 'hooks'),
115
+ copied,
116
+ };
304
117
  } catch (error) {
305
- if (published && fs.existsSync(target)) removeTree(target);
306
- else if (fs.existsSync(staging)) removeTree(staging);
307
- if (movedPrevious && fs.existsSync(backup)) fs.renameSync(backup, target);
118
+ if (fs.existsSync(staging)) removeTree(staging);
119
+ pruneCreatedEmpty(target, cleanupAbsent);
308
120
  throw error;
309
121
  }
310
122
  }
311
123
 
124
+ function shouldRunHostCli(ctx = {}) {
125
+ if (typeof ctx.runHostCli === 'boolean') return ctx.runHostCli;
126
+ return ctx.scope === 'global' && !ctx.configDir;
127
+ }
128
+
312
129
  function doctor(ctx = {}) {
313
130
  const repoRoot = resolveRepoRoot(ctx);
314
- const source = provenance.packageSource(repoRoot);
315
- const report = provenance.inspectProvenance({
316
- file: path.join(resolvePluginRoot(ctx), PROVENANCE_FILE),
317
- expectedAdapter: 'claude',
318
- expectedPackageVersion: source.packageInfo.version,
131
+ const pluginRoot = resolvePluginRoot(ctx);
132
+ const report = inspectPlugin({
133
+ adapter: 'claude',
134
+ repoRoot,
135
+ pluginRoot,
136
+ skillRoot: path.join(pluginRoot, 'skills'),
137
+ hookRoot: path.join(pluginRoot, 'hooks'),
138
+ manifestFile: path.join(pluginRoot, '.claude-plugin', 'plugin.json'),
319
139
  });
320
140
  if (shouldRunHostCli(ctx)) {
321
- try {
322
- const host = inspectClaudeHost(ctx);
323
- report.checks.host_plugin = {
324
- status: host.pluginOk && host.detailsOk ? 'pass' : 'fail',
325
- };
326
- report.checks.host_mcp = { status: host.mcpOk ? 'pass' : 'fail' };
327
- if (!host.pluginOk || !host.detailsOk) {
328
- report.issues.push({
329
- code: 'HOST_PLUGIN_NOT_DISCOVERED',
330
- plugin_id: `${PLUGIN_NAME}@skills-dir`,
331
- });
332
- }
333
- if (!host.mcpOk) {
334
- report.issues.push({
335
- code: 'HOST_MCP_NOT_DISCOVERED',
336
- plugin_id: `${PLUGIN_NAME}@skills-dir`,
337
- server: MCP_SERVER_NAME,
338
- });
339
- }
340
- } catch (error) {
341
- report.checks.host_plugin = { status: 'fail' };
342
- report.checks.host_mcp = { status: 'fail' };
343
- report.issues.push({
344
- code: error.code === 'HOST_CLI_TIMEOUT'
345
- ? 'HOST_CLI_TIMEOUT'
346
- : 'HOST_CLI_INSPECTION_FAILED',
347
- message: error.message,
348
- });
141
+ const result = spawnSync(ctx.claudeBin || 'claude', ['plugin', 'list', '--json'], {
142
+ encoding: 'utf8', timeout: ctx.hostCliTimeoutMs || 30000,
143
+ env: { ...process.env, CLAUDE_CONFIG_DIR: resolveTarget(ctx) },
144
+ });
145
+ let discovered = false;
146
+ if (result.status === 0) {
147
+ try {
148
+ const plugins = JSON.parse(result.stdout);
149
+ discovered = Array.isArray(plugins) && plugins.some((entry) => (
150
+ entry?.id === `${PLUGIN_NAME}@skills-dir` && entry.enabled === true
151
+ ));
152
+ } catch {}
349
153
  }
154
+ report.checks.host_plugin = { status: discovered ? 'pass' : 'fail' };
155
+ if (!discovered) report.issues.push({ code: 'HOST_PLUGIN_NOT_DISCOVERED' });
156
+ report.status = report.issues.length === 0 ? 'healthy' : 'degraded';
350
157
  }
351
- return applyNativeDoctor(report, path.join(resolvePluginRoot(ctx), 'runtime'));
158
+ return report;
352
159
  }
353
160
 
354
161
  function uninstall(ctx = {}) {
355
- const target = resolvePluginRoot(ctx);
356
- const report = { target, removed: {}, config: { updated: false } };
357
- if (fs.existsSync(target) && isManaged(target)) {
358
- removeTree(target);
359
- report.removed.plugin = true;
360
- }
361
- return report;
162
+ const pluginRoot = resolvePluginRoot(ctx);
163
+ const cleanupAbsent = managedMetadata(pluginRoot)?.cleanup_absent || [];
164
+ const removed = removeManaged(pluginRoot, 'Claude plugin');
165
+ const cleaned = pruneCreatedEmpty(resolveTarget(ctx), cleanupAbsent);
166
+ return { target: pluginRoot, pluginRoot, removed, cleaned };
362
167
  }
363
168
 
364
169
  module.exports = {
365
170
  name: 'claude',
366
171
  PLUGIN_NAME,
367
- SENTINEL_KEY,
368
- SOURCE_TAG,
369
- MCP_SERVER_NAME,
370
172
  buildHooksManifest,
371
- inspectClaudeHost,
372
173
  resolveTarget,
373
174
  resolvePluginRoot,
374
175
  install,
375
- uninstall,
376
176
  doctor,
177
+ uninstall,
377
178
  };