@nurix/etna 0.18.0 → 0.18.2

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.
Files changed (118) hide show
  1. package/README.md +6 -5
  2. package/data/harness-index.json +1 -5
  3. package/data/harnesses/code/CLAUDE.md +8 -19
  4. package/data/harnesses/code/agents/brainstorm.md +3 -3
  5. package/data/harnesses/code/agents/change-review.md +13 -10
  6. package/data/harnesses/code/agents/harness-manager.md +15 -15
  7. package/data/harnesses/code/agents/maintenance.md +10 -3
  8. package/data/harnesses/code/agents/performance-review.md +5 -0
  9. package/data/harnesses/code/harness.json +1 -1
  10. package/data/harnesses/code/rules/general.md +40 -36
  11. package/data/harnesses/code/skills/boundary/SKILL.md +15 -42
  12. package/data/harnesses/code/skills/boundary/references/boundary-taxonomy.md +366 -304
  13. package/data/harnesses/code/skills/brainstorm/README.md +9 -9
  14. package/data/harnesses/code/skills/brainstorm/SKILL.md +15 -15
  15. package/data/harnesses/code/skills/brainstorm/harvest.md +3 -3
  16. package/data/harnesses/code/skills/brainstorm/templates/backlog.md +2 -2
  17. package/data/harnesses/code/skills/brainstorm/templates/build.md +6 -6
  18. package/data/harnesses/code/skills/brainstorm/templates/decisions.md +3 -3
  19. package/data/harnesses/code/skills/brainstorm/templates/doctrine.md +2 -2
  20. package/data/harnesses/code/skills/brainstorm/templates/domain-model.md +2 -2
  21. package/data/harnesses/code/skills/brainstorm/templates/glossary.md +2 -1
  22. package/data/harnesses/code/skills/brainstorm/templates/non-goals.md +3 -7
  23. package/data/harnesses/code/skills/brainstorm/templates/questions.md +6 -5
  24. package/data/harnesses/code/skills/brainstorm/templates/state.md +1 -8
  25. package/data/harnesses/code/skills/brainstorm/templates/tech.md +6 -6
  26. package/data/harnesses/code/skills/brainstorm/templates/thesis.md +2 -2
  27. package/data/harnesses/code/skills/distiller/SKILL.md +48 -177
  28. package/data/harnesses/code/skills/distiller/references/docs-mode.md +116 -343
  29. package/data/harnesses/code/skills/distiller/references/method.md +37 -109
  30. package/data/harnesses/code/skills/documentation/SKILL.md +9 -6
  31. package/data/harnesses/code/skills/documentation/references/examples.md +30 -61
  32. package/data/harnesses/code/skills/documentation/references/style-guide.md +59 -62
  33. package/data/harnesses/code/skills/documentation/references/templates.md +26 -34
  34. package/data/harnesses/code/skills/workflow-mapper/SKILL.md +32 -11
  35. package/data/harnesses/code/skills/workflow-mapper/references/patterns.md +1 -1
  36. package/data/harnesses/discover/CLAUDE.md +60 -113
  37. package/data/harnesses/discover/agents/api.md +11 -28
  38. package/data/harnesses/discover/agents/codebase.md +12 -30
  39. package/data/harnesses/discover/agents/community.md +9 -21
  40. package/data/harnesses/discover/agents/deployed-client-bundle.md +16 -67
  41. package/data/harnesses/discover/agents/distribution-artifacts.md +21 -59
  42. package/data/harnesses/discover/agents/docs.md +11 -20
  43. package/data/harnesses/discover/agents/infra-backend-fingerprint.md +28 -68
  44. package/data/harnesses/discover/agents/packages.md +12 -28
  45. package/data/harnesses/discover/agents/session.md +18 -50
  46. package/data/harnesses/discover/agents/website.md +9 -19
  47. package/data/harnesses/discover/agents/wire-capture.md +22 -72
  48. package/data/harnesses/discover/harness.json +1 -1
  49. package/data/harnesses/discover/rules/cartography-coverage.md +94 -0
  50. package/data/harnesses/discover/rules/cartography-flows.md +99 -0
  51. package/data/harnesses/discover/rules/cartography-ia.md +88 -0
  52. package/data/harnesses/discover/rules/cartography.md +109 -0
  53. package/data/harnesses/discover/rules/discovery.md +73 -182
  54. package/data/harnesses/discover/rules/evaluation.md +92 -98
  55. package/data/harnesses/discover/rules/ingestion.md +123 -322
  56. package/data/harnesses/discover/rules/self-correction.md +94 -107
  57. package/data/harnesses/discover/rules/tradecraft.md +201 -172
  58. package/data/harnesses/hr/CLAUDE.md +21 -51
  59. package/data/harnesses/hr/harness.json +1 -1
  60. package/data/harnesses/hr/skills/interview-eval/SKILL.md +23 -11
  61. package/data/harnesses/hr/skills/interview-eval/TEMPLATE.md +49 -29
  62. package/data/harnesses/hr/skills/interview-eval/rubric.md +30 -30
  63. package/data/harnesses/kb-agi/CLAUDE.md +8 -8
  64. package/data/harnesses/kb-agi/agents/kb-agi-init.md +31 -22
  65. package/data/harnesses/kb-agi/agents/kb-catch-stale.md +1 -1
  66. package/data/harnesses/kb-agi/agents/kb-find-gaps.md +1 -1
  67. package/data/harnesses/kb-agi/agents/kb-fix-links.md +1 -1
  68. package/data/harnesses/kb-agi/agents/kb-refresh-summaries.md +2 -2
  69. package/data/harnesses/kb-agi/agents/kb-sync-metadata.md +2 -2
  70. package/data/harnesses/kb-agi/harness.json +1 -1
  71. package/package.json +1 -1
  72. package/data/harnesses/code-fable/.prettierignore +0 -12
  73. package/data/harnesses/code-fable/.prettierrc.json +0 -3
  74. package/data/harnesses/code-fable/.vscode/settings.json +0 -10
  75. package/data/harnesses/code-fable/CLAUDE.md +0 -135
  76. package/data/harnesses/code-fable/agents/brainstorm.md +0 -35
  77. package/data/harnesses/code-fable/agents/change-review.md +0 -248
  78. package/data/harnesses/code-fable/agents/harness-manager.md +0 -181
  79. package/data/harnesses/code-fable/agents/maintenance.md +0 -115
  80. package/data/harnesses/code-fable/agents/performance-review.md +0 -218
  81. package/data/harnesses/code-fable/agents/spec-mode.md +0 -56
  82. package/data/harnesses/code-fable/harness.json +0 -12
  83. package/data/harnesses/code-fable/hooks/hooks.json +0 -27
  84. package/data/harnesses/code-fable/hooks/lib/redact.mjs +0 -35
  85. package/data/harnesses/code-fable/hooks/prompt-recall.mjs +0 -155
  86. package/data/harnesses/code-fable/hooks/session-reflect.mjs +0 -285
  87. package/data/harnesses/code-fable/rules/general.md +0 -79
  88. package/data/harnesses/code-fable/rules/nomenclature.md +0 -30
  89. package/data/harnesses/code-fable/rules/typescript.md +0 -19
  90. package/data/harnesses/code-fable/skills/boundary/SKILL.md +0 -76
  91. package/data/harnesses/code-fable/skills/boundary/references/boundary-taxonomy.md +0 -734
  92. package/data/harnesses/code-fable/skills/brainstorm/README.md +0 -136
  93. package/data/harnesses/code-fable/skills/brainstorm/SKILL.md +0 -135
  94. package/data/harnesses/code-fable/skills/brainstorm/harvest.md +0 -26
  95. package/data/harnesses/code-fable/skills/brainstorm/templates/backlog.md +0 -39
  96. package/data/harnesses/code-fable/skills/brainstorm/templates/build.md +0 -37
  97. package/data/harnesses/code-fable/skills/brainstorm/templates/decisions.md +0 -29
  98. package/data/harnesses/code-fable/skills/brainstorm/templates/doctrine.md +0 -31
  99. package/data/harnesses/code-fable/skills/brainstorm/templates/domain-model.md +0 -25
  100. package/data/harnesses/code-fable/skills/brainstorm/templates/glossary.md +0 -19
  101. package/data/harnesses/code-fable/skills/brainstorm/templates/milestones.md +0 -43
  102. package/data/harnesses/code-fable/skills/brainstorm/templates/non-goals.md +0 -21
  103. package/data/harnesses/code-fable/skills/brainstorm/templates/plan-doc.md +0 -61
  104. package/data/harnesses/code-fable/skills/brainstorm/templates/questions.md +0 -35
  105. package/data/harnesses/code-fable/skills/brainstorm/templates/references.md +0 -28
  106. package/data/harnesses/code-fable/skills/brainstorm/templates/rejected.md +0 -29
  107. package/data/harnesses/code-fable/skills/brainstorm/templates/state.md +0 -8
  108. package/data/harnesses/code-fable/skills/brainstorm/templates/tech.md +0 -23
  109. package/data/harnesses/code-fable/skills/brainstorm/templates/thesis.md +0 -21
  110. package/data/harnesses/code-fable/skills/distiller/SKILL.md +0 -219
  111. package/data/harnesses/code-fable/skills/distiller/references/docs-mode.md +0 -526
  112. package/data/harnesses/code-fable/skills/distiller/references/method.md +0 -166
  113. package/data/harnesses/code-fable/skills/documentation/SKILL.md +0 -125
  114. package/data/harnesses/code-fable/skills/documentation/references/examples.md +0 -193
  115. package/data/harnesses/code-fable/skills/documentation/references/style-guide.md +0 -288
  116. package/data/harnesses/code-fable/skills/documentation/references/templates.md +0 -865
  117. package/data/harnesses/code-fable/skills/workflow-mapper/SKILL.md +0 -430
  118. package/data/harnesses/code-fable/skills/workflow-mapper/references/patterns.md +0 -214
