poe-code 3.0.183 → 3.0.185

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.
Files changed (232) hide show
  1. package/dist/cli/commands/configure-payload.d.ts +2 -1
  2. package/dist/cli/commands/configure-payload.js +4 -2
  3. package/dist/cli/commands/configure-payload.js.map +1 -1
  4. package/dist/cli/commands/configure.d.ts +1 -0
  5. package/dist/cli/commands/configure.js +50 -11
  6. package/dist/cli/commands/configure.js.map +1 -1
  7. package/dist/cli/commands/ensure-isolated-config.js +24 -2
  8. package/dist/cli/commands/ensure-isolated-config.js.map +1 -1
  9. package/dist/cli/commands/experiment.js +15 -2
  10. package/dist/cli/commands/experiment.js.map +1 -1
  11. package/dist/cli/commands/login.js +8 -4
  12. package/dist/cli/commands/login.js.map +1 -1
  13. package/dist/cli/commands/memory.js +16 -7
  14. package/dist/cli/commands/memory.js.map +1 -1
  15. package/dist/cli/commands/pipeline-init.d.ts +0 -1
  16. package/dist/cli/commands/pipeline-init.js +32 -46
  17. package/dist/cli/commands/pipeline-init.js.map +1 -1
  18. package/dist/cli/commands/pipeline.js +97 -41
  19. package/dist/cli/commands/pipeline.js.map +1 -1
  20. package/dist/cli/commands/provider.d.ts +6 -0
  21. package/dist/cli/commands/provider.js +100 -0
  22. package/dist/cli/commands/provider.js.map +1 -0
  23. package/dist/cli/commands/shared.d.ts +7 -0
  24. package/dist/cli/commands/shared.js +3 -0
  25. package/dist/cli/commands/shared.js.map +1 -1
  26. package/dist/cli/commands/test.js +1 -1
  27. package/dist/cli/commands/test.js.map +1 -1
  28. package/dist/cli/commands/unconfigure.js +12 -3
  29. package/dist/cli/commands/unconfigure.js.map +1 -1
  30. package/dist/cli/container.d.ts +2 -0
  31. package/dist/cli/container.js +3 -0
  32. package/dist/cli/container.js.map +1 -1
  33. package/dist/cli/isolated-env-runner.js +2 -2
  34. package/dist/cli/isolated-env-runner.js.map +1 -1
  35. package/dist/cli/isolated-env.d.ts +3 -2
  36. package/dist/cli/isolated-env.js +31 -40
  37. package/dist/cli/isolated-env.js.map +1 -1
  38. package/dist/cli/poe-code-command-runner.js +9 -2
  39. package/dist/cli/poe-code-command-runner.js.map +1 -1
  40. package/dist/cli/program.js +5 -0
  41. package/dist/cli/program.js.map +1 -1
  42. package/dist/cli/service-registry.d.ts +7 -7
  43. package/dist/cli/service-registry.js.map +1 -1
  44. package/dist/index.js +2965 -1968
  45. package/dist/index.js.map +4 -4
  46. package/dist/providers/claude-code.d.ts +2 -1
  47. package/dist/providers/claude-code.js +5 -5
  48. package/dist/providers/claude-code.js.map +2 -2
  49. package/dist/providers/codex.d.ts +5 -1
  50. package/dist/providers/codex.js +39 -12
  51. package/dist/providers/codex.js.map +2 -2
  52. package/dist/providers/goose.d.ts +2 -1
  53. package/dist/providers/goose.js +24 -8
  54. package/dist/providers/goose.js.map +3 -3
  55. package/dist/providers/kimi.js +3 -3
  56. package/dist/providers/kimi.js.map +3 -3
  57. package/dist/providers/opencode.js +2 -2
  58. package/dist/providers/opencode.js.map +3 -3
  59. package/dist/providers/poe-agent.js +786 -653
  60. package/dist/providers/poe-agent.js.map +4 -4
  61. package/dist/sdk/container.js +3 -0
  62. package/dist/sdk/container.js.map +1 -1
  63. package/dist/sdk/pipeline.d.ts +1 -2
  64. package/dist/sdk/pipeline.js +58 -9
  65. package/dist/sdk/pipeline.js.map +1 -1
  66. package/dist/services/config.d.ts +1 -0
  67. package/dist/services/config.js +27 -2
  68. package/dist/services/config.js.map +1 -1
  69. package/dist/templates/pipeline/SKILL_plan.md +7 -20
  70. package/dist/templates/pipeline/steps.yaml.mustache +5 -2
  71. package/package.json +10 -1
  72. package/packages/agent-mcp-config/dist/apply.d.ts +6 -0
  73. package/packages/agent-mcp-config/dist/apply.js +175 -0
  74. package/packages/agent-mcp-config/dist/configs.d.ts +22 -0
  75. package/packages/agent-mcp-config/dist/configs.js +74 -0
  76. package/packages/agent-mcp-config/dist/index.d.ts +3 -0
  77. package/packages/agent-mcp-config/dist/index.js +2 -0
  78. package/packages/agent-mcp-config/dist/shapes.d.ts +31 -0
  79. package/packages/agent-mcp-config/dist/shapes.js +87 -0
  80. package/packages/agent-mcp-config/dist/types.d.ts +25 -0
  81. package/packages/agent-mcp-config/dist/types.js +1 -0
  82. package/packages/agent-skill-config/dist/apply.d.ts +25 -0
  83. package/packages/agent-skill-config/dist/apply.js +109 -0
  84. package/packages/agent-skill-config/dist/configs.d.ts +16 -0
  85. package/packages/agent-skill-config/dist/configs.js +66 -0
  86. package/packages/agent-skill-config/dist/exports.compile-check.d.ts +1 -0
  87. package/packages/agent-skill-config/dist/exports.compile-check.js +1 -0
  88. package/packages/agent-skill-config/dist/index.d.ts +5 -0
  89. package/packages/agent-skill-config/dist/index.js +2 -0
  90. package/packages/agent-skill-config/dist/templates/poe-generate.md +47 -0
  91. package/packages/agent-skill-config/dist/templates/terminal-pilot.md +45 -0
  92. package/packages/agent-skill-config/dist/templates.d.ts +3 -0
  93. package/packages/agent-skill-config/dist/templates.js +63 -0
  94. package/packages/agent-skill-config/dist/types.d.ts +16 -0
  95. package/packages/agent-skill-config/dist/types.js +1 -0
  96. package/packages/cmdkit/dist/cli.js +7 -2
  97. package/packages/cmdkit/dist/cli.js.map +2 -2
  98. package/packages/config-mutations/dist/execution/apply-mutation.d.ts +5 -0
  99. package/packages/config-mutations/dist/execution/apply-mutation.js +552 -0
  100. package/packages/config-mutations/dist/execution/path-utils.d.ts +17 -0
  101. package/packages/config-mutations/dist/execution/path-utils.js +58 -0
  102. package/packages/config-mutations/dist/execution/run-mutations.d.ts +7 -0
  103. package/packages/config-mutations/dist/execution/run-mutations.js +46 -0
  104. package/packages/config-mutations/dist/formats/index.d.ts +13 -0
  105. package/packages/config-mutations/dist/formats/index.js +49 -0
  106. package/packages/config-mutations/dist/formats/json.d.ts +31 -0
  107. package/packages/config-mutations/dist/formats/json.js +140 -0
  108. package/packages/config-mutations/dist/formats/toml.d.ts +2 -0
  109. package/packages/config-mutations/dist/formats/toml.js +72 -0
  110. package/packages/config-mutations/dist/formats/yaml.d.ts +2 -0
  111. package/packages/config-mutations/dist/formats/yaml.js +73 -0
  112. package/packages/config-mutations/dist/fs-utils.d.ts +18 -0
  113. package/packages/config-mutations/dist/fs-utils.js +45 -0
  114. package/packages/config-mutations/dist/index.d.ts +8 -0
  115. package/packages/config-mutations/dist/index.js +8 -0
  116. package/packages/config-mutations/dist/mutations/config-mutation.d.ts +47 -0
  117. package/packages/config-mutations/dist/mutations/config-mutation.js +34 -0
  118. package/packages/config-mutations/dist/mutations/file-mutation.d.ts +52 -0
  119. package/packages/config-mutations/dist/mutations/file-mutation.js +46 -0
  120. package/packages/config-mutations/dist/mutations/template-mutation.d.ts +40 -0
  121. package/packages/config-mutations/dist/mutations/template-mutation.js +32 -0
  122. package/packages/config-mutations/dist/template/render.d.ts +7 -0
  123. package/packages/config-mutations/dist/template/render.js +28 -0
  124. package/packages/config-mutations/dist/testing/format-utils.d.ts +7 -0
  125. package/packages/config-mutations/dist/testing/format-utils.js +21 -0
  126. package/packages/config-mutations/dist/testing/index.d.ts +3 -0
  127. package/packages/config-mutations/dist/testing/index.js +2 -0
  128. package/packages/config-mutations/dist/testing/mock-fs.d.ts +25 -0
  129. package/packages/config-mutations/dist/testing/mock-fs.js +170 -0
  130. package/packages/config-mutations/dist/types.d.ts +156 -0
  131. package/packages/config-mutations/dist/types.js +6 -0
  132. package/packages/design-system/dist/dashboard/components/stats-pane.js +2 -1
  133. package/packages/design-system/dist/dashboard/types.d.ts +1 -0
  134. package/packages/memory/dist/audit.d.ts +11 -0
  135. package/packages/memory/dist/audit.js +131 -0
  136. package/packages/memory/dist/cache.cli.d.ts +9 -0
  137. package/packages/memory/dist/cache.cli.js +24 -0
  138. package/packages/memory/dist/cache.d.ts +14 -0
  139. package/packages/memory/dist/cache.js +149 -0
  140. package/packages/memory/dist/confidence.d.ts +4 -0
  141. package/packages/memory/dist/confidence.js +201 -0
  142. package/packages/memory/dist/corpus/001-archaeoastronomy.md +479 -0
  143. package/packages/memory/dist/corpus/002-magnetohydrodynamics.md +475 -0
  144. package/packages/memory/dist/corpus/003-biosemiotics.md +483 -0
  145. package/packages/memory/dist/corpus/004-cryopedology.md +483 -0
  146. package/packages/memory/dist/corpus/005-geomicrobiology.md +479 -0
  147. package/packages/memory/dist/corpus/006-aeronomy.md +487 -0
  148. package/packages/memory/dist/corpus/007-paleoclimatology.md +479 -0
  149. package/packages/memory/dist/corpus/008-hydrogeophysics.md +479 -0
  150. package/packages/memory/dist/corpus/009-magnetostratigraphy.md +475 -0
  151. package/packages/memory/dist/corpus/010-isotope-hydrology.md +481 -0
  152. package/packages/memory/dist/corpus/011-speleothem-geochemistry.md +474 -0
  153. package/packages/memory/dist/corpus/012-astrobiogeochemistry.md +475 -0
  154. package/packages/memory/dist/corpus/013-neuroethology.md +483 -0
  155. package/packages/memory/dist/corpus/014-chronophysiology.md +483 -0
  156. package/packages/memory/dist/corpus/015-limnogeochemistry.md +475 -0
  157. package/packages/memory/dist/corpus/016-palynology.md +483 -0
  158. package/packages/memory/dist/corpus/017-volcanotectonics.md +473 -0
  159. package/packages/memory/dist/corpus/018-seismotectonics.md +473 -0
  160. package/packages/memory/dist/corpus/019-biogeomorphology.md +475 -0
  161. package/packages/memory/dist/corpus/020-geobiophysics.md +479 -0
  162. package/packages/memory/dist/corpus/021-phytolith-analysis.md +481 -0
  163. package/packages/memory/dist/corpus/022-archaeometallurgy.md +479 -0
  164. package/packages/memory/dist/corpus/023-paleomagnetism.md +479 -0
  165. package/packages/memory/dist/corpus/024-biocalorimetry.md +475 -0
  166. package/packages/memory/dist/corpus/025-atmospheric-chemiluminescence.md +473 -0
  167. package/packages/memory/dist/corpus/026-cryoseismology.md +479 -0
  168. package/packages/memory/dist/corpus/027-extremophile-radiobiology.md +475 -0
  169. package/packages/memory/dist/corpus/028-heliophysics.md +479 -0
  170. package/packages/memory/dist/corpus/029-astroparticle-geophysics.md +474 -0
  171. package/packages/memory/dist/corpus/030-glaciohydrology.md +479 -0
  172. package/packages/memory/dist/corpus/031-permafrost-microbiology.md +477 -0
  173. package/packages/memory/dist/corpus/032-ecoacoustics.md +479 -0
  174. package/packages/memory/dist/corpus/033-dendroclimatology.md +473 -0
  175. package/packages/memory/dist/corpus/034-ionospheric-tomography.md +477 -0
  176. package/packages/memory/dist/corpus/035-marine-geodesy.md +481 -0
  177. package/packages/memory/dist/corpus/036-sedimentary-ancient-dna.md +481 -0
  178. package/packages/memory/dist/corpus/037-myrmecochory-dynamics.md +474 -0
  179. package/packages/memory/dist/corpus/038-chemosensory-ecology.md +477 -0
  180. package/packages/memory/dist/corpus/039-spintronics-materials.md +479 -0
  181. package/packages/memory/dist/corpus/040-nanotoxicology.md +483 -0
  182. package/packages/memory/dist/corpus/041-cosmochemistry.md +483 -0
  183. package/packages/memory/dist/corpus/042-quaternary-geochronology.md +471 -0
  184. package/packages/memory/dist/corpus/043-biophotonics.md +479 -0
  185. package/packages/memory/dist/corpus/044-evolutionary-morphometrics.md +481 -0
  186. package/packages/memory/dist/corpus/045-cryovolcanology.md +475 -0
  187. package/packages/memory/dist/corpus/046-exoplanet-atmospheric-dynamics.md +479 -0
  188. package/packages/memory/dist/corpus/047-microbial-electrosynthesis.md +477 -0
  189. package/packages/memory/dist/corpus/048-paleoseismology.md +479 -0
  190. package/packages/memory/dist/corpus/049-actinide-geochemistry.md +477 -0
  191. package/packages/memory/dist/corpus/050-quantum-biology.md +489 -0
  192. package/packages/memory/dist/edit.d.ts +10 -0
  193. package/packages/memory/dist/edit.js +43 -0
  194. package/packages/memory/dist/explain.cli.d.ts +8 -0
  195. package/packages/memory/dist/explain.cli.js +9 -0
  196. package/packages/memory/dist/explain.d.ts +8 -0
  197. package/packages/memory/dist/explain.js +77 -0
  198. package/packages/memory/dist/frontmatter.d.ts +9 -0
  199. package/packages/memory/dist/frontmatter.js +217 -0
  200. package/packages/memory/dist/index.d.ts +21 -0
  201. package/packages/memory/dist/index.js +4807 -0
  202. package/packages/memory/dist/index.js.map +7 -0
  203. package/packages/memory/dist/ingest.d.ts +3 -0
  204. package/packages/memory/dist/ingest.js +118 -0
  205. package/packages/memory/dist/init.d.ts +2 -0
  206. package/packages/memory/dist/init.js +24 -0
  207. package/packages/memory/dist/install.d.ts +18 -0
  208. package/packages/memory/dist/install.js +50 -0
  209. package/packages/memory/dist/lock.d.ts +19 -0
  210. package/packages/memory/dist/lock.js +102 -0
  211. package/packages/memory/dist/mcp.d.ts +7 -0
  212. package/packages/memory/dist/mcp.js +58 -0
  213. package/packages/memory/dist/pages.d.ts +4 -0
  214. package/packages/memory/dist/pages.js +92 -0
  215. package/packages/memory/dist/paths.d.ts +12 -0
  216. package/packages/memory/dist/paths.js +34 -0
  217. package/packages/memory/dist/query.d.ts +10 -0
  218. package/packages/memory/dist/query.js +130 -0
  219. package/packages/memory/dist/reconcile.d.ts +9 -0
  220. package/packages/memory/dist/reconcile.js +138 -0
  221. package/packages/memory/dist/resolve-root.d.ts +11 -0
  222. package/packages/memory/dist/resolve-root.js +22 -0
  223. package/packages/memory/dist/search.d.ts +2 -0
  224. package/packages/memory/dist/search.js +29 -0
  225. package/packages/memory/dist/status.d.ts +7 -0
  226. package/packages/memory/dist/status.js +46 -0
  227. package/packages/memory/dist/tokens.d.ts +2 -0
  228. package/packages/memory/dist/tokens.js +71 -0
  229. package/packages/memory/dist/types.d.ts +155 -0
  230. package/packages/memory/dist/types.js +1 -0
  231. package/packages/memory/dist/write.d.ts +9 -0
  232. package/packages/memory/dist/write.js +76 -0
