poe-code 3.0.311 → 3.0.313

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.
@@ -1,6 +1,6 @@
1
1
  import path from "node:path";
2
2
  import { installSkill } from "@poe-code/agent-skill-config";
3
- import { configure } from "@poe-code/agent-mcp-config";
3
+ import { configure, resolveAgentSupport } from "@poe-code/agent-mcp-config";
4
4
  const SKILL_NAME = "poe-code-memory";
5
5
  export async function installMemory(options) {
6
6
  if (options.skillOnly && options.mcpOnly) {
@@ -46,9 +46,7 @@ export async function installMemory(options) {
46
46
  }
47
47
  throw error;
48
48
  }
49
- mcpConfigPath = options.agent === "codex"
50
- ? `${options.homeDir}/.config/codex/mcp-config.json`
51
- : `${options.homeDir}/.mcp.json`;
49
+ mcpConfigPath = resolveMcpConfigPath(options.agent, options.homeDir, options.platform);
52
50
  }
53
51
  return {
54
52
  skillInstalled: !options.mcpOnly,
@@ -57,6 +55,16 @@ export async function installMemory(options) {
57
55
  mcpConfigPath
58
56
  };
59
57
  }
58
+ function resolveMcpConfigPath(agent, homeDir, platform) {
59
+ const support = resolveAgentSupport(agent);
60
+ if (support.status !== "supported" || support.config === undefined) {
61
+ throw new Error(`Unsupported agent: ${agent}`);
62
+ }
63
+ const configFile = typeof support.config.configFile === "function"
64
+ ? support.config.configFile(platform)
65
+ : support.config.configFile;
66
+ return configFile.startsWith("~/") ? path.join(homeDir, configFile.slice(2)) : configFile;
67
+ }
60
68
  async function removeInstalledSkill(options, skillPath) {
61
69
  const baseDir = options.scope === "global" ? options.homeDir : options.cwd;
62
70
  const displayPath = skillPath.startsWith("~/") ? skillPath.slice(2) : skillPath;
@@ -62,6 +62,9 @@ export async function assertMemoryRootIsNotSymlink(root) {
62
62
  try {
63
63
  const stat = await fs.lstat(currentPath);
64
64
  if (stat.isSymbolicLink()) {
65
+ if (await isAllowedMacSystemAlias(currentPath)) {
66
+ continue;
67
+ }
65
68
  throw new MemoryPathError(`Memory root "${root}" cannot be a symbolic link.`);
66
69
  }
67
70
  }
@@ -73,6 +76,18 @@ export async function assertMemoryRootIsNotSymlink(root) {
73
76
  }
74
77
  }
75
78
  }
79
+ async function isAllowedMacSystemAlias(currentPath) {
80
+ if (currentPath !== "/var") {
81
+ return false;
82
+ }
83
+ try {
84
+ const target = await fs.readlink(currentPath);
85
+ return target === "/private/var" || target === "private/var";
86
+ }
87
+ catch {
88
+ return false;
89
+ }
90
+ }
76
91
  function isMissing(error) {
77
92
  return hasOwnErrorCode(error, "ENOENT");
78
93
  }
@@ -3,6 +3,7 @@ import path from "node:path";
3
3
  import { countTokens } from "tokenfill";
4
4
  import { spawn } from "@poe-code/agent-spawn";
5
5
  import { resolveAgent } from "@poe-code/poe-code-config";
6
+ import { parseMemoryAgentResponse } from "./agent-response.js";
6
7
  import { listPages } from "./pages.js";
7
8
  import { MEMORY_INDEX_RELPATH } from "./paths.js";
