pilotswarm 0.0.1 → 0.4.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 (149) hide show
  1. package/README.md +37 -1
  2. package/mcp/README.md +484 -0
  3. package/mcp/dist/bin/pilotswarm-mcp.d.ts +3 -0
  4. package/mcp/dist/bin/pilotswarm-mcp.d.ts.map +1 -0
  5. package/mcp/dist/bin/pilotswarm-mcp.js +367 -0
  6. package/mcp/dist/bin/pilotswarm-mcp.js.map +1 -0
  7. package/mcp/dist/src/auth.d.ts +7 -0
  8. package/mcp/dist/src/auth.d.ts.map +1 -0
  9. package/mcp/dist/src/auth.js +99 -0
  10. package/mcp/dist/src/auth.js.map +1 -0
  11. package/mcp/dist/src/context.d.ts +48 -0
  12. package/mcp/dist/src/context.d.ts.map +1 -0
  13. package/mcp/dist/src/context.js +83 -0
  14. package/mcp/dist/src/context.js.map +1 -0
  15. package/mcp/dist/src/index.d.ts +4 -0
  16. package/mcp/dist/src/index.d.ts.map +1 -0
  17. package/mcp/dist/src/index.js +3 -0
  18. package/mcp/dist/src/index.js.map +1 -0
  19. package/mcp/dist/src/prompts/skills.d.ts +4 -0
  20. package/mcp/dist/src/prompts/skills.d.ts.map +1 -0
  21. package/mcp/dist/src/prompts/skills.js +11 -0
  22. package/mcp/dist/src/prompts/skills.js.map +1 -0
  23. package/mcp/dist/src/resources/agents.d.ts +4 -0
  24. package/mcp/dist/src/resources/agents.d.ts.map +1 -0
  25. package/mcp/dist/src/resources/agents.js +64 -0
  26. package/mcp/dist/src/resources/agents.js.map +1 -0
  27. package/mcp/dist/src/resources/facts.d.ts +4 -0
  28. package/mcp/dist/src/resources/facts.d.ts.map +1 -0
  29. package/mcp/dist/src/resources/facts.js +125 -0
  30. package/mcp/dist/src/resources/facts.js.map +1 -0
  31. package/mcp/dist/src/resources/models.d.ts +4 -0
  32. package/mcp/dist/src/resources/models.d.ts.map +1 -0
  33. package/mcp/dist/src/resources/models.js +43 -0
  34. package/mcp/dist/src/resources/models.js.map +1 -0
  35. package/mcp/dist/src/resources/sessions.d.ts +4 -0
  36. package/mcp/dist/src/resources/sessions.d.ts.map +1 -0
  37. package/mcp/dist/src/resources/sessions.js +190 -0
  38. package/mcp/dist/src/resources/sessions.js.map +1 -0
  39. package/mcp/dist/src/resources/subscriptions.d.ts +9 -0
  40. package/mcp/dist/src/resources/subscriptions.d.ts.map +1 -0
  41. package/mcp/dist/src/resources/subscriptions.js +157 -0
  42. package/mcp/dist/src/resources/subscriptions.js.map +1 -0
  43. package/mcp/dist/src/server.d.ts +4 -0
  44. package/mcp/dist/src/server.d.ts.map +1 -0
  45. package/mcp/dist/src/server.js +59 -0
  46. package/mcp/dist/src/server.js.map +1 -0
  47. package/mcp/dist/src/tools/agents.d.ts +4 -0
  48. package/mcp/dist/src/tools/agents.d.ts.map +1 -0
  49. package/mcp/dist/src/tools/agents.js +317 -0
  50. package/mcp/dist/src/tools/agents.js.map +1 -0
  51. package/mcp/dist/src/tools/facts.d.ts +4 -0
  52. package/mcp/dist/src/tools/facts.d.ts.map +1 -0
  53. package/mcp/dist/src/tools/facts.js +151 -0
  54. package/mcp/dist/src/tools/facts.js.map +1 -0
  55. package/mcp/dist/src/tools/models.d.ts +4 -0
  56. package/mcp/dist/src/tools/models.d.ts.map +1 -0
  57. package/mcp/dist/src/tools/models.js +256 -0
  58. package/mcp/dist/src/tools/models.js.map +1 -0
  59. package/mcp/dist/src/tools/sessions.d.ts +4 -0
  60. package/mcp/dist/src/tools/sessions.d.ts.map +1 -0
  61. package/mcp/dist/src/tools/sessions.js +606 -0
  62. package/mcp/dist/src/tools/sessions.js.map +1 -0
  63. package/mcp/dist/src/util/command.d.ts +52 -0
  64. package/mcp/dist/src/util/command.d.ts.map +1 -0
  65. package/mcp/dist/src/util/command.js +78 -0
  66. package/mcp/dist/src/util/command.js.map +1 -0
  67. package/package.json +81 -6
  68. package/tui/README.md +35 -0
  69. package/tui/bin/tui.js +30 -0
  70. package/tui/plugins/.mcp.json +7 -0
  71. package/tui/plugins/plugin.json +13 -0
  72. package/tui/plugins/session-policy.json +8 -0
  73. package/tui/src/app.js +850 -0
  74. package/tui/src/auth/cli.js +111 -0
  75. package/tui/src/auth/entra-auth.js +218 -0
  76. package/tui/src/bootstrap-env.js +176 -0
  77. package/tui/src/embedded-workers.js +79 -0
  78. package/tui/src/http-transport-host.js +106 -0
  79. package/tui/src/index.js +340 -0
  80. package/tui/src/node-sdk-transport.js +1793 -0
  81. package/tui/src/platform.js +984 -0
  82. package/tui/src/plugin-config.js +239 -0
  83. package/tui/src/portal.js +7 -0
  84. package/tui/src/version.js +7 -0
  85. package/tui/tui-splash.txt +11 -0
  86. package/ui/core/README.md +6 -0
  87. package/ui/core/src/commands.js +93 -0
  88. package/ui/core/src/context-usage.js +212 -0
  89. package/ui/core/src/controller.js +6104 -0
  90. package/ui/core/src/formatting.js +1036 -0
  91. package/ui/core/src/history.js +932 -0
  92. package/ui/core/src/index.js +13 -0
  93. package/ui/core/src/layout.js +332 -0
  94. package/ui/core/src/reducer.js +1935 -0
  95. package/ui/core/src/selectors.js +5409 -0
  96. package/ui/core/src/session-errors.js +14 -0
  97. package/ui/core/src/session-tree.js +151 -0
  98. package/ui/core/src/state.js +248 -0
  99. package/ui/core/src/store.js +23 -0
  100. package/ui/core/src/system-titles.js +24 -0
  101. package/ui/core/src/themes/catppuccin-mocha.js +56 -0
  102. package/ui/core/src/themes/cobalt2.js +56 -0
  103. package/ui/core/src/themes/dark-high-contrast.js +56 -0
  104. package/ui/core/src/themes/daylight.js +62 -0
  105. package/ui/core/src/themes/dracula.js +56 -0
  106. package/ui/core/src/themes/github-dark.js +56 -0
  107. package/ui/core/src/themes/github-light.js +59 -0
  108. package/ui/core/src/themes/gruvbox-dark.js +56 -0
  109. package/ui/core/src/themes/hacker-x-matrix.js +56 -0
  110. package/ui/core/src/themes/hacker-x-orion-prime.js +56 -0
  111. package/ui/core/src/themes/helpers.js +79 -0
  112. package/ui/core/src/themes/high-contrast-mono.js +59 -0
  113. package/ui/core/src/themes/index.js +52 -0
  114. package/ui/core/src/themes/light-high-contrast.js +62 -0
  115. package/ui/core/src/themes/noctis-obscuro.js +56 -0
  116. package/ui/core/src/themes/noctis.js +56 -0
  117. package/ui/core/src/themes/paper-ink.js +62 -0
  118. package/ui/core/src/themes/solarized-ops.js +59 -0
  119. package/ui/core/src/themes/terminal-green.js +59 -0
  120. package/ui/core/src/themes/tokyo-night.js +56 -0
  121. package/ui/react/README.md +5 -0
  122. package/ui/react/src/chat-status.js +39 -0
  123. package/ui/react/src/components.js +1989 -0
  124. package/ui/react/src/index.js +4 -0
  125. package/ui/react/src/platform.js +15 -0
  126. package/ui/react/src/use-controller-state.js +38 -0
  127. package/ui/react/src/web-app.js +4390 -0
  128. package/web/README.md +198 -0
  129. package/web/api/router.js +196 -0
  130. package/web/api/ws.js +152 -0
  131. package/web/auth/authz/engine.js +204 -0
  132. package/web/auth/config.js +115 -0
  133. package/web/auth/index.js +175 -0
  134. package/web/auth/normalize/entra.js +22 -0
  135. package/web/auth/providers/entra.js +76 -0
  136. package/web/auth/providers/none.js +24 -0
  137. package/web/auth.js +10 -0
  138. package/web/bin/serve.js +53 -0
  139. package/web/config.js +20 -0
  140. package/web/dist/app.js +469 -0
  141. package/web/dist/assets/index-CBgQQk-j.css +1 -0
  142. package/web/dist/assets/index-DMefB7Wb.js +24 -0
  143. package/web/dist/assets/msal-CytV9RFv.js +7 -0
  144. package/web/dist/assets/pilotswarm-DyBlqVTY.js +87 -0
  145. package/web/dist/assets/react-BZwsW8pe.js +1 -0
  146. package/web/dist/index.html +16 -0
  147. package/web/runtime.js +454 -0
  148. package/web/server.js +276 -0
  149. package/index.js +0 -1
