pilotswarm 0.4.1 → 0.5.1

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 (89) hide show
  1. package/mcp/README.md +88 -4
  2. package/mcp/dist/src/context.d.ts +36 -6
  3. package/mcp/dist/src/context.d.ts.map +1 -1
  4. package/mcp/dist/src/context.js +102 -8
  5. package/mcp/dist/src/context.js.map +1 -1
  6. package/mcp/dist/src/resources/artifacts.d.ts +5 -0
  7. package/mcp/dist/src/resources/artifacts.d.ts.map +1 -0
  8. package/mcp/dist/src/resources/artifacts.js +39 -0
  9. package/mcp/dist/src/resources/artifacts.js.map +1 -0
  10. package/mcp/dist/src/resources/capabilities.d.ts +4 -0
  11. package/mcp/dist/src/resources/capabilities.d.ts.map +1 -0
  12. package/mcp/dist/src/resources/capabilities.js +17 -0
  13. package/mcp/dist/src/resources/capabilities.js.map +1 -0
  14. package/mcp/dist/src/resources/graph.d.ts +5 -0
  15. package/mcp/dist/src/resources/graph.d.ts.map +1 -0
  16. package/mcp/dist/src/resources/graph.js +45 -0
  17. package/mcp/dist/src/resources/graph.js.map +1 -0
  18. package/mcp/dist/src/server.d.ts.map +1 -1
  19. package/mcp/dist/src/server.js +61 -2
  20. package/mcp/dist/src/server.js.map +1 -1
  21. package/mcp/dist/src/tools/agents.d.ts.map +1 -1
  22. package/mcp/dist/src/tools/agents.js +3 -2
  23. package/mcp/dist/src/tools/agents.js.map +1 -1
  24. package/mcp/dist/src/tools/artifacts.d.ts +12 -0
  25. package/mcp/dist/src/tools/artifacts.d.ts.map +1 -0
  26. package/mcp/dist/src/tools/artifacts.js +92 -0
  27. package/mcp/dist/src/tools/artifacts.js.map +1 -0
  28. package/mcp/dist/src/tools/capabilities.d.ts +27 -0
  29. package/mcp/dist/src/tools/capabilities.d.ts.map +1 -0
  30. package/mcp/dist/src/tools/capabilities.js +69 -0
  31. package/mcp/dist/src/tools/capabilities.js.map +1 -0
  32. package/mcp/dist/src/tools/debug.d.ts +4 -0
  33. package/mcp/dist/src/tools/debug.d.ts.map +1 -0
  34. package/mcp/dist/src/tools/debug.js +94 -0
  35. package/mcp/dist/src/tools/debug.js.map +1 -0
  36. package/mcp/dist/src/tools/facts-enhanced.d.ts +13 -0
  37. package/mcp/dist/src/tools/facts-enhanced.d.ts.map +1 -0
  38. package/mcp/dist/src/tools/facts-enhanced.js +80 -0
  39. package/mcp/dist/src/tools/facts-enhanced.js.map +1 -0
  40. package/mcp/dist/src/tools/graph.d.ts +12 -0
  41. package/mcp/dist/src/tools/graph.d.ts.map +1 -0
  42. package/mcp/dist/src/tools/graph.js +237 -0
  43. package/mcp/dist/src/tools/graph.js.map +1 -0
  44. package/mcp/dist/src/tools/groups.d.ts +10 -0
  45. package/mcp/dist/src/tools/groups.d.ts.map +1 -0
  46. package/mcp/dist/src/tools/groups.js +107 -0
  47. package/mcp/dist/src/tools/groups.js.map +1 -0
  48. package/mcp/dist/src/tools/models.d.ts.map +1 -1
  49. package/mcp/dist/src/tools/models.js +16 -4
  50. package/mcp/dist/src/tools/models.js.map +1 -1
  51. package/mcp/dist/src/tools/observability.d.ts +13 -0
  52. package/mcp/dist/src/tools/observability.d.ts.map +1 -0
  53. package/mcp/dist/src/tools/observability.js +174 -0
  54. package/mcp/dist/src/tools/observability.js.map +1 -0
  55. package/mcp/dist/src/tools/sessions.d.ts.map +1 -1
  56. package/mcp/dist/src/tools/sessions.js +120 -94
  57. package/mcp/dist/src/tools/sessions.js.map +1 -1
  58. package/mcp/dist/src/tools/system.d.ts +14 -0
  59. package/mcp/dist/src/tools/system.d.ts.map +1 -0
  60. package/mcp/dist/src/tools/system.js +110 -0
  61. package/mcp/dist/src/tools/system.js.map +1 -0
  62. package/mcp/dist/src/tools/turn-control.d.ts +13 -0
  63. package/mcp/dist/src/tools/turn-control.d.ts.map +1 -0
  64. package/mcp/dist/src/tools/turn-control.js +98 -0
  65. package/mcp/dist/src/tools/turn-control.js.map +1 -0
  66. package/mcp/dist/src/util/respond.d.ts +21 -0
  67. package/mcp/dist/src/util/respond.d.ts.map +1 -0
  68. package/mcp/dist/src/util/respond.js +42 -0
  69. package/mcp/dist/src/util/respond.js.map +1 -0
  70. package/package.json +5 -4
  71. package/tui/bin/tui.js +0 -3
  72. package/tui/src/app.js +36 -5
  73. package/tui/src/node-sdk-transport.js +24 -0
  74. package/ui/core/src/commands.js +6 -0
  75. package/ui/core/src/controller.js +137 -2
  76. package/ui/core/src/reducer.js +31 -1
  77. package/ui/core/src/selectors.js +414 -17
  78. package/ui/core/src/state.js +2 -0
  79. package/ui/react/src/chat-status.js +22 -0
  80. package/ui/react/src/components.js +68 -6
  81. package/ui/react/src/web-app.js +69 -8
  82. package/web/dist/assets/{index-xJ8IzIZY.js → index-BmqU2WsR.js} +4 -4
  83. package/web/dist/assets/index-D2-7fi56.css +1 -0
  84. package/web/dist/assets/pilotswarm-cIaYAE9e.js +90 -0
  85. package/web/dist/assets/{react-CEPDSRB6.js → react-CRYBfNR4.js} +1 -1
  86. package/web/dist/index.html +4 -4
  87. package/web/runtime.js +30 -0
  88. package/web/dist/assets/index-DmGOcKR-.css +0 -1
  89. package/web/dist/assets/pilotswarm-D9pEmenA.js +0 -90
