@stackmemoryai/stackmemory 1.12.0 → 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 +3 -1
- 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/codex-sm.js +51 -11
- package/dist/src/cli/commands/brain.js +206 -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/operator.js +127 -0
- package/dist/src/cli/commands/orchestrate.js +2 -0
- package/dist/src/cli/commands/orchestrator.js +3 -2
- 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/setup.js +1 -4
- 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/hermes-sm.js +224 -0
- package/dist/src/cli/index.js +15 -10
- package/dist/src/cli/utils/real-cli-bin.js +72 -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/token-estimator.js +24 -1
- package/dist/src/core/config/feature-flags.js +2 -6
- package/dist/src/core/context/frame-database.js +44 -0
- package/dist/src/core/context/recursive-context-manager.js +1 -1
- package/dist/src/core/context/rehydration.js +2 -1
- package/dist/src/core/database/sqlite-adapter.js +14 -1
- package/dist/src/core/models/model-router.js +33 -1
- package/dist/src/core/models/provider-pricing.js +58 -4
- 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/retrieval/llm-context-retrieval.js +5 -4
- package/dist/src/core/retrieval/unified-context-assembler.js +11 -66
- package/dist/src/core/skill-packs/types.js +14 -1
- 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/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 +45 -0
- package/dist/src/daemon/services/desire-path-service.js +566 -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 +28 -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/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/{integrations/diffmem/index.js → features/web/client/hooks/use-socket.js} +6 -5
- package/dist/src/features/web/client/lib/utils.js +12 -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 +4 -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 +218 -11
- package/dist/src/integrations/claude-code/task-coordinator.js +2 -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 +27 -52
- package/dist/src/integrations/mcp/server.js +122 -335
- package/dist/src/integrations/mcp/tool-alias-registry.js +0 -73
- package/dist/src/integrations/mcp/tool-definitions.js +111 -510
- package/dist/src/mcp/stackmemory-mcp-server.js +404 -379
- package/dist/src/orchestrators/multimodal/determinism.js +2 -1
- package/dist/src/orchestrators/multimodal/harness.js +2 -1
- package/dist/src/skills/recursive-agent-orchestrator.js +2 -4
- 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 +18 -9
- 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/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/cross-search-handlers.js +0 -188
- 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/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 -354
- package/dist/src/integrations/ralph/index.js +0 -17
- package/dist/src/integrations/ralph/learning/pattern-learner.js +0 -416
- 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 -1005
- package/dist/src/integrations/ralph/visualization/ralph-debugger.js +0 -635
- package/scripts/ralph-loop-implementation.js +0 -404
- /package/dist/src/{integrations/diffmem/types.js → core/storage/cloud-sync-types.js} +0 -0
- /package/dist/src/{integrations/greptile → features/operator}/types.js +0 -0
- /package/dist/src/{integrations/ralph/types.js → features/web/client/next-env.d.js} +0 -0
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { fileURLToPath as __fileURLToPath } from 'url';
|
|
2
|
+
import { dirname as __pathDirname } from 'path';
|
|
3
|
+
const __filename = __fileURLToPath(import.meta.url);
|
|
4
|
+
const __dirname = __pathDirname(__filename);
|
|
5
|
+
import { Command } from "commander";
|
|
6
|
+
import chalk from "chalk";
|
|
7
|
+
import { spawnSync } from "child_process";
|
|
8
|
+
import { join } from "path";
|
|
9
|
+
import { openBrain } from "../../core/brain/index.js";
|
|
10
|
+
import {
|
|
11
|
+
VisionLoop,
|
|
12
|
+
SignalInbox,
|
|
13
|
+
loadVision,
|
|
14
|
+
scaffoldVision
|
|
15
|
+
} from "../../core/vision/index.js";
|
|
16
|
+
function paths(cwd) {
|
|
17
|
+
return {
|
|
18
|
+
visionPath: join(cwd, "VISION.md"),
|
|
19
|
+
statePath: join(cwd, ".stackmemory", "vision", "state.json"),
|
|
20
|
+
signalsPath: join(cwd, ".stackmemory", "vision", "signals.jsonl")
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
function shellDelegate(template, timeoutMs) {
|
|
24
|
+
return async (candidate) => {
|
|
25
|
+
const cmd = template.replaceAll("{{OBJECTIVE}}", candidate.text).replaceAll("{{KIND}}", candidate.kind).replaceAll("{{REFS}}", candidate.refs.join(","));
|
|
26
|
+
const res = spawnSync("sh", ["-c", cmd], {
|
|
27
|
+
encoding: "utf-8",
|
|
28
|
+
timeout: timeoutMs,
|
|
29
|
+
maxBuffer: 32 * 1024 * 1024
|
|
30
|
+
});
|
|
31
|
+
const success = res.status === 0 && !res.error;
|
|
32
|
+
const out = (res.stdout || "").trim().split(/\r?\n/).filter(Boolean);
|
|
33
|
+
const errTail = (res.stderr || "").trim().split(/\r?\n/).filter(Boolean).pop();
|
|
34
|
+
const conclusion = success ? out.pop() || "completed" : `failed (${res.error?.message || `exit ${res.status}`}): ${errTail ?? ""}`.trim();
|
|
35
|
+
return { success, conclusion: conclusion.slice(0, 300) };
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
function fmtDecision(d) {
|
|
39
|
+
if (!d.guardrail.ok) return chalk.red(`\u26D4 stop: ${d.guardrail.reason}`);
|
|
40
|
+
if (!d.candidate) return chalk.dim("\xB7 nothing to do");
|
|
41
|
+
const tag = d.candidate.kind === "signal" ? chalk.yellow("[signal]") : chalk.cyan("[objective]");
|
|
42
|
+
const head = `${tag} ${d.candidate.text}`;
|
|
43
|
+
if (d.skippedAsKnown)
|
|
44
|
+
return `${head}
|
|
45
|
+
${chalk.gray("\u21A9 already concluded:")} ${d.priorConclusion}`;
|
|
46
|
+
if (!d.delegated)
|
|
47
|
+
return `${head}
|
|
48
|
+
${chalk.gray("\xB7 planned (not delegated)")}`;
|
|
49
|
+
const mark = d.outcome?.success ? chalk.green("\u2713") : chalk.red("\u2717");
|
|
50
|
+
return `${head}
|
|
51
|
+
${mark} ${d.outcome?.conclusion}`;
|
|
52
|
+
}
|
|
53
|
+
function createVisionCommand() {
|
|
54
|
+
const cmd = new Command("vision").description("VISION.md-driven meta-loop above the conductor").addHelpText(
|
|
55
|
+
"after",
|
|
56
|
+
`
|
|
57
|
+
Examples:
|
|
58
|
+
stackmemory conductor vision init Scaffold a VISION.md
|
|
59
|
+
stackmemory conductor vision status Mission, objectives, limits
|
|
60
|
+
stackmemory conductor vision signal "500s on /sync" --severity high
|
|
61
|
+
stackmemory conductor vision plan Dry-run: what it WOULD do
|
|
62
|
+
stackmemory conductor vision run --once --dry-run
|
|
63
|
+
stackmemory conductor vision run --delegate-cmd 'claude -p "{{OBJECTIVE}}"'
|
|
64
|
+
|
|
65
|
+
VISION.md is the guardrail: north-star mission, scope, objectives, and hard
|
|
66
|
+
limits (maxIterations, maxConsecutiveFailures, \u2026). See docs/guides/VISION.md.
|
|
67
|
+
`
|
|
68
|
+
);
|
|
69
|
+
cmd.command("init").description("Scaffold a VISION.md in the current repo").option("--force", "Overwrite an existing VISION.md").action((options) => {
|
|
70
|
+
const { visionPath } = paths(process.cwd());
|
|
71
|
+
if (scaffoldVision(visionPath, !!options.force)) {
|
|
72
|
+
console.log(chalk.green("\u2713 created"), visionPath);
|
|
73
|
+
console.log(
|
|
74
|
+
chalk.gray(" Edit the mission, guardrails, and objectives, then:")
|
|
75
|
+
);
|
|
76
|
+
console.log(chalk.gray(" stackmemory conductor vision plan"));
|
|
77
|
+
} else {
|
|
78
|
+
console.log(
|
|
79
|
+
chalk.yellow("VISION.md already exists (use --force to overwrite).")
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
});
|
|
83
|
+
cmd.command("status").description("Show the vision, objective progress, signals, and limits").option("--json", "Output as JSON").action((options) => {
|
|
84
|
+
const p = paths(process.cwd());
|
|
85
|
+
const vision = loadVision(p.visionPath);
|
|
86
|
+
if (!vision) {
|
|
87
|
+
console.log(
|
|
88
|
+
chalk.yellow("No VISION.md. Run: stackmemory conductor vision init")
|
|
89
|
+
);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
const inbox = new SignalInbox(p.signalsPath);
|
|
93
|
+
const pending = inbox.pending();
|
|
94
|
+
const done = vision.objectives.filter((o) => o.done).length;
|
|
95
|
+
if (options.json) {
|
|
96
|
+
console.log(
|
|
97
|
+
JSON.stringify({ vision, pendingSignals: pending }, null, 2)
|
|
98
|
+
);
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
console.log(chalk.bold("Mission"));
|
|
102
|
+
console.log(" " + (vision.mission || chalk.dim("(none set)")));
|
|
103
|
+
console.log(
|
|
104
|
+
chalk.bold(`
|
|
105
|
+
Objectives (${done}/${vision.objectives.length})`)
|
|
106
|
+
);
|
|
107
|
+
for (const o of vision.objectives) {
|
|
108
|
+
console.log(
|
|
109
|
+
` ${o.done ? chalk.green("[x]") : chalk.dim("[ ]")} ${o.text}`
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
console.log(chalk.bold(`
|
|
113
|
+
Guardrails (${vision.guardrails.length})`));
|
|
114
|
+
for (const g of vision.guardrails)
|
|
115
|
+
console.log(` ${chalk.gray("\u2022")} ${g}`);
|
|
116
|
+
console.log(chalk.bold(`
|
|
117
|
+
Pending signals (${pending.length})`));
|
|
118
|
+
for (const s of pending.slice(0, 10)) {
|
|
119
|
+
console.log(` ${chalk.yellow(s.severity.padEnd(8))} ${s.text}`);
|
|
120
|
+
}
|
|
121
|
+
console.log(chalk.bold("\nLimits"));
|
|
122
|
+
console.log(
|
|
123
|
+
chalk.gray(
|
|
124
|
+
` maxIterations=${vision.limits.maxIterations} perDay=${vision.limits.maxIterationsPerDay} maxConsecutiveFailures=${vision.limits.maxConsecutiveFailures} requireApproval=${vision.limits.requireApproval}`
|
|
125
|
+
)
|
|
126
|
+
);
|
|
127
|
+
});
|
|
128
|
+
cmd.command("signal").description("Add a signal to the monitored inbox").argument("<text>", "What happened (bug, CI failure, request)").option("--severity <level>", "low | medium | high | critical", "medium").option(
|
|
129
|
+
"--source <name>",
|
|
130
|
+
"Where it came from (bug, ci, github, \u2026)",
|
|
131
|
+
"manual"
|
|
132
|
+
).option("--refs <refs>", "Comma-separated refs (issue, run id, commit)").action((text, options) => {
|
|
133
|
+
const p = paths(process.cwd());
|
|
134
|
+
const inbox = new SignalInbox(p.signalsPath);
|
|
135
|
+
const refs = options.refs ? String(options.refs).split(",").map((r) => r.trim()) : void 0;
|
|
136
|
+
const s = inbox.add({
|
|
137
|
+
text,
|
|
138
|
+
severity: options.severity,
|
|
139
|
+
source: options.source,
|
|
140
|
+
...refs ? { refs } : {}
|
|
141
|
+
});
|
|
142
|
+
console.log(
|
|
143
|
+
chalk.green("\u2713 signal queued"),
|
|
144
|
+
chalk.dim(s.id.slice(0, 8)),
|
|
145
|
+
`[${s.severity}]`
|
|
146
|
+
);
|
|
147
|
+
});
|
|
148
|
+
cmd.command("plan").description("Dry-run: show what the loop would do next, without acting").option("--max <n>", "Max ticks to plan (default 1 \u2014 the next action)").action(async (options) => {
|
|
149
|
+
await runLoop({
|
|
150
|
+
dryRun: true,
|
|
151
|
+
max: options.max ? parseInt(options.max, 10) : 1
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
cmd.command("run").description(
|
|
155
|
+
"Run the vision loop (plan-only unless --delegate-cmd is given)"
|
|
156
|
+
).option("--once", "Run a single tick").option("--max <n>", "Max ticks this run").option("--dry-run", "Plan without delegating").option(
|
|
157
|
+
"--delegate-cmd <template>",
|
|
158
|
+
"Shell command per objective; {{OBJECTIVE}} {{KIND}} {{REFS}} are substituted"
|
|
159
|
+
).option("--timeout <sec>", "Per-delegation timeout (seconds)", "1800").action(async (options) => {
|
|
160
|
+
const dryRun = !!options.dryRun || !options.delegateCmd;
|
|
161
|
+
if (!options.dryRun && !options.delegateCmd) {
|
|
162
|
+
console.log(
|
|
163
|
+
chalk.yellow(
|
|
164
|
+
`No --delegate-cmd given \u2014 running plan-only. Provide one to act, e.g.:
|
|
165
|
+
--delegate-cmd 'claude -p "{{OBJECTIVE}}"'`
|
|
166
|
+
)
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
const max = options.once ? 1 : options.max ? parseInt(options.max, 10) : void 0;
|
|
170
|
+
await runLoop({
|
|
171
|
+
dryRun,
|
|
172
|
+
timeoutMs: parseInt(options.timeout, 10) * 1e3,
|
|
173
|
+
...max !== void 0 ? { max } : {},
|
|
174
|
+
...options.delegateCmd ? { delegateCmd: options.delegateCmd } : {}
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
return cmd;
|
|
178
|
+
}
|
|
179
|
+
async function runLoop(opts) {
|
|
180
|
+
const p = paths(process.cwd());
|
|
181
|
+
const vision = loadVision(p.visionPath);
|
|
182
|
+
if (!vision) {
|
|
183
|
+
console.error(
|
|
184
|
+
chalk.red("No VISION.md. Run: stackmemory conductor vision init")
|
|
185
|
+
);
|
|
186
|
+
process.exit(1);
|
|
187
|
+
}
|
|
188
|
+
const ctx = openBrain();
|
|
189
|
+
try {
|
|
190
|
+
const delegate = opts.delegateCmd ? shellDelegate(opts.delegateCmd, opts.timeoutMs ?? 18e5) : async (c) => ({
|
|
191
|
+
success: false,
|
|
192
|
+
conclusion: `no delegate configured for: ${c.text}`
|
|
193
|
+
});
|
|
194
|
+
const loop = new VisionLoop({
|
|
195
|
+
visionPath: p.visionPath,
|
|
196
|
+
statePath: p.statePath,
|
|
197
|
+
signalsPath: p.signalsPath,
|
|
198
|
+
brain: ctx.store,
|
|
199
|
+
delegate
|
|
200
|
+
});
|
|
201
|
+
console.log(
|
|
202
|
+
chalk.bold(opts.dryRun ? "Vision plan (dry-run)" : "Vision run")
|
|
203
|
+
);
|
|
204
|
+
console.log(
|
|
205
|
+
chalk.gray(" " + (vision.mission || "(no mission set)")) + "\n"
|
|
206
|
+
);
|
|
207
|
+
const result = await loop.run({
|
|
208
|
+
dryRun: opts.dryRun,
|
|
209
|
+
...opts.max !== void 0 ? { maxIterations: opts.max } : {}
|
|
210
|
+
});
|
|
211
|
+
for (const d of result.decisions) console.log(fmtDecision(d));
|
|
212
|
+
console.log(
|
|
213
|
+
"\n" + chalk.bold("Summary: ") + chalk.green(`${result.delegated} delegated`) + ", " + chalk.gray(`${result.skipped} skipped`) + " \u2014 " + chalk.dim(result.stopped)
|
|
214
|
+
);
|
|
215
|
+
} finally {
|
|
216
|
+
ctx.close();
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
export {
|
|
220
|
+
createVisionCommand
|
|
221
|
+
};
|
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { fileURLToPath as __fileURLToPath } from 'url';
|
|
3
|
+
import { dirname as __pathDirname } from 'path';
|
|
4
|
+
const __filename = __fileURLToPath(import.meta.url);
|
|
5
|
+
const __dirname = __pathDirname(__filename);
|
|
6
|
+
import { spawn, execSync } from "child_process";
|
|
7
|
+
import * as fs from "fs";
|
|
8
|
+
import * as path from "path";
|
|
9
|
+
import * as os from "os";
|
|
10
|
+
import { program } from "commander";
|
|
11
|
+
import { v4 as uuidv4 } from "uuid";
|
|
12
|
+
import chalk from "chalk";
|
|
13
|
+
import { initializeTracing, trace } from "../core/trace/index.js";
|
|
14
|
+
import {
|
|
15
|
+
startDeterminismWatcher,
|
|
16
|
+
stopDeterminismWatcher
|
|
17
|
+
} from "./utils/determinism-watcher.js";
|
|
18
|
+
import {
|
|
19
|
+
canonicalStateStore,
|
|
20
|
+
projectIdFromIdentifier
|
|
21
|
+
} from "../core/shared-state/canonical-store.js";
|
|
22
|
+
const SM_DIR = path.join(os.homedir(), ".stackmemory");
|
|
23
|
+
const HERMES_CONFIG_PATH = path.join(SM_DIR, "hermes-sm.json");
|
|
24
|
+
const DEFAULT_CONFIG = {
|
|
25
|
+
defaultTracing: true,
|
|
26
|
+
defaultContext: true
|
|
27
|
+
};
|
|
28
|
+
function loadConfig() {
|
|
29
|
+
try {
|
|
30
|
+
if (fs.existsSync(HERMES_CONFIG_PATH)) {
|
|
31
|
+
return {
|
|
32
|
+
...DEFAULT_CONFIG,
|
|
33
|
+
...JSON.parse(fs.readFileSync(HERMES_CONFIG_PATH, "utf8"))
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
} catch {
|
|
37
|
+
}
|
|
38
|
+
return { ...DEFAULT_CONFIG };
|
|
39
|
+
}
|
|
40
|
+
function resolveHermesBin() {
|
|
41
|
+
const candidates = [
|
|
42
|
+
path.join(os.homedir(), ".local", "bin", "hermes"),
|
|
43
|
+
"/usr/local/bin/hermes",
|
|
44
|
+
"/opt/homebrew/bin/hermes"
|
|
45
|
+
];
|
|
46
|
+
for (const bin of candidates) {
|
|
47
|
+
if (fs.existsSync(bin)) return bin;
|
|
48
|
+
}
|
|
49
|
+
try {
|
|
50
|
+
const which = execSync("which hermes", { encoding: "utf8" }).trim();
|
|
51
|
+
if (which) return which;
|
|
52
|
+
} catch {
|
|
53
|
+
}
|
|
54
|
+
throw new Error(
|
|
55
|
+
"hermes not found. Install: pip install hermes-agent or check ~/.local/bin/hermes"
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
function ensureDaemon() {
|
|
59
|
+
const pidFile = path.join(SM_DIR, "daemon", "daemon.pid");
|
|
60
|
+
try {
|
|
61
|
+
if (fs.existsSync(pidFile)) {
|
|
62
|
+
const pid = parseInt(fs.readFileSync(pidFile, "utf8").trim(), 10);
|
|
63
|
+
try {
|
|
64
|
+
process.kill(pid, 0);
|
|
65
|
+
return;
|
|
66
|
+
} catch {
|
|
67
|
+
fs.unlinkSync(pidFile);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
} catch {
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
execSync("stackmemory daemon start", { stdio: "ignore", timeout: 5e3 });
|
|
74
|
+
console.log(chalk.dim(" \u21B3 StackMemory daemon started"));
|
|
75
|
+
} catch {
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
function writeSessionHeartbeat(instanceId) {
|
|
79
|
+
const sessionsDir = path.join(SM_DIR, "sessions");
|
|
80
|
+
if (!fs.existsSync(sessionsDir))
|
|
81
|
+
fs.mkdirSync(sessionsDir, { recursive: true });
|
|
82
|
+
const heartbeatFile = path.join(
|
|
83
|
+
sessionsDir,
|
|
84
|
+
`session-${Date.now()}.heartbeat`
|
|
85
|
+
);
|
|
86
|
+
fs.writeFileSync(heartbeatFile, instanceId);
|
|
87
|
+
const interval = setInterval(() => {
|
|
88
|
+
try {
|
|
89
|
+
const now = /* @__PURE__ */ new Date();
|
|
90
|
+
fs.utimesSync(heartbeatFile, now, now);
|
|
91
|
+
} catch {
|
|
92
|
+
}
|
|
93
|
+
}, 6e4);
|
|
94
|
+
interval.unref();
|
|
95
|
+
return interval;
|
|
96
|
+
}
|
|
97
|
+
class HermesSM {
|
|
98
|
+
config;
|
|
99
|
+
detWatcher;
|
|
100
|
+
heartbeatInterval;
|
|
101
|
+
constructor(config) {
|
|
102
|
+
this.config = config;
|
|
103
|
+
}
|
|
104
|
+
async run() {
|
|
105
|
+
const { instanceId, tracingEnabled, verboseTracing } = this.config;
|
|
106
|
+
console.log(chalk.cyan("\u256D\u2500 hermes-sm \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\u2500\u2500\u2500\u256E"));
|
|
107
|
+
console.log(
|
|
108
|
+
chalk.cyan(
|
|
109
|
+
`\u2502 Instance: ${instanceId.slice(0, 8)} \u2502`
|
|
110
|
+
)
|
|
111
|
+
);
|
|
112
|
+
console.log(chalk.cyan("\u2570\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\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u256F"));
|
|
113
|
+
ensureDaemon();
|
|
114
|
+
if (tracingEnabled) {
|
|
115
|
+
initializeTracing({
|
|
116
|
+
serviceName: "hermes-sm",
|
|
117
|
+
verbose: verboseTracing
|
|
118
|
+
});
|
|
119
|
+
trace("session_start", { instanceId, tool: "hermes" });
|
|
120
|
+
}
|
|
121
|
+
this.heartbeatInterval = writeSessionHeartbeat(instanceId);
|
|
122
|
+
if (this.config.contextEnabled) {
|
|
123
|
+
try {
|
|
124
|
+
this.detWatcher = startDeterminismWatcher({
|
|
125
|
+
projectId: projectIdFromIdentifier(process.cwd()),
|
|
126
|
+
sessionId: instanceId
|
|
127
|
+
});
|
|
128
|
+
} catch {
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
let handoffContext = "";
|
|
132
|
+
if (this.config.contextEnabled) {
|
|
133
|
+
try {
|
|
134
|
+
const projectId = projectIdFromIdentifier(process.cwd());
|
|
135
|
+
const store = canonicalStateStore();
|
|
136
|
+
const handoff = store.getLatestHandoff(projectId);
|
|
137
|
+
if (handoff) {
|
|
138
|
+
handoffContext = handoff.content || "";
|
|
139
|
+
console.log(
|
|
140
|
+
chalk.dim(
|
|
141
|
+
` \u21B3 Restored handoff: ${handoff.summary?.slice(0, 60) || "previous session"}`
|
|
142
|
+
)
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
} catch {
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const hermesBin = this.config.hermesBin || resolveHermesBin();
|
|
149
|
+
const args = [];
|
|
150
|
+
if (this.config.resume) {
|
|
151
|
+
args.push("--resume", this.config.resume);
|
|
152
|
+
} else if (this.config.task) {
|
|
153
|
+
args.push("-z", this.config.task);
|
|
154
|
+
}
|
|
155
|
+
if (this.config.model) {
|
|
156
|
+
args.push("-m", this.config.model);
|
|
157
|
+
}
|
|
158
|
+
if (this.config.provider) {
|
|
159
|
+
args.push("--provider", this.config.provider);
|
|
160
|
+
}
|
|
161
|
+
args.push("--pass-session-id");
|
|
162
|
+
const env = {
|
|
163
|
+
...process.env,
|
|
164
|
+
STACKMEMORY_SESSION: instanceId,
|
|
165
|
+
STACKMEMORY_TOOL: "hermes",
|
|
166
|
+
STACKMEMORY_PROJECT: process.cwd()
|
|
167
|
+
};
|
|
168
|
+
if (handoffContext) {
|
|
169
|
+
env.HERMES_SYSTEM_PREFIX = handoffContext.slice(0, 2e3);
|
|
170
|
+
}
|
|
171
|
+
console.log(chalk.dim(` \u21B3 ${hermesBin} ${args.join(" ")}`));
|
|
172
|
+
const child = spawn(hermesBin, args, {
|
|
173
|
+
stdio: "inherit",
|
|
174
|
+
env,
|
|
175
|
+
cwd: process.cwd()
|
|
176
|
+
});
|
|
177
|
+
child.on("exit", (code) => {
|
|
178
|
+
this.cleanup();
|
|
179
|
+
if (tracingEnabled) {
|
|
180
|
+
trace("session_end", {
|
|
181
|
+
instanceId,
|
|
182
|
+
exitCode: code,
|
|
183
|
+
duration: Date.now() - this.config.sessionStartTime
|
|
184
|
+
});
|
|
185
|
+
}
|
|
186
|
+
process.exit(code || 0);
|
|
187
|
+
});
|
|
188
|
+
const handleSignal = (signal) => {
|
|
189
|
+
child.kill(signal);
|
|
190
|
+
};
|
|
191
|
+
process.on("SIGINT", () => handleSignal("SIGINT"));
|
|
192
|
+
process.on("SIGTERM", () => handleSignal("SIGTERM"));
|
|
193
|
+
}
|
|
194
|
+
cleanup() {
|
|
195
|
+
if (this.detWatcher) {
|
|
196
|
+
stopDeterminismWatcher(this.detWatcher);
|
|
197
|
+
}
|
|
198
|
+
if (this.heartbeatInterval) {
|
|
199
|
+
clearInterval(this.heartbeatInterval);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
const smConfig = loadConfig();
|
|
204
|
+
program.name("hermes-smd").description(
|
|
205
|
+
"Hermes with StackMemory context persistence, daemon auto-start, and desire-path tracking"
|
|
206
|
+
).argument("[prompt...]", "Initial prompt for hermes").option("--resume <session>", "Resume a Hermes session by ID").option("-m, --model <model>", "Model to use").option("--provider <provider>", "Model provider").option("--no-context", "Disable context persistence").option("--no-tracing", "Disable tracing").option("--verbose-trace", "Verbose tracing output").option("--hermes-bin <path>", "Path to hermes binary").action(async (prompt, options) => {
|
|
207
|
+
const instanceId = uuidv4();
|
|
208
|
+
const task = prompt.length > 0 ? prompt.join(" ") : void 0;
|
|
209
|
+
const config = {
|
|
210
|
+
instanceId,
|
|
211
|
+
contextEnabled: options.context !== false && smConfig.defaultContext,
|
|
212
|
+
task,
|
|
213
|
+
tracingEnabled: options.tracing !== false && smConfig.defaultTracing,
|
|
214
|
+
verboseTracing: options.verboseTrace || false,
|
|
215
|
+
hermesBin: options.hermesBin,
|
|
216
|
+
sessionStartTime: Date.now(),
|
|
217
|
+
model: options.model,
|
|
218
|
+
provider: options.provider,
|
|
219
|
+
resume: options.resume
|
|
220
|
+
};
|
|
221
|
+
const sm = new HermesSM(config);
|
|
222
|
+
await sm.run();
|
|
223
|
+
});
|
|
224
|
+
program.parse();
|
package/dist/src/cli/index.js
CHANGED
|
@@ -38,12 +38,14 @@ import {
|
|
|
38
38
|
} from "./commands/decision.js";
|
|
39
39
|
import clearCommand from "./commands/clear.js";
|
|
40
40
|
import serviceCommand from "./commands/service.js";
|
|
41
|
-
import { registerLoginCommand } from "./commands/login.js";
|
|
42
41
|
import { registerSignupCommand } from "./commands/signup.js";
|
|
42
|
+
import { createSyncCommand, createLoginCommand } from "./commands/sync.js";
|
|
43
43
|
import { registerLogoutCommand, registerDbCommands } from "./commands/db.js";
|
|
44
44
|
import { createHooksCommand } from "./commands/hooks.js";
|
|
45
45
|
import { createDaemonCommand } from "./commands/daemon.js";
|
|
46
46
|
import { createSweepCommand } from "./commands/sweep.js";
|
|
47
|
+
import { createPortalCommand } from "./commands/portal.js";
|
|
48
|
+
import { createBrainCommand } from "./commands/brain.js";
|
|
47
49
|
import { createShellCommand } from "./commands/shell.js";
|
|
48
50
|
import { createAPICommand } from "./commands/api.js";
|
|
49
51
|
import { createCleanupProcessesCommand } from "./commands/cleanup-processes.js";
|
|
@@ -61,6 +63,8 @@ import { createStateCommand } from "./commands/state.js";
|
|
|
61
63
|
import { createDigestCommands } from "./commands/digest.js";
|
|
62
64
|
import { createDesiresCommands } from "./commands/desires.js";
|
|
63
65
|
import { createConductorCommands } from "./commands/orchestrate.js";
|
|
66
|
+
import { createOperatorCommands } from "./commands/operator.js";
|
|
67
|
+
import { createPatternsCommand } from "./commands/patterns.js";
|
|
64
68
|
import { createPreflightCommand } from "./commands/preflight.js";
|
|
65
69
|
import { createRulesCommand } from "./commands/rules.js";
|
|
66
70
|
import { createSnapshotCommand } from "./commands/snapshot.js";
|
|
@@ -69,6 +73,8 @@ import { createLoopCommand } from "./commands/loop.js";
|
|
|
69
73
|
import { createSkillCommand } from "./commands/skill.js";
|
|
70
74
|
import { createPackCommand } from "./commands/pack.js";
|
|
71
75
|
import { createCacheCommand } from "./commands/cache.js";
|
|
76
|
+
import { createScaffoldCommand } from "./commands/scaffold.js";
|
|
77
|
+
import { createCompanyOsCommand } from "./commands/company-os.js";
|
|
72
78
|
import chalk from "chalk";
|
|
73
79
|
import * as fs from "fs";
|
|
74
80
|
import * as path from "path";
|
|
@@ -497,7 +503,7 @@ program.command("context:test").description("Test context persistence by creatin
|
|
|
497
503
|
});
|
|
498
504
|
registerOnboardingCommand(program);
|
|
499
505
|
registerSignupCommand(program);
|
|
500
|
-
|
|
506
|
+
program.addCommand(createLoginCommand());
|
|
501
507
|
registerLogoutCommand(program);
|
|
502
508
|
registerDbCommands(program);
|
|
503
509
|
registerProjectCommands(program);
|
|
@@ -515,6 +521,7 @@ program.addCommand(createConfigCommand());
|
|
|
515
521
|
program.addCommand(createCaptureCommand());
|
|
516
522
|
program.addCommand(createRestoreCommand());
|
|
517
523
|
program.addCommand(createAutoCaptureCommand());
|
|
524
|
+
program.addCommand(createSyncCommand());
|
|
518
525
|
program.addCommand(createDecisionCommand());
|
|
519
526
|
program.addCommand(createMemoryCommand());
|
|
520
527
|
program.addCommand(clearCommand);
|
|
@@ -587,16 +594,10 @@ if (isFeatureEnabled("skills")) {
|
|
|
587
594
|
})
|
|
588
595
|
);
|
|
589
596
|
}
|
|
590
|
-
if (isFeatureEnabled("ralph")) {
|
|
591
|
-
lazyCommands.push(
|
|
592
|
-
import("./commands/ralph.js").then(
|
|
593
|
-
({ default: createRalphCommand }) => program.addCommand(createRalphCommand())
|
|
594
|
-
).catch(() => {
|
|
595
|
-
})
|
|
596
|
-
);
|
|
597
|
-
}
|
|
598
597
|
program.addCommand(createDaemonCommand());
|
|
599
598
|
program.addCommand(createSweepCommand());
|
|
599
|
+
program.addCommand(createPortalCommand());
|
|
600
|
+
program.addCommand(createBrainCommand());
|
|
600
601
|
program.addCommand(createShellCommand());
|
|
601
602
|
program.addCommand(createAPICommand());
|
|
602
603
|
program.addCommand(createCleanupProcessesCommand());
|
|
@@ -613,6 +614,8 @@ program.addCommand(createStateCommand());
|
|
|
613
614
|
program.addCommand(createDigestCommands());
|
|
614
615
|
program.addCommand(createDesiresCommands());
|
|
615
616
|
program.addCommand(createConductorCommands());
|
|
617
|
+
program.addCommand(createOperatorCommands());
|
|
618
|
+
program.addCommand(createPatternsCommand());
|
|
616
619
|
program.addCommand(createPreflightCommand());
|
|
617
620
|
program.addCommand(createSnapshotCommand());
|
|
618
621
|
program.addCommand(createWikiCommand());
|
|
@@ -621,6 +624,8 @@ program.addCommand(createRulesCommand());
|
|
|
621
624
|
program.addCommand(createSkillCommand());
|
|
622
625
|
program.addCommand(createPackCommand());
|
|
623
626
|
program.addCommand(createCacheCommand());
|
|
627
|
+
program.addCommand(createScaffoldCommand());
|
|
628
|
+
program.addCommand(createCompanyOsCommand());
|
|
624
629
|
registerSetupCommands(program);
|
|
625
630
|
program.command("mm-spike").description(
|
|
626
631
|
"Run multi-agent planning/implementation spike (planner/implementer/critic)"
|
|
@@ -3,7 +3,9 @@ import { dirname as __pathDirname } from 'path';
|
|
|
3
3
|
const __filename = __fileURLToPath(import.meta.url);
|
|
4
4
|
const __dirname = __pathDirname(__filename);
|
|
5
5
|
import { execSync } from "child_process";
|
|
6
|
+
import { createRequire } from "node:module";
|
|
6
7
|
import * as fs from "fs";
|
|
8
|
+
import * as path from "path";
|
|
7
9
|
const DEFAULT_WRAPPER_PATH_SNIPPETS = [
|
|
8
10
|
"/Applications/cmux.app/Contents/Resources/bin/"
|
|
9
11
|
];
|
|
@@ -39,6 +41,76 @@ function resolveRealCliBin(options) {
|
|
|
39
41
|
}
|
|
40
42
|
return null;
|
|
41
43
|
}
|
|
44
|
+
const CODEX_PLATFORM_TRIPLES = {
|
|
45
|
+
darwin: { x64: "x86_64-apple-darwin", arm64: "aarch64-apple-darwin" },
|
|
46
|
+
linux: {
|
|
47
|
+
x64: "x86_64-unknown-linux-musl",
|
|
48
|
+
arm64: "aarch64-unknown-linux-musl"
|
|
49
|
+
},
|
|
50
|
+
win32: { x64: "x86_64-pc-windows-msvc", arm64: "aarch64-pc-windows-msvc" }
|
|
51
|
+
};
|
|
52
|
+
function resolveNativeCodexBin() {
|
|
53
|
+
const triple = CODEX_PLATFORM_TRIPLES[process.platform]?.[process.arch];
|
|
54
|
+
if (!triple) return [];
|
|
55
|
+
const binaryName = process.platform === "win32" ? "codex.exe" : "codex";
|
|
56
|
+
const platformPkg = `@openai/codex-${process.platform}-${process.arch === "arm64" ? "arm64" : "x64"}`;
|
|
57
|
+
const candidates = [];
|
|
58
|
+
try {
|
|
59
|
+
const req = createRequire(
|
|
60
|
+
path.join(
|
|
61
|
+
process.execPath,
|
|
62
|
+
"..",
|
|
63
|
+
"..",
|
|
64
|
+
"lib",
|
|
65
|
+
"node_modules",
|
|
66
|
+
"@openai",
|
|
67
|
+
"codex",
|
|
68
|
+
"package.json"
|
|
69
|
+
)
|
|
70
|
+
);
|
|
71
|
+
const pkgJson = req.resolve(`${platformPkg}/package.json`);
|
|
72
|
+
const vendorBin = path.join(
|
|
73
|
+
path.dirname(pkgJson),
|
|
74
|
+
"vendor",
|
|
75
|
+
triple,
|
|
76
|
+
"bin",
|
|
77
|
+
binaryName
|
|
78
|
+
);
|
|
79
|
+
if (fs.existsSync(vendorBin)) candidates.push(vendorBin);
|
|
80
|
+
} catch {
|
|
81
|
+
}
|
|
82
|
+
try {
|
|
83
|
+
const nodeDir = path.dirname(process.execPath);
|
|
84
|
+
const globalModules = path.join(nodeDir, "..", "lib", "node_modules");
|
|
85
|
+
const vendorBin = path.join(
|
|
86
|
+
globalModules,
|
|
87
|
+
"@openai",
|
|
88
|
+
"codex",
|
|
89
|
+
"node_modules",
|
|
90
|
+
platformPkg,
|
|
91
|
+
"vendor",
|
|
92
|
+
triple,
|
|
93
|
+
"bin",
|
|
94
|
+
binaryName
|
|
95
|
+
);
|
|
96
|
+
if (fs.existsSync(vendorBin) && !candidates.includes(vendorBin)) {
|
|
97
|
+
candidates.push(vendorBin);
|
|
98
|
+
}
|
|
99
|
+
} catch {
|
|
100
|
+
}
|
|
101
|
+
return candidates;
|
|
102
|
+
}
|
|
103
|
+
function resolveNvmBin(name) {
|
|
104
|
+
try {
|
|
105
|
+
const nodeDir = path.dirname(process.execPath);
|
|
106
|
+
const candidate = path.join(nodeDir, name);
|
|
107
|
+
if (fs.existsSync(candidate)) return candidate;
|
|
108
|
+
} catch {
|
|
109
|
+
}
|
|
110
|
+
return void 0;
|
|
111
|
+
}
|
|
42
112
|
export {
|
|
113
|
+
resolveNativeCodexBin,
|
|
114
|
+
resolveNvmBin,
|
|
43
115
|
resolveRealCliBin
|
|
44
116
|
};
|