@stackmemoryai/stackmemory 0.8.0 → 0.8.1

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.
@@ -13,14 +13,6 @@ import { program } from "commander";
13
13
  import { v4 as uuidv4 } from "uuid";
14
14
  import chalk from "chalk";
15
15
  import { initializeTracing, trace } from "../core/trace/index.js";
16
- import {
17
- generateSessionSummary,
18
- formatSummaryMessage
19
- } from "../hooks/session-summary.js";
20
- import { sendNotification, loadSMSConfig } from "../hooks/sms-notify.js";
21
- import { enableAutoSync } from "../hooks/whatsapp-sync.js";
22
- import { enableCommands } from "../hooks/whatsapp-commands.js";
23
- import { startScheduler, listSchedules } from "../hooks/whatsapp-scheduler.js";
24
16
  import {
25
17
  getModelRouter,
26
18
  loadModelRouterConfig
@@ -48,12 +40,9 @@ const DEFAULT_SM_CONFIG = {
48
40
  defaultSandbox: false,
49
41
  defaultChrome: false,
50
42
  defaultTracing: true,
51
- defaultRemote: false,
52
43
  defaultNotifyOnDone: true,
53
- defaultWhatsApp: false,
54
44
  defaultModelRouting: false,
55
45
  defaultSweep: true,
56
- defaultGreptile: true,
57
46
  defaultGEPA: false
58
47
  };
59
48
  function getConfigPath() {
@@ -91,9 +80,7 @@ class ClaudeSM {
91
80
  useSandbox: this.smConfig.defaultSandbox,
92
81
  useChrome: this.smConfig.defaultChrome,
93
82
  useWorktree: this.smConfig.defaultWorktree,
94
- useRemote: this.smConfig.defaultRemote,
95
83
  notifyOnDone: this.smConfig.defaultNotifyOnDone,
96
- useWhatsApp: this.smConfig.defaultWhatsApp,
97
84
  contextEnabled: true,
98
85
  tracingEnabled: this.smConfig.defaultTracing,
99
86
  verboseTracing: false,
@@ -101,7 +88,6 @@ class ClaudeSM {
101
88
  useModelRouting: this.smConfig.defaultModelRouting,
102
89
  useThinkingMode: false,
103
90
  useSweep: this.smConfig.defaultSweep,
104
- useGreptile: this.smConfig.defaultGreptile,
105
91
  useGEPA: this.smConfig.defaultGEPA
106
92
  };
107
93
  this.stackmemoryPath = this.findStackMemory();
@@ -114,6 +100,33 @@ class ClaudeSM {
114
100
  fs.mkdirSync(this.claudeConfigDir, { recursive: true });
115
101
  }
116
102
  }
103
+ getRepoRoot() {
104
+ try {
105
+ const root = execSync("git rev-parse --show-toplevel", {
106
+ encoding: "utf8"
107
+ }).trim();
108
+ return root || null;
109
+ } catch {
110
+ return null;
111
+ }
112
+ }
113
+ ensureInitialized() {
114
+ try {
115
+ const root = this.getRepoRoot();
116
+ const dir = root || process.cwd();
117
+ const dbPath = path.join(dir, ".stackmemory", "context.db");
118
+ if (!fs.existsSync(dbPath)) {
119
+ console.log(
120
+ chalk.blue("\u{1F4E6} Initializing StackMemory for this project...")
121
+ );
122
+ execSync(`${this.stackmemoryPath} init`, {
123
+ cwd: dir,
124
+ stdio: ["ignore", "ignore", "ignore"]
125
+ });
126
+ }
127
+ } catch {
128
+ }
129
+ }
117
130
  generateInstanceId() {
118
131
  return uuidv4().substring(0, 8);
119
132
  }
@@ -239,52 +252,6 @@ class ClaudeSM {
239
252
  }
240
253
  this.gepaProcesses = [];
241
254
  }
242
- ensureGreptileMcp() {
243
- const apiKey = process.env["GREPTILE_API_KEY"];
244
- const ghToken = process.env["GITHUB_TOKEN"];
245
- if (!apiKey) {
246
- console.log(
247
- chalk.gray(" Greptile: disabled (set GREPTILE_API_KEY in .env)")
248
- );
249
- return;
250
- }
251
- try {
252
- const result = execSync("claude mcp list 2>/dev/null", {
253
- encoding: "utf-8"
254
- });
255
- if (result.includes("greptile")) {
256
- console.log(chalk.gray(" Greptile: MCP server registered"));
257
- return;
258
- }
259
- } catch {
260
- }
261
- try {
262
- const cmd = [
263
- "claude mcp add",
264
- "--transport http",
265
- "greptile",
266
- "https://api.greptile.com/mcp",
267
- `--header "Authorization: Bearer ${apiKey}"`
268
- ];
269
- if (ghToken) {
270
- cmd.push(`--header "X-GitHub-Token: ${ghToken}"`);
271
- }
272
- execSync(cmd.join(" "), { stdio: "ignore" });
273
- console.log(chalk.cyan(" Greptile: MCP server registered"));
274
- } catch {
275
- try {
276
- const envArgs = [`GREPTILE_API_KEY=${apiKey}`];
277
- if (ghToken) envArgs.push(`GITHUB_TOKEN=${ghToken}`);
278
- execSync(
279
- `claude mcp add greptile -- env ${envArgs.join(" ")} npx greptile-mcp-server`,
280
- { stdio: "ignore" }
281
- );
282
- console.log(chalk.cyan(" Greptile: MCP server registered (stdio)"));
283
- } catch {
284
- console.log(chalk.gray(" Greptile: failed to register MCP server"));
285
- }
286
- }
287
- }
288
255
  setupWorktree() {
289
256
  if (!this.config.useWorktree || !this.isGitRepo()) {
290
257
  return null;
@@ -347,19 +314,35 @@ class ClaudeSM {
347
314
  } catch {
348
315
  }
349
316
  }
317
+ getHandoffContent() {
318
+ if (!this.config.contextEnabled) return null;
319
+ try {
320
+ const handoffPath = path.join(
321
+ process.cwd(),
322
+ ".stackmemory",
323
+ "last-handoff.md"
324
+ );
325
+ if (fs.existsSync(handoffPath)) {
326
+ const content = fs.readFileSync(handoffPath, "utf8").trim();
327
+ if (content.length > 0) {
328
+ return content.length > 8e3 ? content.substring(0, 8e3) + "\n\n[...truncated]" : content;
329
+ }
330
+ }
331
+ } catch {
332
+ }
333
+ return null;
334
+ }
350
335
  loadContext() {
351
336
  if (!this.config.contextEnabled) return;
352
337
  try {
353
- console.log(chalk.blue("\u{1F4DA} Loading previous context..."));
354
338
  const cmd = `${this.stackmemoryPath} context show`;
355
339
  const output = execSync(cmd, {
356
340
  encoding: "utf8",
357
341
  stdio: ["pipe", "pipe", "pipe"]
358
- // Capture stderr to suppress errors
359
342
  });
360
343
  const lines = output.trim().split("\n").filter((l) => l.trim());
361
344
  if (lines.length > 3) {
362
- console.log(chalk.gray("Context stack loaded"));
345
+ console.log(chalk.gray(" Context stack loaded"));
363
346
  }
364
347
  } catch {
365
348
  }
@@ -394,166 +377,10 @@ class ClaudeSM {
394
377
  );
395
378
  }
396
379
  }
397
- async startWhatsAppServices() {
398
- const WEBHOOK_PORT = 3456;
399
- console.log(chalk.cyan("\n\u{1F4F1} WhatsApp Mode - Full Integration"));
400
- console.log(chalk.gray("\u2500".repeat(42)));
401
- const smsConfig = loadSMSConfig();
402
- if (!smsConfig.enabled) {
403
- console.log(
404
- chalk.yellow(" Notifications disabled. Run: stackmemory notify enable")
405
- );
406
- }
407
- try {
408
- enableAutoSync();
409
- console.log(
410
- chalk.green(" \u2713 Auto-sync enabled (digests on frame close)")
411
- );
412
- } catch {
413
- console.log(chalk.gray(" Auto-sync: skipped"));
414
- }
415
- try {
416
- enableCommands();
417
- console.log(chalk.green(" \u2713 Command processing enabled"));
418
- console.log(
419
- chalk.gray(" Reply: status, tasks, context, help, build, test, lint")
420
- );
421
- } catch {
422
- console.log(chalk.gray(" Command processing: skipped"));
423
- }
424
- try {
425
- const schedules = listSchedules();
426
- if (schedules.length > 0) {
427
- startScheduler();
428
- console.log(
429
- chalk.green(` \u2713 Scheduler started (${schedules.length} schedules)`)
430
- );
431
- }
432
- } catch {
433
- }
434
- const webhookRunning = await fetch(
435
- `http://localhost:${WEBHOOK_PORT}/health`
436
- ).then((r) => r.ok).catch(() => false);
437
- if (!webhookRunning) {
438
- const webhookPath = path.join(__dirname, "../hooks/sms-webhook.js");
439
- const webhookProcess = spawn("node", [webhookPath], {
440
- detached: true,
441
- stdio: "ignore",
442
- env: { ...process.env, SMS_WEBHOOK_PORT: String(WEBHOOK_PORT) }
443
- });
444
- webhookProcess.unref();
445
- console.log(
446
- chalk.green(` \u2713 Webhook server started (port ${WEBHOOK_PORT})`)
447
- );
448
- } else {
449
- console.log(
450
- chalk.green(` \u2713 Webhook already running (port ${WEBHOOK_PORT})`)
451
- );
452
- }
453
- const ngrokRunning = await fetch("http://localhost:4040/api/tunnels").then((r) => r.ok).catch(() => false);
454
- if (!ngrokRunning) {
455
- const ngrokProcess = spawn("ngrok", ["http", String(WEBHOOK_PORT)], {
456
- detached: true,
457
- stdio: "ignore"
458
- });
459
- ngrokProcess.unref();
460
- console.log(chalk.gray(" Starting ngrok tunnel..."));
461
- await new Promise((resolve) => setTimeout(resolve, 3e3));
462
- }
463
- try {
464
- const tunnels = await fetch("http://localhost:4040/api/tunnels").then(
465
- (r) => r.json()
466
- );
467
- const publicUrl = tunnels?.tunnels?.[0]?.public_url;
468
- if (publicUrl) {
469
- const configDir = path.join(os.homedir(), ".stackmemory");
470
- const configPath = path.join(configDir, "ngrok-url.txt");
471
- if (!fs.existsSync(configDir)) {
472
- fs.mkdirSync(configDir, { recursive: true });
473
- }
474
- fs.writeFileSync(configPath, publicUrl);
475
- console.log(chalk.green(` \u2713 ngrok tunnel: ${publicUrl}/sms/incoming`));
476
- }
477
- } catch {
478
- console.log(chalk.yellow(" ngrok: waiting for tunnel..."));
479
- }
480
- if (smsConfig.pendingPrompts.length > 0) {
481
- console.log();
482
- console.log(
483
- chalk.yellow(
484
- ` \u23F3 ${smsConfig.pendingPrompts.length} pending prompt(s) awaiting response:`
485
- )
486
- );
487
- smsConfig.pendingPrompts.slice(0, 3).forEach((p, i) => {
488
- const msg = p.message.length > 40 ? p.message.slice(0, 40) + "..." : p.message;
489
- console.log(chalk.gray(` ${i + 1}. [${p.id}] ${msg}`));
490
- });
491
- if (smsConfig.pendingPrompts.length > 3) {
492
- console.log(
493
- chalk.gray(` ... and ${smsConfig.pendingPrompts.length - 3} more`)
494
- );
495
- }
496
- }
497
- console.log();
498
- console.log(chalk.gray(" Quick actions from WhatsApp:"));
499
- console.log(chalk.gray(' "status" - session status'));
500
- console.log(chalk.gray(' "context" - current frame digest'));
501
- console.log(chalk.gray(' "1", "2" - respond to prompts'));
502
- console.log(chalk.gray("\u2500".repeat(42)));
503
- }
504
- async sendDoneNotification(exitCode) {
505
- try {
506
- const context = {
507
- instanceId: this.config.instanceId,
508
- exitCode,
509
- sessionStartTime: this.config.sessionStartTime,
510
- worktreePath: this.config.worktreePath,
511
- branch: this.config.branch,
512
- task: this.config.task
513
- };
514
- const summary = await generateSessionSummary(context);
515
- const message = formatSummaryMessage(summary, this.config.instanceId);
516
- console.log(chalk.cyan("\nSending session summary via WhatsApp..."));
517
- let options = summary.suggestions.slice(0, 4).map((s) => ({
518
- key: s.key,
519
- label: s.label,
520
- action: s.action
521
- }));
522
- if (options.length < 2) {
523
- const defaults = [
524
- { key: "1", label: "Start new session", action: "claude-sm" },
525
- {
526
- key: "2",
527
- label: "View logs",
528
- action: "tail -30 ~/.claude/logs/*.log"
529
- }
530
- ];
531
- options = defaults.slice(0, 2 - options.length).concat(options);
532
- options.forEach((o, i) => o.key = String(i + 1));
533
- }
534
- const result = await sendNotification({
535
- type: "task_complete",
536
- title: `Claude Session ${this.config.instanceId}`,
537
- message,
538
- prompt: {
539
- type: "options",
540
- options
541
- }
542
- });
543
- if (result.success) {
544
- console.log(chalk.green("Notification sent successfully"));
545
- } else {
546
- console.log(
547
- chalk.yellow(`Notification not sent: ${result.error || "unknown"}`)
548
- );
549
- }
550
- } catch (error) {
551
- console.log(
552
- chalk.yellow(
553
- `Could not send notification: ${error instanceof Error ? error.message : "unknown"}`
554
- )
555
- );
556
- }
380
+ notifyDone(exitCode) {
381
+ process.stdout.write("\x07");
382
+ console.log(chalk.gray(`
383
+ Session ended (exit ${exitCode ?? 0})`));
557
384
  }
558
385
  async run(args) {
559
386
  const claudeArgs = [];
@@ -569,13 +396,6 @@ class ClaudeSM {
569
396
  case "-W":
570
397
  this.config.useWorktree = false;
571
398
  break;
572
- case "--remote":
573
- case "-r":
574
- this.config.useRemote = true;
575
- break;
576
- case "--no-remote":
577
- this.config.useRemote = false;
578
- break;
579
399
  case "--notify-done":
580
400
  case "-n":
581
401
  this.config.notifyOnDone = true;
@@ -583,13 +403,6 @@ class ClaudeSM {
583
403
  case "--no-notify-done":
584
404
  this.config.notifyOnDone = false;
585
405
  break;
586
- case "--whatsapp":
587
- this.config.useWhatsApp = true;
588
- this.config.notifyOnDone = true;
589
- break;
590
- case "--no-whatsapp":
591
- this.config.useWhatsApp = false;
592
- break;
593
406
  case "--sandbox":
594
407
  case "-s":
595
408
  this.config.useSandbox = true;
@@ -661,12 +474,6 @@ class ClaudeSM {
661
474
  case "--no-sweep":
662
475
  this.config.useSweep = false;
663
476
  break;
664
- case "--greptile":
665
- this.config.useGreptile = true;
666
- break;
667
- case "--no-greptile":
668
- this.config.useGreptile = false;
669
- break;
670
477
  case "--gepa":
671
478
  this.config.useGEPA = true;
672
479
  break;
@@ -726,6 +533,7 @@ class ClaudeSM {
726
533
  console.log(chalk.blue("\u2551 Claude + StackMemory + Worktree \u2551"));
727
534
  console.log(chalk.blue("\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u255D"));
728
535
  console.log();
536
+ this.ensureInitialized();
729
537
  if (this.isGitRepo()) {
730
538
  const branch = this.getCurrentBranch();
731
539
  console.log(chalk.gray(`\u{1F4CD} Current branch: ${branch}`));
@@ -750,19 +558,11 @@ class ClaudeSM {
750
558
  if (this.config.worktreePath) {
751
559
  process.env["CLAUDE_WORKTREE_PATH"] = this.config.worktreePath;
752
560
  }
753
- if (this.config.useRemote) {
754
- process.env["CLAUDE_REMOTE"] = "1";
755
- }
756
561
  console.log(chalk.gray(`\u{1F916} Instance ID: ${this.config.instanceId}`));
757
562
  console.log(chalk.gray(`\u{1F4C1} Working in: ${process.cwd()}`));
758
563
  if (this.config.useSandbox) {
759
564
  console.log(chalk.yellow("\u{1F512} Sandbox mode enabled"));
760
565
  }
761
- if (this.config.useRemote) {
762
- console.log(
763
- chalk.cyan("\u{1F4F1} Remote mode: WhatsApp notifications for all questions")
764
- );
765
- }
766
566
  if (this.config.useChrome) {
767
567
  console.log(chalk.yellow("\u{1F310} Chrome automation enabled"));
768
568
  }
@@ -815,17 +615,17 @@ class ClaudeSM {
815
615
  );
816
616
  }
817
617
  }
818
- if (this.config.useGreptile) {
819
- this.ensureGreptileMcp();
820
- }
821
618
  if (this.config.useGEPA) {
822
619
  this.startGEPAWatcher();
823
620
  }
824
- if (this.config.useWhatsApp) {
825
- console.log(
826
- chalk.cyan("\u{1F4F1} WhatsApp mode: notifications + webhook enabled")
827
- );
828
- await this.startWhatsAppServices();
621
+ let initialInput = "";
622
+ const handoffContent = this.getHandoffContent();
623
+ if (handoffContent) {
624
+ const hasResume = claudeArgs.includes("--continue") || claudeArgs.some((a) => a === "--resume");
625
+ if (!hasResume) {
626
+ initialInput = handoffContent;
627
+ console.log(chalk.gray(" Handoff context ready"));
628
+ }
829
629
  }
830
630
  console.log();
831
631
  if (this.config.useSweep) {
@@ -842,7 +642,8 @@ class ClaudeSM {
842
642
  try {
843
643
  await launchWrapper({
844
644
  claudeBin: claudeBin2,
845
- claudeArgs
645
+ claudeArgs,
646
+ initialInput: initialInput || void 0
846
647
  });
847
648
  return;
848
649
  } catch (error) {
@@ -856,6 +657,9 @@ class ClaudeSM {
856
657
  this.config.useSweep = false;
857
658
  }
858
659
  }
660
+ if (initialInput) {
661
+ claudeArgs.push("--append-system-prompt", initialInput);
662
+ }
859
663
  console.log(chalk.gray("Starting Claude..."));
860
664
  console.log(chalk.gray("\u2500".repeat(42)));
861
665
  const claudeBin = this.resolveClaudeBin();
@@ -878,14 +682,6 @@ class ClaudeSM {
878
682
  [auto-fallback] Switching to ${provider}`));
879
683
  console.log(chalk.gray(` Reason: ${reason}`));
880
684
  console.log(chalk.gray(` Session will continue on ${provider}...`));
881
- if (this.config.notifyOnDone || this.config.useWhatsApp) {
882
- sendNotification({
883
- type: "custom",
884
- title: "Model Fallback",
885
- message: `Claude unavailable (${reason}). Switched to ${provider}.`
886
- }).catch(() => {
887
- });
888
- }
889
685
  }
890
686
  });
891
687
  const fallbackAvailable = fallbackMonitor.isFallbackAvailable();
@@ -938,8 +734,8 @@ Session completed on fallback provider: ${status.currentProvider}`
938
734
  console.log(chalk.blue("Debug Trace Summary:"));
939
735
  console.log(chalk.gray(summary));
940
736
  }
941
- if (this.config.notifyOnDone || this.config.useRemote) {
942
- await this.sendDoneNotification(code);
737
+ if (this.config.notifyOnDone) {
738
+ this.notifyDone(code);
943
739
  }
944
740
  if (this.config.worktreePath) {
945
741
  console.log();
@@ -976,11 +772,9 @@ configCmd.command("show").description("Show current default settings").action(()
976
772
  console.log(chalk.cyan("\n Feature Status"));
977
773
  console.log(chalk.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
978
774
  console.log(` Predictive Edit ${config.defaultSweep ? on : off}`);
979
- console.log(` Code Review ${config.defaultGreptile ? on : off}`);
980
775
  console.log(` Prompt Forge ${config.defaultGEPA ? on : off}`);
981
776
  console.log(` Model Switcher ${config.defaultModelRouting ? on : off}`);
982
777
  console.log(` Safe Branch ${config.defaultWorktree ? on : off}`);
983
- console.log(` Mobile Sync ${config.defaultWhatsApp ? on : off}`);
984
778
  console.log(` Session Insights ${config.defaultTracing ? on : off}`);
985
779
  console.log(` Task Alert ${config.defaultNotifyOnDone ? on : off}`);
986
780
  console.log(chalk.gray(" \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500"));
@@ -998,14 +792,11 @@ configCmd.command("set <key> <value>").description("Set a default (e.g., set wor
998
792
  sandbox: "defaultSandbox",
999
793
  chrome: "defaultChrome",
1000
794
  tracing: "defaultTracing",
1001
- remote: "defaultRemote",
1002
795
  "notify-done": "defaultNotifyOnDone",
1003
796
  notifyondone: "defaultNotifyOnDone",
1004
- whatsapp: "defaultWhatsApp",
1005
797
  "model-routing": "defaultModelRouting",
1006
798
  modelrouting: "defaultModelRouting",
1007
799
  sweep: "defaultSweep",
1008
- greptile: "defaultGreptile",
1009
800
  gepa: "defaultGEPA"
1010
801
  };
1011
802
  const configKey = keyMap[key];
@@ -1013,7 +804,7 @@ configCmd.command("set <key> <value>").description("Set a default (e.g., set wor
1013
804
  console.log(chalk.red(`Unknown key: ${key}`));
1014
805
  console.log(
1015
806
  chalk.gray(
1016
- "Valid keys: worktree, sandbox, chrome, tracing, remote, notify-done, whatsapp, sweep, greptile, gepa"
807
+ "Valid keys: worktree, sandbox, chrome, tracing, notify-done, model-routing, sweep, gepa"
1017
808
  )
1018
809
  );
1019
810
  process.exit(1);
@@ -1034,19 +825,7 @@ configCmd.command("worktree-off").description("Disable worktree mode by default"
1034
825
  saveSMConfig(config);
1035
826
  console.log(chalk.green("Worktree mode disabled by default"));
1036
827
  });
1037
- configCmd.command("remote-on").description("Enable remote mode by default (WhatsApp for all questions)").action(() => {
1038
- const config = loadSMConfig();
1039
- config.defaultRemote = true;
1040
- saveSMConfig(config);
1041
- console.log(chalk.green("Remote mode enabled by default"));
1042
- });
1043
- configCmd.command("remote-off").description("Disable remote mode by default").action(() => {
1044
- const config = loadSMConfig();
1045
- config.defaultRemote = false;
1046
- saveSMConfig(config);
1047
- console.log(chalk.green("Remote mode disabled by default"));
1048
- });
1049
- configCmd.command("notify-done-on").description("Enable WhatsApp notification when session ends (default)").action(() => {
828
+ configCmd.command("notify-done-on").description("Enable bell notification when session ends (default)").action(() => {
1050
829
  const config = loadSMConfig();
1051
830
  config.defaultNotifyOnDone = true;
1052
831
  saveSMConfig(config);
@@ -1058,20 +837,6 @@ configCmd.command("notify-done-off").description("Disable notification when sess
1058
837
  saveSMConfig(config);
1059
838
  console.log(chalk.green("Notify-on-done disabled by default"));
1060
839
  });
1061
- configCmd.command("whatsapp-on").description("Enable WhatsApp mode by default (auto-starts webhook + ngrok)").action(() => {
1062
- const config = loadSMConfig();
1063
- config.defaultWhatsApp = true;
1064
- config.defaultNotifyOnDone = true;
1065
- saveSMConfig(config);
1066
- console.log(chalk.green("WhatsApp mode enabled by default"));
1067
- console.log(chalk.gray("Sessions will auto-start webhook and ngrok"));
1068
- });
1069
- configCmd.command("whatsapp-off").description("Disable WhatsApp mode by default").action(() => {
1070
- const config = loadSMConfig();
1071
- config.defaultWhatsApp = false;
1072
- saveSMConfig(config);
1073
- console.log(chalk.green("WhatsApp mode disabled by default"));
1074
- });
1075
840
  configCmd.command("model-routing-on").description(
1076
841
  "Enable model routing by default (route tasks to Qwen/other models)"
1077
842
  ).action(() => {
@@ -1087,23 +852,6 @@ configCmd.command("model-routing-off").description("Disable model routing by def
1087
852
  saveSMConfig(config);
1088
853
  console.log(chalk.green("Model routing disabled by default"));
1089
854
  });
1090
- configCmd.command("greptile-on").description(
1091
- "Enable Greptile AI code review by default (requires GREPTILE_API_KEY)"
1092
- ).action(() => {
1093
- const config = loadSMConfig();
1094
- config.defaultGreptile = true;
1095
- saveSMConfig(config);
1096
- console.log(chalk.green("Greptile enabled by default"));
1097
- if (!process.env["GREPTILE_API_KEY"]) {
1098
- console.log(chalk.gray("Set GREPTILE_API_KEY in .env to activate"));
1099
- }
1100
- });
1101
- configCmd.command("greptile-off").description("Disable Greptile AI code review by default").action(() => {
1102
- const config = loadSMConfig();
1103
- config.defaultGreptile = false;
1104
- saveSMConfig(config);
1105
- console.log(chalk.green("Greptile disabled by default"));
1106
- });
1107
855
  configCmd.command("gepa-on").description("Enable GEPA auto-optimization of CLAUDE.md on changes").action(() => {
1108
856
  const config = loadSMConfig();
1109
857
  config.defaultGEPA = true;
@@ -1130,11 +878,6 @@ configCmd.command("setup").description("Interactive feature setup wizard").actio
1130
878
  name: "Predictive Edit",
1131
879
  desc: "AI-powered next-edit suggestions in real-time"
1132
880
  },
1133
- {
1134
- key: "defaultGreptile",
1135
- name: "Code Review",
1136
- desc: "Automated code review with deep codebase intelligence"
1137
- },
1138
881
  {
1139
882
  key: "defaultGEPA",
1140
883
  name: "Prompt Forge",
@@ -1150,11 +893,6 @@ configCmd.command("setup").description("Interactive feature setup wizard").actio
1150
893
  name: "Safe Branch",
1151
894
  desc: "Isolated git worktrees for conflict-free parallel work"
1152
895
  },
1153
- {
1154
- key: "defaultWhatsApp",
1155
- name: "Mobile Sync",
1156
- desc: "Remote control and notifications via WhatsApp"
1157
- },
1158
896
  {
1159
897
  key: "defaultTracing",
1160
898
  name: "Session Insights",
@@ -1205,44 +943,6 @@ configCmd.command("setup").description("Interactive feature setup wizard").actio
1205
943
  }
1206
944
  }
1207
945
  }
1208
- if (config.defaultGreptile) {
1209
- const apiKey = process.env["GREPTILE_API_KEY"];
1210
- if (!apiKey) {
1211
- const { key } = await inquirer.default.prompt([
1212
- {
1213
- type: "password",
1214
- name: "key",
1215
- message: "Enter your Greptile API key (from app.greptile.com):",
1216
- mask: "*"
1217
- }
1218
- ]);
1219
- if (key && key.trim()) {
1220
- const envPath = path.join(process.cwd(), ".env");
1221
- const line = `
1222
- GREPTILE_API_KEY=${key.trim()}
1223
- `;
1224
- fs.appendFileSync(envPath, line);
1225
- process.env["GREPTILE_API_KEY"] = key.trim();
1226
- console.log(chalk.green(" API key saved to .env"));
1227
- }
1228
- }
1229
- const currentKey = process.env["GREPTILE_API_KEY"];
1230
- if (currentKey) {
1231
- try {
1232
- const result = execSync("claude mcp list 2>/dev/null", {
1233
- encoding: "utf-8"
1234
- });
1235
- if (!result.includes("greptile")) {
1236
- execSync(
1237
- `claude mcp add --transport http greptile https://api.greptile.com/mcp --header "Authorization: Bearer ${currentKey}"`,
1238
- { stdio: "ignore" }
1239
- );
1240
- console.log(chalk.green(" Greptile MCP server registered"));
1241
- }
1242
- } catch {
1243
- }
1244
- }
1245
- }
1246
946
  console.log(chalk.cyan("\nFeature summary:"));
1247
947
  for (const f of features) {
1248
948
  const on = config[f.key];
@@ -1361,10 +1061,7 @@ workersCmd.command("kill [id]").description("Kill entire session or send Ctrl-C
1361
1061
  console.log(chalk.gray("Registry cleared."));
1362
1062
  }
1363
1063
  });
1364
- program.option("-w, --worktree", "Create isolated worktree for this instance").option("-W, --no-worktree", "Disable worktree (override default)").option("-r, --remote", "Enable remote mode (WhatsApp for all questions)").option("--no-remote", "Disable remote mode (override default)").option("-n, --notify-done", "Send WhatsApp notification when session ends").option("--no-notify-done", "Disable notification when session ends").option(
1365
- "--whatsapp",
1366
- "Enable WhatsApp mode (auto-start webhook + ngrok + notifications)"
1367
- ).option("--no-whatsapp", "Disable WhatsApp mode (override default)").option("-s, --sandbox", "Enable sandbox mode (file/network restrictions)").option("-c, --chrome", "Enable Chrome automation").option("-a, --auto", "Automatically detect and apply best settings").option("-b, --branch <name>", "Specify branch name for worktree").option("-t, --task <desc>", "Task description for context").option("--claude-bin <path>", "Path to claude CLI (or use CLAUDE_BIN)").option("--no-context", "Disable StackMemory context integration").option("--no-trace", "Disable debug tracing (enabled by default)").option("--verbose-trace", "Enable verbose debug tracing with full details").option("--think", "Enable thinking mode with Qwen (deep reasoning)").option("--think-hard", "Alias for --think").option("--ultrathink", "Alias for --think").option("--qwen", "Force Qwen provider for this session").option("--openai", "Force OpenAI provider for this session").option("--ollama", "Force Ollama provider for this session").option("--model-routing", "Enable model routing").option("--no-model-routing", "Disable model routing").option("--sweep", "Enable Sweep next-edit predictions (PTY wrapper)").option("--no-sweep", "Disable Sweep predictions").option("--greptile", "Enable Greptile AI code review (MCP server)").option("--no-greptile", "Disable Greptile integration").option("--gepa", "Enable GEPA auto-optimization of CLAUDE.md").option("--no-gepa", "Disable GEPA auto-optimization").helpOption("-h, --help", "Display help").allowUnknownOption(true).action(async (_options) => {
1064
+ program.option("-w, --worktree", "Create isolated worktree for this instance").option("-W, --no-worktree", "Disable worktree (override default)").option("-n, --notify-done", "Bell notification when session ends").option("--no-notify-done", "Disable notification when session ends").option("-s, --sandbox", "Enable sandbox mode (file/network restrictions)").option("-c, --chrome", "Enable Chrome automation").option("-a, --auto", "Automatically detect and apply best settings").option("-b, --branch <name>", "Specify branch name for worktree").option("-t, --task <desc>", "Task description for context").option("--claude-bin <path>", "Path to claude CLI (or use CLAUDE_BIN)").option("--no-context", "Disable StackMemory context integration").option("--no-trace", "Disable debug tracing (enabled by default)").option("--verbose-trace", "Enable verbose debug tracing with full details").option("--think", "Enable thinking mode with Qwen (deep reasoning)").option("--think-hard", "Alias for --think").option("--ultrathink", "Alias for --think").option("--qwen", "Force Qwen provider for this session").option("--openai", "Force OpenAI provider for this session").option("--ollama", "Force Ollama provider for this session").option("--model-routing", "Enable model routing").option("--no-model-routing", "Disable model routing").option("--sweep", "Enable Sweep next-edit predictions (PTY wrapper)").option("--no-sweep", "Disable Sweep predictions").option("--gepa", "Enable GEPA auto-optimization of CLAUDE.md").option("--no-gepa", "Disable GEPA auto-optimization").helpOption("-h, --help", "Display help").allowUnknownOption(true).action(async (_options) => {
1368
1065
  const claudeSM = new ClaudeSM();
1369
1066
  const args = process.argv.slice(2);
1370
1067
  await claudeSM.run(args);