8
9
  export async function queryMemory(root, options) {
@@ -24,7 +25,7 @@ export async function queryMemory(root, options) {
24
25
  const agentId = (await resolveAgent(configOptions, options.agent ?? null)) ?? options.agent ?? "claude-code";
25
26
  const context = await selectQueryContext(root, options.question, options.budget);
26
27
  const spawned = await spawn(agentId, { prompt: context.prompt });
27
- const result = parseQueryResponse(spawned.stdout);
28
+ const result = parseMemoryAgentResponse(spawned.stdout);
28
29
  return {
29
30
  answer: result.answer,
30
31
  citations: result.citations,
@@ -33,30 +34,6 @@ export async function queryMemory(root, options) {
33
34
  exitCode: spawned.exitCode
34
35
  };
35
36
  }
36
- function parseQueryResponse(stdout) {
37
- let value;
38
- try {
39
- value = JSON.parse(stdout);
40
- }
41
- catch {
42
- throw new Error("Memory agent returned invalid JSON output.");
43
- }
44
- if (typeof value !== "object" || value === null || Array.isArray(value)) {
45
- throw new Error("Memory agent returned an invalid result payload.");
46
- }
47
- const result = value;
48
- if (typeof result.answer !== "string" ||
49
- !Array.isArray(result.citations) ||
50
- typeof result.tokensUsed !== "number" ||
51
- !Number.isFinite(result.tokensUsed)) {
52
- throw new Error("Memory agent returned an invalid result payload.");
53
- }
54
- return {
55
- answer: result.answer,
56
- citations: result.citations,
57
- tokensUsed: result.tokensUsed
58
- };
59
- }
60
37
  export async function selectQueryContext(root, question, budget) {
61
38
  if (!Number.isFinite(budget) || budget < 0) {
62
39
  throw new Error("budget must be a finite non-negative number");
@@ -1,13 +1,13 @@
1
1
  import * as fs from "node:fs/promises";
2
2
  import path from "node:path";
3
3
  import { collectMarkdownRelPaths } from "./pages.js";
4
- import { assertNoSymlinkSegments } from "./paths.js";
4
+ import { assertNoSymlinkSegments, MEMORY_PAGES_DIR_RELPATH } from "./paths.js";
5
5
  export async function searchMemory(root, query) {
6
6
  const normalizedQuery = query.trim();
7
7
  if (normalizedQuery.length === 0) {
8
8
  throw new Error("Search query cannot be empty.");
9
9
  }
10
- const relPaths = await collectMarkdownRelPaths(root);
10
+ const relPaths = await collectMarkdownRelPaths(root, MEMORY_PAGES_DIR_RELPATH);
11
11
  const hits = [];
12
12
  for (const relPath of relPaths) {
13
13
  await assertNoSymlinkSegments(root, relPath);
@@ -32,7 +32,7 @@ export async function appendToPage(root, relPath, content, opts) {
32
32
  const before = await snapshot(root);
33
33
  await fs.mkdir(path.dirname(pagePath), { recursive: true });
34
34
  await assertNoSymlinkSegments(root, pageRelPath);
35
- const parsed = originalPage === undefined ? { frontmatter: {}, body: "" } : parseFrontmatter(originalPage);
35
+ const parsed = parseAppendTarget(originalPage, pageRelPath);
36
36
  try {
37
37
  await writeFileAtomically(pagePath, serializeFrontmatter(parsed.frontmatter, `${parsed.body}${content}`));
38
38
  return await reconcile(root, before, "update", opts.reason);
@@ -42,6 +42,19 @@ export async function appendToPage(root, relPath, content, opts) {
42
42
  throw error;
43
43
  }
44
44
  }
45
+ function parseAppendTarget(originalPage, relPath) {
46
+ if (originalPage === undefined) {
47
+ return { frontmatter: {}, body: "" };
48
+ }
49
+ try {
50
+ return parseFrontmatter(originalPage);
51
+ }
52
+ catch (error) {
53
+ const message = error instanceof Error ? error.message : String(error);
54
+ console.warn(`Failed to parse frontmatter for "${relPath}": ${message}`);
55
+ return { frontmatter: {}, body: originalPage };
56
+ }
57
+ }
45
58
  export async function clearMemory(root) {
46
59
  await assertMemoryRootIsNotSymlink(root);
47
60
  const stagedRoot = `${root}.clear-${randomUUID()}`;