@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
@@ -15,204 +15,204 @@ interface FileInfo {
15
15
  file: string;
16
16
  }
17
17
 
18
- export default function (pi: ExtensionAPI) {
19
- pi.registerCommand("diff", {
20
- description: "Show git changes and open in VS Code diff view",
21
- handler: async (_args, ctx) => {
22
- if (!ctx.hasUI) {
23
- ctx.ui.notify("No UI available", "error");
24
- return;
25
- }
18
+ export default function(pi: ExtensionAPI) {
19
+ pi.registerCommand("diff", {
20
+ description: "Show git changes and open in VS Code diff view",
21
+ handler: async(_args, ctx) => {
22
+ if (!ctx.hasUI) {
23
+ ctx.ui.notify("No UI available", "error");
24
+ return;
25
+ }
26
26
 
27
27
  // Get changed files from git status
28
- const result = await pi.exec("git", ["status", "--porcelain"], { cwd: ctx.cwd });
28
+ const result = await pi.exec("git", ["status", "--porcelain"], { cwd: ctx.cwd });
29
29
 
30
- if (result.code !== 0) {
31
- ctx.ui.notify(`git status failed: ${result.stderr}`, "error");
32
- return;
33
- }
30
+ if (result.code !== 0) {
31
+ ctx.ui.notify(`git status failed: ${result.stderr}`, "error");
32
+ return;
33
+ }
34
34
 
35
- if (!result.stdout || !result.stdout.trim()) {
36
- ctx.ui.notify("No changes in working tree", "info");
37
- return;
38
- }
35
+ if (!result.stdout || !result.stdout.trim()) {
36
+ ctx.ui.notify("No changes in working tree", "info");
37
+ return;
38
+ }
39
39
 
40
40
  // Parse git status output
41
41
  // Format: XY filename (where XY is two-letter status, then space, then filename)
42
- const lines = result.stdout.split("\n");
43
- const files: FileInfo[] = [];
42
+ const lines = result.stdout.split("\n");
43
+ const files: FileInfo[] = [];
44
44
 
45
- for (const line of lines) {
46
- if (line.length < 4) continue; // Need at least "XY f"
45
+ for (const line of lines) {
46
+ if (line.length < 4) {continue;} // Need at least "XY f"
47
47
 
48
- const status = line.slice(0, 2);
49
- const file = line.slice(2).trimStart();
48
+ const status = line.slice(0, 2);
49
+ const file = line.slice(2).trimStart();
50
50
 
51
51
  // Translate status codes to short labels
52
- let statusLabel: string;
53
- if (status.includes("M")) statusLabel = "M";
54
- else if (status.includes("A")) statusLabel = "A";
55
- else if (status.includes("D")) statusLabel = "D";
56
- else if (status.includes("?")) statusLabel = "?";
57
- else if (status.includes("R")) statusLabel = "R";
58
- else if (status.includes("C")) statusLabel = "C";
59
- else statusLabel = status.trim() || "~";
60
-
61
- files.push({ status: statusLabel, statusLabel, file });
62
- }
63
-
64
- if (files.length === 0) {
65
- ctx.ui.notify("No changes found", "info");
66
- return;
67
- }
68
-
69
- const WINDOWS_UNSAFE_CMD_CHARS_RE = /[&|<>^%\r\n]/;
70
- const quoteCmdArg = (value: string) => `"${value.replace(/"/g, '""')}"`;
71
-
72
- const openWithCode = async (file: string) => {
73
- if (process.platform === "win32") {
74
- if (WINDOWS_UNSAFE_CMD_CHARS_RE.test(file)) {
75
- ctx.ui.notify(
76
- `Refusing to open ${file}: path contains Windows cmd metacharacters (& | < > ^ % or newline).`,
77
- "error",
78
- );
79
- return null;
80
- }
81
- const commandLine = `code -g ${quoteCmdArg(file)}`;
82
- return pi.exec("cmd", ["/d", "/s", "/c", commandLine], { cwd: ctx.cwd });
83
- }
84
- return pi.exec("code", ["-g", file], { cwd: ctx.cwd });
85
- };
86
-
87
- const openSelected = async (fileInfo: FileInfo): Promise<void> => {
88
- try {
52
+ let statusLabel: string;
53
+ if (status.includes("M")) {statusLabel = "M";}
54
+ else if (status.includes("A")) {statusLabel = "A";}
55
+ else if (status.includes("D")) {statusLabel = "D";}
56
+ else if (status.includes("?")) {statusLabel = "?";}
57
+ else if (status.includes("R")) {statusLabel = "R";}
58
+ else if (status.includes("C")) {statusLabel = "C";}
59
+ else {statusLabel = status.trim() || "~";}
60
+
61
+ files.push({ status: statusLabel, statusLabel, file });
62
+ }
63
+
64
+ if (files.length === 0) {
65
+ ctx.ui.notify("No changes found", "info");
66
+ return;
67
+ }
68
+
69
+ const WINDOWS_UNSAFE_CMD_CHARS_RE = /[&|<>^%\r\n]/;
70
+ const quoteCmdArg = (value: string) => `"${value.replace(/"/g, '""')}"`;
71
+
72
+ const openWithCode = async(file: string) => {
73
+ if (process.platform === "win32") {
74
+ if (WINDOWS_UNSAFE_CMD_CHARS_RE.test(file)) {
75
+ ctx.ui.notify(
76
+ `Refusing to open ${file}: path contains Windows cmd metacharacters (& | < > ^ % or newline).`,
77
+ "error",
78
+ );
79
+ return null;
80
+ }
81
+ const commandLine = `code -g ${quoteCmdArg(file)}`;
82
+ return pi.exec("cmd", ["/d", "/s", "/c", commandLine], { cwd: ctx.cwd });
83
+ }
84
+ return pi.exec("code", ["-g", file], { cwd: ctx.cwd });
85
+ };
86
+
87
+ const openSelected = async(fileInfo: FileInfo): Promise<void> => {
88
+ try {
89
89
  // Open in VS Code diff view.
90
90
  // For untracked files, git difftool won't work, so fall back to just opening the file.
91
- if (fileInfo.status === "?") {
92
- const openResult = await openWithCode(fileInfo.file);
93
- if (!openResult) return;
94
- if (openResult.code !== 0) {
95
- const openStderr = openResult.stderr.trim();
96
- ctx.ui.notify(
97
- `Failed to open ${fileInfo.file} (exit ${openResult.code})${openStderr ? `: ${openStderr}` : ""}`,
98
- "error",
99
- );
100
- }
101
- return;
102
- }
103
-
104
- const diffResult = await pi.exec("git", ["difftool", "-y", "--tool=vscode", fileInfo.file], {
105
- cwd: ctx.cwd,
106
- });
107
- if (diffResult.code !== 0) {
108
- const diffStderr = diffResult.stderr.trim();
109
- ctx.ui.notify(
110
- `Failed to show diff with vscode for ${fileInfo.file} (exit ${diffResult.code})${diffStderr ? `: ${diffStderr}` : ""}`,
111
- "error",
112
- );
113
- ctx.ui.notify(
114
- "Troubleshooting: check git difftool config (e.g. `git config --get difftool.vscode.cmd`).",
115
- "info",
116
- );
117
-
118
- const openResult = await openWithCode(fileInfo.file);
119
- if (!openResult) return;
120
- if (openResult.code !== 0) {
121
- const openStderr = openResult.stderr.trim();
122
- ctx.ui.notify(
123
- `Failed to open ${fileInfo.file} (exit ${openResult.code})${openStderr ? `: ${openStderr}` : ""}`,
124
- "error",
125
- );
126
- }
127
- }
128
- } catch (error) {
129
- const message = error instanceof Error ? error.message : String(error);
130
- ctx.ui.notify(`Failed to open ${fileInfo.file}: ${message}`, "error");
131
- }
132
- };
91
+ if (fileInfo.status === "?") {
92
+ const openResult = await openWithCode(fileInfo.file);
93
+ if (!openResult) {return;}
94
+ if (openResult.code !== 0) {
95
+ const openStderr = openResult.stderr.trim();
96
+ ctx.ui.notify(
97
+ `Failed to open ${fileInfo.file} (exit ${openResult.code})${openStderr ? `: ${openStderr}` : ""}`,
98
+ "error",
99
+ );
100
+ }
101
+ return;
102
+ }
103
+
104
+ const diffResult = await pi.exec("git", ["difftool", "-y", "--tool=vscode", fileInfo.file], {
105
+ cwd: ctx.cwd,
106
+ });
107
+ if (diffResult.code !== 0) {
108
+ const diffStderr = diffResult.stderr.trim();
109
+ ctx.ui.notify(
110
+ `Failed to show diff with vscode for ${fileInfo.file} (exit ${diffResult.code})${diffStderr ? `: ${diffStderr}` : ""}`,
111
+ "error",
112
+ );
113
+ ctx.ui.notify(
114
+ "Troubleshooting: check git difftool config (e.g. `git config --get difftool.vscode.cmd`).",
115
+ "info",
116
+ );
117
+
118
+ const openResult = await openWithCode(fileInfo.file);
119
+ if (!openResult) {return;}
120
+ if (openResult.code !== 0) {
121
+ const openStderr = openResult.stderr.trim();
122
+ ctx.ui.notify(
123
+ `Failed to open ${fileInfo.file} (exit ${openResult.code})${openStderr ? `: ${openStderr}` : ""}`,
124
+ "error",
125
+ );
126
+ }
127
+ }
128
+ } catch (error) {
129
+ const message = error instanceof Error ? error.message : String(error);
130
+ ctx.ui.notify(`Failed to open ${fileInfo.file}: ${message}`, "error");
131
+ }
132
+ };
133
133
 
134
134
  // Show file picker with SelectList
135
- await ctx.ui.custom<void>((tui, theme, _kb, done) => {
136
- const container = new Container();
135
+ await ctx.ui.custom<void>((tui, theme, _kb, done) => {
136
+ const container = new Container();
137
137
 
138
138
  // Top border
139
- container.addChild(new DynamicBorder((s: string) => theme.fg("accent", s)));
139
+ container.addChild(new DynamicBorder((s: string) => theme.fg("accent", s)));
140
140
 
141
141
  // Title
142
- container.addChild(new Text(theme.fg("accent", theme.bold(" Select file to diff")), 0, 0));
142
+ container.addChild(new Text(theme.fg("accent", theme.bold(" Select file to diff")), 0, 0));
143
143
 
144
144
  // Build select items with colored status
145
- const items: SelectItem[] = files.map((f) => {
146
- let statusColor: string;
147
- switch (f.status) {
148
- case "M":
149
- statusColor = theme.fg("warning", f.status);
150
- break;
151
- case "A":
152
- statusColor = theme.fg("success", f.status);
153
- break;
154
- case "D":
155
- statusColor = theme.fg("error", f.status);
156
- break;
157
- case "?":
158
- statusColor = theme.fg("muted", f.status);
159
- break;
160
- default:
161
- statusColor = theme.fg("dim", f.status);
162
- }
163
- return {
164
- value: f,
165
- label: `${statusColor} ${f.file}`,
166
- };
167
- });
168
-
169
- const visibleRows = Math.min(files.length, 15);
170
- let currentIndex = 0;
171
-
172
- const selectList = new SelectList(items, visibleRows, {
173
- selectedPrefix: (t) => theme.fg("accent", t),
174
- selectedText: (t) => t, // Keep existing colors
175
- description: (t) => theme.fg("muted", t),
176
- scrollInfo: (t) => theme.fg("dim", t),
177
- noMatch: (t) => theme.fg("warning", t),
178
- });
179
- selectList.onSelect = (item) => {
180
- void openSelected(item.value as FileInfo);
181
- };
182
- selectList.onCancel = () => done();
183
- selectList.onSelectionChange = (item) => {
184
- currentIndex = items.indexOf(item);
185
- };
186
- container.addChild(selectList);
145
+ const items: SelectItem[] = files.map((f) => {
146
+ let statusColor: string;
147
+ switch (f.status) {
148
+ case "M":
149
+ statusColor = theme.fg("warning", f.status);
150
+ break;
151
+ case "A":
152
+ statusColor = theme.fg("success", f.status);
153
+ break;
154
+ case "D":
155
+ statusColor = theme.fg("error", f.status);
156
+ break;
157
+ case "?":
158
+ statusColor = theme.fg("muted", f.status);
159
+ break;
160
+ default:
161
+ statusColor = theme.fg("dim", f.status);
162
+ }
163
+ return {
164
+ value: f,
165
+ label: `${statusColor} ${f.file}`,
166
+ };
167
+ });
168
+
169
+ const visibleRows = Math.min(files.length, 15);
170
+ let currentIndex = 0;
171
+
172
+ const selectList = new SelectList(items, visibleRows, {
173
+ selectedPrefix: (t) => theme.fg("accent", t),
174
+ selectedText: (t) => t, // Keep existing colors
175
+ description: (t) => theme.fg("muted", t),
176
+ scrollInfo: (t) => theme.fg("dim", t),
177
+ noMatch: (t) => theme.fg("warning", t),
178
+ });
179
+ selectList.onSelect = (item) => {
180
+ void openSelected(item.value as FileInfo);
181
+ };
182
+ selectList.onCancel = () => done();
183
+ selectList.onSelectionChange = (item) => {
184
+ currentIndex = items.indexOf(item);
185
+ };
186
+ container.addChild(selectList);
187
187
 
188
188
  // Help text
189
- container.addChild(
190
- new Text(theme.fg("dim", " ↑↓ navigate • ←→ page • enter open • esc close"), 0, 0),
191
- );
189
+ container.addChild(
190
+ new Text(theme.fg("dim", " ↑↓ navigate • ←→ page • enter open • esc close"), 0, 0),
191
+ );
192
192
 
193
193
  // Bottom border
194
- container.addChild(new DynamicBorder((s: string) => theme.fg("accent", s)));
194
+ container.addChild(new DynamicBorder((s: string) => theme.fg("accent", s)));
195
195
 
196
- return {
197
- render: (w) => container.render(w),
198
- invalidate: () => container.invalidate(),
199
- handleInput: (data) => {
196
+ return {
197
+ render: (w) => container.render(w),
198
+ invalidate: () => container.invalidate(),
199
+ handleInput: (data) => {
200
200
  // Add paging with left/right
201
- if (matchesKey(data, Key.left)) {
201
+ if (matchesKey(data, Key.left)) {
202
202
  // Page up - clamp to 0
203
- currentIndex = Math.max(0, currentIndex - visibleRows);
204
- selectList.setSelectedIndex(currentIndex);
205
- } else if (matchesKey(data, Key.right)) {
203
+ currentIndex = Math.max(0, currentIndex - visibleRows);
204
+ selectList.setSelectedIndex(currentIndex);
205
+ } else if (matchesKey(data, Key.right)) {
206
206
  // Page down - clamp to last
207
- currentIndex = Math.min(items.length - 1, currentIndex + visibleRows);
208
- selectList.setSelectedIndex(currentIndex);
209
- } else {
210
- selectList.handleInput(data);
211
- }
212
- tui.requestRender();
213
- },
214
- };
215
- });
216
- },
217
- });
207
+ currentIndex = Math.min(items.length - 1, currentIndex + visibleRows);
208
+ selectList.setSelectedIndex(currentIndex);
209
+ } else {
210
+ selectList.handleInput(data);
211
+ }
212
+ tui.requestRender();
213
+ },
214
+ };
215
+ });
216
+ },
217
+ });
218
218
  }