ultra-builder-pro-cli 3.0.2 → 5.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (41) hide show
  1. package/.ultra-template/contexts/TEMPLATE.md +6 -0
  2. package/CHANGELOG.md +73 -1
  3. package/README.md +126 -36
  4. package/README.zh-CN.md +440 -0
  5. package/adapters/_shared/host-profile.cjs +3 -151
  6. package/adapters/_shared/plugin-core.cjs +57 -0
  7. package/adapters/_shared/runtime-assets.cjs +64 -12
  8. package/bin/delegate-worker.cjs +2 -345
  9. package/bin/delegate.cjs +3 -530
  10. package/docs/ARCHITECTURE.md +59 -18
  11. package/docs/ARTIFACT-AUTHORITY.md +21 -5
  12. package/docs/DECISIONS.md +31 -10
  13. package/docs/PLUGIN-ISOLATION-CONTRACT.md +28 -12
  14. package/docs/RUNTIME-COMPAT-MATRIX.md +101 -22
  15. package/docs/SKILL-AUTHORING.md +15 -3
  16. package/docs/WORKFLOW-LIFECYCLE.md +83 -29
  17. package/docs/evals/ultra-5-0-journey-results.md +62 -0
  18. package/docs/evals/ultra-5-0-live-acp-conformance.md +93 -0
  19. package/docs/evals/ultra-5-0-route-journeys.md +145 -0
  20. package/package.json +2 -1
  21. package/skills/ultra-change/SKILL.md +30 -4
  22. package/skills/ultra-delegate/SKILL.md +80 -7
  23. package/skills/ultra-delegate/patches/zcode-acp-0.1.0-zcode-0.16.5.patch +184 -0
  24. package/skills/ultra-delegate/references/delegation-contract.md +60 -1
  25. package/skills/ultra-delegate/scripts/acp-conformance.cjs +287 -0
  26. package/skills/ultra-delegate/scripts/acp-driver.cjs +762 -0
  27. package/skills/ultra-delegate/scripts/agent-execution-driver.cjs +320 -0
  28. package/skills/ultra-delegate/scripts/cli-driver.cjs +61 -0
  29. package/skills/ultra-delegate/scripts/delegate-worker.cjs +328 -0
  30. package/skills/ultra-delegate/scripts/delegate.cjs +690 -0
  31. package/skills/ultra-delegate/scripts/host-profile.cjs +267 -0
  32. package/skills/ultra-deliver/SKILL.md +13 -0
  33. package/skills/ultra-dev/SKILL.md +18 -2
  34. package/skills/ultra-init/SKILL.md +12 -0
  35. package/skills/ultra-plan/SKILL.md +21 -3
  36. package/skills/ultra-research/SKILL.md +33 -5
  37. package/skills/ultra-status/SKILL.md +37 -7
  38. package/skills/ultra-status/references/route-contract.md +100 -0
  39. package/skills/ultra-test/SKILL.md +16 -1
  40. /package/{adapters/_shared → skills/ultra-delegate/scripts}/delegate-profiles/kimi-read-only.md +0 -0
  41. /package/{adapters/_shared → skills/ultra-delegate/scripts}/delegate-profiles/kimi-write.md +0 -0
package/bin/delegate.cjs CHANGED
@@ -1,532 +1,5 @@
1
1
  'use strict';
2
2
 
