ultra-builder-pro-cli 0.26.1 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.ultra-template/contexts/TEMPLATE.md +64 -29
- package/.ultra-template/north-star.md +36 -30
- package/.ultra-template/project-brief.md +28 -0
- package/.ultra-template/specs/product.md +4 -0
- package/.ultra-template/specs/research-distillate.md +8 -0
- package/.ultra-template/tasks.json +1 -0
- package/.ultra-template/test-report.json +18 -1
- package/CHANGELOG.md +227 -1
- package/README.md +161 -59
- package/adapters/_shared/host-profile.cjs +68 -12
- package/adapters/_shared/plugin-core.cjs +4 -5
- package/adapters/_shared/runtime-assets.cjs +11 -2
- package/adapters/zcode.js +375 -0
- package/bin/delegate-worker.cjs +20 -0
- package/bin/delegate.cjs +94 -25
- package/bin/install.js +11 -6
- package/docs/ARCHITECTURE.md +109 -25
- package/docs/ARTIFACT-AUTHORITY.md +204 -30
- package/docs/DECISIONS.md +141 -10
- package/docs/PHILOSOPHY.md +61 -8
- package/docs/PLUGIN-ISOLATION-CONTRACT.md +6 -0
- package/docs/RUNTIME-COMPAT-MATRIX.md +106 -13
- package/docs/SKILL-AUTHORING.md +14 -9
- package/docs/WORKFLOW-LIFECYCLE.md +211 -53
- package/docs/evals/adversarial-review-2026-08-14.md +84 -0
- package/docs/evals/zcode-automation-2026-08-14.md +103 -0
- package/hooks/README.md +31 -3
- package/hooks/_common.py +1699 -33
- package/hooks/adapters/zcode.py +227 -0
- package/hooks/compact_context.py +176 -17
- package/hooks/mid_workflow_recall.py +27 -5
- package/hooks/post_edit_guard.py +133 -23
- package/hooks/session_context.py +722 -11
- package/package.json +6 -3
- package/skills/ultra-change/SKILL.md +84 -64
- package/skills/ultra-change/references/change-contract.md +130 -32
- package/skills/ultra-change/references/execution-grant.md +109 -0
- package/skills/ultra-change/references/primary-transfer.md +273 -0
- package/skills/ultra-change/scripts/validate_primary_transfer.cjs +1928 -0
- package/skills/ultra-delegate/SKILL.md +38 -5
- package/skills/ultra-delegate/references/delegation-contract.md +21 -1
- package/skills/ultra-deliver/SKILL.md +123 -44
- package/skills/ultra-deliver/references/baseline-reconciliation.md +5 -3
- package/skills/ultra-dev/SKILL.md +173 -43
- package/skills/ultra-grilling/SKILL.md +19 -16
- package/skills/ultra-grilling/references/reframing.md +7 -3
- package/skills/ultra-init/SKILL.md +99 -87
- package/skills/ultra-init/references/brownfield-adoption.md +23 -40
- package/skills/ultra-init/scripts/init_project.cjs +968 -21
- package/skills/ultra-plan/SKILL.md +83 -46
- package/skills/ultra-plan/references/task-evidence-v2.md +300 -0
- package/skills/ultra-plan/scripts/validate_task_evidence.cjs +859 -0
- package/skills/ultra-research/SKILL.md +119 -68
- package/skills/ultra-research/references/{03-competitive-landscape.md → 03-alternatives.md} +6 -6
- package/skills/ultra-research/references/04-product-strategy.md +11 -2
- package/skills/ultra-research/references/21-features-scope.md +8 -0
- package/skills/ultra-research/references/22-success-metrics.md +9 -4
- package/skills/ultra-research/references/99-synthesis.md +25 -1
- package/skills/ultra-research/references/north-star-v2.md +168 -0
- package/skills/ultra-research/references/wayfinding.md +50 -0
- package/skills/ultra-research/scripts/validate_north_star.cjs +1174 -0
- package/skills/ultra-review/SKILL.md +201 -24
- package/skills/ultra-review/references/adversarial-evaluation.md +31 -0
- package/skills/ultra-review/references/spec.md +5 -0
- package/skills/ultra-review/references/unified-schema.md +146 -11
- package/skills/ultra-review/references/worker-packet.md +151 -8
- package/skills/ultra-review/scripts/review_wait.py +2653 -63
- package/skills/ultra-status/SKILL.md +146 -32
- package/skills/ultra-tdd/SKILL.md +14 -4
- package/skills/ultra-tdd/references/test-execution.md +6 -1
- package/skills/ultra-test/SKILL.md +157 -15
- package/skills/ultra-test/scripts/validate_review_transport.cjs +549 -0
- package/skills/ultra-test/scripts/worktree_digest.cjs +551 -29
- package/skills/ultra-think/SKILL.md +5 -10
- package/skills/ultra-think/references/interaction-boundary.md +2 -1
|
@@ -6,49 +6,571 @@ const fs = require('node:fs');
|
|
|
6
6
|
const path = require('node:path');
|
|
7
7
|
const { execFileSync } = require('node:child_process');
|
|
8
8
|
|
|
9
|
+
const MAX_SNAPSHOT_BYTES = 8 * 1024 * 1024;
|
|
10
|
+
const SNAPSHOT_CHUNK_BYTES = 64 * 1024;
|
|
11
|
+
const MAX_OBSERVATION_FILES = 256;
|
|
12
|
+
const MAX_OBSERVATION_BYTES = 16 * 1024 * 1024;
|
|
13
|
+
const GIT_TIMEOUT_MS = 5000;
|
|
14
|
+
const GIT_MAX_OUTPUT_BYTES = 64 * 1024 * 1024;
|
|
15
|
+
const PRODUCT_PATHSPEC = [
|
|
16
|
+
'--', '.',
|
|
17
|
+
':(exclude).ultra/test-report.json',
|
|
18
|
+
':(exclude).ultra/evidence/**',
|
|
19
|
+
':(exclude).ultra/reviews/**',
|
|
20
|
+
':(exclude).ultra/.runtime/**',
|
|
21
|
+
':(exclude).ultra/progress/**',
|
|
22
|
+
':(exclude).ultra/changes/active/**',
|
|
23
|
+
':(exclude).ultra/changes/archive/**',
|
|
24
|
+
':(exclude).ultra/changes/abandoned/**',
|
|
25
|
+
];
|
|
26
|
+
|
|
9
27
|
function git(cwd, args, encoding = 'utf8') {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
28
|
+
try {
|
|
29
|
+
return execFileSync('git', args, {
|
|
30
|
+
cwd,
|
|
31
|
+
encoding,
|
|
32
|
+
maxBuffer: GIT_MAX_OUTPUT_BYTES,
|
|
33
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
34
|
+
timeout: GIT_TIMEOUT_MS,
|
|
35
|
+
});
|
|
36
|
+
} catch (error) {
|
|
37
|
+
const operation = args.slice(0, 2).join(' ');
|
|
38
|
+
if (error && (error.code === 'ETIMEDOUT' || (error.killed && error.signal))) {
|
|
39
|
+
throw new Error(
|
|
40
|
+
`ULTRA_SNAPSHOT_GIT_TIMEOUT: Git ${JSON.stringify(operation)} exceeded the `
|
|
41
|
+
+ `${GIT_TIMEOUT_MS}ms physical observation limit. Restore a responsive repository `
|
|
42
|
+
+ 'and Git process, then retry worktree_digest.',
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
if (error && error.code === 'ENOBUFS') {
|
|
46
|
+
throw new Error(
|
|
47
|
+
`ULTRA_SNAPSHOT_GIT_OUTPUT_LIMIT: Git ${JSON.stringify(operation)} exceeded the `
|
|
48
|
+
+ `${GIT_MAX_OUTPUT_BYTES}-byte output limit. Reduce or split the physical product `
|
|
49
|
+
+ 'observation, then retry worktree_digest.',
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
const stderr = error && error.stderr
|
|
53
|
+
? Buffer.from(error.stderr).toString('utf8').trim().split('\n')[0]
|
|
54
|
+
: 'Git returned an unknown failure';
|
|
55
|
+
throw new Error(
|
|
56
|
+
`ULTRA_SNAPSHOT_GIT_FAILED: Git ${JSON.stringify(operation)} failed (${stderr}). `
|
|
57
|
+
+ 'Repair the repository and Git operation, then retry worktree_digest.',
|
|
58
|
+
);
|
|
59
|
+
}
|
|
16
60
|
}
|
|
17
61
|
|
|
18
|
-
function
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
62
|
+
function optionsFromArgs(argv) {
|
|
63
|
+
const options = { project: process.cwd(), changeId: null };
|
|
64
|
+
for (let index = 0; index < argv.length; index += 2) {
|
|
65
|
+
const flag = argv[index];
|
|
66
|
+
const value = argv[index + 1];
|
|
67
|
+
if (!value) throw new Error('usage: worktree_digest.cjs [--project <repository-root>] [--change-id <id>]');
|
|
68
|
+
if (flag === '--project') options.project = path.resolve(value);
|
|
69
|
+
else if (flag === '--change-id') options.changeId = value;
|
|
70
|
+
else throw new Error('usage: worktree_digest.cjs [--project <repository-root>] [--change-id <id>]');
|
|
71
|
+
}
|
|
72
|
+
if (options.changeId && !/^[A-Za-z0-9][A-Za-z0-9._-]*$/.test(options.changeId)) {
|
|
73
|
+
throw new Error(`invalid Change id: ${options.changeId}`);
|
|
74
|
+
}
|
|
75
|
+
return options;
|
|
22
76
|
}
|
|
23
77
|
|
|
24
|
-
function
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
78
|
+
function snapshotError(code, relative, observation) {
|
|
79
|
+
return new Error(
|
|
80
|
+
`${code}: cannot snapshot ${JSON.stringify(relative)}: ${observation}. `
|
|
81
|
+
+ 'Restore the repository path as an ordinary regular non-symlink file within the '
|
|
82
|
+
+ '8 MiB limit, then retry worktree_digest.',
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function repositoryPath(root, relative) {
|
|
87
|
+
if (typeof relative !== 'string'
|
|
88
|
+
|| relative.length === 0
|
|
89
|
+
|| relative.includes('\0')
|
|
90
|
+
|| path.posix.isAbsolute(relative)
|
|
91
|
+
|| path.win32.isAbsolute(relative)) {
|
|
92
|
+
throw snapshotError('ULTRA_SNAPSHOT_PATH_ESCAPE', String(relative), 'path is not repository-relative');
|
|
93
|
+
}
|
|
94
|
+
const parts = relative.split('/');
|
|
95
|
+
if (parts.some((part) => part === '' || part === '.' || part === '..')
|
|
96
|
+
|| (path.sep === '\\' && parts.some((part) => part.includes('\\')))) {
|
|
97
|
+
throw snapshotError('ULTRA_SNAPSHOT_PATH_ESCAPE', relative, 'path escapes its repository root');
|
|
98
|
+
}
|
|
99
|
+
const absolute = path.join(root, ...parts);
|
|
100
|
+
const resolvedRelative = path.relative(root, absolute);
|
|
101
|
+
if (resolvedRelative === ''
|
|
102
|
+
|| resolvedRelative === '..'
|
|
103
|
+
|| resolvedRelative.startsWith(`..${path.sep}`)
|
|
104
|
+
|| path.isAbsolute(resolvedRelative)) {
|
|
105
|
+
throw snapshotError('ULTRA_SNAPSHOT_PATH_ESCAPE', relative, 'path escapes its repository root');
|
|
106
|
+
}
|
|
107
|
+
return { absolute, parts };
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
function lstatSnapshot(absolute, relative) {
|
|
111
|
+
try {
|
|
112
|
+
return fs.lstatSync(absolute, { bigint: true });
|
|
113
|
+
} catch (error) {
|
|
114
|
+
if (error && (error.code === 'ENOENT' || error.code === 'ENOTDIR')) {
|
|
115
|
+
throw snapshotError('ULTRA_SNAPSHOT_MISSING', relative, 'path disappeared during observation');
|
|
116
|
+
}
|
|
117
|
+
throw snapshotError(
|
|
118
|
+
'ULTRA_SNAPSHOT_UNREADABLE',
|
|
119
|
+
relative,
|
|
120
|
+
`lstat failed with ${error && error.code ? error.code : 'an unknown error'}`,
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function sameNode(left, right) {
|
|
126
|
+
return left.dev === right.dev
|
|
127
|
+
&& left.ino === right.ino
|
|
128
|
+
&& left.mode === right.mode;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
function sameFileVersion(left, right) {
|
|
132
|
+
return sameNode(left, right)
|
|
133
|
+
&& left.size === right.size
|
|
134
|
+
&& left.mtimeNs === right.mtimeNs
|
|
135
|
+
&& left.ctimeNs === right.ctimeNs;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function walkSnapshotPath(root, relative) {
|
|
139
|
+
const resolved = repositoryPath(root, relative);
|
|
140
|
+
const parents = [];
|
|
141
|
+
let current = root;
|
|
142
|
+
const rootStat = lstatSnapshot(root, '.');
|
|
143
|
+
if (rootStat.isSymbolicLink()) {
|
|
144
|
+
throw snapshotError('ULTRA_SNAPSHOT_SYMLINK', relative, 'repository root is a symlink');
|
|
145
|
+
}
|
|
146
|
+
if (!rootStat.isDirectory()) {
|
|
147
|
+
throw snapshotError('ULTRA_SNAPSHOT_NOT_DIRECTORY', relative, 'repository root is not a directory');
|
|
148
|
+
}
|
|
149
|
+
parents.push({ absolute: root, relative: '.', stat: rootStat });
|
|
150
|
+
|
|
151
|
+
for (const part of resolved.parts.slice(0, -1)) {
|
|
152
|
+
current = path.join(current, part);
|
|
153
|
+
const observedRelative = path.relative(root, current) || '.';
|
|
154
|
+
const stat = lstatSnapshot(current, observedRelative);
|
|
155
|
+
if (stat.isSymbolicLink()) {
|
|
156
|
+
throw snapshotError(
|
|
157
|
+
'ULTRA_SNAPSHOT_SYMLINK',
|
|
158
|
+
relative,
|
|
159
|
+
`parent ${JSON.stringify(observedRelative)} is a symlink`,
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
if (!stat.isDirectory()) {
|
|
163
|
+
throw snapshotError(
|
|
164
|
+
'ULTRA_SNAPSHOT_NOT_DIRECTORY',
|
|
165
|
+
relative,
|
|
166
|
+
`parent ${JSON.stringify(observedRelative)} is not a directory`,
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
parents.push({ absolute: current, relative: observedRelative, stat });
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const finalStat = lstatSnapshot(resolved.absolute, relative);
|
|
173
|
+
if (finalStat.isSymbolicLink()) {
|
|
174
|
+
throw snapshotError('ULTRA_SNAPSHOT_SYMLINK', relative, 'final entry is a symlink');
|
|
175
|
+
}
|
|
176
|
+
if (!finalStat.isFile()) {
|
|
177
|
+
throw snapshotError('ULTRA_SNAPSHOT_NOT_REGULAR', relative, 'final entry is not a regular file');
|
|
178
|
+
}
|
|
179
|
+
if (finalStat.size > BigInt(MAX_SNAPSHOT_BYTES)) {
|
|
180
|
+
throw snapshotError(
|
|
181
|
+
'ULTRA_SNAPSHOT_TOO_LARGE',
|
|
182
|
+
relative,
|
|
183
|
+
`regular file exceeds the ${MAX_SNAPSHOT_BYTES}-byte physical ceiling`,
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
return {
|
|
187
|
+
absolute: resolved.absolute,
|
|
188
|
+
final: { absolute: resolved.absolute, relative, stat: finalStat },
|
|
189
|
+
parents,
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
function verifyFreshRewalk(root, relative, initial, phase) {
|
|
194
|
+
let current;
|
|
195
|
+
try {
|
|
196
|
+
current = walkSnapshotPath(root, relative);
|
|
197
|
+
} catch (error) {
|
|
198
|
+
throw snapshotError(
|
|
199
|
+
'ULTRA_SNAPSHOT_REPLACED',
|
|
200
|
+
relative,
|
|
201
|
+
`${phase} rewalk no longer resolves the initial identities (${error.message})`,
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
const parentsStable = current.parents.length === initial.parents.length
|
|
205
|
+
&& current.parents.every((entry, index) => sameNode(entry.stat, initial.parents[index].stat));
|
|
206
|
+
if (!parentsStable || !sameFileVersion(current.final.stat, initial.final.stat)) {
|
|
207
|
+
throw snapshotError(
|
|
208
|
+
'ULTRA_SNAPSHOT_REPLACED',
|
|
209
|
+
relative,
|
|
210
|
+
`${phase} rewalk observed a replaced root, parent, or final identity`,
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function openSnapshotFile(absolute, relative) {
|
|
216
|
+
const { O_NOFOLLOW, O_NONBLOCK, O_RDONLY } = fs.constants;
|
|
217
|
+
if (![O_NOFOLLOW, O_NONBLOCK, O_RDONLY].every(Number.isInteger)) {
|
|
218
|
+
throw snapshotError(
|
|
219
|
+
'ULTRA_SNAPSHOT_UNSUPPORTED',
|
|
220
|
+
relative,
|
|
221
|
+
'this host cannot enforce O_NONBLOCK and O_NOFOLLOW',
|
|
222
|
+
);
|
|
223
|
+
}
|
|
224
|
+
try {
|
|
225
|
+
return fs.openSync(absolute, O_RDONLY | O_NONBLOCK | O_NOFOLLOW);
|
|
226
|
+
} catch (error) {
|
|
227
|
+
const observed = error && error.code ? error.code : 'an unknown error';
|
|
228
|
+
if (['ELOOP', 'ENOENT', 'ENOTDIR', 'ENXIO'].includes(observed)) {
|
|
229
|
+
throw snapshotError(
|
|
230
|
+
'ULTRA_SNAPSHOT_REPLACED',
|
|
231
|
+
relative,
|
|
232
|
+
`no-follow nonblocking open observed ${observed}`,
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
throw snapshotError(
|
|
236
|
+
'ULTRA_SNAPSHOT_UNREADABLE',
|
|
237
|
+
relative,
|
|
238
|
+
`no-follow nonblocking open failed with ${observed}`,
|
|
239
|
+
);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function streamStableRepositoryFile(root, relative, consume, budget = null) {
|
|
244
|
+
const initial = walkSnapshotPath(root, relative);
|
|
245
|
+
if (budget) budget.reserve(relative, initial.final.stat.size);
|
|
246
|
+
let descriptor;
|
|
247
|
+
try {
|
|
248
|
+
descriptor = openSnapshotFile(initial.absolute, relative);
|
|
249
|
+
const opened = fs.fstatSync(descriptor, { bigint: true });
|
|
250
|
+
if (!opened.isFile() || !sameFileVersion(opened, initial.final.stat)) {
|
|
251
|
+
throw snapshotError(
|
|
252
|
+
'ULTRA_SNAPSHOT_REPLACED',
|
|
253
|
+
relative,
|
|
254
|
+
'opened descriptor does not match the initial regular-file identity',
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
verifyFreshRewalk(root, relative, initial, 'pre-read');
|
|
258
|
+
|
|
259
|
+
const buffer = Buffer.allocUnsafe(SNAPSHOT_CHUNK_BYTES);
|
|
260
|
+
let offset = 0;
|
|
261
|
+
for (;;) {
|
|
262
|
+
const remaining = MAX_SNAPSHOT_BYTES - offset;
|
|
263
|
+
const requested = Math.min(buffer.length, remaining + 1);
|
|
264
|
+
let bytesRead;
|
|
265
|
+
try {
|
|
266
|
+
bytesRead = fs.readSync(descriptor, buffer, 0, requested, offset);
|
|
267
|
+
} catch (error) {
|
|
268
|
+
throw snapshotError(
|
|
269
|
+
'ULTRA_SNAPSHOT_UNREADABLE',
|
|
270
|
+
relative,
|
|
271
|
+
`stream read failed with ${error && error.code ? error.code : 'an unknown error'}`,
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
if (bytesRead === 0) break;
|
|
275
|
+
offset += bytesRead;
|
|
276
|
+
if (offset > MAX_SNAPSHOT_BYTES) {
|
|
277
|
+
throw snapshotError(
|
|
278
|
+
'ULTRA_SNAPSHOT_TOO_LARGE',
|
|
279
|
+
relative,
|
|
280
|
+
`stream exceeded the ${MAX_SNAPSHOT_BYTES}-byte physical ceiling`,
|
|
281
|
+
);
|
|
282
|
+
}
|
|
283
|
+
consume(buffer.subarray(0, bytesRead));
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
const finished = fs.fstatSync(descriptor, { bigint: true });
|
|
287
|
+
if (!finished.isFile()
|
|
288
|
+
|| !sameFileVersion(finished, initial.final.stat)
|
|
289
|
+
|| BigInt(offset) !== finished.size) {
|
|
290
|
+
throw snapshotError(
|
|
291
|
+
'ULTRA_SNAPSHOT_REPLACED',
|
|
292
|
+
relative,
|
|
293
|
+
'file identity or byte extent changed during the streamed read',
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
verifyFreshRewalk(root, relative, initial, 'post-read');
|
|
297
|
+
return initial;
|
|
298
|
+
} finally {
|
|
299
|
+
if (descriptor !== undefined) fs.closeSync(descriptor);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
function resourceError(relative, nextFiles, nextBytes) {
|
|
304
|
+
return new Error(
|
|
305
|
+
`ULTRA_SNAPSHOT_RESOURCE_LIMIT: cannot snapshot ${JSON.stringify(relative)}: aggregate `
|
|
306
|
+
+ `product observation would reach ${nextFiles} files and ${nextBytes} bytes, above the `
|
|
307
|
+
+ `${MAX_OBSERVATION_FILES}-file or ${MAX_OBSERVATION_BYTES}-byte physical ceiling. `
|
|
308
|
+
+ 'Reduce or split the included physical product observation, then retry worktree_digest; '
|
|
309
|
+
+ 'this ceiling is not a semantic quality verdict.',
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function observationBudget() {
|
|
314
|
+
let files = 0;
|
|
315
|
+
let bytes = 0;
|
|
316
|
+
return {
|
|
317
|
+
reserve(relative, size) {
|
|
318
|
+
const nextFiles = files + 1;
|
|
319
|
+
const nextBytes = bytes + Number(size);
|
|
320
|
+
if (nextFiles > MAX_OBSERVATION_FILES || nextBytes > MAX_OBSERVATION_BYTES) {
|
|
321
|
+
throw resourceError(relative, nextFiles, nextBytes);
|
|
322
|
+
}
|
|
323
|
+
files = nextFiles;
|
|
324
|
+
bytes = nextBytes;
|
|
325
|
+
},
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function candidateExists(file) {
|
|
330
|
+
try {
|
|
331
|
+
fs.lstatSync(file);
|
|
332
|
+
return true;
|
|
333
|
+
} catch (error) {
|
|
334
|
+
if (error && (error.code === 'ENOENT' || error.code === 'ENOTDIR')) return false;
|
|
335
|
+
throw error;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
function intentSnapshot(root, changeId) {
|
|
340
|
+
if (!changeId) return { change_id: null, intent_digest: null };
|
|
341
|
+
const matches = ['active', 'archive', 'abandoned']
|
|
342
|
+
.map((state) => path.join(root, '.ultra', 'changes', state, changeId, 'intent.md'))
|
|
343
|
+
.filter(candidateExists);
|
|
344
|
+
if (matches.length !== 1) {
|
|
345
|
+
throw new Error(`expected exactly one intent.md for Change ${changeId}; found ${matches.length}`);
|
|
346
|
+
}
|
|
347
|
+
const intentHash = crypto.createHash('sha256');
|
|
348
|
+
const relative = path.relative(root, matches[0]).split(path.sep).join('/');
|
|
349
|
+
const snapshot = streamStableRepositoryFile(root, relative, (chunk) => intentHash.update(chunk));
|
|
350
|
+
return {
|
|
351
|
+
change_id: changeId,
|
|
352
|
+
intent_digest: intentHash.digest('hex'),
|
|
353
|
+
relative,
|
|
354
|
+
identity: snapshotIdentity(snapshot),
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function snapshotIdentity(snapshot) {
|
|
359
|
+
const statIdentity = (stat) => [
|
|
360
|
+
stat.dev, stat.ino, stat.mode, stat.size, stat.mtimeNs, stat.ctimeNs,
|
|
361
|
+
].map((value) => value.toString()).join(':');
|
|
362
|
+
return [
|
|
363
|
+
...snapshot.parents.map((entry) => statIdentity(entry.stat)),
|
|
364
|
+
statIdentity(snapshot.final.stat),
|
|
365
|
+
].join('|');
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
function excluded(file) {
|
|
369
|
+
return file === '.ultra/test-report.json'
|
|
370
|
+
|| /^\.ultra\/evidence(?:\/|$)/.test(file)
|
|
371
|
+
|| /^\.ultra\/(?:reviews|\.runtime|progress)(?:\/|$)/.test(file)
|
|
372
|
+
|| /^\.ultra\/changes\/(?:active|archive|abandoned)(?:\/|$)/.test(file);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function changedDuringObservation(observation) {
|
|
376
|
+
return new Error(
|
|
377
|
+
`ULTRA_SNAPSHOT_CHANGED_DURING_OBSERVATION: ${observation}. `
|
|
378
|
+
+ 'Finish or restore the concurrent repository change, then retry worktree_digest once; '
|
|
379
|
+
+ 'no digest was accepted.',
|
|
380
|
+
);
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function splitNul(buffer, label) {
|
|
384
|
+
if (buffer.length === 0) return [];
|
|
385
|
+
if (buffer[buffer.length - 1] !== 0) {
|
|
386
|
+
throw new Error(
|
|
387
|
+
`ULTRA_SNAPSHOT_GIT_FAILED: ${label} was not NUL terminated. `
|
|
388
|
+
+ 'Repair the Git observation, then retry worktree_digest.',
|
|
389
|
+
);
|
|
390
|
+
}
|
|
391
|
+
const values = [];
|
|
392
|
+
let start = 0;
|
|
393
|
+
for (let index = 0; index < buffer.length; index += 1) {
|
|
394
|
+
if (buffer[index] !== 0) continue;
|
|
395
|
+
values.push(buffer.subarray(start, index));
|
|
396
|
+
start = index + 1;
|
|
397
|
+
}
|
|
398
|
+
return values;
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
function decodeGitPath(bytes, label) {
|
|
402
|
+
const relative = bytes.toString('utf8');
|
|
403
|
+
if (!Buffer.from(relative, 'utf8').equals(bytes)) {
|
|
404
|
+
throw snapshotError(
|
|
405
|
+
'ULTRA_SNAPSHOT_PATH_ENCODING',
|
|
406
|
+
label,
|
|
407
|
+
'Git returned a path that is not valid UTF-8',
|
|
408
|
+
);
|
|
409
|
+
}
|
|
410
|
+
return relative;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
function trackedManifest(root, head) {
|
|
414
|
+
const raw = git(root, [
|
|
415
|
+
'diff', '--raw', '-z', '--no-renames', '--abbrev=64', head, ...PRODUCT_PATHSPEC,
|
|
30
416
|
], 'buffer');
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
417
|
+
const fields = splitNul(raw, 'tracked manifest');
|
|
418
|
+
if (fields.length % 2 !== 0) {
|
|
419
|
+
throw new Error(
|
|
420
|
+
'ULTRA_SNAPSHOT_GIT_FAILED: tracked manifest has an incomplete raw record. '
|
|
421
|
+
+ 'Repair the Git observation, then retry worktree_digest.',
|
|
422
|
+
);
|
|
423
|
+
}
|
|
424
|
+
const files = [];
|
|
425
|
+
for (let index = 0; index < fields.length; index += 2) {
|
|
426
|
+
const header = fields[index].toString('ascii');
|
|
427
|
+
const match = header.match(
|
|
428
|
+
/^:([0-7]{6}) ([0-7]{6}) ([0-9a-f]+) ([0-9a-f]+) ([A-Z])(?:[0-9]+)?$/u,
|
|
429
|
+
);
|
|
430
|
+
if (!match) {
|
|
431
|
+
throw new Error(
|
|
432
|
+
`ULTRA_SNAPSHOT_GIT_FAILED: tracked manifest record ${JSON.stringify(header)} is invalid. `
|
|
433
|
+
+ 'Repair the Git observation, then retry worktree_digest.',
|
|
434
|
+
);
|
|
435
|
+
}
|
|
436
|
+
const relative = decodeGitPath(fields[index + 1], 'tracked manifest path');
|
|
437
|
+
files.push({
|
|
438
|
+
path: relative,
|
|
439
|
+
status: match[5],
|
|
440
|
+
present: match[5] !== 'D',
|
|
441
|
+
old_mode: match[1],
|
|
442
|
+
new_mode: match[2],
|
|
443
|
+
});
|
|
444
|
+
}
|
|
445
|
+
return { raw, files };
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
function untrackedManifest(root) {
|
|
449
|
+
const raw = git(root, ['ls-files', '--others', '--exclude-standard', '-z'], 'buffer');
|
|
450
|
+
const entries = splitNul(raw, 'untracked manifest')
|
|
451
|
+
.map((bytes) => ({ bytes, path: decodeGitPath(bytes, 'untracked manifest path') }))
|
|
452
|
+
.filter((entry) => !excluded(entry.path))
|
|
453
|
+
.sort((left, right) => Buffer.compare(left.bytes, right.bytes));
|
|
454
|
+
return {
|
|
455
|
+
files: entries.map((entry) => entry.path),
|
|
456
|
+
raw: Buffer.concat(entries.flatMap((entry) => [entry.bytes, Buffer.from([0])])),
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
function exactDiff(root, head) {
|
|
461
|
+
return git(root, [
|
|
462
|
+
'diff', '--binary', '--no-ext-diff', head, ...PRODUCT_PATHSPEC,
|
|
463
|
+
], 'buffer');
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
function verifyObservedPaths(root, records) {
|
|
467
|
+
for (const record of records) {
|
|
468
|
+
try {
|
|
469
|
+
verifyFreshRewalk(root, record.relative, record.snapshot, 'final');
|
|
470
|
+
} catch (error) {
|
|
471
|
+
throw changedDuringObservation(
|
|
472
|
+
`included path ${JSON.stringify(record.relative)} changed after its stable read (${error.message})`,
|
|
473
|
+
);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
function sameIntent(left, right) {
|
|
479
|
+
return left.change_id === right.change_id
|
|
480
|
+
&& left.intent_digest === right.intent_digest
|
|
481
|
+
&& left.relative === right.relative
|
|
482
|
+
&& left.identity === right.identity;
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
function verifyExpectedObservation(root, expected) {
|
|
486
|
+
const observedHead = git(root, ['rev-parse', 'HEAD']).trim();
|
|
487
|
+
const observedTracked = trackedManifest(root, expected.head);
|
|
488
|
+
const observedUntracked = untrackedManifest(root);
|
|
489
|
+
const observedDiff = exactDiff(root, expected.head);
|
|
490
|
+
if (observedHead !== expected.head
|
|
491
|
+
|| !observedTracked.raw.equals(expected.tracked.raw)
|
|
492
|
+
|| !observedUntracked.raw.equals(expected.untracked.raw)
|
|
493
|
+
|| !observedDiff.equals(expected.diff)) {
|
|
494
|
+
throw changedDuringObservation(
|
|
495
|
+
'HEAD, the exact tracked manifest or diff, or the untracked manifest changed during capture',
|
|
496
|
+
);
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
const observedIntent = intentSnapshot(root, expected.intent.change_id);
|
|
500
|
+
if (!sameIntent(expected.intent, observedIntent)) {
|
|
501
|
+
throw changedDuringObservation('the Change intent identity or bytes changed during capture');
|
|
502
|
+
}
|
|
503
|
+
verifyObservedPaths(root, expected.records);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
function verifyClosingObservation(root, expected) {
|
|
507
|
+
verifyExpectedObservation(root, expected);
|
|
508
|
+
verifyExpectedObservation(root, expected);
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
function main(options) {
|
|
512
|
+
const root = fs.realpathSync(git(options.project, ['rev-parse', '--show-toplevel']).trim());
|
|
513
|
+
const head = git(root, ['rev-parse', 'HEAD']).trim();
|
|
514
|
+
const tracked = trackedManifest(root, head);
|
|
515
|
+
const untracked = untrackedManifest(root);
|
|
516
|
+
const intent = intentSnapshot(root, options.changeId);
|
|
517
|
+
const budget = observationBudget();
|
|
518
|
+
const records = [];
|
|
519
|
+
|
|
520
|
+
for (const file of tracked.files) {
|
|
521
|
+
if (!file.present) {
|
|
522
|
+
budget.reserve(file.path, 0n);
|
|
523
|
+
continue;
|
|
524
|
+
}
|
|
525
|
+
const snapshot = streamStableRepositoryFile(root, file.path, () => {}, budget);
|
|
526
|
+
records.push({ relative: file.path, snapshot });
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
const untrackedBytes = [];
|
|
530
|
+
for (const file of untracked.files) {
|
|
531
|
+
const chunks = [];
|
|
532
|
+
const snapshot = streamStableRepositoryFile(
|
|
533
|
+
root,
|
|
534
|
+
file,
|
|
535
|
+
(chunk) => chunks.push(Buffer.from(chunk)),
|
|
536
|
+
budget,
|
|
537
|
+
);
|
|
538
|
+
records.push({ relative: file, snapshot });
|
|
539
|
+
untrackedBytes.push(chunks);
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
const diff = exactDiff(root, head);
|
|
543
|
+
const closingObservation = { diff, head, intent, records, tracked, untracked };
|
|
544
|
+
verifyClosingObservation(root, closingObservation);
|
|
545
|
+
|
|
35
546
|
const hash = crypto.createHash('sha256');
|
|
36
547
|
hash.update('ultra-worktree-digest-v1\0').update(head).update('\0').update(diff);
|
|
37
|
-
for (
|
|
38
|
-
hash.update(
|
|
548
|
+
for (let index = 0; index < untracked.files.length; index += 1) {
|
|
549
|
+
hash.update(untracked.files[index]).update('\0');
|
|
550
|
+
for (const chunk of untrackedBytes[index]) hash.update(chunk);
|
|
551
|
+
hash.update('\0');
|
|
39
552
|
}
|
|
40
553
|
return {
|
|
41
554
|
$schema: 'ultra-worktree-digest-v1',
|
|
555
|
+
change_id: intent.change_id,
|
|
556
|
+
intent_digest: intent.intent_digest,
|
|
42
557
|
head,
|
|
43
|
-
dirty: diff.length > 0 || untracked.length > 0,
|
|
558
|
+
dirty: diff.length > 0 || untracked.files.length > 0,
|
|
44
559
|
diff_digest: hash.digest('hex'),
|
|
45
|
-
untracked_files: untracked,
|
|
560
|
+
untracked_files: untracked.files,
|
|
46
561
|
};
|
|
47
562
|
}
|
|
48
563
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
564
|
+
if (require.main === module) {
|
|
565
|
+
try {
|
|
566
|
+
process.stdout.write(`${JSON.stringify(main(optionsFromArgs(process.argv.slice(2))), null, 2)}\n`);
|
|
567
|
+
} catch (error) {
|
|
568
|
+
process.stderr.write(`${error.message}\n`);
|
|
569
|
+
process.exitCode = 1;
|
|
570
|
+
}
|
|
54
571
|
}
|
|
572
|
+
|
|
573
|
+
// The product-subject pathspec and the stable file-snapshot primitive are the
|
|
574
|
+
// single bounded mechanical definitions shared with the primary-transfer
|
|
575
|
+
// validator, so receipt reads and digest subject bytes can never drift.
|
|
576
|
+
module.exports = { PRODUCT_PATHSPEC, streamStableRepositoryFile };
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ultra-think
|
|
3
|
-
description: Stress-test one consequential product, architecture, recovery, or scope decision and preserve the accepted result when it must outlive the session. Use when another skill
|
|
3
|
+
description: Stress-test one consequential product, architecture, recovery, or scope decision and preserve the accepted result when it must outlive the session. Use when another skill has one evidence-backed trade-off whose answer could materially change accepted work.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Turn one consequential uncertainty into an evidence-backed decision
|
|
7
7
|
|
|
8
|
-
Thinking sharpens
|
|
8
|
+
Thinking sharpens one consequential decision; it does not map a research frontier or
|
|
9
|
+
perform the implementation that follows.
|
|
9
10
|
Persist only decisions that are hard to reverse, look surprising without context, and
|
|
10
11
|
arose from a real trade-off. All three criteria must hold.
|
|
11
12
|
|
|
12
13
|
## Before you start
|
|
13
14
|
|
|
14
|
-
1.
|
|
15
|
+
1. Resolve at most one active `change_id`, read `.ultra/tasks.json`, and if the decision
|
|
16
|
+
is task-scoped read the matching current task's `context_file` and `## Resume Note`.
|
|
15
17
|
2. Read `CONTEXT.md`, relevant `.ultra/decisions/`, the active Change and its evidence.
|
|
16
18
|
3. State the one decision and the assumptions capable of changing its answer.
|
|
17
19
|
|
|
@@ -34,13 +36,6 @@ arose from a real trade-off. All three criteria must hold.
|
|
|
34
36
|
Give the owner one recommendation with the decisive evidence and what changes under
|
|
35
37
|
each viable answer. Reuse an answer already explicit in the request.
|
|
36
38
|
|
|
37
|
-
## Use decision tickets for fog of war
|
|
38
|
-
|
|
39
|
-
When the work does not fit one session *and* the path itself remains unclear, map one
|
|
40
|
-
question instead of manufacturing implementation tasks. Write a decision ticket with
|
|
41
|
-
`status: open`; resolve one at a time until no unresolved ticket prevents planning.
|
|
42
|
-
Each answer should make the remaining fog of war smaller.
|
|
43
|
-
|
|
44
39
|
## Write durable decisions
|
|
45
40
|
|
|
46
41
|
Use `.ultra/decisions/<id>.md`: question, status, options and real trade-offs, accepted
|
|
@@ -16,7 +16,8 @@ every write.
|
|
|
16
16
|
|
|
17
17
|
## Interaction sequence
|
|
18
18
|
|
|
19
|
-
1. Read `.ultra/north-star.md`,
|
|
19
|
+
1. Read `.ultra/north-star.md`, resolve at most one active `change_id`, then read only
|
|
20
|
+
matching `.ultra/tasks.json` rows and the current task context, plus relevant
|
|
20
21
|
specifications, Changes, decisions, and evidence.
|
|
21
22
|
2. Inspect source, runtime, tests, and primary documentation for observable facts.
|
|
22
23
|
3. Reuse an explicit choice already present in the current request or an accepted
|