@remnic/plugin-pi 9.3.687 → 9.3.688

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/publisher.js CHANGED
@@ -61,6 +61,11 @@ var HostMemoryExtensionPublisher = class {
61
61
  }
62
62
  host;
63
63
  static capabilities = {
64
+ // Real publisher: writes host config + wrapper + readme, just no
65
+ // instructions.md/skills/citation/read-path-template artefacts. The
66
+ // explicit flag prevents the parity gate from mis-inferring "all flags
67
+ // false ⇒ stub" for this host (#1518).
68
+ isStub: false,
64
69
  instructionsMd: false,
65
70
  skillsFolder: false,
66
71
  citationFormat: false,
@@ -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 type MemoryExtensionPublisher,\n type PublishContext,\n type PublishResult,\n type PublisherCapabilities,\n type TokenEntry,\n getConnectorToken,\n loadTokenStore,\n saveTokenStore,\n} from \"@remnic/core\";\n\nimport {\n resolveOmpAgentHome,\n resolveOmpConfigRoot,\n resolveOmpExtensionRoot,\n resolvePiAgentHome,\n resolvePiExtensionRoot,\n} from \"./paths.js\";\n\nconst DEFAULT_DAEMON_PORT = 4318;\nconst EXTENSION_OWNED_FILES = [\"remnic.config.json\", \"index.ts\", \"README.md\"] as const;\nconst EXTENSION_OWNED_TEMP_FILE_PATTERN = /^(?:remnic\\.config\\.json|index\\.ts|README\\.md)\\.tmp-\\d+-\\d+$/u;\n\ntype FileSnapshot = {\n path: string;\n existed: boolean;\n content?: Buffer;\n mode?: number;\n};\n\n/**\n * Host-specific parameters for a Pi-family memory extension publisher.\n *\n * The Remnic runtime extension is host-neutral (it only uses Pi's extension\n * hooks, which omp preserves as a superset), so the only things that vary\n * between hosts are *where* the extension is installed, *which* connector\n * token it uses, and *how* it is labelled. Everything else — atomic writes,\n * rollback, symlink guards, config merge — is shared.\n */\nexport interface HostPublisherDescriptor {\n readonly hostId: string;\n readonly connectorId: string;\n readonly displayName: string;\n readonly tokenGenerateHint: string;\n resolveAgentHome(env: NodeJS.ProcessEnv): string;\n resolveExtensionRoot(env: NodeJS.ProcessEnv): string;\n /**\n * Optional: every agent home `unpublish` should sweep for a stale extension,\n * beyond the one resolved from the current env. Hosts with env-sensitive\n * install locations (e.g. omp profiles) provide this so `remnic connectors\n * remove` cleans up even when the remove-time env differs from install time.\n */\n listRemovalAgentHomes?(env: NodeJS.ProcessEnv): string[];\n}\n\nconst PI_HOST: HostPublisherDescriptor = {\n hostId: \"pi\",\n connectorId: \"pi\",\n displayName: \"Pi Coding Agent\",\n tokenGenerateHint: \"remnic token generate pi\",\n resolveAgentHome: resolvePiAgentHome,\n resolveExtensionRoot: resolvePiExtensionRoot,\n};\n\nconst OMP_HOST: HostPublisherDescriptor = {\n hostId: \"omp\",\n connectorId: \"omp\",\n displayName: \"Oh My Pi (omp)\",\n tokenGenerateHint: \"remnic token generate omp\",\n resolveAgentHome: resolveOmpAgentHome,\n resolveExtensionRoot: resolveOmpExtensionRoot,\n listRemovalAgentHomes: ompRemovalAgentHomes,\n};\n\n/**\n * Every omp agent home a stale extension might live under, so `unpublish` cleans\n * up regardless of the profile/env active at remove time: the env-resolved home,\n * the base `<configRoot>/agent`, an explicit `PI_CODING_AGENT_DIR`, and every\n * existing `<configRoot>/profiles/<name>/agent`. Symlinked profile dirs are\n * skipped defensively.\n */\nfunction ompRemovalAgentHomes(env: NodeJS.ProcessEnv): string[] {\n const homes = new Set<string>([resolveOmpAgentHome(env)]);\n const configRoot = resolveOmpConfigRoot(env);\n homes.add(path.join(configRoot, \"agent\"));\n\n const explicit = env.PI_CODING_AGENT_DIR?.trim();\n if (explicit) homes.add(path.resolve(explicit));\n\n const profilesDir = path.join(configRoot, \"profiles\");\n let entries: fs.Dirent[] = [];\n try {\n entries = fs.readdirSync(profilesDir, { withFileTypes: true });\n } catch {\n entries = [];\n }\n for (const entry of entries) {\n if (entry.isDirectory() && !entry.isSymbolicLink()) {\n homes.add(path.join(profilesDir, entry.name, \"agent\"));\n }\n }\n return [...homes];\n}\n\n/**\n * Shared publisher for Pi-family hosts. Concrete hosts (Pi, omp) subclass this\n * with a {@link HostPublisherDescriptor}; the install/rollback machinery is\n * identical across hosts.\n */\nexport class HostMemoryExtensionPublisher implements MemoryExtensionPublisher {\n static readonly capabilities: PublisherCapabilities = {\n instructionsMd: false,\n skillsFolder: false,\n citationFormat: false,\n readPathTemplate: false,\n };\n\n protected constructor(private readonly host: HostPublisherDescriptor) {}\n\n get hostId(): string {\n return this.host.hostId;\n }\n\n async resolveExtensionRoot(env?: NodeJS.ProcessEnv): Promise<string> {\n return this.host.resolveExtensionRoot(env ?? process.env);\n }\n\n async isHostAvailable(): Promise<boolean> {\n // Pi-family agents auto-discover extensions from their agent extensions\n // directory. The directory can be created before the agent has been\n // launched, so availability should not block 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 ${this.host.displayName}`,\n \"\",\n `Remnic provides memory, retrieval, observation, MCP tools, and long-context compaction coordination for ${this.host.displayName}.`,\n \"\",\n \"## Installed Capabilities\",\n \"\",\n \"- Recall relevant Remnic context in the `context` hook before agent turns.\",\n '- Observe user, assistant, and tool messages with `sourceFormat: \"pi\"`.',\n \"- Coordinate `session_before_compact` with Remnic LCM flush and checkpoint recording.\",\n \"- Register Remnic MCP tools as host tools when daemon authentication is configured.\",\n \"- Persist lightweight dedupe state in 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 agentHome = this.host.resolveAgentHome(process.env);\n assertSafeExtensionRoot(extensionRoot, agentHome);\n const filesWritten: string[] = [];\n const skipped: string[] = [];\n\n ctx.log.info(`Publishing ${this.host.displayName} memory extension to ${extensionRoot}`);\n\n const [configPath, wrapperPath, readmePath] = extensionOwnedPaths(extensionRoot);\n const rootExisted = fs.existsSync(extensionRoot);\n const snapshots = snapshotFiles([configPath, wrapperPath, readmePath]);\n const priorTokenEntry =\n ctx.rollbackTokenEntry === undefined\n ? snapshotTokenEntry(this.host.connectorId)\n : cloneTokenEntry(ctx.rollbackTokenEntry);\n\n const token = getConnectorToken(this.host.connectorId);\n if (!token) {\n skipped.push(\n `auth token unavailable; run \\`${this.host.tokenGenerateHint}\\` and reinstall the connector`,\n );\n }\n\n try {\n const priorConfig = readPriorConfig(configPath);\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 startupRequestTimeoutMs: 1000,\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 mkdirExtensionRoot(extensionRoot, agentHome);\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(\n `${this.host.displayName} extension rollback failed: ${restoreErr instanceof Error ? restoreErr.message : String(restoreErr)}`,\n );\n }\n try {\n restoreTokenEntry(priorTokenEntry, this.host.connectorId);\n } catch (tokenErr) {\n ctx.log.warn(\n `${this.host.displayName} connector token rollback failed: ${tokenErr instanceof Error ? tokenErr.message : String(tokenErr)}`,\n );\n }\n throw err;\n }\n\n return {\n hostId: this.host.hostId,\n extensionRoot,\n filesWritten,\n skipped,\n };\n }\n\n async unpublish(): Promise<void> {\n const agentHomes = this.host.listRemovalAgentHomes\n ? this.host.listRemovalAgentHomes(process.env)\n : [this.host.resolveAgentHome(process.env)];\n\n const seen = new Set<string>();\n for (const agentHome of agentHomes) {\n const extensionRoot = path.join(path.resolve(agentHome), \"extensions\", \"remnic\");\n if (seen.has(extensionRoot)) continue;\n seen.add(extensionRoot);\n if (!fs.existsSync(extensionRoot)) continue;\n\n assertSafeExtensionRoot(extensionRoot, agentHome);\n const removableFiles = removableOwnedExtensionFiles(extensionOwnedUnpublishPaths(extensionRoot));\n for (const filePath of removableFiles) {\n fs.rmSync(filePath, { force: true });\n }\n removeEmptyDirectory(extensionRoot);\n }\n }\n}\n\n/** Publisher for upstream Pi (`~/.pi/agent/extensions/remnic`). */\nexport class PiMemoryExtensionPublisher extends HostMemoryExtensionPublisher {\n constructor() {\n super(PI_HOST);\n }\n}\n\n/** Publisher for Oh My Pi / omp (`~/.omp/agent/extensions/remnic`). */\nexport class OmpMemoryExtensionPublisher extends HostMemoryExtensionPublisher {\n constructor() {\n super(OMP_HOST);\n }\n}\n\nfunction extensionOwnedPaths(extensionRoot: string): string[] {\n return EXTENSION_OWNED_FILES.map((fileName) => path.join(extensionRoot, fileName));\n}\n\nfunction extensionOwnedUnpublishPaths(extensionRoot: string): string[] {\n const ownedPaths = extensionOwnedPaths(extensionRoot);\n for (const fileName of fs.readdirSync(extensionRoot)) {\n if (EXTENSION_OWNED_TEMP_FILE_PATTERN.test(fileName)) {\n ownedPaths.push(path.join(extensionRoot, fileName));\n }\n }\n return ownedPaths;\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 rejectSymlinkPath(filePath);\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.lstatSync(filePath);\n if (stat.isSymbolicLink()) {\n throw new Error(`Extension path must not be a symlink: ${filePath}`);\n }\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 && !canCleanNewExtensionRoot(extensionRoot)) return;\n\n for (const snapshot of snapshots) {\n if (!snapshot.existed) {\n assertSafeExistingPath(snapshot.path);\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 if (!rootExisted) {\n removeEmptyDirectory(extensionRoot);\n }\n}\n\nfunction canCleanNewExtensionRoot(extensionRoot: string): boolean {\n let stat: fs.Stats;\n try {\n stat = fs.lstatSync(extensionRoot);\n } catch (err) {\n if (err && typeof err === \"object\" && \"code\" in err && err.code === \"ENOENT\") return false;\n throw err;\n }\n if (stat.isSymbolicLink()) {\n throw new Error(`Extension path must not be a symlink: ${extensionRoot}`);\n }\n return stat.isDirectory();\n}\n\nfunction removeEmptyDirectory(dirPath: string): void {\n let stat: fs.Stats;\n try {\n stat = fs.lstatSync(dirPath);\n } catch (err) {\n if (err && typeof err === \"object\" && \"code\" in err && err.code === \"ENOENT\") return;\n throw err;\n }\n if (stat.isSymbolicLink()) {\n throw new Error(`Extension path must not be a symlink: ${dirPath}`);\n }\n if (!stat.isDirectory()) return;\n if (fs.readdirSync(dirPath).length > 0) return;\n fs.rmdirSync(dirPath);\n}\n\nfunction removableOwnedExtensionFiles(filePaths: string[]): string[] {\n const removableFiles: string[] = [];\n for (const filePath of filePaths) {\n const stat = statOwnedExtensionPath(filePath);\n if (stat === null) continue;\n if (stat.isSymbolicLink()) {\n throw new Error(`Extension path must not be a symlink: ${filePath}`);\n }\n if (stat.isFile()) removableFiles.push(filePath);\n }\n return removableFiles;\n}\n\nfunction statOwnedExtensionPath(filePath: string): fs.Stats | null {\n let stat: fs.Stats;\n try {\n stat = fs.lstatSync(filePath);\n } catch (err) {\n if (err && typeof err === \"object\" && \"code\" in err && err.code === \"ENOENT\") return null;\n throw err;\n }\n return stat;\n}\n\nfunction mkdirExtensionRoot(extensionRoot: string, agentHome: string): void {\n const extensionsDir = path.join(path.resolve(agentHome), \"extensions\");\n assertSafeExtensionRoot(extensionRoot, agentHome);\n fs.mkdirSync(extensionsDir, { recursive: true });\n rejectSymlinkPath(extensionsDir);\n fs.mkdirSync(extensionRoot, { recursive: true });\n rejectSymlinkPath(extensionRoot);\n}\n\nfunction assertSafeExtensionRoot(extensionRoot: string, agentHome: string): void {\n const resolvedAgentHome = path.resolve(agentHome);\n const expected = path.join(resolvedAgentHome, \"extensions\", \"remnic\");\n if (path.resolve(extensionRoot) !== path.resolve(expected)) {\n throw new Error(`Extension root is outside the configured extensions directory: ${extensionRoot}`);\n }\n const extensionsDir = path.join(resolvedAgentHome, \"extensions\");\n assertPathContained(resolvedAgentHome, extensionsDir);\n assertPathContained(extensionsDir, extensionRoot);\n rejectSymlinkPath(resolvedAgentHome);\n if (fs.existsSync(extensionsDir)) rejectSymlinkPath(extensionsDir);\n if (fs.existsSync(extensionRoot)) rejectSymlinkPath(extensionRoot);\n}\n\nfunction assertSafeExistingPath(filePath: string): void {\n if (fs.existsSync(filePath)) rejectSymlinkPath(filePath);\n}\n\nfunction rejectSymlinkPath(filePath: string): void {\n if (!fs.existsSync(filePath)) return;\n const stat = fs.lstatSync(filePath);\n if (stat.isSymbolicLink()) {\n throw new Error(`Extension path must not be a symlink: ${filePath}`);\n }\n}\n\nfunction assertPathContained(root: string, candidate: string): void {\n const rootResolved = path.resolve(root);\n const candidateResolved = path.resolve(candidate);\n const relative = path.relative(rootResolved, candidateResolved);\n if (relative === \"\" || (!relative.startsWith(\"..\") && !path.isAbsolute(relative))) return;\n throw new Error(`Extension path escapes allowed root: ${candidate}`);\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 snapshotTokenEntry(connectorId: string): TokenEntry | null {\n const entry = loadTokenStore().tokens.find((candidate) => candidate.connector === connectorId);\n return cloneTokenEntry(entry ?? null);\n}\n\nfunction cloneTokenEntry(entry: TokenEntry | null): TokenEntry | null {\n return entry ? { ...entry } : null;\n}\n\nfunction restoreTokenEntry(priorEntry: TokenEntry | null, connectorId: string): void {\n const store = loadTokenStore();\n store.tokens = store.tokens.filter((entry) => entry.connector !== connectorId);\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 type MemoryExtensionPublisher,\n type PublishContext,\n type PublishResult,\n type PublisherCapabilities,\n type TokenEntry,\n getConnectorToken,\n loadTokenStore,\n saveTokenStore,\n} from \"@remnic/core\";\n\nimport {\n resolveOmpAgentHome,\n resolveOmpConfigRoot,\n resolveOmpExtensionRoot,\n resolvePiAgentHome,\n resolvePiExtensionRoot,\n} from \"./paths.js\";\n\nconst DEFAULT_DAEMON_PORT = 4318;\nconst EXTENSION_OWNED_FILES = [\"remnic.config.json\", \"index.ts\", \"README.md\"] as const;\nconst EXTENSION_OWNED_TEMP_FILE_PATTERN = /^(?:remnic\\.config\\.json|index\\.ts|README\\.md)\\.tmp-\\d+-\\d+$/u;\n\ntype FileSnapshot = {\n path: string;\n existed: boolean;\n content?: Buffer;\n mode?: number;\n};\n\n/**\n * Host-specific parameters for a Pi-family memory extension publisher.\n *\n * The Remnic runtime extension is host-neutral (it only uses Pi's extension\n * hooks, which omp preserves as a superset), so the only things that vary\n * between hosts are *where* the extension is installed, *which* connector\n * token it uses, and *how* it is labelled. Everything else — atomic writes,\n * rollback, symlink guards, config merge — is shared.\n */\nexport interface HostPublisherDescriptor {\n readonly hostId: string;\n readonly connectorId: string;\n readonly displayName: string;\n readonly tokenGenerateHint: string;\n resolveAgentHome(env: NodeJS.ProcessEnv): string;\n resolveExtensionRoot(env: NodeJS.ProcessEnv): string;\n /**\n * Optional: every agent home `unpublish` should sweep for a stale extension,\n * beyond the one resolved from the current env. Hosts with env-sensitive\n * install locations (e.g. omp profiles) provide this so `remnic connectors\n * remove` cleans up even when the remove-time env differs from install time.\n */\n listRemovalAgentHomes?(env: NodeJS.ProcessEnv): string[];\n}\n\nconst PI_HOST: HostPublisherDescriptor = {\n hostId: \"pi\",\n connectorId: \"pi\",\n displayName: \"Pi Coding Agent\",\n tokenGenerateHint: \"remnic token generate pi\",\n resolveAgentHome: resolvePiAgentHome,\n resolveExtensionRoot: resolvePiExtensionRoot,\n};\n\nconst OMP_HOST: HostPublisherDescriptor = {\n hostId: \"omp\",\n connectorId: \"omp\",\n displayName: \"Oh My Pi (omp)\",\n tokenGenerateHint: \"remnic token generate omp\",\n resolveAgentHome: resolveOmpAgentHome,\n resolveExtensionRoot: resolveOmpExtensionRoot,\n listRemovalAgentHomes: ompRemovalAgentHomes,\n};\n\n/**\n * Every omp agent home a stale extension might live under, so `unpublish` cleans\n * up regardless of the profile/env active at remove time: the env-resolved home,\n * the base `<configRoot>/agent`, an explicit `PI_CODING_AGENT_DIR`, and every\n * existing `<configRoot>/profiles/<name>/agent`. Symlinked profile dirs are\n * skipped defensively.\n */\nfunction ompRemovalAgentHomes(env: NodeJS.ProcessEnv): string[] {\n const homes = new Set<string>([resolveOmpAgentHome(env)]);\n const configRoot = resolveOmpConfigRoot(env);\n homes.add(path.join(configRoot, \"agent\"));\n\n const explicit = env.PI_CODING_AGENT_DIR?.trim();\n if (explicit) homes.add(path.resolve(explicit));\n\n const profilesDir = path.join(configRoot, \"profiles\");\n let entries: fs.Dirent[] = [];\n try {\n entries = fs.readdirSync(profilesDir, { withFileTypes: true });\n } catch {\n entries = [];\n }\n for (const entry of entries) {\n if (entry.isDirectory() && !entry.isSymbolicLink()) {\n homes.add(path.join(profilesDir, entry.name, \"agent\"));\n }\n }\n return [...homes];\n}\n\n/**\n * Shared publisher for Pi-family hosts. Concrete hosts (Pi, omp) subclass this\n * with a {@link HostPublisherDescriptor}; the install/rollback machinery is\n * identical across hosts.\n */\nexport class HostMemoryExtensionPublisher implements MemoryExtensionPublisher {\n static readonly capabilities: PublisherCapabilities = {\n // Real publisher: writes host config + wrapper + readme, just no\n // instructions.md/skills/citation/read-path-template artefacts. The\n // explicit flag prevents the parity gate from mis-inferring \"all flags\n // false ⇒ stub\" for this host (#1518).\n isStub: false,\n instructionsMd: false,\n skillsFolder: false,\n citationFormat: false,\n readPathTemplate: false,\n };\n\n protected constructor(private readonly host: HostPublisherDescriptor) {}\n\n get hostId(): string {\n return this.host.hostId;\n }\n\n async resolveExtensionRoot(env?: NodeJS.ProcessEnv): Promise<string> {\n return this.host.resolveExtensionRoot(env ?? process.env);\n }\n\n async isHostAvailable(): Promise<boolean> {\n // Pi-family agents auto-discover extensions from their agent extensions\n // directory. The directory can be created before the agent has been\n // launched, so availability should not block 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 ${this.host.displayName}`,\n \"\",\n `Remnic provides memory, retrieval, observation, MCP tools, and long-context compaction coordination for ${this.host.displayName}.`,\n \"\",\n \"## Installed Capabilities\",\n \"\",\n \"- Recall relevant Remnic context in the `context` hook before agent turns.\",\n '- Observe user, assistant, and tool messages with `sourceFormat: \"pi\"`.',\n \"- Coordinate `session_before_compact` with Remnic LCM flush and checkpoint recording.\",\n \"- Register Remnic MCP tools as host tools when daemon authentication is configured.\",\n \"- Persist lightweight dedupe state in 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 agentHome = this.host.resolveAgentHome(process.env);\n assertSafeExtensionRoot(extensionRoot, agentHome);\n const filesWritten: string[] = [];\n const skipped: string[] = [];\n\n ctx.log.info(`Publishing ${this.host.displayName} memory extension to ${extensionRoot}`);\n\n const [configPath, wrapperPath, readmePath] = extensionOwnedPaths(extensionRoot);\n const rootExisted = fs.existsSync(extensionRoot);\n const snapshots = snapshotFiles([configPath, wrapperPath, readmePath]);\n const priorTokenEntry =\n ctx.rollbackTokenEntry === undefined\n ? snapshotTokenEntry(this.host.connectorId)\n : cloneTokenEntry(ctx.rollbackTokenEntry);\n\n const token = getConnectorToken(this.host.connectorId);\n if (!token) {\n skipped.push(\n `auth token unavailable; run \\`${this.host.tokenGenerateHint}\\` and reinstall the connector`,\n );\n }\n\n try {\n const priorConfig = readPriorConfig(configPath);\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 startupRequestTimeoutMs: 1000,\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 mkdirExtensionRoot(extensionRoot, agentHome);\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(\n `${this.host.displayName} extension rollback failed: ${restoreErr instanceof Error ? restoreErr.message : String(restoreErr)}`,\n );\n }\n try {\n restoreTokenEntry(priorTokenEntry, this.host.connectorId);\n } catch (tokenErr) {\n ctx.log.warn(\n `${this.host.displayName} connector token rollback failed: ${tokenErr instanceof Error ? tokenErr.message : String(tokenErr)}`,\n );\n }\n throw err;\n }\n\n return {\n hostId: this.host.hostId,\n extensionRoot,\n filesWritten,\n skipped,\n };\n }\n\n async unpublish(): Promise<void> {\n const agentHomes = this.host.listRemovalAgentHomes\n ? this.host.listRemovalAgentHomes(process.env)\n : [this.host.resolveAgentHome(process.env)];\n\n const seen = new Set<string>();\n for (const agentHome of agentHomes) {\n const extensionRoot = path.join(path.resolve(agentHome), \"extensions\", \"remnic\");\n if (seen.has(extensionRoot)) continue;\n seen.add(extensionRoot);\n if (!fs.existsSync(extensionRoot)) continue;\n\n assertSafeExtensionRoot(extensionRoot, agentHome);\n const removableFiles = removableOwnedExtensionFiles(extensionOwnedUnpublishPaths(extensionRoot));\n for (const filePath of removableFiles) {\n fs.rmSync(filePath, { force: true });\n }\n removeEmptyDirectory(extensionRoot);\n }\n }\n}\n\n/** Publisher for upstream Pi (`~/.pi/agent/extensions/remnic`). */\nexport class PiMemoryExtensionPublisher extends HostMemoryExtensionPublisher {\n constructor() {\n super(PI_HOST);\n }\n}\n\n/** Publisher for Oh My Pi / omp (`~/.omp/agent/extensions/remnic`). */\nexport class OmpMemoryExtensionPublisher extends HostMemoryExtensionPublisher {\n constructor() {\n super(OMP_HOST);\n }\n}\n\nfunction extensionOwnedPaths(extensionRoot: string): string[] {\n return EXTENSION_OWNED_FILES.map((fileName) => path.join(extensionRoot, fileName));\n}\n\nfunction extensionOwnedUnpublishPaths(extensionRoot: string): string[] {\n const ownedPaths = extensionOwnedPaths(extensionRoot);\n for (const fileName of fs.readdirSync(extensionRoot)) {\n if (EXTENSION_OWNED_TEMP_FILE_PATTERN.test(fileName)) {\n ownedPaths.push(path.join(extensionRoot, fileName));\n }\n }\n return ownedPaths;\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 rejectSymlinkPath(filePath);\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.lstatSync(filePath);\n if (stat.isSymbolicLink()) {\n throw new Error(`Extension path must not be a symlink: ${filePath}`);\n }\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 && !canCleanNewExtensionRoot(extensionRoot)) return;\n\n for (const snapshot of snapshots) {\n if (!snapshot.existed) {\n assertSafeExistingPath(snapshot.path);\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 if (!rootExisted) {\n removeEmptyDirectory(extensionRoot);\n }\n}\n\nfunction canCleanNewExtensionRoot(extensionRoot: string): boolean {\n let stat: fs.Stats;\n try {\n stat = fs.lstatSync(extensionRoot);\n } catch (err) {\n if (err && typeof err === \"object\" && \"code\" in err && err.code === \"ENOENT\") return false;\n throw err;\n }\n if (stat.isSymbolicLink()) {\n throw new Error(`Extension path must not be a symlink: ${extensionRoot}`);\n }\n return stat.isDirectory();\n}\n\nfunction removeEmptyDirectory(dirPath: string): void {\n let stat: fs.Stats;\n try {\n stat = fs.lstatSync(dirPath);\n } catch (err) {\n if (err && typeof err === \"object\" && \"code\" in err && err.code === \"ENOENT\") return;\n throw err;\n }\n if (stat.isSymbolicLink()) {\n throw new Error(`Extension path must not be a symlink: ${dirPath}`);\n }\n if (!stat.isDirectory()) return;\n if (fs.readdirSync(dirPath).length > 0) return;\n fs.rmdirSync(dirPath);\n}\n\nfunction removableOwnedExtensionFiles(filePaths: string[]): string[] {\n const removableFiles: string[] = [];\n for (const filePath of filePaths) {\n const stat = statOwnedExtensionPath(filePath);\n if (stat === null) continue;\n if (stat.isSymbolicLink()) {\n throw new Error(`Extension path must not be a symlink: ${filePath}`);\n }\n if (stat.isFile()) removableFiles.push(filePath);\n }\n return removableFiles;\n}\n\nfunction statOwnedExtensionPath(filePath: string): fs.Stats | null {\n let stat: fs.Stats;\n try {\n stat = fs.lstatSync(filePath);\n } catch (err) {\n if (err && typeof err === \"object\" && \"code\" in err && err.code === \"ENOENT\") return null;\n throw err;\n }\n return stat;\n}\n\nfunction mkdirExtensionRoot(extensionRoot: string, agentHome: string): void {\n const extensionsDir = path.join(path.resolve(agentHome), \"extensions\");\n assertSafeExtensionRoot(extensionRoot, agentHome);\n fs.mkdirSync(extensionsDir, { recursive: true });\n rejectSymlinkPath(extensionsDir);\n fs.mkdirSync(extensionRoot, { recursive: true });\n rejectSymlinkPath(extensionRoot);\n}\n\nfunction assertSafeExtensionRoot(extensionRoot: string, agentHome: string): void {\n const resolvedAgentHome = path.resolve(agentHome);\n const expected = path.join(resolvedAgentHome, \"extensions\", \"remnic\");\n if (path.resolve(extensionRoot) !== path.resolve(expected)) {\n throw new Error(`Extension root is outside the configured extensions directory: ${extensionRoot}`);\n }\n const extensionsDir = path.join(resolvedAgentHome, \"extensions\");\n assertPathContained(resolvedAgentHome, extensionsDir);\n assertPathContained(extensionsDir, extensionRoot);\n rejectSymlinkPath(resolvedAgentHome);\n if (fs.existsSync(extensionsDir)) rejectSymlinkPath(extensionsDir);\n if (fs.existsSync(extensionRoot)) rejectSymlinkPath(extensionRoot);\n}\n\nfunction assertSafeExistingPath(filePath: string): void {\n if (fs.existsSync(filePath)) rejectSymlinkPath(filePath);\n}\n\nfunction rejectSymlinkPath(filePath: string): void {\n if (!fs.existsSync(filePath)) return;\n const stat = fs.lstatSync(filePath);\n if (stat.isSymbolicLink()) {\n throw new Error(`Extension path must not be a symlink: ${filePath}`);\n }\n}\n\nfunction assertPathContained(root: string, candidate: string): void {\n const rootResolved = path.resolve(root);\n const candidateResolved = path.resolve(candidate);\n const relative = path.relative(rootResolved, candidateResolved);\n if (relative === \"\" || (!relative.startsWith(\"..\") && !path.isAbsolute(relative))) return;\n throw new Error(`Extension path escapes allowed root: ${candidate}`);\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 snapshotTokenEntry(connectorId: string): TokenEntry | null {\n const entry = loadTokenStore().tokens.find((candidate) => candidate.connector === connectorId);\n return cloneTokenEntry(entry ?? null);\n}\n\nfunction cloneTokenEntry(entry: TokenEntry | null): TokenEntry | null {\n return entry ? { ...entry } : null;\n}\n\nfunction restoreTokenEntry(priorEntry: TokenEntry | null, connectorId: string): void {\n const store = loadTokenStore();\n store.tokens = store.tokens.filter((entry) => entry.connector !== connectorId);\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": "9.3.687",
3
+ "version": "9.3.688",
4
4
  "description": "Remnic memory extension for Pi Coding Agent",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -42,7 +42,7 @@
42
42
  },
43
43
  "dependencies": {
44
44
  "@sinclair/typebox": "^0.34.0",
45
- "@remnic/core": "^9.3.687"
45
+ "@remnic/core": "^9.3.688"
46
46
  },
47
47
  "peerDependencies": {
48
48
  "@earendil-works/pi-coding-agent": "*"