@nurix/etna 0.18.24 → 0.19.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/bin/etna.js CHANGED
@@ -92,6 +92,17 @@ function backupIfExists(path) {
92
92
  return backup;
93
93
  }
94
94
 
95
+ // Copy a directory to <path>.bak.<timestamp>, leaving the original in place. Returns the
96
+ // backup path, or null. Used for .claude/, which is refreshed in place (not overwritten
97
+ // wholesale), so the live tree must survive for the in-place update — snapshot, don't move.
98
+ function snapshotDirIfExists(path) {
99
+ if (!existsSync(path)) return null;
100
+ const ts = new Date().toISOString().replace(/[:.]/g, '-');
101
+ const backup = `${path}.bak.${ts}`;
102
+ cpSync(path, backup, { recursive: true });
103
+ return backup;
104
+ }
105
+
95
106
  function readJson(path) {
96
107
  if (!existsSync(path)) return {};
97
108
  try {
@@ -349,6 +360,26 @@ async function installHarness(harnessName, harnesses) {
349
360
  cpSync(bundledClaudeMd, claudeMdDest, { force: true });
350
361
  installed.push('CLAUDE.md → ./');
351
362
 
363
+ // Same safety net for the .claude/ tree, mirroring the CLAUDE.md rule above. The tree is
364
+ // refreshed in place — owned files overwritten, orphaned owned components pruned — so a
365
+ // user's edits to owned files and any pruned component are the loss surface. A git repo
366
+ // recovers them from history, so we skip the backup; without git there's no net, so we
367
+ // snapshot the whole tree first and tell the user. (Snapshot, not move: the live tree has
368
+ // to stay for the in-place refresh below.)
369
+ const claudeDir = join(targetDir, '.claude');
370
+ if (existsSync(claudeDir)) {
371
+ if (projectHasGit) {
372
+ notices.push('Refreshed existing .claude/ in place (tracked by git — `git checkout .claude` to restore).');
373
+ } else {
374
+ const claudeDirBackup = snapshotDirIfExists(claudeDir);
375
+ if (claudeDirBackup) {
376
+ warnings.push(
377
+ `No .git here, so no version-control safety net — snapshotted existing .claude/ → ${claudeDirBackup}`,
378
+ );
379
+ }
380
+ }
381
+ }
382
+
352
383
  // What a prior install recorded as harness-owned — read before we overwrite the marker,
353
384
  // so we can prune anything this bundle has since dropped.
354
385
  const priorOwned = readInstalledOwned(targetDir);
@@ -1,5 +1,5 @@
1
1
  {
2
- "fingerprint": "237ce7f5fd89",
2
+ "fingerprint": "b97962f1b980",
3
3
  "harnesses": {
4
4
  "code": {
5
5
  "plugin": "code",
@@ -129,6 +129,3 @@ Everything above is runtime-neutral. This section is the only place runtime- or
129
129
 
130
130
  - **Claude Code**: sub-agent dispatch is the Agent tool; sub-agents cannot run skills, spawn sub-agents, or reliably hold the browser connection (the "can't hold the browser connection" condition the Browser Automation guardrail refers to) — browser work is Chrome CDP ("Claude in Chrome"), main session only. The user-level memory store is `~/.claude/` (auto-memory under `~/.claude/projects/...`). The ownership index and skill/agent descriptions are injected at session start; skills are invoked as slash commands (e.g. `/brainstorm start`). If pinning dispatch tiers: strong tier (opus-class) for judgment-heavy work, fast tier (sonnet-class) for mechanical fan-out — tier names go stale, re-check on model releases.
131
131
  - **Runtimes without native component support** (AGENTS.md readers, etc.): read `.claude/agents/<name>.md` and each skill's `.claude/skills/<name>/SKILL.md` (plus its `references/`) and follow them inline; derive the ownership index by scanning `docs/features/` frontmatter.
132
-
133
- <!-- publish-trigger: removed in the immediately-following commit -->
134
-
@@ -7,5 +7,5 @@
7
7
  ".prettierignore",
8
8
  ".vscode/settings.json"
9
9
  ],
10
- "digest": "2c5fccb04e52"
10
+ "digest": "19916676801e"
11
11
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nurix/etna",
3
- "version": "0.18.24",
3
+ "version": "0.19.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": {