@ariso-ai/ivan 1.0.37 → 1.0.39

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.
@@ -0,0 +1,332 @@
1
+ import readline from 'readline';
2
+ import chalk from 'chalk';
3
+ import ora from 'ora';
4
+ /**
5
+ * Captures additional context the user types while an Ivan command is running,
6
+ * similar to interjecting in an interactive Claude Code session.
7
+ *
8
+ * Input is read in raw mode with the echo rendered by this class on its own
9
+ * input line — a spinner redrawing its line would otherwise wipe the
10
+ * terminal's native echo, making typing invisible. While the user is
11
+ * composing, the active spinner (registered via claudeSpinner) is paused, and
12
+ * resumed when the input is submitted or cancelled.
13
+ *
14
+ * Each submitted line is either delivered immediately to a live listener (the
15
+ * SDK executor streams it into the running session mid-turn) or buffered until
16
+ * the next turn starts (the CLI executor applies it in an automatic follow-up
17
+ * turn).
18
+ */
19
+ export class InterjectionManager {
20
+ static instance = null;
21
+ static getInstance() {
22
+ if (!InterjectionManager.instance) {
23
+ InterjectionManager.instance = new InterjectionManager();
24
+ }
25
+ return InterjectionManager.instance;
26
+ }
27
+ refCount = 0;
28
+ listening = false;
29
+ keypressAttached = false;
30
+ rawModeSet = false;
31
+ buffer = '';
32
+ pending = [];
33
+ liveListener = null;
34
+ hintShown = false;
35
+ activeSpinner = null;
36
+ pausedSpinner = null;
37
+ keypressHandler = (str, key) => this.handleKeypress(str, key);
38
+ selfWrite = false;
39
+ inputLineVisible = false;
40
+ externalMidLine = false;
41
+ unhookStreams = null;
42
+ /** Interjections require an interactive terminal. */
43
+ isAvailable() {
44
+ return Boolean(process.stdin.isTTY);
45
+ }
46
+ /**
47
+ * Begin capturing keystrokes. Ref-counted so overlapping turns can
48
+ * start/stop freely; the listener is only torn down when the outermost
49
+ * stop() is reached.
50
+ */
51
+ start(quiet = false) {
52
+ if (!this.isAvailable())
53
+ return;
54
+ this.refCount++;
55
+ if (this.listening)
56
+ return;
57
+ this.listening = true;
58
+ if (!this.keypressAttached) {
59
+ readline.emitKeypressEvents(process.stdin);
60
+ this.keypressAttached = true;
61
+ }
62
+ if (typeof process.stdin.setRawMode === 'function') {
63
+ process.stdin.setRawMode(true);
64
+ this.rawModeSet = true;
65
+ }
66
+ process.stdin.on('keypress', this.keypressHandler);
67
+ process.stdin.resume();
68
+ this.hookOutputStreams();
69
+ if (!this.hintShown && !quiet) {
70
+ console.log(chalk.cyan('💬 Type a message and press Enter at any time to give Ivan additional context'));
71
+ this.hintShown = true;
72
+ }
73
+ }
74
+ /** Stop capturing keystrokes once all active turns have finished. */
75
+ stop() {
76
+ if (!this.isAvailable())
77
+ return;
78
+ if (this.refCount > 0)
79
+ this.refCount--;
80
+ if (this.refCount === 0 && this.listening) {
81
+ this.listening = false;
82
+ process.stdin.removeListener('keypress', this.keypressHandler);
83
+ if (this.rawModeSet) {
84
+ process.stdin.setRawMode(false);
85
+ this.rawModeSet = false;
86
+ }
87
+ // Release stdin so the process can exit and later prompts (inquirer)
88
+ // get a clean stream.
89
+ process.stdin.pause();
90
+ // Abandon any partially typed input and restore the spinner.
91
+ if (this.buffer) {
92
+ this.buffer = '';
93
+ this.clearInputLine();
94
+ }
95
+ this.unhookStreams?.();
96
+ this.unhookStreams = null;
97
+ this.resumeSpinner();
98
+ }
99
+ }
100
+ /**
101
+ * While the user is composing, the `💬 > ` echo owns the cursor row with no
102
+ * trailing newline — anything the executors print (tool-usage lines,
103
+ * streamed CLI output) would land right after the typed text and shove the
104
+ * echo onto a new line. Intercept stdout/stderr so external output clears
105
+ * the echo, prints on its own line, and the echo is redrawn beneath it.
106
+ */
107
+ hookOutputStreams() {
108
+ if (this.unhookStreams)
109
+ return;
110
+ const hook = (stream) => {
111
+ const original = stream.write.bind(stream);
112
+ const manager = this;
113
+ stream.write = function (chunk, encoding, callback) {
114
+ if (manager.selfWrite || manager.buffer.length === 0) {
115
+ return original(chunk, encoding, callback);
116
+ }
117
+ if (manager.inputLineVisible) {
118
+ manager.selfWrite = true;
119
+ original('\r\x1b[2K');
120
+ manager.selfWrite = false;
121
+ manager.inputLineVisible = false;
122
+ }
123
+ const result = original(chunk, encoding, callback);
124
+ const text = typeof chunk === 'string'
125
+ ? chunk
126
+ : globalThis.Buffer.from(chunk).toString('utf8');
127
+ if (text.length > 0) {
128
+ manager.externalMidLine = !text.endsWith('\n');
129
+ if (!manager.externalMidLine)
130
+ manager.render();
131
+ }
132
+ return result;
133
+ };
134
+ return () => {
135
+ stream.write = original;
136
+ };
137
+ };
138
+ const unhookStdout = hook(process.stdout);
139
+ const unhookStderr = hook(process.stderr);
140
+ this.unhookStreams = () => {
141
+ unhookStdout();
142
+ unhookStderr();
143
+ };
144
+ }
145
+ /**
146
+ * Registers the spinner currently rendering so it can be paused while the
147
+ * user types (its line redraws would erase the input echo otherwise).
148
+ */
149
+ attachSpinner(spinner) {
150
+ this.activeSpinner = spinner;
151
+ }
152
+ detachSpinner(spinner) {
153
+ if (this.activeSpinner === spinner)
154
+ this.activeSpinner = null;
155
+ if (this.pausedSpinner === spinner)
156
+ this.pausedSpinner = null;
157
+ }
158
+ /**
159
+ * Register a handler that receives interjections the moment they are typed
160
+ * (used by the SDK executor to stream them into the running session).
161
+ * Returns a release function; after release, new input buffers again.
162
+ */
163
+ setLiveListener(listener) {
164
+ this.liveListener = listener;
165
+ return () => {
166
+ if (this.liveListener === listener)
167
+ this.liveListener = null;
168
+ };
169
+ }
170
+ /** Returns and clears any buffered interjections. */
171
+ drainPending() {
172
+ return this.pending.splice(0);
173
+ }
174
+ /**
175
+ * Puts interjections back at the front of the buffer — used when a turn
176
+ * ends before delivering input it had already accepted.
177
+ */
178
+ requeue(texts) {
179
+ if (texts.length > 0)
180
+ this.pending.unshift(...texts);
181
+ }
182
+ hasPending() {
183
+ return this.pending.length > 0;
184
+ }
185
+ handleKeypress(str, key = {}) {
186
+ if (key.ctrl && key.name === 'c') {
187
+ // Raw mode suppresses the terminal's own SIGINT; re-emit it so the
188
+ // executors' Ctrl+C handlers still fire.
189
+ if (this.rawModeSet)
190
+ process.kill(process.pid, 'SIGINT');
191
+ return;
192
+ }
193
+ if (key.name === 'return' || key.name === 'enter') {
194
+ this.submit();
195
+ return;
196
+ }
197
+ if (key.name === 'backspace') {
198
+ if (this.buffer) {
199
+ this.buffer = this.buffer.slice(0, -1);
200
+ this.render();
201
+ }
202
+ return;
203
+ }
204
+ if (key.ctrl && key.name === 'u') {
205
+ this.buffer = '';
206
+ this.render();
207
+ return;
208
+ }
209
+ if (key.name === 'escape') {
210
+ this.buffer = '';
211
+ this.clearInputLine();
212
+ this.resumeSpinner();
213
+ return;
214
+ }
215
+ if (key.ctrl || key.meta)
216
+ return;
217
+ // Printable input only (pasted text arrives as a multi-char str).
218
+ if (!str)
219
+ return;
220
+ const printable = Array.from(str)
221
+ .filter((ch) => {
222
+ const code = ch.codePointAt(0) ?? 0;
223
+ return code >= 0x20 && code !== 0x7f;
224
+ })
225
+ .join('');
226
+ if (!printable)
227
+ return;
228
+ if (this.buffer.length === 0)
229
+ this.pauseSpinner();
230
+ this.buffer += printable;
231
+ this.render();
232
+ }
233
+ submit() {
234
+ const text = this.buffer.trim();
235
+ this.buffer = '';
236
+ this.clearInputLine();
237
+ if (text) {
238
+ if (this.liveListener) {
239
+ this.liveListener(text);
240
+ console.log(chalk.cyan('💬 Context sent to Claude — it will be incorporated into the current task'));
241
+ }
242
+ else {
243
+ this.pending.push(text);
244
+ console.log(chalk.cyan('💬 Context queued — Ivan will include it in the next turn'));
245
+ }
246
+ }
247
+ this.resumeSpinner();
248
+ }
249
+ /**
250
+ * Redraws the input line. The spinner is paused while composing, so this
251
+ * line owns the cursor row; hooked stdout/stderr writes clear and redraw it
252
+ * around any external output so the echo always sits on the bottom line.
253
+ */
254
+ render() {
255
+ if (!this.listening)
256
+ return;
257
+ this.selfWrite = true;
258
+ // If external output left the cursor mid-line, move past it instead of
259
+ // overwriting the partial line.
260
+ if (this.externalMidLine) {
261
+ process.stderr.write('\n');
262
+ this.externalMidLine = false;
263
+ }
264
+ process.stderr.write('\r\x1b[2K' + chalk.cyan('💬 > ') + this.buffer);
265
+ this.selfWrite = false;
266
+ this.inputLineVisible = true;
267
+ }
268
+ clearInputLine() {
269
+ this.selfWrite = true;
270
+ process.stderr.write('\r\x1b[2K');
271
+ this.selfWrite = false;
272
+ this.inputLineVisible = false;
273
+ }
274
+ pauseSpinner() {
275
+ const spinner = this.activeSpinner;
276
+ if (spinner && spinner.isSpinning) {
277
+ this.pausedSpinner = spinner;
278
+ spinner.stop();
279
+ }
280
+ }
281
+ resumeSpinner() {
282
+ // Only restart a spinner we paused ourselves that is still the active
283
+ // one — if the executor finished it (succeed/fail) while the user was
284
+ // typing, detachSpinner has already cleared it.
285
+ if (this.pausedSpinner && this.pausedSpinner === this.activeSpinner) {
286
+ this.pausedSpinner.start();
287
+ }
288
+ this.pausedSpinner = null;
289
+ }
290
+ }
291
+ /**
292
+ * Creates a spinner for phases where a Claude turn runs and interjections are
293
+ * being captured: stdin stays readable (no discardStdin) and the spinner is
294
+ * registered with the InterjectionManager so it pauses while the user types.
295
+ * Finishing the spinner (succeed/fail/warn/info/stopAndPersist) detaches it;
296
+ * plain stop() is left unwrapped because the manager itself uses it to pause.
297
+ */
298
+ export function claudeSpinner(text) {
299
+ const spinner = ora({ text, discardStdin: false });
300
+ const manager = InterjectionManager.getInstance();
301
+ manager.attachSpinner(spinner);
302
+ const finish = (fn) => (...args) => {
303
+ manager.detachSpinner(spinner);
304
+ return fn(...args);
305
+ };
306
+ spinner.succeed = finish(spinner.succeed.bind(spinner));
307
+ spinner.fail = finish(spinner.fail.bind(spinner));
308
+ spinner.warn = finish(spinner.warn.bind(spinner));
309
+ spinner.info = finish(spinner.info.bind(spinner));
310
+ spinner.stopAndPersist = finish(spinner.stopAndPersist.bind(spinner));
311
+ return spinner;
312
+ }
313
+ /**
314
+ * Appends buffered interjections to the initial prompt of the next turn.
315
+ */
316
+ export function appendInterjections(prompt, texts) {
317
+ if (texts.length === 0)
318
+ return prompt;
319
+ return `${prompt}\n\nAdditional context from the user (provided while Ivan was running — treat it as part of the task):\n${texts
320
+ .map((t) => `- ${t}`)
321
+ .join('\n')}`;
322
+ }
323
+ /**
324
+ * Formats interjections delivered as their own message — either streamed into
325
+ * a running SDK session or sent as a CLI follow-up turn.
326
+ */
327
+ export function interjectionMessage(texts) {
328
+ return `The user interjected with additional context while you were working:\n${texts
329
+ .map((t) => `- ${t}`)
330
+ .join('\n')}\nIncorporate this guidance into the task you are working on, adjusting anything you have already done if needed.`;
331
+ }
332
+ //# sourceMappingURL=interjection-manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interjection-manager.js","sourceRoot":"","sources":["../../src/services/interjection-manager.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"risk-analysis-executor.d.ts","sourceRoot":"","sources":["../../src/services/risk-analysis-executor.ts"],"names":[],"mappings":"AAmGA,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,cAAc,CAAkB;IACxC,OAAO,CAAC,iBAAiB,CAAqB;;IAOxC,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;YAuE7C,UAAU;CAqCzB"}
1
+ {"version":3,"file":"risk-analysis-executor.d.ts","sourceRoot":"","sources":["../../src/services/risk-analysis-executor.ts"],"names":[],"mappings":"AAmGA,qBAAa,oBAAoB;IAC/B,OAAO,CAAC,cAAc,CAAkB;IACxC,OAAO,CAAC,iBAAiB,CAAqB;;IAOxC,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;YAiF7C,UAAU;CAqCzB"}
@@ -1,7 +1,7 @@
1
1
  import chalk from 'chalk';
