ultra-builder-pro-cli 0.25.1 → 0.26.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.ultra-template/contexts/TEMPLATE.md +87 -0
- package/.ultra-template/decisions/.gitkeep +1 -0
- package/.ultra-template/evidence/.gitkeep +1 -0
- package/.ultra-template/north-star.md +46 -0
- package/.ultra-template/research/.gitkeep +1 -0
- package/.ultra-template/specs/discovery.md +2 -2
- package/.ultra-template/tasks.json +3 -0
- package/.ultra-template/test-report.json +27 -0
- package/CHANGELOG.md +40 -0
- package/README.md +217 -579
- package/adapters/_shared/delegate-profiles/kimi-read-only.md +15 -0
- package/adapters/_shared/delegate-profiles/kimi-write.md +17 -0
- package/adapters/_shared/file-ops.cjs +76 -2
- package/adapters/_shared/host-profile.cjs +97 -0
- package/adapters/_shared/plugin-core.cjs +204 -0
- package/adapters/_shared/runtime-assets.cjs +31 -96
- package/adapters/claude.js +92 -291
- package/adapters/codex.js +309 -842
- package/adapters/grok.js +143 -1469
- package/adapters/kimi.js +124 -1053
- package/adapters/opencode.js +230 -742
- package/bin/delegate-worker.cjs +323 -0
- package/bin/delegate.cjs +456 -0
- package/bin/install.js +38 -11
- package/docs/ARCHITECTURE.md +122 -216
- package/docs/ARTIFACT-AUTHORITY.md +90 -268
- package/docs/DECISIONS.md +75 -87
- package/docs/PHILOSOPHY.md +177 -0
- package/docs/PLUGIN-ISOLATION-CONTRACT.md +62 -39
- package/docs/RUNTIME-COMPAT-MATRIX.md +99 -156
- package/docs/SKILL-AUTHORING.md +94 -73
- package/docs/WORKFLOW-LIFECYCLE.md +93 -189
- package/hooks/README.md +17 -37
- package/hooks/_common.py +113 -0
- package/hooks/adapters/codex.py +9 -16
- package/hooks/adapters/grok.py +5 -5
- package/hooks/adapters/kimi.py +8 -14
- package/hooks/block_dangerous_commands.py +95 -0
- package/hooks/compact_context.py +65 -0
- package/hooks/mid_workflow_recall.py +25 -0
- package/hooks/post_edit_guard.py +105 -0
- package/hooks/session_context.py +30 -0
- package/package.json +17 -52
- package/skills/ultra-change/SKILL.md +97 -50
- package/skills/ultra-change/references/change-contract.md +40 -1
- package/skills/ultra-delegate/SKILL.md +82 -0
- package/skills/ultra-delegate/references/delegation-contract.md +51 -0
- package/skills/ultra-delegate/scripts/delegate_wait.py +86 -0
- package/skills/ultra-deliver/SKILL.md +61 -42
- package/skills/ultra-deliver/references/baseline-reconciliation.md +39 -20
- package/skills/ultra-dev/SKILL.md +96 -62
- package/skills/ultra-dev/references/debugging.md +22 -0
- package/skills/ultra-domain-modeling/SKILL.md +79 -0
- package/skills/ultra-grilling/SKILL.md +79 -0
- package/skills/ultra-init/SKILL.md +94 -37
- package/skills/ultra-init/references/brownfield-adoption.md +33 -83
- package/skills/ultra-init/scripts/init_project.cjs +84 -0
- package/skills/ultra-plan/SKILL.md +88 -68
- package/skills/ultra-research/SKILL.md +62 -48
- package/skills/ultra-research/references/00-problem-validation.md +5 -5
- package/skills/ultra-research/references/01-opportunity-discovery.md +3 -3
- package/skills/ultra-research/references/02-market-assessment.md +5 -4
- package/skills/ultra-research/references/03-competitive-landscape.md +3 -3
- package/skills/ultra-research/references/04-product-strategy.md +3 -3
- package/skills/ultra-research/references/05-assumptions-validation.md +5 -5
- package/skills/ultra-research/references/10-user-personas.md +3 -2
- package/skills/ultra-research/references/11-user-scenarios.md +3 -3
- package/skills/ultra-research/references/20-user-stories.md +4 -3
- package/skills/ultra-research/references/21-features-scope.md +3 -2
- package/skills/ultra-research/references/22-success-metrics.md +3 -3
- package/skills/ultra-research/references/30-architecture-context.md +3 -3
- package/skills/ultra-research/references/31-solution-strategy.md +3 -3
- package/skills/ultra-research/references/32-building-blocks.md +3 -3
- package/skills/ultra-research/references/40-deployment.md +3 -3
- package/skills/ultra-research/references/41-quality-risks.md +3 -3
- package/skills/ultra-research/references/99-synthesis.md +7 -7
- package/skills/ultra-review/SKILL.md +59 -32
- package/skills/ultra-review/references/code.md +17 -0
- package/skills/ultra-review/references/comments.md +12 -0
- package/skills/ultra-review/references/design.md +12 -0
- package/skills/ultra-review/references/errors.md +13 -0
- package/skills/ultra-review/references/spec.md +13 -0
- package/skills/ultra-review/references/tests.md +12 -0
- package/skills/ultra-review/references/worker-packet.md +40 -0
- package/skills/ultra-review/scripts/review_wait.py +26 -15
- package/skills/ultra-status/SKILL.md +61 -36
- package/skills/ultra-tdd/SKILL.md +81 -0
- package/skills/ultra-tdd/references/templates/README.md +20 -0
- package/skills/ultra-tdd/references/templates/feature-flag-default-audit.sh +79 -0
- package/skills/ultra-tdd/references/templates/persistence-real.ts +78 -0
- package/skills/ultra-tdd/references/templates/testcontainer-postgres.py +78 -0
- package/skills/ultra-tdd/references/templates/testcontainer-postgres.ts +73 -0
- package/skills/ultra-tdd/references/templates/vertical-slice.ts +66 -0
- package/skills/ultra-tdd/references/test-execution.md +18 -0
- package/skills/ultra-test/SKILL.md +70 -30
- package/skills/ultra-test/references/export-syntax.md +18 -0
- package/skills/ultra-test/scripts/worktree_digest.cjs +54 -0
- package/skills/ultra-think/SKILL.md +49 -27
- package/skills/ultra-think/references/autonomy-boundary.md +48 -0
- package/skills/ultra-think/references/interaction-boundary.md +18 -33
- package/.ultra-template/docs/research/README.md +0 -55
- package/.ultra-template/reports/templates/delivery-report.json +0 -17
- package/.ultra-template/reports/templates/test-report.json +0 -18
- package/.ultra-template/tasks/tasks.json +0 -15
- package/.ultra-template/templates/task-context.md +0 -19
- package/adapters/_shared/codex-assets.cjs +0 -725
- package/adapters/_shared/codex-ultra-tools-entry.cjs +0 -11
- package/adapters/_shared/interaction-contract.cjs +0 -129
- package/adapters/_shared/path-rewrite.cjs +0 -79
- package/adapters/_shared/runtime-native.cjs +0 -132
- package/adapters/_shared/settings-merge.cjs +0 -76
- package/agents/code-reviewer.md +0 -42
- package/agents/debugger.md +0 -40
- package/agents/review-code.md +0 -49
- package/agents/review-comments.md +0 -38
- package/agents/review-coordinator.md +0 -56
- package/agents/review-design.md +0 -40
- package/agents/review-errors.md +0 -43
- package/agents/review-spec.md +0 -39
- package/agents/review-tests.md +0 -40
- package/agents/tdd-runner.md +0 -38
- package/bin/orchestrator.js +0 -383
- package/commands/ultra-change.md +0 -10
- package/commands/ultra-deliver.md +0 -10
- package/commands/ultra-dev.md +0 -10
- package/commands/ultra-doctor.md +0 -10
- package/commands/ultra-init.md +0 -10
- package/commands/ultra-plan.md +0 -10
- package/commands/ultra-research.md +0 -10
- package/commands/ultra-review.md +0 -10
- package/commands/ultra-status.md +0 -10
- package/commands/ultra-test.md +0 -10
- package/commands/ultra-think.md +0 -10
- package/docs/AGENT-CONTEXT.md +0 -191
- package/docs/COMMIT-HASH-BACKFILL.md +0 -51
- package/docs/LEGACY-CLI-CROSSWALK.md +0 -175
- package/docs/ROADMAP.md +0 -101
- package/docs/STATE-DB-ACCESS-POLICY.md +0 -161
- package/hooks/active_task_context.py +0 -152
- package/hooks/context_envelope.py +0 -100
- package/hooks/health_check.py +0 -196
- package/hooks/pre_stop_check.py +0 -66
- package/hooks/runtime_paths.py +0 -396
- package/hooks/subagent_tracker.py +0 -88
- package/hooks/workflow_checkpoint.py +0 -76
- package/hooks/workflow_context.py +0 -48
- package/hooks/workflow_resume.py +0 -84
- package/mcp-server/hook-context.cjs +0 -38
- package/mcp-server/hook-event.cjs +0 -34
- package/mcp-server/lib/archive-journal.cjs +0 -1119
- package/mcp-server/lib/archive-mutation-worker.py +0 -365
- package/mcp-server/lib/artifact-registry.cjs +0 -1232
- package/mcp-server/lib/baseline-workflow.cjs +0 -1193
- package/mcp-server/lib/canonical-json.cjs +0 -19
- package/mcp-server/lib/change-authority.cjs +0 -26
- package/mcp-server/lib/change-packet.cjs +0 -790
- package/mcp-server/lib/change-workflow.cjs +0 -65
- package/mcp-server/lib/context-envelope.cjs +0 -581
- package/mcp-server/lib/context-paths.cjs +0 -142
- package/mcp-server/lib/decision-records.cjs +0 -423
- package/mcp-server/lib/delivery-transaction.cjs +0 -471
- package/mcp-server/lib/doctor-backup-worker.cjs +0 -328
- package/mcp-server/lib/doctor.cjs +0 -627
- package/mcp-server/lib/git-bootstrap.cjs +0 -651
- package/mcp-server/lib/init-project.cjs +0 -1021
- package/mcp-server/lib/kernel-change-workflow.cjs +0 -2029
- package/mcp-server/lib/legacy-change-workflow.cjs +0 -3032
- package/mcp-server/lib/managed-file-write.cjs +0 -172
- package/mcp-server/lib/plan-checkpoint.cjs +0 -177
- package/mcp-server/lib/plan-publication-worker.cjs +0 -830
- package/mcp-server/lib/plan-store.cjs +0 -794
- package/mcp-server/lib/prd-parser.cjs +0 -83
- package/mcp-server/lib/pricing.cjs +0 -44
- package/mcp-server/lib/project-context.cjs +0 -178
- package/mcp-server/lib/projector.cjs +0 -386
- package/mcp-server/lib/provider-refs.cjs +0 -42
- package/mcp-server/lib/runtime-paths.cjs +0 -1714
- package/mcp-server/lib/runtime-state.cjs +0 -222
- package/mcp-server/lib/safe-project-file.cjs +0 -385
- package/mcp-server/lib/stage-checkpoints.cjs +0 -463
- package/mcp-server/lib/state-authority.cjs +0 -95
- package/mcp-server/lib/state-db.cjs +0 -1580
- package/mcp-server/lib/state-ops.cjs +0 -1428
- package/mcp-server/lib/task-contract.cjs +0 -404
- package/mcp-server/lib/task-expander.cjs +0 -105
- package/mcp-server/lib/task-ledger.cjs +0 -1964
- package/mcp-server/lib/telemetry.cjs +0 -85
- package/mcp-server/lib/topo.cjs +0 -131
- package/mcp-server/lib/ultra-facade.cjs +0 -2684
- package/mcp-server/lib/worker-packet.cjs +0 -358
- package/mcp-server/server.cjs +0 -437
- package/orchestrator/auto-merge.cjs +0 -128
- package/orchestrator/daemon.cjs +0 -264
- package/orchestrator/dispatch-rules.cjs +0 -78
- package/orchestrator/parallel-orchestrator.cjs +0 -903
- package/orchestrator/planner/plan-builder.cjs +0 -125
- package/orchestrator/recovery.cjs +0 -188
- package/orchestrator/session-close-journal-worker.cjs +0 -5
- package/orchestrator/session-close-journal.cjs +0 -1014
- package/orchestrator/session-runner.cjs +0 -1153
- package/orchestrator/worktree-manager.cjs +0 -282
- package/settings.json +0 -7
- package/skills/cc-collab/SKILL.md +0 -42
- package/skills/code-review-expert/SKILL.md +0 -43
- package/skills/code-review-expert/references/correctness-reliability.md +0 -30
- package/skills/code-review-expert/references/design-boundaries.md +0 -26
- package/skills/code-review-expert/references/removal-plan.md +0 -24
- package/skills/codex-collab/SKILL.md +0 -49
- package/skills/codex-collab/evals/evals.json +0 -35
- package/skills/integration-rules/SKILL.md +0 -32
- package/skills/security-rules/SKILL.md +0 -38
- package/skills/testing-rules/SKILL.md +0 -32
- package/skills/ultra-doctor/SKILL.md +0 -41
- package/skills/ultra-plan/references/semantic-preflight.md +0 -20
- package/skills/ultra-verify/SKILL.md +0 -46
- package/skills/ultra-verify/evals/evals.json +0 -46
- package/skills/ultra-verify/references/cross-verify-modes.md +0 -28
- package/skills/ultra-verify/references/evidence-status.md +0 -21
- package/skills/ultra-verify/scripts/verify_wait.py +0 -94
- package/spec/cli-protocol.md +0 -102
- package/spec/mcp-tools.yaml +0 -312
- package/spec/schemas/baseline-reconciliation.v1.schema.json +0 -73
- package/spec/schemas/change-delta.v1.schema.json +0 -153
- package/spec/schemas/command-manifest.schema.json +0 -29
- package/spec/schemas/context-file.v4.5.schema.json +0 -54
- package/spec/schemas/delivery-report.v1.schema.json +0 -66
- package/spec/schemas/documentation-reconciliation.v1.schema.json +0 -106
- package/spec/schemas/mcp-tools.schema.json +0 -136
- package/spec/schemas/skill-manifest.schema.json +0 -24
- package/spec/schemas/state-db.sql +0 -641
- package/spec/schemas/task-ledger.v2.schema.json +0 -296
- package/spec/schemas/tasks.v4.5.schema.json +0 -96
- package/spec/schemas/test-report.v1.schema.json +0 -225
- package/ultra-tools/cli.cjs +0 -129
- package/ultra-tools/commands/db.cjs +0 -226
- package/ultra-tools/commands/legacy-memory.cjs +0 -159
- package/ultra-tools/commands/migrate.cjs +0 -1386
- package/ultra-tools/commands/session.cjs +0 -213
- package/ultra-tools/commands/status.cjs +0 -559
- package/ultra-tools/commands/system.cjs +0 -498
- package/ultra-tools/commands/task.cjs +0 -105
|
@@ -1,725 +0,0 @@
|
|
|
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
|
-
RUNTIME_SUPPORT_FILES,
|
|
12
|
-
RUNTIME_WORKER_FILES,
|
|
13
|
-
WORKFLOW_HOOK_FILES,
|
|
14
|
-
skillPolicy,
|
|
15
|
-
skillsForRuntime,
|
|
16
|
-
} = require('./runtime-assets.cjs');
|
|
17
|
-
|
|
18
|
-
const { parse: parseFrontmatter } = require('./frontmatter.cjs');
|
|
19
|
-
const {
|
|
20
|
-
copyTree,
|
|
21
|
-
ensureDir,
|
|
22
|
-
listRelative,
|
|
23
|
-
removeTree,
|
|
24
|
-
writeAtomic,
|
|
25
|
-
} = require('./file-ops.cjs');
|
|
26
|
-
const {
|
|
27
|
-
adaptInteractionGuidance,
|
|
28
|
-
interactionContract,
|
|
29
|
-
} = require('./interaction-contract.cjs');
|
|
30
|
-
|
|
31
|
-
const PLUGIN_NAME = 'ultra-builder-pro';
|
|
32
|
-
const MANAGED_MARKER = 'Managed by Ultra Builder Pro Codex adapter.';
|
|
33
|
-
const COMMAND_NAMES = Object.freeze(CORE_PUBLIC_SKILLS.filter((name) => name !== 'ultra-review'));
|
|
34
|
-
const SKILL_REFERENCE_NAMES = Object.freeze([
|
|
35
|
-
...COMMAND_NAMES,
|
|
36
|
-
'cc-collab',
|
|
37
|
-
'ultra-review',
|
|
38
|
-
'ultra-verify',
|
|
39
|
-
]);
|
|
40
|
-
const CODEX_PRIMARY_SKILLS = new Set([...COMMAND_NAMES, 'ultra-review']);
|
|
41
|
-
const TEXT_EXTENSIONS = new Set(['.md', '.json', '.py', '.sh', '.txt', '.yaml', '.yml']);
|
|
42
|
-
const NATIVE_PACKAGES = Object.freeze([
|
|
43
|
-
'better-sqlite3',
|
|
44
|
-
'bindings',
|
|
45
|
-
'file-uri-to-path',
|
|
46
|
-
]);
|
|
47
|
-
|
|
48
|
-
function titleCase(name) {
|
|
49
|
-
const special = { 'cc-collab': 'Claude Code Collaboration' };
|
|
50
|
-
if (special[name]) return special[name];
|
|
51
|
-
return name.split('-').map((part) => part ? part[0].toUpperCase() + part.slice(1) : part).join(' ');
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function replaceSlashCommand(text, command, replacement) {
|
|
55
|
-
const escaped = command.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
56
|
-
return text.replace(
|
|
57
|
-
new RegExp(`(^|[\\s\\x60(>])/${escaped}(?=$|[\\s\\x60,.;):])`, 'gm'),
|
|
58
|
-
(_match, prefix) => `${prefix}${replacement}`,
|
|
59
|
-
);
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
function adaptCodexPrimaryText(input, skillName) {
|
|
63
|
-
let text = String(input);
|
|
64
|
-
if (skillName === 'ultra-review') {
|
|
65
|
-
text = text.replace(
|
|
66
|
-
/(?:the current host's native|the host-native) bounded-worker\s+mechanism/g,
|
|
67
|
-
'native Codex custom agents installed for the selected review workers',
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
return text;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
function adaptSkillAsset(input, targetName, _rel) {
|
|
75
|
-
return adaptHostText(input, targetName);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
function adaptHostText(input, skillName = '') {
|
|
79
|
-
let text = adaptInteractionGuidance(input, 'codex');
|
|
80
|
-
text = text.replaceAll('codex-collab', 'cc-collab');
|
|
81
|
-
text = text.replaceAll('CLAUDE.md', 'AGENTS.md');
|
|
82
|
-
text = text.replaceAll('$CLAUDE_PLUGIN_ROOT/skills', '~/plugins/ultra-builder-pro/skills');
|
|
83
|
-
text = text.replaceAll('~/.claude/skills', '~/plugins/ultra-builder-pro/skills');
|
|
84
|
-
text = text.replaceAll('~/.codex/skills', '~/plugins/ultra-builder-pro/skills');
|
|
85
|
-
text = text.replaceAll('~/.claude/hooks', '~/plugins/ultra-builder-pro/hooks');
|
|
86
|
-
text = text.replaceAll('~/.claude', '~/.codex');
|
|
87
|
-
|
|
88
|
-
for (const skill of SKILL_REFERENCE_NAMES) {
|
|
89
|
-
text = replaceSlashCommand(text, skill, `$ultra-builder-pro:${skill}`);
|
|
90
|
-
}
|
|
91
|
-
text = replaceSlashCommand(text, 'clear', 'start a new Codex task');
|
|
92
|
-
|
|
93
|
-
if (CODEX_PRIMARY_SKILLS.has(skillName)) {
|
|
94
|
-
text = adaptCodexPrimaryText(text, skillName);
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
return text;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
function adaptedDescription(sourceDescription, targetName) {
|
|
101
|
-
const special = {
|
|
102
|
-
'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.',
|
|
103
|
-
'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.',
|
|
104
|
-
'ultra-dev': 'Execute one authoritative Ultra task with Codex-native implementation, verification, and review. Use when a dependency-ready slice is ready for development.',
|
|
105
|
-
};
|
|
106
|
-
return special[targetName] || adaptHostText(String(sourceDescription || `${titleCase(targetName)} workflow for Codex.`), targetName)
|
|
107
|
-
.replace(/\s+/g, ' ')
|
|
108
|
-
.trim();
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
function buildSkillMarkdown(sourceText, sourceName, targetName) {
|
|
112
|
-
const { fm, body } = parseFrontmatter(sourceText);
|
|
113
|
-
const adaptedBody = adaptHostText(body, targetName);
|
|
114
|
-
return yaml.dump({
|
|
115
|
-
name: targetName,
|
|
116
|
-
description: adaptedDescription(fm && fm.description, targetName),
|
|
117
|
-
}, { lineWidth: -1, noRefs: true }).trimEnd()
|
|
118
|
-
.replace(/^/, '---\n') + `\n---\n\n${adaptedBody.trim()}\n`;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function shortDescription(description, name) {
|
|
122
|
-
const value = String(description || `${titleCase(name)} for Codex`).replace(/\s+/g, ' ').trim();
|
|
123
|
-
if (value.length <= 64) return value;
|
|
124
|
-
const candidate = value.slice(0, 65);
|
|
125
|
-
const boundary = candidate.lastIndexOf(' ');
|
|
126
|
-
const short = (boundary >= 25 ? candidate.slice(0, boundary) : value.slice(0, 64))
|
|
127
|
-
.replace(/[\s.,;:]+$/, '');
|
|
128
|
-
return short || `${titleCase(name)} for Codex`;
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
function buildOpenAiYaml(name, description) {
|
|
132
|
-
const policy = skillPolicy(name);
|
|
133
|
-
const metadata = {
|
|
134
|
-
interface: {
|
|
135
|
-
display_name: titleCase(name),
|
|
136
|
-
short_description: shortDescription(description, name),
|
|
137
|
-
default_prompt: `Use $ultra-builder-pro:${name} for this task and follow its workflow.`,
|
|
138
|
-
},
|
|
139
|
-
policy: { allow_implicit_invocation: policy.allowImplicitInvocation },
|
|
140
|
-
};
|
|
141
|
-
if (policy.requiresUltraMcp) {
|
|
142
|
-
metadata.dependencies = {
|
|
143
|
-
tools: [{
|
|
144
|
-
type: 'mcp',
|
|
145
|
-
value: PLUGIN_NAME,
|
|
146
|
-
description: 'Ultra Builder Pro authoritative task and change runtime',
|
|
147
|
-
}],
|
|
148
|
-
};
|
|
149
|
-
}
|
|
150
|
-
return yaml.dump(metadata, {
|
|
151
|
-
lineWidth: -1,
|
|
152
|
-
noRefs: true,
|
|
153
|
-
forceQuotes: true,
|
|
154
|
-
quotingType: "'",
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
function isTextFile(rel) {
|
|
159
|
-
return TEXT_EXTENSIONS.has(path.extname(rel).toLowerCase());
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function copySkill(sourceDir, targetDir, sourceName, targetName) {
|
|
163
|
-
if (targetName === 'cc-collab') {
|
|
164
|
-
ensureDir(targetDir);
|
|
165
|
-
const sourceText = fs.readFileSync(path.join(sourceDir, 'SKILL.md'), 'utf8');
|
|
166
|
-
const skillText = buildSkillMarkdown(sourceText, sourceName, targetName);
|
|
167
|
-
writeAtomic(path.join(targetDir, 'SKILL.md'), skillText);
|
|
168
|
-
const description = parseFrontmatter(skillText).fm.description;
|
|
169
|
-
writeAtomic(path.join(targetDir, 'agents', 'openai.yaml'), buildOpenAiYaml(targetName, description));
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
copyTree(sourceDir, targetDir, {
|
|
174
|
-
transform(original, rel) {
|
|
175
|
-
if (rel === path.join('agents', 'openai.yaml')) return original;
|
|
176
|
-
if (rel === 'SKILL.md') {
|
|
177
|
-
return Buffer.from(buildSkillMarkdown(original.toString('utf8'), sourceName, targetName));
|
|
178
|
-
}
|
|
179
|
-
if (!isTextFile(rel)) return original;
|
|
180
|
-
return Buffer.from(adaptSkillAsset(original.toString('utf8'), targetName, rel));
|
|
181
|
-
},
|
|
182
|
-
});
|
|
183
|
-
const skillText = fs.readFileSync(path.join(targetDir, 'SKILL.md'), 'utf8');
|
|
184
|
-
const description = parseFrontmatter(skillText).fm.description;
|
|
185
|
-
writeAtomic(path.join(targetDir, 'agents', 'openai.yaml'), buildOpenAiYaml(targetName, description));
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
function buildCommandMap() {
|
|
189
|
-
return Object.fromEntries(COMMAND_NAMES.map((name) => [`/${name}`, `$ultra-builder-pro:${name}`]));
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
function shellQuote(value) {
|
|
193
|
-
return `'${String(value).replaceAll("'", "'\"'\"'")}'`;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
function hookCommand(pluginRoot, feature, ...args) {
|
|
197
|
-
const adapter = path.join(path.resolve(pluginRoot), 'hooks', 'adapters', 'codex.py');
|
|
198
|
-
return [
|
|
199
|
-
`python3 ${shellQuote(adapter)}`,
|
|
200
|
-
shellQuote(feature),
|
|
201
|
-
...args.map((arg) => shellQuote(arg)),
|
|
202
|
-
].join(' ');
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
function commandHook(pluginRoot, feature, timeout, statusMessage, ...args) {
|
|
206
|
-
return {
|
|
207
|
-
type: 'command',
|
|
208
|
-
command: hookCommand(pluginRoot, feature, ...args),
|
|
209
|
-
timeout,
|
|
210
|
-
statusMessage,
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
function buildHooksManifest(pluginRoot) {
|
|
215
|
-
return {
|
|
216
|
-
hooks: {
|
|
217
|
-
SessionStart: [
|
|
218
|
-
{ hooks: [commandHook(pluginRoot, 'health_check.py', 5, 'Checking Ultra runtime')] },
|
|
219
|
-
{ hooks: [commandHook(pluginRoot, 'workflow_context.py', 10, 'Loading active Ultra workflow')] },
|
|
220
|
-
],
|
|
221
|
-
PreToolUse: [
|
|
222
|
-
{ matcher: 'Edit|Write|apply_patch', hooks: [commandHook(pluginRoot, 'active_task_context.py', 3, 'Checking active Ultra task')] },
|
|
223
|
-
],
|
|
224
|
-
PreCompact: [
|
|
225
|
-
{ matcher: 'manual|auto', hooks: [commandHook(pluginRoot, 'workflow_checkpoint.py', 10, 'Saving Ultra workflow checkpoint')] },
|
|
226
|
-
],
|
|
227
|
-
PostCompact: [
|
|
228
|
-
{ hooks: [commandHook(pluginRoot, 'workflow_resume.py', 10, 'Restoring Ultra workflow checkpoint')] },
|
|
229
|
-
],
|
|
230
|
-
Stop: [
|
|
231
|
-
{ hooks: [commandHook(pluginRoot, 'pre_stop_check.py', 5, 'Reporting Ultra workflow position')] },
|
|
232
|
-
],
|
|
233
|
-
SubagentStart: [
|
|
234
|
-
{ hooks: [commandHook(pluginRoot, 'subagent_tracker.py', 5, 'Tracking Ultra subagent', 'start')] },
|
|
235
|
-
],
|
|
236
|
-
SubagentStop: [
|
|
237
|
-
{ hooks: [commandHook(pluginRoot, 'subagent_tracker.py', 5, 'Tracking Ultra subagent', 'stop')] },
|
|
238
|
-
],
|
|
239
|
-
},
|
|
240
|
-
};
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
function copyHooks(repoRoot, pluginRoot, publishedRoot = pluginRoot) {
|
|
244
|
-
const sourceRoot = path.join(repoRoot, 'hooks');
|
|
245
|
-
const targetRoot = path.join(pluginRoot, 'hooks');
|
|
246
|
-
ensureDir(targetRoot);
|
|
247
|
-
for (const name of WORKFLOW_HOOK_FILES) {
|
|
248
|
-
fs.copyFileSync(path.join(sourceRoot, name), path.join(targetRoot, name));
|
|
249
|
-
}
|
|
250
|
-
ensureDir(path.join(targetRoot, 'adapters'));
|
|
251
|
-
fs.copyFileSync(
|
|
252
|
-
path.join(sourceRoot, 'adapters', 'codex.py'),
|
|
253
|
-
path.join(targetRoot, 'adapters', 'codex.py'),
|
|
254
|
-
);
|
|
255
|
-
writeAtomic(
|
|
256
|
-
path.join(targetRoot, 'hooks.json'),
|
|
257
|
-
JSON.stringify(buildHooksManifest(publishedRoot), null, 2) + '\n',
|
|
258
|
-
);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
function buildMcpRuntime(repoRoot, pluginRoot, { runtime = 'codex' } = {}) {
|
|
262
|
-
const source = path.join(repoRoot, 'mcp-server', 'server.cjs');
|
|
263
|
-
const cliSource = path.join(repoRoot, 'adapters', '_shared', 'codex-ultra-tools-entry.cjs');
|
|
264
|
-
const runtimeWorkerSources = new Map([
|
|
265
|
-
[
|
|
266
|
-
'session-close-journal-worker.cjs',
|
|
267
|
-
path.join(repoRoot, 'orchestrator', 'session-close-journal-worker.cjs'),
|
|
268
|
-
],
|
|
269
|
-
[
|
|
270
|
-
'doctor-backup-worker.cjs',
|
|
271
|
-
path.join(repoRoot, 'mcp-server', 'lib', 'doctor-backup-worker.cjs'),
|
|
272
|
-
],
|
|
273
|
-
]);
|
|
274
|
-
const runtimeRoot = path.join(pluginRoot, 'runtime');
|
|
275
|
-
const buildRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'ubp-codex-mcp-build-'));
|
|
276
|
-
let nccCli;
|
|
277
|
-
try {
|
|
278
|
-
nccCli = require.resolve('@vercel/ncc/dist/ncc/cli.js');
|
|
279
|
-
} catch (error) {
|
|
280
|
-
throw new Error(`Ultra MCP bundling requires @vercel/ncc: ${error.message}`);
|
|
281
|
-
}
|
|
282
|
-
|
|
283
|
-
try {
|
|
284
|
-
const bundled = spawnSync(process.execPath, [
|
|
285
|
-
nccCli,
|
|
286
|
-
'build',
|
|
287
|
-
source,
|
|
288
|
-
'-o',
|
|
289
|
-
buildRoot,
|
|
290
|
-
'--no-cache',
|
|
291
|
-
'--quiet',
|
|
292
|
-
'-e',
|
|
293
|
-
'better-sqlite3',
|
|
294
|
-
], {
|
|
295
|
-
cwd: repoRoot,
|
|
296
|
-
encoding: 'utf8',
|
|
297
|
-
maxBuffer: 16 * 1024 * 1024,
|
|
298
|
-
});
|
|
299
|
-
if (bundled.error) throw bundled.error;
|
|
300
|
-
if (bundled.status !== 0) {
|
|
301
|
-
const detail = (bundled.stderr || bundled.stdout || '').trim();
|
|
302
|
-
throw new Error(`ncc failed to bundle the Ultra MCP runtime${detail ? `: ${detail}` : ''}`);
|
|
303
|
-
}
|
|
304
|
-
copyTree(buildRoot, runtimeRoot);
|
|
305
|
-
} finally {
|
|
306
|
-
removeTree(buildRoot);
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
const cliBuildRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'ubp-codex-cli-build-'));
|
|
310
|
-
try {
|
|
311
|
-
const bundled = spawnSync(process.execPath, [
|
|
312
|
-
nccCli,
|
|
313
|
-
'build',
|
|
314
|
-
cliSource,
|
|
315
|
-
'-o',
|
|
316
|
-
cliBuildRoot,
|
|
317
|
-
'--no-cache',
|
|
318
|
-
'--quiet',
|
|
319
|
-
'-e',
|
|
320
|
-
'better-sqlite3',
|
|
321
|
-
], {
|
|
322
|
-
cwd: repoRoot,
|
|
323
|
-
encoding: 'utf8',
|
|
324
|
-
maxBuffer: 16 * 1024 * 1024,
|
|
325
|
-
});
|
|
326
|
-
if (bundled.error) throw bundled.error;
|
|
327
|
-
if (bundled.status !== 0) {
|
|
328
|
-
const detail = (bundled.stderr || bundled.stdout || '').trim();
|
|
329
|
-
throw new Error(`ncc failed to bundle the Ultra fallback CLI${detail ? `: ${detail}` : ''}`);
|
|
330
|
-
}
|
|
331
|
-
for (const rel of listRelative(cliBuildRoot)) {
|
|
332
|
-
const target = rel === 'index.cjs'
|
|
333
|
-
? path.join(runtimeRoot, 'ultra-tools.cjs')
|
|
334
|
-
: path.join(runtimeRoot, rel);
|
|
335
|
-
ensureDir(path.dirname(target));
|
|
336
|
-
fs.copyFileSync(path.join(cliBuildRoot, rel), target);
|
|
337
|
-
}
|
|
338
|
-
} finally {
|
|
339
|
-
removeTree(cliBuildRoot);
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
for (const workerFile of RUNTIME_WORKER_FILES) {
|
|
343
|
-
const workerSource = runtimeWorkerSources.get(workerFile);
|
|
344
|
-
if (!workerSource) {
|
|
345
|
-
throw new Error(`Ultra runtime worker source is not registered: ${workerFile}`);
|
|
346
|
-
}
|
|
347
|
-
const workerBuildRoot = fs.mkdtempSync(path.join(
|
|
348
|
-
os.tmpdir(),
|
|
349
|
-
`ubp-${path.basename(workerFile, '.cjs')}-build-`,
|
|
350
|
-
));
|
|
351
|
-
try {
|
|
352
|
-
const bundled = spawnSync(process.execPath, [
|
|
353
|
-
nccCli,
|
|
354
|
-
'build',
|
|
355
|
-
workerSource,
|
|
356
|
-
'-o',
|
|
357
|
-
workerBuildRoot,
|
|
358
|
-
'--no-cache',
|
|
359
|
-
'--quiet',
|
|
360
|
-
'-e',
|
|
361
|
-
'better-sqlite3',
|
|
362
|
-
], {
|
|
363
|
-
cwd: repoRoot,
|
|
364
|
-
encoding: 'utf8',
|
|
365
|
-
maxBuffer: 16 * 1024 * 1024,
|
|
366
|
-
});
|
|
367
|
-
if (bundled.error) throw bundled.error;
|
|
368
|
-
if (bundled.status !== 0) {
|
|
369
|
-
const detail = (bundled.stderr || bundled.stdout || '').trim();
|
|
370
|
-
throw new Error(
|
|
371
|
-
`ncc failed to bundle Ultra runtime worker ${workerFile}${detail ? `: ${detail}` : ''}`,
|
|
372
|
-
);
|
|
373
|
-
}
|
|
374
|
-
const workerOutput = path.join(workerBuildRoot, 'index.cjs');
|
|
375
|
-
if (!fs.existsSync(workerOutput)) {
|
|
376
|
-
throw new Error(`ncc did not emit Ultra runtime worker ${workerFile}`);
|
|
377
|
-
}
|
|
378
|
-
fs.copyFileSync(workerOutput, path.join(runtimeRoot, workerFile));
|
|
379
|
-
} finally {
|
|
380
|
-
removeTree(workerBuildRoot);
|
|
381
|
-
}
|
|
382
|
-
}
|
|
383
|
-
|
|
384
|
-
for (const supportFile of RUNTIME_SUPPORT_FILES) {
|
|
385
|
-
const sourceFile = path.join(repoRoot, 'mcp-server', 'lib', supportFile);
|
|
386
|
-
if (!fs.existsSync(sourceFile) || !fs.statSync(sourceFile).isFile()) {
|
|
387
|
-
throw new Error(`Ultra runtime support asset is missing: ${supportFile}`);
|
|
388
|
-
}
|
|
389
|
-
fs.copyFileSync(sourceFile, path.join(runtimeRoot, supportFile));
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
const nodeModulesRoot = path.join(runtimeRoot, 'node_modules');
|
|
393
|
-
for (const packageName of NATIVE_PACKAGES) {
|
|
394
|
-
let packageFile;
|
|
395
|
-
try {
|
|
396
|
-
packageFile = require.resolve(`${packageName}/package.json`, { paths: [repoRoot] });
|
|
397
|
-
} catch (error) {
|
|
398
|
-
throw new Error(`Ultra native runtime dependency ${packageName} is unavailable: ${error.message}`);
|
|
399
|
-
}
|
|
400
|
-
copyTree(
|
|
401
|
-
path.dirname(packageFile),
|
|
402
|
-
path.join(nodeModulesRoot, packageName),
|
|
403
|
-
);
|
|
404
|
-
}
|
|
405
|
-
const nativeRelative = path.join(
|
|
406
|
-
'node_modules',
|
|
407
|
-
'better-sqlite3',
|
|
408
|
-
'build',
|
|
409
|
-
'Release',
|
|
410
|
-
'better_sqlite3.node',
|
|
411
|
-
);
|
|
412
|
-
const nativeFile = path.join(runtimeRoot, nativeRelative);
|
|
413
|
-
if (!fs.existsSync(nativeFile) || !fs.statSync(nativeFile).isFile()) {
|
|
414
|
-
throw new Error(`Ultra native SQLite driver is missing after staging: ${nativeFile}`);
|
|
415
|
-
}
|
|
416
|
-
const betterSqlitePackage = JSON.parse(fs.readFileSync(
|
|
417
|
-
path.join(nodeModulesRoot, 'better-sqlite3', 'package.json'),
|
|
418
|
-
'utf8',
|
|
419
|
-
));
|
|
420
|
-
writeAtomic(path.join(runtimeRoot, 'native-runtime.json'), JSON.stringify({
|
|
421
|
-
schema_version: 1,
|
|
422
|
-
platform: process.platform,
|
|
423
|
-
arch: process.arch,
|
|
424
|
-
modules: process.versions.modules,
|
|
425
|
-
node_version: process.versions.node,
|
|
426
|
-
package: {
|
|
427
|
-
name: 'better-sqlite3',
|
|
428
|
-
version: betterSqlitePackage.version,
|
|
429
|
-
},
|
|
430
|
-
native_module: nativeRelative.split(path.sep).join('/'),
|
|
431
|
-
native_sha256: crypto.createHash('sha256').update(fs.readFileSync(nativeFile)).digest('hex'),
|
|
432
|
-
}, null, 2) + '\n');
|
|
433
|
-
fs.copyFileSync(
|
|
434
|
-
path.join(repoRoot, 'adapters', '_shared', 'runtime-native.cjs'),
|
|
435
|
-
path.join(runtimeRoot, 'runtime-native.cjs'),
|
|
436
|
-
);
|
|
437
|
-
|
|
438
|
-
const runtimeBootstrap = runtime === 'kimi' ? `
|
|
439
|
-
const fs = require('node:fs');
|
|
440
|
-
const pluginRoot = path.resolve(__dirname, '..');
|
|
441
|
-
|
|
442
|
-
function usableProjectRoot(value) {
|
|
443
|
-
if (typeof value !== 'string' || !value.trim()) return null;
|
|
444
|
-
const candidate = path.resolve(value);
|
|
445
|
-
if (candidate === pluginRoot || candidate.startsWith(pluginRoot + path.sep)) return null;
|
|
446
|
-
try {
|
|
447
|
-
return fs.statSync(candidate).isDirectory() ? candidate : null;
|
|
448
|
-
} catch (_) {
|
|
449
|
-
return null;
|
|
450
|
-
}
|
|
451
|
-
}
|
|
452
|
-
|
|
453
|
-
if (!process.env.UBP_ROOT_DIR) {
|
|
454
|
-
const rootDir = usableProjectRoot(process.cwd()) || usableProjectRoot(process.env.PWD);
|
|
455
|
-
if (!rootDir) {
|
|
456
|
-
throw new Error('Kimi Ultra MCP could not resolve the active project root; start Kimi from the project directory');
|
|
457
|
-
}
|
|
458
|
-
process.env.UBP_ROOT_DIR = rootDir;
|
|
459
|
-
}
|
|
460
|
-
` : '';
|
|
461
|
-
|
|
462
|
-
const launcher = `'use strict';
|
|
463
|
-
|
|
464
|
-
const path = require('node:path');
|
|
465
|
-
const { inspectRuntimeNative } = require('./runtime-native.cjs');
|
|
466
|
-
|
|
467
|
-
process.env.UBP_RUNTIME_ROOT = path.resolve(__dirname, '..');
|
|
468
|
-
${runtimeBootstrap}
|
|
469
|
-
|
|
470
|
-
inspectRuntimeNative(__dirname);
|
|
471
|
-
const { main } = require('./index.cjs');
|
|
472
|
-
|
|
473
|
-
main().catch((error) => {
|
|
474
|
-
process.stderr.write(\`mcp-server fatal: \${error.message}\\n\`);
|
|
475
|
-
process.exit(1);
|
|
476
|
-
});
|
|
477
|
-
`;
|
|
478
|
-
writeAtomic(path.join(runtimeRoot, 'launch.cjs'), launcher);
|
|
479
|
-
fs.copyFileSync(
|
|
480
|
-
path.join(repoRoot, 'mcp-server', 'hook-context.cjs'),
|
|
481
|
-
path.join(runtimeRoot, 'hook-context.cjs'),
|
|
482
|
-
);
|
|
483
|
-
fs.copyFileSync(
|
|
484
|
-
path.join(repoRoot, 'mcp-server', 'hook-event.cjs'),
|
|
485
|
-
path.join(runtimeRoot, 'hook-event.cjs'),
|
|
486
|
-
);
|
|
487
|
-
fs.copyFileSync(
|
|
488
|
-
path.join(repoRoot, 'mcp-server', 'lib', 'plan-publication-worker.cjs'),
|
|
489
|
-
path.join(runtimeRoot, 'plan-publication-worker.cjs'),
|
|
490
|
-
);
|
|
491
|
-
|
|
492
|
-
const sourceToolsFile = path.join(repoRoot, 'spec', 'mcp-tools.yaml');
|
|
493
|
-
const upstreamManifest = yaml.load(fs.readFileSync(sourceToolsFile, 'utf8'));
|
|
494
|
-
const { REGISTERED_TOOLS } = require(path.join(repoRoot, 'mcp-server', 'server.cjs'));
|
|
495
|
-
const registered = new Set(REGISTERED_TOOLS);
|
|
496
|
-
const liveFamilies = new Set(
|
|
497
|
-
upstreamManifest.tools.filter((tool) => registered.has(tool.name)).map((tool) => tool.family),
|
|
498
|
-
);
|
|
499
|
-
const liveManifest = {
|
|
500
|
-
...upstreamManifest,
|
|
501
|
-
info: {
|
|
502
|
-
...upstreamManifest.info,
|
|
503
|
-
notes: `${upstreamManifest.info.notes.trim()}\n\n${runtime} bundled runtime: only tools registered by the MCP server are listed here.`,
|
|
504
|
-
},
|
|
505
|
-
families: upstreamManifest.families.filter((family) => liveFamilies.has(family.name)),
|
|
506
|
-
tools: upstreamManifest.tools.filter((tool) => registered.has(tool.name)),
|
|
507
|
-
};
|
|
508
|
-
const specRoot = path.join(pluginRoot, 'spec');
|
|
509
|
-
ensureDir(specRoot);
|
|
510
|
-
writeAtomic(path.join(specRoot, 'mcp-tools.yaml'), yaml.dump(liveManifest, { lineWidth: -1, noRefs: true }));
|
|
511
|
-
writeAtomic(
|
|
512
|
-
path.join(specRoot, 'interaction-contract.json'),
|
|
513
|
-
JSON.stringify(interactionContract(runtime), null, 2) + '\n',
|
|
514
|
-
);
|
|
515
|
-
const sourceSchema = path.join(repoRoot, 'spec', 'schemas', 'state-db.sql');
|
|
516
|
-
const targetSchema = path.join(specRoot, 'schemas', 'state-db.sql');
|
|
517
|
-
ensureDir(path.dirname(targetSchema));
|
|
518
|
-
fs.copyFileSync(sourceSchema, targetSchema);
|
|
519
|
-
|
|
520
|
-
const preferredTemplate = path.join(repoRoot, 'templates', '.ultra');
|
|
521
|
-
const packagedTemplate = path.join(repoRoot, '.ultra-template');
|
|
522
|
-
const templateRoot = fs.existsSync(preferredTemplate) ? preferredTemplate : packagedTemplate;
|
|
523
|
-
if (!fs.existsSync(templateRoot)) {
|
|
524
|
-
throw new Error(`Ultra project template missing from ${repoRoot}`);
|
|
525
|
-
}
|
|
526
|
-
copyTree(templateRoot, path.join(pluginRoot, 'templates', '.ultra'));
|
|
527
|
-
|
|
528
|
-
return {
|
|
529
|
-
launcher: path.join(runtimeRoot, 'launch.cjs'),
|
|
530
|
-
bundle: path.join(runtimeRoot, 'index.cjs'),
|
|
531
|
-
ultraTools: path.join(runtimeRoot, 'ultra-tools.cjs'),
|
|
532
|
-
nativeManifest: path.join(runtimeRoot, 'native-runtime.json'),
|
|
533
|
-
};
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
function mcpCommand(launcher) {
|
|
537
|
-
if (process.platform === 'win32') {
|
|
538
|
-
return { command: 'node.exe', args: [launcher] };
|
|
539
|
-
}
|
|
540
|
-
return { command: '/usr/bin/env', args: ['node', launcher] };
|
|
541
|
-
}
|
|
542
|
-
|
|
543
|
-
function inspectInstalledRuntime(runtimeRoot) {
|
|
544
|
-
const report = {
|
|
545
|
-
status: 'healthy',
|
|
546
|
-
checks: {},
|
|
547
|
-
issues: [],
|
|
548
|
-
};
|
|
549
|
-
try {
|
|
550
|
-
const detail = require(path.join(runtimeRoot, 'runtime-native.cjs'))
|
|
551
|
-
.inspectRuntimeNative(runtimeRoot);
|
|
552
|
-
report.checks.native_runtime = { status: 'pass', ...detail };
|
|
553
|
-
} catch (error) {
|
|
554
|
-
report.status = 'degraded';
|
|
555
|
-
report.checks.native_runtime = { status: 'fail' };
|
|
556
|
-
report.issues.push({
|
|
557
|
-
code: error.code || 'RUNTIME_NATIVE_MISSING',
|
|
558
|
-
message: error.message,
|
|
559
|
-
...(error.details || {}),
|
|
560
|
-
});
|
|
561
|
-
}
|
|
562
|
-
return report;
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
function applyNativeDoctor(report, runtimeRoot) {
|
|
566
|
-
const native = inspectInstalledRuntime(runtimeRoot);
|
|
567
|
-
report.checks = { ...(report.checks || {}), ...native.checks };
|
|
568
|
-
report.issues = [...(report.issues || []), ...native.issues];
|
|
569
|
-
if (report.status !== 'missing') {
|
|
570
|
-
report.status = report.issues.length === 0 ? 'healthy' : 'degraded';
|
|
571
|
-
}
|
|
572
|
-
return report;
|
|
573
|
-
}
|
|
574
|
-
|
|
575
|
-
function pluginContentHash(pluginRoot, baseVersion) {
|
|
576
|
-
const hash = crypto.createHash('sha256');
|
|
577
|
-
hash.update(baseVersion);
|
|
578
|
-
for (const rel of listRelative(pluginRoot)) {
|
|
579
|
-
if (rel === path.join('.codex-plugin', 'plugin.json') || rel === '.ubp-managed') continue;
|
|
580
|
-
hash.update(rel);
|
|
581
|
-
hash.update(fs.readFileSync(path.join(pluginRoot, rel)));
|
|
582
|
-
}
|
|
583
|
-
return hash.digest('hex').slice(0, 12);
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
function buildPlugin({ repoRoot, pluginRoot, publishedRoot = pluginRoot }) {
|
|
587
|
-
if (fs.existsSync(pluginRoot)) {
|
|
588
|
-
const marker = path.join(pluginRoot, '.ubp-managed');
|
|
589
|
-
const entries = fs.readdirSync(pluginRoot);
|
|
590
|
-
if (entries.length > 0 && !fs.existsSync(marker)) {
|
|
591
|
-
throw new Error(`refusing to replace unmanaged plugin directory: ${pluginRoot}`);
|
|
592
|
-
}
|
|
593
|
-
if (entries.length > 0) removeTree(pluginRoot);
|
|
594
|
-
}
|
|
595
|
-
ensureDir(pluginRoot);
|
|
596
|
-
|
|
597
|
-
const installedSkills = [];
|
|
598
|
-
for (const name of skillsForRuntime('codex')) {
|
|
599
|
-
const sourceDir = path.join(repoRoot, 'skills', name);
|
|
600
|
-
if (!fs.existsSync(path.join(sourceDir, 'SKILL.md'))) {
|
|
601
|
-
throw new Error(`missing allowlisted Codex skill: ${name}`);
|
|
602
|
-
}
|
|
603
|
-
copySkill(sourceDir, path.join(pluginRoot, 'skills', name), name, name);
|
|
604
|
-
installedSkills.push(name);
|
|
605
|
-
}
|
|
606
|
-
|
|
607
|
-
copyHooks(repoRoot, pluginRoot, publishedRoot);
|
|
608
|
-
const mcpRuntime = buildMcpRuntime(repoRoot, pluginRoot);
|
|
609
|
-
const command = mcpCommand(path.join(
|
|
610
|
-
publishedRoot,
|
|
611
|
-
path.relative(pluginRoot, mcpRuntime.launcher),
|
|
612
|
-
));
|
|
613
|
-
writeAtomic(path.join(pluginRoot, '.mcp.json'), JSON.stringify({
|
|
614
|
-
mcpServers: {
|
|
615
|
-
[PLUGIN_NAME]: {
|
|
616
|
-
type: 'stdio',
|
|
617
|
-
command: command.command,
|
|
618
|
-
args: command.args,
|
|
619
|
-
},
|
|
620
|
-
},
|
|
621
|
-
}, null, 2) + '\n');
|
|
622
|
-
writeAtomic(path.join(pluginRoot, 'command-map.json'), JSON.stringify(buildCommandMap(), null, 2) + '\n');
|
|
623
|
-
if (fs.existsSync(path.join(repoRoot, 'LICENSE'))) {
|
|
624
|
-
fs.copyFileSync(path.join(repoRoot, 'LICENSE'), path.join(pluginRoot, 'LICENSE'));
|
|
625
|
-
}
|
|
626
|
-
|
|
627
|
-
const pkg = JSON.parse(fs.readFileSync(path.join(repoRoot, 'package.json'), 'utf8'));
|
|
628
|
-
const version = `${pkg.version}+codex.${pluginContentHash(pluginRoot, pkg.version)}`;
|
|
629
|
-
const manifest = {
|
|
630
|
-
name: PLUGIN_NAME,
|
|
631
|
-
version,
|
|
632
|
-
description: 'Codex-native Ultra Builder Pro workflows with a persistent safety kernel.',
|
|
633
|
-
author: { name: typeof pkg.author === 'string' ? pkg.author : 'Ultra Builder Pro contributors' },
|
|
634
|
-
homepage: pkg.homepage,
|
|
635
|
-
repository: 'https://github.com/rocky2431/ultra-builder-pro-cli',
|
|
636
|
-
license: pkg.license || 'MIT',
|
|
637
|
-
keywords: ['codex', 'skills', 'agents', 'hooks', 'mcp', 'ultra-builder-pro'],
|
|
638
|
-
skills: './skills/',
|
|
639
|
-
mcpServers: './.mcp.json',
|
|
640
|
-
interface: {
|
|
641
|
-
displayName: 'Ultra Builder Pro',
|
|
642
|
-
shortDescription: 'Codex-native engineering workflows and verification gates.',
|
|
643
|
-
longDescription: 'Complete Codex adaptation of Ultra Builder Pro skills, command workflows, custom agents, lifecycle hooks, and a project-local persistence and safety kernel.',
|
|
644
|
-
developerName: typeof pkg.author === 'string' ? pkg.author : 'Ultra Builder Pro contributors',
|
|
645
|
-
category: 'Developer Tools',
|
|
646
|
-
capabilities: ['Interactive', 'Write'],
|
|
647
|
-
websiteURL: pkg.homepage,
|
|
648
|
-
defaultPrompt: [
|
|
649
|
-
'Initialize this project with the Ultra Builder Pro workflow.',
|
|
650
|
-
'Run the Ultra review pipeline on my current changes.',
|
|
651
|
-
'Show the current Ultra project status, valid transitions, and host recommendation.',
|
|
652
|
-
],
|
|
653
|
-
brandColor: '#111827',
|
|
654
|
-
},
|
|
655
|
-
};
|
|
656
|
-
writeAtomic(path.join(pluginRoot, '.codex-plugin', 'plugin.json'), JSON.stringify(manifest, null, 2) + '\n');
|
|
657
|
-
writeAtomic(path.join(pluginRoot, '.ubp-managed'), JSON.stringify({ source: 'ubp', adapter: 'codex', version }, null, 2) + '\n');
|
|
658
|
-
return { root: publishedRoot, version, skills: installedSkills.sort() };
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
function tomlMultiline(value) {
|
|
662
|
-
const escaped = String(value)
|
|
663
|
-
.replace(/\\/g, '\\\\')
|
|
664
|
-
.replace(/"""/g, '\\"\\"\\"')
|
|
665
|
-
.replace(/\r/g, '')
|
|
666
|
-
.replace(/\u0000/g, '');
|
|
667
|
-
return `"""\\\n${escaped.trim()}\n"""`;
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
function buildAgentToml(sourceText) {
|
|
671
|
-
const { fm, body } = parseFrontmatter(sourceText);
|
|
672
|
-
const name = fm.name;
|
|
673
|
-
const description = adaptHostText(String(fm.description || `${name} Ultra Builder Pro agent.`), name)
|
|
674
|
-
.replace(/\s+/g, ' ')
|
|
675
|
-
.trim();
|
|
676
|
-
let instructions = adaptHostText(body, name);
|
|
677
|
-
instructions = instructions.replace(
|
|
678
|
-
/Consult your agent memory[^\n]*/g,
|
|
679
|
-
'Use the current checkout and parent-supplied context; do not assume persistent custom-agent memory.',
|
|
680
|
-
);
|
|
681
|
-
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}`;
|
|
682
|
-
return [
|
|
683
|
-
`# ${MANAGED_MARKER}`,
|
|
684
|
-
`name = ${JSON.stringify(name)}`,
|
|
685
|
-
`description = ${JSON.stringify(description)}`,
|
|
686
|
-
'model_reasoning_effort = "high"',
|
|
687
|
-
`developer_instructions = ${tomlMultiline(instructions)}`,
|
|
688
|
-
'',
|
|
689
|
-
].join('\n');
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
function installAgents({ repoRoot, configDir }) {
|
|
693
|
-
const sourceRoot = path.join(repoRoot, 'agents');
|
|
694
|
-
const targetRoot = path.join(configDir, 'agents');
|
|
695
|
-
ensureDir(targetRoot);
|
|
696
|
-
const installed = [];
|
|
697
|
-
for (const file of fs.readdirSync(sourceRoot).filter((name) => name.endsWith('.md')).sort()) {
|
|
698
|
-
const targetFile = path.join(targetRoot, file.replace(/\.md$/, '.toml'));
|
|
699
|
-
if (fs.existsSync(targetFile)) {
|
|
700
|
-
const existing = fs.readFileSync(targetFile, 'utf8');
|
|
701
|
-
if (!existing.startsWith(`# ${MANAGED_MARKER}`)) {
|
|
702
|
-
throw new Error(`refusing to overwrite unmanaged Codex agent: ${targetFile}`);
|
|
703
|
-
}
|
|
704
|
-
}
|
|
705
|
-
writeAtomic(targetFile, buildAgentToml(fs.readFileSync(path.join(sourceRoot, file), 'utf8')));
|
|
706
|
-
installed.push(path.basename(targetFile));
|
|
707
|
-
}
|
|
708
|
-
return { root: targetRoot, installed };
|
|
709
|
-
}
|
|
710
|
-
|
|
711
|
-
module.exports = {
|
|
712
|
-
PLUGIN_NAME,
|
|
713
|
-
MANAGED_MARKER,
|
|
714
|
-
COMMAND_NAMES,
|
|
715
|
-
adaptHostText,
|
|
716
|
-
buildCommandMap,
|
|
717
|
-
buildHooksManifest,
|
|
718
|
-
buildMcpRuntime,
|
|
719
|
-
inspectInstalledRuntime,
|
|
720
|
-
applyNativeDoctor,
|
|
721
|
-
mcpCommand,
|
|
722
|
-
buildPlugin,
|
|
723
|
-
buildAgentToml,
|
|
724
|
-
installAgents,
|
|
725
|
-
};
|