@evandu/super-pi 0.1.75 → 0.1.77

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 CHANGED
@@ -123,16 +123,25 @@ MIT
123
123
 
124
124
  ## Web tools and terminal
125
125
 
126
- ### Add an HTTP web tool
126
+ ### Add a sidebar tool
127
127
 
128
- 1. Start the tool's HTTP server, for example at `http://127.0.0.1:9000`.
129
- 2. Open the **Tools** tab in Super Pi's right sidebar — it shows only your curated tool icons. Click **工具设置** (Tool settings) at the bottom to open the setup popup.
130
- 3. Inside the popup enter the URL under **添加网址工具**, optionally name it, and add it. The same popup holds the preset tools and the customisation notes.
131
- 4. Select its icon to display the page in the popup, or choose **Open in new tab**.
132
- 5. Use **Copy development prompt** to copy a starter request for an agent building another standalone HTTP tool.
128
+ Open **Tools → 工具设置** and use **复制工具开发 Prompt** in the setup dialog. Ask the Super Pi agent to create the tool; its built-in `tool_register` submits the complete files and mounts the result globally, so the tool is available from every workspace without a separate server.
133
129
 
134
- Only HTTP and HTTPS pages are embedded. Pages that block framing or require browser permissions can be opened in a new tab instead.
130
+ For a tool that needs local computation, include a Python script in the registration and declare its parameter schema. The script receives one JSON object on stdin and must print one JSON object on stdout. Load the built-in browser SDK from the mounted page:
135
131
 
132
+ ```html
133
+ <script src="./super-pi-tool.js"></script>
134
+ <script>
135
+ async function calculate(params) {
136
+ const run = await SuperPiTool.run(params);
137
+ return await SuperPiTool.wait(run.id);
138
+ }
139
+ </script>
140
+ ```
141
+
142
+ `SuperPiTool.run`, `get`, `wait`, and `cancel` are relative, tool-scoped APIs. A page should not call `/api/exec`, guess a tool id, start an HTTP server, or send shell commands. The server enforces the declared schema, timeout, cancellation, and Python process isolation.
143
+
144
+ Legacy URL bookmarks remain available for opening external HTTP/HTTPS pages, but they are not the mechanism for registering or running a Super Pi tool.
136
145
  ### Enable the terminal
137
146
 
138
147
  The terminal is off by default. Set the environment variable before starting Super Pi, then restart it after changing the setting.
@@ -52,7 +52,7 @@ const Parameters = Type.Object({
52
52
  task_id: Type.Optional(Type.String({ description: "Resume a previous task when supported" })),
53
53
  });
54
54
  const QuestionParameters = Type.Object({ question: Type.String(), options: Type.Array(Type.String(), { minItems: 1 }), multiple: Type.Optional(Type.Boolean()), extraNote: Type.Optional(Type.Boolean()) });
55
- const ToolRegisterParameters = Type.Object({ slug: Type.String({ description: "Lowercase tool slug, e.g. json-viewer" }), name: Type.String({ description: "Human-readable tool name" }), description: Type.Optional(Type.String()), entrypoint: Type.String({ description: "Workspace-relative HTML entrypoint, normally tools/<slug>/index.html" }) });
55
+ const ToolRegisterParameters = Type.Object({ slug: Type.String({ description: "Lowercase global tool slug, e.g. json-viewer" }), name: Type.String({ description: "Human-readable tool name" }), description: Type.Optional(Type.String()), entrypoint: Type.Optional(Type.String({ description: "HTML entrypoint, normally index.html" })), files: Type.Array(Type.Object({ path: Type.String({ description: "Tool-relative file path" }), content: Type.String({ description: "Complete UTF-8 text content" }) }), { minItems: 1, maxItems: 32 }), script: Type.Optional(Type.Object({ path: Type.String({ description: "Optional tool-relative Python .py entrypoint" }), timeoutMs: Type.Optional(Type.Number()), parameters: Type.Optional(Type.Record(Type.String(), Type.Object({ type: Type.Union([Type.Literal("string"), Type.Literal("number"), Type.Literal("boolean"), Type.Literal("object"), Type.Literal("array")]), required: Type.Optional(Type.Boolean()), enum: Type.Optional(Type.Array(Type.Union([Type.String(), Type.Number(), Type.Boolean()]))) }))) })) });
56
56
 
