@hanhnd/agent-kit 1.0.33 → 1.0.35
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/dist/cli/commands/cli-digest-pending.test.js +19 -10
- package/dist/cli/commands/memory.js +44 -4
- package/dist/cli.js +307 -129
- package/dist/core/config/index.d.ts +3 -0
- package/dist/core/config/index.js +20 -0
- package/dist/core/handoffs/index.d.ts +8 -7
- package/dist/core/handoffs/index.js +12 -4
- package/dist/core/handoffs/index.test.d.ts +1 -0
- package/dist/core/handoffs/index.test.js +88 -0
- package/dist/entrypoints/server.js +1 -3
- package/dist/mcp/agent.d.ts +1 -1
- package/dist/mcp/agent.js +3 -3
- package/dist/mcp/core.d.ts +7 -0
- package/dist/mcp/core.js +39 -25
- package/dist/mcp/core.test.d.ts +1 -0
- package/dist/mcp/core.test.js +98 -0
- package/dist/mcp/memory.d.ts +2 -1
- package/dist/mcp/memory.js +45 -18
- package/dist/server.js +302 -178
- package/dist/services/digest/constants.d.ts +3 -3
- package/dist/services/digest/constants.js +3 -3
- package/dist/services/digest/digest-background.test.js +19 -8
- package/dist/services/digest/digest-init.test.js +13 -2
- package/dist/services/digest/digest-pending.test.js +13 -2
- package/dist/services/digest/digest-processor.test.js +66 -0
- package/dist/services/digest/files.js +3 -3
- package/dist/services/digest/model-registry.js +2 -2
- package/dist/services/digest/processor.js +43 -13
- package/dist/services/digest/providers/llama-local.js +17 -28
- package/dist/services/digest/types.d.ts +3 -1
- package/dist/services/digest/types.js +1 -1
- package/dist/services/memory/chunker.d.ts +5 -2
- package/dist/services/memory/chunker.js +3 -1
- package/dist/services/memory/chunker.test.js +21 -11
- package/dist/services/memory/constants.js +1 -1
- package/dist/services/memory/embedder.js +1 -1
- package/dist/services/memory/index.d.ts +1 -1
- package/dist/services/memory/indexer.d.ts +2 -1
- package/dist/services/memory/indexer.js +24 -8
- package/dist/services/memory/indexer.test.js +38 -2
- package/dist/services/memory/memory.test.js +172 -15
- package/dist/services/memory/store.d.ts +6 -1
- package/dist/services/memory/store.js +87 -47
- package/dist/services/memory/store.test.js +123 -3
- package/dist/services/memory/types.d.ts +9 -1
- package/dist/services/memory/types.js +2 -1
- package/dist/utils/paths.d.ts +2 -0
- package/dist/utils/paths.js +2 -1
- package/dist/utils/utils.d.ts +1 -0
- package/dist/utils/utils.js +3 -3
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -1,18 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { createRequire } from 'module'; const require = createRequire(import.meta.url);
|
|
3
2
|
var __create = Object.create;
|
|
4
3
|
var __defProp = Object.defineProperty;
|
|
5
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
6
|
var __getProtoOf = Object.getPrototypeOf;
|
|
8
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
-
var
|
|
10
|
-
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
11
|
-
}) : x)(function(x) {
|
|
12
|
-
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
13
|
-
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
14
|
-
});
|
|
15
|
-
var __commonJS = (cb, mod) => function __require2() {
|
|
8
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
16
9
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
17
10
|
};
|
|
18
11
|
var __copyProps = (to, from, except, desc) => {
|
|
@@ -14926,8 +14919,8 @@ import * as path9 from "node:path";
|
|
|
14926
14919
|
|
|
14927
14920
|
// src/services/digest/constants.ts
|
|
14928
14921
|
import * as path from "node:path";
|
|
14929
|
-
var DEFAULT_DIGEST_MODEL_ID = "
|
|
14930
|
-
var DEFAULT_DIGEST_MAX_INPUT_CHARS =
|
|
14922
|
+
var DEFAULT_DIGEST_MODEL_ID = "base" /* BASE */;
|
|
14923
|
+
var DEFAULT_DIGEST_MAX_INPUT_CHARS = 1e4;
|
|
14931
14924
|
var DEFAULT_DIGEST_TIMEOUT_MS = 12e4;
|
|
14932
14925
|
var DIGEST_TIMEOUT_GRACE_MS = 5e3;
|
|
14933
14926
|
var DIGEST_WORKER_FLAG = "__agent-kit-digest-worker";
|
|
@@ -14940,7 +14933,7 @@ var DIGEST_WORKER_DIR = path.join(WIKI_DIR, "digest");
|
|
|
14940
14933
|
var DIGEST_LOCKFILE_REL_PATH = path.join(DIGEST_WORKER_DIR, "digest-worker.lock");
|
|
14941
14934
|
var DIGEST_WORKER_STATUS_REL_PATH = path.join(DIGEST_WORKER_DIR, "digest-worker.status.json");
|
|
14942
14935
|
var DIGEST_WORKER_LOG_REL_PATH = path.join(DIGEST_WORKER_DIR, "digest-worker.log");
|
|
14943
|
-
var LLAMA_CONTEXT_SIZE =
|
|
14936
|
+
var LLAMA_CONTEXT_SIZE = 8192;
|
|
14944
14937
|
var LLAMA_MAX_GENERATED_TOKENS = 512;
|
|
14945
14938
|
var LLAMA_TEMPERATURE = 0.1;
|
|
14946
14939
|
|
|
@@ -15022,6 +15015,7 @@ function sha256Hex(content) {
|
|
|
15022
15015
|
|
|
15023
15016
|
// src/core/config/index.ts
|
|
15024
15017
|
import * as fs2 from "fs";
|
|
15018
|
+
import * as os from "os";
|
|
15025
15019
|
import * as path3 from "path";
|
|
15026
15020
|
|
|
15027
15021
|
// src/services/memory/constants.ts
|
|
@@ -15031,7 +15025,7 @@ var DEFAULT_MEMORY_CONFIG = {
|
|
|
15031
15025
|
topK: 5,
|
|
15032
15026
|
chunkSize: 1500,
|
|
15033
15027
|
overlapLines: 2,
|
|
15034
|
-
embeddingModel: "
|
|
15028
|
+
embeddingModel: "base" /* BASE */,
|
|
15035
15029
|
vectorDimension: 384
|
|
15036
15030
|
};
|
|
15037
15031
|
var LOCK_RETRY_MS = 50;
|
|
@@ -15048,21 +15042,23 @@ function resolveMemoryConfig(settings, workspaceRoot) {
|
|
|
15048
15042
|
wikiDir: typeof override.wikiDir === "string" && override.wikiDir.length > 0 ? override.wikiDir : path3.join(workspaceRoot, ".agent-kit", "wiki")
|
|
15049
15043
|
};
|
|
15050
15044
|
}
|
|
15051
|
-
function
|
|
15052
|
-
|
|
15053
|
-
|
|
15045
|
+
function getGlobalSettingsFile() {
|
|
15046
|
+
return path3.join(os.homedir(), ".agent-kit", "settings.json");
|
|
15047
|
+
}
|
|
15048
|
+
function loadGlobalSettings() {
|
|
15049
|
+
const file = getGlobalSettingsFile();
|
|
15050
|
+
if (fs2.existsSync(file)) {
|
|
15054
15051
|
try {
|
|
15055
|
-
return JSON.parse(fs2.readFileSync(
|
|
15052
|
+
return JSON.parse(fs2.readFileSync(file, "utf-8"));
|
|
15056
15053
|
} catch (error) {
|
|
15057
|
-
console.error(`[agent-kit] Warning: Failed to parse ${
|
|
15054
|
+
console.error(`[agent-kit] Warning: Failed to parse ${file}:`, error);
|
|
15058
15055
|
}
|
|
15059
15056
|
}
|
|
15060
15057
|
return {};
|
|
15061
15058
|
}
|
|
15062
|
-
function
|
|
15063
|
-
const
|
|
15064
|
-
|
|
15065
|
-
atomicWriteJsonFile(settingsPath, { ...current, ...patch });
|
|
15059
|
+
function writeGlobalSettings(patch) {
|
|
15060
|
+
const current = loadGlobalSettings();
|
|
15061
|
+
atomicWriteJsonFile(getGlobalSettingsFile(), { ...current, ...patch });
|
|
15066
15062
|
}
|
|
15067
15063
|
function resolveConversationDigestConfig(settings) {
|
|
15068
15064
|
const digest = settings.memory?.conversationDigest;
|
|
@@ -15104,9 +15100,9 @@ function writeProvisionalDigestFile(outDir, input, markdown) {
|
|
|
15104
15100
|
return markdownPath;
|
|
15105
15101
|
}
|
|
15106
15102
|
function writeConversationDigestSettings(workspaceRoot, digest) {
|
|
15107
|
-
const current =
|
|
15103
|
+
const current = loadGlobalSettings();
|
|
15108
15104
|
const memory = current.memory ?? {};
|
|
15109
|
-
|
|
15105
|
+
writeGlobalSettings({
|
|
15110
15106
|
memory: {
|
|
15111
15107
|
...memory,
|
|
15112
15108
|
enabled: memory.enabled ?? true,
|
|
@@ -15131,8 +15127,8 @@ var DIGEST_MODEL_REGISTRY = {
|
|
|
15131
15127
|
sourceUrl: "https://huggingface.co/bartowski/Qwen2.5-0.5B-Instruct-GGUF",
|
|
15132
15128
|
enabled: true
|
|
15133
15129
|
},
|
|
15134
|
-
["
|
|
15135
|
-
id: "
|
|
15130
|
+
["base" /* BASE */]: {
|
|
15131
|
+
id: "base" /* BASE */,
|
|
15136
15132
|
ggufUri: "hf:bartowski/Qwen2.5-1.5B-Instruct-GGUF/Qwen2.5-1.5B-Instruct-Q4_K_M.gguf",
|
|
15137
15133
|
approxSizeBytes: 1e9,
|
|
15138
15134
|
license: "Apache-2.0",
|
|
@@ -15186,10 +15182,11 @@ async function withTimeout(promise, timeoutMs, createError) {
|
|
|
15186
15182
|
}
|
|
15187
15183
|
|
|
15188
15184
|
// src/utils/paths.ts
|
|
15189
|
-
import * as
|
|
15185
|
+
import * as os2 from "os";
|
|
15190
15186
|
import * as path5 from "path";
|
|
15191
|
-
var AGENT_KIT_HOME = path5.join(
|
|
15187
|
+
var AGENT_KIT_HOME = path5.join(os2.homedir(), ".agent-kit");
|
|
15192
15188
|
var CREDENTIALS_FILE = path5.join(AGENT_KIT_HOME, "credentials");
|
|
15189
|
+
var GLOBAL_SETTINGS_FILE = path5.join(AGENT_KIT_HOME, "settings.json");
|
|
15193
15190
|
var MODEL_CACHE_DIR = path5.join(AGENT_KIT_HOME, "cache", "models");
|
|
15194
15191
|
var FASTEMBED_CACHE_DIR = path5.join(MODEL_CACHE_DIR, "fastembed");
|
|
15195
15192
|
|
|
@@ -15217,39 +15214,19 @@ function buildPrompt(input, maxInputChars) {
|
|
|
15217
15214
|
{
|
|
15218
15215
|
role: "system",
|
|
15219
15216
|
content: [
|
|
15220
|
-
"
|
|
15221
|
-
"
|
|
15222
|
-
"
|
|
15223
|
-
""
|
|
15224
|
-
"# RULES",
|
|
15225
|
-
"1. Read the end of the export FIRST to discover the ultimate resolution.",
|
|
15226
|
-
"2. What the user says LAST ALWAYS overrides earlier agreements.",
|
|
15227
|
-
"3. Capture absolute engineering conclusions, never conversational pleasantries.",
|
|
15228
|
-
"4. Return Markdown only. Do not wrap output in code blocks (```markdown ... ```)."
|
|
15217
|
+
"You are a technical summarizer.",
|
|
15218
|
+
"Focus ONLY on the final decisions made at the end of the transcript.",
|
|
15219
|
+
"Never invent or guess details.",
|
|
15220
|
+
"Keep the output concise and strictly factual."
|
|
15229
15221
|
].join("\n")
|
|
15230
15222
|
},
|
|
15231
15223
|
{
|
|
15232
15224
|
role: "user",
|
|
15233
15225
|
content: [
|
|
15234
|
-
"
|
|
15235
|
-
"",
|
|
15236
|
-
"<layout>",
|
|
15237
|
-
"# Digest: " + titleFromSource(input.sourcePath),
|
|
15238
|
-
"- **Ultimate Core Resolution**: [Describe the final working state of the feature and what problem it solves in 1-2 sentences. No conversational filler.]",
|
|
15239
|
-
"- **Architectural Changes**: [List 3-4 high-level engineering decisions made (e.g., shifts in hook timing, data isolation, atomic locks). Focus on systemic changes, NOT individual files.]",
|
|
15240
|
-
"- **Component State**: [Briefly state how the Plugin side and the MCP/CLI side now interact based on the final decision.]",
|
|
15241
|
-
"- **Considered & Rejected**: [List concepts proposed but discarded (e.g., initial hooks location, mocking strategies). Omit if empty.]",
|
|
15242
|
-
"</layout>",
|
|
15243
|
-
"",
|
|
15244
|
-
"# CRITICAL RULES:",
|
|
15245
|
-
"- DO NOT list individual file paths, line numbers, or specific test cases (EXCLUDE lists of files).",
|
|
15246
|
-
"- Focus entirely on the SYSTEM DESIGN and ARCHITECTURE that the next engineer needs to know.",
|
|
15247
|
-
"- Keep output under 300 tokens. Stop immediately after the last valid section.",
|
|
15248
|
-
"",
|
|
15249
|
-
"Source path: " + input.sourcePath,
|
|
15250
|
-
'<conversation_export format="memory-kit">',
|
|
15226
|
+
"Transcript:",
|
|
15251
15227
|
conversationExport,
|
|
15252
|
-
"
|
|
15228
|
+
"",
|
|
15229
|
+
"Task: Write a brief summary paragraph of the final agreed-upon decisions in the transcript above. Then, provide a simple bulleted list of the specific technical changes or outcomes."
|
|
15253
15230
|
].join("\n")
|
|
15254
15231
|
}
|
|
15255
15232
|
];
|
|
@@ -15312,7 +15289,18 @@ async function createLlamaLocalDigestProvider(modelId) {
|
|
|
15312
15289
|
options.timeoutMs,
|
|
15313
15290
|
() => new LlamaLocalDigestProviderError(`Llama provider timed out after ${options.timeoutMs}ms`)
|
|
15314
15291
|
);
|
|
15315
|
-
|
|
15292
|
+
const metadata = `## Digest: ${titleFromSource(input.sourcePath)}
|
|
15293
|
+
|
|
15294
|
+
| Key | Value |
|
|
15295
|
+
| ------ | ----- |
|
|
15296
|
+
| **Source** | ${input.sourcePath} |
|
|
15297
|
+
| **Generated** | ${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]} |
|
|
15298
|
+
| **Model** | ${modelId} |
|
|
15299
|
+
`;
|
|
15300
|
+
const sanitized = sanitizeConversationDigestMarkdown(response);
|
|
15301
|
+
return `${metadata}
|
|
15302
|
+
|
|
15303
|
+
${sanitized}`;
|
|
15316
15304
|
} finally {
|
|
15317
15305
|
await context.dispose();
|
|
15318
15306
|
}
|
|
@@ -15324,7 +15312,10 @@ async function createLlamaLocalDigestProvider(modelId) {
|
|
|
15324
15312
|
var import_stopword = __toESM(require_stopword_cjs(), 1);
|
|
15325
15313
|
import Database from "better-sqlite3";
|
|
15326
15314
|
import * as fs5 from "fs";
|
|
15315
|
+
import { createRequire } from "module";
|
|
15327
15316
|
import * as path7 from "path";
|
|
15317
|
+
var require2 = createRequire(import.meta.url);
|
|
15318
|
+
var SCHEMA_VERSION = 2;
|
|
15328
15319
|
var StoreError = class extends Error {
|
|
15329
15320
|
constructor(message, cause) {
|
|
15330
15321
|
super(message);
|
|
@@ -15364,7 +15355,7 @@ var MemoryStore = class {
|
|
|
15364
15355
|
}
|
|
15365
15356
|
loadVecExtension(db) {
|
|
15366
15357
|
try {
|
|
15367
|
-
const sqliteVec =
|
|
15358
|
+
const sqliteVec = require2("sqlite-vec");
|
|
15368
15359
|
sqliteVec.load(db);
|
|
15369
15360
|
this._vecAvailable = true;
|
|
15370
15361
|
} catch (err) {
|
|
@@ -15373,57 +15364,77 @@ var MemoryStore = class {
|
|
|
15373
15364
|
}
|
|
15374
15365
|
}
|
|
15375
15366
|
createSchema(db) {
|
|
15376
|
-
|
|
15377
|
-
|
|
15378
|
-
|
|
15379
|
-
|
|
15380
|
-
|
|
15381
|
-
|
|
15382
|
-
|
|
15383
|
-
|
|
15384
|
-
|
|
15385
|
-
|
|
15386
|
-
|
|
15387
|
-
|
|
15367
|
+
try {
|
|
15368
|
+
const current = Number(db.pragma("user_version", { simple: true }) ?? 0);
|
|
15369
|
+
if (current < SCHEMA_VERSION) {
|
|
15370
|
+
db.exec(`
|
|
15371
|
+
DROP TRIGGER IF EXISTS memory_chunks_ai;
|
|
15372
|
+
DROP TRIGGER IF EXISTS memory_chunks_ad;
|
|
15373
|
+
DROP TABLE IF EXISTS memory_fts;
|
|
15374
|
+
DROP TABLE IF EXISTS memory_vec;
|
|
15375
|
+
DROP TABLE IF EXISTS memory_chunks;
|
|
15376
|
+
`);
|
|
15377
|
+
db.pragma(`user_version = ${SCHEMA_VERSION}`);
|
|
15378
|
+
}
|
|
15379
|
+
db.exec(`
|
|
15380
|
+
CREATE TABLE IF NOT EXISTS memory_chunks (
|
|
15381
|
+
rowid INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
15382
|
+
id TEXT NOT NULL UNIQUE,
|
|
15383
|
+
source TEXT NOT NULL,
|
|
15384
|
+
source_type TEXT NOT NULL DEFAULT 'wiki',
|
|
15385
|
+
heading TEXT NOT NULL DEFAULT '',
|
|
15386
|
+
heading_level INTEGER NOT NULL DEFAULT 0,
|
|
15387
|
+
content TEXT NOT NULL,
|
|
15388
|
+
line_start INTEGER NOT NULL,
|
|
15389
|
+
line_end INTEGER NOT NULL,
|
|
15390
|
+
indexed_at INTEGER NOT NULL,
|
|
15391
|
+
file_mtime_at INTEGER NOT NULL DEFAULT 0
|
|
15392
|
+
);
|
|
15388
15393
|
|
|
15389
|
-
|
|
15390
|
-
|
|
15391
|
-
heading,
|
|
15392
|
-
content,
|
|
15393
|
-
content='memory_chunks',
|
|
15394
|
-
content_rowid='rowid'
|
|
15395
|
-
);
|
|
15394
|
+
CREATE INDEX IF NOT EXISTS idx_memory_chunks_type_mtime
|
|
15395
|
+
ON memory_chunks (source_type, file_mtime_at DESC);
|
|
15396
15396
|
|
|
15397
|
-
|
|
15398
|
-
|
|
15399
|
-
|
|
15400
|
-
|
|
15401
|
-
|
|
15397
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS memory_fts USING fts5(
|
|
15398
|
+
source,
|
|
15399
|
+
heading,
|
|
15400
|
+
content,
|
|
15401
|
+
content='memory_chunks',
|
|
15402
|
+
content_rowid='rowid'
|
|
15403
|
+
);
|
|
15402
15404
|
|
|
15403
|
-
|
|
15404
|
-
|
|
15405
|
-
|
|
15406
|
-
|
|
15407
|
-
|
|
15408
|
-
|
|
15409
|
-
|
|
15410
|
-
|
|
15411
|
-
|
|
15412
|
-
|
|
15413
|
-
|
|
15414
|
-
|
|
15415
|
-
|
|
15416
|
-
|
|
15417
|
-
|
|
15418
|
-
|
|
15405
|
+
CREATE TRIGGER IF NOT EXISTS memory_chunks_ai
|
|
15406
|
+
AFTER INSERT ON memory_chunks BEGIN
|
|
15407
|
+
INSERT INTO memory_fts(rowid, source, heading, content)
|
|
15408
|
+
VALUES (new.rowid, new.source, new.heading, new.content);
|
|
15409
|
+
END;
|
|
15410
|
+
|
|
15411
|
+
CREATE TRIGGER IF NOT EXISTS memory_chunks_ad
|
|
15412
|
+
AFTER DELETE ON memory_chunks BEGIN
|
|
15413
|
+
INSERT INTO memory_fts(memory_fts, rowid, source, heading, content)
|
|
15414
|
+
VALUES ('delete', old.rowid, old.source, old.heading, old.content);
|
|
15415
|
+
END;
|
|
15416
|
+
`);
|
|
15417
|
+
if (this._vecAvailable) {
|
|
15418
|
+
try {
|
|
15419
|
+
db.exec(`
|
|
15420
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS memory_vec USING vec0(
|
|
15421
|
+
embedding FLOAT[${this.config.vectorDimension}]
|
|
15422
|
+
);
|
|
15423
|
+
`);
|
|
15424
|
+
} catch (err) {
|
|
15425
|
+
console.warn("[memory-store] Failed to create memory_vec, disabling vector search:", err);
|
|
15426
|
+
this._vecAvailable = false;
|
|
15427
|
+
}
|
|
15419
15428
|
}
|
|
15429
|
+
} catch (err) {
|
|
15430
|
+
throw new StoreError("schema migration failed", err);
|
|
15420
15431
|
}
|
|
15421
15432
|
}
|
|
15422
15433
|
upsert(chunks, embeddings) {
|
|
15423
15434
|
const insertChunk = this.db.prepare(`
|
|
15424
15435
|
INSERT OR REPLACE INTO memory_chunks
|
|
15425
|
-
(id, source, heading, heading_level, content, line_start, line_end, indexed_at)
|
|
15426
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
|
15436
|
+
(id, source, source_type, heading, heading_level, content, line_start, line_end, indexed_at, file_mtime_at)
|
|
15437
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
15427
15438
|
`);
|
|
15428
15439
|
let insertVec = null;
|
|
15429
15440
|
if (this._vecAvailable) {
|
|
@@ -15437,15 +15448,17 @@ var MemoryStore = class {
|
|
|
15437
15448
|
const info = insertChunk.run(
|
|
15438
15449
|
chunk.id,
|
|
15439
15450
|
chunk.source,
|
|
15451
|
+
chunk.sourceType,
|
|
15440
15452
|
chunk.heading,
|
|
15441
15453
|
chunk.headingLevel,
|
|
15442
15454
|
chunk.content,
|
|
15443
15455
|
chunk.lineStart,
|
|
15444
15456
|
chunk.lineEnd,
|
|
15445
|
-
Date.now()
|
|
15457
|
+
Date.now(),
|
|
15458
|
+
chunk.fileMtimeAt
|
|
15446
15459
|
);
|
|
15447
15460
|
if (insertVec && embeddings[i] && info.lastInsertRowid) {
|
|
15448
|
-
const rowid =
|
|
15461
|
+
const rowid = typeof info.lastInsertRowid === "bigint" ? info.lastInsertRowid : BigInt(info.lastInsertRowid);
|
|
15449
15462
|
const emb = embeddings[i];
|
|
15450
15463
|
const buf = Buffer.from(emb.buffer, emb.byteOffset, emb.byteLength);
|
|
15451
15464
|
insertVec.run(rowid, buf);
|
|
@@ -15469,6 +15482,20 @@ var MemoryStore = class {
|
|
|
15469
15482
|
const rows = this.db.prepare(`SELECT DISTINCT source FROM memory_chunks`).all();
|
|
15470
15483
|
return rows.map((r) => r.source);
|
|
15471
15484
|
}
|
|
15485
|
+
getRecentSources(options) {
|
|
15486
|
+
const limit = Math.min(Math.max(1, options.limit || 5), 50);
|
|
15487
|
+
const whereClause = options.sourceType ? " WHERE source_type = ?" : "";
|
|
15488
|
+
const params = options.sourceType ? [options.sourceType, limit] : [limit];
|
|
15489
|
+
try {
|
|
15490
|
+
const rows = this.db.prepare(
|
|
15491
|
+
`SELECT source, MAX(file_mtime_at) AS t FROM memory_chunks${whereClause} GROUP BY source ORDER BY t DESC LIMIT ?`
|
|
15492
|
+
).all(...params);
|
|
15493
|
+
return rows.map((row) => ({ source: row.source, fileMtimeAt: row.t }));
|
|
15494
|
+
} catch (err) {
|
|
15495
|
+
console.warn("[memory-store] Recent source lookup failed:", err);
|
|
15496
|
+
return [];
|
|
15497
|
+
}
|
|
15498
|
+
}
|
|
15472
15499
|
deleteBySource(source) {
|
|
15473
15500
|
const rows = this.db.prepare(`SELECT rowid FROM memory_chunks WHERE source = ?`).all(source);
|
|
15474
15501
|
const deleteAll = this.db.transaction(() => {
|
|
@@ -15545,17 +15572,19 @@ var MemoryStore = class {
|
|
|
15545
15572
|
if (ids.length === 0) return [];
|
|
15546
15573
|
const placeholders = ids.map(() => "?").join(", ");
|
|
15547
15574
|
const rows = this.db.prepare(
|
|
15548
|
-
`SELECT id, source, heading, heading_level, content, line_start, line_end
|
|
15575
|
+
`SELECT id, source, source_type, heading, heading_level, content, line_start, line_end, file_mtime_at
|
|
15549
15576
|
FROM memory_chunks WHERE id IN (${placeholders})`
|
|
15550
15577
|
).all(...ids);
|
|
15551
15578
|
return rows.map((r) => ({
|
|
15552
15579
|
id: r.id,
|
|
15553
15580
|
source: r.source,
|
|
15581
|
+
sourceType: r.source_type,
|
|
15554
15582
|
heading: r.heading,
|
|
15555
15583
|
headingLevel: r.heading_level,
|
|
15556
15584
|
content: r.content,
|
|
15557
15585
|
lineStart: r.line_start,
|
|
15558
|
-
lineEnd: r.line_end
|
|
15586
|
+
lineEnd: r.line_end,
|
|
15587
|
+
fileMtimeAt: r.file_mtime_at
|
|
15559
15588
|
}));
|
|
15560
15589
|
}
|
|
15561
15590
|
get vecAvailable() {
|
|
@@ -15648,7 +15677,7 @@ function splitSection(text, maxLen) {
|
|
|
15648
15677
|
if (byPara.every((p) => p.length <= maxLen)) return byPara;
|
|
15649
15678
|
return byPara.flatMap((p) => p.length <= maxLen ? [p] : splitAtLine(p, maxLen));
|
|
15650
15679
|
}
|
|
15651
|
-
function chunkMarkdown(text, source, config) {
|
|
15680
|
+
function chunkMarkdown(text, source, config, meta) {
|
|
15652
15681
|
if (!text || !text.trim()) return [];
|
|
15653
15682
|
const { chunkSize, overlapLines } = config;
|
|
15654
15683
|
const lines = text.split("\n");
|
|
@@ -15687,11 +15716,13 @@ ${sectionText}` : sectionText;
|
|
|
15687
15716
|
chunks.push({
|
|
15688
15717
|
id: computeChunkId(content),
|
|
15689
15718
|
source,
|
|
15719
|
+
sourceType: meta.sourceType,
|
|
15690
15720
|
heading: section.heading,
|
|
15691
15721
|
headingLevel: section.headingLevel,
|
|
15692
15722
|
content,
|
|
15693
15723
|
lineStart: firstLine,
|
|
15694
|
-
lineEnd: lastLine
|
|
15724
|
+
lineEnd: lastLine,
|
|
15725
|
+
fileMtimeAt: meta.fileMtimeAt
|
|
15695
15726
|
});
|
|
15696
15727
|
if (pi === parts.length - 1) {
|
|
15697
15728
|
prevOverlapLines = partLines.slice(-overlapLines);
|
|
@@ -15702,6 +15733,13 @@ ${sectionText}` : sectionText;
|
|
|
15702
15733
|
}
|
|
15703
15734
|
|
|
15704
15735
|
// src/services/memory/indexer.ts
|
|
15736
|
+
function deriveSourceType(source) {
|
|
15737
|
+
if (source.startsWith("compiled/provisional/conversation-digests/")) return "digest";
|
|
15738
|
+
if (source.startsWith("compiled/concepts/")) return "concept";
|
|
15739
|
+
if (source.startsWith("compiled/entities/")) return "entity";
|
|
15740
|
+
if (source === "compiled/preferences.md") return "preference";
|
|
15741
|
+
return "wiki";
|
|
15742
|
+
}
|
|
15705
15743
|
var MemoryIndexer = class {
|
|
15706
15744
|
constructor(store, embedder, config) {
|
|
15707
15745
|
this.store = store;
|
|
@@ -15722,7 +15760,15 @@ var MemoryIndexer = class {
|
|
|
15722
15760
|
console.warn(`[memory-indexer] Cannot read file ${absolutePath}:`, err);
|
|
15723
15761
|
return { indexed: 0, deleted: 0, skipped: existingChunkIds.size };
|
|
15724
15762
|
}
|
|
15725
|
-
|
|
15763
|
+
let fileMtimeAt;
|
|
15764
|
+
try {
|
|
15765
|
+
fileMtimeAt = fs6.statSync(absolutePath).mtimeMs;
|
|
15766
|
+
} catch (err) {
|
|
15767
|
+
console.warn(`[memory-indexer] Cannot stat file ${absolutePath}:`, err);
|
|
15768
|
+
fileMtimeAt = Date.now();
|
|
15769
|
+
}
|
|
15770
|
+
const sourceType = deriveSourceType(source);
|
|
15771
|
+
const allChunks = chunkMarkdown(text, source, this.config, { sourceType, fileMtimeAt });
|
|
15726
15772
|
const currentChunkIds = new Set(allChunks.map((chunk) => chunk.id));
|
|
15727
15773
|
const toIndex = allChunks.filter((chunk) => !existingChunkIds.has(chunk.id));
|
|
15728
15774
|
const toDelete = [...existingChunkIds].filter((id) => !currentChunkIds.has(id));
|
|
@@ -15809,12 +15855,9 @@ var MemoryIndexer = class {
|
|
|
15809
15855
|
scoreMap.set(r.id, { dense: 1 / (RRF_K + rank + 1), bm25: 0 });
|
|
15810
15856
|
});
|
|
15811
15857
|
bm25Results.forEach((r, rank) => {
|
|
15812
|
-
const
|
|
15813
|
-
|
|
15814
|
-
|
|
15815
|
-
} else {
|
|
15816
|
-
scoreMap.set(r.id, { dense: 0, bm25: 1 / (RRF_K + rank + 1) });
|
|
15817
|
-
}
|
|
15858
|
+
const entry = scoreMap.get(r.id) ?? { dense: 0, bm25: 0 };
|
|
15859
|
+
entry.bm25 = 1 / (RRF_K + rank + 1);
|
|
15860
|
+
scoreMap.set(r.id, entry);
|
|
15818
15861
|
});
|
|
15819
15862
|
const hasDense = this.store.vecAvailable && denseResults.length > 0;
|
|
15820
15863
|
const numRetrievers = hasDense ? 2 : 1;
|
|
@@ -15884,6 +15927,77 @@ ${content}
|
|
|
15884
15927
|
}
|
|
15885
15928
|
};
|
|
15886
15929
|
|
|
15930
|
+
// src/services/memory/embedder.ts
|
|
15931
|
+
var EmbedderError = class extends Error {
|
|
15932
|
+
constructor(message, cause) {
|
|
15933
|
+
super(message);
|
|
15934
|
+
this.name = "EmbedderError";
|
|
15935
|
+
if (cause instanceof Error) this.cause = cause;
|
|
15936
|
+
}
|
|
15937
|
+
};
|
|
15938
|
+
var Embedder = class {
|
|
15939
|
+
modelName;
|
|
15940
|
+
pipeline = null;
|
|
15941
|
+
_dimension;
|
|
15942
|
+
constructor(modelName) {
|
|
15943
|
+
this.modelName = modelName;
|
|
15944
|
+
}
|
|
15945
|
+
async embed(texts) {
|
|
15946
|
+
if (texts.length === 0) return [];
|
|
15947
|
+
if (!this.pipeline) {
|
|
15948
|
+
await this.loadModel();
|
|
15949
|
+
}
|
|
15950
|
+
try {
|
|
15951
|
+
const results = await this.pipeline(texts);
|
|
15952
|
+
return results.map((vec) => {
|
|
15953
|
+
const arr = new Float32Array(vec);
|
|
15954
|
+
if (!this._dimension) this._dimension = arr.length;
|
|
15955
|
+
return arr;
|
|
15956
|
+
});
|
|
15957
|
+
} catch (cause) {
|
|
15958
|
+
throw new EmbedderError(`Embedding failed for batch of ${texts.length} texts`, cause);
|
|
15959
|
+
}
|
|
15960
|
+
}
|
|
15961
|
+
get dimension() {
|
|
15962
|
+
return this._dimension;
|
|
15963
|
+
}
|
|
15964
|
+
isReady() {
|
|
15965
|
+
return this.pipeline !== null;
|
|
15966
|
+
}
|
|
15967
|
+
async initialize() {
|
|
15968
|
+
if (!this.pipeline) {
|
|
15969
|
+
await this.loadModel();
|
|
15970
|
+
}
|
|
15971
|
+
}
|
|
15972
|
+
async loadModel() {
|
|
15973
|
+
try {
|
|
15974
|
+
const { EmbeddingModel, FlagEmbedding } = await import("fastembed");
|
|
15975
|
+
const modelMap = {
|
|
15976
|
+
["tiny" /* TINY */]: EmbeddingModel.AllMiniLML6V2,
|
|
15977
|
+
["base" /* BASE */]: EmbeddingModel.BGESmallENV15,
|
|
15978
|
+
["large" /* LARGE */]: EmbeddingModel.BGEBaseENV15
|
|
15979
|
+
};
|
|
15980
|
+
const model = modelMap[this.modelName] ?? EmbeddingModel.BGESmallENV15;
|
|
15981
|
+
const embedder = await FlagEmbedding.init({
|
|
15982
|
+
model,
|
|
15983
|
+
cacheDir: FASTEMBED_CACHE_DIR,
|
|
15984
|
+
showDownloadProgress: false
|
|
15985
|
+
});
|
|
15986
|
+
this.pipeline = async (texts) => {
|
|
15987
|
+
const result = [];
|
|
15988
|
+
for await (const batch of embedder.embed(texts, texts.length)) {
|
|
15989
|
+
for (const vec of batch) {
|
|
15990
|
+
result.push(Array.from(vec));
|
|
15991
|
+
}
|
|
15992
|
+
}
|
|
15993
|
+
return result;
|
|
15994
|
+
};
|
|
15995
|
+
} catch (cause) {
|
|
15996
|
+
throw new EmbedderError(`Failed to load embedding model: ${this.modelName}`, cause);
|
|
15997
|
+
}
|
|
15998
|
+
}
|
|
15999
|
+
};
|
|
16000
|
+
|
|
15887
16001
|
// src/services/digest/processor.ts
|
|
15888
16002
|
function digestLockPath(workspaceRoot) {
|
|
15889
16003
|
return path9.join(workspaceRoot, DIGEST_LOCKFILE_REL_PATH);
|
|
@@ -15910,19 +16024,25 @@ function discoverPendingConversationFiles(workspaceRoot) {
|
|
|
15910
16024
|
}
|
|
15911
16025
|
});
|
|
15912
16026
|
}
|
|
15913
|
-
async function indexProvisionalDigestFile(workspaceRoot, markdownPath) {
|
|
16027
|
+
async function indexProvisionalDigestFile(workspaceRoot, markdownPath, indexer) {
|
|
16028
|
+
let store;
|
|
15914
16029
|
try {
|
|
15915
|
-
|
|
16030
|
+
if (indexer) {
|
|
16031
|
+
await indexer.indexFile(markdownPath);
|
|
16032
|
+
return { indexed: true };
|
|
16033
|
+
}
|
|
16034
|
+
const settings = loadGlobalSettings();
|
|
15916
16035
|
const config = resolveMemoryConfig(settings, workspaceRoot);
|
|
15917
|
-
|
|
15918
|
-
|
|
15919
|
-
|
|
15920
|
-
|
|
15921
|
-
await
|
|
16036
|
+
if (config.enabled !== true) return { indexed: false };
|
|
16037
|
+
store = new MemoryStore(path9.join(config.wikiDir, "index.db"), config);
|
|
16038
|
+
const embedder = new Embedder(config.embeddingModel);
|
|
16039
|
+
await embedder.initialize();
|
|
16040
|
+
await new MemoryIndexer(store, embedder, config).indexFile(markdownPath);
|
|
15922
16041
|
return { indexed: true };
|
|
15923
16042
|
} catch (err) {
|
|
15924
|
-
|
|
15925
|
-
|
|
16043
|
+
return { indexed: false, error: err instanceof Error ? err.message : String(err) };
|
|
16044
|
+
} finally {
|
|
16045
|
+
store?.close();
|
|
15926
16046
|
}
|
|
15927
16047
|
}
|
|
15928
16048
|
async function digestConversationFile(options) {
|
|
@@ -15930,7 +16050,7 @@ async function digestConversationFile(options) {
|
|
|
15930
16050
|
const input = readConversationDigestInput(options.workspaceRoot, options.inputPath);
|
|
15931
16051
|
const existingPath = findExistingProvisionalDigest(outDir, input);
|
|
15932
16052
|
if (existingPath) {
|
|
15933
|
-
const indexResult = await indexProvisionalDigestFile(options.workspaceRoot, existingPath);
|
|
16053
|
+
const indexResult = await indexProvisionalDigestFile(options.workspaceRoot, existingPath, options.indexer);
|
|
15934
16054
|
return {
|
|
15935
16055
|
markdown: existingPath,
|
|
15936
16056
|
status: "provisional",
|
|
@@ -15947,7 +16067,7 @@ async function digestConversationFile(options) {
|
|
|
15947
16067
|
timeoutMs: options.timeoutMs ?? DEFAULT_DIGEST_TIMEOUT_MS
|
|
15948
16068
|
});
|
|
15949
16069
|
const markdownPath = writeProvisionalDigestFile(outDir, input, markdown);
|
|
15950
|
-
const indexResult = await indexProvisionalDigestFile(options.workspaceRoot, markdownPath);
|
|
16070
|
+
const indexResult = await indexProvisionalDigestFile(options.workspaceRoot, markdownPath, options.indexer);
|
|
15951
16071
|
return {
|
|
15952
16072
|
markdown: markdownPath,
|
|
15953
16073
|
status: "provisional",
|
|
@@ -15960,7 +16080,7 @@ async function digestConversationFile(options) {
|
|
|
15960
16080
|
}
|
|
15961
16081
|
}
|
|
15962
16082
|
function summarizePendingConversations(workspaceRoot) {
|
|
15963
|
-
const digestConfig = resolveConversationDigestConfig(
|
|
16083
|
+
const digestConfig = resolveConversationDigestConfig(loadGlobalSettings());
|
|
15964
16084
|
if (!digestConfig || digestConfig.enabled === false) {
|
|
15965
16085
|
return { initialized: false, pending: 0, reason: "not-initialized" };
|
|
15966
16086
|
}
|
|
@@ -15975,7 +16095,7 @@ async function digestPendingConversations({
|
|
|
15975
16095
|
digestFn = digestConversationFile,
|
|
15976
16096
|
onProgress
|
|
15977
16097
|
}) {
|
|
15978
|
-
const digestConfig = resolveConversationDigestConfig(
|
|
16098
|
+
const digestConfig = resolveConversationDigestConfig(loadGlobalSettings());
|
|
15979
16099
|
if (!digestConfig || digestConfig.enabled === false) {
|
|
15980
16100
|
return { ok: true, initialized: false, action: "noop", reason: "not-initialized" };
|
|
15981
16101
|
}
|
|
@@ -15983,11 +16103,21 @@ async function digestPendingConversations({
|
|
|
15983
16103
|
if (!tryAcquireProcessLock(lockPath)) {
|
|
15984
16104
|
return { ok: true, initialized: true, action: "noop", reason: "locked" };
|
|
15985
16105
|
}
|
|
16106
|
+
let closeIndexer;
|
|
15986
16107
|
try {
|
|
15987
16108
|
const candidates = discoverPendingConversationFiles(workspaceRoot);
|
|
15988
16109
|
if (candidates.length === 0) {
|
|
15989
16110
|
return { ok: true, initialized: true, action: "noop", reason: "no-pending" };
|
|
15990
16111
|
}
|
|
16112
|
+
let indexer;
|
|
16113
|
+
const memoryConfig = resolveMemoryConfig(loadGlobalSettings(), workspaceRoot);
|
|
16114
|
+
if (memoryConfig.enabled === true) {
|
|
16115
|
+
const store = new MemoryStore(path9.join(memoryConfig.wikiDir, "index.db"), memoryConfig);
|
|
16116
|
+
const embedder = new Embedder(memoryConfig.embeddingModel);
|
|
16117
|
+
indexer = new MemoryIndexer(store, embedder, memoryConfig);
|
|
16118
|
+
closeIndexer = () => store.close();
|
|
16119
|
+
await embedder.initialize();
|
|
16120
|
+
}
|
|
15991
16121
|
let count = 0;
|
|
15992
16122
|
let skipped = 0;
|
|
15993
16123
|
let errors = 0;
|
|
@@ -15996,7 +16126,8 @@ async function digestPendingConversations({
|
|
|
15996
16126
|
const result = await digestFn({
|
|
15997
16127
|
workspaceRoot,
|
|
15998
16128
|
inputPath: filePath,
|
|
15999
|
-
modelId: digestConfig.modelId
|
|
16129
|
+
modelId: digestConfig.modelId,
|
|
16130
|
+
indexer
|
|
16000
16131
|
});
|
|
16001
16132
|
if (result.skipped) {
|
|
16002
16133
|
skipped++;
|
|
@@ -16013,9 +16144,17 @@ async function digestPendingConversations({
|
|
|
16013
16144
|
return { ok: true, initialized: true, action: "digested", count, skipped, errors };
|
|
16014
16145
|
} catch (err) {
|
|
16015
16146
|
const message = err instanceof Error ? err.message : String(err);
|
|
16147
|
+
console.warn("[digest] Pending conversation digest failed:", err);
|
|
16016
16148
|
return { ok: false, initialized: true, action: "error", error: message };
|
|
16017
16149
|
} finally {
|
|
16018
16150
|
releaseLock(lockPath);
|
|
16151
|
+
if (closeIndexer) {
|
|
16152
|
+
try {
|
|
16153
|
+
closeIndexer();
|
|
16154
|
+
} catch (err) {
|
|
16155
|
+
console.warn("[digest] Failed to close memory indexer store:", err);
|
|
16156
|
+
}
|
|
16157
|
+
}
|
|
16019
16158
|
}
|
|
16020
16159
|
}
|
|
16021
16160
|
async function initializeConversationDigestModel(input) {
|
|
@@ -16385,7 +16524,7 @@ function runDigestFileInWorker(args) {
|
|
|
16385
16524
|
|
|
16386
16525
|
// src/utils/utils.ts
|
|
16387
16526
|
function getWorkspaceRoot() {
|
|
16388
|
-
return process.env.WORKSPACE_DIR || process.env.CLAUDE_PROJECT_DIR || process.env.CODEX_PROJECT_DIR || process.env.GEMINI_PROJECT_DIR || process.env.
|
|
16527
|
+
return process.env.WORKSPACE_DIR || process.env.CLAUDE_PROJECT_DIR || process.env.CODEX_PROJECT_DIR || process.env.GEMINI_PROJECT_DIR || process.env.INIT_CWD || process.env.PWD || process.cwd();
|
|
16389
16528
|
}
|
|
16390
16529
|
|
|
16391
16530
|
// src/cli/commands/memory.ts
|
|
@@ -16396,6 +16535,37 @@ function writeDigestFileResult(result, workerMode) {
|
|
|
16396
16535
|
}
|
|
16397
16536
|
process.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
16398
16537
|
}
|
|
16538
|
+
function formatLauncherResult(result) {
|
|
16539
|
+
if (!result.ok) return `Digest failed: ${result.error ?? "unknown error"}`;
|
|
16540
|
+
if (result.spawned) return "Background digest started";
|
|
16541
|
+
switch (result.status.state) {
|
|
16542
|
+
case "locked":
|
|
16543
|
+
return "Digest already running";
|
|
16544
|
+
case "no-pending":
|
|
16545
|
+
return "No conversations to digest";
|
|
16546
|
+
case "not-initialized":
|
|
16547
|
+
return "Digest not initialized";
|
|
16548
|
+
default:
|
|
16549
|
+
return `Digest skipped (${result.status.state})`;
|
|
16550
|
+
}
|
|
16551
|
+
}
|
|
16552
|
+
function formatPendingResult(result) {
|
|
16553
|
+
if (!result.ok) return `Digest failed: ${result.error ?? "unknown error"}`;
|
|
16554
|
+
if (result.action === "noop") {
|
|
16555
|
+
switch (result.reason) {
|
|
16556
|
+
case "locked":
|
|
16557
|
+
return "Digest already running";
|
|
16558
|
+
case "no-pending":
|
|
16559
|
+
return "No conversations to digest";
|
|
16560
|
+
case "not-initialized":
|
|
16561
|
+
return "Digest not initialized";
|
|
16562
|
+
}
|
|
16563
|
+
}
|
|
16564
|
+
const parts = [`${result.count} conversation${result.count !== 1 ? "s" : ""} digested`];
|
|
16565
|
+
if (result.skipped > 0) parts.push(`${result.skipped} skipped`);
|
|
16566
|
+
if (result.errors > 0) parts.push(`${result.errors} errors`);
|
|
16567
|
+
return parts.join(", ");
|
|
16568
|
+
}
|
|
16399
16569
|
async function cmdDigestInit(args) {
|
|
16400
16570
|
const parsed = parseArgs(args);
|
|
16401
16571
|
const modelId = stringFlag(parsed.flags, "model") ?? DEFAULT_DIGEST_MODEL_ID;
|
|
@@ -16413,7 +16583,7 @@ async function cmdDigestFile(args) {
|
|
|
16413
16583
|
if (workerResult !== void 0) return workerResult;
|
|
16414
16584
|
const parsed = parseArgs(args);
|
|
16415
16585
|
const workspaceRoot = getWorkspaceRoot();
|
|
16416
|
-
const digestConfig = resolveConversationDigestConfig(
|
|
16586
|
+
const digestConfig = resolveConversationDigestConfig(loadGlobalSettings());
|
|
16417
16587
|
const modelId = stringFlag(parsed.flags, "model") ?? digestConfig?.modelId ?? DEFAULT_DIGEST_MODEL_ID;
|
|
16418
16588
|
const inputPath = stringFlag(parsed.flags, "input");
|
|
16419
16589
|
if (!inputPath) {
|
|
@@ -16446,11 +16616,19 @@ async function cmdDigestPending(args) {
|
|
|
16446
16616
|
args,
|
|
16447
16617
|
entrypoint: process.argv[1]
|
|
16448
16618
|
});
|
|
16449
|
-
process.stdout.write(
|
|
16619
|
+
process.stdout.write(
|
|
16620
|
+
JSON.stringify({
|
|
16621
|
+
systemMessage: `[memory-kit] ${formatLauncherResult(result2)}`
|
|
16622
|
+
}) + "\n"
|
|
16623
|
+
);
|
|
16450
16624
|
return 0;
|
|
16451
16625
|
}
|
|
16452
16626
|
const result = await digestPendingConversations({ workspaceRoot });
|
|
16453
|
-
process.stdout.write(
|
|
16627
|
+
process.stdout.write(
|
|
16628
|
+
JSON.stringify({
|
|
16629
|
+
systemMessage: `[memory-kit] ${formatPendingResult(result)}`
|
|
16630
|
+
}) + "\n"
|
|
16631
|
+
);
|
|
16454
16632
|
return 0;
|
|
16455
16633
|
}
|
|
16456
16634
|
async function runMemoryCli(args, _env) {
|