ultra-builder-pro-cli 5.0.1 → 6.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 (159) hide show
  1. package/CHANGELOG.md +103 -3
  2. package/README.md +67 -478
  3. package/README.zh-CN.md +49 -422
  4. package/adapters/_shared/frontmatter.cjs +1 -18
  5. package/adapters/_shared/plugin-core.cjs +17 -83
  6. package/adapters/_shared/runtime-assets.cjs +6 -120
  7. package/adapters/claude.js +8 -24
  8. package/adapters/codex.js +13 -32
  9. package/bin/install.js +35 -57
  10. package/docs/PLUGIN-ISOLATION-CONTRACT.md +13 -101
  11. package/docs/examples/drive/claude-reviewer.sh +53 -0
  12. package/docs/examples/drive/claude-writer.sh +43 -0
  13. package/engine/FORMATS.md +1051 -0
  14. package/engine/checks.cjs +139 -0
  15. package/engine/cli.cjs +148 -0
  16. package/engine/completion.cjs +48 -0
  17. package/engine/context.cjs +94 -0
  18. package/engine/drive.cjs +220 -0
  19. package/engine/expect-worker.cjs +5 -0
  20. package/engine/expect.cjs +33 -0
  21. package/engine/formats.cjs +189 -0
  22. package/engine/git-state.cjs +112 -0
  23. package/engine/ledger.cjs +205 -0
  24. package/engine/loading.cjs +28 -0
  25. package/engine/merge.cjs +273 -0
  26. package/engine/milestone.cjs +89 -0
  27. package/engine/plan.cjs +232 -0
  28. package/engine/project.cjs +5 -0
  29. package/engine/signals.cjs +3 -0
  30. package/engine/states.cjs +175 -0
  31. package/hooks/session-start.cjs +54 -0
  32. package/package.json +17 -52
  33. package/skills/ultra/SKILL.md +395 -0
  34. package/.ultra-template/changes/abandoned/.gitkeep +0 -0
  35. package/.ultra-template/changes/active/.gitkeep +0 -1
  36. package/.ultra-template/changes/archive/.gitkeep +0 -1
  37. package/.ultra-template/contexts/TEMPLATE.md +0 -135
  38. package/.ultra-template/decisions/.gitkeep +0 -1
  39. package/.ultra-template/evidence/.gitkeep +0 -1
  40. package/.ultra-template/north-star.md +0 -52
  41. package/.ultra-template/project-brief.md +0 -28
  42. package/.ultra-template/research/.gitkeep +0 -1
  43. package/.ultra-template/specs/architecture.md +0 -81
  44. package/.ultra-template/specs/discovery.md +0 -74
  45. package/.ultra-template/specs/product.md +0 -80
  46. package/.ultra-template/specs/research-distillate.md +0 -57
  47. package/.ultra-template/tasks.json +0 -4
  48. package/.ultra-template/test-report.json +0 -44
  49. package/adapters/_shared/host-profile.cjs +0 -5
  50. package/adapters/grok.js +0 -242
  51. package/adapters/kimi.js +0 -232
  52. package/adapters/opencode.js +0 -408
  53. package/adapters/zcode.js +0 -375
  54. package/bin/delegate-worker.cjs +0 -5
  55. package/bin/delegate.cjs +0 -5
  56. package/docs/ARCHITECTURE.md +0 -274
  57. package/docs/ARTIFACT-AUTHORITY.md +0 -305
  58. package/docs/DECISIONS.md +0 -229
  59. package/docs/PHILOSOPHY.md +0 -261
  60. package/docs/RUNTIME-COMPAT-MATRIX.md +0 -316
  61. package/docs/SKILL-AUTHORING.md +0 -113
  62. package/docs/WORKFLOW-LIFECYCLE.md +0 -350
  63. package/docs/evals/adversarial-review-2026-08-14.md +0 -84
  64. package/docs/evals/ultra-5-0-journey-results.md +0 -62
  65. package/docs/evals/ultra-5-0-live-acp-conformance.md +0 -93
  66. package/docs/evals/ultra-5-0-route-journeys.md +0 -145
  67. package/docs/evals/zcode-automation-2026-08-14.md +0 -103
  68. package/hooks/README.md +0 -52
  69. package/hooks/_common.py +0 -1779
  70. package/hooks/adapters/codex.py +0 -295
  71. package/hooks/adapters/grok.py +0 -134
  72. package/hooks/adapters/kimi.py +0 -156
  73. package/hooks/adapters/zcode.py +0 -227
  74. package/hooks/block_dangerous_commands.py +0 -201
  75. package/hooks/compact_context.py +0 -224
  76. package/hooks/mid_workflow_recall.py +0 -47
  77. package/hooks/post_edit_guard.py +0 -215
  78. package/hooks/session_context.py +0 -741
  79. package/skills/ultra-change/SKILL.md +0 -165
  80. package/skills/ultra-change/references/change-contract.md +0 -199
  81. package/skills/ultra-change/references/execution-grant.md +0 -109
  82. package/skills/ultra-change/references/primary-transfer.md +0 -273
  83. package/skills/ultra-change/scripts/validate_primary_transfer.cjs +0 -1928
  84. package/skills/ultra-delegate/SKILL.md +0 -195
  85. package/skills/ultra-delegate/patches/zcode-acp-0.1.0-zcode-0.16.5.patch +0 -184
  86. package/skills/ultra-delegate/references/delegation-contract.md +0 -138
  87. package/skills/ultra-delegate/scripts/acp-conformance.cjs +0 -287
  88. package/skills/ultra-delegate/scripts/acp-driver.cjs +0 -762
  89. package/skills/ultra-delegate/scripts/agent-execution-driver.cjs +0 -320
  90. package/skills/ultra-delegate/scripts/cli-driver.cjs +0 -61
  91. package/skills/ultra-delegate/scripts/delegate-profiles/kimi-read-only.md +0 -15
  92. package/skills/ultra-delegate/scripts/delegate-profiles/kimi-write.md +0 -17
  93. package/skills/ultra-delegate/scripts/delegate-worker.cjs +0 -328
  94. package/skills/ultra-delegate/scripts/delegate.cjs +0 -690
  95. package/skills/ultra-delegate/scripts/delegate_wait.py +0 -86
  96. package/skills/ultra-delegate/scripts/host-profile.cjs +0 -267
  97. package/skills/ultra-deliver/SKILL.md +0 -194
  98. package/skills/ultra-deliver/references/baseline-reconciliation.md +0 -41
  99. package/skills/ultra-dev/SKILL.md +0 -265
  100. package/skills/ultra-dev/references/debugging.md +0 -22
  101. package/skills/ultra-domain-modeling/SKILL.md +0 -79
  102. package/skills/ultra-grilling/SKILL.md +0 -121
  103. package/skills/ultra-grilling/references/reframing.md +0 -76
  104. package/skills/ultra-init/SKILL.md +0 -143
  105. package/skills/ultra-init/references/brownfield-adoption.md +0 -32
  106. package/skills/ultra-init/scripts/init_project.cjs +0 -1031
  107. package/skills/ultra-plan/SKILL.md +0 -160
  108. package/skills/ultra-plan/references/task-evidence-v2.md +0 -300
  109. package/skills/ultra-plan/scripts/validate_task_evidence.cjs +0 -859
  110. package/skills/ultra-research/SKILL.md +0 -167
  111. package/skills/ultra-research/references/00-problem-validation.md +0 -36
  112. package/skills/ultra-research/references/01-opportunity-discovery.md +0 -33
  113. package/skills/ultra-research/references/02-market-assessment.md +0 -31
  114. package/skills/ultra-research/references/03-alternatives.md +0 -31
  115. package/skills/ultra-research/references/04-product-strategy.md +0 -41
  116. package/skills/ultra-research/references/05-assumptions-validation.md +0 -31
  117. package/skills/ultra-research/references/10-user-personas.md +0 -30
  118. package/skills/ultra-research/references/11-user-scenarios.md +0 -28
  119. package/skills/ultra-research/references/20-user-stories.md +0 -31
  120. package/skills/ultra-research/references/21-features-scope.md +0 -38
  121. package/skills/ultra-research/references/22-success-metrics.md +0 -33
  122. package/skills/ultra-research/references/30-architecture-context.md +0 -30
  123. package/skills/ultra-research/references/31-solution-strategy.md +0 -28
  124. package/skills/ultra-research/references/32-building-blocks.md +0 -28
  125. package/skills/ultra-research/references/40-deployment.md +0 -29
  126. package/skills/ultra-research/references/41-quality-risks.md +0 -28
  127. package/skills/ultra-research/references/99-synthesis.md +0 -59
  128. package/skills/ultra-research/references/north-star-v2.md +0 -168
  129. package/skills/ultra-research/references/wayfinding.md +0 -50
  130. package/skills/ultra-research/scripts/validate_north_star.cjs +0 -1174
  131. package/skills/ultra-review/SKILL.md +0 -275
  132. package/skills/ultra-review/references/adversarial-evaluation.md +0 -31
  133. package/skills/ultra-review/references/code.md +0 -17
  134. package/skills/ultra-review/references/comments.md +0 -12
  135. package/skills/ultra-review/references/design.md +0 -12
  136. package/skills/ultra-review/references/errors.md +0 -13
  137. package/skills/ultra-review/references/review-modes.md +0 -29
  138. package/skills/ultra-review/references/spec.md +0 -18
  139. package/skills/ultra-review/references/tests.md +0 -12
  140. package/skills/ultra-review/references/unified-schema.md +0 -284
  141. package/skills/ultra-review/references/worker-packet.md +0 -183
  142. package/skills/ultra-review/scripts/review_wait.py +0 -2943
  143. package/skills/ultra-status/SKILL.md +0 -209
  144. package/skills/ultra-status/references/route-contract.md +0 -100
  145. package/skills/ultra-tdd/SKILL.md +0 -91
  146. package/skills/ultra-tdd/references/templates/README.md +0 -20
  147. package/skills/ultra-tdd/references/templates/feature-flag-default-audit.sh +0 -79
  148. package/skills/ultra-tdd/references/templates/persistence-real.ts +0 -78
  149. package/skills/ultra-tdd/references/templates/testcontainer-postgres.py +0 -78
  150. package/skills/ultra-tdd/references/templates/testcontainer-postgres.ts +0 -73
  151. package/skills/ultra-tdd/references/templates/vertical-slice.ts +0 -66
  152. package/skills/ultra-tdd/references/test-execution.md +0 -23
  153. package/skills/ultra-test/SKILL.md +0 -244
  154. package/skills/ultra-test/references/export-syntax.md +0 -18
  155. package/skills/ultra-test/scripts/validate_review_transport.cjs +0 -549
  156. package/skills/ultra-test/scripts/worktree_digest.cjs +0 -576
  157. package/skills/ultra-think/SKILL.md +0 -56
  158. package/skills/ultra-think/references/autonomy-boundary.md +0 -48
  159. package/skills/ultra-think/references/interaction-boundary.md +0 -42