@@ -0,0 +1,14 @@
1
+ export function isRecoverableTransportErrorText(text) {
2
+ const value = String(text || "");
3
+ return /\bConnection is closed\b/i.test(value)
4
+ || /\bLive Copilot connection lost\b/i.test(value);
5
+ }
6
+
7
+ export function shouldKeepRecoverableTransportWarning(previousSession, nextSession) {
8
+ if (!isRecoverableTransportErrorText(previousSession?.error)) return false;
9
+ if (nextSession?.error !== undefined) return false;
10
+ const nextStatus = String(nextSession?.status || "");
11
+ if (nextStatus !== "running") return false;
12
+ if (["Completed", "Failed", "Terminated"].includes(String(nextSession?.orchestrationStatus || ""))) return false;
13
+ return true;
14
+ }
@@ -0,0 +1,151 @@
1
+ import { systemSessionSortOrder } from "./system-titles.js";
2
+
3
+ function systemSessionOrder(session) {
4
+ if (!session?.isSystem) return Number.MAX_SAFE_INTEGER;
5
+ return systemSessionSortOrder(session);
6
+ }
7
+
8
+ function buildPreviousOrderMap(previousFlat = []) {
9
+ const order = new Map();
10
+ for (let index = 0; index < previousFlat.length; index += 1) {
11
+ const sessionId = previousFlat[index]?.sessionId;
12
+ if (!sessionId || order.has(sessionId)) continue;
13
+ order.set(sessionId, index);
14
+ }
15
+ return order;
16
+ }
17
+
18
+ function buildStableOrderMap(orderSource = []) {
19
+ if (orderSource instanceof Map) {
20
+ return new Map(orderSource);
21
+ }
22
+ if (Array.isArray(orderSource)) {
23
+ return buildPreviousOrderMap(orderSource);
24
+ }
25
+ const order = new Map();
26
+ for (const [sessionId, index] of Object.entries(orderSource || {})) {
27
+ if (!sessionId || typeof index !== "number" || Number.isNaN(index)) continue;
28
+ order.set(sessionId, index);
29
+ }
30
+ return order;
31
+ }
32
+
33
+ function isTreePinnableSession(session) {
34
+ return Boolean(
35
+ session
36
+ && !session.isSystem
37
+ && (session.isGroup || (!session.parentSessionId && !session.groupId)),
38
+ );
39
+ }
40
+
41
+ function isPinnedSession(session, pinnedIds) {
42
+ return Boolean(isTreePinnableSession(session) && pinnedIds && pinnedIds.has(session.sessionId));
43
+ }
44
+
45
+ function rankSessionBand(session, pinnedIds) {
46
+ if (session.isSystem) return 0;
47
+ if (session.isGroup && isPinnedSession(session, pinnedIds)) return 1;
48
+ if (isPinnedSession(session, pinnedIds)) return 2;
49
+ if (session.isGroup) return 3;
50
+ return 4;
51
+ }
52
+
53
+ function summaryTimestamp(session) {
54
+ const raw = session?.updatedAt
55
+ ?? session?.summaryUpdatedAt
56
+ ?? session?.latestSummaryUpdatedAt;
57
+ const value = typeof raw === "number" ? raw : Date.parse(raw || "");
58
+ return Number.isFinite(value) ? value : 0;
59
+ }
60
+
61
+ function sortSessions(a, b, stableOrderMap, pinnedIds) {
62
+ const aRank = rankSessionBand(a, pinnedIds);
63
+ const bRank = rankSessionBand(b, pinnedIds);
64
+ if (aRank !== bRank) return aRank - bRank;
65
+
66
+ const aSystemOrder = systemSessionOrder(a);
67
+ const bSystemOrder = systemSessionOrder(b);
68
+ if (aSystemOrder !== bSystemOrder) return aSystemOrder - bSystemOrder;
69
+
70
+ const aPreviousOrder = stableOrderMap.get(a.sessionId);
71
+ const bPreviousOrder = stableOrderMap.get(b.sessionId);
72
+ if (
73
+ typeof aPreviousOrder === "number"
74
+ && typeof bPreviousOrder === "number"
75
+ && aPreviousOrder !== bPreviousOrder
76
+ ) {
77
+ return aPreviousOrder - bPreviousOrder;
78
+ }
79
+
80
+ const aSummaryAt = summaryTimestamp(a);
81
+ const bSummaryAt = summaryTimestamp(b);
82
+ if (aSummaryAt > 0 && bSummaryAt > 0 && aSummaryAt !== bSummaryAt) {
83
+ return bSummaryAt - aSummaryAt;
84
+ }
85
+
86
+ const createdDiff = (b.createdAt || 0) - (a.createdAt || 0);
87
+ if (createdDiff !== 0) return createdDiff;
88
+
89
+ const aTitle = String(a.title || "");
90
+ const bTitle = String(b.title || "");
91
+ const titleDiff = aTitle.localeCompare(bTitle);
92
+ if (titleDiff !== 0) return titleDiff;
93
+
94
+ return String(a.sessionId || "").localeCompare(String(b.sessionId || ""));
95
+ }
96
+
97
+ export function buildSessionTree(sessions = [], collapsedIds = new Set(), orderSource = [], pinnedIds = null) {
98
+ const byId = new Map();
99
+ const children = new Map();
100
+ const stableOrderMap = buildStableOrderMap(orderSource);
101
+ const pinSet = pinnedIds instanceof Set
102
+ ? pinnedIds
103
+ : new Set(Array.isArray(pinnedIds) ? pinnedIds : []);
104
+
105
+ for (const session of sessions) {
106
+ byId.set(session.sessionId, session);
107
+ }
108
+
109
+ for (const session of sessions) {
110
+ const groupParentId = !session.isGroup && session.groupId && !session.parentSessionId && byId.has(`group:${session.groupId}`)
111
+ ? `group:${session.groupId}`
112
+ : null;
113
+ const parentId = session.parentSessionId || groupParentId;
114
+ if (!parentId || !byId.has(parentId)) continue;
115
+ if (!children.has(parentId)) children.set(parentId, []);
116
+ children.get(parentId).push(session);
117
+ }
118
+
119
+ for (const childList of children.values()) {
120
+ // Pins are a top-level concept. If a previously pinned session moves
121
+ // into a group, the reducer prunes the pin and the tree ignores any
122
+ // stale pin while ordering children.
123
+ childList.sort((a, b) => sortSessions(a, b, stableOrderMap, pinSet));
124
+ }
125
+
126
+ const roots = sessions
127
+ .filter((session) => {
128
+ if (session.parentSessionId && byId.has(session.parentSessionId)) return false;
129
+ if (!session.isGroup && session.groupId && !session.parentSessionId && byId.has(`group:${session.groupId}`)) return false;
130
+ return true;
131
+ })
132
+ .sort((a, b) => sortSessions(a, b, stableOrderMap, pinSet));
133
+
134
+ const flat = [];
135
+
136
+ function visit(session, depth) {
137
+ const childList = children.get(session.sessionId) || [];
138
+ flat.push({
139
+ sessionId: session.sessionId,
140
+ depth,
141
+ hasChildren: childList.length > 0,
142
+ collapsed: collapsedIds.has(session.sessionId),
143
+ });
144
+ if (collapsedIds.has(session.sessionId)) return;
145
+ for (const child of childList) visit(child, depth + 1);
146
+ }
147
+
148
+ for (const root of roots) visit(root, 0);
149
+
150
+ return flat;
151
+ }
@@ -0,0 +1,248 @@
1
+ import { FOCUS_REGIONS, INSPECTOR_TABS } from "./commands.js";
2
+ import { DEFAULT_THEME_ID, getTheme } from "./themes/index.js";
3
+
4
+ const ARTIFACT_SOURCES = new Set(["agent", "user", "system"]);
5
+
6
+ export function normalizeSessionOwnerFilter(filter) {
7
+ const ownerKeys = Array.isArray(filter?.ownerKeys)
8
+ ? [...new Set(filter.ownerKeys.map((key) => String(key || "").trim()).filter(Boolean))]
9
+ : [];
10
+ const hasExplicitFilter = filter && typeof filter === "object";
11
+ return {
12
+ all: hasExplicitFilter ? filter?.all === true : true,
13
+ includeSystem: filter?.includeSystem === true,
14
+ includeUnowned: filter?.includeUnowned === true,
15
+ includeMe: filter?.includeMe === true,
16
+ ownerKeys,
17
+ };
18
+ }
19
+
20
+ export function normalizeArtifactEntry(entry) {
21
+ if (typeof entry === "string") {
22
+ const filename = entry.trim();
23
+ if (!filename) return null;
24
+ return {
25
+ filename,
26
+ sizeBytes: null,
27
+ contentType: "",
28
+ isBinary: false,
29
+ uploadedAt: "",
30
+ source: "agent",
31
+ };
32
+ }
33
+ if (!entry || typeof entry !== "object") return null;
34
+ const filename = String(entry.filename || "").trim();
35
+ if (!filename) return null;
36
+ const sizeBytes = Number(entry.sizeBytes);
37
+ const contentType = typeof entry.contentType === "string" ? entry.contentType : "";
38
+ return {
39
+ filename,
40
+ sizeBytes: Number.isFinite(sizeBytes) && sizeBytes >= 0 ? sizeBytes : null,
41
+ contentType,
42
+ isBinary: entry.isBinary === true,
43
+ uploadedAt: typeof entry.uploadedAt === "string" ? entry.uploadedAt : "",
44
+ source: ARTIFACT_SOURCES.has(entry.source) ? entry.source : "agent",
45
+ };
46
+ }
47
+
48
+ export function normalizeArtifactEntries(entries) {
49
+ const list = Array.isArray(entries) ? entries : [];
50
+ const normalized = [];
51
+ const seen = new Set();
52
+ for (const entry of list) {
53
+ const candidate = normalizeArtifactEntry(entry);
54
+ if (!candidate || seen.has(candidate.filename)) continue;
55
+ seen.add(candidate.filename);
56
+ normalized.push(candidate);
57
+ }
58
+ return normalized;
59
+ }
60
+
61
+ export function findArtifactEntry(entries, filename) {
62
+ const target = String(filename || "").trim();
63
+ if (!target) return null;
64
+ return normalizeArtifactEntries(entries).find((entry) => entry.filename === target) || null;
65
+ }
66
+
67
+ export function normalizeStoredLayoutAdjustments(layoutAdjustments) {
68
+ const candidate = layoutAdjustments && typeof layoutAdjustments === "object"
69
+ ? layoutAdjustments
70
+ : {};
71
+ const paneAdjust = Number(candidate.paneAdjust);
72
+ const sessionPaneAdjust = Number(candidate.sessionPaneAdjust);
73
+ const portalSessionColumnAdjust = Number(candidate.portalSessionColumnAdjust);
74
+ const activityPaneAdjust = Number(candidate.activityPaneAdjust);
75
+ return {
76
+ paneAdjust: Number.isFinite(paneAdjust) ? Math.trunc(paneAdjust) : 0,
77
+ sessionPaneAdjust: Number.isFinite(sessionPaneAdjust) ? Math.trunc(sessionPaneAdjust) : 0,
78
+ portalSessionColumnAdjust: Number.isFinite(portalSessionColumnAdjust) ? Math.trunc(portalSessionColumnAdjust) : 0,
79
+ activityPaneAdjust: Number.isFinite(activityPaneAdjust) ? Math.trunc(activityPaneAdjust) : 0,
80
+ };
81
+ }
82
+
83
+ export function normalizeStoredPinnedSessionIds(value) {
84
+ if (!Array.isArray(value)) return [];
85
+ const seen = new Set();
86
+ const out = [];
87
+ for (const entry of value) {
88
+ const id = String(entry || "").trim();
89
+ if (!id || seen.has(id)) continue;
90
+ seen.add(id);
91
+ out.push(id);
92
+ }
93
+ return out;
94
+ }
95
+
96
+ export function normalizeStoredCollapsedSessionIds(value) {
97
+ if (!Array.isArray(value)) return new Set();
98
+ const out = new Set();
99
+ for (const entry of value) {
100
+ const id = String(entry || "").trim();
101
+ if (!id) continue;
102
+ out.add(id);
103
+ }
104
+ return out;
105
+ }
106
+
107
+ export function normalizeStoredActiveSessionId(value) {
108
+ if (value == null) return null;
109
+ const id = String(value).trim();
110
+ return id ? id : null;
111
+ }
112
+
113
+ export function createInitialState({ mode = "local", branding = null, themeId = null, chatViewMode = null, sessionOwnerFilter = null, layoutAdjustments = null, pinnedSessionIds = null, collapsedSessionIds = null, activeSessionId = null } = {}) {
114
+ const hasStoredSessionOwnerFilter = sessionOwnerFilter != null;
115
+ const hasStoredCollapsedSessionIds = collapsedSessionIds != null;
116
+ const initialLayoutAdjustments = normalizeStoredLayoutAdjustments(layoutAdjustments);
117
+ return {
118
+ branding: branding || {
119
+ title: "PilotSwarm",
120
+ splash: "{bold}{cyan-fg}PilotSwarm{/cyan-fg}{/bold}",
121
+ },
122
+ auth: {
123
+ principal: null,
124
+ authorization: null,
125
+ },
126
+ ui: {
127
+ focusRegion: FOCUS_REGIONS.SESSIONS,
128
+ inspectorTab: INSPECTOR_TABS[0],
129
+ chatViewMode: chatViewMode === "summary" ? "summary" : "transcript",
130
+ statsViewMode: "session",
131
+ prompt: "",
132
+ promptCursor: 0,
133
+ promptRows: 1,
134
+ promptAttachments: [],
135
+ promptEdit: null,
136
+ statusText: "Starting PilotSwarm...",
137
+ // A persisted theme id may name a theme that no longer ships —
138
+ // fall back to the default instead of crashing theme consumers.
139
+ themeId: getTheme(themeId)?.id || DEFAULT_THEME_ID,
140
+ modal: null,
141
+ fullscreenPane: null,
142
+ layout: {
143
+ ...initialLayoutAdjustments,
144
+ viewportWidth: 120,
145
+ viewportHeight: 40,
146
+ },
147
+ scroll: {
148
+ chat: 0,
149
+ inspector: 0,
150
+ activity: 0,
151
+ filePreview: 0,
152
+ },
153
+ followBottom: {
154
+ inspector: true,
155
+ activity: true,
156
+ },
157
+ },
158
+ connection: {
159
+ mode,
160
+ connected: false,
161
+ workersOnline: null,
162
+ error: null,
163
+ },
164
+ sessions: {
165
+ byId: {},
166
+ flat: [],
167
+ activeSessionId: normalizeStoredActiveSessionId(activeSessionId),
168
+ collapsedIds: normalizeStoredCollapsedSessionIds(collapsedSessionIds),
169
+ collapsedIdsExplicit: hasStoredCollapsedSessionIds,
170
+ pinnedIds: normalizeStoredPinnedSessionIds(pinnedSessionIds),
171
+ selectedIds: [],
172
+ selectMode: false,
173
+ orderById: {},
174
+ nextOrderOrdinal: 0,
175
+ filterQuery: "",
176
+ ownerFilterExplicit: hasStoredSessionOwnerFilter,
177
+ ownerFilter: normalizeSessionOwnerFilter(sessionOwnerFilter),
178
+ },
179
+ history: {
180
+ bySessionId: new Map(),
181
+ },
182
+ outbox: {
183
+ bySessionId: {},
184
+ },
185
+ orchestration: {
186
+ bySessionId: {},
187
+ },
188
+ executionHistory: {
189
+ bySessionId: {},
190
+ format: "pretty",
191
+ },
192
+ files: {
193
+ bySessionId: {},
194
+ fullscreen: false,
195
+ selectedArtifactId: null,
196
+ filter: {
197
+ scope: "selectedSession",
198
+ query: "",
199
+ },
200
+ },
201
+ logs: {
202
+ available: false,
203
+ availabilityReason: "Log tailing disabled: no K8S_CONTEXT configured in the env file.",
204
+ tailing: false,
205
+ entries: [],
206
+ filter: {
207
+ source: "allNodes",
208
+ level: "all",
209
+ format: "pretty",
210
+ },
211
+ },
212
+ sessionStats: {
213
+ bySessionId: {},
214
+ },
215
+ fleetStats: {
216
+ loading: false,
217
+ data: null,
218
+ userStats: null,
219
+ fetchedAt: 0,
220
+ },
221
+ admin: {
222
+ // Whether the Admin Console is taking over the workspace and
223
+ // hiding the session/chat panes. Persisted only in-memory.
224
+ visible: false,
225
+ loading: false,
226
+ loadError: null,
227
+ // Public profile snapshot from the management API. Never holds
228
+ // the raw GitHub Copilot key — only the `githubCopilotKeySet`
229
+ // boolean flag.
230
+ profile: null,
231
+ ghcpKey: {
232
+ // Editing flag is the single host-neutral signal that the
233
+ // user is composing a new key. Both the portal's inline
234
+ // form and the native TUI's overlay render against this.
235
+ editing: false,
236
+ draft: "",
237
+ // cursorIndex is only consumed by the native TUI overlay
238
+ // (browser <input> elements manage their own cursor). It
239
+ // is kept in shared state so the controller mutators can
240
+ // remain host-neutral.
241
+ cursorIndex: 0,
242
+ saving: false,
243
+ error: null,
244
+ lastSavedAt: 0,
245
+ },
246
+ },
247
+ };
248
+ }
@@ -0,0 +1,23 @@
1
+ export function createStore(reducer, initialState) {
2
+ let state = initialState;
3
+ const listeners = new Set();
4
+
5
+ return {
6
+ getState() {
7
+ return state;
8
+ },
9
+ dispatch(action) {
10
+ const nextState = reducer(state, action);
11
+ if (Object.is(nextState, state)) {
12
+ return action;
13
+ }
14
+ state = nextState;
15
+ for (const listener of listeners) listener(state, action);
16
+ return action;
17
+ },
18
+ subscribe(listener) {
19
+ listeners.add(listener);
20
+ return () => listeners.delete(listener);
21
+ },
22
+ };
23
+ }
@@ -0,0 +1,24 @@
1
+ export function canonicalSystemTitle(session, brandingTitle = "PilotSwarm") {
2
+ const brandedRootTitle = brandingTitle || "PilotSwarm";
3
+ const agentId = String(session?.agentId || "");
4
+ if (agentId === "pilotswarm") return brandedRootTitle;
5
+ if (agentId === "sweeper") return "Sweeper Agent";
6
+ if (agentId === "resourcemgr") return "Resource Manager Agent";
7
+ if (agentId === "facts-manager") return "Facts Manager";
8
+
9
+ const rawTitle = String(session?.title || "").trim();
10
+ if (/^pilotswarm(?: agent)?$/i.test(rawTitle)) return brandedRootTitle;
11
+ if (/^sweeper agent$/i.test(rawTitle) || /^sweeper$/i.test(rawTitle)) return "Sweeper Agent";
12
+ if (/^resource manager agent$/i.test(rawTitle) || /^resourcemgr$/i.test(rawTitle)) return "Resource Manager Agent";
13
+ if (/^facts manager$/i.test(rawTitle) || /^facts-manager$/i.test(rawTitle)) return "Facts Manager";
14
+ return rawTitle || "System Agent";
15
+ }
16
+
17
+ export function systemSessionSortOrder(session) {
18
+ const title = canonicalSystemTitle(session, "PilotSwarm");
19
+ if (title === "PilotSwarm") return 0;
20
+ if (title === "Sweeper Agent") return 1;
21
+ if (title === "Resource Manager Agent") return 2;
22
+ if (title === "Facts Manager") return 3;
23
+ return 10;
24
+ }
@@ -0,0 +1,56 @@
1
+ import { createTheme } from "./helpers.js";
2
+
3
+ const catppuccinMochaTheme = createTheme({
4
+ id: "catppuccin-mocha",
5
+ label: "Catppuccin Mocha",
6
+ description: "Creamy dark palette with soft pastels and high legibility.",
7
+ page: {
8
+ background: "#1e1e2e",
9
+ foreground: "#cdd6f4",
10
+ overlayBackground: "#1e1e2e",
11
+ overlayForeground: "#cdd6f4",
12
+ hintColor: "#bac2de",
13
+ modalBackdrop: "rgba(17, 17, 27, 0.74)",
14
+ modalBackground: "#313244",
15
+ modalBorder: "#585b70",
16
+ modalForeground: "#cdd6f4",
17
+ modalMuted: "#bac2de",
18
+ modalSelectedBackground: "#45475a",
19
+ modalSelectedBorder: "#89b4fa",
20
+ modalSelectedForeground: "#cdd6f4",
21
+ },
22
+ terminal: {
23
+ background: "#1e1e2e",
24
+ foreground: "#cdd6f4",
25
+ cursor: "#f5e0dc",
26
+ cursorAccent: "#1e1e2e",
27
+ selectionBackground: "rgba(137, 180, 250, 0.22)",
28
+ black: "#45475a",
29
+ red: "#f38ba8",
30
+ green: "#a6e3a1",
31
+ yellow: "#f9e2af",
32
+ blue: "#89b4fa",
33
+ magenta: "#f5c2e7",
34
+ cyan: "#94e2d5",
35
+ white: "#bac2de",
36
+ brightBlack: "#585b70",
37
+ brightRed: "#f38ba8",
38
+ brightGreen: "#a6e3a1",
39
+ brightYellow: "#f9e2af",
40
+ brightBlue: "#89b4fa",
41
+ brightMagenta: "#f5c2e7",
42
+ brightCyan: "#94e2d5",
43
+ brightWhite: "#f5e0dc",
44
+ },
45
+ tui: {
46
+ surface: "#1e1e2e",
47
+ activeHighlightBackground: "#45475a",
48
+ activeHighlightForeground: "#cdd6f4",
49
+ selectionBackground: "#89b4fa",
50
+ selectionForeground: "#1e1e2e",
51
+ promptCursorBackground: "#f5e0dc",
52
+ promptCursorForeground: "#1e1e2e",
53
+ },
54
+ });
55
+
56
+ export default catppuccinMochaTheme;
@@ -0,0 +1,56 @@
1
+ import { createTheme } from "./helpers.js";
2
+
3
+ const cobalt2Theme = createTheme({
4
+ id: "cobalt2",
5
+ label: "Cobalt2",
6
+ description: "Electric blue shell with bright yellow accents and saturated syntax colors.",
7
+ page: {
8
+ background: "#193549",
9
+ foreground: "#ffffff",
10
+ overlayBackground: "#193549",
11
+ overlayForeground: "#ffffff",
12
+ hintColor: "#a8c5e6",
13
+ modalBackdrop: "rgba(7, 17, 28, 0.68)",
14
+ modalBackground: "#224b68",
15
+ modalBorder: "#2e6c99",
16
+ modalForeground: "#ffffff",
17
+ modalMuted: "#a8c5e6",
18
+ modalSelectedBackground: "#ffc600",
19
+ modalSelectedBorder: "#ffc600",
20
+ modalSelectedForeground: "#193549",
21
+ },
22
+ terminal: {
23
+ background: "#193549",
24
+ foreground: "#ffffff",
25
+ cursor: "#ffc600",
26
+ cursorAccent: "#193549",
27
+ selectionBackground: "rgba(255, 255, 255, 0.18)",
28
+ black: "#000000",
29
+ red: "#ff628c",
30
+ green: "#3ad900",
31
+ yellow: "#ff9d00",
32
+ blue: "#0088ff",
33
+ magenta: "#ff628c",
34
+ cyan: "#80ffbb",
35
+ white: "#ffffff",
36
+ brightBlack: "#666666",
37
+ brightRed: "#ff628c",
38
+ brightGreen: "#3ad900",
39
+ brightYellow: "#ff9d00",
40
+ brightBlue: "#0088ff",
41
+ brightMagenta: "#ff9d00",
42
+ brightCyan: "#80ffbb",
43
+ brightWhite: "#ffffff",
44
+ },
45
+ tui: {
46
+ surface: "#193549",
47
+ activeHighlightBackground: "#0f5f91",
48
+ activeHighlightForeground: "#ffffff",
49
+ selectionBackground: "#ffc600",
50
+ selectionForeground: "#193549",
51
+ promptCursorBackground: "#ffc600",
52
+ promptCursorForeground: "#193549",
53
+ },
54
+ });
55
+
56
+ export default cobalt2Theme;
@@ -0,0 +1,56 @@
1
+ import { createTheme } from "./helpers.js";
2
+
3
+ const darkHighContrastTheme = createTheme({
4
+ id: "dark-high-contrast",
5
+ label: "Dark High Contrast",
6
+ description: "Pure black background with maximum contrast ANSI colors for accessibility.",
7
+ page: {
8
+ background: "#000000",
9
+ foreground: "#ffffff",
10
+ overlayBackground: "#000000",
11
+ overlayForeground: "#ffffff",
12
+ hintColor: "#3794ff",
13
+ modalBackdrop: "rgba(0, 0, 0, 0.85)",
14
+ modalBackground: "#0c0c0c",
15
+ modalBorder: "#6fc3df",
16
+ modalForeground: "#ffffff",
17
+ modalMuted: "#9d9d9d",
18
+ modalSelectedBackground: "#0f4a85",
19
+ modalSelectedBorder: "#f38518",
20
+ modalSelectedForeground: "#ffffff",
21
+ },
22
+ terminal: {
23
+ background: "#000000",
24
+ foreground: "#ffffff",
25
+ cursor: "#ffffff",
26
+ cursorAccent: "#000000",
27
+ selectionBackground: "rgba(255, 255, 255, 0.3)",
28
+ black: "#000000",
29
+ red: "#f44747",
30
+ green: "#73c991",
31
+ yellow: "#e5e510",
32
+ blue: "#3794ff",
33
+ magenta: "#bc3fbc",
34
+ cyan: "#29b8db",
35
+ white: "#e5e5e5",
36
+ brightBlack: "#666666",
37
+ brightRed: "#f14c4c",
38
+ brightGreen: "#89d185",
39
+ brightYellow: "#f5f543",
40
+ brightBlue: "#6fc3df",
41
+ brightMagenta: "#d670d6",
42
+ brightCyan: "#2ee2e2",
43
+ brightWhite: "#ffffff",
44
+ },
45
+ tui: {
46
+ surface: "#000000",
47
+ activeHighlightBackground: "#0f4a85",
48
+ activeHighlightForeground: "#ffffff",
49
+ selectionBackground: "#f38518",
50
+ selectionForeground: "#000000",
51
+ promptCursorBackground: "#ffffff",
52
+ promptCursorForeground: "#000000",
53
+ },
54
+ });
55
+
56
+ export default darkHighContrastTheme;