@@ -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.4.1",
3
+ "version": "0.5.1",
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: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",
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.4.1",
80
+ "pilotswarm-sdk": "^0.5.1",
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");
package/tui/src/app.js CHANGED
@@ -264,6 +264,14 @@ export function PilotSwarmTuiApp({ controller, platform, onRequestExit }) {
264
264
  requestExit();
265
265
  return;
266
266
  }
267
+ // Stop the current turn — the TUI equivalent of the portal Stop button.
268
+ // ctrl-x is reliable across terminals; ctrl-esc also fires where the
269
+ // terminal sends it distinctly from a bare Esc. The controller no-ops
270
+ // (status message) when no turn is running.
271
+ if (key.ctrl && (input === "x" || key.escape)) {
272
+ controller.handleCommand(UI_COMMANDS.STOP_TURN).catch(() => {});
273
+ return;
274
+ }
267
275
  if (focus !== "prompt" && input === "q" && quitStateRef.current.armedUntil > Date.now()) {
268
276
  clearQuitArm(false);
269
277
  requestExit();
@@ -398,7 +406,7 @@ export function PilotSwarmTuiApp({ controller, platform, onRequestExit }) {
398
406
  }
399
407
  return;
400
408
  }
401
- if (key.escape || input === "q" || (modal.type === "artifactPicker" && input === "a")) {
409
+ if (key.escape || input === "q" || (modal.type === "artifactPicker" && input === "a") || (modal.type === "help" && input === "?")) {
402
410
  controller.handleCommand(UI_COMMANDS.CLOSE_MODAL).catch(() => {});
403
411
  return;
404
412
  }
@@ -602,21 +610,40 @@ export function PilotSwarmTuiApp({ controller, platform, onRequestExit }) {
602
610
  return;
603
611
  }
604
612
  }
