turnzero 0.20.0 → 0.21.0

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.
@@ -185,6 +185,7 @@ var libraryTakeLineOf = (call) => commandLineOf(call.origin, LIBRARY_SUBCOMMAND,
185
185
  });
186
186
  var PROVISION_SUBCOMMAND = "provision";
187
187
  var PROVISION_OPTION = Object.freeze({ application: SECRET_OPTION.application, envFile: "--env-file", origin: DEPLOY_OPTION.origin });
188
+ var PROVISION_CLAIM_FLAG = "--claim";
188
189
  var PROVISION_ACTION = SECRET_ACTION.rotate;
189
190
  var PROVISION_ENVIRONMENT = "development";
190
191
  var platformCredentialNameOf = (application) => `credential-${application}`;
@@ -1014,7 +1015,6 @@ var mintCallMembers = (kind, challenge, label) => kind === "authorized computer"
1014
1015
  [AUTHORIZED_COMPUTER_MEMBER, true],
1015
1016
  ["label", label]
1016
1017
  ] : [[CODE_CHALLENGE_MEMBER, challenge]];
1017
- var firstActWayOn = (kind) => kind === "authorized computer" ? `Where the platform refuses ${CODE_CHALLENGE_MEMBER}, it does not yet serve this authorization: deploy by the line your tool's deploy call answers until the platform's next release.` : `Where the platform refuses ${CODE_CHALLENGE_MEMBER}, it does not yet serve this mint: until the platform's next release, ${MINT_TOKEN_ACTION} without it answers the token's value as it does today.`;
1018
1018
  var firstActNamed = (kind, origin = DEFAULT_COMMAND_ORIGIN) => `${kind === "authorized computer" ? AUTHORIZE_SUBCOMMAND : `${TOKEN_SUBCOMMAND} ${TOKEN_REQUEST_ACT}`}${originWordsOf(origin)}`;
1019
1019
  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.`;
1020
1020
  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.`;
@@ -1027,8 +1027,7 @@ var firstActLines = (origin, kind, pending, label, loginLines = []) => [
1027
1027
  CALL_LINE_HEAD,
1028
1028
  ...mintCallMembers(kind, pending.challenge, label).map(([name, value]) => ` ${name}: ${JSON.stringify(value)}`),
1029
1029
  kind === "authorized computer" ? `The line 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: it 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.`,
1030
- ...kind === "authorized computer" && loginLines.length > 0 ? [loginWaySentence(loginLines)] : [],
1031
- firstActWayOn(kind)
1030
+ ...kind === "authorized computer" && loginLines.length > 0 ? [loginWaySentence(loginLines)] : []
1032
1031
  ];
1033
1032
  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.`;
1034
1033
  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.`;
@@ -2679,7 +2678,6 @@ var isRecord = (value) => typeof value === "object" && value !== null && !Array.
2679
2678
  var ROOT_FILE_MAX_BYTES = 1024 * 1024;
2680
2679
  var MEMBER_FILE_MAX_BYTES = 64 * 1024;
2681
2680
  var MEMBER_FILES_READ_MAX = 50;
2682
- var WINDOWS_ZIP_COMMAND = "tar.exe -a -c -f app.zip --exclude node_modules --exclude .env --exclude '.env.*' --exclude .git --exclude .claude --exclude .mcp.json --exclude .codex --exclude .cursor --exclude .gemini --exclude .continue --exclude .roo --exclude .kiro --exclude .amazonq --exclude .aider.conf.yml -C app .";
2683
2681
  function readArtifact(bytes) {
2684
2682
  const stored = [];
2685
2683
  const names = [];
@@ -2756,6 +2754,7 @@ function readArtifact(bytes) {
2756
2754
  records
2757
2755
  };
2758
2756
  }
