super-memory-pro 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +247 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +25 -0
- package/dist/config.js.map +1 -0
- package/dist/db/connection.d.ts +20 -0
- package/dist/db/connection.d.ts.map +1 -0
- package/dist/db/connection.js +66 -0
- package/dist/db/connection.js.map +1 -0
- package/dist/db/migrations/001_initial.sql +102 -0
- package/dist/db/migrations.d.ts +14 -0
- package/dist/db/migrations.d.ts.map +1 -0
- package/dist/db/migrations.js +86 -0
- package/dist/db/migrations.js.map +1 -0
- package/dist/db/queries.d.ts +24 -0
- package/dist/db/queries.d.ts.map +1 -0
- package/dist/db/queries.js +179 -0
- package/dist/db/queries.js.map +1 -0
- package/dist/hooks/event-handler.d.ts +13 -0
- package/dist/hooks/event-handler.d.ts.map +1 -0
- package/dist/hooks/event-handler.js +80 -0
- package/dist/hooks/event-handler.js.map +1 -0
- package/dist/hooks/index.d.ts +4 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +7 -0
- package/dist/hooks/index.js.map +1 -0
- package/dist/hooks/message-handler.d.ts +13 -0
- package/dist/hooks/message-handler.d.ts.map +1 -0
- package/dist/hooks/message-handler.js +47 -0
- package/dist/hooks/message-handler.js.map +1 -0
- package/dist/hooks/session-compactor.d.ts +15 -0
- package/dist/hooks/session-compactor.d.ts.map +1 -0
- package/dist/hooks/session-compactor.js +40 -0
- package/dist/hooks/session-compactor.js.map +1 -0
- package/dist/hooks/system-transform.d.ts +27 -0
- package/dist/hooks/system-transform.d.ts.map +1 -0
- package/dist/hooks/system-transform.js +76 -0
- package/dist/hooks/system-transform.js.map +1 -0
- package/dist/hooks/tool-handler.d.ts +14 -0
- package/dist/hooks/tool-handler.d.ts.map +1 -0
- package/dist/hooks/tool-handler.js +94 -0
- package/dist/hooks/tool-handler.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +152 -0
- package/dist/index.js.map +1 -0
- package/dist/installer/index.d.ts +19 -0
- package/dist/installer/index.d.ts.map +1 -0
- package/dist/installer/index.js +553 -0
- package/dist/installer/index.js.map +1 -0
- package/dist/memory/extractor.d.ts +29 -0
- package/dist/memory/extractor.d.ts.map +1 -0
- package/dist/memory/extractor.js +426 -0
- package/dist/memory/extractor.js.map +1 -0
- package/dist/memory/index.d.ts +7 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +7 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/processor.d.ts +50 -0
- package/dist/memory/processor.d.ts.map +1 -0
- package/dist/memory/processor.js +199 -0
- package/dist/memory/processor.js.map +1 -0
- package/dist/memory/search.d.ts +35 -0
- package/dist/memory/search.d.ts.map +1 -0
- package/dist/memory/search.js +170 -0
- package/dist/memory/search.js.map +1 -0
- package/dist/memory/store.d.ts +32 -0
- package/dist/memory/store.d.ts.map +1 -0
- package/dist/memory/store.js +112 -0
- package/dist/memory/store.js.map +1 -0
- package/dist/server/index.d.ts +16 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +49 -0
- package/dist/server/index.js.map +1 -0
- package/dist/server/middleware/async-handler.d.ts +11 -0
- package/dist/server/middleware/async-handler.d.ts.map +1 -0
- package/dist/server/middleware/async-handler.js +14 -0
- package/dist/server/middleware/async-handler.js.map +1 -0
- package/dist/server/middleware/error-handler.d.ts +11 -0
- package/dist/server/middleware/error-handler.d.ts.map +1 -0
- package/dist/server/middleware/error-handler.js +18 -0
- package/dist/server/middleware/error-handler.js.map +1 -0
- package/dist/server/routes/health.d.ts +2 -0
- package/dist/server/routes/health.d.ts.map +1 -0
- package/dist/server/routes/health.js +25 -0
- package/dist/server/routes/health.js.map +1 -0
- package/dist/server/routes/memory.d.ts +2 -0
- package/dist/server/routes/memory.d.ts.map +1 -0
- package/dist/server/routes/memory.js +139 -0
- package/dist/server/routes/memory.js.map +1 -0
- package/dist/server/schemas.d.ts +51 -0
- package/dist/server/schemas.d.ts.map +1 -0
- package/dist/server/schemas.js +23 -0
- package/dist/server/schemas.js.map +1 -0
- package/dist/tools/definitions.d.ts +130 -0
- package/dist/tools/definitions.d.ts.map +1 -0
- package/dist/tools/definitions.js +78 -0
- package/dist/tools/definitions.js.map +1 -0
- package/dist/tools/index.d.ts +32 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +148 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/types.d.ts +108 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +12 -0
- package/dist/types.js.map +1 -0
- package/package.json +70 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import { getPool } from './connection.js';
|
|
2
|
+
// ─── Memories ───────────────────────────────────────────────────────────────
|
|
3
|
+
export async function createMemory(data) {
|
|
4
|
+
const pool = getPool();
|
|
5
|
+
const result = await pool.query(`INSERT INTO memories (memory_type, project_id, session_id, key, value, content, importance, source, metadata)
|
|
6
|
+
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
|
7
|
+
ON CONFLICT (memory_type, project_id, key)
|
|
8
|
+
DO UPDATE SET content = EXCLUDED.content, importance = EXCLUDED.importance, updated_at = NOW()
|
|
9
|
+
RETURNING *`, [
|
|
10
|
+
data.memory_type,
|
|
11
|
+
data.project_id ?? null,
|
|
12
|
+
data.session_id ?? null,
|
|
13
|
+
data.key,
|
|
14
|
+
JSON.stringify(data.value ?? {}),
|
|
15
|
+
data.content,
|
|
16
|
+
data.importance ?? 3,
|
|
17
|
+
data.source ?? 'auto',
|
|
18
|
+
JSON.stringify(data.metadata ?? {}),
|
|
19
|
+
]);
|
|
20
|
+
return result.rows[0];
|
|
21
|
+
}
|
|
22
|
+
export async function getMemory(id) {
|
|
23
|
+
const pool = getPool();
|
|
24
|
+
const result = await pool.query('SELECT * FROM memories WHERE id = $1', [id]);
|
|
25
|
+
return result.rows[0] ?? null;
|
|
26
|
+
}
|
|
27
|
+
export async function searchMemories(query) {
|
|
28
|
+
const pool = getPool();
|
|
29
|
+
const { query: searchText, types, project_id, limit = 10, offset = 0 } = query;
|
|
30
|
+
const conditions = [];
|
|
31
|
+
const params = [];
|
|
32
|
+
// $1 is always reserved for the search text (used in CASE and tsquery)
|
|
33
|
+
let paramIdx = 2;
|
|
34
|
+
// Full-text search
|
|
35
|
+
if (searchText) {
|
|
36
|
+
conditions.push(`search_vector @@ plainto_tsquery('english', $1)`);
|
|
37
|
+
}
|
|
38
|
+
// Type filter
|
|
39
|
+
if (types && types.length > 0) {
|
|
40
|
+
conditions.push(`memory_type = ANY($${paramIdx}::text[])`);
|
|
41
|
+
params.push(types);
|
|
42
|
+
paramIdx++;
|
|
43
|
+
}
|
|
44
|
+
// Project filter
|
|
45
|
+
if (project_id) {
|
|
46
|
+
conditions.push(`project_id = $${paramIdx}`);
|
|
47
|
+
params.push(project_id);
|
|
48
|
+
paramIdx++;
|
|
49
|
+
}
|
|
50
|
+
const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';
|
|
51
|
+
const sql = `
|
|
52
|
+
SELECT *,
|
|
53
|
+
CASE WHEN $1::text IS NOT NULL AND $1::text != ''
|
|
54
|
+
THEN ts_rank(search_vector, plainto_tsquery('english', $1::text))
|
|
55
|
+
ELSE importance::float / 5.0
|
|
56
|
+
END AS relevance
|
|
57
|
+
FROM memories
|
|
58
|
+
${where}
|
|
59
|
+
ORDER BY relevance DESC, importance DESC, last_accessed_at DESC NULLS LAST
|
|
60
|
+
LIMIT $${paramIdx} OFFSET $${paramIdx + 1}
|
|
61
|
+
`;
|
|
62
|
+
const allParams = [searchText ?? '', ...params, limit, offset];
|
|
63
|
+
const result = await pool.query(sql, allParams);
|
|
64
|
+
return result.rows.map((row) => ({
|
|
65
|
+
memory: row,
|
|
66
|
+
relevance: row.relevance,
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
export async function updateMemory(id, data) {
|
|
70
|
+
const pool = getPool();
|
|
71
|
+
const sets = [];
|
|
72
|
+
const params = [];
|
|
73
|
+
let idx = 1;
|
|
74
|
+
if (data.content !== undefined) {
|
|
75
|
+
sets.push(`content = $${idx++}`);
|
|
76
|
+
params.push(data.content);
|
|
77
|
+
}
|
|
78
|
+
if (data.value !== undefined) {
|
|
79
|
+
sets.push(`value = $${idx++}`);
|
|
80
|
+
params.push(JSON.stringify(data.value));
|
|
81
|
+
}
|
|
82
|
+
if (data.importance !== undefined) {
|
|
83
|
+
sets.push(`importance = $${idx++}`);
|
|
84
|
+
params.push(data.importance);
|
|
85
|
+
}
|
|
86
|
+
if (data.metadata !== undefined) {
|
|
87
|
+
sets.push(`metadata = $${idx++}`);
|
|
88
|
+
params.push(JSON.stringify(data.metadata));
|
|
89
|
+
}
|
|
90
|
+
if (sets.length === 0)
|
|
91
|
+
return getMemory(id);
|
|
92
|
+
params.push(id);
|
|
93
|
+
const sql = `UPDATE memories SET ${sets.join(', ')} WHERE id = $${idx} RETURNING *`;
|
|
94
|
+
const result = await pool.query(sql, params);
|
|
95
|
+
return result.rows[0] ?? null;
|
|
96
|
+
}
|
|
97
|
+
export async function deleteMemory(id) {
|
|
98
|
+
const pool = getPool();
|
|
99
|
+
const result = await pool.query('DELETE FROM memories WHERE id = $1', [id]);
|
|
100
|
+
return (result.rowCount ?? 0) > 0;
|
|
101
|
+
}
|
|
102
|
+
export async function recordMemoryAccess(id) {
|
|
103
|
+
const pool = getPool();
|
|
104
|
+
await pool.query(`UPDATE memories SET access_count = access_count + 1, last_accessed_at = NOW() WHERE id = $1`, [id]);
|
|
105
|
+
}
|
|
106
|
+
export async function getMemoryStats() {
|
|
107
|
+
const pool = getPool();
|
|
108
|
+
const result = await pool.query('SELECT memory_type AS type, COUNT(*)::int AS count FROM memories GROUP BY memory_type ORDER BY count DESC');
|
|
109
|
+
return result.rows;
|
|
110
|
+
}
|
|
111
|
+
// ─── Sessions ───────────────────────────────────────────────────────────────
|
|
112
|
+
export async function createSession(id, projectId) {
|
|
113
|
+
const pool = getPool();
|
|
114
|
+
const result = await pool.query('INSERT INTO sessions (id, project_id) VALUES ($1, $2) RETURNING *', [id, projectId ?? null]);
|
|
115
|
+
return result.rows[0];
|
|
116
|
+
}
|
|
117
|
+
export async function getSession(id) {
|
|
118
|
+
const pool = getPool();
|
|
119
|
+
const result = await pool.query('SELECT * FROM sessions WHERE id = $1', [id]);
|
|
120
|
+
return result.rows[0] ?? null;
|
|
121
|
+
}
|
|
122
|
+
export async function updateSession(id, data) {
|
|
123
|
+
const pool = getPool();
|
|
124
|
+
const sets = [];
|
|
125
|
+
const params = [];
|
|
126
|
+
let idx = 1;
|
|
127
|
+
if (data.summary !== undefined) {
|
|
128
|
+
sets.push(`summary = $${idx++}`);
|
|
129
|
+
params.push(data.summary);
|
|
130
|
+
}
|
|
131
|
+
if (data.message_count !== undefined) {
|
|
132
|
+
sets.push(`message_count = $${idx++}`);
|
|
133
|
+
params.push(data.message_count);
|
|
134
|
+
}
|
|
135
|
+
if (data.tokens_used !== undefined) {
|
|
136
|
+
sets.push(`tokens_used = $${idx++}`);
|
|
137
|
+
params.push(data.tokens_used);
|
|
138
|
+
}
|
|
139
|
+
if (data.ended_at !== undefined) {
|
|
140
|
+
sets.push(`ended_at = $${idx++}`);
|
|
141
|
+
params.push(data.ended_at);
|
|
142
|
+
}
|
|
143
|
+
if (data.metadata !== undefined) {
|
|
144
|
+
sets.push(`metadata = $${idx++}`);
|
|
145
|
+
params.push(JSON.stringify(data.metadata));
|
|
146
|
+
}
|
|
147
|
+
if (sets.length === 0)
|
|
148
|
+
return getSession(id);
|
|
149
|
+
params.push(id);
|
|
150
|
+
const sql = `UPDATE sessions SET ${sets.join(', ')} WHERE id = $${idx} RETURNING *`;
|
|
151
|
+
const result = await pool.query(sql, params);
|
|
152
|
+
return result.rows[0] ?? null;
|
|
153
|
+
}
|
|
154
|
+
// ─── Projects ───────────────────────────────────────────────────────────────
|
|
155
|
+
export async function createProject(data) {
|
|
156
|
+
const pool = getPool();
|
|
157
|
+
const result = await pool.query(`INSERT INTO projects (id, name, path, description)
|
|
158
|
+
VALUES ($1, $2, $3, $4)
|
|
159
|
+
ON CONFLICT (id) DO UPDATE SET name = EXCLUDED.name, updated_at = NOW()
|
|
160
|
+
RETURNING *`, [data.id, data.name, data.path ?? null, data.description ?? null]);
|
|
161
|
+
return result.rows[0];
|
|
162
|
+
}
|
|
163
|
+
export async function getProject(id) {
|
|
164
|
+
const pool = getPool();
|
|
165
|
+
const result = await pool.query('SELECT * FROM projects WHERE id = $1', [id]);
|
|
166
|
+
return result.rows[0] ?? null;
|
|
167
|
+
}
|
|
168
|
+
export async function updateProjectTechStack(projectId, tech) {
|
|
169
|
+
const pool = getPool();
|
|
170
|
+
await pool.query(`UPDATE projects SET tech_stack = (
|
|
171
|
+
SELECT jsonb_agg(DISTINCT value) FROM jsonb_array_elements_text(tech_stack || $2::jsonb) AS value
|
|
172
|
+
), updated_at = NOW() WHERE id = $1`, [projectId, JSON.stringify(tech)]);
|
|
173
|
+
}
|
|
174
|
+
export async function getAllProjects() {
|
|
175
|
+
const pool = getPool();
|
|
176
|
+
const result = await pool.query('SELECT * FROM projects ORDER BY updated_at DESC');
|
|
177
|
+
return result.rows;
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=queries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queries.js","sourceRoot":"","sources":["../../src/db/queries.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Hooks } from '@opencode-ai/plugin';
|
|
2
|
+
/**
|
|
3
|
+
* Create a handler for the `event` hook.
|
|
4
|
+
*
|
|
5
|
+
* Filters for relevant event types and triggers memory processing:
|
|
6
|
+
* - On message completion: extracts text and stores via the processor
|
|
7
|
+
* - On session lifecycle: logs and updates session context
|
|
8
|
+
*
|
|
9
|
+
* The handler is fire-and-forget — it returns immediately without awaiting
|
|
10
|
+
* any memory operations.
|
|
11
|
+
*/
|
|
12
|
+
export declare function createEventHandler(): Hooks['event'];
|
|
13
|
+
//# sourceMappingURL=event-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-handler.d.ts","sourceRoot":"","sources":["../../src/hooks/event-handler.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAIjD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,IAAI,KAAK,CAAC,OAAO,CAAC,CAsDnD"}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// ─── Event Handler ───────────────────────────────────────────────────────────
|
|
2
|
+
// Handles the `event` hook — listens for relevant lifecycle events and
|
|
3
|
+
// updates the memory system accordingly. Fire-and-forget to never block.
|
|
4
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
5
|
+
import { processMessage } from '../memory/processor.js';
|
|
6
|
+
/**
|
|
7
|
+
* Create a handler for the `event` hook.
|
|
8
|
+
*
|
|
9
|
+
* Filters for relevant event types and triggers memory processing:
|
|
10
|
+
* - On message completion: extracts text and stores via the processor
|
|
11
|
+
* - On session lifecycle: logs and updates session context
|
|
12
|
+
*
|
|
13
|
+
* The handler is fire-and-forget — it returns immediately without awaiting
|
|
14
|
+
* any memory operations.
|
|
15
|
+
*/
|
|
16
|
+
export function createEventHandler() {
|
|
17
|
+
return async ({ event }) => {
|
|
18
|
+
// Fire-and-forget: kick off async work without awaiting
|
|
19
|
+
const run = async () => {
|
|
20
|
+
try {
|
|
21
|
+
if (!isRelevantEvent(event))
|
|
22
|
+
return;
|
|
23
|
+
switch (event.type) {
|
|
24
|
+
case 'message.updated': {
|
|
25
|
+
const { info } = event.properties;
|
|
26
|
+
// Only process assistant messages (completions) that have text
|
|
27
|
+
if (info.role !== 'assistant')
|
|
28
|
+
return;
|
|
29
|
+
// Record that an assistant interaction occurred
|
|
30
|
+
const summaryLine = `Assistant responded (model: ${info.modelID})`;
|
|
31
|
+
await processMessage(summaryLine, {
|
|
32
|
+
sessionId: info.sessionID,
|
|
33
|
+
source: 'event',
|
|
34
|
+
});
|
|
35
|
+
break;
|
|
36
|
+
}
|
|
37
|
+
case 'session.created': {
|
|
38
|
+
const sessionInfo = event.properties.info;
|
|
39
|
+
console.log(`[UltraMemory] Session created: ${sessionInfo.id} (${sessionInfo.title})`);
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
case 'session.updated': {
|
|
43
|
+
const sessionInfo = event.properties.info;
|
|
44
|
+
console.log(`[UltraMemory] Session updated: ${sessionInfo.id}`);
|
|
45
|
+
break;
|
|
46
|
+
}
|
|
47
|
+
case 'session.compacted': {
|
|
48
|
+
const { sessionID } = event.properties;
|
|
49
|
+
console.log(`[UltraMemory] Session compacted: ${sessionID}`);
|
|
50
|
+
break;
|
|
51
|
+
}
|
|
52
|
+
default:
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
catch (err) {
|
|
57
|
+
console.error('[UltraMemory] event-handler error:', err);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
// Kick off but don't await — fire-and-forget
|
|
61
|
+
void run();
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
65
|
+
/**
|
|
66
|
+
* Event types that the memory system cares about.
|
|
67
|
+
*/
|
|
68
|
+
const RELEVANT_EVENT_TYPES = new Set([
|
|
69
|
+
'message.updated',
|
|
70
|
+
'session.created',
|
|
71
|
+
'session.updated',
|
|
72
|
+
'session.compacted',
|
|
73
|
+
]);
|
|
74
|
+
/**
|
|
75
|
+
* Check whether an event is relevant to the memory system.
|
|
76
|
+
*/
|
|
77
|
+
function isRelevantEvent(event) {
|
|
78
|
+
return RELEVANT_EVENT_TYPES.has(event.type);
|
|
79
|
+
}
|
|
80
|
+
//# sourceMappingURL=event-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"event-handler.js","sourceRoot":"","sources":["../../src/hooks/event-handler.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,uEAAuE;AACvE,yEAAyE;AACzE,iFAAiF;AAIjF,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD;;;;;;;;;GASG;AACH,MAAM,UAAU,kBAAkB;IAChC,OAAO,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;QACzB,wDAAwD;QACxD,MAAM,GAAG,GAAG,KAAK,IAAmB,EAAE;YACpC,IAAI,CAAC;gBACH,IAAI,CAAC,eAAe,CAAC,KAAK,CAAC;oBAAE,OAAO;gBAEpC,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;oBACnB,KAAK,iBAAiB,CAAC,CAAC,CAAC;wBACvB,MAAM,EAAE,IAAI,EAAE,GAAG,KAAK,CAAC,UAAU,CAAC;wBAClC,+DAA+D;wBAC/D,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW;4BAAE,OAAO;wBAEtC,gDAAgD;wBAChD,MAAM,WAAW,GAAG,+BAA+B,IAAI,CAAC,OAAO,GAAG,CAAC;wBAEnE,MAAM,cAAc,CAAC,WAAW,EAAE;4BAChC,SAAS,EAAE,IAAI,CAAC,SAAS;4BACzB,MAAM,EAAE,OAAO;yBAChB,CAAC,CAAC;wBACH,MAAM;oBACR,CAAC;oBAED,KAAK,iBAAiB,CAAC,CAAC,CAAC;wBACvB,MAAM,WAAW,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;wBAC1C,OAAO,CAAC,GAAG,CACT,kCAAkC,WAAW,CAAC,EAAE,KAAK,WAAW,CAAC,KAAK,GAAG,CAC1E,CAAC;wBACF,MAAM;oBACR,CAAC;oBAED,KAAK,iBAAiB,CAAC,CAAC,CAAC;wBACvB,MAAM,WAAW,GAAG,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC;wBAC1C,OAAO,CAAC,GAAG,CAAC,kCAAkC,WAAW,CAAC,EAAE,EAAE,CAAC,CAAC;wBAChE,MAAM;oBACR,CAAC;oBAED,KAAK,mBAAmB,CAAC,CAAC,CAAC;wBACzB,MAAM,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC,UAAU,CAAC;wBACvC,OAAO,CAAC,GAAG,CAAC,oCAAoC,SAAS,EAAE,CAAC,CAAC;wBAC7D,MAAM;oBACR,CAAC;oBAED;wBACE,MAAM;gBACV,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,GAAG,CAAC,CAAC;YAC3D,CAAC;QACH,CAAC,CAAC;QAEF,6CAA6C;QAC7C,KAAK,GAAG,EAAE,CAAC;IACb,CAAC,CAAC;AACJ,CAAC;AAED,gFAAgF;AAEhF;;GAEG;AACH,MAAM,oBAAoB,GAAG,IAAI,GAAG,CAAC;IACnC,iBAAiB;IACjB,iBAAiB;IACjB,iBAAiB;IACjB,mBAAmB;CACpB,CAAC,CAAC;AAEH;;GAEG;AACH,SAAS,eAAe,CAAC,KAAY;IACnC,OAAO,oBAAoB,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// ─── Hooks Barrel ────────────────────────────────────────────────────────────
|
|
2
|
+
// Re-exports all hook handler factories for use by the plugin entry point.
|
|
3
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
4
|
+
export { createMessageHandler } from './message-handler.js';
|
|
5
|
+
export { createEventHandler } from './event-handler.js';
|
|
6
|
+
export { createToolAfterHandler } from './tool-handler.js';
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/hooks/index.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,2EAA2E;AAC3E,iFAAiF;AAEjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AACxD,OAAO,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Hooks } from '@opencode-ai/plugin';
|
|
2
|
+
/**
|
|
3
|
+
* Create a handler for the `chat.message` hook.
|
|
4
|
+
*
|
|
5
|
+
* Extracts message text from text-type parts and feeds it into the memory
|
|
6
|
+
* processor for automatic extraction of tech stack, decisions, preferences,
|
|
7
|
+
* patterns, and content classification.
|
|
8
|
+
*
|
|
9
|
+
* The handler is fire-and-forget — it returns immediately without awaiting
|
|
10
|
+
* the memory processor, ensuring it never blocks message flow.
|
|
11
|
+
*/
|
|
12
|
+
export declare function createMessageHandler(): Hooks['chat.message'];
|
|
13
|
+
//# sourceMappingURL=message-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-handler.d.ts","sourceRoot":"","sources":["../../src/hooks/message-handler.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAWjD;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,IAAI,KAAK,CAAC,cAAc,CAAC,CA0B5D"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// ─── Message Handler ─────────────────────────────────────────────────────────
|
|
2
|
+
// Handles the `chat.message` hook — extracts text from messages and stores
|
|
3
|
+
// them as memories via the memory processor. Fire-and-forget to never block.
|
|
4
|
+
// ──────────────────────────────────────────────────────────────────────────────
|
|
5
|
+
import { processMessage } from '../memory/processor.js';
|
|
6
|
+
/**
|
|
7
|
+
* Narrow a `Part` to a `TextPart` by discriminating on the `type` field.
|
|
8
|
+
*/
|
|
9
|
+
function isTextPart(part) {
|
|
10
|
+
return part.type === 'text';
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Create a handler for the `chat.message` hook.
|
|
14
|
+
*
|
|
15
|
+
* Extracts message text from text-type parts and feeds it into the memory
|
|
16
|
+
* processor for automatic extraction of tech stack, decisions, preferences,
|
|
17
|
+
* patterns, and content classification.
|
|
18
|
+
*
|
|
19
|
+
* The handler is fire-and-forget — it returns immediately without awaiting
|
|
20
|
+
* the memory processor, ensuring it never blocks message flow.
|
|
21
|
+
*/
|
|
22
|
+
export function createMessageHandler() {
|
|
23
|
+
return async (input, output) => {
|
|
24
|
+
// Fire-and-forget: kick off async work without awaiting
|
|
25
|
+
const run = async () => {
|
|
26
|
+
try {
|
|
27
|
+
const { sessionID } = input;
|
|
28
|
+
const { parts } = output;
|
|
29
|
+
// Filter for text-type parts and extract their content
|
|
30
|
+
const textParts = parts.filter(isTextPart);
|
|
31
|
+
const content = textParts.map((p) => p.text).join('\n').trim();
|
|
32
|
+
if (!content)
|
|
33
|
+
return;
|
|
34
|
+
await processMessage(content, {
|
|
35
|
+
sessionId: sessionID,
|
|
36
|
+
source: 'chat',
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
console.error('[UltraMemory] message-handler error:', err);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
// Kick off but don't await — fire-and-forget
|
|
44
|
+
void run();
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=message-handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"message-handler.js","sourceRoot":"","sources":["../../src/hooks/message-handler.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,2EAA2E;AAC3E,6EAA6E;AAC7E,iFAAiF;AAIjF,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAExD;;GAEG;AACH,SAAS,UAAU,CAAC,IAAU;IAC5B,OAAO,IAAI,CAAC,IAAI,KAAK,MAAM,CAAC;AAC9B,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;QAC7B,wDAAwD;QACxD,MAAM,GAAG,GAAG,KAAK,IAAmB,EAAE;YACpC,IAAI,CAAC;gBACH,MAAM,EAAE,SAAS,EAAE,GAAG,KAAK,CAAC;gBAC5B,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC;gBAEzB,uDAAuD;gBACvD,MAAM,SAAS,GAAG,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;gBAC3C,MAAM,OAAO,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;gBAE/D,IAAI,CAAC,OAAO;oBAAE,OAAO;gBAErB,MAAM,cAAc,CAAC,OAAO,EAAE;oBAC5B,SAAS,EAAE,SAAS;oBACpB,MAAM,EAAE,MAAM;iBACf,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,OAAO,CAAC,KAAK,CAAC,sCAAsC,EAAE,GAAG,CAAC,CAAC;YAC7D,CAAC;QACH,CAAC,CAAC;QAEF,6CAA6C;QAC7C,KAAK,GAAG,EAAE,CAAC;IACb,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Hooks } from '@opencode-ai/plugin';
|
|
2
|
+
/**
|
|
3
|
+
* Create a session compaction hook for the Ultra Memory plugin.
|
|
4
|
+
*
|
|
5
|
+
* Hooks into `experimental.session.compacting` to add context hints
|
|
6
|
+
* that tell the compactor to preserve important memory-related information
|
|
7
|
+
* (tech stack, decisions, preferences, patterns, conventions).
|
|
8
|
+
*
|
|
9
|
+
* The hook does NOT override the default compaction prompt — it only
|
|
10
|
+
* appends additional context strings to guide what should be retained.
|
|
11
|
+
*
|
|
12
|
+
* @returns The hook function to assign to `experimental.session.compacting`
|
|
13
|
+
*/
|
|
14
|
+
export declare function createSessionCompactor(): NonNullable<Hooks['experimental.session.compacting']>;
|
|
15
|
+
//# sourceMappingURL=session-compactor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-compactor.d.ts","sourceRoot":"","sources":["../../src/hooks/session-compactor.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAYjD;;;;;;;;;;;GAWG;AACH,wBAAgB,sBAAsB,IAAI,WAAW,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC,CAiB9F"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
// ─── Session Compactor Hook ────────────────────────────────────────────────
|
|
2
|
+
// Preserves important context during session compaction.
|
|
3
|
+
// Tells the compactor which information types to retain.
|
|
4
|
+
/**
|
|
5
|
+
* Context strings added to the compaction prompt.
|
|
6
|
+
* These instruct the compactor to preserve memory-related information.
|
|
7
|
+
*/
|
|
8
|
+
const COMPACTION_CONTEXT_HINTS = [
|
|
9
|
+
'Preserve any tech stack, decisions, and user preferences mentioned',
|
|
10
|
+
'Keep architectural decisions and their rationale',
|
|
11
|
+
'Retain project-specific conventions and patterns',
|
|
12
|
+
];
|
|
13
|
+
/**
|
|
14
|
+
* Create a session compaction hook for the Ultra Memory plugin.
|
|
15
|
+
*
|
|
16
|
+
* Hooks into `experimental.session.compacting` to add context hints
|
|
17
|
+
* that tell the compactor to preserve important memory-related information
|
|
18
|
+
* (tech stack, decisions, preferences, patterns, conventions).
|
|
19
|
+
*
|
|
20
|
+
* The hook does NOT override the default compaction prompt — it only
|
|
21
|
+
* appends additional context strings to guide what should be retained.
|
|
22
|
+
*
|
|
23
|
+
* @returns The hook function to assign to `experimental.session.compacting`
|
|
24
|
+
*/
|
|
25
|
+
export function createSessionCompactor() {
|
|
26
|
+
return async (_input, output) => {
|
|
27
|
+
try {
|
|
28
|
+
// Append compaction context hints — these tell the compactor what
|
|
29
|
+
// information is important to preserve for Ultra Memory.
|
|
30
|
+
output.context.push(...COMPACTION_CONTEXT_HINTS);
|
|
31
|
+
// Do NOT override the prompt — leave it as undefined so the
|
|
32
|
+
// default compaction prompt is used.
|
|
33
|
+
}
|
|
34
|
+
catch (err) {
|
|
35
|
+
// Fire-and-forget: never let a compaction hook crash the session.
|
|
36
|
+
console.error('[UltraMemory] Session compaction hook failed:', err instanceof Error ? err.message : String(err));
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=session-compactor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-compactor.js","sourceRoot":"","sources":["../../src/hooks/session-compactor.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,yDAAyD;AACzD,yDAAyD;AAIzD;;;GAGG;AACH,MAAM,wBAAwB,GAAG;IAC/B,oEAAoE;IACpE,kDAAkD;IAClD,kDAAkD;CACnD,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,sBAAsB;IACpC,OAAO,KAAK,EACV,MAA6B,EAC7B,MAA8C,EAC/B,EAAE;QACjB,IAAI,CAAC;YACH,kEAAkE;YAClE,yDAAyD;YACzD,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,wBAAwB,CAAC,CAAC;YAEjD,4DAA4D;YAC5D,qCAAqC;QACvC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,kEAAkE;YAClE,OAAO,CAAC,KAAK,CAAC,+CAA+C,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC;QACnH,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import type { Hooks } from '@opencode-ai/plugin';
|
|
2
|
+
import type { PluginConfig } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Create the system prompt transform hook.
|
|
5
|
+
*
|
|
6
|
+
* This hook appends relevant memories to the LLM system prompt so the
|
|
7
|
+
* AI has cross-session context about the user, project, and preferences.
|
|
8
|
+
*
|
|
9
|
+
* **Strategy:**
|
|
10
|
+
* - The hook input does **not** include the current user message, so we
|
|
11
|
+
* use a broad search query (`DEFAULT_SEARCH_QUERY`) to fetch high-
|
|
12
|
+
* importance memories across all types.
|
|
13
|
+
* - The `model` parameter is ignored — memories are injected regardless
|
|
14
|
+
* of which LLM is being used.
|
|
15
|
+
* - Respects `config.memory.maxInjections` and `config.memory.minImportance`
|
|
16
|
+
* to control how many memories are injected and their quality floor.
|
|
17
|
+
* - If a Super Memory section already exists in the system prompt array
|
|
18
|
+
* (e.g. from a previous invocation), it is replaced **in-place** rather
|
|
19
|
+
* than duplicated.
|
|
20
|
+
* - All errors are caught and logged — the hook **never throws**, so it
|
|
21
|
+
* cannot crash OpenCode.
|
|
22
|
+
*
|
|
23
|
+
* @param config - Resolved plugin configuration
|
|
24
|
+
* @returns - The system transform hook function
|
|
25
|
+
*/
|
|
26
|
+
export declare function createSystemTransform(config: PluginConfig): NonNullable<Hooks['experimental.chat.system.transform']>;
|
|
27
|
+
//# sourceMappingURL=system-transform.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system-transform.d.ts","sourceRoot":"","sources":["../../src/hooks/system-transform.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAkBhD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,YAAY,GACnB,WAAW,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC,CAwC1D"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
// ─── System Prompt Transform Hook ───────────────────────────────────────
|
|
2
|
+
// Injects relevant memories into the system prompt so the AI can recall
|
|
3
|
+
// past context across sessions.
|
|
4
|
+
//
|
|
5
|
+
// This is the recall mechanism that makes the memory plugin useful — it
|
|
6
|
+
// retrieves the most relevant stored memories and appends them as context
|
|
7
|
+
// to every LLM request.
|
|
8
|
+
import { getContextForQuery } from '../memory/processor.js';
|
|
9
|
+
// ─── Constants ────────────────────────────────────────────────────────────
|
|
10
|
+
const MEMORY_HEADER = '[Super Memory - Relevant Context]';
|
|
11
|
+
const MEMORY_FOOTER = '[End Super Memory]';
|
|
12
|
+
/**
|
|
13
|
+
* Broad search query used to fetch general high-importance memories.
|
|
14
|
+
* Uses broad, inclusive terms to match across all memory types without
|
|
15
|
+
* requiring the current user message (which is not available in this hook).
|
|
16
|
+
*/
|
|
17
|
+
const DEFAULT_SEARCH_QUERY = 'project context preferences decisions tech stack patterns workflow conventions';
|
|
18
|
+
// ─── Hook Factory ─────────────────────────────────────────────────────────
|
|
19
|
+
/**
|
|
20
|
+
* Create the system prompt transform hook.
|
|
21
|
+
*
|
|
22
|
+
* This hook appends relevant memories to the LLM system prompt so the
|
|
23
|
+
* AI has cross-session context about the user, project, and preferences.
|
|
24
|
+
*
|
|
25
|
+
* **Strategy:**
|
|
26
|
+
* - The hook input does **not** include the current user message, so we
|
|
27
|
+
* use a broad search query (`DEFAULT_SEARCH_QUERY`) to fetch high-
|
|
28
|
+
* importance memories across all types.
|
|
29
|
+
* - The `model` parameter is ignored — memories are injected regardless
|
|
30
|
+
* of which LLM is being used.
|
|
31
|
+
* - Respects `config.memory.maxInjections` and `config.memory.minImportance`
|
|
32
|
+
* to control how many memories are injected and their quality floor.
|
|
33
|
+
* - If a Super Memory section already exists in the system prompt array
|
|
34
|
+
* (e.g. from a previous invocation), it is replaced **in-place** rather
|
|
35
|
+
* than duplicated.
|
|
36
|
+
* - All errors are caught and logged — the hook **never throws**, so it
|
|
37
|
+
* cannot crash OpenCode.
|
|
38
|
+
*
|
|
39
|
+
* @param config - Resolved plugin configuration
|
|
40
|
+
* @returns - The system transform hook function
|
|
41
|
+
*/
|
|
42
|
+
export function createSystemTransform(config) {
|
|
43
|
+
return async (_input, output) => {
|
|
44
|
+
try {
|
|
45
|
+
// Fetch relevant memories using a broad query. This ensures the AI
|
|
46
|
+
// always receives context about the project, user preferences, tech
|
|
47
|
+
// stack, decisions, and workflows regardless of the current message.
|
|
48
|
+
const context = await getContextForQuery(DEFAULT_SEARCH_QUERY, {
|
|
49
|
+
maxInjections: config.memory.maxInjections,
|
|
50
|
+
minImportance: config.memory.minImportance,
|
|
51
|
+
});
|
|
52
|
+
// No relevant memories found — leave the system prompt unchanged.
|
|
53
|
+
if (!context || context.trim().length === 0) {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
// Build the memory section as a single, clean markdown block.
|
|
57
|
+
const memorySection = `\n${MEMORY_HEADER}\n${context}\n${MEMORY_FOOTER}`;
|
|
58
|
+
// Check if there is already a Super Memory section in the prompt
|
|
59
|
+
// array. If so, replace it in-place to prevent duplication across
|
|
60
|
+
// multiple hook invocations (defensive — should not happen in
|
|
61
|
+
// normal OpenCode operation but guards against edge cases).
|
|
62
|
+
const existingIdx = output.system.findIndex((s) => s.includes(MEMORY_HEADER));
|
|
63
|
+
if (existingIdx >= 0) {
|
|
64
|
+
output.system[existingIdx] = memorySection;
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
output.system.push(memorySection);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
// Never throw — a hook error must never crash OpenCode.
|
|
72
|
+
console.error('[UltraMemory] system-transform: failed to inject memories', err);
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=system-transform.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system-transform.js","sourceRoot":"","sources":["../../src/hooks/system-transform.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,wEAAwE;AACxE,gCAAgC;AAChC,EAAE;AACF,wEAAwE;AACxE,0EAA0E;AAC1E,wBAAwB;AAIxB,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5D,6EAA6E;AAE7E,MAAM,aAAa,GAAG,mCAAmC,CAAC;AAC1D,MAAM,aAAa,GAAG,oBAAoB,CAAC;AAE3C;;;;GAIG;AACH,MAAM,oBAAoB,GACxB,gFAAgF,CAAC;AAEnF,6EAA6E;AAE7E;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,qBAAqB,CACnC,MAAoB;IAEpB,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,EAAE;QAC9B,IAAI,CAAC;YACH,mEAAmE;YACnE,oEAAoE;YACpE,qEAAqE;YACrE,MAAM,OAAO,GAAG,MAAM,kBAAkB,CAAC,oBAAoB,EAAE;gBAC7D,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,aAAa;gBAC1C,aAAa,EAAE,MAAM,CAAC,MAAM,CAAC,aAAa;aAC3C,CAAC,CAAC;YAEH,kEAAkE;YAClE,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC5C,OAAO;YACT,CAAC;YAED,8DAA8D;YAC9D,MAAM,aAAa,GAAG,KAAK,aAAa,KAAK,OAAO,KAAK,aAAa,EAAE,CAAC;YAEzE,iEAAiE;YACjE,kEAAkE;YAClE,8DAA8D;YAC9D,4DAA4D;YAC5D,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAChD,CAAC,CAAC,QAAQ,CAAC,aAAa,CAAC,CAC1B,CAAC;YAEF,IAAI,WAAW,IAAI,CAAC,EAAE,CAAC;gBACrB,MAAM,CAAC,MAAM,CAAC,WAAW,CAAC,GAAG,aAAa,CAAC;YAC7C,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;YACpC,CAAC;QACH,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,wDAAwD;YACxD,OAAO,CAAC,KAAK,CACX,2DAA2D,EAC3D,GAAG,CACJ,CAAC;QACJ,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Hooks } from '@opencode-ai/plugin';
|
|
2
|
+
/**
|
|
3
|
+
* Create a handler for the `tool.execute.after` hook.
|
|
4
|
+
*
|
|
5
|
+
* When a tool executes successfully, the handler extracts meaningful
|
|
6
|
+
* patterns from the tool output and stores them as `pattern`-type
|
|
7
|
+
* memories. This enables the memory system to learn from tool usage
|
|
8
|
+
* over time.
|
|
9
|
+
*
|
|
10
|
+
* The handler is fire-and-forget — it returns immediately without awaiting
|
|
11
|
+
* any memory operations.
|
|
12
|
+
*/
|
|
13
|
+
export declare function createToolAfterHandler(): Hooks['tool.execute.after'];
|
|
14
|
+
//# sourceMappingURL=tool-handler.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-handler.d.ts","sourceRoot":"","sources":["../../src/hooks/tool-handler.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAGjD;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,IAAI,KAAK,CAAC,oBAAoB,CAAC,CA2CpE"}
|