sproutkit-code 0.1.0 → 0.1.2

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 +266 -45
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -24950,7 +24950,7 @@ var require_has_flag = __commonJS({
24950
24950
  var require_supports_color = __commonJS({
24951
24951
  "../../node_modules/supports-color/index.js"(exports2, module2) {
24952
24952
  "use strict";
24953
- var os = require("os");
24953
+ var os2 = require("os");
24954
24954
  var tty = require("tty");
24955
24955
  var hasFlag = require_has_flag();
24956
24956
  var { env } = process;
@@ -24998,7 +24998,7 @@ var require_supports_color = __commonJS({
24998
24998
  return min;
24999
24999
  }
25000
25000
  if (process.platform === "win32") {
25001
- const osRelease = os.release().split(".");
25001
+ const osRelease = os2.release().split(".");
25002
25002
  if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
25003
25003
  return Number(osRelease[2]) >= 14931 ? 3 : 2;
25004
25004
  }
@@ -25238,7 +25238,7 @@ var require_promisify = __commonJS({
25238
25238
  "../../node_modules/agent-base/dist/src/promisify.js"(exports2) {
25239
25239
  "use strict";
25240
25240
  Object.defineProperty(exports2, "__esModule", { value: true });
25241
- function promisify(fn) {
25241
+ function promisify2(fn) {
25242
25242
  return function(req, opts) {
25243
25243
  return new Promise((resolve, reject) => {
25244
25244
  fn.call(this, req, opts, (err, rtn) => {
@@ -25251,7 +25251,7 @@ var require_promisify = __commonJS({
25251
25251
  });
25252
25252
  };
25253
25253
  }
25254
- exports2.default = promisify;
25254
+ exports2.default = promisify2;
25255
25255
  }
25256
25256
  });
25257
25257
 
@@ -35997,7 +35997,7 @@ var require_signal_exit = __commonJS({
35997
35997
  var require_kill = __commonJS({
35998
35998
  "../../node_modules/execa/lib/kill.js"(exports2, module2) {
35999
35999
  "use strict";
36000
- var os = require("os");
36000
+ var os2 = require("os");
36001
36001
  var onExit = require_signal_exit();
36002
36002
  var DEFAULT_FORCE_KILL_TIMEOUT = 1e3 * 5;
36003
36003
  var spawnedKill = (kill, signal = "SIGTERM", options = {}) => {
@@ -36021,7 +36021,7 @@ var require_kill = __commonJS({
36021
36021
  return isSigterm(signal) && forceKillAfterTimeout !== false && killResult;
36022
36022
  };
36023
36023
  var isSigterm = (signal) => {
36024
- return signal === os.constants.signals.SIGTERM || typeof signal === "string" && signal.toUpperCase() === "SIGTERM";
36024
+ return signal === os2.constants.signals.SIGTERM || typeof signal === "string" && signal.toUpperCase() === "SIGTERM";
36025
36025
  };
36026
36026
  var getForceKillAfterTimeout = ({ forceKillAfterTimeout = true }) => {
36027
36027
  if (forceKillAfterTimeout === true) {
@@ -36147,9 +36147,9 @@ var require_get_stream = __commonJS({
36147
36147
  "use strict";
36148
36148
  var { constants: BufferConstants } = require("buffer");
36149
36149
  var stream = require("stream");
36150
- var { promisify } = require("util");
36150
+ var { promisify: promisify2 } = require("util");
36151
36151
  var bufferStream = require_buffer_stream();
36152
- var streamPipelinePromisified = promisify(stream.pipeline);
36152
+ var streamPipelinePromisified = promisify2(stream.pipeline);
36153
36153
  var MaxBufferError = class extends Error {
36154
36154
  constructor() {
36155
36155
  super("maxBuffer exceeded");
@@ -51006,7 +51006,7 @@ var require_schemas2 = __commonJS({
51006
51006
  exports2.function = _function;
51007
51007
  exports2._function = _function;
51008
51008
  exports2.function = _function;
51009
- exports2.check = check;
51009
+ exports2.check = check2;
51010
51010
  exports2.custom = custom;
51011
51011
  exports2.refine = refine;
51012
51012
  exports2.superRefine = superRefine;
@@ -51050,7 +51050,7 @@ var require_schemas2 = __commonJS({
51050
51050
  inst.safeDecode = (data, params) => parse.safeDecode(inst, data, params);
51051
51051
  inst.safeEncodeAsync = async (data, params) => parse.safeEncodeAsync(inst, data, params);
51052
51052
  inst.safeDecodeAsync = async (data, params) => parse.safeDecodeAsync(inst, data, params);
51053
- inst.refine = (check2, params) => inst.check(refine(check2, params));
51053
+ inst.refine = (check3, params) => inst.check(refine(check3, params));
51054
51054
  inst.superRefine = (refinement) => inst.check(superRefine(refinement));
51055
51055
  inst.overwrite = (fn) => inst.check(checks.overwrite(fn));
51056
51056
  inst.optional = () => optional(inst);
@@ -51942,7 +51942,7 @@ var require_schemas2 = __commonJS({
51942
51942
  core.$ZodCustom.init(inst, def);
51943
51943
  exports2.ZodType.init(inst, def);
51944
51944
  });
51945
- function check(fn) {
51945
+ function check2(fn) {
51946
51946
  const ch = new core.$ZodCheck({
51947
51947
  check: "custom"
51948
51948
  // ...util.normalizeParams(params),
@@ -52357,7 +52357,7 @@ var require_schema = __commonJS({
52357
52357
  var require_lib5 = __commonJS({
52358
52358
  "../../node_modules/os-paths/src/lib/index.js"(exports2, module2) {
52359
52359
  "use strict";
52360
- var os = require("os");
52360
+ var os2 = require("os");
52361
52361
  var paths = require("path");
52362
52362
  var isWinOS = /^win/i.test(process.platform);
52363
52363
  function normalize_path(path) {
@@ -52366,18 +52366,18 @@ var require_lib5 = __commonJS({
52366
52366
  var base = () => {
52367
52367
  const { env } = process;
52368
52368
  const object = {};
52369
- object.home = () => normalize_path(os.homedir ? os.homedir() : env.HOME);
52370
- object.temp = () => normalize_path(os.tmpdir ? os.tmpdir() : env.TMPDIR || env.TEMP || env.TMP);
52369
+ object.home = () => normalize_path(os2.homedir ? os2.homedir() : env.HOME);
52370
+ object.temp = () => normalize_path(os2.tmpdir ? os2.tmpdir() : env.TMPDIR || env.TEMP || env.TMP);
52371
52371
  return object;
52372
52372
  };
52373
52373
  var windows = () => {
52374
52374
  const { env } = process;
52375
52375
  const object = {};
52376
52376
  object.home = () => normalize_path(
52377
- os.homedir ? os.homedir() : env.USERPROFILE || paths.join(env.HOMEDRIVE, env.HOMEPATH) || env.HOME
52377
+ os2.homedir ? os2.homedir() : env.USERPROFILE || paths.join(env.HOMEDRIVE, env.HOMEPATH) || env.HOME
52378
52378
  );
52379
52379
  object.temp = () => normalize_path(
52380
- os.tmpdir ? os.tmpdir() : env.TEMP || env.TMP || paths.join(env.LOCALAPPDATA || env.SystemRoot || env.windir, "Temp")
52380
+ os2.tmpdir ? os2.tmpdir() : env.TEMP || env.TMP || paths.join(env.LOCALAPPDATA || env.SystemRoot || env.windir, "Temp")
52381
52381
  );
52382
52382
  return object;
52383
52383
  };
@@ -52890,7 +52890,7 @@ var require_token_io = __commonJS({
52890
52890
  module2.exports = __toCommonJS(token_io_exports);
52891
52891
  var import_path = __toESM2(require("path"));
52892
52892
  var import_fs = __toESM2(require("fs"));
52893
- var import_os = __toESM2(require("os"));
52893
+ var import_os2 = __toESM2(require("os"));
52894
52894
  var import_token_error = require_token_error();
52895
52895
  function findRootDir() {
52896
52896
  try {
@@ -52913,11 +52913,11 @@ var require_token_io = __commonJS({
52913
52913
  if (process.env.XDG_DATA_HOME) {
52914
52914
  return process.env.XDG_DATA_HOME;
52915
52915
  }
52916
- switch (import_os.default.platform()) {
52916
+ switch (import_os2.default.platform()) {
52917
52917
  case "darwin":
52918
- return import_path.default.join(import_os.default.homedir(), "Library/Application Support");
52918
+ return import_path.default.join(import_os2.default.homedir(), "Library/Application Support");
52919
52919
  case "linux":
52920
- return import_path.default.join(import_os.default.homedir(), ".local/share");
52920
+ return import_path.default.join(import_os2.default.homedir(), ".local/share");
52921
52921
  case "win32":
52922
52922
  if (process.env.LOCALAPPDATA) {
52923
52923
  return process.env.LOCALAPPDATA;
@@ -52957,10 +52957,10 @@ var require_oauth = __commonJS({
52957
52957
  refreshTokenRequest: () => refreshTokenRequest
52958
52958
  });
52959
52959
  module2.exports = __toCommonJS(oauth_exports);
52960
- var import_os = require("os");
52960
+ var import_os2 = require("os");
52961
52961
  var VERCEL_ISSUER = "https://vercel.com";
52962
52962
  var VERCEL_CLI_CLIENT_ID = "cl_HYyOPBNtFMfHhaUn9L4QPfTZz6TP47bp";
52963
- var userAgent = `@vercel/oidc node-${process.version} ${(0, import_os.platform)()} (${(0, import_os.arch)()}) ${(0, import_os.hostname)()}`;
52963
+ var userAgent = `@vercel/oidc node-${process.version} ${(0, import_os2.platform)()} (${(0, import_os2.arch)()}) ${(0, import_os2.hostname)()}`;
52964
52964
  var _tokenEndpoint = null;
52965
52965
  async function getTokenEndpoint() {
52966
52966
  if (_tokenEndpoint) {
@@ -57019,7 +57019,7 @@ var require_thumbprint = __commonJS({
57019
57019
  var errors_js_1 = require_errors4();
57020
57020
  var buffer_utils_js_1 = require_buffer_utils();
57021
57021
  var is_object_js_1 = require_is_object();
57022
- var check = (value, description) => {
57022
+ var check2 = (value, description) => {
57023
57023
  if (typeof value !== "string" || !value) {
57024
57024
  throw new errors_js_1.JWKInvalid(`${description} missing or invalid`);
57025
57025
  }
@@ -57035,23 +57035,23 @@ var require_thumbprint = __commonJS({
57035
57035
  let components;
57036
57036
  switch (jwk.kty) {
57037
57037
  case "EC":
57038
- check(jwk.crv, '"crv" (Curve) Parameter');
57039
- check(jwk.x, '"x" (X Coordinate) Parameter');
57040
- check(jwk.y, '"y" (Y Coordinate) Parameter');
57038
+ check2(jwk.crv, '"crv" (Curve) Parameter');
57039
+ check2(jwk.x, '"x" (X Coordinate) Parameter');
57040
+ check2(jwk.y, '"y" (Y Coordinate) Parameter');
57041
57041
  components = { crv: jwk.crv, kty: jwk.kty, x: jwk.x, y: jwk.y };
57042
57042
  break;
57043
57043
  case "OKP":
57044
- check(jwk.crv, '"crv" (Subtype of Key Pair) Parameter');
57045
- check(jwk.x, '"x" (Public Key) Parameter');
57044
+ check2(jwk.crv, '"crv" (Subtype of Key Pair) Parameter');
57045
+ check2(jwk.x, '"x" (Public Key) Parameter');
57046
57046
  components = { crv: jwk.crv, kty: jwk.kty, x: jwk.x };
57047
57047
  break;
57048
57048
  case "RSA":
57049
- check(jwk.e, '"e" (Exponent) Parameter');
57050
- check(jwk.n, '"n" (Modulus) Parameter');
57049
+ check2(jwk.e, '"e" (Exponent) Parameter');
57050
+ check2(jwk.n, '"n" (Modulus) Parameter');
57051
57051
  components = { e: jwk.e, kty: jwk.kty, n: jwk.n };
57052
57052
  break;
57053
57053
  case "oct":
57054
- check(jwk.k, '"k" (Key Value) Parameter');
57054
+ check2(jwk.k, '"k" (Key Value) Parameter');
57055
57055
  components = { k: jwk.k, kty: jwk.kty };
57056
57056
  break;
57057
57057
  default:
@@ -63264,12 +63264,12 @@ var require_formdata_parser = __commonJS({
63264
63264
  return "failure";
63265
63265
  }
63266
63266
  if (bufferStartsWith(input, filenameBuffer, position)) {
63267
- let check = position.position + filenameBuffer.length;
63268
- if (input[check] === 42) {
63267
+ let check2 = position.position + filenameBuffer.length;
63268
+ if (input[check2] === 42) {
63269
63269
  position.position += 1;
63270
- check += 1;
63270
+ check2 += 1;
63271
63271
  }
63272
- if (input[check] !== 61 || input[check + 1] !== 34) {
63272
+ if (input[check2] !== 61 || input[check2 + 1] !== 34) {
63273
63273
  return "failure";
63274
63274
  }
63275
63275
  position.position += 12;
@@ -68960,7 +68960,7 @@ var require_mock_interceptor = __commonJS({
68960
68960
  var require_mock_client = __commonJS({
68961
68961
  "../../node_modules/undici/lib/mock/mock-client.js"(exports2, module2) {
68962
68962
  "use strict";
68963
- var { promisify } = require("node:util");
68963
+ var { promisify: promisify2 } = require("node:util");
68964
68964
  var Client = require_client();
68965
68965
  var { buildMockDispatch } = require_mock_utils();
68966
68966
  var {
@@ -69000,7 +69000,7 @@ var require_mock_client = __commonJS({
69000
69000
  return new MockInterceptor(opts, this[kDispatches]);
69001
69001
  }
69002
69002
  async [kClose]() {
69003
- await promisify(this[kOriginalClose])();
69003
+ await promisify2(this[kOriginalClose])();
69004
69004
  this[kConnected] = 0;
69005
69005
  this[kMockAgent][Symbols.kClients].delete(this[kOrigin]);
69006
69006
  }
@@ -69013,7 +69013,7 @@ var require_mock_client = __commonJS({
69013
69013
  var require_mock_pool = __commonJS({
69014
69014
  "../../node_modules/undici/lib/mock/mock-pool.js"(exports2, module2) {
69015
69015
  "use strict";
69016
- var { promisify } = require("node:util");
69016
+ var { promisify: promisify2 } = require("node:util");
69017
69017
  var Pool = require_pool();
69018
69018
  var { buildMockDispatch } = require_mock_utils();
69019
69019
  var {
@@ -69053,7 +69053,7 @@ var require_mock_pool = __commonJS({
69053
69053
  return new MockInterceptor(opts, this[kDispatches]);
69054
69054
  }
69055
69055
  async [kClose]() {
69056
- await promisify(this[kOriginalClose])();
69056
+ await promisify2(this[kOriginalClose])();
69057
69057
  this[kConnected] = 0;
69058
69058
  this[kMockAgent][Symbols.kClients].delete(this[kOrigin]);
69059
69059
  }
@@ -81429,14 +81429,14 @@ var require_auto_mode = __commonJS({
81429
81429
  this.broadcast();
81430
81430
  await this.tick();
81431
81431
  return new Promise((resolve) => {
81432
- const check = () => {
81432
+ const check2 = () => {
81433
81433
  if (this.finishedAt !== null) {
81434
81434
  resolve(this.snapshot());
81435
81435
  } else {
81436
81436
  this.resolveIdle = () => resolve(this.snapshot());
81437
81437
  }
81438
81438
  };
81439
- check();
81439
+ check2();
81440
81440
  });
81441
81441
  }
81442
81442
  async tick() {
@@ -82042,6 +82042,50 @@ Return this exact shape:
82042
82042
  }
82043
82043
  });
82044
82044
 
82045
+ // package.json
82046
+ var require_package = __commonJS({
82047
+ "package.json"(exports2, module2) {
82048
+ module2.exports = {
82049
+ name: "sproutkit-code",
82050
+ version: "0.1.2",
82051
+ description: "Sproutkit in your terminal \u2014 find leads, build sites, run outreach, all via chat.",
82052
+ bin: {
82053
+ sproutkit: "./dist/index.js"
82054
+ },
82055
+ type: "commonjs",
82056
+ files: [
82057
+ "dist",
82058
+ "README.md"
82059
+ ],
82060
+ engines: {
82061
+ node: ">=18"
82062
+ },
82063
+ keywords: [
82064
+ "sproutkit",
82065
+ "leads",
82066
+ "websites",
82067
+ "cli",
82068
+ "ai"
82069
+ ],
82070
+ scripts: {
82071
+ dev: "tsc && node dist/index.js",
82072
+ build: "node build.mjs && chmod +x dist/index.js",
82073
+ typecheck: "tsc --noEmit",
82074
+ prepublishOnly: "cd ../desktop && npm run build:main && cd ../sproutkit-code && npm run build"
82075
+ },
82076
+ dependencies: {
82077
+ "@anthropic-ai/sdk": "^0.30.1",
82078
+ axios: "^1.7.1",
82079
+ "node-sqlite3-wasm": "^0.8.20"
82080
+ },
82081
+ devDependencies: {
82082
+ "@types/node": "^20.14.0",
82083
+ typescript: "^5.4.0"
82084
+ }
82085
+ };
82086
+ }
82087
+ });
82088
+
82045
82089
  // src/engine.ts
82046
82090
  var db = require_db();
82047
82091
  var chat = require_chat();
@@ -82082,6 +82126,65 @@ function missingRequiredKeys() {
82082
82126
  }));
82083
82127
  }
82084
82128
 
82129
+ // src/license.ts
82130
+ var import_os = __toESM(require("os"));
82131
+ var import_crypto = require("crypto");
82132
+ var GRACE_MS = 7 * 24 * 60 * 60 * 1e3;
82133
+ function apiBase() {
82134
+ return process.env.SPROUTKIT_API_BASE_URL ?? "https://sproutkit.app";
82135
+ }
82136
+ function deviceId() {
82137
+ const macs = Object.values(import_os.default.networkInterfaces()).flat().filter((i) => !!i && !i.internal).map((i) => i.mac).filter((m) => m && m !== "00:00:00:00:00:00");
82138
+ return (0, import_crypto.createHash)("sha256").update(`${macs[0] ?? "unknown"}|${import_os.default.hostname()}`).digest("hex").slice(0, 32);
82139
+ }
82140
+ async function callValidate(key) {
82141
+ try {
82142
+ const r = await fetch(`${apiBase()}/api/licenses/validate`, {
82143
+ method: "POST",
82144
+ headers: { "Content-Type": "application/json" },
82145
+ body: JSON.stringify({ key, deviceId: deviceId() }),
82146
+ signal: AbortSignal.timeout(8e3)
82147
+ });
82148
+ if (!r.ok) return null;
82149
+ return await r.json();
82150
+ } catch {
82151
+ return null;
82152
+ }
82153
+ }
82154
+ async function activate(key) {
82155
+ const trimmed = key.trim();
82156
+ const result = await callValidate(trimmed);
82157
+ if (!result) return { status: "missing" };
82158
+ if (!result.valid) {
82159
+ return {
82160
+ status: result.reason === "revoked" ? "revoked" : result.reason === "refunded" ? "refunded" : "missing",
82161
+ email: result.email
82162
+ };
82163
+ }
82164
+ setSetting("license_key", trimmed);
82165
+ setSetting("license_email", result.email ?? "");
82166
+ setSetting("license_validated_at", String(Date.now()));
82167
+ return { status: "active", email: result.email };
82168
+ }
82169
+ async function check() {
82170
+ const key = getSetting("license_key");
82171
+ if (!key) return { status: "missing" };
82172
+ const result = await callValidate(key);
82173
+ if (result) {
82174
+ if (result.valid) {
82175
+ setSetting("license_validated_at", String(Date.now()));
82176
+ return { status: "active", email: result.email };
82177
+ }
82178
+ return {
82179
+ status: result.reason === "revoked" ? "revoked" : result.reason === "refunded" ? "refunded" : "missing",
82180
+ email: result.email
82181
+ };
82182
+ }
82183
+ const last = Number(getSetting("license_validated_at") ?? 0);
82184
+ if (Date.now() - last < GRACE_MS) return { status: "active" };
82185
+ return { status: "offline_grace_expired" };
82186
+ }
82187
+
82085
82188
  // src/tty.ts
82086
82189
  var import_readline = __toESM(require("readline"));
82087
82190
  var useColor = process.stdout.isTTY && !process.env.NO_COLOR;
@@ -82135,14 +82238,42 @@ function say(msg = "") {
82135
82238
  }
82136
82239
 
82137
82240
  // src/onboarding.ts
82241
+ async function onboardLicense(force) {
82242
+ if (!force) {
82243
+ const state = await check();
82244
+ if (state.status === "active") return true;
82245
+ }
82246
+ say(` ${c.bold("Licence key")}`);
82247
+ say(` ${c.dim("From your Sproutkit purchase \u2014 the same key the desktop app uses.")}`);
82248
+ while (true) {
82249
+ const key = await askSecret(c.green(" \u203A "));
82250
+ if (!key) {
82251
+ say(c.amber(" A licence is required to use Sproutkit. Get one at https://sproutkit.app"));
82252
+ say();
82253
+ return false;
82254
+ }
82255
+ say(c.dim(" \u2026 validating"));
82256
+ const state = await activate(key);
82257
+ if (state.status === "active") {
82258
+ say(c.green(` \u2713 Licence active${state.email ? ` (${state.email})` : ""}.`));
82259
+ say();
82260
+ return true;
82261
+ }
82262
+ const msg = state.status === "revoked" ? "That licence has been revoked." : state.status === "refunded" ? "That licence was refunded." : "Couldn't validate that key (check it, or your connection).";
82263
+ say(c.red(` ${msg} Try again, or press Enter to quit.`));
82264
+ }
82265
+ }
82138
82266
  async function runOnboarding(force = false) {
82139
82267
  const missing = missingRequiredKeys();
82140
- if (!force && missing.length === 0) return;
82268
+ const licensed = (await check()).status === "active";
82269
+ if (!force && missing.length === 0 && licensed) return true;
82141
82270
  say();
82142
82271
  say(c.greenBold(" Welcome to Sproutkit Code"));
82143
- say(c.dim(" Let's connect your accounts. Keys are stored locally in ~/.sproutkit and never leave your machine."));
82272
+ say(c.dim(" Let's get you set up. Keys are stored locally in ~/.sproutkit and never leave your machine."));
82144
82273
  say(c.dim(" You can re-run this anytime with: sproutkit setup"));
82145
82274
  say();
82275
+ const ok = await onboardLicense(force);
82276
+ if (!ok) return false;
82146
82277
  for (const k of REQUIRED_KEYS) {
82147
82278
  const existing = getSetting(k.key);
82148
82279
  if (existing && !force) continue;
@@ -82164,6 +82295,7 @@ async function runOnboarding(force = false) {
82164
82295
  say(c.green(" \u2713 All set. Type a message to get going \u2014 try \u201Cfind barber shops in Shoreditch\u201D."));
82165
82296
  say();
82166
82297
  }
82298
+ return true;
82167
82299
  }
82168
82300
 
82169
82301
  // src/invoke-ipc.ts
@@ -82361,11 +82493,86 @@ async function runTurn(userMessage) {
82361
82493
  }
82362
82494
  }
82363
82495
 
82496
+ // src/update.ts
82497
+ var import_child_process = require("child_process");
82498
+ var import_util = require("util");
82499
+ var execFileP = (0, import_util.promisify)(import_child_process.execFile);
82500
+ var PKG = "sproutkit-code";
82501
+ var CURRENT_VERSION = require_package().version;
82502
+ async function latestOnRegistry() {
82503
+ try {
82504
+ const r = await fetch(`https://registry.npmjs.org/${PKG}/latest`, {
82505
+ signal: AbortSignal.timeout(5e3)
82506
+ });
82507
+ if (!r.ok) return null;
82508
+ const j = await r.json();
82509
+ return j.version ?? null;
82510
+ } catch {
82511
+ return null;
82512
+ }
82513
+ }
82514
+ function isNewer(a, b) {
82515
+ const pa = a.split(".").map(Number);
82516
+ const pb = b.split(".").map(Number);
82517
+ for (let i = 0; i < 3; i++) {
82518
+ if ((pa[i] ?? 0) > (pb[i] ?? 0)) return true;
82519
+ if ((pa[i] ?? 0) < (pb[i] ?? 0)) return false;
82520
+ }
82521
+ return false;
82522
+ }
82523
+ async function runUpdate() {
82524
+ say(c.dim(` Current version ${CURRENT_VERSION}. Checking npm\u2026`));
82525
+ const latest = await latestOnRegistry();
82526
+ if (!latest) {
82527
+ say(c.amber(" Couldn't reach npm. Check your connection and try again."));
82528
+ return;
82529
+ }
82530
+ if (!isNewer(latest, CURRENT_VERSION)) {
82531
+ say(c.green(` \u2713 You're on the latest version (${CURRENT_VERSION}).`));
82532
+ return;
82533
+ }
82534
+ say(c.dim(` Updating ${CURRENT_VERSION} \u2192 ${latest}\u2026`));
82535
+ try {
82536
+ await execFileP("npm", ["install", "-g", `${PKG}@latest`], { timeout: 12e4 });
82537
+ say(c.green(` \u2713 Updated to ${latest}. Restart sproutkit to use it.`));
82538
+ } catch (e) {
82539
+ say(c.red(` Update failed: ${e.message}`));
82540
+ say(c.dim(` Try manually: npm install -g ${PKG}@latest`));
82541
+ }
82542
+ }
82543
+ async function notifyIfOutdated() {
82544
+ try {
82545
+ const last = Number(getSetting("update_checked_at") ?? 0);
82546
+ if (Date.now() - last < 24 * 60 * 60 * 1e3) return;
82547
+ setSetting("update_checked_at", String(Date.now()));
82548
+ const latest = await latestOnRegistry();
82549
+ if (latest && isNewer(latest, CURRENT_VERSION)) {
82550
+ say(
82551
+ c.amber(
82552
+ ` \u2191 Update available: ${CURRENT_VERSION} \u2192 ${latest}. Run 'sproutkit update'.`
82553
+ )
82554
+ );
82555
+ say();
82556
+ }
82557
+ } catch {
82558
+ }
82559
+ }
82560
+
82364
82561
  // src/index.ts
82365
82562
  process.env.SPROUTKIT_HEADLESS = "1";
82366
82563
  async function main() {
82367
82564
  const arg = process.argv[2];
82368
82565
  initDatabase();
82566
+ if (arg === "update") {
82567
+ await runUpdate();
82568
+ closeTty();
82569
+ return;
82570
+ }
82571
+ if (arg === "version" || arg === "--version" || arg === "-v") {
82572
+ say(CURRENT_VERSION);
82573
+ closeTty();
82574
+ return;
82575
+ }
82369
82576
  if (arg === "setup") {
82370
82577
  await runOnboarding(true);
82371
82578
  closeTty();
@@ -82377,7 +82584,9 @@ async function main() {
82377
82584
  say(" Find leads, build sites and run outreach from your terminal.");
82378
82585
  say();
82379
82586
  say(` ${c.bold("sproutkit")} start the chat`);
82380
- say(` ${c.bold("sproutkit setup")} set or update your API keys`);
82587
+ say(` ${c.bold("sproutkit setup")} set or update your keys and licence`);
82588
+ say(` ${c.bold("sproutkit update")} update to the latest version`);
82589
+ say(` ${c.bold("sproutkit version")} show the installed version`);
82381
82590
  say(` ${c.bold('sproutkit "..."')} run a single message and exit`);
82382
82591
  say();
82383
82592
  say(c.dim(" In chat: type a request, Ctrl+C to quit. Actions that spend money ask y/N first."));
@@ -82385,13 +82594,25 @@ async function main() {
82385
82594
  closeTty();
82386
82595
  return;
82387
82596
  }
82388
- await runOnboarding(false);
82597
+ const ready = await runOnboarding(false);
82598
+ if (!ready) {
82599
+ closeTty();
82600
+ return;
82601
+ }
82602
+ const lic = await check();
82603
+ if (lic.status !== "active") {
82604
+ const why = lic.status === "revoked" ? "Your licence has been revoked." : lic.status === "refunded" ? "Your licence was refunded." : lic.status === "offline_grace_expired" ? "Can't reach the licence server and your offline grace period has expired. Reconnect and try again." : "No active licence. Run 'sproutkit setup' to enter your key, or buy one at https://sproutkit.app";
82605
+ say(c.red(` ${why}`));
82606
+ closeTty();
82607
+ return;
82608
+ }
82389
82609
  const oneShot = process.argv.slice(2).join(" ").trim();
82390
82610
  if (oneShot) {
82391
82611
  await runTurn(oneShot);
82392
82612
  closeTty();
82393
82613
  return;
82394
82614
  }
82615
+ await notifyIfOutdated();
82395
82616
  say(c.dim(" Chat with Sproutkit. Type a request, or 'exit' to quit."));
82396
82617
  say();
82397
82618
  while (true) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sproutkit-code",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
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"