ultra-builder-pro-cli 0.10.0 → 0.12.1
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.
- package/.ultra-template/specs/architecture.md +54 -223
- package/.ultra-template/specs/discovery.md +34 -231
- package/.ultra-template/specs/product.md +44 -200
- package/.ultra-template/tasks/contexts/TEMPLATE.md +36 -0
- package/.ultra-template/tasks/tasks.json +6 -0
- package/CHANGELOG.md +86 -1
- package/README.md +21 -9
- package/adapters/_shared/codex-assets.cjs +24 -342
- package/adapters/_shared/handbook.cjs +4 -3
- package/adapters/_shared/runtime-assets.cjs +24 -0
- package/adapters/_shared/tests/handbook.test.cjs +4 -0
- package/adapters/_shared/tests/runtime-assets.test.cjs +11 -4
- package/adapters/claude.js +28 -5
- package/adapters/kimi.js +15 -138
- package/adapters/opencode.js +22 -49
- package/adapters/tests/claude.test.cjs +22 -8
- package/adapters/tests/codex.test.cjs +21 -8
- package/adapters/tests/kimi-hook.test.cjs +1 -1
- package/adapters/tests/kimi.test.cjs +11 -11
- package/adapters/tests/opencode.test.cjs +47 -8
- package/agents/code-reviewer.md +24 -85
- package/agents/debugger.md +30 -132
- package/agents/review-code.md +24 -104
- package/agents/review-comments.md +20 -83
- package/agents/review-coordinator.md +40 -137
- package/agents/review-design.md +21 -118
- package/agents/review-errors.md +22 -70
- package/agents/review-spec.md +36 -0
- package/agents/review-tests.md +20 -76
- package/agents/tdd-runner.md +26 -84
- package/commands/learn.md +5 -36
- package/commands/ultra-change.md +5 -43
- package/commands/ultra-deliver.md +4 -46
- package/commands/ultra-dev.md +4 -48
- package/commands/ultra-doctor.md +4 -30
- package/commands/ultra-init.md +5 -47
- package/commands/ultra-plan.md +5 -48
- package/commands/ultra-research.md +5 -54
- package/commands/ultra-status.md +5 -44
- package/commands/ultra-test.md +5 -45
- package/commands/ultra-think.md +5 -40
- package/docs/AGENT-CONTEXT.md +16 -8
- package/docs/ARCHITECTURE.md +32 -5
- package/docs/PLAN.zh-CN.md +8 -6
- package/docs/ROADMAP.md +5 -3
- package/docs/RUNTIME-COMPAT-MATRIX.md +8 -5
- package/docs/SKILL-AUTHORING.md +75 -0
- package/docs/STATE-DB-ACCESS-POLICY.md +17 -11
- package/docs/USER-HANDBOOK-CONTRACT.md +8 -5
- package/hooks/README.md +4 -3
- package/hooks/adapters/codex.py +1 -1
- package/hooks/adapters/kimi.py +1 -1
- package/hooks/context_spine.py +120 -16
- package/hooks/health_check.py +11 -0
- package/hooks/pre_stop_check.py +6 -5
- package/mcp-server/lib/baseline-workflow.cjs +415 -0
- package/mcp-server/lib/baseline-workflow.test.cjs +225 -0
- package/mcp-server/lib/change-workflow.cjs +24 -27
- package/mcp-server/lib/change-workflow.test.cjs +202 -6
- package/mcp-server/lib/context-spine.cjs +74 -9
- package/mcp-server/lib/context-spine.test.cjs +15 -0
- package/mcp-server/lib/doctor.cjs +14 -0
- package/mcp-server/lib/doctor.test.cjs +25 -1
- package/mcp-server/lib/init-project.cjs +49 -14
- package/mcp-server/lib/provider-refs.cjs +42 -0
- package/mcp-server/lib/spec-learning.test.cjs +5 -0
- package/mcp-server/lib/state-db.cjs +63 -4
- package/mcp-server/lib/state-db.test.cjs +8 -3
- package/mcp-server/server.cjs +48 -3
- package/mcp-server/tests/init-project.test.cjs +54 -8
- package/mcp-server/tests/server-contract.test.cjs +99 -2
- package/mcp-server/tests/state-db.test.cjs +11 -2
- package/package.json +3 -2
- package/skills/cc-collab/SKILL.md +16 -18
- package/skills/code-review-expert/SKILL.md +39 -114
- package/skills/code-review-expert/references/correctness-reliability.md +30 -0
- package/skills/code-review-expert/references/design-boundaries.md +26 -0
- package/skills/code-review-expert/references/removal-plan.md +17 -45
- package/skills/codex-collab/SKILL.md +23 -28
- package/skills/codex-collab/evals/evals.json +18 -23
- package/skills/integration-rules/SKILL.md +28 -67
- package/skills/learn/SKILL.md +46 -106
- package/skills/security-rules/SKILL.md +34 -56
- package/skills/testing-rules/SKILL.md +28 -52
- package/skills/ultra-change/SKILL.md +68 -114
- package/skills/ultra-deliver/SKILL.md +58 -86
- package/skills/ultra-dev/SKILL.md +46 -105
- package/skills/ultra-doctor/SKILL.md +45 -72
- package/skills/ultra-init/SKILL.md +62 -147
- package/skills/ultra-init/references/brownfield-adoption.md +65 -0
- package/skills/ultra-plan/SKILL.md +56 -89
- package/skills/ultra-research/SKILL.md +64 -152
- package/skills/ultra-research/references/architecture.md +38 -0
- package/skills/ultra-research/references/problem-product.md +39 -0
- package/skills/ultra-research/references/quality-delivery.md +34 -0
- package/skills/ultra-research/references/synthesis.md +38 -0
- package/skills/ultra-research/references/users-scope.md +40 -0
- package/skills/ultra-review/SKILL.md +54 -98
- package/skills/ultra-review/references/unified-schema.md +76 -101
- package/skills/ultra-review/scripts/review_wait.py +242 -77
- package/skills/ultra-status/SKILL.md +41 -56
- package/skills/ultra-test/SKILL.md +37 -72
- package/skills/ultra-think/SKILL.md +43 -102
- package/skills/ultra-verify/SKILL.md +44 -84
- package/skills/ultra-verify/evals/evals.json +24 -27
- package/spec/cli-protocol.md +4 -0
- package/spec/mcp-tools.yaml +223 -4
- package/spec/schemas/command-manifest.schema.json +7 -25
- package/spec/schemas/mcp-tools.schema.json +1 -1
- package/spec/schemas/skill-manifest.schema.json +9 -79
- package/spec/schemas/state-db.sql +33 -2
- package/ultra-tools/commands/status.cjs +20 -2
- package/ultra-tools/commands/task.cjs +4 -1
- package/ultra-tools/status-command.test.cjs +20 -0
- package/ultra-tools/system-command.test.cjs +5 -0
- package/skills/code-review-expert/references/code-quality-checklist.md +0 -112
- package/skills/code-review-expert/references/integration-checklist.md +0 -46
- package/skills/code-review-expert/references/security-checklist.md +0 -100
- package/skills/code-review-expert/references/solid-checklist.md +0 -65
- package/skills/ultra-research/steps/step-00-problem-validation.md +0 -154
- package/skills/ultra-research/steps/step-01-opportunity-discovery.md +0 -172
- package/skills/ultra-research/steps/step-02-market-assessment.md +0 -195
- package/skills/ultra-research/steps/step-03-competitive-landscape.md +0 -197
- package/skills/ultra-research/steps/step-04-product-strategy.md +0 -196
- package/skills/ultra-research/steps/step-05-assumptions-validation.md +0 -234
- package/skills/ultra-research/steps/step-10-user-personas.md +0 -169
- package/skills/ultra-research/steps/step-11-user-scenarios.md +0 -181
- package/skills/ultra-research/steps/step-20-user-stories.md +0 -156
- package/skills/ultra-research/steps/step-21-features-scope.md +0 -157
- package/skills/ultra-research/steps/step-22-success-metrics.md +0 -195
- package/skills/ultra-research/steps/step-30-architecture-context.md +0 -154
- package/skills/ultra-research/steps/step-31-solution-strategy.md +0 -172
- package/skills/ultra-research/steps/step-32-building-blocks.md +0 -188
- package/skills/ultra-research/steps/step-40-deployment.md +0 -123
- package/skills/ultra-research/steps/step-41-quality-risks.md +0 -135
- package/skills/ultra-research/steps/step-99-synthesis.md +0 -188
- package/skills/ultra-review/scripts/review_verdict_update.py +0 -99
|
@@ -8,8 +8,8 @@ const { spawnSync } = require('node:child_process');
|
|
|
8
8
|
const yaml = require('js-yaml');
|
|
9
9
|
const {
|
|
10
10
|
CORE_PUBLIC_SKILLS,
|
|
11
|
-
INTERNAL_AGENT_SKILLS,
|
|
12
11
|
WORKFLOW_HOOK_FILES,
|
|
12
|
+
skillPolicy,
|
|
13
13
|
skillsForRuntime,
|
|
14
14
|
} = require('./runtime-assets.cjs');
|
|
15
15
|
|
|
@@ -69,7 +69,6 @@ const SKILL_REFERENCE_NAMES = Object.freeze([
|
|
|
69
69
|
'ultra-review',
|
|
70
70
|
'ultra-verify',
|
|
71
71
|
]);
|
|
72
|
-
const INTERNAL_SKILLS = new Set(INTERNAL_AGENT_SKILLS);
|
|
73
72
|
const CODEX_PRIMARY_SKILLS = new Set([...COMMAND_NAMES, 'ultra-review']);
|
|
74
73
|
const TEXT_EXTENSIONS = new Set(['.md', '.json', '.py', '.sh', '.txt', '.yaml', '.yml']);
|
|
75
74
|
|
|
@@ -202,11 +201,7 @@ Model agreement never overrides failing tests or authoritative runtime evidence.
|
|
|
202
201
|
Read the bundled references for mode-specific evidence and confidence guidance.
|
|
203
202
|
*/ }).match(/\/\*([\s\S]*?)\*\//)[1].trim();
|
|
204
203
|
function titleCase(name) {
|
|
205
|
-
const special = {
|
|
206
|
-
'ai-collab-base': 'AI Collaboration Base',
|
|
207
|
-
'cc-collab': 'Claude Code Collaboration',
|
|
208
|
-
'use-railway': 'Use Railway',
|
|
209
|
-
};
|
|
204
|
+
const special = { 'cc-collab': 'Claude Code Collaboration' };
|
|
210
205
|
if (special[name]) return special[name];
|
|
211
206
|
return name.split('-').map((part) => part ? part[0].toUpperCase() + part.slice(1) : part).join(' ');
|
|
212
207
|
}
|
|
@@ -221,276 +216,11 @@ function replaceSlashCommand(text, command, replacement) {
|
|
|
221
216
|
|
|
222
217
|
function adaptCodexPrimaryText(input, skillName) {
|
|
223
218
|
let text = String(input);
|
|
224
|
-
text = text.replaceAll('mcp__claude-in-chrome__*', 'the available Codex browser verification tools');
|
|
225
|
-
text = text.replaceAll('claude_md_rule', 'agents_md_rule');
|
|
226
|
-
text = text.replaceAll('claude-opus-4-6', '<codex-model>');
|
|
227
|
-
text = text.replaceAll('Claude', 'Codex');
|
|
228
|
-
text = text.replaceAll('TaskCreate/TaskUpdate', 'the Codex plan tool');
|
|
229
|
-
text = text.replaceAll('TaskCreate', 'the Codex plan tool');
|
|
230
|
-
text = text.replaceAll('TaskUpdate', 'the Codex plan tool');
|
|
231
|
-
text = text.replaceAll('TaskList', 'the current Codex plan');
|
|
232
|
-
text = text.replaceAll('TaskOutput', 'verbose subagent transcript output');
|
|
233
|
-
text = text.replaceAll('run_in_background: true', 'native parallel execution');
|
|
234
|
-
text = text.replaceAll('Bash tool', '`exec_command`');
|
|
235
|
-
text = text.replaceAll('Bash calls', '`exec_command` calls');
|
|
236
|
-
text = text.replaceAll('Read tool', 'targeted file reads');
|
|
237
|
-
text = text.replaceAll('Write tool', '`apply_patch`');
|
|
238
|
-
text = text.replaceAll('`ask.question`', 'a direct user question');
|
|
239
|
-
text = text.replaceAll('ask.question', 'ask the user directly');
|
|
240
|
-
text = text.replaceAll('Playwright via Bash', 'Playwright through `exec_command`');
|
|
241
|
-
text = text.replaceAll('mcp__context7__query-docs', 'official documentation lookup');
|
|
242
|
-
text = text.replaceAll('mcp__exa__web_search_exa', 'verified web search');
|
|
243
|
-
text = text.replaceAll('Context7 MCP', 'official primary documentation');
|
|
244
|
-
text = text.replaceAll('Context7/Exa', 'official primary documentation and verified web search');
|
|
245
|
-
text = text.replaceAll('Context7', 'official primary documentation');
|
|
246
|
-
text = text.replaceAll('Exa MCP', 'verified web search');
|
|
247
|
-
text = text.replaceAll('a direct user question (or runtime `ask the user directly`)', 'ask the user directly');
|
|
248
|
-
text = text.replaceAll('a direct user question (fallback: `ask the user directly` / CLI menu)', 'ask the user directly');
|
|
249
|
-
text = text.replaceAll('questions via ask the user directly.', 'questions directly to the user.');
|
|
250
|
-
text = text.replaceAll('using `the Codex plan tool`', 'with the Codex plan tool');
|
|
251
|
-
text = text.replaceAll("via the runtime's native the Codex plan tool", 'with the Codex plan tool when available');
|
|
252
|
-
text = text.replaceAll('`the Codex plan tool` → `status: "in_progress"`', 'Mark the current Codex plan item `in_progress`');
|
|
253
|
-
text = text.replaceAll('`the Codex plan tool` → `status: "completed"`', 'Mark the current Codex plan item `completed`');
|
|
254
|
-
text = text.replaceAll('`the current Codex plan` → resume from last incomplete step', 'Resume from the first incomplete item in the current Codex plan');
|
|
255
|
-
text = text.replaceAll('`the Codex plan tool`', 'the Codex plan tool');
|
|
256
|
-
|
|
257
|
-
if (skillName === 'ultra-init') {
|
|
258
|
-
text = text.replace(
|
|
259
|
-
/MCP 不可达时回退[^。]*。/,
|
|
260
|
-
'MCP 不可达时只使用插件内置的可验证 CLI 初始化路径;不得手写投影文件。',
|
|
261
|
-
);
|
|
262
|
-
text = text.replace(
|
|
263
|
-
/- \*\*无 Codex 独占依赖\*\*[::][\s\S]*?(?=\n- \*\*模板内置)/,
|
|
264
|
-
'- **Codex-native boundary**: use the bundled `task.init_project` MCP tool; the plugin-local CLI below is only the verified initialization fallback.',
|
|
265
|
-
);
|
|
266
|
-
text = text.replace(
|
|
267
|
-
/在调 `task\.init_project` 之前,调用方(Codex \/ CLI \/ SDK)需要先判断:/,
|
|
268
|
-
'在调 `task.init_project` 之前,Codex 需要先判断:',
|
|
269
|
-
);
|
|
270
|
-
text = text.replace(
|
|
271
|
-
/- 如果调用方是 Codex,可在此用 the Codex plan tool 跟踪 Step 0–4 的 session 内进度\n (这是 runtime 的 session-local 跟踪,不走 MCP)/,
|
|
272
|
-
'- 多步初始化可用 Codex plan 跟踪;持久项目状态仍只通过 Ultra MCP 写入。',
|
|
273
|
-
);
|
|
274
|
-
text = text.replace(
|
|
275
|
-
/交互渠道:[\s\S]*?(?=\n确认 4 个问题:)/,
|
|
276
|
-
'交互渠道:直接向用户提问;不要调用未注册的人机交互 MCP tool。\n',
|
|
277
|
-
);
|
|
278
|
-
text = text.replace(
|
|
279
|
-
/\*\*CLI 回退路径\*\*[\s\S]*?(?=\n\*\*错误处理\*\*)/,
|
|
280
|
-
`**插件内置 CLI 回退路径**(只在 MCP 启动失败时使用):
|
|
281
|
-
|
|
282
|
-
\`\`\`bash
|
|
283
|
-
node ~/plugins/ultra-builder-pro/runtime/ultra-tools.cjs task init-project \\
|
|
284
|
-
--target-dir "$TARGET" \\
|
|
285
|
-
--project-name "$NAME" \\
|
|
286
|
-
--project-type "$TYPE" \\
|
|
287
|
-
--stack "$STACK"
|
|
288
|
-
\`\`\`
|
|
289
|
-
|
|
290
|
-
该 CLI 与 MCP 使用同一模板和校验规则。不得改写 \`.ultra/tasks/tasks.json\` 来模拟成功。
|
|
291
|
-
`,
|
|
292
|
-
);
|
|
293
|
-
text = text.replace(
|
|
294
|
-
/## 调用方式(按 runtime)[\s\S]*?(?=\n## 输出锚点)/,
|
|
295
|
-
'## Codex 调用方式\n\n在 Codex 中显式调用 `$ultra-builder-pro:ultra-init`,并在同一条任务消息中提供项目名、类型、技术栈或 git 约束。\n',
|
|
296
|
-
);
|
|
297
|
-
text = text.replace(
|
|
298
|
-
/- \*\*不\*\*写入 state\.db(state\.db 由第一次 MCP 写操作或显式 `ultra-tools db init` 触发)/,
|
|
299
|
-
'- **不**直接写入 state.db;它由第一次 Ultra MCP 状态写操作初始化。',
|
|
300
|
-
);
|
|
301
|
-
text = text.replaceAll('不再依赖 `~/.codex/.ultra-template/`', '不依赖任何用户目录模板');
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
if (skillName === 'ultra-plan') {
|
|
305
|
-
text = text.replace(
|
|
306
|
-
/Interactive prompt uses[\s\S]*?(?=\n\n\*\*Dual-scale effort)/,
|
|
307
|
-
'Ask the user directly in Codex and record the selected posture.',
|
|
308
|
-
);
|
|
309
|
-
text = text.replace(
|
|
310
|
-
/\*\*CLI fallback\*\* \(per task\):[\s\S]*?(?=\nAfter each `task\.create`)/,
|
|
311
|
-
'**Failure boundary**: if the bundled MCP cannot execute `task.create`, stop and report the MCP error. Do not write state.db or its JSON/Markdown projections directly.\n\n',
|
|
312
|
-
);
|
|
313
|
-
text = text.replace(
|
|
314
|
-
/## MCP → CLI fallback matrix[\s\S]*?(?=\n## What this skill DOES NOT do)/,
|
|
315
|
-
`## Codex runtime boundary
|
|
316
|
-
|
|
317
|
-
- Ask scope and approval questions directly in the Codex conversation.
|
|
318
|
-
- Persist tasks only through bundled MCP \`task.create\` or \`task.parse_prd\`.
|
|
319
|
-
- If that MCP is unavailable, stop the state mutation with evidence; the legacy CLI does not
|
|
320
|
-
implement task creation and is not a valid fallback.
|
|
321
|
-
`,
|
|
322
|
-
);
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
if (skillName === 'ultra-dev') {
|
|
326
|
-
text = text.replace(
|
|
327
|
-
/## Design decisions vs pre-Phase-3[\s\S]*?(?=\n## Prerequisites)/,
|
|
328
|
-
`## Codex-native execution boundaries
|
|
329
|
-
|
|
330
|
-
- Status changes use bundled MCP \`task.update\`; projected JSON and frontmatter are read-only.
|
|
331
|
-
- Review uses \`$ultra-builder-pro:ultra-review\` and the installed native Codex custom agents.
|
|
332
|
-
The active MCP server does not expose a server-side review worker.
|
|
333
|
-
- Recovery uses the Codex plan plus \`.ultra/workflow-state.json\`, with the bundled compact hooks.
|
|
334
|
-
The active MCP server does not expose a checkpoint tool, and no manual compact is required.
|
|
335
|
-
`,
|
|
336
|
-
);
|
|
337
|
-
text = text.replaceAll(
|
|
338
|
-
'**CLI fallback**: `ultra-tools task update <id> --status in_progress`.',
|
|
339
|
-
'**Failure boundary**: if `task.update` is unavailable, stop; do not edit state.db or projections directly.',
|
|
340
|
-
);
|
|
341
|
-
text = text.replaceAll(
|
|
342
|
-
'**CLI fallback**: `ultra-tools task update <id> --status completed`.',
|
|
343
|
-
'**Failure boundary**: if `task.update` is unavailable, stop; do not mark the projection completed manually.',
|
|
344
|
-
);
|
|
345
|
-
text = text.replace(
|
|
346
|
-
/\*\*Subagent isolation \(complexity ≥ 7\)\*\*:[\s\S]*?subagent returns summary\./,
|
|
347
|
-
'**Subagent isolation (complexity ≥ 7)**: use a bounded installed Codex custom agent only when the Subagent Policy or this invoked workflow authorizes delegation; the parent retains decisions and verification.',
|
|
348
|
-
);
|
|
349
|
-
text = text.replace(
|
|
350
|
-
/### Step 4\.4 — Pre-Review Checkpoint[\s\S]*?(?=\n### Step 4\.5)/,
|
|
351
|
-
`### Step 4.4 — Pre-Review Checkpoint
|
|
352
|
-
|
|
353
|
-
Atomically write \`.ultra/workflow-state.json\` with \`step=4.5\`,
|
|
354
|
-
\`status=pre_review\`, the task id, branch, and timestamp. Mark the matching Codex plan item
|
|
355
|
-
complete. The PreCompact/PostCompact hooks preserve and restore this checkpoint automatically;
|
|
356
|
-
do not require the user to compact or call a nonexistent checkpoint tool.
|
|
357
|
-
`,
|
|
358
|
-
);
|
|
359
|
-
text = text.replace(
|
|
360
|
-
/### Step 4\.5 — Ultra Review \(MANDATORY\)[\s\S]*?(?=\n\*\*MAX_REVIEW_ITERATIONS)/,
|
|
361
|
-
`### Step 4.5 — Ultra Review (MANDATORY)
|
|
362
|
-
|
|
363
|
-
Invoke \`$ultra-builder-pro:ultra-review all\`. That skill selects and dispatches the installed
|
|
364
|
-
native Codex review agents, waits on their structured files, and owns \`SUMMARY.json\`. Do not call
|
|
365
|
-
an unregistered review MCP tool or shell out to another Codex process as a substitute.
|
|
366
|
-
|
|
367
|
-
`,
|
|
368
|
-
);
|
|
369
|
-
text = text.replace(
|
|
370
|
-
/## MCP → CLI fallback matrix[\s\S]*?(?=\n## What this skill DOES NOT do)/,
|
|
371
|
-
`## Codex runtime boundary
|
|
372
|
-
|
|
373
|
-
| Purpose | Authoritative Codex path |
|
|
374
|
-
|---------|--------------------------|
|
|
375
|
-
| Select/read/update task | bundled MCP \`task.list\`, \`task.get\`, \`task.update\` |
|
|
376
|
-
| Pre-review recovery | Codex plan + \`.ultra/workflow-state.json\` + compact hooks |
|
|
377
|
-
| Review | \`$ultra-builder-pro:ultra-review\` + native custom agents |
|
|
378
|
-
| Human decision | ask the user directly |
|
|
379
|
-
|
|
380
|
-
If a required task MCP operation fails, stop and report it; never fall back to direct database or
|
|
381
|
-
projection writes.
|
|
382
|
-
`,
|
|
383
|
-
);
|
|
384
|
-
text = text.replace(
|
|
385
|
-
/- Does NOT assume `review\.run` or `session\.checkpoint` are wired — fallbacks are first-class/,
|
|
386
|
-
'- Does NOT call unregistered review or checkpoint MCP tools.',
|
|
387
|
-
);
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
if (skillName === 'ultra-test') {
|
|
391
|
-
text = text.replace(
|
|
392
|
-
/## MCP → CLI fallback matrix[\s\S]*?(?=\n## What this skill DOES NOT do)/,
|
|
393
|
-
`## Codex runtime boundary
|
|
394
|
-
|
|
395
|
-
- Read task completion through bundled MCP \`task.list\`.
|
|
396
|
-
- Ask before risky auto-fixes directly in the Codex conversation.
|
|
397
|
-
- If task state is unavailable, report the missing gate rather than trusting a projection alone.
|
|
398
|
-
`,
|
|
399
|
-
);
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
if (skillName === 'ultra-deliver') {
|
|
403
|
-
text = text.replace(
|
|
404
|
-
/## MCP → CLI fallback matrix[\s\S]*?(?=\n## What this skill DOES NOT do)/,
|
|
405
|
-
`## Codex runtime boundary
|
|
406
|
-
|
|
407
|
-
Ask the user directly before committing, tagging, pushing, or overriding the version bump. These are
|
|
408
|
-
external repository mutations; never infer approval from a prior read-only or test request.
|
|
409
|
-
`,
|
|
410
|
-
);
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
if (skillName === 'ultra-status') {
|
|
414
|
-
text = text.replace(
|
|
415
|
-
/\*\*CLI fallback\*\*: `ultra-tools task list` \+ `ultra-tools session list`\./,
|
|
416
|
-
'**Failure boundary**: if the bundled task/session MCP tools are unavailable, report those panels as unavailable; do not trust projections as authority.',
|
|
417
|
-
);
|
|
418
|
-
text = text.replace(
|
|
419
|
-
/\*\*Output block\*\*:[\s\S]*?(?=\n## Single-task mode)/,
|
|
420
|
-
`**Output block**: name the concrete next skill and use its namespaced Codex invocation, for
|
|
421
|
-
example \`$ultra-builder-pro:ultra-dev\`. If a fresh context would help, recommend starting a new
|
|
422
|
-
Codex task; do not emit a legacy slash-command placeholder.
|
|
423
|
-
|
|
424
|
-
`,
|
|
425
|
-
);
|
|
426
|
-
text = text.replace(
|
|
427
|
-
/## MCP → CLI fallback matrix[\s\S]*?(?=\n## Cost panel)/,
|
|
428
|
-
`## Codex data paths
|
|
429
|
-
|
|
430
|
-
| Purpose | Path |
|
|
431
|
-
|---------|------|
|
|
432
|
-
| List/detail tasks | bundled MCP \`task.list\` / \`task.get\` |
|
|
433
|
-
| Cost panel | \`node ~/plugins/ultra-builder-pro/runtime/ultra-tools.cjs status --cost --json --since 7d\` |
|
|
434
|
-
|
|
435
|
-
Task projections are not an authority fallback. If the MCP is unavailable, label the task panel
|
|
436
|
-
unavailable while still reporting file and git evidence.
|
|
437
|
-
`,
|
|
438
|
-
);
|
|
439
|
-
text = text.replaceAll(
|
|
440
|
-
'`ultra-tools status --cost --json`',
|
|
441
|
-
'`node ~/plugins/ultra-builder-pro/runtime/ultra-tools.cjs status --cost --json`',
|
|
442
|
-
);
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
if (skillName === 'ultra-think') {
|
|
446
|
-
text = text.replace(
|
|
447
|
-
/Every factual claim about tech\/API\/best-practices must be verified via:[\s\S]*?(?=\n\nLabel each assertion:)/,
|
|
448
|
-
`Every factual claim about technology, APIs, or current behavior must use the best available
|
|
449
|
-
primary evidence in this order:
|
|
450
|
-
- current repository or installed source;
|
|
451
|
-
- official primary documentation;
|
|
452
|
-
- web search when the fact may have changed or local evidence is insufficient.
|
|
453
|
-
`,
|
|
454
|
-
);
|
|
455
|
-
text = text.replaceAll(
|
|
456
|
-
'docs via Context7/Exa',
|
|
457
|
-
'official primary documentation or verified web sources',
|
|
458
|
-
);
|
|
459
|
-
text = text.replace(
|
|
460
|
-
/## MCP → CLI fallback matrix[\s\S]*?(?=\n## What this skill DOES NOT do)/,
|
|
461
|
-
`## Codex interaction boundary
|
|
462
|
-
|
|
463
|
-
Ask clarifying questions directly in the Codex conversation. This reasoning workflow is read-only
|
|
464
|
-
and does not require an interactive MCP or legacy CLI menu.
|
|
465
|
-
`,
|
|
466
|
-
);
|
|
467
|
-
}
|
|
468
|
-
|
|
469
219
|
if (skillName === 'ultra-review') {
|
|
470
|
-
text = text.
|
|
471
|
-
'
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
## Codex native worker contract
|
|
475
|
-
|
|
476
|
-
Use the installed native Codex custom agents as bounded review workers. Dispatch independent
|
|
477
|
-
workers concurrently, keep the current Codex task primary, and treat their JSON artifacts—not
|
|
478
|
-
their conversational transcripts—as review evidence.`,
|
|
220
|
+
text = text.replaceAll(
|
|
221
|
+
"the current host's native bounded-worker mechanism",
|
|
222
|
+
'native Codex custom agents installed for the selected review workers',
|
|
479
223
|
);
|
|
480
|
-
text = text.replaceAll('### Phase 3: Background Execution', '### Phase 3: Parallel Native Agent Execution');
|
|
481
|
-
text = text.replaceAll('**Step 4b: Launch coordinator in background:**', '**Step 4b: Delegate coordination:**');
|
|
482
|
-
text = text.replaceAll('in **background mode** (`native parallel execution`)', 'concurrently with native Codex subagent orchestration');
|
|
483
|
-
text = text.replaceAll('using multiple native Codex subagent orchestration calls in a single message', 'using the installed native Codex custom agents');
|
|
484
|
-
text = text.replaceAll('Set `native parallel execution` on every Task call.', 'Dispatch every selected custom agent concurrently and keep each delegated scope bounded.');
|
|
485
|
-
text = text.replaceAll('NEVER call verbose subagent transcript output for any review agent', 'Do not copy verbose subagent transcripts into the parent context');
|
|
486
|
-
text = text.replaceAll('Call `review_wait.py` IMMEDIATELY — do NOT process idle notifications', 'Use `review_wait.py` as the file-completion gate before synthesis');
|
|
487
|
-
text = text.replaceAll('Ignore all agent idle/completion messages between launch and wait script return', 'Treat completion messages only as lifecycle evidence; findings still come from the JSON files');
|
|
488
|
-
text = text.replaceAll('Launch review-coordinator with `native parallel execution`:', 'After reviewer completion, delegate coordination to the native `review-coordinator` agent:');
|
|
489
|
-
text = text.replaceAll('Use Bash to block until all agents finish writing:', 'Run the waiter through `exec_command` with a short yield; if it returns a live session, poll in bounded intervals:');
|
|
490
|
-
text = text.replaceAll('After launching background agents', 'After dispatching the review agents');
|
|
491
|
-
text = text.replaceAll('The review agents write to files; you read from files.', 'The review agents write findings to files; the parent reads only the structured files and concise lifecycle acknowledgements.');
|
|
492
|
-
text = text.replaceAll('The ONLY information path from agents is: wait script → Read SUMMARY.json', 'The authoritative finding path is: wait script → inspect SUMMARY.json');
|
|
493
|
-
text = text.replaceAll('**Read SUMMARY.json**', '**Inspect SUMMARY.json**');
|
|
494
224
|
}
|
|
495
225
|
|
|
496
226
|
return text;
|
|
@@ -536,15 +266,6 @@ function adaptHostText(input, skillName = '') {
|
|
|
536
266
|
text = text.replaceAll('~/.codex/skills', '~/plugins/ultra-builder-pro/skills');
|
|
537
267
|
text = text.replaceAll('~/.claude/hooks', '~/plugins/ultra-builder-pro/hooks');
|
|
538
268
|
text = text.replaceAll('~/.claude', '~/.codex');
|
|
539
|
-
text = text.replaceAll('AskUserQuestion', 'ask the user directly');
|
|
540
|
-
text = text.replaceAll('Claude runtime', 'Codex runtime');
|
|
541
|
-
text = text.replaceAll('Claude-only', 'Codex-only');
|
|
542
|
-
text = text.replaceAll('Claude Task tool', 'Codex native subagent orchestration');
|
|
543
|
-
text = text.replaceAll('Claude `Task` tool', 'Codex native subagent orchestration');
|
|
544
|
-
text = text.replaceAll('Claude: `Task`', 'Codex: native subagent orchestration');
|
|
545
|
-
text = text.replaceAll('Task tool', 'native Codex subagent orchestration');
|
|
546
|
-
text = text.replaceAll('`Task`/`ultra-tools subagent run`', 'native Codex subagent orchestration / `ultra-tools subagent run`');
|
|
547
|
-
text = text.replaceAll('`Task` →', 'native Codex subagent orchestration →');
|
|
548
269
|
|
|
549
270
|
for (const skill of SKILL_REFERENCE_NAMES) {
|
|
550
271
|
text = replaceSlashCommand(text, skill, `$ultra-builder-pro:${skill}`);
|
|
@@ -555,52 +276,8 @@ function adaptHostText(input, skillName = '') {
|
|
|
555
276
|
text = adaptCodexPrimaryText(text, skillName);
|
|
556
277
|
}
|
|
557
278
|
|
|
558
|
-
if (skillName === 'ai-collab-base') {
|
|
559
|
-
text = text.replaceAll("Claude's", "Codex's");
|
|
560
|
-
text = text.replaceAll('Claude-only', 'Codex-only');
|
|
561
|
-
text = text.replaceAll('Claude ', 'Codex ');
|
|
562
|
-
text = text.replaceAll('Claude\n', 'Codex\n');
|
|
563
|
-
text = text.replaceAll('--approval-mode yolo', '--approval-mode plan');
|
|
564
|
-
text = text.replaceAll('--yolo', '--approval-mode plan');
|
|
565
|
-
text = text.replaceAll('Bash tool', '`exec_command`');
|
|
566
|
-
text = text.replaceAll('Read tool', 'targeted file reads');
|
|
567
|
-
text = text.replaceAll('Write tool', '`apply_patch`');
|
|
568
|
-
}
|
|
569
|
-
|
|
570
279
|
if (skillName === 'learn') {
|
|
571
|
-
text = text.replaceAll(
|
|
572
|
-
'~/plugins/ultra-builder-pro/skills/learned-<name>-unverified/SKILL.md',
|
|
573
|
-
'~/.agents/skills/learned-<name>-unverified/SKILL.md',
|
|
574
|
-
);
|
|
575
|
-
text = text.replaceAll(
|
|
576
|
-
'~/plugins/ultra-builder-pro/skills/learned-<pattern-slug>-unverified/SKILL.md',
|
|
577
|
-
'~/.agents/skills/learned-<pattern-slug>-unverified/SKILL.md',
|
|
578
|
-
);
|
|
579
|
-
text = text.replaceAll(
|
|
580
|
-
'~/plugins/ultra-builder-pro/skills/learned-<slug>-unverified/SKILL.md',
|
|
581
|
-
'~/.agents/skills/learned-<slug>-unverified/SKILL.md',
|
|
582
|
-
);
|
|
583
|
-
text = text.replaceAll(
|
|
584
|
-
'~/plugins/ultra-builder-pro/skills/learned/<name>_unverified.md',
|
|
585
|
-
'~/.agents/skills/learned-<name>-unverified/SKILL.md',
|
|
586
|
-
);
|
|
587
|
-
text = text.replaceAll(
|
|
588
|
-
'~/plugins/ultra-builder-pro/skills/learned/<pattern-slug>_unverified.md',
|
|
589
|
-
'~/.agents/skills/learned-<pattern-slug>-unverified/SKILL.md',
|
|
590
|
-
);
|
|
591
|
-
text = text.replaceAll(
|
|
592
|
-
'~/plugins/ultra-builder-pro/skills/learned/<slug>_unverified.md',
|
|
593
|
-
'~/.agents/skills/learned-<slug>-unverified/SKILL.md',
|
|
594
|
-
);
|
|
595
|
-
text = text.replaceAll('append the `_unverified` suffix to the filename', 'append `-unverified` to the skill directory name');
|
|
596
|
-
text = text.replaceAll('Never overwrite an existing unverified file', 'Never overwrite an existing learned skill directory');
|
|
597
|
-
text = text.replaceAll('remove the `_unverified` suffix', 'rename the directory to remove `-unverified` and update the frontmatter name');
|
|
598
|
-
text = text.replaceAll('(`pattern-slug-2_unverified.md`)', '(`learned-pattern-slug-2-unverified/`)');
|
|
599
|
-
text = text.replaceAll('Anything the user already wrote in AGENTS.md or similar project instructions', 'Anything already captured in AGENTS.md or equivalent project instructions');
|
|
600
|
-
text = text.replace(
|
|
601
|
-
/## MCP → CLI fallback matrix[\s\S]*?(?=\n## What this skill DOES NOT do)/,
|
|
602
|
-
'## Codex approval boundary\n\nAsk the user directly before writing a learned skill. No MCP or legacy CLI interaction layer is required.\n',
|
|
603
|
-
);
|
|
280
|
+
text = text.replaceAll("current host's user skill directory", '`~/.agents/skills`');
|
|
604
281
|
text += `\n\n## Codex packaging requirement\n\nEach learned pattern must be a valid skill directory, not a loose Markdown file. The generated\n\`SKILL.md\` must start with only \`name\` and \`description\` frontmatter. Also create\n\`agents/openai.yaml\` with \`policy.allow_implicit_invocation: false\`. A new Codex task is required\nbefore the learned skill appears in discovery.\n`;
|
|
605
282
|
}
|
|
606
283
|
|
|
@@ -610,9 +287,9 @@ function adaptHostText(input, skillName = '') {
|
|
|
610
287
|
function adaptedDescription(sourceDescription, targetName) {
|
|
611
288
|
const special = {
|
|
612
289
|
'cc-collab': 'Ask Claude Code for an independent read-only analysis while Codex owns verification and synthesis. Use only when the user explicitly requests CC or Claude Code collaboration.',
|
|
613
|
-
'ultra-verify': 'Run Codex-primary
|
|
614
|
-
'ultra-dev': 'Execute one Ultra task with Codex-native
|
|
615
|
-
'learn': 'Extract one reusable
|
|
290
|
+
'ultra-verify': 'Run Codex-primary cross-model verification with a read-only Claude Code advisor. Use only when the user explicitly requests independent model verification.',
|
|
291
|
+
'ultra-dev': 'Execute one authoritative Ultra task with Codex-native implementation, verification, and review. Use when a dependency-ready slice is ready for development.',
|
|
292
|
+
'learn': 'Extract one verified reusable workflow from the current Codex task into a portable user skill. Use when the user explicitly asks to preserve the method.',
|
|
616
293
|
};
|
|
617
294
|
return special[targetName] || adaptHostText(String(sourceDescription || `${titleCase(targetName)} workflow for Codex.`), targetName)
|
|
618
295
|
.replace(/\s+/g, ' ')
|
|
@@ -633,21 +310,26 @@ function buildSkillMarkdown(sourceText, sourceName, targetName) {
|
|
|
633
310
|
}
|
|
634
311
|
|
|
635
312
|
function buildOpenAiYaml(name, description) {
|
|
636
|
-
const
|
|
637
|
-
COMMAND_NAMES.includes(name)
|
|
638
|
-
|| INTERNAL_SKILLS.has(name)
|
|
639
|
-
|| name === 'cc-collab'
|
|
640
|
-
|| name.startsWith('ultra-')
|
|
641
|
-
);
|
|
313
|
+
const policy = skillPolicy(name);
|
|
642
314
|
const short = description.replace(/\s+/g, ' ').trim().slice(0, 63).replace(/[\s.,;:]+$/, '');
|
|
643
|
-
|
|
315
|
+
const metadata = {
|
|
644
316
|
interface: {
|
|
645
317
|
display_name: titleCase(name),
|
|
646
318
|
short_description: short || `${titleCase(name)} for Codex`,
|
|
647
319
|
default_prompt: `Use $ultra-builder-pro:${name} for this task and follow its workflow.`,
|
|
648
320
|
},
|
|
649
|
-
policy: { allow_implicit_invocation:
|
|
650
|
-
}
|
|
321
|
+
policy: { allow_implicit_invocation: policy.allowImplicitInvocation },
|
|
322
|
+
};
|
|
323
|
+
if (policy.requiresUltraMcp) {
|
|
324
|
+
metadata.dependencies = {
|
|
325
|
+
tools: [{
|
|
326
|
+
type: 'mcp',
|
|
327
|
+
value: PLUGIN_NAME,
|
|
328
|
+
description: 'Ultra Builder Pro authoritative task and change runtime',
|
|
329
|
+
}],
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
return yaml.dump(metadata, { lineWidth: -1, noRefs: true });
|
|
651
333
|
}
|
|
652
334
|
|
|
653
335
|
function isTextFile(rel) {
|
|
@@ -718,7 +400,7 @@ function buildHooksManifest() {
|
|
|
718
400
|
{ hooks: [commandHook('workflow_resume.py', 10, 'Restoring Ultra workflow checkpoint')] },
|
|
719
401
|
],
|
|
720
402
|
Stop: [
|
|
721
|
-
{ hooks: [commandHook('pre_stop_check.py', 5, '
|
|
403
|
+
{ hooks: [commandHook('pre_stop_check.py', 5, 'Reporting Ultra workflow position')] },
|
|
722
404
|
],
|
|
723
405
|
SubagentStart: [
|
|
724
406
|
{ hooks: [commandHook('subagent_tracker.py', 5, 'Tracking Ultra subagent', 'start')] },
|
|
@@ -59,11 +59,12 @@ function renderHandbook(runtime) {
|
|
|
59
59
|
`- Workflow entry points: ${value.invocation}.`,
|
|
60
60
|
`- Collaboration boundary: ${value.collaboration}. The current host remains primary and owns final verification.`,
|
|
61
61
|
`- Coordination boundary: ${value.coordination}.`,
|
|
62
|
-
'- Authority: `.ultra/state.db` is the only durable Ultra authority for changes, tasks, sessions, events, incidents, projection state, telemetry, and review evidence. Generated JSON and Markdown are projections or workflow artifacts.',
|
|
63
|
-
'-
|
|
62
|
+
'- Authority: `.ultra/state.db` is the only durable Ultra authority for baselines, changes, tasks, sessions, events, incidents, projection state, telemetry, and review evidence. Generated JSON and Markdown are projections or workflow artifacts.',
|
|
63
|
+
'- Baseline boundary: `task.init_project` detects greenfield or brownfield work; `baseline.start`, `baseline.record`, and `baseline.converge` adopt the project without rewriting application code. An incomplete baseline is advisory during active work but blocks change convergence; normal HEAD or tracked-spec drift from that change is reconciled and health-checked atomically at archive.',
|
|
64
|
+
'- Context Spine boundary: `change.context` compiles role/gate readiness, required references, a fresh-context budget, public seam, verification command, and one next action. File, token, and context-share budgets are advisory attention signals, not refusal gates. Hooks inject only the DB-derived `change.breadcrumb`; missing required evidence or stale execution context must be recompiled.',
|
|
64
65
|
'- Specification learning boundary: stable implementation discoveries use approval-gated propose/approve-or-reject/apply transitions. Unresolved learning blocks convergence; review requires independent specification-fidelity and engineering-standards evidence.',
|
|
65
66
|
'- Memory and graph boundary: Ultra Builder Pro does not capture prompts, transcripts, observations, summaries, cross-session memory, or code-graph content. Separately installed providers own that data; Ultra may store only their metadata references in a change context manifest.',
|
|
66
|
-
'- Hook boundary: Ultra hooks observe workflow/change lifecycle only. Health/context may run when `.ultra/state.db` exists;
|
|
67
|
+
'- Hook boundary: Ultra hooks observe workflow/change lifecycle only. Health/context may run when `.ultra/state.db` exists; advisory warnings never reject work, and an incomplete workflow never traps session stop. Direct projection protection remains authoritative; compact and subagent recovery stays active-workflow scoped. Generic command blocking and post-edit policy stay in user or repository governance.',
|
|
67
68
|
'- Installation boundary: `ubp --doctor` is the read-only authority for installed asset provenance, content hashes, and host entry-point wiring; `system.doctor` remains scoped to project state and workflow recovery.',
|
|
68
69
|
'- Agent boundary: the bundled review and debugging agents are bounded workers. They use the current checkout and parent-supplied context, do not own private persistent state, and never replace the primary agent.',
|
|
69
70
|
'- Package boundary: only the twelve Ultra workflows, four internal review-rule skills, host-specific collaboration companions, and the minimal host bootstrap belong to this plugin. General browser, deployment, discovery, and framework skills must be installed from their owners.',
|
|
@@ -38,6 +38,18 @@ const COLLAB_SKILLS_BY_RUNTIME = Object.freeze({
|
|
|
38
38
|
kimi: Object.freeze(['cc-collab', 'codex-collab', 'ultra-verify']),
|
|
39
39
|
});
|
|
40
40
|
|
|
41
|
+
const MCP_DEPENDENT_SKILLS = Object.freeze([
|
|
42
|
+
'ultra-init',
|
|
43
|
+
'ultra-change',
|
|
44
|
+
'ultra-plan',
|
|
45
|
+
'ultra-dev',
|
|
46
|
+
'ultra-test',
|
|
47
|
+
'ultra-review',
|
|
48
|
+
'ultra-deliver',
|
|
49
|
+
'ultra-status',
|
|
50
|
+
'ultra-doctor',
|
|
51
|
+
]);
|
|
52
|
+
|
|
41
53
|
const RETIRED_SKILLS = Object.freeze([
|
|
42
54
|
'agent-browser',
|
|
43
55
|
'find-skills',
|
|
@@ -69,13 +81,25 @@ function isSupportedRuntime(runtime) {
|
|
|
69
81
|
return SUPPORTED_RUNTIMES.includes(runtime);
|
|
70
82
|
}
|
|
71
83
|
|
|
84
|
+
function skillPolicy(name) {
|
|
85
|
+
const packaged = SUPPORTED_RUNTIMES.some((runtime) => skillsForRuntime(runtime).includes(name));
|
|
86
|
+
if (!packaged) throw new Error(`unknown packaged Ultra skill: ${name}`);
|
|
87
|
+
return {
|
|
88
|
+
userInvocable: !INTERNAL_AGENT_SKILLS.includes(name),
|
|
89
|
+
allowImplicitInvocation: false,
|
|
90
|
+
requiresUltraMcp: MCP_DEPENDENT_SKILLS.includes(name),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
|
|
72
94
|
module.exports = {
|
|
73
95
|
CORE_PUBLIC_SKILLS,
|
|
74
96
|
INTERNAL_AGENT_SKILLS,
|
|
75
97
|
SUPPORTED_RUNTIMES,
|
|
76
98
|
COLLAB_SKILLS_BY_RUNTIME,
|
|
99
|
+
MCP_DEPENDENT_SKILLS,
|
|
77
100
|
RETIRED_SKILLS,
|
|
78
101
|
WORKFLOW_HOOK_FILES,
|
|
79
102
|
isSupportedRuntime,
|
|
103
|
+
skillPolicy,
|
|
80
104
|
skillsForRuntime,
|
|
81
105
|
};
|
|
@@ -34,6 +34,10 @@ test('renders one common contract with host-native invocation syntax', () => {
|
|
|
34
34
|
assert.match(rendered, /ultra-doctor/);
|
|
35
35
|
assert.match(rendered, /metadata references/);
|
|
36
36
|
assert.match(rendered, /Context Spine boundary/);
|
|
37
|
+
assert.match(rendered, /budgets are advisory attention signals/);
|
|
38
|
+
assert.match(rendered, /blocks change convergence/);
|
|
39
|
+
assert.match(rendered, /health-checked atomically at archive/);
|
|
40
|
+
assert.match(rendered, /never traps session stop/);
|
|
37
41
|
assert.match(rendered, /change\.breadcrumb/);
|
|
38
42
|
assert.match(rendered, /Specification learning boundary/);
|
|
39
43
|
assert.doesNotMatch(rendered, /\.ultra\/memory|memory\.retain|memory\.recall/);
|
|
@@ -11,8 +11,10 @@ const {
|
|
|
11
11
|
INTERNAL_AGENT_SKILLS,
|
|
12
12
|
SUPPORTED_RUNTIMES,
|
|
13
13
|
COLLAB_SKILLS_BY_RUNTIME,
|
|
14
|
+
MCP_DEPENDENT_SKILLS,
|
|
14
15
|
RETIRED_SKILLS,
|
|
15
16
|
WORKFLOW_HOOK_FILES,
|
|
17
|
+
skillPolicy,
|
|
16
18
|
skillsForRuntime,
|
|
17
19
|
} = require('../runtime-assets.cjs');
|
|
18
20
|
|
|
@@ -74,10 +76,15 @@ test('runtime asset manifest exposes only Ultra-owned core and internal skills',
|
|
|
74
76
|
}
|
|
75
77
|
});
|
|
76
78
|
|
|
77
|
-
test('
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
79
|
+
test('host invocation and MCP metadata live outside source SKILL frontmatter', () => {
|
|
80
|
+
const all = new Set(SUPPORTED_RUNTIMES.flatMap((runtime) => skillsForRuntime(runtime)));
|
|
81
|
+
for (const name of all) {
|
|
82
|
+
const policy = skillPolicy(name);
|
|
83
|
+
assert.equal(policy.allowImplicitInvocation, false, name);
|
|
84
|
+
assert.equal(policy.userInvocable, !INTERNAL_AGENT_SKILLS.includes(name), name);
|
|
85
|
+
assert.equal(policy.requiresUltraMcp, MCP_DEPENDENT_SKILLS.includes(name), name);
|
|
86
|
+
}
|
|
87
|
+
assert.throws(() => skillPolicy('not-packaged'), /unknown packaged Ultra skill/);
|
|
81
88
|
});
|
|
82
89
|
|
|
83
90
|
test('workflow hook allowlist contains no memory, prompt capture, or generic policy hook', () => {
|
package/adapters/claude.js
CHANGED
|
@@ -15,10 +15,12 @@ const {
|
|
|
15
15
|
writeAtomic,
|
|
16
16
|
} = require('./_shared/file-ops.cjs');
|
|
17
17
|
const { buildMcpRuntime } = require('./_shared/codex-assets.cjs');
|
|
18
|
+
const { parse: parseFrontmatter, serialize: serializeFrontmatter } = require('./_shared/frontmatter.cjs');
|
|
18
19
|
const provenance = require('./_shared/provenance.cjs');
|
|
19
20
|
const {
|
|
20
21
|
CORE_PUBLIC_SKILLS,
|
|
21
22
|
WORKFLOW_HOOK_FILES,
|
|
23
|
+
skillPolicy,
|
|
22
24
|
skillsForRuntime,
|
|
23
25
|
} = require('./_shared/runtime-assets.cjs');
|
|
24
26
|
|
|
@@ -46,12 +48,33 @@ function resolveRepoRoot(ctx = {}) {
|
|
|
46
48
|
return ctx.repoRoot || path.resolve(__dirname, '..');
|
|
47
49
|
}
|
|
48
50
|
|
|
49
|
-
function
|
|
51
|
+
function copySkills(repoRoot, target, names) {
|
|
50
52
|
const copied = [];
|
|
51
53
|
for (const name of names) {
|
|
52
|
-
const source = path.join(repoRoot,
|
|
53
|
-
if (!fs.existsSync(source)) throw new Error(`missing allowlisted Claude
|
|
54
|
-
const files = copyTree(source, path.join(target,
|
|
54
|
+
const source = path.join(repoRoot, 'skills', name);
|
|
55
|
+
if (!fs.existsSync(source)) throw new Error(`missing allowlisted Claude skill: ${name}`);
|
|
56
|
+
const files = copyTree(source, path.join(target, 'skills', name), {
|
|
57
|
+
transform(buf, rel) {
|
|
58
|
+
if (rel !== 'SKILL.md') return buf;
|
|
59
|
+
const { fm, body } = parseFrontmatter(buf.toString('utf8'));
|
|
60
|
+
if (!fm) throw new Error(`missing frontmatter in Claude skill: ${name}`);
|
|
61
|
+
let adaptedBody = body;
|
|
62
|
+
if (name === 'learn') {
|
|
63
|
+
adaptedBody = adaptedBody.replaceAll("current host's user skill directory", '`~/.claude/skills`');
|
|
64
|
+
}
|
|
65
|
+
if (name === 'ultra-review') {
|
|
66
|
+
adaptedBody = adaptedBody.replaceAll(
|
|
67
|
+
"the current host's native bounded-worker mechanism",
|
|
68
|
+
'Claude Code Task workers using the installed review agent definitions',
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
return Buffer.from(serializeFrontmatter({
|
|
72
|
+
name,
|
|
73
|
+
description: fm.description,
|
|
74
|
+
'user-invocable': skillPolicy(name).userInvocable,
|
|
75
|
+
}, adaptedBody));
|
|
76
|
+
},
|
|
77
|
+
});
|
|
55
78
|
copied.push(...files.map((rel) => path.join(name, rel)));
|
|
56
79
|
}
|
|
57
80
|
return copied;
|
|
@@ -126,7 +149,7 @@ function install(ctx = {}) {
|
|
|
126
149
|
|
|
127
150
|
const report = { target, copied: {}, config: { updated: false } };
|
|
128
151
|
report.copied.commands = copyCommands(repoRoot, target);
|
|
129
|
-
report.copied.skills =
|
|
152
|
+
report.copied.skills = copySkills(repoRoot, target, skillsForRuntime('claude'));
|
|
130
153
|
report.copied.agents = copyTree(path.join(repoRoot, 'agents'), path.join(target, 'agents'));
|
|
131
154
|
|
|
132
155
|
ensureDir(path.join(target, 'hooks'));
|