poe-code 3.0.184 → 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 (228) 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.js +32 -48
  16. package/dist/cli/commands/pipeline-init.js.map +1 -1
  17. package/dist/cli/commands/pipeline.js +89 -77
  18. package/dist/cli/commands/pipeline.js.map +1 -1
  19. package/dist/cli/commands/provider.d.ts +6 -0
  20. package/dist/cli/commands/provider.js +100 -0
  21. package/dist/cli/commands/provider.js.map +1 -0
  22. package/dist/cli/commands/shared.d.ts +7 -0
  23. package/dist/cli/commands/shared.js +3 -0
  24. package/dist/cli/commands/shared.js.map +1 -1
  25. package/dist/cli/commands/test.js +1 -1
  26. package/dist/cli/commands/test.js.map +1 -1
  27. package/dist/cli/commands/unconfigure.js +12 -3
  28. package/dist/cli/commands/unconfigure.js.map +1 -1
  29. package/dist/cli/container.d.ts +2 -0
  30. package/dist/cli/container.js +3 -0
  31. package/dist/cli/container.js.map +1 -1
  32. package/dist/cli/isolated-env-runner.js +2 -2
  33. package/dist/cli/isolated-env-runner.js.map +1 -1
  34. package/dist/cli/isolated-env.d.ts +3 -2
  35. package/dist/cli/isolated-env.js +31 -40
  36. package/dist/cli/isolated-env.js.map +1 -1
  37. package/dist/cli/poe-code-command-runner.js +9 -2
  38. package/dist/cli/poe-code-command-runner.js.map +1 -1
  39. package/dist/cli/program.js +5 -0
  40. package/dist/cli/program.js.map +1 -1
  41. package/dist/cli/service-registry.d.ts +7 -7
  42. package/dist/cli/service-registry.js.map +1 -1
  43. package/dist/index.js +2491 -1911
  44. package/dist/index.js.map +4 -4
  45. package/dist/providers/claude-code.d.ts +2 -1
  46. package/dist/providers/claude-code.js +5 -5
  47. package/dist/providers/claude-code.js.map +2 -2
  48. package/dist/providers/codex.d.ts +5 -1
  49. package/dist/providers/codex.js +39 -12
  50. package/dist/providers/codex.js.map +2 -2
  51. package/dist/providers/goose.d.ts +2 -1
  52. package/dist/providers/goose.js +24 -8
  53. package/dist/providers/goose.js.map +3 -3
  54. package/dist/providers/kimi.js +3 -3
  55. package/dist/providers/kimi.js.map +3 -3
  56. package/dist/providers/opencode.js +2 -2
  57. package/dist/providers/opencode.js.map +3 -3
  58. package/dist/providers/poe-agent.js +753 -649
  59. package/dist/providers/poe-agent.js.map +4 -4
  60. package/dist/sdk/container.js +3 -0
  61. package/dist/sdk/container.js.map +1 -1
  62. package/dist/sdk/pipeline.d.ts +1 -2
  63. package/dist/sdk/pipeline.js +51 -119
  64. package/dist/sdk/pipeline.js.map +1 -1
  65. package/dist/services/config.d.ts +1 -0
  66. package/dist/services/config.js +27 -2
  67. package/dist/services/config.js.map +1 -1
  68. package/dist/templates/pipeline/SKILL_plan.md +16 -42
  69. package/package.json +10 -1
  70. package/packages/agent-mcp-config/dist/apply.d.ts +6 -0
  71. package/packages/agent-mcp-config/dist/apply.js +175 -0
  72. package/packages/agent-mcp-config/dist/configs.d.ts +22 -0
  73. package/packages/agent-mcp-config/dist/configs.js +74 -0
  74. package/packages/agent-mcp-config/dist/index.d.ts +3 -0
  75. package/packages/agent-mcp-config/dist/index.js +2 -0
  76. package/packages/agent-mcp-config/dist/shapes.d.ts +31 -0
  77. package/packages/agent-mcp-config/dist/shapes.js +87 -0
  78. package/packages/agent-mcp-config/dist/types.d.ts +25 -0
  79. package/packages/agent-mcp-config/dist/types.js +1 -0
  80. package/packages/agent-skill-config/dist/apply.d.ts +25 -0
  81. package/packages/agent-skill-config/dist/apply.js +109 -0
  82. package/packages/agent-skill-config/dist/configs.d.ts +16 -0
  83. package/packages/agent-skill-config/dist/configs.js +66 -0
  84. package/packages/agent-skill-config/dist/exports.compile-check.d.ts +1 -0
  85. package/packages/agent-skill-config/dist/exports.compile-check.js +1 -0
  86. package/packages/agent-skill-config/dist/index.d.ts +5 -0
  87. package/packages/agent-skill-config/dist/index.js +2 -0
  88. package/packages/agent-skill-config/dist/templates/poe-generate.md +47 -0
  89. package/packages/agent-skill-config/dist/templates/terminal-pilot.md +45 -0
  90. package/packages/agent-skill-config/dist/templates.d.ts +3 -0
  91. package/packages/agent-skill-config/dist/templates.js +63 -0
  92. package/packages/agent-skill-config/dist/types.d.ts +16 -0
  93. package/packages/agent-skill-config/dist/types.js +1 -0
  94. package/packages/cmdkit/dist/cli.js +7 -2
  95. package/packages/cmdkit/dist/cli.js.map +2 -2
  96. package/packages/config-mutations/dist/execution/apply-mutation.d.ts +5 -0
  97. package/packages/config-mutations/dist/execution/apply-mutation.js +552 -0
  98. package/packages/config-mutations/dist/execution/path-utils.d.ts +17 -0
  99. package/packages/config-mutations/dist/execution/path-utils.js +58 -0
  100. package/packages/config-mutations/dist/execution/run-mutations.d.ts +7 -0
  101. package/packages/config-mutations/dist/execution/run-mutations.js +46 -0
  102. package/packages/config-mutations/dist/formats/index.d.ts +13 -0
  103. package/packages/config-mutations/dist/formats/index.js +49 -0
  104. package/packages/config-mutations/dist/formats/json.d.ts +31 -0
  105. package/packages/config-mutations/dist/formats/json.js +140 -0
  106. package/packages/config-mutations/dist/formats/toml.d.ts +2 -0
  107. package/packages/config-mutations/dist/formats/toml.js +72 -0
  108. package/packages/config-mutations/dist/formats/yaml.d.ts +2 -0
  109. package/packages/config-mutations/dist/formats/yaml.js +73 -0
  110. package/packages/config-mutations/dist/fs-utils.d.ts +18 -0
  111. package/packages/config-mutations/dist/fs-utils.js +45 -0
  112. package/packages/config-mutations/dist/index.d.ts +8 -0
  113. package/packages/config-mutations/dist/index.js +8 -0
  114. package/packages/config-mutations/dist/mutations/config-mutation.d.ts +47 -0
  115. package/packages/config-mutations/dist/mutations/config-mutation.js +34 -0
  116. package/packages/config-mutations/dist/mutations/file-mutation.d.ts +52 -0
  117. package/packages/config-mutations/dist/mutations/file-mutation.js +46 -0
  118. package/packages/config-mutations/dist/mutations/template-mutation.d.ts +40 -0
  119. package/packages/config-mutations/dist/mutations/template-mutation.js +32 -0
  120. package/packages/config-mutations/dist/template/render.d.ts +7 -0
  121. package/packages/config-mutations/dist/template/render.js +28 -0
  122. package/packages/config-mutations/dist/testing/format-utils.d.ts +7 -0
  123. package/packages/config-mutations/dist/testing/format-utils.js +21 -0
  124. package/packages/config-mutations/dist/testing/index.d.ts +3 -0
  125. package/packages/config-mutations/dist/testing/index.js +2 -0
  126. package/packages/config-mutations/dist/testing/mock-fs.d.ts +25 -0
  127. package/packages/config-mutations/dist/testing/mock-fs.js +170 -0
  128. package/packages/config-mutations/dist/types.d.ts +156 -0
  129. package/packages/config-mutations/dist/types.js +6 -0
  130. package/packages/memory/dist/audit.d.ts +11 -0
  131. package/packages/memory/dist/audit.js +131 -0
  132. package/packages/memory/dist/cache.cli.d.ts +9 -0
  133. package/packages/memory/dist/cache.cli.js +24 -0
  134. package/packages/memory/dist/cache.d.ts +14 -0
  135. package/packages/memory/dist/cache.js +149 -0
  136. package/packages/memory/dist/confidence.d.ts +4 -0
  137. package/packages/memory/dist/confidence.js +201 -0
  138. package/packages/memory/dist/corpus/001-archaeoastronomy.md +479 -0
  139. package/packages/memory/dist/corpus/002-magnetohydrodynamics.md +475 -0
  140. package/packages/memory/dist/corpus/003-biosemiotics.md +483 -0
  141. package/packages/memory/dist/corpus/004-cryopedology.md +483 -0
  142. package/packages/memory/dist/corpus/005-geomicrobiology.md +479 -0
  143. package/packages/memory/dist/corpus/006-aeronomy.md +487 -0
  144. package/packages/memory/dist/corpus/007-paleoclimatology.md +479 -0
  145. package/packages/memory/dist/corpus/008-hydrogeophysics.md +479 -0
  146. package/packages/memory/dist/corpus/009-magnetostratigraphy.md +475 -0
  147. package/packages/memory/dist/corpus/010-isotope-hydrology.md +481 -0
  148. package/packages/memory/dist/corpus/011-speleothem-geochemistry.md +474 -0
  149. package/packages/memory/dist/corpus/012-astrobiogeochemistry.md +475 -0
  150. package/packages/memory/dist/corpus/013-neuroethology.md +483 -0
  151. package/packages/memory/dist/corpus/014-chronophysiology.md +483 -0
  152. package/packages/memory/dist/corpus/015-limnogeochemistry.md +475 -0
  153. package/packages/memory/dist/corpus/016-palynology.md +483 -0
  154. package/packages/memory/dist/corpus/017-volcanotectonics.md +473 -0
  155. package/packages/memory/dist/corpus/018-seismotectonics.md +473 -0
  156. package/packages/memory/dist/corpus/019-biogeomorphology.md +475 -0
  157. package/packages/memory/dist/corpus/020-geobiophysics.md +479 -0
  158. package/packages/memory/dist/corpus/021-phytolith-analysis.md +481 -0
  159. package/packages/memory/dist/corpus/022-archaeometallurgy.md +479 -0
  160. package/packages/memory/dist/corpus/023-paleomagnetism.md +479 -0
  161. package/packages/memory/dist/corpus/024-biocalorimetry.md +475 -0
  162. package/packages/memory/dist/corpus/025-atmospheric-chemiluminescence.md +473 -0
  163. package/packages/memory/dist/corpus/026-cryoseismology.md +479 -0
  164. package/packages/memory/dist/corpus/027-extremophile-radiobiology.md +475 -0
  165. package/packages/memory/dist/corpus/028-heliophysics.md +479 -0
  166. package/packages/memory/dist/corpus/029-astroparticle-geophysics.md +474 -0
  167. package/packages/memory/dist/corpus/030-glaciohydrology.md +479 -0
  168. package/packages/memory/dist/corpus/031-permafrost-microbiology.md +477 -0
  169. package/packages/memory/dist/corpus/032-ecoacoustics.md +479 -0
  170. package/packages/memory/dist/corpus/033-dendroclimatology.md +473 -0
  171. package/packages/memory/dist/corpus/034-ionospheric-tomography.md +477 -0
  172. package/packages/memory/dist/corpus/035-marine-geodesy.md +481 -0
  173. package/packages/memory/dist/corpus/036-sedimentary-ancient-dna.md +481 -0
  174. package/packages/memory/dist/corpus/037-myrmecochory-dynamics.md +474 -0
  175. package/packages/memory/dist/corpus/038-chemosensory-ecology.md +477 -0
  176. package/packages/memory/dist/corpus/039-spintronics-materials.md +479 -0
  177. package/packages/memory/dist/corpus/040-nanotoxicology.md +483 -0
  178. package/packages/memory/dist/corpus/041-cosmochemistry.md +483 -0
  179. package/packages/memory/dist/corpus/042-quaternary-geochronology.md +471 -0
  180. package/packages/memory/dist/corpus/043-biophotonics.md +479 -0
  181. package/packages/memory/dist/corpus/044-evolutionary-morphometrics.md +481 -0
  182. package/packages/memory/dist/corpus/045-cryovolcanology.md +475 -0
  183. package/packages/memory/dist/corpus/046-exoplanet-atmospheric-dynamics.md +479 -0
  184. package/packages/memory/dist/corpus/047-microbial-electrosynthesis.md +477 -0
  185. package/packages/memory/dist/corpus/048-paleoseismology.md +479 -0
  186. package/packages/memory/dist/corpus/049-actinide-geochemistry.md +477 -0
  187. package/packages/memory/dist/corpus/050-quantum-biology.md +489 -0
  188. package/packages/memory/dist/edit.d.ts +10 -0
  189. package/packages/memory/dist/edit.js +43 -0
  190. package/packages/memory/dist/explain.cli.d.ts +8 -0
  191. package/packages/memory/dist/explain.cli.js +9 -0
  192. package/packages/memory/dist/explain.d.ts +8 -0
  193. package/packages/memory/dist/explain.js +77 -0
  194. package/packages/memory/dist/frontmatter.d.ts +9 -0
  195. package/packages/memory/dist/frontmatter.js +217 -0
  196. package/packages/memory/dist/index.d.ts +21 -0
  197. package/packages/memory/dist/index.js +4807 -0
  198. package/packages/memory/dist/index.js.map +7 -0
  199. package/packages/memory/dist/ingest.d.ts +3 -0
  200. package/packages/memory/dist/ingest.js +118 -0
  201. package/packages/memory/dist/init.d.ts +2 -0
  202. package/packages/memory/dist/init.js +24 -0
  203. package/packages/memory/dist/install.d.ts +18 -0
  204. package/packages/memory/dist/install.js +50 -0
  205. package/packages/memory/dist/lock.d.ts +19 -0
  206. package/packages/memory/dist/lock.js +102 -0
  207. package/packages/memory/dist/mcp.d.ts +7 -0
  208. package/packages/memory/dist/mcp.js +58 -0
  209. package/packages/memory/dist/pages.d.ts +4 -0
  210. package/packages/memory/dist/pages.js +92 -0
  211. package/packages/memory/dist/paths.d.ts +12 -0
  212. package/packages/memory/dist/paths.js +34 -0
  213. package/packages/memory/dist/query.d.ts +10 -0
  214. package/packages/memory/dist/query.js +130 -0
  215. package/packages/memory/dist/reconcile.d.ts +9 -0
  216. package/packages/memory/dist/reconcile.js +138 -0
  217. package/packages/memory/dist/resolve-root.d.ts +11 -0
  218. package/packages/memory/dist/resolve-root.js +22 -0
  219. package/packages/memory/dist/search.d.ts +2 -0
  220. package/packages/memory/dist/search.js +29 -0
  221. package/packages/memory/dist/status.d.ts +7 -0
  222. package/packages/memory/dist/status.js +46 -0
  223. package/packages/memory/dist/tokens.d.ts +2 -0
  224. package/packages/memory/dist/tokens.js +71 -0
  225. package/packages/memory/dist/types.d.ts +155 -0
  226. package/packages/memory/dist/types.js +1 -0
  227. package/packages/memory/dist/write.d.ts +9 -0
  228. package/packages/memory/dist/write.js +76 -0
