@evandu/super-pi 0.1.72 → 0.1.73
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.
|
@@ -52,6 +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
56
|
|
|
56
57
|
/**
|
|
57
58
|
* The `todowrite` parameter schema, OpenCode's `tool/todo.ts:6-8` in the TypeBox dialect this adapter
|
|
@@ -144,6 +145,18 @@ const extension = (pi: ExtensionApi): void => {
|
|
|
144
145
|
// cancellation. The text says what was asked and what was chosen, in words.
|
|
145
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 } : {}) }));
|
|
146
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> => {
|
|
149
|
+
const endpoint = process.env.SUPER_PI_TOOLS_ENDPOINT;
|
|
150
|
+
const text = (body: string, isError?: boolean): TaskToolResult => ({ content: [{ type: "text", text: body }], details: undefined, ...(isError ? { isError: true } : {}) });
|
|
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 };
|
|
153
|
+
try {
|
|
154
|
+
const response = await fetch(endpoint, { method: "POST", headers: { "content-type": "application/json" }, body: JSON.stringify({ ...p, workspacePath: context.cwd }) });
|
|
155
|
+
const payload = await response.json() as { id?: string; error?: string };
|
|
156
|
+
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}/` }));
|
|
158
|
+
} catch (error) { return text(`Tool registration could not reach Super Pi: ${error instanceof Error ? error.message : "unknown error"}`, true); }
|
|
159
|
+
});
|
|
147
160
|
// Read ONCE at load, not per call: the environment cannot change under a running Pi, and `prepareLoadout`
|
|
148
161
|
// is synchronous - it cannot await a fetch for a roster - so the roster has to already be here.
|
|
149
162
|
const config = readTaskConfig(process.env);
|
|
@@ -171,9 +171,9 @@ export function createHttpServer(options) {
|
|
|
171
171
|
}
|
|
172
172
|
}
|
|
173
173
|
const body = JSON.parse(raw);
|
|
174
|
-
const workspace = store.snapshot().workspaces.find((x) => x.id === body.workspaceId);
|
|
174
|
+
const workspace = store.snapshot().workspaces.find((x) => x.id === body.workspaceId || (body.workspacePath && resolve(x.path) === resolve(body.workspacePath)));
|
|
175
175
|
if (!workspace || !body.slug || !body.name || !body.entrypoint) {
|
|
176
|
-
json(400, { error: "workspaceId, slug, name and entrypoint are required" });
|
|
176
|
+
json(400, { error: "workspaceId (or workspacePath), slug, name and entrypoint are required" });
|
|
177
177
|
return;
|
|
178
178
|
}
|
|
179
179
|
const tool = await toolRegistry.register({ workspaceId: workspace.id, slug: body.slug, name: body.name, description: body.description, entrypoint: body.entrypoint }, workspace.path);
|
package/dist/server/index.js
CHANGED
|
@@ -47,6 +47,7 @@ const execEndpoint = `http://${internalHost}:${port}/api/exec`;
|
|
|
47
47
|
const todoEndpoint = `http://${internalHost}:${port}/api/todos`;
|
|
48
48
|
const workflowEndpoint = `http://${internalHost}:${port}/api/workflow/run`;
|
|
49
49
|
const questionEndpoint = `http://${internalHost}:${port}/api/question`;
|
|
50
|
+
const toolsEndpoint = `http://${internalHost}:${port}/api/tools`;
|
|
50
51
|
// ------------------------------------------------------------- Core singletons
|
|
51
52
|
const store = await openStateStore(dataDir, process.env.SUPER_PI_PERSISTENCE ?? "sqlite");
|
|
52
53
|
const toolRegistry = new ToolRegistry(dataDir);
|
|
@@ -66,7 +67,7 @@ const paths = {
|
|
|
66
67
|
};
|
|
67
68
|
const runtime = process.env.SUPER_PI_RUNTIME === "welcome"
|
|
68
69
|
? new WelcomeRuntime()
|
|
69
|
-
: new PiRpcRuntime(join(dataDir, "pi-sessions"), undefined, { dir: initialAgentDirs, promptDir: agentPromptDir }, { endpoint: taskEndpoint, execEndpoint, todoEndpoint, workflowEndpoint, questionEndpoint, uploadsDir });
|
|
70
|
+
: new PiRpcRuntime(join(dataDir, "pi-sessions"), undefined, { dir: initialAgentDirs, promptDir: agentPromptDir }, { endpoint: taskEndpoint, execEndpoint, todoEndpoint, workflowEndpoint, questionEndpoint, toolsEndpoint, uploadsDir });
|
|
70
71
|
const broadcaster = new WsBroadcaster(() => store.snapshot());
|
|
71
72
|
const memory = new ActiveMemory(join(dataDir, "memories"), store, runtime);
|
|
72
73
|
process.env.SUPER_PI_MEMORY_ENDPOINT = `http://${internalHost}:${port}/api/memory/tool`;
|
package/dist/server/runtime.d.ts
CHANGED
package/dist/server/runtime.js
CHANGED
|
@@ -388,6 +388,7 @@ export class PiRpcRuntime {
|
|
|
388
388
|
[TODO_ENDPOINT_ENV]: this.options.todoEndpoint ?? "",
|
|
389
389
|
[WORKFLOW_ENDPOINT_ENV]: this.options.workflowEndpoint ?? "",
|
|
390
390
|
SUPER_PI_QUESTION_ENDPOINT: this.options.questionEndpoint ?? "",
|
|
391
|
+
SUPER_PI_TOOLS_ENDPOINT: this.options.toolsEndpoint ?? "",
|
|
391
392
|
// MINTED HERE, AT SPAWN, rather than read from anywhere: this is the only moment the value is
|
|
392
393
|
// decided, so it cannot change underneath a running child. `SubagentSupervisor` never calls this
|
|
393
394
|
// function, so no sub-agent process is ever handed a capability - which is what makes a sub-agent
|
|
@@ -438,7 +439,7 @@ export class PiRpcRuntime {
|
|
|
438
439
|
// other. They also share the extension's existence - `extensionArgs` is non-empty exactly when
|
|
439
440
|
// `index.ts` is on disk and an endpoint was configured - so there is no case where one is mounted and
|
|
440
441
|
// the other is not.
|
|
441
|
-
const agentArgs = memoryReview ? ["--no-extensions", "--no-skills", "--no-mcp", "--no-context-files", "--no-prompt-templates", "--tools", "memory,skill_manage,session_search"] : await agentSpawnArgs(this.agents.promptDir, agent, { extraAllowedTools: [...(extensionArgs.length ? [TASK_TOOL_NAME, TODO_TOOL_NAME, WORKFLOW_TOOL_NAME, RUN_ASYNC_TOOL_NAME, "question"] : []), ...(memoryEnabled ? ["memory", "skill_manage", "session_search"] : [])] });
|
|
442
|
+
const agentArgs = memoryReview ? ["--no-extensions", "--no-skills", "--no-mcp", "--no-context-files", "--no-prompt-templates", "--tools", "memory,skill_manage,session_search"] : await agentSpawnArgs(this.agents.promptDir, agent, { extraAllowedTools: [...(extensionArgs.length ? [TASK_TOOL_NAME, TODO_TOOL_NAME, WORKFLOW_TOOL_NAME, RUN_ASYNC_TOOL_NAME, "question", "tool_register"] : []), ...(memoryEnabled ? ["memory", "skill_manage", "session_search"] : [])] });
|
|
442
443
|
// Refused here, with the reason, rather than handed to the spawn: an ENOENT from `spawn` reads as
|
|
443
444
|
// "the app is broken" and hides the one fact that matters, which is where it looked for Pi.
|
|
444
445
|
if (!this.pi.found)
|