57
57
  /**
58
58
  * The `todowrite` parameter schema, OpenCode's `tool/todo.ts:6-8` in the TypeBox dialect this adapter
@@ -145,16 +145,18 @@ const extension = (pi: ExtensionApi): void => {
145
145
  // cancellation. The text says what was asked and what was chosen, in words.
146
146
  return text(JSON.stringify({ answers: (payload.answers ?? []).map((answer) => ({ question: p.question, selected: answer.selected, ...(answer.note ? { note: answer.note } : {}) })), ...(payload.summary ? { summary: payload.summary } : {}) }));
147
147
  } });
148
- pi.registerTool({ name: "tool_register", label: "Register Tool", description: "Register a workspace tool in Super Pi's right sidebar. Use this when the user asks to create or add a right-sidebar tool. First create the HTML/JS/CSS files under the workspace, then call this tool; do not start another HTTP server.", promptSnippet: "register a newly created right-sidebar tool with Super Pi", parameters: ToolRegisterParameters, execute: async (_id, raw, _signal, _update, context): Promise<TaskToolResult> => {
148
+ pi.registerTool({ name: "tool_register", label: "Register Tool", description: "Register a global Super Pi sidebar tool. Use this when the user asks to create or add a right-sidebar tool. Send complete HTML/JS/CSS files directly; they are stored by Super Pi and work in every workspace. An optional registered Python script receives validated JSON on stdin and must print one JSON object to stdout. In the HTML, load ./super-pi-tool.js and use SuperPiTool.run/get/wait/cancel for the tool's own Python jobs; do not call /api/exec, guess a tool id, or start another HTTP server.", promptSnippet: "register a newly created global right-sidebar tool with Super Pi", parameters: ToolRegisterParameters, execute: async (_id, raw, _signal, _update, _context): Promise<TaskToolResult> => {
149
149
  const endpoint = process.env.SUPER_PI_TOOLS_ENDPOINT;
150
150
  const text = (body: string, isError?: boolean): TaskToolResult => ({ content: [{ type: "text", text: body }], details: undefined, ...(isError ? { isError: true } : {}) });
151
151
  if (!endpoint) return text("The Super Pi tool registry is not available in this run.", true);
152
- const p = raw as { slug: string; name: string; description?: string; entrypoint: string };
152
+ const p = raw as { slug: string; name: string; description?: string; entrypoint?: string; files: { path: string; content: string }[]; script?: unknown };
153
153
  try {
154
- const response = await fetch(endpoint, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ ...p, workspacePath: context.cwd }) });
154
+ const capability = process.env.SUPER_PI_TOOLS_CAPABILITY;
155
+ const conversationId = process.env.SUPER_PI_TASK_CONVERSATION;
156
+ const response = await fetch(endpoint, { method: "POST", headers: { "content-type": "application/json", ...(capability ? { "x-super-pi-capability": capability } : {}) }, body: JSON.stringify({ ...p, conversationId, capability }) });
155
157
  const payload = await response.json() as { id?: string; error?: string };
156
158
  if (!response.ok || payload.error) return text(payload.error ?? `Tool registration failed (HTTP ${response.status}).`, true);
157
- return text(JSON.stringify({ registered: true, id: payload.id, url: `/tools/${payload.id}/` }));
159
+ return text(JSON.stringify({ registered: true, id: payload.id, url: `/tools/${payload.id}/`, runtime: "Load ./super-pi-tool.js; use SuperPiTool.run(params), SuperPiTool.get(runId), SuperPiTool.wait(runId), and SuperPiTool.cancel(runId)." }));
158
160
  } catch (error) { return text(`Tool registration could not reach Super Pi: ${error instanceof Error ? error.message : "unknown error"}`, true); }
159
161
  } });
160
162
  // Read ONCE at load, not per call: the environment cannot change under a running Pi, and `prepareLoadout`