@keepgoingdev/cli 1.4.0 → 1.5.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 +209 -130
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2801,96 +2801,7 @@ function renderEnrichedBriefingQuiet(briefing) {
2801
2801
  console.log(`KeepGoing \xB7 ${core.lastWorked} \xB7 Focus: ${core.currentFocus} \xB7 Next: ${core.smallNextStep}`);
2802
2802
  }
2803
2803
 
2804
- // src/updateCheck.ts
2805
- import { spawn } from "child_process";
2806
- import { readFileSync, existsSync } from "fs";
2807
- import path11 from "path";
2808
- import os5 from "os";
2809
- var CLI_VERSION = "1.4.0";
2810
- var NPM_REGISTRY_URL = "https://registry.npmjs.org/@keepgoingdev/cli/latest";
2811
- var FETCH_TIMEOUT_MS = 5e3;
2812
- var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
2813
- var CACHE_DIR = path11.join(os5.homedir(), ".keepgoing");
2814
- var CACHE_PATH = path11.join(CACHE_DIR, "update-check.json");
2815
- function isNewerVersion(current, latest) {
2816
- const cur = current.split(".").map(Number);
2817
- const lat = latest.split(".").map(Number);
2818
- for (let i = 0; i < 3; i++) {
2819
- if ((lat[i] ?? 0) > (cur[i] ?? 0)) return true;
2820
- if ((lat[i] ?? 0) < (cur[i] ?? 0)) return false;
2821
- }
2822
- return false;
2823
- }
2824
- function getCachedUpdateInfo() {
2825
- try {
2826
- if (!existsSync(CACHE_PATH)) return null;
2827
- const raw = readFileSync(CACHE_PATH, "utf-8");
2828
- const cache = JSON.parse(raw);
2829
- if (!cache.latest || !cache.checkedAt) return null;
2830
- const age = Date.now() - new Date(cache.checkedAt).getTime();
2831
- if (age > CHECK_INTERVAL_MS || cache.current !== CLI_VERSION) return null;
2832
- return {
2833
- current: CLI_VERSION,
2834
- latest: cache.latest,
2835
- updateAvailable: isNewerVersion(CLI_VERSION, cache.latest)
2836
- };
2837
- } catch {
2838
- return null;
2839
- }
2840
- }
2841
- function spawnBackgroundCheck() {
2842
- try {
2843
- if (existsSync(CACHE_PATH)) {
2844
- const raw = readFileSync(CACHE_PATH, "utf-8");
2845
- const cache = JSON.parse(raw);
2846
- const age = Date.now() - new Date(cache.checkedAt).getTime();
2847
- if (age < CHECK_INTERVAL_MS && cache.current === CLI_VERSION) return;
2848
- }
2849
- } catch {
2850
- }
2851
- const script = `
2852
- const https = require('https');
2853
- const fs = require('fs');
2854
- const path = require('path');
2855
- const os = require('os');
2856
-
2857
- const url = ${JSON.stringify(NPM_REGISTRY_URL)};
2858
- const cacheDir = path.join(os.homedir(), '.keepgoing');
2859
- const cachePath = path.join(cacheDir, 'update-check.json');
2860
- const currentVersion = ${JSON.stringify(CLI_VERSION)};
2861
-
2862
- const req = https.get(url, { timeout: ${FETCH_TIMEOUT_MS} }, (res) => {
2863
- let data = '';
2864
- res.on('data', (chunk) => { data += chunk; });
2865
- res.on('end', () => {
2866
- try {
2867
- const latest = JSON.parse(data).version;
2868
- if (!latest) process.exit(0);
2869
- if (!fs.existsSync(cacheDir)) fs.mkdirSync(cacheDir, { recursive: true });
2870
- fs.writeFileSync(cachePath, JSON.stringify({
2871
- latest,
2872
- current: currentVersion,
2873
- checkedAt: new Date().toISOString(),
2874
- }));
2875
- } catch {}
2876
- process.exit(0);
2877
- });
2878
- });
2879
- req.on('error', () => process.exit(0));
2880
- req.on('timeout', () => { req.destroy(); process.exit(0); });
2881
- `;
2882
- const child = spawn(process.execPath, ["-e", script], {
2883
- detached: true,
2884
- stdio: "ignore",
2885
- env: { ...process.env }
2886
- });
2887
- child.unref();
2888
- }
2889
-
2890
2804
  // src/commands/status.ts