2757
+ var WINDOWS_ZIP_STEP_ROUTE = "/cloud/getting-started/deploy-an-application/#3-build-and-upload-the-artifact";
2759
2758
  function entryRefusalDetail(refused) {
2760
2759
  const named = `The zip's entry ${shownEntry(refused.entry)} ${refused.reason}`;
2761
2760
  if (refused.cause === "file_and_folder") return `${named}, and the image build cannot write one path as both a file and a folder: remove one of the two entries, and deploy again`;
@@ -2763,7 +2762,7 @@ function entryRefusalDetail(refused) {
2763
2762
  if (refused.cause === "too_many_segments") return `${named}: deploy the application's own files alone, without node_modules or build caches, and deploy again`;
2764
2763
  const rule = "the image build takes an entry only as a relative path inside the zip's root, with / between its segments";
2765
2764
  if (refused.cause === "backslash") {
2766
- return `${named}, and ${rule}. Windows PowerShell's Compress-Archive writes a backslash there: build the zip with tar.exe from the folder that holds the application's folder, as in \`${WINDOWS_ZIP_COMMAND}\` where that folder is app, and deploy again`;
2765
+ return `${named}, and the image build takes / alone between a name's segments. Windows PowerShell's Compress-Archive writes one: use the tar.exe command read_documentation page ${WINDOWS_ZIP_STEP_ROUTE} gives, and deploy again`;
2767
2766
  }
2768
2767
  return `${named}, and ${rule}: zip the contents of the folder that holds package.json with a tool that writes relative names, and deploy again`;
2769
2768
  }
@@ -6039,6 +6038,13 @@ var PROVISION_OPTIONS = Object.freeze([
6039
6038
  value: "<origin>",
6040
6039
  required: false,
6041
6040
  description: `The platform's address, which is also written as ${LOCAL_RUN_SETTING.api} and ${LOCAL_RUN_SETTING.gatewayUrl}. Where absent, ${DEFAULT_COMMAND_ORIGIN}; with no grant piped, the address ${ORIGIN_VARIABLE} holds where it is set. Under ${MINTED_TOKEN_VARIABLE} the token is sent only to the address ${ORIGIN_VARIABLE} holds, or to ${DEFAULT_COMMAND_ORIGIN} where it is unset. Otherwise, with no grant piped, it names the address whose token the command reads from this computer's credential file, and that token is sent to that address alone.`
6041
+ },
6042
+ {
6043
+ name: PROVISION_CLAIM_FLAG,
6044
+ value: "",
6045
+ required: false,
6046
+ flag: true,
6047
+ description: `With no token for the address, presents this computer's pending verifier, the one the first act kept, as the credential of the provision grant the submit_manifest call recorded, so the line pipes nothing. Where the platform holds no such grant, the run prints the first act. Under a token it runs as the line without it does, and a grant piped beside it is refused.`
6042
6048
  }
6043
6049
  ]);
