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
@@ -0,0 +1,15 @@
1
+ ---
2
+ name: ultra-delegate-read-only
3
+ description: Execute one bounded Ultra delegation without file writes, shell commands, web access, MCP tools, or subagents.
4
+ tools:
5
+ - Read
6
+ - Grep
7
+ - Glob
8
+ subagents: []
9
+ ---
10
+
11
+ ${base_prompt}
12
+
13
+ Follow the supplied immutable delegation instruction. Do not modify files, execute
14
+ commands, access external services, dispatch subagents, or widen scope. Return the
15
+ requested strict JSON object as the final response.
@@ -0,0 +1,17 @@
1
+ ---
2
+ name: ultra-delegate-write
3
+ description: Execute one bounded Ultra delegation with file tools only and without shell commands, web access, MCP tools, or subagents.
4
+ tools:
5
+ - Read
6
+ - Write
7
+ - Edit
8
+ - Grep
9
+ - Glob
10
+ subagents: []
11
+ ---
12
+
13
+ ${base_prompt}
14
+
15
+ Follow the supplied immutable delegation instruction. Use file tools only inside the
16
+ declared worktree roots. Do not execute commands, access external services, dispatch
17
+ subagents, or widen scope. Return the requested strict JSON object as the final response.
@@ -120,9 +120,18 @@ const UBP_SENTINEL_FILE = '.ubp-managed';
120
120
  // ownership before deleting (P1 #3).
