@docyrus/docyrus 0.0.34 → 0.0.36
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/README.md +25 -0
- package/agent-loader.js +3 -2
- package/agent-loader.js.map +2 -2
- package/main.js +82162 -46093
- package/main.js.map +4 -4
- package/package.json +12 -3
- package/resources/chrome-tools/browser-content.js +46 -46
- package/resources/chrome-tools/browser-cookies.js +16 -16
- package/resources/chrome-tools/browser-eval.js +27 -27
- package/resources/chrome-tools/browser-hn-scraper.js +1 -1
- package/resources/chrome-tools/browser-nav.js +23 -23
- package/resources/chrome-tools/browser-pick.js +127 -127
- package/resources/chrome-tools/browser-screenshot.js +10 -10
- package/resources/chrome-tools/browser-start.js +38 -38
- package/resources/pi-agent/extensions/answer.ts +392 -384
- package/resources/pi-agent/extensions/context.ts +415 -415
- package/resources/pi-agent/extensions/control.ts +1287 -1287
- package/resources/pi-agent/extensions/diff.ts +171 -171
- package/resources/pi-agent/extensions/files.ts +155 -155
- package/resources/pi-agent/extensions/knowledge.ts +664 -0
- package/resources/pi-agent/extensions/loop.ts +375 -375
- package/resources/pi-agent/extensions/pi-bash-live-view/index.ts +1 -1
- package/resources/pi-agent/extensions/pi-bash-live-view/package.json +22 -22
- package/resources/pi-agent/extensions/pi-bash-live-view/pty-execute.ts +2 -2
- package/resources/pi-agent/extensions/pi-bash-live-view/pty-session.ts +2 -2
- package/resources/pi-agent/extensions/pi-bash-live-view/spawn-helper.ts +2 -2
- package/resources/pi-agent/extensions/pi-bash-live-view/terminal-emulator.ts +18 -18
- package/resources/pi-agent/extensions/pi-bash-live-view/truncate.ts +1 -1
- package/resources/pi-agent/extensions/pi-bash-live-view/widget.ts +4 -4
- package/resources/pi-agent/extensions/pi-custom-compaction/package.json +4 -4
- package/resources/pi-agent/extensions/pi-mcp-adapter/app-bridge.bundle.js +14 -14
- package/resources/pi-agent/extensions/pi-mcp-adapter/commands.ts +6 -6
- package/resources/pi-agent/extensions/pi-mcp-adapter/config.ts +9 -9
- package/resources/pi-agent/extensions/pi-mcp-adapter/consent-manager.ts +4 -4
- package/resources/pi-agent/extensions/pi-mcp-adapter/direct-tools.ts +13 -13
- package/resources/pi-agent/extensions/pi-mcp-adapter/glimpse-ui.ts +5 -5
- package/resources/pi-agent/extensions/pi-mcp-adapter/host-html-template.ts +13 -13
- package/resources/pi-agent/extensions/pi-mcp-adapter/index.ts +14 -14
- package/resources/pi-agent/extensions/pi-mcp-adapter/init.ts +17 -17
- package/resources/pi-agent/extensions/pi-mcp-adapter/lifecycle.ts +2 -2
- package/resources/pi-agent/extensions/pi-mcp-adapter/logger.ts +2 -2
- package/resources/pi-agent/extensions/pi-mcp-adapter/mcp-panel.ts +17 -17
- package/resources/pi-agent/extensions/pi-mcp-adapter/metadata-cache.ts +9 -9
- package/resources/pi-agent/extensions/pi-mcp-adapter/npx-resolver.ts +35 -35
- package/resources/pi-agent/extensions/pi-mcp-adapter/oauth-handler.ts +1 -1
- package/resources/pi-agent/extensions/pi-mcp-adapter/proxy-modes.ts +12 -12
- package/resources/pi-agent/extensions/pi-mcp-adapter/server-manager.ts +6 -6
- package/resources/pi-agent/extensions/pi-mcp-adapter/tool-metadata.ts +4 -4
- package/resources/pi-agent/extensions/pi-mcp-adapter/types.ts +2 -2
- package/resources/pi-agent/extensions/pi-mcp-adapter/ui-resource-handler.ts +6 -6
- package/resources/pi-agent/extensions/pi-mcp-adapter/ui-server.ts +17 -17
- package/resources/pi-agent/extensions/pi-mcp-adapter/ui-session.ts +22 -22
- package/resources/pi-agent/extensions/pi-mcp-adapter/utils.ts +2 -2
- package/resources/pi-agent/extensions/prompt-editor.ts +900 -900
- package/resources/pi-agent/extensions/prompt-url-widget.ts +122 -122
- package/resources/pi-agent/extensions/redraws.ts +14 -14
- package/resources/pi-agent/extensions/review.ts +1533 -1533
- package/resources/pi-agent/extensions/todos.ts +1735 -1735
- package/resources/pi-agent/extensions/tps.ts +40 -40
- package/resources/pi-agent/extensions/whimsical.ts +3 -3
- package/resources/pi-agent/prompts/agent-system.md +2 -0
- package/resources/pi-agent/prompts/coder-system.md +2 -0
- package/server-loader.js +82 -1
- package/server-loader.js.map +3 -3
- package/tui.mjs +2 -0
- package/tui.mjs.map +1 -1
|
@@ -17,183 +17,183 @@ interface FileEntry {
|
|
|
17
17
|
|
|
18
18
|
type FileToolName = "read" | "write" | "edit";
|
|
19
19
|
|
|
20
|
-
export default function
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
20
|
+
export default function(pi: ExtensionAPI) {
|
|
21
|
+
pi.registerCommand("files", {
|
|
22
|
+
description: "Show files read/written/edited in this session",
|
|
23
|
+
handler: async(_args, ctx) => {
|
|
24
|
+
if (!ctx.hasUI) {
|
|
25
|
+
ctx.ui.notify("No UI available", "error");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
28
|
|
|
29
29
|
// Get the current branch (path from leaf to root)
|
|
30
|
-
|
|
30
|
+
const branch = ctx.sessionManager.getBranch();
|
|
31
31
|
|
|
32
32
|
// First pass: collect tool calls (id -> {path, name}) from assistant messages
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
33
|
+
const toolCalls = new Map<string, { path: string; name: FileToolName; timestamp: number }>();
|
|
34
|
+
|
|
35
|
+
for (const entry of branch) {
|
|
36
|
+
if (entry.type !== "message") {continue;}
|
|
37
|
+
const msg = entry.message;
|
|
38
|
+
|
|
39
|
+
if (msg.role === "assistant" && Array.isArray(msg.content)) {
|
|
40
|
+
for (const block of msg.content) {
|
|
41
|
+
if (block.type === "toolCall") {
|
|
42
|
+
const name = block.name;
|
|
43
|
+
if (name === "read" || name === "write" || name === "edit") {
|
|
44
|
+
const path = block.arguments?.path;
|
|
45
|
+
if (path && typeof path === "string") {
|
|
46
|
+
toolCalls.set(block.id, { path, name, timestamp: msg.timestamp });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
53
|
|
|
54
54
|
// Second pass: match tool results to get the actual execution timestamp
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
55
|
+
const fileMap = new Map<string, FileEntry>();
|
|
56
|
+
|
|
57
|
+
for (const entry of branch) {
|
|
58
|
+
if (entry.type !== "message") {continue;}
|
|
59
|
+
const msg = entry.message;
|
|
60
|
+
|
|
61
|
+
if (msg.role === "toolResult") {
|
|
62
|
+
const toolCall = toolCalls.get(msg.toolCallId);
|
|
63
|
+
if (!toolCall) {continue;}
|
|
64
|
+
|
|
65
|
+
const { path, name } = toolCall;
|
|
66
|
+
const timestamp = msg.timestamp;
|
|
67
|
+
|
|
68
|
+
const existing = fileMap.get(path);
|
|
69
|
+
if (existing) {
|
|
70
|
+
existing.operations.add(name);
|
|
71
|
+
if (timestamp > existing.lastTimestamp) {
|
|
72
|
+
existing.lastTimestamp = timestamp;
|
|
73
|
+
}
|
|
74
|
+
} else {
|
|
75
|
+
fileMap.set(path, {
|
|
76
|
+
path,
|
|
77
|
+
operations: new Set([name]),
|
|
78
|
+
lastTimestamp: timestamp,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (fileMap.size === 0) {
|
|
85
|
+
ctx.ui.notify("No files read/written/edited in this session", "info");
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
88
|
|
|
89
89
|
// Sort by most recent first
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
90
|
+
const files = Array.from(fileMap.values()).sort((a, b) => b.lastTimestamp - a.lastTimestamp);
|
|
91
|
+
|
|
92
|
+
const WINDOWS_UNSAFE_CMD_CHARS_RE = /[&|<>^%\r\n]/;
|
|
93
|
+
const quoteCmdArg = (value: string) => `"${value.replace(/"/g, '""')}"`;
|
|
94
|
+
|
|
95
|
+
const openWithCode = async(path: string) => {
|
|
96
|
+
if (process.platform === "win32") {
|
|
97
|
+
if (WINDOWS_UNSAFE_CMD_CHARS_RE.test(path)) {
|
|
98
|
+
ctx.ui.notify(
|
|
99
|
+
`Refusing to open ${path}: path contains Windows cmd metacharacters (& | < > ^ % or newline).`,
|
|
100
|
+
"error",
|
|
101
|
+
);
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
const commandLine = `code -g ${quoteCmdArg(path)}`;
|
|
105
|
+
return pi.exec("cmd", ["/d", "/s", "/c", commandLine], { cwd: ctx.cwd });
|
|
106
|
+
}
|
|
107
|
+
return pi.exec("code", ["-g", path], { cwd: ctx.cwd });
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
const openSelected = async(file: FileEntry): Promise<void> => {
|
|
111
|
+
try {
|
|
112
|
+
const openResult = await openWithCode(file.path);
|
|
113
|
+
if (!openResult) {return;}
|
|
114
|
+
if (openResult.code !== 0) {
|
|
115
|
+
const openStderr = openResult.stderr.trim();
|
|
116
|
+
ctx.ui.notify(
|
|
117
|
+
`Failed to open ${file.path} (exit ${openResult.code})${openStderr ? `: ${openStderr}` : ""}`,
|
|
118
|
+
"error",
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
} catch (error) {
|
|
122
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
123
|
+
ctx.ui.notify(`Failed to open ${file.path}: ${message}`, "error");
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
126
|
|
|
127
127
|
// Show file picker with SelectList
|
|
128
|
-
|
|
129
|
-
|
|
128
|
+
await ctx.ui.custom<void>((tui, theme, _kb, done) => {
|
|
129
|
+
const container = new Container();
|
|
130
130
|
|
|
131
131
|
// Top border
|
|
132
|
-
|
|
132
|
+
container.addChild(new DynamicBorder((s: string) => theme.fg("accent", s)));
|
|
133
133
|
|
|
134
134
|
// Title
|
|
135
|
-
|
|
135
|
+
container.addChild(new Text(theme.fg("accent", theme.bold(" Select file to open")), 0, 0));
|
|
136
136
|
|
|
137
137
|
// Build select items with colored operations
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
138
|
+
const items: SelectItem[] = files.map((f) => {
|
|
139
|
+
const ops: string[] = [];
|
|
140
|
+
if (f.operations.has("read")) {ops.push(theme.fg("muted", "R"));}
|
|
141
|
+
if (f.operations.has("write")) {ops.push(theme.fg("success", "W"));}
|
|
142
|
+
if (f.operations.has("edit")) {ops.push(theme.fg("warning", "E"));}
|
|
143
|
+
const opsLabel = ops.join("");
|
|
144
|
+
return {
|
|
145
|
+
value: f,
|
|
146
|
+
label: `${opsLabel} ${f.path}`,
|
|
147
|
+
};
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
const visibleRows = Math.min(files.length, 15);
|
|
151
|
+
let currentIndex = 0;
|
|
152
|
+
|
|
153
|
+
const selectList = new SelectList(items, visibleRows, {
|
|
154
|
+
selectedPrefix: (t) => theme.fg("accent", t),
|
|
155
|
+
selectedText: (t) => t, // Keep existing colors
|
|
156
|
+
description: (t) => theme.fg("muted", t),
|
|
157
|
+
scrollInfo: (t) => theme.fg("dim", t),
|
|
158
|
+
noMatch: (t) => theme.fg("warning", t),
|
|
159
|
+
});
|
|
160
|
+
selectList.onSelect = (item) => {
|
|
161
|
+
void openSelected(item.value as FileEntry);
|
|
162
|
+
};
|
|
163
|
+
selectList.onCancel = () => done();
|
|
164
|
+
selectList.onSelectionChange = (item) => {
|
|
165
|
+
currentIndex = items.indexOf(item);
|
|
166
|
+
};
|
|
167
|
+
container.addChild(selectList);
|
|
168
168
|
|
|
169
169
|
// Help text
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
170
|
+
container.addChild(
|
|
171
|
+
new Text(theme.fg("dim", " ↑↓ navigate • ←→ page • enter open • esc close"), 0, 0),
|
|
172
|
+
);
|
|
173
173
|
|
|
174
174
|
// Bottom border
|
|
175
|
-
|
|
175
|
+
container.addChild(new DynamicBorder((s: string) => theme.fg("accent", s)));
|
|
176
176
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
177
|
+
return {
|
|
178
|
+
render: (w) => container.render(w),
|
|
179
|
+
invalidate: () => container.invalidate(),
|
|
180
|
+
handleInput: (data) => {
|
|
181
181
|
// Add paging with left/right
|
|
182
|
-
|
|
182
|
+
if (matchesKey(data, Key.left)) {
|
|
183
183
|
// Page up - clamp to 0
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
184
|
+
currentIndex = Math.max(0, currentIndex - visibleRows);
|
|
185
|
+
selectList.setSelectedIndex(currentIndex);
|
|
186
|
+
} else if (matchesKey(data, Key.right)) {
|
|
187
187
|
// Page down - clamp to last
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
188
|
+
currentIndex = Math.min(items.length - 1, currentIndex + visibleRows);
|
|
189
|
+
selectList.setSelectedIndex(currentIndex);
|
|
190
|
+
} else {
|
|
191
|
+
selectList.handleInput(data);
|
|
192
|
+
}
|
|
193
|
+
tui.requestRender();
|
|
194
|
+
},
|
|
195
|
+
};
|
|
196
|
+
});
|
|
197
|
+
},
|
|
198
|
+
});
|
|
199
199
|
}
|