@xopcai/xopc 0.0.20 → 0.0.21

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 (195) hide show
  1. package/dist/extensions/feishu/src/adapters/cli-login.d.ts +8 -0
  2. package/dist/extensions/feishu/src/adapters/cli-login.js +225 -0
  3. package/dist/extensions/feishu/src/adapters/cli-login.js.map +1 -0
  4. package/dist/extensions/feishu/src/adapters/onboard-cli.js +1 -105
  5. package/dist/extensions/feishu/src/adapters/onboard-cli.js.map +1 -1
  6. package/dist/extensions/feishu/src/auth/app-registration.d.ts +47 -0
  7. package/dist/extensions/feishu/src/auth/app-registration.js +122 -0
  8. package/dist/extensions/feishu/src/auth/app-registration.js.map +1 -0
  9. package/dist/extensions/feishu/src/plugin.d.ts +2 -0
  10. package/dist/extensions/feishu/src/plugin.js +2 -0
  11. package/dist/extensions/feishu/src/plugin.js.map +1 -1
  12. package/dist/extensions/telegram/src/inbound-processor.js +1 -1
  13. package/dist/extensions/telegram/src/plugin.d.ts +1 -1
  14. package/dist/extensions/telegram/src/plugin.js +1 -1
  15. package/dist/extensions/telegram/src/routing-integration.js +2 -2
  16. package/dist/extensions/telegram/xopc.extension.json +1 -1
  17. package/dist/extensions/weixin/src/plugin.js +1 -1
  18. package/dist/gateway/static/root/assets/{agents-DbLV2ldC.js → agents-MbH57-L9.js} +2 -2
  19. package/dist/gateway/static/root/assets/{agents-DbLV2ldC.js.map → agents-MbH57-L9.js.map} +1 -1
  20. package/dist/gateway/static/root/assets/{apps-page-CDRSbv3l.js → apps-page-3i3DvI7i.js} +2 -2
  21. package/dist/gateway/static/root/assets/{apps-page-CDRSbv3l.js.map → apps-page-3i3DvI7i.js.map} +1 -1
  22. package/dist/gateway/static/root/assets/channels-settings-CcuSzoB6.js +9 -0
  23. package/dist/gateway/static/root/assets/channels-settings-CcuSzoB6.js.map +1 -0
  24. package/dist/gateway/static/root/assets/{cron-page-D-fhl446.js → cron-page-Be1h9Yub.js} +2 -2
  25. package/dist/gateway/static/root/assets/{cron-page-D-fhl446.js.map → cron-page-Be1h9Yub.js.map} +1 -1
  26. package/dist/gateway/static/root/assets/{cron-utils-DqyPqEDr.js → cron-utils-CR97EvZS.js} +2 -2
  27. package/dist/gateway/static/root/assets/{cron-utils-DqyPqEDr.js.map → cron-utils-CR97EvZS.js.map} +1 -1
  28. package/dist/gateway/static/root/assets/{dist-BTNDXpKu.js → dist-r_Gy-XJv.js} +2 -2
  29. package/dist/gateway/static/root/assets/{dist-BTNDXpKu.js.map → dist-r_Gy-XJv.js.map} +1 -1
  30. package/dist/gateway/static/root/assets/{extension-debug-page-CiOtMG3X.js → extension-debug-page-QfYEYruq.js} +2 -2
  31. package/dist/gateway/static/root/assets/{extension-debug-page-CiOtMG3X.js.map → extension-debug-page-QfYEYruq.js.map} +1 -1
  32. package/dist/gateway/static/root/assets/{extension-page-a59AFw7Q.js → extension-page-4FW-BmKG.js} +2 -2
  33. package/dist/gateway/static/root/assets/{extension-page-a59AFw7Q.js.map → extension-page-4FW-BmKG.js.map} +1 -1
  34. package/dist/gateway/static/root/assets/{extension-settings-page-BQyLvxBY.js → extension-settings-page-E_Wq9LL8.js} +2 -2
  35. package/dist/gateway/static/root/assets/{extension-settings-page-BQyLvxBY.js.map → extension-settings-page-E_Wq9LL8.js.map} +1 -1
  36. package/dist/gateway/static/root/assets/{index-fGYWcYhm.js → index-CcQtNJKo.js} +60 -54
  37. package/dist/gateway/static/root/assets/{index-fGYWcYhm.js.map → index-CcQtNJKo.js.map} +1 -1
  38. package/dist/gateway/static/root/assets/index-D9Wmfh2f.css +1 -0
  39. package/dist/gateway/static/root/assets/{logs-page-DMSWW0-k.js → logs-page-DFhTU-kG.js} +2 -2
  40. package/dist/gateway/static/root/assets/{logs-page-DMSWW0-k.js.map → logs-page-DFhTU-kG.js.map} +1 -1
  41. package/dist/gateway/static/root/assets/{sessions-page-CL2E3nPk.js → sessions-page-wmnnIj6Z.js} +2 -2
  42. package/dist/gateway/static/root/assets/{sessions-page-CL2E3nPk.js.map → sessions-page-wmnnIj6Z.js.map} +1 -1
  43. package/dist/gateway/static/root/assets/settings-page-BTmUXY4s.js +2 -0
  44. package/dist/gateway/static/root/assets/settings-page-BTmUXY4s.js.map +1 -0
  45. package/dist/gateway/static/root/assets/{skills-page-0rmNu4AL.js → skills-page-D-fRbJG0.js} +2 -2
  46. package/dist/gateway/static/root/assets/{skills-page-0rmNu4AL.js.map → skills-page-D-fRbJG0.js.map} +1 -1
  47. package/dist/gateway/static/root/index.html +2 -2
  48. package/dist/package.js +1 -1
  49. package/dist/src/agent/agent-manager.js +6 -6
  50. package/dist/src/agent/context/workspace-seed.js +1 -1
  51. package/dist/src/agent/ipc/bus.js +1 -1
  52. package/dist/src/agent/ipc/inbox.js +1 -1
  53. package/dist/src/agent/ipc/socket.js +1 -1
  54. package/dist/src/agent/memory/builtin-memory-store.d.ts +2 -1
  55. package/dist/src/agent/memory/builtin-memory-store.js +7 -6
  56. package/dist/src/agent/memory/builtin-memory-store.js.map +1 -1
  57. package/dist/src/agent/models/manager.js +1 -1
  58. package/dist/src/agent/prompt/memory/index.d.ts +4 -2
  59. package/dist/src/agent/prompt/memory/index.js +22 -10
  60. package/dist/src/agent/prompt/memory/index.js.map +1 -1
  61. package/dist/src/agent/prompt/service-prompt-builder.js +1 -1
  62. package/dist/src/agent/service.js +5 -5
  63. package/dist/src/agent/skills/index.js +1 -1
  64. package/dist/src/agent/skills/scanner.js +1 -1
  65. package/dist/src/agent/skills/skill-manage-ops.js +1 -1
  66. package/dist/src/agent/skills/skill-manager.js +1 -1
  67. package/dist/src/agent/tools/factory.js +10 -3
  68. package/dist/src/agent/tools/factory.js.map +1 -1
  69. package/dist/src/agent/tools/index.d.ts +1 -1
  70. package/dist/src/agent/tools/memory-tool.d.ts +7 -2
  71. package/dist/src/agent/tools/memory-tool.js +11 -5
  72. package/dist/src/agent/tools/memory-tool.js.map +1 -1
  73. package/dist/src/agent/tools/send-media.js +1 -1
  74. package/dist/src/agent/tools/skill-manage-tool.js +1 -1
  75. package/dist/src/agent/tools/write.js +1 -1
  76. package/dist/src/auth/credentials.js +2 -2
  77. package/dist/src/auth/sync-provider-auth.js +1 -1
  78. package/dist/src/channels/attachments/inbound-persist.js +1 -1
  79. package/dist/src/channels/attachments/outbound-tts-persist.js +1 -1
  80. package/dist/src/channels/registry.d.ts +1 -1
  81. package/dist/src/channels/registry.js +25 -1
  82. package/dist/src/channels/registry.js.map +1 -1
  83. package/dist/src/chat-commands/builtins/config.js +3 -3
  84. package/dist/src/chat-commands/builtins/session.js +1 -1
  85. package/dist/src/chat-commands/context.js +1 -1
  86. package/dist/src/chat-commands/index.js +1 -1
  87. package/dist/src/chat-commands/processor.js +1 -1
  88. package/dist/src/cli/commands/agent.js +1 -1
  89. package/dist/src/cli/commands/channels.js +20 -2
  90. package/dist/src/cli/commands/channels.js.map +1 -1
  91. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  92. package/dist/src/cli/commands/gateway/call.d.ts +2 -0
  93. package/dist/src/cli/commands/gateway/call.js +90 -0
  94. package/dist/src/cli/commands/gateway/call.js.map +1 -0
  95. package/dist/src/cli/commands/gateway/health.d.ts +2 -0
  96. package/dist/src/cli/commands/gateway/health.js +77 -0
  97. package/dist/src/cli/commands/gateway/health.js.map +1 -0
  98. package/dist/src/cli/commands/gateway/index.d.ts +3 -0
  99. package/dist/src/cli/commands/gateway/index.js +4 -1
  100. package/dist/src/cli/commands/gateway/probe.d.ts +2 -0
  101. package/dist/src/cli/commands/gateway/probe.js +102 -0
  102. package/dist/src/cli/commands/gateway/probe.js.map +1 -0
  103. package/dist/src/cli/commands/gateway/status.d.ts +0 -3
  104. package/dist/src/cli/commands/gateway/status.js +107 -24
  105. package/dist/src/cli/commands/gateway/status.js.map +1 -1
  106. package/dist/src/cli/commands/gateway.js +7 -1
  107. package/dist/src/cli/commands/gateway.js.map +1 -1
  108. package/dist/src/cli/commands/init.js +3 -3
  109. package/dist/src/cli/commands/update.js +19 -1
  110. package/dist/src/cli/commands/update.js.map +1 -1
  111. package/dist/src/cli/utils/gateway-client.d.ts +28 -0
  112. package/dist/src/cli/utils/gateway-client.js +115 -0
  113. package/dist/src/cli/utils/gateway-client.js.map +1 -0
  114. package/dist/src/config/index.js +2 -2
  115. package/dist/src/config/loader.js +1 -1
  116. package/dist/src/config/models-json.js +1 -1
  117. package/dist/src/config/paths-state.d.ts +4 -0
  118. package/dist/src/config/paths-state.js +9 -1
  119. package/dist/src/config/paths-state.js.map +1 -1
  120. package/dist/src/config/profile.js +2 -2
  121. package/dist/src/config/reload.d.ts +2 -0
  122. package/dist/src/config/reload.js +9 -1
  123. package/dist/src/config/reload.js.map +1 -1
  124. package/dist/src/config/rules.js +12 -2
  125. package/dist/src/config/rules.js.map +1 -1
  126. package/dist/src/cron/executor.js +2 -2
  127. package/dist/src/cron/persistence.js +1 -1
  128. package/dist/src/cron/run-log-store.js +1 -1
  129. package/dist/src/extensions/api.d.ts +6 -1
  130. package/dist/src/extensions/api.js +52 -1
  131. package/dist/src/extensions/api.js.map +1 -1
  132. package/dist/src/extensions/health.js +1 -1
  133. package/dist/src/extensions/loader.d.ts +6 -1
  134. package/dist/src/extensions/loader.js +21 -2
  135. package/dist/src/extensions/loader.js.map +1 -1
  136. package/dist/src/extensions/lockfile.js +1 -1
  137. package/dist/src/extensions/normalize-manifest.js +33 -0
  138. package/dist/src/extensions/normalize-manifest.js.map +1 -1
  139. package/dist/src/extensions/sdk/index.d.ts +1 -1
  140. package/dist/src/extensions/sdk/index.js.map +1 -1
  141. package/dist/src/extensions/types/core.d.ts +35 -1
  142. package/dist/src/extensions/types/manifest.d.ts +14 -0
  143. package/dist/src/gateway/agents-admin.js +1 -1
  144. package/dist/src/gateway/hono/lib/config-payload.d.ts +3 -0
  145. package/dist/src/gateway/hono/lib/config-payload.js +1 -0
  146. package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
  147. package/dist/src/gateway/hono/oauth.js +1 -1
  148. package/dist/src/gateway/hono/routes/channels.js +111 -0
  149. package/dist/src/gateway/hono/routes/channels.js.map +1 -1
  150. package/dist/src/gateway/hono/routes/commands-skills.js +13 -2
  151. package/dist/src/gateway/hono/routes/commands-skills.js.map +1 -1
  152. package/dist/src/gateway/hono/routes/config.js +82 -1
  153. package/dist/src/gateway/hono/routes/config.js.map +1 -1
  154. package/dist/src/gateway/hono/routes/public-gateway.js +17 -0
  155. package/dist/src/gateway/hono/routes/public-gateway.js.map +1 -1
  156. package/dist/src/gateway/hono/routes/sessions.js +16 -0
  157. package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
  158. package/dist/src/gateway/hono/routes/status.js +31 -7
  159. package/dist/src/gateway/hono/routes/status.js.map +1 -1
  160. package/dist/src/gateway/hono/routes/update.js +118 -15
  161. package/dist/src/gateway/hono/routes/update.js.map +1 -1
  162. package/dist/src/gateway/hono/routes/workspace.js +2 -2
  163. package/dist/src/gateway/hono/sse.js +2 -2
  164. package/dist/src/gateway/index.js +1 -1
  165. package/dist/src/gateway/server.js +3 -0
  166. package/dist/src/gateway/server.js.map +1 -1
  167. package/dist/src/gateway/service.d.ts +23 -0
  168. package/dist/src/gateway/service.js +111 -4
  169. package/dist/src/gateway/service.js.map +1 -1
  170. package/dist/src/gateway/workspace-heartbeat-path.js +1 -1
  171. package/dist/src/infra/update-check.js +54 -21
  172. package/dist/src/infra/update-check.js.map +1 -1
  173. package/dist/src/infra/update-lock.d.ts +13 -0
  174. package/dist/src/infra/update-lock.js +67 -0
  175. package/dist/src/infra/update-lock.js.map +1 -0
  176. package/dist/src/infra/update-runner.d.ts +6 -5
  177. package/dist/src/infra/update-runner.js +93 -13
  178. package/dist/src/infra/update-runner.js.map +1 -1
  179. package/dist/src/infra/update-startup.js +37 -11
  180. package/dist/src/infra/update-startup.js.map +1 -1
  181. package/dist/src/providers/index.js +2 -2
  182. package/dist/src/providers/model-registry.js +1 -1
  183. package/dist/src/session/config-store.js +1 -1
  184. package/dist/src/session/session-title.js +1 -1
  185. package/dist/src/session/store.js +3 -3
  186. package/dist/src/utils/logger/audit.js +1 -1
  187. package/dist/src/utils/logger/log-store.js +1 -1
  188. package/dist/src/utils/logger/rotation.js +1 -1
  189. package/dist/src/voice/tts/audio.js +1 -1
  190. package/package.json +1 -1
  191. package/dist/gateway/static/root/assets/channels-settings-DyNnMN1-.js +0 -9
  192. package/dist/gateway/static/root/assets/channels-settings-DyNnMN1-.js.map +0 -1
  193. package/dist/gateway/static/root/assets/index-BQNdJlkw.css +0 -1
  194. package/dist/gateway/static/root/assets/settings-page-CSIVMAJE.js +0 -2
  195. package/dist/gateway/static/root/assets/settings-page-CSIVMAJE.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","names":[],"sources":["../../../../../src/gateway/hono/routes/config.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport { type Config, BindingsConfigSchema } from '../../../config/schema.js';\nimport { CredentialResolver } from '../../../auth/credentials.js';\nimport { applyToolsWebPatch } from '../../config-tools-web.js';\nimport { buildSafeWebConfigPayload } from '../lib/config-payload.js';\nimport { normalizePatchAgentModel } from '../lib/agent-model.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nexport function registerConfigRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service, strictRateLimitMiddleware } = deps;\n\n authenticated.post('/api/config/reload', strictRateLimitMiddleware, async (c) => {\n const result = await service.reloadConfig();\n return c.json({ ok: true, payload: result });\n });\n\n authenticated.post('/api/heartbeat/trigger', strictRateLimitMiddleware, async (c) => {\n let reason = 'manual';\n try {\n const body = await c.req.json();\n if (body && typeof body === 'object' && typeof (body as { reason?: unknown }).reason === 'string') {\n const r = (body as { reason: string }).reason.trim();\n if (r) reason = r.slice(0, 120);\n }\n } catch {\n /* empty or invalid body */\n }\n service.requestHeartbeatNow({ reason });\n return c.json({ ok: true, payload: { scheduled: true } });\n });\n\n authenticated.get('/api/config', async (c) => {\n const safeConfig = await buildSafeWebConfigPayload(service);\n return c.json({ ok: true, payload: { config: safeConfig } });\n });\n\n authenticated.patch('/api/config', strictRateLimitMiddleware, async (c) => {\n const body = await c.req.json();\n \n // Merge updates into current config\n const config: Config = service.currentConfig as Config;\n \n // Update agent defaults\n if (body.agents?.defaults) {\n if (!config.agents) config.agents = { defaults: { workspace: '~/.xopc/workspace', model: 'anthropic/claude-sonnet-4-5', maxTokens: 8192, temperature: 0.7, maxToolIterations: 20, maxRequestsPerTurn: 50, maxToolFailuresPerTurn: 3, thinkingDefault: 'medium', reasoningDefault: 'off', verboseDefault: 'off' } };\n if (!config.agents.defaults) config.agents.defaults = {} as any;\n \n if (body.agents.defaults.model !== undefined) {\n config.agents.defaults.model = normalizePatchAgentModel(body.agents.defaults.model) as Config['agents']['defaults']['model'];\n }\n if (body.agents.defaults.maxTokens !== undefined) {\n config.agents.defaults.maxTokens = body.agents.defaults.maxTokens;\n }\n if (body.agents.defaults.temperature !== undefined) {\n config.agents.defaults.temperature = body.agents.defaults.temperature;\n }\n if (body.agents.defaults.maxToolIterations !== undefined) {\n config.agents.defaults.maxToolIterations = body.agents.defaults.maxToolIterations;\n }\n if (body.agents.defaults.workspace !== undefined) {\n config.agents.defaults.workspace = body.agents.defaults.workspace;\n }\n if (body.agents.defaults.thinkingDefault !== undefined) {\n config.agents.defaults.thinkingDefault = body.agents.defaults.thinkingDefault;\n }\n if (body.agents.defaults.reasoningDefault !== undefined) {\n config.agents.defaults.reasoningDefault = body.agents.defaults.reasoningDefault;\n }\n if (body.agents.defaults.verboseDefault !== undefined) {\n config.agents.defaults.verboseDefault = body.agents.defaults.verboseDefault;\n }\n if (body.agents.defaults.imageModel !== undefined) {\n const v = body.agents.defaults.imageModel;\n if (v === '' || v === null) {\n delete (config.agents.defaults as Record<string, unknown>).imageModel;\n } else {\n config.agents.defaults.imageModel = normalizePatchAgentModel(v) as Config['agents']['defaults']['imageModel'];\n }\n }\n if (body.agents.defaults.imageGenerationModel !== undefined) {\n const v = body.agents.defaults.imageGenerationModel;\n if (v === '' || v === null) {\n delete (config.agents.defaults as Record<string, unknown>).imageGenerationModel;\n } else {\n config.agents.defaults.imageGenerationModel = normalizePatchAgentModel(\n v,\n ) as Config['agents']['defaults']['imageGenerationModel'];\n }\n }\n if (body.agents.defaults.mediaMaxMb !== undefined) {\n const v = body.agents.defaults.mediaMaxMb;\n if (v === null) {\n delete (config.agents.defaults as Record<string, unknown>).mediaMaxMb;\n } else {\n const n = typeof v === 'number' ? v : Number(v);\n if (!Number.isNaN(n) && n > 0) {\n config.agents.defaults.mediaMaxMb = n;\n }\n }\n }\n if (body.agents.defaults.browser !== undefined) {\n const b = body.agents.defaults.browser;\n if (b === null) {\n delete (config.agents.defaults as Record<string, unknown>).browser;\n } else if (typeof b === 'object' && !Array.isArray(b)) {\n const br = b as Record<string, unknown>;\n if (!config.agents.defaults.browser) {\n config.agents.defaults.browser = { enabled: false, headless: true };\n }\n const target = config.agents.defaults.browser;\n if (br.enabled !== undefined) {\n target.enabled = Boolean(br.enabled);\n }\n if (br.headless !== undefined) {\n target.headless = Boolean(br.headless);\n }\n }\n }\n\n const dPatch = body.agents.defaults as Record<string, unknown>;\n const def = config.agents.defaults as Record<string, unknown>;\n\n if (dPatch.maxTaskDurationMs !== undefined) {\n const v = dPatch.maxTaskDurationMs;\n if (v === null) {\n delete def.maxTaskDurationMs;\n } else if (typeof v === 'number' && Number.isFinite(v)) {\n const ms = Math.floor(v);\n if (ms >= 60_000 && ms <= 14_400_000) {\n def.maxTaskDurationMs = ms;\n }\n }\n }\n if (dPatch.maxRequestsPerTurn !== undefined) {\n const v = dPatch.maxRequestsPerTurn;\n if (v === null) {\n delete def.maxRequestsPerTurn;\n } else if (typeof v === 'number' && Number.isFinite(v)) {\n const n = Math.floor(v);\n if (n >= 10 && n <= 200) {\n def.maxRequestsPerTurn = n;\n }\n }\n }\n if (dPatch.maxToolFailuresPerTurn !== undefined) {\n const v = dPatch.maxToolFailuresPerTurn;\n if (v === null) {\n delete def.maxToolFailuresPerTurn;\n } else if (typeof v === 'number' && Number.isFinite(v)) {\n const n = Math.floor(v);\n if (n >= 1 && n <= 20) {\n def.maxToolFailuresPerTurn = n;\n }\n }\n }\n\n if (dPatch.compaction !== undefined) {\n const c = dPatch.compaction;\n if (c === null) {\n delete def.compaction;\n } else if (typeof c === 'object' && !Array.isArray(c)) {\n const p = c as Record<string, unknown>;\n if (!def.compaction || typeof def.compaction !== 'object') {\n def.compaction = {};\n }\n const t = def.compaction as Record<string, unknown>;\n if (p.enabled !== undefined) t.enabled = Boolean(p.enabled);\n if (p.mode === 'default' || p.mode === 'safeguard') t.mode = p.mode;\n if (typeof p.reserveTokens === 'number' && Number.isFinite(p.reserveTokens)) {\n t.reserveTokens = Math.floor(p.reserveTokens);\n }\n if (typeof p.triggerThreshold === 'number' && Number.isFinite(p.triggerThreshold)) {\n const x = p.triggerThreshold;\n if (x >= 0.5 && x <= 0.95) t.triggerThreshold = x;\n }\n if (typeof p.minMessagesBeforeCompact === 'number' && Number.isFinite(p.minMessagesBeforeCompact)) {\n t.minMessagesBeforeCompact = Math.floor(p.minMessagesBeforeCompact);\n }\n if (typeof p.keepRecentMessages === 'number' && Number.isFinite(p.keepRecentMessages)) {\n t.keepRecentMessages = Math.floor(p.keepRecentMessages);\n }\n if (typeof p.evictionWindow === 'number' && Number.isFinite(p.evictionWindow)) {\n const x = p.evictionWindow;\n if (x >= 0.1 && x <= 0.5) t.evictionWindow = x;\n }\n if (typeof p.retentionWindow === 'number' && Number.isFinite(p.retentionWindow)) {\n const n = Math.floor(p.retentionWindow);\n if (n >= 3 && n <= 20) t.retentionWindow = n;\n }\n }\n }\n\n if (dPatch.pruning !== undefined) {\n const c = dPatch.pruning;\n if (c === null) {\n delete def.pruning;\n } else if (typeof c === 'object' && !Array.isArray(c)) {\n const p = c as Record<string, unknown>;\n if (!def.pruning || typeof def.pruning !== 'object') {\n def.pruning = {};\n }\n const t = def.pruning as Record<string, unknown>;\n if (p.enabled !== undefined) t.enabled = Boolean(p.enabled);\n if (typeof p.maxToolResultChars === 'number' && Number.isFinite(p.maxToolResultChars)) {\n t.maxToolResultChars = Math.floor(p.maxToolResultChars);\n }\n if (typeof p.headKeepRatio === 'number' && Number.isFinite(p.headKeepRatio)) {\n t.headKeepRatio = p.headKeepRatio;\n }\n if (typeof p.tailKeepRatio === 'number' && Number.isFinite(p.tailKeepRatio)) {\n t.tailKeepRatio = p.tailKeepRatio;\n }\n }\n }\n\n if (dPatch.memory !== undefined) {\n const c = dPatch.memory;\n if (c === null) {\n delete def.memory;\n } else if (typeof c === 'object' && !Array.isArray(c)) {\n const p = c as Record<string, unknown>;\n if (!def.memory || typeof def.memory !== 'object') {\n def.memory = {};\n }\n const t = def.memory as Record<string, unknown>;\n if (p.enabled !== undefined) {\n if (p.enabled === null) delete t.enabled;\n else t.enabled = Boolean(p.enabled);\n }\n if (p.useEnhancedSystem !== undefined) {\n if (p.useEnhancedSystem === null) delete t.useEnhancedSystem;\n else t.useEnhancedSystem = Boolean(p.useEnhancedSystem);\n }\n if (p.userProfileEnabled !== undefined) {\n if (p.userProfileEnabled === null) delete t.userProfileEnabled;\n else t.userProfileEnabled = Boolean(p.userProfileEnabled);\n }\n if (p.memoryCharLimit !== undefined) {\n if (p.memoryCharLimit === null) delete t.memoryCharLimit;\n else if (typeof p.memoryCharLimit === 'number' && p.memoryCharLimit > 0) {\n t.memoryCharLimit = Math.floor(p.memoryCharLimit);\n }\n }\n if (p.userCharLimit !== undefined) {\n if (p.userCharLimit === null) delete t.userCharLimit;\n else if (typeof p.userCharLimit === 'number' && p.userCharLimit > 0) {\n t.userCharLimit = Math.floor(p.userCharLimit);\n }\n }\n if (p.provider === 'none' || p.provider === 'stub') {\n t.provider = p.provider;\n } else if (p.provider === null) {\n delete t.provider;\n }\n if (p.injectionFrequency === 'every-turn' || p.injectionFrequency === 'first-turn') {\n t.injectionFrequency = p.injectionFrequency;\n } else if (p.injectionFrequency === null) {\n delete t.injectionFrequency;\n }\n if (p.contextCadence !== undefined) {\n if (p.contextCadence === null) delete t.contextCadence;\n else if (typeof p.contextCadence === 'number' && p.contextCadence >= 1) {\n t.contextCadence = Math.floor(p.contextCadence);\n }\n }\n if (p.dialecticCadence !== undefined) {\n if (p.dialecticCadence === null) delete t.dialecticCadence;\n else if (typeof p.dialecticCadence === 'number' && p.dialecticCadence >= 1) {\n t.dialecticCadence = Math.floor(p.dialecticCadence);\n }\n }\n }\n }\n\n if (dPatch.sessionSearch !== undefined) {\n const c = dPatch.sessionSearch;\n if (c === null) {\n delete def.sessionSearch;\n } else if (typeof c === 'object' && !Array.isArray(c)) {\n const p = c as Record<string, unknown>;\n if (!def.sessionSearch || typeof def.sessionSearch !== 'object') {\n def.sessionSearch = {};\n }\n const t = def.sessionSearch as Record<string, unknown>;\n if (p.summaryModel !== undefined) {\n if (p.summaryModel === null || p.summaryModel === '') {\n delete t.summaryModel;\n } else if (typeof p.summaryModel === 'string') {\n t.summaryModel = p.summaryModel;\n }\n }\n }\n }\n\n if (dPatch.backgroundReview !== undefined) {\n const c = dPatch.backgroundReview;\n if (c === null) {\n delete def.backgroundReview;\n } else if (typeof c === 'object' && !Array.isArray(c)) {\n const p = c as Record<string, unknown>;\n if (!def.backgroundReview || typeof def.backgroundReview !== 'object') {\n def.backgroundReview = {};\n }\n const t = def.backgroundReview as Record<string, unknown>;\n if (p.enabled !== undefined) {\n if (p.enabled === null) delete t.enabled;\n else t.enabled = Boolean(p.enabled);\n }\n if (p.memoryNudgeInterval !== undefined) {\n if (p.memoryNudgeInterval === null) delete t.memoryNudgeInterval;\n else if (typeof p.memoryNudgeInterval === 'number' && p.memoryNudgeInterval >= 0) {\n t.memoryNudgeInterval = Math.floor(p.memoryNudgeInterval);\n }\n }\n if (p.skillNudgeInterval !== undefined) {\n if (p.skillNudgeInterval === null) delete t.skillNudgeInterval;\n else if (typeof p.skillNudgeInterval === 'number' && p.skillNudgeInterval >= 0) {\n t.skillNudgeInterval = Math.floor(p.skillNudgeInterval);\n }\n }\n if (p.maxToolRounds !== undefined) {\n if (p.maxToolRounds === null) delete t.maxToolRounds;\n else if (typeof p.maxToolRounds === 'number' && p.maxToolRounds >= 1 && p.maxToolRounds <= 32) {\n t.maxToolRounds = Math.floor(p.maxToolRounds);\n }\n }\n if (p.maxHistoryMessages !== undefined) {\n if (p.maxHistoryMessages === null) delete t.maxHistoryMessages;\n else if (typeof p.maxHistoryMessages === 'number' && p.maxHistoryMessages >= 10 && p.maxHistoryMessages <= 200) {\n t.maxHistoryMessages = Math.floor(p.maxHistoryMessages);\n }\n }\n if (p.maxDurationMs !== undefined) {\n if (p.maxDurationMs === null) delete t.maxDurationMs;\n else if (typeof p.maxDurationMs === 'number' && p.maxDurationMs >= 30_000 && p.maxDurationMs <= 600_000) {\n t.maxDurationMs = Math.floor(p.maxDurationMs);\n }\n }\n }\n }\n\n if (dPatch.webExtract !== undefined) {\n const c = dPatch.webExtract;\n if (c === null) {\n delete def.webExtract;\n } else if (typeof c === 'object' && !Array.isArray(c)) {\n const p = c as Record<string, unknown>;\n if (!def.webExtract || typeof def.webExtract !== 'object') {\n def.webExtract = {};\n }\n const t = def.webExtract as Record<string, unknown>;\n if (p.model !== undefined) {\n if (p.model === null || p.model === '') {\n delete t.model;\n } else if (typeof p.model === 'string') {\n t.model = p.model;\n }\n }\n if (p.maxLength !== undefined) {\n if (p.maxLength === null) delete t.maxLength;\n else if (typeof p.maxLength === 'number' && p.maxLength > 0) {\n t.maxLength = p.maxLength;\n }\n }\n }\n }\n\n if (dPatch.delegate !== undefined) {\n const c = dPatch.delegate;\n if (c === null) {\n delete def.delegate;\n } else if (typeof c === 'object' && !Array.isArray(c)) {\n const p = c as Record<string, unknown>;\n if (!def.delegate || typeof def.delegate !== 'object') {\n def.delegate = {};\n }\n const t = def.delegate as Record<string, unknown>;\n if (p.enabled !== undefined) {\n if (p.enabled === null) delete t.enabled;\n else t.enabled = Boolean(p.enabled);\n }\n }\n }\n\n if (dPatch.executeCode !== undefined) {\n const c = dPatch.executeCode;\n if (c === null) {\n delete def.executeCode;\n } else if (typeof c === 'object' && !Array.isArray(c)) {\n const p = c as Record<string, unknown>;\n if (!def.executeCode || typeof def.executeCode !== 'object') {\n def.executeCode = {};\n }\n const t = def.executeCode as Record<string, unknown>;\n if (p.enabled !== undefined) {\n if (p.enabled === null) delete t.enabled;\n else t.enabled = Boolean(p.enabled);\n }\n }\n }\n\n if (dPatch.systemPromptOverride !== undefined) {\n const v = dPatch.systemPromptOverride;\n if (v === null || v === '') {\n delete def.systemPromptOverride;\n } else if (typeof v === 'string') {\n def.systemPromptOverride = v;\n }\n }\n\n if (dPatch.skills !== undefined) {\n const v = dPatch.skills;\n if (v === null) {\n delete def.skills;\n } else if (Array.isArray(v) && v.every((x) => typeof x === 'string')) {\n def.skills = v;\n }\n }\n\n if (dPatch.tools !== undefined) {\n const t0 = dPatch.tools;\n if (t0 === null) {\n delete def.tools;\n } else if (typeof t0 === 'object' && !Array.isArray(t0)) {\n const p = t0 as { disable?: unknown };\n if (!def.tools || typeof def.tools !== 'object') {\n def.tools = {};\n }\n const t = def.tools as { disable?: string[] };\n if (p.disable !== undefined) {\n if (p.disable === null || (Array.isArray(p.disable) && p.disable.length === 0)) {\n delete t.disable;\n } else if (Array.isArray(p.disable) && p.disable.every((x) => typeof x === 'string')) {\n t.disable = p.disable;\n }\n }\n }\n }\n\n if (dPatch.params !== undefined) {\n const v = dPatch.params;\n if (v === null) {\n delete def.params;\n } else if (typeof v === 'object' && !Array.isArray(v) && v !== null) {\n def.params = v as Record<string, unknown>;\n }\n }\n }\n \n // Update channels — use `in` / null so `weixin: null` removes the block; avoid `if (ch.weixin)` missing null.\n const patchChannels = body.channels;\n if (patchChannels != null && typeof patchChannels === 'object' && !Array.isArray(patchChannels)) {\n if ('telegram' in patchChannels) {\n const tgRaw = patchChannels.telegram;\n if (tgRaw === null) {\n if (config.channels) delete config.channels.telegram;\n } else if (typeof tgRaw === 'object' && !Array.isArray(tgRaw)) {\n const bodyTg = tgRaw as Record<string, unknown>;\n if (!config.channels) config.channels = { telegram: { enabled: false, botToken: '', allowFrom: [], groupAllowFrom: [], debug: false, dmPolicy: 'pairing' as const, groupPolicy: 'open' as const, replyToMode: 'off' as const, historyLimit: 50, textChunkLimit: 4000 } };\n if (!config.channels.telegram) config.channels.telegram = {} as any;\n const tg = config.channels.telegram as Record<string, unknown>;\n\n if (bodyTg.enabled !== undefined) {\n tg.enabled = bodyTg.enabled;\n }\n if (bodyTg.botToken !== undefined) {\n tg.botToken = bodyTg.botToken;\n }\n if (bodyTg.allowFrom !== undefined) {\n tg.allowFrom = bodyTg.allowFrom;\n }\n if (bodyTg.apiRoot !== undefined) {\n tg.apiRoot = bodyTg.apiRoot;\n }\n if (bodyTg.debug !== undefined) {\n tg.debug = bodyTg.debug;\n }\n if (bodyTg.streamMode !== undefined) {\n tg.streamMode = bodyTg.streamMode;\n }\n if (bodyTg.groupAllowFrom !== undefined) {\n tg.groupAllowFrom = bodyTg.groupAllowFrom;\n }\n if (bodyTg.dmPolicy !== undefined) {\n tg.dmPolicy = bodyTg.dmPolicy;\n }\n if (bodyTg.groupPolicy !== undefined) {\n tg.groupPolicy = bodyTg.groupPolicy;\n }\n if (bodyTg.replyToMode !== undefined) {\n tg.replyToMode = bodyTg.replyToMode;\n }\n if (bodyTg.historyLimit !== undefined) {\n tg.historyLimit = bodyTg.historyLimit;\n }\n if (bodyTg.textChunkLimit !== undefined) {\n tg.textChunkLimit = bodyTg.textChunkLimit;\n }\n if (bodyTg.proxy !== undefined) {\n tg.proxy = bodyTg.proxy;\n }\n if (bodyTg.accounts !== undefined) {\n tg.accounts = bodyTg.accounts;\n }\n }\n }\n\n if ('weixin' in patchChannels) {\n const wxRaw = patchChannels.weixin;\n if (wxRaw === null) {\n if (config.channels) delete config.channels.weixin;\n } else if (typeof wxRaw === 'object' && !Array.isArray(wxRaw)) {\n const wx = wxRaw as Record<string, unknown>;\n if (!config.channels) config.channels = {} as any;\n if (!config.channels.weixin) {\n config.channels.weixin = {\n enabled: false,\n dmPolicy: 'pairing',\n allowFrom: [],\n debug: false,\n historyLimit: 50,\n textChunkLimit: 4000,\n };\n }\n const wxTarget = config.channels.weixin as Record<string, unknown>;\n if (wx.enabled !== undefined) wxTarget.enabled = wx.enabled;\n if (wx.dmPolicy !== undefined) wxTarget.dmPolicy = wx.dmPolicy;\n if (wx.allowFrom !== undefined) wxTarget.allowFrom = wx.allowFrom;\n if (wx.debug !== undefined) wxTarget.debug = wx.debug;\n if (wx.streamMode !== undefined) wxTarget.streamMode = wx.streamMode;\n if (wx.historyLimit !== undefined) wxTarget.historyLimit = wx.historyLimit;\n if (wx.textChunkLimit !== undefined) wxTarget.textChunkLimit = wx.textChunkLimit;\n if ('routeTag' in wx) {\n const rt = wx.routeTag;\n if (rt === null || rt === undefined || rt === '') {\n delete wxTarget.routeTag;\n } else {\n wxTarget.routeTag = rt as string | number;\n }\n }\n if (wx.accounts !== undefined) wxTarget.accounts = wx.accounts;\n }\n }\n }\n \n // Update gateway heartbeat (partial merge)\n if (body.gateway?.heartbeat !== undefined && typeof body.gateway.heartbeat === 'object') {\n if (!config.gateway) {\n config.gateway = {\n host: '0.0.0.0',\n port: 18790,\n heartbeat: { enabled: true, intervalMs: 1_800_000, includeSystemPromptSection: false },\n maxSseConnections: 100,\n corsOrigins: ['*'],\n };\n }\n if (!config.gateway.heartbeat) {\n config.gateway.heartbeat = { enabled: true, intervalMs: 1_800_000, includeSystemPromptSection: false };\n }\n const h = config.gateway.heartbeat;\n const p = body.gateway.heartbeat as Record<string, unknown>;\n if (p.enabled !== undefined) h.enabled = Boolean(p.enabled);\n if (p.intervalMs !== undefined && typeof p.intervalMs === 'number' && Number.isFinite(p.intervalMs)) {\n h.intervalMs = p.intervalMs;\n }\n if (p.includeSystemPromptSection !== undefined) {\n h.includeSystemPromptSection = Boolean(p.includeSystemPromptSection);\n }\n if (p.target !== undefined) {\n if (p.target === null || p.target === '') delete (h as { target?: string }).target;\n else (h as { target?: string }).target = String(p.target);\n }\n if (p.targetChatId !== undefined) {\n if (p.targetChatId === null || p.targetChatId === '') delete (h as { targetChatId?: string }).targetChatId;\n else (h as { targetChatId?: string }).targetChatId = String(p.targetChatId);\n }\n if (p.prompt !== undefined) {\n if (p.prompt === null || p.prompt === '') delete (h as { prompt?: string }).prompt;\n else (h as { prompt?: string }).prompt = String(p.prompt);\n }\n if (p.ackMaxChars !== undefined) {\n if (p.ackMaxChars === null || p.ackMaxChars === '') delete (h as { ackMaxChars?: number }).ackMaxChars;\n else if (typeof p.ackMaxChars === 'number' && Number.isFinite(p.ackMaxChars)) {\n (h as { ackMaxChars?: number }).ackMaxChars = p.ackMaxChars;\n }\n }\n if (p.isolatedSession !== undefined) {\n if (p.isolatedSession === null || p.isolatedSession === false) {\n delete (h as { isolatedSession?: boolean }).isolatedSession;\n } else {\n (h as { isolatedSession?: boolean }).isolatedSession = Boolean(p.isolatedSession);\n }\n }\n if (p.activeHours !== undefined) {\n if (p.activeHours === null) {\n delete (h as { activeHours?: unknown }).activeHours;\n } else if (typeof p.activeHours === 'object' && p.activeHours !== null) {\n const ah = p.activeHours as Record<string, unknown>;\n const start = typeof ah.start === 'string' ? ah.start : '';\n const end = typeof ah.end === 'string' ? ah.end : '';\n if (start && end) {\n (h as { activeHours?: { start: string; end: string; timezone?: string } }).activeHours = {\n start,\n end,\n ...(typeof ah.timezone === 'string' && ah.timezone.trim() ? { timezone: ah.timezone } : {}),\n };\n } else {\n delete (h as { activeHours?: unknown }).activeHours;\n }\n }\n }\n }\n if (body.gateway?.auth !== undefined) {\n if (!config.gateway) {\n config.gateway = {\n host: '0.0.0.0',\n port: 18790,\n heartbeat: { enabled: true, intervalMs: 1_800_000, includeSystemPromptSection: false },\n maxSseConnections: 100,\n corsOrigins: ['*'],\n };\n }\n if (!config.gateway.auth) config.gateway.auth = { mode: 'token' };\n const a = body.gateway.auth;\n if (a.mode !== undefined) {\n config.gateway.auth.mode = a.mode;\n }\n if (a.token !== undefined) {\n config.gateway.auth.token = a.token;\n }\n }\n\n // Update providers config - save to credential system instead of config\n if (body.providers) {\n const resolver = new CredentialResolver();\n for (const [key, apiKey] of Object.entries(body.providers)) {\n if (\n apiKey !== undefined &&\n typeof apiKey === 'string' &&\n apiKey.trim() &&\n apiKey !== '***' &&\n apiKey !== '••••••••••••'\n ) {\n await resolver.saveApiKey(key, apiKey, { profileName: 'default' });\n }\n }\n }\n\n // Update STT config\n if (body.stt !== undefined) {\n config.stt = body.stt;\n }\n\n // Update TTS config\n if (body.tts !== undefined) {\n config.tts = body.tts;\n }\n\n const toolsPatchErr = applyToolsWebPatch(config, body as Record<string, unknown>);\n if (toolsPatchErr) {\n return c.json({ ok: false, error: { message: toolsPatchErr } }, 400);\n }\n\n if (body.bindings !== undefined) {\n if (!Array.isArray(body.bindings)) {\n return c.json({ ok: false, error: { message: 'bindings must be an array' } }, 400);\n }\n const parsed = BindingsConfigSchema.safeParse(body.bindings);\n if (!parsed.success) {\n return c.json(\n { ok: false, error: { message: parsed.error.issues.map((i) => i.message).join('; ') } },\n 400,\n );\n }\n config.bindings = parsed.data;\n }\n\n // Save config\n const result = await service.saveConfig(config);\n if (!result.saved) {\n return c.json({ ok: false, error: result.error }, 500);\n }\n\n if (body.gateway?.heartbeat !== undefined && typeof body.gateway.heartbeat === 'object') {\n service.reloadHeartbeatFromCurrentConfig();\n }\n\n const safeConfig = await buildSafeWebConfigPayload(service);\n return c.json({ ok: true, payload: { config: safeConfig } });\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"config.js","names":[],"sources":["../../../../../src/gateway/hono/routes/config.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport { type Config, BindingsConfigSchema } from '../../../config/schema.js';\nimport { CredentialResolver } from '../../../auth/credentials.js';\nimport { applyToolsWebPatch } from '../../config-tools-web.js';\nimport { buildSafeWebConfigPayload } from '../lib/config-payload.js';\nimport { normalizePatchAgentModel } from '../lib/agent-model.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nexport function registerConfigRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service, strictRateLimitMiddleware } = deps;\n\n authenticated.post('/api/config/reload', strictRateLimitMiddleware, async (c) => {\n const result = await service.reloadConfig();\n return c.json({ ok: true, payload: result });\n });\n\n authenticated.post('/api/heartbeat/trigger', strictRateLimitMiddleware, async (c) => {\n let reason = 'manual';\n try {\n const body = await c.req.json();\n if (body && typeof body === 'object' && typeof (body as { reason?: unknown }).reason === 'string') {\n const r = (body as { reason: string }).reason.trim();\n if (r) reason = r.slice(0, 120);\n }\n } catch {\n /* empty or invalid body */\n }\n service.requestHeartbeatNow({ reason });\n return c.json({ ok: true, payload: { scheduled: true } });\n });\n\n authenticated.get('/api/config', async (c) => {\n const safeConfig = await buildSafeWebConfigPayload(service);\n return c.json({ ok: true, payload: { config: safeConfig } });\n });\n\n authenticated.patch('/api/config', strictRateLimitMiddleware, async (c) => {\n const body = await c.req.json();\n \n // Merge updates into current config\n const config: Config = service.currentConfig as Config;\n \n // Update agent defaults\n if (body.agents?.defaults) {\n if (!config.agents) config.agents = { defaults: { workspace: '~/.xopc/workspace', model: 'anthropic/claude-sonnet-4-5', maxTokens: 8192, temperature: 0.7, maxToolIterations: 20, maxRequestsPerTurn: 50, maxToolFailuresPerTurn: 3, thinkingDefault: 'medium', reasoningDefault: 'off', verboseDefault: 'off' } };\n if (!config.agents.defaults) config.agents.defaults = {} as any;\n \n if (body.agents.defaults.model !== undefined) {\n config.agents.defaults.model = normalizePatchAgentModel(body.agents.defaults.model) as Config['agents']['defaults']['model'];\n }\n if (body.agents.defaults.maxTokens !== undefined) {\n config.agents.defaults.maxTokens = body.agents.defaults.maxTokens;\n }\n if (body.agents.defaults.temperature !== undefined) {\n config.agents.defaults.temperature = body.agents.defaults.temperature;\n }\n if (body.agents.defaults.maxToolIterations !== undefined) {\n config.agents.defaults.maxToolIterations = body.agents.defaults.maxToolIterations;\n }\n if (body.agents.defaults.workspace !== undefined) {\n config.agents.defaults.workspace = body.agents.defaults.workspace;\n }\n if (body.agents.defaults.thinkingDefault !== undefined) {\n config.agents.defaults.thinkingDefault = body.agents.defaults.thinkingDefault;\n }\n if (body.agents.defaults.reasoningDefault !== undefined) {\n config.agents.defaults.reasoningDefault = body.agents.defaults.reasoningDefault;\n }\n if (body.agents.defaults.verboseDefault !== undefined) {\n config.agents.defaults.verboseDefault = body.agents.defaults.verboseDefault;\n }\n if (body.agents.defaults.imageModel !== undefined) {\n const v = body.agents.defaults.imageModel;\n if (v === '' || v === null) {\n delete (config.agents.defaults as Record<string, unknown>).imageModel;\n } else {\n config.agents.defaults.imageModel = normalizePatchAgentModel(v) as Config['agents']['defaults']['imageModel'];\n }\n }\n if (body.agents.defaults.imageGenerationModel !== undefined) {\n const v = body.agents.defaults.imageGenerationModel;\n if (v === '' || v === null) {\n delete (config.agents.defaults as Record<string, unknown>).imageGenerationModel;\n } else {\n config.agents.defaults.imageGenerationModel = normalizePatchAgentModel(\n v,\n ) as Config['agents']['defaults']['imageGenerationModel'];\n }\n }\n if (body.agents.defaults.mediaMaxMb !== undefined) {\n const v = body.agents.defaults.mediaMaxMb;\n if (v === null) {\n delete (config.agents.defaults as Record<string, unknown>).mediaMaxMb;\n } else {\n const n = typeof v === 'number' ? v : Number(v);\n if (!Number.isNaN(n) && n > 0) {\n config.agents.defaults.mediaMaxMb = n;\n }\n }\n }\n if (body.agents.defaults.browser !== undefined) {\n const b = body.agents.defaults.browser;\n if (b === null) {\n delete (config.agents.defaults as Record<string, unknown>).browser;\n } else if (typeof b === 'object' && !Array.isArray(b)) {\n const br = b as Record<string, unknown>;\n if (!config.agents.defaults.browser) {\n config.agents.defaults.browser = { enabled: false, headless: true };\n }\n const target = config.agents.defaults.browser;\n if (br.enabled !== undefined) {\n target.enabled = Boolean(br.enabled);\n }\n if (br.headless !== undefined) {\n target.headless = Boolean(br.headless);\n }\n }\n }\n\n const dPatch = body.agents.defaults as Record<string, unknown>;\n const def = config.agents.defaults as Record<string, unknown>;\n\n if (dPatch.maxTaskDurationMs !== undefined) {\n const v = dPatch.maxTaskDurationMs;\n if (v === null) {\n delete def.maxTaskDurationMs;\n } else if (typeof v === 'number' && Number.isFinite(v)) {\n const ms = Math.floor(v);\n if (ms >= 60_000 && ms <= 14_400_000) {\n def.maxTaskDurationMs = ms;\n }\n }\n }\n if (dPatch.maxRequestsPerTurn !== undefined) {\n const v = dPatch.maxRequestsPerTurn;\n if (v === null) {\n delete def.maxRequestsPerTurn;\n } else if (typeof v === 'number' && Number.isFinite(v)) {\n const n = Math.floor(v);\n if (n >= 10 && n <= 200) {\n def.maxRequestsPerTurn = n;\n }\n }\n }\n if (dPatch.maxToolFailuresPerTurn !== undefined) {\n const v = dPatch.maxToolFailuresPerTurn;\n if (v === null) {\n delete def.maxToolFailuresPerTurn;\n } else if (typeof v === 'number' && Number.isFinite(v)) {\n const n = Math.floor(v);\n if (n >= 1 && n <= 20) {\n def.maxToolFailuresPerTurn = n;\n }\n }\n }\n\n if (dPatch.compaction !== undefined) {\n const c = dPatch.compaction;\n if (c === null) {\n delete def.compaction;\n } else if (typeof c === 'object' && !Array.isArray(c)) {\n const p = c as Record<string, unknown>;\n if (!def.compaction || typeof def.compaction !== 'object') {\n def.compaction = {};\n }\n const t = def.compaction as Record<string, unknown>;\n if (p.enabled !== undefined) t.enabled = Boolean(p.enabled);\n if (p.mode === 'default' || p.mode === 'safeguard') t.mode = p.mode;\n if (typeof p.reserveTokens === 'number' && Number.isFinite(p.reserveTokens)) {\n t.reserveTokens = Math.floor(p.reserveTokens);\n }\n if (typeof p.triggerThreshold === 'number' && Number.isFinite(p.triggerThreshold)) {\n const x = p.triggerThreshold;\n if (x >= 0.5 && x <= 0.95) t.triggerThreshold = x;\n }\n if (typeof p.minMessagesBeforeCompact === 'number' && Number.isFinite(p.minMessagesBeforeCompact)) {\n t.minMessagesBeforeCompact = Math.floor(p.minMessagesBeforeCompact);\n }\n if (typeof p.keepRecentMessages === 'number' && Number.isFinite(p.keepRecentMessages)) {\n t.keepRecentMessages = Math.floor(p.keepRecentMessages);\n }\n if (typeof p.evictionWindow === 'number' && Number.isFinite(p.evictionWindow)) {\n const x = p.evictionWindow;\n if (x >= 0.1 && x <= 0.5) t.evictionWindow = x;\n }\n if (typeof p.retentionWindow === 'number' && Number.isFinite(p.retentionWindow)) {\n const n = Math.floor(p.retentionWindow);\n if (n >= 3 && n <= 20) t.retentionWindow = n;\n }\n }\n }\n\n if (dPatch.pruning !== undefined) {\n const c = dPatch.pruning;\n if (c === null) {\n delete def.pruning;\n } else if (typeof c === 'object' && !Array.isArray(c)) {\n const p = c as Record<string, unknown>;\n if (!def.pruning || typeof def.pruning !== 'object') {\n def.pruning = {};\n }\n const t = def.pruning as Record<string, unknown>;\n if (p.enabled !== undefined) t.enabled = Boolean(p.enabled);\n if (typeof p.maxToolResultChars === 'number' && Number.isFinite(p.maxToolResultChars)) {\n t.maxToolResultChars = Math.floor(p.maxToolResultChars);\n }\n if (typeof p.headKeepRatio === 'number' && Number.isFinite(p.headKeepRatio)) {\n t.headKeepRatio = p.headKeepRatio;\n }\n if (typeof p.tailKeepRatio === 'number' && Number.isFinite(p.tailKeepRatio)) {\n t.tailKeepRatio = p.tailKeepRatio;\n }\n }\n }\n\n if (dPatch.memory !== undefined) {\n const c = dPatch.memory;\n if (c === null) {\n delete def.memory;\n } else if (typeof c === 'object' && !Array.isArray(c)) {\n const p = c as Record<string, unknown>;\n if (!def.memory || typeof def.memory !== 'object') {\n def.memory = {};\n }\n const t = def.memory as Record<string, unknown>;\n if (p.enabled !== undefined) {\n if (p.enabled === null) delete t.enabled;\n else t.enabled = Boolean(p.enabled);\n }\n if (p.useEnhancedSystem !== undefined) {\n if (p.useEnhancedSystem === null) delete t.useEnhancedSystem;\n else t.useEnhancedSystem = Boolean(p.useEnhancedSystem);\n }\n if (p.userProfileEnabled !== undefined) {\n if (p.userProfileEnabled === null) delete t.userProfileEnabled;\n else t.userProfileEnabled = Boolean(p.userProfileEnabled);\n }\n if (p.memoryCharLimit !== undefined) {\n if (p.memoryCharLimit === null) delete t.memoryCharLimit;\n else if (typeof p.memoryCharLimit === 'number' && p.memoryCharLimit > 0) {\n t.memoryCharLimit = Math.floor(p.memoryCharLimit);\n }\n }\n if (p.userCharLimit !== undefined) {\n if (p.userCharLimit === null) delete t.userCharLimit;\n else if (typeof p.userCharLimit === 'number' && p.userCharLimit > 0) {\n t.userCharLimit = Math.floor(p.userCharLimit);\n }\n }\n if (p.provider === 'none' || p.provider === 'stub') {\n t.provider = p.provider;\n } else if (p.provider === null) {\n delete t.provider;\n }\n if (p.injectionFrequency === 'every-turn' || p.injectionFrequency === 'first-turn') {\n t.injectionFrequency = p.injectionFrequency;\n } else if (p.injectionFrequency === null) {\n delete t.injectionFrequency;\n }\n if (p.contextCadence !== undefined) {\n if (p.contextCadence === null) delete t.contextCadence;\n else if (typeof p.contextCadence === 'number' && p.contextCadence >= 1) {\n t.contextCadence = Math.floor(p.contextCadence);\n }\n }\n if (p.dialecticCadence !== undefined) {\n if (p.dialecticCadence === null) delete t.dialecticCadence;\n else if (typeof p.dialecticCadence === 'number' && p.dialecticCadence >= 1) {\n t.dialecticCadence = Math.floor(p.dialecticCadence);\n }\n }\n }\n }\n\n if (dPatch.sessionSearch !== undefined) {\n const c = dPatch.sessionSearch;\n if (c === null) {\n delete def.sessionSearch;\n } else if (typeof c === 'object' && !Array.isArray(c)) {\n const p = c as Record<string, unknown>;\n if (!def.sessionSearch || typeof def.sessionSearch !== 'object') {\n def.sessionSearch = {};\n }\n const t = def.sessionSearch as Record<string, unknown>;\n if (p.summaryModel !== undefined) {\n if (p.summaryModel === null || p.summaryModel === '') {\n delete t.summaryModel;\n } else if (typeof p.summaryModel === 'string') {\n t.summaryModel = p.summaryModel;\n }\n }\n }\n }\n\n if (dPatch.backgroundReview !== undefined) {\n const c = dPatch.backgroundReview;\n if (c === null) {\n delete def.backgroundReview;\n } else if (typeof c === 'object' && !Array.isArray(c)) {\n const p = c as Record<string, unknown>;\n if (!def.backgroundReview || typeof def.backgroundReview !== 'object') {\n def.backgroundReview = {};\n }\n const t = def.backgroundReview as Record<string, unknown>;\n if (p.enabled !== undefined) {\n if (p.enabled === null) delete t.enabled;\n else t.enabled = Boolean(p.enabled);\n }\n if (p.memoryNudgeInterval !== undefined) {\n if (p.memoryNudgeInterval === null) delete t.memoryNudgeInterval;\n else if (typeof p.memoryNudgeInterval === 'number' && p.memoryNudgeInterval >= 0) {\n t.memoryNudgeInterval = Math.floor(p.memoryNudgeInterval);\n }\n }\n if (p.skillNudgeInterval !== undefined) {\n if (p.skillNudgeInterval === null) delete t.skillNudgeInterval;\n else if (typeof p.skillNudgeInterval === 'number' && p.skillNudgeInterval >= 0) {\n t.skillNudgeInterval = Math.floor(p.skillNudgeInterval);\n }\n }\n if (p.maxToolRounds !== undefined) {\n if (p.maxToolRounds === null) delete t.maxToolRounds;\n else if (typeof p.maxToolRounds === 'number' && p.maxToolRounds >= 1 && p.maxToolRounds <= 32) {\n t.maxToolRounds = Math.floor(p.maxToolRounds);\n }\n }\n if (p.maxHistoryMessages !== undefined) {\n if (p.maxHistoryMessages === null) delete t.maxHistoryMessages;\n else if (typeof p.maxHistoryMessages === 'number' && p.maxHistoryMessages >= 10 && p.maxHistoryMessages <= 200) {\n t.maxHistoryMessages = Math.floor(p.maxHistoryMessages);\n }\n }\n if (p.maxDurationMs !== undefined) {\n if (p.maxDurationMs === null) delete t.maxDurationMs;\n else if (typeof p.maxDurationMs === 'number' && p.maxDurationMs >= 30_000 && p.maxDurationMs <= 600_000) {\n t.maxDurationMs = Math.floor(p.maxDurationMs);\n }\n }\n }\n }\n\n if (dPatch.webExtract !== undefined) {\n const c = dPatch.webExtract;\n if (c === null) {\n delete def.webExtract;\n } else if (typeof c === 'object' && !Array.isArray(c)) {\n const p = c as Record<string, unknown>;\n if (!def.webExtract || typeof def.webExtract !== 'object') {\n def.webExtract = {};\n }\n const t = def.webExtract as Record<string, unknown>;\n if (p.model !== undefined) {\n if (p.model === null || p.model === '') {\n delete t.model;\n } else if (typeof p.model === 'string') {\n t.model = p.model;\n }\n }\n if (p.maxLength !== undefined) {\n if (p.maxLength === null) delete t.maxLength;\n else if (typeof p.maxLength === 'number' && p.maxLength > 0) {\n t.maxLength = p.maxLength;\n }\n }\n }\n }\n\n if (dPatch.delegate !== undefined) {\n const c = dPatch.delegate;\n if (c === null) {\n delete def.delegate;\n } else if (typeof c === 'object' && !Array.isArray(c)) {\n const p = c as Record<string, unknown>;\n if (!def.delegate || typeof def.delegate !== 'object') {\n def.delegate = {};\n }\n const t = def.delegate as Record<string, unknown>;\n if (p.enabled !== undefined) {\n if (p.enabled === null) delete t.enabled;\n else t.enabled = Boolean(p.enabled);\n }\n }\n }\n\n if (dPatch.executeCode !== undefined) {\n const c = dPatch.executeCode;\n if (c === null) {\n delete def.executeCode;\n } else if (typeof c === 'object' && !Array.isArray(c)) {\n const p = c as Record<string, unknown>;\n if (!def.executeCode || typeof def.executeCode !== 'object') {\n def.executeCode = {};\n }\n const t = def.executeCode as Record<string, unknown>;\n if (p.enabled !== undefined) {\n if (p.enabled === null) delete t.enabled;\n else t.enabled = Boolean(p.enabled);\n }\n }\n }\n\n if (dPatch.systemPromptOverride !== undefined) {\n const v = dPatch.systemPromptOverride;\n if (v === null || v === '') {\n delete def.systemPromptOverride;\n } else if (typeof v === 'string') {\n def.systemPromptOverride = v;\n }\n }\n\n if (dPatch.skills !== undefined) {\n const v = dPatch.skills;\n if (v === null) {\n delete def.skills;\n } else if (Array.isArray(v) && v.every((x) => typeof x === 'string')) {\n def.skills = v;\n }\n }\n\n if (dPatch.tools !== undefined) {\n const t0 = dPatch.tools;\n if (t0 === null) {\n delete def.tools;\n } else if (typeof t0 === 'object' && !Array.isArray(t0)) {\n const p = t0 as { disable?: unknown };\n if (!def.tools || typeof def.tools !== 'object') {\n def.tools = {};\n }\n const t = def.tools as { disable?: string[] };\n if (p.disable !== undefined) {\n if (p.disable === null || (Array.isArray(p.disable) && p.disable.length === 0)) {\n delete t.disable;\n } else if (Array.isArray(p.disable) && p.disable.every((x) => typeof x === 'string')) {\n t.disable = p.disable;\n }\n }\n }\n }\n\n if (dPatch.params !== undefined) {\n const v = dPatch.params;\n if (v === null) {\n delete def.params;\n } else if (typeof v === 'object' && !Array.isArray(v) && v !== null) {\n def.params = v as Record<string, unknown>;\n }\n }\n }\n \n // Update channels — use `in` / null so `weixin: null` removes the block; avoid `if (ch.weixin)` missing null.\n const patchChannels = body.channels;\n if (patchChannels != null && typeof patchChannels === 'object' && !Array.isArray(patchChannels)) {\n if ('telegram' in patchChannels) {\n const tgRaw = patchChannels.telegram;\n if (tgRaw === null) {\n if (config.channels) delete config.channels.telegram;\n } else if (typeof tgRaw === 'object' && !Array.isArray(tgRaw)) {\n const bodyTg = tgRaw as Record<string, unknown>;\n if (!config.channels) config.channels = { telegram: { enabled: false, botToken: '', allowFrom: [], groupAllowFrom: [], debug: false, dmPolicy: 'pairing' as const, groupPolicy: 'open' as const, replyToMode: 'off' as const, historyLimit: 50, textChunkLimit: 4000 } };\n if (!config.channels.telegram) config.channels.telegram = {} as any;\n const tg = config.channels.telegram as Record<string, unknown>;\n\n if (bodyTg.enabled !== undefined) {\n tg.enabled = bodyTg.enabled;\n }\n if (bodyTg.botToken !== undefined) {\n tg.botToken = bodyTg.botToken;\n }\n if (bodyTg.allowFrom !== undefined) {\n tg.allowFrom = bodyTg.allowFrom;\n }\n if (bodyTg.apiRoot !== undefined) {\n tg.apiRoot = bodyTg.apiRoot;\n }\n if (bodyTg.debug !== undefined) {\n tg.debug = bodyTg.debug;\n }\n if (bodyTg.streamMode !== undefined) {\n tg.streamMode = bodyTg.streamMode;\n }\n if (bodyTg.groupAllowFrom !== undefined) {\n tg.groupAllowFrom = bodyTg.groupAllowFrom;\n }\n if (bodyTg.dmPolicy !== undefined) {\n tg.dmPolicy = bodyTg.dmPolicy;\n }\n if (bodyTg.groupPolicy !== undefined) {\n tg.groupPolicy = bodyTg.groupPolicy;\n }\n if (bodyTg.replyToMode !== undefined) {\n tg.replyToMode = bodyTg.replyToMode;\n }\n if (bodyTg.historyLimit !== undefined) {\n tg.historyLimit = bodyTg.historyLimit;\n }\n if (bodyTg.textChunkLimit !== undefined) {\n tg.textChunkLimit = bodyTg.textChunkLimit;\n }\n if (bodyTg.proxy !== undefined) {\n tg.proxy = bodyTg.proxy;\n }\n if (bodyTg.accounts !== undefined) {\n tg.accounts = bodyTg.accounts;\n }\n }\n }\n\n if ('weixin' in patchChannels) {\n const wxRaw = patchChannels.weixin;\n if (wxRaw === null) {\n if (config.channels) delete config.channels.weixin;\n } else if (typeof wxRaw === 'object' && !Array.isArray(wxRaw)) {\n const wx = wxRaw as Record<string, unknown>;\n if (!config.channels) config.channels = {} as any;\n if (!config.channels.weixin) {\n config.channels.weixin = {\n enabled: false,\n dmPolicy: 'pairing',\n allowFrom: [],\n debug: false,\n historyLimit: 50,\n textChunkLimit: 4000,\n };\n }\n const wxTarget = config.channels.weixin as Record<string, unknown>;\n if (wx.enabled !== undefined) wxTarget.enabled = wx.enabled;\n if (wx.dmPolicy !== undefined) wxTarget.dmPolicy = wx.dmPolicy;\n if (wx.allowFrom !== undefined) wxTarget.allowFrom = wx.allowFrom;\n if (wx.debug !== undefined) wxTarget.debug = wx.debug;\n if (wx.streamMode !== undefined) wxTarget.streamMode = wx.streamMode;\n if (wx.historyLimit !== undefined) wxTarget.historyLimit = wx.historyLimit;\n if (wx.textChunkLimit !== undefined) wxTarget.textChunkLimit = wx.textChunkLimit;\n if ('routeTag' in wx) {\n const rt = wx.routeTag;\n if (rt === null || rt === undefined || rt === '') {\n delete wxTarget.routeTag;\n } else {\n wxTarget.routeTag = rt as string | number;\n }\n }\n if (wx.accounts !== undefined) wxTarget.accounts = wx.accounts;\n }\n }\n\n if ('feishu' in patchChannels) {\n const fsRaw = patchChannels.feishu;\n if (fsRaw === null) {\n if (config.channels) delete config.channels.feishu;\n } else if (typeof fsRaw === 'object' && !Array.isArray(fsRaw)) {\n const fs = fsRaw as Record<string, unknown>;\n if (!config.channels) config.channels = {} as any;\n if (!config.channels.feishu) {\n config.channels.feishu = {\n enabled: false,\n appId: '',\n appSecret: '',\n domain: 'feishu',\n connectionMode: 'websocket',\n dmPolicy: 'pairing',\n groupPolicy: 'allowlist',\n allowFrom: [],\n groupAllowFrom: [],\n requireMention: true,\n historyLimit: 50,\n textChunkLimit: 4000,\n accounts: {},\n };\n }\n const fsTarget = config.channels.feishu as Record<string, unknown>;\n\n if (fs.enabled !== undefined) fsTarget.enabled = fs.enabled;\n if (fs.defaultAccount !== undefined) {\n const da = fs.defaultAccount;\n if (da === null || da === '') delete fsTarget.defaultAccount;\n else fsTarget.defaultAccount = String(da);\n }\n if (fs.appId !== undefined) fsTarget.appId = fs.appId;\n if (fs.appSecret !== undefined) fsTarget.appSecret = fs.appSecret;\n if (fs.domain !== undefined) fsTarget.domain = fs.domain;\n if (fs.connectionMode !== undefined) fsTarget.connectionMode = fs.connectionMode;\n if (fs.verificationToken !== undefined) {\n const v = fs.verificationToken;\n if (v === null || (typeof v === 'string' && !String(v).trim())) delete fsTarget.verificationToken;\n else fsTarget.verificationToken = v;\n }\n if (fs.encryptKey !== undefined) {\n const v = fs.encryptKey;\n if (v === null || (typeof v === 'string' && !String(v).trim())) delete fsTarget.encryptKey;\n else fsTarget.encryptKey = v;\n }\n if (fs.webhookHost !== undefined) {\n const v = fs.webhookHost;\n if (v === null || (typeof v === 'string' && !String(v).trim())) delete fsTarget.webhookHost;\n else fsTarget.webhookHost = v;\n }\n if (fs.webhookPort !== undefined) fsTarget.webhookPort = fs.webhookPort;\n if (fs.webhookPath !== undefined) {\n const v = fs.webhookPath;\n if (v === null || (typeof v === 'string' && !String(v).trim())) delete fsTarget.webhookPath;\n else fsTarget.webhookPath = v;\n }\n if (fs.dmPolicy !== undefined) fsTarget.dmPolicy = fs.dmPolicy;\n if (fs.groupPolicy !== undefined) fsTarget.groupPolicy = fs.groupPolicy;\n if (fs.allowFrom !== undefined) fsTarget.allowFrom = fs.allowFrom;\n if (fs.groupAllowFrom !== undefined) {\n const ga = fs.groupAllowFrom;\n if (ga === null || (Array.isArray(ga) && ga.length === 0)) delete fsTarget.groupAllowFrom;\n else fsTarget.groupAllowFrom = ga;\n }\n if (fs.requireMention !== undefined) fsTarget.requireMention = fs.requireMention;\n if (fs.historyLimit !== undefined) fsTarget.historyLimit = fs.historyLimit;\n if (fs.textChunkLimit !== undefined) fsTarget.textChunkLimit = fs.textChunkLimit;\n if (fs.renderMode !== undefined) fsTarget.renderMode = fs.renderMode;\n if (fs.streaming !== undefined) fsTarget.streaming = fs.streaming;\n if (fs.reactionNotifications !== undefined) {\n fsTarget.reactionNotifications = fs.reactionNotifications;\n }\n if (fs.tools !== undefined) fsTarget.tools = fs.tools;\n if (fs.actions !== undefined) fsTarget.actions = fs.actions;\n if (fs.accounts !== undefined) fsTarget.accounts = fs.accounts;\n }\n }\n }\n \n // Update gateway heartbeat (partial merge)\n if (body.gateway?.heartbeat !== undefined && typeof body.gateway.heartbeat === 'object') {\n if (!config.gateway) {\n config.gateway = {\n host: '0.0.0.0',\n port: 18790,\n heartbeat: { enabled: true, intervalMs: 1_800_000, includeSystemPromptSection: false },\n maxSseConnections: 100,\n corsOrigins: ['*'],\n };\n }\n if (!config.gateway.heartbeat) {\n config.gateway.heartbeat = { enabled: true, intervalMs: 1_800_000, includeSystemPromptSection: false };\n }\n const h = config.gateway.heartbeat;\n const p = body.gateway.heartbeat as Record<string, unknown>;\n if (p.enabled !== undefined) h.enabled = Boolean(p.enabled);\n if (p.intervalMs !== undefined && typeof p.intervalMs === 'number' && Number.isFinite(p.intervalMs)) {\n h.intervalMs = p.intervalMs;\n }\n if (p.includeSystemPromptSection !== undefined) {\n h.includeSystemPromptSection = Boolean(p.includeSystemPromptSection);\n }\n if (p.target !== undefined) {\n if (p.target === null || p.target === '') delete (h as { target?: string }).target;\n else (h as { target?: string }).target = String(p.target);\n }\n if (p.targetChatId !== undefined) {\n if (p.targetChatId === null || p.targetChatId === '') delete (h as { targetChatId?: string }).targetChatId;\n else (h as { targetChatId?: string }).targetChatId = String(p.targetChatId);\n }\n if (p.prompt !== undefined) {\n if (p.prompt === null || p.prompt === '') delete (h as { prompt?: string }).prompt;\n else (h as { prompt?: string }).prompt = String(p.prompt);\n }\n if (p.ackMaxChars !== undefined) {\n if (p.ackMaxChars === null || p.ackMaxChars === '') delete (h as { ackMaxChars?: number }).ackMaxChars;\n else if (typeof p.ackMaxChars === 'number' && Number.isFinite(p.ackMaxChars)) {\n (h as { ackMaxChars?: number }).ackMaxChars = p.ackMaxChars;\n }\n }\n if (p.isolatedSession !== undefined) {\n if (p.isolatedSession === null || p.isolatedSession === false) {\n delete (h as { isolatedSession?: boolean }).isolatedSession;\n } else {\n (h as { isolatedSession?: boolean }).isolatedSession = Boolean(p.isolatedSession);\n }\n }\n if (p.activeHours !== undefined) {\n if (p.activeHours === null) {\n delete (h as { activeHours?: unknown }).activeHours;\n } else if (typeof p.activeHours === 'object' && p.activeHours !== null) {\n const ah = p.activeHours as Record<string, unknown>;\n const start = typeof ah.start === 'string' ? ah.start : '';\n const end = typeof ah.end === 'string' ? ah.end : '';\n if (start && end) {\n (h as { activeHours?: { start: string; end: string; timezone?: string } }).activeHours = {\n start,\n end,\n ...(typeof ah.timezone === 'string' && ah.timezone.trim() ? { timezone: ah.timezone } : {}),\n };\n } else {\n delete (h as { activeHours?: unknown }).activeHours;\n }\n }\n }\n }\n if (body.gateway?.auth !== undefined) {\n if (!config.gateway) {\n config.gateway = {\n host: '0.0.0.0',\n port: 18790,\n heartbeat: { enabled: true, intervalMs: 1_800_000, includeSystemPromptSection: false },\n maxSseConnections: 100,\n corsOrigins: ['*'],\n };\n }\n if (!config.gateway.auth) config.gateway.auth = { mode: 'token' };\n const a = body.gateway.auth;\n if (a.mode !== undefined) {\n config.gateway.auth.mode = a.mode;\n }\n if (a.token !== undefined) {\n config.gateway.auth.token = a.token;\n }\n }\n\n if (body.update !== undefined && typeof body.update === 'object' && body.update !== null) {\n const p = body.update as Record<string, unknown>;\n if (p.channel === 'stable' || p.channel === 'beta' || p.channel === 'dev') {\n if (!config.update) {\n config.update = { checkOnStart: true, channel: p.channel };\n } else {\n config.update.channel = p.channel;\n }\n }\n }\n\n // Update providers config - save to credential system instead of config\n if (body.providers) {\n const resolver = new CredentialResolver();\n for (const [key, apiKey] of Object.entries(body.providers)) {\n if (\n apiKey !== undefined &&\n typeof apiKey === 'string' &&\n apiKey.trim() &&\n apiKey !== '***' &&\n apiKey !== '••••••••••••'\n ) {\n await resolver.saveApiKey(key, apiKey, { profileName: 'default' });\n }\n }\n }\n\n // Update STT config\n if (body.stt !== undefined) {\n config.stt = body.stt;\n }\n\n // Update TTS config\n if (body.tts !== undefined) {\n config.tts = body.tts;\n }\n\n const toolsPatchErr = applyToolsWebPatch(config, body as Record<string, unknown>);\n if (toolsPatchErr) {\n return c.json({ ok: false, error: { message: toolsPatchErr } }, 400);\n }\n\n if (body.bindings !== undefined) {\n if (!Array.isArray(body.bindings)) {\n return c.json({ ok: false, error: { message: 'bindings must be an array' } }, 400);\n }\n const parsed = BindingsConfigSchema.safeParse(body.bindings);\n if (!parsed.success) {\n return c.json(\n { ok: false, error: { message: parsed.error.issues.map((i) => i.message).join('; ') } },\n 400,\n );\n }\n config.bindings = parsed.data;\n }\n\n // Save config\n const result = await service.saveConfig(config);\n if (!result.saved) {\n return c.json({ ok: false, error: result.error }, 500);\n }\n\n if (body.gateway?.heartbeat !== undefined && typeof body.gateway.heartbeat === 'object') {\n service.reloadHeartbeatFromCurrentConfig();\n }\n\n const safeConfig = await buildSafeWebConfigPayload(service);\n return c.json({ ok: true, payload: { config: safeConfig } });\n });\n}\n"],"mappings":"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"}
@@ -6,6 +6,15 @@ function registerPublicGatewayRoutes(app, service) {
6
6
  app.get("/health", (c) => {
7
7
  return c.json(service.getHealth());
8
8
  });
9
+ /** Public liveness probe (no auth) — minimal payload for CLI / load balancers. */
10
+ app.get("/api/health", (c) => {
11
+ const health = service.getHealth();
12
+ return c.json({
13
+ status: "ok",
14
+ version: health.version,
15
+ uptime: health.uptime
16
+ });
17
+ });
9
18
  app.get("/api", (c) => {
10
19
  return c.json({
11
20
  service: "xopc-gateway",
@@ -13,7 +22,9 @@ function registerPublicGatewayRoutes(app, service) {
13
22
  transport: "streamable-http",
14
23
  endpoints: [
15
24
  "GET /health",
25
+ "GET /api/health",
16
26
  "GET /status",
27
+ "GET /api/status",
17
28
  "POST /api/agent (SSE stream / JSON)",
18
29
  "POST /api/agent/abort",
19
30
  "POST /api/agent/steer",
@@ -44,6 +55,12 @@ function registerPublicGatewayRoutes(app, service) {
44
55
  if (response) return response;
45
56
  return c.text("Not found", 404);
46
57
  });
58
+ /** From `web/public/channel-icons/` (Vite copies to static root). Public: img requests send no Bearer token. */
59
+ app.get("/channel-icons/*", (c) => {
60
+ const response = serveStaticFile(`channel-icons/${c.req.path.replace("/channel-icons/", "")}`);
61
+ if (response) return response;
62
+ return c.text("Not found", 404);
63
+ });
47
64
  app.get("/favicon.ico", (c) => {
48
65
  const response = serveStaticFile("favicon.ico");
49
66
  if (response) return response;
@@ -1 +1 @@
1
- {"version":3,"file":"public-gateway.js","names":[],"sources":["../../../../../src/gateway/hono/routes/public-gateway.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport { PACKAGE_VERSION } from '../../../package-version.js';\nimport type { GatewayService } from '../../service.js';\nimport { serveStaticFile } from '../lib/static-ui.js';\n\nexport function registerPublicGatewayRoutes(app: Hono, service: GatewayService): void {\n app.get('/health', (c) => {\n return c.json(service.getHealth());\n });\n\n app.get('/api', (c) => {\n return c.json({\n service: 'xopc-gateway',\n version: PACKAGE_VERSION,\n transport: 'streamable-http',\n endpoints: [\n 'GET /health',\n 'GET /status',\n 'POST /api/agent (SSE stream / JSON)',\n 'POST /api/agent/abort',\n 'POST /api/agent/steer',\n 'POST /api/send',\n 'GET /api/events (SSE stream)',\n 'GET /api/channels/status',\n 'POST /api/channels/weixin/login/start',\n 'GET /api/channels/weixin/login/:sessionKey',\n 'GET /api/config',\n 'GET /api/agents',\n 'POST /api/agents',\n 'PATCH /api/agents/:id',\n 'DELETE /api/agents/:id',\n 'GET/PUT /api/agents/:id/files/...',\n 'PATCH /api/config',\n 'POST /api/config/reload',\n 'POST /api/heartbeat/trigger',\n '... /api/cron/*',\n 'GET/PATCH /api/sessions/:key/agent-config',\n '... /api/sessions/*',\n 'GET /api/host/fs/meta',\n 'GET /api/host/fs/list',\n ],\n });\n });\n\n app.get('/assets/*', (c) => {\n const path = c.req.path.replace('/assets/', '');\n const response = serveStaticFile(`assets/${path}`);\n if (response) return response;\n return c.text('Not found', 404);\n });\n\n app.get('/favicon.ico', (c) => {\n const response = serveStaticFile('favicon.ico');\n if (response) return response;\n return c.text('Not found', 404);\n });\n\n app.get('/logo.svg', (c) => {\n const response = serveStaticFile('logo.svg');\n if (response) return response;\n return c.text('Not found', 404);\n });\n\n app.get('/logo-dark.svg', (c) => {\n const response = serveStaticFile('logo-dark.svg');\n if (response) return response;\n return c.text('Not found', 404);\n });\n\n app.get('/', (c) => {\n const response = serveStaticFile('index.html');\n if (response) return response;\n return c.text('UI not found', 404);\n });\n}\n"],"mappings":";;;sBAE8D;AAI9D,SAAgB,4BAA4B,KAAW,SAA+B;AACpF,KAAI,IAAI,YAAY,MAAM;AACxB,SAAO,EAAE,KAAK,QAAQ,WAAW,CAAC;GAClC;AAEF,KAAI,IAAI,SAAS,MAAM;AACrB,SAAO,EAAE,KAAK;GACZ,SAAS;GACT,SAAS;GACT,WAAW;GACX,WAAW;IACT;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACD;GACF,CAAC;GACF;AAEF,KAAI,IAAI,cAAc,MAAM;EAE1B,MAAM,WAAW,gBAAgB,UADpB,EAAE,IAAI,KAAK,QAAQ,YAAY,GACG,GAAG;AAClD,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,aAAa,IAAI;GAC/B;AAEF,KAAI,IAAI,iBAAiB,MAAM;EAC7B,MAAM,WAAW,gBAAgB,cAAc;AAC/C,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,aAAa,IAAI;GAC/B;AAEF,KAAI,IAAI,cAAc,MAAM;EAC1B,MAAM,WAAW,gBAAgB,WAAW;AAC5C,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,aAAa,IAAI;GAC/B;AAEF,KAAI,IAAI,mBAAmB,MAAM;EAC/B,MAAM,WAAW,gBAAgB,gBAAgB;AACjD,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,aAAa,IAAI;GAC/B;AAEF,KAAI,IAAI,MAAM,MAAM;EAClB,MAAM,WAAW,gBAAgB,aAAa;AAC9C,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,gBAAgB,IAAI;GAClC"}
1
+ {"version":3,"file":"public-gateway.js","names":[],"sources":["../../../../../src/gateway/hono/routes/public-gateway.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport { PACKAGE_VERSION } from '../../../package-version.js';\nimport type { GatewayService } from '../../service.js';\nimport { serveStaticFile } from '../lib/static-ui.js';\n\nexport function registerPublicGatewayRoutes(app: Hono, service: GatewayService): void {\n app.get('/health', (c) => {\n return c.json(service.getHealth());\n });\n\n /** Public liveness probe (no auth) — minimal payload for CLI / load balancers. */\n app.get('/api/health', (c) => {\n const health = service.getHealth();\n return c.json({\n status: 'ok',\n version: health.version,\n uptime: health.uptime,\n });\n });\n\n app.get('/api', (c) => {\n return c.json({\n service: 'xopc-gateway',\n version: PACKAGE_VERSION,\n transport: 'streamable-http',\n endpoints: [\n 'GET /health',\n 'GET /api/health',\n 'GET /status',\n 'GET /api/status',\n 'POST /api/agent (SSE stream / JSON)',\n 'POST /api/agent/abort',\n 'POST /api/agent/steer',\n 'POST /api/send',\n 'GET /api/events (SSE stream)',\n 'GET /api/channels/status',\n 'POST /api/channels/weixin/login/start',\n 'GET /api/channels/weixin/login/:sessionKey',\n 'GET /api/config',\n 'GET /api/agents',\n 'POST /api/agents',\n 'PATCH /api/agents/:id',\n 'DELETE /api/agents/:id',\n 'GET/PUT /api/agents/:id/files/...',\n 'PATCH /api/config',\n 'POST /api/config/reload',\n 'POST /api/heartbeat/trigger',\n '... /api/cron/*',\n 'GET/PATCH /api/sessions/:key/agent-config',\n '... /api/sessions/*',\n 'GET /api/host/fs/meta',\n 'GET /api/host/fs/list',\n ],\n });\n });\n\n app.get('/assets/*', (c) => {\n const path = c.req.path.replace('/assets/', '');\n const response = serveStaticFile(`assets/${path}`);\n if (response) return response;\n return c.text('Not found', 404);\n });\n\n /** From `web/public/channel-icons/` (Vite copies to static root). Public: img requests send no Bearer token. */\n app.get('/channel-icons/*', (c) => {\n const path = c.req.path.replace('/channel-icons/', '');\n const response = serveStaticFile(`channel-icons/${path}`);\n if (response) return response;\n return c.text('Not found', 404);\n });\n\n app.get('/favicon.ico', (c) => {\n const response = serveStaticFile('favicon.ico');\n if (response) return response;\n return c.text('Not found', 404);\n });\n\n app.get('/logo.svg', (c) => {\n const response = serveStaticFile('logo.svg');\n if (response) return response;\n return c.text('Not found', 404);\n });\n\n app.get('/logo-dark.svg', (c) => {\n const response = serveStaticFile('logo-dark.svg');\n if (response) return response;\n return c.text('Not found', 404);\n });\n\n app.get('/', (c) => {\n const response = serveStaticFile('index.html');\n if (response) return response;\n return c.text('UI not found', 404);\n });\n}\n"],"mappings":";;;sBAE8D;AAI9D,SAAgB,4BAA4B,KAAW,SAA+B;AACpF,KAAI,IAAI,YAAY,MAAM;AACxB,SAAO,EAAE,KAAK,QAAQ,WAAW,CAAC;GAClC;;AAGF,KAAI,IAAI,gBAAgB,MAAM;EAC5B,MAAM,SAAS,QAAQ,WAAW;AAClC,SAAO,EAAE,KAAK;GACZ,QAAQ;GACR,SAAS,OAAO;GAChB,QAAQ,OAAO;GAChB,CAAC;GACF;AAEF,KAAI,IAAI,SAAS,MAAM;AACrB,SAAO,EAAE,KAAK;GACZ,SAAS;GACT,SAAS;GACT,WAAW;GACX,WAAW;IACT;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACD;GACF,CAAC;GACF;AAEF,KAAI,IAAI,cAAc,MAAM;EAE1B,MAAM,WAAW,gBAAgB,UADpB,EAAE,IAAI,KAAK,QAAQ,YAAY,GACG,GAAG;AAClD,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,aAAa,IAAI;GAC/B;;AAGF,KAAI,IAAI,qBAAqB,MAAM;EAEjC,MAAM,WAAW,gBAAgB,iBADpB,EAAE,IAAI,KAAK,QAAQ,mBAAmB,GACG,GAAG;AACzD,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,aAAa,IAAI;GAC/B;AAEF,KAAI,IAAI,iBAAiB,MAAM;EAC7B,MAAM,WAAW,gBAAgB,cAAc;AAC/C,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,aAAa,IAAI;GAC/B;AAEF,KAAI,IAAI,cAAc,MAAM;EAC1B,MAAM,WAAW,gBAAgB,WAAW;AAC5C,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,aAAa,IAAI;GAC/B;AAEF,KAAI,IAAI,mBAAmB,MAAM;EAC/B,MAAM,WAAW,gBAAgB,gBAAgB;AACjD,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,aAAa,IAAI;GAC/B;AAEF,KAAI,IAAI,MAAM,MAAM;EAClB,MAAM,WAAW,gBAAgB,aAAa;AAC9C,MAAI,SAAU,QAAO;AACrB,SAAO,EAAE,KAAK,gBAAgB,IAAI;GAClC"}
@@ -104,6 +104,22 @@ function registerSessionsRoutes(authenticated, deps) {
104
104
  const result = await service.exportSession(key, format);
105
105
  return c.json(result);
106
106
  });
107
+ authenticated.delete("/api/sessions/:key/messages", async (c) => {
108
+ const key = c.req.param("key");
109
+ const body = await c.req.json().catch(() => ({}));
110
+ const startIndex = typeof body.startIndex === "number" ? body.startIndex : -1;
111
+ const count = typeof body.count === "number" ? body.count : 0;
112
+ if (startIndex < 0 || count <= 0) return c.json({ error: "Invalid startIndex or count" }, 400);
113
+ const loaded = await service.sessionManagerInstance.loadMessages(key);
114
+ if (!loaded || startIndex >= loaded.length) return c.json({ error: "Index out of range" }, 400);
115
+ const deleteCount = Math.min(count, loaded.length - startIndex);
116
+ const next = loaded.slice(0, startIndex).concat(loaded.slice(startIndex + deleteCount));
117
+ await service.sessionManagerInstance.saveMessages(key, next);
118
+ return c.json({
119
+ ok: true,
120
+ deleted: deleteCount
121
+ });
122
+ });
107
123
  authenticated.delete("/api/sessions/:key", async (c) => {
108
124
  const key = c.req.param("key");
109
125
  const result = await service.deleteSession(key);
@@ -1 +1 @@
1
- {"version":3,"file":"sessions.js","names":[],"sources":["../../../../../src/gateway/hono/routes/sessions.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport { buildSessionKey, parseSessionKey } from '../../../routing/session-key.js';\nimport { agentExists, getDefaultAgentId } from '../../../routing/resolve-route.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nexport function registerSessionsRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service } = deps;\n\n // ========== Session REST API (/api/sessions) ==========\n\n // POST /api/sessions - Create new session (reuses empty sessions)\n authenticated.post('/api/sessions', async (c) => {\n const body = await c.req.json().catch(() => ({}));\n const channel = body.channel || 'webchat';\n const routingCfg = service.currentConfig;\n let agentId =\n typeof body.agentId === 'string' && body.agentId.trim()\n ? body.agentId.trim().toLowerCase()\n : getDefaultAgentId(routingCfg);\n if (!agentExists(agentId, routingCfg)) {\n agentId = getDefaultAgentId(routingCfg);\n }\n\n // If a specific chat_id is provided, use it (for advanced use cases)\n // Otherwise, try to find and reuse an existing empty session\n if (body.chat_id) {\n const sessionKey = buildSessionKey({\n agentId,\n source: channel,\n accountId: 'default',\n peerKind: 'direct',\n peerId: body.chat_id,\n });\n\n await service.sessionManagerInstance.saveMessages(sessionKey, []);\n const session = await service.getSession(sessionKey);\n return c.json({ session }, 201);\n }\n \n // Look for existing empty sessions to reuse\n const existingSessions = await service.listSessions({\n channel,\n limit: 50,\n sortBy: 'updatedAt',\n sortOrder: 'desc',\n });\n \n // Reuse an empty session only when it matches the requested agent (session key embeds agent id).\n const emptySession = existingSessions.items.find((s) => {\n if (s.messageCount !== 0) return false;\n const parsed = parseSessionKey(s.key);\n return parsed?.agentId === agentId;\n });\n \n if (emptySession) {\n // Return existing empty session instead of creating a new one\n const session = await service.getSession(emptySession.key);\n return c.json({ session, reused: true }, 200);\n }\n \n // No empty session found, create a new one\n const chatId = `chat_${Date.now()}`;\n const sessionKey = buildSessionKey({\n agentId,\n source: channel,\n accountId: 'default',\n peerKind: 'direct',\n peerId: chatId,\n });\n\n await service.sessionManagerInstance.saveMessages(sessionKey, []);\n\n const session = await service.getSession(sessionKey);\n return c.json({ session }, 201);\n });\n\n // GET /api/sessions - List sessions\n authenticated.get('/api/sessions', async (c) => {\n const query = c.req.query();\n const result = await service.listSessions({\n status: query.status as any,\n search: query.search,\n channel: query.channel,\n limit: query.limit ? parseInt(query.limit) : undefined,\n offset: query.offset ? parseInt(query.offset) : undefined,\n });\n return c.json(result);\n });\n\n // GET /api/sessions/stats - Get session stats (must be before /:key)\n authenticated.get('/api/sessions/stats', async (c) => {\n const result = await service.getSessionStats();\n return c.json(result);\n });\n\n // GET /api/sessions/chat-ids - Get unique chat IDs from sessions (must be before /:key)\n authenticated.get('/api/sessions/chat-ids', async (c) => {\n const channel = c.req.query('channel');\n const chatIds = await service.getSessionChatIds(channel || undefined);\n return c.json({ ok: true, payload: { chatIds } });\n });\n\n // GET /api/sessions/:key/agent-config — resolved session agent settings (thinking, etc.)\n authenticated.get('/api/sessions/:key/agent-config', async (c) => {\n const key = c.req.param('key');\n const payload = await service.getSessionAgentConfig(key);\n return c.json({ ok: true, payload });\n });\n\n authenticated.patch('/api/sessions/:key/agent-config', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const result = await service.patchSessionAgentConfig(key, body);\n if (!result.ok) {\n return c.json({ ok: false, error: result.error }, 400);\n }\n return c.json({ ok: true });\n });\n\n // GET /api/sessions/:key - Get single session (must be after /stats and /chat-ids)\n authenticated.get('/api/sessions/:key', async (c) => {\n const key = c.req.param('key');\n const session = await service.getSession(key);\n if (!session) {\n return c.json({ error: 'Session not found' }, 404);\n }\n return c.json({ session });\n });\n\n // GET /api/sessions/:key/export - Export session (must be before /:key)\n authenticated.get('/api/sessions/:key/export', async (c) => {\n const key = c.req.param('key');\n const format = c.req.query('format') as any || 'json';\n const result = await service.exportSession(key, format);\n return c.json(result);\n });\n\n // DELETE /api/sessions/:key - Delete session\n authenticated.delete('/api/sessions/:key', async (c) => {\n const key = c.req.param('key');\n const result = await service.deleteSession(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/archive - Archive session\n authenticated.post('/api/sessions/:key/archive', async (c) => {\n const key = c.req.param('key');\n const result = await service.archiveSession(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/unarchive - Unarchive session\n authenticated.post('/api/sessions/:key/unarchive', async (c) => {\n const key = c.req.param('key');\n const result = await service.unarchiveSession(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/pin - Pin session\n authenticated.post('/api/sessions/:key/pin', async (c) => {\n const key = c.req.param('key');\n const result = await service.pinSession(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/unpin - Unpin session\n authenticated.post('/api/sessions/:key/unpin', async (c) => {\n const key = c.req.param('key');\n const result = await service.unpinSession(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/rename - Rename session\n authenticated.post('/api/sessions/:key/rename', async (c) => {\n const key = c.req.param('key');\n\n const body = await c.req.json();\n const { name } = body;\n const result = await service.renameSession(key, name);\n return c.json(result);\n });\n\n // ========== Subagent REST API (/api/subagents) ==========\n\n // GET /api/subagents - List subagent sessions\n authenticated.get('/api/subagents', async (c) => {\n const query = c.req.query();\n const result = await service.listSubagents({\n limit: query.limit ? parseInt(query.limit) : undefined,\n offset: query.offset ? parseInt(query.offset) : undefined,\n });\n return c.json(result);\n });\n\n // GET /api/subagents/:key - Get subagent session detail\n authenticated.get('/api/subagents/:key', async (c) => {\n const key = c.req.param('key');\n // Verify it's a subagent session\n if (!key.startsWith('subagent:')) {\n return c.json({ error: 'Not a subagent session' }, 400);\n }\n const session = await service.getSession(key);\n if (!session) {\n return c.json({ error: 'Subagent session not found' }, 404);\n }\n return c.json({ session });\n });\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"sessions.js","names":[],"sources":["../../../../../src/gateway/hono/routes/sessions.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport { buildSessionKey, parseSessionKey } from '../../../routing/session-key.js';\nimport { agentExists, getDefaultAgentId } from '../../../routing/resolve-route.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nexport function registerSessionsRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service } = deps;\n\n // ========== Session REST API (/api/sessions) ==========\n\n // POST /api/sessions - Create new session (reuses empty sessions)\n authenticated.post('/api/sessions', async (c) => {\n const body = await c.req.json().catch(() => ({}));\n const channel = body.channel || 'webchat';\n const routingCfg = service.currentConfig;\n let agentId =\n typeof body.agentId === 'string' && body.agentId.trim()\n ? body.agentId.trim().toLowerCase()\n : getDefaultAgentId(routingCfg);\n if (!agentExists(agentId, routingCfg)) {\n agentId = getDefaultAgentId(routingCfg);\n }\n\n // If a specific chat_id is provided, use it (for advanced use cases)\n // Otherwise, try to find and reuse an existing empty session\n if (body.chat_id) {\n const sessionKey = buildSessionKey({\n agentId,\n source: channel,\n accountId: 'default',\n peerKind: 'direct',\n peerId: body.chat_id,\n });\n\n await service.sessionManagerInstance.saveMessages(sessionKey, []);\n const session = await service.getSession(sessionKey);\n return c.json({ session }, 201);\n }\n \n // Look for existing empty sessions to reuse\n const existingSessions = await service.listSessions({\n channel,\n limit: 50,\n sortBy: 'updatedAt',\n sortOrder: 'desc',\n });\n \n // Reuse an empty session only when it matches the requested agent (session key embeds agent id).\n const emptySession = existingSessions.items.find((s) => {\n if (s.messageCount !== 0) return false;\n const parsed = parseSessionKey(s.key);\n return parsed?.agentId === agentId;\n });\n \n if (emptySession) {\n // Return existing empty session instead of creating a new one\n const session = await service.getSession(emptySession.key);\n return c.json({ session, reused: true }, 200);\n }\n \n // No empty session found, create a new one\n const chatId = `chat_${Date.now()}`;\n const sessionKey = buildSessionKey({\n agentId,\n source: channel,\n accountId: 'default',\n peerKind: 'direct',\n peerId: chatId,\n });\n\n await service.sessionManagerInstance.saveMessages(sessionKey, []);\n\n const session = await service.getSession(sessionKey);\n return c.json({ session }, 201);\n });\n\n // GET /api/sessions - List sessions\n authenticated.get('/api/sessions', async (c) => {\n const query = c.req.query();\n const result = await service.listSessions({\n status: query.status as any,\n search: query.search,\n channel: query.channel,\n limit: query.limit ? parseInt(query.limit) : undefined,\n offset: query.offset ? parseInt(query.offset) : undefined,\n });\n return c.json(result);\n });\n\n // GET /api/sessions/stats - Get session stats (must be before /:key)\n authenticated.get('/api/sessions/stats', async (c) => {\n const result = await service.getSessionStats();\n return c.json(result);\n });\n\n // GET /api/sessions/chat-ids - Get unique chat IDs from sessions (must be before /:key)\n authenticated.get('/api/sessions/chat-ids', async (c) => {\n const channel = c.req.query('channel');\n const chatIds = await service.getSessionChatIds(channel || undefined);\n return c.json({ ok: true, payload: { chatIds } });\n });\n\n // GET /api/sessions/:key/agent-config — resolved session agent settings (thinking, etc.)\n authenticated.get('/api/sessions/:key/agent-config', async (c) => {\n const key = c.req.param('key');\n const payload = await service.getSessionAgentConfig(key);\n return c.json({ ok: true, payload });\n });\n\n authenticated.patch('/api/sessions/:key/agent-config', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const result = await service.patchSessionAgentConfig(key, body);\n if (!result.ok) {\n return c.json({ ok: false, error: result.error }, 400);\n }\n return c.json({ ok: true });\n });\n\n // GET /api/sessions/:key - Get single session (must be after /stats and /chat-ids)\n authenticated.get('/api/sessions/:key', async (c) => {\n const key = c.req.param('key');\n const session = await service.getSession(key);\n if (!session) {\n return c.json({ error: 'Session not found' }, 404);\n }\n return c.json({ session });\n });\n\n // GET /api/sessions/:key/export - Export session (must be before /:key)\n authenticated.get('/api/sessions/:key/export', async (c) => {\n const key = c.req.param('key');\n const format = c.req.query('format') as any || 'json';\n const result = await service.exportSession(key, format);\n return c.json(result);\n });\n\n // DELETE /api/sessions/:key/messages — delete a range of messages by index (before whole-session DELETE)\n authenticated.delete('/api/sessions/:key/messages', async (c) => {\n const key = c.req.param('key');\n const body = await c.req.json().catch(() => ({}));\n const startIndex = typeof body.startIndex === 'number' ? body.startIndex : -1;\n const count = typeof body.count === 'number' ? body.count : 0;\n if (startIndex < 0 || count <= 0) {\n return c.json({ error: 'Invalid startIndex or count' }, 400);\n }\n const loaded = await service.sessionManagerInstance.loadMessages(key);\n if (!loaded || startIndex >= loaded.length) {\n return c.json({ error: 'Index out of range' }, 400);\n }\n const deleteCount = Math.min(count, loaded.length - startIndex);\n const next = loaded.slice(0, startIndex).concat(loaded.slice(startIndex + deleteCount));\n await service.sessionManagerInstance.saveMessages(key, next);\n return c.json({ ok: true, deleted: deleteCount });\n });\n\n // DELETE /api/sessions/:key - Delete session\n authenticated.delete('/api/sessions/:key', async (c) => {\n const key = c.req.param('key');\n const result = await service.deleteSession(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/archive - Archive session\n authenticated.post('/api/sessions/:key/archive', async (c) => {\n const key = c.req.param('key');\n const result = await service.archiveSession(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/unarchive - Unarchive session\n authenticated.post('/api/sessions/:key/unarchive', async (c) => {\n const key = c.req.param('key');\n const result = await service.unarchiveSession(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/pin - Pin session\n authenticated.post('/api/sessions/:key/pin', async (c) => {\n const key = c.req.param('key');\n const result = await service.pinSession(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/unpin - Unpin session\n authenticated.post('/api/sessions/:key/unpin', async (c) => {\n const key = c.req.param('key');\n const result = await service.unpinSession(key);\n return c.json(result);\n });\n\n // POST /api/sessions/:key/rename - Rename session\n authenticated.post('/api/sessions/:key/rename', async (c) => {\n const key = c.req.param('key');\n\n const body = await c.req.json();\n const { name } = body;\n const result = await service.renameSession(key, name);\n return c.json(result);\n });\n\n // ========== Subagent REST API (/api/subagents) ==========\n\n // GET /api/subagents - List subagent sessions\n authenticated.get('/api/subagents', async (c) => {\n const query = c.req.query();\n const result = await service.listSubagents({\n limit: query.limit ? parseInt(query.limit) : undefined,\n offset: query.offset ? parseInt(query.offset) : undefined,\n });\n return c.json(result);\n });\n\n // GET /api/subagents/:key - Get subagent session detail\n authenticated.get('/api/subagents/:key', async (c) => {\n const key = c.req.param('key');\n // Verify it's a subagent session\n if (!key.startsWith('subagent:')) {\n return c.json({ error: 'Not a subagent session' }, 400);\n }\n const session = await service.getSession(key);\n if (!session) {\n return c.json({ error: 'Subagent session not found' }, 404);\n }\n return c.json({ session });\n });\n}\n"],"mappings":"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"}
@@ -1,13 +1,37 @@
1
1
  //#region src/gateway/hono/routes/status.ts
2
+ function buildStatusPayload(service) {
3
+ const health = service.getHealth();
4
+ const rows = service.getChannelsStatus();
5
+ const channels = {};
6
+ for (const row of rows) {
7
+ const status = !row.enabled ? "disabled" : row.connected ? "connected" : "disconnected";
8
+ channels[row.name] = { status };
9
+ }
10
+ return {
11
+ status: health.status,
12
+ version: health.version,
13
+ channels,
14
+ uptime: health.uptime
15
+ };
16
+ }
2
17
  function registerStatusRoutes(authenticated, deps) {
3
- const { service } = deps;
4
- authenticated.get("/status", (c) => {
5
- const health = service.getHealth();
18
+ const { service, strictRateLimitMiddleware } = deps;
19
+ const handler = (c) => c.json(buildStatusPayload(service));
20
+ authenticated.get("/status", handler);
21
+ authenticated.get("/api/status", handler);
22
+ /**
23
+ * POST /api/gateway/restart — respawn gateway process when supported (foreground `xopc gateway`).
24
+ */
25
+ authenticated.post("/api/gateway/restart", strictRateLimitMiddleware, (c) => {
26
+ const result = service.triggerGatewayProcessRestart();
27
+ if (!result.ok) return c.json({
28
+ ok: false,
29
+ error: result.mode,
30
+ message: result.message ?? "Restart failed"
31
+ }, 400);
6
32
  return c.json({
7
- status: health.status,
8
- version: health.version,
9
- channels: health.channels,
10
- uptime: health.uptime
33
+ ok: true,
34
+ payload: { mode: result.mode }
11
35
  });
12
36
  });
13
37
  }
@@ -1 +1 @@
1
- {"version":3,"file":"status.js","names":[],"sources":["../../../../../src/gateway/hono/routes/status.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nexport function registerStatusRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service } = deps;\n authenticated.get('/status', (c) => {\n const health = service.getHealth();\n return c.json({\n status: health.status,\n version: health.version,\n channels: health.channels,\n uptime: health.uptime,\n });\n });\n}\n"],"mappings":";AAIA,SAAgB,qBAAqB,eAAqB,MAAoC;CAC5F,MAAM,EAAE,YAAY;AACpB,eAAc,IAAI,YAAY,MAAM;EAClC,MAAM,SAAS,QAAQ,WAAW;AAClC,SAAO,EAAE,KAAK;GACZ,QAAQ,OAAO;GACf,SAAS,OAAO;GAChB,UAAU,OAAO;GACjB,QAAQ,OAAO;GAChB,CAAC;GACF"}
1
+ {"version":3,"file":"status.js","names":[],"sources":["../../../../../src/gateway/hono/routes/status.ts"],"sourcesContent":["import type { Context } from 'hono';\nimport type { Hono } from 'hono';\n\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nfunction buildStatusPayload(service: AuthenticatedRouteDeps['service']) {\n const health = service.getHealth();\n const rows = service.getChannelsStatus();\n const channels: Record<string, { status: string }> = {};\n for (const row of rows) {\n const status = !row.enabled ? 'disabled' : row.connected ? 'connected' : 'disconnected';\n channels[row.name] = { status };\n }\n return {\n status: health.status,\n version: health.version,\n channels,\n uptime: health.uptime,\n };\n}\n\nexport function registerStatusRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service, strictRateLimitMiddleware } = deps;\n\n const handler = (c: Context) => c.json(buildStatusPayload(service));\n\n authenticated.get('/status', handler);\n authenticated.get('/api/status', handler);\n\n /**\n * POST /api/gateway/restart — respawn gateway process when supported (foreground `xopc gateway`).\n */\n authenticated.post('/api/gateway/restart', strictRateLimitMiddleware, (c) => {\n const result = service.triggerGatewayProcessRestart();\n if (!result.ok) {\n return c.json({ ok: false, error: result.mode, message: result.message ?? 'Restart failed' }, 400);\n }\n return c.json({ ok: true, payload: { mode: result.mode } });\n });\n}\n"],"mappings":";AAKA,SAAS,mBAAmB,SAA4C;CACtE,MAAM,SAAS,QAAQ,WAAW;CAClC,MAAM,OAAO,QAAQ,mBAAmB;CACxC,MAAM,WAA+C,EAAE;AACvD,MAAK,MAAM,OAAO,MAAM;EACtB,MAAM,SAAS,CAAC,IAAI,UAAU,aAAa,IAAI,YAAY,cAAc;AACzE,WAAS,IAAI,QAAQ,EAAE,QAAQ;;AAEjC,QAAO;EACL,QAAQ,OAAO;EACf,SAAS,OAAO;EAChB;EACA,QAAQ,OAAO;EAChB;;AAGH,SAAgB,qBAAqB,eAAqB,MAAoC;CAC5F,MAAM,EAAE,SAAS,8BAA8B;CAE/C,MAAM,WAAW,MAAe,EAAE,KAAK,mBAAmB,QAAQ,CAAC;AAEnE,eAAc,IAAI,WAAW,QAAQ;AACrC,eAAc,IAAI,eAAe,QAAQ;;;;AAKzC,eAAc,KAAK,wBAAwB,4BAA4B,MAAM;EAC3E,MAAM,SAAS,QAAQ,8BAA8B;AACrD,MAAI,CAAC,OAAO,GACV,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO,OAAO;GAAM,SAAS,OAAO,WAAW;GAAkB,EAAE,IAAI;AAEpG,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM,SAAS,EAAE,MAAM,OAAO,MAAM;GAAE,CAAC;GAC3D"}
@@ -3,15 +3,16 @@ import { createLogger } from "../../../utils/logger/index.js";
3
3
  import { init_logger } from "../../../utils/logger.js";
4
4
  import { loadConfig } from "../../../config/loader.js";
5
5
  import "../../../config/index.js";
6
+ import { acquireUpdateLock } from "../../../infra/update-lock.js";
6
7
  import { normalizeUpdateChannel } from "../../../infra/update-channels.js";
7
8
  import { detectInstallKind, resolvePackageRoot } from "../../../infra/update-check.js";
8
9
  import { getUpdateAvailable, runGatewayUpdateCheck } from "../../../infra/update-startup.js";
9
- import { runAutoUpdateCommand } from "../../../infra/update-runner.js";
10
+ import { runAutoUpdateCommand, runAutoUpdateCommandWithProgress } from "../../../infra/update-runner.js";
11
+ import { streamSSE } from "hono/streaming";
10
12
  //#region src/gateway/hono/routes/update.ts
11
13
  init_package_version();
12
14
  init_logger();
13
15
  const log = createLogger("GatewayUpdate");
14
- let updateRunInFlight = false;
15
16
  function parseUpdateCliJson(stdout) {
16
17
  const t = stdout.trim();
17
18
  if (!t) return null;
@@ -31,6 +32,29 @@ function parseUpdateCliJson(stdout) {
31
32
  }
32
33
  return null;
33
34
  }
35
+ function isPreconditionFail(x) {
36
+ return !x.ok;
37
+ }
38
+ async function npmUpdatePreconditions(service) {
39
+ const channel = normalizeUpdateChannel(loadConfig(service.getHealth().configPath).update?.channel) ?? "stable";
40
+ const root = await resolvePackageRoot();
41
+ if (root) {
42
+ if (await detectInstallKind(root) === "git") return {
43
+ ok: false,
44
+ status: 400,
45
+ body: {
46
+ ok: false,
47
+ error: "git-checkout",
48
+ message: "Running from a git checkout. Use `git pull` in the repo, or install from npm to use one-click update."
49
+ }
50
+ };
51
+ }
52
+ return {
53
+ ok: true,
54
+ channel,
55
+ root
56
+ };
57
+ }
34
58
  function registerUpdateRoutes(authenticated, deps) {
35
59
  const { strictRateLimitMiddleware, service } = deps;
36
60
  /**
@@ -74,22 +98,15 @@ function registerUpdateRoutes(authenticated, deps) {
74
98
  * POST /api/update/run — one-click npm install (OpenClaw-style). Rejects git checkouts.
75
99
  */
76
100
  authenticated.post("/api/update/run", strictRateLimitMiddleware, async (c) => {
77
- if (updateRunInFlight) return c.json({
101
+ const pre = await npmUpdatePreconditions(service);
102
+ if (isPreconditionFail(pre)) return c.json(pre.body, pre.status);
103
+ const lock = await acquireUpdateLock("gateway");
104
+ if (!lock) return c.json({
78
105
  ok: false,
79
106
  error: "busy",
80
107
  message: "Another update is already in progress."
81
108
  }, 409);
82
- const configPath = service.getHealth().configPath;
83
- const channel = normalizeUpdateChannel(loadConfig(configPath).update?.channel) ?? "stable";
84
- const root = await resolvePackageRoot();
85
- if (root) {
86
- if (await detectInstallKind(root) === "git") return c.json({
87
- ok: false,
88
- error: "git-checkout",
89
- message: "Running from a git checkout. Use `git pull` in the repo, or install from npm to use one-click update."
90
- }, 400);
91
- }
92
- updateRunInFlight = true;
109
+ const { channel, root } = pre;
93
110
  try {
94
111
  log.info({ channel }, "Gateway: starting one-click npm update");
95
112
  const result = await runAutoUpdateCommand({
@@ -131,9 +148,95 @@ function registerUpdateRoutes(authenticated, deps) {
131
148
  message: err instanceof Error ? err.message : String(err)
132
149
  }, 500);
133
150
  } finally {
134
- updateRunInFlight = false;
151
+ await lock.release();
135
152
  }
136
153
  });
154
+ /**
155
+ * POST /api/update/run/stream — SSE-streamed npm update with progress lines.
156
+ */
157
+ authenticated.post("/api/update/run/stream", strictRateLimitMiddleware, async (c) => {
158
+ const pre = await npmUpdatePreconditions(service);
159
+ if (isPreconditionFail(pre)) return c.json(pre.body, pre.status);
160
+ const { channel, root } = pre;
161
+ return streamSSE(c, async (stream) => {
162
+ const lock = await acquireUpdateLock("gateway");
163
+ if (!lock) {
164
+ await stream.writeSSE({
165
+ event: "result",
166
+ data: JSON.stringify({
167
+ ok: false,
168
+ error: "busy",
169
+ message: "Another update is already in progress."
170
+ })
171
+ });
172
+ return;
173
+ }
174
+ try {
175
+ log.info({ channel }, "Gateway: starting streamed one-click npm update");
176
+ const result = await runAutoUpdateCommandWithProgress({
177
+ channel,
178
+ root,
179
+ onProgress: async (line, source) => {
180
+ await stream.writeSSE({
181
+ event: "progress",
182
+ data: JSON.stringify({
183
+ line,
184
+ source
185
+ })
186
+ });
187
+ }
188
+ });
189
+ const parsed = parseUpdateCliJson(result.stdout ?? "");
190
+ if (result.ok && parsed?.status === "skipped" && parsed?.reason === "git-checkout") {
191
+ await stream.writeSSE({
192
+ event: "result",
193
+ data: JSON.stringify({
194
+ ok: false,
195
+ error: "git-checkout",
196
+ message: String(parsed.message ?? "Git checkout — use git pull instead.")
197
+ })
198
+ });
199
+ return;
200
+ }
201
+ if (!result.ok) {
202
+ await stream.writeSSE({
203
+ event: "result",
204
+ data: JSON.stringify({
205
+ ok: false,
206
+ error: "update-failed",
207
+ message: result.stderr?.trim() || result.reason || `Update exited with code ${result.exitCode ?? "unknown"}`,
208
+ result: parsed,
209
+ exitCode: result.exitCode,
210
+ reason: result.reason
211
+ })
212
+ });
213
+ return;
214
+ }
215
+ await stream.writeSSE({
216
+ event: "result",
217
+ data: JSON.stringify({
218
+ ok: true,
219
+ result: parsed
220
+ })
221
+ });
222
+ } catch (err) {
223
+ log.error({
224
+ err,
225
+ channel
226
+ }, "Gateway: streamed npm update threw");
227
+ await stream.writeSSE({
228
+ event: "result",
229
+ data: JSON.stringify({
230
+ ok: false,
231
+ error: "internal",
232
+ message: err instanceof Error ? err.message : String(err)
233
+ })
234
+ });
235
+ } finally {
236
+ await lock.release();
237
+ }
238
+ });
239
+ });
137
240
  }
138
241
  //#endregion
139
242
  export { registerUpdateRoutes };