@@ -0,0 +1,130 @@
1
+ import * as fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { countTokens } from "tokenfill";
4
+ import { resolveAgent } from "@poe-code/poe-code-config";
5
+ import { listPages } from "./pages.js";
6
+ import { MEMORY_INDEX_RELPATH } from "./paths.js";
7
+ export async function queryMemory(root, options) {
8
+ const pages = await listPages(root);
9
+ if (pages.length === 0) {
10
+ return {
11
+ answer: "",
12
+ citations: [],
13
+ tokensUsed: 0,
14
+ budget: options.budget,
15
+ exitCode: 0
16
+ };
17
+ }
18
+ const configOptions = {
19
+ fs: fs,
20
+ filePath: path.join(inferRepoRoot(root), "poe-code.json")
21
+ };
22
+ const agentId = (await resolveAgent(configOptions, options.agent ?? null)) ?? options.agent ?? "claude-code";
23
+ const context = await selectQueryContext(root, options.question, options.budget);
24
+ const spawnFn = options.spawnFn;
25
+ const result = (await spawnFn?.(agentId, context.prompt)) ?? {
26
+ answer: "",
27
+ citations: [],
28
+ tokensUsed: context.tokensUsed,
29
+ budget: options.budget,
30
+ exitCode: 0
31
+ };
32
+ return {
33
+ answer: result.answer,
34
+ citations: result.citations,
35
+ tokensUsed: result.tokensUsed,
36
+ budget: options.budget,
37
+ exitCode: result.exitCode
38
+ };
39
+ }
40
+ export async function selectQueryContext(root, question, budget) {
41
+ const [indexText, pages] = await Promise.all([
42
+ fs.readFile(path.join(root, MEMORY_INDEX_RELPATH), "utf8"),
43
+ listPages(root)
44
+ ]);
45
+ const indexTokens = countTokens(indexText);
46
+ if (indexTokens > budget) {
47
+ throw new Error(`budget too small; needs at least ${indexTokens} tokens`);
48
+ }
49
+ const rankedPages = rankPagesForQuery(pages, question);
50
+ const selectedPages = [];
51
+ let tokensUsed = indexTokens;
52
+ let truncated = false;
53
+ for (const page of rankedPages) {
54
+ const pageTokens = countTokens(renderPageContext(page));
55
+ if (tokensUsed + pageTokens > budget) {
56
+ truncated = true;
57
+ continue;
58
+ }
59
+ selectedPages.push(page);
60
+ tokensUsed += pageTokens;
61
+ }
62
+ return {
63
+ prompt: buildQueryPrompt(question, indexText, selectedPages),
64
+ selectedPages,
65
+ tokensUsed,
66
+ truncated
67
+ };
68
+ }
69
+ export function rankPagesForQuery(pages, question) {
70
+ const terms = tokenize(question);
71
+ const documents = pages.map((page) => {
72
+ const text = [page.relPath, page.frontmatter.name ?? "", page.frontmatter.description ?? "", page.body]
73
+ .join("\n")
74
+ .toLowerCase();
75
+ const tokens = tokenize(text);
76
+ const counts = new Map();
77
+ for (const token of tokens) {
78
+ counts.set(token, (counts.get(token) ?? 0) + 1);
79
+ }
80
+ return { page, counts, size: tokens.length };
81
+ });
82
+ const docFrequency = new Map();
83
+ for (const term of terms) {
84
+ let count = 0;
85
+ for (const document of documents) {
86
+ if ((document.counts.get(term) ?? 0) > 0) {
87
+ count += 1;
88
+ }
89
+ }
90
+ docFrequency.set(term, count);
91
+ }
92
+ return documents
93
+ .map((document) => ({
94
+ page: document.page,
95
+ score: terms.reduce((total, term) => {
96
+ const tf = (document.counts.get(term) ?? 0) / Math.max(document.size, 1);
97
+ const idf = Math.log((documents.length + 1) / ((docFrequency.get(term) ?? 0) + 1)) + 1;
98
+ return total + tf * idf;
99
+ }, 0)
100
+ }))
101
+ .sort((left, right) => right.score - left.score || left.page.relPath.localeCompare(right.page.relPath))
102
+ .map((entry) => entry.page);
103
+ }
104
+ function buildQueryPrompt(question, indexText, pages) {
105
+ const renderedPages = pages.map((page) => renderPageContext(page)).join("\n\n");
106
+ return [
107
+ "Answer using only the provided memory pages.",
108
+ "Cite pages and sections with [rel_path §section]. If memory does not answer the question, say so.",
109
+ "No tools are available.",
110
+ "",
111
+ `Question: ${question}`,
112
+ "",
113
+ "INDEX.md",
114
+ indexText,
115
+ "",
116
+ renderedPages
117
+ ].join("\n");
118
+ }
119
+ function renderPageContext(page) {
120
+ return [`FILE: ${page.relPath}`, page.body].join("\n");
121
+ }
122
+ function tokenize(text) {
123
+ return text
124
+ .toLowerCase()
125
+ .split(/[^a-z0-9]+/)
126
+ .filter((token) => token.length > 0);
127
+ }
128
+ function inferRepoRoot(root) {
129
+ return path.resolve(root, "..", "..");
130
+ }
@@ -0,0 +1,9 @@
1
+ import type { LogVerb, MemoryDiff, MemoryRoot, MemorySnapshot, SourceRef } from "./types.js";
2
+ export declare function snapshot(root: MemoryRoot): Promise<MemorySnapshot>;
3
+ export declare function reconcile(root: MemoryRoot, before: MemorySnapshot, _verb: LogVerb, detail: string): Promise<MemoryDiff>;
4
+ export declare function renderIndex(entries: Array<{
5
+ relPath: string;
6
+ description: string;
7
+ }>): string;
8
+ export declare function appendLogEntries(root: MemoryRoot, diff: MemoryDiff, detail: string, timestamp?: string): Promise<void>;
9
+ export declare function denormalizeSources(markdown: string): SourceRef[];
@@ -0,0 +1,138 @@
1
+ import { createHash } from "node:crypto";
2
+ import * as fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ import { parseClaims } from "./confidence.js";
5
+ import { parseFrontmatter, serializeFrontmatter, serializeSourceRef } from "./frontmatter.js";
6
+ import { initMemory } from "./init.js";
7
+ import { collectMarkdownRelPaths, listPages } from "./pages.js";
8
+ import { MEMORY_INDEX_RELPATH, MEMORY_LOG_RELPATH, MEMORY_PAGES_DIR_RELPATH } from "./paths.js";
9
+ export async function snapshot(root) {
10
+ const pages = Object.fromEntries(await Promise.all((await collectMarkdownRelPaths(root, MEMORY_PAGES_DIR_RELPATH)).map(async (relPath) => [
11
+ relPath,
12
+ hashContent(await fs.readFile(path.join(root, relPath), "utf8"))
13
+ ])));
14
+ return { pages };
15
+ }
16
+ export async function reconcile(root, before, _verb, detail) {
17
+ await initMemory(root);
18
+ const timestamp = new Date().toISOString();
19
+ const currentPages = await Promise.all((await collectMarkdownRelPaths(root, MEMORY_PAGES_DIR_RELPATH)).map(async (relPath) => {
20
+ const absPath = path.join(root, relPath);
21
+ const markdown = await fs.readFile(absPath, "utf8");
22
+ const parsed = parsePageMarkdown(relPath, markdown);
23
+ const normalizedFrontmatter = withDenormalizedSources(parsed.frontmatter, parsed.body);
24
+ const normalizedMarkdown = serializeFrontmatter(normalizedFrontmatter, parsed.body);
25
+ const changed = before.pages[relPath] !== hashContent(normalizedMarkdown);
26
+ const nextMarkdown = changed
27
+ ? serializeFrontmatter({
28
+ ...normalizedFrontmatter,
29
+ lastTouchedAt: timestamp
30
+ }, parsed.body)
31
+ : normalizedMarkdown;
32
+ return {
33
+ relPath,
34
+ changed,
35
+ currentMarkdown: markdown,
36
+ nextMarkdown
37
+ };
38
+ }));
39
+ await Promise.all(currentPages
40
+ .filter((page) => page.currentMarkdown !== page.nextMarkdown)
41
+ .map((page) => fs.writeFile(path.join(root, page.relPath), page.nextMarkdown, "utf8")));
42
+ const diff = diffSnapshots(before, await snapshot(root));
43
+ await writeIndex(root);
44
+ await appendLogEntries(root, diff, detail, timestamp);
45
+ return diff;
46
+ }
47
+ export function renderIndex(entries) {
48
+ if (entries.length === 0) {
49
+ return "# Memory index\n";
50
+ }
51
+ return [
52
+ "# Memory index",
53
+ "",
54
+ ...entries.map(({ relPath, description }) => {
55
+ const pageName = relPath.slice(`${MEMORY_PAGES_DIR_RELPATH}/`.length).replace(/\.md$/i, "");
56
+ return description.length === 0
57
+ ? `- [${pageName}](${relPath})`
58
+ : `- [${pageName}](${relPath}) — ${description}`;
59
+ }),
60
+ ""
61
+ ].join("\n");
62
+ }
63
+ export async function appendLogEntries(root, diff, detail, timestamp = new Date().toISOString()) {
64
+ const entries = [
65
+ ...diff.updated.map((relPath) => formatLogLine(timestamp, "update", relPath, detail)),
66
+ ...diff.deleted.map((relPath) => formatLogLine(timestamp, "delete", relPath, detail)),
67
+ ...diff.created.map((relPath) => formatLogLine(timestamp, "create", relPath, detail))
68
+ ];
69
+ if (entries.length === 0) {
70
+ return;
71
+ }
72
+ const logPath = path.join(root, MEMORY_LOG_RELPATH);
73
+ const existing = await fs.readFile(logPath, "utf8");
74
+ const separator = existing.length === 0 || existing.endsWith("\n") ? "" : "\n";
75
+ await fs.writeFile(logPath, `${existing}${separator}${entries.join("\n")}\n`, "utf8");
76
+ }
77
+ export function denormalizeSources(markdown) {
78
+ const seen = new Map();
79
+ for (const claim of parseClaims(parsePageMarkdown("inline-memory-page", markdown).body)) {
80
+ const source = "source" in claim.tag ? claim.tag.source : undefined;
81
+ if (source === undefined) {
82
+ continue;
83
+ }
84
+ seen.set(serializeSourceRef(source), source);
85
+ }
86
+ return Array.from(seen.entries())
87
+ .sort(([left], [right]) => left.localeCompare(right))
88
+ .map(([, source]) => source);
89
+ }
90
+ async function writeIndex(root) {
91
+ const index = renderIndex((await listPages(root)).map((page) => ({
92
+ relPath: page.relPath,
93
+ description: page.frontmatter.description ?? ""
94
+ })));
95
+ await fs.writeFile(path.join(root, MEMORY_INDEX_RELPATH), index, "utf8");
96
+ }
97
+ function parsePageMarkdown(relPath, markdown) {
98
+ try {
99
+ return parseFrontmatter(markdown);
100
+ }
101
+ catch (error) {
102
+ const message = error instanceof Error ? error.message : String(error);
103
+ console.warn(`Failed to parse frontmatter for "${relPath}": ${message}`);
104
+ return {
105
+ frontmatter: {},
106
+ body: markdown
107
+ };
108
+ }
109
+ }
110
+ function withDenormalizedSources(frontmatter, body) {
111
+ const sources = denormalizeSources(body);
112
+ return {
113
+ ...frontmatter,
114
+ ...(sources.length === 0 ? { sources: undefined } : { sources })
115
+ };
116
+ }
117
+ function diffSnapshots(before, after) {
118
+ const created = Object.keys(after.pages)
119
+ .filter((relPath) => before.pages[relPath] === undefined)
120
+ .sort((left, right) => left.localeCompare(right));
121
+ const updated = Object.keys(after.pages)
122
+ .filter((relPath) => before.pages[relPath] !== undefined && before.pages[relPath] !== after.pages[relPath])
123
+ .sort((left, right) => left.localeCompare(right));
124
+ const deleted = Object.keys(before.pages)
125
+ .filter((relPath) => after.pages[relPath] === undefined)
126
+ .sort((left, right) => left.localeCompare(right));
127
+ return {
128
+ created,
129
+ updated,
130
+ deleted
131
+ };
132
+ }
133
+ function formatLogLine(timestamp, verb, relPath, detail) {
134
+ return `- ${timestamp} **${verb}** \`${relPath}\` — ${detail}`;
135
+ }
136
+ function hashContent(content) {
137
+ return createHash("sha256").update(content).digest("hex");
138
+ }
@@ -0,0 +1,11 @@
1
+ import type { FileSystem } from "../../config-mutations/dist/index.js";
2
+ import type { MemoryRoot } from "./types.js";
3
+ export declare const MEMORY_ROOT_ENV_VAR = "POE_CODE_MEMORY_ROOT";
4
+ export interface ResolveConfiguredMemoryRootOptions {
5
+ cwd: string;
6
+ env: Record<string, string | undefined>;
7
+ fs: FileSystem;
8
+ configPath: string;
9
+ projectConfigPath?: string;
10
+ }
11
+ export declare function resolveConfiguredMemoryRoot(options: ResolveConfiguredMemoryRootOptions): Promise<MemoryRoot>;
@@ -0,0 +1,22 @@
1
+ import path from "node:path";
2
+ import { configuredMemoryRoot } from "@poe-code/poe-code-config";
3
+ import { resolveMemoryRoot } from "./paths.js";
4
+ export const MEMORY_ROOT_ENV_VAR = "POE_CODE_MEMORY_ROOT";
5
+ export async function resolveConfiguredMemoryRoot(options) {
6
+ const envOverride = options.env[MEMORY_ROOT_ENV_VAR]?.trim();
7
+ if (envOverride && envOverride.length > 0) {
8
+ return resolveAgainstCwd(options.cwd, envOverride);
9
+ }
10
+ const configOverride = (await configuredMemoryRoot({
11
+ fs: options.fs,
12
+ filePath: options.configPath,
13
+ projectFilePath: options.projectConfigPath
14
+ }))?.trim();
15
+ if (configOverride && configOverride.length > 0) {
16
+ return resolveAgainstCwd(options.cwd, configOverride);
17
+ }
18
+ return resolveMemoryRoot(options.cwd);
19
+ }
20
+ function resolveAgainstCwd(cwd, value) {
21
+ return path.isAbsolute(value) ? value : path.resolve(cwd, value);
22
+ }
@@ -0,0 +1,2 @@
1
+ import type { MemoryRoot, SearchHit } from "./types.js";
2
+ export declare function searchMemory(root: MemoryRoot, query: string): Promise<SearchHit[]>;
@@ -0,0 +1,29 @@
1
+ import * as fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { collectMarkdownRelPaths } from "./pages.js";
4
+ export async function searchMemory(root, query) {
5
+ const normalizedQuery = query.trim();
6
+ if (normalizedQuery.length === 0) {
7
+ throw new Error("Search query cannot be empty.");
8
+ }
9
+ const relPaths = await collectMarkdownRelPaths(root);
10
+ const hits = [];
11
+ for (const relPath of relPaths) {
12
+ const content = await fs.readFile(path.join(root, relPath), "utf8");
13
+ if (content.length === 0) {
14
+ continue;
15
+ }
16
+ const lines = content.replaceAll("\r\n", "\n").split("\n");
17
+ for (const [index, line] of lines.entries()) {
18
+ if (!line.includes(normalizedQuery)) {
19
+ continue;
20
+ }
21
+ hits.push({
22
+ relPath,
23
+ lineNumber: index + 1,
24
+ line
25
+ });
26
+ }
27
+ }
28
+ return hits;
29
+ }
@@ -0,0 +1,7 @@
1
+ import type { MemoryRoot } from "./types.js";
2
+ export declare function statusOf(root: MemoryRoot): Promise<{
3
+ pageCount: number;
4
+ totalBytes: number;
5
+ lastWriteAt: string | null;
6
+ initialized: boolean;
7
+ }>;
@@ -0,0 +1,46 @@
1
+ import * as fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { MEMORY_PAGES_DIR_RELPATH } from "./paths.js";
4
+ import { collectMarkdownRelPaths } from "./pages.js";
5
+ export async function statusOf(root) {
6
+ if (!(await pathExists(root))) {
7
+ return {
8
+ pageCount: 0,
9
+ totalBytes: 0,
10
+ lastWriteAt: null,
11
+ initialized: false
12
+ };
13
+ }
14
+ const [pageRelPaths, markdownRelPaths] = await Promise.all([
15
+ collectMarkdownRelPaths(root, MEMORY_PAGES_DIR_RELPATH),
16
+ collectMarkdownRelPaths(root)
17
+ ]);
18
+ let totalBytes = 0;
19
+ let lastWriteAtMs = Number.NEGATIVE_INFINITY;
20
+ for (const relPath of markdownRelPaths) {
21
+ const stat = await fs.stat(path.join(root, relPath));
22
+ totalBytes += stat.size;
23
+ lastWriteAtMs = Math.max(lastWriteAtMs, stat.mtimeMs);
24
+ }
25
+ return {
26
+ pageCount: pageRelPaths.length,
27
+ totalBytes,
28
+ lastWriteAt: Number.isFinite(lastWriteAtMs) ? new Date(lastWriteAtMs).toISOString() : null,
29
+ initialized: true
30
+ };
31
+ }
32
+ async function pathExists(targetPath) {
33
+ try {
34
+ await fs.stat(targetPath);
35
+ return true;
36
+ }
37
+ catch (error) {
38
+ if (typeof error === "object" &&
39
+ error !== null &&
40
+ "code" in error &&
41
+ error.code === "ENOENT") {
42
+ return false;
43
+ }
44
+ throw error;
45
+ }
46
+ }
@@ -0,0 +1,2 @@
1
+ import type { MemoryRoot, TokenStats } from "./types.js";
2
+ export declare function computeTokenStats(root: MemoryRoot): Promise<TokenStats>;
@@ -0,0 +1,71 @@
1
+ import * as fs from "node:fs/promises";
2
+ import path from "node:path";
3
+ import { countTokens } from "tokenfill";
4
+ import { listPages } from "./pages.js";
5
+ export async function computeTokenStats(root) {
6
+ if (!(await pathExists(root))) {
7
+ return {
8
+ memoryTokens: 0,
9
+ sourceTokens: 0,
10
+ reductionRatio: 0,
11
+ missingSources: []
12
+ };
13
+ }
14
+ const pages = await listPages(root);
15
+ let memoryTokens = 0;
16
+ const sourcePaths = new Set();
17
+ for (const page of pages) {
18
+ memoryTokens += countTokens(page.body);
19
+ for (const source of page.frontmatter.sources ?? []) {
20
+ const normalized = source.path.trim();
21
+ if (normalized.length > 0) {
22
+ sourcePaths.add(normalized);
23
+ }
24
+ }
25
+ }
26
+ const repoRoot = path.resolve(root, "..", "..");
27
+ let sourceTokens = 0;
28
+ const missingSources = [];
29
+ for (const sourcePath of sourcePaths) {
30
+ const absPath = path.isAbsolute(sourcePath)
31
+ ? sourcePath
32
+ : path.resolve(repoRoot, sourcePath);
33
+ try {
34
+ const content = await fs.readFile(absPath, "utf8");
35
+ sourceTokens += countTokens(content);
36
+ }
37
+ catch (error) {
38
+ if (isMissing(error)) {
39
+ missingSources.push(sourcePath);
40
+ continue;
41
+ }
42
+ throw error;
43
+ }
44
+ }
45
+ missingSources.sort((left, right) => left.localeCompare(right));
46
+ const reductionRatio = sourceTokens === 0 ? 0 : sourceTokens / Math.max(memoryTokens, 1);
47
+ return {
48
+ memoryTokens,
49
+ sourceTokens,
50
+ reductionRatio,
51
+ missingSources
52
+ };
53
+ }
54
+ async function pathExists(targetPath) {
55
+ try {
56
+ await fs.stat(targetPath);
57
+ return true;
58
+ }
59
+ catch (error) {
60
+ if (isMissing(error)) {
61
+ return false;
62
+ }
63
+ throw error;
64
+ }
65
+ }
66
+ function isMissing(error) {
67
+ return (typeof error === "object" &&
68
+ error !== null &&
69
+ "code" in error &&
70
+ error.code === "ENOENT");
71
+ }
@@ -0,0 +1,155 @@
1
+ export type MemoryRoot = string;
2
+ export type PageFrontmatter = {
3
+ name?: string;
4
+ description?: string;
5
+ lastTouchedAt?: string;
6
+ sources?: SourceRef[];
7
+ };
8
+ export type SourceRef = {
9
+ path: string;
10
+ startLine?: number;
11
+ endLine?: number;
12
+ };
13
+ export type ConfidenceVerb = "extracted" | "inferred" | "ambiguous";
14
+ export type ConfidenceTag = {
15
+ verb: "extracted";
16
+ source: SourceRef;
17
+ note?: string;
18
+ } | {
19
+ verb: "inferred";
20
+ confidence: number;
21
+ source?: SourceRef;
22
+ note?: string;
23
+ } | {
24
+ verb: "ambiguous";
25
+ reason: string;
26
+ };
27
+ export type TaggedClaim = {
28
+ tag: ConfidenceTag;
29
+ body: string;
30
+ lineNumber: number;
31
+ };
32
+ export type PageWithClaims = MemoryPage & {
33
+ claims: TaggedClaim[];
34
+ };
35
+ export type MemoryPage = {
36
+ relPath: string;
37
+ frontmatter: PageFrontmatter;
38
+ body: string;
39
+ bytes: number;
40
+ mtimeMs: number;
41
+ };
42
+ export type IndexEntry = {
43
+ relPath: string;
44
+ description: string;
45
+ };
46
+ export type LogVerb = "create" | "update" | "delete" | "ingest" | "lint";
47
+ export type LogEntry = {
48
+ timestamp: string;
49
+ verb: LogVerb;
50
+ relPath?: string;
51
+ detail: string;
52
+ };
53
+ export type MemoryDiff = {
54
+ created: string[];
55
+ updated: string[];
56
+ deleted: string[];
57
+ };
58
+ export type MemorySnapshot = {
59
+ pages: Record<string, string>;
60
+ };
61
+ export type SearchHit = {
62
+ relPath: string;
63
+ lineNumber: number;
64
+ line: string;
65
+ };
66
+ export type IngestSource = {
67
+ kind: "file";
68
+ absPath: string;
69
+ } | {
70
+ kind: "url";
71
+ url: string;
72
+ };
73
+ export type SpawnFn<TResult = unknown> = (agent: string, prompt: string) => Promise<TResult>;
74
+ export type IngestOptions = {
75
+ source: IngestSource;
76
+ agent?: string;
77
+ reason?: string;
78
+ timeoutMs?: number;
79
+ dryRun?: boolean;
80
+ force?: boolean;
81
+ noCacheWrite?: boolean;
82
+ spawnFn?: SpawnFn;
83
+ };
84
+ export type LintOptions = {
85
+ fix?: boolean;
86
+ agent?: string;
87
+ timeoutMs?: number;
88
+ dryRun?: boolean;
89
+ spawnFn?: SpawnFn;
90
+ };
91
+ export type IngestResult = {
92
+ diff: MemoryDiff;
93
+ exitCode: number;
94
+ durationMs: number;
95
+ cacheHit: boolean;
96
+ tokens: TokenStats;
97
+ };
98
+ export type LintResult = {
99
+ diff: MemoryDiff;
100
+ issues: string[];
101
+ exitCode: number;
102
+ durationMs: number;
103
+ tokens: TokenStats;
104
+ };
105
+ export type IngestCacheKey = string;
106
+ export type IngestCacheEntry = {
107
+ key: IngestCacheKey;
108
+ ingestedAt: string;
109
+ sourceLabel: string;
110
+ diff: MemoryDiff;
111
+ exitCode: number;
112
+ durationMs: number;
113
+ memoryTokens: number;
114
+ sourceTokens: number;
115
+ promptTemplateVersion: string;
116
+ agentId: string;
117
+ };
118
+ export type TokenStats = {
119
+ memoryTokens: number;
120
+ sourceTokens: number;
121
+ reductionRatio: number;
122
+ missingSources: string[];
123
+ };
124
+ export type McpServerOptions = {
125
+ root: MemoryRoot;
126
+ allowWrites: boolean;
127
+ };
128
+ export type MemoryInstallResult = {
129
+ skillInstalled: boolean;
130
+ mcpConfigured: boolean;
131
+ skillPath?: string;
132
+ mcpConfigPath?: string;
133
+ };
134
+ export type QueryOptions = {
135
+ question: string;
136
+ budget: number;
137
+ agent?: string;
138
+ spawnFn?: SpawnFn;
139
+ };
140
+ export type QueryCitation = {
141
+ relPath: string;
142
+ section?: string;
143
+ confidence: ConfidenceVerb;
144
+ };
145
+ export type QueryResult = {
146
+ answer: string;
147
+ citations: QueryCitation[];
148
+ tokensUsed: number;
149
+ budget: number;
150
+ exitCode: number;
151
+ };
152
+ export type ExplainResult = QueryResult & {
153
+ inboundPages: string[];
154
+ outboundSources: SourceRef[];
155
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ import type { MemoryDiff, MemoryRoot, PageFrontmatter } from "./types.js";
2
+ export declare function writePage(root: MemoryRoot, relPath: string, body: string, opts: {
3
+ frontmatter?: PageFrontmatter;
4
+ reason: string;
5
+ }): Promise<MemoryDiff>;
6
+ export declare function appendToPage(root: MemoryRoot, relPath: string, content: string, opts: {
7
+ reason: string;
8
+ }): Promise<MemoryDiff>;
9
+ export declare function clearMemory(root: MemoryRoot): Promise<void>;