@@ -1,1031 +0,0 @@
1
- #!/usr/bin/env node
2
- 'use strict';
3
-
4
- const crypto = require('node:crypto');
5
- const fs = require('node:fs');
6
- const path = require('node:path');
7
-
8
- const SNAPSHOT_READ_CHUNK_BYTES = 64 * 1024;
9
-
10
- function usage() {
11
- return 'usage: init_project.cjs --project <repository-root>';
12
- }
13
-
14
- function parseArgs(argv) {
15
- if (argv.length !== 2 || argv[0] !== '--project' || !argv[1]) {
16
- throw new Error(usage());
17
- }
18
- return path.resolve(argv[1]);
19
- }
20
-
21
- function listFiles(root) {
22
- const files = [];
23
- (function walk(directory) {
24
- for (const entry of fs.readdirSync(directory, { withFileTypes: true })) {
25
- const file = path.join(directory, entry.name);
26
- if (entry.isDirectory()) walk(file);
27
- else if (entry.isFile()) files.push(path.relative(root, file));
28
- }
29
- }(root));
30
- return files.sort();
31
- }
32
-
33
- function templateRoot() {
34
- const installed = path.resolve(__dirname, '..', 'assets', 'project-template');
35
- if (fs.existsSync(installed)) return installed;
36
- const checkout = path.resolve(__dirname, '..', '..', '..', '.ultra-template');
37
- if (fs.existsSync(checkout)) return checkout;
38
- throw new Error('ultra-init project template is missing');
39
- }
40
-
41
- function ensurePlainDirectory(directory, label) {
42
- const stat = fs.lstatSync(directory);
43
- if (!stat.isDirectory() || stat.isSymbolicLink()) {
44
- throw new Error(`${label} must be a real directory: ${directory}`);
45
- }
46
- }
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
-
791
- function initialize(project) {
792
- if (!fs.existsSync(project)) throw new Error(`project does not exist: ${project}`);
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
- ]]);
799
- const source = templateRoot();
800
- const ultra = path.join(project, '.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);
831
-
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'));
855
- }
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
- }
999
- }
1000
- }
1001
- if (pendingError) throw pendingError;
1002
- return {
1003
- $schema: 'ultra-init-result-v1',
1004
- project,
1005
- template: source,
1006
- created,
1007
- preserved,
1008
- north_star: {
1009
- path: 'north-star.md',
1010
- ...northStar,
1011
- },
1012
- };
1013
- }
1014
-
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
- }
1026
- }
1027
-
1028
- module.exports = {
1029
- assertFileSnapshotUnchanged,
1030
- stableFileSnapshot,
1031
- };