@evandu/super-pi 0.0.0-stage → 0.1.0

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 (59) hide show
  1. package/README.md +79 -2
  2. package/agents/coder.md +10 -0
  3. package/agents/critic.md +20 -0
  4. package/agents/patcher.md +23 -0
  5. package/agents/planner.md +18 -0
  6. package/agents/reviewer.md +13 -0
  7. package/agents/scout.md +23 -0
  8. package/agents/super-pi-task/core.ts +485 -0
  9. package/agents/super-pi-task/index.ts +141 -0
  10. package/agents/verifier.md +21 -0
  11. package/bin/super-pi.js +17 -0
  12. package/dist/client/assets/index-BMQsEdio.js +24 -0
  13. package/dist/client/assets/index-CsbZzuMy.css +1 -0
  14. package/dist/client/index.html +14 -0
  15. package/dist/extension.d.ts +15 -0
  16. package/dist/extension.js +111 -0
  17. package/dist/server/agents.d.ts +177 -0
  18. package/dist/server/agents.js +484 -0
  19. package/dist/server/application/catalog-service.d.ts +44 -0
  20. package/dist/server/application/catalog-service.js +94 -0
  21. package/dist/server/application/conversation-service.d.ts +73 -0
  22. package/dist/server/application/conversation-service.js +202 -0
  23. package/dist/server/application/extension-ui-service.d.ts +28 -0
  24. package/dist/server/application/extension-ui-service.js +73 -0
  25. package/dist/server/application/run-service.d.ts +115 -0
  26. package/dist/server/application/run-service.js +341 -0
  27. package/dist/server/application/workspace-service.d.ts +45 -0
  28. package/dist/server/application/workspace-service.js +106 -0
  29. package/dist/server/command-handler.d.ts +22 -0
  30. package/dist/server/command-handler.js +137 -0
  31. package/dist/server/files.d.ts +202 -0
  32. package/dist/server/files.js +629 -0
  33. package/dist/server/http-server.d.ts +20 -0
  34. package/dist/server/http-server.js +313 -0
  35. package/dist/server/index.d.ts +1 -0
  36. package/dist/server/index.js +103 -0
  37. package/dist/server/pi-command.d.ts +65 -0
  38. package/dist/server/pi-command.js +183 -0
  39. package/dist/server/runtime.d.ts +819 -0
  40. package/dist/server/runtime.js +1470 -0
  41. package/dist/server/server-context.d.ts +46 -0
  42. package/dist/server/server-context.js +1 -0
  43. package/dist/server/store.d.ts +424 -0
  44. package/dist/server/store.js +1121 -0
  45. package/dist/server/subagent-runs.d.ts +142 -0
  46. package/dist/server/subagent-runs.js +315 -0
  47. package/dist/server/subagents.d.ts +194 -0
  48. package/dist/server/subagents.js +542 -0
  49. package/dist/server/task-tool.d.ts +196 -0
  50. package/dist/server/task-tool.js +285 -0
  51. package/dist/server/tool-calls.d.ts +62 -0
  52. package/dist/server/tool-calls.js +141 -0
  53. package/dist/server/types.d.ts +920 -0
  54. package/dist/server/types.js +11 -0
  55. package/dist/server/upload.d.ts +37 -0
  56. package/dist/server/upload.js +169 -0
  57. package/dist/server/ws-server.d.ts +45 -0
  58. package/dist/server/ws-server.js +116 -0
  59. package/package.json +115 -4
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Turning one Pi tool call into something a human reads, and nothing more.
3
+ *
4
+ * WHY THIS IS ITS OWN MODULE. Two drain loops need exactly this derivation - the sub-agent supervisor
5
+ * (`subagents.ts`) and the PRIMARY agent's runtime (`runtime.ts`) - and `subagents.ts` already imports
6
+ * `runtime.ts` for `RpcChannel`, so the reverse import would be a cycle. One definition of "what does
7
+ * this call show" therefore has to live below both of them, or the two surfaces would drift: a `read`
8
+ * labelled by its path on a card and by its working directory on a call block is worse than either.
9
+ *
10
+ * The rule the whole module exists to enforce: DERIVED AND BOUNDED, NEVER COPIED. What Pi sends in
11
+ * `args` is an arbitrary object that may hold a file's contents, a multi-kilobyte patch or an entire
12
+ * shell script. What leaves here is short strings with a hard character cap, or a bare type word.
13
+ */
14
+ /**
15
+ * The longest label one tool call may contribute. See `SubagentToolCall.detail` and `ToolCallBlock.detail`
16
+ * for why the argument is summarised rather than carried: the cap is what makes the bound structural
17
+ * instead of aspirational, because nothing downstream can grow past it.
18
+ */
19
+ export const TOOL_DETAIL_CAP = 120;
20
+ /**
21
+ * How many parameters one call block may list.
22
+ *
23
+ * A bound on the COUNT as well as on each value, for the same reason `TOOL_DETAIL_CAP` exists: without
24
+ * it, a tool that Pi sends a dozen arguments to would put twelve rows - and twelve times the cap - into a
25
+ * field that is rewritten on every text delta of the message it belongs to. Six covers every call shape
26
+ * this project has seen (`read`'s path/offset/limit, `bash`'s command/description/timeout) and truncating
27
+ * past it is announced by the caller through the row count rather than silently.
28
+ */
29
+ export const TOOL_ARG_CAP = 6;
30
+ /** Argument fields that name a FILE, in the order the tools that read files tend to spell them. */
31
+ const PATH_KEYS = ["path", "file_path", "filePath", "target_file", "filename", "file"];
32
+ /** Argument fields that name a SEARCH, which is the thing a human wants to see on a `grep` row. */
33
+ const PATTERN_KEYS = ["pattern", "query", "regex", "search", "glob"];
34
+ /** Argument fields that name a COMMAND LINE. */
35
+ const COMMAND_KEYS = ["command", "cmd", "script"];
36
+ /**
37
+ * Which argument field names what a given tool was aimed at.
38
+ *
39
+ * A per-tool table rather than one generic scan, because the generic answer is wrong in a way a person
40
+ * would notice: scanning `path` before `command` would label a `bash` row with a working directory, and
41
+ * scanning `pattern` before `path` would label a `read` row with nothing at all. Unknown tools fall
42
+ * back to the union, which is imprecise by construction - and imprecise is acceptable here, because a
43
+ * missing label costs the reader one line and a WRONG one costs them trust in every other label.
44
+ */
45
+ const TARGET_KEYS = {
46
+ read: PATH_KEYS, write: PATH_KEYS, edit: PATH_KEYS, multiedit: PATH_KEYS, notebookread: PATH_KEYS, notebookedit: PATH_KEYS,
47
+ glob: PATTERN_KEYS, grep: PATTERN_KEYS, search: PATTERN_KEYS,
48
+ bash: COMMAND_KEYS, shell: COMMAND_KEYS, run: COMMAND_KEYS,
49
+ };
50
+ const FALLBACK_KEYS = [...COMMAND_KEYS, ...PATH_KEYS, ...PATTERN_KEYS];
51
+ /** One line, whitespace collapsed, hard-capped. The ONLY way a value becomes text in this module. */
52
+ const oneLine = (value) => {
53
+ const collapsed = value.replace(/\s+/g, " ").trim();
54
+ if (!collapsed)
55
+ return "";
56
+ return collapsed.length > TOOL_DETAIL_CAP ? `${collapsed.slice(0, TOOL_DETAIL_CAP - 1)}…` : collapsed;
57
+ };
58
+ /**
59
+ * The one line that tells a reader what a tool call was FOR: the file it opened, the pattern it searched
60
+ * for, the command it ran.
61
+ *
62
+ * Returns `undefined` rather than a placeholder when nothing is recognised, so a row omits the column
63
+ * instead of rendering a column of emptiness.
64
+ *
65
+ * Exported so the mapping can be asserted without spawning a child, which is the only way a table this
66
+ * shape can be regression-tested at all.
67
+ */
68
+ export function describeToolCall(name, args) {
69
+ if (args === null || typeof args !== "object" || Array.isArray(args))
70
+ return undefined;
71
+ const record = args;
72
+ for (const key of TARGET_KEYS[name.trim().toLowerCase()] ?? FALLBACK_KEYS) {
73
+ const value = record[key];
74
+ if (typeof value !== "string")
75
+ continue;
76
+ const line = oneLine(value);
77
+ if (line)
78
+ return line;
79
+ }
80
+ return undefined;
81
+ }
82
+ /**
83
+ * How one non-string argument value is NAMED without being read.
84
+ *
85
+ * THE MOST IMPORTANT LINE IN THIS FILE. An `edit` tool's arguments routinely carry the replacement text
86
+ * for a whole file, and a `bash` call's arguments can carry anything the model wrote. Rendering such a
87
+ * value - even truncated, even `JSON.stringify`d - would put file contents into a field that is
88
+ * persisted in `state.json` and broadcast to every browser, which is precisely the line
89
+ * `SubagentToolCall.detail` is documented as drawing. So a non-primitive contributes its KIND and
90
+ * nothing else: a reader learns that a patch was applied or an array was passed, and cannot learn what
91
+ * was in it.
92
+ */
93
+ const describeShape = (value) => {
94
+ if (value === null)
95
+ return "null";
96
+ if (Array.isArray(value))
97
+ return `(数组 ${value.length} 项)`;
98
+ switch (typeof value) {
99
+ case "number": return Number.isFinite(value) ? String(value) : undefined;
100
+ case "boolean": return String(value);
101
+ case "object": return "(对象)";
102
+ default: return undefined;
103
+ }
104
+ };
105
+ /**
106
+ * Every parameter of one call, as a bounded list of `key`/`value` pairs a block can show when expanded.
107
+ *
108
+ * THIS IS THE SAME LINE `describeToolCall` DRAWS, APPLIED PER KEY. `describeToolCall` answers "what was
109
+ * this aimed at" with one label; this answers "what was this given" with the whole bounded list, which is
110
+ * the difference between a row that says `bash` and a block that says which command, plus its timeout
111
+ * and description. Both are derived: a string is whitespace-collapsed and capped at `TOOL_DETAIL_CAP`, and
112
+ * anything that is not a string or a number or a boolean becomes a type word (see `describeShape`).
113
+ *
114
+ * Order is Pi's own key order rather than this module's table order, because once every key is listed the
115
+ * per-tool table has said everything it knows - and a reader scanning a list wants the order the caller
116
+ * wrote it in, not one this file invented.
117
+ *
118
+ * Capped at `TOOL_ARG_CAP` ENTRIES, and the cap is applied by taking the first N rather than by sampling
119
+ * across the object: a truncated tail is a prefix of the real argument list, so what is shown is never
120
+ * a selection that implies the omitted keys did not exist.
121
+ *
122
+ * Returns `undefined` when there is nothing readable at all, so a call with no usable arguments renders
123
+ * no parameter section rather than an empty one.
124
+ */
125
+ export function describeToolCallArgs(args) {
126
+ if (args === null || typeof args !== "object" || Array.isArray(args))
127
+ return undefined;
128
+ const listed = [];
129
+ // `Object.keys` rather than `for..in`: a key this file cannot render is skipped rather than emitted
130
+ // with an empty value, and an inherited key is not a parameter Pi sent.
131
+ for (const key of Object.keys(args)) {
132
+ if (listed.length >= TOOL_ARG_CAP)
133
+ break;
134
+ const raw = args[key];
135
+ const value = typeof raw === "string" ? oneLine(raw) : describeShape(raw);
136
+ if (value === undefined || value === "")
137
+ continue;
138
+ listed.push({ key, value });
139
+ }
140
+ return listed.length ? listed : undefined;
141
+ }