@dyyz1993/pi-coding-agent 0.74.24 → 0.74.27
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 +9 -0
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +3 -0
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/session-manager.d.ts +5 -0
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +8 -0
- package/dist/core/session-manager.js.map +1 -1
- package/dist/extensions/agent-permissions/index.ts +235 -0
- package/dist/extensions/ask-tools/index.ts +115 -0
- package/dist/extensions/auto-memory/contract.d.ts +51 -0
- package/dist/extensions/auto-memory/contract.d.ts.map +1 -0
- package/dist/extensions/auto-memory/contract.js +2 -0
- package/dist/extensions/auto-memory/contract.js.map +1 -0
- package/dist/extensions/auto-memory/contract.ts +56 -0
- package/dist/extensions/auto-memory/index.ts +969 -0
- package/dist/extensions/auto-memory/prompts.ts +202 -0
- package/dist/extensions/auto-memory/skip-rules.ts +297 -0
- package/dist/extensions/auto-memory/utils.ts +208 -0
- package/dist/extensions/auto-session-title/index.ts +83 -0
- package/dist/extensions/bash-ext/contract.d.ts +79 -0
- package/dist/extensions/bash-ext/contract.d.ts.map +1 -0
- package/dist/extensions/bash-ext/contract.js +2 -0
- package/dist/extensions/bash-ext/contract.js.map +1 -0
- package/dist/extensions/bash-ext/contract.ts +69 -0
- package/dist/extensions/bash-ext/index.ts +858 -0
- package/dist/extensions/claude-hooks-compat/config-loader.ts +49 -0
- package/dist/extensions/claude-hooks-compat/handler-runner.ts +377 -0
- package/dist/extensions/claude-hooks-compat/if-parser.ts +53 -0
- package/dist/extensions/claude-hooks-compat/index.ts +178 -0
- package/dist/extensions/claude-hooks-compat/matcher.ts +17 -0
- package/dist/extensions/claude-hooks-compat/stdin-builder.ts +27 -0
- package/dist/extensions/claude-hooks-compat/types.ts +77 -0
- package/dist/extensions/compaction-manager/config.ts +47 -0
- package/dist/extensions/compaction-manager/context-fold.ts +63 -0
- package/dist/extensions/compaction-manager/index.ts +151 -0
- package/dist/extensions/compaction-manager/microcompact.ts +49 -0
- package/dist/extensions/compaction-manager/reactive.ts +9 -0
- package/dist/extensions/compaction-manager/session-memory.ts +48 -0
- package/dist/extensions/coordinator/INTEGRATION.md +376 -0
- package/dist/extensions/coordinator/handler.test.ts +277 -0
- package/dist/extensions/coordinator/handler.ts +189 -0
- package/dist/extensions/coordinator/index.ts +261 -0
- package/dist/extensions/coordinator/types.d.ts +100 -0
- package/dist/extensions/coordinator/types.d.ts.map +1 -0
- package/dist/extensions/coordinator/types.js +2 -0
- package/dist/extensions/coordinator/types.js.map +1 -0
- package/dist/extensions/coordinator/types.ts +72 -0
- package/dist/extensions/file-snapshot/index.ts +131 -0
- package/dist/extensions/file-time-guard/README.md +133 -0
- package/dist/extensions/file-time-guard/config.ts +13 -0
- package/dist/extensions/file-time-guard/index.ts +171 -0
- package/dist/extensions/hooks-engine/index.ts +117 -0
- package/dist/extensions/lsp/lsp/client/file-tracker.ts +70 -0
- package/dist/extensions/lsp/lsp/client/registry.ts +305 -0
- package/dist/extensions/lsp/lsp/client/runtime.ts +832 -0
- package/dist/extensions/lsp/lsp/config/resolver.ts +573 -0
- package/dist/extensions/lsp/lsp/contract.d.ts +101 -0
- package/dist/extensions/lsp/lsp/contract.d.ts.map +1 -0
- package/dist/extensions/lsp/lsp/contract.js +2 -0
- package/dist/extensions/lsp/lsp/contract.js.map +1 -0
- package/dist/extensions/lsp/lsp/contract.ts +103 -0
- package/dist/extensions/lsp/lsp/hooks/agent-end.ts +169 -0
- package/dist/extensions/lsp/lsp/hooks/diagnostics-mode.d.ts +10 -0
- package/dist/extensions/lsp/lsp/hooks/diagnostics-mode.d.ts.map +1 -0
- package/dist/extensions/lsp/lsp/hooks/diagnostics-mode.js +30 -0
- package/dist/extensions/lsp/lsp/hooks/diagnostics-mode.js.map +1 -0
- package/dist/extensions/lsp/lsp/hooks/diagnostics-mode.ts +41 -0
- package/dist/extensions/lsp/lsp/hooks/writethrough.ts +342 -0
- package/dist/extensions/lsp/lsp/index.ts +310 -0
- package/dist/extensions/lsp/lsp/lsp.test.ts +684 -0
- package/dist/extensions/lsp/lsp/monitoring/server-metrics.ts +176 -0
- package/dist/extensions/lsp/lsp/tools/lsp-tool.ts +402 -0
- package/dist/extensions/lsp/lsp/utils/dependency-resolver.ts +147 -0
- package/dist/extensions/lsp/lsp/utils/diagnostics-wait.ts +41 -0
- package/dist/extensions/lsp/lsp/utils/lsp-helpers.d.ts +20 -0
- package/dist/extensions/lsp/lsp/utils/lsp-helpers.d.ts.map +1 -0
- package/dist/extensions/lsp/lsp/utils/lsp-helpers.js +64 -0
- package/dist/extensions/lsp/lsp/utils/lsp-helpers.js.map +1 -0
- package/dist/extensions/lsp/lsp/utils/lsp-helpers.ts +76 -0
- package/dist/extensions/message-bridge/GUIDE.md +210 -0
- package/dist/extensions/message-bridge/index.ts +222 -0
- package/dist/extensions/output-guard/index.ts +446 -0
- package/dist/extensions/preview/index.ts +278 -0
- package/dist/extensions/rules-engine/MATCH_HISTORY_RECONCILIATION.md +111 -0
- package/dist/extensions/rules-engine/RULES-ENGINE-GUIDE.md +470 -0
- package/dist/extensions/rules-engine/cache.js +232 -0
- package/dist/extensions/rules-engine/cache.ts +38 -0
- package/dist/extensions/rules-engine/config.js +63 -0
- package/dist/extensions/rules-engine/config.ts +70 -0
- package/dist/extensions/rules-engine/index.js +1530 -0
- package/dist/extensions/rules-engine/index.ts +552 -0
- package/dist/extensions/rules-engine/injector.js +68 -0
- package/dist/extensions/rules-engine/injector.ts +74 -0
- package/dist/extensions/rules-engine/loader.js +179 -0
- package/dist/extensions/rules-engine/loader.ts +205 -0
- package/dist/extensions/rules-engine/matcher.js +534 -0
- package/dist/extensions/rules-engine/matcher.ts +52 -0
- package/dist/extensions/rules-engine/types.d.ts +156 -0
- package/dist/extensions/rules-engine/types.d.ts.map +1 -0
- package/dist/extensions/rules-engine/types.js +2 -0
- package/dist/extensions/rules-engine/types.js.map +1 -0
- package/dist/extensions/rules-engine/types.ts +169 -0
- package/dist/extensions/session-supervisor/checker.ts +116 -0
- package/dist/extensions/session-supervisor/config.ts +45 -0
- package/dist/extensions/session-supervisor/index.ts +726 -0
- package/dist/extensions/session-supervisor/prompts.ts +132 -0
- package/dist/extensions/session-supervisor/scheduler.ts +69 -0
- package/dist/extensions/session-supervisor/types.ts +215 -0
- package/dist/extensions/subagent/README.md +172 -0
- package/dist/extensions/subagent/agents/explorer.md +25 -0
- package/dist/extensions/subagent/agents/guide.md +27 -0
- package/dist/extensions/subagent/agents/planner.md +37 -0
- package/dist/extensions/subagent/agents/reviewer.md +35 -0
- package/dist/extensions/subagent/agents/scout.md +50 -0
- package/dist/extensions/subagent/agents/verification.md +35 -0
- package/dist/extensions/subagent/agents/worker.md +24 -0
- package/dist/extensions/subagent/agents.ts +25 -0
- package/dist/extensions/subagent/index.ts +987 -0
- package/dist/extensions/subagent/prompts/implement-and-review.md +10 -0
- package/dist/extensions/subagent/prompts/implement.md +10 -0
- package/dist/extensions/subagent/prompts/scout-and-plan.md +9 -0
- package/dist/extensions/subagent-ext/contract.d.ts +2 -0
- package/dist/extensions/subagent-ext/contract.d.ts.map +1 -0
- package/dist/extensions/subagent-ext/contract.js +2 -0
- package/dist/extensions/subagent-ext/contract.js.map +1 -0
- package/dist/extensions/subagent-ext/contract.ts +1 -0
- package/dist/extensions/subagent-ext/index.ts +347 -0
- package/dist/extensions/subagent-shared/contract.d.ts +25 -0
- package/dist/extensions/subagent-shared/contract.d.ts.map +1 -0
- package/dist/extensions/subagent-shared/contract.js +2 -0
- package/dist/extensions/subagent-shared/contract.js.map +1 -0
- package/dist/extensions/subagent-shared/contract.ts +28 -0
- package/dist/extensions/subagent-shared/index.ts +4 -0
- package/dist/extensions/subagent-shared/render.ts +166 -0
- package/dist/extensions/subagent-shared/types.ts +35 -0
- package/dist/extensions/subagent-shared/utils.ts +112 -0
- package/dist/extensions/subagent-v2/contract.d.ts +2 -0
- package/dist/extensions/subagent-v2/contract.d.ts.map +1 -0
- package/dist/extensions/subagent-v2/contract.js +2 -0
- package/dist/extensions/subagent-v2/contract.js.map +1 -0
- package/dist/extensions/subagent-v2/contract.ts +1 -0
- package/dist/extensions/subagent-v2/index.ts +599 -0
- package/dist/extensions/todo-ext/contract.d.ts +27 -0
- package/dist/extensions/todo-ext/contract.d.ts.map +1 -0
- package/dist/extensions/todo-ext/contract.js +2 -0
- package/dist/extensions/todo-ext/contract.js.map +1 -0
- package/dist/extensions/todo-ext/contract.ts +30 -0
- package/dist/extensions/todo-ext/index.ts +419 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/package.json +6 -5
|
@@ -0,0 +1,419 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Todo Extension - LLM-managed todo list with channel exposure and UI rendering.
|
|
3
|
+
*
|
|
4
|
+
* - Registers a `todo` tool for the LLM (list, add, toggle, remove, clear)
|
|
5
|
+
* - Registers a `todo` channel for real-time event streaming
|
|
6
|
+
* - Persists snapshots via appendEntry for history retrieval
|
|
7
|
+
* - Renders tool calls/results with styled UI (✓/○/✗)
|
|
8
|
+
* - Shows live todo widget in the editor panel
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { AgentToolResult } from "@dyyz1993/pi-agent-core";
|
|
12
|
+
import { StringEnum } from "@dyyz1993/pi-ai";
|
|
13
|
+
import { Text } from "@dyyz1993/pi-tui";
|
|
14
|
+
import { Type } from "typebox";
|
|
15
|
+
import { createTypedChannel } from "@dyyz1993/pi-coding-agent";
|
|
16
|
+
import type { ExtensionAPI, ExtensionContext, ServerChannel } from "@dyyz1993/pi-coding-agent";
|
|
17
|
+
import { TODO_CHANNEL_NAME, type TodoChannelContract, type TodoItem, type TodoChannelEvent } from "./contract.js";
|
|
18
|
+
|
|
19
|
+
export type Todo = TodoItem;
|
|
20
|
+
|
|
21
|
+
export interface TodoDetails {
|
|
22
|
+
action: string;
|
|
23
|
+
todos: Todo[];
|
|
24
|
+
nextId: number;
|
|
25
|
+
error?: string;
|
|
26
|
+
added?: Todo[];
|
|
27
|
+
modified?: Todo[];
|
|
28
|
+
deleted?: Todo[];
|
|
29
|
+
totalActive?: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const PRIORITY_LABELS: Record<string, string> = {
|
|
33
|
+
high: "!",
|
|
34
|
+
medium: "",
|
|
35
|
+
low: "?",
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
const PRIORITY_ORDER: Record<string, number> = {
|
|
39
|
+
high: 0,
|
|
40
|
+
medium: 1,
|
|
41
|
+
low: 2,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
const TodoParams = Type.Object({
|
|
45
|
+
action: StringEnum(["list", "add", "toggle", "remove", "clear"] as const),
|
|
46
|
+
text: Type.Optional(Type.String({ description: "Todo text (for add)" })),
|
|
47
|
+
id: Type.Optional(Type.Number({ description: "Todo ID (for toggle / remove)" })),
|
|
48
|
+
priority: Type.Optional(StringEnum(["high", "medium", "low"] as const)),
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
function persistEntry(pi: ExtensionAPI, action: string, todos: Todo[], nextId: number): void {
|
|
52
|
+
pi.appendEntry("todo", { action, todos: [...todos], nextId, timestamp: Date.now() });
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function updateWidget(ctx: ExtensionContext | undefined, todos: Todo[]): void {
|
|
56
|
+
if (!ctx?.hasUI) return;
|
|
57
|
+
const active = todos.filter((t) => !t.deleted);
|
|
58
|
+
if (active.length === 0) {
|
|
59
|
+
ctx.ui.setWidget("todo-todos", undefined);
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const sorted = [...active].sort((a, b) => {
|
|
63
|
+
const pa = PRIORITY_ORDER[a.priority ?? "medium"] ?? 1;
|
|
64
|
+
const pb = PRIORITY_ORDER[b.priority ?? "medium"] ?? 1;
|
|
65
|
+
return pa - pb || a.id - b.id;
|
|
66
|
+
});
|
|
67
|
+
const lines = sorted.map((t) => {
|
|
68
|
+
const check = t.done ? ctx.ui.theme.fg("success", "☑ ") : ctx.ui.theme.fg("muted", "☐ ");
|
|
69
|
+
const priLabel = t.priority
|
|
70
|
+
? ctx.ui.theme.fg(
|
|
71
|
+
t.priority === "high" ? "error" : t.priority === "low" ? "dim" : "dim",
|
|
72
|
+
PRIORITY_LABELS[t.priority] ?? "",
|
|
73
|
+
)
|
|
74
|
+
: "";
|
|
75
|
+
const text = t.done ? ctx.ui.theme.fg("dim", ctx.ui.theme.strikethrough(t.text)) : t.text;
|
|
76
|
+
return `${check}${priLabel} ${text}`;
|
|
77
|
+
});
|
|
78
|
+
ctx.ui.setWidget("todo-todos", lines);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export default function (pi: ExtensionAPI) {
|
|
82
|
+
let todos: Todo[] = [];
|
|
83
|
+
let nextId = 1;
|
|
84
|
+
let channel: ServerChannel<TodoChannelContract> | null = null;
|
|
85
|
+
|
|
86
|
+
pi.on("session_start", async (_event, ctx) => {
|
|
87
|
+
const rawChannel = pi.registerChannel(TODO_CHANNEL_NAME);
|
|
88
|
+
const typed = createTypedChannel<TodoChannelContract>(rawChannel);
|
|
89
|
+
channel = typed.server;
|
|
90
|
+
|
|
91
|
+
todos = [];
|
|
92
|
+
nextId = 1;
|
|
93
|
+
|
|
94
|
+
for (const entry of ctx.sessionManager.getBranch()) {
|
|
95
|
+
if (entry.type === "custom" && entry.customType === "todo") {
|
|
96
|
+
const data = entry.data as { action: string; todos: Todo[]; nextId: number } | undefined;
|
|
97
|
+
if (data?.todos) {
|
|
98
|
+
todos = data.todos;
|
|
99
|
+
nextId = data.nextId;
|
|
100
|
+
}
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
if (entry.type !== "message") continue;
|
|
104
|
+
const msg = entry.message;
|
|
105
|
+
if (msg.role !== "toolResult" || msg.toolName !== "todo") continue;
|
|
106
|
+
|
|
107
|
+
const details = msg.details as TodoDetails | undefined;
|
|
108
|
+
if (details) {
|
|
109
|
+
todos = details.todos;
|
|
110
|
+
nextId = details.nextId;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
updateWidget(ctx, todos);
|
|
114
|
+
|
|
115
|
+
channel?.emit("restored", { action: "restored", todos, timestamp: Date.now() } satisfies TodoChannelEvent);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
pi.on("session_tree", async (_event, ctx) => {
|
|
119
|
+
todos = [];
|
|
120
|
+
nextId = 1;
|
|
121
|
+
|
|
122
|
+
for (const entry of ctx.sessionManager.getBranch()) {
|
|
123
|
+
if (entry.type === "custom" && entry.customType === "todo") {
|
|
124
|
+
const data = entry.data as { action: string; todos: Todo[]; nextId: number } | undefined;
|
|
125
|
+
if (data?.todos) {
|
|
126
|
+
todos = data.todos;
|
|
127
|
+
nextId = data.nextId;
|
|
128
|
+
}
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
if (entry.type !== "message") continue;
|
|
132
|
+
const msg = entry.message;
|
|
133
|
+
if (msg.role !== "toolResult" || msg.toolName !== "todo") continue;
|
|
134
|
+
|
|
135
|
+
const details = msg.details as TodoDetails | undefined;
|
|
136
|
+
if (details) {
|
|
137
|
+
todos = details.todos;
|
|
138
|
+
nextId = details.nextId;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
updateWidget(ctx, todos);
|
|
142
|
+
channel?.emit("restored", { action: "restored", todos, timestamp: Date.now() } satisfies TodoChannelEvent);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
pi.registerTool({
|
|
146
|
+
name: "todo",
|
|
147
|
+
label: "Todo",
|
|
148
|
+
description: `Manage a todo list for task tracking and planning.
|
|
149
|
+
- add: Create one or more todos. Separate multiple items with newlines in the text field for batch creation. Optional priority: high/medium/low.
|
|
150
|
+
- list: Show all active todos with their IDs, status, and priority.
|
|
151
|
+
- toggle: Mark a todo as done/undone by ID.
|
|
152
|
+
- remove: Delete a todo by ID.
|
|
153
|
+
- clear: Remove all todos.
|
|
154
|
+
|
|
155
|
+
IMPORTANT: For creating a plan with multiple steps, use a SINGLE add call with newline-separated text. Example: text="Step 1\\nStep 2\\nStep 3" creates 3 todos at once. Do NOT call add repeatedly for multiple items.`,
|
|
156
|
+
parameters: TodoParams,
|
|
157
|
+
|
|
158
|
+
async execute(_toolCallId, params, _signal, _onUpdate, ctx): Promise<AgentToolResult<TodoDetails>> {
|
|
159
|
+
const activeTodos = (): Todo[] => todos.filter((t) => !t.deleted);
|
|
160
|
+
|
|
161
|
+
switch (params.action) {
|
|
162
|
+
case "list": {
|
|
163
|
+
const active = activeTodos();
|
|
164
|
+
channel?.emit("list", { action: "list", todos, timestamp: Date.now() } satisfies TodoChannelEvent);
|
|
165
|
+
persistEntry(pi, "list", todos, nextId);
|
|
166
|
+
updateWidget(ctx, todos);
|
|
167
|
+
|
|
168
|
+
return {
|
|
169
|
+
content: [{ type: "text", text: active.length === 0 ? "No todos." : `${active.length} todos.` }],
|
|
170
|
+
details: {
|
|
171
|
+
action: "list",
|
|
172
|
+
todos: [...todos],
|
|
173
|
+
nextId,
|
|
174
|
+
totalActive: active.length,
|
|
175
|
+
},
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
case "add": {
|
|
180
|
+
if (!params.text) {
|
|
181
|
+
channel?.emit("error", { action: "error", todos, timestamp: Date.now() } satisfies TodoChannelEvent);
|
|
182
|
+
persistEntry(pi, "add_error", todos, nextId);
|
|
183
|
+
return {
|
|
184
|
+
content: [{ type: "text", text: "Error: text required for add" }],
|
|
185
|
+
details: { action: "add", todos: [...todos], nextId, error: "text required" },
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
const lines = params.text
|
|
189
|
+
.split("\n")
|
|
190
|
+
.map((l) => l.trim())
|
|
191
|
+
.filter(Boolean);
|
|
192
|
+
const added: Todo[] = [];
|
|
193
|
+
for (const line of lines) {
|
|
194
|
+
const newTodo: Todo = { id: nextId++, text: line, done: false, priority: params.priority };
|
|
195
|
+
todos.push(newTodo);
|
|
196
|
+
added.push(newTodo);
|
|
197
|
+
}
|
|
198
|
+
channel?.emit("add", { action: "add", todos, timestamp: Date.now() } satisfies TodoChannelEvent);
|
|
199
|
+
persistEntry(pi, "add", todos, nextId);
|
|
200
|
+
updateWidget(ctx, todos);
|
|
201
|
+
|
|
202
|
+
const summary = added.length === 1
|
|
203
|
+
? `Created 1 todo: "${added[0].text}"`
|
|
204
|
+
: `Created ${added.length} todos.`;
|
|
205
|
+
|
|
206
|
+
return {
|
|
207
|
+
content: [{ type: "text", text: `✅ ${summary}` }],
|
|
208
|
+
details: { action: added.length === 1 ? "add" : "add_batch", todos: [...todos], nextId, added: [...added] },
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
case "toggle": {
|
|
213
|
+
if (params.id === undefined) {
|
|
214
|
+
return {
|
|
215
|
+
content: [{ type: "text", text: "Error: id required for toggle" }],
|
|
216
|
+
details: { action: "toggle", todos: [...todos], nextId, error: "id required" },
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
const todo = todos.find((t) => t.id === params.id);
|
|
220
|
+
if (!todo) {
|
|
221
|
+
channel?.emit("error", { action: "error", todos, timestamp: Date.now() } satisfies TodoChannelEvent);
|
|
222
|
+
persistEntry(pi, "toggle_notfound", todos, nextId);
|
|
223
|
+
return {
|
|
224
|
+
content: [{ type: "text", text: `Error: Todo #${params.id} not found.` }],
|
|
225
|
+
details: {
|
|
226
|
+
action: "toggle",
|
|
227
|
+
todos: [...todos],
|
|
228
|
+
nextId,
|
|
229
|
+
error: `#${params.id} not found`,
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
todo.done = !todo.done;
|
|
234
|
+
channel?.emit("toggle", { action: "toggle", todos, timestamp: Date.now() } satisfies TodoChannelEvent);
|
|
235
|
+
persistEntry(pi, "toggle", todos, nextId);
|
|
236
|
+
updateWidget(ctx, todos);
|
|
237
|
+
return {
|
|
238
|
+
content: [{ type: "text", text: `✅ Toggled #${todo.id} "${todo.text}" to ${todo.done ? "done" : "undone"}.` }],
|
|
239
|
+
details: { action: "toggle", todos: [...todos], nextId, modified: [todo] },
|
|
240
|
+
};
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
case "remove": {
|
|
244
|
+
if (params.id === undefined) {
|
|
245
|
+
return {
|
|
246
|
+
content: [{ type: "text", text: "Error: id required for remove" }],
|
|
247
|
+
details: { action: "remove", todos: [...todos], nextId, error: "id required" },
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
const todo = todos.find((t) => t.id === params.id);
|
|
251
|
+
if (!todo) {
|
|
252
|
+
channel?.emit("error", { action: "error", todos, timestamp: Date.now() } satisfies TodoChannelEvent);
|
|
253
|
+
persistEntry(pi, "remove_notfound", todos, nextId);
|
|
254
|
+
return {
|
|
255
|
+
content: [{ type: "text", text: `Error: Todo #${params.id} not found.` }],
|
|
256
|
+
details: {
|
|
257
|
+
action: "remove",
|
|
258
|
+
todos: [...todos],
|
|
259
|
+
nextId,
|
|
260
|
+
error: `#${params.id} not found`,
|
|
261
|
+
},
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
todo.deleted = true;
|
|
265
|
+
channel?.emit("remove", { action: "remove", todos, timestamp: Date.now() } satisfies TodoChannelEvent);
|
|
266
|
+
persistEntry(pi, "remove", todos, nextId);
|
|
267
|
+
updateWidget(ctx, todos);
|
|
268
|
+
return {
|
|
269
|
+
content: [{ type: "text", text: `✅ Removed #${todo.id}: "${todo.text}".` }],
|
|
270
|
+
details: { action: "remove", todos: [...todos], nextId, deleted: [todo] },
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
case "clear": {
|
|
275
|
+
const count = todos.length;
|
|
276
|
+
todos = [];
|
|
277
|
+
nextId = 1;
|
|
278
|
+
channel?.emit("clear", { action: "clear", todos: [], timestamp: Date.now() } satisfies TodoChannelEvent);
|
|
279
|
+
persistEntry(pi, "clear", [], 1);
|
|
280
|
+
updateWidget(ctx, todos);
|
|
281
|
+
|
|
282
|
+
return {
|
|
283
|
+
content: [{ type: "text", text: `✅ Cleared ${count} todos.` }],
|
|
284
|
+
details: { action: "clear", todos: [], nextId: 1 },
|
|
285
|
+
};
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
default: {
|
|
289
|
+
channel?.emit("error", { action: "error", todos, timestamp: Date.now() } satisfies TodoChannelEvent);
|
|
290
|
+
return {
|
|
291
|
+
content: [{ type: "text", text: `Error: Unknown action "${params.action}".` }],
|
|
292
|
+
details: {
|
|
293
|
+
action: "list",
|
|
294
|
+
todos: [...todos],
|
|
295
|
+
nextId,
|
|
296
|
+
error: `unknown action: ${params.action}`,
|
|
297
|
+
},
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
},
|
|
302
|
+
|
|
303
|
+
renderCall(args, theme) {
|
|
304
|
+
let text = theme.fg("toolTitle", theme.bold("todo ")) + theme.fg("muted", args.action);
|
|
305
|
+
if (args.text) text += ` ${theme.fg("dim", `"${args.text}"`)}`;
|
|
306
|
+
if (args.id !== undefined) text += ` ${theme.fg("accent", `#${args.id}`)}`;
|
|
307
|
+
if (args.priority) text += ` ${theme.fg(args.priority === "high" ? "error" : "dim", `[${args.priority}]`)}`;
|
|
308
|
+
return new Text(text, 0, 0);
|
|
309
|
+
},
|
|
310
|
+
|
|
311
|
+
renderResult(result, { expanded }, theme) {
|
|
312
|
+
const details = result.details as TodoDetails | undefined;
|
|
313
|
+
if (!details) {
|
|
314
|
+
const text = result.content[0];
|
|
315
|
+
return new Text(text?.type === "text" ? text.text : "", 0, 0);
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
if (details.error) {
|
|
319
|
+
return new Text(theme.fg("error", `Error: ${details.error}`), 0, 0);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const todoList = details.todos.filter((t) => !t.deleted);
|
|
323
|
+
|
|
324
|
+
const statusBadge = (t: Todo): string => {
|
|
325
|
+
if (t.done) return theme.fg("success", "已完成");
|
|
326
|
+
if (t.priority === "high") return theme.fg("error", "高优先");
|
|
327
|
+
if (t.priority === "low") return theme.fg("dim", "低优先");
|
|
328
|
+
return theme.fg("dim", "待处理");
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
const formatRow = (t: Todo): string => {
|
|
332
|
+
const check = t.done ? theme.fg("success", "☑") : theme.fg("muted", "☐");
|
|
333
|
+
const label = t.priority ? (t.priority === "high" ? theme.fg("error", "!") : theme.fg("dim", "?")) : "";
|
|
334
|
+
const txt = t.done ? theme.fg("dim", t.text) : theme.fg("text", t.text);
|
|
335
|
+
const badge = statusBadge(t);
|
|
336
|
+
return `${check} ${label} ${txt}${" ".repeat(Math.max(1, 20 - t.text.length))}${badge}`;
|
|
337
|
+
};
|
|
338
|
+
|
|
339
|
+
switch (details.action) {
|
|
340
|
+
case "list": {
|
|
341
|
+
if (todoList.length === 0) {
|
|
342
|
+
return new Text(theme.fg("dim", "No todos"), 0, 0);
|
|
343
|
+
}
|
|
344
|
+
const header = theme.fg("toolTitle", `${todoList.length} todos`);
|
|
345
|
+
const display = expanded ? todoList : todoList.slice(0, 5);
|
|
346
|
+
let listText = header;
|
|
347
|
+
for (const t of display) {
|
|
348
|
+
listText += `\n${formatRow(t)}`;
|
|
349
|
+
}
|
|
350
|
+
if (!expanded && todoList.length > 5) {
|
|
351
|
+
listText += `\n${theme.fg("dim", `... ${todoList.length - 5} more`)}`;
|
|
352
|
+
}
|
|
353
|
+
return new Text(listText, 0, 0);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
case "add":
|
|
357
|
+
case "add_batch": {
|
|
358
|
+
const added = todoList[todoList.length - 1];
|
|
359
|
+
if (!added) return new Text(theme.fg("success", "✓ Added"), 0, 0);
|
|
360
|
+
const header = theme.fg("toolTitle", `${todoList.length} todos`);
|
|
361
|
+
return new Text(`${header}\n${formatRow(added)}`, 0, 0);
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
case "toggle": {
|
|
365
|
+
const header = theme.fg("toolTitle", `${todoList.length} todos`);
|
|
366
|
+
const display = expanded ? todoList : todoList.slice(0, 5);
|
|
367
|
+
let listText = header;
|
|
368
|
+
for (const t of display) {
|
|
369
|
+
listText += `\n${formatRow(t)}`;
|
|
370
|
+
}
|
|
371
|
+
if (!expanded && todoList.length > 5) {
|
|
372
|
+
listText += `\n${theme.fg("dim", `... ${todoList.length - 5} more`)}`;
|
|
373
|
+
}
|
|
374
|
+
return new Text(listText, 0, 0);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
case "remove": {
|
|
378
|
+
const header = theme.fg("toolTitle", `${todoList.length} todos`);
|
|
379
|
+
const display = expanded ? todoList : todoList.slice(0, 5);
|
|
380
|
+
let listText = header;
|
|
381
|
+
for (const t of display) {
|
|
382
|
+
listText += `\n${formatRow(t)}`;
|
|
383
|
+
}
|
|
384
|
+
if (!expanded && todoList.length > 5) {
|
|
385
|
+
listText += `\n${theme.fg("dim", `... ${todoList.length - 5} more`)}`;
|
|
386
|
+
}
|
|
387
|
+
return new Text(listText, 0, 0);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
case "clear":
|
|
391
|
+
return new Text(theme.fg("success", "☑ Cleared all todos"), 0, 0);
|
|
392
|
+
|
|
393
|
+
default: {
|
|
394
|
+
const text = result.content[0];
|
|
395
|
+
const msg = text?.type === "text" ? text.text : "";
|
|
396
|
+
return new Text(theme.fg("muted", msg), 0, 0);
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
},
|
|
400
|
+
});
|
|
401
|
+
|
|
402
|
+
pi.registerCommand("todos", {
|
|
403
|
+
description: "Show all todos on the current branch",
|
|
404
|
+
handler: async (_args, ctx) => {
|
|
405
|
+
if (!ctx.hasUI) {
|
|
406
|
+
ctx.ui.notify("/todos requires interactive mode", "error");
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
const active = todos.filter((t) => !t.deleted);
|
|
410
|
+
const lines: string[] = [];
|
|
411
|
+
lines.push(`Todos (${active.filter((t) => t.done).length}/${active.length}):`);
|
|
412
|
+
for (const t of active) {
|
|
413
|
+
const pri = t.priority ? (t.priority === "high" ? "!" : t.priority === "low" ? "?" : "") : "";
|
|
414
|
+
lines.push(`${t.done ? "✓" : "○"}${pri} #${t.id}: ${t.text}`);
|
|
415
|
+
}
|
|
416
|
+
ctx.ui.notify(lines.join("\n"), "info");
|
|
417
|
+
},
|
|
418
|
+
});
|
|
419
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-extension-custom-provider",
|
|
3
|
-
"version": "0.74.
|
|
3
|
+
"version": "0.74.16",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "pi-extension-custom-provider",
|
|
9
|
-
"version": "0.74.
|
|
9
|
+
"version": "0.74.16",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@anthropic-ai/sdk": "^0.52.0"
|
|
12
12
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-extension-sandbox",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.16",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "pi-extension-sandbox",
|
|
9
|
-
"version": "1.4.
|
|
9
|
+
"version": "1.4.16",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@anthropic-ai/sandbox-runtime": "^0.0.26"
|
|
12
12
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-extension-with-deps",
|
|
3
|
-
"version": "0.74.
|
|
3
|
+
"version": "0.74.16",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "pi-extension-with-deps",
|
|
9
|
-
"version": "0.74.
|
|
9
|
+
"version": "0.74.16",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"ms": "^2.1.3"
|
|
12
12
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dyyz1993/pi-coding-agent",
|
|
3
|
-
"version": "0.74.
|
|
3
|
+
"version": "0.74.27",
|
|
4
4
|
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"piConfig": {
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
},
|
|
24
24
|
"files": [
|
|
25
25
|
"dist",
|
|
26
|
+
"dist/extensions",
|
|
26
27
|
"docs",
|
|
27
28
|
"examples",
|
|
28
29
|
"CHANGELOG.md"
|
|
@@ -32,15 +33,15 @@
|
|
|
32
33
|
"dev": "tsgo -p tsconfig.build.json --watch --preserveWatchOutput",
|
|
33
34
|
"build": "tsgo -p tsconfig.build.json && shx chmod +x dist/cli.js && npm run copy-assets",
|
|
34
35
|
"build:binary": "npm --prefix ../tui run build && npm --prefix ../ai run build && npm --prefix ../agent run build && npm run build && bun build --compile ./dist/bun/cli.js --outfile dist/pi && npm run copy-binary-assets",
|
|
35
|
-
"copy-assets": "shx mkdir -p dist/modes/interactive/theme && shx cp src/modes/interactive/theme/*.json dist/modes/interactive/theme/ && shx mkdir -p dist/modes/interactive/assets && shx cp src/modes/interactive/assets/*.png dist/modes/interactive/assets/ && shx mkdir -p dist/core/export-html/vendor && shx cp src/core/export-html/template.html src/core/export-html/template.css src/core/export-html/template.js dist/core/export-html/ && shx cp src/core/export-html/vendor/*.js dist/core/export-html/vendor/",
|
|
36
|
+
"copy-assets": "shx mkdir -p dist/modes/interactive/theme && shx cp src/modes/interactive/theme/*.json dist/modes/interactive/theme/ && shx mkdir -p dist/modes/interactive/assets && shx cp src/modes/interactive/assets/*.png dist/modes/interactive/assets/ && shx mkdir -p dist/core/export-html/vendor && shx cp src/core/export-html/template.html src/core/export-html/template.css src/core/export-html/template.js dist/core/export-html/ && shx cp src/core/export-html/vendor/*.js dist/core/export-html/vendor/ && shx mkdir -p dist/extensions && shx cp -r extensions/* dist/extensions/",
|
|
36
37
|
"copy-binary-assets": "shx cp package.json dist/ && shx cp README.md dist/ && shx cp CHANGELOG.md dist/ && shx mkdir -p dist/theme && shx cp src/modes/interactive/theme/*.json dist/theme/ && shx mkdir -p dist/assets && shx cp src/modes/interactive/assets/*.png dist/assets/ && shx mkdir -p dist/export-html/vendor && shx cp src/core/export-html/template.html dist/export-html/ && shx cp src/core/export-html/vendor/*.js dist/export-html/vendor/ && shx cp -r docs dist/ && shx cp -r examples dist/ && shx cp ../../node_modules/@silvia-odwyer/photon-node/photon_rs_bg.wasm dist/",
|
|
37
38
|
"test": "vitest --run",
|
|
38
39
|
"prepublishOnly": "npm run clean && npm run build"
|
|
39
40
|
},
|
|
40
41
|
"dependencies": {
|
|
41
|
-
"@dyyz1993/pi-agent-core": "^0.74.
|
|
42
|
-
"@dyyz1993/pi-ai": "^0.74.
|
|
43
|
-
"@dyyz1993/pi-tui": "^0.74.
|
|
42
|
+
"@dyyz1993/pi-agent-core": "^0.74.27",
|
|
43
|
+
"@dyyz1993/pi-ai": "^0.74.27",
|
|
44
|
+
"@dyyz1993/pi-tui": "^0.74.27",
|
|
44
45
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
45
46
|
"@silvia-odwyer/photon-node": "^0.3.4",
|
|
46
47
|
"chalk": "^5.5.0",
|