@openacp/cli 2026.330.2 → 2026.331.1

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 (145) hide show
  1. package/README.md +17 -0
  2. package/dist/adapter-ELG3VRZ3.js +14 -0
  3. package/dist/{agent-catalog-SZQQERV7.js → agent-catalog-UYD26QDK.js} +3 -3
  4. package/dist/{api-client-XTLRRFPX.js → api-client-PEMHYL5U.js} +2 -2
  5. package/dist/{api-server-JLBDKCU4.js → api-server-DATG2KBR.js} +3 -3
  6. package/dist/api-server-L5Z7XACW.js +7 -0
  7. package/dist/chunk-23SRIVG4.js +50 -0
  8. package/dist/chunk-23SRIVG4.js.map +1 -0
  9. package/dist/{chunk-YIGBJFJL.js → chunk-7GXEMMEV.js} +15 -15
  10. package/dist/{chunk-QWVHCTCA.js → chunk-7U6IZIJP.js} +37 -23
  11. package/dist/chunk-7U6IZIJP.js.map +1 -0
  12. package/dist/{chunk-FCTC7KDT.js → chunk-7YIKTRSM.js} +14 -10
  13. package/dist/chunk-7YIKTRSM.js.map +1 -0
  14. package/dist/{chunk-MITTQMGZ.js → chunk-BYCJQPMN.js} +5 -5
  15. package/dist/chunk-BYCJQPMN.js.map +1 -0
  16. package/dist/{chunk-5ZNBNIK3.js → chunk-EWVXSTQK.js} +193 -53
  17. package/dist/chunk-EWVXSTQK.js.map +1 -0
  18. package/dist/{chunk-UWH7KIAA.js → chunk-FPKQYCQS.js} +88 -13
  19. package/dist/chunk-FPKQYCQS.js.map +1 -0
  20. package/dist/{chunk-GEOXPGCO.js → chunk-K6UY5M75.js} +12 -9
  21. package/dist/chunk-K6UY5M75.js.map +1 -0
  22. package/dist/{chunk-KDU3ZEWT.js → chunk-KGAQW6F4.js} +12 -3
  23. package/dist/chunk-KGAQW6F4.js.map +1 -0
  24. package/dist/{chunk-7RKPIM3E.js → chunk-LRV56K2M.js} +205 -16
  25. package/dist/chunk-LRV56K2M.js.map +1 -0
  26. package/dist/{chunk-V2YZWYXT.js → chunk-MDJHCCFS.js} +18 -17
  27. package/dist/chunk-MDJHCCFS.js.map +1 -0
  28. package/dist/chunk-NHD5XDD2.js +686 -0
  29. package/dist/chunk-NHD5XDD2.js.map +1 -0
  30. package/dist/{chunk-APS6UEFU.js → chunk-NJX75BLK.js} +1 -1
  31. package/dist/chunk-NJX75BLK.js.map +1 -0
  32. package/dist/{chunk-5HKQCYOI.js → chunk-NOEAJNTK.js} +14 -3
  33. package/dist/chunk-NOEAJNTK.js.map +1 -0
  34. package/dist/chunk-ON7HB5O7.js +58 -0
  35. package/dist/chunk-ON7HB5O7.js.map +1 -0
  36. package/dist/{chunk-5OCGO27U.js → chunk-OSBZXY2W.js} +2 -1
  37. package/dist/chunk-OSBZXY2W.js.map +1 -0
  38. package/dist/{chunk-PA6MNBG4.js → chunk-P3HHJANC.js} +32 -13
  39. package/dist/chunk-P3HHJANC.js.map +1 -0
  40. package/dist/{chunk-BTJHGSLM.js → chunk-R2YLDQLI.js} +9 -10
  41. package/dist/chunk-R2YLDQLI.js.map +1 -0
  42. package/dist/{chunk-CFUJGWOP.js → chunk-SSLVNCEA.js} +27 -3
  43. package/dist/chunk-SSLVNCEA.js.map +1 -0
  44. package/dist/{chunk-MPGEHTGE.js → chunk-TGP34LQN.js} +9 -7
  45. package/dist/chunk-TGP34LQN.js.map +1 -0
  46. package/dist/{chunk-TMVTSWVH.js → chunk-VUSCVRJL.js} +2 -1
  47. package/dist/chunk-VUSCVRJL.js.map +1 -0
  48. package/dist/chunk-XRJUS6FE.js +53 -0
  49. package/dist/chunk-XRJUS6FE.js.map +1 -0
  50. package/dist/{chunk-W4LK6WJP.js → chunk-YZCKSNRN.js} +24 -17
  51. package/dist/chunk-YZCKSNRN.js.map +1 -0
  52. package/dist/{chunk-3NAFXVQM.js → chunk-ZIRH6QWW.js} +7 -5
  53. package/dist/chunk-ZIRH6QWW.js.map +1 -0
  54. package/dist/cli.d.ts +11 -0
  55. package/dist/cli.js +334 -140
  56. package/dist/cli.js.map +1 -1
  57. package/dist/config-X4UP7H6R.js +13 -0
  58. package/dist/config-editor-7BENRVG5.js +11 -0
  59. package/dist/{config-registry-ZXAIJNYB.js → config-registry-M3FFWEVM.js} +3 -2
  60. package/dist/context-FVGCU5TI.js +9 -0
  61. package/dist/core-plugins-JSY2I44L.js +25 -0
  62. package/dist/{daemon-XFEMMJSZ.js → daemon-UOSRDEXW.js} +8 -3
  63. package/dist/doctor-6DLACBR4.js +10 -0
  64. package/dist/{file-service-HHB3JQIO.js → file-service-FQQYME7M.js} +2 -2
  65. package/dist/index.d.ts +265 -32
  66. package/dist/index.js +44 -33
  67. package/dist/index.js.map +1 -1
  68. package/dist/{install-cloudflared-JRJ4BSOM.js → install-cloudflared-LNS5L5FR.js} +5 -4
  69. package/dist/install-cloudflared-LNS5L5FR.js.map +1 -0
  70. package/dist/{install-context-EHYV5WRY.js → install-context-KZO5FR4D.js} +4 -3
  71. package/dist/install-context-KZO5FR4D.js.map +1 -0
  72. package/dist/{install-jq-ISTGT263.js → install-jq-SN4IA5K4.js} +3 -3
  73. package/dist/instance-context-FLCE7VZ4.js +13 -0
  74. package/dist/instance-registry-SW5FWKHO.js +7 -0
  75. package/dist/{main-L2M4NTJY.js → main-D7M2AKRM.js} +91 -48
  76. package/dist/main-D7M2AKRM.js.map +1 -0
  77. package/dist/{plugin-create-EHL76ZZG.js → plugin-create-HFKS23JY.js} +4 -2
  78. package/dist/{plugin-create-EHL76ZZG.js.map → plugin-create-HFKS23JY.js.map} +1 -1
  79. package/dist/{post-upgrade-Y26S2ZQ7.js → post-upgrade-F4YPMTUT.js} +6 -6
  80. package/dist/{security-2BA265LN.js → security-O4XGN2CM.js} +2 -2
  81. package/dist/{setup-E6BNEYCS.js → setup-44WLBIOT.js} +209 -22
  82. package/dist/setup-44WLBIOT.js.map +1 -0
  83. package/dist/{speech-SG62JYIF.js → speech-GHTSWDAN.js} +2 -2
  84. package/dist/telegram-D7ASLVEB.js +7 -0
  85. package/dist/telegram-D7ASLVEB.js.map +1 -0
  86. package/dist/tunnel-ALJDPFDQ.js +10 -0
  87. package/dist/tunnel-ALJDPFDQ.js.map +1 -0
  88. package/dist/{tunnel-service-ZMO4THKE.js → tunnel-service-TBAHDXMF.js} +41 -547
  89. package/dist/tunnel-service-TBAHDXMF.js.map +1 -0
  90. package/package.json +1 -1
  91. package/dist/adapter-4U6MC5ZS.js +0 -13
  92. package/dist/api-server-5VNYFWJE.js +0 -7
  93. package/dist/chunk-3NAFXVQM.js.map +0 -1
  94. package/dist/chunk-4WXALZA3.js +0 -45
  95. package/dist/chunk-4WXALZA3.js.map +0 -1
  96. package/dist/chunk-5HKQCYOI.js.map +0 -1
  97. package/dist/chunk-5OCGO27U.js.map +0 -1
  98. package/dist/chunk-5ZNBNIK3.js.map +0 -1
  99. package/dist/chunk-7RKPIM3E.js.map +0 -1
  100. package/dist/chunk-APS6UEFU.js.map +0 -1
  101. package/dist/chunk-BTJHGSLM.js.map +0 -1
  102. package/dist/chunk-CFUJGWOP.js.map +0 -1
  103. package/dist/chunk-FCTC7KDT.js.map +0 -1
  104. package/dist/chunk-GEOXPGCO.js.map +0 -1
  105. package/dist/chunk-KDU3ZEWT.js.map +0 -1
  106. package/dist/chunk-MITTQMGZ.js.map +0 -1
  107. package/dist/chunk-MPGEHTGE.js.map +0 -1
  108. package/dist/chunk-PA6MNBG4.js.map +0 -1
  109. package/dist/chunk-QWVHCTCA.js.map +0 -1
  110. package/dist/chunk-TMVTSWVH.js.map +0 -1
  111. package/dist/chunk-UWH7KIAA.js.map +0 -1
  112. package/dist/chunk-V2YZWYXT.js.map +0 -1
  113. package/dist/chunk-W4LK6WJP.js.map +0 -1
  114. package/dist/config-KN6NKKPF.js +0 -20
  115. package/dist/config-editor-76RVZS4B.js +0 -10
  116. package/dist/context-NXXW62NJ.js +0 -9
  117. package/dist/core-plugins-OCHKGCIZ.js +0 -22
  118. package/dist/doctor-AV6AUO22.js +0 -9
  119. package/dist/install-cloudflared-JRJ4BSOM.js.map +0 -1
  120. package/dist/install-context-EHYV5WRY.js.map +0 -1
  121. package/dist/main-L2M4NTJY.js.map +0 -1
  122. package/dist/setup-E6BNEYCS.js.map +0 -1
  123. package/dist/telegram-EAVRDNFU.js +0 -7
  124. package/dist/tunnel-HWJ27WDH.js +0 -7
  125. package/dist/tunnel-service-ZMO4THKE.js.map +0 -1
  126. /package/dist/{adapter-4U6MC5ZS.js.map → adapter-ELG3VRZ3.js.map} +0 -0
  127. /package/dist/{agent-catalog-SZQQERV7.js.map → agent-catalog-UYD26QDK.js.map} +0 -0
  128. /package/dist/{api-client-XTLRRFPX.js.map → api-client-PEMHYL5U.js.map} +0 -0
  129. /package/dist/{api-server-5VNYFWJE.js.map → api-server-DATG2KBR.js.map} +0 -0
  130. /package/dist/{api-server-JLBDKCU4.js.map → api-server-L5Z7XACW.js.map} +0 -0
  131. /package/dist/{chunk-YIGBJFJL.js.map → chunk-7GXEMMEV.js.map} +0 -0
  132. /package/dist/{config-KN6NKKPF.js.map → config-X4UP7H6R.js.map} +0 -0
  133. /package/dist/{config-editor-76RVZS4B.js.map → config-editor-7BENRVG5.js.map} +0 -0
  134. /package/dist/{config-registry-ZXAIJNYB.js.map → config-registry-M3FFWEVM.js.map} +0 -0
  135. /package/dist/{context-NXXW62NJ.js.map → context-FVGCU5TI.js.map} +0 -0
  136. /package/dist/{core-plugins-OCHKGCIZ.js.map → core-plugins-JSY2I44L.js.map} +0 -0
  137. /package/dist/{daemon-XFEMMJSZ.js.map → daemon-UOSRDEXW.js.map} +0 -0
  138. /package/dist/{doctor-AV6AUO22.js.map → doctor-6DLACBR4.js.map} +0 -0
  139. /package/dist/{file-service-HHB3JQIO.js.map → file-service-FQQYME7M.js.map} +0 -0
  140. /package/dist/{install-jq-ISTGT263.js.map → install-jq-SN4IA5K4.js.map} +0 -0
  141. /package/dist/{security-2BA265LN.js.map → instance-context-FLCE7VZ4.js.map} +0 -0
  142. /package/dist/{speech-SG62JYIF.js.map → instance-registry-SW5FWKHO.js.map} +0 -0
  143. /package/dist/{post-upgrade-Y26S2ZQ7.js.map → post-upgrade-F4YPMTUT.js.map} +0 -0
  144. /package/dist/{telegram-EAVRDNFU.js.map → security-O4XGN2CM.js.map} +0 -0
  145. /package/dist/{tunnel-HWJ27WDH.js.map → speech-GHTSWDAN.js.map} +0 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/plugins/tunnel/tunnel-registry.ts","../../src/plugins/tunnel/providers/cloudflare.ts","../../src/plugins/tunnel/providers/ngrok.ts","../../src/plugins/tunnel/providers/bore.ts","../../src/plugins/tunnel/providers/tailscale.ts"],"sourcesContent":["import fs from 'node:fs'\nimport path from 'node:path'\nimport os from 'node:os'\nimport { createChildLogger } from '../../core/utils/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'\n\nconst log = createChildLogger({ module: 'tunnel-registry' })\n\nexport const MAX_RETRIES = 5\nconst BASE_RETRY_DELAY_MS = 2_000\n\nexport interface TunnelEntry {\n port: number\n type: 'system' | 'user'\n provider: string\n label?: string\n publicUrl?: string\n sessionId?: string\n status: 'stopped' | 'starting' | 'active' | 'failed'\n retryCount: number\n createdAt: string\n}\n\ninterface PersistedEntry {\n port: number\n type: 'system' | 'user'\n provider: string\n label?: string\n sessionId?: string\n createdAt: string\n}\n\ninterface LiveEntry {\n entry: TunnelEntry\n process: TunnelProvider | null\n spawnPromise: Promise<string> | null\n retryTimer: ReturnType<typeof setTimeout> | null\n}\n\nexport class TunnelRegistry {\n private entries: Map<number, LiveEntry> = new Map()\n private saveTimeout: ReturnType<typeof setTimeout> | null = null\n private maxUserTunnels: number\n private providerOptions: Record<string, unknown>\n private registryPath: string\n private shuttingDown = false\n\n constructor(opts: { maxUserTunnels?: number; providerOptions?: Record<string, unknown>; registryPath?: string } = {}) {\n this.maxUserTunnels = opts.maxUserTunnels ?? 5\n this.providerOptions = opts.providerOptions ?? {}\n this.registryPath = opts.registryPath ?? path.join(os.homedir(), '.openacp', 'tunnels.json')\n }\n\n async add(port: number, opts: {\n type: 'system' | 'user'\n provider: string\n label?: string\n sessionId?: string\n }): Promise<TunnelEntry> {\n // Check if port already registered\n if (this.entries.has(port)) {\n const existing = this.entries.get(port)!\n if (existing.entry.status === 'active' || existing.entry.status === 'starting') {\n throw new Error(`Port ${port} is already tunneled → ${existing.entry.publicUrl || 'starting...'}`)\n }\n // Stopped/failed entry — clean up retry timer and re-add\n if (existing.retryTimer) clearTimeout(existing.retryTimer)\n this.entries.delete(port)\n }\n\n // Check max user tunnels\n if (opts.type === 'user') {\n const userCount = this.list(false).filter(e => e.status === 'active' || e.status === 'starting').length\n if (userCount >= this.maxUserTunnels) {\n throw new Error(`Max user tunnels (${this.maxUserTunnels}) reached. Stop a tunnel first.`)\n }\n }\n\n const entry: TunnelEntry = {\n port,\n type: opts.type,\n provider: opts.provider,\n label: opts.label,\n sessionId: opts.sessionId,\n status: 'starting',\n retryCount: 0,\n createdAt: new Date().toISOString(),\n }\n\n const provider = this.createProvider(opts.provider)\n\n // Wire up post-establishment crash detection with auto-retry\n provider.onExit((code) => {\n if (this.shuttingDown) return\n const live = this.entries.get(port)\n if (!live) return\n\n live.entry.status = 'failed'\n live.process = null\n this.scheduleSave()\n\n if (live.entry.retryCount < MAX_RETRIES) {\n const delay = BASE_RETRY_DELAY_MS * Math.pow(2, live.entry.retryCount)\n log.warn({ port, code, retry: live.entry.retryCount + 1, maxRetries: MAX_RETRIES, delayMs: delay },\n 'Tunnel crashed, scheduling retry')\n live.retryTimer = setTimeout(() => this.retry(port, opts), delay)\n } else {\n log.error({ port, code }, `Tunnel crashed and exhausted all ${MAX_RETRIES} retries`)\n }\n })\n\n const spawnPromise = provider.start(port).then(url => {\n entry.publicUrl = url\n entry.status = 'active'\n log.info({ port, url, label: opts.label }, 'Tunnel active')\n this.scheduleSave()\n return url\n }).catch(err => {\n entry.status = 'failed'\n log.error({ port, err: (err as Error).message }, 'Tunnel failed to start')\n this.scheduleSave()\n throw err\n })\n\n this.entries.set(port, { entry, process: provider, spawnPromise, retryTimer: null })\n this.scheduleSave()\n\n // Await spawn — caller gets the URL or error\n await spawnPromise\n return entry\n }\n\n private async retry(port: number, opts: {\n type: 'system' | 'user'\n provider: string\n label?: string\n sessionId?: string\n }): Promise<void> {\n if (this.shuttingDown) return\n const live = this.entries.get(port)\n if (!live) return\n\n const retryCount = live.entry.retryCount + 1\n log.info({ port, retry: retryCount, maxRetries: MAX_RETRIES }, 'Retrying tunnel')\n\n // Remove old entry so add() doesn't reject\n if (live.retryTimer) clearTimeout(live.retryTimer)\n this.entries.delete(port)\n\n try {\n const entry = await this.add(port, opts)\n entry.retryCount = retryCount\n } catch (err) {\n log.error({ port, err: (err as Error).message, retry: retryCount }, 'Tunnel retry failed')\n\n // Re-insert as failed with incremented retry count for next onExit cycle\n const failedEntry: TunnelEntry = {\n port,\n type: opts.type,\n provider: opts.provider,\n label: opts.label,\n sessionId: opts.sessionId,\n status: 'failed',\n retryCount,\n createdAt: live.entry.createdAt,\n }\n\n if (retryCount < MAX_RETRIES) {\n const delay = BASE_RETRY_DELAY_MS * Math.pow(2, retryCount)\n const retryTimer = setTimeout(() => this.retry(port, opts), delay)\n this.entries.set(port, { entry: failedEntry, process: null, spawnPromise: null, retryTimer })\n log.warn({ port, retry: retryCount + 1, delayMs: delay }, 'Scheduling next retry')\n } else {\n this.entries.set(port, { entry: failedEntry, process: null, spawnPromise: null, retryTimer: null })\n log.error({ port }, `Tunnel exhausted all ${MAX_RETRIES} retries`)\n }\n this.scheduleSave()\n }\n }\n\n async stop(port: number): Promise<void> {\n const live = this.entries.get(port)\n if (!live) return\n\n if (live.entry.type === 'system') {\n throw new Error('Cannot stop system tunnel')\n }\n\n // Cancel any pending retry\n if (live.retryTimer) clearTimeout(live.retryTimer)\n\n // Wait for spawn to finish if still starting\n if (live.spawnPromise) {\n try { await live.spawnPromise } catch { /* ignore spawn error */ }\n }\n\n if (live.process) {\n await live.process.stop()\n }\n\n this.entries.delete(port)\n this.scheduleSave()\n log.info({ port, label: live.entry.label }, 'Tunnel stopped')\n }\n\n async stopBySession(sessionId: string): Promise<TunnelEntry[]> {\n const stopped: TunnelEntry[] = []\n const toStop = this.getBySession(sessionId)\n for (const entry of toStop) {\n try {\n await this.stop(entry.port)\n stopped.push(entry)\n } catch { /* ignore */ }\n }\n return stopped\n }\n\n async stopAllUser(): Promise<void> {\n const userEntries = this.list(false)\n for (const entry of userEntries) {\n try { await this.stop(entry.port) } catch { /* ignore */ }\n }\n }\n\n async shutdown(): Promise<void> {\n this.shuttingDown = true\n\n for (const [, live] of this.entries) {\n if (live.retryTimer) clearTimeout(live.retryTimer)\n if (live.spawnPromise) {\n try { await live.spawnPromise } catch { /* ignore */ }\n }\n if (live.process) {\n await live.process.stop()\n }\n }\n this.entries.clear()\n this.scheduleSave()\n }\n\n list(includeSystem = false): TunnelEntry[] {\n const entries = Array.from(this.entries.values()).map(l => l.entry)\n if (includeSystem) return entries\n return entries.filter(e => e.type === 'user')\n }\n\n get(port: number): TunnelEntry | null {\n return this.entries.get(port)?.entry ?? null\n }\n\n getBySession(sessionId: string): TunnelEntry[] {\n return this.list(false).filter(e => e.sessionId === sessionId)\n }\n\n getSystemEntry(): TunnelEntry | null {\n for (const live of this.entries.values()) {\n if (live.entry.type === 'system') return live.entry\n }\n return null\n }\n\n async restore(): Promise<void> {\n if (!fs.existsSync(this.registryPath)) return\n\n try {\n const raw = JSON.parse(fs.readFileSync(this.registryPath, 'utf-8')) as PersistedEntry[]\n log.info({ count: raw.length }, 'Restoring tunnels')\n\n // Only restore user tunnels — system tunnel is registered separately by TunnelService.start()\n const userEntries = raw.filter(e => e.type === 'user')\n for (const persisted of userEntries) {\n try {\n await this.add(persisted.port, {\n type: persisted.type,\n provider: persisted.provider,\n label: persisted.label,\n sessionId: persisted.sessionId,\n })\n } catch (err) {\n log.warn({ port: persisted.port, err: (err as Error).message }, 'Failed to restore tunnel')\n }\n }\n } catch (err) {\n log.warn({ err: (err as Error).message }, 'Failed to read tunnels.json')\n }\n }\n\n private createProvider(name: string): TunnelProvider {\n switch (name) {\n case 'cloudflare':\n return new CloudflareTunnelProvider(this.providerOptions)\n case 'ngrok':\n return new NgrokTunnelProvider(this.providerOptions)\n case 'bore':\n return new BoreTunnelProvider(this.providerOptions)\n case 'tailscale':\n return new TailscaleTunnelProvider(this.providerOptions)\n default:\n log.warn({ provider: name }, 'Unknown provider, falling back to cloudflare')\n return new CloudflareTunnelProvider(this.providerOptions)\n }\n }\n\n private scheduleSave(): void {\n if (this.saveTimeout) clearTimeout(this.saveTimeout)\n this.saveTimeout = setTimeout(() => this.save(), 2000)\n }\n\n private save(): void {\n const data: PersistedEntry[] = Array.from(this.entries.values()).map(l => ({\n port: l.entry.port,\n type: l.entry.type,\n provider: l.entry.provider,\n label: l.entry.label,\n sessionId: l.entry.sessionId,\n createdAt: l.entry.createdAt,\n }))\n\n try {\n const dir = path.dirname(this.registryPath)\n fs.mkdirSync(dir, { recursive: true })\n fs.writeFileSync(this.registryPath, JSON.stringify(data, null, 2))\n } catch (err) {\n log.error({ err: (err as Error).message }, 'Failed to save tunnels.json')\n }\n }\n\n flush(): void {\n if (this.saveTimeout) {\n clearTimeout(this.saveTimeout)\n this.saveTimeout = null\n }\n this.save()\n }\n}\n","import { spawn, type ChildProcess } from 'node:child_process'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport os from 'node:os'\nimport { createChildLogger } from '../../../core/utils/log.js'\nimport { commandExists } from '../../../core/agents/agent-dependencies.js'\nimport type { TunnelProvider } from '../provider.js'\n\nconst log = createChildLogger({ module: 'cloudflare-tunnel' })\n\nconst SIGKILL_TIMEOUT_MS = 5_000\n\nexport class CloudflareTunnelProvider implements TunnelProvider {\n private child: ChildProcess | null = null\n private publicUrl = ''\n private options: Record<string, unknown>\n private binDir: string\n private exitCallback: ((code: number | null) => void) | null = null\n\n constructor(options: Record<string, unknown> = {}, binDir?: string) {\n this.options = options\n this.binDir = binDir ?? path.join(os.homedir(), '.openacp', 'bin')\n }\n\n onExit(callback: (code: number | null) => void): void {\n this.exitCallback = callback\n }\n\n async start(localPort: number): Promise<string> {\n // Find binary — post-upgrade should have installed it, but fallback to ensureCloudflared() as safety net\n let binaryPath = this.findBinary()\n if (!binaryPath) {\n log.warn('cloudflared not found locally, attempting auto-install as fallback...')\n try {\n const { ensureCloudflared } = await import('./install-cloudflared.js')\n binaryPath = await ensureCloudflared()\n } catch (err) {\n throw new Error(`cloudflared is not installed and auto-install failed: ${(err as Error).message}`)\n }\n }\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 let settled = false\n const settle = (fn: () => void) => { if (!settled) { settled = true; fn() } }\n\n const timeout = setTimeout(() => {\n this.stop()\n settle(() => 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 settle(() => 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 settle(() => 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 settle(() => 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 settle(() => reject(new Error(`cloudflared exited with code ${code} before establishing tunnel`)))\n } else {\n // Post-establishment crash\n log.error({ code }, 'cloudflared exited unexpectedly after establishment')\n this.child = null\n this.exitCallback?.(code)\n }\n })\n })\n }\n\n async stop(): Promise<void> {\n const child = this.child\n if (!child) return\n this.child = null\n\n child.kill('SIGTERM')\n\n // Wait for graceful exit, then SIGKILL if still alive\n const exited = await Promise.race([\n new Promise<boolean>((resolve) => child.on('exit', () => resolve(true))),\n new Promise<boolean>((resolve) => setTimeout(() => resolve(false), SIGKILL_TIMEOUT_MS)),\n ])\n\n if (!exited) {\n log.warn('cloudflared did not exit after SIGTERM, sending SIGKILL')\n child.kill('SIGKILL')\n }\n\n log.info('Cloudflare tunnel stopped')\n }\n\n getPublicUrl(): string {\n return this.publicUrl\n }\n\n private findBinary(): string | null {\n // 1. Check PATH first (respects user's system install)\n if (commandExists('cloudflared')) return 'cloudflared'\n\n // 2. Check binDir (installed by post-upgrade)\n const binPath = path.join(this.binDir, 'cloudflared')\n if (fs.existsSync(binPath)) return binPath\n\n // 3. Not found\n return null\n }\n}\n","import { spawn, type ChildProcess } from 'node:child_process'\nimport { createChildLogger } from '../../../core/utils/log.js'\nimport type { TunnelProvider } from '../provider.js'\n\nconst log = createChildLogger({ module: 'ngrok-tunnel' })\n\nconst SIGKILL_TIMEOUT_MS = 5_000\n\nexport class NgrokTunnelProvider implements TunnelProvider {\n private child: ChildProcess | null = null\n private publicUrl = ''\n private options: Record<string, unknown>\n private exitCallback: ((code: number | null) => void) | null = null\n\n constructor(options: Record<string, unknown> = {}) {\n this.options = options\n }\n\n onExit(callback: (code: number | null) => void): void {\n this.exitCallback = callback\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 let settled = false\n const settle = (fn: () => void) => { if (!settled) { settled = true; fn() } }\n\n const timeout = setTimeout(() => {\n this.stop()\n settle(() => 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 settle(() => reject(new Error(\n 'Failed to start ngrok. Install it from https://ngrok.com/download'\n )))\n return\n }\n\n // Match both v2 (*.ngrok.io) and v3 (*.ngrok-free.app, *.ngrok.app) domains\n const urlPattern = /https:\\/\\/[a-zA-Z0-9-]+\\.(?:ngrok(?:-free)?\\.app|ngrok\\.io)/\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 settle(() => 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 settle(() => 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 settle(() => reject(new Error(`ngrok exited with code ${code} before establishing tunnel`)))\n } else {\n log.error({ code }, 'ngrok exited unexpectedly after establishment')\n this.child = null\n this.exitCallback?.(code)\n }\n })\n })\n }\n\n async stop(): Promise<void> {\n const child = this.child\n if (!child) return\n this.child = null\n\n child.kill('SIGTERM')\n\n const exited = await Promise.race([\n new Promise<boolean>((resolve) => child.on('exit', () => resolve(true))),\n new Promise<boolean>((resolve) => setTimeout(() => resolve(false), SIGKILL_TIMEOUT_MS)),\n ])\n\n if (!exited) {\n log.warn('ngrok did not exit after SIGTERM, sending SIGKILL')\n child.kill('SIGKILL')\n }\n\n log.info('ngrok tunnel stopped')\n }\n\n getPublicUrl(): string {\n return this.publicUrl\n }\n}\n","import { spawn, type ChildProcess } from 'node:child_process'\nimport { createChildLogger } from '../../../core/utils/log.js'\nimport type { TunnelProvider } from '../provider.js'\n\nconst log = createChildLogger({ module: 'bore-tunnel' })\n\nconst SIGKILL_TIMEOUT_MS = 5_000\n\nexport class BoreTunnelProvider implements TunnelProvider {\n private child: ChildProcess | null = null\n private publicUrl = ''\n private options: Record<string, unknown>\n private exitCallback: ((code: number | null) => void) | null = null\n\n constructor(options: Record<string, unknown> = {}) {\n this.options = options\n }\n\n onExit(callback: (code: number | null) => void): void {\n this.exitCallback = callback\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 let settled = false\n const settle = (fn: () => void) => { if (!settled) { settled = true; fn() } }\n\n const timeout = setTimeout(() => {\n this.stop()\n settle(() => 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 settle(() => 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 settle(() => 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 settle(() => 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 settle(() => reject(new Error(`bore exited with code ${code} before establishing tunnel`)))\n } else {\n log.error({ code }, 'bore exited unexpectedly after establishment')\n this.child = null\n this.exitCallback?.(code)\n }\n })\n })\n }\n\n async stop(): Promise<void> {\n const child = this.child\n if (!child) return\n this.child = null\n\n child.kill('SIGTERM')\n\n const exited = await Promise.race([\n new Promise<boolean>((resolve) => child.on('exit', () => resolve(true))),\n new Promise<boolean>((resolve) => setTimeout(() => resolve(false), SIGKILL_TIMEOUT_MS)),\n ])\n\n if (!exited) {\n log.warn('bore did not exit after SIGTERM, sending SIGKILL')\n child.kill('SIGKILL')\n }\n\n log.info('Bore tunnel stopped')\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/utils/log.js'\nimport type { TunnelProvider } from '../provider.js'\n\nconst log = createChildLogger({ module: 'tailscale-tunnel' })\n\nconst SIGKILL_TIMEOUT_MS = 5_000\n\nexport class TailscaleTunnelProvider implements TunnelProvider {\n private child: ChildProcess | null = null\n private publicUrl = ''\n private options: Record<string, unknown>\n private exitCallback: ((code: number | null) => void) | null = null\n\n constructor(options: Record<string, unknown> = {}) {\n this.options = options\n }\n\n onExit(callback: (code: number | null) => void): void {\n this.exitCallback = callback\n }\n\n async start(localPort: number): Promise<string> {\n let hostname = ''\n try {\n const statusJson = execSync('tailscale status --json', { encoding: 'utf-8', timeout: 10_000 })\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 let settled = false\n const settle = (fn: () => void) => { if (!settled) { settled = true; fn() } }\n\n const timeout = setTimeout(() => {\n this.stop()\n settle(() => 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 settle(() => reject(new Error(\n 'Failed to start tailscale. Install it from https://tailscale.com/download'\n )))\n return\n }\n\n // Match only Tailscale funnel URLs (*.ts.net pattern)\n const urlPattern = /https:\\/\\/[a-zA-Z0-9-]+\\.[a-zA-Z0-9-]+\\.ts\\.net/\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 settle(() => 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 settle(() => 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 // Tailscale funnel may exit immediately after configuring — construct URL with port\n this.publicUrl = `https://${hostname}:${localPort}`\n this.child = null // process is done; prevent stop() from sending SIGTERM to dead process\n log.info({ url: this.publicUrl }, 'Tailscale funnel ready (constructed from hostname)')\n settle(() => resolve(this.publicUrl))\n } else {\n settle(() => reject(new Error(`tailscale exited with code ${code} before establishing funnel`)))\n }\n } else {\n log.error({ code }, 'tailscale exited unexpectedly after establishment')\n this.child = null\n this.exitCallback?.(code)\n }\n })\n })\n }\n\n async stop(): Promise<void> {\n const child = this.child\n if (!child) return\n this.child = null\n\n child.kill('SIGTERM')\n\n const exited = await Promise.race([\n new Promise<boolean>((resolve) => child.on('exit', () => resolve(true))),\n new Promise<boolean>((resolve) => setTimeout(() => resolve(false), SIGKILL_TIMEOUT_MS)),\n ])\n\n if (!exited) {\n log.warn('tailscale did not exit after SIGTERM, sending SIGKILL')\n child.kill('SIGKILL')\n }\n\n log.info('Tailscale funnel stopped')\n }\n\n getPublicUrl(): string {\n return this.publicUrl\n }\n}\n"],"mappings":"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","names":["fs","path","os","spawn","log","SIGKILL_TIMEOUT_MS","spawn","spawn","log","SIGKILL_TIMEOUT_MS","spawn","spawn","log","SIGKILL_TIMEOUT_MS","spawn","log","path","os","fs"]}
@@ -256,4 +256,4 @@ export {
256
256
  TOKENS_PER_TURN_ESTIMATE,
257
257
  CheckpointReader
258
258
  };
259
- //# sourceMappingURL=chunk-APS6UEFU.js.map
259
+ //# sourceMappingURL=chunk-NJX75BLK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/plugins/context/context-provider.ts","../../src/plugins/context/entire/checkpoint-reader.ts"],"sourcesContent":["// NOTE: This interface is designed around Entire as the first provider.\n// It may evolve when additional providers (Cursor history, Zed, etc.) are added.\n// Providers may only support a subset of query types and should return empty results\n// for unsupported types rather than throwing.\n\nexport interface ContextProvider {\n readonly name: string;\n isAvailable(repoPath: string): Promise<boolean>;\n listSessions(query: ContextQuery): Promise<SessionListResult>;\n buildContext(query: ContextQuery, options?: ContextOptions): Promise<ContextResult>;\n}\n\nexport interface ContextQuery {\n repoPath: string;\n type: \"branch\" | \"commit\" | \"pr\" | \"latest\" | \"checkpoint\" | \"session\";\n value: string;\n}\n\nexport interface ContextOptions {\n maxTokens?: number;\n limit?: number;\n /** When true, insert `## [agentName]` headers at agent boundaries in merged history */\n labelAgent?: boolean;\n}\n\nexport interface SessionInfo {\n checkpointId: string;\n sessionIndex: string;\n transcriptPath: string;\n createdAt: string;\n endedAt: string;\n branch: string;\n agent: string;\n turnCount: number;\n filesTouched: string[];\n sessionId: string;\n}\n\nexport interface SessionListResult {\n sessions: SessionInfo[];\n estimatedTokens: number;\n}\n\nexport type ContextMode = \"full\" | \"balanced\" | \"compact\";\n\nexport interface ContextResult {\n markdown: string;\n tokenEstimate: number;\n sessionCount: number;\n totalTurns: number;\n mode: ContextMode;\n truncated: boolean;\n timeRange: { start: string; end: string };\n}\n\nexport const DEFAULT_MAX_TOKENS = 30_000;\nexport const TOKENS_PER_TURN_ESTIMATE = 400;\n","import { execFileSync } from \"child_process\";\nimport type { SessionInfo } from \"../context-provider.js\";\n\n// ─── Internal types ────────────────────────────────────────────────────────────\n\ninterface CheckpointMeta {\n checkpoint_id?: string;\n branch?: string;\n files_touched?: string[];\n sessions: Array<{\n metadata: string;\n transcript: string;\n }>;\n}\n\ninterface SessionMeta {\n session_id?: string;\n created_at?: string;\n branch?: string;\n agent?: string;\n files_touched?: string[];\n session_metrics?: {\n turn_count?: number;\n };\n}\n\n// ─── CheckpointReader ─────────────────────────────────────────────────────────\n\nconst ENTIRE_BRANCH = \"origin/entire/checkpoints/v1\";\nconst CHECKPOINT_ID_RE = /^[0-9a-f]{12}$/;\nconst SESSION_ID_RE =\n /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/;\n\nexport class CheckpointReader {\n constructor(private readonly repoPath: string) {}\n\n // ─── Git execution ───────────────────────────────────────────────────────────\n\n /**\n * Run a git command in the repo directory.\n * Returns trimmed stdout on success, empty string on failure.\n */\n private git(...args: string[]): string {\n try {\n return execFileSync(\"git\", [\"-C\", this.repoPath, ...args], {\n encoding: \"utf-8\",\n }).trim();\n } catch {\n return \"\";\n }\n }\n\n // ─── Static helpers ──────────────────────────────────────────────────────────\n\n /**\n * Convert a 12-char checkpoint ID to its shard path: \"f634acf05138\" → \"f6/34acf05138\"\n */\n static shardPath(cpId: string): string {\n return `${cpId.slice(0, 2)}/${cpId.slice(2)}`;\n }\n\n /**\n * Returns true when value looks like a 12-char lowercase hex checkpoint ID.\n */\n static isCheckpointId(value: string): boolean {\n return CHECKPOINT_ID_RE.test(value);\n }\n\n /**\n * Returns true when value looks like a UUID (session ID).\n */\n static isSessionId(value: string): boolean {\n return SESSION_ID_RE.test(value);\n }\n\n /**\n * Parse checkpoint-level metadata JSON. Returns null on error.\n */\n static parseCheckpointMeta(json: string): CheckpointMeta | null {\n try {\n const parsed = JSON.parse(json) as CheckpointMeta;\n if (!parsed || typeof parsed !== \"object\") return null;\n if (!Array.isArray(parsed.sessions)) return null;\n return parsed;\n } catch {\n return null;\n }\n }\n\n /**\n * Extract Entire-Checkpoint trailer IDs from `git log --format=\"%H|%(trailers:...)\"` output.\n * Each line is: `<hash>|<trailer_value_or_empty>`. Returns only non-empty trailer values.\n * Uses the last pipe on each line to locate the trailer value, to be robust against\n * subject lines that contain pipes.\n */\n static parseCheckpointTrailers(output: string): string[] {\n const ids: string[] = [];\n for (const line of output.split(\"\\n\")) {\n const pipe = line.lastIndexOf(\"|\");\n if (pipe === -1) continue;\n const trailerId = line.slice(pipe + 1).trim();\n if (trailerId) ids.push(trailerId);\n }\n return ids;\n }\n\n // ─── Branch check ────────────────────────────────────────────────────────────\n\n async hasEntireBranch(): Promise<boolean> {\n const out = this.git(\"branch\", \"-r\");\n return out.includes(\"entire/checkpoints/v1\");\n }\n\n // ─── Core session fetching ───────────────────────────────────────────────────\n\n private listAllCheckpointIds(): string[] {\n const out = this.git(\n \"ls-tree\",\n \"-r\",\n ENTIRE_BRANCH,\n \"--name-only\"\n );\n if (!out) return [];\n\n const ids = new Set<string>();\n for (const file of out.split(\"\\n\")) {\n const parts = file.split(\"/\");\n // Checkpoint-level metadata: XX/YYYYYYYYYY/metadata.json (3 parts)\n if (parts.length === 3 && parts[2] === \"metadata.json\") {\n ids.add(parts[0] + parts[1]);\n }\n }\n return [...ids];\n }\n\n private fetchCheckpointMeta(cpId: string): CheckpointMeta | null {\n const shard = CheckpointReader.shardPath(cpId);\n const raw = this.git(\"show\", `${ENTIRE_BRANCH}:${shard}/metadata.json`);\n if (!raw) return null;\n return CheckpointReader.parseCheckpointMeta(raw);\n }\n\n private fetchSessionMeta(metaPath: string): SessionMeta {\n const normalized = metaPath.startsWith(\"/\") ? metaPath.slice(1) : metaPath;\n const raw = this.git(\"show\", `${ENTIRE_BRANCH}:${normalized}`);\n if (!raw) return {};\n try {\n return JSON.parse(raw) as SessionMeta;\n } catch {\n return {};\n }\n }\n\n /**\n * Build SessionInfo[] from a single checkpoint's metadata.\n */\n private buildSessionsForCheckpoint(\n cpId: string,\n cpMeta: CheckpointMeta\n ): SessionInfo[] {\n const sessions: SessionInfo[] = [];\n\n for (let idx = 0; idx < cpMeta.sessions.length; idx++) {\n const sess = cpMeta.sessions[idx];\n const transcriptPath = (sess.transcript ?? \"\").replace(/^\\//, \"\");\n const metaPath = sess.metadata ?? \"\";\n\n const smeta = this.fetchSessionMeta(metaPath);\n const createdAt = smeta.created_at ?? \"\";\n\n sessions.push({\n checkpointId: cpId,\n sessionIndex: String(idx),\n transcriptPath,\n createdAt,\n endedAt: createdAt, // will be filled from JSONL by conversation builder\n branch: smeta.branch ?? cpMeta.branch ?? \"\",\n agent: smeta.agent ?? \"\",\n turnCount: smeta.session_metrics?.turn_count ?? 0,\n filesTouched: smeta.files_touched ?? cpMeta.files_touched ?? [],\n sessionId: smeta.session_id ?? \"\",\n });\n }\n\n return sessions;\n }\n\n private getSessionsForCheckpoint(cpId: string): SessionInfo[] {\n const meta = this.fetchCheckpointMeta(cpId);\n if (!meta) return [];\n return this.buildSessionsForCheckpoint(cpId, meta);\n }\n\n // ─── Public resolvers ────────────────────────────────────────────────────────\n\n /**\n * All sessions recorded on a given branch, sorted by createdAt ascending.\n */\n async resolveByBranch(branchName: string): Promise<SessionInfo[]> {\n const cpIds = this.listAllCheckpointIds();\n const sessions: SessionInfo[] = [];\n\n for (const cpId of cpIds) {\n const meta = this.fetchCheckpointMeta(cpId);\n if (!meta) continue;\n if (meta.branch !== branchName) continue;\n sessions.push(...this.buildSessionsForCheckpoint(cpId, meta));\n }\n\n sessions.sort((a, b) => a.createdAt.localeCompare(b.createdAt));\n return sessions;\n }\n\n /**\n * Sessions linked to a specific commit via the Entire-Checkpoint git trailer.\n */\n async resolveByCommit(commitHash: string): Promise<SessionInfo[]> {\n const fullHash = this.git(\"rev-parse\", commitHash);\n if (!fullHash) return [];\n\n const cpId = this.git(\n \"log\",\n \"-1\",\n \"--format=%(trailers:key=Entire-Checkpoint,valueonly)\",\n fullHash\n );\n if (!cpId) return [];\n\n return this.getSessionsForCheckpoint(cpId.trim());\n }\n\n /**\n * All sessions from a merged PR (by number or GitHub URL).\n */\n async resolveByPr(prInput: string): Promise<SessionInfo[]> {\n let prNumber: string;\n\n if (/^\\d+$/.test(prInput)) {\n prNumber = prInput;\n } else {\n const m = /\\/pull\\/(\\d+)/.exec(prInput);\n if (!m) return [];\n prNumber = m[1];\n }\n\n const mergeOut = this.git(\n \"log\",\n \"--all\",\n \"--oneline\",\n \"--grep\",\n `Merge pull request #${prNumber}`\n );\n if (!mergeOut) return [];\n\n const mergeCommit = mergeOut.split(\"\\n\")[0].split(\" \")[0];\n\n const logOut = this.git(\n \"log\",\n \"--format=%H|%(trailers:key=Entire-Checkpoint,valueonly)\",\n `${mergeCommit}^2`,\n \"--not\",\n `${mergeCommit}^1`\n );\n if (!logOut) return [];\n\n const cpIds = CheckpointReader.parseCheckpointTrailers(logOut);\n const sessions: SessionInfo[] = [];\n\n for (const cpId of cpIds) {\n sessions.push(...this.getSessionsForCheckpoint(cpId));\n }\n\n sessions.sort((a, b) => a.createdAt.localeCompare(b.createdAt));\n return sessions;\n }\n\n /**\n * Sessions matching a specific checkpoint ID.\n */\n async resolveByCheckpoint(checkpointId: string): Promise<SessionInfo[]> {\n return this.getSessionsForCheckpoint(checkpointId);\n }\n\n /**\n * Find a session by its UUID.\n */\n async resolveBySessionId(sessionId: string): Promise<SessionInfo[]> {\n const cpIds = this.listAllCheckpointIds();\n\n for (const cpId of cpIds) {\n const sessions = this.getSessionsForCheckpoint(cpId);\n const match = sessions.find((s) => s.sessionId === sessionId);\n if (match) return [match];\n }\n\n return [];\n }\n\n /**\n * Latest N sessions across all checkpoints, sorted by createdAt descending.\n */\n async resolveLatest(count: number): Promise<SessionInfo[]> {\n const cpIds = this.listAllCheckpointIds();\n const all: SessionInfo[] = [];\n\n for (const cpId of cpIds) {\n all.push(...this.getSessionsForCheckpoint(cpId));\n }\n\n all.sort((a, b) => b.createdAt.localeCompare(a.createdAt));\n return all.slice(0, count);\n }\n\n /**\n * Read the full JSONL transcript content from the entire branch.\n */\n getTranscript(transcriptPath: string): string {\n const normalized = transcriptPath.startsWith(\"/\")\n ? transcriptPath.slice(1)\n : transcriptPath;\n return this.git(\"show\", `${ENTIRE_BRANCH}:${normalized}`);\n }\n}\n"],"mappings":"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","names":[]}
@@ -1,7 +1,10 @@
1
+ import {
2
+ getGlobalRoot
3
+ } from "./chunk-ON7HB5O7.js";
4
+
1
5
  // src/core/config/config-registry.ts
2
6
  import * as fs from "fs";
3
7
  import * as path from "path";
4
- import * as os from "os";
5
8
  var CONFIG_REGISTRY = [
6
9
  {
7
10
  path: "defaultAgent",
@@ -10,7 +13,7 @@ var CONFIG_REGISTRY = [
10
13
  type: "select",
11
14
  options: (config) => {
12
15
  try {
13
- const agentsPath = path.join(os.homedir(), ".openacp", "agents.json");
16
+ const agentsPath = path.join(getGlobalRoot(), "agents.json");
14
17
  if (fs.existsSync(agentsPath)) {
15
18
  const data = JSON.parse(fs.readFileSync(agentsPath, "utf-8"));
16
19
  return Object.keys(data.installed ?? {});
@@ -105,6 +108,14 @@ var CONFIG_REGISTRY = [
105
108
  type: "string",
106
109
  scope: "sensitive",
107
110
  hotReload: true
111
+ },
112
+ {
113
+ path: "agentSwitch.labelHistory",
114
+ displayName: "Label Agent in History",
115
+ group: "agent",
116
+ type: "toggle",
117
+ scope: "safe",
118
+ hotReload: true
108
119
  }
109
120
  ];
110
121
  function getFieldDef(path2) {
@@ -142,4 +153,4 @@ export {
142
153
  resolveOptions,
143
154
  getConfigValue
144
155
  };
145
- //# sourceMappingURL=chunk-5HKQCYOI.js.map
156
+ //# sourceMappingURL=chunk-NOEAJNTK.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/config/config-registry.ts"],"sourcesContent":["import * as fs from \"node:fs\";\nimport * as path from \"node:path\";\nimport type { Config } from \"./config.js\";\nimport { getGlobalRoot } from \"../instance-context.js\";\n\nexport interface ConfigFieldDef {\n path: string;\n displayName: string;\n group: string;\n type: \"toggle\" | \"select\" | \"number\" | \"string\";\n options?: string[] | ((config: Config) => string[]);\n scope: \"safe\" | \"sensitive\";\n hotReload: boolean;\n}\n\nexport const CONFIG_REGISTRY: ConfigFieldDef[] = [\n {\n path: \"defaultAgent\",\n displayName: \"Default Agent\",\n group: \"agent\",\n type: \"select\",\n options: (config) => {\n try {\n const agentsPath = path.join(getGlobalRoot(), \"agents.json\");\n if (fs.existsSync(agentsPath)) {\n const data = JSON.parse(fs.readFileSync(agentsPath, \"utf-8\"));\n return Object.keys(data.installed ?? {});\n }\n } catch {\n /* fallback */\n }\n return Object.keys(config.agents ?? {});\n },\n scope: \"safe\",\n hotReload: true,\n },\n {\n path: \"channels.telegram.displayVerbosity\",\n displayName: \"Telegram Verbosity\",\n group: \"display\",\n type: \"select\",\n options: [\"low\", \"medium\", \"high\"],\n scope: \"safe\",\n hotReload: true,\n },\n {\n path: \"channels.discord.displayVerbosity\",\n displayName: \"Discord Verbosity\",\n group: \"display\",\n type: \"select\",\n options: [\"low\", \"medium\", \"high\"],\n scope: \"safe\",\n hotReload: true,\n },\n {\n path: \"logging.level\",\n displayName: \"Log Level\",\n group: \"logging\",\n type: \"select\",\n options: [\"silent\", \"debug\", \"info\", \"warn\", \"error\", \"fatal\"],\n scope: \"safe\",\n hotReload: true,\n },\n {\n path: \"tunnel.enabled\",\n displayName: \"Tunnel\",\n group: \"tunnel\",\n type: \"toggle\",\n scope: \"safe\",\n hotReload: false,\n },\n {\n path: \"security.maxConcurrentSessions\",\n displayName: \"Max Concurrent Sessions\",\n group: \"security\",\n type: \"number\",\n scope: \"safe\",\n hotReload: true,\n },\n {\n path: \"security.sessionTimeoutMinutes\",\n displayName: \"Session Timeout (min)\",\n group: \"security\",\n type: \"number\",\n scope: \"safe\",\n hotReload: true,\n },\n {\n path: \"workspace.baseDir\",\n displayName: \"Workspace Directory\",\n group: \"workspace\",\n type: \"string\",\n scope: \"safe\",\n hotReload: true,\n },\n {\n path: \"sessionStore.ttlDays\",\n displayName: \"Session Store TTL (days)\",\n group: \"storage\",\n type: \"number\",\n scope: \"safe\",\n hotReload: true,\n },\n {\n path: \"speech.stt.provider\",\n displayName: \"Speech to Text\",\n group: \"speech\",\n type: \"select\",\n options: [\"groq\"],\n scope: \"safe\",\n hotReload: true,\n },\n {\n path: \"speech.stt.apiKey\",\n displayName: \"STT API Key\",\n group: \"speech\",\n type: \"string\",\n scope: \"sensitive\",\n hotReload: true,\n },\n {\n path: \"agentSwitch.labelHistory\",\n displayName: \"Label Agent in History\",\n group: \"agent\",\n type: \"toggle\",\n scope: \"safe\",\n hotReload: true,\n },\n];\n\nexport function getFieldDef(path: string): ConfigFieldDef | undefined {\n return CONFIG_REGISTRY.find((f) => f.path === path);\n}\n\nexport function getSafeFields(): ConfigFieldDef[] {\n return CONFIG_REGISTRY.filter((f) => f.scope === \"safe\");\n}\n\nexport function isHotReloadable(path: string): boolean {\n const def = getFieldDef(path);\n return def?.hotReload ?? false;\n}\n\nexport function resolveOptions(\n def: ConfigFieldDef,\n config: Config,\n): string[] | undefined {\n if (!def.options) return undefined;\n return typeof def.options === \"function\" ? def.options(config) : def.options;\n}\n\nexport function getConfigValue(config: Config, path: string): unknown {\n const parts = path.split(\".\");\n let current: unknown = config;\n for (const part of parts) {\n if (current && typeof current === \"object\" && part in current) {\n current = (current as Record<string, unknown>)[part];\n } else {\n return undefined;\n }\n }\n return current;\n}\n"],"mappings":"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","names":["path"]}
@@ -0,0 +1,58 @@
1
+ // src/core/instance-context.ts
2
+ import path from "path";
3
+ import fs from "fs";
4
+ import os from "os";
5
+ function createInstanceContext(opts) {
6
+ const { id, root, isGlobal } = opts;
7
+ return {
8
+ id,
9
+ root,
10
+ isGlobal,
11
+ paths: {
12
+ config: path.join(root, "config.json"),
13
+ sessions: path.join(root, "sessions.json"),
14
+ agents: path.join(root, "agents.json"),
15
+ registryCache: path.join(root, "registry-cache.json"),
16
+ plugins: path.join(root, "plugins"),
17
+ pluginsData: path.join(root, "plugins", "data"),
18
+ pluginRegistry: path.join(root, "plugins.json"),
19
+ logs: path.join(root, "logs"),
20
+ pid: path.join(root, "openacp.pid"),
21
+ running: path.join(root, "running"),
22
+ apiPort: path.join(root, "api.port"),
23
+ apiSecret: path.join(root, "api-secret"),
24
+ bin: path.join(root, "bin"),
25
+ cache: path.join(root, "cache"),
26
+ tunnels: path.join(root, "tunnels.json"),
27
+ agentsDir: path.join(root, "agents")
28
+ }
29
+ };
30
+ }
31
+ function generateSlug(name) {
32
+ const slug = name.toLowerCase().replace(/[^a-z0-9-]/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
33
+ return slug || "openacp";
34
+ }
35
+ function expandHome(p) {
36
+ if (p.startsWith("~")) return path.join(os.homedir(), p.slice(1));
37
+ return p;
38
+ }
39
+ function resolveInstanceRoot(opts) {
40
+ const cwd = opts.cwd ?? process.cwd();
41
+ if (opts.dir) return path.join(expandHome(opts.dir), ".openacp");
42
+ if (opts.local) return path.join(cwd, ".openacp");
43
+ if (opts.global) return path.join(os.homedir(), ".openacp");
44
+ const localRoot = path.join(cwd, ".openacp");
45
+ if (fs.existsSync(localRoot)) return localRoot;
46
+ return null;
47
+ }
48
+ function getGlobalRoot() {
49
+ return path.join(os.homedir(), ".openacp");
50
+ }
51
+
52
+ export {
53
+ createInstanceContext,
54
+ generateSlug,
55
+ resolveInstanceRoot,
56
+ getGlobalRoot
57
+ };
58
+ //# sourceMappingURL=chunk-ON7HB5O7.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/core/instance-context.ts"],"sourcesContent":["import path from 'node:path'\nimport fs from 'node:fs'\nimport os from 'node:os'\n\nexport interface InstanceContext {\n id: string\n root: string\n isGlobal: boolean\n paths: {\n config: string\n sessions: string\n agents: string\n registryCache: string\n plugins: string\n pluginsData: string\n pluginRegistry: string\n logs: string\n pid: string\n running: string\n apiPort: string\n apiSecret: string\n bin: string\n cache: string\n tunnels: string\n agentsDir: string\n }\n}\n\nexport interface CreateInstanceContextOpts {\n id: string\n root: string\n isGlobal: boolean\n}\n\nexport function createInstanceContext(opts: CreateInstanceContextOpts): InstanceContext {\n const { id, root, isGlobal } = opts\n return {\n id, root, isGlobal,\n paths: {\n config: path.join(root, 'config.json'),\n sessions: path.join(root, 'sessions.json'),\n agents: path.join(root, 'agents.json'),\n registryCache: path.join(root, 'registry-cache.json'),\n plugins: path.join(root, 'plugins'),\n pluginsData: path.join(root, 'plugins', 'data'),\n pluginRegistry: path.join(root, 'plugins.json'),\n logs: path.join(root, 'logs'),\n pid: path.join(root, 'openacp.pid'),\n running: path.join(root, 'running'),\n apiPort: path.join(root, 'api.port'),\n apiSecret: path.join(root, 'api-secret'),\n bin: path.join(root, 'bin'),\n cache: path.join(root, 'cache'),\n tunnels: path.join(root, 'tunnels.json'),\n agentsDir: path.join(root, 'agents'),\n },\n }\n}\n\nexport function generateSlug(name: string): string {\n const slug = name.toLowerCase().replace(/[^a-z0-9-]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '')\n return slug || 'openacp'\n}\n\nfunction expandHome(p: string): string {\n if (p.startsWith('~')) return path.join(os.homedir(), p.slice(1))\n return p\n}\n\nexport interface ResolveOpts {\n dir?: string\n local?: boolean\n global?: boolean\n cwd?: string\n}\n\nexport function resolveInstanceRoot(opts: ResolveOpts): string | null {\n const cwd = opts.cwd ?? process.cwd()\n if (opts.dir) return path.join(expandHome(opts.dir), '.openacp')\n if (opts.local) return path.join(cwd, '.openacp')\n if (opts.global) return path.join(os.homedir(), '.openacp')\n const localRoot = path.join(cwd, '.openacp')\n if (fs.existsSync(localRoot)) return localRoot\n return null\n}\n\nexport function getGlobalRoot(): string {\n return path.join(os.homedir(), '.openacp')\n}\n"],"mappings":";AAAA,OAAO,UAAU;AACjB,OAAO,QAAQ;AACf,OAAO,QAAQ;AAgCR,SAAS,sBAAsB,MAAkD;AACtF,QAAM,EAAE,IAAI,MAAM,SAAS,IAAI;AAC/B,SAAO;AAAA,IACL;AAAA,IAAI;AAAA,IAAM;AAAA,IACV,OAAO;AAAA,MACL,QAAQ,KAAK,KAAK,MAAM,aAAa;AAAA,MACrC,UAAU,KAAK,KAAK,MAAM,eAAe;AAAA,MACzC,QAAQ,KAAK,KAAK,MAAM,aAAa;AAAA,MACrC,eAAe,KAAK,KAAK,MAAM,qBAAqB;AAAA,MACpD,SAAS,KAAK,KAAK,MAAM,SAAS;AAAA,MAClC,aAAa,KAAK,KAAK,MAAM,WAAW,MAAM;AAAA,MAC9C,gBAAgB,KAAK,KAAK,MAAM,cAAc;AAAA,MAC9C,MAAM,KAAK,KAAK,MAAM,MAAM;AAAA,MAC5B,KAAK,KAAK,KAAK,MAAM,aAAa;AAAA,MAClC,SAAS,KAAK,KAAK,MAAM,SAAS;AAAA,MAClC,SAAS,KAAK,KAAK,MAAM,UAAU;AAAA,MACnC,WAAW,KAAK,KAAK,MAAM,YAAY;AAAA,MACvC,KAAK,KAAK,KAAK,MAAM,KAAK;AAAA,MAC1B,OAAO,KAAK,KAAK,MAAM,OAAO;AAAA,MAC9B,SAAS,KAAK,KAAK,MAAM,cAAc;AAAA,MACvC,WAAW,KAAK,KAAK,MAAM,QAAQ;AAAA,IACrC;AAAA,EACF;AACF;AAEO,SAAS,aAAa,MAAsB;AACjD,QAAM,OAAO,KAAK,YAAY,EAAE,QAAQ,eAAe,GAAG,EAAE,QAAQ,OAAO,GAAG,EAAE,QAAQ,UAAU,EAAE;AACpG,SAAO,QAAQ;AACjB;AAEA,SAAS,WAAW,GAAmB;AACrC,MAAI,EAAE,WAAW,GAAG,EAAG,QAAO,KAAK,KAAK,GAAG,QAAQ,GAAG,EAAE,MAAM,CAAC,CAAC;AAChE,SAAO;AACT;AASO,SAAS,oBAAoB,MAAkC;AACpE,QAAM,MAAM,KAAK,OAAO,QAAQ,IAAI;AACpC,MAAI,KAAK,IAAK,QAAO,KAAK,KAAK,WAAW,KAAK,GAAG,GAAG,UAAU;AAC/D,MAAI,KAAK,MAAO,QAAO,KAAK,KAAK,KAAK,UAAU;AAChD,MAAI,KAAK,OAAQ,QAAO,KAAK,KAAK,GAAG,QAAQ,GAAG,UAAU;AAC1D,QAAM,YAAY,KAAK,KAAK,KAAK,UAAU;AAC3C,MAAI,GAAG,WAAW,SAAS,EAAG,QAAO;AACrC,SAAO;AACT;AAEO,SAAS,gBAAwB;AACtC,SAAO,KAAK,KAAK,GAAG,QAAQ,GAAG,UAAU;AAC3C;","names":[]}
@@ -10,6 +10,7 @@ function createSecurityPlugin() {
10
10
  description: "User access control and session limits",
11
11
  essential: false,
12
12
  permissions: ["services:register", "middleware:register", "kernel:access", "commands:register"],
13
+ inheritableKeys: ["allowedUsers", "maxSessionsPerUser", "rateLimits"],
13
14
  async install(ctx) {
14
15
  const { settings, legacyConfig, terminal } = ctx;
15
16
  if (legacyConfig) {
@@ -122,4 +123,4 @@ var security_default = createSecurityPlugin();
122
123
  export {
123
124
  security_default
124
125
  };
125
- //# sourceMappingURL=chunk-5OCGO27U.js.map
126
+ //# sourceMappingURL=chunk-OSBZXY2W.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/plugins/security/index.ts"],"sourcesContent":["import type { OpenACPPlugin, InstallContext, MiddlewarePayloadMap } from '../../core/plugin/types.js'\nimport { SecurityGuard } from './security-guard.js'\nimport type { IncomingMessage } from '../../core/types.js'\n\n// Structural type for the core fields SecurityGuard needs, avoiding\n// a direct dependency on OpenACPCore's full interface.\ninterface SecurityCoreAccess {\n configManager: ConstructorParameters<typeof SecurityGuard>[0]\n sessionManager: ConstructorParameters<typeof SecurityGuard>[1]\n}\n\n// Factory function pattern (closure for state)\nfunction createSecurityPlugin(): OpenACPPlugin {\n return {\n name: '@openacp/security',\n version: '1.0.0',\n description: 'User access control and session limits',\n essential: false,\n permissions: ['services:register', 'middleware:register', 'kernel:access', 'commands:register'],\n inheritableKeys: ['allowedUsers', 'maxSessionsPerUser', 'rateLimits'],\n\n async install(ctx: InstallContext) {\n const { settings, legacyConfig, terminal } = ctx\n\n // Migrate from legacy config if present\n if (legacyConfig) {\n const securityCfg = legacyConfig.security as Record<string, unknown> | undefined\n if (securityCfg) {\n await settings.setAll({\n allowedUserIds: securityCfg.allowedUserIds ?? [],\n maxConcurrentSessions: securityCfg.maxConcurrentSessions ?? 20,\n sessionTimeoutMinutes: securityCfg.sessionTimeoutMinutes ?? 60,\n })\n terminal.log.success('Security settings migrated from legacy config')\n return\n }\n }\n\n // Save defaults (no interactive prompts needed)\n await settings.setAll({\n allowedUserIds: [],\n maxConcurrentSessions: 20,\n sessionTimeoutMinutes: 60,\n })\n terminal.log.success('Security defaults saved')\n },\n\n async configure(ctx: InstallContext) {\n const { terminal, settings } = ctx\n const current = await settings.getAll()\n\n const choice = await terminal.select({\n message: 'What to configure?',\n options: [\n { value: 'allowedUsers', label: 'Edit allowed user IDs' },\n { value: 'maxSessions', label: `Max concurrent sessions (current: ${current.maxConcurrentSessions ?? 20})` },\n { value: 'timeout', label: `Session timeout minutes (current: ${current.sessionTimeoutMinutes ?? 60})` },\n { value: 'done', label: 'Done' },\n ],\n })\n\n if (choice === 'allowedUsers') {\n const currentIds = (current.allowedUserIds as string[]) ?? []\n const val = await terminal.text({\n message: 'Allowed user IDs (comma-separated, empty = allow all):',\n defaultValue: currentIds.join(', '),\n })\n const ids = val.split(',').map((s) => s.trim()).filter(Boolean)\n await settings.set('allowedUserIds', ids)\n terminal.log.success('Allowed user IDs updated')\n } else if (choice === 'maxSessions') {\n const val = await terminal.text({\n message: 'Max concurrent sessions:',\n defaultValue: String(current.maxConcurrentSessions ?? 20),\n validate: (v) => {\n const n = Number(v.trim())\n if (isNaN(n) || n < 1) return 'Must be a positive number'\n return undefined\n },\n })\n await settings.set('maxConcurrentSessions', Number(val.trim()))\n terminal.log.success('Max sessions updated')\n } else if (choice === 'timeout') {\n const val = await terminal.text({\n message: 'Session timeout (minutes):',\n defaultValue: String(current.sessionTimeoutMinutes ?? 60),\n validate: (v) => {\n const n = Number(v.trim())\n if (isNaN(n) || n < 1) return 'Must be a positive number'\n return undefined\n },\n })\n await settings.set('sessionTimeoutMinutes', Number(val.trim()))\n terminal.log.success('Session timeout updated')\n }\n },\n\n async uninstall(ctx: InstallContext, opts: { purge: boolean }) {\n if (opts.purge) {\n await ctx.settings.clear()\n ctx.terminal.log.success('Security settings cleared')\n }\n },\n\n async setup(ctx) {\n const core = ctx.core as SecurityCoreAccess\n const guard = new SecurityGuard(core.configManager, core.sessionManager)\n\n // Register middleware for message:incoming — block unauthorized users\n ctx.registerMiddleware('message:incoming', {\n handler: async (payload: MiddlewarePayloadMap['message:incoming'], next) => {\n const access = guard.checkAccess(payload as unknown as IncomingMessage)\n if (!access.allowed) {\n ctx.log.info(`Access denied: ${access.reason}`)\n return null // block\n }\n return next()\n }\n })\n\n // Register SecurityGuard as the service directly\n ctx.registerService('security', guard)\n\n ctx.registerCommand({\n name: 'dangerous',\n description: 'Toggle dangerous mode (auto-approve all permissions)',\n usage: 'on|off',\n category: 'plugin',\n handler: async (args) => {\n const mode = args.raw.trim().toLowerCase()\n if (mode === 'on') return { type: 'text', text: 'Dangerous mode enabled — all permissions will be auto-approved.' }\n if (mode === 'off') return { type: 'text', text: 'Dangerous mode disabled — permissions require manual approval.' }\n return { type: 'menu', title: 'Dangerous Mode', options: [\n { label: 'Enable', command: '/dangerous on' },\n { label: 'Disable', command: '/dangerous off' },\n ]}\n },\n })\n\n ctx.log.info('Security service ready')\n },\n }\n}\n\nexport default createSecurityPlugin()\n"],"mappings":"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","names":[]}
@@ -1,4 +1,9 @@
1
+ import {
2
+ MAX_RETRIES
3
+ } from "./chunk-NHD5XDD2.js";
4
+
1
5
  // src/plugins/tunnel/index.ts
6
+ import path from "path";
2
7
  function createTunnelPlugin() {
3
8
  let service = null;
4
9
  return {
@@ -110,6 +115,7 @@ function createTunnelPlugin() {
110
115
  ctx.terminal.log.success("Tunnel settings cleared");
111
116
  }
112
117
  },
118
+ inheritableKeys: ["provider", "maxUserTunnels", "auth"],
113
119
  async setup(ctx) {
114
120
  const config = ctx.pluginConfig;
115
121
  if (!config.enabled) {
@@ -120,8 +126,12 @@ function createTunnelPlugin() {
120
126
  ctx.log.info("Tunnel disabled (no provider configured)");
121
127
  return;
122
128
  }
123
- const { TunnelService } = await import("./tunnel-service-ZMO4THKE.js");
124
- const tunnelSvc = new TunnelService(config);
129
+ const { TunnelService } = await import("./tunnel-service-TBAHDXMF.js");
130
+ const instanceRoot = ctx.instanceRoot;
131
+ const tunnelSvc = new TunnelService(
132
+ config,
133
+ path.join(instanceRoot, "tunnels.json")
134
+ );
125
135
  const publicUrl = await tunnelSvc.start();
126
136
  service = tunnelSvc;
127
137
  ctx.registerService("tunnel", tunnelSvc);
@@ -137,8 +147,8 @@ function createTunnelPlugin() {
137
147
  try {
138
148
  await tunnelSvc.stopTunnel(port);
139
149
  return { type: "text", text: `Tunnel on port ${port} stopped.` };
140
- } catch (err) {
141
- return { type: "error", message: err.message };
150
+ } catch (err2) {
151
+ return { type: "error", message: err2.message };
142
152
  }
143
153
  }
144
154
  if (parts[0] && parts[0] !== "") {
@@ -148,12 +158,16 @@ function createTunnelPlugin() {
148
158
  try {
149
159
  const entry = await tunnelSvc.addTunnel(port, { label });
150
160
  return { type: "text", text: `Tunnel created: ${entry.publicUrl ?? "starting..."}` };
151
- } catch (err) {
152
- return { type: "error", message: err.message };
161
+ } catch (err2) {
162
+ return { type: "error", message: err2.message };
153
163
  }
154
164
  }
155
165
  const url = tunnelSvc.getPublicUrl();
156
- return { type: "text", text: url ? `Tunnel: ${url}` : "No tunnel active." };
166
+ const err = tunnelSvc.getStartError();
167
+ let text = url ? `Tunnel: ${url}` : "No tunnel active.";
168
+ if (err) text += `
169
+ \u26A0\uFE0F System tunnel error: ${err}`;
170
+ return { type: "text", text };
157
171
  }
158
172
  });
159
173
  ctx.registerCommand({
@@ -163,12 +177,17 @@ function createTunnelPlugin() {
163
177
  handler: async () => {
164
178
  const userTunnels = tunnelSvc.listTunnels();
165
179
  const systemUrl = tunnelSvc.getPublicUrl();
180
+ const sysError = tunnelSvc.getStartError();
181
+ const systemDetail = sysError ? `${systemUrl} \u26A0\uFE0F ${sysError}` : systemUrl;
166
182
  const items = [
167
- { label: "System", detail: systemUrl },
168
- ...userTunnels.map((t) => ({
169
- label: t.label ?? `Port ${t.port}`,
170
- detail: `${t.publicUrl ?? t.status} (${t.provider})`
171
- }))
183
+ { label: "System", detail: systemDetail },
184
+ ...userTunnels.map((t) => {
185
+ const statusInfo = t.status === "failed" && t.retryCount > 0 ? `${t.status} (retry ${t.retryCount}/${MAX_RETRIES})` : t.status;
186
+ return {
187
+ label: t.label ?? `Port ${t.port}`,
188
+ detail: `${t.publicUrl ?? statusInfo} (${t.provider})`
189
+ };
190
+ })
172
191
  ];
173
192
  return { type: "list", title: "Active Tunnels", items };
174
193
  }
@@ -187,4 +206,4 @@ var tunnel_default = createTunnelPlugin();
187
206
  export {
188
207
  tunnel_default
189
208
  };
190
- //# sourceMappingURL=chunk-PA6MNBG4.js.map
209
+ //# sourceMappingURL=chunk-P3HHJANC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../src/plugins/tunnel/index.ts"],"sourcesContent":["import path from 'node:path'\nimport type { OpenACPPlugin, InstallContext } from '../../core/plugin/types.js'\nimport type { TunnelConfig } from '../../core/config/config.js'\nimport { MAX_RETRIES } from './tunnel-registry.js'\n\nfunction createTunnelPlugin(): OpenACPPlugin {\n let service: { stop(): Promise<void> } | null = null\n\n return {\n name: '@openacp/tunnel',\n version: '1.0.0',\n description: 'Expose local services to internet via tunnel providers',\n essential: false,\n permissions: ['services:register', 'kernel:access', 'commands:register'],\n\n async install(ctx: InstallContext) {\n const { terminal, settings, legacyConfig } = ctx\n\n // Migrate from legacy config if present\n if (legacyConfig) {\n const tunnelCfg = legacyConfig.tunnel as Record<string, unknown> | undefined\n if (tunnelCfg) {\n await settings.setAll({\n enabled: tunnelCfg.enabled ?? true,\n provider: tunnelCfg.provider ?? 'cloudflare',\n port: tunnelCfg.port ?? 3100,\n options: tunnelCfg.options ?? {},\n maxUserTunnels: tunnelCfg.maxUserTunnels ?? 5,\n storeTtlMinutes: tunnelCfg.storeTtlMinutes ?? 60,\n auth: tunnelCfg.auth ?? { enabled: false },\n })\n terminal.log.success('Tunnel settings migrated from legacy config')\n return\n }\n }\n\n // Interactive setup\n const provider = await terminal.select({\n message: 'Tunnel provider:',\n options: [\n { value: 'cloudflare', label: 'Cloudflare (cloudflared)', hint: 'Free, no account needed' },\n { value: 'ngrok', label: 'ngrok', hint: 'Requires auth token' },\n { value: 'bore', label: 'bore', hint: 'Self-hostable' },\n { value: 'tailscale', label: 'Tailscale Funnel' },\n ],\n })\n\n const portStr = await terminal.text({\n message: 'Local port to expose:',\n defaultValue: '3100',\n validate: (v) => {\n const n = Number(v.trim())\n if (isNaN(n) || n < 1 || n > 65535) return 'Port must be 1-65535'\n return undefined\n },\n })\n\n let authToken = ''\n if (provider === 'ngrok') {\n authToken = await terminal.text({\n message: 'ngrok auth token:',\n validate: (v) => (!v.trim() ? 'Auth token cannot be empty' : undefined),\n })\n authToken = authToken.trim()\n }\n\n await settings.setAll({\n enabled: true,\n provider,\n port: Number(portStr.trim()),\n options: authToken ? { authtoken: authToken } : {},\n maxUserTunnels: 5,\n storeTtlMinutes: 60,\n auth: { enabled: false },\n })\n terminal.log.success('Tunnel settings saved')\n },\n\n async configure(ctx: InstallContext) {\n const { terminal, settings } = ctx\n const current = await settings.getAll()\n\n const choice = await terminal.select({\n message: 'What to configure?',\n options: [\n { value: 'provider', label: `Change provider (current: ${current.provider ?? 'none'})` },\n { value: 'port', label: `Change port (current: ${current.port ?? 3100})` },\n { value: 'toggle', label: `${current.enabled ? 'Disable' : 'Enable'} tunnel` },\n { value: 'done', label: 'Done' },\n ],\n })\n\n if (choice === 'provider') {\n const provider = await terminal.select({\n message: 'Tunnel provider:',\n options: [\n { value: 'cloudflare', label: 'Cloudflare' },\n { value: 'ngrok', label: 'ngrok' },\n { value: 'bore', label: 'bore' },\n { value: 'tailscale', label: 'Tailscale' },\n ],\n })\n await settings.set('provider', provider)\n terminal.log.success('Provider updated')\n } else if (choice === 'port') {\n const val = await terminal.text({\n message: 'New port:',\n defaultValue: String(current.port ?? 3100),\n validate: (v) => {\n const n = Number(v.trim())\n if (isNaN(n) || n < 1 || n > 65535) return 'Port must be 1-65535'\n return undefined\n },\n })\n await settings.set('port', Number(val.trim()))\n terminal.log.success('Port updated')\n } else if (choice === 'toggle') {\n const newState = !current.enabled\n await settings.set('enabled', newState)\n terminal.log.success(`Tunnel ${newState ? 'enabled' : 'disabled'}`)\n }\n },\n\n async uninstall(ctx: InstallContext, opts: { purge: boolean }) {\n if (opts.purge) {\n await ctx.settings.clear()\n ctx.terminal.log.success('Tunnel settings cleared')\n }\n },\n\n inheritableKeys: ['provider', 'maxUserTunnels', 'auth'],\n\n async setup(ctx) {\n const config = ctx.pluginConfig as Record<string, unknown>\n if (!config.enabled) {\n ctx.log.info('Tunnel disabled')\n return\n }\n if (!config.provider) {\n ctx.log.info('Tunnel disabled (no provider configured)')\n return\n }\n\n const { TunnelService } = await import('./tunnel-service.js')\n const instanceRoot = ctx.instanceRoot\n const tunnelSvc = new TunnelService(\n config as unknown as TunnelConfig,\n path.join(instanceRoot, 'tunnels.json'),\n )\n const publicUrl = await tunnelSvc.start()\n service = tunnelSvc\n\n ctx.registerService('tunnel', tunnelSvc)\n\n ctx.registerCommand({\n name: 'tunnel',\n description: 'Manage tunnels: /tunnel <port> [label] | /tunnel stop <port>',\n category: 'plugin',\n handler: async (args) => {\n const parts = args.raw.trim().split(/\\s+/)\n\n // /tunnel stop <port>\n if (parts[0] === 'stop' && parts[1]) {\n const port = parseInt(parts[1], 10)\n if (isNaN(port)) return { type: 'error', message: 'Invalid port number' }\n try {\n await tunnelSvc.stopTunnel(port)\n return { type: 'text', text: `Tunnel on port ${port} stopped.` }\n } catch (err) {\n return { type: 'error', message: (err as Error).message }\n }\n }\n\n // /tunnel <port> [label]\n if (parts[0] && parts[0] !== '') {\n const port = parseInt(parts[0], 10)\n if (isNaN(port)) return { type: 'error', message: 'Invalid port number' }\n const label = parts.slice(1).join(' ') || undefined\n try {\n const entry = await tunnelSvc.addTunnel(port, { label })\n return { type: 'text', text: `Tunnel created: ${entry.publicUrl ?? 'starting...'}` }\n } catch (err) {\n return { type: 'error', message: (err as Error).message }\n }\n }\n\n // /tunnel (no args) — show current tunnel URL + health\n const url = tunnelSvc.getPublicUrl()\n const err = tunnelSvc.getStartError()\n let text = url ? `Tunnel: ${url}` : 'No tunnel active.'\n if (err) text += `\\n⚠️ System tunnel error: ${err}`\n return { type: 'text', text }\n },\n })\n\n ctx.registerCommand({\n name: 'tunnels',\n description: 'List active tunnels',\n category: 'plugin',\n handler: async () => {\n const userTunnels = tunnelSvc.listTunnels()\n const systemUrl = tunnelSvc.getPublicUrl()\n const sysError = tunnelSvc.getStartError()\n const systemDetail = sysError ? `${systemUrl} ⚠️ ${sysError}` : systemUrl\n const items = [\n { label: 'System', detail: systemDetail },\n ...userTunnels.map(t => {\n const statusInfo = t.status === 'failed' && t.retryCount > 0\n ? `${t.status} (retry ${t.retryCount}/${MAX_RETRIES})`\n : t.status\n return {\n label: t.label ?? `Port ${t.port}`,\n detail: `${t.publicUrl ?? statusInfo} (${t.provider})`,\n }\n }),\n ]\n return { type: 'list', title: 'Active Tunnels', items }\n },\n })\n\n ctx.log.info(`Tunnel ready: ${publicUrl}`)\n },\n\n async teardown() {\n if (service) {\n await service.stop()\n }\n },\n }\n}\n\nexport default createTunnelPlugin()\n"],"mappings":"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","names":["err"]}
@@ -1,9 +1,9 @@
1
- import {
2
- getAgentCapabilities
3
- } from "./chunk-ZSLHHQPQ.js";
4
1
  import {
5
2
  createChildLogger
6
3
  } from "./chunk-R6KZYF7D.js";
4
+ import {
5
+ getAgentCapabilities
6
+ } from "./chunk-ZSLHHQPQ.js";
7
7
 
8
8
  // src/plugins/api-server/api-server.ts
9
9
  import * as http from "http";
@@ -592,7 +592,7 @@ function redactDeep(obj) {
592
592
  }
593
593
  function registerConfigRoutes(router, deps) {
594
594
  router.get("/api/config/editable", async (_req, res) => {
595
- const { getSafeFields, resolveOptions, getConfigValue } = await import("./config-registry-ZXAIJNYB.js");
595
+ const { getSafeFields, resolveOptions, getConfigValue } = await import("./config-registry-M3FFWEVM.js");
596
596
  const config = deps.core.configManager.get();
597
597
  const safeFields = getSafeFields();
598
598
  const fields = safeFields.map((def) => ({
@@ -634,7 +634,7 @@ function registerConfigRoutes(router, deps) {
634
634
  deps.sendJson(res, 400, { error: "Invalid config path" });
635
635
  return;
636
636
  }
637
- const { getFieldDef } = await import("./config-registry-ZXAIJNYB.js");
637
+ const { getFieldDef } = await import("./config-registry-M3FFWEVM.js");
638
638
  const fieldDef = getFieldDef(configPath);
639
639
  if (!fieldDef || fieldDef.scope !== "safe") {
640
640
  deps.sendJson(res, 403, {
@@ -659,7 +659,7 @@ function registerConfigRoutes(router, deps) {
659
659
  }
660
660
  const lastKey = parts[parts.length - 1];
661
661
  target[lastKey] = value;
662
- const { ConfigSchema } = await import("./config-KN6NKKPF.js");
662
+ const { ConfigSchema } = await import("./config-X4UP7H6R.js");
663
663
  const result = ConfigSchema.safeParse(cloned);
664
664
  if (!result.success) {
665
665
  deps.sendJson(res, 400, {
@@ -679,7 +679,7 @@ function registerConfigRoutes(router, deps) {
679
679
  }
680
680
  updateTarget[lastKey] = value;
681
681
  await deps.core.configManager.save(updates, configPath);
682
- const { isHotReloadable } = await import("./config-registry-ZXAIJNYB.js");
682
+ const { isHotReloadable } = await import("./config-registry-M3FFWEVM.js");
683
683
  const needsRestart = !isHotReloadable(configPath);
684
684
  deps.sendJson(res, 200, {
685
685
  ok: true,
@@ -867,7 +867,6 @@ function registerNotifyRoutes(router, deps) {
867
867
 
868
868
  // src/plugins/api-server/api-server.ts
869
869
  var log2 = createChildLogger({ module: "api-server" });
870
- var DEFAULT_PORT_FILE = path2.join(os.homedir(), ".openacp", "api.port");
871
870
  var cachedVersion;
872
871
  function getVersion() {
873
872
  if (cachedVersion) return cachedVersion;
@@ -889,7 +888,7 @@ var ApiServer = class {
889
888
  this.core = core;
890
889
  this.config = config;
891
890
  this.topicManager = topicManager;
892
- this.portFilePath = portFilePath ?? DEFAULT_PORT_FILE;
891
+ this.portFilePath = portFilePath ?? path2.join(os.homedir(), ".openacp", "api.port");
893
892
  this.secretFilePath = secretFilePath ?? path2.join(os.homedir(), ".openacp", "api-secret");
894
893
  this.staticServer = new StaticServer(uiDir);
895
894
  this.sseManager = new SSEManager(
@@ -1113,4 +1112,4 @@ export {
1113
1112
  StaticServer,
1114
1113
  ApiServer
1115
1114
  };
1116
- //# sourceMappingURL=chunk-BTJHGSLM.js.map
1115
+ //# sourceMappingURL=chunk-R2YLDQLI.js.map