@cotal-ai/cli 0.151.2 → 0.152.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 +9 -7
- package/dist/command.js.map +1 -1
- package/dist/commands/channel-members.d.ts.map +1 -1
- package/dist/commands/channel-members.js +4 -12
- package/dist/commands/channel-members.js.map +1 -1
- package/dist/commands/channels.js +8 -4
- package/dist/commands/channels.js.map +1 -1
- package/dist/commands/chat.d.ts +4 -3
- package/dist/commands/chat.d.ts.map +1 -1
- package/dist/commands/chat.js +7 -4
- package/dist/commands/chat.js.map +1 -1
- package/dist/commands/completion.d.ts +6 -0
- package/dist/commands/completion.d.ts.map +1 -1
- package/dist/commands/completion.js +27 -9
- package/dist/commands/completion.js.map +1 -1
- package/dist/commands/history.d.ts.map +1 -1
- package/dist/commands/history.js +10 -10
- package/dist/commands/history.js.map +1 -1
- package/dist/commands/meshes-add.d.ts +1 -21
- package/dist/commands/meshes-add.d.ts.map +1 -1
- package/dist/commands/meshes-add.js +2 -58
- package/dist/commands/meshes-add.js.map +1 -1
- package/dist/commands/send.d.ts.map +1 -1
- package/dist/commands/send.js +2 -5
- package/dist/commands/send.js.map +1 -1
- package/dist/commands/service-registry.js +31 -9
- package/dist/commands/service-registry.js.map +1 -1
- package/dist/commands/spawn-preview.d.ts.map +1 -1
- package/dist/commands/spawn-preview.js +15 -8
- package/dist/commands/spawn-preview.js.map +1 -1
- package/dist/commands/spawn.d.ts.map +1 -1
- package/dist/commands/spawn.js +1 -7
- package/dist/commands/spawn.js.map +1 -1
- package/dist/commands/stack-up.d.ts +1 -0
- package/dist/commands/stack-up.d.ts.map +1 -1
- package/dist/commands/stack-up.js +8 -2
- package/dist/commands/stack-up.js.map +1 -1
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +9 -3
- package/dist/commands/sync.js.map +1 -1
- package/dist/commands/up.d.ts.map +1 -1
- package/dist/commands/up.js +22 -5
- package/dist/commands/up.js.map +1 -1
- package/dist/lib/completion-install.d.ts.map +1 -1
- package/dist/lib/completion-install.js +35 -23
- package/dist/lib/completion-install.js.map +1 -1
- package/dist/lib/spawn-defaults.d.ts +3 -1
- package/dist/lib/spawn-defaults.d.ts.map +1 -1
- package/dist/lib/spawn-defaults.js +7 -1
- package/dist/lib/spawn-defaults.js.map +1 -1
- package/dist/watch-data.d.ts +8 -1
- package/dist/watch-data.d.ts.map +1 -1
- package/dist/watch-data.js +17 -8
- package/dist/watch-data.js.map +1 -1
- package/package.json +4 -4
package/dist/commands/up.js
CHANGED
|
@@ -6,7 +6,7 @@ import { createConnection, createServer, isIP } from "node:net";
|
|
|
6
6
|
import { homedir, hostname } from "node:os";
|
|
7
7
|
import { accessSync, constants, mkdirSync, readFileSync, existsSync, statSync, closeSync, lstatSync, realpathSync, readdirSync, rmdirSync, } from "node:fs";
|
|
8
8
|
import { basename, dirname, isAbsolute, join, resolve } from "node:path";
|
|
9
|
-
import { isReachable, dialerFor, DEFAULT_SERVER, DEFAULT_SPACE, SERVICE_AUTHORITY_MAX_BYTES, SERVICE_CALLER_PAYLOAD_FLOOR, createSpaceAuth, serverConfig, openServerConfig, validateTlsMaterial, credsProblem, mintCreds, mintLifecycleUid, DEV_OWNER, mintConnectionEvictorCreds, mintMembershipObserverCreds, newIdentity, setupSpaceStreams, removeIssuedStoresBeforeRetention, IssuedStoreBeforeRetentionError, IssuedStoreRecreateRefusal, reconcileSpaceTtls, ttlBuckets, standaloneConnectOpts, requireBrokerFloor, parseServerVersion, presenceBucket, spaceDeletionStreams, isJetStreamMissing, seedChannelRegistry, ensureDefaultDeliveryClass, UndecodableRegistryEntry, assertValidChannel, isConcreteChannel, validateChannelConfig, validateChannelDefaults, LEASE_TTL_MS, EpEnvelopeError, mkSecretDir, openPrivateAppend, realDirNoSymlink, writeSecretFile, utf16Problem, } from "@cotal-ai/core";
|
|
9
|
+
import { isReachable, dialerFor, DEFAULT_SERVER, DEFAULT_SPACE, SERVICE_AUTHORITY_MAX_BYTES, SERVICE_CALLER_PAYLOAD_FLOOR, CONTRACT_ARTIFACT_MAX_BYTES, MANAGER_START_PAYLOAD_FLOOR, createSpaceAuth, serverConfig, openServerConfig, validateTlsMaterial, credsProblem, mintCreds, mintLifecycleUid, DEV_OWNER, mintConnectionEvictorCreds, mintMembershipObserverCreds, newIdentity, setupSpaceStreams, removeIssuedStoresBeforeRetention, IssuedStoreBeforeRetentionError, IssuedStoreRecreateRefusal, reconcileSpaceTtls, ttlBuckets, standaloneConnectOpts, requireBrokerFloor, parseServerVersion, presenceBucket, spaceDeletionStreams, isJetStreamMissing, seedChannelRegistry, ensureDefaultDeliveryClass, UndecodableRegistryEntry, assertValidChannel, isConcreteChannel, validateChannelConfig, validateChannelDefaults, LEASE_TTL_MS, EpEnvelopeError, mkSecretDir, openPrivateAppend, realDirNoSymlink, writeSecretFile, utf16Problem, } from "@cotal-ai/core";
|
|
10
10
|
import { JetStreamApiCodes, jetstreamManager, StorageType } from "@nats-io/jetstream";
|
|
11
11
|
import { Kvm } from "@nats-io/kv";
|
|
12
12
|
import { assertManagerName, readManagerName, readManagerSeatCap, recordManagerName, recordManagerSeatCap, parseSeatCapFlag, seatCapText, CommandFailure, codeSpan, commandFailureReport, isCommandFailure, protectedLocalDirectory, jsonFlag, plainFlag, renderReport, assertSingleSpaceBroker, assertUserAuthInfo, authDir, brokerAddressForDisplay, brokerPolicyPath, getSoleSpaceAuth, soleSpaceOf, getSpaceAuth, hasUserAuthState, listSpaceAccounts, preloadSpaceAccounts, putSpaceAuth, brokerAddressKey, canonicalRoot, rootPathProblem, rootControlProblem, clearCurrent, findMesh, findPreparedSpace, homeCotalDir, getCurrent, loadMeshes, preparedSpaceAt, removePreparedSpace, localMeshesForRoot, keepsRegistration, oneLine, presentationOf, writeResult, connectionEvictorCredsKey, membershipConfigPath, membershipObserverCredsKey, membershipRwCredsKey, MEMBERSHIP_CONFIG_KIND, MEMBERSHIP_RW_CREDS_KIND, WEB_CREDS_KIND, webCredsKey, parsePositiveIntegerFlag, recordMesh, retainedLegacyBroker, meshesForRoot, removeMesh, rotateSystemCreds, setCurrent, staleSystemCreds, SYSTEM_CREDS_FILES, userAuthStateDir, userAuthSpacesOnDisk, workspaceSecretStore, acquireMaintenanceLock, assertStoreIdentity, assessMaintenanceClaim, assessRestoreClaim, beginOrdinaryResume, bindOrdinaryResumeListener, consumeRetiredMaintenance, markOrdinaryResumeActive, markOrdinaryResumeDegraded, replaceDeadOrdinaryResumeListener, localProcessOwnerStatus, readMaintenanceJournal, rootNamesNoSpace, readMaintenanceResumeDocument, seatCheckpointDir, readStoreIdentity, recordOrdinaryResumeManagerCommit, releaseMaintenanceLock, retireOrdinaryResume, settleTokenHandoff, sweepTokenHandoff, writeTokenHandoff, sameStoreIdentity, cutController, readBrokerPolicy, writeBrokerPolicy, removePidPair, writePidPair, isLoopbackHost, connectUserControlOrThrow, userViewAuth, recordOperationSpace, recordsElsewhereError, recordOperationWarning, retainSystemSigningSeed, restoreLeftOut, SPACE_NAME_MAX, spaceNameTooLong, NATS_PIDFILE, UNTRUSTED_CERTIFICATE, exitCode, canonicalLocalProcessPath, DELIVERY_LOGFILE, terminalWidth, } from "@cotal-ai/workspace";
|
|
@@ -93,7 +93,7 @@ export const upFlags = [
|
|
|
93
93
|
{ name: "logfile-size-limit", type: "string", value: "<bytes>", description: "nats-server log rotation threshold in bytes; requires --log-file" },
|
|
94
94
|
{ name: "logfile-max-num", type: "string", value: "<count>", description: "maximum total broker log files retained; requires --log-file" },
|
|
95
95
|
{ name: "auth-timeout", type: "string", value: "<seconds>", description: "user-auth only: how long the broker waits for the auth callout, 1 to 60 seconds (default: nats-server's 2); the auth service answers inside it. Fixed at broker start and recorded for the next `up`" },
|
|
96
|
-
{ name: "max-payload", type: "string", value: "<bytes>", description: "broker-wide message size limit in bytes (default: nats-server's 1048576).
|
|
96
|
+
{ name: "max-payload", type: "string", value: "<bytes>", description: "broker-wide message size limit in bytes (default: nats-server's 1048576). A manager-backed start needs at least 263168, and service endpoint caller grants need at least 2098176. Fixed at broker start and recorded for the next `up`" },
|
|
97
97
|
{ name: "channels", type: "string", value: "<path>", description: "channel-registry seed file (JSON; default .cotal/channels.json)" },
|
|
98
98
|
{ name: "tls-cert", type: "string", value: "<file>", description: "serve the broker over TLS with this certificate (requires --tls-key)" },
|
|
99
99
|
{ name: "tls-key", type: "string", value: "<file>", description: "the private key for --tls-cert" },
|
|
@@ -228,6 +228,11 @@ export function validateUpArguments(args) {
|
|
|
228
228
|
// anything starts and a broker that comes up without its auth plane.
|
|
229
229
|
if (args.values["service-endpoints"] === true && requestedPayload < SERVICE_CALLER_PAYLOAD_FLOOR)
|
|
230
230
|
throw new CommandFailure("refused", "USAGE_INVALID", `--max-payload ${requestedPayload} is below ${SERVICE_CALLER_PAYLOAD_FLOOR} bytes, the least a space with --service-endpoints starts on: a caller policy row may grow to ${SERVICE_AUTHORITY_MAX_BYTES} bytes and its write needs ${SERVICE_CALLER_PAYLOAD_FLOOR - SERVICE_AUTHORITY_MAX_BYTES} more, so the auth host refuses to open; nothing was started`, { remedy: `pass --max-payload ${SERVICE_CALLER_PAYLOAD_FLOOR} or more, or drop --service-endpoints` });
|
|
231
|
+
// The manager publishes its contract artifacts, one message each, before it is ready. A limit
|
|
232
|
+
// below that publish is recorded and then every later start exits the same way. A broker-only
|
|
233
|
+
// start does not publish them, so it keeps the positive-integer check alone.
|
|
234
|
+
if (args.values["no-manager"] !== true && requestedPayload < MANAGER_START_PAYLOAD_FLOOR)
|
|
235
|
+
throw new CommandFailure("refused", "USAGE_INVALID", `--max-payload ${requestedPayload} is below ${MANAGER_START_PAYLOAD_FLOOR} bytes, the least the space's manager starts on: it publishes its contract artifacts, one message each, and the largest is bounded at ${CONTRACT_ARTIFACT_MAX_BYTES} bytes with ${MANAGER_START_PAYLOAD_FLOOR - CONTRACT_ARTIFACT_MAX_BYTES} more for the publish; nothing was started`, { remedy: `pass --max-payload ${MANAGER_START_PAYLOAD_FLOOR} or more, or pass --no-manager to start the broker without a manager` });
|
|
231
236
|
}
|
|
232
237
|
if (typeof args.values["store-dir"] === "string")
|
|
233
238
|
assertStoreDirArgument(args.values["store-dir"], typeof args.values.root === "string" ? resolve(args.values.root) : freshFolderRoot(args.values) ?? cotalRoot());
|
|
@@ -1782,6 +1787,14 @@ async function runUp(args, inheritedLock, onAdopt, freshTeamBoot = false, restor
|
|
|
1782
1787
|
console.error(c.red(`✗ mesh "${held.space}" is already running at ${server} - a running broker can't change --max-payload (it is fixed at start); \`cotal down\` it first, then \`cotal up --max-payload ${maxPayload}\``));
|
|
1783
1788
|
process.exit(1);
|
|
1784
1789
|
}
|
|
1790
|
+
// A bare refresh adds the manager this broker was started without. The manager publishes its
|
|
1791
|
+
// contract on the limit the broker already serves, so a recorded one below the floor is refused
|
|
1792
|
+
// before that launch rather than dying on the publish.
|
|
1793
|
+
const refreshPayload = maxPayload ?? runningPolicy?.maxPayload;
|
|
1794
|
+
if (!noManager && held.mode !== "open" && refreshPayload !== undefined && refreshPayload < MANAGER_START_PAYLOAD_FLOOR) {
|
|
1795
|
+
console.error(c.red(`✗ --max-payload ${refreshPayload} is below ${MANAGER_START_PAYLOAD_FLOOR} bytes, the least the space's manager starts on: it publishes its contract artifacts, one message each, and the largest is bounded at ${CONTRACT_ARTIFACT_MAX_BYTES} bytes with ${MANAGER_START_PAYLOAD_FLOOR - CONTRACT_ARTIFACT_MAX_BYTES} more for the publish; nothing was started`));
|
|
1796
|
+
process.exit(1);
|
|
1797
|
+
}
|
|
1785
1798
|
// The store directory is fixed the same way: an explicit --store-dir on a live refresh can
|
|
1786
1799
|
// only be refused when it disagrees with what the running broker actually opened. Absent
|
|
1787
1800
|
// `held.storeDir` (a pre-field record) has nothing to compare against, so it is not checked.
|
|
@@ -2135,7 +2148,7 @@ async function runUp(args, inheritedLock, onAdopt, freshTeamBoot = false, restor
|
|
|
2135
2148
|
// Decided above the branch; the dial host is only settled here (a port collision may have moved
|
|
2136
2149
|
// the server, and the hostname is what the certificate has to match).
|
|
2137
2150
|
assertServesDialHost(transport, new URL(server).hostname);
|
|
2138
|
-
const setup = useAuth ? await authSetup(storeDir, server, space, host, wantUser ? { idpUrl: values.idp } : undefined, transport, values["rotate-sys"], maxFileStore, false, { authTimeout, maxPayload }) : undefined;
|
|
2151
|
+
const setup = useAuth ? await authSetup(storeDir, server, space, host, wantUser ? { idpUrl: values.idp } : undefined, transport, values["rotate-sys"], maxFileStore, false, { authTimeout, maxPayload, manager: values["no-manager"] !== true }) : undefined;
|
|
2139
2152
|
const port = Number(new URL(server).port) || 4222;
|
|
2140
2153
|
// Both modes go through a RENDERER, never bare CLI flags. Open mode used to start from
|
|
2141
2154
|
// `-js -sd … -p … -a …`, which never called a renderer at all — so the required transport union
|
|
@@ -3308,7 +3321,7 @@ export async function recheckFreshTeamBoot(plan, own) {
|
|
|
3308
3321
|
export function controllerStackNative() {
|
|
3309
3322
|
return {
|
|
3310
3323
|
prepareBroker: async (opts) => {
|
|
3311
|
-
const prepared = await prepareBrokerStart({ transport: opts.transport, server: opts.server, space: opts.space, ...(opts.open ? { open: true } : {}), ...(opts.userAuth ? { userAuth: opts.userAuth } : {}), ...(opts.host ? { host: opts.host } : {}), ...(opts.storeDir ? { storeDir: opts.storeDir } : {}), ...(opts.existingStore ? { existingStore: opts.existingStore } : {}), ...(opts.maxFileStore !== undefined ? { maxFileStore: opts.maxFileStore } : {}), ...(opts.logFile !== undefined ? { logFile: opts.logFile } : {}), ...(opts.logfileSizeLimit !== undefined ? { logfileSizeLimit: opts.logfileSizeLimit } : {}), ...(opts.logfileMaxNum !== undefined ? { logfileMaxNum: opts.logfileMaxNum } : {}), ...(opts.authTimeout !== undefined ? { authTimeout: opts.authTimeout } : {}), ...(opts.maxPayload !== undefined ? { maxPayload: opts.maxPayload } : {}), ...(opts.seed !== undefined ? { seed: opts.seed } : opts.channels ? { channels: opts.channels } : {}), quietBoot: true });
|
|
3324
|
+
const prepared = await prepareBrokerStart({ transport: opts.transport, server: opts.server, space: opts.space, ...(opts.open ? { open: true } : {}), ...(opts.userAuth ? { userAuth: opts.userAuth } : {}), ...(opts.host ? { host: opts.host } : {}), ...(opts.storeDir ? { storeDir: opts.storeDir } : {}), ...(opts.existingStore ? { existingStore: opts.existingStore } : {}), ...(opts.maxFileStore !== undefined ? { maxFileStore: opts.maxFileStore } : {}), ...(opts.logFile !== undefined ? { logFile: opts.logFile } : {}), ...(opts.logfileSizeLimit !== undefined ? { logfileSizeLimit: opts.logfileSizeLimit } : {}), ...(opts.logfileMaxNum !== undefined ? { logfileMaxNum: opts.logfileMaxNum } : {}), ...(opts.authTimeout !== undefined ? { authTimeout: opts.authTimeout } : {}), ...(opts.maxPayload !== undefined ? { maxPayload: opts.maxPayload } : {}), ...(opts.noManager ? { noManager: true } : {}), ...(opts.seed !== undefined ? { seed: opts.seed } : opts.channels ? { channels: opts.channels } : {}), quietBoot: true });
|
|
3312
3325
|
return { root: prepared.root, server: prepared.server, space: prepared.space, storeDir: prepared.storeDir, transport: prepared.transport, ...(prepared.setup ? { setup: { creds: prepared.setup.creds, wsPort: prepared.setup.wsPort } } : {}), ...(prepared.setup?.prepared && prepared.setup.stateDir ? { user: { prepared: prepared.setup.prepared, stateDir: prepared.setup.stateDir } } : {}), confPath: prepared.confPath, bin: prepared.bin, source: prepared.source, version: prepared.version, seedFile: prepared.seedFile, ...(prepared.setup?.authTimeout !== undefined ? { authTimeout: prepared.setup.authTimeout } : {}), ...(prepared.setup?.maxPayload !== undefined ? { maxPayload: prepared.setup.maxPayload } : {}) };
|
|
3313
3326
|
},
|
|
3314
3327
|
initializeStreams: (server, space, setup, seedFile, recreateIssuedStores) => postStart(server, space, setup, seedFile, recreateIssuedStores),
|
|
@@ -3959,7 +3972,7 @@ export async function prepareBrokerStart(opts) {
|
|
|
3959
3972
|
closeSync(fd);
|
|
3960
3973
|
}
|
|
3961
3974
|
}
|
|
3962
|
-
const setup = useAuth ? await authSetup(storeDir, server, space, host, opts.userAuth, transport, opts.rotateSys, opts.maxFileStore, opts.quietBoot, { authTimeout: opts.authTimeout, maxPayload: opts.maxPayload, logFile, logfileSizeLimit: opts.logfileSizeLimit, logfileMaxNum: opts.logfileMaxNum }) : undefined;
|
|
3975
|
+
const setup = useAuth ? await authSetup(storeDir, server, space, host, opts.userAuth, transport, opts.rotateSys, opts.maxFileStore, opts.quietBoot, { authTimeout: opts.authTimeout, maxPayload: opts.maxPayload, manager: opts.noManager !== true, logFile, logfileSizeLimit: opts.logfileSizeLimit, logfileMaxNum: opts.logfileMaxNum }) : undefined;
|
|
3963
3976
|
const port = Number(new URL(server).port) || 4222;
|
|
3964
3977
|
// Same rule as the foreground path: every route to a listener names its transport (see
|
|
3965
3978
|
// `writeOpenBrokerConf`). Detach must not be the mode where the fence quietly does not apply.
|
|
@@ -5388,6 +5401,10 @@ requested = {}) {
|
|
|
5388
5401
|
const recorded = readBrokerPolicy(cotalRoot());
|
|
5389
5402
|
const authTimeout = requested.authTimeout ?? recorded?.authTimeout;
|
|
5390
5403
|
const maxPayload = requested.maxPayload ?? recorded?.maxPayload;
|
|
5404
|
+
// The same floor an explicit --max-payload already met. A later bare up reads the recorded limit
|
|
5405
|
+
// and would otherwise render it again, then die the same way. A broker-only start does not publish.
|
|
5406
|
+
if (requested.manager === true && maxPayload !== undefined && maxPayload < MANAGER_START_PAYLOAD_FLOOR)
|
|
5407
|
+
throw new CommandFailure("refused", "USAGE_INVALID", `--max-payload ${maxPayload} is below ${MANAGER_START_PAYLOAD_FLOOR} bytes, the least the space's manager starts on: it publishes its contract artifacts, one message each, and the largest is bounded at ${CONTRACT_ARTIFACT_MAX_BYTES} bytes with ${MANAGER_START_PAYLOAD_FLOOR - CONTRACT_ARTIFACT_MAX_BYTES} more for the publish; nothing was started`, { remedy: `pass --max-payload ${MANAGER_START_PAYLOAD_FLOOR} or more, or pass --no-manager to start the broker without a manager` });
|
|
5391
5408
|
writeBrokerConfig(confPath, serverConfig(auth, spaces, { transport, port, storeDir: configuredStoreDir(cotalRoot(), storeDir), maxFileStore, authTimeout, maxPayload, logFile: requested.logFile, logfileSizeLimit: requested.logfileSizeLimit, logfileMaxNum: requested.logfileMaxNum, host, wsPort, wsHost: host, extraAccounts }));
|
|
5392
5409
|
// Ephemeral setup cred: used only to probe reachability, pre-create the space streams/buckets
|
|
5393
5410
|
// (setupSpaceStreams) and seed the channel registry (seedChannelRegistry) — all within the
|