@cotal-ai/cli 0.5.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/command.d.ts.map +1 -1
- package/dist/command.js +3 -2
- package/dist/command.js.map +1 -1
- package/dist/commands/channels.d.ts +4 -2
- package/dist/commands/channels.d.ts.map +1 -1
- package/dist/commands/channels.js +17 -18
- package/dist/commands/channels.js.map +1 -1
- package/dist/commands/completion.d.ts.map +1 -1
- package/dist/commands/completion.js +5 -1
- package/dist/commands/completion.js.map +1 -1
- package/dist/commands/console.d.ts.map +1 -1
- package/dist/commands/console.js +13 -29
- package/dist/commands/console.js.map +1 -1
- package/dist/commands/down.d.ts +1 -1
- package/dist/commands/down.d.ts.map +1 -1
- package/dist/commands/down.js +13 -1
- package/dist/commands/down.js.map +1 -1
- package/dist/commands/history.d.ts.map +1 -1
- package/dist/commands/history.js +6 -13
- package/dist/commands/history.js.map +1 -1
- package/dist/commands/join.d.ts.map +1 -1
- package/dist/commands/join.js +20 -7
- package/dist/commands/join.js.map +1 -1
- package/dist/commands/meshes.d.ts +5 -0
- package/dist/commands/meshes.d.ts.map +1 -0
- package/dist/commands/meshes.js +25 -0
- package/dist/commands/meshes.js.map +1 -0
- package/dist/commands/mint.d.ts +4 -1
- package/dist/commands/mint.d.ts.map +1 -1
- package/dist/commands/mint.js +26 -3
- package/dist/commands/mint.js.map +1 -1
- package/dist/commands/send.d.ts +8 -15
- package/dist/commands/send.d.ts.map +1 -1
- package/dist/commands/send.js +41 -24
- package/dist/commands/send.js.map +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +23 -18
- package/dist/commands/setup.js.map +1 -1
- package/dist/commands/spawn.d.ts +4 -2
- package/dist/commands/spawn.d.ts.map +1 -1
- package/dist/commands/spawn.js +54 -22
- package/dist/commands/spawn.js.map +1 -1
- package/dist/commands/up.d.ts.map +1 -1
- package/dist/commands/up.js +133 -6
- package/dist/commands/up.js.map +1 -1
- package/dist/commands/use.d.ts +7 -0
- package/dist/commands/use.d.ts.map +1 -0
- package/dist/commands/use.js +27 -0
- package/dist/commands/use.js.map +1 -0
- package/dist/commands/web.d.ts.map +1 -1
- package/dist/commands/web.js +57 -27
- package/dist/commands/web.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +24 -37
- package/dist/index.js.map +1 -1
- package/dist/lib/connect.d.ts +72 -0
- package/dist/lib/connect.d.ts.map +1 -0
- package/dist/lib/connect.js +115 -0
- package/dist/lib/connect.js.map +1 -0
- package/dist/lib/delivery-proc.d.ts +35 -0
- package/dist/lib/delivery-proc.d.ts.map +1 -0
- package/dist/lib/delivery-proc.js +128 -0
- package/dist/lib/delivery-proc.js.map +1 -0
- package/dist/lib/manager-proc.d.ts +11 -2
- package/dist/lib/manager-proc.d.ts.map +1 -1
- package/dist/lib/manager-proc.js +43 -3
- package/dist/lib/manager-proc.js.map +1 -1
- package/dist/lib/meshes.d.ts +8 -0
- package/dist/lib/meshes.d.ts.map +1 -0
- package/dist/lib/meshes.js +15 -0
- package/dist/lib/meshes.js.map +1 -0
- package/dist/lib/onboard.js +6 -6
- package/dist/lib/onboard.js.map +1 -1
- package/dist/lib/transient.d.ts +7 -6
- package/dist/lib/transient.d.ts.map +1 -1
- package/dist/lib/transient.js +6 -25
- package/dist/lib/transient.js.map +1 -1
- package/dist/render.js +1 -1
- package/dist/web/graph.html +204 -0
- package/dist/web/graph.js +453 -0
- package/dist/web/index.html +6 -0
- package/package.json +2 -2
- package/dist/commands/signer.d.ts +0 -6
- package/dist/commands/signer.d.ts.map +0 -1
- package/dist/commands/signer.js +0 -30
- package/dist/commands/signer.js.map +0 -1
- package/dist/commands/watch.d.ts +0 -4
- package/dist/commands/watch.d.ts.map +0 -1
- package/dist/commands/watch.js +0 -7
- package/dist/commands/watch.js.map +0 -1
package/dist/lib/manager-proc.js
CHANGED
|
@@ -5,6 +5,12 @@ import { selfArgv } from "./self-exec.js";
|
|
|
5
5
|
import { resolveSpace } from "./status.js";
|
|
6
6
|
import { cotalPath } from "./paths.js";
|
|
7
7
|
const PID_PATH = () => cotalPath("manager.pid");
|
|
8
|
+
/** Sibling marker of `manager.pid`: written by THIS build's manager (which no longer hosts Plane-3 —
|
|
9
|
+
* the server-side delivery daemon does). Its presence beside a live `manager.pid` proves the manager is
|
|
10
|
+
* "delivery-aware" / non-hosting. A live `manager.pid` WITHOUT this marker is an OLD (pre-delivery-daemon)
|
|
11
|
+
* manager that still calls `startPlane3` — the delivery preflight stops it before the daemon binds, so an
|
|
12
|
+
* old hosting manager never double-binds `fanout`/`reader` against the new daemon. */
|
|
13
|
+
const DELIVERY_AWARE_MARKER = () => cotalPath("manager.delivery-aware");
|
|
8
14
|
function alive(pid) {
|
|
9
15
|
try {
|
|
10
16
|
process.kill(pid, 0); // signal 0: liveness probe, doesn't actually signal
|
|
@@ -22,16 +28,46 @@ export function managerUp() {
|
|
|
22
28
|
const pid = Number(readFileSync(p, "utf8").trim());
|
|
23
29
|
return Number.isFinite(pid) && alive(pid);
|
|
24
30
|
}
|
|
31
|
+
/** True if the live manager carries a delivery-aware marker BOUND to its current pid (i.e. it's THIS
|
|
32
|
+
* build, non-hosting). Fail-closed: the marker stores the pid it was written for, and this requires it
|
|
33
|
+
* to equal the live `manager.pid` — a stale marker left by a crash, a mismatch, or an unparseable file
|
|
34
|
+
* all read as NOT delivery-aware, so a live old hosting `manager.pid` can't be mistaken for non-hosting
|
|
35
|
+
* and the delivery preflight stops it. */
|
|
36
|
+
export function managerHasDeliveryMarker() {
|
|
37
|
+
const markerPath = DELIVERY_AWARE_MARKER();
|
|
38
|
+
const pidPath = PID_PATH();
|
|
39
|
+
if (!existsSync(markerPath) || !existsSync(pidPath))
|
|
40
|
+
return false;
|
|
41
|
+
const markerPid = Number(readFileSync(markerPath, "utf8").trim());
|
|
42
|
+
const livePid = Number(readFileSync(pidPath, "utf8").trim());
|
|
43
|
+
return Number.isFinite(markerPid) && Number.isFinite(livePid) && markerPid === livePid;
|
|
44
|
+
}
|
|
25
45
|
/** True if any process's full command line matches `pattern` (`pgrep -f`). Detects processes that
|
|
26
46
|
* have no pid file — the cmux-tab manager and the driving session — which live in cmux tabs. */
|
|
27
47
|
export function pgrepMatches(pattern) {
|
|
28
48
|
return spawnSync("pgrep", ["-f", pattern], { stdio: "ignore" }).status === 0;
|
|
29
49
|
}
|
|
30
50
|
/** True if a cmux-runtime manager is live for this space. Its cmux tab persists after the process
|
|
31
|
-
* exits, so a workspace listing isn't proof — the process is.
|
|
32
|
-
*
|
|
51
|
+
* exits, so a workspace listing isn't proof — the process is. A cmux manager runs `… supervise
|
|
52
|
+
* --runtime cmux … --space <space> …`; match order-independently (the session launcher emits the
|
|
53
|
+
* two flags adjacent, but a hand-typed launch may reorder them) by narrowing to `--runtime cmux`
|
|
54
|
+
* processes, then confirming the exact `--space <space>` token in each one's argv. Works for prod
|
|
55
|
+
* `cotal.js` and dev `cotal.ts` alike. */
|
|
33
56
|
export function cmuxManagerRunning(space) {
|
|
34
|
-
|
|
57
|
+
// `--` so pgrep doesn't read the leading `--runtime` as one of its own options.
|
|
58
|
+
const r = spawnSync("pgrep", ["-f", "--", "--runtime cmux"], { encoding: "utf8" });
|
|
59
|
+
if (r.status !== 0)
|
|
60
|
+
return false;
|
|
61
|
+
// Match the `--space` value as a whole token (space names can't contain whitespace), so `demo`
|
|
62
|
+
// never matches a process serving `demo2`. Both `--space <space>` and `--space=<space>` forms.
|
|
63
|
+
const servesSpace = (args) => {
|
|
64
|
+
const tokens = args.split(/\s+/);
|
|
65
|
+
return tokens.some((t, i) => (t === "--space" && tokens[i + 1] === space) || t === `--space=${space}`);
|
|
66
|
+
};
|
|
67
|
+
return r.stdout
|
|
68
|
+
.split("\n")
|
|
69
|
+
.filter(Boolean)
|
|
70
|
+
.some((pid) => servesSpace(spawnSync("ps", ["-p", pid, "-o", "args="], { encoding: "utf8" }).stdout));
|
|
35
71
|
}
|
|
36
72
|
/** Start the control-plane manager detached (pid in `.cotal/manager.pid`, output to
|
|
37
73
|
* `.cotal/manager.log`), stopped by `cotal down`. Re-execs this same CLI's `supervise` — the
|
|
@@ -54,6 +90,9 @@ export function startManagerDetached(o = {}) {
|
|
|
54
90
|
closeSync(fd);
|
|
55
91
|
child.unref();
|
|
56
92
|
writeFileSync(PID_PATH(), String(child.pid));
|
|
93
|
+
// Mark this manager as delivery-aware (non-hosting) so the delivery preflight can tell it apart from
|
|
94
|
+
// an old Plane-3-hosting manager. Written next to the pid, removed together in stopManager / down.
|
|
95
|
+
writeFileSync(DELIVERY_AWARE_MARKER(), String(child.pid));
|
|
57
96
|
return child.pid ?? 0;
|
|
58
97
|
}
|
|
59
98
|
/** Make the control plane available: reuse a manager already running for this folder, else start
|
|
@@ -68,6 +107,7 @@ export function ensureManager(o = {}) {
|
|
|
68
107
|
* so the two don't both answer the control plane (queue-grouped requests would split between them). */
|
|
69
108
|
export function stopManager() {
|
|
70
109
|
const p = PID_PATH();
|
|
110
|
+
rmSync(DELIVERY_AWARE_MARKER(), { force: true }); // drop the marker with the pid (gone either way)
|
|
71
111
|
if (!existsSync(p))
|
|
72
112
|
return;
|
|
73
113
|
const pid = Number(readFileSync(p, "utf8").trim());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"manager-proc.js","sourceRoot":"","sources":["../../src/lib/manager-proc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAC/F,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAEvC,MAAM,QAAQ,GAAG,GAAG,EAAE,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"manager-proc.js","sourceRoot":"","sources":["../../src/lib/manager-proc.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drop registry entries whose broker is gone — a `cotal up` that crashed or was `kill -9`'d without
|
|
3
|
+
* `cotal down` leaves a record behind. Probe each in parallel; only `unreachable` (refused/timeout)
|
|
4
|
+
* is stale, an auth broker answering `auth-required` is alive. Called by `spawn`/`use`/`meshes`
|
|
5
|
+
* before they act on the registry — never by completion (a `<TAB>` must not open the network).
|
|
6
|
+
*/
|
|
7
|
+
export declare function pruneStaleMeshes(): Promise<void>;
|
|
8
|
+
//# sourceMappingURL=meshes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"meshes.d.ts","sourceRoot":"","sources":["../../src/lib/meshes.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,wBAAsB,gBAAgB,IAAI,OAAO,CAAC,IAAI,CAAC,CAOtD"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { loadMeshes, probeConnect, removeMesh } from "@cotal-ai/core";
|
|
2
|
+
/**
|
|
3
|
+
* Drop registry entries whose broker is gone — a `cotal up` that crashed or was `kill -9`'d without
|
|
4
|
+
* `cotal down` leaves a record behind. Probe each in parallel; only `unreachable` (refused/timeout)
|
|
5
|
+
* is stale, an auth broker answering `auth-required` is alive. Called by `spawn`/`use`/`meshes`
|
|
6
|
+
* before they act on the registry — never by completion (a `<TAB>` must not open the network).
|
|
7
|
+
*/
|
|
8
|
+
export async function pruneStaleMeshes() {
|
|
9
|
+
await Promise.all(loadMeshes().map(async (m) => {
|
|
10
|
+
const r = await probeConnect(m.server);
|
|
11
|
+
if (!r.ok && r.reason === "unreachable")
|
|
12
|
+
removeMesh(m.space);
|
|
13
|
+
}));
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=meshes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"meshes.js","sourceRoot":"","sources":["../../src/lib/meshes.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAEtE;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,MAAM,OAAO,CAAC,GAAG,CACf,UAAU,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,EAAE,EAAE;QAC3B,MAAM,CAAC,GAAG,MAAM,YAAY,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACvC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,MAAM,KAAK,aAAa;YAAE,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IAC/D,CAAC,CAAC,CACH,CAAC;AACJ,CAAC"}
|
package/dist/lib/onboard.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { homedir } from "node:os";
|
|
3
2
|
import { join } from "node:path";
|
|
3
|
+
import { homeCotalDir } from "@cotal-ai/core";
|
|
4
4
|
/** Machine-level "I've onboarded before" marker. Its presence flips `cotal` from the
|
|
5
5
|
* full first-run flow to the compact ensure+status run. Lives next to the materialized
|
|
6
|
-
* plugin marketplace under ~/.cotal. */
|
|
7
|
-
const MARKER = join(
|
|
6
|
+
* plugin marketplace under ~/.cotal (COTAL_HOME-overridable, via {@link homeCotalDir}). */
|
|
7
|
+
const MARKER = () => join(homeCotalDir(), "onboarded.json");
|
|
8
8
|
export function isOnboarded() {
|
|
9
|
-
return existsSync(MARKER);
|
|
9
|
+
return existsSync(MARKER());
|
|
10
10
|
}
|
|
11
11
|
export function markOnboarded(version) {
|
|
12
|
-
mkdirSync(
|
|
13
|
-
writeFileSync(MARKER, JSON.stringify({ version, ts: new Date().toISOString() }, null, 2));
|
|
12
|
+
mkdirSync(homeCotalDir(), { recursive: true, mode: 0o700 });
|
|
13
|
+
writeFileSync(MARKER(), JSON.stringify({ version, ts: new Date().toISOString() }, null, 2));
|
|
14
14
|
}
|
|
15
15
|
//# sourceMappingURL=onboard.js.map
|
package/dist/lib/onboard.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"onboard.js","sourceRoot":"","sources":["../../src/lib/onboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"onboard.js","sourceRoot":"","sources":["../../src/lib/onboard.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC/D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAE9C;;4FAE4F;AAC5F,MAAM,MAAM,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,YAAY,EAAE,EAAE,gBAAgB,CAAC,CAAC;AAE5D,MAAM,UAAU,WAAW;IACzB,OAAO,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC;AAC9B,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAe;IAC3C,SAAS,CAAC,YAAY,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IAC5D,aAAa,CAAC,MAAM,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC9F,CAAC"}
|
package/dist/lib/transient.d.ts
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
import { CotalEndpoint } from "@cotal-ai/core";
|
|
2
2
|
/**
|
|
3
3
|
* A one-shot, write-capable connection for the headless commands that touch the live mesh
|
|
4
|
-
* (`dm`/`msg`/`ask`, and `personas list --running`).
|
|
5
|
-
*
|
|
6
|
-
*
|
|
4
|
+
* (`dm`/`msg`/`ask`, and `personas list --running`). Resolution + creds + reachability all go through
|
|
5
|
+
* the shared `connectOrExit` (so these work from any directory, and an explicit `--creds` is a raw
|
|
6
|
+
* off-registry connection). Opens a transient endpoint that never joins the roster, does the one
|
|
7
|
+
* thing, stops.
|
|
7
8
|
*/
|
|
8
9
|
export interface ConnectValues {
|
|
9
10
|
space?: string;
|
|
10
11
|
server?: string;
|
|
11
12
|
creds?: string;
|
|
12
13
|
}
|
|
13
|
-
/** Resolve where to connect
|
|
14
|
-
*
|
|
15
|
-
*
|
|
14
|
+
/** Resolve where to connect + with what credentials (`--creds` → raw off-registry; else the running
|
|
15
|
+
* mesh's minted manager creds). Fail-loud — an unresolved registry or an unreachable/auth-mismatched
|
|
16
|
+
* broker exits with one sentence, never degrades. */
|
|
16
17
|
export declare function resolveConnect(values: ConnectValues): Promise<{
|
|
17
18
|
server: string;
|
|
18
19
|
space: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transient.d.ts","sourceRoot":"","sources":["../../src/lib/transient.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"transient.d.ts","sourceRoot":"","sources":["../../src/lib/transient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAI/C;;;;;;GAMG;AAEH,MAAM,WAAW,aAAa;IAC5B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;sDAEsD;AACtD,wBAAsB,cAAc,CAClC,MAAM,EAAE,aAAa,GACpB,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAG5D;AAED;iGACiG;AACjG,wBAAsB,aAAa,CACjC,MAAM,EAAE,aAAa,EACrB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC;IAAE,EAAE,EAAE,aAAa,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAe/C"}
|
package/dist/lib/transient.js
CHANGED
|
@@ -1,30 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { CotalEndpoint, isReachable, DEFAULT_SERVER, DEFAULT_SPACE, authDir, loadSpaceAuth, mintCreds, newIdentity, } from "@cotal-ai/core";
|
|
1
|
+
import { CotalEndpoint } from "@cotal-ai/core";
|
|
3
2
|
import { c } from "../ui.js";
|
|
4
|
-
import {
|
|
5
|
-
/** Resolve where to connect
|
|
6
|
-
*
|
|
7
|
-
*
|
|
3
|
+
import { connectOrExit } from "./connect.js";
|
|
4
|
+
/** Resolve where to connect + with what credentials (`--creds` → raw off-registry; else the running
|
|
5
|
+
* mesh's minted manager creds). Fail-loud — an unresolved registry or an unreachable/auth-mismatched
|
|
6
|
+
* broker exits with one sentence, never degrades. */
|
|
8
7
|
export async function resolveConnect(values) {
|
|
9
|
-
const server = values
|
|
10
|
-
let creds = values.creds ? readFileSync(values.creds, "utf8") : undefined;
|
|
11
|
-
let space = values.space;
|
|
12
|
-
if (!creds) {
|
|
13
|
-
const auth = loadSpaceAuth(authDir(cotalRoot()));
|
|
14
|
-
if (auth) {
|
|
15
|
-
if (space && space !== auth.space) {
|
|
16
|
-
console.error(c.red(`Auth here is for space "${auth.space}", not "${space}". Use --space ${auth.space} (or pass --creds).`));
|
|
17
|
-
process.exit(1);
|
|
18
|
-
}
|
|
19
|
-
space = auth.space;
|
|
20
|
-
creds = await mintCreds(auth, newIdentity(), "manager");
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
space = space ?? DEFAULT_SPACE;
|
|
24
|
-
if (!(await isReachable(server, { creds }))) {
|
|
25
|
-
console.error(c.red(`Can't reach NATS at ${server}. Run: cotal up`));
|
|
26
|
-
process.exit(1);
|
|
27
|
-
}
|
|
8
|
+
const { server, space, creds } = await connectOrExit(values, "manager");
|
|
28
9
|
return { server, space, creds };
|
|
29
10
|
}
|
|
30
11
|
/** Open a transient endpoint: it watches presence (so name→id resolution and the live roster work)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transient.js","sourceRoot":"","sources":["../../src/lib/transient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"transient.js","sourceRoot":"","sources":["../../src/lib/transient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,CAAC,EAAE,MAAM,UAAU,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAgB7C;;sDAEsD;AACtD,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,MAAqB;IAErB,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,MAAM,aAAa,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IACxE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;AAClC,CAAC;AAED;iGACiG;AACjG,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAAqB,EACrB,IAAY;IAEZ,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,MAAM,cAAc,CAAC,MAAM,CAAC,CAAC;IAC9D,MAAM,EAAE,GAAG,IAAI,aAAa,CAAC;QAC3B,KAAK;QACL,OAAO,EAAE,MAAM;QACf,KAAK;QACL,QAAQ,EAAE,EAAE;QACZ,OAAO,EAAE,KAAK;QACd,gBAAgB,EAAE,KAAK;QACvB,aAAa,EAAE,IAAI;QACnB,IAAI,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,UAAU,EAAE;KACjC,CAAC,CAAC;IACH,EAAE,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,CAAQ,EAAE,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACrE,MAAM,EAAE,CAAC,KAAK,EAAE,CAAC;IACjB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,CAAC;AACvB,CAAC"}
|
package/dist/render.js
CHANGED
|
@@ -42,7 +42,7 @@ function presenceLine(ev) {
|
|
|
42
42
|
const activity = ev.presence.activity ? c.dim(" — " + ev.presence.activity) : "";
|
|
43
43
|
return `${ts(Date.now())} ${label} ${who(ev.presence.card)} ${statusBadge(ev.presence.status)}${activity}`;
|
|
44
44
|
}
|
|
45
|
-
// ---- the passive line stream (console --plain /
|
|
45
|
+
// ---- the passive line stream (console --plain / pipes) ---------------------
|
|
46
46
|
/** Wire the (not-yet-started) observer into a scrolling line log via the shared MeshView, and
|
|
47
47
|
* park until SIGINT. MeshView owns the endpoint lifecycle and all the normalization; this just
|
|
48
48
|
* prints presence changes and each classified+coalesced feed entry as it lands. */
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8" />
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
|
+
<title>Cotal · graph</title>
|
|
7
|
+
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
8
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
9
|
+
<link
|
|
10
|
+
href="https://fonts.googleapis.com/css2?family=Work+Sans:wght@400;500;600;700&display=swap"
|
|
11
|
+
rel="stylesheet"
|
|
12
|
+
/>
|
|
13
|
+
<style>
|
|
14
|
+
:root {
|
|
15
|
+
--bg: #131a26; --panel: #1b2330cc; --line: #38414f; --fg: #eef2f7;
|
|
16
|
+
--dim: #8b949e; --faint: #6e7681;
|
|
17
|
+
--chat: #58a6ff; --unicast: #d29922; --anycast: #3fb950;
|
|
18
|
+
--working: #3fb950; --waiting: #e3b341; --idle: #6e7681; --red: #f85149;
|
|
19
|
+
--font: "Work Sans", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
20
|
+
}
|
|
21
|
+
* { box-sizing: border-box; }
|
|
22
|
+
html, body { height: 100%; margin: 0; }
|
|
23
|
+
body {
|
|
24
|
+
font-family: var(--font); font-size: 13px; background: var(--bg); color: var(--fg);
|
|
25
|
+
overflow: hidden; -webkit-font-smoothing: antialiased;
|
|
26
|
+
}
|
|
27
|
+
#graph { position: fixed; inset: 0; display: block; cursor: grab; }
|
|
28
|
+
#graph.hover { cursor: pointer; }
|
|
29
|
+
|
|
30
|
+
/* floating glass surfaces */
|
|
31
|
+
.glass {
|
|
32
|
+
background: var(--panel); border: 1px solid var(--line); border-radius: 12px;
|
|
33
|
+
backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* ── header (top, floating) ── */
|
|
37
|
+
header {
|
|
38
|
+
position: fixed; top: 14px; left: 14px; right: 14px; z-index: 10;
|
|
39
|
+
display: flex; align-items: center; gap: 16px; padding: 9px 14px;
|
|
40
|
+
}
|
|
41
|
+
.brand { display: flex; align-items: center; gap: 9px; }
|
|
42
|
+
.brand .mark { width: 9px; height: 9px; border-radius: 50%; background: var(--chat);
|
|
43
|
+
box-shadow: 0 0 10px var(--chat); }
|
|
44
|
+
.brand .title { font-size: 16px; font-weight: 700; }
|
|
45
|
+
.brand .space { font-size: 13px; color: var(--dim); }
|
|
46
|
+
.navlink {
|
|
47
|
+
font-size: 12px; font-weight: 600; color: var(--dim); text-decoration: none;
|
|
48
|
+
padding: 5px 11px; border-radius: 8px; border: 1px solid var(--line);
|
|
49
|
+
}
|
|
50
|
+
.navlink:hover { color: var(--fg); border-color: var(--chat); }
|
|
51
|
+
.pill { display: inline-flex; align-items: center; gap: 6px; padding: 4px 9px;
|
|
52
|
+
border-radius: 20px; background: #1f2d24; }
|
|
53
|
+
.pill .d { width: 7px; height: 7px; border-radius: 50%; background: var(--working); }
|
|
54
|
+
.pill .t { font-size: 11px; font-weight: 600; color: var(--working); }
|
|
55
|
+
.pill.down { background: #2a1717; } .pill.down .d { background: var(--red); }
|
|
56
|
+
.pill.down .t { color: var(--red); }
|
|
57
|
+
/* membership-freshness pill states */
|
|
58
|
+
.pill.stale { background: #2a2417; } .pill.stale .d { background: var(--waiting); }
|
|
59
|
+
.pill.stale .t { color: var(--waiting); }
|
|
60
|
+
.pill.off { background: #1f242c; } .pill.off .d { background: var(--faint); }
|
|
61
|
+
.pill.off .t { color: var(--dim); }
|
|
62
|
+
|
|
63
|
+
.ctrls { margin-left: auto; display: flex; align-items: center; gap: 7px; }
|
|
64
|
+
.grp { display: flex; align-items: center; gap: 4px; padding-right: 7px;
|
|
65
|
+
margin-right: 0; border-right: 1px solid var(--line); }
|
|
66
|
+
.grp:last-child { border-right: 0; padding-right: 0; }
|
|
67
|
+
.chip {
|
|
68
|
+
font-size: 11px; padding: 4px 9px; border-radius: 13px; cursor: pointer;
|
|
69
|
+
color: var(--faint); user-select: none; border: 1px solid transparent; white-space: nowrap;
|
|
70
|
+
}
|
|
71
|
+
.chip:hover { color: var(--fg); }
|
|
72
|
+
.chip.on { background: #ffffff10; border-color: var(--line); color: var(--fg); }
|
|
73
|
+
.chip.mode.chat.on { color: var(--chat); } .chip.mode.unicast.on { color: var(--unicast); }
|
|
74
|
+
.chip.mode.anycast.on { color: var(--anycast); }
|
|
75
|
+
.chip.pause.on { color: var(--waiting); border-color: var(--waiting); }
|
|
76
|
+
|
|
77
|
+
/* ── legend (bottom-left, collapsible) ── */
|
|
78
|
+
#legend { position: fixed; left: 14px; bottom: 14px; z-index: 10; padding: 0;
|
|
79
|
+
max-width: 200px; overflow: hidden; }
|
|
80
|
+
#legend .ltoggle {
|
|
81
|
+
display: flex; align-items: center; justify-content: space-between;
|
|
82
|
+
width: 100%; padding: 7px 12px; cursor: pointer; appearance: none;
|
|
83
|
+
font-size: 10px; font-weight: 600; letter-spacing: .6px; color: var(--faint);
|
|
84
|
+
text-transform: uppercase; background: transparent; border: 0;
|
|
85
|
+
text-align: left; font-family: inherit;
|
|
86
|
+
}
|
|
87
|
+
#legend .ltoggle:hover { color: var(--dim); }
|
|
88
|
+
#legend .ltoggle .chev { font-size: 9px; opacity: .5; transition: transform .2s ease; }
|
|
89
|
+
#legend.collapsed .ltoggle .chev { transform: rotate(-90deg); }
|
|
90
|
+
#legend .lbody { display: flex; flex-direction: column; gap: 5px; padding: 2px 12px 10px; }
|
|
91
|
+
#legend.collapsed .lbody { display: none; }
|
|
92
|
+
#legend .ls { font-size: 9px; font-weight: 600; letter-spacing: .5px; color: var(--faint);
|
|
93
|
+
text-transform: uppercase; opacity: .65; margin-top: 3px; }
|
|
94
|
+
#legend .ls:first-child { margin-top: 0; }
|
|
95
|
+
#legend .row { display: flex; align-items: center; gap: 9px; font-size: 11px; color: var(--dim); }
|
|
96
|
+
#legend .sw { width: 14px; height: 2px; border-radius: 1px; flex: none; }
|
|
97
|
+
#legend .sw-dot { width: 8px; height: 8px; border-radius: 50%; }
|
|
98
|
+
#legend .ring { width: 8px; height: 8px; border-radius: 50%; flex: none;
|
|
99
|
+
background: transparent; box-shadow: 0 0 0 1.5px currentColor inset; }
|
|
100
|
+
|
|
101
|
+
/* ── detail panel (right, floating) ── */
|
|
102
|
+
#detail {
|
|
103
|
+
position: fixed; top: 64px; right: 14px; bottom: 14px; width: 308px; z-index: 10;
|
|
104
|
+
padding: 16px 16px 18px; overflow-y: auto; display: none; flex-direction: column; gap: 14px;
|
|
105
|
+
scrollbar-width: thin; scrollbar-color: var(--line) transparent;
|
|
106
|
+
}
|
|
107
|
+
#detail::-webkit-scrollbar { width: 6px; }
|
|
108
|
+
#detail::-webkit-scrollbar-thumb { background: var(--line); border-radius: 3px; }
|
|
109
|
+
#detail.open { display: flex; }
|
|
110
|
+
#detail .x { position: absolute; top: 10px; right: 10px; cursor: pointer; color: var(--faint);
|
|
111
|
+
font-size: 13px; width: 22px; height: 22px; display: flex; align-items: center;
|
|
112
|
+
justify-content: center; border-radius: 5px; line-height: 1; }
|
|
113
|
+
#detail .x:hover { color: var(--fg); background: #ffffff12; }
|
|
114
|
+
.d-kind { font-size: 10px; font-weight: 600; letter-spacing: .6px; color: var(--faint);
|
|
115
|
+
text-transform: uppercase; }
|
|
116
|
+
.d-who { font-size: 16px; font-weight: 700; line-height: 1.25; padding-right: 26px; }
|
|
117
|
+
.d-who .role { font-size: 11px; font-weight: 500; color: var(--faint); margin-left: 6px; }
|
|
118
|
+
.d-status { display: inline-flex; align-items: center; gap: 6px; font-size: 11.5px;
|
|
119
|
+
font-weight: 500; padding: 3px 10px; border-radius: 20px; background: #ffffff08;
|
|
120
|
+
color: var(--dim); width: fit-content; }
|
|
121
|
+
.d-status .dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor;
|
|
122
|
+
box-shadow: 0 0 6px currentColor; }
|
|
123
|
+
.d-status.working { background: #16231a; color: var(--working); }
|
|
124
|
+
.d-status.waiting { background: #2a2117; color: var(--waiting); }
|
|
125
|
+
.d-status.idle { color: var(--dim); }
|
|
126
|
+
.d-status.offline { color: var(--faint); }
|
|
127
|
+
.d-section { display: flex; flex-direction: column; gap: 5px; }
|
|
128
|
+
.d-label { font-size: 9.5px; font-weight: 600; letter-spacing: .5px; color: var(--faint);
|
|
129
|
+
text-transform: uppercase; }
|
|
130
|
+
.d-block { font-size: 12px; line-height: 1.55; padding: 9px 11px; border-radius: 7px;
|
|
131
|
+
background: #ffffff08; border: 1px solid var(--line); white-space: pre-wrap; word-break: break-word; }
|
|
132
|
+
.d-block.muted { color: var(--dim); font-style: italic; }
|
|
133
|
+
.d-rows { display: flex; flex-direction: column; gap: 5px; }
|
|
134
|
+
.d-row { display: flex; gap: 10px; font-size: 11.5px; line-height: 1.4; }
|
|
135
|
+
.d-row .k { color: var(--faint); min-width: 64px; flex: none; }
|
|
136
|
+
.d-row .v { color: var(--fg); word-break: break-word; }
|
|
137
|
+
.d-msgs { display: flex; flex-direction: column; gap: 5px; }
|
|
138
|
+
.d-msg { font-size: 11px; line-height: 1.45; padding: 7px 10px 8px; border-radius: 6px;
|
|
139
|
+
background: #ffffff06; border-left: 2px solid var(--line); }
|
|
140
|
+
.d-msg .mhead { display: flex; align-items: baseline; gap: 6px; margin-bottom: 3px; }
|
|
141
|
+
.d-msg .m { font-size: 9px; font-weight: 700; letter-spacing: .3px; text-transform: uppercase; }
|
|
142
|
+
.d-msg .who { color: var(--fg); font-weight: 600; }
|
|
143
|
+
.d-msg .tgt { color: var(--dim); }
|
|
144
|
+
.d-msg .body { color: var(--dim); word-break: break-word; }
|
|
145
|
+
.d-msg.empty { text-align: center; color: var(--faint); font-style: italic; border-left-color: transparent; }
|
|
146
|
+
/* member / subscription tag rows in the detail panel */
|
|
147
|
+
.d-tags { display: flex; flex-wrap: wrap; gap: 5px; }
|
|
148
|
+
.mtag { display: inline-flex; align-items: center; gap: 6px; font-size: 11px; color: var(--fg);
|
|
149
|
+
padding: 3px 8px; border-radius: 13px; background: #ffffff08; border: 1px solid var(--line); }
|
|
150
|
+
.mtag .dot { width: 7px; height: 7px; border-radius: 50%; flex: none; box-shadow: 0 0 5px currentColor; }
|
|
151
|
+
.mtag .act { font-size: 9px; font-weight: 700; letter-spacing: .3px; text-transform: uppercase; color: var(--chat); }
|
|
152
|
+
.mtag .off { font-size: 9px; font-weight: 600; letter-spacing: .3px; text-transform: uppercase; color: var(--faint); }
|
|
153
|
+
.ctag { font-size: 11px; color: var(--chat); padding: 3px 8px; border-radius: 13px;
|
|
154
|
+
background: #58a6ff14; border: 1px solid #58a6ff33; }
|
|
155
|
+
.ctag.off { color: var(--dim); background: #ffffff06; border-color: var(--line); }
|
|
156
|
+
.hint { position: fixed; bottom: 16px; left: 50%; transform: translateX(-50%); z-index: 9;
|
|
157
|
+
font-size: 11.5px; color: var(--faint); pointer-events: none; transition: opacity .4s; }
|
|
158
|
+
</style>
|
|
159
|
+
</head>
|
|
160
|
+
<body>
|
|
161
|
+
<canvas id="graph"></canvas>
|
|
162
|
+
|
|
163
|
+
<header class="glass">
|
|
164
|
+
<span class="brand">
|
|
165
|
+
<span class="mark"></span>
|
|
166
|
+
<span class="title">Cotal</span>
|
|
167
|
+
<span class="space" id="space"></span>
|
|
168
|
+
</span>
|
|
169
|
+
<a class="navlink" href="/">← Monitor</a>
|
|
170
|
+
<span class="pill down" id="conn"><span class="d"></span><span class="t">connecting</span></span>
|
|
171
|
+
<span class="pill off" id="feed" hidden><span class="d"></span><span class="t">membership</span></span>
|
|
172
|
+
<div class="ctrls">
|
|
173
|
+
<div class="grp" id="modes">
|
|
174
|
+
<span class="chip mode chat on" data-mode="chat">channel</span>
|
|
175
|
+
<span class="chip mode unicast on" data-mode="unicast">direct</span>
|
|
176
|
+
<span class="chip mode anycast on" data-mode="anycast">anycast</span>
|
|
177
|
+
</div>
|
|
178
|
+
<span class="chip pause" id="pause">⏸ pause</span>
|
|
179
|
+
</div>
|
|
180
|
+
</header>
|
|
181
|
+
|
|
182
|
+
<div id="legend" class="glass">
|
|
183
|
+
<button class="ltoggle" id="legendToggle" type="button"><span>legend</span><span class="chev">▾</span></button>
|
|
184
|
+
<div class="lbody">
|
|
185
|
+
<span class="ls">traffic</span>
|
|
186
|
+
<span class="row"><span class="sw" style="background:var(--chat)"></span> channel post → hub</span>
|
|
187
|
+
<span class="row"><span class="sw" style="background:var(--unicast)"></span> direct message</span>
|
|
188
|
+
<span class="row"><span class="sw sw-dot" style="background:var(--anycast)"></span> anycast (to a role)</span>
|
|
189
|
+
<span class="ls">membership</span>
|
|
190
|
+
<span class="row"><span class="sw" style="background:#8493a8"></span> subscribed (live)</span>
|
|
191
|
+
<span class="row"><span class="sw" style="background:#5a6472;opacity:.7"></span> member · offline</span>
|
|
192
|
+
<span class="ls">agents</span>
|
|
193
|
+
<span class="row"><span class="ring" style="color:var(--working)"></span> working</span>
|
|
194
|
+
<span class="row"><span class="ring" style="color:var(--waiting)"></span> waiting · needs input</span>
|
|
195
|
+
<span class="row"><span class="ring" style="color:var(--idle)"></span> idle / offline</span>
|
|
196
|
+
</div>
|
|
197
|
+
</div>
|
|
198
|
+
|
|
199
|
+
<aside id="detail" class="glass"></aside>
|
|
200
|
+
<div class="hint" id="hint">click a node for detail · scroll to zoom · drag to pan</div>
|
|
201
|
+
|
|
202
|
+
<script src="/graph.js"></script>
|
|
203
|
+
</body>
|
|
204
|
+
</html>
|