@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 +1 -1
- package/src/cli.js +3 -2
- package/src/constants.js +3 -0
- package/src/hooks/index.js +76 -10
- package/src/hooks/post-command.js +50 -0
- package/src/hooks/post-edit.js +49 -0
- package/src/hooks/post-failure.js +93 -0
- package/src/hooks/pre-command.js +44 -0
- package/src/hooks/pre-edit.js +53 -0
- package/src/hooks/pre-task.js +17 -1
- package/src/hooks/remember.js +63 -0
- package/src/hooks/session-end.js +50 -0
- package/src/hooks/session-start.js +6 -1
- package/src/hooks/subagent-start.js +72 -0
- package/src/hooks/subagent-stop.js +89 -0
- package/src/hooks/suggest-context.js +48 -0
- package/src/hooks/task-completed.js +57 -0
package/package.json
CHANGED
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.
|
|
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
|
|
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 = [
|
package/src/hooks/index.js
CHANGED
|
@@ -7,11 +7,22 @@ const { loadEnv } = require('./env');
|
|
|
7
7
|
* Usage: daxiom hooks <subcommand> [args...]
|
|
8
8
|
*
|
|
9
9
|
* Subcommands:
|
|
10
|
-
* pre-task
|
|
11
|
-
* post-task
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
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
|
|
49
|
-
console.log(' post-task
|
|
50
|
-
console.log('
|
|
51
|
-
console.log('
|
|
52
|
-
console.log('
|
|
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 };
|
package/src/hooks/pre-task.js
CHANGED
|
@@ -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
|
|
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({
|
|
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 };
|