@@ -1,285 +0,0 @@
1
- // plugins/code/hooks/session-reflect.mjs — SessionEnd hook: reflect the session into durable lessons (headless haiku pass) appended to the actor's memory inbox.
2
-
3
- import fs from "node:fs";
4
- import os from "node:os";
5
- import path from "node:path";
6
- import { execFileSync, spawn } from "node:child_process";
7
- import { fileURLToPath } from "node:url";
8
- import { redact } from "./lib/redact.mjs";
9
-
10
- // ESM has no __filename; derive it from this module's URL for the detached worker re-spawn.
11
- const __filename = fileURLToPath(import.meta.url);
12
-
13
- // A session below all three thresholds carries no lesson worth a model call.
14
- const MIN_TURNS = 8;
15
- const MAX_MESSAGE_CHARS = 1500;
16
- const MAX_DIGEST_CHARS = 80000;
17
- const MAX_LESSONS = 6;
18
-
19
- // Read all of stdin synchronously; returns "" if nothing is piped.
20
- function readStdin() {
21
- try {
22
- return fs.readFileSync(0, "utf8");
23
- } catch (e) {
24
- return "";
25
- }
26
- }
27
-
28
- // Resolve the project root: CLAUDE_PROJECT_DIR env, else payload cwd, else process cwd.
29
- function resolveProjectDir(payload) {
30
- return process.env.CLAUDE_PROJECT_DIR || (payload && payload.cwd) || process.cwd();
31
- }
32
-
33
- // Run a git command in projectDir; returns trimmed stdout or fallback on any error.
34
- function git(projectDir, args, fallback) {
35
- try {
36
- return execFileSync("git", ["-C", projectDir, ...args], {
37
- encoding: "utf8",
38
- stdio: ["ignore", "pipe", "ignore"],
39
- }).trim() || fallback;
40
- } catch (e) {
41
- return fallback;
42
- }
43
- }
44
-
45
- // Slug a raw actor name into kebab-case ASCII.
46
- function slugActor(name) {
47
- return String(name || "")
48
- .toLowerCase()
49
- .replace(/[^a-z0-9]+/g, "-")
50
- .replace(/^-+|-+$/g, "");
51
- }
52
-
53
- // Determine the actor: git user.name (slugged) → $USER → "agent".
54
- function resolveActor(projectDir) {
55
- const fromGit = slugActor(git(projectDir, ["config", "user.name"], ""));
56
- if (fromGit) return fromGit;
57
- const fromEnv = slugActor(process.env.USER || "");
58
- if (fromEnv) return fromEnv;
59
- return "agent";
60
- }
61
-
62
- // Truncate a single line to n chars with an ellipsis marker.
63
- function clip(text, n) {
64
- const clean = String(text || "").replace(/\s+/g, " ").trim();
65
- return clean.length > n ? clean.slice(0, n) + "…" : clean;
66
- }
67
-
68
- // Extract plain text from a message whose content is a string or content-block array.
69
- function extractText(msg) {
70
- if (!msg || !msg.content) return "";
71
- if (typeof msg.content === "string") return msg.content;
72
- if (Array.isArray(msg.content)) {
73
- return msg.content
74
- .filter((b) => b && b.type === "text" && typeof b.text === "string")
75
- .map((b) => b.text)
76
- .join(" ");
77
- }
78
- return "";
79
- }
80
-
81
- // Strip harness-injected wrappers so only what the user actually typed survives.
82
- function stripInjected(text) {
83
- return String(text || "")
84
- .replace(/<system-reminder>[\s\S]*?<\/system-reminder>/g, "")
85
- .replace(/<(local-command-caveat|local-command-stdout|local-command-stderr|command-name|command-message|command-args|command-contents)>[\s\S]*?<\/\1>/g, "")
86
- .trim();
87
- }
88
-
89
- // Scan an assistant message's tool_use blocks for edited files and git commits.
90
- function collectToolUse(msg, summary) {
91
- if (!msg || !Array.isArray(msg.content)) return;
92
- for (const block of msg.content) {
93
- if (!block || block.type !== "tool_use") continue;
94
- const name = block.name || "";
95
- const input = block.input || {};
96
- if (/^(Edit|Write|MultiEdit|NotebookEdit)$/.test(name) && input.file_path) {
97
- summary.files.add(input.file_path);
98
- }
99
- if (name === "Bash" && typeof input.command === "string" && /\bgit\s+commit\b/.test(input.command)) {
100
- summary.sawCommit = true;
101
- }
102
- }
103
- }
104
-
105
- // Walk the JSONL transcript once: turn/edit/commit counts plus a USER/ASSISTANT text digest.
106
- function digestTranscript(transcriptPath) {
107
- const out = { turns: 0, files: new Set(), sawCommit: false, lines: [] };
108
- if (!transcriptPath || !fs.existsSync(transcriptPath)) return out;
109
- for (const line of fs.readFileSync(transcriptPath, "utf8").split("\n")) {
110
- if (!line.trim()) continue;
111
- let row;
112
- try {
113
- row = JSON.parse(line);
114
- } catch (e) {
115
- continue;
116
- }
117
- if (row.isSidechain) continue;
118
- const msg = row && row.message ? row.message : row;
119
- const role = (msg && msg.role) || row.type;
120
- if (role === "user") {
121
- const text = stripInjected(extractText(msg));
122
- if (!text || text.startsWith("Caveat: The messages below")) continue;
123
- out.lines.push("USER: " + clip(text, MAX_MESSAGE_CHARS));
124
- } else if (role === "assistant") {
125
- out.turns += 1;
126
- collectToolUse(msg, out);
127
- const text = extractText(msg);
128
- if (text) out.lines.push("ASSISTANT: " + clip(text, MAX_MESSAGE_CHARS));
129
- }
130
- }
131
- return out;
132
- }
133
-
134
- // Compute the per-actor inbox file path.
135
- function inboxPath(projectDir, actor) {
136
- const dir = path.join(projectDir, "docs", "memory", "inbox");
137
- return { dir, file: path.join(dir, `${actor}.md`) };
138
- }
139
-
140
- // True when this session already wrote an inbox entry (SessionEnd re-fires on resume).
141
- function alreadyReflected(file, sessionId) {
142
- try {
143
- return Boolean(sessionId) && fs.existsSync(file) && fs.readFileSync(file, "utf8").includes(`session ${sessionId}`);
144
- } catch (e) {
145
- return false;
146
- }
147
- }
148
-
149
- // Build the inbox file header block.
150
- function inboxHeader(actor) {
151
- return `# Memory inbox — ${actor}\nSession lessons awaiting distillation — appended by the session-reflect hook, consumed by \`distiller facts\`.\n`;
152
- }
153
-
154
- // The full output contract sits AFTER the transcript — with it only up front, the model
155
- // continues the conversation in the transcript instead of reflecting on it.
156
- const PROMPT_HEADER = [
157
- "You are a memory reflector. Below is the transcript of a FINISHED coding session,",
158
- "delimited by <transcript> tags. Do not reply to it or continue it — you will be asked",
159
- "to extract durable lessons from it after the closing tag.",
160
- "",
161
- "<transcript>",
162
- "",
163
- ].join("\n");
164
-
165
- const PROMPT_FOOTER = [
166
- "",
167
- "</transcript>",
168
- "",
169
- "The session above is over. Extract ONLY durable lessons a future session in this",
170
- "repository would benefit from knowing:",
171
- "- corrections or preferences the user stated",
172
- "- failures whose root cause was found, with the fix",
173
- "- decisions made, with their rationale",
174
- "- discovered constraints or non-obvious facts about the project or its tooling",
175
- "Rules:",
176
- "- Most sessions contain none. If nothing qualifies, output exactly: NONE",
177
- `- Otherwise output at most ${MAX_LESSONS} bullets and nothing else — no preamble, no headers.`,
178
- '- Each bullet starts with "- [project]" (true of this repo or its tooling) or "- [user]" (true of this user).',
179
- "- Each bullet is one complete, self-contained sentence with names and identifiers spelled out.",
180
- "- Routine work (commits made, files edited, tasks completed) is NOT a lesson. Never include secrets.",
181
- ].join("\n");
182
-
183
- // Hook mode: stash the payload and hand off to a detached worker so session exit is never delayed.
184
- function hook() {
185
- const raw = readStdin();
186
- let payload = {};
187
- try {
188
- payload = raw ? JSON.parse(raw) : {};
189
- } catch (e) {
190
- payload = {};
191
- }
192
- if (!payload.transcript_path) return;
193
-
194
- const stash = {
195
- projectDir: resolveProjectDir(payload),
196
- transcriptPath: payload.transcript_path,
197
- sessionId: payload.session_id || "",
198
- };
199
- const stashFile = path.join(os.tmpdir(), `etna-reflect-${stash.sessionId || process.pid}.json`);
200
- fs.writeFileSync(stashFile, JSON.stringify(stash), "utf8");
201
- spawn(process.execPath, [__filename, "--worker", stashFile], { detached: true, stdio: "ignore" }).unref();
202
- }
203
-
204
- // Worker mode: filter, digest, run the reflection model, append surviving lessons to the inbox.
205
- function worker(stashFile) {
206
- let stash;
207
- try {
208
- stash = JSON.parse(fs.readFileSync(stashFile, "utf8"));
209
- } finally {
210
- try {
211
- fs.rmSync(stashFile, { force: true });
212
- } catch (e) {
213
- // Stale stash files are harmless.
214
- }
215
- }
216
-
217
- const { projectDir, transcriptPath, sessionId } = stash;
218
- const digest = digestTranscript(transcriptPath);
219
- if (digest.turns < MIN_TURNS && digest.files.size === 0 && !digest.sawCommit) return;
220
-
221
- const actor = resolveActor(projectDir);
222
- const { dir, file } = inboxPath(projectDir, actor);
223
- if (alreadyReflected(file, sessionId)) return;
224
-
225
- let text = redact(digest.lines.join("\n"));
226
- if (text.length > MAX_DIGEST_CHARS) {
227
- text = text.slice(0, 8000) + "\n[... middle of session elided ...]\n" + text.slice(-(MAX_DIGEST_CHARS - 8000));
228
- }
229
-
230
- const output = execFileSync("claude", ["-p", "--model", "haiku"], {
231
- input: PROMPT_HEADER + text + PROMPT_FOOTER,
232
- encoding: "utf8",
233
- cwd: os.tmpdir(),
234
- env: Object.assign({}, process.env, { ETNA_REFLECT: "1" }),
235
- timeout: 240000,
236
- maxBuffer: 4 * 1024 * 1024,
237
- stdio: ["pipe", "pipe", "ignore"],
238
- });
239
-
240
- const lessons = output
241
- .split("\n")
242
- .map((l) => l.trim())
243
- .filter((l) => /^- \[(project|user)\]\s+\S/.test(l))
244
- .slice(0, MAX_LESSONS)
245
- .map((l) => redact(l));
246
- if (!lessons.length) return;
247
-
248
- const repo = path.basename(projectDir);
249
- const branch = git(projectDir, ["rev-parse", "--abbrev-ref", "HEAD"], "-");
250
- const now = new Date();
251
- const pad = (n) => String(n).padStart(2, "0");
252
- const stamp = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())} ${pad(now.getHours())}:${pad(now.getMinutes())}`;
253
-
254
- fs.mkdirSync(dir, { recursive: true });
255
- if (alreadyReflected(file, sessionId)) return;
256
- const exists = fs.existsSync(file);
257
- const block =
258
- (exists ? "\n" : inboxHeader(actor) + "\n") +
259
- `## ${stamp} · session ${sessionId || "unknown"} · ${repo}@${branch}\n` +
260
- lessons.join("\n") +
261
- "\n";
262
- fs.appendFileSync(file, block, "utf8");
263
- }
264
-
265
- function main() {
266
- if (process.env.ETNA_REFLECT) return;
267
- const workerIdx = process.argv.indexOf("--worker");
268
- if (workerIdx !== -1) {
269
- worker(process.argv[workerIdx + 1]);
270
- } else {
271
- hook();
272
- }
273
- }
274
-
275
- try {
276
- main();
277
- } catch (e) {
278
- try {
279
- process.stderr.write(`session-reflect hook: ${e && e.message ? e.message : e}\n`);
280
- } catch (e2) {
281
- // Nothing more we can do.
282
- }
283
- } finally {
284
- process.exit(0);
285
- }
@@ -1,79 +0,0 @@
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
- - **@nurix/components** — the UI component library (linked, pre-built); import by subpath, e.g. `@nurix/components/button`.
53
- - No components.json / shadcn CLI scaffold (.tsx, not .jsx) — consume the prebuilt library; never `npx shadcn add`.
54
- - 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` (linked @nurix/* ship nested react — keep one hook dispatcher).
55
- - Tailwind v4, CSS-only (no tailwind.config.js, no PostCSS): styling runs through the `@tailwindcss/vite` plugin.
56
- - 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.
57
- - 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 supports dark mode). The library bundles class-variance-authority, clsx, tailwind-merge.
58
- - Plus general styling rules (spacing in 2/4/6/8, object-cover, truncate, motion, color tokens — never hardcoded hex in components).
59
-
60
- ## Express 5.x
61
-
62
- ```javascript
63
- app.use(cors({ origin: process.env.FRONTEND_URL }));
64
- app.use(compression());
65
- app.use(express.json({ limit: "10mb" }));
66
- app.use(rateLimit({ windowMs: 15 * 60 * 1000, max: 100 }));
67
- ```
68
-
69
- - Middleware order: body parsers → custom middleware → routes → error handlers (centralized, last). Auth via middleware. Use Express Router for modular routes.
70
-
71
- ## API Response Format
72
-
73
- ```json
74
- { "status": 1, "message": "Message sent successfully", "data": { "delivered": [{ "user@example.com": 2 }] } }
75
- ```
76
-
77
- Error: `{ "status": 0, "message": "Error description", "data": null }`
78
-
79
- HTTP codes: `200`, `201` (created), `400`, `401` (not authenticated), `403` (not authorized), `404`, `500`
@@ -1,30 +0,0 @@
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`
@@ -1,19 +0,0 @@
1
- # TypeScript
2
-
3
- TypeScript conventions. Compiles under `strict: true` and `noUncheckedIndexedAccess: true`.
4
-
5
- ## Type Safety
6
-
7
- - Never `any` to silence the checker. Unknown value → type `unknown`, then narrow (type guard / `zod` parse).
8
- - Never weaken strictness. No `// @ts-nocheck`; `// @ts-expect-error` only with a same-line reason.
9
- - Infer locals & return types; annotate at boundaries (exports, props, contracts).
10
-
11
- ## Generics
12
-
13
- Shared libraries (`@nurix/components`, etc.) are generic on purpose — that's what types `cell(row)`, checks `slug` against `keyof TData`, and ties `data`/`columns` together. Keep the safety; never widen to `any` to dodge it. State the row type **once per file**, then let inference carry it:
14
-
15
- - **Bind a repeated factory once** (preferred): `const col = defineColumn<BriefRow>;` → `col({...})`. No `<T>` per call; `row` stays typed. Canonical: `modules/briefs/BriefsListPage.tsx`.
16
- - **Infer JSX type args from props:** `<Table data={rows} columns={columns} />`, not `<Table<BriefRow> …>`.
17
- - **Anchor with a collection annotation** when nothing else can: `const columns: ColumnDefinition<BriefRow>[] = [...]`.
18
-
19
- Don't repeat `fn<Type>(…)` / `<Comp<Type>>` at every call site — cosmetic only (same safety, same emitted JS).
@@ -1,76 +0,0 @@
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
11
- share an assumption with **no compile-time link** between them: the column a raw
12
- SQL string names, the JSON envelope a client unwraps, the event string a
13
- dispatcher parses, the env var a deploy script writes. Changing one side ships
14
- green and breaks the other silently. Your job is to find those edges in the
15
- plan's path *before* execution.
16
-
17
- [`references/boundary-taxonomy.md`](references/boundary-taxonomy.md) is the
18
- catalog of boundary types (~170 across persistence, wire/API, frontend,
19
- auth/tenancy, async/messaging, config/build, runtime/infra), with per-type
20
- severities and safe-change checklists. Read it first — it tells you what to
21
- look for; the code tells you what exists.
22
-
23
- ## Run
24
-
25
- **Input:** a plan path (given, or the newest in `docs/history/plans/`) — or a
26
- diff / named code area for non-plan work. Everything below is identical either
27
- way; a diff's hunks stand in for the plan's steps.
28
-
29
- 1. **Build the touch list.** Parse the plan's Proposed Changes: files to be
30
- created or modified, entities/state added or changed, API changes, anything
31
- the author flags as a cross-module contract. Note missing subsections.
32
-
33
- 2. **Identify the boundaries in the touched code.** Read each touched file (and
34
- its immediate imports). Against the taxonomy, list the contracts this code
35
- participates in — the schema it queries, the envelope it emits, the events
36
- it publishes or parses, the auth checks it sits behind, the env it reads.
37
-
38
- 3. **Trace the other side.** A boundary has two sides; the danger lives on the
39
- one the plan *doesn't* mention. For each contract, grep the shared name or
40
- shape across the repo — the column name in other SQL strings, the response
41
- field in client unwrappers, the event kind in subscribers, the route in
42
- fetch calls and scripts, the env key in deploy tooling. Record consumers as
43
- `file:line`.
44
-
45
- 4. **Judge each intersection.** Does the planned change alter a shape a traced
46
- consumer depends on, break an invariant the code establishes (append-only
47
- vocabularies, idempotency keys, fail-closed checks, ordering guarantees), or
48
- add a new cross-module edge? Severity:
49
- - **CRITICAL** — can corrupt persisted data, or open an auth/money path.
50
- - **HIGH** — silent cross-module breakage that would ship green.
51
- - **MEDIUM** — drift-prone coupling (string-matched, duplicated constants).
52
- - **LOW** — smell. Loud, immediately-visible breakage caps at HIGH.
53
-
54
- 5. **Report in chat:**
55
-
56
- ```
57
- # Boundary check — {plan}
58
-
59
- Touched files read: {N} · Boundaries identified: {N}
60
- Violations: {N} ({critical}/{high}/{medium}/{low})
61
-
62
- | # | Boundary | Planned change | Other side (file:line) | Severity |
63
-
64
- ## Suggested plan amendments
65
- ## Missing plan subsections
66
- ```
67
-
68
- ## Rules
69
-
70
- - **Read-only.** You never edit the plan, the code, or any doc. The user folds
71
- your amendments into the plan.
72
- - **Verify in source.** Never flag from plan text alone — read both sides of
73
- every boundary you report, and cite both as `file:line`.
74
- - **No consumer, no finding.** An intersection with no traced other side isn't
75
- a violation; at most note it as a new edge the plan introduces.
76
- - **A clean report is valid.** Zero violations means say so — don't pad.