wholestack 0.6.1 → 0.6.2
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/{chunk-KJ5INI3M.js → chunk-UBDW5N5G.js} +52 -0
- package/dist/cli.js +376 -60
- package/dist/index.d.ts +68 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -830,10 +830,12 @@ function normalize(result) {
|
|
|
830
830
|
const verify = result.verify ?? {};
|
|
831
831
|
const proofVerdict = result.proof?.verdict;
|
|
832
832
|
const shipped = proofVerdict ? proofVerdict === "SHIP" : !!verify.ok;
|
|
833
|
+
const pending = result.proof?.proofStatus === "pending" && shipped;
|
|
833
834
|
return {
|
|
834
835
|
ok: true,
|
|
835
836
|
buildId: result.buildId ?? null,
|
|
836
837
|
verdict: shipped ? "SHIP" : "NO_SHIP",
|
|
838
|
+
proofPending: pending,
|
|
837
839
|
themeId: result.themeId ?? null,
|
|
838
840
|
fileCount: files.length,
|
|
839
841
|
spec: typeof result.spec === "string" ? result.spec : null,
|
|
@@ -869,6 +871,33 @@ function makeConsumer(onPhase) {
|
|
|
869
871
|
}
|
|
870
872
|
};
|
|
871
873
|
}
|
|
874
|
+
async function pollProofStatus(zetaApiUrl, buildId, authHeaders8, opts = {}) {
|
|
875
|
+
const interval = opts.intervalMs ?? 5e3;
|
|
876
|
+
const timeout = opts.timeoutMs ?? 10 * 60 * 1e3;
|
|
877
|
+
const started = Date.now();
|
|
878
|
+
let last = { proofStatus: "pending", verdict: null, dirty: false };
|
|
879
|
+
while (Date.now() - started < timeout) {
|
|
880
|
+
try {
|
|
881
|
+
const resp = await fetch(
|
|
882
|
+
`${zetaApiUrl}/api/zeta/build/${encodeURIComponent(buildId)}/proof-status`,
|
|
883
|
+
{ headers: { ...authHeaders8 } }
|
|
884
|
+
);
|
|
885
|
+
if (resp.ok) {
|
|
886
|
+
const j = await resp.json();
|
|
887
|
+
last = {
|
|
888
|
+
proofStatus: j.proofStatus ?? null,
|
|
889
|
+
verdict: j.verdict ?? null,
|
|
890
|
+
dirty: j.dirty === true
|
|
891
|
+
};
|
|
892
|
+
if (last.proofStatus && last.proofStatus !== "pending") return last;
|
|
893
|
+
}
|
|
894
|
+
} catch {
|
|
895
|
+
}
|
|
896
|
+
opts.onTick?.(Date.now() - started);
|
|
897
|
+
await new Promise((r) => setTimeout(r, interval));
|
|
898
|
+
}
|
|
899
|
+
return last;
|
|
900
|
+
}
|
|
872
901
|
async function httpBuild(zetaApiUrl, body, onPhase) {
|
|
873
902
|
let resp;
|
|
874
903
|
try {
|
|
@@ -2470,6 +2499,24 @@ function buildTools(ctx) {
|
|
|
2470
2499
|
viaHosted = true;
|
|
2471
2500
|
}
|
|
2472
2501
|
}
|
|
2502
|
+
if (viaHosted && result.ok && result.proofPending && result.buildId) {
|
|
2503
|
+
const bid = String(result.buildId);
|
|
2504
|
+
line(c.dim(" \u21B3 shipped fast \u2014 runtime proofs running in the background\u2026"));
|
|
2505
|
+
const final = await pollProofStatus(ctx.zetaApiUrl, bid, {}, {
|
|
2506
|
+
timeoutMs: 6 * 60 * 1e3,
|
|
2507
|
+
onTick: (ms) => line(c.dim(` proving\u2026 (${Math.round(ms / 1e3)}s)`))
|
|
2508
|
+
});
|
|
2509
|
+
if (final.proofStatus === "proven") {
|
|
2510
|
+
line(c.green(` \u2713 proven \u2014 ${final.verdict ?? "SHIP"}`));
|
|
2511
|
+
result = { ...result, verdict: final.verdict ?? result.verdict, proofPending: false };
|
|
2512
|
+
} else if (final.proofStatus === "failed") {
|
|
2513
|
+
line(c.red(` \u2717 proof FAILED after ship \u2014 your app is live but UNPROVEN (${final.verdict ?? "NO_SHIP"}).`));
|
|
2514
|
+
line(c.red(` Roll it back: zeta rollback ${bid}`));
|
|
2515
|
+
result = { ...result, verdict: "NO_SHIP", proofPending: false };
|
|
2516
|
+
} else {
|
|
2517
|
+
line(c.dim(` still proving \u2014 check later: zeta proof ${bid}`));
|
|
2518
|
+
}
|
|
2519
|
+
}
|
|
2473
2520
|
if (keep !== false && viaHosted && result.ok && result.buildId && !result.paywalled) {
|
|
2474
2521
|
const dest = opts.destDir ? join5(ctx.cwd, opts.destDir) : join5(ctx.cwd, `zeta-${String(result.buildId).slice(-8)}`);
|
|
2475
2522
|
line(c.dim(" \u21B3 saving your code\u2026"));
|
|
@@ -9946,6 +9993,9 @@ export {
|
|
|
9946
9993
|
writeProjectLink,
|
|
9947
9994
|
writeWorkingTree,
|
|
9948
9995
|
collectLocalFiles,
|
|
9996
|
+
httpBuild,
|
|
9997
|
+
demoBootBuild,
|
|
9998
|
+
deliverBuild,
|
|
9949
9999
|
deployBuild,
|
|
9950
10000
|
promoteBuild,
|
|
9951
10001
|
rollbackDeployment,
|
|
@@ -9959,6 +10009,8 @@ export {
|
|
|
9959
10009
|
PROPERTY_KINDS,
|
|
9960
10010
|
runProver,
|
|
9961
10011
|
killRunningApps,
|
|
10012
|
+
isolateFromWorkspace,
|
|
10013
|
+
installDeps,
|
|
9962
10014
|
fetchGithubInstallations,
|
|
9963
10015
|
fetchGithubRepos,
|
|
9964
10016
|
runRepoAuditStream,
|
package/dist/cli.js
CHANGED
|
@@ -20,6 +20,8 @@ import {
|
|
|
20
20
|
buildWebTools,
|
|
21
21
|
c,
|
|
22
22
|
collectLocalFiles,
|
|
23
|
+
deliverBuild,
|
|
24
|
+
demoBootBuild,
|
|
23
25
|
deployBuild,
|
|
24
26
|
drawCanvas,
|
|
25
27
|
escalationBus,
|
|
@@ -28,8 +30,11 @@ import {
|
|
|
28
30
|
generateLegal,
|
|
29
31
|
getBusiness,
|
|
30
32
|
getLaunchKit,
|
|
33
|
+
httpBuild,
|
|
31
34
|
inspectUrl,
|
|
35
|
+
installDeps,
|
|
32
36
|
isPermissionMode,
|
|
37
|
+
isolateFromWorkspace,
|
|
33
38
|
killRunningApps,
|
|
34
39
|
line,
|
|
35
40
|
listBusinesses,
|
|
@@ -75,11 +80,11 @@ import {
|
|
|
75
80
|
webBaseUrl,
|
|
76
81
|
writeProjectLink,
|
|
77
82
|
writeWorkingTree
|
|
78
|
-
} from "./chunk-
|
|
83
|
+
} from "./chunk-UBDW5N5G.js";
|
|
79
84
|
|
|
80
85
|
// src/cli.ts
|
|
81
86
|
import { createInterface } from "readline/promises";
|
|
82
|
-
import { stdin, stdout as
|
|
87
|
+
import { stdin, stdout as stdout4, argv, exit, cwd as cwd3 } from "process";
|
|
83
88
|
|
|
84
89
|
// src/cli-login.ts
|
|
85
90
|
import { createServer } from "http";
|
|
@@ -107,7 +112,7 @@ async function loginBrowser(opts) {
|
|
|
107
112
|
const state = randomBytes(16).toString("hex");
|
|
108
113
|
const device = hostname().slice(0, 60);
|
|
109
114
|
const timeoutMs = (opts.timeoutSec ?? 240) * 1e3;
|
|
110
|
-
return new Promise((
|
|
115
|
+
return new Promise((resolve5) => {
|
|
111
116
|
let settled = false;
|
|
112
117
|
const finish = (token) => {
|
|
113
118
|
if (settled) return;
|
|
@@ -117,7 +122,7 @@ async function loginBrowser(opts) {
|
|
|
117
122
|
server.close();
|
|
118
123
|
} catch {
|
|
119
124
|
}
|
|
120
|
-
|
|
125
|
+
resolve5(token);
|
|
121
126
|
};
|
|
122
127
|
const server = createServer((req, res) => {
|
|
123
128
|
const url = new URL(req.url ?? "/", "http://127.0.0.1");
|
|
@@ -334,7 +339,7 @@ async function renderTree(absDir, relDir) {
|
|
|
334
339
|
return `${relDir || "."}/ (directory tree)
|
|
335
340
|
${lines.join("\n")}`;
|
|
336
341
|
}
|
|
337
|
-
async function expandMentions(message,
|
|
342
|
+
async function expandMentions(message, cwd4, tokenBudget = DEFAULT_TOKEN_BUDGET) {
|
|
338
343
|
const mentions = extractMentions(message);
|
|
339
344
|
if (mentions.length === 0) return { context: "", notice: null };
|
|
340
345
|
const blocks = [];
|
|
@@ -344,7 +349,7 @@ async function expandMentions(message, cwd3, tokenBudget = DEFAULT_TOKEN_BUDGET)
|
|
|
344
349
|
for (const mention of mentions) {
|
|
345
350
|
if (spent >= tokenBudget) break;
|
|
346
351
|
const raw = mention.startsWith("~/") ? join(process.env.HOME ?? "", mention.slice(2)) : mention;
|
|
347
|
-
const direct = isAbsolute(raw) ? raw : resolve(
|
|
352
|
+
const direct = isAbsolute(raw) ? raw : resolve(cwd4, raw);
|
|
348
353
|
let isDir = false;
|
|
349
354
|
try {
|
|
350
355
|
isDir = (await stat(direct)).isDirectory();
|
|
@@ -352,7 +357,7 @@ async function expandMentions(message, cwd3, tokenBudget = DEFAULT_TOKEN_BUDGET)
|
|
|
352
357
|
isDir = false;
|
|
353
358
|
}
|
|
354
359
|
if (isDir) {
|
|
355
|
-
const rel = relative(
|
|
360
|
+
const rel = relative(cwd4, direct);
|
|
356
361
|
const tree = await renderTree(direct, rel);
|
|
357
362
|
const cost = estTokens(tree);
|
|
358
363
|
if (spent + cost <= tokenBudget) {
|
|
@@ -365,7 +370,7 @@ async function expandMentions(message, cwd3, tokenBudget = DEFAULT_TOKEN_BUDGET)
|
|
|
365
370
|
let files = [];
|
|
366
371
|
try {
|
|
367
372
|
files = await fg(raw, {
|
|
368
|
-
cwd:
|
|
373
|
+
cwd: cwd4,
|
|
369
374
|
ignore: IGNORE,
|
|
370
375
|
onlyFiles: true,
|
|
371
376
|
dot: true,
|
|
@@ -377,7 +382,7 @@ async function expandMentions(message, cwd3, tokenBudget = DEFAULT_TOKEN_BUDGET)
|
|
|
377
382
|
}
|
|
378
383
|
if (files.length === 0) {
|
|
379
384
|
try {
|
|
380
|
-
if ((await stat(direct)).isFile()) files = [relative(
|
|
385
|
+
if ((await stat(direct)).isFile()) files = [relative(cwd4, direct)];
|
|
381
386
|
} catch {
|
|
382
387
|
}
|
|
383
388
|
}
|
|
@@ -388,7 +393,7 @@ async function expandMentions(message, cwd3, tokenBudget = DEFAULT_TOKEN_BUDGET)
|
|
|
388
393
|
seen.add(rel);
|
|
389
394
|
let buf;
|
|
390
395
|
try {
|
|
391
|
-
buf = await readFile2(resolve(
|
|
396
|
+
buf = await readFile2(resolve(cwd4, rel), "utf8");
|
|
392
397
|
} catch {
|
|
393
398
|
continue;
|
|
394
399
|
}
|
|
@@ -563,9 +568,9 @@ function workerToolset(worktreeCtx) {
|
|
|
563
568
|
return out;
|
|
564
569
|
}
|
|
565
570
|
var WORKER_SYSTEM = "You are an autonomous engineer spawned by a lead engineer to complete ONE focused, self-contained slice of a larger task. You have a full coding toolset (read_file, write_file, edit_file, multi_edit, list_dir, glob, grep, run_command) and you are working in your OWN isolated git worktree \u2014 your edits cannot affect anyone else, so edit freely. Approach: (1) explore the relevant files, (2) make the change, (3) verify it (build/test/typecheck where it makes sense), (4) report. Stay strictly within your assigned slice \u2014 do not refactor unrelated code. When done, return a tight summary: what you changed, which files, and how you verified it.";
|
|
566
|
-
function git(args,
|
|
571
|
+
function git(args, cwd4, timeoutMs = 3e4) {
|
|
567
572
|
return new Promise((res) => {
|
|
568
|
-
const child = spawn2("git", args, { cwd:
|
|
573
|
+
const child = spawn2("git", args, { cwd: cwd4, shell: false });
|
|
569
574
|
let out = "";
|
|
570
575
|
const timer = setTimeout(() => child.kill("SIGKILL"), timeoutMs);
|
|
571
576
|
const sink = (b) => {
|
|
@@ -846,6 +851,309 @@ async function runOpsSubcommand(raw) {
|
|
|
846
851
|
return 1;
|
|
847
852
|
}
|
|
848
853
|
|
|
854
|
+
// src/factory.ts
|
|
855
|
+
import { existsSync, mkdirSync, readFileSync } from "fs";
|
|
856
|
+
import { join as join3, resolve as resolve2 } from "path";
|
|
857
|
+
import { cwd as cwd2, stderr, stdout as stdout2 } from "process";
|
|
858
|
+
var HELP = `${c.bold("wholestack make")} \u2014 the app factory. One idea in, a full-stack app out.
|
|
859
|
+
|
|
860
|
+
${c.bold("USAGE")}
|
|
861
|
+
wholestack make ${c.dim('"<idea>"')} make one app from an idea
|
|
862
|
+
wholestack make --batch ${c.dim("<file>")} make one app per non-blank line of a file
|
|
863
|
+
|
|
864
|
+
${c.bold("OPTIONS")}
|
|
865
|
+
--out ${c.dim("<dir>")} parent dir for delivered apps ${c.dim("(default: ./out)")}
|
|
866
|
+
--batch ${c.dim("<file>")} a file of ideas, one per line (# comments allowed)
|
|
867
|
+
--concurrency ${c.dim("<n>")} build N apps at once ${c.dim("(default: 1; engine may rate-limit)")}
|
|
868
|
+
--json emit NDJSON results to stdout, human chrome to stderr
|
|
869
|
+
--boot boot a free live URL instead of delivering code ${c.dim("(no paywall)")}
|
|
870
|
+
--install run pnpm install in each delivered app
|
|
871
|
+
--max use the zeta-g1-max build model ${c.dim("(default: zeta-g1)")}
|
|
872
|
+
--theme ${c.dim("<id>")} force a theme id
|
|
873
|
+
--style ${c.dim("<id>")} force a Launch Style id (e.g. mono-noir, voltage)
|
|
874
|
+
--color ${c.dim("<d|l>")} force dark or light
|
|
875
|
+
--verbose stream the engine's build phases
|
|
876
|
+
-h, --help show this help
|
|
877
|
+
|
|
878
|
+
${c.bold("NOTES")}
|
|
879
|
+
\u2022 Delivering code requires a Wholestack membership and spends one build credit per
|
|
880
|
+
app. Run ${c.cyan("wholestack login")} first. ${c.dim("--boot is free but keeps no code.")}
|
|
881
|
+
\u2022 Exit code is 0 only when every requested app shipped.`;
|
|
882
|
+
var KNOWN = /* @__PURE__ */ new Set([
|
|
883
|
+
"--out",
|
|
884
|
+
"--batch",
|
|
885
|
+
"--concurrency",
|
|
886
|
+
"--json",
|
|
887
|
+
"--boot",
|
|
888
|
+
"--install",
|
|
889
|
+
"--max",
|
|
890
|
+
"--theme",
|
|
891
|
+
"--style",
|
|
892
|
+
"--color",
|
|
893
|
+
"--verbose",
|
|
894
|
+
"-h",
|
|
895
|
+
"--help"
|
|
896
|
+
]);
|
|
897
|
+
function parseFlags(rest) {
|
|
898
|
+
const f = {
|
|
899
|
+
out: "out",
|
|
900
|
+
concurrency: 1,
|
|
901
|
+
json: false,
|
|
902
|
+
boot: false,
|
|
903
|
+
install: false,
|
|
904
|
+
buildModel: "zeta-g1",
|
|
905
|
+
verbose: false,
|
|
906
|
+
help: false,
|
|
907
|
+
ideaParts: []
|
|
908
|
+
};
|
|
909
|
+
for (let i = 0; i < rest.length; i++) {
|
|
910
|
+
const a = rest[i];
|
|
911
|
+
const need = (label) => {
|
|
912
|
+
const v = rest[++i];
|
|
913
|
+
if (v == null || v.startsWith("-")) throw new Error(`${label} needs a value`);
|
|
914
|
+
return v;
|
|
915
|
+
};
|
|
916
|
+
switch (a) {
|
|
917
|
+
case "-h":
|
|
918
|
+
case "--help":
|
|
919
|
+
f.help = true;
|
|
920
|
+
break;
|
|
921
|
+
case "--json":
|
|
922
|
+
f.json = true;
|
|
923
|
+
break;
|
|
924
|
+
case "--boot":
|
|
925
|
+
f.boot = true;
|
|
926
|
+
break;
|
|
927
|
+
case "--install":
|
|
928
|
+
f.install = true;
|
|
929
|
+
break;
|
|
930
|
+
case "--max":
|
|
931
|
+
f.buildModel = "zeta-g1-max";
|
|
932
|
+
break;
|
|
933
|
+
case "--verbose":
|
|
934
|
+
f.verbose = true;
|
|
935
|
+
break;
|
|
936
|
+
case "--out":
|
|
937
|
+
f.out = need("--out");
|
|
938
|
+
break;
|
|
939
|
+
case "--batch":
|
|
940
|
+
f.batch = need("--batch");
|
|
941
|
+
break;
|
|
942
|
+
case "--concurrency": {
|
|
943
|
+
const n = Number(need("--concurrency"));
|
|
944
|
+
if (!Number.isInteger(n) || n < 1 || n > 16)
|
|
945
|
+
throw new Error("--concurrency must be an integer 1\u201316");
|
|
946
|
+
f.concurrency = n;
|
|
947
|
+
break;
|
|
948
|
+
}
|
|
949
|
+
case "--theme":
|
|
950
|
+
f.themeId = need("--theme");
|
|
951
|
+
break;
|
|
952
|
+
case "--style":
|
|
953
|
+
f.styleId = need("--style");
|
|
954
|
+
break;
|
|
955
|
+
case "--color": {
|
|
956
|
+
const v = need("--color").toLowerCase();
|
|
957
|
+
if (v === "d" || v === "dark") f.colorScheme = "dark";
|
|
958
|
+
else if (v === "l" || v === "light") f.colorScheme = "light";
|
|
959
|
+
else throw new Error("--color must be dark or light");
|
|
960
|
+
break;
|
|
961
|
+
}
|
|
962
|
+
default:
|
|
963
|
+
if (a.startsWith("-") && !KNOWN.has(a)) throw new Error(`unknown flag: ${a}`);
|
|
964
|
+
f.ideaParts.push(a);
|
|
965
|
+
}
|
|
966
|
+
}
|
|
967
|
+
return f;
|
|
968
|
+
}
|
|
969
|
+
function slugify(idea) {
|
|
970
|
+
const s = idea.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").split("-").filter(Boolean).slice(0, 5).join("-");
|
|
971
|
+
return s || "app";
|
|
972
|
+
}
|
|
973
|
+
function readBatch(file) {
|
|
974
|
+
const path = resolve2(cwd2(), file);
|
|
975
|
+
if (!existsSync(path)) throw new Error(`batch file not found: ${file}`);
|
|
976
|
+
return readFileSync(path, "utf8").split("\n").map((l) => l.trim()).filter((l) => l && !l.startsWith("#"));
|
|
977
|
+
}
|
|
978
|
+
function destFor(outRoot, idea, buildId) {
|
|
979
|
+
const base2 = join3(outRoot, slugify(idea));
|
|
980
|
+
if (!existsSync(base2)) return base2;
|
|
981
|
+
return `${base2}-${buildId.slice(-6)}`;
|
|
982
|
+
}
|
|
983
|
+
async function buildOne(engine, idea, flags, outRoot, onPhase) {
|
|
984
|
+
const slug2 = slugify(idea);
|
|
985
|
+
try {
|
|
986
|
+
if (flags.boot) {
|
|
987
|
+
const booted = await demoBootBuild(
|
|
988
|
+
engine,
|
|
989
|
+
{ idea, buildModel: flags.buildModel, ...flags.themeId ? { themeId: flags.themeId } : {}, lean: true },
|
|
990
|
+
onPhase
|
|
991
|
+
);
|
|
992
|
+
if (booted.ok && booted.liveUrl) {
|
|
993
|
+
return {
|
|
994
|
+
idea,
|
|
995
|
+
slug: slug2,
|
|
996
|
+
ok: true,
|
|
997
|
+
verdict: booted.verdict,
|
|
998
|
+
files: booted.files,
|
|
999
|
+
liveUrl: booted.liveUrl,
|
|
1000
|
+
buildId: booted.buildId
|
|
1001
|
+
};
|
|
1002
|
+
}
|
|
1003
|
+
return { idea, slug: slug2, ok: false, error: booted.error ?? "boot failed" };
|
|
1004
|
+
}
|
|
1005
|
+
const result = await httpBuild(
|
|
1006
|
+
engine,
|
|
1007
|
+
{
|
|
1008
|
+
idea,
|
|
1009
|
+
buildModel: flags.buildModel,
|
|
1010
|
+
install: false,
|
|
1011
|
+
scope: "full",
|
|
1012
|
+
...flags.themeId ? { themeId: flags.themeId } : {},
|
|
1013
|
+
...flags.styleId ? { styleId: flags.styleId } : {},
|
|
1014
|
+
...flags.colorScheme ? { colorScheme: flags.colorScheme } : {},
|
|
1015
|
+
lean: true
|
|
1016
|
+
},
|
|
1017
|
+
onPhase
|
|
1018
|
+
);
|
|
1019
|
+
if (!result.ok) return { idea, slug: slug2, ok: false, error: result.error ?? "build failed" };
|
|
1020
|
+
if (result.paywalled || !result.buildId) {
|
|
1021
|
+
return {
|
|
1022
|
+
idea,
|
|
1023
|
+
slug: slug2,
|
|
1024
|
+
ok: false,
|
|
1025
|
+
error: `preview only \u2014 subscribe to keep code: ${result.upgradeUrl ?? `${engine.replace(/\/$/, "")}/pricing`}`
|
|
1026
|
+
};
|
|
1027
|
+
}
|
|
1028
|
+
const dest = destFor(outRoot, idea, String(result.buildId));
|
|
1029
|
+
mkdirSync(dest, { recursive: true });
|
|
1030
|
+
const delivered = await deliverBuild(engine, String(result.buildId), dest, onPhase);
|
|
1031
|
+
if (!delivered.ok) {
|
|
1032
|
+
const why = delivered.paywalled ? `subscribe to keep code: ${delivered.upgradeUrl ?? "/pricing"}` : delivered.error ?? "delivery failed";
|
|
1033
|
+
return { idea, slug: slug2, ok: false, buildId: String(result.buildId), error: why };
|
|
1034
|
+
}
|
|
1035
|
+
isolateFromWorkspace(dest);
|
|
1036
|
+
if (flags.install) {
|
|
1037
|
+
const inst = await installDeps(dest, onPhase);
|
|
1038
|
+
if (!inst.ok) onPhase(`install failed \u2014 fix package.json then run pnpm install`);
|
|
1039
|
+
}
|
|
1040
|
+
return {
|
|
1041
|
+
idea,
|
|
1042
|
+
slug: slug2,
|
|
1043
|
+
ok: true,
|
|
1044
|
+
verdict: result.verdict,
|
|
1045
|
+
files: result.fileCount,
|
|
1046
|
+
dir: dest,
|
|
1047
|
+
buildId: String(result.buildId)
|
|
1048
|
+
};
|
|
1049
|
+
} catch (e) {
|
|
1050
|
+
return { idea, slug: slug2, ok: false, error: e.message };
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
async function runPool(items, n, worker, onDone) {
|
|
1054
|
+
const results = new Array(items.length);
|
|
1055
|
+
let next = 0;
|
|
1056
|
+
async function lane() {
|
|
1057
|
+
for (; ; ) {
|
|
1058
|
+
const i = next++;
|
|
1059
|
+
if (i >= items.length) return;
|
|
1060
|
+
const r = await worker(items[i], i);
|
|
1061
|
+
results[i] = r;
|
|
1062
|
+
onDone(r, i);
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
await Promise.all(Array.from({ length: Math.min(n, items.length) }, () => lane()));
|
|
1066
|
+
return results;
|
|
1067
|
+
}
|
|
1068
|
+
async function runMakeSubcommand(rawArgs) {
|
|
1069
|
+
const verb = rawArgs[0];
|
|
1070
|
+
if (verb !== "make" && verb !== "factory") return null;
|
|
1071
|
+
let flags;
|
|
1072
|
+
try {
|
|
1073
|
+
flags = parseFlags(rawArgs.slice(1));
|
|
1074
|
+
} catch (e) {
|
|
1075
|
+
line(c.red(` ${e.message}`));
|
|
1076
|
+
line(c.dim(" wholestack make --help"));
|
|
1077
|
+
return 1;
|
|
1078
|
+
}
|
|
1079
|
+
if (flags.help) {
|
|
1080
|
+
line(HELP);
|
|
1081
|
+
return 0;
|
|
1082
|
+
}
|
|
1083
|
+
const chrome = flags.json ? (s = "") => stderr.write(s + "\n") : line;
|
|
1084
|
+
let ideas;
|
|
1085
|
+
try {
|
|
1086
|
+
if (flags.batch) {
|
|
1087
|
+
if (flags.ideaParts.length) throw new Error("pass an idea OR --batch, not both");
|
|
1088
|
+
ideas = readBatch(flags.batch);
|
|
1089
|
+
} else {
|
|
1090
|
+
const inline = flags.ideaParts.join(" ").trim();
|
|
1091
|
+
ideas = inline ? [inline] : [];
|
|
1092
|
+
}
|
|
1093
|
+
} catch (e) {
|
|
1094
|
+
chrome(c.red(` ${e.message}`));
|
|
1095
|
+
return 1;
|
|
1096
|
+
}
|
|
1097
|
+
if (!ideas.length) {
|
|
1098
|
+
chrome(c.red(" no idea given."));
|
|
1099
|
+
chrome(c.dim(' wholestack make "a CRM for dog groomers" \xB7 wholestack make --batch ideas.txt'));
|
|
1100
|
+
return 1;
|
|
1101
|
+
}
|
|
1102
|
+
if (!process.env.ZETA_API_KEY?.trim()) {
|
|
1103
|
+
chrome(c.red(" login required."));
|
|
1104
|
+
chrome(c.dim(" run `wholestack login` \u2014 the factory uses your membership and build credits."));
|
|
1105
|
+
return 1;
|
|
1106
|
+
}
|
|
1107
|
+
const engine = webBaseUrl();
|
|
1108
|
+
const outRoot = resolve2(cwd2(), flags.out);
|
|
1109
|
+
const conc = Math.min(flags.concurrency, ideas.length);
|
|
1110
|
+
chrome(
|
|
1111
|
+
c.dim(
|
|
1112
|
+
` factory \xB7 ${ideas.length} app${ideas.length > 1 ? "s" : ""} \xB7 ${flags.boot ? "boot (live URL)" : `deliver \u2192 ${flags.out}/`} \xB7 ${flags.buildModel}${conc > 1 ? ` \xB7 ${conc}\xD7 parallel` : ""}`
|
|
1113
|
+
)
|
|
1114
|
+
);
|
|
1115
|
+
const render = (r, idx) => {
|
|
1116
|
+
if (flags.json) {
|
|
1117
|
+
stdout2.write(JSON.stringify(r) + "\n");
|
|
1118
|
+
return;
|
|
1119
|
+
}
|
|
1120
|
+
const tag = ideas.length > 1 ? c.dim(`[${idx + 1}/${ideas.length}] `) : "";
|
|
1121
|
+
if (r.ok) {
|
|
1122
|
+
const verdict = r.verdict === "SHIP" ? c.green("SHIP") : c.yellow(r.verdict ?? "?");
|
|
1123
|
+
const where = r.liveUrl ? c.cyan(r.liveUrl) : r.dir ? c.cyan(relOut(flags.out, outRoot, r.dir)) : "";
|
|
1124
|
+
const bits = [`${r.files ?? 0} files`, verdict, where].filter(Boolean);
|
|
1125
|
+
chrome(` ${tag}${c.green("\u2713")} ${r.slug} \xB7 ${bits.join(" \xB7 ")}`);
|
|
1126
|
+
} else {
|
|
1127
|
+
chrome(` ${tag}${c.red("\u2717")} ${r.slug} \xB7 ${r.error ?? "failed"}`);
|
|
1128
|
+
}
|
|
1129
|
+
};
|
|
1130
|
+
const results = await runPool(
|
|
1131
|
+
ideas,
|
|
1132
|
+
conc,
|
|
1133
|
+
(idea, i) => {
|
|
1134
|
+
if (conc === 1 && !flags.json) {
|
|
1135
|
+
const short = idea.length > 56 ? idea.slice(0, 55) + "\u2026" : idea;
|
|
1136
|
+
chrome(`${c.bold("\u2192")} ${short}`);
|
|
1137
|
+
}
|
|
1138
|
+
const tagged = (m) => flags.verbose ? chrome(c.dim(` \u21B3 ${conc > 1 ? `${slugify(idea)}: ` : ""}${m}`)) : void 0;
|
|
1139
|
+
return buildOne(engine, idea, flags, outRoot, tagged);
|
|
1140
|
+
},
|
|
1141
|
+
render
|
|
1142
|
+
);
|
|
1143
|
+
const failures = results.filter((r) => !r.ok).length;
|
|
1144
|
+
if (ideas.length > 1) {
|
|
1145
|
+
const made = ideas.length - failures;
|
|
1146
|
+
chrome(
|
|
1147
|
+
` ${c.bold("factory done")} \xB7 ${made}/${ideas.length} shipped` + (failures ? c.red(` \xB7 ${failures} failed`) : "")
|
|
1148
|
+
);
|
|
1149
|
+
}
|
|
1150
|
+
return failures ? 1 : 0;
|
|
1151
|
+
}
|
|
1152
|
+
function relOut(outFlag, outRoot, dest) {
|
|
1153
|
+
const tail = dest.startsWith(outRoot) ? dest.slice(outRoot.length).replace(/^[\\/]/, "") : dest;
|
|
1154
|
+
return join3(outFlag, tail);
|
|
1155
|
+
}
|
|
1156
|
+
|
|
849
1157
|
// src/learned-tools.ts
|
|
850
1158
|
import { tool as tool3 } from "ai";
|
|
851
1159
|
import { z as z3 } from "zod";
|
|
@@ -931,7 +1239,7 @@ function buildLearnedMemoryTools(deps) {
|
|
|
931
1239
|
}
|
|
932
1240
|
|
|
933
1241
|
// src/skills-cli.ts
|
|
934
|
-
import { stdout as
|
|
1242
|
+
import { stdout as stdout3 } from "process";
|
|
935
1243
|
async function runSkillsSubcommand(raw) {
|
|
936
1244
|
if (raw[0] !== "skills") return null;
|
|
937
1245
|
const rest = raw.slice(1);
|
|
@@ -951,7 +1259,7 @@ async function runSkillsSubcommand(raw) {
|
|
|
951
1259
|
return 1;
|
|
952
1260
|
}
|
|
953
1261
|
if (rest.includes("--json")) {
|
|
954
|
-
|
|
1262
|
+
stdout3.write(
|
|
955
1263
|
JSON.stringify(
|
|
956
1264
|
{
|
|
957
1265
|
name: skill.name,
|
|
@@ -974,7 +1282,7 @@ async function runSkillsSubcommand(raw) {
|
|
|
974
1282
|
}
|
|
975
1283
|
const skills = registry.list();
|
|
976
1284
|
if (rest.includes("--json")) {
|
|
977
|
-
|
|
1285
|
+
stdout3.write(
|
|
978
1286
|
JSON.stringify(
|
|
979
1287
|
skills.map((s) => ({
|
|
980
1288
|
name: s.name,
|
|
@@ -1005,7 +1313,7 @@ async function runSkillsSubcommand(raw) {
|
|
|
1005
1313
|
|
|
1006
1314
|
// src/images.ts
|
|
1007
1315
|
import { readFile as readFile3, stat as stat2 } from "fs/promises";
|
|
1008
|
-
import { resolve as
|
|
1316
|
+
import { resolve as resolve3, extname, relative as relative2, isAbsolute as isAbsolute2, join as join4 } from "path";
|
|
1009
1317
|
import { execFile } from "child_process";
|
|
1010
1318
|
import { tmpdir as tmpdir2, platform as platform2 } from "os";
|
|
1011
1319
|
var EXT_TO_MEDIA = {
|
|
@@ -1026,7 +1334,7 @@ function run(cmd, args) {
|
|
|
1026
1334
|
});
|
|
1027
1335
|
}
|
|
1028
1336
|
async function grabClipboardImage() {
|
|
1029
|
-
const out =
|
|
1337
|
+
const out = join4(tmpdir2(), `zeta-clip-${process.pid}-${process.hrtime.bigint()}.png`);
|
|
1030
1338
|
const os = platform2();
|
|
1031
1339
|
if (os === "darwin") {
|
|
1032
1340
|
const script = `set thePath to "${out}"
|
|
@@ -1060,7 +1368,7 @@ function imageTokens(message) {
|
|
|
1060
1368
|
for (let m = re.exec(message); m; m = re.exec(message)) out.add(m[1]);
|
|
1061
1369
|
return [...out];
|
|
1062
1370
|
}
|
|
1063
|
-
async function scanImages(message,
|
|
1371
|
+
async function scanImages(message, cwd4) {
|
|
1064
1372
|
const tokens = imageTokens(message);
|
|
1065
1373
|
const images = [];
|
|
1066
1374
|
const skipped = [];
|
|
@@ -1089,8 +1397,8 @@ async function scanImages(message, cwd3) {
|
|
|
1089
1397
|
}
|
|
1090
1398
|
}
|
|
1091
1399
|
for (const tok of tokens) {
|
|
1092
|
-
const raw = tok.startsWith("~/") ?
|
|
1093
|
-
const abs = isAbsolute2(raw) ? raw :
|
|
1400
|
+
const raw = tok.startsWith("~/") ? join4(process.env.HOME ?? "", tok.slice(2)) : tok;
|
|
1401
|
+
const abs = isAbsolute2(raw) ? raw : resolve3(cwd4, raw);
|
|
1094
1402
|
const mediaType = EXT_TO_MEDIA[extname(abs).toLowerCase()];
|
|
1095
1403
|
if (!mediaType) continue;
|
|
1096
1404
|
let bytes;
|
|
@@ -1101,7 +1409,7 @@ async function scanImages(message, cwd3) {
|
|
|
1101
1409
|
} catch {
|
|
1102
1410
|
continue;
|
|
1103
1411
|
}
|
|
1104
|
-
const label = isAbsolute2(raw) ? raw : relative2(
|
|
1412
|
+
const label = isAbsolute2(raw) ? raw : relative2(cwd4, abs);
|
|
1105
1413
|
if (bytes > PER_IMAGE_BYTES || total + bytes > TOTAL_BYTES) {
|
|
1106
1414
|
skipped.push(`${label} (${Math.round(bytes / 1024)}KB \u2014 over the size cap)`);
|
|
1107
1415
|
continue;
|
|
@@ -1197,7 +1505,7 @@ ${body}`);
|
|
|
1197
1505
|
|
|
1198
1506
|
// src/export.ts
|
|
1199
1507
|
import { writeFileSync } from "fs";
|
|
1200
|
-
import { resolve as
|
|
1508
|
+
import { resolve as resolve4 } from "path";
|
|
1201
1509
|
function renderContent(content) {
|
|
1202
1510
|
if (typeof content === "string") return content.trim();
|
|
1203
1511
|
if (!Array.isArray(content)) return "";
|
|
@@ -1235,32 +1543,32 @@ ${text}`;
|
|
|
1235
1543
|
${body}
|
|
1236
1544
|
`;
|
|
1237
1545
|
}
|
|
1238
|
-
function writeTranscript(messages, meta, file,
|
|
1239
|
-
const abs =
|
|
1546
|
+
function writeTranscript(messages, meta, file, cwd4) {
|
|
1547
|
+
const abs = resolve4(cwd4, file);
|
|
1240
1548
|
writeFileSync(abs, renderTranscript(messages, meta), "utf8");
|
|
1241
1549
|
return abs;
|
|
1242
1550
|
}
|
|
1243
1551
|
|
|
1244
1552
|
// src/cli.ts
|
|
1245
|
-
import { existsSync as
|
|
1246
|
-
import { join as
|
|
1553
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync4, writeFileSync as writeFileSync4 } from "fs";
|
|
1554
|
+
import { join as join7 } from "path";
|
|
1247
1555
|
|
|
1248
1556
|
// src/update-check.ts
|
|
1249
|
-
import { existsSync, mkdirSync, readFileSync, writeFileSync as writeFileSync2 } from "fs";
|
|
1250
|
-
import { join as
|
|
1557
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync2 } from "fs";
|
|
1558
|
+
import { join as join5 } from "path";
|
|
1251
1559
|
var PKG = "wholestack";
|
|
1252
|
-
var CACHE =
|
|
1560
|
+
var CACHE = join5(stateDir(), "update-check.json");
|
|
1253
1561
|
var DAY_MS = 24 * 60 * 60 * 1e3;
|
|
1254
1562
|
function readCache() {
|
|
1255
1563
|
try {
|
|
1256
|
-
return JSON.parse(
|
|
1564
|
+
return JSON.parse(readFileSync2(CACHE, "utf8"));
|
|
1257
1565
|
} catch {
|
|
1258
1566
|
return { lastCheck: 0, latest: null };
|
|
1259
1567
|
}
|
|
1260
1568
|
}
|
|
1261
1569
|
function writeCache(c2) {
|
|
1262
1570
|
try {
|
|
1263
|
-
|
|
1571
|
+
mkdirSync2(stateDir(), { recursive: true });
|
|
1264
1572
|
writeFileSync2(CACHE, JSON.stringify(c2));
|
|
1265
1573
|
} catch {
|
|
1266
1574
|
}
|
|
@@ -1276,7 +1584,7 @@ function isNewer(a, b) {
|
|
|
1276
1584
|
return false;
|
|
1277
1585
|
}
|
|
1278
1586
|
async function checkForUpdate(current) {
|
|
1279
|
-
if (process.env.ZETA_NO_UPDATE_CHECK || !
|
|
1587
|
+
if (process.env.ZETA_NO_UPDATE_CHECK || !existsSync2) return null;
|
|
1280
1588
|
const cache = readCache();
|
|
1281
1589
|
const fresh = Date.now() - cache.lastCheck < DAY_MS;
|
|
1282
1590
|
let latest = cache.latest;
|
|
@@ -1302,20 +1610,20 @@ async function checkForUpdate(current) {
|
|
|
1302
1610
|
}
|
|
1303
1611
|
|
|
1304
1612
|
// src/access.ts
|
|
1305
|
-
import { mkdirSync as
|
|
1306
|
-
import { join as
|
|
1307
|
-
var CACHE2 =
|
|
1613
|
+
import { mkdirSync as mkdirSync3, readFileSync as readFileSync3, rmSync, writeFileSync as writeFileSync3 } from "fs";
|
|
1614
|
+
import { join as join6 } from "path";
|
|
1615
|
+
var CACHE2 = join6(stateDir(), "access.json");
|
|
1308
1616
|
var TTL_MS = 60 * 60 * 1e3;
|
|
1309
1617
|
function readCache2() {
|
|
1310
1618
|
try {
|
|
1311
|
-
return JSON.parse(
|
|
1619
|
+
return JSON.parse(readFileSync3(CACHE2, "utf8"));
|
|
1312
1620
|
} catch {
|
|
1313
1621
|
return null;
|
|
1314
1622
|
}
|
|
1315
1623
|
}
|
|
1316
1624
|
function writeCache2(c2) {
|
|
1317
1625
|
try {
|
|
1318
|
-
|
|
1626
|
+
mkdirSync3(stateDir(), { recursive: true });
|
|
1319
1627
|
writeFileSync3(CACHE2, JSON.stringify(c2));
|
|
1320
1628
|
} catch {
|
|
1321
1629
|
}
|
|
@@ -1412,20 +1720,20 @@ function showPaywall(loggedIn, webUrl) {
|
|
|
1412
1720
|
}
|
|
1413
1721
|
|
|
1414
1722
|
// src/cli.ts
|
|
1415
|
-
import { readFileSync as
|
|
1723
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
1416
1724
|
import { basename as basename2, dirname as dirname2 } from "path";
|
|
1417
1725
|
import { fileURLToPath } from "url";
|
|
1418
1726
|
var VERSION = (() => {
|
|
1419
1727
|
try {
|
|
1420
1728
|
const here = dirname2(fileURLToPath(import.meta.url));
|
|
1421
|
-
return JSON.parse(
|
|
1729
|
+
return JSON.parse(readFileSync4(join7(here, "..", "package.json"), "utf8")).version;
|
|
1422
1730
|
} catch {
|
|
1423
1731
|
return "0.0.0";
|
|
1424
1732
|
}
|
|
1425
1733
|
})();
|
|
1426
1734
|
function gitBranch(dir) {
|
|
1427
1735
|
try {
|
|
1428
|
-
const head =
|
|
1736
|
+
const head = readFileSync4(join7(dir, ".git", "HEAD"), "utf8").trim();
|
|
1429
1737
|
const m = head.match(/ref:\s*refs\/heads\/(.+)$/);
|
|
1430
1738
|
return m ? m[1] : head.slice(0, 7);
|
|
1431
1739
|
} catch {
|
|
@@ -1480,13 +1788,19 @@ function parse(raw) {
|
|
|
1480
1788
|
a.prompt = rest.join(" ").trim();
|
|
1481
1789
|
return a;
|
|
1482
1790
|
}
|
|
1483
|
-
var
|
|
1791
|
+
var HELP2 = `${c.cyan("wholestack")} \u2014 conversational coding agent for the Wholestack engine ${c.dim("(alias: zeta)")}
|
|
1484
1792
|
|
|
1485
1793
|
${c.bold("Usage")}
|
|
1486
1794
|
wholestack start an interactive session
|
|
1487
1795
|
wholestack "build me a todo app" run one prompt and exit
|
|
1488
1796
|
wholestack -m zeta-g1-max "..." drive it with the most capable brain
|
|
1489
1797
|
|
|
1798
|
+
${c.bold("Factory")} ${c.dim("(strict \xB7 no chat \xB7 ~0 client tokens \xB7 one idea in, app out)")}
|
|
1799
|
+
wholestack make "a barbershop booking app" make one app \u2192 ./out/<slug>
|
|
1800
|
+
wholestack make --batch ideas.txt one app per line of a file
|
|
1801
|
+
wholestack make "..." --boot free live URL instead of code
|
|
1802
|
+
${c.dim("wholestack make --help for all flags (--out, --install, --style, --max, \u2026)")}
|
|
1803
|
+
|
|
1490
1804
|
${c.bold("Projects")} ${c.dim("(one spine across terminal, dashboard and the web IDE)")}
|
|
1491
1805
|
wholestack projects list your platform projects
|
|
1492
1806
|
wholestack pull <id> [dir] download a project's working tree
|
|
@@ -1728,7 +2042,7 @@ async function runProveSubcommand(raw) {
|
|
|
1728
2042
|
}
|
|
1729
2043
|
const data = await resp.json().catch(() => null);
|
|
1730
2044
|
if (wantsJson) {
|
|
1731
|
-
|
|
2045
|
+
stdout4.write(JSON.stringify(data) + "\n");
|
|
1732
2046
|
return data?.verdict === "SHIP" ? 0 : 1;
|
|
1733
2047
|
}
|
|
1734
2048
|
if (resp.status === 401 || resp.status === 402 || resp.status === 503 || !data) {
|
|
@@ -1744,14 +2058,14 @@ async function runProveSubcommand(raw) {
|
|
|
1744
2058
|
);
|
|
1745
2059
|
return data.verdict === "SHIP" ? 0 : 1;
|
|
1746
2060
|
}
|
|
1747
|
-
const path = rest.find((a) => !a.startsWith("-")) ??
|
|
1748
|
-
if (!
|
|
2061
|
+
const path = rest.find((a) => !a.startsWith("-")) ?? cwd3();
|
|
2062
|
+
if (!existsSync3(path)) {
|
|
1749
2063
|
line(c.red(` path not found: ${path}`));
|
|
1750
2064
|
return 1;
|
|
1751
2065
|
}
|
|
1752
2066
|
const result = proveLocalRepo(path);
|
|
1753
2067
|
if (wantsJson) {
|
|
1754
|
-
|
|
2068
|
+
stdout4.write(JSON.stringify(result) + "\n");
|
|
1755
2069
|
return result.verdict === "SHIP" ? 0 : 1;
|
|
1756
2070
|
}
|
|
1757
2071
|
line();
|
|
@@ -1796,7 +2110,7 @@ async function runSecuritySubcommand(raw) {
|
|
|
1796
2110
|
line();
|
|
1797
2111
|
line(c.cyan(` \u259F ShipGate ${verb}`) + c.dim(" \xB7 forge \xB7 slither \xB7 firewall \xB7 halmos"));
|
|
1798
2112
|
line();
|
|
1799
|
-
const r = await runProver(proverArgs, { cwd:
|
|
2113
|
+
const r = await runProver(proverArgs, { cwd: cwd3(), inherit: true });
|
|
1800
2114
|
if (r.missing) {
|
|
1801
2115
|
line(c.red(` ${r.out}`));
|
|
1802
2116
|
return 1;
|
|
@@ -1808,12 +2122,12 @@ async function runSecuritySubcommand(raw) {
|
|
|
1808
2122
|
function maybeYoloNotice() {
|
|
1809
2123
|
try {
|
|
1810
2124
|
const dir = stateDir();
|
|
1811
|
-
const marker =
|
|
1812
|
-
if (
|
|
2125
|
+
const marker = join7(dir, "yolo-notice-seen");
|
|
2126
|
+
if (existsSync3(marker)) return;
|
|
1813
2127
|
line(
|
|
1814
2128
|
" " + c.yellow("\u26A1 yolo mode") + c.dim(" \u2014 actions run without confirmation. ") + c.cyan("/mode default") + c.dim(" to require approvals \xB7 /undo reverts.") + "\n"
|
|
1815
2129
|
);
|
|
1816
|
-
|
|
2130
|
+
mkdirSync4(dir, { recursive: true });
|
|
1817
2131
|
writeFileSync4(marker, (/* @__PURE__ */ new Date()).toISOString());
|
|
1818
2132
|
} catch {
|
|
1819
2133
|
}
|
|
@@ -1869,7 +2183,7 @@ async function runLogin(raw) {
|
|
|
1869
2183
|
line(c.red(" usage: wholestack login --member <key> | --brain <key> | --build <key>"));
|
|
1870
2184
|
return 1;
|
|
1871
2185
|
}
|
|
1872
|
-
const rl = createInterface({ input: stdin, output:
|
|
2186
|
+
const rl = createInterface({ input: stdin, output: stdout4 });
|
|
1873
2187
|
if (!name) {
|
|
1874
2188
|
const which = (await rl.question(c.cyan(" key for [member/brain/engine]: "))).trim().toLowerCase();
|
|
1875
2189
|
name = which.startsWith("m") ? "ZETA_API_KEY" : "CEREBRAS_API_KEY";
|
|
@@ -2051,7 +2365,7 @@ async function runLaunchSubcommand(raw) {
|
|
|
2051
2365
|
return 1;
|
|
2052
2366
|
}
|
|
2053
2367
|
if (wantsJson) {
|
|
2054
|
-
|
|
2368
|
+
stdout4.write(JSON.stringify(r2.plan, null, 2) + "\n");
|
|
2055
2369
|
return 0;
|
|
2056
2370
|
}
|
|
2057
2371
|
for (const ln of renderGtmPlanLines(r2.plan)) line(ln);
|
|
@@ -2067,7 +2381,7 @@ async function runLaunchSubcommand(raw) {
|
|
|
2067
2381
|
return 1;
|
|
2068
2382
|
}
|
|
2069
2383
|
if (wantsJson) {
|
|
2070
|
-
|
|
2384
|
+
stdout4.write(JSON.stringify(r.kit, null, 2) + "\n");
|
|
2071
2385
|
return 0;
|
|
2072
2386
|
}
|
|
2073
2387
|
for (const ln of renderLaunchKitLines(r.kit)) line(ln);
|
|
@@ -2093,7 +2407,7 @@ async function runHqSubcommand(raw) {
|
|
|
2093
2407
|
line(c.red(` \u2717 ${r2.error ?? "no document produced"}`));
|
|
2094
2408
|
return 1;
|
|
2095
2409
|
}
|
|
2096
|
-
|
|
2410
|
+
stdout4.write(r2.markdown.trimEnd() + "\n");
|
|
2097
2411
|
return 0;
|
|
2098
2412
|
}
|
|
2099
2413
|
if (verb === "styles") {
|
|
@@ -2110,7 +2424,7 @@ async function runHqSubcommand(raw) {
|
|
|
2110
2424
|
return 1;
|
|
2111
2425
|
}
|
|
2112
2426
|
if (wantsJson) {
|
|
2113
|
-
|
|
2427
|
+
stdout4.write(JSON.stringify(data, null, 2) + "\n");
|
|
2114
2428
|
return 0;
|
|
2115
2429
|
}
|
|
2116
2430
|
if (data.recommended) {
|
|
@@ -2138,7 +2452,7 @@ async function runHqSubcommand(raw) {
|
|
|
2138
2452
|
return 1;
|
|
2139
2453
|
}
|
|
2140
2454
|
if (wantsJson) {
|
|
2141
|
-
|
|
2455
|
+
stdout4.write(JSON.stringify(r2.metrics, null, 2) + "\n");
|
|
2142
2456
|
return 0;
|
|
2143
2457
|
}
|
|
2144
2458
|
for (const ln of renderMetricsLines(r2.metrics)) line(ln);
|
|
@@ -2166,7 +2480,7 @@ async function runHqSubcommand(raw) {
|
|
|
2166
2480
|
return 1;
|
|
2167
2481
|
}
|
|
2168
2482
|
if (wantsJson) {
|
|
2169
|
-
|
|
2483
|
+
stdout4.write(JSON.stringify(r2.businesses ?? [], null, 2) + "\n");
|
|
2170
2484
|
return 0;
|
|
2171
2485
|
}
|
|
2172
2486
|
const rows = r2.businesses ?? [];
|
|
@@ -2189,7 +2503,7 @@ async function runHqSubcommand(raw) {
|
|
|
2189
2503
|
line(c.red(` \u2717 ${r.error}`));
|
|
2190
2504
|
return 1;
|
|
2191
2505
|
}
|
|
2192
|
-
|
|
2506
|
+
stdout4.write(JSON.stringify({ business: r.business, readiness: r.readiness }, null, 2) + "\n");
|
|
2193
2507
|
return 0;
|
|
2194
2508
|
}
|
|
2195
2509
|
var EMPTY_PLUGINS = {
|
|
@@ -2220,6 +2534,8 @@ async function main() {
|
|
|
2220
2534
|
const rawArgs = argv.slice(2);
|
|
2221
2535
|
const loggedIn = await runLogin(rawArgs);
|
|
2222
2536
|
if (loggedIn !== null) exit(loggedIn);
|
|
2537
|
+
const made = await runMakeSubcommand(rawArgs);
|
|
2538
|
+
if (made !== null) exit(made);
|
|
2223
2539
|
const gh = await runGithubSubcommand(rawArgs);
|
|
2224
2540
|
if (gh !== null) exit(gh);
|
|
2225
2541
|
const provePath = await runProveSubcommand(rawArgs);
|
|
@@ -2246,7 +2562,7 @@ async function main() {
|
|
|
2246
2562
|
return;
|
|
2247
2563
|
}
|
|
2248
2564
|
if (args.help) {
|
|
2249
|
-
line(
|
|
2565
|
+
line(HELP2);
|
|
2250
2566
|
return;
|
|
2251
2567
|
}
|
|
2252
2568
|
{
|
|
@@ -2260,7 +2576,7 @@ async function main() {
|
|
|
2260
2576
|
token ? "Your session expired." : "The agent is free \u2014 make, edit & preview unlimited. Sign in to start."
|
|
2261
2577
|
)
|
|
2262
2578
|
);
|
|
2263
|
-
const rl = createInterface({ input: stdin, output:
|
|
2579
|
+
const rl = createInterface({ input: stdin, output: stdout4 });
|
|
2264
2580
|
const ans = (await rl.question(
|
|
2265
2581
|
" " + c.dim("Open the browser to sign in with Google? ") + c.dim("[Y/n] ")
|
|
2266
2582
|
)).trim().toLowerCase();
|
|
@@ -2312,7 +2628,7 @@ async function main() {
|
|
|
2312
2628
|
}
|
|
2313
2629
|
const isTty = !!stdin.isTTY;
|
|
2314
2630
|
const oneShot = args.prompt.length > 0;
|
|
2315
|
-
const workdir =
|
|
2631
|
+
const workdir = cwd3();
|
|
2316
2632
|
const persistedMode = isPermissionMode(
|
|
2317
2633
|
process.env.ZETA_PERMISSION_MODE
|
|
2318
2634
|
) ? process.env.ZETA_PERMISSION_MODE : void 0;
|
package/dist/index.d.ts
CHANGED
|
@@ -173,6 +173,12 @@ interface BuildResult {
|
|
|
173
173
|
error?: string;
|
|
174
174
|
buildId?: unknown;
|
|
175
175
|
verdict?: "SHIP" | "NO_SHIP";
|
|
176
|
+
/**
|
|
177
|
+
* True when `verdict` is PROVISIONAL — a deferProofs build that shipped fast with its
|
|
178
|
+
* runtime proofs running in a durable background job. The CLI renders "proving…" and
|
|
179
|
+
* polls {@link pollProofStatus} to flip to the real verdict.
|
|
180
|
+
*/
|
|
181
|
+
proofPending?: boolean;
|
|
176
182
|
themeId?: unknown;
|
|
177
183
|
fileCount?: number;
|
|
178
184
|
spec?: string | null;
|
|
@@ -491,6 +497,29 @@ declare function buildTools(ctx: ToolContext): {
|
|
|
491
497
|
error?: string;
|
|
492
498
|
buildId?: unknown;
|
|
493
499
|
verdict?: "SHIP" | "NO_SHIP";
|
|
500
|
+
proofPending?: boolean;
|
|
501
|
+
themeId?: unknown;
|
|
502
|
+
fileCount?: number;
|
|
503
|
+
spec?: string | null;
|
|
504
|
+
verifyErrors?: string[];
|
|
505
|
+
fileList?: (string | null | undefined)[];
|
|
506
|
+
paywalled?: boolean;
|
|
507
|
+
upgradeUrl?: string;
|
|
508
|
+
liveUrl?: undefined;
|
|
509
|
+
files?: undefined;
|
|
510
|
+
loc?: undefined;
|
|
511
|
+
trust?: undefined;
|
|
512
|
+
note?: undefined;
|
|
513
|
+
} | {
|
|
514
|
+
delivered: DeliverResult;
|
|
515
|
+
dir: string;
|
|
516
|
+
installed: boolean;
|
|
517
|
+
nextStep: string;
|
|
518
|
+
verdict: string;
|
|
519
|
+
proofPending: boolean;
|
|
520
|
+
ok: boolean;
|
|
521
|
+
error?: string;
|
|
522
|
+
buildId?: unknown;
|
|
494
523
|
themeId?: unknown;
|
|
495
524
|
fileCount?: number;
|
|
496
525
|
spec?: string | null;
|
|
@@ -510,6 +539,45 @@ declare function buildTools(ctx: ToolContext): {
|
|
|
510
539
|
error?: string;
|
|
511
540
|
buildId?: unknown;
|
|
512
541
|
verdict?: "SHIP" | "NO_SHIP";
|
|
542
|
+
proofPending?: boolean;
|
|
543
|
+
themeId?: unknown;
|
|
544
|
+
fileCount?: number;
|
|
545
|
+
spec?: string | null;
|
|
546
|
+
verifyErrors?: string[];
|
|
547
|
+
fileList?: (string | null | undefined)[];
|
|
548
|
+
paywalled?: boolean;
|
|
549
|
+
upgradeUrl?: string;
|
|
550
|
+
liveUrl?: undefined;
|
|
551
|
+
files?: undefined;
|
|
552
|
+
loc?: undefined;
|
|
553
|
+
trust?: undefined;
|
|
554
|
+
note?: undefined;
|
|
555
|
+
} | {
|
|
556
|
+
delivered: DeliverResult;
|
|
557
|
+
dir: string;
|
|
558
|
+
verdict: string;
|
|
559
|
+
proofPending: boolean;
|
|
560
|
+
ok: boolean;
|
|
561
|
+
error?: string;
|
|
562
|
+
buildId?: unknown;
|
|
563
|
+
themeId?: unknown;
|
|
564
|
+
fileCount?: number;
|
|
565
|
+
spec?: string | null;
|
|
566
|
+
verifyErrors?: string[];
|
|
567
|
+
fileList?: (string | null | undefined)[];
|
|
568
|
+
paywalled?: boolean;
|
|
569
|
+
upgradeUrl?: string;
|
|
570
|
+
liveUrl?: undefined;
|
|
571
|
+
files?: undefined;
|
|
572
|
+
loc?: undefined;
|
|
573
|
+
trust?: undefined;
|
|
574
|
+
note?: undefined;
|
|
575
|
+
} | {
|
|
576
|
+
verdict: string;
|
|
577
|
+
proofPending: boolean;
|
|
578
|
+
ok: boolean;
|
|
579
|
+
error?: string;
|
|
580
|
+
buildId?: unknown;
|
|
513
581
|
themeId?: unknown;
|
|
514
582
|
fileCount?: number;
|
|
515
583
|
spec?: string | null;
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wholestack",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"description": "Wholestack — a pro-grade conversational terminal agent for the Wholestack codegen engine. Talk to it in plain language: it writes ISL, generates full-stack or Solidity apps, and proves them with ShipGate. Browser login, membership-gated builds, slash commands, sessions, plan mode, diffs, MCP, plugins.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|