@shepai/cli 1.16.0 → 1.18.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 (126) hide show
  1. package/dist/eslint.config.mjs +8 -1
  2. package/dist/src/application/ports/output/agents/agent-executor-provider.interface.d.ts +5 -0
  3. package/dist/src/application/ports/output/agents/agent-executor-provider.interface.d.ts.map +1 -0
  4. package/dist/src/application/ports/output/agents/agent-executor-provider.interface.js +1 -0
  5. package/dist/src/application/ports/output/agents/agent-executor.interface.d.ts +4 -0
  6. package/dist/src/application/ports/output/agents/agent-executor.interface.d.ts.map +1 -1
  7. package/dist/src/application/ports/output/agents/feature-agent-process.interface.d.ts +2 -0
  8. package/dist/src/application/ports/output/agents/feature-agent-process.interface.d.ts.map +1 -1
  9. package/dist/src/application/ports/output/agents/index.d.ts +1 -0
  10. package/dist/src/application/ports/output/agents/index.d.ts.map +1 -1
  11. package/dist/src/application/ports/output/index.d.ts +1 -1
  12. package/dist/src/application/ports/output/index.d.ts.map +1 -1
  13. package/dist/src/application/use-cases/features/create-feature.use-case.d.ts +3 -3
  14. package/dist/src/application/use-cases/features/create-feature.use-case.d.ts.map +1 -1
  15. package/dist/src/application/use-cases/features/create-feature.use-case.js +9 -7
  16. package/dist/src/application/use-cases/features/resume-feature.use-case.d.ts.map +1 -1
  17. package/dist/src/application/use-cases/features/resume-feature.use-case.js +6 -1
  18. package/dist/src/infrastructure/di/container.d.ts.map +1 -1
  19. package/dist/src/infrastructure/di/container.js +9 -2
  20. package/dist/src/infrastructure/services/agents/common/agent-executor-factory.service.d.ts +1 -1
  21. package/dist/src/infrastructure/services/agents/common/agent-executor-factory.service.d.ts.map +1 -1
  22. package/dist/src/infrastructure/services/agents/common/agent-executor-factory.service.js +6 -2
  23. package/dist/src/infrastructure/services/agents/common/agent-executor-provider.service.d.ts +9 -0
  24. package/dist/src/infrastructure/services/agents/common/agent-executor-provider.service.d.ts.map +1 -0
  25. package/dist/src/infrastructure/services/agents/common/agent-executor-provider.service.js +11 -0
  26. package/dist/src/infrastructure/services/agents/common/agent-runner.service.d.ts +3 -3
  27. package/dist/src/infrastructure/services/agents/common/agent-runner.service.d.ts.map +1 -1
  28. package/dist/src/infrastructure/services/agents/common/agent-runner.service.js +4 -4
  29. package/dist/src/infrastructure/services/agents/common/agent-validator.service.d.ts +1 -9
  30. package/dist/src/infrastructure/services/agents/common/agent-validator.service.d.ts.map +1 -1
  31. package/dist/src/infrastructure/services/agents/common/agent-validator.service.js +1 -0
  32. package/dist/src/infrastructure/services/agents/common/executors/claude-code-executor.service.d.ts +1 -7
  33. package/dist/src/infrastructure/services/agents/common/executors/claude-code-executor.service.d.ts.map +1 -1
  34. package/dist/src/infrastructure/services/agents/common/executors/claude-code-executor.service.js +4 -0
  35. package/dist/src/infrastructure/services/agents/common/executors/cursor-executor.service.d.ts +38 -0
  36. package/dist/src/infrastructure/services/agents/common/executors/cursor-executor.service.d.ts.map +1 -0
  37. package/dist/src/infrastructure/services/agents/common/executors/cursor-executor.service.js +296 -0
  38. package/dist/src/infrastructure/services/agents/common/types.d.ts +23 -0
  39. package/dist/src/infrastructure/services/agents/common/types.d.ts.map +1 -0
  40. package/dist/src/infrastructure/services/agents/common/types.js +7 -0
  41. package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.d.ts +2 -0
  42. package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.d.ts.map +1 -1
  43. package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.js +6 -0
  44. package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts +2 -0
  45. package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts.map +1 -1
  46. package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-worker.js +32 -12
  47. package/dist/src/infrastructure/services/agents/feature-agent/nodes/implement.node.d.ts.map +1 -1
  48. package/dist/src/infrastructure/services/agents/feature-agent/nodes/implement.node.js +19 -10
  49. package/dist/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.d.ts +41 -1
  50. package/dist/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.d.ts.map +1 -1
  51. package/dist/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.js +125 -6
  52. package/dist/src/presentation/cli/commands/feat/ls.command.d.ts.map +1 -1
  53. package/dist/src/presentation/cli/commands/feat/ls.command.js +42 -7
  54. package/dist/src/presentation/tui/prompts/agent-select.prompt.d.ts +1 -1
  55. package/dist/src/presentation/tui/prompts/agent-select.prompt.js +1 -1
  56. package/dist/src/presentation/web/components/common/sidebar-section-header/sidebar-section-header.js +1 -1
  57. package/dist/src/presentation/web/components/ui/alert.js +1 -1
  58. package/dist/src/presentation/web/components/ui/badge.js +4 -4
  59. package/dist/src/presentation/web/components/ui/button.js +3 -3
  60. package/dist/src/presentation/web/components/ui/sidebar.js +2 -2
  61. package/dist/tsconfig.build.tsbuildinfo +1 -1
  62. package/package.json +1 -1
  63. package/web/.next/BUILD_ID +1 -1
  64. package/web/.next/build-manifest.json +2 -2
  65. package/web/.next/cache/.previewinfo +1 -1
  66. package/web/.next/cache/.rscinfo +1 -1
  67. package/web/.next/cache/.tsbuildinfo +1 -1
  68. package/web/.next/cache/config.json +3 -3
  69. package/web/.next/fallback-build-manifest.json +2 -2
  70. package/web/.next/prerender-manifest.json +3 -3
  71. package/web/.next/required-server-files.js +1 -1
  72. package/web/.next/required-server-files.json +1 -1
  73. package/web/.next/server/app/_global-error.html +2 -2
  74. package/web/.next/server/app/_global-error.rsc +1 -1
  75. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  76. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  77. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  78. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  79. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  80. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  81. package/web/.next/server/app/_not-found.html +2 -2
  82. package/web/.next/server/app/_not-found.rsc +8 -8
  83. package/web/.next/server/app/_not-found.segments/_full.segment.rsc +8 -8
  84. package/web/.next/server/app/_not-found.segments/_head.segment.rsc +3 -3
  85. package/web/.next/server/app/_not-found.segments/_index.segment.rsc +4 -4
  86. package/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  87. package/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  88. package/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  89. package/web/.next/server/app/index.html +2 -2
  90. package/web/.next/server/app/index.rsc +3 -3
  91. package/web/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  92. package/web/.next/server/app/index.segments/_full.segment.rsc +3 -3
  93. package/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  94. package/web/.next/server/app/index.segments/_index.segment.rsc +2 -2
  95. package/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  96. package/web/.next/server/app/page_client-reference-manifest.js +1 -1
  97. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  98. package/web/.next/server/app/version.html +2 -2
  99. package/web/.next/server/app/version.rsc +3 -3
  100. package/web/.next/server/app/version.segments/_full.segment.rsc +3 -3
  101. package/web/.next/server/app/version.segments/_head.segment.rsc +1 -1
  102. package/web/.next/server/app/version.segments/_index.segment.rsc +2 -2
  103. package/web/.next/server/app/version.segments/_tree.segment.rsc +1 -1
  104. package/web/.next/server/app/version.segments/version/__PAGE__.segment.rsc +2 -2
  105. package/web/.next/server/app/version.segments/version.segment.rsc +1 -1
  106. package/web/.next/server/chunks/ssr/_0f02ab66._.js +1 -1
  107. package/web/.next/server/chunks/ssr/_0f02ab66._.js.map +1 -1
  108. package/web/.next/server/chunks/ssr/_19be0743._.js +1 -1
  109. package/web/.next/server/chunks/ssr/_4582f3c3._.js +1 -1
  110. package/web/.next/server/chunks/ssr/_4582f3c3._.js.map +1 -1
  111. package/web/.next/server/chunks/ssr/_a0c04017._.js +1 -1
  112. package/web/.next/server/chunks/ssr/_a0c04017._.js.map +1 -1
  113. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_version_version-page-client_tsx_fe9db753._.js +1 -1
  114. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_version_version-page-client_tsx_fe9db753._.js.map +1 -1
  115. package/web/.next/server/pages/404.html +2 -2
  116. package/web/.next/server/pages/500.html +2 -2
  117. package/web/.next/server/server-reference-manifest.js +1 -1
  118. package/web/.next/server/server-reference-manifest.json +1 -1
  119. package/web/.next/static/chunks/{5130d7093ad39f4a.js → 26d260496abf3ed8.js} +1 -1
  120. package/web/.next/static/chunks/{ef1296dbe67d5aae.js → 8353f5690707d9a5.js} +1 -1
  121. package/web/.next/static/chunks/{523c5cfe0570712c.js → f74cb59a5a6c94f1.js} +1 -1
  122. package/web/.next/trace +1 -1
  123. package/web/.next/trace-build +1 -1
  124. /package/web/.next/static/{KqMr5DLdrvbaA-agLuHP1 → iV3kEDpfUq_ttVqv3E57o}/_buildManifest.js +0 -0
  125. /package/web/.next/static/{KqMr5DLdrvbaA-agLuHP1 → iV3kEDpfUq_ttVqv3E57o}/_clientMiddlewareManifest.json +0 -0
  126. /package/web/.next/static/{KqMr5DLdrvbaA-agLuHP1 → iV3kEDpfUq_ttVqv3E57o}/_ssgManifest.js +0 -0
