sproutkit-code 0.8.0 → 0.9.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 +59 -8
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -82456,7 +82456,7 @@ var require_package = __commonJS({
|
|
|
82456
82456
|
"package.json"(exports2, module2) {
|
|
82457
82457
|
module2.exports = {
|
|
82458
82458
|
name: "sproutkit-code",
|
|
82459
|
-
version: "0.
|
|
82459
|
+
version: "0.9.0",
|
|
82460
82460
|
description: "Sproutkit in your terminal \u2014 find leads, build sites, run outreach, all via chat.",
|
|
82461
82461
|
bin: {
|
|
82462
82462
|
sproutkit: "./dist/index.js"
|
|
@@ -82529,7 +82529,8 @@ var REQUIRED_KEYS = [
|
|
|
82529
82529
|
{ key: "anthropic_key", label: "Anthropic API key", hint: "sk-ant-\u2026 \u2014 powers the chat + site generation", required: true, apiBackendOnly: true },
|
|
82530
82530
|
{ key: "places_key", label: "Google Places API key", hint: "finds businesses, photos, reviews", required: true },
|
|
82531
82531
|
{ key: "vercel_token", label: "Vercel token", hint: "deploys the generated sites", required: true },
|
|
82532
|
-
{ key: "blob_token", label: "Vercel Blob token", hint: "
|
|
82532
|
+
{ key: "blob_token", label: "Vercel Blob token", hint: "required for booking sites & CMS (stores form config/submissions)", required: false },
|
|
82533
|
+
{ key: "resend_key", label: "Resend API key", hint: "optional \u2014 emails the business owner when a booking comes in", required: false }
|
|
82533
82534
|
];
|
|
82534
82535
|
function getSetting(key) {
|
|
82535
82536
|
const row = getDb().get("SELECT value FROM settings WHERE key = ?", [key]);
|
|
@@ -83029,7 +83030,7 @@ function makeInvokeIpc(emit) {
|
|
|
83029
83030
|
const resendKey = getSetting("resend_key");
|
|
83030
83031
|
if (!anthropicKey) throw new Error("Anthropic API key not set");
|
|
83031
83032
|
if (!vercelToken) throw new Error("Vercel token not set");
|
|
83032
|
-
if (!blobToken) throw new Error("Vercel Blob token
|
|
83033
|
+
if (!blobToken) throw new Error("Booking sites need a Vercel Blob token (stores the form config & submissions). Add one with 'sproutkit setup' \u2014 create a Blob store at vercel.com, copy its read-write token.");
|
|
83033
83034
|
emit("bookings:progress", { leadId: p.leadId, msg: "Designing the booking form\u2026" });
|
|
83034
83035
|
const leadInfo = lead;
|
|
83035
83036
|
const config = await generatePreset({
|
|
@@ -83070,7 +83071,7 @@ function makeInvokeIpc(emit) {
|
|
|
83070
83071
|
const blobToken = getSetting("blob_token");
|
|
83071
83072
|
const resendKey = getSetting("resend_key");
|
|
83072
83073
|
if (!vercelToken) throw new Error("Vercel token not set");
|
|
83073
|
-
if (!blobToken) throw new Error("Vercel Blob token
|
|
83074
|
+
if (!blobToken) throw new Error("Booking sites need a Vercel Blob token (stores the form config & submissions). Add one with 'sproutkit setup' \u2014 create a Blob store at vercel.com, copy its read-write token.");
|
|
83074
83075
|
emit("bookings:progress", { leadId: p.leadId, msg: "Designing the booking form\u2026" });
|
|
83075
83076
|
const leadInfo = lead;
|
|
83076
83077
|
const config = await generatePreset({
|
|
@@ -83742,8 +83743,36 @@ async function cmdBuildAll(argv) {
|
|
|
83742
83743
|
|
|
83743
83744
|
// src/claude-bridge.ts
|
|
83744
83745
|
var import_child_process3 = require("child_process");
|
|
83746
|
+
var TASK_SYSTEM_PROMPT = `You operate the "sproutkit" CLI on the user's behalf. Sproutkit finds local businesses without websites, builds them demo sites, adds booking, and prepares outreach.
|
|
83747
|
+
|
|
83748
|
+
HOW TO ACT \u2014 this is strict:
|
|
83749
|
+
- Fulfil each request by running the matching sproutkit command(s) via Bash. Nothing else.
|
|
83750
|
+
- Do NOT read, list, or explore the repo. Do NOT narrate a plan, think out loud, or look for a skill. No preamble, no "let me\u2026". Either ask a crisp question (below) or run the command.
|
|
83751
|
+
- Always pass --json and parse it. When an action completes, report the outcome in ONE short line (what happened + the URL/result).
|
|
83752
|
+
- Get lead ids from \`sproutkit list --json\` \u2014 never guess an id.
|
|
83753
|
+
|
|
83754
|
+
GATHER REQUIRED CHOICES FIRST \u2014 ask, don't guess, don't chatter:
|
|
83755
|
+
When a request is missing information the command needs, ask a SHORT, STRUCTURED question that lists the options \u2014 then wait. Present choices as a tight numbered/bulleted list, no rambling. Specifically:
|
|
83756
|
+
- Which business/lead is not clear \u2192 run \`sproutkit list --json\`, then ask: "Which business?" and list a few (id + name).
|
|
83757
|
+
- "make/build a booking site" \u2192 you MUST establish the booking TYPE before running. Ask: "What type of booking site?" and present exactly:
|
|
83758
|
+
1. Slot-based \u2014 timed appointments (barbers, salons, clinics)
|
|
83759
|
+
2. Reservation \u2014 table / party booking (restaurants, cafes)
|
|
83760
|
+
3. Enquiry \u2014 a simple request/contact form
|
|
83761
|
+
Also ask whether it should be standalone (its own URL, for a client who already has a website) or added to a Sproutkit-built site. Then run \`sproutkit book <id> --archetype <slots|reservation|enquiry> [--standalone] --json\`.
|
|
83762
|
+
- Once you have the needed choices, act immediately \u2014 one command, one line of result. Don't re-confirm what they already told you.
|
|
83763
|
+
|
|
83764
|
+
COMMANDS:
|
|
83765
|
+
- sproutkit find "<area>" --categories "<type>,<type>" --json \u2014 find leads
|
|
83766
|
+
- sproutkit list --json [--status <s>] [--city <c>] \u2014 list leads (get ids)
|
|
83767
|
+
- sproutkit build <id> --json [--instructions "..."] [--cms] \u2014 build a demo site
|
|
83768
|
+
- sproutkit build-all --json [--ids 3,5] [--concurrency 3] \u2014 build many at once
|
|
83769
|
+
- sproutkit book <id> --json [--standalone] [--instructions "..."] [--archetype slots|reservation|enquiry] [--email x@y.com] \u2014 booking site (--standalone = its own URL for clients who already have a website)
|
|
83770
|
+
- sproutkit outreach --json [--ids 3,5] \u2014 prepare outreach links
|
|
83771
|
+
|
|
83772
|
+
If no command fits the request, say so in one line and name the closest thing you can do. Never invent results.`;
|
|
83773
|
+
var FREE_SYSTEM_PROMPT = `You are Sproutkit's assistant, talking with the user about their lead-generation and website work. You can run the sproutkit CLI (find, list, build, build-all, book, outreach \u2014 all support --json) via Bash, and you can help with small custom changes and questions. Be conversational and helpful, but stay within Sproutkit's domain (leads, demo sites, booking, outreach). You don't need to collapse everything to a single command here \u2014 it's fine to discuss, then act.`;
|
|
83745
83774
|
function runClaudeTurn(args) {
|
|
83746
|
-
const { message, sessionId, write } = args;
|
|
83775
|
+
const { message, sessionId, write, freeMode } = args;
|
|
83747
83776
|
const timeoutMs = args.timeoutMs ?? 6e5;
|
|
83748
83777
|
const cliArgs = [
|
|
83749
83778
|
"-p",
|
|
@@ -83752,6 +83781,11 @@ function runClaudeTurn(args) {
|
|
|
83752
83781
|
"--include-partial-messages",
|
|
83753
83782
|
"--verbose",
|
|
83754
83783
|
// required for stream_event emission
|
|
83784
|
+
// Inject the operating instructions directly so behaviour is precise and
|
|
83785
|
+
// doesn't depend on flaky skill discovery. Task mode pins exact commands;
|
|
83786
|
+
// free mode allows open conversation.
|
|
83787
|
+
"--append-system-prompt",
|
|
83788
|
+
freeMode ? FREE_SYSTEM_PROMPT : TASK_SYSTEM_PROMPT,
|
|
83755
83789
|
// Let Claude drive the sproutkit CLI without hanging on a permission
|
|
83756
83790
|
// prompt, but ONLY the sproutkit command — nothing else runs unattended.
|
|
83757
83791
|
"--allowedTools",
|
|
@@ -83950,20 +83984,37 @@ async function main() {
|
|
|
83950
83984
|
if (bridged && !skillInstalled()) {
|
|
83951
83985
|
say(c.amber(" Tip: run 'sproutkit setup' to install the Sproutkit skill so Claude can find/build/book for you."));
|
|
83952
83986
|
}
|
|
83953
|
-
|
|
83954
|
-
|
|
83955
|
-
);
|
|
83987
|
+
if (bridged) {
|
|
83988
|
+
say(c.dim(" Talk to Sproutkit (powered by your Claude subscription). Type a request, or 'exit'."));
|
|
83989
|
+
say(c.dim(" It runs the right action precisely. Type '/freemode' for open conversation + custom tweaks."));
|
|
83990
|
+
} else {
|
|
83991
|
+
say(c.dim(" Chat with Sproutkit. Type a request, or 'exit' to quit."));
|
|
83992
|
+
}
|
|
83956
83993
|
say();
|
|
83957
83994
|
let claudeSession = null;
|
|
83995
|
+
let freeMode = false;
|
|
83958
83996
|
while (true) {
|
|
83959
83997
|
const line = await ask(c.greenBold("sproutkit \u203A "));
|
|
83960
83998
|
if (!line) continue;
|
|
83961
83999
|
if (line === "exit" || line === "quit") break;
|
|
84000
|
+
if (bridged && (line === "/freemode" || line === "/free")) {
|
|
84001
|
+
freeMode = true;
|
|
84002
|
+
say(c.amber(" Free mode ON \u2014 open conversation. You can ask for small custom changes. '/taskmode' to switch back."));
|
|
84003
|
+
say();
|
|
84004
|
+
continue;
|
|
84005
|
+
}
|
|
84006
|
+
if (bridged && (line === "/taskmode" || line === "/task")) {
|
|
84007
|
+
freeMode = false;
|
|
84008
|
+
say(c.green(" Task mode ON \u2014 precise actions."));
|
|
84009
|
+
say();
|
|
84010
|
+
continue;
|
|
84011
|
+
}
|
|
83962
84012
|
try {
|
|
83963
84013
|
if (bridged) {
|
|
83964
84014
|
const r = await runClaudeTurn({
|
|
83965
84015
|
message: line,
|
|
83966
84016
|
sessionId: claudeSession,
|
|
84017
|
+
freeMode,
|
|
83967
84018
|
write: (t) => process.stdout.write(t)
|
|
83968
84019
|
});
|
|
83969
84020
|
say();
|