@daniel156161/prism 0.2.81 → 0.2.82

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 (35) hide show
  1. package/dist/prism-extensions/integrations/ai-memory-errors.d.ts +13 -0
  2. package/dist/prism-extensions/integrations/ai-memory-errors.js +54 -0
  3. package/dist/prism-extensions/integrations/ai-memory-errors.js.map +1 -1
  4. package/dist/prism-extensions/integrations/ai-memory-http.d.ts +28 -0
  5. package/dist/prism-extensions/integrations/ai-memory-http.js +92 -0
  6. package/dist/prism-extensions/integrations/ai-memory-http.js.map +1 -0
  7. package/dist/prism-extensions/integrations/ai-memory-system.d.ts +2 -0
  8. package/dist/prism-extensions/integrations/ai-memory-system.js +49 -127
  9. package/dist/prism-extensions/integrations/ai-memory-system.js.map +1 -1
  10. package/dist/prism-extensions/integrations/ai-memory-write-preview.d.ts +36 -0
  11. package/dist/prism-extensions/integrations/ai-memory-write-preview.js +67 -0
  12. package/dist/prism-extensions/integrations/ai-memory-write-preview.js.map +1 -0
  13. package/dist/prism-extensions/ui/collapsed-text-rendering.d.ts +4 -2
  14. package/dist/prism-extensions/ui/collapsed-text-rendering.js +12 -7
  15. package/dist/prism-extensions/ui/collapsed-text-rendering.js.map +1 -1
  16. package/node_modules/@earendil-works/pi-coding-agent/dist/cli.js +1 -1
  17. package/node_modules/@earendil-works/pi-coding-agent/dist/config.js +11 -6
  18. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.js +1 -1
  19. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js +0 -5
  20. package/node_modules/@earendil-works/pi-coding-agent/dist/core/auth-storage.js +1 -1
  21. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/loader.js +1 -3
  22. package/node_modules/@earendil-works/pi-coding-agent/dist/core/project-trust.js +1 -1
  23. package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.js +1 -1
  24. package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.js +37 -39
  25. package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.js +16 -20
  26. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/session-selector.js +0 -4
  27. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js +2376 -234
  28. package/node_modules/@earendil-works/pi-tui/dist/autocomplete.js +1 -1
  29. package/package.json +3 -3
  30. package/src/prism-extensions/integrations/ai-memory-errors.ts +59 -0
  31. package/src/prism-extensions/integrations/ai-memory-http.ts +114 -0
  32. package/src/prism-extensions/integrations/ai-memory-system.ts +60 -135
  33. package/src/prism-extensions/integrations/ai-memory-write-preview.ts +83 -0
  34. package/src/prism-extensions/ui/collapsed-text-rendering.ts +14 -8
  35. package/node_modules/@earendil-works/pi-coding-agent/dist/core/prism-session-db.js +0 -128
