ultra-builder-pro-cli 0.5.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.
- package/.ultra-template/delivery-report.json +9 -0
- package/.ultra-template/docs/research/README.md +53 -0
- package/.ultra-template/specs/architecture.md +250 -0
- package/.ultra-template/specs/discovery.md +248 -0
- package/.ultra-template/specs/product.md +223 -0
- package/.ultra-template/tasks/contexts/TEMPLATE.md +57 -0
- package/.ultra-template/tasks/tasks.json +33 -0
- package/.ultra-template/test-report.json +8 -0
- package/CHANGELOG.md +194 -0
- package/LICENSE +21 -0
- package/README.md +187 -0
- package/adapters/_shared/codex-assets.cjs +1128 -0
- package/adapters/_shared/codex-ultra-tools-entry.cjs +11 -0
- package/adapters/_shared/file-ops.cjs +115 -0
- package/adapters/_shared/frontmatter.cjs +52 -0
- package/adapters/_shared/handbook.cjs +144 -0
- package/adapters/_shared/md-to-toml.cjs +54 -0
- package/adapters/_shared/path-rewrite.cjs +79 -0
- package/adapters/_shared/rtk-detect.cjs +86 -0
- package/adapters/_shared/runtime-assets.cjs +70 -0
- package/adapters/_shared/settings-merge.cjs +76 -0
- package/adapters/_shared/tests/file-ops.test.cjs +54 -0
- package/adapters/_shared/tests/frontmatter.test.cjs +47 -0
- package/adapters/_shared/tests/handbook.test.cjs +86 -0
- package/adapters/_shared/tests/md-to-toml.test.cjs +48 -0
- package/adapters/_shared/tests/path-rewrite.test.cjs +60 -0
- package/adapters/_shared/tests/resolve-target.test.cjs +85 -0
- package/adapters/_shared/tests/rtk-detect.test.cjs +116 -0
- package/adapters/_shared/tests/runtime-assets.test.cjs +107 -0
- package/adapters/_shared/tests/settings-merge.test.cjs +85 -0
- package/adapters/_shared/tests/validate.test.cjs +30 -0
- package/adapters/_shared/validate.cjs +24 -0
- package/adapters/claude.js +182 -0
- package/adapters/codex.js +385 -0
- package/adapters/gemini.js +204 -0
- package/adapters/opencode.js +506 -0
- package/adapters/tests/claude.test.cjs +117 -0
- package/adapters/tests/codex-hook.test.cjs +90 -0
- package/adapters/tests/codex.test.cjs +356 -0
- package/adapters/tests/gemini.test.cjs +112 -0
- package/adapters/tests/opencode.test.cjs +246 -0
- package/agents/code-reviewer.md +102 -0
- package/agents/debugger.md +127 -0
- package/agents/review-code.md +125 -0
- package/agents/review-comments.md +98 -0
- package/agents/review-coordinator.md +146 -0
- package/agents/review-design.md +133 -0
- package/agents/review-errors.md +87 -0
- package/agents/review-tests.md +93 -0
- package/agents/tdd-runner.md +92 -0
- package/bin/handbook.js +54 -0
- package/bin/install.js +254 -0
- package/bin/orchestrator.js +214 -0
- package/commands/learn.md +41 -0
- package/commands/ultra-deliver.md +45 -0
- package/commands/ultra-dev.md +50 -0
- package/commands/ultra-init.md +51 -0
- package/commands/ultra-plan.md +49 -0
- package/commands/ultra-research.md +59 -0
- package/commands/ultra-status.md +46 -0
- package/commands/ultra-test.md +48 -0
- package/commands/ultra-think.md +45 -0
- package/docs/AGENT-CONTEXT.md +143 -0
- package/docs/ARCHITECTURE.md +197 -0
- package/docs/COMMIT-HASH-BACKFILL.md +101 -0
- package/docs/LEGACY-HERMES.md +1175 -0
- package/docs/PLAN.zh-CN.md +1683 -0
- package/docs/ROADMAP.md +102 -0
- package/docs/RUNTIME-COMPAT-MATRIX.md +98 -0
- package/docs/STATE-DB-ACCESS-POLICY.md +109 -0
- package/docs/USER-HANDBOOK-CONTRACT.md +61 -0
- package/hooks/README.md +24 -0
- package/hooks/active_task_context.py +44 -0
- package/hooks/adapters/codex.py +302 -0
- package/hooks/health_check.py +61 -0
- package/hooks/pre_stop_check.py +56 -0
- package/hooks/subagent_tracker.py +116 -0
- package/hooks/workflow_checkpoint.py +56 -0
- package/hooks/workflow_context.py +63 -0
- package/hooks/workflow_resume.py +50 -0
- package/mcp-server/lib/init-project.cjs +162 -0
- package/mcp-server/lib/llm-client.cjs +157 -0
- package/mcp-server/lib/llm-client.test.cjs +156 -0
- package/mcp-server/lib/plan-store.cjs +96 -0
- package/mcp-server/lib/plan-store.test.cjs +132 -0
- package/mcp-server/lib/prd-parser.cjs +110 -0
- package/mcp-server/lib/prd-parser.test.cjs +171 -0
- package/mcp-server/lib/pricing.cjs +53 -0
- package/mcp-server/lib/projector.cjs +158 -0
- package/mcp-server/lib/state-db.cjs +113 -0
- package/mcp-server/lib/state-db.test.cjs +116 -0
- package/mcp-server/lib/state-ops.cjs +725 -0
- package/mcp-server/lib/task-expander.cjs +123 -0
- package/mcp-server/lib/task-expander.test.cjs +253 -0
- package/mcp-server/lib/telemetry.cjs +72 -0
- package/mcp-server/lib/topo.cjs +131 -0
- package/mcp-server/lib/topo.test.cjs +158 -0
- package/mcp-server/server.cjs +482 -0
- package/mcp-server/tests/circuit-breaker.test.cjs +125 -0
- package/mcp-server/tests/commit-hash-flow.test.cjs +117 -0
- package/mcp-server/tests/concurrency-update.test.cjs +96 -0
- package/mcp-server/tests/concurrency.test.cjs +112 -0
- package/mcp-server/tests/db-ops.test.cjs +117 -0
- package/mcp-server/tests/init-project.test.cjs +141 -0
- package/mcp-server/tests/migrate.test.cjs +144 -0
- package/mcp-server/tests/projector.test.cjs +130 -0
- package/mcp-server/tests/server-contract.test.cjs +750 -0
- package/mcp-server/tests/staleness.test.cjs +190 -0
- package/mcp-server/tests/state-ops.test.cjs +286 -0
- package/mcp-server/tests/tagged-tasks.test.cjs +163 -0
- package/mcp-server/tests/telemetry.test.cjs +205 -0
- package/orchestrator/auto-merge.cjs +109 -0
- package/orchestrator/code-graph-watcher.cjs +121 -0
- package/orchestrator/daemon.cjs +112 -0
- package/orchestrator/dispatch-rules.cjs +93 -0
- package/orchestrator/parallel-orchestrator.cjs +195 -0
- package/orchestrator/planner/expand-prompt.cjs +62 -0
- package/orchestrator/planner/expand-prompt.test.cjs +52 -0
- package/orchestrator/planner/plan-builder.cjs +116 -0
- package/orchestrator/planner/plan-builder.test.cjs +165 -0
- package/orchestrator/planner/prd-prompt.cjs +44 -0
- package/orchestrator/planner/prd-prompt.test.cjs +30 -0
- package/orchestrator/recovery.cjs +70 -0
- package/orchestrator/session-runner.cjs +224 -0
- package/orchestrator/skill-miner.cjs +133 -0
- package/orchestrator/tests/auto-merge.test.cjs +216 -0
- package/orchestrator/tests/code-graph-watcher.test.cjs +183 -0
- package/orchestrator/tests/daemon.test.cjs +260 -0
- package/orchestrator/tests/dispatch-rules.test.cjs +122 -0
- package/orchestrator/tests/parallel-orchestrator.test.cjs +233 -0
- package/orchestrator/tests/phase-8b-gate.test.cjs +183 -0
- package/orchestrator/tests/recovery.test.cjs +190 -0
- package/orchestrator/tests/session-runner.test.cjs +314 -0
- package/orchestrator/tests/skill-miner.test.cjs +147 -0
- package/orchestrator/tests/worktree-manager.test.cjs +148 -0
- package/orchestrator/worktree-manager.cjs +131 -0
- package/output-styles/coding-vibes.md +67 -0
- package/output-styles/structural-thinking.md +61 -0
- package/package.json +109 -0
- package/settings.json +8 -0
- package/skills/cc-collab/SKILL.md +41 -0
- package/skills/code-review-expert/SKILL.md +118 -0
- package/skills/code-review-expert/references/code-quality-checklist.md +112 -0
- package/skills/code-review-expert/references/integration-checklist.md +46 -0
- package/skills/code-review-expert/references/removal-plan.md +52 -0
- package/skills/code-review-expert/references/security-checklist.md +100 -0
- package/skills/code-review-expert/references/solid-checklist.md +65 -0
- package/skills/codex-collab/SKILL.md +52 -0
- package/skills/codex-collab/evals/evals.json +40 -0
- package/skills/gemini-collab/SKILL.md +51 -0
- package/skills/gemini-collab/evals/evals.json +42 -0
- package/skills/integration-rules/SKILL.md +71 -0
- package/skills/learn/SKILL.md +117 -0
- package/skills/security-rules/SKILL.md +60 -0
- package/skills/testing-rules/SKILL.md +56 -0
- package/skills/ultra-deliver/SKILL.md +171 -0
- package/skills/ultra-dev/SKILL.md +324 -0
- package/skills/ultra-init/SKILL.md +148 -0
- package/skills/ultra-plan/SKILL.md +314 -0
- package/skills/ultra-research/SKILL.md +156 -0
- package/skills/ultra-research/steps/step-00-problem-validation.md +154 -0
- package/skills/ultra-research/steps/step-01-opportunity-discovery.md +172 -0
- package/skills/ultra-research/steps/step-02-market-assessment.md +195 -0
- package/skills/ultra-research/steps/step-03-competitive-landscape.md +197 -0
- package/skills/ultra-research/steps/step-04-product-strategy.md +196 -0
- package/skills/ultra-research/steps/step-05-assumptions-validation.md +234 -0
- package/skills/ultra-research/steps/step-10-user-personas.md +169 -0
- package/skills/ultra-research/steps/step-11-user-scenarios.md +181 -0
- package/skills/ultra-research/steps/step-20-user-stories.md +156 -0
- package/skills/ultra-research/steps/step-21-features-scope.md +157 -0
- package/skills/ultra-research/steps/step-22-success-metrics.md +195 -0
- package/skills/ultra-research/steps/step-30-architecture-context.md +154 -0
- package/skills/ultra-research/steps/step-31-solution-strategy.md +172 -0
- package/skills/ultra-research/steps/step-32-building-blocks.md +188 -0
- package/skills/ultra-research/steps/step-40-deployment.md +123 -0
- package/skills/ultra-research/steps/step-41-quality-risks.md +135 -0
- package/skills/ultra-research/steps/step-99-synthesis.md +188 -0
- package/skills/ultra-review/SKILL.md +437 -0
- package/skills/ultra-review/references/unified-schema.md +127 -0
- package/skills/ultra-review/scripts/review_verdict_update.py +99 -0
- package/skills/ultra-review/scripts/review_wait.py +120 -0
- package/skills/ultra-status/SKILL.md +162 -0
- package/skills/ultra-test/SKILL.md +195 -0
- package/skills/ultra-think/SKILL.md +109 -0
- package/skills/ultra-verify/SKILL.md +111 -0
- package/skills/ultra-verify/evals/evals.json +51 -0
- package/skills/ultra-verify/references/confidence-system.md +38 -0
- package/skills/ultra-verify/references/cross-verify-modes.md +73 -0
- package/skills/ultra-verify/scripts/verify_wait.py +131 -0
- package/spec/cli-protocol.md +118 -0
- package/spec/mcp-tools.yaml +658 -0
- package/spec/schemas/command-manifest.schema.json +47 -0
- package/spec/schemas/context-file.v4.5.schema.json +54 -0
- package/spec/schemas/mcp-tools.schema.json +136 -0
- package/spec/schemas/skill-manifest.schema.json +94 -0
- package/spec/schemas/state-db.sql +154 -0
- package/spec/schemas/tasks.v4.5.schema.json +66 -0
- package/ultra-tools/cli.cjs +121 -0
- package/ultra-tools/commands/db.cjs +175 -0
- package/ultra-tools/commands/legacy-memory.cjs +159 -0
- package/ultra-tools/commands/migrate.cjs +354 -0
- package/ultra-tools/commands/session.cjs +180 -0
- package/ultra-tools/commands/status.cjs +158 -0
- package/ultra-tools/commands/task.cjs +95 -0
- package/ultra-tools/legacy-memory.test.cjs +80 -0
- package/ultra-tools/status-command.test.cjs +132 -0
|
@@ -0,0 +1,1128 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const crypto = require('node:crypto');
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const os = require('node:os');
|
|
6
|
+
const path = require('node:path');
|
|
7
|
+
const { spawnSync } = require('node:child_process');
|
|
8
|
+
const yaml = require('js-yaml');
|
|
9
|
+
const {
|
|
10
|
+
CORE_PUBLIC_SKILLS,
|
|
11
|
+
INTERNAL_AGENT_SKILLS,
|
|
12
|
+
WORKFLOW_HOOK_FILES,
|
|
13
|
+
skillsForRuntime,
|
|
14
|
+
} = require('./runtime-assets.cjs');
|
|
15
|
+
|
|
16
|
+
const { parse: parseFrontmatter } = require('./frontmatter.cjs');
|
|
17
|
+
const {
|
|
18
|
+
copyTree,
|
|
19
|
+
ensureDir,
|
|
20
|
+
listRelative,
|
|
21
|
+
removeTree,
|
|
22
|
+
writeAtomic,
|
|
23
|
+
} = require('./file-ops.cjs');
|
|
24
|
+
|
|
25
|
+
const PLUGIN_NAME = 'ultra-builder-pro';
|
|
26
|
+
const MANAGED_MARKER = 'Managed by Ultra Builder Pro Codex adapter.';
|
|
27
|
+
const CODEX_NATIVE_MCP_REPLACEMENTS = Object.freeze({
|
|
28
|
+
'review.run': {
|
|
29
|
+
surface: 'native_custom_agents',
|
|
30
|
+
replacement: '$ultra-builder-pro:ultra-review with the installed review-* agents',
|
|
31
|
+
},
|
|
32
|
+
'review.verdict': {
|
|
33
|
+
surface: 'native_custom_agents',
|
|
34
|
+
replacement: 'review-coordinator synthesis using the Ultra unified review artifact',
|
|
35
|
+
},
|
|
36
|
+
'impact.radius': {
|
|
37
|
+
surface: 'codex_code_discovery',
|
|
38
|
+
replacement: 'indexed code graph tools when current, otherwise targeted repository reads',
|
|
39
|
+
},
|
|
40
|
+
'impact.changes': {
|
|
41
|
+
surface: 'codex_code_discovery',
|
|
42
|
+
replacement: 'git diff plus indexed code graph tools when current',
|
|
43
|
+
},
|
|
44
|
+
'impact.dependents': {
|
|
45
|
+
surface: 'codex_code_discovery',
|
|
46
|
+
replacement: 'indexed caller/dependency tracing when current, otherwise targeted repository search',
|
|
47
|
+
},
|
|
48
|
+
'skill.resolve': {
|
|
49
|
+
surface: 'plugin_skill_discovery',
|
|
50
|
+
replacement: 'Codex plugin skill discovery with explicit $ultra-builder-pro:<skill> invocation',
|
|
51
|
+
},
|
|
52
|
+
'skill.manifest': {
|
|
53
|
+
surface: 'plugin_skill_discovery',
|
|
54
|
+
replacement: 'the installed plugin skill SKILL.md and agents/openai.yaml contract',
|
|
55
|
+
},
|
|
56
|
+
'ask.question': {
|
|
57
|
+
surface: 'direct_user_interaction',
|
|
58
|
+
replacement: 'ask the user directly, or request_user_input when that Codex surface is available',
|
|
59
|
+
},
|
|
60
|
+
'ask.menu': {
|
|
61
|
+
surface: 'direct_user_interaction',
|
|
62
|
+
replacement: 'present a concise choice directly, or request_user_input when that Codex surface is available',
|
|
63
|
+
},
|
|
64
|
+
});
|
|
65
|
+
const COMMAND_NAMES = Object.freeze(CORE_PUBLIC_SKILLS.filter((name) => name !== 'ultra-review'));
|
|
66
|
+
const SKILL_REFERENCE_NAMES = Object.freeze([
|
|
67
|
+
...COMMAND_NAMES,
|
|
68
|
+
'cc-collab',
|
|
69
|
+
'gemini-collab',
|
|
70
|
+
'ultra-review',
|
|
71
|
+
'ultra-verify',
|
|
72
|
+
]);
|
|
73
|
+
const INTERNAL_SKILLS = new Set(INTERNAL_AGENT_SKILLS);
|
|
74
|
+
const CODEX_PRIMARY_SKILLS = new Set([...COMMAND_NAMES, 'ultra-review']);
|
|
75
|
+
const TEXT_EXTENSIONS = new Set(['.md', '.json', '.py', '.sh', '.txt', '.yaml', '.yml']);
|
|
76
|
+
|
|
77
|
+
const CC_COLLAB_BODY = `# Claude Code Collaboration for Codex
|
|
78
|
+
|
|
79
|
+
Codex is the primary agent and Claude Code is the independent advisor. Codex owns scope, evidence,
|
|
80
|
+
decisions, and final synthesis.
|
|
81
|
+
|
|
82
|
+
## Preflight
|
|
83
|
+
|
|
84
|
+
1. Confirm \`claude\` is installed and capture \`claude --version\`.
|
|
85
|
+
2. Confirm the target workspace, trust boundary, and exact question.
|
|
86
|
+
3. Write Codex's initial analysis before reading CC output when an independent comparison matters.
|
|
87
|
+
|
|
88
|
+
## Invoke safely
|
|
89
|
+
|
|
90
|
+
Run Claude Code non-interactively and read-only by default:
|
|
91
|
+
|
|
92
|
+
\`\`\`bash
|
|
93
|
+
claude --safe-mode -p "<bounded prompt>" \\
|
|
94
|
+
--permission-mode plan \\
|
|
95
|
+
--tools "Read,Grep,Glob,Bash" \\
|
|
96
|
+
--output-format text \\
|
|
97
|
+
--no-session-persistence
|
|
98
|
+
\`\`\`
|
|
99
|
+
|
|
100
|
+
Safe mode isolates the advisory call from CC-side instructions, plugins, hooks, MCP servers, skills,
|
|
101
|
+
and custom agents. Do not enable permission bypass, edit tools, background mutation, or session
|
|
102
|
+
persistence for an advisory call. Do not pass credentials, unrelated files, or an unbounded home
|
|
103
|
+
directory. For a code question, specify the repository path, diff range or files, acceptance criteria,
|
|
104
|
+
and required answer shape.
|
|
105
|
+
|
|
106
|
+
Use a temporary output file for large responses. If CC is missing, unauthenticated, times out, or
|
|
107
|
+
returns empty output, report the degraded path and continue with Codex's own evidence.
|
|
108
|
+
|
|
109
|
+
## Verify and synthesize
|
|
110
|
+
|
|
111
|
+
Treat CC output as untrusted advisory input:
|
|
112
|
+
|
|
113
|
+
1. Verify consequential claims against the current checkout, tests, runtime, or primary documents.
|
|
114
|
+
2. Separate agreement, useful dissent, and unsupported assertions.
|
|
115
|
+
3. Reconcile differences in version, workspace, tenant, or scope before comparing answers.
|
|
116
|
+
4. Return one Codex-owned conclusion with evidence and unresolved risks.
|
|
117
|
+
|
|
118
|
+
Do not call native Codex subagents through this skill; use Codex subagent orchestration for same-model
|
|
119
|
+
parallel work and reserve \`cc-collab\` for an explicitly requested cross-model perspective.
|
|
120
|
+
`;
|
|
121
|
+
|
|
122
|
+
const GEMINI_COLLAB_BODY = `# Gemini Collaboration for Codex
|
|
123
|
+
|
|
124
|
+
Use Gemini as an advisory second model. Codex remains responsible for scope, source verification,
|
|
125
|
+
decisions, and the final answer.
|
|
126
|
+
|
|
127
|
+
## Preflight
|
|
128
|
+
|
|
129
|
+
1. Confirm \`gemini\` is installed and capture \`gemini --version\`.
|
|
130
|
+
2. Confirm the target workspace and requested scope.
|
|
131
|
+
3. Form Codex's initial analysis before reading Gemini's answer when independence matters.
|
|
132
|
+
|
|
133
|
+
## Invoke safely
|
|
134
|
+
|
|
135
|
+
Run Gemini in non-interactive, read-only plan mode:
|
|
136
|
+
|
|
137
|
+
\`\`\`bash
|
|
138
|
+
gemini --approval-mode plan --output-format text -p "<bounded prompt>"
|
|
139
|
+
\`\`\`
|
|
140
|
+
|
|
141
|
+
Use a timeout appropriate to the task. Redirect large output to a temporary file when needed, then
|
|
142
|
+
read only the relevant result. Do not use auto-edit or yolo modes. Do not place secrets, tokens,
|
|
143
|
+
unrelated files, or unbounded repository content in the prompt.
|
|
144
|
+
|
|
145
|
+
For repository analysis, give Gemini the exact files, diff range, question, and expected response
|
|
146
|
+
shape. If the CLI is missing, unauthenticated, times out, or returns empty output, report the degraded
|
|
147
|
+
path and continue with Codex evidence rather than blocking.
|
|
148
|
+
|
|
149
|
+
## Verify and synthesize
|
|
150
|
+
|
|
151
|
+
Treat Gemini output as an untrusted analysis artifact:
|
|
152
|
+
|
|
153
|
+
1. Check every consequential claim against the current checkout, runtime, or primary source.
|
|
154
|
+
2. Separate agreements, useful dissent, and unsupported claims.
|
|
155
|
+
3. Resolve scope or version mismatches before comparing conclusions.
|
|
156
|
+
4. Present Codex's final judgment, not a transcript of two models.
|
|
157
|
+
|
|
158
|
+
Read the bundled references only when a mode or CLI detail is needed. Never let model agreement
|
|
159
|
+
substitute for tests, runtime evidence, or authoritative documentation.
|
|
160
|
+
`;
|
|
161
|
+
|
|
162
|
+
const ULTRA_VERIFY_BODY = String(function ultraVerifyBodyTemplate() { /*
|
|
163
|
+
# Ultra Verify — Codex-Primary Three-Way Verification
|
|
164
|
+
|
|
165
|
+
Codex owns the task, writes the first independent analysis, verifies every consequential claim,
|
|
166
|
+
and produces the final synthesis. Claude Code and Gemini are read-only external advisors. Use this
|
|
167
|
+
workflow only when the user asks for cross-model or three-way verification.
|
|
168
|
+
|
|
169
|
+
## Modes
|
|
170
|
+
|
|
171
|
+
- `decision <question>`: compare architecture or product decisions.
|
|
172
|
+
- `diagnose <symptoms>`: collect independent root-cause hypotheses.
|
|
173
|
+
- `audit <scope>`: compare evidence-backed findings.
|
|
174
|
+
- `estimate <task>`: compare estimates and their assumptions.
|
|
175
|
+
|
|
176
|
+
## Preconditions
|
|
177
|
+
|
|
178
|
+
1. Confirm `claude --version` and `gemini --version`.
|
|
179
|
+
2. Define the exact workspace, scope, evidence standard, and expected answer shape.
|
|
180
|
+
3. Do not send secrets, unrelated files, or an unbounded home directory to either advisor.
|
|
181
|
+
|
|
182
|
+
## Workflow
|
|
183
|
+
|
|
184
|
+
### 1. Create the session and write Codex's independent view
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
SESSION_ID="$(date +%Y%m%d-%H%M%S)-verify-<mode>"
|
|
188
|
+
SESSION_PATH=".ultra/collab/${SESSION_ID}"
|
|
189
|
+
mkdir -p "${SESSION_PATH}"
|
|
190
|
+
```
|
|
191
|
+
|
|
192
|
+
Before invoking either advisor, write the evidence-backed Codex analysis to
|
|
193
|
+
`${SESSION_PATH}/codex-analysis.md`. This ordering is mandatory because it prevents the external
|
|
194
|
+
answers from priming the primary analysis.
|
|
195
|
+
|
|
196
|
+
### 2. Launch Claude Code and Gemini concurrently
|
|
197
|
+
|
|
198
|
+
Give both advisors the same bounded raw question and evidence, without Codex's conclusions.
|
|
199
|
+
|
|
200
|
+
Claude Code:
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
claude --safe-mode -p "<BOUNDED_PROMPT>" \\
|
|
204
|
+
--permission-mode plan \\
|
|
205
|
+
--tools "Read,Grep,Glob,Bash" \\
|
|
206
|
+
--output-format text \\
|
|
207
|
+
--no-session-persistence \\
|
|
208
|
+
> "${SESSION_PATH}/claude-output.md" \\
|
|
209
|
+
2> "${SESSION_PATH}/claude-error.log"
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Gemini:
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
gemini --approval-mode plan --output-format text -p "<BOUNDED_PROMPT>" \\
|
|
216
|
+
> "${SESSION_PATH}/gemini-output.md" \\
|
|
217
|
+
2> "${SESSION_PATH}/gemini-error.log"
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
Start the two commands with parallel `exec_command` calls and a short initial yield. If a command
|
|
221
|
+
returns a live session id, poll it with `write_stdin` in bounded intervals. Do not use YOLO,
|
|
222
|
+
auto-edit, permission bypass, or write-capable external tools.
|
|
223
|
+
|
|
224
|
+
### 3. Collect only completed outputs
|
|
225
|
+
|
|
226
|
+
Wait for both CLI sessions to finish or reach their explicit timeout. The bundled
|
|
227
|
+
`scripts/verify_wait.py` can verify file stability for automation, but Codex must not perform one
|
|
228
|
+
blocking wait longer than 60 seconds. Read an output only when it is non-empty; retain the matching
|
|
229
|
+
error log as evidence when a CLI fails.
|
|
230
|
+
|
|
231
|
+
### 4. Verify and synthesize
|
|
232
|
+
|
|
233
|
+
Compare `codex-analysis.md`, `claude-output.md`, and `gemini-output.md`:
|
|
234
|
+
|
|
235
|
+
1. Verify claims against the current checkout, runtime, tests, or primary documentation.
|
|
236
|
+
2. Separate consensus, majority views, useful dissent, and unsupported assertions.
|
|
237
|
+
3. Explain scope, version, or assumption differences before scoring agreement.
|
|
238
|
+
4. Write `${SESSION_PATH}/synthesis.md` and `metadata.json`, then present one Codex-owned answer.
|
|
239
|
+
|
|
240
|
+
Use the bundled confidence rules. Three agreeing, independently verified views are consensus; two
|
|
241
|
+
are a majority; three materially different answers are no consensus and require decomposition or
|
|
242
|
+
more evidence. Model agreement never overrides failing tests or authoritative runtime evidence.
|
|
243
|
+
|
|
244
|
+
## Degraded operation
|
|
245
|
+
|
|
246
|
+
- One advisor fails: continue with Codex plus the available advisor and name the missing view.
|
|
247
|
+
- Both advisors fail: return Codex-only analysis with an explicit single-source warning.
|
|
248
|
+
- Never block the user's task solely because an external CLI is absent, unauthenticated, or slow.
|
|
249
|
+
|
|
250
|
+
## Session files
|
|
251
|
+
|
|
252
|
+
```text
|
|
253
|
+
.ultra/collab/<SESSION_ID>/
|
|
254
|
+
codex-analysis.md
|
|
255
|
+
claude-output.md
|
|
256
|
+
claude-error.log
|
|
257
|
+
gemini-output.md
|
|
258
|
+
gemini-error.log
|
|
259
|
+
metadata.json
|
|
260
|
+
synthesis.md
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
Read the bundled references for mode-specific prompts, scoring, metadata, and automation details.
|
|
264
|
+
*/ }).match(/\/\*([\s\S]*?)\*\//)[1].trim();
|
|
265
|
+
|
|
266
|
+
const ULTRA_VERIFY_FLOW = String(function ultraVerifyFlowTemplate() { /*
|
|
267
|
+
# Codex-Native Orchestration Flow
|
|
268
|
+
|
|
269
|
+
## 1. Primary analysis
|
|
270
|
+
|
|
271
|
+
Create `.ultra/collab/<SESSION_ID>/` and write `codex-analysis.md` before reading any external
|
|
272
|
+
answer. Record the mode, scope, checkout, and evidence boundary.
|
|
273
|
+
|
|
274
|
+
## 2. Parallel advisors
|
|
275
|
+
|
|
276
|
+
Launch Claude Code in `--safe-mode --permission-mode plan` and Gemini in
|
|
277
|
+
`--approval-mode plan` through separate `exec_command` calls. Redirect their output to
|
|
278
|
+
`claude-output.md` and `gemini-output.md`. If a call yields a session id, poll with
|
|
279
|
+
`write_stdin` in bounded intervals; do not grant either advisor mutation authority.
|
|
280
|
+
|
|
281
|
+
## 3. Completion gate
|
|
282
|
+
|
|
283
|
+
Proceed only after both sessions have completed or timed out. For automation, run:
|
|
284
|
+
|
|
285
|
+
```bash
|
|
286
|
+
python3 ~/plugins/ultra-builder-pro/skills/ultra-verify/scripts/verify_wait.py \\
|
|
287
|
+
"${SESSION_PATH}" --timeout 1200
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
Run the waiter as a yielded exec session and poll it; never hold one blocking tool call for more
|
|
291
|
+
than 60 seconds. Its JSON reports `claude` and `gemini` as `complete`, `failed`, `empty`, or
|
|
292
|
+
`pending`.
|
|
293
|
+
|
|
294
|
+
## 4. Synthesis
|
|
295
|
+
|
|
296
|
+
Read `codex-analysis.md` plus each completed advisor output. Verify consequential claims, compute
|
|
297
|
+
consensus using `confidence-system.md`, and write `synthesis.md` plus:
|
|
298
|
+
|
|
299
|
+
```json
|
|
300
|
+
{
|
|
301
|
+
"id": "<SESSION_ID>",
|
|
302
|
+
"agent": "ultra-verify",
|
|
303
|
+
"mode": "<mode>",
|
|
304
|
+
"models": {"codex": "<primary>", "claude": "<advisor>", "gemini": "<advisor>"},
|
|
305
|
+
"scope": "<scope>",
|
|
306
|
+
"timestamp": "<ISO 8601>",
|
|
307
|
+
"confidence": "<consensus|majority|no_consensus>",
|
|
308
|
+
"degraded": false
|
|
309
|
+
}
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
If one advisor fails, cap the result at majority and name the missing perspective. If both fail,
|
|
313
|
+
set `degraded: true`, `agents_responded: ["codex"]`, and mark the result single-source.
|
|
314
|
+
*/ }).match(/\/\*([\s\S]*?)\*\//)[1].trim();
|
|
315
|
+
|
|
316
|
+
function titleCase(name) {
|
|
317
|
+
const special = {
|
|
318
|
+
'ai-collab-base': 'AI Collaboration Base',
|
|
319
|
+
'cc-collab': 'Claude Code Collaboration',
|
|
320
|
+
'gemini-collab': 'Gemini Collaboration',
|
|
321
|
+
'use-railway': 'Use Railway',
|
|
322
|
+
};
|
|
323
|
+
if (special[name]) return special[name];
|
|
324
|
+
return name.split('-').map((part) => part ? part[0].toUpperCase() + part.slice(1) : part).join(' ');
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
function replaceSlashCommand(text, command, replacement) {
|
|
328
|
+
const escaped = command.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
329
|
+
return text.replace(
|
|
330
|
+
new RegExp(`(^|[\\s\\x60(>])/${escaped}(?=$|[\\s\\x60,.;):])`, 'gm'),
|
|
331
|
+
(_match, prefix) => `${prefix}${replacement}`,
|
|
332
|
+
);
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function adaptCodexPrimaryText(input, skillName) {
|
|
336
|
+
let text = String(input);
|
|
337
|
+
text = text.replaceAll('mcp__claude-in-chrome__*', 'the available Codex browser verification tools');
|
|
338
|
+
text = text.replaceAll('claude_md_rule', 'agents_md_rule');
|
|
339
|
+
text = text.replaceAll('claude-opus-4-6', '<codex-model>');
|
|
340
|
+
text = text.replaceAll('Claude', 'Codex');
|
|
341
|
+
text = text.replaceAll('TaskCreate/TaskUpdate', 'the Codex plan tool');
|
|
342
|
+
text = text.replaceAll('TaskCreate', 'the Codex plan tool');
|
|
343
|
+
text = text.replaceAll('TaskUpdate', 'the Codex plan tool');
|
|
344
|
+
text = text.replaceAll('TaskList', 'the current Codex plan');
|
|
345
|
+
text = text.replaceAll('TaskOutput', 'verbose subagent transcript output');
|
|
346
|
+
text = text.replaceAll('run_in_background: true', 'native parallel execution');
|
|
347
|
+
text = text.replaceAll('Bash tool', '`exec_command`');
|
|
348
|
+
text = text.replaceAll('Bash calls', '`exec_command` calls');
|
|
349
|
+
text = text.replaceAll('Read tool', 'targeted file reads');
|
|
350
|
+
text = text.replaceAll('Write tool', '`apply_patch`');
|
|
351
|
+
text = text.replaceAll('`ask.question`', 'a direct user question');
|
|
352
|
+
text = text.replaceAll('ask.question', 'ask the user directly');
|
|
353
|
+
text = text.replaceAll('Playwright via Bash', 'Playwright through `exec_command`');
|
|
354
|
+
text = text.replaceAll('mcp__context7__query-docs', 'official documentation lookup');
|
|
355
|
+
text = text.replaceAll('mcp__exa__web_search_exa', 'verified web search');
|
|
356
|
+
text = text.replaceAll('Context7 MCP', 'official primary documentation');
|
|
357
|
+
text = text.replaceAll('Context7/Exa', 'official primary documentation and verified web search');
|
|
358
|
+
text = text.replaceAll('Context7', 'official primary documentation');
|
|
359
|
+
text = text.replaceAll('Exa MCP', 'verified web search');
|
|
360
|
+
text = text.replaceAll('a direct user question (or runtime `ask the user directly`)', 'ask the user directly');
|
|
361
|
+
text = text.replaceAll('a direct user question (fallback: `ask the user directly` / CLI menu)', 'ask the user directly');
|
|
362
|
+
text = text.replaceAll('questions via ask the user directly.', 'questions directly to the user.');
|
|
363
|
+
text = text.replaceAll('using `the Codex plan tool`', 'with the Codex plan tool');
|
|
364
|
+
text = text.replaceAll("via the runtime's native the Codex plan tool", 'with the Codex plan tool when available');
|
|
365
|
+
text = text.replaceAll('`the Codex plan tool` → `status: "in_progress"`', 'Mark the current Codex plan item `in_progress`');
|
|
366
|
+
text = text.replaceAll('`the Codex plan tool` → `status: "completed"`', 'Mark the current Codex plan item `completed`');
|
|
367
|
+
text = text.replaceAll('`the current Codex plan` → resume from last incomplete step', 'Resume from the first incomplete item in the current Codex plan');
|
|
368
|
+
text = text.replaceAll('`the Codex plan tool`', 'the Codex plan tool');
|
|
369
|
+
|
|
370
|
+
if (skillName === 'ultra-init') {
|
|
371
|
+
text = text.replace(
|
|
372
|
+
/MCP 不可达时回退[^。]*。/,
|
|
373
|
+
'MCP 不可达时只使用插件内置的可验证 CLI 初始化路径;不得手写投影文件。',
|
|
374
|
+
);
|
|
375
|
+
text = text.replace(
|
|
376
|
+
/- \*\*无 Codex 独占依赖\*\*[::][\s\S]*?(?=\n- \*\*模板内置)/,
|
|
377
|
+
'- **Codex-native boundary**: use the bundled `task.init_project` MCP tool; the plugin-local CLI below is only the verified initialization fallback.',
|
|
378
|
+
);
|
|
379
|
+
text = text.replace(
|
|
380
|
+
/在调 `task\.init_project` 之前,调用方(Codex \/ CLI \/ SDK)需要先判断:/,
|
|
381
|
+
'在调 `task.init_project` 之前,Codex 需要先判断:',
|
|
382
|
+
);
|
|
383
|
+
text = text.replace(
|
|
384
|
+
/- 如果调用方是 Codex,可在此用 the Codex plan tool 跟踪 Step 0–4 的 session 内进度\n (这是 runtime 的 session-local 跟踪,不走 MCP)/,
|
|
385
|
+
'- 多步初始化可用 Codex plan 跟踪;持久项目状态仍只通过 Ultra MCP 写入。',
|
|
386
|
+
);
|
|
387
|
+
text = text.replace(
|
|
388
|
+
/交互渠道:[\s\S]*?(?=\n确认 4 个问题:)/,
|
|
389
|
+
'交互渠道:直接向用户提问;不要调用未注册的人机交互 MCP tool。\n',
|
|
390
|
+
);
|
|
391
|
+
text = text.replace(
|
|
392
|
+
/\*\*CLI 回退路径\*\*[\s\S]*?(?=\n\*\*错误处理\*\*)/,
|
|
393
|
+
`**插件内置 CLI 回退路径**(只在 MCP 启动失败时使用):
|
|
394
|
+
|
|
395
|
+
\`\`\`bash
|
|
396
|
+
node ~/plugins/ultra-builder-pro/runtime/ultra-tools.cjs task init-project \\
|
|
397
|
+
--target-dir "$TARGET" \\
|
|
398
|
+
--project-name "$NAME" \\
|
|
399
|
+
--project-type "$TYPE" \\
|
|
400
|
+
--stack "$STACK"
|
|
401
|
+
\`\`\`
|
|
402
|
+
|
|
403
|
+
该 CLI 与 MCP 使用同一模板和校验规则。不得改写 \`.ultra/tasks/tasks.json\` 来模拟成功。
|
|
404
|
+
`,
|
|
405
|
+
);
|
|
406
|
+
text = text.replace(
|
|
407
|
+
/## 调用方式(按 runtime)[\s\S]*?(?=\n## 输出锚点)/,
|
|
408
|
+
'## Codex 调用方式\n\n在 Codex 中显式调用 `$ultra-builder-pro:ultra-init`,并在同一条任务消息中提供项目名、类型、技术栈或 git 约束。\n',
|
|
409
|
+
);
|
|
410
|
+
text = text.replace(
|
|
411
|
+
/- \*\*不\*\*写入 state\.db(state\.db 由第一次 MCP 写操作或显式 `ultra-tools db init` 触发)/,
|
|
412
|
+
'- **不**直接写入 state.db;它由第一次 Ultra MCP 状态写操作初始化。',
|
|
413
|
+
);
|
|
414
|
+
text = text.replaceAll('不再依赖 `~/.codex/.ultra-template/`', '不依赖任何用户目录模板');
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
if (skillName === 'ultra-plan') {
|
|
418
|
+
text = text.replace(
|
|
419
|
+
/Interactive prompt uses[\s\S]*?(?=\n\n\*\*Dual-scale effort)/,
|
|
420
|
+
'Ask the user directly in Codex and record the selected posture.',
|
|
421
|
+
);
|
|
422
|
+
text = text.replace(
|
|
423
|
+
/\*\*CLI fallback\*\* \(per task\):[\s\S]*?(?=\nAfter each `task\.create`)/,
|
|
424
|
+
'**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',
|
|
425
|
+
);
|
|
426
|
+
text = text.replace(
|
|
427
|
+
/## MCP → CLI fallback matrix[\s\S]*?(?=\n## What this skill DOES NOT do)/,
|
|
428
|
+
`## Codex runtime boundary
|
|
429
|
+
|
|
430
|
+
- Ask scope and approval questions directly in the Codex conversation.
|
|
431
|
+
- Persist tasks only through bundled MCP \`task.create\` or \`task.parse_prd\`.
|
|
432
|
+
- If that MCP is unavailable, stop the state mutation with evidence; the legacy CLI does not
|
|
433
|
+
implement task creation and is not a valid fallback.
|
|
434
|
+
`,
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (skillName === 'ultra-dev') {
|
|
439
|
+
text = text.replace(
|
|
440
|
+
/## Design decisions vs pre-Phase-3[\s\S]*?(?=\n## Prerequisites)/,
|
|
441
|
+
`## Codex-native execution boundaries
|
|
442
|
+
|
|
443
|
+
- Status changes use bundled MCP \`task.update\`; projected JSON and frontmatter are read-only.
|
|
444
|
+
- Review uses \`$ultra-builder-pro:ultra-review\` and the installed native Codex custom agents.
|
|
445
|
+
The active MCP server does not expose a server-side review worker.
|
|
446
|
+
- Recovery uses the Codex plan plus \`.ultra/workflow-state.json\`, with the bundled compact hooks.
|
|
447
|
+
The active MCP server does not expose a checkpoint tool, and no manual compact is required.
|
|
448
|
+
`,
|
|
449
|
+
);
|
|
450
|
+
text = text.replaceAll(
|
|
451
|
+
'**CLI fallback**: `ultra-tools task update <id> --status in_progress`.',
|
|
452
|
+
'**Failure boundary**: if `task.update` is unavailable, stop; do not edit state.db or projections directly.',
|
|
453
|
+
);
|
|
454
|
+
text = text.replaceAll(
|
|
455
|
+
'**CLI fallback**: `ultra-tools task update <id> --status completed`.',
|
|
456
|
+
'**Failure boundary**: if `task.update` is unavailable, stop; do not mark the projection completed manually.',
|
|
457
|
+
);
|
|
458
|
+
text = text.replace(
|
|
459
|
+
/\*\*Subagent isolation \(complexity ≥ 7\)\*\*:[\s\S]*?subagent returns summary\./,
|
|
460
|
+
'**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.',
|
|
461
|
+
);
|
|
462
|
+
text = text.replace(
|
|
463
|
+
/### Step 4\.4 — Pre-Review Checkpoint[\s\S]*?(?=\n### Step 4\.5)/,
|
|
464
|
+
`### Step 4.4 — Pre-Review Checkpoint
|
|
465
|
+
|
|
466
|
+
Atomically write \`.ultra/workflow-state.json\` with \`step=4.5\`,
|
|
467
|
+
\`status=pre_review\`, the task id, branch, and timestamp. Mark the matching Codex plan item
|
|
468
|
+
complete. The PreCompact/PostCompact hooks preserve and restore this checkpoint automatically;
|
|
469
|
+
do not require the user to compact or call a nonexistent checkpoint tool.
|
|
470
|
+
`,
|
|
471
|
+
);
|
|
472
|
+
text = text.replace(
|
|
473
|
+
/### Step 4\.5 — Ultra Review \(MANDATORY\)[\s\S]*?(?=\n\*\*MAX_REVIEW_ITERATIONS)/,
|
|
474
|
+
`### Step 4.5 — Ultra Review (MANDATORY)
|
|
475
|
+
|
|
476
|
+
Invoke \`$ultra-builder-pro:ultra-review all\`. That skill selects and dispatches the installed
|
|
477
|
+
native Codex review agents, waits on their structured files, and owns \`SUMMARY.json\`. Do not call
|
|
478
|
+
an unregistered review MCP tool or shell out to another Codex process as a substitute.
|
|
479
|
+
|
|
480
|
+
`,
|
|
481
|
+
);
|
|
482
|
+
text = text.replace(
|
|
483
|
+
/## MCP → CLI fallback matrix[\s\S]*?(?=\n## What this skill DOES NOT do)/,
|
|
484
|
+
`## Codex runtime boundary
|
|
485
|
+
|
|
486
|
+
| Purpose | Authoritative Codex path |
|
|
487
|
+
|---------|--------------------------|
|
|
488
|
+
| Select/read/update task | bundled MCP \`task.list\`, \`task.get\`, \`task.update\` |
|
|
489
|
+
| Pre-review recovery | Codex plan + \`.ultra/workflow-state.json\` + compact hooks |
|
|
490
|
+
| Review | \`$ultra-builder-pro:ultra-review\` + native custom agents |
|
|
491
|
+
| Human decision | ask the user directly |
|
|
492
|
+
|
|
493
|
+
If a required task MCP operation fails, stop and report it; never fall back to direct database or
|
|
494
|
+
projection writes.
|
|
495
|
+
`,
|
|
496
|
+
);
|
|
497
|
+
text = text.replace(
|
|
498
|
+
/- Does NOT assume `review\.run` or `session\.checkpoint` are wired — fallbacks are first-class/,
|
|
499
|
+
'- Does NOT call unregistered review or checkpoint MCP tools.',
|
|
500
|
+
);
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
if (skillName === 'ultra-test') {
|
|
504
|
+
text = text.replace(
|
|
505
|
+
/## MCP → CLI fallback matrix[\s\S]*?(?=\n## What this skill DOES NOT do)/,
|
|
506
|
+
`## Codex runtime boundary
|
|
507
|
+
|
|
508
|
+
- Read task completion through bundled MCP \`task.list\`.
|
|
509
|
+
- Ask before risky auto-fixes directly in the Codex conversation.
|
|
510
|
+
- If task state is unavailable, report the missing gate rather than trusting a projection alone.
|
|
511
|
+
`,
|
|
512
|
+
);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
if (skillName === 'ultra-deliver') {
|
|
516
|
+
text = text.replace(
|
|
517
|
+
/## MCP → CLI fallback matrix[\s\S]*?(?=\n## What this skill DOES NOT do)/,
|
|
518
|
+
`## Codex runtime boundary
|
|
519
|
+
|
|
520
|
+
Ask the user directly before committing, tagging, pushing, or overriding the version bump. These are
|
|
521
|
+
external repository mutations; never infer approval from a prior read-only or test request.
|
|
522
|
+
`,
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
if (skillName === 'ultra-status') {
|
|
527
|
+
text = text.replace(
|
|
528
|
+
/\*\*CLI fallback\*\*: `ultra-tools task list` \+ `ultra-tools session list`\./,
|
|
529
|
+
'**Failure boundary**: if the bundled task/session MCP tools are unavailable, report those panels as unavailable; do not trust projections as authority.',
|
|
530
|
+
);
|
|
531
|
+
text = text.replace(
|
|
532
|
+
/\*\*Output block\*\*:[\s\S]*?(?=\n## Single-task mode)/,
|
|
533
|
+
`**Output block**: name the concrete next skill and use its namespaced Codex invocation, for
|
|
534
|
+
example \`$ultra-builder-pro:ultra-dev\`. If a fresh context would help, recommend starting a new
|
|
535
|
+
Codex task; do not emit a legacy slash-command placeholder.
|
|
536
|
+
|
|
537
|
+
`,
|
|
538
|
+
);
|
|
539
|
+
text = text.replace(
|
|
540
|
+
/## MCP → CLI fallback matrix[\s\S]*?(?=\n## Cost panel)/,
|
|
541
|
+
`## Codex data paths
|
|
542
|
+
|
|
543
|
+
| Purpose | Path |
|
|
544
|
+
|---------|------|
|
|
545
|
+
| List/detail tasks | bundled MCP \`task.list\` / \`task.get\` |
|
|
546
|
+
| Cost panel | \`node ~/plugins/ultra-builder-pro/runtime/ultra-tools.cjs status --cost --json --since 7d\` |
|
|
547
|
+
|
|
548
|
+
Task projections are not an authority fallback. If the MCP is unavailable, label the task panel
|
|
549
|
+
unavailable while still reporting file and git evidence.
|
|
550
|
+
`,
|
|
551
|
+
);
|
|
552
|
+
text = text.replaceAll(
|
|
553
|
+
'`ultra-tools status --cost --json`',
|
|
554
|
+
'`node ~/plugins/ultra-builder-pro/runtime/ultra-tools.cjs status --cost --json`',
|
|
555
|
+
);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
if (skillName === 'ultra-think') {
|
|
559
|
+
text = text.replace(
|
|
560
|
+
/Every factual claim about tech\/API\/best-practices must be verified via:[\s\S]*?(?=\n\nLabel each assertion:)/,
|
|
561
|
+
`Every factual claim about technology, APIs, or current behavior must use the best available
|
|
562
|
+
primary evidence in this order:
|
|
563
|
+
- current repository or installed source;
|
|
564
|
+
- official primary documentation;
|
|
565
|
+
- web search when the fact may have changed or local evidence is insufficient.
|
|
566
|
+
`,
|
|
567
|
+
);
|
|
568
|
+
text = text.replaceAll(
|
|
569
|
+
'docs via Context7/Exa',
|
|
570
|
+
'official primary documentation or verified web sources',
|
|
571
|
+
);
|
|
572
|
+
text = text.replace(
|
|
573
|
+
/## MCP → CLI fallback matrix[\s\S]*?(?=\n## What this skill DOES NOT do)/,
|
|
574
|
+
`## Codex interaction boundary
|
|
575
|
+
|
|
576
|
+
Ask clarifying questions directly in the Codex conversation. This reasoning workflow is read-only
|
|
577
|
+
and does not require an interactive MCP or legacy CLI menu.
|
|
578
|
+
`,
|
|
579
|
+
);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
if (skillName === 'ultra-review') {
|
|
583
|
+
text = text.replaceAll('### Phase 3: Background Execution', '### Phase 3: Parallel Native Agent Execution');
|
|
584
|
+
text = text.replaceAll('**Step 4b: Launch coordinator in background:**', '**Step 4b: Delegate coordination:**');
|
|
585
|
+
text = text.replaceAll('in **background mode** (`native parallel execution`)', 'concurrently with native Codex subagent orchestration');
|
|
586
|
+
text = text.replaceAll('using multiple native Codex subagent orchestration calls in a single message', 'using the installed native Codex custom agents');
|
|
587
|
+
text = text.replaceAll('Set `native parallel execution` on every Task call.', 'Dispatch every selected custom agent concurrently and keep each delegated scope bounded.');
|
|
588
|
+
text = text.replaceAll('NEVER call verbose subagent transcript output for any review agent', 'Do not copy verbose subagent transcripts into the parent context');
|
|
589
|
+
text = text.replaceAll('Call `review_wait.py` IMMEDIATELY — do NOT process idle notifications', 'Use `review_wait.py` as the file-completion gate before synthesis');
|
|
590
|
+
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');
|
|
591
|
+
text = text.replaceAll('Launch review-coordinator with `native parallel execution`:', 'After reviewer completion, delegate coordination to the native `review-coordinator` agent:');
|
|
592
|
+
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:');
|
|
593
|
+
text = text.replaceAll('After launching background agents', 'After dispatching the review agents');
|
|
594
|
+
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.');
|
|
595
|
+
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');
|
|
596
|
+
text = text.replaceAll('**Read SUMMARY.json**', '**Inspect SUMMARY.json**');
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
return text;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
function adaptUltraVerifyAsset(input, rel) {
|
|
603
|
+
if (rel === path.join('references', 'orchestration-flow.md')) return ULTRA_VERIFY_FLOW;
|
|
604
|
+
|
|
605
|
+
let text = adaptHostText(String(input), '');
|
|
606
|
+
if (rel === path.join('scripts', 'verify_wait.py')) {
|
|
607
|
+
text = text.replaceAll('Codex', 'Claude Code');
|
|
608
|
+
text = text.replaceAll('codex', 'claude');
|
|
609
|
+
text = text.replaceAll('run_in_background', 'a yielded exec session');
|
|
610
|
+
return text;
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
text = text.replaceAll('Claude', '__UBP_CODEX_PRIMARY__');
|
|
614
|
+
text = text.replaceAll('Codex', 'Claude Code');
|
|
615
|
+
text = text.replaceAll('__UBP_CODEX_PRIMARY__', 'Codex');
|
|
616
|
+
text = text.replaceAll('claude-analysis.md', 'codex-analysis.md');
|
|
617
|
+
text = text.replaceAll('codex-output.md', 'claude-output.md');
|
|
618
|
+
text = text.replaceAll('codex-error.log', 'claude-error.log');
|
|
619
|
+
text = text.replaceAll('codex-review', 'claude-review');
|
|
620
|
+
text = text.replaceAll('"claude": "claude-opus-4-6"', '"codex": "<primary>"');
|
|
621
|
+
text = text.replaceAll('"codex": "<model>"', '"claude": "<advisor>"');
|
|
622
|
+
text = text.replaceAll('["claude"]', '["codex"]');
|
|
623
|
+
text = text.replaceAll('Claude Code-only', 'Codex-only');
|
|
624
|
+
text = text.replaceAll('Gemini and Claude Code in parallel (native parallel execution)', 'Claude Code and Gemini concurrently');
|
|
625
|
+
text = text.replaceAll('run_in_background', 'native concurrent execution');
|
|
626
|
+
text = text.replaceAll('Bash tool', '`exec_command`');
|
|
627
|
+
text = text.replaceAll('Read tool', 'targeted file reads');
|
|
628
|
+
return text;
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
function adaptSkillAsset(input, targetName, rel) {
|
|
632
|
+
if (targetName === 'ultra-verify') return adaptUltraVerifyAsset(input, rel);
|
|
633
|
+
return adaptHostText(input, targetName);
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
function adaptHostText(input, skillName = '') {
|
|
637
|
+
let text = String(input);
|
|
638
|
+
text = text.replaceAll('codex-collab', 'cc-collab');
|
|
639
|
+
text = text.replaceAll('CLAUDE.md', 'AGENTS.md');
|
|
640
|
+
text = text.replaceAll('$CLAUDE_PLUGIN_ROOT/skills', '~/plugins/ultra-builder-pro/skills');
|
|
641
|
+
text = text.replaceAll('~/.claude/skills', '~/plugins/ultra-builder-pro/skills');
|
|
642
|
+
text = text.replaceAll('~/.codex/skills', '~/plugins/ultra-builder-pro/skills');
|
|
643
|
+
text = text.replaceAll('~/.claude/hooks', '~/plugins/ultra-builder-pro/hooks');
|
|
644
|
+
text = text.replaceAll('~/.claude', '~/.codex');
|
|
645
|
+
text = text.replaceAll('AskUserQuestion', 'ask the user directly');
|
|
646
|
+
text = text.replaceAll('Claude runtime', 'Codex runtime');
|
|
647
|
+
text = text.replaceAll('Claude-only', 'Codex-only');
|
|
648
|
+
text = text.replaceAll('Claude Task tool', 'Codex native subagent orchestration');
|
|
649
|
+
text = text.replaceAll('Claude `Task` tool', 'Codex native subagent orchestration');
|
|
650
|
+
text = text.replaceAll('Claude: `Task`', 'Codex: native subagent orchestration');
|
|
651
|
+
text = text.replaceAll('Task tool', 'native Codex subagent orchestration');
|
|
652
|
+
text = text.replaceAll('`Task`/`ultra-tools subagent run`', 'native Codex subagent orchestration / `ultra-tools subagent run`');
|
|
653
|
+
text = text.replaceAll('`Task` →', 'native Codex subagent orchestration →');
|
|
654
|
+
|
|
655
|
+
for (const skill of SKILL_REFERENCE_NAMES) {
|
|
656
|
+
text = replaceSlashCommand(text, skill, `$ultra-builder-pro:${skill}`);
|
|
657
|
+
}
|
|
658
|
+
text = replaceSlashCommand(text, 'clear', 'start a new Codex task');
|
|
659
|
+
|
|
660
|
+
if (CODEX_PRIMARY_SKILLS.has(skillName)) {
|
|
661
|
+
text = adaptCodexPrimaryText(text, skillName);
|
|
662
|
+
}
|
|
663
|
+
|
|
664
|
+
if (skillName === 'gemini-collab' || skillName === 'ai-collab-base') {
|
|
665
|
+
text = text.replaceAll("Claude's", "Codex's");
|
|
666
|
+
text = text.replaceAll('Claude-only', 'Codex-only');
|
|
667
|
+
text = text.replaceAll('Claude ', 'Codex ');
|
|
668
|
+
text = text.replaceAll('Claude\n', 'Codex\n');
|
|
669
|
+
text = text.replaceAll('--approval-mode yolo', '--approval-mode plan');
|
|
670
|
+
text = text.replaceAll('--yolo', '--approval-mode plan');
|
|
671
|
+
text = text.replaceAll('Bash tool', '`exec_command`');
|
|
672
|
+
text = text.replaceAll('Read tool', 'targeted file reads');
|
|
673
|
+
text = text.replaceAll('Write tool', '`apply_patch`');
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
if (skillName === 'learn') {
|
|
677
|
+
text = text.replaceAll(
|
|
678
|
+
'~/plugins/ultra-builder-pro/skills/learned-<name>-unverified/SKILL.md',
|
|
679
|
+
'~/.agents/skills/learned-<name>-unverified/SKILL.md',
|
|
680
|
+
);
|
|
681
|
+
text = text.replaceAll(
|
|
682
|
+
'~/plugins/ultra-builder-pro/skills/learned-<pattern-slug>-unverified/SKILL.md',
|
|
683
|
+
'~/.agents/skills/learned-<pattern-slug>-unverified/SKILL.md',
|
|
684
|
+
);
|
|
685
|
+
text = text.replaceAll(
|
|
686
|
+
'~/plugins/ultra-builder-pro/skills/learned-<slug>-unverified/SKILL.md',
|
|
687
|
+
'~/.agents/skills/learned-<slug>-unverified/SKILL.md',
|
|
688
|
+
);
|
|
689
|
+
text = text.replaceAll(
|
|
690
|
+
'~/plugins/ultra-builder-pro/skills/learned/<name>_unverified.md',
|
|
691
|
+
'~/.agents/skills/learned-<name>-unverified/SKILL.md',
|
|
692
|
+
);
|
|
693
|
+
text = text.replaceAll(
|
|
694
|
+
'~/plugins/ultra-builder-pro/skills/learned/<pattern-slug>_unverified.md',
|
|
695
|
+
'~/.agents/skills/learned-<pattern-slug>-unverified/SKILL.md',
|
|
696
|
+
);
|
|
697
|
+
text = text.replaceAll(
|
|
698
|
+
'~/plugins/ultra-builder-pro/skills/learned/<slug>_unverified.md',
|
|
699
|
+
'~/.agents/skills/learned-<slug>-unverified/SKILL.md',
|
|
700
|
+
);
|
|
701
|
+
text = text.replaceAll('append the `_unverified` suffix to the filename', 'append `-unverified` to the skill directory name');
|
|
702
|
+
text = text.replaceAll('Never overwrite an existing unverified file', 'Never overwrite an existing learned skill directory');
|
|
703
|
+
text = text.replaceAll('remove the `_unverified` suffix', 'rename the directory to remove `-unverified` and update the frontmatter name');
|
|
704
|
+
text = text.replaceAll('(`pattern-slug-2_unverified.md`)', '(`learned-pattern-slug-2-unverified/`)');
|
|
705
|
+
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');
|
|
706
|
+
text = text.replace(
|
|
707
|
+
/## MCP → CLI fallback matrix[\s\S]*?(?=\n## What this skill DOES NOT do)/,
|
|
708
|
+
'## Codex approval boundary\n\nAsk the user directly before writing a learned skill. No MCP or legacy CLI interaction layer is required.\n',
|
|
709
|
+
);
|
|
710
|
+
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`;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
return text;
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
function adaptedDescription(sourceDescription, targetName) {
|
|
717
|
+
const special = {
|
|
718
|
+
'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.',
|
|
719
|
+
'gemini-collab': 'Ask Gemini CLI for an independent read-only analysis while Codex verifies and synthesizes. Use only when the user explicitly requests Gemini collaboration.',
|
|
720
|
+
'ultra-verify': 'Run Codex-primary three-way verification with read-only Claude Code and Gemini advisors, then verify and synthesize the evidence.',
|
|
721
|
+
'ultra-dev': 'Execute one Ultra task with Codex-native TDD, persistent task.update state, workflow checkpoints, and the native Ultra review agents.',
|
|
722
|
+
'learn': 'Extract one reusable pattern from the current Codex task into a valid user skill, with explicit user approval before writing.',
|
|
723
|
+
};
|
|
724
|
+
return special[targetName] || adaptHostText(String(sourceDescription || `${titleCase(targetName)} workflow for Codex.`), targetName)
|
|
725
|
+
.replace(/\s+/g, ' ')
|
|
726
|
+
.trim();
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
function buildSkillMarkdown(sourceText, sourceName, targetName) {
|
|
730
|
+
const { fm, body } = parseFrontmatter(sourceText);
|
|
731
|
+
let adaptedBody;
|
|
732
|
+
if (targetName === 'cc-collab') adaptedBody = CC_COLLAB_BODY;
|
|
733
|
+
else if (targetName === 'gemini-collab') adaptedBody = GEMINI_COLLAB_BODY;
|
|
734
|
+
else if (targetName === 'ultra-verify') adaptedBody = ULTRA_VERIFY_BODY;
|
|
735
|
+
else adaptedBody = adaptHostText(body, targetName);
|
|
736
|
+
return yaml.dump({
|
|
737
|
+
name: targetName,
|
|
738
|
+
description: adaptedDescription(fm && fm.description, targetName),
|
|
739
|
+
}, { lineWidth: -1, noRefs: true }).trimEnd()
|
|
740
|
+
.replace(/^/, '---\n') + `\n---\n\n${adaptedBody.trim()}\n`;
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
function buildOpenAiYaml(name, description) {
|
|
744
|
+
const implicit = !(
|
|
745
|
+
COMMAND_NAMES.includes(name)
|
|
746
|
+
|| INTERNAL_SKILLS.has(name)
|
|
747
|
+
|| name === 'cc-collab'
|
|
748
|
+
|| name === 'gemini-collab'
|
|
749
|
+
|| name.startsWith('ultra-')
|
|
750
|
+
);
|
|
751
|
+
const short = description.replace(/\s+/g, ' ').trim().slice(0, 63).replace(/[\s.,;:]+$/, '');
|
|
752
|
+
return yaml.dump({
|
|
753
|
+
interface: {
|
|
754
|
+
display_name: titleCase(name),
|
|
755
|
+
short_description: short || `${titleCase(name)} for Codex`,
|
|
756
|
+
default_prompt: `Use $ultra-builder-pro:${name} for this task and follow its workflow.`,
|
|
757
|
+
},
|
|
758
|
+
policy: { allow_implicit_invocation: implicit },
|
|
759
|
+
}, { lineWidth: -1, noRefs: true });
|
|
760
|
+
}
|
|
761
|
+
|
|
762
|
+
function isTextFile(rel) {
|
|
763
|
+
return TEXT_EXTENSIONS.has(path.extname(rel).toLowerCase());
|
|
764
|
+
}
|
|
765
|
+
|
|
766
|
+
function copySkill(sourceDir, targetDir, sourceName, targetName) {
|
|
767
|
+
if (targetName === 'cc-collab') {
|
|
768
|
+
ensureDir(targetDir);
|
|
769
|
+
const sourceText = fs.readFileSync(path.join(sourceDir, 'SKILL.md'), 'utf8');
|
|
770
|
+
const skillText = buildSkillMarkdown(sourceText, sourceName, targetName);
|
|
771
|
+
writeAtomic(path.join(targetDir, 'SKILL.md'), skillText);
|
|
772
|
+
const description = parseFrontmatter(skillText).fm.description;
|
|
773
|
+
writeAtomic(path.join(targetDir, 'agents', 'openai.yaml'), buildOpenAiYaml(targetName, description));
|
|
774
|
+
return;
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
copyTree(sourceDir, targetDir, {
|
|
778
|
+
transform(original, rel) {
|
|
779
|
+
if (rel === path.join('agents', 'openai.yaml')) return original;
|
|
780
|
+
if (rel === 'SKILL.md') {
|
|
781
|
+
return Buffer.from(buildSkillMarkdown(original.toString('utf8'), sourceName, targetName));
|
|
782
|
+
}
|
|
783
|
+
if (!isTextFile(rel)) return original;
|
|
784
|
+
return Buffer.from(adaptSkillAsset(original.toString('utf8'), targetName, rel));
|
|
785
|
+
},
|
|
786
|
+
});
|
|
787
|
+
const skillText = fs.readFileSync(path.join(targetDir, 'SKILL.md'), 'utf8');
|
|
788
|
+
const description = parseFrontmatter(skillText).fm.description;
|
|
789
|
+
writeAtomic(path.join(targetDir, 'agents', 'openai.yaml'), buildOpenAiYaml(targetName, description));
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
function buildCommandMap() {
|
|
793
|
+
return Object.fromEntries(COMMAND_NAMES.map((name) => [`/${name}`, `$ultra-builder-pro:${name}`]));
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
function hookCommand(feature, ...args) {
|
|
797
|
+
return [
|
|
798
|
+
'python3 "$PLUGIN_ROOT/hooks/adapters/codex.py"',
|
|
799
|
+
JSON.stringify(feature),
|
|
800
|
+
...args.map((arg) => JSON.stringify(arg)),
|
|
801
|
+
].join(' ');
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
function commandHook(feature, timeout, statusMessage, ...args) {
|
|
805
|
+
return {
|
|
806
|
+
type: 'command',
|
|
807
|
+
command: hookCommand(feature, ...args),
|
|
808
|
+
timeout,
|
|
809
|
+
statusMessage,
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
function buildHooksManifest() {
|
|
814
|
+
return {
|
|
815
|
+
hooks: {
|
|
816
|
+
SessionStart: [
|
|
817
|
+
{ hooks: [commandHook('health_check.py', 5, 'Checking Ultra runtime')] },
|
|
818
|
+
{ hooks: [commandHook('workflow_context.py', 10, 'Loading active Ultra workflow')] },
|
|
819
|
+
],
|
|
820
|
+
PreToolUse: [
|
|
821
|
+
{ matcher: 'Edit|Write', hooks: [commandHook('active_task_context.py', 3, 'Checking active Ultra task')] },
|
|
822
|
+
],
|
|
823
|
+
PreCompact: [
|
|
824
|
+
{ matcher: 'manual|auto', hooks: [commandHook('workflow_checkpoint.py', 10, 'Saving Ultra workflow checkpoint')] },
|
|
825
|
+
],
|
|
826
|
+
PostCompact: [
|
|
827
|
+
{ hooks: [commandHook('workflow_resume.py', 10, 'Restoring Ultra workflow checkpoint')] },
|
|
828
|
+
],
|
|
829
|
+
Stop: [
|
|
830
|
+
{ hooks: [commandHook('pre_stop_check.py', 5, 'Checking Ultra completion gates')] },
|
|
831
|
+
],
|
|
832
|
+
SubagentStart: [
|
|
833
|
+
{ hooks: [commandHook('subagent_tracker.py', 5, 'Tracking Ultra subagent', 'start')] },
|
|
834
|
+
],
|
|
835
|
+
SubagentStop: [
|
|
836
|
+
{ hooks: [commandHook('subagent_tracker.py', 5, 'Tracking Ultra subagent', 'stop')] },
|
|
837
|
+
],
|
|
838
|
+
},
|
|
839
|
+
};
|
|
840
|
+
}
|
|
841
|
+
|
|
842
|
+
function copyHooks(repoRoot, pluginRoot) {
|
|
843
|
+
const sourceRoot = path.join(repoRoot, 'hooks');
|
|
844
|
+
const targetRoot = path.join(pluginRoot, 'hooks');
|
|
845
|
+
ensureDir(targetRoot);
|
|
846
|
+
for (const name of WORKFLOW_HOOK_FILES) {
|
|
847
|
+
fs.copyFileSync(path.join(sourceRoot, name), path.join(targetRoot, name));
|
|
848
|
+
}
|
|
849
|
+
ensureDir(path.join(targetRoot, 'adapters'));
|
|
850
|
+
fs.copyFileSync(
|
|
851
|
+
path.join(sourceRoot, 'adapters', 'codex.py'),
|
|
852
|
+
path.join(targetRoot, 'adapters', 'codex.py'),
|
|
853
|
+
);
|
|
854
|
+
writeAtomic(path.join(targetRoot, 'hooks.json'), JSON.stringify(buildHooksManifest(), null, 2) + '\n');
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
function buildMcpRuntime(repoRoot, pluginRoot, { runtime = 'codex' } = {}) {
|
|
858
|
+
const source = path.join(repoRoot, 'mcp-server', 'server.cjs');
|
|
859
|
+
const cliSource = path.join(repoRoot, 'adapters', '_shared', 'codex-ultra-tools-entry.cjs');
|
|
860
|
+
const runtimeRoot = path.join(pluginRoot, 'runtime');
|
|
861
|
+
const buildRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'ubp-codex-mcp-build-'));
|
|
862
|
+
let nccCli;
|
|
863
|
+
try {
|
|
864
|
+
nccCli = require.resolve('@vercel/ncc/dist/ncc/cli.js');
|
|
865
|
+
} catch (error) {
|
|
866
|
+
throw new Error(`Ultra MCP bundling requires @vercel/ncc: ${error.message}`);
|
|
867
|
+
}
|
|
868
|
+
|
|
869
|
+
try {
|
|
870
|
+
const bundled = spawnSync(process.execPath, [
|
|
871
|
+
nccCli,
|
|
872
|
+
'build',
|
|
873
|
+
source,
|
|
874
|
+
'-o',
|
|
875
|
+
buildRoot,
|
|
876
|
+
'--no-cache',
|
|
877
|
+
'--quiet',
|
|
878
|
+
], {
|
|
879
|
+
cwd: repoRoot,
|
|
880
|
+
encoding: 'utf8',
|
|
881
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
882
|
+
});
|
|
883
|
+
if (bundled.error) throw bundled.error;
|
|
884
|
+
if (bundled.status !== 0) {
|
|
885
|
+
const detail = (bundled.stderr || bundled.stdout || '').trim();
|
|
886
|
+
throw new Error(`ncc failed to bundle the Ultra MCP runtime${detail ? `: ${detail}` : ''}`);
|
|
887
|
+
}
|
|
888
|
+
copyTree(buildRoot, runtimeRoot);
|
|
889
|
+
} finally {
|
|
890
|
+
removeTree(buildRoot);
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
const cliBuildRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'ubp-codex-cli-build-'));
|
|
894
|
+
try {
|
|
895
|
+
const bundled = spawnSync(process.execPath, [
|
|
896
|
+
nccCli,
|
|
897
|
+
'build',
|
|
898
|
+
cliSource,
|
|
899
|
+
'-o',
|
|
900
|
+
cliBuildRoot,
|
|
901
|
+
'--no-cache',
|
|
902
|
+
'--quiet',
|
|
903
|
+
], {
|
|
904
|
+
cwd: repoRoot,
|
|
905
|
+
encoding: 'utf8',
|
|
906
|
+
maxBuffer: 16 * 1024 * 1024,
|
|
907
|
+
});
|
|
908
|
+
if (bundled.error) throw bundled.error;
|
|
909
|
+
if (bundled.status !== 0) {
|
|
910
|
+
const detail = (bundled.stderr || bundled.stdout || '').trim();
|
|
911
|
+
throw new Error(`ncc failed to bundle the Ultra fallback CLI${detail ? `: ${detail}` : ''}`);
|
|
912
|
+
}
|
|
913
|
+
for (const rel of listRelative(cliBuildRoot)) {
|
|
914
|
+
const target = rel === 'index.cjs'
|
|
915
|
+
? path.join(runtimeRoot, 'ultra-tools.cjs')
|
|
916
|
+
: path.join(runtimeRoot, rel);
|
|
917
|
+
ensureDir(path.dirname(target));
|
|
918
|
+
fs.copyFileSync(path.join(cliBuildRoot, rel), target);
|
|
919
|
+
}
|
|
920
|
+
} finally {
|
|
921
|
+
removeTree(cliBuildRoot);
|
|
922
|
+
}
|
|
923
|
+
|
|
924
|
+
const launcher = `'use strict';
|
|
925
|
+
|
|
926
|
+
const path = require('node:path');
|
|
927
|
+
|
|
928
|
+
process.env.UBP_RUNTIME_ROOT = path.resolve(__dirname, '..');
|
|
929
|
+
|
|
930
|
+
const { main } = require('./index.cjs');
|
|
931
|
+
|
|
932
|
+
main().catch((error) => {
|
|
933
|
+
process.stderr.write(\`mcp-server fatal: \${error.message}\\n\`);
|
|
934
|
+
process.exit(1);
|
|
935
|
+
});
|
|
936
|
+
`;
|
|
937
|
+
writeAtomic(path.join(runtimeRoot, 'launch.cjs'), launcher);
|
|
938
|
+
|
|
939
|
+
const sourceToolsFile = path.join(repoRoot, 'spec', 'mcp-tools.yaml');
|
|
940
|
+
const upstreamManifest = yaml.load(fs.readFileSync(sourceToolsFile, 'utf8'));
|
|
941
|
+
const { REGISTERED_TOOLS } = require(path.join(repoRoot, 'mcp-server', 'server.cjs'));
|
|
942
|
+
const registered = new Set(REGISTERED_TOOLS);
|
|
943
|
+
const liveFamilies = new Set(
|
|
944
|
+
upstreamManifest.tools.filter((tool) => registered.has(tool.name)).map((tool) => tool.family),
|
|
945
|
+
);
|
|
946
|
+
const liveManifest = {
|
|
947
|
+
...upstreamManifest,
|
|
948
|
+
info: {
|
|
949
|
+
...upstreamManifest.info,
|
|
950
|
+
notes: `${upstreamManifest.info.notes.trim()}\n\n${runtime} bundled runtime: only tools registered by the MCP server are listed here.`,
|
|
951
|
+
},
|
|
952
|
+
families: upstreamManifest.families.filter((family) => liveFamilies.has(family.name)),
|
|
953
|
+
tools: upstreamManifest.tools.filter((tool) => registered.has(tool.name)),
|
|
954
|
+
};
|
|
955
|
+
const specRoot = path.join(pluginRoot, 'spec');
|
|
956
|
+
ensureDir(specRoot);
|
|
957
|
+
writeAtomic(path.join(specRoot, 'mcp-tools.yaml'), yaml.dump(liveManifest, { lineWidth: -1, noRefs: true }));
|
|
958
|
+
if (runtime === 'codex') {
|
|
959
|
+
fs.copyFileSync(sourceToolsFile, path.join(specRoot, 'upstream-mcp-tools.yaml'));
|
|
960
|
+
writeAtomic(path.join(specRoot, 'codex-capability-map.json'), JSON.stringify({
|
|
961
|
+
runtime: 'codex',
|
|
962
|
+
live_mcp_tools: REGISTERED_TOOLS,
|
|
963
|
+
codex_native_replacements: CODEX_NATIVE_MCP_REPLACEMENTS,
|
|
964
|
+
}, null, 2) + '\n');
|
|
965
|
+
}
|
|
966
|
+
const sourceSchema = path.join(repoRoot, 'spec', 'schemas', 'state-db.sql');
|
|
967
|
+
const targetSchema = path.join(specRoot, 'schemas', 'state-db.sql');
|
|
968
|
+
ensureDir(path.dirname(targetSchema));
|
|
969
|
+
fs.copyFileSync(sourceSchema, targetSchema);
|
|
970
|
+
|
|
971
|
+
const preferredTemplate = path.join(repoRoot, 'templates', '.ultra');
|
|
972
|
+
const packagedTemplate = path.join(repoRoot, '.ultra-template');
|
|
973
|
+
const templateRoot = fs.existsSync(preferredTemplate) ? preferredTemplate : packagedTemplate;
|
|
974
|
+
if (!fs.existsSync(templateRoot)) {
|
|
975
|
+
throw new Error(`Ultra project template missing from ${repoRoot}`);
|
|
976
|
+
}
|
|
977
|
+
copyTree(templateRoot, path.join(pluginRoot, 'templates', '.ultra'));
|
|
978
|
+
|
|
979
|
+
return {
|
|
980
|
+
launcher: path.join(runtimeRoot, 'launch.cjs'),
|
|
981
|
+
bundle: path.join(runtimeRoot, 'index.cjs'),
|
|
982
|
+
ultraTools: path.join(runtimeRoot, 'ultra-tools.cjs'),
|
|
983
|
+
};
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
function pluginContentHash(pluginRoot, baseVersion) {
|
|
987
|
+
const hash = crypto.createHash('sha256');
|
|
988
|
+
hash.update(baseVersion);
|
|
989
|
+
for (const rel of listRelative(pluginRoot)) {
|
|
990
|
+
if (rel === path.join('.codex-plugin', 'plugin.json') || rel === '.ubp-managed') continue;
|
|
991
|
+
hash.update(rel);
|
|
992
|
+
hash.update(fs.readFileSync(path.join(pluginRoot, rel)));
|
|
993
|
+
}
|
|
994
|
+
return hash.digest('hex').slice(0, 12);
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
function buildPlugin({ repoRoot, pluginRoot }) {
|
|
998
|
+
if (fs.existsSync(pluginRoot)) {
|
|
999
|
+
const marker = path.join(pluginRoot, '.ubp-managed');
|
|
1000
|
+
if (!fs.existsSync(marker)) {
|
|
1001
|
+
throw new Error(`refusing to replace unmanaged plugin directory: ${pluginRoot}`);
|
|
1002
|
+
}
|
|
1003
|
+
removeTree(pluginRoot);
|
|
1004
|
+
}
|
|
1005
|
+
ensureDir(pluginRoot);
|
|
1006
|
+
|
|
1007
|
+
const installedSkills = [];
|
|
1008
|
+
for (const name of skillsForRuntime('codex')) {
|
|
1009
|
+
const sourceDir = path.join(repoRoot, 'skills', name);
|
|
1010
|
+
if (!fs.existsSync(path.join(sourceDir, 'SKILL.md'))) {
|
|
1011
|
+
throw new Error(`missing allowlisted Codex skill: ${name}`);
|
|
1012
|
+
}
|
|
1013
|
+
copySkill(sourceDir, path.join(pluginRoot, 'skills', name), name, name);
|
|
1014
|
+
installedSkills.push(name);
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
copyHooks(repoRoot, pluginRoot);
|
|
1018
|
+
const mcpRuntime = buildMcpRuntime(repoRoot, pluginRoot);
|
|
1019
|
+
writeAtomic(path.join(pluginRoot, '.mcp.json'), JSON.stringify({
|
|
1020
|
+
mcpServers: {
|
|
1021
|
+
[PLUGIN_NAME]: {
|
|
1022
|
+
type: 'stdio',
|
|
1023
|
+
command: process.execPath,
|
|
1024
|
+
args: [mcpRuntime.launcher],
|
|
1025
|
+
},
|
|
1026
|
+
},
|
|
1027
|
+
}, null, 2) + '\n');
|
|
1028
|
+
writeAtomic(path.join(pluginRoot, 'command-map.json'), JSON.stringify(buildCommandMap(), null, 2) + '\n');
|
|
1029
|
+
if (fs.existsSync(path.join(repoRoot, 'LICENSE'))) {
|
|
1030
|
+
fs.copyFileSync(path.join(repoRoot, 'LICENSE'), path.join(pluginRoot, 'LICENSE'));
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(repoRoot, 'package.json'), 'utf8'));
|
|
1034
|
+
const version = `${pkg.version}+codex.${pluginContentHash(pluginRoot, pkg.version)}`;
|
|
1035
|
+
const manifest = {
|
|
1036
|
+
name: PLUGIN_NAME,
|
|
1037
|
+
version,
|
|
1038
|
+
description: 'Codex-native Ultra Builder Pro workflows, agents, hooks, and MCP task state.',
|
|
1039
|
+
author: { name: typeof pkg.author === 'string' ? pkg.author : 'Ultra Builder Pro contributors' },
|
|
1040
|
+
homepage: pkg.homepage,
|
|
1041
|
+
repository: 'https://github.com/rocky2431/ultra-builder-pro-cli',
|
|
1042
|
+
license: pkg.license || 'MIT',
|
|
1043
|
+
keywords: ['codex', 'skills', 'agents', 'hooks', 'mcp', 'ultra-builder-pro'],
|
|
1044
|
+
skills: './skills/',
|
|
1045
|
+
mcpServers: './.mcp.json',
|
|
1046
|
+
interface: {
|
|
1047
|
+
displayName: 'Ultra Builder Pro',
|
|
1048
|
+
shortDescription: 'Codex-native engineering workflows and verification gates.',
|
|
1049
|
+
longDescription: 'Complete Codex adaptation of Ultra Builder Pro skills, command workflows, custom agents, lifecycle hooks, and project-local MCP state.',
|
|
1050
|
+
developerName: typeof pkg.author === 'string' ? pkg.author : 'Ultra Builder Pro contributors',
|
|
1051
|
+
category: 'Developer Tools',
|
|
1052
|
+
capabilities: ['Interactive', 'Write'],
|
|
1053
|
+
websiteURL: pkg.homepage,
|
|
1054
|
+
defaultPrompt: [
|
|
1055
|
+
'Initialize this project with the Ultra Builder Pro workflow.',
|
|
1056
|
+
'Run the Ultra review pipeline on my current changes.',
|
|
1057
|
+
'Show the current Ultra project status and next action.',
|
|
1058
|
+
],
|
|
1059
|
+
brandColor: '#111827',
|
|
1060
|
+
},
|
|
1061
|
+
};
|
|
1062
|
+
writeAtomic(path.join(pluginRoot, '.codex-plugin', 'plugin.json'), JSON.stringify(manifest, null, 2) + '\n');
|
|
1063
|
+
writeAtomic(path.join(pluginRoot, '.ubp-managed'), JSON.stringify({ source: 'ubp', adapter: 'codex', version }, null, 2) + '\n');
|
|
1064
|
+
return { root: pluginRoot, version, skills: installedSkills.sort() };
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
function tomlMultiline(value) {
|
|
1068
|
+
const escaped = String(value)
|
|
1069
|
+
.replace(/\\/g, '\\\\')
|
|
1070
|
+
.replace(/"""/g, '\\"\\"\\"')
|
|
1071
|
+
.replace(/\r/g, '')
|
|
1072
|
+
.replace(/\u0000/g, '');
|
|
1073
|
+
return `"""\\\n${escaped.trim()}\n"""`;
|
|
1074
|
+
}
|
|
1075
|
+
|
|
1076
|
+
function buildAgentToml(sourceText) {
|
|
1077
|
+
const { fm, body } = parseFrontmatter(sourceText);
|
|
1078
|
+
const name = fm.name;
|
|
1079
|
+
const description = adaptHostText(String(fm.description || `${name} Ultra Builder Pro agent.`), name)
|
|
1080
|
+
.replace(/\s+/g, ' ')
|
|
1081
|
+
.trim();
|
|
1082
|
+
let instructions = adaptHostText(body, name);
|
|
1083
|
+
instructions = instructions.replace(
|
|
1084
|
+
/Consult your agent memory[^\n]*/g,
|
|
1085
|
+
'Use the current checkout and parent-supplied context; do not assume persistent custom-agent memory.',
|
|
1086
|
+
);
|
|
1087
|
+
instructions = `You are a native Codex custom agent. Stay inside the delegated scope, preserve unrelated changes, and return concise evidence to the parent task.\n\n${instructions}`;
|
|
1088
|
+
return [
|
|
1089
|
+
`# ${MANAGED_MARKER}`,
|
|
1090
|
+
`name = ${JSON.stringify(name)}`,
|
|
1091
|
+
`description = ${JSON.stringify(description)}`,
|
|
1092
|
+
'model_reasoning_effort = "high"',
|
|
1093
|
+
`developer_instructions = ${tomlMultiline(instructions)}`,
|
|
1094
|
+
'',
|
|
1095
|
+
].join('\n');
|
|
1096
|
+
}
|
|
1097
|
+
|
|
1098
|
+
function installAgents({ repoRoot, configDir }) {
|
|
1099
|
+
const sourceRoot = path.join(repoRoot, 'agents');
|
|
1100
|
+
const targetRoot = path.join(configDir, 'agents');
|
|
1101
|
+
ensureDir(targetRoot);
|
|
1102
|
+
const installed = [];
|
|
1103
|
+
for (const file of fs.readdirSync(sourceRoot).filter((name) => name.endsWith('.md')).sort()) {
|
|
1104
|
+
const targetFile = path.join(targetRoot, file.replace(/\.md$/, '.toml'));
|
|
1105
|
+
if (fs.existsSync(targetFile)) {
|
|
1106
|
+
const existing = fs.readFileSync(targetFile, 'utf8');
|
|
1107
|
+
if (!existing.startsWith(`# ${MANAGED_MARKER}`)) {
|
|
1108
|
+
throw new Error(`refusing to overwrite unmanaged Codex agent: ${targetFile}`);
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
writeAtomic(targetFile, buildAgentToml(fs.readFileSync(path.join(sourceRoot, file), 'utf8')));
|
|
1112
|
+
installed.push(path.basename(targetFile));
|
|
1113
|
+
}
|
|
1114
|
+
return { root: targetRoot, installed };
|
|
1115
|
+
}
|
|
1116
|
+
|
|
1117
|
+
module.exports = {
|
|
1118
|
+
PLUGIN_NAME,
|
|
1119
|
+
MANAGED_MARKER,
|
|
1120
|
+
COMMAND_NAMES,
|
|
1121
|
+
adaptHostText,
|
|
1122
|
+
buildCommandMap,
|
|
1123
|
+
buildHooksManifest,
|
|
1124
|
+
buildMcpRuntime,
|
|
1125
|
+
buildPlugin,
|
|
1126
|
+
buildAgentToml,
|
|
1127
|
+
installAgents,
|
|
1128
|
+
};
|