@nurix/etna 0.18.10 → 0.18.12
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 -13
- package/bin/etna.js +98 -2
- package/data/harness-index.json +9 -1
- package/data/harnesses/code/CLAUDE.md +9 -10
- package/data/harnesses/code/agents/brainstorm.md +3 -3
- package/data/harnesses/code/agents/change-review.md +4 -4
- package/data/harnesses/code/agents/maintenance.md +177 -59
- package/data/harnesses/code/agents/spec-mode.md +3 -3
- package/data/harnesses/code/harness.json +2 -2
- package/data/harnesses/code/hooks/generate-ownership-index.mjs +148 -0
- package/data/harnesses/code/hooks/hooks.json +12 -0
- package/data/harnesses/code/skills/boundary/references/boundary-taxonomy.md +3 -3
- package/data/harnesses/code/skills/brainstorm/README.md +11 -9
- package/data/harnesses/code/skills/brainstorm/SKILL.md +2 -2
- package/data/harnesses/code/skills/brainstorm/harvest.md +5 -6
- package/data/harnesses/code/skills/distiller/SKILL.md +3 -3
- package/data/harnesses/code/skills/distiller/references/docs-mode.md +7 -7
- package/data/harnesses/code/skills/documentation/SKILL.md +23 -23
- package/data/harnesses/code/skills/documentation/references/templates.md +26 -64
- package/data/harnesses/etna/.prettierignore +12 -0
- package/data/harnesses/etna/.prettierrc.json +3 -0
- package/data/harnesses/etna/.vscode/settings.json +10 -0
- package/data/harnesses/etna/CLAUDE.md +151 -0
- package/data/harnesses/etna/agents/brainstorm.md +35 -0
- package/data/harnesses/etna/agents/change-review.md +251 -0
- package/data/harnesses/etna/agents/maintenance.md +240 -0
- package/data/harnesses/etna/agents/performance-review.md +223 -0
- package/data/harnesses/etna/agents/spec-mode.md +56 -0
- package/data/harnesses/etna/harness.json +11 -0
- package/data/harnesses/etna/hooks/generate-ownership-index.mjs +148 -0
- package/data/harnesses/etna/hooks/hooks.json +39 -0
- package/data/harnesses/etna/hooks/lib/redact.mjs +35 -0
- package/data/harnesses/etna/hooks/prompt-recall.mjs +155 -0
- package/data/harnesses/etna/hooks/session-reflect.mjs +285 -0
- package/data/harnesses/etna/rules/general.md +86 -0
- package/data/harnesses/etna/rules/kb.md +13 -0
- package/data/harnesses/etna/rules/nomenclature.md +41 -0
- package/data/harnesses/etna/rules/npm-cli.md +88 -0
- package/data/harnesses/etna/skills/boundary/SKILL.md +49 -0
- package/data/harnesses/etna/skills/boundary/references/boundary-taxonomy.md +796 -0
- package/data/harnesses/etna/skills/brainstorm/README.md +138 -0
- package/data/harnesses/etna/skills/brainstorm/SKILL.md +135 -0
- package/data/harnesses/etna/skills/brainstorm/harvest.md +25 -0
- package/data/harnesses/etna/skills/brainstorm/templates/backlog.md +39 -0
- package/data/harnesses/etna/skills/brainstorm/templates/build.md +37 -0
- package/data/harnesses/etna/skills/brainstorm/templates/decisions.md +29 -0
- package/data/harnesses/etna/skills/brainstorm/templates/doctrine.md +31 -0
- package/data/harnesses/etna/skills/brainstorm/templates/domain-model.md +25 -0
- package/data/harnesses/etna/skills/brainstorm/templates/glossary.md +20 -0
- package/data/harnesses/etna/skills/brainstorm/templates/milestones.md +43 -0
- package/data/harnesses/etna/skills/brainstorm/templates/non-goals.md +17 -0
- package/data/harnesses/etna/skills/brainstorm/templates/plan-doc.md +61 -0
- package/data/harnesses/etna/skills/brainstorm/templates/questions.md +36 -0
- package/data/harnesses/etna/skills/brainstorm/templates/references.md +28 -0
- package/data/harnesses/etna/skills/brainstorm/templates/rejected.md +29 -0
- package/data/harnesses/etna/skills/brainstorm/templates/state.md +1 -0
- package/data/harnesses/etna/skills/brainstorm/templates/tech.md +23 -0
- package/data/harnesses/etna/skills/brainstorm/templates/thesis.md +21 -0
- package/data/harnesses/etna/skills/distiller/SKILL.md +90 -0
- package/data/harnesses/etna/skills/distiller/references/docs-mode.md +299 -0
- package/data/harnesses/etna/skills/distiller/references/method.md +94 -0
- package/data/harnesses/etna/skills/documentation/SKILL.md +124 -0
- package/data/harnesses/etna/skills/documentation/references/examples.md +162 -0
- package/data/harnesses/etna/skills/documentation/references/style-guide.md +308 -0
- package/data/harnesses/etna/skills/documentation/references/templates.md +853 -0
- package/data/harnesses/etna/skills/workflow-mapper/SKILL.md +451 -0
- package/data/harnesses/etna/skills/workflow-mapper/references/patterns.md +214 -0
- package/data/harnesses/hr/harness.json +1 -1
- package/data/harnesses/hr/skills/evaluator/criteria/testing.md +4 -4
- package/data/harnesses/mobile/.prettierignore +12 -0
- package/data/harnesses/mobile/.prettierrc.json +3 -0
- package/data/harnesses/mobile/.vscode/settings.json +10 -0
- package/data/harnesses/mobile/CLAUDE.md +128 -0
- package/data/harnesses/mobile/agents/brainstorm.md +35 -0
- package/data/harnesses/mobile/agents/change-review.md +251 -0
- package/data/harnesses/mobile/agents/maintenance.md +240 -0
- package/data/harnesses/mobile/agents/performance-review.md +223 -0
- package/data/harnesses/mobile/agents/spec-mode.md +56 -0
- package/data/harnesses/mobile/harness.json +11 -0
- package/data/harnesses/mobile/hooks/generate-ownership-index.mjs +148 -0
- package/data/harnesses/mobile/hooks/hooks.json +39 -0
- package/data/harnesses/mobile/hooks/lib/redact.mjs +35 -0
- package/data/harnesses/mobile/hooks/prompt-recall.mjs +155 -0
- package/data/harnesses/mobile/hooks/session-reflect.mjs +285 -0
- package/data/harnesses/mobile/rules/general.md +86 -0
- package/data/harnesses/mobile/rules/nomenclature.md +41 -0
- package/data/harnesses/mobile/rules/react-native.md +132 -0
- package/data/harnesses/mobile/rules/typescript.md +40 -0
- package/data/harnesses/mobile/skills/boundary/SKILL.md +49 -0
- package/data/harnesses/mobile/skills/boundary/references/boundary-taxonomy.md +796 -0
- package/data/harnesses/mobile/skills/brainstorm/README.md +138 -0
- package/data/harnesses/mobile/skills/brainstorm/SKILL.md +135 -0
- package/data/harnesses/mobile/skills/brainstorm/harvest.md +25 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/backlog.md +39 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/build.md +37 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/decisions.md +29 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/doctrine.md +31 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/domain-model.md +25 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/glossary.md +20 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/milestones.md +43 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/non-goals.md +17 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/plan-doc.md +61 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/questions.md +36 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/references.md +28 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/rejected.md +29 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/state.md +1 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/tech.md +23 -0
- package/data/harnesses/mobile/skills/brainstorm/templates/thesis.md +21 -0
- package/data/harnesses/mobile/skills/distiller/SKILL.md +90 -0
- package/data/harnesses/mobile/skills/distiller/references/docs-mode.md +299 -0
- package/data/harnesses/mobile/skills/distiller/references/method.md +94 -0
- package/data/harnesses/mobile/skills/documentation/SKILL.md +124 -0
- package/data/harnesses/mobile/skills/documentation/references/examples.md +162 -0
- package/data/harnesses/mobile/skills/documentation/references/style-guide.md +308 -0
- package/data/harnesses/mobile/skills/documentation/references/templates.md +853 -0
- package/data/harnesses/mobile/skills/workflow-mapper/SKILL.md +451 -0
- package/data/harnesses/mobile/skills/workflow-mapper/references/patterns.md +214 -0
- package/package.json +1 -1
- package/data/harnesses/code/agents/harness-manager.md +0 -184
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# General Standards
|
|
2
|
+
|
|
3
|
+
## Runtime Versions
|
|
4
|
+
|
|
5
|
+
- **Node.js:** 22 LTS (latest)
|
|
6
|
+
- **Package manager:** detect from lockfile (`pnpm-lock.yaml` → pnpm, `yarn.lock` → yarn, `package-lock.json` → npm). Don't hardcode one.
|
|
7
|
+
- **PostgreSQL:** 17 · **Redis:** 7.x (latest)
|
|
8
|
+
|
|
9
|
+
## Recommended Packages
|
|
10
|
+
|
|
11
|
+
No alternatives. Just use these.
|
|
12
|
+
|
|
13
|
+
| Package | Version | Use | Don't use |
|
|
14
|
+
| ------------------------ | --------- | ---------------------- | -------------------------- |
|
|
15
|
+
| react | ^19.2.3 | UI components | - |
|
|
16
|
+
| vite | ^8.0.0 | Build tool, dev server | webpack, CRA |
|
|
17
|
+
| tailwindcss | ^4.1.18 | Styling | styled-components |
|
|
18
|
+
| @vitejs/plugin-react-swc | ^4.2.2 | JSX compilation | @vitejs/plugin-react |
|
|
19
|
+
| react-router-dom | ^7.11.0 | Routing | - |
|
|
20
|
+
| @reduxjs/toolkit | ^2.11.2 | State management | zustand, jotai |
|
|
21
|
+
| react-redux | ^9.2.0 | Redux React bindings | - |
|
|
22
|
+
| axios | ^1.13.2 | HTTP requests | fetch |
|
|
23
|
+
| date-fns | ^4.1.0 | Date formatting | moment, dayjs |
|
|
24
|
+
| @dnd-kit/core | ^6.3.1 | Drag and drop | react-beautiful-dnd |
|
|
25
|
+
| motion | ^12.23.26 | Animations | react-spring |
|
|
26
|
+
| sonner | ^2.0.7 | Toast notifications | react-toastify |
|
|
27
|
+
| react-window | ^2.2.3 | List virtualization | react-virtualized |
|
|
28
|
+
| nanoid | ^5.1.6 | ID generation | uuid |
|
|
29
|
+
| express | ^5.2.1 | HTTP server | fastify, koa |
|
|
30
|
+
| drizzle-orm | latest | Database ORM | prisma, sequelize, typeorm |
|
|
31
|
+
| drizzle-kit | latest | Schema tooling | - |
|
|
32
|
+
| zod | ^4.2.1 | Schema validation | yup, joi |
|
|
33
|
+
| jose | ^6.1.3 | JWT handling | jsonwebtoken |
|
|
34
|
+
| microdiff | ^1.5.0 | JSON object diffing | deep-diff, just-diff |
|
|
35
|
+
| react18-json-view | ^0.2.9 | JSON tree view | react-json-view |
|
|
36
|
+
| @tiptap/react | ^3.11.1 | Rich text editor | slate, quill, draft-js |
|
|
37
|
+
| shiki | ^3.22.0 | Syntax highlighting | prism, highlight.js |
|
|
38
|
+
| lucide-react | ^0.562.0 | Icons | react-icons, heroicons |
|
|
39
|
+
| @pdfme/generator | ^5.5.8 | PDF generation | jspdf, pdfkit |
|
|
40
|
+
| cmdk | ^1.1.1 | Command palette | kbar, ninja-keys |
|
|
41
|
+
| @monaco-editor/react | ^4.7.0 | Code editor | codemirror, ace |
|
|
42
|
+
| localforage | ^1.10.0 | Client-side storage | idb, dexie |
|
|
43
|
+
| react-markdown | ^10.1.0 | Markdown rendering | marked, markdown-it |
|
|
44
|
+
| fast-deep-equal | ^3.1.3 | Deep equality checks | lodash.isEqual |
|
|
45
|
+
| @ngneat/falso | latest | Fake data generation | @faker-js/faker, chance |
|
|
46
|
+
| pino | ^10.1.0 | Logging | winston |
|
|
47
|
+
|
|
48
|
+
## Frontend
|
|
49
|
+
|
|
50
|
+
Tailwind v4 + shadcn-based UI; conventions below.
|
|
51
|
+
|
|
52
|
+
- **Build every UI through the `frontend-design` skill** — route the brief through it instead of hand-rolling layouts; it owns the archetype, personality tokens, and `@nurix/components` wiring.
|
|
53
|
+
- **Light mode is the default** — design for the light theme as the default; dark mode is opt-in, never the default.
|
|
54
|
+
- **@nurix/\* are restricted-scope npm packages** — installed from the npm registry, auto-authed by a read token in `~/.npmrc`. Just attempt the install; the token authenticates you automatically. Don't pre-empt or second-guess it. If the install actually fails, flag it to the user — never reach for alternatives, a substitute package, or `npm login`.
|
|
55
|
+
- **@nurix/components** — the UI component library (restricted-scope npm package, pre-built); import by subpath, e.g. `@nurix/components/button`.
|
|
56
|
+
- No components.json / shadcn CLI scaffold (.tsx, not .jsx) — consume the prebuilt library; never `npx shadcn add`.
|
|
57
|
+
- Vite: `@tailwindcss/vite` + `@vitejs/plugin-react-swc`. Pin react / react-dom / react/jsx-runtime / react/jsx-dev-runtime to the app's single copy via `resolve.alias` (@nurix/\* ship nested react — keep one hook dispatcher).
|
|
58
|
+
- Tailwind v4, CSS-only (no tailwind.config.js, no PostCSS): styling runs through the `@tailwindcss/vite` plugin.
|
|
59
|
+
- CSS entry `globals.css`, imports in order — `@import "./personality.css"` (token source) → `@import "tailwindcss"` → the library's `styles.css` — then `@theme inline {…}` mapping vars to tokens.
|
|
60
|
+
- Tokens: CSS vars in `:root, :root[data-theme="light"]` + the archetype selector `[data-style="…"]` (personality.css), consumed as semantic Tailwind tokens (bg-card, text-foreground). Honor the archetype's radius/theme decisions (e.g. re-assert `--radius-*` to 0 for a flat archetype; add `@custom-variant dark` only if the project opts into dark mode, and keep light as the default). The library bundles class-variance-authority, clsx, tailwind-merge.
|
|
61
|
+
- Plus general styling rules (spacing in 2/4/6/8, object-cover, truncate, motion, color tokens — never hardcoded hex in components).
|
|
62
|
+
|
|
63
|
+
## Express 5.x
|
|
64
|
+
|
|
65
|
+
```javascript
|
|
66
|
+
app.use(cors({ origin: process.env.FRONTEND_URL }));
|
|
67
|
+
app.use(compression());
|
|
68
|
+
app.use(express.json({ limit: '10mb' }));
|
|
69
|
+
app.use(rateLimit({ windowMs: 15 * 60 * 1000, max: 100 }));
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
- Middleware order: body parsers → custom middleware → routes → error handlers (centralized, last). Auth via middleware. Use Express Router for modular routes.
|
|
73
|
+
|
|
74
|
+
## API Response Format
|
|
75
|
+
|
|
76
|
+
```json
|
|
77
|
+
{
|
|
78
|
+
"status": 1,
|
|
79
|
+
"message": "Message sent successfully",
|
|
80
|
+
"data": { "delivered": [{ "user@example.com": 2 }] }
|
|
81
|
+
}
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Error: `{ "status": 0, "message": "Error description", "data": null }`
|
|
85
|
+
|
|
86
|
+
HTTP codes: `200`, `201` (created), `400`, `401` (not authenticated), `403` (not authorized), `404`, `500`
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# kb.md — Patterns for Obsidian-like Folders
|
|
2
|
+
|
|
3
|
+
Conventions for any folder that is majority markdown — `docs/`, `research/`, an Obsidian vault, or any knowledge base. Rules grow over time; append new ones below.
|
|
4
|
+
|
|
5
|
+
## Rules
|
|
6
|
+
|
|
7
|
+
### 1. Every topic gets a `Readme.md`
|
|
8
|
+
|
|
9
|
+
When you start documenting a topic, create `Readme.md` as the folder's landing page. Don't use `index.md` or unscoped filenames — `Readme.md` is what readers and tools (GitHub, Obsidian) look for first, and it makes the folder self-introducing.
|
|
10
|
+
|
|
11
|
+
### 2. Always link documents to each other
|
|
12
|
+
|
|
13
|
+
When one document references an idea, concept, or topic covered in another, link to it. Wikilinks (`[[other-doc]]`) inside Obsidian-native vaults; relative markdown links (`[label](../other-doc.md)`) elsewhere. If you mention it, you link it — that's how the folder becomes a knowledge graph instead of a pile of files.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# Nomenclature Guidelines
|
|
2
|
+
|
|
3
|
+
## Naming Guidelines
|
|
4
|
+
|
|
5
|
+
- Use descriptive names that reveal intent, purpose, and usage
|
|
6
|
+
- Names should explain why something exists and how it's used
|
|
7
|
+
- Favor clarity over brevity
|
|
8
|
+
- Maintain consistency within the codebase
|
|
9
|
+
- Avoid abbreviations unless they're universally understood
|
|
10
|
+
|
|
11
|
+
## Naming Styles
|
|
12
|
+
|
|
13
|
+
- Variables : Use nouns or noun phrases. Examples: `userData`, `firstName`, `paymentStatus`, `configOptions`
|
|
14
|
+
- Functions & Methods : Use verbs or verb phrases that describe the action. Examples: `calculateTotal`, `getUserInfo`, `validateInput`, `sendNotification`
|
|
15
|
+
- Boolean Variables : Prefix with is**, has**, can**, or should**. Examples: `isValid`, `hasPermission`, `canEdit`, `shouldRefresh`
|
|
16
|
+
- Arrays : Use plural nouns. Examples: `users`, `productList`, `errorMessages`, `activeConnections`
|
|
17
|
+
- Classes & Components : Use singular nouns or noun phrases. Examples: `RequestHandler`, `UserProfile`, `PaymentProcessor`, `DataValidator`
|
|
18
|
+
- Constants : Use uppercase with meaningful names. Examples: `DEFAULT_TIMEOUT`, `API_BASE_URL`, `MAX_RETRY_COUNT`, `COLOR_PRIMARY`
|
|
19
|
+
- Event Handlers : Use Prefix with handle or on. Examples: `handleSubmit`, `onUserLogin`, `handleInputChange`, `onPageLoad`
|
|
20
|
+
- Interfaces & Types : Use Consider prefixing with I for interfaces (if preferred). Examples: `IUserData`, `IConfigOptions`, `AuthResponse`, `RequestParams`
|
|
21
|
+
- Promises & Async Functions : Use Consider using future tense or suffixes like Async. Examples: `fetchUserData`, `getUserProfileAsync`, `loadConfigAsync`, `processPayment`
|
|
22
|
+
- File & Folder Structure : Use lowercase with descriptive names. Group by feature or function type. Example: `auth/login_service.js`
|
|
23
|
+
|
|
24
|
+
## Casing Styles
|
|
25
|
+
|
|
26
|
+
- camelCase : Used in Variables, function names, method names, property names. Examples: `userData`, `calculateTotal`, `firstName`, `isValidEmail`
|
|
27
|
+
- PascalCase : Used in Class names, component names, type definitions. Examples: `UserProfile`, `DataService`, `AuthProvider`, `RequestHandler`
|
|
28
|
+
- snake_case : Used in File names, folder names. Examples: `user_service`, `api_utils`, `auth_middleware`, `data_models`
|
|
29
|
+
- UPPER_SNAKE_CASE : Used in Constants, environment variables. Examples: `MAX_RETRY_COUNT`, `API_KEY`, `DEFAULT_TIMEOUT`, `COLOR_PRIMARY`
|
|
30
|
+
- kebab-case : Used in URLs, CSS class names, HTML IDs. Examples: `nav-container`, `user-profile`, `button-primary`, `form-wrapper`
|
|
31
|
+
|
|
32
|
+
## Database
|
|
33
|
+
|
|
34
|
+
Naming for D1 tables, columns, indexes, and their Drizzle mirrors. (For column **types** — PK shape, timestamp columns — see the Cloudflare D1 Schema rule, not here; this section governs names only.)
|
|
35
|
+
|
|
36
|
+
- **Tables** : snake_case. Entity / hub tables use the plural noun for the thing they hold. Examples: `users`, `apps`, `devices`, `services`.
|
|
37
|
+
- **Junction (M:N) tables** : name a many-to-many join `<entityA>_<entityB>_map` — **always**, even when the join carries its own columns (a `role`, a secret, a status). The `_map` suffix is the signal that a row is a relationship, not an entity; extra attributes on the join do **not** earn it a standalone noun. Use the **singular** stem of each side, owning/anchor entity first (mirror the existing tables — `app_*`). Examples: `app_user_map` (apps ⨯ users), `app_device_map` (apps ⨯ devices), `app_service_map` (apps ⨯ services).
|
|
38
|
+
- ❌ Don't invent a "nice" noun for a junction — no `members`, `installs`, `memberships`, `enrolments`. A reviewer should read the table name and know both sides and that it's a join.
|
|
39
|
+
- **Columns** : snake_case. Foreign keys are `<entity>_id` (`user_id`, `app_id`, `device_id`, `service_id`). Booleans follow the boolean rule (`is_*`/`has_*`); timestamps are `created_at` / `updated_at`.
|
|
40
|
+
- **Indexes** : `<table>_<col(s)>_idx`; unique indexes `<table>_<col(s)>_unique`. The composite unique on a junction reads `<table>_<colA>_<colB>_unique` — e.g. `app_user_map_app_user_unique`, `app_device_map_device_app_unique`.
|
|
41
|
+
- **Drizzle mirror** : the exported table object is the camelCase of the snake_case table name (`app_user_map` → `appUserMap`); column TS properties are the camelCase of the column (`created_at` → `createdAt`, `service_key` → `serviceKey`). The snake_case string passed to `sqliteTable("…")` and every index name must match `seed/init.sql` exactly (the G1 schema-parity boundary).
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# npm CLI Design — the `@nurix/*` pattern
|
|
2
|
+
|
|
3
|
+
Conventions for building a distributable Nurix command-line tool, distilled from the two we ship: **`@nurix/etna`** (`packages/cli/` here — the harness installer, plain ESM JS) and **`@nurix/apollo`** (`~/dev/apollo/packages/cli/` — the service-bootstrap CLI, TypeScript → `dist/`). When you build or change a `@nurix` CLI, follow these. Where the two diverge, both variants are noted as valid.
|
|
4
|
+
|
|
5
|
+
## 1. Packaging
|
|
6
|
+
|
|
7
|
+
- **Scoped + restricted.** Name is `@nurix/<tool>`; `"publishConfig": { "access": "restricted" }`. Never publish public.
|
|
8
|
+
- **ESM only** — `"type": "module"`.
|
|
9
|
+
- **`bin` maps the command to its entry** — `{ "etna": "bin/etna.js" }` / `{ "apollo": "dist/index.js" }`. The entry has a `#!/usr/bin/env node` shebang.
|
|
10
|
+
- **`files` is an allowlist** — ship only the runnable artifact: `["bin/", "data/", "README.md"]` (etna) or `["dist"]` (apollo). Never ship `src/`, tests, or the repo.
|
|
11
|
+
- **`engines.node` ≥ 22** for new CLIs (matches the workspace Node baseline).
|
|
12
|
+
- **One version source** — read the running version from `package.json` at startup; don't hardcode it elsewhere.
|
|
13
|
+
- **Minimal deps.** Both ship with essentially one runtime dep (`@clack/prompts`); apollo adds `commander` + `ajv`. Keep the dependency surface tiny — it's installed on every `npx` run.
|
|
14
|
+
|
|
15
|
+
## 2. Distribution: `npx`-first, install into the project, never globally
|
|
16
|
+
|
|
17
|
+
- The canonical entry is **`npx @nurix/<tool>`** — no global install step, no marketplace, no plugin-enablement dance. The user runs `npx`, the tool does its job in the current directory.
|
|
18
|
+
- **The CLI writes ONLY inside the folder it was invoked in.** An installer run as `npx @nurix/etna` in a project must touch only that project tree — never `$HOME`, never `~/.claude`, never any shared/user-level location. Reaching outside the target folder is surprising, clobber-prone, and wrong. (This is a hard-won rule: an earlier etna build installed agents to `~/.claude/agents/` and it was reverted precisely for this reason.)
|
|
19
|
+
- **Idempotent refresh.** Re-running the CLI re-pulls the latest and overwrites the files it owns (force), while leaving anything the user authored untouched. "Re-run anytime to refresh" must always be safe.
|
|
20
|
+
|
|
21
|
+
## 3. Always run the latest — self-update by re-exec
|
|
22
|
+
|
|
23
|
+
**The problem:** `npx` caches aggressively. A bare `npx @nurix/<tool>` can keep running a *stale* unpacked copy long after a newer version is published (npm's packument cache resolves an old `latest`, and npx reuses the matching install). Users shouldn't have to remember `@latest`.
|
|
24
|
+
|
|
25
|
+
**The mechanism** (etna's `selfUpdateOrReexec()`, run before anything else): on startup, ask the registry for the latest version; if this copy is behind, re-exec the latest and hand off.
|
|
26
|
+
|
|
27
|
+
```js
|
|
28
|
+
function selfUpdateOrReexec() {
|
|
29
|
+
if (process.env.TOOL_SELFUPDATED || process.env.TOOL_NO_SELFUPDATE) return;
|
|
30
|
+
const here = readJson(join(pkgRoot, 'package.json')).version;
|
|
31
|
+
if (!here) return;
|
|
32
|
+
const view = spawnSync('npm', ['view', '@nurix/<tool>', 'version', '--prefer-online'], { encoding: 'utf8' });
|
|
33
|
+
const latest = view.status === 0 ? (view.stdout || '').trim() : null;
|
|
34
|
+
if (!latest || latest === here) return; // current, offline, or unauthed → run this copy
|
|
35
|
+
const child = spawnSync('npx', ['-y', '--prefer-online', `@nurix/<tool>@${latest}`, ...process.argv.slice(2)],
|
|
36
|
+
{ stdio: 'inherit', env: { ...process.env, TOOL_SELFUPDATED: '1' } });
|
|
37
|
+
if (!child.error) process.exit(child.status ?? 0); // re-exec ran → hand off complete
|
|
38
|
+
// npx unavailable (child.error) → fall through and run this (older) copy.
|
|
39
|
+
}
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Required properties:
|
|
43
|
+
|
|
44
|
+
- **`--prefer-online`** on both the `npm view` and the `npx` re-exec — defeats the metadata cache so npx fetches the fresh tarball.
|
|
45
|
+
- **Loop guard** — set `<TOOL>_SELFUPDATED=1` in the child's env so the re-exec'd process doesn't try to update again.
|
|
46
|
+
- **Opt-out** — `<TOOL>_NO_SELFUPDATE=1` skips the whole thing (CI, offline, or running an intentionally pinned/local-dev build). This is also how you test a local build.
|
|
47
|
+
- **Degrade gracefully** — *any* failure (offline, unauthed, `npm`/`npx` missing, timeout) falls through to running the current copy. The update is a convenience, never a gate.
|
|
48
|
+
- **Reuse existing npm auth** — the `npm view` rides the caller's npm credentials (the same auth that installed the restricted package); never prompt for login.
|
|
49
|
+
|
|
50
|
+
## 4. Editing the user's files: own a delimited block, idempotently
|
|
51
|
+
|
|
52
|
+
When the CLI must modify a file it doesn't own (`.env`, `settings.json`, `.gitignore`), it **owns only a delimited region** and rewrites that region in place — never the whole file.
|
|
53
|
+
|
|
54
|
+
- apollo wraps its `.env` writes in a managed block:
|
|
55
|
+
`# >>> apollo:managed — do not edit by hand; the apollo CLI rewrites this block >>>` … `# <<< apollo:managed <<<`. Reads/merges/removes happen *inside* the markers; everything outside belongs to the user.
|
|
56
|
+
- etna merges its hooks into `.claude/settings.json` and migrates/retires only its own prior entries.
|
|
57
|
+
- Rewrites are **idempotent** (re-running converges to the same block) and **reversible** (logout/uninstall removes exactly the managed region).
|
|
58
|
+
- If the block holds secrets, ensure `.gitignore` covers the file so they're never committed.
|
|
59
|
+
|
|
60
|
+
## 5. Interactive when it can, flag-driven when it can't
|
|
61
|
+
|
|
62
|
+
- Use **`@clack/prompts`** for the interactive path (TTY): intro/outro, spinners, notes.
|
|
63
|
+
- When **not a TTY**, require explicit flags and fail loudly with the correct syntax rather than guessing — e.g. etna needs `--name=<harness>` outside a TTY, and a removed/renamed flag (the dropped positional form in 0.18.0) errors with the new syntax instead of silently misfiring.
|
|
64
|
+
- A bare invocation in a TTY may present a menu; the same invocation headless must error, not hang.
|
|
65
|
+
|
|
66
|
+
## 6. Detect the package manager from the lockfile
|
|
67
|
+
|
|
68
|
+
When the CLI installs packages or runs scripts on the user's behalf, detect the manager: `pnpm-lock.yaml` → pnpm, `yarn.lock` → yarn, else npm. Never hardcode one. (apollo's `detectPackageManager()`.)
|
|
69
|
+
|
|
70
|
+
## 7. Publishing is CI-owned
|
|
71
|
+
|
|
72
|
+
Publish from CI on push to `dev`/`main`, path-filtered to the CLI package — never `npm publish` by hand for a routine change.
|
|
73
|
+
|
|
74
|
+
- **Two valid version models:**
|
|
75
|
+
- **Fingerprint auto-bump (etna):** the build stamps a content hash (`fingerprint`) of the shipped payload; CI bumps the **patch** automatically when the fingerprint changed, publishes, and tags. Never hand-bump for a content change — let the fingerprint drive it; hand-edit the version only for a deliberate minor/major.
|
|
76
|
+
- **Manual bump input (apollo):** a `workflow_dispatch` `bump` input (`patch`/`minor`/`major`) drives `npm version`.
|
|
77
|
+
- **Common to both:**
|
|
78
|
+
- The bump commit message carries **`[skip ci]`** so the publish workflow doesn't re-trigger itself.
|
|
79
|
+
- `npm version --no-git-tag-version` (file-only), then commit + tag separately — `npm version` skips the git step when run in a subdirectory of the repo root.
|
|
80
|
+
- Push the bump back to the branch and tag with a **package-scoped prefix** (`v…` for etna, `apollo-v…` for apollo) via `git push origin HEAD:<ref> --follow-tags`.
|
|
81
|
+
- `prepack` / `prepublishOnly` builds the shipped artifact (`data/` via `build-data.js`, or `dist/` via `tsc`) so what's published always matches source.
|
|
82
|
+
- `registry-url: https://registry.npmjs.org` in the Node setup so `.npmrc` uses `$NODE_AUTH_TOKEN`.
|
|
83
|
+
|
|
84
|
+
## 8. Robustness defaults
|
|
85
|
+
|
|
86
|
+
- **Never hard-block on an advisory/network check.** Version currency, registry lookups, telemetry — all degrade to a one-line notice and continue.
|
|
87
|
+
- **Restricted-scope auth is ambient** — the read token in `~/.npmrc` (or `$NODE_AUTH_TOKEN` in CI) authenticates installs and `npm view`. Just attempt the operation; never prompt for `npm login` or reach for a substitute package.
|
|
88
|
+
- **Keep the hot path fast** — everything runs on every `npx`, so avoid heavy startup work beyond the self-update check.
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: boundary
|
|
3
|
+
description: Boundary diagnostic for implementation plans. Given a plan file, reads the source files the plan touches, identifies the application boundaries they participate in — the cross-cutting contracts (db schema, wire envelope, auth, events, env/config, …) where editing one side silently breaks the other — and reports whether the planned changes would violate any of them, severity-ranked, with suggested plan amendments. Read-only; the report lands in chat. Can also run against a diff or named code area instead of a plan. Triggers on "boundary check", "check this plan", "what could break", "impact analysis", "/boundary".
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Boundary Diagnostic
|
|
7
|
+
|
|
8
|
+
You diagnose whether a plan's changes would break an application boundary.
|
|
9
|
+
|
|
10
|
+
A boundary is a contract between two pieces of code (or code and infra) that share an assumption with **no compile-time link** between them: the column a raw SQL string names, the JSON envelope a client unwraps, the event string a dispatcher parses, the env var a deploy script writes. Changing one side ships green and breaks the other silently. Your job is to find those edges in the plan's path _before_ execution.
|
|
11
|
+
|
|
12
|
+
[`references/boundary-taxonomy.md`](references/boundary-taxonomy.md) is the catalog of boundary types (~170 across persistence, wire/API, frontend, auth/tenancy, async/messaging, config/build, runtime/infra), with per-type severities and safe-change checklists. Read it first — it tells you what to look for; the code tells you what exists.
|
|
13
|
+
|
|
14
|
+
## Run
|
|
15
|
+
|
|
16
|
+
**Input:** a plan path (given, or the newest in `docs/history/plans/`) — or a diff / named code area for non-plan work. Everything below is identical either way; a diff's hunks stand in for the plan's steps.
|
|
17
|
+
|
|
18
|
+
1. **Build the touch list.** Parse the plan's Proposed Changes: files to be created or modified, entities/state added or changed, API changes, anything the author flags as a cross-module contract. Note missing subsections.
|
|
19
|
+
|
|
20
|
+
2. **Identify the boundaries in the touched code.** Read each touched file (and its immediate imports). Against the taxonomy, list the contracts this code participates in — the schema it queries, the envelope it emits, the events it publishes or parses, the auth checks it sits behind, the env it reads.
|
|
21
|
+
|
|
22
|
+
3. **Trace the other side.** A boundary has two sides; the danger lives on the one the plan _doesn't_ mention. For each contract, grep the shared name or shape across the repo — the column name in other SQL strings, the response field in client unwrappers, the event kind in subscribers, the route in fetch calls and scripts, the env key in deploy tooling. Record consumers as `file:line`.
|
|
23
|
+
|
|
24
|
+
4. **Judge each intersection.** Does the planned change alter a shape a traced consumer depends on, break an invariant the code establishes (append-only vocabularies, idempotency keys, fail-closed checks, ordering guarantees), or add a new cross-module edge? Severity:
|
|
25
|
+
- **CRITICAL** — can corrupt persisted data, or open an auth/money path.
|
|
26
|
+
- **HIGH** — silent cross-module breakage that would ship green.
|
|
27
|
+
- **MEDIUM** — drift-prone coupling (string-matched, duplicated constants).
|
|
28
|
+
- **LOW** — smell. Loud, immediately-visible breakage caps at HIGH.
|
|
29
|
+
|
|
30
|
+
5. **Report in chat:**
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
# Boundary check — {plan}
|
|
34
|
+
|
|
35
|
+
Touched files read: {N} · Boundaries identified: {N}
|
|
36
|
+
Violations: {N} ({critical}/{high}/{medium}/{low})
|
|
37
|
+
|
|
38
|
+
| # | Boundary | Planned change | Other side (file:line) | Severity |
|
|
39
|
+
|
|
40
|
+
## Suggested plan amendments
|
|
41
|
+
## Missing plan subsections
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Rules
|
|
45
|
+
|
|
46
|
+
- **Read-only.** You never edit the plan, the code, or any doc. The user folds your amendments into the plan.
|
|
47
|
+
- **Verify in source.** Never flag from plan text alone — read both sides of every boundary you report, and cite both as `file:line`.
|
|
48
|
+
- **No consumer, no finding.** An intersection with no traced other side isn't a violation; at most note it as a new edge the plan introduces.
|
|
49
|
+
- **A clean report is valid.** Zero violations means say so — don't pad.
|