@fixy/code 0.0.3 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,11 +1,16 @@
1
1
  #!/usr/bin/env node
2
2
  import path from 'node:path';
3
3
  import fs from 'node:fs/promises';
4
+ import { readFileSync } from 'node:fs';
5
+ import { fileURLToPath } from 'node:url';
4
6
  import { LocalThreadStore, AdapterRegistry, TurnController, WorktreeManager } from '@fixy/core';
5
7
  import { createClaudeAdapter } from '@fixy/claude-adapter';
6
8
  import { createCodexAdapter } from '@fixy/codex-adapter';
7
- import { banner } from './format.js';
9
+ import { startupPanel } from './format.js';
8
10
  import { startRepl } from './repl.js';
11
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
12
+ const pkg = JSON.parse(readFileSync(path.join(__dirname, '../package.json'), 'utf8'));
13
+ const version = pkg.version;
9
14
  async function findGitRoot(dir) {
10
15
  let current = dir;
11
16
  while (true) {
@@ -28,7 +33,6 @@ async function main() {
28
33
  process.exit(1);
29
34
  }
30
35
  const projectRoot = gitRoot;
31
- // Parse args: --thread <id>
32
36
  let threadId;
33
37
  const args = process.argv.slice(2);
34
38
  for (let i = 0; i < args.length; i++) {
@@ -46,9 +50,10 @@ async function main() {
46
50
  const thread = threadId
47
51
  ? await store.getThread(threadId, projectRoot)
48
52
  : await store.createThread(projectRoot);
49
- console.log(banner('0.0.0', registry.list().map((a) => a.id)));
50
- console.log(`thread: ${thread.id}`);
51
- await startRepl({ thread, store, registry, worktreeManager, turnController });
53
+ if (process.stdout.isTTY)
54
+ process.stdout.write('\x1b[2J\x1b[H');
55
+ process.stdout.write(startupPanel(version, registry.list().map((a) => a.id), projectRoot, thread.id) + '\n');
56
+ await startRepl({ thread, store, registry, worktreeManager, turnController, version, projectRoot });
52
57
  }
53
58
  main().catch((err) => {
54
59
  console.error(err);
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/dist/format.d.ts CHANGED
@@ -1,4 +1,9 @@
1
1
  export declare function agentColor(agentId: string): (text: string) => string;
2
2
  export declare function formatPrefix(agentId: string): string;
3
- export declare function banner(version: string, adapters: string[]): string;
3
+ export declare const PROMPT = "\u001B[33m\u276F\u001B[0m ";
4
+ export declare function startupPanel(version: string, adapters: string[], projectRoot: string, threadId: string): string;
5
+ export declare function createSpinner(): {
6
+ start(label: string): void;
7
+ stop(): void;
8
+ };
4
9
  //# sourceMappingURL=format.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AASA,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAIpE;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,wBAAgB,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,GAAG,MAAM,CAIlE"}
1
+ {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAeA,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAIpE;AAED,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAEpD;AAED,eAAO,MAAM,MAAM,gCAA6B,CAAC;AAEjD,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAAE,EAClB,WAAW,EAAE,MAAM,EACnB,QAAQ,EAAE,MAAM,GACf,MAAM,CA4BR;AAED,wBAAgB,aAAa,IAAI;IAAE,KAAK,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,IAAI,IAAI,IAAI,CAAA;CAAE,CA6B5E"}
package/dist/format.js CHANGED
@@ -1,9 +1,14 @@
1
+ import os from 'node:os';
2
+ import path from 'node:path';
1
3
  const RESET = '\x1b[0m';
4
+ const DIM = '\x1b[2m';
5
+ const BOLD = '\x1b[1m';
6
+ const FIXY_COLOR = '\x1b[33m';
2
7
  const COLORS = {
3
8
  claude: '\x1b[34m',
4
9
  codex: '\x1b[32m',
5
- fixy: '\x1b[33m',
6
- system: '\x1b[2m',
10
+ fixy: FIXY_COLOR,
11
+ system: DIM,
7
12
  };
8
13
  export function agentColor(agentId) {
9
14
  const code = COLORS[agentId];
@@ -14,9 +19,56 @@ export function agentColor(agentId) {
14
19
  export function formatPrefix(agentId) {
15
20
  return agentColor(agentId)(`[${agentId}]`);
16
21
  }
17
- export function banner(version, adapters) {
18
- const adapterList = adapters.map((a) => `@${a}`).join(', ');
19
- const text = `fixy v${version} ${adapterList} ready`;
20
- return agentColor('fixy')(text);
22
+ export const PROMPT = `${FIXY_COLOR}❯${RESET} `;
23
+ export function startupPanel(version, adapters, projectRoot, threadId) {
24
+ const cols = Math.max(Math.min(process.stdout.columns ?? 80, 80), 52);
25
+ const innerWidth = cols - 2;
26
+ const homeDir = os.homedir();
27
+ const rel = path.relative(homeDir, projectRoot);
28
+ const dirDisplay = rel.startsWith('..') ? projectRoot : `~/${rel}`;
29
+ const contentLines = [
30
+ `${BOLD}${FIXY_COLOR}Fixy v${version}${RESET}`,
31
+ `${DIM}agents: ${adapters.map((a) => `@${a}`).join(' · ')}${RESET}`,
32
+ `${DIM}directory: ${dirDisplay}${RESET}`,
33
+ `${DIM}thread: ${threadId}${RESET}`,
34
+ ];
35
+ const visibleLen = (s) => s.replace(/\x1b\[[0-9;]*m/g, '').length;
36
+ const padLine = (line) => {
37
+ const vl = visibleLen(line);
38
+ const available = innerWidth - 2; // 1 space on each side
39
+ const spaces = Math.max(0, available - vl);
40
+ return `${FIXY_COLOR}│${RESET} ${line}${' '.repeat(spaces)} ${FIXY_COLOR}│${RESET}`;
41
+ };
42
+ const top = `${FIXY_COLOR}╭${'─'.repeat(innerWidth)}╮${RESET}`;
43
+ const bottom = `${FIXY_COLOR}╰${'─'.repeat(innerWidth)}╯${RESET}`;
44
+ return [top, ...contentLines.map(padLine), bottom].join('\n');
45
+ }
46
+ export function createSpinner() {
47
+ const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
48
+ let intervalId = null;
49
+ let frameIndex = 0;
50
+ if (!process.stdout.isTTY) {
51
+ return {
52
+ start: (_label) => { },
53
+ stop: () => { },
54
+ };
55
+ }
56
+ return {
57
+ start(label) {
58
+ frameIndex = 0;
59
+ intervalId = setInterval(() => {
60
+ const frame = frames[frameIndex % frames.length] ?? frames[0] ?? '⠋';
61
+ process.stdout.write(`\r${FIXY_COLOR}${frame}${RESET} ${label}`);
62
+ frameIndex++;
63
+ }, 100);
64
+ },
65
+ stop() {
66
+ if (intervalId !== null) {
67
+ clearInterval(intervalId);
68
+ intervalId = null;
69
+ }
70
+ process.stdout.write('\r\x1b[2K');
71
+ },
72
+ };
21
73
  }
22
74
  //# sourceMappingURL=format.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA,MAAM,KAAK,GAAG,SAAS,CAAC;AAExB,MAAM,MAAM,GAA2B;IACrC,MAAM,EAAE,UAAU;IAClB,KAAK,EAAE,UAAU;IACjB,IAAI,EAAE,UAAU;IAChB,MAAM,EAAE,SAAS;CAClB,CAAC;AAEF,MAAM,UAAU,UAAU,CAAC,OAAe;IACxC,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAC7B,IAAI,CAAC,IAAI;QAAE,OAAO,CAAC,IAAY,EAAE,EAAE,CAAC,IAAI,CAAC;IACzC,OAAO,CAAC,IAAY,EAAE,EAAE,CAAC,GAAG,IAAI,GAAG,IAAI,GAAG,KAAK,EAAE,CAAC;AACpD,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,OAAe;IAC1C,OAAO,UAAU,CAAC,OAAO,CAAC,CAAC,IAAI,OAAO,GAAG,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,OAAe,EAAE,QAAkB;IACxD,MAAM,WAAW,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC5D,MAAM,IAAI,GAAG,SAAS,OAAO,MAAM,WAAW,QAAQ,CAAC;IACvD,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC;AAClC,CAAC"}
1
+ {"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"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"}
package/dist/repl.d.ts CHANGED
@@ -5,6 +5,8 @@ export interface ReplParams {
5
5
  registry: AdapterRegistry;
6
6
  worktreeManager: WorktreeManager;
7
7
  turnController: TurnController;
8
+ version: string;
9
+ projectRoot: string;
8
10
  }
9
11
  export declare function startRepl(params: ReplParams): Promise<void>;
10
12
  //# sourceMappingURL=repl.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"repl.d.ts","sourceRoot":"","sources":["../src/repl.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,UAAU,EACV,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,eAAe,EAChB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,gBAAgB,CAAC;IACxB,QAAQ,EAAE,eAAe,CAAC;IAC1B,eAAe,EAAE,eAAe,CAAC;IACjC,cAAc,EAAE,cAAc,CAAC;CAChC;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAkGjE"}
1
+ {"version":3,"file":"repl.d.ts","sourceRoot":"","sources":["../src/repl.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,UAAU,EACV,gBAAgB,EAChB,eAAe,EACf,cAAc,EACd,eAAe,EAChB,MAAM,YAAY,CAAC;AAGpB,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,EAAE,gBAAgB,CAAC;IACxB,QAAQ,EAAE,eAAe,CAAC;IAC1B,eAAe,EAAE,eAAe,CAAC;IACjC,cAAc,EAAE,cAAc,CAAC;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAiGjE"}
package/dist/repl.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import readline from 'node:readline';
2
+ import { PROMPT, createSpinner } from './format.js';
2
3
  export async function startRepl(params) {
3
4
  const { store, registry, worktreeManager, turnController } = params;
4
5
  let thread = params.thread;
@@ -9,42 +10,41 @@ export async function startRepl(params) {
9
10
  output: process.stdout,
10
11
  terminal: process.stdin.isTTY ?? false,
11
12
  });
12
- // Ctrl-C: first press aborts active turn, second press (or idle) exits
13
13
  process.on('SIGINT', () => {
14
14
  if (turnActive && turnAbort) {
15
15
  turnAbort.abort();
16
16
  turnAbort = null;
17
17
  turnActive = false;
18
- process.stdout.write('\n(turn cancelled)\n');
18
+ process.stdout.write('\x1b[33m(turn cancelled)\x1b[0m\n');
19
19
  }
20
20
  else {
21
- console.log('\nbye');
21
+ process.stdout.write('\x1b[2mgoodbye\x1b[0m\n');
22
22
  process.exit(0);
23
23
  }
24
24
  });
25
25
  const ask = () => new Promise((resolve) => {
26
- rl.question('fixy> ', (answer) => resolve(answer));
26
+ rl.question(PROMPT, (answer) => resolve(answer));
27
27
  rl.once('close', () => resolve(null));
28
28
  });
29
29
  while (true) {
30
30
  const line = await ask();
31
- // Ctrl-D or stream closed
32
31
  if (line === null) {
33
- console.log('bye');
32
+ process.stdout.write('\x1b[2mgoodbye\x1b[0m\n');
34
33
  break;
35
34
  }
36
35
  const input = line.trim();
37
36
  if (input.length === 0)
38
37
  continue;
39
38
  if (input === '/quit' || input === '/exit') {
40
- console.log('bye');
39
+ process.stdout.write('\x1b[2mgoodbye\x1b[0m\n');
41
40
  break;
42
41
  }
43
42
  turnAbort = new AbortController();
44
43
  turnActive = true;
44
+ const spinner = createSpinner();
45
45
  try {
46
- // Re-read thread from disk to get latest state
47
46
  thread = await store.getThread(thread.id, thread.projectRoot);
47
+ spinner.start('thinking...');
48
48
  await turnController.runTurn({
49
49
  thread,
50
50
  input,
@@ -56,14 +56,11 @@ export async function startRepl(params) {
56
56
  signal: turnAbort.signal,
57
57
  worktreeManager,
58
58
  });
59
- // Re-read thread after turn to pick up new messages/sessions
60
59
  thread = await store.getThread(thread.id, thread.projectRoot);
61
- // Print system messages (from @fixy commands like /status, /worker, /reset)
62
60
  const lastMsg = thread.messages[thread.messages.length - 1];
63
61
  if (lastMsg && lastMsg.role === 'system') {
64
62
  process.stdout.write(`\n${lastMsg.content}\n`);
65
63
  }
66
- // Print warnings from the latest agent message
67
64
  if (lastMsg && lastMsg.warnings.length > 0) {
68
65
  for (const w of lastMsg.warnings) {
69
66
  process.stderr.write(`warning: ${w}\n`);
@@ -72,14 +69,15 @@ export async function startRepl(params) {
72
69
  }
73
70
  catch (err) {
74
71
  if (turnAbort.signal.aborted) {
75
- // Turn was cancelled by Ctrl-C, already handled
72
+ // cancelled by Ctrl-C, already handled
76
73
  }
77
74
  else {
78
75
  const msg = err instanceof Error ? err.message : String(err);
79
- process.stderr.write(`error: ${msg}\n`);
76
+ process.stderr.write(`\x1b[31merror:\x1b[0m ${msg}\n`);
80
77
  }
81
78
  }
82
79
  finally {
80
+ spinner.stop();
83
81
  turnActive = false;
84
82
  turnAbort = null;
85
83
  }
package/dist/repl.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"repl.js","sourceRoot":"","sources":["../src/repl.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"repl.js","sourceRoot":"","sources":["../src/repl.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fixy/code",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "fixy": "./dist/cli.js"
@@ -8,13 +8,13 @@
8
8
  "main": "./dist/cli.js",
9
9
  "types": "./dist/cli.d.ts",
10
10
  "dependencies": {
11
- "@fixy/core": "0.0.3",
12
- "@fixy/adapter-utils": "0.0.3",
13
- "@fixy/claude-adapter": "0.0.3",
14
- "@fixy/codex-adapter": "0.0.3"
11
+ "@fixy/core": "0.0.5",
12
+ "@fixy/claude-adapter": "0.0.5",
13
+ "@fixy/codex-adapter": "0.0.5",
14
+ "@fixy/adapter-utils": "0.0.5"
15
15
  },
16
16
  "devDependencies": {
17
- "@types/node": "^22.0.0"
17
+ "@types/node": "^25.6.0"
18
18
  },
19
19
  "license": "MIT",
20
20
  "scripts": {
package/src/cli.ts CHANGED
@@ -1,12 +1,20 @@
1
1
  #!/usr/bin/env node
2
2
  import path from 'node:path';
3
3
  import fs from 'node:fs/promises';
4
+ import { readFileSync } from 'node:fs';
5
+ import { fileURLToPath } from 'node:url';
4
6
  import { LocalThreadStore, AdapterRegistry, TurnController, WorktreeManager } from '@fixy/core';
5
7
  import { createClaudeAdapter } from '@fixy/claude-adapter';
6
8
  import { createCodexAdapter } from '@fixy/codex-adapter';
7
- import { banner } from './format.js';
9
+ import { startupPanel } from './format.js';
8
10
  import { startRepl } from './repl.js';
9
11
 
12
+ const __dirname = path.dirname(fileURLToPath(import.meta.url));
13
+ const pkg = JSON.parse(
14
+ readFileSync(path.join(__dirname, '../package.json'), 'utf8'),
15
+ ) as { version: string };
16
+ const version = pkg.version;
17
+
10
18
  async function findGitRoot(dir: string): Promise<string | null> {
11
19
  let current = dir;
12
20
  while (true) {
@@ -31,7 +39,6 @@ async function main(): Promise<void> {
31
39
  }
32
40
  const projectRoot: string = gitRoot;
33
41
 
34
- // Parse args: --thread <id>
35
42
  let threadId: string | undefined;
36
43
  const args = process.argv.slice(2);
37
44
  for (let i = 0; i < args.length; i++) {
@@ -54,15 +61,18 @@ async function main(): Promise<void> {
54
61
  ? await store.getThread(threadId, projectRoot)
55
62
  : await store.createThread(projectRoot);
56
63
 
57
- console.log(
58
- banner(
59
- '0.0.0',
64
+ if (process.stdout.isTTY) process.stdout.write('\x1b[2J\x1b[H');
65
+
66
+ process.stdout.write(
67
+ startupPanel(
68
+ version,
60
69
  registry.list().map((a) => a.id),
61
- ),
70
+ projectRoot,
71
+ thread.id,
72
+ ) + '\n',
62
73
  );
63
- console.log(`thread: ${thread.id}`);
64
74
 
65
- await startRepl({ thread, store, registry, worktreeManager, turnController });
75
+ await startRepl({ thread, store, registry, worktreeManager, turnController, version, projectRoot });
66
76
  }
67
77
 
68
78
  main().catch((err) => {
package/src/format.ts CHANGED
@@ -1,10 +1,16 @@
1
+ import os from 'node:os';
2
+ import path from 'node:path';
3
+
1
4
  const RESET = '\x1b[0m';
5
+ const DIM = '\x1b[2m';
6
+ const BOLD = '\x1b[1m';
7
+ const FIXY_COLOR = '\x1b[33m';
2
8
 
3
9
  const COLORS: Record<string, string> = {
4
10
  claude: '\x1b[34m',
5
11
  codex: '\x1b[32m',
6
- fixy: '\x1b[33m',
7
- system: '\x1b[2m',
12
+ fixy: FIXY_COLOR,
13
+ system: DIM,
8
14
  };
9
15
 
10
16
  export function agentColor(agentId: string): (text: string) => string {
@@ -17,8 +23,70 @@ export function formatPrefix(agentId: string): string {
17
23
  return agentColor(agentId)(`[${agentId}]`);
18
24
  }
19
25
 
20
- export function banner(version: string, adapters: string[]): string {
21
- const adapterList = adapters.map((a) => `@${a}`).join(', ');
22
- const text = `fixy v${version} — ${adapterList} ready`;
23
- return agentColor('fixy')(text);
26
+ export const PROMPT = `${FIXY_COLOR}❯${RESET} `;
27
+
28
+ export function startupPanel(
29
+ version: string,
30
+ adapters: string[],
31
+ projectRoot: string,
32
+ threadId: string,
33
+ ): string {
34
+ const cols = Math.max(Math.min(process.stdout.columns ?? 80, 80), 52);
35
+ const innerWidth = cols - 2;
36
+
37
+ const homeDir = os.homedir();
38
+ const rel = path.relative(homeDir, projectRoot);
39
+ const dirDisplay = rel.startsWith('..') ? projectRoot : `~/${rel}`;
40
+
41
+ const contentLines: string[] = [
42
+ `${BOLD}${FIXY_COLOR}Fixy v${version}${RESET}`,
43
+ `${DIM}agents: ${adapters.map((a) => `@${a}`).join(' · ')}${RESET}`,
44
+ `${DIM}directory: ${dirDisplay}${RESET}`,
45
+ `${DIM}thread: ${threadId}${RESET}`,
46
+ ];
47
+
48
+ const visibleLen = (s: string): number => s.replace(/\x1b\[[0-9;]*m/g, '').length;
49
+
50
+ const padLine = (line: string): string => {
51
+ const vl = visibleLen(line);
52
+ const available = innerWidth - 2; // 1 space on each side
53
+ const spaces = Math.max(0, available - vl);
54
+ return `${FIXY_COLOR}│${RESET} ${line}${' '.repeat(spaces)} ${FIXY_COLOR}│${RESET}`;
55
+ };
56
+
57
+ const top = `${FIXY_COLOR}╭${'─'.repeat(innerWidth)}╮${RESET}`;
58
+ const bottom = `${FIXY_COLOR}╰${'─'.repeat(innerWidth)}╯${RESET}`;
59
+
60
+ return [top, ...contentLines.map(padLine), bottom].join('\n');
61
+ }
62
+
63
+ export function createSpinner(): { start(label: string): void; stop(): void } {
64
+ const frames = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧', '⠇', '⠏'];
65
+ let intervalId: ReturnType<typeof setInterval> | null = null;
66
+ let frameIndex = 0;
67
+
68
+ if (!process.stdout.isTTY) {
69
+ return {
70
+ start: (_label: string) => {},
71
+ stop: () => {},
72
+ };
73
+ }
74
+
75
+ return {
76
+ start(label: string): void {
77
+ frameIndex = 0;
78
+ intervalId = setInterval(() => {
79
+ const frame = frames[frameIndex % frames.length] ?? frames[0] ?? '⠋';
80
+ process.stdout.write(`\r${FIXY_COLOR}${frame}${RESET} ${label}`);
81
+ frameIndex++;
82
+ }, 100);
83
+ },
84
+ stop(): void {
85
+ if (intervalId !== null) {
86
+ clearInterval(intervalId);
87
+ intervalId = null;
88
+ }
89
+ process.stdout.write('\r\x1b[2K');
90
+ },
91
+ };
24
92
  }
package/src/repl.ts CHANGED
@@ -6,6 +6,7 @@ import type {
6
6
  TurnController,
7
7
  WorktreeManager,
8
8
  } from '@fixy/core';
9
+ import { PROMPT, createSpinner } from './format.js';
9
10
 
10
11
  export interface ReplParams {
11
12
  thread: FixyThread;
@@ -13,6 +14,8 @@ export interface ReplParams {
13
14
  registry: AdapterRegistry;
14
15
  worktreeManager: WorktreeManager;
15
16
  turnController: TurnController;
17
+ version: string;
18
+ projectRoot: string;
16
19
  }
17
20
 
18
21
  export async function startRepl(params: ReplParams): Promise<void> {
@@ -28,31 +31,29 @@ export async function startRepl(params: ReplParams): Promise<void> {
28
31
  terminal: process.stdin.isTTY ?? false,
29
32
  });
30
33
 
31
- // Ctrl-C: first press aborts active turn, second press (or idle) exits
32
34
  process.on('SIGINT', () => {
33
35
  if (turnActive && turnAbort) {
34
36
  turnAbort.abort();
35
37
  turnAbort = null;
36
38
  turnActive = false;
37
- process.stdout.write('\n(turn cancelled)\n');
39
+ process.stdout.write('\x1b[33m(turn cancelled)\x1b[0m\n');
38
40
  } else {
39
- console.log('\nbye');
41
+ process.stdout.write('\x1b[2mgoodbye\x1b[0m\n');
40
42
  process.exit(0);
41
43
  }
42
44
  });
43
45
 
44
46
  const ask = (): Promise<string | null> =>
45
47
  new Promise((resolve) => {
46
- rl.question('fixy> ', (answer) => resolve(answer));
48
+ rl.question(PROMPT, (answer) => resolve(answer));
47
49
  rl.once('close', () => resolve(null));
48
50
  });
49
51
 
50
52
  while (true) {
51
53
  const line = await ask();
52
54
 
53
- // Ctrl-D or stream closed
54
55
  if (line === null) {
55
- console.log('bye');
56
+ process.stdout.write('\x1b[2mgoodbye\x1b[0m\n');
56
57
  break;
57
58
  }
58
59
 
@@ -60,17 +61,20 @@ export async function startRepl(params: ReplParams): Promise<void> {
60
61
  if (input.length === 0) continue;
61
62
 
62
63
  if (input === '/quit' || input === '/exit') {
63
- console.log('bye');
64
+ process.stdout.write('\x1b[2mgoodbye\x1b[0m\n');
64
65
  break;
65
66
  }
66
67
 
67
68
  turnAbort = new AbortController();
68
69
  turnActive = true;
69
70
 
71
+ const spinner = createSpinner();
72
+
70
73
  try {
71
- // Re-read thread from disk to get latest state
72
74
  thread = await store.getThread(thread.id, thread.projectRoot);
73
75
 
76
+ spinner.start('thinking...');
77
+
74
78
  await turnController.runTurn({
75
79
  thread,
76
80
  input,
@@ -83,16 +87,13 @@ export async function startRepl(params: ReplParams): Promise<void> {
83
87
  worktreeManager,
84
88
  });
85
89
 
86
- // Re-read thread after turn to pick up new messages/sessions
87
90
  thread = await store.getThread(thread.id, thread.projectRoot);
88
91
 
89
- // Print system messages (from @fixy commands like /status, /worker, /reset)
90
92
  const lastMsg = thread.messages[thread.messages.length - 1];
91
93
  if (lastMsg && lastMsg.role === 'system') {
92
94
  process.stdout.write(`\n${lastMsg.content}\n`);
93
95
  }
94
96
 
95
- // Print warnings from the latest agent message
96
97
  if (lastMsg && lastMsg.warnings.length > 0) {
97
98
  for (const w of lastMsg.warnings) {
98
99
  process.stderr.write(`warning: ${w}\n`);
@@ -100,12 +101,13 @@ export async function startRepl(params: ReplParams): Promise<void> {
100
101
  }
101
102
  } catch (err) {
102
103
  if (turnAbort.signal.aborted) {
103
- // Turn was cancelled by Ctrl-C, already handled
104
+ // cancelled by Ctrl-C, already handled
104
105
  } else {
105
106
  const msg = err instanceof Error ? err.message : String(err);
106
- process.stderr.write(`error: ${msg}\n`);
107
+ process.stderr.write(`\x1b[31merror:\x1b[0m ${msg}\n`);
107
108
  }
108
109
  } finally {
110
+ spinner.stop();
109
111
  turnActive = false;
110
112
  turnAbort = null;
111
113
  }