sproutkit-code 0.6.0 → 0.8.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/index.js CHANGED
@@ -35355,21 +35355,21 @@ var require_cross_spawn = __commonJS({
35355
35355
  var cp = require("child_process");
35356
35356
  var parse = require_parse();
35357
35357
  var enoent = require_enoent();
35358
- function spawn(command, args, options) {
35358
+ function spawn2(command, args, options) {
35359
35359
  const parsed = parse(command, args, options);
35360
35360
  const spawned = cp.spawn(parsed.command, parsed.args, parsed.options);
35361
35361
  enoent.hookChildProcess(spawned, parsed);
35362
35362
  return spawned;
35363
35363
  }
35364
- function spawnSync2(command, args, options) {
35364
+ function spawnSync3(command, args, options) {
35365
35365
  const parsed = parse(command, args, options);
35366
35366
  const result = cp.spawnSync(parsed.command, parsed.args, parsed.options);
35367
35367
  result.error = result.error || enoent.verifyENOENTSync(result.status, parsed);
35368
35368
  return result;
35369
35369
  }
35370
- module2.exports = spawn;
35371
- module2.exports.spawn = spawn;
35372
- module2.exports.sync = spawnSync2;
35370
+ module2.exports = spawn2;
35371
+ module2.exports.spawn = spawn2;
35372
+ module2.exports.sync = spawnSync3;
35373
35373
  module2.exports._parse = parse;
35374
35374
  module2.exports._enoent = enoent;
35375
35375
  }
@@ -79482,6 +79482,7 @@ var require_builder = __commonJS({
79482
79482
  exports2.buildAndDeploySite = buildAndDeploySite;
79483
79483
  exports2.redeployCmsOnly = redeployCmsOnly;
79484
79484
  exports2.deployBookingOnly = deployBookingOnly2;
79485
+ exports2.deployStandaloneBooking = deployStandaloneBooking2;
79485
79486
  var sdk_1 = __importDefault(require_sdk());
79486
79487
  var axios_1 = __importDefault(require_axios());
79487
79488
  var runtime_1 = require_runtime();
@@ -80372,6 +80373,63 @@ export default defineConfig({ plugins: [react()] });`;
80372
80373
  onProgress(`Live at ${publicUrl}`);
80373
80374
  return { url: publicUrl, bookingUrl: `${publicUrl}/book` };
80374
80375
  }
80376
+ async function deployStandaloneBooking2(args) {
80377
+ const { lead, vercelToken, blobToken, resendKey, ownerEmail, bookingConfig, onProgress } = args;
80378
+ const slug = lead.name.toLowerCase().replace(/[^a-z0-9]/g, "-").replace(/-+/g, "-").slice(0, 26);
80379
+ const projectName = `sprout-book-${lead.id}-${slug}`;
80380
+ onProgress("Seeding booking config\u2026");
80381
+ try {
80382
+ const { put } = await Promise.resolve().then(() => __importStar(require_dist5()));
80383
+ await put("booking-config.json", JSON.stringify(bookingConfig), {
80384
+ access: "public",
80385
+ addRandomSuffix: false,
80386
+ allowOverwrite: true,
80387
+ contentType: "application/json",
80388
+ token: blobToken
80389
+ });
80390
+ } catch (e) {
80391
+ throw new Error(`Failed to seed booking config: ${e.message}`);
80392
+ }
80393
+ onProgress("Setting booking env vars\u2026");
80394
+ await setProjectEnv(projectName, vercelToken, {
80395
+ RESEND_API_KEY: resendKey,
80396
+ OWNER_EMAIL: ownerEmail,
80397
+ BUSINESS_NAME: lead.name,
80398
+ BLOB_READ_WRITE_TOKEN: blobToken
80399
+ });
80400
+ const files = [
80401
+ { file: "index.html", data: booking_runtime_1.BOOK_INDEX_HTML, encoding: "utf-8" },
80402
+ { file: "app.js", data: booking_runtime_1.BOOK_APP_JS, encoding: "utf-8" },
80403
+ { file: "api/bookings.js", data: booking_runtime_1.API_BOOKINGS_JS, encoding: "utf-8" },
80404
+ { file: "api/booking-config.js", data: booking_runtime_1.API_BOOKING_CONFIG_JS, encoding: "utf-8" },
80405
+ {
80406
+ file: "package.json",
80407
+ data: JSON.stringify({
80408
+ name: "sprout-booking",
80409
+ private: true,
80410
+ version: "0.1.0",
80411
+ type: "module",
80412
+ dependencies: { "@vercel/blob": "^0.23.4" }
80413
+ }),
80414
+ encoding: "utf-8"
80415
+ }
80416
+ ];
80417
+ files[0] = {
80418
+ file: "index.html",
80419
+ data: booking_runtime_1.BOOK_INDEX_HTML.replace(/\/book\/app\.js/g, "/app.js"),
80420
+ encoding: "utf-8"
80421
+ };
80422
+ onProgress("Deploying booking site\u2026");
80423
+ const res = await postVercelDeployment({ name: projectName, files, target: "production" }, vercelToken, onProgress);
80424
+ await axios_1.default.patch(`https://api.vercel.com/v9/projects/${res.data.name}`, { ssoProtection: null }, { headers: { Authorization: `Bearer ${vercelToken}` } }).catch(() => null);
80425
+ const publicUrl = await stableProjectUrl({
80426
+ projectName,
80427
+ vercelToken,
80428
+ fallbackUrl: `https://${res.data.url}`
80429
+ });
80430
+ onProgress(`Live at ${publicUrl}`);
80431
+ return { url: publicUrl, bookingUrl: publicUrl };
80432
+ }
80375
80433
  function hasBookLink(code) {
80376
80434
  return /(href\s*=\s*["'`{]*\s*["'`]?\/book\/?["'`}]?)|(location(?:\.href)?\s*=\s*["'`]\/book["'`])/i.test(code);
80377
80435
  }
@@ -81047,11 +81105,15 @@ var require_chat_tools = __commonJS({
81047
81105
  },
81048
81106
  {
81049
81107
  name: "add_booking_site",
81050
- description: "Add an online booking / reservation form to a lead's EXISTING website (the site must already be built). Sproutkit designs a booking form suited to the business \u2014 appointment slots for barbers/salons, table reservations for restaurants, or an enquiry form \u2014 and deploys it onto the same domain. Use this for requests like 'add a booking system to The Porch' or 'give the barber online appointments'. Pass `instructions` to customise it (services, slot length, party size, occasion, copy) and `archetype` to force a specific style. Costs a Claude call + a Vercel redeploy.",
81108
+ description: "Create an online booking / reservation form for a lead. Sproutkit designs a form suited to the business \u2014 appointment slots for barbers/salons, table reservations for restaurants, or an enquiry form. TWO modes: (1) default \u2014 deploy it onto a website Sproutkit ALREADY built for this lead, on the same domain ('add a booking system to The Porch'); (2) standalone (set standalone=true) \u2014 a self-contained booking site with its OWN url, for a client who already has their own website and just needs a booking page to link to ('build a booking site for this client'). Pass `instructions` to customise (services, slot length, party size, copy) and `archetype` to force a style. Costs a Claude call + a Vercel deploy.",
81051
81109
  input_schema: {
81052
81110
  type: "object",
81053
81111
  properties: {
81054
- id: { type: "number", description: "The lead's id. Its website must already be built." },
81112
+ id: { type: "number", description: "The lead's id." },
81113
+ standalone: {
81114
+ type: "boolean",
81115
+ description: "true = build a standalone booking site with its own URL (no Sproutkit-built website required \u2014 for clients who already have their own site). false/omit = add booking onto a site Sproutkit already built for this lead."
81116
+ },
81055
81117
  instructions: {
81056
81118
  type: "string",
81057
81119
  description: "Optional custom direction for the booking form, in plain English. e.g. '45-minute slots, add a beard trim at \xA312', 'tables up to 12 people, ask for the occasion', 'just a simple enquiry form'. Shapes the deployed form."
@@ -81397,10 +81459,20 @@ Interested?`;
81397
81459
  const lead = db2.get("SELECT site_url FROM leads WHERE id = ?", [id]);
81398
81460
  if (!lead)
81399
81461
  throw new Error(`Lead #${id} not found`);
81462
+ const standalone = input.standalone === true;
81463
+ if (standalone) {
81464
+ const result2 = await ctx.invokeIpc("bookings:provision-standalone", {
81465
+ leadId: id,
81466
+ instructions: input.instructions,
81467
+ archetypeOverride: input.archetype,
81468
+ ownerEmail: input.ownerEmail
81469
+ });
81470
+ return { ok: true, id, standalone: true, ...result2 };
81471
+ }
81400
81472
  if (!lead.site_url) {
81401
81473
  return {
81402
81474
  ok: false,
81403
- error: "This lead has no website yet. Build the site first, then add booking \u2014 bookings live on the same domain."
81475
+ error: "This lead has no Sproutkit-built website. Either build the site first, or set standalone=true to create a booking site with its own URL (for clients who already have their own website)."
81404
81476
  };
81405
81477
  }
81406
81478
  const result = await ctx.invokeIpc("bookings:provision", {
@@ -82384,7 +82456,7 @@ var require_package = __commonJS({
82384
82456
  "package.json"(exports2, module2) {
82385
82457
  module2.exports = {
82386
82458
  name: "sproutkit-code",
82387
- version: "0.6.0",
82459
+ version: "0.8.0",
82388
82460
  description: "Sproutkit in your terminal \u2014 find leads, build sites, run outreach, all via chat.",
82389
82461
  bin: {
82390
82462
  sproutkit: "./dist/index.js"
@@ -82441,6 +82513,7 @@ var startAutoJob = autoMode.startAutoJob;
82441
82513
  var provisionCmsForLead = cms.provisionCmsForLead;
82442
82514
  var generatePreset = bookingPreset.generatePreset;
82443
82515
  var deployBookingOnly = builder.deployBookingOnly;
82516
+ var deployStandaloneBooking = builder.deployStandaloneBooking;
82444
82517
  var refreshModels = models.refreshModels;
82445
82518
  var refreshIfStale = models.refreshIfStale;
82446
82519
  var listCachedModels = models.listCachedModels;
@@ -82988,6 +83061,46 @@ function makeInvokeIpc(emit) {
82988
83061
  emit("bookings:done", { leadId: p.leadId, ...result });
82989
83062
  return result;
82990
83063
  }
83064
+ if (channel === "bookings:provision-standalone") {
83065
+ const p = payload;
83066
+ const db2 = getDb();
83067
+ const lead = db2.get("SELECT * FROM leads WHERE id = ?", [p.leadId]);
83068
+ if (!lead) throw new Error("Lead not found");
83069
+ const vercelToken = getSetting("vercel_token");
83070
+ const blobToken = getSetting("blob_token");
83071
+ const resendKey = getSetting("resend_key");
83072
+ if (!vercelToken) throw new Error("Vercel token not set");
83073
+ if (!blobToken) throw new Error("Vercel Blob token not set");
83074
+ emit("bookings:progress", { leadId: p.leadId, msg: "Designing the booking form\u2026" });
83075
+ const leadInfo = lead;
83076
+ const config = await generatePreset({
83077
+ anthropicKey: getSetting("anthropic_key") ?? "",
83078
+ lead: { name: leadInfo.name, type: leadInfo.type, city: leadInfo.city },
83079
+ instructions: p.instructions,
83080
+ archetypeOverride: p.archetypeOverride
83081
+ });
83082
+ const result = await deployStandaloneBooking({
83083
+ lead,
83084
+ vercelToken,
83085
+ blobToken,
83086
+ resendKey: resendKey || "",
83087
+ ownerEmail: p.ownerEmail ?? "",
83088
+ bookingConfig: config,
83089
+ onProgress: (msg) => emit("bookings:progress", { leadId: p.leadId, msg })
83090
+ });
83091
+ db2.run(
83092
+ "UPDATE leads SET booking_url = ?, owner_email = ?, booking_archetype = ?, booking_config = ? WHERE id = ?",
83093
+ [
83094
+ result.bookingUrl,
83095
+ p.ownerEmail ?? "",
83096
+ config.archetype,
83097
+ JSON.stringify(config),
83098
+ p.leadId
83099
+ ]
83100
+ );
83101
+ emit("bookings:done", { leadId: p.leadId, ...result });
83102
+ return result;
83103
+ }
82991
83104
  throw new Error(`channel not supported in CLI: ${channel}`);
82992
83105
  };
82993
83106
  }
@@ -83520,6 +83633,48 @@ async function cmdOutreach(argv) {
83520
83633
  if (result.noPhone) say(c.dim(` ${result.noPhone} had no phone number and were skipped for messaging.`));
83521
83634
  say();
83522
83635
  }
83636
+ async function cmdBook(argv) {
83637
+ const { flags, rest } = parseArgs(argv);
83638
+ const json = !!flags.json;
83639
+ const id = Number(flags.id ?? rest[0]);
83640
+ if (!id || Number.isNaN(id)) {
83641
+ const err = 'Usage: sproutkit book <leadId> [--standalone] [--instructions "..."] [--email owner@x.com]';
83642
+ json ? emitJson({ ok: false, error: err }) : say(c.red(" " + err));
83643
+ process.exitCode = 1;
83644
+ return;
83645
+ }
83646
+ const standalone = !!flags.standalone;
83647
+ const status = json ? void 0 : new Status();
83648
+ if (status) {
83649
+ status.start(standalone ? `Building standalone booking site for lead #${id}` : `Adding booking to lead #${id}`);
83650
+ }
83651
+ try {
83652
+ const result = await runTool(
83653
+ "add_booking_site",
83654
+ {
83655
+ id,
83656
+ standalone,
83657
+ instructions: flags.instructions ? String(flags.instructions) : void 0,
83658
+ archetype: flags.archetype ? String(flags.archetype) : void 0,
83659
+ ownerEmail: flags.email ? String(flags.email) : void 0
83660
+ },
83661
+ makeCtx({ json, status })
83662
+ );
83663
+ if (result && result.ok === false) {
83664
+ if (status) status.done(false, result.error ?? "Booking failed");
83665
+ if (json) emitJson(result);
83666
+ process.exitCode = 1;
83667
+ return;
83668
+ }
83669
+ if (status) status.done(true, result.bookingUrl ? `Booking live at ${result.bookingUrl}` : `Booking added to lead #${id}`);
83670
+ autoSync();
83671
+ if (json) emitJson(result);
83672
+ } catch (e) {
83673
+ if (status) status.done(false, "Booking failed");
83674
+ json ? emitJson({ ok: false, error: e.message }) : say(c.red(" " + e.message));
83675
+ process.exitCode = 1;
83676
+ }
83677
+ }
83523
83678
  async function cmdBuildAll(argv) {
83524
83679
  const { flags } = parseArgs(argv);
83525
83680
  const json = !!flags.json;
@@ -83585,8 +83740,108 @@ async function cmdBuildAll(argv) {
83585
83740
  });
83586
83741
  }
83587
83742
 
83743
+ // src/claude-bridge.ts
83744
+ var import_child_process3 = require("child_process");
83745
+ function runClaudeTurn(args) {
83746
+ const { message, sessionId, write } = args;
83747
+ const timeoutMs = args.timeoutMs ?? 6e5;
83748
+ const cliArgs = [
83749
+ "-p",
83750
+ "--output-format",
83751
+ "stream-json",
83752
+ "--include-partial-messages",
83753
+ "--verbose",
83754
+ // required for stream_event emission
83755
+ // Let Claude drive the sproutkit CLI without hanging on a permission
83756
+ // prompt, but ONLY the sproutkit command — nothing else runs unattended.
83757
+ "--allowedTools",
83758
+ "Bash(sproutkit *)"
83759
+ ];
83760
+ if (sessionId) cliArgs.push("--resume", sessionId);
83761
+ return new Promise((resolve) => {
83762
+ let child;
83763
+ try {
83764
+ child = (0, import_child_process3.spawn)(claudeBin(), cliArgs, { stdio: ["pipe", "pipe", "pipe"] });
83765
+ } catch (e) {
83766
+ resolve({ sessionId, ok: false, error: e.message });
83767
+ return;
83768
+ }
83769
+ let buf = "";
83770
+ let newSessionId = sessionId;
83771
+ let sawText = false;
83772
+ let settled = false;
83773
+ let stderr = "";
83774
+ const timer = setTimeout(() => {
83775
+ if (settled) return;
83776
+ settled = true;
83777
+ child.kill("SIGKILL");
83778
+ resolve({ sessionId: newSessionId, ok: false, error: `Timed out after ${Math.round(timeoutMs / 1e3)}s.` });
83779
+ }, timeoutMs);
83780
+ child.stdout.on("data", (d) => {
83781
+ buf += d.toString();
83782
+ let nl;
83783
+ while ((nl = buf.indexOf("\n")) >= 0) {
83784
+ const line = buf.slice(0, nl).trim();
83785
+ buf = buf.slice(nl + 1);
83786
+ if (!line) continue;
83787
+ let ev;
83788
+ try {
83789
+ ev = JSON.parse(line);
83790
+ } catch {
83791
+ continue;
83792
+ }
83793
+ if (ev.session_id) newSessionId = ev.session_id;
83794
+ if (ev.type === "stream_event" && ev.event?.delta?.type === "text_delta" && typeof ev.event.delta.text === "string") {
83795
+ sawText = true;
83796
+ write(ev.event.delta.text);
83797
+ }
83798
+ if (ev.type === "result" && !sawText && typeof ev.result === "string") {
83799
+ write(ev.result);
83800
+ }
83801
+ }
83802
+ });
83803
+ child.stderr.on("data", (d) => stderr += d.toString());
83804
+ child.on("error", (e) => {
83805
+ if (settled) return;
83806
+ settled = true;
83807
+ clearTimeout(timer);
83808
+ const msg = e.code === "ENOENT" ? `Claude Code CLI not found. Install it and run 'claude /login'.` : `Failed to run Claude Code: ${e.message}`;
83809
+ resolve({ sessionId: newSessionId, ok: false, error: msg });
83810
+ });
83811
+ child.on("close", (code) => {
83812
+ if (settled) return;
83813
+ settled = true;
83814
+ clearTimeout(timer);
83815
+ if (code !== 0 && !sawText) {
83816
+ resolve({
83817
+ sessionId: newSessionId,
83818
+ ok: false,
83819
+ error: stderr.trim() || `Claude Code exited with code ${code}.`
83820
+ });
83821
+ } else {
83822
+ resolve({ sessionId: newSessionId, ok: true });
83823
+ }
83824
+ });
83825
+ child.stdin.write(message);
83826
+ child.stdin.end();
83827
+ });
83828
+ }
83829
+
83588
83830
  // src/index.ts
83831
+ var import_child_process4 = require("child_process");
83589
83832
  process.env.SPROUTKIT_HEADLESS = "1";
83833
+ function claudePresent() {
83834
+ try {
83835
+ const bin = process.env.SPROUTKIT_CLAUDE_BIN || "claude";
83836
+ return (0, import_child_process4.spawnSync)(bin, ["--version"], { stdio: "ignore", timeout: 1e4 }).status === 0;
83837
+ } catch {
83838
+ return false;
83839
+ }
83840
+ }
83841
+ function useClaudeBridge() {
83842
+ if (getBackend() === "claude_code") return true;
83843
+ return claudePresent() && !getSetting("anthropic_key");
83844
+ }
83590
83845
  async function main() {
83591
83846
  const arg = process.argv[2];
83592
83847
  initDatabase();
@@ -83619,7 +83874,7 @@ async function main() {
83619
83874
  closeTty();
83620
83875
  return;
83621
83876
  }
83622
- if (arg === "find" || arg === "list" || arg === "build" || arg === "build-all" || arg === "outreach") {
83877
+ if (arg === "find" || arg === "list" || arg === "build" || arg === "build-all" || arg === "book" || arg === "outreach") {
83623
83878
  const subArgs = process.argv.slice(3);
83624
83879
  const lic2 = await check();
83625
83880
  if (lic2.status !== "active") {
@@ -83634,6 +83889,7 @@ async function main() {
83634
83889
  else if (arg === "list") await cmdList(subArgs);
83635
83890
  else if (arg === "build") await cmdBuild(subArgs);
83636
83891
  else if (arg === "build-all") await cmdBuildAll(subArgs);
83892
+ else if (arg === "book") await cmdBook(subArgs);
83637
83893
  else await cmdOutreach(subArgs);
83638
83894
  closeTty();
83639
83895
  return;
@@ -83648,6 +83904,7 @@ async function main() {
83648
83904
  say(` ${c.bold("sproutkit list")} list leads (--status, --city, --json)`);
83649
83905
  say(` ${c.bold("sproutkit build <id>")} build a website (--instructions, --cms)`);
83650
83906
  say(` ${c.bold("sproutkit build-all")} build many at once (--ids, --concurrency 3)`);
83907
+ say(` ${c.bold("sproutkit book <id>")} booking site (--standalone for own-URL)`);
83651
83908
  say(` ${c.bold("sproutkit outreach")} prep outreach links (--ids 3,5)`);
83652
83909
  say(` ${c.bold("sproutkit setup")} set or update keys, licence, backend`);
83653
83910
  say(` ${c.bold("sproutkit models")} list Claude models and pick one`);
@@ -83674,23 +83931,47 @@ async function main() {
83674
83931
  closeTty();
83675
83932
  return;
83676
83933
  }
83934
+ const bridged = useClaudeBridge();
83677
83935
  const oneShot = process.argv.slice(2).join(" ").trim();
83678
83936
  if (oneShot) {
83679
- await runTurn(oneShot);
83937
+ if (bridged) {
83938
+ const r = await runClaudeTurn({ message: oneShot, sessionId: null, write: (t) => process.stdout.write(t) });
83939
+ say();
83940
+ if (!r.ok) say(c.red(` ${r.error ?? "Claude Code failed."}`));
83941
+ } else {
83942
+ await runTurn(oneShot);
83943
+ }
83680
83944
  closeTty();
83681
83945
  return;
83682
83946
  }
83683
83947
  await refreshIfStale(getSetting("anthropic_key")).catch(() => {
83684
83948
  });
83685
83949
  await notifyIfOutdated();
83686
- say(c.dim(" Chat with Sproutkit. Type a request, or 'exit' to quit."));
83950
+ if (bridged && !skillInstalled()) {
83951
+ say(c.amber(" Tip: run 'sproutkit setup' to install the Sproutkit skill so Claude can find/build/book for you."));
83952
+ }
83953
+ say(
83954
+ bridged ? c.dim(" Talk to Sproutkit (powered by your Claude subscription). Type a request, or 'exit'.") : c.dim(" Chat with Sproutkit. Type a request, or 'exit' to quit.")
83955
+ );
83687
83956
  say();
83957
+ let claudeSession = null;
83688
83958
  while (true) {
83689
83959
  const line = await ask(c.greenBold("sproutkit \u203A "));
83690
83960
  if (!line) continue;
83691
83961
  if (line === "exit" || line === "quit") break;
83692
83962
  try {
83693
- await runTurn(line);
83963
+ if (bridged) {
83964
+ const r = await runClaudeTurn({
83965
+ message: line,
83966
+ sessionId: claudeSession,
83967
+ write: (t) => process.stdout.write(t)
83968
+ });
83969
+ say();
83970
+ if (r.sessionId) claudeSession = r.sessionId;
83971
+ if (!r.ok) say(c.red(` ${r.error ?? "Claude Code failed."}`));
83972
+ } else {
83973
+ await runTurn(line);
83974
+ }
83694
83975
  } catch (e) {
83695
83976
  say(c.red(` Error: ${e.message}`));
83696
83977
  }
@@ -48,6 +48,17 @@ you can parse results reliably, then summarise them for the user in prose.
48
48
  renders the progress. One `sproutkit build-all` call is correct; N parallel
49
49
  `sproutkit build` calls via subagents is not.
50
50
 
51
+ - **Add a booking site** — `sproutkit book <leadId> --json`
52
+ - Default: adds an online booking/reservation form onto a site Sproutkit
53
+ already built for this lead (same domain, at /book).
54
+ - `--standalone`: builds a self-contained booking site with its OWN url, for
55
+ a client who already has their own website and just needs a booking page to
56
+ link to. No Sproutkit-built site required.
57
+ - Optional: `--instructions "45-min slots, add beard trim £12"`,
58
+ `--archetype slots|reservation|enquiry`, `--email owner@x.com`.
59
+ - Use `book --standalone` when the user says the client "already has a
60
+ website" or "just needs a booking page".
61
+
51
62
  - **Prepare outreach** — `sproutkit outreach --json` (optional `--ids 3,5,9`)
52
63
  - Fills the message template, moves the leads to Contacted, and returns a
53
64
  link per lead to open in WhatsApp/SMS. It does NOT auto-send — give the user
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sproutkit-code",
3
- "version": "0.6.0",
3
+ "version": "0.8.0",
4
4
  "description": "Sproutkit in your terminal — find leads, build sites, run outreach, all via chat.",
5
5
  "bin": {
6
6
  "sproutkit": "./dist/index.js"