613
+ // Sequence tab: j/k move the turn cursor across completed turns, enter
614
+ // expands/collapses the selected turn (paging/g-G still scroll).
615
+ if (focus === "inspector" && inspectorTab === "sequence") {
616
+ if (key.return) {
617
+ controller.handleCommand(UI_COMMANDS.TOGGLE_SEQUENCE_TURN).catch(() => {});
618
+ return;
619
+ }
620
+ if (key.upArrow || input === "k") {
621
+ controller.handleCommand(UI_COMMANDS.SEQUENCE_SELECT_PREV).catch(() => {});
622
+ return;
623
+ }
624
+ if (key.downArrow || input === "j") {
625
+ controller.handleCommand(UI_COMMANDS.SEQUENCE_SELECT_NEXT).catch(() => {});
626
+ return;
627
+ }
628
+ }
605
629
 
630
+ // [ / ] resize the vertical pane of whatever is focused (sessions/chat
631
+ // share the left split; inspector/activity share the right split).
632
+ // { / } resize the horizontal left/right column split.
606
633
  if (focus !== "prompt" && input === "[") {
607
- controller.handleCommand(UI_COMMANDS.GROW_LEFT_PANE).catch(() => {});
634
+ controller.handleCommand(UI_COMMANDS.SHRINK_FOCUSED_PANE).catch(() => {});
608
635
  return;
609
636
  }
610
637
  if (focus !== "prompt" && input === "]") {
611
- controller.handleCommand(UI_COMMANDS.GROW_RIGHT_PANE).catch(() => {});
638
+ controller.handleCommand(UI_COMMANDS.GROW_FOCUSED_PANE).catch(() => {});
612
639
  return;
613
640
  }
614
641
  if (focus !== "prompt" && input === "{") {
615
- controller.handleCommand(UI_COMMANDS.SHRINK_SESSION_PANE).catch(() => {});
642
+ controller.handleCommand(UI_COMMANDS.GROW_LEFT_PANE).catch(() => {});
616
643
  return;
617
644
  }
618
645
  if (focus !== "prompt" && input === "}") {
619
- controller.handleCommand(UI_COMMANDS.GROW_SESSION_PANE).catch(() => {});
646
+ controller.handleCommand(UI_COMMANDS.GROW_RIGHT_PANE).catch(() => {});
620
647
  return;
621
648
  }
622
649
 
@@ -718,6 +745,10 @@ export function PilotSwarmTuiApp({ controller, platform, onRequestExit }) {
718
745
  controller.handleCommand(UI_COMMANDS.OPEN_ARTIFACT_PICKER).catch(() => {});
719
746
  return;
720
747
  }
748
+ if (focus !== "prompt" && input === "?") {
749
+ controller.handleCommand(UI_COMMANDS.OPEN_HELP).catch(() => {});
750
+ return;
751
+ }
721
752
  if (plainShortcut && input === "m") {
722
753
  controller.handleCommand(UI_COMMANDS.CYCLE_INSPECTOR_TAB).catch(() => {});
723
754
  return;
@@ -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
  }
@@ -45,7 +45,13 @@ export const UI_COMMANDS = {
45
45
  GROW_RIGHT_PANE: "growRightPane",
46
46
  GROW_SESSION_PANE: "growSessionPane",
47
47
  SHRINK_SESSION_PANE: "shrinkSessionPane",
48
+ GROW_FOCUSED_PANE: "growFocusedPane",
49
+ SHRINK_FOCUSED_PANE: "shrinkFocusedPane",
48
50
  OPEN_ARTIFACT_PICKER: "openArtifactPicker",
51
+ OPEN_HELP: "openHelp",
52
+ SEQUENCE_SELECT_PREV: "sequenceSelectPrev",
53
+ SEQUENCE_SELECT_NEXT: "sequenceSelectNext",
54
+ TOGGLE_SEQUENCE_TURN: "toggleSequenceTurn",
49
55
  TOGGLE_LOG_TAIL: "toggleLogTail",
50
56
  TOGGLE_STATS_VIEW: "toggleStatsView",
51
57
  OPEN_LOG_FILTER: "openLogFilter",