121
121
  function markManaged(dir, meta = {}) {
122
122
  ensureDir(dir);
123
- writeAtomic(path.join(dir, UBP_SENTINEL_FILE), JSON.stringify({
123
+ let previous = {};
124
+ const sentinel = path.join(dir, UBP_SENTINEL_FILE);
125
+ if (fs.existsSync(sentinel)) {
126
+ try {
127
+ const parsed = JSON.parse(fs.readFileSync(sentinel, 'utf8'));
128
+ if (parsed?.source === 'ubp') previous = parsed;
129
+ } catch {}
130
+ }
131
+ writeAtomic(sentinel, JSON.stringify({
132
+ ...previous,
124
133
  source: 'ubp',
125
- installed_at: new Date().toISOString(),
134
+ installed_at: previous.installed_at || new Date().toISOString(),
126
135
  ...meta,
127
136
  }, null, 2) + '\n');
128
137
  }
@@ -131,6 +140,68 @@ function isManaged(dir) {
131
140
  return fs.existsSync(path.join(dir, UBP_SENTINEL_FILE));
132
141
  }
133
142
 
143
+ function managedMetadata(dir) {
144
+ const sentinel = path.join(dir, UBP_SENTINEL_FILE);
145
+ if (!fs.existsSync(sentinel)) return null;
146
+ const value = JSON.parse(fs.readFileSync(sentinel, 'utf8'));
147
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
148
+ throw new Error(`invalid managed marker: ${sentinel}`);
149
+ }
150
+ if (value.source === undefined && Object.keys(value).length === 0) return {};
151
+ if (value.source !== 'ubp') throw new Error(`invalid managed marker: ${sentinel}`);
152
+ return value;
153
+ }
154
+
155
+ function normalizeOwnedRelative(value) {
156
+ if (value === '.') return '.';
157
+ if (typeof value !== 'string' || !value || path.isAbsolute(value)) {
158
+ throw new Error(`owned cleanup path must be relative: ${String(value)}`);
159
+ }
160
+ const normalized = path.normalize(value);
161
+ if (
162
+ normalized !== value
163
+ || normalized === '.'
164
+ || normalized === '..'
165
+ || normalized.startsWith(`..${path.sep}`)
166
+ ) {
167
+ throw new Error(`owned cleanup path escapes its root: ${value}`);
168
+ }
169
+ return normalized;
170
+ }
171
+
172
+ function captureAbsent(root, relatives) {
173
+ const absoluteRoot = path.resolve(root);
174
+ return [...new Set(relatives.map(normalizeOwnedRelative))]
175
+ .filter((relative) => !fs.existsSync(relative === '.' ? absoluteRoot : path.join(absoluteRoot, relative)));
176
+ }
177
+
178
+ function pruneCreatedEmpty(root, relatives) {
179
+ const absoluteRoot = path.resolve(root);
180
+ const ordered = [...new Set((relatives || []).map(normalizeOwnedRelative))]
181
+ .sort((a, b) => {
182
+ const depth = (value) => (value === '.' ? 0 : value.split(path.sep).length);
183
+ return depth(b) - depth(a);
184
+ });
185
+ const removed = [];
186
+ for (const relative of ordered) {
187
+ const target = relative === '.' ? absoluteRoot : path.resolve(absoluteRoot, relative);
188
+ if (target !== absoluteRoot && !target.startsWith(`${absoluteRoot}${path.sep}`)) {
189
+ throw new Error(`owned cleanup path escapes its root: ${relative}`);
190
+ }
191
+ if (!fs.existsSync(target)) continue;
192
+ const stat = fs.lstatSync(target);
193
+ if (stat.isSymbolicLink()) continue;
194
+ if (stat.isDirectory() && fs.readdirSync(target).length === 0) {
195
+ fs.rmdirSync(target);
196
+ removed.push(relative);
197
+ } else if (stat.isFile() && stat.size === 0) {
198
+ fs.unlinkSync(target);
199
+ removed.push(relative);
200
+ }
201
+ }
202
+ return removed;
203
+ }
204
+
134
205
  function copyFlatByExt(srcDir, dstDir, ext) {
135
206
  if (!fs.existsSync(srcDir)) return [];
136
207
  const files = fs.readdirSync(srcDir).filter((f) => f.endsWith(ext));
@@ -152,5 +223,8 @@ module.exports = {
152
223
  removeTree,
153
224
  markManaged,
154
225
  isManaged,
226
+ managedMetadata,
227
+ captureAbsent,
228
+ pruneCreatedEmpty,
155
229
  copyFlatByExt,
156
230
  };
@@ -0,0 +1,97 @@
1
+ 'use strict';
2
+
3
+ const path = require('node:path');
4
+
5
+ const KIMI_PROFILE_ROOT = path.join(__dirname, 'delegate-profiles');
6
+
7
+ function opencodePermission(writableRoots) {
8
+ const edit = { '*': 'deny' };
9
+ for (const root of writableRoots) {
10
+ if (root === '.') edit['*'] = 'allow';
11
+ else edit[`${root}/**`] = 'allow';
12
+ }
13
+ return JSON.stringify({
14
+ share: 'disabled',
15
+ permission: {
16
+ '*': 'deny',
17
+ read: 'allow',
18
+ glob: 'allow',
19
+ grep: 'allow',
20
+ list: 'allow',
21
+ lsp: 'allow',
22
+ edit,
23
+ external_directory: 'deny',
24
+ bash: 'deny',
25
+ task: 'deny',
26
+ webfetch: 'deny',
27
+ websearch: 'deny',
28
+ question: 'deny',
29
+ skill: 'deny',
30
+ },
31
+ });
32
+ }
33
+
34
+ const PROFILES = Object.freeze({
35
+ claude: Object.freeze({
36
+ binary: 'claude',
37
+ delegateArgv: (prompt, _cwd, options) => [
38
+ '-p', prompt,
39
+ '--permission-mode', options.readOnly ? 'plan' : 'acceptEdits',
40
+ '--no-session-persistence',
41
+ '--output-format', 'json',
42
+ '--json-schema', options.schemaJson,
43
+ '--tools', options.readOnly ? 'Read,Grep,Glob' : 'Read,Write,Edit,Grep,Glob',
44
+ ],
45
+ }),
46
+ codex: Object.freeze({
47
+ binary: 'codex',
48
+ delegateArgv: (prompt, cwd, options) => [
49
+ 'exec', '--ephemeral', '--ignore-user-config',
50
+ '--sandbox', options.readOnly ? 'read-only' : 'workspace-write',
51
+ '--cd', cwd,
52
+ '--config', 'sandbox_workspace_write.network_access=false',
53
+ '--output-schema', options.schemaFile,
54
+ '--output-last-message', options.hostOutput,
55
+ '--json', prompt,
56
+ ],
57
+ }),
58
+ opencode: Object.freeze({
59
+ binary: 'opencode',
60
+ delegateArgv: (prompt, cwd) => [
61
+ 'run', '--dir', cwd, '--format', 'json', '--auto', prompt,
62
+ ],
63
+ delegateEnv: (options) => ({
64
+ OPENCODE_CONFIG_CONTENT: opencodePermission(options.writableRoots),
65
+ }),
66
+ }),
67
+ kimi: Object.freeze({
68
+ binary: 'kimi',
69
+ delegateArgv: (prompt, _cwd, options) => [
70
+ '-p', prompt,
71
+ '--output-format', 'stream-json',
72
+ '--agent-file', path.join(
73
+ KIMI_PROFILE_ROOT,
74
+ options.readOnly ? 'kimi-read-only.md' : 'kimi-write.md',
75
+ ),
76
+ ],
77
+ }),
78
+ grok: Object.freeze({
79
+ binary: 'grok',
80
+ delegateArgv: (prompt, cwd, options) => [
81
+ '--cwd', cwd, '--single', prompt,
82
+ '--permission-mode', options.readOnly ? 'plan' : 'acceptEdits',
83
+ '--sandbox', options.readOnly ? 'read-only' : 'workspace',
84
+ '--no-memory', '--no-subagents', '--disable-web-search',
85
+ '--json-schema', options.schemaJson,
86
+ '--output-format', 'json',
87
+ ],
88
+ }),
89
+ });
90
+
91
+ function hostProfile(runtime) {
92
+ const profile = PROFILES[runtime];
93
+ if (!profile) throw new Error(`unsupported delegate host: ${runtime}`);
94
+ return profile;
95
+ }
96
+
97
+ module.exports = { PROFILES, hostProfile, opencodePermission };
@@ -0,0 +1,204 @@
1
+ 'use strict';
2
+
3
+ const fs = require('node:fs');
4
+ const path = require('node:path');
5
+ const crypto = require('node:crypto');
6
+
7
+ const {
8
+ copyTree,
9
+ ensureDir,
10
+ isManaged,
11
+ markManaged,
12
+ removeTree,
13
+ writeAtomic,
14
+ } = require('./file-ops.cjs');
15
+ const { parse, serialize } = require('./frontmatter.cjs');
16
+ const provenance = require('./provenance.cjs');
17
+ const {
18
+ MODEL_INVOKED_SKILLS,
19
+ WORKFLOW_HOOK_FILES,
20
+ skillPolicy,
21
+ skillsForRuntime,
22
+ } = require('./runtime-assets.cjs');
23
+
24
+ const PROVENANCE_FILE = 'provenance.json';
25
+
26
+ function titleCase(name) {
27
+ return name.split('-').map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join(' ');
28
+ }
29
+
30
+ function skillFrontmatter(runtime, name, fm) {
31
+ const base = { name, description: String(fm.description || '') };
32
+ const policy = skillPolicy(name);
33
+ if (runtime === 'claude' || runtime === 'grok') {
34
+ return {
35
+ ...base,
36
+ 'user-invocable': policy.userInvocable,
37
+ ...(policy.userInvocable ? { 'disable-model-invocation': true } : {}),
38
+ };
39
+ }
40
+ if (runtime === 'kimi') {
41
+ return {
42
+ ...base,
43
+ ...(policy.userInvocable ? { disableModelInvocation: true } : {}),
44
+ };
45
+ }
46
+ return base;
47
+ }
48
+
49
+ function codexMetadata(name, description) {
50
+ const short = String(description).replace(/\s+/g, ' ').trim().slice(0, 64).replace(/[\s.,;:]+$/, '');
51
+ return [
52
+ 'interface:',
53
+ ` display_name: ${JSON.stringify(titleCase(name))}`,
54
+ ` short_description: ${JSON.stringify(short || titleCase(name))}`,
55
+ ` default_prompt: ${JSON.stringify(`Use $ultra-builder-pro:${name} and follow its workflow.`)}`,
56
+ 'policy:',
57
+ ` allow_implicit_invocation: ${MODEL_INVOKED_SKILLS.includes(name) ? 'true' : 'false'}`,
58
+ '',
59
+ ].join('\n');
60
+ }
61
+
62
+ function copySkills({ runtime, repoRoot, skillRoot }) {
63
+ const installed = [];
64
+ for (const name of skillsForRuntime(runtime)) {
65
+ const source = path.join(repoRoot, 'skills', name);
66
+ if (!fs.existsSync(path.join(source, 'SKILL.md'))) {
67
+ throw new Error(`missing allowlisted ${runtime} skill: ${name}`);
68
+ }
69
+ const target = path.join(skillRoot, name);
70
+ copyTree(source, target, {
71
+ transform(buffer, relative) {
72
+ if (relative !== 'SKILL.md') return buffer;
73
+ const { fm, body } = parse(buffer.toString('utf8'));
74
+ if (!fm) throw new Error(`missing frontmatter in ${name}`);
75
+ return Buffer.from(serialize(skillFrontmatter(runtime, name, fm), body));
76
+ },
77
+ });
78
+ if (name === 'ultra-init') {
79
+ const template = path.join(repoRoot, '.ultra-template');
80
+ if (!fs.existsSync(template)) throw new Error('missing canonical .ultra-template');
81
+ copyTree(template, path.join(target, 'assets', 'project-template'));
82
+ }
83
+ if (runtime === 'codex') {
84
+ const { fm } = parse(fs.readFileSync(path.join(source, 'SKILL.md'), 'utf8'));
85
+ writeAtomic(
86
+ path.join(target, 'agents', 'openai.yaml'),
87
+ codexMetadata(name, fm.description),
88
+ );
89
+ }
90
+ installed.push(name);
91
+ }
92
+ return installed;
93
+ }
94
+
95
+ function copyHooks({ runtime, repoRoot, hookRoot, hooksManifest }) {
96
+ ensureDir(hookRoot);
97
+ for (const name of [...WORKFLOW_HOOK_FILES, '_common.py']) {
98
+ const source = path.join(repoRoot, 'hooks', name);
99
+ if (!fs.existsSync(source)) throw new Error(`missing allowlisted hook: ${name}`);
100
+ fs.copyFileSync(source, path.join(hookRoot, name));
101
+ }
102
+ if (['codex', 'kimi', 'grok'].includes(runtime)) {
103
+ ensureDir(path.join(hookRoot, 'adapters'));
104
+ fs.copyFileSync(
105
+ path.join(repoRoot, 'hooks', 'adapters', `${runtime}.py`),
106
+ path.join(hookRoot, 'adapters', `${runtime}.py`),
107
+ );
108
+ }
109
+ writeAtomic(path.join(hookRoot, 'hooks.json'), `${JSON.stringify(hooksManifest, null, 2)}\n`);
110
+ return [...WORKFLOW_HOOK_FILES];
111
+ }
112
+
113
+ function writePluginProvenance({ adapter, repoRoot, stagingRoot, publishedRoot, contracts = {} }) {
114
+ const source = provenance.packageSource(repoRoot);
115
+ return provenance.writeProvenance({
116
+ file: path.join(stagingRoot, PROVENANCE_FILE),
117
+ adapter,
118
+ ...source,
119
+ roots: { plugin: publishedRoot },
120
+ assetRoots: { plugin: stagingRoot },
121
+ assets: provenance.assetRefsForTree('plugin', stagingRoot, {
122
+ exclude: ['.ubp-managed', PROVENANCE_FILE],
123
+ }),
124
+ contracts,
125
+ });
126
+ }
127
+
128
+ function publishManagedTrees(entries) {
129
+ const transaction = [];
130
+ for (const { source, target, label } of entries) {
131
+ if (fs.existsSync(target) && !isManaged(target)) {
132
+ throw new Error(`refusing to replace unmanaged ${label}: ${target}`);
133
+ }
134
+ ensureDir(path.dirname(target));
135
+ }
136
+ try {
137
+ for (const { source, target } of entries) {
138
+ const backup = `${target}.ubp-backup-${crypto.randomUUID()}`;
139
+ if (fs.existsSync(target)) fs.renameSync(target, backup);
140
+ fs.renameSync(source, target);
141
+ transaction.push({ target, backup });
142
+ }
143
+ for (const { backup } of transaction) {
144
+ if (fs.existsSync(backup)) removeTree(backup);
145
+ }
146
+ } catch (error) {
147
+ for (const { target, backup } of transaction.reverse()) {
148
+ if (fs.existsSync(target)) removeTree(target);
149
+ if (fs.existsSync(backup)) fs.renameSync(backup, target);
150
+ }
151
+ throw error;
152
+ }
153
+ }
154
+
155
+ function inspectPlugin({ adapter, repoRoot, pluginRoot, skillRoot, hookRoot, manifestFile }) {
156
+ const source = provenance.packageSource(repoRoot);
157
+ const report = provenance.inspectProvenance({
158
+ file: path.join(pluginRoot, PROVENANCE_FILE),
159
+ expectedAdapter: adapter,
160
+ expectedPackageVersion: source.packageInfo.version,
161
+ });
162
+ const issue = (code, details = {}) => report.issues.push({ code, ...details });
163
+ if (!fs.existsSync(manifestFile)) issue('PLUGIN_MANIFEST_MISSING', { path: manifestFile });
164
+ for (const name of skillsForRuntime(adapter)) {
165
+ if (!fs.existsSync(path.join(skillRoot, name, 'SKILL.md'))) {
166
+ issue('SKILL_MISSING', { skill: name });
167
+ }
168
+ }
169
+ for (const name of [...WORKFLOW_HOOK_FILES, '_common.py']) {
170
+ if (!fs.existsSync(path.join(hookRoot, name))) issue('HOOK_MISSING', { hook: name });
171
+ }
172
+ for (const retired of ['commands', 'agents', 'runtime', '.mcp.json']) {
173
+ if (fs.existsSync(path.join(pluginRoot, retired))) issue('RETIRED_ASSET_PRESENT', { path: retired });
174
+ }
175
+ report.checks.skill_inventory = {
176
+ status: report.issues.some((entry) => entry.code === 'SKILL_MISSING') ? 'fail' : 'pass',
177
+ };
178
+ report.checks.hook_inventory = {
179
+ status: report.issues.some((entry) => entry.code === 'HOOK_MISSING') ? 'fail' : 'pass',
180
+ };
181
+ report.checks.plugin_manifest = {
182
+ status: fs.existsSync(manifestFile) ? 'pass' : 'fail',
183
+ };
184
+ report.status = report.issues.length === 0 ? 'healthy' : 'degraded';
185
+ return report;
186
+ }
187
+
188
+ function removeManaged(target, label) {
189
+ if (!fs.existsSync(target)) return false;
190
+ if (!isManaged(target)) throw new Error(`refusing to remove unmanaged ${label}: ${target}`);
191
+ removeTree(target);
192
+ return true;
193
+ }
194
+
195
+ module.exports = {
196
+ PROVENANCE_FILE,
197
+ copySkills,
198
+ copyHooks,
199
+ inspectPlugin,
200
+ markManaged,
201
+ publishManagedTrees,
202
+ removeManaged,
203
+ writePluginProvenance,
204
+ };
@@ -1,109 +1,47 @@
1
1
  'use strict';
2
2
 
3
3
  /**
4
- * Canonical Ultra Builder Pro package boundary.
4
+ * Canonical v0.26 package boundary.
5
5
  *
6
- * Adapters must build from this allowlist. A new directory under skills/ or
7
- * hooks/ is not packaged until it is deliberately classified here.
6
+ * Skills carry semantic workflow. Hooks are optional acceleration and safety.
7
+ * There is no prompt projection, worker registry, MCP kernel, or runtime daemon.
8
8
  */
9
9
 
10
- const CORE_PUBLIC_SKILLS = Object.freeze([
10
+ const USER_INVOKED_SKILLS = Object.freeze([
11
11
  'ultra-init',
12
12
  'ultra-research',
13
+ 'ultra-change',
13
14
  'ultra-plan',
14
15
  'ultra-dev',
15
16
  'ultra-test',
16
- 'ultra-review',
17
17
  'ultra-deliver',
18
- 'ultra-status',
19
- 'ultra-think',
20
- 'ultra-change',
21
- 'ultra-doctor',
18
+ 'ultra-delegate',
22
19
  ]);
23
20
 
24
- const PUBLIC_CAPABILITY_MODES = Object.freeze({
25
- 'ultra-init': 'setup',
26
- 'ultra-research': 'workflow',
27
- 'ultra-plan': 'workflow',
28
- 'ultra-dev': 'workflow',
29
- 'ultra-test': 'workflow',
30
- 'ultra-review': 'workflow',
31
- 'ultra-deliver': 'workflow',
32
- 'ultra-status': 'read_only',
33
- 'ultra-think': 'reasoning',
34
- 'ultra-change': 'workflow',
35
- 'ultra-doctor': 'diagnostic',
36
- });
37
-
38
- const PUBLIC_CAPABILITY_GRAPH = Object.freeze(Object.fromEntries(
39
- CORE_PUBLIC_SKILLS.map((name) => [
40
- name,
41
- Object.freeze({
42
- mode: PUBLIC_CAPABILITY_MODES[name],
43
- activation: 'explicit_only',
44
- next_capability_source: 'host_model_from_ultra_context',
45
- recommendation_owner: 'host_model',
46
- selection_owner: 'user',
47
- automatic_invocation: false,
48
- }),
49
- ]),
50
- ));
51
-
52
- const INTERNAL_AGENT_SKILLS = Object.freeze([
53
- 'code-review-expert',
54
- 'security-rules',
55
- 'integration-rules',
56
- 'testing-rules',
21
+ const MODEL_INVOKED_SKILLS = Object.freeze([
22
+ 'ultra-grilling',
23
+ 'ultra-domain-modeling',
24
+ 'ultra-tdd',
25
+ 'ultra-review',
26
+ 'ultra-think',
57
27
  ]);
58
28
 
29
+ const ROUTER_SKILLS = Object.freeze(['ultra-status']);
59
30
  const SUPPORTED_RUNTIMES = Object.freeze(['claude', 'opencode', 'codex', 'kimi', 'grok']);
60
31
 
61
- const COLLAB_SKILLS_BY_RUNTIME = Object.freeze({
62
- claude: Object.freeze(['codex-collab', 'ultra-verify']),
63
- codex: Object.freeze(['cc-collab', 'ultra-verify']),
64
- opencode: Object.freeze(['cc-collab', 'codex-collab', 'ultra-verify']),
65
- kimi: Object.freeze(['cc-collab', 'codex-collab', 'ultra-verify']),
66
- grok: Object.freeze(['cc-collab', 'codex-collab', 'ultra-verify']),
67
- });
68
-
69
- const MCP_DEPENDENT_SKILLS = Object.freeze([
70
- 'ultra-init',
71
- 'ultra-research',
72
- 'ultra-change',
73
- 'ultra-plan',
74
- 'ultra-dev',
75
- 'ultra-test',
76
- 'ultra-review',
77
- 'ultra-deliver',
78
- 'ultra-status',
79
- 'ultra-doctor',
80
- ]);
81
-
82
32
  const WORKFLOW_HOOK_FILES = Object.freeze([
83
- 'active_task_context.py',
84
- 'context_envelope.py',
85
- 'health_check.py',
86
- 'pre_stop_check.py',
87
- 'runtime_paths.py',
88
- 'subagent_tracker.py',
89
- 'workflow_checkpoint.py',
90
- 'workflow_context.py',
91
- 'workflow_resume.py',
92
- ]);
93
-
94
- const RUNTIME_WORKER_FILES = Object.freeze([
95
- 'session-close-journal-worker.cjs',
96
- 'doctor-backup-worker.cjs',
97
- ]);
98
-
99
- const RUNTIME_SUPPORT_FILES = Object.freeze([
100
- 'archive-mutation-worker.py',
33
+ 'session_context.py',
34
+ 'mid_workflow_recall.py',
35
+ 'compact_context.py',
36
+ 'post_edit_guard.py',
37
+ 'block_dangerous_commands.py',
101
38
  ]);
102
39
 
103
40
  function skillsForRuntime(runtime) {
104
- const collab = COLLAB_SKILLS_BY_RUNTIME[runtime];
105
- if (!collab) throw new Error(`unsupported Ultra runtime: ${runtime}`);
106
- return [...CORE_PUBLIC_SKILLS, ...INTERNAL_AGENT_SKILLS, ...collab];
41
+ if (!SUPPORTED_RUNTIMES.includes(runtime)) {
42
+ throw new Error(`unsupported Ultra runtime: ${runtime}`);
43
+ }
44
+ return [...USER_INVOKED_SKILLS, ...MODEL_INVOKED_SKILLS, ...ROUTER_SKILLS];
107
45
  }
108
46
 
109
47
  function isSupportedRuntime(runtime) {
@@ -111,25 +49,22 @@ function isSupportedRuntime(runtime) {
111
49
  }
112
50
 
113
51
  function skillPolicy(name) {
114
- const packaged = SUPPORTED_RUNTIMES.some((runtime) => skillsForRuntime(runtime).includes(name));
115
- if (!packaged) throw new Error(`unknown packaged Ultra skill: ${name}`);
52
+ if (!skillsForRuntime(SUPPORTED_RUNTIMES[0]).includes(name)) {
53
+ throw new Error(`unknown packaged Ultra skill: ${name}`);
54
+ }
55
+ const modelInvoked = MODEL_INVOKED_SKILLS.includes(name);
116
56
  return {
117
- userInvocable: !INTERNAL_AGENT_SKILLS.includes(name),
118
- allowImplicitInvocation: false,
119
- requiresUltraMcp: MCP_DEPENDENT_SKILLS.includes(name),
57
+ userInvocable: !modelInvoked,
58
+ allowImplicitInvocation: modelInvoked,
120
59
  };
121
60
  }
122
61
 
123
62
  module.exports = {
124
- CORE_PUBLIC_SKILLS,
125
- PUBLIC_CAPABILITY_GRAPH,
126
- INTERNAL_AGENT_SKILLS,
63
+ USER_INVOKED_SKILLS,
64
+ MODEL_INVOKED_SKILLS,
65
+ ROUTER_SKILLS,
127
66
  SUPPORTED_RUNTIMES,
128
- COLLAB_SKILLS_BY_RUNTIME,
129
- MCP_DEPENDENT_SKILLS,
130
- RUNTIME_SUPPORT_FILES,
131
67
  WORKFLOW_HOOK_FILES,
132
- RUNTIME_WORKER_FILES,
133
68
  isSupportedRuntime,
134
69
  skillPolicy,
135
70
  skillsForRuntime,