@nurix/etna 0.20.26 → 0.20.28
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/README.md +15 -14
- package/bin/etna.js +61 -19
- package/data/harness-index.json +1 -1
- package/data/harnesses/code/codex/agents/bookkeeper.toml +1 -1
- package/data/harnesses/code/harness.json +6 -2
- package/data/harnesses/code/hooks/awareness.mjs +50 -2
- package/data/harnesses/code/hooks/hooks.json +1 -1
- package/data/harnesses/code/hooks/lib/backlog-detector.mjs +82 -0
- package/data/harnesses/code/hooks/lib/records-door.mjs +54 -0
- package/data/harnesses/code/hooks/mount.mjs +470 -0
- package/data/harnesses/code/skills/documentation/SKILL.md +6 -6
- package/data/harnesses/code/skills/documentation/references/examples.md +29 -25
- package/data/harnesses/code/skills/documentation/references/style-guide.md +211 -335
- package/data/harnesses/code/skills/documentation/references/untemplated.md +2 -1
- package/data/harnesses/code/skills/documentation/scripts/doc-lint.mjs +33 -17
- package/data/harnesses/code/skills/documentation/templates/doctrine.md +15 -16
- package/data/harnesses/code/skills/documentation/templates/feature.md +53 -17
- package/data/harnesses/code/skills/documentation/templates/handover.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/package.md +38 -15
- package/data/harnesses/code/skills/documentation/templates/root-readme.md +16 -16
- package/data/harnesses/code/skills/documentation/templates/setup.md +1 -1
- package/data/harnesses/code/skills/documentation/templates/system.md +37 -15
- package/data/harnesses/delivery/harness.json +6 -2
- package/data/harnesses/delivery/skills/documentation/SKILL.md +6 -6
- package/data/harnesses/delivery/skills/documentation/references/examples.md +29 -25
- package/data/harnesses/delivery/skills/documentation/references/style-guide.md +211 -335
- package/data/harnesses/delivery/skills/documentation/references/untemplated.md +2 -1
- package/data/harnesses/delivery/skills/documentation/scripts/doc-lint.mjs +33 -17
- package/data/harnesses/delivery/skills/documentation/templates/doctrine.md +15 -16
- package/data/harnesses/delivery/skills/documentation/templates/feature.md +53 -17
- package/data/harnesses/delivery/skills/documentation/templates/handover.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/package.md +38 -15
- package/data/harnesses/delivery/skills/documentation/templates/root-readme.md +16 -16
- package/data/harnesses/delivery/skills/documentation/templates/setup.md +1 -1
- package/data/harnesses/delivery/skills/documentation/templates/system.md +37 -15
- package/data/harnesses/discover/harness.json +4 -0
- package/data/harnesses/discussion/harness.json +4 -0
- package/data/harnesses/etna/harness.json +6 -2
- package/data/harnesses/etna/skills/documentation/SKILL.md +6 -6
- package/data/harnesses/etna/skills/documentation/references/examples.md +29 -25
- package/data/harnesses/etna/skills/documentation/references/style-guide.md +211 -335
- package/data/harnesses/etna/skills/documentation/references/untemplated.md +2 -1
- package/data/harnesses/etna/skills/documentation/scripts/doc-lint.mjs +33 -17
- package/data/harnesses/etna/skills/documentation/templates/doctrine.md +15 -16
- package/data/harnesses/etna/skills/documentation/templates/feature.md +53 -17
- package/data/harnesses/etna/skills/documentation/templates/handover.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/package.md +38 -15
- package/data/harnesses/etna/skills/documentation/templates/root-readme.md +16 -16
- package/data/harnesses/etna/skills/documentation/templates/setup.md +1 -1
- package/data/harnesses/etna/skills/documentation/templates/system.md +37 -15
- package/data/harnesses/hr/harness.json +4 -0
- package/data/harnesses/kb-agi/harness.json +4 -0
- package/lib/install/materialize.mjs +51 -23
- package/lib/install/mount.mjs +448 -0
- package/lib/install/plan.mjs +24 -29
- package/package.json +6 -3
package/lib/install/plan.mjs
CHANGED
|
@@ -21,11 +21,13 @@
|
|
|
21
21
|
// project's living copy, never refreshed and never pruned.
|
|
22
22
|
// merge — folded into whatever the project already has, key by key. Only `.claude/settings.json`,
|
|
23
23
|
// which carries the user's own hooks and permissions beside the harness's.
|
|
24
|
+
// mount — the gitignored harness (`isMountedPath`), written here and at session start by `mount.mjs`.
|
|
24
25
|
|
|
25
26
|
import { existsSync, readdirSync, readFileSync, statSync } from 'node:fs';
|
|
26
27
|
import { join, relative, sep } from 'node:path';
|
|
27
28
|
import { buildCodexAdapter } from '../codex/agents-md.mjs';
|
|
28
29
|
import { toCodexCommand } from '../codex/hooks.mjs';
|
|
30
|
+
import { isMountedPath, hasWorkerConfig, DEFAULT_ORIGIN } from './mount.mjs';
|
|
29
31
|
|
|
30
32
|
// Subfolders bundled inside each harness payload that map 1:1 onto <project>/.claude/<name>/.
|
|
31
33
|
// Order matches Claude Code's own folder layout. hooks/ carries the hook scripts + lib/ (and
|
|
@@ -166,30 +168,7 @@ function codexHooks(bundleDir) {
|
|
|
166
168
|
const CAPABILITY_RULES = { 'cloudflare.md': targetHasWorkerConfig };
|
|
167
169
|
|
|
168
170
|
function targetHasWorkerConfig(targetDir) {
|
|
169
|
-
|
|
170
|
-
if (names.some((n) => existsSync(join(targetDir, n)))) return true;
|
|
171
|
-
let entries = [];
|
|
172
|
-
try {
|
|
173
|
-
entries = readdirSync(targetDir, { withFileTypes: true });
|
|
174
|
-
} catch {
|
|
175
|
-
return false;
|
|
176
|
-
}
|
|
177
|
-
for (const e of entries) {
|
|
178
|
-
if (!e.isDirectory() || e.name === 'node_modules' || e.name.startsWith('.')) continue;
|
|
179
|
-
if (names.some((n) => existsSync(join(targetDir, e.name, n)))) return true;
|
|
180
|
-
// one more level: packages/*/wrangler.jsonc — the common monorepo shape
|
|
181
|
-
let sub = [];
|
|
182
|
-
try {
|
|
183
|
-
sub = readdirSync(join(targetDir, e.name), { withFileTypes: true });
|
|
184
|
-
} catch {
|
|
185
|
-
continue;
|
|
186
|
-
}
|
|
187
|
-
for (const s of sub) {
|
|
188
|
-
if (!s.isDirectory() || s.name === 'node_modules' || s.name.startsWith('.')) continue;
|
|
189
|
-
if (names.some((n) => existsSync(join(targetDir, e.name, s.name, n)))) return true;
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
return false;
|
|
171
|
+
return hasWorkerConfig(targetDir);
|
|
193
172
|
}
|
|
194
173
|
|
|
195
174
|
// A rule the target's capabilities exclude. No targetDir (payload verification, byte-identity
|
|
@@ -209,19 +188,32 @@ function ruleExcluded(sub, rel, targetDir) {
|
|
|
209
188
|
//
|
|
210
189
|
// Read from the target, never from the bundle. An absent or unreadable marker returns nothing and
|
|
211
190
|
// the manifest default stands.
|
|
191
|
+
// `mount.origin` and `mount.track` are consumer-owned the same way.
|
|
212
192
|
function consumerOwnedMarkerKeys(targetDir) {
|
|
213
193
|
if (!targetDir) return {};
|
|
214
194
|
try {
|
|
215
195
|
const prior = JSON.parse(readFileSync(join(targetDir, '.claude', 'harness.json'), 'utf8'));
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
196
|
+
const keys = {};
|
|
197
|
+
if (typeof prior.docsRoot === 'string' && prior.docsRoot.trim()) keys.docsRoot = prior.docsRoot.trim();
|
|
198
|
+
const mount = prior.mount && typeof prior.mount === 'object' ? prior.mount : {};
|
|
199
|
+
if (typeof mount.origin === 'string' && mount.origin.trim()) keys.origin = mount.origin.trim();
|
|
200
|
+
if (mount.track === 'latest' || mount.track === 'pinned') keys.track = mount.track;
|
|
201
|
+
return keys;
|
|
219
202
|
} catch (e) {
|
|
220
203
|
return {};
|
|
221
204
|
}
|
|
222
205
|
}
|
|
223
206
|
|
|
224
|
-
|
|
207
|
+
// The marker's `mount` block: the CLI's flags, else the consumer's value, else the bundle's, else the defaults.
|
|
208
|
+
function markerMount(meta, prior, override = {}) {
|
|
209
|
+
const bundled = meta.mount && typeof meta.mount === 'object' ? meta.mount : {};
|
|
210
|
+
return {
|
|
211
|
+
origin: override.origin || prior.origin || bundled.origin || DEFAULT_ORIGIN,
|
|
212
|
+
track: override.track || prior.track || bundled.track || 'latest',
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
export function planHarnessFiles(bundleDir, targetDir = null, options = {}) {
|
|
225
217
|
const claudeMdPath = join(bundleDir, 'CLAUDE.md');
|
|
226
218
|
if (!existsSync(claudeMdPath)) {
|
|
227
219
|
throw new Error(`Bundled CLAUDE.md missing at ${claudeMdPath}. Rebuild package data.`);
|
|
@@ -300,9 +292,11 @@ export function planHarnessFiles(bundleDir, targetDir = null) {
|
|
|
300
292
|
const markerPath = join(bundleDir, 'harness.json');
|
|
301
293
|
const meta = existsSync(markerPath) ? JSON.parse(readFileSync(markerPath, 'utf8')) : {};
|
|
302
294
|
if (existsSync(markerPath)) {
|
|
295
|
+
const { origin, track, ...prior } = consumerOwnedMarkerKeys(targetDir);
|
|
296
|
+
const mount = markerMount(meta, { origin, track }, options.mount);
|
|
303
297
|
files.push({
|
|
304
298
|
path: '.claude/harness.json',
|
|
305
|
-
content: asJson({ ...meta, ...
|
|
299
|
+
content: asJson({ ...meta, ...prior, mount, owned }),
|
|
306
300
|
policy: 'own',
|
|
307
301
|
});
|
|
308
302
|
}
|
|
@@ -318,6 +312,7 @@ export function planHarnessFiles(bundleDir, targetDir = null) {
|
|
|
318
312
|
// Sorted so the plan is byte-stable across machines — readdir order is not guaranteed, and an
|
|
319
313
|
// unstable order would make two identical builds look different to anything comparing them.
|
|
320
314
|
files.sort((a, b) => (a.path < b.path ? -1 : a.path > b.path ? 1 : 0));
|
|
315
|
+
for (const file of files) if (file.policy === 'own' && isMountedPath(file.path)) file.policy = 'mount';
|
|
321
316
|
|
|
322
317
|
const seen = new Set();
|
|
323
318
|
for (const file of files) {
|
package/package.json
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nurix/etna",
|
|
3
|
-
"version": "0.20.
|
|
4
|
-
"description": "Bootstrap a project with a Nurix harness —
|
|
3
|
+
"version": "0.20.28",
|
|
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": {
|
|
7
7
|
"etna": "bin/etna.js"
|
|
8
8
|
},
|
|
9
|
+
"exports": {
|
|
10
|
+
"./mount": "./lib/install/mount.mjs"
|
|
11
|
+
},
|
|
9
12
|
"dependencies": {
|
|
10
13
|
"@clack/prompts": "^0.11.0"
|
|
11
14
|
},
|
|
@@ -43,5 +46,5 @@
|
|
|
43
46
|
"agent",
|
|
44
47
|
"plugin"
|
|
45
48
|
],
|
|
46
|
-
"etnaFingerprint": "
|
|
49
|
+
"etnaFingerprint": "47047f5258d8"
|
|
47
50
|
}
|