turnzero 0.30.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 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 guides you through connecting Turn Zero Cloud, signing in or creating a free account, and building a demo you can open in your browser.
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
 
@@ -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((resolve13) => {
844
+ var readStandardInputEnded = (input, boundMs = GRANT_READ_BOUND_MS) => new Promise((resolve14) => {
793
845
  if (input.isTTY) {
794
- resolve13({ text: "", bytes: 0, ending: "terminal" });
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
- resolve13({ text: Buffer.concat(chunks).toString("utf8"), bytes, ending });
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 minted token's value is printed whole",
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 (!MINTED_TOKEN_FORM.test(value)) throw new Error(VALUE_LINE_REFUSED.form);
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) => `${kind === "authorized computer" ? AUTHORIZE_SUBCOMMAND : `${TOKEN_SUBCOMMAND} ${TOKEN_REQUEST_ACT}`}${originWordsOf(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 firstActLines = (origin, kind, pending, label, loginLines = []) => [
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" || !MINTED_TOKEN_FORM.test(value)) return null;
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. A folder within the caps of the tool's deploy_files call deploys now through deploy_files, with no login. The credential file is ${CREDENTIAL_FILE_WORDS}.`,
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((resolve13) => {
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
- resolve13(read2);
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((resolve13) => {
5798
- cancel = io2.schedule(OPENER_WAIT_MS, () => resolve13("waiting"));
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((resolve13) => {
5880
- settle = resolve13;
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((resolve13) => {
5885
- outcome = resolve13;
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. ${authorizeRouteSentence(origin)} ${PROVISION_SUBCOMMAND}${originWordsOf(origin)} run so prints the call that answers its line.`;
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, ${AUTHORIZE_SUBCOMMAND}, and ${PROVISION_SUBCOMMAND}), then prints the login route. It prints no token.`,
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((resolve13) => {
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", () => resolve13(null));
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
- resolve13(null);
10213
+ resolve14(null);
9658
10214
  return;
9659
10215
  }
9660
10216
  let closed = false;
9661
- resolve13({
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((resolve13) => {
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) => resolve13({ status: null, signal: null, error: startErrorOf(error) }));
9772
- child.once("close", (status, signal) => resolve13({ status, signal, error: null, ...interrupted ? { interrupted: true } : {} }));
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
- resolve13({ status: null, signal: null, error: startErrorOf(error) });
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((resolve13) => setTimeout(() => setImmediate(resolve13), ms)),
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 minted token's value alone, whole, on
9869
- // standard output; any other text is written as print writes it.
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(`${MINTED_TOKEN_FORM.test(value) ? value : redactCredentials(value)}
10429
+ process.stdout.write(`${isClaimableToken(value) ? value : redactCredentials(value)}
9872
10430
  `);
9873
10431
  }
9874
10432
  });
9875
- var writeWhole = (fd2, chunk) => new Promise((resolve13, reject) => {
10433
+ var writeWhole = (fd2, chunk) => new Promise((resolve14, reject) => {
9876
10434
  const from = (offset) => {
9877
10435
  if (offset >= chunk.length) {
9878
- resolve13();
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 uses deploy_files within its caps, or the deploy skill's setup steps, never the npx line.`;
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 = () => SUBCOMMANDS.filter((subcommand) => subcommand.credential === null && subcommand.reads === void 0).map((subcommand) => subcommand.name);
9987
- var unattendedNames = () => SUBCOMMANDS.filter((subcommand) => subcommand.credential?.mintedToken === true).map((subcommand) => subcommand.name);
9988
- var computerOnlyNames = () => SUBCOMMANDS.filter((subcommand) => subcommand.credential?.computerToken === true).map((subcommand) => subcommand.name);
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
- ...SUBCOMMANDS.map((subcommand) => ` ${usageLineOf(subcommand)}`),
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
- ...SUBCOMMANDS.map((subcommand) => ` ${namedWithActs(subcommand)}: ${subcommand.summary}`),
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 ${SUBCOMMANDS.map((entry) => entry.name).join(", ")}. ${NOTHING_STARTED2}`;
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() };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "turnzero",
3
- "version": "0.30.1",
3
+ "version": "0.31.1-next.1",
4
4
  "type": "module",
5
5
  "description": "Deploy and run AI-built apps with Turn Zero Cloud hosting and backend services.",
6
6
  "license": "Apache-2.0",