@gowelle/stint-agent 1.2.32 → 1.2.34

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.
@@ -2,10 +2,10 @@ import {
2
2
  gitService,
3
3
  projectService,
4
4
  validatePidFile
5
- } from "./chunk-HCOIO2ND.js";
5
+ } from "./chunk-UB56ZQNI.js";
6
6
  import {
7
7
  authService
8
- } from "./chunk-6WYXA4IS.js";
8
+ } from "./chunk-BKJMUBZE.js";
9
9
 
10
10
  // src/components/StatusDashboard.tsx
11
11
  import { useState, useEffect } from "react";
@@ -0,0 +1,7 @@
1
+ import {
2
+ apiService
3
+ } from "./chunk-NEUK7ZZY.js";
4
+ import "./chunk-BKJMUBZE.js";
5
+ export {
6
+ apiService
7
+ };
@@ -180,6 +180,13 @@ var ERROR_LOG = path.join(LOG_DIR, "error.log");
180
180
  var MAX_LOG_SIZE = 10 * 1024 * 1024;
181
181
  var MAX_LOG_FILES = 7;
182
182
  var Logger = class {
183
+ consoleEnabled = true;
184
+ disableConsole() {
185
+ this.consoleEnabled = false;
186
+ }
187
+ enableConsole() {
188
+ this.consoleEnabled = true;
189
+ }
183
190
  ensureLogDir() {
184
191
  if (!fs.existsSync(LOG_DIR)) {
185
192
  fs.mkdirSync(LOG_DIR, { recursive: true });
@@ -212,17 +219,17 @@ var Logger = class {
212
219
  }
213
220
  info(category, message) {
214
221
  this.writeLog("INFO", category, message, AGENT_LOG);
215
- console.log(`\u2139 [${category}] ${message}`);
222
+ if (this.consoleEnabled) console.log(`\u2139 [${category}] ${message}`);
216
223
  }
217
224
  warn(category, message) {
218
225
  this.writeLog("WARN", category, message, AGENT_LOG);
219
- console.warn(`\u26A0 [${category}] ${message}`);
226
+ if (this.consoleEnabled) console.warn(`\u26A0 [${category}] ${message}`);
220
227
  }
221
228
  error(category, message, error) {
222
229
  const fullMessage = error ? `${message}: ${error.message}` : message;
223
230
  this.writeLog("ERROR", category, fullMessage, ERROR_LOG);
224
231
  this.writeLog("ERROR", category, fullMessage, AGENT_LOG);
225
- console.error(`\u2716 [${category}] ${fullMessage}`);
232
+ if (this.consoleEnabled) console.error(`\u2716 [${category}] ${fullMessage}`);
226
233
  if (error?.stack) {
227
234
  this.writeLog("ERROR", category, error.stack, ERROR_LOG);
228
235
  }
@@ -230,12 +237,12 @@ var Logger = class {
230
237
  debug(category, message) {
231
238
  if (process.env.DEBUG) {
232
239
  this.writeLog("DEBUG", category, message, AGENT_LOG);
233
- console.debug(`\u{1F41B} [${category}] ${message}`);
240
+ if (this.consoleEnabled) console.debug(`\u{1F41B} [${category}] ${message}`);
234
241
  }
235
242
  }
236
243
  success(category, message) {
237
244
  this.writeLog("INFO", category, message, AGENT_LOG);
238
- console.log(`\u2713 [${category}] ${message}`);
245
+ if (this.consoleEnabled) console.log(`\u2713 [${category}] ${message}`);
239
246
  }
240
247
  };
241
248
  var logger = new Logger();
@@ -308,7 +315,7 @@ var AuthServiceImpl = class {
308
315
  return null;
309
316
  }
310
317
  try {
311
- const { apiService } = await import("./api-MYPJRJLZ.js");
318
+ const { apiService } = await import("./api-TC3OYN5R.js");
312
319
  const user = await apiService.getCurrentUser();
313
320
  logger.info("auth", `Token validated for user: ${user.email}`);
314
321
  return user;
@@ -1,15 +1,15 @@
1
1
  import {
2
2
  apiService
3
- } from "./chunk-FHPSIVFK.js";
3
+ } from "./chunk-NEUK7ZZY.js";
4
4
  import {
5
5
  gitService,
6
6
  projectService
7
- } from "./chunk-HCOIO2ND.js";
7
+ } from "./chunk-UB56ZQNI.js";
8
8
  import {
9
9
  authService,
10
10
  config,
11
11
  logger
12
- } from "./chunk-6WYXA4IS.js";
12
+ } from "./chunk-BKJMUBZE.js";
13
13
 
14
14
  // src/utils/notify.ts
15
15
  import notifier from "node-notifier";
@@ -519,6 +519,7 @@ var WebSocketServiceImpl = class {
519
519
  maxReconnectAttempts = 10;
520
520
  reconnectTimer = null;
521
521
  isManualDisconnect = false;
522
+ currentPusherClient = null;
522
523
  // Event handlers
523
524
  commitApprovedHandlers = [];
524
525
  commitPendingHandlers = [];
@@ -532,10 +533,12 @@ var WebSocketServiceImpl = class {
532
533
  * @throws Error if connection fails or no auth token available
533
534
  */
534
535
  async connect() {
536
+ this.currentPusherClient = null;
535
537
  if (this.echo) {
536
538
  logger.debug("websocket", "Closing existing connection before reconnecting...");
537
539
  this.echo.disconnect();
538
540
  this.echo = null;
541
+ await new Promise((resolve) => setTimeout(resolve, 10));
539
542
  }
540
543
  try {
541
544
  const token = await authService.getToken();
@@ -625,40 +628,54 @@ var WebSocketServiceImpl = class {
625
628
  client: pusherClient
626
629
  });
627
630
  this.echo = echoInstance;
631
+ this.currentPusherClient = pusherClient;
628
632
  logger.info("websocket", "Echo instance created, setting up connection handlers...");
629
633
  return new Promise((resolve, reject) => {
634
+ let isSettled = false;
635
+ const safeResolve = () => {
636
+ if (!isSettled) {
637
+ isSettled = true;
638
+ resolve();
639
+ }
640
+ };
641
+ const safeReject = (error) => {
642
+ if (!isSettled) {
643
+ isSettled = true;
644
+ reject(error);
645
+ }
646
+ };
630
647
  if (pusherClient.connection.state === "connected") {
631
648
  logger.success("websocket", "\u2705 Already connected to Broadcaster");
632
649
  writeStatus({ connected: true });
633
650
  this.reconnectAttempts = 0;
634
651
  this.isManualDisconnect = false;
635
- resolve();
652
+ safeResolve();
636
653
  return;
637
654
  }
638
655
  const connectionTimeout = setTimeout(() => {
639
- if (this.echo !== echoInstance) return;
656
+ if (this.currentPusherClient !== pusherClient) return;
640
657
  const state = pusherClient.connection.state || "unknown";
641
658
  logger.error("websocket", `Connection timeout after 30s (state: ${state})`);
642
659
  if (state !== "connected") {
643
- reject(new Error(`Connection timeout - stuck in state: ${state}`));
660
+ safeReject(new Error(`Connection timeout - stuck in state: ${state}`));
644
661
  }
645
662
  }, 3e4);
646
663
  pusherClient.connection.bind("state_change", (states) => {
647
- if (this.echo === echoInstance) {
664
+ if (this.currentPusherClient === pusherClient) {
648
665
  logger.info("websocket", `Connection state: ${states.previous} -> ${states.current}`);
649
666
  }
650
667
  });
651
668
  pusherClient.connection.bind("connected", () => {
652
- if (this.echo !== echoInstance) return;
669
+ if (this.currentPusherClient !== pusherClient) return;
653
670
  clearTimeout(connectionTimeout);
654
671
  logger.success("websocket", "\u2705 Connected to Broadcaster via Sanctum");
655
672
  writeStatus({ connected: true });
656
673
  this.reconnectAttempts = 0;
657
674
  this.isManualDisconnect = false;
658
- resolve();
675
+ safeResolve();
659
676
  });
660
677
  pusherClient.connection.bind("error", (error) => {
661
- if (this.echo !== echoInstance) return;
678
+ if (this.currentPusherClient !== pusherClient) return;
662
679
  clearTimeout(connectionTimeout);
663
680
  const errorMessage = error instanceof Error ? error.message : JSON.stringify(error) || "Unknown connection error";
664
681
  logger.error("websocket", `WebSocket error: ${errorMessage}`);
@@ -667,28 +684,31 @@ var WebSocketServiceImpl = class {
667
684
  this.handleDisconnect();
668
685
  }
669
686
  if (pusherClient.connection.state === "failed") {
670
- reject(new Error(errorMessage));
687
+ safeReject(new Error(errorMessage));
671
688
  }
672
689
  });
673
690
  pusherClient.connection.bind("disconnected", () => {
674
- if (this.echo !== echoInstance) return;
691
+ if (this.currentPusherClient !== pusherClient) {
692
+ logger.debug("websocket", "Ignoring disconnected event from previous connection attempt");
693
+ return;
694
+ }
675
695
  logger.warn("websocket", "WebSocket disconnected");
676
696
  writeStatus({ connected: false });
677
697
  this.handleDisconnect();
678
- reject(new Error("WebSocket disconnected during connection"));
698
+ safeReject(new Error("WebSocket disconnected during connection"));
679
699
  });
680
700
  pusherClient.connection.bind("failed", () => {
681
- if (this.echo !== echoInstance) return;
701
+ if (this.currentPusherClient !== pusherClient) return;
682
702
  clearTimeout(connectionTimeout);
683
703
  logger.error("websocket", "WebSocket connection failed");
684
704
  this.handleDisconnect();
685
- reject(new Error("WebSocket connection failed"));
705
+ safeReject(new Error("WebSocket connection failed"));
686
706
  });
687
707
  pusherClient.connection.bind("unavailable", () => {
688
- if (this.echo !== echoInstance) return;
708
+ if (this.currentPusherClient !== pusherClient) return;
689
709
  logger.warn("websocket", "WebSocket connection unavailable, attempting auto-reconnect");
690
710
  writeStatus({ connected: false });
691
- reject(new Error("WebSocket connection unavailable"));
711
+ safeReject(new Error("WebSocket connection unavailable"));
692
712
  });
693
713
  });
694
714
  } catch (error) {
@@ -706,6 +726,7 @@ var WebSocketServiceImpl = class {
706
726
  clearTimeout(this.reconnectTimer);
707
727
  this.reconnectTimer = null;
708
728
  }
729
+ this.currentPusherClient = null;
709
730
  if (this.echo) {
710
731
  if (this.userId) {
711
732
  this.echo.leave(`user.${this.userId}`);
@@ -747,7 +768,7 @@ var WebSocketServiceImpl = class {
747
768
  if (commit.has_large_files) {
748
769
  try {
749
770
  logger.info("websocket", `Commit ${commit.id} marked as large, fetching full details...`);
750
- const { apiService: apiService2 } = await import("./api-MYPJRJLZ.js");
771
+ const { apiService: apiService2 } = await import("./api-TC3OYN5R.js");
751
772
  const fullCommit = await apiService2.getCommit(commit.id);
752
773
  commit = {
753
774
  ...commit,
@@ -833,7 +854,12 @@ var WebSocketServiceImpl = class {
833
854
  await this.subscribeToUserChannel(this.userId);
834
855
  }
835
856
  } catch (error) {
836
- logger.error("websocket", "Reconnection failed", error);
857
+ const errorMessage = error instanceof Error ? error.message : String(error);
858
+ if (errorMessage.includes("disconnected during connection")) {
859
+ logger.debug("websocket", "Connection disconnected during reconnection attempt, will retry");
860
+ } else {
861
+ logger.error("websocket", "Reconnection failed", error);
862
+ }
837
863
  }
838
864
  }, delay);
839
865
  } else {
@@ -2,7 +2,7 @@ import {
2
2
  authService,
3
3
  config,
4
4
  logger
5
- } from "./chunk-6WYXA4IS.js";
5
+ } from "./chunk-BKJMUBZE.js";
6
6
 
7
7
  // src/utils/circuit-breaker.ts
8
8
  var CircuitBreaker = class {
@@ -98,7 +98,7 @@ var CircuitBreaker = class {
98
98
  };
99
99
 
100
100
  // src/services/api.ts
101
- var AGENT_VERSION = "1.2.32";
101
+ var AGENT_VERSION = "1.2.34";
102
102
  var ApiServiceImpl = class {
103
103
  sessionId = null;
104
104
  circuitBreaker = new CircuitBreaker({
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  config,
3
3
  logger
4
- } from "./chunk-6WYXA4IS.js";
4
+ } from "./chunk-BKJMUBZE.js";
5
5
 
6
6
  // src/services/git.ts
7
7
  import simpleGit from "simple-git";
@@ -3,20 +3,20 @@ import {
3
3
  commitQueue,
4
4
  notify,
5
5
  websocketService
6
- } from "../chunk-JFKHNWBC.js";
6
+ } from "../chunk-L4S6LLKQ.js";
7
7
  import {
8
8
  apiService
9
- } from "../chunk-FHPSIVFK.js";
9
+ } from "../chunk-NEUK7ZZY.js";
10
10
  import {
11
11
  gitService,
12
12
  projectService,
13
13
  removePidFile,
14
14
  writePidFile
15
- } from "../chunk-HCOIO2ND.js";
15
+ } from "../chunk-UB56ZQNI.js";
16
16
  import {
17
17
  authService,
18
18
  logger
19
- } from "../chunk-6WYXA4IS.js";
19
+ } from "../chunk-BKJMUBZE.js";
20
20
 
21
21
  // src/daemon/runner.ts
22
22
  import "dotenv/config";
package/dist/index.js CHANGED
@@ -2,10 +2,10 @@
2
2
  import {
3
3
  commitQueue,
4
4
  websocketService
5
- } from "./chunk-JFKHNWBC.js";
5
+ } from "./chunk-L4S6LLKQ.js";
6
6
  import {
7
7
  apiService
8
- } from "./chunk-FHPSIVFK.js";
8
+ } from "./chunk-NEUK7ZZY.js";
9
9
  import {
10
10
  getPidFilePath,
11
11
  gitService,
@@ -14,14 +14,14 @@ import {
14
14
  projectService,
15
15
  spawnDetached,
16
16
  validatePidFile
17
- } from "./chunk-HCOIO2ND.js";
17
+ } from "./chunk-UB56ZQNI.js";
18
18
  import {
19
19
  __commonJS,
20
20
  __toESM,
21
21
  authService,
22
22
  config,
23
23
  logger
24
- } from "./chunk-6WYXA4IS.js";
24
+ } from "./chunk-BKJMUBZE.js";
25
25
 
26
26
  // node_modules/semver/internal/constants.js
27
27
  var require_constants = __commonJS({
@@ -2341,26 +2341,52 @@ function registerLogoutCommand(program2) {
2341
2341
  import ora3 from "ora";
2342
2342
  import chalk3 from "chalk";
2343
2343
  function registerWhoamiCommand(program2) {
2344
- program2.command("whoami").description("Show current user and machine information").action(async () => {
2345
- const spinner = ora3("Checking authentication...").start();
2344
+ program2.command("whoami").description("Show current user and machine information").option("-j, --json", "Output in JSON format").action(async (options) => {
2345
+ if (options.json) logger.disableConsole();
2346
+ const spinner = options.json ? null : ora3("Checking authentication...").start();
2346
2347
  try {
2347
2348
  const token = await authService.getToken();
2348
2349
  if (!token) {
2349
- spinner.info("Not logged in");
2350
+ if (options.json) {
2351
+ console.log(JSON.stringify({ authenticated: false }));
2352
+ return;
2353
+ }
2354
+ if (spinner) spinner.info("Not logged in");
2350
2355
  console.log(chalk3.yellow("\n\u26A0 You are not logged in."));
2351
2356
  console.log(chalk3.gray('Run "stint login" to authenticate.\n'));
2352
2357
  return;
2353
2358
  }
2354
- spinner.text = "Validating credentials...";
2359
+ if (spinner) spinner.text = "Validating credentials...";
2355
2360
  const user = await authService.validateToken();
2356
2361
  if (!user) {
2357
- spinner.fail("Authentication invalid");
2362
+ if (options.json) {
2363
+ console.log(JSON.stringify({ authenticated: false, error: "Token invalid" }));
2364
+ await authService.clearToken();
2365
+ return;
2366
+ }
2367
+ if (spinner) spinner.fail("Authentication invalid");
2358
2368
  console.log(chalk3.red("\n\u2716 Your authentication token is invalid or expired."));
2359
2369
  console.log(chalk3.gray('Run "stint login" to re-authenticate.\n'));
2360
2370
  await authService.clearToken();
2361
2371
  return;
2362
2372
  }
2363
- spinner.succeed("Authenticated");
2373
+ if (options.json) {
2374
+ logger.disableConsole();
2375
+ console.log(JSON.stringify({
2376
+ authenticated: true,
2377
+ user: {
2378
+ name: user.name,
2379
+ email: user.email,
2380
+ id: user.id
2381
+ },
2382
+ machine: {
2383
+ name: authService.getMachineName(),
2384
+ id: authService.getMachineId()
2385
+ }
2386
+ }, null, 2));
2387
+ return;
2388
+ }
2389
+ if (spinner) spinner.succeed("Authenticated");
2364
2390
  console.log(chalk3.blue("\n\u{1F464} User Information:"));
2365
2391
  console.log(chalk3.gray("\u2500".repeat(50)));
2366
2392
  console.log(`${chalk3.bold("Name:")} ${user.name}`);
@@ -2373,10 +2399,14 @@ function registerWhoamiCommand(program2) {
2373
2399
  console.log();
2374
2400
  logger.info("whoami", `User: ${user.email}, Machine: ${authService.getMachineName()}`);
2375
2401
  } catch (error) {
2376
- spinner.fail("Failed to retrieve information");
2402
+ if (spinner) spinner.fail("Failed to retrieve information");
2377
2403
  logger.error("whoami", "Command failed", error);
2378
- console.error(chalk3.red(`
2404
+ if (options.json) {
2405
+ console.error(JSON.stringify({ error: error.message }));
2406
+ } else {
2407
+ console.error(chalk3.red(`
2379
2408
  \u2716 Error: ${error.message}`));
2409
+ }
2380
2410
  process.exit(1);
2381
2411
  }
2382
2412
  });
@@ -2546,13 +2576,14 @@ import process4 from "process";
2546
2576
  import path2 from "path";
2547
2577
  import os from "os";
2548
2578
  function registerStatusCommand(program2) {
2549
- program2.command("status").description("Show linked project and connection status").option("-d, --dashboard", "Launch interactive TUI dashboard").action(async (options) => {
2579
+ program2.command("status").description("Show linked project and connection status").option("-d, --dashboard", "Launch interactive TUI dashboard").option("-j, --json", "Output in JSON format").action(async (options) => {
2580
+ if (options.json) logger.disableConsole();
2550
2581
  const cwd = process4.cwd();
2551
- if (options.dashboard) {
2582
+ if (options.dashboard && !options.json) {
2552
2583
  try {
2553
2584
  const { render } = await import("ink");
2554
2585
  const { createElement } = await import("react");
2555
- const { StatusDashboard } = await import("./StatusDashboard-LF6THHHE.js");
2586
+ const { StatusDashboard } = await import("./StatusDashboard-6H3FWITW.js");
2556
2587
  render(createElement(StatusDashboard, { cwd }));
2557
2588
  return;
2558
2589
  } catch (error) {
@@ -2560,11 +2591,63 @@ function registerStatusCommand(program2) {
2560
2591
  process4.exit(1);
2561
2592
  }
2562
2593
  }
2563
- const spinner = ora6("Gathering status...").start();
2594
+ const spinner = options.json ? null : ora6("Gathering status...").start();
2564
2595
  try {
2565
2596
  const linkedProject = await projectService.getLinkedProject(cwd);
2566
2597
  const user = await authService.validateToken();
2567
- spinner.stop();
2598
+ const isRepo = await gitService.isRepo(cwd);
2599
+ let repoInfo = null;
2600
+ if (isRepo) {
2601
+ try {
2602
+ repoInfo = await gitService.getRepoInfo(cwd);
2603
+ } catch {
2604
+ }
2605
+ }
2606
+ const { valid, pid } = validatePidFile();
2607
+ if (options.json) {
2608
+ logger.disableConsole();
2609
+ const statusOutput = {
2610
+ project: linkedProject ? {
2611
+ id: linkedProject.projectId,
2612
+ linkedAt: linkedProject.linkedAt
2613
+ } : null,
2614
+ authentication: user ? {
2615
+ authenticated: true,
2616
+ user: {
2617
+ name: user.name,
2618
+ email: user.email,
2619
+ id: user.id
2620
+ },
2621
+ machine: {
2622
+ name: authService.getMachineName(),
2623
+ id: authService.getMachineId()
2624
+ }
2625
+ } : {
2626
+ authenticated: false
2627
+ },
2628
+ git: isRepo && repoInfo ? {
2629
+ isRepo: true,
2630
+ branch: repoInfo.currentBranch,
2631
+ remote: repoInfo.remoteUrl,
2632
+ lastCommit: {
2633
+ sha: repoInfo.lastCommitSha,
2634
+ message: repoInfo.lastCommitMessage,
2635
+ date: repoInfo.lastCommitDate
2636
+ },
2637
+ status: repoInfo.status
2638
+ } : {
2639
+ isRepo: !!isRepo
2640
+ },
2641
+ daemon: {
2642
+ running: valid && !!pid,
2643
+ pid: pid || null,
2644
+ logFile: path2.join(os.homedir(), ".config", "stint", "logs", "daemon.log")
2645
+ }
2646
+ };
2647
+ console.log(JSON.stringify(statusOutput, null, 2));
2648
+ return;
2649
+ }
2650
+ if (spinner) spinner.stop();
2568
2651
  console.log(chalk6.blue("\n\u{1F4E6} Project Status:"));
2569
2652
  console.log(chalk6.gray("\u2500".repeat(50)));
2570
2653
  if (linkedProject) {
@@ -2577,26 +2660,28 @@ function registerStatusCommand(program2) {
2577
2660
  }
2578
2661
  console.log(chalk6.blue("\n\u{1F4C2} Git Repository:"));
2579
2662
  console.log(chalk6.gray("\u2500".repeat(50)));
2580
- const isRepo = await gitService.isRepo(cwd);
2581
2663
  if (isRepo) {
2582
2664
  try {
2583
- const repoInfo = await gitService.getRepoInfo(cwd);
2584
- console.log(`${chalk6.bold("Branch:")} ${chalk6.cyan(repoInfo.currentBranch)}`);
2585
- console.log(`${chalk6.bold("Remote:")} ${repoInfo.remoteUrl || chalk6.gray("None")}`);
2586
- console.log(`${chalk6.bold("Last Commit:")} ${repoInfo.lastCommitSha.substring(0, 7)} - ${repoInfo.lastCommitMessage}`);
2587
- console.log(`${chalk6.bold("Commit Date:")} ${new Date(repoInfo.lastCommitDate).toLocaleString()}`);
2588
- const { staged, unstaged, untracked, ahead, behind } = repoInfo.status;
2589
- const totalChanges = staged.length + unstaged.length + untracked.length;
2590
- if (totalChanges > 0) {
2591
- console.log(`${chalk6.bold("Changes:")} ${chalk6.yellow(`${totalChanges} file(s)`)}`);
2592
- if (staged.length > 0) console.log(` ${chalk6.green("Staged:")} ${staged.length}`);
2593
- if (unstaged.length > 0) console.log(` ${chalk6.yellow("Unstaged:")} ${unstaged.length}`);
2594
- if (untracked.length > 0) console.log(` ${chalk6.gray("Untracked:")} ${untracked.length}`);
2665
+ if (repoInfo) {
2666
+ console.log(`${chalk6.bold("Branch:")} ${chalk6.cyan(repoInfo.currentBranch)}`);
2667
+ console.log(`${chalk6.bold("Remote:")} ${repoInfo.remoteUrl || chalk6.gray("None")}`);
2668
+ console.log(`${chalk6.bold("Last Commit:")} ${repoInfo.lastCommitSha.substring(0, 7)} - ${repoInfo.lastCommitMessage}`);
2669
+ console.log(`${chalk6.bold("Commit Date:")} ${new Date(repoInfo.lastCommitDate).toLocaleString()}`);
2670
+ const { staged, unstaged, untracked, ahead, behind } = repoInfo.status;
2671
+ const totalChanges = staged.length + unstaged.length + untracked.length;
2672
+ if (totalChanges > 0) {
2673
+ console.log(`${chalk6.bold("Changes:")} ${chalk6.yellow(`${totalChanges} file(s)`)}`);
2674
+ if (staged.length > 0) console.log(` ${chalk6.green("Staged:")} ${staged.length}`);
2675
+ if (unstaged.length > 0) console.log(` ${chalk6.yellow("Unstaged:")} ${unstaged.length}`);
2676
+ if (untracked.length > 0) console.log(` ${chalk6.gray("Untracked:")} ${untracked.length}`);
2677
+ } else {
2678
+ console.log(`${chalk6.bold("Changes:")} ${chalk6.green("Clean working tree")}`);
2679
+ }
2680
+ if (ahead > 0 || behind > 0) {
2681
+ console.log(`${chalk6.bold("Sync Status:")} ${ahead > 0 ? chalk6.yellow(`\u2191${ahead}`) : ""} ${behind > 0 ? chalk6.yellow(`\u2193${behind}`) : ""}`);
2682
+ }
2595
2683
  } else {
2596
- console.log(`${chalk6.bold("Changes:")} ${chalk6.green("Clean working tree")}`);
2597
- }
2598
- if (ahead > 0 || behind > 0) {
2599
- console.log(`${chalk6.bold("Sync Status:")} ${ahead > 0 ? chalk6.yellow(`\u2191${ahead}`) : ""} ${behind > 0 ? chalk6.yellow(`\u2193${behind}`) : ""}`);
2684
+ console.log(chalk6.red("Error reading repository information"));
2600
2685
  }
2601
2686
  } catch {
2602
2687
  console.log(chalk6.red("Error reading repository information"));
@@ -2616,7 +2701,6 @@ function registerStatusCommand(program2) {
2616
2701
  }
2617
2702
  console.log(chalk6.blue("\n\u2699\uFE0F Daemon:"));
2618
2703
  console.log(chalk6.gray("\u2500".repeat(50)));
2619
- const { valid, pid } = validatePidFile();
2620
2704
  if (valid && pid) {
2621
2705
  console.log(`${chalk6.bold("Status:")} ${chalk6.green("\u2713 Running")}`);
2622
2706
  console.log(`${chalk6.bold("PID:")} ${pid}`);
@@ -2628,7 +2712,7 @@ function registerStatusCommand(program2) {
2628
2712
  console.log();
2629
2713
  logger.info("status", "Status command executed");
2630
2714
  } catch (error) {
2631
- spinner.fail("Failed to get status");
2715
+ if (spinner) spinner.fail("Failed to get status");
2632
2716
  logger.error("status", "Status command failed", error);
2633
2717
  console.error(chalk6.red(`
2634
2718
  \u2716 Error: ${error.message}
@@ -3160,20 +3244,30 @@ import chalk9 from "chalk";
3160
3244
  import { confirm as confirm2 } from "@inquirer/prompts";
3161
3245
  import process6 from "process";
3162
3246
  function registerCommitCommands(program2) {
3163
- program2.command("commits").description("List pending commits for the current project").action(async () => {
3164
- const spinner = ora9("Loading pending commits...").start();
3247
+ program2.command("commits").description("List pending commits for the current project").option("-j, --json", "Output in JSON format").action(async (options) => {
3248
+ if (options.json) logger.disableConsole();
3249
+ const spinner = options.json ? null : ora9("Loading pending commits...").start();
3165
3250
  try {
3166
3251
  const cwd = process6.cwd();
3167
3252
  const linkedProject = await projectService.getLinkedProject(cwd);
3168
3253
  if (!linkedProject) {
3169
- spinner.fail("Not linked");
3254
+ if (options.json) {
3255
+ console.error(JSON.stringify({ error: "Not linked to a project", code: "NOT_LINKED" }));
3256
+ process6.exit(1);
3257
+ }
3258
+ if (spinner) spinner.fail("Not linked");
3170
3259
  console.log(chalk9.yellow("\n\u26A0 This directory is not linked to any project."));
3171
3260
  console.log(chalk9.gray('Run "stint link" first to link this directory.\n'));
3172
3261
  process6.exit(1);
3173
3262
  }
3174
- spinner.text = "Fetching pending commits...";
3263
+ if (spinner) spinner.text = "Fetching pending commits...";
3175
3264
  const commits = await apiService.getPendingCommits(linkedProject.projectId);
3176
- spinner.stop();
3265
+ if (options.json) {
3266
+ logger.disableConsole();
3267
+ console.log(JSON.stringify(commits, null, 2));
3268
+ return;
3269
+ }
3270
+ if (spinner) spinner.stop();
3177
3271
  if (commits.length === 0) {
3178
3272
  console.log(chalk9.blue("\n\u{1F4CB} No pending commits\n"));
3179
3273
  console.log(chalk9.gray("All commits have been executed.\n"));
@@ -3194,9 +3288,10 @@ function registerCommitCommands(program2) {
3194
3288
  console.log(chalk9.gray('\nRun "stint commit <id>" to execute a specific commit.\n'));
3195
3289
  logger.info("commits", `Listed ${commits.length} pending commits`);
3196
3290
  } catch (error) {
3197
- spinner.fail("Failed to fetch commits");
3291
+ if (spinner) spinner.fail("Failed to fetch commits");
3292
+ else if (options.json) console.error(JSON.stringify({ error: error.message }));
3198
3293
  logger.error("commits", "Failed to fetch commits", error);
3199
- console.error(chalk9.red(`
3294
+ if (!options.json) console.error(chalk9.red(`
3200
3295
  \u2716 Error: ${error.message}
3201
3296
  `));
3202
3297
  process6.exit(1);
@@ -4356,7 +4451,7 @@ ${chalk14.bold("Config file:")} ${chalk14.cyan(configPath)}
4356
4451
  }
4357
4452
 
4358
4453
  // src/index.ts
4359
- var AGENT_VERSION = "1.2.32";
4454
+ var AGENT_VERSION = "1.2.34";
4360
4455
  var program = new Command();
4361
4456
  program.name("stint").description("Stint Agent - Local daemon for Stint Project Assistant").version(AGENT_VERSION, "-v, --version", "output the current version").addHelpText("after", `
4362
4457
  ${chalk15.bold("Examples:")}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gowelle/stint-agent",
3
- "version": "1.2.32",
3
+ "version": "1.2.34",
4
4
  "description": "Local agent for Stint - Project Assistant",
5
5
  "author": "Gowelle John <gowelle.john@icloud.com>",
6
6
  "license": "MIT",
@@ -1,7 +0,0 @@
1
- import {
2
- apiService
3
- } from "./chunk-FHPSIVFK.js";
4
- import "./chunk-6WYXA4IS.js";
5
- export {
6
- apiService
7
- };