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/dist/cli.js CHANGED
@@ -75,7 +75,7 @@ import {
75
75
  webBaseUrl,
76
76
  writeProjectLink,
77
77
  writeWorkingTree
78
- } from "./chunk-JXARRLAW.js";
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((a, b) => Number(b.isDirectory()) - Number(a.isDirectory()) || a.name.localeCompare(b.name));
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(f.loaded ? c.green(" \u2713 loaded") + c.dim(` ${f.url}`) : c.red(" \u2717 not healthy") + c.dim(` ${f.url}`));
477
- if (f.httpStatus !== null) line(c.dim(` HTTP ${f.httpStatus}`) + (f.title ? c.dim(` \xB7 ${f.title}`) : ""));
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(`1\u2013${maxWorkers} INDEPENDENT, edit-heavy tasks to run concurrently in isolated worktrees.`)
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) line(" " + c.dim(`visitors 7d ${m.traffic.visitors7d} \xB7 signups 7d ${m.traffic.signups7d}`));
804
- if (m.revenue) line(" " + c.dim(`MRR $${m.revenue.mrr} \xB7 subs ${m.revenue.activeSubscriptions}`));
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(c.dim(" verbs: health <url> \xB7 status <deploymentId> [buildId] \xB7 metrics \xB7 errors (+ --json)"));
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("worked = a pattern that worked; failed = a dead end to avoid; quirk = a project gotcha; note = general."),
855
- tags: z3.array(z3.string()).optional().describe("Optional keywords to make this lesson findable later, e.g. ['prisma','migrations']."),
856
- scope: z3.string().optional().describe("Project/repo this applies to. Omit to use the current project; use 'global' for everywhere.")
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") return { ok: false, error: permissions.planRefusal() };
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("Free-text search over lesson bodies, tags, and kind. Omit to list everything."),
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") a.mcp = (raw[++i] ?? "").split(",").map((s) => s.trim()).filter(Boolean);
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(c.red(" usage: wholestack github installations | wholestack github repos --installation <id>"));
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(verdict === "SHIP" || verdict === "ship" ? c.green(" \u2713 SHIP") : c.yellow(` verdict: ${verdict}`));
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(data.verdict ?? "NO_SHIP", data.score ?? 0, data.checks ?? [], data.blockingReasons ?? []);
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(c.cyan(" \u259F ISL prove-gate") + c.dim(" \xB7 deterministic \xB7 fail-closed \xB7 foreign default-deny"));
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(c.dim(' no projects yet \u2014 build something (`wholestack "an idea"`) or create one in the web IDE.'));
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(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>`));
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(c.dim(" edit locally, then ") + c.cyan(`wholestack push ${dest === "." ? "" : dest}`).trimEnd() + c.dim(" to sync back to the web IDE."));
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(c.green(` \u2713 pushed ${files.length} files`) + c.dim(skipped ? ` (${skipped} skipped: binary/oversize)` : ""));
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(c.cyan(" \u259F deploy") + c.dim(" \xB7 deploy & host with us (managed add-on) \u2014 or own the code on Pro and self-host"));
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)) return null;
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(`${base2}/api/zeta/styles${idea ? `?idea=${encodeURIComponent(idea)}` : ""}`);
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(" " + c.bold("Recommended: ") + c.cyan(data.recommended.id) + c.dim(` \u2014 ${data.recommended.why}`));
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(" " + c.dim(`${styles.length} Launch Styles \u2014 build in one with: wholestack build \u2026 --style <id>`));
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) bits.push(`${memory.sources.length} memory file${memory.sources.length === 1 ? "" : "s"}`);
2154
- if (plugins.plugins.length) bits.push(`${plugins.plugins.length} plugin${plugins.plugins.length === 1 ? "" : "s"}`);
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(" " + c.dim(token ? "Your session expired." : "The agent is free \u2014 make, edit & preview unlimited. Sign in to start."));
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 = { cwd: workdir, zetaApiUrl: args.zetaUrl, buildMode: args.buildMode, permissions, checkpoints };
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) line(" " + c.dim(`resumed ${session.meta.id} \xB7 ${resumedMessages.length} messages`) + "\n");
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(agent.snapshot(), { model: modelLabel(modelKey) }, file, workdir);
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(c.dim(` \u29C9 image attached \u2192 switched to ${modelLabel(vkey)} (/model zeta-g1 to switch back)`) + "\n");
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(c.dim(` \u29C9 attached ${imgs.images.length} image(s): ${imgs.images.map((i) => i.path).join(", ")}`) + "\n");
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(` \u29C9 ${imgs.images.length} image(s) ignored \u2014 ${modelLabel(modelKey)} is text-only.`) + c.dim(" set OPENROUTER_API_KEY (or /model vision) to enable Zeta-G1.0 Vision") + "\n"
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
@@ -465,6 +465,7 @@ declare function buildTools(ctx: ToolContext): {
465
465
  }>;
466
466
  generate_app: ai.Tool<{
467
467
  idea: string;
468
+ lean: boolean;
468
469
  install: boolean;
469
470
  scope: "full" | "static" | "component" | "page";
470
471
  buildModel: "zeta-g1" | "zeta-g1-max";
package/dist/index.js CHANGED
@@ -49,7 +49,7 @@ import {
49
49
  resolveModelKey,
50
50
  severityRank,
51
51
  supportsThinking
52
- } from "./chunk-JXARRLAW.js";
52
+ } from "./chunk-C56OI76J.js";
53
53
 
54
54
  // src/prompts/template.ts
55
55
  var PLACEHOLDER = /\{\{([A-Za-z0-9_.]+)\}\}/g;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wholestack",
3
- "version": "0.5.8",
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.
@@ -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.