ultra-builder-pro-cli 0.26.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 (82) hide show
  1. package/.ultra-template/contexts/TEMPLATE.md +70 -29
  2. package/.ultra-template/north-star.md +35 -18
  3. package/.ultra-template/tasks.json +1 -0
  4. package/.ultra-template/test-report.json +17 -1
  5. package/CHANGELOG.md +235 -1
  6. package/README.md +210 -50
  7. package/README.zh-CN.md +440 -0
  8. package/adapters/_shared/host-profile.cjs +3 -95
  9. package/adapters/_shared/plugin-core.cjs +61 -5
  10. package/adapters/_shared/runtime-assets.cjs +66 -5
  11. package/adapters/zcode.js +375 -0
  12. package/bin/delegate-worker.cjs +2 -325
  13. package/bin/delegate.cjs +3 -461
  14. package/bin/install.js +11 -6
  15. package/docs/ARCHITECTURE.md +133 -31
  16. package/docs/ARTIFACT-AUTHORITY.md +185 -24
  17. package/docs/DECISIONS.md +153 -18
  18. package/docs/PHILOSOPHY.md +58 -7
  19. package/docs/PLUGIN-ISOLATION-CONTRACT.md +34 -12
  20. package/docs/RUNTIME-COMPAT-MATRIX.md +195 -23
  21. package/docs/SKILL-AUTHORING.md +19 -6
  22. package/docs/WORKFLOW-LIFECYCLE.md +196 -44
  23. package/docs/evals/adversarial-review-2026-08-14.md +84 -0
  24. package/docs/evals/ultra-5-0-journey-results.md +62 -0
  25. package/docs/evals/ultra-5-0-live-acp-conformance.md +93 -0
  26. package/docs/evals/ultra-5-0-route-journeys.md +145 -0
  27. package/docs/evals/zcode-automation-2026-08-14.md +103 -0
  28. package/hooks/README.md +27 -4
  29. package/hooks/_common.py +1678 -61
  30. package/hooks/adapters/zcode.py +227 -0
  31. package/hooks/compact_context.py +176 -17
  32. package/hooks/mid_workflow_recall.py +27 -5
  33. package/hooks/post_edit_guard.py +133 -23
  34. package/hooks/session_context.py +707 -22
  35. package/package.json +7 -3
  36. package/skills/ultra-change/SKILL.md +69 -12
  37. package/skills/ultra-change/references/change-contract.md +93 -27
  38. package/skills/ultra-change/references/execution-grant.md +109 -0
  39. package/skills/ultra-change/references/primary-transfer.md +273 -0
  40. package/skills/ultra-change/scripts/validate_primary_transfer.cjs +1928 -0
  41. package/skills/ultra-delegate/SKILL.md +103 -8
  42. package/skills/ultra-delegate/patches/zcode-acp-0.1.0-zcode-0.16.5.patch +184 -0
  43. package/skills/ultra-delegate/references/delegation-contract.md +80 -1
  44. package/skills/ultra-delegate/scripts/acp-conformance.cjs +287 -0
  45. package/skills/ultra-delegate/scripts/acp-driver.cjs +762 -0
  46. package/skills/ultra-delegate/scripts/agent-execution-driver.cjs +320 -0
  47. package/skills/ultra-delegate/scripts/cli-driver.cjs +61 -0
  48. package/skills/ultra-delegate/scripts/delegate-worker.cjs +328 -0
  49. package/skills/ultra-delegate/scripts/delegate.cjs +690 -0
  50. package/skills/ultra-delegate/scripts/host-profile.cjs +267 -0
  51. package/skills/ultra-deliver/SKILL.md +98 -11
  52. package/skills/ultra-dev/SKILL.md +188 -42
  53. package/skills/ultra-grilling/SKILL.md +10 -7
  54. package/skills/ultra-grilling/references/reframing.md +7 -3
  55. package/skills/ultra-init/SKILL.md +56 -7
  56. package/skills/ultra-init/scripts/init_project.cjs +968 -21
  57. package/skills/ultra-plan/SKILL.md +91 -47
  58. package/skills/ultra-plan/references/task-evidence-v2.md +300 -0
  59. package/skills/ultra-plan/scripts/validate_task_evidence.cjs +859 -0
  60. package/skills/ultra-research/SKILL.md +70 -14
  61. package/skills/ultra-research/references/04-product-strategy.md +11 -2
  62. package/skills/ultra-research/references/21-features-scope.md +8 -0
  63. package/skills/ultra-research/references/22-success-metrics.md +4 -3
  64. package/skills/ultra-research/references/99-synthesis.md +19 -2
  65. package/skills/ultra-research/references/north-star-v2.md +168 -0
  66. package/skills/ultra-research/references/wayfinding.md +8 -0
  67. package/skills/ultra-research/scripts/validate_north_star.cjs +1174 -0
  68. package/skills/ultra-review/SKILL.md +201 -27
  69. package/skills/ultra-review/references/adversarial-evaluation.md +31 -0
  70. package/skills/ultra-review/references/spec.md +5 -0
  71. package/skills/ultra-review/references/unified-schema.md +146 -11
  72. package/skills/ultra-review/references/worker-packet.md +151 -8
  73. package/skills/ultra-review/scripts/review_wait.py +2653 -63
  74. package/skills/ultra-status/SKILL.md +129 -15
  75. package/skills/ultra-status/references/route-contract.md +100 -0
  76. package/skills/ultra-tdd/SKILL.md +11 -4
  77. package/skills/ultra-tdd/references/test-execution.md +6 -1
  78. package/skills/ultra-test/SKILL.md +161 -18
  79. package/skills/ultra-test/scripts/validate_review_transport.cjs +549 -0
  80. package/skills/ultra-test/scripts/worktree_digest.cjs +518 -30
  81. /package/{adapters/_shared → skills/ultra-delegate/scripts}/delegate-profiles/kimi-read-only.md +0 -0
  82. /package/{adapters/_shared → skills/ultra-delegate/scripts}/delegate-profiles/kimi-write.md +0 -0
