@oh-my-pi/pi-coding-agent 17.1.3 → 17.1.4
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 +54 -0
- package/dist/cli.js +3759 -3751
- package/dist/types/cli/__tests__/auth-gateway-catalog.test.d.ts +1 -0
- package/dist/types/cli/auth-gateway-cli.d.ts +8 -0
- package/dist/types/cli/update-cli.d.ts +41 -0
- package/dist/types/cli/usage-cli.d.ts +4 -2
- package/dist/types/commands/update.d.ts +1 -0
- package/dist/types/config/model-registry.d.ts +19 -0
- package/dist/types/config/settings-schema.d.ts +30 -7
- package/dist/types/cursor.d.ts +47 -1
- package/dist/types/eval/js/process-entry.d.ts +2 -1
- package/dist/types/eval/js/worker-core.d.ts +4 -1
- package/dist/types/extensibility/extensions/runner.d.ts +1 -0
- package/dist/types/extensibility/legacy-pi-ai-shim.d.ts +4 -0
- package/dist/types/extensibility/legacy-pi-coding-agent-shim.d.ts +4 -0
- package/dist/types/extensibility/legacy-pi-tui-shim.d.ts +15 -7
- package/dist/types/extensibility/shared-events.d.ts +2 -0
- package/dist/types/modes/components/assistant-message.d.ts +9 -0
- package/dist/types/modes/components/custom-editor.d.ts +12 -8
- package/dist/types/plan-mode/approved-plan.d.ts +3 -2
- package/dist/types/secrets/obfuscator.d.ts +7 -31
- package/dist/types/session/agent-session.d.ts +19 -4
- package/dist/types/session/prewalk.d.ts +2 -1
- package/dist/types/session/session-advisors.d.ts +8 -0
- package/dist/types/session/session-metadata.d.ts +29 -0
- package/dist/types/session/turn-recovery.d.ts +5 -5
- package/dist/types/stt/sherpa-runtime.d.ts +38 -0
- package/dist/types/thinking.d.ts +24 -0
- package/dist/types/tools/bash.d.ts +5 -4
- package/dist/types/tools/computer/exposure.d.ts +8 -0
- package/dist/types/tools/computer/supervisor.d.ts +1 -1
- package/dist/types/tools/computer/worker-entry.d.ts +1 -1
- package/dist/types/tools/computer/worker.d.ts +1 -1
- package/dist/types/tools/computer.d.ts +6 -0
- package/dist/types/tools/shell-tokenize.d.ts +14 -0
- package/dist/types/tools/todo.d.ts +7 -1
- package/package.json +12 -12
- package/src/advisor/__tests__/advisor.test.ts +80 -10
- package/src/advisor/runtime.ts +27 -1
- package/src/cli/__tests__/auth-gateway-catalog.test.ts +111 -0
- package/src/cli/auth-gateway-cli.ts +63 -16
- package/src/cli/config-cli.ts +25 -7
- package/src/cli/update-cli.ts +229 -29
- package/src/cli/usage-cli.ts +144 -15
- package/src/cli.ts +21 -15
- package/src/commands/update.ts +6 -0
- package/src/config/__tests__/model-registry.test.ts +42 -7
- package/src/config/model-registry.ts +67 -4
- package/src/config/settings-schema.ts +39 -8
- package/src/config/settings.ts +24 -2
- package/src/cursor.ts +153 -0
- package/src/dap/session.ts +70 -11
- package/src/eval/__tests__/js-context-manager.test.ts +9 -1
- package/src/eval/__tests__/process-entry-import.test.ts +111 -1
- package/src/eval/js/process-entry.ts +9 -5
- package/src/eval/js/worker-core.ts +6 -2
- package/src/exec/bash-executor.ts +4 -2
- package/src/extensibility/extensions/runner.ts +23 -8
- package/src/extensibility/legacy-pi-ai-shim.ts +9 -0
- package/src/extensibility/legacy-pi-coding-agent-shim.ts +14 -2
- package/src/extensibility/legacy-pi-tui-shim.ts +33 -0
- package/src/extensibility/shared-events.ts +2 -0
- package/src/main.ts +22 -1
- package/src/modes/acp/acp-agent.ts +6 -0
- package/src/modes/components/assistant-message.ts +88 -11
- package/src/modes/components/chat-transcript-builder.ts +2 -0
- package/src/modes/components/custom-editor.test.ts +170 -0
- package/src/modes/components/custom-editor.ts +79 -29
- package/src/modes/components/settings-defs.ts +5 -1
- package/src/modes/controllers/event-controller.ts +96 -4
- package/src/modes/controllers/selector-controller.ts +14 -0
- package/src/modes/interactive-mode.ts +34 -8
- package/src/modes/utils/context-usage.ts +19 -2
- package/src/modes/utils/interactive-context-helpers.ts +1 -0
- package/src/plan-mode/approved-plan.ts +18 -10
- package/src/prompts/system/custom-system-prompt.md +1 -1
- package/src/prompts/system/system-prompt.md +10 -1
- package/src/sdk.ts +4 -0
- package/src/secrets/obfuscator.ts +36 -126
- package/src/session/agent-session.ts +69 -60
- package/src/session/prewalk.ts +8 -3
- package/src/session/session-advisors.ts +67 -3
- package/src/session/session-metadata.ts +53 -0
- package/src/session/session-provider-boundary.ts +0 -1
- package/src/session/session-tools.ts +35 -1
- package/src/session/turn-recovery.ts +36 -19
- package/src/slash-commands/builtin-registry.ts +49 -7
- package/src/stt/asr-worker.ts +2 -37
- package/src/stt/sherpa-runtime.ts +71 -0
- package/src/task/executor.ts +6 -5
- package/src/thinking.ts +39 -0
- package/src/tools/bash.ts +43 -15
- package/src/tools/computer/exposure.ts +38 -0
- package/src/tools/computer/supervisor.ts +61 -13
- package/src/tools/computer/worker-entry.ts +28 -19
- package/src/tools/computer/worker.ts +3 -7
- package/src/tools/computer.ts +65 -10
- package/src/tools/gh-cache-invalidation.ts +2 -82
- package/src/tools/shell-tokenize.ts +83 -0
- package/src/tools/todo.ts +44 -17
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Conservative shell command tokenizer shared by the bash approval-pattern
|
|
3
|
+
* matcher and the gh-cache invalidator.
|
|
4
|
+
*
|
|
5
|
+
* Splits a bash command into independent command segments, each a list of word
|
|
6
|
+
* tokens. Handles single/double-quoted strings, backslash escapes, and the
|
|
7
|
+
* standard operators (`;`, `&&`, `||`, `|`, `&`, `(`, `)`, newlines) as segment
|
|
8
|
+
* boundaries so callers treat the pieces as independent command sequences.
|
|
9
|
+
*
|
|
10
|
+
* It is deliberately not a full POSIX parser — heredocs, command substitution,
|
|
11
|
+
* and arithmetic expansion are out of scope; callers fall through when they
|
|
12
|
+
* cannot find the structure they need.
|
|
13
|
+
*/
|
|
14
|
+
export function tokenizeShellSegments(command: string): string[][] {
|
|
15
|
+
const segments: string[][] = [];
|
|
16
|
+
let current: string[] = [];
|
|
17
|
+
let buffer = "";
|
|
18
|
+
let inSingle = false;
|
|
19
|
+
let inDouble = false;
|
|
20
|
+
const pushBuffer = () => {
|
|
21
|
+
if (buffer.length > 0) {
|
|
22
|
+
current.push(buffer);
|
|
23
|
+
buffer = "";
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const pushSegment = () => {
|
|
27
|
+
pushBuffer();
|
|
28
|
+
if (current.length > 0) segments.push(current);
|
|
29
|
+
current = [];
|
|
30
|
+
};
|
|
31
|
+
for (let i = 0; i < command.length; i++) {
|
|
32
|
+
const ch = command[i];
|
|
33
|
+
if (inSingle) {
|
|
34
|
+
if (ch === "'") {
|
|
35
|
+
inSingle = false;
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
buffer += ch;
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (inDouble) {
|
|
42
|
+
if (ch === "\\" && i + 1 < command.length) {
|
|
43
|
+
const next = command[i + 1];
|
|
44
|
+
if (next === '"' || next === "\\" || next === "$" || next === "`") {
|
|
45
|
+
buffer += next;
|
|
46
|
+
i++;
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
if (ch === '"') {
|
|
51
|
+
inDouble = false;
|
|
52
|
+
continue;
|
|
53
|
+
}
|
|
54
|
+
buffer += ch;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (ch === "'") {
|
|
58
|
+
inSingle = true;
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
if (ch === '"') {
|
|
62
|
+
inDouble = true;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (ch === "\\" && i + 1 < command.length) {
|
|
66
|
+
buffer += command[i + 1];
|
|
67
|
+
i++;
|
|
68
|
+
continue;
|
|
69
|
+
}
|
|
70
|
+
if (ch === " " || ch === "\t") {
|
|
71
|
+
pushBuffer();
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
if (ch === "\n" || ch === ";" || ch === "&" || ch === "|" || ch === "(" || ch === ")") {
|
|
75
|
+
pushSegment();
|
|
76
|
+
// `&&`, `||` already collapsed by the segment break above.
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
buffer += ch;
|
|
80
|
+
}
|
|
81
|
+
pushSegment();
|
|
82
|
+
return segments;
|
|
83
|
+
}
|
package/src/tools/todo.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { AgentTool, AgentToolContext, AgentToolResult, AgentToolUpdateCallb
|
|
|
2
2
|
import type { ToolExample } from "@oh-my-pi/pi-ai";
|
|
3
3
|
import type { Component } from "@oh-my-pi/pi-tui";
|
|
4
4
|
import { Text } from "@oh-my-pi/pi-tui";
|
|
5
|
-
import { isRecord, prompt } from "@oh-my-pi/pi-utils";
|
|
5
|
+
import { isRecord, prompt, sanitizeText } from "@oh-my-pi/pi-utils";
|
|
6
6
|
import { type } from "arktype";
|
|
7
7
|
import chalk from "chalk";
|
|
8
8
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
@@ -12,7 +12,7 @@ import type { ToolSession } from "../sdk";
|
|
|
12
12
|
import type { SessionEntry } from "../session/session-entries";
|
|
13
13
|
import { framedBlock, renderStatusLine, renderTreeList } from "../tui";
|
|
14
14
|
import { normalizePathLikeInput, resolveToCwd } from "./path-utils";
|
|
15
|
-
import { formatErrorDetail, formatMoreItems, PREVIEW_LIMITS, pluralize } from "./render-utils";
|
|
15
|
+
import { formatErrorDetail, formatMoreItems, PREVIEW_LIMITS, pluralize, replaceTabs } from "./render-utils";
|
|
16
16
|
|
|
17
17
|
// =============================================================================
|
|
18
18
|
// Types
|
|
@@ -929,9 +929,27 @@ export function phaseRomanNumeral(oneBasedIndex: number): string {
|
|
|
929
929
|
return out;
|
|
930
930
|
}
|
|
931
931
|
|
|
932
|
-
/**
|
|
932
|
+
/**
|
|
933
|
+
* Every render boundary in this file funnels display text through here.
|
|
934
|
+
*
|
|
935
|
+
* `sanitizeText` strips ANSI/C0 sequences but deliberately preserves tabs, and
|
|
936
|
+
* a raw tab punches holes in bordered TUI output, so both are needed. The raw
|
|
937
|
+
* value stays untouched everywhere else: task content and phase names are the
|
|
938
|
+
* identity keys the local list is looked up by, and what gets persisted.
|
|
939
|
+
*/
|
|
940
|
+
function forDisplay(text: string): string {
|
|
941
|
+
return replaceTabs(sanitizeText(text));
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
/**
|
|
945
|
+
* Display-only phase header: `I. Foundation`. State and prompts never see this.
|
|
946
|
+
*
|
|
947
|
+
* Sanitized for the same reason task labels are: this is a render boundary and
|
|
948
|
+
* the name may carry provider or session text holding control sequences. The
|
|
949
|
+
* raw `phase.name` stays the lookup key everywhere else.
|
|
950
|
+
*/
|
|
933
951
|
export function formatPhaseDisplayName(name: string, oneBasedIndex: number): string {
|
|
934
|
-
return `${phaseRomanNumeral(oneBasedIndex)}. ${name}`;
|
|
952
|
+
return `${phaseRomanNumeral(oneBasedIndex)}. ${forDisplay(name)}`;
|
|
935
953
|
}
|
|
936
954
|
|
|
937
955
|
export const TODO_STRIKE_HOLD_FRAMES = 2;
|
|
@@ -970,27 +988,31 @@ function formatTodoLine(
|
|
|
970
988
|
matched = false,
|
|
971
989
|
): string {
|
|
972
990
|
const checkbox = uiTheme.checkbox;
|
|
991
|
+
// Sanitize only for display. A mirrored Cursor snapshot carries provider text
|
|
992
|
+
// verbatim, and a label holding ANSI/C0 sequences would otherwise rewrite the
|
|
993
|
+
// terminal every time the list renders or replays. `item.content` stays raw
|
|
994
|
+
// everywhere else: it is the identity key the local list is looked up by
|
|
995
|
+
// (`findTaskByContent`) and what gets persisted.
|
|
996
|
+
const label = forDisplay(item.content);
|
|
973
997
|
switch (item.status) {
|
|
974
998
|
case "completed": {
|
|
975
|
-
const revealCount = completionKeys.has(item.content) ? strikeRevealCount(
|
|
999
|
+
const revealCount = completionKeys.has(item.content) ? strikeRevealCount(label, frame) : undefined;
|
|
976
1000
|
const content =
|
|
977
|
-
revealCount === undefined
|
|
978
|
-
? strikethroughText(item.content)
|
|
979
|
-
: partialStrikethrough(item.content, revealCount);
|
|
1001
|
+
revealCount === undefined ? strikethroughText(label) : partialStrikethrough(label, revealCount);
|
|
980
1002
|
return uiTheme.fg("success", `${prefix}${checkbox.checked} ${content}`);
|
|
981
1003
|
}
|
|
982
1004
|
case "in_progress":
|
|
983
|
-
return uiTheme.fg("accent", `${prefix}${checkbox.unchecked} ${
|
|
1005
|
+
return uiTheme.fg("accent", `${prefix}${checkbox.unchecked} ${label}`);
|
|
984
1006
|
case "abandoned":
|
|
985
|
-
return uiTheme.fg("error", `${prefix}${checkbox.unchecked} ${strikethroughText(
|
|
1007
|
+
return uiTheme.fg("error", `${prefix}${checkbox.unchecked} ${strikethroughText(label)}`);
|
|
986
1008
|
case "blocked": {
|
|
987
|
-
const note = item.blocker ? `blocked: ${item.blocker}` : "blocked";
|
|
988
|
-
return uiTheme.fg("warning", `${prefix}${checkbox.unchecked} ${
|
|
1009
|
+
const note = item.blocker ? `blocked: ${forDisplay(item.blocker)}` : "blocked";
|
|
1010
|
+
return uiTheme.fg("warning", `${prefix}${checkbox.unchecked} ${label} (${note})`);
|
|
989
1011
|
}
|
|
990
1012
|
default:
|
|
991
1013
|
// A pending todo lit by a live subagent match renders accent, matching
|
|
992
1014
|
// the sticky HUD's convention (#5873).
|
|
993
|
-
return uiTheme.fg(matched ? "accent" : "dim", `${prefix}${checkbox.unchecked} ${
|
|
1015
|
+
return uiTheme.fg(matched ? "accent" : "dim", `${prefix}${checkbox.unchecked} ${label}`);
|
|
994
1016
|
}
|
|
995
1017
|
}
|
|
996
1018
|
|
|
@@ -1065,13 +1087,15 @@ export const todoToolRenderer = {
|
|
|
1065
1087
|
// both the new single-op and legacy batch shapes so a malformed delta
|
|
1066
1088
|
// never breaks the TUI render loop (#2005).
|
|
1067
1089
|
const opsList = normalizeTodoArg(args);
|
|
1090
|
+
// Model-authored, partially-streamed strings going straight into a header:
|
|
1091
|
+
// `renderStatusLine` only flattens CR/LF and leaves the rest to the caller.
|
|
1068
1092
|
const ops =
|
|
1069
1093
|
opsList.length === 0
|
|
1070
1094
|
? ["update"]
|
|
1071
1095
|
: opsList.map(e => {
|
|
1072
|
-
const parts = [e.op ?? "update"];
|
|
1073
|
-
if (e.task) parts.push(e.task);
|
|
1074
|
-
if (e.phase) parts.push(e.phase);
|
|
1096
|
+
const parts = [forDisplay(e.op ?? "update")];
|
|
1097
|
+
if (e.task) parts.push(forDisplay(e.task));
|
|
1098
|
+
if (e.phase) parts.push(forDisplay(e.phase));
|
|
1075
1099
|
if (Array.isArray(e.items) && e.items.length) {
|
|
1076
1100
|
parts.push(`${e.items.length} item${e.items.length === 1 ? "" : "s"}`);
|
|
1077
1101
|
}
|
|
@@ -1125,7 +1149,10 @@ export const todoToolRenderer = {
|
|
|
1125
1149
|
uiTheme,
|
|
1126
1150
|
);
|
|
1127
1151
|
if (allTasks.length === 0) {
|
|
1128
|
-
|
|
1152
|
+
// Provider text on the Cursor path (the todo summary or a refusal note),
|
|
1153
|
+
// so sanitize like every other label. The error branch above already
|
|
1154
|
+
// goes through `formatErrorDetail`.
|
|
1155
|
+
const fallback = forDisplay(result.content?.find(content => content.type === "text")?.text ?? "No todos");
|
|
1129
1156
|
return new Text(`${header}\n ${uiTheme.fg("dim", fallback)}`, 0, 0);
|
|
1130
1157
|
}
|
|
1131
1158
|
|