turnzero 0.18.3 → 0.19.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/README.md +1 -1
- package/dist/turnzero-cloud.mjs +238 -103
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Turn Zero Cloud connects to your AI coding tool through a Model Context Protocol (MCP) server. Once connected, your AI can code, build, and test backends, connect them to your app, and host your code in the cloud.
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Your AI coding tool writes the app; Turn Zero Cloud runs it, with hosting, database, sign-in and scaling included. Your tool writes, builds, and tests the application on your computer. The platform builds it, runs it in production at the application's address, and records its logs, counters, and usage. To start, connect your AI coding tool: https://turnzero.ai/cloud/getting-started/connect-your-tool/
|
|
6
6
|
|
|
7
7
|
## What this package is
|
|
8
8
|
|
package/dist/turnzero-cloud.mjs
CHANGED
|
@@ -222,7 +222,8 @@ var SCAFFOLD_OPTION = Object.freeze({
|
|
|
222
222
|
singular: "--singular",
|
|
223
223
|
fields: "--fields",
|
|
224
224
|
path: DEPLOY_OPTION.path,
|
|
225
|
-
origin: DEPLOY_OPTION.origin
|
|
225
|
+
origin: DEPLOY_OPTION.origin,
|
|
226
|
+
application: DEPLOY_OPTION.application
|
|
226
227
|
});
|
|
227
228
|
var SCAFFOLD_NAME_FORM = /^[a-z][a-z0-9]{0,29}$/;
|
|
228
229
|
var SCAFFOLD_FIELD_NAME_FORM = /^[a-z][a-z0-9_]{0,29}$/;
|
|
@@ -419,6 +420,10 @@ var originOf = (text) => {
|
|
|
419
420
|
if (url.protocol === "http:" && LOOPBACK_HOSTNAMES.includes(url.hostname)) return url.origin;
|
|
420
421
|
return null;
|
|
421
422
|
};
|
|
423
|
+
var originReadOf = (value) => {
|
|
424
|
+
const held = (value ?? "").trim();
|
|
425
|
+
return held === "" ? DEFAULT_COMMAND_ORIGIN : originOf(held) ?? held;
|
|
426
|
+
};
|
|
422
427
|
var commandOriginOf = (text) => {
|
|
423
428
|
const origin = originOf(text);
|
|
424
429
|
if (origin !== null) return { origin };
|
|
@@ -2922,6 +2927,76 @@ function healthPathReadingOf(bytes, reading, recorded) {
|
|
|
2922
2927
|
};
|
|
2923
2928
|
}
|
|
2924
2929
|
|
|
2930
|
+
// src/turnzero_cloud_command/application_manifest.ts
|
|
2931
|
+
import { join as join3, relative as relative3 } from "node:path";
|
|
2932
|
+
var FOLDER_MANIFEST = "manifest.json";
|
|
2933
|
+
var APPLICATION_MEMBER = "application";
|
|
2934
|
+
var BYTE_ORDER_MARK3 = "\uFEFF";
|
|
2935
|
+
var jsonTextOf = (bytes) => {
|
|
2936
|
+
const text = bytes.toString("utf8");
|
|
2937
|
+
return text.startsWith(BYTE_ORDER_MARK3) ? text.slice(BYTE_ORDER_MARK3.length) : text;
|
|
2938
|
+
};
|
|
2939
|
+
var applicationManifestPartialOf = (at) => `${at}.partial`;
|
|
2940
|
+
var NOT_BOUND = Object.freeze({ kind: "unbound", manifest: null });
|
|
2941
|
+
var folderBindingOf = (io2, path) => {
|
|
2942
|
+
let text;
|
|
2943
|
+
let at;
|
|
2944
|
+
try {
|
|
2945
|
+
const folder = io2.realPath(path);
|
|
2946
|
+
if (folder === null) return NOT_BOUND;
|
|
2947
|
+
at = join3(folder, FOLDER_MANIFEST);
|
|
2948
|
+
const real = io2.realPath(at);
|
|
2949
|
+
if (real === null || relative3(at, real) !== "") return NOT_BOUND;
|
|
2950
|
+
const standing = io2.stat(at);
|
|
2951
|
+
if (standing === null || standing.folder) return NOT_BOUND;
|
|
2952
|
+
text = jsonTextOf(io2.readFile(at));
|
|
2953
|
+
} catch {
|
|
2954
|
+
return NOT_BOUND;
|
|
2955
|
+
}
|
|
2956
|
+
let parsed;
|
|
2957
|
+
try {
|
|
2958
|
+
parsed = JSON.parse(text);
|
|
2959
|
+
} catch {
|
|
2960
|
+
return NOT_BOUND;
|
|
2961
|
+
}
|
|
2962
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return NOT_BOUND;
|
|
2963
|
+
const members = parsed;
|
|
2964
|
+
if (!Object.prototype.hasOwnProperty.call(members, APPLICATION_MEMBER)) return { kind: "unbound", manifest: { at, parsed: members } };
|
|
2965
|
+
const application = members[APPLICATION_MEMBER];
|
|
2966
|
+
return typeof application === "string" && UPLOAD_ID.test(application) ? { kind: "bound", application } : { kind: "off_form" };
|
|
2967
|
+
};
|
|
2968
|
+
var BOUND_LINE_HEAD = "bound: ";
|
|
2969
|
+
var boundLineOf = (application) => `${BOUND_LINE_HEAD}${FOLDER_MANIFEST} now names application ${application}; a deploy or check line naming another application is refused`;
|
|
2970
|
+
var BIND_WRITE_FAILED_LINE = `${FOLDER_MANIFEST} could not be written to bind this folder to its application, so the deploy goes on unbound, and the next deploy writes it again.`;
|
|
2971
|
+
var boundElsewhereSentence = (bound) => `${FOLDER_MANIFEST} binds this folder to application ${bound}, and this line names another.`;
|
|
2972
|
+
var OFF_FORM_SENTENCE = `${FOLDER_MANIFEST}'s ${APPLICATION_MEMBER} member is not an application id, a lowercase UUID, so it binds this folder to no application a line can name.`;
|
|
2973
|
+
var BINDING_OWNER_ASK = `Ask the account's owner; where they mean this folder for that application, change or remove the manifest's ${APPLICATION_MEMBER} member, then run the line again.`;
|
|
2974
|
+
var HASH_BINDING_OWNER_ASK = `Ask the account's owner which application this folder deploys to; change or remove the manifest's ${APPLICATION_MEMBER} member to match, then run the line again.`;
|
|
2975
|
+
var bindingRefusalOf = (binding, application, closing) => {
|
|
2976
|
+
if (binding.kind === "unbound" || binding.kind === "bound" && binding.application === application) return null;
|
|
2977
|
+
const first = binding.kind === "bound" ? boundElsewhereSentence(binding.application) : OFF_FORM_SENTENCE;
|
|
2978
|
+
return `${first} ${closing} ${BINDING_OWNER_ASK}`;
|
|
2979
|
+
};
|
|
2980
|
+
var manifestTextWithMember = (parsed, member, value) => `${JSON.stringify({ ...parsed, [member]: value }, null, 2)}
|
|
2981
|
+
`;
|
|
2982
|
+
var writeManifestMember = (io2, manifest, member, value) => {
|
|
2983
|
+
const partial = applicationManifestPartialOf(manifest.at);
|
|
2984
|
+
let made = false;
|
|
2985
|
+
try {
|
|
2986
|
+
if (io2.stat(partial)?.folder === false) io2.remove(partial);
|
|
2987
|
+
made = io2.stat(partial) === null;
|
|
2988
|
+
io2.writeNewFile(partial, manifestTextWithMember(manifest.parsed, member, value));
|
|
2989
|
+
io2.rename(partial, manifest.at);
|
|
2990
|
+
} catch {
|
|
2991
|
+
try {
|
|
2992
|
+
if (made) io2.remove(partial);
|
|
2993
|
+
} catch {
|
|
2994
|
+
}
|
|
2995
|
+
return false;
|
|
2996
|
+
}
|
|
2997
|
+
return true;
|
|
2998
|
+
};
|
|
2999
|
+
|
|
2925
3000
|
// src/turnzero_cloud_command/deploy.ts
|
|
2926
3001
|
import { createHash as createHash2 } from "node:crypto";
|
|
2927
3002
|
import { readFileSync as readFileSync4, realpathSync, statSync as statSync3 } from "node:fs";
|
|
@@ -2929,7 +3004,7 @@ import { resolve as resolve4 } from "node:path";
|
|
|
2929
3004
|
|
|
2930
3005
|
// src/turnzero_cloud_command/commit.ts
|
|
2931
3006
|
import { readFileSync as readFileSync2, statSync } from "node:fs";
|
|
2932
|
-
import { dirname as dirname3, join as
|
|
3007
|
+
import { dirname as dirname3, join as join4, resolve as resolve3 } from "node:path";
|
|
2933
3008
|
var START_COMMIT_FORM = /^[0-9a-f]{7,64}$/;
|
|
2934
3009
|
var GIT_ENTRY = ".git";
|
|
2935
3010
|
var SYMBOLIC_DEPTH_MAX = 5;
|
|
@@ -2959,7 +3034,7 @@ var firstLineOf = (text) => (text.split(/\r?\n/, 1)[0] ?? "").trim();
|
|
|
2959
3034
|
var gitFolderOf = (folder, reads = FILE_SYSTEM_READS) => {
|
|
2960
3035
|
let dir = resolve3(folder);
|
|
2961
3036
|
for (; ; ) {
|
|
2962
|
-
const entry =
|
|
3037
|
+
const entry = join4(dir, GIT_ENTRY);
|
|
2963
3038
|
const kind = reads.kind(entry);
|
|
2964
3039
|
if (kind === "folder") return entry;
|
|
2965
3040
|
if (kind === "file") {
|
|
@@ -2977,7 +3052,7 @@ var gitFolderOf = (folder, reads = FILE_SYSTEM_READS) => {
|
|
|
2977
3052
|
}
|
|
2978
3053
|
};
|
|
2979
3054
|
var sharedGitFolderOf = (gitFolder, reads = FILE_SYSTEM_READS) => {
|
|
2980
|
-
const text = reads.text(
|
|
3055
|
+
const text = reads.text(join4(gitFolder, "commondir"));
|
|
2981
3056
|
const named = text === null ? "" : firstLineOf(text);
|
|
2982
3057
|
if (named === "") return gitFolder;
|
|
2983
3058
|
const shared = resolve3(gitFolder, named);
|
|
@@ -2987,9 +3062,9 @@ var followable = (ref) => ref.startsWith("refs/") && ref.split("/").every((segme
|
|
|
2987
3062
|
var refValueOf = (reads, gitFolder, sharedFolder, ref, depth) => {
|
|
2988
3063
|
if (depth > SYMBOLIC_DEPTH_MAX || !followable(ref)) return null;
|
|
2989
3064
|
const home = PER_WORKTREE_REFS.some((prefix) => ref.startsWith(prefix)) ? gitFolder : sharedFolder;
|
|
2990
|
-
const loose = reads.text(
|
|
3065
|
+
const loose = reads.text(join4(home, ...ref.split("/")));
|
|
2991
3066
|
if (loose !== null) return valueOf(reads, gitFolder, sharedFolder, firstLineOf(loose), depth + 1);
|
|
2992
|
-
const packed = reads.text(
|
|
3067
|
+
const packed = reads.text(join4(sharedFolder, "packed-refs"));
|
|
2993
3068
|
if (packed === null) return null;
|
|
2994
3069
|
for (const line of packed.split(/\r?\n/)) {
|
|
2995
3070
|
if (line.startsWith("#") || line.startsWith("^")) continue;
|
|
@@ -3006,7 +3081,7 @@ var headCommitOf = (folder, reads = FILE_SYSTEM_READS) => {
|
|
|
3006
3081
|
try {
|
|
3007
3082
|
const gitFolder = gitFolderOf(folder, reads);
|
|
3008
3083
|
if (gitFolder === null) return null;
|
|
3009
|
-
const head = reads.text(
|
|
3084
|
+
const head = reads.text(join4(gitFolder, "HEAD"));
|
|
3010
3085
|
if (head === null) return null;
|
|
3011
3086
|
const sharedFolder = sharedGitFolderOf(gitFolder, reads);
|
|
3012
3087
|
if (sharedFolder === null) return null;
|
|
@@ -3105,7 +3180,7 @@ async function writeAgain(io2, what, write) {
|
|
|
3105
3180
|
|
|
3106
3181
|
// src/turnzero_cloud_command/zip.ts
|
|
3107
3182
|
import { readdirSync, readFileSync as readFileSync3, statSync as statSync2 } from "node:fs";
|
|
3108
|
-
import { join as
|
|
3183
|
+
import { join as join5 } from "node:path";
|
|
3109
3184
|
import * as zlib from "node:zlib";
|
|
3110
3185
|
import { deflateRawSync, inflateRawSync as inflateRawSync2 } from "node:zlib";
|
|
3111
3186
|
var AI_TOOL_NAMES = Object.freeze([
|
|
@@ -3144,7 +3219,7 @@ var walkFolder = (root, limit, leftOut) => {
|
|
|
3144
3219
|
leftOut?.push(entry.isDirectory() ? `${name}/` : name);
|
|
3145
3220
|
continue;
|
|
3146
3221
|
}
|
|
3147
|
-
const path =
|
|
3222
|
+
const path = join5(folder.path, entry.name);
|
|
3148
3223
|
if (entry.isSymbolicLink()) throw new ZipRefusal(linkRefusalSentence(name));
|
|
3149
3224
|
if (entry.isDirectory()) {
|
|
3150
3225
|
pending.push({ path, name });
|
|
@@ -3234,7 +3309,7 @@ var NO_PACKAGE_SENTENCE = "The folder holds no package.json at its root, so it i
|
|
|
3234
3309
|
function zipFolder(root, seams = {}) {
|
|
3235
3310
|
let rootFile = false;
|
|
3236
3311
|
try {
|
|
3237
|
-
rootFile = statSync2(
|
|
3312
|
+
rootFile = statSync2(join5(root, "package.json")).isFile();
|
|
3238
3313
|
} catch {
|
|
3239
3314
|
rootFile = false;
|
|
3240
3315
|
}
|
|
@@ -3440,6 +3515,7 @@ async function prepareDeploy(io2, options, zipSha256Value, bearer, userAgent, re
|
|
|
3440
3515
|
return prepared;
|
|
3441
3516
|
}
|
|
3442
3517
|
var NOTHING_STARTED = "Nothing was started.";
|
|
3518
|
+
var BINDING_NOTHING_SENT = "Nothing further was read and nothing was sent.";
|
|
3443
3519
|
var NOTHING_UPLOADED_OR_STARTED = "Nothing was uploaded and nothing was started.";
|
|
3444
3520
|
var healthPathRefusalOf = (prepared, zip, places) => {
|
|
3445
3521
|
if (prepared.healthPathToRead === void 0 || places === null) return null;
|
|
@@ -3536,6 +3612,12 @@ async function deploy(named, io2, flags = /* @__PURE__ */ new Set()) {
|
|
|
3536
3612
|
}
|
|
3537
3613
|
const origin = sent.origin;
|
|
3538
3614
|
const refused = () => credential.source === "credential_file" ? fileReadSentence(origin) : variableReadSentence(origin, fileStandingOf(io2, origin, io2.print));
|
|
3615
|
+
const binding = pathKindOf(options.path) === "folder" ? folderBindingOf(io2, options.path) : null;
|
|
3616
|
+
const unbound = binding === null ? null : bindingRefusalOf(binding, options.application, BINDING_NOTHING_SENT);
|
|
3617
|
+
if (unbound !== null) {
|
|
3618
|
+
io2.print(unbound);
|
|
3619
|
+
return PROGRESS_EXIT_STATUS.nothing_started;
|
|
3620
|
+
}
|
|
3539
3621
|
const zipped = zipOf(options.path, io2, NOTHING_STARTED, named[DEPLOY_OPTION.path] !== void 0);
|
|
3540
3622
|
if ("refusal" in zipped) {
|
|
3541
3623
|
io2.print(zipped.refusal);
|
|
@@ -3557,6 +3639,9 @@ async function deploy(named, io2, flags = /* @__PURE__ */ new Set()) {
|
|
|
3557
3639
|
return PROGRESS_EXIT_STATUS.nothing_started;
|
|
3558
3640
|
}
|
|
3559
3641
|
io2.print(preparedLineOf(prepared));
|
|
3642
|
+
if (binding?.kind === "unbound" && binding.manifest !== null) {
|
|
3643
|
+
io2.print(writeManifestMember(io2, binding.manifest, APPLICATION_MEMBER, options.application) ? boundLineOf(options.application) : BIND_WRITE_FAILED_LINE);
|
|
3644
|
+
}
|
|
3560
3645
|
const { upload, grant, environment } = prepared;
|
|
3561
3646
|
const headers = { authorization: `Bearer ${grant}`, "user-agent": agent.userAgent };
|
|
3562
3647
|
const stop = commandStopSentence(options.application, environment);
|
|
@@ -3667,7 +3752,7 @@ async function deploy(named, io2, flags = /* @__PURE__ */ new Set()) {
|
|
|
3667
3752
|
}
|
|
3668
3753
|
if (read2.status !== 200 || !read2.type.startsWith("text/plain")) {
|
|
3669
3754
|
const refusal = markedRefusalOf(read2.status, read2.text);
|
|
3670
|
-
const said = refusal
|
|
3755
|
+
const said = refusal === null ? [notThePlatformLine(PROGRESS_READ_ACT, read2.status)] : read2.status >= PLATFORM_FAILURE_STATUS ? failureLines(PROGRESS_READ_ACT, read2.status, refusal) : refusalLines(PROGRESS_READ_ACT, read2.status, refusal);
|
|
3671
3756
|
for (const line of said) io2.print(line);
|
|
3672
3757
|
io2.print(stop);
|
|
3673
3758
|
return PROGRESS_EXIT_STATUS.refused;
|
|
@@ -3702,7 +3787,7 @@ var DEPLOY_ROW = Object.freeze({
|
|
|
3702
3787
|
done: `the version deployed, or the deploy started where ${DEPLOY_NO_WAIT_VARIABLE} is set`,
|
|
3703
3788
|
failed: "the deploy failed",
|
|
3704
3789
|
unknown: "the wait stopped, or the start drew no answer: the deploy may go on, and read_status reads it",
|
|
3705
|
-
nothing_started: "an option,
|
|
3790
|
+
nothing_started: "an option, credential, folder, or the folder's binding was refused, no credential was read, the platform was too old, no usable upload was answered, no zipped file names the health path, the upload or start was refused, or the upload drew no answer"
|
|
3706
3791
|
},
|
|
3707
3792
|
variables: [[DEPLOY_NO_WAIT_VARIABLE, "any value returns the command once the deploy has started, without waiting for it."]],
|
|
3708
3793
|
note: [
|
|
@@ -3714,7 +3799,9 @@ var DEPLOY_ROW = Object.freeze({
|
|
|
3714
3799
|
`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.`,
|
|
3715
3800
|
`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.`,
|
|
3716
3801
|
`Then it prints the paths the zip left out, a warning for a .zip file at the folder's root, a warning for a file that looks like a key or a credential, and a warning for a health path that no file names, package files and documentation set aside, each on a line of its own and only where there is something to name. The health warning refuses nothing.`,
|
|
3717
|
-
`After the preparing call, where the platform's answer names the recorded manifest's health path and says the environment serves no version, and no file of the folder's zip names that path, ${DEPLOY_SUBCOMMAND} prints the platform's own refusal, then that nothing was uploaded and nothing was started, and ends 3 with no ${PREPARED_LINE_HEAD.trimEnd()} line, as the start would refuse it. A .zip file the line names is not read for it, and the start's own refusal stands
|
|
3802
|
+
`After the preparing call, where the platform's answer names the recorded manifest's health path and says the environment serves no version, and no file of the folder's zip names that path, ${DEPLOY_SUBCOMMAND} prints the platform's own refusal, then that nothing was uploaded and nothing was started, and ends 3 with no ${PREPARED_LINE_HEAD.trimEnd()} line, as the start would refuse it. A .zip file the line names is not read for it, and the start's own refusal stands.`,
|
|
3803
|
+
`Before its zip, ${DEPLOY_SUBCOMMAND} reads the folder's manifest.json. Where its application member names another application than ${DEPLOY_OPTION.application}, or is not an application id, the deploy ends 3 before anything is zipped or sent. To deploy the folder to another application on purpose, the account's owner changes or removes that member.`,
|
|
3804
|
+
`Where the manifest holds no application member, ${DEPLOY_SUBCOMMAND} writes ${DEPLOY_OPTION.application}'s id into it after the ${PREPARED_LINE_HEAD.trimEnd()} line and prints a ${BOUND_LINE_HEAD.trimEnd()} line, so later deploy and check lines naming another application are refused. A write that fails prints one line and stops nothing. A .zip file the line names is not read for it.`
|
|
3718
3805
|
],
|
|
3719
3806
|
afterOwnError: DEPLOY_AFTER_OWN_ERROR,
|
|
3720
3807
|
run: (call, io2) => deploy(call.named, io2, call.flags)
|
|
@@ -3723,6 +3810,7 @@ var DEPLOY_ROW = Object.freeze({
|
|
|
3723
3810
|
// src/turnzero_cloud_command/check.ts
|
|
3724
3811
|
var NOTHING_SENT_OR_CHECKED = "Nothing was sent and nothing was checked.";
|
|
3725
3812
|
var NOTHING_CHECKED = "Nothing was checked.";
|
|
3813
|
+
var BINDING_NOTHING_CHECKED = "Nothing further was read, and nothing was sent or checked.";
|
|
3726
3814
|
var REFUSED_LINE_HEAD = "refused: ";
|
|
3727
3815
|
var MANIFEST_LINE_HEAD = "manifest: ";
|
|
3728
3816
|
var CHECKED_LINE_HEAD = "checked: ";
|
|
@@ -3914,6 +4002,12 @@ async function check(named, io2) {
|
|
|
3914
4002
|
}
|
|
3915
4003
|
const origin = sent.origin;
|
|
3916
4004
|
const refused = () => credential.source === "credential_file" ? fileReadSentence(origin) : variableReadSentence(origin, fileStandingOf(io2, origin, io2.print));
|
|
4005
|
+
const binding = pathKindOf(options.path) === "folder" ? folderBindingOf(io2, options.path) : null;
|
|
4006
|
+
const unbound = binding === null ? null : bindingRefusalOf(binding, options.application, BINDING_NOTHING_CHECKED);
|
|
4007
|
+
if (unbound !== null) {
|
|
4008
|
+
io2.print(unbound);
|
|
4009
|
+
return COMMAND_STATUS.nothing_started;
|
|
4010
|
+
}
|
|
3917
4011
|
const zipped = zipOf(options.path, io2, NOTHING_CHECKED, named[CHECK_OPTION.path] !== void 0, null, "checked");
|
|
3918
4012
|
if ("refusal" in zipped) {
|
|
3919
4013
|
io2.print(zipped.refusal);
|
|
@@ -3946,11 +4040,12 @@ var CHECK_ROW = Object.freeze({
|
|
|
3946
4040
|
statuses: {
|
|
3947
4041
|
done: "none of the checks would refuse a deploy now",
|
|
3948
4042
|
failed: "a deploy would be refused now, the refused: lines naming each refusal",
|
|
3949
|
-
nothing_started: "nothing was checked: an option,
|
|
4043
|
+
nothing_started: "nothing was checked: an option, credential, folder, or the folder's binding was refused, no credential was read and the two routes to one were printed, the platform was too old, or the check call was refused, drew no answer, was redirected, or failed"
|
|
3950
4044
|
},
|
|
3951
4045
|
note: [
|
|
3952
4046
|
`A check is one line, which carries no credential: run the line your tool's ${CHECK_ACTION} call answers, or ${CHECK_SUBCOMMAND} ${CHECK_OPTION.application} <application id>, from the application's folder, before a first deploy and after each fix. It reads its credential and the platform's address as ${DEPLOY_SUBCOMMAND} does, builds the zip ${DEPLOY_SUBCOMMAND} builds, and sends the platform the application alone, no byte of the zip and no hash. It uploads nothing and starts nothing.`,
|
|
3953
4047
|
`After its zip line, ${CHECK_SUBCOMMAND} prints the further lines ${DEPLOY_SUBCOMMAND} prints, leaving out the health warning where the platform says the deploy would be a first one, since a refused: line then reads the recorded health path. Then it prints one refused: line for each refusal the platform answered for the application's state, then one for each refusal of the zip by the deploy's own checks, a line naming submit_manifest where the zip's manifest.json names another health path, and a last checked: line counting the refusals.`,
|
|
4048
|
+
`Before its zip, ${CHECK_SUBCOMMAND} reads the folder's manifest.json as ${DEPLOY_SUBCOMMAND} reads it. Where its application member names another application than ${CHECK_OPTION.application}, or is not an application id, the check ends 3 before anything is zipped or sent. A check writes no member where none stands.`,
|
|
3954
4049
|
`A passing check does not guarantee the deploy is accepted: a deploy in flight, the day's deploys, and the hosting cell's room can change before the deploy, which makes every check again.`
|
|
3955
4050
|
],
|
|
3956
4051
|
afterOwnError: CHECK_AFTER_OWN_ERROR,
|
|
@@ -3978,6 +4073,10 @@ async function hash(named, io2, flags = /* @__PURE__ */ new Set()) {
|
|
|
3978
4073
|
io2.print(LIST_ZIP_FILE_SENTENCE);
|
|
3979
4074
|
return PROGRESS_EXIT_STATUS.nothing_started;
|
|
3980
4075
|
}
|
|
4076
|
+
if (pathKindOf(folder) === "folder" && folderBindingOf(io2, folder).kind === "off_form") {
|
|
4077
|
+
io2.print(`${OFF_FORM_SENTENCE} ${NO_HASH_PRINTED} ${HASH_BINDING_OWNER_ASK}`);
|
|
4078
|
+
return PROGRESS_EXIT_STATUS.nothing_started;
|
|
4079
|
+
}
|
|
3981
4080
|
const zipped = zipOf(folder, io2, NO_HASH_PRINTED, path !== void 0);
|
|
3982
4081
|
if ("refusal" in zipped) {
|
|
3983
4082
|
io2.print(zipped.refusal);
|
|
@@ -3999,7 +4098,7 @@ var HASH_ROW = Object.freeze({
|
|
|
3999
4098
|
});
|
|
4000
4099
|
|
|
4001
4100
|
// src/turnzero_cloud_command/secret.ts
|
|
4002
|
-
import { isAbsolute as isAbsolute3, join as
|
|
4101
|
+
import { isAbsolute as isAbsolute3, join as join6, relative as relative4, resolve as resolve7, sep as sep2 } from "node:path";
|
|
4003
4102
|
|
|
4004
4103
|
// src/turnzero_cloud_command/value.ts
|
|
4005
4104
|
var NOTHING_SENT2 = "Nothing was sent.";
|
|
@@ -4204,15 +4303,15 @@ var secretUnknownSentence = (act) => `Whether the value was written is unknown:
|
|
|
4204
4303
|
var PACKAGE_FILE = "package.json";
|
|
4205
4304
|
var VALUE_FILE_WARNING = `warning: the file ${SECRET_OPTION.valueFile} names stands inside an application folder, and a deploy from that folder would include it. Keep the file outside the application's folder, or delete it once this line ends 0.`;
|
|
4206
4305
|
var valueFileWouldDeploy = (io2, cwd, file) => {
|
|
4207
|
-
const between =
|
|
4306
|
+
const between = relative4(cwd, file);
|
|
4208
4307
|
if (between === "" || between === ".." || between.startsWith(`..${sep2}`) || isAbsolute3(between)) return false;
|
|
4209
4308
|
const segments = between.split(sep2);
|
|
4210
4309
|
if (segments.some(leftOutName)) return false;
|
|
4211
4310
|
let folder = cwd;
|
|
4212
4311
|
for (let depth = 0; depth < segments.length; depth += 1) {
|
|
4213
|
-
if (depth > 0) folder =
|
|
4312
|
+
if (depth > 0) folder = join6(folder, segments[depth - 1]);
|
|
4214
4313
|
try {
|
|
4215
|
-
if (io2.stat(
|
|
4314
|
+
if (io2.stat(join6(folder, PACKAGE_FILE))?.folder === false) return true;
|
|
4216
4315
|
} catch {
|
|
4217
4316
|
}
|
|
4218
4317
|
}
|
|
@@ -4486,11 +4585,11 @@ var PUT_ROW = Object.freeze({
|
|
|
4486
4585
|
|
|
4487
4586
|
// src/turnzero_cloud_command/library_take.ts
|
|
4488
4587
|
import { createHash as createHash3 } from "node:crypto";
|
|
4489
|
-
import { basename as basename2, dirname as dirname4, isAbsolute as isAbsolute4, join as
|
|
4588
|
+
import { basename as basename2, dirname as dirname4, isAbsolute as isAbsolute4, join as join8, relative as relative5, resolve as resolve10, sep as sep3 } from "node:path";
|
|
4490
4589
|
|
|
4491
4590
|
// src/turnzero_cloud_command/run.ts
|
|
4492
4591
|
import { constants } from "node:os";
|
|
4493
|
-
import { join as
|
|
4592
|
+
import { join as join7, resolve as resolve9, win32 as win323 } from "node:path";
|
|
4494
4593
|
var RUN_OPTIONS = Object.freeze([
|
|
4495
4594
|
{
|
|
4496
4595
|
name: RUN_OPTION.path,
|
|
@@ -4674,7 +4773,7 @@ async function localRun(call, io2) {
|
|
|
4674
4773
|
return COMMAND_STATUS.nothing_started;
|
|
4675
4774
|
}
|
|
4676
4775
|
try {
|
|
4677
|
-
io2.readFile(
|
|
4776
|
+
io2.readFile(join7(options.folder, PACKAGE_FILE2));
|
|
4678
4777
|
} catch (error) {
|
|
4679
4778
|
io2.print(
|
|
4680
4779
|
`The application's folder holds no ${PACKAGE_FILE2} the command could read (${fileErrorCodeOf(error, "unreadable")}), so npm start has nothing to start there: ${RUN_OPTION.path} names the folder, and it is the folder the command runs in where the option is absent. ${NO_APPLICATION_STARTED}`
|
|
@@ -4788,13 +4887,13 @@ var libraryTakeOptionsOf = (call, cwd) => {
|
|
|
4788
4887
|
return { entry, root: resolve10(cwd, path ?? "."), named: path !== void 0, origin: origin.origin };
|
|
4789
4888
|
};
|
|
4790
4889
|
var inside = (parent, child) => {
|
|
4791
|
-
const between =
|
|
4890
|
+
const between = relative5(parent, child);
|
|
4792
4891
|
return between !== "" && !between.startsWith("..") && !isAbsolute4(between);
|
|
4793
4892
|
};
|
|
4794
|
-
var shownFrom = (root) => (path) => shownName(
|
|
4893
|
+
var shownFrom = (root) => (path) => shownName(relative5(root, path).split(sep3).join("/") || ".");
|
|
4795
4894
|
var repositoryRootOf = (io2, root) => {
|
|
4796
4895
|
for (let at = root; ; at = dirname4(at)) {
|
|
4797
|
-
if (io2.stat(
|
|
4896
|
+
if (io2.stat(join8(at, ".git")) !== null) return at;
|
|
4798
4897
|
if (dirname4(at) === at) return root;
|
|
4799
4898
|
}
|
|
4800
4899
|
};
|
|
@@ -4814,14 +4913,14 @@ var TAKE_FOLDER_WORDS = Object.freeze({
|
|
|
4814
4913
|
manifestCannot: "so the take cannot add its row to it"
|
|
4815
4914
|
});
|
|
4816
4915
|
var libraryFolderOf = (io2, root, words = TAKE_FOLDER_WORDS) => {
|
|
4817
|
-
const own =
|
|
4916
|
+
const own = join8(root, LIBRARY_FOLDER);
|
|
4818
4917
|
const inRoot = { folder: root, called: ROOT_CALLED };
|
|
4819
4918
|
const standing = io2.stat(own);
|
|
4820
4919
|
if (standing !== null) {
|
|
4821
4920
|
if (!standing.folder) return { refusal: `The project's ${LIBRARY_FOLDER} is a file, where the library folder stands. ${NOTHING_WRITTEN2}` };
|
|
4822
4921
|
return { folder: own, fresh: false, within: inRoot };
|
|
4823
4922
|
}
|
|
4824
|
-
const pointerAt =
|
|
4923
|
+
const pointerAt = join8(root, POINTER_FILE);
|
|
4825
4924
|
if (io2.stat(pointerAt) === null) return { folder: own, fresh: true, within: inRoot };
|
|
4826
4925
|
let named;
|
|
4827
4926
|
try {
|
|
@@ -4845,22 +4944,22 @@ var libraryFolderOf = (io2, root, words = TAKE_FOLDER_WORDS) => {
|
|
|
4845
4944
|
return { folder: at, fresh: false, within: { folder: repository, called: REPOSITORY_CALLED } };
|
|
4846
4945
|
};
|
|
4847
4946
|
var applicationFolderRefusalOf = (io2, options) => {
|
|
4848
|
-
const holds = (folder) => io2.stat(
|
|
4947
|
+
const holds = (folder) => io2.stat(join8(folder, LIBRARY_FOLDER)) !== null || io2.stat(join8(folder, POINTER_FILE)) !== null;
|
|
4849
4948
|
const parent = dirname4(options.root);
|
|
4850
4949
|
if (parent === options.root || holds(options.root) || !holds(parent)) return null;
|
|
4851
4950
|
return options.named ? `The folder ${LIBRARY_OPTION.path} names holds neither ${LIBRARY_FOLDER}/ nor ${POINTER_FILE}, and the folder above it holds one, so it may be an application's folder inside that project. Take the entry at the project's root: name the folder above it with ${LIBRARY_OPTION.path}. Or, where the folder is a project of its own, make an empty ${LIBRARY_FOLDER}/ folder in it and run the line again. ${NOTHING_WRITTEN2}` : `This folder holds neither ${LIBRARY_FOLDER}/ nor ${POINTER_FILE}, and the folder above it holds one, so this may be an application's folder inside that project. Take the entry at the project's root: run the line in the folder above. Or, where this folder is a project of its own, make an empty ${LIBRARY_FOLDER}/ folder here and run the line again. ${NOTHING_WRITTEN2}`;
|
|
4852
4951
|
};
|
|
4853
4952
|
var entryFoldersIn = (io2, library) => {
|
|
4854
|
-
const folders = (at) => (io2.listFolder(
|
|
4953
|
+
const folders = (at) => (io2.listFolder(join8(library, ...at.split("/"))) ?? []).filter((name) => !NEVER_PUBLISHED.has(name) && io2.stat(join8(library, ...at.split("/"), name))?.folder === true).sort();
|
|
4855
4954
|
return [
|
|
4856
4955
|
...folders("features"),
|
|
4857
4956
|
...folders("ui").filter((name) => name !== "assets").map((name) => `ui/${name}`),
|
|
4858
4957
|
...folders("ui/assets/fonts").map((name) => `fonts/${name}`),
|
|
4859
|
-
...io2.stat(
|
|
4958
|
+
...io2.stat(join8(library, "prd"))?.folder === true ? ["library/prd"] : []
|
|
4860
4959
|
];
|
|
4861
4960
|
};
|
|
4862
4961
|
var manifestRowsOf = (io2, library, words = TAKE_FOLDER_WORDS) => {
|
|
4863
|
-
const at =
|
|
4962
|
+
const at = join8(library, MANIFEST_FILE2);
|
|
4864
4963
|
if (io2.stat(at) === null) return { rows: null, stood: null };
|
|
4865
4964
|
try {
|
|
4866
4965
|
const stood = io2.readFile(at);
|
|
@@ -4924,6 +5023,7 @@ var readOf = async (io2, origin, userAgent, body, what) => {
|
|
|
4924
5023
|
if (status >= 200 && status <= 299 && answer !== null) return { answer };
|
|
4925
5024
|
const refusal = markedRefusalOf(status, text);
|
|
4926
5025
|
if (refusal === null) return { lines: [`${LIBRARY_READ_ACTION} was answered HTTP ${status}, not by the platform. ${NOTHING_WRITTEN2}`] };
|
|
5026
|
+
if (status >= PLATFORM_FAILURE_STATUS) return { lines: [...failureLines(LIBRARY_READ_ACTION, status, refusal), NOTHING_WRITTEN2] };
|
|
4927
5027
|
return { lines: [...refusalLines(LIBRARY_READ_ACTION, status, refusal), NOTHING_WRITTEN2] };
|
|
4928
5028
|
};
|
|
4929
5029
|
var fileBytesOf = async (io2, origin, userAgent, name, file) => {
|
|
@@ -4979,11 +5079,6 @@ var ofModuleType = (plan, name) => {
|
|
|
4979
5079
|
};
|
|
4980
5080
|
var MADE_LINE_HEAD = "made: ";
|
|
4981
5081
|
var madeLineOf = (made) => `${MADE_LINE_HEAD}${MADE_FOLDER}/package.json, since neither app/package.json nor the project root's package.json stood: private, named ${made.name}${made.module ? ", of type module" : ""}, with no scripts.`;
|
|
4982
|
-
var BYTE_ORDER_MARK3 = "\uFEFF";
|
|
4983
|
-
var jsonTextOf = (bytes) => {
|
|
4984
|
-
const text = bytes.toString("utf8");
|
|
4985
|
-
return text.startsWith(BYTE_ORDER_MARK3) ? text.slice(BYTE_ORDER_MARK3.length) : text;
|
|
4986
|
-
};
|
|
4987
5082
|
var openingCharacterClauseOf = (text) => {
|
|
4988
5083
|
const first = text.codePointAt(0);
|
|
4989
5084
|
if (first === void 0) return "";
|
|
@@ -4993,19 +5088,19 @@ var openingCharacterClauseOf = (text) => {
|
|
|
4993
5088
|
const control = first < 32 && first !== 9 && first !== 10 && first !== 13 || first >= 127 && first <= 159;
|
|
4994
5089
|
return control ? `: the file opens with ${point}, a control character` : "";
|
|
4995
5090
|
};
|
|
4996
|
-
var applicationFolderOf = (io2, root) => [
|
|
5091
|
+
var applicationFolderOf = (io2, root) => [join8(root, "app"), root].find((folder) => io2.stat(join8(folder, "package.json"))?.folder === false) ?? null;
|
|
4997
5092
|
var copyPlanOf = (io2, root, library, name) => {
|
|
4998
5093
|
const shown2 = shownFrom(root);
|
|
4999
5094
|
if (name.includes("/")) return { refusal: `The entry ${LIBRARY_OPTION.entry} names carries compiled modules under a name that holds a slash, which an npm package cannot take. ${NOTHING_WRITTEN2}` };
|
|
5000
5095
|
const application = applicationFolderOf(io2, root);
|
|
5001
5096
|
if (application === null) {
|
|
5002
|
-
const app =
|
|
5097
|
+
const app = join8(root, MADE_FOLDER);
|
|
5003
5098
|
const standing = io2.stat(app);
|
|
5004
5099
|
if (standing !== null && !standing.folder || danglingLinkAt(io2, root, MADE_FOLDER)) {
|
|
5005
5100
|
return { refusal: `Something that is no folder stands at ${MADE_FOLDER}, where the take would make the application's package.json. ${NOTHING_WRITTEN2}` };
|
|
5006
5101
|
}
|
|
5007
|
-
const copy2 =
|
|
5008
|
-
const madeFile =
|
|
5102
|
+
const copy2 = join8(app, "lib", name);
|
|
5103
|
+
const madeFile = join8(app, "package.json");
|
|
5009
5104
|
if (io2.stat(madeFile) !== null || standing !== null && danglingLinkAt(io2, app, "package.json")) {
|
|
5010
5105
|
return { refusal: `Something that is no package file stands at ${MADE_FOLDER}/package.json, where the take would make it. ${NOTHING_WRITTEN2}` };
|
|
5011
5106
|
}
|
|
@@ -5018,7 +5113,7 @@ var copyPlanOf = (io2, root, library, name) => {
|
|
|
5018
5113
|
const declaredAt2 = `file:lib/${name}`;
|
|
5019
5114
|
return { application: app, copy: copy2, declared: madePackageFileOf(made, `${PACKAGE_SCOPE}${name}`, declaredAt2), declaredAt: declaredAt2, made };
|
|
5020
5115
|
}
|
|
5021
|
-
const packageFile =
|
|
5116
|
+
const packageFile = join8(application, "package.json");
|
|
5022
5117
|
const read2 = io2.readFile(packageFile);
|
|
5023
5118
|
const text = jsonTextOf(read2);
|
|
5024
5119
|
let parsed;
|
|
@@ -5030,12 +5125,12 @@ var copyPlanOf = (io2, root, library, name) => {
|
|
|
5030
5125
|
}
|
|
5031
5126
|
const packageName = `${PACKAGE_SCOPE}${name}`;
|
|
5032
5127
|
const specs = DEPENDENCY_SECTIONS.map((section) => parsed[section]?.[packageName]).filter((spec) => spec !== void 0);
|
|
5033
|
-
const place = application === root && io2.stat(
|
|
5128
|
+
const place = application === root && io2.stat(join8(root, "app"))?.folder === true ? `app/lib/${name}` : `lib/${name}`;
|
|
5034
5129
|
let copy;
|
|
5035
5130
|
let declared = null;
|
|
5036
5131
|
let declaredAt = null;
|
|
5037
5132
|
if (specs.length === 0) {
|
|
5038
|
-
copy =
|
|
5133
|
+
copy = join8(application, ...place.split("/"));
|
|
5039
5134
|
declaredAt = `file:${place}`;
|
|
5040
5135
|
declared = withDependency(text, parsed, packageName, declaredAt);
|
|
5041
5136
|
} else {
|
|
@@ -5061,11 +5156,11 @@ var stageRefusalOf = (io2, stage, beside) => {
|
|
|
5061
5156
|
return own ? null : `Something that is not the take's own stands at ${STAGE} beside ${beside}, the name the take writes under: move it, then run the line again. ${NOTHING_WRITTEN2}`;
|
|
5062
5157
|
};
|
|
5063
5158
|
var moveFolderIn = (io2, stage, target, files) => {
|
|
5064
|
-
const fresh =
|
|
5065
|
-
const old =
|
|
5159
|
+
const fresh = join8(stage, "new");
|
|
5160
|
+
const old = join8(stage, "old");
|
|
5066
5161
|
io2.remove(stage);
|
|
5067
5162
|
for (const [path, bytes] of files) {
|
|
5068
|
-
const at =
|
|
5163
|
+
const at = join8(fresh, ...path.split("/"));
|
|
5069
5164
|
io2.makeFolder(dirname4(at));
|
|
5070
5165
|
io2.writeFile(at, bytes);
|
|
5071
5166
|
}
|
|
@@ -5105,15 +5200,14 @@ var PACKAGES_LINE_HEAD = "packages: ";
|
|
|
5105
5200
|
var jsonEscapeOf = (character) => Array.from({ length: character.length }, (_, index) => `\\u${character.charCodeAt(index).toString(16).padStart(4, "0")}`).join("");
|
|
5106
5201
|
var shownJson = (text) => [...text].map((character) => shownWhole(character) === character ? character : jsonEscapeOf(character)).join("");
|
|
5107
5202
|
var packagesLineOf = (rows) => `${PACKAGES_LINE_HEAD}${shownJson(JSON.stringify(rows))}`;
|
|
5108
|
-
var applicationManifestPartialOf = (at) => `${at}.partial`;
|
|
5109
5203
|
var PARTIAL_LINK_SENTENCE = writtenLinkSentence(`The file the application manifest is written to first, ${MANIFEST_FILE2}.partial beside it,`);
|
|
5110
|
-
var danglingLinkAt = (io2, folder, name) => io2.stat(
|
|
5204
|
+
var danglingLinkAt = (io2, folder, name) => io2.stat(join8(folder, name)) === null && (io2.listFolder(folder) ?? []).some((held) => held.toLowerCase() === name.toLowerCase() && io2.stat(join8(folder, held)) === null);
|
|
5111
5205
|
var linkStandsAt = (io2, path) => {
|
|
5112
5206
|
const name = basename2(path);
|
|
5113
5207
|
if (!(io2.listFolder(dirname4(path)) ?? []).includes(name)) return false;
|
|
5114
5208
|
const real = io2.realPath(path);
|
|
5115
5209
|
const folder = io2.realPath(dirname4(path));
|
|
5116
|
-
return real === null || folder === null ||
|
|
5210
|
+
return real === null || folder === null || relative5(join8(folder, name), real) !== "";
|
|
5117
5211
|
};
|
|
5118
5212
|
var writesThroughLink = (io2, holder, path) => linkStandsAt(io2, path) || !heldInside(io2, holder, path);
|
|
5119
5213
|
var writtenNameRefusalOf = (io2, holder, names) => {
|
|
@@ -5122,11 +5216,11 @@ var writtenNameRefusalOf = (io2, holder, names) => {
|
|
|
5122
5216
|
};
|
|
5123
5217
|
var applicationManifestOf = (io2, root, library, folder = applicationFolderOf(io2, root)) => {
|
|
5124
5218
|
if (folder === null) return { at: null, unwritten: "no_folder" };
|
|
5125
|
-
const at =
|
|
5219
|
+
const at = join8(folder, MANIFEST_FILE2);
|
|
5126
5220
|
const standing = io2.stat(at);
|
|
5127
5221
|
if (standing === null) return { at, unwritten: "not_standing" };
|
|
5128
5222
|
if (!heldInside(io2, root, at)) return { refusal: linkSentence("The application manifest", ROOT_CALLED) };
|
|
5129
|
-
const libraryManifest =
|
|
5223
|
+
const libraryManifest = join8(library, MANIFEST_FILE2);
|
|
5130
5224
|
if (resolve10(at) === resolve10(libraryManifest) || realPlaceOf(io2, at) === realPlaceOf(io2, libraryManifest)) return { at, unwritten: "library_manifest" };
|
|
5131
5225
|
if (standing.folder) return { at, unwritten: "no_object" };
|
|
5132
5226
|
const partial = applicationManifestPartialOf(at);
|
|
@@ -5138,25 +5232,9 @@ var applicationManifestOf = (io2, root, library, folder = applicationFolderOf(io
|
|
|
5138
5232
|
}
|
|
5139
5233
|
return { at, unwritten: "no_object" };
|
|
5140
5234
|
};
|
|
5141
|
-
var applicationManifestTextOf = (parsed, packages) => `${JSON.stringify({ ...parsed, packages }, null, 2)}
|
|
5142
|
-
`;
|
|
5143
5235
|
var writeApplicationManifest = (io2, manifest, packages) => {
|
|
5144
5236
|
if (!("parsed" in manifest)) return manifest;
|
|
5145
|
-
|
|
5146
|
-
let made = false;
|
|
5147
|
-
try {
|
|
5148
|
-
if (io2.stat(partial)?.folder === false) io2.remove(partial);
|
|
5149
|
-
made = io2.stat(partial) === null;
|
|
5150
|
-
io2.writeNewFile(partial, applicationManifestTextOf(manifest.parsed, packages));
|
|
5151
|
-
io2.rename(partial, manifest.at);
|
|
5152
|
-
} catch {
|
|
5153
|
-
try {
|
|
5154
|
-
if (made) io2.remove(partial);
|
|
5155
|
-
} catch {
|
|
5156
|
-
}
|
|
5157
|
-
return { at: manifest.at, unwritten: "write_failed" };
|
|
5158
|
-
}
|
|
5159
|
-
return { written: manifest.at };
|
|
5237
|
+
return writeManifestMember(io2, manifest, "packages", packages) ? { written: manifest.at } : { at: manifest.at, unwritten: "write_failed" };
|
|
5160
5238
|
};
|
|
5161
5239
|
var packagesWhereOf = (root, outcome) => {
|
|
5162
5240
|
const shown2 = shownFrom(root);
|
|
@@ -5186,11 +5264,11 @@ async function readTake(io2, options, userAgent, planOf, planeChecked = false) {
|
|
|
5186
5264
|
if ("refusal" in found) return refuse(found.refusal);
|
|
5187
5265
|
const library = found.folder;
|
|
5188
5266
|
if (!heldInside(io2, found.within.folder, library)) return refuse(linkSentence("The project's library folder", found.within.called));
|
|
5189
|
-
const manifestAt =
|
|
5267
|
+
const manifestAt = join8(library, MANIFEST_FILE2);
|
|
5190
5268
|
const inLibrary = writtenNameRefusalOf(io2, found.within.folder, [
|
|
5191
5269
|
[WRITTEN_NAMES.manifest, manifestAt],
|
|
5192
5270
|
[WRITTEN_NAMES.manifestPartial, `${manifestAt}.partial`],
|
|
5193
|
-
[WRITTEN_NAMES.libraryStage,
|
|
5271
|
+
[WRITTEN_NAMES.libraryStage, join8(library, STAGE)]
|
|
5194
5272
|
]);
|
|
5195
5273
|
if (inLibrary !== null) return refuse(inLibrary);
|
|
5196
5274
|
const manifest = found.fresh ? { rows: null, stood: null } : manifestRowsOf(io2, library);
|
|
@@ -5204,7 +5282,7 @@ async function readTake(io2, options, userAgent, planOf, planeChecked = false) {
|
|
|
5204
5282
|
if ("lines" in list) return refuse(...list.lines);
|
|
5205
5283
|
const entry = listedEntryOf(list.answer, options.entry);
|
|
5206
5284
|
if ("refusal" in entry) return refuse(entry.refusal);
|
|
5207
|
-
const entryFolder =
|
|
5285
|
+
const entryFolder = join8(library, ...entry.path.split("/"));
|
|
5208
5286
|
if (!heldInside(io2, found.within.folder, entryFolder)) return refuse(linkSentence("The entry's folder", found.within.called));
|
|
5209
5287
|
if (io2.stat(entryFolder) !== null && !(manifest.rows ?? []).some((row) => rowName(row) === entry.name)) {
|
|
5210
5288
|
return refuse(sourceSentence(`holds ${entry.name}'s folder and no row for it in its ${MANIFEST_FILE2}`));
|
|
@@ -5214,11 +5292,11 @@ async function readTake(io2, options, userAgent, planOf, planeChecked = false) {
|
|
|
5214
5292
|
if (plan !== null && "refusal" in plan) return refuse(plan.refusal, ...plan.after ?? []);
|
|
5215
5293
|
if (plan !== null && !heldInside(io2, options.root, plan.copy)) return refuse(linkSentence("The application's copy", ROOT_CALLED));
|
|
5216
5294
|
const besideCopy = plan === null ? null : writtenNameRefusalOf(io2, options.root, [
|
|
5217
|
-
...plan.declared !== null ? [[WRITTEN_NAMES.packageFile,
|
|
5295
|
+
...plan.declared !== null ? [[WRITTEN_NAMES.packageFile, join8(plan.application, "package.json")]] : [],
|
|
5218
5296
|
[WRITTEN_NAMES.copyStage, `${plan.copy}${STAGE}`]
|
|
5219
5297
|
]);
|
|
5220
5298
|
if (besideCopy !== null) return refuse(besideCopy);
|
|
5221
|
-
const staged = stageRefusalOf(io2,
|
|
5299
|
+
const staged = stageRefusalOf(io2, join8(library, STAGE), "the library folder") ?? (plan !== null ? stageRefusalOf(io2, `${plan.copy}${STAGE}`, "the application's copy") : null);
|
|
5222
5300
|
if (staged !== null) return refuse(staged);
|
|
5223
5301
|
const bytes = /* @__PURE__ */ new Map();
|
|
5224
5302
|
for (const file of entry.files) {
|
|
@@ -5242,11 +5320,11 @@ function writeTake(io2, root, { entry, library, entryFolder, rows, manifestStood
|
|
|
5242
5320
|
source_commit: entry.source_commit,
|
|
5243
5321
|
fetched_at: (/* @__PURE__ */ new Date()).toISOString()
|
|
5244
5322
|
});
|
|
5245
|
-
const manifestAt =
|
|
5323
|
+
const manifestAt = join8(library, MANIFEST_FILE2);
|
|
5246
5324
|
const manifestPartial = `${manifestAt}.partial`;
|
|
5247
5325
|
io2.writeFile(manifestPartial, manifestText);
|
|
5248
5326
|
io2.rename(manifestPartial, manifestAt);
|
|
5249
|
-
const entryStage =
|
|
5327
|
+
const entryStage = join8(library, STAGE);
|
|
5250
5328
|
try {
|
|
5251
5329
|
moveFolderIn(
|
|
5252
5330
|
io2,
|
|
@@ -5276,7 +5354,7 @@ function writeTake(io2, root, { entry, library, entryFolder, rows, manifestStood
|
|
|
5276
5354
|
plan.copy,
|
|
5277
5355
|
compiled.map((file) => [file.path.slice(entry.path.length + 1), bytes.get(file.path)])
|
|
5278
5356
|
);
|
|
5279
|
-
const packageFile =
|
|
5357
|
+
const packageFile = join8(plan.application, "package.json");
|
|
5280
5358
|
if (plan.declared !== null) io2.writeFile(packageFile, plan.declared);
|
|
5281
5359
|
if (plan.made !== void 0) io2.print(madeLineOf(plan.made));
|
|
5282
5360
|
io2.print(
|
|
@@ -5856,7 +5934,7 @@ var startUpgradeCheck = (io2, subcommand, named, running) => {
|
|
|
5856
5934
|
const read2 = io2.registryFetch;
|
|
5857
5935
|
if (read2 === void 0 || !UPGRADE_CHECK_SUBCOMMANDS.includes(subcommand)) return NO_CHECK;
|
|
5858
5936
|
if (UPGRADE_CHECK_SKIP_VARIABLES.some((name) => io2.env[name] !== void 0)) return NO_CHECK;
|
|
5859
|
-
const origin = named[DEPLOY_OPTION.origin] ?? io2.env[ORIGIN_VARIABLE]
|
|
5937
|
+
const origin = originReadOf(named[DEPLOY_OPTION.origin] ?? io2.env[ORIGIN_VARIABLE]);
|
|
5860
5938
|
const tag = commandTagOf(origin);
|
|
5861
5939
|
const place = credentialFileOf(io2);
|
|
5862
5940
|
const path = (onWindows(io2) ? win324 : posix3).join(place.folder, UPGRADE_CHECK_FILE_NAME);
|
|
@@ -5900,7 +5978,7 @@ var startUpgradeCheck = (io2, subcommand, named, running) => {
|
|
|
5900
5978
|
};
|
|
5901
5979
|
|
|
5902
5980
|
// src/turnzero_cloud_command/provision.ts
|
|
5903
|
-
import { basename as basename3, dirname as dirname5, join as
|
|
5981
|
+
import { basename as basename3, dirname as dirname5, join as join9 } from "node:path";
|
|
5904
5982
|
var PROVISION_OPTIONS = Object.freeze([
|
|
5905
5983
|
{
|
|
5906
5984
|
name: PROVISION_OPTION.application,
|
|
@@ -5957,7 +6035,7 @@ var APPLICATION_FOLDER_MARKS = Object.freeze(["package.json", "manifest.json"]);
|
|
|
5957
6035
|
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.`;
|
|
5958
6036
|
var outsideApplicationFolder = (io2, envFile) => APPLICATION_FOLDER_MARKS.every((mark) => {
|
|
5959
6037
|
try {
|
|
5960
|
-
return io2.stat(
|
|
6038
|
+
return io2.stat(join9(dirname5(envFile), mark))?.folder !== false;
|
|
5961
6039
|
} catch {
|
|
5962
6040
|
return false;
|
|
5963
6041
|
}
|
|
@@ -6299,7 +6377,7 @@ var PROVISION_ROW = Object.freeze({
|
|
|
6299
6377
|
});
|
|
6300
6378
|
|
|
6301
6379
|
// src/turnzero_cloud_command/scaffold.ts
|
|
6302
|
-
import { basename as basename4, dirname as dirname6, isAbsolute as isAbsolute5, join as
|
|
6380
|
+
import { basename as basename4, dirname as dirname6, isAbsolute as isAbsolute5, join as join10, relative as relative6, resolve as resolve11 } from "node:path";
|
|
6303
6381
|
|
|
6304
6382
|
// src/turnzero_cloud_command/scaffold_template.ts
|
|
6305
6383
|
var SCAFFOLD_TEMPLATE_FILES = Object.freeze({
|
|
@@ -7751,6 +7829,12 @@ var SCAFFOLD_OPTIONS = Object.freeze([
|
|
|
7751
7829
|
value: "<origin>",
|
|
7752
7830
|
required: false,
|
|
7753
7831
|
description: `The platform's address. Where absent, ${DEFAULT_COMMAND_ORIGIN}.`
|
|
7832
|
+
},
|
|
7833
|
+
{
|
|
7834
|
+
name: SCAFFOLD_OPTION.application,
|
|
7835
|
+
value: "<application id>",
|
|
7836
|
+
required: false,
|
|
7837
|
+
description: `Under every template, the application the service deploys to, by its id, a lowercase UUID, as create_application answers it. The written ${APPLICATION_MANIFEST} names it in its application member, which binds the folder to that application, so a deploy or check line naming another is refused. Where absent, the first deploy writes the member.`
|
|
7754
7838
|
}
|
|
7755
7839
|
]);
|
|
7756
7840
|
var EMPTY_PACKAGES = '"packages": []';
|
|
@@ -7777,6 +7861,7 @@ var NEITHER_LEFT = Object.freeze({ tools: "written", claude: false });
|
|
|
7777
7861
|
var ROOT_TOOLS_STEP = `Add this sentence to ${TOOLS_FILE} at the project's root, which the scaffold did not change, so a coding tool started at the root reads ${APPLICATION_FOLDER}/${TOOLS_FILE}: ${ROOT_SENTENCE}`;
|
|
7778
7862
|
var ROOT_TOOLS_FAILED_STEP = `Add this sentence to ${TOOLS_FILE} at the project's root, which the scaffold could not write, so a coding tool started at the root reads ${APPLICATION_FOLDER}/${TOOLS_FILE}: ${ROOT_SENTENCE}`;
|
|
7779
7863
|
var ROOT_CLAUDE_STEP = `Add this sentence to ${CLAUDE_FILE} at the project's root, since Claude Code reads that file and then reads no ${TOOLS_FILE} by itself: ${ROOT_SENTENCE}`;
|
|
7864
|
+
var APPLICATION_FORM_REFUSAL = `${SCAFFOLD_OPTION.application} names the application the service deploys to, by its id, a lowercase UUID, as create_application answers it. ${NOTHING_WRITTEN2}`;
|
|
7780
7865
|
var RESOURCE_REFUSAL = Object.freeze({
|
|
7781
7866
|
/** A plural outside SCAFFOLD_NAME_FORM. */
|
|
7782
7867
|
resourceForm: `${SCAFFOLD_OPTION.resource} takes the plural of the resource the service keeps, the word of its table and its route: an ASCII lower-case letter, then ASCII lower-case letters and digits, at most 30 characters, such as orders. ${NOTHING_WRITTEN2}`,
|
|
@@ -7787,11 +7872,17 @@ var RESOURCE_REFUSAL = Object.freeze({
|
|
|
7787
7872
|
/** A plural that does not end in s, with no `--singular`. */
|
|
7788
7873
|
noClosingS: `${SCAFFOLD_OPTION.resource} takes a plural that ends in s where the line names no ${SCAFFOLD_OPTION.singular}, since the singular is then the plural without its closing s: name the singular with ${SCAFFOLD_OPTION.singular}, such as ${SCAFFOLD_OPTION.resource} people ${SCAFFOLD_OPTION.singular} person. ${NOTHING_WRITTEN2}`,
|
|
7789
7874
|
/** The plural `s` alone, with no `--singular`: its singular would be empty. */
|
|
7790
|
-
emptySingular: `${SCAFFOLD_OPTION.resource} takes a plural longer than s alone where the line names no ${SCAFFOLD_OPTION.singular}, since the singular, the plural without its closing s, is never empty: name the singular with ${SCAFFOLD_OPTION.singular}, or a longer plural. ${NOTHING_WRITTEN2}
|
|
7875
|
+
emptySingular: `${SCAFFOLD_OPTION.resource} takes a plural longer than s alone where the line names no ${SCAFFOLD_OPTION.singular}, since the singular, the plural without its closing s, is never empty: name the singular with ${SCAFFOLD_OPTION.singular}, or a longer plural. ${NOTHING_WRITTEN2}`,
|
|
7876
|
+
/** A singular, given or derived, of `json` (#5225): the resource's
|
|
7877
|
+
* invalid error, invalid_<singular>, would then be invalid_json, the
|
|
7878
|
+
* error of a body that does not parse, and a caller could no longer
|
|
7879
|
+
* tell the two apart (PLD-L0-106). */
|
|
7880
|
+
jsonSingular: `${SCAFFOLD_OPTION.singular} takes a singular other than json, since the service answers invalid_json for a body that does not parse and invalid_ with the singular for a row it refuses: name another singular with ${SCAFFOLD_OPTION.singular}, such as ${SCAFFOLD_OPTION.resource} jsons ${SCAFFOLD_OPTION.singular} document. ${NOTHING_WRITTEN2}`
|
|
7791
7881
|
});
|
|
7792
7882
|
var RESOURCE_NONE_KEPT = `${SCAFFOLD_OPTION.resource} and ${SCAFFOLD_OPTION.singular} name the resource ${RESOURCE_TEMPLATES_NAMED} keep, and the template this line writes keeps none: leave them out, or name ${RESOURCE_TEMPLATE_CHOICES}. ${NOTHING_WRITTEN2}`;
|
|
7793
7883
|
var UNKNOWN_TEMPLATE = `${SCAFFOLD_OPTION.template} names the template to write, and the command has no template of that name: it has ${listedAnd(SCAFFOLD_TEMPLATES)}, and it writes ${SCAFFOLD_DEFAULT_TEMPLATE} where the line names none. ${NOTHING_WRITTEN2}`;
|
|
7794
7884
|
var ownRouteRefusal = (word) => `${SCAFFOLD_OPTION.resource} takes a plural other than ${word}, the word of a route the template serves itself: name another plural. ${NOTHING_WRITTEN2}`;
|
|
7885
|
+
var JSON_SINGULAR = "json";
|
|
7795
7886
|
var resourceNamesOf = (call, template) => {
|
|
7796
7887
|
const plural = call.named[SCAFFOLD_OPTION.resource];
|
|
7797
7888
|
const singular = call.named[SCAFFOLD_OPTION.singular];
|
|
@@ -7802,10 +7893,11 @@ var resourceNamesOf = (call, template) => {
|
|
|
7802
7893
|
if (singular !== void 0 && !SCAFFOLD_NAME_FORM.test(singular)) return { refusal: RESOURCE_REFUSAL.singularForm };
|
|
7803
7894
|
const own = kept2.routes.find((word) => word === plural);
|
|
7804
7895
|
if (own !== void 0) return { refusal: ownRouteRefusal(own) };
|
|
7805
|
-
if (singular !== void 0) return { plural, singular };
|
|
7896
|
+
if (singular !== void 0) return singular === JSON_SINGULAR ? { refusal: RESOURCE_REFUSAL.jsonSingular } : { plural, singular };
|
|
7806
7897
|
if (!plural.endsWith("s")) return { refusal: RESOURCE_REFUSAL.noClosingS };
|
|
7807
7898
|
if (plural.length === 1) return { refusal: RESOURCE_REFUSAL.emptySingular };
|
|
7808
|
-
|
|
7899
|
+
const derived = plural.slice(0, -1);
|
|
7900
|
+
return derived === JSON_SINGULAR ? { refusal: RESOURCE_REFUSAL.jsonSingular } : { plural, singular: derived };
|
|
7809
7901
|
};
|
|
7810
7902
|
var CARRIED_FIELDS = Object.freeze([Object.freeze({ name: "title", kind: "text" })]);
|
|
7811
7903
|
var FIELD_KINDS_CLAUSE = `the kind ${orListed(SCAFFOLD_FIELD_KINDS)}`;
|
|
@@ -7857,10 +7949,12 @@ var scaffoldOptionsOf = (call, cwd) => {
|
|
|
7857
7949
|
if (names !== null && "refusal" in names) return names;
|
|
7858
7950
|
const fields = fieldsOf(call, template);
|
|
7859
7951
|
if (fields !== null && "refusal" in fields) return fields;
|
|
7952
|
+
const application = call.named[SCAFFOLD_OPTION.application];
|
|
7953
|
+
if (application !== void 0 && !UPLOAD_ID.test(application)) return { refusal: APPLICATION_FORM_REFUSAL };
|
|
7860
7954
|
const path = call.named[SCAFFOLD_OPTION.path];
|
|
7861
7955
|
const origin = commandOriginOf(call.named[SCAFFOLD_OPTION.origin] ?? DEFAULT_COMMAND_ORIGIN);
|
|
7862
7956
|
if ("refusal" in origin) return origin;
|
|
7863
|
-
return { template, names, fields, root: resolve11(cwd, path ?? "."), named: path !== void 0, origin: origin.origin };
|
|
7957
|
+
return { template, names, fields, root: resolve11(cwd, path ?? "."), named: path !== void 0, origin: origin.origin, application: application ?? null };
|
|
7864
7958
|
};
|
|
7865
7959
|
var capitalised = (name) => `${name.charAt(0).toUpperCase()}${name.slice(1)}`;
|
|
7866
7960
|
var resourceFormsOf = (names) => [
|
|
@@ -8179,9 +8273,36 @@ var manifestWithMinute = (text, minute) => {
|
|
|
8179
8273
|
if (!WRITTEN_MINUTE.test(String(minute))) throw new Error("a minute a run writes is a whole number from 0 to 59");
|
|
8180
8274
|
return `${around[0]}${CRON_HEAD}${minute} ${around[1]}`;
|
|
8181
8275
|
};
|
|
8182
|
-
var
|
|
8276
|
+
var MANIFEST_VERSION_LINE = ' "manifest_version": 1,\n';
|
|
8277
|
+
var APPLICATION_LINE_OPEN = ' "application": "';
|
|
8278
|
+
var applicationLineOf = (application) => `${APPLICATION_LINE_OPEN}${application}",
|
|
8279
|
+
`;
|
|
8280
|
+
var manifestWithApplication = (text, application) => {
|
|
8281
|
+
if (application === null) return text;
|
|
8282
|
+
const around = text.split(MANIFEST_VERSION_LINE);
|
|
8283
|
+
if (around.length !== 2) throw new Error("the template's manifest does not hold one manifest_version line");
|
|
8284
|
+
return `${around[0]}${MANIFEST_VERSION_LINE}${applicationLineOf(application)}${around[1]}`;
|
|
8285
|
+
};
|
|
8286
|
+
var composedFilesOf = (files, rows, minute, application = null) => files.map(([path, text]) => [path, path === APPLICATION_MANIFEST ? manifestWithApplication(manifestWithMinute(manifestWithPackages(text, rows), minute), application) : text]);
|
|
8287
|
+
var APPLICATION_LINE_REST = 'hhhhhhhh-hhhh-hhhh-hhhh-hhhhhhhhhhhh",';
|
|
8288
|
+
var applicationLineRestPart = (text) => text.length <= APPLICATION_LINE_REST.length && [...text].every((character, index) => APPLICATION_LINE_REST[index] === "h" ? /^[0-9a-f]$/.test(character) : character === APPLICATION_LINE_REST[index]);
|
|
8289
|
+
var withoutApplicationLine = (staged, text) => {
|
|
8290
|
+
const at = text.indexOf(MANIFEST_VERSION_LINE);
|
|
8291
|
+
if (at < 0) return staged;
|
|
8292
|
+
const head = text.slice(0, at + MANIFEST_VERSION_LINE.length);
|
|
8293
|
+
if (staged.length <= head.length || !staged.startsWith(head)) return staged;
|
|
8294
|
+
const rest = staged.slice(head.length);
|
|
8295
|
+
if (APPLICATION_LINE_OPEN.startsWith(rest)) return true;
|
|
8296
|
+
if (!rest.startsWith(APPLICATION_LINE_OPEN)) return staged;
|
|
8297
|
+
const after = rest.slice(APPLICATION_LINE_OPEN.length);
|
|
8298
|
+
const lineEnd = after.indexOf("\n");
|
|
8299
|
+
if (lineEnd < 0) return applicationLineRestPart(after);
|
|
8300
|
+
const line = after.slice(0, lineEnd);
|
|
8301
|
+
if (line.length !== APPLICATION_LINE_REST.length || !applicationLineRestPart(line)) return false;
|
|
8302
|
+
return `${head}${after.slice(lineEnd + 1)}`;
|
|
8303
|
+
};
|
|
8183
8304
|
var inside2 = (parent, child) => {
|
|
8184
|
-
const between =
|
|
8305
|
+
const between = relative6(parent, child);
|
|
8185
8306
|
return between !== "" && !between.startsWith("..") && !isAbsolute5(between);
|
|
8186
8307
|
};
|
|
8187
8308
|
var ownManifestText = (staged, text) => {
|
|
@@ -8189,7 +8310,9 @@ var ownManifestText = (staged, text) => {
|
|
|
8189
8310
|
if (around.length !== 2) return false;
|
|
8190
8311
|
const carried = text.split(CARRIED_CRON);
|
|
8191
8312
|
if (carried.length > 2) return false;
|
|
8192
|
-
|
|
8313
|
+
const unbound = withoutApplicationLine(staged, text);
|
|
8314
|
+
if (typeof unbound === "boolean") return unbound;
|
|
8315
|
+
let read2 = unbound;
|
|
8193
8316
|
if (carried.length === 2) {
|
|
8194
8317
|
const head = `${carried[0]}${CRON_HEAD}`;
|
|
8195
8318
|
if (read2.length > head.length) {
|
|
@@ -8223,18 +8346,18 @@ var ownStage = (io2, stage, files) => {
|
|
|
8223
8346
|
const folders = new Set([...texts.keys()].flatMap((path) => path.split("/").slice(0, -1).map((_, index, segments) => segments.slice(0, index + 1).join("/"))));
|
|
8224
8347
|
const own = (at, prefix) => (io2.listFolder(at) ?? []).every((name) => {
|
|
8225
8348
|
const path = prefix === "" ? name : `${prefix}/${name}`;
|
|
8226
|
-
const standing = io2.stat(
|
|
8349
|
+
const standing = io2.stat(join10(at, name));
|
|
8227
8350
|
if (standing === null) return false;
|
|
8228
|
-
if (standing.folder) return folders.has(path) && own(
|
|
8351
|
+
if (standing.folder) return folders.has(path) && own(join10(at, name), path);
|
|
8229
8352
|
const text = texts.get(path);
|
|
8230
|
-
return text !== void 0 && ownFile(io2,
|
|
8353
|
+
return text !== void 0 && ownFile(io2, join10(at, name), standing.size, path, text);
|
|
8231
8354
|
});
|
|
8232
8355
|
return own(stage, "");
|
|
8233
8356
|
};
|
|
8234
|
-
var danglingAt = (io2, folder, name) => io2.stat(
|
|
8357
|
+
var danglingAt = (io2, folder, name) => io2.stat(join10(folder, name)) === null && (io2.listFolder(folder) ?? []).some((held) => held.toLowerCase() === name.toLowerCase() && io2.stat(join10(folder, held)) === null);
|
|
8235
8358
|
var standsAt = (io2, folder, name) => {
|
|
8236
8359
|
try {
|
|
8237
|
-
return io2.stat(
|
|
8360
|
+
return io2.stat(join10(folder, name)) !== null || danglingAt(io2, folder, name);
|
|
8238
8361
|
} catch {
|
|
8239
8362
|
return true;
|
|
8240
8363
|
}
|
|
@@ -8269,8 +8392,8 @@ var folderRefusalOf = (io2, options, files, takeLines) => {
|
|
|
8269
8392
|
}
|
|
8270
8393
|
if (standing2 !== null || dirname6(at) === at) break;
|
|
8271
8394
|
}
|
|
8272
|
-
const app =
|
|
8273
|
-
const stage =
|
|
8395
|
+
const app = join10(root, APPLICATION_FOLDER);
|
|
8396
|
+
const stage = join10(root, STAGE_FOLDER);
|
|
8274
8397
|
const notOwn = STAGE_NOT_OWN;
|
|
8275
8398
|
const standing = io2.stat(app);
|
|
8276
8399
|
if (standing === null ? danglingAt(io2, root, APPLICATION_FOLDER) : !standing.folder) return [noFolderSentence(APPLICATION_FOLDER, "the scaffold writes the application")];
|
|
@@ -8379,7 +8502,7 @@ var nextStepLines = (origin, windows = LINES_IN_WINDOWS_FORM, left = NEITHER_LEF
|
|
|
8379
8502
|
var writeTemplate = (io2, stage, app, files) => {
|
|
8380
8503
|
io2.remove(stage);
|
|
8381
8504
|
for (const [path, text] of files) {
|
|
8382
|
-
const at =
|
|
8505
|
+
const at = join10(stage, ...path.split("/"));
|
|
8383
8506
|
io2.makeFolder(dirname6(at));
|
|
8384
8507
|
io2.writeFile(at, text);
|
|
8385
8508
|
}
|
|
@@ -8392,7 +8515,7 @@ var writeTemplate = (io2, stage, app, files) => {
|
|
|
8392
8515
|
};
|
|
8393
8516
|
var writeRootSentence = (io2, root) => {
|
|
8394
8517
|
try {
|
|
8395
|
-
io2.writeNewFile(
|
|
8518
|
+
io2.writeNewFile(join10(root, TOOLS_FILE), `${ROOT_SENTENCE}
|
|
8396
8519
|
`);
|
|
8397
8520
|
return "written";
|
|
8398
8521
|
} catch (error) {
|
|
@@ -8449,8 +8572,8 @@ async function scaffold(call, io2) {
|
|
|
8449
8572
|
const { takes } = TEMPLATE_FACTS[template];
|
|
8450
8573
|
const defaulted = call.named[SCAFFOLD_OPTION.template] === void 0;
|
|
8451
8574
|
const files = writtenFilesOf(template, options.names, options.fields);
|
|
8452
|
-
const app =
|
|
8453
|
-
const stage =
|
|
8575
|
+
const app = join10(root, APPLICATION_FOLDER);
|
|
8576
|
+
const stage = join10(root, STAGE_FOLDER);
|
|
8454
8577
|
const takeLines = takes.map((take) => machineLineOf(libraryTakeLineOf({ origin, entry: take.entry }), { windows: io2.windows ?? LINES_IN_WINDOWS_FORM, npx: ranThroughNpx(io2) }, origin));
|
|
8455
8578
|
let reached = "checks";
|
|
8456
8579
|
const stateNow = () => {
|
|
@@ -8479,7 +8602,7 @@ async function scaffold(call, io2) {
|
|
|
8479
8602
|
held = found;
|
|
8480
8603
|
} else {
|
|
8481
8604
|
for (const take of takes) {
|
|
8482
|
-
const copy =
|
|
8605
|
+
const copy = join10(app, "lib", take.entry);
|
|
8483
8606
|
const planOf = (library) => writesOver(library, copy) ? { refusal: LIBRARY_OVER_APPLICATION } : { application: app, copy, declared: null, declaredAt: null };
|
|
8484
8607
|
const read2 = await readTake(io2, { entry: take.entry, root, named: options.named, origin }, agent.userAgent, planOf, checks.length > 0);
|
|
8485
8608
|
if ("lines" in read2) return refuse(...read2.lines);
|
|
@@ -8502,7 +8625,7 @@ async function scaffold(call, io2) {
|
|
|
8502
8625
|
reached = "writes";
|
|
8503
8626
|
if (io2.stat(root) === null) io2.makeFolder(root);
|
|
8504
8627
|
if (held.fresh) io2.makeFolder(held.library);
|
|
8505
|
-
writeTemplate(io2, stage, app, composedFilesOf(files, held.packages, minute));
|
|
8628
|
+
writeTemplate(io2, stage, app, composedFilesOf(files, held.packages, minute, options.application));
|
|
8506
8629
|
reached = "template";
|
|
8507
8630
|
const tools = toolsStands ? "stands" : writeRootSentence(io2, root);
|
|
8508
8631
|
if (defaulted) io2.print(DEFAULT_TEMPLATE_LINE);
|
|
@@ -8577,6 +8700,7 @@ var SCAFFOLD_ROW = Object.freeze({
|
|
|
8577
8700
|
},
|
|
8578
8701
|
note: [
|
|
8579
8702
|
`Run the ${SCAFFOLD_SUBCOMMAND} line at the root of a new project, or name the root with ${SCAFFOLD_OPTION.path}, which the command makes where it does not stand. A line that names no ${SCAFFOLD_OPTION.template} writes ${SCAFFOLD_DEFAULT_TEMPLATE}, which takes no library entry and makes no request, and says so in a line before the files it wrote. Under scheduled-job, the minute of the schedule's cron in the manifest is the minute of the hour, in UTC, at which the run started.`,
|
|
8703
|
+
`With ${SCAFFOLD_OPTION.application}, the manifest names that application in its application member, on the line after manifest_version, which binds the folder to it before any deploy: a deploy or check line naming another application is refused. Where absent, the first deploy writes the member.`,
|
|
8580
8704
|
`Under ${listedAnd(RESOURCE_TEMPLATES)}, with ${SCAFFOLD_OPTION.resource}, and ${SCAFFOLD_OPTION.singular} where the singular is not the plural without its closing s, it writes the same service under the resource's names, its table, its route, its functions, and its file names among them, and runs the tests on the files as written. It refuses, writing nothing, where the root's ${APPLICATION_FOLDER}/ holds any file or folder, and it takes no option that overwrites: where the template takes entries, its sentence names the ${LIBRARY_SUBCOMMAND} take line for each, which adds the package to an application that stands.`,
|
|
8581
8705
|
`A root that holds neither ${LIBRARY_FOLDER}/ nor ${POINTER_FILE} takes a ${LIBRARY_FOLDER}/ of its own. Where the root holds no ${TOOLS_FILE}, it writes one of one sentence, which sends a coding tool to ${APPLICATION_FOLDER}/${TOOLS_FILE}; it changes no file that stands at the root, and where an ${TOOLS_FILE} or a ${CLAUDE_FILE} stands there it prints the sentence to add.`,
|
|
8582
8706
|
`${SCAFFOLD_SUBCOMMAND} leaves ${COMMAND_CREDENTIAL_VARIABLES.join(" and ")} out of what npm install and npm test receive. An interrupt reaches npm, the command ends after it, and after an interrupted install the tests are not started. A signal that arrives after the command's first write and before npm starts is acted on once the writes are made: the command prints the way on, starts no npm, and ends with 128 and the signal's number.`,
|
|
@@ -8759,6 +8883,7 @@ var startErrorOf = (error) => {
|
|
|
8759
8883
|
var HELD_SIGNALS = Object.freeze(["SIGINT", "SIGTERM", "SIGHUP"]);
|
|
8760
8884
|
var endedStatusOf = (signal) => 128 + (constants2.signals[signal] ?? 0);
|
|
8761
8885
|
var SIGNALS_PASS_ON = process.platform !== "win32";
|
|
8886
|
+
var CHILD_GROUPS = process.platform !== "win32";
|
|
8762
8887
|
var passedOnSignalOf = (signal, interrupts, inputIsTerminal, passesOn = SIGNALS_PASS_ON) => {
|
|
8763
8888
|
if (!passesOn) return null;
|
|
8764
8889
|
if (signal !== "SIGINT") return signal;
|
|
@@ -8783,16 +8908,18 @@ var holdSignals = (signals, inputIsTerminal, passesOn, passOn, onInterrupt) => {
|
|
|
8783
8908
|
for (const [signal, handler] of held) signals.off(signal, handler);
|
|
8784
8909
|
};
|
|
8785
8910
|
};
|
|
8786
|
-
var childRunnerOf = (signals, inputIsTerminal, passesOn = SIGNALS_PASS_ON) => (run) => new Promise((resolve12) => {
|
|
8911
|
+
var childRunnerOf = (signals, inputIsTerminal, passesOn = SIGNALS_PASS_ON, groups = CHILD_GROUPS) => (run) => new Promise((resolve12) => {
|
|
8787
8912
|
const output = run.output;
|
|
8788
8913
|
let interrupted = false;
|
|
8914
|
+
const group = run.foreground === true && passesOn && groups;
|
|
8789
8915
|
try {
|
|
8790
8916
|
const child = spawn(run.command, [...run.args], {
|
|
8791
8917
|
cwd: run.cwd,
|
|
8792
8918
|
env: run.env,
|
|
8793
8919
|
shell: run.shell ?? false,
|
|
8794
8920
|
stdio: ["ignore", output ? "pipe" : "inherit", output ? "pipe" : "inherit"],
|
|
8795
|
-
windowsHide: false
|
|
8921
|
+
windowsHide: false,
|
|
8922
|
+
detached: group
|
|
8796
8923
|
});
|
|
8797
8924
|
if (output) {
|
|
8798
8925
|
child.stdout?.setEncoding("utf8").on("data", (chunk) => output(chunk, "stdout"));
|
|
@@ -8803,9 +8930,17 @@ var childRunnerOf = (signals, inputIsTerminal, passesOn = SIGNALS_PASS_ON) => (r
|
|
|
8803
8930
|
if (run.foreground) {
|
|
8804
8931
|
const release = holdSignals(
|
|
8805
8932
|
signals,
|
|
8806
|
-
|
|
8933
|
+
// A group of its own hears no terminal's interrupt, so the command hands on the first one too.
|
|
8934
|
+
group ? false : inputIsTerminal(),
|
|
8807
8935
|
passesOn,
|
|
8808
8936
|
(signal) => {
|
|
8937
|
+
if (group && child.pid !== void 0) {
|
|
8938
|
+
try {
|
|
8939
|
+
process.kill(-child.pid, signal);
|
|
8940
|
+
return;
|
|
8941
|
+
} catch {
|
|
8942
|
+
}
|
|
8943
|
+
}
|
|
8809
8944
|
child.kill(signal);
|
|
8810
8945
|
},
|
|
8811
8946
|
() => {
|
|
@@ -9182,7 +9317,7 @@ async function runGuarded(argv2, io2) {
|
|
|
9182
9317
|
if (parsed.kind === "refused") {
|
|
9183
9318
|
say(carriesTokenCode(argv2) ? `${parsed.sentence} ${TOKEN_CODE_UNREAD}` : parsed.sentence);
|
|
9184
9319
|
const npx = "ranThroughNpx" in io2 && io2.ranThroughNpx === true;
|
|
9185
|
-
const help = npx ? npxFormOf(`${SERVED} --help`, io2.env[ORIGIN_VARIABLE]
|
|
9320
|
+
const help = npx ? npxFormOf(`${SERVED} --help`, originReadOf(io2.env[ORIGIN_VARIABLE])) : `${SERVED} --help`;
|
|
9186
9321
|
say(`${io2.windows ?? ON_WINDOWS ? windowsLineOf(help) : help} prints the usage.`);
|
|
9187
9322
|
return COMMAND_STATUS.nothing_started;
|
|
9188
9323
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "turnzero",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0-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",
|