@a-company/paradigm 3.43.0 → 3.46.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 (37) hide show
  1. package/dist/{chunk-YW5OCVKB.js → chunk-FKJUBQU3.js} +14 -1
  2. package/dist/chunk-KVDYJLTC.js +121 -0
  3. package/dist/{symphony-ROEKK7VD.js → chunk-S2HO5MLR.js} +53 -431
  4. package/dist/{chunk-RGFANZ4Q.js → chunk-ZDHLG5VP.js} +14 -1
  5. package/dist/{chunk-CZEIK3Y2.js → chunk-ZMQA6SCO.js} +1 -1
  6. package/dist/{chunk-7WEKMZ46.js → chunk-ZSYVKSY6.js} +1 -1
  7. package/dist/{commands-LEPFD7S5.js → commands-5N4ILTPH.js} +13 -0
  8. package/dist/{dist-RVKYUCRU.js → dist-CM3MVWWW.js} +1 -1
  9. package/dist/{dist-Y7I3CFY5.js → dist-POMVY6WP.js} +2 -2
  10. package/dist/{habits-O37HTUKE.js → habits-RG5SVKXP.js} +2 -2
  11. package/dist/index.js +69 -48
  12. package/dist/mcp.js +89 -9
  13. package/dist/peers-RFQCWVLV.js +82 -0
  14. package/dist/{platform-server-KK4OCRTV.js → platform-server-H7Y6Q7O4.js} +10 -1
  15. package/dist/{reindex-NZQRGKPN.js → reindex-WIJMCJ4A.js} +1 -1
  16. package/dist/{sentinel-BKYTBT7M.js → sentinel-UOIGJWHH.js} +1 -1
  17. package/dist/{sentinel-bridge-IZTXYS5M.js → sentinel-bridge-APDXYAZS.js} +1 -1
  18. package/dist/sentinel-mcp.js +13 -0
  19. package/dist/sentinel.js +6 -6
  20. package/dist/{serve-3V2WXLGM.js → serve-KKEHE44G.js} +1 -1
  21. package/dist/{server-OFEJ2HJP.js → server-JV6UFGWZ.js} +1 -1
  22. package/dist/symphony-6K3HD7AW.js +791 -0
  23. package/dist/symphony-YCHBYN3E.js +326 -0
  24. package/dist/symphony-peers-APOGJPF4.js +120 -0
  25. package/dist/symphony-peers-HSY3RI3S.js +34 -0
  26. package/dist/symphony-relay-GTAJRCVF.js +683 -0
  27. package/dist/{triage-POXJ2TIX.js → triage-IZ4MDYNB.js} +2 -2
  28. package/dist/university-content/courses/para-501.json +84 -0
  29. package/package.json +1 -1
  30. package/platform-ui/dist/assets/{GitSection-DvyJBF_-.js → GitSection-BD3Ze06e.js} +1 -1
  31. package/platform-ui/dist/assets/{GraphSection-BiQrXqfs.js → GraphSection-SglITfSs.js} +1 -1
  32. package/platform-ui/dist/assets/{LoreSection-BaH1FaRb.js → LoreSection-bR5Km4Fd.js} +1 -1
  33. package/platform-ui/dist/assets/{SentinelSection-DemAznjI.js → SentinelSection-QSpAZArG.js} +1 -1
  34. package/platform-ui/dist/assets/SymphonySection-CobYJgvg.js +1 -0
  35. package/platform-ui/dist/assets/SymphonySection-zY0C5tFl.css +1 -0
  36. package/platform-ui/dist/assets/{index-DDKhCt-w.js → index-DbxeSMkV.js} +11 -11
  37. package/platform-ui/dist/index.html +1 -1
