wholestack 0.5.8 → 0.6.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/README.md +7 -7
- package/dist/{chunk-JXARRLAW.js → chunk-C56OI76J.js} +677 -216
- package/dist/cli.js +117 -36
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/skills/fix-failing-build.md +7 -1
- package/skills/review-before-ship.md +6 -0
- package/skills/ship-a-saas.md +7 -1
package/dist/cli.js
CHANGED
|
@@ -75,7 +75,7 @@ import {
|
|
|
75
75
|
webBaseUrl,
|
|
76
76
|
writeProjectLink,
|
|
77
77
|
writeWorkingTree
|
|
78
|
-
} from "./chunk-
|
|
78
|
+
} from "./chunk-C56OI76J.js";
|
|
79
79
|
|
|
80
80
|
// src/cli.ts
|
|
81
81
|
import { createInterface } from "readline/promises";
|
|
@@ -317,7 +317,9 @@ async function renderTree(absDir, relDir) {
|
|
|
317
317
|
} catch {
|
|
318
318
|
return;
|
|
319
319
|
}
|
|
320
|
-
const filtered = entries.filter((e) => !["node_modules", ".git", "dist", ".next", "build", ".turbo"].includes(e.name)).sort(
|
|
320
|
+
const filtered = entries.filter((e) => !["node_modules", ".git", "dist", ".next", "build", ".turbo"].includes(e.name)).sort(
|
|
321
|
+
(a, b) => Number(b.isDirectory()) - Number(a.isDirectory()) || a.name.localeCompare(b.name)
|
|
322
|
+
);
|
|
321
323
|
for (const e of filtered) {
|
|
322
324
|
if (count >= MAX_TREE_ENTRIES) {
|
|
323
325
|
lines.push(`${prefix}\u2026 (truncated)`);
|
|
@@ -473,8 +475,11 @@ function flagValue(args, flag) {
|
|
|
473
475
|
}
|
|
474
476
|
function printFinding(f) {
|
|
475
477
|
line();
|
|
476
|
-
line(
|
|
477
|
-
|
|
478
|
+
line(
|
|
479
|
+
f.loaded ? c.green(" \u2713 loaded") + c.dim(` ${f.url}`) : c.red(" \u2717 not healthy") + c.dim(` ${f.url}`)
|
|
480
|
+
);
|
|
481
|
+
if (f.httpStatus !== null)
|
|
482
|
+
line(c.dim(` HTTP ${f.httpStatus}`) + (f.title ? c.dim(` \xB7 ${f.title}`) : ""));
|
|
478
483
|
if (f.pageErrors.length) {
|
|
479
484
|
line(c.red(` page errors (${f.pageErrors.length}):`));
|
|
480
485
|
for (const e of f.pageErrors.slice(0, 8)) line(" " + c.dim(e));
|
|
@@ -672,7 +677,9 @@ function buildWorkersTool(deps) {
|
|
|
672
677
|
"The complete, self-contained instruction for this worker. It must be doable WITHOUT coordinating with the other workers (they run concurrently in separate worktrees)."
|
|
673
678
|
)
|
|
674
679
|
})
|
|
675
|
-
).min(1).max(maxWorkers).describe(
|
|
680
|
+
).min(1).max(maxWorkers).describe(
|
|
681
|
+
`1\u2013${maxWorkers} INDEPENDENT, edit-heavy tasks to run concurrently in isolated worktrees.`
|
|
682
|
+
)
|
|
676
683
|
}),
|
|
677
684
|
execute: async ({ tasks: tasks2 }) => {
|
|
678
685
|
if (deps.ctx.permissions.guardMutation() === "deny") {
|
|
@@ -800,8 +807,10 @@ async function runOpsSubcommand(raw) {
|
|
|
800
807
|
line(
|
|
801
808
|
" connected: " + (m.connected.posthog ? c.green("posthog") : c.dim("posthog")) + " \xB7 " + (m.connected.stripe ? c.green("stripe") : c.dim("stripe"))
|
|
802
809
|
);
|
|
803
|
-
if (m.traffic)
|
|
804
|
-
|
|
810
|
+
if (m.traffic)
|
|
811
|
+
line(" " + c.dim(`visitors 7d ${m.traffic.visitors7d} \xB7 signups 7d ${m.traffic.signups7d}`));
|
|
812
|
+
if (m.revenue)
|
|
813
|
+
line(" " + c.dim(`MRR $${m.revenue.mrr} \xB7 subs ${m.revenue.activeSubscriptions}`));
|
|
805
814
|
return 0;
|
|
806
815
|
}
|
|
807
816
|
if (verb === "errors") {
|
|
@@ -831,7 +840,9 @@ async function runOpsSubcommand(raw) {
|
|
|
831
840
|
return 0;
|
|
832
841
|
}
|
|
833
842
|
line(c.red(` unknown: wholestack ops ${verb ?? ""}`));
|
|
834
|
-
line(
|
|
843
|
+
line(
|
|
844
|
+
c.dim(" verbs: health <url> \xB7 status <deploymentId> [buildId] \xB7 metrics \xB7 errors (+ --json)")
|
|
845
|
+
);
|
|
835
846
|
return 1;
|
|
836
847
|
}
|
|
837
848
|
|
|
@@ -851,12 +862,19 @@ function buildLearnedMemoryTools(deps) {
|
|
|
851
862
|
description: "Record ONE durable lesson learned this session so future sessions inherit it (cross-session memory). Use after finishing a non-trivial task to capture: a pattern that WORKED, an approach that FAILED, or a project QUIRK. Keep it to a single atomic fact \u2014 one lesson per call. Auto-loaded into the system prompt at the start of every session.",
|
|
852
863
|
inputSchema: z3.object({
|
|
853
864
|
text: z3.string().min(4).describe("The lesson \u2014 one self-contained, durable fact. Be specific and actionable."),
|
|
854
|
-
kind: z3.enum(KIND_VALUES).default("note").describe(
|
|
855
|
-
|
|
856
|
-
|
|
865
|
+
kind: z3.enum(KIND_VALUES).default("note").describe(
|
|
866
|
+
"worked = a pattern that worked; failed = a dead end to avoid; quirk = a project gotcha; note = general."
|
|
867
|
+
),
|
|
868
|
+
tags: z3.array(z3.string()).optional().describe(
|
|
869
|
+
"Optional keywords to make this lesson findable later, e.g. ['prisma','migrations']."
|
|
870
|
+
),
|
|
871
|
+
scope: z3.string().optional().describe(
|
|
872
|
+
"Project/repo this applies to. Omit to use the current project; use 'global' for everywhere."
|
|
873
|
+
)
|
|
857
874
|
}),
|
|
858
875
|
execute: async ({ text, kind, tags, scope }) => {
|
|
859
|
-
if (permissions.guardMutation() === "deny")
|
|
876
|
+
if (permissions.guardMutation() === "deny")
|
|
877
|
+
return { ok: false, error: permissions.planRefusal() };
|
|
860
878
|
try {
|
|
861
879
|
const saved = rememberLesson({
|
|
862
880
|
text,
|
|
@@ -882,7 +900,9 @@ function buildLearnedMemoryTools(deps) {
|
|
|
882
900
|
recall: tool3({
|
|
883
901
|
description: "Search the lessons you learned in earlier sessions (cross-session memory). Use to check whether you've already solved something here, or to review what worked/failed before. Returns matching lessons newest-first. Lessons from the current project plus any 'global' lessons are always eligible.",
|
|
884
902
|
inputSchema: z3.object({
|
|
885
|
-
query: z3.string().optional().describe(
|
|
903
|
+
query: z3.string().optional().describe(
|
|
904
|
+
"Free-text search over lesson bodies, tags, and kind. Omit to list everything."
|
|
905
|
+
),
|
|
886
906
|
scope: z3.string().optional().describe("Limit to a project/repo (plus global). Omit to use the current project."),
|
|
887
907
|
limit: z3.number().int().min(1).max(50).default(10).describe("Max lessons to return.")
|
|
888
908
|
}),
|
|
@@ -1443,7 +1463,8 @@ function parse(raw) {
|
|
|
1443
1463
|
else if (t === "--nzt48" || t === "--nzt-48") a.persona = "nzt-48";
|
|
1444
1464
|
else if (t === "--think") a.think = true;
|
|
1445
1465
|
else if (t === "--no-think") a.think = false;
|
|
1446
|
-
else if (t === "--mcp")
|
|
1466
|
+
else if (t === "--mcp")
|
|
1467
|
+
a.mcp = (raw[++i] ?? "").split(",").map((s) => s.trim()).filter(Boolean);
|
|
1447
1468
|
else if (t === "--no-mcp") a.noMcp = true;
|
|
1448
1469
|
else if (t === "--no-plugins") a.noPlugins = true;
|
|
1449
1470
|
else if (t === "--print" || t === "-p") a.print = true;
|
|
@@ -1590,7 +1611,9 @@ async function runGithubSubcommand(raw) {
|
|
|
1590
1611
|
line();
|
|
1591
1612
|
return 0;
|
|
1592
1613
|
}
|
|
1593
|
-
line(
|
|
1614
|
+
line(
|
|
1615
|
+
c.red(" usage: wholestack github installations | wholestack github repos --installation <id>")
|
|
1616
|
+
);
|
|
1594
1617
|
return 1;
|
|
1595
1618
|
}
|
|
1596
1619
|
async function runAuditRepoSubcommand(rest) {
|
|
@@ -1653,7 +1676,9 @@ async function runAuditRepoSubcommand(rest) {
|
|
|
1653
1676
|
return 1;
|
|
1654
1677
|
}
|
|
1655
1678
|
const verdict = String(r.result.verdict ?? r.result.shipVerdict ?? "unknown");
|
|
1656
|
-
line(
|
|
1679
|
+
line(
|
|
1680
|
+
verdict === "SHIP" || verdict === "ship" ? c.green(" \u2713 SHIP") : c.yellow(` verdict: ${verdict}`)
|
|
1681
|
+
);
|
|
1657
1682
|
if (r.result.certificateUrl) line(c.dim(` certificate: ${r.result.certificateUrl}`));
|
|
1658
1683
|
if (r.result.bundleId) line(c.dim(` bundle: ${base2}/api/audit/bundle/${r.result.bundleId}`));
|
|
1659
1684
|
return 0;
|
|
@@ -1711,7 +1736,12 @@ async function runProveSubcommand(raw) {
|
|
|
1711
1736
|
if (data?.upgradeUrl) line(c.dim(` upgrade: ${base2}${data.upgradeUrl}`));
|
|
1712
1737
|
return 1;
|
|
1713
1738
|
}
|
|
1714
|
-
printProveVerdict(
|
|
1739
|
+
printProveVerdict(
|
|
1740
|
+
data.verdict ?? "NO_SHIP",
|
|
1741
|
+
data.score ?? 0,
|
|
1742
|
+
data.checks ?? [],
|
|
1743
|
+
data.blockingReasons ?? []
|
|
1744
|
+
);
|
|
1715
1745
|
return data.verdict === "SHIP" ? 0 : 1;
|
|
1716
1746
|
}
|
|
1717
1747
|
const path = rest.find((a) => !a.startsWith("-")) ?? cwd2();
|
|
@@ -1725,7 +1755,9 @@ async function runProveSubcommand(raw) {
|
|
|
1725
1755
|
return result.verdict === "SHIP" ? 0 : 1;
|
|
1726
1756
|
}
|
|
1727
1757
|
line();
|
|
1728
|
-
line(
|
|
1758
|
+
line(
|
|
1759
|
+
c.cyan(" \u259F ISL prove-gate") + c.dim(" \xB7 deterministic \xB7 fail-closed \xB7 foreign default-deny")
|
|
1760
|
+
);
|
|
1729
1761
|
line();
|
|
1730
1762
|
printProveVerdict(result.verdict, result.score, result.checks, result.blockingReasons);
|
|
1731
1763
|
return result.verdict === "SHIP" ? 0 : 1;
|
|
@@ -1867,7 +1899,11 @@ async function runProjectSubcommand(raw) {
|
|
|
1867
1899
|
return 1;
|
|
1868
1900
|
}
|
|
1869
1901
|
if (!r2.projects?.length) {
|
|
1870
|
-
line(
|
|
1902
|
+
line(
|
|
1903
|
+
c.dim(
|
|
1904
|
+
' no projects yet \u2014 build something (`wholestack "an idea"`) or create one in the web IDE.'
|
|
1905
|
+
)
|
|
1906
|
+
);
|
|
1871
1907
|
return 0;
|
|
1872
1908
|
}
|
|
1873
1909
|
line();
|
|
@@ -1877,7 +1913,9 @@ async function runProjectSubcommand(raw) {
|
|
|
1877
1913
|
if (p.description) line(" " + c.dim(` ${p.description}`));
|
|
1878
1914
|
}
|
|
1879
1915
|
line();
|
|
1880
|
-
line(
|
|
1916
|
+
line(
|
|
1917
|
+
c.dim(" pull one with ") + c.cyan("wholestack pull <id>") + c.dim(" \xB7 open in the IDE at ") + c.cyan(`${base2}/ide/studio?projectId=<id>`)
|
|
1918
|
+
);
|
|
1881
1919
|
return 0;
|
|
1882
1920
|
}
|
|
1883
1921
|
if (verb === "pull") {
|
|
@@ -1895,7 +1933,9 @@ async function runProjectSubcommand(raw) {
|
|
|
1895
1933
|
const written = writeWorkingTree(dest, r2.files ?? []);
|
|
1896
1934
|
writeProjectLink(dest, { projectId });
|
|
1897
1935
|
line(c.green(` \u2713 pulled ${written} files`) + c.dim(` \u2192 ${dest}/`));
|
|
1898
|
-
line(
|
|
1936
|
+
line(
|
|
1937
|
+
c.dim(" edit locally, then ") + c.cyan(`wholestack push ${dest === "." ? "" : dest}`).trimEnd() + c.dim(" to sync back to the web IDE.")
|
|
1938
|
+
);
|
|
1899
1939
|
return 0;
|
|
1900
1940
|
}
|
|
1901
1941
|
if (verb === "push") {
|
|
@@ -1918,7 +1958,9 @@ async function runProjectSubcommand(raw) {
|
|
|
1918
1958
|
return 1;
|
|
1919
1959
|
}
|
|
1920
1960
|
writeProjectLink(dir, { projectId });
|
|
1921
|
-
line(
|
|
1961
|
+
line(
|
|
1962
|
+
c.green(` \u2713 pushed ${files.length} files`) + c.dim(skipped ? ` (${skipped} skipped: binary/oversize)` : "")
|
|
1963
|
+
);
|
|
1922
1964
|
line(c.dim(" open it: ") + c.cyan(`${base2}/ide/studio?projectId=${projectId}`));
|
|
1923
1965
|
return 0;
|
|
1924
1966
|
}
|
|
@@ -1949,7 +1991,9 @@ async function runShipSubcommand(raw) {
|
|
|
1949
1991
|
}
|
|
1950
1992
|
if (verb === "deploy") {
|
|
1951
1993
|
line();
|
|
1952
|
-
line(
|
|
1994
|
+
line(
|
|
1995
|
+
c.cyan(" \u259F deploy") + c.dim(" \xB7 deploy & host with us (managed add-on) \u2014 or own the code on Pro and self-host")
|
|
1996
|
+
);
|
|
1953
1997
|
const r2 = await deployBuild(base2, buildId, {
|
|
1954
1998
|
poll: true,
|
|
1955
1999
|
onPhase: (s) => line(c.dim(` \xB7 ${s}`))
|
|
@@ -2031,7 +2075,8 @@ async function runLaunchSubcommand(raw) {
|
|
|
2031
2075
|
}
|
|
2032
2076
|
async function runHqSubcommand(raw) {
|
|
2033
2077
|
const verb = raw[0];
|
|
2034
|
-
if (!["legal", "metrics", "waitlist", "businesses", "business", "styles"].includes(verb))
|
|
2078
|
+
if (!["legal", "metrics", "waitlist", "businesses", "business", "styles"].includes(verb))
|
|
2079
|
+
return null;
|
|
2035
2080
|
const base2 = webBaseUrl();
|
|
2036
2081
|
const rest = raw.slice(1);
|
|
2037
2082
|
const wantsJson = rest.includes("--json");
|
|
@@ -2055,7 +2100,9 @@ async function runHqSubcommand(raw) {
|
|
|
2055
2100
|
const idea = rest.filter((a) => !a.startsWith("-")).join(" ").trim();
|
|
2056
2101
|
let data;
|
|
2057
2102
|
try {
|
|
2058
|
-
const res = await fetch(
|
|
2103
|
+
const res = await fetch(
|
|
2104
|
+
`${base2}/api/zeta/styles${idea ? `?idea=${encodeURIComponent(idea)}` : ""}`
|
|
2105
|
+
);
|
|
2059
2106
|
if (!res.ok) throw new Error(`HTTP ${res.status}`);
|
|
2060
2107
|
data = await res.json();
|
|
2061
2108
|
} catch (e) {
|
|
@@ -2067,14 +2114,20 @@ async function runHqSubcommand(raw) {
|
|
|
2067
2114
|
return 0;
|
|
2068
2115
|
}
|
|
2069
2116
|
if (data.recommended) {
|
|
2070
|
-
line(
|
|
2117
|
+
line(
|
|
2118
|
+
" " + c.bold("Recommended: ") + c.cyan(data.recommended.id) + c.dim(` \u2014 ${data.recommended.why}`)
|
|
2119
|
+
);
|
|
2071
2120
|
if (data.recommended.alternatives?.length) {
|
|
2072
2121
|
line(" " + c.dim(` also: ${data.recommended.alternatives.join(", ")}`));
|
|
2073
2122
|
}
|
|
2074
2123
|
line("");
|
|
2075
2124
|
}
|
|
2076
2125
|
const styles = data.styles ?? [];
|
|
2077
|
-
line(
|
|
2126
|
+
line(
|
|
2127
|
+
" " + c.dim(
|
|
2128
|
+
`${styles.length} Launch Styles \u2014 build in one with: wholestack build \u2026 --style <id>`
|
|
2129
|
+
)
|
|
2130
|
+
);
|
|
2078
2131
|
for (const s of styles) line(" " + c.cyan(String(s.id).padEnd(20)) + c.dim(s.aesthetic));
|
|
2079
2132
|
return 0;
|
|
2080
2133
|
}
|
|
@@ -2150,8 +2203,10 @@ var EMPTY_PLUGINS = {
|
|
|
2150
2203
|
function bootSummary(memory, plugins, mcp, mode, thinking) {
|
|
2151
2204
|
const bits = [`mode ${c.yellow(mode)}`];
|
|
2152
2205
|
if (thinking) bits.push("thinking on");
|
|
2153
|
-
if (memory.sources.length)
|
|
2154
|
-
|
|
2206
|
+
if (memory.sources.length)
|
|
2207
|
+
bits.push(`${memory.sources.length} memory file${memory.sources.length === 1 ? "" : "s"}`);
|
|
2208
|
+
if (plugins.plugins.length)
|
|
2209
|
+
bits.push(`${plugins.plugins.length} plugin${plugins.plugins.length === 1 ? "" : "s"}`);
|
|
2155
2210
|
if (mcp.mounted.length) bits.push(`${mcp.mounted.length} mcp`);
|
|
2156
2211
|
line(" " + c.dim(bits.join(" \xB7 ")));
|
|
2157
2212
|
for (const s of memory.sources) line(" " + c.dim(` memory: ${s.path}`));
|
|
@@ -2200,7 +2255,11 @@ async function main() {
|
|
|
2200
2255
|
if (!access.active && stdin.isTTY) {
|
|
2201
2256
|
line();
|
|
2202
2257
|
line(" " + c.bold("Sign in to use Wholestack"));
|
|
2203
|
-
line(
|
|
2258
|
+
line(
|
|
2259
|
+
" " + c.dim(
|
|
2260
|
+
token ? "Your session expired." : "The agent is free \u2014 make, edit & preview unlimited. Sign in to start."
|
|
2261
|
+
)
|
|
2262
|
+
);
|
|
2204
2263
|
const rl = createInterface({ input: stdin, output: stdout3 });
|
|
2205
2264
|
const ans = (await rl.question(
|
|
2206
2265
|
" " + c.dim("Open the browser to sign in with Google? ") + c.dim("[Y/n] ")
|
|
@@ -2312,7 +2371,13 @@ async function main() {
|
|
|
2312
2371
|
};
|
|
2313
2372
|
const permissions = new Permissions(mode, confirm, persistMode);
|
|
2314
2373
|
const checkpoints = new CheckpointStore();
|
|
2315
|
-
const toolCtx = {
|
|
2374
|
+
const toolCtx = {
|
|
2375
|
+
cwd: workdir,
|
|
2376
|
+
zetaApiUrl: args.zetaUrl,
|
|
2377
|
+
buildMode: args.buildMode,
|
|
2378
|
+
permissions,
|
|
2379
|
+
checkpoints
|
|
2380
|
+
};
|
|
2316
2381
|
const extraTools = {
|
|
2317
2382
|
...buildWebTools(),
|
|
2318
2383
|
...mcp.tools,
|
|
@@ -2385,7 +2450,8 @@ ${m.context}` : args.prompt;
|
|
|
2385
2450
|
bootSummary(memory, plugins, mcp, mode, thinking);
|
|
2386
2451
|
if (mode === "plan") announcePlanMode();
|
|
2387
2452
|
else if (yoloIsDefault) maybeYoloNotice();
|
|
2388
|
-
if (resumedMessages)
|
|
2453
|
+
if (resumedMessages)
|
|
2454
|
+
line(" " + c.dim(`resumed ${session.meta.id} \xB7 ${resumedMessages.length} messages`) + "\n");
|
|
2389
2455
|
void checkForUpdate(VERSION).then((latest) => {
|
|
2390
2456
|
if (latest) {
|
|
2391
2457
|
line(
|
|
@@ -2496,7 +2562,12 @@ ${m.context}` : args.prompt;
|
|
|
2496
2562
|
} else if (res.type === "export") {
|
|
2497
2563
|
const file = res.file ?? `zeta-transcript-${gitBranch(workdir) || "session"}.md`;
|
|
2498
2564
|
try {
|
|
2499
|
-
const abs = writeTranscript(
|
|
2565
|
+
const abs = writeTranscript(
|
|
2566
|
+
agent.snapshot(),
|
|
2567
|
+
{ model: modelLabel(modelKey) },
|
|
2568
|
+
file,
|
|
2569
|
+
workdir
|
|
2570
|
+
);
|
|
2500
2571
|
line(" " + c.green(`\u2713 transcript \u2192 ${abs}`) + "\n");
|
|
2501
2572
|
} catch (e) {
|
|
2502
2573
|
line(" " + c.red(e.message) + "\n");
|
|
@@ -2519,17 +2590,27 @@ ${m.context}` : args.prompt;
|
|
|
2519
2590
|
modelKey = vkey;
|
|
2520
2591
|
agent.setModel(resolveModel(vkey), vkey, modelContextWindow(vkey));
|
|
2521
2592
|
agent.setThinking(false);
|
|
2522
|
-
line(
|
|
2593
|
+
line(
|
|
2594
|
+
c.dim(
|
|
2595
|
+
` \u29C9 image attached \u2192 switched to ${modelLabel(vkey)} (/model zeta-g1 to switch back)`
|
|
2596
|
+
) + "\n"
|
|
2597
|
+
);
|
|
2523
2598
|
} catch (e) {
|
|
2524
2599
|
line(c.red(` \u29C9 couldn't switch to the vision lane: ${e.message}`) + "\n");
|
|
2525
2600
|
}
|
|
2526
2601
|
}
|
|
2527
2602
|
if (visionCapable(modelKey)) {
|
|
2528
2603
|
attachments = imgs.images.map((i) => ({ dataUrl: i.dataUrl }));
|
|
2529
|
-
line(
|
|
2604
|
+
line(
|
|
2605
|
+
c.dim(
|
|
2606
|
+
` \u29C9 attached ${imgs.images.length} image(s): ${imgs.images.map((i) => i.path).join(", ")}`
|
|
2607
|
+
) + "\n"
|
|
2608
|
+
);
|
|
2530
2609
|
} else {
|
|
2531
2610
|
line(
|
|
2532
|
-
c.yellow(
|
|
2611
|
+
c.yellow(
|
|
2612
|
+
` \u29C9 ${imgs.images.length} image(s) ignored \u2014 ${modelLabel(modelKey)} is text-only.`
|
|
2613
|
+
) + c.dim(" set OPENROUTER_API_KEY (or /model vision) to enable Zeta-G1.0 Vision") + "\n"
|
|
2533
2614
|
);
|
|
2534
2615
|
}
|
|
2535
2616
|
}
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wholestack",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
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",
|
|
@@ -9,14 +9,17 @@ when-to-use: When a build errors, tests fail, the prove gate returns NO_SHIP, or
|
|
|
9
9
|
Work from evidence, not guesses. Fix the ROOT cause, not the symptom, then prove the fix.
|
|
10
10
|
|
|
11
11
|
## 1. Collect the real failure
|
|
12
|
+
|
|
12
13
|
- Get the exact error text: prove `blockingReasons`, the build/run log, the failing test, or the compiler error.
|
|
13
14
|
- Quote the precise message and the file:line it points at. Do not paraphrase a guess.
|
|
14
15
|
|
|
15
16
|
## 2. Locate
|
|
17
|
+
|
|
16
18
|
- Read the file(s) the error names. If the cause is unclear, grep for the failing symbol/string across the repo.
|
|
17
19
|
- For breadth (several suspect areas at once), fan out read-only sub-agents, one per hypothesis.
|
|
18
20
|
|
|
19
21
|
## 3. Identify the root cause
|
|
22
|
+
|
|
20
23
|
- Map the message to a cause, e.g.:
|
|
21
24
|
- module-not-found / unresolved import → missing dep or wrong path.
|
|
22
25
|
- type mismatch → fix the type, never silence with `as any`.
|
|
@@ -25,14 +28,17 @@ Work from evidence, not guesses. Fix the ROOT cause, not the symptom, then prove
|
|
|
25
28
|
- State the root cause in one sentence before editing.
|
|
26
29
|
|
|
27
30
|
## 4. Apply the minimal fix
|
|
31
|
+
|
|
28
32
|
- Make the smallest change that addresses the cause. Match the surrounding code's patterns and conventions.
|
|
29
33
|
- Avoid scope creep — fix the failure, not unrelated nits.
|
|
30
34
|
|
|
31
35
|
## 5. Re-verify (mandatory)
|
|
36
|
+
|
|
32
37
|
- Re-run whatever was red: build, run, the failing test, AND the prove gate.
|
|
33
38
|
- A fix is only done when the previously-red signal is now green. If still red, return to step 1 with the new error.
|
|
34
39
|
|
|
35
40
|
## Done criteria
|
|
41
|
+
|
|
36
42
|
- The original failing signal now passes.
|
|
37
43
|
- If this was a NO_SHIP, the prove verdict is now SHIP.
|
|
38
|
-
Report the root cause and the now-green verification.
|
|
44
|
+
Report the root cause and the now-green verification.
|
|
@@ -9,26 +9,32 @@ when-to-use: When the user asks for a review, a sanity check, or "is this ready
|
|
|
9
9
|
A quick, evidence-based pass to catch what an automated gate can miss. Report findings by severity; do not rubber-stamp.
|
|
10
10
|
|
|
11
11
|
## 1. Scope the diff
|
|
12
|
+
|
|
12
13
|
- Identify what actually changed (the files touched this session, or the generated app's entities/routes).
|
|
13
14
|
- Skip unchanged code — review the delta.
|
|
14
15
|
|
|
15
16
|
## 2. Correctness
|
|
17
|
+
|
|
16
18
|
- Do the new/changed functions do what their name says? Check the obvious edge cases (empty input, error path).
|
|
17
19
|
- Look for swallowed errors: empty catch blocks, try/catch that ignores, handlers that return 200 for everything.
|
|
18
20
|
|
|
19
21
|
## 3. Security
|
|
22
|
+
|
|
20
23
|
- Any endpoint touching sensitive data must enforce auth/ownership — flag unprotected ones.
|
|
21
24
|
- No secrets in client code; server-only keys stay server-side.
|
|
22
25
|
- DB access is parameterized (no string-interpolated queries).
|
|
23
26
|
|
|
24
27
|
## 4. Fake-success
|
|
28
|
+
|
|
25
29
|
- Functions that always return success regardless of input.
|
|
26
30
|
- Loading states with no error state.
|
|
27
31
|
- A "pass" that doesn't bind the real artifact (a proof that can't actually fail is no proof).
|
|
28
32
|
|
|
29
33
|
## 5. Run the gate
|
|
34
|
+
|
|
30
35
|
- Run the prove gate and read the verdict alongside your manual findings.
|
|
31
36
|
|
|
32
37
|
## Done criteria
|
|
38
|
+
|
|
33
39
|
- Findings listed by severity (critical / high / medium / low) with file:line and a concrete fix each.
|
|
34
40
|
- A clear go / no-go recommendation, reconciled with the prove verdict.
|
package/skills/ship-a-saas.md
CHANGED
|
@@ -9,31 +9,37 @@ when-to-use: When the user wants to build AND ship a full SaaS — "ship this",
|
|
|
9
9
|
Follow these steps in order. After each step, report what happened before moving on. Do not skip the prove gate — a NO_SHIP verdict blocks deploy.
|
|
10
10
|
|
|
11
11
|
## 1. Clarify the build
|
|
12
|
+
|
|
12
13
|
- Restate the app in one sentence (what it does, who it's for).
|
|
13
14
|
- If the idea is too vague to generate (no core entities/actions), ask ONE focused question, then proceed.
|
|
14
15
|
|
|
15
16
|
## 2. Generate
|
|
17
|
+
|
|
16
18
|
- Use the build tool to generate the full-stack app from the idea.
|
|
17
19
|
- Capture the resulting `buildId` — every later step keys off the linked build.
|
|
18
20
|
- If generation fails, switch to the `fix-failing-build` skill, then return here.
|
|
19
21
|
|
|
20
22
|
## 3. Prove (ShipGate — the gate)
|
|
23
|
+
|
|
21
24
|
- Run the prove gate on the generated repo.
|
|
22
25
|
- Read the `verdict`:
|
|
23
26
|
- `SHIP` → continue to deploy.
|
|
24
27
|
- `NO_SHIP` → STOP. List the `blockingReasons` plainly. Fix the underlying issue (often via `fix-failing-build`), regenerate or edit, then re-prove. Never deploy a NO_SHIP build.
|
|
25
28
|
|
|
26
29
|
## 4. Deploy
|
|
30
|
+
|
|
27
31
|
- Only after a SHIP verdict, deploy the build (the linked `buildId`).
|
|
28
32
|
- Report the live URL and the deploy status. If a database was provisioned, say so.
|
|
29
33
|
|
|
30
34
|
## 5. Launch kit
|
|
35
|
+
|
|
31
36
|
- Pull the launch kit for the build (brand, pricing, copy, social, email, pitch, analytics, checklist).
|
|
32
37
|
- Summarize what's ready and what the founder still needs to fill in.
|
|
33
38
|
- Offer the next concrete action (custom domain, payments, waitlist, first campaign).
|
|
34
39
|
|
|
35
40
|
## Done criteria
|
|
41
|
+
|
|
36
42
|
- A SHIP verdict was recorded.
|
|
37
43
|
- A live URL was returned.
|
|
38
44
|
- The launch kit was surfaced.
|
|
39
|
-
Report all three back to the user.
|
|
45
|
+
Report all three back to the user.
|