@openacp/cli 0.2.17 → 0.2.19

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/index.d.ts CHANGED
@@ -10,7 +10,7 @@ interface IncomingMessage {
10
10
  text: string;
11
11
  }
12
12
  interface OutgoingMessage {
13
- type: 'text' | 'thought' | 'tool_call' | 'tool_update' | 'plan' | 'usage' | 'session_end' | 'error';
13
+ type: "text" | "thought" | "tool_call" | "tool_update" | "plan" | "usage" | "session_end" | "error";
14
14
  text: string;
15
15
  metadata?: Record<string, unknown>;
16
16
  }
@@ -27,7 +27,7 @@ interface PermissionOption {
27
27
  interface NotificationMessage {
28
28
  sessionId: string;
29
29
  sessionName?: string;
30
- type: 'completed' | 'error' | 'permission' | 'input_required';
30
+ type: "completed" | "error" | "permission" | "input_required";
31
31
  summary: string;
32
32
  deepLink?: string;
33
33
  }
@@ -37,13 +37,13 @@ interface AgentCommand {
37
37
  input?: unknown;
38
38
  }
39
39
  type AgentEvent = {
40
- type: 'text';
40
+ type: "text";
41
41
  content: string;
42
42
  } | {
43
- type: 'thought';
43
+ type: "thought";
44
44
  content: string;
45
45
  } | {
46
- type: 'tool_call';
46
+ type: "tool_call";
47
47
  id: string;
48
48
  name: string;
49
49
  kind?: string;
@@ -51,16 +51,16 @@ type AgentEvent = {
51
51
  content?: unknown;
52
52
  locations?: unknown;
53
53
  } | {
54
- type: 'tool_update';
54
+ type: "tool_update";
55
55
  id: string;
56
56
  status: string;
57
57
  content?: unknown;
58
58
  locations?: unknown;
59
59
  } | {
60
- type: 'plan';
60
+ type: "plan";
61
61
  entries: PlanEntry[];
62
62
  } | {
63
- type: 'usage';
63
+ type: "usage";
64
64
  tokensUsed?: number;
65
65
  contextSize?: number;
66
66
  cost?: {
@@ -68,19 +68,19 @@ type AgentEvent = {
68
68
  currency: string;
69
69
  };
70
70
  } | {
71
- type: 'commands_update';
71
+ type: "commands_update";
72
72
  commands: AgentCommand[];
73
73
  } | {
74
- type: 'session_end';
74
+ type: "session_end";
75
75
  reason: string;
76
76
  } | {
77
- type: 'error';
77
+ type: "error";
78
78
  message: string;
79
79
  };
80
80
  interface PlanEntry {
81
81
  content: string;
82
- status: 'pending' | 'in_progress' | 'completed';
83
- priority: 'high' | 'medium' | 'low';
82
+ status: "pending" | "in_progress" | "completed";
83
+ priority: "high" | "medium" | "low";
84
84
  }
85
85
  interface AgentDefinition {
86
86
  name: string;
@@ -89,7 +89,22 @@ interface AgentDefinition {
89
89
  workingDirectory?: string;
90
90
  env?: Record<string, string>;
91
91
  }
92
- type SessionStatus = 'initializing' | 'active' | 'cancelled' | 'finished' | 'error';
92
+ type SessionStatus = "initializing" | "active" | "cancelled" | "finished" | "error";
93
+ interface SessionRecord<P = Record<string, unknown>> {
94
+ sessionId: string;
95
+ agentSessionId: string;
96
+ agentName: string;
97
+ workingDir: string;
98
+ channelId: string;
99
+ status: SessionStatus;
100
+ createdAt: string;
101
+ lastActiveAt: string;
102
+ name?: string;
103
+ platform: P;
104
+ }
105
+ interface TelegramPlatformData {
106
+ topicId: number;
107
+ }
93
108
 
94
109
  declare const PLUGINS_DIR: string;
95
110
  declare const LoggingSchema: z.ZodDefault<z.ZodObject<{
@@ -115,7 +130,7 @@ type LoggingConfig = z.infer<typeof LoggingSchema>;
115
130
  declare const TunnelSchema: z.ZodDefault<z.ZodObject<{
116
131
  enabled: z.ZodDefault<z.ZodBoolean>;
117
132
  port: z.ZodDefault<z.ZodNumber>;
118
- provider: z.ZodDefault<z.ZodEnum<["cloudflare", "ngrok", "bore"]>>;
133
+ provider: z.ZodDefault<z.ZodEnum<["cloudflare", "ngrok", "bore", "tailscale"]>>;
119
134
  options: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
120
135
  storeTtlMinutes: z.ZodDefault<z.ZodNumber>;
121
136
  auth: z.ZodDefault<z.ZodObject<{
@@ -132,7 +147,7 @@ declare const TunnelSchema: z.ZodDefault<z.ZodObject<{
132
147
  options: Record<string, unknown>;
133
148
  enabled: boolean;
134
149
  port: number;
135
- provider: "cloudflare" | "ngrok" | "bore";
150
+ provider: "cloudflare" | "ngrok" | "bore" | "tailscale";
136
151
  storeTtlMinutes: number;
137
152
  auth: {
138
153
  enabled: boolean;
@@ -142,7 +157,7 @@ declare const TunnelSchema: z.ZodDefault<z.ZodObject<{
142
157
  options?: Record<string, unknown> | undefined;
143
158
  enabled?: boolean | undefined;
144
159
  port?: number | undefined;
145
- provider?: "cloudflare" | "ngrok" | "bore" | undefined;
160
+ provider?: "cloudflare" | "ngrok" | "bore" | "tailscale" | undefined;
146
161
  storeTtlMinutes?: number | undefined;
147
162
  auth?: {
148
163
  enabled?: boolean | undefined;
@@ -217,10 +232,17 @@ declare const ConfigSchema: z.ZodObject<{
217
232
  maxFiles?: number | undefined;
218
233
  sessionLogRetentionDays?: number | undefined;
219
234
  }>>;
235
+ sessionStore: z.ZodDefault<z.ZodObject<{
236
+ ttlDays: z.ZodDefault<z.ZodNumber>;
237
+ }, "strip", z.ZodTypeAny, {
238
+ ttlDays: number;
239
+ }, {
240
+ ttlDays?: number | undefined;
241
+ }>>;
220
242
  tunnel: z.ZodDefault<z.ZodObject<{
221
243
  enabled: z.ZodDefault<z.ZodBoolean>;
222
244
  port: z.ZodDefault<z.ZodNumber>;
223
- provider: z.ZodDefault<z.ZodEnum<["cloudflare", "ngrok", "bore"]>>;
245
+ provider: z.ZodDefault<z.ZodEnum<["cloudflare", "ngrok", "bore", "tailscale"]>>;
224
246
  options: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
225
247
  storeTtlMinutes: z.ZodDefault<z.ZodNumber>;
226
248
  auth: z.ZodDefault<z.ZodObject<{
@@ -237,7 +259,7 @@ declare const ConfigSchema: z.ZodObject<{
237
259
  options: Record<string, unknown>;
238
260
  enabled: boolean;
239
261
  port: number;
240
- provider: "cloudflare" | "ngrok" | "bore";
262
+ provider: "cloudflare" | "ngrok" | "bore" | "tailscale";
241
263
  storeTtlMinutes: number;
242
264
  auth: {
243
265
  enabled: boolean;
@@ -247,7 +269,7 @@ declare const ConfigSchema: z.ZodObject<{
247
269
  options?: Record<string, unknown> | undefined;
248
270
  enabled?: boolean | undefined;
249
271
  port?: number | undefined;
250
- provider?: "cloudflare" | "ngrok" | "bore" | undefined;
272
+ provider?: "cloudflare" | "ngrok" | "bore" | "tailscale" | undefined;
251
273
  storeTtlMinutes?: number | undefined;
252
274
  auth?: {
253
275
  enabled?: boolean | undefined;
@@ -281,11 +303,14 @@ declare const ConfigSchema: z.ZodObject<{
281
303
  maxFiles: number;
282
304
  sessionLogRetentionDays: number;
283
305
  };
306
+ sessionStore: {
307
+ ttlDays: number;
308
+ };
284
309
  tunnel: {
285
310
  options: Record<string, unknown>;
286
311
  enabled: boolean;
287
312
  port: number;
288
- provider: "cloudflare" | "ngrok" | "bore";
313
+ provider: "cloudflare" | "ngrok" | "bore" | "tailscale";
289
314
  storeTtlMinutes: number;
290
315
  auth: {
291
316
  enabled: boolean;
@@ -319,11 +344,14 @@ declare const ConfigSchema: z.ZodObject<{
319
344
  maxFiles?: number | undefined;
320
345
  sessionLogRetentionDays?: number | undefined;
321
346
  } | undefined;
347
+ sessionStore?: {
348
+ ttlDays?: number | undefined;
349
+ } | undefined;
322
350
  tunnel?: {
323
351
  options?: Record<string, unknown> | undefined;
324
352
  enabled?: boolean | undefined;
325
353
  port?: number | undefined;
326
- provider?: "cloudflare" | "ngrok" | "bore" | undefined;
354
+ provider?: "cloudflare" | "ngrok" | "bore" | "tailscale" | undefined;
327
355
  storeTtlMinutes?: number | undefined;
328
356
  auth?: {
329
357
  enabled?: boolean | undefined;
@@ -413,7 +441,10 @@ declare class AgentInstance {
413
441
  onSessionUpdate: (event: AgentEvent) => void;
414
442
  onPermissionRequest: (request: PermissionRequest) => Promise<string>;
415
443
  private constructor();
444
+ private static spawnSubprocess;
445
+ private setupCrashDetection;
416
446
  static spawn(agentDef: AgentDefinition, workingDirectory: string): Promise<AgentInstance>;
447
+ static resume(agentDef: AgentDefinition, workingDirectory: string, agentSessionId: string): Promise<AgentInstance>;
417
448
  private createClient;
418
449
  prompt(text: string): Promise<PromptResponse>;
419
450
  cancel(): Promise<void>;
@@ -426,6 +457,7 @@ declare class AgentManager {
426
457
  getAvailableAgents(): AgentDefinition[];
427
458
  getAgent(name: string): AgentDefinition | undefined;
428
459
  spawn(agentName: string, workingDirectory: string): Promise<AgentInstance>;
460
+ resume(agentName: string, workingDirectory: string, agentSessionId: string): Promise<AgentInstance>;
429
461
  }
430
462
 
431
463
  declare class Session {
@@ -435,6 +467,7 @@ declare class Session {
435
467
  agentName: string;
436
468
  workingDirectory: string;
437
469
  agentInstance: AgentInstance;
470
+ agentSessionId: string;
438
471
  status: SessionStatus;
439
472
  name?: string;
440
473
  promptQueue: string[];
@@ -462,11 +495,25 @@ declare class Session {
462
495
  destroy(): Promise<void>;
463
496
  }
464
497
 
498
+ interface SessionStore {
499
+ save(record: SessionRecord): Promise<void>;
500
+ get(sessionId: string): SessionRecord | undefined;
501
+ findByPlatform(channelId: string, predicate: (platform: Record<string, unknown>) => boolean): SessionRecord | undefined;
502
+ list(channelId?: string): SessionRecord[];
503
+ remove(sessionId: string): Promise<void>;
504
+ }
505
+
465
506
  declare class SessionManager {
466
507
  private sessions;
508
+ private store;
509
+ constructor(store?: SessionStore | null);
467
510
  createSession(channelId: string, agentName: string, workingDirectory: string, agentManager: AgentManager): Promise<Session>;
468
511
  getSession(sessionId: string): Session | undefined;
469
512
  getSessionByThread(channelId: string, threadId: string): Session | undefined;
513
+ registerSession(session: Session): void;
514
+ updateSessionPlatform(sessionId: string, platform: Record<string, unknown>): Promise<void>;
515
+ updateSessionActivity(sessionId: string): Promise<void>;
516
+ updateSessionStatus(sessionId: string, status: SessionStatus): Promise<void>;
470
517
  cancelSession(sessionId: string): Promise<void>;
471
518
  listSessions(channelId?: string): Session[];
472
519
  destroyAll(): Promise<void>;
@@ -521,6 +568,8 @@ declare class OpenACPCore {
521
568
  notificationManager: NotificationManager;
522
569
  adapters: Map<string, ChannelAdapter>;
523
570
  tunnelService?: TunnelService;
571
+ private sessionStore;
572
+ private resumeLocks;
524
573
  constructor(configManager: ConfigManager);
525
574
  registerAdapter(name: string, adapter: ChannelAdapter): void;
526
575
  start(): Promise<void>;
@@ -528,6 +577,7 @@ declare class OpenACPCore {
528
577
  handleMessage(message: IncomingMessage): Promise<void>;
529
578
  handleNewSession(channelId: string, agentName?: string, workspacePath?: string): Promise<Session>;
530
579
  handleNewChat(channelId: string, currentThreadId: string): Promise<Session | null>;
580
+ private lazyResume;
531
581
  private toOutgoingMessage;
532
582
  private enrichWithViewerLinks;
533
583
  wireSessionEvents(session: Session, adapter: ChannelAdapter): void;
@@ -575,4 +625,4 @@ declare class TelegramAdapter extends ChannelAdapter {
575
625
  private finalizeDraft;
576
626
  }
577
627
 
578
- export { type AdapterFactory, type AgentCommand, type AgentDefinition, type AgentEvent, AgentInstance, AgentManager, ChannelAdapter, type ChannelConfig, type Config, ConfigManager, type IncomingMessage, type Logger, type LoggingConfig, NotificationManager, type NotificationMessage, OpenACPCore, type OutgoingMessage, PLUGINS_DIR, type PermissionOption, type PermissionRequest, type PlanEntry, Session, SessionManager, type SessionStatus, StderrCapture, TelegramAdapter, cleanupOldSessionLogs, createChildLogger, createSessionLogger, expandHome, initLogger, installPlugin, listPlugins, loadAdapterFactory, log, nodeToWebReadable, nodeToWebWritable, shutdownLogger, uninstallPlugin };
628
+ export { type AdapterFactory, type AgentCommand, type AgentDefinition, type AgentEvent, AgentInstance, AgentManager, ChannelAdapter, type ChannelConfig, type Config, ConfigManager, type IncomingMessage, type Logger, type LoggingConfig, NotificationManager, type NotificationMessage, OpenACPCore, type OutgoingMessage, PLUGINS_DIR, type PermissionOption, type PermissionRequest, type PlanEntry, Session, SessionManager, type SessionRecord, type SessionStatus, StderrCapture, TelegramAdapter, type TelegramPlatformData, cleanupOldSessionLogs, createChildLogger, createSessionLogger, expandHome, initLogger, installPlugin, listPlugins, loadAdapterFactory, log, nodeToWebReadable, nodeToWebWritable, shutdownLogger, uninstallPlugin };
package/dist/index.js CHANGED
@@ -10,7 +10,7 @@ import {
10
10
  TelegramAdapter,
11
11
  nodeToWebReadable,
12
12
  nodeToWebWritable
13
- } from "./chunk-E6BM7RUB.js";
13
+ } from "./chunk-HTXK4NLG.js";
14
14
  import {
15
15
  ConfigManager,
16
16
  PLUGINS_DIR,
@@ -19,7 +19,7 @@ import {
19
19
  listPlugins,
20
20
  loadAdapterFactory,
21
21
  uninstallPlugin
22
- } from "./chunk-QY32F5S7.js";
22
+ } from "./chunk-XOVJLTEC.js";
23
23
  import {
24
24
  cleanupOldSessionLogs,
25
25
  createChildLogger,
@@ -2,11 +2,11 @@
2
2
  import {
3
3
  OpenACPCore,
4
4
  TelegramAdapter
5
- } from "./chunk-E6BM7RUB.js";
5
+ } from "./chunk-HTXK4NLG.js";
6
6
  import {
7
7
  ConfigManager,
8
8
  loadAdapterFactory
9
- } from "./chunk-QY32F5S7.js";
9
+ } from "./chunk-XOVJLTEC.js";
10
10
  import {
11
11
  cleanupOldSessionLogs,
12
12
  initLogger,
@@ -20,7 +20,7 @@ async function startServer() {
20
20
  const configManager = new ConfigManager();
21
21
  const configExists = await configManager.exists();
22
22
  if (!configExists) {
23
- const { runSetup } = await import("./setup-GIUUMBDH.js");
23
+ const { runSetup } = await import("./setup-FB4DGR6R.js");
24
24
  const shouldStart = await runSetup(configManager);
25
25
  if (!shouldStart) process.exit(0);
26
26
  }
@@ -34,7 +34,7 @@ async function startServer() {
34
34
  const core = new OpenACPCore(configManager);
35
35
  let tunnelService;
36
36
  if (config.tunnel.enabled) {
37
- const { TunnelService } = await import("./tunnel-service-FPRPBPQ5.js");
37
+ const { TunnelService } = await import("./tunnel-service-I6NUMBT4.js");
38
38
  tunnelService = new TunnelService(config.tunnel);
39
39
  const publicUrl = await tunnelService.start();
40
40
  core.tunnelService = tunnelService;
@@ -100,4 +100,4 @@ if (isDirectExecution) {
100
100
  export {
101
101
  startServer
102
102
  };
103
- //# sourceMappingURL=main-OAVE4LUW.js.map
103
+ //# sourceMappingURL=main-WH6JJXBY.js.map
@@ -174,7 +174,8 @@ async function detectChatId(token) {
174
174
  }
175
175
  }
176
176
  var KNOWN_AGENTS = [
177
- { name: "claude", commands: ["claude-agent-acp"] }
177
+ { name: "claude", commands: ["claude-agent-acp", "claude-code", "claude"] },
178
+ { name: "codex", commands: ["codex"] }
178
179
  ];
179
180
  function commandExists(cmd) {
180
181
  try {
@@ -306,7 +307,15 @@ async function runSetup(configManager) {
306
307
  maxFiles: 7,
307
308
  sessionLogRetentionDays: 30
308
309
  },
309
- tunnel: { enabled: false, port: 3100, provider: "cloudflare", options: {}, storeTtlMinutes: 60, auth: { enabled: false } }
310
+ sessionStore: { ttlDays: 30 },
311
+ tunnel: {
312
+ enabled: false,
313
+ port: 3100,
314
+ provider: "cloudflare",
315
+ options: {},
316
+ storeTtlMinutes: 60,
317
+ auth: { enabled: false }
318
+ }
310
319
  };
311
320
  try {
312
321
  await configManager.writeNew(config);
@@ -341,4 +350,4 @@ export {
341
350
  validateBotToken,
342
351
  validateChatId
343
352
  };
344
- //# sourceMappingURL=setup-GIUUMBDH.js.map
353
+ //# sourceMappingURL=setup-FB4DGR6R.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/setup.ts"],"sourcesContent":["import { execFileSync } from \"node:child_process\";\nimport * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport { input, select } from \"@inquirer/prompts\";\nimport type { Config, ConfigManager } from \"./config.js\";\n\n// --- ANSI colors ---\n\nconst c = {\n reset: \"\\x1b[0m\",\n bold: \"\\x1b[1m\",\n dim: \"\\x1b[2m\",\n green: \"\\x1b[32m\",\n yellow: \"\\x1b[33m\",\n red: \"\\x1b[31m\",\n cyan: \"\\x1b[36m\",\n white: \"\\x1b[37m\",\n};\n\nconst ok = (msg: string) =>\n `${c.green}${c.bold}✓${c.reset} ${c.green}${msg}${c.reset}`;\nconst warn = (msg: string) => `${c.yellow}⚠ ${msg}${c.reset}`;\nconst fail = (msg: string) => `${c.red}✗ ${msg}${c.reset}`;\nconst step = (n: number, title: string) =>\n `\\n${c.cyan}${c.bold}[${n}/3]${c.reset} ${c.bold}${title}${c.reset}\\n`;\nconst dim = (msg: string) => `${c.dim}${msg}${c.reset}`;\n\n// --- Telegram validation ---\n\nexport async function validateBotToken(\n token: string,\n): Promise<\n | { ok: true; botName: string; botUsername: string }\n | { ok: false; error: string }\n> {\n try {\n const res = await fetch(`https://api.telegram.org/bot${token}/getMe`);\n const data = (await res.json()) as {\n ok: boolean;\n result?: { first_name: string; username: string };\n description?: string;\n };\n if (data.ok && data.result) {\n return {\n ok: true,\n botName: data.result.first_name,\n botUsername: data.result.username,\n };\n }\n return { ok: false, error: data.description || \"Invalid token\" };\n } catch (err) {\n return { ok: false, error: (err as Error).message };\n }\n}\n\nexport async function validateChatId(\n token: string,\n chatId: number,\n): Promise<\n { ok: true; title: string; isForum: boolean } | { ok: false; error: string }\n> {\n try {\n const res = await fetch(`https://api.telegram.org/bot${token}/getChat`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ chat_id: chatId }),\n });\n const data = (await res.json()) as {\n ok: boolean;\n result?: { title: string; type: string; is_forum?: boolean };\n description?: string;\n };\n if (!data.ok || !data.result) {\n return { ok: false, error: data.description || \"Invalid chat ID\" };\n }\n if (data.result.type !== \"supergroup\") {\n return {\n ok: false,\n error: `Chat is \"${data.result.type}\", must be a supergroup`,\n };\n }\n return {\n ok: true,\n title: data.result.title,\n isForum: data.result.is_forum === true,\n };\n } catch (err) {\n return { ok: false, error: (err as Error).message };\n }\n}\n\n// --- Chat ID auto-detection ---\n\nfunction promptManualChatId(): Promise<number> {\n return input({\n message: \"Supergroup chat ID (e.g. -1001234567890):\",\n validate: (val) => {\n const n = Number(val.trim());\n if (isNaN(n) || !Number.isInteger(n)) return \"Chat ID must be an integer\";\n return true;\n },\n }).then((val) => Number(val.trim()));\n}\n\nasync function detectChatId(token: string): Promise<number> {\n // Clear old updates\n let lastUpdateId = 0;\n try {\n const clearRes = await fetch(\n `https://api.telegram.org/bot${token}/getUpdates?offset=-1`,\n );\n const clearData = (await clearRes.json()) as {\n ok: boolean;\n result?: Array<{ update_id: number }>;\n };\n if (clearData.ok && clearData.result?.length) {\n lastUpdateId = clearData.result[clearData.result.length - 1].update_id;\n }\n } catch {\n // ignore\n }\n\n console.log(\"\");\n console.log(` ${c.bold}If you don't have a supergroup yet:${c.reset}`);\n console.log(dim(\" 1. Open Telegram → New Group → add your bot\"));\n console.log(dim(\" 2. Group Settings → convert to Supergroup\"));\n console.log(dim(\" 3. Enable Topics in group settings\"));\n console.log(\"\");\n console.log(` ${c.bold}Then send \"hi\" in the group.${c.reset}`);\n console.log(\n dim(\n ` Listening... press ${c.reset}${c.yellow}m${c.reset}${c.dim} to enter ID manually`,\n ),\n );\n console.log(\"\");\n\n const MAX_ATTEMPTS = 120;\n const POLL_INTERVAL = 1000;\n\n // Listen for 'm' keypress to switch to manual\n let cancelled = false;\n const onKeypress = (data: Buffer) => {\n const key = data.toString();\n if (key === \"m\" || key === \"M\") {\n cancelled = true;\n }\n };\n if (process.stdin.isTTY) {\n process.stdin.setRawMode(true);\n process.stdin.resume();\n process.stdin.on(\"data\", onKeypress);\n }\n\n const cleanup = () => {\n if (process.stdin.isTTY) {\n process.stdin.removeListener(\"data\", onKeypress);\n process.stdin.setRawMode(false);\n process.stdin.pause();\n }\n };\n\n try {\n for (let i = 0; i < MAX_ATTEMPTS; i++) {\n if (cancelled) {\n cleanup();\n return promptManualChatId();\n }\n\n try {\n const offset = lastUpdateId ? lastUpdateId + 1 : 0;\n const res = await fetch(\n `https://api.telegram.org/bot${token}/getUpdates?offset=${offset}&timeout=1`,\n );\n const data = (await res.json()) as {\n ok: boolean;\n result?: Array<{\n update_id: number;\n message?: {\n chat: { id: number; title?: string; type: string };\n };\n my_chat_member?: {\n chat: { id: number; title?: string; type: string };\n };\n }>;\n };\n\n if (!data.ok || !data.result?.length) {\n await new Promise((r) => setTimeout(r, POLL_INTERVAL));\n continue;\n }\n\n const groups = new Map<number, string>();\n for (const update of data.result) {\n lastUpdateId = update.update_id;\n const chat = update.message?.chat ?? update.my_chat_member?.chat;\n if (chat && (chat.type === \"supergroup\" || chat.type === \"group\")) {\n groups.set(chat.id, chat.title ?? String(chat.id));\n }\n }\n\n if (groups.size === 1) {\n const [id, title] = [...groups.entries()][0];\n console.log(\n ok(`Group detected: ${c.bold}${title}${c.reset}${c.green} (${id})`),\n );\n cleanup();\n return id;\n }\n\n if (groups.size > 1) {\n cleanup();\n const choices = [...groups.entries()].map(([id, title]) => ({\n name: `${title} (${id})`,\n value: id,\n }));\n return select({\n message: \"Multiple groups found. Pick one:\",\n choices,\n });\n }\n } catch {\n // Network error, retry\n }\n await new Promise((r) => setTimeout(r, POLL_INTERVAL));\n }\n\n console.log(warn(\"Timed out waiting for messages.\"));\n cleanup();\n return promptManualChatId();\n } catch (err) {\n cleanup();\n throw err;\n }\n}\n\n// --- Agent detection ---\n\nconst KNOWN_AGENTS: Array<{ name: string; commands: string[] }> = [\n { name: \"claude\", commands: [\"claude-agent-acp\", \"claude-code\", \"claude\"] },\n { name: \"codex\", commands: [\"codex\"] },\n];\n\nfunction commandExists(cmd: string): boolean {\n try {\n execFileSync(\"which\", [cmd], { stdio: \"pipe\" });\n return true;\n } catch {\n // not in PATH\n }\n // Check node_modules/.bin (walks up from cwd)\n let dir = process.cwd();\n while (true) {\n const binPath = path.join(dir, \"node_modules\", \".bin\", cmd);\n if (fs.existsSync(binPath)) return true;\n const parent = path.dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return false;\n}\n\nexport async function detectAgents(): Promise<\n Array<{ name: string; command: string }>\n> {\n const found: Array<{ name: string; command: string }> = [];\n for (const agent of KNOWN_AGENTS) {\n // Find all available commands for this agent (PATH + node_modules/.bin)\n const available: string[] = [];\n for (const cmd of agent.commands) {\n if (commandExists(cmd)) {\n available.push(cmd);\n }\n }\n if (available.length > 0) {\n // Prefer claude-agent-acp over claude/claude-code (priority order)\n found.push({ name: agent.name, command: available[0] });\n }\n }\n return found;\n}\n\nexport async function validateAgentCommand(command: string): Promise<boolean> {\n try {\n execFileSync(\"which\", [command], { stdio: \"pipe\" });\n return true;\n } catch {\n return false;\n }\n}\n\n// --- Setup steps ---\n\nexport async function setupTelegram(): Promise<Config[\"channels\"][string]> {\n console.log(step(1, \"Telegram Bot\"));\n\n let botToken = \"\";\n\n while (true) {\n botToken = await input({\n message: \"Bot token (from @BotFather):\",\n validate: (val) => val.trim().length > 0 || \"Token cannot be empty\",\n });\n botToken = botToken.trim();\n\n const result = await validateBotToken(botToken);\n if (result.ok) {\n console.log(ok(`Connected to @${result.botUsername}`));\n break;\n }\n console.log(fail(result.error));\n const action = await select({\n message: \"What to do?\",\n choices: [\n { name: \"Re-enter token\", value: \"retry\" },\n { name: \"Use as-is (skip validation)\", value: \"skip\" },\n ],\n });\n if (action === \"skip\") break;\n }\n\n console.log(step(2, \"Group Chat\"));\n\n const chatId = await detectChatId(botToken);\n\n return {\n enabled: true,\n botToken,\n chatId,\n notificationTopicId: null,\n assistantTopicId: null,\n };\n}\n\nexport async function setupAgents(): Promise<{\n agents: Config[\"agents\"];\n defaultAgent: string;\n}> {\n const detected = await detectAgents();\n const agents: Config[\"agents\"] = {};\n\n if (detected.length > 0) {\n for (const agent of detected) {\n agents[agent.name] = { command: agent.command, args: [], env: {} };\n }\n } else {\n agents[\"claude\"] = { command: \"claude-agent-acp\", args: [], env: {} };\n }\n\n const defaultAgent = Object.keys(agents)[0];\n const agentCmd = agents[defaultAgent].command;\n console.log(\n ok(`Agent: ${c.bold}${defaultAgent}${c.reset}${c.green} (${agentCmd})`),\n );\n\n return { agents, defaultAgent };\n}\n\nexport async function setupWorkspace(): Promise<{ baseDir: string }> {\n console.log(step(3, \"Workspace\"));\n\n const baseDir = await input({\n message: \"Base directory for workspaces:\",\n default: \"~/openacp-workspace\",\n validate: (val) => val.trim().length > 0 || \"Path cannot be empty\",\n });\n\n return { baseDir: baseDir.trim().replace(/^['\"]|['\"]$/g, \"\") };\n}\n\n// --- Orchestrator ---\n\nfunction printWelcomeBanner(): void {\n console.log(`\n${c.cyan}${c.bold} ╔══════════════════════════════╗\n ║ Welcome to OpenACP ║\n ╚══════════════════════════════╝${c.reset}\n`);\n}\n\nexport async function runSetup(configManager: ConfigManager): Promise<boolean> {\n printWelcomeBanner();\n\n try {\n const telegram = await setupTelegram();\n const { agents, defaultAgent } = await setupAgents();\n const workspace = await setupWorkspace();\n const security = {\n allowedUserIds: [] as string[],\n maxConcurrentSessions: 5,\n sessionTimeoutMinutes: 60,\n };\n\n const config: Config = {\n channels: { telegram },\n agents,\n defaultAgent,\n workspace,\n security,\n logging: {\n level: \"info\",\n logDir: \"~/.openacp/logs\",\n maxFileSize: \"10m\",\n maxFiles: 7,\n sessionLogRetentionDays: 30,\n },\n sessionStore: { ttlDays: 30 },\n tunnel: {\n enabled: false,\n port: 3100,\n provider: \"cloudflare\",\n options: {},\n storeTtlMinutes: 60,\n auth: { enabled: false },\n },\n };\n\n try {\n await configManager.writeNew(config);\n } catch (writeErr) {\n console.log(\n fail(`Could not save config: ${(writeErr as Error).message}`),\n );\n return false;\n }\n\n console.log(\"\");\n console.log(\n ok(`Config saved to ${c.bold}${configManager.getConfigPath()}`),\n );\n console.log(ok(\"Starting OpenACP...\"));\n console.log(\"\");\n\n return true;\n } catch (err) {\n if ((err as Error).name === \"ExitPromptError\") {\n console.log(dim(\"\\nSetup cancelled.\"));\n return false;\n }\n throw err;\n }\n}\n"],"mappings":"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","names":[]}