2
- import ora from 'ora';
3
2
  import { ExecutorFactory } from './executor-factory.js';
4
3
  import { createRepositoryManager } from './service-factory.js';
4
+ import { claudeSpinner } from './interjection-manager.js';
5
5
  const RISK_ANALYSIS_SYSTEM_PROMPT = `You are a principal engineer performing a pre-deployment risk analysis of a set of proposed changes.
6
6
 
7
7
  Your job is NOT to review code style or suggest improvements — it is to identify what could go wrong when these changes ship, how likely that is, how bad the blast radius would be, and what mitigations should be in place before rollout.
@@ -108,28 +108,30 @@ export class RiskAnalysisExecutor {
108
108
  // Suppress the executor's per-turn logging so the tree output stays readable
109
109
  this.claudeExecutor.quietMode = true;
110
110
  const changesSection = buildChangesSection(changes);
111
- const dimensionResults = [];
112
- for (const [i, dimension] of RISK_DIMENSIONS.entries()) {
113
- const branch = i === RISK_DIMENSIONS.length - 1 ? '└' : '├';
114
- const spinner = ora(`${branch} ${dimension.label}`).start();
115
- try {
111
+ // Run all dimensions concurrently. Individual per-dimension spinners
112
+ // aren't used here since ora/InterjectionManager only support a single
113
+ // active spinner at a time a batch spinner covers the parallel work.
114
+ const batchSpinner = claudeSpinner(`Analyzing ${RISK_DIMENSIONS.length} risk dimensions in parallel`).start();
115
+ let dimensionResults;
116
+ try {
117
+ dimensionResults = await Promise.all(RISK_DIMENSIONS.map(async (dimension) => {
116
118
  const result = await this.claudeExecutor.executeTurn(`${changesSection}\n\n${dimension.prompt}`, workingDir, {
117
119
  systemPrompt: RISK_ANALYSIS_SYSTEM_PROMPT,
118
120
  readOnly: true,
119
121
  permissionMode: 'plan'
120
122
  });
121
- dimensionResults.push({
122
- label: dimension.label,
123
- analysis: result.lastMessage
124
- });
125
- spinner.succeed(`${branch} ${dimension.label}`);
126
- }
127
- catch (err) {
128
- spinner.fail(`${branch} ${dimension.label}`);
129
- throw err;
123
+ return { label: dimension.label, analysis: result.lastMessage };
124
+ }));
125
+ batchSpinner.succeed(`Completed ${RISK_DIMENSIONS.length} risk dimension analyses`);
126
+ for (const { label } of dimensionResults) {
127
+ console.log(chalk.gray(` ✔ ${label}`));
130
128
  }
131
129
  }
132
- const synthesisSpinner = ora('Synthesizing final risk analysis').start();
130
+ catch (err) {
131
+ batchSpinner.fail('Risk dimension analysis failed');
132
+ throw err;
133
+ }
134
+ const synthesisSpinner = claudeSpinner('Synthesizing final risk analysis').start();
133
135
  let finalReport;
134
136
  try {
135
137
  finalReport = await this.synthesize(changes, dimensionResults, workingDir);
@@ -1 +1 @@
1
- {"version":3,"file":"risk-analysis-executor.js","sourceRoot":"","sources":["../../src/services/risk-analysis-executor.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"risk-analysis-executor.js","sourceRoot":"","sources":["../../src/services/risk-analysis-executor.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"task-executor.d.ts","sourceRoot":"","sources":["../../src/services/task-executor.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAa/E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AAOxE,qBAAa,YAAY;IACvB,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,UAAU,CAA4B;IAC9C,OAAO,CAAC,cAAc,CAAgC;IACtD,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,iBAAiB,CAAqB;IAC9C,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,gBAAgB,CAAqB;IAC7C,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,iBAAiB,CAAU;;IAanC;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAmBvB;;;;OAIG;YACW,iBAAiB;IA8B/B,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,gBAAgB;IAOxB;;;;OAIG;YACW,iBAAiB;IAgI/B;;;;OAIG;YACW,aAAa;IA2DrB,eAAe,CACnB,aAAa,GAAE,OAAe,EAC9B,UAAU,CAAC,EAAE,MAAM,EACnB,IAAI,GAAE,aAAwB,EAC9B,UAAU,GAAE,OAAe,EAC3B,cAAc,CAAC,EAAE,MAAM,EAAE,GACxB,OAAO,CAAC,IAAI,CAAC;YAyRF,0BAA0B;YA6D1B,WAAW;YAuMX,wBAAwB;IAuNhC,6BAA6B,CACjC,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,IAAI,CAAC;CAsJjB"}
1
+ {"version":3,"file":"task-executor.d.ts","sourceRoot":"","sources":["../../src/services/task-executor.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,oCAAoC,CAAC;AAc/E,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oCAAoC,CAAC;AAOxE,qBAAa,YAAY;IACvB,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,UAAU,CAA4B;IAC9C,OAAO,CAAC,cAAc,CAAgC;IACtD,OAAO,CAAC,aAAa,CAA8B;IACnD,OAAO,CAAC,iBAAiB,CAAqB;IAC9C,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,UAAU,CAAS;IAC3B,OAAO,CAAC,gBAAgB,CAAqB;IAC7C,OAAO,CAAC,UAAU,CAAqB;IACvC,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,iBAAiB,CAAU;;IAanC;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAmBvB;;;;OAIG;YACW,iBAAiB;IA8B/B,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,gBAAgB;IAOxB;;;;OAIG;YACW,iBAAiB;IAkI/B;;;;OAIG;YACW,aAAa;IA2DrB,eAAe,CACnB,aAAa,GAAE,OAAe,EAC9B,UAAU,CAAC,EAAE,MAAM,EACnB,IAAI,GAAE,aAAwB,EAC9B,UAAU,GAAE,OAAe,EAC3B,cAAc,CAAC,EAAE,MAAM,EAAE,GACxB,OAAO,CAAC,IAAI,CAAC;YAyRF,0BAA0B;YA6D1B,WAAW;YAwMX,wBAAwB;IAwNhC,6BAA6B,CACjC,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,IAAI,CAAC;CAsJjB"}
@@ -7,6 +7,7 @@ import { ConfigManager } from '../config.js';
7
7
  import { AddressTaskExecutor } from './address-task-executor.js';
8
8
  import { createGitManager, createPRService, createRepositoryManager } from './service-factory.js';
9
9
  import { PromptRewriter } from './prompt-rewriter.js';
10
+ import { claudeSpinner } from './interjection-manager.js';
10
11
  import { CollaborativeExecutor } from './collaborative-executor.js';
11
12
  const SELF_REVIEW_PROMPT = "ok review the changes in the current branch carefully. make sure it follows repo convention, reusable component/utils/etc. don't over-engineer, dont reinvent.";
12
13
  export class TaskExecutor {
@@ -144,7 +145,7 @@ export class TaskExecutor {
144
145
  // Prepare prompt for Claude to fix the errors
145
146
  const fixPrompt = `Fix the following pre-commit hook errors:\n\n${errorDetails}\n\nPlease fix all TypeScript errors, linting issues, and any other problems preventing the commit.`;
146
147
  if (!quiet)
147
- spinner = ora('Running Claude to fix pre-commit errors...').start();
148
+ spinner = claudeSpinner('Running Claude to fix pre-commit errors...').start();
148
149
  try {
149
150
  // Run Claude to fix the errors (pass session ID to maintain context)
150
151
  const fixResult = await this.getClaudeExecutor().executeTask(fixPrompt, executionPath, sessionId);
@@ -186,7 +187,7 @@ export class TaskExecutor {
186
187
  async runSelfReview(executionPath, taskUuid, quiet, sessionId) {
187
188
  let spinner = quiet
188
189
  ? null
189
- : ora('Running self-review with Claude Code...').start();
190
+ : claudeSpinner('Running self-review with Claude Code...').start();
190
191
  const reviewResult = await this.getClaudeExecutor().executeTask(SELF_REVIEW_PROMPT, executionPath, sessionId);
191
192
  sessionId = reviewResult.sessionId;
192
193
  if (spinner)
@@ -482,7 +483,7 @@ export class TaskExecutor {
482
483
  spinner.succeed(`Worktree created: ${worktreePath}`);
483
484
  await this.jobManager.updateTaskBranch(task.uuid, branchName);
484
485
  if (!quiet)
485
- spinner = ora('Executing task with Claude Code...').start();
486
+ spinner = claudeSpinner('Executing task with Claude Code...').start();
486
487
  // Append repository-specific instructions to the task if they exist
487
488
  let taskWithInstructions = task.description;
488
489
  if (this.repoInstructions) {
@@ -649,7 +650,7 @@ export class TaskExecutor {
649
650
  if (spinner)
650
651
  spinner.succeed('Task marked as active');
651
652
  if (!quiet)
652
- spinner = ora('Executing task with Claude Code...').start();
653
+ spinner = claudeSpinner('Executing task with Claude Code...').start();
653
654
  // Append repository-specific instructions to the task if they exist
654
655
  let taskWithInstructions = task.description;
655
656
  if (this.repoInstructions) {