wholestack 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-KJ5INI3M.js → chunk-NHABZZTE.js} +788 -186
- package/dist/cli.js +443 -61
- package/dist/index.d.ts +249 -13
- package/dist/index.js +1 -1
- package/package.json +3 -3
|
@@ -590,6 +590,424 @@ async function collectLocalFiles(dir) {
|
|
|
590
590
|
return { files, skipped };
|
|
591
591
|
}
|
|
592
592
|
|
|
593
|
+
// src/config.ts
|
|
594
|
+
import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync as mkdirSync2, existsSync as existsSync2, chmodSync, renameSync } from "fs";
|
|
595
|
+
import { homedir } from "os";
|
|
596
|
+
import { join as join2 } from "path";
|
|
597
|
+
var LEGACY_DIR = join2(homedir(), ".zeta-g");
|
|
598
|
+
var STATE_DIR = join2(homedir(), ".wholestack");
|
|
599
|
+
try {
|
|
600
|
+
if (existsSync2(LEGACY_DIR) && !existsSync2(STATE_DIR)) renameSync(LEGACY_DIR, STATE_DIR);
|
|
601
|
+
} catch {
|
|
602
|
+
}
|
|
603
|
+
function stateDir() {
|
|
604
|
+
return STATE_DIR;
|
|
605
|
+
}
|
|
606
|
+
function webBaseUrl() {
|
|
607
|
+
return process.env.ZETA_WEB_URL?.trim() || process.env.ZETA_API_URL?.trim() || "https://wholestack.ai";
|
|
608
|
+
}
|
|
609
|
+
function projectDirs(cwd2) {
|
|
610
|
+
return [join2(cwd2, ".wholestack"), join2(cwd2, ".zeta-g")];
|
|
611
|
+
}
|
|
612
|
+
var CONFIG_DIR = STATE_DIR;
|
|
613
|
+
var CONFIG_PATH = join2(CONFIG_DIR, "config.json");
|
|
614
|
+
function parseDotenv(text) {
|
|
615
|
+
const out = {};
|
|
616
|
+
for (const raw of text.split("\n")) {
|
|
617
|
+
const l = raw.trim();
|
|
618
|
+
if (!l || l.startsWith("#")) continue;
|
|
619
|
+
const eq = l.indexOf("=");
|
|
620
|
+
if (eq < 0) continue;
|
|
621
|
+
const k = l.slice(0, eq).trim();
|
|
622
|
+
let v = l.slice(eq + 1).trim();
|
|
623
|
+
if (v.startsWith('"') && v.endsWith('"') || v.startsWith("'") && v.endsWith("'")) {
|
|
624
|
+
v = v.slice(1, -1);
|
|
625
|
+
}
|
|
626
|
+
if (k) out[k] = v;
|
|
627
|
+
}
|
|
628
|
+
return out;
|
|
629
|
+
}
|
|
630
|
+
function fill(src) {
|
|
631
|
+
for (const [k, v] of Object.entries(src)) {
|
|
632
|
+
if (v && process.env[k] === void 0) process.env[k] = v;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
function loadStoredEnv() {
|
|
636
|
+
const localEnv = join2(process.cwd(), ".env");
|
|
637
|
+
if (existsSync2(localEnv)) {
|
|
638
|
+
try {
|
|
639
|
+
fill(parseDotenv(readFileSync2(localEnv, "utf8")));
|
|
640
|
+
} catch {
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
if (existsSync2(CONFIG_PATH)) {
|
|
644
|
+
try {
|
|
645
|
+
const json = JSON.parse(readFileSync2(CONFIG_PATH, "utf8"));
|
|
646
|
+
const flat = {};
|
|
647
|
+
for (const [k, v] of Object.entries(json)) if (typeof v === "string") flat[k] = v;
|
|
648
|
+
fill(flat);
|
|
649
|
+
} catch {
|
|
650
|
+
}
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
function saveKey(name, value) {
|
|
654
|
+
mkdirSync2(CONFIG_DIR, { recursive: true });
|
|
655
|
+
let current = {};
|
|
656
|
+
if (existsSync2(CONFIG_PATH)) {
|
|
657
|
+
try {
|
|
658
|
+
current = JSON.parse(readFileSync2(CONFIG_PATH, "utf8"));
|
|
659
|
+
} catch {
|
|
660
|
+
current = {};
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
current[name] = value;
|
|
664
|
+
writeFileSync2(CONFIG_PATH, JSON.stringify(current, null, 2) + "\n", { mode: 384 });
|
|
665
|
+
chmodSync(CONFIG_PATH, 384);
|
|
666
|
+
return CONFIG_PATH;
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
// src/volition.ts
|
|
670
|
+
import { cwd, stdout } from "process";
|
|
671
|
+
function apiBase() {
|
|
672
|
+
return webBaseUrl().replace(/\/$/, "");
|
|
673
|
+
}
|
|
674
|
+
function jsonOut(obj) {
|
|
675
|
+
stdout.write(JSON.stringify(obj) + "\n");
|
|
676
|
+
}
|
|
677
|
+
async function resolveVolitionProject(nameOrId) {
|
|
678
|
+
const r = await apiJson(`${apiBase()}/api/projects`);
|
|
679
|
+
if (!r.ok) return { ok: false, error: r.error };
|
|
680
|
+
const projects = r.data.projects ?? [];
|
|
681
|
+
const byId = projects.find((p) => p.id === nameOrId);
|
|
682
|
+
if (byId) return { ok: true, project: byId };
|
|
683
|
+
const needle = nameOrId.trim().toLowerCase();
|
|
684
|
+
const byName = projects.find((p) => p.name?.trim().toLowerCase() === needle);
|
|
685
|
+
if (byName) return { ok: true, project: byName };
|
|
686
|
+
return { ok: false, error: `no project matches "${nameOrId}"` };
|
|
687
|
+
}
|
|
688
|
+
async function createVolitionProject(name, description) {
|
|
689
|
+
const r = await apiJson(
|
|
690
|
+
`${apiBase()}/api/projects`,
|
|
691
|
+
{
|
|
692
|
+
method: "POST",
|
|
693
|
+
body: JSON.stringify({
|
|
694
|
+
name,
|
|
695
|
+
description: description?.trim() || "Business handed to the Volition crew from the terminal"
|
|
696
|
+
})
|
|
697
|
+
}
|
|
698
|
+
);
|
|
699
|
+
if (!r.ok) return { ok: false, error: r.error };
|
|
700
|
+
const id = r.data.project?.id;
|
|
701
|
+
if (!id) return { ok: false, error: r.data.error ?? "project create returned no id" };
|
|
702
|
+
return { ok: true, id };
|
|
703
|
+
}
|
|
704
|
+
async function activateVolition(projectId, opts = {}) {
|
|
705
|
+
return apiJson(
|
|
706
|
+
`${apiBase()}/api/projects/${encodeURIComponent(projectId)}/volition/activate`,
|
|
707
|
+
{ method: "POST", body: JSON.stringify({ live: opts.live === true }) }
|
|
708
|
+
);
|
|
709
|
+
}
|
|
710
|
+
async function volitionStatus(projectId) {
|
|
711
|
+
return apiJson(
|
|
712
|
+
`${apiBase()}/api/projects/${encodeURIComponent(projectId)}/volition`
|
|
713
|
+
);
|
|
714
|
+
}
|
|
715
|
+
async function volitionActions(projectId, limit = 20) {
|
|
716
|
+
const r = await apiJson(
|
|
717
|
+
`${apiBase()}/api/projects/${encodeURIComponent(projectId)}/volition/actions?limit=${limit}`
|
|
718
|
+
);
|
|
719
|
+
if (!r.ok) return { ok: false, error: r.error, status: r.status };
|
|
720
|
+
return { ok: true, actions: r.data.actions ?? [] };
|
|
721
|
+
}
|
|
722
|
+
async function volitionRunNow(projectId) {
|
|
723
|
+
return apiJson(
|
|
724
|
+
`${apiBase()}/api/projects/${encodeURIComponent(projectId)}/volition/run`,
|
|
725
|
+
{ method: "POST", body: JSON.stringify({}) }
|
|
726
|
+
);
|
|
727
|
+
}
|
|
728
|
+
async function launchVolition(input2) {
|
|
729
|
+
const step = input2.onStep ?? (() => {
|
|
730
|
+
});
|
|
731
|
+
let projectId;
|
|
732
|
+
let created = false;
|
|
733
|
+
const target = input2.target?.trim();
|
|
734
|
+
if (target) {
|
|
735
|
+
const found = await resolveVolitionProject(target);
|
|
736
|
+
if (found.ok) {
|
|
737
|
+
projectId = found.project.id;
|
|
738
|
+
step(`project: ${found.project.name ?? projectId}`);
|
|
739
|
+
} else {
|
|
740
|
+
step(`creating project "${target}"`);
|
|
741
|
+
const made = await createVolitionProject(target, input2.description);
|
|
742
|
+
if (!made.ok) return { ok: false, error: made.error };
|
|
743
|
+
projectId = made.id;
|
|
744
|
+
created = true;
|
|
745
|
+
}
|
|
746
|
+
} else {
|
|
747
|
+
projectId = readProjectLink(input2.cwd ?? cwd())?.projectId;
|
|
748
|
+
if (!projectId) {
|
|
749
|
+
return {
|
|
750
|
+
ok: false,
|
|
751
|
+
error: 'no target \u2014 pass a business name or project id (wholestack volition "my business"), or run inside a linked project directory.'
|
|
752
|
+
};
|
|
753
|
+
}
|
|
754
|
+
step(`linked project: ${projectId}`);
|
|
755
|
+
}
|
|
756
|
+
step(input2.live ? "activating crew (LIVE \u2014 real external actions)" : "activating crew (sandbox)");
|
|
757
|
+
const r = await activateVolition(projectId, { live: input2.live });
|
|
758
|
+
const consoleUrl = `${apiBase()}/volition/${projectId}`;
|
|
759
|
+
if (!r.ok) {
|
|
760
|
+
return { ok: false, projectId, consoleUrl, status: r.status, activation: r.data, error: r.error };
|
|
761
|
+
}
|
|
762
|
+
if (created && input2.cwd) {
|
|
763
|
+
try {
|
|
764
|
+
writeProjectLink(input2.cwd, { projectId });
|
|
765
|
+
} catch {
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
return { ok: true, projectId, consoleUrl, activation: r.data };
|
|
769
|
+
}
|
|
770
|
+
function renderVerdictHelp(status, a) {
|
|
771
|
+
const out = [];
|
|
772
|
+
if (status === 401) {
|
|
773
|
+
out.push(c.red(" \u2717 sign in first \u2014 run `wholestack login`."));
|
|
774
|
+
} else if (status === 402) {
|
|
775
|
+
const price = a?.priceUsdCents ? `$${(a.priceUsdCents / 100).toFixed(0)}/mo` : "$99/mo";
|
|
776
|
+
out.push(c.red(` \u2717 Operation Volition is a ${price} add-on.`));
|
|
777
|
+
out.push(c.dim(` subscribe: ${apiBase()}${a?.checkoutPath ?? "/api/billing/addons/volition/checkout"}`));
|
|
778
|
+
} else if (status === 503) {
|
|
779
|
+
out.push(c.red(" \u2717 Volition inference is not configured."));
|
|
780
|
+
out.push(c.dim(" add an OpenRouter key in account secrets (web \u2192 Account \u2192 Secrets)."));
|
|
781
|
+
}
|
|
782
|
+
return out;
|
|
783
|
+
}
|
|
784
|
+
function renderActivation(projectId, consoleUrl, a) {
|
|
785
|
+
const out = [];
|
|
786
|
+
out.push(c.green(" \u2713 Volition crew activated") + (a.live ? c.red(" LIVE") : c.dim(" sandbox")));
|
|
787
|
+
if (a.firstRun?.runId) {
|
|
788
|
+
out.push(c.dim(` first cycle: ${a.firstRun.runId}`));
|
|
789
|
+
if (a.firstRun.summary) out.push(c.dim(` ${a.firstRun.summary}`));
|
|
790
|
+
} else {
|
|
791
|
+
out.push(c.dim(" first cycle queued \u2014 the crew runs on the hourly heartbeat."));
|
|
792
|
+
}
|
|
793
|
+
out.push(c.cyan(` console: ${consoleUrl}`));
|
|
794
|
+
if (!a.live) {
|
|
795
|
+
out.push(c.dim(" sandbox = external actions are simulated. Re-run with --live to go real."));
|
|
796
|
+
}
|
|
797
|
+
return out;
|
|
798
|
+
}
|
|
799
|
+
var VERBS = /* @__PURE__ */ new Set(["status", "actions", "run", "launch", "activate", "start"]);
|
|
800
|
+
async function runVolitionSubcommand(raw) {
|
|
801
|
+
if (raw[0] !== "volition") return null;
|
|
802
|
+
const rest = raw.slice(1);
|
|
803
|
+
const wantsJson = rest.includes("--json");
|
|
804
|
+
const live = rest.includes("--live");
|
|
805
|
+
const descIdx = rest.indexOf("--desc");
|
|
806
|
+
const description = descIdx >= 0 ? rest[descIdx + 1] : void 0;
|
|
807
|
+
const limitIdx = rest.indexOf("--limit");
|
|
808
|
+
const limit = limitIdx >= 0 ? Math.max(1, Number(rest[limitIdx + 1]) || 20) : 20;
|
|
809
|
+
const flagValueIdx = new Set(
|
|
810
|
+
[descIdx >= 0 ? descIdx + 1 : -1, limitIdx >= 0 ? limitIdx + 1 : -1].filter((i) => i >= 0)
|
|
811
|
+
);
|
|
812
|
+
const positional = rest.filter((a, i) => !a.startsWith("-") && !flagValueIdx.has(i));
|
|
813
|
+
if (!process.env.ZETA_API_KEY?.trim()) {
|
|
814
|
+
line(c.red(" login required \u2014 run `wholestack login` first."));
|
|
815
|
+
return 1;
|
|
816
|
+
}
|
|
817
|
+
const verb = VERBS.has(positional[0] ?? "") ? positional[0] : "launch";
|
|
818
|
+
const target = verb === "launch" && !VERBS.has(positional[0] ?? "") ? positional.join(" ") || void 0 : positional.slice(1).join(" ") || void 0;
|
|
819
|
+
const projectIdOr = async () => {
|
|
820
|
+
if (target) {
|
|
821
|
+
const found = await resolveVolitionProject(target);
|
|
822
|
+
if (found.ok) return found.project.id;
|
|
823
|
+
line(c.red(` \u2717 ${found.error}`));
|
|
824
|
+
return null;
|
|
825
|
+
}
|
|
826
|
+
const linked = readProjectLink(cwd())?.projectId;
|
|
827
|
+
if (!linked) {
|
|
828
|
+
line(c.red(" no project \u2014 pass an id/name or run inside a linked project."));
|
|
829
|
+
return null;
|
|
830
|
+
}
|
|
831
|
+
return linked;
|
|
832
|
+
};
|
|
833
|
+
if (verb === "status") {
|
|
834
|
+
const id = await projectIdOr();
|
|
835
|
+
if (!id) return 1;
|
|
836
|
+
const r = await volitionStatus(id);
|
|
837
|
+
if (wantsJson) {
|
|
838
|
+
jsonOut(r.ok ? { ok: true, ...r.data } : { ok: false, error: r.error });
|
|
839
|
+
return r.ok ? 0 : 1;
|
|
840
|
+
}
|
|
841
|
+
line("");
|
|
842
|
+
if (!r.ok) {
|
|
843
|
+
line(c.red(` \u2717 ${r.error}`));
|
|
844
|
+
return 1;
|
|
845
|
+
}
|
|
846
|
+
const op = r.data.operator ?? {};
|
|
847
|
+
const on = op.enabled === true;
|
|
848
|
+
line(
|
|
849
|
+
" " + (on ? c.green("\u25CF operating") : c.dim("\u25CB idle")) + (op.sandbox === false ? c.red(" LIVE") : c.dim(" sandbox"))
|
|
850
|
+
);
|
|
851
|
+
const counts = r.data.actionCounts ?? {};
|
|
852
|
+
const countStr = Object.entries(counts).map(([k, v]) => `${k} ${v}`).join(" \xB7 ");
|
|
853
|
+
if (countStr) line(c.dim(` actions: ${countStr}`));
|
|
854
|
+
for (const run of (r.data.recentRuns ?? []).slice(0, 5)) {
|
|
855
|
+
line(
|
|
856
|
+
c.dim(
|
|
857
|
+
` ${run.status === "completed" ? "\u2713" : "\u2022"} ${run.runId ?? "run"} ${run.trigger ?? ""} ${run.summary ?? ""}`.trimEnd()
|
|
858
|
+
)
|
|
859
|
+
);
|
|
860
|
+
}
|
|
861
|
+
line(c.cyan(` console: ${apiBase()}/volition/${id}`));
|
|
862
|
+
return 0;
|
|
863
|
+
}
|
|
864
|
+
if (verb === "actions") {
|
|
865
|
+
const id = await projectIdOr();
|
|
866
|
+
if (!id) return 1;
|
|
867
|
+
const r = await volitionActions(id, limit);
|
|
868
|
+
if (wantsJson) {
|
|
869
|
+
jsonOut(r.ok ? { ok: true, actions: r.actions } : { ok: false, error: r.error });
|
|
870
|
+
return r.ok ? 0 : 1;
|
|
871
|
+
}
|
|
872
|
+
line("");
|
|
873
|
+
if (!r.ok) {
|
|
874
|
+
line(c.red(` \u2717 ${r.error}`));
|
|
875
|
+
return 1;
|
|
876
|
+
}
|
|
877
|
+
if (r.actions.length === 0) {
|
|
878
|
+
line(c.dim(" no actions yet \u2014 run a cycle (`wholestack volition run`)."));
|
|
879
|
+
return 0;
|
|
880
|
+
}
|
|
881
|
+
for (const a of r.actions) {
|
|
882
|
+
const mark = a.status === "executed" ? c.green("\u2713") : a.status === "blocked" ? c.red("\u2717") : c.cyan("\u2022");
|
|
883
|
+
line(
|
|
884
|
+
` ${mark} ${c.bold(a.agent ?? "agent")} ${c.dim(a.kind ?? "")} ${a.summary ?? ""}`.trimEnd()
|
|
885
|
+
);
|
|
886
|
+
const proof = a.proofHash ? ` proof ${a.proofHash.slice(0, 12)}\u2026` : "";
|
|
887
|
+
line(c.dim(` ${a.status ?? ""}${a.verdict ? ` \xB7 ${a.verdict}` : ""}${proof}`));
|
|
888
|
+
}
|
|
889
|
+
return 0;
|
|
890
|
+
}
|
|
891
|
+
if (verb === "run") {
|
|
892
|
+
const id = await projectIdOr();
|
|
893
|
+
if (!id) return 1;
|
|
894
|
+
line(c.dim(" running one cycle\u2026"));
|
|
895
|
+
const r = await volitionRunNow(id);
|
|
896
|
+
if (wantsJson) {
|
|
897
|
+
jsonOut(r.ok ? { ok: true, ...r.data } : { ok: false, error: r.error });
|
|
898
|
+
return r.ok ? 0 : 1;
|
|
899
|
+
}
|
|
900
|
+
if (!r.ok) {
|
|
901
|
+
line(c.red(` \u2717 ${r.error}`));
|
|
902
|
+
return 1;
|
|
903
|
+
}
|
|
904
|
+
line(c.green(` \u2713 cycle ${r.data.runId ?? "done"}`));
|
|
905
|
+
if (r.data.summary) line(c.dim(` ${r.data.summary}`));
|
|
906
|
+
return 0;
|
|
907
|
+
}
|
|
908
|
+
const result = await launchVolition({
|
|
909
|
+
target,
|
|
910
|
+
live,
|
|
911
|
+
description,
|
|
912
|
+
cwd: cwd(),
|
|
913
|
+
onStep: (s) => line(c.dim(` ${s}`))
|
|
914
|
+
});
|
|
915
|
+
if (wantsJson) {
|
|
916
|
+
jsonOut(
|
|
917
|
+
result.ok ? { ok: true, projectId: result.projectId, consoleUrl: result.consoleUrl, ...result.activation } : { ok: false, error: result.error, status: result.status, ...result.activation }
|
|
918
|
+
);
|
|
919
|
+
return result.ok ? 0 : 1;
|
|
920
|
+
}
|
|
921
|
+
line("");
|
|
922
|
+
if (!result.ok) {
|
|
923
|
+
const help = renderVerdictHelp(result.status, result.activation);
|
|
924
|
+
if (help.length > 0) for (const h of help) line(h);
|
|
925
|
+
else line(c.red(` \u2717 ${result.error}`));
|
|
926
|
+
return 1;
|
|
927
|
+
}
|
|
928
|
+
for (const l of renderActivation(result.projectId, result.consoleUrl, result.activation ?? {}))
|
|
929
|
+
line(l);
|
|
930
|
+
return 0;
|
|
931
|
+
}
|
|
932
|
+
var volitionCommands = [
|
|
933
|
+
{
|
|
934
|
+
name: "volition",
|
|
935
|
+
aliases: ["crew"],
|
|
936
|
+
summary: "hand this business to the autonomous Volition crew",
|
|
937
|
+
source: "builtin",
|
|
938
|
+
run: async (ctx) => {
|
|
939
|
+
const arg = ctx.args.trim();
|
|
940
|
+
const live = /(^|\s)--live(\s|$)/.test(arg);
|
|
941
|
+
const target = arg.replace(/(^|\s)--live(\s|$)/g, " ").trim() || void 0;
|
|
942
|
+
const result = await launchVolition({
|
|
943
|
+
target,
|
|
944
|
+
live,
|
|
945
|
+
cwd: ctx.cwd,
|
|
946
|
+
onStep: (s) => ctx.print(" " + c.dim(s))
|
|
947
|
+
});
|
|
948
|
+
ctx.print();
|
|
949
|
+
if (!result.ok) {
|
|
950
|
+
const help = renderVerdictHelp(result.status, result.activation);
|
|
951
|
+
if (help.length > 0) for (const h of help) ctx.print(h);
|
|
952
|
+
else ctx.print(" " + c.red(`\u2717 ${result.error}`));
|
|
953
|
+
return { type: "handled" };
|
|
954
|
+
}
|
|
955
|
+
for (const l of renderActivation(
|
|
956
|
+
result.projectId,
|
|
957
|
+
result.consoleUrl,
|
|
958
|
+
result.activation ?? {}
|
|
959
|
+
))
|
|
960
|
+
ctx.print(l);
|
|
961
|
+
return { type: "handled" };
|
|
962
|
+
}
|
|
963
|
+
},
|
|
964
|
+
{
|
|
965
|
+
name: "volition-status",
|
|
966
|
+
aliases: ["crew-status"],
|
|
967
|
+
summary: "operator state + recent runs of the Volition crew",
|
|
968
|
+
source: "builtin",
|
|
969
|
+
run: async (ctx) => {
|
|
970
|
+
const target = ctx.args.trim() || void 0;
|
|
971
|
+
let id = target;
|
|
972
|
+
if (id) {
|
|
973
|
+
const found = await resolveVolitionProject(id);
|
|
974
|
+
if (!found.ok) {
|
|
975
|
+
ctx.print(" " + c.red(`\u2717 ${found.error}`));
|
|
976
|
+
return { type: "handled" };
|
|
977
|
+
}
|
|
978
|
+
id = found.project.id;
|
|
979
|
+
} else {
|
|
980
|
+
id = readProjectLink(ctx.cwd)?.projectId;
|
|
981
|
+
}
|
|
982
|
+
if (!id) {
|
|
983
|
+
ctx.print(" " + c.red("no project \u2014 pass an id/name or run inside a linked project."));
|
|
984
|
+
return { type: "handled" };
|
|
985
|
+
}
|
|
986
|
+
const r = await volitionStatus(id);
|
|
987
|
+
ctx.print();
|
|
988
|
+
if (!r.ok) {
|
|
989
|
+
ctx.print(" " + c.red(`\u2717 ${r.error}`));
|
|
990
|
+
return { type: "handled" };
|
|
991
|
+
}
|
|
992
|
+
const op = r.data.operator ?? {};
|
|
993
|
+
ctx.print(
|
|
994
|
+
" " + (op.enabled === true ? c.green("\u25CF operating") : c.dim("\u25CB idle")) + (op.sandbox === false ? c.red(" LIVE") : c.dim(" sandbox"))
|
|
995
|
+
);
|
|
996
|
+
const counts = Object.entries(r.data.actionCounts ?? {}).map(([k, v]) => `${k} ${v}`).join(" \xB7 ");
|
|
997
|
+
if (counts) ctx.print(" " + c.dim(`actions: ${counts}`));
|
|
998
|
+
for (const run of (r.data.recentRuns ?? []).slice(0, 5)) {
|
|
999
|
+
ctx.print(
|
|
1000
|
+
" " + c.dim(
|
|
1001
|
+
`${run.status === "completed" ? "\u2713" : "\u2022"} ${run.runId ?? "run"} ${run.summary ?? ""}`.trimEnd()
|
|
1002
|
+
)
|
|
1003
|
+
);
|
|
1004
|
+
}
|
|
1005
|
+
ctx.print(" " + c.cyan(`console: ${apiBase()}/volition/${id}`));
|
|
1006
|
+
return { type: "handled" };
|
|
1007
|
+
}
|
|
1008
|
+
}
|
|
1009
|
+
];
|
|
1010
|
+
|
|
593
1011
|
// src/launch.ts
|
|
594
1012
|
function deployError(d, fallback) {
|
|
595
1013
|
return {
|
|
@@ -816,24 +1234,28 @@ async function patchBusiness(apiUrl, body) {
|
|
|
816
1234
|
|
|
817
1235
|
// src/prover.ts
|
|
818
1236
|
import { spawn as spawn2 } from "child_process";
|
|
819
|
-
import { join as
|
|
820
|
-
import { existsSync as
|
|
1237
|
+
import { join as join4 } from "path";
|
|
1238
|
+
import { existsSync as existsSync4 } from "fs";
|
|
821
1239
|
|
|
822
1240
|
// src/zeta-engine.ts
|
|
823
1241
|
import { spawn } from "child_process";
|
|
824
1242
|
import { tmpdir } from "os";
|
|
825
|
-
import { join as
|
|
826
|
-
import { existsSync as
|
|
1243
|
+
import { join as join3, dirname as dirname2, normalize as pathNormalize2, resolve as resolve2, sep as sep2 } from "path";
|
|
1244
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
827
1245
|
import { fileURLToPath } from "url";
|
|
828
1246
|
function normalize(result) {
|
|
829
1247
|
const files = Array.isArray(result.files) ? result.files : [];
|
|
830
1248
|
const verify = result.verify ?? {};
|
|
831
1249
|
const proofVerdict = result.proof?.verdict;
|
|
832
1250
|
const shipped = proofVerdict ? proofVerdict === "SHIP" : !!verify.ok;
|
|
1251
|
+
const pending = result.proof?.proofStatus === "pending" && shipped;
|
|
1252
|
+
const unverified = result.proof?.proofStatus === "unverified";
|
|
833
1253
|
return {
|
|
834
1254
|
ok: true,
|
|
835
1255
|
buildId: result.buildId ?? null,
|
|
836
1256
|
verdict: shipped ? "SHIP" : "NO_SHIP",
|
|
1257
|
+
proofPending: pending,
|
|
1258
|
+
unverified,
|
|
837
1259
|
themeId: result.themeId ?? null,
|
|
838
1260
|
fileCount: files.length,
|
|
839
1261
|
spec: typeof result.spec === "string" ? result.spec : null,
|
|
@@ -869,17 +1291,48 @@ function makeConsumer(onPhase) {
|
|
|
869
1291
|
}
|
|
870
1292
|
};
|
|
871
1293
|
}
|
|
1294
|
+
async function pollProofStatus(zetaApiUrl, buildId, authHeaders8, opts = {}) {
|
|
1295
|
+
const interval = opts.intervalMs ?? 5e3;
|
|
1296
|
+
const timeout = opts.timeoutMs ?? 10 * 60 * 1e3;
|
|
1297
|
+
const started = Date.now();
|
|
1298
|
+
let last = { proofStatus: "pending", verdict: null, dirty: false };
|
|
1299
|
+
while (Date.now() - started < timeout) {
|
|
1300
|
+
try {
|
|
1301
|
+
const resp = await fetch(
|
|
1302
|
+
`${zetaApiUrl}/api/zeta/build/${encodeURIComponent(buildId)}/proof-status`,
|
|
1303
|
+
{ headers: { ...authHeaders8 } }
|
|
1304
|
+
);
|
|
1305
|
+
if (resp.ok) {
|
|
1306
|
+
const j = await resp.json();
|
|
1307
|
+
last = {
|
|
1308
|
+
proofStatus: j.proofStatus ?? null,
|
|
1309
|
+
verdict: j.verdict ?? null,
|
|
1310
|
+
dirty: j.dirty === true
|
|
1311
|
+
};
|
|
1312
|
+
if (last.proofStatus && last.proofStatus !== "pending") return last;
|
|
1313
|
+
}
|
|
1314
|
+
} catch {
|
|
1315
|
+
}
|
|
1316
|
+
opts.onTick?.(Date.now() - started);
|
|
1317
|
+
await new Promise((r) => setTimeout(r, interval));
|
|
1318
|
+
}
|
|
1319
|
+
return last;
|
|
1320
|
+
}
|
|
872
1321
|
async function httpBuild(zetaApiUrl, body, onPhase) {
|
|
873
1322
|
let resp;
|
|
874
1323
|
try {
|
|
875
1324
|
const apiKey = process.env.ZETA_API_KEY?.trim();
|
|
1325
|
+
const byokKey = process.env.ZETA_BYOK_KEY?.trim();
|
|
1326
|
+
const byokProvider = process.env.ZETA_BYOK_PROVIDER?.trim();
|
|
876
1327
|
resp = await fetch(`${zetaApiUrl}/api/zeta/build`, {
|
|
877
1328
|
method: "POST",
|
|
878
1329
|
headers: {
|
|
879
1330
|
"content-type": "application/json",
|
|
880
1331
|
// Membership: lets the engine verify the subscription and return the code
|
|
881
1332
|
// (and charge one credit per app). Without it, only the preview comes back.
|
|
882
|
-
...apiKey ? { authorization: `Bearer ${apiKey}` } : {}
|
|
1333
|
+
...apiKey ? { authorization: `Bearer ${apiKey}` } : {},
|
|
1334
|
+
...byokKey ? { "x-zeta-byok-key": byokKey } : {},
|
|
1335
|
+
...byokKey && byokProvider ? { "x-zeta-byok-provider": byokProvider } : {}
|
|
883
1336
|
},
|
|
884
1337
|
body: JSON.stringify({ ...body, mode: "idea" })
|
|
885
1338
|
});
|
|
@@ -1038,8 +1491,8 @@ async function deliverBuild(zetaApiUrl, buildId, destDir, onPhase) {
|
|
|
1038
1491
|
const rel = pathNormalize2(f.path).replace(/^(\.\.(\/|\\|$))+/, "");
|
|
1039
1492
|
const full = resolve2(root, rel);
|
|
1040
1493
|
if (full !== root && !full.startsWith(root + sep2)) continue;
|
|
1041
|
-
|
|
1042
|
-
|
|
1494
|
+
mkdirSync3(dirname2(full), { recursive: true });
|
|
1495
|
+
writeFileSync3(full, f.content);
|
|
1043
1496
|
written += 1;
|
|
1044
1497
|
onPhase?.(`wrote ${rel}`);
|
|
1045
1498
|
}
|
|
@@ -1049,7 +1502,7 @@ async function deliverBuild(zetaApiUrl, buildId, destDir, onPhase) {
|
|
|
1049
1502
|
function findRepoRoot(start) {
|
|
1050
1503
|
let dir = start ?? dirname2(fileURLToPath(import.meta.url));
|
|
1051
1504
|
for (let i = 0; i < 12; i++) {
|
|
1052
|
-
if (
|
|
1505
|
+
if (existsSync3(join3(dir, "scripts", "zeta-build-worker.mts"))) return dir;
|
|
1053
1506
|
const up = dirname2(dir);
|
|
1054
1507
|
if (up === dir) break;
|
|
1055
1508
|
dir = up;
|
|
@@ -1070,9 +1523,9 @@ async function localBuild(body, onPhase, repoRoot) {
|
|
|
1070
1523
|
error: "local build needs the ZETA monorepo (scripts/zeta-build-worker.mts not found). Run from inside the repo, or use the http engine (--zeta-url)."
|
|
1071
1524
|
};
|
|
1072
1525
|
}
|
|
1073
|
-
const worker =
|
|
1526
|
+
const worker = join3(root, "scripts", "zeta-build-worker.mts");
|
|
1074
1527
|
const buildId = `zeta-build-${Date.now().toString(36)}-${Math.floor(performance.now())}`;
|
|
1075
|
-
const projectDir =
|
|
1528
|
+
const projectDir = join3(tmpdir(), buildId);
|
|
1076
1529
|
const ideaB64 = Buffer.from(body.idea, "utf8").toString("base64");
|
|
1077
1530
|
const args = [
|
|
1078
1531
|
"--import",
|
|
@@ -1097,8 +1550,17 @@ async function localBuild(body, onPhase, repoRoot) {
|
|
|
1097
1550
|
...process.env,
|
|
1098
1551
|
...body.styleId ? { ZETA_COMPOSE_STYLE: body.styleId } : {},
|
|
1099
1552
|
...body.colorScheme ? { ZETA_BUILD_COLOR_SCHEME: body.colorScheme } : {},
|
|
1553
|
+
// App-sizing override → the worker parses it (parseScopeOverride) into opts.appScope.
|
|
1554
|
+
...body.appScope ? { ZETA_BUILD_SCOPE: JSON.stringify(body.appScope) } : {},
|
|
1100
1555
|
// SNIPER / lean → worker skips the Launch Kit + Brand Studio campaign.
|
|
1101
|
-
...body.lean ? { ZETA_LEAN: "1" } : {}
|
|
1556
|
+
...body.lean ? { ZETA_LEAN: "1" } : {},
|
|
1557
|
+
// UNHINGED → worker skips ALL proofs/gates (fastest bootable, UNVERIFIED ship).
|
|
1558
|
+
// BYOK keys ride the inherited ...process.env above (set by the /build command).
|
|
1559
|
+
...body.unhinged ? { ZETA_UNHINGED: "1" } : {},
|
|
1560
|
+
// Studio parity pins — same worker envs the web route forwards.
|
|
1561
|
+
...body.platform === "mobile" ? { ZETA_BUILD_PLATFORM: "mobile" } : {},
|
|
1562
|
+
...body.archetype ? { ZETA_BUILD_ARCHETYPE: body.archetype } : {},
|
|
1563
|
+
...body.styleVibe ? { ZETA_STYLE_VIBE: body.styleVibe } : {}
|
|
1102
1564
|
},
|
|
1103
1565
|
stdio: ["ignore", "pipe", "pipe"]
|
|
1104
1566
|
});
|
|
@@ -1143,11 +1605,11 @@ var PROPERTY_KINDS = [
|
|
|
1143
1605
|
function resolveProver(repoRoot) {
|
|
1144
1606
|
const root = repoRoot ?? findRepoRoot();
|
|
1145
1607
|
if (!root) return null;
|
|
1146
|
-
const base =
|
|
1147
|
-
const dist =
|
|
1148
|
-
if (
|
|
1149
|
-
const src =
|
|
1150
|
-
if (
|
|
1608
|
+
const base = join4(root, "packages", "shipgate-contract-prover");
|
|
1609
|
+
const dist = join4(base, "dist", "cli.js");
|
|
1610
|
+
if (existsSync4(dist)) return { nodeArgs: [dist] };
|
|
1611
|
+
const src = join4(base, "src", "cli.ts");
|
|
1612
|
+
if (existsSync4(src)) return { nodeArgs: ["--import", "tsx", src] };
|
|
1151
1613
|
return null;
|
|
1152
1614
|
}
|
|
1153
1615
|
function runProver(proverArgs, opts) {
|
|
@@ -1192,8 +1654,8 @@ ${e.message}` });
|
|
|
1192
1654
|
// src/app-runner.ts
|
|
1193
1655
|
import { spawn as spawn3, spawnSync } from "child_process";
|
|
1194
1656
|
import { readFile } from "fs/promises";
|
|
1195
|
-
import { existsSync as
|
|
1196
|
-
import { join as
|
|
1657
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3, writeFileSync as writeFileSync4 } from "fs";
|
|
1658
|
+
import { join as join5, dirname as dirname3 } from "path";
|
|
1197
1659
|
var running = [];
|
|
1198
1660
|
function killRunningApps() {
|
|
1199
1661
|
for (const a of running.splice(0)) {
|
|
@@ -1209,8 +1671,8 @@ function listRunningApps() {
|
|
|
1209
1671
|
var URL_RE = /(https?:\/\/(?:localhost|127\.0\.0\.1|0\.0\.0\.0)(?::\d+)?[^\s)]*)/i;
|
|
1210
1672
|
var FATAL_RE = /(Error:|error TS\d+|Cannot find module|EADDRINUSE|Failed to compile|SyntaxError|Module not found|exited with)/i;
|
|
1211
1673
|
async function detectRun(dir) {
|
|
1212
|
-
const pkgPath =
|
|
1213
|
-
if (!
|
|
1674
|
+
const pkgPath = join5(dir, "package.json");
|
|
1675
|
+
if (!existsSync5(pkgPath)) {
|
|
1214
1676
|
return { error: `no package.json in ${dir} \u2014 not a runnable app directory` };
|
|
1215
1677
|
}
|
|
1216
1678
|
let scripts = {};
|
|
@@ -1220,7 +1682,7 @@ async function detectRun(dir) {
|
|
|
1220
1682
|
} catch (e) {
|
|
1221
1683
|
return { error: `unreadable package.json: ${e.message}` };
|
|
1222
1684
|
}
|
|
1223
|
-
const pm =
|
|
1685
|
+
const pm = existsSync5(join5(dir, "pnpm-lock.yaml")) ? "pnpm" : existsSync5(join5(dir, "yarn.lock")) ? "yarn" : "npm";
|
|
1224
1686
|
for (const s of ["dev", "start", "serve"]) {
|
|
1225
1687
|
if (scripts[s]) return { command: pm, args: ["run", s], reason: `${pm} run ${s}` };
|
|
1226
1688
|
}
|
|
@@ -1237,27 +1699,27 @@ function pnpmAvailable() {
|
|
|
1237
1699
|
return _pnpmOnPath;
|
|
1238
1700
|
}
|
|
1239
1701
|
function installPmFor(dir) {
|
|
1240
|
-
if (
|
|
1241
|
-
if (
|
|
1702
|
+
if (existsSync5(join5(dir, "yarn.lock"))) return "yarn";
|
|
1703
|
+
if (existsSync5(join5(dir, "pnpm-lock.yaml"))) return "pnpm";
|
|
1242
1704
|
return pnpmAvailable() ? "pnpm" : "npm";
|
|
1243
1705
|
}
|
|
1244
1706
|
function ensureNpmrc(dir, lines) {
|
|
1245
1707
|
try {
|
|
1246
|
-
const npmrc =
|
|
1247
|
-
const prev =
|
|
1708
|
+
const npmrc = join5(dir, ".npmrc");
|
|
1709
|
+
const prev = existsSync5(npmrc) ? readFileSync3(npmrc, "utf8") : "";
|
|
1248
1710
|
const missing = lines.filter((l) => !prev.includes(l.split("=")[0]));
|
|
1249
1711
|
if (missing.length === 0) return;
|
|
1250
1712
|
const sep5 = prev && !prev.endsWith("\n") ? "\n" : "";
|
|
1251
|
-
|
|
1713
|
+
writeFileSync4(npmrc, prev + sep5 + missing.join("\n") + "\n");
|
|
1252
1714
|
} catch {
|
|
1253
1715
|
}
|
|
1254
1716
|
}
|
|
1255
1717
|
function isolateFromWorkspace(dir) {
|
|
1256
|
-
if (
|
|
1718
|
+
if (existsSync5(join5(dir, "pnpm-workspace.yaml"))) return;
|
|
1257
1719
|
let cur = dirname3(dir);
|
|
1258
1720
|
let nested = false;
|
|
1259
1721
|
for (let i = 0; i < 12; i++) {
|
|
1260
|
-
if (
|
|
1722
|
+
if (existsSync5(join5(cur, "pnpm-workspace.yaml"))) {
|
|
1261
1723
|
nested = true;
|
|
1262
1724
|
break;
|
|
1263
1725
|
}
|
|
@@ -1267,14 +1729,14 @@ function isolateFromWorkspace(dir) {
|
|
|
1267
1729
|
}
|
|
1268
1730
|
if (!nested) return;
|
|
1269
1731
|
try {
|
|
1270
|
-
|
|
1732
|
+
writeFileSync4(join5(dir, "pnpm-workspace.yaml"), "packages:\n - .\n");
|
|
1271
1733
|
ensureNpmrc(dir, ["ignore-workspace-root-check=true"]);
|
|
1272
1734
|
} catch {
|
|
1273
1735
|
}
|
|
1274
1736
|
}
|
|
1275
1737
|
function installDeps(dir, onLog, signal) {
|
|
1276
1738
|
const pm = installPmFor(dir);
|
|
1277
|
-
if (pm === "pnpm" && !
|
|
1739
|
+
if (pm === "pnpm" && !existsSync5(join5(dir, "pnpm-lock.yaml"))) {
|
|
1278
1740
|
ensureNpmrc(dir, ["shamefully-hoist=true", "prefer-offline=true"]);
|
|
1279
1741
|
}
|
|
1280
1742
|
const args = pm === "pnpm" ? (
|
|
@@ -1314,7 +1776,7 @@ ${e.message}` });
|
|
|
1314
1776
|
});
|
|
1315
1777
|
}
|
|
1316
1778
|
async function runApp(dir, opts = {}) {
|
|
1317
|
-
if (!
|
|
1779
|
+
if (!existsSync5(join5(dir, "node_modules"))) {
|
|
1318
1780
|
isolateFromWorkspace(dir);
|
|
1319
1781
|
const inst = await installDeps(dir, void 0, opts.signal);
|
|
1320
1782
|
if (!inst.ok) {
|
|
@@ -1328,7 +1790,7 @@ async function runApp(dir, opts = {}) {
|
|
|
1328
1790
|
let command;
|
|
1329
1791
|
let cmdArgs;
|
|
1330
1792
|
if (opts.script) {
|
|
1331
|
-
const pm =
|
|
1793
|
+
const pm = existsSync5(join5(dir, "pnpm-lock.yaml")) ? "pnpm" : "npm";
|
|
1332
1794
|
command = pm;
|
|
1333
1795
|
cmdArgs = ["run", opts.script];
|
|
1334
1796
|
} else {
|
|
@@ -1432,7 +1894,7 @@ async function fetchGithubRepos(webBase, installationId) {
|
|
|
1432
1894
|
}
|
|
1433
1895
|
|
|
1434
1896
|
// src/repo-audit.ts
|
|
1435
|
-
import { readFileSync as
|
|
1897
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
1436
1898
|
import { createInterface } from "readline/promises";
|
|
1437
1899
|
import { stdin as input, stdout as output } from "process";
|
|
1438
1900
|
|
|
@@ -1598,7 +2060,7 @@ async function pickGithubRepoInteractive(webBase) {
|
|
|
1598
2060
|
}
|
|
1599
2061
|
function readSourceFile(path) {
|
|
1600
2062
|
try {
|
|
1601
|
-
const source =
|
|
2063
|
+
const source = readFileSync4(path, "utf8");
|
|
1602
2064
|
if (source.trim().length < 20) return { ok: false, error: "source file is too short" };
|
|
1603
2065
|
return { ok: true, source };
|
|
1604
2066
|
} catch (e) {
|
|
@@ -1613,11 +2075,11 @@ var TaskManager = class {
|
|
|
1613
2075
|
seq = 0;
|
|
1614
2076
|
map = /* @__PURE__ */ new Map();
|
|
1615
2077
|
/** Start a detached-from-the-REPL background command. Returns the task id. */
|
|
1616
|
-
start(command, args,
|
|
2078
|
+
start(command, args, cwd2) {
|
|
1617
2079
|
const id = `t${++this.seq}`;
|
|
1618
2080
|
const display = [command, ...args].join(" ");
|
|
1619
2081
|
const child = spawn4(command, args, {
|
|
1620
|
-
cwd,
|
|
2082
|
+
cwd: cwd2,
|
|
1621
2083
|
stdio: ["ignore", "pipe", "pipe"],
|
|
1622
2084
|
// Own process group so we can signal the whole tree on kill.
|
|
1623
2085
|
detached: false
|
|
@@ -1712,7 +2174,7 @@ import { tool as tool6 } from "ai";
|
|
|
1712
2174
|
import { z as z6 } from "zod";
|
|
1713
2175
|
import { spawn as spawn5 } from "child_process";
|
|
1714
2176
|
import { readFile as readFile2, writeFile, mkdir, readdir, stat } from "fs/promises";
|
|
1715
|
-
import { resolve as resolve3, dirname as dirname4, relative, join as
|
|
2177
|
+
import { resolve as resolve3, dirname as dirname4, relative, join as join6, sep as sep3 } from "path";
|
|
1716
2178
|
import fg2 from "fast-glob";
|
|
1717
2179
|
|
|
1718
2180
|
// src/crypto-tools.ts
|
|
@@ -2400,8 +2862,11 @@ function buildTools(ctx) {
|
|
|
2400
2862
|
const { permissions } = ctx;
|
|
2401
2863
|
async function runGenerate(opts) {
|
|
2402
2864
|
const { idea, scope, buildModel, install, keep, themeId, styleId, colorScheme } = opts;
|
|
2865
|
+
const { platform, archetype, styleVibe } = opts;
|
|
2403
2866
|
const lean = opts.lean ?? true;
|
|
2404
|
-
const
|
|
2867
|
+
const unhinged = opts.unhinged ?? false;
|
|
2868
|
+
const byokActive = Boolean(process.env.ZETA_BYOK_KEY?.trim());
|
|
2869
|
+
const preferBoot = (opts.preferBoot ?? true) && !unhinged && !byokActive;
|
|
2405
2870
|
if (permissions.guardMutation() === "deny") {
|
|
2406
2871
|
return { ok: false, error: permissions.planRefusal() };
|
|
2407
2872
|
}
|
|
@@ -2427,7 +2892,13 @@ function buildTools(ctx) {
|
|
|
2427
2892
|
...styleId ? { styleId } : {},
|
|
2428
2893
|
...colorScheme ? { colorScheme } : {},
|
|
2429
2894
|
// SNIPER: app surfaces only, no marketing campaign. On by default for the CLI.
|
|
2430
|
-
...lean ? { lean: true } : {}
|
|
2895
|
+
...lean ? { lean: true } : {},
|
|
2896
|
+
// UNHINGED: skip ALL proofs/gates → fastest bootable app, shipped UNVERIFIED.
|
|
2897
|
+
...unhinged ? { unhinged: true } : {},
|
|
2898
|
+
// Studio parity pins — mobile shell, interior archetype, look vibe.
|
|
2899
|
+
...platform === "mobile" ? { platform } : {},
|
|
2900
|
+
...archetype ? { archetype } : {},
|
|
2901
|
+
...styleVibe ? { styleVibe } : {}
|
|
2431
2902
|
};
|
|
2432
2903
|
const onPhase = (msg) => line(c.dim(` \u21B3 ${scrubVendor(msg)}`));
|
|
2433
2904
|
try {
|
|
@@ -2470,8 +2941,38 @@ function buildTools(ctx) {
|
|
|
2470
2941
|
viaHosted = true;
|
|
2471
2942
|
}
|
|
2472
2943
|
}
|
|
2944
|
+
if (viaHosted && result.ok && result.proofPending && result.buildId) {
|
|
2945
|
+
const bid = String(result.buildId);
|
|
2946
|
+
line(c.dim(" \u21B3 shipped fast \u2014 runtime proofs running in the background\u2026"));
|
|
2947
|
+
const final = await pollProofStatus(ctx.zetaApiUrl, bid, {}, {
|
|
2948
|
+
timeoutMs: 6 * 60 * 1e3,
|
|
2949
|
+
onTick: (ms) => line(c.dim(` proving\u2026 (${Math.round(ms / 1e3)}s)`))
|
|
2950
|
+
});
|
|
2951
|
+
if (final.proofStatus === "proven") {
|
|
2952
|
+
line(c.green(` \u2713 proven \u2014 ${final.verdict ?? "SHIP"}`));
|
|
2953
|
+
result = { ...result, verdict: final.verdict ?? result.verdict, proofPending: false };
|
|
2954
|
+
} else if (final.proofStatus === "failed") {
|
|
2955
|
+
line(c.red(` \u2717 proof FAILED after ship \u2014 your app is live but UNPROVEN (${final.verdict ?? "NO_SHIP"}).`));
|
|
2956
|
+
line(c.red(` Roll it back: zeta rollback ${bid}`));
|
|
2957
|
+
result = { ...result, verdict: "NO_SHIP", proofPending: false };
|
|
2958
|
+
} else {
|
|
2959
|
+
line(c.dim(` still proving \u2014 check later: zeta proof ${bid}`));
|
|
2960
|
+
}
|
|
2961
|
+
}
|
|
2962
|
+
if (result.ok && result.unverified) {
|
|
2963
|
+
line(
|
|
2964
|
+
c.yellow(
|
|
2965
|
+
" \u26A0 UNHINGED build \u2014 ALL ShipGate proofs/gates were skipped. It boots, but auth / tenant isolation / data rules are UNVERIFIED. Verify before any real use."
|
|
2966
|
+
)
|
|
2967
|
+
);
|
|
2968
|
+
}
|
|
2969
|
+
if (viaHosted && result.ok && result.buildId) {
|
|
2970
|
+
const passportUrl = `${ctx.zetaApiUrl.replace(/\/$/, "")}/proof/build/${encodeURIComponent(String(result.buildId))}`;
|
|
2971
|
+
line(c.dim(` \u21B3 build passport: ${passportUrl}`));
|
|
2972
|
+
result = { ...result, passportUrl };
|
|
2973
|
+
}
|
|
2473
2974
|
if (keep !== false && viaHosted && result.ok && result.buildId && !result.paywalled) {
|
|
2474
|
-
const dest = opts.destDir ?
|
|
2975
|
+
const dest = opts.destDir ? join6(ctx.cwd, opts.destDir) : join6(ctx.cwd, `zeta-${String(result.buildId).slice(-8)}`);
|
|
2475
2976
|
line(c.dim(" \u21B3 saving your code\u2026"));
|
|
2476
2977
|
const delivered = await deliverBuild(
|
|
2477
2978
|
ctx.zetaApiUrl,
|
|
@@ -2557,9 +3058,65 @@ function buildTools(ctx) {
|
|
|
2557
3058
|
),
|
|
2558
3059
|
lean: z6.boolean().default(true).describe(
|
|
2559
3060
|
"SNIPER mode (default true). Build ONLY the product surfaces \u2014 landing \xB7 login \xB7 app \xB7 dashboard \u2014 and SKIP the build-time go-to-market campaign (Launch Kit: pricing/social/email/pitch/checklist, and Brand Studio: DNA + visual campaigns). Faster and focused on the app. Set false ONLY when the user explicitly asks for the full marketing/launch kit."
|
|
3061
|
+
),
|
|
3062
|
+
unhinged: z6.boolean().default(false).describe(
|
|
3063
|
+
"UNHINGED mode \u2014 build as fast as possible: SKIP ALL ShipGate proofs and gates (RLS/RBAC/authz/client-contract/truth-gate + the ~30 runtime proofs). Keeps the compile check so the app still boots, but ships UNVERIFIED \u2014 no security proofs run. Set true ONLY when the user explicitly asks for a fast / raw / unhinged / no-checks build. Default false (the normal proven-before-ship path)."
|
|
3064
|
+
),
|
|
3065
|
+
platform: z6.enum(["web", "mobile"]).optional().describe(
|
|
3066
|
+
'"mobile" adds a Capacitor store-shippable iOS/Android shell after the web app is emitted. Use ONLY when the user asks for a mobile/phone app. OMIT for normal web apps.'
|
|
3067
|
+
),
|
|
3068
|
+
archetype: z6.enum([
|
|
3069
|
+
"analytics",
|
|
3070
|
+
"document-editor",
|
|
3071
|
+
"collaboration",
|
|
3072
|
+
"kanban",
|
|
3073
|
+
"calendar",
|
|
3074
|
+
"marketplace",
|
|
3075
|
+
"studio"
|
|
3076
|
+
]).optional().describe(
|
|
3077
|
+
"Pin the app's interior layout archetype. 'studio' = the two-plane generator/maker product class. OMIT to let the engine detect it from the idea (the default)."
|
|
3078
|
+
),
|
|
3079
|
+
styleVibe: z6.enum([
|
|
3080
|
+
"cinematic-dark",
|
|
3081
|
+
"editorial-luxe",
|
|
3082
|
+
"warm-minimal",
|
|
3083
|
+
"bold-brutalist",
|
|
3084
|
+
"glass-futuristic",
|
|
3085
|
+
"vibrant-playful",
|
|
3086
|
+
"corporate-clean"
|
|
3087
|
+
]).optional().describe(
|
|
3088
|
+
"Restrict the look to one vibe bucket when the user names a mood but not an exact style. A styleId pin still wins. OMIT for full-auto."
|
|
2560
3089
|
)
|
|
2561
3090
|
}),
|
|
2562
|
-
execute: async ({
|
|
3091
|
+
execute: async ({
|
|
3092
|
+
idea,
|
|
3093
|
+
scope,
|
|
3094
|
+
buildModel,
|
|
3095
|
+
install,
|
|
3096
|
+
keep,
|
|
3097
|
+
themeId,
|
|
3098
|
+
styleId,
|
|
3099
|
+
colorScheme,
|
|
3100
|
+
lean,
|
|
3101
|
+
unhinged,
|
|
3102
|
+
platform,
|
|
3103
|
+
archetype,
|
|
3104
|
+
styleVibe
|
|
3105
|
+
}) => runGenerate({
|
|
3106
|
+
idea,
|
|
3107
|
+
scope,
|
|
3108
|
+
buildModel,
|
|
3109
|
+
install,
|
|
3110
|
+
keep,
|
|
3111
|
+
themeId,
|
|
3112
|
+
styleId,
|
|
3113
|
+
colorScheme,
|
|
3114
|
+
lean,
|
|
3115
|
+
unhinged,
|
|
3116
|
+
platform,
|
|
3117
|
+
archetype,
|
|
3118
|
+
styleVibe
|
|
3119
|
+
})
|
|
2563
3120
|
}),
|
|
2564
3121
|
deploy_app: tool6({
|
|
2565
3122
|
description: "Deploy a BUILT app to a live preview URL (the studio's one-click Deploy \u2192 Vercel). Use AFTER generate_app has produced a build. Charges one build credit, paid once per build (re-deploying the same build is free); provisions a database + applies the schema when the app needs one. Polls until the deployment is live and returns its URL. This is an ephemeral PREVIEW \u2014 use promote_app to ship a durable production deployment.",
|
|
@@ -2647,6 +3204,79 @@ function buildTools(ctx) {
|
|
|
2647
3204
|
};
|
|
2648
3205
|
}
|
|
2649
3206
|
}),
|
|
3207
|
+
launch_volition: tool6({
|
|
3208
|
+
description: "Hand a business to OPERATION VOLITION \u2014 the autonomous operate-plane crew (strategy, social, outreach, support, ads, finance agents) that RUNS the business 24/7 on the platform. Use when the user wants the business operated/marketed for them, not just built. Pass a project id or name for an existing business, or a new business name to create one; omit target to use the project linked in this directory. Starts in SANDBOX (external actions simulated, every action proof-gated + certificate-hashed); live:true goes real. The $99/mo add-on is enforced server-side \u2014 a 402 returns the checkout path, never fake an activation.",
|
|
3209
|
+
inputSchema: z6.object({
|
|
3210
|
+
target: z6.string().max(200).optional().describe(
|
|
3211
|
+
"Project id, existing project name, or a NEW business name to create. Omit to use the linked project."
|
|
3212
|
+
),
|
|
3213
|
+
live: z6.boolean().optional().describe(
|
|
3214
|
+
"true = real external actions (posts, emails). Default false = sandbox simulation. Only set true when the user explicitly asks to go live."
|
|
3215
|
+
),
|
|
3216
|
+
description: z6.string().max(500).optional().describe("One-line description of the business (used when creating a new project).")
|
|
3217
|
+
}),
|
|
3218
|
+
execute: async ({ target, live, description }) => {
|
|
3219
|
+
if (permissions.guardMutation() === "deny")
|
|
3220
|
+
return { ok: false, error: permissions.planRefusal() };
|
|
3221
|
+
if (!process.env.ZETA_API_KEY?.trim()) {
|
|
3222
|
+
return {
|
|
3223
|
+
ok: false,
|
|
3224
|
+
error: "Login required \u2014 run `wholestack login` (Volition runs on your account)."
|
|
3225
|
+
};
|
|
3226
|
+
}
|
|
3227
|
+
const result = await launchVolition({
|
|
3228
|
+
target,
|
|
3229
|
+
live,
|
|
3230
|
+
description,
|
|
3231
|
+
cwd: ctx.cwd,
|
|
3232
|
+
onStep: (s) => toolLine("launch_volition", c.dim(s))
|
|
3233
|
+
});
|
|
3234
|
+
if (!result.ok) {
|
|
3235
|
+
return {
|
|
3236
|
+
ok: false,
|
|
3237
|
+
error: result.error,
|
|
3238
|
+
status: result.status,
|
|
3239
|
+
// 402 carries the checkout path; 503 carries readiness — surface them
|
|
3240
|
+
// so the agent can tell the user exactly what to do next.
|
|
3241
|
+
...result.activation
|
|
3242
|
+
};
|
|
3243
|
+
}
|
|
3244
|
+
return {
|
|
3245
|
+
ok: true,
|
|
3246
|
+
projectId: result.projectId,
|
|
3247
|
+
consoleUrl: result.consoleUrl,
|
|
3248
|
+
...result.activation
|
|
3249
|
+
};
|
|
3250
|
+
}
|
|
3251
|
+
}),
|
|
3252
|
+
volition_status: tool6({
|
|
3253
|
+
description: "Read the Volition crew's state for a project: operator on/off, sandbox vs live, action counts by status, recent shift summaries. Use to answer 'what has the crew done?' or before launching (to avoid double-activation). Pass a project id or name; omit to use the linked project.",
|
|
3254
|
+
inputSchema: z6.object({
|
|
3255
|
+
target: z6.string().max(200).optional().describe("Project id or name. Omit to use the project linked in this directory.")
|
|
3256
|
+
}),
|
|
3257
|
+
execute: async ({ target }) => {
|
|
3258
|
+
if (!process.env.ZETA_API_KEY?.trim()) {
|
|
3259
|
+
return { ok: false, error: "Login required \u2014 run `wholestack login` first." };
|
|
3260
|
+
}
|
|
3261
|
+
let id = target?.trim();
|
|
3262
|
+
if (id) {
|
|
3263
|
+
const found = await resolveVolitionProject(id);
|
|
3264
|
+
if (!found.ok) return { ok: false, error: found.error };
|
|
3265
|
+
id = found.project.id;
|
|
3266
|
+
} else {
|
|
3267
|
+
id = readProjectLink(ctx.cwd)?.projectId;
|
|
3268
|
+
}
|
|
3269
|
+
if (!id) {
|
|
3270
|
+
return {
|
|
3271
|
+
ok: false,
|
|
3272
|
+
error: "No project \u2014 pass a target or run inside a linked project directory."
|
|
3273
|
+
};
|
|
3274
|
+
}
|
|
3275
|
+
const r = await volitionStatus(id);
|
|
3276
|
+
if (!r.ok) return { ok: false, error: r.error, status: r.status };
|
|
3277
|
+
return { ok: true, projectId: id, ...r.data };
|
|
3278
|
+
}
|
|
3279
|
+
}),
|
|
2650
3280
|
promote_app: tool6({
|
|
2651
3281
|
description: "Promote a BUILT app to a DURABLE PRODUCTION deployment \u2014 a real (non-ephemeral) database and production env with dev-auth OFF, optionally bound to a custom domain. This is the 'make it a real product' step (stronger than deploy_app's ephemeral preview). Requires the platform to have a database provider configured. Charges/credits follow the same rules as deploy.",
|
|
2652
3282
|
inputSchema: z6.object({
|
|
@@ -3077,7 +3707,7 @@ function buildTools(ctx) {
|
|
|
3077
3707
|
const themeId = themes[i % themes.length];
|
|
3078
3708
|
line(c.bold(`
|
|
3079
3709
|
[${i + 1}/${picks.length}] ${p.name} \xB7 ${themeId}`));
|
|
3080
|
-
const destDir =
|
|
3710
|
+
const destDir = join6("zeta-batch", `${String(i + 1).padStart(2, "0")}-${slugify(p.name)}`);
|
|
3081
3711
|
let r;
|
|
3082
3712
|
try {
|
|
3083
3713
|
r = await runGenerate({
|
|
@@ -3357,7 +3987,7 @@ function buildTools(ctx) {
|
|
|
3357
3987
|
const names = await readdir(abs);
|
|
3358
3988
|
const entries = await Promise.all(
|
|
3359
3989
|
names.map(async (n) => {
|
|
3360
|
-
const s = await stat(
|
|
3990
|
+
const s = await stat(join6(abs, n)).catch(() => null);
|
|
3361
3991
|
return { name: n, dir: s?.isDirectory() ?? false };
|
|
3362
3992
|
})
|
|
3363
3993
|
);
|
|
@@ -3548,102 +4178,26 @@ function buildTools(ctx) {
|
|
|
3548
4178
|
};
|
|
3549
4179
|
}
|
|
3550
4180
|
|
|
3551
|
-
// src/config.ts
|
|
3552
|
-
import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, mkdirSync as mkdirSync3, existsSync as existsSync5, chmodSync, renameSync } from "fs";
|
|
3553
|
-
import { homedir } from "os";
|
|
3554
|
-
import { join as join6 } from "path";
|
|
3555
|
-
var LEGACY_DIR = join6(homedir(), ".zeta-g");
|
|
3556
|
-
var STATE_DIR = join6(homedir(), ".wholestack");
|
|
3557
|
-
try {
|
|
3558
|
-
if (existsSync5(LEGACY_DIR) && !existsSync5(STATE_DIR)) renameSync(LEGACY_DIR, STATE_DIR);
|
|
3559
|
-
} catch {
|
|
3560
|
-
}
|
|
3561
|
-
function stateDir() {
|
|
3562
|
-
return STATE_DIR;
|
|
3563
|
-
}
|
|
3564
|
-
function webBaseUrl() {
|
|
3565
|
-
return process.env.ZETA_WEB_URL?.trim() || process.env.ZETA_API_URL?.trim() || "https://wholestack.ai";
|
|
3566
|
-
}
|
|
3567
|
-
function projectDirs(cwd) {
|
|
3568
|
-
return [join6(cwd, ".wholestack"), join6(cwd, ".zeta-g")];
|
|
3569
|
-
}
|
|
3570
|
-
var CONFIG_DIR = STATE_DIR;
|
|
3571
|
-
var CONFIG_PATH = join6(CONFIG_DIR, "config.json");
|
|
3572
|
-
function parseDotenv(text) {
|
|
3573
|
-
const out = {};
|
|
3574
|
-
for (const raw of text.split("\n")) {
|
|
3575
|
-
const l = raw.trim();
|
|
3576
|
-
if (!l || l.startsWith("#")) continue;
|
|
3577
|
-
const eq = l.indexOf("=");
|
|
3578
|
-
if (eq < 0) continue;
|
|
3579
|
-
const k = l.slice(0, eq).trim();
|
|
3580
|
-
let v = l.slice(eq + 1).trim();
|
|
3581
|
-
if (v.startsWith('"') && v.endsWith('"') || v.startsWith("'") && v.endsWith("'")) {
|
|
3582
|
-
v = v.slice(1, -1);
|
|
3583
|
-
}
|
|
3584
|
-
if (k) out[k] = v;
|
|
3585
|
-
}
|
|
3586
|
-
return out;
|
|
3587
|
-
}
|
|
3588
|
-
function fill(src) {
|
|
3589
|
-
for (const [k, v] of Object.entries(src)) {
|
|
3590
|
-
if (v && process.env[k] === void 0) process.env[k] = v;
|
|
3591
|
-
}
|
|
3592
|
-
}
|
|
3593
|
-
function loadStoredEnv() {
|
|
3594
|
-
const localEnv = join6(process.cwd(), ".env");
|
|
3595
|
-
if (existsSync5(localEnv)) {
|
|
3596
|
-
try {
|
|
3597
|
-
fill(parseDotenv(readFileSync4(localEnv, "utf8")));
|
|
3598
|
-
} catch {
|
|
3599
|
-
}
|
|
3600
|
-
}
|
|
3601
|
-
if (existsSync5(CONFIG_PATH)) {
|
|
3602
|
-
try {
|
|
3603
|
-
const json = JSON.parse(readFileSync4(CONFIG_PATH, "utf8"));
|
|
3604
|
-
const flat = {};
|
|
3605
|
-
for (const [k, v] of Object.entries(json)) if (typeof v === "string") flat[k] = v;
|
|
3606
|
-
fill(flat);
|
|
3607
|
-
} catch {
|
|
3608
|
-
}
|
|
3609
|
-
}
|
|
3610
|
-
}
|
|
3611
|
-
function saveKey(name, value) {
|
|
3612
|
-
mkdirSync3(CONFIG_DIR, { recursive: true });
|
|
3613
|
-
let current = {};
|
|
3614
|
-
if (existsSync5(CONFIG_PATH)) {
|
|
3615
|
-
try {
|
|
3616
|
-
current = JSON.parse(readFileSync4(CONFIG_PATH, "utf8"));
|
|
3617
|
-
} catch {
|
|
3618
|
-
current = {};
|
|
3619
|
-
}
|
|
3620
|
-
}
|
|
3621
|
-
current[name] = value;
|
|
3622
|
-
writeFileSync4(CONFIG_PATH, JSON.stringify(current, null, 2) + "\n", { mode: 384 });
|
|
3623
|
-
chmodSync(CONFIG_PATH, 384);
|
|
3624
|
-
return CONFIG_PATH;
|
|
3625
|
-
}
|
|
3626
|
-
|
|
3627
4181
|
// src/hooks.ts
|
|
3628
4182
|
import { spawn as spawn6 } from "child_process";
|
|
3629
4183
|
import { readFileSync as readFileSync5, existsSync as existsSync6 } from "fs";
|
|
3630
4184
|
import { join as join7 } from "path";
|
|
3631
4185
|
var HOOK_TIMEOUT_MS = 15e3;
|
|
3632
|
-
function runOne(def, event, payload,
|
|
4186
|
+
function runOne(def, event, payload, cwd2) {
|
|
3633
4187
|
return new Promise((res) => {
|
|
3634
|
-
const child = spawn6("sh", ["-c", def.command], { cwd });
|
|
3635
|
-
let
|
|
4188
|
+
const child = spawn6("sh", ["-c", def.command], { cwd: cwd2 });
|
|
4189
|
+
let stdout3 = "";
|
|
3636
4190
|
let stderr = "";
|
|
3637
4191
|
const timer = setTimeout(() => child.kill("SIGKILL"), HOOK_TIMEOUT_MS);
|
|
3638
|
-
child.stdout.on("data", (b) =>
|
|
4192
|
+
child.stdout.on("data", (b) => stdout3 += b.toString());
|
|
3639
4193
|
child.stderr.on("data", (b) => stderr += b.toString());
|
|
3640
4194
|
child.on("error", (e) => {
|
|
3641
4195
|
clearTimeout(timer);
|
|
3642
|
-
res({ code: 1, stdout:
|
|
4196
|
+
res({ code: 1, stdout: stdout3, stderr: stderr + e.message });
|
|
3643
4197
|
});
|
|
3644
4198
|
child.on("close", (code) => {
|
|
3645
4199
|
clearTimeout(timer);
|
|
3646
|
-
res({ code: code ?? 0, stdout:
|
|
4200
|
+
res({ code: code ?? 0, stdout: stdout3, stderr });
|
|
3647
4201
|
});
|
|
3648
4202
|
try {
|
|
3649
4203
|
child.stdin.write(JSON.stringify({ event, ...payload }));
|
|
@@ -3653,9 +4207,9 @@ function runOne(def, event, payload, cwd) {
|
|
|
3653
4207
|
});
|
|
3654
4208
|
}
|
|
3655
4209
|
var HookRunner = class {
|
|
3656
|
-
constructor(hooks,
|
|
4210
|
+
constructor(hooks, cwd2) {
|
|
3657
4211
|
this.hooks = hooks;
|
|
3658
|
-
this.cwd =
|
|
4212
|
+
this.cwd = cwd2;
|
|
3659
4213
|
}
|
|
3660
4214
|
hooks;
|
|
3661
4215
|
cwd;
|
|
@@ -3672,22 +4226,22 @@ var HookRunner = class {
|
|
|
3672
4226
|
for (const def of defs) {
|
|
3673
4227
|
if (def.matcher && payload.toolName && !new RegExp(def.matcher).test(payload.toolName))
|
|
3674
4228
|
continue;
|
|
3675
|
-
const { code, stdout:
|
|
3676
|
-
const parsed = tryJson(
|
|
4229
|
+
const { code, stdout: stdout3, stderr } = await runOne(def, event, payload, this.cwd);
|
|
4230
|
+
const parsed = tryJson(stdout3);
|
|
3677
4231
|
if (parsed && (parsed.decision === "block" || parsed.block)) {
|
|
3678
4232
|
outcome.block = String(parsed.reason ?? parsed.message ?? "blocked by hook");
|
|
3679
4233
|
return outcome;
|
|
3680
4234
|
}
|
|
3681
4235
|
if (canBlock && code !== 0) {
|
|
3682
4236
|
const reason = parsed ? String(parsed.reason ?? parsed.message ?? "") : "";
|
|
3683
|
-
outcome.block = (stderr || reason ||
|
|
4237
|
+
outcome.block = (stderr || reason || stdout3 || `hook exited ${code}`).trim();
|
|
3684
4238
|
return outcome;
|
|
3685
4239
|
}
|
|
3686
4240
|
if (parsed) {
|
|
3687
4241
|
const extra = parsed.additionalContext ?? parsed.hookSpecificOutput?.additionalContext;
|
|
3688
4242
|
if (extra) outcome.context.push(String(extra));
|
|
3689
4243
|
} else {
|
|
3690
|
-
const text =
|
|
4244
|
+
const text = stdout3.trim();
|
|
3691
4245
|
if (text) outcome.context.push(text);
|
|
3692
4246
|
}
|
|
3693
4247
|
}
|
|
@@ -3713,10 +4267,10 @@ function mergeHookSets(...sets) {
|
|
|
3713
4267
|
}
|
|
3714
4268
|
return out;
|
|
3715
4269
|
}
|
|
3716
|
-
function loadHookFiles(
|
|
4270
|
+
function loadHookFiles(cwd2) {
|
|
3717
4271
|
const files = [
|
|
3718
4272
|
join7(stateDir(), "hooks.json"),
|
|
3719
|
-
...projectDirs(
|
|
4273
|
+
...projectDirs(cwd2).map((d) => join7(d, "hooks.json"))
|
|
3720
4274
|
];
|
|
3721
4275
|
const sets = [];
|
|
3722
4276
|
for (const f of files) {
|
|
@@ -3878,7 +4432,9 @@ var MODEL_IDS = {
|
|
|
3878
4432
|
/** BRAIN lane — frontend swarm, decisions, debugging, editing, planning. Cerebras. The 20%. */
|
|
3879
4433
|
glm: readEnv("ZETA_GLM_MODEL") || "zai-glm-4.7",
|
|
3880
4434
|
/** VISION lane — accepts image input. OpenRouter (Cerebras text lanes can't see). */
|
|
3881
|
-
vision: readEnv("ZETA_VISION_MODEL") || "anthropic/claude-sonnet-4.6"
|
|
4435
|
+
vision: readEnv("ZETA_VISION_MODEL") || "anthropic/claude-sonnet-4.6",
|
|
4436
|
+
/** SONNET lane — Claude Sonnet 5 via OpenRouter. Premium reasoning + design brain (CLI + studio design pass). */
|
|
4437
|
+
sonnet: readEnv("ZETA_SONNET_MODEL") || "anthropic/claude-sonnet-5"
|
|
3882
4438
|
};
|
|
3883
4439
|
var ZETA_AGENT_PIPELINE = Object.freeze({
|
|
3884
4440
|
/** THINK lane — ISL spec authoring BASE. gpt-oss-120b ($0.35/$0.75 per 1M) so a build
|
|
@@ -3903,6 +4459,7 @@ var CEREBRAS_KEY = PROVIDERS.cerebras.keyEnv;
|
|
|
3903
4459
|
var KEY_ENV = PROVIDERS.openrouter.keyEnv;
|
|
3904
4460
|
var DEFAULT_CUSTOM_MODEL = MODEL_IDS.vision;
|
|
3905
4461
|
var VISION_MODEL = MODEL_IDS.vision;
|
|
4462
|
+
var SONNET_MODEL = MODEL_IDS.sonnet;
|
|
3906
4463
|
var MODELS = /* @__PURE__ */ new Map([
|
|
3907
4464
|
[
|
|
3908
4465
|
"zeta-g1-lite",
|
|
@@ -3949,6 +4506,19 @@ var MODELS = /* @__PURE__ */ new Map([
|
|
|
3949
4506
|
contextWindow: 2e5,
|
|
3950
4507
|
thinking: null
|
|
3951
4508
|
}
|
|
4509
|
+
],
|
|
4510
|
+
// The Sonnet tier — Claude Sonnet 5 via OpenRouter: the premium reasoning + design
|
|
4511
|
+
// brain, and vision-capable. BYOK OpenRouter like the vision tier (set OPENROUTER_API_KEY).
|
|
4512
|
+
[
|
|
4513
|
+
"zeta-g1-sonnet",
|
|
4514
|
+
{
|
|
4515
|
+
modelId: SONNET_MODEL,
|
|
4516
|
+
label: "Zeta-G1.0 Sonnet",
|
|
4517
|
+
keyEnv: KEY_ENV,
|
|
4518
|
+
baseURL: OPENROUTER_URL,
|
|
4519
|
+
contextWindow: 2e5,
|
|
4520
|
+
thinking: null
|
|
4521
|
+
}
|
|
3952
4522
|
]
|
|
3953
4523
|
]);
|
|
3954
4524
|
var MODEL_KEYS = [...MODELS.keys()];
|
|
@@ -3990,9 +4560,9 @@ function resolveModelKey(raw) {
|
|
|
3990
4560
|
image: "zeta-g1-vision",
|
|
3991
4561
|
// legacy convenience — resolve silently, but only the Zeta label is shown
|
|
3992
4562
|
opus: "zeta-g1-max",
|
|
3993
|
-
sonnet: "zeta-g1",
|
|
4563
|
+
sonnet: "zeta-g1-sonnet",
|
|
3994
4564
|
haiku: "zeta-g1-lite",
|
|
3995
|
-
claude: "zeta-g1"
|
|
4565
|
+
claude: "zeta-g1-sonnet"
|
|
3996
4566
|
};
|
|
3997
4567
|
if (ALIASES[lower]) return ALIASES[lower];
|
|
3998
4568
|
throw new Error(`Unknown model "${raw}". Try: ${MODEL_KEYS.join(", ")}.`);
|
|
@@ -4010,7 +4580,7 @@ function modelId(key) {
|
|
|
4010
4580
|
return spec(key).modelId;
|
|
4011
4581
|
}
|
|
4012
4582
|
function visionCapable(key) {
|
|
4013
|
-
return key === "zeta-g1-vision" || key.startsWith("custom:");
|
|
4583
|
+
return key === "zeta-g1-vision" || key === "zeta-g1-sonnet" || key.startsWith("custom:");
|
|
4014
4584
|
}
|
|
4015
4585
|
function modelContextWindow(key) {
|
|
4016
4586
|
return spec(key).contextWindow;
|
|
@@ -5047,11 +5617,11 @@ function readScripts(dir) {
|
|
|
5047
5617
|
return {};
|
|
5048
5618
|
}
|
|
5049
5619
|
}
|
|
5050
|
-
function runScript(pm, script,
|
|
5620
|
+
function runScript(pm, script, cwd2, timeoutMs) {
|
|
5051
5621
|
const shell = process.env.SHELL || "/bin/bash";
|
|
5052
5622
|
const line2 = `${pm} run ${script}`;
|
|
5053
5623
|
return new Promise((res) => {
|
|
5054
|
-
const child = spawn7(shell, ["-lc", line2], { cwd, shell: false });
|
|
5624
|
+
const child = spawn7(shell, ["-lc", line2], { cwd: cwd2, shell: false });
|
|
5055
5625
|
let out = "";
|
|
5056
5626
|
const timer = setTimeout(() => child.kill("SIGKILL"), timeoutMs);
|
|
5057
5627
|
const sink = (b) => {
|
|
@@ -6745,13 +7315,13 @@ async function readBounded(path, limit) {
|
|
|
6745
7315
|
return null;
|
|
6746
7316
|
}
|
|
6747
7317
|
}
|
|
6748
|
-
async function loadProjectMemory(
|
|
7318
|
+
async function loadProjectMemory(cwd2) {
|
|
6749
7319
|
const candidates = [];
|
|
6750
7320
|
const globalFile = join9(stateDir(), "ZETA.md");
|
|
6751
7321
|
if (existsSync9(globalFile)) candidates.push(globalFile);
|
|
6752
|
-
const root = repoRootFrom(
|
|
7322
|
+
const root = repoRootFrom(cwd2);
|
|
6753
7323
|
const chain = [];
|
|
6754
|
-
let dir =
|
|
7324
|
+
let dir = cwd2;
|
|
6755
7325
|
for (let i = 0; i < 24; i++) {
|
|
6756
7326
|
chain.unshift(dir);
|
|
6757
7327
|
if (dir === root) break;
|
|
@@ -6943,10 +7513,10 @@ var Session = class _Session {
|
|
|
6943
7513
|
meta;
|
|
6944
7514
|
path;
|
|
6945
7515
|
/** Start a fresh session and write its meta header. */
|
|
6946
|
-
static create(
|
|
7516
|
+
static create(cwd2, model) {
|
|
6947
7517
|
ensureDir();
|
|
6948
7518
|
const id = `${Date.now().toString(36)}-${randomUUID().slice(0, 8)}`;
|
|
6949
|
-
const meta = { id, cwd, model, startedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
7519
|
+
const meta = { id, cwd: cwd2, model, startedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
6950
7520
|
const path = fileFor(id);
|
|
6951
7521
|
appendFileSync(path, JSON.stringify({ kind: "meta", ...meta }) + "\n", "utf8");
|
|
6952
7522
|
return new _Session(meta, path);
|
|
@@ -6973,12 +7543,12 @@ var Session = class _Session {
|
|
|
6973
7543
|
return { session: new _Session(meta, path), messages };
|
|
6974
7544
|
}
|
|
6975
7545
|
/** The most recent session (optionally scoped to a working directory). */
|
|
6976
|
-
static latestId(
|
|
6977
|
-
const all = _Session.list(1,
|
|
7546
|
+
static latestId(cwd2) {
|
|
7547
|
+
const all = _Session.list(1, cwd2);
|
|
6978
7548
|
return all.length ? all[0].id : null;
|
|
6979
7549
|
}
|
|
6980
7550
|
/** List sessions newest-first, with a preview of the first user message. */
|
|
6981
|
-
static list(limit = 30,
|
|
7551
|
+
static list(limit = 30, cwd2) {
|
|
6982
7552
|
if (!existsSync10(SESSIONS_DIR)) return [];
|
|
6983
7553
|
const out = [];
|
|
6984
7554
|
for (const name of readdirSync2(SESSIONS_DIR)) {
|
|
@@ -7004,7 +7574,7 @@ var Session = class _Session {
|
|
|
7004
7574
|
continue;
|
|
7005
7575
|
}
|
|
7006
7576
|
if (!meta) continue;
|
|
7007
|
-
if (
|
|
7577
|
+
if (cwd2 && meta.cwd !== cwd2) continue;
|
|
7008
7578
|
const updatedAt = statSync2(path).mtimeMs;
|
|
7009
7579
|
out.push({ ...meta, preview: preview.slice(0, 70), turns, updatedAt });
|
|
7010
7580
|
}
|
|
@@ -7035,9 +7605,9 @@ async function loadChromium() {
|
|
|
7035
7605
|
return null;
|
|
7036
7606
|
}
|
|
7037
7607
|
}
|
|
7038
|
-
function insideCwd(
|
|
7039
|
-
const abs = resolve5(
|
|
7040
|
-
const rel = relative3(
|
|
7608
|
+
function insideCwd(cwd2, p) {
|
|
7609
|
+
const abs = resolve5(cwd2, p);
|
|
7610
|
+
const rel = relative3(cwd2, abs);
|
|
7041
7611
|
if (rel === ".." || rel.startsWith(".." + sep4)) {
|
|
7042
7612
|
throw new Error(`path "${p}" escapes the workspace root`);
|
|
7043
7613
|
}
|
|
@@ -7788,7 +8358,7 @@ function shippedSkillsDir() {
|
|
|
7788
8358
|
for (const dir of candidates) if (existsSync12(dir)) return dir;
|
|
7789
8359
|
return "";
|
|
7790
8360
|
}
|
|
7791
|
-
function loadAllSkills(
|
|
8361
|
+
function loadAllSkills(cwd2) {
|
|
7792
8362
|
const byName = /* @__PURE__ */ new Map();
|
|
7793
8363
|
const add = (skills) => {
|
|
7794
8364
|
for (const s of skills) byName.set(s.name, s);
|
|
@@ -7796,7 +8366,7 @@ function loadAllSkills(cwd) {
|
|
|
7796
8366
|
const shipped = shippedSkillsDir();
|
|
7797
8367
|
if (shipped) add(loadSkillsFromDir(shipped, "shipped"));
|
|
7798
8368
|
add(loadSkillsFromDir(join13(stateDir(), "skills"), "user"));
|
|
7799
|
-
for (const d of projectDirs(
|
|
8369
|
+
for (const d of projectDirs(cwd2)) add(loadSkillsFromDir(join13(d, "skills"), "project"));
|
|
7800
8370
|
return [...byName.values()].sort((a, b) => a.name.localeCompare(b.name));
|
|
7801
8371
|
}
|
|
7802
8372
|
var SkillRegistry = class _SkillRegistry {
|
|
@@ -7806,8 +8376,8 @@ var SkillRegistry = class _SkillRegistry {
|
|
|
7806
8376
|
this.skills = skills;
|
|
7807
8377
|
this.index = new Map(skills.map((s) => [s.name, s]));
|
|
7808
8378
|
}
|
|
7809
|
-
static load(
|
|
7810
|
-
return new _SkillRegistry(loadAllSkills(
|
|
8379
|
+
static load(cwd2) {
|
|
8380
|
+
return new _SkillRegistry(loadAllSkills(cwd2));
|
|
7811
8381
|
}
|
|
7812
8382
|
list() {
|
|
7813
8383
|
return this.skills;
|
|
@@ -7893,23 +8463,23 @@ import { join as join14 } from "path";
|
|
|
7893
8463
|
|
|
7894
8464
|
// src/git.ts
|
|
7895
8465
|
import { execFileSync } from "child_process";
|
|
7896
|
-
function git(args,
|
|
8466
|
+
function git(args, cwd2) {
|
|
7897
8467
|
return execFileSync("git", args, {
|
|
7898
|
-
cwd,
|
|
8468
|
+
cwd: cwd2,
|
|
7899
8469
|
encoding: "utf8",
|
|
7900
8470
|
maxBuffer: 32 * 1024 * 1024,
|
|
7901
8471
|
stdio: ["ignore", "pipe", "pipe"]
|
|
7902
8472
|
}).trim();
|
|
7903
8473
|
}
|
|
7904
|
-
function gitSafe(args,
|
|
8474
|
+
function gitSafe(args, cwd2) {
|
|
7905
8475
|
try {
|
|
7906
|
-
return git(args,
|
|
8476
|
+
return git(args, cwd2);
|
|
7907
8477
|
} catch {
|
|
7908
8478
|
return null;
|
|
7909
8479
|
}
|
|
7910
8480
|
}
|
|
7911
|
-
function isRepo(
|
|
7912
|
-
return gitSafe(["rev-parse", "--is-inside-work-tree"],
|
|
8481
|
+
function isRepo(cwd2) {
|
|
8482
|
+
return gitSafe(["rev-parse", "--is-inside-work-tree"], cwd2) === "true";
|
|
7913
8483
|
}
|
|
7914
8484
|
var SECRET_HINTS = [
|
|
7915
8485
|
{ re: /\bAKIA[0-9A-Z]{16}\b/, label: "AWS access key id" },
|
|
@@ -8072,7 +8642,7 @@ var eyesCommands = [
|
|
|
8072
8642
|
];
|
|
8073
8643
|
|
|
8074
8644
|
// src/ops-commands.ts
|
|
8075
|
-
function
|
|
8645
|
+
function apiBase2() {
|
|
8076
8646
|
return (process.env.ZETA_WEB_URL?.trim() || process.env.ZETA_API_URL?.trim() || "https://wholestack.ai").replace(/\/$/, "");
|
|
8077
8647
|
}
|
|
8078
8648
|
async function probe2(url, timeoutMs) {
|
|
@@ -8144,7 +8714,7 @@ var opsCommands = [
|
|
|
8144
8714
|
return { type: "handled" };
|
|
8145
8715
|
}
|
|
8146
8716
|
const r = await apiJson(
|
|
8147
|
-
`${
|
|
8717
|
+
`${apiBase2()}/api/zeta/build/${encodeURIComponent(buildId)}/deploy?deploymentId=${encodeURIComponent(deploymentId)}`
|
|
8148
8718
|
);
|
|
8149
8719
|
ctx.print();
|
|
8150
8720
|
if (!r.ok) {
|
|
@@ -8163,7 +8733,7 @@ var opsCommands = [
|
|
|
8163
8733
|
summary: "read live traffic + revenue (PostHog/Stripe)",
|
|
8164
8734
|
source: "builtin",
|
|
8165
8735
|
run: async (ctx) => {
|
|
8166
|
-
const r = await readMetrics(
|
|
8736
|
+
const r = await readMetrics(apiBase2());
|
|
8167
8737
|
ctx.print();
|
|
8168
8738
|
if (!r.ok || !r.metrics) {
|
|
8169
8739
|
ctx.print(" " + c.red(`\u2717 ${r.error ?? "no metrics"}`));
|
|
@@ -8196,7 +8766,7 @@ var opsCommands = [
|
|
|
8196
8766
|
summary: "read recent production errors (Sentry/PostHog)",
|
|
8197
8767
|
source: "builtin",
|
|
8198
8768
|
run: async (ctx) => {
|
|
8199
|
-
const r = await readMetrics(
|
|
8769
|
+
const r = await readMetrics(apiBase2());
|
|
8200
8770
|
ctx.print();
|
|
8201
8771
|
if (!r.ok || !r.metrics) {
|
|
8202
8772
|
ctx.print(" " + c.red(`\u2717 ${r.error ?? "no metrics"}`));
|
|
@@ -8467,7 +9037,7 @@ var BUILTINS = [
|
|
|
8467
9037
|
},
|
|
8468
9038
|
{
|
|
8469
9039
|
name: "build",
|
|
8470
|
-
summary: "scaffold a full-stack app \u2014 sniper by default: landing \xB7 login \xB7 app \xB7 dashboard, no marketing campaign (/build <idea> [--style <id>] [--color dark|light] [--campaign] [--deploy])",
|
|
9040
|
+
summary: "scaffold a full-stack app \u2014 sniper by default: landing \xB7 login \xB7 app \xB7 dashboard, no marketing campaign (/build <idea> [--style <id>] [--color dark|light] [--campaign] [--deploy] [--unhinged] [--key <k> --provider <p>])",
|
|
8471
9041
|
source: "builtin",
|
|
8472
9042
|
run: (ctx) => {
|
|
8473
9043
|
if (!ctx.args) {
|
|
@@ -8505,6 +9075,29 @@ var BUILTINS = [
|
|
|
8505
9075
|
campaign = true;
|
|
8506
9076
|
rest = rest.replace(/(^|\s)--(campaign|full-kit)(\s|$)/, " ");
|
|
8507
9077
|
}
|
|
9078
|
+
let unhinged = false;
|
|
9079
|
+
if (/(^|\s)--unhinged(\s|$)/.test(rest)) {
|
|
9080
|
+
unhinged = true;
|
|
9081
|
+
rest = rest.replace(/(^|\s)--unhinged(\s|$)/, " ");
|
|
9082
|
+
}
|
|
9083
|
+
const provM = rest.match(/--provider[=\s]+(openrouter|cerebras|anthropic|openai|google)/i);
|
|
9084
|
+
if (provM) {
|
|
9085
|
+
process.env.ZETA_BYOK_PROVIDER = provM[1].toLowerCase();
|
|
9086
|
+
rest = rest.replace(provM[0], " ");
|
|
9087
|
+
}
|
|
9088
|
+
const keyM = rest.match(/--key[=\s]+(\S+)/i);
|
|
9089
|
+
if (keyM) {
|
|
9090
|
+
process.env.ZETA_BYOK_KEY = keyM[1];
|
|
9091
|
+
if (!process.env.ZETA_BYOK_PROVIDER) process.env.ZETA_BYOK_PROVIDER = "openrouter";
|
|
9092
|
+
rest = rest.replace(keyM[0], " ");
|
|
9093
|
+
const k = keyM[1];
|
|
9094
|
+
const masked = k.length > 8 ? `${k.slice(0, 4)}\u2026${k.slice(-2)}` : "\u2026";
|
|
9095
|
+
ctx.print(
|
|
9096
|
+
" " + c.dim(
|
|
9097
|
+
`BYOK key set for this session (provider: ${process.env.ZETA_BYOK_PROVIDER}, key: ${masked}). It is never logged or sent to the model.`
|
|
9098
|
+
)
|
|
9099
|
+
);
|
|
9100
|
+
}
|
|
8508
9101
|
const idea = rest.trim();
|
|
8509
9102
|
if (!idea) {
|
|
8510
9103
|
ctx.print(
|
|
@@ -8516,6 +9109,8 @@ var BUILTINS = [
|
|
|
8516
9109
|
'scope: "full"',
|
|
8517
9110
|
// Sniper by default (lean:true) — skip the marketing campaign. --campaign opts in.
|
|
8518
9111
|
`lean: ${campaign ? "false" : "true"}`,
|
|
9112
|
+
// UNHINGED (--unhinged): skip ALL proofs/gates → fastest bootable app, UNVERIFIED ship.
|
|
9113
|
+
unhinged ? "unhinged: true" : null,
|
|
8519
9114
|
styleId ? `styleId: "${styleId}"` : null,
|
|
8520
9115
|
colorScheme ? `colorScheme: "${colorScheme}"` : null
|
|
8521
9116
|
].filter(Boolean).join(", ");
|
|
@@ -9047,6 +9642,7 @@ var BUILTINS = [
|
|
|
9047
9642
|
...gitCommands,
|
|
9048
9643
|
...eyesCommands,
|
|
9049
9644
|
...opsCommands,
|
|
9645
|
+
...volitionCommands,
|
|
9050
9646
|
...learnedCommands,
|
|
9051
9647
|
...autoRouteCommands,
|
|
9052
9648
|
...skillsCommands,
|
|
@@ -9149,8 +9745,8 @@ var CommandRegistry = class {
|
|
|
9149
9745
|
return this.ordered.flatMap((c2) => [c2.name, ...c2.aliases ?? []]);
|
|
9150
9746
|
}
|
|
9151
9747
|
/** Load *.md commands from ~/.wholestack/commands and <cwd>/.wholestack/commands (or legacy .zeta-g/). */
|
|
9152
|
-
loadCustom(
|
|
9153
|
-
const dirs = [join14(stateDir(), "commands"), ...projectDirs(
|
|
9748
|
+
loadCustom(cwd2) {
|
|
9749
|
+
const dirs = [join14(stateDir(), "commands"), ...projectDirs(cwd2).map((d) => join14(d, "commands"))];
|
|
9154
9750
|
for (const dir of dirs) {
|
|
9155
9751
|
for (const cmd of loadMdCommands(dir, "custom")) this.register(cmd);
|
|
9156
9752
|
}
|
|
@@ -9172,8 +9768,8 @@ var CommandRegistry = class {
|
|
|
9172
9768
|
// src/plugins.ts
|
|
9173
9769
|
import { readFileSync as readFileSync12, existsSync as existsSync14, readdirSync as readdirSync6, statSync as statSync4 } from "fs";
|
|
9174
9770
|
import { join as join15 } from "path";
|
|
9175
|
-
function pluginRoots(
|
|
9176
|
-
return [join15(stateDir(), "plugins"), ...projectDirs(
|
|
9771
|
+
function pluginRoots(cwd2) {
|
|
9772
|
+
return [join15(stateDir(), "plugins"), ...projectDirs(cwd2).map((d) => join15(d, "plugins"))];
|
|
9177
9773
|
}
|
|
9178
9774
|
function resolveSystemPrompt(dir, value) {
|
|
9179
9775
|
const asFile = join15(dir, value);
|
|
@@ -9186,7 +9782,7 @@ function resolveSystemPrompt(dir, value) {
|
|
|
9186
9782
|
}
|
|
9187
9783
|
return value.trim();
|
|
9188
9784
|
}
|
|
9189
|
-
function loadPlugins(
|
|
9785
|
+
function loadPlugins(cwd2) {
|
|
9190
9786
|
const result = {
|
|
9191
9787
|
plugins: [],
|
|
9192
9788
|
systemText: "",
|
|
@@ -9197,7 +9793,7 @@ function loadPlugins(cwd) {
|
|
|
9197
9793
|
};
|
|
9198
9794
|
const systemBlocks = [];
|
|
9199
9795
|
const hookSets = [];
|
|
9200
|
-
for (const root of pluginRoots(
|
|
9796
|
+
for (const root of pluginRoots(cwd2)) {
|
|
9201
9797
|
if (!existsSync14(root)) continue;
|
|
9202
9798
|
for (const entry of readdirSync6(root)) {
|
|
9203
9799
|
const dir = join15(root, entry);
|
|
@@ -9265,11 +9861,11 @@ function readConfigFile(path) {
|
|
|
9265
9861
|
return {};
|
|
9266
9862
|
}
|
|
9267
9863
|
}
|
|
9268
|
-
function discoverConfigs(
|
|
9864
|
+
function discoverConfigs(cwd2) {
|
|
9269
9865
|
const merged = {};
|
|
9270
9866
|
const global = join16(stateDir(), "mcp.json");
|
|
9271
9867
|
if (existsSync15(global)) Object.assign(merged, readConfigFile(global));
|
|
9272
|
-
let dir =
|
|
9868
|
+
let dir = cwd2;
|
|
9273
9869
|
for (let i = 0; i < 24; i++) {
|
|
9274
9870
|
const p = join16(dir, ".mcp.json");
|
|
9275
9871
|
if (existsSync15(p)) {
|
|
@@ -9537,7 +10133,7 @@ function buildWebTools() {
|
|
|
9537
10133
|
// src/input.ts
|
|
9538
10134
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
9539
10135
|
import { emitKeypressEvents } from "readline";
|
|
9540
|
-
import { stdin, stdout } from "process";
|
|
10136
|
+
import { stdin, stdout as stdout2 } from "process";
|
|
9541
10137
|
import { readFileSync as readFileSync14, appendFileSync as appendFileSync2, mkdirSync as mkdirSync6, existsSync as existsSync16, readdirSync as readdirSync7 } from "fs";
|
|
9542
10138
|
import { join as join17, dirname as dirname10, basename as basename2 } from "path";
|
|
9543
10139
|
var HISTORY_FILE = join17(stateDir(), "history");
|
|
@@ -9554,7 +10150,7 @@ var InputController = class {
|
|
|
9554
10150
|
this.opts = opts;
|
|
9555
10151
|
this.rl = createInterface2({
|
|
9556
10152
|
input: stdin,
|
|
9557
|
-
output:
|
|
10153
|
+
output: stdout2,
|
|
9558
10154
|
terminal: stdin.isTTY ?? false,
|
|
9559
10155
|
historySize: HISTORY_MAX,
|
|
9560
10156
|
completer: (line2) => this.complete(line2)
|
|
@@ -9685,7 +10281,7 @@ var InputController = class {
|
|
|
9685
10281
|
});
|
|
9686
10282
|
out += "\r " + c.dim("\u2570" + "\u2500".repeat(W) + "\u256F");
|
|
9687
10283
|
out += up(contentRows - caret.r) + "\r" + right(4 + caret.c);
|
|
9688
|
-
|
|
10284
|
+
stdout2.write(out);
|
|
9689
10285
|
prevRows = contentRows;
|
|
9690
10286
|
prevCaretR = caret.r;
|
|
9691
10287
|
};
|
|
@@ -9697,7 +10293,7 @@ var InputController = class {
|
|
|
9697
10293
|
this.rl.pause();
|
|
9698
10294
|
if (stdin.isTTY) stdin.setRawMode(true);
|
|
9699
10295
|
stdin.resume();
|
|
9700
|
-
|
|
10296
|
+
stdout2.write("\x1B[?2004h");
|
|
9701
10297
|
const onResize = () => {
|
|
9702
10298
|
F = Math.max(8, boxInnerWidth() - 2);
|
|
9703
10299
|
W = F + 2;
|
|
@@ -9708,10 +10304,10 @@ var InputController = class {
|
|
|
9708
10304
|
const finish = (val) => {
|
|
9709
10305
|
stdin.off("keypress", onKey);
|
|
9710
10306
|
process.stdout.off("resize", onResize);
|
|
9711
|
-
|
|
10307
|
+
stdout2.write("\x1B[?2004l");
|
|
9712
10308
|
if (stdin.isTTY) stdin.setRawMode(false);
|
|
9713
10309
|
const down = prevRows - prevCaretR;
|
|
9714
|
-
|
|
10310
|
+
stdout2.write("\x1B[" + Math.max(1, down) + "B\r\n");
|
|
9715
10311
|
this.rl.resume();
|
|
9716
10312
|
if (watching) this.startWatch(watching);
|
|
9717
10313
|
resolve6(val);
|
|
@@ -9723,7 +10319,7 @@ var InputController = class {
|
|
|
9723
10319
|
const onKey = (s, key) => {
|
|
9724
10320
|
const name = key?.name;
|
|
9725
10321
|
if (key?.ctrl && name === "c") {
|
|
9726
|
-
|
|
10322
|
+
stdout2.write("\n");
|
|
9727
10323
|
this.opts.onExit();
|
|
9728
10324
|
return;
|
|
9729
10325
|
}
|
|
@@ -9839,7 +10435,7 @@ var InputController = class {
|
|
|
9839
10435
|
}
|
|
9840
10436
|
};
|
|
9841
10437
|
const bar = this.opts.contextBar?.();
|
|
9842
|
-
if (bar)
|
|
10438
|
+
if (bar) stdout2.write(" " + bar + "\n");
|
|
9843
10439
|
stdin.on("keypress", onKey);
|
|
9844
10440
|
render();
|
|
9845
10441
|
});
|
|
@@ -9946,6 +10542,14 @@ export {
|
|
|
9946
10542
|
writeProjectLink,
|
|
9947
10543
|
writeWorkingTree,
|
|
9948
10544
|
collectLocalFiles,
|
|
10545
|
+
httpBuild,
|
|
10546
|
+
demoBootBuild,
|
|
10547
|
+
deliverBuild,
|
|
10548
|
+
stateDir,
|
|
10549
|
+
webBaseUrl,
|
|
10550
|
+
loadStoredEnv,
|
|
10551
|
+
saveKey,
|
|
10552
|
+
runVolitionSubcommand,
|
|
9949
10553
|
deployBuild,
|
|
9950
10554
|
promoteBuild,
|
|
9951
10555
|
rollbackDeployment,
|
|
@@ -9959,6 +10563,8 @@ export {
|
|
|
9959
10563
|
PROPERTY_KINDS,
|
|
9960
10564
|
runProver,
|
|
9961
10565
|
killRunningApps,
|
|
10566
|
+
isolateFromWorkspace,
|
|
10567
|
+
installDeps,
|
|
9962
10568
|
fetchGithubInstallations,
|
|
9963
10569
|
fetchGithubRepos,
|
|
9964
10570
|
runRepoAuditStream,
|
|
@@ -9966,10 +10572,6 @@ export {
|
|
|
9966
10572
|
readSourceFile,
|
|
9967
10573
|
tasks,
|
|
9968
10574
|
buildTools,
|
|
9969
|
-
stateDir,
|
|
9970
|
-
webBaseUrl,
|
|
9971
|
-
loadStoredEnv,
|
|
9972
|
-
saveKey,
|
|
9973
10575
|
HookRunner,
|
|
9974
10576
|
mergeHookSets,
|
|
9975
10577
|
loadHookFiles,
|