code-session-memory 0.3.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 +290 -0
- package/dist/mcp/index.d.ts +15 -0
- package/dist/mcp/index.d.ts.map +1 -0
- package/dist/mcp/index.js +140 -0
- package/dist/mcp/index.js.map +1 -0
- package/dist/mcp/server.d.ts +60 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +192 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/src/chunker.d.ts +18 -0
- package/dist/src/chunker.d.ts.map +1 -0
- package/dist/src/chunker.js +149 -0
- package/dist/src/chunker.js.map +1 -0
- package/dist/src/cli.d.ts +11 -0
- package/dist/src/cli.d.ts.map +1 -0
- package/dist/src/cli.js +514 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/database.d.ts +50 -0
- package/dist/src/database.d.ts.map +1 -0
- package/dist/src/database.js +238 -0
- package/dist/src/database.js.map +1 -0
- package/dist/src/embedder.d.ts +19 -0
- package/dist/src/embedder.d.ts.map +1 -0
- package/dist/src/embedder.js +80 -0
- package/dist/src/embedder.js.map +1 -0
- package/dist/src/indexer-cli-claude.d.ts +14 -0
- package/dist/src/indexer-cli-claude.d.ts.map +1 -0
- package/dist/src/indexer-cli-claude.js +67 -0
- package/dist/src/indexer-cli-claude.js.map +1 -0
- package/dist/src/indexer-cli.d.ts +16 -0
- package/dist/src/indexer-cli.d.ts.map +1 -0
- package/dist/src/indexer-cli.js +53 -0
- package/dist/src/indexer-cli.js.map +1 -0
- package/dist/src/indexer.d.ts +44 -0
- package/dist/src/indexer.d.ts.map +1 -0
- package/dist/src/indexer.js +129 -0
- package/dist/src/indexer.js.map +1 -0
- package/dist/src/session-to-md.d.ts +15 -0
- package/dist/src/session-to-md.d.ts.map +1 -0
- package/dist/src/session-to-md.js +148 -0
- package/dist/src/session-to-md.js.map +1 -0
- package/dist/src/transcript-to-messages.d.ts +32 -0
- package/dist/src/transcript-to-messages.d.ts.map +1 -0
- package/dist/src/transcript-to-messages.js +230 -0
- package/dist/src/transcript-to-messages.js.map +1 -0
- package/dist/src/types.d.ts +91 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +3 -0
- package/dist/src/types.js.map +1 -0
- package/package.json +59 -0
- package/plugin/memory.ts +42 -0
- package/skill/memory.md +61 -0
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* MCP query handlers for opencode-memory.
|
|
4
|
+
*
|
|
5
|
+
* Adapted from doc2vec/mcp/src/server.ts — simplified to:
|
|
6
|
+
* - SQLite-vec only (no Qdrant)
|
|
7
|
+
* - Fixed single DB path (no multi-DB resolution)
|
|
8
|
+
* - Two tools: query_sessions + get_session_chunks
|
|
9
|
+
*/
|
|
10
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
11
|
+
exports.createSqliteProvider = createSqliteProvider;
|
|
12
|
+
exports.createToolHandlers = createToolHandlers;
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Provider factory
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
function createSqliteProvider(deps) {
|
|
17
|
+
const { dbPath, sqliteVec, Database, fs } = deps;
|
|
18
|
+
/**
|
|
19
|
+
* Opens a short-lived connection, runs the callback, closes the connection.
|
|
20
|
+
*/
|
|
21
|
+
function withDb(fn) {
|
|
22
|
+
if (!fs.existsSync(dbPath)) {
|
|
23
|
+
throw new Error(`Database not found at ${dbPath}. Run "code-session-memory install" first.`);
|
|
24
|
+
}
|
|
25
|
+
const db = new Database(dbPath);
|
|
26
|
+
sqliteVec.load(db);
|
|
27
|
+
try {
|
|
28
|
+
return fn(db);
|
|
29
|
+
}
|
|
30
|
+
finally {
|
|
31
|
+
db.close();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
// ---- query_sessions -------------------------------------------------------
|
|
35
|
+
async function querySessions(queryEmbedding, topK = 10, projectFilter, sourceFilter) {
|
|
36
|
+
return withDb((db) => {
|
|
37
|
+
let sql = `
|
|
38
|
+
WITH knn AS (
|
|
39
|
+
SELECT
|
|
40
|
+
chunk_id, content, url, section, heading_hierarchy,
|
|
41
|
+
chunk_index, total_chunks, session_id, session_title, project,
|
|
42
|
+
distance
|
|
43
|
+
FROM vec_items
|
|
44
|
+
WHERE embedding MATCH ?
|
|
45
|
+
AND k = ?
|
|
46
|
+
)
|
|
47
|
+
SELECT knn.*, m.source
|
|
48
|
+
FROM knn
|
|
49
|
+
LEFT JOIN sessions_meta m ON knn.session_id = m.session_id
|
|
50
|
+
WHERE 1=1
|
|
51
|
+
`;
|
|
52
|
+
const params = [new Float32Array(queryEmbedding), topK];
|
|
53
|
+
if (projectFilter) {
|
|
54
|
+
sql += " AND knn.project = ?";
|
|
55
|
+
params.push(projectFilter);
|
|
56
|
+
}
|
|
57
|
+
if (sourceFilter) {
|
|
58
|
+
sql += " AND m.source = ?";
|
|
59
|
+
params.push(sourceFilter);
|
|
60
|
+
}
|
|
61
|
+
sql += " ORDER BY distance";
|
|
62
|
+
const rows = db.prepare(sql).all(...params);
|
|
63
|
+
rows.forEach((r) => {
|
|
64
|
+
delete r["embedding"];
|
|
65
|
+
});
|
|
66
|
+
return rows;
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
// ---- get_session_chunks ---------------------------------------------------
|
|
70
|
+
async function getSessionChunks(url, startIndex, endIndex) {
|
|
71
|
+
return withDb((db) => {
|
|
72
|
+
let sql = `
|
|
73
|
+
SELECT chunk_id, content, url, section, heading_hierarchy, chunk_index, total_chunks
|
|
74
|
+
FROM vec_items
|
|
75
|
+
WHERE url = ?
|
|
76
|
+
`;
|
|
77
|
+
const params = [url];
|
|
78
|
+
if (typeof startIndex === "number") {
|
|
79
|
+
sql += " AND chunk_index >= ?";
|
|
80
|
+
params.push(startIndex);
|
|
81
|
+
}
|
|
82
|
+
if (typeof endIndex === "number") {
|
|
83
|
+
sql += " AND chunk_index <= ?";
|
|
84
|
+
params.push(endIndex);
|
|
85
|
+
}
|
|
86
|
+
sql += " ORDER BY chunk_index";
|
|
87
|
+
return db.prepare(sql).all(...params);
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
return { querySessions, getSessionChunks };
|
|
91
|
+
}
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
// MCP tool handlers
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
function createToolHandlers(deps) {
|
|
96
|
+
const { createEmbedding, querySessions, getSessionChunks } = deps;
|
|
97
|
+
// ---- query_sessions handler -----------------------------------------------
|
|
98
|
+
const querySessionsHandler = async (args) => {
|
|
99
|
+
const limit = args.limit ?? 5;
|
|
100
|
+
console.error(`[query_sessions] text="${args.queryText}" project="${args.project ?? "any"}" source="${args.source ?? "any"}" limit=${limit}`);
|
|
101
|
+
try {
|
|
102
|
+
const embedding = await createEmbedding(args.queryText);
|
|
103
|
+
const results = await querySessions(embedding, limit, args.project, args.source);
|
|
104
|
+
if (results.length === 0) {
|
|
105
|
+
return {
|
|
106
|
+
content: [
|
|
107
|
+
{
|
|
108
|
+
type: "text",
|
|
109
|
+
text: `No sessions found matching "${args.queryText}"${args.project ? ` in project "${args.project}"` : ""}.`,
|
|
110
|
+
},
|
|
111
|
+
],
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
const formatted = results
|
|
115
|
+
.map((r, i) => {
|
|
116
|
+
const lines = [
|
|
117
|
+
`Result ${i + 1}:`,
|
|
118
|
+
` Content: ${r.content}`,
|
|
119
|
+
typeof r.distance === "number" ? ` Distance: ${r.distance.toFixed(4)}` : null,
|
|
120
|
+
r.url ? ` URL: ${r.url}` : null,
|
|
121
|
+
r.section ? ` Section: ${r.section}` : null,
|
|
122
|
+
typeof r.chunk_index === "number" && typeof r.total_chunks === "number"
|
|
123
|
+
? ` Chunk: ${r.chunk_index + 1} of ${r.total_chunks}`
|
|
124
|
+
: null,
|
|
125
|
+
"---",
|
|
126
|
+
].filter(Boolean);
|
|
127
|
+
return lines.join("\n");
|
|
128
|
+
})
|
|
129
|
+
.join("\n");
|
|
130
|
+
return {
|
|
131
|
+
content: [
|
|
132
|
+
{
|
|
133
|
+
type: "text",
|
|
134
|
+
text: `Found ${results.length} result(s) for "${args.queryText}":\n\n${formatted}`,
|
|
135
|
+
},
|
|
136
|
+
],
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
catch (err) {
|
|
140
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
141
|
+
console.error("[query_sessions] error:", err);
|
|
142
|
+
return { content: [{ type: "text", text: `Error: ${msg}` }] };
|
|
143
|
+
}
|
|
144
|
+
};
|
|
145
|
+
// ---- get_session_chunks handler -------------------------------------------
|
|
146
|
+
const getSessionChunksHandler = async (args) => {
|
|
147
|
+
console.error(`[get_session_chunks] url="${args.sessionUrl}" start=${args.startIndex} end=${args.endIndex}`);
|
|
148
|
+
try {
|
|
149
|
+
const results = await getSessionChunks(args.sessionUrl, args.startIndex, args.endIndex);
|
|
150
|
+
if (results.length === 0) {
|
|
151
|
+
return {
|
|
152
|
+
content: [
|
|
153
|
+
{
|
|
154
|
+
type: "text",
|
|
155
|
+
text: `No chunks found for "${args.sessionUrl}".`,
|
|
156
|
+
},
|
|
157
|
+
],
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
const formatted = results
|
|
161
|
+
.map((r) => {
|
|
162
|
+
const chunkLabel = typeof r.chunk_index === "number" && typeof r.total_chunks === "number"
|
|
163
|
+
? `Chunk ${r.chunk_index + 1} of ${r.total_chunks}`
|
|
164
|
+
: "Chunk";
|
|
165
|
+
return [
|
|
166
|
+
chunkLabel,
|
|
167
|
+
` Content: ${r.content}`,
|
|
168
|
+
r.section ? ` Section: ${r.section}` : null,
|
|
169
|
+
"---",
|
|
170
|
+
]
|
|
171
|
+
.filter(Boolean)
|
|
172
|
+
.join("\n");
|
|
173
|
+
})
|
|
174
|
+
.join("\n");
|
|
175
|
+
return {
|
|
176
|
+
content: [
|
|
177
|
+
{
|
|
178
|
+
type: "text",
|
|
179
|
+
text: `Retrieved ${results.length} chunk(s) for "${args.sessionUrl}":\n\n${formatted}`,
|
|
180
|
+
},
|
|
181
|
+
],
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
catch (err) {
|
|
185
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
186
|
+
console.error("[get_session_chunks] error:", err);
|
|
187
|
+
return { content: [{ type: "text", text: `Error: ${msg}` }] };
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
return { querySessionsHandler, getSessionChunksHandler };
|
|
191
|
+
}
|
|
192
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../mcp/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { DocumentChunk } from "./types";
|
|
2
|
+
export declare function hashContent(content: string): string;
|
|
3
|
+
export interface ChunkOptions {
|
|
4
|
+
sessionId: string;
|
|
5
|
+
sessionTitle: string;
|
|
6
|
+
project: string;
|
|
7
|
+
/** Base URL for the message, e.g. "session://ses_xxx#msg_yyy" */
|
|
8
|
+
baseUrl: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Splits a markdown string into semantically meaningful, heading-aware chunks.
|
|
12
|
+
* Adapted from doc2vec's ContentProcessor.chunkMarkdown().
|
|
13
|
+
*
|
|
14
|
+
* @param markdown Full markdown text to chunk
|
|
15
|
+
* @param options Metadata to attach to each chunk
|
|
16
|
+
*/
|
|
17
|
+
export declare function chunkMarkdown(markdown: string, options: ChunkOptions): DocumentChunk[];
|
|
18
|
+
//# sourceMappingURL=chunker.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunker.d.ts","sourceRoot":"","sources":["../../src/chunker.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAa7C,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEnD;AAMD,MAAM,WAAW,YAAY;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;CACjB;AA8DD;;;;;;GAMG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,YAAY,GACpB,aAAa,EAAE,CA6EjB"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.hashContent = hashContent;
|
|
7
|
+
exports.chunkMarkdown = chunkMarkdown;
|
|
8
|
+
const crypto_1 = __importDefault(require("crypto"));
|
|
9
|
+
// ---------------------------------------------------------------------------
|
|
10
|
+
// Constants (matching doc2vec defaults)
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
const MAX_TOKENS = 1000;
|
|
13
|
+
const MIN_TOKENS = 150;
|
|
14
|
+
const OVERLAP_PERCENT = 0.1;
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Hashing
|
|
17
|
+
// ---------------------------------------------------------------------------
|
|
18
|
+
function hashContent(content) {
|
|
19
|
+
return crypto_1.default.createHash("sha256").update(content).digest("hex");
|
|
20
|
+
}
|
|
21
|
+
function countTokens(text) {
|
|
22
|
+
return text.trim().split(/\s+/).filter(Boolean).length;
|
|
23
|
+
}
|
|
24
|
+
function buildBreadcrumb(headingHierarchy) {
|
|
25
|
+
return headingHierarchy.filter(Boolean).join(" > ");
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Splits an oversized buffer into overlapping sub-chunks.
|
|
29
|
+
*/
|
|
30
|
+
function splitWithOverlap(lines) {
|
|
31
|
+
const words = lines.join("\n").split(/\s+/).filter(Boolean);
|
|
32
|
+
const overlapCount = Math.floor(MAX_TOKENS * OVERLAP_PERCENT);
|
|
33
|
+
const chunks = [];
|
|
34
|
+
let start = 0;
|
|
35
|
+
while (start < words.length) {
|
|
36
|
+
const end = Math.min(start + MAX_TOKENS, words.length);
|
|
37
|
+
chunks.push(words.slice(start, end));
|
|
38
|
+
if (end >= words.length)
|
|
39
|
+
break;
|
|
40
|
+
start = end - overlapCount;
|
|
41
|
+
}
|
|
42
|
+
return chunks;
|
|
43
|
+
}
|
|
44
|
+
function createChunk(content, headingHierarchy, chunkIndex, options) {
|
|
45
|
+
const breadcrumb = buildBreadcrumb(headingHierarchy);
|
|
46
|
+
const prefixedContent = breadcrumb
|
|
47
|
+
? `[Session: ${breadcrumb}]\n\n${content}`
|
|
48
|
+
: content;
|
|
49
|
+
const hash = hashContent(prefixedContent);
|
|
50
|
+
const chunkId = hashContent(`${options.baseUrl}::${chunkIndex}::${prefixedContent}`);
|
|
51
|
+
return {
|
|
52
|
+
content: prefixedContent,
|
|
53
|
+
metadata: {
|
|
54
|
+
session_id: options.sessionId,
|
|
55
|
+
session_title: options.sessionTitle,
|
|
56
|
+
project: options.project,
|
|
57
|
+
heading_hierarchy: headingHierarchy,
|
|
58
|
+
section: headingHierarchy[headingHierarchy.length - 1] ?? "",
|
|
59
|
+
chunk_id: chunkId,
|
|
60
|
+
url: options.baseUrl,
|
|
61
|
+
hash,
|
|
62
|
+
chunk_index: chunkIndex,
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
// Main chunker
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
/**
|
|
70
|
+
* Splits a markdown string into semantically meaningful, heading-aware chunks.
|
|
71
|
+
* Adapted from doc2vec's ContentProcessor.chunkMarkdown().
|
|
72
|
+
*
|
|
73
|
+
* @param markdown Full markdown text to chunk
|
|
74
|
+
* @param options Metadata to attach to each chunk
|
|
75
|
+
*/
|
|
76
|
+
function chunkMarkdown(markdown, options) {
|
|
77
|
+
const lines = markdown.split("\n");
|
|
78
|
+
const headingHierarchy = [];
|
|
79
|
+
let buffer = [];
|
|
80
|
+
const pendingChunks = [];
|
|
81
|
+
function flushBuffer(hierarchy) {
|
|
82
|
+
if (buffer.length === 0)
|
|
83
|
+
return;
|
|
84
|
+
const tokenCount = countTokens(buffer.join("\n"));
|
|
85
|
+
if (tokenCount > MAX_TOKENS) {
|
|
86
|
+
// Split with overlap
|
|
87
|
+
const subChunks = splitWithOverlap(buffer);
|
|
88
|
+
for (const wordBatch of subChunks) {
|
|
89
|
+
pendingChunks.push({
|
|
90
|
+
lines: [wordBatch.join(" ")],
|
|
91
|
+
hierarchy: [...hierarchy],
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
pendingChunks.push({ lines: [...buffer], hierarchy: [...hierarchy] });
|
|
97
|
+
}
|
|
98
|
+
buffer = [];
|
|
99
|
+
}
|
|
100
|
+
for (const line of lines) {
|
|
101
|
+
const headingMatch = line.match(/^(#{1,6})\s+(.*)/);
|
|
102
|
+
if (headingMatch) {
|
|
103
|
+
const level = headingMatch[1].length;
|
|
104
|
+
const title = headingMatch[2].trim();
|
|
105
|
+
// Flush before updating the heading stack
|
|
106
|
+
const tokenCount = countTokens(buffer.join("\n"));
|
|
107
|
+
if (tokenCount >= MIN_TOKENS) {
|
|
108
|
+
flushBuffer([...headingHierarchy]);
|
|
109
|
+
}
|
|
110
|
+
else if (buffer.length > 0) {
|
|
111
|
+
// Merge small buffer into next section
|
|
112
|
+
// keep it in buffer
|
|
113
|
+
}
|
|
114
|
+
// Update heading hierarchy
|
|
115
|
+
headingHierarchy[level - 1] = title;
|
|
116
|
+
// Clear deeper levels
|
|
117
|
+
headingHierarchy.splice(level);
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
buffer.push(line);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// Flush remaining
|
|
124
|
+
flushBuffer([...headingHierarchy]);
|
|
125
|
+
// Merge tiny trailing chunks into the previous one
|
|
126
|
+
const merged = [];
|
|
127
|
+
for (const chunk of pendingChunks) {
|
|
128
|
+
const tokens = countTokens(chunk.lines.join("\n"));
|
|
129
|
+
if (tokens < MIN_TOKENS && merged.length > 0) {
|
|
130
|
+
const prev = merged[merged.length - 1];
|
|
131
|
+
prev.lines = [...prev.lines, "", ...chunk.lines];
|
|
132
|
+
}
|
|
133
|
+
else {
|
|
134
|
+
merged.push(chunk);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
// Filter out empty/whitespace-only chunks before finalizing
|
|
138
|
+
const nonEmpty = merged.filter((m) => m.lines.join("\n").trim().length > 0);
|
|
139
|
+
// Build final DocumentChunks with correct total_chunks
|
|
140
|
+
const total = nonEmpty.length;
|
|
141
|
+
return nonEmpty.map((m, idx) => {
|
|
142
|
+
const partial = createChunk(m.lines.join("\n"), m.hierarchy, idx, options);
|
|
143
|
+
return {
|
|
144
|
+
...partial,
|
|
145
|
+
metadata: { ...partial.metadata, total_chunks: total },
|
|
146
|
+
};
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=chunker.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chunker.js","sourceRoot":"","sources":["../../src/chunker.ts"],"names":[],"mappings":";;;;;AAcA,kCAEC;AAiFD,sCAgFC;AAjLD,oDAA4B;AAG5B,8EAA8E;AAC9E,wCAAwC;AACxC,8EAA8E;AAC9E,MAAM,UAAU,GAAG,IAAI,CAAC;AACxB,MAAM,UAAU,GAAG,GAAG,CAAC;AACvB,MAAM,eAAe,GAAG,GAAG,CAAC;AAE5B,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E,SAAgB,WAAW,CAAC,OAAe;IACzC,OAAO,gBAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACnE,CAAC;AAcD,SAAS,WAAW,CAAC,IAAY;IAC/B,OAAO,IAAI,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC;AACzD,CAAC;AAED,SAAS,eAAe,CAAC,gBAA0B;IACjD,OAAO,gBAAgB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACtD,CAAC;AAED;;GAEG;AACH,SAAS,gBAAgB,CAAC,KAAe;IACvC,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC5D,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,UAAU,GAAG,eAAe,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAe,EAAE,CAAC;IAC9B,IAAI,KAAK,GAAG,CAAC,CAAC;IAEd,OAAO,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,GAAG,UAAU,EAAE,KAAK,CAAC,MAAM,CAAC,CAAC;QACvD,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC;QACrC,IAAI,GAAG,IAAI,KAAK,CAAC,MAAM;YAAE,MAAM;QAC/B,KAAK,GAAG,GAAG,GAAG,YAAY,CAAC;IAC7B,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,WAAW,CAClB,OAAe,EACf,gBAA0B,EAC1B,UAAkB,EAClB,OAAqB;IAErB,MAAM,UAAU,GAAG,eAAe,CAAC,gBAAgB,CAAC,CAAC;IACrD,MAAM,eAAe,GAAG,UAAU;QAChC,CAAC,CAAC,aAAa,UAAU,QAAQ,OAAO,EAAE;QAC1C,CAAC,CAAC,OAAO,CAAC;IACZ,MAAM,IAAI,GAAG,WAAW,CAAC,eAAe,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,WAAW,CAAC,GAAG,OAAO,CAAC,OAAO,KAAK,UAAU,KAAK,eAAe,EAAE,CAAC,CAAC;IAErF,OAAO;QACL,OAAO,EAAE,eAAe;QACxB,QAAQ,EAAE;YACR,UAAU,EAAE,OAAO,CAAC,SAAS;YAC7B,aAAa,EAAE,OAAO,CAAC,YAAY;YACnC,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,iBAAiB,EAAE,gBAAgB;YACnC,OAAO,EAAE,gBAAgB,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC,IAAI,EAAE;YAC5D,QAAQ,EAAE,OAAO;YACjB,GAAG,EAAE,OAAO,CAAC,OAAO;YACpB,IAAI;YACJ,WAAW,EAAE,UAAU;SACxB;KACF,CAAC;AACJ,CAAC;AAED,8EAA8E;AAC9E,eAAe;AACf,8EAA8E;AAE9E;;;;;;GAMG;AACH,SAAgB,aAAa,CAC3B,QAAgB,EAChB,OAAqB;IAErB,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,gBAAgB,GAAa,EAAE,CAAC;IACtC,IAAI,MAAM,GAAa,EAAE,CAAC;IAC1B,MAAM,aAAa,GAAoD,EAAE,CAAC;IAE1E,SAAS,WAAW,CAAC,SAAmB;QACtC,IAAI,MAAM,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO;QAChC,MAAM,UAAU,GAAG,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QAElD,IAAI,UAAU,GAAG,UAAU,EAAE,CAAC;YAC5B,qBAAqB;YACrB,MAAM,SAAS,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;YAC3C,KAAK,MAAM,SAAS,IAAI,SAAS,EAAE,CAAC;gBAClC,aAAa,CAAC,IAAI,CAAC;oBACjB,KAAK,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;oBAC5B,SAAS,EAAE,CAAC,GAAG,SAAS,CAAC;iBAC1B,CAAC,CAAC;YACL,CAAC;QACH,CAAC;aAAM,CAAC;YACN,aAAa,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,MAAM,CAAC,EAAE,SAAS,EAAE,CAAC,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC;QACxE,CAAC;QACD,MAAM,GAAG,EAAE,CAAC;IACd,CAAC;IAED,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,kBAAkB,CAAC,CAAC;QAEpD,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;YACrC,MAAM,KAAK,GAAG,YAAY,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YAErC,0CAA0C;YAC1C,MAAM,UAAU,GAAG,WAAW,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;YAClD,IAAI,UAAU,IAAI,UAAU,EAAE,CAAC;gBAC7B,WAAW,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC;YACrC,CAAC;iBAAM,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC7B,uCAAuC;gBACvC,oBAAoB;YACtB,CAAC;YAED,2BAA2B;YAC3B,gBAAgB,CAAC,KAAK,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;YACpC,sBAAsB;YACtB,gBAAgB,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IAED,kBAAkB;IAClB,WAAW,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC,CAAC;IAEnC,mDAAmD;IACnD,MAAM,MAAM,GAAoD,EAAE,CAAC;IACnE,KAAK,MAAM,KAAK,IAAI,aAAa,EAAE,CAAC;QAClC,MAAM,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;QACnD,IAAI,MAAM,GAAG,UAAU,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC7C,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;YACvC,IAAI,CAAC,KAAK,GAAG,CAAC,GAAG,IAAI,CAAC,KAAK,EAAE,EAAE,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC;QACnD,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAED,4DAA4D;IAC5D,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAE5E,uDAAuD;IACvD,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC;IAC9B,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE;QAC7B,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,SAAS,EAAE,GAAG,EAAE,OAAO,CAAC,CAAC;QAC3E,OAAO;YACL,GAAG,OAAO;YACV,QAAQ,EAAE,EAAE,GAAG,OAAO,CAAC,QAAQ,EAAE,YAAY,EAAE,KAAK,EAAE;SACvD,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* code-session-memory CLI
|
|
4
|
+
*
|
|
5
|
+
* Usage:
|
|
6
|
+
* npx code-session-memory install — install for OpenCode + Claude Code
|
|
7
|
+
* npx code-session-memory status — show installation status
|
|
8
|
+
* npx code-session-memory uninstall — remove all installed components
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../../src/cli.ts"],"names":[],"mappings":";AACA;;;;;;;GAOG"}
|