@renseiai/agentfactory-cli 0.8.7 → 0.8.8

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.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAEH,QAAA,MAAM,OAAO,QAAkB,CAAA;AAE/B,iBAAS,SAAS,IAAI,IAAI,CAwBzB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAEH,QAAA,MAAM,OAAO,QAAkB,CAAA;AAE/B,iBAAS,SAAS,IAAI,IAAI,CAyBzB"}
package/dist/src/index.js CHANGED
@@ -25,6 +25,7 @@ Commands:
25
25
  analyze-logs Analyze agent session logs for errors
26
26
  linear Linear issue tracker operations
27
27
  sync-routes Generate missing route and page files from manifest
28
+ status Show fleet status (inline one-line summary)
28
29
  help Show this help message
29
30
 
30
31
  Run 'agentfactory <command> --help' for command-specific options.
@@ -63,6 +64,9 @@ switch (command) {
63
64
  case 'sync-routes':
64
65
  import('./sync-routes');
65
66
  break;
67
+ case 'status':
68
+ import('./status');
69
+ break;
66
70
  case 'help':
67
71
  case '--help':
68
72
  case '-h':
@@ -1 +1 @@
1
- {"version":3,"file":"agent-runner.d.ts","sourceRoot":"","sources":["../../../src/lib/agent-runner.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAiBH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,WAAW,GAAG,MAAM,CAAA;AAE5E,MAAM,WAAW,iBAAiB;IAChC,yBAAyB;IACzB,OAAO,EAAE,YAAY,CAAA;IACrB,uFAAuF;IACvF,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,wEAAwE;IACxE,GAAG,CAAC,EAAE,OAAO,CAAA;CACd;AAMD,eAAO,MAAM,CAAC;;;;;;;CAOJ,CAAA;AAuRV,wBAAsB,QAAQ,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBvE"}
1
+ {"version":3,"file":"agent-runner.d.ts","sourceRoot":"","sources":["../../../src/lib/agent-runner.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAiBH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,WAAW,GAAG,MAAM,CAAA;AAE5E,MAAM,WAAW,iBAAiB;IAChC,yBAAyB;IACzB,OAAO,EAAE,YAAY,CAAA;IACrB,uFAAuF;IACvF,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,sCAAsC;IACtC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,wEAAwE;IACxE,GAAG,CAAC,EAAE,OAAO,CAAA;CACd;AAMD,eAAO,MAAM,CAAC;;;;;;;CAOJ,CAAA;AA8RV,wBAAsB,QAAQ,CAAC,MAAM,EAAE,iBAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBvE"}
@@ -5,7 +5,7 @@
5
5
  * agent sessions. Works by updating Redis state directly — workers poll for
6
6
  * status changes and pending prompts every 5 seconds.
7
7
  */
8
- import { getRedisClient, getAllSessions, updateSessionStatus, storeSessionState, storePendingPrompt, disconnectRedis, } from '@renseiai/agentfactory-server';
8
+ import { getRedisClient, getAllSessions, updateSessionStatus, storeSessionState, publishUrgent, disconnectRedis, } from '@renseiai/agentfactory-server';
9
9
  import { createLinearAgentClient } from '@renseiai/plugin-linear';
10
10
  // ---------------------------------------------------------------------------
11
11
  // ANSI colors
@@ -114,12 +114,23 @@ async function chatWithAgent(issueId, message) {
114
114
  await disconnectRedis();
115
115
  return;
116
116
  }
117
- const prompt = await storePendingPrompt(session.linearSessionId, session.issueId, message);
118
- if (prompt) {
119
- console.log(`${C.green}Message queued${C.reset} (id: ${prompt.id})worker will pick up within ~5 seconds`);
117
+ const agentId = session.agentId;
118
+ if (!agentId) {
119
+ console.error(`${C.red}Session has no agentIdcannot publish to inbox${C.reset}`);
120
+ await disconnectRedis();
121
+ return;
120
122
  }
121
- else {
122
- console.error(`${C.red}Failed to store pending prompt${C.reset}`);
123
+ try {
124
+ const streamId = await publishUrgent(agentId, {
125
+ type: 'directive',
126
+ sessionId: session.linearSessionId,
127
+ payload: message,
128
+ createdAt: Date.now(),
129
+ });
130
+ console.log(`${C.green}Message queued${C.reset} (id: ${streamId}) — worker will pick up within ~5 seconds`);
131
+ }
132
+ catch (err) {
133
+ console.error(`${C.red}Failed to publish to inbox: ${err instanceof Error ? err.message : String(err)}${C.reset}`);
123
134
  }
124
135
  await disconnectRedis();
125
136
  }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Status Runner -- Programmatic API for the af-status CLI.
3
+ *
4
+ * Provides fleet status via the AgentFactory public API.
5
+ * In TTY mode, spawns the Go `af-status` binary for rich inline output.
6
+ * In piped/JSON mode, fetches stats directly from Node.js.
7
+ */
8
+ export interface StatusRunnerConfig {
9
+ /** Output raw JSON instead of human-readable format */
10
+ json?: boolean;
11
+ /** Enable auto-refresh watch mode */
12
+ watch?: boolean;
13
+ /** Watch interval (e.g., "1s", "5s") — only used with watch */
14
+ interval?: string;
15
+ /** API base URL override */
16
+ url?: string;
17
+ }
18
+ export declare const C: {
19
+ readonly reset: "\u001B[0m";
20
+ readonly red: "\u001B[31m";
21
+ readonly green: "\u001B[32m";
22
+ readonly yellow: "\u001B[33m";
23
+ readonly cyan: "\u001B[36m";
24
+ readonly gray: "\u001B[90m";
25
+ };
26
+ export declare function runStatus(config: StatusRunnerConfig): Promise<void>;
27
+ //# sourceMappingURL=status-runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status-runner.d.ts","sourceRoot":"","sources":["../../../src/lib/status-runner.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAaH,MAAM,WAAW,kBAAkB;IACjC,uDAAuD;IACvD,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,qCAAqC;IACrC,KAAK,CAAC,EAAE,OAAO,CAAA;IACf,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,4BAA4B;IAC5B,GAAG,CAAC,EAAE,MAAM,CAAA;CACb;AAMD,eAAO,MAAM,CAAC;;;;;;;CAOJ,CAAA;AAuEV,wBAAsB,SAAS,CAAC,MAAM,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAkBzE"}
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Status Runner -- Programmatic API for the af-status CLI.
3
+ *
4
+ * Provides fleet status via the AgentFactory public API.
5
+ * In TTY mode, spawns the Go `af-status` binary for rich inline output.
6
+ * In piped/JSON mode, fetches stats directly from Node.js.
7
+ */
8
+ import { spawn } from 'child_process';
9
+ import path from 'path';
10
+ import { fileURLToPath } from 'url';
11
+ const __filename = fileURLToPath(import.meta.url);
12
+ const __dirname = path.dirname(__filename);
13
+ // ---------------------------------------------------------------------------
14
+ // ANSI colors (same as agent-runner)
15
+ // ---------------------------------------------------------------------------
16
+ export const C = {
17
+ reset: '\x1b[0m',
18
+ red: '\x1b[31m',
19
+ green: '\x1b[32m',
20
+ yellow: '\x1b[33m',
21
+ cyan: '\x1b[36m',
22
+ gray: '\x1b[90m',
23
+ };
24
+ // ---------------------------------------------------------------------------
25
+ // Helpers
26
+ // ---------------------------------------------------------------------------
27
+ function getBaseURL(override) {
28
+ return override ?? process.env.WORKER_API_URL ?? 'http://localhost:3000';
29
+ }
30
+ async function fetchStats(baseURL) {
31
+ const url = `${baseURL.replace(/\/+$/, '')}/api/public/stats`;
32
+ const resp = await fetch(url);
33
+ if (!resp.ok) {
34
+ throw new Error(`API request failed: ${resp.status} ${resp.statusText}`);
35
+ }
36
+ return resp.json();
37
+ }
38
+ function resolveGoBinary() {
39
+ // Go binary lives in packages/tui/bin/af-status relative to the CLI package
40
+ return path.resolve(__dirname, '../../tui/bin/af-status');
41
+ }
42
+ // ---------------------------------------------------------------------------
43
+ // Command handlers
44
+ // ---------------------------------------------------------------------------
45
+ async function showJSON(baseURL) {
46
+ const stats = await fetchStats(baseURL);
47
+ console.log(JSON.stringify(stats, null, 2));
48
+ }
49
+ function spawnGoBinary(config, baseURL) {
50
+ return new Promise((resolve, reject) => {
51
+ const binPath = resolveGoBinary();
52
+ const args = ['--url', baseURL];
53
+ if (config.json)
54
+ args.push('--json');
55
+ if (config.watch)
56
+ args.push('--watch');
57
+ if (config.interval)
58
+ args.push('--interval', config.interval);
59
+ const child = spawn(binPath, args, {
60
+ stdio: 'inherit',
61
+ });
62
+ child.on('error', (err) => {
63
+ if (err.code === 'ENOENT') {
64
+ // Go binary not built yet — fall back to Node.js JSON output
65
+ console.error(`${C.yellow}Go binary not found at ${binPath}${C.reset}`);
66
+ console.error(`${C.gray}Falling back to JSON output. Build with: cd packages/tui && make build-status${C.reset}`);
67
+ showJSON(baseURL).then(resolve, reject);
68
+ }
69
+ else {
70
+ reject(err);
71
+ }
72
+ });
73
+ child.on('close', (code) => {
74
+ if (code === 0) {
75
+ resolve();
76
+ }
77
+ else {
78
+ reject(new Error(`af-status exited with code ${code}`));
79
+ }
80
+ });
81
+ });
82
+ }
83
+ // ---------------------------------------------------------------------------
84
+ // Public entry point
85
+ // ---------------------------------------------------------------------------
86
+ export async function runStatus(config) {
87
+ const baseURL = getBaseURL(config.url);
88
+ const isTTY = process.stdout.isTTY ?? false;
89
+ // If piped (non-TTY) and not explicitly requesting watch, default to JSON
90
+ if (!isTTY && !config.watch) {
91
+ await showJSON(baseURL);
92
+ return;
93
+ }
94
+ // If --json flag without watch, just fetch and print
95
+ if (config.json && !config.watch) {
96
+ await showJSON(baseURL);
97
+ return;
98
+ }
99
+ // TTY mode or watch mode — delegate to Go binary
100
+ await spawnGoBinary(config, baseURL);
101
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"worker-runner.d.ts","sourceRoot":"","sources":["../../../src/lib/worker-runner.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAyBH,MAAM,WAAW,kBAAkB;IACjC,0BAA0B;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,iCAAiC;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,mDAAmD;IACnD,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,gFAAgF;IAChF,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,uDAAuD;IACvD,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CACpB;AAwED;;;;;GAKG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,kBAAkB,EAC1B,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CAy7Bf"}
1
+ {"version":3,"file":"worker-runner.d.ts","sourceRoot":"","sources":["../../../src/lib/worker-runner.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAyBH,MAAM,WAAW,kBAAkB;IACjC,0BAA0B;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,iCAAiC;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,mDAAmD;IACnD,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,gFAAgF;IAChF,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,uDAAuD;IACvD,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAA;CACpB;AAyED;;;;;GAKG;AACH,wBAAsB,SAAS,CAC7B,MAAM,EAAE,kBAAkB,EAC1B,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,IAAI,CAAC,CA89Bf"}
@@ -277,25 +277,26 @@ export async function runWorker(config, signal) {
277
277
  // -----------------------------------------------------------------------
278
278
  async function pollForWork() {
279
279
  if (!workerId)
280
- return { work: [], pendingPrompts: {}, hasPendingPrompts: false };
280
+ return { work: [], inboxMessages: {}, hasInboxMessages: false };
281
281
  const result = await apiRequestWithError(`/api/workers/${workerId}/poll`);
282
282
  if (result.error?.type === 'worker_not_found') {
283
283
  await attemptReregistration();
284
- return { work: [], pendingPrompts: {}, hasPendingPrompts: false };
284
+ return { work: [], inboxMessages: {}, hasInboxMessages: false };
285
285
  }
286
286
  if (!result.data) {
287
- return { work: [], pendingPrompts: {}, hasPendingPrompts: false };
287
+ return { work: [], inboxMessages: {}, hasInboxMessages: false };
288
288
  }
289
289
  const pollData = result.data;
290
- if (pollData.hasPendingPrompts) {
291
- const totalPrompts = Object.values(pollData.pendingPrompts).reduce((sum, prompts) => sum + prompts.length, 0);
292
- log.info('Received pending prompts', {
293
- sessionCount: Object.keys(pollData.pendingPrompts).length,
294
- totalPrompts,
295
- sessions: Object.entries(pollData.pendingPrompts).map(([sessionId, prompts]) => ({
290
+ if (pollData.hasInboxMessages) {
291
+ const totalMessages = Object.values(pollData.inboxMessages).reduce((sum, messages) => sum + messages.length, 0);
292
+ log.info('Received inbox messages', {
293
+ sessionCount: Object.keys(pollData.inboxMessages).length,
294
+ totalMessages,
295
+ sessions: Object.entries(pollData.inboxMessages).map(([sessionId, messages]) => ({
296
296
  sessionId: sessionId.substring(0, 8),
297
- promptCount: prompts.length,
298
- promptIds: prompts.map((p) => p.id),
297
+ messageCount: messages.length,
298
+ messageIds: messages.map((m) => m.id),
299
+ types: messages.map((m) => m.type),
299
300
  })),
300
301
  });
301
302
  }
@@ -309,6 +310,15 @@ export async function runWorker(config, signal) {
309
310
  body: JSON.stringify({ workerId }),
310
311
  });
311
312
  }
313
+ async function ackInboxMessage(sessionId, message) {
314
+ await apiRequest(`/api/sessions/${sessionId}/inbox/ack`, {
315
+ method: 'POST',
316
+ body: JSON.stringify({
317
+ messageId: message.id,
318
+ lane: message.lane,
319
+ }),
320
+ });
321
+ }
312
322
  async function reportStatus(sessionId, status, extra) {
313
323
  if (!workerId)
314
324
  return;
@@ -696,68 +706,94 @@ export async function runWorker(config, signal) {
696
706
  }
697
707
  }
698
708
  }
699
- // Handle pending prompts for active sessions
700
- if (pollResult.hasPendingPrompts) {
701
- for (const [sessionId, prompts] of Object.entries(pollResult.pendingPrompts)) {
702
- for (const prompt of prompts) {
703
- log.info('Processing pending prompt', {
709
+ // Handle inbox messages for active sessions (urgent-first)
710
+ if (pollResult.hasInboxMessages) {
711
+ for (const [sessionId, messages] of Object.entries(pollResult.inboxMessages)) {
712
+ for (const message of messages) {
713
+ // Handle nudge: no-op wake signal, just discard
714
+ if (message.type === 'nudge') {
715
+ log.debug('Nudge received (no-op)', {
716
+ sessionId: sessionId.substring(0, 8),
717
+ messageId: message.id,
718
+ });
719
+ await ackInboxMessage(sessionId, message);
720
+ continue;
721
+ }
722
+ const orchestrator = activeOrchestrators.get(sessionId);
723
+ // Handle stop signal: trigger graceful agent shutdown
724
+ if (message.type === 'stop') {
725
+ log.info('Stop signal received', {
726
+ sessionId: sessionId.substring(0, 8),
727
+ messageId: message.id,
728
+ });
729
+ if (orchestrator) {
730
+ const agent = orchestrator.getAgentBySession(sessionId);
731
+ if (agent) {
732
+ try {
733
+ await orchestrator.stopAgent(agent.issueId, false);
734
+ log.success('Agent stopped via inbox signal', {
735
+ sessionId: sessionId.substring(0, 8),
736
+ });
737
+ }
738
+ catch (error) {
739
+ log.error('Failed to stop agent', {
740
+ sessionId: sessionId.substring(0, 8),
741
+ error: error instanceof Error ? error.message : String(error),
742
+ });
743
+ }
744
+ }
745
+ }
746
+ await ackInboxMessage(sessionId, message);
747
+ continue;
748
+ }
749
+ // Handle directive and hook-result: inject as follow-up prompt
750
+ log.info('Processing inbox message', {
704
751
  sessionId: sessionId.substring(0, 8),
705
- promptId: prompt.id,
706
- promptLength: prompt.prompt.length,
707
- userName: prompt.userName,
752
+ messageId: message.id,
753
+ type: message.type,
754
+ lane: message.lane,
755
+ payloadLength: message.payload.length,
756
+ userName: message.userName,
708
757
  });
709
- const orchestrator = activeOrchestrators.get(sessionId);
710
758
  if (!orchestrator) {
711
759
  log.warn('No active orchestrator found for session', {
712
760
  sessionId: sessionId.substring(0, 8),
713
- promptId: prompt.id,
761
+ messageId: message.id,
714
762
  });
715
763
  continue;
716
764
  }
717
765
  const agent = orchestrator.getAgentBySession(sessionId);
718
766
  const providerSessionId = agent?.providerSessionId;
719
- log.info('Forwarding prompt to provider session', {
720
- sessionId: sessionId.substring(0, 8),
721
- promptId: prompt.id,
722
- hasProviderSession: !!providerSessionId,
723
- agentStatus: agent?.status,
724
- });
725
767
  try {
726
- const result = await orchestrator.forwardPrompt(prompt.issueId, sessionId, prompt.prompt, providerSessionId, agent?.workType);
768
+ const result = await orchestrator.forwardPrompt(agent?.issueId ?? '', sessionId, message.payload, providerSessionId, agent?.workType);
727
769
  if (result.forwarded) {
728
770
  log.success(result.injected
729
771
  ? 'Message injected into running session'
730
- : 'Prompt forwarded successfully', {
772
+ : 'Inbox message forwarded successfully', {
731
773
  sessionId: sessionId.substring(0, 8),
732
- promptId: prompt.id,
774
+ messageId: message.id,
775
+ type: message.type,
733
776
  injected: result.injected ?? false,
734
777
  resumed: result.resumed,
735
778
  newAgentPid: result.agent?.pid,
736
779
  });
737
- const claimResult = await apiRequest(`/api/sessions/${sessionId}/prompts`, {
738
- method: 'POST',
739
- body: JSON.stringify({ promptId: prompt.id }),
740
- });
741
- if (claimResult?.claimed) {
742
- log.debug('Prompt claimed', { promptId: prompt.id });
743
- }
744
- else {
745
- log.warn('Failed to claim prompt', { promptId: prompt.id });
746
- }
780
+ // ACK after successful delivery
781
+ await ackInboxMessage(sessionId, message);
747
782
  }
748
783
  else {
749
- log.error('Failed to forward prompt', {
784
+ log.error('Failed to forward inbox message', {
750
785
  sessionId: sessionId.substring(0, 8),
751
- promptId: prompt.id,
786
+ messageId: message.id,
787
+ type: message.type,
752
788
  reason: result.reason,
753
789
  error: result.error?.message,
754
790
  });
755
791
  }
756
792
  }
757
793
  catch (error) {
758
- log.error('Error forwarding prompt', {
794
+ log.error('Error forwarding inbox message', {
759
795
  sessionId: sessionId.substring(0, 8),
760
- promptId: prompt.id,
796
+ messageId: message.id,
761
797
  error: error instanceof Error ? error.message : String(error),
762
798
  });
763
799
  }
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * AgentFactory Status CLI
4
+ *
5
+ * Quick fleet status checks for terminal and scripting use.
6
+ *
7
+ * Usage:
8
+ * af-status One-line fleet summary (via Go binary in TTY)
9
+ * af-status --json JSON stats to stdout
10
+ * af-status --watch Auto-refresh every 3 seconds
11
+ * af-status --watch --interval 5s Custom refresh interval
12
+ * af-status | jq Pipe-friendly (auto-detects non-TTY)
13
+ *
14
+ * Environment (loaded from .env.local in CWD):
15
+ * WORKER_API_URL API base URL (default: http://localhost:3000)
16
+ */
17
+ export {};
18
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/status.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;GAcG"}
@@ -0,0 +1,78 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * AgentFactory Status CLI
4
+ *
5
+ * Quick fleet status checks for terminal and scripting use.
6
+ *
7
+ * Usage:
8
+ * af-status One-line fleet summary (via Go binary in TTY)
9
+ * af-status --json JSON stats to stdout
10
+ * af-status --watch Auto-refresh every 3 seconds
11
+ * af-status --watch --interval 5s Custom refresh interval
12
+ * af-status | jq Pipe-friendly (auto-detects non-TTY)
13
+ *
14
+ * Environment (loaded from .env.local in CWD):
15
+ * WORKER_API_URL API base URL (default: http://localhost:3000)
16
+ */
17
+ import path from 'path';
18
+ import { config } from 'dotenv';
19
+ // Load environment variables from .env.local in CWD
20
+ config({ path: path.resolve(process.cwd(), '.env.local') });
21
+ import { runStatus, C } from './lib/status-runner.js';
22
+ // ---------------------------------------------------------------------------
23
+ // Usage
24
+ // ---------------------------------------------------------------------------
25
+ function printUsage() {
26
+ console.log(`
27
+ ${C.cyan}AgentFactory Status${C.reset} - Quick fleet status checks
28
+
29
+ ${C.yellow}Usage:${C.reset}
30
+ af-status [options]
31
+
32
+ ${C.yellow}Options:${C.reset}
33
+ --json Output raw JSON stats to stdout
34
+ --watch Auto-refresh status every 3 seconds
35
+ --interval <duration> Custom refresh interval (e.g., 1s, 5s) [default: 3s]
36
+ --url <url> API base URL [default: WORKER_API_URL or http://localhost:3000]
37
+ --help, -h Show this help message
38
+
39
+ ${C.yellow}Examples:${C.reset}
40
+ af-status One-line fleet summary
41
+ af-status --json JSON output
42
+ af-status --json | jq .agentsWorking Extract a field
43
+ af-status --watch Auto-refresh mode
44
+ af-status --watch --interval 1s Refresh every second
45
+
46
+ ${C.yellow}Environment:${C.reset}
47
+ WORKER_API_URL API base URL (default: http://localhost:3000)
48
+ `);
49
+ }
50
+ // ---------------------------------------------------------------------------
51
+ // Main
52
+ // ---------------------------------------------------------------------------
53
+ async function main() {
54
+ const args = process.argv.slice(2);
55
+ if (args.includes('--help') || args.includes('-h') || args.includes('help')) {
56
+ printUsage();
57
+ return;
58
+ }
59
+ const jsonMode = args.includes('--json');
60
+ const watchMode = args.includes('--watch');
61
+ // Parse --interval value
62
+ let interval;
63
+ const intervalIdx = args.indexOf('--interval');
64
+ if (intervalIdx !== -1 && intervalIdx + 1 < args.length) {
65
+ interval = args[intervalIdx + 1];
66
+ }
67
+ // Parse --url value
68
+ let url;
69
+ const urlIdx = args.indexOf('--url');
70
+ if (urlIdx !== -1 && urlIdx + 1 < args.length) {
71
+ url = args[urlIdx + 1];
72
+ }
73
+ await runStatus({ json: jsonMode, watch: watchMode, interval, url });
74
+ }
75
+ main().catch((error) => {
76
+ console.error('Error:', error instanceof Error ? error.message : error);
77
+ process.exit(1);
78
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@renseiai/agentfactory-cli",
3
- "version": "0.8.7",
3
+ "version": "0.8.8",
4
4
  "type": "module",
5
5
  "description": "CLI tools for AgentFactory — local orchestrator, remote worker, queue admin",
6
6
  "author": "Rensei AI (https://rensei.ai)",
@@ -37,7 +37,8 @@
37
37
  "af-analyze-logs": "dist/src/analyze-logs.js",
38
38
  "af-linear": "dist/src/linear.js",
39
39
  "af-governor": "dist/src/governor.js",
40
- "af-sync-routes": "dist/src/sync-routes.js"
40
+ "af-sync-routes": "dist/src/sync-routes.js",
41
+ "af-status": "dist/src/status.js"
41
42
  },
42
43
  "main": "./dist/src/index.js",
43
44
  "module": "./dist/src/index.js",
@@ -92,6 +93,11 @@
92
93
  "types": "./dist/src/lib/sync-routes-runner.d.ts",
93
94
  "import": "./dist/src/lib/sync-routes-runner.js",
94
95
  "default": "./dist/src/lib/sync-routes-runner.js"
96
+ },
97
+ "./status": {
98
+ "types": "./dist/src/lib/status-runner.d.ts",
99
+ "import": "./dist/src/lib/status-runner.js",
100
+ "default": "./dist/src/lib/status-runner.js"
95
101
  }
96
102
  },
97
103
  "files": [
@@ -101,10 +107,10 @@
101
107
  ],
102
108
  "dependencies": {
103
109
  "dotenv": "^17.2.3",
104
- "@renseiai/agentfactory": "0.8.7",
105
- "@renseiai/plugin-linear": "0.8.7",
106
- "@renseiai/agentfactory-code-intelligence": "0.8.7",
107
- "@renseiai/agentfactory-server": "0.8.7"
110
+ "@renseiai/agentfactory-code-intelligence": "0.8.8",
111
+ "@renseiai/plugin-linear": "0.8.8",
112
+ "@renseiai/agentfactory": "0.8.8",
113
+ "@renseiai/agentfactory-server": "0.8.8"
108
114
  },
109
115
  "devDependencies": {
110
116
  "@types/node": "^22.5.4",