@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.
- package/dist/prism-extensions/integrations/ai-memory-errors.d.ts +13 -0
- package/dist/prism-extensions/integrations/ai-memory-errors.js +54 -0
- package/dist/prism-extensions/integrations/ai-memory-errors.js.map +1 -1
- package/dist/prism-extensions/integrations/ai-memory-http.d.ts +28 -0
- package/dist/prism-extensions/integrations/ai-memory-http.js +92 -0
- package/dist/prism-extensions/integrations/ai-memory-http.js.map +1 -0
- package/dist/prism-extensions/integrations/ai-memory-system.d.ts +2 -0
- package/dist/prism-extensions/integrations/ai-memory-system.js +49 -127
- package/dist/prism-extensions/integrations/ai-memory-system.js.map +1 -1
- package/dist/prism-extensions/integrations/ai-memory-write-preview.d.ts +36 -0
- package/dist/prism-extensions/integrations/ai-memory-write-preview.js +67 -0
- package/dist/prism-extensions/integrations/ai-memory-write-preview.js.map +1 -0
- package/dist/prism-extensions/ui/collapsed-text-rendering.d.ts +4 -2
- package/dist/prism-extensions/ui/collapsed-text-rendering.js +12 -7
- package/dist/prism-extensions/ui/collapsed-text-rendering.js.map +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/cli.js +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/config.js +11 -6
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.js +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js +0 -5
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/auth-storage.js +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/loader.js +1 -3
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/project-trust.js +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.js +1 -1
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.js +37 -39
- package/node_modules/@earendil-works/pi-coding-agent/dist/core/system-prompt.js +16 -20
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/session-selector.js +0 -4
- package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js +2376 -234
- package/node_modules/@earendil-works/pi-tui/dist/autocomplete.js +1 -1
- package/package.json +3 -3
- package/src/prism-extensions/integrations/ai-memory-errors.ts +59 -0
- package/src/prism-extensions/integrations/ai-memory-http.ts +114 -0
- package/src/prism-extensions/integrations/ai-memory-system.ts +60 -135
- package/src/prism-extensions/integrations/ai-memory-write-preview.ts +83 -0
- package/src/prism-extensions/ui/collapsed-text-rendering.ts +14 -8
- 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
|
|
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 (!
|
|
19
|
-
rendered
|
|
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
|
-
|
|
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;
|
|
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
|
-
//
|
|
325
|
-
|
|
326
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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:
|
|
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 =
|
|
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 "
|
|
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
|
|
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 =
|
|
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
|
|
643
|
-
|
|
644
|
-
|
|
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
|
-
|
|
742
|
-
|
|
743
|
-
|
|
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
|
-
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
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
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
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 {
|
|
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
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
const
|
|
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
|
|
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}
|
|
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" });
|