@oh-my-pi/pi-coding-agent 12.7.6 → 12.8.0
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/CHANGELOG.md +37 -37
- package/README.md +9 -1052
- package/package.json +7 -7
- package/src/cli/args.ts +1 -0
- package/src/cli/update-cli.ts +49 -35
- package/src/cli/web-search-cli.ts +3 -2
- package/src/commands/web-search.ts +1 -0
- package/src/config/model-registry.ts +6 -0
- package/src/config/settings-schema.ts +25 -3
- package/src/config/settings.ts +1 -0
- package/src/extensibility/extensions/wrapper.ts +20 -13
- package/src/extensibility/slash-commands.ts +12 -91
- package/src/lsp/client.ts +24 -27
- package/src/lsp/index.ts +92 -42
- package/src/mcp/config-writer.ts +33 -0
- package/src/mcp/config.ts +6 -1
- package/src/mcp/types.ts +1 -0
- package/src/modes/components/custom-editor.ts +8 -5
- package/src/modes/components/settings-defs.ts +2 -1
- package/src/modes/controllers/command-controller.ts +12 -6
- package/src/modes/controllers/input-controller.ts +21 -186
- package/src/modes/controllers/mcp-command-controller.ts +60 -3
- package/src/modes/interactive-mode.ts +2 -2
- package/src/modes/types.ts +1 -1
- package/src/sdk.ts +23 -1
- package/src/secrets/index.ts +116 -0
- package/src/secrets/obfuscator.ts +269 -0
- package/src/secrets/regex.ts +21 -0
- package/src/session/agent-session.ts +143 -21
- package/src/session/compaction/branch-summarization.ts +2 -2
- package/src/session/compaction/compaction.ts +10 -3
- package/src/session/compaction/utils.ts +25 -1
- package/src/slash-commands/builtin-registry.ts +419 -0
- package/src/web/scrapers/github.ts +50 -12
- package/src/web/search/index.ts +5 -5
- package/src/web/search/provider.ts +13 -2
- package/src/web/search/providers/brave.ts +165 -0
- package/src/web/search/types.ts +1 -1
- package/docs/compaction.md +0 -436
- package/docs/config-usage.md +0 -176
- package/docs/custom-tools.md +0 -585
- package/docs/environment-variables.md +0 -257
- package/docs/extension-loading.md +0 -106
- package/docs/extensions.md +0 -1342
- package/docs/fs-scan-cache-architecture.md +0 -50
- package/docs/hooks.md +0 -906
- package/docs/models.md +0 -234
- package/docs/python-repl.md +0 -110
- package/docs/rpc.md +0 -1173
- package/docs/sdk.md +0 -1039
- package/docs/session-tree-plan.md +0 -84
- package/docs/session.md +0 -368
- package/docs/skills.md +0 -254
- package/docs/theme.md +0 -696
- package/docs/tree.md +0 -206
- package/docs/tui.md +0 -487
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oh-my-pi/pi-coding-agent",
|
|
3
|
-
"version": "12.
|
|
3
|
+
"version": "12.8.0",
|
|
4
4
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -84,12 +84,12 @@
|
|
|
84
84
|
},
|
|
85
85
|
"dependencies": {
|
|
86
86
|
"@mozilla/readability": "0.6.0",
|
|
87
|
-
"@oh-my-pi/omp-stats": "12.
|
|
88
|
-
"@oh-my-pi/pi-agent-core": "12.
|
|
89
|
-
"@oh-my-pi/pi-ai": "12.
|
|
90
|
-
"@oh-my-pi/pi-natives": "12.
|
|
91
|
-
"@oh-my-pi/pi-tui": "12.
|
|
92
|
-
"@oh-my-pi/pi-utils": "12.
|
|
87
|
+
"@oh-my-pi/omp-stats": "12.8.0",
|
|
88
|
+
"@oh-my-pi/pi-agent-core": "12.8.0",
|
|
89
|
+
"@oh-my-pi/pi-ai": "12.8.0",
|
|
90
|
+
"@oh-my-pi/pi-natives": "12.8.0",
|
|
91
|
+
"@oh-my-pi/pi-tui": "12.8.0",
|
|
92
|
+
"@oh-my-pi/pi-utils": "12.8.0",
|
|
93
93
|
"@sinclair/typebox": "^0.34.48",
|
|
94
94
|
"@xterm/headless": "^6.0.0",
|
|
95
95
|
"ajv": "^8.18.0",
|
package/src/cli/args.ts
CHANGED
|
@@ -213,6 +213,7 @@ export function getExtraHelpText(): string {
|
|
|
213
213
|
|
|
214
214
|
${chalk.dim("# Search & Tools")}
|
|
215
215
|
EXA_API_KEY - Exa web search
|
|
216
|
+
BRAVE_API_KEY - Brave web search
|
|
216
217
|
PERPLEXITY_API_KEY - Perplexity web search
|
|
217
218
|
ANTHROPIC_SEARCH_API_KEY - Anthropic search provider
|
|
218
219
|
|
package/src/cli/update-cli.ts
CHANGED
|
@@ -80,7 +80,7 @@ async function getLatestRelease(): Promise<ReleaseInfo> {
|
|
|
80
80
|
return {
|
|
81
81
|
tag,
|
|
82
82
|
version,
|
|
83
|
-
assets: [makeAsset(getBinaryName()),
|
|
83
|
+
assets: [makeAsset(getBinaryName()), ...getNativeAddonNames().map(makeAsset)],
|
|
84
84
|
};
|
|
85
85
|
}
|
|
86
86
|
|
|
@@ -143,13 +143,11 @@ function getBinaryName(): string {
|
|
|
143
143
|
}
|
|
144
144
|
|
|
145
145
|
/**
|
|
146
|
-
* Get
|
|
147
|
-
* Uses process.platform directly (linux, darwin, win32).
|
|
146
|
+
* Get native addon names for this platform, ordered by preference.
|
|
148
147
|
*/
|
|
149
|
-
function
|
|
148
|
+
function getNativeAddonNames(): string[] {
|
|
150
149
|
const platform = process.platform;
|
|
151
150
|
const arch = process.arch;
|
|
152
|
-
|
|
153
151
|
if (!["linux", "darwin", "win32"].includes(platform)) {
|
|
154
152
|
throw new Error(`Unsupported platform: ${platform}`);
|
|
155
153
|
}
|
|
@@ -157,7 +155,12 @@ function getNativeAddonName(): string {
|
|
|
157
155
|
throw new Error(`Unsupported architecture: ${arch}`);
|
|
158
156
|
}
|
|
159
157
|
|
|
160
|
-
|
|
158
|
+
const baseName = `pi_natives.${platform}-${arch}.node`;
|
|
159
|
+
if (arch !== "x64") {
|
|
160
|
+
return [baseName];
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
return [`pi_natives.${platform}-${arch}-modern.node`, `pi_natives.${platform}-${arch}-baseline.node`];
|
|
161
164
|
}
|
|
162
165
|
|
|
163
166
|
/**
|
|
@@ -197,50 +200,58 @@ async function updateViaBun(expectedVersion: string): Promise<void> {
|
|
|
197
200
|
*/
|
|
198
201
|
async function updateViaBinary(release: ReleaseInfo): Promise<void> {
|
|
199
202
|
const binaryName = getBinaryName();
|
|
200
|
-
const
|
|
201
|
-
|
|
203
|
+
const nativeAddonNames = getNativeAddonNames();
|
|
202
204
|
const asset = release.assets.find(a => a.name === binaryName);
|
|
203
|
-
const nativeAsset = release.assets.find(a => a.name === nativeAddonName);
|
|
204
|
-
|
|
205
205
|
if (!asset) {
|
|
206
206
|
throw new Error(`No binary found for ${binaryName}`);
|
|
207
207
|
}
|
|
208
|
-
if (!nativeAsset) {
|
|
209
|
-
throw new Error(`No native addon found for ${nativeAddonName}`);
|
|
210
|
-
}
|
|
211
|
-
|
|
212
208
|
const execPath = process.execPath;
|
|
213
209
|
const execDir = path.dirname(execPath);
|
|
214
210
|
const tempPath = `${execPath}.new`;
|
|
215
211
|
const backupPath = `${execPath}.bak`;
|
|
216
|
-
const
|
|
217
|
-
|
|
212
|
+
const nativeDownloads: Array<{ name: string; tempPath: string; finalPath: string }> = [];
|
|
213
|
+
|
|
214
|
+
const downloadNativeAsset = async (name: string, required: boolean): Promise<boolean> => {
|
|
215
|
+
const nativeAsset = release.assets.find(assetEntry => assetEntry.name === name);
|
|
216
|
+
if (!nativeAsset) {
|
|
217
|
+
if (required) throw new Error(`No native addon found for ${name}`);
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
console.log(chalk.dim(`Downloading ${name}…`));
|
|
222
|
+
try {
|
|
223
|
+
const nativeResponse = await fetch(nativeAsset.url, { redirect: "follow" });
|
|
224
|
+
if (!nativeResponse.ok || !nativeResponse.body) {
|
|
225
|
+
if (required) throw new Error(`Native addon download failed for ${name}: ${nativeResponse.statusText}`);
|
|
226
|
+
return false;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const nativeFinalPath = path.join(execDir, name);
|
|
230
|
+
const nativeTempPath = `${nativeFinalPath}.new`;
|
|
231
|
+
const nativeFileStream = fs.createWriteStream(nativeTempPath, { mode: 0o755 });
|
|
232
|
+
await pipeline(nativeResponse.body, nativeFileStream);
|
|
233
|
+
nativeDownloads.push({ name, tempPath: nativeTempPath, finalPath: nativeFinalPath });
|
|
234
|
+
return true;
|
|
235
|
+
} catch (err) {
|
|
236
|
+
if (required) throw err;
|
|
237
|
+
return false;
|
|
238
|
+
}
|
|
239
|
+
};
|
|
218
240
|
|
|
219
241
|
console.log(chalk.dim(`Downloading ${binaryName}…`));
|
|
220
242
|
|
|
221
|
-
// Download to temp file
|
|
243
|
+
// Download binary to temp file
|
|
222
244
|
const response = await fetch(asset.url, { redirect: "follow" });
|
|
223
245
|
if (!response.ok || !response.body) {
|
|
224
246
|
throw new Error(`Download failed: ${response.statusText}`);
|
|
225
247
|
}
|
|
226
|
-
|
|
227
248
|
const fileStream = fs.createWriteStream(tempPath, { mode: 0o755 });
|
|
228
249
|
await pipeline(response.body, fileStream);
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
console.log(chalk.dim(`Downloading ${nativeAddonName}…`));
|
|
232
|
-
|
|
233
|
-
const nativeResponse = await fetch(nativeAsset.url, { redirect: "follow" });
|
|
234
|
-
if (!nativeResponse.ok || !nativeResponse.body) {
|
|
235
|
-
throw new Error(`Native addon download failed: ${nativeResponse.statusText}`);
|
|
250
|
+
for (const nativeAddonName of nativeAddonNames) {
|
|
251
|
+
await downloadNativeAsset(nativeAddonName, true);
|
|
236
252
|
}
|
|
237
|
-
|
|
238
|
-
const nativeFileStream = fs.createWriteStream(nativeTempPath, { mode: 0o755 });
|
|
239
|
-
await pipeline(nativeResponse.body, nativeFileStream);
|
|
240
|
-
|
|
241
253
|
// Replace current binary
|
|
242
254
|
console.log(chalk.dim("Installing update..."));
|
|
243
|
-
|
|
244
255
|
try {
|
|
245
256
|
try {
|
|
246
257
|
await fs.promises.unlink(backupPath);
|
|
@@ -251,10 +262,11 @@ async function updateViaBinary(release: ReleaseInfo): Promise<void> {
|
|
|
251
262
|
await fs.promises.rename(tempPath, execPath);
|
|
252
263
|
await fs.promises.unlink(backupPath);
|
|
253
264
|
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
265
|
+
for (const nativeDownload of nativeDownloads) {
|
|
266
|
+
await fs.promises.rename(nativeDownload.tempPath, nativeDownload.finalPath);
|
|
267
|
+
}
|
|
257
268
|
console.log(chalk.green(`\n${theme.status.success} Updated to ${release.version}`));
|
|
269
|
+
console.log(chalk.dim(`Installed ${nativeDownloads.length} native addon file(s)`));
|
|
258
270
|
console.log(chalk.dim(`Restart ${APP_NAME} to use the new version`));
|
|
259
271
|
} catch (err) {
|
|
260
272
|
if (fs.existsSync(backupPath) && !fs.existsSync(execPath)) {
|
|
@@ -263,8 +275,10 @@ async function updateViaBinary(release: ReleaseInfo): Promise<void> {
|
|
|
263
275
|
if (fs.existsSync(tempPath)) {
|
|
264
276
|
await fs.promises.unlink(tempPath);
|
|
265
277
|
}
|
|
266
|
-
|
|
267
|
-
|
|
278
|
+
for (const nativeDownload of nativeDownloads) {
|
|
279
|
+
if (fs.existsSync(nativeDownload.tempPath)) {
|
|
280
|
+
await fs.promises.unlink(nativeDownload.tempPath);
|
|
281
|
+
}
|
|
268
282
|
}
|
|
269
283
|
throw err;
|
|
270
284
|
}
|
|
@@ -24,6 +24,7 @@ const PROVIDERS: Array<SearchProviderId | "auto"> = [
|
|
|
24
24
|
"anthropic",
|
|
25
25
|
"perplexity",
|
|
26
26
|
"exa",
|
|
27
|
+
"brave",
|
|
27
28
|
"jina",
|
|
28
29
|
"zai",
|
|
29
30
|
"gemini",
|
|
@@ -131,14 +132,14 @@ ${chalk.bold("Arguments:")}
|
|
|
131
132
|
|
|
132
133
|
${chalk.bold("Options:")}
|
|
133
134
|
--provider <name> Provider: ${PROVIDERS.join(", ")}
|
|
134
|
-
--recency <value> Recency filter (Perplexity
|
|
135
|
+
--recency <value> Recency filter (Brave/Perplexity): ${RECENCY_OPTIONS.join(", ")}
|
|
135
136
|
-l, --limit <n> Max results to return
|
|
136
137
|
--compact Render condensed output
|
|
137
138
|
-h, --help Show this help
|
|
138
139
|
|
|
139
140
|
${chalk.bold("Examples:")}
|
|
140
141
|
${APP_NAME} q --provider=exa "what's the color of the sky"
|
|
141
|
-
${APP_NAME} q --provider=
|
|
142
|
+
${APP_NAME} q --provider=brave --recency=week "latest TypeScript 5.7 changes"
|
|
142
143
|
`);
|
|
143
144
|
}
|
|
144
145
|
|
|
@@ -93,6 +93,7 @@ const ModelDefinitionSchema = Type.Object({
|
|
|
93
93
|
maxTokens: Type.Optional(Type.Number()),
|
|
94
94
|
headers: Type.Optional(Type.Record(Type.String(), Type.String())),
|
|
95
95
|
compat: Type.Optional(OpenAICompatSchema),
|
|
96
|
+
contextPromotionTarget: Type.Optional(Type.String({ minLength: 1 })),
|
|
96
97
|
});
|
|
97
98
|
|
|
98
99
|
// Schema for per-model overrides (all fields optional, merged with built-in model)
|
|
@@ -112,6 +113,7 @@ const ModelOverrideSchema = Type.Object({
|
|
|
112
113
|
maxTokens: Type.Optional(Type.Number()),
|
|
113
114
|
headers: Type.Optional(Type.Record(Type.String(), Type.String())),
|
|
114
115
|
compat: Type.Optional(OpenAICompatSchema),
|
|
116
|
+
contextPromotionTarget: Type.Optional(Type.String({ minLength: 1 })),
|
|
115
117
|
});
|
|
116
118
|
|
|
117
119
|
type ModelOverride = Static<typeof ModelOverrideSchema>;
|
|
@@ -274,6 +276,7 @@ function applyModelOverride(model: Model<Api>, override: ModelOverride): Model<A
|
|
|
274
276
|
if (override.input !== undefined) result.input = override.input as ("text" | "image")[];
|
|
275
277
|
if (override.contextWindow !== undefined) result.contextWindow = override.contextWindow;
|
|
276
278
|
if (override.maxTokens !== undefined) result.maxTokens = override.maxTokens;
|
|
279
|
+
if (override.contextPromotionTarget !== undefined) result.contextPromotionTarget = override.contextPromotionTarget;
|
|
277
280
|
if (override.cost) {
|
|
278
281
|
result.cost = {
|
|
279
282
|
input: override.cost.input ?? model.cost.input,
|
|
@@ -652,6 +655,7 @@ export class ModelRegistry {
|
|
|
652
655
|
maxTokens: modelDef.maxTokens ?? 16384,
|
|
653
656
|
headers,
|
|
654
657
|
compat: modelDef.compat,
|
|
658
|
+
contextPromotionTarget: modelDef.contextPromotionTarget,
|
|
655
659
|
} as Model<Api>);
|
|
656
660
|
}
|
|
657
661
|
}
|
|
@@ -816,6 +820,7 @@ export class ModelRegistry {
|
|
|
816
820
|
maxTokens: modelDef.maxTokens,
|
|
817
821
|
headers,
|
|
818
822
|
compat: modelDef.compat,
|
|
823
|
+
contextPromotionTarget: modelDef.contextPromotionTarget,
|
|
819
824
|
} as Model<Api>);
|
|
820
825
|
}
|
|
821
826
|
|
|
@@ -872,5 +877,6 @@ export interface ProviderConfigInput {
|
|
|
872
877
|
maxTokens: number;
|
|
873
878
|
headers?: Record<string, string>;
|
|
874
879
|
compat?: Model<Api>["compat"];
|
|
880
|
+
contextPromotionTarget?: string;
|
|
875
881
|
}>;
|
|
876
882
|
}
|
|
@@ -299,6 +299,24 @@ export const SETTINGS_SCHEMA = {
|
|
|
299
299
|
disabledProviders: { type: "array", default: [] as string[] },
|
|
300
300
|
disabledExtensions: { type: "array", default: [] as string[] },
|
|
301
301
|
modelRoles: { type: "record", default: {} as Record<string, string> },
|
|
302
|
+
"contextPromotion.enabled": {
|
|
303
|
+
type: "boolean",
|
|
304
|
+
default: true,
|
|
305
|
+
ui: {
|
|
306
|
+
tab: "agent",
|
|
307
|
+
label: "Auto-promote context",
|
|
308
|
+
description: "Promote to a larger-context model on context overflow instead of compacting",
|
|
309
|
+
},
|
|
310
|
+
},
|
|
311
|
+
|
|
312
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
313
|
+
// Secrets settings
|
|
314
|
+
// ─────────────────────────────────────────────────────────────────────────
|
|
315
|
+
"secrets.enabled": {
|
|
316
|
+
type: "boolean",
|
|
317
|
+
default: false,
|
|
318
|
+
ui: { tab: "config", label: "Hide secrets", description: "Obfuscate secrets before sending to AI providers" },
|
|
319
|
+
},
|
|
302
320
|
|
|
303
321
|
// ─────────────────────────────────────────────────────────────────────────
|
|
304
322
|
// Compaction settings
|
|
@@ -409,7 +427,7 @@ export const SETTINGS_SCHEMA = {
|
|
|
409
427
|
},
|
|
410
428
|
"grep.contextBefore": {
|
|
411
429
|
type: "number",
|
|
412
|
-
default:
|
|
430
|
+
default: 0,
|
|
413
431
|
ui: {
|
|
414
432
|
tab: "tools",
|
|
415
433
|
label: "Grep context before",
|
|
@@ -419,7 +437,7 @@ export const SETTINGS_SCHEMA = {
|
|
|
419
437
|
},
|
|
420
438
|
"grep.contextAfter": {
|
|
421
439
|
type: "number",
|
|
422
|
-
default:
|
|
440
|
+
default: 0,
|
|
423
441
|
ui: {
|
|
424
442
|
tab: "tools",
|
|
425
443
|
label: "Grep context after",
|
|
@@ -617,7 +635,7 @@ export const SETTINGS_SCHEMA = {
|
|
|
617
635
|
// ─────────────────────────────────────────────────────────────────────────
|
|
618
636
|
"providers.webSearch": {
|
|
619
637
|
type: "enum",
|
|
620
|
-
values: ["auto", "exa", "jina", "zai", "perplexity", "anthropic"] as const,
|
|
638
|
+
values: ["auto", "exa", "brave", "jina", "zai", "perplexity", "anthropic"] as const,
|
|
621
639
|
default: "auto",
|
|
622
640
|
ui: { tab: "services", label: "Web search provider", description: "Provider for web search tool", submenu: true },
|
|
623
641
|
},
|
|
@@ -1027,6 +1045,9 @@ export interface CompactionSettings {
|
|
|
1027
1045
|
remoteEndpoint: string | undefined;
|
|
1028
1046
|
}
|
|
1029
1047
|
|
|
1048
|
+
export interface ContextPromotionSettings {
|
|
1049
|
+
enabled: boolean;
|
|
1050
|
+
}
|
|
1030
1051
|
export interface RetrySettings {
|
|
1031
1052
|
enabled: boolean;
|
|
1032
1053
|
maxRetries: number;
|
|
@@ -1134,6 +1155,7 @@ export interface BashInterceptorRule {
|
|
|
1134
1155
|
/** Map group prefix -> typed settings interface */
|
|
1135
1156
|
export interface GroupTypeMap {
|
|
1136
1157
|
compaction: CompactionSettings;
|
|
1158
|
+
contextPromotion: ContextPromotionSettings;
|
|
1137
1159
|
retry: RetrySettings;
|
|
1138
1160
|
memories: MemoriesSettings;
|
|
1139
1161
|
branchSummary: BranchSummarySettings;
|
package/src/config/settings.ts
CHANGED
|
@@ -18,11 +18,31 @@ export class RegisteredToolAdapter implements AgentTool<any, any, any> {
|
|
|
18
18
|
declare parameters: any;
|
|
19
19
|
declare label: string;
|
|
20
20
|
|
|
21
|
+
renderCall?: (args: any, theme: any) => any;
|
|
22
|
+
renderResult?: (result: any, options: any, theme: any, args?: any) => any;
|
|
23
|
+
|
|
21
24
|
constructor(
|
|
22
25
|
private registeredTool: RegisteredTool,
|
|
23
26
|
private runner: ExtensionRunner,
|
|
24
27
|
) {
|
|
25
28
|
applyToolProxy(registeredTool.definition, this);
|
|
29
|
+
|
|
30
|
+
// Only define render methods when the underlying definition provides them.
|
|
31
|
+
// If these exist unconditionally on the prototype, ToolExecutionComponent
|
|
32
|
+
// enters the custom-renderer path, gets undefined back, and silently
|
|
33
|
+
// discards tool result text (extensions without renderers show blank).
|
|
34
|
+
if (registeredTool.definition.renderCall) {
|
|
35
|
+
this.renderCall = (args: any, theme: any) => registeredTool.definition.renderCall!(args, theme as Theme);
|
|
36
|
+
}
|
|
37
|
+
if (registeredTool.definition.renderResult) {
|
|
38
|
+
this.renderResult = (result: any, options: any, theme: any, args?: any) =>
|
|
39
|
+
registeredTool.definition.renderResult!(
|
|
40
|
+
result,
|
|
41
|
+
{ expanded: options.expanded, isPartial: options.isPartial, spinnerFrame: options.spinnerFrame },
|
|
42
|
+
theme as Theme,
|
|
43
|
+
args,
|
|
44
|
+
);
|
|
45
|
+
}
|
|
26
46
|
}
|
|
27
47
|
|
|
28
48
|
async execute(
|
|
@@ -34,19 +54,6 @@ export class RegisteredToolAdapter implements AgentTool<any, any, any> {
|
|
|
34
54
|
) {
|
|
35
55
|
return this.registeredTool.definition.execute(toolCallId, params, signal, onUpdate, this.runner.createContext());
|
|
36
56
|
}
|
|
37
|
-
|
|
38
|
-
renderCall?(args: any, theme: any) {
|
|
39
|
-
return this.registeredTool.definition.renderCall?.(args, theme as Theme);
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
renderResult?(result: any, options: any, theme: any, args?: any) {
|
|
43
|
-
return this.registeredTool.definition.renderResult?.(
|
|
44
|
-
result,
|
|
45
|
-
{ expanded: options.expanded, isPartial: options.isPartial, spinnerFrame: options.spinnerFrame },
|
|
46
|
-
theme as Theme,
|
|
47
|
-
args,
|
|
48
|
-
);
|
|
49
|
-
}
|
|
50
57
|
}
|
|
51
58
|
|
|
52
59
|
/**
|
|
@@ -1,4 +1,15 @@
|
|
|
1
1
|
import type { AutocompleteItem } from "@oh-my-pi/pi-tui";
|
|
2
|
+
import { slashCommandCapability } from "../capability/slash-command";
|
|
3
|
+
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
4
|
+
import type { SlashCommand } from "../discovery";
|
|
5
|
+
import { loadCapability } from "../discovery";
|
|
6
|
+
import {
|
|
7
|
+
BUILTIN_SLASH_COMMAND_DEFS,
|
|
8
|
+
type BuiltinSlashCommand,
|
|
9
|
+
type SubcommandDef,
|
|
10
|
+
} from "../slash-commands/builtin-registry";
|
|
11
|
+
import { EMBEDDED_COMMAND_TEMPLATES } from "../task/commands";
|
|
12
|
+
import { parseFrontmatter } from "../utils/frontmatter";
|
|
2
13
|
|
|
3
14
|
export type SlashCommandSource = "extension" | "prompt" | "skill";
|
|
4
15
|
|
|
@@ -12,22 +23,7 @@ export interface SlashCommandInfo {
|
|
|
12
23
|
path?: string;
|
|
13
24
|
}
|
|
14
25
|
|
|
15
|
-
|
|
16
|
-
export interface SubcommandDef {
|
|
17
|
-
name: string;
|
|
18
|
-
description: string;
|
|
19
|
-
/** Usage hint shown as dim ghost text, e.g. "<name> [--scope project|user]" */
|
|
20
|
-
usage?: string;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export interface BuiltinSlashCommand {
|
|
24
|
-
name: string;
|
|
25
|
-
description: string;
|
|
26
|
-
/** Subcommands for dropdown completion (e.g. /mcp add, /mcp list) */
|
|
27
|
-
subcommands?: SubcommandDef[];
|
|
28
|
-
/** Static inline hint when command takes a simple argument (no subcommands) */
|
|
29
|
-
inlineHint?: string;
|
|
30
|
-
}
|
|
26
|
+
export type { BuiltinSlashCommand, SubcommandDef } from "../slash-commands/builtin-registry";
|
|
31
27
|
|
|
32
28
|
/**
|
|
33
29
|
* Build getArgumentCompletions from declarative subcommand definitions.
|
|
@@ -93,74 +89,6 @@ function buildStaticInlineHint(hint: string): (argumentText: string) => string |
|
|
|
93
89
|
return (argumentText: string) => (argumentText.trim().length === 0 ? hint : null);
|
|
94
90
|
}
|
|
95
91
|
|
|
96
|
-
const BUILTIN_SLASH_COMMAND_DEFS: ReadonlyArray<BuiltinSlashCommand> = [
|
|
97
|
-
{ name: "settings", description: "Open settings menu" },
|
|
98
|
-
{ name: "plan", description: "Toggle plan mode (agent plans before executing)" },
|
|
99
|
-
{ name: "model", description: "Select model (opens selector UI)" },
|
|
100
|
-
{ name: "export", description: "Export session to HTML file", inlineHint: "[path]" },
|
|
101
|
-
{ name: "dump", description: "Copy session transcript to clipboard" },
|
|
102
|
-
{ name: "share", description: "Share session as a secret GitHub gist" },
|
|
103
|
-
{
|
|
104
|
-
name: "browser",
|
|
105
|
-
description: "Toggle browser headless vs visible mode",
|
|
106
|
-
subcommands: [
|
|
107
|
-
{ name: "headless", description: "Switch to headless mode" },
|
|
108
|
-
{ name: "visible", description: "Switch to visible mode" },
|
|
109
|
-
],
|
|
110
|
-
},
|
|
111
|
-
{ name: "copy", description: "Copy last agent message to clipboard" },
|
|
112
|
-
{ name: "session", description: "Show session info and stats" },
|
|
113
|
-
{ name: "usage", description: "Show provider usage and limits" },
|
|
114
|
-
{ name: "changelog", description: "Show changelog entries" },
|
|
115
|
-
{ name: "hotkeys", description: "Show all keyboard shortcuts" },
|
|
116
|
-
{ name: "extensions", description: "Open Extension Control Center dashboard" },
|
|
117
|
-
{ name: "branch", description: "Create a new branch from a previous message" },
|
|
118
|
-
{ name: "fork", description: "Create a new fork from a previous message" },
|
|
119
|
-
{ name: "tree", description: "Navigate session tree (switch branches)" },
|
|
120
|
-
{ name: "login", description: "Login with OAuth provider" },
|
|
121
|
-
{ name: "logout", description: "Logout from OAuth provider" },
|
|
122
|
-
{
|
|
123
|
-
name: "mcp",
|
|
124
|
-
description: "Manage MCP servers (add, list, remove, test)",
|
|
125
|
-
subcommands: [
|
|
126
|
-
{
|
|
127
|
-
name: "add",
|
|
128
|
-
description: "Add a new MCP server",
|
|
129
|
-
usage: "<name> [--scope project|user] [--url <url>] [-- <command...>]",
|
|
130
|
-
},
|
|
131
|
-
{ name: "list", description: "List all configured MCP servers" },
|
|
132
|
-
{ name: "remove", description: "Remove an MCP server", usage: "<name> [--scope project|user]" },
|
|
133
|
-
{ name: "test", description: "Test connection to a server", usage: "<name>" },
|
|
134
|
-
{ name: "reauth", description: "Reauthorize OAuth for a server", usage: "<name>" },
|
|
135
|
-
{ name: "unauth", description: "Remove OAuth auth from a server", usage: "<name>" },
|
|
136
|
-
{ name: "enable", description: "Enable an MCP server", usage: "<name>" },
|
|
137
|
-
{ name: "disable", description: "Disable an MCP server", usage: "<name>" },
|
|
138
|
-
{ name: "reload", description: "Force reload MCP runtime tools" },
|
|
139
|
-
{ name: "help", description: "Show help message" },
|
|
140
|
-
],
|
|
141
|
-
},
|
|
142
|
-
{ name: "new", description: "Start a new session" },
|
|
143
|
-
{ name: "compact", description: "Manually compact the session context", inlineHint: "[focus instructions]" },
|
|
144
|
-
{ name: "handoff", description: "Hand off session context to a new session", inlineHint: "[focus instructions]" },
|
|
145
|
-
{ name: "resume", description: "Resume a different session" },
|
|
146
|
-
{ name: "background", description: "Detach UI and continue running in background" },
|
|
147
|
-
{ name: "debug", description: "Write debug log (TUI state and messages)" },
|
|
148
|
-
{
|
|
149
|
-
name: "memory",
|
|
150
|
-
description: "Inspect and operate memory maintenance",
|
|
151
|
-
subcommands: [
|
|
152
|
-
{ name: "view", description: "Show current memory injection payload" },
|
|
153
|
-
{ name: "clear", description: "Clear persisted memory data and artifacts" },
|
|
154
|
-
{ name: "reset", description: "Alias for clear" },
|
|
155
|
-
{ name: "enqueue", description: "Enqueue memory consolidation maintenance" },
|
|
156
|
-
{ name: "rebuild", description: "Alias for enqueue" },
|
|
157
|
-
],
|
|
158
|
-
},
|
|
159
|
-
{ name: "move", description: "Move session to a different working directory", inlineHint: "<path>" },
|
|
160
|
-
{ name: "exit", description: "Exit the application" },
|
|
161
|
-
{ name: "quit", description: "Quit the application" },
|
|
162
|
-
];
|
|
163
|
-
|
|
164
92
|
/**
|
|
165
93
|
* Materialized builtin slash commands with completion functions derived from
|
|
166
94
|
* declarative subcommand/hint definitions.
|
|
@@ -187,13 +115,6 @@ export const BUILTIN_SLASH_COMMANDS: ReadonlyArray<
|
|
|
187
115
|
return cmd;
|
|
188
116
|
});
|
|
189
117
|
|
|
190
|
-
import { slashCommandCapability } from "../capability/slash-command";
|
|
191
|
-
import { renderPromptTemplate } from "../config/prompt-templates";
|
|
192
|
-
import type { SlashCommand } from "../discovery";
|
|
193
|
-
import { loadCapability } from "../discovery";
|
|
194
|
-
import { EMBEDDED_COMMAND_TEMPLATES } from "../task/commands";
|
|
195
|
-
import { parseFrontmatter } from "../utils/frontmatter";
|
|
196
|
-
|
|
197
118
|
/**
|
|
198
119
|
* Represents a custom slash command loaded from a file
|
|
199
120
|
*/
|