6044
6050
  var PROVISION_CREDENTIAL = Object.freeze({
@@ -6050,6 +6056,9 @@ var PROVISION_CREDENTIAL = Object.freeze({
6050
6056
  bare: `with nothing piped and neither token, it keeps a verifier and prints the challenge and the submit_manifest call naming local_run and ${CODE_CHALLENGE_MEMBER}, and a grant piped is presented with that verifier`
6051
6057
  });
6052
6058
  var NOTHING_REMINTED = "Nothing was re-minted, and the environment file is as it stood.";
6059
+ var CLAIM_FALLBACK_ERRORS = Object.freeze(["authentication_required", "secret_grant_not_admitted", "secret_grant_expired", "secret_grant_spent"]);
6060
+ var claimRefusedSentence = (origin, error) => `This computer's pending verifier was presented to ${origin}, which holds no provision grant it claims (${error}), so nothing was re-minted, and the first act follows.`;
6061
+ var CLAIM_BESIDE_GRANT_REFUSAL = `${PROVISION_CLAIM_FLAG} presents this computer's pending verifier in place of a grant, so a grant piped beside it is refused: run the line the submit_manifest call answered as given. ${NOTHING_REMINTED}`;
6053
6062
  var PROVISION_BARE_LINE_WORDS = commandLineOf(DEFAULT_COMMAND_ORIGIN, PROVISION_SUBCOMMAND, { options: [[PROVISION_OPTION.application, "<application id>"]] });
6054
6063
  var freshLineOf = (io2, application, origin, envFile) => provisionLineFor(io2, { origin, application, ...envFile !== void 0 ? { envFile } : {} });
6055
6064
  var freshLineSteps2 = (line) => `${line} with nothing piped, and where it prints a submit_manifest call, make that call from your tool and run the line it answers as given`;
@@ -6071,7 +6080,7 @@ var provisionOptionsOf = (call, cwd, stands = () => false) => {
6071
6080
  if ("refusal" in origin) return origin;
6072
6081
  const envFile = environmentFileOf(cwd, call.named[PROVISION_OPTION.envFile]);
6073
6082
  if (!environmentFileName(basename3(envFile))) return { refusal: envFileNameRefusalOf(stands(envFile)) };
6074
- return { application, envFile, origin: origin.origin };
6083
+ return { application, envFile, origin: origin.origin, claim: call.flags.has(PROVISION_CLAIM_FLAG) };
6075
6084
  };
6076
6085
  var APPLICATION_FOLDER_MARKS = Object.freeze(["package.json", "manifest.json"]);
6077
6086
  var outsideApplicationWarningOf = (folder) => `warning: ${folder} holds neither ${APPLICATION_FOLDER_MARKS[0]} nor ${APPLICATION_FOLDER_MARKS[1]}, so it may not be the application's folder, and the environment file was written there all the same. Where the application stands in another folder, move the file into that folder: a local run reads the environment file from the folder it runs in.`;
@@ -6229,12 +6238,20 @@ async function provision(call, io2) {
6229
6238
  io2.print(noCredentialRefusal(PROVISION_CREDENTIAL, read2.unauthorized.origin, read2.unauthorized.expiredAt, ""));
6230
6239
  return COMMAND_STATUS.nothing_started;
6231
6240
  }
6241
+ if (options.claim) {
6242
+ const claimed2 = await claimRun(io2, call, options, agent.userAgent, standing.text, namedEnvFile, read2.unauthorized);
6243
+ if (claimed2 !== null) return claimed2;
6244
+ }
6232
6245
  return firstProvisionAct(io2, call, options.application, namedEnvFile, read2.unauthorized);
6233
6246
  }
6234
6247
  if ("refusal" in read2) {
6235
6248
  io2.print(read2.refusal);
6236
6249
  return COMMAND_STATUS.nothing_started;
6237
6250
  }
6251
+ if (options.claim && read2.kind === "grant") {
6252
+ io2.print(CLAIM_BESIDE_GRANT_REFUSAL);
6253
+ return COMMAND_STATUS.nothing_started;
6254
+ }
6238
6255
  if (read2.kind === "token") io2.hide(read2.credential, REDACTED_TOKEN);
6239
6256
  const where = credentialOriginOf(io2.env, read2, { named: call.named[PROVISION_OPTION.origin], closing: NOTHING_REMINTED });
6240
6257
  if ("refusal" in where) {
@@ -6242,9 +6259,31 @@ async function provision(call, io2) {
6242
6259
  return COMMAND_STATUS.nothing_started;
6243
6260
  }
6244
6261
  const sent = { ...options, origin: where.origin };
6245
- const again = freshLineOf(io2, options.application, sent.origin, namedEnvFile);
6246
6262
  const verifier = read2.kind === "grant" ? pendingVerifierOf(io2, sent.origin) : null;
6247
- const tried = tryEnvironmentFile(io2, options.envFile);
6263
+ return remintRun(io2, sent, agent.userAgent, { credential: read2.credential, kind: read2.kind, verifier }, standing.text, namedEnvFile);
6264
+ }
6265
+ async function claimRun(io2, call, options, userAgent, standing, namedEnvFile, unauthorized) {
6266
+ const origin = authorizationOriginOf(io2.env, call.named[PROVISION_OPTION.origin], NOTHING_REMINTED);
6267
+ if ("refusal" in origin) {
6268
+ io2.print(origin.refusal);
6269
+ return COMMAND_STATUS.nothing_started;
6270
+ }
6271
+ const verifier = pendingVerifierOf(io2, origin.origin);
6272
+ if (verifier === null) return null;
6273
+ const sent = { ...options, origin: origin.origin };
6274
+ return remintRun(
6275
+ io2,
6276
+ sent,
6277
+ userAgent,
6278
+ { credential: verifier, kind: "grant", verifier },
6279
+ standing,
6280
+ namedEnvFile,
6281
+ () => firstProvisionAct(io2, call, options.application, namedEnvFile, unauthorized, true)
6282
+ );
6283
+ }
6284
+ async function remintRun(io2, sent, userAgent, read2, standing, namedEnvFile, claimFallback) {
6285
+ const again = freshLineOf(io2, sent.application, sent.origin, namedEnvFile);
6286
+ const tried = tryEnvironmentFile(io2, sent.envFile);
6248
6287
  if ("unwritten" in tried) {
6249
6288
  io2.print(
6250
6289
  `The environment file could not be written (${tried.unwritten}): ${PROVISION_OPTION.envFile} names it, and it is ${ENVIRONMENT_FILE_NAME} in the folder the command runs in where the option is absent; its folder must stand. ${NOTHING_REMINTED}`
@@ -6254,7 +6293,7 @@ async function provision(call, io2) {
6254
6293
  const reminted = { database: "no", platform: "no" };
6255
6294
  const release = io2.whenEnded(() => {
6256
6295
  for (const line of signalEndedLines(reminted, read2.kind, again)) io2.print(line);
6257
- dropWritingFile(io2, options.envFile);
6296
+ dropWritingFile(io2, sent.envFile);
6258
6297
  });
6259
6298
  try {
6260
6299
  const older = await planeWireRefusal(io2, sent.origin);
@@ -6262,10 +6301,10 @@ async function provision(call, io2) {
6262
6301
  io2.print(older);
6263
6302
  return COMMAND_STATUS.nothing_started;
6264
6303
  }
6265
- return await remintAndWrite(io2, sent, agent.userAgent, { ...read2, verifier, again, next: nextRunLineOf(io2, sent.origin, namedEnvFile) }, standing.text, reminted);
6304
+ return await remintAndWrite(io2, sent, userAgent, { ...read2, again, next: nextRunLineOf(io2, sent.origin, namedEnvFile) }, standing, reminted, claimFallback);
6266
6305
  } finally {
6267
6306
  release();
6268
- dropWritingFile(io2, options.envFile);
6307
+ dropWritingFile(io2, sent.envFile);
6269
6308
  }
6270
6309
  }
6271
6310
  var signalEndedLines = (reminted, kind, line) => {
@@ -6298,8 +6337,8 @@ var provisionFirstActLines = (origin, application, challenge, expiresAt, line) =
6298
6337
  ` ${CODE_CHALLENGE_MEMBER}: ${JSON.stringify(challenge)}`,
6299
6338
  `That line presents its grant with this computer's verifier, so a copy of it re-mints nothing elsewhere; it re-mints the development credentials and writes them into the environment file. The request is pending until ${expiresAt}: ${line} run again before then prints this challenge again.`
6300
6339
  ];
6301
- async function firstProvisionAct(io2, call, application, envFile, unauthorized) {
6302
- io2.print(noTokenSentence(unauthorized.origin, unauthorized.expiredAt));
6340
+ async function firstProvisionAct(io2, call, application, envFile, unauthorized, afterClaim = false) {
6341
+ if (!afterClaim) io2.print(noTokenSentence(unauthorized.origin, unauthorized.expiredAt));
6303
6342
  const origin = authorizationOriginOf(io2.env, call.named[PROVISION_OPTION.origin], NOTHING_REMINTED);
6304
6343
  if ("refusal" in origin) {
6305
6344
  io2.print(origin.refusal);
@@ -6318,7 +6357,7 @@ async function firstProvisionAct(io2, call, application, envFile, unauthorized)
6318
6357
  }
6319
6358
  return COMMAND_STATUS.done;
6320
6359
  }
6321
- async function remintAndWrite(io2, { application, envFile, origin }, userAgent, read2, standing, reminted = { database: "no", platform: "no" }) {
6360
+ async function remintAndWrite(io2, { application, envFile, origin }, userAgent, read2, standing, reminted = { database: "no", platform: "no" }, claimFallback) {
6322
6361
  const untouched = (lines2) => {
6323
6362
  for (const line of [...lines2, NOTHING_REMINTED]) io2.print(line);
6324
6363
  return COMMAND_STATUS.nothing_started;
@@ -6329,6 +6368,10 @@ async function remintAndWrite(io2, { application, envFile, origin }, userAgent,
6329
6368
  };
6330
6369
  const database = await remint(io2, origin, read2.credential, userAgent, application, databaseCredentialNameOf(application), read2.verifier);
6331
6370
  reminted.database = database.kind === "answered" || database.kind === "unknown" ? database.kind : "no";
6371
+ if (claimFallback !== void 0 && database.kind === "refused" && CLAIM_FALLBACK_ERRORS.includes(database.error)) {
6372
+ io2.print(claimRefusedSentence(origin, database.error));
6373
+ return claimFallback();
6374
+ }
6332
6375
  if (database.kind === "unsent") return untouched(database.lines);
6333
6376
  if (database.kind === "unknown") return lost([...database.lines, remintUnknownSentence("database")]);
6334
6377
  const noDatabase = database.kind === "refused" && database.error === NO_DATABASE_ERROR && database.action === PROVISION_ACTION;
@@ -9166,7 +9209,7 @@ var SUBCOMMANDS = Object.freeze([
9166
9209
  WHOAMI_ROW
9167
9210
  ]);
9168
9211
  var SERVED = LINE_RUNNER;
9169
- var NPX_FORM_SENTENCE = `Where the command is not installed, install it with ${installLineOf(DEFAULT_COMMAND_ORIGIN)}, or run the same line through npx: write ${commandRunnerOf("latest")} for ${LINE_RUNNER}, with next in place of latest on Turn Zero's development platform.`;
9212
+ var NPX_FORM_SENTENCE = `Where the command is not installed, install it with ${installLineOf(DEFAULT_COMMAND_ORIGIN)}, or run the same line through npx: write ${commandRunnerOf("latest")} for ${LINE_RUNNER}.`;
9170
9213
  var namedWithActs = (subcommand) => subcommand.acts ? `${subcommand.name} ${subcommand.acts.join("|")}` : subcommand.name;
9171
9214
  var shown = (option) => option.flag ? option.name : `${option.name} ${option.value}`;
9172
9215
  var listed = (names) => names.length < 3 ? names.join(" and ") : `${names.slice(0, -1).join(", ")}, and ${names[names.length - 1]}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "turnzero",
3
- "version": "0.20.0",
3
+ "version": "0.21.0",
4
4
  "type": "module",
5
5
  "description": "The Turn Zero Cloud command, which an AI coding tool runs on your machine to deploy an application, store a secret, upload a file, download an export, take a library entry, write a local run's settings, start the application locally, and scaffold a new service from a template.",
6
6
  "license": "Apache-2.0",