3
- const crypto = require('node:crypto');
4
- const fs = require('node:fs');
5
- const path = require('node:path');
6
- const { execFileSync, spawn } = require('node:child_process');
7
-
8
- const { hostProfile, transportSurface } = require('../adapters/_shared/host-profile.cjs');
9
- const { writeAtomic } = require('../adapters/_shared/file-ops.cjs');
10
-
11
- const PERMISSION_SCHEMA = 'ultra-delegation-permission-v1';
12
- const RECEIPT_SCHEMA = 'ultra-delegation-receipt-v1';
13
- const RESULT_SCHEMA = 'ultra-delegation-result-v1';
14
- const PERMISSION_FIELDS = new Set(['$schema', 'writable_roots', 'external_effects']);
15
- const PROTECTED_ROOT = '.ultra';
16
- const RESULT_JSON_SCHEMA = Object.freeze({
17
- type: 'object',
18
- additionalProperties: false,
19
- required: [
20
- '$schema', 'status', 'summary', 'changed_files', 'checks', 'evidence',
21
- 'questions', 'residual_risks',
22
- ],
23
- properties: {
24
- $schema: { type: 'string', const: RESULT_SCHEMA },
25
- status: { type: 'string', enum: ['finished', 'blocked', 'failed'] },
26
- summary: { type: 'string' },
27
- changed_files: {
28
- type: 'array', items: { type: 'string' },
29
- },
30
- checks: {
31
- type: 'array',
32
- items: {
33
- type: 'object',
34
- additionalProperties: false,
35
- required: ['command', 'status', 'output_ref'],
36
- properties: {
37
- command: { type: 'string' },
38
- status: { type: 'string', enum: ['passed', 'failed', 'not_run'] },
39
- output_ref: { type: 'string' },
40
- },
41
- },
42
- },
43
- evidence: { type: 'array', items: { type: 'string' } },
44
- questions: { type: 'array', items: { type: 'string' } },
45
- residual_risks: { type: 'array', items: { type: 'string' } },
46
- },
47
- });
48
-
49
- function inside(root, candidate) {
50
- const relative = path.relative(root, candidate);
51
- return relative !== '' && relative !== '..' && !relative.startsWith(`..${path.sep}`)
52
- && !path.isAbsolute(relative);
53
- }
54
-
55
- function atOrInside(root, candidate) {
56
- return candidate === root || inside(root, candidate);
57
- }
58
-
59
- function projectPath(projectRoot, value, label, { directory = false } = {}) {
60
- const lexical = path.resolve(projectRoot, value);
61
- const resolved = fs.existsSync(lexical) ? fs.realpathSync(lexical) : lexical;
62
- if (!inside(projectRoot, resolved)) throw new Error(`${label} must be inside the current project`);
63
- if (directory && (!fs.existsSync(resolved) || !fs.statSync(resolved).isDirectory())) {
64
- throw new Error(`${label} must be an existing directory`);
65
- }
66
- return resolved;
67
- }
68
-
69
- function sha256(file) {
70
- return crypto.createHash('sha256').update(fs.readFileSync(file)).digest('hex');
71
- }
72
-
73
- function git(cwd, args) {
74
- return execFileSync('git', args, {
75
- cwd,
76
- encoding: 'utf8',
77
- maxBuffer: 16 * 1024 * 1024,
78
- stdio: ['ignore', 'pipe', 'pipe'],
79
- }).trim();
80
- }
81
-
82
- function observedChangedFiles(cwd, baseHead) {
83
- const run = (args) => execFileSync('git', args, {
84
- cwd,
85
- encoding: 'buffer',
86
- maxBuffer: 16 * 1024 * 1024,
87
- stdio: ['ignore', 'pipe', 'pipe'],
88
- }).toString('utf8').split('\0').filter(Boolean);
89
- return [...new Set([
90
- ...run(['diff', '--name-only', '-z', baseHead, '--']),
91
- ...run(['ls-files', '--others', '--exclude-standard', '-z']),
92
- ].map((file) => file.split(path.sep).join('/')))].sort();
93
- }
94
-
95
- function validateWorktree(worktree) {
96
- let top;
97
- try {
98
- top = fs.realpathSync(git(worktree, ['rev-parse', '--show-toplevel']));
99
- } catch {
100
- throw new Error('worktree must be a real Git worktree');
101
- }
102
- if (top !== worktree) throw new Error('worktree must be the root of a real Git worktree');
103
- const registered = git(worktree, ['worktree', 'list', '--porcelain'])
104
- .split('\n')
105
- .filter((line) => line.startsWith('worktree '))
106
- .map((line) => line.slice('worktree '.length))
107
- .some((entry) => {
108
- try { return fs.realpathSync(entry) === worktree; } catch { return false; }
109
- });
110
- if (!registered) throw new Error('worktree is not registered as a Git worktree');
111
- const dirty = git(worktree, ['status', '--porcelain=v1', '--untracked-files=all']);
112
- if (dirty) throw new Error('delegated Git worktree must start clean');
113
- return git(worktree, ['rev-parse', 'HEAD']);
114
- }
115
-
116
- function readPermission(file, worktree) {
117
- let payload;
118
- let source;
119
- try {
120
- source = fs.readFileSync(file, 'utf8');
121
- payload = JSON.parse(source);
122
- } catch {
123
- throw new Error('permission must be valid JSON');
124
- }
125
- if (!payload || Array.isArray(payload) || typeof payload !== 'object') {
126
- throw new Error('permission must be a JSON object');
127
- }
128
- for (const key of Object.keys(payload)) {
129
- if (!PERMISSION_FIELDS.has(key)) throw new Error(`unknown permission field: ${key}`);
130
- }
131
- if (payload.$schema !== PERMISSION_SCHEMA) {
132
- throw new Error(`permission $schema must be ${PERMISSION_SCHEMA}`);
133
- }
134
- if (!Array.isArray(payload.writable_roots)) {
135
- throw new Error('permission writable_roots must be an array');
136
- }
137
- const writableRoots = [];
138
- const writableRootPaths = [];
139
- for (const value of payload.writable_roots) {
140
- if (typeof value !== 'string' || !value.trim() || path.isAbsolute(value)) {
141
- throw new Error('permission writable_roots entries must be relative non-empty paths');
142
- }
143
- const resolved = path.resolve(worktree, value);
144
- if (!atOrInside(worktree, resolved)) {
145
- throw new Error('permission writable_roots must stay inside the delegated worktree');
146
- }
147
- if (!fs.existsSync(resolved) || !fs.statSync(resolved).isDirectory()) {
148
- throw new Error(`permission writable_roots entry must be an existing directory: ${value}`);
149
- }
150
- const real = fs.realpathSync(resolved);
151
- if (!atOrInside(worktree, real)) {
152
- throw new Error('permission writable_roots must not escape through symlinks');
153
- }
154
- const normalized = path.relative(worktree, real).split(path.sep).join('/') || '.';
155
- // `.ultra` is the project's memory and has exactly one writer: the primary host.
156
- // Rejected here so the delegation never starts, and again against the actual diff
157
- // in the worker, which also covers the `.` grant.
158
- if (normalized === PROTECTED_ROOT || normalized.startsWith(`${PROTECTED_ROOT}/`)) {
159
- throw new Error(`permission writable_roots must not include ${PROTECTED_ROOT}; the primary host is its only writer`);
160
- }
161
- if (!writableRoots.includes(normalized)) {
162
- writableRoots.push(normalized);
163
- writableRootPaths.push(real);
164
- }
165
- }
166
- if (!Array.isArray(payload.external_effects)) {
167
- throw new Error('permission external_effects must be an array');
168
- }
169
- if (payload.external_effects.length !== 0) {
170
- throw new Error('permission external_effects must be empty; the primary host performs separately authorized effects');
171
- }
172
- return {
173
- writableRoots,
174
- writableRootPaths,
175
- source,
176
- digest: crypto.createHash('sha256').update(source).digest('hex'),
177
- };
178
- }
179
-
180
- function delegatePrompt({
181
- instructionSource, instructionDigest, permissionSource, permissionDigest,
182
- worktree, readOnly,
183
- }) {
184
- return [
185
- 'Execute one bounded Ultra Builder Pro delegation in the isolated Git worktree.',
186
- 'The launcher embedded the digest-bound packet below. Do not access packet paths outside the worktree.',
187
- `Instruction SHA-256: ${instructionDigest}`,
188
- '--- instruction.md ---',
189
- instructionSource.trimEnd(),
190
- '--- end instruction.md ---',
191
- `Permission SHA-256: ${permissionDigest}`,
192
- '--- permission.json ---',
193
- permissionSource.trimEnd(),
194
- '--- end permission.json ---',
195
- `Use this worktree as the only filesystem boundary: ${worktree}`,
196
- readOnly
197
- ? 'This is read-only delegation. Do not create, modify, or delete any project file.'
198
- : 'Modify only paths covered by permission.writable_roots.',
199
- 'Do not perform external effects, edit the primary checkout, or change Ultra task authority.',
200
- 'Batch independent reads in the earliest tool turn. Do not emit a preliminary result, and reserve a final turn for the one terminal JSON response.',
201
- `Return exactly one JSON object as the final response using $schema ${RESULT_SCHEMA}.`,
202
- 'The exact fields are $schema, status, summary, changed_files, checks, evidence, questions, and residual_risks.',
203
- 'status is finished, blocked, or failed. blocked requires at least one question.',
204
- 'changed_files must exactly list every repository-relative path changed in the worktree.',
205
- 'checks items use command, status (passed, failed, or not_run), and output_ref. Use a short evidence reference when no file exists.',
206
- 'Do not write the receipt yourself. The launcher validates structured output, process exit, permissions, and the actual Git diff before publication.',
207
- ].join('\n');
208
- }
209
-
210
- function selectedBinary(runtime, fallback) {
211
- return process.env[`UBP_DELEGATE_${runtime.toUpperCase()}_BIN`] || fallback;
212
- }
213
-
214
- function selectedModel(runtime, explicit) {
215
- return explicit || process.env[`UBP_DELEGATE_${runtime.toUpperCase()}_MODEL`] || null;
216
- }
217
-
218
- function parsePairs(argv, allowed) {
219
- const values = {};
220
- for (let index = 0; index < argv.length; index += 2) {
221
- const key = argv[index];
222
- const value = argv[index + 1];
223
- if (!allowed.has(key) || value === undefined || value === '') {
224
- throw new Error(`invalid delegate argument: ${key || '<missing>'}`);
225
- }
226
- if (values[key]) throw new Error(`duplicate delegate argument: ${key}`);
227
- values[key] = value;
228
- }
229
- return values;
230
- }
231
-
232
- function parseRun(argv) {
233
- // --ack-experimental is the one valueless flag: launching an experimental
234
- // transport must be a visible choice, never a silent default.
235
- const ackExperimental = argv.includes('--ack-experimental');
236
- const pairs = argv.filter((arg) => arg !== '--ack-experimental');
237
- const values = parsePairs(pairs, new Set([
238
- '--to', '--instruction', '--permission', '--worktree', '--timeout', '--model',
239
- ]));
240
- for (const key of ['--to', '--instruction', '--permission', '--worktree']) {
241
- if (!values[key]) throw new Error(`delegate run requires ${key}`);
242
- }
243
- const timeout = values['--timeout'] === undefined ? 1800 : Number(values['--timeout']);
244
- if (!Number.isFinite(timeout) || timeout <= 0 || timeout > 86400) {
245
- throw new Error('delegate --timeout must be greater than 0 and at most 86400 seconds');
246
- }
247
- return {
248
- to: values['--to'], instruction: values['--instruction'],
249
- permission: values['--permission'], worktree: values['--worktree'],
250
- model: values['--model'] || null,
251
- timeoutMs: Math.ceil(timeout * 1000),
252
- ackExperimental,
253
- };
254
- }
255
-
256
- function readJson(file) {
257
- return JSON.parse(fs.readFileSync(file, 'utf8'));
258
- }
259
-
260
- function processAlive(pid) {
261
- if (!Number.isInteger(pid) || pid <= 0) return false;
262
- try { process.kill(pid, 0); return true; } catch { return false; }
263
- }
264
-
265
- function run(argv, { projectRoot = process.cwd() } = {}) {
266
- const args = parseRun(argv);
267
- projectRoot = fs.realpathSync(projectRoot);
268
- const profile = hostProfile(args.to);
269
- if (args.model && !profile.supportsModelSelection) {
270
- throw new Error(`delegate --model is not supported by host ${args.to}`);
271
- }
272
- const model = profile.supportsModelSelection ? selectedModel(args.to, args.model) : null;
273
- const binary = selectedBinary(args.to, profile.binary);
274
- const transportMaturity = profile.transportMaturity;
275
- const transportSurfaceNote = transportSurface(args.to, binary);
276
- if (transportMaturity === 'experimental' && !args.ackExperimental) {
277
- throw new Error(
278
- `delegate --to ${args.to} would launch ${transportSurfaceNote}. `
279
- + 'This transport is experimental (verified-local only; the provider publishes no '
280
- + 'stability contract), and it is not the documented ZCode Desktop interactive '
281
- + 'surface. Acknowledge explicitly with --ack-experimental to proceed, or pick a '
282
- + 'documented transport.',
283
- );
284
- }
285
- if (transportMaturity === 'experimental') {
286
- process.stderr.write(
287
- `ultra-delegate: warning: host '${args.to}' runs ${transportSurfaceNote}; `
288
- + `recovery: ubp delegate cancel --delegation <dir>\n`,
289
- );
290
- }
291
- const instruction = projectPath(projectRoot, args.instruction, 'instruction');
292
- const permission = projectPath(projectRoot, args.permission, 'permission');
293
- const worktree = projectPath(projectRoot, args.worktree, 'worktree', { directory: true });
294
- if (!fs.statSync(instruction).isFile()) throw new Error('instruction must be a file');
295
- if (!fs.statSync(permission).isFile()) throw new Error('permission must be a file');
296
- if (path.dirname(instruction) !== path.dirname(permission)) {
297
- throw new Error('instruction and permission must share one delegation directory');
298
- }
299
- const baseHead = validateWorktree(worktree);
300
- const permissionContract = readPermission(permission, worktree);
301
- const instructionSource = fs.readFileSync(instruction, 'utf8');
302
- const delegationRoot = path.dirname(instruction);
303
- const delegationId = path.basename(delegationRoot);
304
- const result = path.join(delegationRoot, 'result.json');
305
- const receiptFile = path.join(delegationRoot, 'receipt.json');
306
- const stdout = path.join(delegationRoot, 'stdout.log');
307
- const stderr = path.join(delegationRoot, 'stderr.log');
308
- const spec = path.join(delegationRoot, 'worker-spec.json');
309
- const outputSchema = path.join(delegationRoot, 'result-schema.json');
310
- const hostOutput = path.join(delegationRoot, 'host-result.json');
311
- const lock = path.join(delegationRoot, 'run.lock');
312
- const cancel = path.join(delegationRoot, 'cancel.request');
313
- if (fs.existsSync(result)) throw new Error('delegation result.json already exists; use a new delegation id');
314
- if (fs.existsSync(lock)) throw new Error('delegation is already running');
315
- if (fs.existsSync(receiptFile) || fs.existsSync(spec) || fs.existsSync(outputSchema) || fs.existsSync(hostOutput)) {
316
- throw new Error('delegation id already has run artifacts; cancel or use a new delegation id');
317
- }
318
- let lockFd;
319
- try {
320
- lockFd = fs.openSync(lock, 'wx', 0o600);
321
- } catch (error) {
322
- if (error.code === 'EEXIST') throw new Error('delegation is already running');
323
- throw error;
324
- }
325
- const startedAt = new Date().toISOString();
326
- const instructionDigest = crypto.createHash('sha256').update(instructionSource).digest('hex');
327
- const permissionDigest = permissionContract.digest;
328
- try {
329
- fs.writeFileSync(lockFd, `${JSON.stringify({ pid: process.pid, started_at: startedAt })}\n`);
330
- fs.closeSync(lockFd);
331
- lockFd = undefined;
332
- writeAtomic(outputSchema, `${JSON.stringify(RESULT_JSON_SCHEMA, null, 2)}\n`);
333
- fs.chmodSync(outputSchema, 0o600);
334
- const outputSchemaDigest = sha256(outputSchema);
335
- const profileOptions = {
336
- readOnly: permissionContract.writableRoots.length === 0,
337
- writableRoots: permissionContract.writableRoots,
338
- schemaFile: outputSchema,
339
- schemaJson: JSON.stringify(RESULT_JSON_SCHEMA),
340
- hostOutput,
341
- model,
342
- };
343
- const prompt = delegatePrompt({
344
- instructionSource,
345
- instructionDigest,
346
- permissionSource: permissionContract.source,
347
- permissionDigest,
348
- worktree,
349
- readOnly: profileOptions.readOnly,
350
- });
351
- const workerSpec = {
352
- $schema: 'ultra-delegation-worker-spec-v1',
353
- delegation_id: delegationId,
354
- host: args.to,
355
- model,
356
- command: binary,
357
- transport_maturity: transportMaturity,
358
- transport_surface: transportSurfaceNote,
359
- experimental_ack: transportMaturity === 'experimental' ? args.ackExperimental : undefined,
360
- args: profile.delegateArgv(prompt, worktree, profileOptions),
361
- cwd: worktree,
362
- instruction,
363
- permission,
364
- instruction_digest: instructionDigest,
365
- permission_digest: permissionDigest,
366
- output_schema: outputSchema,
367
- output_schema_digest: outputSchemaDigest,
368
- host_output: hostOutput,
369
- read_only: profileOptions.readOnly,
370
- writable_roots: permissionContract.writableRoots,
371
- writable_root_paths: permissionContract.writableRootPaths,
372
- base_head: baseHead,
373
- started_at: startedAt,
374
- timeout_ms: args.timeoutMs,
375
- result,
376
- stdout,
377
- stderr,
378
- lock,
379
- cancel,
380
- env: {
381
- ...(profile.delegateEnv ? profile.delegateEnv(profileOptions) : {}),
382
- UBP_DELEGATE_INSTRUCTION_FILE: instruction,
383
- UBP_DELEGATE_PERMISSION_FILE: permission,
384
- UBP_DELEGATE_WORKTREE: worktree,
385
- },
386
- };
387
- writeAtomic(spec, `${JSON.stringify(workerSpec, null, 2)}\n`);
388
- fs.chmodSync(spec, 0o600);
389
- const specDigest = sha256(spec);
390
- const worker = spawn(process.execPath, [
391
- path.join(__dirname, 'delegate-worker.cjs'), spec, specDigest,
392
- ], {
393
- cwd: projectRoot,
394
- detached: true,
395
- stdio: 'ignore',
396
- env: process.env,
397
- });
398
- if (!worker.pid) throw new Error('failed to start delegation worker');
399
- worker.unref();
400
- const receipt = {
401
- $schema: RECEIPT_SCHEMA,
402
- status: 'started',
403
- delegation_id: delegationId,
404
- host: args.to,
405
- model,
406
- transport_maturity: transportMaturity,
407
- transport_surface: transportSurfaceNote,
408
- ...(transportMaturity === 'experimental' ? { experimental_ack: args.ackExperimental } : {}),
409
- worker_pid: worker.pid,
410
- instruction_digest: instructionDigest,
411
- permission_digest: permissionDigest,
412
- output_schema_digest: outputSchemaDigest,
413
- spec_digest: specDigest,
414
- base_head: baseHead,
415
- started_at: startedAt,
416
- timeout_ms: args.timeoutMs,
417
- result_file: result,
418
- read_only: profileOptions.readOnly,
419
- stdout_file: stdout,
420
- stderr_file: stderr,
421
- cancel_command: `ubp delegate cancel --delegation ${delegationRoot}`,
422
- };
423
- writeAtomic(receiptFile, `${JSON.stringify(receipt, null, 2)}\n`);
424
- writeAtomic(lock, `${JSON.stringify({ pid: worker.pid, started_at: startedAt })}\n`);
425
- fs.chmodSync(lock, 0o600);
426
- if (fs.existsSync(result)) {
427
- try { fs.unlinkSync(lock); } catch (error) { if (error.code !== 'ENOENT') throw error; }
428
- }
429
- return receipt;
430
- } catch (error) {
431
- if (lockFd !== undefined) fs.closeSync(lockFd);
432
- try { fs.unlinkSync(lock); } catch (unlinkError) { if (unlinkError.code !== 'ENOENT') throw unlinkError; }
433
- for (const file of [spec, outputSchema, hostOutput]) {
434
- try { fs.unlinkSync(file); } catch (unlinkError) { if (unlinkError.code !== 'ENOENT') throw unlinkError; }
435
- }
436
- throw error;
437
- }
438
- }
439
-
440
- function delegationPath(projectRoot, value) {
441
- return projectPath(projectRoot, value, 'delegation', { directory: true });
442
- }
443
-
444
- function status(argv, { projectRoot = process.cwd() } = {}) {
445
- const values = parsePairs(argv, new Set(['--delegation']));
446
- if (!values['--delegation']) throw new Error('delegate status requires --delegation');
447
- projectRoot = fs.realpathSync(projectRoot);
448
- const root = delegationPath(projectRoot, values['--delegation']);
449
- const result = path.join(root, 'result.json');
450
- if (fs.existsSync(result)) return readJson(result);
451
- const receiptFile = path.join(root, 'receipt.json');
452
- const receipt = fs.existsSync(receiptFile) ? readJson(receiptFile) : null;
453
- const lockFile = path.join(root, 'run.lock');
454
- const lock = fs.existsSync(lockFile) ? readJson(lockFile) : null;
455
- const cancelling = fs.existsSync(path.join(root, 'cancel.request'));
456
- return {
457
- $schema: 'ultra-delegation-status-v1',
458
- status: cancelling ? 'cancelling' : lock && processAlive(lock.pid) ? 'running' : receipt ? 'stalled' : 'not_started',
459
- delegation_id: path.basename(root),
460
- worker_pid: lock?.pid || receipt?.worker_pid || null,
461
- result_file: result,
462
- repair: receipt ? `ubp delegate cancel --delegation ${root}` : null,
463
- };
464
- }
465
-
466
- function failureFromSpec(spec, failureType, summary) {
467
- let finalHead = null;
468
- let changedFiles = [];
469
- try { finalHead = git(spec.cwd, ['rev-parse', 'HEAD']); } catch {}
470
- try { changedFiles = observedChangedFiles(spec.cwd, spec.base_head); } catch {}
471
- return {
472
- $schema: RESULT_SCHEMA,
473
- status: 'failed',
474
- summary,
475
- changed_files: changedFiles,
476
- checks: [],
477
- evidence: [],
478
- questions: [],
479
- residual_risks: [],
480
- failure_type: failureType,
481
- delegation_id: spec.delegation_id,
482
- host: spec.host,
483
- transport_maturity: spec.transport_maturity ?? null,
484
- transport_surface: spec.transport_surface ?? null,
485
- // Terminal recovery results carry the same transport truth as live ones.
486
- ...(spec.experimental_ack === true ? { experimental_ack: true } : {}),
487
- instruction_digest: spec.instruction_digest,
488
- permission_digest: spec.permission_digest,
489
- output_schema_digest: spec.output_schema_digest,
490
- base_head: spec.base_head,
491
- final_head: finalHead,
492
- started_at: spec.started_at,
493
- finished_at: new Date().toISOString(),
494
- exit_code: null,
495
- };
496
- }
497
-
498
- function cancel(argv, { projectRoot = process.cwd() } = {}) {
499
- const values = parsePairs(argv, new Set(['--delegation']));
500
- if (!values['--delegation']) throw new Error('delegate cancel requires --delegation');
501
- projectRoot = fs.realpathSync(projectRoot);
502
- const root = delegationPath(projectRoot, values['--delegation']);
503
- const result = path.join(root, 'result.json');
504
- if (fs.existsSync(result)) return { status: 'already_terminal', result: readJson(result) };
505
- const specFile = path.join(root, 'worker-spec.json');
506
- if (!fs.existsSync(specFile)) throw new Error('delegation has no worker spec to cancel');
507
- const spec = readJson(specFile);
508
- const request = path.join(root, 'cancel.request');
509
- writeAtomic(request, `${JSON.stringify({ requested_at: new Date().toISOString() })}\n`);
510
- const receiptFile = path.join(root, 'receipt.json');
511
- const receipt = fs.existsSync(receiptFile) ? readJson(receiptFile) : null;
512
- if (!processAlive(receipt?.worker_pid)) {
513
- writeAtomic(result, `${JSON.stringify(failureFromSpec(spec, 'cancelled', 'Delegation cancelled after its worker stopped.'), null, 2)}\n`);
514
- try { fs.unlinkSync(path.join(root, 'run.lock')); } catch (error) { if (error.code !== 'ENOENT') throw error; }
515
- }
516
- return {
517
- $schema: 'ultra-delegation-cancel-v1',
518
- status: 'cancel_requested',
519
- delegation_id: path.basename(root),
520
- result_file: result,
521
- };
522
- }
523
-
524
- function handle(argv, options) {
525
- if (argv[0] !== 'delegate') throw new Error('delegate command is required');
526
- if (argv[1] === 'run') return run(argv.slice(2), options);
527
- if (argv[1] === 'status') return status(argv.slice(2), options);
528
- if (argv[1] === 'cancel') return cancel(argv.slice(2), options);
529
- throw new Error('usage: ubp delegate <run|status|cancel> ...');
530
- }
531
-
532
- module.exports = { handle, run, status, cancel };
3
+ // Compatibility surface for one release cycle. The installed Skill owns the
4
+ // implementation used by both `ubp delegate` and direct Skill invocation.
5
+ module.exports = require('../skills/ultra-delegate/scripts/delegate.cjs');
@@ -14,14 +14,14 @@ bounded effects, and recovery.
14
14
  Owner request
