@nurix/etna 0.20.30 → 0.20.31
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/data/harness-index.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"harness": "code",
|
|
3
3
|
"name": "code",
|
|
4
|
-
"version": "3.20.
|
|
4
|
+
"version": "3.20.2",
|
|
5
5
|
"files": [
|
|
6
6
|
".prettierignore",
|
|
7
7
|
".prettierrc.json",
|
|
@@ -29,5 +29,5 @@
|
|
|
29
29
|
"origin": "https://cdn.nustack.io",
|
|
30
30
|
"track": "latest"
|
|
31
31
|
},
|
|
32
|
-
"digest": "
|
|
32
|
+
"digest": "535a7aa34dfe"
|
|
33
33
|
}
|
|
@@ -206,7 +206,7 @@ function removeEmptyParents(projectDir, rel) {
|
|
|
206
206
|
}
|
|
207
207
|
}
|
|
208
208
|
|
|
209
|
-
//
|
|
209
|
+
// Fetches the manifest's mounted files that differ on disk, writes them deepest path first, then deletes owned names the manifest omits.
|
|
210
210
|
async function mountFromManifest({ projectDir, manifest, origin, cacheDir, fetchImpl, timeoutMs, priorOwned }) {
|
|
211
211
|
const all = mountedEntries(manifest);
|
|
212
212
|
const entries = admittedEntries(projectDir, all);
|
|
@@ -218,14 +218,28 @@ async function mountFromManifest({ projectDir, manifest, origin, cacheDir, fetch
|
|
|
218
218
|
const dest = join(projectDir, entry.path);
|
|
219
219
|
return !(existsSync(dest) && sha256Of(readFileSync(dest)) === entry.sha256);
|
|
220
220
|
});
|
|
221
|
+
// Booby trap: every live session in the checkout runs these hooks while the mount rewrites them.
|
|
222
|
+
// Writing as each fetch lands let `hooks/compliance.mjs` arrive seconds before a new `hooks/lib/`
|
|
223
|
+
// module it imports, and every hook call in that window died with ERR_MODULE_NOT_FOUND (3.20.1
|
|
224
|
+
// rollout, 2026-10-05). Fetch everything, then write locally, imports (deeper paths) before importers.
|
|
225
|
+
const fetched = [];
|
|
221
226
|
await eachLimited(stale, async (entry) => {
|
|
222
227
|
try {
|
|
223
|
-
|
|
224
|
-
written.push(entry.path);
|
|
228
|
+
fetched.push({ entry, bytes: await readObject({ origin, entry, cacheDir, fetchImpl, timeoutMs }) });
|
|
225
229
|
} catch {
|
|
226
230
|
failed.push(entry.path);
|
|
227
231
|
}
|
|
228
232
|
});
|
|
233
|
+
const depth = (path) => path.split('/').length;
|
|
234
|
+
fetched.sort((a, b) => depth(b.entry.path) - depth(a.entry.path) || a.entry.path.localeCompare(b.entry.path));
|
|
235
|
+
for (const { entry, bytes } of fetched) {
|
|
236
|
+
try {
|
|
237
|
+
writeAtomic(join(projectDir, entry.path), bytes);
|
|
238
|
+
written.push(entry.path);
|
|
239
|
+
} catch {
|
|
240
|
+
failed.push(entry.path);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
229
243
|
for (const rel of prunableFiles(projectDir, unionOwned(manifest.owned, priorOwned))) {
|
|
230
244
|
if (listed.has(rel)) continue;
|
|
231
245
|
rmSync(join(projectDir, rel), { force: true });
|
package/lib/install/mount.mjs
CHANGED
|
@@ -204,7 +204,7 @@ function removeEmptyParents(projectDir, rel) {
|
|
|
204
204
|
}
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
-
//
|
|
207
|
+
// Fetches the manifest's mounted files that differ on disk, writes them deepest path first, then deletes owned names the manifest omits.
|
|
208
208
|
async function mountFromManifest({ projectDir, manifest, origin, cacheDir, fetchImpl, timeoutMs, priorOwned }) {
|
|
209
209
|
const all = mountedEntries(manifest);
|
|
210
210
|
const entries = admittedEntries(projectDir, all);
|
|
@@ -216,14 +216,28 @@ async function mountFromManifest({ projectDir, manifest, origin, cacheDir, fetch
|
|
|
216
216
|
const dest = join(projectDir, entry.path);
|
|
217
217
|
return !(existsSync(dest) && sha256Of(readFileSync(dest)) === entry.sha256);
|
|
218
218
|
});
|
|
219
|
+
// Booby trap: every live session in the checkout runs these hooks while the mount rewrites them.
|
|
220
|
+
// Writing as each fetch lands let `hooks/compliance.mjs` arrive seconds before a new `hooks/lib/`
|
|
221
|
+
// module it imports, and every hook call in that window died with ERR_MODULE_NOT_FOUND (3.20.1
|
|
222
|
+
// rollout, 2026-10-05). Fetch everything, then write locally, imports (deeper paths) before importers.
|
|
223
|
+
const fetched = [];
|
|
219
224
|
await eachLimited(stale, async (entry) => {
|
|
220
225
|
try {
|
|
221
|
-
|
|
222
|
-
written.push(entry.path);
|
|
226
|
+
fetched.push({ entry, bytes: await readObject({ origin, entry, cacheDir, fetchImpl, timeoutMs }) });
|
|
223
227
|
} catch {
|
|
224
228
|
failed.push(entry.path);
|
|
225
229
|
}
|
|
226
230
|
});
|
|
231
|
+
const depth = (path) => path.split('/').length;
|
|
232
|
+
fetched.sort((a, b) => depth(b.entry.path) - depth(a.entry.path) || a.entry.path.localeCompare(b.entry.path));
|
|
233
|
+
for (const { entry, bytes } of fetched) {
|
|
234
|
+
try {
|
|
235
|
+
writeAtomic(join(projectDir, entry.path), bytes);
|
|
236
|
+
written.push(entry.path);
|
|
237
|
+
} catch {
|
|
238
|
+
failed.push(entry.path);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
227
241
|
for (const rel of prunableFiles(projectDir, unionOwned(manifest.owned, priorOwned))) {
|
|
228
242
|
if (listed.has(rel)) continue;
|
|
229
243
|
rmSync(join(projectDir, rel), { force: true });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nurix/etna",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.31",
|
|
4
4
|
"description": "Bootstrap a project with a Nurix harness — writes the committed contract (CLAUDE.md, AGENTS.md, .claude/harness.json, settings.json, the mount hook) and mounts the harness itself, gitignored, from a bundled payload; sessions keep it current from the CDN.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -46,5 +46,5 @@
|
|
|
46
46
|
"agent",
|
|
47
47
|
"plugin"
|
|
48
48
|
],
|
|
49
|
-
"etnaFingerprint": "
|
|
49
|
+
"etnaFingerprint": "1ced34191650"
|
|
50
50
|
}
|