sproutkit-code 0.11.0 → 0.12.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.
Files changed (2) hide show
  1. package/dist/index.js +78 -26
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -80731,29 +80731,39 @@ var require_places = __commonJS({
80731
80731
  }
80732
80732
  var COST_PER_REQUEST_GBP = 0.025;
80733
80733
  async function searchOneType(args) {
80734
- const body = {
80735
- textQuery: `${args.type} in ${args.city}`,
80736
- maxResultCount: 20
80737
- };
80738
- if (args.center && args.radiusMeters) {
80739
- body.locationBias = {
80740
- circle: {
80741
- center: { latitude: args.center.lat, longitude: args.center.lng },
80742
- radius: args.radiusMeters
80743
- }
80734
+ const all = [];
80735
+ let pageToken;
80736
+ for (let page = 0; page < 3; page++) {
80737
+ const body = {
80738
+ textQuery: `${args.type} in ${args.city}`,
80739
+ maxResultCount: 20
80744
80740
  };
80741
+ if (args.center && args.radiusMeters) {
80742
+ body.locationBias = {
80743
+ circle: {
80744
+ center: { latitude: args.center.lat, longitude: args.center.lng },
80745
+ radius: args.radiusMeters
80746
+ }
80747
+ };
80748
+ }
80749
+ if (pageToken)
80750
+ body.pageToken = pageToken;
80751
+ try {
80752
+ const r = await axios_1.default.post("https://places.googleapis.com/v1/places:searchText", body, {
80753
+ headers: {
80754
+ "X-Goog-Api-Key": args.apiKey,
80755
+ "X-Goog-FieldMask": "nextPageToken,places.id,places.displayName,places.formattedAddress,places.nationalPhoneNumber,places.websiteUri,places.rating,places.userRatingCount,places.location,places.priceLevel,places.businessStatus,places.regularOpeningHours"
80756
+ }
80757
+ });
80758
+ all.push(...r.data.places ?? []);
80759
+ pageToken = r.data.nextPageToken;
80760
+ if (!pageToken)
80761
+ break;
80762
+ } catch {
80763
+ break;
80764
+ }
80745
80765
  }
80746
- try {
80747
- const r = await axios_1.default.post("https://places.googleapis.com/v1/places:searchText", body, {
80748
- headers: {
80749
- "X-Goog-Api-Key": args.apiKey,
80750
- "X-Goog-FieldMask": "places.id,places.displayName,places.formattedAddress,places.nationalPhoneNumber,places.websiteUri,places.rating,places.userRatingCount,places.location,places.priceLevel,places.businessStatus,places.regularOpeningHours"
80751
- }
80752
- });
80753
- return { type: args.type, places: r.data.places ?? [] };
80754
- } catch {
80755
- return { type: args.type, places: [] };
80756
- }
80766
+ return { type: args.type, places: all };
80757
80767
  }
80758
80768
  function processRawPlaces(type, places, center, radiusMeters) {
80759
80769
  const out = [];
@@ -81022,7 +81032,7 @@ var require_chat_tools = __commonJS({
81022
81032
  },
81023
81033
  radiusMeters: {
81024
81034
  type: "number",
81025
- description: "Search radius around the location in metres (default 3000). Larger radius = more leads but less focused."
81035
+ description: "Search radius around the location in metres (default 10000 = 10km). Use a larger radius for big cities where central businesses mostly have websites; smaller (e.g. 3000) for a tight local search."
81026
81036
  }
81027
81037
  },
81028
81038
  required: ["location", "categories"]
@@ -81327,7 +81337,11 @@ Interested?`;
81327
81337
  types: categories,
81328
81338
  maxResults: Math.min(Number(input.maxResults ?? 25), 100),
81329
81339
  center: place ? { lat: place.lat, lng: place.lng } : void 0,
81330
- radiusMeters: Number(input.radiusMeters ?? 3e3)
81340
+ // Default widened from 3km → 10km. A 3km circle in a website-
81341
+ // saturated city centre (e.g. central London) yields almost no
81342
+ // no-website leads; 10km covers a realistic catchment. Caller/model
81343
+ // can still override for a tighter or wider search.
81344
+ radiusMeters: Number(input.radiusMeters ?? 1e4)
81331
81345
  },
81332
81346
  // Emit each lead the instant it's saved, so the UI/CLI streams results
81333
81347
  // in rather than waiting for every category to finish.
@@ -82551,7 +82565,7 @@ var require_package = __commonJS({
82551
82565
  "package.json"(exports2, module2) {
82552
82566
  module2.exports = {
82553
82567
  name: "sproutkit-code",
82554
- version: "0.11.0",
82568
+ version: "0.12.0",
82555
82569
  description: "Sproutkit in your terminal \u2014 find leads, build sites, run outreach, all via chat.",
82556
82570
  bin: {
82557
82571
  sproutkit: "./dist/index.js"
@@ -83862,8 +83876,14 @@ var TASK_SYSTEM_PROMPT = `You operate the "sproutkit" CLI on the user's behalf.
83862
83876
  HOW TO ACT \u2014 this is strict:
83863
83877
  - Fulfil each request by running the matching sproutkit command(s) via Bash. Nothing else.
83864
83878
  - 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.
83865
- - Always pass --json and parse it. When an action completes, report the outcome in ONE short line (what happened + the URL/result).
83866
- - Get lead ids from \`sproutkit list --json\` \u2014 never guess an id.
83879
+ - Always pass --json and parse it. Get lead ids from \`sproutkit list --json\` \u2014 never guess an id.
83880
+
83881
+ OUTPUT FORMAT \u2014 terse, scannable, NO editorialising:
83882
+ - Never write rambling sentences or commentary about the results ("well short of 20, so the source is returning few matches" \u2014 DON'T). Just present the data.
83883
+ - For find: one line "Found N (M new)", then one line per NEW lead: "#<id> <name> \xB7 <type>".
83884
+ - For list: one line per lead "#<id> <name> \xB7 <type> \xB7 <city> \xB7 <status>" (cap at ~15, then "\u2026and K more").
83885
+ - For build/book: one line "\u2713 <name> \u2014 <url>".
83886
+ - Use a plain "#<id> <name>" style. No tables, no fluff, no "Here's what I found". If a result count is low, state the number plainly \u2014 do NOT speculate about why unless asked.
83867
83887
 
83868
83888
  GATHER REQUIRED CHOICES FIRST \u2014 ask, don't guess, don't chatter:
83869
83889
  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:
@@ -84123,6 +84143,38 @@ async function main() {
84123
84143
  say();
84124
84144
  continue;
84125
84145
  }
84146
+ const direct = line.replace(/^\//, "");
84147
+ const verb = direct.split(/\s+/)[0]?.toLowerCase();
84148
+ const DIRECT_VERBS = ["find", "list", "build", "build-all", "book", "outreach"];
84149
+ if (verb === "commands" || verb === "help" || line === "/help" || line === "/?") {
84150
+ say();
84151
+ say(c.bold(" Commands (type with or without a leading /):"));
84152
+ say(` ${c.greenBold("find")} "<area>" --categories "cafe,barber" find leads`);
84153
+ say(` ${c.greenBold("list")} [--status <s>] [--city <c>] list leads`);
84154
+ say(` ${c.greenBold("build")} <id> [--instructions "\u2026"] [--cms] build a demo site`);
84155
+ say(` ${c.greenBold("build-all")} [--ids 3,5] [--concurrency 3] build many at once`);
84156
+ say(` ${c.greenBold("book")} <id> [--standalone] [--archetype \u2026] booking site`);
84157
+ say(` ${c.greenBold("outreach")} [--ids 3,5] prepare outreach links`);
84158
+ say(c.dim(" /freemode \u2014 open conversation \xB7 /taskmode \u2014 precise \xB7 exit \u2014 quit"));
84159
+ say(c.dim(" Or just talk: \u201Cfind cafes in Leeds and build the best two\u201D."));
84160
+ say();
84161
+ continue;
84162
+ }
84163
+ const isSlash = line.startsWith("/");
84164
+ if (DIRECT_VERBS.includes(verb) && (isSlash || !freeMode)) {
84165
+ const argv = (direct.match(/"[^"]*"|'[^']*'|\S+/g) ?? []).slice(1).map((a) => a.replace(/^['"]|['"]$/g, ""));
84166
+ try {
84167
+ if (verb === "find") await cmdFind(argv);
84168
+ else if (verb === "list") await cmdList(argv);
84169
+ else if (verb === "build") await cmdBuild(argv);
84170
+ else if (verb === "build-all") await cmdBuildAll(argv);
84171
+ else if (verb === "book") await cmdBook(argv);
84172
+ else if (verb === "outreach") await cmdOutreach(argv);
84173
+ } catch (e) {
84174
+ say(c.red(` Error: ${e.message}`));
84175
+ }
84176
+ continue;
84177
+ }
84126
84178
  try {
84127
84179
  if (bridged) {
84128
84180
  const r = await runClaudeTurn({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sproutkit-code",
3
- "version": "0.11.0",
3
+ "version": "0.12.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"