@openacp/cli 0.2.22 → 0.2.24

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.
Files changed (44) hide show
  1. package/dist/autostart-YBYXQA77.js +18 -0
  2. package/dist/autostart-YBYXQA77.js.map +1 -0
  3. package/dist/{setup-XQBEZZQB.js → chunk-4BN7NSKB.js} +140 -9
  4. package/dist/chunk-4BN7NSKB.js.map +1 -0
  5. package/dist/chunk-CQMS5U7Z.js +63 -0
  6. package/dist/chunk-CQMS5U7Z.js.map +1 -0
  7. package/dist/{chunk-XOVJLTEC.js → chunk-FGXG3H3F.js} +14 -58
  8. package/dist/chunk-FGXG3H3F.js.map +1 -0
  9. package/dist/{chunk-HTXK4NLG.js → chunk-IX63F4JG.js} +463 -44
  10. package/dist/chunk-IX63F4JG.js.map +1 -0
  11. package/dist/{chunk-ZATQZUJT.js → chunk-MNJDYDGH.js} +9 -1
  12. package/dist/{chunk-ZATQZUJT.js.map → chunk-MNJDYDGH.js.map} +1 -1
  13. package/dist/chunk-PQRVTUNH.js +145 -0
  14. package/dist/chunk-PQRVTUNH.js.map +1 -0
  15. package/dist/chunk-QWUJIKTX.js +527 -0
  16. package/dist/chunk-QWUJIKTX.js.map +1 -0
  17. package/dist/chunk-S6O7SM6A.js +129 -0
  18. package/dist/chunk-S6O7SM6A.js.map +1 -0
  19. package/dist/chunk-WXS6ONOD.js +103 -0
  20. package/dist/chunk-WXS6ONOD.js.map +1 -0
  21. package/dist/cli.js +354 -4
  22. package/dist/cli.js.map +1 -1
  23. package/dist/config-2XALNLAA.js +14 -0
  24. package/dist/config-2XALNLAA.js.map +1 -0
  25. package/dist/config-editor-56B6YU7B.js +11 -0
  26. package/dist/config-editor-56B6YU7B.js.map +1 -0
  27. package/dist/daemon-3E5OMLT3.js +29 -0
  28. package/dist/daemon-3E5OMLT3.js.map +1 -0
  29. package/dist/index.d.ts +96 -18
  30. package/dist/index.js +35 -6
  31. package/dist/install-cloudflared-57NRTI4E.js +8 -0
  32. package/dist/install-cloudflared-57NRTI4E.js.map +1 -0
  33. package/dist/{main-GC6JY7DS.js → main-YNCSLYVV.js} +43 -11
  34. package/dist/main-YNCSLYVV.js.map +1 -0
  35. package/dist/setup-FTNJACSC.js +27 -0
  36. package/dist/setup-FTNJACSC.js.map +1 -0
  37. package/dist/{tunnel-service-I6NUMBT4.js → tunnel-service-I6WM6USB.js} +10 -10
  38. package/dist/tunnel-service-I6WM6USB.js.map +1 -0
  39. package/package.json +2 -2
  40. package/dist/chunk-HTXK4NLG.js.map +0 -1
  41. package/dist/chunk-XOVJLTEC.js.map +0 -1
  42. package/dist/main-GC6JY7DS.js.map +0 -1
  43. package/dist/setup-XQBEZZQB.js.map +0 -1
  44. package/dist/tunnel-service-I6NUMBT4.js.map +0 -1
package/dist/index.d.ts CHANGED
@@ -114,13 +114,13 @@ declare const LoggingSchema: z.ZodDefault<z.ZodObject<{
114
114
  maxFiles: z.ZodDefault<z.ZodNumber>;
115
115
  sessionLogRetentionDays: z.ZodDefault<z.ZodNumber>;
116
116
  }, "strip", z.ZodTypeAny, {
117
- level: "fatal" | "error" | "warn" | "info" | "debug" | "silent";
117
+ level: "error" | "silent" | "debug" | "info" | "warn" | "fatal";
118
118
  logDir: string;
119
119
  maxFileSize: string | number;
120
120
  maxFiles: number;
121
121
  sessionLogRetentionDays: number;
122
122
  }, {
123
- level?: "fatal" | "error" | "warn" | "info" | "debug" | "silent" | undefined;
123
+ level?: "error" | "silent" | "debug" | "info" | "warn" | "fatal" | undefined;
124
124
  logDir?: string | undefined;
125
125
  maxFileSize?: string | number | undefined;
126
126
  maxFiles?: number | undefined;
@@ -220,18 +220,30 @@ declare const ConfigSchema: z.ZodObject<{
220
220
  maxFiles: z.ZodDefault<z.ZodNumber>;
221
221
  sessionLogRetentionDays: z.ZodDefault<z.ZodNumber>;
222
222
  }, "strip", z.ZodTypeAny, {
223
- level: "fatal" | "error" | "warn" | "info" | "debug" | "silent";
223
+ level: "error" | "silent" | "debug" | "info" | "warn" | "fatal";
224
224
  logDir: string;
225
225
  maxFileSize: string | number;
226
226
  maxFiles: number;
227
227
  sessionLogRetentionDays: number;
228
228
  }, {
229
- level?: "fatal" | "error" | "warn" | "info" | "debug" | "silent" | undefined;
229
+ level?: "error" | "silent" | "debug" | "info" | "warn" | "fatal" | undefined;
230
230
  logDir?: string | undefined;
231
231
  maxFileSize?: string | number | undefined;
232
232
  maxFiles?: number | undefined;
233
233
  sessionLogRetentionDays?: number | undefined;
234
234
  }>>;
235
+ runMode: z.ZodDefault<z.ZodEnum<["foreground", "daemon"]>>;
236
+ autoStart: z.ZodDefault<z.ZodBoolean>;
237
+ api: z.ZodDefault<z.ZodObject<{
238
+ port: z.ZodDefault<z.ZodNumber>;
239
+ host: z.ZodDefault<z.ZodString>;
240
+ }, "strip", z.ZodTypeAny, {
241
+ port: number;
242
+ host: string;
243
+ }, {
244
+ port?: number | undefined;
245
+ host?: string | undefined;
246
+ }>>;
235
247
  sessionStore: z.ZodDefault<z.ZodObject<{
236
248
  ttlDays: z.ZodDefault<z.ZodNumber>;
237
249
  }, "strip", z.ZodTypeAny, {
@@ -277,32 +289,38 @@ declare const ConfigSchema: z.ZodObject<{
277
289
  } | undefined;
278
290
  }>>;
279
291
  }, "strip", z.ZodTypeAny, {
280
- channels: Record<string, z.objectOutputType<{
281
- enabled: z.ZodDefault<z.ZodBoolean>;
282
- adapter: z.ZodOptional<z.ZodString>;
283
- }, z.ZodTypeAny, "passthrough">>;
292
+ workspace: {
293
+ baseDir: string;
294
+ };
284
295
  agents: Record<string, {
285
296
  command: string;
286
297
  args: string[];
287
298
  env: Record<string, string>;
288
299
  workingDirectory?: string | undefined;
289
300
  }>;
301
+ channels: Record<string, z.objectOutputType<{
302
+ enabled: z.ZodDefault<z.ZodBoolean>;
303
+ adapter: z.ZodOptional<z.ZodString>;
304
+ }, z.ZodTypeAny, "passthrough">>;
290
305
  defaultAgent: string;
291
- workspace: {
292
- baseDir: string;
293
- };
294
306
  security: {
295
307
  allowedUserIds: string[];
296
308
  maxConcurrentSessions: number;
297
309
  sessionTimeoutMinutes: number;
298
310
  };
299
311
  logging: {
300
- level: "fatal" | "error" | "warn" | "info" | "debug" | "silent";
312
+ level: "error" | "silent" | "debug" | "info" | "warn" | "fatal";
301
313
  logDir: string;
302
314
  maxFileSize: string | number;
303
315
  maxFiles: number;
304
316
  sessionLogRetentionDays: number;
305
317
  };
318
+ runMode: "foreground" | "daemon";
319
+ autoStart: boolean;
320
+ api: {
321
+ port: number;
322
+ host: string;
323
+ };
306
324
  sessionStore: {
307
325
  ttlDays: number;
308
326
  };
@@ -318,16 +336,16 @@ declare const ConfigSchema: z.ZodObject<{
318
336
  };
319
337
  };