@@ -0,0 +1,36 @@
1
+ /**
2
+ * Live preview and rendering of memory writes.
3
+ *
4
+ * Vault writes used to be invisible until the tool finished: the call row only
5
+ * showed the path and the result slot said "Searching AI Memory...". This module
6
+ * formats the *partially streamed* arguments so the note content is readable
7
+ * while the model is still producing it, and keeps the row expandable with
8
+ * Ctrl+O / Strg+O (`app.tools.expand`) in both states.
9
+ */
10
+ import { type ThemeLike } from "../ui/tool-call-rendering.js";
11
+ /** Collapsed height while arguments stream in; the newest lines stay visible. */
12
+ export declare const WRITE_STREAM_COLLAPSED_LINES = 16;
13
+ /** Collapsed height of a finished write result. */
14
+ export declare const WRITE_RESULT_COLLAPSED_LINES = 24;
15
+ export declare function isAiMemoryWriteTool(toolName: string): boolean;
16
+ export declare function formatAiMemoryWriteTarget(toolName: string, args: any): string;
17
+ /**
18
+ * @param args partially streamed tool arguments (may miss fields entirely)
19
+ * @param streaming true while arguments are still arriving
20
+ */
21
+ export declare function buildAiMemoryWritePreview(toolName: string, args: any, streaming?: boolean): {
22
+ header: string;
23
+ content: string;
24
+ };
25
+ export declare function formatAiMemoryWritePreview(toolName: string, args: any, streaming?: boolean): string;
26
+ /**
27
+ * Result slot for vault writes: streams the note content while the model writes,
28
+ * shows the confirmed content afterwards. Both states honour `expanded`, so
29
+ * Ctrl+O / Strg+O toggles between the collapsed excerpt and the full text.
30
+ */
31
+ export declare function renderAiMemoryWriteResult(toolName: string, result: any, options: {
32
+ expanded?: boolean;
33
+ isPartial?: boolean;
34
+ } | undefined, theme: ThemeLike, context?: any): {
35
+ render(width: number): string[];
36
+ };
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Live preview and rendering of memory writes.
3
+ *
4
+ * Vault writes used to be invisible until the tool finished: the call row only
5
+ * showed the path and the result slot said "Searching AI Memory...". This module
6
+ * formats the *partially streamed* arguments so the note content is readable
7
+ * while the model is still producing it, and keeps the row expandable with
8
+ * Ctrl+O / Strg+O (`app.tools.expand`) in both states.
9
+ */
10
+ import { renderCollapsibleText, renderCollapsibleTextResult } from "../ui/collapsed-text-rendering.js";
11
+ import { truncateToWidth } from "../ui/tool-call-rendering.js";
12
+ /** Collapsed height while arguments stream in; the newest lines stay visible. */
13
+ export const WRITE_STREAM_COLLAPSED_LINES = 16;
14
+ /** Collapsed height of a finished write result. */
15
+ export const WRITE_RESULT_COLLAPSED_LINES = 24;
16
+ const WRITE_PREVIEW_TOOLS = new Set(["ai_memory_vault_write", "ai_memory_vault_edit"]);
17
+ export function isAiMemoryWriteTool(toolName) {
18
+ return WRITE_PREVIEW_TOOLS.has(toolName);
19
+ }
20
+ function text(value) {
21
+ return value === undefined || value === null ? "" : String(value);
22
+ }
23
+ export function formatAiMemoryWriteTarget(toolName, args) {
24
+ const path = text(args?.path).trim() || "(path pending)";
25
+ const heading = text(args?.heading).trim();
26
+ return toolName === "ai_memory_vault_edit" && heading ? `${path} > # ${heading}` : path;
27
+ }
28
+ /**
29
+ * @param args partially streamed tool arguments (may miss fields entirely)
30
+ * @param streaming true while arguments are still arriving
31
+ */
32
+ export function buildAiMemoryWritePreview(toolName, args, streaming = true) {
33
+ const label = toolName === "ai_memory_vault_edit" ? "Editing" : "Writing";
34
+ const frontmatter = text(args?.frontmatter).trim();
35
+ const heading = text(args?.heading).trim();
36
+ const headingLine = toolName === "ai_memory_vault_edit" && heading ? `# ${heading}` : "";
37
+ const body = text(args?.body);
38
+ const written = [frontmatter, headingLine, body.trimEnd()].filter(Boolean).join("\n\n");
39
+ const header = `${label}: ${formatAiMemoryWriteTarget(toolName, args)}${streaming ? " … streaming" : ""}`;
40
+ const content = written || (streaming ? "(waiting for content…)" : "(empty)");
41
+ return { header, content };
42
+ }
43
+ export function formatAiMemoryWritePreview(toolName, args, streaming = true) {
44
+ const { header, content } = buildAiMemoryWritePreview(toolName, args, streaming);
45
+ return `${header}\n\n${content}`;
46
+ }
47
+ /**
48
+ * Result slot for vault writes: streams the note content while the model writes,
49
+ * shows the confirmed content afterwards. Both states honour `expanded`, so
50
+ * Ctrl+O / Strg+O toggles between the collapsed excerpt and the full text.
51
+ */
52
+ export function renderAiMemoryWriteResult(toolName, result, options = {}, theme, context) {
53
+ if (!options.isPartial) {
54
+ return renderCollapsibleTextResult(result, options, theme, {
55
+ partialLabel: "Writing AI Memory...",
56
+ emptyLabel: "No AI Memory write result",
57
+ maxLines: WRITE_RESULT_COLLAPSED_LINES,
58
+ });
59
+ }
60
+ const { header, content } = buildAiMemoryWritePreview(toolName, context?.args ?? {}, context?.argsComplete !== true);
61
+ // Keep the target pinned above the streamed tail so it never scrolls away.
62
+ const body = renderCollapsibleText(content, options, theme, { maxLines: WRITE_STREAM_COLLAPSED_LINES, keep: "tail" });
63
+ return {
64
+ render: (width) => [theme.fg("accent", truncateToWidth(header, Math.max(10, width - 2))), ...body.render(width)],
65
+ };
66
+ }
67
+ //# sourceMappingURL=ai-memory-write-preview.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ai-memory-write-preview.js","sourceRoot":"","sources":["../../../src/prism-extensions/integrations/ai-memory-write-preview.ts"],"names":[],"mappings":"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"}
@@ -7,15 +7,17 @@ export type CollapsibleTextRenderConfig = {
7
7
  partialLabel: string;
8
8
  emptyLabel: string;
9
9
  maxLines: number;
10
+ /** "head" keeps the first lines (default), "tail" keeps the newest lines. */
11
+ keep?: "head" | "tail";
10
12
  lines?: (text: string) => string[];
11
13
  strip?: (text: string) => string;
12
14
  };
13
15
  export declare function renderCollapsibleTextResult(result: any, options: CollapsibleTextRenderOptions | undefined, theme: ThemeLike, config: CollapsibleTextRenderConfig): {
14
16
  render(width: number): string[];
15
17
  };
