turnzero 0.18.1 → 0.18.2-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 +40 -26
- package/package.json +1 -1
package/dist/turnzero-cloud.mjs
CHANGED
|
@@ -895,7 +895,7 @@ var variableReadSentence = (origin, standing) => {
|
|
|
895
895
|
};
|
|
896
896
|
var fileReadSentence = (origin) => `The credential this run read was this computer's token for ${origin}, from its credential file: where the platform no longer accepts it, run ${LOGIN_SUBCOMMAND}${originWordsOf(origin)} to authorize this computer again.`;
|
|
897
897
|
var noTokenSentence = (origin, expiredAt) => expiredAt === null ? `No credential was read, so nothing was sent: ${MINTED_TOKEN_VARIABLE} is not set, and this computer's credential file holds no token for ${origin}.` : `No credential was read, so nothing was sent: ${MINTED_TOKEN_VARIABLE} is not set, and this computer's token for ${origin} in its credential file expired at ${expiredAt}.`;
|
|
898
|
-
var VARIABLE_ROUTE_SENTENCES = `A tool connected by a minted token, or a job,
|
|
898
|
+
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, and ${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 the deploy or check line alone and unsets it once that line ends.`;
|
|
899
899
|
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:";
|
|
900
900
|
var DEPLOY_FILES_ROUTE_SENTENCE = "A folder within the caps of your tool's deploy_files call deploys now through deploy_files, with no login.";
|
|
901
901
|
var loginRouteLines = (io2, origin) => [LOGIN_ROUTE_OPENER, ...loginLinesFor(io2, origin), DEPLOY_FILES_ROUTE_SENTENCE];
|
|
@@ -3584,9 +3584,9 @@ var DEPLOY_ROW = Object.freeze({
|
|
|
3584
3584
|
variables: [[DEPLOY_NO_WAIT_VARIABLE, "any value returns the command once the deploy has started, without waiting for it."]],
|
|
3585
3585
|
note: [
|
|
3586
3586
|
`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, and sends it 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}.`,
|
|
3587
|
-
`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,
|
|
3587
|
+
`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, such as the job's secret store, 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.`,
|
|
3588
3588
|
`Otherwise a person logs this computer in once with ${LOGIN_SUBCOMMAND}, in a terminal of their own, then runs the deploy line again; a folder within the caps of the tool's deploy_files call deploys now through deploy_files, with no login. The credential file is ${CREDENTIAL_FILE_WORDS}.`,
|
|
3589
|
-
`A tool sets ${MINTED_TOKEN_VARIABLE} for the deploy or check line alone and unsets it once that line ends, since the command cannot unset a variable of the shell that started it. 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.`,
|
|
3589
|
+
`A tool sets ${MINTED_TOKEN_VARIABLE} for the deploy or check line alone 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.`,
|
|
3590
3590
|
`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.`,
|
|
3591
3591
|
`A progress read answered 502, 503, or 504, which is often temporary, is made again, at most three more times, and an upload answered 503 credential_lookup_busy, which wrote nothing, is made again after the wait it names, at most twice.`,
|
|
3592
3592
|
`After its zip line, ${DEPLOY_SUBCOMMAND} prints the folder's top-level entries the zip holds on one line, at most ten and then the count of the rest, and ${HASH_SUBCOMMAND} ${HASH_OPTION.list} names every file; no such line prints for a .zip file.`,
|
|
@@ -4511,7 +4511,8 @@ var npmEntryOf = (io2, nodePath) => npmEntryCandidatesOf(io2.env, nodePath).find
|
|
|
4511
4511
|
return false;
|
|
4512
4512
|
}
|
|
4513
4513
|
}) ?? null;
|
|
4514
|
-
var npmStartOf = (viaShell = NPM_NEEDS_SHELL, entry = null, nodePath = process.execPath) => entry !== null ? { command: nodePath, args: [entry,
|
|
4514
|
+
var npmStartOf = (viaShell = NPM_NEEDS_SHELL, entry = null, nodePath = process.execPath) => entry !== null ? { command: nodePath, args: [entry, ...START_ARGS] } : viaShell ? { command: ["npm", ...START_ARGS].join(" "), args: [], shell: true } : { command: "npm", args: START_ARGS };
|
|
4515
|
+
var START_ARGS = Object.freeze(["start", "--no-update-notifier"]);
|
|
4515
4516
|
var npmRunOf = (words, viaShell = NPM_NEEDS_SHELL, entry = null, nodePath = process.execPath) => entry !== null ? { command: nodePath, args: [entry, ...words] } : viaShell ? { command: ["npm", ...words].join(" "), args: [], shell: true } : { command: "npm", args: words };
|
|
4516
4517
|
var INTERRUPTED_ON_WINDOWS = 'The application has ended. cmd may ask "Terminate batch job (Y/N)?" next: either answer returns the prompt.';
|
|
4517
4518
|
var afterInterruptLineOf = (ended, onWindows2 = NPM_NEEDS_SHELL) => onWindows2 && ended.interrupted === true ? INTERRUPTED_ON_WINDOWS : null;
|
|
@@ -5050,6 +5051,7 @@ var committedFilesOf = (copied, written) => {
|
|
|
5050
5051
|
return `${files.slice(0, -1).join(", ")}${files.length > 2 ? "," : ""} and ${files[files.length - 1]}`;
|
|
5051
5052
|
};
|
|
5052
5053
|
var COPY_PACKAGES_CLAUSE = "copy the packages line into the application manifest's packages member at each submission; ";
|
|
5054
|
+
var KEEP_PACKAGES_CLAUSE = "the application manifest was written whole, so read it again before patching it, and carry its packages member over in any later rewrite; ";
|
|
5053
5055
|
var installFailedSentence = (folder) => `npm install in ${folder} did not finish: the entry, its row, and the copy are written. Run npm install there again; running this line again takes the entry again whole.`;
|
|
5054
5056
|
var LIBRARY_AFTER_OWN_ERROR = "the entry's folder, its manifest row, or the application's copy may stand in part, and running the line again replaces each whole";
|
|
5055
5057
|
async function readTake(io2, options, userAgent, planOf, planeChecked = false) {
|
|
@@ -5183,7 +5185,7 @@ async function installTake(io2, root, plan, manifestText, application) {
|
|
|
5183
5185
|
io2.print(`${packagesLineOf(packagesOf(manifestText))} ${packagesWhereOf(root, application)}`);
|
|
5184
5186
|
if (!("written" in application) && application.unwritten === "write_failed") status = COMMAND_STATUS.failed;
|
|
5185
5187
|
io2.print(
|
|
5186
|
-
`next: commit ${committedFilesOf(plan !== null, "written" in application)}; ${"written" in application ?
|
|
5188
|
+
`next: commit ${committedFilesOf(plan !== null, "written" in application)}; ${"written" in application ? KEEP_PACKAGES_CLAUSE : COPY_PACKAGES_CLAUSE}and, where the project holds the registrar, pin the version in its instance file and run validate with kind library.`
|
|
5187
5189
|
);
|
|
5188
5190
|
printAfterInterrupt(io2, afterInterrupt);
|
|
5189
5191
|
return status;
|
|
@@ -5772,7 +5774,7 @@ var startUpgradeCheck = (io2, subcommand, named, running) => {
|
|
|
5772
5774
|
};
|
|
5773
5775
|
|
|
5774
5776
|
// src/turnzero_cloud_command/provision.ts
|
|
5775
|
-
import { basename as basename3 } from "node:path";
|
|
5777
|
+
import { basename as basename3, dirname as dirname5, join as join8 } from "node:path";
|
|
5776
5778
|
var PROVISION_OPTIONS = Object.freeze([
|
|
5777
5779
|
{
|
|
5778
5780
|
name: PROVISION_OPTION.application,
|
|
@@ -5824,6 +5826,15 @@ var provisionOptionsOf = (call, cwd, stands = () => false) => {
|
|
|
5824
5826
|
if (!environmentFileName(basename3(envFile))) return { refusal: envFileNameRefusalOf(stands(envFile)) };
|
|
5825
5827
|
return { application, envFile, origin: origin.origin };
|
|
5826
5828
|
};
|
|
5829
|
+
var APPLICATION_FOLDER_MARKS = Object.freeze(["package.json", "manifest.json"]);
|
|
5830
|
+
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.`;
|
|
5831
|
+
var outsideApplicationFolder = (io2, envFile) => APPLICATION_FOLDER_MARKS.every((mark) => {
|
|
5832
|
+
try {
|
|
5833
|
+
return io2.stat(join8(dirname5(envFile), mark))?.folder !== false;
|
|
5834
|
+
} catch {
|
|
5835
|
+
return false;
|
|
5836
|
+
}
|
|
5837
|
+
});
|
|
5827
5838
|
var charactersOf = (value) => `<${value.length} characters>`;
|
|
5828
5839
|
var transportText = (error) => {
|
|
5829
5840
|
const oneLine2 = (text) => text.replace(/\s+/g, " ").trim();
|
|
@@ -6110,6 +6121,7 @@ async function remintAndWrite(io2, { application, envFile, origin }, userAgent,
|
|
|
6110
6121
|
);
|
|
6111
6122
|
}
|
|
6112
6123
|
if (typeof platform.answer.detail === "string") io2.print(oneLine(platform.answer.detail));
|
|
6124
|
+
if (outsideApplicationFolder(io2, envFile)) io2.print(outsideApplicationWarningOf(dirname5(envFile)));
|
|
6113
6125
|
if (facts !== null && limitCarried !== null) {
|
|
6114
6126
|
const cause = limitMember ? "the plan's database-connection-limit holds no usable quantity, which platform staff set with set_plan_quota" : "the platform that answered serves no such member yet";
|
|
6115
6127
|
io2.print(
|
|
@@ -6146,7 +6158,7 @@ var PROVISION_ROW = Object.freeze({
|
|
|
6146
6158
|
});
|
|
6147
6159
|
|
|
6148
6160
|
// src/turnzero_cloud_command/scaffold.ts
|
|
6149
|
-
import { basename as basename4, dirname as
|
|
6161
|
+
import { basename as basename4, dirname as dirname6, isAbsolute as isAbsolute5, join as join9, relative as relative5, resolve as resolve11 } from "node:path";
|
|
6150
6162
|
|
|
6151
6163
|
// src/turnzero_cloud_command/scaffold_template.ts
|
|
6152
6164
|
var SCAFFOLD_TEMPLATE_FILES = Object.freeze({
|
|
@@ -7540,6 +7552,7 @@ var templatesDescribed = () => [
|
|
|
7540
7552
|
`The template to write, one of ${andListed(SCAFFOLD_TEMPLATES)}, ${SCAFFOLD_DEFAULT_TEMPLATE} where absent.`,
|
|
7541
7553
|
...SCAFFOLD_TEMPLATES.map((template) => `The ${template} template is ${TEMPLATE_FACTS[template].is}.`)
|
|
7542
7554
|
].join(" ");
|
|
7555
|
+
var OTHER_TYPE_WAY_ON = "For a type outside these, name the nearest kind, then change the written migration and routes: the files are your service's own.";
|
|
7543
7556
|
var SCAFFOLD_OPTIONS = Object.freeze([
|
|
7544
7557
|
{
|
|
7545
7558
|
name: SCAFFOLD_OPTION.template,
|
|
@@ -7563,7 +7576,7 @@ var SCAFFOLD_OPTIONS = Object.freeze([
|
|
|
7563
7576
|
name: SCAFFOLD_OPTION.fields,
|
|
7564
7577
|
value: "<list>",
|
|
7565
7578
|
required: false,
|
|
7566
|
-
description: `Under ${RESOURCE_TEMPLATES_NAMED}, the resource's columns: fields separated by commas, each a name, a colon, and a kind, such as "name:text,message:text", written between double quotes. A name is an ASCII lower-case letter, then ASCII lower-case letters, digits, and underscores, at most 30 characters. It is never a column the migration writes itself: ${perResourceTemplate((kept2) => kept2.columns)}. A kind is ${orListed(SCAFFOLD_FIELD_KINDS)}. Every column is required, and a list holds one to ${SCAFFOLD_FIELDS_MAX} fields. Where absent, the service keeps one text column, title. A template that keeps no resource refuses it.`
|
|
7579
|
+
description: `Under ${RESOURCE_TEMPLATES_NAMED}, the resource's columns: fields separated by commas, each a name, a colon, and a kind, such as "name:text,message:text", written between double quotes. A name is an ASCII lower-case letter, then ASCII lower-case letters, digits, and underscores, at most 30 characters. It is never a column the migration writes itself: ${perResourceTemplate((kept2) => kept2.columns)}. A kind is ${orListed(SCAFFOLD_FIELD_KINDS)}. ${OTHER_TYPE_WAY_ON} Every column is required, and a list holds one to ${SCAFFOLD_FIELDS_MAX} fields. Where absent, the service keeps one text column, title. A template that keeps no resource refuses it.`
|
|
7567
7580
|
},
|
|
7568
7581
|
{
|
|
7569
7582
|
name: SCAFFOLD_OPTION.path,
|
|
@@ -7645,8 +7658,9 @@ var FIELD_REFUSAL = Object.freeze({
|
|
|
7645
7658
|
nameForm: `${SCAFFOLD_OPTION.fields} takes each field's name as an ASCII lower-case letter, then ASCII lower-case letters, digits, and underscores, at most 30 characters, such as due_date, and ${FIELD_KINDS_CLAUSE}. ${NOTHING_WRITTEN2}`,
|
|
7646
7659
|
/** A name of SCAFFOLD_FIELD_RESERVED. */
|
|
7647
7660
|
reservedName: reservedFieldRefusal(SCAFFOLD_FIELD_RESERVED),
|
|
7648
|
-
/** A kind outside SCAFFOLD_FIELD_KINDS
|
|
7649
|
-
|
|
7661
|
+
/** A kind outside SCAFFOLD_FIELD_KINDS, with the way on for another type
|
|
7662
|
+
* (#4572). */
|
|
7663
|
+
kindUnknown: `${SCAFFOLD_OPTION.fields} takes each field's kind after its name and a colon, ${FIELD_KINDS_CLAUSE}, such as count:integer. ${OTHER_TYPE_WAY_ON} ${NOTHING_WRITTEN2}`,
|
|
7650
7664
|
/** Two fields under one name. */
|
|
7651
7665
|
duplicate: `${SCAFFOLD_OPTION.fields} takes each field's name once, and two fields of the list share a name, ${FIELD_KINDS_CLAUSE} after each: name each field once. ${NOTHING_WRITTEN2}`
|
|
7652
7666
|
});
|
|
@@ -8047,18 +8061,18 @@ var ownStage = (io2, stage, files) => {
|
|
|
8047
8061
|
const folders = new Set([...texts.keys()].flatMap((path) => path.split("/").slice(0, -1).map((_, index, segments) => segments.slice(0, index + 1).join("/"))));
|
|
8048
8062
|
const own = (at, prefix) => (io2.listFolder(at) ?? []).every((name) => {
|
|
8049
8063
|
const path = prefix === "" ? name : `${prefix}/${name}`;
|
|
8050
|
-
const standing = io2.stat(
|
|
8064
|
+
const standing = io2.stat(join9(at, name));
|
|
8051
8065
|
if (standing === null) return false;
|
|
8052
|
-
if (standing.folder) return folders.has(path) && own(
|
|
8066
|
+
if (standing.folder) return folders.has(path) && own(join9(at, name), path);
|
|
8053
8067
|
const text = texts.get(path);
|
|
8054
|
-
return text !== void 0 && ownFile(io2,
|
|
8068
|
+
return text !== void 0 && ownFile(io2, join9(at, name), standing.size, path, text);
|
|
8055
8069
|
});
|
|
8056
8070
|
return own(stage, "");
|
|
8057
8071
|
};
|
|
8058
|
-
var danglingAt = (io2, folder, name) => io2.stat(
|
|
8072
|
+
var danglingAt = (io2, folder, name) => io2.stat(join9(folder, name)) === null && (io2.listFolder(folder) ?? []).some((held) => held.toLowerCase() === name.toLowerCase() && io2.stat(join9(folder, held)) === null);
|
|
8059
8073
|
var standsAt = (io2, folder, name) => {
|
|
8060
8074
|
try {
|
|
8061
|
-
return io2.stat(
|
|
8075
|
+
return io2.stat(join9(folder, name)) !== null || danglingAt(io2, folder, name);
|
|
8062
8076
|
} catch {
|
|
8063
8077
|
return true;
|
|
8064
8078
|
}
|
|
@@ -8081,16 +8095,16 @@ var applicationStandsLines = (template, takeLines) => {
|
|
|
8081
8095
|
var STAGE_NOT_OWN = `Something that is not this run's own stands at ${STAGE_FOLDER} in the project's root, the name the scaffold writes under, an earlier run's files under another template or another resource name among it: move or remove ${STAGE_FOLDER}, then run the line again. ${NOTHING_WRITTEN2}`;
|
|
8082
8096
|
var folderRefusalOf = (io2, options, files, takeLines) => {
|
|
8083
8097
|
const { root } = options;
|
|
8084
|
-
for (let at = root; ; at =
|
|
8098
|
+
for (let at = root; ; at = dirname6(at)) {
|
|
8085
8099
|
const standing2 = io2.stat(at);
|
|
8086
|
-
const what = standing2 !== null ? standing2.folder ? null : "a file" : danglingAt(io2,
|
|
8100
|
+
const what = standing2 !== null ? standing2.folder ? null : "a file" : danglingAt(io2, dirname6(at), basename4(at)) ? "a link whose target does not stand" : null;
|
|
8087
8101
|
if (what !== null) {
|
|
8088
8102
|
return [`${options.named ? `${SCAFFOLD_OPTION.path} names ${what}, or a place under one` : `The folder the line runs in is ${what}, or stands under one`}, where the project's root stands or is made. ${NOTHING_WRITTEN2}`];
|
|
8089
8103
|
}
|
|
8090
|
-
if (standing2 !== null ||
|
|
8104
|
+
if (standing2 !== null || dirname6(at) === at) break;
|
|
8091
8105
|
}
|
|
8092
|
-
const app =
|
|
8093
|
-
const stage =
|
|
8106
|
+
const app = join9(root, APPLICATION_FOLDER);
|
|
8107
|
+
const stage = join9(root, STAGE_FOLDER);
|
|
8094
8108
|
const notOwn = STAGE_NOT_OWN;
|
|
8095
8109
|
const standing = io2.stat(app);
|
|
8096
8110
|
if (standing === null ? danglingAt(io2, root, APPLICATION_FOLDER) : !standing.folder) return [noFolderSentence(APPLICATION_FOLDER, "the scaffold writes the application")];
|
|
@@ -8198,8 +8212,8 @@ var nextStepLines = (origin, windows = LINES_IN_WINDOWS_FORM, left = NEITHER_LEF
|
|
|
8198
8212
|
var writeTemplate = (io2, stage, app, files) => {
|
|
8199
8213
|
io2.remove(stage);
|
|
8200
8214
|
for (const [path, text] of files) {
|
|
8201
|
-
const at =
|
|
8202
|
-
io2.makeFolder(
|
|
8215
|
+
const at = join9(stage, ...path.split("/"));
|
|
8216
|
+
io2.makeFolder(dirname6(at));
|
|
8203
8217
|
io2.writeFile(at, text);
|
|
8204
8218
|
}
|
|
8205
8219
|
const standing = io2.stat(app);
|
|
@@ -8211,7 +8225,7 @@ var writeTemplate = (io2, stage, app, files) => {
|
|
|
8211
8225
|
};
|
|
8212
8226
|
var writeRootSentence = (io2, root) => {
|
|
8213
8227
|
try {
|
|
8214
|
-
io2.writeNewFile(
|
|
8228
|
+
io2.writeNewFile(join9(root, TOOLS_FILE), `${ROOT_SENTENCE}
|
|
8215
8229
|
`);
|
|
8216
8230
|
return "written";
|
|
8217
8231
|
} catch (error) {
|
|
@@ -8268,8 +8282,8 @@ async function scaffold(call, io2) {
|
|
|
8268
8282
|
const { takes } = TEMPLATE_FACTS[template];
|
|
8269
8283
|
const defaulted = call.named[SCAFFOLD_OPTION.template] === void 0;
|
|
8270
8284
|
const files = writtenFilesOf(template, options.names, options.fields);
|
|
8271
|
-
const app =
|
|
8272
|
-
const stage =
|
|
8285
|
+
const app = join9(root, APPLICATION_FOLDER);
|
|
8286
|
+
const stage = join9(root, STAGE_FOLDER);
|
|
8273
8287
|
const takeLines = takes.map((take) => machineLineOf(libraryTakeLineOf({ origin, entry: take.entry }), { windows: io2.windows ?? LINES_IN_WINDOWS_FORM, npx: ranThroughNpx(io2) }, origin));
|
|
8274
8288
|
let reached = "checks";
|
|
8275
8289
|
const stateNow = () => {
|
|
@@ -8298,7 +8312,7 @@ async function scaffold(call, io2) {
|
|
|
8298
8312
|
held = found;
|
|
8299
8313
|
} else {
|
|
8300
8314
|
for (const take of takes) {
|
|
8301
|
-
const copy =
|
|
8315
|
+
const copy = join9(app, "lib", take.entry);
|
|
8302
8316
|
const planOf = (library) => writesOver(library, copy) ? { refusal: LIBRARY_OVER_APPLICATION } : { application: app, copy, declared: null, declaredAt: null };
|
|
8303
8317
|
const read2 = await readTake(io2, { entry: take.entry, root, named: options.named, origin }, agent.userAgent, planOf, checks.length > 0);
|
|
8304
8318
|
if ("lines" in read2) return refuse(...read2.lines);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "turnzero",
|
|
3
|
-
"version": "0.18.1",
|
|
3
|
+
"version": "0.18.2-next.1",
|
|
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",
|