agileflow 2.95.2 → 2.96.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.
Files changed (81) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/README.md +6 -6
  3. package/lib/api-routes.js +605 -0
  4. package/lib/api-server.js +260 -0
  5. package/lib/claude-cli-bridge.js +221 -0
  6. package/lib/dashboard-protocol.js +541 -0
  7. package/lib/dashboard-server.js +1601 -0
  8. package/lib/drivers/claude-driver.ts +310 -0
  9. package/lib/drivers/codex-driver.ts +454 -0
  10. package/lib/drivers/driver-manager.ts +158 -0
  11. package/lib/drivers/gemini-driver.ts +485 -0
  12. package/lib/drivers/index.ts +17 -0
  13. package/lib/flag-detection.js +350 -0
  14. package/lib/git-operations.js +267 -0
  15. package/lib/lock-file.js +144 -0
  16. package/lib/merge-operations.js +959 -0
  17. package/lib/protocol/driver.ts +360 -0
  18. package/lib/protocol/index.ts +12 -0
  19. package/lib/protocol/ir.ts +271 -0
  20. package/lib/session-display.js +330 -0
  21. package/lib/worktree-operations.js +221 -0
  22. package/package.json +2 -2
  23. package/scripts/agileflow-welcome.js +272 -24
  24. package/scripts/api-server-runner.js +177 -0
  25. package/scripts/archive-completed-stories.sh +22 -0
  26. package/scripts/automation-run-due.js +126 -0
  27. package/scripts/backfill-ideation-status.js +124 -0
  28. package/scripts/claude-tmux.sh +62 -1
  29. package/scripts/context-loader.js +292 -0
  30. package/scripts/dashboard-serve.js +323 -0
  31. package/scripts/lib/automation-registry.js +544 -0
  32. package/scripts/lib/automation-runner.js +476 -0
  33. package/scripts/lib/concurrency-limiter.js +513 -0
  34. package/scripts/lib/configure-features.js +46 -0
  35. package/scripts/lib/context-formatter.js +61 -0
  36. package/scripts/lib/damage-control-utils.js +29 -4
  37. package/scripts/lib/hook-metrics.js +324 -0
  38. package/scripts/lib/ideation-index.js +1196 -0
  39. package/scripts/lib/process-cleanup.js +359 -0
  40. package/scripts/lib/quality-gates.js +574 -0
  41. package/scripts/lib/status-task-bridge.js +522 -0
  42. package/scripts/lib/sync-ideation-status.js +292 -0
  43. package/scripts/lib/task-registry-cache.js +490 -0
  44. package/scripts/lib/task-registry.js +1181 -0
  45. package/scripts/migrate-ideation-index.js +515 -0
  46. package/scripts/precompact-context.sh +104 -0
  47. package/scripts/ralph-loop.js +2 -2
  48. package/scripts/session-manager.js +363 -2770
  49. package/scripts/spawn-parallel.js +45 -9
  50. package/src/core/agents/api-validator.md +180 -0
  51. package/src/core/agents/api.md +2 -0
  52. package/src/core/agents/code-reviewer.md +289 -0
  53. package/src/core/agents/configuration/damage-control.md +17 -0
  54. package/src/core/agents/database.md +2 -0
  55. package/src/core/agents/error-analyzer.md +203 -0
  56. package/src/core/agents/logic-analyzer-edge.md +171 -0
  57. package/src/core/agents/logic-analyzer-flow.md +254 -0
  58. package/src/core/agents/logic-analyzer-invariant.md +207 -0
  59. package/src/core/agents/logic-analyzer-race.md +267 -0
  60. package/src/core/agents/logic-analyzer-type.md +218 -0
  61. package/src/core/agents/logic-consensus.md +256 -0
  62. package/src/core/agents/orchestrator.md +89 -1
  63. package/src/core/agents/schema-validator.md +451 -0
  64. package/src/core/agents/team-coordinator.md +328 -0
  65. package/src/core/agents/ui-validator.md +328 -0
  66. package/src/core/agents/ui.md +2 -0
  67. package/src/core/commands/api.md +267 -0
  68. package/src/core/commands/automate.md +415 -0
  69. package/src/core/commands/babysit.md +290 -9
  70. package/src/core/commands/ideate/history.md +403 -0
  71. package/src/core/commands/{ideate.md → ideate/new.md} +244 -34
  72. package/src/core/commands/logic/audit.md +368 -0
  73. package/src/core/commands/roadmap/analyze.md +1 -1
  74. package/src/core/experts/documentation/expertise.yaml +29 -2
  75. package/src/core/templates/CONTEXT.md.example +49 -0
  76. package/src/core/templates/claude-settings.advanced.example.json +4 -0
  77. package/tools/cli/commands/serve.js +456 -0
  78. package/tools/cli/installers/core/installer.js +7 -2
  79. package/tools/cli/installers/ide/claude-code.js +85 -0
  80. package/tools/cli/lib/content-injector.js +27 -1
  81. package/tools/cli/lib/ui.js +26 -57