320
338
  }, {
321
- channels: Record<string, z.objectInputType<{
322
- enabled: z.ZodDefault<z.ZodBoolean>;
323
- adapter: z.ZodOptional<z.ZodString>;
324
- }, z.ZodTypeAny, "passthrough">>;
325
339
  agents: Record<string, {
326
340
  command: string;
327
341
  args?: string[] | undefined;
328
342
  workingDirectory?: string | undefined;
329
343
  env?: Record<string, string> | undefined;
330
344
  }>;
345
+ channels: Record<string, z.objectInputType<{
346
+ enabled: z.ZodDefault<z.ZodBoolean>;
347
+ adapter: z.ZodOptional<z.ZodString>;
348
+ }, z.ZodTypeAny, "passthrough">>;
331
349
  defaultAgent: string;
332
350
  workspace?: {
333
351
  baseDir?: string | undefined;
@@ -338,12 +356,18 @@ declare const ConfigSchema: z.ZodObject<{
338
356
  sessionTimeoutMinutes?: number | undefined;
339
357
  } | undefined;
340
358
  logging?: {
341
- level?: "fatal" | "error" | "warn" | "info" | "debug" | "silent" | undefined;
359
+ level?: "error" | "silent" | "debug" | "info" | "warn" | "fatal" | undefined;
342
360
  logDir?: string | undefined;
343
361
  maxFileSize?: string | number | undefined;
344
362
  maxFiles?: number | undefined;
345
363
  sessionLogRetentionDays?: number | undefined;
346
364
  } | undefined;
365
+ runMode?: "foreground" | "daemon" | undefined;
366
+ autoStart?: boolean | undefined;
367
+ api?: {
368
+ port?: number | undefined;
369
+ host?: string | undefined;
370
+ } | undefined;
347
371
  sessionStore?: {
348
372
  ttlDays?: number | undefined;
349
373
  } | undefined;
@@ -592,6 +616,60 @@ declare function uninstallPlugin(packageName: string): void;
592
616
  declare function listPlugins(): Record<string, string>;
593
617
  declare function loadAdapterFactory(packageName: string): Promise<AdapterFactory | null>;
594
618
 
619
+ declare function getStatus(pidPath?: string): {
620
+ running: boolean;
621
+ pid?: number;
622
+ };
623
+ declare function startDaemon(pidPath?: string, logDir?: string): {
624
+ pid: number;
625
+ } | {
626
+ error: string;
627
+ };
628
+ declare function stopDaemon(pidPath?: string): {
629
+ stopped: boolean;
630
+ pid?: number;
631
+ error?: string;
632
+ };
633
+ declare function getPidPath(): string;
634
+
635
+ declare function isAutoStartSupported(): boolean;
636
+ declare function installAutoStart(logDir: string): {
637
+ success: boolean;
638
+ error?: string;
639
+ };
640
+ declare function uninstallAutoStart(): {
641
+ success: boolean;
642
+ error?: string;
643
+ };
644
+ declare function isAutoStartInstalled(): boolean;
645
+
646
+ declare function runConfigEditor(configManager: ConfigManager): Promise<void>;
647
+
648
+ interface ApiConfig {
649
+ port: number;
650
+ host: string;
651
+ }
652
+ declare class ApiServer {
653
+ private core;
654
+ private config;
655
+ private server;
656
+ private actualPort;
657
+ private portFilePath;
658
+ constructor(core: OpenACPCore, config: ApiConfig, portFilePath?: string);
659
+ start(): Promise<void>;
660
+ stop(): Promise<void>;
661
+ getPort(): number;
662
+ private writePortFile;
663
+ private removePortFile;
664
+ private handleRequest;
665
+ private handleCreateSession;
666
+ private handleCancelSession;
667
+ private handleListSessions;
668
+ private handleListAgents;
669
+ private sendJson;
670
+ private readBody;
671
+ }
672
+
595
673
  interface TelegramChannelConfig {
596
674
  enabled: boolean;
597
675
  botToken: string;
@@ -625,4 +703,4 @@ declare class TelegramAdapter extends ChannelAdapter {
625
703
  private finalizeDraft;
626
704
  }
627
705
 
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 };
706
+ export { type AdapterFactory, type AgentCommand, type AgentDefinition, type AgentEvent, AgentInstance, AgentManager, type ApiConfig, ApiServer, 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, getPidPath, getStatus, initLogger, installAutoStart, installPlugin, isAutoStartInstalled, isAutoStartSupported, listPlugins, loadAdapterFactory, log, nodeToWebReadable, nodeToWebWritable, runConfigEditor, shutdownLogger, startDaemon, stopDaemon, uninstallAutoStart, uninstallPlugin };
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import {
2
2
  AgentInstance,
3
3
  AgentManager,
4
+ ApiServer,
4
5
  ChannelAdapter,
5
6
  NotificationManager,
6
7
  OpenACPCore,
@@ -10,16 +11,34 @@ import {
10
11
  TelegramAdapter,
11
12
  nodeToWebReadable,
12
13
  nodeToWebWritable
13
- } from "./chunk-HTXK4NLG.js";
14
+ } from "./chunk-IX63F4JG.js";
14
15
  import {
15
- ConfigManager,
16
- PLUGINS_DIR,
17
- expandHome,
18
16
  installPlugin,
19
17
  listPlugins,
20
18
  loadAdapterFactory,
21
19
  uninstallPlugin
22
- } from "./chunk-XOVJLTEC.js";
20
+ } from "./chunk-CQMS5U7Z.js";
21
+ import {
22
+ getPidPath,
23
+ getStatus,
24
+ startDaemon,
25
+ stopDaemon
26
+ } from "./chunk-S6O7SM6A.js";
27
+ import {
28
+ runConfigEditor
29
+ } from "./chunk-QWUJIKTX.js";
30
+ import {
31
+ installAutoStart,
32
+ isAutoStartInstalled,
33
+ isAutoStartSupported,
34
+ uninstallAutoStart
35
+ } from "./chunk-PQRVTUNH.js";
36
+ import "./chunk-4BN7NSKB.js";
37
+ import {
38
+ ConfigManager,
39
+ PLUGINS_DIR,
40
+ expandHome
41
+ } from "./chunk-FGXG3H3F.js";
23
42
  import {
24
43
  cleanupOldSessionLogs,
25
44
  createChildLogger,
@@ -27,10 +46,11 @@ import {
27
46
  initLogger,
28
47
  log,
29
48
  shutdownLogger
30
- } from "./chunk-ZATQZUJT.js";
49
+ } from "./chunk-MNJDYDGH.js";
31
50
  export {
32
51
  AgentInstance,
33
52
  AgentManager,
53
+ ApiServer,
34
54
  ChannelAdapter,
35
55
  ConfigManager,
36
56
  NotificationManager,
@@ -44,14 +64,23 @@ export {
44
64
  createChildLogger,
45
65
  createSessionLogger,
46
66
  expandHome,
67
+ getPidPath,
68
+ getStatus,
47
69
  initLogger,
70
+ installAutoStart,
48
71
  installPlugin,
72
+ isAutoStartInstalled,
73
+ isAutoStartSupported,
49
74
  listPlugins,
50
75
  loadAdapterFactory,
51
76
  log,
52
77
  nodeToWebReadable,
53
78
  nodeToWebWritable,
79
+ runConfigEditor,
54
80
  shutdownLogger,
81
+ startDaemon,
82
+ stopDaemon,
83
+ uninstallAutoStart,
55
84
  uninstallPlugin
56
85
  };
57
86
  //# sourceMappingURL=index.js.map
@@ -0,0 +1,8 @@
1
+ import {
2
+ ensureCloudflared
3
+ } from "./chunk-WXS6ONOD.js";
4
+ import "./chunk-MNJDYDGH.js";
5
+ export {
6
+ ensureCloudflared
7
+ };
8
+ //# sourceMappingURL=install-cloudflared-57NRTI4E.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,26 +1,50 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
+ ApiServer,
3
4
  OpenACPCore,
4
5
  TelegramAdapter
5
- } from "./chunk-HTXK4NLG.js";
6
+ } from "./chunk-IX63F4JG.js";
6
7
  import {
7
- ConfigManager,
8
8
  loadAdapterFactory
9
- } from "./chunk-XOVJLTEC.js";
9
+ } from "./chunk-CQMS5U7Z.js";
10
+ import "./chunk-S6O7SM6A.js";
11
+ import "./chunk-QWUJIKTX.js";
12
+ import "./chunk-PQRVTUNH.js";
13
+ import "./chunk-4BN7NSKB.js";
14
+ import {
15
+ ConfigManager
16
+ } from "./chunk-FGXG3H3F.js";
10
17
  import {
11
18
  cleanupOldSessionLogs,
12
19
  initLogger,
13
20
  log,
14
21
  shutdownLogger
15
- } from "./chunk-ZATQZUJT.js";
22
+ } from "./chunk-MNJDYDGH.js";
16
23
 