15
15
  │ explicit selection or verified execution grant (session-local / durable)
16
16
  ▼
17
- User-invoked Skill ──────── stops at the next owner boundary
17
+ Public Skill mode ───────── stops at the next owner boundary
18
18
  │
19
19
  ├── model-invoked disciplines (reasoning methods)
20
20
  ├── source / tests / runtime / primary documentation
21
21
  └── canonical project files + Git
22
22
  │
23
23
  ├── optional five hooks (derived context and effect guard)
24
- └── optional delegate CLI (bounded external host process)
24
+ └── optional delegation (ACP-first driver or CLI fallback)
25
25
  ```
26
26
 
27
27
  Ultra has no semantic runtime supervisor. Reading the files is the recovery protocol;
@@ -37,15 +37,20 @@ Fourteen `skills/*/SKILL.md` files carry the workflow:
37
37
  - five model-invoked reusable disciplines;
38
38
  - one read-only router.
39
39
 
40
- The exact allowlists live in `adapters/_shared/runtime-assets.cjs`. Public workflows
41
- are explicit by default. The narrow exception is an accepted Change-scoped `Execution
42
- Grant` in one of two modes. `session-local`: Research, Plan, Dev, Test, and Deliver
43
- reconciliation may be selected by the model only while the same session still contains
44
- the owner's activation and approved task ledger; once that conversation activation is
45
- lost, the work stops. `durable work-package`: a fresh Agent or host may continue one
46
- exact work package, but only after stably verifying the recorded grant. Stored text
47
- alone grants nothing, and neither mode grants finalization or archive; owner
48
- checkpoints, final delivery effects, and every external effect still stop.
40
+ The exact allowlists and per-mode invocation map live in
41
+ `adapters/_shared/runtime-assets.cjs`. Public modes are `explicit-entry`,
42
+ `grant-continuable`, or read-only `router`. Under an accepted Change-scoped Execution
43
+ Grant, change-scoped Research, same-Change reconciliation, Plan, Dev, Test, and Deliver
44
+ reconciliation may be selected by the model only while `session-local` activation is
45
+ live or a fresh Agent has stably verified a `durable work-package` grant. Host metadata
46
+ does not preserve session activation: a fresh session, Host switch, or compaction stops
47
+ `session-local` continuation until the Owner activates it again. Host metadata
48
+ is a coarse discovery bit; each loaded Skill rechecks its mode, Change, effects, and
49
+ material checkpoints. Stored text alone grants nothing, and neither mode grants Change
50
+ intake/acceptance, primary transfer, Deliver finalization or archive; every external
51
+ effect still stops. The derived Route Card makes each boundary owner-visible without
52
+ becoming workflow state or authority. The router itself remains owner-invoked; public
53
+ Skills derive their own cards from the shared Route Contract instead of invoking it.
49
54
 
50
55
  Research's seventeen references are workflow-owned semantic lenses. Its optional
51
56
  `wayfinding.md` maps a multi-lens question without becoming a new Skill or authority.
@@ -108,9 +113,12 @@ hard ceilings, while the model interprets whether acceptance and stop conditions
108
113
  - hook command paths and wire normalization;
109
114
  - atomic managed installation, provenance, doctor, and uninstall behavior.
110
115
 
111
- `adapters/_shared/plugin-core.cjs` owns the common copy and managed-publication
112
- mechanics. `host-profile.cjs` owns the six non-interactive delegation argv contracts.
113
- Adapters never rewrite workflow meaning.
116
+ `adapters/_shared/plugin-core.cjs` owns the common copy, managed publication, and
117
+ delegation-runner inventory and driver-reporting checks. The canonical six-host
118
+ non-interactive profile lives
119
+ beside the installed launcher at `skills/ultra-delegate/scripts/host-profile.cjs`;
120
+ `adapters/_shared/host-profile.cjs` is a one-release compatibility re-export. Adapters
121
+ never rewrite workflow meaning.
114
122
 
115
123
  ### Why the old Agents are Skill assets now
116
124
 
@@ -139,6 +147,12 @@ successfully, then it may be garbage-collected. Premature loss requires a fresh
139
147
  and Test; never reconstruct the old receipt. The dangerous-command hook is the only
140
148
  hard effect guard; it classifies a small named destructive set and provides an
141
149
  exact-command authorization repair.
150
+
151
+ ACP `session/update` telemetry follows the same rule. The Skill-local driver stores only
152
+ bounded redacted event metadata under the delegation directory, drops hidden thought
153
+ chunks and raw tool payloads, and exposes the latest safe observation through status.
154
+ The journal, session id, capability report, permission decision, and stop reason are all
155
+ disposable execution observations; none can select a route or establish completion.
142
156
  Additive protected-branch publication remains advisory when portable host wiring cannot
143
157
  project a trusted owner-approval receipt; history rewrites and branch deletion remain
144
158
  guarded.
@@ -180,16 +194,42 @@ These are independent sensors. None rewrites a finding into product truth.
180
194
 
181
195
  ## Delegation
182
196
 
183
- `ubp delegate run` validates all paths inside the selected project, reads a bounded
184
- instruction and permission JSON, builds argv from one host profile, and starts a
185
- background worker. Declared writable roots must already exist inside the delegated
197
+ The canonical installed `ultra-delegate/scripts/delegate.cjs` validates all paths inside
198
+ the selected project, reads a bounded instruction and permission JSON, probes the
199
+ Skill-local Host profile, and starts the Skill-local background worker. One
200
+ `AgentExecutionDriver` boundary selects stable ACP v1 stdio only after the exact Host's
201
+ versioned conformance row passes with a non-empty evidence reference and the declared
202
+ executable and bounded candidate-identity probes succeed; otherwise the same packet
203
+ runs through `CliDriver` and records the fallback reason. Capability inspection uses
204
+ local version commands only and does not start a provider task. The
205
+ one-release `ubp delegate` surface imports those same functions and owns no forked
206
+ behavior. Declared writable roots must already exist inside the delegated
186
207
  worktree; no readable-root or external-effect grant can widen the host's native
187
208
  sandbox. Empty writable roots select native read-only mode. The model returns a
188
- schema-constrained final response; the Node worker validates `finished`, `blocked`, or
209
+ schema-constrained final response; `AcpDriver` reconstructs only agent-message text as
210
+ that same validator input, while ACP stop reasons remain observations. It accepts a
211
+ bounded set of creation-time session metadata that some agents emit before
212
+ `session/new` resolves, then validates every buffered session identity before exposing
213
+ derived events; early message/tool content and unbounded startup traffic fail closed.
214
+ The Node worker validates `finished`, `blocked`, or
189
215
  `failed` and atomically publishes `result.json` beside the instruction. The model never
190
216
  writes its own receipt; stdout, stderr, native final output, and the launch receipt
191
217
  remain diagnostic files.
192
218
 
219
+ `ULTRA_DELEGATE_FORCE_CLI=1` is a per-run recovery seam that selects the same bounded
220
+ CLI validator path and records `acp_forced_cli`; it does not erase conformance evidence.
221
+ An `acp_auth_required` error from `session/new` before `session/prompt` also selects that
222
+ already-bound CLI path once. The terminal result retains redacted ACP fallback metadata;
223
+ no post-prompt or other ACP failure is automatically retried.
224
+ ZCode uses the independently installed, source-pinned `zcode-acp` bridge plus the
225
+ digest-bound 0.16.5 runtime-preferences patch to translate stable ACP v1 to the installed
226
+ Desktop runtime. Ultra ships only the patch, neither the bridge binary nor App bytes.
227
+ The profile verifies an Ultra build marker on that bridge plus the exact installed
228
+ runtime version before ACP selection.
229
+ The Host/runtime is ZCode Desktop while provider identity remains owner-controlled; the
230
+ verified local receipt uses domestic BigModel rather than international Z.AI OAuth. The
231
+ headless ZCode transport remains explicitly experimental even after conformance.
232
+
193
233
  The instruction binds the active `change_id` and one of three semantic scopes: task
194
234
  execution/continuation, scoped Research evidence, or aggregate Change
195
235
  review/verification. Only task execution requires a task row. The read-only Research
@@ -226,6 +266,7 @@ The architecture does not include:
226
266
  - an MCP server or tool protocol;
227
267
  - a workflow state machine or semantic validator;
228
268
  - a background orchestration daemon;
269
+ - a resident ACP service, ACP session store, or semantic route ledger;
229
270
  - command or custom-agent prompt projections;
230
271
  - general memory, code graph, browser, deployment, or framework packages.
231
272