@nurix/etna 0.17.1 → 0.18.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.
- package/README.md +13 -4
- package/bin/etna.js +56 -28
- package/data/harness-index.json +21 -6
- package/data/harnesses/code/agents/harness-manager.md +3 -3
- package/data/harnesses/code/harness.json +1 -1
- package/data/harnesses/code-fable/agents/harness-manager.md +3 -3
- package/data/harnesses/code-fable/harness.json +1 -1
- package/data/harnesses/hr/CLAUDE.md +1 -1
- package/data/harnesses/hr/harness.json +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,17 +6,26 @@ A second install path also exists and is fully supported: `/plugin install <plug
|
|
|
6
6
|
|
|
7
7
|
## Usage
|
|
8
8
|
|
|
9
|
-
From the root of the project you want to bootstrap:
|
|
9
|
+
From the root of the project you want to bootstrap, pick a harness from the interactive menu:
|
|
10
10
|
|
|
11
11
|
```sh
|
|
12
|
-
npx @nurix/etna
|
|
12
|
+
npx @nurix/etna
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
…or install one directly by name:
|
|
16
|
+
|
|
17
|
+
```sh
|
|
18
|
+
npx @nurix/etna --name=code
|
|
13
19
|
```
|
|
14
20
|
|
|
15
21
|
After this completes:
|
|
16
22
|
|
|
17
23
|
```
|
|
18
24
|
your-project/
|
|
19
|
-
├── CLAUDE.md ← harness policy (
|
|
25
|
+
├── CLAUDE.md ← harness policy (non-git repo: existing file → CLAUDE.md.bak.<ISO>)
|
|
26
|
+
├── .prettierrc.json ← markdown formatting (proseWrap: never)
|
|
27
|
+
├── .prettierignore
|
|
28
|
+
├── .vscode/settings.json ← editor settings (markdown formatter on save)
|
|
20
29
|
└── .claude/
|
|
21
30
|
├── skills/ ← documentation, boundary, distiller, brainstorm, workflow-mapper
|
|
22
31
|
├── agents/ ← harness-manager, spec-mode, brainstorm, maintenance, change-review, performance-review
|
|
@@ -28,7 +37,7 @@ your-project/
|
|
|
28
37
|
|
|
29
38
|
That's the entire footprint. Nothing is written outside the project. No marketplace registration, no `enabledPlugins` entry, no global cache dependency — Claude Code picks up the project-scoped agents/skills/rules on its next session start, and the hooks wire in through `.claude/settings.json`.
|
|
30
39
|
|
|
31
|
-
Re-run `npx @nurix/etna code` anytime to refresh the harness content with what the latest published package ships. Existing same-named files are overwritten; files you've added that aren't part of the harness are left alone.
|
|
40
|
+
Re-run `npx @nurix/etna --name=code` anytime to refresh the harness content with what the latest published package ships. Existing same-named files are overwritten; files you've added that aren't part of the harness are left alone. In a git repo the previous `CLAUDE.md` is overwritten in place (recover it with `git checkout CLAUDE.md`); outside a git repo it's backed up to `CLAUDE.md.bak.<ISO-timestamp>`. Because the new `harness.json` carries the installed `{version, epoch, digest}`, a re-run that's ahead of your repo's stamped `harness-version` is what the reconcile (below) detects as an upgrade.
|
|
32
41
|
|
|
33
42
|
## After install: bootstrap the harness
|
|
34
43
|
|
package/bin/etna.js
CHANGED
|
@@ -43,15 +43,16 @@ function isInteractive() {
|
|
|
43
43
|
return Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
// Boxed list of installable harnesses, for --help and
|
|
46
|
+
// Boxed list of installable harnesses (name + description), for --help and error paths.
|
|
47
47
|
function printHarnessList(harnesses) {
|
|
48
48
|
const entries = Object.entries(harnesses);
|
|
49
49
|
if (!entries.length) {
|
|
50
50
|
p.log.warn('No harnesses are bundled. Run `npm run build:data` from the package root.');
|
|
51
51
|
return;
|
|
52
52
|
}
|
|
53
|
+
const width = Math.max(...entries.map(([folder]) => folder.length));
|
|
53
54
|
const lines = entries.map(
|
|
54
|
-
([folder,
|
|
55
|
+
([folder, meta]) => `${folder.padEnd(width)}${meta?.description ? ` ${meta.description}` : ''}`,
|
|
55
56
|
);
|
|
56
57
|
p.note(lines.join('\n'), 'Available harnesses');
|
|
57
58
|
}
|
|
@@ -216,35 +217,32 @@ function mergeHooks(targetDir, bundledHooksJson) {
|
|
|
216
217
|
return added;
|
|
217
218
|
}
|
|
218
219
|
|
|
219
|
-
// Resolve the harness to install: the
|
|
220
|
-
//
|
|
221
|
-
async function resolveHarnessName(
|
|
220
|
+
// Resolve the harness to install: the --name value, or — in a TTY — an interactive pick
|
|
221
|
+
// showing each harness's description. Returns the chosen folder, or null on cancel.
|
|
222
|
+
async function resolveHarnessName(name, harnesses) {
|
|
222
223
|
const names = Object.keys(harnesses);
|
|
223
|
-
if (
|
|
224
|
-
if (!harnesses[
|
|
225
|
-
p.log.error(`Unknown harness '${
|
|
224
|
+
if (name !== null) {
|
|
225
|
+
if (!name || !harnesses[name]) {
|
|
226
|
+
p.log.error(name ? `Unknown harness '${name}'.` : 'Empty --name value.');
|
|
226
227
|
printHarnessList(harnesses);
|
|
227
|
-
p.outro('
|
|
228
|
+
p.outro('Pass --name=<harness> with one of the names above.');
|
|
228
229
|
process.exit(1);
|
|
229
230
|
}
|
|
230
|
-
return
|
|
231
|
+
return name;
|
|
231
232
|
}
|
|
232
233
|
if (!isInteractive()) {
|
|
233
|
-
p.log.error('No
|
|
234
|
+
p.log.error('No --name given, and not running in an interactive terminal.');
|
|
234
235
|
printHarnessList(harnesses);
|
|
235
|
-
p.outro('Re-run as `npx @nurix/etna
|
|
236
|
+
p.outro('Re-run as `npx @nurix/etna --name=<harness>`.');
|
|
236
237
|
process.exit(1);
|
|
237
238
|
}
|
|
238
239
|
const choice = await p.select({
|
|
239
240
|
message: 'Which harness do you want to install here?',
|
|
240
|
-
options: names.map((folder) => {
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
hint: plugin && plugin !== folder ? `plugin: ${plugin}` : undefined,
|
|
246
|
-
};
|
|
247
|
-
}),
|
|
241
|
+
options: names.map((folder) => ({
|
|
242
|
+
value: folder,
|
|
243
|
+
label: folder,
|
|
244
|
+
hint: harnesses[folder]?.description || undefined,
|
|
245
|
+
})),
|
|
248
246
|
});
|
|
249
247
|
if (p.isCancel(choice)) {
|
|
250
248
|
p.cancel('Cancelled — nothing installed.');
|
|
@@ -273,7 +271,7 @@ async function installHarness(harnessName, harnesses) {
|
|
|
273
271
|
const versionTag = harnessMeta.version ? ` v${harnessMeta.version}` : '';
|
|
274
272
|
// The underlying plugin's name — may differ from the harness name, and several
|
|
275
273
|
// harnesses may share it. Used only for legacy marketplace-entry cleanup.
|
|
276
|
-
const pluginName = harnessMeta.name || harnesses[harnessName] || harnessName;
|
|
274
|
+
const pluginName = harnessMeta.name || harnesses[harnessName]?.plugin || harnessName;
|
|
277
275
|
|
|
278
276
|
const spin = p.spinner();
|
|
279
277
|
spin.start(`Installing ${harnessName}${versionTag} into ${targetDir}`);
|
|
@@ -346,32 +344,62 @@ async function installHarness(harnessName, harnesses) {
|
|
|
346
344
|
|
|
347
345
|
p.outro(
|
|
348
346
|
`${harnessName}${versionTag} ready in ${targetDir}. ` +
|
|
349
|
-
`Re-run \`npx @nurix/etna
|
|
347
|
+
`Re-run \`npx @nurix/etna --name=${harnessName}\` anytime to refresh harness content.`,
|
|
350
348
|
);
|
|
351
349
|
}
|
|
352
350
|
|
|
351
|
+
// Parse argv. `--name=<harness>` / `--name <harness>` selects a harness; -h/--help shows
|
|
352
|
+
// help; any other bare token is the dropped positional form (a breaking change in 0.18.0).
|
|
353
|
+
function parseArgs(args) {
|
|
354
|
+
let name = null;
|
|
355
|
+
let help = false;
|
|
356
|
+
let positional = null;
|
|
357
|
+
for (let i = 0; i < args.length; i++) {
|
|
358
|
+
const a = args[i];
|
|
359
|
+
if (a === '-h' || a === '--help') help = true;
|
|
360
|
+
else if (a.startsWith('--name=')) name = a.slice('--name='.length);
|
|
361
|
+
else if (a === '--name') name = args[++i] ?? '';
|
|
362
|
+
else if (!a.startsWith('-') && positional === null) positional = a;
|
|
363
|
+
}
|
|
364
|
+
return { name, help, positional };
|
|
365
|
+
}
|
|
366
|
+
|
|
353
367
|
async function main(args) {
|
|
354
368
|
const idx = loadHarnessIndex();
|
|
355
369
|
const harnesses = idx.harnesses || {};
|
|
370
|
+
const { name, help, positional } = parseArgs(args);
|
|
356
371
|
|
|
357
|
-
if (
|
|
372
|
+
if (help) {
|
|
358
373
|
p.intro('@nurix/etna — Nurix harness installer');
|
|
359
|
-
p.log.message(
|
|
374
|
+
p.log.message(
|
|
375
|
+
'Usage:\n' +
|
|
376
|
+
' npx @nurix/etna pick a harness from the menu\n' +
|
|
377
|
+
' npx @nurix/etna --name=<harness> install that harness directly',
|
|
378
|
+
);
|
|
360
379
|
printHarnessList(harnesses);
|
|
361
|
-
p.outro('
|
|
380
|
+
p.outro('No args → interactive menu. --name=<harness> → direct install.');
|
|
362
381
|
return;
|
|
363
382
|
}
|
|
364
383
|
|
|
365
|
-
const positional = args.find((a) => !a.startsWith('-'));
|
|
366
|
-
|
|
367
384
|
p.intro('@nurix/etna — Nurix harness installer');
|
|
368
385
|
|
|
386
|
+
// Breaking change (0.18.0): the positional form `etna <harness>` was replaced by
|
|
387
|
+
// `--name=<harness>`. Fail loudly with the new syntax rather than silently misfiring.
|
|
388
|
+
if (positional && name === null) {
|
|
389
|
+
p.log.error(
|
|
390
|
+
`Positional arguments are no longer supported. Install with \`npx @nurix/etna --name=${positional}\`.`,
|
|
391
|
+
);
|
|
392
|
+
printHarnessList(harnesses);
|
|
393
|
+
p.outro('Use --name=<harness> to install, or no args to pick from the menu.');
|
|
394
|
+
process.exit(1);
|
|
395
|
+
}
|
|
396
|
+
|
|
369
397
|
const boot = p.spinner();
|
|
370
398
|
boot.start('Starting up');
|
|
371
399
|
await sleep(2000);
|
|
372
400
|
boot.stop('Ready');
|
|
373
401
|
|
|
374
|
-
const harnessName = await resolveHarnessName(
|
|
402
|
+
const harnessName = await resolveHarnessName(name, harnesses);
|
|
375
403
|
if (!harnessName) return; // user cancelled the interactive pick
|
|
376
404
|
|
|
377
405
|
await installHarness(harnessName, harnesses);
|
package/data/harness-index.json
CHANGED
|
@@ -1,10 +1,25 @@
|
|
|
1
1
|
{
|
|
2
|
-
"fingerprint": "
|
|
2
|
+
"fingerprint": "2a8b6a3ea74d",
|
|
3
3
|
"harnesses": {
|
|
4
|
-
"code":
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
"
|
|
4
|
+
"code": {
|
|
5
|
+
"plugin": "code-fable",
|
|
6
|
+
"description": "Nurix code-project harness"
|
|
7
|
+
},
|
|
8
|
+
"code-fable": {
|
|
9
|
+
"plugin": "code-fable",
|
|
10
|
+
"description": "Nurix code-project harness"
|
|
11
|
+
},
|
|
12
|
+
"discover": {
|
|
13
|
+
"plugin": "discover",
|
|
14
|
+
"description": "Product Discovery harness"
|
|
15
|
+
},
|
|
16
|
+
"hr": {
|
|
17
|
+
"plugin": "hr",
|
|
18
|
+
"description": "Hiring / AI-Steering Evaluation harness"
|
|
19
|
+
},
|
|
20
|
+
"kb-agi": {
|
|
21
|
+
"plugin": "kb-agi",
|
|
22
|
+
"description": "self-improving knowledge-base harness"
|
|
23
|
+
}
|
|
9
24
|
}
|
|
10
25
|
}
|
|
@@ -15,7 +15,7 @@ Reconcile is **declarative, not a migration ladder.** You converge to the *curre
|
|
|
15
15
|
|
|
16
16
|
## The two version layers (don't confuse them)
|
|
17
17
|
|
|
18
|
-
- The **CLI** (`npx @nurix/etna code`) refreshes the *engine* — `CLAUDE.md` + `.claude/{agents,skills,rules,scripts}/`. That is not your job; the install does it.
|
|
18
|
+
- The **CLI** (`npx @nurix/etna --name=code`) refreshes the *engine* — `CLAUDE.md` + `.claude/{agents,skills,rules,scripts}/`. That is not your job; the install does it.
|
|
19
19
|
- **You** reconcile the *repo's authored data* — the `docs/` tree — to match that engine.
|
|
20
20
|
|
|
21
21
|
The upgrade story is the two run back-to-back: install refreshes the engine → you reconcile the docs to it.
|
|
@@ -37,7 +37,7 @@ You never edit a doc for content fidelity (that is `maintenance`); `maintenance`
|
|
|
37
37
|
## Before starting
|
|
38
38
|
|
|
39
39
|
1. Verify a **root `CLAUDE.md` exists** before any reconcile. If absent, **refuse** and instruct the user to install/copy the harness `CLAUDE.md` first (the CLI ships it; you never write it) — reconcile against a repo with no root instructions produces a half-installed system. Detect-and-instruct, not a gate.
|
|
40
|
-
2. Resolve the **installed harness epoch** — read it from `.claude/harness.json`, shipped by the CLI at install. Never a number baked into this file. If `.claude/harness.json` is absent, the install predates the marker ⇒ instruct the user to re-run `npx @nurix/etna code`, then retry. The resolved epoch is the target.
|
|
40
|
+
2. Resolve the **installed harness epoch** — read it from `.claude/harness.json`, shipped by the CLI at install. Never a number baked into this file. If `.claude/harness.json` is absent, the install predates the marker ⇒ instruct the user to re-run `npx @nurix/etna --name=code`, then retry. The resolved epoch is the target.
|
|
41
41
|
3. Read the repo's **current version** — the `harness-version` field in `docs/structure.md` frontmatter. Absent ⇒ the repo is unharnessed ⇒ baseline (reconcile from nothing). Equal to installed ⇒ report and stop, **except** when re-invoked for the Step 6 module proposal: the version is already current from your first pass, so skip the stop and go straight to Step 6. (Health asked ⇒ run Health.) Behind ⇒ reconcile forward.
|
|
42
42
|
4. If `docs/memory/harness-manager.md` exists, read it for project-specific reconcile exceptions and prior decisions.
|
|
43
43
|
|
|
@@ -158,7 +158,7 @@ Confirm all mandated files exist; `structure.md` carries the current `harness-ve
|
|
|
158
158
|
Conformance, not fidelity. Report a table; fix nothing destructively without asking.
|
|
159
159
|
|
|
160
160
|
- **Version currency** — `harness-version` present in `structure.md` and equal to installed? If behind/absent → recommend Reconcile. (This is the *repo-vs-installed* gap — it self-heals once the consumer reinstalls and re-runs you. The next two checks catch what reinstall *hasn't* happened yet, or was bypassed by a hand-edit.)
|
|
161
|
-
- **Published-version currency** *(advisory, network)* — the installed `.claude/harness.json` records the kit's `version`; the published kit may have moved past it. Attempt `npm view @nurix/etna version` (the kit is a restricted package — needs npm auth + network). **Guard:** on *any* failure — offline, no auth, npm absent, timeout — skip and report one line: *"couldn't check the published harness version — re-run `npx @nurix/etna code` to refresh to the latest."* On success, compare the published version against `.claude/harness.json`'s `version`; if published is ahead, recommend re-running the CLI to pull the newer kit. Never a gate, never blocks.
|
|
161
|
+
- **Published-version currency** *(advisory, network)* — the installed `.claude/harness.json` records the kit's `version`; the published kit may have moved past it. Attempt `npm view @nurix/etna version` (the kit is a restricted package — needs npm auth + network). **Guard:** on *any* failure — offline, no auth, npm absent, timeout — skip and report one line: *"couldn't check the published harness version — re-run `npx @nurix/etna --name=code` to refresh to the latest."* On success, compare the published version against `.claude/harness.json`'s `version`; if published is ahead, recommend re-running the CLI to pull the newer kit. Never a gate, never blocks.
|
|
162
162
|
- **Kit build fingerprint (digest)** *(informational)* — `.claude/harness.json` carries a `digest`: a deterministic fingerprint of the exact kit **build** the consumer installed (`build-data` computes it over the shipped bundle). Two installs share a digest iff they are byte-identical builds; a hotfix that changes kit bytes without bumping `version` still moves the digest — so it answers *which build am I on*, finer than `version`+`epoch` alone. **Don't recompute it over `.claude/` to self-check:** the installed layout is a superset of the build (the project `CLAUDE.md` sits at the repo root, `.claude/` adds `settings.json`/`harness.json`/local rule files), so paths and file sets differ **by design** — a recompute would never match. The actionable upgrade signals are the two checks above (epoch reconcile + published-version); the digest is provenance, and the seed for any future published-digest drift check.
|
|
163
163
|
- **Scaffold completeness** — every mandated file present.
|
|
164
164
|
- **Dissolved-version residue** — any `operations/guardrails.md`, repo-wide `docs/pillars/`, `architecture/overview.md`, a persisted `docs/boundaries/` tree, or other old-shape artifact lingering.
|
|
@@ -15,7 +15,7 @@ Reconcile is **declarative, not a migration ladder.** You converge to the *curre
|
|
|
15
15
|
|
|
16
16
|
## The two version layers (don't confuse them)
|
|
17
17
|
|
|
18
|
-
- The **CLI** (`npx @nurix/etna code`) refreshes the *engine* — `CLAUDE.md` + `.claude/{agents,skills,rules,scripts}/`. That is not your job; the install does it.
|
|
18
|
+
- The **CLI** (`npx @nurix/etna --name=code`) refreshes the *engine* — `CLAUDE.md` + `.claude/{agents,skills,rules,scripts}/`. That is not your job; the install does it.
|
|
19
19
|
- **You** reconcile the *repo's authored data* — the `docs/` tree — to match that engine.
|
|
20
20
|
|
|
21
21
|
The upgrade story is the two run back-to-back: install refreshes the engine → you reconcile the docs to it.
|
|
@@ -37,7 +37,7 @@ You never edit a doc for content fidelity (that is `maintenance`); `maintenance`
|
|
|
37
37
|
## Before starting
|
|
38
38
|
|
|
39
39
|
1. Verify a **root `CLAUDE.md` exists** before any reconcile. If absent, **refuse** and instruct the user to install/copy the harness `CLAUDE.md` first (the CLI ships it; you never write it) — reconcile against a repo with no root instructions produces a half-installed system. Detect-and-instruct, not a gate.
|
|
40
|
-
2. Resolve the **installed harness epoch** — read it from `.claude/harness.json`, shipped by the CLI at install. Never a number baked into this file. If `.claude/harness.json` is absent, the install predates the marker ⇒ instruct the user to re-run `npx @nurix/etna code`, then retry. The resolved epoch is the target.
|
|
40
|
+
2. Resolve the **installed harness epoch** — read it from `.claude/harness.json`, shipped by the CLI at install. Never a number baked into this file. If `.claude/harness.json` is absent, the install predates the marker ⇒ instruct the user to re-run `npx @nurix/etna --name=code`, then retry. The resolved epoch is the target.
|
|
41
41
|
3. Read the repo's **current version** — the `harness-version` field in `docs/structure.md` frontmatter. Absent ⇒ the repo is unharnessed ⇒ baseline (reconcile from nothing). Equal to installed ⇒ report and stop, **except** when re-invoked for the Step 6 module proposal: the version is already current from your first pass, so skip the stop and go straight to Step 6. (Health asked ⇒ run Health.) Behind ⇒ reconcile forward.
|
|
42
42
|
4. If `docs/memory/harness-manager.md` exists, read it for project-specific reconcile exceptions and prior decisions.
|
|
43
43
|
|
|
@@ -158,7 +158,7 @@ Confirm all mandated files exist; `structure.md` carries the current `harness-ve
|
|
|
158
158
|
Conformance, not fidelity. Report a table; fix nothing destructively without asking.
|
|
159
159
|
|
|
160
160
|
- **Version currency** — `harness-version` present in `structure.md` and equal to installed? If behind/absent → recommend Reconcile. (This is the *repo-vs-installed* gap — it self-heals once the consumer reinstalls and re-runs you. The next two checks catch what reinstall *hasn't* happened yet, or was bypassed by a hand-edit.)
|
|
161
|
-
- **Published-version currency** *(advisory, network)* — the installed `.claude/harness.json` records the kit's `version`; the published kit may have moved past it. Attempt `npm view @nurix/etna version` (the kit is a restricted package — needs npm auth + network). **Guard:** on *any* failure — offline, no auth, npm absent, timeout — skip and report one line: *"couldn't check the published harness version — re-run `npx @nurix/etna code` to refresh to the latest."* On success, compare the published version against `.claude/harness.json`'s `version`; if published is ahead, recommend re-running the CLI to pull the newer kit. Never a gate, never blocks.
|
|
161
|
+
- **Published-version currency** *(advisory, network)* — the installed `.claude/harness.json` records the kit's `version`; the published kit may have moved past it. Attempt `npm view @nurix/etna version` (the kit is a restricted package — needs npm auth + network). **Guard:** on *any* failure — offline, no auth, npm absent, timeout — skip and report one line: *"couldn't check the published harness version — re-run `npx @nurix/etna --name=code` to refresh to the latest."* On success, compare the published version against `.claude/harness.json`'s `version`; if published is ahead, recommend re-running the CLI to pull the newer kit. Never a gate, never blocks.
|
|
162
162
|
- **Kit build fingerprint (digest)** *(informational)* — `.claude/harness.json` carries a `digest`: a deterministic fingerprint of the exact kit **build** the consumer installed (`build-data` computes it over the shipped bundle). Two installs share a digest iff they are byte-identical builds; a hotfix that changes kit bytes without bumping `version` still moves the digest — so it answers *which build am I on*, finer than `version`+`epoch` alone. **Don't recompute it over `.claude/` to self-check:** the installed layout is a superset of the build (the project `CLAUDE.md` sits at the repo root, `.claude/` adds `settings.json`/`harness.json`/local rule files), so paths and file sets differ **by design** — a recompute would never match. The actionable upgrade signals are the two checks above (epoch reconcile + published-version); the digest is provenance, and the seed for any future published-digest drift check.
|
|
163
163
|
- **Scaffold completeness** — every mandated file present.
|
|
164
164
|
- **Dissolved-version residue** — any `operations/guardrails.md`, repo-wide `docs/pillars/`, `architecture/overview.md`, a persisted `docs/boundaries/` tree, or other old-shape artifact lingering.
|
|
@@ -24,7 +24,7 @@ mistake, the redirect that pulled it off a bad path. Turn count, prompt length,
|
|
|
24
24
|
## Step 0 — first run
|
|
25
25
|
|
|
26
26
|
If the `interview-eval` skill isn't resolvable (no `.claude/skills/interview-eval/`), this project isn't set
|
|
27
|
-
up — tell the user to run `npx @nurix/etna hr` (or point you at the skill) before continuing. Confirm
|
|
27
|
+
up — tell the user to run `npx @nurix/etna --name=hr` (or point you at the skill) before continuing. Confirm
|
|
28
28
|
`python3` is on PATH; the extractor is stdlib-only and needs nothing else.
|
|
29
29
|
|
|
30
30
|
## Step 1 — intake interview
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nurix/etna",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "Bootstrap a project with a Nurix harness — copies the harness's CLAUDE.md, skills, agents, rules, and hooks directly into the project from a bundled payload (no marketplace fetch, no network).",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|