@@ -0,0 +1,3 @@
1
+ import type { IngestOptions, IngestResult, MemoryRoot } from "./types.js";
2
+ export declare const INGEST_PROMPT_VERSION = "v1";
3
+ export declare function ingest(root: MemoryRoot, opts: IngestOptions): Promise<IngestResult>;
@@ -0,0 +1,118 @@
1
+ import * as fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { cacheEnabled, configuredTimeout, resolveAgent } from "@poe-code/poe-code-config";
4
+ import { computeIngestKey, readCacheEntry, writeCacheEntry } from "./cache.js";
5
+ import { MEMORY_INDEX_RELPATH } from "./paths.js";
6
+ import { reconcile, snapshot } from "./reconcile.js";
7
+ import { computeTokenStats } from "./tokens.js";
8
+ export const INGEST_PROMPT_VERSION = "v1";
9
+ export async function ingest(root, opts) {
10
+ const source = await materializeSource(opts.source);
11
+ const indexMdBytes = await fs.readFile(path.join(root, MEMORY_INDEX_RELPATH));
12
+ const configOptions = {
13
+ fs: fs,
14
+ filePath: path.join(inferRepoRoot(root), "poe-code.json")
15
+ };
16
+ const agentId = (await resolveAgent(configOptions, opts.agent ?? null)) ?? opts.agent ?? "claude-code";
17
+ const key = computeIngestKey({
18
+ sourceBytes: source.bytes,
19
+ indexMdBytes,
20
+ promptTemplateVersion: INGEST_PROMPT_VERSION,
21
+ agentId
22
+ });
23
+ if (!opts.force && (await cacheEnabled(configOptions))) {
24
+ const hit = await readCacheEntry(root, key);
25
+ if (hit !== null) {
26
+ return {
27
+ diff: { created: [], updated: [], deleted: [] },
28
+ exitCode: 0,
29
+ durationMs: 0,
30
+ cacheHit: true,
31
+ tokens: await computeTokenStats(root)
32
+ };
33
+ }
34
+ }
35
+ const prompt = buildIngestPrompt(root, source.label, source.text);
36
+ if (opts.dryRun) {
37
+ console.log(prompt);
38
+ return {
39
+ diff: { created: [], updated: [], deleted: [] },
40
+ exitCode: 0,
41
+ durationMs: 0,
42
+ cacheHit: false,
43
+ tokens: await computeTokenStats(root)
44
+ };
45
+ }
46
+ const before = await snapshot(root);
47
+ let exitCode = 1;
48
+ let durationMs = 0;
49
+ let timeoutError;
50
+ try {
51
+ const spawnFn = opts.spawnFn;
52
+ const result = await runWithTimeout(spawnFn?.(agentId, prompt) ?? Promise.resolve({ exitCode: 0, durationMs: 0 }), opts.timeoutMs ?? (await configuredTimeout(configOptions)));
53
+ exitCode = result.exitCode;
54
+ durationMs = result.durationMs;
55
+ }
56
+ catch (error) {
57
+ timeoutError = error instanceof Error ? error : new Error(String(error));
58
+ }
59
+ const diff = await reconcile(root, before, "ingest", opts.reason ?? `ingest ${source.label}`);
60
+ const tokens = await computeTokenStats(root);
61
+ if (timeoutError !== undefined) {
62
+ throw timeoutError;
63
+ }
64
+ if (!opts.noCacheWrite && (await cacheEnabled(configOptions)) && exitCode === 0) {
65
+ await writeCacheEntry(root, {
66
+ key,
67
+ ingestedAt: new Date().toISOString(),
68
+ sourceLabel: source.label,
69
+ diff,
70
+ exitCode,
71
+ durationMs,
72
+ memoryTokens: tokens.memoryTokens,
73
+ sourceTokens: tokens.sourceTokens,
74
+ promptTemplateVersion: INGEST_PROMPT_VERSION,
75
+ agentId
76
+ });
77
+ }
78
+ return { diff, exitCode, durationMs, cacheHit: false, tokens };
79
+ }
80
+ function buildIngestPrompt(root, sourceLabel, sourceText) {
81
+ return [
82
+ `Prompt version: ${INGEST_PROMPT_VERSION}`,
83
+ `Memory root: ${root}`,
84
+ `Source: ${sourceLabel}`,
85
+ "Update memory pages under pages/ only. Do not edit INDEX.md directly.",
86
+ "Add confidence tags to non-trivial claims.",
87
+ "",
88
+ sourceText
89
+ ].join("\n");
90
+ }
91
+ async function materializeSource(source) {
92
+ if (source.kind === "file") {
93
+ const bytes = await fs.readFile(source.absPath);
94
+ return {
95
+ label: source.absPath,
96
+ bytes,
97
+ text: bytes.toString("utf8")
98
+ };
99
+ }
100
+ throw new Error("URL ingest not implemented yet.");
101
+ }
102
+ function inferRepoRoot(root) {
103
+ return path.resolve(root, "..", "..");
104
+ }
105
+ async function runWithTimeout(promise, timeoutMs) {
106
+ return await new Promise((resolve, reject) => {
107
+ const timer = setTimeout(() => {
108
+ reject(new Error(`ingest timed out after ${timeoutMs}ms`));
109
+ }, timeoutMs);
110
+ promise.then((value) => {
111
+ clearTimeout(timer);
112
+ resolve(value);
113
+ }, (error) => {
114
+ clearTimeout(timer);
115
+ reject(error);
116
+ });
117
+ });
118
+ }
@@ -0,0 +1,2 @@
1
+ import type { MemoryRoot } from "./types.js";
2
+ export declare function initMemory(root: MemoryRoot): Promise<void>;
@@ -0,0 +1,24 @@
1
+ import * as fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { MEMORY_INDEX_RELPATH, MEMORY_LOG_RELPATH, MEMORY_PAGES_DIR_RELPATH } from "./paths.js";
4
+ export async function initMemory(root) {
5
+ await fs.mkdir(path.join(root, MEMORY_PAGES_DIR_RELPATH), { recursive: true });
6
+ await writeFileIfMissing(path.join(root, MEMORY_INDEX_RELPATH), "# Memory index\n");
7
+ await writeFileIfMissing(path.join(root, MEMORY_LOG_RELPATH), "");
8
+ }
9
+ async function writeFileIfMissing(filePath, content) {
10
+ try {
11
+ await fs.writeFile(filePath, content, { encoding: "utf8", flag: "wx" });
12
+ }
13
+ catch (error) {
14
+ if (!hasErrorCode(error, "EEXIST")) {
15
+ throw error;
16
+ }
17
+ }
18
+ }
19
+ function hasErrorCode(error, code) {
20
+ return (typeof error === "object" &&
21
+ error !== null &&
22
+ "code" in error &&
23
+ error.code === code);
24
+ }
@@ -0,0 +1,18 @@
1
+ import type { ApplyOptions as McpApplyOptions } from "../../agent-mcp-config/dist/index.js";
2
+ import type { FileSystem, MutationObservers } from "../../config-mutations/dist/index.js";
3
+ import type { MemoryInstallResult } from "./types.js";
4
+ export type MemoryInstallOptions = {
5
+ agent: string;
6
+ skillContent: string;
7
+ fs: FileSystem;
8
+ cwd: string;
9
+ homeDir: string;
10
+ platform: McpApplyOptions["platform"];
11
+ scope?: "local" | "global";
12
+ skillOnly?: boolean;
13
+ mcpOnly?: boolean;
14
+ allowWrites?: boolean;
15
+ dryRun?: boolean;
16
+ observers?: MutationObservers;
17
+ };
18
+ export declare function installMemory(options: MemoryInstallOptions): Promise<MemoryInstallResult>;
@@ -0,0 +1,50 @@
1
+ import { installSkill } from "@poe-code/agent-skill-config";
2
+ import { configure } from "@poe-code/agent-mcp-config";
3
+ const SKILL_NAME = "poe-code-memory";
4
+ export async function installMemory(options) {
5
+ if (options.skillOnly && options.mcpOnly) {
6
+ throw new Error("--skill-only and --mcp-only cannot be combined.");
7
+ }
8
+ const scope = options.scope ?? "local";
9
+ let skillPath;
10
+ if (!options.mcpOnly) {
11
+ const installed = await installSkill(options.agent, {
12
+ name: SKILL_NAME,
13
+ content: options.skillContent
14
+ }, {
15
+ fs: options.fs,
16
+ cwd: options.cwd,
17
+ homeDir: options.homeDir,
18
+ scope,
19
+ dryRun: options.dryRun,
20
+ observers: options.observers
21
+ });
22
+ skillPath = installed.displayPath;
23
+ }
24
+ let mcpConfigPath;
25
+ if (!options.skillOnly) {
26
+ await configure(options.agent, {
27
+ name: SKILL_NAME,
28
+ config: {
29
+ transport: "stdio",
30
+ command: "poe-code",
31
+ args: options.allowWrites ? ["memory-mcp", "--allow-writes"] : ["memory-mcp"]
32
+ }
33
+ }, {
34
+ fs: options.fs,
35
+ homeDir: options.homeDir,
36
+ platform: options.platform,
37
+ dryRun: options.dryRun,
38
+ observers: options.observers
39
+ });
40
+ mcpConfigPath = options.agent === "codex"
41
+ ? `${options.homeDir}/.config/codex/mcp-config.json`
42
+ : `${options.homeDir}/.mcp.json`;
43
+ }
44
+ return {
45
+ skillInstalled: !options.mcpOnly,
46
+ mcpConfigured: !options.skillOnly,
47
+ skillPath,
48
+ mcpConfigPath
49
+ };
50
+ }
@@ -0,0 +1,19 @@
1
+ import type { MemoryRoot } from "./types.js";
2
+ interface LockFileSystem {
3
+ readFile(path: string, encoding: BufferEncoding): Promise<string>;
4
+ unlink(path: string): Promise<void>;
5
+ writeFile(path: string, data: string, options?: {
6
+ encoding?: BufferEncoding;
7
+ flag?: string;
8
+ }): Promise<void>;
9
+ }
10
+ export interface LockOptions {
11
+ fs?: LockFileSystem;
12
+ isPidRunning?: (pid: number) => boolean;
13
+ maxTimeoutMs?: number;
14
+ minTimeoutMs?: number;
15
+ pid?: number;
16
+ retries?: number;
17
+ }
18
+ export declare function withLock<TResult>(root: MemoryRoot, run: () => Promise<TResult> | TResult, options?: LockOptions): Promise<TResult>;
19
+ export {};
@@ -0,0 +1,102 @@
1
+ import * as fsPromises from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { MEMORY_LOCK_RELPATH } from "./paths.js";
4
+ function createDefaultFs() {
5
+ return {
6
+ readFile: (filePath, encoding) => fsPromises.readFile(filePath, encoding),
7
+ unlink: fsPromises.unlink,
8
+ writeFile: (filePath, data, options) => fsPromises.writeFile(filePath, data, options)
9
+ };
10
+ }
11
+ function sleep(ms) {
12
+ return new Promise((resolve) => setTimeout(resolve, ms));
13
+ }
14
+ function hasErrorCode(error, code) {
15
+ return (typeof error === "object" &&
16
+ error !== null &&
17
+ "code" in error &&
18
+ error.code === code);
19
+ }
20
+ function lockDelay(attempt, minTimeoutMs, maxTimeoutMs) {
21
+ return Math.min(maxTimeoutMs, minTimeoutMs * Math.pow(2, attempt));
22
+ }
23
+ function parsePid(input) {
24
+ const value = input.trim();
25
+ if (value.length === 0) {
26
+ return undefined;
27
+ }
28
+ for (const char of value) {
29
+ if (char < "0" || char > "9") {
30
+ return undefined;
31
+ }
32
+ }
33
+ const pid = Number.parseInt(value, 10);
34
+ return Number.isSafeInteger(pid) && pid > 0 ? pid : undefined;
35
+ }
36
+ function isPidRunning(pid) {
37
+ try {
38
+ process.kill(pid, 0);
39
+ return true;
40
+ }
41
+ catch (error) {
42
+ return !hasErrorCode(error, "ESRCH");
43
+ }
44
+ }
45
+ async function removeLockFile(fs, lockPath) {
46
+ try {
47
+ await fs.unlink(lockPath);
48
+ }
49
+ catch (error) {
50
+ if (!hasErrorCode(error, "ENOENT")) {
51
+ throw error;
52
+ }
53
+ }
54
+ }
55
+ async function readLockPid(fs, lockPath) {
56
+ try {
57
+ return parsePid(await fs.readFile(lockPath, "utf8"));
58
+ }
59
+ catch (error) {
60
+ if (hasErrorCode(error, "ENOENT")) {
61
+ return null;
62
+ }
63
+ throw error;
64
+ }
65
+ }
66
+ export async function withLock(root, run, options = {}) {
67
+ const fs = options.fs ?? createDefaultFs();
68
+ const lockPath = path.join(root, MEMORY_LOCK_RELPATH);
69
+ const pid = options.pid ?? process.pid;
70
+ const retries = options.retries ?? 20;
71
+ const minTimeoutMs = options.minTimeoutMs ?? 25;
72
+ const maxTimeoutMs = options.maxTimeoutMs ?? 250;
73
+ const pidIsRunning = options.isPidRunning ?? isPidRunning;
74
+ for (let attempt = 0; attempt <= retries; attempt += 1) {
75
+ try {
76
+ await fs.writeFile(lockPath, `${pid}\n`, { encoding: "utf8", flag: "wx" });
77
+ try {
78
+ return await run();
79
+ }
80
+ finally {
81
+ await removeLockFile(fs, lockPath);
82
+ }
83
+ }
84
+ catch (error) {
85
+ if (!hasErrorCode(error, "EEXIST")) {
86
+ throw error;
87
+ }
88
+ }
89
+ const existingPid = await readLockPid(fs, lockPath);
90
+ if (existingPid === null) {
91
+ continue;
92
+ }
93
+ if (existingPid === undefined || !pidIsRunning(existingPid)) {
94
+ await removeLockFile(fs, lockPath);
95
+ continue;
96
+ }
97
+ if (attempt < retries) {
98
+ await sleep(lockDelay(attempt, minTimeoutMs, maxTimeoutMs));
99
+ }
100
+ }
101
+ throw new Error(`Failed to acquire memory lock at "${lockPath}".`);
102
+ }
@@ -0,0 +1,7 @@
1
+ import type { Server } from "../../tiny-stdio-mcp-server/dist/index.js";
2
+ import type { McpServerOptions } from "./types.js";
3
+ export declare function startMemoryMcpServer(opts: McpServerOptions): Promise<{
4
+ stop: () => Promise<void>;
5
+ server: Server;
6
+ }>;
7
+ export declare function printMcpConfig(): string;
@@ -0,0 +1,58 @@
1
+ import { createServer, defineSchema } from "tiny-stdio-mcp-server";
2
+ import { appendToPage } from "./write.js";
3
+ import { listPages, readPage } from "./pages.js";
4
+ import { searchMemory } from "./search.js";
5
+ import { statusOf } from "./status.js";
6
+ export async function startMemoryMcpServer(opts) {
7
+ const server = createServer({
8
+ name: "poe-code-memory",
9
+ version: "0.0.1"
10
+ });
11
+ server.tool("list_pages", "List memory pages.", defineSchema({}), async () => ({
12
+ pages: (await listPages(opts.root)).map((page) => ({
13
+ rel_path: page.relPath,
14
+ description: page.frontmatter.description ?? ""
15
+ }))
16
+ }));
17
+ server.tool("read_page", "Read a memory page.", defineSchema({ rel_path: { type: "string" } }), async ({ rel_path }) => {
18
+ const page = await readPage(opts.root, rel_path);
19
+ return {
20
+ rel_path: page.relPath,
21
+ frontmatter: page.frontmatter,
22
+ body: page.body,
23
+ bytes: page.bytes
24
+ };
25
+ });
26
+ server.tool("search_memory", "Search memory pages.", defineSchema({
27
+ query: { type: "string" },
28
+ limit: { type: "number", optional: true }
29
+ }), async ({ query, limit }) => {
30
+ const hits = await searchMemory(opts.root, query);
31
+ return { hits: typeof limit === "number" ? hits.slice(0, limit) : hits };
32
+ });
33
+ server.tool("status", "Show memory status.", defineSchema({}), async () => statusOf(opts.root));
34
+ if (opts.allowWrites) {
35
+ server.tool("append_to_page", "Append content to a memory page.", defineSchema({
36
+ rel_path: { type: "string" },
37
+ content: { type: "string" },
38
+ reason: { type: "string" }
39
+ }), async ({ rel_path, content, reason }) => ({
40
+ diff: await appendToPage(opts.root, rel_path, content, { reason })
41
+ }));
42
+ }
43
+ return {
44
+ server,
45
+ stop: async () => { },
46
+ };
47
+ }
48
+ export function printMcpConfig() {
49
+ return JSON.stringify({
50
+ mcpServers: {
51
+ "poe-code-memory": {
52
+ type: "stdio",
53
+ command: "poe-code",
54
+ args: ["memory-mcp"]
55
+ }
56
+ }
57
+ }, null, 2);
58
+ }
@@ -0,0 +1,4 @@
1
+ import type { MemoryPage, MemoryRoot } from "./types.js";
2
+ export declare function listPages(root: MemoryRoot): Promise<MemoryPage[]>;
3
+ export declare function readPage(root: MemoryRoot, relPath: string): Promise<MemoryPage>;
4
+ export declare function collectMarkdownRelPaths(root: MemoryRoot, startRelPath?: string): Promise<string[]>;
@@ -0,0 +1,92 @@
1
+ import * as fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { parseFrontmatter } from "./frontmatter.js";
4
+ import { assertSafeRelPath, MEMORY_CACHE_DIR_RELPATH, MEMORY_LOCK_RELPATH, MEMORY_PAGES_DIR_RELPATH } from "./paths.js";
5
+ export async function listPages(root) {
6
+ const relPaths = await collectMarkdownRelPaths(root, MEMORY_PAGES_DIR_RELPATH);
7
+ const pages = await Promise.all(relPaths.map(async (relPath) => readPage(root, relPath)));
8
+ return pages.sort((left, right) => left.relPath.localeCompare(right.relPath));
9
+ }
10
+ export async function readPage(root, relPath) {
11
+ const normalizedRelPath = assertMarkdownRelPath(relPath);
12
+ const absPath = path.join(root, normalizedRelPath);
13
+ const [content, stat] = await Promise.all([fs.readFile(absPath, "utf8"), fs.stat(absPath)]);
14
+ try {
15
+ const parsed = parseFrontmatter(content);
16
+ return {
17
+ relPath: normalizedRelPath,
18
+ frontmatter: parsed.frontmatter,
19
+ body: parsed.body,
20
+ bytes: Buffer.byteLength(content),
21
+ mtimeMs: stat.mtimeMs
22
+ };
23
+ }
24
+ catch (error) {
25
+ const message = error instanceof Error ? error.message : String(error);
26
+ console.warn(`Failed to parse frontmatter for "${normalizedRelPath}": ${message}`);
27
+ return {
28
+ relPath: normalizedRelPath,
29
+ frontmatter: {},
30
+ body: content,
31
+ bytes: Buffer.byteLength(content),
32
+ mtimeMs: stat.mtimeMs
33
+ };
34
+ }
35
+ }
36
+ export async function collectMarkdownRelPaths(root, startRelPath = "") {
37
+ const relPaths = [];
38
+ await collectMarkdownRelPathsInto(root, startRelPath, relPaths);
39
+ return relPaths.sort((left, right) => left.localeCompare(right));
40
+ }
41
+ async function collectMarkdownRelPathsInto(root, currentRelPath, relPaths) {
42
+ const absPath = path.join(root, currentRelPath);
43
+ let entryNames;
44
+ try {
45
+ entryNames = await fs.readdir(absPath);
46
+ }
47
+ catch (error) {
48
+ if (isMissing(error)) {
49
+ return;
50
+ }
51
+ throw error;
52
+ }
53
+ for (const entryName of entryNames.sort((left, right) => left.localeCompare(right))) {
54
+ const entryRelPath = currentRelPath.length === 0 ? entryName : path.posix.join(currentRelPath, entryName);
55
+ const entryAbsPath = path.join(root, entryRelPath);
56
+ const entryStat = await fs.stat(entryAbsPath);
57
+ if (entryStat.isDirectory()) {
58
+ if (entryName === MEMORY_CACHE_DIR_RELPATH) {
59
+ continue;
60
+ }
61
+ await collectMarkdownRelPathsInto(root, entryRelPath, relPaths);
62
+ continue;
63
+ }
64
+ if (!entryStat.isFile()) {
65
+ continue;
66
+ }
67
+ if (!isMarkdownPath(entryRelPath)) {
68
+ if (entryName === MEMORY_LOCK_RELPATH) {
69
+ continue;
70
+ }
71
+ console.warn(`Skipping non-markdown memory file "${entryRelPath}".`);
72
+ continue;
73
+ }
74
+ relPaths.push(entryRelPath);
75
+ }
76
+ }
77
+ function assertMarkdownRelPath(relPath) {
78
+ const normalizedRelPath = assertSafeRelPath(relPath);
79
+ if (!isMarkdownPath(normalizedRelPath)) {
80
+ throw new Error(`Expected a markdown path, received "${relPath}".`);
81
+ }
82
+ return normalizedRelPath;
83
+ }
84
+ function isMarkdownPath(relPath) {
85
+ return path.posix.extname(relPath).toLowerCase() === ".md";
86
+ }
87
+ function isMissing(error) {
88
+ return (typeof error === "object" &&
89
+ error !== null &&
90
+ "code" in error &&
91
+ error.code === "ENOENT");
92
+ }
@@ -0,0 +1,12 @@
1
+ import type { MemoryRoot } from "./types.js";
2
+ export declare const MEMORY_INDEX_RELPATH = "INDEX.md";
3
+ export declare const MEMORY_LOG_RELPATH = "LOG.md";
4
+ export declare const MEMORY_LOCK_RELPATH = ".lock";
5
+ export declare const MEMORY_PAGES_DIR_RELPATH = "pages";
6
+ export declare const MEMORY_CACHE_DIR_RELPATH = ".cache";
7
+ export declare const MEMORY_INGEST_CACHE_DIR_RELPATH = ".cache/ingest";
8
+ export declare class MemoryPathError extends Error {
9
+ constructor(message: string);
10
+ }
11
+ export declare function resolveMemoryRoot(cwd: string): MemoryRoot;
12
+ export declare function assertSafeRelPath(input: string): string;
@@ -0,0 +1,34 @@
1
+ import path from "node:path";
2
+ export const MEMORY_INDEX_RELPATH = "INDEX.md";
3
+ export const MEMORY_LOG_RELPATH = "LOG.md";
4
+ export const MEMORY_LOCK_RELPATH = ".lock";
5
+ export const MEMORY_PAGES_DIR_RELPATH = "pages";
6
+ export const MEMORY_CACHE_DIR_RELPATH = ".cache";
7
+ export const MEMORY_INGEST_CACHE_DIR_RELPATH = `${MEMORY_CACHE_DIR_RELPATH}/ingest`;
8
+ export class MemoryPathError extends Error {
9
+ constructor(message) {
10
+ super(message);
11
+ this.name = "MemoryPathError";
12
+ }
13
+ }
14
+ export function resolveMemoryRoot(cwd) {
15
+ return path.resolve(cwd, ".poe-code", "memory");
16
+ }
17
+ export function assertSafeRelPath(input) {
18
+ const trimmed = input.trim();
19
+ if (trimmed.length === 0) {
20
+ throw new MemoryPathError("Expected a non-empty relative path.");
21
+ }
22
+ const slashNormalized = trimmed.replaceAll("\\", "/");
23
+ if (path.posix.isAbsolute(slashNormalized) || path.win32.isAbsolute(slashNormalized)) {
24
+ throw new MemoryPathError(`Expected a relative path, received absolute path "${input}".`);
25
+ }
26
+ const normalized = path.posix.normalize(slashNormalized);
27
+ if (normalized === "." || normalized.length === 0) {
28
+ throw new MemoryPathError("Expected a relative path to a file or directory.");
29
+ }
30
+ if (normalized === ".." || normalized.startsWith("../")) {
31
+ throw new MemoryPathError(`Relative path "${input}" cannot escape the memory root.`);
32
+ }
33
+ return normalized;
34
+ }
@@ -0,0 +1,10 @@
1
+ import type { MemoryPage, MemoryRoot, QueryOptions, QueryResult } from "./types.js";
2
+ export type QueryContext = {
3
+ prompt: string;
4
+ selectedPages: MemoryPage[];
5
+ tokensUsed: number;
6
+ truncated: boolean;
7
+ };
8
+ export declare function queryMemory(root: MemoryRoot, options: QueryOptions): Promise<QueryResult>;
9
+ export declare function selectQueryContext(root: MemoryRoot, question: string, budget: number): Promise<QueryContext>;
10
+ export declare function rankPagesForQuery(pages: MemoryPage[], question: string): MemoryPage[];