@remnic/plugin-pi 1.0.0 → 1.0.1
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 +2 -2
- package/dist/index.js +9 -1
- package/dist/index.js.map +1 -1
- package/dist/publisher.js +1 -1
- package/dist/publisher.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -81,7 +81,7 @@ Supported config keys:
|
|
|
81
81
|
| `compactionEnabled` | `true` | Enable LCM flush and checkpoint coordination |
|
|
82
82
|
| `mcpToolsEnabled` | `true` | Register Remnic MCP tools as Pi tools |
|
|
83
83
|
| `statusEnabled` | `true` | Set Pi UI status from daemon health |
|
|
84
|
-
| `requestTimeoutMs` | `
|
|
84
|
+
| `requestTimeoutMs` | `60000` | HTTP/MCP request timeout |
|
|
85
85
|
|
|
86
86
|
Boolean-like strings such as `"false"`, `"0"`, `"no"`, and `"off"` are treated as false.
|
|
87
87
|
|
|
@@ -99,7 +99,7 @@ Example:
|
|
|
99
99
|
"compactionEnabled": true,
|
|
100
100
|
"mcpToolsEnabled": true,
|
|
101
101
|
"statusEnabled": true,
|
|
102
|
-
"requestTimeoutMs":
|
|
102
|
+
"requestTimeoutMs": 60000
|
|
103
103
|
}
|
|
104
104
|
```
|
|
105
105
|
|
package/dist/index.js
CHANGED
|
@@ -22,7 +22,7 @@ var DEFAULT_CONFIG = {
|
|
|
22
22
|
compactionEnabled: true,
|
|
23
23
|
mcpToolsEnabled: true,
|
|
24
24
|
statusEnabled: true,
|
|
25
|
-
requestTimeoutMs:
|
|
25
|
+
requestTimeoutMs: 6e4
|
|
26
26
|
};
|
|
27
27
|
function defaultConfigPath(env) {
|
|
28
28
|
return path.join(resolvePiAgentHome(env), "extensions", REMNIC_PI_EXTENSION_DIR_NAME, "remnic.config.json");
|
|
@@ -248,6 +248,11 @@ var RemnicClient = class {
|
|
|
248
248
|
throw new RemnicHttpError(response.status, typeof payload?.error === "string" ? payload.error : response.statusText);
|
|
249
249
|
}
|
|
250
250
|
return payload;
|
|
251
|
+
} catch (err) {
|
|
252
|
+
if (isAbortError(err)) {
|
|
253
|
+
throw new Error(`Remnic request timed out after ${this.config.requestTimeoutMs}ms`);
|
|
254
|
+
}
|
|
255
|
+
throw err;
|
|
251
256
|
} finally {
|
|
252
257
|
clearTimeout(timeout);
|
|
253
258
|
}
|
|
@@ -269,6 +274,9 @@ var RemnicClient = class {
|
|
|
269
274
|
function isMcpTool(value) {
|
|
270
275
|
return !!value && typeof value === "object" && typeof value.name === "string";
|
|
271
276
|
}
|
|
277
|
+
function isAbortError(err) {
|
|
278
|
+
return err instanceof Error && (err.name === "AbortError" || err.message === "This operation was aborted");
|
|
279
|
+
}
|
|
272
280
|
|
|
273
281
|
// src/messages.ts
|
|
274
282
|
import { createHash } from "crypto";
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/config.ts","../src/client.ts","../src/messages.ts"],"sourcesContent":["import { Type, type TSchema } from \"@sinclair/typebox\";\n\nimport { loadConfig, type LoadConfigOptions, type RemnicPiConfig } from \"./config.js\";\nimport { RemnicClient, type McpTool, type ObserveMessage } from \"./client.js\";\nimport {\n hashObservedMessage,\n latestUserQuery,\n observedMessageDedupeKey,\n sessionKeyFromContext,\n summarizeMessages,\n textFromMessage,\n toObserveMessage,\n} from \"./messages.js\";\n\ntype PiApi = {\n on(event: string, handler: (event: any, ctx: any) => unknown | Promise<unknown>): void;\n registerCommand(name: string, options: { description?: string; handler: (args: string, ctx: any) => Promise<void> }): void;\n registerTool(tool: Record<string, unknown>): void;\n appendEntry<T = unknown>(customType: string, data?: T): void;\n};\n\nexport interface RemnicPiExtensionOptions extends LoadConfigOptions {\n config?: RemnicPiConfig;\n}\n\nconst STATE_CUSTOM_TYPE = \"remnic_state\";\nconst MAX_OBSERVED_HASHES = 2000;\nconst MAX_SESSION_STATES = 50;\nconst MAX_CONTEXT_CHARS = 12000;\nconst TRUNCATION_NOTICE = \"\\n\\n[Remnic context truncated]\";\n\ntype PiSessionState = {\n observedHashes: Set<string>;\n liveObservedReplayKeys: Map<string, number>;\n lastInjectedQuery: string;\n};\n\nexport function createRemnicPiExtension(options: RemnicPiExtensionOptions = {}) {\n const config = options.config ?? loadConfig(options);\n const client = new RemnicClient(config);\n const sessionStates = new Map<string, PiSessionState>();\n\n return async function remnicPiExtension(pi: PiApi): Promise<void> {\n pi.on(\"session_start\", async (_event, ctx) => {\n const { state } = getSessionState(ctx, sessionStates);\n restoreObservedState(ctx, state.observedHashes);\n if (!config.statusEnabled) return;\n await setStatus(ctx, client, config);\n });\n\n pi.on(\"context\", async (event, ctx) => {\n if (!config.recallEnabled || !config.authToken) return;\n const query = latestUserQuery(Array.isArray(event.messages) ? event.messages : []);\n if (!query) return;\n const sessionKey = sessionKeyFromContext(ctx);\n const { state } = getSessionState(ctx, sessionStates);\n if (query === state.lastInjectedQuery) return;\n\n try {\n const recalled = await client.recall(query, sessionKey, ctx.cwd);\n const context = trimContext(recalled.context ?? \"\", config.recallBudgetChars);\n if (!context) return;\n state.lastInjectedQuery = query;\n return {\n messages: [\n {\n role: \"user\",\n content: [{ type: \"text\", text: `Remnic recalled context for this turn:\\n\\n${context}` }],\n timestamp: Date.now(),\n },\n ...event.messages,\n ],\n };\n } catch (err) {\n notify(ctx, `Remnic recall unavailable: ${errorMessage(err)}`, \"warning\");\n }\n });\n\n pi.on(\"message_end\", async (event, ctx) => {\n if (!config.observeEnabled || !isUserMessage(event.message)) return;\n const { state } = getSessionState(ctx, sessionStates);\n await observeMessages(ctx, client, [event.message], state.observedHashes, state.liveObservedReplayKeys);\n });\n\n pi.on(\"turn_end\", async (event, ctx) => {\n if (!config.observeEnabled) return;\n const messages = [event.message, ...(Array.isArray(event.toolResults) ? event.toolResults : [])];\n const { state } = getSessionState(ctx, sessionStates);\n await observeMessages(ctx, client, messages, state.observedHashes, state.liveObservedReplayKeys);\n });\n\n pi.on(\"session_shutdown\", async (_event, ctx) => {\n const { sessionKey, state } = getSessionState(ctx, sessionStates);\n if (config.observeEnabled) {\n const branch = safeBranch(ctx);\n const branchMessages = branchMessagesWithEntryIdentity(branch);\n const unobservedBranchMessages = skipLiveObservedReplayMessages(ctx, branchMessages, state.liveObservedReplayKeys);\n if (unobservedBranchMessages.length > 0) await observeMessages(ctx, client, unobservedBranchMessages, state.observedHashes);\n }\n persistObservedState(pi, state.observedHashes);\n sessionStates.delete(sessionKey);\n });\n\n pi.on(\"session_before_compact\", async (event, ctx) => {\n if (!config.compactionEnabled || !config.authToken) return;\n const sessionKey = sessionKeyFromContext(ctx);\n const preparation = event.preparation ?? {};\n try {\n await client.lcmCompactionFlush(sessionKey);\n } catch (err) {\n notify(ctx, `Remnic LCM flush failed: ${errorMessage(err)}`, \"warning\");\n return;\n }\n\n const summary = buildCompactionSummary(preparation);\n if (!summary.trim()) return;\n void client.contextCheckpoint(sessionKey, summary).catch(() => undefined);\n const tokensBefore = finiteTokenCount(preparation.tokensBefore);\n const tokensAfter = finiteTokenCount(preparation.tokensAfter);\n if (tokensBefore !== null && tokensAfter !== null) {\n void client.lcmCompactionRecord(sessionKey, tokensBefore, tokensAfter).catch(() => undefined);\n }\n const details = fileDetailsFromPreparation(preparation);\n return {\n compaction: {\n summary,\n firstKeptEntryId: preparation.firstKeptEntryId,\n tokensBefore: preparation.tokensBefore,\n details: {\n ...details,\n remnic: { version: 1, source: \"pi\" },\n },\n },\n };\n });\n\n registerCommands(pi, client, config);\n if (config.mcpToolsEnabled && config.authToken) {\n await registerMcpTools(pi, client, config);\n }\n };\n}\n\nexport default async function remnicPiExtension(pi: PiApi): Promise<void> {\n await createRemnicPiExtension()(pi);\n}\n\nfunction registerCommands(pi: PiApi, client: RemnicClient, config: RemnicPiConfig): void {\n pi.registerCommand(\"remnic-status\", {\n description: \"Check Remnic daemon status\",\n handler: commandHandler(async (_args, ctx) => {\n const health = await client.health();\n notify(ctx, `Remnic ${health.ok ? \"healthy\" : \"unhealthy\"} at ${config.remnicDaemonUrl}`, health.ok ? \"success\" : \"warning\");\n }),\n });\n\n pi.registerCommand(\"remnic-recall\", {\n description: \"Recall Remnic context for a query\",\n handler: commandHandler(async (args, ctx) => {\n const query = args.trim();\n if (!query) {\n notify(ctx, \"Usage: /remnic-recall <query>\", \"warning\");\n return;\n }\n const result = await client.recall(query, sessionKeyFromContext(ctx), ctx.cwd);\n notify(ctx, trimContext(result.context ?? \"(no Remnic context)\", MAX_CONTEXT_CHARS), \"info\");\n }),\n });\n\n pi.registerCommand(\"remnic-remember\", {\n description: \"Store a Remnic memory\",\n handler: commandHandler(async (args, ctx) => {\n const content = args.trim();\n if (!content) {\n notify(ctx, \"Usage: /remnic-remember <memory>\", \"warning\");\n return;\n }\n await client.storeMemory(content, sessionKeyFromContext(ctx));\n notify(ctx, \"Stored Remnic memory\", \"success\");\n }),\n });\n\n pi.registerCommand(\"remnic-lcm-search\", {\n description: \"Search Remnic LCM archived Pi context\",\n handler: commandHandler(async (args, ctx) => {\n const query = args.trim();\n if (!query) {\n notify(ctx, \"Usage: /remnic-lcm-search <query>\", \"warning\");\n return;\n }\n const result = await client.lcmSearch(query, sessionKeyFromContext(ctx));\n notify(ctx, JSON.stringify(result, null, 2), \"info\");\n }),\n });\n\n pi.registerCommand(\"remnic-why\", {\n description: \"Explain the last Remnic recall\",\n handler: commandHandler(async (_args, ctx) => {\n const result = await client.recallExplain(sessionKeyFromContext(ctx));\n notify(ctx, JSON.stringify(result, null, 2), \"info\");\n }),\n });\n\n pi.registerCommand(\"remnic-compact\", {\n description: \"Trigger Pi compaction with Remnic LCM coordination\",\n handler: commandHandler(async (_args, ctx) => {\n ctx.compact?.();\n notify(ctx, \"Compaction requested\", \"info\");\n }),\n });\n}\n\nfunction commandHandler(handler: (args: string, ctx: any) => Promise<void>): (args: string, ctx: any) => Promise<void> {\n return async (args, ctx) => {\n try {\n await handler(args, ctx);\n } catch (err) {\n notify(ctx, `Remnic command failed: ${errorMessage(err)}`, \"warning\");\n }\n };\n}\n\nasync function registerMcpTools(pi: PiApi, client: RemnicClient, config: RemnicPiConfig): Promise<void> {\n let tools: McpTool[] = [];\n try {\n tools = await client.mcpListTools();\n } catch {\n return;\n }\n for (const tool of tools) {\n if (!tool.name.startsWith(\"remnic.\")) continue;\n const piToolName = tool.name.replace(/^remnic\\./, \"remnic_\").replace(/[^a-zA-Z0-9_]/g, \"_\");\n pi.registerTool({\n name: piToolName,\n label: tool.name,\n description: tool.description ?? `Call ${tool.name}`,\n parameters: toPiToolParametersSchema(tool.inputSchema),\n async execute(_toolCallId: string, params: Record<string, unknown>, _signal: AbortSignal | undefined, _onUpdate: unknown, ctx: any) {\n const sessionKey = sessionKeyFromContext(ctx);\n const {\n sessionKey: _ignoredSessionKey,\n namespace: _ignoredNamespace,\n cwd: _ignoredCwd,\n ...safeParams\n } = params ?? {};\n const result = await client.mcpTool(tool.name, {\n ...safeParams,\n sessionKey,\n namespace: config.namespace,\n cwd: ctx.cwd,\n });\n return {\n content: [{ type: \"text\", text: JSON.stringify(result, null, 2) }],\n details: result,\n };\n },\n });\n }\n}\n\nexport function toPiToolParametersSchema(inputSchema: unknown): TSchema {\n return Type.Unsafe(stripSessionOwnedSchemaFields(inputSchema));\n}\n\nexport function stripSessionOwnedSchemaFields(inputSchema: unknown): Record<string, unknown> {\n if (!isRecord(inputSchema)) {\n return { type: \"object\", properties: {}, additionalProperties: true };\n }\n const schema: Record<string, unknown> = { ...inputSchema };\n const properties = isRecord(inputSchema.properties)\n ? { ...inputSchema.properties }\n : {};\n delete properties.sessionKey;\n delete properties.namespace;\n delete properties.cwd;\n schema.properties = properties;\n if (Array.isArray(inputSchema.required)) {\n schema.required = inputSchema.required.filter(\n (field) => field !== \"sessionKey\" && field !== \"namespace\" && field !== \"cwd\",\n );\n }\n return schema;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction isUserMessage(message: unknown): boolean {\n return isRecord(message) && message.role === \"user\";\n}\n\nfunction getSessionState(ctx: any, states: Map<string, PiSessionState>): { sessionKey: string; state: PiSessionState } {\n const sessionKey = sessionKeyFromContext(ctx);\n let state = states.get(sessionKey);\n if (!state) {\n state = {\n observedHashes: new Set<string>(),\n liveObservedReplayKeys: new Map<string, number>(),\n lastInjectedQuery: \"\",\n };\n states.set(sessionKey, state);\n pruneSessionStates(states);\n }\n return { sessionKey, state };\n}\n\nfunction pruneSessionStates(states: Map<string, PiSessionState>): void {\n while (states.size > MAX_SESSION_STATES) {\n const oldest = states.keys().next().value;\n if (typeof oldest !== \"string\") return;\n states.delete(oldest);\n }\n}\n\nexport async function observeMessages(\n ctx: any,\n client: RemnicClient,\n rawMessages: unknown[],\n observedHashes: Set<string>,\n liveObservedReplayKeys?: Map<string, number>,\n): Promise<void> {\n const sessionKey = sessionKeyFromContext(ctx);\n const messages: ObserveMessage[] = [];\n const pendingHashes = new Set<string>();\n for (const raw of rawMessages) {\n const message = toObserveMessage(raw);\n if (!message) continue;\n const hash = observedMessageDedupeKey(message, sessionKey);\n if (hash && (observedHashes.has(hash) || pendingHashes.has(hash))) continue;\n if (hash) pendingHashes.add(hash);\n messages.push(message);\n }\n if (messages.length === 0) return;\n try {\n await client.observe(sessionKey, ctx.cwd, messages);\n for (const hash of pendingHashes) rememberObservedHash(observedHashes, hash);\n if (liveObservedReplayKeys) {\n for (const message of messages) {\n rememberLiveObservedReplayKey(liveObservedReplayKeys, liveReplayKey(message, sessionKey));\n }\n }\n } catch (err) {\n notify(ctx, `Remnic observe failed: ${errorMessage(err)}`, \"warning\");\n }\n}\n\nexport function buildCompactionSummary(preparation: any): string {\n const previousSummary = typeof preparation.previousSummary === \"string\"\n ? preparation.previousSummary.trim()\n : \"\";\n const messages = [\n ...(Array.isArray(preparation.messagesToSummarize) ? preparation.messagesToSummarize : []),\n ...(Array.isArray(preparation.turnPrefixMessages) ? preparation.turnPrefixMessages : []),\n ];\n const transcript = summarizeMessages(messages, 24000);\n const details = fileDetailsFromPreparation(preparation);\n\n if (\n !previousSummary &&\n !transcript &&\n details.readFiles.length === 0 &&\n details.modifiedFiles.length === 0\n ) {\n return \"\";\n }\n\n const sections: string[] = [\n \"## Remnic Pi Context Checkpoint\",\n \"\",\n \"This checkpoint was created by Remnic during Pi context compaction.\",\n ];\n if (previousSummary) sections.push(\"\", \"## Previous Summary\", previousSummary);\n if (transcript) sections.push(\"\", \"## Conversation Excerpt\", transcript);\n if (details.readFiles.length > 0) sections.push(\"\", \"<read-files>\", ...details.readFiles, \"</read-files>\");\n if (details.modifiedFiles.length > 0) sections.push(\"\", \"<modified-files>\", ...details.modifiedFiles, \"</modified-files>\");\n return sections.join(\"\\n\");\n}\n\nfunction fileDetailsFromPreparation(preparation: any): { readFiles: string[]; modifiedFiles: string[] } {\n const fileOps = preparation?.fileOps;\n const read = fileOps?.read instanceof Set ? Array.from(fileOps.read).filter(isString) : [];\n const edited = fileOps?.edited instanceof Set ? Array.from(fileOps.edited).filter(isString) : [];\n const written = fileOps?.written instanceof Set ? Array.from(fileOps.written).filter(isString) : [];\n const modified = new Set([...edited, ...written]);\n return {\n readFiles: read.filter((file) => !modified.has(file)).sort(),\n modifiedFiles: Array.from(modified).sort(),\n };\n}\n\nfunction restoreObservedState(ctx: any, observedHashes: Set<string>): void {\n for (const entry of safeEntries(ctx)) {\n if (entry?.type !== \"custom\" || entry.customType !== STATE_CUSTOM_TYPE) continue;\n const hashes = entry.data?.observedHashes;\n if (Array.isArray(hashes)) {\n for (const hash of hashes) {\n if (typeof hash === \"string\") rememberObservedHash(observedHashes, hash);\n }\n }\n }\n}\n\nfunction rememberObservedHash(observedHashes: Set<string>, hash: string): void {\n if (observedHashes.has(hash)) return;\n while (observedHashes.size >= MAX_OBSERVED_HASHES) {\n const oldest = observedHashes.keys().next().value;\n if (typeof oldest !== \"string\") break;\n observedHashes.delete(oldest);\n }\n observedHashes.add(hash);\n}\n\nfunction rememberLiveObservedReplayKey(liveObservedReplayKeys: Map<string, number>, key: string): void {\n liveObservedReplayKeys.set(key, (liveObservedReplayKeys.get(key) ?? 0) + 1);\n}\n\nfunction consumeLiveObservedReplayKey(liveObservedReplayKeys: Map<string, number>, key: string): boolean {\n const count = liveObservedReplayKeys.get(key) ?? 0;\n if (count <= 0) return false;\n if (count === 1) liveObservedReplayKeys.delete(key);\n else liveObservedReplayKeys.set(key, count - 1);\n return true;\n}\n\nfunction skipLiveObservedReplayMessages(\n ctx: any,\n rawMessages: unknown[],\n liveObservedReplayKeys: Map<string, number>,\n): unknown[] {\n if (liveObservedReplayKeys.size === 0) return rawMessages;\n const sessionKey = sessionKeyFromContext(ctx);\n const unobserved: unknown[] = [];\n for (const raw of rawMessages) {\n const message = toObserveMessage(raw);\n if (message && consumeLiveObservedReplayKey(liveObservedReplayKeys, liveReplayKey(message, sessionKey))) {\n continue;\n }\n unobserved.push(raw);\n }\n return unobserved;\n}\n\nfunction liveReplayKey(message: ObserveMessage, sessionKey: string): string {\n return hashObservedMessage(message, sessionKey, \"live-replay\");\n}\n\nfunction persistObservedState(pi: PiApi, observedHashes: Set<string>): void {\n const observed = Array.from(observedHashes).slice(-MAX_OBSERVED_HASHES);\n pi.appendEntry(STATE_CUSTOM_TYPE, {\n observedHashes: observed,\n recordedAt: new Date().toISOString(),\n });\n}\n\nasync function setStatus(ctx: any, client: RemnicClient, config: RemnicPiConfig): Promise<void> {\n try {\n await client.health();\n ctx.ui?.setStatus?.(\"remnic\", `Remnic ${config.namespace ? `(${config.namespace})` : \"ready\"}`);\n } catch {\n ctx.ui?.setStatus?.(\"remnic\", \"Remnic offline\");\n }\n}\n\nfunction safeEntries(ctx: any): any[] {\n try {\n const entries = ctx.sessionManager?.getEntries?.();\n return Array.isArray(entries) ? entries : [];\n } catch {\n return [];\n }\n}\n\nfunction safeBranch(ctx: any): any[] {\n try {\n const branch = ctx.sessionManager?.getBranch?.();\n return Array.isArray(branch) ? branch : [];\n } catch {\n return [];\n }\n}\n\nfunction branchMessagesWithEntryIdentity(branch: any[]): unknown[] {\n const messages: unknown[] = [];\n for (const entry of branch) {\n const message = messageWithEntryIdentity(entry);\n if (message) messages.push(message);\n }\n return messages;\n}\n\nfunction messageWithEntryIdentity(entry: any): unknown | null {\n const message = entry?.message;\n if (!message || typeof message !== \"object\" || Array.isArray(message)) return message ?? null;\n\n const source = isRecord(entry) ? entry : {};\n const enriched: Record<string, unknown> = { ...(message as Record<string, unknown>) };\n assignMissingIdentity(enriched, \"entryId\", source.id ?? source.entryId ?? source.entry_id);\n assignMissingIdentity(enriched, \"timestamp\", source.timestamp);\n assignMissingIdentity(enriched, \"createdAt\", source.createdAt ?? source.created_at);\n return enriched;\n}\n\nfunction assignMissingIdentity(target: Record<string, unknown>, field: string, value: unknown): void {\n if (target[field] !== undefined) return;\n if (typeof value === \"string\" && value.length > 0) {\n target[field] = value;\n return;\n }\n if (typeof value === \"number\" && Number.isFinite(value)) {\n target[field] = value;\n }\n}\n\nfunction trimContext(value: string, budget: number): string {\n if (value.length <= budget) return value;\n if (budget <= TRUNCATION_NOTICE.length) return TRUNCATION_NOTICE.slice(0, budget);\n return `${value.slice(0, budget - TRUNCATION_NOTICE.length)}${TRUNCATION_NOTICE}`;\n}\n\nfunction notify(ctx: any, message: string, level: \"info\" | \"success\" | \"warning\" | \"error\"): void {\n if (ctx?.hasUI === false) return;\n ctx?.ui?.notify?.(message, level);\n}\n\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\nfunction finiteTokenCount(value: unknown): number | null {\n return typeof value === \"number\" && Number.isFinite(value) && value >= 0 ? value : null;\n}\n\nfunction isString(value: unknown): value is string {\n return typeof value === \"string\";\n}\n\nexport { textFromMessage };\n","import { existsSync, readFileSync } from \"node:fs\";\nimport path from \"node:path\";\n\nimport { expandTildePath } from \"@remnic/core\";\n\nimport { REMNIC_PI_EXTENSION_DIR_NAME, resolvePiAgentHome } from \"./paths.js\";\n\nexport interface RemnicPiConfig {\n remnicDaemonUrl: string;\n authToken?: string;\n namespace?: string;\n recallMode: \"auto\" | \"minimal\" | \"full\" | \"graph_mode\" | \"no_recall\";\n recallTopK: number;\n recallBudgetChars: number;\n recallEnabled: boolean;\n observeEnabled: boolean;\n observeSkipExtraction: boolean;\n compactionEnabled: boolean;\n mcpToolsEnabled: boolean;\n statusEnabled: boolean;\n requestTimeoutMs: number;\n}\n\nexport interface LoadConfigOptions {\n configPath?: string;\n env?: NodeJS.ProcessEnv;\n}\n\nconst DEFAULT_CONFIG: RemnicPiConfig = {\n remnicDaemonUrl: \"http://127.0.0.1:4318\",\n recallMode: \"auto\",\n recallTopK: 8,\n recallBudgetChars: 12000,\n recallEnabled: true,\n observeEnabled: true,\n observeSkipExtraction: false,\n compactionEnabled: true,\n mcpToolsEnabled: true,\n statusEnabled: true,\n requestTimeoutMs: 5000,\n};\n\nfunction defaultConfigPath(env: NodeJS.ProcessEnv): string {\n return path.join(resolvePiAgentHome(env), \"extensions\", REMNIC_PI_EXTENSION_DIR_NAME, \"remnic.config.json\");\n}\n\nfunction coerceBoolean(value: unknown, fallback: boolean, fieldName: string): boolean {\n if (value === undefined || value === null) return fallback;\n if (typeof value === \"boolean\") return value;\n if (typeof value === \"string\") {\n const normalized = value.trim().toLowerCase();\n if ([\"true\", \"1\", \"yes\", \"on\"].includes(normalized)) return true;\n if ([\"false\", \"0\", \"no\", \"off\"].includes(normalized)) return false;\n }\n throw new Error(`Invalid boolean value for Remnic Pi config field ${fieldName}`);\n}\n\nfunction coercePositiveInt(value: unknown, fallback: number, max: number, fieldName: string): number {\n if (value === undefined || value === null || value === \"\") return fallback;\n let parsed: number;\n if (typeof value === \"number\") {\n parsed = value;\n } else if (typeof value === \"string\") {\n const trimmed = value.trim();\n if (trimmed.length === 0) return fallback;\n if (!/^[+-]?\\d+$/.test(trimmed)) {\n throw new Error(`Invalid numeric value for Remnic Pi config field ${fieldName}: expected an integer from 1 to ${max}`);\n }\n parsed = Number(trimmed);\n } else {\n throw new Error(`Invalid numeric value for Remnic Pi config field ${fieldName}: expected an integer from 1 to ${max}`);\n }\n if (!Number.isInteger(parsed) || parsed <= 0 || parsed > max) {\n throw new Error(`Invalid numeric value for Remnic Pi config field ${fieldName}: expected an integer from 1 to ${max}`);\n }\n return parsed;\n}\n\nfunction coerceOptionalNonEmptyString(value: unknown, fieldName: string): string | undefined {\n if (value === undefined || value === null) return undefined;\n if (typeof value === \"string\" && value.trim().length > 0) return value.trim();\n throw new Error(`Invalid string value for Remnic Pi config field ${fieldName}`);\n}\n\nfunction coerceOptionalString(value: unknown, fieldName: string): string | undefined {\n if (value === undefined || value === null) return undefined;\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n }\n throw new Error(`Invalid string value for Remnic Pi config field ${fieldName}`);\n}\n\nfunction coerceOptionalHttpUrl(value: unknown, fieldName: string): string | undefined {\n if (value === undefined || value === null) return undefined;\n if (typeof value !== \"string\") {\n throw new Error(`Invalid URL value for Remnic Pi config field ${fieldName}: expected an http or https URL`);\n }\n const trimmed = value.trim();\n if (trimmed.length === 0) return undefined;\n try {\n const parsed = new URL(trimmed);\n if (parsed.protocol === \"http:\" || parsed.protocol === \"https:\") return trimTrailingSlashes(trimmed);\n } catch {\n // Fall through to the shared error below.\n }\n throw new Error(`Invalid URL value for Remnic Pi config field ${fieldName}: expected an http or https URL`);\n}\n\nfunction coerceRecallMode(value: unknown): RemnicPiConfig[\"recallMode\"] {\n if (value === undefined || value === null || value === \"\") return DEFAULT_CONFIG.recallMode;\n if (\n value === \"minimal\" ||\n value === \"full\" ||\n value === \"graph_mode\" ||\n value === \"no_recall\" ||\n value === \"auto\"\n ) {\n return value;\n }\n throw new Error(`Invalid recallMode value for Remnic Pi config: ${JSON.stringify(value)}`);\n}\n\nfunction readConfigFile(configPath: string): Record<string, unknown> {\n if (!existsSync(configPath)) return {};\n try {\n const raw = readFileSync(configPath, \"utf-8\");\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n throw new Error(\"expected a JSON object\");\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n throw new Error(`Failed to load Remnic Pi config at ${configPath}: ${reason}`);\n }\n}\n\nfunction trimTrailingSlashes(value: string): string {\n let end = value.length;\n while (end > 0 && value.charCodeAt(end - 1) === 47) end -= 1;\n return value.slice(0, end);\n}\n\nexport function resolveConfigPath(options: LoadConfigOptions = {}): string {\n const env = options.env ?? process.env;\n return expandTildePath(options.configPath || env.REMNIC_PI_CONFIG || defaultConfigPath(env));\n}\n\nexport function loadConfig(options: LoadConfigOptions = {}): RemnicPiConfig {\n const env = options.env ?? process.env;\n const fileConfig = readConfigFile(resolveConfigPath(options));\n const daemonUrl =\n coerceOptionalHttpUrl(fileConfig.remnicDaemonUrl, \"remnicDaemonUrl\") ??\n coerceOptionalHttpUrl(env.REMNIC_DAEMON_URL, \"REMNIC_DAEMON_URL\") ??\n DEFAULT_CONFIG.remnicDaemonUrl;\n const authToken =\n coerceOptionalString(fileConfig.authToken, \"authToken\") ??\n coerceOptionalString(env.REMNIC_PI_AUTH_TOKEN, \"REMNIC_PI_AUTH_TOKEN\");\n const namespace = coerceOptionalNonEmptyString(fileConfig.namespace, \"namespace\");\n\n return {\n remnicDaemonUrl: daemonUrl,\n authToken,\n namespace,\n recallMode: coerceRecallMode(fileConfig.recallMode),\n recallTopK: coercePositiveInt(fileConfig.recallTopK, DEFAULT_CONFIG.recallTopK, 50, \"recallTopK\"),\n recallBudgetChars: coercePositiveInt(fileConfig.recallBudgetChars, DEFAULT_CONFIG.recallBudgetChars, 64000, \"recallBudgetChars\"),\n recallEnabled: coerceBoolean(fileConfig.recallEnabled, DEFAULT_CONFIG.recallEnabled, \"recallEnabled\"),\n observeEnabled: coerceBoolean(fileConfig.observeEnabled, DEFAULT_CONFIG.observeEnabled, \"observeEnabled\"),\n observeSkipExtraction: coerceBoolean(fileConfig.observeSkipExtraction, DEFAULT_CONFIG.observeSkipExtraction, \"observeSkipExtraction\"),\n compactionEnabled: coerceBoolean(fileConfig.compactionEnabled, DEFAULT_CONFIG.compactionEnabled, \"compactionEnabled\"),\n mcpToolsEnabled: coerceBoolean(fileConfig.mcpToolsEnabled, DEFAULT_CONFIG.mcpToolsEnabled, \"mcpToolsEnabled\"),\n statusEnabled: coerceBoolean(fileConfig.statusEnabled, DEFAULT_CONFIG.statusEnabled, \"statusEnabled\"),\n requestTimeoutMs: coercePositiveInt(fileConfig.requestTimeoutMs, DEFAULT_CONFIG.requestTimeoutMs, 60_000, \"requestTimeoutMs\"),\n };\n}\n","import type { RemnicPiConfig } from \"./config.js\";\n\nexport interface RecallResponse {\n context?: string;\n results?: Array<{ id?: string; content?: string; score?: number; category?: string }>;\n count?: number;\n}\n\nexport interface ObserveMessagePart {\n ordinal?: number;\n kind: \"text\" | \"tool_call\" | \"tool_result\" | \"patch\" | \"file_read\" | \"file_write\" | \"step_start\" | \"step_finish\" | \"snapshot\" | \"retry\";\n payload: Record<string, unknown>;\n toolName?: string | null;\n filePath?: string | null;\n createdAt?: string | null;\n}\n\nexport interface ObserveMessage {\n role: \"user\" | \"assistant\";\n content: string;\n sourceFormat?: \"pi\";\n rawContent?: unknown;\n parts?: ObserveMessagePart[];\n}\n\nexport interface McpTool {\n name: string;\n description?: string;\n inputSchema?: Record<string, unknown>;\n}\n\nexport class RemnicHttpError extends Error {\n constructor(\n readonly status: number,\n message: string,\n ) {\n super(message);\n }\n}\n\nexport class RemnicClient {\n private requestId = 0;\n\n constructor(private readonly config: RemnicPiConfig) {}\n\n async health(): Promise<Record<string, unknown>> {\n return this.request(\"GET\", \"/engram/v1/health\");\n }\n\n async recall(query: string, sessionKey: string, cwd: string): Promise<RecallResponse> {\n return this.request(\"POST\", \"/engram/v1/recall\", {\n query,\n sessionKey,\n cwd,\n namespace: this.config.namespace,\n topK: this.config.recallTopK,\n mode: this.config.recallMode,\n });\n }\n\n async recallExplain(sessionKey: string): Promise<Record<string, unknown>> {\n return this.request(\"POST\", \"/engram/v1/recall/explain\", {\n sessionKey,\n namespace: this.config.namespace,\n });\n }\n\n async observe(sessionKey: string, cwd: string, messages: ObserveMessage[]): Promise<Record<string, unknown>> {\n return this.request(\"POST\", \"/engram/v1/observe\", {\n sessionKey,\n cwd,\n namespace: this.config.namespace,\n skipExtraction: this.config.observeSkipExtraction,\n messages,\n });\n }\n\n async storeMemory(content: string, sessionKey: string): Promise<Record<string, unknown>> {\n return this.request(\"POST\", \"/engram/v1/memories\", {\n content,\n category: \"fact\",\n sourceReason: \"Captured from Pi via Remnic extension\",\n sessionKey,\n namespace: this.config.namespace,\n });\n }\n\n async lcmSearch(query: string, sessionKey: string, limit = 10): Promise<Record<string, unknown>> {\n return this.request(\"POST\", \"/engram/v1/lcm/search\", {\n query,\n sessionKey,\n namespace: this.config.namespace,\n limit,\n });\n }\n\n async lcmCompactionFlush(sessionKey: string): Promise<Record<string, unknown>> {\n return this.request(\"POST\", \"/engram/v1/lcm/compaction/flush\", {\n sessionKey,\n namespace: this.config.namespace,\n });\n }\n\n async lcmCompactionRecord(sessionKey: string, tokensBefore: number, tokensAfter: number): Promise<Record<string, unknown>> {\n return this.request(\"POST\", \"/engram/v1/lcm/compaction/record\", {\n sessionKey,\n namespace: this.config.namespace,\n tokensBefore,\n tokensAfter,\n });\n }\n\n async contextCheckpoint(sessionKey: string, context: string): Promise<Record<string, unknown>> {\n return this.mcpTool(\"remnic.context_checkpoint\", {\n sessionKey,\n context,\n namespace: this.config.namespace,\n });\n }\n\n async mcpListTools(): Promise<McpTool[]> {\n const result = await this.mcpRequest(\"tools/list\", {});\n const tools = (result as { tools?: unknown }).tools;\n return Array.isArray(tools) ? tools.filter(isMcpTool) : [];\n }\n\n async mcpTool(name: string, args: Record<string, unknown>): Promise<Record<string, unknown>> {\n return this.mcpRequest(\"tools/call\", {\n name,\n arguments: args,\n });\n }\n\n private async request<T = Record<string, unknown>>(method: string, pathname: string, body?: unknown): Promise<T> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.config.requestTimeoutMs);\n try {\n const response = await fetch(`${this.config.remnicDaemonUrl}${pathname}`, {\n method,\n headers: {\n ...(body === undefined ? {} : { \"Content-Type\": \"application/json\" }),\n ...(this.config.authToken ? { Authorization: `Bearer ${this.config.authToken}` } : {}),\n \"X-Engram-Client-Id\": \"pi\",\n },\n body: body === undefined ? undefined : JSON.stringify(body),\n signal: controller.signal,\n });\n const text = await response.text();\n const payload = text ? JSON.parse(text) : {};\n if (!response.ok) {\n throw new RemnicHttpError(response.status, typeof payload?.error === \"string\" ? payload.error : response.statusText);\n }\n return payload as T;\n } finally {\n clearTimeout(timeout);\n }\n }\n\n private async mcpRequest(method: string, params: Record<string, unknown>): Promise<Record<string, unknown>> {\n this.requestId += 1;\n const payload = await this.request<Record<string, unknown>>(\"POST\", \"/mcp\", {\n jsonrpc: \"2.0\",\n id: this.requestId,\n method,\n params,\n });\n if (payload.error) {\n throw new Error(JSON.stringify(payload.error));\n }\n return (payload.result && typeof payload.result === \"object\" ? payload.result : payload) as Record<string, unknown>;\n }\n}\n\nfunction isMcpTool(value: unknown): value is McpTool {\n return !!value && typeof value === \"object\" && typeof (value as { name?: unknown }).name === \"string\";\n}\n","import { createHash } from \"node:crypto\";\n\nimport { parsePiMessageParts, type LcmMessagePartInput } from \"@remnic/core\";\n\nimport type { ObserveMessage, ObserveMessagePart } from \"./client.js\";\n\ntype PiMessage = Record<string, unknown>;\n\nexport function sessionKeyFromContext(ctx: { sessionManager?: { getSessionId?: () => string } }): string {\n const id = ctx.sessionManager?.getSessionId?.();\n return id && id.trim().length > 0 ? `pi:${id}` : \"pi:default\";\n}\n\nexport function textFromMessage(message: unknown): string {\n if (!message || typeof message !== \"object\") return \"\";\n const obj = message as PiMessage;\n const role = typeof obj.role === \"string\" ? obj.role : \"message\";\n if (role === \"bashExecution\") {\n const command = typeof obj.command === \"string\" ? obj.command : \"\";\n const output = typeof obj.output === \"string\" ? obj.output : \"\";\n return [`Ran ${command}`, output].filter(Boolean).join(\"\\n\");\n }\n return textFromContent(obj.content).trim();\n}\n\nexport function latestUserQuery(messages: unknown[]): string {\n for (let index = messages.length - 1; index >= 0; index--) {\n const message = messages[index] as PiMessage;\n if (isExcludedFromContext(message)) continue;\n if (message?.role === \"user\") {\n const text = textFromMessage(message);\n if (text.length > 0) return text;\n }\n }\n return \"\";\n}\n\nexport function toObserveMessage(message: unknown): ObserveMessage | null {\n if (!message || typeof message !== \"object\") return null;\n const obj = message as PiMessage;\n if (isExcludedFromContext(obj)) return null;\n const role = obj.role === \"user\" || obj.role === \"bashExecution\" ? \"user\" : \"assistant\";\n const content = textFromMessage(obj);\n if (content.length === 0) return null;\n return {\n role,\n content,\n sourceFormat: \"pi\",\n rawContent: obj,\n parts: partsFromMessage(obj, content),\n };\n}\n\nexport function hashObservedMessage(message: ObserveMessage, sessionKey = \"\", identity = \"content\"): string {\n return createHash(\"sha256\")\n .update(sessionKey)\n .update(\"\\0\")\n .update(message.role)\n .update(\"\\0\")\n .update(identity)\n .update(\"\\0\")\n .update(message.content)\n .digest(\"hex\");\n}\n\nexport function observedMessageDedupeKey(\n message: ObserveMessage,\n sessionKey = \"\",\n): string | null {\n const identity = stableObservedMessageIdentity(message.rawContent);\n return identity ? hashObservedMessage(message, sessionKey, identity) : null;\n}\n\nexport function summarizeMessages(messages: unknown[], maxChars: number): string {\n const chunks: string[] = [];\n let used = 0;\n for (const message of messages) {\n if (isExcludedFromContext(message)) continue;\n const text = textFromMessage(message);\n if (!text) continue;\n const role = typeof (message as PiMessage)?.role === \"string\" ? (message as PiMessage).role : \"message\";\n const line = `[${role}] ${text}`;\n const separatorLength = chunks.length > 0 ? 2 : 0;\n const remaining = maxChars - used - separatorLength;\n if (remaining <= 0) break;\n const clipped = line.length > remaining ? line.slice(0, remaining) : line;\n if (clipped.length > 0) chunks.push(clipped);\n used += separatorLength + clipped.length;\n if (used >= maxChars) break;\n }\n return chunks.join(\"\\n\\n\");\n}\n\nexport function isExcludedFromContext(message: unknown): boolean {\n return !!message && typeof message === \"object\" && (message as PiMessage).excludeFromContext === true;\n}\n\nfunction textFromContent(content: unknown): string {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n const chunks: string[] = [];\n for (const block of content) {\n if (!block || typeof block !== \"object\") continue;\n const obj = block as PiMessage;\n if (obj.type === \"text\" && typeof obj.text === \"string\") chunks.push(obj.text);\n if (obj.type === \"toolCall\" && typeof obj.name === \"string\") {\n chunks.push(`Tool ${obj.name} called with ${JSON.stringify(obj.arguments ?? {})}`);\n }\n }\n return chunks.join(\"\\n\");\n}\n\nfunction partsFromMessage(message: PiMessage, renderedContent: string): ObserveMessagePart[] {\n return parsePiMessageParts(message, {\n renderedContent,\n allowRenderedFallback: true,\n }).map(toObserveMessagePart);\n}\n\nfunction toObserveMessagePart(part: LcmMessagePartInput): ObserveMessagePart {\n return {\n ordinal: part.ordinal ?? undefined,\n kind: part.kind,\n payload: part.payload,\n toolName: part.toolName ?? part.tool_name ?? undefined,\n filePath: part.filePath ?? part.file_path ?? undefined,\n createdAt: part.createdAt ?? part.created_at ?? undefined,\n };\n}\n\nfunction stableObservedMessageIdentity(rawContent: unknown): string | null {\n if (rawContent && typeof rawContent === \"object\") {\n const obj = rawContent as PiMessage;\n const fields = [\n \"id\",\n \"entryId\",\n \"entry_id\",\n \"messageId\",\n \"message_id\",\n \"turnId\",\n \"turn_id\",\n \"timestamp\",\n \"createdAt\",\n \"created_at\",\n ];\n for (const field of fields) {\n const value = obj[field];\n if (typeof value === \"string\" && value.length > 0) return `${field}:${value}`;\n if (typeof value === \"number\" && Number.isFinite(value)) return `${field}:${value}`;\n }\n }\n return null;\n}\n"],"mappings":"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","names":["remnicPiExtension"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/config.ts","../src/client.ts","../src/messages.ts"],"sourcesContent":["import { Type, type TSchema } from \"@sinclair/typebox\";\n\nimport { loadConfig, type LoadConfigOptions, type RemnicPiConfig } from \"./config.js\";\nimport { RemnicClient, type McpTool, type ObserveMessage } from \"./client.js\";\nimport {\n hashObservedMessage,\n latestUserQuery,\n observedMessageDedupeKey,\n sessionKeyFromContext,\n summarizeMessages,\n textFromMessage,\n toObserveMessage,\n} from \"./messages.js\";\n\ntype PiApi = {\n on(event: string, handler: (event: any, ctx: any) => unknown | Promise<unknown>): void;\n registerCommand(name: string, options: { description?: string; handler: (args: string, ctx: any) => Promise<void> }): void;\n registerTool(tool: Record<string, unknown>): void;\n appendEntry<T = unknown>(customType: string, data?: T): void;\n};\n\nexport interface RemnicPiExtensionOptions extends LoadConfigOptions {\n config?: RemnicPiConfig;\n}\n\nconst STATE_CUSTOM_TYPE = \"remnic_state\";\nconst MAX_OBSERVED_HASHES = 2000;\nconst MAX_SESSION_STATES = 50;\nconst MAX_CONTEXT_CHARS = 12000;\nconst TRUNCATION_NOTICE = \"\\n\\n[Remnic context truncated]\";\n\ntype PiSessionState = {\n observedHashes: Set<string>;\n liveObservedReplayKeys: Map<string, number>;\n lastInjectedQuery: string;\n};\n\nexport function createRemnicPiExtension(options: RemnicPiExtensionOptions = {}) {\n const config = options.config ?? loadConfig(options);\n const client = new RemnicClient(config);\n const sessionStates = new Map<string, PiSessionState>();\n\n return async function remnicPiExtension(pi: PiApi): Promise<void> {\n pi.on(\"session_start\", async (_event, ctx) => {\n const { state } = getSessionState(ctx, sessionStates);\n restoreObservedState(ctx, state.observedHashes);\n if (!config.statusEnabled) return;\n await setStatus(ctx, client, config);\n });\n\n pi.on(\"context\", async (event, ctx) => {\n if (!config.recallEnabled || !config.authToken) return;\n const query = latestUserQuery(Array.isArray(event.messages) ? event.messages : []);\n if (!query) return;\n const sessionKey = sessionKeyFromContext(ctx);\n const { state } = getSessionState(ctx, sessionStates);\n if (query === state.lastInjectedQuery) return;\n\n try {\n const recalled = await client.recall(query, sessionKey, ctx.cwd);\n const context = trimContext(recalled.context ?? \"\", config.recallBudgetChars);\n if (!context) return;\n state.lastInjectedQuery = query;\n return {\n messages: [\n {\n role: \"user\",\n content: [{ type: \"text\", text: `Remnic recalled context for this turn:\\n\\n${context}` }],\n timestamp: Date.now(),\n },\n ...event.messages,\n ],\n };\n } catch (err) {\n notify(ctx, `Remnic recall unavailable: ${errorMessage(err)}`, \"warning\");\n }\n });\n\n pi.on(\"message_end\", async (event, ctx) => {\n if (!config.observeEnabled || !isUserMessage(event.message)) return;\n const { state } = getSessionState(ctx, sessionStates);\n await observeMessages(ctx, client, [event.message], state.observedHashes, state.liveObservedReplayKeys);\n });\n\n pi.on(\"turn_end\", async (event, ctx) => {\n if (!config.observeEnabled) return;\n const messages = [event.message, ...(Array.isArray(event.toolResults) ? event.toolResults : [])];\n const { state } = getSessionState(ctx, sessionStates);\n await observeMessages(ctx, client, messages, state.observedHashes, state.liveObservedReplayKeys);\n });\n\n pi.on(\"session_shutdown\", async (_event, ctx) => {\n const { sessionKey, state } = getSessionState(ctx, sessionStates);\n if (config.observeEnabled) {\n const branch = safeBranch(ctx);\n const branchMessages = branchMessagesWithEntryIdentity(branch);\n const unobservedBranchMessages = skipLiveObservedReplayMessages(ctx, branchMessages, state.liveObservedReplayKeys);\n if (unobservedBranchMessages.length > 0) await observeMessages(ctx, client, unobservedBranchMessages, state.observedHashes);\n }\n persistObservedState(pi, state.observedHashes);\n sessionStates.delete(sessionKey);\n });\n\n pi.on(\"session_before_compact\", async (event, ctx) => {\n if (!config.compactionEnabled || !config.authToken) return;\n const sessionKey = sessionKeyFromContext(ctx);\n const preparation = event.preparation ?? {};\n try {\n await client.lcmCompactionFlush(sessionKey);\n } catch (err) {\n notify(ctx, `Remnic LCM flush failed: ${errorMessage(err)}`, \"warning\");\n return;\n }\n\n const summary = buildCompactionSummary(preparation);\n if (!summary.trim()) return;\n void client.contextCheckpoint(sessionKey, summary).catch(() => undefined);\n const tokensBefore = finiteTokenCount(preparation.tokensBefore);\n const tokensAfter = finiteTokenCount(preparation.tokensAfter);\n if (tokensBefore !== null && tokensAfter !== null) {\n void client.lcmCompactionRecord(sessionKey, tokensBefore, tokensAfter).catch(() => undefined);\n }\n const details = fileDetailsFromPreparation(preparation);\n return {\n compaction: {\n summary,\n firstKeptEntryId: preparation.firstKeptEntryId,\n tokensBefore: preparation.tokensBefore,\n details: {\n ...details,\n remnic: { version: 1, source: \"pi\" },\n },\n },\n };\n });\n\n registerCommands(pi, client, config);\n if (config.mcpToolsEnabled && config.authToken) {\n await registerMcpTools(pi, client, config);\n }\n };\n}\n\nexport default async function remnicPiExtension(pi: PiApi): Promise<void> {\n await createRemnicPiExtension()(pi);\n}\n\nfunction registerCommands(pi: PiApi, client: RemnicClient, config: RemnicPiConfig): void {\n pi.registerCommand(\"remnic-status\", {\n description: \"Check Remnic daemon status\",\n handler: commandHandler(async (_args, ctx) => {\n const health = await client.health();\n notify(ctx, `Remnic ${health.ok ? \"healthy\" : \"unhealthy\"} at ${config.remnicDaemonUrl}`, health.ok ? \"success\" : \"warning\");\n }),\n });\n\n pi.registerCommand(\"remnic-recall\", {\n description: \"Recall Remnic context for a query\",\n handler: commandHandler(async (args, ctx) => {\n const query = args.trim();\n if (!query) {\n notify(ctx, \"Usage: /remnic-recall <query>\", \"warning\");\n return;\n }\n const result = await client.recall(query, sessionKeyFromContext(ctx), ctx.cwd);\n notify(ctx, trimContext(result.context ?? \"(no Remnic context)\", MAX_CONTEXT_CHARS), \"info\");\n }),\n });\n\n pi.registerCommand(\"remnic-remember\", {\n description: \"Store a Remnic memory\",\n handler: commandHandler(async (args, ctx) => {\n const content = args.trim();\n if (!content) {\n notify(ctx, \"Usage: /remnic-remember <memory>\", \"warning\");\n return;\n }\n await client.storeMemory(content, sessionKeyFromContext(ctx));\n notify(ctx, \"Stored Remnic memory\", \"success\");\n }),\n });\n\n pi.registerCommand(\"remnic-lcm-search\", {\n description: \"Search Remnic LCM archived Pi context\",\n handler: commandHandler(async (args, ctx) => {\n const query = args.trim();\n if (!query) {\n notify(ctx, \"Usage: /remnic-lcm-search <query>\", \"warning\");\n return;\n }\n const result = await client.lcmSearch(query, sessionKeyFromContext(ctx));\n notify(ctx, JSON.stringify(result, null, 2), \"info\");\n }),\n });\n\n pi.registerCommand(\"remnic-why\", {\n description: \"Explain the last Remnic recall\",\n handler: commandHandler(async (_args, ctx) => {\n const result = await client.recallExplain(sessionKeyFromContext(ctx));\n notify(ctx, JSON.stringify(result, null, 2), \"info\");\n }),\n });\n\n pi.registerCommand(\"remnic-compact\", {\n description: \"Trigger Pi compaction with Remnic LCM coordination\",\n handler: commandHandler(async (_args, ctx) => {\n ctx.compact?.();\n notify(ctx, \"Compaction requested\", \"info\");\n }),\n });\n}\n\nfunction commandHandler(handler: (args: string, ctx: any) => Promise<void>): (args: string, ctx: any) => Promise<void> {\n return async (args, ctx) => {\n try {\n await handler(args, ctx);\n } catch (err) {\n notify(ctx, `Remnic command failed: ${errorMessage(err)}`, \"warning\");\n }\n };\n}\n\nasync function registerMcpTools(pi: PiApi, client: RemnicClient, config: RemnicPiConfig): Promise<void> {\n let tools: McpTool[] = [];\n try {\n tools = await client.mcpListTools();\n } catch {\n return;\n }\n for (const tool of tools) {\n if (!tool.name.startsWith(\"remnic.\")) continue;\n const piToolName = tool.name.replace(/^remnic\\./, \"remnic_\").replace(/[^a-zA-Z0-9_]/g, \"_\");\n pi.registerTool({\n name: piToolName,\n label: tool.name,\n description: tool.description ?? `Call ${tool.name}`,\n parameters: toPiToolParametersSchema(tool.inputSchema),\n async execute(_toolCallId: string, params: Record<string, unknown>, _signal: AbortSignal | undefined, _onUpdate: unknown, ctx: any) {\n const sessionKey = sessionKeyFromContext(ctx);\n const {\n sessionKey: _ignoredSessionKey,\n namespace: _ignoredNamespace,\n cwd: _ignoredCwd,\n ...safeParams\n } = params ?? {};\n const result = await client.mcpTool(tool.name, {\n ...safeParams,\n sessionKey,\n namespace: config.namespace,\n cwd: ctx.cwd,\n });\n return {\n content: [{ type: \"text\", text: JSON.stringify(result, null, 2) }],\n details: result,\n };\n },\n });\n }\n}\n\nexport function toPiToolParametersSchema(inputSchema: unknown): TSchema {\n return Type.Unsafe(stripSessionOwnedSchemaFields(inputSchema));\n}\n\nexport function stripSessionOwnedSchemaFields(inputSchema: unknown): Record<string, unknown> {\n if (!isRecord(inputSchema)) {\n return { type: \"object\", properties: {}, additionalProperties: true };\n }\n const schema: Record<string, unknown> = { ...inputSchema };\n const properties = isRecord(inputSchema.properties)\n ? { ...inputSchema.properties }\n : {};\n delete properties.sessionKey;\n delete properties.namespace;\n delete properties.cwd;\n schema.properties = properties;\n if (Array.isArray(inputSchema.required)) {\n schema.required = inputSchema.required.filter(\n (field) => field !== \"sessionKey\" && field !== \"namespace\" && field !== \"cwd\",\n );\n }\n return schema;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return !!value && typeof value === \"object\" && !Array.isArray(value);\n}\n\nfunction isUserMessage(message: unknown): boolean {\n return isRecord(message) && message.role === \"user\";\n}\n\nfunction getSessionState(ctx: any, states: Map<string, PiSessionState>): { sessionKey: string; state: PiSessionState } {\n const sessionKey = sessionKeyFromContext(ctx);\n let state = states.get(sessionKey);\n if (!state) {\n state = {\n observedHashes: new Set<string>(),\n liveObservedReplayKeys: new Map<string, number>(),\n lastInjectedQuery: \"\",\n };\n states.set(sessionKey, state);\n pruneSessionStates(states);\n }\n return { sessionKey, state };\n}\n\nfunction pruneSessionStates(states: Map<string, PiSessionState>): void {\n while (states.size > MAX_SESSION_STATES) {\n const oldest = states.keys().next().value;\n if (typeof oldest !== \"string\") return;\n states.delete(oldest);\n }\n}\n\nexport async function observeMessages(\n ctx: any,\n client: RemnicClient,\n rawMessages: unknown[],\n observedHashes: Set<string>,\n liveObservedReplayKeys?: Map<string, number>,\n): Promise<void> {\n const sessionKey = sessionKeyFromContext(ctx);\n const messages: ObserveMessage[] = [];\n const pendingHashes = new Set<string>();\n for (const raw of rawMessages) {\n const message = toObserveMessage(raw);\n if (!message) continue;\n const hash = observedMessageDedupeKey(message, sessionKey);\n if (hash && (observedHashes.has(hash) || pendingHashes.has(hash))) continue;\n if (hash) pendingHashes.add(hash);\n messages.push(message);\n }\n if (messages.length === 0) return;\n try {\n await client.observe(sessionKey, ctx.cwd, messages);\n for (const hash of pendingHashes) rememberObservedHash(observedHashes, hash);\n if (liveObservedReplayKeys) {\n for (const message of messages) {\n rememberLiveObservedReplayKey(liveObservedReplayKeys, liveReplayKey(message, sessionKey));\n }\n }\n } catch (err) {\n notify(ctx, `Remnic observe failed: ${errorMessage(err)}`, \"warning\");\n }\n}\n\nexport function buildCompactionSummary(preparation: any): string {\n const previousSummary = typeof preparation.previousSummary === \"string\"\n ? preparation.previousSummary.trim()\n : \"\";\n const messages = [\n ...(Array.isArray(preparation.messagesToSummarize) ? preparation.messagesToSummarize : []),\n ...(Array.isArray(preparation.turnPrefixMessages) ? preparation.turnPrefixMessages : []),\n ];\n const transcript = summarizeMessages(messages, 24000);\n const details = fileDetailsFromPreparation(preparation);\n\n if (\n !previousSummary &&\n !transcript &&\n details.readFiles.length === 0 &&\n details.modifiedFiles.length === 0\n ) {\n return \"\";\n }\n\n const sections: string[] = [\n \"## Remnic Pi Context Checkpoint\",\n \"\",\n \"This checkpoint was created by Remnic during Pi context compaction.\",\n ];\n if (previousSummary) sections.push(\"\", \"## Previous Summary\", previousSummary);\n if (transcript) sections.push(\"\", \"## Conversation Excerpt\", transcript);\n if (details.readFiles.length > 0) sections.push(\"\", \"<read-files>\", ...details.readFiles, \"</read-files>\");\n if (details.modifiedFiles.length > 0) sections.push(\"\", \"<modified-files>\", ...details.modifiedFiles, \"</modified-files>\");\n return sections.join(\"\\n\");\n}\n\nfunction fileDetailsFromPreparation(preparation: any): { readFiles: string[]; modifiedFiles: string[] } {\n const fileOps = preparation?.fileOps;\n const read = fileOps?.read instanceof Set ? Array.from(fileOps.read).filter(isString) : [];\n const edited = fileOps?.edited instanceof Set ? Array.from(fileOps.edited).filter(isString) : [];\n const written = fileOps?.written instanceof Set ? Array.from(fileOps.written).filter(isString) : [];\n const modified = new Set([...edited, ...written]);\n return {\n readFiles: read.filter((file) => !modified.has(file)).sort(),\n modifiedFiles: Array.from(modified).sort(),\n };\n}\n\nfunction restoreObservedState(ctx: any, observedHashes: Set<string>): void {\n for (const entry of safeEntries(ctx)) {\n if (entry?.type !== \"custom\" || entry.customType !== STATE_CUSTOM_TYPE) continue;\n const hashes = entry.data?.observedHashes;\n if (Array.isArray(hashes)) {\n for (const hash of hashes) {\n if (typeof hash === \"string\") rememberObservedHash(observedHashes, hash);\n }\n }\n }\n}\n\nfunction rememberObservedHash(observedHashes: Set<string>, hash: string): void {\n if (observedHashes.has(hash)) return;\n while (observedHashes.size >= MAX_OBSERVED_HASHES) {\n const oldest = observedHashes.keys().next().value;\n if (typeof oldest !== \"string\") break;\n observedHashes.delete(oldest);\n }\n observedHashes.add(hash);\n}\n\nfunction rememberLiveObservedReplayKey(liveObservedReplayKeys: Map<string, number>, key: string): void {\n liveObservedReplayKeys.set(key, (liveObservedReplayKeys.get(key) ?? 0) + 1);\n}\n\nfunction consumeLiveObservedReplayKey(liveObservedReplayKeys: Map<string, number>, key: string): boolean {\n const count = liveObservedReplayKeys.get(key) ?? 0;\n if (count <= 0) return false;\n if (count === 1) liveObservedReplayKeys.delete(key);\n else liveObservedReplayKeys.set(key, count - 1);\n return true;\n}\n\nfunction skipLiveObservedReplayMessages(\n ctx: any,\n rawMessages: unknown[],\n liveObservedReplayKeys: Map<string, number>,\n): unknown[] {\n if (liveObservedReplayKeys.size === 0) return rawMessages;\n const sessionKey = sessionKeyFromContext(ctx);\n const unobserved: unknown[] = [];\n for (const raw of rawMessages) {\n const message = toObserveMessage(raw);\n if (message && consumeLiveObservedReplayKey(liveObservedReplayKeys, liveReplayKey(message, sessionKey))) {\n continue;\n }\n unobserved.push(raw);\n }\n return unobserved;\n}\n\nfunction liveReplayKey(message: ObserveMessage, sessionKey: string): string {\n return hashObservedMessage(message, sessionKey, \"live-replay\");\n}\n\nfunction persistObservedState(pi: PiApi, observedHashes: Set<string>): void {\n const observed = Array.from(observedHashes).slice(-MAX_OBSERVED_HASHES);\n pi.appendEntry(STATE_CUSTOM_TYPE, {\n observedHashes: observed,\n recordedAt: new Date().toISOString(),\n });\n}\n\nasync function setStatus(ctx: any, client: RemnicClient, config: RemnicPiConfig): Promise<void> {\n try {\n await client.health();\n ctx.ui?.setStatus?.(\"remnic\", `Remnic ${config.namespace ? `(${config.namespace})` : \"ready\"}`);\n } catch {\n ctx.ui?.setStatus?.(\"remnic\", \"Remnic offline\");\n }\n}\n\nfunction safeEntries(ctx: any): any[] {\n try {\n const entries = ctx.sessionManager?.getEntries?.();\n return Array.isArray(entries) ? entries : [];\n } catch {\n return [];\n }\n}\n\nfunction safeBranch(ctx: any): any[] {\n try {\n const branch = ctx.sessionManager?.getBranch?.();\n return Array.isArray(branch) ? branch : [];\n } catch {\n return [];\n }\n}\n\nfunction branchMessagesWithEntryIdentity(branch: any[]): unknown[] {\n const messages: unknown[] = [];\n for (const entry of branch) {\n const message = messageWithEntryIdentity(entry);\n if (message) messages.push(message);\n }\n return messages;\n}\n\nfunction messageWithEntryIdentity(entry: any): unknown | null {\n const message = entry?.message;\n if (!message || typeof message !== \"object\" || Array.isArray(message)) return message ?? null;\n\n const source = isRecord(entry) ? entry : {};\n const enriched: Record<string, unknown> = { ...(message as Record<string, unknown>) };\n assignMissingIdentity(enriched, \"entryId\", source.id ?? source.entryId ?? source.entry_id);\n assignMissingIdentity(enriched, \"timestamp\", source.timestamp);\n assignMissingIdentity(enriched, \"createdAt\", source.createdAt ?? source.created_at);\n return enriched;\n}\n\nfunction assignMissingIdentity(target: Record<string, unknown>, field: string, value: unknown): void {\n if (target[field] !== undefined) return;\n if (typeof value === \"string\" && value.length > 0) {\n target[field] = value;\n return;\n }\n if (typeof value === \"number\" && Number.isFinite(value)) {\n target[field] = value;\n }\n}\n\nfunction trimContext(value: string, budget: number): string {\n if (value.length <= budget) return value;\n if (budget <= TRUNCATION_NOTICE.length) return TRUNCATION_NOTICE.slice(0, budget);\n return `${value.slice(0, budget - TRUNCATION_NOTICE.length)}${TRUNCATION_NOTICE}`;\n}\n\nfunction notify(ctx: any, message: string, level: \"info\" | \"success\" | \"warning\" | \"error\"): void {\n if (ctx?.hasUI === false) return;\n ctx?.ui?.notify?.(message, level);\n}\n\nfunction errorMessage(err: unknown): string {\n return err instanceof Error ? err.message : String(err);\n}\n\nfunction finiteTokenCount(value: unknown): number | null {\n return typeof value === \"number\" && Number.isFinite(value) && value >= 0 ? value : null;\n}\n\nfunction isString(value: unknown): value is string {\n return typeof value === \"string\";\n}\n\nexport { textFromMessage };\n","import { existsSync, readFileSync } from \"node:fs\";\nimport path from \"node:path\";\n\nimport { expandTildePath } from \"@remnic/core\";\n\nimport { REMNIC_PI_EXTENSION_DIR_NAME, resolvePiAgentHome } from \"./paths.js\";\n\nexport interface RemnicPiConfig {\n remnicDaemonUrl: string;\n authToken?: string;\n namespace?: string;\n recallMode: \"auto\" | \"minimal\" | \"full\" | \"graph_mode\" | \"no_recall\";\n recallTopK: number;\n recallBudgetChars: number;\n recallEnabled: boolean;\n observeEnabled: boolean;\n observeSkipExtraction: boolean;\n compactionEnabled: boolean;\n mcpToolsEnabled: boolean;\n statusEnabled: boolean;\n requestTimeoutMs: number;\n}\n\nexport interface LoadConfigOptions {\n configPath?: string;\n env?: NodeJS.ProcessEnv;\n}\n\nconst DEFAULT_CONFIG: RemnicPiConfig = {\n remnicDaemonUrl: \"http://127.0.0.1:4318\",\n recallMode: \"auto\",\n recallTopK: 8,\n recallBudgetChars: 12000,\n recallEnabled: true,\n observeEnabled: true,\n observeSkipExtraction: false,\n compactionEnabled: true,\n mcpToolsEnabled: true,\n statusEnabled: true,\n requestTimeoutMs: 60000,\n};\n\nfunction defaultConfigPath(env: NodeJS.ProcessEnv): string {\n return path.join(resolvePiAgentHome(env), \"extensions\", REMNIC_PI_EXTENSION_DIR_NAME, \"remnic.config.json\");\n}\n\nfunction coerceBoolean(value: unknown, fallback: boolean, fieldName: string): boolean {\n if (value === undefined || value === null) return fallback;\n if (typeof value === \"boolean\") return value;\n if (typeof value === \"string\") {\n const normalized = value.trim().toLowerCase();\n if ([\"true\", \"1\", \"yes\", \"on\"].includes(normalized)) return true;\n if ([\"false\", \"0\", \"no\", \"off\"].includes(normalized)) return false;\n }\n throw new Error(`Invalid boolean value for Remnic Pi config field ${fieldName}`);\n}\n\nfunction coercePositiveInt(value: unknown, fallback: number, max: number, fieldName: string): number {\n if (value === undefined || value === null || value === \"\") return fallback;\n let parsed: number;\n if (typeof value === \"number\") {\n parsed = value;\n } else if (typeof value === \"string\") {\n const trimmed = value.trim();\n if (trimmed.length === 0) return fallback;\n if (!/^[+-]?\\d+$/.test(trimmed)) {\n throw new Error(`Invalid numeric value for Remnic Pi config field ${fieldName}: expected an integer from 1 to ${max}`);\n }\n parsed = Number(trimmed);\n } else {\n throw new Error(`Invalid numeric value for Remnic Pi config field ${fieldName}: expected an integer from 1 to ${max}`);\n }\n if (!Number.isInteger(parsed) || parsed <= 0 || parsed > max) {\n throw new Error(`Invalid numeric value for Remnic Pi config field ${fieldName}: expected an integer from 1 to ${max}`);\n }\n return parsed;\n}\n\nfunction coerceOptionalNonEmptyString(value: unknown, fieldName: string): string | undefined {\n if (value === undefined || value === null) return undefined;\n if (typeof value === \"string\" && value.trim().length > 0) return value.trim();\n throw new Error(`Invalid string value for Remnic Pi config field ${fieldName}`);\n}\n\nfunction coerceOptionalString(value: unknown, fieldName: string): string | undefined {\n if (value === undefined || value === null) return undefined;\n if (typeof value === \"string\") {\n const trimmed = value.trim();\n return trimmed.length > 0 ? trimmed : undefined;\n }\n throw new Error(`Invalid string value for Remnic Pi config field ${fieldName}`);\n}\n\nfunction coerceOptionalHttpUrl(value: unknown, fieldName: string): string | undefined {\n if (value === undefined || value === null) return undefined;\n if (typeof value !== \"string\") {\n throw new Error(`Invalid URL value for Remnic Pi config field ${fieldName}: expected an http or https URL`);\n }\n const trimmed = value.trim();\n if (trimmed.length === 0) return undefined;\n try {\n const parsed = new URL(trimmed);\n if (parsed.protocol === \"http:\" || parsed.protocol === \"https:\") return trimTrailingSlashes(trimmed);\n } catch {\n // Fall through to the shared error below.\n }\n throw new Error(`Invalid URL value for Remnic Pi config field ${fieldName}: expected an http or https URL`);\n}\n\nfunction coerceRecallMode(value: unknown): RemnicPiConfig[\"recallMode\"] {\n if (value === undefined || value === null || value === \"\") return DEFAULT_CONFIG.recallMode;\n if (\n value === \"minimal\" ||\n value === \"full\" ||\n value === \"graph_mode\" ||\n value === \"no_recall\" ||\n value === \"auto\"\n ) {\n return value;\n }\n throw new Error(`Invalid recallMode value for Remnic Pi config: ${JSON.stringify(value)}`);\n}\n\nfunction readConfigFile(configPath: string): Record<string, unknown> {\n if (!existsSync(configPath)) return {};\n try {\n const raw = readFileSync(configPath, \"utf-8\");\n const parsed = JSON.parse(raw);\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n throw new Error(\"expected a JSON object\");\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n throw new Error(`Failed to load Remnic Pi config at ${configPath}: ${reason}`);\n }\n}\n\nfunction trimTrailingSlashes(value: string): string {\n let end = value.length;\n while (end > 0 && value.charCodeAt(end - 1) === 47) end -= 1;\n return value.slice(0, end);\n}\n\nexport function resolveConfigPath(options: LoadConfigOptions = {}): string {\n const env = options.env ?? process.env;\n return expandTildePath(options.configPath || env.REMNIC_PI_CONFIG || defaultConfigPath(env));\n}\n\nexport function loadConfig(options: LoadConfigOptions = {}): RemnicPiConfig {\n const env = options.env ?? process.env;\n const fileConfig = readConfigFile(resolveConfigPath(options));\n const daemonUrl =\n coerceOptionalHttpUrl(fileConfig.remnicDaemonUrl, \"remnicDaemonUrl\") ??\n coerceOptionalHttpUrl(env.REMNIC_DAEMON_URL, \"REMNIC_DAEMON_URL\") ??\n DEFAULT_CONFIG.remnicDaemonUrl;\n const authToken =\n coerceOptionalString(fileConfig.authToken, \"authToken\") ??\n coerceOptionalString(env.REMNIC_PI_AUTH_TOKEN, \"REMNIC_PI_AUTH_TOKEN\");\n const namespace = coerceOptionalNonEmptyString(fileConfig.namespace, \"namespace\");\n\n return {\n remnicDaemonUrl: daemonUrl,\n authToken,\n namespace,\n recallMode: coerceRecallMode(fileConfig.recallMode),\n recallTopK: coercePositiveInt(fileConfig.recallTopK, DEFAULT_CONFIG.recallTopK, 50, \"recallTopK\"),\n recallBudgetChars: coercePositiveInt(fileConfig.recallBudgetChars, DEFAULT_CONFIG.recallBudgetChars, 64000, \"recallBudgetChars\"),\n recallEnabled: coerceBoolean(fileConfig.recallEnabled, DEFAULT_CONFIG.recallEnabled, \"recallEnabled\"),\n observeEnabled: coerceBoolean(fileConfig.observeEnabled, DEFAULT_CONFIG.observeEnabled, \"observeEnabled\"),\n observeSkipExtraction: coerceBoolean(fileConfig.observeSkipExtraction, DEFAULT_CONFIG.observeSkipExtraction, \"observeSkipExtraction\"),\n compactionEnabled: coerceBoolean(fileConfig.compactionEnabled, DEFAULT_CONFIG.compactionEnabled, \"compactionEnabled\"),\n mcpToolsEnabled: coerceBoolean(fileConfig.mcpToolsEnabled, DEFAULT_CONFIG.mcpToolsEnabled, \"mcpToolsEnabled\"),\n statusEnabled: coerceBoolean(fileConfig.statusEnabled, DEFAULT_CONFIG.statusEnabled, \"statusEnabled\"),\n requestTimeoutMs: coercePositiveInt(fileConfig.requestTimeoutMs, DEFAULT_CONFIG.requestTimeoutMs, 60_000, \"requestTimeoutMs\"),\n };\n}\n","import type { RemnicPiConfig } from \"./config.js\";\n\nexport interface RecallResponse {\n context?: string;\n results?: Array<{ id?: string; content?: string; score?: number; category?: string }>;\n count?: number;\n}\n\nexport interface ObserveMessagePart {\n ordinal?: number;\n kind: \"text\" | \"tool_call\" | \"tool_result\" | \"patch\" | \"file_read\" | \"file_write\" | \"step_start\" | \"step_finish\" | \"snapshot\" | \"retry\";\n payload: Record<string, unknown>;\n toolName?: string | null;\n filePath?: string | null;\n createdAt?: string | null;\n}\n\nexport interface ObserveMessage {\n role: \"user\" | \"assistant\";\n content: string;\n sourceFormat?: \"pi\";\n rawContent?: unknown;\n parts?: ObserveMessagePart[];\n}\n\nexport interface McpTool {\n name: string;\n description?: string;\n inputSchema?: Record<string, unknown>;\n}\n\nexport class RemnicHttpError extends Error {\n constructor(\n readonly status: number,\n message: string,\n ) {\n super(message);\n }\n}\n\nexport class RemnicClient {\n private requestId = 0;\n\n constructor(private readonly config: RemnicPiConfig) {}\n\n async health(): Promise<Record<string, unknown>> {\n return this.request(\"GET\", \"/engram/v1/health\");\n }\n\n async recall(query: string, sessionKey: string, cwd: string): Promise<RecallResponse> {\n return this.request(\"POST\", \"/engram/v1/recall\", {\n query,\n sessionKey,\n cwd,\n namespace: this.config.namespace,\n topK: this.config.recallTopK,\n mode: this.config.recallMode,\n });\n }\n\n async recallExplain(sessionKey: string): Promise<Record<string, unknown>> {\n return this.request(\"POST\", \"/engram/v1/recall/explain\", {\n sessionKey,\n namespace: this.config.namespace,\n });\n }\n\n async observe(sessionKey: string, cwd: string, messages: ObserveMessage[]): Promise<Record<string, unknown>> {\n return this.request(\"POST\", \"/engram/v1/observe\", {\n sessionKey,\n cwd,\n namespace: this.config.namespace,\n skipExtraction: this.config.observeSkipExtraction,\n messages,\n });\n }\n\n async storeMemory(content: string, sessionKey: string): Promise<Record<string, unknown>> {\n return this.request(\"POST\", \"/engram/v1/memories\", {\n content,\n category: \"fact\",\n sourceReason: \"Captured from Pi via Remnic extension\",\n sessionKey,\n namespace: this.config.namespace,\n });\n }\n\n async lcmSearch(query: string, sessionKey: string, limit = 10): Promise<Record<string, unknown>> {\n return this.request(\"POST\", \"/engram/v1/lcm/search\", {\n query,\n sessionKey,\n namespace: this.config.namespace,\n limit,\n });\n }\n\n async lcmCompactionFlush(sessionKey: string): Promise<Record<string, unknown>> {\n return this.request(\"POST\", \"/engram/v1/lcm/compaction/flush\", {\n sessionKey,\n namespace: this.config.namespace,\n });\n }\n\n async lcmCompactionRecord(sessionKey: string, tokensBefore: number, tokensAfter: number): Promise<Record<string, unknown>> {\n return this.request(\"POST\", \"/engram/v1/lcm/compaction/record\", {\n sessionKey,\n namespace: this.config.namespace,\n tokensBefore,\n tokensAfter,\n });\n }\n\n async contextCheckpoint(sessionKey: string, context: string): Promise<Record<string, unknown>> {\n return this.mcpTool(\"remnic.context_checkpoint\", {\n sessionKey,\n context,\n namespace: this.config.namespace,\n });\n }\n\n async mcpListTools(): Promise<McpTool[]> {\n const result = await this.mcpRequest(\"tools/list\", {});\n const tools = (result as { tools?: unknown }).tools;\n return Array.isArray(tools) ? tools.filter(isMcpTool) : [];\n }\n\n async mcpTool(name: string, args: Record<string, unknown>): Promise<Record<string, unknown>> {\n return this.mcpRequest(\"tools/call\", {\n name,\n arguments: args,\n });\n }\n\n private async request<T = Record<string, unknown>>(method: string, pathname: string, body?: unknown): Promise<T> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.config.requestTimeoutMs);\n try {\n const response = await fetch(`${this.config.remnicDaemonUrl}${pathname}`, {\n method,\n headers: {\n ...(body === undefined ? {} : { \"Content-Type\": \"application/json\" }),\n ...(this.config.authToken ? { Authorization: `Bearer ${this.config.authToken}` } : {}),\n \"X-Engram-Client-Id\": \"pi\",\n },\n body: body === undefined ? undefined : JSON.stringify(body),\n signal: controller.signal,\n });\n const text = await response.text();\n const payload = text ? JSON.parse(text) : {};\n if (!response.ok) {\n throw new RemnicHttpError(response.status, typeof payload?.error === \"string\" ? payload.error : response.statusText);\n }\n return payload as T;\n } catch (err) {\n if (isAbortError(err)) {\n throw new Error(`Remnic request timed out after ${this.config.requestTimeoutMs}ms`);\n }\n throw err;\n } finally {\n clearTimeout(timeout);\n }\n }\n\n private async mcpRequest(method: string, params: Record<string, unknown>): Promise<Record<string, unknown>> {\n this.requestId += 1;\n const payload = await this.request<Record<string, unknown>>(\"POST\", \"/mcp\", {\n jsonrpc: \"2.0\",\n id: this.requestId,\n method,\n params,\n });\n if (payload.error) {\n throw new Error(JSON.stringify(payload.error));\n }\n return (payload.result && typeof payload.result === \"object\" ? payload.result : payload) as Record<string, unknown>;\n }\n}\n\nfunction isMcpTool(value: unknown): value is McpTool {\n return !!value && typeof value === \"object\" && typeof (value as { name?: unknown }).name === \"string\";\n}\n\nfunction isAbortError(err: unknown): boolean {\n return err instanceof Error && (err.name === \"AbortError\" || err.message === \"This operation was aborted\");\n}\n","import { createHash } from \"node:crypto\";\n\nimport { parsePiMessageParts, type LcmMessagePartInput } from \"@remnic/core\";\n\nimport type { ObserveMessage, ObserveMessagePart } from \"./client.js\";\n\ntype PiMessage = Record<string, unknown>;\n\nexport function sessionKeyFromContext(ctx: { sessionManager?: { getSessionId?: () => string } }): string {\n const id = ctx.sessionManager?.getSessionId?.();\n return id && id.trim().length > 0 ? `pi:${id}` : \"pi:default\";\n}\n\nexport function textFromMessage(message: unknown): string {\n if (!message || typeof message !== \"object\") return \"\";\n const obj = message as PiMessage;\n const role = typeof obj.role === \"string\" ? obj.role : \"message\";\n if (role === \"bashExecution\") {\n const command = typeof obj.command === \"string\" ? obj.command : \"\";\n const output = typeof obj.output === \"string\" ? obj.output : \"\";\n return [`Ran ${command}`, output].filter(Boolean).join(\"\\n\");\n }\n return textFromContent(obj.content).trim();\n}\n\nexport function latestUserQuery(messages: unknown[]): string {\n for (let index = messages.length - 1; index >= 0; index--) {\n const message = messages[index] as PiMessage;\n if (isExcludedFromContext(message)) continue;\n if (message?.role === \"user\") {\n const text = textFromMessage(message);\n if (text.length > 0) return text;\n }\n }\n return \"\";\n}\n\nexport function toObserveMessage(message: unknown): ObserveMessage | null {\n if (!message || typeof message !== \"object\") return null;\n const obj = message as PiMessage;\n if (isExcludedFromContext(obj)) return null;\n const role = obj.role === \"user\" || obj.role === \"bashExecution\" ? \"user\" : \"assistant\";\n const content = textFromMessage(obj);\n if (content.length === 0) return null;\n return {\n role,\n content,\n sourceFormat: \"pi\",\n rawContent: obj,\n parts: partsFromMessage(obj, content),\n };\n}\n\nexport function hashObservedMessage(message: ObserveMessage, sessionKey = \"\", identity = \"content\"): string {\n return createHash(\"sha256\")\n .update(sessionKey)\n .update(\"\\0\")\n .update(message.role)\n .update(\"\\0\")\n .update(identity)\n .update(\"\\0\")\n .update(message.content)\n .digest(\"hex\");\n}\n\nexport function observedMessageDedupeKey(\n message: ObserveMessage,\n sessionKey = \"\",\n): string | null {\n const identity = stableObservedMessageIdentity(message.rawContent);\n return identity ? hashObservedMessage(message, sessionKey, identity) : null;\n}\n\nexport function summarizeMessages(messages: unknown[], maxChars: number): string {\n const chunks: string[] = [];\n let used = 0;\n for (const message of messages) {\n if (isExcludedFromContext(message)) continue;\n const text = textFromMessage(message);\n if (!text) continue;\n const role = typeof (message as PiMessage)?.role === \"string\" ? (message as PiMessage).role : \"message\";\n const line = `[${role}] ${text}`;\n const separatorLength = chunks.length > 0 ? 2 : 0;\n const remaining = maxChars - used - separatorLength;\n if (remaining <= 0) break;\n const clipped = line.length > remaining ? line.slice(0, remaining) : line;\n if (clipped.length > 0) chunks.push(clipped);\n used += separatorLength + clipped.length;\n if (used >= maxChars) break;\n }\n return chunks.join(\"\\n\\n\");\n}\n\nexport function isExcludedFromContext(message: unknown): boolean {\n return !!message && typeof message === \"object\" && (message as PiMessage).excludeFromContext === true;\n}\n\nfunction textFromContent(content: unknown): string {\n if (typeof content === \"string\") return content;\n if (!Array.isArray(content)) return \"\";\n const chunks: string[] = [];\n for (const block of content) {\n if (!block || typeof block !== \"object\") continue;\n const obj = block as PiMessage;\n if (obj.type === \"text\" && typeof obj.text === \"string\") chunks.push(obj.text);\n if (obj.type === \"toolCall\" && typeof obj.name === \"string\") {\n chunks.push(`Tool ${obj.name} called with ${JSON.stringify(obj.arguments ?? {})}`);\n }\n }\n return chunks.join(\"\\n\");\n}\n\nfunction partsFromMessage(message: PiMessage, renderedContent: string): ObserveMessagePart[] {\n return parsePiMessageParts(message, {\n renderedContent,\n allowRenderedFallback: true,\n }).map(toObserveMessagePart);\n}\n\nfunction toObserveMessagePart(part: LcmMessagePartInput): ObserveMessagePart {\n return {\n ordinal: part.ordinal ?? undefined,\n kind: part.kind,\n payload: part.payload,\n toolName: part.toolName ?? part.tool_name ?? undefined,\n filePath: part.filePath ?? part.file_path ?? undefined,\n createdAt: part.createdAt ?? part.created_at ?? undefined,\n };\n}\n\nfunction stableObservedMessageIdentity(rawContent: unknown): string | null {\n if (rawContent && typeof rawContent === \"object\") {\n const obj = rawContent as PiMessage;\n const fields = [\n \"id\",\n \"entryId\",\n \"entry_id\",\n \"messageId\",\n \"message_id\",\n \"turnId\",\n \"turn_id\",\n \"timestamp\",\n \"createdAt\",\n \"created_at\",\n ];\n for (const field of fields) {\n const value = obj[field];\n if (typeof value === \"string\" && value.length > 0) return `${field}:${value}`;\n if (typeof value === \"number\" && Number.isFinite(value)) return `${field}:${value}`;\n }\n }\n return null;\n}\n"],"mappings":"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","names":["remnicPiExtension"]}
|
package/dist/publisher.js
CHANGED
package/dist/publisher.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/publisher.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\n\nimport {\n getConnectorToken,\n loadTokenStore,\n saveTokenStore,\n type MemoryExtensionPublisher,\n type PublishContext,\n type PublishResult,\n type PublisherCapabilities,\n type TokenEntry,\n} from \"@remnic/core\";\n\nimport { resolvePiExtensionRoot } from \"./paths.js\";\n\nconst DEFAULT_DAEMON_PORT = 4318;\n\ntype FileSnapshot = {\n path: string;\n existed: boolean;\n content?: Buffer;\n mode?: number;\n};\n\nexport class PiMemoryExtensionPublisher implements MemoryExtensionPublisher {\n readonly hostId = \"pi\";\n\n static readonly capabilities: PublisherCapabilities = {\n instructionsMd: false,\n skillsFolder: false,\n citationFormat: false,\n readPathTemplate: false,\n };\n\n async resolveExtensionRoot(env?: NodeJS.ProcessEnv): Promise<string> {\n return resolvePiExtensionRoot(env ?? process.env);\n }\n\n async isHostAvailable(): Promise<boolean> {\n // Pi auto-discovers extensions from ~/.pi/agent/extensions. The directory can\n // be created before Pi has been launched, so availability should not block\n // first-time installation.\n return true;\n }\n\n async renderInstructions(ctx: PublishContext): Promise<string> {\n const namespace = ctx.config.namespace ?? \"default\";\n const daemonUrl = resolveDaemonUrl(ctx);\n return [\n \"# Remnic for Pi\",\n \"\",\n \"Remnic provides memory, retrieval, observation, MCP tools, and long-context compaction coordination for Pi Coding Agent.\",\n \"\",\n \"## Installed Capabilities\",\n \"\",\n \"- Recall relevant Remnic context in Pi's `context` hook before agent turns.\",\n \"- Observe Pi user, assistant, and tool messages with `sourceFormat: \\\"pi\\\"`.\",\n \"- Coordinate Pi `session_before_compact` with Remnic LCM flush and checkpoint recording.\",\n \"- Register Remnic MCP tools as Pi tools when daemon authentication is configured.\",\n \"- Persist lightweight dedupe state in Pi custom entries via `appendEntry`.\",\n \"\",\n \"## Runtime\",\n \"\",\n `- Remnic daemon: \\`${daemonUrl}\\``,\n `- Namespace: \\`${namespace}\\``,\n `- Memory directory: \\`${ctx.config.memoryDir}\\``,\n \"\",\n \"The private `remnic.config.json` file stores the daemon URL, namespace, and connector auth token with owner-only permissions.\",\n ].join(\"\\n\");\n }\n\n async publish(ctx: PublishContext): Promise<PublishResult> {\n const extensionRoot = await this.resolveExtensionRoot();\n const filesWritten: string[] = [];\n const skipped: string[] = [];\n\n ctx.log.info(`Publishing Pi memory extension to ${extensionRoot}`);\n\n const configPath = path.join(extensionRoot, \"remnic.config.json\");\n const wrapperPath = path.join(extensionRoot, \"index.ts\");\n const readmePath = path.join(extensionRoot, \"README.md\");\n const rootExisted = fs.existsSync(extensionRoot);\n const snapshots = snapshotFiles([configPath, wrapperPath, readmePath]);\n const priorConfig = readPriorConfig(configPath);\n const priorTokenEntry =\n ctx.rollbackTokenEntry === undefined ? snapshotPiTokenEntry() : cloneTokenEntry(ctx.rollbackTokenEntry);\n\n const token = getConnectorToken(\"pi\");\n if (!token) {\n skipped.push(\"auth token unavailable; run `remnic token generate pi` and reinstall the connector\");\n }\n\n const config: Record<string, unknown> = {\n recallMode: \"auto\",\n recallTopK: 8,\n recallBudgetChars: 12000,\n recallEnabled: true,\n observeEnabled: true,\n observeSkipExtraction: false,\n compactionEnabled: true,\n mcpToolsEnabled: true,\n statusEnabled: true,\n requestTimeoutMs: 5000,\n ...priorConfig,\n remnicDaemonUrl: resolveDaemonUrl(ctx),\n };\n if (token) {\n config.authToken = token;\n }\n if (ctx.config.namespace) {\n config.namespace = ctx.config.namespace;\n }\n\n try {\n fs.mkdirSync(extensionRoot, { recursive: true });\n\n atomicWriteFile(configPath, `${JSON.stringify(config, null, 2)}\\n`, 0o600);\n filesWritten.push(configPath);\n\n atomicWriteFile(wrapperPath, renderWrapper(resolveExtensionModulePath(), configPath), 0o644);\n filesWritten.push(wrapperPath);\n\n atomicWriteFile(readmePath, `${await this.renderInstructions(ctx)}\\n`, 0o644);\n filesWritten.push(readmePath);\n } catch (err) {\n try {\n restorePublishSnapshot(extensionRoot, rootExisted, snapshots);\n } catch (restoreErr) {\n ctx.log.warn(`Pi extension rollback failed: ${restoreErr instanceof Error ? restoreErr.message : String(restoreErr)}`);\n }\n try {\n restorePiTokenEntry(priorTokenEntry);\n } catch (tokenErr) {\n ctx.log.warn(`Pi connector token rollback failed: ${tokenErr instanceof Error ? tokenErr.message : String(tokenErr)}`);\n }\n throw err;\n }\n\n return {\n hostId: this.hostId,\n extensionRoot,\n filesWritten,\n skipped,\n };\n }\n\n async unpublish(): Promise<void> {\n const extensionRoot = await this.resolveExtensionRoot();\n if (fs.existsSync(extensionRoot)) {\n fs.rmSync(extensionRoot, { recursive: true, force: true });\n }\n }\n}\n\nfunction resolveDaemonUrl(ctx: PublishContext): string {\n if (ctx.config.daemonUrl && ctx.config.daemonUrl.trim().length > 0) {\n return trimTrailingSlashes(ctx.config.daemonUrl.trim());\n }\n return `http://127.0.0.1:${ctx.config.daemonPort ?? DEFAULT_DAEMON_PORT}`;\n}\n\nfunction trimTrailingSlashes(value: string): string {\n let end = value.length;\n while (end > 0 && value.charCodeAt(end - 1) === 47) end -= 1;\n return value.slice(0, end);\n}\n\nfunction resolveExtensionModulePath(): string {\n const moduleDir = path.dirname(fileURLToPath(import.meta.url));\n const built = path.join(moduleDir, \"index.js\");\n if (fs.existsSync(built)) return built;\n\n const source = path.join(moduleDir, \"index.ts\");\n if (fs.existsSync(source)) return source;\n\n return built;\n}\n\nfunction renderWrapper(extensionModulePath: string, configPath: string): string {\n const moduleUrl = pathToFileURL(extensionModulePath).href;\n return [\n `import { createRemnicPiExtension } from ${JSON.stringify(moduleUrl)};`,\n \"\",\n `export default createRemnicPiExtension({ configPath: ${JSON.stringify(configPath)} });`,\n \"\",\n ].join(\"\\n\");\n}\n\nfunction atomicWriteFile(filePath: string, content: string, mode: number): void {\n const tmpPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;\n try {\n fs.writeFileSync(tmpPath, content, { encoding: \"utf-8\", mode });\n fs.renameSync(tmpPath, filePath);\n try {\n fs.chmodSync(filePath, mode);\n } catch {\n // Best effort for platforms that do not support chmod.\n }\n } catch (err) {\n try {\n if (fs.existsSync(tmpPath)) fs.unlinkSync(tmpPath);\n } catch {\n // Best-effort cleanup only.\n }\n throw err;\n }\n}\n\nfunction snapshotFiles(paths: string[]): FileSnapshot[] {\n return paths.map((filePath) => {\n if (!fs.existsSync(filePath)) return { path: filePath, existed: false };\n const stat = fs.statSync(filePath);\n if (!stat.isFile()) return { path: filePath, existed: false };\n return {\n path: filePath,\n existed: true,\n content: fs.readFileSync(filePath),\n mode: stat.mode & 0o777,\n };\n });\n}\n\nfunction restorePublishSnapshot(extensionRoot: string, rootExisted: boolean, snapshots: FileSnapshot[]): void {\n if (!rootExisted) {\n fs.rmSync(extensionRoot, { recursive: true, force: true });\n return;\n }\n\n for (const snapshot of snapshots) {\n if (!snapshot.existed) {\n fs.rmSync(snapshot.path, { force: true });\n continue;\n }\n fs.mkdirSync(path.dirname(snapshot.path), { recursive: true });\n fs.writeFileSync(snapshot.path, snapshot.content ?? Buffer.alloc(0), { mode: snapshot.mode });\n if (snapshot.mode !== undefined) {\n try {\n fs.chmodSync(snapshot.path, snapshot.mode);\n } catch {\n // Best effort for platforms that do not support chmod.\n }\n }\n }\n}\n\nfunction readPriorConfig(configPath: string): Record<string, unknown> {\n if (!fs.existsSync(configPath)) return {};\n try {\n const parsed = JSON.parse(fs.readFileSync(configPath, \"utf8\"));\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n throw new Error(\"expected a JSON object\");\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n throw new Error(`Failed to load existing Remnic Pi config at ${configPath}: ${reason}`);\n }\n}\n\nfunction snapshotPiTokenEntry(): TokenEntry | null {\n const entry = loadTokenStore().tokens.find((candidate) => candidate.connector === \"pi\");\n return cloneTokenEntry(entry ?? null);\n}\n\nfunction cloneTokenEntry(entry: TokenEntry | null): TokenEntry | null {\n return entry ? { ...entry } : null;\n}\n\nfunction restorePiTokenEntry(priorEntry: TokenEntry | null): void {\n const store = loadTokenStore();\n store.tokens = store.tokens.filter((entry) => entry.connector !== \"pi\");\n if (priorEntry) store.tokens.push(priorEntry);\n saveTokenStore(store);\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/publisher.ts"],"sourcesContent":["import fs from \"node:fs\";\nimport path from \"node:path\";\nimport { fileURLToPath, pathToFileURL } from \"node:url\";\n\nimport {\n getConnectorToken,\n loadTokenStore,\n saveTokenStore,\n type MemoryExtensionPublisher,\n type PublishContext,\n type PublishResult,\n type PublisherCapabilities,\n type TokenEntry,\n} from \"@remnic/core\";\n\nimport { resolvePiExtensionRoot } from \"./paths.js\";\n\nconst DEFAULT_DAEMON_PORT = 4318;\n\ntype FileSnapshot = {\n path: string;\n existed: boolean;\n content?: Buffer;\n mode?: number;\n};\n\nexport class PiMemoryExtensionPublisher implements MemoryExtensionPublisher {\n readonly hostId = \"pi\";\n\n static readonly capabilities: PublisherCapabilities = {\n instructionsMd: false,\n skillsFolder: false,\n citationFormat: false,\n readPathTemplate: false,\n };\n\n async resolveExtensionRoot(env?: NodeJS.ProcessEnv): Promise<string> {\n return resolvePiExtensionRoot(env ?? process.env);\n }\n\n async isHostAvailable(): Promise<boolean> {\n // Pi auto-discovers extensions from ~/.pi/agent/extensions. The directory can\n // be created before Pi has been launched, so availability should not block\n // first-time installation.\n return true;\n }\n\n async renderInstructions(ctx: PublishContext): Promise<string> {\n const namespace = ctx.config.namespace ?? \"default\";\n const daemonUrl = resolveDaemonUrl(ctx);\n return [\n \"# Remnic for Pi\",\n \"\",\n \"Remnic provides memory, retrieval, observation, MCP tools, and long-context compaction coordination for Pi Coding Agent.\",\n \"\",\n \"## Installed Capabilities\",\n \"\",\n \"- Recall relevant Remnic context in Pi's `context` hook before agent turns.\",\n \"- Observe Pi user, assistant, and tool messages with `sourceFormat: \\\"pi\\\"`.\",\n \"- Coordinate Pi `session_before_compact` with Remnic LCM flush and checkpoint recording.\",\n \"- Register Remnic MCP tools as Pi tools when daemon authentication is configured.\",\n \"- Persist lightweight dedupe state in Pi custom entries via `appendEntry`.\",\n \"\",\n \"## Runtime\",\n \"\",\n `- Remnic daemon: \\`${daemonUrl}\\``,\n `- Namespace: \\`${namespace}\\``,\n `- Memory directory: \\`${ctx.config.memoryDir}\\``,\n \"\",\n \"The private `remnic.config.json` file stores the daemon URL, namespace, and connector auth token with owner-only permissions.\",\n ].join(\"\\n\");\n }\n\n async publish(ctx: PublishContext): Promise<PublishResult> {\n const extensionRoot = await this.resolveExtensionRoot();\n const filesWritten: string[] = [];\n const skipped: string[] = [];\n\n ctx.log.info(`Publishing Pi memory extension to ${extensionRoot}`);\n\n const configPath = path.join(extensionRoot, \"remnic.config.json\");\n const wrapperPath = path.join(extensionRoot, \"index.ts\");\n const readmePath = path.join(extensionRoot, \"README.md\");\n const rootExisted = fs.existsSync(extensionRoot);\n const snapshots = snapshotFiles([configPath, wrapperPath, readmePath]);\n const priorConfig = readPriorConfig(configPath);\n const priorTokenEntry =\n ctx.rollbackTokenEntry === undefined ? snapshotPiTokenEntry() : cloneTokenEntry(ctx.rollbackTokenEntry);\n\n const token = getConnectorToken(\"pi\");\n if (!token) {\n skipped.push(\"auth token unavailable; run `remnic token generate pi` and reinstall the connector\");\n }\n\n const config: Record<string, unknown> = {\n recallMode: \"auto\",\n recallTopK: 8,\n recallBudgetChars: 12000,\n recallEnabled: true,\n observeEnabled: true,\n observeSkipExtraction: false,\n compactionEnabled: true,\n mcpToolsEnabled: true,\n statusEnabled: true,\n requestTimeoutMs: 60000,\n ...priorConfig,\n remnicDaemonUrl: resolveDaemonUrl(ctx),\n };\n if (token) {\n config.authToken = token;\n }\n if (ctx.config.namespace) {\n config.namespace = ctx.config.namespace;\n }\n\n try {\n fs.mkdirSync(extensionRoot, { recursive: true });\n\n atomicWriteFile(configPath, `${JSON.stringify(config, null, 2)}\\n`, 0o600);\n filesWritten.push(configPath);\n\n atomicWriteFile(wrapperPath, renderWrapper(resolveExtensionModulePath(), configPath), 0o644);\n filesWritten.push(wrapperPath);\n\n atomicWriteFile(readmePath, `${await this.renderInstructions(ctx)}\\n`, 0o644);\n filesWritten.push(readmePath);\n } catch (err) {\n try {\n restorePublishSnapshot(extensionRoot, rootExisted, snapshots);\n } catch (restoreErr) {\n ctx.log.warn(`Pi extension rollback failed: ${restoreErr instanceof Error ? restoreErr.message : String(restoreErr)}`);\n }\n try {\n restorePiTokenEntry(priorTokenEntry);\n } catch (tokenErr) {\n ctx.log.warn(`Pi connector token rollback failed: ${tokenErr instanceof Error ? tokenErr.message : String(tokenErr)}`);\n }\n throw err;\n }\n\n return {\n hostId: this.hostId,\n extensionRoot,\n filesWritten,\n skipped,\n };\n }\n\n async unpublish(): Promise<void> {\n const extensionRoot = await this.resolveExtensionRoot();\n if (fs.existsSync(extensionRoot)) {\n fs.rmSync(extensionRoot, { recursive: true, force: true });\n }\n }\n}\n\nfunction resolveDaemonUrl(ctx: PublishContext): string {\n if (ctx.config.daemonUrl && ctx.config.daemonUrl.trim().length > 0) {\n return trimTrailingSlashes(ctx.config.daemonUrl.trim());\n }\n return `http://127.0.0.1:${ctx.config.daemonPort ?? DEFAULT_DAEMON_PORT}`;\n}\n\nfunction trimTrailingSlashes(value: string): string {\n let end = value.length;\n while (end > 0 && value.charCodeAt(end - 1) === 47) end -= 1;\n return value.slice(0, end);\n}\n\nfunction resolveExtensionModulePath(): string {\n const moduleDir = path.dirname(fileURLToPath(import.meta.url));\n const built = path.join(moduleDir, \"index.js\");\n if (fs.existsSync(built)) return built;\n\n const source = path.join(moduleDir, \"index.ts\");\n if (fs.existsSync(source)) return source;\n\n return built;\n}\n\nfunction renderWrapper(extensionModulePath: string, configPath: string): string {\n const moduleUrl = pathToFileURL(extensionModulePath).href;\n return [\n `import { createRemnicPiExtension } from ${JSON.stringify(moduleUrl)};`,\n \"\",\n `export default createRemnicPiExtension({ configPath: ${JSON.stringify(configPath)} });`,\n \"\",\n ].join(\"\\n\");\n}\n\nfunction atomicWriteFile(filePath: string, content: string, mode: number): void {\n const tmpPath = `${filePath}.tmp-${process.pid}-${Date.now()}`;\n try {\n fs.writeFileSync(tmpPath, content, { encoding: \"utf-8\", mode });\n fs.renameSync(tmpPath, filePath);\n try {\n fs.chmodSync(filePath, mode);\n } catch {\n // Best effort for platforms that do not support chmod.\n }\n } catch (err) {\n try {\n if (fs.existsSync(tmpPath)) fs.unlinkSync(tmpPath);\n } catch {\n // Best-effort cleanup only.\n }\n throw err;\n }\n}\n\nfunction snapshotFiles(paths: string[]): FileSnapshot[] {\n return paths.map((filePath) => {\n if (!fs.existsSync(filePath)) return { path: filePath, existed: false };\n const stat = fs.statSync(filePath);\n if (!stat.isFile()) return { path: filePath, existed: false };\n return {\n path: filePath,\n existed: true,\n content: fs.readFileSync(filePath),\n mode: stat.mode & 0o777,\n };\n });\n}\n\nfunction restorePublishSnapshot(extensionRoot: string, rootExisted: boolean, snapshots: FileSnapshot[]): void {\n if (!rootExisted) {\n fs.rmSync(extensionRoot, { recursive: true, force: true });\n return;\n }\n\n for (const snapshot of snapshots) {\n if (!snapshot.existed) {\n fs.rmSync(snapshot.path, { force: true });\n continue;\n }\n fs.mkdirSync(path.dirname(snapshot.path), { recursive: true });\n fs.writeFileSync(snapshot.path, snapshot.content ?? Buffer.alloc(0), { mode: snapshot.mode });\n if (snapshot.mode !== undefined) {\n try {\n fs.chmodSync(snapshot.path, snapshot.mode);\n } catch {\n // Best effort for platforms that do not support chmod.\n }\n }\n }\n}\n\nfunction readPriorConfig(configPath: string): Record<string, unknown> {\n if (!fs.existsSync(configPath)) return {};\n try {\n const parsed = JSON.parse(fs.readFileSync(configPath, \"utf8\"));\n if (parsed && typeof parsed === \"object\" && !Array.isArray(parsed)) {\n return parsed as Record<string, unknown>;\n }\n throw new Error(\"expected a JSON object\");\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err);\n throw new Error(`Failed to load existing Remnic Pi config at ${configPath}: ${reason}`);\n }\n}\n\nfunction snapshotPiTokenEntry(): TokenEntry | null {\n const entry = loadTokenStore().tokens.find((candidate) => candidate.connector === \"pi\");\n return cloneTokenEntry(entry ?? null);\n}\n\nfunction cloneTokenEntry(entry: TokenEntry | null): TokenEntry | null {\n return entry ? { ...entry } : null;\n}\n\nfunction restorePiTokenEntry(priorEntry: TokenEntry | null): void {\n const store = loadTokenStore();\n store.tokens = store.tokens.filter((entry) => entry.connector !== \"pi\");\n if (priorEntry) store.tokens.push(priorEntry);\n saveTokenStore(store);\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@remnic/plugin-pi",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Remnic memory extension for Pi Coding Agent",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
},
|
|
39
39
|
"dependencies": {
|
|
40
40
|
"@sinclair/typebox": "^0.34.0",
|
|
41
|
-
"@remnic/core": "^1.1.
|
|
41
|
+
"@remnic/core": "^1.1.21"
|
|
42
42
|
},
|
|
43
43
|
"peerDependencies": {
|
|
44
44
|
"@earendil-works/pi-coding-agent": "*"
|
|
@@ -61,6 +61,7 @@
|
|
|
61
61
|
},
|
|
62
62
|
"scripts": {
|
|
63
63
|
"build": "tsup src/index.ts src/publisher.ts --format esm --dts",
|
|
64
|
+
"precheck-types": "node ../../scripts/ensure-bench-build-deps.mjs",
|
|
64
65
|
"check-types": "tsc --noEmit",
|
|
65
66
|
"test": "tsx --test 'src/**/*.test.ts'"
|
|
66
67
|
}
|