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.
- package/dist/turnzero-cloud.mjs +58 -15
- package/package.json +1 -1
package/dist/turnzero-cloud.mjs
CHANGED
|
@@ -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
|
|
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
|
-
|
|
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,
|
|
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,
|
|
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,
|
|
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}
|
|
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.
|
|
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",
|