@stackmemoryai/stackmemory 0.5.64 → 0.5.67
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 +69 -346
- package/bin/claude-sm +1 -1
- package/bin/claude-smd +1 -1
- package/bin/codex-sm +6 -0
- package/bin/codex-smd +1 -1
- package/bin/opencode-sm +1 -1
- package/dist/src/cli/claude-sm.js +162 -25
- package/dist/src/cli/claude-sm.js.map +2 -2
- package/dist/src/cli/commands/ping.js +14 -0
- package/dist/src/cli/commands/ping.js.map +7 -0
- package/dist/src/cli/commands/ralph.js +103 -1
- package/dist/src/cli/commands/ralph.js.map +2 -2
- package/dist/src/cli/commands/retrieval.js +1 -1
- package/dist/src/cli/commands/retrieval.js.map +2 -2
- package/dist/src/cli/commands/skills.js +300 -1
- package/dist/src/cli/commands/skills.js.map +2 -2
- package/dist/src/cli/index.js +362 -20
- package/dist/src/cli/index.js.map +2 -2
- package/dist/src/core/digest/types.js +1 -1
- package/dist/src/core/digest/types.js.map +1 -1
- package/dist/src/core/extensions/provider-adapter.js +2 -5
- package/dist/src/core/extensions/provider-adapter.js.map +2 -2
- package/dist/src/core/retrieval/llm-provider.js +2 -2
- package/dist/src/core/retrieval/llm-provider.js.map +1 -1
- package/dist/src/core/retrieval/types.js +1 -1
- package/dist/src/core/retrieval/types.js.map +1 -1
- package/dist/src/features/sweep/pty-wrapper.js +15 -5
- package/dist/src/features/sweep/pty-wrapper.js.map +2 -2
- package/dist/src/features/workers/tmux-manager.js +71 -0
- package/dist/src/features/workers/tmux-manager.js.map +7 -0
- package/dist/src/features/workers/worker-registry.js +52 -0
- package/dist/src/features/workers/worker-registry.js.map +7 -0
- package/dist/src/integrations/linear/webhook-handler.js +82 -0
- package/dist/src/integrations/linear/webhook-handler.js.map +2 -2
- package/dist/src/integrations/mcp/pending-utils.js +33 -0
- package/dist/src/integrations/mcp/pending-utils.js.map +7 -0
- package/dist/src/integrations/mcp/server.js +571 -1
- package/dist/src/integrations/mcp/server.js.map +2 -2
- package/dist/src/integrations/ralph/patterns/oracle-worker-pattern.js +2 -2
- package/dist/src/integrations/ralph/patterns/oracle-worker-pattern.js.map +2 -2
- package/dist/src/orchestrators/multimodal/constants.js +17 -0
- package/dist/src/orchestrators/multimodal/constants.js.map +7 -0
- package/dist/src/orchestrators/multimodal/harness.js +292 -0
- package/dist/src/orchestrators/multimodal/harness.js.map +7 -0
- package/dist/src/orchestrators/multimodal/providers.js +98 -0
- package/dist/src/orchestrators/multimodal/providers.js.map +7 -0
- package/dist/src/orchestrators/multimodal/types.js +5 -0
- package/dist/src/orchestrators/multimodal/types.js.map +7 -0
- package/dist/src/orchestrators/multimodal/utils.js +25 -0
- package/dist/src/orchestrators/multimodal/utils.js.map +7 -0
- package/dist/src/skills/claude-skills.js +116 -1
- package/dist/src/skills/claude-skills.js.map +2 -2
- package/dist/src/skills/linear-task-runner.js +262 -0
- package/dist/src/skills/linear-task-runner.js.map +7 -0
- package/dist/src/skills/recursive-agent-orchestrator.js +114 -85
- package/dist/src/skills/recursive-agent-orchestrator.js.map +2 -2
- package/dist/src/skills/spec-generator-skill.js +441 -0
- package/dist/src/skills/spec-generator-skill.js.map +7 -0
- package/package.json +14 -9
- package/scripts/claude-code-wrapper.sh +18 -30
- package/scripts/demos/ralph-integration-demo.ts +14 -13
- package/scripts/demos/trace-demo.ts +7 -21
- package/scripts/demos/trace-test.ts +20 -8
- package/scripts/install-claude-hooks.sh +2 -2
- package/scripts/verify-dist.cjs +83 -0
- package/templates/claude-hooks/post-edit-sweep.js +7 -10
|
@@ -0,0 +1,262 @@
|
|
|
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 { logger } from "../core/monitoring/logger.js";
|
|
6
|
+
import * as fs from "fs";
|
|
7
|
+
import * as path from "path";
|
|
8
|
+
const PROMPT_PLAN_PATH = "docs/specs/PROMPT_PLAN.md";
|
|
9
|
+
class LinearTaskRunner {
|
|
10
|
+
constructor(taskManager, rlmOrchestrator, context, specSkill) {
|
|
11
|
+
this.taskManager = taskManager;
|
|
12
|
+
this.rlmOrchestrator = rlmOrchestrator;
|
|
13
|
+
this.context = context;
|
|
14
|
+
this.specSkill = specSkill;
|
|
15
|
+
}
|
|
16
|
+
/** Pull next task from Linear, execute via RLM, update status */
|
|
17
|
+
async runNext(opts) {
|
|
18
|
+
const tasks = this.getFilteredTasks(opts);
|
|
19
|
+
if (tasks.length === 0) {
|
|
20
|
+
return {
|
|
21
|
+
success: true,
|
|
22
|
+
message: "No pending tasks found",
|
|
23
|
+
data: { tasksAvailable: 0 }
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
const task = tasks[0];
|
|
27
|
+
return this.runTask(task.id, opts);
|
|
28
|
+
}
|
|
29
|
+
/** Run all active tasks iteratively */
|
|
30
|
+
async runAll(opts) {
|
|
31
|
+
const startTime = Date.now();
|
|
32
|
+
const tasks = this.getFilteredTasks(opts);
|
|
33
|
+
if (tasks.length === 0) {
|
|
34
|
+
return {
|
|
35
|
+
success: true,
|
|
36
|
+
message: "No pending tasks to execute",
|
|
37
|
+
data: { tasksAvailable: 0 }
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
if (opts?.dryRun) {
|
|
41
|
+
return this.preview();
|
|
42
|
+
}
|
|
43
|
+
const summary = {
|
|
44
|
+
completed: [],
|
|
45
|
+
failed: [],
|
|
46
|
+
skipped: [],
|
|
47
|
+
totalTokens: 0,
|
|
48
|
+
totalCost: 0,
|
|
49
|
+
duration: 0
|
|
50
|
+
};
|
|
51
|
+
for (const task of tasks) {
|
|
52
|
+
try {
|
|
53
|
+
const result = await this.executeTask(task);
|
|
54
|
+
if (result.success) {
|
|
55
|
+
summary.completed.push(task.id);
|
|
56
|
+
const data = result.data;
|
|
57
|
+
summary.totalTokens += data?.totalTokens || 0;
|
|
58
|
+
summary.totalCost += data?.totalCost || 0;
|
|
59
|
+
await this.autoUpdatePromptPlan(task);
|
|
60
|
+
} else {
|
|
61
|
+
summary.failed.push({
|
|
62
|
+
taskId: task.id,
|
|
63
|
+
error: result.message
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
await this.syncSafe();
|
|
67
|
+
} catch (error) {
|
|
68
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
69
|
+
summary.failed.push({ taskId: task.id, error: msg });
|
|
70
|
+
logger.error("Task execution failed", { taskId: task.id, error: msg });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
summary.duration = Date.now() - startTime;
|
|
74
|
+
return {
|
|
75
|
+
success: summary.failed.length === 0,
|
|
76
|
+
message: `Completed ${summary.completed.length}/${tasks.length} tasks`,
|
|
77
|
+
data: summary,
|
|
78
|
+
action: `Executed ${summary.completed.length} tasks, ${summary.failed.length} failures`
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/** Execute a specific Linear task by ID */
|
|
82
|
+
async runTask(taskId, opts) {
|
|
83
|
+
const task = this.taskManager.getTask(taskId);
|
|
84
|
+
if (!task) {
|
|
85
|
+
return { success: false, message: `Task not found: ${taskId}` };
|
|
86
|
+
}
|
|
87
|
+
if (opts?.dryRun) {
|
|
88
|
+
return this.previewTask(task);
|
|
89
|
+
}
|
|
90
|
+
const result = await this.executeTask(task);
|
|
91
|
+
if (result.success) {
|
|
92
|
+
await this.autoUpdatePromptPlan(task);
|
|
93
|
+
await this.syncSafe();
|
|
94
|
+
}
|
|
95
|
+
return result;
|
|
96
|
+
}
|
|
97
|
+
/** Show execution plan without running */
|
|
98
|
+
async preview(taskId) {
|
|
99
|
+
if (taskId) {
|
|
100
|
+
const task = this.taskManager.getTask(taskId);
|
|
101
|
+
if (!task) {
|
|
102
|
+
return { success: false, message: `Task not found: ${taskId}` };
|
|
103
|
+
}
|
|
104
|
+
return this.previewTask(task);
|
|
105
|
+
}
|
|
106
|
+
const tasks = this.getFilteredTasks();
|
|
107
|
+
const plan = tasks.map((t, i) => ({
|
|
108
|
+
order: i + 1,
|
|
109
|
+
id: t.id,
|
|
110
|
+
identifier: t.externalIdentifier || t.id,
|
|
111
|
+
title: t.title,
|
|
112
|
+
priority: t.priority || "medium",
|
|
113
|
+
status: t.status,
|
|
114
|
+
tags: t.tags
|
|
115
|
+
}));
|
|
116
|
+
return {
|
|
117
|
+
success: true,
|
|
118
|
+
message: `${plan.length} tasks in execution queue`,
|
|
119
|
+
data: { plan, totalTasks: plan.length }
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
// --- Private helpers ---
|
|
123
|
+
async executeTask(task) {
|
|
124
|
+
const taskLabel = task.externalIdentifier || task.id;
|
|
125
|
+
logger.info("Starting task execution", {
|
|
126
|
+
taskId: task.id,
|
|
127
|
+
title: task.title
|
|
128
|
+
});
|
|
129
|
+
try {
|
|
130
|
+
this.taskManager.updateTaskStatus(
|
|
131
|
+
task.id,
|
|
132
|
+
"in_progress",
|
|
133
|
+
"LinearTaskRunner: starting execution"
|
|
134
|
+
);
|
|
135
|
+
} catch {
|
|
136
|
+
}
|
|
137
|
+
try {
|
|
138
|
+
const result = await this.rlmOrchestrator.execute(
|
|
139
|
+
task.description || task.title,
|
|
140
|
+
{
|
|
141
|
+
linearTaskId: task.id,
|
|
142
|
+
linearIdentifier: task.externalIdentifier,
|
|
143
|
+
title: task.title,
|
|
144
|
+
tags: task.tags
|
|
145
|
+
}
|
|
146
|
+
);
|
|
147
|
+
if (result.success) {
|
|
148
|
+
this.taskManager.updateTaskStatus(
|
|
149
|
+
task.id,
|
|
150
|
+
"done",
|
|
151
|
+
`Completed via RLM: ${result.improvements.length} improvements, ${result.testsGenerated} tests`
|
|
152
|
+
);
|
|
153
|
+
return {
|
|
154
|
+
success: true,
|
|
155
|
+
message: `${taskLabel}: completed`,
|
|
156
|
+
data: {
|
|
157
|
+
taskId: task.id,
|
|
158
|
+
duration: result.duration,
|
|
159
|
+
totalTokens: result.totalTokens,
|
|
160
|
+
totalCost: result.totalCost,
|
|
161
|
+
testsGenerated: result.testsGenerated,
|
|
162
|
+
improvements: result.improvements.length,
|
|
163
|
+
issuesFound: result.issuesFound,
|
|
164
|
+
issuesFixed: result.issuesFixed
|
|
165
|
+
},
|
|
166
|
+
action: `Executed ${taskLabel} via RLM`
|
|
167
|
+
};
|
|
168
|
+
} else {
|
|
169
|
+
logger.warn("Task execution failed", {
|
|
170
|
+
taskId: task.id,
|
|
171
|
+
rootNode: result.rootNode
|
|
172
|
+
});
|
|
173
|
+
return {
|
|
174
|
+
success: false,
|
|
175
|
+
message: `${taskLabel}: execution failed`,
|
|
176
|
+
data: {
|
|
177
|
+
taskId: task.id,
|
|
178
|
+
duration: result.duration,
|
|
179
|
+
totalTokens: result.totalTokens
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
} catch (error) {
|
|
184
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
185
|
+
logger.error("Task execution threw", { taskId: task.id, error: msg });
|
|
186
|
+
return {
|
|
187
|
+
success: false,
|
|
188
|
+
message: `${taskLabel}: ${msg}`,
|
|
189
|
+
data: { taskId: task.id }
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
getFilteredTasks(opts) {
|
|
194
|
+
const tasks = this.taskManager.getTasksByStatus("todo");
|
|
195
|
+
let filtered = tasks;
|
|
196
|
+
if (opts?.priority) {
|
|
197
|
+
filtered = filtered.filter((t) => t.priority === opts.priority);
|
|
198
|
+
}
|
|
199
|
+
if (opts?.tag) {
|
|
200
|
+
const tag = opts.tag;
|
|
201
|
+
filtered = filtered.filter((t) => t.tags.includes(tag));
|
|
202
|
+
}
|
|
203
|
+
const priorityOrder = {
|
|
204
|
+
urgent: 0,
|
|
205
|
+
high: 1,
|
|
206
|
+
medium: 2,
|
|
207
|
+
low: 3
|
|
208
|
+
};
|
|
209
|
+
return filtered.sort(
|
|
210
|
+
(a, b) => (priorityOrder[a.priority || "medium"] || 2) - (priorityOrder[b.priority || "medium"] || 2)
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
previewTask(task) {
|
|
214
|
+
return {
|
|
215
|
+
success: true,
|
|
216
|
+
message: `Preview: ${task.externalIdentifier || task.id}`,
|
|
217
|
+
data: {
|
|
218
|
+
id: task.id,
|
|
219
|
+
identifier: task.externalIdentifier,
|
|
220
|
+
title: task.title,
|
|
221
|
+
description: task.description?.slice(0, 200),
|
|
222
|
+
priority: task.priority,
|
|
223
|
+
status: task.status,
|
|
224
|
+
tags: task.tags,
|
|
225
|
+
willExecuteVia: "RLM Orchestrator",
|
|
226
|
+
estimatedSteps: [
|
|
227
|
+
"Planning agent decomposes task",
|
|
228
|
+
"Code/Test/Review subagents execute",
|
|
229
|
+
"Multi-stage review",
|
|
230
|
+
"Update Linear status to done"
|
|
231
|
+
]
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
/** Auto-update PROMPT_PLAN checkboxes when a task completes */
|
|
236
|
+
async autoUpdatePromptPlan(task) {
|
|
237
|
+
if (!this.specSkill) return;
|
|
238
|
+
const promptPlanPath = path.join(process.cwd(), PROMPT_PLAN_PATH);
|
|
239
|
+
if (!fs.existsSync(promptPlanPath)) return;
|
|
240
|
+
try {
|
|
241
|
+
await this.specSkill.update(PROMPT_PLAN_PATH, task.title);
|
|
242
|
+
logger.info("Auto-updated PROMPT_PLAN checkbox", {
|
|
243
|
+
taskId: task.id,
|
|
244
|
+
title: task.title
|
|
245
|
+
});
|
|
246
|
+
} catch {
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
/** Safe Linear sync — log errors but don't throw */
|
|
250
|
+
async syncSafe() {
|
|
251
|
+
try {
|
|
252
|
+
await this.taskManager.syncWithLinear();
|
|
253
|
+
} catch (error) {
|
|
254
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
255
|
+
logger.warn("Linear sync failed (non-fatal)", { error: msg });
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
export {
|
|
260
|
+
LinearTaskRunner
|
|
261
|
+
};
|
|
262
|
+
//# sourceMappingURL=linear-task-runner.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../../src/skills/linear-task-runner.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Linear Task Runner\n * Bridges LinearTaskManager \u2192 RLM Orchestrator \u2192 Linear status updates.\n * Stateless: pull \u2192 execute \u2192 update. Ralph loop handles retries/learning.\n */\n\nimport type { SkillContext, SkillResult } from './claude-skills.js';\nimport type { RecursiveAgentOrchestrator } from './recursive-agent-orchestrator.js';\nimport type { SpecGeneratorSkill } from './spec-generator-skill.js';\nimport type { Task } from '../types/task.js';\nimport { logger } from '../core/monitoring/logger.js';\nimport * as fs from 'fs';\nimport * as path from 'path';\n\n// Dynamic import type for LinearTaskManager (loaded lazily)\ntype LinearTaskManagerType = {\n getActiveTasks(): Task[];\n getTask(id: string): Task | undefined;\n updateTaskStatus(id: string, status: string, reason?: string): void;\n syncWithLinear(): Promise<{ synced: number; errors: string[] }>;\n getTasksByStatus(status: string): Task[];\n};\n\ninterface RunOptions {\n priority?: string;\n tag?: string;\n dryRun?: boolean;\n maxConcurrent?: number;\n}\n\ninterface RunSummary {\n completed: string[];\n failed: Array<{ taskId: string; error: string }>;\n skipped: string[];\n totalTokens: number;\n totalCost: number;\n duration: number;\n}\n\nconst PROMPT_PLAN_PATH = 'docs/specs/PROMPT_PLAN.md';\n\nexport class LinearTaskRunner {\n constructor(\n private taskManager: LinearTaskManagerType,\n private rlmOrchestrator: RecursiveAgentOrchestrator,\n private context: SkillContext,\n private specSkill?: SpecGeneratorSkill\n ) {}\n\n /** Pull next task from Linear, execute via RLM, update status */\n async runNext(opts?: RunOptions): Promise<SkillResult> {\n const tasks = this.getFilteredTasks(opts);\n\n if (tasks.length === 0) {\n return {\n success: true,\n message: 'No pending tasks found',\n data: { tasksAvailable: 0 },\n };\n }\n\n const task = tasks[0];\n return this.runTask(task.id, opts);\n }\n\n /** Run all active tasks iteratively */\n async runAll(opts?: RunOptions): Promise<SkillResult> {\n const startTime = Date.now();\n const tasks = this.getFilteredTasks(opts);\n\n if (tasks.length === 0) {\n return {\n success: true,\n message: 'No pending tasks to execute',\n data: { tasksAvailable: 0 },\n };\n }\n\n if (opts?.dryRun) {\n return this.preview();\n }\n\n const summary: RunSummary = {\n completed: [],\n failed: [],\n skipped: [],\n totalTokens: 0,\n totalCost: 0,\n duration: 0,\n };\n\n // Sequential by default\n for (const task of tasks) {\n try {\n const result = await this.executeTask(task);\n\n if (result.success) {\n summary.completed.push(task.id);\n const data = result.data as Record<string, unknown> | undefined;\n summary.totalTokens += (data?.totalTokens as number) || 0;\n summary.totalCost += (data?.totalCost as number) || 0;\n\n // Auto-update PROMPT_PLAN checkboxes if spec skill available\n await this.autoUpdatePromptPlan(task);\n } else {\n summary.failed.push({\n taskId: task.id,\n error: result.message,\n });\n }\n\n // Sync to Linear after each task\n await this.syncSafe();\n } catch (error: unknown) {\n const msg = error instanceof Error ? error.message : String(error);\n summary.failed.push({ taskId: task.id, error: msg });\n logger.error('Task execution failed', { taskId: task.id, error: msg });\n }\n }\n\n summary.duration = Date.now() - startTime;\n\n return {\n success: summary.failed.length === 0,\n message: `Completed ${summary.completed.length}/${tasks.length} tasks`,\n data: summary,\n action: `Executed ${summary.completed.length} tasks, ${summary.failed.length} failures`,\n };\n }\n\n /** Execute a specific Linear task by ID */\n async runTask(taskId: string, opts?: RunOptions): Promise<SkillResult> {\n const task = this.taskManager.getTask(taskId);\n\n if (!task) {\n return { success: false, message: `Task not found: ${taskId}` };\n }\n\n if (opts?.dryRun) {\n return this.previewTask(task);\n }\n\n const result = await this.executeTask(task);\n\n // Auto-update PROMPT_PLAN if successful\n if (result.success) {\n await this.autoUpdatePromptPlan(task);\n await this.syncSafe();\n }\n\n return result;\n }\n\n /** Show execution plan without running */\n async preview(taskId?: string): Promise<SkillResult> {\n if (taskId) {\n const task = this.taskManager.getTask(taskId);\n if (!task) {\n return { success: false, message: `Task not found: ${taskId}` };\n }\n return this.previewTask(task);\n }\n\n const tasks = this.getFilteredTasks();\n const plan = tasks.map((t, i) => ({\n order: i + 1,\n id: t.id,\n identifier: t.externalIdentifier || t.id,\n title: t.title,\n priority: t.priority || 'medium',\n status: t.status,\n tags: t.tags,\n }));\n\n return {\n success: true,\n message: `${plan.length} tasks in execution queue`,\n data: { plan, totalTasks: plan.length },\n };\n }\n\n // --- Private helpers ---\n\n private async executeTask(task: Task): Promise<SkillResult> {\n const taskLabel = task.externalIdentifier || task.id;\n\n logger.info('Starting task execution', {\n taskId: task.id,\n title: task.title,\n });\n\n // 1. Mark as in_progress\n try {\n this.taskManager.updateTaskStatus(\n task.id,\n 'in_progress',\n 'LinearTaskRunner: starting execution'\n );\n } catch {\n // Non-fatal \u2014 task may already be in_progress\n }\n\n // 2. Execute via RLM orchestrator\n try {\n const result = await this.rlmOrchestrator.execute(\n task.description || task.title,\n {\n linearTaskId: task.id,\n linearIdentifier: task.externalIdentifier,\n title: task.title,\n tags: task.tags,\n }\n );\n\n if (result.success) {\n // 3. Mark as done\n this.taskManager.updateTaskStatus(\n task.id,\n 'done',\n `Completed via RLM: ${result.improvements.length} improvements, ${result.testsGenerated} tests`\n );\n\n return {\n success: true,\n message: `${taskLabel}: completed`,\n data: {\n taskId: task.id,\n duration: result.duration,\n totalTokens: result.totalTokens,\n totalCost: result.totalCost,\n testsGenerated: result.testsGenerated,\n improvements: result.improvements.length,\n issuesFound: result.issuesFound,\n issuesFixed: result.issuesFixed,\n },\n action: `Executed ${taskLabel} via RLM`,\n };\n } else {\n // Leave as in_progress on failure \u2014 don't regress to todo\n logger.warn('Task execution failed', {\n taskId: task.id,\n rootNode: result.rootNode,\n });\n\n return {\n success: false,\n message: `${taskLabel}: execution failed`,\n data: {\n taskId: task.id,\n duration: result.duration,\n totalTokens: result.totalTokens,\n },\n };\n }\n } catch (error: unknown) {\n const msg = error instanceof Error ? error.message : String(error);\n logger.error('Task execution threw', { taskId: task.id, error: msg });\n\n return {\n success: false,\n message: `${taskLabel}: ${msg}`,\n data: { taskId: task.id },\n };\n }\n }\n\n private getFilteredTasks(opts?: RunOptions): Task[] {\n const tasks = this.taskManager.getTasksByStatus('todo');\n\n let filtered = tasks;\n\n // Filter by priority\n if (opts?.priority) {\n filtered = filtered.filter((t) => t.priority === opts.priority);\n }\n\n // Filter by tag\n if (opts?.tag) {\n const tag = opts.tag;\n filtered = filtered.filter((t) => t.tags.includes(tag));\n }\n\n // Sort: urgent > high > medium > low\n const priorityOrder: Record<string, number> = {\n urgent: 0,\n high: 1,\n medium: 2,\n low: 3,\n };\n\n return filtered.sort(\n (a, b) =>\n (priorityOrder[a.priority || 'medium'] || 2) -\n (priorityOrder[b.priority || 'medium'] || 2)\n );\n }\n\n private previewTask(task: Task): SkillResult {\n return {\n success: true,\n message: `Preview: ${task.externalIdentifier || task.id}`,\n data: {\n id: task.id,\n identifier: task.externalIdentifier,\n title: task.title,\n description: task.description?.slice(0, 200),\n priority: task.priority,\n status: task.status,\n tags: task.tags,\n willExecuteVia: 'RLM Orchestrator',\n estimatedSteps: [\n 'Planning agent decomposes task',\n 'Code/Test/Review subagents execute',\n 'Multi-stage review',\n 'Update Linear status to done',\n ],\n },\n };\n }\n\n /** Auto-update PROMPT_PLAN checkboxes when a task completes */\n private async autoUpdatePromptPlan(task: Task): Promise<void> {\n if (!this.specSkill) return;\n\n const promptPlanPath = path.join(process.cwd(), PROMPT_PLAN_PATH);\n if (!fs.existsSync(promptPlanPath)) return;\n\n try {\n // Try to match task title to a checkbox in PROMPT_PLAN\n await this.specSkill.update(PROMPT_PLAN_PATH, task.title);\n logger.info('Auto-updated PROMPT_PLAN checkbox', {\n taskId: task.id,\n title: task.title,\n });\n } catch {\n // Non-fatal \u2014 task title may not match any checkbox\n }\n }\n\n /** Safe Linear sync \u2014 log errors but don't throw */\n private async syncSafe(): Promise<void> {\n try {\n await this.taskManager.syncWithLinear();\n } catch (error: unknown) {\n const msg = error instanceof Error ? error.message : String(error);\n logger.warn('Linear sync failed (non-fatal)', { error: msg });\n }\n }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -2,6 +2,8 @@ import { fileURLToPath as __fileURLToPath } from 'url';
|
|
|
2
2
|
import { dirname as __pathDirname } from 'path';
|
|
3
3
|
const __filename = __fileURLToPath(import.meta.url);
|
|
4
4
|
const __dirname = __pathDirname(__filename);
|
|
5
|
+
import * as fs from "fs";
|
|
6
|
+
import * as path from "path";
|
|
5
7
|
import { logger } from "../core/monitoring/logger.js";
|
|
6
8
|
import { ParallelExecutor } from "../core/execution/parallel-executor.js";
|
|
7
9
|
import { RecursiveContextManager } from "../core/context/recursive-context-manager.js";
|
|
@@ -61,42 +63,46 @@ class RecursiveAgentOrchestrator {
|
|
|
61
63
|
const configs = /* @__PURE__ */ new Map();
|
|
62
64
|
configs.set("planning", {
|
|
63
65
|
type: "planning",
|
|
64
|
-
model: "claude-
|
|
66
|
+
model: "claude-sonnet-4-5-20250929",
|
|
65
67
|
maxTokens: 2e4,
|
|
66
68
|
temperature: 0.3,
|
|
67
|
-
systemPrompt: `You
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
systemPrompt: `You decompose tasks into parallel/sequential subtask trees.
|
|
70
|
+
Output JSON: { subtasks: [{ id, description, agent, dependencies[], parallel: bool }] }
|
|
71
|
+
Rules:
|
|
72
|
+
- Maximize parallelism \u2014 independent tasks run concurrently
|
|
73
|
+
- Each subtask names its agent type: planning, code, testing, linting, review, improve, context, publish
|
|
74
|
+
- Include failure modes and rollback steps for risky operations
|
|
75
|
+
- Keep subtask descriptions actionable (verb + object + constraint)`,
|
|
72
76
|
capabilities: ["decompose", "analyze", "strategize", "prioritize"]
|
|
73
77
|
});
|
|
74
78
|
configs.set("code", {
|
|
75
79
|
type: "code",
|
|
76
|
-
model: "claude-
|
|
80
|
+
model: "claude-sonnet-4-5-20250929",
|
|
77
81
|
maxTokens: 3e4,
|
|
78
82
|
temperature: 0.2,
|
|
79
|
-
systemPrompt: `You
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
83
|
+
systemPrompt: `You implement code changes. Read existing code before modifying.
|
|
84
|
+
Output JSON: { success: bool, filesChanged: string[], changes: string[], notes: string[] }
|
|
85
|
+
Rules:
|
|
86
|
+
- Follow existing project conventions (naming, imports, patterns)
|
|
87
|
+
- Add .js extensions to relative TypeScript imports (ESM)
|
|
88
|
+
- Return undefined over throwing; log+continue over crash
|
|
89
|
+
- No emojis, no unnecessary comments, functions under 20 lines
|
|
90
|
+
- Validate inputs at system boundaries only`,
|
|
84
91
|
capabilities: ["implement", "refactor", "optimize", "document"]
|
|
85
92
|
});
|
|
86
93
|
configs.set("testing", {
|
|
87
94
|
type: "testing",
|
|
88
|
-
model: "claude-
|
|
89
|
-
// High quality for test generation
|
|
95
|
+
model: "claude-sonnet-4-5-20250929",
|
|
90
96
|
maxTokens: 25e3,
|
|
91
97
|
temperature: 0.1,
|
|
92
|
-
systemPrompt: `You
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
98
|
+
systemPrompt: `You generate and run tests using the project's test framework.
|
|
99
|
+
Output JSON: { success: bool, tests: [{ name, type, file }], coverage: string, notes: string[] }
|
|
100
|
+
Rules:
|
|
101
|
+
- Use vitest (describe/it/expect) \u2014 check existing tests for patterns
|
|
102
|
+
- Prioritize: critical paths > edge cases > happy paths
|
|
103
|
+
- Each test should assert meaningful behavior, not implementation details
|
|
104
|
+
- Use parameterized tests (it.each) to consolidate similar cases
|
|
105
|
+
- Run tests after writing: npm run test:run`,
|
|
100
106
|
capabilities: [
|
|
101
107
|
"generate-tests",
|
|
102
108
|
"validate",
|
|
@@ -106,33 +112,31 @@ class RecursiveAgentOrchestrator {
|
|
|
106
112
|
});
|
|
107
113
|
configs.set("linting", {
|
|
108
114
|
type: "linting",
|
|
109
|
-
model: "claude-
|
|
115
|
+
model: "claude-haiku-4-5-20251001",
|
|
110
116
|
maxTokens: 15e3,
|
|
111
117
|
temperature: 0,
|
|
112
|
-
systemPrompt: `You
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
Provide actionable fixes for all issues found.`,
|
|
118
|
+
systemPrompt: `You run lint checks and fix issues.
|
|
119
|
+
Output JSON: { success: bool, issuesFound: number, issuesFixed: number, remaining: string[] }
|
|
120
|
+
Rules:
|
|
121
|
+
- Run: npm run lint (ESLint + Prettier)
|
|
122
|
+
- Auto-fix: npm run lint:fix
|
|
123
|
+
- ESM imports require .js extension on relative paths
|
|
124
|
+
- Report unfixable issues with file:line format`,
|
|
120
125
|
capabilities: ["lint", "format", "type-check", "security-scan"]
|
|
121
126
|
});
|
|
122
127
|
configs.set("review", {
|
|
123
128
|
type: "review",
|
|
124
|
-
model: "claude-
|
|
129
|
+
model: "claude-sonnet-4-5-20250929",
|
|
125
130
|
maxTokens: 25e3,
|
|
126
131
|
temperature: 0.2,
|
|
127
|
-
systemPrompt: `You
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
Rate quality on a 0-1 scale.`,
|
|
132
|
+
systemPrompt: `You review code changes for quality, security, and correctness.
|
|
133
|
+
Output JSON: { qualityScore: 0-1, issues: [{ severity, file, line, description, suggestion }], approved: bool }
|
|
134
|
+
Rules:
|
|
135
|
+
- Score 0.85+ = approved, below = needs improvement
|
|
136
|
+
- Flag: SQL injection, XSS, secret exposure, command injection
|
|
137
|
+
- Flag: functions > 20 lines, cyclomatic complexity > 5
|
|
138
|
+
- Flag: missing error handling at system boundaries
|
|
139
|
+
- Suggest specific fixes, not vague improvements`,
|
|
136
140
|
capabilities: [
|
|
137
141
|
"review",
|
|
138
142
|
"critique",
|
|
@@ -142,46 +146,44 @@ class RecursiveAgentOrchestrator {
|
|
|
142
146
|
});
|
|
143
147
|
configs.set("improve", {
|
|
144
148
|
type: "improve",
|
|
145
|
-
model: "claude-
|
|
149
|
+
model: "claude-sonnet-4-5-20250929",
|
|
146
150
|
maxTokens: 3e4,
|
|
147
151
|
temperature: 0.3,
|
|
148
|
-
systemPrompt: `You
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
Ensure all improvements maintain backward compatibility.`,
|
|
152
|
+
systemPrompt: `You implement review feedback and improve code quality.
|
|
153
|
+
Output JSON: { success: bool, improvements: string[], filesChanged: string[] }
|
|
154
|
+
Rules:
|
|
155
|
+
- Apply only the specific improvements requested \u2014 no scope creep
|
|
156
|
+
- Maintain backward compatibility unless explicitly breaking
|
|
157
|
+
- Run lint + tests after changes to verify nothing regressed
|
|
158
|
+
- Keep changes minimal and focused`,
|
|
156
159
|
capabilities: ["enhance", "refactor", "optimize", "polish"]
|
|
157
160
|
});
|
|
158
161
|
configs.set("context", {
|
|
159
162
|
type: "context",
|
|
160
|
-
model: "claude-
|
|
163
|
+
model: "claude-haiku-4-5-20251001",
|
|
161
164
|
maxTokens: 1e4,
|
|
162
165
|
temperature: 0,
|
|
163
|
-
systemPrompt: `You
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
166
|
+
systemPrompt: `You retrieve relevant context from the codebase and specs.
|
|
167
|
+
Output JSON: { context: string, sources: string[], relevanceScore: 0-1 }
|
|
168
|
+
Rules:
|
|
169
|
+
- Check docs/specs/ for ONE_PAGER.md, DEV_SPEC.md, PROMPT_PLAN.md
|
|
170
|
+
- Check CLAUDE.md and AGENTS.md for project conventions
|
|
171
|
+
- Search src/ for relevant implementations
|
|
172
|
+
- Return concise summaries, not full file contents`,
|
|
170
173
|
capabilities: ["search", "retrieve", "summarize", "contextualize"]
|
|
171
174
|
});
|
|
172
175
|
configs.set("publish", {
|
|
173
176
|
type: "publish",
|
|
174
|
-
model: "claude-
|
|
177
|
+
model: "claude-haiku-4-5-20251001",
|
|
175
178
|
maxTokens: 15e3,
|
|
176
179
|
temperature: 0,
|
|
177
|
-
systemPrompt: `You
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
Ensure all release steps are properly sequenced.`,
|
|
180
|
+
systemPrompt: `You handle releases and publishing.
|
|
181
|
+
Output JSON: { success: bool, version: string, actions: string[] }
|
|
182
|
+
Rules:
|
|
183
|
+
- Verify lint + tests + build pass before any publish
|
|
184
|
+
- Follow semver: breaking=major, feature=minor, fix=patch
|
|
185
|
+
- Generate changelog from git log since last tag
|
|
186
|
+
- Never force-push or skip pre-publish hooks`,
|
|
185
187
|
capabilities: ["publish-npm", "github-release", "deploy", "document"]
|
|
186
188
|
});
|
|
187
189
|
return configs;
|
|
@@ -479,23 +481,50 @@ class RecursiveAgentOrchestrator {
|
|
|
479
481
|
node.children.push(testNode);
|
|
480
482
|
}
|
|
481
483
|
injectReviewStages(_node, _stages) {
|
|
484
|
+
}
|
|
485
|
+
loadSpecContext() {
|
|
486
|
+
const specDir = path.join(process.cwd(), "docs", "specs");
|
|
487
|
+
if (!fs.existsSync(specDir)) return "";
|
|
488
|
+
const specFiles = ["ONE_PAGER.md", "DEV_SPEC.md", "PROMPT_PLAN.md"];
|
|
489
|
+
const sections = [];
|
|
490
|
+
for (const file of specFiles) {
|
|
491
|
+
const filePath = path.join(specDir, file);
|
|
492
|
+
if (fs.existsSync(filePath)) {
|
|
493
|
+
const content = fs.readFileSync(filePath, "utf-8");
|
|
494
|
+
const truncated = content.length > 2e3 ? content.slice(0, 2e3) + "\n...[truncated]" : content;
|
|
495
|
+
sections.push(`### ${file}
|
|
496
|
+
${truncated}`);
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
return sections.length > 0 ? `
|
|
500
|
+
## Project Specs
|
|
501
|
+
${sections.join("\n\n")}` : "";
|
|
482
502
|
}
|
|
483
503
|
buildAgentPrompt(node, context) {
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
node.
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
504
|
+
const depResults = node.dependencies.map((id) => {
|
|
505
|
+
const dep = this.activeExecutions.get(id);
|
|
506
|
+
if (!dep?.result) return null;
|
|
507
|
+
return { id, agent: dep.agent, result: dep.result };
|
|
508
|
+
}).filter(Boolean);
|
|
509
|
+
const specContext = node.agent === "planning" || node.agent === "code" ? this.loadSpecContext() : "";
|
|
510
|
+
return [
|
|
511
|
+
`## Task`,
|
|
512
|
+
node.description,
|
|
513
|
+
"",
|
|
514
|
+
`## Agent Role: ${node.agent}`,
|
|
515
|
+
`Config: ${JSON.stringify(this.subagentConfigs.get(node.agent)?.capabilities || [])}`,
|
|
516
|
+
"",
|
|
517
|
+
`## Context`,
|
|
518
|
+
JSON.stringify(context, null, 2),
|
|
519
|
+
"",
|
|
520
|
+
...depResults.length > 0 ? [`## Dependency Results`, JSON.stringify(depResults, null, 2), ""] : [],
|
|
521
|
+
...specContext ? [specContext, ""] : [],
|
|
522
|
+
`## Constraints`,
|
|
523
|
+
`- ESM imports: use .js extensions on relative imports`,
|
|
524
|
+
`- Testing: vitest (not jest)`,
|
|
525
|
+
`- Lint: npm run lint (eslint + prettier)`,
|
|
526
|
+
`- Output structured JSON when possible`
|
|
527
|
+
].join("\n");
|
|
499
528
|
}
|
|
500
529
|
estimateTokens(text) {
|
|
501
530
|
return Math.ceil(text.length / 4);
|
|
@@ -526,9 +555,9 @@ class RecursiveAgentOrchestrator {
|
|
|
526
555
|
}
|
|
527
556
|
calculateNodeCost(tokens, model) {
|
|
528
557
|
const pricing = {
|
|
529
|
-
"claude-
|
|
530
|
-
"claude-
|
|
531
|
-
"claude-
|
|
558
|
+
"claude-sonnet-4-5-20250929": 15,
|
|
559
|
+
"claude-haiku-4-5-20251001": 1,
|
|
560
|
+
"claude-opus-4-6": 75
|
|
532
561
|
};
|
|
533
562
|
return tokens / 1e6 * (pricing[model] || 10);
|
|
534
563
|
}
|