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