@cotal-ai/web 0.0.0 → 0.11.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.
package/dist/web.js ADDED
@@ -0,0 +1,327 @@
1
+ import { spawn } from "node:child_process";
2
+ import { createServer } from "node:http";
3
+ import { closeSync, openSync, readFileSync, rmSync, writeFileSync } from "node:fs";
4
+ import { fileURLToPath } from "node:url";
5
+ import { dirname, join } from "node:path";
6
+ import { CotalEndpoint, deliveryOf, parseSubject, spaceWildcard, mintCreds, newIdentity, clearChannel, } from "@cotal-ai/core";
7
+ import { c, connectOrExit, localProcessPath, userViewAuth, userViewAuthOrExit, } from "@cotal-ai/workspace";
8
+ const here = dirname(fileURLToPath(import.meta.url));
9
+ /** The dashboard's default port and its branded address. The server binds loopback
10
+ * (127.0.0.1) but serves any Host, so `cotal.localhost` — which Chrome/Firefox/Edge
11
+ * resolve to loopback with no DNS setup — just works. (Safari may not resolve
12
+ * `*.localhost`; plain http://127.0.0.1:7799 always does.) */
13
+ export const WEB_PORT = 7799;
14
+ export const WEB_URL = `http://cotal.localhost:${WEB_PORT}/`;
15
+ export const webProcess = {
16
+ kind: "local-process",
17
+ name: "web",
18
+ label: "web dashboard",
19
+ order: 40,
20
+ pidFile: "web.pid",
21
+ };
22
+ function pidAlive(pid) {
23
+ if (!Number.isInteger(pid) || pid <= 0)
24
+ return false;
25
+ try {
26
+ process.kill(pid, 0);
27
+ return true;
28
+ }
29
+ catch (e) {
30
+ return e.code === "EPERM";
31
+ }
32
+ }
33
+ /** Atomically claim this mesh's web pidfile so concurrent custom-port launches cannot overwrite it. */
34
+ function claimPid(path) {
35
+ let created = false;
36
+ try {
37
+ const fd = openSync(path, "wx", 0o600);
38
+ created = true;
39
+ try {
40
+ writeFileSync(fd, String(process.pid));
41
+ }
42
+ finally {
43
+ closeSync(fd);
44
+ }
45
+ }
46
+ catch (e) {
47
+ if (created)
48
+ rmSync(path, { force: true });
49
+ if (e.code !== "EEXIST")
50
+ throw e;
51
+ const raw = readFileSync(path, "utf8").trim();
52
+ if (raw.startsWith("removing:")) {
53
+ const owner = Number(raw.slice("removing:".length));
54
+ throw new Error(pidAlive(owner)
55
+ ? `web extension removal is in progress (pid ${owner})`
56
+ : `web dashboard has a stale extension-removal reservation at ${path} - remove it and retry`);
57
+ }
58
+ const prior = Number(raw);
59
+ if (pidAlive(prior))
60
+ throw new Error(`web dashboard is already running for this mesh (pid ${prior})`);
61
+ throw new Error(`web dashboard has a stale pidfile at ${path} - clean it with \`cotal down web\`, then retry`);
62
+ }
63
+ }
64
+ function releasePid(path) {
65
+ try {
66
+ if (readFileSync(path, "utf8").trim() === String(process.pid))
67
+ rmSync(path, { force: true });
68
+ }
69
+ catch {
70
+ // Already removed by `down` or another cleanup path.
71
+ }
72
+ }
73
+ const PAGE = {
74
+ "/": { path: join(here, "web/index.html"), type: "text/html; charset=utf-8" },
75
+ "/app.js": { path: join(here, "web/app.js"), type: "text/javascript; charset=utf-8" },
76
+ "/graph": { path: join(here, "web/graph.html"), type: "text/html; charset=utf-8" },
77
+ "/graph.js": { path: join(here, "web/graph.js"), type: "text/javascript; charset=utf-8" },
78
+ };
79
+ /** A live observability dashboard for a space, served over HTTP + SSE. A read-only
80
+ * observer endpoint (invisible to peers) feeds the page presence, channel history,
81
+ * and a live message stream — no manager required. Bound to loopback. */
82
+ export async function web(args) {
83
+ const values = args.values;
84
+ // Resolve WHICH running mesh + creds (admin god-view: shows DMs + anycast), then DROP the account
85
+ // seed. The dashboard is a loopback HTTP process; holding the space signing seed (`auth` — it can
86
+ // mint ANY identity/role) for the whole session would make a dashboard compromise = full account
87
+ // control. Instead pre-mint ONE scoped `channel-purger` cred for the only write path (channel delete
88
+ // = filtered CHAT purge + a channel-registry key delete) and let the seed fall out of scope here, so
89
+ // it isn't reachable from the request handlers. `--creds` / open mode have no seed → the connection
90
+ // creds carry the purge rights.
91
+ //
92
+ // USER MODE: the god view rides an exchange-gated "admin" VIEW bearer (ledger scope "admin",
93
+ // fresh-checked at every mint and every connect) — standing via a bearer SOURCE so the tap
94
+ // survives the ≤5-minute token life. No pre-minted purge cred: channel delete mints a one-shot
95
+ // "channel-purger" view per action, so each destructive click is a fresh ledger check, and
96
+ // `cotal actor revoke` kills the dashboard live (eviction) while a scope edit bites at the next
97
+ // refresh.
98
+ const { conn, user } = await (async () => {
99
+ const conn = await connectOrExit(values, "admin");
100
+ return { conn, user: conn.bearer ? await userViewAuthOrExit(conn, "admin") : undefined };
101
+ })();
102
+ const { server, space } = conn;
103
+ const pidPath = conn.root ? localProcessPath(webProcess.pidFile, { root: conn.root, space }) : undefined;
104
+ if (pidPath) {
105
+ claimPid(pidPath);
106
+ process.once("exit", () => releasePid(pidPath));
107
+ }
108
+ const purgeCreds = !user && conn.auth ? await mintCreds(conn.auth, newIdentity(), "channel-purger") : conn.creds;
109
+ const port = values.port ? Number(values.port) : WEB_PORT;
110
+ // Observer: never registers presence, never consumes an inbox — invisible to peers.
111
+ const ep = new CotalEndpoint({
112
+ space,
113
+ servers: server,
114
+ ...(user
115
+ ? { bearer: user.source, sentinelCreds: user.sentinelCreds, card: { owner: user.owner, actor: user.actor, name: "web", kind: "endpoint" } }
116
+ : { creds: conn.creds, card: { name: "web", kind: "endpoint" } }),
117
+ channels: [],
118
+ consume: false, // observer: reads via tap + history + presence-watch, binds no durables
119
+ registerPresence: false,
120
+ watchPresence: true,
121
+ });
122
+ ep.on("error", (e) => console.error(c.red("! " + e.message)));
123
+ await ep.start();
124
+ const clients = new Set();
125
+ const send = (res, event, data) => res.write(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`);
126
+ const broadcast = (event, data) => {
127
+ for (const res of clients)
128
+ if (!res.writableEnded)
129
+ send(res, event, data);
130
+ };
131
+ // Presence changes → push the whole roster; the client just re-renders it.
132
+ ep.on("presence", () => broadcast("roster", ep.getRoster()));
133
+ // Broker-sourced channel membership (the authoritative graph spokes): push a `membership` SSE event
134
+ // on every feed change (debounced; the client re-reads the snapshot). Best-effort — a space without the
135
+ // feed (no delivery daemon, or provisioned before this feature) simply never emits, and the graph
136
+ // degrades to traffic-only. The admin cred carries the read grant; agents never do.
137
+ let membershipWatch;
138
+ const pushMembership = debounce(() => {
139
+ void ep.readMembership().then((m) => broadcast("membership", m)).catch(() => { });
140
+ }, 150);
141
+ try {
142
+ membershipWatch = await ep.watchMembership(pushMembership);
143
+ }
144
+ catch (e) {
145
+ console.error(c.dim(`• membership feed unavailable - graph shows traffic only (${e.message})`));
146
+ }
147
+ // Every comm on the mesh (chat / unicast / anycast) → push to the live feed. The admin cred
148
+ // allows the whole space, so the observer taps everything — DMs + anycast included.
149
+ const tapSubject = spaceWildcard(space);
150
+ ep.tap((subject, msg) => {
151
+ const mode = deliveryOf(subject);
152
+ if (!mode || !msg)
153
+ return;
154
+ // senderId is the subject's sender token — the *verified* publisher (the server
155
+ // policed who could publish it), vs the advisory `from` in the payload.
156
+ const senderId = parseSubject(subject)?.sender;
157
+ broadcast("message", { mode, senderId, msg });
158
+ }, { subject: tapSubject });
159
+ const httpServer = createServer(async (req, res) => {
160
+ const path = (req.url ?? "/").split("?")[0];
161
+ const query = new URLSearchParams((req.url ?? "").split("?")[1] ?? "");
162
+ if (path === "/feed") {
163
+ res.writeHead(200, {
164
+ "content-type": "text/event-stream",
165
+ "cache-control": "no-cache",
166
+ connection: "keep-alive",
167
+ });
168
+ clients.add(res);
169
+ send(res, "roster", ep.getRoster());
170
+ // Seed this client's graph with the current membership snapshot (the live tap only carries
171
+ // post-connect traffic; membership is state, so a fresh client needs it explicitly).
172
+ void ep.readMembership().then((m) => { if (!res.writableEnded)
173
+ send(res, "membership", m); }).catch(() => { });
174
+ req.on("close", () => clients.delete(res));
175
+ return;
176
+ }
177
+ if (path === "/api/meta")
178
+ return json(res, { space });
179
+ if (path === "/api/roster")
180
+ return json(res, ep.getRoster());
181
+ if (path === "/api/membership") {
182
+ // Authoritative who-is-subscribed (broker-sourced); {asOf, members:[{id,live,durable,observedAt}]}.
183
+ // An unavailable feed returns an empty snapshot so the graph cleanly degrades to traffic-only.
184
+ try {
185
+ return json(res, await ep.readMembership());
186
+ }
187
+ catch {
188
+ return json(res, { asOf: undefined, members: [] });
189
+ }
190
+ }
191
+ if (path === "/api/channels")
192
+ return json(res, await ep.listChannels());
193
+ if (path === "/api/activity") {
194
+ // Backfill the all-activity feed: merge recent channel history with DM history (the live
195
+ // SSE tap only carries messages from after a client connects). Entries are mode-tagged
196
+ // ({mode, msg}) to match the live feed so DMs render as DMs.
197
+ const limit = query.get("limit") ? Number(query.get("limit")) : 200;
198
+ const chans = await ep.listChannels();
199
+ const chat = (await Promise.all(chans.map((ch) => ep.channelHistory(ch.channel, { limit }))))
200
+ .flat()
201
+ .map((msg) => ({ mode: "chat", msg }));
202
+ const dms = (await ep.dmHistory({ limit })).map((msg) => ({ mode: "unicast", msg }));
203
+ const all = [...chat, ...dms].sort((a, b) => a.msg.ts - b.msg.ts);
204
+ return json(res, all.slice(-limit));
205
+ }
206
+ if (path === "/api/dms") {
207
+ // DM history for the Direct-messages lens (god-view); the client groups it by peer/pair.
208
+ const limit = query.get("limit") ? Number(query.get("limit")) : 500;
209
+ return json(res, await ep.dmHistory({ limit }));
210
+ }
211
+ if (path.startsWith("/api/channels/") && path.endsWith("/history")) {
212
+ const name = decodeURIComponent(path.slice("/api/channels/".length, -"/history".length));
213
+ const limit = query.get("limit") ? Number(query.get("limit")) : 200;
214
+ return json(res, await ep.channelHistory(name, { limit }));
215
+ }
216
+ // Delete a channel and its content. The only write path on this otherwise read-only
217
+ // dashboard, so it's POST-gated and guarded by a confirm in the UI. Uses the manager cred
218
+ // pre-minted at startup (auth mode) or the connection creds (open / --creds), NOT the account
219
+ // seed (which we dropped). A wildcard / missing channel is a 400.
220
+ if (path === "/api/channel/delete" && req.method === "POST") {
221
+ const body = await readBody(req).catch(() => ({}));
222
+ const channel = typeof body.channel === "string" ? body.channel : "";
223
+ if (!channel) {
224
+ res.writeHead(400, { "content-type": "application/json" });
225
+ res.end(JSON.stringify({ error: "channel required" }));
226
+ return;
227
+ }
228
+ try {
229
+ // User mode mints a one-shot channel-purger VIEW per delete — the ledger is re-checked at
230
+ // this click, and a mid-session revoke becomes this handler's 400, never a dead dashboard.
231
+ const result = user
232
+ ? await userViewAuth(conn, "channel-purger").then((p) => clearChannel({ servers: server, space, channel, bearer: p.bearer, sentinelCreds: p.sentinelCreds }))
233
+ : await clearChannel({ servers: server, space, channel, creds: purgeCreds });
234
+ return json(res, { ok: true, ...result });
235
+ }
236
+ catch (e) {
237
+ res.writeHead(400, { "content-type": "application/json" });
238
+ res.end(JSON.stringify({ error: e.message }));
239
+ return;
240
+ }
241
+ }
242
+ const file = PAGE[path];
243
+ if (file) {
244
+ // no-cache: always revalidate so a `cotal` upgrade's new dashboard code is picked up on
245
+ // reload — a stale cached graph.js silently runs old behavior (e.g. pre-fix filters).
246
+ res.writeHead(200, { "content-type": file.type, "cache-control": "no-cache" });
247
+ res.end(readFileSync(file.path));
248
+ return;
249
+ }
250
+ res.writeHead(404).end("not found");
251
+ });
252
+ // Comment ping keeps idle SSE connections alive through proxies.
253
+ const ping = setInterval(() => {
254
+ for (const res of clients)
255
+ if (!res.writableEnded)
256
+ res.write(": ping\n\n");
257
+ }, 20_000);
258
+ httpServer.on("error", (e) => {
259
+ if (e.code === "EADDRINUSE")
260
+ console.error(c.red(`Port ${port} is in use. Pass --port <n>.`));
261
+ else
262
+ console.error(c.red("! " + e.message));
263
+ process.exit(1);
264
+ });
265
+ await new Promise((ready) => httpServer.listen(port, "127.0.0.1", ready));
266
+ // Branded URL only when on the default port; a custom --port keeps the plain loopback address.
267
+ const url = port === WEB_PORT ? WEB_URL : `http://127.0.0.1:${port}/`;
268
+ console.log(`${c.bold("Cotal web")} - observing space ${c.bold(space)}`);
269
+ console.log(c.dim(" god-view - DMs + anycast visible"));
270
+ console.log(` ${c.cyan(url)} ${c.dim("(Ctrl-C to stop)")}`);
271
+ if (!values["no-open"])
272
+ openBrowser(url);
273
+ let shuttingDown = false;
274
+ const shutdown = async () => {
275
+ if (shuttingDown)
276
+ return;
277
+ shuttingDown = true;
278
+ clearInterval(ping);
279
+ membershipWatch?.stop();
280
+ for (const res of clients)
281
+ res.end();
282
+ httpServer.close();
283
+ await ep.stop();
284
+ if (pidPath)
285
+ releasePid(pidPath);
286
+ process.exit(0);
287
+ };
288
+ process.on("SIGINT", () => void shutdown());
289
+ process.on("SIGTERM", () => void shutdown());
290
+ await new Promise(() => { });
291
+ }
292
+ function json(res, data) {
293
+ res.writeHead(200, { "content-type": "application/json" });
294
+ res.end(JSON.stringify(data));
295
+ }
296
+ /** Trailing-edge debounce — coalesces a burst of membership-feed deltas into one push. */
297
+ function debounce(fn, ms) {
298
+ let t;
299
+ return () => {
300
+ if (t)
301
+ clearTimeout(t);
302
+ t = setTimeout(fn, ms);
303
+ };
304
+ }
305
+ async function readBody(req) {
306
+ const chunks = [];
307
+ for await (const chunk of req)
308
+ chunks.push(chunk);
309
+ const raw = Buffer.concat(chunks).toString("utf8");
310
+ return raw ? JSON.parse(raw) : {};
311
+ }
312
+ /** Best-effort open of the dashboard in the default browser. The URL is already
313
+ * printed, so a failure here is harmless — never block startup on it. */
314
+ function openBrowser(url) {
315
+ const [cmd, args] = process.platform === "darwin"
316
+ ? ["open", [url]]
317
+ : process.platform === "win32"
318
+ ? ["cmd", ["/c", "start", "", url]]
319
+ : ["xdg-open", [url]];
320
+ try {
321
+ spawn(cmd, args, { stdio: "ignore", detached: true }).unref();
322
+ }
323
+ catch {
324
+ /* no opener on this platform — the printed URL is the fallback */
325
+ }
326
+ }
327
+ //# sourceMappingURL=web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"web.js","sourceRoot":"","sources":["../src/web.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,11 +1,38 @@
1
1
  {
2
2
  "name": "@cotal-ai/web",
3
- "version": "0.0.0",
4
- "description": "Placeholder for @cotal-ai/web (Cotal browser dashboard). The first real release is published from the Cotal monorepo.",
3
+ "description": "Cotal browser observability dashboard — adds the `web` command to the cotal CLI (install: cotal ext add @cotal-ai/web).",
4
+ "version": "0.11.1",
5
5
  "license": "Apache-2.0",
6
- "homepage": "https://github.com/Cotal-AI/Cotal",
7
6
  "repository": {
8
7
  "type": "git",
9
- "url": "git+https://github.com/Cotal-AI/Cotal.git"
8
+ "url": "https://github.com/Cotal-AI/Cotal.git",
9
+ "directory": "implementations/web"
10
+ },
11
+ "type": "module",
12
+ "main": "./dist/index.js",
13
+ "types": "./dist/index.d.ts",
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "import": "./dist/index.js"
18
+ }
19
+ },
20
+ "peerDependencies": {
21
+ "@cotal-ai/core": "*",
22
+ "@cotal-ai/workspace": "*"
23
+ },
24
+ "devDependencies": {
25
+ "@cotal-ai/core": "0.11.2",
26
+ "@cotal-ai/workspace": "0.11.2"
27
+ },
28
+ "files": [
29
+ "dist"
30
+ ],
31
+ "publishConfig": {
32
+ "access": "public"
33
+ },
34
+ "scripts": {
35
+ "typecheck": "tsc -p tsconfig.json --noEmit",
36
+ "build": "tsc -p tsconfig.json && rm -rf dist/web && cp -R src/web dist/web"
10
37
  }
11
- }
38
+ }
package/README.md DELETED
@@ -1,4 +0,0 @@
1
- # @cotal-ai/web
2
-
3
- Placeholder release to reserve the package name. The real `@cotal-ai/web` (Cotal browser
4
- dashboard) is published from the [Cotal monorepo](https://github.com/Cotal-AI/Cotal).