@@ -0,0 +1,296 @@
1
+ /**
2
+ * Cursor Executor Service
3
+ *
4
+ * Infrastructure implementation of IAgentExecutor for the Cursor agent.
5
+ * Executes prompts via the `agent` CLI subprocess with JSON and stream-json
6
+ * output formats.
7
+ *
8
+ * Uses constructor dependency injection for the spawn function
9
+ * to enable testability without mocking node:child_process directly.
10
+ */
11
+ /** Features supported by Cursor CLI */
12
+ const SUPPORTED_FEATURES = new Set(['session-resume', 'streaming']);
13
+ /**
14
+ * Executor service for Cursor agent.
15
+ * Uses subprocess spawning to interact with the `agent` CLI.
16
+ */
17
+ export class CursorExecutorService {
18
+ spawn;
19
+ agentType = 'cursor';
20
+ /** When true, suppresses debug logging (set per-call via options.silent) */
21
+ silent = false;
22
+ constructor(spawn) {
23
+ this.spawn = spawn;
24
+ }
25
+ /** Debug logging — writes to stdout so it appears in the worker log file */
26
+ log(message) {
27
+ if (this.silent)
28
+ return;
29
+ const ts = new Date().toISOString();
30
+ process.stdout.write(`[${ts}] [cursor-executor] ${message}\n`);
31
+ }
32
+ supportsFeature(feature) {
33
+ return SUPPORTED_FEATURES.has(feature);
34
+ }
35
+ async execute(prompt, options) {
36
+ this.silent = options?.silent ?? false;
37
+ const args = this.buildStreamArgs(prompt, options);
38
+ const spawnOpts = this.buildSpawnOptions(options);
39
+ this.log(`Spawning: agent ${args.map((a) => (a.length > 80 ? `${a.slice(0, 77)}...` : a)).join(' ')}`);
40
+ this.log(`Spawn options: ${JSON.stringify(spawnOpts)}`);
41
+ const proc = this.spawn('agent', args, spawnOpts);
42
+ this.log(`Subprocess PID: ${proc.pid ?? 'undefined (spawn may have failed)'}`);
43
+ if (proc.stdin)
44
+ proc.stdin.end();
45
+ return new Promise((resolve, reject) => {
46
+ let lineBuffer = '';
47
+ let stderr = '';
48
+ let timedOut = false;
49
+ let timeoutId;
50
+ // Accumulated from assistant events
51
+ let resultText = '';
52
+ let sessionId;
53
+ let metadata;
54
+ if (options?.timeout) {
55
+ timeoutId = setTimeout(() => {
56
+ timedOut = true;
57
+ proc.kill();
58
+ }, options.timeout);
59
+ }
60
+ const processLine = (line) => {
61
+ this.logStreamEvent(line);
62
+ try {
63
+ const parsed = JSON.parse(line);
64
+ if (parsed.type === 'assistant' && Array.isArray(parsed.message?.content)) {
65
+ for (const block of parsed.message.content) {
66
+ if (block.type === 'text' && block.text)
67
+ resultText += block.text;
68
+ }
69
+ }
70
+ else if (parsed.type === 'result') {
71
+ if (parsed.session_id)
72
+ sessionId = parsed.session_id;
73
+ if (parsed.duration_ms !== undefined) {
74
+ metadata = { ...metadata, duration_ms: parsed.duration_ms };
75
+ }
76
+ }
77
+ // user events and tool_call events: logged but don't affect result
78
+ }
79
+ catch {
80
+ /* malformed JSON — already logged */
81
+ }
82
+ };
83
+ proc.stdout?.on('data', (chunk) => {
84
+ lineBuffer += chunk.toString();
85
+ const lines = lineBuffer.split('\n');
86
+ lineBuffer = lines.pop() ?? '';
87
+ for (const line of lines) {
88
+ const trimmed = line.trim();
89
+ if (trimmed)
90
+ processLine(trimmed);
91
+ }
92
+ });
93
+ proc.stderr?.on('data', (chunk) => {
94
+ const data = chunk.toString();
95
+ stderr += data;
96
+ this.log(`stderr: ${data.trimEnd()}`);
97
+ });
98
+ proc.on('error', (error) => {
99
+ this.log(`Process error event: ${error.message}`);
100
+ if (timeoutId)
101
+ clearTimeout(timeoutId);
102
+ reject(error);
103
+ });
104
+ proc.on('close', (code) => {
105
+ if (lineBuffer.trim())
106
+ processLine(lineBuffer.trim());
107
+ this.log(`Process closed with code ${code}, result=${resultText.length} chars`);
108
+ if (timeoutId)
109
+ clearTimeout(timeoutId);
110
+ if (timedOut) {
111
+ reject(new Error('Agent execution timed out'));
112
+ return;
113
+ }
114
+ if (code !== 0 && code !== null) {
115
+ reject(new Error(stderr.trim() || `Process exited with code ${code}`));
116
+ return;
117
+ }
118
+ const result = { result: resultText };
119
+ if (sessionId)
120
+ result.sessionId = sessionId;
121
+ if (metadata)
122
+ result.metadata = metadata;
123
+ resolve(result);
124
+ });
125
+ });
126
+ }
127
+ async *executeStream(prompt, options) {
128
+ const args = this.buildStreamArgs(prompt, options);
129
+ const spawnOpts = this.buildSpawnOptions(options);
130
+ const proc = this.spawn('agent', args, spawnOpts);
131
+ if (proc.stdin)
132
+ proc.stdin.end();
133
+ let lineBuffer = '';
134
+ let stderr = '';
135
+ const queue = [];
136
+ let resolve = null;
137
+ let error = null;
138
+ function enqueue(event) {
139
+ queue.push(event);
140
+ if (resolve) {
141
+ resolve();
142
+ resolve = null;
143
+ }
144
+ }
145
+ function waitForItem() {
146
+ if (queue.length > 0)
147
+ return Promise.resolve();
148
+ return new Promise((r) => {
149
+ resolve = r;
150
+ });
151
+ }
152
+ proc.stdout?.on('data', (chunk) => {
153
+ lineBuffer += chunk.toString();
154
+ const lines = lineBuffer.split('\n');
155
+ lineBuffer = lines.pop() ?? '';
156
+ for (const line of lines) {
157
+ const trimmed = line.trim();
158
+ if (!trimmed)
159
+ continue;
160
+ const event = this.parseStreamLine(trimmed);
161
+ if (event)
162
+ enqueue(event);
163
+ }
164
+ });
165
+ proc.stderr?.on('data', (chunk) => {
166
+ stderr += chunk.toString();
167
+ });
168
+ proc.on('error', (err) => {
169
+ error = err;
170
+ enqueue(null);
171
+ });
172
+ proc.on('close', (code) => {
173
+ if (lineBuffer.trim()) {
174
+ const event = this.parseStreamLine(lineBuffer.trim());
175
+ if (event)
176
+ enqueue(event);
177
+ }
178
+ if (code !== 0 && code !== null && stderr.trim()) {
179
+ enqueue({ type: 'error', content: stderr.trim(), timestamp: new Date() });
180
+ }
181
+ enqueue(null);
182
+ });
183
+ while (true) {
184
+ await waitForItem();
185
+ const item = queue.shift();
186
+ if (item === null || item === undefined) {
187
+ if (error !== null) {
188
+ yield {
189
+ type: 'error',
190
+ content: error.message,
191
+ timestamp: new Date(),
192
+ };
193
+ }
194
+ return;
195
+ }
196
+ yield item;
197
+ }
198
+ }
199
+ /**
200
+ * Log a stream-json line as a human-readable event in the worker log.
201
+ */
202
+ logStreamEvent(line) {
203
+ try {
204
+ const parsed = JSON.parse(line);
205
+ if (parsed.type === 'assistant' && Array.isArray(parsed.message?.content)) {
206
+ for (const block of parsed.message.content) {
207
+ if (block.type === 'text' && block.text?.trim()) {
208
+ this.log(`[text] ${block.text.trim().replace(/\n/g, ' ')}`);
209
+ }
210
+ }
211
+ return;
212
+ }
213
+ if (parsed.type === 'tool_call') {
214
+ const toolName = Object.keys(parsed).find((k) => k.endsWith('ToolCall') || k.endsWith('toolCall')) ??
215
+ 'unknown';
216
+ this.log(`[tool] ${parsed.subtype ?? 'call'}: ${toolName}`);
217
+ return;
218
+ }
219
+ if (parsed.type === 'result') {
220
+ this.log(`[result] session=${parsed.session_id ?? 'none'}, duration=${parsed.duration_ms ?? 'unknown'}ms`);
221
+ return;
222
+ }
223
+ if (parsed.type === 'user')
224
+ return; // Skip echoed input
225
+ }
226
+ catch {
227
+ if (line.length > 0)
228
+ this.log(`[raw] ${line}`);
229
+ }
230
+ }
231
+ buildArgs(prompt, options) {
232
+ const args = ['-p', prompt, '--output-format', 'json', '--force'];
233
+ if (options?.resumeSession)
234
+ args.push('--resume', options.resumeSession);
235
+ if (options?.model)
236
+ args.push('-m', options.model);
237
+ // Unsupported options silently omitted: systemPrompt, allowedTools, maxTurns, outputSchema
238
+ // No auth flags — binary handles its own auth
239
+ return args;
240
+ }
241
+ buildStreamArgs(prompt, options) {
242
+ const args = this.buildArgs(prompt, options);
243
+ const fmtIdx = args.indexOf('--output-format');
244
+ if (fmtIdx !== -1)
245
+ args[fmtIdx + 1] = 'stream-json';
246
+ return args;
247
+ }
248
+ buildSpawnOptions(options) {
249
+ const spawnOpts = {};
250
+ if (options?.cwd)
251
+ spawnOpts.cwd = options.cwd;
252
+ return spawnOpts;
253
+ }
254
+ parseStreamLine(line) {
255
+ try {
256
+ const parsed = JSON.parse(line);
257
+ if (parsed.type === 'assistant' && Array.isArray(parsed.message?.content)) {
258
+ const textParts = [];
259
+ for (const block of parsed.message.content) {
260
+ if (block.type === 'text' && block.text)
261
+ textParts.push(block.text);
262
+ }
263
+ if (textParts.length > 0) {
264
+ return { type: 'progress', content: textParts.join(''), timestamp: new Date() };
265
+ }
266
+ return null;
267
+ }
268
+ if (parsed.type === 'tool_call' && parsed.subtype === 'completed') {
269
+ const toolName = Object.keys(parsed).find((k) => k.endsWith('ToolCall') || k.endsWith('toolCall')) ??
270
+ 'tool';
271
+ return { type: 'progress', content: `Tool completed: ${toolName}`, timestamp: new Date() };
272
+ }
273
+ if (parsed.type === 'tool_call' && parsed.subtype === 'started') {
274
+ const toolName = Object.keys(parsed).find((k) => k.endsWith('ToolCall') || k.endsWith('toolCall')) ??
275
+ 'tool';
276
+ return { type: 'progress', content: `Tool started: ${toolName}`, timestamp: new Date() };
277
+ }
278
+ if (parsed.type === 'result') {
279
+ return { type: 'result', content: parsed.session_id ?? '', timestamp: new Date() };
280
+ }
281
+ if (parsed.type === 'user')
282
+ return null; // Skip echoed input
283
+ if (parsed.type === 'error') {
284
+ return {
285
+ type: 'error',
286
+ content: parsed.error ?? parsed.message ?? '',
287
+ timestamp: new Date(),
288
+ };
289
+ }
290
+ return null;
291
+ }
292
+ catch {
293
+ return { type: 'progress', content: line, timestamp: new Date() };
294
+ }
295
+ }
296
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Shared Types for Agent Infrastructure
3
+ *
4
+ * Common type definitions used across agent executor implementations
5
+ * and the agent validator service.
6
+ */
7
+ import type { ChildProcess } from 'node:child_process';
8
+ /**
9
+ * Type for the spawn dependency.
10
+ * Matches the signature of child_process.spawn.
11
+ * Injected via constructor to enable testability.
12
+ */
13
+ export type SpawnFunction = (command: string, args: string[], options?: object) => ChildProcess;
14
+ /**
15
+ * Type for the command executor dependency.
16
+ * Matches the promisified signature of child_process.execFile.
17
+ * Injected via constructor to avoid direct node module mocking in tests.
18
+ */
19
+ export type ExecFunction = (file: string, args: string[]) => Promise<{
20
+ stdout: string;
21
+ stderr: string;
22
+ }>;
23
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../../src/infrastructure/services/agents/common/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAEvD;;;;GAIG;AACH,MAAM,MAAM,aAAa,GAAG,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,CAAC,EAAE,MAAM,KAAK,YAAY,CAAC;AAEhG;;;;GAIG;AACH,MAAM,MAAM,YAAY,GAAG,CACzB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EAAE,KACX,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ /**
2
+ * Shared Types for Agent Infrastructure
3
+ *
4
+ * Common type definitions used across agent executor implementations
5
+ * and the agent validator service.
6
+ */
7
+ export {};
@@ -13,6 +13,8 @@ export declare class FeatureAgentProcessService implements IFeatureAgentProcessS
13
13
  spawn(featureId: string, runId: string, repoPath: string, specDir: string, worktreePath?: string, options?: {
14
14
  approvalMode?: string;
15
15
  resume?: boolean;
16
+ threadId?: string;
17
+ resumeFromInterrupt?: boolean;
16
18
  }): number;
17
19
  isAlive(pid: number): boolean;
18
20
  checkAndMarkCrashed(runId: string): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"feature-agent-process.service.d.ts","sourceRoot":"","sources":["../../../../../../src/infrastructure/services/agents/feature-agent/feature-agent-process.service.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,sEAAsE,CAAC;AACxH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qEAAqE,CAAC;AAa/G,qBAAa,0BAA2B,YAAW,2BAA2B;IAChE,OAAO,CAAC,QAAQ,CAAC,aAAa;gBAAb,aAAa,EAAE,mBAAmB;IAE/D,KAAK,CACH,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,YAAY,CAAC,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,GACpD,MAAM;IA4CT,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IASvB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAexD"}
1
+ {"version":3,"file":"feature-agent-process.service.d.ts","sourceRoot":"","sources":["../../../../../../src/infrastructure/services/agents/feature-agent/feature-agent-process.service.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,sEAAsE,CAAC;AACxH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qEAAqE,CAAC;AAa/G,qBAAa,0BAA2B,YAAW,2BAA2B;IAChE,OAAO,CAAC,QAAQ,CAAC,aAAa;gBAAb,aAAa,EAAE,mBAAmB;IAE/D,KAAK,CACH,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,YAAY,CAAC,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE;QACR,YAAY,CAAC,EAAE,MAAM,CAAC;QACtB,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;KAC/B,GACA,MAAM;IAkDT,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IASvB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAexD"}
@@ -44,9 +44,15 @@ export class FeatureAgentProcessService {
44
44
  if (options?.approvalMode) {
45
45
  args.push('--approval-mode', options.approvalMode);
46
46
  }
47
+ if (options?.threadId) {
48
+ args.push('--thread-id', options.threadId);
49
+ }
47
50
  if (options?.resume) {
48
51
  args.push('--resume');
49
52
  }
53
+ if (options?.resumeFromInterrupt) {
54
+ args.push('--resume-from-interrupt');
55
+ }
50
56
  // Create log file for worker output (for debugging)
51
57
  const logsDir = join(homedir(), '.shep', 'logs');
52
58
  mkdirSync(logsDir, { recursive: true });
@@ -17,6 +17,8 @@ export interface WorkerArgs {
17
17
  worktreePath?: string;
18
18
  approvalMode?: string;
19
19
  resume?: boolean;
20
+ threadId?: string;
21
+ resumeFromInterrupt?: boolean;
20
22
  }
21
23
  /**
22
24
  * Parse CLI arguments into a WorkerArgs object.
@@ -1 +1 @@
1
- {"version":3,"file":"feature-agent-worker.d.ts","sourceRoot":"","sources":["../../../../../../src/infrastructure/services/agents/feature-agent/feature-agent-worker.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG;AAEH,OAAO,kBAAkB,CAAC;AAc1B,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CA4B1D;AAgCD;;;GAGG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAqH/D"}
1
+ {"version":3,"file":"feature-agent-worker.d.ts","sourceRoot":"","sources":["../../../../../../src/infrastructure/services/agents/feature-agent/feature-agent-worker.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG;AAEH,OAAO,kBAAkB,CAAC;AAc1B,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAmC1D;AAgCD;;;GAGG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAmI/D"}
@@ -16,7 +16,7 @@ import { initializeContainer, container } from '../../../../infrastructure/di/co
16
16
  import { createFeatureAgentGraph } from './feature-agent-graph.js';
17
17
  import { createCheckpointer } from '../common/checkpointer.js';
18
18
  import { AgentRunStatus } from '../../../../domain/generated/output.js';
19
- import { getSettings, initializeSettings } from '../../../../infrastructure/services/settings.service.js';
19
+ import { initializeSettings } from '../../../../infrastructure/services/settings.service.js';
20
20
  import { InitializeSettingsUseCase } from '../../../../application/use-cases/settings/initialize-settings.use-case.js';
21
21
  import { setHeartbeatContext } from './heartbeat.js';
22
22
  /**
@@ -36,6 +36,9 @@ export function parseWorkerArgs(args) {
36
36
  const approvalIdx = args.indexOf('--approval-mode');
37
37
  const approvalMode = approvalIdx !== -1 && approvalIdx + 1 < args.length ? args[approvalIdx + 1] : undefined;
38
38
  const resume = args.includes('--resume');
39
+ const resumeFromInterrupt = args.includes('--resume-from-interrupt');
40
+ const threadIdx = args.indexOf('--thread-id');
41
+ const threadId = threadIdx !== -1 && threadIdx + 1 < args.length ? args[threadIdx + 1] : undefined;
39
42
  return {
40
43
  featureId: getArg('feature-id'),
41
44
  runId: getArg('run-id'),
@@ -44,6 +47,8 @@ export function parseWorkerArgs(args) {
44
47
  worktreePath,
45
48
  approvalMode,
46
49
  resume,
50
+ threadId,
51
+ resumeFromInterrupt,
47
52
  };
48
53
  }
49
54
  /** Simple worker logger — writes to stdout which is redirected to log file by the parent. */
@@ -92,14 +97,15 @@ export async function runWorker(args) {
92
97
  const settings = await initSettingsUseCase.execute();
93
98
  initializeSettings(settings);
94
99
  const runRepository = container.resolve('IAgentRunRepository');
95
- const executorFactory = container.resolve('IAgentExecutorFactory');
96
- // Create executor from configured agent settings (now settings are initialized)
97
- const configuredSettings = getSettings();
98
- log(`Creating executor for agent type: ${configuredSettings.agent.type}`);
99
- const executor = executorFactory.createExecutor(configuredSettings.agent.type, configuredSettings.agent);
100
- // Use a file-based checkpointer for persistence across restarts
101
- const checkpointPath = join(homedir(), '.shep', 'checkpoints', `${args.runId}.db`);
102
- log(`Creating checkpointer at ${checkpointPath}`);
100
+ const executorProvider = container.resolve('IAgentExecutorProvider');
101
+ // Create executor from configured agent settings
102
+ log('Creating executor from configured agent settings...');
103
+ const executor = executorProvider.getExecutor();
104
+ // Use threadId for checkpoint path so resume runs share the same checkpoint DB.
105
+ // Falls back to runId for backwards compatibility with existing runs.
106
+ const checkpointId = args.threadId ?? args.runId;
107
+ const checkpointPath = join(homedir(), '.shep', 'checkpoints', `${checkpointId}.db`);
108
+ log(`Creating checkpointer at ${checkpointPath} (thread: ${checkpointId})`);
103
109
  const checkpointer = createCheckpointer(checkpointPath);
104
110
  const graph = createFeatureAgentGraph(executor, checkpointer);
105
111
  // Mark the run as running with our PID
@@ -116,12 +122,26 @@ export async function runWorker(args) {
116
122
  // Set heartbeat context so node-helpers can update current node
117
123
  setHeartbeatContext(args.runId, runRepository);
118
124
  try {
119
- const graphConfig = { configurable: { thread_id: args.runId } };
125
+ const graphConfig = { configurable: { thread_id: checkpointId } };
120
126
  let result;
121
- if (args.resume) {
122
- log('Resuming graph from checkpoint...');
127
+ if (args.resume && args.resumeFromInterrupt) {
128
+ // Resume from an interrupt (human-in-the-loop approval)
129
+ log('Resuming graph from interrupt checkpoint...');
123
130
  result = await graph.invoke(new Command({ resume: { approved: true } }), graphConfig);
124
131
  }
132
+ else if (args.resume) {
133
+ // Resume from error — re-invoke with initial state; LangGraph continues
134
+ // from the last successfully checkpointed node.
135
+ log('Resuming graph from error checkpoint...');
136
+ result = await graph.invoke({
137
+ featureId: args.featureId,
138
+ repositoryPath: args.repo,
139
+ worktreePath: args.worktreePath ?? args.repo,
140
+ specDir: args.specDir,
141
+ error: undefined, // Clear previous error state
142
+ ...(args.approvalMode ? { approvalMode: args.approvalMode } : {}),
143
+ }, graphConfig);
144
+ }
125
145
  else {
126
146
  log('Starting graph invocation...');
127
147
  result = await graph.invoke({
@@ -1 +1 @@
1
- {"version":3,"file":"implement.node.d.ts","sourceRoot":"","sources":["../../../../../../../src/infrastructure/services/agents/feature-agent/nodes/implement.node.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+DAA+D,CAAC;AACpG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AA2DrD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,cAAc,IAG5C,OAAO,iBAAiB,KAAG,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAqJ7E"}
1
+ {"version":3,"file":"implement.node.d.ts","sourceRoot":"","sources":["../../../../../../../src/infrastructure/services/agents/feature-agent/nodes/implement.node.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+DAA+D,CAAC;AACpG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AA+DrD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,cAAc,IAG5C,OAAO,iBAAiB,KAAG,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAgK7E"}
@@ -10,7 +10,7 @@ import yaml from 'js-yaml';
10
10
  import { writeFileSync } from 'node:fs';
11
11
  import { join } from 'node:path';
12
12
  import { interrupt, isGraphBubbleUp } from '@langchain/langgraph';
13
- import { createNodeLogger, readSpecFile, buildExecutorOptions, shouldInterrupt, } from './node-helpers.js';
13
+ import { createNodeLogger, readSpecFile, buildExecutorOptions, shouldInterrupt, safeYamlLoad, retryExecute, getCompletedPhases, markPhaseComplete, } from './node-helpers.js';
14
14
  import { reportNodeStart } from '../heartbeat.js';
15
15
  import { buildImplementPhasePrompt, } from './prompts/implement.prompt.js';
16
16
  /**
@@ -60,8 +60,8 @@ export function createImplementNode(executor) {
60
60
  log.error(msg);
61
61
  return { currentNode: 'implement', error: msg, messages: [`[implement] Error: ${msg}`] };
62
62
  }
63
- const planData = yaml.load(planContent);
64
- const tasksData = yaml.load(tasksContent);
63
+ const planData = safeYamlLoad(planContent);
64
+ const tasksData = safeYamlLoad(tasksContent);
65
65
  if (!planData?.phases?.length || !tasksData?.tasks?.length) {
66
66
  const msg = 'Empty phases or tasks — nothing to implement';
67
67
  log.error(msg);
@@ -71,6 +71,9 @@ export function createImplementNode(executor) {
71
71
  const totalTasks = tasksData.tasks.length;
72
72
  let completedTasks = 0;
73
73
  const totalPhases = planData.phases.length;
74
+ // --- Check for completed phases (skip on resume) ---
75
+ const completedPhaseIds = getCompletedPhases(state.specDir);
76
+ const retryOpts = { logger: log };
74
77
  // --- Execute phases in order ---
75
78
  for (let i = 0; i < totalPhases; i++) {
76
79
  const phase = planData.phases[i];
@@ -81,6 +84,12 @@ export function createImplementNode(executor) {
81
84
  .map((id) => taskMap.get(id))
82
85
  .filter((t) => t !== undefined)
83
86
  : tasksData.tasks.filter((t) => t.phaseId === phase.id);
87
+ // Skip already-completed phases
88
+ if (completedPhaseIds.includes(phase.id)) {
89
+ completedTasks += phaseTasks.length;
90
+ log.info(`Phase ${phase.id} "${phase.name}" — already complete, skipping`);
91
+ continue;
92
+ }
84
93
  if (phaseTasks.length === 0) {
85
94
  log.info(`Phase ${phase.id} "${phase.name}" — no tasks, skipping`);
86
95
  continue;
@@ -99,7 +108,7 @@ export function createImplementNode(executor) {
99
108
  };
100
109
  const prompt = buildImplementPhasePrompt(state, singleTaskPhase, [task], promptContext);
101
110
  log.info(` [parallel] Task ${task.id}: "${task.title}" — ${prompt.length} chars`);
102
- return executor.execute(prompt, options);
111
+ return retryExecute(executor, prompt, options, retryOpts);
103
112
  }));
104
113
  for (let j = 0; j < results.length; j++) {
105
114
  log.info(` [parallel] Task ${phaseTasks[j].id} complete (${results[j].result.length} chars)`);
@@ -109,10 +118,11 @@ export function createImplementNode(executor) {
109
118
  // Sequential: single executor call with all phase tasks
110
119
  const prompt = buildImplementPhasePrompt(state, phase, phaseTasks, promptContext);
111
120
  log.info(`Executing phase prompt — ${prompt.length} chars`);
112
- const result = await executor.execute(prompt, options);
121
+ const result = await retryExecute(executor, prompt, options, retryOpts);
113
122
  log.info(`Phase complete (${result.result.length} chars)`);
114
123
  }
115
124
  completedTasks += phaseTasks.length;
125
+ markPhaseComplete(state.specDir, phase.id, log);
116
126
  const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
117
127
  messages.push(`[implement] Phase ${phase.id} "${phase.name}" — ${phaseTasks.length} task(s) done (${elapsed}s)`);
118
128
  updateFeatureProgress(state.specDir, completedTasks, totalTasks, `implementing-${phase.id}`, null, log);
@@ -137,11 +147,10 @@ export function createImplementNode(executor) {
137
147
  const message = err instanceof Error ? err.message : String(err);
138
148
  const elapsed = ((Date.now() - startTime) / 1000).toFixed(1);
139
149
  log.error(`${message} (after ${elapsed}s)`);
140
- return {
141
- currentNode: 'implement',
142
- error: message,
143
- messages: [...messages, `[implement] Error: ${message}`],
144
- };
150
+ // Throw so LangGraph does NOT checkpoint this node as "completed".
151
+ // The worker catch block marks the run as failed, and on resume
152
+ // LangGraph re-executes from the last successfully checkpointed node.
153
+ throw new Error(`[implement] ${message}`);
145
154
  }
146
155
  };
147
156
  }
@@ -4,7 +4,7 @@
4
4
  * Provides consistent logging, spec file reading, executor invocation,
5
5
  * and error handling so every node follows the same patterns.
6
6
  */
7
- import type { IAgentExecutor, AgentExecutionOptions } from '../../../../../application/ports/output/agents/agent-executor.interface.js';
7
+ import type { IAgentExecutor, AgentExecutionOptions, AgentExecutionResult } from '../../../../../application/ports/output/agents/agent-executor.interface.js';
8
8
  import type { FeatureAgentState } from '../state.js';
9
9
  /**
10
10
  * Create a scoped logger that prefixes messages with the node name.
@@ -23,11 +23,51 @@ export declare function readSpecFile(specDir: string, filename: string): string;
23
23
  * Build executor options with cwd. Each node gets a clean agent context.
24
24
  */
25
25
  export declare function buildExecutorOptions(state: FeatureAgentState): AgentExecutionOptions;
26
+ /**
27
+ * Parse YAML with automatic sanitization of common AI-generated issues.
28
+ * First attempts normal parsing; on failure, sanitizes unquoted braces
29
+ * in list items and retries.
30
+ */
31
+ export declare function safeYamlLoad(content: string): unknown;
26
32
  /**
27
33
  * Determine whether the current node should trigger an interrupt
28
34
  * for human approval given the configured approval mode.
29
35
  */
30
36
  export declare function shouldInterrupt(nodeName: string, approvalMode: string | undefined): boolean;
37
+ export type ErrorCategory = 'retryable-api' | 'retryable-network' | 'non-retryable' | 'unknown';
38
+ /**
39
+ * Classify an error message into a retry category.
40
+ *
41
+ * - **retryable-api**: Transient API errors (rate-limit, overload, bad request)
42
+ * - **retryable-network**: Network-level failures (DNS, timeouts, connection refused)
43
+ * - **non-retryable**: Logic / filesystem / syntax errors that won't resolve on retry
44
+ * - **unknown**: Anything unrecognised (callers may choose to retry cautiously)
45
+ */
46
+ export declare function classifyError(errorMessage: string): ErrorCategory;
47
+ export interface RetryOptions {
48
+ /** Maximum number of execution attempts (default 3). */
49
+ maxAttempts?: number;
50
+ /** Base delay in ms before the first retry (default 2000). Doubles each retry. */
51
+ baseDelayMs?: number;
52
+ /** Optional logger for retry messages. */
53
+ logger?: NodeLogger;
54
+ }
55
+ /**
56
+ * Execute a prompt via the given executor with automatic retry and
57
+ * exponential back-off for transient errors.
58
+ *
59
+ * Non-retryable errors are thrown immediately. Unknown errors are
60
+ * retried (conservative stance: could be transient).
61
+ */
62
+ export declare function retryExecute(executor: IAgentExecutor, prompt: string, options: AgentExecutionOptions, retryOpts?: RetryOptions): Promise<AgentExecutionResult>;
63
+ /**
64
+ * Read completed phases from feature.yaml.
65
+ */
66
+ export declare function getCompletedPhases(specDir: string): string[];
67
+ /**
68
+ * Mark a phase as complete in feature.yaml by adding its ID to completedPhases.
69
+ */
70
+ export declare function markPhaseComplete(specDir: string, phaseId: string, log?: NodeLogger): void;
31
71
  /**
32
72
  * Execute a node with consistent logging and error handling.
33
73
  *
@@ -1 +1 @@
1
- {"version":3,"file":"node-helpers.d.ts","sourceRoot":"","sources":["../../../../../../../src/infrastructure/services/agents/feature-agent/nodes/node-helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EACtB,MAAM,+DAA+D,CAAC;AACvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGrD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM;kBAE/B,MAAM,GAAG,IAAI;mBAIZ,MAAM,GAAG,IAAI;EAK/B;AAED,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE7D;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMtE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,iBAAiB,GAAG,qBAAqB,CAIpF;AAUD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAI3F;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,cAAc,EACxB,WAAW,EAAE,CAAC,KAAK,EAAE,iBAAiB,EAAE,GAAG,EAAE,UAAU,KAAK,MAAM,GACjE,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAiDnE"}
1
+ {"version":3,"file":"node-helpers.d.ts","sourceRoot":"","sources":["../../../../../../../src/infrastructure/services/agents/feature-agent/nodes/node-helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EACrB,oBAAoB,EACrB,MAAM,+DAA+D,CAAC;AACvE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGrD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM;kBAE/B,MAAM,GAAG,IAAI;mBAIZ,MAAM,GAAG,IAAI;EAK/B;AAED,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE7D;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMtE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,iBAAiB,GAAG,qBAAqB,CAMpF;AAeD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAQrD;AAUD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAI3F;AAMD,MAAM,MAAM,aAAa,GAAG,eAAe,GAAG,mBAAmB,GAAG,eAAe,GAAG,SAAS,CAAC;AAMhG;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,aAAa,CAKjE;AAED,MAAM,WAAW,YAAY;IAC3B,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,QAAQ,EAAE,cAAc,EACxB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,qBAAqB,EAC9B,SAAS,CAAC,EAAE,YAAY,GACvB,OAAO,CAAC,oBAAoB,CAAC,CA6B/B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAW5D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,UAAU,GAAG,IAAI,CAwB1F;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,cAAc,EACxB,WAAW,EAAE,CAAC,KAAK,EAAE,iBAAiB,EAAE,GAAG,EAAE,UAAU,KAAK,MAAM,GACjE,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAgDnE"}