pi-ui-extend 0.1.3 → 0.1.5
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/app/app.d.ts +1 -1
- package/dist/app/app.js +14 -4
- package/dist/app/clipboard.d.ts +1 -0
- package/dist/app/clipboard.js +16 -0
- package/dist/app/conversation-entry-renderer.d.ts +0 -1
- package/dist/app/conversation-entry-renderer.js +2 -6
- package/dist/app/conversation-tool-renderer.js +2 -3
- package/dist/app/conversation-viewport.d.ts +0 -1
- package/dist/app/conversation-viewport.js +0 -1
- package/dist/app/startup-info.d.ts +1 -1
- package/dist/app/startup-info.js +3 -2
- package/dist/app/update.d.ts +2 -0
- package/dist/app/update.js +16 -0
- package/dist/config.d.ts +0 -3
- package/dist/config.js +0 -79
- package/dist/default-pix-config.js +2 -2
- package/dist/markdown-format.js +18 -1
- package/external/pi-tools-suite/README.md +4 -4
- package/external/pi-tools-suite/licenses/opencode-dynamic-context-pruning-AGPL-3.0.txt +619 -0
- package/external/pi-tools-suite/package.json +1 -1
- package/external/pi-tools-suite/src/config.ts +5 -1
- package/external/pi-tools-suite/src/{compress → dcp}/config.ts +10 -70
- package/external/pi-tools-suite/src/{compress → dcp}/index.ts +16 -66
- package/external/pi-tools-suite/src/dcp/ui.ts +45 -0
- package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +3 -2
- package/external/pi-tools-suite/src/index.ts +1 -1
- package/external/pi-tools-suite/src/tool-descriptions.ts +1 -1
- package/package.json +1 -1
- package/external/pi-tools-suite/src/compress/dcp-tui-filter.ts +0 -498
- package/external/pi-tools-suite/src/compress/ui.ts +0 -308
- /package/external/pi-tools-suite/src/{compress → dcp}/commands.ts +0 -0
- /package/external/pi-tools-suite/src/{compress → dcp}/compress-tool.ts +0 -0
- /package/external/pi-tools-suite/src/{compress → dcp}/compression-blocks.ts +0 -0
- /package/external/pi-tools-suite/src/{compress → dcp}/prompts.ts +0 -0
- /package/external/pi-tools-suite/src/{compress → dcp}/pruner-candidates.ts +0 -0
- /package/external/pi-tools-suite/src/{compress → dcp}/pruner-compression-blocks.ts +0 -0
- /package/external/pi-tools-suite/src/{compress → dcp}/pruner-message-ids.ts +0 -0
- /package/external/pi-tools-suite/src/{compress → dcp}/pruner-metadata.ts +0 -0
- /package/external/pi-tools-suite/src/{compress → dcp}/pruner-nudge.ts +0 -0
- /package/external/pi-tools-suite/src/{compress → dcp}/pruner-tools.ts +0 -0
- /package/external/pi-tools-suite/src/{compress → dcp}/pruner-types.ts +0 -0
- /package/external/pi-tools-suite/src/{compress → dcp}/pruner.ts +0 -0
- /package/external/pi-tools-suite/src/{compress → dcp}/state.ts +0 -0
package/dist/app/app.d.ts
CHANGED
|
@@ -19,7 +19,6 @@ export declare class PiUiExtendApp {
|
|
|
19
19
|
private readonly extensionActions;
|
|
20
20
|
private readonly pixConfig;
|
|
21
21
|
private readonly outputFilters;
|
|
22
|
-
private readonly suppressPendingDcpIdMetadata;
|
|
23
22
|
private readonly commandController;
|
|
24
23
|
private readonly inputActions;
|
|
25
24
|
private readonly inputController;
|
|
@@ -57,6 +56,7 @@ export declare class PiUiExtendApp {
|
|
|
57
56
|
private resumeLoading;
|
|
58
57
|
constructor(options: AppOptions);
|
|
59
58
|
start(): Promise<void>;
|
|
59
|
+
private checkPixUpdateOnStartup;
|
|
60
60
|
private bindCurrentSession;
|
|
61
61
|
private activateRuntime;
|
|
62
62
|
private createExtensionEventBus;
|
package/dist/app/app.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { THEMES } from "../theme.js";
|
|
2
2
|
import { InputEditor } from "../input-editor.js";
|
|
3
|
-
import { compileOutputFilterPatterns, loadPixConfig,
|
|
3
|
+
import { compileOutputFilterPatterns, loadPixConfig, resolveToolRule, } from "../config.js";
|
|
4
4
|
import { AppCommandController } from "./command-controller.js";
|
|
5
5
|
import { ConversationViewport } from "./conversation-viewport.js";
|
|
6
6
|
import { EditorLayoutRenderer } from "./editor-layout-renderer.js";
|
|
@@ -38,6 +38,7 @@ import { AppTabsController } from "./tabs-controller.js";
|
|
|
38
38
|
import { TabLineRenderer } from "./tab-line-renderer.js";
|
|
39
39
|
import { AppTerminalController } from "./terminal-controller.js";
|
|
40
40
|
import { AppToastController } from "./toast-controller.js";
|
|
41
|
+
import { checkPixUpdate, formatPixStartupUpdateDialog } from "./update.js";
|
|
41
42
|
import { AppVoiceController } from "./voice-controller.js";
|
|
42
43
|
import { createIsolatedExtensionEventBus } from "./extension-event-bus.js";
|
|
43
44
|
import { setAppIconTheme } from "./icons.js";
|
|
@@ -64,7 +65,6 @@ export class PiUiExtendApp {
|
|
|
64
65
|
extensionActions;
|
|
65
66
|
pixConfig;
|
|
66
67
|
outputFilters;
|
|
67
|
-
suppressPendingDcpIdMetadata;
|
|
68
68
|
commandController;
|
|
69
69
|
inputActions;
|
|
70
70
|
inputController;
|
|
@@ -367,7 +367,6 @@ export class PiUiExtendApp {
|
|
|
367
367
|
suppressExtensionWidget: (key) => this.extensionUiController.suppressWidget(key),
|
|
368
368
|
});
|
|
369
369
|
this.outputFilters = compileOutputFilterPatterns(this.pixConfig.outputFilters.patterns);
|
|
370
|
-
this.suppressPendingDcpIdMetadata = outputFiltersRemoveDcpIdMetadataLine(this.outputFilters);
|
|
371
370
|
this.conversationViewport = new ConversationViewport({
|
|
372
371
|
get entries() { return app.entries; },
|
|
373
372
|
get session() { return app.runtime?.session; },
|
|
@@ -379,7 +378,6 @@ export class PiUiExtendApp {
|
|
|
379
378
|
colors: this.theme.colors,
|
|
380
379
|
pixConfig: this.pixConfig,
|
|
381
380
|
outputFilters: this.outputFilters,
|
|
382
|
-
suppressPendingDcpIdMetadata: this.suppressPendingDcpIdMetadata,
|
|
383
381
|
hasDynamicConversationBlock: () => this.popupMenus.hasDynamicConversationBlock(),
|
|
384
382
|
isDynamicConversationBlock: (entry) => this.popupMenus.isDynamicConversationBlock(entry),
|
|
385
383
|
renderInlineUserMessageMenu: (entry, context) => this.popupMenus.renderInlineUserMessageMenu(entry, context),
|
|
@@ -677,6 +675,18 @@ export class PiUiExtendApp {
|
|
|
677
675
|
await this.sessionLifecycle.start();
|
|
678
676
|
this.modelUsageController.startPolling();
|
|
679
677
|
this.nerdFontController.ensureInstalledOnStartup();
|
|
678
|
+
void this.checkPixUpdateOnStartup();
|
|
679
|
+
}
|
|
680
|
+
async checkPixUpdateOnStartup() {
|
|
681
|
+
try {
|
|
682
|
+
const result = await checkPixUpdate();
|
|
683
|
+
if (result.status !== "newer")
|
|
684
|
+
return;
|
|
685
|
+
this.showToast(formatPixStartupUpdateDialog(result), "warning", { variant: "dialog" });
|
|
686
|
+
}
|
|
687
|
+
catch {
|
|
688
|
+
// Startup update checks should never interrupt the TUI.
|
|
689
|
+
}
|
|
680
690
|
}
|
|
681
691
|
async bindCurrentSession() {
|
|
682
692
|
await this.sessionLifecycle.bindCurrentSession();
|
package/dist/app/clipboard.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
export declare function copyTextToClipboard(text: string): void;
|
|
2
2
|
export declare function clipboardSupportAvailable(env?: NodeJS.ProcessEnv): boolean;
|
|
3
3
|
export declare function clipboardInstallHint(): string;
|
|
4
|
+
export declare function osc52ClipboardSequence(text: string, env?: NodeJS.ProcessEnv): string;
|
package/dist/app/clipboard.js
CHANGED
|
@@ -10,6 +10,8 @@ export function copyTextToClipboard(text) {
|
|
|
10
10
|
}
|
|
11
11
|
if (copyWithNativeClipboard(text))
|
|
12
12
|
return;
|
|
13
|
+
if (copyWithOsc52(text))
|
|
14
|
+
return;
|
|
13
15
|
throw new Error(`No clipboard command found. ${clipboardInstallHint()}`);
|
|
14
16
|
}
|
|
15
17
|
export function clipboardSupportAvailable(env = process.env) {
|
|
@@ -60,6 +62,20 @@ function copyWithNativeClipboard(text) {
|
|
|
60
62
|
});
|
|
61
63
|
return !result.error && result.status === 0;
|
|
62
64
|
}
|
|
65
|
+
function copyWithOsc52(text) {
|
|
66
|
+
if (process.stdout.destroyed || (!process.stdout.isTTY && !process.env.TMUX && !process.env.STY))
|
|
67
|
+
return false;
|
|
68
|
+
process.stdout.write(osc52ClipboardSequence(text));
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
export function osc52ClipboardSequence(text, env = process.env) {
|
|
72
|
+
const sequence = `\x1b]52;c;${Buffer.from(text, "utf8").toString("base64")}\x07`;
|
|
73
|
+
if (env.TMUX)
|
|
74
|
+
return `\x1bPtmux;${sequence.replaceAll("\x1b", "\x1b\x1b")}\x1b\\`;
|
|
75
|
+
if (env.STY)
|
|
76
|
+
return `\x1bP${sequence}\x1b\\`;
|
|
77
|
+
return sequence;
|
|
78
|
+
}
|
|
63
79
|
function resolveNativeClipboardEntrypoint() {
|
|
64
80
|
try {
|
|
65
81
|
return require.resolve("@mariozechner/clipboard");
|
|
@@ -11,7 +11,6 @@ export type ConversationEntryRenderOptions = {
|
|
|
11
11
|
colors: Theme["colors"];
|
|
12
12
|
pixConfig: PixConfig;
|
|
13
13
|
outputFilters: readonly RegExp[];
|
|
14
|
-
suppressPendingDcpIdMetadata: boolean;
|
|
15
14
|
superCompactTools?: boolean;
|
|
16
15
|
allThinkingExpanded?: boolean;
|
|
17
16
|
renderInlineUserMessageMenu: (entry: Extract<Entry, {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { applyOutputFilters
|
|
1
|
+
import { applyOutputFilters } from "../config.js";
|
|
2
2
|
import { renderMarkdownTextLines } from "../markdown-format.js";
|
|
3
3
|
import { attachImageClickTargets } from "./image-click-targets.js";
|
|
4
4
|
import { horizontalPaddingLayout, padHorizontalText, wrapText } from "./render-text.js";
|
|
@@ -65,7 +65,7 @@ function renderCustomEntry(entry, width) {
|
|
|
65
65
|
}));
|
|
66
66
|
}
|
|
67
67
|
function renderAssistantLines(text, width, options) {
|
|
68
|
-
const displayText =
|
|
68
|
+
const displayText = applyOutputFilters(text, options.outputFilters).trimEnd();
|
|
69
69
|
if (!displayText)
|
|
70
70
|
return [];
|
|
71
71
|
return renderMarkdownTextLines(displayText, width).map((line) => ({
|
|
@@ -75,7 +75,3 @@ function renderAssistantLines(text, width, options) {
|
|
|
75
75
|
...(line.syntaxHighlight ? { syntaxHighlight: line.syntaxHighlight } : {}),
|
|
76
76
|
}));
|
|
77
77
|
}
|
|
78
|
-
function displayAssistantText(text, outputFilters, suppressPendingDcpIdMetadata) {
|
|
79
|
-
const filtered = stripDcpDisplayMetadata(applyOutputFilters(text, outputFilters)).trimEnd();
|
|
80
|
-
return suppressPendingDcpIdMetadata ? suppressPendingDcpIdMetadataLine(filtered) : filtered;
|
|
81
|
-
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { resolveColor, resolveToolRule
|
|
1
|
+
import { resolveColor, resolveToolRule } from "../config.js";
|
|
2
2
|
import { formatMarkdownTables, markdownSyntaxHighlightsForText } from "../markdown-format.js";
|
|
3
3
|
import { renderToolDisplay } from "../tool-renderers/index.js";
|
|
4
4
|
import { DEFAULT_THINKING_TOOL_RULE, SUBAGENT_STATUSES, THINKING_TOOL_NAME, TODO_TOOL_NAME } from "./constants.js";
|
|
@@ -47,8 +47,7 @@ export function renderConversationToolEntry(entry, width, options) {
|
|
|
47
47
|
}
|
|
48
48
|
export function renderThinkingEntry(entry, width, options) {
|
|
49
49
|
const rule = resolveThinkingToolRule(options.pixConfig);
|
|
50
|
-
const
|
|
51
|
-
const markdownText = displayText ? formatMarkdownTables(displayText, Math.max(1, width - 2)) : "";
|
|
50
|
+
const markdownText = entry.text ? formatMarkdownTables(entry.text, Math.max(1, width - 2)) : "";
|
|
52
51
|
const expandedText = trimTrailingBlankLines(markdownText);
|
|
53
52
|
const compactExpandedText = options.superCompactTools ? removeBlankLines(expandedText) : expandedText;
|
|
54
53
|
const forceExpanded = Boolean(options.allThinkingExpanded);
|
|
@@ -12,7 +12,6 @@ export type ConversationViewportHost = {
|
|
|
12
12
|
readonly colors: Theme["colors"];
|
|
13
13
|
readonly pixConfig: PixConfig;
|
|
14
14
|
readonly outputFilters: readonly RegExp[];
|
|
15
|
-
readonly suppressPendingDcpIdMetadata: boolean;
|
|
16
15
|
readonly superCompactTools?: boolean;
|
|
17
16
|
readonly allThinkingExpanded?: boolean;
|
|
18
17
|
hasDynamicConversationBlock?(): boolean;
|
|
@@ -65,7 +65,6 @@ export class ConversationViewport {
|
|
|
65
65
|
colors: this.host.colors,
|
|
66
66
|
pixConfig: this.host.pixConfig,
|
|
67
67
|
outputFilters: this.host.outputFilters,
|
|
68
|
-
suppressPendingDcpIdMetadata: this.host.suppressPendingDcpIdMetadata,
|
|
69
68
|
superCompactTools: Boolean(this.host.superCompactTools),
|
|
70
69
|
allThinkingExpanded: Boolean(this.host.allThinkingExpanded),
|
|
71
70
|
renderInlineUserMessageMenu: (userEntry, context) => this.host.renderInlineUserMessageMenu(userEntry, context),
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { AgentSessionRuntime } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
export declare function createStartupInfoMessage(runtime: AgentSessionRuntime): string;
|
|
3
3
|
export declare function isEmptyStartupSession(runtime: AgentSessionRuntime): boolean;
|
package/dist/app/startup-info.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { homedir } from "node:os";
|
|
2
2
|
import { basename, isAbsolute, relative, sep } from "node:path";
|
|
3
|
-
import {
|
|
3
|
+
import { getPixPackageVersion } from "./update.js";
|
|
4
4
|
export function createStartupInfoMessage(runtime) {
|
|
5
5
|
const sections = startupSections(runtime);
|
|
6
6
|
return [
|
|
7
7
|
formatModelLine(runtime),
|
|
8
|
-
|
|
8
|
+
"",
|
|
9
|
+
`pix v${getPixPackageVersion()}`,
|
|
9
10
|
"escape interrupt · ctrl+c/ctrl+d clear/exit · / commands",
|
|
10
11
|
"",
|
|
11
12
|
...sections.flatMap(formatSection),
|
package/dist/app/update.d.ts
CHANGED
|
@@ -30,7 +30,9 @@ export type PixUpdateCheckOptions = {
|
|
|
30
30
|
};
|
|
31
31
|
export declare function pixUpdateUsage(): string;
|
|
32
32
|
export declare function parsePixUpdateArgs(argv: readonly string[]): PixUpdateCliOptions;
|
|
33
|
+
export declare function getPixPackageVersion(packageRoot?: string): string;
|
|
33
34
|
export declare function checkPixUpdate(options?: PixUpdateCheckOptions): Promise<PixUpdateCheckResult>;
|
|
34
35
|
export declare function formatPixUpdateCheck(result: PixUpdateCheckResult): string;
|
|
36
|
+
export declare function formatPixStartupUpdateDialog(result: PixUpdateCheckResult): string;
|
|
35
37
|
export declare function getPixSelfUpdateCommand(packageName: string, latestVersion?: string, packageRoot?: string): PixSelfUpdateCommand | undefined;
|
|
36
38
|
export declare function runPixUpdateCli(argv?: readonly string[]): Promise<number>;
|
package/dist/app/update.js
CHANGED
|
@@ -40,6 +40,9 @@ export function parsePixUpdateArgs(argv) {
|
|
|
40
40
|
}
|
|
41
41
|
return { checkOnly, force, help };
|
|
42
42
|
}
|
|
43
|
+
export function getPixPackageVersion(packageRoot) {
|
|
44
|
+
return readPixPackageInfo(packageRoot).version;
|
|
45
|
+
}
|
|
43
46
|
export async function checkPixUpdate(options = {}) {
|
|
44
47
|
const packageInfo = readPixPackageInfo(options.packageRoot);
|
|
45
48
|
const base = {
|
|
@@ -107,6 +110,19 @@ export function formatPixUpdateCheck(result) {
|
|
|
107
110
|
lines.push("scope: Pix package, renderer extensions, bundled skills copied into ~/.agents/skills, and the pi-tools-suite payload linked into ~/.pi/agent/extensions");
|
|
108
111
|
return lines.join("\n");
|
|
109
112
|
}
|
|
113
|
+
export function formatPixStartupUpdateDialog(result) {
|
|
114
|
+
const lines = [
|
|
115
|
+
"A new Pix version is available.",
|
|
116
|
+
`current: ${result.packageName} v${result.currentVersion}`,
|
|
117
|
+
...(result.latestVersion ? [`latest: ${result.latestVersion}`] : []),
|
|
118
|
+
"",
|
|
119
|
+
"To update:",
|
|
120
|
+
"1. Exit Pix.",
|
|
121
|
+
"2. Run `pix update` in your shell.",
|
|
122
|
+
"3. Start Pix again after the update completes.",
|
|
123
|
+
];
|
|
124
|
+
return lines.join("\n");
|
|
125
|
+
}
|
|
110
126
|
export function getPixSelfUpdateCommand(packageName, latestVersion, packageRoot = readPixPackageInfo().packageRoot) {
|
|
111
127
|
if (!packageRootLooksPackageManaged(packageRoot))
|
|
112
128
|
return undefined;
|
package/dist/config.d.ts
CHANGED
|
@@ -54,9 +54,6 @@ export declare function savePixDictationLanguage(language: string): void;
|
|
|
54
54
|
export declare function upsertPixDictationLanguageInJsonc(source: string, language: string): string;
|
|
55
55
|
export declare function resolveModelColor(modelRef: string, config: ModelColorsConfig): string | undefined;
|
|
56
56
|
export declare function compileOutputFilterPatterns(patterns: readonly string[]): RegExp[];
|
|
57
|
-
export declare function stripDcpDisplayMetadata(text: string): string;
|
|
58
57
|
export declare function applyOutputFilters(text: string, filters: readonly RegExp[]): string;
|
|
59
|
-
export declare function outputFiltersRemoveDcpIdMetadataLine(filters: readonly RegExp[]): boolean;
|
|
60
|
-
export declare function suppressPendingDcpIdMetadataLine(text: string): string;
|
|
61
58
|
export declare function resolveToolRule(toolName: string, config: ToolRendererConfig): ResolvedToolRule;
|
|
62
59
|
export declare function resolveColor(colorRef: string, themeColors: Record<string, string>): string;
|
package/dist/config.js
CHANGED
|
@@ -77,17 +77,6 @@ const DEFAULT_DICTATION = {
|
|
|
77
77
|
},
|
|
78
78
|
},
|
|
79
79
|
};
|
|
80
|
-
const DCP_ID_METADATA_SAMPLE = "<dcp-id>m001</dcp-id>";
|
|
81
|
-
const DCP_ID_METADATA_PREFIX = "<dcp-id>m";
|
|
82
|
-
const DCP_ID_METADATA_SUFFIX = "</dcp-id>";
|
|
83
|
-
const DCP_XML_PAIRED_TAG_RE = /<dcp[^>]*>[\s\S]*?<\/dcp[^>]*>/gi;
|
|
84
|
-
const DCP_XML_OPEN_TAG_TO_END_RE = /<dcp[^>]*>[\s\S]*$/gi;
|
|
85
|
-
const DCP_XML_UNPAIRED_TAG_RE = /<\/?dcp[^>]*>/gi;
|
|
86
|
-
const DCP_MARKDOWN_REFERENCE_RE = /[ \t]*\[dcp(?:-[a-z0-9-]+)?\]:[ \t]*#(?:[ \t]+\([^\n]*\))?[ \t]*/gi;
|
|
87
|
-
const DCP_MARKDOWN_REFERENCE_LINE_RE = /^[ \t]*\[dcp(?:-[a-z0-9-]+)?\]:[ \t]*#(?:[ \t]+\([^\n]*\))?[ \t]*$/i;
|
|
88
|
-
const DCP_MARKDOWN_REFERENCE_PENDING_RE = /^\[d(?:c(?:p(?:-[a-z0-9-]*)?)?)?(?:\]?(?::[ \t]*#?(?:[ \t]*\([^\)\n]*)?)?)?$/i;
|
|
89
|
-
const DCP_XML_METADATA_LINE_RE = /^[ \t]*<dcp[^>]*>(?:[\s\S]*?<\/dcp[^>]*>)?[ \t]*$/i;
|
|
90
|
-
const DCP_DISPLAY_QUICK_CHECK_RE = /<\/?d(?:c(?:p)?)?|\[d(?:c(?:p)?)?/i;
|
|
91
80
|
function parseJsonc(text) {
|
|
92
81
|
return parse(text, undefined, { allowTrailingComma: true });
|
|
93
82
|
}
|
|
@@ -322,37 +311,6 @@ export function resolveModelColor(modelRef, config) {
|
|
|
322
311
|
export function compileOutputFilterPatterns(patterns) {
|
|
323
312
|
return patterns.flatMap((pattern) => compileOutputFilterPattern(pattern));
|
|
324
313
|
}
|
|
325
|
-
export function stripDcpDisplayMetadata(text) {
|
|
326
|
-
if (text.length === 0 || !DCP_DISPLAY_QUICK_CHECK_RE.test(text))
|
|
327
|
-
return text;
|
|
328
|
-
let cleaned = stripDcpDisplayMetadataLines(text);
|
|
329
|
-
// Strip fully paired XML-style DCP tags first. During streaming, strip an
|
|
330
|
-
// unterminated opening XML tag and everything after it before removing
|
|
331
|
-
// orphan tags, otherwise `<dcp-id>m123` would leave `m123` behind.
|
|
332
|
-
cleaned = cleaned
|
|
333
|
-
.replace(DCP_XML_PAIRED_TAG_RE, "")
|
|
334
|
-
.replace(DCP_XML_OPEN_TAG_TO_END_RE, "")
|
|
335
|
-
.replace(DCP_XML_UNPAIRED_TAG_RE, "");
|
|
336
|
-
// Hide a partially streamed markdown reference line before the complete-line
|
|
337
|
-
// regex can strip the prefix and strand the `(m123` payload.
|
|
338
|
-
cleaned = suppressPendingDcpIdMetadataLine(cleaned).replace(DCP_MARKDOWN_REFERENCE_RE, "");
|
|
339
|
-
cleaned = suppressPendingDcpIdMetadataLine(cleaned);
|
|
340
|
-
cleaned = stripDcpDisplayMetadataLines(cleaned);
|
|
341
|
-
return cleaned.replace(/\n{3,}/g, "\n\n").trimEnd();
|
|
342
|
-
}
|
|
343
|
-
function stripDcpDisplayMetadataLines(text) {
|
|
344
|
-
if (text.length === 0)
|
|
345
|
-
return text;
|
|
346
|
-
let removed = false;
|
|
347
|
-
const keptLines = text.split("\n").filter((line) => {
|
|
348
|
-
const normalizedLine = line.replace(/\r$/u, "");
|
|
349
|
-
const isMetadataLine = DCP_MARKDOWN_REFERENCE_LINE_RE.test(normalizedLine) || DCP_XML_METADATA_LINE_RE.test(normalizedLine);
|
|
350
|
-
if (isMetadataLine)
|
|
351
|
-
removed = true;
|
|
352
|
-
return !isMetadataLine;
|
|
353
|
-
});
|
|
354
|
-
return removed ? keptLines.join("\n") : text;
|
|
355
|
-
}
|
|
356
314
|
export function applyOutputFilters(text, filters) {
|
|
357
315
|
if (filters.length === 0 || text.length === 0)
|
|
358
316
|
return text;
|
|
@@ -374,43 +332,6 @@ export function applyOutputFilters(text, filters) {
|
|
|
374
332
|
}
|
|
375
333
|
return filteredLines.join("\n");
|
|
376
334
|
}
|
|
377
|
-
export function outputFiltersRemoveDcpIdMetadataLine(filters) {
|
|
378
|
-
return filters.length > 0 && applyOutputFilters(DCP_ID_METADATA_SAMPLE, filters).length === 0;
|
|
379
|
-
}
|
|
380
|
-
export function suppressPendingDcpIdMetadataLine(text) {
|
|
381
|
-
if (text.length === 0)
|
|
382
|
-
return text;
|
|
383
|
-
const lineStart = text.lastIndexOf("\n") + 1;
|
|
384
|
-
const line = text.slice(lineStart);
|
|
385
|
-
if (!isPendingDcpIdMetadataLine(line))
|
|
386
|
-
return text;
|
|
387
|
-
// Hide the still-streaming metadata line and its line break until it either
|
|
388
|
-
// becomes a complete filtered line or diverges from the metadata prefix.
|
|
389
|
-
return lineStart > 0 ? text.slice(0, lineStart - 1) : "";
|
|
390
|
-
}
|
|
391
|
-
function isPendingDcpIdMetadataLine(line) {
|
|
392
|
-
const candidate = line.trimStart();
|
|
393
|
-
if (candidate.length === 0)
|
|
394
|
-
return false;
|
|
395
|
-
return isPendingXmlDcpIdMetadataLine(candidate) || isPendingMarkdownDcpMetadataLine(candidate);
|
|
396
|
-
}
|
|
397
|
-
function isPendingXmlDcpIdMetadataLine(candidate) {
|
|
398
|
-
if (DCP_ID_METADATA_PREFIX.startsWith(candidate))
|
|
399
|
-
return true;
|
|
400
|
-
if (!candidate.startsWith(DCP_ID_METADATA_PREFIX))
|
|
401
|
-
return false;
|
|
402
|
-
const afterPrefix = candidate.slice(DCP_ID_METADATA_PREFIX.length);
|
|
403
|
-
const digits = afterPrefix.match(/^\d*/)?.[0] ?? "";
|
|
404
|
-
const afterDigits = afterPrefix.slice(digits.length);
|
|
405
|
-
if (afterDigits.length === 0)
|
|
406
|
-
return true;
|
|
407
|
-
return DCP_ID_METADATA_SUFFIX.startsWith(afterDigits) && afterDigits.length < DCP_ID_METADATA_SUFFIX.length;
|
|
408
|
-
}
|
|
409
|
-
function isPendingMarkdownDcpMetadataLine(candidate) {
|
|
410
|
-
if (DCP_MARKDOWN_REFERENCE_LINE_RE.test(candidate))
|
|
411
|
-
return false;
|
|
412
|
-
return DCP_MARKDOWN_REFERENCE_PENDING_RE.test(candidate);
|
|
413
|
-
}
|
|
414
335
|
function applyOutputFiltersToLine(line, filters) {
|
|
415
336
|
let filtered = line;
|
|
416
337
|
for (const filter of filters) {
|
|
@@ -169,10 +169,10 @@ export const DEFAULT_PIX_CONFIG_JSONC = String.raw `{
|
|
|
169
169
|
},
|
|
170
170
|
|
|
171
171
|
// Output filters applied to assistant text in the renderer.
|
|
172
|
-
// Supports glob-style * wildcards, or regex literals like "
|
|
172
|
+
// Supports glob-style * wildcards, or regex literals like "/token=\\w+/".
|
|
173
173
|
// "outputFilters": {
|
|
174
174
|
// "patterns": [
|
|
175
|
-
// "
|
|
175
|
+
// "secret-*"
|
|
176
176
|
// ]
|
|
177
177
|
// },
|
|
178
178
|
|
package/dist/markdown-format.js
CHANGED
|
@@ -4,6 +4,7 @@ export function formatMarkdownTables(text, maxWidth) {
|
|
|
4
4
|
const lines = text.split("\n");
|
|
5
5
|
const formatted = [];
|
|
6
6
|
let fence;
|
|
7
|
+
let skipBlankAfterHiddenReference = false;
|
|
7
8
|
for (let index = 0; index < lines.length;) {
|
|
8
9
|
const line = lines[index] ?? "";
|
|
9
10
|
const nextFence = markdownFence(line);
|
|
@@ -16,6 +17,16 @@ export function formatMarkdownTables(text, maxWidth) {
|
|
|
16
17
|
index += 1;
|
|
17
18
|
continue;
|
|
18
19
|
}
|
|
20
|
+
if (!fence && isMarkdownReferenceDefinition(line)) {
|
|
21
|
+
skipBlankAfterHiddenReference = formatted.length === 0 || (formatted.at(-1) ?? "").trim().length === 0;
|
|
22
|
+
index += 1;
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (!fence && skipBlankAfterHiddenReference && line.trim().length === 0) {
|
|
26
|
+
index += 1;
|
|
27
|
+
continue;
|
|
28
|
+
}
|
|
29
|
+
skipBlankAfterHiddenReference = false;
|
|
19
30
|
if (!fence) {
|
|
20
31
|
const table = parseMarkdownTableBlock(lines, index);
|
|
21
32
|
if (table) {
|
|
@@ -61,7 +72,10 @@ export function renderMarkdownLine(text, start = 0) {
|
|
|
61
72
|
export function renderMarkdownTextLines(text, width, start = 0) {
|
|
62
73
|
const lines = [];
|
|
63
74
|
let fence;
|
|
64
|
-
|
|
75
|
+
const formattedText = formatMarkdownTables(sanitizeMarkdownText(text), width);
|
|
76
|
+
if (formattedText.length === 0)
|
|
77
|
+
return [];
|
|
78
|
+
for (const rawLine of formattedText.split("\n")) {
|
|
65
79
|
const nextFence = markdownFence(rawLine);
|
|
66
80
|
const closesFence = Boolean(fence && nextFence && fence.marker === nextFence.marker && nextFence.length >= fence.length);
|
|
67
81
|
const opensFence = !fence && nextFence !== undefined;
|
|
@@ -533,6 +547,9 @@ function markdownLineSyntaxHighlight(fence, fenceDelimiterLine, start) {
|
|
|
533
547
|
function sanitizeMarkdownText(text) {
|
|
534
548
|
return expandTabs(text.replace(/\x1b/g, "␛").replace(/\r/g, ""));
|
|
535
549
|
}
|
|
550
|
+
function isMarkdownReferenceDefinition(line) {
|
|
551
|
+
return /^ {0,3}\[[^\]\n]+\]:[ \t]*\S.*$/u.test(line);
|
|
552
|
+
}
|
|
536
553
|
function markdownFence(line) {
|
|
537
554
|
const match = /^\s{0,3}(`{3,}|~{3,})(.*)$/.exec(line);
|
|
538
555
|
const marker = match?.[1];
|
|
@@ -14,12 +14,12 @@ This package keeps the former standalone extensions as ordinary source folders u
|
|
|
14
14
|
- `src/model-tools` — model-specific tool aliases such as Claude/GLM-style `Read` / `Edit` / `Write` / `Bash` / `Grep` / `Glob` / `LS`, GPT/Codex-style `shell`, and model-gated `apply_patch`
|
|
15
15
|
- `src/usage` — `/usage` command and startup hint for read-only AI quota checks across OpenAI, Zhipu AI, Z.ai, and Google Antigravity, including Antigravity quota by model
|
|
16
16
|
- `src/web-search` — `web_search` and `web_fetch` tools migrated from `@ollama/pi-web-search`; calls the local Ollama experimental web search/fetch APIs, honors `OLLAMA_HOST`, supports request timeouts via `timeout_ms` / `PI_WEB_SEARCH_TIMEOUT_MS`, and reports targeted `ollama signin`, unsupported-endpoint, invalid-response, timeout, DNS, and Ollama-not-running errors
|
|
17
|
-
- `src/
|
|
17
|
+
- `src/dcp` — headless Dynamic Context Pruning ported from `opencode-dynamic-context-pruning` for the Pi SDK: explicit `compress` tool with range and message modes, `/dcp` commands (context, stats, sweep, manual, decompress, recompress, compress), same-call overlap validation, recoverable compressed-block rollups, grouped message-mode skip diagnostics, stable raw-message anchors when available, protected user/tool preservation, deduplication, error purging, and context nudges; visualization is left to `compress` tool responses and the renderer-owned context-percent click dialog
|
|
18
18
|
- `src/prompt-commands` — user slash-command builder: `/prompt-commands` opens a CRUD menu for saved prompt-backed slash commands, stores them under `promptCommands` in `~/.config/pi/pi-tools-suite.jsonc`, reloads after edits, and runs each saved prompt as a normal user message
|
|
19
19
|
|
|
20
20
|
`index.ts` is intentionally only a thin auto-discovery shim that re-exports `src/index.ts`. There is no `pi.extensions` manifest here, so local Pi auto-discovery loads the suite once via `~/.pi/agent/extensions/pi-tools-suite/index.ts` and does not double-register tools.
|
|
21
21
|
|
|
22
|
-
Registration order is preserved in `src/index.ts`: ast-grep, async-subagents, terminal-bell, lsp, repo-discovery command/tool gate, antigravity-auth provider, todo, model-tools, usage, web-search,
|
|
22
|
+
Registration order is preserved in `src/index.ts`: ast-grep, async-subagents, terminal-bell, lsp, repo-discovery command/tool gate, antigravity-auth provider, todo, model-tools, usage, web-search, dcp, then prompt-commands. Tool metadata and active model-specific tool sets have two modes: standard and repo-aware. When `.indexer-cli` enables `repo_*`, those tools stay active ahead of overlapping lower-level aliases so the indexed discovery surface has priority.
|
|
23
23
|
|
|
24
24
|
## Disabling modules
|
|
25
25
|
|
|
@@ -55,7 +55,7 @@ Saved prompt slash commands are stored under `promptCommands`. Use `/prompt-comm
|
|
|
55
55
|
}
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
DCP
|
|
58
|
+
DCP settings are stored only under `dcp` in the user shared config file `~/.config/pi/pi-tools-suite.jsonc`. Legacy standalone `dcp.jsonc`, `$PI_CONFIG_DIR`, and project-local `.pi/pi-tools-suite.jsonc` DCP settings are intentionally ignored by the ported headless DCP module.
|
|
59
59
|
|
|
60
60
|
```jsonc
|
|
61
61
|
{
|
|
@@ -214,7 +214,7 @@ pi-tools-suite/
|
|
|
214
214
|
model-tools/
|
|
215
215
|
usage/
|
|
216
216
|
web-search/
|
|
217
|
-
|
|
217
|
+
dcp/
|
|
218
218
|
prompt-commands/
|
|
219
219
|
docs/
|
|
220
220
|
licenses/
|