@@ -0,0 +1,310 @@
1
+ /**
2
+ * Claude Code Driver
3
+ *
4
+ * Driver implementation for Claude Code CLI (Anthropic).
5
+ * Translates Claude's native protocol to the unified IR format.
6
+ */
7
+
8
+ import {
9
+ Driver,
10
+ DriverConfig,
11
+ DriverStatus,
12
+ Capability,
13
+ CapabilityName,
14
+ CLICommand,
15
+ IREventHandler,
16
+ CLAUDE_CAPABILITIES,
17
+ } from "../protocol/driver";
18
+ import {
19
+ IREnvelope,
20
+ IRSource,
21
+ createIREnvelope,
22
+ IRTextDelta,
23
+ IRToolStart,
24
+ IRToolResult,
25
+ IRSession,
26
+ IRInit,
27
+ IRTask,
28
+ IRGit,
29
+ IRError,
30
+ } from "../protocol/ir";
31
+
32
+ // ============================================================================
33
+ // Tool Name Mapping (Claude -> IR normalized names)
34
+ // ============================================================================
35
+
36
+ const CLAUDE_TOOL_MAPPING: Record<string, string> = {
37
+ "Read": "file_read",
38
+ "Write": "file_write",
39
+ "Edit": "file_edit",
40
+ "Bash": "shell_exec",
41
+ "Glob": "file_glob",
42
+ "Grep": "file_grep",
43
+ "WebSearch": "web_search",
44
+ "WebFetch": "web_fetch",
45
+ "Task": "agent_spawn",
46
+ "TaskCreate": "todo_create",
47
+ "TaskUpdate": "todo_update",
48
+ "TaskList": "todo_list",
49
+ "TaskGet": "todo_get",
50
+ "AskUserQuestion": "user_question",
51
+ "EnterPlanMode": "plan_mode_enter",
52
+ "ExitPlanMode": "plan_mode_exit",
53
+ "Skill": "skill_invoke",
54
+ "NotebookEdit": "notebook_edit",
55
+ };
56
+
57
+ /**
58
+ * Normalize Claude tool name to IR format
59
+ */
60
+ function normalizeToolName(claudeName: string): string {
61
+ return CLAUDE_TOOL_MAPPING[claudeName] || claudeName.toLowerCase();
62
+ }
63
+
64
+ // ============================================================================
65
+ // Claude Driver Implementation
66
+ // ============================================================================
67
+
68
+ export class ClaudeDriver implements Driver {
69
+ readonly id: IRSource = "claude";
70
+ readonly name = "Claude Code";
71
+
72
+ private _status: DriverStatus = {
73
+ state: "stopped",
74
+ provider: "claude",
75
+ };
76
+
77
+ private _capabilities: Capability[] = [...CLAUDE_CAPABILITIES];
78
+ private _eventHandlers: Set<IREventHandler> = new Set();
79
+ private _sessions: Map<string, { config: DriverConfig; seqCounter: number }> = new Map();
80
+
81
+ // -------------------------------------------------------------------------
82
+ // Getters
83
+ // -------------------------------------------------------------------------
84
+
85
+ get status(): DriverStatus {
86
+ return this._status;
87
+ }
88
+
89
+ // -------------------------------------------------------------------------
90
+ // Lifecycle
91
+ // -------------------------------------------------------------------------
92
+
93
+ async start(sessionId: string, config: DriverConfig): Promise<void> {
94
+ this._sessions.set(sessionId, { config, seqCounter: 0 });
95
+
96
+ this._status = {
97
+ state: "ready",
98
+ provider: "claude",
99
+ model: config.model || "claude-3-opus",
100
+ contextMax: config.maxTokens || 200000,
101
+ };
102
+
103
+ // Emit init event
104
+ const initPayload: IRInit = {
105
+ provider: "claude",
106
+ version: "1.0.0", // TODO: Get actual version from CLI
107
+ capabilities: this._capabilities.filter(c => c.available).map(c => c.name),
108
+ maxContext: config.maxTokens || 200000,
109
+ };
110
+
111
+ this._emit(createIREnvelope("init", sessionId, "claude", initPayload));
112
+ }
113
+
114
+ async stop(sessionId: string): Promise<void> {
115
+ this._sessions.delete(sessionId);
116
+
117
+ if (this._sessions.size === 0) {
118
+ this._status = {
119
+ ...this._status,
120
+ state: "stopped",
121
+ };
122
+ }
123
+ }
124
+
125
+ async isAvailable(): Promise<boolean> {
126
+ // Check if 'claude' command is available
127
+ // In a real implementation, this would use exec/spawn to check
128
+ return true; // Assume available for now
129
+ }
130
+
131
+ // -------------------------------------------------------------------------
132
+ // Capabilities
133
+ // -------------------------------------------------------------------------
134
+
135
+ capabilities(): Capability[] {
136
+ return this._capabilities;
137
+ }
138
+
139
+ hasCapability(name: CapabilityName): boolean {
140
+ const cap = this._capabilities.find(c => c.name === name);
141
+ return cap?.available ?? false;
142
+ }
143
+
144
+ // -------------------------------------------------------------------------
145
+ // Communication
146
+ // -------------------------------------------------------------------------
147
+
148
+ async send(sessionId: string, command: CLICommand): Promise<void> {
149
+ // Mark as busy
150
+ this._status = { ...this._status, state: "busy" };
151
+
152
+ // This would normally send to the CLI process
153
+ // For now, just emit a session state change
154
+ const sessionPayload: IRSession = {
155
+ state: "thinking",
156
+ };
157
+ this._emit(createIREnvelope("session", sessionId, "claude", sessionPayload));
158
+ }
159
+
160
+ // -------------------------------------------------------------------------
161
+ // Message Translation (Claude -> IR)
162
+ // -------------------------------------------------------------------------
163
+
164
+ /**
165
+ * Translate a Claude-native message to IR format
166
+ * Called by the dashboard server when it receives messages from Claude
167
+ */
168
+ translateToIR(sessionId: string, claudeMessage: ClaudeNativeMessage): IREnvelope | null {
169
+ const session = this._sessions.get(sessionId);
170
+ if (!session) return null;
171
+
172
+ switch (claudeMessage.type) {
173
+ case "text":
174
+ return createIREnvelope<IRTextDelta>("text_delta", sessionId, "claude", {
175
+ text: claudeMessage.content,
176
+ done: claudeMessage.done ?? false,
177
+ });
178
+
179
+ case "tool_use":
180
+ return createIREnvelope<IRToolStart>("tool_start", sessionId, "claude", {
181
+ id: claudeMessage.id || `tool_${Date.now()}`,
182
+ name: normalizeToolName(claudeMessage.tool),
183
+ nativeName: claudeMessage.tool,
184
+ input: claudeMessage.input || {},
185
+ });
186
+
187
+ case "tool_result":
188
+ return createIREnvelope<IRToolResult>("tool_result", sessionId, "claude", {
189
+ id: claudeMessage.id || "",
190
+ ok: !claudeMessage.error,
191
+ output: claudeMessage.content,
192
+ error: claudeMessage.error,
193
+ });
194
+
195
+ case "task":
196
+ return createIREnvelope<IRTask>("task", sessionId, "claude", {
197
+ action: claudeMessage.action as "create" | "update" | "delete" | "list",
198
+ task: claudeMessage.task ? {
199
+ ...claudeMessage.task,
200
+ status: claudeMessage.task.status as "pending" | "in_progress" | "completed",
201
+ } : undefined,
202
+ tasks: claudeMessage.tasks?.map((t: { id: string; subject: string; status: string }) => ({
203
+ ...t,
204
+ status: t.status as "pending" | "in_progress" | "completed",
205
+ })),
206
+ });
207
+
208
+ case "git_status":
209
+ return createIREnvelope<IRGit>("git", sessionId, "claude", {
210
+ action: "status",
211
+ branch: claudeMessage.branch,
212
+ staged: claudeMessage.staged,
213
+ unstaged: claudeMessage.unstaged,
214
+ });
215
+
216
+ case "session_state":
217
+ return createIREnvelope<IRSession>("session", sessionId, "claude", {
218
+ state: claudeMessage.state as "connected" | "thinking" | "idle" | "error",
219
+ message: claudeMessage.message,
220
+ });
221
+
222
+ case "error":
223
+ return createIREnvelope<IRError>("error", sessionId, "claude", {
224
+ code: claudeMessage.code || "UNKNOWN",
225
+ message: claudeMessage.message,
226
+ details: claudeMessage.details,
227
+ recoverable: claudeMessage.recoverable ?? true,
228
+ });
229
+
230
+ default:
231
+ // Unknown message type, skip
232
+ return null;
233
+ }
234
+ }
235
+
236
+ /**
237
+ * Emit translated IR message to all handlers
238
+ */
239
+ emitIR(envelope: IREnvelope): void {
240
+ this._emit(envelope);
241
+ }
242
+
243
+ // -------------------------------------------------------------------------
244
+ // Events
245
+ // -------------------------------------------------------------------------
246
+
247
+ onEvent(handler: IREventHandler): void {
248
+ this._eventHandlers.add(handler);
249
+ }
250
+
251
+ offEvent(handler: IREventHandler): void {
252
+ this._eventHandlers.delete(handler);
253
+ }
254
+
255
+ private _emit(envelope: IREnvelope): void {
256
+ Array.from(this._eventHandlers).forEach((handler) => {
257
+ try {
258
+ handler(envelope);
259
+ } catch (error) {
260
+ console.error("[ClaudeDriver] Event handler error:", error);
261
+ }
262
+ });
263
+ }
264
+ }
265
+
266
+ // ============================================================================
267
+ // Claude Native Message Types (from dashboard-protocol.js)
268
+ // ============================================================================
269
+
270
+ export interface ClaudeNativeMessage {
271
+ type: string;
272
+ id?: string;
273
+ content?: string;
274
+ done?: boolean;
275
+ tool?: string;
276
+ input?: Record<string, unknown>;
277
+ error?: string;
278
+ action?: string;
279
+ task?: {
280
+ id: string;
281
+ subject: string;
282
+ description?: string;
283
+ status: string;
284
+ activeForm?: string;
285
+ };
286
+ tasks?: Array<{
287
+ id: string;
288
+ subject: string;
289
+ status: string;
290
+ }>;
291
+ branch?: string;
292
+ staged?: Array<{ path: string; status: string }>;
293
+ unstaged?: Array<{ path: string; status: string }>;
294
+ state?: string;
295
+ message?: string;
296
+ code?: string;
297
+ details?: unknown;
298
+ recoverable?: boolean;
299
+ }
300
+
301
+ // ============================================================================
302
+ // Factory Function
303
+ // ============================================================================
304
+
305
+ /**
306
+ * Create a new Claude driver instance
307
+ */
308
+ export function createClaudeDriver(): ClaudeDriver {
309
+ return new ClaudeDriver();
310
+ }