@lucieri/daxiom 0.2.1 → 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.1",
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.');
package/src/constants.js CHANGED
@@ -28,6 +28,7 @@ const KNOWN_CLASSES = [
28
28
  'tool', 'guidance', 'interface', 'algorithm', 'integration',
29
29
  'ui', 'adapter', 'skill', 'session-context', 'session-summary',
30
30
  'wire_integrate', 'general',
31
+ 'file-edit', 'command', 'activity', 'session',
31
32
  ];
32
33
 
33
34
  const KNOWN_NAMESPACES = [
@@ -49,6 +50,8 @@ const KNOWN_NAMESPACES = [
49
50
  'forge', 'vibe-cast', 'agentic-qe',
50
51
  'plugin-ecosystem', 'plugin-prime-radiant', 'gastown',
51
52
  'plugin-code-intelligence', 'plugin-test-intelligence',
53
+ // Additional project namespaces
54
+ 'openclaw', 'memu', 'voicemode', 'mission-control',
52
55
  ];
53
56
 
54
57
  const SECURITY_PATTERNS = [
@@ -7,11 +7,22 @@ const { loadEnv } = require('./env');
7
7
  * Usage: daxiom hooks <subcommand> [args...]
8
8
  *
9
9
  * Subcommands:
10
- * pre-task - Search DAXIOM for relevant patterns before agent task
11
- * post-task - Store learnings after agent task completion
12
- * session-start - Inject SOUL.md + DAXIOM context on session start
13
- * pre-compact - Capture transcript before context compaction
14
- * summarize - Process and embed daily session logs
10
+ * pre-task - Search DAXIOM for relevant patterns before agent task
11
+ * post-task - Store learnings after agent task completion
12
+ * pre-edit - Search DAXIOM for patterns before file edit
13
+ * post-edit - Record file edits for cross-repo learning
14
+ * pre-command - Search DAXIOM for patterns before shell command
15
+ * post-command - Record significant commands for learning
16
+ * post-failure - Learn from tool failures, suggest known fixes
17
+ * remember - Track file access, searches, agent spawns
18
+ * session-start - Inject SOUL.md + DAXIOM context on session start
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
22
+ * suggest-context - Surface relevant patterns on user prompt
23
+ * task-completed - Record task completions for learning
24
+ * pre-compact - Capture transcript before context compaction
25
+ * summarize - Process and embed daily session logs
15
26
  */
16
27
  async function dispatch(args) {
17
28
  // Load env before any hook runs
@@ -29,10 +40,54 @@ async function dispatch(args) {
29
40
  const { run } = require('./post-task');
30
41
  return run(subArgs);
31
42
  }
43
+ case 'pre-edit': {
44
+ const { run } = require('./pre-edit');
45
+ return run(subArgs);
46
+ }
47
+ case 'post-edit': {
48
+ const { run } = require('./post-edit');
49
+ return run(subArgs);
50
+ }
51
+ case 'pre-command': {
52
+ const { run } = require('./pre-command');
53
+ return run(subArgs);
54
+ }
55
+ case 'post-command': {
56
+ const { run } = require('./post-command');
57
+ return run(subArgs);
58
+ }
59
+ case 'post-failure': {
60
+ const { run } = require('./post-failure');
61
+ return run(subArgs);
62
+ }
63
+ case 'remember': {
64
+ const { run } = require('./remember');
65
+ return run(subArgs);
66
+ }
32
67
  case 'session-start': {
33
68
  const { run } = require('./session-start');
34
69
  return run(subArgs);
35
70
  }
71
+ case 'session-end': {
72
+ const { run } = require('./session-end');
73
+ return run(subArgs);
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
+ }
83
+ case 'suggest-context': {
84
+ const { run } = require('./suggest-context');
85
+ return run(subArgs);
86
+ }
87
+ case 'task-completed': {
88
+ const { run } = require('./task-completed');
89
+ return run(subArgs);
90
+ }
36
91
  case 'pre-compact': {
37
92
  const { run } = require('./pre-compact');
38
93
  return run(subArgs);
@@ -45,11 +100,22 @@ async function dispatch(args) {
45
100
  console.log('daxiom hooks — Claude Code hook handlers');
46
101
  console.log('');
47
102
  console.log('Subcommands:');
48
- console.log(' pre-task Search DAXIOM before agent task');
49
- console.log(' post-task Store learnings after agent task');
50
- console.log(' session-start Inject context on session start');
51
- console.log(' pre-compact Capture transcript before compaction');
52
- console.log(' summarize Process daily session logs');
103
+ console.log(' pre-task Search DAXIOM before agent task');
104
+ console.log(' post-task Store learnings after agent task');
105
+ console.log(' pre-edit Search DAXIOM before file edit');
106
+ console.log(' post-edit Record file edits for learning');
107
+ console.log(' pre-command Search DAXIOM before shell command');
108
+ console.log(' post-command Record significant commands');
109
+ console.log(' post-failure Learn from tool failures, suggest fixes');
110
+ console.log(' remember Track file access, searches, agent spawns');
111
+ console.log(' session-start Inject context on session start');
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');
115
+ console.log(' suggest-context Surface relevant patterns on user prompt');
116
+ console.log(' task-completed Record task completions for learning');
117
+ console.log(' pre-compact Capture transcript before compaction');
118
+ console.log(' summarize Process daily session logs');
53
119
  console.log('');
54
120
  console.log('Env: DAXIOM_DATABASE_URL or DATABASE_URL, GEMINI_API_KEY');
55
121
  console.log('Auto-loads from ~/.daxiom/.env if env vars not set.');
@@ -0,0 +1,50 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const { init, close, storeLearnedPattern } = require('../index');
5
+
6
+ /**
7
+ * Post-command hook: record significant commands in DAXIOM for cross-repo learning.
8
+ * Only stores non-trivial commands (builds, deploys, migrations, installs, etc.)
9
+ *
10
+ * @param {string[]} args - [command string]
11
+ */
12
+ async function run(args) {
13
+ const command = args.join(' ');
14
+ if (!command) return;
15
+
16
+ // Only record significant commands
17
+ const significant = /\b(npm|pnpm|yarn|npx|docker|psql|git push|git merge|deploy|migrate|build|test|publish)\b/i;
18
+ if (!significant.test(command)) return;
19
+
20
+ try {
21
+ await init();
22
+
23
+ const repo = path.basename(process.cwd());
24
+ const cmdSlug = command.replace(/[^a-z0-9\s]/gi, '').trim()
25
+ .split(/\s+/).slice(0, 5).join('_').substring(0, 60);
26
+
27
+ await storeLearnedPattern({
28
+ patternName: `cmd_${repo}_${cmdSlug}`,
29
+ description: `Command: ${command.substring(0, 300)}`,
30
+ compactText: `Ran command in ${repo}: ${command.substring(0, 200)}`,
31
+ patternClass: 'command',
32
+ namespace: repo,
33
+ category: 'activity',
34
+ tier: 'warm',
35
+ tags: [repo, 'command'],
36
+ metadata: {
37
+ command: command.substring(0, 500),
38
+ repo,
39
+ cwd: process.cwd(),
40
+ ranAt: new Date().toISOString(),
41
+ },
42
+ });
43
+ } catch {
44
+ // Non-fatal
45
+ } finally {
46
+ await close();
47
+ }
48
+ }
49
+
50
+ module.exports = { run };
@@ -0,0 +1,49 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const { init, close, storeLearnedPattern } = require('../index');
5
+
6
+ /**
7
+ * Post-edit hook: record file edits in DAXIOM for cross-repo learning.
8
+ *
9
+ * @param {string[]} args - [filePath, ...flags]
10
+ */
11
+ async function run(args) {
12
+ const filePath = args[0];
13
+ if (!filePath) return;
14
+
15
+ try {
16
+ await init();
17
+
18
+ const fileName = path.basename(filePath);
19
+ const ext = path.extname(filePath).slice(1);
20
+ const repo = path.basename(process.cwd());
21
+ const dir = path.dirname(filePath).split('/').slice(-2).join('/');
22
+
23
+ await storeLearnedPattern({
24
+ patternName: `edit_${repo}_${fileName}`.replace(/[^a-z0-9_.-]/gi, '_').substring(0, 80),
25
+ description: `Edited ${fileName} in ${dir} (${repo})`,
26
+ compactText: `File edit: ${filePath} in repo ${repo}. Extension: ${ext}.`,
27
+ patternClass: 'file-edit',
28
+ namespace: repo,
29
+ category: 'activity',
30
+ tier: 'warm',
31
+ tags: [ext, repo, 'edit'].filter(Boolean),
32
+ metadata: {
33
+ filePath,
34
+ extension: ext,
35
+ repo,
36
+ editedAt: new Date().toISOString(),
37
+ },
38
+ });
39
+
40
+ console.log(JSON.stringify({ recorded: true, file: fileName, repo }));
41
+ } catch (err) {
42
+ // Non-fatal — don't block edits
43
+ console.log(JSON.stringify({ recorded: false, error: err.message }));
44
+ } finally {
45
+ await close();
46
+ }
47
+ }
48
+
49
+ module.exports = { run };
@@ -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 };
@@ -0,0 +1,44 @@
1
+ 'use strict';
2
+
3
+ const { init, close, searchWithSalience } = require('../index');
4
+
5
+ /**
6
+ * Pre-command hook: search DAXIOM for patterns related to the command being run.
7
+ * Surfaces relevant learnings before executing shell commands.
8
+ *
9
+ * @param {string[]} args - [command string]
10
+ */
11
+ async function run(args) {
12
+ const command = args.join(' ');
13
+ if (!command) return;
14
+
15
+ // Skip trivial commands
16
+ const trivial = /^(ls|pwd|cd|echo|cat|head|tail|which|true|false)\b/;
17
+ if (trivial.test(command.trim())) return;
18
+
19
+ try {
20
+ await init();
21
+
22
+ const results = await searchWithSalience(command, {
23
+ limit: 2,
24
+ threshold: 0.5,
25
+ decay: 0.03,
26
+ candidatePool: 10,
27
+ });
28
+
29
+ if (results.length > 0) {
30
+ const hints = results.map(r => `${r.patternName} (${r.namespace}): ${r.description.substring(0, 100)}`);
31
+ const additionalContext = `DAXIOM hints for command: ${hints.join('; ')}`;
32
+ console.log(JSON.stringify({
33
+ hookSpecificOutput: { hookEventName: 'PreToolUse', additionalContext },
34
+ daxiom_intel: true,
35
+ }));
36
+ }
37
+ } catch {
38
+ // Non-fatal
39
+ } finally {
40
+ await close();
41
+ }
42
+ }
43
+
44
+ module.exports = { run };
@@ -0,0 +1,53 @@
1
+ 'use strict';
2
+
3
+ const { init, close, searchWithSalience } = require('../index');
4
+
5
+ /**
6
+ * Pre-edit hook: search DAXIOM for patterns related to the file being edited.
7
+ * Provides relevant context before making changes.
8
+ *
9
+ * @param {string[]} args - [filePath, ...flags]
10
+ */
11
+ async function run(args) {
12
+ const filePath = args[0];
13
+ if (!filePath) {
14
+ console.log(JSON.stringify({ daxiom_intel: false, message: 'No file path' }));
15
+ return;
16
+ }
17
+
18
+ try {
19
+ await init();
20
+
21
+ const fileName = filePath.split('/').pop();
22
+ const ext = fileName.split('.').pop();
23
+ const query = `editing ${fileName} ${ext} file patterns conventions`;
24
+
25
+ const results = await searchWithSalience(query, {
26
+ limit: 3,
27
+ threshold: 0.4,
28
+ decay: 0.03,
29
+ candidatePool: 15,
30
+ });
31
+
32
+ if (results.length === 0) {
33
+ console.log(JSON.stringify({ daxiom_intel: false }));
34
+ return;
35
+ }
36
+
37
+ const hints = results.map(r => `${r.patternName}: ${r.description.substring(0, 120)}`);
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));
46
+ } catch (err) {
47
+ console.log(JSON.stringify({ daxiom_intel: false, error: err.message }));
48
+ } finally {
49
+ await close();
50
+ }
51
+ }
52
+
53
+ module.exports = { run };
@@ -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)) {
@@ -0,0 +1,63 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const { init, close, storeLearnedPattern } = require('../index');
5
+
6
+ /**
7
+ * Remember hook: track file access, search patterns, and agent spawns in DAXIOM.
8
+ * Builds a cross-repo activity graph for learning and context retrieval.
9
+ *
10
+ * Usage:
11
+ * daxiom hooks remember "Reading: src/foo.ts" -t file_access
12
+ * daxiom hooks remember "Search: auth pattern" -t search_pattern
13
+ * daxiom hooks remember "Agent: coder" -t agent_spawn
14
+ *
15
+ * @param {string[]} args - [description, -t type]
16
+ */
17
+ async function run(args) {
18
+ let description = '';
19
+ let activityType = 'general';
20
+
21
+ for (let i = 0; i < args.length; i++) {
22
+ if (args[i] === '-t' && i + 1 < args.length) {
23
+ activityType = args[++i];
24
+ } else {
25
+ description += (description ? ' ' : '') + args[i];
26
+ }
27
+ }
28
+
29
+ if (!description) return;
30
+
31
+ // Throttle: only record 1 in 5 file reads to avoid flooding
32
+ if (activityType === 'file_access' && Math.random() > 0.2) return;
33
+
34
+ try {
35
+ await init();
36
+
37
+ const repo = path.basename(process.cwd());
38
+ const slug = description.replace(/[^a-z0-9\s]/gi, '').trim()
39
+ .split(/\s+/).slice(0, 5).join('_').substring(0, 60);
40
+
41
+ await storeLearnedPattern({
42
+ patternName: `mem_${activityType}_${slug}`,
43
+ description,
44
+ compactText: `${activityType}: ${description} (${repo})`,
45
+ patternClass: 'activity',
46
+ namespace: repo,
47
+ category: activityType,
48
+ tier: 'cold',
49
+ tags: [repo, activityType],
50
+ metadata: {
51
+ activityType,
52
+ repo,
53
+ trackedAt: new Date().toISOString(),
54
+ },
55
+ });
56
+ } catch {
57
+ // Non-fatal
58
+ } finally {
59
+ await close();
60
+ }
61
+ }
62
+
63
+ module.exports = { run };
@@ -0,0 +1,50 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const { init, close, storeLearnedPattern, updateTiers } = require('../index');
5
+
6
+ /**
7
+ * Session-end hook: store session summary in DAXIOM and run tier maintenance.
8
+ * Captures what repo was worked on, when, and triggers tier decay.
9
+ *
10
+ * @param {string[]} args - unused
11
+ */
12
+ async function run(args) {
13
+ try {
14
+ await init();
15
+
16
+ const repo = path.basename(process.cwd());
17
+ const now = new Date();
18
+ const sessionId = `${now.toISOString().slice(0, 10)}-${repo}-${now.getHours()}${now.getMinutes()}`;
19
+
20
+ await storeLearnedPattern({
21
+ patternName: `session_end_${sessionId}`,
22
+ description: `Session ended in ${repo} at ${now.toISOString()}`,
23
+ compactText: `Claude session in ${repo} ended. Date: ${now.toISOString().slice(0, 10)}.`,
24
+ patternClass: 'session',
25
+ namespace: 'session-memory',
26
+ category: 'session',
27
+ tier: 'warm',
28
+ tags: [repo, 'session-end'],
29
+ metadata: {
30
+ repo,
31
+ endedAt: now.toISOString(),
32
+ cwd: process.cwd(),
33
+ },
34
+ });
35
+
36
+ // Run tier maintenance on every session end
37
+ const tierResult = await updateTiers();
38
+ if (tierResult.promoted + tierResult.demotedToWarm + tierResult.demotedToCold > 0) {
39
+ console.error(`[DAXIOM] Tier maintenance: ${JSON.stringify(tierResult)}`);
40
+ }
41
+
42
+ console.log(JSON.stringify({ session_ended: true, repo, tiers: tierResult }));
43
+ } catch (err) {
44
+ console.error('DAXIOM session-end error:', err.message);
45
+ } finally {
46
+ await close();
47
+ }
48
+ }
49
+
50
+ module.exports = { run };
@@ -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 };
@@ -0,0 +1,48 @@
1
+ 'use strict';
2
+
3
+ const path = require('path');
4
+ const { init, close, searchWithSalience } = require('../index');
5
+
6
+ /**
7
+ * Suggest-context hook: on each user prompt, surface relevant DAXIOM patterns.
8
+ * Reads CLAUDE_USER_PROMPT env var or args to find matching patterns.
9
+ *
10
+ * @param {string[]} args - [prompt text] or reads $CLAUDE_USER_PROMPT
11
+ */
12
+ async function run(args) {
13
+ const prompt = args.join(' ') || process.env.CLAUDE_USER_PROMPT || '';
14
+ if (!prompt || prompt.length < 5) return;
15
+
16
+ try {
17
+ await init();
18
+
19
+ const repo = path.basename(process.cwd());
20
+
21
+ const results = await searchWithSalience(prompt, {
22
+ limit: 3,
23
+ threshold: 0.45,
24
+ decay: 0.03,
25
+ candidatePool: 15,
26
+ });
27
+
28
+ if (results.length === 0) return;
29
+
30
+ const learned = results.filter(r => r.patternClass === 'learned' || r.namespace === repo);
31
+ const display = (learned.length > 0 ? learned : results).slice(0, 2);
32
+
33
+ const hints = display.map(r =>
34
+ `${r.patternName} (${r.namespace}, ${r.patternClass}): ${r.description.substring(0, 150)}`
35
+ );
36
+
37
+ const additionalContext = `DAXIOM Intelligence: ${hints.join('; ')}`;
38
+ console.log(JSON.stringify({
39
+ hookSpecificOutput: { hookEventName: 'UserPromptSubmit', additionalContext },
40
+ }));
41
+ } catch {
42
+ // Non-fatal
43
+ } finally {
44
+ await close();
45
+ }
46
+ }
47
+
48
+ module.exports = { run };
@@ -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 };