turnzero 0.30.1-next.1 → 0.31.1-next.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 +2 -2
- package/dist/turnzero-cloud.mjs +614 -54
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,13 +10,13 @@ Paste this into Claude, ChatGPT, or Codex:
|
|
|
10
10
|
Set me up with Turn Zero Cloud and a small demo app. Read https://turnzero.ai/cloud/getting-started/set-up/index.md in full and follow the steps.
|
|
11
11
|
```
|
|
12
12
|
|
|
13
|
-
Your AI
|
|
13
|
+
Your AI connects Turn Zero Cloud and signs you in, or creates a free account. Then it gives you a build prompt to paste, which builds a demo you can open in your browser.
|
|
14
14
|
|
|
15
15
|
[Read the setup guide](https://turnzero.ai/cloud/getting-started/set-up/) · [Explore Turn Zero Cloud](https://turnzero.ai/cloud/)
|
|
16
16
|
|
|
17
17
|
## What this package does
|
|
18
18
|
|
|
19
|
-
The `turnzero` CLI lets your AI tool deploy files, run and test your app locally, and create a project from a template. The setup guide handles installation and authorization when needed.
|
|
19
|
+
The `turnzero` CLI lets your AI coding tool deploy files, run and test your app locally, and create a project from a template. The setup guide handles installation and authorization when needed.
|
|
20
20
|
|
|
21
21
|
To install it yourself, run `npm install -g turnzero`. It needs Node.js 24 or later. For commands and examples, run `turnzero --help`, or `turnzero.cmd --help` on Windows. Use `turnzero <subcommand> --help` for a specific command.
|
|
22
22
|
|
package/dist/turnzero-cloud.mjs
CHANGED
|
@@ -64,6 +64,7 @@ var TURNZERO_CLOUD_PACKAGE = "turnzero";
|
|
|
64
64
|
var LOGIN_SUBCOMMAND = "login";
|
|
65
65
|
var LOGIN_OPTION = Object.freeze({ origin: "--origin", noBrowser: "--no-browser" });
|
|
66
66
|
var loginLineOf = (origin) => commandLineOf(origin, LOGIN_SUBCOMMAND, origin !== DEFAULT_COMMAND_ORIGIN ? { origin } : {});
|
|
67
|
+
var HAND_OVER_SENTENCE = "If your tool's own safety check refuses a line, give the person that exact line to run once in their own terminal, never a rewritten one.";
|
|
67
68
|
var COMPUTER_LOGIN_PATH = "/approve/computer";
|
|
68
69
|
var COMPUTER_LOGIN_QUERY = Object.freeze({ challenge: "challenge", state: "state", port: "port", label: "label" });
|
|
69
70
|
var LOGIN_STATE_FORM = /^[A-Za-z0-9_-]{43}$/;
|
|
@@ -280,6 +281,57 @@ var COMPLETION_MINT = "mint";
|
|
|
280
281
|
var MINT_MEMBER = "mint";
|
|
281
282
|
var MINT_OPTION = "--mint";
|
|
282
283
|
var MINT_ID_FORM = UPLOAD_ID;
|
|
284
|
+
var TZMESH_SUBCOMMAND = "tzmesh";
|
|
285
|
+
var TZMESH_REGISTER_ACT = "register";
|
|
286
|
+
var TZMESH_OPTION = {
|
|
287
|
+
name: "--name",
|
|
288
|
+
secret: "--secret",
|
|
289
|
+
toFile: "--to-file",
|
|
290
|
+
application: "--application",
|
|
291
|
+
environment: "--environment",
|
|
292
|
+
force: "--force",
|
|
293
|
+
origin: "--origin",
|
|
294
|
+
tzmeshEstate: "--tzmesh-estate",
|
|
295
|
+
mint: "--mint"
|
|
296
|
+
};
|
|
297
|
+
var TZMESH_ESTATES = Object.freeze(["production", "development"]);
|
|
298
|
+
var TZMESH_ESTATE_ORIGINS = Object.freeze({
|
|
299
|
+
production: Object.freeze({ plane: DEFAULT_COMMAND_ORIGIN, wire: "https://tzmesh.turnzero.ai" }),
|
|
300
|
+
development: Object.freeze({ plane: DEVELOPMENT_COMMAND_ORIGIN, wire: "https://tzmesh.dev.turnzero.ai" })
|
|
301
|
+
});
|
|
302
|
+
var tzmeshEstateOfPlane = (origin) => TZMESH_ESTATES.find((estate) => TZMESH_ESTATE_ORIGINS[estate].plane === origin) ?? null;
|
|
303
|
+
var TZMESH_MINT_GRANT = "tzmesh";
|
|
304
|
+
var TZMESH_COMMAND_LABEL = "turnzero command";
|
|
305
|
+
var TZMESH_MINT_DAYS = 1;
|
|
306
|
+
var TZMESH_SIGNED_TOKEN_PREFIX = `${MINTED_TOKEN_PREFIX}${TZMESH_MINT_GRANT}1.`;
|
|
307
|
+
var TZMESH_SIGNED_TOKEN_MAX = 4096;
|
|
308
|
+
var TZMESH_SIGNED_TOKEN_FORM = new RegExp(`^${TZMESH_SIGNED_TOKEN_PREFIX.replace(/\./g, "\\.")}[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]{86}$`);
|
|
309
|
+
var isTzmeshSignedToken = (value) => typeof value === "string" && value.length <= TZMESH_SIGNED_TOKEN_MAX && TZMESH_SIGNED_TOKEN_FORM.test(value);
|
|
310
|
+
var SIGNED_TOKEN_PRODUCTS = ["tzmesh", "tztrack"];
|
|
311
|
+
var PRODUCT_SIGNED_TOKEN_FORM = new RegExp(`^${MINTED_TOKEN_PREFIX}(?:${SIGNED_TOKEN_PRODUCTS.join("|")})1\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]{86}$`);
|
|
312
|
+
var isClaimableToken = (value) => MINTED_TOKEN_FORM.test(value) || value.length <= TZMESH_SIGNED_TOKEN_MAX && PRODUCT_SIGNED_TOKEN_FORM.test(value);
|
|
313
|
+
var TZMESH_SECRET_PREFIX = "turnzero_tzmesh_sec_";
|
|
314
|
+
var TZMESH_SECRET_FORM = new RegExp(`^${TZMESH_SECRET_PREFIX}[A-Za-z0-9_-]{16,256}$`);
|
|
315
|
+
var TZMESH_NAME_FORM = /^[A-Za-z0-9_-]{1,32}$/;
|
|
316
|
+
var TZMESH_REGISTER_PATH = "/v1/register";
|
|
317
|
+
var TZMESH_END_PATH = "/v1/end";
|
|
318
|
+
var tzmeshMintMembers = (challenge) => [
|
|
319
|
+
[CODE_CHALLENGE_MEMBER, challenge],
|
|
320
|
+
["scope_kind", "account"],
|
|
321
|
+
["grants", [TZMESH_MINT_GRANT]],
|
|
322
|
+
["label", TZMESH_COMMAND_LABEL],
|
|
323
|
+
["expires_in_days", TZMESH_MINT_DAYS],
|
|
324
|
+
[COMPLETION_MEMBER, COMPLETION_MINT]
|
|
325
|
+
];
|
|
326
|
+
var tzmeshRegisterOptionsOf = (call) => [
|
|
327
|
+
`${TZMESH_OPTION.name} ${call.name}`,
|
|
328
|
+
call.secret !== void 0 ? `${TZMESH_OPTION.secret} ${call.secret}` : `${TZMESH_OPTION.toFile} "${call.toFile ?? ""}"`,
|
|
329
|
+
...call.application !== void 0 ? [`${TZMESH_OPTION.application} ${call.application}`] : [],
|
|
330
|
+
...call.environment !== void 0 ? [`${TZMESH_OPTION.environment} ${call.environment}`] : [],
|
|
331
|
+
...call.force === true ? [TZMESH_OPTION.force] : [],
|
|
332
|
+
`${TZMESH_OPTION.origin} ${originWord(call.origin)}`,
|
|
333
|
+
`${TZMESH_OPTION.tzmeshEstate} ${call.tzmeshEstate}`
|
|
334
|
+
].join(" ");
|
|
283
335
|
|
|
284
336
|
// src/turnzero_cloud_command/credential_file.ts
|
|
285
337
|
import { randomBytes } from "node:crypto";
|
|
@@ -789,9 +841,9 @@ var readMovingCredentialFile = (io2, place, say) => {
|
|
|
789
841
|
// src/turnzero_cloud_command/grant.ts
|
|
790
842
|
var GRANT_READ_BOUND_MS = 1e4;
|
|
791
843
|
var GRANT_INPUT_BYTES_MAX = 4096;
|
|
792
|
-
var readStandardInputEnded = (input, boundMs = GRANT_READ_BOUND_MS) => new Promise((
|
|
844
|
+
var readStandardInputEnded = (input, boundMs = GRANT_READ_BOUND_MS) => new Promise((resolve14) => {
|
|
793
845
|
if (input.isTTY) {
|
|
794
|
-
|
|
846
|
+
resolve14({ text: "", bytes: 0, ending: "terminal" });
|
|
795
847
|
return;
|
|
796
848
|
}
|
|
797
849
|
const chunks = [];
|
|
@@ -813,7 +865,7 @@ var readStandardInputEnded = (input, boundMs = GRANT_READ_BOUND_MS) => new Promi
|
|
|
813
865
|
input.removeListener("close", onEnd);
|
|
814
866
|
input.pause();
|
|
815
867
|
input.destroy?.();
|
|
816
|
-
|
|
868
|
+
resolve14({ text: Buffer.concat(chunks).toString("utf8"), bytes, ending });
|
|
817
869
|
};
|
|
818
870
|
const onEnd = () => finish("end");
|
|
819
871
|
const onError = () => finish("error");
|
|
@@ -943,11 +995,12 @@ var noTokenSentence = (origin, expiredAt) => expiredAt === null ? `No credential
|
|
|
943
995
|
var VARIABLE_ROUTE_SENTENCES = `A tool connected by a minted token, or a job, sets ${MINTED_TOKEN_VARIABLE} from where its token is kept, never by writing the value in a line. It sets ${ORIGIN_VARIABLE} to the address that minted the token where that is not ${DEFAULT_COMMAND_ORIGIN}, then runs the line again. Such a tool cannot use ${MINT_TOKEN_ACTION}, which takes a sign-in alone. A tool sets ${MINTED_TOKEN_VARIABLE} for one line at a time and unsets it once that line ends.`;
|
|
944
996
|
var authorizeRouteSentence = (origin) => `${AUTHORIZE_SUBCOMMAND}${originWordsOf(origin)} run with nothing piped prints the ${MINT_TOKEN_ACTION} call a signed-in tool makes to authorize this computer.`;
|
|
945
997
|
var LOGIN_ROUTE_OPENER = "A person logs this computer in once, in a terminal of their own, and its token then stays on this computer for 30 days:";
|
|
946
|
-
var DEPLOY_FILES_ROUTE_SENTENCE = "A folder within the caps of your tool's deploy_files call deploys now through deploy_files, with no login.";
|
|
998
|
+
var DEPLOY_FILES_ROUTE_SENTENCE = "A folder within the caps of your tool's deploy_files call deploys now through deploy_files, with no login; past them, through mint_upload_grant and deploy's artifact.";
|
|
947
999
|
var loginRouteLines = (io2, origin, deployFiles = true) => [
|
|
948
1000
|
LOGIN_ROUTE_OPENER,
|
|
949
1001
|
...loginLinesFor(io2, origin),
|
|
950
|
-
...deployFiles ? [DEPLOY_FILES_ROUTE_SENTENCE] : []
|
|
1002
|
+
...deployFiles ? [DEPLOY_FILES_ROUTE_SENTENCE] : [],
|
|
1003
|
+
HAND_OVER_SENTENCE
|
|
951
1004
|
];
|
|
952
1005
|
var loginRouteRefusalOf = (io2, closing) => {
|
|
953
1006
|
const place = credentialFileOf(io2);
|
|
@@ -963,6 +1016,8 @@ var loginRouteRefusalOf = (io2, closing) => {
|
|
|
963
1016
|
// src/turnzero_cloud_command/guard.ts
|
|
964
1017
|
var GRANT_TEXT = new RegExp(`${UPLOAD_GRANT_PREFIX}[A-Za-z0-9_-]*(?:\\.[A-Za-z0-9_-]+)*`, "g");
|
|
965
1018
|
var TOKEN_TEXT = new RegExp(`${MINTED_TOKEN_PREFIX}[A-Za-z0-9_-]*(?:\\.[A-Za-z0-9_-]+)*`, "g");
|
|
1019
|
+
var PROGRAM_SECRET_TEXT = new RegExp(`${TZMESH_SECRET_PREFIX}[A-Za-z0-9_-]*`, "g");
|
|
1020
|
+
var REDACTED_PROGRAM_SECRET = "<program secret>";
|
|
966
1021
|
var REDACTED_GRANT = "<grant>";
|
|
967
1022
|
var REDACTED_VALUE = "<value>";
|
|
968
1023
|
var REDACTED_TOKEN_CODE = "<token code>";
|
|
@@ -970,10 +1025,10 @@ var REDACTED_VERIFIER = "<verifier>";
|
|
|
970
1025
|
var REDACTED_CHALLENGE = "<challenge>";
|
|
971
1026
|
var HIDDEN_TEXT_MIN = 8;
|
|
972
1027
|
var redactGrants = (line) => line.replace(GRANT_TEXT, REDACTED_GRANT);
|
|
973
|
-
var redactCredentials = (line) => redactGrants(line).replace(TOKEN_TEXT, REDACTED_TOKEN);
|
|
1028
|
+
var redactCredentials = (line) => redactGrants(line).replace(TOKEN_TEXT, REDACTED_TOKEN).replace(PROGRAM_SECRET_TEXT, REDACTED_PROGRAM_SECRET);
|
|
974
1029
|
var VALUE_LINE_REFUSED = Object.freeze({
|
|
975
1030
|
twice: "the value line is printed once in a run",
|
|
976
|
-
form: "only a
|
|
1031
|
+
form: "only a value of a form token claim prints is printed whole",
|
|
977
1032
|
terminal: "the value line is printed only where the command's standard error is a terminal",
|
|
978
1033
|
seam: "this io prints no value line"
|
|
979
1034
|
});
|
|
@@ -1001,7 +1056,7 @@ var guarded = (io2) => {
|
|
|
1001
1056
|
},
|
|
1002
1057
|
printValue: (value) => {
|
|
1003
1058
|
if (valuePrinted) throw new Error(VALUE_LINE_REFUSED.twice);
|
|
1004
|
-
if (!
|
|
1059
|
+
if (!isClaimableToken(value)) throw new Error(VALUE_LINE_REFUSED.form);
|
|
1005
1060
|
if (io2.errorIsTerminal !== true) throw new Error(VALUE_LINE_REFUSED.terminal);
|
|
1006
1061
|
if (io2.printValue === void 0) throw new Error(VALUE_LINE_REFUSED.seam);
|
|
1007
1062
|
valuePrinted = true;
|
|
@@ -1041,17 +1096,33 @@ var hideStandingTokens = (io2, state) => {
|
|
|
1041
1096
|
};
|
|
1042
1097
|
var CHALLENGE_LINE_HEAD = "challenge: ";
|
|
1043
1098
|
var CALL_LINE_HEAD = `call ${MINT_TOKEN_ACTION} with:`;
|
|
1044
|
-
var mintCallMembers = (kind, challenge, label) => kind === "authorized computer" ? [
|
|
1099
|
+
var mintCallMembers = (kind, challenge, label) => kind === "tzmesh" ? tzmeshMintMembers(challenge) : kind === "authorized computer" ? [
|
|
1045
1100
|
[CODE_CHALLENGE_MEMBER, challenge],
|
|
1046
1101
|
["scope_kind", "account"],
|
|
1047
1102
|
[AUTHORIZED_COMPUTER_MEMBER, true],
|
|
1048
1103
|
["label", label],
|
|
1049
1104
|
[COMPLETION_MEMBER, COMPLETION_MINT]
|
|
1050
1105
|
] : [[CODE_CHALLENGE_MEMBER, challenge]];
|
|
1051
|
-
var firstActNamed = (kind, origin = DEFAULT_COMMAND_ORIGIN) =>
|
|
1106
|
+
var firstActNamed = (kind, origin = DEFAULT_COMMAND_ORIGIN) => kind === "tzmesh" ? (
|
|
1107
|
+
// The tzmesh first act takes its options, which its own lines name, so
|
|
1108
|
+
// the act is named by its words alone (PLD-L0-112).
|
|
1109
|
+
`${TZMESH_SUBCOMMAND} ${TZMESH_REGISTER_ACT}`
|
|
1110
|
+
) : `${kind === "authorized computer" ? AUTHORIZE_SUBCOMMAND : `${TOKEN_SUBCOMMAND} ${TOKEN_REQUEST_ACT}`}${originWordsOf(origin)}`;
|
|
1052
1111
|
var noConnectionLine = (origin) => `Where your tool holds no connection signed in to ${origin}, ${MINT_TOKEN_ACTION} is not among its tools: a person connects the tool and signs in, in a browser, before the call.`;
|
|
1053
1112
|
var loginWaySentence = (loginLines) => `A person can instead log this computer in themselves, in a terminal of their own, by running ${loginLines.join(", then ")}, and approving the login in the browser.`;
|
|
1054
|
-
var
|
|
1113
|
+
var OPTIONS_LINE_HEAD = "options: ";
|
|
1114
|
+
var tzmeshFirstActLines = (origin, pending, completing2) => [
|
|
1115
|
+
`To register a tzMesh agent, call ${MINT_TOKEN_ACTION} at ${origin} from your tool, through the connection you signed in with, naming the members below and no others. Then run the line it answers once, on this computer, with the options below after it.`,
|
|
1116
|
+
noConnectionLine(origin),
|
|
1117
|
+
`${CHALLENGE_LINE_HEAD}${pending.challenge}`,
|
|
1118
|
+
CALL_LINE_HEAD,
|
|
1119
|
+
...mintCallMembers("tzmesh", pending.challenge, TZMESH_COMMAND_LABEL).map(([name, value]) => ` ${name}: ${JSON.stringify(value)}`),
|
|
1120
|
+
`${OPTIONS_LINE_HEAD}${completing2}`,
|
|
1121
|
+
`The line it answers holds no code. The run presents this computer's verifier, registers the agent with the token it mints, keeps the agent's secret where the options say, and revokes the token. No line prints the secret.`,
|
|
1122
|
+
`The request is pending until ${pending.expires_at}: ${firstActNamed("tzmesh", origin)} run again with the same options before then prints this challenge again.`,
|
|
1123
|
+
HAND_OVER_SENTENCE
|
|
1124
|
+
];
|
|
1125
|
+
var firstActLines = (origin, kind, pending, label, loginLines = [], completing2 = "") => kind === "tzmesh" ? tzmeshFirstActLines(origin, pending, completing2) : [
|
|
1055
1126
|
kind === "authorized computer" ? `To authorize this computer at ${origin}, call ${MINT_TOKEN_ACTION} from your tool, through the connection you signed in with, naming the members below and no others. Then run the line it answers once, as given, on this computer.` : `To mint a token whose value never passes through the chat, call ${MINT_TOKEN_ACTION} at ${origin} from your tool, through the connection you signed in with. Name the member below beside the scope_kind, application, grants, label, and expires_in_days the task needs.`,
|
|
1056
1127
|
// The case this command cannot see (#4273): a tool with no signed-in
|
|
1057
1128
|
// connection holds no mint_token, and only a person's sign-in mends it.
|
|
@@ -1060,11 +1131,12 @@ var firstActLines = (origin, kind, pending, label, loginLines = []) => [
|
|
|
1060
1131
|
CALL_LINE_HEAD,
|
|
1061
1132
|
...mintCallMembers(kind, pending.challenge, label).map(([name, value]) => ` ${name}: ${JSON.stringify(value)}`),
|
|
1062
1133
|
kind === "authorized computer" ? `The line it answers holds no code. It keeps the token it mints in this computer's credential file and revokes the one this computer held there before. The token is account-scoped and works from any computer until it expires or revoke_token ends it, and list_tokens shows it by its label. The request is pending until ${pending.expires_at}: ${firstActNamed(kind, origin)} run again before then prints this challenge again.` : `It answers a ${TOKEN_SUBCOMMAND} ${TOKEN_CLAIM_ACT} line, which is yours to run in a terminal outside the AI coding tool, on this computer as this user, and never through the tool. That line prints the token's value once to standard output, so pipe it into your secret store's command where the token is a job's. The request is pending until ${pending.expires_at}: ${firstActNamed(kind, origin)} run again before then prints this challenge again.`,
|
|
1063
|
-
...kind === "authorized computer" && loginLines.length > 0 ? [loginWaySentence(loginLines)] : []
|
|
1134
|
+
...kind === "authorized computer" && loginLines.length > 0 ? [loginWaySentence(loginLines)] : [],
|
|
1135
|
+
...kind === "authorized computer" ? [HAND_OVER_SENTENCE] : []
|
|
1064
1136
|
];
|
|
1065
1137
|
var reusedRequestSentence = (origin, pending) => `A request for ${origin} is pending until ${pending.expires_at}, so its challenge is printed again and no new verifier was made.`;
|
|
1066
1138
|
var replacedRequestSentence = (origin, expired2) => `The request pending for ${origin} expired at ${expired2.expires_at}, so a new one replaces it. A line minted against the old challenge is refused at its exchange, and a ${MINT_TOKEN_ACTION} call naming the new challenge below answers a fresh one.`;
|
|
1067
|
-
async function firstAct(io2, origin, kind, say, opener = null) {
|
|
1139
|
+
async function firstAct(io2, origin, kind, say, opener = null, completing2 = "") {
|
|
1068
1140
|
const kept2 = keepPendingRequest(io2, origin, say);
|
|
1069
1141
|
if ("status" in kept2) return kept2.status;
|
|
1070
1142
|
const { pending, opening } = kept2;
|
|
@@ -1072,7 +1144,7 @@ async function firstAct(io2, origin, kind, say, opener = null) {
|
|
|
1072
1144
|
const lines = [
|
|
1073
1145
|
...opener !== null ? [opener] : [],
|
|
1074
1146
|
...opening !== "" ? [opening] : [],
|
|
1075
|
-
...firstActLines(origin, kind, pending, label, kind === "authorized computer" ? loginLinesFor(io2, origin) : [])
|
|
1147
|
+
...firstActLines(origin, kind, pending, label, kind === "authorized computer" ? loginLinesFor(io2, origin) : [], completing2)
|
|
1076
1148
|
];
|
|
1077
1149
|
let last = -1;
|
|
1078
1150
|
for (const [index, line] of lines.entries()) if (line.includes(pending.challenge)) last = index;
|
|
@@ -1167,9 +1239,10 @@ async function revokeUnder(io2, origin, token2, id, userAgent) {
|
|
|
1167
1239
|
var standsSentence = (what, id, expiresAt) => `${what} was not revoked, so it works until it expires${expiresAt !== null ? ` at ${expiresAt}` : ""}: revoke_token from your tool with id ${id} ends it, and list_tokens shows whether it stands.`;
|
|
1168
1240
|
var INSTANT_FORM2 = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,9})?Z$/;
|
|
1169
1241
|
var KEPT_LABEL_FORM = /^[^\u0000-\u001f\u007f-\u009f]{1,512}$/;
|
|
1170
|
-
var mintedTokenOf = (answer) => {
|
|
1242
|
+
var mintedTokenOf = (answer, kind = "authorized computer") => {
|
|
1171
1243
|
const { value, token: token2 } = answer;
|
|
1172
|
-
if (typeof value !== "string"
|
|
1244
|
+
if (typeof value !== "string") return null;
|
|
1245
|
+
if (kind === "tzmesh" || kind === "general" ? value === "" || value.length > TZMESH_SIGNED_TOKEN_MAX : !MINTED_TOKEN_FORM.test(value)) return null;
|
|
1173
1246
|
if (token2 === null || typeof token2 !== "object" || Array.isArray(token2)) return null;
|
|
1174
1247
|
const view = token2;
|
|
1175
1248
|
if (typeof view.id !== "string" || !UPLOAD_ID.test(view.id)) return null;
|
|
@@ -1185,6 +1258,7 @@ var mintAgainSentence = (kind, origin = DEFAULT_COMMAND_ORIGIN, login2 = null) =
|
|
|
1185
1258
|
var exchangeUnknownSentence = (kind, origin = DEFAULT_COMMAND_ORIGIN, login2 = null) => `Whether a token was minted is unknown: list_tokens from your tool shows each token by its label, and revoke_token ends one nothing holds. ${mintAgainSentence(kind, origin, login2)}`;
|
|
1186
1259
|
var noPendingSentence = (origin, kind, presented = "code") => `No request is pending for ${origin} on this computer, so ${presented === "mint" ? "nothing was sent: the verifier the mint needs" : "the token code was not presented and nothing was sent: the verifier it needs"} is kept only on the computer whose ${firstActNamed(kind)} printed its challenge. Run ${firstActNamed(kind, origin)} on this computer, call ${MINT_TOKEN_ACTION} from your tool with the challenge it prints, and run the line it answers.`;
|
|
1187
1260
|
var markerDisagreesSentence = (kind, origin = DEFAULT_COMMAND_ORIGIN) => kind === "authorized computer" ? `The exchange minted a token that is not an authorized computer's, and ${AUTHORIZE_SUBCOMMAND} keeps only an authorized computer's, so nothing of its value was printed or kept. Call ${MINT_TOKEN_ACTION} from your tool again naming ${AUTHORIZED_COMPUTER_MEMBER}: true, as ${AUTHORIZE_SUBCOMMAND} prints it, and run the line it answers.` : `The exchange minted an authorized computer's token, and ${TOKEN_SUBCOMMAND} ${TOKEN_CLAIM_ACT} prints only a token that is not one, so nothing of its value was printed or kept. Call ${MINT_TOKEN_ACTION} from your tool again without ${AUTHORIZED_COMPUTER_MEMBER}, as ${TOKEN_SUBCOMMAND} ${TOKEN_REQUEST_ACT} prints it, and run the line it answers; to authorize this computer, run ${AUTHORIZE_SUBCOMMAND}${originWordsOf(origin)}.`;
|
|
1261
|
+
var unclaimableFormSentence = (origin = DEFAULT_COMMAND_ORIGIN) => `The exchange minted a token whose value is of no form ${TOKEN_SUBCOMMAND} ${TOKEN_CLAIM_ACT} prints, so nothing of its value was printed or kept. ${mintAgainSentence("general", origin)}`;
|
|
1188
1262
|
var mintedRevocationLines = (revocation, minted) => "lines" in revocation ? [...revocation.lines, standsSentence(`The token it minted, ${minted.id},`, minted.id, minted.expiresAt)] : [`The token it minted, ${minted.id}, is revoked.`];
|
|
1189
1263
|
var authorizedLineOf = (origin, entry, account = null) => `${AUTHORIZED_LINE_HEAD}${origin}${account !== null ? ` as ${accountWordsOf(account)}` : ""}, label ${entry.label !== null ? JSON.stringify(entry.label) : "none"}, its token expiring ${entry.expires_at !== null ? `at ${entry.expires_at}` : "never"}`;
|
|
1190
1264
|
var READ_ACCOUNT_ACTION = "read_account";
|
|
@@ -1214,7 +1288,7 @@ async function readAccountUnder(io2, origin, token2, userAgent) {
|
|
|
1214
1288
|
var whoamiLineFor = (io2, origin) => printedLineOf(io2, commandLineOf(origin, WHOAMI_SUBCOMMAND, origin !== DEFAULT_COMMAND_ORIGIN ? { origin } : {}), origin);
|
|
1215
1289
|
var accountUnreadSentence = (whoami2) => `The account this computer's token acts as was not read, and the token is kept: run ${whoami2} to read it.`;
|
|
1216
1290
|
var CLAIMED_LINE_HEAD = "claimed: ";
|
|
1217
|
-
async function completeAct(io2, origin, kind, presentation, userAgent, say, deliver = () => void 0, login2 = null) {
|
|
1291
|
+
async function completeAct(io2, origin, kind, presentation, userAgent, say, deliver = () => void 0, login2 = null, carried = null) {
|
|
1218
1292
|
const held = "mint" in presentation;
|
|
1219
1293
|
const unread = held ? MINT_UNPRESENTED : TOKEN_CODE_UNREAD;
|
|
1220
1294
|
const place = credentialFileOf(io2);
|
|
@@ -1232,13 +1306,14 @@ async function completeAct(io2, origin, kind, presentation, userAgent, say, deli
|
|
|
1232
1306
|
io2.hide(pending.verifier, REDACTED_VERIFIER);
|
|
1233
1307
|
io2.hide(pending.challenge, REDACTED_CHALLENGE);
|
|
1234
1308
|
const tag = runTagOf();
|
|
1235
|
-
const stage = { now: "unsent", ended: false };
|
|
1309
|
+
const stage = carried?.stage ?? { now: "unsent", ended: false };
|
|
1236
1310
|
const release = io2.whenEnded(() => {
|
|
1237
1311
|
stage.ended = true;
|
|
1238
1312
|
say(
|
|
1239
|
-
stage.now === "unsent" ? `The run was ended before its exchange. ${unread}` : stage.now === "sent" ? `The run was ended during its exchange. ${exchangeUnknownSentence(kind, origin, login2)}` : `The run was ended after its exchange minted a token, which may not have been ${kind === "authorized computer" ? "kept" : "printed"}: list_tokens from your tool shows it by its label, and revoke_token ends it.`
|
|
1313
|
+
carried !== null ? carried.endedLine(stage.now) : stage.now === "unsent" ? `The run was ended before its exchange. ${unread}` : stage.now === "sent" ? `The run was ended during its exchange. ${exchangeUnknownSentence(kind, origin, login2)}` : `The run was ended after its exchange minted a token, which may not have been ${kind === "authorized computer" ? "kept" : "printed"}: list_tokens from your tool shows it by its label, and revoke_token ends it.`
|
|
1240
1314
|
);
|
|
1241
1315
|
dropCredentialWriting(io2, place, tag);
|
|
1316
|
+
carried?.drop();
|
|
1242
1317
|
});
|
|
1243
1318
|
try {
|
|
1244
1319
|
const prepared = prepareCredentialFile(io2, place, tag);
|
|
@@ -1246,6 +1321,11 @@ async function completeAct(io2, origin, kind, presentation, userAgent, say, deli
|
|
|
1246
1321
|
say(`${unwritableFileSentence(place.path, prepared.unwritten)} Nothing was sent. ${unread}`);
|
|
1247
1322
|
return COMMAND_STATUS.nothing_started;
|
|
1248
1323
|
}
|
|
1324
|
+
const untried = carried?.prepare() ?? null;
|
|
1325
|
+
if (untried !== null) {
|
|
1326
|
+
say(untried);
|
|
1327
|
+
return COMMAND_STATUS.nothing_started;
|
|
1328
|
+
}
|
|
1249
1329
|
if (stage.ended) return COMMAND_STATUS.nothing_started;
|
|
1250
1330
|
const older = await planeWireRefusal(io2, origin, held ? "" : TOKEN_CODE_UNREAD_FIRST);
|
|
1251
1331
|
if (stage.ended) return COMMAND_STATUS.nothing_started;
|
|
@@ -1253,6 +1333,14 @@ async function completeAct(io2, origin, kind, presentation, userAgent, say, deli
|
|
|
1253
1333
|
say(older);
|
|
1254
1334
|
return COMMAND_STATUS.nothing_started;
|
|
1255
1335
|
}
|
|
1336
|
+
if (carried !== null) {
|
|
1337
|
+
const further = await carried.checks();
|
|
1338
|
+
if (stage.ended) return COMMAND_STATUS.nothing_started;
|
|
1339
|
+
if (further !== null) {
|
|
1340
|
+
say(further);
|
|
1341
|
+
return COMMAND_STATUS.nothing_started;
|
|
1342
|
+
}
|
|
1343
|
+
}
|
|
1256
1344
|
stage.now = "sent";
|
|
1257
1345
|
const answered = "mint" in presentation ? await postAction(io2, origin, MINT_TOKEN_ACTION, pending.verifier, userAgent, heldExchangeBodyOf(presentation.mint)) : await postAction(io2, origin, MINT_TOKEN_ACTION, presentation.code, userAgent, exchangeBodyOf(pending.verifier));
|
|
1258
1346
|
if (stage.ended) {
|
|
@@ -1291,7 +1379,7 @@ async function completeAct(io2, origin, kind, presentation, userAgent, say, deli
|
|
|
1291
1379
|
);
|
|
1292
1380
|
return COMMAND_STATUS.nothing_started;
|
|
1293
1381
|
}
|
|
1294
|
-
const minted = answer === null ? null : mintedTokenOf(answer);
|
|
1382
|
+
const minted = answer === null ? null : mintedTokenOf(answer, kind);
|
|
1295
1383
|
if (minted === null) {
|
|
1296
1384
|
say(`The exchange was answered HTTP ${answered.status} with no token the command can use: a value and an id, each in its form. Nothing of the answer was printed or kept.`);
|
|
1297
1385
|
say(unknown);
|
|
@@ -1299,6 +1387,17 @@ async function completeAct(io2, origin, kind, presentation, userAgent, say, deli
|
|
|
1299
1387
|
}
|
|
1300
1388
|
stage.now = "minted";
|
|
1301
1389
|
io2.hide(minted.value, REDACTED_TOKEN);
|
|
1390
|
+
if (kind === "tzmesh" && carried !== null) {
|
|
1391
|
+
const ended = updateCredentialFile(io2, place, tag, withoutPending(origin));
|
|
1392
|
+
if (stage.ended) return COMMAND_STATUS.unknown;
|
|
1393
|
+
if (!("written" in ended)) say(`The request pending for ${origin} stands in the credential file, which could not be written now: it ends at its expiry, or when ${firstActNamed(kind, origin)} replaces it.`);
|
|
1394
|
+
return isTzmeshSignedToken(minted.value) && !minted.authorizedComputer ? await carried.deliver(minted) : await carried.refuse(minted);
|
|
1395
|
+
}
|
|
1396
|
+
if (kind === "general" && !isClaimableToken(minted.value)) {
|
|
1397
|
+
say(unclaimableFormSentence(origin));
|
|
1398
|
+
for (const line of mintedRevocationLines(await revokeUnder(io2, origin, minted.value, minted.id, userAgent), minted)) say(line);
|
|
1399
|
+
return COMMAND_STATUS.failed;
|
|
1400
|
+
}
|
|
1302
1401
|
if (minted.authorizedComputer !== (kind === "authorized computer")) {
|
|
1303
1402
|
say(markerDisagreesSentence(kind, origin));
|
|
1304
1403
|
for (const line of mintedRevocationLines(await revokeUnder(io2, origin, minted.value, minted.id, userAgent), minted)) say(line);
|
|
@@ -1309,6 +1408,7 @@ async function completeAct(io2, origin, kind, presentation, userAgent, say, deli
|
|
|
1309
1408
|
} finally {
|
|
1310
1409
|
release();
|
|
1311
1410
|
dropCredentialWriting(io2, place, tag);
|
|
1411
|
+
carried?.drop();
|
|
1312
1412
|
}
|
|
1313
1413
|
}
|
|
1314
1414
|
function claimed(io2, place, tag, origin, minted, say, deliver) {
|
|
@@ -3325,7 +3425,7 @@ var headCommitOf = (folder, reads = FILE_SYSTEM_READS) => {
|
|
|
3325
3425
|
|
|
3326
3426
|
// src/turnzero_cloud_command/options.ts
|
|
3327
3427
|
var afterOwnErrorOf = (row, call, io2) => typeof row.afterOwnError === "function" ? row.afterOwnError(call, io2) : row.afterOwnError;
|
|
3328
|
-
var PATH_OPTION_NAMES = Object.freeze([DEPLOY_OPTION.path, SECRET_OPTION.valueFile, PROVISION_OPTION.envFile, SESSION_OPTION.out]);
|
|
3428
|
+
var PATH_OPTION_NAMES = Object.freeze([DEPLOY_OPTION.path, SECRET_OPTION.valueFile, PROVISION_OPTION.envFile, SESSION_OPTION.out, TZMESH_OPTION.toFile]);
|
|
3329
3429
|
var DEPLOY_OPTIONS = Object.freeze([
|
|
3330
3430
|
{
|
|
3331
3431
|
name: DEPLOY_OPTION.application,
|
|
@@ -4039,7 +4139,8 @@ var DEPLOY_ROW = Object.freeze({
|
|
|
4039
4139
|
note: [
|
|
4040
4140
|
`A deploy is one line, which carries no credential: run the line your tool's deploy call answers, or ${DEPLOY_SUBCOMMAND} ${DEPLOY_OPTION.application} <application id>, from the application's folder. It reads no standard input. On an authorized computer it runs under this computer's token, which ${LOGIN_SUBCOMMAND} or ${AUTHORIZE_SUBCOMMAND} keeps in the credential file for each platform address. It sends that token only to the address it is kept under: ${DEPLOY_OPTION.origin} where the line names one, else the address ${ORIGIN_VARIABLE} holds, else ${DEFAULT_COMMAND_ORIGIN}.`,
|
|
4041
4141
|
`On a computer with no token for that address, or one that has expired, it sends nothing, ends 3, and prints two routes, in this order. A tool connected by a minted token, or a job with no tool, such as a CI job's, sets ${MINTED_TOKEN_VARIABLE} from where its token is kept, never by writing the value in a line. It sets ${ORIGIN_VARIABLE} to the address that minted the token where that is not ${DEFAULT_COMMAND_ORIGIN}, then runs the deploy line again. Such a tool cannot use ${MINT_TOKEN_ACTION}, which takes a sign-in alone.`,
|
|
4042
|
-
`Otherwise a person logs this computer in once with ${LOGIN_SUBCOMMAND}, in a terminal of their own, then runs the deploy line again.
|
|
4142
|
+
`Otherwise a person logs this computer in once with ${LOGIN_SUBCOMMAND}, in a terminal of their own, then runs the deploy line again. The credential file is ${CREDENTIAL_FILE_WORDS}.`,
|
|
4143
|
+
`${DEPLOY_FILES_ROUTE_SENTENCE} ${HAND_OVER_SENTENCE}`,
|
|
4043
4144
|
`A tool sets ${MINTED_TOKEN_VARIABLE} for one line at a time and unsets it once that line ends, since the command cannot unset a variable of the shell that started it. A value a job's environment already supplies stays as it stands. A job's token is minted for the application, with an expiry. The variable's token wins over the credential file: the command makes the preparing call under that token, and sends the token in no other request.`,
|
|
4044
4145
|
`Under the variable, the command sends its token only to the address ${ORIGIN_VARIABLE} holds, or to ${DEFAULT_COMMAND_ORIGIN} where that variable is unset. Under the token, ${DEPLOY_OPTION.origin} may name that address alone, and where the line names none the command addresses it. ${DEPLOY_OPTION.env} names the environment where a line names one, ${COMMAND_ENVIRONMENTS.join(" or ")}. Where none is named, the platform chooses, and the command deploys to the environment the platform answers.`,
|
|
4045
4146
|
`A progress read answered 502, 503, or 504, which is often temporary, is made again, at most three more times. An upload answered 503 credential_lookup_busy, which wrote nothing, is made again after the wait it names, at most twice.`,
|
|
@@ -4412,7 +4513,7 @@ var noTerminalSentence = (option, call) => `${option} reads the value from a ter
|
|
|
4412
4513
|
var readPromptedValue = (io2, option, fileOption, call) => {
|
|
4413
4514
|
const terminal = io2.terminal();
|
|
4414
4515
|
if (terminal === null) return Promise.resolve({ refusal: noTerminalSentence(option, call) });
|
|
4415
|
-
return new Promise((
|
|
4516
|
+
return new Promise((resolve14) => {
|
|
4416
4517
|
let typed = "";
|
|
4417
4518
|
let done = false;
|
|
4418
4519
|
let cancel = () => void 0;
|
|
@@ -4422,7 +4523,7 @@ var readPromptedValue = (io2, option, fileOption, call) => {
|
|
|
4422
4523
|
cancel();
|
|
4423
4524
|
terminal.write("\n");
|
|
4424
4525
|
terminal.close();
|
|
4425
|
-
|
|
4526
|
+
resolve14(read2);
|
|
4426
4527
|
};
|
|
4427
4528
|
cancel = io2.schedule(
|
|
4428
4529
|
PROMPT_BOUND_SECONDS * 1e3,
|
|
@@ -5794,8 +5895,8 @@ var openerRunOf = (io2, address) => {
|
|
|
5794
5895
|
};
|
|
5795
5896
|
var openBrowser = async (io2, address) => {
|
|
5796
5897
|
let cancel = () => void 0;
|
|
5797
|
-
const waited = new Promise((
|
|
5798
|
-
cancel = io2.schedule(OPENER_WAIT_MS, () =>
|
|
5898
|
+
const waited = new Promise((resolve14) => {
|
|
5899
|
+
cancel = io2.schedule(OPENER_WAIT_MS, () => resolve14("waiting"));
|
|
5799
5900
|
});
|
|
5800
5901
|
const ended = await Promise.race([io2.child(openerRunOf(io2, address)), waited]);
|
|
5801
5902
|
cancel();
|
|
@@ -5876,13 +5977,13 @@ async function login(call, io2) {
|
|
|
5876
5977
|
const endMs = Math.max(1e3, Date.parse(pending.expires_at) - io2.clock().getTime());
|
|
5877
5978
|
const minutes = minutesLeftOf(pending.expires_at, io2.clock());
|
|
5878
5979
|
let settle = () => void 0;
|
|
5879
|
-
const arrived = new Promise((
|
|
5880
|
-
settle =
|
|
5980
|
+
const arrived = new Promise((resolve14) => {
|
|
5981
|
+
settle = resolve14;
|
|
5881
5982
|
});
|
|
5882
5983
|
let taken = false;
|
|
5883
5984
|
let outcome = () => void 0;
|
|
5884
|
-
const outcomeKnown = new Promise((
|
|
5885
|
-
outcome =
|
|
5985
|
+
const outcomeKnown = new Promise((resolve14) => {
|
|
5986
|
+
outcome = resolve14;
|
|
5886
5987
|
});
|
|
5887
5988
|
const take = (arrival2) => {
|
|
5888
5989
|
if (taken) return false;
|
|
@@ -6141,7 +6242,7 @@ var whoamiLinesOf = (origin, account, entry) => [
|
|
|
6141
6242
|
`${WHOAMI_LINE_HEADS.token}label ${entry.label !== null ? JSON.stringify(entry.label) : "none"}, expiring ${entry.expires_at !== null ? `at ${entry.expires_at}` : "never"}`
|
|
6142
6243
|
];
|
|
6143
6244
|
var noComputerTokenSentence = (origin, expiredAt) => expiredAt === null ? `This computer's credential file holds no token for ${origin}, so nothing was sent.` : `This computer's token for ${origin} in its credential file expired at ${expiredAt}, so nothing was sent.`;
|
|
6144
|
-
var noLoginRoutesSentence = (origin) => `Your AI coding tool's own sign-in is not this computer's credential. With no login, deploy_files deploys a folder within its caps. ${
|
|
6245
|
+
var noLoginRoutesSentence = (origin) => `Your AI coding tool's own sign-in is not this computer's credential. With no login, deploy_files deploys a folder within its caps; past them, upload a zip with mint_upload_grant, then name it as deploy's artifact. ${PROVISION_SUBCOMMAND}${originWordsOf(origin)} run with nothing piped prints the call that answers its line.`;
|
|
6145
6246
|
var whoamiAfterLoginSentence = (whoami2) => `Once login has printed authorized:, run ${whoami2} again.`;
|
|
6146
6247
|
async function whoami(call, io2) {
|
|
6147
6248
|
const origin = entryOriginOf(io2.env, call.named[DEPLOY_OPTION.origin], NOTHING_SENT_OR_READ);
|
|
@@ -6173,6 +6274,7 @@ async function whoami(call, io2) {
|
|
|
6173
6274
|
}
|
|
6174
6275
|
io2.print(LOGIN_ROUTE_OPENER);
|
|
6175
6276
|
for (const line of loginLinesFor(io2, reached.origin)) io2.print(line);
|
|
6277
|
+
io2.print(HAND_OVER_SENTENCE);
|
|
6176
6278
|
io2.print(whoamiAfterLoginSentence(whoamiLineFor(io2, reached.origin)));
|
|
6177
6279
|
return COMMAND_STATUS.nothing_started;
|
|
6178
6280
|
}
|
|
@@ -6196,7 +6298,7 @@ async function whoami(call, io2) {
|
|
|
6196
6298
|
}
|
|
6197
6299
|
var WHOAMI_ROW = Object.freeze({
|
|
6198
6300
|
name: WHOAMI_SUBCOMMAND,
|
|
6199
|
-
summary: `Names the account this computer's token acts as at the platform's address. It reads the token the credential file keeps for the address, and makes one ${READ_ACCOUNT_ACTION} call under it. It prints the address, the account's sign-in address and id, and the token's label and expiry. With no token for the address, it sends nothing. It names the ways on with no login (deploy_files,
|
|
6301
|
+
summary: `Names the account this computer's token acts as at the platform's address. It reads the token the credential file keeps for the address, and makes one ${READ_ACCOUNT_ACTION} call under it. It prints the address, the account's sign-in address and id, and the token's label and expiry. With no token for the address, it sends nothing. It names the ways on with no login (deploy_files, the upload route, and ${PROVISION_SUBCOMMAND}), then prints the login route. It prints no token.`,
|
|
6200
6302
|
example: WHOAMI_SUBCOMMAND,
|
|
6201
6303
|
options: WHOAMI_OPTIONS,
|
|
6202
6304
|
credential: null,
|
|
@@ -9624,6 +9726,460 @@ var TOKEN_ROW = Object.freeze({
|
|
|
9624
9726
|
run: token
|
|
9625
9727
|
});
|
|
9626
9728
|
|
|
9729
|
+
// src/turnzero_cloud_command/tzmesh_register.ts
|
|
9730
|
+
import { dirname as dirname8, resolve as resolve13 } from "node:path";
|
|
9731
|
+
var TZMESH_LISTED = false;
|
|
9732
|
+
var TZMESH_ACT_WORDS = `${TZMESH_SUBCOMMAND} ${TZMESH_REGISTER_ACT}`;
|
|
9733
|
+
var TZMESH_OPTIONS = Object.freeze([
|
|
9734
|
+
{
|
|
9735
|
+
name: TZMESH_OPTION.name,
|
|
9736
|
+
value: "<name>",
|
|
9737
|
+
required: true,
|
|
9738
|
+
description: "The agent's name, 1 to 32 letters, digits, hyphens, and underscores. Its handle is this name under your account's handle."
|
|
9739
|
+
},
|
|
9740
|
+
{
|
|
9741
|
+
name: TZMESH_OPTION.secret,
|
|
9742
|
+
value: "<secret name>",
|
|
9743
|
+
required: false,
|
|
9744
|
+
description: `The name the agent's secret is stored under in your account's secret store. Give exactly one of this and ${TZMESH_OPTION.toFile}. Under it, the secret never reaches your tool.`
|
|
9745
|
+
},
|
|
9746
|
+
{
|
|
9747
|
+
name: TZMESH_OPTION.toFile,
|
|
9748
|
+
value: "<file>",
|
|
9749
|
+
required: false,
|
|
9750
|
+
description: "A file the agent's secret is written into, alone on one line and readable by you alone, for a program on this computer. Anything that runs as you can read it, your tool among them."
|
|
9751
|
+
},
|
|
9752
|
+
{
|
|
9753
|
+
name: TZMESH_OPTION.application,
|
|
9754
|
+
value: "<application id>",
|
|
9755
|
+
required: false,
|
|
9756
|
+
description: `Under ${TZMESH_OPTION.secret}, the application whose scope holds the secret. Where absent, the account's scope.`
|
|
9757
|
+
},
|
|
9758
|
+
{
|
|
9759
|
+
name: TZMESH_OPTION.environment,
|
|
9760
|
+
value: "<environment>",
|
|
9761
|
+
required: false,
|
|
9762
|
+
description: `Under ${TZMESH_OPTION.secret}, the environment of that application whose scope holds the secret, ${COMMAND_ENVIRONMENTS.join(" or ")}. It goes with ${TZMESH_OPTION.application}.`
|
|
9763
|
+
},
|
|
9764
|
+
{
|
|
9765
|
+
name: TZMESH_OPTION.force,
|
|
9766
|
+
value: "",
|
|
9767
|
+
required: false,
|
|
9768
|
+
flag: true,
|
|
9769
|
+
description: `Under ${TZMESH_OPTION.toFile}, replaces the file that stands there.`
|
|
9770
|
+
},
|
|
9771
|
+
{
|
|
9772
|
+
name: TZMESH_OPTION.origin,
|
|
9773
|
+
value: "<origin>",
|
|
9774
|
+
required: false,
|
|
9775
|
+
description: `The platform's address the secret is stored at, ${DEFAULT_COMMAND_ORIGIN} or ${DEVELOPMENT_COMMAND_ORIGIN}. Where absent, the address ${ORIGIN_VARIABLE} holds, or ${DEFAULT_COMMAND_ORIGIN} where it is unset.`
|
|
9776
|
+
},
|
|
9777
|
+
{
|
|
9778
|
+
name: TZMESH_OPTION.tzmeshEstate,
|
|
9779
|
+
value: "<estate>",
|
|
9780
|
+
required: false,
|
|
9781
|
+
description: `The estate the agent is registered at, ${TZMESH_ESTATES.join(" or ")}: its platform mints the run's token, and its tzMesh service registers the agent. Where absent, the estate of ${TZMESH_OPTION.origin}.`
|
|
9782
|
+
},
|
|
9783
|
+
{
|
|
9784
|
+
name: TZMESH_OPTION.mint,
|
|
9785
|
+
value: "<id>",
|
|
9786
|
+
required: false,
|
|
9787
|
+
description: `The mint the line names, by its id, as the line a ${MINT_TOKEN_ACTION} call answers names it. The id is no credential. Under it, the command presents this computer's verifier for that mint.`
|
|
9788
|
+
}
|
|
9789
|
+
]);
|
|
9790
|
+
var UNPRINTABLE_PATH = /["$`%\u0000-\u001f\u007f]/;
|
|
9791
|
+
var closingOf = (call) => call.named[TZMESH_OPTION.mint] !== void 0 ? MINT_UNPRESENTED : NOTHING_SENT;
|
|
9792
|
+
var TZMESH_MINT_ID_REFUSAL = `${TZMESH_OPTION.mint} names the mint by its id, a lowercase UUID, as the line the ${MINT_TOKEN_ACTION} call answered names it: run that line as given, with the options the first act printed after it. ${NOTHING_SENT}`;
|
|
9793
|
+
var tzmeshOriginRefusal = (closing) => `${TZMESH_OPTION.origin} names the platform's address the secret is stored at, and ${TZMESH_ACT_WORDS} reaches only ${DEFAULT_COMMAND_ORIGIN} or ${DEVELOPMENT_COMMAND_ORIGIN}. Where the line names none, ${ORIGIN_VARIABLE} must hold one of those two, or be unset. ${closing}`;
|
|
9794
|
+
var tzmeshOptionsOf = (call, io2) => {
|
|
9795
|
+
const mint = call.named[TZMESH_OPTION.mint] ?? null;
|
|
9796
|
+
if (mint !== null && !MINT_ID_FORM.test(mint)) return { refusal: TZMESH_MINT_ID_REFUSAL };
|
|
9797
|
+
const closing = closingOf(call);
|
|
9798
|
+
const name = call.named[TZMESH_OPTION.name];
|
|
9799
|
+
if (name === void 0 || !TZMESH_NAME_FORM.test(name)) return { refusal: `${TZMESH_OPTION.name} names the agent: 1 to 32 letters, digits, hyphens, and underscores. ${closing}` };
|
|
9800
|
+
const secret2 = call.named[TZMESH_OPTION.secret];
|
|
9801
|
+
const toFile = call.named[TZMESH_OPTION.toFile];
|
|
9802
|
+
if (secret2 === void 0 === (toFile === void 0)) {
|
|
9803
|
+
return { refusal: `Give one of ${TZMESH_OPTION.secret} and ${TZMESH_OPTION.toFile}: the name the agent's secret is stored under, or the file it is written into. ${closing}` };
|
|
9804
|
+
}
|
|
9805
|
+
if (secret2 !== void 0 && !SECRET_NAME_FORM.test(secret2)) {
|
|
9806
|
+
return { refusal: `${TZMESH_OPTION.secret} names the secret the agent's secret is stored under: a letter or digit first, then letters, digits, _ or -, up to 64 characters. ${closing}` };
|
|
9807
|
+
}
|
|
9808
|
+
const application = call.named[TZMESH_OPTION.application] ?? null;
|
|
9809
|
+
if (application !== null && toFile !== void 0) return { refusal: `${TZMESH_OPTION.application} goes with ${TZMESH_OPTION.secret} alone: a file has no scope. ${closing}` };
|
|
9810
|
+
if (application !== null && !UPLOAD_ID.test(application)) {
|
|
9811
|
+
return { refusal: `${TZMESH_OPTION.application} names the application whose scope holds the secret, by its id, a lowercase UUID. ${closing}` };
|
|
9812
|
+
}
|
|
9813
|
+
const named = call.named[TZMESH_OPTION.environment];
|
|
9814
|
+
const environment = COMMAND_ENVIRONMENTS.find((entry) => entry === named) ?? null;
|
|
9815
|
+
if (named !== void 0 && (environment === null || application === null)) {
|
|
9816
|
+
return {
|
|
9817
|
+
refusal: `${TZMESH_OPTION.environment} names the environment of an application whose scope holds the secret, ${COMMAND_ENVIRONMENTS.join(" or ")}, and goes with ${TZMESH_OPTION.application}: the account's scope has no environment. ${closing}`
|
|
9818
|
+
};
|
|
9819
|
+
}
|
|
9820
|
+
const force = call.flags.has(TZMESH_OPTION.force);
|
|
9821
|
+
if (force && toFile === void 0) return { refusal: `${TZMESH_OPTION.force} goes with ${TZMESH_OPTION.toFile} alone: it replaces a file that stands there. ${closing}` };
|
|
9822
|
+
const path = toFile !== void 0 ? resolve13(io2.cwd, toFile) : null;
|
|
9823
|
+
if (path !== null && UNPRINTABLE_PATH.test(path)) {
|
|
9824
|
+
return { refusal: `${TZMESH_OPTION.toFile} names a path holding a character a line cannot carry between double quotes: a double quote, $, a backtick, %, or a control character. Name a path without one. ${closing}` };
|
|
9825
|
+
}
|
|
9826
|
+
const origin = entryOriginOf(io2.env, call.named[TZMESH_OPTION.origin], closing);
|
|
9827
|
+
if ("refusal" in origin) return origin;
|
|
9828
|
+
if (!FIRST_PARTY_COMMAND_ORIGINS.includes(origin.origin)) return { refusal: tzmeshOriginRefusal(closing) };
|
|
9829
|
+
const namedEstate = call.named[TZMESH_OPTION.tzmeshEstate];
|
|
9830
|
+
const estate = namedEstate === void 0 ? tzmeshEstateOfPlane(origin.origin) : TZMESH_ESTATES.find((entry) => entry === namedEstate) ?? null;
|
|
9831
|
+
if (estate === null) return { refusal: `${TZMESH_OPTION.tzmeshEstate} names the estate the agent is registered at, ${TZMESH_ESTATES.join(" or ")}. ${closing}` };
|
|
9832
|
+
return {
|
|
9833
|
+
name,
|
|
9834
|
+
route: secret2 !== void 0 ? { secret: secret2 } : { toFile: path },
|
|
9835
|
+
application,
|
|
9836
|
+
environment,
|
|
9837
|
+
force,
|
|
9838
|
+
origin: origin.origin,
|
|
9839
|
+
estate,
|
|
9840
|
+
mint
|
|
9841
|
+
};
|
|
9842
|
+
};
|
|
9843
|
+
var completingOptionsOf = (options) => {
|
|
9844
|
+
const call = {
|
|
9845
|
+
name: options.name,
|
|
9846
|
+
..."secret" in options.route ? { secret: options.route.secret } : { toFile: options.route.toFile },
|
|
9847
|
+
...options.application !== null ? { application: options.application } : {},
|
|
9848
|
+
...options.environment !== null ? { environment: options.environment } : {},
|
|
9849
|
+
...options.force ? { force: true } : {},
|
|
9850
|
+
origin: options.origin,
|
|
9851
|
+
tzmeshEstate: options.estate
|
|
9852
|
+
};
|
|
9853
|
+
return tzmeshRegisterOptionsOf(call);
|
|
9854
|
+
};
|
|
9855
|
+
var tzmeshMintedTokenRefusal = (closing) => `${MINTED_TOKEN_VARIABLE} is set, and ${TZMESH_ACT_WORDS} never runs under a minted token: it runs under this computer's token for each address it sends to. Unset the variable for this line and run it again. ${closing}`;
|
|
9856
|
+
var NEEDED_FOR = Object.freeze({
|
|
9857
|
+
revoke: "to revoke the token the run mints there",
|
|
9858
|
+
store: "to store the secret there",
|
|
9859
|
+
both: "to revoke the token the run mints there and to store the secret there"
|
|
9860
|
+
});
|
|
9861
|
+
var tzmeshNoTokenSentence = (origin, expiredAt, need) => expiredAt === null ? `This computer's credential file holds no token for ${origin}, which ${TZMESH_ACT_WORDS} needs ${NEEDED_FOR[need]}, so nothing was sent.` : `This computer's token for ${origin} in its credential file expired at ${expiredAt}, and ${TZMESH_ACT_WORDS} needs one ${NEEDED_FOR[need]}, so nothing was sent.`;
|
|
9862
|
+
var readComputerTokens = (io2, mintPlane, storeOrigin, closing) => {
|
|
9863
|
+
const place = credentialFileOf(io2);
|
|
9864
|
+
const read2 = readMovingCredentialFile(io2, place, io2.print);
|
|
9865
|
+
if (!("state" in read2)) {
|
|
9866
|
+
io2.print(`${readRefusalOf(read2, place.path)} ${closing}`);
|
|
9867
|
+
return { status: COMMAND_STATUS.nothing_started };
|
|
9868
|
+
}
|
|
9869
|
+
hideStandingTokens(io2, read2.state);
|
|
9870
|
+
const now = io2.clock().getTime();
|
|
9871
|
+
const needs = storeOrigin === null ? [[mintPlane, "revoke"]] : storeOrigin === mintPlane ? [[mintPlane, "both"]] : [[mintPlane, "revoke"], [storeOrigin, "store"]];
|
|
9872
|
+
for (const [origin, need] of needs) {
|
|
9873
|
+
const entry = read2.state.origins.get(origin);
|
|
9874
|
+
const expiredAt = entry !== void 0 && entry.expires_at !== null && Date.parse(entry.expires_at) <= now ? entry.expires_at : null;
|
|
9875
|
+
if (entry !== void 0 && expiredAt === null) continue;
|
|
9876
|
+
io2.print(tzmeshNoTokenSentence(origin, expiredAt, need));
|
|
9877
|
+
io2.print(authorizeRouteSentence(origin));
|
|
9878
|
+
const unwritable = loginRouteRefusalOf(io2, closing);
|
|
9879
|
+
if (unwritable !== null) io2.print(unwritable);
|
|
9880
|
+
else for (const line of loginRouteLines(io2, origin, false)) io2.print(line);
|
|
9881
|
+
return { status: COMMAND_STATUS.nothing_started };
|
|
9882
|
+
}
|
|
9883
|
+
const mint = read2.state.origins.get(mintPlane);
|
|
9884
|
+
return { mint, store: storeOrigin === null ? null : read2.state.origins.get(storeOrigin) };
|
|
9885
|
+
};
|
|
9886
|
+
var toFileFolderRefusal = (closing) => `${TZMESH_OPTION.toFile} names a folder: name a file for the secret, in that folder or another. ${closing}`;
|
|
9887
|
+
var toFileStandsRefusal = (closing) => `A file stands where ${TZMESH_OPTION.toFile} names, and ${TZMESH_ACT_WORDS} writes over one only where the line names ${TZMESH_OPTION.force}. Name a new file, or add ${TZMESH_OPTION.force} to replace it. ${closing}`;
|
|
9888
|
+
var toFileDeployedRefusal = (closing) => `${TZMESH_OPTION.toFile} names a file a deploy from the folder this line runs in would include, so the secret would be uploaded with the application. Name a file outside the application's folder. ${closing}`;
|
|
9889
|
+
var toFileParentRefusal = (closing) => `The folder ${TZMESH_OPTION.toFile} names a file in does not stand: make it, or name a file in a folder that stands. ${closing}`;
|
|
9890
|
+
var toFileUntriedRefusal = (code, closing) => `The file ${TZMESH_OPTION.toFile} names could not be written (${code}): its folder must admit a write. ${closing}`;
|
|
9891
|
+
var toFileRefusalOf = (io2, path, force, closing) => {
|
|
9892
|
+
const standing = io2.stat(path);
|
|
9893
|
+
if (standing !== null && standing.folder) return toFileFolderRefusal(closing);
|
|
9894
|
+
if (standing !== null && !force) return toFileStandsRefusal(closing);
|
|
9895
|
+
if (valueFileWouldDeploy(io2, resolve13(io2.cwd), path)) return toFileDeployedRefusal(closing);
|
|
9896
|
+
const folder = io2.stat(dirname8(path));
|
|
9897
|
+
if (folder === null || !folder.folder) return toFileParentRefusal(closing);
|
|
9898
|
+
return null;
|
|
9899
|
+
};
|
|
9900
|
+
var REGISTERED_LINE_HEAD = "registered: ";
|
|
9901
|
+
var WRITTEN_LINE_HEAD = "written: ";
|
|
9902
|
+
var REGISTER_ACT = "register";
|
|
9903
|
+
var END_ACT = "deletion";
|
|
9904
|
+
var PRINTED_NAME_FORM = /^[A-Za-z0-9_.:/@-]{1,160}$/;
|
|
9905
|
+
var agentWords = (agent) => agent.handle !== null ? agent.handle : `with id ${agent.id}`;
|
|
9906
|
+
var registeredLineOf = (agent, wire) => `${REGISTERED_LINE_HEAD}agent ${agent.handle ?? "with no handle"}, id ${agent.id}, at ${wire}, its secret printed nowhere`;
|
|
9907
|
+
var WRITTEN_LINE = `${WRITTEN_LINE_HEAD}the agent's secret, alone on one line, into the file ${TZMESH_OPTION.toFile} names, readable by its owner alone`;
|
|
9908
|
+
var REGISTER_UNKNOWN = "Whether the agent was registered is unknown: tzmesh_participants from your tool shows it, and end from your tool, naming its participant and delete true, deletes it.";
|
|
9909
|
+
var agentStandsSentence = (agent) => `The agent ${agentWords(agent)} stands with no secret kept: end from your tool, naming participant ${agent.id} and delete true, deletes it and frees its name.`;
|
|
9910
|
+
var storeUnknownSentence = (secretName, agent) => `Whether the secret was stored is unknown: list_secrets from your tool shows when ${secretName} was last written. Where it was not written, end from your tool, naming participant ${agent.id} and delete true, deletes the agent ${agentWords(agent)}.`;
|
|
9911
|
+
var TOKEN_LEFT = `list_tokens from your tool shows the run's token by its label, ${TZMESH_COMMAND_LABEL}, and revoke_token ends it; it expires within a day either way.`;
|
|
9912
|
+
var tokenStandsSentence = (id) => `The run's token, ${id}, was not revoked, so it works until it expires within a day: revoke_token from your tool with id ${id} ends it, and list_tokens shows whether it stands.`;
|
|
9913
|
+
var revocationBearerRefused = (origin) => `This computer's token for ${origin} was refused as the bearer of the revocation.`;
|
|
9914
|
+
var revocationNotFound = (origin) => `The account this computer's token for ${origin} acts as holds no such token: that token likely belongs to another account than the one your tool signed in with.`;
|
|
9915
|
+
var postWire = async (io2, wire, path, bearer, userAgent, body) => {
|
|
9916
|
+
const controller = new AbortController();
|
|
9917
|
+
const cancel = io2.schedule(TOKEN_CALL_BOUND_SECONDS * 1e3, () => controller.abort());
|
|
9918
|
+
try {
|
|
9919
|
+
const response = await io2.fetch(`${wire}${path}`, {
|
|
9920
|
+
method: "POST",
|
|
9921
|
+
headers: { authorization: `Bearer ${bearer}`, "user-agent": userAgent, "content-type": "application/json" },
|
|
9922
|
+
body: JSON.stringify(body),
|
|
9923
|
+
redirect: "manual",
|
|
9924
|
+
signal: controller.signal
|
|
9925
|
+
});
|
|
9926
|
+
return { status: response.status, redirected: redirected(response), text: await response.text() };
|
|
9927
|
+
} catch {
|
|
9928
|
+
return null;
|
|
9929
|
+
} finally {
|
|
9930
|
+
cancel();
|
|
9931
|
+
}
|
|
9932
|
+
};
|
|
9933
|
+
var register = async (io2, wire, token2, userAgent, name) => {
|
|
9934
|
+
const answered = await postWire(io2, wire, TZMESH_REGISTER_PATH, token2, userAgent, { kind: "standing", name, label: TZMESH_COMMAND_LABEL });
|
|
9935
|
+
if (answered === null) return { unknown: [`The ${REGISTER_ACT} drew no answer.`] };
|
|
9936
|
+
if (answered.redirected) return { unknown: [`The ${REGISTER_ACT} was answered ${answeredHow(answered.status)}, which the command never follows, so the token was sent to no second address.`] };
|
|
9937
|
+
if (answered.status >= PLATFORM_FAILURE_STATUS) return { unknown: failureLines(REGISTER_ACT, answered.status, planeRefusalOf(answered.text)) };
|
|
9938
|
+
const answer = planeObjectOf(answered.text);
|
|
9939
|
+
if (answer !== null && typeof answer.secret === "string") io2.hide(answer.secret, REDACTED_PROGRAM_SECRET);
|
|
9940
|
+
if (answered.status < 200 || answered.status > 299) {
|
|
9941
|
+
const refusal = planeRefusalOf(answered.text);
|
|
9942
|
+
if (refusal === null) return { unknown: [`The ${REGISTER_ACT} was answered HTTP ${answered.status}, not by the tzMesh service.`] };
|
|
9943
|
+
return { refused: [...refusalLines(REGISTER_ACT, answered.status, refusal), "Nothing was registered."] };
|
|
9944
|
+
}
|
|
9945
|
+
const participant = answer?.participant;
|
|
9946
|
+
const record = participant !== null && typeof participant === "object" && !Array.isArray(participant) ? participant : null;
|
|
9947
|
+
const id = typeof record?.id === "string" && PRINTED_NAME_FORM.test(record.id) ? record.id : null;
|
|
9948
|
+
if (id === null) return { unknown: [`The ${REGISTER_ACT} was answered HTTP ${answered.status} with no participant the command can read.`] };
|
|
9949
|
+
const agent = { id, handle: typeof record?.handle === "string" && PRINTED_NAME_FORM.test(record.handle) ? record.handle : null };
|
|
9950
|
+
const secret2 = answer?.secret;
|
|
9951
|
+
if (typeof secret2 !== "string" || !TZMESH_SECRET_FORM.test(secret2)) {
|
|
9952
|
+
return { standing: agent, lines: [`The ${REGISTER_ACT} answered no secret the command can keep, so the agent stands with none kept.`] };
|
|
9953
|
+
}
|
|
9954
|
+
return { agent, secret: secret2 };
|
|
9955
|
+
};
|
|
9956
|
+
var deleteAgent = async (io2, wire, token2, userAgent, agent) => {
|
|
9957
|
+
const answered = await postWire(io2, wire, TZMESH_END_PATH, token2, userAgent, { participant: agent.id, delete: true });
|
|
9958
|
+
const deleted = answered !== null && !answered.redirected && answered.status >= 200 && answered.status <= 299 && planeObjectOf(answered.text) !== null;
|
|
9959
|
+
if (deleted) return [`The agent ${agentWords(agent)} was deleted, and its name is free again.`];
|
|
9960
|
+
const why = answered === null ? [`The ${END_ACT} drew no answer.`] : answered.redirected ? [`The ${END_ACT} was answered ${answeredHow(answered.status)}, which the command never follows.`] : answered.status >= PLATFORM_FAILURE_STATUS ? failureLines(END_ACT, answered.status, planeRefusalOf(answered.text)) : planeRefusalOf(answered.text) !== null ? refusalLines(END_ACT, answered.status, planeRefusalOf(answered.text)) : [`The ${END_ACT} was answered HTTP ${answered.status}, not by the tzMesh service.`];
|
|
9961
|
+
return [...why, agentStandsSentence(agent)];
|
|
9962
|
+
};
|
|
9963
|
+
var revokeRunToken = async (io2, plane, bearer, id, userAgent) => {
|
|
9964
|
+
const answered = await postAction(io2, plane, REVOKE_TOKEN_ACTION, bearer, userAgent, revocationBodyOf(id));
|
|
9965
|
+
let lines;
|
|
9966
|
+
if (answered === null) lines = [`${REVOKE_TOKEN_ACTION} drew no answer.`];
|
|
9967
|
+
else if (answered.redirected) lines = [`${REVOKE_TOKEN_ACTION} was answered ${answeredHow(answered.status)}, which the command never follows.`];
|
|
9968
|
+
else if (answered.status >= PLATFORM_FAILURE_STATUS) lines = failureLines(REVOKE_TOKEN_ACTION, answered.status, planeRefusalOf(answered.text));
|
|
9969
|
+
else if (answered.status >= 200 && answered.status <= 299) {
|
|
9970
|
+
const row = planeObjectOf(answered.text)?.token;
|
|
9971
|
+
if (row !== null && typeof row === "object" && !Array.isArray(row) && row.id === id) return null;
|
|
9972
|
+
lines = [`${REVOKE_TOKEN_ACTION} was answered HTTP ${answered.status} with no revocation of token ${id} the command can read.`];
|
|
9973
|
+
} else {
|
|
9974
|
+
const refusal = markedRefusalOf(answered.status, answered.text);
|
|
9975
|
+
lines = refusal === null ? [notThePlatformLine("revocation", answered.status)] : [
|
|
9976
|
+
...refusalLines(REVOKE_TOKEN_ACTION, answered.status, refusal),
|
|
9977
|
+
...answered.status === 401 ? [revocationBearerRefused(plane)] : answered.status === 404 ? [revocationNotFound(plane)] : []
|
|
9978
|
+
];
|
|
9979
|
+
}
|
|
9980
|
+
return [...lines, tokenStandsSentence(id)];
|
|
9981
|
+
};
|
|
9982
|
+
var endedLineOf = (stage, plane, agent, route) => {
|
|
9983
|
+
switch (stage) {
|
|
9984
|
+
case "unsent":
|
|
9985
|
+
return `The run was ended before its exchange. ${MINT_UNPRESENTED}`;
|
|
9986
|
+
case "sent":
|
|
9987
|
+
return `The run was ended during its exchange. ${exchangeUnknownSentence("tzmesh", plane)}`;
|
|
9988
|
+
case "minted":
|
|
9989
|
+
return `The run was ended after its exchange minted the run's token, before the register. ${TOKEN_LEFT}`;
|
|
9990
|
+
case "registering":
|
|
9991
|
+
return `The run was ended during the register. ${REGISTER_UNKNOWN} ${TOKEN_LEFT}`;
|
|
9992
|
+
case "registered":
|
|
9993
|
+
return agent === null ? `The run was ended after the register. ${REGISTER_UNKNOWN} ${TOKEN_LEFT}` : "secret" in route ? `The run was ended after the register, while its secret was being stored. ${storeUnknownSentence(route.secret, agent)} ${TOKEN_LEFT}` : `The run was ended after the register, before its secret was written. ${agentStandsSentence(agent)} ${TOKEN_LEFT}`;
|
|
9994
|
+
case "stored":
|
|
9995
|
+
return `The run was ended after the agent's secret was kept, before the run's token was revoked. ${TOKEN_LEFT}`;
|
|
9996
|
+
}
|
|
9997
|
+
};
|
|
9998
|
+
var completing = async (io2, options, mint, tokens, userAgent) => {
|
|
9999
|
+
const { plane, wire } = TZMESH_ESTATE_ORIGINS[options.estate];
|
|
10000
|
+
const route = options.route;
|
|
10001
|
+
const tag = runTagOf();
|
|
10002
|
+
const stage = { now: "unsent", ended: false };
|
|
10003
|
+
let agent = null;
|
|
10004
|
+
const revokedThen = async (minted, status) => {
|
|
10005
|
+
const lines = await revokeRunToken(io2, plane, tokens.mint.token, minted.id, userAgent);
|
|
10006
|
+
if (stage.ended) return COMMAND_STATUS.unknown;
|
|
10007
|
+
if (lines === null) {
|
|
10008
|
+
io2.print(`The run's token, ${minted.id}, is revoked.`);
|
|
10009
|
+
return status;
|
|
10010
|
+
}
|
|
10011
|
+
for (const line of lines) io2.print(line);
|
|
10012
|
+
return Math.max(status, COMMAND_STATUS.failed);
|
|
10013
|
+
};
|
|
10014
|
+
const deletedThen = async (minted, standing) => {
|
|
10015
|
+
const lines = await deleteAgent(io2, wire, minted.value, userAgent, standing);
|
|
10016
|
+
if (stage.ended) return COMMAND_STATUS.unknown;
|
|
10017
|
+
for (const line of lines) io2.print(line);
|
|
10018
|
+
return revokedThen(minted, COMMAND_STATUS.failed);
|
|
10019
|
+
};
|
|
10020
|
+
const carried = {
|
|
10021
|
+
stage,
|
|
10022
|
+
endedLine: (now) => endedLineOf(now, plane, agent, route),
|
|
10023
|
+
// The file's try, by an empty file beside it under the run's tag,
|
|
10024
|
+
// owner-only, before any request (decision 6).
|
|
10025
|
+
prepare: () => {
|
|
10026
|
+
if (!("toFile" in route)) return null;
|
|
10027
|
+
const tried = tryWritingFile(io2, route.toFile, "owner only", tag);
|
|
10028
|
+
return "unwritten" in tried ? toFileUntriedRefusal(tried.unwritten, MINT_UNPRESENTED) : null;
|
|
10029
|
+
},
|
|
10030
|
+
// The store estate's plane check, where the run sends there and it is
|
|
10031
|
+
// not the mint estate's plane, which the act checked first (PLD-L0-110).
|
|
10032
|
+
checks: async () => "secret" in route && options.origin !== plane ? planeWireRefusal(io2, options.origin, "") : null,
|
|
10033
|
+
drop: () => {
|
|
10034
|
+
if ("toFile" in route) dropWritingFile(io2, route.toFile, tag);
|
|
10035
|
+
},
|
|
10036
|
+
refuse: async (minted) => {
|
|
10037
|
+
io2.print(`The exchange minted a token that is not an unmarked tzMesh token of the signed form, so nothing of its value was used or kept. Call ${MINT_TOKEN_ACTION} from your tool again with the members ${TZMESH_ACT_WORDS} prints, and run the line it answers.`);
|
|
10038
|
+
return revokedThen(minted, COMMAND_STATUS.failed);
|
|
10039
|
+
},
|
|
10040
|
+
deliver: async (minted) => {
|
|
10041
|
+
stage.now = "registering";
|
|
10042
|
+
const registered = await register(io2, wire, minted.value, userAgent, options.name);
|
|
10043
|
+
if (stage.ended) return COMMAND_STATUS.unknown;
|
|
10044
|
+
if ("refused" in registered) {
|
|
10045
|
+
for (const line of registered.refused) io2.print(line);
|
|
10046
|
+
return revokedThen(minted, COMMAND_STATUS.failed);
|
|
10047
|
+
}
|
|
10048
|
+
if ("unknown" in registered) {
|
|
10049
|
+
for (const line of registered.unknown) io2.print(line);
|
|
10050
|
+
io2.print(REGISTER_UNKNOWN);
|
|
10051
|
+
return revokedThen(minted, COMMAND_STATUS.unknown);
|
|
10052
|
+
}
|
|
10053
|
+
if ("standing" in registered) {
|
|
10054
|
+
agent = registered.standing;
|
|
10055
|
+
stage.now = "registered";
|
|
10056
|
+
for (const line of registered.lines) io2.print(line);
|
|
10057
|
+
return deletedThen(minted, registered.standing);
|
|
10058
|
+
}
|
|
10059
|
+
agent = registered.agent;
|
|
10060
|
+
const secret2 = registered.secret;
|
|
10061
|
+
stage.now = "registered";
|
|
10062
|
+
io2.print(registeredLineOf(agent, wire));
|
|
10063
|
+
if ("toFile" in route) {
|
|
10064
|
+
const written = writeThenRename(io2, route.toFile, `${secret2}
|
|
10065
|
+
`, "owner only", tag);
|
|
10066
|
+
if (stage.ended) return COMMAND_STATUS.unknown;
|
|
10067
|
+
if ("unwritten" in written) {
|
|
10068
|
+
io2.print(`The file ${TZMESH_OPTION.toFile} names could not be written (${written.unwritten}), so the agent's secret was not kept.`);
|
|
10069
|
+
return deletedThen(minted, agent);
|
|
10070
|
+
}
|
|
10071
|
+
stage.now = "stored";
|
|
10072
|
+
io2.print(WRITTEN_LINE);
|
|
10073
|
+
return revokedThen(minted, COMMAND_STATUS.done);
|
|
10074
|
+
}
|
|
10075
|
+
const action = SECRET_ACTION.store;
|
|
10076
|
+
const answered = await postAction(io2, options.origin, action, (tokens.store ?? tokens.mint).token, userAgent, {
|
|
10077
|
+
name: route.secret,
|
|
10078
|
+
value: secret2,
|
|
10079
|
+
...options.application !== null ? { application: options.application } : {},
|
|
10080
|
+
...options.environment !== null ? { environment: options.environment } : {}
|
|
10081
|
+
});
|
|
10082
|
+
if (stage.ended) return COMMAND_STATUS.unknown;
|
|
10083
|
+
const unknownStore = async (lines) => {
|
|
10084
|
+
for (const line of lines) io2.print(line);
|
|
10085
|
+
io2.print(storeUnknownSentence(route.secret, agent));
|
|
10086
|
+
return revokedThen(minted, COMMAND_STATUS.unknown);
|
|
10087
|
+
};
|
|
10088
|
+
if (answered === null) return unknownStore([`${action} drew no answer.`]);
|
|
10089
|
+
if (answered.redirected) return unknownStore([`${action} was answered ${answeredHow(answered.status)}, which the command never follows, so the value was sent to no second address.`]);
|
|
10090
|
+
if (answered.status >= PLATFORM_FAILURE_STATUS) return unknownStore(failureLines(action, answered.status, planeRefusalOf(answered.text)));
|
|
10091
|
+
const answer = planeObjectOf(answered.text);
|
|
10092
|
+
if (answered.status < 200 || answered.status > 299) {
|
|
10093
|
+
const refusal = markedRefusalOf(answered.status, answered.text);
|
|
10094
|
+
if (refusal === null) return unknownStore([`${action} was answered HTTP ${answered.status}, not by the platform.`]);
|
|
10095
|
+
for (const line of refusalLines(action, answered.status, refusal)) io2.print(line);
|
|
10096
|
+
return deletedThen(minted, agent);
|
|
10097
|
+
}
|
|
10098
|
+
if (answer === null) return unknownStore([`${action} was answered HTTP ${answered.status}, not by the platform.`]);
|
|
10099
|
+
stage.now = "stored";
|
|
10100
|
+
io2.print(`${SECRET_LINE_HEAD.store}${JSON.stringify(Object.fromEntries(SECRET_SHOWN.filter((member) => member in answer).map((member) => [member, answer[member]])))}`);
|
|
10101
|
+
if (typeof answer.detail === "string") io2.print(oneLine(answer.detail));
|
|
10102
|
+
if ("value" in answer) io2.print("The answer carried a value, which the command never prints.");
|
|
10103
|
+
return revokedThen(minted, COMMAND_STATUS.done);
|
|
10104
|
+
}
|
|
10105
|
+
};
|
|
10106
|
+
return completeAct(io2, plane, "tzmesh", { mint }, userAgent, io2.print, void 0, null, carried);
|
|
10107
|
+
};
|
|
10108
|
+
async function tzmeshRegister(call, io2) {
|
|
10109
|
+
const options = tzmeshOptionsOf(call, io2);
|
|
10110
|
+
if ("refusal" in options) {
|
|
10111
|
+
io2.print(options.refusal);
|
|
10112
|
+
return COMMAND_STATUS.nothing_started;
|
|
10113
|
+
}
|
|
10114
|
+
const closing = options.mint !== null ? MINT_UNPRESENTED : NOTHING_SENT;
|
|
10115
|
+
const agent = userAgentOf(io2.env);
|
|
10116
|
+
if ("refusal" in agent) {
|
|
10117
|
+
io2.print(`${agent.refusal} ${options.mint !== null ? MINT_UNPRESENTED : ""}`.trimEnd());
|
|
10118
|
+
return COMMAND_STATUS.nothing_started;
|
|
10119
|
+
}
|
|
10120
|
+
if ((io2.env[MINTED_TOKEN_VARIABLE] ?? "").trim() !== "") {
|
|
10121
|
+
io2.print(tzmeshMintedTokenRefusal(closing));
|
|
10122
|
+
return COMMAND_STATUS.nothing_started;
|
|
10123
|
+
}
|
|
10124
|
+
const { plane } = TZMESH_ESTATE_ORIGINS[options.estate];
|
|
10125
|
+
const tokens = readComputerTokens(io2, plane, "secret" in options.route ? options.origin : null, closing);
|
|
10126
|
+
if ("status" in tokens) return tokens.status;
|
|
10127
|
+
io2.hide(tokens.mint.token, REDACTED_TOKEN);
|
|
10128
|
+
if (tokens.store !== null) io2.hide(tokens.store.token, REDACTED_TOKEN);
|
|
10129
|
+
if ("toFile" in options.route) {
|
|
10130
|
+
const refused = toFileRefusalOf(io2, options.route.toFile, options.force, closing);
|
|
10131
|
+
if (refused !== null) {
|
|
10132
|
+
io2.print(refused);
|
|
10133
|
+
return COMMAND_STATUS.nothing_started;
|
|
10134
|
+
}
|
|
10135
|
+
}
|
|
10136
|
+
if (options.mint !== null) return completing(io2, options, options.mint, tokens, agent.userAgent);
|
|
10137
|
+
if ("toFile" in options.route) {
|
|
10138
|
+
const path = options.route.toFile;
|
|
10139
|
+
const tag = runTagOf();
|
|
10140
|
+
const release = io2.whenEnded(() => dropWritingFile(io2, path, tag));
|
|
10141
|
+
try {
|
|
10142
|
+
const tried = tryWritingFile(io2, path, "owner only", tag);
|
|
10143
|
+
if ("unwritten" in tried) {
|
|
10144
|
+
io2.print(toFileUntriedRefusal(tried.unwritten, closing));
|
|
10145
|
+
return COMMAND_STATUS.nothing_started;
|
|
10146
|
+
}
|
|
10147
|
+
} finally {
|
|
10148
|
+
dropWritingFile(io2, path, tag);
|
|
10149
|
+
release();
|
|
10150
|
+
}
|
|
10151
|
+
}
|
|
10152
|
+
return firstAct(io2, plane, "tzmesh", io2.print, null, completingOptionsOf(options));
|
|
10153
|
+
}
|
|
10154
|
+
var TZMESH_READS = `this computer's token for each address it sends to, and the verifier its first act keeps, from its credential file. It never reads a minted token from ${MINTED_TOKEN_VARIABLE}, and refuses the run where that variable is set`;
|
|
10155
|
+
var TZMESH_AFTER_OWN_ERROR = "whether the run's token was minted, the agent registered, or its secret kept is unknown. list_tokens from your tool shows the token by its label, turnzero command, and revoke_token ends it. tzmesh_participants shows the agent, and end with delete true deletes it";
|
|
10156
|
+
var TZMESH_FIRST_ACT_AFTER_OWN_ERROR = "a request may now be pending in this computer's credential file, and nothing was sent";
|
|
10157
|
+
var TZMESH_ROW = Object.freeze({
|
|
10158
|
+
name: TZMESH_SUBCOMMAND,
|
|
10159
|
+
acts: Object.freeze([TZMESH_REGISTER_ACT]),
|
|
10160
|
+
summary: `Registers a tzMesh standing agent, and keeps its program secret where a program reads it, never printing it. It keeps the secret in your account's secret store by name, or in a file. It runs in two acts around one ${MINT_TOKEN_ACTION} call your tool makes.`,
|
|
10161
|
+
example: `${TZMESH_ACT_WORDS} ${TZMESH_OPTION.name} <name> ${TZMESH_OPTION.secret} <secret name> ${TZMESH_OPTION.application} <application id> ${TZMESH_OPTION.environment} production`,
|
|
10162
|
+
options: TZMESH_OPTIONS,
|
|
10163
|
+
credential: null,
|
|
10164
|
+
reads: TZMESH_READS,
|
|
10165
|
+
statuses: {
|
|
10166
|
+
done: "the challenge printed, or the agent registered, its secret kept, and the run's token revoked",
|
|
10167
|
+
failed: "a part failed: the agent was not registered, its secret was not kept, or the run's token was not revoked. The printed lines name what stands and the call that ends it",
|
|
10168
|
+
unknown: "an outcome is unknown: the printed lines name list_tokens, tzmesh_participants, or list_secrets",
|
|
10169
|
+
nothing_started: `nothing was minted. An option, the credential file, the file ${TZMESH_OPTION.toFile} names, or this computer's token was refused. Or no request was pending, the platform was too old, or the exchange was refused`
|
|
10170
|
+
},
|
|
10171
|
+
variables: [[ORIGIN_VARIABLE, `the platform's address the secret is stored at where the line names no ${TZMESH_OPTION.origin}. It must be ${DEFAULT_COMMAND_ORIGIN} or ${DEVELOPMENT_COMMAND_ORIGIN}.`]],
|
|
10172
|
+
note: [
|
|
10173
|
+
`Registering an agent takes two acts around one ${MINT_TOKEN_ACTION} call, which your signed-in tool makes itself. ${TZMESH_ACT_WORDS} run without ${TZMESH_OPTION.mint} prints a challenge, the call to make, and the options its completing line takes. Your tool makes that call, and runs the line it answers once, on this computer, with those options after it. That line holds no code.`,
|
|
10174
|
+
`The completing line presents this computer's verifier and receives a tzMesh token minted for this run alone. It registers the agent with that token, keeps the agent's secret, and revokes the token. Where the secret could not be kept, it deletes the agent.`,
|
|
10175
|
+
`With ${TZMESH_OPTION.secret}, the secret goes from the register's answer to your account's secret store, and never reaches your tool. With ${TZMESH_OPTION.toFile}, it goes into that file, which anything that runs as you can read, your tool among them. Keep that file outside any application's folder.`,
|
|
10176
|
+
`The run reads this computer's token for each address it sends to: the ${TZMESH_OPTION.tzmeshEstate} platform's, to revoke the run's token, and under ${TZMESH_OPTION.secret} the ${TZMESH_OPTION.origin} platform's, to store the secret. Authorize this computer at each first.`
|
|
10177
|
+
],
|
|
10178
|
+
afterOwnError: (call) => call.named[TZMESH_OPTION.mint] !== void 0 ? TZMESH_AFTER_OWN_ERROR : TZMESH_FIRST_ACT_AFTER_OWN_ERROR,
|
|
10179
|
+
listed: TZMESH_LISTED,
|
|
10180
|
+
run: tzmeshRegister
|
|
10181
|
+
});
|
|
10182
|
+
|
|
9627
10183
|
// src/turnzero_cloud_command/process_io.ts
|
|
9628
10184
|
import { spawn } from "node:child_process";
|
|
9629
10185
|
import { chmodSync, closeSync, openSync, readFileSync as readFileSync5, realpathSync as realpathSync2, writeFileSync, writeSync } from "node:fs";
|
|
@@ -9632,7 +10188,7 @@ import { createServer } from "node:http";
|
|
|
9632
10188
|
import { constants as constants2 } from "node:os";
|
|
9633
10189
|
import { sep as sep5 } from "node:path";
|
|
9634
10190
|
import { ReadStream, isatty } from "node:tty";
|
|
9635
|
-
var listenLoopback = (answer) => new Promise((
|
|
10191
|
+
var listenLoopback = (answer) => new Promise((resolve14) => {
|
|
9636
10192
|
const server = createServer((request, response) => {
|
|
9637
10193
|
const url = new URL(request.url ?? "/", "http://127.0.0.1");
|
|
9638
10194
|
const query = {};
|
|
@@ -9649,16 +10205,16 @@ var listenLoopback = (answer) => new Promise((resolve13) => {
|
|
|
9649
10205
|
}
|
|
9650
10206
|
);
|
|
9651
10207
|
});
|
|
9652
|
-
server.once("error", () =>
|
|
10208
|
+
server.once("error", () => resolve14(null));
|
|
9653
10209
|
server.listen(0, "127.0.0.1", () => {
|
|
9654
10210
|
const address = server.address();
|
|
9655
10211
|
if (address === null || typeof address === "string") {
|
|
9656
10212
|
server.close();
|
|
9657
|
-
|
|
10213
|
+
resolve14(null);
|
|
9658
10214
|
return;
|
|
9659
10215
|
}
|
|
9660
10216
|
let closed = false;
|
|
9661
|
-
|
|
10217
|
+
resolve14({
|
|
9662
10218
|
port: address.port,
|
|
9663
10219
|
close: () => {
|
|
9664
10220
|
if (closed) return;
|
|
@@ -9751,7 +10307,7 @@ var holdSignals = (signals, inputIsTerminal, passesOn, passOn, onInterrupt) => {
|
|
|
9751
10307
|
for (const [signal, handler] of held) signals.off(signal, handler);
|
|
9752
10308
|
};
|
|
9753
10309
|
};
|
|
9754
|
-
var childRunnerOf = (signals, inputIsTerminal, passesOn = SIGNALS_PASS_ON, groups = CHILD_GROUPS) => (run) => new Promise((
|
|
10310
|
+
var childRunnerOf = (signals, inputIsTerminal, passesOn = SIGNALS_PASS_ON, groups = CHILD_GROUPS) => (run) => new Promise((resolve14) => {
|
|
9755
10311
|
const output = run.output;
|
|
9756
10312
|
let interrupted = false;
|
|
9757
10313
|
const group = run.foreground === true && passesOn && groups;
|
|
@@ -9768,8 +10324,8 @@ var childRunnerOf = (signals, inputIsTerminal, passesOn = SIGNALS_PASS_ON, group
|
|
|
9768
10324
|
child.stdout?.setEncoding("utf8").on("data", (chunk) => output(chunk, "stdout"));
|
|
9769
10325
|
child.stderr?.setEncoding("utf8").on("data", (chunk) => output(chunk, "stderr"));
|
|
9770
10326
|
}
|
|
9771
|
-
child.once("error", (error) =>
|
|
9772
|
-
child.once("close", (status, signal) =>
|
|
10327
|
+
child.once("error", (error) => resolve14({ status: null, signal: null, error: startErrorOf(error) }));
|
|
10328
|
+
child.once("close", (status, signal) => resolve14({ status, signal, error: null, ...interrupted ? { interrupted: true } : {} }));
|
|
9773
10329
|
if (run.foreground) {
|
|
9774
10330
|
const release = holdSignals(
|
|
9775
10331
|
signals,
|
|
@@ -9794,7 +10350,7 @@ var childRunnerOf = (signals, inputIsTerminal, passesOn = SIGNALS_PASS_ON, group
|
|
|
9794
10350
|
child.once("close", release);
|
|
9795
10351
|
}
|
|
9796
10352
|
} catch (error) {
|
|
9797
|
-
|
|
10353
|
+
resolve14({ status: null, signal: null, error: startErrorOf(error) });
|
|
9798
10354
|
}
|
|
9799
10355
|
});
|
|
9800
10356
|
var runChild = childRunnerOf(process, () => isatty(0));
|
|
@@ -9839,7 +10395,7 @@ var processIo = () => ({
|
|
|
9839
10395
|
// hold a subcommand lets go after a pause has seen it (scaffold.ts;
|
|
9840
10396
|
// PLD-L0-103). A bare timer of no length ends before the loop polls, and
|
|
9841
10397
|
// the signal would be dropped with the hold.
|
|
9842
|
-
sleep: (ms) => new Promise((
|
|
10398
|
+
sleep: (ms) => new Promise((resolve14) => setTimeout(() => setImmediate(resolve14), ms)),
|
|
9843
10399
|
schedule: (ms, fire) => {
|
|
9844
10400
|
const timer = setTimeout(fire, ms);
|
|
9845
10401
|
return () => clearTimeout(timer);
|
|
@@ -9865,17 +10421,19 @@ var processIo = () => ({
|
|
|
9865
10421
|
},
|
|
9866
10422
|
errorIsTerminal: process.stderr.isTTY === true,
|
|
9867
10423
|
outputIsTerminal: process.stdout.isTTY === true,
|
|
9868
|
-
// The one value line (PLD-L0-94): a
|
|
9869
|
-
//
|
|
10424
|
+
// The one value line (PLD-L0-94; PLD-L0-104): a value of a form `token
|
|
10425
|
+
// claim` prints, the minted token's or a product's signed form since
|
|
10426
|
+
// #7168, alone and whole on standard output; any other text is written as
|
|
10427
|
+
// print writes it.
|
|
9870
10428
|
printValue: (value) => {
|
|
9871
|
-
process.stdout.write(`${
|
|
10429
|
+
process.stdout.write(`${isClaimableToken(value) ? value : redactCredentials(value)}
|
|
9872
10430
|
`);
|
|
9873
10431
|
}
|
|
9874
10432
|
});
|
|
9875
|
-
var writeWhole = (fd2, chunk) => new Promise((
|
|
10433
|
+
var writeWhole = (fd2, chunk) => new Promise((resolve14, reject) => {
|
|
9876
10434
|
const from = (offset) => {
|
|
9877
10435
|
if (offset >= chunk.length) {
|
|
9878
|
-
|
|
10436
|
+
resolve14();
|
|
9879
10437
|
return;
|
|
9880
10438
|
}
|
|
9881
10439
|
writeAt(fd2, chunk, offset, chunk.length - offset, null, (error, written) => error ? reject(error) : from(offset + written));
|
|
@@ -9956,10 +10514,12 @@ var SUBCOMMANDS = Object.freeze([
|
|
|
9956
10514
|
TOKEN_ROW,
|
|
9957
10515
|
LOGIN_ROW,
|
|
9958
10516
|
WHOAMI_ROW,
|
|
9959
|
-
SESSION_ROW
|
|
10517
|
+
SESSION_ROW,
|
|
10518
|
+
TZMESH_ROW
|
|
9960
10519
|
]);
|
|
10520
|
+
var listedSubcommands = () => SUBCOMMANDS.filter((subcommand) => subcommand.listed !== false);
|
|
9961
10521
|
var SERVED = LINE_RUNNER;
|
|
9962
|
-
var NPX_FORM_SENTENCE = `Where the command is not installed, install it with ${installLineOf(DEFAULT_COMMAND_ORIGIN)}. A person or a job may instead run the same line through npx: write ${commandRunnerOf("latest")} for ${LINE_RUNNER}. A tool where the command is not installed
|
|
10522
|
+
var NPX_FORM_SENTENCE = `Where the command is not installed, install it with ${installLineOf(DEFAULT_COMMAND_ORIGIN)}. A person or a job may instead run the same line through npx: write ${commandRunnerOf("latest")} for ${LINE_RUNNER}. A tool where the command is not installed deploys through deploy_files within its caps and the upload route past them. For any other line it takes the deploy skill's setup steps, never the npx line.`;
|
|
9963
10523
|
var namedWithActs = (subcommand) => subcommand.acts ? `${subcommand.name} ${subcommand.acts.join("|")}` : subcommand.name;
|
|
9964
10524
|
var shown = (option) => option.flag ? option.name : `${option.name} ${option.value}`;
|
|
9965
10525
|
var listed = (names) => names.length < 3 ? names.join(" and ") : `${names.slice(0, -1).join(", ")}, and ${names[names.length - 1]}`;
|
|
@@ -9983,9 +10543,9 @@ var usageLineOf = (subcommand) => {
|
|
|
9983
10543
|
return `${pipedHead(subcommand)}${SERVED} ${[namedWithActs(subcommand), ...required, ...optional].join(" ")}`;
|
|
9984
10544
|
};
|
|
9985
10545
|
var usageHeadOf = (version) => `${TURNZERO_CLOUD_PACKAGE} ${version}: the Turn Zero Cloud command, installed from the public npm registry by your platform's tag, latest on production and next on development.`;
|
|
9986
|
-
var unreadNames = () =>
|
|
9987
|
-
var unattendedNames = () =>
|
|
9988
|
-
var computerOnlyNames = () =>
|
|
10546
|
+
var unreadNames = () => listedSubcommands().filter((subcommand) => subcommand.credential === null && subcommand.reads === void 0).map((subcommand) => subcommand.name);
|
|
10547
|
+
var unattendedNames = () => listedSubcommands().filter((subcommand) => subcommand.credential?.mintedToken === true).map((subcommand) => subcommand.name);
|
|
10548
|
+
var computerOnlyNames = () => listedSubcommands().filter((subcommand) => subcommand.credential?.computerToken === true).map((subcommand) => subcommand.name);
|
|
9989
10549
|
var exampleLineOf = (subcommand) => {
|
|
9990
10550
|
const credential = subcommand.credential;
|
|
9991
10551
|
const mustPipe = credential !== null && credential.piped !== false && credential.bare === void 0 && credential.computerToken !== true;
|
|
@@ -10025,7 +10585,7 @@ var statusClauseOf = (name, clause) => `Under ${name}, ${clause}`;
|
|
|
10025
10585
|
var noteLinesOf2 = (subcommand) => (subcommand.note ?? []).flatMap((paragraph) => ["", paragraph]);
|
|
10026
10586
|
var usageBlockOf = (subcommandHelp) => [
|
|
10027
10587
|
"Usage:",
|
|
10028
|
-
...
|
|
10588
|
+
...listedSubcommands().map((subcommand) => ` ${usageLineOf(subcommand)}`),
|
|
10029
10589
|
` ${SERVED} --version`,
|
|
10030
10590
|
` ${SERVED} --help`,
|
|
10031
10591
|
...subcommandHelp ? [` ${SERVED} <subcommand> --help`] : []
|
|
@@ -10044,7 +10604,7 @@ var shortUsageText = (version = commandVersion()) => [
|
|
|
10044
10604
|
...STATUS_MEANINGS.map(([status, meaning, also]) => statusLineOf(status, meaning, [], also)),
|
|
10045
10605
|
"",
|
|
10046
10606
|
"Subcommands:",
|
|
10047
|
-
...
|
|
10607
|
+
...listedSubcommands().map((subcommand) => ` ${namedWithActs(subcommand)}: ${subcommand.summary}`),
|
|
10048
10608
|
"",
|
|
10049
10609
|
SUBCOMMAND_HELP_SENTENCE
|
|
10050
10610
|
].join("\n");
|
|
@@ -10086,7 +10646,7 @@ var valuePlacesOf = (argv2) => {
|
|
|
10086
10646
|
}
|
|
10087
10647
|
return places;
|
|
10088
10648
|
};
|
|
10089
|
-
var noSubcommandSentence = (first) => `${first === void 0 ? "No subcommand was named" : `The first argument is not a subcommand of ${TURNZERO_CLOUD_PACKAGE}`}: the subcommands are ${
|
|
10649
|
+
var noSubcommandSentence = (first) => `${first === void 0 ? "No subcommand was named" : `The first argument is not a subcommand of ${TURNZERO_CLOUD_PACKAGE}`}: the subcommands are ${listedSubcommands().map((entry) => entry.name).join(", ")}. ${NOTHING_STARTED2}`;
|
|
10090
10650
|
var parseArguments = (argv2, onWindows2 = ON_WINDOWS) => {
|
|
10091
10651
|
if (argv2.some((argument) => argument.includes(UPLOAD_GRANT_PREFIX))) return { kind: "refused", sentence: grantArgumentSentence() };
|
|
10092
10652
|
if (argv2.some((argument) => argument.includes(MINTED_TOKEN_PREFIX))) return { kind: "refused", sentence: tokenArgumentSentence() };
|