@cotal-ai/cli 0.48.2 → 0.49.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/commands/agents.d.ts +24 -5
- package/dist/commands/agents.d.ts.map +1 -1
- package/dist/commands/agents.js +25 -12
- package/dist/commands/agents.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/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/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/up.d.ts +13 -0
- package/dist/commands/up.d.ts.map +1 -1
- package/dist/commands/up.js +53 -4
- package/dist/commands/up.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/delivery-proc.d.ts +1 -0
- package/dist/lib/delivery-proc.d.ts.map +1 -1
- 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 +34 -6
- 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/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 +4 -4
package/dist/commands/up.js
CHANGED
|
@@ -6,15 +6,16 @@ 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 { managerHasDeliveryMarker, managerLogDisplayPath, managerUp, stopManager } from "../lib/manager-proc.js";
|
|
18
|
+
import { liveManagerWouldApplyMaxSessions, managerHasDeliveryMarker, managerLogDisplayPath, managerRecordState, managerUp, stopManager } from "../lib/manager-proc.js";
|
|
18
19
|
import { loadManifest } from "../lib/manifest/index.js";
|
|
19
20
|
import { buildLaunchSpec, genRunId, manifestToChannels, preflightConnectors, writeLaunchSpec } from "../lib/manifest/apply.js";
|
|
20
21
|
import { renderUpPlan, renderInherited, renderWarnings } from "../lib/manifest/render.js";
|
|
@@ -48,6 +49,7 @@ export const upFlags = [
|
|
|
48
49
|
{ 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
50
|
{ name: "detach", type: "boolean", description: "run in the background (stop with `cotal down`)" },
|
|
50
51
|
{ 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" },
|
|
52
|
+
{ 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
53
|
{ name: "file", type: "string", short: "f", value: "<cotal.yaml>", description: "launch a whole mesh from a manifest" },
|
|
52
54
|
{ name: "dry-run", type: "boolean", description: "with -f: print the plan, mutate nothing" },
|
|
53
55
|
];
|
|
@@ -367,6 +369,7 @@ async function runUp(args, inheritedLock, onAdopt) {
|
|
|
367
369
|
throw new Error('--idp is for user-auth spaces; pair it with --user-auth, or set broker.auth: "user" in a manifest');
|
|
368
370
|
}
|
|
369
371
|
const publicExchange = publicExchangeArgs(values, wantUser);
|
|
372
|
+
const maxSessions = parsePositiveIntegerFlag("--max-sessions", values["max-sessions"]);
|
|
370
373
|
// An open mesh has no operator, no system account, and no $SYS creds, so there is nothing to
|
|
371
374
|
// rotate; the request is a misunderstanding to name, never a silent no-op that reports success.
|
|
372
375
|
if (values["rotate-sys"] && values.open) {
|
|
@@ -455,6 +458,7 @@ async function runUp(args, inheritedLock, onAdopt) {
|
|
|
455
458
|
userAuth: wantUser,
|
|
456
459
|
idp: values.idp,
|
|
457
460
|
rotateSys: values["rotate-sys"],
|
|
461
|
+
maxSessions,
|
|
458
462
|
});
|
|
459
463
|
return;
|
|
460
464
|
}
|
|
@@ -472,6 +476,7 @@ async function runUp(args, inheritedLock, onAdopt) {
|
|
|
472
476
|
userAuth: wantUser,
|
|
473
477
|
idp: values.idp,
|
|
474
478
|
rotateSys: values["rotate-sys"],
|
|
479
|
+
maxSessions,
|
|
475
480
|
});
|
|
476
481
|
}
|
|
477
482
|
finally {
|
|
@@ -609,6 +614,18 @@ async function runUp(args, inheritedLock, onAdopt) {
|
|
|
609
614
|
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
615
|
process.exit(1);
|
|
611
616
|
}
|
|
617
|
+
// `--max-sessions` is fixed when the manager starts. A refresh reuses a live manager as-is
|
|
618
|
+
// (`ensureManager` returns immediately), then used to persist the requested ceiling anyway.
|
|
619
|
+
// That printed `✓ already running` over an unchanged plane and left MeshEntry lying about it.
|
|
620
|
+
// Refuse rather than warn: the flag either applies or the command fails. Matching the live
|
|
621
|
+
// argv is a no-op and may proceed. An unreadable command line cannot prove a match.
|
|
622
|
+
if (maxSessions !== undefined) {
|
|
623
|
+
const live = managerRecordState(undefined, undefined, held.space);
|
|
624
|
+
if (live.state === "alive" && !liveManagerWouldApplyMaxSessions(live.command, maxSessions)) {
|
|
625
|
+
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}\``));
|
|
626
|
+
process.exit(1);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
612
629
|
// Live INFO must agree with the recorded/requested transport. A bare refresh that greets
|
|
613
630
|
// "already running" over a plaintext listener while policy claims TLS is S5's second half —
|
|
614
631
|
// the refuse left a durable lie and this path used to reprint TLS success over cleartext.
|
|
@@ -719,18 +736,20 @@ async function runUp(args, inheritedLock, onAdopt) {
|
|
|
719
736
|
const controlPlane = await startDeliveryWithBroker(held.space, server, wantTls, {
|
|
720
737
|
runtime: values.runtime,
|
|
721
738
|
attachHost: attachHostFor(held.space, values.host),
|
|
739
|
+
maxSessions: maxSessionsFor(held.space, maxSessions),
|
|
722
740
|
});
|
|
723
741
|
if (!controlPlane)
|
|
724
742
|
process.exitCode = 1;
|
|
725
743
|
}
|
|
726
744
|
const heldAttachHost = attachHostFor(held.space, values.host);
|
|
745
|
+
const heldMaxSessions = maxSessionsFor(held.space, maxSessions);
|
|
727
746
|
// A broker was already answering here — this branch starts nothing, so it must not claim the
|
|
728
747
|
// record as ours (see `Provenance`).
|
|
729
748
|
// `tlsRequired` is CARRIED FORWARD, not re-derived. This branch starts no listener, so it has
|
|
730
749
|
// no transport decision to record — and `recordOurMesh` writes the entry whole, so omitting
|
|
731
750
|
// the field here would erase the requirement on every bare refresh, exactly the way dropping
|
|
732
751
|
// `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");
|
|
752
|
+
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
753
|
return;
|
|
735
754
|
}
|
|
736
755
|
const who = held ? `mesh "${held.space}" (${held.root})` : "a broker not started here";
|
|
@@ -773,6 +792,7 @@ async function runUp(args, inheritedLock, onAdopt) {
|
|
|
773
792
|
// from "nobody asked", or every mesh would persist an exposure decision it never made.
|
|
774
793
|
host: values.host,
|
|
775
794
|
runtime: values.runtime,
|
|
795
|
+
maxSessions,
|
|
776
796
|
resumeAttempt,
|
|
777
797
|
resumeCommitToken: restored?.managerCommit?.durableCommitToken ?? ordinaryAttempt?.managerCommit?.durableCommitToken,
|
|
778
798
|
...(restored ? {
|
|
@@ -795,6 +815,9 @@ async function runUp(args, inheritedLock, onAdopt) {
|
|
|
795
815
|
// Transport policy is committed inside startMeshDetached before delivery launch (S5+S9).
|
|
796
816
|
console.log(c.dim(`Started nats-server (${source}).`));
|
|
797
817
|
console.log(c.green(renderDetachedSummary({ pid, delivery, authService: wantUser && authService, manager })));
|
|
818
|
+
const supervisionWarning = detachedSystemdSupervisionWarning();
|
|
819
|
+
if (supervisionWarning)
|
|
820
|
+
console.error(c.yellow(supervisionWarning));
|
|
798
821
|
if (restored && process.env.COTAL_SMOKE_FAIL_AFTER_RESTORE_LISTENER_READY === "1")
|
|
799
822
|
throw new Error("smoke-injected failure after restore listener readiness");
|
|
800
823
|
// A user mesh whose auth service never became ready is recorded + running (a re-`cotal up`
|
|
@@ -949,6 +972,7 @@ async function runUp(args, inheritedLock, onAdopt) {
|
|
|
949
972
|
// registry — and the record below is written whole, so reading it afterwards would find the
|
|
950
973
|
// field this very call had just erased.
|
|
951
974
|
const effectiveAttachHost = attachHostFor(space, values.host);
|
|
975
|
+
const effectiveMaxSessions = maxSessionsFor(space, maxSessions);
|
|
952
976
|
recordOurMesh({
|
|
953
977
|
space, server, root: cotalRoot(),
|
|
954
978
|
mode: setup?.prepared ? "user" : useAuth ? "auth" : "open",
|
|
@@ -962,6 +986,7 @@ async function runUp(args, inheritedLock, onAdopt) {
|
|
|
962
986
|
// previous launch. The bare case stays absent rather than recording the loopback default as
|
|
963
987
|
// though the operator had chosen it.
|
|
964
988
|
...(effectiveAttachHost ? { attachHost: effectiveAttachHost } : {}),
|
|
989
|
+
...(effectiveMaxSessions !== undefined ? { maxSessions: effectiveMaxSessions } : {}),
|
|
965
990
|
ts: new Date().toISOString(),
|
|
966
991
|
}, "started");
|
|
967
992
|
// Bring up the delivery daemon WITH the server (auth mode only — it self-gates on `.cotal/auth`).
|
|
@@ -974,6 +999,7 @@ async function runUp(args, inheritedLock, onAdopt) {
|
|
|
974
999
|
// from another machine; without it the attach face stays loopback-only, so exposing terminals
|
|
975
1000
|
// is never a side effect of anything but the operator binding the mesh somewhere reachable.
|
|
976
1001
|
attachHost: effectiveAttachHost,
|
|
1002
|
+
maxSessions: effectiveMaxSessions,
|
|
977
1003
|
resumeAttempt,
|
|
978
1004
|
resumeCommitToken: restored?.managerCommit?.durableCommitToken ?? ordinaryAttempt?.managerCommit?.durableCommitToken,
|
|
979
1005
|
wsPort: setup?.wsPort, // P2 item 6: the console session client's broker ws port
|
|
@@ -1314,6 +1340,7 @@ async function resumeProvenOrdinaryListener(pending, heldLock) {
|
|
|
1314
1340
|
// record built without this field would erase the operator's decision, and the adopted manager
|
|
1315
1341
|
// below would then be launched loopback-only from an entry that no longer remembers otherwise.
|
|
1316
1342
|
const adoptAttachHost = attachHostFor(pending.space);
|
|
1343
|
+
const adoptMaxSessions = maxSessionsFor(pending.space);
|
|
1317
1344
|
recordOurMesh({
|
|
1318
1345
|
space: pending.space,
|
|
1319
1346
|
server: pending.server,
|
|
@@ -1323,11 +1350,13 @@ async function resumeProvenOrdinaryListener(pending, heldLock) {
|
|
|
1323
1350
|
tlsRequired: adoptedTlsRequired(pending.root),
|
|
1324
1351
|
...(svc.userAuth ? { userAuth: svc.userAuth } : {}),
|
|
1325
1352
|
...(adoptAttachHost ? { attachHost: adoptAttachHost } : {}),
|
|
1353
|
+
...(adoptMaxSessions !== undefined ? { maxSessions: adoptMaxSessions } : {}),
|
|
1326
1354
|
ts: new Date().toISOString(),
|
|
1327
1355
|
}, "started");
|
|
1328
1356
|
const controlPlane = await startDeliveryWithBroker(pending.space, pending.server, adoptedTlsRequired(pending.root), {
|
|
1329
1357
|
runtime: pending.runtime,
|
|
1330
1358
|
attachHost: adoptAttachHost,
|
|
1359
|
+
maxSessions: adoptMaxSessions,
|
|
1331
1360
|
resumeAttempt: pending.attemptId,
|
|
1332
1361
|
resumeCommitToken: pending.managerCommit?.durableCommitToken,
|
|
1333
1362
|
});
|
|
@@ -1355,6 +1384,7 @@ async function resumeProvenRestoreListener(prepared, heldLock) {
|
|
|
1355
1384
|
// Same ordering constraint as the pending-adopt path above: capture the recorded exposure before
|
|
1356
1385
|
// `recordOurMesh` rewrites the entry, or a restore silently demotes the mesh to loopback attach.
|
|
1357
1386
|
const restoreAttachHost = attachHostFor(prepared.space);
|
|
1387
|
+
const restoreMaxSessions = maxSessionsFor(prepared.space);
|
|
1358
1388
|
recordOurMesh({
|
|
1359
1389
|
space: prepared.space,
|
|
1360
1390
|
server: prepared.server,
|
|
@@ -1365,11 +1395,13 @@ async function resumeProvenRestoreListener(prepared, heldLock) {
|
|
|
1365
1395
|
tlsRequired: adoptedTlsRequired(prepared.root),
|
|
1366
1396
|
...(svc.userAuth ? { userAuth: svc.userAuth } : {}),
|
|
1367
1397
|
...(restoreAttachHost ? { attachHost: restoreAttachHost } : {}),
|
|
1398
|
+
...(restoreMaxSessions !== undefined ? { maxSessions: restoreMaxSessions } : {}),
|
|
1368
1399
|
ts: new Date().toISOString(),
|
|
1369
1400
|
}, "started");
|
|
1370
1401
|
const controlPlane = await startDeliveryWithBroker(prepared.space, prepared.server, adoptedTlsRequired(prepared.root), {
|
|
1371
1402
|
runtime: prepared.runtime,
|
|
1372
1403
|
attachHost: restoreAttachHost,
|
|
1404
|
+
maxSessions: restoreMaxSessions,
|
|
1373
1405
|
resumeAttempt: prepared.attemptId,
|
|
1374
1406
|
resumeCommitToken: prepared.managerCommit?.durableCommitToken,
|
|
1375
1407
|
});
|
|
@@ -1710,7 +1742,7 @@ async function upManifest(file, opts) {
|
|
|
1710
1742
|
try {
|
|
1711
1743
|
// `m.broker?.host`, not the defaulted `host`: same reason as the flag path — only a host the
|
|
1712
1744
|
// 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 }));
|
|
1745
|
+
({ 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
1746
|
}
|
|
1715
1747
|
catch (e) {
|
|
1716
1748
|
console.error(c.red(`✗ ${e.message}`));
|
|
@@ -1919,6 +1951,7 @@ opts) {
|
|
|
1919
1951
|
// RESUMES an already-recorded mesh, whose exposure decision exists only in the registry entry the
|
|
1920
1952
|
// call below rewrites.
|
|
1921
1953
|
const effectiveAttachHost = attachHostFor(space, opts.host);
|
|
1954
|
+
const effectiveMaxSessions = maxSessionsFor(space, opts.maxSessions);
|
|
1922
1955
|
recordOurMesh({
|
|
1923
1956
|
space, server, root: cotalRoot(),
|
|
1924
1957
|
mode: setup?.prepared ? "user" : useAuth ? "auth" : "open",
|
|
@@ -1928,6 +1961,7 @@ opts) {
|
|
|
1928
1961
|
...(svc.userAuth ? { userAuth: svc.userAuth } : {}),
|
|
1929
1962
|
// Persist only a real decision — declared now, or carried forward — never the loopback default.
|
|
1930
1963
|
...(effectiveAttachHost ? { attachHost: effectiveAttachHost } : {}),
|
|
1964
|
+
...(effectiveMaxSessions !== undefined ? { maxSessions: effectiveMaxSessions } : {}),
|
|
1931
1965
|
ts: new Date().toISOString(),
|
|
1932
1966
|
}, "started");
|
|
1933
1967
|
// Commit policy BEFORE delivery launch (S9). Listener is proved; refuse paths never reach here.
|
|
@@ -1939,6 +1973,7 @@ opts) {
|
|
|
1939
1973
|
launch: opts.launch,
|
|
1940
1974
|
// See the foreground path: the broker's bind address is what makes attach reachable off-box.
|
|
1941
1975
|
attachHost: effectiveAttachHost,
|
|
1976
|
+
maxSessions: effectiveMaxSessions,
|
|
1942
1977
|
resumeAttempt: opts.resumeAttempt,
|
|
1943
1978
|
resumeCommitToken: opts.resumeCommitToken,
|
|
1944
1979
|
wsPort: setup?.wsPort, // P2 item 6: the console session client's broker ws port
|
|
@@ -2049,6 +2084,20 @@ export async function claimSpace(space, server, root) {
|
|
|
2049
2084
|
export function attachHostFor(space, explicit) {
|
|
2050
2085
|
return explicit ?? findMesh(space)?.attachHost;
|
|
2051
2086
|
}
|
|
2087
|
+
/**
|
|
2088
|
+
* The manager live-session ceiling for a launch into `space`.
|
|
2089
|
+
*
|
|
2090
|
+
* Like {@link attachHostFor}, this is an operator DECISION (`--max-sessions`), not something later
|
|
2091
|
+
* commands can reconstruct. Every later manager launch — same-root repair, resume, `spawn -f` —
|
|
2092
|
+
* has no flag of its own unless the operator typed one, so it reads the decision back. Without
|
|
2093
|
+
* this a replacement manager silently falls to 64 and the next console pane past that is refused.
|
|
2094
|
+
*
|
|
2095
|
+
* An explicit value on THIS invocation always wins. Absent both, undefined — the plane's own
|
|
2096
|
+
* default of 64, unchanged, and nothing is recorded as though chosen.
|
|
2097
|
+
*/
|
|
2098
|
+
export function maxSessionsFor(space, explicit) {
|
|
2099
|
+
return explicit ?? findMesh(space)?.maxSessions;
|
|
2100
|
+
}
|
|
2052
2101
|
/** {@link recordOurMesh} under a name that says it is a test seam: the origin rule it enforces is
|
|
2053
2102
|
* asserted directly by the registry smoke, since reaching each branch through a full `up` would
|
|
2054
2103
|
* need a live broker per case. */
|