2891
- var RESET2 = "\x1B[0m";
2892
- var BOLD2 = "\x1B[1m";
2893
- var DIM2 = "\x1B[2m";
2894
2805
  async function statusCommand(opts) {
2895
2806
  const reader = new KeepGoingReader(opts.cwd);
2896
2807
  if (!reader.exists()) {
@@ -2918,15 +2829,10 @@ async function statusCommand(opts) {
2918
2829
  (Date.now() - new Date(lastSession.timestamp).getTime()) / (1e3 * 60 * 60 * 24)
2919
2830
  );
2920
2831
  renderCheckpoint(lastSession, daysSince);
2921
- const cached = getCachedUpdateInfo();
2922
- if (cached?.updateAvailable) {
2923
- console.log(`${DIM2}Update available: ${cached.current} \u2192 ${cached.latest}. Run: ${RESET2}${BOLD2}npm install -g @keepgoingdev/cli@latest${RESET2}`);
2924
- }
2925
- spawnBackgroundCheck();
2926
2832
  }
2927
2833
 
2928
2834
  // src/commands/save.ts
2929
- import path12 from "path";
2835
+ import path11 from "path";
2930
2836
  async function saveCommand(opts) {
2931
2837
  const { cwd, message, nextStepOverride, json, quiet, force } = opts;
2932
2838
  const isManual = !!message;
@@ -2955,9 +2861,9 @@ async function saveCommand(opts) {
2955
2861
  sessionStartTime: lastSession?.timestamp ?? now,
2956
2862
  lastActivityTime: now
2957
2863
  });
2958
- const summary = message ?? buildSmartSummary(events) ?? `Worked on ${touchedFiles.slice(0, 5).map((f) => path12.basename(f)).join(", ")}`;
2864
+ const summary = message ?? buildSmartSummary(events) ?? `Worked on ${touchedFiles.slice(0, 5).map((f) => path11.basename(f)).join(", ")}`;
2959
2865
  const nextStep = nextStepOverride ?? buildSmartNextStep(events);
2960
- const projectName = path12.basename(resolveStorageRoot(cwd));
2866
+ const projectName = path11.basename(resolveStorageRoot(cwd));
2961
2867
  const sessionId = generateSessionId({
2962
2868
  workspaceRoot: cwd,
2963
2869
  branch: gitBranch ?? void 0,
@@ -2991,16 +2897,16 @@ async function saveCommand(opts) {
2991
2897
 
2992
2898
  // src/commands/hook.ts
2993
2899
  import fs9 from "fs";
2994
- import path13 from "path";
2995
- import os6 from "os";
2900
+ import path12 from "path";
2901
+ import os5 from "os";
2996
2902
  import { execSync as execSync2 } from "child_process";
2997
2903
  var HOOK_MARKER_START = "# keepgoing-hook-start";
2998
2904
  var HOOK_MARKER_END = "# keepgoing-hook-end";
2999
2905
  var POST_COMMIT_MARKER_START = "# keepgoing-post-commit-start";
3000
2906
  var POST_COMMIT_MARKER_END = "# keepgoing-post-commit-end";
3001
- var KEEPGOING_HOOKS_DIR = path13.join(os6.homedir(), ".keepgoing", "hooks");
3002
- var POST_COMMIT_HOOK_PATH = path13.join(KEEPGOING_HOOKS_DIR, "post-commit");
3003
- var KEEPGOING_MANAGED_MARKER = path13.join(KEEPGOING_HOOKS_DIR, ".keepgoing-managed");
2907
+ var KEEPGOING_HOOKS_DIR = path12.join(os5.homedir(), ".keepgoing", "hooks");
2908
+ var POST_COMMIT_HOOK_PATH = path12.join(KEEPGOING_HOOKS_DIR, "post-commit");
2909
+ var KEEPGOING_MANAGED_MARKER = path12.join(KEEPGOING_HOOKS_DIR, ".keepgoing-managed");
3004
2910
  var POST_COMMIT_HOOK = `#!/bin/sh
3005
2911
  ${POST_COMMIT_MARKER_START}
3006
2912
  # Runs after every git commit. Detects high-signal decisions.
@@ -3041,7 +2947,7 @@ if command -v keepgoing >/dev/null 2>&1
3041
2947
  end
3042
2948
  ${HOOK_MARKER_END}`;
3043
2949
  function detectShellInfo(shellOverride) {
3044
- const home = os6.homedir();
2950
+ const home = os5.homedir();
3045
2951
  let shell;
3046
2952
  if (shellOverride) {
3047
2953
  shell = shellOverride.toLowerCase();
@@ -3064,14 +2970,14 @@ function detectShellInfo(shellOverride) {
3064
2970
  }
3065
2971
  }
3066
2972
  if (shell === "zsh") {
3067
- return { shell: "zsh", rcFile: path13.join(home, ".zshrc") };
2973
+ return { shell: "zsh", rcFile: path12.join(home, ".zshrc") };
3068
2974
  }
3069
2975
  if (shell === "bash") {
3070
- return { shell: "bash", rcFile: path13.join(home, ".bashrc") };
2976
+ return { shell: "bash", rcFile: path12.join(home, ".bashrc") };
3071
2977
  }
3072
2978
  if (shell === "fish") {
3073
- const xdgConfig = process.env["XDG_CONFIG_HOME"] || path13.join(home, ".config");
3074
- return { shell: "fish", rcFile: path13.join(xdgConfig, "fish", "config.fish") };
2979
+ const xdgConfig = process.env["XDG_CONFIG_HOME"] || path12.join(home, ".config");
2980
+ return { shell: "fish", rcFile: path12.join(xdgConfig, "fish", "config.fish") };
3075
2981
  }
3076
2982
  return void 0;
3077
2983
  }
@@ -3102,11 +3008,11 @@ function resolveGlobalGitignorePath() {
3102
3008
  stdio: ["pipe", "pipe", "pipe"]
3103
3009
  }).trim();
3104
3010
  if (configured) {
3105
- return configured.startsWith("~") ? path13.join(os6.homedir(), configured.slice(1)) : configured;
3011
+ return configured.startsWith("~") ? path12.join(os5.homedir(), configured.slice(1)) : configured;
3106
3012
  }
3107
3013
  } catch {
3108
3014
  }
3109
- return path13.join(os6.homedir(), ".gitignore_global");
3015
+ return path12.join(os5.homedir(), ".gitignore_global");
3110
3016
  }
3111
3017
  function performGlobalGitignore() {
3112
3018
  const ignorePath = resolveGlobalGitignorePath();
@@ -3426,12 +3332,12 @@ async function briefingCommand(opts) {
3426
3332
  }
3427
3333
 
3428
3334
  // src/commands/init.ts
3429
- var RESET3 = "\x1B[0m";
3430
- var BOLD3 = "\x1B[1m";
3335
+ var RESET2 = "\x1B[0m";
3336
+ var BOLD2 = "\x1B[1m";
3431
3337
  var GREEN2 = "\x1B[32m";
3432
3338
  var YELLOW2 = "\x1B[33m";
3433
3339
  var CYAN2 = "\x1B[36m";
3434
- var DIM3 = "\x1B[2m";
3340
+ var DIM2 = "\x1B[2m";
3435
3341
  function initCommand(options) {
3436
3342
  const scope = options.scope === "user" ? "user" : "project";
3437
3343
  const result = setupProject({
@@ -3439,7 +3345,7 @@ function initCommand(options) {
3439
3345
  scope
3440
3346
  });
3441
3347
  console.log(`
3442
- ${BOLD3}KeepGoing Init${RESET3} ${DIM3}(${scope} scope)${RESET3}
3348
+ ${BOLD2}KeepGoing Init${RESET2} ${DIM2}(${scope} scope)${RESET2}
3443
3349
  `);
3444
3350
  for (const msg of result.messages) {
3445
3351
  const colonIdx = msg.indexOf(":");
@@ -3450,16 +3356,16 @@ ${BOLD3}KeepGoing Init${RESET3} ${DIM3}(${scope} scope)${RESET3}
3450
3356
  const label = msg.slice(0, colonIdx + 1);
3451
3357
  const body = msg.slice(colonIdx + 1);
3452
3358
  if (label.startsWith("Warning")) {
3453
- console.log(` ${YELLOW2}${label}${RESET3}${body}`);
3359
+ console.log(` ${YELLOW2}${label}${RESET2}${body}`);
3454
3360
  } else if (body.includes("Added")) {
3455
- console.log(` ${GREEN2}${label}${RESET3}${body}`);
3361
+ console.log(` ${GREEN2}${label}${RESET2}${body}`);
3456
3362
  } else {
3457
- console.log(` ${CYAN2}${label}${RESET3}${body}`);
3363
+ console.log(` ${CYAN2}${label}${RESET2}${body}`);
3458
3364
  }
3459
3365
  }
3460
3366
  if (result.changed) {
3461
3367
  console.log(`
3462
- ${GREEN2}Done!${RESET3} KeepGoing is set up for this project.
3368
+ ${GREEN2}Done!${RESET2} KeepGoing is set up for this project.
3463
3369
  `);
3464
3370
  } else {
3465
3371
  console.log(`
@@ -3470,8 +3376,8 @@ Everything was already configured. No changes made.
3470
3376
 
3471
3377
  // src/commands/setup.ts
3472
3378
  import fs10 from "fs";
3473
- import path14 from "path";
3474
- import os7 from "os";
3379
+ import path13 from "path";
3380
+ import os6 from "os";
3475
3381
  import { execSync as execSync3, exec as exec2 } from "child_process";
3476
3382
  import { promisify as promisify2 } from "util";
3477
3383
 
@@ -5433,14 +5339,14 @@ function detectJetBrainsIdes() {
5433
5339
  if (process.platform !== "darwin") return [];
5434
5340
  return JETBRAINS_IDES.filter((ide) => {
5435
5341
  try {
5436
- return fs10.statSync(path14.join("/Applications", ide.app)).isDirectory();
5342
+ return fs10.statSync(path13.join("/Applications", ide.app)).isDirectory();
5437
5343
  } catch {
5438
5344
  return false;
5439
5345
  }
5440
5346
  });
5441
5347
  }
5442
5348
  async function setupCommand(options) {
5443
- const displayPath = options.cwd.startsWith(os7.homedir()) ? "~" + options.cwd.slice(os7.homedir().length) : options.cwd;
5349
+ const displayPath = options.cwd.startsWith(os6.homedir()) ? "~" + options.cwd.slice(os6.homedir().length) : options.cwd;
5444
5350
  const presetDefaults = options.preset ? PRESET_DEFAULTS[options.preset] : void 0;
5445
5351
  const presetLabel = options.preset ? PRESET_LABELS[options.preset] : void 0;
5446
5352
  dist_exports.intro(presetLabel ? `KeepGoing Setup - ${presetLabel}` : "KeepGoing Setup Wizard");
@@ -5793,10 +5699,10 @@ async function setupCommand(options) {
5793
5699
  claudePlugin,
5794
5700
  licensed
5795
5701
  };
5796
- const keepgoingDir = path14.join(os7.homedir(), ".keepgoing");
5702
+ const keepgoingDir = path13.join(os6.homedir(), ".keepgoing");
5797
5703
  fs10.mkdirSync(keepgoingDir, { recursive: true });
5798
5704
  fs10.writeFileSync(
5799
- path14.join(keepgoingDir, "setup-profile.json"),
5705
+ path13.join(keepgoingDir, "setup-profile.json"),
5800
5706
  JSON.stringify(profile, null, 2) + "\n",
5801
5707
  "utf-8"
5802
5708
  );
@@ -6007,8 +5913,8 @@ function filterDecisions(decisions, opts) {
6007
5913
  }
6008
5914
 
6009
5915
  // src/commands/log.ts
6010
- var RESET4 = "\x1B[0m";
6011
- var DIM4 = "\x1B[2m";
5916
+ var RESET3 = "\x1B[0m";
5917
+ var DIM3 = "\x1B[2m";
6012
5918
  function logSessions(reader, opts) {
6013
5919
  const { effectiveBranch } = reader.resolveBranchScope(opts.branch || void 0);
6014
5920
  let sessions = reader.getSessions();
@@ -6019,7 +5925,7 @@ function logSessions(reader, opts) {
6019
5925
  sessions = filterSessions(sessions, opts);
6020
5926
  const totalFiltered = sessions.length;
6021
5927
  if (totalFiltered === 0) {
6022
- console.log(`${DIM4}No checkpoints match the given filters.${RESET4}`);
5928
+ console.log(`${DIM3}No checkpoints match the given filters.${RESET3}`);
6023
5929
  return;
6024
5930
  }
6025
5931
  const displayed = sessions.slice(0, opts.count);
@@ -6043,7 +5949,7 @@ function logSessions(reader, opts) {
6043
5949
  }
6044
5950
  }
6045
5951
  if (totalFiltered > opts.count) {
6046
- console.log(`${DIM4}(showing ${displayed.length} of ${totalFiltered} checkpoints)${RESET4}`);
5952
+ console.log(`${DIM3}(showing ${displayed.length} of ${totalFiltered} checkpoints)${RESET3}`);
6047
5953
  }
6048
5954
  }
6049
5955
  function renderGrouped(sessions, showStat) {
@@ -6082,7 +5988,7 @@ async function logDecisions(reader, opts) {
6082
5988
  decisions = filterDecisions(decisions, opts);
6083
5989
  const totalFiltered = decisions.length;
6084
5990
  if (totalFiltered === 0) {
6085
- console.log(`${DIM4}No decisions match the given filters.${RESET4}`);
5991
+ console.log(`${DIM3}No decisions match the given filters.${RESET3}`);
6086
5992
  return;
6087
5993
  }
6088
5994
  const displayed = decisions.slice(0, opts.count);
@@ -6104,7 +6010,7 @@ async function logDecisions(reader, opts) {
6104
6010
  }
6105
6011
  }
6106
6012
  if (totalFiltered > opts.count) {
6107
- console.log(`${DIM4}(showing ${displayed.length} of ${totalFiltered} decisions)${RESET4}`);
6013
+ console.log(`${DIM3}(showing ${displayed.length} of ${totalFiltered} decisions)${RESET3}`);
6108
6014
  }
6109
6015
  }
6110
6016
  async function logCommand(opts) {
@@ -6245,6 +6151,154 @@ function hotCommand(opts) {
6245
6151
  }
6246
6152
  }
6247
6153
 
6154
+ // src/commands/update.ts
6155
+ import { execSync as execSync5 } from "child_process";
6156
+
6157
+ // src/updateCheck.ts
6158
+ import { spawn } from "child_process";
6159
+ import { readFileSync, existsSync } from "fs";
6160
+ import path14 from "path";
6161
+ import os7 from "os";
6162
+ var CLI_VERSION = "1.5.0";
6163
+ var NPM_REGISTRY_URL = "https://registry.npmjs.org/@keepgoingdev/cli/latest";
6164
+ var FETCH_TIMEOUT_MS = 5e3;
6165
+ var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
6166
+ var CACHE_DIR = path14.join(os7.homedir(), ".keepgoing");
6167
+ var CACHE_PATH = path14.join(CACHE_DIR, "update-check.json");
6168
+ function isNewerVersion(current, latest) {
6169
+ const cur = current.split(".").map(Number);
6170
+ const lat = latest.split(".").map(Number);
6171
+ for (let i = 0; i < 3; i++) {
6172
+ if ((lat[i] ?? 0) > (cur[i] ?? 0)) return true;
6173
+ if ((lat[i] ?? 0) < (cur[i] ?? 0)) return false;
6174
+ }
6175
+ return false;
6176
+ }
6177
+ function getCachedUpdateInfo() {
6178
+ try {
6179
+ if (!existsSync(CACHE_PATH)) return null;
6180
+ const raw = readFileSync(CACHE_PATH, "utf-8");
6181
+ const cache = JSON.parse(raw);
6182
+ if (!cache.latest || !cache.checkedAt) return null;
6183
+ const age = Date.now() - new Date(cache.checkedAt).getTime();
6184
+ if (age > CHECK_INTERVAL_MS || cache.current !== CLI_VERSION) return null;
6185
+ return {
6186
+ current: CLI_VERSION,
6187
+ latest: cache.latest,
6188
+ updateAvailable: isNewerVersion(CLI_VERSION, cache.latest)
6189
+ };
6190
+ } catch {
6191
+ return null;
6192
+ }
6193
+ }
6194
+ function spawnBackgroundCheck() {
6195
+ try {
6196
+ if (existsSync(CACHE_PATH)) {
6197
+ const raw = readFileSync(CACHE_PATH, "utf-8");
6198
+ const cache = JSON.parse(raw);
6199
+ const age = Date.now() - new Date(cache.checkedAt).getTime();
6200
+ if (age < CHECK_INTERVAL_MS && cache.current === CLI_VERSION) return;
6201
+ }
6202
+ } catch {
6203
+ }
6204
+ const script = `
6205
+ const https = require('https');
6206
+ const fs = require('fs');
6207
+ const path = require('path');
6208
+ const os = require('os');
6209
+
6210
+ const url = ${JSON.stringify(NPM_REGISTRY_URL)};
6211
+ const cacheDir = path.join(os.homedir(), '.keepgoing');
6212
+ const cachePath = path.join(cacheDir, 'update-check.json');
6213
+ const currentVersion = ${JSON.stringify(CLI_VERSION)};
6214
+
6215
+ const req = https.get(url, { timeout: ${FETCH_TIMEOUT_MS} }, (res) => {
6216
+ let data = '';
6217
+ res.on('data', (chunk) => { data += chunk; });
6218
+ res.on('end', () => {
6219
+ try {
6220
+ const latest = JSON.parse(data).version;
6221
+ if (!latest) process.exit(0);
6222
+ if (!fs.existsSync(cacheDir)) fs.mkdirSync(cacheDir, { recursive: true });
6223
+ fs.writeFileSync(cachePath, JSON.stringify({
6224
+ latest,
6225
+ current: currentVersion,
6226
+ checkedAt: new Date().toISOString(),
6227
+ }));
6228
+ } catch {}
6229
+ process.exit(0);
6230
+ });
6231
+ });
6232
+ req.on('error', () => process.exit(0));
6233
+ req.on('timeout', () => { req.destroy(); process.exit(0); });
6234
+ `;
6235
+ const child = spawn(process.execPath, ["-e", script], {
6236
+ detached: true,
6237
+ stdio: "ignore",
6238
+ env: { ...process.env }
6239
+ });
6240
+ child.unref();
6241
+ }
6242
+
6243
+ // src/commands/update.ts
6244
+ var RESET4 = "\x1B[0m";
6245
+ var BOLD3 = "\x1B[1m";
6246
+ var DIM4 = "\x1B[2m";
6247
+ var GREEN3 = "\x1B[32m";
6248
+ var YELLOW3 = "\x1B[33m";
6249
+ var CLI_VERSION2 = "1.5.0";
6250
+ async function updateCommand() {
6251
+ console.log(`
6252
+ ${BOLD3}KeepGoing CLI${RESET4} ${DIM4}v${CLI_VERSION2}${RESET4}
6253
+ `);
6254
+ console.log(`${DIM4}Checking for updates...${RESET4}`);
6255
+ let latest;
6256
+ try {
6257
+ latest = execSync5("npm view @keepgoingdev/cli version", {
6258
+ encoding: "utf-8",
6259
+ timeout: 1e4,
6260
+ stdio: ["pipe", "pipe", "pipe"]
6261
+ }).trim();
6262
+ } catch {
6263
+ console.error(`${YELLOW3}Could not reach the npm registry. Check your network connection.${RESET4}
6264
+ `);
6265
+ process.exit(1);
6266
+ }
6267
+ if (!latest) {
6268
+ console.error(`${YELLOW3}Could not determine the latest version.${RESET4}
6269
+ `);
6270
+ process.exit(1);
6271
+ }
6272
+ const current = CLI_VERSION2;
6273
+ const updateAvailable = isNewerVersion(current, latest);
6274
+ if (!updateAvailable) {
6275
+ console.log(`${GREEN3}Already up to date.${RESET4}
6276
+ `);
6277
+ return;
6278
+ }
6279
+ console.log(`${YELLOW3}Update available:${RESET4} ${DIM4}${current}${RESET4} -> ${BOLD3}${latest}${RESET4}
6280
+ `);
6281
+ console.log(`${DIM4}Installing @keepgoingdev/cli@${latest}...${RESET4}
6282
+ `);
6283
+ try {
6284
+ execSync5(`npm install -g @keepgoingdev/cli@${latest}`, {
6285
+ encoding: "utf-8",
6286
+ timeout: 6e4,
6287
+ stdio: "inherit"
6288
+ });
6289
+ console.log(`
6290
+ ${GREEN3}Updated to v${latest}${RESET4}
6291
+ `);
6292
+ } catch {
6293
+ console.error(`
6294
+ ${YELLOW3}Update failed.${RESET4} Try manually:
6295
+ `);
6296
+ console.error(` ${BOLD3}npm install -g @keepgoingdev/cli@latest${RESET4}
6297
+ `);
6298
+ process.exit(1);
6299
+ }
6300
+ }
6301
+
6248
6302
  // src/index.ts
6249
6303
  var HELP_TEXT = `
6250
6304
  keepgoing: resume side projects without the mental friction
@@ -6264,6 +6318,7 @@ Commands:
6264
6318
  continue Export context for use in another AI tool
6265
6319
  save Save a checkpoint (auto-generates from git)
6266
6320
  hook Manage the shell hook (zsh, bash, fish)
6321
+ update Update the CLI to the latest version
6267
6322
  activate <key> Activate a Pro license on this device
6268
6323
  deactivate Deactivate the Pro license from this device
6269
6324
 
@@ -6428,6 +6483,13 @@ Usage: keepgoing activate <key>
6428
6483
 
6429
6484
  Example:
6430
6485
  keepgoing activate XXXX-XXXX-XXXX-XXXX
6486
+ `,
6487
+ update: `
6488
+ keepgoing update: Update the CLI to the latest version
6489
+
6490
+ Usage: keepgoing update
6491
+
6492
+ Checks the npm registry for a newer version and installs it globally.
6431
6493
  `,
6432
6494
  deactivate: `
6433
6495
  keepgoing deactivate: Deactivate the Pro license from this device
@@ -6709,8 +6771,11 @@ async function main() {
6709
6771
  console.log(COMMAND_HELP.hook);
6710
6772
  }
6711
6773
  break;
6774
+ case "update":
6775
+ await updateCommand();
6776
+ break;
6712
6777
  case "version":
6713
- console.log(`keepgoing v${"1.4.0"}`);
6778
+ console.log(`keepgoing v${"1.5.0"}`);
6714
6779
  break;
6715
6780
  case "activate":
6716
6781
  await activateCommand({ licenseKey: subcommand });
@@ -6725,6 +6790,20 @@ async function main() {
6725
6790
  console.error(`Unknown command: "${command}". Run "keepgoing --help" for usage.`);
6726
6791
  process.exit(1);
6727
6792
  }
6793
+ if (command && command !== "update" && command !== "version" && command !== "help" && !json && !quiet && !parsed.help) {
6794
+ showUpdateHint();
6795
+ }
6796
+ }
6797
+ function showUpdateHint() {
6798
+ const cached = getCachedUpdateInfo();
6799
+ if (cached?.updateAvailable) {
6800
+ const DIM5 = "\x1B[2m";
6801
+ const BOLD4 = "\x1B[1m";
6802
+ const RESET5 = "\x1B[0m";
6803
+ console.log(`
6804
+ ${DIM5}Update available: ${cached.current} -> ${cached.latest}. Run:${RESET5} ${BOLD4}keepgoing update${RESET5}`);
6805
+ }
6806
+ spawnBackgroundCheck();
6728
6807
  }
6729
6808
  main().catch((err) => {
6730
6809
  console.error(err instanceof Error ? err.message : String(err));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@keepgoingdev/cli",
3
- "version": "1.4.0",
3
+ "version": "1.5.0",
4
4
  "description": "Terminal CLI for KeepGoing. Resume side projects without the mental friction.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",