@nirnex/cli 3.0.0 → 4.0.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.
Files changed (48) hide show
  1. package/dist/commands/runtime.d.ts +2 -0
  2. package/dist/commands/runtime.d.ts.map +1 -0
  3. package/dist/commands/runtime.js +60 -0
  4. package/dist/commands/runtime.js.map +1 -0
  5. package/dist/commands/setup.d.ts.map +1 -1
  6. package/dist/commands/setup.js +99 -0
  7. package/dist/commands/setup.js.map +1 -1
  8. package/dist/commands/status.d.ts.map +1 -1
  9. package/dist/commands/status.js +69 -1
  10. package/dist/commands/status.js.map +1 -1
  11. package/dist/commands/trace.d.ts.map +1 -1
  12. package/dist/commands/trace.js +74 -1
  13. package/dist/commands/trace.js.map +1 -1
  14. package/dist/index.js +12 -7
  15. package/dist/index.js.map +1 -1
  16. package/dist/runtime/bootstrap.d.ts +2 -0
  17. package/dist/runtime/bootstrap.d.ts.map +1 -0
  18. package/dist/runtime/bootstrap.js +90 -0
  19. package/dist/runtime/bootstrap.js.map +1 -0
  20. package/dist/runtime/entry.d.ts +2 -0
  21. package/dist/runtime/entry.d.ts.map +1 -0
  22. package/dist/runtime/entry.js +86 -0
  23. package/dist/runtime/entry.js.map +1 -0
  24. package/dist/runtime/envelope.d.ts +4 -0
  25. package/dist/runtime/envelope.d.ts.map +1 -0
  26. package/dist/runtime/envelope.js +113 -0
  27. package/dist/runtime/envelope.js.map +1 -0
  28. package/dist/runtime/guard.d.ts +2 -0
  29. package/dist/runtime/guard.d.ts.map +1 -0
  30. package/dist/runtime/guard.js +114 -0
  31. package/dist/runtime/guard.js.map +1 -0
  32. package/dist/runtime/session.d.ts +13 -0
  33. package/dist/runtime/session.d.ts.map +1 -0
  34. package/dist/runtime/session.js +111 -0
  35. package/dist/runtime/session.js.map +1 -0
  36. package/dist/runtime/trace-hook.d.ts +2 -0
  37. package/dist/runtime/trace-hook.d.ts.map +1 -0
  38. package/dist/runtime/trace-hook.js +102 -0
  39. package/dist/runtime/trace-hook.js.map +1 -0
  40. package/dist/runtime/types.d.ts +108 -0
  41. package/dist/runtime/types.d.ts.map +1 -0
  42. package/dist/runtime/types.js +3 -0
  43. package/dist/runtime/types.js.map +1 -0
  44. package/dist/runtime/validate.d.ts +2 -0
  45. package/dist/runtime/validate.d.ts.map +1 -0
  46. package/dist/runtime/validate.js +91 -0
  47. package/dist/runtime/validate.js.map +1 -0
  48. package/package.json +1 -1