@@ -1,9 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  'use strict';
3
3
 
4
+ const crypto = require('node:crypto');
4
5
  const fs = require('node:fs');
5
6
  const path = require('node:path');
6
7
 
8
+ const SNAPSHOT_READ_CHUNK_BYTES = 64 * 1024;
9
+
7
10
  function usage() {
8
11
  return 'usage: init_project.cjs --project <repository-root>';
9
12
  }
@@ -42,43 +45,987 @@ function ensurePlainDirectory(directory, label) {
42
45
  }
43
46
  }
44
47
 
48
+ function northStarValidator() {
49
+ const validator = path.resolve(
50
+ __dirname,
51
+ '..',
52
+ '..',
53
+ 'ultra-research',
54
+ 'scripts',
55
+ 'validate_north_star.cjs',
56
+ );
57
+ return fs.existsSync(validator) ? require(validator) : null;
58
+ }
59
+
60
+ function identity(stat) {
61
+ return [
62
+ stat.dev,
63
+ stat.ino,
64
+ stat.mode,
65
+ stat.size,
66
+ stat.mtimeNs,
67
+ stat.ctimeNs,
68
+ ];
69
+ }
70
+
71
+ function sameIdentity(left, right) {
72
+ return left.length === right.length && left.every((value, index) => value === right[index]);
73
+ }
74
+
75
+ function objectIdentity(snapshotIdentity) {
76
+ return snapshotIdentity.slice(0, 3);
77
+ }
78
+
79
+ function directoryIdentity(stat) {
80
+ return [stat.dev, stat.ino, stat.mode];
81
+ }
82
+
83
+ function preservedNorthStarConflict(phase) {
84
+ const error = new Error(
85
+ 'Preserved North Star changed during initialization; retry after the file is stable.',
86
+ );
87
+ error.code = 'preserved_north_star_changed';
88
+ error.retryable = true;
89
+ error.phase = phase;
90
+ error.path = 'north-star.md';
91
+ return error;
92
+ }
93
+
94
+ function northStarTemplateInvalid(report) {
95
+ const error = new Error(
96
+ 'new North Star template must pass the full North Star validator as an exact unresearched placeholder',
97
+ );
98
+ error.code = 'north_star_template_invalid';
99
+ error.retryable = true;
100
+ error.phase = 'template_validation';
101
+ error.path = 'north-star.md';
102
+ error.diagnostics = Array.isArray(report?.diagnostics)
103
+ ? report.diagnostics.map((diagnostic) => ({ ...diagnostic }))
104
+ : [];
105
+ return error;
106
+ }
107
+
108
+ function initializationSnapshotConflict(relative, phase, preservedNorthStar = false) {
109
+ if (preservedNorthStar) return preservedNorthStarConflict(phase);
110
+ const error = new Error(
111
+ `Initialization path changed during ${phase}: ${relative}; preserve the current bytes and retry after workspace writes settle.`,
112
+ );
113
+ error.code = 'initialization_snapshot_changed';
114
+ error.retryable = true;
115
+ error.phase = phase;
116
+ error.path = relative;
117
+ return error;
118
+ }
119
+
120
+ function initializationSnapshotIoError(relative, phase, operation, cause) {
121
+ const allowedOperations = new Set(['lstat', 'open', 'fstat', 'read']);
122
+ const safeOperation = allowedOperations.has(operation) ? operation : 'unknown';
123
+ const safeErrno = typeof cause?.code === 'string'
124
+ && /^[A-Z][A-Z0-9_]*$/u.test(cause.code)
125
+ ? cause.code
126
+ : 'UNKNOWN';
127
+ let manualAction = 'Repair the reported filesystem I/O condition, then retry initialization.';
128
+ if (safeErrno === 'EACCES' || safeErrno === 'EPERM') {
129
+ manualAction = 'Check permissions and ownership for the path, then retry initialization.';
130
+ } else if (safeErrno === 'EMFILE' || safeErrno === 'ENFILE') {
131
+ manualAction = 'Release unused file descriptors or raise the process descriptor limit, then retry initialization.';
132
+ } else if (safeErrno === 'EIO') {
133
+ manualAction = 'Check filesystem availability and storage health for the path, then retry initialization.';
134
+ }
135
+ const error = new Error(
136
+ `Initialization snapshot ${safeOperation} failed during ${phase}: ${relative} (${safeErrno}).`,
137
+ );
138
+ error.code = 'initialization_snapshot_io_error';
139
+ error.retryable = true;
140
+ error.phase = phase;
141
+ error.path = relative;
142
+ error.operation = safeOperation;
143
+ error.errno = safeErrno;
144
+ error.recovery = { manual_action: manualAction };
145
+ return error;
146
+ }
147
+
148
+ function snapshotIo(relative, phase, operation, read) {
149
+ try {
150
+ return read();
151
+ } catch (error) {
152
+ throw initializationSnapshotIoError(relative, phase, operation, error);
153
+ }
154
+ }
155
+
156
+ function stageCleanupConflict(stage, snapshot, {
157
+ currentPathPreserved,
158
+ destructiveCleanupAttempted = false,
159
+ } = {}) {
160
+ const error = new Error(
161
+ `Staging directory identity changed before cleanup: ${stage}. `
162
+ + 'No replacement path was removed; locate the owned directory by device and inode before manual removal.',
163
+ );
164
+ error.code = 'initialization_cleanup_conflict';
165
+ error.retryable = true;
166
+ error.phase = 'stage_cleanup';
167
+ error.path = path.basename(stage);
168
+ error.recovery = {
169
+ current_path: stage,
170
+ current_path_preserved: Boolean(currentPathPreserved),
171
+ destructive_cleanup_attempted: Boolean(destructiveCleanupAttempted),
172
+ owned_directory: {
173
+ device: String(snapshot.identity[0]),
174
+ inode: String(snapshot.identity[1]),
175
+ },
176
+ manual_action: 'Locate the owned staging directory by device and inode; remove it only after verifying that identity. Do not remove a replacement at current_path.',
177
+ };
178
+ return error;
179
+ }
180
+
181
+ function stableFileSnapshot(file, relative, phase, {
182
+ preservedNorthStar = false,
183
+ retainBytes = false,
184
+ } = {}) {
185
+ let descriptor;
186
+ try {
187
+ const beforePath = snapshotIo(
188
+ relative,
189
+ phase,
190
+ 'lstat',
191
+ () => fs.lstatSync(file, { bigint: true }),
192
+ );
193
+ if (!beforePath.isFile() || beforePath.isSymbolicLink()) {
194
+ throw initializationSnapshotConflict(relative, phase, preservedNorthStar);
195
+ }
196
+ const noFollow = fs.constants.O_NOFOLLOW || 0;
197
+ descriptor = snapshotIo(
198
+ relative,
199
+ phase,
200
+ 'open',
201
+ () => fs.openSync(
202
+ file,
203
+ fs.constants.O_RDONLY | fs.constants.O_NONBLOCK | noFollow,
204
+ ),
205
+ );
206
+ const before = snapshotIo(
207
+ relative,
208
+ phase,
209
+ 'fstat',
210
+ () => fs.fstatSync(descriptor, { bigint: true }),
211
+ );
212
+ if (!before.isFile() || !sameIdentity(identity(beforePath), identity(before))) {
213
+ throw initializationSnapshotConflict(relative, phase, preservedNorthStar);
214
+ }
215
+ const hash = crypto.createHash('sha256');
216
+ const retainedChunks = retainBytes ? [] : null;
217
+ const readBuffer = Buffer.allocUnsafe(SNAPSHOT_READ_CHUNK_BYTES);
218
+ let size = 0;
219
+ while (true) {
220
+ const bytesRead = snapshotIo(
221
+ relative,
222
+ phase,
223
+ 'read',
224
+ () => fs.readSync(
225
+ descriptor,
226
+ readBuffer,
227
+ 0,
228
+ readBuffer.length,
229
+ null,
230
+ ),
231
+ );
232
+ if (bytesRead === 0) break;
233
+ const chunk = readBuffer.subarray(0, bytesRead);
234
+ hash.update(chunk);
235
+ if (retainedChunks) retainedChunks.push(Buffer.from(chunk));
236
+ size += bytesRead;
237
+ }
238
+ const after = snapshotIo(
239
+ relative,
240
+ phase,
241
+ 'fstat',
242
+ () => fs.fstatSync(descriptor, { bigint: true }),
243
+ );
244
+ const afterPath = snapshotIo(
245
+ relative,
246
+ phase,
247
+ 'lstat',
248
+ () => fs.lstatSync(file, { bigint: true }),
249
+ );
250
+ if (!sameIdentity(identity(before), identity(after))
251
+ || !sameIdentity(identity(after), identity(afterPath))
252
+ || BigInt(size) !== after.size) {
253
+ throw initializationSnapshotConflict(relative, phase, preservedNorthStar);
254
+ }
255
+ const snapshot = {
256
+ size,
257
+ digest: hash.digest('hex'),
258
+ identity: identity(after),
259
+ };
260
+ if (retainedChunks) snapshot.bytes = Buffer.concat(retainedChunks, size);
261
+ return snapshot;
262
+ } finally {
263
+ if (descriptor !== undefined) fs.closeSync(descriptor);
264
+ }
265
+ }
266
+
267
+ function assertFileSnapshotUnchanged(
268
+ file,
269
+ relative,
270
+ expected,
271
+ phase,
272
+ preservedNorthStar = false,
273
+ ) {
274
+ const observed = stableFileSnapshot(file, relative, phase, { preservedNorthStar });
275
+ if (!sameIdentity(expected.identity, observed.identity)
276
+ || expected.digest !== observed.digest) {
277
+ throw initializationSnapshotConflict(relative, phase, preservedNorthStar);
278
+ }
279
+ return observed;
280
+ }
281
+
282
+ function stableRepositoryFileSnapshot(
283
+ root,
284
+ ultra,
285
+ relative,
286
+ phase,
287
+ knownDirectories,
288
+ options = {},
289
+ ) {
290
+ const file = path.join(ultra, relative);
291
+ const parent = path.dirname(file);
292
+ const before = captureDirectoryChain(
293
+ root,
294
+ parent,
295
+ relative,
296
+ phase,
297
+ knownDirectories,
298
+ );
299
+ const snapshot = stableFileSnapshot(file, relative, phase, options);
300
+ const after = captureDirectoryChain(
301
+ root,
302
+ parent,
303
+ relative,
304
+ phase,
305
+ knownDirectories,
306
+ );
307
+ assertSameDirectoryChain(before, after, relative, phase);
308
+ return snapshot;
309
+ }
310
+
311
+ function assertPreservedFilesUnchanged(
312
+ root,
313
+ ultra,
314
+ snapshots,
315
+ phase,
316
+ knownDirectories,
317
+ ) {
318
+ for (const [relative, expected] of snapshots) {
319
+ const observed = stableRepositoryFileSnapshot(
320
+ root,
321
+ ultra,
322
+ relative,
323
+ phase,
324
+ knownDirectories,
325
+ { preservedNorthStar: relative === 'north-star.md' },
326
+ );
327
+ if (!sameIdentity(expected.identity, observed.identity)
328
+ || expected.digest !== observed.digest) {
329
+ throw initializationSnapshotConflict(
330
+ relative,
331
+ phase,
332
+ relative === 'north-star.md',
333
+ );
334
+ }
335
+ }
336
+ }
337
+
338
+ function captureRoot(project) {
339
+ const before = fs.lstatSync(project, { bigint: true });
340
+ if (!before.isDirectory() || before.isSymbolicLink()) {
341
+ throw initializationSnapshotConflict('.', 'root_snapshot');
342
+ }
343
+ const resolved = fs.realpathSync.native(project);
344
+ const after = fs.lstatSync(project, { bigint: true });
345
+ if (!after.isDirectory()
346
+ || after.isSymbolicLink()
347
+ || !sameIdentity(directoryIdentity(before), directoryIdentity(after))) {
348
+ throw initializationSnapshotConflict('.', 'root_snapshot');
349
+ }
350
+ return {
351
+ path: project,
352
+ resolved,
353
+ identity: directoryIdentity(after),
354
+ };
355
+ }
356
+
357
+ function captureDirectoryChain(root, directory, relative, phase, knownDirectories) {
358
+ const target = path.resolve(directory);
359
+ const withinRoot = path.relative(root.path, target);
360
+ if (withinRoot === '..'
361
+ || withinRoot.startsWith(`..${path.sep}`)
362
+ || path.isAbsolute(withinRoot)) {
363
+ throw initializationSnapshotConflict(relative, phase);
364
+ }
365
+
366
+ const parts = withinRoot === '' ? [] : withinRoot.split(path.sep);
367
+ const chain = [];
368
+ let current = root.path;
369
+ for (let index = 0; index <= parts.length; index += 1) {
370
+ if (index > 0) current = path.join(current, parts[index - 1]);
371
+ let entry;
372
+ let resolved;
373
+ try {
374
+ entry = fs.lstatSync(current, { bigint: true });
375
+ if (!entry.isDirectory() || entry.isSymbolicLink()) {
376
+ throw initializationSnapshotConflict(relative, phase);
377
+ }
378
+ resolved = fs.realpathSync.native(current);
379
+ } catch (error) {
380
+ if (error.code === 'initialization_snapshot_changed') throw error;
381
+ throw initializationSnapshotConflict(relative, phase);
382
+ }
383
+ const expectedResolved = path.join(root.resolved, ...parts.slice(0, index));
384
+ const snapshot = {
385
+ path: current,
386
+ resolved,
387
+ identity: directoryIdentity(entry),
388
+ };
389
+ if (resolved !== expectedResolved) {
390
+ throw initializationSnapshotConflict(relative, phase);
391
+ }
392
+ const known = knownDirectories.get(current);
393
+ if (known
394
+ && (known.resolved !== snapshot.resolved
395
+ || !sameIdentity(known.identity, snapshot.identity))) {
396
+ throw initializationSnapshotConflict(relative, phase);
397
+ }
398
+ if (!known) knownDirectories.set(current, snapshot);
399
+ chain.push(snapshot);
400
+ }
401
+ if (root.resolved !== chain[0].resolved
402
+ || !sameIdentity(root.identity, chain[0].identity)) {
403
+ throw initializationSnapshotConflict(relative, phase);
404
+ }
405
+ return chain;
406
+ }
407
+
408
+ function assertSameDirectoryChain(before, after, relative, phase) {
409
+ if (before.length !== after.length) {
410
+ throw initializationSnapshotConflict(relative, phase);
411
+ }
412
+ for (let index = 0; index < before.length; index += 1) {
413
+ if (before[index].path !== after[index].path
414
+ || before[index].resolved !== after[index].resolved
415
+ || !sameIdentity(before[index].identity, after[index].identity)) {
416
+ throw initializationSnapshotConflict(relative, phase);
417
+ }
418
+ }
419
+ }
420
+
421
+ function classifyPreservedNorthStar(file, snapshot) {
422
+ const validator = northStarValidator();
423
+ if (validator?.validateBytes) {
424
+ const report = validator.validateBytes(file, snapshot.bytes);
425
+ if (report.valid && report.kind === 'legacy') return { disposition: 'preserved_legacy' };
426
+ if (report.valid && report.kind === 'north-star-v2' && report.status === 'unresearched') {
427
+ return { disposition: 'preserved_unresearched' };
428
+ }
429
+ if (report.valid && report.kind === 'north-star-v2' && report.status === 'accepted') {
430
+ return { disposition: 'preserved_accepted' };
431
+ }
432
+ return {
433
+ disposition: 'preserved_unknown',
434
+ diagnostics: Array.isArray(report.diagnostics) ? report.diagnostics : [],
435
+ };
436
+ }
437
+ return {
438
+ disposition: 'preserved_unknown',
439
+ diagnostics: [{
440
+ code: 'north_star_validator_missing',
441
+ severity: 'error',
442
+ message: 'Full North Star validator is missing from the installed plugin',
443
+ location: file,
444
+ }],
445
+ };
446
+ }
447
+
448
+ function validateNewNorthStar(file) {
449
+ const validator = northStarValidator();
450
+ if (!validator) throw new Error('full North Star validator is missing from the installed plugin');
451
+ const report = validator.validate(file);
452
+ const idsEmpty = ['FP', 'NS', 'HC'].every(
453
+ (kind) => Array.isArray(report.ids?.[kind]) && report.ids[kind].length === 0,
454
+ );
455
+ if (!(report.valid
456
+ && report.kind === 'north-star-v2'
457
+ && report.status === 'unresearched'
458
+ && idsEmpty)) {
459
+ throw northStarTemplateInvalid(report);
460
+ }
461
+ }
462
+
463
+ function stageFiles(source, relativeFiles, stage) {
464
+ const snapshots = new Map();
465
+ for (const relative of relativeFiles) {
466
+ const target = path.join(stage, relative);
467
+ fs.mkdirSync(path.dirname(target), { recursive: true });
468
+ fs.copyFileSync(path.join(source, relative), target, fs.constants.COPYFILE_EXCL);
469
+ snapshots.set(relative, stableFileSnapshot(target, relative, 'stage_snapshot'));
470
+ }
471
+ return snapshots;
472
+ }
473
+
474
+ function ensurePublishDirectory(
475
+ directory,
476
+ ultra,
477
+ createdDirectories,
478
+ root,
479
+ knownDirectories,
480
+ relative,
481
+ ) {
482
+ if (directory === ultra) {
483
+ captureDirectoryChain(root, directory, relative, 'publish_parent', knownDirectories);
484
+ return;
485
+ }
486
+ const parent = path.dirname(directory);
487
+ ensurePublishDirectory(
488
+ parent,
489
+ ultra,
490
+ createdDirectories,
491
+ root,
492
+ knownDirectories,
493
+ relative,
494
+ );
495
+ if (fs.existsSync(directory)) {
496
+ captureDirectoryChain(root, directory, relative, 'publish_parent', knownDirectories);
497
+ return;
498
+ }
499
+ const before = captureDirectoryChain(
500
+ root,
501
+ parent,
502
+ relative,
503
+ 'publish_parent_before',
504
+ knownDirectories,
505
+ );
506
+ try {
507
+ fs.mkdirSync(directory);
508
+ } catch {
509
+ throw initializationSnapshotConflict(relative, 'publish_parent');
510
+ }
511
+ const afterParent = captureDirectoryChain(
512
+ root,
513
+ parent,
514
+ relative,
515
+ 'publish_parent_after',
516
+ knownDirectories,
517
+ );
518
+ assertSameDirectoryChain(before, afterParent, relative, 'publish_parent_after');
519
+ const chain = captureDirectoryChain(
520
+ root,
521
+ directory,
522
+ relative,
523
+ 'publish_parent_after',
524
+ knownDirectories,
525
+ );
526
+ const snapshot = chain[chain.length - 1];
527
+ createdDirectories.push({
528
+ path: directory,
529
+ relative: path.relative(ultra, directory) || '.',
530
+ snapshot,
531
+ });
532
+ }
533
+
534
+ function rollbackPublishedFiles(
535
+ published,
536
+ createdDirectories,
537
+ root,
538
+ knownDirectories,
539
+ ) {
540
+ let conflict = null;
541
+ for (const item of [...published].reverse()) {
542
+ try {
543
+ const current = stableFileSnapshot(item.target, item.relative, 'rollback');
544
+ if (!item.snapshot
545
+ || !sameIdentity(item.snapshot.identity, current.identity)
546
+ || item.snapshot.digest !== current.digest) {
547
+ conflict ||= initializationSnapshotConflict(item.relative, 'rollback');
548
+ continue;
549
+ }
550
+ const before = captureDirectoryChain(
551
+ root,
552
+ path.dirname(item.target),
553
+ item.relative,
554
+ 'rollback',
555
+ knownDirectories,
556
+ );
557
+ fs.unlinkSync(item.target);
558
+ const after = captureDirectoryChain(
559
+ root,
560
+ path.dirname(item.target),
561
+ item.relative,
562
+ 'rollback',
563
+ knownDirectories,
564
+ );
565
+ assertSameDirectoryChain(before, after, item.relative, 'rollback');
566
+ } catch (error) {
567
+ conflict ||= error.code === 'initialization_snapshot_changed'
568
+ ? error
569
+ : initializationSnapshotConflict(item.relative, 'rollback');
570
+ }
571
+ }
572
+ for (const item of [...createdDirectories].reverse()) {
573
+ try {
574
+ const entry = fs.lstatSync(item.path, { bigint: true });
575
+ const resolved = fs.realpathSync.native(item.path);
576
+ if (!entry.isDirectory()
577
+ || entry.isSymbolicLink()
578
+ || resolved !== item.snapshot.resolved
579
+ || !sameIdentity(directoryIdentity(entry), item.snapshot.identity)) {
580
+ conflict ||= initializationSnapshotConflict(item.relative, 'rollback');
581
+ continue;
582
+ }
583
+ fs.rmdirSync(item.path);
584
+ } catch (error) {
585
+ conflict ||= initializationSnapshotConflict(item.relative, 'rollback');
586
+ }
587
+ }
588
+ return conflict;
589
+ }
590
+
591
+ function isInitializationConflict(error) {
592
+ return error.code === 'preserved_north_star_changed'
593
+ || error.code === 'initialization_snapshot_changed';
594
+ }
595
+
596
+ function isTypedInitializationError(error) {
597
+ return error?.code === 'preserved_north_star_changed'
598
+ || error?.code === 'initialization_snapshot_changed'
599
+ || error?.code === 'initialization_snapshot_io_error'
600
+ || error?.code === 'initialization_cleanup_conflict'
601
+ || error?.code === 'north_star_template_invalid';
602
+ }
603
+
604
+ function initializationErrorPayload(error, includeSchema = true) {
605
+ const payload = {
606
+ code: error.code,
607
+ retryable: error.retryable,
608
+ phase: error.phase,
609
+ path: error.path,
610
+ message: error.message,
611
+ };
612
+ if (includeSchema) payload.$schema = 'ultra-init-error-v1';
613
+ if (error.operation) payload.operation = error.operation;
614
+ if (error.errno) payload.errno = error.errno;
615
+ if (Array.isArray(error.diagnostics)) payload.diagnostics = error.diagnostics;
616
+ if (error.recovery) payload.recovery = error.recovery;
617
+ if (error.cleanupConflict) {
618
+ payload.cleanup_conflict = initializationErrorPayload(error.cleanupConflict, false);
619
+ }
620
+ return payload;
621
+ }
622
+
623
+ function assertPublishedFilesUnchanged(published, phase) {
624
+ for (const item of published) {
625
+ assertFileSnapshotUnchanged(
626
+ item.target,
627
+ item.relative,
628
+ item.snapshot,
629
+ phase,
630
+ );
631
+ }
632
+ }
633
+
634
+ function publishStagedFiles(
635
+ stage,
636
+ ultra,
637
+ relativeFiles,
638
+ stagedSnapshots,
639
+ root,
640
+ knownDirectories,
641
+ ) {
642
+ const published = [];
643
+ const createdDirectories = [];
644
+ try {
645
+ for (const relative of relativeFiles) {
646
+ const target = path.join(ultra, relative);
647
+ const staged = path.join(stage, relative);
648
+ const expected = stagedSnapshots.get(relative);
649
+ ensurePublishDirectory(
650
+ path.dirname(target),
651
+ ultra,
652
+ createdDirectories,
653
+ root,
654
+ knownDirectories,
655
+ relative,
656
+ );
657
+ assertFileSnapshotUnchanged(staged, relative, expected, 'before_publish');
658
+ const beforeParent = captureDirectoryChain(
659
+ root,
660
+ path.dirname(target),
661
+ relative,
662
+ 'publish_parent_before',
663
+ knownDirectories,
664
+ );
665
+ try {
666
+ fs.linkSync(staged, target);
667
+ } catch {
668
+ throw initializationSnapshotConflict(relative, 'publish');
669
+ }
670
+ const item = { target, relative, snapshot: null };
671
+ published.push(item);
672
+ let observed = stableFileSnapshot(target, relative, 'publish_verify');
673
+ if (!sameIdentity(objectIdentity(expected.identity), objectIdentity(observed.identity))
674
+ || expected.digest !== observed.digest) {
675
+ throw initializationSnapshotConflict(relative, 'publish_verify');
676
+ }
677
+ item.snapshot = observed;
678
+ try {
679
+ fs.unlinkSync(staged);
680
+ } catch {
681
+ throw initializationSnapshotConflict(relative, 'publish_commit');
682
+ }
683
+ observed = stableFileSnapshot(target, relative, 'publish_verify');
684
+ if (!sameIdentity(objectIdentity(expected.identity), objectIdentity(observed.identity))
685
+ || expected.digest !== observed.digest) {
686
+ throw initializationSnapshotConflict(relative, 'publish_verify');
687
+ }
688
+ item.snapshot = observed;
689
+ const afterParent = captureDirectoryChain(
690
+ root,
691
+ path.dirname(target),
692
+ relative,
693
+ 'publish_parent_after',
694
+ knownDirectories,
695
+ );
696
+ assertSameDirectoryChain(
697
+ beforeParent,
698
+ afterParent,
699
+ relative,
700
+ 'publish_parent_after',
701
+ );
702
+ }
703
+ assertPublishedFilesUnchanged(published, 'after_publish');
704
+ } catch (error) {
705
+ const rollbackConflict = rollbackPublishedFiles(
706
+ published,
707
+ createdDirectories,
708
+ root,
709
+ knownDirectories,
710
+ );
711
+ if (rollbackConflict && !isInitializationConflict(error)) throw rollbackConflict;
712
+ throw error;
713
+ }
714
+ return { published, createdDirectories };
715
+ }
716
+
717
+ function captureStagedDirectories(stage, ultra, root) {
718
+ const directories = [];
719
+ (function walk(directory) {
720
+ const relative = path.relative(stage, directory);
721
+ const entry = fs.lstatSync(directory, { bigint: true });
722
+ if (!entry.isDirectory() || entry.isSymbolicLink()) {
723
+ throw initializationSnapshotConflict(relative || '.ultra', 'before_publish');
724
+ }
725
+ directories.push({
726
+ path: path.join(ultra, relative),
727
+ relative: relative || '.',
728
+ snapshot: {
729
+ resolved: path.join(root.resolved, '.ultra', relative),
730
+ identity: directoryIdentity(entry),
731
+ },
732
+ });
733
+ for (const child of fs.readdirSync(directory, { withFileTypes: true })) {
734
+ if (child.isDirectory()) walk(path.join(directory, child.name));
735
+ }
736
+ }(stage));
737
+ return directories;
738
+ }
739
+
740
+ function assertPathAbsent(file, relative, phase) {
741
+ try {
742
+ fs.lstatSync(file);
743
+ } catch (error) {
744
+ if (error.code === 'ENOENT') return;
745
+ throw initializationSnapshotConflict(relative, phase);
746
+ }
747
+ throw initializationSnapshotConflict(relative, phase);
748
+ }
749
+
750
+ function pathExistsWithoutFollowing(file) {
751
+ try {
752
+ fs.lstatSync(file);
753
+ return true;
754
+ } catch (error) {
755
+ if (error.code === 'ENOENT') return false;
756
+ return true;
757
+ }
758
+ }
759
+
760
+ function cleanupOwnedStage(stage, expected, root, knownDirectories) {
761
+ let current;
762
+ try {
763
+ const chain = captureDirectoryChain(
764
+ root,
765
+ stage,
766
+ path.basename(stage),
767
+ 'stage_cleanup',
768
+ knownDirectories,
769
+ );
770
+ current = chain[chain.length - 1];
771
+ if (current.resolved !== expected.resolved
772
+ || !sameIdentity(current.identity, expected.identity)) {
773
+ throw initializationSnapshotConflict(path.basename(stage), 'stage_cleanup');
774
+ }
775
+ } catch {
776
+ throw stageCleanupConflict(stage, expected, {
777
+ currentPathPreserved: pathExistsWithoutFollowing(stage),
778
+ });
779
+ }
780
+
781
+ try {
782
+ fs.rmSync(stage, { recursive: true });
783
+ } catch {
784
+ throw stageCleanupConflict(stage, expected, {
785
+ currentPathPreserved: pathExistsWithoutFollowing(stage),
786
+ destructiveCleanupAttempted: true,
787
+ });
788
+ }
789
+ }
790
+
45
791
  function initialize(project) {
46
792
  if (!fs.existsSync(project)) throw new Error(`project does not exist: ${project}`);
47
793
  ensurePlainDirectory(project, 'project');
794
+ const root = captureRoot(project);
795
+ const knownDirectories = new Map([[
796
+ project,
797
+ { path: project, resolved: root.resolved, identity: root.identity },
798
+ ]]);
48
799
  const source = templateRoot();
49
800
  const ultra = path.join(project, '.ultra');
50
- if (fs.existsSync(ultra)) ensurePlainDirectory(ultra, '.ultra');
51
- else fs.mkdirSync(ultra);
801
+ const ultraExists = fs.existsSync(ultra);
802
+ if (ultraExists) {
803
+ ensurePlainDirectory(ultra, '.ultra');
804
+ captureDirectoryChain(root, ultra, '.ultra', 'initialization_snapshot', knownDirectories);
805
+ }
806
+
807
+ const templateFiles = listFiles(source);
808
+ const preserved = ultraExists
809
+ ? templateFiles.filter((relative) => fs.existsSync(path.join(ultra, relative)))
810
+ : [];
811
+ const created = templateFiles.filter((relative) => !preserved.includes(relative));
812
+ const preservedSnapshots = new Map(preserved.map((relative) => [
813
+ relative,
814
+ stableRepositoryFileSnapshot(
815
+ root,
816
+ ultra,
817
+ relative,
818
+ 'classification',
819
+ knownDirectories,
820
+ {
821
+ preservedNorthStar: relative === 'north-star.md',
822
+ retainBytes: relative === 'north-star.md',
823
+ },
824
+ ),
825
+ ]));
826
+ const northStarPath = path.join(ultra, 'north-star.md');
827
+ const northStarSnapshot = preservedSnapshots.get('north-star.md') || null;
828
+ let northStar = created.includes('north-star.md')
829
+ ? { disposition: 'created_unresearched' }
830
+ : classifyPreservedNorthStar(northStarPath, northStarSnapshot);
52
831
 
53
- const created = [];
54
- const preserved = [];
55
- for (const relative of listFiles(source)) {
56
- const target = path.join(ultra, relative);
57
- if (fs.existsSync(target)) {
58
- preserved.push(relative);
59
- continue;
832
+ assertPreservedFilesUnchanged(
833
+ root,
834
+ ultra,
835
+ preservedSnapshots,
836
+ 'before_stage',
837
+ knownDirectories,
838
+ );
839
+
840
+ let stage = fs.mkdtempSync(path.join(project, '.ultra-init-'));
841
+ const stageChain = captureDirectoryChain(
842
+ root,
843
+ stage,
844
+ path.basename(stage),
845
+ 'stage_snapshot',
846
+ knownDirectories,
847
+ );
848
+ const stageSnapshot = stageChain[stageChain.length - 1];
849
+ let publication = null;
850
+ let pendingError = null;
851
+ try {
852
+ const stagedSnapshots = stageFiles(source, created, stage);
853
+ if (created.includes('north-star.md')) {
854
+ validateNewNorthStar(path.join(stage, 'north-star.md'));
60
855
  }
61
- fs.mkdirSync(path.dirname(target), { recursive: true });
62
- fs.copyFileSync(path.join(source, relative), target, fs.constants.COPYFILE_EXCL);
63
- created.push(relative);
64
- }
65
- for (const relative of [...created, ...preserved]) {
66
- if (!fs.existsSync(path.join(ultra, relative))) {
67
- throw new Error(`initialization read-back failed: ${relative}`);
856
+ assertPreservedFilesUnchanged(
857
+ root,
858
+ ultra,
859
+ preservedSnapshots,
860
+ 'before_publish',
861
+ knownDirectories,
862
+ );
863
+
864
+ if (!ultraExists) {
865
+ for (const [relative, expected] of stagedSnapshots) {
866
+ assertFileSnapshotUnchanged(
867
+ path.join(stage, relative),
868
+ relative,
869
+ expected,
870
+ 'before_publish',
871
+ );
872
+ }
873
+ const beforeParent = captureDirectoryChain(
874
+ root,
875
+ project,
876
+ '.ultra',
877
+ 'publish_parent_before',
878
+ knownDirectories,
879
+ );
880
+ assertPathAbsent(ultra, '.ultra', 'before_publish');
881
+ const createdDirectories = captureStagedDirectories(stage, ultra, root);
882
+ try {
883
+ fs.renameSync(stage, ultra);
884
+ } catch {
885
+ throw initializationSnapshotConflict('.ultra', 'publish');
886
+ }
887
+ stage = null;
888
+ publication = {
889
+ published: [...stagedSnapshots].map(([relative, snapshot]) => ({
890
+ target: path.join(ultra, relative),
891
+ relative,
892
+ snapshot,
893
+ })),
894
+ createdDirectories,
895
+ };
896
+ const afterParent = captureDirectoryChain(
897
+ root,
898
+ project,
899
+ '.ultra',
900
+ 'publish_parent_after',
901
+ knownDirectories,
902
+ );
903
+ assertSameDirectoryChain(
904
+ beforeParent,
905
+ afterParent,
906
+ '.ultra',
907
+ 'publish_parent_after',
908
+ );
909
+ const ultraChain = captureDirectoryChain(
910
+ root,
911
+ ultra,
912
+ '.ultra',
913
+ 'publish_parent_after',
914
+ knownDirectories,
915
+ );
916
+ const expectedUltra = createdDirectories[0].snapshot;
917
+ const observedUltra = ultraChain[ultraChain.length - 1];
918
+ if (expectedUltra.resolved !== observedUltra.resolved
919
+ || !sameIdentity(expectedUltra.identity, observedUltra.identity)) {
920
+ throw initializationSnapshotConflict('.ultra', 'publish_parent_after');
921
+ }
922
+ for (const item of publication.published) {
923
+ const { relative } = item;
924
+ const expected = stagedSnapshots.get(relative);
925
+ const beforeFileParent = captureDirectoryChain(
926
+ root,
927
+ path.dirname(item.target),
928
+ relative,
929
+ 'publish_parent_before',
930
+ knownDirectories,
931
+ );
932
+ const observed = stableFileSnapshot(
933
+ item.target,
934
+ relative,
935
+ 'after_publish',
936
+ );
937
+ if (!sameIdentity(objectIdentity(expected.identity), objectIdentity(observed.identity))
938
+ || expected.digest !== observed.digest) {
939
+ throw initializationSnapshotConflict(relative, 'after_publish');
940
+ }
941
+ item.snapshot = observed;
942
+ const afterFileParent = captureDirectoryChain(
943
+ root,
944
+ path.dirname(item.target),
945
+ relative,
946
+ 'publish_parent_after',
947
+ knownDirectories,
948
+ );
949
+ assertSameDirectoryChain(
950
+ beforeFileParent,
951
+ afterFileParent,
952
+ relative,
953
+ 'publish_parent_after',
954
+ );
955
+ }
956
+ assertPublishedFilesUnchanged(publication.published, 'after_publish');
957
+ } else {
958
+ publication = publishStagedFiles(
959
+ stage,
960
+ ultra,
961
+ created,
962
+ stagedSnapshots,
963
+ root,
964
+ knownDirectories,
965
+ );
966
+ assertPreservedFilesUnchanged(
967
+ root,
968
+ ultra,
969
+ preservedSnapshots,
970
+ 'after_publish',
971
+ knownDirectories,
972
+ );
973
+ assertPublishedFilesUnchanged(publication.published, 'after_publish');
974
+ }
975
+ } catch (error) {
976
+ pendingError = error;
977
+ if (publication) {
978
+ const rollbackConflict = rollbackPublishedFiles(
979
+ publication.published,
980
+ publication.createdDirectories,
981
+ root,
982
+ knownDirectories,
983
+ );
984
+ if (rollbackConflict && !isInitializationConflict(error)) {
985
+ pendingError = rollbackConflict;
986
+ }
987
+ }
988
+ } finally {
989
+ if (stage) {
990
+ try {
991
+ cleanupOwnedStage(stage, stageSnapshot, root, knownDirectories);
992
+ } catch (cleanupError) {
993
+ if (pendingError && isTypedInitializationError(pendingError)) {
994
+ pendingError.cleanupConflict = cleanupError;
995
+ } else {
996
+ throw cleanupError;
997
+ }
998
+ }
68
999
  }
69
1000
  }
1001
+ if (pendingError) throw pendingError;
70
1002
  return {
71
1003
  $schema: 'ultra-init-result-v1',
72
1004
  project,
73
1005
  template: source,
74
1006
  created,
75
1007
  preserved,
1008
+ north_star: {
1009
+ path: 'north-star.md',
1010
+ ...northStar,
1011
+ },
76
1012
  };
77
1013
  }
78
1014
 
79
- try {
80
- process.stdout.write(`${JSON.stringify(initialize(parseArgs(process.argv.slice(2))), null, 2)}\n`);
81
- } catch (error) {
82
- process.stderr.write(`${error.message}\n`);
83
- process.exitCode = 1;
1015
+ if (require.main === module) {
1016
+ try {
1017
+ process.stdout.write(`${JSON.stringify(initialize(parseArgs(process.argv.slice(2))), null, 2)}\n`);
1018
+ } catch (error) {
1019
+ if (isTypedInitializationError(error)) {
1020
+ process.stderr.write(`${JSON.stringify(initializationErrorPayload(error), null, 2)}\n`);
1021
+ } else {
1022
+ process.stderr.write(`${error.message}\n`);
1023
+ }
1024
+ process.exitCode = 1;
1025
+ }
84
1026
  }
1027
+
1028
+ module.exports = {
1029
+ assertFileSnapshotUnchanged,
1030
+ stableFileSnapshot,
1031
+ };