@cotal-ai/cli 0.148.2 → 0.149.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/app-identity.d.ts.map +1 -1
- package/dist/commands/app-identity.js +10 -25
- package/dist/commands/app-identity.js.map +1 -1
- package/dist/commands/join.d.ts.map +1 -1
- package/dist/commands/join.js +25 -39
- package/dist/commands/join.js.map +1 -1
- package/dist/commands/mint.d.ts.map +1 -1
- package/dist/commands/mint.js +4 -9
- package/dist/commands/mint.js.map +1 -1
- package/dist/commands/spawn.d.ts.map +1 -1
- package/dist/commands/spawn.js +35 -90
- package/dist/commands/spawn.js.map +1 -1
- package/dist/lib/app-user-identity.d.ts.map +1 -1
- package/dist/lib/app-user-identity.js +3 -14
- package/dist/lib/app-user-identity.js.map +1 -1
- package/dist/lib/provisioner.d.ts +16 -0
- package/dist/lib/provisioner.d.ts.map +1 -0
- package/dist/lib/provisioner.js +30 -0
- package/dist/lib/provisioner.js.map +1 -0
- package/dist/lib/restore.js +7 -7
- package/dist/lib/restore.js.map +1 -1
- package/package.json +4 -4
package/dist/commands/spawn.js
CHANGED
|
@@ -3,11 +3,12 @@ import { createHash } from "node:crypto";
|
|
|
3
3
|
import { readFileSync, rmSync, statSync } from "node:fs";
|
|
4
4
|
import { hostname } from "node:os";
|
|
5
5
|
import { resolve as resolvePath } from "node:path";
|
|
6
|
-
import { assertValidRole, agentFilePath, AgentGrantConflictError, connectorServers, spawnEnvAllow, deprovisionAgent, discardLaunchArtifacts, firstFreeName, isReachable, reclaimWithChild, loadCotalConfig, modelPolicyRefusal, mintCreds, newIdentity, DEV_OWNER, parseShareSelection, principalKey, assertLifecycleToken, mintLifecycleUid, MANAGED_HANDOFF_FILE_ENV, parseManagedLifecycleHandoff, spawnNameError, provisionAgent, provisionAgentDurables, registry, resolveAuthProvider, resolveReadAcl, runAgentBearer,
|
|
6
|
+
import { assertValidRole, agentFilePath, AgentGrantConflictError, connectorServers, spawnEnvAllow, deprovisionAgent, discardLaunchArtifacts, firstFreeName, isReachable, reclaimWithChild, loadCotalConfig, modelPolicyRefusal, mintCreds, newIdentity, DEV_OWNER, parseShareSelection, principalKey, assertLifecycleToken, mintLifecycleUid, MANAGED_HANDOFF_FILE_ENV, parseManagedLifecycleHandoff, spawnNameError, provisionAgent, provisionAgentDurables, registry, resolveAuthProvider, resolveReadAcl, runAgentBearer, GOAL_ENTITY_RUNNING_DETAIL_KIND, EP_UNDECLARED_ARG, seatCapFrom, acquireLock, inspectLock, localConsumerClaimPath, transferBucket, writeTransfer, peerLabel, attemptCleanup, describeCleanupFailures, rejectionText, } from "@cotal-ai/core";
|
|
7
7
|
import { parseCommaList, CommandFailure, loadLaunchPersonaFile, personaFileReference, PersonaSourceError, inputDisabledByFlag, jsonFlag, plainFlag, presentationOf, recordOperationWarning, renderReport, terminalWidth, wrapWords, writeResult, agentActorTokenKey, agentLifecycleSecretFilePaths, agentSecretFilePaths, agentSecretKeyForFile, agentSentinelCredsKey, authDir, cachedPreferences, credsFlag, launchFlags, findMesh, getSpaceAuth, loadManagerInstanceIdentity, materializeSecretToFile, mergeLaunchOptions, parseLaunchOptions, preflightOrThrow, provenance, resolveAgentType, resolvePreference, resolveTargetOrThrow, serverFlag, spaceAccountPath, spaceFlag, spaceKey, userAuthStateDir, workspaceSecretStore, refreshRegistrationPolicy, resolveSeatControlTarget, connectUserControlOrExit, userViewAuth, oneLine, codeSpan, DEFAULT_CONNECTOR, hintedConnector, manifestExtensionNames, OFFICIAL_CONNECTORS, recordOperationSpace, resolveMeshTarget, activateTerminalSeat, issueTerminalSeat, retireTerminalSeat, seatExpiryAt, resolveControlTarget, } from "@cotal-ai/workspace";
|
|
8
8
|
import { readManagedLaunch, requestManagedLaunch } from "@cotal-ai/workspace/launch";
|
|
9
9
|
import { c, stderrLine } from "../ui.js";
|
|
10
10
|
import { liveMeshNames } from "../lib/live-names.js";
|
|
11
|
+
import { withProvisioner } from "../lib/provisioner.js";
|
|
11
12
|
import { displayCmd } from "../lib/self-exec.js";
|
|
12
13
|
import { entryScript } from "../seed/paths.js";
|
|
13
14
|
import { completedFlagValue, completingFlagValue, hasCompletedFlagValue, positionalsForCompletion } from "../lib/completion.js";
|
|
@@ -586,7 +587,8 @@ export async function launchManagedPersona(values, positionals, events, launchOp
|
|
|
586
587
|
// Without a flag the harness is the persona pin or a default, which only the target manager
|
|
587
588
|
// can read: ask it, so the carry looks with the connector the launch runs (#2899).
|
|
588
589
|
const agent = values.agent ?? await launchAgentOrExit(t, on, { name: ref, config: managerConfigRef, defaultAgent });
|
|
589
|
-
|
|
590
|
+
// The carry and its transfer-writer view stay on the mesh selected for this launch.
|
|
591
|
+
const claim = await carryTranscriptOrExit({ ...flags, space: t.space, server: t.server }, on, values.resume, agent);
|
|
590
592
|
if (claim !== undefined)
|
|
591
593
|
resumeClaim = { claim, agent };
|
|
592
594
|
}
|
|
@@ -1596,49 +1598,36 @@ export async function spawn(args) {
|
|
|
1596
1598
|
// channel rather than two.
|
|
1597
1599
|
if (launchEvents)
|
|
1598
1600
|
allowPublish = [...(allowPublish ?? []), connector.eventChannel({ owner: DEV_OWNER, actor: identity.id })];
|
|
1599
|
-
const prov = new CotalEndpoint({
|
|
1600
|
-
space,
|
|
1601
|
-
servers: server,
|
|
1602
|
-
creds: await mintCreds(auth, newIdentity(), "provisioner"),
|
|
1603
|
-
channels: [],
|
|
1604
|
-
consume: false,
|
|
1605
|
-
registerPresence: false,
|
|
1606
|
-
watchPresence: false,
|
|
1607
|
-
watchChannels: false,
|
|
1608
|
-
card: { name: "spawn-provisioner", role: "provisioner", kind: "endpoint" },
|
|
1609
|
-
});
|
|
1610
|
-
const reportStaticProvisioner = (e) => console.error(`! provisioner: ${e.message}`);
|
|
1611
|
-
prov.on("error", reportStaticProvisioner);
|
|
1612
|
-
prov.on("warning", reportStaticProvisioner);
|
|
1613
|
-
await prov.start();
|
|
1614
1601
|
// Foreground provisions the SAME durable footprint as `--detach` (DM/DLV durables + read-ACL
|
|
1615
1602
|
// row): the daemon authorizes durable joins off the ACL row and leave is agent self-service, so
|
|
1616
1603
|
// no managing host is required — and a silently live-only foreground agent permanently loses
|
|
1617
1604
|
// every channel message posted while its connection blips (reconnect deliberately re-opens the
|
|
1618
1605
|
// core-subs without re-backfill). `--live-only` opts back out; on a mesh with no delivery
|
|
1619
|
-
// daemon the boot join itself reports live-only, ACL row or not.
|
|
1606
|
+
// daemon the boot join itself reports live-only, ACL row or not. A failed provisioner stop
|
|
1607
|
+
// never reaches this catch, so it cannot retire a credential the provisioning already minted.
|
|
1620
1608
|
try {
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1609
|
+
const creds = await withProvisioner({ space, servers: server, auth }, "spawn-provisioner", async (prov) => {
|
|
1610
|
+
// The seat's lifecycle is activated first, so the issuance can name its gate as the source of
|
|
1611
|
+
// the evidence a helper's spawn is bounded by.
|
|
1612
|
+
const seatTarget = { server, space, tlsRequired: target.tlsRequired, auth };
|
|
1613
|
+
seat = { actor: identity.id, alias: name, lifecycleUid };
|
|
1614
|
+
await activateTerminalSeat(seatTarget, seat);
|
|
1615
|
+
return issueTerminalSeat(seatTarget, seat, seatExpiry(values, true), (issue) => {
|
|
1616
|
+
acceptedToken = issue.issued.acceptedToken;
|
|
1617
|
+
return provisionAgent(prov, auth, identity, {
|
|
1618
|
+
subscribe,
|
|
1619
|
+
allowSubscribe,
|
|
1620
|
+
allowPublish,
|
|
1621
|
+
role,
|
|
1622
|
+
capabilities: def.capabilities,
|
|
1623
|
+
...(values["live-only"] ? { durableMembership: false } : {}),
|
|
1624
|
+
lifecycleUid,
|
|
1625
|
+
expiresAt: issue.expiresAt,
|
|
1626
|
+
issued: issue.issued,
|
|
1627
|
+
issuance: issue.issuance,
|
|
1628
|
+
});
|
|
1639
1629
|
});
|
|
1640
1630
|
});
|
|
1641
|
-
await prov.stop();
|
|
1642
1631
|
// Store first (the source of truth), then materialize — the child's launch reads this FILE.
|
|
1643
1632
|
// The CLI is the local FS composition (byte-identical), same posture as the manager's spawn.
|
|
1644
1633
|
const secrets = workspaceSecretStore(target.root);
|
|
@@ -1797,31 +1786,6 @@ function checkRemoteAgentMaterial(v, actor) {
|
|
|
1797
1786
|
},
|
|
1798
1787
|
};
|
|
1799
1788
|
}
|
|
1800
|
-
/** A caught value's text for a refusal. A provider or store may reject with any value, including null
|
|
1801
|
-
* or one whose `message` getter or `toString` throws, and the refusal must still be printed, so the
|
|
1802
|
-
* coercion to text runs inside the guard. */
|
|
1803
|
-
function rejectionText(e) {
|
|
1804
|
-
try {
|
|
1805
|
-
return String(e?.message ?? e);
|
|
1806
|
-
}
|
|
1807
|
-
catch {
|
|
1808
|
-
return "an unreadable rejection";
|
|
1809
|
-
}
|
|
1810
|
-
}
|
|
1811
|
-
/** Run one cleanup step, recording its failure in `failed`. A step that threw would otherwise skip
|
|
1812
|
-
* every step after it, and a swallowed one would leave nothing to report. */
|
|
1813
|
-
async function attemptCleanup(failed, step, run) {
|
|
1814
|
-
try {
|
|
1815
|
-
await run();
|
|
1816
|
-
}
|
|
1817
|
-
catch (err) {
|
|
1818
|
-
failed.push({ step, err });
|
|
1819
|
-
}
|
|
1820
|
-
}
|
|
1821
|
-
/** `<step>: <reason>` for each failure. */
|
|
1822
|
-
function describeCleanupFailures(failed) {
|
|
1823
|
-
return failed.map(({ step, err }) => `${step}: ${rejectionText(err)}`).join("; ");
|
|
1824
|
-
}
|
|
1825
1789
|
/** Shred a user-mode agent's local material: both secrets from the store, then their files and the
|
|
1826
1790
|
* health file. Each step is attempted and a failed one is recorded in `failed`. */
|
|
1827
1791
|
async function shredAgentMaterial(failed, store, space, name, composition, paths) {
|
|
@@ -2070,34 +2034,15 @@ async function provisionUserForeground(target, name, ref, opts) {
|
|
|
2070
2034
|
custody: { kind: "foreground" },
|
|
2071
2035
|
});
|
|
2072
2036
|
ownedToken = grant.actorToken;
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
card: { name: "spawn-provisioner", role: "provisioner", kind: "endpoint" },
|
|
2083
|
-
});
|
|
2084
|
-
const reportUserProvisioner = (e) => console.error(`! provisioner: ${e.message}`);
|
|
2085
|
-
prov.on("error", reportUserProvisioner);
|
|
2086
|
-
prov.on("warning", reportUserProvisioner);
|
|
2087
|
-
await prov.start();
|
|
2088
|
-
try {
|
|
2089
|
-
// Full durable footprint, same as the static foreground path: the ACL row is what lets the
|
|
2090
|
-
// delivery daemon authorize this agent's durable joins. `--live-only` opts out.
|
|
2091
|
-
await provisionAgentDurables(prov, { owner, actor: name, lifecycleUid: opts.lifecycleUid }, {
|
|
2092
|
-
subscribe: opts.subscribe,
|
|
2093
|
-
allowSubscribe: opts.allowSubscribe,
|
|
2094
|
-
role: opts.role,
|
|
2095
|
-
...(opts.liveOnly ? { durableMembership: false } : {}),
|
|
2096
|
-
});
|
|
2097
|
-
}
|
|
2098
|
-
finally {
|
|
2099
|
-
await prov.stop();
|
|
2100
|
-
}
|
|
2037
|
+
await withProvisioner({ space, servers: server, auth: infra }, "spawn-provisioner", (prov) =>
|
|
2038
|
+
// Full durable footprint, same as the static foreground path: the ACL row is what lets the
|
|
2039
|
+
// delivery daemon authorize this agent's durable joins. `--live-only` opts out.
|
|
2040
|
+
provisionAgentDurables(prov, { owner, actor: name, lifecycleUid: opts.lifecycleUid }, {
|
|
2041
|
+
subscribe: opts.subscribe,
|
|
2042
|
+
allowSubscribe: opts.allowSubscribe,
|
|
2043
|
+
role: opts.role,
|
|
2044
|
+
...(opts.liveOnly ? { durableMembership: false } : {}),
|
|
2045
|
+
}));
|
|
2101
2046
|
// The store holds the source of truth; the bearer re-exec (`--token-file`) and the launch's
|
|
2102
2047
|
// sentinel handoff read FILES — materialize both at the canonical paths (byte-identical
|
|
2103
2048
|
// rewrites under this, the local FS, composition).
|