@stackmemoryai/stackmemory 0.5.30 → 0.5.33
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/README.md +44 -44
- package/dist/cli/claude-sm.js +199 -16
- package/dist/cli/claude-sm.js.map +2 -2
- package/dist/cli/commands/context.js +0 -11
- package/dist/cli/commands/context.js.map +2 -2
- package/dist/cli/commands/linear.js +1 -14
- package/dist/cli/commands/linear.js.map +2 -2
- package/dist/cli/commands/login.js +32 -10
- package/dist/cli/commands/login.js.map +2 -2
- package/dist/cli/commands/migrate.js +80 -22
- package/dist/cli/commands/migrate.js.map +2 -2
- package/dist/cli/commands/model.js +533 -0
- package/dist/cli/commands/model.js.map +7 -0
- package/dist/cli/commands/ralph.js +93 -28
- package/dist/cli/commands/ralph.js.map +2 -2
- package/dist/cli/commands/service.js +10 -3
- package/dist/cli/commands/service.js.map +2 -2
- package/dist/cli/commands/skills.js +60 -10
- package/dist/cli/commands/skills.js.map +2 -2
- package/dist/cli/commands/sms-notify.js +342 -22
- package/dist/cli/commands/sms-notify.js.map +3 -3
- package/dist/cli/index.js +2 -0
- package/dist/cli/index.js.map +2 -2
- package/dist/core/context/dual-stack-manager.js +23 -7
- package/dist/core/context/dual-stack-manager.js.map +2 -2
- package/dist/core/context/frame-database.js +33 -5
- package/dist/core/context/frame-database.js.map +2 -2
- package/dist/core/context/frame-digest.js +6 -1
- package/dist/core/context/frame-digest.js.map +2 -2
- package/dist/core/context/frame-manager.js +56 -9
- package/dist/core/context/frame-manager.js.map +2 -2
- package/dist/core/context/permission-manager.js +0 -11
- package/dist/core/context/permission-manager.js.map +2 -2
- package/dist/core/context/recursive-context-manager.js +15 -9
- package/dist/core/context/recursive-context-manager.js.map +2 -2
- package/dist/core/context/shared-context-layer.js +0 -11
- package/dist/core/context/shared-context-layer.js.map +2 -2
- package/dist/core/context/validation.js +6 -1
- package/dist/core/context/validation.js.map +2 -2
- package/dist/core/models/fallback-monitor.js +229 -0
- package/dist/core/models/fallback-monitor.js.map +7 -0
- package/dist/core/models/model-router.js +331 -0
- package/dist/core/models/model-router.js.map +7 -0
- package/dist/hooks/claude-code-whatsapp-hook.js +197 -0
- package/dist/hooks/claude-code-whatsapp-hook.js.map +7 -0
- package/dist/hooks/linear-task-picker.js +1 -1
- package/dist/hooks/linear-task-picker.js.map +2 -2
- package/dist/hooks/schemas.js +55 -1
- package/dist/hooks/schemas.js.map +2 -2
- package/dist/hooks/session-summary.js +5 -1
- package/dist/hooks/session-summary.js.map +2 -2
- package/dist/hooks/sms-action-runner.js +12 -1
- package/dist/hooks/sms-action-runner.js.map +2 -2
- package/dist/hooks/sms-notify.js +4 -2
- package/dist/hooks/sms-notify.js.map +2 -2
- package/dist/hooks/sms-webhook.js +23 -2
- package/dist/hooks/sms-webhook.js.map +2 -2
- package/dist/hooks/whatsapp-commands.js +376 -0
- package/dist/hooks/whatsapp-commands.js.map +7 -0
- package/dist/hooks/whatsapp-scheduler.js +317 -0
- package/dist/hooks/whatsapp-scheduler.js.map +7 -0
- package/dist/hooks/whatsapp-sync.js +375 -0
- package/dist/hooks/whatsapp-sync.js.map +7 -0
- package/package.json +2 -3
package/README.md
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
# StackMemory
|
|
2
2
|
|
|
3
|
-
**Lossless, project-scoped memory for AI tools** • v0.5.
|
|
3
|
+
**Lossless, project-scoped memory for AI tools** • v0.5.30
|
|
4
4
|
|
|
5
5
|
StackMemory is a **production-ready memory runtime** for AI coding tools that preserves full project context across sessions. With **Phases 1-4 complete**, it delivers:
|
|
6
6
|
|
|
7
|
-
-
|
|
8
|
-
-
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
-
|
|
14
|
-
-
|
|
15
|
-
-
|
|
16
|
-
-
|
|
7
|
+
- **89-98% faster** task operations than manual tracking
|
|
8
|
+
- **10,000+ frame depth** support with hierarchical organization
|
|
9
|
+
- **Full Linear integration** with bidirectional sync
|
|
10
|
+
- **20+ MCP tools** for Claude Code
|
|
11
|
+
- **Context persistence** that survives /clear operations
|
|
12
|
+
- **Two-tier storage system** with local tiers and infinite remote storage
|
|
13
|
+
- **Smart compression** (LZ4/ZSTD) with 2.5-3.5x ratios
|
|
14
|
+
- **Background migration** with configurable triggers
|
|
15
|
+
- **396 tests passing** with standardized error handling
|
|
16
|
+
- **npm v0.5.30** published with WhatsApp notifications and improved integrations
|
|
17
17
|
|
|
18
18
|
Instead of a linear chat log, StackMemory organizes memory as a **call stack** of scoped work (frames), with intelligent LLM-driven retrieval and team collaboration features.
|
|
19
19
|
|
|
@@ -96,16 +96,16 @@ The editor never manages memory directly; it asks StackMemory for the **context
|
|
|
96
96
|
|
|
97
97
|
## Product Health Metrics
|
|
98
98
|
|
|
99
|
-
### Current Status (v0.5.
|
|
99
|
+
### Current Status (v0.5.30)
|
|
100
100
|
|
|
101
101
|
| Metric | Current | Target | Status |
|
|
102
102
|
|--------|---------|--------|--------|
|
|
103
|
-
| **Test Coverage** | 85% | 90% |
|
|
104
|
-
| **Performance (p50)** | TBD | <50ms |
|
|
105
|
-
| **Documentation** | 70% | 100% |
|
|
106
|
-
| **Active Issues** | 5 high | 0 high |
|
|
107
|
-
| **Code Quality** | 396 tests | 400+ |
|
|
108
|
-
| **npm Downloads** | Growing | 1K+/week |
|
|
103
|
+
| **Test Coverage** | 85% | 90% | In Progress |
|
|
104
|
+
| **Performance (p50)** | TBD | <50ms | Pending |
|
|
105
|
+
| **Documentation** | 70% | 100% | In Progress |
|
|
106
|
+
| **Active Issues** | 5 high | 0 high | In Progress |
|
|
107
|
+
| **Code Quality** | 396 tests | 400+ | Done |
|
|
108
|
+
| **npm Downloads** | Growing | 1K+/week | On Track |
|
|
109
109
|
|
|
110
110
|
### Quality Score: 78/100
|
|
111
111
|
|
|
@@ -136,7 +136,7 @@ This creates a **project-scoped memory space** tied to the repo.
|
|
|
136
136
|
### Step 2: Install StackMemory
|
|
137
137
|
|
|
138
138
|
```bash
|
|
139
|
-
npm install -g @stackmemoryai/stackmemory@0.5.
|
|
139
|
+
npm install -g @stackmemoryai/stackmemory@0.5.30
|
|
140
140
|
# or latest
|
|
141
141
|
npm install -g @stackmemoryai/stackmemory@latest
|
|
142
142
|
```
|
|
@@ -455,7 +455,7 @@ stackmemory mcp-server [--port 3001]
|
|
|
455
455
|
- Hosted: **Private beta**
|
|
456
456
|
- OSS mirror: **Production ready**
|
|
457
457
|
- MCP integration: **Stable**
|
|
458
|
-
- CLI: **v0.5.
|
|
458
|
+
- CLI: **v0.5.30** - Full task, context, Linear, and storage management
|
|
459
459
|
- Two-tier storage: **Complete**
|
|
460
460
|
- Test Suite: **396 tests passing**
|
|
461
461
|
|
|
@@ -463,40 +463,40 @@ stackmemory mcp-server [--port 3001]
|
|
|
463
463
|
|
|
464
464
|
## Changelog
|
|
465
465
|
|
|
466
|
-
### v0.5.
|
|
467
|
-
-
|
|
468
|
-
-
|
|
469
|
-
-
|
|
470
|
-
-
|
|
471
|
-
-
|
|
466
|
+
### v0.5.30 (2026-01-26)
|
|
467
|
+
- Standardized error handling with `IntegrationError`, `DatabaseError`, `ValidationError`
|
|
468
|
+
- Adopted error classes across Linear integration (12 files)
|
|
469
|
+
- Adopted error classes across database layer (6 files)
|
|
470
|
+
- WhatsApp notifications with session ID and interactive options
|
|
471
|
+
- 396 tests passing with improved code quality
|
|
472
472
|
|
|
473
473
|
### v0.5.28 (2026-01-25)
|
|
474
|
-
-
|
|
475
|
-
-
|
|
476
|
-
-
|
|
474
|
+
- WhatsApp flag for claude-sm automatic notifications
|
|
475
|
+
- Incoming request queue for WhatsApp triggers
|
|
476
|
+
- SMS webhook /send endpoint for outgoing notifications
|
|
477
477
|
|
|
478
478
|
### v0.5.26 (2026-01-24)
|
|
479
|
-
-
|
|
480
|
-
-
|
|
481
|
-
-
|
|
482
|
-
-
|
|
479
|
+
- OpenCode wrapper (opencode-sm) with context integration
|
|
480
|
+
- Discovery CLI and MCP tools
|
|
481
|
+
- Real LLM provider and retrieval audit system
|
|
482
|
+
- Linear issue management and task picker
|
|
483
483
|
|
|
484
484
|
### v0.5.21 (2026-01-23)
|
|
485
|
-
-
|
|
486
|
-
-
|
|
487
|
-
-
|
|
485
|
+
- Claude-sm remote mode and configurable defaults
|
|
486
|
+
- Context loading command improvements
|
|
487
|
+
- Session summary features
|
|
488
488
|
|
|
489
489
|
### v0.3.16 (2026-01-15)
|
|
490
|
-
-
|
|
491
|
-
-
|
|
492
|
-
-
|
|
493
|
-
-
|
|
490
|
+
- Fixed critical error handling - getFrame() returns undefined instead of throwing
|
|
491
|
+
- Improved test coverage and fixed StackMemoryError constructor usage
|
|
492
|
+
- Removed dangerous secret-cleaning scripts from repository
|
|
493
|
+
- All tests passing, lint clean, build successful
|
|
494
494
|
|
|
495
495
|
### v0.3.15 (2026-01-14)
|
|
496
|
-
-
|
|
497
|
-
-
|
|
498
|
-
-
|
|
499
|
-
-
|
|
496
|
+
- Two-tier storage system implementation complete
|
|
497
|
+
- Smart compression with LZ4/ZSTD support
|
|
498
|
+
- Background migration with configurable triggers
|
|
499
|
+
- Improved Linear integration with bidirectional sync
|
|
500
500
|
|
|
501
501
|
---
|
|
502
502
|
|
package/dist/cli/claude-sm.js
CHANGED
|
@@ -17,7 +17,15 @@ import {
|
|
|
17
17
|
generateSessionSummary,
|
|
18
18
|
formatSummaryMessage
|
|
19
19
|
} from "../hooks/session-summary.js";
|
|
20
|
-
import { sendNotification } from "../hooks/sms-notify.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
|
+
import {
|
|
25
|
+
getModelRouter,
|
|
26
|
+
loadModelRouterConfig
|
|
27
|
+
} from "../core/models/model-router.js";
|
|
28
|
+
import { FallbackMonitor } from "../core/models/fallback-monitor.js";
|
|
21
29
|
const DEFAULT_SM_CONFIG = {
|
|
22
30
|
defaultWorktree: false,
|
|
23
31
|
defaultSandbox: false,
|
|
@@ -25,7 +33,8 @@ const DEFAULT_SM_CONFIG = {
|
|
|
25
33
|
defaultTracing: true,
|
|
26
34
|
defaultRemote: false,
|
|
27
35
|
defaultNotifyOnDone: true,
|
|
28
|
-
defaultWhatsApp: false
|
|
36
|
+
defaultWhatsApp: false,
|
|
37
|
+
defaultModelRouting: false
|
|
29
38
|
};
|
|
30
39
|
function getConfigPath() {
|
|
31
40
|
return path.join(os.homedir(), ".stackmemory", "claude-sm.json");
|
|
@@ -68,7 +77,9 @@ class ClaudeSM {
|
|
|
68
77
|
contextEnabled: true,
|
|
69
78
|
tracingEnabled: this.smConfig.defaultTracing,
|
|
70
79
|
verboseTracing: false,
|
|
71
|
-
sessionStartTime: Date.now()
|
|
80
|
+
sessionStartTime: Date.now(),
|
|
81
|
+
useModelRouting: this.smConfig.defaultModelRouting,
|
|
82
|
+
useThinkingMode: false
|
|
72
83
|
};
|
|
73
84
|
this.stackmemoryPath = this.findStackMemory();
|
|
74
85
|
this.worktreeScriptPath = path.join(
|
|
@@ -249,7 +260,41 @@ class ClaudeSM {
|
|
|
249
260
|
}
|
|
250
261
|
async startWhatsAppServices() {
|
|
251
262
|
const WEBHOOK_PORT = 3456;
|
|
252
|
-
console.log(chalk.cyan("
|
|
263
|
+
console.log(chalk.cyan("\n\u{1F4F1} WhatsApp Mode - Full Integration"));
|
|
264
|
+
console.log(chalk.gray("\u2500".repeat(42)));
|
|
265
|
+
const smsConfig = loadSMSConfig();
|
|
266
|
+
if (!smsConfig.enabled) {
|
|
267
|
+
console.log(
|
|
268
|
+
chalk.yellow(" Notifications disabled. Run: stackmemory notify enable")
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
try {
|
|
272
|
+
enableAutoSync();
|
|
273
|
+
console.log(
|
|
274
|
+
chalk.green(" \u2713 Auto-sync enabled (digests on frame close)")
|
|
275
|
+
);
|
|
276
|
+
} catch {
|
|
277
|
+
console.log(chalk.gray(" Auto-sync: skipped"));
|
|
278
|
+
}
|
|
279
|
+
try {
|
|
280
|
+
enableCommands();
|
|
281
|
+
console.log(chalk.green(" \u2713 Command processing enabled"));
|
|
282
|
+
console.log(
|
|
283
|
+
chalk.gray(" Reply: status, tasks, context, help, build, test, lint")
|
|
284
|
+
);
|
|
285
|
+
} catch {
|
|
286
|
+
console.log(chalk.gray(" Command processing: skipped"));
|
|
287
|
+
}
|
|
288
|
+
try {
|
|
289
|
+
const schedules = listSchedules();
|
|
290
|
+
if (schedules.length > 0) {
|
|
291
|
+
startScheduler();
|
|
292
|
+
console.log(
|
|
293
|
+
chalk.green(` \u2713 Scheduler started (${schedules.length} schedules)`)
|
|
294
|
+
);
|
|
295
|
+
}
|
|
296
|
+
} catch {
|
|
297
|
+
}
|
|
253
298
|
const webhookRunning = await fetch(
|
|
254
299
|
`http://localhost:${WEBHOOK_PORT}/health`
|
|
255
300
|
).then((r) => r.ok).catch(() => false);
|
|
@@ -262,11 +307,11 @@ class ClaudeSM {
|
|
|
262
307
|
});
|
|
263
308
|
webhookProcess.unref();
|
|
264
309
|
console.log(
|
|
265
|
-
chalk.
|
|
310
|
+
chalk.green(` \u2713 Webhook server started (port ${WEBHOOK_PORT})`)
|
|
266
311
|
);
|
|
267
312
|
} else {
|
|
268
313
|
console.log(
|
|
269
|
-
chalk.
|
|
314
|
+
chalk.green(` \u2713 Webhook already running (port ${WEBHOOK_PORT})`)
|
|
270
315
|
);
|
|
271
316
|
}
|
|
272
317
|
const ngrokRunning = await fetch("http://localhost:4040/api/tunnels").then((r) => r.ok).catch(() => false);
|
|
@@ -276,7 +321,7 @@ class ClaudeSM {
|
|
|
276
321
|
stdio: "ignore"
|
|
277
322
|
});
|
|
278
323
|
ngrokProcess.unref();
|
|
279
|
-
console.log(chalk.gray(" ngrok tunnel
|
|
324
|
+
console.log(chalk.gray(" Starting ngrok tunnel..."));
|
|
280
325
|
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
281
326
|
}
|
|
282
327
|
try {
|
|
@@ -291,15 +336,34 @@ class ClaudeSM {
|
|
|
291
336
|
fs.mkdirSync(configDir, { recursive: true });
|
|
292
337
|
}
|
|
293
338
|
fs.writeFileSync(configPath, publicUrl);
|
|
294
|
-
console.log(
|
|
295
|
-
chalk.green(` WhatsApp webhook: ${publicUrl}/sms/incoming`)
|
|
296
|
-
);
|
|
339
|
+
console.log(chalk.green(` \u2713 ngrok tunnel: ${publicUrl}/sms/incoming`));
|
|
297
340
|
}
|
|
298
341
|
} catch {
|
|
342
|
+
console.log(chalk.yellow(" ngrok: waiting for tunnel..."));
|
|
343
|
+
}
|
|
344
|
+
if (smsConfig.pendingPrompts.length > 0) {
|
|
345
|
+
console.log();
|
|
299
346
|
console.log(
|
|
300
|
-
chalk.yellow(
|
|
347
|
+
chalk.yellow(
|
|
348
|
+
` \u23F3 ${smsConfig.pendingPrompts.length} pending prompt(s) awaiting response:`
|
|
349
|
+
)
|
|
301
350
|
);
|
|
351
|
+
smsConfig.pendingPrompts.slice(0, 3).forEach((p, i) => {
|
|
352
|
+
const msg = p.message.length > 40 ? p.message.slice(0, 40) + "..." : p.message;
|
|
353
|
+
console.log(chalk.gray(` ${i + 1}. [${p.id}] ${msg}`));
|
|
354
|
+
});
|
|
355
|
+
if (smsConfig.pendingPrompts.length > 3) {
|
|
356
|
+
console.log(
|
|
357
|
+
chalk.gray(` ... and ${smsConfig.pendingPrompts.length - 3} more`)
|
|
358
|
+
);
|
|
359
|
+
}
|
|
302
360
|
}
|
|
361
|
+
console.log();
|
|
362
|
+
console.log(chalk.gray(" Quick actions from WhatsApp:"));
|
|
363
|
+
console.log(chalk.gray(' "status" - session status'));
|
|
364
|
+
console.log(chalk.gray(' "context" - current frame digest'));
|
|
365
|
+
console.log(chalk.gray(' "1", "2" - respond to prompts'));
|
|
366
|
+
console.log(chalk.gray("\u2500".repeat(42)));
|
|
303
367
|
}
|
|
304
368
|
async sendDoneNotification(exitCode) {
|
|
305
369
|
try {
|
|
@@ -430,6 +494,31 @@ class ClaudeSM {
|
|
|
430
494
|
this.config.useWorktree = this.hasUncommittedChanges() || this.detectMultipleInstances();
|
|
431
495
|
}
|
|
432
496
|
break;
|
|
497
|
+
case "--think":
|
|
498
|
+
case "--think-hard":
|
|
499
|
+
case "--ultrathink":
|
|
500
|
+
this.config.useThinkingMode = true;
|
|
501
|
+
this.config.useModelRouting = true;
|
|
502
|
+
this.config.forceProvider = "qwen";
|
|
503
|
+
break;
|
|
504
|
+
case "--qwen":
|
|
505
|
+
this.config.useModelRouting = true;
|
|
506
|
+
this.config.forceProvider = "qwen";
|
|
507
|
+
break;
|
|
508
|
+
case "--openai":
|
|
509
|
+
this.config.useModelRouting = true;
|
|
510
|
+
this.config.forceProvider = "openai";
|
|
511
|
+
break;
|
|
512
|
+
case "--ollama":
|
|
513
|
+
this.config.useModelRouting = true;
|
|
514
|
+
this.config.forceProvider = "ollama";
|
|
515
|
+
break;
|
|
516
|
+
case "--model-routing":
|
|
517
|
+
this.config.useModelRouting = true;
|
|
518
|
+
break;
|
|
519
|
+
case "--no-model-routing":
|
|
520
|
+
this.config.useModelRouting = false;
|
|
521
|
+
break;
|
|
433
522
|
default:
|
|
434
523
|
claudeArgs.push(arg);
|
|
435
524
|
}
|
|
@@ -517,6 +606,45 @@ class ClaudeSM {
|
|
|
517
606
|
);
|
|
518
607
|
}
|
|
519
608
|
}
|
|
609
|
+
if (this.config.useModelRouting) {
|
|
610
|
+
const routerConfig = loadModelRouterConfig();
|
|
611
|
+
if (routerConfig.enabled || this.config.forceProvider) {
|
|
612
|
+
const router = getModelRouter();
|
|
613
|
+
let routeResult;
|
|
614
|
+
if (this.config.forceProvider) {
|
|
615
|
+
const env = router.switchTo(this.config.forceProvider);
|
|
616
|
+
Object.assign(process.env, env);
|
|
617
|
+
console.log(
|
|
618
|
+
chalk.magenta(`\u{1F500} Model: ${this.config.forceProvider} (forced)`)
|
|
619
|
+
);
|
|
620
|
+
if (this.config.forceProvider === "qwen" && this.config.useThinkingMode) {
|
|
621
|
+
const qwenConfig = routerConfig.providers.qwen;
|
|
622
|
+
if (qwenConfig?.params?.enable_thinking) {
|
|
623
|
+
console.log(
|
|
624
|
+
chalk.gray(
|
|
625
|
+
` Thinking mode: budget ${qwenConfig.params.thinking_budget || 1e4} tokens`
|
|
626
|
+
)
|
|
627
|
+
);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
} else {
|
|
631
|
+
const taskType = this.config.useThinkingMode ? "think" : "default";
|
|
632
|
+
routeResult = router.route(taskType, this.config.task);
|
|
633
|
+
Object.assign(process.env, routeResult.env);
|
|
634
|
+
if (routeResult.switched) {
|
|
635
|
+
console.log(
|
|
636
|
+
chalk.magenta(`\u{1F500} Model routed to: ${routeResult.provider}`)
|
|
637
|
+
);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
} else {
|
|
641
|
+
console.log(
|
|
642
|
+
chalk.gray(
|
|
643
|
+
" Model routing: disabled (run: stackmemory model enable)"
|
|
644
|
+
)
|
|
645
|
+
);
|
|
646
|
+
}
|
|
647
|
+
}
|
|
520
648
|
if (this.config.useWhatsApp) {
|
|
521
649
|
console.log(
|
|
522
650
|
chalk.cyan("\u{1F4F1} WhatsApp mode: notifications + webhook enabled")
|
|
@@ -537,10 +665,36 @@ class ClaudeSM {
|
|
|
537
665
|
process.exit(1);
|
|
538
666
|
return;
|
|
539
667
|
}
|
|
540
|
-
const
|
|
541
|
-
|
|
542
|
-
|
|
668
|
+
const fallbackMonitor = new FallbackMonitor({
|
|
669
|
+
enabled: true,
|
|
670
|
+
maxRestarts: 2,
|
|
671
|
+
restartDelayMs: 1500,
|
|
672
|
+
onFallback: (provider, reason) => {
|
|
673
|
+
console.log(chalk.yellow(`
|
|
674
|
+
[auto-fallback] Switching to ${provider}`));
|
|
675
|
+
console.log(chalk.gray(` Reason: ${reason}`));
|
|
676
|
+
console.log(chalk.gray(` Session will continue on ${provider}...`));
|
|
677
|
+
if (this.config.notifyOnDone || this.config.useWhatsApp) {
|
|
678
|
+
sendNotification({
|
|
679
|
+
type: "custom",
|
|
680
|
+
title: "Model Fallback",
|
|
681
|
+
message: `Claude unavailable (${reason}). Switched to ${provider}.`
|
|
682
|
+
}).catch(() => {
|
|
683
|
+
});
|
|
684
|
+
}
|
|
685
|
+
}
|
|
543
686
|
});
|
|
687
|
+
const fallbackAvailable = fallbackMonitor.isFallbackAvailable();
|
|
688
|
+
if (fallbackAvailable) {
|
|
689
|
+
console.log(
|
|
690
|
+
chalk.gray(` Auto-fallback: Qwen ready (on rate limit/error)`)
|
|
691
|
+
);
|
|
692
|
+
}
|
|
693
|
+
const wrapper = fallbackMonitor.wrapProcess(claudeBin, claudeArgs, {
|
|
694
|
+
env: process.env,
|
|
695
|
+
cwd: process.cwd()
|
|
696
|
+
});
|
|
697
|
+
const claude = wrapper.start();
|
|
544
698
|
claude.on("error", (err) => {
|
|
545
699
|
console.error(chalk.red("\u274C Failed to launch Claude CLI."));
|
|
546
700
|
if (err.code === "ENOENT") {
|
|
@@ -559,6 +713,15 @@ class ClaudeSM {
|
|
|
559
713
|
process.exit(1);
|
|
560
714
|
});
|
|
561
715
|
claude.on("exit", async (code) => {
|
|
716
|
+
const status = fallbackMonitor.getStatus();
|
|
717
|
+
if (status.inFallback) {
|
|
718
|
+
console.log(
|
|
719
|
+
chalk.yellow(
|
|
720
|
+
`
|
|
721
|
+
Session completed on fallback provider: ${status.currentProvider}`
|
|
722
|
+
)
|
|
723
|
+
);
|
|
724
|
+
}
|
|
562
725
|
this.saveContext("Claude session ended", {
|
|
563
726
|
action: "session_end",
|
|
564
727
|
exitCode: code
|
|
@@ -624,6 +787,9 @@ configCmd.command("show").description("Show current default settings").action(()
|
|
|
624
787
|
console.log(
|
|
625
788
|
` defaultWhatsApp: ${config.defaultWhatsApp ? chalk.green("true") : chalk.gray("false")}`
|
|
626
789
|
);
|
|
790
|
+
console.log(
|
|
791
|
+
` defaultModelRouting: ${config.defaultModelRouting ? chalk.green("true") : chalk.gray("false")}`
|
|
792
|
+
);
|
|
627
793
|
console.log(chalk.gray(`
|
|
628
794
|
Config: ${getConfigPath()}`));
|
|
629
795
|
});
|
|
@@ -638,7 +804,9 @@ configCmd.command("set <key> <value>").description("Set a default (e.g., set wor
|
|
|
638
804
|
remote: "defaultRemote",
|
|
639
805
|
"notify-done": "defaultNotifyOnDone",
|
|
640
806
|
notifyondone: "defaultNotifyOnDone",
|
|
641
|
-
whatsapp: "defaultWhatsApp"
|
|
807
|
+
whatsapp: "defaultWhatsApp",
|
|
808
|
+
"model-routing": "defaultModelRouting",
|
|
809
|
+
modelrouting: "defaultModelRouting"
|
|
642
810
|
};
|
|
643
811
|
const configKey = keyMap[key];
|
|
644
812
|
if (!configKey) {
|
|
@@ -704,10 +872,25 @@ configCmd.command("whatsapp-off").description("Disable WhatsApp mode by default"
|
|
|
704
872
|
saveSMConfig(config);
|
|
705
873
|
console.log(chalk.green("WhatsApp mode disabled by default"));
|
|
706
874
|
});
|
|
875
|
+
configCmd.command("model-routing-on").description(
|
|
876
|
+
"Enable model routing by default (route tasks to Qwen/other models)"
|
|
877
|
+
).action(() => {
|
|
878
|
+
const config = loadSMConfig();
|
|
879
|
+
config.defaultModelRouting = true;
|
|
880
|
+
saveSMConfig(config);
|
|
881
|
+
console.log(chalk.green("Model routing enabled by default"));
|
|
882
|
+
console.log(chalk.gray("Configure with: stackmemory model setup-qwen"));
|
|
883
|
+
});
|
|
884
|
+
configCmd.command("model-routing-off").description("Disable model routing by default (use Claude only)").action(() => {
|
|
885
|
+
const config = loadSMConfig();
|
|
886
|
+
config.defaultModelRouting = false;
|
|
887
|
+
saveSMConfig(config);
|
|
888
|
+
console.log(chalk.green("Model routing disabled by default"));
|
|
889
|
+
});
|
|
707
890
|
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(
|
|
708
891
|
"--whatsapp",
|
|
709
892
|
"Enable WhatsApp mode (auto-start webhook + ngrok + notifications)"
|
|
710
|
-
).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").helpOption("-h, --help", "Display help").allowUnknownOption(true).action(async (_options) => {
|
|
893
|
+
).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").helpOption("-h, --help", "Display help").allowUnknownOption(true).action(async (_options) => {
|
|
711
894
|
const claudeSM = new ClaudeSM();
|
|
712
895
|
const args = process.argv.slice(2);
|
|
713
896
|
await claudeSM.run(args);
|