turnzero 0.31.1 → 0.33.0-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/dist/turnzero-cloud.mjs +421 -60
- package/package.json +1 -1
package/dist/turnzero-cloud.mjs
CHANGED
|
@@ -64,7 +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
|
+
var HAND_OVER_SENTENCE = "If your tool's own safety check refuses a line, first take any route named above that your tool can still use, telling the person which and why. Only where none works, give the person that exact line to run once in their own terminal, never a rewritten one.";
|
|
68
68
|
var COMPUTER_LOGIN_PATH = "/approve/computer";
|
|
69
69
|
var COMPUTER_LOGIN_QUERY = Object.freeze({ challenge: "challenge", state: "state", port: "port", label: "label" });
|
|
70
70
|
var LOGIN_STATE_FORM = /^[A-Za-z0-9_-]{43}$/;
|
|
@@ -169,6 +169,9 @@ var SECRET_NAME_FORM = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/;
|
|
|
169
169
|
var PUT_SUBCOMMAND = "put";
|
|
170
170
|
var PUT_OPTION = Object.freeze({ area: "--area", name: "--name", path: DEPLOY_OPTION.path, origin: DEPLOY_OPTION.origin });
|
|
171
171
|
var PUT_AREA_FORM = /^[a-zA-Z0-9][a-zA-Z0-9_-]{0,63}$/;
|
|
172
|
+
var LINE_PATH_SHELL_CLASS = /["$`%!&|<>^\u201c\u201d\u201e]|\\\\|\\$/;
|
|
173
|
+
var LINE_CONTROL_CHARACTER = /[\u0000-\u001f\u007f]/;
|
|
174
|
+
var lineValueCarries = (value) => !LINE_CONTROL_CHARACTER.test(value) && !LINE_PATH_SHELL_CLASS.test(value);
|
|
172
175
|
var EXPORT_AREA_PREFIX = "export-";
|
|
173
176
|
var exportAreaName = (application) => `${EXPORT_AREA_PREFIX}${application}`;
|
|
174
177
|
var EXPORT_MANIFEST_FILE = "manifest.json";
|
|
@@ -292,7 +295,14 @@ var TZMESH_OPTION = {
|
|
|
292
295
|
force: "--force",
|
|
293
296
|
origin: "--origin",
|
|
294
297
|
tzmeshEstate: "--tzmesh-estate",
|
|
295
|
-
mint: "--mint"
|
|
298
|
+
mint: "--mint",
|
|
299
|
+
// The hosted setup's options (the tzmesh hosted setup plan's decision 1).
|
|
300
|
+
webhookOrigin: "--webhook-origin",
|
|
301
|
+
webhookSecret: "--webhook-secret",
|
|
302
|
+
description: "--description",
|
|
303
|
+
title: "--title",
|
|
304
|
+
join: "--join",
|
|
305
|
+
public: "--public"
|
|
296
306
|
};
|
|
297
307
|
var TZMESH_ESTATES = Object.freeze(["production", "development"]);
|
|
298
308
|
var TZMESH_ESTATE_ORIGINS = Object.freeze({
|
|
@@ -315,6 +325,13 @@ var TZMESH_SECRET_FORM = new RegExp(`^${TZMESH_SECRET_PREFIX}[A-Za-z0-9_-]{16,25
|
|
|
315
325
|
var TZMESH_NAME_FORM = /^[A-Za-z0-9_-]{1,32}$/;
|
|
316
326
|
var TZMESH_REGISTER_PATH = "/v1/register";
|
|
317
327
|
var TZMESH_END_PATH = "/v1/end";
|
|
328
|
+
var TZMESH_WEBHOOK_SET_PATH = "/v1/webhook_set";
|
|
329
|
+
var TZMESH_JOIN_PATH = "/v1/join";
|
|
330
|
+
var TZMESH_WEBHOOK_ROUTE = "/tzmesh/webhook";
|
|
331
|
+
var TZMESH_WEBHOOK_SECRET_PREFIX = "turnzero_tzmesh_whk_";
|
|
332
|
+
var TZMESH_WEBHOOK_SECRET_FORM = new RegExp(`^${TZMESH_WEBHOOK_SECRET_PREFIX}[A-Za-z0-9_-]{43}$`);
|
|
333
|
+
var TZMESH_TITLE_MAX = 80;
|
|
334
|
+
var TZMESH_DESCRIPTION_MAX = 120;
|
|
318
335
|
var tzmeshMintMembers = (challenge) => [
|
|
319
336
|
[CODE_CHALLENGE_MEMBER, challenge],
|
|
320
337
|
["scope_kind", "account"],
|
|
@@ -328,6 +345,12 @@ var tzmeshRegisterOptionsOf = (call) => [
|
|
|
328
345
|
call.secret !== void 0 ? `${TZMESH_OPTION.secret} ${call.secret}` : `${TZMESH_OPTION.toFile} "${call.toFile ?? ""}"`,
|
|
329
346
|
...call.application !== void 0 ? [`${TZMESH_OPTION.application} ${call.application}`] : [],
|
|
330
347
|
...call.environment !== void 0 ? [`${TZMESH_OPTION.environment} ${call.environment}`] : [],
|
|
348
|
+
...call.webhookOrigin !== void 0 ? [`${TZMESH_OPTION.webhookOrigin} ${call.webhookOrigin}`] : [],
|
|
349
|
+
...call.webhookSecret !== void 0 ? [`${TZMESH_OPTION.webhookSecret} ${call.webhookSecret}`] : [],
|
|
350
|
+
...call.description !== void 0 ? [`${TZMESH_OPTION.description} "${call.description}"`] : [],
|
|
351
|
+
...call.title !== void 0 ? [`${TZMESH_OPTION.title} "${call.title}"`] : [],
|
|
352
|
+
...call.join !== void 0 && call.join.length > 0 ? [`${TZMESH_OPTION.join} "${call.join.join(",")}"`] : [],
|
|
353
|
+
...call.public === true ? [TZMESH_OPTION.public] : [],
|
|
331
354
|
...call.force === true ? [TZMESH_OPTION.force] : [],
|
|
332
355
|
`${TZMESH_OPTION.origin} ${originWord(call.origin)}`,
|
|
333
356
|
`${TZMESH_OPTION.tzmeshEstate} ${call.tzmeshEstate}`
|
|
@@ -995,11 +1018,11 @@ var noTokenSentence = (origin, expiredAt) => expiredAt === null ? `No credential
|
|
|
995
1018
|
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.`;
|
|
996
1019
|
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.`;
|
|
997
1020
|
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:";
|
|
998
|
-
var
|
|
1021
|
+
var DEPLOY_ROUTES_SENTENCE = "For regular use, prefer this command wherever your tool can install and run it and reach the platform. A first simple test within the caps of your tool's deploy_files call may deploy through deploy_files, as may any folder within them where this command cannot work. Past the caps, where your tool may not install or run this command, upload a zip with mint_upload_grant, then name it as deploy's artifact.";
|
|
999
1022
|
var loginRouteLines = (io2, origin, deployFiles = true) => [
|
|
1000
1023
|
LOGIN_ROUTE_OPENER,
|
|
1001
1024
|
...loginLinesFor(io2, origin),
|
|
1002
|
-
...deployFiles ? [
|
|
1025
|
+
...deployFiles ? [DEPLOY_ROUTES_SENTENCE] : [],
|
|
1003
1026
|
HAND_OVER_SENTENCE
|
|
1004
1027
|
];
|
|
1005
1028
|
var loginRouteRefusalOf = (io2, closing) => {
|
|
@@ -1018,6 +1041,8 @@ var GRANT_TEXT = new RegExp(`${UPLOAD_GRANT_PREFIX}[A-Za-z0-9_-]*(?:\\.[A-Za-z0-
|
|
|
1018
1041
|
var TOKEN_TEXT = new RegExp(`${MINTED_TOKEN_PREFIX}[A-Za-z0-9_-]*(?:\\.[A-Za-z0-9_-]+)*`, "g");
|
|
1019
1042
|
var PROGRAM_SECRET_TEXT = new RegExp(`${TZMESH_SECRET_PREFIX}[A-Za-z0-9_-]*`, "g");
|
|
1020
1043
|
var REDACTED_PROGRAM_SECRET = "<program secret>";
|
|
1044
|
+
var WEBHOOK_SECRET_TEXT = new RegExp(`${TZMESH_WEBHOOK_SECRET_PREFIX}[A-Za-z0-9_-]*`, "g");
|
|
1045
|
+
var REDACTED_WEBHOOK_SECRET = "<webhook signing secret>";
|
|
1021
1046
|
var REDACTED_GRANT = "<grant>";
|
|
1022
1047
|
var REDACTED_VALUE = "<value>";
|
|
1023
1048
|
var REDACTED_TOKEN_CODE = "<token code>";
|
|
@@ -1025,7 +1050,7 @@ var REDACTED_VERIFIER = "<verifier>";
|
|
|
1025
1050
|
var REDACTED_CHALLENGE = "<challenge>";
|
|
1026
1051
|
var HIDDEN_TEXT_MIN = 8;
|
|
1027
1052
|
var redactGrants = (line) => line.replace(GRANT_TEXT, REDACTED_GRANT);
|
|
1028
|
-
var redactCredentials = (line) => redactGrants(line).replace(TOKEN_TEXT, REDACTED_TOKEN).replace(PROGRAM_SECRET_TEXT, REDACTED_PROGRAM_SECRET);
|
|
1053
|
+
var redactCredentials = (line) => redactGrants(line).replace(TOKEN_TEXT, REDACTED_TOKEN).replace(PROGRAM_SECRET_TEXT, REDACTED_PROGRAM_SECRET).replace(WEBHOOK_SECRET_TEXT, REDACTED_WEBHOOK_SECRET);
|
|
1029
1054
|
var VALUE_LINE_REFUSED = Object.freeze({
|
|
1030
1055
|
twice: "the value line is printed once in a run",
|
|
1031
1056
|
form: "only a value of a form token claim prints is printed whole",
|
|
@@ -1110,6 +1135,8 @@ var firstActNamed = (kind, origin = DEFAULT_COMMAND_ORIGIN) => kind === "tzmesh"
|
|
|
1110
1135
|
) : `${kind === "authorized computer" ? AUTHORIZE_SUBCOMMAND : `${TOKEN_SUBCOMMAND} ${TOKEN_REQUEST_ACT}`}${originWordsOf(origin)}`;
|
|
1111
1136
|
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.`;
|
|
1112
1137
|
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.`;
|
|
1138
|
+
var AUTHORIZE_HAND_OVER_SENTENCE = "If your tool's own safety check refuses the answered line, a deploy can still go through a route that does not require the turnzero command. That is deploy_files within its caps or, past them where your tool can zip and upload the folder, mint_upload_grant followed by deploy naming the uploaded zip as artifact. Tell the person which route you take and why. Only where no such route serves, give the person that exact line to run once in their own terminal, never a rewritten one.";
|
|
1139
|
+
var TZMESH_HAND_OVER_SENTENCE = "If your tool's own safety check refuses the answered line, give the person that exact line to run once in their own terminal, never a rewritten one.";
|
|
1113
1140
|
var OPTIONS_LINE_HEAD = "options: ";
|
|
1114
1141
|
var tzmeshFirstActLines = (origin, pending, completing2) => [
|
|
1115
1142
|
`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.`,
|
|
@@ -1120,7 +1147,7 @@ var tzmeshFirstActLines = (origin, pending, completing2) => [
|
|
|
1120
1147
|
`${OPTIONS_LINE_HEAD}${completing2}`,
|
|
1121
1148
|
`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
1149
|
`The request is pending until ${pending.expires_at}: ${firstActNamed("tzmesh", origin)} run again with the same options before then prints this challenge again.`,
|
|
1123
|
-
|
|
1150
|
+
TZMESH_HAND_OVER_SENTENCE
|
|
1124
1151
|
];
|
|
1125
1152
|
var firstActLines = (origin, kind, pending, label, loginLines = [], completing2 = "") => kind === "tzmesh" ? tzmeshFirstActLines(origin, pending, completing2) : [
|
|
1126
1153
|
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.`,
|
|
@@ -1132,7 +1159,7 @@ var firstActLines = (origin, kind, pending, label, loginLines = [], completing2
|
|
|
1132
1159
|
...mintCallMembers(kind, pending.challenge, label).map(([name, value]) => ` ${name}: ${JSON.stringify(value)}`),
|
|
1133
1160
|
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.`,
|
|
1134
1161
|
...kind === "authorized computer" && loginLines.length > 0 ? [loginWaySentence(loginLines)] : [],
|
|
1135
|
-
...kind === "authorized computer" ? [
|
|
1162
|
+
...kind === "authorized computer" ? [AUTHORIZE_HAND_OVER_SENTENCE] : []
|
|
1136
1163
|
];
|
|
1137
1164
|
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.`;
|
|
1138
1165
|
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.`;
|
|
@@ -1257,6 +1284,16 @@ var mintedTokenOf = (answer, kind = "authorized computer") => {
|
|
|
1257
1284
|
var mintAgainSentence = (kind, origin = DEFAULT_COMMAND_ORIGIN, login2 = null) => login2 !== null ? `Run ${login2} again to log this computer in.` : `Call ${MINT_TOKEN_ACTION} from your tool again with the challenge ${firstActNamed(kind, origin)} prints, and run the line it answers.`;
|
|
1258
1285
|
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)}`;
|
|
1259
1286
|
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.`;
|
|
1287
|
+
var otherLivingRequestOf = (pending, origin, now) => {
|
|
1288
|
+
let found = null;
|
|
1289
|
+
for (const [other, entry] of pending) {
|
|
1290
|
+
const expires = Date.parse(entry.expires_at);
|
|
1291
|
+
if (other === origin || !Number.isFinite(expires) || expires <= now.getTime()) continue;
|
|
1292
|
+
if (found === null || expires > found.expires) found = { origin: other, expires };
|
|
1293
|
+
}
|
|
1294
|
+
return found?.origin ?? null;
|
|
1295
|
+
};
|
|
1296
|
+
var elsewhereRequestSentence = (origin, other) => `A request is pending on this computer for ${other} instead, so the first act ran against ${other}. Where the mint was made at ${origin}, run the first act above. Where it was made at ${other}, run the line its ${MINT_TOKEN_ACTION} call answered exactly as given.`;
|
|
1260
1297
|
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
1298
|
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)}`;
|
|
1262
1299
|
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.`];
|
|
@@ -1301,6 +1338,8 @@ async function completeAct(io2, origin, kind, presentation, userAgent, say, deli
|
|
|
1301
1338
|
const pending = read2.state.pending.get(origin);
|
|
1302
1339
|
if (pending === void 0) {
|
|
1303
1340
|
say(noPendingSentence(origin, kind, held ? "mint" : "code"));
|
|
1341
|
+
const other = otherLivingRequestOf(read2.state.pending, origin, io2.clock());
|
|
1342
|
+
if (other !== null) say(elsewhereRequestSentence(origin, other));
|
|
1304
1343
|
return COMMAND_STATUS.nothing_started;
|
|
1305
1344
|
}
|
|
1306
1345
|
io2.hide(pending.verifier, REDACTED_VERIFIER);
|
|
@@ -2626,7 +2665,14 @@ var localWriteLineIn = (data) => {
|
|
|
2626
2665
|
var localWriteLineOf = (found) => found === null ? null : `${WARNING_LINE_HEAD}${shownNoteName(found.name)}, line ${found.line}, writes to a local file inside the application's folder. A running copy's disk is lost whenever the copy is replaced or stops: keep files in a storage area and records in a database, as read_documentation's pages /cloud/guides/store-files/ and /cloud/guides/add-a-database/ describe.`;
|
|
2627
2666
|
var LIST_LINE_HEAD = "file: ";
|
|
2628
2667
|
var listLineOf = (file) => `${LIST_LINE_HEAD}${file.size} ${shownWhole(file.name)}`;
|
|
2629
|
-
var NO_NOTES = Object.freeze({ leftOut: Object.freeze([]), rootZips: Object.freeze([]), rootRunOutput: Object.freeze([]), credentialFiles: Object.freeze([]), localWrite: null, unservedHealthPath: null, nearestHealthPath: null });
|
|
2668
|
+
var NO_NOTES = Object.freeze({ leftOut: Object.freeze([]), rootZips: Object.freeze([]), rootRunOutput: Object.freeze([]), credentialFiles: Object.freeze([]), localWrite: null, unservedHealthPath: null, nearestHealthPath: null, gitignored: Object.freeze([]) });
|
|
2669
|
+
var gitignoredLineOf = (entries) => entries.length === 0 ? null : `note: .gitignore lists ${entries.length === 1 ? "a file" : `${entries.length} files`} the upload includes, since the zip never honours .gitignore: a build's output is often listed there, and the image build runs no build script. ${listedPairs(entries)}. To leave a path out, list it in .deployignore at the folder's root.`;
|
|
2670
|
+
var listedPairs = (entries) => {
|
|
2671
|
+
const sorted = [...entries].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
2672
|
+
const shown2 = sorted.slice(0, NOTE_NAMES_MAX).map((entry) => `${shownNoteName(entry.name)} (${shownNoteName(entry.pattern)})`).join(", ");
|
|
2673
|
+
const rest = sorted.length - NOTE_NAMES_MAX;
|
|
2674
|
+
return rest > 0 ? `${shown2}, and ${rest} more` : shown2;
|
|
2675
|
+
};
|
|
2630
2676
|
var noteLinesOf = (notes, health, zipped = null) => {
|
|
2631
2677
|
const lines = [];
|
|
2632
2678
|
const files = zipped === null ? null : filesLineOf(zipped.map((file) => file.name));
|
|
@@ -2641,6 +2687,8 @@ var noteLinesOf = (notes, health, zipped = null) => {
|
|
|
2641
2687
|
if (credential !== null) lines.push(credential);
|
|
2642
2688
|
const localWrite = localWriteLineOf(notes.localWrite);
|
|
2643
2689
|
if (localWrite !== null) lines.push(localWrite);
|
|
2690
|
+
const gitignored = gitignoredLineOf(notes.gitignored ?? []);
|
|
2691
|
+
if (gitignored !== null) lines.push(gitignored);
|
|
2644
2692
|
if (health && notes.unservedHealthPath !== null) {
|
|
2645
2693
|
lines.push(healthLineOf(notes.unservedHealthPath));
|
|
2646
2694
|
if (notes.nearestHealthPath !== null) lines.push(nearestHealthLineOf(notes.nearestHealthPath));
|
|
@@ -3512,6 +3560,96 @@ import { readdirSync, readFileSync as readFileSync3, statSync as statSync2 } fro
|
|
|
3512
3560
|
import { join as join5 } from "node:path";
|
|
3513
3561
|
import * as zlib from "node:zlib";
|
|
3514
3562
|
import { deflateRawSync, inflateRawSync as inflateRawSync2 } from "node:zlib";
|
|
3563
|
+
|
|
3564
|
+
// src/turnzero_cloud_command/ignore_rules.ts
|
|
3565
|
+
var DEPLOY_IGNORE_FILE = ".deployignore";
|
|
3566
|
+
var GIT_IGNORE_FILE = ".gitignore";
|
|
3567
|
+
var matcherOf = (body, anchored) => {
|
|
3568
|
+
let source = "";
|
|
3569
|
+
for (let i2 = 0; i2 < body.length; i2 += 1) {
|
|
3570
|
+
const c = body[i2];
|
|
3571
|
+
if (c === "\\" && i2 + 1 < body.length) {
|
|
3572
|
+
source += body[i2 + 1].replace(/[.*+?^${}()|[\]\\/]/g, "\\$&");
|
|
3573
|
+
i2 += 1;
|
|
3574
|
+
} else if (c === "*" && body[i2 + 1] === "*") {
|
|
3575
|
+
const before = i2 === 0 || body[i2 - 1] === "/";
|
|
3576
|
+
const after = i2 + 2 === body.length || body[i2 + 2] === "/";
|
|
3577
|
+
if (before && after) {
|
|
3578
|
+
if (i2 + 2 === body.length) source += ".*";
|
|
3579
|
+
else {
|
|
3580
|
+
source += "(?:.*/)?";
|
|
3581
|
+
i2 += 1;
|
|
3582
|
+
}
|
|
3583
|
+
i2 += 1;
|
|
3584
|
+
} else {
|
|
3585
|
+
source += "[^/]*";
|
|
3586
|
+
i2 += 1;
|
|
3587
|
+
}
|
|
3588
|
+
} else if (c === "*") source += "[^/]*";
|
|
3589
|
+
else if (c === "?") source += "[^/]";
|
|
3590
|
+
else if (c === "[") {
|
|
3591
|
+
const found = classOf(body, i2);
|
|
3592
|
+
if (found === null) source += "\\[";
|
|
3593
|
+
else {
|
|
3594
|
+
source += found.source;
|
|
3595
|
+
i2 = found.end;
|
|
3596
|
+
}
|
|
3597
|
+
} else source += c.replace(/[.+^${}()|\\]/g, "\\$&");
|
|
3598
|
+
}
|
|
3599
|
+
return new RegExp(anchored ? `^${source}$` : `^(?:.*/)?${source}$`);
|
|
3600
|
+
};
|
|
3601
|
+
var classOf = (body, open) => {
|
|
3602
|
+
let i2 = open + 1;
|
|
3603
|
+
const negated = body[i2] === "!" || body[i2] === "^";
|
|
3604
|
+
if (negated) i2 += 1;
|
|
3605
|
+
let inner = "";
|
|
3606
|
+
for (let first = true; i2 < body.length; i2 += 1, first = false) {
|
|
3607
|
+
const c = body[i2];
|
|
3608
|
+
if (c === "]" && !first) return { source: negated ? `[^/${inner}]` : `(?!/)[${inner}]`, end: i2 };
|
|
3609
|
+
if (c === "\\" && i2 + 1 < body.length) {
|
|
3610
|
+
i2 += 1;
|
|
3611
|
+
inner += inClass(body[i2]);
|
|
3612
|
+
} else inner += c === "-" ? c : inClass(c);
|
|
3613
|
+
}
|
|
3614
|
+
return null;
|
|
3615
|
+
};
|
|
3616
|
+
var inClass = (c) => c.replace(/[\\\]\[^-]/g, "\\$&");
|
|
3617
|
+
function ignoreRulesOf(text) {
|
|
3618
|
+
const rules = [];
|
|
3619
|
+
for (const [index, raw] of text.split(/\r?\n/).entries()) {
|
|
3620
|
+
let line = raw.replace(/(?<!\\) +$/, "");
|
|
3621
|
+
if (line === "" || line.startsWith("#") || /(?:^|[^\\])(?:\\\\)*\\$/.test(line)) continue;
|
|
3622
|
+
const negated = line.startsWith("!");
|
|
3623
|
+
if (negated) line = line.slice(1);
|
|
3624
|
+
else if (line.startsWith("\\!") || line.startsWith("\\#")) line = line.slice(1);
|
|
3625
|
+
const folderOnly = line.endsWith("/");
|
|
3626
|
+
let body = folderOnly ? line.slice(0, -1) : line;
|
|
3627
|
+
const anchored = body.includes("/");
|
|
3628
|
+
if (body.startsWith("/")) body = body.slice(1);
|
|
3629
|
+
if (body === "") continue;
|
|
3630
|
+
rules.push({ pattern: raw.trim(), line: index + 1, negated, folderOnly, matcher: matcherOf(body, anchored) });
|
|
3631
|
+
}
|
|
3632
|
+
return rules;
|
|
3633
|
+
}
|
|
3634
|
+
function ignoringRuleOf(rules, path, folder) {
|
|
3635
|
+
if (rules.length === 0) return null;
|
|
3636
|
+
const segments = path.split("/");
|
|
3637
|
+
for (let depth = 1; depth < segments.length; depth += 1) {
|
|
3638
|
+
const ancestor = ruleAt(rules, segments.slice(0, depth).join("/"), true);
|
|
3639
|
+
if (ancestor !== null) return ancestor;
|
|
3640
|
+
}
|
|
3641
|
+
return ruleAt(rules, path, folder);
|
|
3642
|
+
}
|
|
3643
|
+
var ruleAt = (rules, path, folder) => {
|
|
3644
|
+
let decided = null;
|
|
3645
|
+
for (const rule of rules) {
|
|
3646
|
+
if (rule.folderOnly && !folder) continue;
|
|
3647
|
+
if (rule.matcher.test(path)) decided = rule.negated ? null : rule;
|
|
3648
|
+
}
|
|
3649
|
+
return decided;
|
|
3650
|
+
};
|
|
3651
|
+
|
|
3652
|
+
// src/turnzero_cloud_command/zip.ts
|
|
3515
3653
|
var AI_TOOL_NAMES = Object.freeze([
|
|
3516
3654
|
".claude",
|
|
3517
3655
|
".mcp.json",
|
|
@@ -3537,14 +3675,23 @@ var ZIP_VERSION = 20;
|
|
|
3537
3675
|
var ZIP32_MAX = 4294967295;
|
|
3538
3676
|
var ZipRefusal = class extends Error {
|
|
3539
3677
|
};
|
|
3540
|
-
var
|
|
3678
|
+
var rootIgnoreRulesOf = (root, name) => {
|
|
3679
|
+
try {
|
|
3680
|
+
const path = join5(root, name);
|
|
3681
|
+
return statSync2(path).isFile() ? ignoreRulesOf(readFileSync3(path, "utf8")) : [];
|
|
3682
|
+
} catch {
|
|
3683
|
+
return [];
|
|
3684
|
+
}
|
|
3685
|
+
};
|
|
3686
|
+
var walkFolder = (root, limit, leftOut, ignore = []) => {
|
|
3541
3687
|
const found = [];
|
|
3542
3688
|
const pending = [{ path: root, name: "" }];
|
|
3543
3689
|
while (pending.length > 0) {
|
|
3544
3690
|
const folder = pending.pop();
|
|
3545
3691
|
for (const entry of readdirSync(folder.path, { withFileTypes: true })) {
|
|
3546
3692
|
const name = folder.name === "" ? entry.name : `${folder.name}/${entry.name}`;
|
|
3547
|
-
|
|
3693
|
+
const kept2 = folder.name === "" && (entry.name === "package.json" || entry.name === MANIFEST_FILE);
|
|
3694
|
+
if (leftOutName(entry.name) || !kept2 && ignoringRuleOf(ignore, name, entry.isDirectory()) !== null) {
|
|
3548
3695
|
leftOut?.push(entry.isDirectory() ? `${name}/` : name);
|
|
3549
3696
|
continue;
|
|
3550
3697
|
}
|
|
@@ -3644,7 +3791,9 @@ function zipFolder(root, seams = {}) {
|
|
|
3644
3791
|
}
|
|
3645
3792
|
if (!rootFile) throw new ZipRefusal(NO_PACKAGE_SENTENCE);
|
|
3646
3793
|
const leftOut = [];
|
|
3647
|
-
const
|
|
3794
|
+
const deployIgnore = rootIgnoreRulesOf(root, DEPLOY_IGNORE_FILE);
|
|
3795
|
+
const gitIgnore = rootIgnoreRulesOf(root, GIT_IGNORE_FILE);
|
|
3796
|
+
const files = (seams.walk ?? walkFolder)(root, ARTIFACT_ENTRIES_MAX + 1, leftOut, deployIgnore);
|
|
3648
3797
|
if (files.length > ARTIFACT_ENTRIES_MAX) throw new ZipRefusal(entryBoundSentence());
|
|
3649
3798
|
const manifest = files.find((file) => file.name === MANIFEST_FILE);
|
|
3650
3799
|
let healthPath = null;
|
|
@@ -3692,7 +3841,11 @@ function zipFolder(root, seams = {}) {
|
|
|
3692
3841
|
credentialFiles,
|
|
3693
3842
|
localWrite,
|
|
3694
3843
|
unservedHealthPath: segment !== null && !held ? healthPath : null,
|
|
3695
|
-
nearestHealthPath: segment !== null && !held && healthPath !== null ? nearestHealthPathOf(healthLike, healthPath) : null
|
|
3844
|
+
nearestHealthPath: segment !== null && !held && healthPath !== null ? nearestHealthPathOf(healthLike, healthPath) : null,
|
|
3845
|
+
gitignored: files.flatMap((file) => {
|
|
3846
|
+
const rule = ignoringRuleOf(gitIgnore, file.name, false);
|
|
3847
|
+
return rule === null ? [] : [{ name: file.name, pattern: rule.pattern }];
|
|
3848
|
+
})
|
|
3696
3849
|
}
|
|
3697
3850
|
};
|
|
3698
3851
|
}
|
|
@@ -4139,8 +4292,9 @@ var DEPLOY_ROW = Object.freeze({
|
|
|
4139
4292
|
note: [
|
|
4140
4293
|
`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}.`,
|
|
4141
4294
|
`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.`,
|
|
4142
|
-
`
|
|
4143
|
-
|
|
4295
|
+
`The second route authorizes this computer, and the deploy line then runs again. A tool signed in to the platform may do it itself with ${AUTHORIZE_SUBCOMMAND}, and the run prints the person's way, ${LOGIN_SUBCOMMAND}, run once in a terminal of their own. The credential file is ${CREDENTIAL_FILE_WORDS}.`,
|
|
4296
|
+
DEPLOY_ROUTES_SENTENCE,
|
|
4297
|
+
HAND_OVER_SENTENCE,
|
|
4144
4298
|
`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.`,
|
|
4145
4299
|
`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.`,
|
|
4146
4300
|
`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.`,
|
|
@@ -6242,7 +6396,7 @@ var whoamiLinesOf = (origin, account, entry) => [
|
|
|
6242
6396
|
`${WHOAMI_LINE_HEADS.token}label ${entry.label !== null ? JSON.stringify(entry.label) : "none"}, expiring ${entry.expires_at !== null ? `at ${entry.expires_at}` : "never"}`
|
|
6243
6397
|
];
|
|
6244
6398
|
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.`;
|
|
6245
|
-
var noLoginRoutesSentence = (origin) => `Your AI coding tool's own sign-in is not this computer's credential.
|
|
6399
|
+
var noLoginRoutesSentence = (origin) => `Your AI coding tool's own sign-in is not this computer's credential. For regular use, prefer this command where it works. A signed-in tool can authorize this computer with ${AUTHORIZE_SUBCOMMAND}${originWordsOf(origin)}; the login route below is the person's alternative. A first simple test within the caps of your tool's deploy_files call may deploy through deploy_files with no login, as may any folder within them where this command cannot work. Past the caps, or for a file deploy_files cannot carry, where this command cannot run, 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.`;
|
|
6246
6400
|
var whoamiAfterLoginSentence = (whoami2) => `Once login has printed authorized:, run ${whoami2} again.`;
|
|
6247
6401
|
async function whoami(call, io2) {
|
|
6248
6402
|
const origin = entryOriginOf(io2.env, call.named[DEPLOY_OPTION.origin], NOTHING_SENT_OR_READ);
|
|
@@ -6298,7 +6452,7 @@ async function whoami(call, io2) {
|
|
|
6298
6452
|
}
|
|
6299
6453
|
var WHOAMI_ROW = Object.freeze({
|
|
6300
6454
|
name: WHOAMI_SUBCOMMAND,
|
|
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
|
|
6455
|
+
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 routes a tool takes itself (${AUTHORIZE_SUBCOMMAND}, deploy_files, the upload route, and ${PROVISION_SUBCOMMAND}), then the person's login route. It prints no token.`,
|
|
6302
6456
|
example: WHOAMI_SUBCOMMAND,
|
|
6303
6457
|
options: WHOAMI_OPTIONS,
|
|
6304
6458
|
credential: null,
|
|
@@ -9761,6 +9915,43 @@ var TZMESH_OPTIONS = Object.freeze([
|
|
|
9761
9915
|
required: false,
|
|
9762
9916
|
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
9917
|
},
|
|
9918
|
+
{
|
|
9919
|
+
name: TZMESH_OPTION.webhookOrigin,
|
|
9920
|
+
value: "<origin>",
|
|
9921
|
+
required: false,
|
|
9922
|
+
description: `Under ${TZMESH_OPTION.secret}, the https origin of the application that hosts the agent. The run sets the agent's webhook to ${TZMESH_WEBHOOK_ROUTE} at that origin, and stores its signing secret under ${TZMESH_OPTION.webhookSecret}.`
|
|
9923
|
+
},
|
|
9924
|
+
{
|
|
9925
|
+
name: TZMESH_OPTION.webhookSecret,
|
|
9926
|
+
value: "<secret name>",
|
|
9927
|
+
required: false,
|
|
9928
|
+
description: `With ${TZMESH_OPTION.webhookOrigin}, the name the webhook's signing secret is stored under, in the scope ${TZMESH_OPTION.secret} is stored in. It names the secret and never holds it.`
|
|
9929
|
+
},
|
|
9930
|
+
{
|
|
9931
|
+
name: TZMESH_OPTION.description,
|
|
9932
|
+
value: "<text>",
|
|
9933
|
+
required: false,
|
|
9934
|
+
description: `Under ${TZMESH_OPTION.secret}, the agent's description, at most ${TZMESH_DESCRIPTION_MAX} characters.`
|
|
9935
|
+
},
|
|
9936
|
+
{
|
|
9937
|
+
name: TZMESH_OPTION.title,
|
|
9938
|
+
value: "<text>",
|
|
9939
|
+
required: false,
|
|
9940
|
+
description: `Under ${TZMESH_OPTION.secret}, the agent's title, at most ${TZMESH_TITLE_MAX} characters.`
|
|
9941
|
+
},
|
|
9942
|
+
{
|
|
9943
|
+
name: TZMESH_OPTION.join,
|
|
9944
|
+
value: "<channels>",
|
|
9945
|
+
required: false,
|
|
9946
|
+
description: `Under ${TZMESH_OPTION.secret}, the channels the agent joins, as one value: channel ids, #names, or account/#names, separated by commas.`
|
|
9947
|
+
},
|
|
9948
|
+
{
|
|
9949
|
+
name: TZMESH_OPTION.public,
|
|
9950
|
+
value: "",
|
|
9951
|
+
required: false,
|
|
9952
|
+
flag: true,
|
|
9953
|
+
description: `Under ${TZMESH_OPTION.secret}, makes the agent public at its register. Whether it is public is your choice: a tool passes this only after you answer.`
|
|
9954
|
+
},
|
|
9764
9955
|
{
|
|
9765
9956
|
name: TZMESH_OPTION.force,
|
|
9766
9957
|
value: "",
|
|
@@ -9787,7 +9978,69 @@ var TZMESH_OPTIONS = Object.freeze([
|
|
|
9787
9978
|
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
9979
|
}
|
|
9789
9980
|
]);
|
|
9790
|
-
var
|
|
9981
|
+
var SETUP_OPTIONS = [TZMESH_OPTION.webhookOrigin, TZMESH_OPTION.webhookSecret, TZMESH_OPTION.description, TZMESH_OPTION.title, TZMESH_OPTION.join];
|
|
9982
|
+
var UNCARRIED_WORDS = "a double quote, $, a backtick, %, !, &, |, <, >, ^, a curly double quote, a doubled or trailing backslash, or a control character";
|
|
9983
|
+
var JOIN_CHANNEL_FORM = /^[^\s,]{1,200}$/;
|
|
9984
|
+
var WEBHOOK_ORIGIN_FORM = /^https:\/\/[a-z0-9.-]+(?::[0-9]{1,5})?$/;
|
|
9985
|
+
var isHttpsOrigin = (value) => {
|
|
9986
|
+
if (!WEBHOOK_ORIGIN_FORM.test(value)) return false;
|
|
9987
|
+
try {
|
|
9988
|
+
const url = new URL(value);
|
|
9989
|
+
return url.protocol === "https:" && url.origin === value && url.username === "" && url.password === "";
|
|
9990
|
+
} catch {
|
|
9991
|
+
return false;
|
|
9992
|
+
}
|
|
9993
|
+
};
|
|
9994
|
+
var setupOptionsOf = (call, toFile, closing) => {
|
|
9995
|
+
const named = (option) => call.named[option] ?? null;
|
|
9996
|
+
const isPublic = call.flags.has(TZMESH_OPTION.public);
|
|
9997
|
+
if (toFile) {
|
|
9998
|
+
const given = [...SETUP_OPTIONS.filter((option) => named(option) !== null), ...isPublic ? [TZMESH_OPTION.public] : []];
|
|
9999
|
+
if (given.length > 0) return { refusal: `${given[0]} goes with ${TZMESH_OPTION.secret} alone: an agent whose secret goes into a file is set up by its own program. ${closing}` };
|
|
10000
|
+
}
|
|
10001
|
+
const webhookOrigin = named(TZMESH_OPTION.webhookOrigin);
|
|
10002
|
+
const webhookSecret = named(TZMESH_OPTION.webhookSecret);
|
|
10003
|
+
if (webhookOrigin === null !== (webhookSecret === null)) {
|
|
10004
|
+
return { refusal: `${TZMESH_OPTION.webhookOrigin} and ${TZMESH_OPTION.webhookSecret} go together: the webhook's address, and the name its signing secret is stored under. ${closing}` };
|
|
10005
|
+
}
|
|
10006
|
+
if (webhookOrigin !== null && !isHttpsOrigin(webhookOrigin)) {
|
|
10007
|
+
return {
|
|
10008
|
+
refusal: `${TZMESH_OPTION.webhookOrigin} names the https origin of the application that hosts the agent, such as https://<name>.ai.host: its host in lowercase letters, digits, hyphens, and dots, with no path. ${closing}`
|
|
10009
|
+
};
|
|
10010
|
+
}
|
|
10011
|
+
if (webhookSecret !== null && !SECRET_NAME_FORM.test(webhookSecret)) {
|
|
10012
|
+
return { refusal: `${TZMESH_OPTION.webhookSecret} names the secret the webhook's signing secret is stored under: a letter or digit first, then letters, digits, _ or -, up to 64 characters. ${closing}` };
|
|
10013
|
+
}
|
|
10014
|
+
const secret2 = named(TZMESH_OPTION.secret);
|
|
10015
|
+
if (webhookSecret !== null && secret2 !== null && webhookSecret.toLowerCase() === secret2.toLowerCase()) {
|
|
10016
|
+
return { refusal: `${TZMESH_OPTION.webhookSecret} names a secret other than the one ${TZMESH_OPTION.secret} names: the agent's secret and the webhook's signing secret are stored under two names. ${closing}` };
|
|
10017
|
+
}
|
|
10018
|
+
const bounded = (option, max) => {
|
|
10019
|
+
const value = named(option);
|
|
10020
|
+
if (value === null) return null;
|
|
10021
|
+
if (value === "" || [...value].length > max) return { refusal: `${option} takes 1 to ${max} characters. ${closing}` };
|
|
10022
|
+
if (!lineValueCarries(value)) return { refusal: `${option} holds a character a line cannot carry alike in every shell between double quotes: ${UNCARRIED_WORDS}. ${closing}` };
|
|
10023
|
+
return value;
|
|
10024
|
+
};
|
|
10025
|
+
const description = bounded(TZMESH_OPTION.description, TZMESH_DESCRIPTION_MAX);
|
|
10026
|
+
if (description !== null && typeof description === "object") return description;
|
|
10027
|
+
const title = bounded(TZMESH_OPTION.title, TZMESH_TITLE_MAX);
|
|
10028
|
+
if (title !== null && typeof title === "object") return title;
|
|
10029
|
+
const joinValue = named(TZMESH_OPTION.join);
|
|
10030
|
+
const join12 = joinValue === null ? [] : joinValue.split(",");
|
|
10031
|
+
if (joinValue !== null && (join12.some((channel) => !JOIN_CHANNEL_FORM.test(channel)) || !lineValueCarries(joinValue))) {
|
|
10032
|
+
return {
|
|
10033
|
+
refusal: `${TZMESH_OPTION.join} lists the channels the agent joins, as one value: ids, #names, or account/#names, separated by commas, with no space and nothing a line cannot carry between double quotes: ${UNCARRIED_WORDS}. ${closing}`
|
|
10034
|
+
};
|
|
10035
|
+
}
|
|
10036
|
+
return {
|
|
10037
|
+
webhook: webhookOrigin !== null && webhookSecret !== null ? { origin: webhookOrigin, secretName: webhookSecret } : null,
|
|
10038
|
+
description,
|
|
10039
|
+
title,
|
|
10040
|
+
join: join12,
|
|
10041
|
+
public: isPublic
|
|
10042
|
+
};
|
|
10043
|
+
};
|
|
9791
10044
|
var closingOf = (call) => call.named[TZMESH_OPTION.mint] !== void 0 ? MINT_UNPRESENTED : NOTHING_SENT;
|
|
9792
10045
|
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
10046
|
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}`;
|
|
@@ -9820,9 +10073,11 @@ var tzmeshOptionsOf = (call, io2) => {
|
|
|
9820
10073
|
const force = call.flags.has(TZMESH_OPTION.force);
|
|
9821
10074
|
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
10075
|
const path = toFile !== void 0 ? resolve13(io2.cwd, toFile) : null;
|
|
9823
|
-
if (path !== null &&
|
|
9824
|
-
return { refusal: `${TZMESH_OPTION.toFile} names a path holding a character a line cannot carry between double quotes:
|
|
10076
|
+
if (path !== null && !lineValueCarries(path)) {
|
|
10077
|
+
return { refusal: `${TZMESH_OPTION.toFile} names a path holding a character a line cannot carry alike in every shell between double quotes: ${UNCARRIED_WORDS}. Name a path without one. ${closing}` };
|
|
9825
10078
|
}
|
|
10079
|
+
const setup = setupOptionsOf(call, toFile !== void 0, closing);
|
|
10080
|
+
if ("refusal" in setup) return setup;
|
|
9826
10081
|
const origin = entryOriginOf(io2.env, call.named[TZMESH_OPTION.origin], closing);
|
|
9827
10082
|
if ("refusal" in origin) return origin;
|
|
9828
10083
|
if (!FIRST_PARTY_COMMAND_ORIGINS.includes(origin.origin)) return { refusal: tzmeshOriginRefusal(closing) };
|
|
@@ -9837,7 +10092,8 @@ var tzmeshOptionsOf = (call, io2) => {
|
|
|
9837
10092
|
force,
|
|
9838
10093
|
origin: origin.origin,
|
|
9839
10094
|
estate,
|
|
9840
|
-
mint
|
|
10095
|
+
mint,
|
|
10096
|
+
...setup
|
|
9841
10097
|
};
|
|
9842
10098
|
};
|
|
9843
10099
|
var completingOptionsOf = (options) => {
|
|
@@ -9846,6 +10102,11 @@ var completingOptionsOf = (options) => {
|
|
|
9846
10102
|
..."secret" in options.route ? { secret: options.route.secret } : { toFile: options.route.toFile },
|
|
9847
10103
|
...options.application !== null ? { application: options.application } : {},
|
|
9848
10104
|
...options.environment !== null ? { environment: options.environment } : {},
|
|
10105
|
+
...options.webhook !== null ? { webhookOrigin: options.webhook.origin, webhookSecret: options.webhook.secretName } : {},
|
|
10106
|
+
...options.description !== null ? { description: options.description } : {},
|
|
10107
|
+
...options.title !== null ? { title: options.title } : {},
|
|
10108
|
+
...options.join.length > 0 ? { join: options.join } : {},
|
|
10109
|
+
...options.public ? { public: true } : {},
|
|
9849
10110
|
...options.force ? { force: true } : {},
|
|
9850
10111
|
origin: options.origin,
|
|
9851
10112
|
tzmeshEstate: options.estate
|
|
@@ -9930,13 +10191,20 @@ var postWire = async (io2, wire, path, bearer, userAgent, body) => {
|
|
|
9930
10191
|
cancel();
|
|
9931
10192
|
}
|
|
9932
10193
|
};
|
|
9933
|
-
var register = async (io2, wire, token2, userAgent,
|
|
9934
|
-
const answered = await postWire(io2, wire, TZMESH_REGISTER_PATH, token2, userAgent, {
|
|
10194
|
+
var register = async (io2, wire, token2, userAgent, options) => {
|
|
10195
|
+
const answered = await postWire(io2, wire, TZMESH_REGISTER_PATH, token2, userAgent, {
|
|
10196
|
+
kind: "standing",
|
|
10197
|
+
name: options.name,
|
|
10198
|
+
label: TZMESH_COMMAND_LABEL,
|
|
10199
|
+
...options.title !== null ? { title: options.title } : {},
|
|
10200
|
+
...options.description !== null ? { description: options.description } : {},
|
|
10201
|
+
...options.public ? { visibility: "public" } : {}
|
|
10202
|
+
});
|
|
9935
10203
|
if (answered === null) return { unknown: [`The ${REGISTER_ACT} drew no answer.`] };
|
|
9936
10204
|
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
10205
|
const answer = planeObjectOf(answered.text);
|
|
9939
10206
|
if (answer !== null && typeof answer.secret === "string") io2.hide(answer.secret, REDACTED_PROGRAM_SECRET);
|
|
10207
|
+
if (answered.status >= PLATFORM_FAILURE_STATUS) return { unknown: failureLines(REGISTER_ACT, answered.status, planeRefusalOf(answered.text)) };
|
|
9940
10208
|
if (answered.status < 200 || answered.status > 299) {
|
|
9941
10209
|
const refusal = planeRefusalOf(answered.text);
|
|
9942
10210
|
if (refusal === null) return { unknown: [`The ${REGISTER_ACT} was answered HTTP ${answered.status}, not by the tzMesh service.`] };
|
|
@@ -9956,10 +10224,60 @@ var register = async (io2, wire, token2, userAgent, name) => {
|
|
|
9956
10224
|
var deleteAgent = async (io2, wire, token2, userAgent, agent) => {
|
|
9957
10225
|
const answered = await postWire(io2, wire, TZMESH_END_PATH, token2, userAgent, { participant: agent.id, delete: true });
|
|
9958
10226
|
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
|
|
9961
|
-
|
|
9962
|
-
};
|
|
10227
|
+
if (deleted) return { deleted: true, lines: [`The agent ${agentWords(agent)} was deleted, and its name is free again.`], unknown: false };
|
|
10228
|
+
const refusal = answered === null || answered.redirected || answered.status >= PLATFORM_FAILURE_STATUS ? null : planeRefusalOf(answered.text);
|
|
10229
|
+
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)) : refusal !== null ? refusalLines(END_ACT, answered.status, refusal) : [`The ${END_ACT} was answered HTTP ${answered.status}, not by the tzMesh service.`];
|
|
10230
|
+
return { deleted: false, lines: why, unknown: refusal === null };
|
|
10231
|
+
};
|
|
10232
|
+
var WEBHOOK_ACT = "webhook_set";
|
|
10233
|
+
var JOIN_ACT = "join";
|
|
10234
|
+
var WEBHOOK_LINE_HEAD = "webhook: ";
|
|
10235
|
+
var JOINED_LINE_HEAD = "joined: ";
|
|
10236
|
+
var webhookLineOf = (url) => `${WEBHOOK_LINE_HEAD}set to ${url}, its signing secret printed nowhere`;
|
|
10237
|
+
var setupCall = async (io2, wire, path, secret2, userAgent, act, body, hide) => {
|
|
10238
|
+
const answered = await postWire(io2, wire, path, secret2, userAgent, body);
|
|
10239
|
+
if (answered === null) return { unknown: [`The ${act} drew no answer.`] };
|
|
10240
|
+
if (answered.redirected) return { unknown: [`The ${act} was answered ${answeredHow(answered.status)}, which the command never follows, so the secret was sent to no second address.`] };
|
|
10241
|
+
const answer = planeObjectOf(answered.text);
|
|
10242
|
+
hide(answer);
|
|
10243
|
+
if (answered.status >= PLATFORM_FAILURE_STATUS) return { unknown: failureLines(act, answered.status, planeRefusalOf(answered.text)) };
|
|
10244
|
+
if (answered.status < 200 || answered.status > 299) {
|
|
10245
|
+
const refusal = planeRefusalOf(answered.text);
|
|
10246
|
+
if (refusal === null) return { unknown: [`The ${act} was answered HTTP ${answered.status}, not by the tzMesh service.`] };
|
|
10247
|
+
return { refused: refusalLines(act, answered.status, refusal) };
|
|
10248
|
+
}
|
|
10249
|
+
if (answer === null) return { unknown: [`The ${act} was answered HTTP ${answered.status}, not by the tzMesh service.`] };
|
|
10250
|
+
return { answer };
|
|
10251
|
+
};
|
|
10252
|
+
var setUpAgent = async (io2, wire, secret2, userAgent, options, ended) => {
|
|
10253
|
+
let signing = null;
|
|
10254
|
+
if (options.webhook !== null) {
|
|
10255
|
+
const url = `${options.webhook.origin}${TZMESH_WEBHOOK_ROUTE}`;
|
|
10256
|
+
const set = await setupCall(io2, wire, TZMESH_WEBHOOK_SET_PATH, secret2, userAgent, WEBHOOK_ACT, { url }, (answer) => {
|
|
10257
|
+
if (typeof answer?.signing_secret === "string") io2.hide(answer.signing_secret, REDACTED_WEBHOOK_SECRET);
|
|
10258
|
+
});
|
|
10259
|
+
if (ended()) return "ended";
|
|
10260
|
+
if (!("answer" in set)) return "refused" in set ? { refused: [...set.refused, "The webhook was not set."] } : set;
|
|
10261
|
+
const value = set.answer.signing_secret;
|
|
10262
|
+
if (typeof value !== "string" || !TZMESH_WEBHOOK_SECRET_FORM.test(value)) {
|
|
10263
|
+
return { refused: [`The ${WEBHOOK_ACT} answered no signing secret of its form, so the command keeps none.`] };
|
|
10264
|
+
}
|
|
10265
|
+
signing = value;
|
|
10266
|
+
io2.print(webhookLineOf(url));
|
|
10267
|
+
}
|
|
10268
|
+
for (const channel of options.join) {
|
|
10269
|
+
const joined = await setupCall(io2, wire, TZMESH_JOIN_PATH, secret2, userAgent, JOIN_ACT, { channel }, () => void 0);
|
|
10270
|
+
if (ended()) return "ended";
|
|
10271
|
+
if (!("answer" in joined)) return "refused" in joined ? { refused: [...joined.refused, `The agent did not join ${channel}.`] } : joined;
|
|
10272
|
+
io2.print(`${JOINED_LINE_HEAD}${channel}`);
|
|
10273
|
+
}
|
|
10274
|
+
return { signing };
|
|
10275
|
+
};
|
|
10276
|
+
var firstStoreStandsSentence = (secretName) => `${secretName} now holds the deleted agent's secret, which works nowhere, until the line runs again.`;
|
|
10277
|
+
var signingUnknownSentence = (signingName, agent) => `Whether the webhook's signing secret was stored is unknown: list_secrets from your tool shows when ${signingName} was last written. Where it was not written, end from your tool, naming participant ${agent.id} and delete true, deletes the agent ${agentWords(agent)}, and the line runs again.`;
|
|
10278
|
+
var unfinishableSentence = (agent) => `The agent ${agentWords(agent)} cannot be finished, since its webhook's signing secret ended with the run: end from your tool, naming participant ${agent.id} and delete true, deletes it, and the line runs again.`;
|
|
10279
|
+
var firstStoreUnknownSentence = (secretName) => `Whether ${secretName} was written is unknown: list_secrets from your tool shows when it was last written. Where it was, it holds the deleted agent's secret, which works nowhere, until the line runs again.`;
|
|
10280
|
+
var unfinishedStandsSentence = (agent, kept2) => `${kept2.known ? `${kept2.name} holds the secret of the agent ${agentWords(agent)}.` : `Whether ${kept2.name} holds the secret of the agent ${agentWords(agent)} is unknown: list_secrets from your tool shows when it was last written.`} ${unfinishableSentence(agent)}`;
|
|
9963
10281
|
var revokeRunToken = async (io2, plane, bearer, id, userAgent) => {
|
|
9964
10282
|
const answered = await postAction(io2, plane, REVOKE_TOKEN_ACTION, bearer, userAgent, revocationBodyOf(id));
|
|
9965
10283
|
let lines;
|
|
@@ -9979,7 +10297,8 @@ var revokeRunToken = async (io2, plane, bearer, id, userAgent) => {
|
|
|
9979
10297
|
}
|
|
9980
10298
|
return [...lines, tokenStandsSentence(id)];
|
|
9981
10299
|
};
|
|
9982
|
-
var endedLineOf = (stage, plane, agent,
|
|
10300
|
+
var endedLineOf = (stage, plane, agent, options) => {
|
|
10301
|
+
const route = options.route;
|
|
9983
10302
|
switch (stage) {
|
|
9984
10303
|
case "unsent":
|
|
9985
10304
|
return `The run was ended before its exchange. ${MINT_UNPRESENTED}`;
|
|
@@ -9990,7 +10309,11 @@ var endedLineOf = (stage, plane, agent, route) => {
|
|
|
9990
10309
|
case "registering":
|
|
9991
10310
|
return `The run was ended during the register. ${REGISTER_UNKNOWN} ${TOKEN_LEFT}`;
|
|
9992
10311
|
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}`;
|
|
10312
|
+
return agent === null ? `The run was ended after the register. ${REGISTER_UNKNOWN} ${TOKEN_LEFT}` : "secret" in route ? options.webhook !== null ? `The run was ended after the register, while its secret was being stored. ${unfinishableSentence(agent)} ${TOKEN_LEFT}` : `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}`;
|
|
10313
|
+
case "setting up":
|
|
10314
|
+
return agent === null ? `The run was ended after the register. ${REGISTER_UNKNOWN} ${TOKEN_LEFT}` : `The run was ended while the agent's webhook or channels were being set. tzmesh_participants from your tool shows the agent and its webhook. ${agentStandsSentence(agent)} ${TOKEN_LEFT}`;
|
|
10315
|
+
case "storing signing":
|
|
10316
|
+
return agent === null || options.webhook === null ? `The run was ended after the register. ${REGISTER_UNKNOWN} ${TOKEN_LEFT}` : `The run was ended while the webhook's signing secret was being stored. ${signingUnknownSentence(options.webhook.secretName, agent)} ${TOKEN_LEFT}`;
|
|
9994
10317
|
case "stored":
|
|
9995
10318
|
return `The run was ended after the agent's secret was kept, before the run's token was revoked. ${TOKEN_LEFT}`;
|
|
9996
10319
|
}
|
|
@@ -10011,15 +10334,43 @@ var completing = async (io2, options, mint, tokens, userAgent) => {
|
|
|
10011
10334
|
for (const line of lines) io2.print(line);
|
|
10012
10335
|
return Math.max(status, COMMAND_STATUS.failed);
|
|
10013
10336
|
};
|
|
10014
|
-
const deletedThen = async (minted, standing) => {
|
|
10015
|
-
const
|
|
10337
|
+
const deletedThen = async (minted, standing, whenUnknown = COMMAND_STATUS.failed, kept2 = null) => {
|
|
10338
|
+
const deleted = await deleteAgent(io2, wire, minted.value, userAgent, standing);
|
|
10016
10339
|
if (stage.ended) return COMMAND_STATUS.unknown;
|
|
10017
|
-
for (const line of lines) io2.print(line);
|
|
10018
|
-
|
|
10340
|
+
for (const line of deleted.lines) io2.print(line);
|
|
10341
|
+
if (deleted.deleted) {
|
|
10342
|
+
if (kept2 !== null) io2.print(kept2.known ? firstStoreStandsSentence(kept2.name) : firstStoreUnknownSentence(kept2.name));
|
|
10343
|
+
} else io2.print(kept2 === null ? agentStandsSentence(standing) : unfinishedStandsSentence(standing, kept2));
|
|
10344
|
+
return revokedThen(minted, deleted.unknown ? whenUnknown : COMMAND_STATUS.failed);
|
|
10345
|
+
};
|
|
10346
|
+
const storeNamed = async (name, value) => {
|
|
10347
|
+
const action = SECRET_ACTION.store;
|
|
10348
|
+
const answered = await postAction(io2, options.origin, action, (tokens.store ?? tokens.mint).token, userAgent, {
|
|
10349
|
+
name,
|
|
10350
|
+
value,
|
|
10351
|
+
...options.application !== null ? { application: options.application } : {},
|
|
10352
|
+
...options.environment !== null ? { environment: options.environment } : {}
|
|
10353
|
+
});
|
|
10354
|
+
if (stage.ended) return "ended";
|
|
10355
|
+
if (answered === null) return { unknown: [`${action} drew no answer.`] };
|
|
10356
|
+
if (answered.redirected) return { unknown: [`${action} was answered ${answeredHow(answered.status)}, which the command never follows, so the value was sent to no second address.`] };
|
|
10357
|
+
if (answered.status >= PLATFORM_FAILURE_STATUS) return { unknown: failureLines(action, answered.status, planeRefusalOf(answered.text)) };
|
|
10358
|
+
const answer = planeObjectOf(answered.text);
|
|
10359
|
+
if (answered.status < 200 || answered.status > 299) {
|
|
10360
|
+
const refusal = markedRefusalOf(answered.status, answered.text);
|
|
10361
|
+
if (refusal === null) return { unknown: [`${action} was answered HTTP ${answered.status}, not by the platform.`] };
|
|
10362
|
+
for (const line of refusalLines(action, answered.status, refusal)) io2.print(line);
|
|
10363
|
+
return "refused";
|
|
10364
|
+
}
|
|
10365
|
+
if (answer === null) return { unknown: [`${action} was answered HTTP ${answered.status}, not by the platform.`] };
|
|
10366
|
+
io2.print(`${SECRET_LINE_HEAD.store}${JSON.stringify(Object.fromEntries(SECRET_SHOWN.filter((member) => member in answer).map((member) => [member, answer[member]])))}`);
|
|
10367
|
+
if (typeof answer.detail === "string") io2.print(oneLine(answer.detail));
|
|
10368
|
+
if ("value" in answer) io2.print("The answer carried a value, which the command never prints.");
|
|
10369
|
+
return "stored";
|
|
10019
10370
|
};
|
|
10020
10371
|
const carried = {
|
|
10021
10372
|
stage,
|
|
10022
|
-
endedLine: (now) => endedLineOf(now, plane, agent,
|
|
10373
|
+
endedLine: (now) => endedLineOf(now, plane, agent, options),
|
|
10023
10374
|
// The file's try, by an empty file beside it under the run's tag,
|
|
10024
10375
|
// owner-only, before any request (decision 6).
|
|
10025
10376
|
prepare: () => {
|
|
@@ -10039,7 +10390,7 @@ var completing = async (io2, options, mint, tokens, userAgent) => {
|
|
|
10039
10390
|
},
|
|
10040
10391
|
deliver: async (minted) => {
|
|
10041
10392
|
stage.now = "registering";
|
|
10042
|
-
const registered = await register(io2, wire, minted.value, userAgent, options
|
|
10393
|
+
const registered = await register(io2, wire, minted.value, userAgent, options);
|
|
10043
10394
|
if (stage.ended) return COMMAND_STATUS.unknown;
|
|
10044
10395
|
if ("refused" in registered) {
|
|
10045
10396
|
for (const line of registered.refused) io2.print(line);
|
|
@@ -10072,34 +10423,43 @@ var completing = async (io2, options, mint, tokens, userAgent) => {
|
|
|
10072
10423
|
io2.print(WRITTEN_LINE);
|
|
10073
10424
|
return revokedThen(minted, COMMAND_STATUS.done);
|
|
10074
10425
|
}
|
|
10075
|
-
|
|
10076
|
-
|
|
10077
|
-
|
|
10078
|
-
|
|
10079
|
-
|
|
10080
|
-
|
|
10081
|
-
|
|
10082
|
-
|
|
10083
|
-
|
|
10084
|
-
|
|
10426
|
+
let signing = null;
|
|
10427
|
+
if (options.webhook !== null || options.join.length > 0) {
|
|
10428
|
+
stage.now = "setting up";
|
|
10429
|
+
const set = await setUpAgent(io2, wire, secret2, userAgent, options, () => stage.ended);
|
|
10430
|
+
if (set === "ended" || stage.ended) return COMMAND_STATUS.unknown;
|
|
10431
|
+
if ("refused" in set) {
|
|
10432
|
+
for (const line of set.refused) io2.print(line);
|
|
10433
|
+
return deletedThen(minted, agent);
|
|
10434
|
+
}
|
|
10435
|
+
if ("unknown" in set) {
|
|
10436
|
+
for (const line of set.unknown) io2.print(line);
|
|
10437
|
+
return deletedThen(minted, agent, COMMAND_STATUS.unknown);
|
|
10438
|
+
}
|
|
10439
|
+
signing = set.signing;
|
|
10440
|
+
stage.now = "registered";
|
|
10441
|
+
}
|
|
10442
|
+
const stored = await storeNamed(route.secret, secret2);
|
|
10443
|
+
if (stored === "ended" || stage.ended) return COMMAND_STATUS.unknown;
|
|
10444
|
+
if (stored === "refused") return deletedThen(minted, agent);
|
|
10445
|
+
if (stored !== "stored") {
|
|
10446
|
+
for (const line of stored.unknown) io2.print(line);
|
|
10447
|
+
if (options.webhook !== null) return deletedThen(minted, agent, COMMAND_STATUS.unknown, { name: route.secret, known: false });
|
|
10085
10448
|
io2.print(storeUnknownSentence(route.secret, agent));
|
|
10086
10449
|
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
10450
|
}
|
|
10098
|
-
if (
|
|
10451
|
+
if (options.webhook !== null && signing !== null) {
|
|
10452
|
+
stage.now = "storing signing";
|
|
10453
|
+
const kept2 = await storeNamed(options.webhook.secretName, signing);
|
|
10454
|
+
if (kept2 === "ended" || stage.ended) return COMMAND_STATUS.unknown;
|
|
10455
|
+
if (kept2 === "refused") return deletedThen(minted, agent, COMMAND_STATUS.failed, { name: route.secret, known: true });
|
|
10456
|
+
if (kept2 !== "stored") {
|
|
10457
|
+
for (const line of kept2.unknown) io2.print(line);
|
|
10458
|
+
io2.print(signingUnknownSentence(options.webhook.secretName, agent));
|
|
10459
|
+
return revokedThen(minted, COMMAND_STATUS.unknown);
|
|
10460
|
+
}
|
|
10461
|
+
}
|
|
10099
10462
|
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
10463
|
return revokedThen(minted, COMMAND_STATUS.done);
|
|
10104
10464
|
}
|
|
10105
10465
|
};
|
|
@@ -10173,6 +10533,7 @@ var TZMESH_ROW = Object.freeze({
|
|
|
10173
10533
|
`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
10534
|
`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
10535
|
`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.`,
|
|
10536
|
+
`For an agent a Turn Zero Cloud application hosts, the same run sets it up. ${TZMESH_OPTION.webhookOrigin} sets its webhook at that application's origin, and ${TZMESH_OPTION.webhookSecret} names where the webhook's signing secret is stored. ${TZMESH_OPTION.join} joins its channels. Its description, title, and ${TZMESH_OPTION.public} go into the register. Where a step fails, follow the recovery the run prints before running the line again.`,
|
|
10176
10537
|
`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
10538
|
],
|
|
10178
10539
|
afterOwnError: (call) => call.named[TZMESH_OPTION.mint] !== void 0 ? TZMESH_AFTER_OWN_ERROR : TZMESH_FIRST_ACT_AFTER_OWN_ERROR,
|
|
@@ -10519,7 +10880,7 @@ var SUBCOMMANDS = Object.freeze([
|
|
|
10519
10880
|
]);
|
|
10520
10881
|
var listedSubcommands = () => SUBCOMMANDS.filter((subcommand) => subcommand.listed !== false);
|
|
10521
10882
|
var SERVED = LINE_RUNNER;
|
|
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
|
|
10883
|
+
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 chooses its deploy route. It installs the command for regular use where it can install and run it and reach the platform. It uses deploy_files within its caps for a first simple test or where the command cannot work. Past the caps, where it may not install or run the command, it uploads a zip with mint_upload_grant and names it as deploy's artifact. For any other line it takes the deploy skill's setup steps, never the npx line.`;
|
|
10523
10884
|
var namedWithActs = (subcommand) => subcommand.acts ? `${subcommand.name} ${subcommand.acts.join("|")}` : subcommand.name;
|
|
10524
10885
|
var shown = (option) => option.flag ? option.name : `${option.name} ${option.value}`;
|
|
10525
10886
|
var listed = (names) => names.length < 3 ? names.join(" and ") : `${names.slice(0, -1).join(", ")}, and ${names[names.length - 1]}`;
|