17
24
  // src/main.ts
18
25
  var shuttingDown = false;
19
26
  async function startServer() {
27
+ if (process.argv.includes("--daemon-child")) {
28
+ const { writePidFile, readPidFile, getPidPath, shouldAutoStart } = await import("./daemon-3E5OMLT3.js");
29
+ if (!shouldAutoStart()) {
30
+ process.exit(0);
31
+ }
32
+ const pidPath = getPidPath();
33
+ const existingPid = readPidFile(pidPath);
34
+ if (existingPid !== null && existingPid !== process.pid) {
35
+ try {
36
+ process.kill(existingPid, 0);
37
+ console.error(`Another OpenACP instance is already running (PID ${existingPid}). Exiting.`);
38
+ process.exit(1);
39
+ } catch {
40
+ }
41
+ }
42
+ writePidFile(pidPath, process.pid);
43
+ }
20
44
  const configManager = new ConfigManager();
21
45
  const configExists = await configManager.exists();
22
46
  if (!configExists) {
23
- const { runSetup } = await import("./setup-XQBEZZQB.js");
47
+ const { runSetup } = await import("./setup-FTNJACSC.js");
24
48
  const shouldStart = await runSetup(configManager);
25
49
  if (!shouldStart) process.exit(0);
26
50
  }
@@ -34,7 +58,7 @@ async function startServer() {
34
58
  const core = new OpenACPCore(configManager);
35
59
  let tunnelService;
36
60
  if (config.tunnel.enabled) {
37
- const { TunnelService } = await import("./tunnel-service-I6NUMBT4.js");
61
+ const { TunnelService } = await import("./tunnel-service-I6WM6USB.js");
38
62
  tunnelService = new TunnelService(config.tunnel);
39
63
  const publicUrl = await tunnelService.start();
40
64
  core.tunnelService = tunnelService;
@@ -64,20 +88,22 @@ async function startServer() {
64
88
  log.error("No channels enabled. Enable at least one channel in config.");
65
89
  process.exit(1);
66
90
  }
67
- await core.start();
68
- const agents = Object.keys(config.agents);
69
- log.info({ agents }, "OpenACP started");
70
- log.info("Press Ctrl+C to stop");
91
+ let apiServer;
71
92
  const shutdown = async (signal) => {
72
93
  if (shuttingDown) return;
73
94
  shuttingDown = true;
74
95
  log.info({ signal }, "Signal received, shutting down");
75
96
  try {
97
+ if (apiServer) await apiServer.stop();
76
98
  await core.stop();
77
99
  if (tunnelService) await tunnelService.stop();
78
100
  } catch (err) {
79
101
  log.error({ err }, "Error during shutdown");
80
102
  }
103
+ if (process.argv.includes("--daemon-child")) {
104
+ const { removePidFile, getPidPath } = await import("./daemon-3E5OMLT3.js");
105
+ removePidFile(getPidPath());
106
+ }
81
107
  await shutdownLogger();
82
108
  process.exit(0);
83
109
  };
@@ -89,6 +115,12 @@ async function startServer() {
89
115
  process.on("unhandledRejection", (err) => {
90
116
  log.error({ err }, "Unhandled rejection");
91
117
  });
118
+ await core.start();
119
+ apiServer = new ApiServer(core, config.api);
120
+ await apiServer.start();
121
+ const agents = Object.keys(config.agents);
122
+ log.info({ agents }, "OpenACP started");
123
+ log.info("Press Ctrl+C to stop");
92
124
  }
93
125
  var isDirectExecution = process.argv[1]?.endsWith("main.js");
94
126
  if (isDirectExecution) {
@@ -100,4 +132,4 @@ if (isDirectExecution) {
100
132
  export {
101
133
  startServer
102
134
  };
103
- //# sourceMappingURL=main-GC6JY7DS.js.map
135
+ //# sourceMappingURL=main-YNCSLYVV.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/main.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { ConfigManager } from './core/config.js'\nimport { OpenACPCore } from './core/core.js'\nimport { loadAdapterFactory } from './core/plugin-manager.js'\nimport { initLogger, shutdownLogger, cleanupOldSessionLogs, log } from './core/log.js'\nimport { TelegramAdapter } from './adapters/telegram/index.js'\nimport { ApiServer } from './core/api-server.js'\n\nlet shuttingDown = false\n\nexport async function startServer() {\n // 0. If running as daemon child, check state and write PID file\n if (process.argv.includes('--daemon-child')) {\n const { writePidFile, readPidFile, getPidPath, shouldAutoStart } = await import('./core/daemon.js')\n\n // Only auto-start if the daemon was previously running (user started it)\n if (!shouldAutoStart()) {\n process.exit(0)\n }\n\n const pidPath = getPidPath()\n const existingPid = readPidFile(pidPath)\n if (existingPid !== null && existingPid !== process.pid) {\n try {\n process.kill(existingPid, 0)\n console.error(`Another OpenACP instance is already running (PID ${existingPid}). Exiting.`)\n process.exit(1)\n } catch {\n // Stale PID file — safe to overwrite\n }\n }\n writePidFile(pidPath, process.pid)\n }\n\n // 1. Check config exists, run setup if not\n const configManager = new ConfigManager()\n const configExists = await configManager.exists()\n\n if (!configExists) {\n const { runSetup } = await import('./core/setup.js')\n const shouldStart = await runSetup(configManager)\n if (!shouldStart) process.exit(0)\n }\n\n // 2. Load config (validates with Zod)\n await configManager.load()\n const config = configManager.get()\n initLogger(config.logging)\n log.info({ configPath: configManager.getConfigPath() }, 'Config loaded')\n\n // Async cleanup of old session logs (non-blocking)\n cleanupOldSessionLogs(config.logging.sessionLogRetentionDays).catch(err =>\n log.warn({ err }, 'Session log cleanup failed')\n )\n\n // 3. Create core\n const core = new OpenACPCore(configManager)\n\n // 3.5 Start tunnel if configured\n let tunnelService: import('./tunnel/tunnel-service.js').TunnelService | undefined\n if (config.tunnel.enabled) {\n const { TunnelService } = await import('./tunnel/tunnel-service.js')\n tunnelService = new TunnelService(config.tunnel)\n const publicUrl = await tunnelService.start()\n core.tunnelService = tunnelService\n log.info({ publicUrl }, 'Tunnel started')\n }\n\n // 4. Register adapters from config\n for (const [channelName, channelConfig] of Object.entries(config.channels)) {\n if (!channelConfig.enabled) continue\n\n if (channelName === 'telegram') {\n core.registerAdapter('telegram', new TelegramAdapter(core, channelConfig as any))\n log.info({ adapter: 'telegram' }, 'Adapter registered')\n } else if (channelConfig.adapter) {\n // Plugin adapter\n const factory = await loadAdapterFactory(channelConfig.adapter)\n if (factory) {\n const adapter = factory.createAdapter(core, channelConfig)\n core.registerAdapter(channelName, adapter)\n log.info({ adapter: channelName, plugin: channelConfig.adapter }, 'Adapter registered')\n } else {\n const name = channelName\n const err = channelConfig.adapter\n log.error({ adapter: name, err }, 'Failed to load adapter')\n }\n } else {\n log.error({ adapter: channelName }, 'Channel has no built-in adapter; set \"adapter\" field to a plugin package')\n }\n }\n\n if (core.adapters.size === 0) {\n log.error('No channels enabled. Enable at least one channel in config.')\n process.exit(1)\n }\n\n // 5. Start\n let apiServer: ApiServer | undefined\n\n const shutdown = async (signal: string) => {\n if (shuttingDown) return\n shuttingDown = true\n log.info({ signal }, 'Signal received, shutting down')\n\n try {\n if (apiServer) await apiServer.stop()\n await core.stop()\n if (tunnelService) await tunnelService.stop()\n } catch (err) {\n log.error({ err }, 'Error during shutdown')\n }\n\n // Clean up PID file if running as daemon\n if (process.argv.includes('--daemon-child')) {\n const { removePidFile, getPidPath } = await import('./core/daemon.js')\n removePidFile(getPidPath())\n }\n\n await shutdownLogger()\n process.exit(0)\n }\n\n process.on('SIGINT', () => shutdown('SIGINT'))\n process.on('SIGTERM', () => shutdown('SIGTERM'))\n\n process.on('uncaughtException', (err) => {\n log.error({ err }, 'Uncaught exception')\n })\n\n process.on('unhandledRejection', (err) => {\n log.error({ err }, 'Unhandled rejection')\n })\n\n await core.start()\n\n apiServer = new ApiServer(core, config.api)\n await apiServer.start()\n\n // 6. Log ready\n const agents = Object.keys(config.agents)\n log.info({ agents }, 'OpenACP started')\n log.info('Press Ctrl+C to stop')\n}\n\n// Direct execution for dev (node dist/main.js)\nconst isDirectExecution = process.argv[1]?.endsWith('main.js')\nif (isDirectExecution) {\n startServer().catch((err) => {\n log.error({ err }, 'Fatal error')\n process.exit(1)\n })\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,27 @@
1
+ import {
2
+ detectAgents,
3
+ runSetup,
4
+ setupAgents,
5
+ setupRunMode,
6
+ setupTelegram,
7
+ setupWorkspace,
8
+ validateAgentCommand,
9
+ validateBotAdmin,
10
+ validateBotToken,
11
+ validateChatId
12
+ } from "./chunk-4BN7NSKB.js";
13
+ import "./chunk-FGXG3H3F.js";
14
+ import "./chunk-MNJDYDGH.js";
15
+ export {
16
+ detectAgents,
17
+ runSetup,
18
+ setupAgents,
19
+ setupRunMode,
20
+ setupTelegram,
21
+ setupWorkspace,
22
+ validateAgentCommand,
23
+ validateBotAdmin,
24
+ validateBotToken,
25
+ validateChatId
26
+ };
27
+ //# sourceMappingURL=setup-FTNJACSC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,6 +1,9 @@
1
+ import {
2
+ ensureCloudflared
3
+ } from "./chunk-WXS6ONOD.js";
1
4
  import {
2
5
  createChildLogger
3
- } from "./chunk-ZATQZUJT.js";
6
+ } from "./chunk-MNJDYDGH.js";
4
7
 
5
8
  // src/tunnel/tunnel-service.ts
6
9
  import { serve } from "@hono/node-server";
@@ -16,6 +19,7 @@ var CloudflareTunnelProvider = class {
16
19
  this.options = options;
17
20
  }
18
21
  async start(localPort) {
22
+ const binaryPath = await ensureCloudflared();
19
23
  const args = ["tunnel", "--url", `http://localhost:${localPort}`];
20
24
  if (this.options.domain) {
21
25
  args.push("--hostname", String(this.options.domain));
@@ -23,15 +27,13 @@ var CloudflareTunnelProvider = class {
23
27
  return new Promise((resolve2, reject) => {
24
28
  const timeout = setTimeout(() => {
25
29
  this.stop();
26
- reject(new Error("Cloudflare tunnel timed out after 30s. Is cloudflared installed?"));
30
+ reject(new Error("Cloudflare tunnel timed out after 30s"));
27
31
  }, 3e4);
28
32
  try {
29
- this.child = spawn("cloudflared", args, { stdio: ["ignore", "pipe", "pipe"] });
33
+ this.child = spawn(binaryPath, args, { stdio: ["ignore", "pipe", "pipe"] });
30
34
  } catch {
31
35
  clearTimeout(timeout);
32
- reject(new Error(
33
- "Failed to start cloudflared. Install it from https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation/"
34
- ));
36
+ reject(new Error(`Failed to start cloudflared at ${binaryPath}`));
35
37
  return;
36
38
  }
37
39
  const urlPattern = /https:\/\/[a-zA-Z0-9-]+\.trycloudflare\.com/;
@@ -50,9 +52,7 @@ var CloudflareTunnelProvider = class {
50
52
  this.child.stderr?.on("data", onData);
51
53
  this.child.on("error", (err) => {
52
54
  clearTimeout(timeout);
53
- reject(new Error(
54
- `cloudflared failed to start: ${err.message}. Install it from https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation/`
55
- ));
55
+ reject(new Error(`cloudflared failed to start: ${err.message}`));
56
56
  });
57
57
  this.child.on("exit", (code) => {
58
58
  if (!this.publicUrl) {
@@ -878,4 +878,4 @@ var TunnelService = class {
878
878
  export {
879
879
  TunnelService
880
880
  };
881
- //# sourceMappingURL=tunnel-service-I6NUMBT4.js.map
881
+ //# sourceMappingURL=tunnel-service-I6WM6USB.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/tunnel/tunnel-service.ts","../../src/tunnel/providers/cloudflare.ts","../../src/tunnel/providers/ngrok.ts","../../src/tunnel/providers/bore.ts","../../src/tunnel/providers/tailscale.ts","../../src/tunnel/viewer-store.ts","../../src/tunnel/server.ts","../../src/tunnel/templates/file-viewer.ts","../../src/tunnel/templates/diff-viewer.ts"],"sourcesContent":["import { serve } from '@hono/node-server'\nimport type { TunnelConfig } from '../core/config.js'\nimport { createChildLogger } from '../core/log.js'\nimport type { TunnelProvider } from './provider.js'\nimport { CloudflareTunnelProvider } from './providers/cloudflare.js'\nimport { NgrokTunnelProvider } from './providers/ngrok.js'\nimport { BoreTunnelProvider } from './providers/bore.js'\nimport { TailscaleTunnelProvider } from './providers/tailscale.js'\nimport { ViewerStore } from './viewer-store.js'\nimport { createTunnelServer } from './server.js'\n\nconst log = createChildLogger({ module: 'tunnel' })\n\nexport class TunnelService {\n private provider: TunnelProvider\n private store: ViewerStore\n private server: ReturnType<typeof serve> | null = null\n private publicUrl = ''\n private config: TunnelConfig\n\n constructor(config: TunnelConfig) {\n this.config = config\n this.store = new ViewerStore(config.storeTtlMinutes)\n this.provider = this.createProvider(config.provider, config.options)\n }\n\n async start(): Promise<string> {\n // 1. Start HTTP server\n const authToken = this.config.auth.enabled ? this.config.auth.token : undefined\n const app = createTunnelServer(this.store, authToken)\n\n this.server = serve({ fetch: app.fetch, port: this.config.port })\n // Wait for server to be listening or fail\n await new Promise<void>((resolve, reject) => {\n this.server!.on('listening', () => resolve())\n this.server!.on('error', (err: NodeJS.ErrnoException) => reject(err))\n }).catch((err) => {\n log.warn({ err: err.message, port: this.config.port }, 'Tunnel HTTP server failed to start')\n this.server = null\n this.publicUrl = `http://localhost:${this.config.port}`\n return\n })\n if (!this.server) return this.publicUrl\n log.info({ port: this.config.port }, 'Tunnel HTTP server started')\n\n // 2. Start tunnel provider\n try {\n this.publicUrl = await this.provider.start(this.config.port)\n log.info({ url: this.publicUrl }, 'Tunnel public URL ready')\n } catch (err) {\n log.warn({ err }, 'Tunnel provider failed to start, running without public URL')\n this.publicUrl = `http://localhost:${this.config.port}`\n }\n\n return this.publicUrl\n }\n\n async stop(): Promise<void> {\n await this.provider.stop()\n if (this.server) {\n this.server.close()\n this.server = null\n }\n this.store.destroy()\n log.info('Tunnel service stopped')\n }\n\n getPublicUrl(): string {\n return this.publicUrl\n }\n\n getStore(): ViewerStore {\n return this.store\n }\n\n fileUrl(entryId: string): string {\n return `${this.publicUrl}/view/${entryId}`\n }\n\n diffUrl(entryId: string): string {\n return `${this.publicUrl}/diff/${entryId}`\n }\n\n private createProvider(name: string, options: Record<string, unknown>): TunnelProvider {\n switch (name) {\n case 'cloudflare':\n return new CloudflareTunnelProvider(options)\n case 'ngrok':\n return new NgrokTunnelProvider(options)\n case 'bore':\n return new BoreTunnelProvider(options)\n case 'tailscale':\n return new TailscaleTunnelProvider(options)\n default:\n log.warn({ provider: name }, 'Unknown tunnel provider, falling back to cloudflare')\n return new CloudflareTunnelProvider(options)\n }\n }\n}\n","import { spawn, type ChildProcess } from 'node:child_process'\nimport { createChildLogger } from '../../core/log.js'\nimport type { TunnelProvider } from '../provider.js'\nimport { ensureCloudflared } from './install-cloudflared.js'\n\nconst log = createChildLogger({ module: 'cloudflare-tunnel' })\n\nexport class CloudflareTunnelProvider implements TunnelProvider {\n private child: ChildProcess | null = null\n private publicUrl = ''\n private options: Record<string, unknown>\n\n constructor(options: Record<string, unknown> = {}) {\n this.options = options\n }\n\n async start(localPort: number): Promise<string> {\n // Auto-install cloudflared if not present\n const binaryPath = await ensureCloudflared()\n\n const args = ['tunnel', '--url', `http://localhost:${localPort}`]\n if (this.options.domain) {\n args.push('--hostname', String(this.options.domain))\n }\n\n return new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.stop()\n reject(new Error('Cloudflare tunnel timed out after 30s'))\n }, 30_000)\n\n try {\n this.child = spawn(binaryPath, args, { stdio: ['ignore', 'pipe', 'pipe'] })\n } catch {\n clearTimeout(timeout)\n reject(new Error(`Failed to start cloudflared at ${binaryPath}`))\n return\n }\n\n const urlPattern = /https:\\/\\/[a-zA-Z0-9-]+\\.trycloudflare\\.com/\n\n const onData = (data: Buffer) => {\n const line = data.toString()\n log.debug(line.trim())\n const match = line.match(urlPattern)\n if (match) {\n clearTimeout(timeout)\n this.publicUrl = match[0]\n log.info({ url: this.publicUrl }, 'Cloudflare tunnel ready')\n resolve(this.publicUrl)\n }\n }\n\n this.child.stdout?.on('data', onData)\n this.child.stderr?.on('data', onData)\n\n this.child.on('error', (err) => {\n clearTimeout(timeout)\n reject(new Error(`cloudflared failed to start: ${err.message}`))\n })\n\n this.child.on('exit', (code) => {\n if (!this.publicUrl) {\n clearTimeout(timeout)\n reject(new Error(`cloudflared exited with code ${code} before establishing tunnel`))\n }\n })\n })\n }\n\n async stop(): Promise<void> {\n if (this.child) {\n this.child.kill('SIGTERM')\n this.child = null\n log.info('Cloudflare tunnel stopped')\n }\n }\n\n getPublicUrl(): string {\n return this.publicUrl\n }\n}\n","import { spawn, type ChildProcess } from 'node:child_process'\nimport { createChildLogger } from '../../core/log.js'\nimport type { TunnelProvider } from '../provider.js'\n\nconst log = createChildLogger({ module: 'ngrok-tunnel' })\n\nexport class NgrokTunnelProvider implements TunnelProvider {\n private child: ChildProcess | null = null\n private publicUrl = ''\n private options: Record<string, unknown>\n\n constructor(options: Record<string, unknown> = {}) {\n this.options = options\n }\n\n async start(localPort: number): Promise<string> {\n const args = ['http', String(localPort), '--log', 'stdout', '--log-format', 'json']\n if (this.options.authtoken) {\n args.push('--authtoken', String(this.options.authtoken))\n }\n if (this.options.domain) {\n args.push('--domain', String(this.options.domain))\n }\n if (this.options.region) {\n args.push('--region', String(this.options.region))\n }\n\n return new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.stop()\n reject(new Error('ngrok tunnel timed out after 30s. Is ngrok installed?'))\n }, 30_000)\n\n try {\n this.child = spawn('ngrok', args, { stdio: ['ignore', 'pipe', 'pipe'] })\n } catch {\n clearTimeout(timeout)\n reject(new Error(\n 'Failed to start ngrok. Install it from https://ngrok.com/download'\n ))\n return\n }\n\n const urlPattern = /https:\\/\\/[a-zA-Z0-9-]+\\.ngrok(-free)?\\.app/\n\n const onData = (data: Buffer) => {\n const line = data.toString()\n log.debug(line.trim())\n const match = line.match(urlPattern)\n if (match) {\n clearTimeout(timeout)\n this.publicUrl = match[0]\n log.info({ url: this.publicUrl }, 'ngrok tunnel ready')\n resolve(this.publicUrl)\n }\n }\n\n this.child.stdout?.on('data', onData)\n this.child.stderr?.on('data', onData)\n\n this.child.on('error', (err) => {\n clearTimeout(timeout)\n reject(new Error(\n `ngrok failed to start: ${err.message}. Install it from https://ngrok.com/download`\n ))\n })\n\n this.child.on('exit', (code) => {\n if (!this.publicUrl) {\n clearTimeout(timeout)\n reject(new Error(`ngrok exited with code ${code} before establishing tunnel`))\n }\n })\n })\n }\n\n async stop(): Promise<void> {\n if (this.child) {\n this.child.kill('SIGTERM')\n this.child = null\n log.info('ngrok tunnel stopped')\n }\n }\n\n getPublicUrl(): string {\n return this.publicUrl\n }\n}\n","import { spawn, type ChildProcess } from 'node:child_process'\nimport { createChildLogger } from '../../core/log.js'\nimport type { TunnelProvider } from '../provider.js'\n\nconst log = createChildLogger({ module: 'bore-tunnel' })\n\nexport class BoreTunnelProvider implements TunnelProvider {\n private child: ChildProcess | null = null\n private publicUrl = ''\n private options: Record<string, unknown>\n\n constructor(options: Record<string, unknown> = {}) {\n this.options = options\n }\n\n async start(localPort: number): Promise<string> {\n const server = String(this.options.server || 'bore.pub')\n const args = ['local', String(localPort), '--to', server]\n if (this.options.port) {\n args.push('--port', String(this.options.port))\n }\n if (this.options.secret) {\n args.push('--secret', String(this.options.secret))\n }\n\n return new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.stop()\n reject(new Error('Bore tunnel timed out after 30s. Is bore installed?'))\n }, 30_000)\n\n try {\n this.child = spawn('bore', args, { stdio: ['ignore', 'pipe', 'pipe'] })\n } catch {\n clearTimeout(timeout)\n reject(new Error(\n 'Failed to start bore. Install it from https://github.com/ekzhang/bore'\n ))\n return\n }\n\n const urlPattern = /listening at ([^\\s]+):(\\d+)/\n\n const onData = (data: Buffer) => {\n const line = data.toString()\n log.debug(line.trim())\n const match = line.match(urlPattern)\n if (match) {\n clearTimeout(timeout)\n this.publicUrl = `http://${match[1]}:${match[2]}`\n log.info({ url: this.publicUrl }, 'Bore tunnel ready')\n resolve(this.publicUrl)\n }\n }\n\n this.child.stdout?.on('data', onData)\n this.child.stderr?.on('data', onData)\n\n this.child.on('error', (err) => {\n clearTimeout(timeout)\n reject(new Error(\n `bore failed to start: ${err.message}. Install it from https://github.com/ekzhang/bore`\n ))\n })\n\n this.child.on('exit', (code) => {\n if (!this.publicUrl) {\n clearTimeout(timeout)\n reject(new Error(`bore exited with code ${code} before establishing tunnel`))\n }\n })\n })\n }\n\n async stop(): Promise<void> {\n if (this.child) {\n this.child.kill('SIGTERM')\n this.child = null\n log.info('Bore tunnel stopped')\n }\n }\n\n getPublicUrl(): string {\n return this.publicUrl\n }\n}\n","import { spawn, execSync, type ChildProcess } from 'node:child_process'\nimport { createChildLogger } from '../../core/log.js'\nimport type { TunnelProvider } from '../provider.js'\n\nconst log = createChildLogger({ module: 'tailscale-tunnel' })\n\nexport class TailscaleTunnelProvider implements TunnelProvider {\n private child: ChildProcess | null = null\n private publicUrl = ''\n private options: Record<string, unknown>\n\n constructor(options: Record<string, unknown> = {}) {\n this.options = options\n }\n\n async start(localPort: number): Promise<string> {\n let hostname = ''\n try {\n const statusJson = execSync('tailscale status --json', { encoding: 'utf-8' })\n const status = JSON.parse(statusJson)\n hostname = String(status.Self.DNSName).replace(/\\.$/, '')\n log.debug({ hostname }, 'Resolved Tailscale hostname')\n } catch (err) {\n log.warn('Failed to resolve Tailscale hostname via status --json')\n }\n\n const args = ['funnel', String(localPort)]\n if (this.options.bg) {\n args.push('--bg')\n }\n\n return new Promise<string>((resolve, reject) => {\n const timeout = setTimeout(() => {\n this.stop()\n reject(new Error('Tailscale funnel timed out after 30s. Is tailscale installed?'))\n }, 30_000)\n\n try {\n this.child = spawn('tailscale', args, { stdio: ['ignore', 'pipe', 'pipe'] })\n } catch {\n clearTimeout(timeout)\n reject(new Error(\n 'Failed to start tailscale. Install it from https://tailscale.com/download'\n ))\n return\n }\n\n const urlPattern = /https:\\/\\/[^\\s]+/\n\n const onData = (data: Buffer) => {\n const line = data.toString()\n log.debug(line.trim())\n const match = line.match(urlPattern)\n if (match) {\n clearTimeout(timeout)\n this.publicUrl = match[0]\n log.info({ url: this.publicUrl }, 'Tailscale funnel ready')\n resolve(this.publicUrl)\n }\n }\n\n this.child.stdout?.on('data', onData)\n this.child.stderr?.on('data', onData)\n\n this.child.on('error', (err) => {\n clearTimeout(timeout)\n reject(new Error(\n `tailscale failed to start: ${err.message}. Install it from https://tailscale.com/download`\n ))\n })\n\n this.child.on('exit', (code) => {\n if (!this.publicUrl) {\n clearTimeout(timeout)\n if (hostname) {\n this.publicUrl = `https://${hostname}`\n log.info({ url: this.publicUrl }, 'Tailscale funnel ready (constructed from hostname)')\n resolve(this.publicUrl)\n } else {\n reject(new Error(`tailscale exited with code ${code} before establishing funnel`))\n }\n }\n })\n })\n }\n\n async stop(): Promise<void> {\n if (this.child) {\n this.child.kill('SIGTERM')\n this.child = null\n log.info('Tailscale funnel stopped')\n }\n }\n\n getPublicUrl(): string {\n return this.publicUrl\n }\n}\n","import * as path from 'node:path'\nimport { nanoid } from 'nanoid'\nimport { createChildLogger } from '../core/log.js'\n\nconst log = createChildLogger({ module: 'viewer-store' })\n\nconst MAX_CONTENT_SIZE = 1_000_000 // 1MB\n\nconst EXTENSION_LANGUAGE: Record<string, string> = {\n '.ts': 'typescript', '.tsx': 'typescript', '.js': 'javascript', '.jsx': 'javascript',\n '.py': 'python', '.rs': 'rust', '.go': 'go', '.java': 'java', '.kt': 'kotlin',\n '.rb': 'ruby', '.php': 'php', '.c': 'c', '.cpp': 'cpp', '.h': 'c', '.hpp': 'cpp',\n '.cs': 'csharp', '.swift': 'swift', '.sh': 'bash', '.zsh': 'bash', '.bash': 'bash',\n '.json': 'json', '.yaml': 'yaml', '.yml': 'yaml', '.toml': 'toml',\n '.xml': 'xml', '.html': 'html', '.css': 'css', '.scss': 'scss',\n '.sql': 'sql', '.md': 'markdown', '.dockerfile': 'dockerfile',\n '.tf': 'hcl', '.vue': 'xml', '.svelte': 'xml',\n}\n\nexport interface ViewerEntry {\n id: string\n type: 'file' | 'diff'\n filePath?: string\n content: string\n oldContent?: string\n language?: string\n sessionId: string\n workingDirectory: string\n createdAt: number\n expiresAt: number\n}\n\nexport class ViewerStore {\n private entries = new Map<string, ViewerEntry>()\n private cleanupTimer: ReturnType<typeof setInterval>\n private ttlMs: number\n\n constructor(ttlMinutes: number = 60) {\n this.ttlMs = ttlMinutes * 60 * 1000\n this.cleanupTimer = setInterval(() => this.cleanup(), 5 * 60 * 1000)\n }\n\n storeFile(sessionId: string, filePath: string, content: string, workingDirectory: string): string | null {\n if (!this.isPathAllowed(filePath, workingDirectory)) {\n log.warn({ filePath, workingDirectory }, 'Path outside workspace, rejecting')\n return null\n }\n if (content.length > MAX_CONTENT_SIZE) {\n log.debug({ filePath, size: content.length }, 'File too large for viewer')\n return null\n }\n\n const id = nanoid(12)\n const now = Date.now()\n this.entries.set(id, {\n id,\n type: 'file',\n filePath,\n content,\n language: this.detectLanguage(filePath),\n sessionId,\n workingDirectory,\n createdAt: now,\n expiresAt: now + this.ttlMs,\n })\n log.debug({ id, filePath }, 'Stored file for viewing')\n return id\n }\n\n storeDiff(sessionId: string, filePath: string, oldContent: string, newContent: string, workingDirectory: string): string | null {\n if (!this.isPathAllowed(filePath, workingDirectory)) {\n log.warn({ filePath, workingDirectory }, 'Path outside workspace, rejecting')\n return null\n }\n const combined = oldContent.length + newContent.length\n if (combined > MAX_CONTENT_SIZE) {\n log.debug({ filePath, size: combined }, 'Diff content too large for viewer')\n return null\n }\n\n const id = nanoid(12)\n const now = Date.now()\n this.entries.set(id, {\n id,\n type: 'diff',\n filePath,\n content: newContent,\n oldContent,\n language: this.detectLanguage(filePath),\n sessionId,\n workingDirectory,\n createdAt: now,\n expiresAt: now + this.ttlMs,\n })\n log.debug({ id, filePath }, 'Stored diff for viewing')\n return id\n }\n\n get(id: string): ViewerEntry | undefined {\n const entry = this.entries.get(id)\n if (!entry) return undefined\n if (Date.now() > entry.expiresAt) {\n this.entries.delete(id)\n return undefined\n }\n return entry\n }\n\n private cleanup(): void {\n const now = Date.now()\n let removed = 0\n for (const [id, entry] of this.entries) {\n if (now > entry.expiresAt) {\n this.entries.delete(id)\n removed++\n }\n }\n if (removed > 0) {\n log.debug({ removed, remaining: this.entries.size }, 'Cleaned up expired viewer entries')\n }\n }\n\n private isPathAllowed(filePath: string, workingDirectory: string): boolean {\n const resolved = path.resolve(workingDirectory, filePath)\n return resolved.startsWith(path.resolve(workingDirectory))\n }\n\n private detectLanguage(filePath: string): string | undefined {\n const ext = path.extname(filePath).toLowerCase()\n return EXTENSION_LANGUAGE[ext]\n }\n\n destroy(): void {\n clearInterval(this.cleanupTimer)\n this.entries.clear()\n }\n}\n","import { Hono } from 'hono'\nimport type { ViewerStore } from './viewer-store.js'\nimport { renderFileViewer } from './templates/file-viewer.js'\nimport { renderDiffViewer } from './templates/diff-viewer.js'\n\nfunction notFoundPage(): string {\n return `<!DOCTYPE html>\n<html><head><meta charset=\"UTF-8\"><title>Not Found - OpenACP</title>\n<style>body{background:#0d1117;color:#c9d1d9;font-family:sans-serif;display:flex;align-items:center;justify-content:center;min-height:100vh;margin:0}\n.box{text-align:center;padding:40px}.code{font-size:72px;font-weight:bold;color:#484f58}p{margin-top:16px;color:#8b949e}</style>\n</head><body><div class=\"box\"><div class=\"code\">404</div><p>This viewer link has expired or does not exist.</p></div></body></html>`\n}\n\nexport function createTunnelServer(store: ViewerStore, authToken?: string): Hono {\n const app = new Hono()\n\n // Auth middleware\n if (authToken) {\n app.use('*', async (c, next) => {\n if (c.req.path === '/health') return next()\n const bearer = c.req.header('Authorization')?.replace('Bearer ', '')\n const query = c.req.query('token')\n if (bearer !== authToken && query !== authToken) {\n return c.text('Unauthorized', 401)\n }\n return next()\n })\n }\n\n app.get('/health', (c) => c.json({ status: 'ok' }))\n\n app.get('/view/:id', (c) => {\n const entry = store.get(c.req.param('id'))\n if (!entry || entry.type !== 'file') {\n return c.html(notFoundPage(), 404)\n }\n return c.html(renderFileViewer(entry))\n })\n\n app.get('/diff/:id', (c) => {\n const entry = store.get(c.req.param('id'))\n if (!entry || entry.type !== 'diff') {\n return c.html(notFoundPage(), 404)\n }\n return c.html(renderDiffViewer(entry))\n })\n\n app.get('/api/file/:id', (c) => {\n const entry = store.get(c.req.param('id'))\n if (!entry || entry.type !== 'file') {\n return c.json({ error: 'not found' }, 404)\n }\n return c.json({ filePath: entry.filePath, content: entry.content, language: entry.language })\n })\n\n app.get('/api/diff/:id', (c) => {\n const entry = store.get(c.req.param('id'))\n if (!entry || entry.type !== 'diff') {\n return c.json({ error: 'not found' }, 404)\n }\n return c.json({ filePath: entry.filePath, oldContent: entry.oldContent, newContent: entry.content, language: entry.language })\n })\n\n return app\n}\n","import type { ViewerEntry } from '../viewer-store.js'\n\nfunction escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n}\n\n// Map our language IDs to Monaco language IDs\nconst MONACO_LANGUAGE: Record<string, string> = {\n typescript: 'typescript', javascript: 'javascript', python: 'python',\n rust: 'rust', go: 'go', java: 'java', kotlin: 'kotlin', ruby: 'ruby',\n php: 'php', c: 'c', cpp: 'cpp', csharp: 'csharp', swift: 'swift',\n bash: 'shell', json: 'json', yaml: 'yaml', toml: 'ini', xml: 'xml',\n html: 'html', css: 'css', scss: 'scss', sql: 'sql', markdown: 'markdown',\n dockerfile: 'dockerfile', hcl: 'hcl', plaintext: 'plaintext',\n}\n\nfunction getMonacoLang(lang?: string): string {\n if (!lang) return 'plaintext'\n return MONACO_LANGUAGE[lang] || 'plaintext'\n}\n\nexport function renderFileViewer(entry: ViewerEntry): string {\n const fileName = entry.filePath || 'untitled'\n const lang = getMonacoLang(entry.language)\n // Escape </script> inside content to prevent premature tag closure\n const safeContent = JSON.stringify(entry.content).replace(/<\\//g, '<\\\\/')\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${escapeHtml(fileName)} - OpenACP</title>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body { background: #1e1e1e; color: #d4d4d4; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; display: flex; flex-direction: column; height: 100vh; }\n .header { background: #252526; border-bottom: 1px solid #3c3c3c; padding: 8px 16px; display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; z-index: 10; }\n .file-info { display: flex; align-items: center; gap: 8px; font-size: 13px; min-width: 0; }\n .file-icon { font-size: 14px; flex-shrink: 0; }\n .file-path { color: #969696; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n .file-name { color: #e0e0e0; font-weight: 500; flex-shrink: 0; }\n .actions { display: flex; gap: 6px; flex-shrink: 0; }\n .btn { background: #3c3c3c; color: #d4d4d4; border: 1px solid #505050; padding: 4px 10px; border-radius: 4px; cursor: pointer; font-size: 12px; transition: background 0.15s; }\n .btn:hover { background: #505050; }\n .btn.active { background: #0e639c; border-color: #1177bb; }\n #editor-container { flex: 1; overflow: hidden; }\n .status-bar { background: #007acc; color: #fff; padding: 2px 16px; font-size: 12px; display: flex; justify-content: space-between; flex-shrink: 0; }\n </style>\n</head>\n<body>\n <div class=\"header\">\n <div class=\"file-info\">\n <span class=\"file-icon\">📄</span>\n ${formatBreadcrumb(fileName)}\n </div>\n <div class=\"actions\">\n <button class=\"btn\" onclick=\"toggleWordWrap()\" id=\"btn-wrap\">Wrap</button>\n <button class=\"btn\" onclick=\"toggleMinimap()\" id=\"btn-minimap\">Minimap</button>\n <button class=\"btn\" onclick=\"toggleTheme()\" id=\"btn-theme\">Light</button>\n <button class=\"btn\" onclick=\"copyCode()\">Copy</button>\n </div>\n </div>\n <div id=\"editor-container\"></div>\n <div class=\"status-bar\">\n <span>${escapeHtml(entry.language || 'plaintext')} | ${entry.content.split('\\n').length} lines</span>\n <span>OpenACP Viewer (read-only)</span>\n </div>\n\n <script src=\"https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs/loader.js\"></script>\n <script>\n const content = ${safeContent};\n const lang = ${JSON.stringify(lang)};\n let editor;\n let isDark = true;\n let wordWrap = false;\n let minimap = true;\n\n require.config({ paths: { vs: 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } });\n require(['vs/editor/editor.main'], function () {\n editor = monaco.editor.create(document.getElementById('editor-container'), {\n value: content,\n language: lang,\n theme: 'vs-dark',\n readOnly: true,\n automaticLayout: true,\n minimap: { enabled: true },\n scrollBeyondLastLine: false,\n fontSize: 13,\n fontFamily: \"'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace\",\n lineNumbers: 'on',\n renderLineHighlight: 'all',\n wordWrap: 'off',\n padding: { top: 8 },\n });\n\n // Handle line range from URL hash: #L42 or #L42-L55\n function highlightFromHash() {\n const hash = location.hash.slice(1);\n const match = hash.match(/^L(\\\\d+)(?:-L?(\\\\d+))?$/);\n if (!match) return;\n const startLine = parseInt(match[1], 10);\n const endLine = match[2] ? parseInt(match[2], 10) : startLine;\n editor.revealLineInCenter(startLine);\n editor.setSelection(new monaco.Selection(startLine, 1, endLine + 1, 1));\n }\n highlightFromHash();\n window.addEventListener('hashchange', highlightFromHash);\n });\n\n function toggleTheme() {\n isDark = !isDark;\n monaco.editor.setTheme(isDark ? 'vs-dark' : 'vs');\n document.body.style.background = isDark ? '#1e1e1e' : '#ffffff';\n document.querySelector('.header').style.background = isDark ? '#252526' : '#f3f3f3';\n document.querySelector('.header').style.borderColor = isDark ? '#3c3c3c' : '#e0e0e0';\n document.getElementById('btn-theme').textContent = isDark ? 'Light' : 'Dark';\n }\n\n function toggleWordWrap() {\n wordWrap = !wordWrap;\n editor.updateOptions({ wordWrap: wordWrap ? 'on' : 'off' });\n document.getElementById('btn-wrap').classList.toggle('active', wordWrap);\n }\n\n function toggleMinimap() {\n minimap = !minimap;\n editor.updateOptions({ minimap: { enabled: minimap } });\n document.getElementById('btn-minimap').classList.toggle('active', !minimap);\n }\n\n function copyCode() {\n navigator.clipboard.writeText(content).then(() => {\n const btn = event.target;\n btn.textContent = 'Copied!';\n setTimeout(() => btn.textContent = 'Copy', 2000);\n });\n }\n </script>\n</body>\n</html>`\n}\n\nfunction formatBreadcrumb(filePath: string): string {\n const parts = filePath.split('/')\n if (parts.length <= 1) return `<span class=\"file-name\">${escapeHtml(filePath)}</span>`\n const dir = parts.slice(0, -1).join(' / ')\n const name = parts[parts.length - 1]\n return `<span class=\"file-path\">${escapeHtml(dir)} /</span> <span class=\"file-name\">${escapeHtml(name)}</span>`\n}\n","import { createPatch } from 'diff'\nimport type { ViewerEntry } from '../viewer-store.js'\n\nfunction escapeHtml(text: string): string {\n return text\n .replace(/&/g, '&amp;')\n .replace(/</g, '&lt;')\n .replace(/>/g, '&gt;')\n .replace(/\"/g, '&quot;')\n}\n\nconst MONACO_LANGUAGE: Record<string, string> = {\n typescript: 'typescript', javascript: 'javascript', python: 'python',\n rust: 'rust', go: 'go', java: 'java', kotlin: 'kotlin', ruby: 'ruby',\n php: 'php', c: 'c', cpp: 'cpp', csharp: 'csharp', swift: 'swift',\n bash: 'shell', json: 'json', yaml: 'yaml', toml: 'ini', xml: 'xml',\n html: 'html', css: 'css', scss: 'scss', sql: 'sql', markdown: 'markdown',\n dockerfile: 'dockerfile', hcl: 'hcl', plaintext: 'plaintext',\n}\n\nfunction getMonacoLang(lang?: string): string {\n if (!lang) return 'plaintext'\n return MONACO_LANGUAGE[lang] || 'plaintext'\n}\n\nexport function renderDiffViewer(entry: ViewerEntry): string {\n const fileName = entry.filePath || 'untitled'\n const lang = getMonacoLang(entry.language)\n const oldContent = entry.oldContent || ''\n const newContent = entry.content\n\n // Count changes for stats\n const patch = createPatch(fileName, oldContent, newContent, 'before', 'after')\n const adds = (patch.match(/^\\+[^+]/gm) || []).length\n const dels = (patch.match(/^-[^-]/gm) || []).length\n\n // Escape </script> in content\n const safeOld = JSON.stringify(oldContent).replace(/<\\//g, '<\\\\/')\n const safeNew = JSON.stringify(newContent).replace(/<\\//g, '<\\\\/')\n\n return `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n <title>${escapeHtml(fileName)} (diff) - OpenACP</title>\n <style>\n * { margin: 0; padding: 0; box-sizing: border-box; }\n body { background: #1e1e1e; color: #d4d4d4; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; display: flex; flex-direction: column; height: 100vh; }\n .header { background: #252526; border-bottom: 1px solid #3c3c3c; padding: 8px 16px; display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; z-index: 10; }\n .file-info { display: flex; align-items: center; gap: 8px; font-size: 13px; }\n .file-icon { font-size: 14px; }\n .file-name { color: #e0e0e0; font-weight: 500; }\n .stats { font-size: 12px; margin-left: 12px; }\n .stats .add { color: #4ec9b0; }\n .stats .del { color: #f14c4c; }\n .actions { display: flex; gap: 6px; }\n .btn { background: #3c3c3c; color: #d4d4d4; border: 1px solid #505050; padding: 4px 10px; border-radius: 4px; cursor: pointer; font-size: 12px; transition: background 0.15s; }\n .btn:hover { background: #505050; }\n .btn.active { background: #0e639c; border-color: #1177bb; }\n #editor-container { flex: 1; overflow: hidden; }\n .status-bar { background: #007acc; color: #fff; padding: 2px 16px; font-size: 12px; display: flex; justify-content: space-between; flex-shrink: 0; }\n </style>\n</head>\n<body>\n <div class=\"header\">\n <div class=\"file-info\">\n <span class=\"file-icon\">📝</span>\n <span class=\"file-name\">${escapeHtml(fileName)}</span>\n <span class=\"stats\"><span class=\"add\">+${adds}</span> / <span class=\"del\">-${dels}</span></span>\n </div>\n <div class=\"actions\">\n <button class=\"btn active\" id=\"btn-side\" onclick=\"setView('side')\">Side by Side</button>\n <button class=\"btn\" id=\"btn-inline\" onclick=\"setView('inline')\">Inline</button>\n <button class=\"btn\" onclick=\"toggleTheme()\" id=\"btn-theme\">Light</button>\n </div>\n </div>\n <div id=\"editor-container\"></div>\n <div class=\"status-bar\">\n <span>${escapeHtml(entry.language || 'plaintext')} | <span class=\"add\">+${adds}</span> <span class=\"del\">-${dels}</span></span>\n <span>OpenACP Diff Viewer</span>\n </div>\n\n <script src=\"https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs/loader.js\"></script>\n <script>\n const oldContent = ${safeOld};\n const newContent = ${safeNew};\n const lang = ${JSON.stringify(lang)};\n let diffEditor;\n let isDark = true;\n let renderSideBySide = true;\n\n require.config({ paths: { vs: 'https://cdn.jsdelivr.net/npm/monaco-editor@0.52.2/min/vs' } });\n require(['vs/editor/editor.main'], function () {\n const originalModel = monaco.editor.createModel(oldContent, lang);\n const modifiedModel = monaco.editor.createModel(newContent, lang);\n\n diffEditor = monaco.editor.createDiffEditor(document.getElementById('editor-container'), {\n theme: 'vs-dark',\n readOnly: true,\n automaticLayout: true,\n renderSideBySide: true,\n scrollBeyondLastLine: false,\n fontSize: 13,\n fontFamily: \"'SF Mono', SFMono-Regular, Consolas, 'Liberation Mono', Menlo, monospace\",\n padding: { top: 8 },\n enableSplitViewResizing: true,\n renderOverviewRuler: true,\n });\n\n diffEditor.setModel({ original: originalModel, modified: modifiedModel });\n });\n\n function setView(mode) {\n renderSideBySide = mode === 'side';\n diffEditor.updateOptions({ renderSideBySide });\n document.getElementById('btn-side').classList.toggle('active', renderSideBySide);\n document.getElementById('btn-inline').classList.toggle('active', !renderSideBySide);\n }\n\n function toggleTheme() {\n isDark = !isDark;\n monaco.editor.setTheme(isDark ? 'vs-dark' : 'vs');\n document.body.style.background = isDark ? '#1e1e1e' : '#ffffff';\n document.querySelector('.header').style.background = isDark ? '#252526' : '#f3f3f3';\n document.querySelector('.header').style.borderColor = isDark ? '#3c3c3c' : '#e0e0e0';\n document.getElementById('btn-theme').textContent = isDark ? 'Light' : 'Dark';\n }\n </script>\n</body>\n</html>`\n}\n"],"mappings":"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","names":["resolve","spawn","log","resolve","spawn","spawn","log","resolve","spawn","spawn","log","resolve","spawn","log","escapeHtml","MONACO_LANGUAGE","getMonacoLang","log","resolve"]}