@@ -0,0 +1,326 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ approveFileRequest,
4
+ buildMessage,
5
+ cleanStaleAgents,
6
+ createThread,
7
+ denyFileRequest,
8
+ discoverClaudeCodeSessions,
9
+ expireOldRequests,
10
+ getMyIdentity,
11
+ getThreadMessages,
12
+ isAgentAsleep,
13
+ listAgents,
14
+ listFileRequests,
15
+ listThreads,
16
+ loadThread,
17
+ readInbox,
18
+ resolveAgentIdentity,
19
+ resolveThread,
20
+ routeMessage
21
+ } from "./chunk-S2HO5MLR.js";
22
+ import "./chunk-ZXMDA7VB.js";
23
+
24
+ // src/platform-server/routes/symphony.ts
25
+ import { Router } from "express";
26
+ function createSymphonyRouter(projectDir, broadcast) {
27
+ const router = Router();
28
+ router.get("/agents", (_req, res) => {
29
+ try {
30
+ cleanStaleAgents();
31
+ const agents = listAgents();
32
+ const discovered = discoverClaudeCodeSessions();
33
+ const agentIds = new Set(agents.map((a) => a.id));
34
+ for (const d of discovered) {
35
+ if (!agentIds.has(d.id)) agents.push(d);
36
+ }
37
+ const result = agents.map((a) => ({
38
+ id: a.id,
39
+ name: a.name,
40
+ project: a.project,
41
+ role: a.role,
42
+ status: isAgentAsleep(a) ? "asleep" : "awake",
43
+ lastPoll: a.lastPoll,
44
+ startedAt: a.startedAt,
45
+ statusBlurb: a.statusBlurb
46
+ }));
47
+ res.json({ agents: result });
48
+ } catch (err) {
49
+ res.status(500).json({ error: "Failed to list agents", detail: String(err) });
50
+ }
51
+ });
52
+ router.get("/agents/me", (_req, res) => {
53
+ try {
54
+ const identity = getMyIdentity(projectDir);
55
+ res.json({ identity: identity || null });
56
+ } catch (err) {
57
+ res.status(500).json({ error: "Failed to get identity", detail: String(err) });
58
+ }
59
+ });
60
+ router.get("/peers", async (_req, res) => {
61
+ try {
62
+ const { loadPeers } = await import("./symphony-peers-HSY3RI3S.js");
63
+ const peers = loadPeers();
64
+ const result = peers.map((p) => ({
65
+ id: p.id,
66
+ displayName: p.displayName,
67
+ address: p.address,
68
+ connectedAt: p.connectedAt,
69
+ lastSeen: p.lastSeen,
70
+ revoked: p.revoked,
71
+ agents: p.agents || []
72
+ }));
73
+ res.json({ peers: result });
74
+ } catch (err) {
75
+ res.status(500).json({ error: "Failed to list peers", detail: String(err) });
76
+ }
77
+ });
78
+ router.get("/threads", (req, res) => {
79
+ try {
80
+ const statusParam = req.query.status;
81
+ let status;
82
+ if (statusParam === "active" || statusParam === "resolved") {
83
+ status = statusParam;
84
+ }
85
+ const threads = listThreads(status);
86
+ const result = threads.map((t) => ({
87
+ id: t.id,
88
+ topic: t.topic,
89
+ status: t.status,
90
+ participants: t.participants.map((p) => ({ id: p.id, name: p.name, type: p.type })),
91
+ messageCount: t.messageCount,
92
+ lastActivity: t.lastActivity,
93
+ decision: t.decision
94
+ }));
95
+ res.json({ threads: result });
96
+ } catch (err) {
97
+ res.status(500).json({ error: "Failed to list threads", detail: String(err) });
98
+ }
99
+ });
100
+ router.get("/threads/:threadId", (req, res) => {
101
+ try {
102
+ const { threadId } = req.params;
103
+ const thread = loadThread(threadId);
104
+ if (!thread) {
105
+ res.status(404).json({ error: `Thread not found: ${threadId}` });
106
+ return;
107
+ }
108
+ const messages = getThreadMessages(threadId);
109
+ const symbolsDiscussed = /* @__PURE__ */ new Set();
110
+ for (const msg of messages) {
111
+ for (const sym of msg.symbols) symbolsDiscussed.add(sym);
112
+ }
113
+ res.json({
114
+ thread: {
115
+ id: thread.id,
116
+ topic: thread.topic,
117
+ status: thread.status,
118
+ participants: thread.participants.map((p) => ({ id: p.id, name: p.name, type: p.type })),
119
+ messageCount: thread.messageCount,
120
+ lastActivity: thread.lastActivity,
121
+ decision: thread.decision
122
+ },
123
+ messages: messages.map((m) => ({
124
+ id: m.id,
125
+ sender: { id: m.sender.id, name: m.sender.name, type: m.sender.type },
126
+ intent: m.intent,
127
+ text: m.content.text,
128
+ timestamp: m.timestamp,
129
+ symbols: m.symbols,
130
+ diff: m.content.diff,
131
+ decision: m.content.decision,
132
+ recipients: m.recipients?.map((r) => ({ id: r.id, name: r.name }))
133
+ })),
134
+ symbolsDiscussed: [...symbolsDiscussed]
135
+ });
136
+ } catch (err) {
137
+ res.status(500).json({ error: "Failed to load thread", detail: String(err) });
138
+ }
139
+ });
140
+ router.post("/threads/:threadId/resolve", (req, res) => {
141
+ try {
142
+ const { threadId } = req.params;
143
+ const { decision } = req.body;
144
+ const success = resolveThread(threadId, decision);
145
+ if (!success) {
146
+ res.status(404).json({ error: `Thread not found: ${threadId}` });
147
+ return;
148
+ }
149
+ if (broadcast) {
150
+ broadcast({ type: "symphony:thread_resolved", threadId, decision });
151
+ }
152
+ res.json({ resolved: true, threadId, decision });
153
+ } catch (err) {
154
+ res.status(500).json({ error: "Failed to resolve thread", detail: String(err) });
155
+ }
156
+ });
157
+ router.post("/messages", (req, res) => {
158
+ try {
159
+ const { intent, text, threadRoot, recipients, symbols, diff, decision } = req.body;
160
+ if (!intent || !text) {
161
+ res.status(400).json({ error: "intent and text are required" });
162
+ return;
163
+ }
164
+ const agentId = resolveAgentIdentity(projectDir);
165
+ const sender = {
166
+ id: `human/${agentId}`,
167
+ name: "Human (Platform UI)",
168
+ type: "human"
169
+ };
170
+ let effectiveThreadRoot = threadRoot;
171
+ let threadCreated = false;
172
+ if (!threadRoot) {
173
+ const topic = text.length > 60 ? text.slice(0, 60) + "..." : text;
174
+ const thread = createThread(topic, sender);
175
+ effectiveThreadRoot = thread.id;
176
+ threadCreated = true;
177
+ }
178
+ let resolvedRecipients;
179
+ if (recipients && recipients.length > 0) {
180
+ const allAgents = listAgents();
181
+ resolvedRecipients = recipients.map((id) => {
182
+ const agent = allAgents.find((a) => a.id === id);
183
+ if (agent) return { id: agent.id, name: agent.name, type: "agent" };
184
+ return { id, name: id, type: "agent" };
185
+ });
186
+ }
187
+ const message = buildMessage({
188
+ sender,
189
+ recipients: resolvedRecipients,
190
+ intent,
191
+ text,
192
+ threadRoot: effectiveThreadRoot,
193
+ symbols,
194
+ diff,
195
+ decision
196
+ });
197
+ const deliveryCount = routeMessage(message);
198
+ if (broadcast) {
199
+ broadcast({
200
+ type: "symphony:message",
201
+ message: {
202
+ id: message.id,
203
+ sender: { id: sender.id, name: sender.name, type: sender.type },
204
+ intent: message.intent,
205
+ text: message.content.text,
206
+ timestamp: message.timestamp,
207
+ symbols: message.symbols,
208
+ diff: message.content.diff,
209
+ decision: message.content.decision
210
+ },
211
+ threadId: effectiveThreadRoot
212
+ });
213
+ }
214
+ res.json({
215
+ sent: true,
216
+ messageId: message.id,
217
+ threadId: effectiveThreadRoot,
218
+ threadCreated,
219
+ deliveredTo: deliveryCount
220
+ });
221
+ } catch (err) {
222
+ res.status(500).json({ error: "Failed to send message", detail: String(err) });
223
+ }
224
+ });
225
+ router.get("/inbox", (_req, res) => {
226
+ try {
227
+ const agentId = resolveAgentIdentity(projectDir);
228
+ const messages = readInbox(agentId);
229
+ res.json({
230
+ agentId,
231
+ messages: messages.map((m) => ({
232
+ id: m.id,
233
+ sender: { id: m.sender.id, name: m.sender.name, type: m.sender.type },
234
+ intent: m.intent,
235
+ text: m.content.text,
236
+ timestamp: m.timestamp,
237
+ threadRoot: m.threadRoot,
238
+ symbols: m.symbols
239
+ }))
240
+ });
241
+ } catch (err) {
242
+ res.status(500).json({ error: "Failed to read inbox", detail: String(err) });
243
+ }
244
+ });
245
+ router.get("/file-requests", (req, res) => {
246
+ try {
247
+ expireOldRequests();
248
+ const statusParam = req.query.status;
249
+ let status;
250
+ if (statusParam === "pending" || statusParam === "approved" || statusParam === "denied" || statusParam === "expired") {
251
+ status = statusParam;
252
+ }
253
+ const requests = listFileRequests(status);
254
+ const result = requests.map((r) => ({
255
+ requestId: r.request.requestId,
256
+ filePath: r.request.filePath,
257
+ reason: r.request.reason,
258
+ requester: { id: r.request.requester.id, name: r.request.requester.name },
259
+ urgency: r.request.urgency,
260
+ snippet: r.request.snippet,
261
+ status: r.status,
262
+ createdAt: r.createdAt,
263
+ resolvedAt: r.resolvedAt,
264
+ denyReason: r.denyReason
265
+ }));
266
+ res.json({ fileRequests: result });
267
+ } catch (err) {
268
+ res.status(500).json({ error: "Failed to list file requests", detail: String(err) });
269
+ }
270
+ });
271
+ router.post("/file-requests/:requestId/action", (req, res) => {
272
+ try {
273
+ const { requestId } = req.params;
274
+ const { action, reason } = req.body;
275
+ if (!action) {
276
+ res.status(400).json({ error: "action is required" });
277
+ return;
278
+ }
279
+ if (action === "deny") {
280
+ const success = denyFileRequest(requestId, reason);
281
+ res.json({ success, requestId, action: "denied", reason });
282
+ return;
283
+ }
284
+ const redact = action === "approve-redacted";
285
+ const result = approveFileRequest(requestId, projectDir, redact);
286
+ if (!result.success) {
287
+ res.status(400).json({ success: false, requestId, error: result.error });
288
+ return;
289
+ }
290
+ res.json({
291
+ success: true,
292
+ requestId,
293
+ action: redact ? "approved-redacted" : "approved",
294
+ filePath: result.delivery?.filePath,
295
+ size: result.delivery?.size
296
+ });
297
+ } catch (err) {
298
+ res.status(500).json({ error: "Failed to handle file request", detail: String(err) });
299
+ }
300
+ });
301
+ router.get("/status", (_req, res) => {
302
+ try {
303
+ cleanStaleAgents();
304
+ const agents = listAgents();
305
+ const awake = agents.filter((a) => !isAgentAsleep(a)).length;
306
+ const threads = listThreads("active");
307
+ const agentId = resolveAgentIdentity(projectDir);
308
+ const unread = readInbox(agentId);
309
+ const pendingRequests = listFileRequests("pending");
310
+ res.json({
311
+ agentCount: agents.length,
312
+ awakeCount: awake,
313
+ asleepCount: agents.length - awake,
314
+ activeThreadCount: threads.length,
315
+ unreadCount: unread.length,
316
+ pendingFileRequests: pendingRequests.length
317
+ });
318
+ } catch (err) {
319
+ res.status(500).json({ error: "Failed to get status", detail: String(err) });
320
+ }
321
+ });
322
+ return router;
323
+ }
324
+ export {
325
+ createSymphonyRouter
326
+ };
@@ -0,0 +1,120 @@
1
+ #!/usr/bin/env node
2
+
3
+ // ../paradigm-mcp/src/utils/symphony-peers.ts
4
+ import * as fs from "fs";
5
+ import * as path from "path";
6
+ import * as os from "os";
7
+ import * as crypto from "crypto";
8
+ var SCORE_DIR = path.join(os.homedir(), ".paradigm", "score");
9
+ var PEERS_FILE = path.join(SCORE_DIR, "peers.json");
10
+ var PAIRING_TTL_MS = 5 * 60 * 1e3;
11
+ function loadPeers() {
12
+ try {
13
+ if (!fs.existsSync(PEERS_FILE)) return [];
14
+ const content = fs.readFileSync(PEERS_FILE, "utf-8");
15
+ const parsed = JSON.parse(content);
16
+ if (!Array.isArray(parsed)) return [];
17
+ return parsed;
18
+ } catch {
19
+ return [];
20
+ }
21
+ }
22
+ function savePeers(peers) {
23
+ if (!fs.existsSync(SCORE_DIR)) {
24
+ fs.mkdirSync(SCORE_DIR, { recursive: true });
25
+ }
26
+ fs.writeFileSync(PEERS_FILE, JSON.stringify(peers, null, 2), { mode: 384 });
27
+ }
28
+ function findPeer(id) {
29
+ const peers = loadPeers();
30
+ return peers.find((p) => p.id === id) ?? null;
31
+ }
32
+ function addPeer(peer) {
33
+ const peers = loadPeers();
34
+ const idx = peers.findIndex((p) => p.id === peer.id);
35
+ if (idx >= 0) {
36
+ peers[idx] = peer;
37
+ } else {
38
+ peers.push(peer);
39
+ }
40
+ savePeers(peers);
41
+ }
42
+ function revokePeer(id) {
43
+ const peers = loadPeers();
44
+ const peer = peers.find((p) => p.id === id);
45
+ if (!peer) return false;
46
+ peer.revoked = true;
47
+ savePeers(peers);
48
+ return true;
49
+ }
50
+ function forgetAllPeers() {
51
+ const peers = loadPeers();
52
+ const count = peers.length;
53
+ if (fs.existsSync(PEERS_FILE)) {
54
+ fs.unlinkSync(PEERS_FILE);
55
+ }
56
+ return count;
57
+ }
58
+ function updatePeerLastSeen(id) {
59
+ const peers = loadPeers();
60
+ const peer = peers.find((p) => p.id === id);
61
+ if (!peer) return;
62
+ peer.lastSeen = (/* @__PURE__ */ new Date()).toISOString();
63
+ savePeers(peers);
64
+ }
65
+ function updatePeerAgents(id, agents) {
66
+ const peers = loadPeers();
67
+ const peer = peers.find((p) => p.id === id);
68
+ if (!peer) return;
69
+ peer.agents = agents;
70
+ savePeers(peers);
71
+ }
72
+ function generatePairing() {
73
+ const sharedSecret = crypto.randomBytes(32).toString("hex");
74
+ const code = (parseInt(crypto.randomBytes(3).toString("hex"), 16) % 1e6).toString().padStart(6, "0");
75
+ const codeHash = crypto.createHash("sha256").update(code).digest("hex");
76
+ return {
77
+ code,
78
+ codeHash,
79
+ sharedSecret,
80
+ createdAt: Date.now()
81
+ };
82
+ }
83
+ function verifyPairingCode(state, code) {
84
+ if (Date.now() - state.createdAt > PAIRING_TTL_MS) {
85
+ return false;
86
+ }
87
+ const hash = crypto.createHash("sha256").update(code).digest("hex");
88
+ return hash === state.codeHash;
89
+ }
90
+ function computeHmacProof(challenge, codeHash) {
91
+ return crypto.createHmac("sha256", codeHash).update(challenge).digest("hex");
92
+ }
93
+ function verifyHmacProof(challenge, codeHash, proof) {
94
+ const expected = computeHmacProof(challenge, codeHash);
95
+ if (expected.length !== proof.length) return false;
96
+ try {
97
+ return crypto.timingSafeEqual(
98
+ Buffer.from(expected, "hex"),
99
+ Buffer.from(proof, "hex")
100
+ );
101
+ } catch {
102
+ return false;
103
+ }
104
+ }
105
+ export {
106
+ PAIRING_TTL_MS,
107
+ PEERS_FILE,
108
+ addPeer,
109
+ computeHmacProof,
110
+ findPeer,
111
+ forgetAllPeers,
112
+ generatePairing,
113
+ loadPeers,
114
+ revokePeer,
115
+ savePeers,
116
+ updatePeerAgents,
117
+ updatePeerLastSeen,
118
+ verifyHmacProof,
119
+ verifyPairingCode
120
+ };
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ PAIRING_TTL_MS,
4
+ PEERS_FILE,
5
+ addPeer,
6
+ computeHmacProof,
7
+ findPeer,
8
+ forgetAllPeers,
9
+ generatePairing,
10
+ loadPeers,
11
+ revokePeer,
12
+ savePeers,
13
+ updatePeerAgents,
14
+ updatePeerLastSeen,
15
+ verifyHmacProof,
16
+ verifyPairingCode
17
+ } from "./chunk-KVDYJLTC.js";
18
+ import "./chunk-ZXMDA7VB.js";
19
+ export {
20
+ PAIRING_TTL_MS,
21
+ PEERS_FILE,
22
+ addPeer,
23
+ computeHmacProof,
24
+ findPeer,
25
+ forgetAllPeers,
26
+ generatePairing,
27
+ loadPeers,
28
+ revokePeer,
29
+ savePeers,
30
+ updatePeerAgents,
31
+ updatePeerLastSeen,
32
+ verifyHmacProof,
33
+ verifyPairingCode
34
+ };