@tinycloud/cli 1.2.3-beta.0 → 1.2.3-beta.1
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/README.md +3 -2
- package/bin/tinycloud +3 -0
- package/dist/courier-entry.js +7 -2
- package/dist/courier-entry.js.map +1 -1
- package/dist/index.js +53 -37
- package/dist/index.js.map +1 -1
- package/dist/legacy-entry.js +160 -130
- package/dist/legacy-entry.js.map +1 -1
- package/package.json +5 -4
- package/skills/tc-cli/SKILL.md +1 -1
package/dist/legacy-entry.js
CHANGED
|
@@ -319,13 +319,14 @@ var init_warnings = __esm({
|
|
|
319
319
|
|
|
320
320
|
// src/output/formatter.ts
|
|
321
321
|
import ora from "ora";
|
|
322
|
+
import { CLI_NAME } from "@tinycloud/operations/cli-name";
|
|
322
323
|
function outputJson(data) {
|
|
323
324
|
process.stdout.write(JSON.stringify(data, null, 2) + "\n");
|
|
324
325
|
}
|
|
325
326
|
function warningLine(warnings) {
|
|
326
327
|
const which = warnings.map((warning) => `${warning.grantCid ?? "unidentified"}: ${warning.reason}`).join(", ");
|
|
327
328
|
const subject = warnings.length === 1 ? "A stored grant was" : `${warnings.length} stored grants were`;
|
|
328
|
-
return `${subject} not used (${which}). Approve access again when a command needs it; remove the old grant with
|
|
329
|
+
return `${subject} not used (${which}). Approve access again when a command needs it; remove the old grant with ${CLI_NAME} auth grants remove <cid>.`;
|
|
329
330
|
}
|
|
330
331
|
function outputError(code3, message, hint, details = {}) {
|
|
331
332
|
const { meta, warnings = [], setup, recovery, progress } = details;
|
|
@@ -530,6 +531,7 @@ import { readFileSync, readdirSync } from "fs";
|
|
|
530
531
|
import { join as join2 } from "path";
|
|
531
532
|
import { ProfileDeletedError, ProfileLockTimeoutError } from "@tinycloud/operations/state";
|
|
532
533
|
import { isSafeRecovery } from "@tinycloud/operations/recovery";
|
|
534
|
+
import { CLI_NAME as CLI_NAME2 } from "@tinycloud/operations/cli-name";
|
|
533
535
|
import {
|
|
534
536
|
buildSecretRequestUrl,
|
|
535
537
|
isSafeRequestAccessRecovery,
|
|
@@ -608,7 +610,7 @@ function missingPrivateKeyError() {
|
|
|
608
610
|
"AUTH_REQUIRED",
|
|
609
611
|
`Profile "${profileName2}" cannot restore its session because its private key material is missing.`,
|
|
610
612
|
ExitCode.AUTH_REQUIRED,
|
|
611
|
-
{ hint: `Sign in again with:
|
|
613
|
+
{ hint: `Sign in again with: ${CLI_NAME2} --profile ${profileName2} auth login --method openkey` }
|
|
612
614
|
);
|
|
613
615
|
}
|
|
614
616
|
function storageFullError(error, progress) {
|
|
@@ -699,7 +701,7 @@ function buildAuthHint(error) {
|
|
|
699
701
|
if (!spec) return void 0;
|
|
700
702
|
return [
|
|
701
703
|
"The active session is missing a TinyCloud capability.",
|
|
702
|
-
`Request it with:
|
|
704
|
+
`Request it with: ${CLI_NAME2} auth request --cap '${spec.replaceAll("'", "'\\''")}'`,
|
|
703
705
|
"Then retry the original command."
|
|
704
706
|
].join("\n");
|
|
705
707
|
}
|
|
@@ -742,12 +744,12 @@ function buildNetworkHint() {
|
|
|
742
744
|
const lines = [];
|
|
743
745
|
lines.push(activeHost ? `Active profile "${activeName}" \u2192 ${activeHost}` : `Active profile "${activeName}"`);
|
|
744
746
|
if (others.length === 0) {
|
|
745
|
-
lines.push(`No other profiles configured. Run
|
|
747
|
+
lines.push(`No other profiles configured. Run \`${CLI_NAME2} profile create <name>\` or \`${CLI_NAME2} init\`.`);
|
|
746
748
|
} else {
|
|
747
749
|
lines.push(`Switch to a reachable profile:`);
|
|
748
750
|
const longest = Math.max(...others.map((p) => p.name.length));
|
|
749
751
|
for (const { name, host } of others) {
|
|
750
|
-
lines.push(`
|
|
752
|
+
lines.push(` ${CLI_NAME2} profile switch ${name.padEnd(longest)} # ${host}`);
|
|
751
753
|
}
|
|
752
754
|
}
|
|
753
755
|
lines.push(`Or override per-command with --host or TC_HOST.`);
|
|
@@ -807,6 +809,7 @@ var init_types = __esm({
|
|
|
807
809
|
});
|
|
808
810
|
|
|
809
811
|
// src/lib/space.ts
|
|
812
|
+
import { CLI_NAME as CLI_NAME3 } from "@tinycloud/operations/cli-name";
|
|
810
813
|
function canonicalizeAddress(address) {
|
|
811
814
|
const trimmed = address.trim();
|
|
812
815
|
return trimmed.startsWith("0x") ? `0x${trimmed.slice(2).toLowerCase()}` : trimmed.toLowerCase();
|
|
@@ -854,7 +857,7 @@ function resolveAddress(profile, session) {
|
|
|
854
857
|
}
|
|
855
858
|
throw new CLIError(
|
|
856
859
|
"ADDRESS_UNKNOWN",
|
|
857
|
-
`Cannot determine Ethereum address for profile "${profile.name}". Run
|
|
860
|
+
`Cannot determine Ethereum address for profile "${profile.name}". Run \`${CLI_NAME3} auth login\` to refresh the session.`,
|
|
858
861
|
ExitCode.AUTH_REQUIRED
|
|
859
862
|
);
|
|
860
863
|
}
|
|
@@ -14775,6 +14778,7 @@ var init_permissions = __esm({
|
|
|
14775
14778
|
|
|
14776
14779
|
// src/auth/session-expired.ts
|
|
14777
14780
|
import { signInRecovery } from "@tinycloud/operations/recovery";
|
|
14781
|
+
import { CLI_NAME as CLI_NAME4 } from "@tinycloud/operations/cli-name";
|
|
14778
14782
|
function signInAgainHint(profileName2, posture) {
|
|
14779
14783
|
const delegate = posture === "delegate-session";
|
|
14780
14784
|
const { command } = signInRecovery(
|
|
@@ -14782,7 +14786,7 @@ function signInAgainHint(profileName2, posture) {
|
|
|
14782
14786
|
delegate ? "delegate-session" : posture === "local-owner-key" ? "local-owner-key" : "owner-openkey"
|
|
14783
14787
|
);
|
|
14784
14788
|
if (command === void 0) {
|
|
14785
|
-
return delegate ? `Have the owner approve a new scoped login for profile ${JSON.stringify(profileName2)} with
|
|
14789
|
+
return delegate ? `Have the owner approve a new scoped login for profile ${JSON.stringify(profileName2)} with ${CLI_NAME4} auth login --method openkey --paste --manifest <manifest.json>.` : `Sign in again to profile ${JSON.stringify(profileName2)} with ${CLI_NAME4} auth login.`;
|
|
14786
14790
|
}
|
|
14787
14791
|
return delegate ? `Have the owner approve a new scoped login: ${command}. Pass the owner's code on stdin, newline-terminated.` : `Sign in again with: ${command}`;
|
|
14788
14792
|
}
|
|
@@ -14827,6 +14831,7 @@ var init_delegation_expiry = __esm({
|
|
|
14827
14831
|
});
|
|
14828
14832
|
|
|
14829
14833
|
// src/lib/replication-log.ts
|
|
14834
|
+
import { CLI_NAME as CLI_NAME5 } from "@tinycloud/operations/cli-name";
|
|
14830
14835
|
import { appendFileSync, chmodSync, mkdirSync, renameSync, statSync, writeFileSync } from "fs";
|
|
14831
14836
|
import { dirname as dirname2, join as join4 } from "path";
|
|
14832
14837
|
function appendReplicationEvent(root, event) {
|
|
@@ -14889,7 +14894,7 @@ function createReplicationEventSink(profileRoot, options) {
|
|
|
14889
14894
|
}
|
|
14890
14895
|
if (event.type === "replication.read" && (event.pendingState === "in_flight" || event.pendingState === "ambiguous") && !options.quiet && !pinnedNotices.has(event.key)) {
|
|
14891
14896
|
pinnedNotices.add(event.key);
|
|
14892
|
-
process.stderr.write(`[replication] ${event.key} reads from the network: an earlier write's outcome is unknown (${event.pendingState}${event.code ? `, ${event.code}` : ""}). Review:
|
|
14897
|
+
process.stderr.write(`[replication] ${event.key} reads from the network: an earlier write's outcome is unknown (${event.pendingState}${event.code ? `, ${event.code}` : ""}). Review: ${CLI_NAME5} replica report
|
|
14893
14898
|
`);
|
|
14894
14899
|
}
|
|
14895
14900
|
};
|
|
@@ -17729,6 +17734,7 @@ var init_dist3 = __esm({
|
|
|
17729
17734
|
|
|
17730
17735
|
// src/lib/replication-config.ts
|
|
17731
17736
|
import { join as join5 } from "path";
|
|
17737
|
+
import { CLI_NAME as CLI_NAME6 } from "@tinycloud/operations/cli-name";
|
|
17732
17738
|
import { profilePath, withProfileLock as withProfileLock2 } from "@tinycloud/operations/state";
|
|
17733
17739
|
import { sqliteReplicaStorage } from "@tinycloud/node-sdk";
|
|
17734
17740
|
function createCliReplicationConfig(profile, settings, output2, enabled) {
|
|
@@ -17743,7 +17749,7 @@ function createCliReplicationConfig(profile, settings, output2, enabled) {
|
|
|
17743
17749
|
"INVALID_REPLICATION_PREFIX",
|
|
17744
17750
|
error instanceof Error ? error.message : String(error),
|
|
17745
17751
|
ExitCode.USAGE_ERROR,
|
|
17746
|
-
{ hint: `Replace the saved replication prefix with
|
|
17752
|
+
{ hint: `Replace the saved replication prefix with \`${CLI_NAME6} auth login --replication-prefix ${replacement}\`; purging a replica alone does not change this profile setting.` }
|
|
17747
17753
|
);
|
|
17748
17754
|
}
|
|
17749
17755
|
}
|
|
@@ -17789,6 +17795,7 @@ __export(sdk_exports, {
|
|
|
17789
17795
|
storedSessionVerifiesLocally: () => storedSessionVerifiesLocally
|
|
17790
17796
|
});
|
|
17791
17797
|
import { TinyCloudNode, signedCompactUcanExpiry } from "@tinycloud/node-sdk";
|
|
17798
|
+
import { CLI_NAME as CLI_NAME7 } from "@tinycloud/operations/cli-name";
|
|
17792
17799
|
import { ownerSessionLacksProof } from "@tinycloud/operations/profile";
|
|
17793
17800
|
function jwkHasPrivateParameter(jwk) {
|
|
17794
17801
|
if (!jwk || typeof jwk !== "object") return false;
|
|
@@ -17811,7 +17818,7 @@ function signerJwkForProfile(profileName2, sessionJwk, key) {
|
|
|
17811
17818
|
`Profile "${profileName2}" cannot restore its session because its private key material is missing.`,
|
|
17812
17819
|
ExitCode.AUTH_REQUIRED,
|
|
17813
17820
|
{
|
|
17814
|
-
hint: `Sign in again with:
|
|
17821
|
+
hint: `Sign in again with: ${CLI_NAME7} --profile ${profileName2} auth login --method openkey`
|
|
17815
17822
|
}
|
|
17816
17823
|
);
|
|
17817
17824
|
}
|
|
@@ -17898,7 +17905,7 @@ async function createSDKInstance(ctx, options) {
|
|
|
17898
17905
|
if (!key && !effectivePrivateKey && !(profile?.authMethod === "openkey" && session !== null)) {
|
|
17899
17906
|
throw new CLIError(
|
|
17900
17907
|
"AUTH_REQUIRED",
|
|
17901
|
-
`No key found for profile "${ctx.profile}". Run
|
|
17908
|
+
`No key found for profile "${ctx.profile}". Run \`${CLI_NAME7} --profile ${ctx.profile} auth rotate\` to create a new key and sign in.`,
|
|
17902
17909
|
ExitCode.AUTH_REQUIRED
|
|
17903
17910
|
);
|
|
17904
17911
|
}
|
|
@@ -18017,7 +18024,7 @@ async function bootstrapDelegatedSession(ctx, delegation) {
|
|
|
18017
18024
|
return restoreBeforeBootstrap(ctx.profile, written.previousProfile);
|
|
18018
18025
|
}, { timeoutMs: PROFILE_COMMIT_LOCK_TIMEOUT_MS }).catch((error) => (
|
|
18019
18026
|
// The lock or a read failed: the import's error stays the one reported.
|
|
18020
|
-
`Rolling back the provisional session of profile "${ctx.profile}" could not run (${failureName(error)}); check
|
|
18027
|
+
`Rolling back the provisional session of profile "${ctx.profile}" could not run (${failureName(error)}); check \`${CLI_NAME7} --profile ${ctx.profile} context\`.`
|
|
18021
18028
|
));
|
|
18022
18029
|
throw annotate(reported, note);
|
|
18023
18030
|
};
|
|
@@ -18047,7 +18054,7 @@ async function restoreBeforeBootstrap(profileName2, previousProfile) {
|
|
|
18047
18054
|
});
|
|
18048
18055
|
}
|
|
18049
18056
|
if (failures.length === 0) return void 0;
|
|
18050
|
-
return `Rolling back the provisional session of profile "${profileName2}" failed too (${failures.join("; ")}); check
|
|
18057
|
+
return `Rolling back the provisional session of profile "${profileName2}" failed too (${failures.join("; ")}); check \`${CLI_NAME7} --profile ${profileName2} context\`.`;
|
|
18051
18058
|
}
|
|
18052
18059
|
function failureName(error) {
|
|
18053
18060
|
if (error instanceof SyntaxError) return "a profile file is not valid JSON";
|
|
@@ -18071,7 +18078,7 @@ async function ensureAuthenticated(ctx, options) {
|
|
|
18071
18078
|
if (!session) {
|
|
18072
18079
|
throw new CLIError(
|
|
18073
18080
|
"AUTH_REQUIRED",
|
|
18074
|
-
`Not authenticated. Run
|
|
18081
|
+
`Not authenticated. Run \`${CLI_NAME7} auth login\` or \`${CLI_NAME7} init\` first.`,
|
|
18075
18082
|
ExitCode.AUTH_REQUIRED
|
|
18076
18083
|
);
|
|
18077
18084
|
}
|
|
@@ -18108,6 +18115,7 @@ __export(host_exports, {
|
|
|
18108
18115
|
spaceNameFromUri: () => spaceNameFromUri,
|
|
18109
18116
|
unhostedSpaceError: () => unhostedSpaceError
|
|
18110
18117
|
});
|
|
18118
|
+
import { CLI_NAME as CLI_NAME8 } from "@tinycloud/operations/cli-name";
|
|
18111
18119
|
import {
|
|
18112
18120
|
discoverLocalTinyCloudNode
|
|
18113
18121
|
} from "@tinycloud/sdk-core";
|
|
@@ -18201,13 +18209,13 @@ async function unhostedSpaceError(error, spaceUri, profileName2) {
|
|
|
18201
18209
|
const owner = await isRootAuthority(spaceUri, profileName2);
|
|
18202
18210
|
const hint = owner ? [
|
|
18203
18211
|
"You are the owner. Host it once:",
|
|
18204
|
-
`
|
|
18212
|
+
` ${CLI_NAME8} space host ${spaceName}`,
|
|
18205
18213
|
"Then retry."
|
|
18206
18214
|
].join("\n") : [
|
|
18207
18215
|
"You are a delegate and CANNOT host this space \u2014 only its owner can.",
|
|
18208
18216
|
"Emit a host request:",
|
|
18209
|
-
`
|
|
18210
|
-
|
|
18217
|
+
` ${CLI_NAME8} space host-request ${spaceName} --emit ./host-request.json`,
|
|
18218
|
+
`Send it to the owner; they run \`${CLI_NAME8} space host\` and confirm. Then retry.`
|
|
18211
18219
|
].join("\n");
|
|
18212
18220
|
const message = owner ? `Space '${spaceName}' (${spaceUri}) is not hosted.` : `Space '${spaceName}' (owner ${ownerDidFromSpaceUri(spaceUri) ?? spaceUri}) is not hosted.`;
|
|
18213
18221
|
return new CLIError("SPACE_NOT_HOSTED", message, ExitCode.ERROR, { hint });
|
|
@@ -18232,6 +18240,7 @@ var init_host = __esm({
|
|
|
18232
18240
|
|
|
18233
18241
|
// src/config/profiles.ts
|
|
18234
18242
|
import { chmod as chmod2, lstat, readdir as readdir2, rm as rm2, rmdir } from "fs/promises";
|
|
18243
|
+
import { CLI_NAME as CLI_NAME9 } from "@tinycloud/operations/cli-name";
|
|
18235
18244
|
import { join as join6 } from "path";
|
|
18236
18245
|
import {
|
|
18237
18246
|
profilePath as profilePath2,
|
|
@@ -18317,7 +18326,7 @@ var init_profiles = __esm({
|
|
|
18317
18326
|
if (!profile) {
|
|
18318
18327
|
throw new CLIError(
|
|
18319
18328
|
"PROFILE_NOT_FOUND",
|
|
18320
|
-
`Profile "${name}" does not exist. Create it with
|
|
18329
|
+
`Profile "${name}" does not exist. Create it with \`${CLI_NAME9} init --name ${name}\`.`
|
|
18321
18330
|
);
|
|
18322
18331
|
}
|
|
18323
18332
|
return profile;
|
|
@@ -18375,7 +18384,7 @@ var init_profiles = __esm({
|
|
|
18375
18384
|
if (config.defaultProfile === name) {
|
|
18376
18385
|
throw new CLIError(
|
|
18377
18386
|
"PROFILE_DELETE_DEFAULT",
|
|
18378
|
-
`Cannot delete the default profile "${name}". Change the default first with
|
|
18387
|
+
`Cannot delete the default profile "${name}". Change the default first with \`${CLI_NAME9} profile default <other>\`.`
|
|
18379
18388
|
);
|
|
18380
18389
|
}
|
|
18381
18390
|
const kind = await lstat(profileDir).then((stats) => stats.isSymbolicLink() ? "link" : "present", (error) => {
|
|
@@ -18832,6 +18841,7 @@ function formatSpace(space) {
|
|
|
18832
18841
|
}
|
|
18833
18842
|
|
|
18834
18843
|
// src/commands/auth.ts
|
|
18844
|
+
import { CLI_NAME as CLI_NAME14 } from "@tinycloud/operations/cli-name";
|
|
18835
18845
|
import { get as httpGet } from "http";
|
|
18836
18846
|
import { get as httpsGet } from "https";
|
|
18837
18847
|
import { spawn } from "child_process";
|
|
@@ -21026,13 +21036,14 @@ init_constants();
|
|
|
21026
21036
|
init_profiles();
|
|
21027
21037
|
init_errors();
|
|
21028
21038
|
init_space();
|
|
21039
|
+
import { CLI_NAME as CLI_NAME10 } from "@tinycloud/operations/cli-name";
|
|
21029
21040
|
import { isLocalOwnerProfile as isLocalOwnerProfile3, ownerSessionLacksProof as ownerSessionLacksProof3 } from "@tinycloud/operations/profile";
|
|
21030
21041
|
import { ProfileLockTimeoutError as ProfileLockTimeoutError2 } from "@tinycloud/operations/state";
|
|
21031
21042
|
function assertNotLocalOwner(profileName2, profile, flow) {
|
|
21032
21043
|
if (profile === null || !isLocalOwnerProfile3(profile)) return;
|
|
21033
21044
|
throw new CLIError(
|
|
21034
21045
|
"LOCAL_OWNER_PROFILE",
|
|
21035
|
-
`Profile "${profileName2}" holds a local owner key. ${flow} would turn it into an OpenKey profile while keeping that key. Use a separate profile:
|
|
21046
|
+
`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 ...\`.`,
|
|
21036
21047
|
ExitCode.USAGE_ERROR
|
|
21037
21048
|
);
|
|
21038
21049
|
}
|
|
@@ -21067,7 +21078,7 @@ function assertSessionReplaceable(profileName2, snapshot, ownerDid, scope, newEx
|
|
|
21067
21078
|
if (problem !== void 0) {
|
|
21068
21079
|
throw new CLIError(
|
|
21069
21080
|
"PROFILE_STATE_INCONSISTENT",
|
|
21070
|
-
`Profile "${profileName2}" is inconsistent (${problem}), possibly from an interrupted write. Nothing was saved. Check
|
|
21081
|
+
`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.`,
|
|
21071
21082
|
ExitCode.ERROR
|
|
21072
21083
|
);
|
|
21073
21084
|
}
|
|
@@ -21083,7 +21094,7 @@ function assertSessionReplaceable(profileName2, snapshot, ownerDid, scope, newEx
|
|
|
21083
21094
|
const space = typeof session.spaceId === "string" ? session.spaceId : "an unknown space";
|
|
21084
21095
|
throw new CLIError(
|
|
21085
21096
|
"SESSION_IN_USE",
|
|
21086
|
-
`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 (
|
|
21097
|
+
`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.`,
|
|
21087
21098
|
ExitCode.USAGE_ERROR
|
|
21088
21099
|
);
|
|
21089
21100
|
}
|
|
@@ -21112,7 +21123,7 @@ async function commitLogin(profileName2, snapshot, commit) {
|
|
|
21112
21123
|
if (canonicalJson(current.profile) !== canonicalJson(snapshot.profile) || canonicalJson(current.key) !== canonicalJson(snapshot.key) || canonicalJson(current.session) !== canonicalJson(snapshot.session)) {
|
|
21113
21124
|
throw new CLIError(
|
|
21114
21125
|
"PROFILE_CHANGED_DURING_LOGIN",
|
|
21115
|
-
`Profile "${profileName2}" changed while this login was in progress (another login, key rotation or logout). Nothing was saved; check
|
|
21126
|
+
`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.`,
|
|
21116
21127
|
ExitCode.ERROR
|
|
21117
21128
|
);
|
|
21118
21129
|
}
|
|
@@ -21129,7 +21140,7 @@ async function commitLogin(profileName2, snapshot, commit) {
|
|
|
21129
21140
|
if (failures.length === 0) throw error;
|
|
21130
21141
|
throw new CLIError(
|
|
21131
21142
|
"PROFILE_STATE_INCONSISTENT",
|
|
21132
|
-
`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
|
|
21143
|
+
`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.`,
|
|
21133
21144
|
ExitCode.ERROR
|
|
21134
21145
|
);
|
|
21135
21146
|
}
|
|
@@ -21145,6 +21156,7 @@ async function commitLogin(profileName2, snapshot, commit) {
|
|
|
21145
21156
|
|
|
21146
21157
|
// src/auth/owner-key.ts
|
|
21147
21158
|
init_theme();
|
|
21159
|
+
import { CLI_NAME as CLI_NAME11 } from "@tinycloud/operations/cli-name";
|
|
21148
21160
|
function openKeyPrimaryFlag(delegation) {
|
|
21149
21161
|
return typeof delegation.primary === "boolean" ? delegation.primary : void 0;
|
|
21150
21162
|
}
|
|
@@ -21155,7 +21167,7 @@ function withOwnerKeyPrimary(profile, primary) {
|
|
|
21155
21167
|
function nonPrimaryKeyWarning(ownerDid) {
|
|
21156
21168
|
const address = ownerDid.split(":")[4] ?? ownerDid;
|
|
21157
21169
|
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.
|
|
21158
|
-
To use your primary key, log in again and choose the primary key in OpenKey, for example into a new profile:
|
|
21170
|
+
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>
|
|
21159
21171
|
`;
|
|
21160
21172
|
}
|
|
21161
21173
|
function warnIfNotPrimaryKey(ownerDid, primary) {
|
|
@@ -21164,7 +21176,7 @@ function warnIfNotPrimaryKey(ownerDid, primary) {
|
|
|
21164
21176
|
}
|
|
21165
21177
|
function announceFirstOwner(profileName2, expectedOwner, ownerDid) {
|
|
21166
21178
|
if (expectedOwner !== void 0 || ownerDid === void 0) return;
|
|
21167
|
-
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
|
|
21179
|
+
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.
|
|
21168
21180
|
`);
|
|
21169
21181
|
}
|
|
21170
21182
|
function ownerLoginPermissions(owner) {
|
|
@@ -21588,6 +21600,7 @@ init_types();
|
|
|
21588
21600
|
init_constants();
|
|
21589
21601
|
init_permissions();
|
|
21590
21602
|
init_sdk();
|
|
21603
|
+
import { CLI_NAME as CLI_NAME13 } from "@tinycloud/operations/cli-name";
|
|
21591
21604
|
import { TinyCloudNode as TinyCloudNode2 } from "@tinycloud/node-sdk";
|
|
21592
21605
|
import { DelegationRequestBindingSchema, PermissionEntrySchema } from "@tinycloud/operations/artifacts";
|
|
21593
21606
|
import {
|
|
@@ -21602,6 +21615,7 @@ import {
|
|
|
21602
21615
|
// src/lib/revoke-delegation.ts
|
|
21603
21616
|
init_constants();
|
|
21604
21617
|
init_errors();
|
|
21618
|
+
import { CLI_NAME as CLI_NAME12 } from "@tinycloud/operations/cli-name";
|
|
21605
21619
|
import { parseSignedCompactUcanAttenuation } from "@tinycloud/sdk-core";
|
|
21606
21620
|
import { inspectStoredDelegation, withoutBearer } from "@tinycloud/operations/delegation-binding";
|
|
21607
21621
|
init_permissions();
|
|
@@ -21787,7 +21801,7 @@ async function revokeDelegationOnNode(params) {
|
|
|
21787
21801
|
"REVOKE_UNAUTHORIZED",
|
|
21788
21802
|
"The node rejected this revocation: Unauthorized Revoker.",
|
|
21789
21803
|
ExitCode.PERMISSION_DENIED,
|
|
21790
|
-
{ 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
|
|
21804
|
+
{ 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}\`.` }
|
|
21791
21805
|
);
|
|
21792
21806
|
}
|
|
21793
21807
|
throw cliErrorFromService(result.error);
|
|
@@ -21870,7 +21884,7 @@ function renderList(result) {
|
|
|
21870
21884
|
}
|
|
21871
21885
|
process.stdout.write(`Profile: ${result.profile}
|
|
21872
21886
|
`);
|
|
21873
|
-
process.stdout.write(`Session CID: ${result.session?.cid ?? "unavailable"}` + (result.session?.cid ? ` (revoke with
|
|
21887
|
+
process.stdout.write(`Session CID: ${result.session?.cid ?? "unavailable"}` + (result.session?.cid ? ` (revoke with ${CLI_NAME13} delegation revoke ${result.session.cid})
|
|
21874
21888
|
` : "\n"));
|
|
21875
21889
|
process.stdout.write(`Local verification: ${result.localVerification}; node validation and revocation are not checked.
|
|
21876
21890
|
`);
|
|
@@ -21966,7 +21980,7 @@ function registerAuthGrantsCommand(auth, options = {}) {
|
|
|
21966
21980
|
ExitCode.ERROR,
|
|
21967
21981
|
{
|
|
21968
21982
|
causeCode: cause.code,
|
|
21969
|
-
hint: `Do not use --revoke again. After fixing local profile storage, run:
|
|
21983
|
+
hint: `Do not use --revoke again. After fixing local profile storage, run: ${CLI_NAME13} --profile ${ctx.profile} auth grants remove ${cid}`
|
|
21970
21984
|
}
|
|
21971
21985
|
);
|
|
21972
21986
|
}
|
|
@@ -22127,7 +22141,7 @@ async function promptAuthMethod() {
|
|
|
22127
22141
|
function registerAuthCommand(program, options) {
|
|
22128
22142
|
const auth = program.command("auth").description("Authentication management");
|
|
22129
22143
|
registerAuthGrantsCommand(auth, { openKeyAcquisition: options?.openKeyAcquisition });
|
|
22130
|
-
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", "Use manual paste mode instead of browser callback").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
|
|
22144
|
+
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", "Use manual paste mode instead of browser callback").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) => {
|
|
22131
22145
|
try {
|
|
22132
22146
|
if (options2.device && options2.paste) {
|
|
22133
22147
|
throw new CLIError("INVALID_ARGUMENT", "--device and --paste are mutually exclusive.", ExitCode.USAGE_ERROR);
|
|
@@ -22235,7 +22249,7 @@ function registerAuthCommand(program, options) {
|
|
|
22235
22249
|
return handleError(error);
|
|
22236
22250
|
}
|
|
22237
22251
|
});
|
|
22238
|
-
auth.command("logout").description(
|
|
22252
|
+
auth.command("logout").description(`Clear the local session and remove local replicas. Logout is local; delegations and grants on the node stay valid until they expire. Use \`${CLI_NAME14} delegation revoke <cid>\` to end access now.`).option("--keep-replicas", "Keep this profile's local replicas").action(async (options2, cmd) => {
|
|
22239
22253
|
try {
|
|
22240
22254
|
const globalOpts = cmd.optsWithGlobals();
|
|
22241
22255
|
const ctx = await ProfileManager.resolveContext(globalOpts, { storedSession: "unused" });
|
|
@@ -22247,7 +22261,7 @@ function registerAuthCommand(program, options) {
|
|
|
22247
22261
|
authenticated: false,
|
|
22248
22262
|
replicasRemoved,
|
|
22249
22263
|
replicasKept: options2.keepReplicas === true,
|
|
22250
|
-
warning:
|
|
22264
|
+
warning: `Logout is local; delegations and grants on the node stay valid until they expire. Use \`${CLI_NAME14} delegation revoke <cid>\` to end access now.`
|
|
22251
22265
|
});
|
|
22252
22266
|
} catch (error) {
|
|
22253
22267
|
return handleError(error);
|
|
@@ -22369,7 +22383,7 @@ ${signInAgainHint(ctx.profile, posture ?? void 0)}
|
|
|
22369
22383
|
if (profile.authMethod === "openkey" || options2.device) {
|
|
22370
22384
|
const key = await ProfileManager.getKey(ctx.profile);
|
|
22371
22385
|
if (!key) {
|
|
22372
|
-
throw new CLIError("NO_KEY", `No key found for profile "${ctx.profile}". Run
|
|
22386
|
+
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);
|
|
22373
22387
|
}
|
|
22374
22388
|
const openkeyHost = resolveOpenKeyHost(profile);
|
|
22375
22389
|
const grants = [];
|
|
@@ -22383,7 +22397,7 @@ ${signInAgainHint(ctx.profile, posture ?? void 0)}
|
|
|
22383
22397
|
const declined = [];
|
|
22384
22398
|
for (const group of groupPermissionsBySpace(requested)) {
|
|
22385
22399
|
const reason = permissionGrantReason(
|
|
22386
|
-
|
|
22400
|
+
`Grant requested TinyCloud permissions from \`${CLI_NAME14} auth request --grant\`.`,
|
|
22387
22401
|
group
|
|
22388
22402
|
);
|
|
22389
22403
|
const request = grantRequestPermissions(group, profile.spaceId ?? profile.spaceName);
|
|
@@ -22492,7 +22506,7 @@ ${signInAgainHint(ctx.profile, posture ?? void 0)}
|
|
|
22492
22506
|
kind: parsed.kind,
|
|
22493
22507
|
requestId: parsed.requestId,
|
|
22494
22508
|
requested: parsed.requested,
|
|
22495
|
-
next:
|
|
22509
|
+
next: `${CLI_NAME14} auth retry ${parsed.requestId}`
|
|
22496
22510
|
});
|
|
22497
22511
|
return;
|
|
22498
22512
|
}
|
|
@@ -23043,7 +23057,7 @@ async function ensureDelegationAuthority(params) {
|
|
|
23043
23057
|
if (!key) {
|
|
23044
23058
|
throw new CLIError(
|
|
23045
23059
|
"NO_KEY",
|
|
23046
|
-
`No key found for profile "${params.ctx.profile}". Run
|
|
23060
|
+
`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.`,
|
|
23047
23061
|
ExitCode.AUTH_REQUIRED
|
|
23048
23062
|
);
|
|
23049
23063
|
}
|
|
@@ -23288,7 +23302,7 @@ async function rotateAuthKey(profileName2, host, options = {}) {
|
|
|
23288
23302
|
if (!profile.privateKey) {
|
|
23289
23303
|
throw new CLIError(
|
|
23290
23304
|
"LOCAL_OWNER_KEY_REQUIRED",
|
|
23291
|
-
`Profile "${profileName2}" does not have a local owner private key. Run
|
|
23305
|
+
`Profile "${profileName2}" does not have a local owner private key. Run \`${CLI_NAME14} auth login --method local\` first.`,
|
|
23292
23306
|
ExitCode.AUTH_REQUIRED
|
|
23293
23307
|
);
|
|
23294
23308
|
}
|
|
@@ -23511,7 +23525,7 @@ async function refreshOpenKeySession(profileName2, host, options = {}) {
|
|
|
23511
23525
|
if (!key) {
|
|
23512
23526
|
throw new CLIError(
|
|
23513
23527
|
"NO_KEY",
|
|
23514
|
-
`No key found for profile "${profileName2}". Run
|
|
23528
|
+
`No key found for profile "${profileName2}". Run \`${CLI_NAME14} --profile ${profileName2} auth rotate\` to create a new key and sign in.`,
|
|
23515
23529
|
ExitCode.AUTH_REQUIRED
|
|
23516
23530
|
);
|
|
23517
23531
|
}
|
|
@@ -23592,6 +23606,7 @@ async function refreshOpenKeySession(profileName2, host, options = {}) {
|
|
|
23592
23606
|
}
|
|
23593
23607
|
|
|
23594
23608
|
// src/commands/completion.ts
|
|
23609
|
+
import { CLI_NAME as CLI_NAME15 } from "@tinycloud/operations/cli-name";
|
|
23595
23610
|
function registerCompletionCommand(program) {
|
|
23596
23611
|
const completion = program.command("completion").description("Generate shell completions");
|
|
23597
23612
|
completion.command("bash").description("Output bash completions").action(() => {
|
|
@@ -23608,7 +23623,7 @@ function registerCompletionCommand(program) {
|
|
|
23608
23623
|
});
|
|
23609
23624
|
}
|
|
23610
23625
|
function generateBashCompletion() {
|
|
23611
|
-
return `#
|
|
23626
|
+
return `# ${CLI_NAME15} bash completion
|
|
23612
23627
|
_tc_completions() {
|
|
23613
23628
|
local cur prev commands subcommands
|
|
23614
23629
|
COMPREPLY=()
|
|
@@ -23633,11 +23648,11 @@ _tc_completions() {
|
|
|
23633
23648
|
COMPREPLY=( $(compgen -W "\${subcommands}" -- "\${cur}") )
|
|
23634
23649
|
fi
|
|
23635
23650
|
}
|
|
23636
|
-
complete -F _tc_completions
|
|
23651
|
+
complete -F _tc_completions ${CLI_NAME15}
|
|
23637
23652
|
`;
|
|
23638
23653
|
}
|
|
23639
23654
|
function generateZshCompletion() {
|
|
23640
|
-
return `#compdef
|
|
23655
|
+
return `#compdef ${CLI_NAME15}
|
|
23641
23656
|
|
|
23642
23657
|
_tc() {
|
|
23643
23658
|
local -a commands
|
|
@@ -23688,49 +23703,50 @@ _tc
|
|
|
23688
23703
|
`;
|
|
23689
23704
|
}
|
|
23690
23705
|
function generateFishCompletion() {
|
|
23691
|
-
return `#
|
|
23706
|
+
return `# ${CLI_NAME15} fish completion
|
|
23692
23707
|
set -l commands init auth kv space delegation share node profile completion
|
|
23693
23708
|
|
|
23694
23709
|
# Disable file completion by default
|
|
23695
|
-
complete -c
|
|
23710
|
+
complete -c ${CLI_NAME15} -f
|
|
23696
23711
|
|
|
23697
23712
|
# Top-level commands
|
|
23698
|
-
complete -c
|
|
23699
|
-
complete -c
|
|
23700
|
-
complete -c
|
|
23701
|
-
complete -c
|
|
23702
|
-
complete -c
|
|
23703
|
-
complete -c
|
|
23704
|
-
complete -c
|
|
23705
|
-
complete -c
|
|
23706
|
-
complete -c
|
|
23713
|
+
complete -c ${CLI_NAME15} -n "not __fish_seen_subcommand_from $commands" -a init -d "Initialize a new TinyCloud profile"
|
|
23714
|
+
complete -c ${CLI_NAME15} -n "not __fish_seen_subcommand_from $commands" -a auth -d "Authentication management"
|
|
23715
|
+
complete -c ${CLI_NAME15} -n "not __fish_seen_subcommand_from $commands" -a kv -d "Key-value store operations"
|
|
23716
|
+
complete -c ${CLI_NAME15} -n "not __fish_seen_subcommand_from $commands" -a space -d "Space management"
|
|
23717
|
+
complete -c ${CLI_NAME15} -n "not __fish_seen_subcommand_from $commands" -a delegation -d "Manage delegations"
|
|
23718
|
+
complete -c ${CLI_NAME15} -n "not __fish_seen_subcommand_from $commands" -a share -d "Share data with others"
|
|
23719
|
+
complete -c ${CLI_NAME15} -n "not __fish_seen_subcommand_from $commands" -a node -d "Node health and info"
|
|
23720
|
+
complete -c ${CLI_NAME15} -n "not __fish_seen_subcommand_from $commands" -a profile -d "Profile management"
|
|
23721
|
+
complete -c ${CLI_NAME15} -n "not __fish_seen_subcommand_from $commands" -a completion -d "Generate shell completions"
|
|
23707
23722
|
|
|
23708
23723
|
# Subcommands
|
|
23709
|
-
complete -c
|
|
23710
|
-
complete -c
|
|
23711
|
-
complete -c
|
|
23712
|
-
complete -c
|
|
23713
|
-
complete -c
|
|
23714
|
-
complete -c
|
|
23715
|
-
complete -c
|
|
23716
|
-
complete -c
|
|
23724
|
+
complete -c ${CLI_NAME15} -n "__fish_seen_subcommand_from auth" -a "login logout rotate status whoami"
|
|
23725
|
+
complete -c ${CLI_NAME15} -n "__fish_seen_subcommand_from kv" -a "get put delete list head"
|
|
23726
|
+
complete -c ${CLI_NAME15} -n "__fish_seen_subcommand_from space" -a "list create info switch"
|
|
23727
|
+
complete -c ${CLI_NAME15} -n "__fish_seen_subcommand_from delegation" -a "create list info revoke"
|
|
23728
|
+
complete -c ${CLI_NAME15} -n "__fish_seen_subcommand_from share" -a "create receive list revoke"
|
|
23729
|
+
complete -c ${CLI_NAME15} -n "__fish_seen_subcommand_from node" -a "health version status"
|
|
23730
|
+
complete -c ${CLI_NAME15} -n "__fish_seen_subcommand_from profile" -a "list create show switch delete"
|
|
23731
|
+
complete -c ${CLI_NAME15} -n "__fish_seen_subcommand_from completion" -a "bash zsh fish"
|
|
23717
23732
|
|
|
23718
23733
|
# Global options
|
|
23719
|
-
complete -c
|
|
23720
|
-
complete -c
|
|
23721
|
-
complete -c
|
|
23722
|
-
complete -c
|
|
23723
|
-
complete -c
|
|
23724
|
-
complete -c
|
|
23725
|
-
complete -c
|
|
23726
|
-
complete -c
|
|
23734
|
+
complete -c ${CLI_NAME15} -l profile -s p -d "Profile to use"
|
|
23735
|
+
complete -c ${CLI_NAME15} -l host -s H -d "TinyCloud node URL"
|
|
23736
|
+
complete -c ${CLI_NAME15} -l verbose -s v -d "Enable verbose output"
|
|
23737
|
+
complete -c ${CLI_NAME15} -l no-cache -d "Disable caching"
|
|
23738
|
+
complete -c ${CLI_NAME15} -l quiet -s q -d "Suppress non-essential output"
|
|
23739
|
+
complete -c ${CLI_NAME15} -l replication -d "Enable read-through replication"
|
|
23740
|
+
complete -c ${CLI_NAME15} -l no-replication -d "Disable replication"
|
|
23741
|
+
complete -c ${CLI_NAME15} -l replication-debug -d "Write replication diagnostics to stderr"
|
|
23727
23742
|
`;
|
|
23728
23743
|
}
|
|
23729
23744
|
|
|
23730
23745
|
// src/commands/courier.ts
|
|
23731
|
-
|
|
23746
|
+
import { CLI_NAME as CLI_NAME16 } from "@tinycloud/operations/cli-name";
|
|
23747
|
+
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>.`;
|
|
23732
23748
|
function registerCourierCommand(program) {
|
|
23733
|
-
const courier = program.command("courier").description(
|
|
23749
|
+
const courier = program.command("courier").description(`Agent-to-agent threads over TinyCloud; run \`${CLI_NAME16} courier --help\` (beta)`).argument("[args...]").allowUnknownOption().helpOption(false);
|
|
23734
23750
|
courier.action(() => courier.error(TC_OPTIONS_BEFORE_COURIER, { exitCode: 2, code: "tc.courier.options" }));
|
|
23735
23751
|
}
|
|
23736
23752
|
|
|
@@ -23887,6 +23903,7 @@ init_constants();
|
|
|
23887
23903
|
init_formatter();
|
|
23888
23904
|
init_theme();
|
|
23889
23905
|
init_errors();
|
|
23906
|
+
import { CLI_NAME as CLI_NAME17 } from "@tinycloud/operations/cli-name";
|
|
23890
23907
|
init_session_expired();
|
|
23891
23908
|
init_types();
|
|
23892
23909
|
function registerDoctorCommand(program) {
|
|
@@ -23920,7 +23937,7 @@ function registerDoctorCommand(program) {
|
|
|
23920
23937
|
const profile = await ProfileManager.getProfile(profileName2);
|
|
23921
23938
|
keyDetail = profile.did ? `${profile.did.slice(0, 20)}...` : "key found";
|
|
23922
23939
|
} else {
|
|
23923
|
-
keyDetail =
|
|
23940
|
+
keyDetail = `no key \u2014 run ${CLI_NAME17} init`;
|
|
23924
23941
|
}
|
|
23925
23942
|
} catch {
|
|
23926
23943
|
keyDetail = "error reading key";
|
|
@@ -23942,7 +23959,7 @@ function registerDoctorCommand(program) {
|
|
|
23942
23959
|
} else if (state2 === "unverified") {
|
|
23943
23960
|
sessionDetail = `not usable (no signed OpenKey proof) \u2014 ${signInAgainHint(profileName2, resolveProfilePosture(profile))}`;
|
|
23944
23961
|
} else {
|
|
23945
|
-
sessionDetail = sessionOk ? "active" :
|
|
23962
|
+
sessionDetail = sessionOk ? "active" : `no session \u2014 run ${CLI_NAME17} auth login`;
|
|
23946
23963
|
}
|
|
23947
23964
|
} catch {
|
|
23948
23965
|
sessionDetail = "error reading session";
|
|
@@ -23970,7 +23987,7 @@ function registerDoctorCommand(program) {
|
|
|
23970
23987
|
try {
|
|
23971
23988
|
const profile = await ProfileManager.getProfile(profileName2);
|
|
23972
23989
|
spaceOk = Boolean(profile.spaceId);
|
|
23973
|
-
spaceDetail = spaceOk ? `${profile.spaceId.slice(0, 16)}...` :
|
|
23990
|
+
spaceDetail = spaceOk ? `${profile.spaceId.slice(0, 16)}...` : `no space \u2014 run ${CLI_NAME17} space create`;
|
|
23974
23991
|
} catch {
|
|
23975
23992
|
spaceDetail = "error checking space";
|
|
23976
23993
|
}
|
|
@@ -24160,6 +24177,7 @@ ${rowCount} row${rowCount === 1 ? "" : "s"} returned`) + "\n");
|
|
|
24160
24177
|
}
|
|
24161
24178
|
|
|
24162
24179
|
// src/commands/enable.ts
|
|
24180
|
+
import { CLI_NAME as CLI_NAME18 } from "@tinycloud/operations/cli-name";
|
|
24163
24181
|
init_constants();
|
|
24164
24182
|
init_profiles();
|
|
24165
24183
|
init_errors();
|
|
@@ -24167,7 +24185,7 @@ init_formatter();
|
|
|
24167
24185
|
init_publishing_manifest();
|
|
24168
24186
|
function registerEnableCommand(program) {
|
|
24169
24187
|
const enable = program.command("enable").description("Enable a narrowly scoped TinyCloud service");
|
|
24170
|
-
enable.command("share").description(
|
|
24188
|
+
enable.command("share").description(`Approve Share publishing scope through OpenKey device authorization (same as \`${CLI_NAME18} auth login --device --manifest builtin:share-publishing\`). Use a dedicated profile, e.g. \`${CLI_NAME18} init --name publisher --key-only && ${CLI_NAME18} --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) => {
|
|
24171
24189
|
try {
|
|
24172
24190
|
const globalOptions = command.optsWithGlobals();
|
|
24173
24191
|
const context = await ProfileManager.resolveContext(globalOptions, { storedSession: "unused" });
|
|
@@ -24203,6 +24221,7 @@ init_profiles();
|
|
|
24203
24221
|
init_formatter();
|
|
24204
24222
|
init_errors();
|
|
24205
24223
|
init_constants();
|
|
24224
|
+
import { CLI_NAME as CLI_NAME19 } from "@tinycloud/operations/cli-name";
|
|
24206
24225
|
function registerInitCommand(program) {
|
|
24207
24226
|
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) => {
|
|
24208
24227
|
try {
|
|
@@ -24220,7 +24239,7 @@ function registerInitCommand(program) {
|
|
|
24220
24239
|
if (await ProfileManager.profileExists(profileName2)) {
|
|
24221
24240
|
throw new CLIError(
|
|
24222
24241
|
"PROFILE_EXISTS",
|
|
24223
|
-
`Profile "${profileName2}" already exists. Use
|
|
24242
|
+
`Profile "${profileName2}" already exists. Use \`${CLI_NAME19} profile delete ${profileName2}\` first or choose a different name.`,
|
|
24224
24243
|
ExitCode.ERROR
|
|
24225
24244
|
);
|
|
24226
24245
|
}
|
|
@@ -24562,6 +24581,7 @@ init_errors();
|
|
|
24562
24581
|
init_constants();
|
|
24563
24582
|
init_theme();
|
|
24564
24583
|
import { resolveManifestKnowledgeRoot as resolveManifestKnowledgeRoot2 } from "@tinycloud/sdk-core";
|
|
24584
|
+
import { CLI_NAME as CLI_NAME20 } from "@tinycloud/operations/cli-name";
|
|
24565
24585
|
import { readFile as readFile8 } from "fs/promises";
|
|
24566
24586
|
var DEFAULT_APP_SPACE = "applications";
|
|
24567
24587
|
function registerManifestCommand(program) {
|
|
@@ -24569,8 +24589,8 @@ function registerManifestCommand(program) {
|
|
|
24569
24589
|
manifest.command("resolve <source>").description("Resolve a manifest file or URL to its effective space, paths, and DB basenames").addHelpText("after", `
|
|
24570
24590
|
|
|
24571
24591
|
Examples:
|
|
24572
|
-
$
|
|
24573
|
-
$
|
|
24592
|
+
$ ${CLI_NAME20} manifest resolve ./manifest.json
|
|
24593
|
+
$ ${CLI_NAME20} manifest resolve https://app.example.com/manifest.json --json
|
|
24574
24594
|
|
|
24575
24595
|
What it shows:
|
|
24576
24596
|
- app_id, name, manifest_version
|
|
@@ -24580,7 +24600,7 @@ What it shows:
|
|
|
24580
24600
|
|
|
24581
24601
|
This command is read-only and does NOT contact the node \u2014 it just resolves
|
|
24582
24602
|
the manifest against the active profile's address/chain so you know which
|
|
24583
|
-
\`--space\` and \`--db\` values to pass to other
|
|
24603
|
+
\`--space\` and \`--db\` values to pass to other ${CLI_NAME20} commands.
|
|
24584
24604
|
`).action(async (source, _options, cmd) => {
|
|
24585
24605
|
try {
|
|
24586
24606
|
const globalOpts = cmd.optsWithGlobals();
|
|
@@ -24649,7 +24669,7 @@ ${theme.heading("SQL databases")}
|
|
|
24649
24669
|
`);
|
|
24650
24670
|
}
|
|
24651
24671
|
process.stdout.write(theme.muted(`
|
|
24652
|
-
Use with:
|
|
24672
|
+
Use with: ${CLI_NAME20} sql query --space ${spaceName} --db <db> "..."
|
|
24653
24673
|
`));
|
|
24654
24674
|
}
|
|
24655
24675
|
if (permissions.length > 0) {
|
|
@@ -24769,6 +24789,7 @@ init_profiles();
|
|
|
24769
24789
|
init_formatter();
|
|
24770
24790
|
init_errors();
|
|
24771
24791
|
init_constants();
|
|
24792
|
+
import { CLI_NAME as CLI_NAME21 } from "@tinycloud/operations/cli-name";
|
|
24772
24793
|
import { createInterface as createInterface3 } from "readline";
|
|
24773
24794
|
init_theme();
|
|
24774
24795
|
init_types();
|
|
@@ -24914,9 +24935,9 @@ profile at command time. Precedence for every kv/sql command:
|
|
|
24914
24935
|
explicit --space flag > profile defaultSpace > primary space.
|
|
24915
24936
|
|
|
24916
24937
|
Examples:
|
|
24917
|
-
$
|
|
24918
|
-
$
|
|
24919
|
-
$
|
|
24938
|
+
$ ${CLI_NAME21} profile set-default-space applications
|
|
24939
|
+
$ ${CLI_NAME21} profile set-default-space applications --profile cli-test
|
|
24940
|
+
$ ${CLI_NAME21} profile set-default-space --unset
|
|
24920
24941
|
`).action(async (name, options, cmd) => {
|
|
24921
24942
|
try {
|
|
24922
24943
|
const globalOpts = cmd.optsWithGlobals();
|
|
@@ -24928,7 +24949,7 @@ Examples:
|
|
|
24928
24949
|
if (!options.unset && (name === void 0 || name === "")) {
|
|
24929
24950
|
throw new CLIError(
|
|
24930
24951
|
"USAGE_ERROR",
|
|
24931
|
-
|
|
24952
|
+
`Provide a space name (e.g. \`${CLI_NAME21} profile set-default-space applications\`) or pass --unset.`,
|
|
24932
24953
|
ExitCode.USAGE_ERROR
|
|
24933
24954
|
);
|
|
24934
24955
|
}
|
|
@@ -24988,6 +25009,7 @@ function parseOperatorType(raw) {
|
|
|
24988
25009
|
// src/commands/replica.ts
|
|
24989
25010
|
init_sdk();
|
|
24990
25011
|
init_replication_registry();
|
|
25012
|
+
import { CLI_NAME as CLI_NAME22 } from "@tinycloud/operations/cli-name";
|
|
24991
25013
|
import { randomBytes as randomBytes6 } from "crypto";
|
|
24992
25014
|
import { constants as fsConstants2 } from "fs";
|
|
24993
25015
|
import { open as open4, readdir as readdir5, rename as rename3, stat as stat3, unlink as unlink2, readFile as readFile9, lstat as lstat4 } from "fs/promises";
|
|
@@ -25127,11 +25149,11 @@ var EXIT_BY_CODE = {
|
|
|
25127
25149
|
var READ_FAILURE = {
|
|
25128
25150
|
absent: { code: "KEY_ABSENT", exit: ExitCode.NOT_FOUND, what: "is not in the replica (the replica covers its whole prefix)" },
|
|
25129
25151
|
deleted: { code: "KEY_DELETED", exit: ExitCode.NOT_FOUND, what: "was deleted at the source" },
|
|
25130
|
-
content_missing: { code: "CONTENT_MISSING", exit: ExitCode.NOT_FOUND, what:
|
|
25152
|
+
content_missing: { code: "CONTENT_MISSING", exit: ExitCode.NOT_FOUND, what: `is known but its content has not been fetched yet; run ${CLI_NAME22} replica sync` },
|
|
25131
25153
|
coverage_incomplete: {
|
|
25132
25154
|
code: "COVERAGE_INCOMPLETE",
|
|
25133
25155
|
exit: ExitCode.NOT_FOUND,
|
|
25134
|
-
what:
|
|
25156
|
+
what: `is not in the replica, which has not finished its first sync; run ${CLI_NAME22} replica sync`
|
|
25135
25157
|
},
|
|
25136
25158
|
not_covered: { code: "NOT_COVERED", exit: ExitCode.USAGE_ERROR, what: "is outside the replica's prefix" }
|
|
25137
25159
|
};
|
|
@@ -25182,7 +25204,7 @@ async function existingReplicaName(profile, option) {
|
|
|
25182
25204
|
const names = await replicaNames(profile);
|
|
25183
25205
|
if (names.length === 1) return names[0];
|
|
25184
25206
|
if (names.length === 0) {
|
|
25185
|
-
throw new ReplicaError(ReplicaErrorCode.NOT_FOUND, `Profile "${profile}" has no replicas. Create one with:
|
|
25207
|
+
throw new ReplicaError(ReplicaErrorCode.NOT_FOUND, `Profile "${profile}" has no replicas. Create one with: ${CLI_NAME22} replica sync --prefix <prefix>`);
|
|
25186
25208
|
}
|
|
25187
25209
|
throw new CLIError("USAGE_ERROR", `Profile "${profile}" has several replicas (${names.join(", ")}); pass --replica <name>.`, ExitCode.USAGE_ERROR);
|
|
25188
25210
|
}
|
|
@@ -25241,9 +25263,9 @@ async function storedGrants(profile) {
|
|
|
25241
25263
|
function grantHint(space, prefix) {
|
|
25242
25264
|
return [
|
|
25243
25265
|
"A replica needs a device grant with get and sync on its prefix:",
|
|
25244
|
-
` device:
|
|
25245
|
-
|
|
25246
|
-
|
|
25266
|
+
` device: ${CLI_NAME22} auth request --cap tinycloud.kv:${space}:${prefix}:get,list,metadata,sync --expiry 30d --emit req.json`,
|
|
25267
|
+
` owner: ${CLI_NAME22} auth grant req.json > grant.json`,
|
|
25268
|
+
` device: ${CLI_NAME22} auth import grant.json`
|
|
25247
25269
|
].join("\n");
|
|
25248
25270
|
}
|
|
25249
25271
|
function resolveSpace(input, prefix, grants) {
|
|
@@ -25334,7 +25356,7 @@ function describeStatus(status) {
|
|
|
25334
25356
|
formatField("Size", formatBytes(status.bytes)),
|
|
25335
25357
|
formatField("Grant", status.device.delegationCid),
|
|
25336
25358
|
formatField("Last error", status.lastError ? `${status.lastError.code}: ${status.lastError.message}` : null),
|
|
25337
|
-
formatField("Purge", status.purgePending ?
|
|
25359
|
+
formatField("Purge", status.purgePending ? `incomplete: content files remain; the next ${CLI_NAME22} replica command retries` : null)
|
|
25338
25360
|
].join("\n");
|
|
25339
25361
|
}
|
|
25340
25362
|
async function writeFileAtomic(path, bytes) {
|
|
@@ -25506,7 +25528,7 @@ or coverage incomplete; 5 grant expired, revoked or not yet valid; 6 network;
|
|
|
25506
25528
|
await store.close();
|
|
25507
25529
|
throw new ReplicaError(
|
|
25508
25530
|
ReplicaErrorCode.CONFIG_MISMATCH,
|
|
25509
|
-
`Replica ${name} already follows ${differs}. Use another --replica name, or
|
|
25531
|
+
`Replica ${name} already follows ${differs}. Use another --replica name, or ${CLI_NAME22} replica reset --replica ${name} --purge first.`
|
|
25510
25532
|
);
|
|
25511
25533
|
}
|
|
25512
25534
|
} else {
|
|
@@ -25684,6 +25706,7 @@ init_theme();
|
|
|
25684
25706
|
init_errors();
|
|
25685
25707
|
init_warnings();
|
|
25686
25708
|
init_constants();
|
|
25709
|
+
import { CLI_NAME as CLI_NAME24 } from "@tinycloud/operations/cli-name";
|
|
25687
25710
|
import { readFile as readFile10 } from "fs/promises";
|
|
25688
25711
|
import { join as join11 } from "path";
|
|
25689
25712
|
import { homedir, hostname, userInfo } from "os";
|
|
@@ -25894,6 +25917,7 @@ function parseStatusEnvelope(line) {
|
|
|
25894
25917
|
// src/lib/secrets-wait.ts
|
|
25895
25918
|
init_constants();
|
|
25896
25919
|
init_errors();
|
|
25920
|
+
import { CLI_NAME as CLI_NAME23 } from "@tinycloud/operations/cli-name";
|
|
25897
25921
|
var WAIT_BACKOFF_MS = [3e3, 4500, 6750, 10125];
|
|
25898
25922
|
var WAIT_STEADY_INTERVAL_MS = 15e3;
|
|
25899
25923
|
var DEFAULT_WAIT_TIMEOUT = "5m";
|
|
@@ -25901,7 +25925,7 @@ var MAX_WAIT_TIMEOUT_MS = 9 * 6e4;
|
|
|
25901
25925
|
var MAX_CONSECUTIVE_FAILURES = 5;
|
|
25902
25926
|
var TIMEOUT_RE = /^(0|\d+s|\d+m)$/;
|
|
25903
25927
|
var RETRYABLE_STATUS_ERRORS = { NODE_UNREACHABLE: true, NODE_ERROR: true };
|
|
25904
|
-
var EXPLICIT_KEY_HINT =
|
|
25928
|
+
var EXPLICIT_KEY_HINT = `${CLI_NAME23} secrets wait never signs in, and an explicit private key has no stored session. Use a local profile signed in once with ${CLI_NAME23} --profile <profile> auth login --method local, without TC_PRIVATE_KEY.`;
|
|
25905
25929
|
function abortableSleep(ms2, signal) {
|
|
25906
25930
|
return new Promise((resolve5) => {
|
|
25907
25931
|
if (signal.aborted) {
|
|
@@ -25937,7 +25961,7 @@ async function runSecretsWait(request, deps) {
|
|
|
25937
25961
|
let step = 0;
|
|
25938
25962
|
const cancelled = () => new CLIError(
|
|
25939
25963
|
"CANCELLED",
|
|
25940
|
-
|
|
25964
|
+
`Interrupted: ${CLI_NAME23} secrets wait stopped before the secrets were ready.`,
|
|
25941
25965
|
ExitCode.CANCELLED,
|
|
25942
25966
|
progress === void 0 ? {} : { progress }
|
|
25943
25967
|
);
|
|
@@ -26081,13 +26105,13 @@ function statusError(error, profile, warnings) {
|
|
|
26081
26105
|
if (error.code === "AUTH_REQUIRED" || error.code === "SESSION_NOT_FOUND") {
|
|
26082
26106
|
const recovery = recoveryOf(error, "sign_in");
|
|
26083
26107
|
if (recovery !== void 0) {
|
|
26084
|
-
const hint = recovery.command !== void 0 ? `Sign in once with: ${recovery.command}, then retry.` : `Sign in to profile "${profile}" once with
|
|
26108
|
+
const hint = recovery.command !== void 0 ? `Sign in once with: ${recovery.command}, then retry.` : `Sign in to profile "${profile}" once with ${CLI_NAME23} auth login, then retry.`;
|
|
26085
26109
|
return new CLIError("AUTH_REQUIRED", error.message, ExitCode.AUTH_REQUIRED, { hint, recovery, ...extra });
|
|
26086
26110
|
}
|
|
26087
26111
|
}
|
|
26088
26112
|
if (error.code === "PROFILE_MIGRATION_REQUIRED") {
|
|
26089
26113
|
const recovery = recoveryOf(error, "complete_migration");
|
|
26090
|
-
const hint = recovery?.command !== void 0 ? `Run ${recovery.command} once to finish this profile's one-time upgrade, then retry wait.` : `Run
|
|
26114
|
+
const hint = recovery?.command !== void 0 ? `Run ${recovery.command} once to finish this profile's one-time upgrade, then retry wait.` : `Run ${CLI_NAME23} auth caps once with profile "${profile}" to finish its one-time upgrade, then retry wait.`;
|
|
26091
26115
|
return new CLIError("PROFILE_MIGRATION_REQUIRED", error.message, ExitCode.ERROR, {
|
|
26092
26116
|
hint,
|
|
26093
26117
|
...recovery === void 0 ? {} : { recovery },
|
|
@@ -26279,11 +26303,11 @@ async function runSecretOperation(params) {
|
|
|
26279
26303
|
}
|
|
26280
26304
|
function secretPermissionReason(action, name) {
|
|
26281
26305
|
const target = name ? ` secret "${name}"` : " secrets";
|
|
26282
|
-
return `Allow
|
|
26306
|
+
return `Allow \`${CLI_NAME24} secrets ${action}${name ? ` ${name}` : ""}\` to access${target} with the required TinyCloud permissions.`;
|
|
26283
26307
|
}
|
|
26284
26308
|
function assertOwnerApprovalPossible(profileName2, profile, action, name, missing = []) {
|
|
26285
26309
|
if (profile.authMethod !== "openkey" || process.stdin.isTTY || process.stderr.isTTY) return;
|
|
26286
|
-
const command =
|
|
26310
|
+
const command = `${CLI_NAME24} secrets ${action === "del" ? "delete" : action}${name ? ` ${name}` : ""}`;
|
|
26287
26311
|
throw new CLIError(
|
|
26288
26312
|
"PERMISSION_DENIED",
|
|
26289
26313
|
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.`,
|
|
@@ -26294,7 +26318,7 @@ function assertOwnerApprovalPossible(profileName2, profile, action, name, missin
|
|
|
26294
26318
|
);
|
|
26295
26319
|
}
|
|
26296
26320
|
function scopedSecretLoginHint(profileName2) {
|
|
26297
|
-
return `Have the owner approve a scoped login whose manifest names the secret:
|
|
26321
|
+
return `Have the owner approve a scoped login whose manifest names the secret: ${CLI_NAME24} --profile ${profileName2} auth login --method openkey --paste --manifest <manifest.json>. Pass the owner's code on stdin, newline-terminated.`;
|
|
26298
26322
|
}
|
|
26299
26323
|
async function runSecretOperationAttempt(label, operation) {
|
|
26300
26324
|
try {
|
|
@@ -26428,7 +26452,7 @@ ${message}`,
|
|
|
26428
26452
|
"AUTH_REQUIRED",
|
|
26429
26453
|
"Not signed in to TinyCloud.",
|
|
26430
26454
|
ExitCode.AUTH_REQUIRED,
|
|
26431
|
-
{ hint: `Sign in with:
|
|
26455
|
+
{ hint: `Sign in with: ${CLI_NAME24} --profile ${result.context.profile} auth login` }
|
|
26432
26456
|
);
|
|
26433
26457
|
}
|
|
26434
26458
|
if (result.error.code === "NODE_UNREACHABLE") {
|
|
@@ -26905,7 +26929,7 @@ function registerSecretsCommand(program, openKeyAcquisition) {
|
|
|
26905
26929
|
name: "Encryption network",
|
|
26906
26930
|
ok: false,
|
|
26907
26931
|
detail: `${networkName} not found`,
|
|
26908
|
-
hint:
|
|
26932
|
+
hint: `${CLI_NAME24} secrets network init ${networkName}`
|
|
26909
26933
|
}
|
|
26910
26934
|
];
|
|
26911
26935
|
let secret;
|
|
@@ -26951,7 +26975,7 @@ function registerSecretsCommand(program, openKeyAcquisition) {
|
|
|
26951
26975
|
name: "Secret access",
|
|
26952
26976
|
ok: false,
|
|
26953
26977
|
detail: notFound ? `${resolved.permissionPaths.vault} not found` : result.error.message,
|
|
26954
|
-
hint: notFound ? local ?
|
|
26978
|
+
hint: notFound ? local ? `${CLI_NAME24} secrets put ${resolved.name}${formatSecretScopeFlag(scopeOptions)} --stdin` : `${CLI_NAME24} secrets request ${resolved.name}${formatSecretScopeFlag(scopeOptions)}` : `Ask the owner profile to grant ${secretCapabilityAction("get")} and ${SECRET_DECRYPT_CAPABILITY}.`
|
|
26955
26979
|
});
|
|
26956
26980
|
}
|
|
26957
26981
|
} else {
|
|
@@ -27195,7 +27219,7 @@ function registerSecretsCommand(program, openKeyAcquisition) {
|
|
|
27195
27219
|
if (effectiveLocal(profile, options)) {
|
|
27196
27220
|
throw new CLIError(
|
|
27197
27221
|
"LOCAL_OWNER_PROFILE",
|
|
27198
|
-
`Profile "${ctx.profile}" uses a local key, which owns its secrets: store them with
|
|
27222
|
+
`Profile "${ctx.profile}" uses a local key, which owns its secrets: store them with ${CLI_NAME24} secrets put NAME --stdin instead of requesting them.`,
|
|
27199
27223
|
ExitCode.USAGE_ERROR
|
|
27200
27224
|
);
|
|
27201
27225
|
}
|
|
@@ -27316,6 +27340,9 @@ function registerSecretsCommand(program, openKeyAcquisition) {
|
|
|
27316
27340
|
});
|
|
27317
27341
|
}
|
|
27318
27342
|
|
|
27343
|
+
// src/commands/share.ts
|
|
27344
|
+
import { CLI_NAME as CLI_NAME25 } from "@tinycloud/operations/cli-name";
|
|
27345
|
+
|
|
27319
27346
|
// ../share-sdk/dist/index.js
|
|
27320
27347
|
init_sha2();
|
|
27321
27348
|
init_ed25519();
|
|
@@ -35795,12 +35822,12 @@ function shareCliError(error, operation = "publish") {
|
|
|
35795
35822
|
const profileName2 = "profileName" in failure ? failure.profileName : void 0;
|
|
35796
35823
|
const localKey = "localKey" in failure && failure.localKey === true;
|
|
35797
35824
|
const profileHint = profileName2 === void 0 ? "" : `--profile ${profileName2} `;
|
|
35798
|
-
const loginHint = localKey ?
|
|
35825
|
+
const loginHint = localKey ? `\`${CLI_NAME25} ${profileHint}auth login --method local\`` : `\`${CLI_NAME25} ${profileHint}auth login --device --manifest builtin:share-publishing\` (or \`${CLI_NAME25} ${profileHint}enable share\`)`;
|
|
35799
35826
|
if (failure.kind === "caveated-session") {
|
|
35800
35827
|
const holder = profileName2 === void 0 ? "this session" : `profile ${profileName2}'s session`;
|
|
35801
35828
|
return new CLIError(
|
|
35802
35829
|
"PERMISSION_DENIED",
|
|
35803
|
-
`${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):
|
|
35830
|
+
`${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_NAME25} init --name publisher --key-only && ${CLI_NAME25} --profile publisher enable share\``,
|
|
35804
35831
|
5
|
|
35805
35832
|
);
|
|
35806
35833
|
}
|
|
@@ -36161,6 +36188,7 @@ init_constants();
|
|
|
36161
36188
|
init_sdk();
|
|
36162
36189
|
init_host();
|
|
36163
36190
|
init_theme();
|
|
36191
|
+
import { CLI_NAME as CLI_NAME26 } from "@tinycloud/operations/cli-name";
|
|
36164
36192
|
import { randomBytes as randomBytes8 } from "crypto";
|
|
36165
36193
|
import { mkdir as mkdir5, writeFile as writeFile4 } from "fs/promises";
|
|
36166
36194
|
import { dirname as dirname6 } from "path";
|
|
@@ -36212,10 +36240,10 @@ function registerSpaceCommand(program) {
|
|
|
36212
36240
|
|
|
36213
36241
|
A delegate cannot host a space \u2014 only its owner (root authority) can. This
|
|
36214
36242
|
emits a tinycloud.host.request artifact naming the space and its owner so you
|
|
36215
|
-
can hand it to the owner; they run
|
|
36243
|
+
can hand it to the owner; they run \`${CLI_NAME26} space host <name>\` and confirm.
|
|
36216
36244
|
|
|
36217
36245
|
If you ARE the owner of the resolved space, this refuses and tells you to host
|
|
36218
|
-
it directly with
|
|
36246
|
+
it directly with \`${CLI_NAME26} space host <name>\` (no request needed).
|
|
36219
36247
|
`).action(async (name, options, cmd) => {
|
|
36220
36248
|
try {
|
|
36221
36249
|
const globalOpts = cmd.optsWithGlobals();
|
|
@@ -36226,7 +36254,7 @@ it directly with \`tc space host <name>\` (no request needed).
|
|
|
36226
36254
|
if (await isRootAuthority(spaceId, ctx.profile)) {
|
|
36227
36255
|
throw new CLIError(
|
|
36228
36256
|
"ALREADY_ROOT_AUTHORITY",
|
|
36229
|
-
`You are the owner of ${spaceId}. Host it directly:
|
|
36257
|
+
`You are the owner of ${spaceId}. Host it directly: ${CLI_NAME26} space host ${spaceName}`,
|
|
36230
36258
|
ExitCode.USAGE_ERROR
|
|
36231
36259
|
);
|
|
36232
36260
|
}
|
|
@@ -36312,6 +36340,7 @@ init_sdk();
|
|
|
36312
36340
|
init_space();
|
|
36313
36341
|
init_host();
|
|
36314
36342
|
init_theme();
|
|
36343
|
+
import { CLI_NAME as CLI_NAME27 } from "@tinycloud/operations/cli-name";
|
|
36315
36344
|
import { writeFile as writeFile5 } from "fs/promises";
|
|
36316
36345
|
import { resolve as resolve4 } from "path";
|
|
36317
36346
|
async function dbHandle(node, dbName, spaceInput, profileName2) {
|
|
@@ -36335,12 +36364,12 @@ database for simple apps, or pass --db to target a named database. Pass
|
|
|
36335
36364
|
--space to target a non-primary space (e.g. the manifest "applications" space).
|
|
36336
36365
|
|
|
36337
36366
|
Common workflows:
|
|
36338
|
-
$
|
|
36339
|
-
$
|
|
36340
|
-
$
|
|
36341
|
-
$
|
|
36342
|
-
$
|
|
36343
|
-
$
|
|
36367
|
+
$ ${CLI_NAME27} sql execute "CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY, body TEXT)"
|
|
36368
|
+
$ ${CLI_NAME27} sql execute "INSERT INTO notes (body) VALUES (?)" --params '["ship docs"]'
|
|
36369
|
+
$ ${CLI_NAME27} sql query "SELECT id, body FROM notes ORDER BY id"
|
|
36370
|
+
$ ${CLI_NAME27} sql query "SELECT * FROM events WHERE type = ?" --db analytics --params '["signup"]'
|
|
36371
|
+
$ ${CLI_NAME27} sql query "SELECT count(*) FROM conversation" --space applications --db xyz.tinycloud.listen/conversations
|
|
36372
|
+
$ ${CLI_NAME27} sql export --db analytics --output analytics.db
|
|
36344
36373
|
|
|
36345
36374
|
Commands:
|
|
36346
36375
|
query Read rows with SELECT statements
|
|
@@ -36357,10 +36386,10 @@ Tips:
|
|
|
36357
36386
|
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", `
|
|
36358
36387
|
|
|
36359
36388
|
Examples:
|
|
36360
|
-
$
|
|
36361
|
-
$
|
|
36362
|
-
$
|
|
36363
|
-
$
|
|
36389
|
+
$ ${CLI_NAME27} sql query "SELECT * FROM notes ORDER BY id"
|
|
36390
|
+
$ ${CLI_NAME27} sql query "SELECT * FROM notes WHERE id = ?" --params '[42]'
|
|
36391
|
+
$ ${CLI_NAME27} sql query "SELECT count(*) AS total FROM events" --db analytics --json
|
|
36392
|
+
$ ${CLI_NAME27} sql query "SELECT count(*) FROM conversation" --space applications --db xyz.tinycloud.listen/conversations
|
|
36364
36393
|
|
|
36365
36394
|
Output:
|
|
36366
36395
|
Human output is formatted as a table. Piped output or --json returns
|
|
@@ -36401,11 +36430,11 @@ ${rowCount} row${rowCount === 1 ? "" : "s"} returned`) + "\n");
|
|
|
36401
36430
|
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", `
|
|
36402
36431
|
|
|
36403
36432
|
Examples:
|
|
36404
|
-
$
|
|
36405
|
-
$
|
|
36406
|
-
$
|
|
36407
|
-
$
|
|
36408
|
-
$
|
|
36433
|
+
$ ${CLI_NAME27} sql execute "CREATE TABLE IF NOT EXISTS notes (id INTEGER PRIMARY KEY, body TEXT)"
|
|
36434
|
+
$ ${CLI_NAME27} sql execute "INSERT INTO notes (body) VALUES (?)" --params '["first note"]'
|
|
36435
|
+
$ ${CLI_NAME27} sql execute "UPDATE notes SET body = ? WHERE id = ?" --params '["edited", 1]'
|
|
36436
|
+
$ ${CLI_NAME27} sql execute "DROP TABLE old_notes" --db archive
|
|
36437
|
+
$ ${CLI_NAME27} sql execute "DELETE FROM conversation WHERE id = ?" --space applications --db xyz.tinycloud.listen/conversations --params '["abc"]'
|
|
36409
36438
|
|
|
36410
36439
|
Output:
|
|
36411
36440
|
Returns JSON with the changed row count and last inserted row id when available.
|
|
@@ -36434,9 +36463,9 @@ Output:
|
|
|
36434
36463
|
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", `
|
|
36435
36464
|
|
|
36436
36465
|
Examples:
|
|
36437
|
-
$
|
|
36438
|
-
$
|
|
36439
|
-
$
|
|
36466
|
+
$ ${CLI_NAME27} sql export
|
|
36467
|
+
$ ${CLI_NAME27} sql export --db analytics --output analytics.db
|
|
36468
|
+
$ ${CLI_NAME27} sql export --space applications --db xyz.tinycloud.listen/conversations --output listen.db
|
|
36440
36469
|
|
|
36441
36470
|
Output:
|
|
36442
36471
|
Writes the database file locally and returns JSON with the path and size.
|
|
@@ -36469,19 +36498,19 @@ Output:
|
|
|
36469
36498
|
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", `
|
|
36470
36499
|
|
|
36471
36500
|
Examples:
|
|
36472
|
-
$
|
|
36501
|
+
$ ${CLI_NAME27} sql copy --from-db com.tinycloud.conversation-sync/conversations \\
|
|
36473
36502
|
--to-db xyz.tinycloud.listen/conversations \\
|
|
36474
36503
|
--space applications --dry-run
|
|
36475
|
-
$
|
|
36504
|
+
$ ${CLI_NAME27} sql copy --from-space applications --from-db com.foo/data \\
|
|
36476
36505
|
--to-space applications --to-db com.bar/data \\
|
|
36477
36506
|
--table conversation --table participant
|
|
36478
36507
|
|
|
36479
36508
|
Notes:
|
|
36480
36509
|
- Refuses to run when (resolved space, db) is identical for source and destination.
|
|
36481
|
-
- Does NOT create destination tables. Run the target app once (or use
|
|
36510
|
+
- Does NOT create destination tables. Run the target app once (or use \`${CLI_NAME27} sql execute\`)
|
|
36482
36511
|
to materialize the schema before copying.
|
|
36483
36512
|
- One row at a time; suitable for small/medium datasets. Large copies should
|
|
36484
|
-
use
|
|
36513
|
+
use \`${CLI_NAME27} sql export\` + bulk import.
|
|
36485
36514
|
- Authorization: the active session/delegation must cover sql/read on source
|
|
36486
36515
|
AND sql/write on destination. Otherwise the relevant operation will fail.
|
|
36487
36516
|
`).action(async (options, cmd) => {
|
|
@@ -36581,6 +36610,7 @@ init_errors();
|
|
|
36581
36610
|
init_formatter();
|
|
36582
36611
|
init_theme();
|
|
36583
36612
|
init_permissions();
|
|
36613
|
+
import { CLI_NAME as CLI_NAME28 } from "@tinycloud/operations/cli-name";
|
|
36584
36614
|
import {
|
|
36585
36615
|
NodeWasmBindings as NodeWasmBindings2
|
|
36586
36616
|
} from "@tinycloud/node-sdk";
|
|
@@ -36854,7 +36884,7 @@ function formatStatus(summary) {
|
|
|
36854
36884
|
lines.push(`Default profile: ${theme.value(summary.defaultProfile)}`);
|
|
36855
36885
|
lines.push("");
|
|
36856
36886
|
if (summary.profiles.length === 0) {
|
|
36857
|
-
lines.push(theme.muted(
|
|
36887
|
+
lines.push(theme.muted(`No profiles configured. Run: ${CLI_NAME28} init`));
|
|
36858
36888
|
return `${lines.join("\n")}
|
|
36859
36889
|
`;
|
|
36860
36890
|
}
|