@tinycloud/cli 1.5.0-beta.32 → 1.5.0-beta.34
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +5 -11
- package/dist/index.js.map +1 -1
- package/dist/legacy-entry.js +150 -149
- package/dist/legacy-entry.js.map +1 -1
- package/package.json +1 -1
- package/skills/tinycloud-cli/AUTH.md +2 -0
- package/skills/tinycloud-cli/REFERENCE.md +2 -0
package/dist/legacy-entry.js
CHANGED
|
@@ -10157,7 +10157,7 @@ var init_profiles = __esm({
|
|
|
10157
10157
|
if (!profile) {
|
|
10158
10158
|
throw new CLIError(
|
|
10159
10159
|
"PROFILE_NOT_FOUND",
|
|
10160
|
-
`Profile "${name}" does not exist. Create it with \`${CLI_NAME9} init --name ${name}\`.`
|
|
10160
|
+
`Profile "${name}" does not exist. Create it with \`${CLI_NAME9} init --key-only --name ${name}\`.`
|
|
10161
10161
|
);
|
|
10162
10162
|
}
|
|
10163
10163
|
return profile;
|
|
@@ -17967,7 +17967,7 @@ function formatSpace(space) {
|
|
|
17967
17967
|
init_profile_gate();
|
|
17968
17968
|
init_dist();
|
|
17969
17969
|
init_profiles();
|
|
17970
|
-
import { CLI_NAME as
|
|
17970
|
+
import { CLI_NAME as CLI_NAME19 } from "@tinycloud/operations/cli-name";
|
|
17971
17971
|
import { get as httpGet } from "http";
|
|
17972
17972
|
import { get as httpsGet } from "https";
|
|
17973
17973
|
import { spawn } from "child_process";
|
|
@@ -35741,6 +35741,81 @@ function registerAuthGrantsCommand(auth, options = {}) {
|
|
|
35741
35741
|
});
|
|
35742
35742
|
}
|
|
35743
35743
|
|
|
35744
|
+
// src/commands/init.ts
|
|
35745
|
+
init_profiles();
|
|
35746
|
+
init_formatter();
|
|
35747
|
+
init_errors();
|
|
35748
|
+
init_constants();
|
|
35749
|
+
import { CLI_NAME as CLI_NAME18 } from "@tinycloud/operations/cli-name";
|
|
35750
|
+
async function createKeyOnlyProfile(profileName2, host, defaultSpace) {
|
|
35751
|
+
await ProfileManager.ensureConfigDir();
|
|
35752
|
+
const { jwk, did } = await generateKey2();
|
|
35753
|
+
await ProfileManager.setKey(profileName2, jwk);
|
|
35754
|
+
await ProfileManager.setProfile(profileName2, {
|
|
35755
|
+
name: profileName2,
|
|
35756
|
+
host,
|
|
35757
|
+
chainId: DEFAULT_CHAIN_ID,
|
|
35758
|
+
spaceName: "default",
|
|
35759
|
+
did,
|
|
35760
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
35761
|
+
...defaultSpace ? { defaultSpace } : {}
|
|
35762
|
+
});
|
|
35763
|
+
const config = await ProfileManager.getConfig();
|
|
35764
|
+
if (profileName2 === "default" || !await ProfileManager.profileExists(config.defaultProfile)) {
|
|
35765
|
+
await ProfileManager.setConfig({ ...config, defaultProfile: profileName2 });
|
|
35766
|
+
}
|
|
35767
|
+
return { did };
|
|
35768
|
+
}
|
|
35769
|
+
function registerInitCommand(program) {
|
|
35770
|
+
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) => {
|
|
35771
|
+
try {
|
|
35772
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
35773
|
+
const profileName2 = options.name;
|
|
35774
|
+
const host = options.host ?? globalOpts.host ?? DEFAULT_HOST;
|
|
35775
|
+
const defaultSpace = options.defaultSpace;
|
|
35776
|
+
if (defaultSpace !== void 0 && !/^[A-Za-z0-9_-]+$/.test(defaultSpace)) {
|
|
35777
|
+
throw new CLIError(
|
|
35778
|
+
"INVALID_SPACE",
|
|
35779
|
+
`Invalid --default-space "${defaultSpace}". Use a short name ([A-Za-z0-9_-]).`,
|
|
35780
|
+
ExitCode.USAGE_ERROR
|
|
35781
|
+
);
|
|
35782
|
+
}
|
|
35783
|
+
if (await ProfileManager.profileExists(profileName2)) {
|
|
35784
|
+
throw new CLIError(
|
|
35785
|
+
"PROFILE_EXISTS",
|
|
35786
|
+
`Profile "${profileName2}" already exists. Use \`${CLI_NAME18} profile delete ${profileName2}\` first or choose a different name.`,
|
|
35787
|
+
ExitCode.ERROR
|
|
35788
|
+
);
|
|
35789
|
+
}
|
|
35790
|
+
const { did } = await withSpinner("Generating key...", () => createKeyOnlyProfile(profileName2, host, defaultSpace));
|
|
35791
|
+
if (options.keyOnly) {
|
|
35792
|
+
outputJson({
|
|
35793
|
+
profile: profileName2,
|
|
35794
|
+
did,
|
|
35795
|
+
host,
|
|
35796
|
+
authenticated: false
|
|
35797
|
+
});
|
|
35798
|
+
return;
|
|
35799
|
+
}
|
|
35800
|
+
const { delegationData } = await refreshOpenKeySession(profileName2, host, {
|
|
35801
|
+
paste: options.paste,
|
|
35802
|
+
noPopup: options.popup === false,
|
|
35803
|
+
persistHost: true
|
|
35804
|
+
});
|
|
35805
|
+
await ensureSpaceSetup({ profile: profileName2, host }, delegationData, delegationData.permissions);
|
|
35806
|
+
outputJson({
|
|
35807
|
+
profile: profileName2,
|
|
35808
|
+
did,
|
|
35809
|
+
host,
|
|
35810
|
+
spaceId: delegationData.spaceId,
|
|
35811
|
+
authenticated: true
|
|
35812
|
+
});
|
|
35813
|
+
} catch (error) {
|
|
35814
|
+
return handleError(error);
|
|
35815
|
+
}
|
|
35816
|
+
});
|
|
35817
|
+
}
|
|
35818
|
+
|
|
35744
35819
|
// src/commands/auth.ts
|
|
35745
35820
|
init_sdk();
|
|
35746
35821
|
init_session_expired();
|
|
@@ -36020,7 +36095,7 @@ async function prepareProfileRemoteLogout(ctx, expectedSessionCid, discardLocalC
|
|
|
36020
36095
|
"REVOCATION_AUTHORITY_UNAVAILABLE",
|
|
36021
36096
|
"OpenKey owner CID revocation requires a verified signed revoke-control grant or wallet proof. No CID was revoked; session, key and replica files remain for retry, while local replica reads stay denied.",
|
|
36022
36097
|
ExitCode.AUTH_REQUIRED,
|
|
36023
|
-
{ hint: `This sign-in can't be revoked from the CLI yet. Revoke it at https://account.tinycloud.xyz/delegations. To sign out on this computer only, run \`${
|
|
36098
|
+
{ hint: `This sign-in can't be revoked from the CLI yet. Revoke it at https://account.tinycloud.xyz/delegations. To sign out on this computer only, run \`${CLI_NAME19} auth logout\`.` }
|
|
36024
36099
|
);
|
|
36025
36100
|
}
|
|
36026
36101
|
const signerDid = addressToDID(
|
|
@@ -36064,7 +36139,7 @@ async function revokeForLogout(ctx, discardLocalChanges) {
|
|
|
36064
36139
|
"REVOCATION_FAILED",
|
|
36065
36140
|
`Revocation failed for ${cid}: ${result.error.message}. Session, key, and replica files are retained for retry; local reads stay denied.`,
|
|
36066
36141
|
ExitCode.ERROR,
|
|
36067
|
-
{ cid, hint: `Retry \`${
|
|
36142
|
+
{ cid, hint: `Retry \`${CLI_NAME19} auth logout --revoke\` when the node is available.` }
|
|
36068
36143
|
);
|
|
36069
36144
|
}
|
|
36070
36145
|
if (result.data.cid !== cid || result.data.revoked !== true) {
|
|
@@ -36083,7 +36158,7 @@ async function revokeForLogout(ctx, discardLocalChanges) {
|
|
|
36083
36158
|
"REVOCATION_FAILED",
|
|
36084
36159
|
`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.`,
|
|
36085
36160
|
ExitCode.ERROR,
|
|
36086
|
-
{ hint: `Retry \`${
|
|
36161
|
+
{ hint: `Retry \`${CLI_NAME19} auth logout --revoke\` when online authority is available.` }
|
|
36087
36162
|
);
|
|
36088
36163
|
}
|
|
36089
36164
|
}
|
|
@@ -36282,7 +36357,7 @@ async function finishProfileLogout(ctx, options = {}) {
|
|
|
36282
36357
|
function registerAuthCommand(program, options) {
|
|
36283
36358
|
const auth = program.command("auth").description("Authentication management");
|
|
36284
36359
|
registerAuthGrantsCommand(auth, { openKeyAcquisition: options?.openKeyAcquisition });
|
|
36285
|
-
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; OpenKey return codes expire after 5 minutes").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 \`${
|
|
36360
|
+
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; OpenKey return codes expire after 5 minutes").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_NAME19} 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("--force", "Replica-enabled OpenKey login: replace the stored session key even when recorded shares could not be checked or hold unexpired shares that need the current key").option("--keys <folder>", "Also let this sign-in create and use encryption keys in this folder (for example `qa`). The node must support named keys. With OpenKey, the first time on a profile also needs `--owner`.").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) => {
|
|
36286
36361
|
try {
|
|
36287
36362
|
if (options2.device && options2.paste) {
|
|
36288
36363
|
throw new CLIError("INVALID_ARGUMENT", "--device and --paste are mutually exclusive.", ExitCode.USAGE_ERROR);
|
|
@@ -36380,6 +36455,13 @@ function registerAuthCommand(program, options) {
|
|
|
36380
36455
|
await persistReplicationLogin(ctx.profile, replicationOptions);
|
|
36381
36456
|
if (replicationOptions.allowSecrets) writeReplicationSecretsWarning();
|
|
36382
36457
|
} else {
|
|
36458
|
+
const created = await ProfileManager.withLock(ctx.profile, async () => {
|
|
36459
|
+
if (await ProfileManager.profileExists(ctx.profile)) return false;
|
|
36460
|
+
await createKeyOnlyProfile(ctx.profile, globalOpts.host ?? DEFAULT_HOST);
|
|
36461
|
+
return true;
|
|
36462
|
+
});
|
|
36463
|
+
if (created) process.stderr.write(`Created profile "${ctx.profile}"
|
|
36464
|
+
`);
|
|
36383
36465
|
const preparedCommitted = await handleOpenKeyAuth(ctx.profile, ctx.host, {
|
|
36384
36466
|
paste: options2.paste,
|
|
36385
36467
|
noPopup: options2.popup === false,
|
|
@@ -36440,7 +36522,7 @@ function registerAuthCommand(program, options) {
|
|
|
36440
36522
|
authenticated: false,
|
|
36441
36523
|
replicasRemoved,
|
|
36442
36524
|
replicasKept: options2.keepReplicas === true,
|
|
36443
|
-
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 \`${
|
|
36525
|
+
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_NAME19} delegation revoke <cid>\` to end access now.`,
|
|
36444
36526
|
...online === void 0 ? {} : {
|
|
36445
36527
|
revokedCids: online.plan.cids,
|
|
36446
36528
|
revocationExcluded: online.plan.excluded
|
|
@@ -36585,7 +36667,7 @@ ${appsAgentScopeNotice(preset.mode, preset.appIds)}
|
|
|
36585
36667
|
if (profile.authMethod === "openkey" || options2.device) {
|
|
36586
36668
|
const key = await ProfileManager.getKey(ctx.profile);
|
|
36587
36669
|
if (!key) {
|
|
36588
|
-
throw new CLIError("NO_KEY", `No key found for profile "${ctx.profile}". Run \`${
|
|
36670
|
+
throw new CLIError("NO_KEY", `No key found for profile "${ctx.profile}". Run \`${CLI_NAME19} --profile ${ctx.profile} auth rotate\` to create a new key and sign in.`, ExitCode.AUTH_REQUIRED);
|
|
36589
36671
|
}
|
|
36590
36672
|
const openkeyHost = resolveOpenKeyHost(profile);
|
|
36591
36673
|
const grants = [];
|
|
@@ -36605,7 +36687,7 @@ ${appsAgentScopeNotice(preset.mode, preset.appIds)}
|
|
|
36605
36687
|
if (notices) process.stderr.write(`${notices.prompts[index]}
|
|
36606
36688
|
`);
|
|
36607
36689
|
const reason = permissionGrantReason(
|
|
36608
|
-
`Grant requested TinyCloud permissions from \`${
|
|
36690
|
+
`Grant requested TinyCloud permissions from \`${CLI_NAME19} auth request --grant\`.`,
|
|
36609
36691
|
group
|
|
36610
36692
|
);
|
|
36611
36693
|
const request = grantRequestPermissions(group, profile.spaceId ?? profile.spaceName);
|
|
@@ -36717,7 +36799,7 @@ ${appsAgentScopeNotice(preset.mode, preset.appIds)}
|
|
|
36717
36799
|
kind: parsed.kind,
|
|
36718
36800
|
requestId: parsed.requestId,
|
|
36719
36801
|
requested: parsed.requested,
|
|
36720
|
-
next: `${
|
|
36802
|
+
next: `${CLI_NAME19} auth retry ${parsed.requestId}`
|
|
36721
36803
|
});
|
|
36722
36804
|
return;
|
|
36723
36805
|
}
|
|
@@ -37338,7 +37420,7 @@ async function acquireOpenKeyApproval(params) {
|
|
|
37338
37420
|
if (!key) {
|
|
37339
37421
|
throw new CLIError(
|
|
37340
37422
|
"NO_KEY",
|
|
37341
|
-
`No key found for profile "${params.ctx.profile}". Run \`${
|
|
37423
|
+
`No key found for profile "${params.ctx.profile}". Run \`${CLI_NAME19} --profile ${params.ctx.profile} auth rotate\` to create a new key and sign in.`,
|
|
37342
37424
|
ExitCode.AUTH_REQUIRED
|
|
37343
37425
|
);
|
|
37344
37426
|
}
|
|
@@ -37414,7 +37496,7 @@ async function ensureDelegationAuthority(params) {
|
|
|
37414
37496
|
if (!key) {
|
|
37415
37497
|
throw new CLIError(
|
|
37416
37498
|
"NO_KEY",
|
|
37417
|
-
`No key found for profile "${params.ctx.profile}". Run \`${
|
|
37499
|
+
`No key found for profile "${params.ctx.profile}". Run \`${CLI_NAME19} --profile ${params.ctx.profile} auth rotate\` to create a new key and sign in.`,
|
|
37418
37500
|
ExitCode.AUTH_REQUIRED
|
|
37419
37501
|
);
|
|
37420
37502
|
}
|
|
@@ -37671,7 +37753,7 @@ async function rotateAuthKey(profileName2, host, options = {}) {
|
|
|
37671
37753
|
if (!profile.privateKey) {
|
|
37672
37754
|
throw new CLIError(
|
|
37673
37755
|
"LOCAL_OWNER_KEY_REQUIRED",
|
|
37674
|
-
`Profile "${profileName2}" does not have a local owner private key. Run \`${
|
|
37756
|
+
`Profile "${profileName2}" does not have a local owner private key. Run \`${CLI_NAME19} auth login --method local\` first.`,
|
|
37675
37757
|
ExitCode.AUTH_REQUIRED
|
|
37676
37758
|
);
|
|
37677
37759
|
}
|
|
@@ -38036,9 +38118,9 @@ async function refreshPreparedOpenKeySession(params) {
|
|
|
38036
38118
|
}
|
|
38037
38119
|
var KEYS_APPROVAL_NOTE = (folder) => `On the OpenKey page, the row that mentions tinycloud.encryption lets this profile create and use keys in the folder "${folder}/". Keep every row ticked. To sign in without keys, untick that whole row and nothing else; any other change makes OpenKey refuse the sign-in.
|
|
38038
38120
|
`;
|
|
38039
|
-
var keysNotGrantedAfterLogin = (profileName2) => `You're signed in, but without named keys: the tinycloud.encryption permission wasn't approved. To add them, sign in again with \`${
|
|
38121
|
+
var keysNotGrantedAfterLogin = (profileName2) => `You're signed in, but without named keys: the tinycloud.encryption permission wasn't approved. To add them, sign in again with \`${CLI_NAME19} --profile ${profileName2} auth login --keys <folder>\` and leave the row that mentions tinycloud.encryption ticked.
|
|
38040
38122
|
`;
|
|
38041
|
-
var KEYS_FOLDER_NOT_READY = `You're signed in, but your encryption keys aren't set up yet. Try \`${
|
|
38123
|
+
var KEYS_FOLDER_NOT_READY = `You're signed in, but your encryption keys aren't set up yet. Try \`${CLI_NAME19} keys ensure <folder>/<name>\` again in a minute.
|
|
38042
38124
|
`;
|
|
38043
38125
|
async function readyNamedKeysNetwork(node) {
|
|
38044
38126
|
try {
|
|
@@ -38250,7 +38332,7 @@ async function refreshOpenKeySession(profileName2, host, options = {}) {
|
|
|
38250
38332
|
}
|
|
38251
38333
|
|
|
38252
38334
|
// src/commands/completion.ts
|
|
38253
|
-
import { CLI_NAME as
|
|
38335
|
+
import { CLI_NAME as CLI_NAME20 } from "@tinycloud/operations/cli-name";
|
|
38254
38336
|
function registerCompletionCommand(program) {
|
|
38255
38337
|
const completion = program.command("completion").description("Generate shell completions");
|
|
38256
38338
|
completion.command("bash").description("Output bash completions").action(() => {
|
|
@@ -38267,7 +38349,7 @@ function registerCompletionCommand(program) {
|
|
|
38267
38349
|
});
|
|
38268
38350
|
}
|
|
38269
38351
|
function generateBashCompletion() {
|
|
38270
|
-
return `# ${
|
|
38352
|
+
return `# ${CLI_NAME20} bash completion
|
|
38271
38353
|
_tc_completions() {
|
|
38272
38354
|
local cur prev commands subcommands
|
|
38273
38355
|
COMPREPLY=()
|
|
@@ -38292,11 +38374,11 @@ _tc_completions() {
|
|
|
38292
38374
|
COMPREPLY=( $(compgen -W "\${subcommands}" -- "\${cur}") )
|
|
38293
38375
|
fi
|
|
38294
38376
|
}
|
|
38295
|
-
complete -F _tc_completions ${
|
|
38377
|
+
complete -F _tc_completions ${CLI_NAME20}
|
|
38296
38378
|
`;
|
|
38297
38379
|
}
|
|
38298
38380
|
function generateZshCompletion() {
|
|
38299
|
-
return `#compdef ${
|
|
38381
|
+
return `#compdef ${CLI_NAME20}
|
|
38300
38382
|
|
|
38301
38383
|
_tc() {
|
|
38302
38384
|
local -a commands
|
|
@@ -38347,50 +38429,50 @@ _tc
|
|
|
38347
38429
|
`;
|
|
38348
38430
|
}
|
|
38349
38431
|
function generateFishCompletion() {
|
|
38350
|
-
return `# ${
|
|
38432
|
+
return `# ${CLI_NAME20} fish completion
|
|
38351
38433
|
set -l commands init auth kv space delegation share node profile completion
|
|
38352
38434
|
|
|
38353
38435
|
# Disable file completion by default
|
|
38354
|
-
complete -c ${
|
|
38436
|
+
complete -c ${CLI_NAME20} -f
|
|
38355
38437
|
|
|
38356
38438
|
# Top-level commands
|
|
38357
|
-
complete -c ${
|
|
38358
|
-
complete -c ${
|
|
38359
|
-
complete -c ${
|
|
38360
|
-
complete -c ${
|
|
38361
|
-
complete -c ${
|
|
38362
|
-
complete -c ${
|
|
38363
|
-
complete -c ${
|
|
38364
|
-
complete -c ${
|
|
38365
|
-
complete -c ${
|
|
38439
|
+
complete -c ${CLI_NAME20} -n "not __fish_seen_subcommand_from $commands" -a init -d "Initialize a new TinyCloud profile"
|
|
38440
|
+
complete -c ${CLI_NAME20} -n "not __fish_seen_subcommand_from $commands" -a auth -d "Authentication management"
|
|
38441
|
+
complete -c ${CLI_NAME20} -n "not __fish_seen_subcommand_from $commands" -a kv -d "Key-value store operations"
|
|
38442
|
+
complete -c ${CLI_NAME20} -n "not __fish_seen_subcommand_from $commands" -a space -d "Space management"
|
|
38443
|
+
complete -c ${CLI_NAME20} -n "not __fish_seen_subcommand_from $commands" -a delegation -d "Manage delegations"
|
|
38444
|
+
complete -c ${CLI_NAME20} -n "not __fish_seen_subcommand_from $commands" -a share -d "Share data with others"
|
|
38445
|
+
complete -c ${CLI_NAME20} -n "not __fish_seen_subcommand_from $commands" -a node -d "Node health and info"
|
|
38446
|
+
complete -c ${CLI_NAME20} -n "not __fish_seen_subcommand_from $commands" -a profile -d "Profile management"
|
|
38447
|
+
complete -c ${CLI_NAME20} -n "not __fish_seen_subcommand_from $commands" -a completion -d "Generate shell completions"
|
|
38366
38448
|
|
|
38367
38449
|
# Subcommands
|
|
38368
|
-
complete -c ${
|
|
38369
|
-
complete -c ${
|
|
38370
|
-
complete -c ${
|
|
38371
|
-
complete -c ${
|
|
38372
|
-
complete -c ${
|
|
38373
|
-
complete -c ${
|
|
38374
|
-
complete -c ${
|
|
38375
|
-
complete -c ${
|
|
38450
|
+
complete -c ${CLI_NAME20} -n "__fish_seen_subcommand_from auth" -a "login logout rotate status whoami"
|
|
38451
|
+
complete -c ${CLI_NAME20} -n "__fish_seen_subcommand_from kv" -a "get put delete list head"
|
|
38452
|
+
complete -c ${CLI_NAME20} -n "__fish_seen_subcommand_from space" -a "list create info switch"
|
|
38453
|
+
complete -c ${CLI_NAME20} -n "__fish_seen_subcommand_from delegation" -a "create list info revoke"
|
|
38454
|
+
complete -c ${CLI_NAME20} -n "__fish_seen_subcommand_from share" -a "create receive list revoke"
|
|
38455
|
+
complete -c ${CLI_NAME20} -n "__fish_seen_subcommand_from node" -a "health version status"
|
|
38456
|
+
complete -c ${CLI_NAME20} -n "__fish_seen_subcommand_from profile" -a "list create show switch delete"
|
|
38457
|
+
complete -c ${CLI_NAME20} -n "__fish_seen_subcommand_from completion" -a "bash zsh fish"
|
|
38376
38458
|
|
|
38377
38459
|
# Global options
|
|
38378
|
-
complete -c ${
|
|
38379
|
-
complete -c ${
|
|
38380
|
-
complete -c ${
|
|
38381
|
-
complete -c ${
|
|
38382
|
-
complete -c ${
|
|
38383
|
-
complete -c ${
|
|
38384
|
-
complete -c ${
|
|
38385
|
-
complete -c ${
|
|
38460
|
+
complete -c ${CLI_NAME20} -l profile -s p -d "Profile to use"
|
|
38461
|
+
complete -c ${CLI_NAME20} -l host -s H -d "TinyCloud node URL"
|
|
38462
|
+
complete -c ${CLI_NAME20} -l verbose -s v -d "Enable verbose output"
|
|
38463
|
+
complete -c ${CLI_NAME20} -l no-cache -d "Disable caching"
|
|
38464
|
+
complete -c ${CLI_NAME20} -l quiet -s q -d "Suppress non-essential output"
|
|
38465
|
+
complete -c ${CLI_NAME20} -l replication -d "Enable read-through replication"
|
|
38466
|
+
complete -c ${CLI_NAME20} -l no-replication -d "Disable replication"
|
|
38467
|
+
complete -c ${CLI_NAME20} -l replication-debug -d "Write replication diagnostics to stderr"
|
|
38386
38468
|
`;
|
|
38387
38469
|
}
|
|
38388
38470
|
|
|
38389
38471
|
// src/commands/courier.ts
|
|
38390
|
-
import { CLI_NAME as
|
|
38391
|
-
var TC_OPTIONS_BEFORE_COURIER = `${
|
|
38472
|
+
import { CLI_NAME as CLI_NAME21 } from "@tinycloud/operations/cli-name";
|
|
38473
|
+
var TC_OPTIONS_BEFORE_COURIER = `${CLI_NAME21} courier takes no ${CLI_NAME21} options and does not use ${CLI_NAME21} profiles; Courier keeps its own profile in $COURIER_HOME (default ~/.courier). Put flags after "courier", e.g. ${CLI_NAME21} courier init --host <url>.`;
|
|
38392
38474
|
function registerCourierCommand(program) {
|
|
38393
|
-
const courier = program.command("courier").description(`Agent-to-agent threads over TinyCloud; run \`${
|
|
38475
|
+
const courier = program.command("courier").description(`Agent-to-agent threads over TinyCloud; run \`${CLI_NAME21} courier --help\` (beta)`).argument("[args...]").allowUnknownOption().helpOption(false);
|
|
38394
38476
|
courier.action(() => courier.error(TC_OPTIONS_BEFORE_COURIER, { exitCode: 2, code: "tc.courier.options" }));
|
|
38395
38477
|
}
|
|
38396
38478
|
|
|
@@ -38435,7 +38517,7 @@ init_formatter();
|
|
|
38435
38517
|
init_errors();
|
|
38436
38518
|
init_constants();
|
|
38437
38519
|
init_sdk();
|
|
38438
|
-
import { CLI_NAME as
|
|
38520
|
+
import { CLI_NAME as CLI_NAME22 } from "@tinycloud/operations/cli-name";
|
|
38439
38521
|
import { PermissionNotInManifestError } from "@tinycloud/node-sdk";
|
|
38440
38522
|
async function queryDelegations(node, options, until) {
|
|
38441
38523
|
const found = [];
|
|
@@ -38446,7 +38528,7 @@ async function queryDelegations(node, options, until) {
|
|
|
38446
38528
|
if (page.error.code === "PERMISSION_DENIED") {
|
|
38447
38529
|
throw new CLIError(
|
|
38448
38530
|
"PERMISSION_DENIED",
|
|
38449
|
-
`This session cannot read delegations: it lacks tinycloud.delegation/list. Run \`${
|
|
38531
|
+
`This session cannot read delegations: it lacks tinycloud.delegation/list. Run \`${CLI_NAME22} auth login\` again to grant it.`,
|
|
38450
38532
|
ExitCode.PERMISSION_DENIED
|
|
38451
38533
|
);
|
|
38452
38534
|
}
|
|
@@ -38509,7 +38591,7 @@ async function revokeIssuedDelegation(node, ctx, cid) {
|
|
|
38509
38591
|
ExitCode.PERMISSION_DENIED,
|
|
38510
38592
|
{
|
|
38511
38593
|
status: result.error.meta?.status,
|
|
38512
|
-
hint: `A profile can revoke only the delegations its own key issued. See them with \`${
|
|
38594
|
+
hint: `A profile can revoke only the delegations its own key issued. See them with \`${CLI_NAME22} --profile ${ctx.profile} delegation list --granted\`.`
|
|
38513
38595
|
}
|
|
38514
38596
|
);
|
|
38515
38597
|
}
|
|
@@ -38682,7 +38764,7 @@ init_constants();
|
|
|
38682
38764
|
init_formatter();
|
|
38683
38765
|
init_theme();
|
|
38684
38766
|
init_errors();
|
|
38685
|
-
import { CLI_NAME as
|
|
38767
|
+
import { CLI_NAME as CLI_NAME23 } from "@tinycloud/operations/cli-name";
|
|
38686
38768
|
init_session_expired();
|
|
38687
38769
|
init_types();
|
|
38688
38770
|
function registerDoctorCommand(program) {
|
|
@@ -38716,7 +38798,7 @@ function registerDoctorCommand(program) {
|
|
|
38716
38798
|
const profile = await ProfileManager.getProfile(profileName2);
|
|
38717
38799
|
keyDetail = profile.did ? `${profile.did.slice(0, 20)}...` : "key found";
|
|
38718
38800
|
} else {
|
|
38719
|
-
keyDetail = `no key \u2014 run ${
|
|
38801
|
+
keyDetail = `no key \u2014 run ${CLI_NAME23} init`;
|
|
38720
38802
|
}
|
|
38721
38803
|
} catch {
|
|
38722
38804
|
keyDetail = "error reading key";
|
|
@@ -38738,7 +38820,7 @@ function registerDoctorCommand(program) {
|
|
|
38738
38820
|
} else if (state2 === "unverified") {
|
|
38739
38821
|
sessionDetail = `not usable (no signed OpenKey proof) \u2014 ${signInAgainHint(profileName2, resolveProfilePosture(profile))}`;
|
|
38740
38822
|
} else {
|
|
38741
|
-
sessionDetail = sessionOk ? "active" : `no session \u2014 run ${
|
|
38823
|
+
sessionDetail = sessionOk ? "active" : `no session \u2014 run ${CLI_NAME23} auth login`;
|
|
38742
38824
|
}
|
|
38743
38825
|
} catch {
|
|
38744
38826
|
sessionDetail = "error reading session";
|
|
@@ -38766,7 +38848,7 @@ function registerDoctorCommand(program) {
|
|
|
38766
38848
|
try {
|
|
38767
38849
|
const profile = await ProfileManager.getProfile(profileName2);
|
|
38768
38850
|
spaceOk = Boolean(profile.spaceId);
|
|
38769
|
-
spaceDetail = spaceOk ? `${profile.spaceId.slice(0, 16)}...` : `no space \u2014 run ${
|
|
38851
|
+
spaceDetail = spaceOk ? `${profile.spaceId.slice(0, 16)}...` : `no space \u2014 run ${CLI_NAME23} space create`;
|
|
38770
38852
|
} catch {
|
|
38771
38853
|
spaceDetail = "error checking space";
|
|
38772
38854
|
}
|
|
@@ -38956,7 +39038,7 @@ ${rowCount} row${rowCount === 1 ? "" : "s"} returned`) + "\n");
|
|
|
38956
39038
|
}
|
|
38957
39039
|
|
|
38958
39040
|
// src/commands/enable.ts
|
|
38959
|
-
import { CLI_NAME as
|
|
39041
|
+
import { CLI_NAME as CLI_NAME24 } from "@tinycloud/operations/cli-name";
|
|
38960
39042
|
init_constants();
|
|
38961
39043
|
init_profiles();
|
|
38962
39044
|
init_errors();
|
|
@@ -38964,7 +39046,7 @@ init_formatter();
|
|
|
38964
39046
|
init_publishing_manifest();
|
|
38965
39047
|
function registerEnableCommand(program) {
|
|
38966
39048
|
const enable = program.command("enable").description("Enable a narrowly scoped TinyCloud service");
|
|
38967
|
-
enable.command("share").description(`Approve Share publishing scope through OpenKey device authorization (same as \`${
|
|
39049
|
+
enable.command("share").description(`Approve Share publishing scope through OpenKey device authorization (same as \`${CLI_NAME24} auth login --device --manifest builtin:share-publishing\`). Use a dedicated profile, e.g. \`${CLI_NAME24} init --name publisher --key-only && ${CLI_NAME24} --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) => {
|
|
38968
39050
|
try {
|
|
38969
39051
|
const globalOptions = command.optsWithGlobals();
|
|
38970
39052
|
const context2 = await ProfileManager.resolveContext(globalOptions, { storedSession: "unused" });
|
|
@@ -38999,7 +39081,7 @@ function registerEnableCommand(program) {
|
|
|
38999
39081
|
init_profiles();
|
|
39000
39082
|
init_constants();
|
|
39001
39083
|
init_sdk();
|
|
39002
|
-
import { CLI_NAME as
|
|
39084
|
+
import { CLI_NAME as CLI_NAME25 } from "@tinycloud/operations/cli-name";
|
|
39003
39085
|
import { operationSpaceResolver as operationSpaceResolver2 } from "@tinycloud/operations/delegation-binding";
|
|
39004
39086
|
|
|
39005
39087
|
// src/lib/knowledge-input.ts
|
|
@@ -39265,7 +39347,7 @@ function registerAppsCommand(program) {
|
|
|
39265
39347
|
"after",
|
|
39266
39348
|
`
|
|
39267
39349
|
Examples:
|
|
39268
|
-
$ ${
|
|
39350
|
+
$ ${CLI_NAME25} apps install xyz.tinycloud.sample.healthlog
|
|
39269
39351
|
`
|
|
39270
39352
|
).action(async (appIdInput, _options, cmd) => {
|
|
39271
39353
|
try {
|
|
@@ -40355,81 +40437,6 @@ slash prefix and output are explicit; source get/sync grants are separate from f
|
|
|
40355
40437
|
});
|
|
40356
40438
|
}
|
|
40357
40439
|
|
|
40358
|
-
// src/commands/init.ts
|
|
40359
|
-
init_profiles();
|
|
40360
|
-
init_formatter();
|
|
40361
|
-
init_errors();
|
|
40362
|
-
init_constants();
|
|
40363
|
-
import { CLI_NAME as CLI_NAME25 } from "@tinycloud/operations/cli-name";
|
|
40364
|
-
async function createKeyOnlyProfile(profileName2, host, defaultSpace) {
|
|
40365
|
-
await ProfileManager.ensureConfigDir();
|
|
40366
|
-
const { jwk, did } = await generateKey2();
|
|
40367
|
-
await ProfileManager.setKey(profileName2, jwk);
|
|
40368
|
-
await ProfileManager.setProfile(profileName2, {
|
|
40369
|
-
name: profileName2,
|
|
40370
|
-
host,
|
|
40371
|
-
chainId: DEFAULT_CHAIN_ID,
|
|
40372
|
-
spaceName: "default",
|
|
40373
|
-
did,
|
|
40374
|
-
createdAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
40375
|
-
...defaultSpace ? { defaultSpace } : {}
|
|
40376
|
-
});
|
|
40377
|
-
const config = await ProfileManager.getConfig();
|
|
40378
|
-
if (profileName2 === "default" || !await ProfileManager.profileExists(config.defaultProfile)) {
|
|
40379
|
-
await ProfileManager.setConfig({ ...config, defaultProfile: profileName2 });
|
|
40380
|
-
}
|
|
40381
|
-
return { did };
|
|
40382
|
-
}
|
|
40383
|
-
function registerInitCommand(program) {
|
|
40384
|
-
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) => {
|
|
40385
|
-
try {
|
|
40386
|
-
const globalOpts = cmd.optsWithGlobals();
|
|
40387
|
-
const profileName2 = options.name;
|
|
40388
|
-
const host = options.host ?? globalOpts.host ?? DEFAULT_HOST;
|
|
40389
|
-
const defaultSpace = options.defaultSpace;
|
|
40390
|
-
if (defaultSpace !== void 0 && !/^[A-Za-z0-9_-]+$/.test(defaultSpace)) {
|
|
40391
|
-
throw new CLIError(
|
|
40392
|
-
"INVALID_SPACE",
|
|
40393
|
-
`Invalid --default-space "${defaultSpace}". Use a short name ([A-Za-z0-9_-]).`,
|
|
40394
|
-
ExitCode.USAGE_ERROR
|
|
40395
|
-
);
|
|
40396
|
-
}
|
|
40397
|
-
if (await ProfileManager.profileExists(profileName2)) {
|
|
40398
|
-
throw new CLIError(
|
|
40399
|
-
"PROFILE_EXISTS",
|
|
40400
|
-
`Profile "${profileName2}" already exists. Use \`${CLI_NAME25} profile delete ${profileName2}\` first or choose a different name.`,
|
|
40401
|
-
ExitCode.ERROR
|
|
40402
|
-
);
|
|
40403
|
-
}
|
|
40404
|
-
const { did } = await withSpinner("Generating key...", () => createKeyOnlyProfile(profileName2, host, defaultSpace));
|
|
40405
|
-
if (options.keyOnly) {
|
|
40406
|
-
outputJson({
|
|
40407
|
-
profile: profileName2,
|
|
40408
|
-
did,
|
|
40409
|
-
host,
|
|
40410
|
-
authenticated: false
|
|
40411
|
-
});
|
|
40412
|
-
return;
|
|
40413
|
-
}
|
|
40414
|
-
const { delegationData } = await refreshOpenKeySession(profileName2, host, {
|
|
40415
|
-
paste: options.paste,
|
|
40416
|
-
noPopup: options.popup === false,
|
|
40417
|
-
persistHost: true
|
|
40418
|
-
});
|
|
40419
|
-
await ensureSpaceSetup({ profile: profileName2, host }, delegationData, delegationData.permissions);
|
|
40420
|
-
outputJson({
|
|
40421
|
-
profile: profileName2,
|
|
40422
|
-
did,
|
|
40423
|
-
host,
|
|
40424
|
-
spaceId: delegationData.spaceId,
|
|
40425
|
-
authenticated: true
|
|
40426
|
-
});
|
|
40427
|
-
} catch (error) {
|
|
40428
|
-
return handleError(error);
|
|
40429
|
-
}
|
|
40430
|
-
});
|
|
40431
|
-
}
|
|
40432
|
-
|
|
40433
40440
|
// src/commands/knowledge.ts
|
|
40434
40441
|
init_session_expired();
|
|
40435
40442
|
init_constants();
|
|
@@ -44315,7 +44322,6 @@ function registerSecretsCommand(program, openKeyAcquisition) {
|
|
|
44315
44322
|
|
|
44316
44323
|
// src/commands/share.ts
|
|
44317
44324
|
import { Option } from "commander";
|
|
44318
|
-
import { readFile as readFile18 } from "fs/promises";
|
|
44319
44325
|
import { CLI_NAME as CLI_NAME34 } from "@tinycloud/operations/cli-name";
|
|
44320
44326
|
import { ProfileLockTimeoutError as ProfileLockTimeoutError3 } from "@tinycloud/operations/state";
|
|
44321
44327
|
init_errors();
|
|
@@ -45989,19 +45995,16 @@ function registerShareCommand(program) {
|
|
|
45989
45995
|
try {
|
|
45990
45996
|
const json = jsonOutput(options, command);
|
|
45991
45997
|
if (options.ongoing === true) throw new CLIError("UNSUPPORTED_TARGET", ONGOING_UNAVAILABLE, 2);
|
|
45998
|
+
const target = parseShareTarget(options.to);
|
|
45999
|
+
if (target.kind === "email") throw new CLIError("UNAVAILABLE", "email-addressed shares are not available in this release; nothing was shared", 4);
|
|
45992
46000
|
const maxBytes = byteLimit(options.maxBytes);
|
|
45993
46001
|
if (files.length === 0 || files.includes("-") && files.length > 1) throw new CLIError("INVALID_ARGUMENT", "stdin must be the only publish input", 2);
|
|
45994
46002
|
const name = files.length === 1 ? options.name : void 0;
|
|
45995
|
-
const target = parseShareTarget(options.to);
|
|
45996
46003
|
const actions = requestedActions(options.action);
|
|
45997
46004
|
if (options.notify === true && !actions.includes("read")) throw new CLIError("INVALID_ARGUMENT", "--notify requires the read action; nothing was shared", 2);
|
|
45998
|
-
if (
|
|
45999
|
-
throw new CLIError("INVALID_ARGUMENT", "email publication requires --credential-descriptor, --issuer-did, and --issuer-kid", 2);
|
|
46000
|
-
}
|
|
46001
|
-
if (target.kind !== "email" && (options.credentialDescriptor || options.issuerDid || options.issuerKid)) {
|
|
46005
|
+
if (options.credentialDescriptor || options.issuerDid || options.issuerKid) {
|
|
46002
46006
|
throw new CLIError("INVALID_ARGUMENT", "credential options require an exact email target", 2);
|
|
46003
46007
|
}
|
|
46004
|
-
const credentialDescriptor = target.kind === "email" ? JSON.parse(await readFile18(options.credentialDescriptor, "utf8")) : void 0;
|
|
46005
46008
|
const folder = files.length === 1 && target.kind === "bearer" && options.prefix !== true && await isDirectoryInput(files[0]);
|
|
46006
46009
|
let inputs;
|
|
46007
46010
|
if (folder) {
|
|
@@ -46027,8 +46030,7 @@ function registerShareCommand(program) {
|
|
|
46027
46030
|
throw new CLIError("INVALID_ARGUMENT", "--notify-to requires --to domain:<name> --notify", 2);
|
|
46028
46031
|
}
|
|
46029
46032
|
let notifyRecipient;
|
|
46030
|
-
if (options.notify === true && target.kind === "
|
|
46031
|
-
else if (options.notify === true && target.kind === "emailDomain") {
|
|
46033
|
+
if (options.notify === true && target.kind === "emailDomain") {
|
|
46032
46034
|
const mailbox = options.notifyTo === void 0 ? void 0 : canonicalMailbox(options.notifyTo);
|
|
46033
46035
|
if (mailbox === void 0 || mailbox.domain !== target.domain) {
|
|
46034
46036
|
throw new CLIError("INVALID_ARGUMENT", "--to domain:<name> --notify requires --notify-to <email> at that exact domain (node 1.17.3+)", 2);
|
|
@@ -46052,7 +46054,6 @@ function registerShareCommand(program) {
|
|
|
46052
46054
|
origin: options.viewerOrigin,
|
|
46053
46055
|
...maxBytes === void 0 ? {} : { maxBytes },
|
|
46054
46056
|
notify: options.notify === true,
|
|
46055
|
-
...credentialDescriptor === void 0 ? {} : { credentialDescriptor, issuerDid: options.issuerDid, issuerKid: options.issuerKid },
|
|
46056
46057
|
// The artifact request rides on the adapter call rather than through `publishTargetShare`, whose code is part of
|
|
46057
46058
|
// the browser bundles (the web-sdk size ceiling counts every byte it carries).
|
|
46058
46059
|
targetAdapter: artifact === void 0 || shareServices.targetAdapter === void 0 ? shareServices.targetAdapter : { publish: (request) => shareServices.targetAdapter.publish({ ...request, artifact }) }
|
|
@@ -47188,7 +47189,7 @@ function registerUpgradeCommand(program) {
|
|
|
47188
47189
|
}
|
|
47189
47190
|
|
|
47190
47191
|
// src/commands/vault.ts
|
|
47191
|
-
import { readFile as
|
|
47192
|
+
import { readFile as readFile18 } from "fs/promises";
|
|
47192
47193
|
init_profiles();
|
|
47193
47194
|
init_formatter();
|
|
47194
47195
|
init_errors();
|
|
@@ -47250,7 +47251,7 @@ function registerVaultCommand(program) {
|
|
|
47250
47251
|
throw new CLIError("USAGE_ERROR", "Provide only one of: value argument, --file, or --stdin", ExitCode.USAGE_ERROR);
|
|
47251
47252
|
}
|
|
47252
47253
|
if (options.file) {
|
|
47253
|
-
putValue = new Uint8Array(await
|
|
47254
|
+
putValue = new Uint8Array(await readFile18(options.file));
|
|
47254
47255
|
} else if (options.stdin) {
|
|
47255
47256
|
putValue = new Uint8Array(await readStdin5());
|
|
47256
47257
|
} else {
|
|
@@ -47365,7 +47366,7 @@ function registerVaultCommand(program) {
|
|
|
47365
47366
|
}
|
|
47366
47367
|
|
|
47367
47368
|
// src/commands/vars.ts
|
|
47368
|
-
import { readFile as
|
|
47369
|
+
import { readFile as readFile19 } from "fs/promises";
|
|
47369
47370
|
init_profiles();
|
|
47370
47371
|
init_formatter();
|
|
47371
47372
|
init_errors();
|
|
@@ -47470,7 +47471,7 @@ function registerVarsCommand(program) {
|
|
|
47470
47471
|
throw new CLIError("USAGE_ERROR", "Provide only one of: value argument, --file, or --stdin", ExitCode.USAGE_ERROR);
|
|
47471
47472
|
}
|
|
47472
47473
|
if (options.file) {
|
|
47473
|
-
varValue = await
|
|
47474
|
+
varValue = await readFile19(options.file, "utf-8");
|
|
47474
47475
|
} else if (options.stdin) {
|
|
47475
47476
|
varValue = (await readStdin6()).toString("utf-8");
|
|
47476
47477
|
} else {
|