pilotswarm 0.4.1 → 0.5.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.
- package/mcp/README.md +88 -4
- package/mcp/dist/src/context.d.ts +36 -6
- package/mcp/dist/src/context.d.ts.map +1 -1
- package/mcp/dist/src/context.js +102 -8
- package/mcp/dist/src/context.js.map +1 -1
- package/mcp/dist/src/resources/artifacts.d.ts +5 -0
- package/mcp/dist/src/resources/artifacts.d.ts.map +1 -0
- package/mcp/dist/src/resources/artifacts.js +39 -0
- package/mcp/dist/src/resources/artifacts.js.map +1 -0
- package/mcp/dist/src/resources/capabilities.d.ts +4 -0
- package/mcp/dist/src/resources/capabilities.d.ts.map +1 -0
- package/mcp/dist/src/resources/capabilities.js +17 -0
- package/mcp/dist/src/resources/capabilities.js.map +1 -0
- package/mcp/dist/src/resources/graph.d.ts +5 -0
- package/mcp/dist/src/resources/graph.d.ts.map +1 -0
- package/mcp/dist/src/resources/graph.js +45 -0
- package/mcp/dist/src/resources/graph.js.map +1 -0
- package/mcp/dist/src/server.d.ts.map +1 -1
- package/mcp/dist/src/server.js +61 -2
- package/mcp/dist/src/server.js.map +1 -1
- package/mcp/dist/src/tools/agents.d.ts.map +1 -1
- package/mcp/dist/src/tools/agents.js +3 -2
- package/mcp/dist/src/tools/agents.js.map +1 -1
- package/mcp/dist/src/tools/artifacts.d.ts +12 -0
- package/mcp/dist/src/tools/artifacts.d.ts.map +1 -0
- package/mcp/dist/src/tools/artifacts.js +92 -0
- package/mcp/dist/src/tools/artifacts.js.map +1 -0
- package/mcp/dist/src/tools/capabilities.d.ts +27 -0
- package/mcp/dist/src/tools/capabilities.d.ts.map +1 -0
- package/mcp/dist/src/tools/capabilities.js +69 -0
- package/mcp/dist/src/tools/capabilities.js.map +1 -0
- package/mcp/dist/src/tools/debug.d.ts +4 -0
- package/mcp/dist/src/tools/debug.d.ts.map +1 -0
- package/mcp/dist/src/tools/debug.js +94 -0
- package/mcp/dist/src/tools/debug.js.map +1 -0
- package/mcp/dist/src/tools/facts-enhanced.d.ts +13 -0
- package/mcp/dist/src/tools/facts-enhanced.d.ts.map +1 -0
- package/mcp/dist/src/tools/facts-enhanced.js +80 -0
- package/mcp/dist/src/tools/facts-enhanced.js.map +1 -0
- package/mcp/dist/src/tools/graph.d.ts +12 -0
- package/mcp/dist/src/tools/graph.d.ts.map +1 -0
- package/mcp/dist/src/tools/graph.js +237 -0
- package/mcp/dist/src/tools/graph.js.map +1 -0
- package/mcp/dist/src/tools/groups.d.ts +10 -0
- package/mcp/dist/src/tools/groups.d.ts.map +1 -0
- package/mcp/dist/src/tools/groups.js +107 -0
- package/mcp/dist/src/tools/groups.js.map +1 -0
- package/mcp/dist/src/tools/models.d.ts.map +1 -1
- package/mcp/dist/src/tools/models.js +16 -4
- package/mcp/dist/src/tools/models.js.map +1 -1
- package/mcp/dist/src/tools/observability.d.ts +13 -0
- package/mcp/dist/src/tools/observability.d.ts.map +1 -0
- package/mcp/dist/src/tools/observability.js +174 -0
- package/mcp/dist/src/tools/observability.js.map +1 -0
- package/mcp/dist/src/tools/sessions.d.ts.map +1 -1
- package/mcp/dist/src/tools/sessions.js +120 -94
- package/mcp/dist/src/tools/sessions.js.map +1 -1
- package/mcp/dist/src/tools/system.d.ts +14 -0
- package/mcp/dist/src/tools/system.d.ts.map +1 -0
- package/mcp/dist/src/tools/system.js +110 -0
- package/mcp/dist/src/tools/system.js.map +1 -0
- package/mcp/dist/src/tools/turn-control.d.ts +13 -0
- package/mcp/dist/src/tools/turn-control.d.ts.map +1 -0
- package/mcp/dist/src/tools/turn-control.js +98 -0
- package/mcp/dist/src/tools/turn-control.js.map +1 -0
- package/mcp/dist/src/util/respond.d.ts +21 -0
- package/mcp/dist/src/util/respond.d.ts.map +1 -0
- package/mcp/dist/src/util/respond.js +42 -0
- package/mcp/dist/src/util/respond.js.map +1 -0
- package/package.json +5 -4
- package/tui/bin/tui.js +0 -3
- package/tui/src/node-sdk-transport.js +24 -0
- package/ui/core/src/selectors.js +23 -2
- package/ui/react/src/web-app.js +51 -6
- package/web/dist/assets/{index-xJ8IzIZY.js → index-B8ge3rzb.js} +4 -4
- package/web/dist/assets/index-DXRIxmIv.css +1 -0
- package/web/dist/assets/{pilotswarm-D9pEmenA.js → pilotswarm-Dt1qY6hD.js} +52 -52
- package/web/dist/assets/{react-CEPDSRB6.js → react-IRUjK5Iz.js} +1 -1
- package/web/dist/index.html +4 -4
- package/web/runtime.js +30 -0
- package/web/dist/assets/index-DmGOcKR-.css +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../../../src/tools/system.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGnD;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,aAAa,QA8GxE"}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { jsonResult, errorResult, withToolErrors } from "../util/respond.js";
|
|
3
|
+
/**
|
|
4
|
+
* Ops preflight & system tools (proposal G7).
|
|
5
|
+
*
|
|
6
|
+
* get_system_status workers / log config / session policy / creatable agents
|
|
7
|
+
* restart_system_session bounce sweeper, resourcemgr, ... [admin]
|
|
8
|
+
* facts_admin purge tombstoned facts, prune deleted summaries [admin]
|
|
9
|
+
*
|
|
10
|
+
* get_system_status turns the `no_worker_claimed` create_session failure into
|
|
11
|
+
* a preflight check: workers === 0 means don't bother creating sessions yet.
|
|
12
|
+
*/
|
|
13
|
+
export function registerSystemTools(server, ctx) {
|
|
14
|
+
// Web-mode only: worker count / log config / policy / agents are Web API
|
|
15
|
+
// operations with no direct-mode equivalent.
|
|
16
|
+
if (ctx.api) {
|
|
17
|
+
server.registerTool("get_system_status", {
|
|
18
|
+
title: "Get System Status",
|
|
19
|
+
description: "Deployment status: embedded-worker count (workers running inside the portal process — dedicated "
|
|
20
|
+
+ "worker pods report 0 here and that is normal), session-creation policy, creatable agents, and "
|
|
21
|
+
+ "log-tail availability. include narrows the fetch (default all).",
|
|
22
|
+
inputSchema: {
|
|
23
|
+
include: z
|
|
24
|
+
.array(z.enum(["workers", "policy", "agents", "log_config"]))
|
|
25
|
+
.optional()
|
|
26
|
+
.describe("Axes to fetch (default all)"),
|
|
27
|
+
},
|
|
28
|
+
}, withToolErrors(async ({ include }) => {
|
|
29
|
+
const wants = new Set(include ?? ["workers", "policy", "agents", "log_config"]);
|
|
30
|
+
const result = {};
|
|
31
|
+
const errors = {};
|
|
32
|
+
const grab = async (key, fn) => {
|
|
33
|
+
try {
|
|
34
|
+
result[key] = await fn();
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
errors[key] = err instanceof Error ? err.message : String(err);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
if (wants.has("workers")) {
|
|
41
|
+
await grab("workers", async () => {
|
|
42
|
+
const w = await ctx.api.call("getWorkerCount");
|
|
43
|
+
const count = typeof w === "number" ? w : (w?.count ?? null);
|
|
44
|
+
return {
|
|
45
|
+
embedded_count: count,
|
|
46
|
+
note: "Counts workers embedded in the portal process only. Deployments with dedicated worker pods report 0 here — use worker_claimed on create_session responses for per-run liveness.",
|
|
47
|
+
};
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
if (wants.has("policy"))
|
|
51
|
+
await grab("policy", () => ctx.api.call("getSessionCreationPolicy"));
|
|
52
|
+
if (wants.has("agents"))
|
|
53
|
+
await grab("agents", () => ctx.api.call("listCreatableAgents"));
|
|
54
|
+
if (wants.has("log_config"))
|
|
55
|
+
await grab("log_config", () => ctx.api.call("getLogConfig"));
|
|
56
|
+
if (Object.keys(errors).length > 0)
|
|
57
|
+
result.errors = errors;
|
|
58
|
+
return jsonResult(result);
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
61
|
+
// restart_system_session — [admin] disruptive lifecycle operation on the
|
|
62
|
+
// deployment's system agents (sweeper, resourcemgr, ...).
|
|
63
|
+
if (ctx.admin) {
|
|
64
|
+
server.registerTool("restart_system_session", {
|
|
65
|
+
title: "Restart System Session",
|
|
66
|
+
description: "Restart a system session (sweeper, resourcemgr, ...) by agent id or session id. disposition "
|
|
67
|
+
+ "controls what happens to the old session: complete (graceful), terminate, or hard_delete. [admin]",
|
|
68
|
+
inputSchema: {
|
|
69
|
+
agent_or_session_id: z.string().min(1).describe("System agent id (e.g. 'sweeper') or its session id"),
|
|
70
|
+
disposition: z.enum(["complete", "terminate", "hard_delete"]).describe("How to dispose of the old session"),
|
|
71
|
+
reason: z.string().optional().describe("Reason recorded on the restart"),
|
|
72
|
+
},
|
|
73
|
+
}, withToolErrors(async ({ agent_or_session_id, disposition, reason }) => {
|
|
74
|
+
const result = await ctx.mgmt.restartSystemSession(agent_or_session_id, { disposition, reason });
|
|
75
|
+
// The system-agent set may have changed identity; refresh the
|
|
76
|
+
// dynamic resource registrations' source of truth.
|
|
77
|
+
await ctx.refreshSystemAgentIds();
|
|
78
|
+
return jsonResult({ restarted: true, ...(result && typeof result === "object" ? result : {}) });
|
|
79
|
+
}));
|
|
80
|
+
// facts_admin — destructive housekeeping, action-dispatched.
|
|
81
|
+
server.registerTool("facts_admin", {
|
|
82
|
+
title: "Facts Admin",
|
|
83
|
+
description: "Administrative facts housekeeping. action: 'purge' force-purges soft-deleted (tombstoned) facts; "
|
|
84
|
+
+ "'prune_summaries' prunes summaries of deleted sessions older than a cutoff. Both DESTRUCTIVE. [admin]",
|
|
85
|
+
inputSchema: {
|
|
86
|
+
action: z.enum(["purge", "prune_summaries"]).describe("The housekeeping operation"),
|
|
87
|
+
cutoff: z.string().describe("ISO timestamp — purge/prune anything soft-deleted before this"),
|
|
88
|
+
key_prefix: z.string().optional().describe("purge: restrict to keys under this prefix"),
|
|
89
|
+
only_unreconciled: z.boolean().optional().describe("purge: only facts whose graph evidence is not yet reconciled"),
|
|
90
|
+
limit: z.number().int().positive().optional().describe("purge: max rows per call"),
|
|
91
|
+
},
|
|
92
|
+
}, withToolErrors(async ({ action, cutoff, key_prefix, only_unreconciled, limit }) => {
|
|
93
|
+
const cutoffDate = new Date(cutoff);
|
|
94
|
+
if (Number.isNaN(cutoffDate.getTime()))
|
|
95
|
+
return errorResult("cutoff must be a valid ISO timestamp");
|
|
96
|
+
if (action === "purge") {
|
|
97
|
+
const purged = await ctx.facts.forcePurgeFacts({
|
|
98
|
+
cutoff: cutoffDate,
|
|
99
|
+
keyPrefix: key_prefix,
|
|
100
|
+
onlyUnreconciled: only_unreconciled,
|
|
101
|
+
limit,
|
|
102
|
+
});
|
|
103
|
+
return jsonResult({ purged });
|
|
104
|
+
}
|
|
105
|
+
const pruned = await ctx.mgmt.pruneDeletedSummaries(cutoffDate);
|
|
106
|
+
return jsonResult({ pruned });
|
|
107
|
+
}));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=system.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system.js","sourceRoot":"","sources":["../../../src/tools/system.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import type { ServerContext } from "../context.js";
|
|
3
|
+
/**
|
|
4
|
+
* Turn- and queue-level session control (proposal G3) — finer levers than
|
|
5
|
+
* abort_session's whole-session cancel:
|
|
6
|
+
*
|
|
7
|
+
* stop_turn abort the in-flight turn, keep the session
|
|
8
|
+
* complete_session mark done (distinct from cancelled)
|
|
9
|
+
* cancel_pending_messages drop queued messages by client message id
|
|
10
|
+
* send_session_event inject a custom event into the session
|
|
11
|
+
*/
|
|
12
|
+
export declare function registerTurnControlTools(server: McpServer, ctx: ServerContext): void;
|
|
13
|
+
//# sourceMappingURL=turn-control.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"turn-control.d.ts","sourceRoot":"","sources":["../../../src/tools/turn-control.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAGnD;;;;;;;;GAQG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,EAAE,aAAa,QA+G7E"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { jsonResult, errorResult, withToolErrors } from "../util/respond.js";
|
|
3
|
+
/**
|
|
4
|
+
* Turn- and queue-level session control (proposal G3) — finer levers than
|
|
5
|
+
* abort_session's whole-session cancel:
|
|
6
|
+
*
|
|
7
|
+
* stop_turn abort the in-flight turn, keep the session
|
|
8
|
+
* complete_session mark done (distinct from cancelled)
|
|
9
|
+
* cancel_pending_messages drop queued messages by client message id
|
|
10
|
+
* send_session_event inject a custom event into the session
|
|
11
|
+
*/
|
|
12
|
+
export function registerTurnControlTools(server, ctx) {
|
|
13
|
+
async function requireSession(session_id) {
|
|
14
|
+
const existing = await ctx.mgmt.getSession(session_id);
|
|
15
|
+
return existing ?? null;
|
|
16
|
+
}
|
|
17
|
+
server.registerTool("stop_turn", {
|
|
18
|
+
title: "Stop Turn",
|
|
19
|
+
description: "Abort the in-flight turn of a running PilotSwarm session without cancelling the session — it stays "
|
|
20
|
+
+ "alive and accepts new messages. Use abort_session only when the whole session should end.",
|
|
21
|
+
inputSchema: {
|
|
22
|
+
session_id: z.string().uuid({ message: "session_id must be a valid UUID" }).describe("The session whose current turn to stop"),
|
|
23
|
+
reason: z.string().optional().describe("Optional reason, surfaced to the session"),
|
|
24
|
+
timeout_ms: z.number().int().positive().optional().describe("Max time to wait for the turn to stop"),
|
|
25
|
+
},
|
|
26
|
+
}, withToolErrors(async ({ session_id, reason, timeout_ms }) => {
|
|
27
|
+
if (!(await requireSession(session_id))) {
|
|
28
|
+
return errorResult("session not found", { session_id });
|
|
29
|
+
}
|
|
30
|
+
const result = await ctx.mgmt.stopSessionTurn(session_id, { reason, timeoutMs: timeout_ms });
|
|
31
|
+
return jsonResult({ stopped: true, ...(result && typeof result === "object" ? result : {}) });
|
|
32
|
+
}));
|
|
33
|
+
server.registerTool("complete_session", {
|
|
34
|
+
title: "Complete Session",
|
|
35
|
+
description: "Mark a PilotSwarm session completed (a successful terminal state — distinct from abort_session's "
|
|
36
|
+
+ "cancelled). Use when the session's work is done and it should stop cleanly.",
|
|
37
|
+
inputSchema: {
|
|
38
|
+
session_id: z.string().uuid({ message: "session_id must be a valid UUID" }).describe("The session to complete"),
|
|
39
|
+
reason: z.string().optional().describe("Optional completion reason"),
|
|
40
|
+
},
|
|
41
|
+
}, withToolErrors(async ({ session_id, reason }) => {
|
|
42
|
+
if (!(await requireSession(session_id))) {
|
|
43
|
+
return errorResult("session not found", { session_id });
|
|
44
|
+
}
|
|
45
|
+
await ctx.mgmt.completeSession(session_id, reason);
|
|
46
|
+
return jsonResult({ completed: true });
|
|
47
|
+
}));
|
|
48
|
+
server.registerTool("cancel_pending_messages", {
|
|
49
|
+
title: "Cancel Pending Messages",
|
|
50
|
+
description: "Cancel queued (not yet processed) messages in a session, identified by the client_message_ids they "
|
|
51
|
+
+ "were sent with. Pair with send_message's client_message_ids parameter.",
|
|
52
|
+
inputSchema: {
|
|
53
|
+
session_id: z.string().uuid({ message: "session_id must be a valid UUID" }).describe("The session holding the queued messages"),
|
|
54
|
+
client_message_ids: z.array(z.string().min(1)).min(1).describe("Client message ids to cancel"),
|
|
55
|
+
},
|
|
56
|
+
}, withToolErrors(async ({ session_id, client_message_ids }) => {
|
|
57
|
+
if (!(await requireSession(session_id))) {
|
|
58
|
+
return errorResult("session not found", { session_id });
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
await ctx.mgmt.cancelPendingMessage(session_id, client_message_ids);
|
|
62
|
+
}
|
|
63
|
+
catch (err) {
|
|
64
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
65
|
+
if (/not started|NotFound/i.test(msg)) {
|
|
66
|
+
// Pending-message cancellation rides the orchestration
|
|
67
|
+
// command channel, which only exists once the session's
|
|
68
|
+
// orchestration has started. Explain, don't confuse.
|
|
69
|
+
return errorResult("cannot cancel yet: this session's orchestration has not started, so the command channel "
|
|
70
|
+
+ "is not live. Monitor the session (get_session_detail include: ['status']) and retry "
|
|
71
|
+
+ "once orchestration_status is no longer NotFound.", { session_id, client_message_ids });
|
|
72
|
+
}
|
|
73
|
+
throw err;
|
|
74
|
+
}
|
|
75
|
+
return jsonResult({ cancelled: true, client_message_ids });
|
|
76
|
+
}));
|
|
77
|
+
// sendSessionEvent is a Web API session operation; in direct mode there is
|
|
78
|
+
// no equivalent seam (events are worker-internal), so web-only.
|
|
79
|
+
if (ctx.api) {
|
|
80
|
+
server.registerTool("send_session_event", {
|
|
81
|
+
title: "Send Session Event",
|
|
82
|
+
description: "Inject a custom named event into a PilotSwarm session (e.g. a webhook-style signal an agent "
|
|
83
|
+
+ "is waiting on). Not a chat message — use send_message for prompts.",
|
|
84
|
+
inputSchema: {
|
|
85
|
+
session_id: z.string().uuid({ message: "session_id must be a valid UUID" }).describe("The target session"),
|
|
86
|
+
event_name: z.string().min(1).describe("Event name the session listens for"),
|
|
87
|
+
data: z.record(z.string(), z.any()).optional().describe("Event payload"),
|
|
88
|
+
},
|
|
89
|
+
}, withToolErrors(async ({ session_id, event_name, data }) => {
|
|
90
|
+
if (!(await requireSession(session_id))) {
|
|
91
|
+
return errorResult("session not found", { session_id });
|
|
92
|
+
}
|
|
93
|
+
await ctx.api.call("sendSessionEvent", { sessionId: session_id, eventName: event_name, data });
|
|
94
|
+
return jsonResult({ sent: true, event_name });
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=turn-control.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"turn-control.js","sourceRoot":"","sources":["../../../src/tools/turn-control.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Shared MCP tool-response helpers — same content shape the existing tool
|
|
2
|
+
* files emit inline; new tool modules use these to cut boilerplate. */
|
|
3
|
+
export interface ToolResult {
|
|
4
|
+
content: Array<{
|
|
5
|
+
type: "text";
|
|
6
|
+
text: string;
|
|
7
|
+
}>;
|
|
8
|
+
isError?: boolean;
|
|
9
|
+
[key: string]: unknown;
|
|
10
|
+
}
|
|
11
|
+
export declare function jsonResult(payload: unknown): ToolResult;
|
|
12
|
+
export declare function errorResult(message: string, extra?: Record<string, unknown>): ToolResult;
|
|
13
|
+
/**
|
|
14
|
+
* Map a thrown error to a tool error result. Recognizes the Web API's 403
|
|
15
|
+
* (admin-gated operation hit without the admin role) and shapes it into
|
|
16
|
+
* actionable text instead of a bare status line.
|
|
17
|
+
*/
|
|
18
|
+
export declare function errorToResult(err: unknown): ToolResult;
|
|
19
|
+
/** Wrap a tool handler with the standard try/catch → errorToResult mapping. */
|
|
20
|
+
export declare function withToolErrors<A extends unknown[]>(fn: (...args: A) => Promise<ToolResult>): (...args: A) => Promise<ToolResult>;
|
|
21
|
+
//# sourceMappingURL=respond.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"respond.d.ts","sourceRoot":"","sources":["../../../src/util/respond.ts"],"names":[],"mappings":"AAAA;uEACuE;AAEvE,MAAM,WAAW,UAAU;IACvB,OAAO,EAAE,KAAK,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,OAAO,GAAG,UAAU,CAIvD;AAED,wBAAgB,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,UAAU,CAQxF;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,UAAU,CAWtD;AAED,+EAA+E;AAC/E,wBAAgB,cAAc,CAAC,CAAC,SAAS,OAAO,EAAE,EAC9C,EAAE,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,UAAU,CAAC,GACxC,CAAC,GAAG,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,UAAU,CAAC,CAQrC"}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/** Shared MCP tool-response helpers — same content shape the existing tool
|
|
2
|
+
* files emit inline; new tool modules use these to cut boilerplate. */
|
|
3
|
+
export function jsonResult(payload) {
|
|
4
|
+
return {
|
|
5
|
+
content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
|
|
6
|
+
};
|
|
7
|
+
}
|
|
8
|
+
export function errorResult(message, extra) {
|
|
9
|
+
const text = extra
|
|
10
|
+
? JSON.stringify({ error: message, ...extra })
|
|
11
|
+
: `Error: ${message}`;
|
|
12
|
+
return {
|
|
13
|
+
content: [{ type: "text", text }],
|
|
14
|
+
isError: true,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Map a thrown error to a tool error result. Recognizes the Web API's 403
|
|
19
|
+
* (admin-gated operation hit without the admin role) and shapes it into
|
|
20
|
+
* actionable text instead of a bare status line.
|
|
21
|
+
*/
|
|
22
|
+
export function errorToResult(err) {
|
|
23
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
24
|
+
const status = err?.status ?? err?.statusCode;
|
|
25
|
+
if (status === 403 || /\b403\b|forbidden/i.test(message)) {
|
|
26
|
+
return errorResult("forbidden: this operation requires the deployment's admin role. "
|
|
27
|
+
+ "The MCP server's credential (PILOTSWARM_API_TOKEN or cached login) does not carry it.", { status: 403 });
|
|
28
|
+
}
|
|
29
|
+
return errorResult(message);
|
|
30
|
+
}
|
|
31
|
+
/** Wrap a tool handler with the standard try/catch → errorToResult mapping. */
|
|
32
|
+
export function withToolErrors(fn) {
|
|
33
|
+
return async (...args) => {
|
|
34
|
+
try {
|
|
35
|
+
return await fn(...args);
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
return errorToResult(err);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=respond.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"respond.js","sourceRoot":"","sources":["../../../src/util/respond.ts"],"names":[],"mappings":"AAAA;uEACuE;AAQvE,MAAM,UAAU,UAAU,CAAC,OAAgB;IACvC,OAAO;QACH,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;KAC/E,CAAC;AACN,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAAe,EAAE,KAA+B;IACxE,MAAM,IAAI,GAAG,KAAK;QACd,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,KAAK,EAAE,CAAC;QAC9C,CAAC,CAAC,UAAU,OAAO,EAAE,CAAC;IAC1B,OAAO;QACH,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,CAAC;QAC1C,OAAO,EAAE,IAAI;KAChB,CAAC;AACN,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,GAAY;IACtC,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACjE,MAAM,MAAM,GAAI,GAAW,EAAE,MAAM,IAAK,GAAW,EAAE,UAAU,CAAC;IAChE,IAAI,MAAM,KAAK,GAAG,IAAI,oBAAoB,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACvD,OAAO,WAAW,CACd,kEAAkE;cAChE,uFAAuF,EACzF,EAAE,MAAM,EAAE,GAAG,EAAE,CAClB,CAAC;IACN,CAAC;IACD,OAAO,WAAW,CAAC,OAAO,CAAC,CAAC;AAChC,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,cAAc,CAC1B,EAAuC;IAEvC,OAAO,KAAK,EAAE,GAAG,IAAO,EAAE,EAAE;QACxB,IAAI,CAAC;YACD,OAAO,MAAM,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC;QAC7B,CAAC;QAAC,OAAO,GAAY,EAAE,CAAC;YACpB,OAAO,aAAa,CAAC,GAAG,CAAC,CAAC;QAC9B,CAAC;IACL,CAAC,CAAC;AACN,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pilotswarm",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "PilotSwarm application package: terminal UI, browser portal + Web API server, and MCP server — one install, three bins.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -62,9 +62,10 @@
|
|
|
62
62
|
"test:tui": "node --test tui/test/*.test.mjs",
|
|
63
63
|
"test:web": "node --test web/test/*.test.mjs",
|
|
64
64
|
"test:ui": "node --test ui/core/test/*.test.mjs",
|
|
65
|
-
"test:mcp": "node mcp/test/unit/sendCommandAndWait.unit.mjs",
|
|
65
|
+
"test:mcp": "node mcp/test/unit/sendCommandAndWait.unit.mjs && node mcp/test/unit/registration.unit.mjs && node mcp/test/unit/dispatch.unit.mjs",
|
|
66
66
|
"test:mcp:integration": "node mcp/test/integration/smoke.live.mjs",
|
|
67
|
-
"test:mcp:integration:
|
|
67
|
+
"test:mcp:integration:horizondb": "MCP_PARITY_REQUIRE=search,graph node --env-file=../../.env.horizondb mcp/test/integration/parity.live.mjs",
|
|
68
|
+
"test:mcp:integration:all": "node mcp/test/integration/smoke.live.mjs && node mcp/test/integration/tools.live.mjs && node mcp/test/integration/edge-cases.live.mjs && node mcp/test/integration/verify.live.mjs && node mcp/test/integration/parity.live.mjs",
|
|
68
69
|
"clean": "rm -rf web/dist mcp/dist"
|
|
69
70
|
},
|
|
70
71
|
"dependencies": {
|
|
@@ -76,7 +77,7 @@
|
|
|
76
77
|
"hono": "^4.12.10",
|
|
77
78
|
"ink": "^6.8.0",
|
|
78
79
|
"jose": "^6.2.2",
|
|
79
|
-
"pilotswarm-sdk": "^0.
|
|
80
|
+
"pilotswarm-sdk": "^0.5.0",
|
|
80
81
|
"react": "^19.2.4",
|
|
81
82
|
"react-dom": "^19.2.4",
|
|
82
83
|
"ws": "^8.18.2"
|
package/tui/bin/tui.js
CHANGED
|
@@ -4,9 +4,6 @@
|
|
|
4
4
|
// explicitly opts into another environment for debugging.
|
|
5
5
|
process.env.NODE_ENV ??= "production";
|
|
6
6
|
|
|
7
|
-
const { syncBundledWorkspaceUiPackages } = await import("../src/sync-workspace-ui.js");
|
|
8
|
-
syncBundledWorkspaceUiPackages({ linkWorkspacePackages: true });
|
|
9
|
-
|
|
10
7
|
const argv = process.argv.slice(2);
|
|
11
8
|
if (argv[0] === "auth") {
|
|
12
9
|
const { runAuthCommand } = await import("../src/auth/cli.js");
|
|
@@ -782,6 +782,30 @@ export class NodeSdkTransport {
|
|
|
782
782
|
return this.mgmt.getFleetRetrievalUsage(opts);
|
|
783
783
|
}
|
|
784
784
|
|
|
785
|
+
async getSessionRetrievalUsage(sessionId, opts) {
|
|
786
|
+
return this.mgmt.getSessionRetrievalUsage(sessionId, opts);
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
async getSessionTreeRetrievalUsage(sessionId, opts) {
|
|
790
|
+
return this.mgmt.getSessionTreeRetrievalUsage(sessionId, opts);
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
async getSessionGraphNodeUsage(sessionId, opts) {
|
|
794
|
+
return this.mgmt.getSessionGraphNodeUsage(sessionId, opts);
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
async getSessionGraphEdgeSearchUsage(sessionId, opts) {
|
|
798
|
+
return this.mgmt.getSessionGraphEdgeSearchUsage(sessionId, opts);
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
async getSessionGraphSearches(sessionId, limit) {
|
|
802
|
+
return this.mgmt.getSessionGraphSearches(sessionId, limit);
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
async getFleetGraphNodeUsage(opts) {
|
|
806
|
+
return this.mgmt.getFleetGraphNodeUsage(opts);
|
|
807
|
+
}
|
|
808
|
+
|
|
785
809
|
async getSessionFactsStats(sessionId) {
|
|
786
810
|
return this.mgmt.getSessionFactsStats(sessionId);
|
|
787
811
|
}
|
package/ui/core/src/selectors.js
CHANGED
|
@@ -1706,9 +1706,17 @@ function splashArtWidth(text) {
|
|
|
1706
1706
|
function buildChatMessageLines(message, maxWidth, options = {}) {
|
|
1707
1707
|
if (message?.splash) {
|
|
1708
1708
|
// Swap in the narrow-viewport variant when the main art would
|
|
1709
|
-
// overflow the pane (mobile portal, narrow terminals).
|
|
1709
|
+
// overflow the pane (mobile portal, narrow terminals). When the
|
|
1710
|
+
// width metrics keep the desktop art, still hand renderers the
|
|
1711
|
+
// mobile variant (splashAlt) so environments with real media
|
|
1712
|
+
// queries (the browser) can make the final call by CSS viewport —
|
|
1713
|
+
// character metrics and device width can disagree.
|
|
1710
1714
|
const useMobile = message.mobileText && splashArtWidth(message.text) > maxWidth;
|
|
1711
|
-
return [{
|
|
1715
|
+
return [{
|
|
1716
|
+
kind: "markup",
|
|
1717
|
+
value: useMobile ? message.mobileText : message.text,
|
|
1718
|
+
splashAlt: !useMobile && message.mobileText ? message.mobileText : null,
|
|
1719
|
+
}];
|
|
1712
1720
|
}
|
|
1713
1721
|
|
|
1714
1722
|
if (message?.thinking) {
|
|
@@ -2848,6 +2856,15 @@ function formatCompactBytes(value) {
|
|
|
2848
2856
|
return `${mb >= 10 ? Math.round(mb) : mb.toFixed(1)} MB`;
|
|
2849
2857
|
}
|
|
2850
2858
|
|
|
2859
|
+
/** "12.4×" compression ratio (raw / stored); null when either is missing. */
|
|
2860
|
+
function formatCompressionRatio(rawBytes, storedBytes) {
|
|
2861
|
+
const raw = Number(rawBytes);
|
|
2862
|
+
const stored = Number(storedBytes);
|
|
2863
|
+
if (!Number.isFinite(raw) || !Number.isFinite(stored) || raw <= 0 || stored <= 0) return null;
|
|
2864
|
+
const ratio = raw / stored;
|
|
2865
|
+
return `${ratio >= 10 ? ratio.toFixed(0) : ratio.toFixed(1)}×`;
|
|
2866
|
+
}
|
|
2867
|
+
|
|
2851
2868
|
function summarizeEventPreview(text, maxLength = 18) {
|
|
2852
2869
|
const normalized = String(text || "")
|
|
2853
2870
|
.replace(/\s+/g, " ")
|
|
@@ -4463,6 +4480,8 @@ function buildSessionStatsLines(state, session, maxWidth) {
|
|
|
4463
4480
|
title: "Persistence",
|
|
4464
4481
|
body: formatKeyValueTable([
|
|
4465
4482
|
["Snapshot", formatCompactBytes(summary.snapshotSizeBytes)],
|
|
4483
|
+
["Uncompressed", summary.rawSizeBytes ? formatCompactBytes(summary.rawSizeBytes) : null],
|
|
4484
|
+
["Compression", formatCompressionRatio(summary.rawSizeBytes, summary.snapshotSizeBytes)],
|
|
4466
4485
|
["Dehydrations", String(summary.dehydrationCount)],
|
|
4467
4486
|
["Hydrations", String(summary.hydrationCount)],
|
|
4468
4487
|
["Lossy Handoffs", String(summary.lossyHandoffCount)],
|
|
@@ -4492,6 +4511,8 @@ function buildSessionStatsLines(state, session, maxWidth) {
|
|
|
4492
4511
|
["Cache Write", formatCompactNumber(tree.totalTokensCacheWrite)],
|
|
4493
4512
|
["Hit Ratio", treeHitLabel],
|
|
4494
4513
|
["Snapshot", formatCompactBytes(tree.totalSnapshotSizeBytes)],
|
|
4514
|
+
["Uncompressed", tree.totalRawSizeBytes ? formatCompactBytes(tree.totalRawSizeBytes) : null],
|
|
4515
|
+
["Compression", formatCompressionRatio(tree.totalRawSizeBytes, tree.totalSnapshotSizeBytes)],
|
|
4495
4516
|
["Dehydrations", String(tree.totalDehydrationCount)],
|
|
4496
4517
|
["Hydrations", String(tree.totalHydrationCount)],
|
|
4497
4518
|
]),
|
package/ui/react/src/web-app.js
CHANGED
|
@@ -342,9 +342,17 @@ function normalizeLines(lines) {
|
|
|
342
342
|
// Markup lines carry preformatted art (splash screens). Tag them
|
|
343
343
|
// so the chat renderer keeps each line intact: the pane's
|
|
344
344
|
// pre-wrap/overflow-wrap rules would rewrap wide art lines at
|
|
345
|
-
// arbitrary points and scramble the image.
|
|
346
|
-
|
|
347
|
-
|
|
345
|
+
// arbitrary points and scramble the image. When a splashAlt is
|
|
346
|
+
// present, emit BOTH variants tagged by name — CSS shows exactly
|
|
347
|
+
// one based on the real device viewport, which beats character
|
|
348
|
+
// metrics at deciding what actually fits.
|
|
349
|
+
const variants = line.splashAlt
|
|
350
|
+
? [{ text: line.value, variant: "desktop" }, { text: line.splashAlt, variant: "mobile" }]
|
|
351
|
+
: [{ text: line.value, variant: null }];
|
|
352
|
+
for (const v of variants) {
|
|
353
|
+
for (const parsedLine of parseTerminalMarkupRuns(v.text || "")) {
|
|
354
|
+
normalized.push({ kind: "runs", runs: parsedLine, preserve: true, splashVariant: v.variant });
|
|
355
|
+
}
|
|
348
356
|
}
|
|
349
357
|
continue;
|
|
350
358
|
}
|
|
@@ -1322,12 +1330,13 @@ function parseStructuredChatBlocks(lines = []) {
|
|
|
1322
1330
|
// detection entirely and render as one preserve block, so no line
|
|
1323
1331
|
// ever rewraps or gets reinterpreted as a structured element.
|
|
1324
1332
|
if (currentLine?.preserve) {
|
|
1333
|
+
const variant = currentLine.splashVariant || null;
|
|
1325
1334
|
const preserveLines = [];
|
|
1326
|
-
while (index < lines.length && lines[index]?.preserve) {
|
|
1335
|
+
while (index < lines.length && lines[index]?.preserve && (lines[index].splashVariant || null) === variant) {
|
|
1327
1336
|
preserveLines.push(lines[index]);
|
|
1328
1337
|
index += 1;
|
|
1329
1338
|
}
|
|
1330
|
-
blocks.push({ type: "preserve", lines: preserveLines });
|
|
1339
|
+
blocks.push({ type: "preserve", lines: preserveLines, splashVariant: variant });
|
|
1331
1340
|
continue;
|
|
1332
1341
|
}
|
|
1333
1342
|
|
|
@@ -1483,7 +1492,8 @@ function StructuredChatBlocks({ lines, theme }) {
|
|
|
1483
1492
|
return React.createElement(React.Fragment, null,
|
|
1484
1493
|
blocks.map((block, index) => {
|
|
1485
1494
|
if (block.type === "preserve") {
|
|
1486
|
-
|
|
1495
|
+
const variantClass = block.splashVariant ? ` is-splash-${block.splashVariant}` : "";
|
|
1496
|
+
return React.createElement("div", { key: `preserve:${index}`, className: `ps-chat-preserve-block${variantClass}` },
|
|
1487
1497
|
block.lines.map((line, lineIndex) => React.createElement(Line, {
|
|
1488
1498
|
key: `preserve:${index}:${lineIndex}`,
|
|
1489
1499
|
line,
|
|
@@ -4145,6 +4155,41 @@ export function PilotSwarmWebApp({ controller }) {
|
|
|
4145
4155
|
const viewport = useMeasuredViewport(viewportRef);
|
|
4146
4156
|
const mainGridViewport = useMeasuredViewport(mainGridRef);
|
|
4147
4157
|
const gridViewport = computeGridViewport(viewport);
|
|
4158
|
+
|
|
4159
|
+
// Publish the real viewport in character cells. Without this the ui-core
|
|
4160
|
+
// layout model runs on its 120×40 fallback everywhere in the browser, so
|
|
4161
|
+
// width-derived behavior (markdown wrap width, render metrics, the
|
|
4162
|
+
// splashMobile width swap) assumed a ~120-column terminal regardless of
|
|
4163
|
+
// device — phones kept getting desktop splash art narrower than ~76 cols.
|
|
4164
|
+
React.useEffect(() => {
|
|
4165
|
+
const publish = () => {
|
|
4166
|
+
const probe = document.createElement("span");
|
|
4167
|
+
probe.style.cssText = "position:absolute;visibility:hidden;white-space:pre;";
|
|
4168
|
+
// Measure with the font real lines render in — an off-context
|
|
4169
|
+
// probe can inherit a different size and skew the column count.
|
|
4170
|
+
const sample = document.querySelector(".ps-scroll-panel .ps-line") || document.querySelector(".ps-line");
|
|
4171
|
+
if (sample) probe.style.font = window.getComputedStyle(sample).font;
|
|
4172
|
+
probe.textContent = "0".repeat(100);
|
|
4173
|
+
(sample?.parentElement || document.body).appendChild(probe);
|
|
4174
|
+
const charWidth = (probe.getBoundingClientRect().width / 100) || 8;
|
|
4175
|
+
probe.remove();
|
|
4176
|
+
controller.dispatch({
|
|
4177
|
+
type: "ui/viewport",
|
|
4178
|
+
width: Math.floor(window.innerWidth / charWidth),
|
|
4179
|
+
height: Math.floor(window.innerHeight / SCROLL_ROW_HEIGHT),
|
|
4180
|
+
});
|
|
4181
|
+
};
|
|
4182
|
+
publish();
|
|
4183
|
+
let timer;
|
|
4184
|
+
const onResize = () => { clearTimeout(timer); timer = setTimeout(publish, 150); };
|
|
4185
|
+
window.addEventListener("resize", onResize);
|
|
4186
|
+
window.addEventListener("orientationchange", onResize);
|
|
4187
|
+
return () => {
|
|
4188
|
+
clearTimeout(timer);
|
|
4189
|
+
window.removeEventListener("resize", onResize);
|
|
4190
|
+
window.removeEventListener("orientationchange", onResize);
|
|
4191
|
+
};
|
|
4192
|
+
}, [controller]);
|
|
4148
4193
|
const [chatFocusMode, setChatFocusMode] = React.useState(false);
|
|
4149
4194
|
const [chatFocusPane, setChatFocusPane] = React.useState(null);
|
|
4150
4195
|
const state = useControllerSelector(controller, (rootState) => ({
|