@stackmemoryai/stackmemory 1.10.5 → 1.12.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/README.md +104 -23
- package/dist/src/cli/claude-sm.js +266 -84
- package/dist/src/cli/codex-sm.js +185 -33
- package/dist/src/cli/commands/bench.js +209 -2
- package/dist/src/cli/commands/cache.js +126 -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/optimize.js +117 -0
- package/dist/src/cli/commands/orchestrate.js +230 -5
- package/dist/src/cli/commands/orchestrator.js +312 -24
- package/dist/src/cli/commands/pack.js +322 -0
- package/dist/src/cli/commands/search.js +40 -1
- package/dist/src/cli/commands/setup.js +177 -7
- package/dist/src/cli/commands/skills.js +10 -1
- package/dist/src/cli/commands/state.js +265 -0
- package/dist/src/cli/gemini-sm.js +19 -29
- package/dist/src/cli/index.js +90 -29
- 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 +44 -0
- package/dist/src/core/cache/content-cache.js +238 -0
- package/dist/src/core/cache/index.js +11 -0
- package/dist/src/core/cache/token-estimator.js +16 -0
- package/dist/src/core/context/frame-database.js +38 -30
- package/dist/src/core/cross-search/cross-project-search.js +269 -0
- package/dist/src/core/{merge → cross-search}/index.js +6 -4
- package/dist/src/core/database/sqlite-adapter.js +0 -83
- package/dist/src/core/extensions/provider-adapter.js +5 -0
- package/dist/src/core/models/model-router.js +22 -2
- package/dist/src/core/monitoring/logger.js +2 -1
- package/dist/src/core/optimization/trace-optimizer.js +413 -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/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 +66 -0
- package/dist/src/core/trace/trace-event-store.js +282 -0
- package/dist/src/core/trace/trace-event.js +4 -0
- package/dist/src/daemon/daemon-config.js +7 -0
- package/dist/src/daemon/services/github-service.js +126 -0
- package/dist/src/daemon/unified-daemon.js +30 -0
- package/dist/src/features/sweep/pty-wrapper.js +13 -5
- package/dist/src/hooks/schemas.js +2 -0
- package/dist/src/integrations/claude-code/subagent-client.js +89 -0
- package/dist/src/integrations/github/pr-state.js +158 -0
- package/dist/src/integrations/linear/client.js +4 -1
- package/dist/src/integrations/mcp/handlers/cross-search-handlers.js +188 -0
- package/dist/src/integrations/mcp/handlers/index.js +40 -59
- package/dist/src/integrations/mcp/server.js +425 -311
- package/dist/src/integrations/mcp/tool-alias-registry.js +370 -0
- package/dist/src/integrations/mcp/tool-definitions.js +98 -229
- package/dist/src/integrations/ralph/context/stackmemory-context-loader.js +3 -40
- package/dist/src/integrations/ralph/learning/pattern-learner.js +1 -20
- package/dist/src/integrations/ralph/swarm/swarm-coordinator.js +0 -2
- package/dist/src/mcp/stackmemory-mcp-server.js +315 -0
- package/dist/src/orchestrators/multimodal/determinism.js +243 -0
- package/dist/src/orchestrators/multimodal/harness.js +147 -77
- package/dist/src/orchestrators/multimodal/providers.js +44 -3
- package/dist/src/utils/hook-installer.js +0 -8
- package/package.json +10 -1
- 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/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/integrations/mcp/handlers/cord-handlers.js +0 -397
- package/dist/src/integrations/mcp/handlers/team-handlers.js +0 -211
- /package/dist/src/core/{merge → cache}/types.js +0 -0
|
@@ -0,0 +1,265 @@
|
|
|
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 {
|
|
8
|
+
canonicalStateStore
|
|
9
|
+
} from "../../core/shared-state/canonical-store.js";
|
|
10
|
+
import {
|
|
11
|
+
getCurrentRepoGitHubInfo,
|
|
12
|
+
refreshCurrentRepoPullRequestState
|
|
13
|
+
} from "../../integrations/github/pr-state.js";
|
|
14
|
+
function parseJsonObject(input) {
|
|
15
|
+
if (!input) {
|
|
16
|
+
return {};
|
|
17
|
+
}
|
|
18
|
+
const parsed = JSON.parse(input);
|
|
19
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
20
|
+
throw new Error("Expected a JSON object");
|
|
21
|
+
}
|
|
22
|
+
return parsed;
|
|
23
|
+
}
|
|
24
|
+
function createStateCommand() {
|
|
25
|
+
const cmd = new Command("state").description(
|
|
26
|
+
"Manage canonical user-scoped shared state across instances and sessions"
|
|
27
|
+
);
|
|
28
|
+
const instance = cmd.command("instance").description("Manage instance state");
|
|
29
|
+
instance.command("upsert").requiredOption("--id <id>", "Instance identifier").requiredOption(
|
|
30
|
+
"--tool <tool>",
|
|
31
|
+
"Tool name (claude|codex|opencode|stackmemory)"
|
|
32
|
+
).option("--session <id>", "Session identifier").option("--project <id>", "Project identifier").option("--project-path <path>", "Project path").option("--branch <branch>", "Git branch").option("--worktree-path <path>", "Worktree path").option("--pid <pid>", "Process id").option("--status <status>", "Status", "active").option("--metadata <json>", "Metadata JSON object").action(async (options) => {
|
|
33
|
+
const record = await canonicalStateStore.upsertInstance({
|
|
34
|
+
instanceId: options.id,
|
|
35
|
+
tool: options.tool,
|
|
36
|
+
sessionId: options.session,
|
|
37
|
+
projectId: options.project,
|
|
38
|
+
projectPath: options.projectPath,
|
|
39
|
+
branch: options.branch,
|
|
40
|
+
worktreePath: options.worktreePath,
|
|
41
|
+
pid: options.pid ? Number(options.pid) : void 0,
|
|
42
|
+
status: options.status,
|
|
43
|
+
metadata: parseJsonObject(options.metadata)
|
|
44
|
+
});
|
|
45
|
+
console.log(JSON.stringify(record, null, 2));
|
|
46
|
+
});
|
|
47
|
+
instance.command("end").requiredOption("--id <id>", "Instance identifier").action(async (options) => {
|
|
48
|
+
await canonicalStateStore.endInstance(options.id);
|
|
49
|
+
console.log(chalk.green(`Ended instance ${options.id}`));
|
|
50
|
+
});
|
|
51
|
+
const session = cmd.command("session").description("Manage session state");
|
|
52
|
+
session.command("upsert").requiredOption("--id <id>", "Session identifier").requiredOption(
|
|
53
|
+
"--tool <tool>",
|
|
54
|
+
"Tool name (claude|codex|opencode|stackmemory)"
|
|
55
|
+
).option("--project <id>", "Project identifier").option("--project-path <path>", "Project path").option("--branch <branch>", "Git branch").option("--instance <id>", "Associated instance identifier").option("--status <status>", "Status", "active").option("--metadata <json>", "Metadata JSON object").action(async (options) => {
|
|
56
|
+
const record = await canonicalStateStore.upsertSession({
|
|
57
|
+
sessionId: options.id,
|
|
58
|
+
tool: options.tool,
|
|
59
|
+
projectId: options.project,
|
|
60
|
+
projectPath: options.projectPath,
|
|
61
|
+
branch: options.branch,
|
|
62
|
+
instanceId: options.instance,
|
|
63
|
+
status: options.status,
|
|
64
|
+
metadata: parseJsonObject(options.metadata)
|
|
65
|
+
});
|
|
66
|
+
console.log(JSON.stringify(record, null, 2));
|
|
67
|
+
});
|
|
68
|
+
session.command("end").requiredOption("--id <id>", "Session identifier").option("--status <status>", "Status", "closed").action(async (options) => {
|
|
69
|
+
await canonicalStateStore.endSession(options.id, options.status);
|
|
70
|
+
console.log(chalk.green(`Ended session ${options.id}`));
|
|
71
|
+
});
|
|
72
|
+
cmd.command("event").description("Append a shared-state event").requiredOption("--type <type>", "Event type").option("--tool <tool>", "Tool name (claude|codex|opencode|stackmemory)").option("--instance <id>", "Instance identifier").option("--session <id>", "Session identifier").option("--project <id>", "Project identifier").option("--project-path <path>", "Project path").option("--branch <branch>", "Git branch").option("--payload <json>", "Payload JSON object").action(async (options) => {
|
|
73
|
+
const event = await canonicalStateStore.appendEvent({
|
|
74
|
+
type: options.type,
|
|
75
|
+
tool: options.tool,
|
|
76
|
+
instanceId: options.instance,
|
|
77
|
+
sessionId: options.session,
|
|
78
|
+
projectId: options.project,
|
|
79
|
+
projectPath: options.projectPath,
|
|
80
|
+
branch: options.branch,
|
|
81
|
+
payload: parseJsonObject(options.payload)
|
|
82
|
+
});
|
|
83
|
+
console.log(JSON.stringify(event, null, 2));
|
|
84
|
+
});
|
|
85
|
+
cmd.command("show").description("Show canonical shared state for a project").option("--project <id>", "Project identifier").option("--project-path <path>", "Project path").option("--limit <count>", "Recent event limit", "10").option("--json", "Emit JSON output").action(async (options) => {
|
|
86
|
+
const summary = await canonicalStateStore.getProjectSummary({
|
|
87
|
+
projectId: options.project,
|
|
88
|
+
projectPath: options.projectPath,
|
|
89
|
+
eventLimit: Number(options.limit)
|
|
90
|
+
});
|
|
91
|
+
if (options.json) {
|
|
92
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
console.log(chalk.bold("Canonical Shared State"));
|
|
96
|
+
console.log(
|
|
97
|
+
` Active sessions: ${summary.activeSessions.length} | Active instances: ${summary.activeInstances.length} | Active claims: ${summary.activeClaims.length}`
|
|
98
|
+
);
|
|
99
|
+
if (summary.projectId) {
|
|
100
|
+
console.log(` Project: ${summary.projectId}`);
|
|
101
|
+
}
|
|
102
|
+
if (summary.activeSessions.length > 0) {
|
|
103
|
+
console.log(chalk.bold("\nSessions"));
|
|
104
|
+
for (const record of summary.activeSessions) {
|
|
105
|
+
console.log(
|
|
106
|
+
` ${record.sessionId.slice(0, 8)} ${record.tool} ${record.branch || ""}`.trim()
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
if (summary.activeInstances.length > 0) {
|
|
111
|
+
console.log(chalk.bold("\nInstances"));
|
|
112
|
+
for (const record of summary.activeInstances) {
|
|
113
|
+
console.log(
|
|
114
|
+
` ${record.instanceId} ${record.tool} ${record.branch || ""}`.trim()
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
if (summary.activeClaims.length > 0) {
|
|
119
|
+
console.log(chalk.bold("\nClaims"));
|
|
120
|
+
for (const claim of summary.activeClaims) {
|
|
121
|
+
const scopes = [
|
|
122
|
+
claim.branch ? `branch:${claim.branch}` : "",
|
|
123
|
+
...claim.paths.map((item) => `path:${item}`)
|
|
124
|
+
].filter(Boolean).join(", ");
|
|
125
|
+
console.log(
|
|
126
|
+
` ${claim.claimId.slice(0, 8)} ${claim.tool} ${scopes || "(no scope)"}`.trim()
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (summary.recentEvents.length > 0) {
|
|
131
|
+
console.log(chalk.bold("\nRecent events"));
|
|
132
|
+
for (const event of summary.recentEvents) {
|
|
133
|
+
console.log(
|
|
134
|
+
` ${event.type} ${new Date(event.timestamp).toISOString()}`
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
const claims = cmd.command("claims").description("Manage shared ownership claims");
|
|
140
|
+
claims.command("claim").requiredOption(
|
|
141
|
+
"--tool <tool>",
|
|
142
|
+
"Tool name (claude|codex|opencode|stackmemory)"
|
|
143
|
+
).option("--session <id>", "Session identifier").option("--instance <id>", "Instance identifier").option("--project <id>", "Project identifier").option("--project-path <path>", "Project path").option("--branch <branch>", "Git branch").option("--path <path...>", "Claimed file or directory path(s)").option("--ttl-ms <ttl>", "Time to live in milliseconds", "86400000").option("--metadata <json>", "Metadata JSON object").option("--json", "Emit JSON output").action(async (options) => {
|
|
144
|
+
const result = await canonicalStateStore.claimPaths({
|
|
145
|
+
tool: options.tool,
|
|
146
|
+
sessionId: options.session,
|
|
147
|
+
instanceId: options.instance,
|
|
148
|
+
projectId: options.project,
|
|
149
|
+
projectPath: options.projectPath,
|
|
150
|
+
branch: options.branch,
|
|
151
|
+
paths: options.path || [],
|
|
152
|
+
ttlMs: Number(options.ttlMs),
|
|
153
|
+
metadata: parseJsonObject(options.metadata)
|
|
154
|
+
});
|
|
155
|
+
if (options.json) {
|
|
156
|
+
console.log(JSON.stringify(result, null, 2));
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
console.log(chalk.green(`Claimed ${result.record.claimId.slice(0, 8)}`));
|
|
160
|
+
if (result.conflicts.length > 0) {
|
|
161
|
+
console.log(chalk.yellow(`Conflicts: ${result.conflicts.length}`));
|
|
162
|
+
for (const conflict of result.conflicts) {
|
|
163
|
+
console.log(
|
|
164
|
+
` ${conflict.claimId.slice(0, 8)} ${conflict.branch || ""} ${conflict.paths.join(", ")}`.trim()
|
|
165
|
+
);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
claims.command("release").option("--claim <id>", "Claim identifier").option("--session <id>", "Session identifier").option("--instance <id>", "Instance identifier").option("--project <id>", "Project identifier").option("--project-path <path>", "Project path").option("--branch <branch>", "Git branch").option("--reason <reason>", "Release reason").action(async (options) => {
|
|
170
|
+
const released = await canonicalStateStore.releaseClaims({
|
|
171
|
+
claimId: options.claim,
|
|
172
|
+
sessionId: options.session,
|
|
173
|
+
instanceId: options.instance,
|
|
174
|
+
projectId: options.project,
|
|
175
|
+
projectPath: options.projectPath,
|
|
176
|
+
branch: options.branch,
|
|
177
|
+
reason: options.reason
|
|
178
|
+
});
|
|
179
|
+
console.log(chalk.green(`Released ${released} claim(s)`));
|
|
180
|
+
});
|
|
181
|
+
claims.command("show").option("--project <id>", "Project identifier").option("--project-path <path>", "Project path").option("--all", "Show released and expired claims too").option("--json", "Emit JSON output").action(async (options) => {
|
|
182
|
+
const records = await canonicalStateStore.listPathClaims({
|
|
183
|
+
projectId: options.project,
|
|
184
|
+
projectPath: options.projectPath,
|
|
185
|
+
activeOnly: !options.all
|
|
186
|
+
});
|
|
187
|
+
if (options.json) {
|
|
188
|
+
console.log(JSON.stringify(records, null, 2));
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
if (records.length === 0) {
|
|
192
|
+
console.log(chalk.yellow("No claims found"));
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
for (const claim of records) {
|
|
196
|
+
const scopes = [
|
|
197
|
+
claim.branch ? `branch:${claim.branch}` : "",
|
|
198
|
+
...claim.paths.map((item) => `path:${item}`)
|
|
199
|
+
].filter(Boolean).join(", ");
|
|
200
|
+
console.log(
|
|
201
|
+
`${claim.claimId.slice(0, 8)} ${claim.status} ${claim.tool} ${scopes || "(no scope)"}`
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
const github = cmd.command("github").description("GitHub projection state");
|
|
206
|
+
github.command("refresh").description("Refresh current repo branch PR state from GitHub CLI").option("--json", "Emit JSON output").action(async (options) => {
|
|
207
|
+
const projection = await refreshCurrentRepoPullRequestState();
|
|
208
|
+
if (!projection) {
|
|
209
|
+
console.log(
|
|
210
|
+
chalk.yellow(
|
|
211
|
+
"No GitHub PR projection available for current repo/branch"
|
|
212
|
+
)
|
|
213
|
+
);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
if (options.json) {
|
|
217
|
+
console.log(JSON.stringify(projection, null, 2));
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
console.log(chalk.green(`Refreshed PR #${projection.prNumber}`));
|
|
221
|
+
console.log(`${projection.state} ${projection.title}`);
|
|
222
|
+
console.log(projection.url);
|
|
223
|
+
});
|
|
224
|
+
github.command("show").description("Show cached current repo branch PR projection").option("--json", "Emit JSON output").action(async (options) => {
|
|
225
|
+
const info = getCurrentRepoGitHubInfo();
|
|
226
|
+
if (!info) {
|
|
227
|
+
console.log(chalk.yellow("Not in a GitHub repository"));
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
const projection = await canonicalStateStore.getGitHubPullRequest({
|
|
231
|
+
repo: info.repo,
|
|
232
|
+
branch: info.branch
|
|
233
|
+
});
|
|
234
|
+
if (!projection) {
|
|
235
|
+
console.log(
|
|
236
|
+
chalk.yellow("No cached GitHub PR projection for current branch")
|
|
237
|
+
);
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
240
|
+
if (options.json) {
|
|
241
|
+
console.log(JSON.stringify(projection, null, 2));
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
console.log(chalk.bold(`PR #${projection.prNumber}`));
|
|
245
|
+
console.log(`${projection.state} ${projection.title}`);
|
|
246
|
+
console.log(`Repo: ${projection.repo}`);
|
|
247
|
+
console.log(
|
|
248
|
+
`Branch: ${projection.headRefName} -> ${projection.baseRefName}`
|
|
249
|
+
);
|
|
250
|
+
if (projection.reviewDecision) {
|
|
251
|
+
console.log(`Review: ${projection.reviewDecision}`);
|
|
252
|
+
}
|
|
253
|
+
if (projection.statusCheckRollup) {
|
|
254
|
+
console.log(`Checks: ${projection.statusCheckRollup}`);
|
|
255
|
+
}
|
|
256
|
+
console.log(`Synced: ${new Date(projection.lastSyncedAt).toISOString()}`);
|
|
257
|
+
console.log(projection.url);
|
|
258
|
+
});
|
|
259
|
+
return cmd;
|
|
260
|
+
}
|
|
261
|
+
var state_default = createStateCommand;
|
|
262
|
+
export {
|
|
263
|
+
createStateCommand,
|
|
264
|
+
state_default as default
|
|
265
|
+
};
|
|
@@ -13,6 +13,7 @@ import { program } from "commander";
|
|
|
13
13
|
import { v4 as uuidv4 } from "uuid";
|
|
14
14
|
import chalk from "chalk";
|
|
15
15
|
import { initializeTracing, trace } from "../core/trace/index.js";
|
|
16
|
+
import { resolveRealCliBin } from "./utils/real-cli-bin.js";
|
|
16
17
|
const DEFAULT_SM_CONFIG = {
|
|
17
18
|
defaultWorktree: false,
|
|
18
19
|
defaultTracing: true
|
|
@@ -125,35 +126,24 @@ class GeminiSM {
|
|
|
125
126
|
}
|
|
126
127
|
}
|
|
127
128
|
resolveGeminiBin() {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
"gemini"
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
"
|
|
145
|
-
|
|
146
|
-
for (const binPath of possiblePaths) {
|
|
147
|
-
if (fs.existsSync(binPath)) {
|
|
148
|
-
return binPath;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
try {
|
|
152
|
-
execSync("which gemini", { stdio: "ignore" });
|
|
153
|
-
return "gemini";
|
|
154
|
-
} catch {
|
|
155
|
-
}
|
|
156
|
-
return null;
|
|
129
|
+
return resolveRealCliBin({
|
|
130
|
+
explicitBin: this.config.geminiBin,
|
|
131
|
+
envBin: process.env["GEMINI_BIN"],
|
|
132
|
+
preferredPaths: [
|
|
133
|
+
path.join(
|
|
134
|
+
os.homedir(),
|
|
135
|
+
".nvm",
|
|
136
|
+
"versions",
|
|
137
|
+
"node",
|
|
138
|
+
"v22.22.0",
|
|
139
|
+
"bin",
|
|
140
|
+
"gemini"
|
|
141
|
+
),
|
|
142
|
+
"/usr/local/bin/gemini",
|
|
143
|
+
"/opt/homebrew/bin/gemini"
|
|
144
|
+
],
|
|
145
|
+
pathCommands: ["gemini"]
|
|
146
|
+
});
|
|
157
147
|
}
|
|
158
148
|
setupWorktree() {
|
|
159
149
|
if (!this.config.useWorktree || !this.isGitRepo()) {
|
package/dist/src/cli/index.js
CHANGED
|
@@ -4,6 +4,9 @@ import { dirname as __pathDirname } from 'path';
|
|
|
4
4
|
const __filename = __fileURLToPath(import.meta.url);
|
|
5
5
|
const __dirname = __pathDirname(__filename);
|
|
6
6
|
process.env["STACKMEMORY_CLI"] = "true";
|
|
7
|
+
if (!process.env["STACKMEMORY_LOG_LEVEL"] && process.argv.includes("--json")) {
|
|
8
|
+
process.env["STACKMEMORY_LOG_LEVEL"] = "ERROR";
|
|
9
|
+
}
|
|
7
10
|
import { config as loadDotenv } from "dotenv";
|
|
8
11
|
loadDotenv({ quiet: true });
|
|
9
12
|
import { initializeTracing, trace } from "../core/trace/index.js";
|
|
@@ -12,7 +15,6 @@ import { program } from "commander";
|
|
|
12
15
|
import { logger } from "../core/monitoring/logger.js";
|
|
13
16
|
import { FrameManager } from "../core/context/index.js";
|
|
14
17
|
import { sessionManager, FrameQueryMode } from "../core/session/index.js";
|
|
15
|
-
import { sharedContextLayer } from "../core/context/shared-context-layer.js";
|
|
16
18
|
import { UpdateChecker } from "../core/utils/update-checker.js";
|
|
17
19
|
import { ProgressTracker } from "../core/monitoring/progress-tracker.js";
|
|
18
20
|
import { registerProjectCommands } from "./commands/projects.js";
|
|
@@ -54,8 +56,9 @@ import { createPingCommand } from "./commands/ping.js";
|
|
|
54
56
|
import { createAuditCommand } from "./commands/audit.js";
|
|
55
57
|
import { createStatsCommand } from "./commands/stats.js";
|
|
56
58
|
import { createBenchCommand } from "./commands/bench.js";
|
|
59
|
+
import { createOptimizeCommand } from "./commands/optimize.js";
|
|
60
|
+
import { createStateCommand } from "./commands/state.js";
|
|
57
61
|
import { createDigestCommands } from "./commands/digest.js";
|
|
58
|
-
import { createTeamCommands } from "./commands/team.js";
|
|
59
62
|
import { createDesiresCommands } from "./commands/desires.js";
|
|
60
63
|
import { createConductorCommands } from "./commands/orchestrate.js";
|
|
61
64
|
import { createPreflightCommand } from "./commands/preflight.js";
|
|
@@ -64,11 +67,18 @@ import { createSnapshotCommand } from "./commands/snapshot.js";
|
|
|
64
67
|
import { createWikiCommand } from "./commands/wiki.js";
|
|
65
68
|
import { createLoopCommand } from "./commands/loop.js";
|
|
66
69
|
import { createSkillCommand } from "./commands/skill.js";
|
|
70
|
+
import { createPackCommand } from "./commands/pack.js";
|
|
71
|
+
import { createCacheCommand } from "./commands/cache.js";
|
|
67
72
|
import chalk from "chalk";
|
|
68
73
|
import * as fs from "fs";
|
|
69
74
|
import * as path from "path";
|
|
70
75
|
import { filterPending } from "../integrations/mcp/pending-utils.js";
|
|
76
|
+
import {
|
|
77
|
+
getCurrentRepoGitHubInfo,
|
|
78
|
+
refreshCurrentRepoPullRequestState
|
|
79
|
+
} from "../integrations/github/pr-state.js";
|
|
71
80
|
import { ProjectManager } from "../core/projects/project-manager.js";
|
|
81
|
+
import { canonicalStateStore } from "../core/shared-state/canonical-store.js";
|
|
72
82
|
import { join } from "path";
|
|
73
83
|
import { existsSync, mkdirSync } from "fs";
|
|
74
84
|
import { createRequire } from "module";
|
|
@@ -105,10 +115,13 @@ async function openDatabase(dbPath) {
|
|
|
105
115
|
function isTestEnv() {
|
|
106
116
|
return process.env["VITEST"] === "true" || process.env["NODE_ENV"] === "test" || process.env["STACKMEMORY_TEST_SKIP_DB"] === "1";
|
|
107
117
|
}
|
|
118
|
+
function collectRepeatedOption(value, previous = []) {
|
|
119
|
+
return [...previous, value];
|
|
120
|
+
}
|
|
108
121
|
UpdateChecker.checkForUpdates(VERSION, true).catch(() => {
|
|
109
122
|
});
|
|
110
123
|
program.name("stackmemory").description(
|
|
111
|
-
"Lossless memory runtime for AI coding tools - organizes context as a call stack instead of linear chat logs, with
|
|
124
|
+
"Lossless memory runtime for AI coding tools - organizes context as a call stack instead of linear chat logs, with infinite retention"
|
|
112
125
|
).version(VERSION);
|
|
113
126
|
program.command("init").description(
|
|
114
127
|
"Initialize StackMemory in current project (zero-config by default)"
|
|
@@ -198,33 +211,24 @@ program.command("status").description("Show current StackMemory status").option(
|
|
|
198
211
|
}
|
|
199
212
|
await UpdateChecker.checkForUpdates(VERSION);
|
|
200
213
|
await sessionManager.initialize();
|
|
201
|
-
await sharedContextLayer.initialize();
|
|
202
214
|
const { initObsidianVault } = await import("../core/storage/obsidian-vault-adapter.js");
|
|
203
215
|
await initObsidianVault();
|
|
204
216
|
const session = await sessionManager.getOrCreateSession({
|
|
205
217
|
projectPath: projectRoot,
|
|
206
218
|
sessionId: options.session
|
|
207
219
|
});
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
);
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
if (contextDiscovery.lastDecisions.length > 0) {
|
|
224
|
-
console.log(
|
|
225
|
-
` Last decision: ${contextDiscovery.lastDecisions[0].decision.slice(0, 60)}`
|
|
226
|
-
);
|
|
227
|
-
}
|
|
220
|
+
const sharedProjectState = await canonicalStateStore.getProjectSummary({
|
|
221
|
+
projectId: session.projectId,
|
|
222
|
+
projectPath: projectRoot,
|
|
223
|
+
eventLimit: 5
|
|
224
|
+
});
|
|
225
|
+
const githubInfo = getCurrentRepoGitHubInfo(projectRoot);
|
|
226
|
+
let githubProjection = githubInfo && await canonicalStateStore.getGitHubPullRequest({
|
|
227
|
+
repo: githubInfo.repo,
|
|
228
|
+
branch: githubInfo.branch
|
|
229
|
+
});
|
|
230
|
+
if (githubInfo && (!githubProjection || Date.now() - githubProjection.lastSyncedAt > 2 * 60 * 1e3)) {
|
|
231
|
+
githubProjection = await refreshCurrentRepoPullRequestState(projectRoot) || githubProjection;
|
|
228
232
|
}
|
|
229
233
|
const db = await openDatabase(dbPath);
|
|
230
234
|
const frameManager = new FrameManager(db, session.projectId);
|
|
@@ -276,6 +280,23 @@ program.command("status").description("Show current StackMemory status").option(
|
|
|
276
280
|
console.log(
|
|
277
281
|
` Cached contexts: ${contextCount.count || 0} (global)`
|
|
278
282
|
);
|
|
283
|
+
console.log(
|
|
284
|
+
` Shared sessions: ${sharedProjectState.activeSessions.length}`
|
|
285
|
+
);
|
|
286
|
+
console.log(
|
|
287
|
+
` Shared instances: ${sharedProjectState.activeInstances.length}`
|
|
288
|
+
);
|
|
289
|
+
console.log(
|
|
290
|
+
` Shared claims: ${sharedProjectState.activeClaims.length}`
|
|
291
|
+
);
|
|
292
|
+
const branchClaim = sharedProjectState.activeClaims.find(
|
|
293
|
+
(claim) => claim.branch && claim.branch === session.branch
|
|
294
|
+
);
|
|
295
|
+
if (branchClaim) {
|
|
296
|
+
console.log(
|
|
297
|
+
` Branch owner: ${branchClaim.tool} ${branchClaim.instanceId || branchClaim.sessionId || branchClaim.claimId.slice(0, 8)}`
|
|
298
|
+
);
|
|
299
|
+
}
|
|
279
300
|
const recentFrames = db.prepare(
|
|
280
301
|
`
|
|
281
302
|
SELECT name, type, state, datetime(created_at, 'unixepoch') as created
|
|
@@ -295,6 +316,22 @@ program.command("status").description("Show current StackMemory status").option(
|
|
|
295
316
|
);
|
|
296
317
|
});
|
|
297
318
|
}
|
|
319
|
+
if (githubProjection) {
|
|
320
|
+
console.log(`
|
|
321
|
+
GitHub PR:`);
|
|
322
|
+
console.log(
|
|
323
|
+
` #${githubProjection.prNumber} ${githubProjection.state} ${githubProjection.title}`
|
|
324
|
+
);
|
|
325
|
+
console.log(
|
|
326
|
+
` ${githubProjection.headRefName} -> ${githubProjection.baseRefName}`
|
|
327
|
+
);
|
|
328
|
+
if (githubProjection.reviewDecision) {
|
|
329
|
+
console.log(` Review: ${githubProjection.reviewDecision}`);
|
|
330
|
+
}
|
|
331
|
+
if (githubProjection.statusCheckRollup) {
|
|
332
|
+
console.log(` Checks: ${githubProjection.statusCheckRollup}`);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
298
335
|
console.log(`
|
|
299
336
|
Current Session:`);
|
|
300
337
|
console.log(` Stack depth: ${stackDepth}`);
|
|
@@ -571,8 +608,9 @@ program.addCommand(createModelCommand());
|
|
|
571
608
|
program.addCommand(createAuditCommand());
|
|
572
609
|
program.addCommand(createStatsCommand());
|
|
573
610
|
program.addCommand(createBenchCommand());
|
|
611
|
+
program.addCommand(createOptimizeCommand());
|
|
612
|
+
program.addCommand(createStateCommand());
|
|
574
613
|
program.addCommand(createDigestCommands());
|
|
575
|
-
program.addCommand(createTeamCommands());
|
|
576
614
|
program.addCommand(createDesiresCommands());
|
|
577
615
|
program.addCommand(createConductorCommands());
|
|
578
616
|
program.addCommand(createPreflightCommand());
|
|
@@ -581,6 +619,8 @@ program.addCommand(createWikiCommand());
|
|
|
581
619
|
program.addCommand(createLoopCommand());
|
|
582
620
|
program.addCommand(createRulesCommand());
|
|
583
621
|
program.addCommand(createSkillCommand());
|
|
622
|
+
program.addCommand(createPackCommand());
|
|
623
|
+
program.addCommand(createCacheCommand());
|
|
584
624
|
registerSetupCommands(program);
|
|
585
625
|
program.command("mm-spike").description(
|
|
586
626
|
"Run multi-agent planning/implementation spike (planner/implementer/critic)"
|
|
@@ -600,7 +640,16 @@ program.command("mm-spike").description(
|
|
|
600
640
|
"--execute",
|
|
601
641
|
"Execute implementer (codex-sm) instead of dry-run",
|
|
602
642
|
false
|
|
603
|
-
).option("--implementer <name>", "codex|claude", "codex").option("--max-iters <n>", "Retry loop iterations", "2").option("--audit-dir <path>", "Persist spike results to directory").option(
|
|
643
|
+
).option("--implementer <name>", "codex|claude", "codex").option("--max-iters <n>", "Retry loop iterations", "2").option("--audit-dir <path>", "Persist spike results to directory").option(
|
|
644
|
+
"--verify <cmd>",
|
|
645
|
+
"Verification command to run after each implementation attempt; repeatable",
|
|
646
|
+
collectRepeatedOption,
|
|
647
|
+
[]
|
|
648
|
+
).option("--record-frame", "Record as real frame with anchors", false).option("--record", "Record plan & critique into StackMemory context", false).option(
|
|
649
|
+
"--deterministic-fixture",
|
|
650
|
+
"Use deterministic fixture planner/critic for replayable smoke runs",
|
|
651
|
+
false
|
|
652
|
+
).option("--json", "Emit single JSON result (UI-friendly)", false).option("--quiet", "Minimal output (default)", true).option("--verbose", "Verbose sectioned output", false).option(
|
|
604
653
|
"--log",
|
|
605
654
|
"Pretty print interaction log (planner/implementer/critic)",
|
|
606
655
|
false
|
|
@@ -619,8 +668,10 @@ program.command("mm-spike").description(
|
|
|
619
668
|
maxIters: parseInt(opts.maxIters),
|
|
620
669
|
dryRun: !opts.execute,
|
|
621
670
|
auditDir: opts.auditDir,
|
|
671
|
+
verificationCommands: opts.verify,
|
|
622
672
|
recordFrame: Boolean(opts.recordFrame),
|
|
623
|
-
record: Boolean(opts.record)
|
|
673
|
+
record: Boolean(opts.record),
|
|
674
|
+
deterministicFixture: Boolean(opts.deterministicFixture)
|
|
624
675
|
}
|
|
625
676
|
);
|
|
626
677
|
if (opts.log) {
|
|
@@ -677,7 +728,15 @@ program.command("build").description(
|
|
|
677
728
|
"--reviewer-model <name>",
|
|
678
729
|
"Claude model for review",
|
|
679
730
|
"claude-sonnet-4-20250514"
|
|
680
|
-
).option("--execute", "Execute implementer (default: true)", true).option("--dry-run", "Skip execution, show commands only").option("--implementer <name>", "codex|claude", "codex").option("--max-iters <n>", "Retry loop iterations", "2").option("--audit-dir <path>", "Persist spike results to directory").option(
|
|
731
|
+
).option("--execute", "Execute implementer (default: true)", true).option("--dry-run", "Skip execution, show commands only").option("--implementer <name>", "codex|claude", "codex").option("--max-iters <n>", "Retry loop iterations", "2").option("--audit-dir <path>", "Persist spike results to directory").option(
|
|
732
|
+
"--verify <cmd>",
|
|
733
|
+
"Verification command to run after each implementation attempt; repeatable",
|
|
734
|
+
collectRepeatedOption,
|
|
735
|
+
[]
|
|
736
|
+
).option("--record-frame", "Record as real frame with anchors").option("--record", "Record plan & critique into StackMemory context").option(
|
|
737
|
+
"--deterministic-fixture",
|
|
738
|
+
"Use deterministic fixture planner/critic for replayable smoke runs"
|
|
739
|
+
).option("--json", "Emit single JSON result (UI-friendly)").option("--quiet", "Minimal output").option("--verbose", "Verbose sectioned output").option("--log", "Pretty print interaction log (default: true)", true).option("-C, --cwd <path>", "Working directory for implementation").action(async (taskArg, opts) => {
|
|
681
740
|
try {
|
|
682
741
|
const task = typeof taskArg === "string" && taskArg.length > 0 ? taskArg : opts.task;
|
|
683
742
|
if (!task) {
|
|
@@ -713,8 +772,10 @@ program.command("build").description(
|
|
|
713
772
|
maxIters: parseInt(opts.maxIters),
|
|
714
773
|
dryRun,
|
|
715
774
|
auditDir: opts.auditDir,
|
|
775
|
+
verificationCommands: opts.verify,
|
|
716
776
|
recordFrame: Boolean(opts.recordFrame),
|
|
717
|
-
record: Boolean(opts.record)
|
|
777
|
+
record: Boolean(opts.record),
|
|
778
|
+
deterministicFixture: Boolean(opts.deterministicFixture)
|
|
718
779
|
}
|
|
719
780
|
);
|
|
720
781
|
if (opts.log) {
|