@tinycloud/cli 1.3.0-beta.24 → 1.3.0-beta.25

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.
@@ -9786,18 +9786,89 @@ var init_profiles = __esm({
9786
9786
  // src/commands/account.ts
9787
9787
  init_profiles();
9788
9788
  init_constants();
9789
+ import open6 from "open";
9790
+ import { readFile as readFile6 } from "fs/promises";
9791
+
9792
+ // src/lib/account-access.ts
9793
+ init_constants();
9794
+ init_errors();
9795
+ init_profiles();
9796
+ init_permissions();
9797
+ import { ACCOUNT_MANIFEST_PERMISSIONS } from "@tinycloud/sdk-core";
9798
+ import { CLI_NAME as CLI_NAME10 } from "@tinycloud/operations/cli-name";
9799
+ var PRIMARY_SPACE = "default";
9800
+ function accountPermissionEntries(need = "registry") {
9801
+ const entries = ACCOUNT_MANIFEST_PERMISSIONS.map((resource) => ({
9802
+ service: resource.service,
9803
+ space: resource.space,
9804
+ path: resource.path,
9805
+ actions: [...resource.actions]
9806
+ }));
9807
+ if (need === "remove") {
9808
+ for (const path of ["applications/", "spaces/"]) {
9809
+ entries.push({ service: "tinycloud.kv", space: "account", path, actions: ["tinycloud.kv/del"] });
9810
+ }
9811
+ }
9812
+ if (need === "spaces" || need === "delegations") {
9813
+ entries.push({ service: "tinycloud.space", space: PRIMARY_SPACE, path: "", actions: ["tinycloud.space/list"] });
9814
+ }
9815
+ if (need === "delegations") {
9816
+ entries.push(capabilitiesRead(PRIMARY_SPACE));
9817
+ }
9818
+ return entries;
9819
+ }
9820
+ function capabilitiesRead(space) {
9821
+ return { service: "tinycloud.capabilities", space, path: "", actions: ["tinycloud.capabilities/read"] };
9822
+ }
9823
+ function capSpecs(entries) {
9824
+ return entries.map((entry) => {
9825
+ const actions = entry.actions.map((action) => action.slice(action.lastIndexOf("/") + 1));
9826
+ return `${entry.service}:${entry.space}:${entry.path}:${actions.join(",")}`;
9827
+ });
9828
+ }
9829
+ function shellWord(value) {
9830
+ return /^[A-Za-z0-9._@:+-]+$/.test(value) ? value : `'${value.replace(/'/g, `'\\''`)}'`;
9831
+ }
9832
+ function accessRequired(profile, entries, what) {
9833
+ const grant = `${CLI_NAME10} --profile ${shellWord(profile)} auth request --grant ` + capSpecs(entries).map((spec) => `--cap '${spec}'`).join(" ");
9834
+ const approvals = new Set(entries.map((entry) => entry.space)).size;
9835
+ return new CLIError(
9836
+ "ACCOUNT_ACCESS_REQUIRED",
9837
+ `This session lacks account permissions this command needs (${what}). A plain OpenKey login grants only the \`default\` space.`,
9838
+ ExitCode.PERMISSION_DENIED,
9839
+ {
9840
+ hint: `Grant account access (${approvals} OpenKey approval${approvals === 1 ? "" : "s"}), then retry: ${grant}
9841
+ If the browser cannot reach the CLI, re-run with --paste: ${grant} --paste`
9842
+ }
9843
+ );
9844
+ }
9845
+ async function assertAccountAccess(node, profile, need = "registry", cid) {
9846
+ if (need === "revoke") {
9847
+ if ((await ProfileManager.getProfile(profile)).authMethod === "local") return;
9848
+ throw new CLIError(
9849
+ "ACCOUNT_REVOKE_UNSUPPORTED",
9850
+ "This profile signs through OpenKey, which cannot sign the raw-CID revocation `account delegations revoke` needs.",
9851
+ ExitCode.PERMISSION_DENIED,
9852
+ { hint: `Revoke it with: ${CLI_NAME10} --profile ${shellWord(profile)} delegation revoke ${cid ?? "<cid>"}` }
9853
+ );
9854
+ }
9855
+ const entries = accountPermissionEntries(need);
9856
+ const required = await resolvePermissionSpaces(entries, profile);
9857
+ if (node.hasRuntimePermissions(required)) return;
9858
+ throw accessRequired(profile, entries, need === "registry" ? "kv applications/ and spaces/, sql account, delegation list, capabilities read on `account`" : `the \`account\` registry set plus ${need === "remove" ? "kv del on applications/ and spaces/" : "space list and capabilities read on `default`"}`);
9859
+ }
9860
+
9861
+ // src/commands/account.ts
9789
9862
  init_sdk();
9790
9863
  init_errors();
9791
9864
  init_formatter();
9792
9865
  init_theme();
9793
- import open6 from "open";
9794
- import { readFile as readFile6 } from "fs/promises";
9795
9866
  var ACCOUNT_BILLING_URL = "https://account.tinycloud.xyz/billing";
9796
9867
  function registerAccountCommand(program) {
9797
9868
  const account = program.command("account").description("Account applications, spaces, delegations, and billing");
9798
9869
  account.command("status").description("Show account status").action(async (_options, cmd) => {
9799
9870
  try {
9800
- const node = await authenticatedNode(cmd);
9871
+ const node = await authenticatedNode(cmd, "delegations");
9801
9872
  const status = await node.account.status();
9802
9873
  assertOk(status);
9803
9874
  outputJson(status.data);
@@ -9839,7 +9910,7 @@ function registerAccountCommand(program) {
9839
9910
  const spaces = account.command("spaces").description("Manage account space registry");
9840
9911
  spaces.command("list").description("List spaces registered under account/spaces").option("--live", "Read canonical account KV records instead of the SQLite index").action(async (options, cmd) => {
9841
9912
  try {
9842
- const node = await authenticatedNode(cmd);
9913
+ const node = await authenticatedNode(cmd, "spaces");
9843
9914
  const result = options.live ? await node.account.spaces.list() : await node.account.spaces.list({ preferIndex: true });
9844
9915
  assertOk(result);
9845
9916
  const payload = { spaces: result.data.map(formatSpace), count: result.data.length };
@@ -9896,7 +9967,7 @@ function registerAccountCommand(program) {
9896
9967
  });
9897
9968
  spaces.command("sync").description("Register currently accessible spaces into account/spaces").action(async (_options, cmd) => {
9898
9969
  try {
9899
- const node = await authenticatedNode(cmd);
9970
+ const node = await authenticatedNode(cmd, "spaces");
9900
9971
  const result = await node.account.spaces.syncAccessible();
9901
9972
  assertOk(result);
9902
9973
  outputJson({ spaces: result.data.map(formatSpace), count: result.data.length, synced: true });
@@ -9906,7 +9977,7 @@ function registerAccountCommand(program) {
9906
9977
  });
9907
9978
  spaces.command("remove <space-id>").alias("delete").description("Remove a space registry entry").action(async (spaceId, _options, cmd) => {
9908
9979
  try {
9909
- const node = await authenticatedNode(cmd);
9980
+ const node = await authenticatedNode(cmd, "remove");
9910
9981
  const result = await node.account.spaces.remove(spaceId);
9911
9982
  assertOk(result);
9912
9983
  outputJson({ spaceId, removed: true });
@@ -9937,7 +10008,7 @@ function registerAccountCommand(program) {
9937
10008
  });
9938
10009
  apps.command("remove <app-id>").alias("delete").description("Remove an application registry entry").action(async (appId, _options, cmd) => {
9939
10010
  try {
9940
- const node = await authenticatedNode(cmd);
10011
+ const node = await authenticatedNode(cmd, "remove");
9941
10012
  const result = await node.account.applications.remove(appId);
9942
10013
  assertOk(result);
9943
10014
  outputJson({ appId, removed: true });
@@ -9951,7 +10022,7 @@ function registerAccountCommand(program) {
9951
10022
  if (options.granted && options.received) {
9952
10023
  throw new CLIError("USAGE_ERROR", "Use only one of --granted or --received.", ExitCode.USAGE_ERROR);
9953
10024
  }
9954
- const node = await authenticatedNode(cmd);
10025
+ const node = await authenticatedNode(cmd, "delegations");
9955
10026
  const direction = options.granted ? "granted" : options.received ? "received" : "all";
9956
10027
  const result = options.live ? await node.account.delegations.list({ direction, space: options.space }) : await node.account.delegations.list({ direction, space: options.space, preferIndex: true });
9957
10028
  assertOk(result);
@@ -9983,7 +10054,7 @@ function registerAccountCommand(program) {
9983
10054
  });
9984
10055
  delegations.command("revoke <cid>").description("Revoke an active delegation granted by this account").requiredOption("--space <space>", "Space name or ID containing the delegation").action(async (cid, options, cmd) => {
9985
10056
  try {
9986
- const node = await authenticatedNode(cmd);
10057
+ const node = await authenticatedNode(cmd, "revoke", cid);
9987
10058
  const result = await node.account.delegations.revoke({ cid, space: options.space });
9988
10059
  assertOk(result);
9989
10060
  outputJson({ cid, space: options.space, revoked: true });
@@ -10014,7 +10085,7 @@ function registerAccountCommand(program) {
10014
10085
  });
10015
10086
  index.command("rebuild").description("Rebuild account SQLite index from canonical account data").action(async (_options, cmd) => {
10016
10087
  try {
10017
- const node = await authenticatedNode(cmd);
10088
+ const node = await authenticatedNode(cmd, "delegations");
10018
10089
  const result = await node.account.index.rebuild();
10019
10090
  assertOk(result);
10020
10091
  outputJson(result.data);
@@ -10047,10 +10118,12 @@ function registerAccountCommand(program) {
10047
10118
  });
10048
10119
  }
10049
10120
  }
10050
- async function authenticatedNode(cmd) {
10121
+ async function authenticatedNode(cmd, need = "registry", cid) {
10051
10122
  const globalOpts = cmd.optsWithGlobals();
10052
10123
  const ctx = await ProfileManager.resolveContext(globalOpts);
10053
- return ensureAuthenticated(ctx);
10124
+ const node = await ensureAuthenticated(ctx);
10125
+ await assertAccountAccess(node, ctx.profile, need, cid);
10126
+ return node;
10054
10127
  }
10055
10128
  function assertOk(result) {
10056
10129
  if (!result.ok) {
@@ -10107,7 +10180,7 @@ function formatSpace(space) {
10107
10180
  init_profile_gate();
10108
10181
  init_dist();
10109
10182
  init_profiles();
10110
- import { CLI_NAME as CLI_NAME14 } from "@tinycloud/operations/cli-name";
10183
+ import { CLI_NAME as CLI_NAME15 } from "@tinycloud/operations/cli-name";
10111
10184
  import { get as httpGet } from "http";
10112
10185
  import { get as httpsGet } from "https";
10113
10186
  import { spawn } from "child_process";
@@ -11067,14 +11140,14 @@ init_space();
11067
11140
  import { lstat as lstat6 } from "fs/promises";
11068
11141
  import { join as join12 } from "path";
11069
11142
  import { REPLICA_LOGOUT_PENDING_FILE as REPLICA_LOGOUT_PENDING_FILE3 } from "@tinycloud/node-sdk";
11070
- import { CLI_NAME as CLI_NAME10 } from "@tinycloud/operations/cli-name";
11143
+ import { CLI_NAME as CLI_NAME11 } from "@tinycloud/operations/cli-name";
11071
11144
  import { isLocalOwnerProfile as isLocalOwnerProfile3, ownerSessionLacksProof as ownerSessionLacksProof3 } from "@tinycloud/operations/profile";
11072
11145
  import { ProfileLockTimeoutError as ProfileLockTimeoutError2, profilePath as profilePath7 } from "@tinycloud/operations/state";
11073
11146
  function assertNotLocalOwner(profileName2, profile, flow) {
11074
11147
  if (profile === null || !isLocalOwnerProfile3(profile)) return;
11075
11148
  throw new CLIError(
11076
11149
  "LOCAL_OWNER_PROFILE",
11077
- `Profile "${profileName2}" holds a local owner key. ${flow} would turn it into an OpenKey profile while keeping that key. Use a separate profile: \`${CLI_NAME10} init --name publisher --key-only\`, then \`${CLI_NAME10} --profile publisher auth login --device --manifest ...\`.`,
11150
+ `Profile "${profileName2}" holds a local owner key. ${flow} would turn it into an OpenKey profile while keeping that key. Use a separate profile: \`${CLI_NAME11} init --name publisher --key-only\`, then \`${CLI_NAME11} --profile publisher auth login --device --manifest ...\`.`,
11078
11151
  ExitCode.USAGE_ERROR
11079
11152
  );
11080
11153
  }
@@ -11109,7 +11182,7 @@ function assertSessionReplaceable(profileName2, snapshot, ownerDid, scope, newEx
11109
11182
  if (problem !== void 0) {
11110
11183
  throw new CLIError(
11111
11184
  "PROFILE_STATE_INCONSISTENT",
11112
- `Profile "${profileName2}" is inconsistent (${problem}), possibly from an interrupted write. Nothing was saved. Check \`${CLI_NAME10} --profile ${profileName2} context\`, then pass --replace-session to replace this state, or use a new profile.`,
11185
+ `Profile "${profileName2}" is inconsistent (${problem}), possibly from an interrupted write. Nothing was saved. Check \`${CLI_NAME11} --profile ${profileName2} context\`, then pass --replace-session to replace this state, or use a new profile.`,
11113
11186
  ExitCode.ERROR
11114
11187
  );
11115
11188
  }
@@ -11125,7 +11198,7 @@ function assertSessionReplaceable(profileName2, snapshot, ownerDid, scope, newEx
11125
11198
  const space = typeof session.spaceId === "string" ? session.spaceId : "an unknown space";
11126
11199
  throw new CLIError(
11127
11200
  "SESSION_IN_USE",
11128
- `Profile "${profileName2}" has a live session for ${space}${expiresAt ? ` until ${expiresAt}` : ""} that this login would ${keepsScope ? "shorten" : "narrow or replace"}, dropping that authority. Nothing was saved. Keep the user's existing profiles: use a new profile name (\`${CLI_NAME10} init --name publisher --key-only\`, then \`${CLI_NAME10} --profile publisher auth login --device --manifest ...\`), or pass --replace-session to replace this session.`,
11201
+ `Profile "${profileName2}" has a live session for ${space}${expiresAt ? ` until ${expiresAt}` : ""} that this login would ${keepsScope ? "shorten" : "narrow or replace"}, dropping that authority. Nothing was saved. Keep the user's existing profiles: use a new profile name (\`${CLI_NAME11} init --name publisher --key-only\`, then \`${CLI_NAME11} --profile publisher auth login --device --manifest ...\`), or pass --replace-session to replace this session.`,
11129
11202
  ExitCode.USAGE_ERROR
11130
11203
  );
11131
11204
  }
@@ -11159,7 +11232,7 @@ async function commitLogin(profileName2, snapshot, commit) {
11159
11232
  if (canonicalJson(current.profile) !== canonicalJson(snapshot.profile) || canonicalJson(current.key) !== canonicalJson(snapshot.key) || canonicalJson(current.session) !== canonicalJson(snapshot.session)) {
11160
11233
  throw new CLIError(
11161
11234
  "PROFILE_CHANGED_DURING_LOGIN",
11162
- `Profile "${profileName2}" changed while this login was in progress (another login, key rotation or logout). Nothing was saved; check \`${CLI_NAME10} --profile ${profileName2} context\` and run the login again if it is still needed.`,
11235
+ `Profile "${profileName2}" changed while this login was in progress (another login, key rotation or logout). Nothing was saved; check \`${CLI_NAME11} --profile ${profileName2} context\` and run the login again if it is still needed.`,
11163
11236
  ExitCode.ERROR
11164
11237
  );
11165
11238
  }
@@ -11191,7 +11264,7 @@ async function commitLogin(profileName2, snapshot, commit) {
11191
11264
  if (failures.length === 0) throw error;
11192
11265
  throw new CLIError(
11193
11266
  "PROFILE_STATE_INCONSISTENT",
11194
- `Saving the login for profile "${profileName2}" failed (${errorMessage(error)}), and restoring its previous state failed too (${failures.map(errorMessage).join("; ")}). The profile's key, session and settings may not match. Check \`${CLI_NAME10} --profile ${profileName2} context\`, then run the login again with --replace-session, or use a new profile.`,
11267
+ `Saving the login for profile "${profileName2}" failed (${errorMessage(error)}), and restoring its previous state failed too (${failures.map(errorMessage).join("; ")}). The profile's key, session and settings may not match. Check \`${CLI_NAME11} --profile ${profileName2} context\`, then run the login again with --replace-session, or use a new profile.`,
11195
11268
  ExitCode.ERROR
11196
11269
  );
11197
11270
  }
@@ -11207,7 +11280,7 @@ async function commitLogin(profileName2, snapshot, commit) {
11207
11280
 
11208
11281
  // src/auth/owner-key.ts
11209
11282
  init_theme();
11210
- import { CLI_NAME as CLI_NAME11 } from "@tinycloud/operations/cli-name";
11283
+ import { CLI_NAME as CLI_NAME12 } from "@tinycloud/operations/cli-name";
11211
11284
  function openKeyPrimaryFlag(delegation) {
11212
11285
  return typeof delegation.primary === "boolean" ? delegation.primary : void 0;
11213
11286
  }
@@ -11218,7 +11291,7 @@ function withOwnerKeyPrimary(profile, primary) {
11218
11291
  function nonPrimaryKeyWarning(ownerDid) {
11219
11292
  const address = ownerDid.split(":")[4] ?? ownerDid;
11220
11293
  return `${theme.warn("Warning:")} you signed in with OpenKey key ${address} (${ownerDid}), which is not your account's primary OpenKey key. This key is a separate owner with its own spaces and data, so this profile does not see the data stored under your primary key.
11221
- To use your primary key, log in again and choose the primary key in OpenKey, for example into a new profile: ${CLI_NAME11} init --name <profile>
11294
+ To use your primary key, log in again and choose the primary key in OpenKey, for example into a new profile: ${CLI_NAME12} init --name <profile>
11222
11295
  `;
11223
11296
  }
11224
11297
  function warnIfNotPrimaryKey(ownerDid, primary) {
@@ -11227,7 +11300,7 @@ function warnIfNotPrimaryKey(ownerDid, primary) {
11227
11300
  }
11228
11301
  function announceFirstOwner(profileName2, expectedOwner, ownerDid) {
11229
11302
  if (expectedOwner !== void 0 || ownerDid === void 0) return;
11230
- process.stderr.write(`Profile "${profileName2}" now belongs to ${ownerDid}. If that isn't your OpenKey account, stop using this profile and create a new one with ${CLI_NAME11} init.
11303
+ process.stderr.write(`Profile "${profileName2}" now belongs to ${ownerDid}. If that isn't your OpenKey account, stop using this profile and create a new one with ${CLI_NAME12} init.
11231
11304
  `);
11232
11305
  }
11233
11306
  function ownerLoginPermissions(owner) {
@@ -11929,7 +12002,7 @@ init_types();
11929
12002
  init_constants();
11930
12003
  init_permissions();
11931
12004
  init_sdk();
11932
- import { CLI_NAME as CLI_NAME13 } from "@tinycloud/operations/cli-name";
12005
+ import { CLI_NAME as CLI_NAME14 } from "@tinycloud/operations/cli-name";
11933
12006
  import { TinyCloudNode as TinyCloudNode2 } from "@tinycloud/node-sdk";
11934
12007
  import { DelegationRequestBindingSchema, PermissionEntrySchema } from "@tinycloud/operations/artifacts";
11935
12008
  import {
@@ -11944,7 +12017,7 @@ import {
11944
12017
  // src/lib/revoke-delegation.ts
11945
12018
  init_constants();
11946
12019
  init_errors();
11947
- import { CLI_NAME as CLI_NAME12 } from "@tinycloud/operations/cli-name";
12020
+ import { CLI_NAME as CLI_NAME13 } from "@tinycloud/operations/cli-name";
11948
12021
  import { parseSignedCompactUcanAttenuation as parseSignedCompactUcanAttenuation2 } from "@tinycloud/sdk-core";
11949
12022
  import { inspectStoredDelegation, withoutBearer as withoutBearer2 } from "@tinycloud/operations/delegation-binding";
11950
12023
  init_permissions();
@@ -12130,7 +12203,7 @@ async function revokeDelegationOnNode(params) {
12130
12203
  "REVOKE_UNAUTHORIZED",
12131
12204
  "The node rejected this revocation: Unauthorized Revoker.",
12132
12205
  ExitCode.PERMISSION_DENIED,
12133
- { status: 403, hint: `Use a different profile belonging to the delegation's grantor, its recipient, or the owner of a space it covers; the rejected profile was "${ctx.profile}" (DID ${profileDid}). Retry with \`${CLI_NAME12} --profile <profile-name> delegation revoke ${cid}\`.` }
12206
+ { status: 403, hint: `Use a different profile belonging to the delegation's grantor, its recipient, or the owner of a space it covers; the rejected profile was "${ctx.profile}" (DID ${profileDid}). Retry with \`${CLI_NAME13} --profile <profile-name> delegation revoke ${cid}\`.` }
12134
12207
  );
12135
12208
  }
12136
12209
  throw cliErrorFromService(result.error);
@@ -12213,7 +12286,7 @@ function renderList(result) {
12213
12286
  }
12214
12287
  process.stdout.write(`Profile: ${result.profile}
12215
12288
  `);
12216
- process.stdout.write(`Session CID: ${result.session?.cid ?? "unavailable"}` + (result.session?.cid ? ` (current session; revoke with ${CLI_NAME13} delegation revoke ${result.session.cid})
12289
+ process.stdout.write(`Session CID: ${result.session?.cid ?? "unavailable"}` + (result.session?.cid ? ` (current session; revoke with ${CLI_NAME14} delegation revoke ${result.session.cid})
12217
12290
  ` : "\n"));
12218
12291
  process.stdout.write(`Local verification: ${result.localVerification}; node validation and revocation are not checked.
12219
12292
  `);
@@ -12311,7 +12384,7 @@ function registerAuthGrantsCommand(auth, options = {}) {
12311
12384
  ExitCode.ERROR,
12312
12385
  {
12313
12386
  causeCode: cause.code,
12314
- hint: `Do not use --revoke again. After fixing local profile storage, run: ${CLI_NAME13} --profile ${ctx.profile} auth grants remove ${cid}`
12387
+ hint: `Do not use --revoke again. After fixing local profile storage, run: ${CLI_NAME14} --profile ${ctx.profile} auth grants remove ${cid}`
12315
12388
  }
12316
12389
  );
12317
12390
  }
@@ -12356,6 +12429,19 @@ init_delegation_expiry();
12356
12429
  init_space();
12357
12430
  init_permissions();
12358
12431
 
12432
+ // src/lib/approval-notices.ts
12433
+ var spaceLabel = (group) => {
12434
+ const space = group[0]?.space ?? "";
12435
+ return `${space.split(":").pop() || space} space`;
12436
+ };
12437
+ function approvalNotices(groups) {
12438
+ if (groups.length < 2) return void 0;
12439
+ return {
12440
+ intro: `This needs ${groups.length} approvals in OpenKey (${groups.map(spaceLabel).join(", then ")}).`,
12441
+ prompts: groups.map((group, index) => `Approval ${index + 1} of ${groups.length}: ${spaceLabel(group)}...`)
12442
+ };
12443
+ }
12444
+
12359
12445
  // src/auth/replication-login.ts
12360
12446
  init_dist();
12361
12447
  init_errors();
@@ -12649,7 +12735,7 @@ async function revokeForLogout(ctx, discardLocalChanges) {
12649
12735
  "REVOCATION_FAILED",
12650
12736
  `Revocation failed for ${cid}: ${result.error.message}. Session, key, and replica files are retained for retry; local reads stay denied.`,
12651
12737
  ExitCode.ERROR,
12652
- { cid, hint: `Retry \`${CLI_NAME14} auth logout --revoke\` when the node is available.` }
12738
+ { cid, hint: `Retry \`${CLI_NAME15} auth logout --revoke\` when the node is available.` }
12653
12739
  );
12654
12740
  }
12655
12741
  if (result.data.cid !== cid || result.data.revoked !== true) {
@@ -12668,7 +12754,7 @@ async function revokeForLogout(ctx, discardLocalChanges) {
12668
12754
  "REVOCATION_FAILED",
12669
12755
  `Revocation failed before local logout: ${error instanceof Error ? error.message : String(error)}. Session, key, and replica files are retained for retry; local reads stay denied.`,
12670
12756
  ExitCode.ERROR,
12671
- { hint: `Retry \`${CLI_NAME14} auth logout --revoke\` when online authority is available.` }
12757
+ { hint: `Retry \`${CLI_NAME15} auth logout --revoke\` when online authority is available.` }
12672
12758
  );
12673
12759
  }
12674
12760
  }
@@ -12867,7 +12953,7 @@ async function finishProfileLogout(ctx, options = {}) {
12867
12953
  function registerAuthCommand(program, options) {
12868
12954
  const auth = program.command("auth").description("Authentication management");
12869
12955
  registerAuthGrantsCommand(auth, { openKeyAcquisition: options?.openKeyAcquisition });
12870
- auth.command("login").description("Authenticate with TinyCloud").option("--device", "Approve on another device (e.g. a phone) through OpenKey device authorization; requires a KV-scoped --manifest (SQL and secret decrypt need browser or --paste login)").option("--paste", "Wait up to 5 minutes for a signed code from OpenKey on stdin instead of a browser callback (Safari may require paste)").option("--no-popup", "Print the OpenKey URL without opening a browser").option("--method <method>", "Authentication method: local or openkey").option("--manifest <fileOrBase64>", `Request only this manifest's permissions (one space, plus raw encryption network entries such as a secrets decrypt grant); ${SHARE_PUBLISHING_MANIFEST_REF} covers \`${CLI_NAME14} share publish\``).option("--expiry <duration>", "OpenKey session lifetime, e.g. 1h or 7d (device login: at most 30d, default 30d)").option("--owner <did>", "Sign in as this owner (did:pkh:eip155:CHAIN:ADDRESS): OpenKey preselects that key, e.g. one that is not the account's primary key, and an approval by any other identity is refused. With --manifest, also names the secrets owner for a manifest's `secrets` on a profile with no recorded owner").option("--replace-session", "Scoped or device login: replace this profile's live session even though the new scope would narrow, change or shorten it (prefer a new profile)").option("--replication-prefix <prefix>", "Add replication get+sync authority for a folder prefix ending in /, or root (repeatable)", (prefix, values = []) => [...values, prefix]).option("--replication-allow-secrets", "Allow replication of secret material (network-wide decrypt warning)").action(async (options2, cmd) => {
12956
+ auth.command("login").description("Authenticate with TinyCloud").option("--device", "Approve on another device (e.g. a phone) through OpenKey device authorization; requires a KV-scoped --manifest (SQL and secret decrypt need browser or --paste login)").option("--paste", "Wait up to 5 minutes for a signed code from OpenKey on stdin instead of a browser callback (Safari may require paste)").option("--no-popup", "Print the OpenKey URL without opening a browser").option("--method <method>", "Authentication method: local or openkey").option("--manifest <fileOrBase64>", `Request only this manifest's permissions (one space, plus raw encryption network entries such as a secrets decrypt grant); ${SHARE_PUBLISHING_MANIFEST_REF} covers \`${CLI_NAME15} share publish\``).option("--expiry <duration>", "OpenKey session lifetime, e.g. 1h or 7d (device login: at most 30d, default 30d)").option("--owner <did>", "Sign in as this owner (did:pkh:eip155:CHAIN:ADDRESS): OpenKey preselects that key, e.g. one that is not the account's primary key, and an approval by any other identity is refused. With --manifest, also names the secrets owner for a manifest's `secrets` on a profile with no recorded owner").option("--replace-session", "Scoped or device login: replace this profile's live session even though the new scope would narrow, change or shorten it (prefer a new profile)").option("--replication-prefix <prefix>", "Add replication get+sync authority for a folder prefix ending in /, or root (repeatable)", (prefix, values = []) => [...values, prefix]).option("--replication-allow-secrets", "Allow replication of secret material (network-wide decrypt warning)").action(async (options2, cmd) => {
12871
12957
  try {
12872
12958
  if (options2.device && options2.paste) {
12873
12959
  throw new CLIError("INVALID_ARGUMENT", "--device and --paste are mutually exclusive.", ExitCode.USAGE_ERROR);
@@ -13016,7 +13102,7 @@ function registerAuthCommand(program, options) {
13016
13102
  authenticated: false,
13017
13103
  replicasRemoved,
13018
13104
  replicasKept: options2.keepReplicas === true,
13019
- warning: online ? "The node confirmed revocation of the listed CIDs before local logout." : options2.keepReplicas ? "Legacy replica files remain on disk; this local logout clears the session but does not revoke node grants. Purge the files before a future sign-in if they must not be reused." : `Logout is local; delegations and grants on the node stay valid until they expire. Use \`${CLI_NAME14} delegation revoke <cid>\` to end access now.`,
13105
+ warning: online ? "The node confirmed revocation of the listed CIDs before local logout." : options2.keepReplicas ? "Legacy replica files remain on disk; this local logout clears the session but does not revoke node grants. Purge the files before a future sign-in if they must not be reused." : `Logout is local; delegations and grants on the node stay valid until they expire. Use \`${CLI_NAME15} delegation revoke <cid>\` to end access now.`,
13020
13106
  ...online === void 0 ? {} : {
13021
13107
  revokedCids: online.plan.cids,
13022
13108
  revocationExcluded: online.plan.excluded
@@ -13106,11 +13192,14 @@ ${signInAgainHint(ctx.profile, posture ?? void 0)}
13106
13192
  ).option("--permission <file>", 'JSON permission request: { "permissions": PermissionEntry[] }').option("--manifest <fileOrBase64>", "Manifest file, base64:<json>, or raw base64 JSON").option(
13107
13193
  "--expiry <duration>",
13108
13194
  `Lifetime of the granted delegation. ms-format string (e.g. "7d", "30m") or raw milliseconds. Defaults to 7d, capped by the active session's expiry.`
13109
- ).option("--emit [file]", "Emit the request artifact to stdout, or write it to file when provided").option("--grant", "Grant the requested permissions immediately with this owner profile").option("--yes", "Skip local-key TTY confirmation", false).option("--no-popup", "Print the OpenKey URL without opening a browser when granting with OpenKey").option("--device", "With --grant: approve on another device (e.g. a phone) through OpenKey device authorization (KV-scoped; SQL needs browser login)").action(async (options2, cmd) => {
13195
+ ).option("--emit [file]", "Emit the request artifact to stdout, or write it to file when provided").option("--grant", "Grant the requested permissions immediately with this owner profile").option("--yes", "Skip local-key TTY confirmation", false).option("--no-popup", "Print the OpenKey URL without opening a browser when granting with OpenKey").option("--device", "With --grant: approve on another device (e.g. a phone) through OpenKey device authorization (KV-scoped; SQL needs browser login)").option("--paste", "With --grant on an OpenKey profile: wait up to 5 minutes for a signed code from OpenKey on stdin instead of a browser callback (use when the browser cannot reach this CLI)").action(async (options2, cmd) => {
13110
13196
  try {
13111
13197
  const globalOpts = cmd.optsWithGlobals();
13112
13198
  const ctx = await ProfileManager.resolveContext(globalOpts, options2.grant ? {} : { storedSession: "unused" });
13113
13199
  const profile = await ProfileManager.getProfile(ctx.profile);
13200
+ if (options2.paste && (!options2.grant || options2.device || resolveProfilePosture(profile) !== "owner-openkey")) {
13201
+ throw new CLIError("INVALID_ARGUMENT", "--paste requires --grant on an OpenKey owner profile and cannot be combined with --device.", ExitCode.USAGE_ERROR);
13202
+ }
13114
13203
  if (options2.device && (!options2.grant || resolveProfilePosture(profile) !== "owner-openkey")) {
13115
13204
  throw new CLIError("INVALID_ARGUMENT", "--device requires --grant on an OpenKey owner profile.", ExitCode.USAGE_ERROR);
13116
13205
  }
@@ -13143,7 +13232,7 @@ ${signInAgainHint(ctx.profile, posture ?? void 0)}
13143
13232
  if (profile.authMethod === "openkey" || options2.device) {
13144
13233
  const key = await ProfileManager.getKey(ctx.profile);
13145
13234
  if (!key) {
13146
- throw new CLIError("NO_KEY", `No key found for profile "${ctx.profile}". Run \`${CLI_NAME14} --profile ${ctx.profile} auth rotate\` to create a new key and sign in.`, ExitCode.AUTH_REQUIRED);
13235
+ throw new CLIError("NO_KEY", `No key found for profile "${ctx.profile}". Run \`${CLI_NAME15} --profile ${ctx.profile} auth rotate\` to create a new key and sign in.`, ExitCode.AUTH_REQUIRED);
13147
13236
  }
13148
13237
  const openkeyHost = resolveOpenKeyHost(profile);
13149
13238
  const grants = [];
@@ -13155,9 +13244,15 @@ ${signInAgainHint(ctx.profile, posture ?? void 0)}
13155
13244
  expiry: expiryCap
13156
13245
  };
13157
13246
  const declined = [];
13158
- for (const group of groupPermissionsBySpace(requested)) {
13247
+ const groups = groupPermissionsBySpace(requested);
13248
+ const notices = approvalNotices(groups);
13249
+ if (notices) process.stderr.write(`${notices.intro}
13250
+ `);
13251
+ for (const [index, group] of groups.entries()) {
13252
+ if (notices) process.stderr.write(`${notices.prompts[index]}
13253
+ `);
13159
13254
  const reason = permissionGrantReason(
13160
- `Grant requested TinyCloud permissions from \`${CLI_NAME14} auth request --grant\`.`,
13255
+ `Grant requested TinyCloud permissions from \`${CLI_NAME15} auth request --grant\`.`,
13161
13256
  group
13162
13257
  );
13163
13258
  const request = grantRequestPermissions(group, profile.spaceId ?? profile.spaceName);
@@ -13184,7 +13279,8 @@ ${signInAgainHint(ctx.profile, posture ?? void 0)}
13184
13279
  reason,
13185
13280
  openkeyHost,
13186
13281
  expiry: expiryCap === void 0 ? void 0 : openKeyExpiryParam(expiryCap),
13187
- noPopup: options2.popup === false
13282
+ noPopup: options2.popup === false,
13283
+ paste: options2.paste
13188
13284
  });
13189
13285
  }
13190
13286
  const delegation = portableFromOpenKeyDelegation(delegationData, request, ctx.host, proof);
@@ -13266,7 +13362,7 @@ ${signInAgainHint(ctx.profile, posture ?? void 0)}
13266
13362
  kind: parsed.kind,
13267
13363
  requestId: parsed.requestId,
13268
13364
  requested: parsed.requested,
13269
- next: `${CLI_NAME14} auth retry ${parsed.requestId}`
13365
+ next: `${CLI_NAME15} auth retry ${parsed.requestId}`
13270
13366
  });
13271
13367
  return;
13272
13368
  }
@@ -13817,7 +13913,7 @@ async function ensureDelegationAuthority(params) {
13817
13913
  if (!key) {
13818
13914
  throw new CLIError(
13819
13915
  "NO_KEY",
13820
- `No key found for profile "${params.ctx.profile}". Run \`${CLI_NAME14} --profile ${params.ctx.profile} auth rotate\` to create a new key and sign in.`,
13916
+ `No key found for profile "${params.ctx.profile}". Run \`${CLI_NAME15} --profile ${params.ctx.profile} auth rotate\` to create a new key and sign in.`,
13821
13917
  ExitCode.AUTH_REQUIRED
13822
13918
  );
13823
13919
  }
@@ -14063,7 +14159,7 @@ async function rotateAuthKey(profileName2, host, options = {}) {
14063
14159
  if (!profile.privateKey) {
14064
14160
  throw new CLIError(
14065
14161
  "LOCAL_OWNER_KEY_REQUIRED",
14066
- `Profile "${profileName2}" does not have a local owner private key. Run \`${CLI_NAME14} auth login --method local\` first.`,
14162
+ `Profile "${profileName2}" does not have a local owner private key. Run \`${CLI_NAME15} auth login --method local\` first.`,
14067
14163
  ExitCode.AUTH_REQUIRED
14068
14164
  );
14069
14165
  }
@@ -14503,7 +14599,7 @@ async function refreshOpenKeySession(profileName2, host, options = {}) {
14503
14599
  }
14504
14600
 
14505
14601
  // src/commands/completion.ts
14506
- import { CLI_NAME as CLI_NAME15 } from "@tinycloud/operations/cli-name";
14602
+ import { CLI_NAME as CLI_NAME16 } from "@tinycloud/operations/cli-name";
14507
14603
  function registerCompletionCommand(program) {
14508
14604
  const completion = program.command("completion").description("Generate shell completions");
14509
14605
  completion.command("bash").description("Output bash completions").action(() => {
@@ -14520,7 +14616,7 @@ function registerCompletionCommand(program) {
14520
14616
  });
14521
14617
  }
14522
14618
  function generateBashCompletion() {
14523
- return `# ${CLI_NAME15} bash completion
14619
+ return `# ${CLI_NAME16} bash completion
14524
14620
  _tc_completions() {
14525
14621
  local cur prev commands subcommands
14526
14622
  COMPREPLY=()
@@ -14545,11 +14641,11 @@ _tc_completions() {
14545
14641
  COMPREPLY=( $(compgen -W "\${subcommands}" -- "\${cur}") )
14546
14642
  fi
14547
14643
  }
14548
- complete -F _tc_completions ${CLI_NAME15}
14644
+ complete -F _tc_completions ${CLI_NAME16}
14549
14645
  `;
14550
14646
  }
14551
14647
  function generateZshCompletion() {
14552
- return `#compdef ${CLI_NAME15}
14648
+ return `#compdef ${CLI_NAME16}
14553
14649
 
14554
14650
  _tc() {
14555
14651
  local -a commands
@@ -14600,50 +14696,50 @@ _tc
14600
14696
  `;
14601
14697
  }
14602
14698
  function generateFishCompletion() {
14603
- return `# ${CLI_NAME15} fish completion
14699
+ return `# ${CLI_NAME16} fish completion
14604
14700
  set -l commands init auth kv space delegation share node profile completion
14605
14701
 
14606
14702
  # Disable file completion by default
14607
- complete -c ${CLI_NAME15} -f
14703
+ complete -c ${CLI_NAME16} -f
14608
14704
 
14609
14705
  # Top-level commands
14610
- complete -c ${CLI_NAME15} -n "not __fish_seen_subcommand_from $commands" -a init -d "Initialize a new TinyCloud profile"
14611
- complete -c ${CLI_NAME15} -n "not __fish_seen_subcommand_from $commands" -a auth -d "Authentication management"
14612
- complete -c ${CLI_NAME15} -n "not __fish_seen_subcommand_from $commands" -a kv -d "Key-value store operations"
14613
- complete -c ${CLI_NAME15} -n "not __fish_seen_subcommand_from $commands" -a space -d "Space management"
14614
- complete -c ${CLI_NAME15} -n "not __fish_seen_subcommand_from $commands" -a delegation -d "Manage delegations"
14615
- complete -c ${CLI_NAME15} -n "not __fish_seen_subcommand_from $commands" -a share -d "Share data with others"
14616
- complete -c ${CLI_NAME15} -n "not __fish_seen_subcommand_from $commands" -a node -d "Node health and info"
14617
- complete -c ${CLI_NAME15} -n "not __fish_seen_subcommand_from $commands" -a profile -d "Profile management"
14618
- complete -c ${CLI_NAME15} -n "not __fish_seen_subcommand_from $commands" -a completion -d "Generate shell completions"
14706
+ complete -c ${CLI_NAME16} -n "not __fish_seen_subcommand_from $commands" -a init -d "Initialize a new TinyCloud profile"
14707
+ complete -c ${CLI_NAME16} -n "not __fish_seen_subcommand_from $commands" -a auth -d "Authentication management"
14708
+ complete -c ${CLI_NAME16} -n "not __fish_seen_subcommand_from $commands" -a kv -d "Key-value store operations"
14709
+ complete -c ${CLI_NAME16} -n "not __fish_seen_subcommand_from $commands" -a space -d "Space management"
14710
+ complete -c ${CLI_NAME16} -n "not __fish_seen_subcommand_from $commands" -a delegation -d "Manage delegations"
14711
+ complete -c ${CLI_NAME16} -n "not __fish_seen_subcommand_from $commands" -a share -d "Share data with others"
14712
+ complete -c ${CLI_NAME16} -n "not __fish_seen_subcommand_from $commands" -a node -d "Node health and info"
14713
+ complete -c ${CLI_NAME16} -n "not __fish_seen_subcommand_from $commands" -a profile -d "Profile management"
14714
+ complete -c ${CLI_NAME16} -n "not __fish_seen_subcommand_from $commands" -a completion -d "Generate shell completions"
14619
14715
 
14620
14716
  # Subcommands
14621
- complete -c ${CLI_NAME15} -n "__fish_seen_subcommand_from auth" -a "login logout rotate status whoami"
14622
- complete -c ${CLI_NAME15} -n "__fish_seen_subcommand_from kv" -a "get put delete list head"
14623
- complete -c ${CLI_NAME15} -n "__fish_seen_subcommand_from space" -a "list create info switch"
14624
- complete -c ${CLI_NAME15} -n "__fish_seen_subcommand_from delegation" -a "create list info revoke"
14625
- complete -c ${CLI_NAME15} -n "__fish_seen_subcommand_from share" -a "create receive list revoke"
14626
- complete -c ${CLI_NAME15} -n "__fish_seen_subcommand_from node" -a "health version status"
14627
- complete -c ${CLI_NAME15} -n "__fish_seen_subcommand_from profile" -a "list create show switch delete"
14628
- complete -c ${CLI_NAME15} -n "__fish_seen_subcommand_from completion" -a "bash zsh fish"
14717
+ complete -c ${CLI_NAME16} -n "__fish_seen_subcommand_from auth" -a "login logout rotate status whoami"
14718
+ complete -c ${CLI_NAME16} -n "__fish_seen_subcommand_from kv" -a "get put delete list head"
14719
+ complete -c ${CLI_NAME16} -n "__fish_seen_subcommand_from space" -a "list create info switch"
14720
+ complete -c ${CLI_NAME16} -n "__fish_seen_subcommand_from delegation" -a "create list info revoke"
14721
+ complete -c ${CLI_NAME16} -n "__fish_seen_subcommand_from share" -a "create receive list revoke"
14722
+ complete -c ${CLI_NAME16} -n "__fish_seen_subcommand_from node" -a "health version status"
14723
+ complete -c ${CLI_NAME16} -n "__fish_seen_subcommand_from profile" -a "list create show switch delete"
14724
+ complete -c ${CLI_NAME16} -n "__fish_seen_subcommand_from completion" -a "bash zsh fish"
14629
14725
 
14630
14726
  # Global options
14631
- complete -c ${CLI_NAME15} -l profile -s p -d "Profile to use"
14632
- complete -c ${CLI_NAME15} -l host -s H -d "TinyCloud node URL"
14633
- complete -c ${CLI_NAME15} -l verbose -s v -d "Enable verbose output"
14634
- complete -c ${CLI_NAME15} -l no-cache -d "Disable caching"
14635
- complete -c ${CLI_NAME15} -l quiet -s q -d "Suppress non-essential output"
14636
- complete -c ${CLI_NAME15} -l replication -d "Enable read-through replication"
14637
- complete -c ${CLI_NAME15} -l no-replication -d "Disable replication"
14638
- complete -c ${CLI_NAME15} -l replication-debug -d "Write replication diagnostics to stderr"
14727
+ complete -c ${CLI_NAME16} -l profile -s p -d "Profile to use"
14728
+ complete -c ${CLI_NAME16} -l host -s H -d "TinyCloud node URL"
14729
+ complete -c ${CLI_NAME16} -l verbose -s v -d "Enable verbose output"
14730
+ complete -c ${CLI_NAME16} -l no-cache -d "Disable caching"
14731
+ complete -c ${CLI_NAME16} -l quiet -s q -d "Suppress non-essential output"
14732
+ complete -c ${CLI_NAME16} -l replication -d "Enable read-through replication"
14733
+ complete -c ${CLI_NAME16} -l no-replication -d "Disable replication"
14734
+ complete -c ${CLI_NAME16} -l replication-debug -d "Write replication diagnostics to stderr"
14639
14735
  `;
14640
14736
  }
14641
14737
 
14642
14738
  // src/commands/courier.ts
14643
- import { CLI_NAME as CLI_NAME16 } from "@tinycloud/operations/cli-name";
14644
- var TC_OPTIONS_BEFORE_COURIER = `${CLI_NAME16} courier takes no ${CLI_NAME16} options and does not use ${CLI_NAME16} profiles; Courier keeps its own profile in $COURIER_HOME (default ~/.courier). Put flags after "courier", e.g. ${CLI_NAME16} courier init --host <url>.`;
14739
+ import { CLI_NAME as CLI_NAME17 } from "@tinycloud/operations/cli-name";
14740
+ var TC_OPTIONS_BEFORE_COURIER = `${CLI_NAME17} courier takes no ${CLI_NAME17} options and does not use ${CLI_NAME17} profiles; Courier keeps its own profile in $COURIER_HOME (default ~/.courier). Put flags after "courier", e.g. ${CLI_NAME17} courier init --host <url>.`;
14645
14741
  function registerCourierCommand(program) {
14646
- const courier = program.command("courier").description(`Agent-to-agent threads over TinyCloud; run \`${CLI_NAME16} courier --help\` (beta)`).argument("[args...]").allowUnknownOption().helpOption(false);
14742
+ const courier = program.command("courier").description(`Agent-to-agent threads over TinyCloud; run \`${CLI_NAME17} courier --help\` (beta)`).argument("[args...]").allowUnknownOption().helpOption(false);
14647
14743
  courier.action(() => courier.error(TC_OPTIONS_BEFORE_COURIER, { exitCode: 2, code: "tc.courier.options" }));
14648
14744
  }
14649
14745
 
@@ -14688,7 +14784,7 @@ init_formatter();
14688
14784
  init_errors();
14689
14785
  init_constants();
14690
14786
  init_sdk();
14691
- import { CLI_NAME as CLI_NAME17 } from "@tinycloud/operations/cli-name";
14787
+ import { CLI_NAME as CLI_NAME18 } from "@tinycloud/operations/cli-name";
14692
14788
  import { PermissionNotInManifestError } from "@tinycloud/node-sdk";
14693
14789
  async function queryDelegations(node, options, until) {
14694
14790
  const found = [];
@@ -14699,7 +14795,7 @@ async function queryDelegations(node, options, until) {
14699
14795
  if (page.error.code === "PERMISSION_DENIED") {
14700
14796
  throw new CLIError(
14701
14797
  "PERMISSION_DENIED",
14702
- `This session cannot read delegations: it lacks tinycloud.delegation/list. Run \`${CLI_NAME17} auth login\` again to grant it.`,
14798
+ `This session cannot read delegations: it lacks tinycloud.delegation/list. Run \`${CLI_NAME18} auth login\` again to grant it.`,
14703
14799
  ExitCode.PERMISSION_DENIED
14704
14800
  );
14705
14801
  }
@@ -14874,7 +14970,7 @@ init_constants();
14874
14970
  init_formatter();
14875
14971
  init_theme();
14876
14972
  init_errors();
14877
- import { CLI_NAME as CLI_NAME18 } from "@tinycloud/operations/cli-name";
14973
+ import { CLI_NAME as CLI_NAME19 } from "@tinycloud/operations/cli-name";
14878
14974
  init_session_expired();
14879
14975
  init_types();
14880
14976
  function registerDoctorCommand(program) {
@@ -14908,7 +15004,7 @@ function registerDoctorCommand(program) {
14908
15004
  const profile = await ProfileManager.getProfile(profileName2);
14909
15005
  keyDetail = profile.did ? `${profile.did.slice(0, 20)}...` : "key found";
14910
15006
  } else {
14911
- keyDetail = `no key \u2014 run ${CLI_NAME18} init`;
15007
+ keyDetail = `no key \u2014 run ${CLI_NAME19} init`;
14912
15008
  }
14913
15009
  } catch {
14914
15010
  keyDetail = "error reading key";
@@ -14930,7 +15026,7 @@ function registerDoctorCommand(program) {
14930
15026
  } else if (state2 === "unverified") {
14931
15027
  sessionDetail = `not usable (no signed OpenKey proof) \u2014 ${signInAgainHint(profileName2, resolveProfilePosture(profile))}`;
14932
15028
  } else {
14933
- sessionDetail = sessionOk ? "active" : `no session \u2014 run ${CLI_NAME18} auth login`;
15029
+ sessionDetail = sessionOk ? "active" : `no session \u2014 run ${CLI_NAME19} auth login`;
14934
15030
  }
14935
15031
  } catch {
14936
15032
  sessionDetail = "error reading session";
@@ -14958,7 +15054,7 @@ function registerDoctorCommand(program) {
14958
15054
  try {
14959
15055
  const profile = await ProfileManager.getProfile(profileName2);
14960
15056
  spaceOk = Boolean(profile.spaceId);
14961
- spaceDetail = spaceOk ? `${profile.spaceId.slice(0, 16)}...` : `no space \u2014 run ${CLI_NAME18} space create`;
15057
+ spaceDetail = spaceOk ? `${profile.spaceId.slice(0, 16)}...` : `no space \u2014 run ${CLI_NAME19} space create`;
14962
15058
  } catch {
14963
15059
  spaceDetail = "error checking space";
14964
15060
  }
@@ -15148,7 +15244,7 @@ ${rowCount} row${rowCount === 1 ? "" : "s"} returned`) + "\n");
15148
15244
  }
15149
15245
 
15150
15246
  // src/commands/enable.ts
15151
- import { CLI_NAME as CLI_NAME19 } from "@tinycloud/operations/cli-name";
15247
+ import { CLI_NAME as CLI_NAME20 } from "@tinycloud/operations/cli-name";
15152
15248
  init_constants();
15153
15249
  init_profiles();
15154
15250
  init_errors();
@@ -15156,7 +15252,7 @@ init_formatter();
15156
15252
  init_publishing_manifest();
15157
15253
  function registerEnableCommand(program) {
15158
15254
  const enable = program.command("enable").description("Enable a narrowly scoped TinyCloud service");
15159
- enable.command("share").description(`Approve Share publishing scope through OpenKey device authorization (same as \`${CLI_NAME19} auth login --device --manifest builtin:share-publishing\`). Use a dedicated profile, e.g. \`${CLI_NAME19} init --name publisher --key-only && ${CLI_NAME19} --profile publisher enable share\`; keep existing profiles for their apps.`).option("--replace-session", "Replace this profile's live session even though the new scope would narrow, change or shorten it (prefer a new profile)").action(async (options, command) => {
15255
+ enable.command("share").description(`Approve Share publishing scope through OpenKey device authorization (same as \`${CLI_NAME20} auth login --device --manifest builtin:share-publishing\`). Use a dedicated profile, e.g. \`${CLI_NAME20} init --name publisher --key-only && ${CLI_NAME20} --profile publisher enable share\`; keep existing profiles for their apps.`).option("--replace-session", "Replace this profile's live session even though the new scope would narrow, change or shorten it (prefer a new profile)").action(async (options, command) => {
15160
15256
  try {
15161
15257
  const globalOptions = command.optsWithGlobals();
15162
15258
  const context = await ProfileManager.resolveContext(globalOptions, { storedSession: "unused" });
@@ -15192,7 +15288,7 @@ init_profiles();
15192
15288
  init_formatter();
15193
15289
  init_errors();
15194
15290
  init_constants();
15195
- import { CLI_NAME as CLI_NAME20 } from "@tinycloud/operations/cli-name";
15291
+ import { CLI_NAME as CLI_NAME21 } from "@tinycloud/operations/cli-name";
15196
15292
  function registerInitCommand(program) {
15197
15293
  program.command("init").description("Initialize a new TinyCloud profile").option("--name <profile>", "Profile name", "default").option("--key-only", "Only generate key, skip authentication").option("--host <url>", "TinyCloud node URL").option("--paste", "Use manual paste mode for authentication").option("--no-popup", "Print the OpenKey URL without opening a browser").option("--default-space <name>", "Default space used when --space is omitted (e.g. applications)").action(async (options, cmd) => {
15198
15294
  try {
@@ -15210,7 +15306,7 @@ function registerInitCommand(program) {
15210
15306
  if (await ProfileManager.profileExists(profileName2)) {
15211
15307
  throw new CLIError(
15212
15308
  "PROFILE_EXISTS",
15213
- `Profile "${profileName2}" already exists. Use \`${CLI_NAME20} profile delete ${profileName2}\` first or choose a different name.`,
15309
+ `Profile "${profileName2}" already exists. Use \`${CLI_NAME21} profile delete ${profileName2}\` first or choose a different name.`,
15214
15310
  ExitCode.ERROR
15215
15311
  );
15216
15312
  }
@@ -15560,7 +15656,7 @@ init_errors();
15560
15656
  init_constants();
15561
15657
  init_theme();
15562
15658
  import { resolveManifestKnowledgeRoot as resolveManifestKnowledgeRoot2 } from "@tinycloud/sdk-core";
15563
- import { CLI_NAME as CLI_NAME21 } from "@tinycloud/operations/cli-name";
15659
+ import { CLI_NAME as CLI_NAME22 } from "@tinycloud/operations/cli-name";
15564
15660
  import { readFile as readFile11 } from "fs/promises";
15565
15661
  var DEFAULT_APP_SPACE = "applications";
15566
15662
  function registerManifestCommand(program) {
@@ -15568,8 +15664,8 @@ function registerManifestCommand(program) {
15568
15664
  manifest.command("resolve <source>").description("Resolve a manifest file or URL to its effective space, paths, and DB basenames").addHelpText("after", `
15569
15665
 
15570
15666
  Examples:
15571
- $ ${CLI_NAME21} manifest resolve ./manifest.json
15572
- $ ${CLI_NAME21} manifest resolve https://app.example.com/manifest.json --json
15667
+ $ ${CLI_NAME22} manifest resolve ./manifest.json
15668
+ $ ${CLI_NAME22} manifest resolve https://app.example.com/manifest.json --json
15573
15669
 
15574
15670
  What it shows:
15575
15671
  - app_id, name, manifest_version
@@ -15579,7 +15675,7 @@ What it shows:
15579
15675
 
15580
15676
  This command is read-only and does NOT contact the node \u2014 it just resolves
15581
15677
  the manifest against the active profile's address/chain so you know which
15582
- \`--space\` and \`--db\` values to pass to other ${CLI_NAME21} commands.
15678
+ \`--space\` and \`--db\` values to pass to other ${CLI_NAME22} commands.
15583
15679
  `).action(async (source, _options, cmd) => {
15584
15680
  try {
15585
15681
  const globalOpts = cmd.optsWithGlobals();
@@ -15648,7 +15744,7 @@ ${theme.heading("SQL databases")}
15648
15744
  `);
15649
15745
  }
15650
15746
  process.stdout.write(theme.muted(`
15651
- Use with: ${CLI_NAME21} sql query --space ${spaceName} --db <db> "..."
15747
+ Use with: ${CLI_NAME22} sql query --space ${spaceName} --db <db> "..."
15652
15748
  `));
15653
15749
  }
15654
15750
  if (permissions.length > 0) {
@@ -15768,7 +15864,7 @@ init_profiles();
15768
15864
  init_formatter();
15769
15865
  init_errors();
15770
15866
  init_constants();
15771
- import { CLI_NAME as CLI_NAME22 } from "@tinycloud/operations/cli-name";
15867
+ import { CLI_NAME as CLI_NAME23 } from "@tinycloud/operations/cli-name";
15772
15868
  import { createInterface as createInterface5 } from "readline";
15773
15869
  init_theme();
15774
15870
  init_types();
@@ -15914,9 +16010,9 @@ profile at command time. Precedence for every kv/sql command:
15914
16010
  explicit --space flag > profile defaultSpace > primary space.
15915
16011
 
15916
16012
  Examples:
15917
- $ ${CLI_NAME22} profile set-default-space applications
15918
- $ ${CLI_NAME22} profile set-default-space applications --profile cli-test
15919
- $ ${CLI_NAME22} profile set-default-space --unset
16013
+ $ ${CLI_NAME23} profile set-default-space applications
16014
+ $ ${CLI_NAME23} profile set-default-space applications --profile cli-test
16015
+ $ ${CLI_NAME23} profile set-default-space --unset
15920
16016
  `).action(async (name, options, cmd) => {
15921
16017
  try {
15922
16018
  const globalOpts = cmd.optsWithGlobals();
@@ -15928,7 +16024,7 @@ Examples:
15928
16024
  if (!options.unset && (name === void 0 || name === "")) {
15929
16025
  throw new CLIError(
15930
16026
  "USAGE_ERROR",
15931
- `Provide a space name (e.g. \`${CLI_NAME22} profile set-default-space applications\`) or pass --unset.`,
16027
+ `Provide a space name (e.g. \`${CLI_NAME23} profile set-default-space applications\`) or pass --unset.`,
15932
16028
  ExitCode.USAGE_ERROR
15933
16029
  );
15934
16030
  }
@@ -15987,7 +16083,7 @@ function parseOperatorType(raw) {
15987
16083
 
15988
16084
  // src/commands/replica.ts
15989
16085
  init_profile_replicas();
15990
- import { CLI_NAME as CLI_NAME23 } from "@tinycloud/operations/cli-name";
16086
+ import { CLI_NAME as CLI_NAME24 } from "@tinycloud/operations/cli-name";
15991
16087
  import { randomBytes as randomBytes7 } from "crypto";
15992
16088
  import { constants as fsConstants5 } from "fs";
15993
16089
  import { mkdir as mkdir5, open as open9, readdir as readdir6, rename as rename4, unlink as unlink4, lstat as lstat9 } from "fs/promises";
@@ -16128,11 +16224,11 @@ var EXIT_BY_CODE = {
16128
16224
  var READ_FAILURE = {
16129
16225
  absent: { code: "KEY_ABSENT", exit: ExitCode.NOT_FOUND, what: "is not in the replica (the replica covers its whole prefix)" },
16130
16226
  deleted: { code: "KEY_DELETED", exit: ExitCode.NOT_FOUND, what: "was deleted at the source" },
16131
- content_missing: { code: "CONTENT_MISSING", exit: ExitCode.NOT_FOUND, what: `is known but its content has not been fetched yet; run ${CLI_NAME23} replica sync` },
16227
+ content_missing: { code: "CONTENT_MISSING", exit: ExitCode.NOT_FOUND, what: `is known but its content has not been fetched yet; run ${CLI_NAME24} replica sync` },
16132
16228
  coverage_incomplete: {
16133
16229
  code: "COVERAGE_INCOMPLETE",
16134
16230
  exit: ExitCode.NOT_FOUND,
16135
- what: `is not in the replica, which has not finished its first sync; run ${CLI_NAME23} replica sync`
16231
+ what: `is not in the replica, which has not finished its first sync; run ${CLI_NAME24} replica sync`
16136
16232
  },
16137
16233
  not_covered: { code: "NOT_COVERED", exit: ExitCode.USAGE_ERROR, what: "is outside the replica's prefix" }
16138
16234
  };
@@ -16250,7 +16346,7 @@ async function existingReplicaName(profile, option) {
16250
16346
  const names = await replicaNames(profile);
16251
16347
  if (names.length === 1) return names[0];
16252
16348
  if (names.length === 0) {
16253
- throw new ReplicaError(ReplicaErrorCode.NOT_FOUND, `Profile "${profile}" has no replicas. Create one with: ${CLI_NAME23} replica sync --prefix <prefix>`);
16349
+ throw new ReplicaError(ReplicaErrorCode.NOT_FOUND, `Profile "${profile}" has no replicas. Create one with: ${CLI_NAME24} replica sync --prefix <prefix>`);
16254
16350
  }
16255
16351
  throw new CLIError("USAGE_ERROR", `Profile "${profile}" has several replicas (${names.join(", ")}); pass --replica <name>.`, ExitCode.USAGE_ERROR);
16256
16352
  }
@@ -16358,9 +16454,9 @@ async function storedGrants(profile) {
16358
16454
  function grantHint(space, prefix) {
16359
16455
  return [
16360
16456
  "A replica needs a device grant with get and sync on its prefix:",
16361
- ` device: ${CLI_NAME23} auth request --cap tinycloud.kv:${space}:${prefix}:get,list,metadata,sync --expiry 30d --emit req.json`,
16362
- ` owner: ${CLI_NAME23} auth grant req.json > grant.json`,
16363
- ` device: ${CLI_NAME23} auth import grant.json`
16457
+ ` device: ${CLI_NAME24} auth request --cap tinycloud.kv:${space}:${prefix}:get,list,metadata,sync --expiry 30d --emit req.json`,
16458
+ ` owner: ${CLI_NAME24} auth grant req.json > grant.json`,
16459
+ ` device: ${CLI_NAME24} auth import grant.json`
16364
16460
  ].join("\n");
16365
16461
  }
16366
16462
  function resolveSpace(input, prefix, grants) {
@@ -16451,7 +16547,7 @@ function describeStatus(status) {
16451
16547
  formatField("Size", formatBytes(status.bytes)),
16452
16548
  formatField("Grant", status.device.delegationCid),
16453
16549
  formatField("Last error", status.lastError ? `${status.lastError.code}: ${status.lastError.message}` : null),
16454
- formatField("Purge", status.purgePending ? `incomplete: content files remain; the next ${CLI_NAME23} replica command retries` : null)
16550
+ formatField("Purge", status.purgePending ? `incomplete: content files remain; the next ${CLI_NAME24} replica command retries` : null)
16455
16551
  ].join("\n");
16456
16552
  }
16457
16553
  async function writeFileAtomic(path, bytes) {
@@ -16615,7 +16711,7 @@ or coverage incomplete; 5 grant expired, revoked or not yet valid; 6 network;
16615
16711
  (options, cmd) => run(async () => {
16616
16712
  const profile = await profileName(cmd);
16617
16713
  if (options.purge) {
16618
- throw new CLIError("REPORT_READ_ONLY", `Replica report is read-only. To remove a named local replica, run ${CLI_NAME23} replica reset --replica <name> --purge; flag-owned purge has no equivalent yet (TC-1309).`, ExitCode.USAGE_ERROR);
16714
+ throw new CLIError("REPORT_READ_ONLY", `Replica report is read-only. To remove a named local replica, run ${CLI_NAME24} replica reset --replica <name> --purge; flag-owned purge has no equivalent yet (TC-1309).`, ExitCode.USAGE_ERROR);
16619
16715
  }
16620
16716
  if (options.clearPending) {
16621
16717
  throw new CLIError("REPORT_READ_ONLY", "Clearing pending replica writes has no equivalent yet; see TC-1309 for a safe replacement command.", ExitCode.USAGE_ERROR);
@@ -16717,7 +16813,7 @@ or coverage incomplete; 5 grant expired, revoked or not yet valid; 6 network;
16717
16813
  if (differs !== void 0) {
16718
16814
  throw new ReplicaError(
16719
16815
  ReplicaErrorCode.CONFIG_MISMATCH,
16720
- `Replica ${name} already follows ${differs}. Use another --replica name, or ${CLI_NAME23} replica reset --replica ${name} --purge first.`
16816
+ `Replica ${name} already follows ${differs}. Use another --replica name, or ${CLI_NAME24} replica reset --replica ${name} --purge first.`
16721
16817
  );
16722
16818
  }
16723
16819
  }
@@ -16882,7 +16978,7 @@ init_theme();
16882
16978
  init_errors();
16883
16979
  init_warnings();
16884
16980
  init_constants();
16885
- import { CLI_NAME as CLI_NAME25 } from "@tinycloud/operations/cli-name";
16981
+ import { CLI_NAME as CLI_NAME26 } from "@tinycloud/operations/cli-name";
16886
16982
  import { readFile as readFile12 } from "fs/promises";
16887
16983
  import { join as join16 } from "path";
16888
16984
  import { homedir, hostname, userInfo } from "os";
@@ -17093,7 +17189,7 @@ function parseStatusEnvelope(line) {
17093
17189
  // src/lib/secrets-wait.ts
17094
17190
  init_constants();
17095
17191
  init_errors();
17096
- import { CLI_NAME as CLI_NAME24 } from "@tinycloud/operations/cli-name";
17192
+ import { CLI_NAME as CLI_NAME25 } from "@tinycloud/operations/cli-name";
17097
17193
  var WAIT_BACKOFF_MS = [3e3, 4500, 6750, 10125];
17098
17194
  var WAIT_STEADY_INTERVAL_MS = 15e3;
17099
17195
  var DEFAULT_WAIT_TIMEOUT = "5m";
@@ -17101,7 +17197,7 @@ var MAX_WAIT_TIMEOUT_MS = 9 * 6e4;
17101
17197
  var MAX_CONSECUTIVE_FAILURES = 5;
17102
17198
  var TIMEOUT_RE = /^(0|\d+s|\d+m)$/;
17103
17199
  var RETRYABLE_STATUS_ERRORS = { NODE_UNREACHABLE: true, NODE_ERROR: true };
17104
- var EXPLICIT_KEY_HINT = `${CLI_NAME24} secrets wait never signs in, and an explicit private key has no stored session. Use a local profile signed in once with ${CLI_NAME24} --profile <profile> auth login --method local, without TC_PRIVATE_KEY.`;
17200
+ var EXPLICIT_KEY_HINT = `${CLI_NAME25} secrets wait never signs in, and an explicit private key has no stored session. Use a local profile signed in once with ${CLI_NAME25} --profile <profile> auth login --method local, without TC_PRIVATE_KEY.`;
17105
17201
  function abortableSleep(ms2, signal) {
17106
17202
  return new Promise((resolve8) => {
17107
17203
  if (signal.aborted) {
@@ -17137,7 +17233,7 @@ async function runSecretsWait(request, deps) {
17137
17233
  let step = 0;
17138
17234
  const cancelled = () => new CLIError(
17139
17235
  "CANCELLED",
17140
- `Interrupted: ${CLI_NAME24} secrets wait stopped before the secrets were ready.`,
17236
+ `Interrupted: ${CLI_NAME25} secrets wait stopped before the secrets were ready.`,
17141
17237
  ExitCode.CANCELLED,
17142
17238
  progress === void 0 ? {} : { progress }
17143
17239
  );
@@ -17281,13 +17377,13 @@ function statusError(error, profile, warnings) {
17281
17377
  if (error.code === "AUTH_REQUIRED" || error.code === "SESSION_NOT_FOUND") {
17282
17378
  const recovery = recoveryOf(error, "sign_in");
17283
17379
  if (recovery !== void 0) {
17284
- const hint = recovery.command !== void 0 ? `Sign in once with: ${recovery.command}, then retry.` : `Sign in to profile "${profile}" once with ${CLI_NAME24} auth login, then retry.`;
17380
+ const hint = recovery.command !== void 0 ? `Sign in once with: ${recovery.command}, then retry.` : `Sign in to profile "${profile}" once with ${CLI_NAME25} auth login, then retry.`;
17285
17381
  return new CLIError("AUTH_REQUIRED", error.message, ExitCode.AUTH_REQUIRED, { hint, recovery, ...extra });
17286
17382
  }
17287
17383
  }
17288
17384
  if (error.code === "PROFILE_MIGRATION_REQUIRED") {
17289
17385
  const recovery = recoveryOf(error, "complete_migration");
17290
- const hint = recovery?.command !== void 0 ? `Run ${recovery.command} once to finish this profile's one-time upgrade, then retry wait.` : `Run ${CLI_NAME24} auth caps once with profile "${profile}" to finish its one-time upgrade, then retry wait.`;
17386
+ const hint = recovery?.command !== void 0 ? `Run ${recovery.command} once to finish this profile's one-time upgrade, then retry wait.` : `Run ${CLI_NAME25} auth caps once with profile "${profile}" to finish its one-time upgrade, then retry wait.`;
17291
17387
  return new CLIError("PROFILE_MIGRATION_REQUIRED", error.message, ExitCode.ERROR, {
17292
17388
  hint,
17293
17389
  ...recovery === void 0 ? {} : { recovery },
@@ -17479,11 +17575,11 @@ async function runSecretOperation(params) {
17479
17575
  }
17480
17576
  function secretPermissionReason(action, name) {
17481
17577
  const target = name ? ` secret "${name}"` : " secrets";
17482
- return `Allow \`${CLI_NAME25} secrets ${action}${name ? ` ${name}` : ""}\` to access${target} with the required TinyCloud permissions.`;
17578
+ return `Allow \`${CLI_NAME26} secrets ${action}${name ? ` ${name}` : ""}\` to access${target} with the required TinyCloud permissions.`;
17483
17579
  }
17484
17580
  function assertOwnerApprovalPossible(profileName2, profile, action, name, missing = []) {
17485
17581
  if (profile.authMethod !== "openkey" || process.stdin.isTTY || process.stderr.isTTY) return;
17486
- const command = `${CLI_NAME25} secrets ${action === "del" ? "delete" : action}${name ? ` ${name}` : ""}`;
17582
+ const command = `${CLI_NAME26} secrets ${action === "del" ? "delete" : action}${name ? ` ${name}` : ""}`;
17487
17583
  throw new CLIError(
17488
17584
  "PERMISSION_DENIED",
17489
17585
  action === "get" ? missing.length > 0 && missing.every((permission) => permission.service === "tinycloud.encryption" && Array.isArray(permission.actions) && permission.actions.length > 0 && permission.actions.every((capability) => capability === SECRET_DECRYPT_CAPABILITY)) ? `Profile "${profileName2}" lacks the scoped decrypt authority (${SECRET_DECRYPT_CAPABILITY}) needed to read secret "${name}", and requesting it needs an interactive browser approval.` : `Profile "${profileName2}" lacks a scoped read or decrypt grant needed to read secret "${name}", and requesting it needs an interactive browser approval.` : `Profile "${profileName2}" holds no grant for \`${command}\`, and requesting one needs an interactive browser approval.`,
@@ -17494,7 +17590,7 @@ function assertOwnerApprovalPossible(profileName2, profile, action, name, missin
17494
17590
  );
17495
17591
  }
17496
17592
  function scopedSecretLoginHint(profileName2) {
17497
- return `Have the owner approve a scoped login whose manifest names the secret: ${CLI_NAME25} --profile ${profileName2} auth login --method openkey --paste --manifest <manifest.json>. Pass the owner's code on stdin, newline-terminated.`;
17593
+ return `Have the owner approve a scoped login whose manifest names the secret: ${CLI_NAME26} --profile ${profileName2} auth login --method openkey --paste --manifest <manifest.json>. Pass the owner's code on stdin, newline-terminated.`;
17498
17594
  }
17499
17595
  async function runSecretOperationAttempt(label, operation) {
17500
17596
  try {
@@ -17628,7 +17724,7 @@ ${message}`,
17628
17724
  "AUTH_REQUIRED",
17629
17725
  "Not signed in to TinyCloud.",
17630
17726
  ExitCode.AUTH_REQUIRED,
17631
- { hint: `Sign in with: ${CLI_NAME25} --profile ${result.context.profile} auth login` }
17727
+ { hint: `Sign in with: ${CLI_NAME26} --profile ${result.context.profile} auth login` }
17632
17728
  );
17633
17729
  }
17634
17730
  if (result.error.code === "NODE_UNREACHABLE") {
@@ -18105,7 +18201,7 @@ function registerSecretsCommand(program, openKeyAcquisition) {
18105
18201
  name: "Encryption network",
18106
18202
  ok: false,
18107
18203
  detail: `${networkName} not found`,
18108
- hint: `${CLI_NAME25} secrets network init ${networkName}`
18204
+ hint: `${CLI_NAME26} secrets network init ${networkName}`
18109
18205
  }
18110
18206
  ];
18111
18207
  let secret;
@@ -18151,7 +18247,7 @@ function registerSecretsCommand(program, openKeyAcquisition) {
18151
18247
  name: "Secret access",
18152
18248
  ok: false,
18153
18249
  detail: notFound ? `${resolved.permissionPaths.vault} not found` : result.error.message,
18154
- hint: notFound ? local ? `${CLI_NAME25} secrets put ${resolved.name}${formatSecretScopeFlag(scopeOptions)} --stdin` : `${CLI_NAME25} secrets request ${resolved.name}${formatSecretScopeFlag(scopeOptions)}` : `Ask the owner profile to grant ${secretCapabilityAction("get")} and ${SECRET_DECRYPT_CAPABILITY}.`
18250
+ hint: notFound ? local ? `${CLI_NAME26} secrets put ${resolved.name}${formatSecretScopeFlag(scopeOptions)} --stdin` : `${CLI_NAME26} secrets request ${resolved.name}${formatSecretScopeFlag(scopeOptions)}` : `Ask the owner profile to grant ${secretCapabilityAction("get")} and ${SECRET_DECRYPT_CAPABILITY}.`
18155
18251
  });
18156
18252
  }
18157
18253
  } else {
@@ -18395,7 +18491,7 @@ function registerSecretsCommand(program, openKeyAcquisition) {
18395
18491
  if (effectiveLocal(profile, options)) {
18396
18492
  throw new CLIError(
18397
18493
  "LOCAL_OWNER_PROFILE",
18398
- `Profile "${ctx.profile}" uses a local key, which owns its secrets: store them with ${CLI_NAME25} secrets put NAME --stdin instead of requesting them.`,
18494
+ `Profile "${ctx.profile}" uses a local key, which owns its secrets: store them with ${CLI_NAME26} secrets put NAME --stdin instead of requesting them.`,
18399
18495
  ExitCode.USAGE_ERROR
18400
18496
  );
18401
18497
  }
@@ -18518,7 +18614,7 @@ function registerSecretsCommand(program, openKeyAcquisition) {
18518
18614
 
18519
18615
  // src/commands/share.ts
18520
18616
  import { Option } from "commander";
18521
- import { CLI_NAME as CLI_NAME26 } from "@tinycloud/operations/cli-name";
18617
+ import { CLI_NAME as CLI_NAME27 } from "@tinycloud/operations/cli-name";
18522
18618
 
18523
18619
  // ../share-sdk/dist/artifact.js
18524
18620
  init_sha256();
@@ -36649,12 +36745,12 @@ function shareCliError(error, operation = "publish") {
36649
36745
  const profileName2 = "profileName" in failure ? failure.profileName : void 0;
36650
36746
  const localKey = "localKey" in failure && failure.localKey === true;
36651
36747
  const profileHint = profileName2 === void 0 ? "" : `--profile ${profileName2} `;
36652
- const loginHint = localKey ? `\`${CLI_NAME26} ${profileHint}auth login --method local\`` : `\`${CLI_NAME26} ${profileHint}auth login --device --manifest builtin:share-publishing\` (or \`${CLI_NAME26} ${profileHint}enable share\`)`;
36748
+ const loginHint = localKey ? `\`${CLI_NAME27} ${profileHint}auth login --method local\`` : `\`${CLI_NAME27} ${profileHint}auth login --device --manifest builtin:share-publishing\` (or \`${CLI_NAME27} ${profileHint}enable share\`)`;
36653
36749
  if (failure.kind === "caveated-session") {
36654
36750
  const holder = profileName2 === void 0 ? "this session" : `profile ${profileName2}'s session`;
36655
36751
  return new CLIError(
36656
36752
  "PERMISSION_DENIED",
36657
- `${holder} carries signed restrictions (caveats) on the authority an anyone-with-link share needs, so it cannot create the share link; nothing was shared. Approve Share publishing without restrictions on a new, dedicated profile (any unused name): \`${CLI_NAME26} init --name publisher --key-only && ${CLI_NAME26} --profile publisher enable share\``,
36753
+ `${holder} carries signed restrictions (caveats) on the authority an anyone-with-link share needs, so it cannot create the share link; nothing was shared. Approve Share publishing without restrictions on a new, dedicated profile (any unused name): \`${CLI_NAME27} init --name publisher --key-only && ${CLI_NAME27} --profile publisher enable share\``,
36658
36754
  5
36659
36755
  );
36660
36756
  }
@@ -37059,7 +37155,7 @@ init_constants();
37059
37155
  init_sdk();
37060
37156
  init_host();
37061
37157
  init_theme();
37062
- import { CLI_NAME as CLI_NAME27 } from "@tinycloud/operations/cli-name";
37158
+ import { CLI_NAME as CLI_NAME28 } from "@tinycloud/operations/cli-name";
37063
37159
  import { ACCOUNT_REGISTRY_SPACE } from "@tinycloud/node-sdk";
37064
37160
  import { randomBytes as randomBytes9 } from "crypto";
37065
37161
  import { mkdir as mkdir7, writeFile as writeFile4 } from "fs/promises";
@@ -37106,7 +37202,7 @@ function registerSpaceCommand(program) {
37106
37202
  } else {
37107
37203
  const profile = await ProfileManager.getProfile(ctx.profile);
37108
37204
  const cap = "tinycloud.kv:account:spaces/:get,list";
37109
- const hint = resolveProfilePosture(profile) === "delegate-session" ? `Ask the space owner to grant it. Create the request with: ${CLI_NAME27} --profile ${ctx.profile} auth request --cap ${cap} --emit` : `Grant it to this session with: ${CLI_NAME27} --profile ${ctx.profile} auth request --grant --cap ${cap}. The default OpenKey owner sign-in covers only the default space, so it includes neither.`;
37205
+ const hint = resolveProfilePosture(profile) === "delegate-session" ? `Ask the space owner to grant it. Create the request with: ${CLI_NAME28} --profile ${ctx.profile} auth request --cap ${cap} --emit` : `Grant it to this session with: ${CLI_NAME28} --profile ${ctx.profile} auth request --grant --cap ${cap}. The default OpenKey owner sign-in covers only the default space, so it includes neither.`;
37110
37206
  throw new CLIError(
37111
37207
  "PERMISSION_DENIED",
37112
37208
  `Listing spaces needs tinycloud.kv/get and tinycloud.kv/list on the account space's spaces/ registry (${accountSpaceId ?? ACCOUNT_REGISTRY_SPACE}), or tinycloud.space/list. This session holds neither.`,
@@ -37143,10 +37239,10 @@ function registerSpaceCommand(program) {
37143
37239
 
37144
37240
  A delegate cannot host a space \u2014 only its owner (root authority) can. This
37145
37241
  emits a tinycloud.host.request artifact naming the space and its owner so you
37146
- can hand it to the owner; they run \`${CLI_NAME27} space host <name>\` and confirm.
37242
+ can hand it to the owner; they run \`${CLI_NAME28} space host <name>\` and confirm.
37147
37243
 
37148
37244
  If you ARE the owner of the resolved space, this refuses and tells you to host
37149
- it directly with \`${CLI_NAME27} space host <name>\` (no request needed).
37245
+ it directly with \`${CLI_NAME28} space host <name>\` (no request needed).
37150
37246
  `).action(async (name, options, cmd) => {
37151
37247
  try {
37152
37248
  const globalOpts = cmd.optsWithGlobals();
@@ -37157,7 +37253,7 @@ it directly with \`${CLI_NAME27} space host <name>\` (no request needed).
37157
37253
  if (await isRootAuthority(spaceId, ctx.profile)) {
37158
37254
  throw new CLIError(
37159
37255
  "ALREADY_ROOT_AUTHORITY",
37160
- `You are the owner of ${spaceId}. Host it directly: ${CLI_NAME27} space host ${spaceName}`,
37256
+ `You are the owner of ${spaceId}. Host it directly: ${CLI_NAME28} space host ${spaceName}`,
37161
37257
  ExitCode.USAGE_ERROR
37162
37258
  );
37163
37259
  }
@@ -37243,7 +37339,7 @@ init_sdk();
37243
37339
  init_space();
37244
37340
  init_host();
37245
37341
  init_theme();
37246
- import { CLI_NAME as CLI_NAME28 } from "@tinycloud/operations/cli-name";
37342
+ import { CLI_NAME as CLI_NAME29 } from "@tinycloud/operations/cli-name";
37247
37343
  import { writeFile as writeFile5 } from "fs/promises";
37248
37344
  import { resolve as resolve7 } from "path";
37249
37345
  async function dbHandle(node, dbName, spaceInput, profileName2) {
@@ -37267,12 +37363,12 @@ database for simple apps, or pass --db to target a named database. Pass
37267
37363
  --space to target a non-primary space (e.g. the manifest "applications" space).
37268
37364
 
37269
37365
  Common workflows:
37270
- $ ${CLI_NAME28} sql execute "CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY, body TEXT)"
37271
- $ ${CLI_NAME28} sql execute "INSERT INTO notes (body) VALUES (?)" --params '["ship docs"]'
37272
- $ ${CLI_NAME28} sql query "SELECT id, body FROM notes ORDER BY id"
37273
- $ ${CLI_NAME28} sql query "SELECT * FROM events WHERE type = ?" --db analytics --params '["signup"]'
37274
- $ ${CLI_NAME28} sql query "SELECT count(*) FROM conversation" --space applications --db xyz.tinycloud.listen/conversations
37275
- $ ${CLI_NAME28} sql export --db analytics --output analytics.db
37366
+ $ ${CLI_NAME29} sql execute "CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY, body TEXT)"
37367
+ $ ${CLI_NAME29} sql execute "INSERT INTO notes (body) VALUES (?)" --params '["ship docs"]'
37368
+ $ ${CLI_NAME29} sql query "SELECT id, body FROM notes ORDER BY id"
37369
+ $ ${CLI_NAME29} sql query "SELECT * FROM events WHERE type = ?" --db analytics --params '["signup"]'
37370
+ $ ${CLI_NAME29} sql query "SELECT count(*) FROM conversation" --space applications --db xyz.tinycloud.listen/conversations
37371
+ $ ${CLI_NAME29} sql export --db analytics --output analytics.db
37276
37372
 
37277
37373
  Commands:
37278
37374
  query Read rows with SELECT statements
@@ -37289,10 +37385,10 @@ Tips:
37289
37385
  sql.command("query <sql>").description("Run a read-only SELECT query").option("--db <name>", "SQLite database name within the current space", "default").option("--space <name|uri>", "Target a non-primary space (short name or full URI)").option("--params <json>", "Bind parameters as a JSON array for ? placeholders").addHelpText("after", `
37290
37386
 
37291
37387
  Examples:
37292
- $ ${CLI_NAME28} sql query "SELECT * FROM notes ORDER BY id"
37293
- $ ${CLI_NAME28} sql query "SELECT * FROM notes WHERE id = ?" --params '[42]'
37294
- $ ${CLI_NAME28} sql query "SELECT count(*) AS total FROM events" --db analytics --json
37295
- $ ${CLI_NAME28} sql query "SELECT count(*) FROM conversation" --space applications --db xyz.tinycloud.listen/conversations
37388
+ $ ${CLI_NAME29} sql query "SELECT * FROM notes ORDER BY id"
37389
+ $ ${CLI_NAME29} sql query "SELECT * FROM notes WHERE id = ?" --params '[42]'
37390
+ $ ${CLI_NAME29} sql query "SELECT count(*) AS total FROM events" --db analytics --json
37391
+ $ ${CLI_NAME29} sql query "SELECT count(*) FROM conversation" --space applications --db xyz.tinycloud.listen/conversations
37296
37392
 
37297
37393
  Output:
37298
37394
  Human output is formatted as a table. Piped output or --json returns
@@ -37333,11 +37429,11 @@ ${rowCount} row${rowCount === 1 ? "" : "s"} returned`) + "\n");
37333
37429
  sql.command("execute <sql>").description("Run a write or schema statement").option("--db <name>", "SQLite database name within the current space", "default").option("--space <name|uri>", "Target a non-primary space (short name or full URI)").option("--params <json>", "Bind parameters as a JSON array for ? placeholders").addHelpText("after", `
37334
37430
 
37335
37431
  Examples:
37336
- $ ${CLI_NAME28} sql execute "CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY, body TEXT)"
37337
- $ ${CLI_NAME28} sql execute "INSERT INTO notes (body) VALUES (?)" --params '["first note"]'
37338
- $ ${CLI_NAME28} sql execute "UPDATE notes SET body = ? WHERE id = ?" --params '["edited", 1]'
37339
- $ ${CLI_NAME28} sql execute "DROP TABLE old_notes" --db archive
37340
- $ ${CLI_NAME28} sql execute "DELETE FROM conversation WHERE id = ?" --space applications --db xyz.tinycloud.listen/conversations --params '["abc"]'
37432
+ $ ${CLI_NAME29} sql execute "CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY, body TEXT)"
37433
+ $ ${CLI_NAME29} sql execute "INSERT INTO notes (body) VALUES (?)" --params '["first note"]'
37434
+ $ ${CLI_NAME29} sql execute "UPDATE notes SET body = ? WHERE id = ?" --params '["edited", 1]'
37435
+ $ ${CLI_NAME29} sql execute "DROP TABLE old_notes" --db archive
37436
+ $ ${CLI_NAME29} sql execute "DELETE FROM conversation WHERE id = ?" --space applications --db xyz.tinycloud.listen/conversations --params '["abc"]'
37341
37437
 
37342
37438
  Output:
37343
37439
  Returns JSON with the changed row count and last inserted row id when available.
@@ -37366,9 +37462,9 @@ Output:
37366
37462
  sql.command("export").description("Export a SQLite database as a binary .db file").option("--db <name>", "SQLite database name within the current space", "default").option("--space <name|uri>", "Target a non-primary space (short name or full URI)").option("-o, --output <file>", "Output file path", "export.db").addHelpText("after", `
37367
37463
 
37368
37464
  Examples:
37369
- $ ${CLI_NAME28} sql export
37370
- $ ${CLI_NAME28} sql export --db analytics --output analytics.db
37371
- $ ${CLI_NAME28} sql export --space applications --db xyz.tinycloud.listen/conversations --output listen.db
37465
+ $ ${CLI_NAME29} sql export
37466
+ $ ${CLI_NAME29} sql export --db analytics --output analytics.db
37467
+ $ ${CLI_NAME29} sql export --space applications --db xyz.tinycloud.listen/conversations --output listen.db
37372
37468
 
37373
37469
  Output:
37374
37470
  Writes the database file locally and returns JSON with the path and size.
@@ -37401,19 +37497,19 @@ Output:
37401
37497
  sql.command("copy").description("Copy rows between SQL databases (optionally across spaces)").requiredOption("--from-db <name>", "Source database name").requiredOption("--to-db <name>", "Destination database name").option("--from-space <name|uri>", "Source space (defaults to primary)").option("--to-space <name|uri>", "Destination space (defaults to primary)").option("--table <name...>", "Restrict copy to specific tables (repeat or comma-separated)").option("--dry-run", "Print the plan without writing", false).addHelpText("after", `
37402
37498
 
37403
37499
  Examples:
37404
- $ ${CLI_NAME28} sql copy --from-db com.tinycloud.conversation-sync/conversations \\
37500
+ $ ${CLI_NAME29} sql copy --from-db com.tinycloud.conversation-sync/conversations \\
37405
37501
  --to-db xyz.tinycloud.listen/conversations \\
37406
37502
  --space applications --dry-run
37407
- $ ${CLI_NAME28} sql copy --from-space applications --from-db com.foo/data \\
37503
+ $ ${CLI_NAME29} sql copy --from-space applications --from-db com.foo/data \\
37408
37504
  --to-space applications --to-db com.bar/data \\
37409
37505
  --table conversation --table participant
37410
37506
 
37411
37507
  Notes:
37412
37508
  - Refuses to run when (resolved space, db) is identical for source and destination.
37413
- - Does NOT create destination tables. Run the target app once (or use \`${CLI_NAME28} sql execute\`)
37509
+ - Does NOT create destination tables. Run the target app once (or use \`${CLI_NAME29} sql execute\`)
37414
37510
  to materialize the schema before copying.
37415
37511
  - One row at a time; suitable for small/medium datasets. Large copies should
37416
- use \`${CLI_NAME28} sql export\` + bulk import.
37512
+ use \`${CLI_NAME29} sql export\` + bulk import.
37417
37513
  - Authorization: the active session/delegation must cover sql/read on source
37418
37514
  AND sql/write on destination. Otherwise the relevant operation will fail.
37419
37515
  `).action(async (options, cmd) => {
@@ -37513,7 +37609,7 @@ init_errors();
37513
37609
  init_formatter();
37514
37610
  init_theme();
37515
37611
  init_permissions();
37516
- import { CLI_NAME as CLI_NAME29 } from "@tinycloud/operations/cli-name";
37612
+ import { CLI_NAME as CLI_NAME30 } from "@tinycloud/operations/cli-name";
37517
37613
  import {
37518
37614
  NodeWasmBindings as NodeWasmBindings2
37519
37615
  } from "@tinycloud/node-sdk";
@@ -37787,7 +37883,7 @@ function formatStatus(summary) {
37787
37883
  lines.push(`Default profile: ${theme.value(summary.defaultProfile)}`);
37788
37884
  lines.push("");
37789
37885
  if (summary.profiles.length === 0) {
37790
- lines.push(theme.muted(`No profiles configured. Run: ${CLI_NAME29} init`));
37886
+ lines.push(theme.muted(`No profiles configured. Run: ${CLI_NAME30} init`));
37791
37887
  return `${lines.join("\n")}
37792
37888
  `;
37793
37889
  }