@lucieri/daxiom 0.2.2 → 0.2.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lucieri/daxiom",
3
- "version": "0.2.2",
3
+ "version": "0.2.3",
4
4
  "description": "DAXIOM SDK — Pattern database client with quality gates, tier management, and semantic search via RuVector PostgreSQL",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/cli.js CHANGED
@@ -398,7 +398,7 @@ if (cmd === 'hooks') {
398
398
  }
399
399
 
400
400
  default:
401
- console.log('daxiom — Self-Learning Second Brain SDK v0.2.0');
401
+ console.log('daxiom — Self-Learning Second Brain SDK v0.2.3');
402
402
  console.log('');
403
403
  console.log('Knowledge: search | store | coherence | quality-check | stats');
404
404
  console.log('Tiers: tiers | tier-check | tier-promote');
@@ -407,7 +407,8 @@ if (cmd === 'hooks') {
407
407
  console.log('Registry: namespaces');
408
408
  console.log('Rollback: demote | rollback-check');
409
409
  console.log('Decay: decay | drift | decay-preview');
410
- console.log('Hooks: hooks pre-task | hooks post-task | hooks session-start | hooks pre-compact | hooks summarize');
410
+ console.log('Hooks: hooks <subcommand> 16 Claude Code hook handlers');
411
+ console.log(' Run "daxiom hooks" for full list');
411
412
  console.log('');
412
413
  console.log('All self-mgmt commands accept --namespace <ns> to target a specific repo.');
413
414
  console.log('todo/changelog with no args list entries. Use --namespace to filter.');
@@ -13,10 +13,14 @@ const { loadEnv } = require('./env');
13
13
  * post-edit - Record file edits for cross-repo learning
14
14
  * pre-command - Search DAXIOM for patterns before shell command
15
15
  * post-command - Record significant commands for learning
16
+ * post-failure - Learn from tool failures, suggest known fixes
16
17
  * remember - Track file access, searches, agent spawns
17
18
  * session-start - Inject SOUL.md + DAXIOM context on session start
18
19
  * session-end - Store session summary and run tier maintenance
20
+ * subagent-start - Inject DAXIOM patterns into subagent context
21
+ * subagent-stop - Extract learnings from subagent transcript
19
22
  * suggest-context - Surface relevant patterns on user prompt
23
+ * task-completed - Record task completions for learning
20
24
  * pre-compact - Capture transcript before context compaction
21
25
  * summarize - Process and embed daily session logs
22
26
  */
@@ -52,6 +56,10 @@ async function dispatch(args) {
52
56
  const { run } = require('./post-command');
53
57
  return run(subArgs);
54
58
  }
59
+ case 'post-failure': {
60
+ const { run } = require('./post-failure');
61
+ return run(subArgs);
62
+ }
55
63
  case 'remember': {
56
64
  const { run } = require('./remember');
57
65
  return run(subArgs);
@@ -64,10 +72,22 @@ async function dispatch(args) {
64
72
  const { run } = require('./session-end');
65
73
  return run(subArgs);
66
74
  }
75
+ case 'subagent-start': {
76
+ const { run } = require('./subagent-start');
77
+ return run(subArgs);
78
+ }
79
+ case 'subagent-stop': {
80
+ const { run } = require('./subagent-stop');
81
+ return run(subArgs);
82
+ }
67
83
  case 'suggest-context': {
68
84
  const { run } = require('./suggest-context');
69
85
  return run(subArgs);
70
86
  }
87
+ case 'task-completed': {
88
+ const { run } = require('./task-completed');
89
+ return run(subArgs);
90
+ }
71
91
  case 'pre-compact': {
72
92
  const { run } = require('./pre-compact');
73
93
  return run(subArgs);
@@ -86,10 +106,14 @@ async function dispatch(args) {
86
106
  console.log(' post-edit Record file edits for learning');
87
107
  console.log(' pre-command Search DAXIOM before shell command');
88
108
  console.log(' post-command Record significant commands');
109
+ console.log(' post-failure Learn from tool failures, suggest fixes');
89
110
  console.log(' remember Track file access, searches, agent spawns');
90
111
  console.log(' session-start Inject context on session start');
91
112
  console.log(' session-end Store session summary, run tier maintenance');
113
+ console.log(' subagent-start Inject DAXIOM patterns into subagent');
114
+ console.log(' subagent-stop Extract learnings from subagent transcript');
92
115
  console.log(' suggest-context Surface relevant patterns on user prompt');
116
+ console.log(' task-completed Record task completions for learning');
93
117
  console.log(' pre-compact Capture transcript before compaction');
94
118
  console.log(' summarize Process daily session logs');
95
119
  console.log('');
@@ -0,0 +1,93 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { init, close, storeLearnedPattern, searchWithSalience } = require('../index');
6
+
7
+ /**
8
+ * PostToolUseFailure hook: learn from tool failures.
9
+ * Records what failed and why, searches for known fixes.
10
+ *
11
+ * Reads stdin JSON: { tool_name, tool_input, error, is_interrupt }
12
+ * Outputs JSON: { additionalContext: "..." } with known fixes if found
13
+ *
14
+ * @param {string[]} args - unused (stdin-driven)
15
+ */
16
+ async function run(args) {
17
+ let input = {};
18
+ try {
19
+ const stdin = fs.readFileSync(0, 'utf8').trim();
20
+ if (stdin) input = JSON.parse(stdin);
21
+ } catch { /* No stdin */ }
22
+
23
+ const toolName = input.tool_name || args[0] || '';
24
+ const error = input.error || '';
25
+ const isInterrupt = input.is_interrupt || false;
26
+
27
+ // Skip user interruptions — nothing to learn
28
+ if (isInterrupt || !toolName || !error) {
29
+ process.stdout.write('{}');
30
+ return;
31
+ }
32
+
33
+ try {
34
+ await init();
35
+
36
+ const repo = path.basename(input.cwd || process.cwd());
37
+ const errorSnippet = error.substring(0, 300);
38
+
39
+ // Store the failure for future learning
40
+ const slug = `${toolName}_${error.replace(/[^a-z0-9]/gi, '_').substring(0, 40)}`.toLowerCase();
41
+ await storeLearnedPattern({
42
+ patternName: `failure_${repo}_${slug}`,
43
+ description: `Tool ${toolName} failed in ${repo}: ${errorSnippet}`,
44
+ compactText: `${toolName} failure: ${errorSnippet}`,
45
+ patternClass: 'error-fix',
46
+ namespace: repo,
47
+ category: 'failure',
48
+ tier: 'warm',
49
+ tags: [repo, 'failure', toolName.toLowerCase()],
50
+ metadata: {
51
+ toolName,
52
+ error: error.substring(0, 1000),
53
+ toolInput: JSON.stringify(input.tool_input || {}).substring(0, 500),
54
+ repo,
55
+ failedAt: new Date().toISOString(),
56
+ },
57
+ });
58
+
59
+ // Search for known fixes to similar errors
60
+ const fixes = await searchWithSalience(`fix ${toolName} error: ${errorSnippet}`, {
61
+ limit: 3,
62
+ threshold: 0.5,
63
+ decay: 0.03,
64
+ candidatePool: 15,
65
+ });
66
+
67
+ const knownFixes = fixes.filter(r =>
68
+ r.patternClass === 'error-fix' || r.patternClass === 'learned'
69
+ );
70
+
71
+ if (knownFixes.length > 0) {
72
+ const fixText = knownFixes.map((r, i) =>
73
+ `${i + 1}. [${r.namespace}] ${r.patternName}: ${r.description.substring(0, 200)}`
74
+ ).join('\n');
75
+
76
+ const fixContext = `DAXIOM found ${knownFixes.length} known fix(es) for this ${toolName} failure:\n${fixText}\nConsider applying these learned solutions.`;
77
+ process.stdout.write(JSON.stringify({
78
+ hookSpecificOutput: {
79
+ hookEventName: 'PostToolUseFailure',
80
+ additionalContext: fixContext,
81
+ },
82
+ }));
83
+ } else {
84
+ process.stdout.write('{}');
85
+ }
86
+ } catch {
87
+ process.stdout.write('{}');
88
+ } finally {
89
+ await close();
90
+ }
91
+ }
92
+
93
+ module.exports = { run };
@@ -28,7 +28,11 @@ async function run(args) {
28
28
 
29
29
  if (results.length > 0) {
30
30
  const hints = results.map(r => `${r.patternName} (${r.namespace}): ${r.description.substring(0, 100)}`);
31
- console.log(JSON.stringify({ daxiom_intel: true, command_hints: hints }));
31
+ const additionalContext = `DAXIOM hints for command: ${hints.join('; ')}`;
32
+ console.log(JSON.stringify({
33
+ hookSpecificOutput: { hookEventName: 'PreToolUse', additionalContext },
34
+ daxiom_intel: true,
35
+ }));
32
36
  }
33
37
  } catch {
34
38
  // Non-fatal
@@ -35,12 +35,14 @@ async function run(args) {
35
35
  }
36
36
 
37
37
  const hints = results.map(r => `${r.patternName}: ${r.description.substring(0, 120)}`);
38
- console.log(JSON.stringify({
39
- daxiom_intel: true,
40
- file: filePath,
41
- patterns: results.length,
42
- hints,
43
- }));
38
+ const additionalContext = hints.length > 0
39
+ ? `DAXIOM patterns for ${fileName}: ${hints.join('; ')}`
40
+ : undefined;
41
+ const output = { daxiom_intel: true, file: filePath, patterns: results.length };
42
+ if (additionalContext) {
43
+ output.hookSpecificOutput = { hookEventName: 'PreToolUse', additionalContext };
44
+ }
45
+ console.log(JSON.stringify(output));
44
46
  } catch (err) {
45
47
  console.log(JSON.stringify({ daxiom_intel: false, error: err.message }));
46
48
  } finally {
@@ -65,7 +65,23 @@ async function run(args) {
65
65
  });
66
66
  }
67
67
 
68
+ // Build human-readable context for injection into agent
69
+ const patternSummary = results.slice(0, 5).map((r, i) =>
70
+ `${i + 1}. [${r.namespace}/${r.patternClass}] ${r.patternName} (sim=${r.similarity.toFixed(2)}): ${r.description.substring(0, 180)}`
71
+ ).join('\n');
72
+
73
+ const additionalContext = [
74
+ `DAXIOM Intelligence: ${results.length} patterns found for this task.`,
75
+ patternSummary,
76
+ '',
77
+ 'Apply these learned patterns where relevant.',
78
+ ].join('\n');
79
+
68
80
  const output = {
81
+ hookSpecificOutput: {
82
+ hookEventName: 'PreToolUse',
83
+ additionalContext,
84
+ },
69
85
  daxiom_intel: true,
70
86
  ranking: 'salience',
71
87
  patterns_found: results.length,
@@ -80,7 +96,7 @@ async function run(args) {
80
96
  task: taskDescription,
81
97
  };
82
98
 
83
- console.log(JSON.stringify(output, null, 2));
99
+ console.log(JSON.stringify(output));
84
100
 
85
101
  // Record usage for top 3 patterns
86
102
  for (const r of results.slice(0, 3)) {
@@ -102,7 +102,12 @@ async function run(args) {
102
102
  }
103
103
 
104
104
  const context = parts.join('\n\n---\n\n');
105
- process.stdout.write(JSON.stringify({ additionalContext: context }));
105
+ process.stdout.write(JSON.stringify({
106
+ hookSpecificOutput: {
107
+ hookEventName: 'SessionStart',
108
+ additionalContext: context,
109
+ },
110
+ }));
106
111
  }
107
112
 
108
113
  module.exports = { run };
@@ -0,0 +1,72 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { init, close, searchWithSalience } = require('../index');
6
+
7
+ /**
8
+ * SubagentStart hook: inject DAXIOM patterns directly into subagent context.
9
+ * Uses additionalContext field so patterns appear in the subagent's system prompt.
10
+ *
11
+ * Reads stdin JSON: { agent_id, agent_type, session_id, cwd }
12
+ * Outputs JSON: { additionalContext: "..." }
13
+ *
14
+ * @param {string[]} args - unused (stdin-driven)
15
+ */
16
+ async function run(args) {
17
+ let input = {};
18
+ try {
19
+ const stdin = fs.readFileSync(0, 'utf8').trim();
20
+ if (stdin) input = JSON.parse(stdin);
21
+ } catch { /* No stdin */ }
22
+
23
+ const agentType = input.agent_type || args[0] || '';
24
+ if (!agentType) {
25
+ process.stdout.write('{}');
26
+ return;
27
+ }
28
+
29
+ try {
30
+ await init();
31
+
32
+ const repo = path.basename(input.cwd || process.cwd());
33
+ const query = `${agentType} agent patterns conventions ${repo}`;
34
+
35
+ const results = await searchWithSalience(query, {
36
+ limit: 5,
37
+ threshold: 0.4,
38
+ decay: 0.03,
39
+ candidatePool: 20,
40
+ });
41
+
42
+ if (results.length === 0) {
43
+ process.stdout.write('{}');
44
+ return;
45
+ }
46
+
47
+ // Build context string for the subagent
48
+ const patterns = results.map((r, i) =>
49
+ `${i + 1}. [${r.namespace}/${r.patternClass}] ${r.patternName}: ${r.description.substring(0, 200)}`
50
+ ).join('\n');
51
+
52
+ const context = [
53
+ `DAXIOM Intelligence (${results.length} patterns for ${agentType} agent in ${repo}):`,
54
+ patterns,
55
+ '',
56
+ 'Use these learned patterns to inform your work. They represent cross-repo knowledge.',
57
+ ].join('\n');
58
+
59
+ process.stdout.write(JSON.stringify({
60
+ hookSpecificOutput: {
61
+ hookEventName: 'SubagentStart',
62
+ additionalContext: context,
63
+ },
64
+ }));
65
+ } catch {
66
+ process.stdout.write('{}');
67
+ } finally {
68
+ await close();
69
+ }
70
+ }
71
+
72
+ module.exports = { run };
@@ -0,0 +1,89 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { init, close, storeLearnedPattern } = require('../index');
6
+
7
+ /**
8
+ * SubagentStop hook: extract learnings from subagent transcript.
9
+ * Reads the agent transcript and stores key findings in DAXIOM.
10
+ *
11
+ * Reads stdin JSON: { agent_id, agent_type, agent_transcript_path, session_id, cwd }
12
+ * Outputs JSON: {} (async, non-blocking)
13
+ *
14
+ * @param {string[]} args - unused (stdin-driven)
15
+ */
16
+ async function run(args) {
17
+ let input = {};
18
+ try {
19
+ const stdin = fs.readFileSync(0, 'utf8').trim();
20
+ if (stdin) input = JSON.parse(stdin);
21
+ } catch { /* No stdin */ }
22
+
23
+ const agentType = input.agent_type || '';
24
+ const transcriptPath = input.agent_transcript_path || '';
25
+
26
+ if (!agentType) return;
27
+
28
+ try {
29
+ await init();
30
+
31
+ const repo = path.basename(input.cwd || process.cwd());
32
+ let transcriptSummary = '';
33
+
34
+ // Read last portion of transcript if available
35
+ if (transcriptPath && fs.existsSync(transcriptPath)) {
36
+ try {
37
+ const content = fs.readFileSync(transcriptPath, 'utf8');
38
+ const lines = content.split('\n').filter(Boolean);
39
+
40
+ // Extract assistant messages from last 10 JSONL entries
41
+ const recentEntries = lines.slice(-10);
42
+ const discoveries = [];
43
+
44
+ for (const line of recentEntries) {
45
+ try {
46
+ const entry = JSON.parse(line);
47
+ if (entry.role === 'assistant' && typeof entry.content === 'string') {
48
+ // Look for findings, conclusions, or results
49
+ const text = entry.content.substring(0, 300);
50
+ if (text.length > 30) discoveries.push(text);
51
+ }
52
+ } catch { /* skip malformed lines */ }
53
+ }
54
+
55
+ if (discoveries.length > 0) {
56
+ transcriptSummary = discoveries.slice(0, 3).join(' | ');
57
+ }
58
+ } catch { /* transcript read failed, non-fatal */ }
59
+ }
60
+
61
+ const description = transcriptSummary
62
+ ? `${agentType} agent completed in ${repo}. Key findings: ${transcriptSummary.substring(0, 500)}`
63
+ : `${agentType} agent completed work in ${repo}`;
64
+
65
+ await storeLearnedPattern({
66
+ patternName: `agent_${repo}_${agentType}_${Date.now()}`,
67
+ description,
68
+ compactText: `${agentType} agent finished in ${repo}`,
69
+ patternClass: 'activity',
70
+ namespace: repo,
71
+ category: 'agent-completion',
72
+ tier: 'warm',
73
+ tags: [repo, 'agent-completion', agentType],
74
+ metadata: {
75
+ agentType,
76
+ agentId: input.agent_id,
77
+ repo,
78
+ hadTranscript: !!transcriptSummary,
79
+ completedAt: new Date().toISOString(),
80
+ },
81
+ });
82
+ } catch {
83
+ // Non-fatal
84
+ } finally {
85
+ await close();
86
+ }
87
+ }
88
+
89
+ module.exports = { run };
@@ -34,7 +34,10 @@ async function run(args) {
34
34
  `${r.patternName} (${r.namespace}, ${r.patternClass}): ${r.description.substring(0, 150)}`
35
35
  );
36
36
 
37
- console.log(`RuVector Intelligence: ${results.length} learned patterns, 0 error fixes available. Use 'ruvector hooks route' for agent suggestions.`);
37
+ const additionalContext = `DAXIOM Intelligence: ${hints.join('; ')}`;
38
+ console.log(JSON.stringify({
39
+ hookSpecificOutput: { hookEventName: 'UserPromptSubmit', additionalContext },
40
+ }));
38
41
  } catch {
39
42
  // Non-fatal
40
43
  } finally {
@@ -0,0 +1,57 @@
1
+ 'use strict';
2
+
3
+ const fs = require('fs');
4
+ const path = require('path');
5
+ const { init, close, storeLearnedPattern } = require('../index');
6
+
7
+ /**
8
+ * TaskCompleted hook: record task completions for learning.
9
+ * Captures what was accomplished for cross-session intelligence.
10
+ *
11
+ * Reads stdin JSON: { task_id, task_subject, task_description }
12
+ * Exit code 2 would block completion (not used currently).
13
+ *
14
+ * @param {string[]} args - unused (stdin-driven)
15
+ */
16
+ async function run(args) {
17
+ let input = {};
18
+ try {
19
+ const stdin = fs.readFileSync(0, 'utf8').trim();
20
+ if (stdin) input = JSON.parse(stdin);
21
+ } catch { /* No stdin */ }
22
+
23
+ const taskSubject = input.task_subject || args[0] || '';
24
+ if (!taskSubject) return;
25
+
26
+ try {
27
+ await init();
28
+
29
+ const repo = path.basename(input.cwd || process.cwd());
30
+ const slug = taskSubject.replace(/[^a-z0-9\s]/gi, '').trim()
31
+ .split(/\s+/).slice(0, 6).join('_').substring(0, 60).toLowerCase();
32
+
33
+ await storeLearnedPattern({
34
+ patternName: `completed_${repo}_${slug}`,
35
+ description: `Completed: ${taskSubject}${input.task_description ? ' — ' + input.task_description.substring(0, 200) : ''}`,
36
+ compactText: `Task completed in ${repo}: ${taskSubject}`,
37
+ patternClass: 'activity',
38
+ namespace: repo,
39
+ category: 'task-completed',
40
+ tier: 'warm',
41
+ tags: [repo, 'completed'],
42
+ metadata: {
43
+ taskId: input.task_id,
44
+ taskSubject,
45
+ taskDescription: (input.task_description || '').substring(0, 500),
46
+ repo,
47
+ completedAt: new Date().toISOString(),
48
+ },
49
+ });
50
+ } catch {
51
+ // Non-fatal
52
+ } finally {
53
+ await close();
54
+ }
55
+ }
56
+
57
+ module.exports = { run };