@nurix/etna 0.15.7 → 0.16.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 +64 -13
- package/data/harness-index.json +7 -5
- package/data/harnesses/code/CLAUDE.md +3 -7
- package/data/harnesses/code/agents/harness-manager.md +4 -4
- package/data/harnesses/code/agents/maintenance.md +1 -1
- package/data/harnesses/code/harness.json +4 -3
- package/data/harnesses/code/hooks/hooks.json +3 -17
- package/data/harnesses/code/hooks/prompt-recall.js +157 -0
- package/data/harnesses/code/hooks/session-reflect.js +283 -0
- package/data/harnesses/code/skills/distiller/SKILL.md +62 -60
- package/data/harnesses/code/skills/distiller/references/docs-mode.md +21 -21
- package/data/harnesses/code/skills/distiller/references/method.md +41 -41
- package/data/harnesses/code/skills/documentation/references/templates.md +20 -27
- package/data/harnesses/code-fable/CLAUDE.md +138 -0
- package/data/harnesses/code-fable/agents/brainstorm.md +35 -0
- package/data/harnesses/code-fable/agents/change-review.md +249 -0
- package/data/harnesses/code-fable/agents/harness-manager.md +193 -0
- package/data/harnesses/code-fable/agents/maintenance.md +123 -0
- package/data/harnesses/code-fable/agents/performance-review.md +218 -0
- package/data/harnesses/code-fable/agents/spec-mode.md +56 -0
- package/data/harnesses/code-fable/harness.json +7 -0
- package/data/harnesses/code-fable/hooks/hooks.json +27 -0
- package/data/harnesses/code-fable/hooks/lib/redact.js +37 -0
- package/data/harnesses/code-fable/hooks/prompt-recall.js +157 -0
- package/data/harnesses/code-fable/hooks/session-reflect.js +283 -0
- package/data/harnesses/code-fable/rules/general.md +96 -0
- package/data/harnesses/code-fable/rules/nomenclature.md +34 -0
- package/data/harnesses/code-fable/skills/boundary/SKILL.md +262 -0
- package/data/harnesses/code-fable/skills/boundary/references/boundary-taxonomy.md +734 -0
- package/data/harnesses/code-fable/skills/brainstorm/README.md +136 -0
- package/data/harnesses/code-fable/skills/brainstorm/SKILL.md +135 -0
- package/data/harnesses/code-fable/skills/brainstorm/harvest.md +26 -0
- package/data/harnesses/code-fable/skills/brainstorm/templates/backlog.md +39 -0
- package/data/harnesses/code-fable/skills/brainstorm/templates/build.md +37 -0
- package/data/harnesses/code-fable/skills/brainstorm/templates/decisions.md +29 -0
- package/data/harnesses/code-fable/skills/brainstorm/templates/doctrine.md +31 -0
- package/data/harnesses/code-fable/skills/brainstorm/templates/domain-model.md +25 -0
- package/data/harnesses/code-fable/skills/brainstorm/templates/glossary.md +19 -0
- package/data/harnesses/code-fable/skills/brainstorm/templates/milestones.md +43 -0
- package/data/harnesses/code-fable/skills/brainstorm/templates/non-goals.md +21 -0
- package/data/harnesses/code-fable/skills/brainstorm/templates/plan-doc.md +61 -0
- package/data/harnesses/code-fable/skills/brainstorm/templates/questions.md +35 -0
- package/data/harnesses/code-fable/skills/brainstorm/templates/references.md +28 -0
- package/data/harnesses/code-fable/skills/brainstorm/templates/rejected.md +29 -0
- package/data/harnesses/code-fable/skills/brainstorm/templates/state.md +8 -0
- package/data/harnesses/code-fable/skills/brainstorm/templates/tech.md +23 -0
- package/data/harnesses/code-fable/skills/brainstorm/templates/thesis.md +21 -0
- package/data/harnesses/code-fable/skills/distiller/SKILL.md +219 -0
- package/data/harnesses/code-fable/skills/distiller/references/docs-mode.md +526 -0
- package/data/harnesses/code-fable/skills/distiller/references/method.md +166 -0
- package/data/harnesses/code-fable/skills/documentation/SKILL.md +127 -0
- package/data/harnesses/code-fable/skills/documentation/references/examples.md +193 -0
- package/data/harnesses/code-fable/skills/documentation/references/style-guide.md +288 -0
- package/data/harnesses/code-fable/skills/documentation/references/templates.md +942 -0
- package/data/harnesses/code-fable/skills/workflow-mapper/SKILL.md +430 -0
- package/data/harnesses/code-fable/skills/workflow-mapper/references/patterns.md +214 -0
- package/data/harnesses/{re → discover}/CLAUDE.md +48 -33
- package/data/harnesses/{re → discover}/agents/api.md +3 -3
- package/data/harnesses/{re → discover}/agents/codebase.md +3 -3
- package/data/harnesses/{re → discover}/agents/community.md +3 -3
- package/data/harnesses/{re → discover}/agents/deployed-client-bundle.md +5 -5
- package/data/harnesses/{re → discover}/agents/distribution-artifacts.md +4 -4
- package/data/harnesses/{re → discover}/agents/docs.md +3 -3
- package/data/harnesses/{re → discover}/agents/infra-backend-fingerprint.md +2 -2
- package/data/harnesses/{re → discover}/agents/packages.md +3 -3
- package/data/harnesses/{re → discover}/agents/session.md +19 -11
- package/data/harnesses/{re → discover}/agents/website.md +3 -3
- package/data/harnesses/{re → discover}/agents/wire-capture.md +9 -7
- package/data/harnesses/discover/harness.json +7 -0
- package/data/harnesses/{re/rules/re-discovery.md → discover/rules/discovery.md} +54 -17
- package/data/harnesses/{re/rules/re-evaluation.md → discover/rules/evaluation.md} +12 -1
- package/data/harnesses/{re/rules/re-ingestion.md → discover/rules/ingestion.md} +192 -23
- package/data/harnesses/discover/rules/self-correction.md +177 -0
- package/data/harnesses/discover/rules/tradecraft.md +532 -0
- package/data/harnesses/hr/CLAUDE.md +91 -0
- package/data/harnesses/hr/harness.json +7 -0
- package/data/harnesses/hr/skills/interview-eval/SKILL.md +118 -0
- package/data/harnesses/hr/skills/interview-eval/TEMPLATE.md +124 -0
- package/data/harnesses/hr/skills/interview-eval/extract_session.py +418 -0
- package/data/harnesses/hr/skills/interview-eval/rubric.md +219 -0
- package/data/harnesses/kb-agi/harness.json +1 -0
- package/package.json +1 -1
- package/data/harnesses/code/hooks/post-commit.js +0 -136
- package/data/harnesses/code/hooks/post-tool-failure.js +0 -136
- package/data/harnesses/code/hooks/session-stop.js +0 -207
- package/data/harnesses/re/harness.json +0 -6
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
// harness/code/hooks/session-stop.js — SessionEnd hook: append one cheap session-summary ledger entry.
|
|
2
|
-
|
|
3
|
-
"use strict";
|
|
4
|
-
|
|
5
|
-
const fs = require("fs");
|
|
6
|
-
const path = require("path");
|
|
7
|
-
const os = require("os");
|
|
8
|
-
const { execFileSync } = require("child_process");
|
|
9
|
-
const { redact } = require("./lib/redact.js");
|
|
10
|
-
|
|
11
|
-
// Read all of stdin synchronously; returns "" if nothing is piped.
|
|
12
|
-
function readStdin() {
|
|
13
|
-
try {
|
|
14
|
-
return fs.readFileSync(0, "utf8");
|
|
15
|
-
} catch (e) {
|
|
16
|
-
return "";
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
// Resolve the project root: CLAUDE_PROJECT_DIR env, else payload cwd, else process cwd.
|
|
21
|
-
function resolveProjectDir(payload) {
|
|
22
|
-
return process.env.CLAUDE_PROJECT_DIR || (payload && payload.cwd) || process.cwd();
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Run a git command in projectDir; returns trimmed stdout or fallback on any error.
|
|
26
|
-
function git(projectDir, args, fallback) {
|
|
27
|
-
try {
|
|
28
|
-
return execFileSync("git", ["-C", projectDir, ...args], {
|
|
29
|
-
encoding: "utf8",
|
|
30
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
31
|
-
}).trim() || fallback;
|
|
32
|
-
} catch (e) {
|
|
33
|
-
return fallback;
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// Slug a raw actor name into kebab-case ASCII.
|
|
38
|
-
function slugActor(name) {
|
|
39
|
-
return String(name || "")
|
|
40
|
-
.toLowerCase()
|
|
41
|
-
.replace(/[^a-z0-9]+/g, "-")
|
|
42
|
-
.replace(/^-+|-+$/g, "");
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
// Determine the actor: git user.name (slugged) → $USER → "agent".
|
|
46
|
-
function resolveActor(projectDir) {
|
|
47
|
-
const fromGit = slugActor(git(projectDir, ["config", "user.name"], ""));
|
|
48
|
-
if (fromGit) return fromGit;
|
|
49
|
-
const fromEnv = slugActor(process.env.USER || "");
|
|
50
|
-
if (fromEnv) return fromEnv;
|
|
51
|
-
return "agent";
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// Truncate a single line to n chars with an ellipsis marker.
|
|
55
|
-
function truncate(text, n) {
|
|
56
|
-
const clean = String(text || "").replace(/\s+/g, " ").trim();
|
|
57
|
-
return clean.length > n ? clean.slice(0, n) + "…" : clean;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
// Parse the JSONL transcript into a cheap mechanical summary.
|
|
61
|
-
function summarizeTranscript(transcriptPath) {
|
|
62
|
-
const summary = { firstPrompt: "", assistantTurns: 0, files: new Set(), lastAssistant: "", sawCommit: false };
|
|
63
|
-
try {
|
|
64
|
-
if (!transcriptPath || !fs.existsSync(transcriptPath)) return summary;
|
|
65
|
-
const lines = fs.readFileSync(transcriptPath, "utf8").split("\n");
|
|
66
|
-
for (const line of lines) {
|
|
67
|
-
if (!line.trim()) continue;
|
|
68
|
-
let row;
|
|
69
|
-
try {
|
|
70
|
-
row = JSON.parse(line);
|
|
71
|
-
} catch (e) {
|
|
72
|
-
continue;
|
|
73
|
-
}
|
|
74
|
-
const msg = row && row.message ? row.message : row;
|
|
75
|
-
const role = (msg && msg.role) || row.type;
|
|
76
|
-
if (role === "user" && !summary.firstPrompt) {
|
|
77
|
-
summary.firstPrompt = extractText(msg);
|
|
78
|
-
}
|
|
79
|
-
if (role === "assistant") {
|
|
80
|
-
summary.assistantTurns += 1;
|
|
81
|
-
const text = extractText(msg);
|
|
82
|
-
if (text) summary.lastAssistant = text;
|
|
83
|
-
collectToolUse(msg, summary);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
} catch (e) {
|
|
87
|
-
// Best-effort summary; ignore parse issues.
|
|
88
|
-
}
|
|
89
|
-
return summary;
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// Extract plain text from a message whose content is a string or content-block array.
|
|
93
|
-
function extractText(msg) {
|
|
94
|
-
if (!msg || !msg.content) return "";
|
|
95
|
-
if (typeof msg.content === "string") return msg.content;
|
|
96
|
-
if (Array.isArray(msg.content)) {
|
|
97
|
-
return msg.content
|
|
98
|
-
.filter((b) => b && b.type === "text" && typeof b.text === "string")
|
|
99
|
-
.map((b) => b.text)
|
|
100
|
-
.join(" ");
|
|
101
|
-
}
|
|
102
|
-
return "";
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Scan an assistant message's tool_use blocks for edited files and git commits.
|
|
106
|
-
function collectToolUse(msg, summary) {
|
|
107
|
-
if (!msg || !Array.isArray(msg.content)) return;
|
|
108
|
-
for (const block of msg.content) {
|
|
109
|
-
if (!block || block.type !== "tool_use") continue;
|
|
110
|
-
const name = block.name || "";
|
|
111
|
-
const input = block.input || {};
|
|
112
|
-
if (/^(Edit|Write|MultiEdit|NotebookEdit)$/.test(name) && input.file_path) {
|
|
113
|
-
summary.files.add(input.file_path);
|
|
114
|
-
}
|
|
115
|
-
if (name === "Bash" && typeof input.command === "string" && /\bgit\s+commit\b/.test(input.command)) {
|
|
116
|
-
summary.sawCommit = true;
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
// Compute the ledger day-file path for a given actor and date.
|
|
122
|
-
function ledgerPath(projectDir, date, actor) {
|
|
123
|
-
const dir = path.join(projectDir, "docs", "memory", "ledger");
|
|
124
|
-
return { dir, file: path.join(dir, `${date}--${actor}.md`) };
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Build the day-file header block.
|
|
128
|
-
function header(date, actor) {
|
|
129
|
-
return `# Ledger — ${date} — ${actor}\nAppend-only event ledger. Raw input to distillation — see docs/memory/.\n`;
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
// Skip if the day-file's last entry was written by this session within the current minute.
|
|
133
|
-
function isDuplicate(file, sessionId, hhmm) {
|
|
134
|
-
try {
|
|
135
|
-
if (!sessionId || !fs.existsSync(file)) return false;
|
|
136
|
-
const text = fs.readFileSync(file, "utf8");
|
|
137
|
-
const idx = text.lastIndexOf("\n## ");
|
|
138
|
-
const tail = idx >= 0 ? text.slice(idx) : text;
|
|
139
|
-
return tail.includes(`session ${sessionId}`) && tail.includes(`## ${hhmm} `);
|
|
140
|
-
} catch (e) {
|
|
141
|
-
return false;
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
// Main: assemble and append one session-summary entry, never blocking.
|
|
146
|
-
function main() {
|
|
147
|
-
const raw = readStdin();
|
|
148
|
-
let payload = {};
|
|
149
|
-
try {
|
|
150
|
-
payload = raw ? JSON.parse(raw) : {};
|
|
151
|
-
} catch (e) {
|
|
152
|
-
payload = {};
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
const projectDir = resolveProjectDir(payload);
|
|
156
|
-
const actor = resolveActor(projectDir);
|
|
157
|
-
const repo = path.basename(projectDir);
|
|
158
|
-
const branch = git(projectDir, ["rev-parse", "--abbrev-ref", "HEAD"], "-");
|
|
159
|
-
|
|
160
|
-
const now = new Date();
|
|
161
|
-
const pad = (n) => String(n).padStart(2, "0");
|
|
162
|
-
const date = `${now.getFullYear()}-${pad(now.getMonth() + 1)}-${pad(now.getDate())}`;
|
|
163
|
-
const hhmm = `${pad(now.getHours())}:${pad(now.getMinutes())}`;
|
|
164
|
-
|
|
165
|
-
const summary = summarizeTranscript(payload.transcript_path);
|
|
166
|
-
const sessionId = payload.session_id || "";
|
|
167
|
-
|
|
168
|
-
// Nothing meaningful to record (garbage/empty payload, unreadable transcript) → silent no-op.
|
|
169
|
-
if (summary.assistantTurns === 0 && !summary.firstPrompt) return;
|
|
170
|
-
|
|
171
|
-
const { dir, file } = ledgerPath(projectDir, date, actor);
|
|
172
|
-
if (isDuplicate(file, sessionId, hhmm)) return;
|
|
173
|
-
|
|
174
|
-
const type = summary.sawCommit ? "decision" : summary.assistantTurns > 0 ? "action" : "observation";
|
|
175
|
-
const fileCount = summary.files.size;
|
|
176
|
-
const whatBits = [];
|
|
177
|
-
if (summary.firstPrompt) whatBits.push(`task "${truncate(redact(summary.firstPrompt), 100)}"`);
|
|
178
|
-
whatBits.push(`${summary.assistantTurns} turns`);
|
|
179
|
-
if (fileCount) whatBits.push(`${fileCount} file${fileCount === 1 ? "" : "s"} edited`);
|
|
180
|
-
const what = whatBits.join(", ") || "session ended";
|
|
181
|
-
|
|
182
|
-
const lines = [`## ${hhmm} · ${actor} · ${repo}@${branch}`, `- type: ${type}`, `- what: ${redact(what)}`];
|
|
183
|
-
if (summary.lastAssistant) {
|
|
184
|
-
lines.push(`- why: ${truncate(redact(summary.lastAssistant), 100)}`);
|
|
185
|
-
}
|
|
186
|
-
const refs = [];
|
|
187
|
-
if (sessionId) refs.push(`session ${sessionId}`);
|
|
188
|
-
if (fileCount) refs.push(`${fileCount} files`);
|
|
189
|
-
if (refs.length) lines.push(`- refs: ${redact(refs.join(" · "))}`);
|
|
190
|
-
|
|
191
|
-
const exists = fs.existsSync(file);
|
|
192
|
-
fs.mkdirSync(dir, { recursive: true });
|
|
193
|
-
const block = (exists ? "\n" : header(date, actor) + "\n") + lines.join("\n") + "\n";
|
|
194
|
-
fs.appendFileSync(file, block, "utf8");
|
|
195
|
-
}
|
|
196
|
-
|
|
197
|
-
try {
|
|
198
|
-
main();
|
|
199
|
-
} catch (e) {
|
|
200
|
-
try {
|
|
201
|
-
process.stderr.write(`session-stop hook: ${e && e.message ? e.message : e}\n`);
|
|
202
|
-
} catch (e2) {
|
|
203
|
-
// Nothing more we can do.
|
|
204
|
-
}
|
|
205
|
-
} finally {
|
|
206
|
-
process.exit(0);
|
|
207
|
-
}
|