@stackmemoryai/stackmemory 1.3.1 → 1.4.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/dist/src/cli/commands/{symphony.js → orchestrate.js} +44 -13
- package/dist/src/cli/commands/orchestrator.js +773 -0
- package/dist/src/cli/commands/preflight.js +87 -0
- package/dist/src/cli/commands/snapshot.js +89 -0
- package/dist/src/cli/index.js +6 -2
- package/dist/src/core/retrieval/summary-generator.js +2 -14
- package/dist/src/core/utils/fs.js +18 -0
- package/dist/src/core/utils/git.js +91 -0
- package/dist/src/core/utils/text.js +63 -0
- package/dist/src/core/worktree/capture.js +178 -0
- package/dist/src/core/worktree/preflight.js +313 -0
- package/dist/src/integrations/claude-code/subagent-client.js +1 -85
- package/dist/src/integrations/claude-code/task-coordinator.js +9 -4
- package/package.json +1 -1
- package/scripts/git-hooks/post-commit-stackmemory.sh +27 -0
|
@@ -3,13 +3,15 @@ import { dirname as __pathDirname } from 'path';
|
|
|
3
3
|
const __filename = __fileURLToPath(import.meta.url);
|
|
4
4
|
const __dirname = __pathDirname(__filename);
|
|
5
5
|
import { Command } from "commander";
|
|
6
|
+
import { execSync } from "child_process";
|
|
6
7
|
import { existsSync, mkdirSync, writeFileSync } from "fs";
|
|
7
8
|
import { join } from "path";
|
|
8
|
-
import { homedir } from "os";
|
|
9
|
+
import { homedir, tmpdir } from "os";
|
|
9
10
|
import Database from "better-sqlite3";
|
|
10
11
|
import { logger } from "../../core/monitoring/logger.js";
|
|
12
|
+
import { Conductor } from "./orchestrator.js";
|
|
11
13
|
function getGlobalStorePath() {
|
|
12
|
-
const dir = join(homedir(), ".stackmemory", "
|
|
14
|
+
const dir = join(homedir(), ".stackmemory", "conductor");
|
|
13
15
|
if (!existsSync(dir)) {
|
|
14
16
|
mkdirSync(dir, { recursive: true });
|
|
15
17
|
}
|
|
@@ -41,9 +43,9 @@ function getGlobalDb() {
|
|
|
41
43
|
`);
|
|
42
44
|
return db;
|
|
43
45
|
}
|
|
44
|
-
function
|
|
45
|
-
const cmd = new Command("
|
|
46
|
-
cmd.description("
|
|
46
|
+
function createConductorCommands() {
|
|
47
|
+
const cmd = new Command("conductor");
|
|
48
|
+
cmd.description("Conductor \u2014 autonomous agent orchestration via Linear");
|
|
47
49
|
cmd.command("capture").description("Capture workspace context after an agent run").requiredOption("--issue <id>", "Issue identifier (e.g., STA-476)").option("--workspace <path>", "Workspace directory", process.cwd()).option("--attempt <n>", "Attempt number", "1").action(async (options) => {
|
|
48
50
|
const workspace = options.workspace;
|
|
49
51
|
const issueId = options.issue;
|
|
@@ -53,16 +55,20 @@ function createSymphonyCommands() {
|
|
|
53
55
|
let framesJson = "[]";
|
|
54
56
|
let anchorsJson = "[]";
|
|
55
57
|
let eventsJson = "[]";
|
|
58
|
+
let frameCount = 0;
|
|
59
|
+
let anchorCount = 0;
|
|
56
60
|
if (existsSync(dbPath)) {
|
|
57
61
|
try {
|
|
58
62
|
const db = new Database(dbPath, { readonly: true });
|
|
59
63
|
const frames = db.prepare(
|
|
60
64
|
"SELECT frame_id, name, type, digest_text, created_at FROM frames ORDER BY created_at DESC LIMIT 20"
|
|
61
65
|
).all();
|
|
66
|
+
frameCount = frames.length;
|
|
62
67
|
framesJson = JSON.stringify(frames);
|
|
63
68
|
const anchors = db.prepare(
|
|
64
69
|
"SELECT anchor_id, type, text, priority FROM anchors WHERE type IN ('DECISION', 'FACT', 'CONSTRAINT', 'RISK') ORDER BY priority DESC LIMIT 30"
|
|
65
70
|
).all();
|
|
71
|
+
anchorCount = anchors.length;
|
|
66
72
|
anchorsJson = JSON.stringify(anchors);
|
|
67
73
|
const events = db.prepare(
|
|
68
74
|
"SELECT event_type, payload, ts FROM events ORDER BY ts DESC LIMIT 50"
|
|
@@ -79,7 +85,6 @@ function createSymphonyCommands() {
|
|
|
79
85
|
}
|
|
80
86
|
let metadata = { workspace, attempt };
|
|
81
87
|
try {
|
|
82
|
-
const { execSync } = await import("child_process");
|
|
83
88
|
const branch = execSync("git rev-parse --abbrev-ref HEAD", {
|
|
84
89
|
cwd: workspace,
|
|
85
90
|
encoding: "utf8",
|
|
@@ -112,8 +117,6 @@ function createSymphonyCommands() {
|
|
|
112
117
|
JSON.stringify(metadata)
|
|
113
118
|
);
|
|
114
119
|
globalDb.close();
|
|
115
|
-
const frameCount = JSON.parse(framesJson).length;
|
|
116
|
-
const anchorCount = JSON.parse(anchorsJson).length;
|
|
117
120
|
console.log(
|
|
118
121
|
`Captured ${frameCount} frames, ${anchorCount} anchors for ${issueId} (attempt ${attempt})`
|
|
119
122
|
);
|
|
@@ -123,7 +126,7 @@ function createSymphonyCommands() {
|
|
|
123
126
|
const issueId = options.issue;
|
|
124
127
|
const globalDbPath = join(getGlobalStorePath(), "context.db");
|
|
125
128
|
if (!existsSync(globalDbPath)) {
|
|
126
|
-
console.log("No prior
|
|
129
|
+
console.log("No prior orchestrator context found");
|
|
127
130
|
return;
|
|
128
131
|
}
|
|
129
132
|
const globalDb = getGlobalDb();
|
|
@@ -185,7 +188,7 @@ function createSymphonyCommands() {
|
|
|
185
188
|
if (!existsSync(restoreDir)) {
|
|
186
189
|
mkdirSync(restoreDir, { recursive: true });
|
|
187
190
|
}
|
|
188
|
-
const restorePath = join(restoreDir, "
|
|
191
|
+
const restorePath = join(restoreDir, "conductor-context.md");
|
|
189
192
|
writeFileSync(restorePath, lines.join("\n"));
|
|
190
193
|
globalDb.close();
|
|
191
194
|
console.log(
|
|
@@ -226,10 +229,10 @@ function createSymphonyCommands() {
|
|
|
226
229
|
`Archived ${frames.length} frames, ${anchors.length} anchors for ${issueId}`
|
|
227
230
|
);
|
|
228
231
|
});
|
|
229
|
-
cmd.command("search").description("Search across all
|
|
232
|
+
cmd.command("search").description("Search across all orchestrator issue contexts").argument("<query>", "Search query").option("--limit <n>", "Max results", "10").action(async (query, options) => {
|
|
230
233
|
const globalDbPath = join(getGlobalStorePath(), "context.db");
|
|
231
234
|
if (!existsSync(globalDbPath)) {
|
|
232
|
-
console.log("No
|
|
235
|
+
console.log("No orchestrator context database found");
|
|
233
236
|
return;
|
|
234
237
|
}
|
|
235
238
|
const limit = parseInt(options.limit, 10);
|
|
@@ -260,8 +263,36 @@ function createSymphonyCommands() {
|
|
|
260
263
|
}
|
|
261
264
|
globalDb.close();
|
|
262
265
|
});
|
|
266
|
+
cmd.command("start").description("Start the orchestrator daemon").option("--team <id>", "Linear team ID").option(
|
|
267
|
+
"--states <states>",
|
|
268
|
+
"Comma-separated issue states to pick up",
|
|
269
|
+
"Todo"
|
|
270
|
+
).option(
|
|
271
|
+
"--in-progress <state>",
|
|
272
|
+
"State name for in-progress",
|
|
273
|
+
"In Progress"
|
|
274
|
+
).option(
|
|
275
|
+
"--in-review <state>",
|
|
276
|
+
"State name for completed review",
|
|
277
|
+
"In Review"
|
|
278
|
+
).option("--poll <ms>", "Polling interval in milliseconds", "30000").option("--concurrency <n>", "Max concurrent agents", "3").option("--workspace-root <path>", "Workspace root directory").option("--repo <path>", "Git repo root for worktrees", process.cwd()).option("--branch <name>", "Base branch for worktrees", "main").option("--retries <n>", "Max retries per issue", "1").option("--turn-timeout <ms>", "Agent turn timeout in ms", "3600000").action(async (options) => {
|
|
279
|
+
const conductor = new Conductor({
|
|
280
|
+
teamId: options.team,
|
|
281
|
+
activeStates: options.states.split(",").map((s) => s.trim()),
|
|
282
|
+
inProgressState: options.inProgress,
|
|
283
|
+
inReviewState: options.inReview,
|
|
284
|
+
pollIntervalMs: parseInt(options.poll, 10),
|
|
285
|
+
maxConcurrent: parseInt(options.concurrency, 10),
|
|
286
|
+
workspaceRoot: options.workspaceRoot || join(tmpdir(), "conductor_workspaces"),
|
|
287
|
+
repoRoot: options.repo,
|
|
288
|
+
baseBranch: options.branch,
|
|
289
|
+
maxRetries: parseInt(options.retries, 10),
|
|
290
|
+
turnTimeoutMs: parseInt(options.turnTimeout, 10)
|
|
291
|
+
});
|
|
292
|
+
await conductor.start();
|
|
293
|
+
});
|
|
263
294
|
return cmd;
|
|
264
295
|
}
|
|
265
296
|
export {
|
|
266
|
-
|
|
297
|
+
createConductorCommands
|
|
267
298
|
};
|