16
- export declare function renderCollapsibleText(text: string, options: CollapsibleTextRenderOptions | undefined, theme: ThemeLike, config: Pick<CollapsibleTextRenderConfig, "maxLines" | "lines" | "strip">): {
18
+ export declare function renderCollapsibleText(text: string, options: CollapsibleTextRenderOptions | undefined, theme: ThemeLike, config: Pick<CollapsibleTextRenderConfig, "maxLines" | "keep" | "lines" | "strip">): {
17
19
  render(width: number): string[];
18
20
  };
19
- export declare function collapseHint(hiddenLineCount: number): string;
21
+ export declare function collapseHint(hiddenLineCount: number, position?: "below" | "above"): string;
20
22
  export declare function stripLeadingPathHeader(text: string, relPath: string): string;
21
23
  export declare function stripLeadingSearchTerms(text: string): string;
@@ -10,20 +10,25 @@ export function renderCollapsibleTextResult(result, options = {}, theme, config)
10
10
  export function renderCollapsibleText(text, options = {}, theme, config) {
11
11
  const body = config.strip ? config.strip(text) : text;
12
12
  const lines = config.lines ? config.lines(body) : body.split(/\r?\n/);
13
- const shown = options.expanded ? lines : lines.slice(0, config.maxLines);
13
+ const keepTail = config.keep === "tail";
14
+ const shown = options.expanded ? lines : keepTail ? lines.slice(-config.maxLines) : lines.slice(0, config.maxLines);
15
+ const hidden = lines.length - shown.length;
14
16
  return {
15
17
  render: (width) => {
16
18
  const maxWidth = Math.max(10, width - 2);
19
+ const hint = hidden > 0 && !options.expanded
20
+ ? theme.fg("muted", truncateToWidth(collapseHint(hidden, keepTail ? "above" : "below"), maxWidth))
21
+ : undefined;
17
22
  const rendered = shown.map((line) => theme.fg("dim", truncateToWidth(line, maxWidth)));
18
- if (!options.expanded && lines.length > shown.length) {
19
- rendered.push(theme.fg("muted", truncateToWidth(collapseHint(lines.length - shown.length), maxWidth)));
20
- }
21
- return rendered;
23
+ if (!hint)
24
+ return rendered;
25
+ return keepTail ? [hint, ...rendered] : [...rendered, hint];
22
26
  },
23
27
  };
24
28
  }
25
- export function collapseHint(hiddenLineCount) {
26
- return `... ${hiddenLineCount} more lines (Ctrl+O / Strg+O to expand)`;
29
+ export function collapseHint(hiddenLineCount, position = "below") {
30
+ const what = position === "above" ? "earlier lines" : "more lines";
31
+ return `... ${hiddenLineCount} ${what} (Ctrl+O / Strg+O to expand)`;
27
32
  }
28
33
  export function stripLeadingPathHeader(text, relPath) {
29
34
  return text.replace(new RegExp(`^Path: ${escapeRegExp(relPath)}\\r?\\n\\r?\\n`), "");
@@ -1 +1 @@
1
- {"version":3,"file":"collapsed-text-rendering.js","sourceRoot":"","sources":["../../../src/prism-extensions/ui/collapsed-text-rendering.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAkB,MAAM,0BAA0B,CAAA;AAe1E,MAAM,UAAU,2BAA2B,CACzC,MAAW,EACX,OAAO,GAAiC,EAAE,EAC1C,KAAgB,EAChB,MAAmC;IAEnC,IAAI,OAAO,CAAC,SAAS;QAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC,EAAE,CAAA;IAE1F,MAAM,OAAO,GAAG,MAAM,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAA;IACpC,IAAI,OAAO,EAAE,IAAI,KAAK,MAAM;QAAE,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC,EAAE,CAAA;IAE7F,OAAO,qBAAqB,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,CAAC,CAAA;AAClF,CAAC;AAED,MAAM,UAAU,qBAAqB,CACnC,IAAY,EACZ,OAAO,GAAiC,EAAE,EAC1C,KAAgB,EAChB,MAAyE;IAEzE,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAA;IACrD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;IACrE,MAAM,KAAK,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAA;IAExE,OAAO;QACL,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,KAAK,GAAG,CAAC,CAAC,CAAA;YACxC,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,eAAe,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAA;YACtF,IAAI,CAAC,OAAO,CAAC,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC;gBACrD,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,eAAe,CAAC,YAAY,CAAC,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAA;YACxG,CAAC;YACD,OAAO,QAAQ,CAAA;QACjB,CAAC;KACF,CAAA;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,eAAuB;IAClD,OAAO,OAAO,eAAe,yCAAyC,CAAA;AACxE,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,IAAY,EAAE,OAAe;IAClE,OAAO,IAAI,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,UAAU,YAAY,CAAC,OAAO,CAAC,gBAAgB,CAAC,EAAE,EAAE,CAAC,CAAA;AACtF,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,IAAY;IAClD,OAAO,IAAI,CAAC,OAAO,CAAC,+BAA+B,EAAE,EAAE,CAAC,CAAA;AAC1D,CAAC;AAED,SAAS,YAAY,CAAC,KAAa;IACjC,OAAO,KAAK,CAAC,OAAO,CAAC,qBAAqB,EAAE,MAAM,CAAC,CAAA;AACrD,CAAC"}
1
+ {"version":3,"file":"collapsed-text-rendering.js","sourceRoot":"","sources":["../../../src/prism-extensions/ui/collapsed-text-rendering.ts"],"names":[],"mappings":"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"}
@@ -8,7 +8,7 @@
8
8
  import { APP_NAME } from "./config.js";
9
9
  import { configureHttpDispatcher } from "./core/http-dispatcher.js";
10
10
  import { main } from "./main.js";
11
- process.title = "▲";
11
+ process.title = APP_NAME;
12
12
  process.env.PI_CODING_AGENT = "true";
13
13
  process.env.AI_AGENT = "pi";
14
14
  process.emitWarning = (() => { });
@@ -321,9 +321,10 @@ export function getThemesDir() {
321
321
  if (isBunBinary) {
322
322
  return join(getPackageDir(), "theme");
323
323
  }
324
- // Prism: use __dirname so built-in themes resolve from the actual dist/,
325
- // not PI_PACKAGE_DIR which may point to a config-only dir without dist/.
326
- return join(__dirname, "modes", "interactive", "theme");
324
+ // Theme is in modes/interactive/theme/ relative to src/ or dist/
325
+ const packageDir = getPackageDir();
326
+ const srcOrDist = existsSync(join(packageDir, "src")) ? "src" : "dist";
327
+ return join(packageDir, srcOrDist, "modes", "interactive", "theme");
327
328
  }
328
329
  /**
329
330
  * Get path to HTML export template directory (shipped with package)
@@ -335,7 +336,9 @@ export function getExportTemplateDir() {
335
336
  if (isBunBinary) {
336
337
  return join(getPackageDir(), "export-html");
337
338
  }
338
- return join(__dirname, "core", "export-html");
339
+ const packageDir = getPackageDir();
340
+ const srcOrDist = existsSync(join(packageDir, "src")) ? "src" : "dist";
341
+ return join(packageDir, srcOrDist, "core", "export-html");
339
342
  }
340
343
  /** Get path to package.json */
341
344
  export function getPackageJsonPath() {
@@ -367,7 +370,9 @@ export function getInteractiveAssetsDir() {
367
370
  if (isBunBinary) {
368
371
  return join(getPackageDir(), "assets");
369
372
  }
370
- return join(__dirname, "modes", "interactive", "assets");
373
+ const packageDir = getPackageDir();
374
+ const srcOrDist = existsSync(join(packageDir, "src")) ? "src" : "dist";
375
+ return join(packageDir, srcOrDist, "modes", "interactive", "assets");
371
376
  }
372
377
  /** Get path to a bundled interactive asset */
373
378
  export function getBundledInteractiveAssetPath(name) {
@@ -421,7 +426,7 @@ export function getModelsPath() {
421
426
  }
422
427
  /** Get path to auth.json */
423
428
  export function getAuthPath() {
424
- return process.env.PRISM_AUTH_PATH || process.env.PI_AUTH_PATH || join(getAgentDir(), "auth.json");
429
+ return join(getAgentDir(), "auth.json");
425
430
  }
426
431
  /** Get path to settings.json */
427
432
  export function getSettingsPath() {
@@ -55,7 +55,7 @@ export async function createAgentSessionServices(options) {
55
55
  const agentDir = options.agentDir ? resolvePath(options.agentDir) : getAgentDir();
56
56
  const modelRuntime = options.modelRuntime ??
57
57
  (await ModelRuntime.create({
58
- authPath: process.env.PRISM_AUTH_PATH || process.env.PI_AUTH_PATH || join(agentDir, "auth.json"),
58
+ authPath: join(agentDir, "auth.json"),
59
59
  modelsPath: join(agentDir, "models.json"),
60
60
  signal: options.modelRuntimeSignal,
61
61
  }));
@@ -2084,11 +2084,6 @@ export class AgentSession {
2084
2084
  // Context overflow is handled by compaction, not retry.
2085
2085
  if (isContextOverflow(message, this.model?.contextWindow ?? 0))
2086
2086
  return false;
2087
- // Prism: provider account/quota usage limits need a user decision (wait, switch model, or cancel).
2088
- // Do not auto-retry them with the generic exponential backoff, because provider reset
2089
- // windows are often much longer than the retry delay.
2090
- if (/GoUsageLimitError|FreeUsageLimitError|Monthly usage limit reached|available balance|insufficient_quota|out of budget|quota exceeded|billing|usage[_\s-]*limit|usage_limit_reached/i.test(message.errorMessage || ""))
2091
- return false;
2092
2087
  return isRetryableAssistantError(message);
2093
2088
  }
2094
2089
  /**
@@ -14,7 +14,7 @@ const AUTH_FILE_WRITE_OPTIONS = { encoding: "utf-8", mode: 0o600 };
14
14
  let sharedAuthFileReadState;
15
15
  export class FileAuthStorageBackend {
16
16
  authPath;
17
- constructor(authPath = (process.env.PRISM_AUTH_PATH || process.env.PI_AUTH_PATH || join(getAgentDir(), "auth.json"))) {
17
+ constructor(authPath = join(getAgentDir(), "auth.json")) {
18
18
  this.authPath = normalizePath(authPath);
19
19
  }
20
20
  ensureParentDir() {
@@ -9,7 +9,6 @@ import { fileURLToPath } from "node:url";
9
9
  import * as _bundledPiAgentCore from "@earendil-works/pi-agent-core";
10
10
  import * as _bundledPiAiCompat from "@earendil-works/pi-ai/compat";
11
11
  import * as _bundledPiAiOauth from "@earendil-works/pi-ai/oauth";
12
- import * as _prismPiAiOpenAICompletions from "@earendil-works/pi-ai/api/openai-completions";
13
12
  import * as _bundledPiAiProviders from "@earendil-works/pi-ai/providers/all";
14
13
  import * as _bundledPiTui from "@earendil-works/pi-tui";
15
14
  import { createJiti } from "jiti/static";
@@ -22,13 +21,12 @@ import * as _bundledTypeboxValue from "typebox/value";
22
21
  import { CONFIG_DIR_NAME, getAgentDir, isBunBinary } from "../../config.js";
23
22
  // NOTE: This import works because loader.ts exports are NOT re-exported from index.ts,
24
23
  // avoiding a circular dependency. Extensions can import from @earendil-works/pi-coding-agent.
25
- import * as _bundledPiCodingAgent from "./index.js";
24
+ import * as _bundledPiCodingAgent from "../../index.js";
26
25
  import { resolvePath } from "../../utils/paths.js";
27
26
  import { createEventBus } from "../event-bus.js";
28
27
  import { execCommand } from "../exec.js";
29
28
  import { readPiManifest } from "../pi-manifest.js";
30
29
  import { createSyntheticSourceInfo } from "../source-info.js";
31
- globalThis.__PRISM_PI_AI_OPENAI_COMPLETIONS__ = _prismPiAiOpenAICompletions;
32
30
  import { time } from "../timings.js";
33
31
  /** Modules available to extensions via virtualModules (for compiled Bun binary) */
34
32
  const VIRTUAL_MODULES = {
@@ -2,7 +2,7 @@ import { CONFIG_DIR_NAME } from "../config.js";
2
2
  import { emitProjectTrustEvent } from "./extensions/runner.js";
3
3
  import { getProjectTrustOptions, hasTrustRequiringProjectResources, } from "./trust-manager.js";
4
4
  function formatProjectTrustPrompt(cwd) {
5
- return `Trust project folder?\n${cwd}\n\nThis allows Prism to load ${CONFIG_DIR_NAME} settings and resources, install missing project packages, and execute project extensions.`;
5
+ return `Trust project folder?\n${cwd}\n\nThis allows pi to load ${CONFIG_DIR_NAME} settings and resources, install missing project packages, and execute project extensions.`;
6
6
  }
7
7
  async function selectProjectTrustOption(cwd, ctx) {
8
8
  const options = getProjectTrustOptions(cwd, { includeSessionOnly: true });
@@ -67,7 +67,7 @@ export async function createAgentSession(options = {}) {
67
67
  const cwd = resolvePath(options.cwd ?? options.sessionManager?.getCwd() ?? process.cwd());
68
68
  const agentDir = options.agentDir ? resolvePath(options.agentDir) : getDefaultAgentDir();
69
69
  let resourceLoader = options.resourceLoader;
70
- const authPath = process.env.PRISM_AUTH_PATH || process.env.PI_AUTH_PATH || (options.agentDir ? join(agentDir, "auth.json") : undefined);
70
+ const authPath = options.agentDir ? join(agentDir, "auth.json") : undefined;
71
71
  const modelsPath = options.agentDir ? join(agentDir, "models.json") : undefined;
72
72
  const modelRuntime = options.modelRuntime ?? (await ModelRuntime.create({ authPath, modelsPath }));
73
73
  const settingsManager = options.settingsManager ?? SettingsManager.create(cwd, agentDir);
@@ -3,7 +3,6 @@ import { randomUUID } from "crypto";
3
3
  import { appendFileSync, closeSync, createReadStream, existsSync, mkdirSync, openSync, readdirSync, readSync, statSync, writeFileSync, } from "fs";
4
4
  import { readdir, stat } from "fs/promises";
5
5
  import { join, resolve } from "path";
6
- import { findMostRecentSessionFromDb, getSessionBackend, listAllSessionsFromDb, listSessionsFromDb, loadEntriesFromDb, mirrorEntryToDb, mirrorSessionFileToDb } from "./prism-session-db.js";
7
6
  import { createInterface } from "readline";
8
7
  import { StringDecoder } from "string_decoder";
9
8
  import { getAgentDir as getDefaultAgentDir, getSessionsDir } from "../config.js";
@@ -635,23 +634,12 @@ export class SessionManager {
635
634
  this._rewriteFile();
636
635
  }
637
636
  this._buildIndex();
638
- if (getSessionBackend() !== "file") { try { mirrorSessionFileToDb(this.sessionFile, this.fileEntries, this.cwd, this.sessionDir); } catch { } }
639
637
  this.flushed = true;
640
638
  }
641
639
  else {
642
- const dbEntries = getSessionBackend() !== "file" ? loadEntriesFromDb(this.sessionFile) : null;
643
- if (dbEntries) {
644
- this.fileEntries = dbEntries;
645
- const header = this.fileEntries.find((e) => e.type === "session");
646
- this.sessionId = header?.id ?? createSessionId();
647
- this._buildIndex();
648
- if (getSessionBackend() !== "file") { try { mirrorSessionFileToDb(this.sessionFile, this.fileEntries, this.cwd, this.sessionDir); } catch {} }
649
- this.flushed = true;
650
- } else {
651
- const explicitPath = this.sessionFile;
652
- this.newSession();
653
- this.sessionFile = explicitPath;
654
- }
640
+ const explicitPath = this.sessionFile;
641
+ this.newSession();
642
+ this.sessionFile = explicitPath; // preserve explicit path from --session flag
655
643
  }
656
644
  }
657
645
  newSession(options) {
@@ -705,8 +693,6 @@ export class SessionManager {
705
693
  _rewriteFile() {
706
694
  if (!this.persist || !this.sessionFile)
707
695
  return;
708
- if (getSessionBackend() !== "file") { try { mirrorSessionFileToDb(this.sessionFile, this.fileEntries, this.cwd, this.sessionDir); } catch { } }
709
- if (getSessionBackend() === "db") return;
710
696
  const fd = openSync(this.sessionFile, "w");
711
697
  try {
712
698
  for (const entry of this.fileEntries) {
@@ -738,14 +724,30 @@ export class SessionManager {
738
724
  _persist(entry) {
739
725
  if (!this.persist || !this.sessionFile)
740
726
  return;
741
- // Prism: persist every entry immediately. Pi defers session writes until the
742
- // first assistant message, which can lose user prompts if multiple harnesses
743
- // run at once or a process exits before the assistant response is recorded.
727
+ const hasAssistant = this.fileEntries.some((e) => e.type === "message" && e.message.role === "assistant");
728
+ if (!hasAssistant) {
729
+ if (this.flushed) {
730
+ appendFileSync(this.sessionFile, `${JSON.stringify(entry)}\n`);
731
+ }
732
+ else {
733
+ // Mark as not flushed so when assistant arrives, all entries get written
734
+ this.flushed = false;
735
+ }
736
+ return;
737
+ }
744
738
  if (!this.flushed) {
745
- if (getSessionBackend() !== "db") { const fd = openSync(this.sessionFile, "wx"); try { for (const e of this.fileEntries) { writeFileSync(fd, `${JSON.stringify(e)}\n`); } } finally { closeSync(fd); } }
739
+ const fd = openSync(this.sessionFile, "wx");
740
+ try {
741
+ for (const e of this.fileEntries) {
742
+ writeFileSync(fd, `${JSON.stringify(e)}\n`);
743
+ }
744
+ }
745
+ finally {
746
+ closeSync(fd);
747
+ }
746
748
  this.flushed = true;
747
749
  }
748
- else if (getSessionBackend() !== "db") {
750
+ else {
749
751
  appendFileSync(this.sessionFile, `${JSON.stringify(entry)}\n`);
750
752
  }
751
753
  }
@@ -754,7 +756,6 @@ export class SessionManager {
754
756
  this.byId.set(entry.id, entry);
755
757
  this.leafId = entry.id;
756
758
  this._persist(entry);
757
- if (getSessionBackend() !== "file") { try { mirrorEntryToDb(this.sessionFile, this.fileEntries.find((e) => e.type === "session"), entry, this.cwd, this.sessionDir, this.fileEntries.length - 2); } catch { } }
758
759
  }
759
760
  /** Append a message as child of current leaf, then advance leaf. Returns entry id.
760
761
  * Does not allow writing CompactionSummaryMessage and BranchSummaryMessage directly.
@@ -1200,7 +1201,6 @@ export class SessionManager {
1200
1201
  header = firstEntry?.type === "session" ? firstEntry : null;
1201
1202
  }
1202
1203
  }
1203
- if (!header && getSessionBackend() !== "file") { try { preloadedFileEntries = loadEntriesFromDb(resolvedPath) ?? undefined; header = preloadedFileEntries?.find((e) => e.type === "session") ?? null; } catch {} }
1204
1204
  const cwd = cwdOverride ?? (header ? getSessionHeaderCwd(header) : undefined) ?? process.cwd();
1205
1205
  // If no sessionDir provided, derive from file's parent directory
1206
1206
  const dir = sessionDir ? normalizePath(sessionDir) : resolve(resolvedPath, "..");
@@ -1214,7 +1214,7 @@ export class SessionManager {
1214
1214
  static continueRecent(cwd, sessionDir) {
1215
1215
  const dir = sessionDir ? normalizePath(sessionDir) : getDefaultSessionDir(cwd);
1216
1216
  const filterCwd = sessionDir !== undefined && dir !== getDefaultSessionDirPath(cwd);
1217
- const mostRecent = getSessionBackend() === "file" ? findMostRecentSession(dir, filterCwd ? cwd : undefined) : findMostRecentSessionFromDb(dir);
1217
+ const mostRecent = findMostRecentSession(dir, filterCwd ? cwd : undefined);
1218
1218
  if (mostRecent) {
1219
1219
  return new SessionManager(cwd, dir, mostRecent, true);
1220
1220
  }
@@ -1234,8 +1234,7 @@ export class SessionManager {
1234
1234
  static forkFrom(sourcePath, targetCwd, sessionDir, options) {
1235
1235
  const resolvedSourcePath = resolvePath(sourcePath);
1236
1236
  const resolvedTargetCwd = resolvePath(targetCwd);
1237
- let sourceEntries = loadEntriesFromFile(resolvedSourcePath);
1238
- if (sourceEntries.length === 0 && getSessionBackend() !== "file") { try { sourceEntries = loadEntriesFromDb(resolvedSourcePath) ?? []; } catch {} }
1237
+ const sourceEntries = loadEntriesFromFile(resolvedSourcePath);
1239
1238
  if (sourceEntries.length === 0) {
1240
1239
  throw new Error(`Cannot fork: source session file is empty or invalid: ${resolvedSourcePath}`);
1241
1240
  }
@@ -1264,10 +1263,12 @@ export class SessionManager {
1264
1263
  cwd: resolvedTargetCwd,
1265
1264
  parentSession: resolvedSourcePath,
1266
1265
  };
1267
- if (getSessionBackend() !== "file") { try { mirrorSessionFileToDb(newSessionFile, [newHeader, ...sourceEntries.filter((e) => e.type !== "session")], resolvedTargetCwd, dir); } catch {} }
1268
- if (getSessionBackend() !== "db") {
1269
- writeFileSync(newSessionFile, `${JSON.stringify(newHeader)}\n`, { flag: "wx" });
1270
- for (const entry of sourceEntries) { if (entry.type !== "session") appendFileSync(newSessionFile, `${JSON.stringify(entry)}\n`); }
1266
+ writeFileSync(newSessionFile, `${JSON.stringify(newHeader)}\n`, { flag: "wx" });
1267
+ // Copy all non-header entries from source
1268
+ for (const entry of sourceEntries) {
1269
+ if (entry.type !== "session") {
1270
+ appendFileSync(newSessionFile, `${JSON.stringify(entry)}\n`);
1271
+ }
1271
1272
  }
1272
1273
  return new SessionManager(resolvedTargetCwd, dir, newSessionFile, true);
1273
1274
  }
@@ -1279,14 +1280,11 @@ export class SessionManager {
1279
1280
  */
1280
1281
  static async list(cwd, sessionDir, onProgress) {
1281
1282
  const dir = sessionDir ? normalizePath(sessionDir) : getDefaultSessionDir(cwd);
1282
- if (getSessionBackend() === "file") {
1283
- const filterCwd = sessionDir !== undefined && dir !== getDefaultSessionDirPath(cwd);
1284
- const resolvedCwd = resolvePath(cwd);
1285
- const sessions = (await listSessionsFromDir(dir, onProgress)).filter((session) => !filterCwd || sessionCwdMatches(session.cwd, resolvedCwd));
1286
- sessions.sort((a, b) => b.modified.getTime() - a.modified.getTime());
1287
- return sessions;
1288
- }
1289
- return listSessionsFromDb(dir, onProgress);
1283
+ const filterCwd = sessionDir !== undefined && dir !== getDefaultSessionDirPath(cwd);
1284
+ const resolvedCwd = resolvePath(cwd);
1285
+ const sessions = (await listSessionsFromDir(dir, onProgress)).filter((session) => !filterCwd || sessionCwdMatches(session.cwd, resolvedCwd));
1286
+ sessions.sort((a, b) => b.modified.getTime() - a.modified.getTime());
1287
+ return sessions;
1290
1288
  }
1291
1289
  static async listAll(sessionDirOrOnProgress, onProgress) {
1292
1290
  const customSessionDir = typeof sessionDirOrOnProgress === "string" ? normalizePath(sessionDirOrOnProgress) : undefined;
@@ -1,8 +1,7 @@
1
1
  /**
2
2
  * System prompt construction and project context loading
3
3
  */
4
- import { existsSync } from "node:fs";
5
- import { join } from "node:path";
4
+ import { getDocsPath, getExamplesPath, getReadmePath } from "../config.js";
6
5
  import { formatSkillsForPrompt } from "./skills.js";
7
6
  /** Build the system prompt with tools, guidelines, and context */
8
7
  export function buildSystemPrompt(options) {
@@ -33,22 +32,10 @@ export function buildSystemPrompt(options) {
33
32
  prompt += `\nCurrent working directory: ${promptCwd}`;
34
33
  return prompt;
35
34
  }
36
- // Get absolute paths to project documentation and examples.
37
- // Only project docs are advertised here. Harness/pi docs can be linked into the project docs
38
- // tree (for example docs/pi) when a project wants them in the prompt.
39
- const resolvedCwd = cwd;
40
- const existingPath = (filePath) => existsSync(filePath) ? filePath : undefined;
41
- const firstExistingPath = (filePaths) => filePaths.find((filePath) => existsSync(filePath));
42
- const projectReadmePath = firstExistingPath(["README.md", "README.MD", "readme.md"].map((name) => join(resolvedCwd, name)));
43
- const projectDocsPath = existingPath(join(resolvedCwd, "docs"));
44
- const projectExamplesPath = existingPath(join(resolvedCwd, "examples"));
45
- const documentationLines = [];
46
- if (projectReadmePath) documentationLines.push(`- Main documentation: ${projectReadmePath}`);
47
- if (projectDocsPath) documentationLines.push(`- Additional docs: ${projectDocsPath}`);
48
- if (projectExamplesPath) documentationLines.push(`- Examples: ${projectExamplesPath}`);
49
- if (projectDocsPath || projectExamplesPath) documentationLines.push("- When reading these docs or examples, resolve docs/... under Additional docs and examples/... under Examples, not the current working directory");
50
- if (projectDocsPath) documentationLines.push("- When working on this project, read the relevant docs and follow .md cross-references before implementing");
51
- const documentationSection = documentationLines.length > 0 ? `\n\nProject documentation (read only when relevant):\n${documentationLines.join("\n")}` : "";
35
+ // Get absolute paths to documentation and examples
36
+ const readmePath = getReadmePath();
37
+ const docsPath = getDocsPath();
38
+ const examplesPath = getExamplesPath();
52
39
  // Build tools list based on selected tools.
53
40
  // A tool appears in Available tools only when the caller provides a one-line snippet.
54
41
  const tools = selectedTools || ["read", "bash", "edit", "write"];
@@ -83,7 +70,7 @@ export function buildSystemPrompt(options) {
83
70
  addGuideline("Be concise in your responses");
84
71
  addGuideline("Show file paths clearly when working with files");
85
72
  const guidelines = guidelinesList.map((g) => `- ${g}`).join("\n");
86
- let prompt = `You are an expert coding assistant operating inside prism, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.
73
+ let prompt = `You are an expert coding assistant operating inside pi, a coding agent harness. You help users by reading files, executing commands, editing code, and writing new files.
87
74
 
88
75
  Available tools:
89
76
  ${toolsList}
@@ -91,7 +78,16 @@ ${toolsList}
91
78
  In addition to the tools above, you may have access to other custom tools depending on the project.
92
79
 
93
80
  Guidelines:
94
- ${guidelines}${documentationSection}`;
81
+ ${guidelines}
82
+
83
+ Pi documentation (read only when the user asks about pi itself, its SDK, extensions, themes, skills, or TUI):
84
+ - Main documentation: ${readmePath}
85
+ - Additional docs: ${docsPath}
86
+ - Examples: ${examplesPath} (extensions, custom tools, SDK)
87
+ - When reading pi docs or examples, resolve docs/... under Additional docs and examples/... under Examples, not the current working directory
88
+ - When asked about: extensions (docs/extensions.md, examples/extensions/), themes (docs/themes.md), skills (docs/skills.md), prompt templates (docs/prompt-templates.md), TUI components (docs/tui.md), keybindings (docs/keybindings.md), SDK integrations (docs/sdk.md), custom providers (docs/custom-provider.md), adding models (docs/models.md), pi packages (docs/packages.md), environment variables (docs/environment-variables.md)
89
+ - When working on pi topics, read the docs and examples, and follow .md cross-references before implementing
90
+ - Always read pi .md files completely and follow links to related docs (e.g., tui.md for TUI API details)`;
95
91
  if (appendSection) {
96
92
  prompt += appendSection;
97
93
  }
@@ -1,5 +1,4 @@
1
1
  import { spawnSync } from "node:child_process";
2
- import { deleteSessionFromDb } from "../../../core/prism-session-db.js";
3
2
  import { existsSync } from "node:fs";
4
3
  import { unlink } from "node:fs/promises";
5
4
  import * as os from "node:os";
@@ -540,9 +539,6 @@ class SessionList {
540
539
  * Delete a session file, trying the `trash` CLI first, then falling back to unlink
541
540
  */
542
541
  async function deleteSessionFile(sessionPath) {
543
- const _backend = process.env.PRISM_SESSION_BACKEND || "db";
544
- if (_backend !== "file") { try { deleteSessionFromDb(sessionPath); } catch {} }
545
- if (_backend === "db" && !existsSync(sessionPath)) return { ok: true, method: "trash" };
546
542
  // Try `trash` first (if installed)
547
543
  const trashArgs = sessionPath.startsWith("-") ? ["--", sessionPath] : [sessionPath];
548
544
  const trashResult = spawnSync("trash", trashArgs, { encoding: "utf-8" });