@stackmemoryai/stackmemory 1.10.5 → 1.14.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.
- package/LICENSE +131 -64
- package/README.md +107 -24
- package/bin/claude-sm +16 -1
- package/bin/claude-smd +16 -1
- package/bin/codex-smd +16 -1
- package/bin/gemini-sm +16 -1
- package/bin/hermes-sm +21 -0
- package/bin/hermes-smd +21 -0
- package/bin/opencode-sm +16 -1
- package/dist/src/cli/claude-sm.js +266 -84
- package/dist/src/cli/codex-sm.js +225 -33
- package/dist/src/cli/commands/bench.js +209 -2
- package/dist/src/cli/commands/brain.js +206 -0
- package/dist/src/cli/commands/cache.js +126 -0
- package/dist/src/cli/commands/company-os.js +184 -0
- package/dist/src/cli/commands/context.js +5 -0
- package/dist/src/cli/commands/daemon.js +41 -0
- package/dist/src/cli/commands/handoff.js +40 -9
- package/dist/src/cli/commands/onboard.js +70 -3
- package/dist/src/cli/commands/operator.js +127 -0
- package/dist/src/cli/commands/optimize.js +117 -0
- package/dist/src/cli/commands/orchestrate.js +232 -5
- package/dist/src/cli/commands/orchestrator.js +315 -26
- package/dist/src/cli/commands/pack.js +322 -0
- package/dist/src/cli/commands/patterns.js +254 -0
- package/dist/src/cli/commands/portal.js +161 -0
- package/dist/src/cli/commands/scaffold.js +92 -0
- package/dist/src/cli/commands/search.js +40 -1
- package/dist/src/cli/commands/setup.js +178 -11
- package/dist/src/cli/commands/skills.js +10 -1
- package/dist/src/cli/commands/state.js +265 -0
- package/dist/src/cli/commands/sync.js +253 -0
- package/dist/src/cli/commands/tasks.js +130 -1
- package/dist/src/cli/commands/vision.js +221 -0
- package/dist/src/cli/gemini-sm.js +19 -29
- package/dist/src/cli/hermes-sm.js +224 -0
- package/dist/src/cli/index.js +105 -39
- package/dist/src/cli/opencode-sm.js +38 -21
- package/dist/src/cli/utils/determinism-watcher.js +66 -0
- package/dist/src/cli/utils/real-cli-bin.js +116 -0
- package/dist/src/core/brain/brain-store.js +187 -0
- package/dist/src/core/brain/brain-sync.js +193 -0
- package/dist/src/core/brain/index.js +78 -0
- package/dist/src/core/brain/types.js +10 -0
- package/dist/src/core/cache/content-cache.js +238 -0
- package/dist/src/{integrations/diffmem → core/cache}/index.js +5 -5
- package/dist/src/core/cache/token-estimator.js +39 -0
- package/dist/src/core/config/feature-flags.js +2 -6
- package/dist/src/core/context/frame-database.js +79 -27
- package/dist/src/core/context/recursive-context-manager.js +1 -1
- package/dist/src/core/context/rehydration.js +2 -1
- package/dist/src/core/cross-search/cross-project-search.js +269 -0
- package/dist/src/core/cross-search/index.js +10 -0
- package/dist/src/core/database/sqlite-adapter.js +14 -84
- package/dist/src/core/extensions/provider-adapter.js +5 -0
- package/dist/src/core/models/model-router.js +54 -2
- package/dist/src/core/models/provider-pricing.js +58 -4
- package/dist/src/core/monitoring/logger.js +2 -1
- package/dist/src/core/optimization/trace-optimizer.js +413 -0
- package/dist/src/core/patterns/index.js +22 -0
- package/dist/src/core/patterns/pattern-applier.js +39 -0
- package/dist/src/core/patterns/pattern-observer.js +157 -0
- package/dist/src/core/patterns/pattern-store.js +259 -0
- package/dist/src/core/patterns/types.js +19 -0
- package/dist/src/core/provenance/confidence-scorer.js +128 -0
- package/dist/src/core/provenance/index.js +40 -0
- package/dist/src/core/provenance/provenance-store.js +194 -0
- package/dist/src/core/provenance/types.js +82 -0
- package/dist/src/core/retrieval/llm-context-retrieval.js +5 -4
- package/dist/src/core/retrieval/unified-context-assembler.js +11 -66
- package/dist/src/core/session/project-handoff.js +64 -0
- package/dist/src/core/session/session-manager.js +28 -0
- package/dist/src/core/shared-state/canonical-store.js +564 -0
- package/dist/src/core/skill-packs/index.js +18 -0
- package/dist/src/core/skill-packs/parser.js +42 -0
- package/dist/src/core/skill-packs/registry.js +224 -0
- package/dist/src/core/skill-packs/types.js +79 -0
- package/dist/src/core/storage/cloud-sync-manager.js +116 -0
- package/dist/src/core/storage/cloud-sync.js +574 -0
- package/dist/src/core/storage/two-tier-storage.js +5 -1
- package/dist/src/core/tasks/master-tasks-template.js +43 -0
- package/dist/src/core/tasks/md-task-parser.js +138 -0
- package/dist/src/core/trace/trace-event-store.js +282 -0
- package/dist/src/core/vision/index.js +27 -0
- package/dist/src/core/vision/signals.js +79 -0
- package/dist/src/core/vision/types.js +22 -0
- package/dist/src/core/vision/vision-file.js +146 -0
- package/dist/src/core/vision/vision-loop.js +220 -0
- package/dist/src/core/wiki/wiki-compiler.js +103 -1
- package/dist/src/daemon/daemon-config.js +52 -0
- package/dist/src/daemon/services/desire-path-service.js +566 -0
- package/dist/src/daemon/services/github-service.js +126 -0
- package/dist/src/daemon/services/research-stream-service.js +320 -0
- package/dist/src/daemon/services/telemetry-service.js +192 -0
- package/dist/src/daemon/unified-daemon.js +58 -1
- package/dist/src/features/browser/cli-browser-agent.js +417 -0
- package/dist/src/features/browser/stagehand-workflows.js +578 -0
- package/dist/src/features/operator/adapter-factory.js +62 -0
- package/dist/src/features/operator/browser-adapter.js +109 -0
- package/dist/src/features/operator/desktop-adapter.js +125 -0
- package/dist/src/features/operator/index.js +39 -0
- package/dist/src/features/operator/llm-decision.js +137 -0
- package/dist/src/features/operator/operator-logger.js +92 -0
- package/dist/src/features/operator/overnight-runner.js +327 -0
- package/dist/src/features/operator/screen-adapter.js +91 -0
- package/dist/src/features/operator/session-manager.js +127 -0
- package/dist/src/features/operator/state-machine.js +227 -0
- package/dist/src/features/operator/task-queue.js +81 -0
- package/dist/src/features/portal/index.js +26 -0
- package/dist/src/features/portal/server.js +240 -0
- package/dist/src/features/portal/types.js +14 -0
- package/dist/src/features/portal/ui.js +195 -0
- package/dist/src/features/sweep/pty-wrapper.js +13 -5
- package/dist/src/features/tasks/task-aware-context.js +2 -1
- package/dist/src/features/tui/simple-monitor.js +0 -23
- package/dist/src/features/tui/swarm-monitor.js +8 -66
- package/dist/src/features/web/client/hooks/use-socket.js +12 -0
- package/dist/src/{core/merge/index.js → features/web/client/lib/utils.js} +8 -4
- package/dist/src/features/web/client/next-env.d.js +4 -0
- package/dist/src/features/web/client/stores/session-store.js +12 -0
- package/dist/src/features/web/server/gcp-billing.js +76 -0
- package/dist/src/features/web/server/index.js +10 -0
- package/dist/src/features/web/server/spend-calculator.js +228 -0
- package/dist/src/hooks/schemas.js +6 -1
- package/dist/src/integrations/anthropic/client.js +3 -2
- package/dist/src/integrations/claude-code/agent-bridge.js +0 -3
- package/dist/src/integrations/claude-code/subagent-client.js +307 -11
- package/dist/src/integrations/claude-code/task-coordinator.js +2 -1
- package/dist/src/integrations/github/pr-state.js +158 -0
- package/dist/src/integrations/linear/client.js +4 -1
- package/dist/src/integrations/linear/webhook-retry.js +196 -0
- package/dist/src/integrations/linear/webhook-server.js +18 -22
- package/dist/src/integrations/mcp/handlers/cloud-sync-handlers.js +101 -0
- package/dist/src/integrations/mcp/handlers/index.js +40 -84
- package/dist/src/integrations/mcp/server.js +542 -641
- package/dist/src/integrations/mcp/tool-alias-registry.js +297 -0
- package/dist/src/integrations/mcp/tool-definitions.js +152 -682
- package/dist/src/mcp/stackmemory-mcp-server.js +571 -231
- package/dist/src/orchestrators/multimodal/determinism.js +244 -0
- package/dist/src/orchestrators/multimodal/harness.js +149 -78
- package/dist/src/orchestrators/multimodal/providers.js +44 -3
- package/dist/src/skills/recursive-agent-orchestrator.js +2 -4
- package/dist/src/utils/hook-installer.js +0 -8
- package/dist/src/utils/process-cleanup.js +1 -7
- package/docs/README.md +42 -0
- package/docs/guides/README_INSTALL.md +208 -0
- package/package.json +27 -9
- package/packs/coding/python-fastapi/instructions.md +60 -0
- package/packs/coding/python-fastapi/pack.yaml +28 -0
- package/packs/coding/typescript-react/instructions.md +47 -0
- package/packs/coding/typescript-react/pack.yaml +28 -0
- package/packs/core/commands/capture.md +32 -0
- package/packs/core/commands/learn.md +73 -0
- package/packs/core/commands/next.md +36 -0
- package/packs/core/commands/restart.md +58 -0
- package/packs/core/commands/restore.md +29 -0
- package/packs/core/commands/start.md +57 -0
- package/packs/core/commands/stop.md +65 -0
- package/packs/core/commands/summary.md +40 -0
- package/packs/core/manifest.json +24 -0
- package/packs/ops/decision-recovery/instructions.md +65 -0
- package/packs/ops/decision-recovery/pack.yaml +89 -0
- package/scripts/claude-code-wrapper.sh +11 -0
- package/scripts/claude-sm-setup.sh +12 -1
- package/scripts/codex-wrapper.sh +11 -0
- package/scripts/git-hooks/branch-context-manager.sh +11 -0
- package/scripts/git-hooks/post-checkout-stackmemory.sh +11 -0
- package/scripts/git-hooks/post-commit-stackmemory.sh +11 -0
- package/scripts/git-hooks/pre-commit-stackmemory.sh +11 -0
- package/scripts/hooks/cleanup-shell.sh +12 -1
- package/scripts/hooks/task-complete.sh +12 -1
- package/scripts/install-code-execution-hooks.sh +12 -1
- package/scripts/install-sweep-hook.sh +12 -0
- package/scripts/install.sh +11 -0
- package/scripts/opencode-wrapper.sh +11 -0
- package/scripts/portal/cloud-init.yaml +69 -0
- package/scripts/portal/setup.sh +69 -0
- package/scripts/portal/stackmemory-portal.service +34 -0
- package/scripts/setup-claude-integration.sh +12 -1
- package/scripts/smoke-init-db.sh +23 -0
- package/scripts/stackmemory-daemon.sh +11 -0
- package/scripts/verify-dist.cjs +11 -4
- package/dist/src/cli/commands/ralph.js +0 -1053
- package/dist/src/cli/commands/team.js +0 -168
- package/dist/src/core/context/shared-context-layer.js +0 -620
- package/dist/src/core/context/stack-merge-resolver.js +0 -748
- package/dist/src/core/merge/conflict-detector.js +0 -430
- package/dist/src/core/merge/resolution-engine.js +0 -557
- package/dist/src/core/merge/stack-diff.js +0 -531
- package/dist/src/core/merge/unified-merge-resolver.js +0 -302
- package/dist/src/hooks/diffmem-hooks.js +0 -376
- package/dist/src/integrations/diffmem/client.js +0 -208
- package/dist/src/integrations/diffmem/config.js +0 -14
- package/dist/src/integrations/greptile/client.js +0 -101
- package/dist/src/integrations/greptile/config.js +0 -14
- package/dist/src/integrations/greptile/index.js +0 -11
- package/dist/src/integrations/mcp/handlers/cord-handlers.js +0 -397
- package/dist/src/integrations/mcp/handlers/diffmem-handlers.js +0 -455
- package/dist/src/integrations/mcp/handlers/greptile-handlers.js +0 -456
- package/dist/src/integrations/mcp/handlers/provider-handlers.js +0 -227
- package/dist/src/integrations/mcp/handlers/team-handlers.js +0 -211
- package/dist/src/integrations/ralph/bridge/ralph-stackmemory-bridge.js +0 -863
- package/dist/src/integrations/ralph/context/context-budget-manager.js +0 -308
- package/dist/src/integrations/ralph/context/stackmemory-context-loader.js +0 -391
- package/dist/src/integrations/ralph/index.js +0 -17
- package/dist/src/integrations/ralph/learning/pattern-learner.js +0 -435
- package/dist/src/integrations/ralph/lifecycle/iteration-lifecycle.js +0 -448
- package/dist/src/integrations/ralph/loopmax.js +0 -488
- package/dist/src/integrations/ralph/monitoring/swarm-dashboard.js +0 -293
- package/dist/src/integrations/ralph/monitoring/swarm-registry.js +0 -107
- package/dist/src/integrations/ralph/orchestration/multi-loop-orchestrator.js +0 -508
- package/dist/src/integrations/ralph/patterns/compounding-engineering-pattern.js +0 -407
- package/dist/src/integrations/ralph/patterns/extended-coherence-sessions.js +0 -495
- package/dist/src/integrations/ralph/patterns/oracle-worker-pattern.js +0 -387
- package/dist/src/integrations/ralph/performance/performance-optimizer.js +0 -357
- package/dist/src/integrations/ralph/recovery/crash-recovery.js +0 -461
- package/dist/src/integrations/ralph/state/state-reconciler.js +0 -420
- package/dist/src/integrations/ralph/swarm/git-workflow-manager.js +0 -444
- package/dist/src/integrations/ralph/swarm/swarm-coordinator.js +0 -1007
- package/dist/src/integrations/ralph/visualization/ralph-debugger.js +0 -635
- package/scripts/ralph-loop-implementation.js +0 -404
- /package/dist/src/core/{merge → cache}/types.js +0 -0
- /package/dist/src/{integrations/diffmem/types.js → core/storage/cloud-sync-types.js} +0 -0
- /package/dist/src/{integrations/greptile/types.js → core/trace/trace-event.js} +0 -0
- /package/dist/src/{integrations/ralph → features/operator}/types.js +0 -0
|
@@ -9,10 +9,21 @@ import { spawn, execSync, execFileSync } from "child_process";
|
|
|
9
9
|
import * as fs from "fs";
|
|
10
10
|
import * as path from "path";
|
|
11
11
|
import * as os from "os";
|
|
12
|
+
import { fileURLToPath } from "url";
|
|
12
13
|
import { program } from "commander";
|
|
13
14
|
import { v4 as uuidv4 } from "uuid";
|
|
14
15
|
import chalk from "chalk";
|
|
15
16
|
import { initializeTracing, trace } from "../core/trace/index.js";
|
|
17
|
+
import { resolveRealCliBin } from "./utils/real-cli-bin.js";
|
|
18
|
+
import {
|
|
19
|
+
startDeterminismWatcher,
|
|
20
|
+
stopDeterminismWatcher
|
|
21
|
+
} from "./utils/determinism-watcher.js";
|
|
22
|
+
import {
|
|
23
|
+
canonicalStateStore,
|
|
24
|
+
projectIdFromIdentifier
|
|
25
|
+
} from "../core/shared-state/canonical-store.js";
|
|
26
|
+
import { loadProjectHandoff } from "../core/session/project-handoff.js";
|
|
16
27
|
import {
|
|
17
28
|
getModelRouter,
|
|
18
29
|
loadModelRouterConfig
|
|
@@ -43,6 +54,7 @@ import {
|
|
|
43
54
|
writeSettingsAtomic,
|
|
44
55
|
getSettingsPath
|
|
45
56
|
} from "../utils/hook-installer.js";
|
|
57
|
+
const runtimeDirname = path.dirname(fileURLToPath(import.meta.url));
|
|
46
58
|
const DEFAULT_SM_CONFIG = {
|
|
47
59
|
defaultWorktree: false,
|
|
48
60
|
defaultSandbox: false,
|
|
@@ -81,6 +93,11 @@ class ClaudeSM {
|
|
|
81
93
|
worktreeScriptPath;
|
|
82
94
|
claudeConfigDir;
|
|
83
95
|
smConfig;
|
|
96
|
+
sessionId;
|
|
97
|
+
ownsSession;
|
|
98
|
+
sessionEnded;
|
|
99
|
+
determinismWatcher;
|
|
100
|
+
skippedHandoffReason;
|
|
84
101
|
constructor() {
|
|
85
102
|
this.smConfig = loadSMConfig();
|
|
86
103
|
this.config = {
|
|
@@ -100,10 +117,15 @@ class ClaudeSM {
|
|
|
100
117
|
};
|
|
101
118
|
this.stackmemoryPath = this.findStackMemory();
|
|
102
119
|
this.worktreeScriptPath = path.join(
|
|
103
|
-
|
|
120
|
+
runtimeDirname,
|
|
104
121
|
"../../scripts/claude-worktree-manager.sh"
|
|
105
122
|
);
|
|
106
123
|
this.claudeConfigDir = path.join(os.homedir(), ".claude");
|
|
124
|
+
this.sessionId = process.env["STACKMEMORY_SESSION"] || uuidv4();
|
|
125
|
+
this.ownsSession = !process.env["STACKMEMORY_SESSION"];
|
|
126
|
+
this.sessionEnded = false;
|
|
127
|
+
this.determinismWatcher = null;
|
|
128
|
+
this.skippedHandoffReason = null;
|
|
107
129
|
if (!fs.existsSync(this.claudeConfigDir)) {
|
|
108
130
|
fs.mkdirSync(this.claudeConfigDir, { recursive: true });
|
|
109
131
|
}
|
|
@@ -172,6 +194,20 @@ class ClaudeSM {
|
|
|
172
194
|
return "main";
|
|
173
195
|
}
|
|
174
196
|
}
|
|
197
|
+
getProjectId() {
|
|
198
|
+
const root = this.getRepoRoot() || process.cwd();
|
|
199
|
+
try {
|
|
200
|
+
const remote = execSync("git config --get remote.origin.url", {
|
|
201
|
+
cwd: root,
|
|
202
|
+
encoding: "utf8"
|
|
203
|
+
}).trim();
|
|
204
|
+
if (remote) {
|
|
205
|
+
return projectIdFromIdentifier(remote);
|
|
206
|
+
}
|
|
207
|
+
} catch {
|
|
208
|
+
}
|
|
209
|
+
return projectIdFromIdentifier(root);
|
|
210
|
+
}
|
|
175
211
|
hasUncommittedChanges() {
|
|
176
212
|
try {
|
|
177
213
|
const status = execSync("git status --porcelain", { encoding: "utf8" });
|
|
@@ -181,17 +217,16 @@ class ClaudeSM {
|
|
|
181
217
|
}
|
|
182
218
|
}
|
|
183
219
|
resolveClaudeBin() {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
}
|
|
194
|
-
return null;
|
|
220
|
+
return resolveRealCliBin({
|
|
221
|
+
explicitBin: this.config.claudeBin,
|
|
222
|
+
envBin: process.env["CLAUDE_BIN"],
|
|
223
|
+
preferredPaths: [
|
|
224
|
+
path.join(os.homedir(), ".local", "bin", "claude"),
|
|
225
|
+
"/usr/local/bin/claude",
|
|
226
|
+
"/opt/homebrew/bin/claude"
|
|
227
|
+
],
|
|
228
|
+
pathCommands: ["claude"]
|
|
229
|
+
});
|
|
195
230
|
}
|
|
196
231
|
gepaProcesses = [];
|
|
197
232
|
startGEPAWatcher() {
|
|
@@ -206,9 +241,9 @@ class ClaudeSM {
|
|
|
206
241
|
}
|
|
207
242
|
const gepaPaths = [
|
|
208
243
|
// From dist/src/cli -> scripts/gepa (3 levels up)
|
|
209
|
-
path.join(
|
|
244
|
+
path.join(runtimeDirname, "../../../scripts/gepa/hooks/auto-optimize.js"),
|
|
210
245
|
// From src/cli -> scripts/gepa (2 levels up, for dev mode)
|
|
211
|
-
path.join(
|
|
246
|
+
path.join(runtimeDirname, "../../scripts/gepa/hooks/auto-optimize.js"),
|
|
212
247
|
// Global install location
|
|
213
248
|
path.join(
|
|
214
249
|
os.homedir(),
|
|
@@ -220,7 +255,7 @@ class ClaudeSM {
|
|
|
220
255
|
),
|
|
221
256
|
// npm global install
|
|
222
257
|
path.join(
|
|
223
|
-
|
|
258
|
+
runtimeDirname,
|
|
224
259
|
"..",
|
|
225
260
|
"..",
|
|
226
261
|
"scripts",
|
|
@@ -260,6 +295,24 @@ class ClaudeSM {
|
|
|
260
295
|
}
|
|
261
296
|
this.gepaProcesses = [];
|
|
262
297
|
}
|
|
298
|
+
startDeterminismWatcher() {
|
|
299
|
+
this.determinismWatcher = startDeterminismWatcher({
|
|
300
|
+
stackmemoryBin: this.stackmemoryPath,
|
|
301
|
+
cwd: process.cwd(),
|
|
302
|
+
task: this.config.task,
|
|
303
|
+
instanceId: this.config.instanceId,
|
|
304
|
+
sessionId: this.sessionId,
|
|
305
|
+
tool: "claude"
|
|
306
|
+
});
|
|
307
|
+
if (this.determinismWatcher) {
|
|
308
|
+
const modeLabel = this.determinismWatcher.mode === "targeted" ? "targeted" : "repo-root fallback";
|
|
309
|
+
console.log(chalk.gray(` Determinism: ${modeLabel}`));
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
stopDeterminismWatcher() {
|
|
313
|
+
stopDeterminismWatcher(this.determinismWatcher);
|
|
314
|
+
this.determinismWatcher = null;
|
|
315
|
+
}
|
|
263
316
|
setupWorktree() {
|
|
264
317
|
if (!this.config.useWorktree || !this.isGitRepo()) {
|
|
265
318
|
return null;
|
|
@@ -347,16 +400,22 @@ class ClaudeSM {
|
|
|
347
400
|
getHandoffContent() {
|
|
348
401
|
if (!this.config.contextEnabled) return null;
|
|
349
402
|
try {
|
|
350
|
-
const
|
|
403
|
+
const handoff = loadProjectHandoff(
|
|
351
404
|
process.cwd(),
|
|
352
|
-
|
|
353
|
-
"last-handoff.md"
|
|
405
|
+
this.isGitRepo() ? this.getCurrentBranch() : void 0
|
|
354
406
|
);
|
|
355
|
-
if (
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
407
|
+
if (!handoff) {
|
|
408
|
+
this.skippedHandoffReason = null;
|
|
409
|
+
return null;
|
|
410
|
+
}
|
|
411
|
+
if (!handoff.compatible) {
|
|
412
|
+
this.skippedHandoffReason = handoff.mismatchReason || "stale handoff";
|
|
413
|
+
return null;
|
|
414
|
+
}
|
|
415
|
+
this.skippedHandoffReason = null;
|
|
416
|
+
const content = handoff.content.trim();
|
|
417
|
+
if (content.length > 0) {
|
|
418
|
+
return content.length > 8e3 ? content.substring(0, 8e3) + "\n\n[...truncated]" : content;
|
|
360
419
|
}
|
|
361
420
|
} catch {
|
|
362
421
|
}
|
|
@@ -373,10 +432,10 @@ class ClaudeSM {
|
|
|
373
432
|
fs.mkdirSync(hooksDir, { recursive: true });
|
|
374
433
|
}
|
|
375
434
|
const candidateDirs = [
|
|
376
|
-
path.join(
|
|
377
|
-
path.join(
|
|
435
|
+
path.join(runtimeDirname, "../../templates/claude-hooks"),
|
|
436
|
+
path.join(runtimeDirname, "../../../templates/claude-hooks"),
|
|
378
437
|
path.join(
|
|
379
|
-
|
|
438
|
+
runtimeDirname,
|
|
380
439
|
"..",
|
|
381
440
|
"..",
|
|
382
441
|
"..",
|
|
@@ -468,6 +527,149 @@ class ClaudeSM {
|
|
|
468
527
|
console.log(chalk.gray(`
|
|
469
528
|
Session ended (exit ${exitCode ?? 0})`));
|
|
470
529
|
}
|
|
530
|
+
async publishSessionStart() {
|
|
531
|
+
const projectPath = process.cwd();
|
|
532
|
+
const projectId = this.getProjectId();
|
|
533
|
+
const branch = this.isGitRepo() ? this.getCurrentBranch() : void 0;
|
|
534
|
+
await canonicalStateStore.upsertSession({
|
|
535
|
+
sessionId: this.sessionId,
|
|
536
|
+
tool: "claude",
|
|
537
|
+
projectId,
|
|
538
|
+
projectPath,
|
|
539
|
+
branch,
|
|
540
|
+
instanceId: this.config.instanceId,
|
|
541
|
+
metadata: {
|
|
542
|
+
task: this.config.task,
|
|
543
|
+
sandbox: this.config.useSandbox,
|
|
544
|
+
chrome: this.config.useChrome
|
|
545
|
+
}
|
|
546
|
+
});
|
|
547
|
+
await canonicalStateStore.upsertInstance({
|
|
548
|
+
instanceId: this.config.instanceId,
|
|
549
|
+
tool: "claude",
|
|
550
|
+
sessionId: this.sessionId,
|
|
551
|
+
projectId,
|
|
552
|
+
projectPath,
|
|
553
|
+
branch,
|
|
554
|
+
worktreePath: this.config.worktreePath,
|
|
555
|
+
pid: process.pid,
|
|
556
|
+
status: "active",
|
|
557
|
+
metadata: {
|
|
558
|
+
task: this.config.task,
|
|
559
|
+
sandbox: this.config.useSandbox,
|
|
560
|
+
chrome: this.config.useChrome
|
|
561
|
+
}
|
|
562
|
+
});
|
|
563
|
+
await canonicalStateStore.appendEvent({
|
|
564
|
+
type: "session_start",
|
|
565
|
+
tool: "claude",
|
|
566
|
+
sessionId: this.sessionId,
|
|
567
|
+
instanceId: this.config.instanceId,
|
|
568
|
+
projectId,
|
|
569
|
+
projectPath,
|
|
570
|
+
branch,
|
|
571
|
+
payload: {
|
|
572
|
+
task: this.config.task,
|
|
573
|
+
worktreePath: this.config.worktreePath,
|
|
574
|
+
sandbox: this.config.useSandbox,
|
|
575
|
+
chrome: this.config.useChrome
|
|
576
|
+
}
|
|
577
|
+
});
|
|
578
|
+
const claimResult = await canonicalStateStore.claimPaths({
|
|
579
|
+
tool: "claude",
|
|
580
|
+
sessionId: this.sessionId,
|
|
581
|
+
instanceId: this.config.instanceId,
|
|
582
|
+
projectId,
|
|
583
|
+
projectPath,
|
|
584
|
+
branch,
|
|
585
|
+
paths: [],
|
|
586
|
+
metadata: {
|
|
587
|
+
task: this.config.task,
|
|
588
|
+
scope: "branch"
|
|
589
|
+
}
|
|
590
|
+
});
|
|
591
|
+
if (claimResult.conflicts.length > 0) {
|
|
592
|
+
console.log(chalk.yellow("\u26A0\uFE0F Shared state conflict detected"));
|
|
593
|
+
for (const conflict of claimResult.conflicts.slice(0, 3)) {
|
|
594
|
+
console.log(
|
|
595
|
+
chalk.gray(
|
|
596
|
+
` Claim ${conflict.claimId.slice(0, 8)} already owns ${conflict.branch || "overlapping work"}`
|
|
597
|
+
)
|
|
598
|
+
);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
}
|
|
602
|
+
async publishSessionEnd(eventType, payload = {}) {
|
|
603
|
+
if (this.sessionEnded) {
|
|
604
|
+
return;
|
|
605
|
+
}
|
|
606
|
+
this.sessionEnded = true;
|
|
607
|
+
const projectPath = process.cwd();
|
|
608
|
+
const projectId = this.getProjectId();
|
|
609
|
+
const branch = this.isGitRepo() ? this.getCurrentBranch() : void 0;
|
|
610
|
+
await canonicalStateStore.appendEvent({
|
|
611
|
+
type: eventType,
|
|
612
|
+
tool: "claude",
|
|
613
|
+
sessionId: this.sessionId,
|
|
614
|
+
instanceId: this.config.instanceId,
|
|
615
|
+
projectId,
|
|
616
|
+
projectPath,
|
|
617
|
+
branch,
|
|
618
|
+
payload
|
|
619
|
+
});
|
|
620
|
+
await canonicalStateStore.releaseClaims({
|
|
621
|
+
instanceId: this.config.instanceId,
|
|
622
|
+
reason: eventType
|
|
623
|
+
});
|
|
624
|
+
await canonicalStateStore.endInstance(this.config.instanceId);
|
|
625
|
+
if (this.ownsSession) {
|
|
626
|
+
await canonicalStateStore.endSession(this.sessionId);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
async finalizeSession(eventType, exitCode, payload = {}) {
|
|
630
|
+
this.stopGEPAWatcher();
|
|
631
|
+
this.stopDeterminismWatcher();
|
|
632
|
+
this.saveContext(
|
|
633
|
+
eventType === "session_end" ? "Claude session ended" : eventType === "session_interrupt" ? "Claude session interrupted" : "Claude session terminated",
|
|
634
|
+
{
|
|
635
|
+
action: eventType,
|
|
636
|
+
exitCode,
|
|
637
|
+
...payload
|
|
638
|
+
}
|
|
639
|
+
);
|
|
640
|
+
await this.publishSessionEnd(eventType, {
|
|
641
|
+
exitCode,
|
|
642
|
+
...payload
|
|
643
|
+
});
|
|
644
|
+
if (eventType === "session_end" && process.env["LINEAR_API_KEY"]) {
|
|
645
|
+
try {
|
|
646
|
+
execSync("stackmemory linear sync", {
|
|
647
|
+
stdio: "ignore",
|
|
648
|
+
timeout: 1e4
|
|
649
|
+
});
|
|
650
|
+
} catch {
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
if (this.config.tracingEnabled) {
|
|
654
|
+
const summary = trace.getExecutionSummary();
|
|
655
|
+
console.log();
|
|
656
|
+
console.log(chalk.gray("\u2500".repeat(42)));
|
|
657
|
+
console.log(chalk.blue("Debug Trace Summary:"));
|
|
658
|
+
console.log(chalk.gray(summary));
|
|
659
|
+
}
|
|
660
|
+
if (eventType === "session_end" && this.config.notifyOnDone) {
|
|
661
|
+
this.notifyDone(exitCode);
|
|
662
|
+
}
|
|
663
|
+
if (this.config.worktreePath) {
|
|
664
|
+
console.log();
|
|
665
|
+
console.log(chalk.gray("\u2500".repeat(42)));
|
|
666
|
+
console.log(chalk.blue("Session ended in worktree:"));
|
|
667
|
+
console.log(chalk.gray(` ${this.config.worktreePath}`));
|
|
668
|
+
console.log();
|
|
669
|
+
console.log(chalk.gray("To remove worktree: gd_claude"));
|
|
670
|
+
console.log(chalk.gray("To merge to main: cwm"));
|
|
671
|
+
}
|
|
672
|
+
}
|
|
471
673
|
async run(args) {
|
|
472
674
|
const claudeArgs = [];
|
|
473
675
|
let i = 0;
|
|
@@ -642,10 +844,25 @@ Session ended (exit ${exitCode ?? 0})`));
|
|
|
642
844
|
this.loadContext();
|
|
643
845
|
this.ensureHooks();
|
|
644
846
|
process.env["CLAUDE_INSTANCE_ID"] = this.config.instanceId;
|
|
847
|
+
process.env["STACKMEMORY_SESSION"] = this.sessionId;
|
|
645
848
|
if (this.config.worktreePath) {
|
|
646
849
|
process.env["CLAUDE_WORKTREE_PATH"] = this.config.worktreePath;
|
|
647
850
|
}
|
|
851
|
+
const claudeBin = this.resolveClaudeBin();
|
|
852
|
+
if (!claudeBin) {
|
|
853
|
+
console.error(chalk.red("\u274C Claude CLI not found."));
|
|
854
|
+
console.log(
|
|
855
|
+
chalk.gray(
|
|
856
|
+
" Install Claude CLI or set an override:\n export CLAUDE_BIN=/path/to/claude\n claude-sm --help\n\n Ensure PATH includes npm global bin (npm bin -g)."
|
|
857
|
+
)
|
|
858
|
+
);
|
|
859
|
+
process.exit(1);
|
|
860
|
+
return;
|
|
861
|
+
}
|
|
862
|
+
await this.publishSessionStart();
|
|
863
|
+
this.startDeterminismWatcher();
|
|
648
864
|
console.log(chalk.gray(`\u{1F916} Instance ID: ${this.config.instanceId}`));
|
|
865
|
+
console.log(chalk.gray(`\u{1F9E0} Session ID: ${this.sessionId.slice(0, 8)}`));
|
|
649
866
|
console.log(chalk.gray(`\u{1F4C1} Working in: ${process.cwd()}`));
|
|
650
867
|
if (this.config.useSandbox) {
|
|
651
868
|
console.log(chalk.yellow("\u{1F512} Sandbox mode enabled"));
|
|
@@ -712,6 +929,10 @@ Session ended (exit ${exitCode ?? 0})`));
|
|
|
712
929
|
if (handoffContent) {
|
|
713
930
|
initialInput = handoffContent;
|
|
714
931
|
console.log(chalk.gray(" Handoff context ready"));
|
|
932
|
+
} else if (this.skippedHandoffReason) {
|
|
933
|
+
console.log(
|
|
934
|
+
chalk.gray(` Handoff skipped: ${this.skippedHandoffReason}`)
|
|
935
|
+
);
|
|
715
936
|
}
|
|
716
937
|
const theoryContent = this.getTheoryContent();
|
|
717
938
|
if (theoryContent) {
|
|
@@ -723,21 +944,25 @@ ${theoryContent}`;
|
|
|
723
944
|
}
|
|
724
945
|
console.log();
|
|
725
946
|
if (this.config.useSweep) {
|
|
726
|
-
const claudeBin2 = this.resolveClaudeBin();
|
|
727
|
-
if (!claudeBin2) {
|
|
728
|
-
console.error(chalk.red("Claude CLI not found."));
|
|
729
|
-
process.exit(1);
|
|
730
|
-
return;
|
|
731
|
-
}
|
|
732
947
|
console.log(
|
|
733
948
|
chalk.cyan("[Sweep] Launching Claude with prediction bar...")
|
|
734
949
|
);
|
|
735
950
|
console.log(chalk.gray("\u2500".repeat(42)));
|
|
736
951
|
try {
|
|
737
952
|
await launchWrapper({
|
|
738
|
-
claudeBin
|
|
953
|
+
claudeBin,
|
|
739
954
|
claudeArgs,
|
|
740
|
-
initialInput: initialInput || void 0
|
|
955
|
+
initialInput: initialInput || void 0,
|
|
956
|
+
onExit: async (exitCode) => {
|
|
957
|
+
await this.finalizeSession("session_end", exitCode);
|
|
958
|
+
},
|
|
959
|
+
onSignal: async (signal) => {
|
|
960
|
+
await this.finalizeSession(
|
|
961
|
+
signal === "SIGINT" ? "session_interrupt" : "session_terminate",
|
|
962
|
+
null,
|
|
963
|
+
{ signal }
|
|
964
|
+
);
|
|
965
|
+
}
|
|
741
966
|
});
|
|
742
967
|
return;
|
|
743
968
|
} catch (error) {
|
|
@@ -756,17 +981,6 @@ ${theoryContent}`;
|
|
|
756
981
|
}
|
|
757
982
|
console.log(chalk.gray("Starting Claude..."));
|
|
758
983
|
console.log(chalk.gray("\u2500".repeat(42)));
|
|
759
|
-
const claudeBin = this.resolveClaudeBin();
|
|
760
|
-
if (!claudeBin) {
|
|
761
|
-
console.error(chalk.red("\u274C Claude CLI not found."));
|
|
762
|
-
console.log(
|
|
763
|
-
chalk.gray(
|
|
764
|
-
" Install Claude CLI or set an override:\n export CLAUDE_BIN=/path/to/claude\n claude-sm --help\n\n Ensure PATH includes npm global bin (npm bin -g)."
|
|
765
|
-
)
|
|
766
|
-
);
|
|
767
|
-
process.exit(1);
|
|
768
|
-
return;
|
|
769
|
-
}
|
|
770
984
|
const fallbackMonitor = new FallbackMonitor({
|
|
771
985
|
enabled: true,
|
|
772
986
|
maxRestarts: 2,
|
|
@@ -807,7 +1021,6 @@ ${theoryContent}`;
|
|
|
807
1021
|
process.exit(1);
|
|
808
1022
|
});
|
|
809
1023
|
claude.on("exit", async (code) => {
|
|
810
|
-
this.stopGEPAWatcher();
|
|
811
1024
|
const status = fallbackMonitor.getStatus();
|
|
812
1025
|
if (status.inFallback) {
|
|
813
1026
|
console.log(
|
|
@@ -817,49 +1030,18 @@ Session completed on fallback provider: ${status.currentProvider}`
|
|
|
817
1030
|
)
|
|
818
1031
|
);
|
|
819
1032
|
}
|
|
820
|
-
this.
|
|
821
|
-
action: "session_end",
|
|
822
|
-
exitCode: code
|
|
823
|
-
});
|
|
824
|
-
if (process.env["LINEAR_API_KEY"]) {
|
|
825
|
-
try {
|
|
826
|
-
execSync("stackmemory linear sync", {
|
|
827
|
-
stdio: "ignore",
|
|
828
|
-
timeout: 1e4
|
|
829
|
-
});
|
|
830
|
-
} catch {
|
|
831
|
-
}
|
|
832
|
-
}
|
|
833
|
-
if (this.config.tracingEnabled) {
|
|
834
|
-
const summary = trace.getExecutionSummary();
|
|
835
|
-
console.log();
|
|
836
|
-
console.log(chalk.gray("\u2500".repeat(42)));
|
|
837
|
-
console.log(chalk.blue("Debug Trace Summary:"));
|
|
838
|
-
console.log(chalk.gray(summary));
|
|
839
|
-
}
|
|
840
|
-
if (this.config.notifyOnDone) {
|
|
841
|
-
this.notifyDone(code);
|
|
842
|
-
}
|
|
843
|
-
if (this.config.worktreePath) {
|
|
844
|
-
console.log();
|
|
845
|
-
console.log(chalk.gray("\u2500".repeat(42)));
|
|
846
|
-
console.log(chalk.blue("Session ended in worktree:"));
|
|
847
|
-
console.log(chalk.gray(` ${this.config.worktreePath}`));
|
|
848
|
-
console.log();
|
|
849
|
-
console.log(chalk.gray("To remove worktree: gd_claude"));
|
|
850
|
-
console.log(chalk.gray("To merge to main: cwm"));
|
|
851
|
-
}
|
|
1033
|
+
await this.finalizeSession("session_end", code);
|
|
852
1034
|
process.exit(code || 0);
|
|
853
1035
|
});
|
|
854
|
-
process.on("SIGINT", () => {
|
|
855
|
-
this.
|
|
856
|
-
|
|
1036
|
+
process.on("SIGINT", async () => {
|
|
1037
|
+
await this.finalizeSession("session_interrupt", null, {
|
|
1038
|
+
signal: "SIGINT"
|
|
857
1039
|
});
|
|
858
1040
|
claude.kill("SIGINT");
|
|
859
1041
|
});
|
|
860
|
-
process.on("SIGTERM", () => {
|
|
861
|
-
this.
|
|
862
|
-
|
|
1042
|
+
process.on("SIGTERM", async () => {
|
|
1043
|
+
await this.finalizeSession("session_terminate", null, {
|
|
1044
|
+
signal: "SIGTERM"
|
|
863
1045
|
});
|
|
864
1046
|
claude.kill("SIGTERM");
|
|
865
1047
|
});
|