@cotal-ai/cli 0.48.2 → 0.50.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 +8 -0
- package/dist/command.js.map +1 -1
- package/dist/commands/agents.d.ts +167 -6
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +151 -61
- package/dist/commands/agents.js.map +1 -1
- package/dist/commands/doctor.d.ts.map +1 -1
- package/dist/commands/doctor.js +175 -11
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/down.d.ts +18 -1
- package/dist/commands/down.d.ts.map +1 -1
- package/dist/commands/down.js +99 -3
- package/dist/commands/down.js.map +1 -1
- package/dist/commands/join.d.ts.map +1 -1
- package/dist/commands/join.js +9 -1
- package/dist/commands/join.js.map +1 -1
- package/dist/commands/meshes.js +5 -5
- package/dist/commands/meshes.js.map +1 -1
- package/dist/commands/send.d.ts.map +1 -1
- package/dist/commands/send.js +2 -8
- package/dist/commands/send.js.map +1 -1
- package/dist/commands/setup.d.ts +1 -1
- package/dist/commands/setup.d.ts.map +1 -1
- package/dist/commands/setup.js +1 -1
- package/dist/commands/spawn-manifest.d.ts.map +1 -1
- package/dist/commands/spawn-manifest.js +3 -2
- package/dist/commands/spawn-manifest.js.map +1 -1
- package/dist/commands/status.d.ts +11 -3
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +176 -13
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/up.d.ts +13 -0
- package/dist/commands/up.d.ts.map +1 -1
- package/dist/commands/up.js +65 -5
- package/dist/commands/up.js.map +1 -1
- package/dist/commands/update.d.ts.map +1 -1
- package/dist/commands/update.js +19 -7
- package/dist/commands/update.js.map +1 -1
- package/dist/commands/use.js +2 -2
- package/dist/commands/use.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -3
- package/dist/index.js.map +1 -1
- package/dist/lib/auth-proc.d.ts.map +1 -1
- package/dist/lib/auth-proc.js +2 -1
- package/dist/lib/auth-proc.js.map +1 -1
- package/dist/lib/control.d.ts +28 -1
- package/dist/lib/control.d.ts.map +1 -1
- package/dist/lib/control.js +58 -11
- package/dist/lib/control.js.map +1 -1
- package/dist/lib/delivery-proc.d.ts +22 -5
- package/dist/lib/delivery-proc.d.ts.map +1 -1
- package/dist/lib/delivery-proc.js +82 -18
- package/dist/lib/delivery-proc.js.map +1 -1
- package/dist/lib/delivery-responder.d.ts +92 -0
- package/dist/lib/delivery-responder.d.ts.map +1 -0
- package/dist/lib/delivery-responder.js +78 -0
- package/dist/lib/delivery-responder.js.map +1 -0
- package/dist/lib/manager-proc.d.ts +15 -13
- package/dist/lib/manager-proc.d.ts.map +1 -1
- package/dist/lib/manager-proc.js +38 -7
- package/dist/lib/manager-proc.js.map +1 -1
- package/dist/lib/restore.d.ts.map +1 -1
- package/dist/lib/restore.js +6 -4
- package/dist/lib/restore.js.map +1 -1
- package/dist/lib/self-exec.d.ts +15 -1
- package/dist/lib/self-exec.d.ts.map +1 -1
- package/dist/lib/self-exec.js +30 -3
- package/dist/lib/self-exec.js.map +1 -1
- package/dist/lib/systemd-supervision.d.ts +15 -0
- package/dist/lib/systemd-supervision.d.ts.map +1 -0
- package/dist/lib/systemd-supervision.js +64 -0
- package/dist/lib/systemd-supervision.js.map +1 -0
- package/dist/lib/transient.d.ts +1 -10
- package/dist/lib/transient.d.ts.map +1 -1
- package/dist/lib/transient.js +4 -24
- package/dist/lib/transient.js.map +1 -1
- package/dist/seed/reconcile.d.ts.map +1 -1
- package/dist/seed/reconcile.js +27 -1
- package/dist/seed/reconcile.js.map +1 -1
- package/package.json +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"up.d.ts","sourceRoot":"","sources":["../../src/commands/up.ts"],"names":[],"mappings":"AAkBA,OAAO,EAOL,KAAK,eAAe,EAgBpB,KAAK,mBAAmB,EACxB,KAAK,UAAU,EACf,KAAK,QAAQ,EACb,KAAK,gBAAgB,EACtB,MAAM,gBAAgB,CAAC;AAExB,OAAO,
|
|
1
|
+
{"version":3,"file":"up.d.ts","sourceRoot":"","sources":["../../src/commands/up.ts"],"names":[],"mappings":"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"}
|
package/dist/commands/up.js
CHANGED
|
@@ -6,15 +6,18 @@ import { mkdirSync, writeFileSync, readFileSync, existsSync, openSync, statSync,
|
|
|
6
6
|
import { dirname, join, resolve } from "node:path";
|
|
7
7
|
import { isReachable, DEFAULT_SERVER, createSpaceAuth, serverConfig, openServerConfig, validateTlsMaterial, mintCreds, mintLifecycleUid, DEV_OWNER, mintConnectionEvictorCreds, mintMembershipObserverCreds, newIdentity, setupSpaceStreams, reconcileSpaceTtls, standaloneConnectOpts, seedChannelRegistry, ensureDefaultDeliveryClass, mkSecretDir, writeSecretFile, } from "@cotal-ai/core";
|
|
8
8
|
import { connect } from "@nats-io/transport-node";
|
|
9
|
-
import { assertSingleSpaceBroker, assertUserAuthInfo, authDir, getSoleSpaceAuth, getSpaceAuth, hasUserAuthState, listSpaceAccounts, preloadSpaceAccounts, putSpaceAuth, clearCurrent, findMesh, getCurrent, loadMeshes, connectionEvictorCredsKey, membershipConfigPath, membershipObserverCredsKey, membershipRwCredsKey, MEMBERSHIP_CONFIG_KIND, MEMBERSHIP_RW_CREDS_KIND, recordMesh, meshesForRoot, removeMesh, rotateSystemCreds, setCurrent, staleSystemCreds, SYSTEM_CREDS_FILES, userAuthStateDir, workspaceSecretStore, acquireMaintenanceLock, assertStoreIdentity, assessRestoreClaim, beginOrdinaryResume, bindOrdinaryResumeListener, consumeRetiredMaintenance, markOrdinaryResumeActive, markOrdinaryResumeDegraded, replaceDeadOrdinaryResumeListener, localProcessOwnerStatus, readMaintenanceJournal, readMaintenanceResumeDocument, readStoreIdentity, recordOrdinaryResumeManagerCommit, releaseMaintenanceLock, retireOrdinaryResume, sameStoreIdentity, readBrokerPolicy, writeBrokerPolicy, removeIdentityPin, writeIdentityPin, } from "@cotal-ai/workspace";
|
|
9
|
+
import { assertSingleSpaceBroker, assertUserAuthInfo, authDir, getSoleSpaceAuth, getSpaceAuth, hasUserAuthState, listSpaceAccounts, preloadSpaceAccounts, putSpaceAuth, clearCurrent, findMesh, getCurrent, loadMeshes, connectionEvictorCredsKey, membershipConfigPath, membershipObserverCredsKey, membershipRwCredsKey, MEMBERSHIP_CONFIG_KIND, MEMBERSHIP_RW_CREDS_KIND, parsePositiveIntegerFlag, recordMesh, meshesForRoot, removeMesh, rotateSystemCreds, setCurrent, staleSystemCreds, SYSTEM_CREDS_FILES, userAuthStateDir, workspaceSecretStore, acquireMaintenanceLock, assertStoreIdentity, assessRestoreClaim, beginOrdinaryResume, bindOrdinaryResumeListener, consumeRetiredMaintenance, markOrdinaryResumeActive, markOrdinaryResumeDegraded, replaceDeadOrdinaryResumeListener, localProcessOwnerStatus, readMaintenanceJournal, readMaintenanceResumeDocument, readStoreIdentity, recordOrdinaryResumeManagerCommit, releaseMaintenanceLock, retireOrdinaryResume, sameStoreIdentity, readBrokerPolicy, writeBrokerPolicy, removeIdentityPin, writeIdentityPin, } from "@cotal-ai/workspace";
|
|
10
10
|
import { ensureAuthService, resolveAuthProvider, stopAuthService } from "../lib/auth-proc.js";
|
|
11
11
|
import { resolveSpace } from "../lib/status.js";
|
|
12
12
|
import { c } from "../ui.js";
|
|
13
13
|
import { resolveNatsServer } from "../lib/nats-bin.js";
|
|
14
14
|
import { cotalPath, cotalRoot } from "../lib/paths.js";
|
|
15
15
|
import { renderDetachedSummary } from "../lib/up-report.js";
|
|
16
|
+
import { detachedSystemdSupervisionWarning } from "../lib/systemd-supervision.js";
|
|
16
17
|
import { deliveryUp, ensureControlPlane, stopDelivery } from "../lib/delivery-proc.js";
|
|
17
|
-
import {
|
|
18
|
+
import { RESPONDER_UNBOUND_CONSEQUENCE } from "../lib/delivery-responder.js";
|
|
19
|
+
import { displayCmd } from "../lib/self-exec.js";
|
|
20
|
+
import { liveManagerWouldApplyMaxSessions, managerHasDeliveryMarker, managerLogDisplayPath, managerRecordState, managerUp, stopManager } from "../lib/manager-proc.js";
|
|
18
21
|
import { loadManifest } from "../lib/manifest/index.js";
|
|
19
22
|
import { buildLaunchSpec, genRunId, manifestToChannels, preflightConnectors, writeLaunchSpec } from "../lib/manifest/apply.js";
|
|
20
23
|
import { renderUpPlan, renderInherited, renderWarnings } from "../lib/manifest/render.js";
|
|
@@ -48,6 +51,7 @@ export const upFlags = [
|
|
|
48
51
|
{ name: "rotate-sys", type: "boolean", description: "renew the expired/expiring $SYS creds by rotating the system account (agents, data and creds survive; needs a stopped mesh)" },
|
|
49
52
|
{ name: "detach", type: "boolean", description: "run in the background (stop with `cotal down`)" },
|
|
50
53
|
{ name: "runtime", type: "string", value: "<name>", description: "agent runtime for the mesh manager (default pty; extension runtimes are explicit-only, see `cotal runtimes`); with -f overrides the manifest's runtime" },
|
|
54
|
+
{ name: "max-sessions", type: "string", value: "<n>", description: "live-session ceiling for the mesh manager (default 64; one session per console pane, so size for agents × panes). Recorded and reused by later manager launches" },
|
|
51
55
|
{ name: "file", type: "string", short: "f", value: "<cotal.yaml>", description: "launch a whole mesh from a manifest" },
|
|
52
56
|
{ name: "dry-run", type: "boolean", description: "with -f: print the plan, mutate nothing" },
|
|
53
57
|
];
|
|
@@ -367,6 +371,7 @@ async function runUp(args, inheritedLock, onAdopt) {
|
|
|
367
371
|
throw new Error('--idp is for user-auth spaces; pair it with --user-auth, or set broker.auth: "user" in a manifest');
|
|
368
372
|
}
|
|
369
373
|
const publicExchange = publicExchangeArgs(values, wantUser);
|
|
374
|
+
const maxSessions = parsePositiveIntegerFlag("--max-sessions", values["max-sessions"]);
|
|
370
375
|
// An open mesh has no operator, no system account, and no $SYS creds, so there is nothing to
|
|
371
376
|
// rotate; the request is a misunderstanding to name, never a silent no-op that reports success.
|
|
372
377
|
if (values["rotate-sys"] && values.open) {
|
|
@@ -455,6 +460,7 @@ async function runUp(args, inheritedLock, onAdopt) {
|
|
|
455
460
|
userAuth: wantUser,
|
|
456
461
|
idp: values.idp,
|
|
457
462
|
rotateSys: values["rotate-sys"],
|
|
463
|
+
maxSessions,
|
|
458
464
|
});
|
|
459
465
|
return;
|
|
460
466
|
}
|
|
@@ -472,6 +478,7 @@ async function runUp(args, inheritedLock, onAdopt) {
|
|
|
472
478
|
userAuth: wantUser,
|
|
473
479
|
idp: values.idp,
|
|
474
480
|
rotateSys: values["rotate-sys"],
|
|
481
|
+
maxSessions,
|
|
475
482
|
});
|
|
476
483
|
}
|
|
477
484
|
finally {
|
|
@@ -609,6 +616,18 @@ async function runUp(args, inheritedLock, onAdopt) {
|
|
|
609
616
|
console.error(c.red(`✗ mesh "${held.space}" is already running at ${server} - a running broker can't change its transport; \`cotal down\` it first, then \`cotal up --tls-cert <cert> --tls-key <key>\``));
|
|
610
617
|
process.exit(1);
|
|
611
618
|
}
|
|
619
|
+
// `--max-sessions` is fixed when the manager starts. A refresh reuses a live manager as-is
|
|
620
|
+
// (`ensureManager` returns immediately), then used to persist the requested ceiling anyway.
|
|
621
|
+
// That printed `✓ already running` over an unchanged plane and left MeshEntry lying about it.
|
|
622
|
+
// Refuse rather than warn: the flag either applies or the command fails. Matching the live
|
|
623
|
+
// argv is a no-op and may proceed. An unreadable command line cannot prove a match.
|
|
624
|
+
if (maxSessions !== undefined) {
|
|
625
|
+
const live = managerRecordState(undefined, undefined, held.space);
|
|
626
|
+
if (live.state === "alive" && !liveManagerWouldApplyMaxSessions(live.command, maxSessions)) {
|
|
627
|
+
console.error(c.red(`✗ mesh "${held.space}" is already running at ${server} - a running manager can't change --max-sessions (it is fixed at start); \`cotal down\` it first, then \`cotal up --max-sessions ${maxSessions}\``));
|
|
628
|
+
process.exit(1);
|
|
629
|
+
}
|
|
630
|
+
}
|
|
612
631
|
// Live INFO must agree with the recorded/requested transport. A bare refresh that greets
|
|
613
632
|
// "already running" over a plaintext listener while policy claims TLS is S5's second half —
|
|
614
633
|
// the refuse left a durable lie and this path used to reprint TLS success over cleartext.
|
|
@@ -719,18 +738,20 @@ async function runUp(args, inheritedLock, onAdopt) {
|
|
|
719
738
|
const controlPlane = await startDeliveryWithBroker(held.space, server, wantTls, {
|
|
720
739
|
runtime: values.runtime,
|
|
721
740
|
attachHost: attachHostFor(held.space, values.host),
|
|
741
|
+
maxSessions: maxSessionsFor(held.space, maxSessions),
|
|
722
742
|
});
|
|
723
743
|
if (!controlPlane)
|
|
724
744
|
process.exitCode = 1;
|
|
725
745
|
}
|
|
726
746
|
const heldAttachHost = attachHostFor(held.space, values.host);
|
|
747
|
+
const heldMaxSessions = maxSessionsFor(held.space, maxSessions);
|
|
727
748
|
// A broker was already answering here — this branch starts nothing, so it must not claim the
|
|
728
749
|
// record as ours (see `Provenance`).
|
|
729
750
|
// `tlsRequired` is CARRIED FORWARD, not re-derived. This branch starts no listener, so it has
|
|
730
751
|
// no transport decision to record — and `recordOurMesh` writes the entry whole, so omitting
|
|
731
752
|
// the field here would erase the requirement on every bare refresh, exactly the way dropping
|
|
732
753
|
// `attachHost` would silently demote the mesh to loopback.
|
|
733
|
-
recordOurMesh({ space: held.space, server, root, mode: held.mode, ...(held.tlsRequired !== undefined ? { tlsRequired: held.tlsRequired } : {}), ...(userAuth ? { userAuth } : {}), ...(heldAttachHost ? { attachHost: heldAttachHost } : {}), ts: new Date().toISOString() }, "refresh");
|
|
754
|
+
recordOurMesh({ space: held.space, server, root, mode: held.mode, ...(held.tlsRequired !== undefined ? { tlsRequired: held.tlsRequired } : {}), ...(userAuth ? { userAuth } : {}), ...(heldAttachHost ? { attachHost: heldAttachHost } : {}), ...(heldMaxSessions !== undefined ? { maxSessions: heldMaxSessions } : {}), ts: new Date().toISOString() }, "refresh");
|
|
734
755
|
return;
|
|
735
756
|
}
|
|
736
757
|
const who = held ? `mesh "${held.space}" (${held.root})` : "a broker not started here";
|
|
@@ -773,6 +794,7 @@ async function runUp(args, inheritedLock, onAdopt) {
|
|
|
773
794
|
// from "nobody asked", or every mesh would persist an exposure decision it never made.
|
|
774
795
|
host: values.host,
|
|
775
796
|
runtime: values.runtime,
|
|
797
|
+
maxSessions,
|
|
776
798
|
resumeAttempt,
|
|
777
799
|
resumeCommitToken: restored?.managerCommit?.durableCommitToken ?? ordinaryAttempt?.managerCommit?.durableCommitToken,
|
|
778
800
|
...(restored ? {
|
|
@@ -795,6 +817,9 @@ async function runUp(args, inheritedLock, onAdopt) {
|
|
|
795
817
|
// Transport policy is committed inside startMeshDetached before delivery launch (S5+S9).
|
|
796
818
|
console.log(c.dim(`Started nats-server (${source}).`));
|
|
797
819
|
console.log(c.green(renderDetachedSummary({ pid, delivery, authService: wantUser && authService, manager })));
|
|
820
|
+
const supervisionWarning = detachedSystemdSupervisionWarning();
|
|
821
|
+
if (supervisionWarning)
|
|
822
|
+
console.error(c.yellow(supervisionWarning));
|
|
798
823
|
if (restored && process.env.COTAL_SMOKE_FAIL_AFTER_RESTORE_LISTENER_READY === "1")
|
|
799
824
|
throw new Error("smoke-injected failure after restore listener readiness");
|
|
800
825
|
// A user mesh whose auth service never became ready is recorded + running (a re-`cotal up`
|
|
@@ -949,6 +974,7 @@ async function runUp(args, inheritedLock, onAdopt) {
|
|
|
949
974
|
// registry — and the record below is written whole, so reading it afterwards would find the
|
|
950
975
|
// field this very call had just erased.
|
|
951
976
|
const effectiveAttachHost = attachHostFor(space, values.host);
|
|
977
|
+
const effectiveMaxSessions = maxSessionsFor(space, maxSessions);
|
|
952
978
|
recordOurMesh({
|
|
953
979
|
space, server, root: cotalRoot(),
|
|
954
980
|
mode: setup?.prepared ? "user" : useAuth ? "auth" : "open",
|
|
@@ -962,6 +988,7 @@ async function runUp(args, inheritedLock, onAdopt) {
|
|
|
962
988
|
// previous launch. The bare case stays absent rather than recording the loopback default as
|
|
963
989
|
// though the operator had chosen it.
|
|
964
990
|
...(effectiveAttachHost ? { attachHost: effectiveAttachHost } : {}),
|
|
991
|
+
...(effectiveMaxSessions !== undefined ? { maxSessions: effectiveMaxSessions } : {}),
|
|
965
992
|
ts: new Date().toISOString(),
|
|
966
993
|
}, "started");
|
|
967
994
|
// Bring up the delivery daemon WITH the server (auth mode only — it self-gates on `.cotal/auth`).
|
|
@@ -974,6 +1001,7 @@ async function runUp(args, inheritedLock, onAdopt) {
|
|
|
974
1001
|
// from another machine; without it the attach face stays loopback-only, so exposing terminals
|
|
975
1002
|
// is never a side effect of anything but the operator binding the mesh somewhere reachable.
|
|
976
1003
|
attachHost: effectiveAttachHost,
|
|
1004
|
+
maxSessions: effectiveMaxSessions,
|
|
977
1005
|
resumeAttempt,
|
|
978
1006
|
resumeCommitToken: restored?.managerCommit?.durableCommitToken ?? ordinaryAttempt?.managerCommit?.durableCommitToken,
|
|
979
1007
|
wsPort: setup?.wsPort, // P2 item 6: the console session client's broker ws port
|
|
@@ -1314,6 +1342,7 @@ async function resumeProvenOrdinaryListener(pending, heldLock) {
|
|
|
1314
1342
|
// record built without this field would erase the operator's decision, and the adopted manager
|
|
1315
1343
|
// below would then be launched loopback-only from an entry that no longer remembers otherwise.
|
|
1316
1344
|
const adoptAttachHost = attachHostFor(pending.space);
|
|
1345
|
+
const adoptMaxSessions = maxSessionsFor(pending.space);
|
|
1317
1346
|
recordOurMesh({
|
|
1318
1347
|
space: pending.space,
|
|
1319
1348
|
server: pending.server,
|
|
@@ -1323,11 +1352,13 @@ async function resumeProvenOrdinaryListener(pending, heldLock) {
|
|
|
1323
1352
|
tlsRequired: adoptedTlsRequired(pending.root),
|
|
1324
1353
|
...(svc.userAuth ? { userAuth: svc.userAuth } : {}),
|
|
1325
1354
|
...(adoptAttachHost ? { attachHost: adoptAttachHost } : {}),
|
|
1355
|
+
...(adoptMaxSessions !== undefined ? { maxSessions: adoptMaxSessions } : {}),
|
|
1326
1356
|
ts: new Date().toISOString(),
|
|
1327
1357
|
}, "started");
|
|
1328
1358
|
const controlPlane = await startDeliveryWithBroker(pending.space, pending.server, adoptedTlsRequired(pending.root), {
|
|
1329
1359
|
runtime: pending.runtime,
|
|
1330
1360
|
attachHost: adoptAttachHost,
|
|
1361
|
+
maxSessions: adoptMaxSessions,
|
|
1331
1362
|
resumeAttempt: pending.attemptId,
|
|
1332
1363
|
resumeCommitToken: pending.managerCommit?.durableCommitToken,
|
|
1333
1364
|
});
|
|
@@ -1355,6 +1386,7 @@ async function resumeProvenRestoreListener(prepared, heldLock) {
|
|
|
1355
1386
|
// Same ordering constraint as the pending-adopt path above: capture the recorded exposure before
|
|
1356
1387
|
// `recordOurMesh` rewrites the entry, or a restore silently demotes the mesh to loopback attach.
|
|
1357
1388
|
const restoreAttachHost = attachHostFor(prepared.space);
|
|
1389
|
+
const restoreMaxSessions = maxSessionsFor(prepared.space);
|
|
1358
1390
|
recordOurMesh({
|
|
1359
1391
|
space: prepared.space,
|
|
1360
1392
|
server: prepared.server,
|
|
@@ -1365,11 +1397,13 @@ async function resumeProvenRestoreListener(prepared, heldLock) {
|
|
|
1365
1397
|
tlsRequired: adoptedTlsRequired(prepared.root),
|
|
1366
1398
|
...(svc.userAuth ? { userAuth: svc.userAuth } : {}),
|
|
1367
1399
|
...(restoreAttachHost ? { attachHost: restoreAttachHost } : {}),
|
|
1400
|
+
...(restoreMaxSessions !== undefined ? { maxSessions: restoreMaxSessions } : {}),
|
|
1368
1401
|
ts: new Date().toISOString(),
|
|
1369
1402
|
}, "started");
|
|
1370
1403
|
const controlPlane = await startDeliveryWithBroker(prepared.space, prepared.server, adoptedTlsRequired(prepared.root), {
|
|
1371
1404
|
runtime: prepared.runtime,
|
|
1372
1405
|
attachHost: restoreAttachHost,
|
|
1406
|
+
maxSessions: restoreMaxSessions,
|
|
1373
1407
|
resumeAttempt: prepared.attemptId,
|
|
1374
1408
|
resumeCommitToken: prepared.managerCommit?.durableCommitToken,
|
|
1375
1409
|
});
|
|
@@ -1710,7 +1744,7 @@ async function upManifest(file, opts) {
|
|
|
1710
1744
|
try {
|
|
1711
1745
|
// `m.broker?.host`, not the defaulted `host`: same reason as the flag path — only a host the
|
|
1712
1746
|
// manifest actually declared is an exposure decision worth persisting.
|
|
1713
|
-
({ pid, controlPlane, authService } = await startMeshDetached({ transport: opts.transport, server, space: m.space, open, userAuth, rotateSys: opts.rotateSys, host: m.broker?.host, seed: manifestToChannels(eff), runtime, launch: specPath }));
|
|
1747
|
+
({ pid, controlPlane, authService } = await startMeshDetached({ transport: opts.transport, server, space: m.space, open, userAuth, rotateSys: opts.rotateSys, host: m.broker?.host, seed: manifestToChannels(eff), runtime, launch: specPath, maxSessions: opts.maxSessions }));
|
|
1714
1748
|
}
|
|
1715
1749
|
catch (e) {
|
|
1716
1750
|
console.error(c.red(`✗ ${e.message}`));
|
|
@@ -1789,7 +1823,16 @@ async function startDeliveryWithBroker(space, server,
|
|
|
1789
1823
|
*/
|
|
1790
1824
|
tlsRequired, mgr) {
|
|
1791
1825
|
try {
|
|
1792
|
-
await ensureControlPlane({ space, server, tls: tlsRequired, ...(mgr ?? {}) });
|
|
1826
|
+
const plane = await ensureControlPlane({ space, server, tls: tlsRequired, ...(mgr ?? {}) });
|
|
1827
|
+
// #1576: `up` either BINDS the responder or SAYS SO HERE. The delivery daemon is a hard
|
|
1828
|
+
// dependency of spawn, retirement and join, and this function used to return `true` for a boot
|
|
1829
|
+
// that started a daemon whose responder never bound — so `cotal up` printed its success banner
|
|
1830
|
+
// over a control plane that could not perform any of the three. The reporter's fleet ran 22
|
|
1831
|
+
// hours in that state. This is not a failure of `up` (live messaging is unaffected and the
|
|
1832
|
+
// responder may still bind), so it does not throw; it states the condition and its consequence.
|
|
1833
|
+
if (plane.responderBound === false)
|
|
1834
|
+
console.error(c.yellow(`! delivery responder did not bind before this boot finished - ${RESPONDER_UNBOUND_CONSEQUENCE}`) +
|
|
1835
|
+
c.dim(`\n The daemon process is running and the wait is open-ended; boot durable joins reconcile by themselves once it binds (agents do NOT need respawning).\n Watch it with \`${displayCmd()} status --components\`.`));
|
|
1793
1836
|
return true;
|
|
1794
1837
|
}
|
|
1795
1838
|
catch (e) {
|
|
@@ -1919,6 +1962,7 @@ opts) {
|
|
|
1919
1962
|
// RESUMES an already-recorded mesh, whose exposure decision exists only in the registry entry the
|
|
1920
1963
|
// call below rewrites.
|
|
1921
1964
|
const effectiveAttachHost = attachHostFor(space, opts.host);
|
|
1965
|
+
const effectiveMaxSessions = maxSessionsFor(space, opts.maxSessions);
|
|
1922
1966
|
recordOurMesh({
|
|
1923
1967
|
space, server, root: cotalRoot(),
|
|
1924
1968
|
mode: setup?.prepared ? "user" : useAuth ? "auth" : "open",
|
|
@@ -1928,6 +1972,7 @@ opts) {
|
|
|
1928
1972
|
...(svc.userAuth ? { userAuth: svc.userAuth } : {}),
|
|
1929
1973
|
// Persist only a real decision — declared now, or carried forward — never the loopback default.
|
|
1930
1974
|
...(effectiveAttachHost ? { attachHost: effectiveAttachHost } : {}),
|
|
1975
|
+
...(effectiveMaxSessions !== undefined ? { maxSessions: effectiveMaxSessions } : {}),
|
|
1931
1976
|
ts: new Date().toISOString(),
|
|
1932
1977
|
}, "started");
|
|
1933
1978
|
// Commit policy BEFORE delivery launch (S9). Listener is proved; refuse paths never reach here.
|
|
@@ -1939,6 +1984,7 @@ opts) {
|
|
|
1939
1984
|
launch: opts.launch,
|
|
1940
1985
|
// See the foreground path: the broker's bind address is what makes attach reachable off-box.
|
|
1941
1986
|
attachHost: effectiveAttachHost,
|
|
1987
|
+
maxSessions: effectiveMaxSessions,
|
|
1942
1988
|
resumeAttempt: opts.resumeAttempt,
|
|
1943
1989
|
resumeCommitToken: opts.resumeCommitToken,
|
|
1944
1990
|
wsPort: setup?.wsPort, // P2 item 6: the console session client's broker ws port
|
|
@@ -2049,6 +2095,20 @@ export async function claimSpace(space, server, root) {
|
|
|
2049
2095
|
export function attachHostFor(space, explicit) {
|
|
2050
2096
|
return explicit ?? findMesh(space)?.attachHost;
|
|
2051
2097
|
}
|
|
2098
|
+
/**
|
|
2099
|
+
* The manager live-session ceiling for a launch into `space`.
|
|
2100
|
+
*
|
|
2101
|
+
* Like {@link attachHostFor}, this is an operator DECISION (`--max-sessions`), not something later
|
|
2102
|
+
* commands can reconstruct. Every later manager launch — same-root repair, resume, `spawn -f` —
|
|
2103
|
+
* has no flag of its own unless the operator typed one, so it reads the decision back. Without
|
|
2104
|
+
* this a replacement manager silently falls to 64 and the next console pane past that is refused.
|
|
2105
|
+
*
|
|
2106
|
+
* An explicit value on THIS invocation always wins. Absent both, undefined — the plane's own
|
|
2107
|
+
* default of 64, unchanged, and nothing is recorded as though chosen.
|
|
2108
|
+
*/
|
|
2109
|
+
export function maxSessionsFor(space, explicit) {
|
|
2110
|
+
return explicit ?? findMesh(space)?.maxSessions;
|
|
2111
|
+
}
|
|
2052
2112
|
/** {@link recordOurMesh} under a name that says it is a test seam: the origin rule it enforces is
|
|
2053
2113
|
* asserted directly by the registry smoke, since reaching each branch through a full `up` would
|
|
2054
2114
|
* need a live broker per case. */
|