@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.
Files changed (66) hide show
  1. package/README.md +25 -0
  2. package/agent-loader.js +3 -2
  3. package/agent-loader.js.map +2 -2
  4. package/main.js +82162 -46093
  5. package/main.js.map +4 -4
  6. package/package.json +12 -3
  7. package/resources/chrome-tools/browser-content.js +46 -46
  8. package/resources/chrome-tools/browser-cookies.js +16 -16
  9. package/resources/chrome-tools/browser-eval.js +27 -27
  10. package/resources/chrome-tools/browser-hn-scraper.js +1 -1
  11. package/resources/chrome-tools/browser-nav.js +23 -23
  12. package/resources/chrome-tools/browser-pick.js +127 -127
  13. package/resources/chrome-tools/browser-screenshot.js +10 -10
  14. package/resources/chrome-tools/browser-start.js +38 -38
  15. package/resources/pi-agent/extensions/answer.ts +392 -384
  16. package/resources/pi-agent/extensions/context.ts +415 -415
  17. package/resources/pi-agent/extensions/control.ts +1287 -1287
  18. package/resources/pi-agent/extensions/diff.ts +171 -171
  19. package/resources/pi-agent/extensions/files.ts +155 -155
  20. package/resources/pi-agent/extensions/knowledge.ts +664 -0
  21. package/resources/pi-agent/extensions/loop.ts +375 -375
  22. package/resources/pi-agent/extensions/pi-bash-live-view/index.ts +1 -1
  23. package/resources/pi-agent/extensions/pi-bash-live-view/package.json +22 -22
  24. package/resources/pi-agent/extensions/pi-bash-live-view/pty-execute.ts +2 -2
  25. package/resources/pi-agent/extensions/pi-bash-live-view/pty-session.ts +2 -2
  26. package/resources/pi-agent/extensions/pi-bash-live-view/spawn-helper.ts +2 -2
  27. package/resources/pi-agent/extensions/pi-bash-live-view/terminal-emulator.ts +18 -18
  28. package/resources/pi-agent/extensions/pi-bash-live-view/truncate.ts +1 -1
  29. package/resources/pi-agent/extensions/pi-bash-live-view/widget.ts +4 -4
  30. package/resources/pi-agent/extensions/pi-custom-compaction/package.json +4 -4
  31. package/resources/pi-agent/extensions/pi-mcp-adapter/app-bridge.bundle.js +14 -14
  32. package/resources/pi-agent/extensions/pi-mcp-adapter/commands.ts +6 -6
  33. package/resources/pi-agent/extensions/pi-mcp-adapter/config.ts +9 -9
  34. package/resources/pi-agent/extensions/pi-mcp-adapter/consent-manager.ts +4 -4
  35. package/resources/pi-agent/extensions/pi-mcp-adapter/direct-tools.ts +13 -13
  36. package/resources/pi-agent/extensions/pi-mcp-adapter/glimpse-ui.ts +5 -5
  37. package/resources/pi-agent/extensions/pi-mcp-adapter/host-html-template.ts +13 -13
  38. package/resources/pi-agent/extensions/pi-mcp-adapter/index.ts +14 -14
  39. package/resources/pi-agent/extensions/pi-mcp-adapter/init.ts +17 -17
  40. package/resources/pi-agent/extensions/pi-mcp-adapter/lifecycle.ts +2 -2
  41. package/resources/pi-agent/extensions/pi-mcp-adapter/logger.ts +2 -2
  42. package/resources/pi-agent/extensions/pi-mcp-adapter/mcp-panel.ts +17 -17
  43. package/resources/pi-agent/extensions/pi-mcp-adapter/metadata-cache.ts +9 -9
  44. package/resources/pi-agent/extensions/pi-mcp-adapter/npx-resolver.ts +35 -35
  45. package/resources/pi-agent/extensions/pi-mcp-adapter/oauth-handler.ts +1 -1
  46. package/resources/pi-agent/extensions/pi-mcp-adapter/proxy-modes.ts +12 -12
  47. package/resources/pi-agent/extensions/pi-mcp-adapter/server-manager.ts +6 -6
  48. package/resources/pi-agent/extensions/pi-mcp-adapter/tool-metadata.ts +4 -4
  49. package/resources/pi-agent/extensions/pi-mcp-adapter/types.ts +2 -2
  50. package/resources/pi-agent/extensions/pi-mcp-adapter/ui-resource-handler.ts +6 -6
  51. package/resources/pi-agent/extensions/pi-mcp-adapter/ui-server.ts +17 -17
  52. package/resources/pi-agent/extensions/pi-mcp-adapter/ui-session.ts +22 -22
  53. package/resources/pi-agent/extensions/pi-mcp-adapter/utils.ts +2 -2
  54. package/resources/pi-agent/extensions/prompt-editor.ts +900 -900
  55. package/resources/pi-agent/extensions/prompt-url-widget.ts +122 -122
  56. package/resources/pi-agent/extensions/redraws.ts +14 -14
  57. package/resources/pi-agent/extensions/review.ts +1533 -1533
  58. package/resources/pi-agent/extensions/todos.ts +1735 -1735
  59. package/resources/pi-agent/extensions/tps.ts +40 -40
  60. package/resources/pi-agent/extensions/whimsical.ts +3 -3
  61. package/resources/pi-agent/prompts/agent-system.md +2 -0
  62. package/resources/pi-agent/prompts/coder-system.md +2 -0
  63. package/server-loader.js +82 -1
  64. package/server-loader.js.map +3 -3
  65. package/tui.mjs +2 -0
  66. 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 (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
- }
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
- const branch = ctx.sessionManager.getBranch();
30
+ const branch = ctx.sessionManager.getBranch();
31
31
 
32
32
  // First pass: collect tool calls (id -> {path, name}) from assistant messages
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
- }
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
- 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
- }
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
- 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
- };
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
- await ctx.ui.custom<void>((tui, theme, _kb, done) => {
129
- const container = new Container();
128
+ await ctx.ui.custom<void>((tui, theme, _kb, done) => {
129
+ const container = new Container();
130
130
 
131
131
  // Top border
132
- container.addChild(new DynamicBorder((s: string) => theme.fg("accent", s)));
132
+ container.addChild(new DynamicBorder((s: string) => theme.fg("accent", s)));
133
133
 
134
134
  // Title
135
- container.addChild(new Text(theme.fg("accent", theme.bold(" Select file to open")), 0, 0));
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
- 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);
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
- container.addChild(
171
- new Text(theme.fg("dim", " ↑↓ navigate • ←→ page • enter open • esc close"), 0, 0),
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
- container.addChild(new DynamicBorder((s: string) => theme.fg("accent", s)));
175
+ container.addChild(new DynamicBorder((s: string) => theme.fg("accent", s)));
176
176
 
177
- return {
178
- render: (w) => container.render(w),
179
- invalidate: () => container.invalidate(),
180
- handleInput: (data) => {
177
+ return {
178
+ render: (w) => container.render(w),
179
+ invalidate: () => container.invalidate(),
180
+ handleInput: (data) => {
181
181
  // Add paging with left/right
182
- if (matchesKey(data, Key.left)) {
182
+ if (matchesKey(data, Key.left)) {
183
183
  // Page up - clamp to 0
184
- currentIndex = Math.max(0, currentIndex - visibleRows);
185
- selectList.setSelectedIndex(currentIndex);
186
- } else if (matchesKey(data, Key.right)) {
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
- 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
- });
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
  }