@oh-my-pi/pi-coding-agent 15.10.8 → 15.10.10
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 +41 -1
- package/dist/types/config/model-registry.d.ts +13 -0
- package/dist/types/config/settings-schema.d.ts +0 -9
- package/dist/types/debug/terminal-info.d.ts +0 -1
- package/dist/types/extensibility/custom-tools/loader.d.ts +22 -3
- package/dist/types/extensibility/extensions/index.d.ts +1 -1
- package/dist/types/extensibility/extensions/loader.d.ts +17 -1
- package/dist/types/extensibility/plugins/legacy-pi-compat.d.ts +8 -0
- package/dist/types/mcp/transports/stdio.d.ts +12 -0
- package/dist/types/modes/components/custom-editor.d.ts +3 -2
- package/dist/types/modes/components/transcript-container.d.ts +12 -26
- package/dist/types/sdk.d.ts +42 -2
- package/dist/types/task/discovery.d.ts +1 -2
- package/dist/types/task/executor.d.ts +16 -0
- package/dist/types/tiny/title-client.d.ts +1 -1
- package/dist/types/tools/index.d.ts +17 -0
- package/dist/types/tools/todo.d.ts +2 -0
- package/dist/types/tui/hyperlink.d.ts +8 -0
- package/package.json +9 -9
- package/src/cli/list-models.ts +5 -11
- package/src/config/model-registry.ts +91 -20
- package/src/config/settings-schema.ts +0 -10
- package/src/debug/terminal-info.ts +0 -3
- package/src/edit/diff.ts +48 -15
- package/src/eval/js/shared/rewrite-imports.ts +9 -1
- package/src/extensibility/custom-tools/loader.ts +43 -19
- package/src/extensibility/extensions/index.ts +1 -0
- package/src/extensibility/extensions/loader.ts +29 -6
- package/src/extensibility/plugins/legacy-pi-compat.ts +30 -6
- package/src/internal-urls/docs-index.generated.ts +4 -4
- package/src/mcp/transports/stdio.ts +139 -3
- package/src/modes/components/custom-editor.ts +69 -9
- package/src/modes/components/model-selector.ts +62 -52
- package/src/modes/components/transcript-container.ts +204 -125
- package/src/modes/controllers/event-controller.ts +0 -45
- package/src/modes/controllers/input-controller.ts +5 -5
- package/src/modes/controllers/mcp-command-controller.ts +2 -2
- package/src/modes/controllers/selector-controller.ts +0 -4
- package/src/modes/interactive-mode.ts +2 -10
- package/src/prompts/system/system-prompt.md +3 -3
- package/src/prompts/tools/bash.md +3 -3
- package/src/prompts/tools/todo.md +5 -1
- package/src/sdk.ts +138 -56
- package/src/ssh/ssh-executor.ts +60 -4
- package/src/task/discovery.ts +17 -24
- package/src/task/executor.ts +19 -0
- package/src/task/index.ts +4 -0
- package/src/tiny/title-client.ts +6 -3
- package/src/tools/index.ts +17 -0
- package/src/tools/todo.ts +16 -7
- package/src/tui/hyperlink.ts +27 -3
- package/src/web/search/providers/anthropic.ts +8 -2
package/src/tools/index.ts
CHANGED
|
@@ -3,10 +3,12 @@ import type { AgentTelemetryConfig, AgentTool } from "@oh-my-pi/pi-agent-core";
|
|
|
3
3
|
import type { FetchImpl, ToolChoice } from "@oh-my-pi/pi-ai";
|
|
4
4
|
import { logger } from "@oh-my-pi/pi-utils";
|
|
5
5
|
import type { AsyncJobManager } from "../async/job-manager";
|
|
6
|
+
import type { Rule } from "../capability/rule";
|
|
6
7
|
import type { PromptTemplate } from "../config/prompt-templates";
|
|
7
8
|
import type { Settings } from "../config/settings";
|
|
8
9
|
import { EditTool } from "../edit";
|
|
9
10
|
import { checkPythonKernelAvailability } from "../eval/py/kernel";
|
|
11
|
+
import type { ToolPathWithSource } from "../extensibility/custom-tools";
|
|
10
12
|
import type { Skill } from "../extensibility/skills";
|
|
11
13
|
import type { GoalModeState, GoalRuntime } from "../goals";
|
|
12
14
|
import { GoalTool } from "../goals/tools/goal-tool";
|
|
@@ -154,6 +156,21 @@ export interface ToolSession {
|
|
|
154
156
|
skills?: Skill[];
|
|
155
157
|
/** Pre-loaded prompt templates */
|
|
156
158
|
promptTemplates?: PromptTemplate[];
|
|
159
|
+
/** Pre-loaded rules (forwarded to subagents to skip re-discovery). */
|
|
160
|
+
rules?: Rule[];
|
|
161
|
+
/**
|
|
162
|
+
* Pre-discovered extension source paths. Forwarded to subagents so they
|
|
163
|
+
* skip the FS scan but still re-bind extensions to their own session-scoped
|
|
164
|
+
* `ExtensionAPI` (cwd, eventBus, runtime). Inline extension factories
|
|
165
|
+
* (`<inline-N>`) are NOT included — those are session-local.
|
|
166
|
+
*/
|
|
167
|
+
extensionPaths?: string[];
|
|
168
|
+
/**
|
|
169
|
+
* Pre-discovered custom-tool source paths from `.omp/tools/`, `.claude/tools/`,
|
|
170
|
+
* plugins, etc. Forwarded to subagents so they skip the FS scan but still
|
|
171
|
+
* re-bind tools to their own session-scoped `CustomToolAPI`.
|
|
172
|
+
*/
|
|
173
|
+
customToolPaths?: ToolPathWithSource[];
|
|
157
174
|
/** Whether LSP integrations are enabled */
|
|
158
175
|
enableLsp?: boolean;
|
|
159
176
|
/** Whether an edit-capable tool is available in this session (controls hashline output) */
|
package/src/tools/todo.ts
CHANGED
|
@@ -51,7 +51,7 @@ export interface TodoToolDetails {
|
|
|
51
51
|
// =============================================================================
|
|
52
52
|
|
|
53
53
|
const TodoOp = z
|
|
54
|
-
.enum(["init", "start", "done", "rm", "drop", "append", "note"] as const)
|
|
54
|
+
.enum(["init", "start", "done", "rm", "drop", "append", "note", "view"] as const)
|
|
55
55
|
.describe("operation to apply");
|
|
56
56
|
|
|
57
57
|
const InitListEntry = z.object({
|
|
@@ -380,6 +380,8 @@ function applyEntry(phases: TodoPhase[], entry: TodoOpEntryValue, errors: string
|
|
|
380
380
|
}
|
|
381
381
|
case "append":
|
|
382
382
|
return appendItems(phases, entry, errors);
|
|
383
|
+
case "view":
|
|
384
|
+
return phases;
|
|
383
385
|
}
|
|
384
386
|
}
|
|
385
387
|
|
|
@@ -523,9 +525,12 @@ export function markdownToPhases(md: string): { phases: TodoPhase[]; errors: str
|
|
|
523
525
|
return { phases, errors };
|
|
524
526
|
}
|
|
525
527
|
|
|
526
|
-
function formatSummary(phases: TodoPhase[], errors: string[]): string {
|
|
528
|
+
function formatSummary(phases: TodoPhase[], errors: string[], readOnly = false): string {
|
|
527
529
|
const tasks = phases.flatMap(phase => phase.tasks);
|
|
528
|
-
if (tasks.length === 0)
|
|
530
|
+
if (tasks.length === 0) {
|
|
531
|
+
if (errors.length > 0) return `Errors: ${errors.join("; ")}`;
|
|
532
|
+
return readOnly ? "Todo list is empty." : "Todo list cleared.";
|
|
533
|
+
}
|
|
529
534
|
|
|
530
535
|
const remainingByPhase = phases
|
|
531
536
|
.map(phase => ({
|
|
@@ -608,15 +613,19 @@ export class TodoTool implements AgentTool<typeof todoSchema, TodoToolDetails> {
|
|
|
608
613
|
_context?: AgentToolContext,
|
|
609
614
|
): Promise<AgentToolResult<TodoToolDetails>> {
|
|
610
615
|
const previousPhases = clonePhases(this.session.getTodoPhases?.() ?? []);
|
|
611
|
-
|
|
612
|
-
const
|
|
613
|
-
|
|
616
|
+
// Pure-view calls are reads: no normalization, no state write.
|
|
617
|
+
const readOnly = params.ops.every(entry => entry.op === "view");
|
|
618
|
+
const { phases: updated, errors } = readOnly
|
|
619
|
+
? { phases: previousPhases, errors: [] as string[] }
|
|
620
|
+
: applyParams(clonePhases(previousPhases), params);
|
|
621
|
+
const completedTasks = readOnly ? [] : getCompletionTransitions(previousPhases, updated);
|
|
622
|
+
if (!readOnly) this.session.setTodoPhases?.(updated);
|
|
614
623
|
const storage = this.session.getSessionFile() ? "session" : "memory";
|
|
615
624
|
const details: TodoToolDetails = { phases: updated, storage };
|
|
616
625
|
if (completedTasks.length > 0) details.completedTasks = completedTasks;
|
|
617
626
|
|
|
618
627
|
return {
|
|
619
|
-
content: [{ type: "text", text: formatSummary(updated, errors) }],
|
|
628
|
+
content: [{ type: "text", text: formatSummary(updated, errors, readOnly) }],
|
|
620
629
|
details,
|
|
621
630
|
isError: errors.length > 0 ? true : undefined,
|
|
622
631
|
};
|
package/src/tui/hyperlink.ts
CHANGED
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
|
|
19
19
|
const OSC = "\x1b]";
|
|
20
20
|
const ST = "\x1b\\";
|
|
21
|
+
const BEL = "\x07";
|
|
21
22
|
|
|
22
23
|
/** Stable 8-char hex ID derived from a URI — hints terminals to coalesce identical adjacent links. */
|
|
23
24
|
function buildLinkId(uri: string): string {
|
|
@@ -60,14 +61,18 @@ function safeHyperlinkUri(uri: string): string | undefined {
|
|
|
60
61
|
return uri;
|
|
61
62
|
}
|
|
62
63
|
|
|
63
|
-
function
|
|
64
|
-
if (!isHyperlinkEnabled()) return displayText;
|
|
64
|
+
function wrapHyperlinkCore(uri: string, displayText: string, terminator: typeof ST | typeof BEL): string {
|
|
65
65
|
// Do not double-wrap if the text already embeds an OSC 8 sequence.
|
|
66
66
|
if (displayText.includes("\x1b]8;")) return displayText;
|
|
67
67
|
const safeUri = safeHyperlinkUri(uri);
|
|
68
68
|
if (!safeUri) return displayText;
|
|
69
69
|
const id = buildLinkId(safeUri);
|
|
70
|
-
return `${OSC}8;id=${id};${safeUri}${
|
|
70
|
+
return `${OSC}8;id=${id};${safeUri}${terminator}${displayText}${OSC}8;;${terminator}`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function wrapHyperlink(uri: string, displayText: string): string {
|
|
74
|
+
if (!isHyperlinkEnabled()) return displayText;
|
|
75
|
+
return wrapHyperlinkCore(uri, displayText, ST);
|
|
71
76
|
}
|
|
72
77
|
|
|
73
78
|
/**
|
|
@@ -95,6 +100,25 @@ export function urlHyperlink(url: string, displayText: string): string {
|
|
|
95
100
|
}
|
|
96
101
|
}
|
|
97
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Wrap `displayText` in an OSC 8 hyperlink pointing at an HTTP(S) URL,
|
|
105
|
+
* bypassing terminal capability auto-detection. Used for auth prompts where
|
|
106
|
+
* an inert "click" label blocks login on terminals whose capabilities are
|
|
107
|
+
* not advertised. Still returns plain text when the user has explicitly
|
|
108
|
+
* opted out via `tui.hyperlinks=off`.
|
|
109
|
+
*/
|
|
110
|
+
export function urlHyperlinkAlways(url: string, displayText: string): string {
|
|
111
|
+
if (settings.get("tui.hyperlinks") === "off") return displayText;
|
|
112
|
+
const normalized = url.match(/^www\./i) ? `https://${url}` : url;
|
|
113
|
+
try {
|
|
114
|
+
const parsed = new URL(normalized);
|
|
115
|
+
if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return displayText;
|
|
116
|
+
return wrapHyperlinkCore(parsed.href, displayText, BEL);
|
|
117
|
+
} catch {
|
|
118
|
+
return displayText;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
98
122
|
/**
|
|
99
123
|
* Wrap `displayText` in an OSC 8 hyperlink pointing at a filesystem path.
|
|
100
124
|
*
|
|
@@ -16,6 +16,7 @@ import {
|
|
|
16
16
|
type FetchImpl,
|
|
17
17
|
stripClaudeToolPrefix,
|
|
18
18
|
withAuth,
|
|
19
|
+
wrapFetchForCch,
|
|
19
20
|
} from "@oh-my-pi/pi-ai";
|
|
20
21
|
import { $env } from "@oh-my-pi/pi-utils";
|
|
21
22
|
import type {
|
|
@@ -64,7 +65,9 @@ function buildSystemBlocks(
|
|
|
64
65
|
model: string,
|
|
65
66
|
systemPrompt?: string,
|
|
66
67
|
): AnthropicSystemBlock[] | undefined {
|
|
67
|
-
|
|
68
|
+
// Match the streaming path: the CC billing header + system instruction are
|
|
69
|
+
// an OAuth fingerprint and must not be claimed on API-key requests.
|
|
70
|
+
const includeClaudeCode = auth.isOAuth && !model.startsWith("claude-3-5-haiku");
|
|
68
71
|
const extraInstructions = auth.isOAuth ? ["You are a helpful AI assistant with web search capabilities."] : [];
|
|
69
72
|
|
|
70
73
|
return buildAnthropicSystemBlocks(systemPrompt ? [systemPrompt] : undefined, {
|
|
@@ -118,7 +121,10 @@ async function callSearch(
|
|
|
118
121
|
body.system = systemBlocks;
|
|
119
122
|
}
|
|
120
123
|
|
|
121
|
-
|
|
124
|
+
// OAuth requests inject the CC billing header (buildSystemBlocks); patch its
|
|
125
|
+
// cch attestation like the streaming path instead of shipping `cch=00000`.
|
|
126
|
+
const doFetch = auth.isOAuth ? wrapFetchForCch(fetchImpl) : fetchImpl;
|
|
127
|
+
const response = await doFetch(url, {
|
|
122
128
|
method: "POST",
|
|
123
129
|
headers,
|
|
124
130
|
body: JSON.stringify(body),
|