@@ -0,0 +1,86 @@
1
+ // UserPromptSubmit hook handler.
2
+ // Called before Claude processes each user prompt.
3
+ // Builds ECO from the prompt, creates a task envelope, writes session state,
4
+ // and returns additionalContext so Claude sees the envelope before acting.
5
+ import fs from 'node:fs';
6
+ import path from 'node:path';
7
+ import { buildEnvelope, formatEnvelopeContext } from './envelope.js';
8
+ import { loadSession, saveSession, saveEnvelope } from './session.js';
9
+ function readStdin() {
10
+ return new Promise(resolve => {
11
+ let buf = '';
12
+ process.stdin.setEncoding('utf8');
13
+ process.stdin.on('data', chunk => { buf += chunk; });
14
+ process.stdin.on('end', () => resolve(buf));
15
+ });
16
+ }
17
+ export async function runEntry() {
18
+ const raw = await readStdin();
19
+ let hookData = {
20
+ session_id: 'unknown',
21
+ hook_event_name: 'UserPromptSubmit',
22
+ prompt: '',
23
+ };
24
+ try {
25
+ hookData = JSON.parse(raw || '{}');
26
+ }
27
+ catch {
28
+ // Non-fatal: proceed with empty prompt
29
+ }
30
+ const repoRoot = process.env.NIRNEX_REPO_ROOT ?? process.cwd();
31
+ const sessionId = hookData.session_id ?? process.env.NIRNEX_SESSION_ID ?? `sess_${Date.now().toString(36)}`;
32
+ const prompt = hookData.prompt ?? '';
33
+ // Skip if not a Nirnex project
34
+ if (!fs.existsSync(path.join(repoRoot, 'nirnex.config.json'))) {
35
+ process.exit(0);
36
+ }
37
+ // Skip very short or empty prompts (e.g. clarifications, single words)
38
+ if (prompt.trim().length < 10) {
39
+ process.exit(0);
40
+ }
41
+ let eco = {};
42
+ try {
43
+ const { buildECO } = await import('@nirnex/core/dist/eco.js');
44
+ eco = buildECO(null, repoRoot, { query: prompt });
45
+ }
46
+ catch {
47
+ // Degraded mode: use a minimal ECO
48
+ eco = {
49
+ recommended_lane: 'A',
50
+ forced_lane_minimum: 'A',
51
+ confidence_score: 50,
52
+ forced_unknown: false,
53
+ blocked: false,
54
+ intent: { primary: 'unknown' },
55
+ modules_touched: [],
56
+ penalties: [],
57
+ escalation_reasons: [],
58
+ boundary_warnings: [],
59
+ eco_dimensions: {},
60
+ evidence_checkpoints: {},
61
+ };
62
+ }
63
+ const envelope = buildEnvelope(eco, prompt, sessionId);
64
+ // Persist envelope and link to session
65
+ saveEnvelope(repoRoot, envelope);
66
+ const session = loadSession(repoRoot, sessionId);
67
+ if (session) {
68
+ session.active_task_id = envelope.task_id;
69
+ session.tasks.push(envelope.task_id);
70
+ saveSession(repoRoot, session);
71
+ }
72
+ // Block if ECO says blocked
73
+ if (eco.blocked) {
74
+ const output = {
75
+ blockMessage: `[Nirnex] Task blocked by ECO. Reasons: ${(eco.escalation_reasons ?? []).join('; ') || 'unknown'}. Please revise the spec or run nirnex plan for details.`,
76
+ };
77
+ process.stdout.write(JSON.stringify(output));
78
+ process.exit(0);
79
+ }
80
+ // Return envelope context to Claude
81
+ const contextText = formatEnvelopeContext(envelope);
82
+ const output = { additionalContext: contextText };
83
+ process.stdout.write(JSON.stringify(output));
84
+ process.exit(0);
85
+ }
86
+ //# sourceMappingURL=entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"entry.js","sourceRoot":"","sources":["../../src/runtime/entry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import { TaskEnvelope } from './types.js';
2
+ export declare function buildEnvelope(eco: Record<string, any>, prompt: string, sessionId: string): TaskEnvelope;
3
+ export declare function formatEnvelopeContext(envelope: TaskEnvelope): string;
4
+ //# sourceMappingURL=envelope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.d.ts","sourceRoot":"","sources":["../../src/runtime/envelope.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAQ,MAAM,YAAY,CAAC;AAyBhD,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,YAAY,CAmEvG;AAED,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,YAAY,GAAG,MAAM,CA0BpE"}
@@ -0,0 +1,113 @@
1
+ // Converts an ECO (Execution Context Object) into a TaskEnvelope (TEE).
2
+ // The envelope is the actionable, policy-bearing runtime representation.
3
+ import { generateTaskId } from './session.js';
4
+ import { getConfidenceLabel } from '@nirnex/core/dist/confidence.js';
5
+ const LANE_TOOL_POLICY = {
6
+ A: {
7
+ allowed_tools: ['Read', 'Glob', 'Grep', 'Bash', 'Edit', 'Write', 'MultiEdit', 'NotebookEdit', 'WebFetch', 'WebSearch'],
8
+ requires_guard: [],
9
+ denied_patterns: [],
10
+ },
11
+ B: {
12
+ allowed_tools: ['Read', 'Glob', 'Grep', 'Bash', 'Edit', 'Write', 'MultiEdit', 'NotebookEdit', 'WebFetch', 'WebSearch'],
13
+ requires_guard: ['Edit', 'Write', 'MultiEdit'],
14
+ denied_patterns: ['rm -rf', 'git reset --hard', 'git push --force', 'git push -f'],
15
+ },
16
+ C: {
17
+ allowed_tools: ['Read', 'Glob', 'Grep', 'Bash', 'Edit', 'Write', 'MultiEdit', 'NotebookEdit', 'WebFetch', 'WebSearch'],
18
+ requires_guard: ['Bash', 'Edit', 'Write', 'MultiEdit'],
19
+ denied_patterns: [
20
+ 'rm -rf', 'git reset --hard', 'git push --force', 'git push -f',
21
+ 'DROP TABLE', 'ALTER TABLE', 'truncate', '> /dev/null 2>&1 &',
22
+ ],
23
+ },
24
+ };
25
+ export function buildEnvelope(eco, prompt, sessionId) {
26
+ const lane = (eco.recommended_lane ?? eco.forced_lane_minimum ?? 'A');
27
+ const taskId = generateTaskId();
28
+ // Derive scope from ECO
29
+ const modulesTouched = eco.modules_touched ?? [];
30
+ const blockedPaths = [
31
+ ...(eco.boundary_warnings ?? []).map((w) => w.split(':')[0]).filter(Boolean),
32
+ ];
33
+ // Derive acceptance criteria from evidence checkpoints
34
+ const checkpoints = eco.evidence_checkpoints ?? {};
35
+ const acceptanceCriteria = Object.keys(checkpoints).map(k => `checkpoint:${k}`);
36
+ // Derive constraints from dimension severities
37
+ const constraints = [];
38
+ const dims = eco.eco_dimensions ?? {};
39
+ for (const [dim, val] of Object.entries(dims)) {
40
+ const v = val;
41
+ if (v.severity === 'warn' || v.severity === 'escalate') {
42
+ constraints.push(`dimension:${dim}:${v.severity}${v.detail ? ' — ' + v.detail : ''}`);
43
+ }
44
+ else if (v.severity === 'block') {
45
+ constraints.push(`dimension:${dim}:blocked${v.detail ? ' — ' + v.detail : ''}`);
46
+ }
47
+ }
48
+ for (const r of (eco.escalation_reasons ?? [])) {
49
+ constraints.push(`escalation:${r}`);
50
+ }
51
+ const penalties = eco.penalties ?? [];
52
+ const confidenceScore = eco.confidence_score ?? 100;
53
+ const envelope = {
54
+ task_id: taskId,
55
+ session_id: sessionId,
56
+ created_at: new Date().toISOString(),
57
+ prompt,
58
+ lane,
59
+ scope: {
60
+ allowed_paths: modulesTouched,
61
+ blocked_paths: blockedPaths,
62
+ modules_expected: modulesTouched,
63
+ },
64
+ constraints,
65
+ acceptance_criteria: acceptanceCriteria,
66
+ tool_policy: LANE_TOOL_POLICY[lane],
67
+ stop_conditions: {
68
+ required_validations: acceptanceCriteria,
69
+ forbidden_files: blockedPaths,
70
+ },
71
+ confidence: {
72
+ score: confidenceScore,
73
+ label: getConfidenceLabel(confidenceScore),
74
+ penalties,
75
+ },
76
+ eco_summary: {
77
+ intent: eco.intent?.primary ?? 'unknown',
78
+ recommended_lane: eco.recommended_lane ?? 'A',
79
+ forced_unknown: eco.forced_unknown ?? false,
80
+ blocked: eco.blocked ?? false,
81
+ escalation_reasons: eco.escalation_reasons ?? [],
82
+ boundary_warnings: eco.boundary_warnings ?? [],
83
+ },
84
+ status: 'active',
85
+ };
86
+ return envelope;
87
+ }
88
+ export function formatEnvelopeContext(envelope) {
89
+ const lines = [
90
+ `[Nirnex] Task ${envelope.task_id} · Lane ${envelope.lane} · Confidence ${envelope.confidence.score}% (${envelope.confidence.label})`,
91
+ `Intent: ${envelope.eco_summary.intent}`,
92
+ ];
93
+ if (envelope.eco_summary.forced_unknown) {
94
+ lines.push(`⚠ ECO forced unknown — proceed with caution`);
95
+ }
96
+ if (envelope.eco_summary.blocked) {
97
+ lines.push(`✘ Task blocked by ECO — do not proceed with implementation`);
98
+ }
99
+ if (envelope.scope.allowed_paths.length > 0) {
100
+ lines.push(`Scope: ${envelope.scope.allowed_paths.join(', ')}`);
101
+ }
102
+ if (envelope.constraints.length > 0) {
103
+ lines.push(`Constraints: ${envelope.constraints.slice(0, 3).join('; ')}`);
104
+ }
105
+ if (envelope.tool_policy.requires_guard.length > 0) {
106
+ lines.push(`Guarded tools (Lane ${envelope.lane}): ${envelope.tool_policy.requires_guard.join(', ')}`);
107
+ }
108
+ if (envelope.eco_summary.escalation_reasons.length > 0) {
109
+ lines.push(`Escalation: ${envelope.eco_summary.escalation_reasons.join('; ')}`);
110
+ }
111
+ return lines.join('\n');
112
+ }
113
+ //# sourceMappingURL=envelope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../src/runtime/envelope.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function runGuard(): Promise<void>;
2
+ //# sourceMappingURL=guard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guard.d.ts","sourceRoot":"","sources":["../../src/runtime/guard.ts"],"names":[],"mappings":"AA2FA,wBAAsB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,CAsC9C"}
@@ -0,0 +1,114 @@
1
+ // PreToolUse hook handler.
2
+ // Called before Claude executes each tool call.
3
+ // Loads the active task envelope and evaluates the tool against lane policy.
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+ import { loadActiveEnvelope } from './session.js';
7
+ function readStdin() {
8
+ return new Promise(resolve => {
9
+ let buf = '';
10
+ process.stdin.setEncoding('utf8');
11
+ process.stdin.on('data', chunk => { buf += chunk; });
12
+ process.stdin.on('end', () => resolve(buf));
13
+ });
14
+ }
15
+ function extractAffectedFile(toolName, toolInput) {
16
+ if (toolName === 'Edit' || toolName === 'Write' || toolName === 'Read') {
17
+ return (toolInput.file_path ?? toolInput.path ?? null);
18
+ }
19
+ if (toolName === 'MultiEdit') {
20
+ const edits = toolInput.edits;
21
+ return edits?.[0]?.file_path ?? null;
22
+ }
23
+ return null;
24
+ }
25
+ function matchesDeniedPattern(command, patterns) {
26
+ for (const pattern of patterns) {
27
+ if (command.includes(pattern))
28
+ return pattern;
29
+ }
30
+ return null;
31
+ }
32
+ function evaluateGuard(envelope, toolName, toolInput) {
33
+ const policy = envelope.tool_policy;
34
+ // If tool doesn't require guarding for this lane, allow immediately
35
+ if (!policy.requires_guard.includes(toolName)) {
36
+ return { decision: 'allow' };
37
+ }
38
+ // Bash: check denylist
39
+ if (toolName === 'Bash') {
40
+ const command = (toolInput.command ?? '');
41
+ const matched = matchesDeniedPattern(command, policy.denied_patterns);
42
+ if (matched) {
43
+ return {
44
+ decision: 'deny',
45
+ reason: `[Nirnex Guard] Command contains denied pattern "${matched}" (Lane ${envelope.lane} policy).`,
46
+ };
47
+ }
48
+ // For Lane C, ask for commands that touch git or system state
49
+ if (envelope.lane === 'C' && /\b(git|rm|mv|chmod|chown)\b/.test(command)) {
50
+ return {
51
+ decision: 'ask',
52
+ message: `[Nirnex Guard] Lane C task — confirm this command is within scope:\n ${command}`,
53
+ };
54
+ }
55
+ return { decision: 'allow' };
56
+ }
57
+ // Edit / Write / MultiEdit: check scope
58
+ const filePath = extractAffectedFile(toolName, toolInput);
59
+ if (filePath && envelope.scope.blocked_paths.length > 0) {
60
+ for (const blocked of envelope.scope.blocked_paths) {
61
+ if (filePath.includes(blocked)) {
62
+ return {
63
+ decision: 'deny',
64
+ reason: `[Nirnex Guard] File "${filePath}" is in a blocked path "${blocked}" for this task.`,
65
+ };
66
+ }
67
+ }
68
+ }
69
+ // Lane C: require file to be within expected scope
70
+ if (envelope.lane === 'C' && filePath && envelope.scope.allowed_paths.length > 0) {
71
+ const inScope = envelope.scope.allowed_paths.some(p => filePath.includes(p));
72
+ if (!inScope) {
73
+ return {
74
+ decision: 'ask',
75
+ message: `[Nirnex Guard] Lane C — "${filePath}" is outside the expected scope [${envelope.scope.allowed_paths.join(', ')}]. Proceed?`,
76
+ };
77
+ }
78
+ }
79
+ return { decision: 'allow' };
80
+ }
81
+ export async function runGuard() {
82
+ const raw = await readStdin();
83
+ let hookData = {
84
+ session_id: 'unknown',
85
+ hook_event_name: 'PreToolUse',
86
+ tool_name: '',
87
+ tool_input: {},
88
+ };
89
+ try {
90
+ hookData = JSON.parse(raw || '{}');
91
+ }
92
+ catch {
93
+ // Non-fatal: allow on parse failure
94
+ process.stdout.write(JSON.stringify({ decision: 'allow' }));
95
+ process.exit(0);
96
+ }
97
+ const repoRoot = process.env.NIRNEX_REPO_ROOT ?? process.cwd();
98
+ const sessionId = hookData.session_id ?? process.env.NIRNEX_SESSION_ID ?? '';
99
+ // Allow if not in a Nirnex project
100
+ if (!fs.existsSync(path.join(repoRoot, 'nirnex.config.json'))) {
101
+ process.stdout.write(JSON.stringify({ decision: 'allow' }));
102
+ process.exit(0);
103
+ }
104
+ const envelope = loadActiveEnvelope(repoRoot, sessionId);
105
+ // No active envelope → allow (not in a guarded task context)
106
+ if (!envelope) {
107
+ process.stdout.write(JSON.stringify({ decision: 'allow' }));
108
+ process.exit(0);
109
+ }
110
+ const decision = evaluateGuard(envelope, hookData.tool_name, hookData.tool_input);
111
+ process.stdout.write(JSON.stringify(decision));
112
+ process.exit(0);
113
+ }
114
+ //# sourceMappingURL=guard.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"guard.js","sourceRoot":"","sources":["../../src/runtime/guard.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ import { NirnexSession, TaskEnvelope, TraceEvent } from './types.js';
2
+ export declare const RUNTIME_DIR = ".ai-index/runtime";
3
+ export declare function createSession(repoRoot: string, sessionId: string, partial?: Partial<NirnexSession>): NirnexSession;
4
+ export declare function loadSession(repoRoot: string, sessionId: string): NirnexSession | null;
5
+ export declare function saveSession(repoRoot: string, session: NirnexSession): void;
6
+ export declare function saveEnvelope(repoRoot: string, envelope: TaskEnvelope): void;
7
+ export declare function loadEnvelope(repoRoot: string, taskId: string): TaskEnvelope | null;
8
+ export declare function loadActiveEnvelope(repoRoot: string, sessionId: string): TaskEnvelope | null;
9
+ export declare function appendTraceEvent(repoRoot: string, sessionId: string, event: TraceEvent): void;
10
+ export declare function loadTraceEvents(repoRoot: string, sessionId: string): TraceEvent[];
11
+ export declare function generateTaskId(): string;
12
+ export declare function generateEventId(): string;
13
+ //# sourceMappingURL=session.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/runtime/session.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAErE,eAAO,MAAM,WAAW,sBAAsB,CAAC;AAwB/C,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,OAAO,GAAE,OAAO,CAAC,aAAa,CAAM,GAAG,aAAa,CAetH;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAQrF;AAED,wBAAgB,WAAW,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,aAAa,GAAG,IAAI,CAO1E;AAID,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,YAAY,GAAG,IAAI,CAO3E;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAQlF;AAED,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAI3F;AAID,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,IAAI,CAK7F;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,UAAU,EAAE,CAWjF;AAED,wBAAgB,cAAc,IAAI,MAAM,CAIvC;AAED,wBAAgB,eAAe,IAAI,MAAM,CAIxC"}
@@ -0,0 +1,111 @@
1
+ // Session and envelope state management.
2
+ // All state is stored under .ai-index/runtime/ as JSON files.
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
+ export const RUNTIME_DIR = '.ai-index/runtime';
6
+ function runtimeDir(repoRoot) {
7
+ return path.join(repoRoot, RUNTIME_DIR);
8
+ }
9
+ function sessionsDir(repoRoot) {
10
+ return path.join(runtimeDir(repoRoot), 'sessions');
11
+ }
12
+ function envelopesDir(repoRoot) {
13
+ return path.join(runtimeDir(repoRoot), 'envelopes');
14
+ }
15
+ function eventsDir(repoRoot, sessionId) {
16
+ return path.join(runtimeDir(repoRoot), 'events', sessionId);
17
+ }
18
+ function ensureDir(p) {
19
+ if (!fs.existsSync(p))
20
+ fs.mkdirSync(p, { recursive: true });
21
+ }
22
+ // ─── Session ──────────────────────────────────────────────────────────────
23
+ export function createSession(repoRoot, sessionId, partial = {}) {
24
+ ensureDir(sessionsDir(repoRoot));
25
+ const session = {
26
+ session_id: sessionId,
27
+ repo_root: repoRoot,
28
+ db_path: path.join(repoRoot, '.aidos.db'),
29
+ index_freshness: 'unknown',
30
+ current_head: '',
31
+ policy_mode: 'standard',
32
+ created_at: new Date().toISOString(),
33
+ tasks: [],
34
+ ...partial,
35
+ };
36
+ saveSession(repoRoot, session);
37
+ return session;
38
+ }
39
+ export function loadSession(repoRoot, sessionId) {
40
+ const p = path.join(sessionsDir(repoRoot), `${sessionId}.json`);
41
+ if (!fs.existsSync(p))
42
+ return null;
43
+ try {
44
+ return JSON.parse(fs.readFileSync(p, 'utf8'));
45
+ }
46
+ catch {
47
+ return null;
48
+ }
49
+ }
50
+ export function saveSession(repoRoot, session) {
51
+ ensureDir(sessionsDir(repoRoot));
52
+ fs.writeFileSync(path.join(sessionsDir(repoRoot), `${session.session_id}.json`), JSON.stringify(session, null, 2), 'utf8');
53
+ }
54
+ // ─── Envelope ─────────────────────────────────────────────────────────────
55
+ export function saveEnvelope(repoRoot, envelope) {
56
+ ensureDir(envelopesDir(repoRoot));
57
+ fs.writeFileSync(path.join(envelopesDir(repoRoot), `${envelope.task_id}.json`), JSON.stringify(envelope, null, 2), 'utf8');
58
+ }
59
+ export function loadEnvelope(repoRoot, taskId) {
60
+ const p = path.join(envelopesDir(repoRoot), `${taskId}.json`);
61
+ if (!fs.existsSync(p))
62
+ return null;
63
+ try {
64
+ return JSON.parse(fs.readFileSync(p, 'utf8'));
65
+ }
66
+ catch {
67
+ return null;
68
+ }
69
+ }
70
+ export function loadActiveEnvelope(repoRoot, sessionId) {
71
+ const session = loadSession(repoRoot, sessionId);
72
+ if (!session?.active_task_id)
73
+ return null;
74
+ return loadEnvelope(repoRoot, session.active_task_id);
75
+ }
76
+ // ─── Trace events ─────────────────────────────────────────────────────────
77
+ export function appendTraceEvent(repoRoot, sessionId, event) {
78
+ const dir = eventsDir(repoRoot, sessionId);
79
+ ensureDir(dir);
80
+ const eventsPath = path.join(dir, 'events.jsonl');
81
+ fs.appendFileSync(eventsPath, JSON.stringify(event) + '\n', 'utf8');
82
+ }
83
+ export function loadTraceEvents(repoRoot, sessionId) {
84
+ const eventsPath = path.join(eventsDir(repoRoot, sessionId), 'events.jsonl');
85
+ if (!fs.existsSync(eventsPath))
86
+ return [];
87
+ return fs
88
+ .readFileSync(eventsPath, 'utf8')
89
+ .split('\n')
90
+ .filter(Boolean)
91
+ .map(line => {
92
+ try {
93
+ return JSON.parse(line);
94
+ }
95
+ catch {
96
+ return null;
97
+ }
98
+ })
99
+ .filter((e) => e !== null);
100
+ }
101
+ export function generateTaskId() {
102
+ const ts = Date.now().toString(36);
103
+ const rand = Math.random().toString(36).slice(2, 6);
104
+ return `task_${ts}_${rand}`;
105
+ }
106
+ export function generateEventId() {
107
+ const ts = Date.now().toString(36);
108
+ const rand = Math.random().toString(36).slice(2, 6);
109
+ return `evt_${ts}_${rand}`;
110
+ }
111
+ //# sourceMappingURL=session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/runtime/session.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export declare function runTraceHook(): Promise<void>;
2
+ //# sourceMappingURL=trace-hook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-hook.d.ts","sourceRoot":"","sources":["../../src/runtime/trace-hook.ts"],"names":[],"mappings":"AA6DA,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAiElD"}
@@ -0,0 +1,102 @@
1
+ // PostToolUse hook handler.
2
+ // Called after each tool execution. Appends a trace event, detects deviation,
3
+ // and optionally injects context back to Claude if drift is found.
4
+ import fs from 'node:fs';
5
+ import path from 'node:path';
6
+ import { loadActiveEnvelope, appendTraceEvent, generateEventId } from './session.js';
7
+ function readStdin() {
8
+ return new Promise(resolve => {
9
+ let buf = '';
10
+ process.stdin.setEncoding('utf8');
11
+ process.stdin.on('data', chunk => { buf += chunk; });
12
+ process.stdin.on('end', () => resolve(buf));
13
+ });
14
+ }
15
+ function extractAffectedFiles(toolName, toolInput) {
16
+ const files = [];
17
+ if (toolName === 'Edit' || toolName === 'Write' || toolName === 'Read') {
18
+ const f = toolInput.file_path ?? toolInput.path;
19
+ if (typeof f === 'string')
20
+ files.push(f);
21
+ }
22
+ else if (toolName === 'MultiEdit') {
23
+ const edits = toolInput.edits;
24
+ for (const e of edits ?? []) {
25
+ if (e.file_path)
26
+ files.push(e.file_path);
27
+ }
28
+ }
29
+ else if (toolName === 'Bash') {
30
+ // Cannot reliably extract files from arbitrary commands
31
+ }
32
+ return files;
33
+ }
34
+ function detectDeviations(affectedFiles, toolName, toolInput, allowedPaths, blockedPaths, lane) {
35
+ const flags = [];
36
+ for (const f of affectedFiles) {
37
+ for (const blocked of blockedPaths) {
38
+ if (f.includes(blocked)) {
39
+ flags.push(`file_in_blocked_path:${f}`);
40
+ }
41
+ }
42
+ if (lane === 'C' && allowedPaths.length > 0) {
43
+ const inScope = allowedPaths.some(p => f.includes(p));
44
+ if (!inScope) {
45
+ flags.push(`file_out_of_scope:${f}`);
46
+ }
47
+ }
48
+ }
49
+ return flags;
50
+ }
51
+ export async function runTraceHook() {
52
+ const raw = await readStdin();
53
+ let hookData = {
54
+ session_id: 'unknown',
55
+ hook_event_name: 'PostToolUse',
56
+ tool_name: '',
57
+ tool_input: {},
58
+ tool_result: {},
59
+ };
60
+ try {
61
+ hookData = JSON.parse(raw || '{}');
62
+ }
63
+ catch {
64
+ process.exit(0);
65
+ }
66
+ const repoRoot = process.env.NIRNEX_REPO_ROOT ?? process.cwd();
67
+ const sessionId = hookData.session_id ?? process.env.NIRNEX_SESSION_ID ?? '';
68
+ if (!fs.existsSync(path.join(repoRoot, 'nirnex.config.json'))) {
69
+ process.exit(0);
70
+ }
71
+ const envelope = loadActiveEnvelope(repoRoot, sessionId);
72
+ const affectedFiles = extractAffectedFiles(hookData.tool_name, hookData.tool_input);
73
+ const deviationFlags = envelope
74
+ ? detectDeviations(affectedFiles, hookData.tool_name, hookData.tool_input, envelope.scope.allowed_paths, envelope.scope.blocked_paths, envelope.lane)
75
+ : [];
76
+ const event = {
77
+ event_id: generateEventId(),
78
+ session_id: sessionId,
79
+ task_id: envelope?.task_id ?? 'none',
80
+ timestamp: new Date().toISOString(),
81
+ tool: hookData.tool_name,
82
+ tool_input: hookData.tool_input,
83
+ tool_result: hookData.tool_result,
84
+ affected_files: affectedFiles,
85
+ deviation_flags: deviationFlags,
86
+ };
87
+ try {
88
+ appendTraceEvent(repoRoot, sessionId, event);
89
+ }
90
+ catch {
91
+ // Non-fatal
92
+ }
93
+ // If deviation detected, inject context back to Claude
94
+ if (deviationFlags.length > 0) {
95
+ const output = {
96
+ additionalContext: `[Nirnex Trace] Deviation detected in ${hookData.tool_name}: ${deviationFlags.join(', ')}. Verify this is intentional.`,
97
+ };
98
+ process.stdout.write(JSON.stringify(output));
99
+ }
100
+ process.exit(0);
101
+ }
102
+ //# sourceMappingURL=trace-hook.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace-hook.js","sourceRoot":"","sources":["../../src/runtime/trace-hook.ts"],"names":[],"mappings":"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"}