@xopcai/xopc 0.0.126 → 0.0.127

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 (191) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/xopc.extension.json +1 -1
  3. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-C70vgt60.js → agent-avatar-dicebear-CgGgO4OV.js} +1 -1
  4. package/dist/gateway/static/root/assets/agents-k59l7NMb.js +2 -0
  5. package/dist/gateway/static/root/assets/{app-management-settings-panel-D9-HW6cy.js → app-management-settings-panel-DeQsTsyy.js} +1 -1
  6. package/dist/gateway/static/root/assets/{appearance-settings-BHlahIDL.js → appearance-settings-BnHQW7Hv.js} +1 -1
  7. package/dist/gateway/static/root/assets/{apps-page-BdJ1eQg3.js → apps-page-BG9b4abG.js} +1 -1
  8. package/dist/gateway/static/root/assets/{archive-plugin-B-aoIt0w.js → archive-plugin-5NXT7Zqv.js} +1 -1
  9. package/dist/gateway/static/root/assets/{attachment-load-BD0G0FD5.js → attachment-load-DghwhYe0.js} +1 -1
  10. package/dist/gateway/static/root/assets/{automation-suggestion-card-iJRVI7aZ.js → automation-suggestion-card-DYmESgwl.js} +1 -1
  11. package/dist/gateway/static/root/assets/automations-page-De8mVutL.js +4 -0
  12. package/dist/gateway/static/root/assets/{binary-plugins-B0mNlVSz.js → binary-plugins-DSbPKdWX.js} +1 -1
  13. package/dist/gateway/static/root/assets/{block-editor-CJY9Lu5G.js → block-editor-CoZ-_np-.js} +27 -27
  14. package/dist/gateway/static/root/assets/browser-settings-page-C_ZRa4LF.js +8 -0
  15. package/dist/gateway/static/root/assets/{capability-presets-api-Bgc8ag55.js → capability-presets-api-hny224j-.js} +1 -1
  16. package/dist/gateway/static/root/assets/{capability-presets-settings-panel-B1nIi0TC.js → capability-presets-settings-panel-Drc0qLsw.js} +1 -1
  17. package/dist/gateway/static/root/assets/{channel-recipient-api-0sauApoC.js → channel-recipient-api-DAlOHxKJ.js} +1 -1
  18. package/dist/gateway/static/root/assets/channels-settings-CA20zBV9.js +1 -0
  19. package/dist/gateway/static/root/assets/connectors-page-qMyMB5te.js +2 -0
  20. package/dist/gateway/static/root/assets/desktop-pet-XG6Vb_fZ.js +1 -0
  21. package/dist/gateway/static/root/assets/desktop-pet-settings-npJ0Oh5p.js +1 -0
  22. package/dist/gateway/static/root/assets/desktop-pet-sprite-DqZ6fbIj.js +1 -0
  23. package/dist/gateway/static/root/assets/directory-picker-path-field-BR2ItBuf.js +1 -0
  24. package/dist/gateway/static/root/assets/dreaming-settings-CkUZ997f.js +3 -0
  25. package/dist/gateway/static/root/assets/{extension-debug-page-BbyczVZ3.js → extension-debug-page-Tl0f1rNv.js} +1 -1
  26. package/dist/gateway/static/root/assets/{extension-page-DLN1I3DR.js → extension-page-Ck7QuwE3.js} +1 -1
  27. package/dist/gateway/static/root/assets/{extension-settings-page-D9VGHmYJ.js → extension-settings-page-3RMhQtZ3.js} +1 -1
  28. package/dist/gateway/static/root/assets/{fetch-5V96dUz3.js → fetch-pg2ErdAk.js} +1 -1
  29. package/dist/gateway/static/root/assets/{gateway-config-api-BtIzObwp.js → gateway-config-api-DbG97ia2.js} +1 -1
  30. package/dist/gateway/static/root/assets/gateway-settings-B8cyqKk-.js +1 -0
  31. package/dist/gateway/static/root/assets/{gateway-startup-retry-DEMad2wt.js → gateway-startup-retry-Yh8h3hkj.js} +1 -1
  32. package/dist/gateway/static/root/assets/{goal-create-dialog-4PcF6Sh6.js → goal-create-dialog-DmeW7Zz3.js} +1 -1
  33. package/dist/gateway/static/root/assets/goal-detail-page-DrTyGbVD.js +1 -0
  34. package/dist/gateway/static/root/assets/{goals-config-api-CVN7-pdM.js → goals-config-api-CxCWGIBB.js} +1 -1
  35. package/dist/gateway/static/root/assets/goals-page-DV1bJhIh.js +2 -0
  36. package/dist/gateway/static/root/assets/{goals-settings-IYCH3-Pi.js → goals-settings-9DrfOkP5.js} +1 -1
  37. package/dist/gateway/static/root/assets/{heartbeat-settings-Cf_a2Bmz.js → heartbeat-settings-KaDpZrv0.js} +1 -1
  38. package/dist/gateway/static/root/assets/index-C2F0Clvm.js +256 -0
  39. package/dist/gateway/static/root/assets/index-COQSX5d_.css +1 -0
  40. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-lKTg6St7.js → keyboard-shortcuts-settings-CfQrt_Rb.js} +1 -1
  41. package/dist/gateway/static/root/assets/logs-page-C9dpiNTF.js +2 -0
  42. package/dist/gateway/static/root/assets/{markdown-split-Bv4k6iGJ.js → markdown-split-BwiMdCf_.js} +1 -1
  43. package/dist/gateway/static/root/assets/{media-plugins-Bbi8g3N8.js → media-plugins-DhoizyZv.js} +1 -1
  44. package/dist/gateway/static/root/assets/messages-DmnbiNxU.js +3 -0
  45. package/dist/gateway/static/root/assets/models-hub-panel-zdCdmBmH.js +2 -0
  46. package/dist/gateway/static/root/assets/notes-page-MpGeFfPt.js +1 -0
  47. package/dist/gateway/static/root/assets/notes-workbench-DYCM3yd2.js +2 -0
  48. package/dist/gateway/static/root/assets/{page-tabs-Cp395RYD.js → page-tabs-DDC2t4Z8.js} +1 -1
  49. package/dist/gateway/static/root/assets/{preview-open-alternatives-DqV5OM4m.js → preview-open-alternatives-BTmk-XDM.js} +1 -1
  50. package/dist/gateway/static/root/assets/project-detail-page-Cu0ElRnS.js +1 -0
  51. package/dist/gateway/static/root/assets/projects-page-DakNaUjZ.js +1 -0
  52. package/dist/gateway/static/root/assets/remote-access-hub-DYKjt7L9.js +1 -0
  53. package/dist/gateway/static/root/assets/{save-bar-controls-BItmzAzI.js → save-bar-controls-DqU-yKIh.js} +1 -1
  54. package/dist/gateway/static/root/assets/{schedule-field-BQ8IjjCn.js → schedule-field-CUttkoSB.js} +1 -1
  55. package/dist/gateway/static/root/assets/{schema-form-BRpD6x3d.js → schema-form-CVSQA9nI.js} +1 -1
  56. package/dist/gateway/static/root/assets/sessions-page-CcGHDsz1.js +1 -0
  57. package/dist/gateway/static/root/assets/settings-advanced-gate-CuFdeKNu.js +1 -0
  58. package/dist/gateway/static/root/assets/{settings-collapsible-section-BKSPQM4R.js → settings-collapsible-section-CK7ogS-P.js} +1 -1
  59. package/dist/gateway/static/root/assets/{settings-form-section-BmyfthNQ.js → settings-form-section-Bugp38Fa.js} +1 -1
  60. package/dist/gateway/static/root/assets/settings-page-0AJoUvxi.js +1 -0
  61. package/dist/gateway/static/root/assets/{settings-page-layout-Bls5tfbH.js → settings-page-layout-DBRWwdhh.js} +1 -1
  62. package/dist/gateway/static/root/assets/{setup-status-panel-kQEsTGAs.js → setup-status-panel-D6a_hEk7.js} +1 -1
  63. package/dist/gateway/static/root/assets/{share-preview-page-DbYZNAPb.js → share-preview-page-BtsuETKF.js} +1 -1
  64. package/dist/gateway/static/root/assets/shares-settings-CcEFT7S9.js +1 -0
  65. package/dist/gateway/static/root/assets/skill-reload-api-BcN_RuTD.js +1 -0
  66. package/dist/gateway/static/root/assets/skills-page-BbRZZZA5.js +2 -0
  67. package/dist/gateway/static/root/assets/{system-settings-panel-DKDAojWM.js → system-settings-panel-DJ6YuLqR.js} +1 -1
  68. package/dist/gateway/static/root/assets/{typed-models-lib-BCCV4Kkp.js → typed-models-lib-B0T7N8Km.js} +1 -1
  69. package/dist/gateway/static/root/assets/{use-channel-catalog-NBqg3iFY.js → use-channel-catalog-C6vrxdzZ.js} +1 -1
  70. package/dist/gateway/static/root/assets/{user-profile-settings-panel-suQ2x-LB.js → user-profile-settings-panel-DZ0nKMgj.js} +1 -1
  71. package/dist/gateway/static/root/assets/{utils-DPGVr3tS.js → utils-CehXcWAY.js} +1 -1
  72. package/dist/gateway/static/root/assets/voice-api-key-field-2QKflCx8.js +1 -0
  73. package/dist/gateway/static/root/assets/work-item-detail-page-DfJnuWq1.js +1 -0
  74. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-BTkRVNAh.js → workflow-run-setup-panel-c4jeaohQ.js} +2 -2
  75. package/dist/gateway/static/root/assets/{workflow-start-dialog-DAImVtdO.js → workflow-start-dialog-ENRHjoqa.js} +1 -1
  76. package/dist/gateway/static/root/assets/workflows-page-BJwwFTm_.js +18 -0
  77. package/dist/gateway/static/root/index.html +5 -5
  78. package/dist/package.js +1 -1
  79. package/dist/src/agent/agent-instance-gateway.d.ts +5 -0
  80. package/dist/src/agent/agent-manager.d.ts +14 -0
  81. package/dist/src/agent/agent-manager.js +111 -2
  82. package/dist/src/agent/agent-manager.js.map +1 -1
  83. package/dist/src/agent/capabilities/definitions.d.ts +153 -0
  84. package/dist/src/agent/capabilities/definitions.js +156 -0
  85. package/dist/src/agent/capabilities/definitions.js.map +1 -0
  86. package/dist/src/agent/capabilities/index.d.ts +2 -0
  87. package/dist/src/agent/capabilities/index.js +3 -0
  88. package/dist/src/agent/capabilities/registry.d.ts +10 -0
  89. package/dist/src/agent/capabilities/registry.js +51 -0
  90. package/dist/src/agent/capabilities/registry.js.map +1 -0
  91. package/dist/src/agent/service/process-direct-one-shot.js +5 -3
  92. package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
  93. package/dist/src/agent/service/process-direct-streaming.js +4 -3
  94. package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
  95. package/dist/src/agent/service.d.ts +2 -0
  96. package/dist/src/agent/service.js +3 -0
  97. package/dist/src/agent/service.js.map +1 -1
  98. package/dist/src/agent/skills/parse-skill-metadata.js +9 -1
  99. package/dist/src/agent/skills/parse-skill-metadata.js.map +1 -1
  100. package/dist/src/agent/skills/skill-manager.d.ts +4 -0
  101. package/dist/src/agent/skills/skill-manager.js +17 -0
  102. package/dist/src/agent/skills/skill-manager.js.map +1 -1
  103. package/dist/src/agent/skills/types.d.ts +5 -0
  104. package/dist/src/agent/tools/desktop-pet-tool.d.ts +24 -0
  105. package/dist/src/agent/tools/desktop-pet-tool.js +90 -0
  106. package/dist/src/agent/tools/desktop-pet-tool.js.map +1 -0
  107. package/dist/src/agent/tools/factory.d.ts +2 -0
  108. package/dist/src/agent/tools/factory.js +17 -0
  109. package/dist/src/agent/tools/factory.js.map +1 -1
  110. package/dist/src/agent/tools/index.d.ts +1 -0
  111. package/dist/src/agent/tools/index.js +2 -1
  112. package/dist/src/automations/draft/automation-draft-service.js +1 -1
  113. package/dist/src/cli/commands/agent.js +2 -2
  114. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  115. package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
  116. package/dist/src/cli/commands/models.js +1 -1
  117. package/dist/src/cli/commands/onboard.js +1 -1
  118. package/dist/src/cli/commands/profile.js +1 -1
  119. package/dist/src/cli/commands/tunnel.js +1 -1
  120. package/dist/src/cli/commands/update.js +1 -1
  121. package/dist/src/cli/extension-cli-register.js +1 -1
  122. package/dist/src/config/index.js +1 -1
  123. package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
  124. package/dist/src/gateway/agent-builtin-tools.js +1 -0
  125. package/dist/src/gateway/agent-builtin-tools.js.map +1 -1
  126. package/dist/src/gateway/hono/routes/commands-skills.js +7 -0
  127. package/dist/src/gateway/hono/routes/commands-skills.js.map +1 -1
  128. package/dist/src/gateway/hono/routes/lazy-bundles.js +2 -1
  129. package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
  130. package/dist/src/gateway/hono/routes/projects.js +28 -0
  131. package/dist/src/gateway/hono/routes/projects.js.map +1 -1
  132. package/dist/src/gateway/run-loop.js +1 -1
  133. package/dist/src/gateway/service/run-gateway-agent.js +6 -2
  134. package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
  135. package/dist/src/mcp/channel-bridge.js +1 -1
  136. package/dist/src/pets/factory.d.ts +25 -0
  137. package/dist/src/pets/factory.js +327 -0
  138. package/dist/src/pets/factory.js.map +1 -0
  139. package/dist/src/pets/manifest.d.ts +2 -0
  140. package/dist/src/pets/manifest.js +16 -0
  141. package/dist/src/pets/manifest.js.map +1 -0
  142. package/dist/src/pets/validator.d.ts +12 -0
  143. package/dist/src/pets/validator.js +175 -0
  144. package/dist/src/pets/validator.js.map +1 -0
  145. package/dist/src/projects/project-service.d.ts +2 -0
  146. package/dist/src/projects/project-service.js +6 -0
  147. package/dist/src/projects/project-service.js.map +1 -1
  148. package/dist/src/projects/project-store.d.ts +1 -0
  149. package/dist/src/projects/project-store.js +14 -7
  150. package/dist/src/projects/project-store.js.map +1 -1
  151. package/dist/src/projects/types.d.ts +2 -0
  152. package/dist/src/session/session-title.js +22 -2
  153. package/dist/src/session/session-title.js.map +1 -1
  154. package/dist/src/storage/sqlite/migrations/025_project_pinned_at.sql +5 -0
  155. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  156. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  157. package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
  158. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  159. package/dist/src/storage/sqlite/schema.js +1 -1
  160. package/package.json +1 -1
  161. package/skills/creative/hatch-pet/SKILL.md +63 -0
  162. package/dist/gateway/static/root/assets/agents-DRYVahI-.js +0 -2
  163. package/dist/gateway/static/root/assets/automations-page-D8hYQbkl.js +0 -4
  164. package/dist/gateway/static/root/assets/browser-settings-page-CiWEO-Iy.js +0 -8
  165. package/dist/gateway/static/root/assets/channels-settings-BddPdqVo.js +0 -1
  166. package/dist/gateway/static/root/assets/connectors-page-Ba2GDhSE.js +0 -2
  167. package/dist/gateway/static/root/assets/directory-picker-path-field-CiEc4KmY.js +0 -1
  168. package/dist/gateway/static/root/assets/dist-By6Rh2ee.js +0 -1
  169. package/dist/gateway/static/root/assets/dreaming-settings-4bvpk5wr.js +0 -3
  170. package/dist/gateway/static/root/assets/gateway-settings-KFsGGDhg.js +0 -1
  171. package/dist/gateway/static/root/assets/goal-detail-page-B482PSaG.js +0 -1
  172. package/dist/gateway/static/root/assets/goals-page-CUdgJuDn.js +0 -2
  173. package/dist/gateway/static/root/assets/index-CA2tR2vm.js +0 -256
  174. package/dist/gateway/static/root/assets/index-Ds3u0LOk.css +0 -1
  175. package/dist/gateway/static/root/assets/logs-page-BCporcNH.js +0 -2
  176. package/dist/gateway/static/root/assets/messages-C22hxE1N.js +0 -3
  177. package/dist/gateway/static/root/assets/models-hub-panel-D68Pyow7.js +0 -2
  178. package/dist/gateway/static/root/assets/notes-page-CuUMOiyv.js +0 -1
  179. package/dist/gateway/static/root/assets/notes-workbench-Dx2N5zTk.js +0 -2
  180. package/dist/gateway/static/root/assets/project-detail-page-sB8AzZi3.js +0 -1
  181. package/dist/gateway/static/root/assets/projects-page-LBnJqWK2.js +0 -1
  182. package/dist/gateway/static/root/assets/remote-access-hub-Dbj0o6SC.js +0 -1
  183. package/dist/gateway/static/root/assets/sessions-page-DhDZKspB.js +0 -1
  184. package/dist/gateway/static/root/assets/settings-advanced-gate-BvXLMNL6.js +0 -1
  185. package/dist/gateway/static/root/assets/settings-page-Cfm9UxAr.js +0 -1
  186. package/dist/gateway/static/root/assets/shares-settings-BtR4B0kn.js +0 -1
  187. package/dist/gateway/static/root/assets/skill-reload-api-CJNVOWoK.js +0 -1
  188. package/dist/gateway/static/root/assets/skills-page-DcWDHrt3.js +0 -2
  189. package/dist/gateway/static/root/assets/voice-api-key-field-DaJASKFP.js +0 -1
  190. package/dist/gateway/static/root/assets/work-item-detail-page-BrCZpAWh.js +0 -1
  191. package/dist/gateway/static/root/assets/workflows-page-vyJ8wSXm.js +0 -18
@@ -1 +1 @@
1
- {"version":3,"file":"projects.js","names":["path","record"],"sources":["../../../../../src/gateway/hono/routes/projects.ts"],"sourcesContent":["import type { Hono } from 'hono';\nimport { readdir, readFile, realpath, stat, writeFile } from 'node:fs/promises';\nimport * as path from 'node:path';\n\nimport { ActivityService } from '../../../activity/index.js';\nimport { resolveEffectiveAgentProfile } from '../../../config/agent-profile.js';\nimport type { GoalWithDetails } from '../../../goals/index.js';\nimport { GoalService } from '../../../goals/index.js';\nimport {\n buildProjectLoopOverview,\n inferProjectKind,\n inferSuggestedProjectDefaultAgentId,\n isValidProjectAgentId,\n normalizeProjectAgentId,\n ProjectWorkspaceConflictError,\n ProjectWorkspaceMissingError,\n type Project,\n resolveProjectAgentId,\n type ProjectStatus,\n type ProjectWorkflowRunBrief,\n} from '../../../projects/index.js';\nimport { buildSessionKey } from '../../../routing/session-key.js';\nimport {\n getSqliteDatabase,\n getSessionMetadata,\n listMemoryRecords,\n loadTranscriptRowsForSession,\n type SessionMetadataSeed,\n upsertMemoryRecord,\n} from '../../../storage/sqlite/index.js';\nimport {\n buildWorkItemAgentContext,\n WorkItemService,\n WORK_ITEM_ATTACHMENT_MAX_BYTES,\n WORK_ITEM_ATTACHMENT_MAX_COUNT,\n type WorkItemPriority,\n type WorkItemStatus,\n} from '../../../work-items/index.js';\nimport { createGatewayRouteLogger } from '../lib/route-logger.js';\nimport { parseActivityIncludeRelated, parseActivityQuery } from './activity.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nconst log = createGatewayRouteLogger('Projects');\n\nfunction parseProjectStatus(raw: unknown): ProjectStatus | undefined {\n return raw === 'active' || raw === 'paused' || raw === 'archived' ? raw : undefined;\n}\n\nfunction parseLimit(raw: string | undefined, fallback = 50): number | undefined {\n if (!raw) return undefined;\n const n = Number.parseInt(raw, 10);\n return Number.isFinite(n) ? Math.min(500, Math.max(1, n)) : fallback;\n}\n\nfunction isHiddenEmptyProjectChatShell(session: {\n hiddenFromSessionList?: boolean;\n messageCount?: number;\n routing?: { peerId?: string };\n customData?: Record<string, unknown>;\n}): boolean {\n return session.hiddenFromSessionList === true\n && session.messageCount === 0\n && session.customData?.genericNewChatShell !== false\n && Boolean(session.routing?.peerId?.startsWith('chat_'));\n}\n\nfunction textField(body: Record<string, unknown>, key: string): string | undefined {\n const value = body[key];\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction optionalTextField(body: Record<string, unknown>, key: string): string | null | undefined {\n if (!(key in body)) return undefined;\n const value = body[key];\n return typeof value === 'string' ? value : null;\n}\n\nfunction resolveEffectiveWorkspaceRoot(\n service: AuthenticatedRouteDeps['service'],\n project: Project,\n): string | undefined {\n const fixedRoot = project.workspaceRoot?.trim();\n if (fixedRoot) return fixedRoot;\n const agentId = resolveProjectAgentId({\n config: service.currentConfig,\n projects: service.projects,\n projectId: project.id,\n });\n return resolveEffectiveAgentProfile(service.currentConfig, agentId).resolvedWorkspacePath;\n}\n\nfunction enrichProjectWorkspace<T extends Project>(\n service: AuthenticatedRouteDeps['service'],\n project: T,\n): T {\n return {\n ...project,\n workspaceMode: project.workspaceRoot?.trim() ? 'fixed' : 'followAgent',\n effectiveWorkspaceRoot: resolveEffectiveWorkspaceRoot(service, project),\n };\n}\n\nfunction finiteNumberField(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) return value;\n if (typeof value === 'string' && value.trim()) {\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n }\n return undefined;\n}\n\nfunction collectUploadedFiles(body: Record<string, unknown>): File[] {\n const raw = body.file ?? body.files ?? body.attachments;\n const values = Array.isArray(raw) ? raw : raw ? [raw] : [];\n return values.filter((value): value is File => value instanceof File);\n}\n\nfunction validateUploadedWorkItemFiles(files: File[]): string | null {\n if (files.length > WORK_ITEM_ATTACHMENT_MAX_COUNT) {\n return `Too many attachments (max ${WORK_ITEM_ATTACHMENT_MAX_COUNT})`;\n }\n for (const file of files) {\n if (file.size > WORK_ITEM_ATTACHMENT_MAX_BYTES) {\n return `Attachment ${JSON.stringify(file.name || 'upload')} exceeds ${Math.floor(WORK_ITEM_ATTACHMENT_MAX_BYTES / (1024 * 1024))}MB limit`;\n }\n }\n return null;\n}\n\nasync function uploadedFileToBuffer(file: File): Promise<{ name: string; buffer: Buffer; mimeType: string }> {\n return {\n name: file.name || 'upload',\n buffer: Buffer.from(await file.arrayBuffer()),\n mimeType: file.type || 'application/octet-stream',\n };\n}\n\nfunction parseCsvEnum<T extends string>(raw: string | undefined, values: readonly T[]): T[] | undefined {\n if (!raw) return undefined;\n const allowed = new Set(values);\n const parsed = raw\n .split(',')\n .map((item) => item.trim())\n .filter((item): item is T => allowed.has(item as T));\n return parsed.length > 0 ? [...new Set(parsed)] : undefined;\n}\n\nfunction parseEnumValue<T extends string>(raw: unknown, values: readonly T[]): T | undefined {\n if (typeof raw !== 'string') return undefined;\n return values.includes(raw as T) ? raw as T : undefined;\n}\n\nconst WORK_ITEM_STATUSES = [\n 'backlog',\n 'todo',\n 'in_progress',\n 'blocked',\n 'needs_input',\n 'in_review',\n 'done',\n 'cancelled',\n] as const satisfies readonly WorkItemStatus[];\nconst WORK_ITEM_PRIORITIES = ['urgent', 'high', 'normal', 'low'] as const satisfies readonly WorkItemPriority[];\nconst WORK_ITEM_SUGGESTION_STATUSES = ['pending', 'applied', 'dismissed'] as const;\n\nconst SKIP_FILE_NAMES = new Set(['.git', 'node_modules']);\n\nconst PROJECT_FILE_MIME_BY_EXT: Record<string, string> = {\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n webp: 'image/webp',\n bmp: 'image/bmp',\n svg: 'image/svg+xml',\n pdf: 'application/pdf',\n docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n txt: 'text/plain',\n md: 'text/markdown',\n json: 'application/json',\n html: 'text/html',\n css: 'text/css',\n js: 'text/javascript',\n ts: 'text/typescript',\n mp3: 'audio/mpeg',\n wav: 'audio/wav',\n ogg: 'audio/ogg',\n webm: 'video/webm',\n mp4: 'video/mp4',\n mov: 'video/quicktime',\n};\n\nfunction normalizeRelativePath(raw: string | undefined): string {\n const normalized = (raw ?? '').trim().replaceAll('\\\\', '/');\n return normalized.replace(/^\\/+/, '');\n}\n\nfunction isWithinDirectory(root: string, target: string): boolean {\n const relativePath = path.relative(root, target);\n return relativePath === '' || (!relativePath.startsWith('..') && !path.isAbsolute(relativePath));\n}\n\nasync function resolveProjectWorkspaceRoot(\n service: AuthenticatedRouteDeps['service'],\n projectId: string,\n): Promise<{ ok: true; projectId: string; root: string } | { ok: false; status: number; error: string }> {\n const project = service.projects.get(projectId);\n if (!project) return { ok: false, status: 404, error: 'Project not found' };\n const workspaceRoot = resolveEffectiveWorkspaceRoot(service, project);\n if (!workspaceRoot?.trim()) {\n return { ok: false, status: 400, error: 'Project workspace root is not set' };\n }\n\n try {\n const root = await realpath(workspaceRoot);\n const rootStat = await stat(root);\n if (!rootStat.isDirectory()) {\n return { ok: false, status: 400, error: 'Project workspace root is not a directory' };\n }\n return { ok: true, projectId: project.id, root };\n } catch (err) {\n log.warn({ err, projectId: project.id, path: workspaceRoot }, 'project workspace root unavailable');\n return { ok: false, status: 404, error: 'Project workspace root is unavailable' };\n }\n}\n\nasync function resolveProjectWorkspacePath(\n service: AuthenticatedRouteDeps['service'],\n projectId: string,\n rawPath: string | undefined,\n): Promise<\n | { ok: true; projectId: string; root: string; requestedPath: string; absolutePath: string; relativePath: string }\n | { ok: false; status: number; error: string }\n> {\n const rootResult = await resolveProjectWorkspaceRoot(service, projectId);\n if (rootResult.ok === false) {\n return { ok: false, status: rootResult.status, error: rootResult.error };\n }\n\n const requestedPath = normalizeRelativePath(rawPath);\n const candidate = path.resolve(rootResult.root, requestedPath);\n if (!isWithinDirectory(rootResult.root, candidate)) {\n return { ok: false, status: 400, error: 'Path is outside project workspace' };\n }\n\n const relativePath = path.relative(rootResult.root, candidate).split(path.sep).join('/');\n return {\n ok: true,\n projectId: rootResult.projectId,\n root: rootResult.root,\n requestedPath,\n absolutePath: candidate,\n relativePath: relativePath === '.' ? '' : relativePath,\n };\n}\n\nasync function resolveExistingProjectWorkspacePath(\n service: AuthenticatedRouteDeps['service'],\n projectId: string,\n rawPath: string | undefined,\n): Promise<\n | {\n ok: true;\n projectId: string;\n root: string;\n requestedPath: string;\n absolutePath: string;\n relativePath: string;\n stat: Awaited<ReturnType<typeof stat>>;\n }\n | { ok: false; status: number; error: string }\n> {\n const resolved = await resolveProjectWorkspacePath(service, projectId, rawPath);\n if (resolved.ok === false) return resolved;\n if (!resolved.requestedPath.trim()) {\n return { ok: false, status: 400, error: 'Missing path' };\n }\n\n let realTarget: string;\n try {\n realTarget = await realpath(resolved.absolutePath);\n } catch {\n return { ok: false, status: 404, error: 'Not found' };\n }\n if (!isWithinDirectory(resolved.root, realTarget)) {\n return { ok: false, status: 400, error: 'Path is outside project workspace' };\n }\n const targetStat = await stat(realTarget);\n return {\n ...resolved,\n absolutePath: realTarget,\n stat: targetStat,\n };\n}\n\nasync function resolveProjectWorkspaceWritePath(\n service: AuthenticatedRouteDeps['service'],\n projectId: string,\n rawPath: string | undefined,\n): Promise<\n | {\n ok: true;\n projectId: string;\n root: string;\n requestedPath: string;\n absolutePath: string;\n relativePath: string;\n existingStat?: Awaited<ReturnType<typeof stat>>;\n }\n | { ok: false; status: number; error: string }\n> {\n const resolved = await resolveProjectWorkspacePath(service, projectId, rawPath);\n if (resolved.ok === false) return resolved;\n if (!resolved.requestedPath.trim()) {\n return { ok: false, status: 400, error: 'Missing path' };\n }\n\n try {\n const realTarget = await realpath(resolved.absolutePath);\n if (!isWithinDirectory(resolved.root, realTarget)) {\n return { ok: false, status: 400, error: 'Path is outside project workspace' };\n }\n return {\n ...resolved,\n absolutePath: realTarget,\n existingStat: await stat(realTarget),\n };\n } catch {\n const parentPath = path.dirname(resolved.absolutePath);\n try {\n const realParent = await realpath(parentPath);\n if (!isWithinDirectory(resolved.root, realParent)) {\n return { ok: false, status: 400, error: 'Path is outside project workspace' };\n }\n } catch {\n return { ok: false, status: 404, error: 'Parent directory not found' };\n }\n return resolved;\n }\n}\n\nfunction textFromTranscriptContent(content: unknown): string {\n if (typeof content === 'string') return content;\n if (!Array.isArray(content)) return '';\n return content\n .map((part) => {\n if (!part || typeof part !== 'object') return '';\n const record = part as Record<string, unknown>;\n return typeof record.text === 'string' ? record.text : '';\n })\n .filter(Boolean)\n .join('\\n');\n}\n\nfunction buildSessionSummaryMemoryContent(sessionKey: string, explicitSummary?: string): string {\n const summary = explicitSummary?.trim();\n if (summary) return summary;\n const rows = loadTranscriptRowsForSession(sessionKey)\n .filter((row) => {\n if (!row || typeof row !== 'object') return false;\n const record = row as unknown as Record<string, unknown>;\n const role = record.role;\n return role === 'user' || role === 'assistant' || role === 'compactionSummary' || role === 'branchSummary';\n })\n .slice(-12);\n const lines = rows\n .map((row) => {\n const record = row as unknown as Record<string, unknown>;\n const rowRole = typeof record.role === 'string' ? record.role : 'message';\n const role = rowRole === 'compactionSummary' || rowRole === 'branchSummary' ? 'summary' : rowRole;\n const text = (typeof record.summary === 'string' ? record.summary : undefined) ?? textFromTranscriptContent(record.content);\n const compact = text.trim().replace(/\\s+/g, ' ').slice(0, 280);\n return compact ? `- ${role}: ${compact}` : '';\n })\n .filter(Boolean);\n return lines.length > 0\n ? [`Session summary for ${sessionKey}:`, ...lines].join('\\n')\n : `Session summary for ${sessionKey}: no transcript content available.`;\n}\n\nfunction buildWorkItemChatSessionMetadata(params: {\n agentId: string;\n accountId: string;\n peerId: string;\n workItemId: string;\n title: string;\n updatedAt: number;\n}): SessionMetadataSeed {\n return {\n name: params.title,\n tags: ['work-item'],\n sourceChannel: 'webchat',\n sourceChatId: [params.accountId, 'direct', params.peerId].join(':'),\n sessionType: 'chat',\n hiddenFromSessionList: true,\n routing: {\n agentId: params.agentId,\n source: 'webchat',\n accountId: params.accountId,\n peerKind: 'direct',\n peerId: params.peerId,\n },\n customData: {\n genericNewChatShell: false,\n sourceBinding: {\n kind: 'work_item',\n sourceId: params.workItemId,\n version: String(params.updatedAt),\n attachedAt: Date.now(),\n },\n },\n };\n}\n\nfunction listFailedProjectWorkflowRuns(projectId: string, limit = 5): ProjectWorkflowRunBrief[] {\n const rows = getSqliteDatabase()\n .prepare(\n `SELECT run_id, definition_id, status, created_at_ms, error_message\n FROM workflow_runs\n WHERE project_id = ? AND status IN ('failed', 'timeout', 'cancelled')\n ORDER BY created_at_ms DESC\n LIMIT ?`,\n )\n .all(projectId, Math.max(1, Math.min(20, Math.floor(limit)))) as Array<{\n run_id: string;\n definition_id: string;\n status: string;\n created_at_ms: number;\n error_message: string | null;\n }>;\n return rows.map((row) => ({\n runId: row.run_id,\n definitionId: row.definition_id,\n status: row.status,\n createdAt: row.created_at_ms,\n errorMessage: row.error_message ?? undefined,\n }));\n}\n\nfunction buildProjectDigestMemoryContent(input: ReturnType<typeof buildProjectLoopOverview> & { projectName: string }): string {\n const lines = [\n `Project digest: ${input.projectName}`,\n `Status: ${input.digest.summary}`,\n input.digest.nextAction ? `Next: ${input.digest.nextAction}` : undefined,\n ].filter(Boolean) as string[];\n if (input.attentionItems.length > 0) {\n lines.push('', 'Attention:');\n for (const item of input.attentionItems.slice(0, 8)) {\n lines.push(`- ${item.kind}: ${item.title}${item.detail ? ` - ${item.detail}` : ''}`);\n }\n }\n if (input.timeline.length > 0) {\n lines.push('', 'Recent activity:');\n for (const item of input.timeline.slice(0, 8)) {\n lines.push(`- ${item.kind}: ${item.title}${item.detail ? ` - ${item.detail}` : ''}`);\n }\n }\n return lines.join('\\n');\n}\n\nfunction projectDigestMemoryRecordId(projectId: string): string {\n return `project-digest:${projectId}`;\n}\n\nexport function registerProjectsRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service } = deps;\n const activity = new ActivityService();\n const goals = new GoalService();\n const workItems = new WorkItemService();\n\n authenticated.post('/api/projects', async (c) => {\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const name = textField(body, 'name')?.trim();\n const workspaceRoot = textField(body, 'workspaceRoot')?.trim();\n if (!name && !workspaceRoot) return c.json({ ok: false, error: 'Missing name' }, 400);\n const hasDefaultAgentPatch = Object.hasOwn(body, 'defaultAgentId');\n const explicitDefaultAgentId = normalizeProjectAgentId(textField(body, 'defaultAgentId'));\n const defaultAgentId = hasDefaultAgentPatch\n ? explicitDefaultAgentId\n : inferSuggestedProjectDefaultAgentId({\n config: service.currentConfig,\n name,\n description: textField(body, 'description'),\n workspaceRoot,\n projectKind: textField(body, 'projectKind'),\n });\n if (!isValidProjectAgentId(service.currentConfig, defaultAgentId)) {\n return c.json({ ok: false, error: 'Default agent not found' }, 400);\n }\n try {\n const project = service.projects.create({\n name,\n description: textField(body, 'description'),\n defaultAgentId,\n workspaceRoot,\n createWorkspaceRoot: body.createWorkspaceRoot === true,\n projectKind: textField(body, 'projectKind'),\n brief: textField(body, 'brief'),\n instructions: textField(body, 'instructions'),\n });\n return c.json({ ok: true, project: enrichProjectWorkspace(service, project) }, 201);\n } catch (error) {\n if (error instanceof ProjectWorkspaceConflictError) {\n return c.json({ ok: false, code: 'workspace_already_bound', error: error.message, project: error.project }, 409);\n }\n if (error instanceof ProjectWorkspaceMissingError) {\n return c.json({ ok: false, code: 'workspace_root_missing', error: error.message, workspaceRoot: error.workspaceRoot }, 409);\n }\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 400);\n }\n });\n\n authenticated.get('/api/projects', async (c) => {\n const status = parseProjectStatus(c.req.query('status'));\n const result = service.projects.list({\n ...(status ? { status } : {}),\n search: c.req.query('search'),\n sortBy: c.req.query('sortBy') as 'updatedAt' | 'createdAt' | 'name' | undefined,\n sortOrder: c.req.query('sortOrder') as 'asc' | 'desc' | undefined,\n limit: parseLimit(c.req.query('limit')),\n offset: c.req.query('offset') ? Math.max(0, Number.parseInt(c.req.query('offset')!, 10) || 0) : undefined,\n });\n return c.json({ ok: true, ...result, items: result.items.map((project) => enrichProjectWorkspace(service, project)) });\n });\n\n authenticated.get('/api/projects/suggestions', async (c) => {\n const sessionKey = c.req.query('sessionKey')?.trim();\n return c.json({ ok: true, suggestions: sessionKey ? service.projects.suggestProjectsForSession(sessionKey) : [] });\n });\n\n authenticated.post('/api/projects/infer-defaults', async (c) => {\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const input = {\n name: textField(body, 'name'),\n description: textField(body, 'description'),\n workspaceRoot: textField(body, 'workspaceRoot'),\n projectKind: textField(body, 'projectKind'),\n };\n const inference = inferProjectKind(input);\n const defaultAgentId = inferSuggestedProjectDefaultAgentId({\n config: service.currentConfig,\n ...input,\n });\n return c.json({ ok: true, inference, defaultAgentId });\n });\n\n authenticated.post('/api/projects/resolve-workspace', async (c) => {\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const workspacePath = textField(body, 'workspacePath')?.trim();\n if (!workspacePath) return c.json({ ok: false, error: 'Missing workspacePath' }, 400);\n const agentId = textField(body, 'agentId')?.trim() || 'main';\n const suggestedDefaultAgentId = inferSuggestedProjectDefaultAgentId({\n config: service.currentConfig,\n workspaceRoot: workspacePath,\n projectKind: textField(body, 'projectKind'),\n });\n let match;\n try {\n match = service.projects.resolveOrCreateForWorkspacePath({\n workspacePath,\n agentId,\n defaultAgentId: suggestedDefaultAgentId,\n autoCreate: body.autoCreate !== false,\n });\n } catch (error) {\n if (error instanceof ProjectWorkspaceConflictError) {\n match = { project: error.project, reason: 'exact' as const, created: false };\n } else {\n throw error;\n }\n }\n if (!match) return c.json({ ok: true, project: null });\n\n const sessionKey = textField(body, 'sessionKey')?.trim();\n const projectDefaultAgentId = normalizeProjectAgentId(match.project.defaultAgentId);\n const shouldBindRequestedSession = !projectDefaultAgentId || projectDefaultAgentId === normalizeProjectAgentId(agentId);\n if (sessionKey && shouldBindRequestedSession) {\n const existingSession = getSessionMetadata(sessionKey);\n if (!existingSession) {\n await service.sessionIndexInstance.saveMessages(sessionKey, [], {\n metadata: {\n sourceChannel: 'tui',\n sourceChatId: `default:direct:${sessionKey}`,\n sessionType: 'chat',\n projectId: match.project.id,\n routing: {\n agentId,\n source: 'tui',\n accountId: 'default',\n peerKind: 'direct',\n peerId: sessionKey,\n },\n },\n });\n }\n service.projects.attachSession(sessionKey, match.project.id);\n }\n\n return c.json({ ok: true, ...match });\n });\n\n authenticated.get('/api/projects/:id/overview', async (c) => {\n const project = service.projects.getWithDetails(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const goalIds = service.projects.listGoalIds(project.id, parseLimit(c.req.query('goalLimit'), 100));\n const projectGoals = goalIds\n .map((id) => goals.get(id))\n .filter((goal): goal is GoalWithDetails => Boolean(goal));\n const loop = buildProjectLoopOverview({\n project,\n goals: projectGoals,\n recentWorkflowRuns: project.recentWorkflowRuns,\n failedWorkflowRuns: listFailedProjectWorkflowRuns(project.id),\n memoryRecords: listMemoryRecords({ projectId: project.id, status: 'active', limit: 5 }),\n });\n return c.json({\n ok: true,\n overview: {\n project: enrichProjectWorkspace(service, project),\n stats: {\n sessionCount: project.sessionCount,\n goalCount: project.goalCount,\n activeGoalCount: project.activeGoalCount,\n recentWorkflowRunCount: project.recentWorkflowRuns.length,\n staleGoalCount: loop.staleGoals.length,\n attentionCount: loop.attentionItems.length,\n failedWorkflowRunCount: loop.failedWorkflowRuns.length,\n },\n activeGoals: loop.activeGoals,\n blockedGoals: loop.blockedGoals,\n staleGoals: loop.staleGoals,\n nextActions: loop.nextActions,\n attentionItems: loop.attentionItems,\n timeline: loop.timeline,\n digest: loop.digest,\n failedWorkflowRuns: loop.failedWorkflowRuns,\n recentSessions: project.recentSessions,\n recentWorkflowRuns: project.recentWorkflowRuns,\n recommendedAction: loop.recommendedAction,\n },\n });\n });\n\n authenticated.get('/api/projects/:id/activity', (c) => {\n const project = service.projects.get(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const result = activity.listForProject({\n projectId: project.id,\n includeRelated: parseActivityIncludeRelated(c.req.query('includeRelated')),\n ...parseActivityQuery(c),\n });\n return c.json({ ok: true, ...result });\n });\n\n authenticated.get('/api/projects/:id/work-items', async (c) => {\n const project = service.projects.get(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const result = workItems.listProjectWorkItems(project.id, {\n status: parseCsvEnum(c.req.query('status'), WORK_ITEM_STATUSES),\n priority: parseCsvEnum(c.req.query('priority'), WORK_ITEM_PRIORITIES),\n includeArchived: c.req.query('includeArchived') === 'true',\n search: c.req.query('search'),\n sortBy: c.req.query('sortBy') as 'updatedAt' | 'createdAt' | 'priority' | 'status' | undefined,\n sortOrder: c.req.query('sortOrder') as 'asc' | 'desc' | undefined,\n limit: parseLimit(c.req.query('limit')),\n offset: c.req.query('offset') ? Math.max(0, Number.parseInt(c.req.query('offset')!, 10) || 0) : undefined,\n });\n return c.json({ ok: true, ...result });\n });\n\n authenticated.post('/api/projects/:id/work-items', async (c) => {\n const project = service.projects.get(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const contentType = c.req.header('content-type') || '';\n let body: Record<string, unknown>;\n let files: File[] = [];\n if (contentType.includes('multipart/form-data')) {\n try {\n body = await c.req.parseBody({ all: true }) as Record<string, unknown>;\n } catch {\n return c.json({ ok: false, error: 'Invalid multipart body' }, 400);\n }\n files = collectUploadedFiles(body);\n } else {\n body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n }\n const attachmentError = validateUploadedWorkItemFiles(files);\n if (attachmentError) return c.json({ ok: false, error: attachmentError }, 413);\n const title = textField(body, 'title')?.trim();\n if (!title) return c.json({ ok: false, error: 'Work item title is required' }, 400);\n const status = parseEnumValue(body.status, WORK_ITEM_STATUSES);\n const priority = parseEnumValue(body.priority, WORK_ITEM_PRIORITIES);\n const dueAt = finiteNumberField(body.dueAt);\n if (Object.hasOwn(body, 'status') && !status) return c.json({ ok: false, error: 'Invalid work item status' }, 400);\n if (Object.hasOwn(body, 'priority') && !priority) return c.json({ ok: false, error: 'Invalid work item priority' }, 400);\n if (Object.hasOwn(body, 'dueAt') && dueAt === undefined && body.dueAt !== null) return c.json({ ok: false, error: 'Invalid dueAt' }, 400);\n const uploads: Array<{ name: string; buffer: Buffer; mimeType: string }> = [];\n for (const file of files) {\n uploads.push(await uploadedFileToBuffer(file));\n }\n const item = workItems.createProjectWorkItem(project.id, {\n title,\n description: textField(body, 'description'),\n status,\n priority,\n ownerAgentId: textField(body, 'ownerAgentId') || project.defaultAgentId || undefined,\n nextAction: textField(body, 'nextAction'),\n blockedReason: textField(body, 'blockedReason'),\n dueAt,\n });\n for (const upload of uploads) {\n await workItems.addAttachment(item.id, upload);\n }\n const created = files.length > 0 ? workItems.getWorkItem(item.id) ?? item : item;\n return c.json({ ok: true, item: created }, 201);\n });\n\n authenticated.get('/api/work-items/:id', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n return c.json({ ok: true, item });\n });\n\n authenticated.get('/api/work-items/:id/attachments', async (c) => {\n const attachments = workItems.listAttachments(c.req.param('id'));\n if (!attachments) return c.json({ ok: false, error: 'Work item not found' }, 404);\n return c.json({ ok: true, attachments });\n });\n\n authenticated.post('/api/work-items/:id/attachments', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n let body: Record<string, unknown>;\n try {\n body = await c.req.parseBody({ all: true }) as Record<string, unknown>;\n } catch {\n return c.json({ ok: false, error: 'Invalid multipart body' }, 400);\n }\n const files = collectUploadedFiles(body);\n if (!files.length) return c.json({ ok: false, error: 'Missing file field' }, 400);\n const attachmentError = validateUploadedWorkItemFiles(files);\n if (attachmentError) return c.json({ ok: false, error: attachmentError }, 413);\n const attachments = [];\n for (const file of files) {\n const upload = await uploadedFileToBuffer(file);\n const attachment = await workItems.addAttachment(item.id, upload);\n if (attachment) attachments.push(attachment);\n }\n return c.json({ ok: true, attachments, item: workItems.getWorkItem(item.id) }, 201);\n });\n\n authenticated.get('/api/work-items/:id/attachments/:attachmentId/content', async (c) => {\n const result = await workItems.readAttachment(c.req.param('id'), c.req.param('attachmentId'));\n if (!result) return c.json({ ok: false, error: 'Attachment not found' }, 404);\n return new Response(result.buffer, {\n headers: {\n 'Content-Type': result.attachment.mimeType,\n 'Content-Length': String(result.attachment.size),\n 'Content-Disposition': `inline; filename=\"${encodeURIComponent(result.attachment.fileName)}\"`,\n 'Cache-Control': 'private, max-age=31536000, immutable',\n },\n });\n });\n\n authenticated.delete('/api/work-items/:id/attachments/:attachmentId', async (c) => {\n const attachment = await workItems.removeAttachment(c.req.param('id'), c.req.param('attachmentId'));\n if (!attachment) return c.json({ ok: false, error: 'Attachment not found' }, 404);\n return c.json({ ok: true, attachment, item: workItems.getWorkItem(c.req.param('id')) });\n });\n\n authenticated.patch('/api/work-items/:id', async (c) => {\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const status = Object.hasOwn(body, 'status')\n ? parseEnumValue(body.status, WORK_ITEM_STATUSES)\n : undefined;\n const priority = Object.hasOwn(body, 'priority')\n ? parseEnumValue(body.priority, WORK_ITEM_PRIORITIES)\n : undefined;\n const dueAt = Object.hasOwn(body, 'dueAt')\n ? (body.dueAt === null ? null : (typeof body.dueAt === 'number' && Number.isFinite(body.dueAt) ? body.dueAt : undefined))\n : undefined;\n const archivedAt = Object.hasOwn(body, 'archivedAt')\n ? (body.archivedAt === null ? null : (typeof body.archivedAt === 'number' && Number.isFinite(body.archivedAt) ? body.archivedAt : undefined))\n : undefined;\n if (status === undefined && Object.hasOwn(body, 'status')) return c.json({ ok: false, error: 'Invalid work item status' }, 400);\n if (priority === undefined && Object.hasOwn(body, 'priority')) return c.json({ ok: false, error: 'Invalid work item priority' }, 400);\n if (dueAt === undefined && Object.hasOwn(body, 'dueAt')) return c.json({ ok: false, error: 'Invalid dueAt' }, 400);\n if (archivedAt === undefined && Object.hasOwn(body, 'archivedAt')) return c.json({ ok: false, error: 'Invalid archivedAt' }, 400);\n\n const item = workItems.updateWorkItem(c.req.param('id'), {\n ...(Object.hasOwn(body, 'title') ? { title: textField(body, 'title') ?? '' } : {}),\n ...(Object.hasOwn(body, 'description') ? { description: optionalTextField(body, 'description') } : {}),\n ...(Object.hasOwn(body, 'status') ? { status } : {}),\n ...(Object.hasOwn(body, 'priority') ? { priority } : {}),\n ...(Object.hasOwn(body, 'ownerAgentId') ? { ownerAgentId: optionalTextField(body, 'ownerAgentId') } : {}),\n ...(Object.hasOwn(body, 'nextAction') ? { nextAction: optionalTextField(body, 'nextAction') } : {}),\n ...(Object.hasOwn(body, 'blockedReason') ? { blockedReason: optionalTextField(body, 'blockedReason') } : {}),\n ...(Object.hasOwn(body, 'dueAt') ? { dueAt } : {}),\n ...(Object.hasOwn(body, 'archivedAt') ? { archivedAt } : {}),\n });\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n return c.json({ ok: true, item });\n });\n\n authenticated.delete('/api/work-items/:id', async (c) => {\n const item = workItems.updateWorkItem(c.req.param('id'), { archivedAt: Date.now() });\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n return c.json({ ok: true, item });\n });\n\n authenticated.get('/api/work-items/:id/events', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n return c.json({ ok: true, events: workItems.listEvents(item.id) });\n });\n\n authenticated.get('/api/work-items/:id/update-suggestions', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n const status = parseEnumValue(c.req.query('status'), WORK_ITEM_SUGGESTION_STATUSES);\n if (c.req.query('status') && !status) return c.json({ ok: false, error: 'Invalid suggestion status' }, 400);\n return c.json({ ok: true, suggestions: workItems.listUpdateSuggestions(item.id, status) });\n });\n\n authenticated.post('/api/work-items/:id/update-suggestions', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const sourceKind = parseEnumValue(body.sourceKind, ['chat', 'goal', 'workflow_run', 'automation'] as const);\n const sourceId = textField(body, 'sourceId')?.trim();\n if (!sourceKind) return c.json({ ok: false, error: 'Invalid sourceKind' }, 400);\n if (!sourceId) return c.json({ ok: false, error: 'sourceId is required' }, 400);\n const patchBody = body.patch && typeof body.patch === 'object' && !Array.isArray(body.patch)\n ? body.patch as Record<string, unknown>\n : {};\n const status = Object.hasOwn(patchBody, 'status')\n ? parseEnumValue(patchBody.status, WORK_ITEM_STATUSES)\n : undefined;\n if (Object.hasOwn(patchBody, 'status') && !status) return c.json({ ok: false, error: 'Invalid work item status' }, 400);\n const confidence = typeof body.confidence === 'number' && Number.isFinite(body.confidence)\n ? Math.max(0, Math.min(1, body.confidence))\n : undefined;\n const suggestion = workItems.createUpdateSuggestion(item.id, {\n sourceKind,\n sourceId,\n patch: {\n ...(Object.hasOwn(patchBody, 'status') ? { status } : {}),\n ...(Object.hasOwn(patchBody, 'nextAction') ? { nextAction: optionalTextField(patchBody, 'nextAction') } : {}),\n ...(Object.hasOwn(patchBody, 'blockedReason') ? { blockedReason: optionalTextField(patchBody, 'blockedReason') } : {}),\n },\n progressNote: optionalTextField(body, 'progressNote') ?? undefined,\n rationale: optionalTextField(body, 'rationale') ?? undefined,\n confidence,\n });\n if (!suggestion) return c.json({ ok: false, error: 'Work item not found' }, 404);\n return c.json({ ok: true, suggestion }, 201);\n });\n\n authenticated.post('/api/work-item-update-suggestions/:id/apply', async (c) => {\n const result = workItems.applyUpdateSuggestion(c.req.param('id'));\n if (!result) return c.json({ ok: false, error: 'Suggestion not found or already resolved' }, 404);\n return c.json({ ok: true, item: result.item, suggestion: result.suggestion });\n });\n\n authenticated.post('/api/work-item-update-suggestions/:id/dismiss', async (c) => {\n const suggestion = workItems.dismissUpdateSuggestion(c.req.param('id'));\n if (!suggestion) return c.json({ ok: false, error: 'Suggestion not found or already resolved' }, 404);\n return c.json({ ok: true, suggestion });\n });\n\n authenticated.post('/api/work-items/:id/start-chat', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n const project = service.projects.get(item.projectId);\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const agentId = resolveProjectAgentId({\n config: service.currentConfig,\n projects: service.projects,\n explicitAgentId: item.ownerAgentId,\n projectId: project.id,\n });\n const peerId = `work_item_${Date.now()}`;\n const sessionKey = buildSessionKey({\n agentId,\n source: 'webchat',\n accountId: 'default',\n peerKind: 'direct',\n peerId,\n });\n await service.sessionIndexInstance.saveMessages(sessionKey, [], {\n metadata: buildWorkItemChatSessionMetadata({\n agentId,\n accountId: 'default',\n peerId,\n workItemId: item.id,\n title: item.title,\n updatedAt: item.updatedAt,\n }),\n });\n service.projects.attachSession(sessionKey, project.id);\n const session = await service.sessions.getSession(sessionKey);\n workItems.addLink(item.id, {\n kind: 'chat',\n targetId: sessionKey,\n title: session?.name || item.title,\n statusSnapshot: session?.status,\n }, 'chat_started');\n const updated = item.status === 'todo' || item.status === 'backlog'\n ? workItems.updateWorkItem(item.id, { status: 'in_progress' })\n : workItems.getWorkItem(item.id);\n return c.json({ ok: true, session, item: updated }, 201);\n });\n\n authenticated.post('/api/work-items/:id/create-goal', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n const project = service.projects.get(item.projectId);\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const attachments = await workItems.snapshotAttachmentsForGoal(item.id);\n if (!attachments) return c.json({ ok: false, error: 'Work item not found' }, 404);\n const context = await buildWorkItemAgentContext(item, { attachments, includeImages: false });\n const goal = goals.create({\n title: item.title,\n description: item.description || item.nextAction,\n priority: item.priority === 'urgent' ? 'high' : item.priority,\n agentId: item.ownerAgentId || project.defaultAgentId || undefined,\n projectId: project.id,\n source: 'api',\n config: service.currentConfig,\n });\n const goalWithContext = goals.setContextMessage({\n goalId: goal.id,\n text: context.text,\n attachments,\n }) ?? goal;\n workItems.addLink(item.id, {\n kind: 'goal',\n targetId: goal.id,\n title: goal.title,\n statusSnapshot: goal.status,\n }, 'goal_created');\n const updated = item.status === 'todo' || item.status === 'backlog'\n ? workItems.updateWorkItem(item.id, { status: 'in_progress' })\n : workItems.getWorkItem(item.id);\n return c.json({ ok: true, goal: goalWithContext, item: updated }, 201);\n });\n\n authenticated.post('/api/projects/:id/digest-memory', async (c) => {\n const project = service.projects.getWithDetails(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const goalIds = service.projects.listGoalIds(project.id, 100);\n const projectGoals = goalIds\n .map((id) => goals.get(id))\n .filter((goal): goal is GoalWithDetails => Boolean(goal));\n const loop = buildProjectLoopOverview({\n project,\n goals: projectGoals,\n recentWorkflowRuns: project.recentWorkflowRuns,\n failedWorkflowRuns: listFailedProjectWorkflowRuns(project.id),\n memoryRecords: listMemoryRecords({ projectId: project.id, status: 'active', limit: 5 }),\n });\n const record = upsertMemoryRecord({\n id: projectDigestMemoryRecordId(project.id),\n providerId: 'local',\n kind: 'daily_note',\n agentId: resolveProjectAgentId({\n config: service.currentConfig,\n projects: service.projects,\n projectId: project.id,\n }),\n workspaceId: project.workspaceRoot,\n projectId: project.id,\n content: buildProjectDigestMemoryContent({ ...loop, projectName: project.name }),\n source: {\n provider: 'project-digest',\n },\n confidence: 0.75,\n tags: ['project', 'project-digest', project.slug],\n status: 'active',\n sensitivity: 'normal',\n });\n return c.json({ ok: true, record }, 201);\n });\n\n authenticated.post('/api/projects/:id/blockers', async (c) => {\n const project = service.projects.getWithDetails(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const title = typeof body.title === 'string' ? body.title.trim() : '';\n if (!title) return c.json({ ok: false, error: 'Missing title' }, 400);\n const reason = typeof body.reason === 'string' ? body.reason.trim() : '';\n const goal = goals.create({\n title,\n description: reason || undefined,\n agentId: resolveProjectAgentId({\n config: service.currentConfig,\n projects: service.projects,\n projectId: project.id,\n }),\n priority: body.priority === 'low' || body.priority === 'normal' || body.priority === 'high' ? body.priority : 'high',\n source: 'api',\n projectId: project.id,\n });\n const blocked = goals.setStatus(goal.id, 'blocked', { reason: reason || title });\n if (reason) {\n goals.setContextMessage({ goalId: goal.id, text: reason });\n }\n return c.json({ ok: true, goal: blocked ?? goals.get(goal.id) }, 201);\n });\n\n authenticated.get('/api/projects/:id', async (c) => {\n const project = service.projects.getWithDetails(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n return c.json({ ok: true, project: enrichProjectWorkspace(service, project) });\n });\n\n authenticated.patch('/api/projects/:id', async (c) => {\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const status = parseProjectStatus(body.status);\n const defaultAgentPatch = optionalTextField(body, 'defaultAgentId');\n const defaultAgentId = defaultAgentPatch === undefined ? undefined : normalizeProjectAgentId(defaultAgentPatch);\n if (defaultAgentId && !isValidProjectAgentId(service.currentConfig, defaultAgentId)) {\n return c.json({ ok: false, error: 'Default agent not found' }, 400);\n }\n try {\n const project = service.projects.update(c.req.param('id'), {\n ...(textField(body, 'name') !== undefined ? { name: textField(body, 'name') } : {}),\n ...(optionalTextField(body, 'description') !== undefined ? { description: optionalTextField(body, 'description') } : {}),\n ...(status ? { status } : {}),\n ...(defaultAgentPatch !== undefined ? { defaultAgentId: defaultAgentId ?? null } : {}),\n ...(optionalTextField(body, 'workspaceRoot') !== undefined ? { workspaceRoot: optionalTextField(body, 'workspaceRoot') } : {}),\n createWorkspaceRoot: body.createWorkspaceRoot === true,\n ...(optionalTextField(body, 'brief') !== undefined ? { brief: optionalTextField(body, 'brief') } : {}),\n ...(optionalTextField(body, 'instructions') !== undefined ? { instructions: optionalTextField(body, 'instructions') } : {}),\n });\n return c.json({ ok: true, project: enrichProjectWorkspace(service, project) });\n } catch (error) {\n if (error instanceof ProjectWorkspaceConflictError) {\n return c.json({ ok: false, code: 'workspace_already_bound', error: error.message, project: error.project }, 409);\n }\n if (error instanceof ProjectWorkspaceMissingError) {\n return c.json({ ok: false, code: 'workspace_root_missing', error: error.message, workspaceRoot: error.workspaceRoot }, 409);\n }\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.delete('/api/projects/:id', async (c) => {\n service.projects.delete(c.req.param('id'));\n return c.json({ ok: true });\n });\n\n authenticated.get('/api/projects/:id/sessions', async (c) => {\n try {\n const keys = service.projects.listSessionKeys(c.req.param('id'), parseLimit(c.req.query('limit'), 100));\n const sessions = await Promise.all(keys.map((key) => service.sessions.getSession(key)));\n return c.json({\n ok: true,\n sessions: sessions.filter((session) => session && !isHiddenEmptyProjectChatShell(session)),\n });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.get('/api/projects/:id/goals', async (c) => {\n try {\n const ids = service.projects.listGoalIds(c.req.param('id'), parseLimit(c.req.query('limit'), 100));\n return c.json({ ok: true, goals: ids.map((id) => goals.get(id)).filter(Boolean) });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.get('/api/projects/:id/files', async (c) => {\n const resolved = await resolveProjectWorkspacePath(service, c.req.param('id'), c.req.query('path'));\n if (resolved.ok === false) return c.json({ ok: false, error: resolved.error }, resolved.status as 400);\n const { root, absolutePath: candidate } = resolved;\n let currentPath: string;\n try {\n currentPath = await realpath(candidate);\n if (!isWithinDirectory(root, currentPath)) {\n return c.json({ ok: false, error: 'Path is outside project workspace' }, 400);\n }\n const currentStat = await stat(currentPath);\n if (!currentStat.isDirectory()) {\n return c.json({ ok: false, error: 'Path is not a directory' }, 400);\n }\n } catch (err) {\n log.warn({ err, projectId: resolved.projectId, path: candidate }, 'project file path unavailable');\n return c.json({ ok: false, error: 'Path not found' }, 404);\n }\n\n try {\n const dirents = await readdir(currentPath, { withFileTypes: true });\n const entries = await Promise.all(dirents\n .filter((entry) => !SKIP_FILE_NAMES.has(entry.name))\n .map(async (entry) => {\n const displayPath = path.join(currentPath, entry.name);\n const absolutePath = await realpath(displayPath).catch(() => null);\n if (!absolutePath || !isWithinDirectory(root, absolutePath)) return null;\n const entryStat = await stat(absolutePath).catch(() => null);\n if (!entryStat) return null;\n const relativePath = path.relative(root, displayPath).split(path.sep).join('/');\n return {\n name: entry.name,\n path: relativePath,\n absolutePath,\n type: entryStat.isDirectory() ? 'directory' : 'file',\n size: entryStat?.isFile() ? entryStat.size : undefined,\n updatedAt: entryStat?.mtime.toISOString(),\n };\n }));\n const visibleEntries = entries.filter((entry): entry is NonNullable<typeof entry> => entry !== null);\n visibleEntries.sort((left, right) => {\n if (left.type !== right.type) return left.type === 'directory' ? -1 : 1;\n return left.name.localeCompare(right.name);\n });\n const relativeCurrentPath = path.relative(root, currentPath).split(path.sep).join('/');\n const parentRelativePath = relativeCurrentPath ? path.dirname(relativeCurrentPath).replaceAll('\\\\', '/') : null;\n return c.json({\n ok: true,\n root,\n path: relativeCurrentPath === '.' ? '' : relativeCurrentPath,\n parentPath: parentRelativePath === '.' ? '' : parentRelativePath,\n entries: visibleEntries,\n });\n } catch (err) {\n log.warn({ err, projectId: resolved.projectId, path: currentPath }, 'project file list failed');\n if ((err as NodeJS.ErrnoException)?.code === 'EACCES') {\n return c.json({ ok: false, error: 'Permission denied' }, 403);\n }\n return c.json({ ok: false, error: 'Failed to read project files' }, 500);\n }\n });\n\n authenticated.get('/api/projects/:id/files/read', async (c) => {\n const resolved = await resolveExistingProjectWorkspacePath(service, c.req.param('id'), c.req.query('path'));\n if (resolved.ok === false) return c.json({ ok: false, error: { message: resolved.error } }, resolved.status as 400);\n if (!resolved.stat.isFile()) {\n return c.json({ ok: false, error: { message: 'Not a file' } }, 400);\n }\n try {\n const content = await readFile(resolved.absolutePath, 'utf-8');\n return c.json({\n ok: true,\n payload: {\n content,\n path: resolved.relativePath,\n absolutePath: resolved.absolutePath,\n mtimeMs: resolved.stat.mtimeMs,\n },\n });\n } catch {\n return c.json({ ok: false, error: { message: 'Read failed' } }, 500);\n }\n });\n\n authenticated.get('/api/projects/:id/files/raw', async (c) => {\n const resolved = await resolveExistingProjectWorkspacePath(service, c.req.param('id'), c.req.query('path'));\n if (resolved.ok === false) return c.json({ ok: false, error: { message: resolved.error } }, resolved.status as 400);\n if (!resolved.stat.isFile()) {\n return c.json({ ok: false, error: { message: 'Not a file' } }, 400);\n }\n const ext = resolved.relativePath.split('.').pop()?.toLowerCase() ?? '';\n const contentType = PROJECT_FILE_MIME_BY_EXT[ext] || 'application/octet-stream';\n try {\n const buf = await readFile(resolved.absolutePath);\n return new Response(buf, {\n headers: {\n 'Content-Type': contentType,\n 'Cache-Control': 'private, max-age=3600',\n },\n });\n } catch {\n return c.json({ ok: false, error: { message: 'Read failed' } }, 500);\n }\n });\n\n authenticated.get('/api/projects/:id/files/resolve-reference', async (c) => {\n const rawPath = typeof c.req.query('path') === 'string' ? c.req.query('path')!.trim() : '';\n if (!rawPath) {\n return c.json({ ok: false, error: { code: 'INVALID_PATH', message: 'Missing path' } }, 400);\n }\n const resolved = await resolveProjectWorkspacePath(service, c.req.param('id'), rawPath);\n if (resolved.ok === false) {\n return c.json({ ok: false, error: { code: 'PROJECT_WORKSPACE_RESOLUTION_FAILED', message: resolved.error } }, resolved.status as 400);\n }\n let st: Awaited<ReturnType<typeof stat>> | null = null;\n let absolutePath = resolved.absolutePath;\n try {\n absolutePath = await realpath(resolved.absolutePath);\n if (!isWithinDirectory(resolved.root, absolutePath)) {\n return c.json({\n ok: false,\n error: { code: 'PROJECT_WORKSPACE_RESOLUTION_FAILED', message: 'Path is outside project workspace' },\n }, 400);\n }\n st = await stat(absolutePath);\n } catch {\n st = null;\n }\n const displayName = path.basename(rawPath);\n if (!st) {\n return c.json({\n ok: true,\n payload: {\n inputPath: rawPath,\n displayName,\n scope: 'missing',\n exists: false,\n absolutePath: resolved.absolutePath,\n capabilities: ['copyPath'],\n errorCode: 'FILE_NOT_FOUND',\n },\n });\n }\n return c.json({\n ok: true,\n payload: {\n inputPath: rawPath,\n displayName,\n scope: 'workspace',\n exists: true,\n isDirectory: st.isDirectory(),\n absolutePath,\n workspaceRelativePath: resolved.relativePath,\n capabilities: st.isDirectory()\n ? ['openExternal', 'revealInFolder', 'copyPath']\n : ['preview', 'edit', 'openExternal', 'revealInFolder', 'copyPath'],\n mtimeMs: st.mtimeMs,\n },\n });\n });\n\n authenticated.put('/api/projects/:id/files/write', async (c) => {\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json({ ok: false, error: { message: 'Invalid JSON' } }, 400);\n }\n const bodyRecord = typeof body === 'object' && body !== null ? body as Record<string, unknown> : {};\n const pathRel = typeof bodyRecord.path === 'string' ? bodyRecord.path : '';\n const content = typeof bodyRecord.content === 'string' ? bodyRecord.content : '';\n if (!pathRel.trim()) {\n return c.json({ ok: false, error: { message: 'Missing path' } }, 400);\n }\n const resolved = await resolveProjectWorkspaceWritePath(service, c.req.param('id'), pathRel);\n if (resolved.ok === false) return c.json({ ok: false, error: { message: resolved.error } }, resolved.status as 400);\n if (resolved.existingStat && !resolved.existingStat.isFile()) {\n return c.json({ ok: false, error: { message: 'Not a file' } }, 400);\n }\n try {\n await writeFile(resolved.absolutePath, content, 'utf-8');\n const mtimeMs = (await stat(resolved.absolutePath).catch(() => ({ mtimeMs: Date.now() }))).mtimeMs;\n return c.json({\n ok: true,\n payload: { path: resolved.relativePath, mtimeMs },\n });\n } catch (err) {\n log.error({ err, projectId: resolved.projectId, path: resolved.absolutePath }, 'project file write failed');\n return c.json({ ok: false, error: { message: 'Write failed' } }, 500);\n }\n });\n\n authenticated.post('/api/projects/:id/sessions/:sessionKey', async (c) => {\n try {\n service.projects.attachSession(c.req.param('sessionKey'), c.req.param('id'));\n const session = await service.sessions.getSession(c.req.param('sessionKey'));\n return c.json({ ok: true, session });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.delete('/api/projects/:id/sessions/:sessionKey', async (c) => {\n try {\n const projectId = c.req.param('id');\n const sessionKey = c.req.param('sessionKey');\n if (!service.projects.get(projectId)) {\n return c.json({ ok: false, error: 'Project not found' }, 404);\n }\n const session = await service.sessions.getSession(sessionKey);\n if (!session) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n if (session.projectId !== projectId) {\n return c.json({ ok: false, error: 'Session is not attached to this project' }, 409);\n }\n service.projects.detachSession(sessionKey);\n return c.json({ ok: true });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.post('/api/projects/:id/sessions/:sessionKey/summary-memory', async (c) => {\n const projectId = c.req.param('id');\n const sessionKey = c.req.param('sessionKey');\n const project = service.projects.get(projectId);\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const session = getSessionMetadata(sessionKey);\n if (!session) return c.json({ ok: false, error: 'Session not found' }, 404);\n if (session.projectId !== projectId) {\n return c.json({ ok: false, error: 'Session is not attached to this project' }, 409);\n }\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const content = buildSessionSummaryMemoryContent(\n sessionKey,\n typeof body.summary === 'string' ? body.summary : undefined,\n );\n const record = upsertMemoryRecord({\n providerId: 'local',\n kind: 'session_summary',\n agentId: session.routing?.agentId ?? 'main',\n workspaceId: session.cwd,\n sessionKey,\n projectId,\n content,\n source: {\n provider: 'project-summary',\n sessionEntryId: sessionKey,\n },\n confidence: typeof body.confidence === 'number' ? body.confidence : 0.7,\n tags: ['project', 'session-summary', project.slug],\n status: 'active',\n sensitivity: 'normal',\n evidence: [{ sessionKey }],\n });\n return c.json({ ok: true, record }, 201);\n });\n\n authenticated.post('/api/projects/:id/goals/:goalId', async (c) => {\n try {\n service.projects.attachGoal(c.req.param('goalId'), c.req.param('id'));\n return c.json({ ok: true, goal: goals.get(c.req.param('goalId')) });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.delete('/api/projects/:id/goals/:goalId', async (c) => {\n try {\n const projectId = c.req.param('id');\n const goalId = c.req.param('goalId');\n if (!service.projects.get(projectId)) {\n return c.json({ ok: false, error: 'Project not found' }, 404);\n }\n const goal = goals.get(goalId);\n if (!goal) {\n return c.json({ ok: false, error: 'Goal not found' }, 404);\n }\n if (goal.projectId !== projectId) {\n return c.json({ ok: false, error: 'Goal is not attached to this project' }, 409);\n }\n service.projects.detachGoal(goalId);\n return c.json({ ok: true });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;kBAqBkE;AAqBlE,MAAM,MAAM,yBAAyB,WAAW;AAEhD,SAAS,mBAAmB,KAAyC;AACnE,QAAO,QAAQ,YAAY,QAAQ,YAAY,QAAQ,aAAa,MAAM,KAAA;;AAG5E,SAAS,WAAW,KAAyB,WAAW,IAAwB;AAC9E,KAAI,CAAC,IAAK,QAAO,KAAA;CACjB,MAAM,IAAI,OAAO,SAAS,KAAK,GAAG;AAClC,QAAO,OAAO,SAAS,EAAE,GAAG,KAAK,IAAI,KAAK,KAAK,IAAI,GAAG,EAAE,CAAC,GAAG;;AAG9D,SAAS,8BAA8B,SAK3B;AACV,QAAO,QAAQ,0BAA0B,QACpC,QAAQ,iBAAiB,KACzB,QAAQ,YAAY,wBAAwB,SAC5C,QAAQ,QAAQ,SAAS,QAAQ,WAAW,QAAQ,CAAC;;AAG5D,SAAS,UAAU,MAA+B,KAAiC;CACjF,MAAM,QAAQ,KAAK;AACnB,QAAO,OAAO,UAAU,WAAW,QAAQ,KAAA;;AAG7C,SAAS,kBAAkB,MAA+B,KAAwC;AAChG,KAAI,EAAE,OAAO,MAAO,QAAO,KAAA;CAC3B,MAAM,QAAQ,KAAK;AACnB,QAAO,OAAO,UAAU,WAAW,QAAQ;;AAG7C,SAAS,8BACP,SACA,SACoB;CACpB,MAAM,YAAY,QAAQ,eAAe,MAAM;AAC/C,KAAI,UAAW,QAAO;CACtB,MAAM,UAAU,sBAAsB;EACpC,QAAQ,QAAQ;EAChB,UAAU,QAAQ;EAClB,WAAW,QAAQ;EACpB,CAAC;AACF,QAAO,6BAA6B,QAAQ,eAAe,QAAQ,CAAC;;AAGtE,SAAS,uBACP,SACA,SACG;AACH,QAAO;EACL,GAAG;EACH,eAAe,QAAQ,eAAe,MAAM,GAAG,UAAU;EACzD,wBAAwB,8BAA8B,SAAS,QAAQ;EACxE;;AAGH,SAAS,kBAAkB,OAAoC;AAC7D,KAAI,OAAO,UAAU,YAAY,OAAO,SAAS,MAAM,CAAE,QAAO;AAChE,KAAI,OAAO,UAAU,YAAY,MAAM,MAAM,EAAE;EAC7C,MAAM,SAAS,OAAO,MAAM;AAC5B,SAAO,OAAO,SAAS,OAAO,GAAG,SAAS,KAAA;;;AAK9C,SAAS,qBAAqB,MAAuC;CACnE,MAAM,MAAM,KAAK,QAAQ,KAAK,SAAS,KAAK;AAE5C,SADe,MAAM,QAAQ,IAAI,GAAG,MAAM,MAAM,CAAC,IAAI,GAAG,EAAE,EAC5C,QAAQ,UAAyB,iBAAiB,KAAK;;AAGvE,SAAS,8BAA8B,OAA8B;AACnE,KAAI,MAAM,SAAA,GACR,QAAO;AAET,MAAK,MAAM,QAAQ,MACjB,KAAI,KAAK,OAAA,SACP,QAAO,cAAc,KAAK,UAAU,KAAK,QAAQ,SAAS,CAAC,WAAW,KAAK,MAAM,kCAAkC,OAAO,MAAM,CAAC;AAGrI,QAAO;;AAGT,eAAe,qBAAqB,MAAyE;AAC3G,QAAO;EACL,MAAM,KAAK,QAAQ;EACnB,QAAQ,OAAO,KAAK,MAAM,KAAK,aAAa,CAAC;EAC7C,UAAU,KAAK,QAAQ;EACxB;;AAGH,SAAS,aAA+B,KAAyB,QAAuC;AACtG,KAAI,CAAC,IAAK,QAAO,KAAA;CACjB,MAAM,UAAU,IAAI,IAAI,OAAO;CAC/B,MAAM,SAAS,IACZ,MAAM,IAAI,CACV,KAAK,SAAS,KAAK,MAAM,CAAC,CAC1B,QAAQ,SAAoB,QAAQ,IAAI,KAAU,CAAC;AACtD,QAAO,OAAO,SAAS,IAAI,CAAC,GAAG,IAAI,IAAI,OAAO,CAAC,GAAG,KAAA;;AAGpD,SAAS,eAAiC,KAAc,QAAqC;AAC3F,KAAI,OAAO,QAAQ,SAAU,QAAO,KAAA;AACpC,QAAO,OAAO,SAAS,IAAS,GAAG,MAAW,KAAA;;AAGhD,MAAM,qBAAqB;CACzB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AACD,MAAM,uBAAuB;CAAC;CAAU;CAAQ;CAAU;CAAM;AAChE,MAAM,gCAAgC;CAAC;CAAW;CAAW;CAAY;AAEzE,MAAM,kBAAkB,IAAI,IAAI,CAAC,QAAQ,eAAe,CAAC;AAEzD,MAAM,2BAAmD;CACvD,KAAK;CACL,KAAK;CACL,MAAM;CACN,KAAK;CACL,MAAM;CACN,KAAK;CACL,KAAK;CACL,KAAK;CACL,MAAM;CACN,MAAM;CACN,MAAM;CACN,KAAK;CACL,IAAI;CACJ,MAAM;CACN,MAAM;CACN,KAAK;CACL,IAAI;CACJ,IAAI;CACJ,KAAK;CACL,KAAK;CACL,KAAK;CACL,MAAM;CACN,KAAK;CACL,KAAK;CACN;AAED,SAAS,sBAAsB,KAAiC;AAE9D,SADoB,OAAO,IAAI,MAAM,CAAC,WAAW,MAAM,IACtC,CAAC,QAAQ,QAAQ,GAAG;;AAGvC,SAAS,kBAAkB,MAAc,QAAyB;CAChE,MAAM,eAAeA,OAAK,SAAS,MAAM,OAAO;AAChD,QAAO,iBAAiB,MAAO,CAAC,aAAa,WAAW,KAAK,IAAI,CAACA,OAAK,WAAW,aAAa;;AAGjG,eAAe,4BACb,SACA,WACuG;CACvG,MAAM,UAAU,QAAQ,SAAS,IAAI,UAAU;AAC/C,KAAI,CAAC,QAAS,QAAO;EAAE,IAAI;EAAO,QAAQ;EAAK,OAAO;EAAqB;CAC3E,MAAM,gBAAgB,8BAA8B,SAAS,QAAQ;AACrE,KAAI,CAAC,eAAe,MAAM,CACxB,QAAO;EAAE,IAAI;EAAO,QAAQ;EAAK,OAAO;EAAqC;AAG/E,KAAI;EACF,MAAM,OAAO,MAAM,SAAS,cAAc;AAE1C,MAAI,EAAC,MADkB,KAAK,KAAK,EACnB,aAAa,CACzB,QAAO;GAAE,IAAI;GAAO,QAAQ;GAAK,OAAO;GAA6C;AAEvF,SAAO;GAAE,IAAI;GAAM,WAAW,QAAQ;GAAI;GAAM;UACzC,KAAK;AACZ,MAAI,KAAK;GAAE;GAAK,WAAW,QAAQ;GAAI,MAAM;GAAe,EAAE,qCAAqC;AACnG,SAAO;GAAE,IAAI;GAAO,QAAQ;GAAK,OAAO;GAAyC;;;AAIrF,eAAe,4BACb,SACA,WACA,SAIA;CACA,MAAM,aAAa,MAAM,4BAA4B,SAAS,UAAU;AACxE,KAAI,WAAW,OAAO,MACpB,QAAO;EAAE,IAAI;EAAO,QAAQ,WAAW;EAAQ,OAAO,WAAW;EAAO;CAG1E,MAAM,gBAAgB,sBAAsB,QAAQ;CACpD,MAAM,YAAYA,OAAK,QAAQ,WAAW,MAAM,cAAc;AAC9D,KAAI,CAAC,kBAAkB,WAAW,MAAM,UAAU,CAChD,QAAO;EAAE,IAAI;EAAO,QAAQ;EAAK,OAAO;EAAqC;CAG/E,MAAM,eAAeA,OAAK,SAAS,WAAW,MAAM,UAAU,CAAC,MAAMA,OAAK,IAAI,CAAC,KAAK,IAAI;AACxF,QAAO;EACL,IAAI;EACJ,WAAW,WAAW;EACtB,MAAM,WAAW;EACjB;EACA,cAAc;EACd,cAAc,iBAAiB,MAAM,KAAK;EAC3C;;AAGH,eAAe,oCACb,SACA,WACA,SAYA;CACA,MAAM,WAAW,MAAM,4BAA4B,SAAS,WAAW,QAAQ;AAC/E,KAAI,SAAS,OAAO,MAAO,QAAO;AAClC,KAAI,CAAC,SAAS,cAAc,MAAM,CAChC,QAAO;EAAE,IAAI;EAAO,QAAQ;EAAK,OAAO;EAAgB;CAG1D,IAAI;AACJ,KAAI;AACF,eAAa,MAAM,SAAS,SAAS,aAAa;SAC5C;AACN,SAAO;GAAE,IAAI;GAAO,QAAQ;GAAK,OAAO;GAAa;;AAEvD,KAAI,CAAC,kBAAkB,SAAS,MAAM,WAAW,CAC/C,QAAO;EAAE,IAAI;EAAO,QAAQ;EAAK,OAAO;EAAqC;CAE/E,MAAM,aAAa,MAAM,KAAK,WAAW;AACzC,QAAO;EACL,GAAG;EACH,cAAc;EACd,MAAM;EACP;;AAGH,eAAe,iCACb,SACA,WACA,SAYA;CACA,MAAM,WAAW,MAAM,4BAA4B,SAAS,WAAW,QAAQ;AAC/E,KAAI,SAAS,OAAO,MAAO,QAAO;AAClC,KAAI,CAAC,SAAS,cAAc,MAAM,CAChC,QAAO;EAAE,IAAI;EAAO,QAAQ;EAAK,OAAO;EAAgB;AAG1D,KAAI;EACF,MAAM,aAAa,MAAM,SAAS,SAAS,aAAa;AACxD,MAAI,CAAC,kBAAkB,SAAS,MAAM,WAAW,CAC/C,QAAO;GAAE,IAAI;GAAO,QAAQ;GAAK,OAAO;GAAqC;AAE/E,SAAO;GACL,GAAG;GACH,cAAc;GACd,cAAc,MAAM,KAAK,WAAW;GACrC;SACK;EACN,MAAM,aAAaA,OAAK,QAAQ,SAAS,aAAa;AACtD,MAAI;GACF,MAAM,aAAa,MAAM,SAAS,WAAW;AAC7C,OAAI,CAAC,kBAAkB,SAAS,MAAM,WAAW,CAC/C,QAAO;IAAE,IAAI;IAAO,QAAQ;IAAK,OAAO;IAAqC;UAEzE;AACN,UAAO;IAAE,IAAI;IAAO,QAAQ;IAAK,OAAO;IAA8B;;AAExE,SAAO;;;AAIX,SAAS,0BAA0B,SAA0B;AAC3D,KAAI,OAAO,YAAY,SAAU,QAAO;AACxC,KAAI,CAAC,MAAM,QAAQ,QAAQ,CAAE,QAAO;AACpC,QAAO,QACJ,KAAK,SAAS;AACb,MAAI,CAAC,QAAQ,OAAO,SAAS,SAAU,QAAO;EAC9C,MAAM,SAAS;AACf,SAAO,OAAO,OAAO,SAAS,WAAW,OAAO,OAAO;GACvD,CACD,OAAO,QAAQ,CACf,KAAK,KAAK;;AAGf,SAAS,iCAAiC,YAAoB,iBAAkC;CAC9F,MAAM,UAAU,iBAAiB,MAAM;AACvC,KAAI,QAAS,QAAO;CASpB,MAAM,QARO,6BAA6B,WAAW,CAClD,QAAQ,QAAQ;AACf,MAAI,CAAC,OAAO,OAAO,QAAQ,SAAU,QAAO;EAE5C,MAAM,OAAOC,IAAO;AACpB,SAAO,SAAS,UAAU,SAAS,eAAe,SAAS,uBAAuB,SAAS;GAC3F,CACD,MAAM,IACS,CACf,KAAK,QAAQ;EACZ,MAAM,SAAS;EACf,MAAM,UAAU,OAAO,OAAO,SAAS,WAAW,OAAO,OAAO;EAChE,MAAM,OAAO,YAAY,uBAAuB,YAAY,kBAAkB,YAAY;EAE1F,MAAM,YADQ,OAAO,OAAO,YAAY,WAAW,OAAO,UAAU,KAAA,MAAc,0BAA0B,OAAO,QAAQ,EACtG,MAAM,CAAC,QAAQ,QAAQ,IAAI,CAAC,MAAM,GAAG,IAAI;AAC9D,SAAO,UAAU,KAAK,KAAK,IAAI,YAAY;GAC3C,CACD,OAAO,QAAQ;AAClB,QAAO,MAAM,SAAS,IAClB,CAAC,uBAAuB,WAAW,IAAI,GAAG,MAAM,CAAC,KAAK,KAAK,GAC3D,uBAAuB,WAAW;;AAGxC,SAAS,iCAAiC,QAOlB;AACtB,QAAO;EACL,MAAM,OAAO;EACb,MAAM,CAAC,YAAY;EACnB,eAAe;EACf,cAAc;GAAC,OAAO;GAAW;GAAU,OAAO;GAAO,CAAC,KAAK,IAAI;EACnE,aAAa;EACb,uBAAuB;EACvB,SAAS;GACP,SAAS,OAAO;GAChB,QAAQ;GACR,WAAW,OAAO;GAClB,UAAU;GACV,QAAQ,OAAO;GAChB;EACD,YAAY;GACV,qBAAqB;GACrB,eAAe;IACb,MAAM;IACN,UAAU,OAAO;IACjB,SAAS,OAAO,OAAO,UAAU;IACjC,YAAY,KAAK,KAAK;IACvB;GACF;EACF;;AAGH,SAAS,8BAA8B,WAAmB,QAAQ,GAA8B;AAgB9F,QAfa,mBAAmB,CAC7B,QACC;;;;gBAKD,CACA,IAAI,WAAW,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,KAAK,MAAM,MAAM,CAAC,CAAC,CAOnD,CAAC,KAAK,SAAS;EACxB,OAAO,IAAI;EACX,cAAc,IAAI;EAClB,QAAQ,IAAI;EACZ,WAAW,IAAI;EACf,cAAc,IAAI,iBAAiB,KAAA;EACpC,EAAE;;AAGL,SAAS,gCAAgC,OAAsF;CAC7H,MAAM,QAAQ;EACZ,mBAAmB,MAAM;EACzB,WAAW,MAAM,OAAO;EACxB,MAAM,OAAO,aAAa,SAAS,MAAM,OAAO,eAAe,KAAA;EAChE,CAAC,OAAO,QAAQ;AACjB,KAAI,MAAM,eAAe,SAAS,GAAG;AACnC,QAAM,KAAK,IAAI,aAAa;AAC5B,OAAK,MAAM,QAAQ,MAAM,eAAe,MAAM,GAAG,EAAE,CACjD,OAAM,KAAK,KAAK,KAAK,KAAK,IAAI,KAAK,QAAQ,KAAK,SAAS,MAAM,KAAK,WAAW,KAAK;;AAGxF,KAAI,MAAM,SAAS,SAAS,GAAG;AAC7B,QAAM,KAAK,IAAI,mBAAmB;AAClC,OAAK,MAAM,QAAQ,MAAM,SAAS,MAAM,GAAG,EAAE,CAC3C,OAAM,KAAK,KAAK,KAAK,KAAK,IAAI,KAAK,QAAQ,KAAK,SAAS,MAAM,KAAK,WAAW,KAAK;;AAGxF,QAAO,MAAM,KAAK,KAAK;;AAGzB,SAAS,4BAA4B,WAA2B;AAC9D,QAAO,kBAAkB;;AAG3B,SAAgB,uBAAuB,eAAqB,MAAoC;CAC9F,MAAM,EAAE,YAAY;CACpB,MAAM,WAAW,IAAI,iBAAiB;CACtC,MAAM,QAAQ,IAAI,aAAa;CAC/B,MAAM,YAAY,IAAI,iBAAiB;AAEvC,eAAc,KAAK,iBAAiB,OAAO,MAAM;EAC/C,MAAM,OAAQ,MAAM,EAAE,IAAI,MAAM,CAAC,aAAa,EAAE,EAAE;EAClD,MAAM,OAAO,UAAU,MAAM,OAAO,EAAE,MAAM;EAC5C,MAAM,gBAAgB,UAAU,MAAM,gBAAgB,EAAE,MAAM;AAC9D,MAAI,CAAC,QAAQ,CAAC,cAAe,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAgB,EAAE,IAAI;EACrF,MAAM,uBAAuB,OAAO,OAAO,MAAM,iBAAiB;EAClE,MAAM,yBAAyB,wBAAwB,UAAU,MAAM,iBAAiB,CAAC;EACzF,MAAM,iBAAiB,uBACnB,yBACA,oCAAoC;GACpC,QAAQ,QAAQ;GAChB;GACA,aAAa,UAAU,MAAM,cAAc;GAC3C;GACA,aAAa,UAAU,MAAM,cAAc;GAC5C,CAAC;AACJ,MAAI,CAAC,sBAAsB,QAAQ,eAAe,eAAe,CAC/D,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAA2B,EAAE,IAAI;AAErE,MAAI;GACF,MAAM,UAAU,QAAQ,SAAS,OAAO;IACtC;IACA,aAAa,UAAU,MAAM,cAAc;IAC3C;IACA;IACA,qBAAqB,KAAK,wBAAwB;IAClD,aAAa,UAAU,MAAM,cAAc;IAC3C,OAAO,UAAU,MAAM,QAAQ;IAC/B,cAAc,UAAU,MAAM,eAAe;IAC9C,CAAC;AACF,UAAO,EAAE,KAAK;IAAE,IAAI;IAAM,SAAS,uBAAuB,SAAS,QAAQ;IAAE,EAAE,IAAI;WAC5E,OAAO;AACd,OAAI,iBAAiB,8BACnB,QAAO,EAAE,KAAK;IAAE,IAAI;IAAO,MAAM;IAA2B,OAAO,MAAM;IAAS,SAAS,MAAM;IAAS,EAAE,IAAI;AAElH,OAAI,iBAAiB,6BACnB,QAAO,EAAE,KAAK;IAAE,IAAI;IAAO,MAAM;IAA0B,OAAO,MAAM;IAAS,eAAe,MAAM;IAAe,EAAE,IAAI;AAE7H,UAAO,EAAE,KAAK;IAAE,IAAI;IAAO,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAAE,EAAE,IAAI;;GAElG;AAEF,eAAc,IAAI,iBAAiB,OAAO,MAAM;EAC9C,MAAM,SAAS,mBAAmB,EAAE,IAAI,MAAM,SAAS,CAAC;EACxD,MAAM,SAAS,QAAQ,SAAS,KAAK;GACnC,GAAI,SAAS,EAAE,QAAQ,GAAG,EAAE;GAC5B,QAAQ,EAAE,IAAI,MAAM,SAAS;GAC7B,QAAQ,EAAE,IAAI,MAAM,SAAS;GAC7B,WAAW,EAAE,IAAI,MAAM,YAAY;GACnC,OAAO,WAAW,EAAE,IAAI,MAAM,QAAQ,CAAC;GACvC,QAAQ,EAAE,IAAI,MAAM,SAAS,GAAG,KAAK,IAAI,GAAG,OAAO,SAAS,EAAE,IAAI,MAAM,SAAS,EAAG,GAAG,IAAI,EAAE,GAAG,KAAA;GACjG,CAAC;AACF,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM,GAAG;GAAQ,OAAO,OAAO,MAAM,KAAK,YAAY,uBAAuB,SAAS,QAAQ,CAAC;GAAE,CAAC;GACtH;AAEF,eAAc,IAAI,6BAA6B,OAAO,MAAM;EAC1D,MAAM,aAAa,EAAE,IAAI,MAAM,aAAa,EAAE,MAAM;AACpD,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM,aAAa,aAAa,QAAQ,SAAS,0BAA0B,WAAW,GAAG,EAAE;GAAE,CAAC;GAClH;AAEF,eAAc,KAAK,gCAAgC,OAAO,MAAM;EAC9D,MAAM,OAAQ,MAAM,EAAE,IAAI,MAAM,CAAC,aAAa,EAAE,EAAE;EAClD,MAAM,QAAQ;GACZ,MAAM,UAAU,MAAM,OAAO;GAC7B,aAAa,UAAU,MAAM,cAAc;GAC3C,eAAe,UAAU,MAAM,gBAAgB;GAC/C,aAAa,UAAU,MAAM,cAAc;GAC5C;EACD,MAAM,YAAY,iBAAiB,MAAM;EACzC,MAAM,iBAAiB,oCAAoC;GACzD,QAAQ,QAAQ;GAChB,GAAG;GACJ,CAAC;AACF,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM;GAAW;GAAgB,CAAC;GACtD;AAEF,eAAc,KAAK,mCAAmC,OAAO,MAAM;EACjE,MAAM,OAAQ,MAAM,EAAE,IAAI,MAAM,CAAC,aAAa,EAAE,EAAE;EAClD,MAAM,gBAAgB,UAAU,MAAM,gBAAgB,EAAE,MAAM;AAC9D,MAAI,CAAC,cAAe,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAyB,EAAE,IAAI;EACrF,MAAM,UAAU,UAAU,MAAM,UAAU,EAAE,MAAM,IAAI;EACtD,MAAM,0BAA0B,oCAAoC;GAClE,QAAQ,QAAQ;GAChB,eAAe;GACf,aAAa,UAAU,MAAM,cAAc;GAC5C,CAAC;EACF,IAAI;AACJ,MAAI;AACF,WAAQ,QAAQ,SAAS,gCAAgC;IACvD;IACA;IACA,gBAAgB;IAChB,YAAY,KAAK,eAAe;IACjC,CAAC;WACK,OAAO;AACd,OAAI,iBAAiB,8BACnB,SAAQ;IAAE,SAAS,MAAM;IAAS,QAAQ;IAAkB,SAAS;IAAO;OAE5E,OAAM;;AAGV,MAAI,CAAC,MAAO,QAAO,EAAE,KAAK;GAAE,IAAI;GAAM,SAAS;GAAM,CAAC;EAEtD,MAAM,aAAa,UAAU,MAAM,aAAa,EAAE,MAAM;EACxD,MAAM,wBAAwB,wBAAwB,MAAM,QAAQ,eAAe;EACnF,MAAM,6BAA6B,CAAC,yBAAyB,0BAA0B,wBAAwB,QAAQ;AACvH,MAAI,cAAc,4BAA4B;AAE5C,OAAI,CADoB,mBAAmB,WACvB,CAClB,OAAM,QAAQ,qBAAqB,aAAa,YAAY,EAAE,EAAE,EAC9D,UAAU;IACR,eAAe;IACf,cAAc,kBAAkB;IAChC,aAAa;IACb,WAAW,MAAM,QAAQ;IACzB,SAAS;KACP;KACA,QAAQ;KACR,WAAW;KACX,UAAU;KACV,QAAQ;KACT;IACF,EACF,CAAC;AAEJ,WAAQ,SAAS,cAAc,YAAY,MAAM,QAAQ,GAAG;;AAG9D,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM,GAAG;GAAO,CAAC;GACrC;AAEF,eAAc,IAAI,8BAA8B,OAAO,MAAM;EAC3D,MAAM,UAAU,QAAQ,SAAS,eAAe,EAAE,IAAI,MAAM,KAAK,CAAC;AAClE,MAAI,CAAC,QAAS,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAqB,EAAE,IAAI;EAK3E,MAAM,OAAO,yBAAyB;GACpC;GACA,OANc,QAAQ,SAAS,YAAY,QAAQ,IAAI,WAAW,EAAE,IAAI,MAAM,YAAY,EAAE,IAAI,CACtE,CACzB,KAAK,OAAO,MAAM,IAAI,GAAG,CAAC,CAC1B,QAAQ,SAAkC,QAAQ,KAAK,CAGrC;GACnB,oBAAoB,QAAQ;GAC5B,oBAAoB,8BAA8B,QAAQ,GAAG;GAC7D,eAAe,kBAAkB;IAAE,WAAW,QAAQ;IAAI,QAAQ;IAAU,OAAO;IAAG,CAAC;GACxF,CAAC;AACF,SAAO,EAAE,KAAK;GACZ,IAAI;GACJ,UAAU;IACR,SAAS,uBAAuB,SAAS,QAAQ;IACjD,OAAO;KACL,cAAc,QAAQ;KACtB,WAAW,QAAQ;KACnB,iBAAiB,QAAQ;KACzB,wBAAwB,QAAQ,mBAAmB;KACnD,gBAAgB,KAAK,WAAW;KAChC,gBAAgB,KAAK,eAAe;KACpC,wBAAwB,KAAK,mBAAmB;KACjD;IACD,aAAa,KAAK;IAClB,cAAc,KAAK;IACnB,YAAY,KAAK;IACjB,aAAa,KAAK;IAClB,gBAAgB,KAAK;IACrB,UAAU,KAAK;IACf,QAAQ,KAAK;IACb,oBAAoB,KAAK;IACzB,gBAAgB,QAAQ;IACxB,oBAAoB,QAAQ;IAC5B,mBAAmB,KAAK;IACzB;GACF,CAAC;GACF;AAEF,eAAc,IAAI,+BAA+B,MAAM;EACrD,MAAM,UAAU,QAAQ,SAAS,IAAI,EAAE,IAAI,MAAM,KAAK,CAAC;AACvD,MAAI,CAAC,QAAS,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAqB,EAAE,IAAI;EAC3E,MAAM,SAAS,SAAS,eAAe;GACrC,WAAW,QAAQ;GACnB,gBAAgB,4BAA4B,EAAE,IAAI,MAAM,iBAAiB,CAAC;GAC1E,GAAG,mBAAmB,EAAE;GACzB,CAAC;AACF,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM,GAAG;GAAQ,CAAC;GACtC;AAEF,eAAc,IAAI,gCAAgC,OAAO,MAAM;EAC7D,MAAM,UAAU,QAAQ,SAAS,IAAI,EAAE,IAAI,MAAM,KAAK,CAAC;AACvD,MAAI,CAAC,QAAS,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAqB,EAAE,IAAI;EAC3E,MAAM,SAAS,UAAU,qBAAqB,QAAQ,IAAI;GACxD,QAAQ,aAAa,EAAE,IAAI,MAAM,SAAS,EAAE,mBAAmB;GAC/D,UAAU,aAAa,EAAE,IAAI,MAAM,WAAW,EAAE,qBAAqB;GACrE,iBAAiB,EAAE,IAAI,MAAM,kBAAkB,KAAK;GACpD,QAAQ,EAAE,IAAI,MAAM,SAAS;GAC7B,QAAQ,EAAE,IAAI,MAAM,SAAS;GAC7B,WAAW,EAAE,IAAI,MAAM,YAAY;GACnC,OAAO,WAAW,EAAE,IAAI,MAAM,QAAQ,CAAC;GACvC,QAAQ,EAAE,IAAI,MAAM,SAAS,GAAG,KAAK,IAAI,GAAG,OAAO,SAAS,EAAE,IAAI,MAAM,SAAS,EAAG,GAAG,IAAI,EAAE,GAAG,KAAA;GACjG,CAAC;AACF,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM,GAAG;GAAQ,CAAC;GACtC;AAEF,eAAc,KAAK,gCAAgC,OAAO,MAAM;EAC9D,MAAM,UAAU,QAAQ,SAAS,IAAI,EAAE,IAAI,MAAM,KAAK,CAAC;AACvD,MAAI,CAAC,QAAS,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAqB,EAAE,IAAI;EAC3E,MAAM,cAAc,EAAE,IAAI,OAAO,eAAe,IAAI;EACpD,IAAI;EACJ,IAAI,QAAgB,EAAE;AACtB,MAAI,YAAY,SAAS,sBAAsB,EAAE;AAC/C,OAAI;AACF,WAAO,MAAM,EAAE,IAAI,UAAU,EAAE,KAAK,MAAM,CAAC;WACrC;AACN,WAAO,EAAE,KAAK;KAAE,IAAI;KAAO,OAAO;KAA0B,EAAE,IAAI;;AAEpE,WAAQ,qBAAqB,KAAK;QAElC,QAAQ,MAAM,EAAE,IAAI,MAAM,CAAC,aAAa,EAAE,EAAE;EAE9C,MAAM,kBAAkB,8BAA8B,MAAM;AAC5D,MAAI,gBAAiB,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAiB,EAAE,IAAI;EAC9E,MAAM,QAAQ,UAAU,MAAM,QAAQ,EAAE,MAAM;AAC9C,MAAI,CAAC,MAAO,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAA+B,EAAE,IAAI;EACnF,MAAM,SAAS,eAAe,KAAK,QAAQ,mBAAmB;EAC9D,MAAM,WAAW,eAAe,KAAK,UAAU,qBAAqB;EACpE,MAAM,QAAQ,kBAAkB,KAAK,MAAM;AAC3C,MAAI,OAAO,OAAO,MAAM,SAAS,IAAI,CAAC,OAAQ,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAA4B,EAAE,IAAI;AAClH,MAAI,OAAO,OAAO,MAAM,WAAW,IAAI,CAAC,SAAU,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAA8B,EAAE,IAAI;AACxH,MAAI,OAAO,OAAO,MAAM,QAAQ,IAAI,UAAU,KAAA,KAAa,KAAK,UAAU,KAAM,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAiB,EAAE,IAAI;EACzI,MAAM,UAAqE,EAAE;AAC7E,OAAK,MAAM,QAAQ,MACjB,SAAQ,KAAK,MAAM,qBAAqB,KAAK,CAAC;EAEhD,MAAM,OAAO,UAAU,sBAAsB,QAAQ,IAAI;GACvD;GACA,aAAa,UAAU,MAAM,cAAc;GAC3C;GACA;GACA,cAAc,UAAU,MAAM,eAAe,IAAI,QAAQ,kBAAkB,KAAA;GAC3E,YAAY,UAAU,MAAM,aAAa;GACzC,eAAe,UAAU,MAAM,gBAAgB;GAC/C;GACD,CAAC;AACF,OAAK,MAAM,UAAU,QACnB,OAAM,UAAU,cAAc,KAAK,IAAI,OAAO;EAEhD,MAAM,UAAU,MAAM,SAAS,IAAI,UAAU,YAAY,KAAK,GAAG,IAAI,OAAO;AAC5E,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM,MAAM;GAAS,EAAE,IAAI;GAC/C;AAEF,eAAc,IAAI,uBAAuB,OAAO,MAAM;EACpD,MAAM,OAAO,UAAU,YAAY,EAAE,IAAI,MAAM,KAAK,CAAC;AACrD,MAAI,CAAC,KAAM,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAuB,EAAE,IAAI;AAC1E,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM;GAAM,CAAC;GACjC;AAEF,eAAc,IAAI,mCAAmC,OAAO,MAAM;EAChE,MAAM,cAAc,UAAU,gBAAgB,EAAE,IAAI,MAAM,KAAK,CAAC;AAChE,MAAI,CAAC,YAAa,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAuB,EAAE,IAAI;AACjF,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM;GAAa,CAAC;GACxC;AAEF,eAAc,KAAK,mCAAmC,OAAO,MAAM;EACjE,MAAM,OAAO,UAAU,YAAY,EAAE,IAAI,MAAM,KAAK,CAAC;AACrD,MAAI,CAAC,KAAM,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAuB,EAAE,IAAI;EAC1E,IAAI;AACJ,MAAI;AACF,UAAO,MAAM,EAAE,IAAI,UAAU,EAAE,KAAK,MAAM,CAAC;UACrC;AACN,UAAO,EAAE,KAAK;IAAE,IAAI;IAAO,OAAO;IAA0B,EAAE,IAAI;;EAEpE,MAAM,QAAQ,qBAAqB,KAAK;AACxC,MAAI,CAAC,MAAM,OAAQ,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAsB,EAAE,IAAI;EACjF,MAAM,kBAAkB,8BAA8B,MAAM;AAC5D,MAAI,gBAAiB,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAiB,EAAE,IAAI;EAC9E,MAAM,cAAc,EAAE;AACtB,OAAK,MAAM,QAAQ,OAAO;GACxB,MAAM,SAAS,MAAM,qBAAqB,KAAK;GAC/C,MAAM,aAAa,MAAM,UAAU,cAAc,KAAK,IAAI,OAAO;AACjE,OAAI,WAAY,aAAY,KAAK,WAAW;;AAE9C,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM;GAAa,MAAM,UAAU,YAAY,KAAK,GAAG;GAAE,EAAE,IAAI;GACnF;AAEF,eAAc,IAAI,yDAAyD,OAAO,MAAM;EACtF,MAAM,SAAS,MAAM,UAAU,eAAe,EAAE,IAAI,MAAM,KAAK,EAAE,EAAE,IAAI,MAAM,eAAe,CAAC;AAC7F,MAAI,CAAC,OAAQ,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAwB,EAAE,IAAI;AAC7E,SAAO,IAAI,SAAS,OAAO,QAAQ,EACjC,SAAS;GACP,gBAAgB,OAAO,WAAW;GAClC,kBAAkB,OAAO,OAAO,WAAW,KAAK;GAChD,uBAAuB,qBAAqB,mBAAmB,OAAO,WAAW,SAAS,CAAC;GAC3F,iBAAiB;GAClB,EACF,CAAC;GACF;AAEF,eAAc,OAAO,iDAAiD,OAAO,MAAM;EACjF,MAAM,aAAa,MAAM,UAAU,iBAAiB,EAAE,IAAI,MAAM,KAAK,EAAE,EAAE,IAAI,MAAM,eAAe,CAAC;AACnG,MAAI,CAAC,WAAY,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAwB,EAAE,IAAI;AACjF,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM;GAAY,MAAM,UAAU,YAAY,EAAE,IAAI,MAAM,KAAK,CAAC;GAAE,CAAC;GACvF;AAEF,eAAc,MAAM,uBAAuB,OAAO,MAAM;EACtD,MAAM,OAAQ,MAAM,EAAE,IAAI,MAAM,CAAC,aAAa,EAAE,EAAE;EAClD,MAAM,SAAS,OAAO,OAAO,MAAM,SAAS,GACxC,eAAe,KAAK,QAAQ,mBAAmB,GAC/C,KAAA;EACJ,MAAM,WAAW,OAAO,OAAO,MAAM,WAAW,GAC5C,eAAe,KAAK,UAAU,qBAAqB,GACnD,KAAA;EACJ,MAAM,QAAQ,OAAO,OAAO,MAAM,QAAQ,GACrC,KAAK,UAAU,OAAO,OAAQ,OAAO,KAAK,UAAU,YAAY,OAAO,SAAS,KAAK,MAAM,GAAG,KAAK,QAAQ,KAAA,IAC5G,KAAA;EACJ,MAAM,aAAa,OAAO,OAAO,MAAM,aAAa,GAC/C,KAAK,eAAe,OAAO,OAAQ,OAAO,KAAK,eAAe,YAAY,OAAO,SAAS,KAAK,WAAW,GAAG,KAAK,aAAa,KAAA,IAChI,KAAA;AACJ,MAAI,WAAW,KAAA,KAAa,OAAO,OAAO,MAAM,SAAS,CAAE,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAA4B,EAAE,IAAI;AAC/H,MAAI,aAAa,KAAA,KAAa,OAAO,OAAO,MAAM,WAAW,CAAE,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAA8B,EAAE,IAAI;AACrI,MAAI,UAAU,KAAA,KAAa,OAAO,OAAO,MAAM,QAAQ,CAAE,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAiB,EAAE,IAAI;AAClH,MAAI,eAAe,KAAA,KAAa,OAAO,OAAO,MAAM,aAAa,CAAE,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAsB,EAAE,IAAI;EAEjI,MAAM,OAAO,UAAU,eAAe,EAAE,IAAI,MAAM,KAAK,EAAE;GACvD,GAAI,OAAO,OAAO,MAAM,QAAQ,GAAG,EAAE,OAAO,UAAU,MAAM,QAAQ,IAAI,IAAI,GAAG,EAAE;GACjF,GAAI,OAAO,OAAO,MAAM,cAAc,GAAG,EAAE,aAAa,kBAAkB,MAAM,cAAc,EAAE,GAAG,EAAE;GACrG,GAAI,OAAO,OAAO,MAAM,SAAS,GAAG,EAAE,QAAQ,GAAG,EAAE;GACnD,GAAI,OAAO,OAAO,MAAM,WAAW,GAAG,EAAE,UAAU,GAAG,EAAE;GACvD,GAAI,OAAO,OAAO,MAAM,eAAe,GAAG,EAAE,cAAc,kBAAkB,MAAM,eAAe,EAAE,GAAG,EAAE;GACxG,GAAI,OAAO,OAAO,MAAM,aAAa,GAAG,EAAE,YAAY,kBAAkB,MAAM,aAAa,EAAE,GAAG,EAAE;GAClG,GAAI,OAAO,OAAO,MAAM,gBAAgB,GAAG,EAAE,eAAe,kBAAkB,MAAM,gBAAgB,EAAE,GAAG,EAAE;GAC3G,GAAI,OAAO,OAAO,MAAM,QAAQ,GAAG,EAAE,OAAO,GAAG,EAAE;GACjD,GAAI,OAAO,OAAO,MAAM,aAAa,GAAG,EAAE,YAAY,GAAG,EAAE;GAC5D,CAAC;AACF,MAAI,CAAC,KAAM,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAuB,EAAE,IAAI;AAC1E,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM;GAAM,CAAC;GACjC;AAEF,eAAc,OAAO,uBAAuB,OAAO,MAAM;EACvD,MAAM,OAAO,UAAU,eAAe,EAAE,IAAI,MAAM,KAAK,EAAE,EAAE,YAAY,KAAK,KAAK,EAAE,CAAC;AACpF,MAAI,CAAC,KAAM,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAuB,EAAE,IAAI;AAC1E,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM;GAAM,CAAC;GACjC;AAEF,eAAc,IAAI,8BAA8B,OAAO,MAAM;EAC3D,MAAM,OAAO,UAAU,YAAY,EAAE,IAAI,MAAM,KAAK,CAAC;AACrD,MAAI,CAAC,KAAM,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAuB,EAAE,IAAI;AAC1E,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM,QAAQ,UAAU,WAAW,KAAK,GAAG;GAAE,CAAC;GAClE;AAEF,eAAc,IAAI,0CAA0C,OAAO,MAAM;EACvE,MAAM,OAAO,UAAU,YAAY,EAAE,IAAI,MAAM,KAAK,CAAC;AACrD,MAAI,CAAC,KAAM,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAuB,EAAE,IAAI;EAC1E,MAAM,SAAS,eAAe,EAAE,IAAI,MAAM,SAAS,EAAE,8BAA8B;AACnF,MAAI,EAAE,IAAI,MAAM,SAAS,IAAI,CAAC,OAAQ,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAA6B,EAAE,IAAI;AAC3G,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM,aAAa,UAAU,sBAAsB,KAAK,IAAI,OAAO;GAAE,CAAC;GAC1F;AAEF,eAAc,KAAK,0CAA0C,OAAO,MAAM;EACxE,MAAM,OAAO,UAAU,YAAY,EAAE,IAAI,MAAM,KAAK,CAAC;AACrD,MAAI,CAAC,KAAM,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAuB,EAAE,IAAI;EAC1E,MAAM,OAAQ,MAAM,EAAE,IAAI,MAAM,CAAC,aAAa,EAAE,EAAE;EAClD,MAAM,aAAa,eAAe,KAAK,YAAY;GAAC;GAAQ;GAAQ;GAAgB;GAAa,CAAU;EAC3G,MAAM,WAAW,UAAU,MAAM,WAAW,EAAE,MAAM;AACpD,MAAI,CAAC,WAAY,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAsB,EAAE,IAAI;AAC/E,MAAI,CAAC,SAAU,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAwB,EAAE,IAAI;EAC/E,MAAM,YAAY,KAAK,SAAS,OAAO,KAAK,UAAU,YAAY,CAAC,MAAM,QAAQ,KAAK,MAAM,GACxF,KAAK,QACL,EAAE;EACN,MAAM,SAAS,OAAO,OAAO,WAAW,SAAS,GAC7C,eAAe,UAAU,QAAQ,mBAAmB,GACpD,KAAA;AACJ,MAAI,OAAO,OAAO,WAAW,SAAS,IAAI,CAAC,OAAQ,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAA4B,EAAE,IAAI;EACvH,MAAM,aAAa,OAAO,KAAK,eAAe,YAAY,OAAO,SAAS,KAAK,WAAW,GACtF,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,WAAW,CAAC,GACzC,KAAA;EACJ,MAAM,aAAa,UAAU,uBAAuB,KAAK,IAAI;GAC3D;GACA;GACA,OAAO;IACL,GAAI,OAAO,OAAO,WAAW,SAAS,GAAG,EAAE,QAAQ,GAAG,EAAE;IACxD,GAAI,OAAO,OAAO,WAAW,aAAa,GAAG,EAAE,YAAY,kBAAkB,WAAW,aAAa,EAAE,GAAG,EAAE;IAC5G,GAAI,OAAO,OAAO,WAAW,gBAAgB,GAAG,EAAE,eAAe,kBAAkB,WAAW,gBAAgB,EAAE,GAAG,EAAE;IACtH;GACD,cAAc,kBAAkB,MAAM,eAAe,IAAI,KAAA;GACzD,WAAW,kBAAkB,MAAM,YAAY,IAAI,KAAA;GACnD;GACD,CAAC;AACF,MAAI,CAAC,WAAY,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAuB,EAAE,IAAI;AAChF,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM;GAAY,EAAE,IAAI;GAC5C;AAEF,eAAc,KAAK,+CAA+C,OAAO,MAAM;EAC7E,MAAM,SAAS,UAAU,sBAAsB,EAAE,IAAI,MAAM,KAAK,CAAC;AACjE,MAAI,CAAC,OAAQ,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAA4C,EAAE,IAAI;AACjG,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM,MAAM,OAAO;GAAM,YAAY,OAAO;GAAY,CAAC;GAC7E;AAEF,eAAc,KAAK,iDAAiD,OAAO,MAAM;EAC/E,MAAM,aAAa,UAAU,wBAAwB,EAAE,IAAI,MAAM,KAAK,CAAC;AACvE,MAAI,CAAC,WAAY,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAA4C,EAAE,IAAI;AACrG,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM;GAAY,CAAC;GACvC;AAEF,eAAc,KAAK,kCAAkC,OAAO,MAAM;EAChE,MAAM,OAAO,UAAU,YAAY,EAAE,IAAI,MAAM,KAAK,CAAC;AACrD,MAAI,CAAC,KAAM,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAuB,EAAE,IAAI;EAC1E,MAAM,UAAU,QAAQ,SAAS,IAAI,KAAK,UAAU;AACpD,MAAI,CAAC,QAAS,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAqB,EAAE,IAAI;EAC3E,MAAM,UAAU,sBAAsB;GACpC,QAAQ,QAAQ;GAChB,UAAU,QAAQ;GAClB,iBAAiB,KAAK;GACtB,WAAW,QAAQ;GACpB,CAAC;EACF,MAAM,SAAS,aAAa,KAAK,KAAK;EACtC,MAAM,aAAa,gBAAgB;GACjC;GACA,QAAQ;GACR,WAAW;GACX,UAAU;GACV;GACD,CAAC;AACF,QAAM,QAAQ,qBAAqB,aAAa,YAAY,EAAE,EAAE,EAC9D,UAAU,iCAAiC;GACzC;GACA,WAAW;GACX;GACA,YAAY,KAAK;GACjB,OAAO,KAAK;GACZ,WAAW,KAAK;GACjB,CAAC,EACH,CAAC;AACF,UAAQ,SAAS,cAAc,YAAY,QAAQ,GAAG;EACtD,MAAM,UAAU,MAAM,QAAQ,SAAS,WAAW,WAAW;AAC7D,YAAU,QAAQ,KAAK,IAAI;GACzB,MAAM;GACN,UAAU;GACV,OAAO,SAAS,QAAQ,KAAK;GAC7B,gBAAgB,SAAS;GAC1B,EAAE,eAAe;EAClB,MAAM,UAAU,KAAK,WAAW,UAAU,KAAK,WAAW,YACtD,UAAU,eAAe,KAAK,IAAI,EAAE,QAAQ,eAAe,CAAC,GAC5D,UAAU,YAAY,KAAK,GAAG;AAClC,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM;GAAS,MAAM;GAAS,EAAE,IAAI;GACxD;AAEF,eAAc,KAAK,mCAAmC,OAAO,MAAM;EACjE,MAAM,OAAO,UAAU,YAAY,EAAE,IAAI,MAAM,KAAK,CAAC;AACrD,MAAI,CAAC,KAAM,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAuB,EAAE,IAAI;EAC1E,MAAM,UAAU,QAAQ,SAAS,IAAI,KAAK,UAAU;AACpD,MAAI,CAAC,QAAS,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAqB,EAAE,IAAI;EAC3E,MAAM,cAAc,MAAM,UAAU,2BAA2B,KAAK,GAAG;AACvE,MAAI,CAAC,YAAa,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAuB,EAAE,IAAI;EACjF,MAAM,UAAU,MAAM,0BAA0B,MAAM;GAAE;GAAa,eAAe;GAAO,CAAC;EAC5F,MAAM,OAAO,MAAM,OAAO;GACxB,OAAO,KAAK;GACZ,aAAa,KAAK,eAAe,KAAK;GACtC,UAAU,KAAK,aAAa,WAAW,SAAS,KAAK;GACrD,SAAS,KAAK,gBAAgB,QAAQ,kBAAkB,KAAA;GACxD,WAAW,QAAQ;GACnB,QAAQ;GACR,QAAQ,QAAQ;GACjB,CAAC;EACF,MAAM,kBAAkB,MAAM,kBAAkB;GAC9C,QAAQ,KAAK;GACb,MAAM,QAAQ;GACd;GACD,CAAC,IAAI;AACN,YAAU,QAAQ,KAAK,IAAI;GACzB,MAAM;GACN,UAAU,KAAK;GACf,OAAO,KAAK;GACZ,gBAAgB,KAAK;GACtB,EAAE,eAAe;EAClB,MAAM,UAAU,KAAK,WAAW,UAAU,KAAK,WAAW,YACtD,UAAU,eAAe,KAAK,IAAI,EAAE,QAAQ,eAAe,CAAC,GAC5D,UAAU,YAAY,KAAK,GAAG;AAClC,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM,MAAM;GAAiB,MAAM;GAAS,EAAE,IAAI;GACtE;AAEF,eAAc,KAAK,mCAAmC,OAAO,MAAM;EACjE,MAAM,UAAU,QAAQ,SAAS,eAAe,EAAE,IAAI,MAAM,KAAK,CAAC;AAClE,MAAI,CAAC,QAAS,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAqB,EAAE,IAAI;EAK3E,MAAM,OAAO,yBAAyB;GACpC;GACA,OANc,QAAQ,SAAS,YAAY,QAAQ,IAAI,IAC7B,CACzB,KAAK,OAAO,MAAM,IAAI,GAAG,CAAC,CAC1B,QAAQ,SAAkC,QAAQ,KAAK,CAGrC;GACnB,oBAAoB,QAAQ;GAC5B,oBAAoB,8BAA8B,QAAQ,GAAG;GAC7D,eAAe,kBAAkB;IAAE,WAAW,QAAQ;IAAI,QAAQ;IAAU,OAAO;IAAG,CAAC;GACxF,CAAC;EACF,MAAM,SAAS,mBAAmB;GAChC,IAAI,4BAA4B,QAAQ,GAAG;GAC3C,YAAY;GACZ,MAAM;GACN,SAAS,sBAAsB;IAC7B,QAAQ,QAAQ;IAChB,UAAU,QAAQ;IAClB,WAAW,QAAQ;IACpB,CAAC;GACF,aAAa,QAAQ;GACrB,WAAW,QAAQ;GACnB,SAAS,gCAAgC;IAAE,GAAG;IAAM,aAAa,QAAQ;IAAM,CAAC;GAChF,QAAQ,EACN,UAAU,kBACX;GACD,YAAY;GACZ,MAAM;IAAC;IAAW;IAAkB,QAAQ;IAAK;GACjD,QAAQ;GACR,aAAa;GACd,CAAC;AACF,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM;GAAQ,EAAE,IAAI;GACxC;AAEF,eAAc,KAAK,8BAA8B,OAAO,MAAM;EAC5D,MAAM,UAAU,QAAQ,SAAS,eAAe,EAAE,IAAI,MAAM,KAAK,CAAC;AAClE,MAAI,CAAC,QAAS,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAqB,EAAE,IAAI;EAC3E,MAAM,OAAQ,MAAM,EAAE,IAAI,MAAM,CAAC,aAAa,EAAE,EAAE;EAClD,MAAM,QAAQ,OAAO,KAAK,UAAU,WAAW,KAAK,MAAM,MAAM,GAAG;AACnE,MAAI,CAAC,MAAO,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAiB,EAAE,IAAI;EACrE,MAAM,SAAS,OAAO,KAAK,WAAW,WAAW,KAAK,OAAO,MAAM,GAAG;EACtE,MAAM,OAAO,MAAM,OAAO;GACxB;GACA,aAAa,UAAU,KAAA;GACvB,SAAS,sBAAsB;IAC7B,QAAQ,QAAQ;IAChB,UAAU,QAAQ;IAClB,WAAW,QAAQ;IACpB,CAAC;GACF,UAAU,KAAK,aAAa,SAAS,KAAK,aAAa,YAAY,KAAK,aAAa,SAAS,KAAK,WAAW;GAC9G,QAAQ;GACR,WAAW,QAAQ;GACpB,CAAC;EACF,MAAM,UAAU,MAAM,UAAU,KAAK,IAAI,WAAW,EAAE,QAAQ,UAAU,OAAO,CAAC;AAChF,MAAI,OACF,OAAM,kBAAkB;GAAE,QAAQ,KAAK;GAAI,MAAM;GAAQ,CAAC;AAE5D,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM,MAAM,WAAW,MAAM,IAAI,KAAK,GAAG;GAAE,EAAE,IAAI;GACrE;AAEF,eAAc,IAAI,qBAAqB,OAAO,MAAM;EAClD,MAAM,UAAU,QAAQ,SAAS,eAAe,EAAE,IAAI,MAAM,KAAK,CAAC;AAClE,MAAI,CAAC,QAAS,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAqB,EAAE,IAAI;AAC3E,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM,SAAS,uBAAuB,SAAS,QAAQ;GAAE,CAAC;GAC9E;AAEF,eAAc,MAAM,qBAAqB,OAAO,MAAM;EACpD,MAAM,OAAQ,MAAM,EAAE,IAAI,MAAM,CAAC,aAAa,EAAE,EAAE;EAClD,MAAM,SAAS,mBAAmB,KAAK,OAAO;EAC9C,MAAM,oBAAoB,kBAAkB,MAAM,iBAAiB;EACnE,MAAM,iBAAiB,sBAAsB,KAAA,IAAY,KAAA,IAAY,wBAAwB,kBAAkB;AAC/G,MAAI,kBAAkB,CAAC,sBAAsB,QAAQ,eAAe,eAAe,CACjF,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAA2B,EAAE,IAAI;AAErE,MAAI;GACF,MAAM,UAAU,QAAQ,SAAS,OAAO,EAAE,IAAI,MAAM,KAAK,EAAE;IACzD,GAAI,UAAU,MAAM,OAAO,KAAK,KAAA,IAAY,EAAE,MAAM,UAAU,MAAM,OAAO,EAAE,GAAG,EAAE;IAClF,GAAI,kBAAkB,MAAM,cAAc,KAAK,KAAA,IAAY,EAAE,aAAa,kBAAkB,MAAM,cAAc,EAAE,GAAG,EAAE;IACvH,GAAI,SAAS,EAAE,QAAQ,GAAG,EAAE;IAC5B,GAAI,sBAAsB,KAAA,IAAY,EAAE,gBAAgB,kBAAkB,MAAM,GAAG,EAAE;IACrF,GAAI,kBAAkB,MAAM,gBAAgB,KAAK,KAAA,IAAY,EAAE,eAAe,kBAAkB,MAAM,gBAAgB,EAAE,GAAG,EAAE;IAC7H,qBAAqB,KAAK,wBAAwB;IAClD,GAAI,kBAAkB,MAAM,QAAQ,KAAK,KAAA,IAAY,EAAE,OAAO,kBAAkB,MAAM,QAAQ,EAAE,GAAG,EAAE;IACrG,GAAI,kBAAkB,MAAM,eAAe,KAAK,KAAA,IAAY,EAAE,cAAc,kBAAkB,MAAM,eAAe,EAAE,GAAG,EAAE;IAC3H,CAAC;AACF,UAAO,EAAE,KAAK;IAAE,IAAI;IAAM,SAAS,uBAAuB,SAAS,QAAQ;IAAE,CAAC;WACvE,OAAO;AACd,OAAI,iBAAiB,8BACnB,QAAO,EAAE,KAAK;IAAE,IAAI;IAAO,MAAM;IAA2B,OAAO,MAAM;IAAS,SAAS,MAAM;IAAS,EAAE,IAAI;AAElH,OAAI,iBAAiB,6BACnB,QAAO,EAAE,KAAK;IAAE,IAAI;IAAO,MAAM;IAA0B,OAAO,MAAM;IAAS,eAAe,MAAM;IAAe,EAAE,IAAI;AAE7H,UAAO,EAAE,KAAK;IAAE,IAAI;IAAO,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAAE,EAAE,IAAI;;GAElG;AAEF,eAAc,OAAO,qBAAqB,OAAO,MAAM;AACrD,UAAQ,SAAS,OAAO,EAAE,IAAI,MAAM,KAAK,CAAC;AAC1C,SAAO,EAAE,KAAK,EAAE,IAAI,MAAM,CAAC;GAC3B;AAEF,eAAc,IAAI,8BAA8B,OAAO,MAAM;AAC3D,MAAI;GACF,MAAM,OAAO,QAAQ,SAAS,gBAAgB,EAAE,IAAI,MAAM,KAAK,EAAE,WAAW,EAAE,IAAI,MAAM,QAAQ,EAAE,IAAI,CAAC;GACvG,MAAM,WAAW,MAAM,QAAQ,IAAI,KAAK,KAAK,QAAQ,QAAQ,SAAS,WAAW,IAAI,CAAC,CAAC;AACvF,UAAO,EAAE,KAAK;IACZ,IAAI;IACJ,UAAU,SAAS,QAAQ,YAAY,WAAW,CAAC,8BAA8B,QAAQ,CAAC;IAC3F,CAAC;WACK,OAAO;AACd,UAAO,EAAE,KAAK;IAAE,IAAI;IAAO,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAAE,EAAE,IAAI;;GAElG;AAEF,eAAc,IAAI,2BAA2B,OAAO,MAAM;AACxD,MAAI;GACF,MAAM,MAAM,QAAQ,SAAS,YAAY,EAAE,IAAI,MAAM,KAAK,EAAE,WAAW,EAAE,IAAI,MAAM,QAAQ,EAAE,IAAI,CAAC;AAClG,UAAO,EAAE,KAAK;IAAE,IAAI;IAAM,OAAO,IAAI,KAAK,OAAO,MAAM,IAAI,GAAG,CAAC,CAAC,OAAO,QAAQ;IAAE,CAAC;WAC3E,OAAO;AACd,UAAO,EAAE,KAAK;IAAE,IAAI;IAAO,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAAE,EAAE,IAAI;;GAElG;AAEF,eAAc,IAAI,2BAA2B,OAAO,MAAM;EACxD,MAAM,WAAW,MAAM,4BAA4B,SAAS,EAAE,IAAI,MAAM,KAAK,EAAE,EAAE,IAAI,MAAM,OAAO,CAAC;AACnG,MAAI,SAAS,OAAO,MAAO,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO,SAAS;GAAO,EAAE,SAAS,OAAc;EACtG,MAAM,EAAE,MAAM,cAAc,cAAc;EAC1C,IAAI;AACJ,MAAI;AACF,iBAAc,MAAM,SAAS,UAAU;AACvC,OAAI,CAAC,kBAAkB,MAAM,YAAY,CACvC,QAAO,EAAE,KAAK;IAAE,IAAI;IAAO,OAAO;IAAqC,EAAE,IAAI;AAG/E,OAAI,EAAC,MADqB,KAAK,YAAY,EAC1B,aAAa,CAC5B,QAAO,EAAE,KAAK;IAAE,IAAI;IAAO,OAAO;IAA2B,EAAE,IAAI;WAE9D,KAAK;AACZ,OAAI,KAAK;IAAE;IAAK,WAAW,SAAS;IAAW,MAAM;IAAW,EAAE,gCAAgC;AAClG,UAAO,EAAE,KAAK;IAAE,IAAI;IAAO,OAAO;IAAkB,EAAE,IAAI;;AAG5D,MAAI;GACF,MAAM,UAAU,MAAM,QAAQ,aAAa,EAAE,eAAe,MAAM,CAAC;GAmBnE,MAAM,kBAAiB,MAlBD,QAAQ,IAAI,QAC/B,QAAQ,UAAU,CAAC,gBAAgB,IAAI,MAAM,KAAK,CAAC,CACnD,IAAI,OAAO,UAAU;IACpB,MAAM,cAAcD,OAAK,KAAK,aAAa,MAAM,KAAK;IACtD,MAAM,eAAe,MAAM,SAAS,YAAY,CAAC,YAAY,KAAK;AAClE,QAAI,CAAC,gBAAgB,CAAC,kBAAkB,MAAM,aAAa,CAAE,QAAO;IACpE,MAAM,YAAY,MAAM,KAAK,aAAa,CAAC,YAAY,KAAK;AAC5D,QAAI,CAAC,UAAW,QAAO;IACvB,MAAM,eAAeA,OAAK,SAAS,MAAM,YAAY,CAAC,MAAMA,OAAK,IAAI,CAAC,KAAK,IAAI;AAC/E,WAAO;KACL,MAAM,MAAM;KACZ,MAAM;KACN;KACA,MAAM,UAAU,aAAa,GAAG,cAAc;KAC9C,MAAM,WAAW,QAAQ,GAAG,UAAU,OAAO,KAAA;KAC7C,WAAW,WAAW,MAAM,aAAa;KAC1C;KACD,CAAC,EAC0B,QAAQ,UAA8C,UAAU,KAAK;AACpG,kBAAe,MAAM,MAAM,UAAU;AACnC,QAAI,KAAK,SAAS,MAAM,KAAM,QAAO,KAAK,SAAS,cAAc,KAAK;AACtE,WAAO,KAAK,KAAK,cAAc,MAAM,KAAK;KAC1C;GACF,MAAM,sBAAsBA,OAAK,SAAS,MAAM,YAAY,CAAC,MAAMA,OAAK,IAAI,CAAC,KAAK,IAAI;GACtF,MAAM,qBAAqB,sBAAsBA,OAAK,QAAQ,oBAAoB,CAAC,WAAW,MAAM,IAAI,GAAG;AAC3G,UAAO,EAAE,KAAK;IACZ,IAAI;IACJ;IACA,MAAM,wBAAwB,MAAM,KAAK;IACzC,YAAY,uBAAuB,MAAM,KAAK;IAC9C,SAAS;IACV,CAAC;WACK,KAAK;AACZ,OAAI,KAAK;IAAE;IAAK,WAAW,SAAS;IAAW,MAAM;IAAa,EAAE,2BAA2B;AAC/F,OAAK,KAA+B,SAAS,SAC3C,QAAO,EAAE,KAAK;IAAE,IAAI;IAAO,OAAO;IAAqB,EAAE,IAAI;AAE/D,UAAO,EAAE,KAAK;IAAE,IAAI;IAAO,OAAO;IAAgC,EAAE,IAAI;;GAE1E;AAEF,eAAc,IAAI,gCAAgC,OAAO,MAAM;EAC7D,MAAM,WAAW,MAAM,oCAAoC,SAAS,EAAE,IAAI,MAAM,KAAK,EAAE,EAAE,IAAI,MAAM,OAAO,CAAC;AAC3G,MAAI,SAAS,OAAO,MAAO,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO,EAAE,SAAS,SAAS,OAAO;GAAE,EAAE,SAAS,OAAc;AACnH,MAAI,CAAC,SAAS,KAAK,QAAQ,CACzB,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO,EAAE,SAAS,cAAc;GAAE,EAAE,IAAI;AAErE,MAAI;GACF,MAAM,UAAU,MAAM,SAAS,SAAS,cAAc,QAAQ;AAC9D,UAAO,EAAE,KAAK;IACZ,IAAI;IACJ,SAAS;KACP;KACA,MAAM,SAAS;KACf,cAAc,SAAS;KACvB,SAAS,SAAS,KAAK;KACxB;IACF,CAAC;UACI;AACN,UAAO,EAAE,KAAK;IAAE,IAAI;IAAO,OAAO,EAAE,SAAS,eAAe;IAAE,EAAE,IAAI;;GAEtE;AAEF,eAAc,IAAI,+BAA+B,OAAO,MAAM;EAC5D,MAAM,WAAW,MAAM,oCAAoC,SAAS,EAAE,IAAI,MAAM,KAAK,EAAE,EAAE,IAAI,MAAM,OAAO,CAAC;AAC3G,MAAI,SAAS,OAAO,MAAO,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO,EAAE,SAAS,SAAS,OAAO;GAAE,EAAE,SAAS,OAAc;AACnH,MAAI,CAAC,SAAS,KAAK,QAAQ,CACzB,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO,EAAE,SAAS,cAAc;GAAE,EAAE,IAAI;EAGrE,MAAM,cAAc,yBADR,SAAS,aAAa,MAAM,IAAI,CAAC,KAAK,EAAE,aAAa,IAAI,OAChB;AACrD,MAAI;GACF,MAAM,MAAM,MAAM,SAAS,SAAS,aAAa;AACjD,UAAO,IAAI,SAAS,KAAK,EACvB,SAAS;IACP,gBAAgB;IAChB,iBAAiB;IAClB,EACF,CAAC;UACI;AACN,UAAO,EAAE,KAAK;IAAE,IAAI;IAAO,OAAO,EAAE,SAAS,eAAe;IAAE,EAAE,IAAI;;GAEtE;AAEF,eAAc,IAAI,6CAA6C,OAAO,MAAM;EAC1E,MAAM,UAAU,OAAO,EAAE,IAAI,MAAM,OAAO,KAAK,WAAW,EAAE,IAAI,MAAM,OAAO,CAAE,MAAM,GAAG;AACxF,MAAI,CAAC,QACH,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;IAAE,MAAM;IAAgB,SAAS;IAAgB;GAAE,EAAE,IAAI;EAE7F,MAAM,WAAW,MAAM,4BAA4B,SAAS,EAAE,IAAI,MAAM,KAAK,EAAE,QAAQ;AACvF,MAAI,SAAS,OAAO,MAClB,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;IAAE,MAAM;IAAuC,SAAS,SAAS;IAAO;GAAE,EAAE,SAAS,OAAc;EAEvI,IAAI,KAA8C;EAClD,IAAI,eAAe,SAAS;AAC5B,MAAI;AACF,kBAAe,MAAM,SAAS,SAAS,aAAa;AACpD,OAAI,CAAC,kBAAkB,SAAS,MAAM,aAAa,CACjD,QAAO,EAAE,KAAK;IACZ,IAAI;IACJ,OAAO;KAAE,MAAM;KAAuC,SAAS;KAAqC;IACrG,EAAE,IAAI;AAET,QAAK,MAAM,KAAK,aAAa;UACvB;AACN,QAAK;;EAEP,MAAM,cAAcA,OAAK,SAAS,QAAQ;AAC1C,MAAI,CAAC,GACH,QAAO,EAAE,KAAK;GACZ,IAAI;GACJ,SAAS;IACP,WAAW;IACX;IACA,OAAO;IACP,QAAQ;IACR,cAAc,SAAS;IACvB,cAAc,CAAC,WAAW;IAC1B,WAAW;IACZ;GACF,CAAC;AAEJ,SAAO,EAAE,KAAK;GACZ,IAAI;GACJ,SAAS;IACP,WAAW;IACX;IACA,OAAO;IACP,QAAQ;IACR,aAAa,GAAG,aAAa;IAC7B;IACA,uBAAuB,SAAS;IAChC,cAAc,GAAG,aAAa,GAC1B;KAAC;KAAgB;KAAkB;KAAW,GAC9C;KAAC;KAAW;KAAQ;KAAgB;KAAkB;KAAW;IACrE,SAAS,GAAG;IACb;GACF,CAAC;GACF;AAEF,eAAc,IAAI,iCAAiC,OAAO,MAAM;EAC9D,IAAI;AACJ,MAAI;AACF,UAAO,MAAM,EAAE,IAAI,MAAM;UACnB;AACN,UAAO,EAAE,KAAK;IAAE,IAAI;IAAO,OAAO,EAAE,SAAS,gBAAgB;IAAE,EAAE,IAAI;;EAEvE,MAAM,aAAa,OAAO,SAAS,YAAY,SAAS,OAAO,OAAkC,EAAE;EACnG,MAAM,UAAU,OAAO,WAAW,SAAS,WAAW,WAAW,OAAO;EACxE,MAAM,UAAU,OAAO,WAAW,YAAY,WAAW,WAAW,UAAU;AAC9E,MAAI,CAAC,QAAQ,MAAM,CACjB,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO,EAAE,SAAS,gBAAgB;GAAE,EAAE,IAAI;EAEvE,MAAM,WAAW,MAAM,iCAAiC,SAAS,EAAE,IAAI,MAAM,KAAK,EAAE,QAAQ;AAC5F,MAAI,SAAS,OAAO,MAAO,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO,EAAE,SAAS,SAAS,OAAO;GAAE,EAAE,SAAS,OAAc;AACnH,MAAI,SAAS,gBAAgB,CAAC,SAAS,aAAa,QAAQ,CAC1D,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO,EAAE,SAAS,cAAc;GAAE,EAAE,IAAI;AAErE,MAAI;AACF,SAAM,UAAU,SAAS,cAAc,SAAS,QAAQ;GACxD,MAAM,WAAW,MAAM,KAAK,SAAS,aAAa,CAAC,aAAa,EAAE,SAAS,KAAK,KAAK,EAAE,EAAE,EAAE;AAC3F,UAAO,EAAE,KAAK;IACZ,IAAI;IACJ,SAAS;KAAE,MAAM,SAAS;KAAc;KAAS;IAClD,CAAC;WACK,KAAK;AACZ,OAAI,MAAM;IAAE;IAAK,WAAW,SAAS;IAAW,MAAM,SAAS;IAAc,EAAE,4BAA4B;AAC3G,UAAO,EAAE,KAAK;IAAE,IAAI;IAAO,OAAO,EAAE,SAAS,gBAAgB;IAAE,EAAE,IAAI;;GAEvE;AAEF,eAAc,KAAK,0CAA0C,OAAO,MAAM;AACxE,MAAI;AACF,WAAQ,SAAS,cAAc,EAAE,IAAI,MAAM,aAAa,EAAE,EAAE,IAAI,MAAM,KAAK,CAAC;GAC5E,MAAM,UAAU,MAAM,QAAQ,SAAS,WAAW,EAAE,IAAI,MAAM,aAAa,CAAC;AAC5E,UAAO,EAAE,KAAK;IAAE,IAAI;IAAM;IAAS,CAAC;WAC7B,OAAO;AACd,UAAO,EAAE,KAAK;IAAE,IAAI;IAAO,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAAE,EAAE,IAAI;;GAElG;AAEF,eAAc,OAAO,0CAA0C,OAAO,MAAM;AAC1E,MAAI;GACF,MAAM,YAAY,EAAE,IAAI,MAAM,KAAK;GACnC,MAAM,aAAa,EAAE,IAAI,MAAM,aAAa;AAC5C,OAAI,CAAC,QAAQ,SAAS,IAAI,UAAU,CAClC,QAAO,EAAE,KAAK;IAAE,IAAI;IAAO,OAAO;IAAqB,EAAE,IAAI;GAE/D,MAAM,UAAU,MAAM,QAAQ,SAAS,WAAW,WAAW;AAC7D,OAAI,CAAC,QACH,QAAO,EAAE,KAAK;IAAE,IAAI;IAAO,OAAO;IAAqB,EAAE,IAAI;AAE/D,OAAI,QAAQ,cAAc,UACxB,QAAO,EAAE,KAAK;IAAE,IAAI;IAAO,OAAO;IAA2C,EAAE,IAAI;AAErF,WAAQ,SAAS,cAAc,WAAW;AAC1C,UAAO,EAAE,KAAK,EAAE,IAAI,MAAM,CAAC;WACpB,OAAO;AACd,UAAO,EAAE,KAAK;IAAE,IAAI;IAAO,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAAE,EAAE,IAAI;;GAElG;AAEF,eAAc,KAAK,yDAAyD,OAAO,MAAM;EACvF,MAAM,YAAY,EAAE,IAAI,MAAM,KAAK;EACnC,MAAM,aAAa,EAAE,IAAI,MAAM,aAAa;EAC5C,MAAM,UAAU,QAAQ,SAAS,IAAI,UAAU;AAC/C,MAAI,CAAC,QAAS,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAqB,EAAE,IAAI;EAC3E,MAAM,UAAU,mBAAmB,WAAW;AAC9C,MAAI,CAAC,QAAS,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAAqB,EAAE,IAAI;AAC3E,MAAI,QAAQ,cAAc,UACxB,QAAO,EAAE,KAAK;GAAE,IAAI;GAAO,OAAO;GAA2C,EAAE,IAAI;EAErF,MAAM,OAAQ,MAAM,EAAE,IAAI,MAAM,CAAC,aAAa,EAAE,EAAE;EAClD,MAAM,UAAU,iCACd,YACA,OAAO,KAAK,YAAY,WAAW,KAAK,UAAU,KAAA,EACnD;EACD,MAAM,SAAS,mBAAmB;GAChC,YAAY;GACZ,MAAM;GACN,SAAS,QAAQ,SAAS,WAAW;GACrC,aAAa,QAAQ;GACrB;GACA;GACA;GACA,QAAQ;IACN,UAAU;IACV,gBAAgB;IACjB;GACD,YAAY,OAAO,KAAK,eAAe,WAAW,KAAK,aAAa;GACpE,MAAM;IAAC;IAAW;IAAmB,QAAQ;IAAK;GAClD,QAAQ;GACR,aAAa;GACb,UAAU,CAAC,EAAE,YAAY,CAAC;GAC3B,CAAC;AACF,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM;GAAQ,EAAE,IAAI;GACxC;AAEF,eAAc,KAAK,mCAAmC,OAAO,MAAM;AACjE,MAAI;AACF,WAAQ,SAAS,WAAW,EAAE,IAAI,MAAM,SAAS,EAAE,EAAE,IAAI,MAAM,KAAK,CAAC;AACrE,UAAO,EAAE,KAAK;IAAE,IAAI;IAAM,MAAM,MAAM,IAAI,EAAE,IAAI,MAAM,SAAS,CAAC;IAAE,CAAC;WAC5D,OAAO;AACd,UAAO,EAAE,KAAK;IAAE,IAAI;IAAO,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAAE,EAAE,IAAI;;GAElG;AAEF,eAAc,OAAO,mCAAmC,OAAO,MAAM;AACnE,MAAI;GACF,MAAM,YAAY,EAAE,IAAI,MAAM,KAAK;GACnC,MAAM,SAAS,EAAE,IAAI,MAAM,SAAS;AACpC,OAAI,CAAC,QAAQ,SAAS,IAAI,UAAU,CAClC,QAAO,EAAE,KAAK;IAAE,IAAI;IAAO,OAAO;IAAqB,EAAE,IAAI;GAE/D,MAAM,OAAO,MAAM,IAAI,OAAO;AAC9B,OAAI,CAAC,KACH,QAAO,EAAE,KAAK;IAAE,IAAI;IAAO,OAAO;IAAkB,EAAE,IAAI;AAE5D,OAAI,KAAK,cAAc,UACrB,QAAO,EAAE,KAAK;IAAE,IAAI;IAAO,OAAO;IAAwC,EAAE,IAAI;AAElF,WAAQ,SAAS,WAAW,OAAO;AACnC,UAAO,EAAE,KAAK,EAAE,IAAI,MAAM,CAAC;WACpB,OAAO;AACd,UAAO,EAAE,KAAK;IAAE,IAAI;IAAO,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAAE,EAAE,IAAI;;GAElG"}
1
+ {"version":3,"file":"projects.js","names":["path","record"],"sources":["../../../../../src/gateway/hono/routes/projects.ts"],"sourcesContent":["import type { Hono } from 'hono';\nimport { readdir, readFile, realpath, stat, writeFile } from 'node:fs/promises';\nimport * as path from 'node:path';\n\nimport { ActivityService } from '../../../activity/index.js';\nimport { resolveEffectiveAgentProfile } from '../../../config/agent-profile.js';\nimport type { GoalWithDetails } from '../../../goals/index.js';\nimport { GoalService } from '../../../goals/index.js';\nimport {\n buildProjectLoopOverview,\n inferProjectKind,\n inferSuggestedProjectDefaultAgentId,\n isValidProjectAgentId,\n normalizeProjectAgentId,\n ProjectWorkspaceConflictError,\n ProjectWorkspaceMissingError,\n type Project,\n resolveProjectAgentId,\n type ProjectStatus,\n type ProjectWorkflowRunBrief,\n} from '../../../projects/index.js';\nimport { buildSessionKey } from '../../../routing/session-key.js';\nimport {\n getSqliteDatabase,\n getSessionMetadata,\n listMemoryRecords,\n loadTranscriptRowsForSession,\n type SessionMetadataSeed,\n upsertMemoryRecord,\n} from '../../../storage/sqlite/index.js';\nimport {\n buildWorkItemAgentContext,\n WorkItemService,\n WORK_ITEM_ATTACHMENT_MAX_BYTES,\n WORK_ITEM_ATTACHMENT_MAX_COUNT,\n type WorkItemPriority,\n type WorkItemStatus,\n} from '../../../work-items/index.js';\nimport { createGatewayRouteLogger } from '../lib/route-logger.js';\nimport { parseActivityIncludeRelated, parseActivityQuery } from './activity.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nconst log = createGatewayRouteLogger('Projects');\n\nfunction parseProjectStatus(raw: unknown): ProjectStatus | undefined {\n return raw === 'active' || raw === 'paused' || raw === 'archived' ? raw : undefined;\n}\n\nfunction parseLimit(raw: string | undefined, fallback = 50): number | undefined {\n if (!raw) return undefined;\n const n = Number.parseInt(raw, 10);\n return Number.isFinite(n) ? Math.min(500, Math.max(1, n)) : fallback;\n}\n\nfunction isHiddenEmptyProjectChatShell(session: {\n hiddenFromSessionList?: boolean;\n messageCount?: number;\n routing?: { peerId?: string };\n customData?: Record<string, unknown>;\n}): boolean {\n return session.hiddenFromSessionList === true\n && session.messageCount === 0\n && session.customData?.genericNewChatShell !== false\n && Boolean(session.routing?.peerId?.startsWith('chat_'));\n}\n\nfunction textField(body: Record<string, unknown>, key: string): string | undefined {\n const value = body[key];\n return typeof value === 'string' ? value : undefined;\n}\n\nfunction optionalTextField(body: Record<string, unknown>, key: string): string | null | undefined {\n if (!(key in body)) return undefined;\n const value = body[key];\n return typeof value === 'string' ? value : null;\n}\n\nfunction resolveEffectiveWorkspaceRoot(\n service: AuthenticatedRouteDeps['service'],\n project: Project,\n): string | undefined {\n const fixedRoot = project.workspaceRoot?.trim();\n if (fixedRoot) return fixedRoot;\n const agentId = resolveProjectAgentId({\n config: service.currentConfig,\n projects: service.projects,\n projectId: project.id,\n });\n return resolveEffectiveAgentProfile(service.currentConfig, agentId).resolvedWorkspacePath;\n}\n\nfunction enrichProjectWorkspace<T extends Project>(\n service: AuthenticatedRouteDeps['service'],\n project: T,\n): T {\n return {\n ...project,\n workspaceMode: project.workspaceRoot?.trim() ? 'fixed' : 'followAgent',\n effectiveWorkspaceRoot: resolveEffectiveWorkspaceRoot(service, project),\n };\n}\n\nfunction finiteNumberField(value: unknown): number | undefined {\n if (typeof value === 'number' && Number.isFinite(value)) return value;\n if (typeof value === 'string' && value.trim()) {\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : undefined;\n }\n return undefined;\n}\n\nfunction collectUploadedFiles(body: Record<string, unknown>): File[] {\n const raw = body.file ?? body.files ?? body.attachments;\n const values = Array.isArray(raw) ? raw : raw ? [raw] : [];\n return values.filter((value): value is File => value instanceof File);\n}\n\nfunction validateUploadedWorkItemFiles(files: File[]): string | null {\n if (files.length > WORK_ITEM_ATTACHMENT_MAX_COUNT) {\n return `Too many attachments (max ${WORK_ITEM_ATTACHMENT_MAX_COUNT})`;\n }\n for (const file of files) {\n if (file.size > WORK_ITEM_ATTACHMENT_MAX_BYTES) {\n return `Attachment ${JSON.stringify(file.name || 'upload')} exceeds ${Math.floor(WORK_ITEM_ATTACHMENT_MAX_BYTES / (1024 * 1024))}MB limit`;\n }\n }\n return null;\n}\n\nasync function uploadedFileToBuffer(file: File): Promise<{ name: string; buffer: Buffer; mimeType: string }> {\n return {\n name: file.name || 'upload',\n buffer: Buffer.from(await file.arrayBuffer()),\n mimeType: file.type || 'application/octet-stream',\n };\n}\n\nfunction parseCsvEnum<T extends string>(raw: string | undefined, values: readonly T[]): T[] | undefined {\n if (!raw) return undefined;\n const allowed = new Set(values);\n const parsed = raw\n .split(',')\n .map((item) => item.trim())\n .filter((item): item is T => allowed.has(item as T));\n return parsed.length > 0 ? [...new Set(parsed)] : undefined;\n}\n\nfunction parseEnumValue<T extends string>(raw: unknown, values: readonly T[]): T | undefined {\n if (typeof raw !== 'string') return undefined;\n return values.includes(raw as T) ? raw as T : undefined;\n}\n\nconst WORK_ITEM_STATUSES = [\n 'backlog',\n 'todo',\n 'in_progress',\n 'blocked',\n 'needs_input',\n 'in_review',\n 'done',\n 'cancelled',\n] as const satisfies readonly WorkItemStatus[];\nconst WORK_ITEM_PRIORITIES = ['urgent', 'high', 'normal', 'low'] as const satisfies readonly WorkItemPriority[];\nconst WORK_ITEM_SUGGESTION_STATUSES = ['pending', 'applied', 'dismissed'] as const;\n\nconst SKIP_FILE_NAMES = new Set(['.git', 'node_modules']);\n\nconst PROJECT_FILE_MIME_BY_EXT: Record<string, string> = {\n png: 'image/png',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n gif: 'image/gif',\n webp: 'image/webp',\n bmp: 'image/bmp',\n svg: 'image/svg+xml',\n pdf: 'application/pdf',\n docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',\n pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',\n txt: 'text/plain',\n md: 'text/markdown',\n json: 'application/json',\n html: 'text/html',\n css: 'text/css',\n js: 'text/javascript',\n ts: 'text/typescript',\n mp3: 'audio/mpeg',\n wav: 'audio/wav',\n ogg: 'audio/ogg',\n webm: 'video/webm',\n mp4: 'video/mp4',\n mov: 'video/quicktime',\n};\n\nfunction normalizeRelativePath(raw: string | undefined): string {\n const normalized = (raw ?? '').trim().replaceAll('\\\\', '/');\n return normalized.replace(/^\\/+/, '');\n}\n\nfunction isWithinDirectory(root: string, target: string): boolean {\n const relativePath = path.relative(root, target);\n return relativePath === '' || (!relativePath.startsWith('..') && !path.isAbsolute(relativePath));\n}\n\nasync function resolveProjectWorkspaceRoot(\n service: AuthenticatedRouteDeps['service'],\n projectId: string,\n): Promise<{ ok: true; projectId: string; root: string } | { ok: false; status: number; error: string }> {\n const project = service.projects.get(projectId);\n if (!project) return { ok: false, status: 404, error: 'Project not found' };\n const workspaceRoot = resolveEffectiveWorkspaceRoot(service, project);\n if (!workspaceRoot?.trim()) {\n return { ok: false, status: 400, error: 'Project workspace root is not set' };\n }\n\n try {\n const root = await realpath(workspaceRoot);\n const rootStat = await stat(root);\n if (!rootStat.isDirectory()) {\n return { ok: false, status: 400, error: 'Project workspace root is not a directory' };\n }\n return { ok: true, projectId: project.id, root };\n } catch (err) {\n log.warn({ err, projectId: project.id, path: workspaceRoot }, 'project workspace root unavailable');\n return { ok: false, status: 404, error: 'Project workspace root is unavailable' };\n }\n}\n\nasync function resolveProjectWorkspacePath(\n service: AuthenticatedRouteDeps['service'],\n projectId: string,\n rawPath: string | undefined,\n): Promise<\n | { ok: true; projectId: string; root: string; requestedPath: string; absolutePath: string; relativePath: string }\n | { ok: false; status: number; error: string }\n> {\n const rootResult = await resolveProjectWorkspaceRoot(service, projectId);\n if (rootResult.ok === false) {\n return { ok: false, status: rootResult.status, error: rootResult.error };\n }\n\n const requestedPath = normalizeRelativePath(rawPath);\n const candidate = path.resolve(rootResult.root, requestedPath);\n if (!isWithinDirectory(rootResult.root, candidate)) {\n return { ok: false, status: 400, error: 'Path is outside project workspace' };\n }\n\n const relativePath = path.relative(rootResult.root, candidate).split(path.sep).join('/');\n return {\n ok: true,\n projectId: rootResult.projectId,\n root: rootResult.root,\n requestedPath,\n absolutePath: candidate,\n relativePath: relativePath === '.' ? '' : relativePath,\n };\n}\n\nasync function resolveExistingProjectWorkspacePath(\n service: AuthenticatedRouteDeps['service'],\n projectId: string,\n rawPath: string | undefined,\n): Promise<\n | {\n ok: true;\n projectId: string;\n root: string;\n requestedPath: string;\n absolutePath: string;\n relativePath: string;\n stat: Awaited<ReturnType<typeof stat>>;\n }\n | { ok: false; status: number; error: string }\n> {\n const resolved = await resolveProjectWorkspacePath(service, projectId, rawPath);\n if (resolved.ok === false) return resolved;\n if (!resolved.requestedPath.trim()) {\n return { ok: false, status: 400, error: 'Missing path' };\n }\n\n let realTarget: string;\n try {\n realTarget = await realpath(resolved.absolutePath);\n } catch {\n return { ok: false, status: 404, error: 'Not found' };\n }\n if (!isWithinDirectory(resolved.root, realTarget)) {\n return { ok: false, status: 400, error: 'Path is outside project workspace' };\n }\n const targetStat = await stat(realTarget);\n return {\n ...resolved,\n absolutePath: realTarget,\n stat: targetStat,\n };\n}\n\nasync function resolveProjectWorkspaceWritePath(\n service: AuthenticatedRouteDeps['service'],\n projectId: string,\n rawPath: string | undefined,\n): Promise<\n | {\n ok: true;\n projectId: string;\n root: string;\n requestedPath: string;\n absolutePath: string;\n relativePath: string;\n existingStat?: Awaited<ReturnType<typeof stat>>;\n }\n | { ok: false; status: number; error: string }\n> {\n const resolved = await resolveProjectWorkspacePath(service, projectId, rawPath);\n if (resolved.ok === false) return resolved;\n if (!resolved.requestedPath.trim()) {\n return { ok: false, status: 400, error: 'Missing path' };\n }\n\n try {\n const realTarget = await realpath(resolved.absolutePath);\n if (!isWithinDirectory(resolved.root, realTarget)) {\n return { ok: false, status: 400, error: 'Path is outside project workspace' };\n }\n return {\n ...resolved,\n absolutePath: realTarget,\n existingStat: await stat(realTarget),\n };\n } catch {\n const parentPath = path.dirname(resolved.absolutePath);\n try {\n const realParent = await realpath(parentPath);\n if (!isWithinDirectory(resolved.root, realParent)) {\n return { ok: false, status: 400, error: 'Path is outside project workspace' };\n }\n } catch {\n return { ok: false, status: 404, error: 'Parent directory not found' };\n }\n return resolved;\n }\n}\n\nfunction textFromTranscriptContent(content: unknown): string {\n if (typeof content === 'string') return content;\n if (!Array.isArray(content)) return '';\n return content\n .map((part) => {\n if (!part || typeof part !== 'object') return '';\n const record = part as Record<string, unknown>;\n return typeof record.text === 'string' ? record.text : '';\n })\n .filter(Boolean)\n .join('\\n');\n}\n\nfunction buildSessionSummaryMemoryContent(sessionKey: string, explicitSummary?: string): string {\n const summary = explicitSummary?.trim();\n if (summary) return summary;\n const rows = loadTranscriptRowsForSession(sessionKey)\n .filter((row) => {\n if (!row || typeof row !== 'object') return false;\n const record = row as unknown as Record<string, unknown>;\n const role = record.role;\n return role === 'user' || role === 'assistant' || role === 'compactionSummary' || role === 'branchSummary';\n })\n .slice(-12);\n const lines = rows\n .map((row) => {\n const record = row as unknown as Record<string, unknown>;\n const rowRole = typeof record.role === 'string' ? record.role : 'message';\n const role = rowRole === 'compactionSummary' || rowRole === 'branchSummary' ? 'summary' : rowRole;\n const text = (typeof record.summary === 'string' ? record.summary : undefined) ?? textFromTranscriptContent(record.content);\n const compact = text.trim().replace(/\\s+/g, ' ').slice(0, 280);\n return compact ? `- ${role}: ${compact}` : '';\n })\n .filter(Boolean);\n return lines.length > 0\n ? [`Session summary for ${sessionKey}:`, ...lines].join('\\n')\n : `Session summary for ${sessionKey}: no transcript content available.`;\n}\n\nfunction buildWorkItemChatSessionMetadata(params: {\n agentId: string;\n accountId: string;\n peerId: string;\n workItemId: string;\n title: string;\n updatedAt: number;\n}): SessionMetadataSeed {\n return {\n name: params.title,\n tags: ['work-item'],\n sourceChannel: 'webchat',\n sourceChatId: [params.accountId, 'direct', params.peerId].join(':'),\n sessionType: 'chat',\n hiddenFromSessionList: true,\n routing: {\n agentId: params.agentId,\n source: 'webchat',\n accountId: params.accountId,\n peerKind: 'direct',\n peerId: params.peerId,\n },\n customData: {\n genericNewChatShell: false,\n sourceBinding: {\n kind: 'work_item',\n sourceId: params.workItemId,\n version: String(params.updatedAt),\n attachedAt: Date.now(),\n },\n },\n };\n}\n\nfunction listFailedProjectWorkflowRuns(projectId: string, limit = 5): ProjectWorkflowRunBrief[] {\n const rows = getSqliteDatabase()\n .prepare(\n `SELECT run_id, definition_id, status, created_at_ms, error_message\n FROM workflow_runs\n WHERE project_id = ? AND status IN ('failed', 'timeout', 'cancelled')\n ORDER BY created_at_ms DESC\n LIMIT ?`,\n )\n .all(projectId, Math.max(1, Math.min(20, Math.floor(limit)))) as Array<{\n run_id: string;\n definition_id: string;\n status: string;\n created_at_ms: number;\n error_message: string | null;\n }>;\n return rows.map((row) => ({\n runId: row.run_id,\n definitionId: row.definition_id,\n status: row.status,\n createdAt: row.created_at_ms,\n errorMessage: row.error_message ?? undefined,\n }));\n}\n\nfunction buildProjectDigestMemoryContent(input: ReturnType<typeof buildProjectLoopOverview> & { projectName: string }): string {\n const lines = [\n `Project digest: ${input.projectName}`,\n `Status: ${input.digest.summary}`,\n input.digest.nextAction ? `Next: ${input.digest.nextAction}` : undefined,\n ].filter(Boolean) as string[];\n if (input.attentionItems.length > 0) {\n lines.push('', 'Attention:');\n for (const item of input.attentionItems.slice(0, 8)) {\n lines.push(`- ${item.kind}: ${item.title}${item.detail ? ` - ${item.detail}` : ''}`);\n }\n }\n if (input.timeline.length > 0) {\n lines.push('', 'Recent activity:');\n for (const item of input.timeline.slice(0, 8)) {\n lines.push(`- ${item.kind}: ${item.title}${item.detail ? ` - ${item.detail}` : ''}`);\n }\n }\n return lines.join('\\n');\n}\n\nfunction projectDigestMemoryRecordId(projectId: string): string {\n return `project-digest:${projectId}`;\n}\n\nexport function registerProjectsRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service } = deps;\n const activity = new ActivityService();\n const goals = new GoalService();\n const workItems = new WorkItemService();\n\n authenticated.post('/api/projects', async (c) => {\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const name = textField(body, 'name')?.trim();\n const workspaceRoot = textField(body, 'workspaceRoot')?.trim();\n if (!name && !workspaceRoot) return c.json({ ok: false, error: 'Missing name' }, 400);\n const hasDefaultAgentPatch = Object.hasOwn(body, 'defaultAgentId');\n const explicitDefaultAgentId = normalizeProjectAgentId(textField(body, 'defaultAgentId'));\n const defaultAgentId = hasDefaultAgentPatch\n ? explicitDefaultAgentId\n : inferSuggestedProjectDefaultAgentId({\n config: service.currentConfig,\n name,\n description: textField(body, 'description'),\n workspaceRoot,\n projectKind: textField(body, 'projectKind'),\n });\n if (!isValidProjectAgentId(service.currentConfig, defaultAgentId)) {\n return c.json({ ok: false, error: 'Default agent not found' }, 400);\n }\n try {\n const project = service.projects.create({\n name,\n description: textField(body, 'description'),\n defaultAgentId,\n workspaceRoot,\n createWorkspaceRoot: body.createWorkspaceRoot === true,\n projectKind: textField(body, 'projectKind'),\n brief: textField(body, 'brief'),\n instructions: textField(body, 'instructions'),\n });\n return c.json({ ok: true, project: enrichProjectWorkspace(service, project) }, 201);\n } catch (error) {\n if (error instanceof ProjectWorkspaceConflictError) {\n return c.json({ ok: false, code: 'workspace_already_bound', error: error.message, project: error.project }, 409);\n }\n if (error instanceof ProjectWorkspaceMissingError) {\n return c.json({ ok: false, code: 'workspace_root_missing', error: error.message, workspaceRoot: error.workspaceRoot }, 409);\n }\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 400);\n }\n });\n\n authenticated.get('/api/projects', async (c) => {\n const status = parseProjectStatus(c.req.query('status'));\n const result = service.projects.list({\n ...(status ? { status } : {}),\n search: c.req.query('search'),\n sortBy: c.req.query('sortBy') as 'updatedAt' | 'createdAt' | 'name' | undefined,\n sortOrder: c.req.query('sortOrder') as 'asc' | 'desc' | undefined,\n limit: parseLimit(c.req.query('limit')),\n offset: c.req.query('offset') ? Math.max(0, Number.parseInt(c.req.query('offset')!, 10) || 0) : undefined,\n });\n return c.json({ ok: true, ...result, items: result.items.map((project) => enrichProjectWorkspace(service, project)) });\n });\n\n authenticated.get('/api/projects/suggestions', async (c) => {\n const sessionKey = c.req.query('sessionKey')?.trim();\n return c.json({ ok: true, suggestions: sessionKey ? service.projects.suggestProjectsForSession(sessionKey) : [] });\n });\n\n authenticated.post('/api/projects/infer-defaults', async (c) => {\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const input = {\n name: textField(body, 'name'),\n description: textField(body, 'description'),\n workspaceRoot: textField(body, 'workspaceRoot'),\n projectKind: textField(body, 'projectKind'),\n };\n const inference = inferProjectKind(input);\n const defaultAgentId = inferSuggestedProjectDefaultAgentId({\n config: service.currentConfig,\n ...input,\n });\n return c.json({ ok: true, inference, defaultAgentId });\n });\n\n authenticated.post('/api/projects/resolve-workspace', async (c) => {\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const workspacePath = textField(body, 'workspacePath')?.trim();\n if (!workspacePath) return c.json({ ok: false, error: 'Missing workspacePath' }, 400);\n const agentId = textField(body, 'agentId')?.trim() || 'main';\n const suggestedDefaultAgentId = inferSuggestedProjectDefaultAgentId({\n config: service.currentConfig,\n workspaceRoot: workspacePath,\n projectKind: textField(body, 'projectKind'),\n });\n let match;\n try {\n match = service.projects.resolveOrCreateForWorkspacePath({\n workspacePath,\n agentId,\n defaultAgentId: suggestedDefaultAgentId,\n autoCreate: body.autoCreate !== false,\n });\n } catch (error) {\n if (error instanceof ProjectWorkspaceConflictError) {\n match = { project: error.project, reason: 'exact' as const, created: false };\n } else {\n throw error;\n }\n }\n if (!match) return c.json({ ok: true, project: null });\n\n const sessionKey = textField(body, 'sessionKey')?.trim();\n const projectDefaultAgentId = normalizeProjectAgentId(match.project.defaultAgentId);\n const shouldBindRequestedSession = !projectDefaultAgentId || projectDefaultAgentId === normalizeProjectAgentId(agentId);\n if (sessionKey && shouldBindRequestedSession) {\n const existingSession = getSessionMetadata(sessionKey);\n if (!existingSession) {\n await service.sessionIndexInstance.saveMessages(sessionKey, [], {\n metadata: {\n sourceChannel: 'tui',\n sourceChatId: `default:direct:${sessionKey}`,\n sessionType: 'chat',\n projectId: match.project.id,\n routing: {\n agentId,\n source: 'tui',\n accountId: 'default',\n peerKind: 'direct',\n peerId: sessionKey,\n },\n },\n });\n }\n service.projects.attachSession(sessionKey, match.project.id);\n }\n\n return c.json({ ok: true, ...match });\n });\n\n authenticated.get('/api/projects/:id/overview', async (c) => {\n const project = service.projects.getWithDetails(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const goalIds = service.projects.listGoalIds(project.id, parseLimit(c.req.query('goalLimit'), 100));\n const projectGoals = goalIds\n .map((id) => goals.get(id))\n .filter((goal): goal is GoalWithDetails => Boolean(goal));\n const loop = buildProjectLoopOverview({\n project,\n goals: projectGoals,\n recentWorkflowRuns: project.recentWorkflowRuns,\n failedWorkflowRuns: listFailedProjectWorkflowRuns(project.id),\n memoryRecords: listMemoryRecords({ projectId: project.id, status: 'active', limit: 5 }),\n });\n return c.json({\n ok: true,\n overview: {\n project: enrichProjectWorkspace(service, project),\n stats: {\n sessionCount: project.sessionCount,\n goalCount: project.goalCount,\n activeGoalCount: project.activeGoalCount,\n recentWorkflowRunCount: project.recentWorkflowRuns.length,\n staleGoalCount: loop.staleGoals.length,\n attentionCount: loop.attentionItems.length,\n failedWorkflowRunCount: loop.failedWorkflowRuns.length,\n },\n activeGoals: loop.activeGoals,\n blockedGoals: loop.blockedGoals,\n staleGoals: loop.staleGoals,\n nextActions: loop.nextActions,\n attentionItems: loop.attentionItems,\n timeline: loop.timeline,\n digest: loop.digest,\n failedWorkflowRuns: loop.failedWorkflowRuns,\n recentSessions: project.recentSessions,\n recentWorkflowRuns: project.recentWorkflowRuns,\n recommendedAction: loop.recommendedAction,\n },\n });\n });\n\n authenticated.get('/api/projects/:id/activity', (c) => {\n const project = service.projects.get(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const result = activity.listForProject({\n projectId: project.id,\n includeRelated: parseActivityIncludeRelated(c.req.query('includeRelated')),\n ...parseActivityQuery(c),\n });\n return c.json({ ok: true, ...result });\n });\n\n authenticated.get('/api/projects/:id/work-items', async (c) => {\n const project = service.projects.get(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const result = workItems.listProjectWorkItems(project.id, {\n status: parseCsvEnum(c.req.query('status'), WORK_ITEM_STATUSES),\n priority: parseCsvEnum(c.req.query('priority'), WORK_ITEM_PRIORITIES),\n includeArchived: c.req.query('includeArchived') === 'true',\n search: c.req.query('search'),\n sortBy: c.req.query('sortBy') as 'updatedAt' | 'createdAt' | 'priority' | 'status' | undefined,\n sortOrder: c.req.query('sortOrder') as 'asc' | 'desc' | undefined,\n limit: parseLimit(c.req.query('limit')),\n offset: c.req.query('offset') ? Math.max(0, Number.parseInt(c.req.query('offset')!, 10) || 0) : undefined,\n });\n return c.json({ ok: true, ...result });\n });\n\n authenticated.post('/api/projects/:id/work-items', async (c) => {\n const project = service.projects.get(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const contentType = c.req.header('content-type') || '';\n let body: Record<string, unknown>;\n let files: File[] = [];\n if (contentType.includes('multipart/form-data')) {\n try {\n body = await c.req.parseBody({ all: true }) as Record<string, unknown>;\n } catch {\n return c.json({ ok: false, error: 'Invalid multipart body' }, 400);\n }\n files = collectUploadedFiles(body);\n } else {\n body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n }\n const attachmentError = validateUploadedWorkItemFiles(files);\n if (attachmentError) return c.json({ ok: false, error: attachmentError }, 413);\n const title = textField(body, 'title')?.trim();\n if (!title) return c.json({ ok: false, error: 'Work item title is required' }, 400);\n const status = parseEnumValue(body.status, WORK_ITEM_STATUSES);\n const priority = parseEnumValue(body.priority, WORK_ITEM_PRIORITIES);\n const dueAt = finiteNumberField(body.dueAt);\n if (Object.hasOwn(body, 'status') && !status) return c.json({ ok: false, error: 'Invalid work item status' }, 400);\n if (Object.hasOwn(body, 'priority') && !priority) return c.json({ ok: false, error: 'Invalid work item priority' }, 400);\n if (Object.hasOwn(body, 'dueAt') && dueAt === undefined && body.dueAt !== null) return c.json({ ok: false, error: 'Invalid dueAt' }, 400);\n const uploads: Array<{ name: string; buffer: Buffer; mimeType: string }> = [];\n for (const file of files) {\n uploads.push(await uploadedFileToBuffer(file));\n }\n const item = workItems.createProjectWorkItem(project.id, {\n title,\n description: textField(body, 'description'),\n status,\n priority,\n ownerAgentId: textField(body, 'ownerAgentId') || project.defaultAgentId || undefined,\n nextAction: textField(body, 'nextAction'),\n blockedReason: textField(body, 'blockedReason'),\n dueAt,\n });\n for (const upload of uploads) {\n await workItems.addAttachment(item.id, upload);\n }\n const created = files.length > 0 ? workItems.getWorkItem(item.id) ?? item : item;\n return c.json({ ok: true, item: created }, 201);\n });\n\n authenticated.get('/api/work-items/:id', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n return c.json({ ok: true, item });\n });\n\n authenticated.get('/api/work-items/:id/attachments', async (c) => {\n const attachments = workItems.listAttachments(c.req.param('id'));\n if (!attachments) return c.json({ ok: false, error: 'Work item not found' }, 404);\n return c.json({ ok: true, attachments });\n });\n\n authenticated.post('/api/work-items/:id/attachments', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n let body: Record<string, unknown>;\n try {\n body = await c.req.parseBody({ all: true }) as Record<string, unknown>;\n } catch {\n return c.json({ ok: false, error: 'Invalid multipart body' }, 400);\n }\n const files = collectUploadedFiles(body);\n if (!files.length) return c.json({ ok: false, error: 'Missing file field' }, 400);\n const attachmentError = validateUploadedWorkItemFiles(files);\n if (attachmentError) return c.json({ ok: false, error: attachmentError }, 413);\n const attachments = [];\n for (const file of files) {\n const upload = await uploadedFileToBuffer(file);\n const attachment = await workItems.addAttachment(item.id, upload);\n if (attachment) attachments.push(attachment);\n }\n return c.json({ ok: true, attachments, item: workItems.getWorkItem(item.id) }, 201);\n });\n\n authenticated.get('/api/work-items/:id/attachments/:attachmentId/content', async (c) => {\n const result = await workItems.readAttachment(c.req.param('id'), c.req.param('attachmentId'));\n if (!result) return c.json({ ok: false, error: 'Attachment not found' }, 404);\n return new Response(result.buffer, {\n headers: {\n 'Content-Type': result.attachment.mimeType,\n 'Content-Length': String(result.attachment.size),\n 'Content-Disposition': `inline; filename=\"${encodeURIComponent(result.attachment.fileName)}\"`,\n 'Cache-Control': 'private, max-age=31536000, immutable',\n },\n });\n });\n\n authenticated.delete('/api/work-items/:id/attachments/:attachmentId', async (c) => {\n const attachment = await workItems.removeAttachment(c.req.param('id'), c.req.param('attachmentId'));\n if (!attachment) return c.json({ ok: false, error: 'Attachment not found' }, 404);\n return c.json({ ok: true, attachment, item: workItems.getWorkItem(c.req.param('id')) });\n });\n\n authenticated.patch('/api/work-items/:id', async (c) => {\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const status = Object.hasOwn(body, 'status')\n ? parseEnumValue(body.status, WORK_ITEM_STATUSES)\n : undefined;\n const priority = Object.hasOwn(body, 'priority')\n ? parseEnumValue(body.priority, WORK_ITEM_PRIORITIES)\n : undefined;\n const dueAt = Object.hasOwn(body, 'dueAt')\n ? (body.dueAt === null ? null : (typeof body.dueAt === 'number' && Number.isFinite(body.dueAt) ? body.dueAt : undefined))\n : undefined;\n const archivedAt = Object.hasOwn(body, 'archivedAt')\n ? (body.archivedAt === null ? null : (typeof body.archivedAt === 'number' && Number.isFinite(body.archivedAt) ? body.archivedAt : undefined))\n : undefined;\n if (status === undefined && Object.hasOwn(body, 'status')) return c.json({ ok: false, error: 'Invalid work item status' }, 400);\n if (priority === undefined && Object.hasOwn(body, 'priority')) return c.json({ ok: false, error: 'Invalid work item priority' }, 400);\n if (dueAt === undefined && Object.hasOwn(body, 'dueAt')) return c.json({ ok: false, error: 'Invalid dueAt' }, 400);\n if (archivedAt === undefined && Object.hasOwn(body, 'archivedAt')) return c.json({ ok: false, error: 'Invalid archivedAt' }, 400);\n\n const item = workItems.updateWorkItem(c.req.param('id'), {\n ...(Object.hasOwn(body, 'title') ? { title: textField(body, 'title') ?? '' } : {}),\n ...(Object.hasOwn(body, 'description') ? { description: optionalTextField(body, 'description') } : {}),\n ...(Object.hasOwn(body, 'status') ? { status } : {}),\n ...(Object.hasOwn(body, 'priority') ? { priority } : {}),\n ...(Object.hasOwn(body, 'ownerAgentId') ? { ownerAgentId: optionalTextField(body, 'ownerAgentId') } : {}),\n ...(Object.hasOwn(body, 'nextAction') ? { nextAction: optionalTextField(body, 'nextAction') } : {}),\n ...(Object.hasOwn(body, 'blockedReason') ? { blockedReason: optionalTextField(body, 'blockedReason') } : {}),\n ...(Object.hasOwn(body, 'dueAt') ? { dueAt } : {}),\n ...(Object.hasOwn(body, 'archivedAt') ? { archivedAt } : {}),\n });\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n return c.json({ ok: true, item });\n });\n\n authenticated.delete('/api/work-items/:id', async (c) => {\n const item = workItems.updateWorkItem(c.req.param('id'), { archivedAt: Date.now() });\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n return c.json({ ok: true, item });\n });\n\n authenticated.get('/api/work-items/:id/events', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n return c.json({ ok: true, events: workItems.listEvents(item.id) });\n });\n\n authenticated.get('/api/work-items/:id/update-suggestions', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n const status = parseEnumValue(c.req.query('status'), WORK_ITEM_SUGGESTION_STATUSES);\n if (c.req.query('status') && !status) return c.json({ ok: false, error: 'Invalid suggestion status' }, 400);\n return c.json({ ok: true, suggestions: workItems.listUpdateSuggestions(item.id, status) });\n });\n\n authenticated.post('/api/work-items/:id/update-suggestions', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const sourceKind = parseEnumValue(body.sourceKind, ['chat', 'goal', 'workflow_run', 'automation'] as const);\n const sourceId = textField(body, 'sourceId')?.trim();\n if (!sourceKind) return c.json({ ok: false, error: 'Invalid sourceKind' }, 400);\n if (!sourceId) return c.json({ ok: false, error: 'sourceId is required' }, 400);\n const patchBody = body.patch && typeof body.patch === 'object' && !Array.isArray(body.patch)\n ? body.patch as Record<string, unknown>\n : {};\n const status = Object.hasOwn(patchBody, 'status')\n ? parseEnumValue(patchBody.status, WORK_ITEM_STATUSES)\n : undefined;\n if (Object.hasOwn(patchBody, 'status') && !status) return c.json({ ok: false, error: 'Invalid work item status' }, 400);\n const confidence = typeof body.confidence === 'number' && Number.isFinite(body.confidence)\n ? Math.max(0, Math.min(1, body.confidence))\n : undefined;\n const suggestion = workItems.createUpdateSuggestion(item.id, {\n sourceKind,\n sourceId,\n patch: {\n ...(Object.hasOwn(patchBody, 'status') ? { status } : {}),\n ...(Object.hasOwn(patchBody, 'nextAction') ? { nextAction: optionalTextField(patchBody, 'nextAction') } : {}),\n ...(Object.hasOwn(patchBody, 'blockedReason') ? { blockedReason: optionalTextField(patchBody, 'blockedReason') } : {}),\n },\n progressNote: optionalTextField(body, 'progressNote') ?? undefined,\n rationale: optionalTextField(body, 'rationale') ?? undefined,\n confidence,\n });\n if (!suggestion) return c.json({ ok: false, error: 'Work item not found' }, 404);\n return c.json({ ok: true, suggestion }, 201);\n });\n\n authenticated.post('/api/work-item-update-suggestions/:id/apply', async (c) => {\n const result = workItems.applyUpdateSuggestion(c.req.param('id'));\n if (!result) return c.json({ ok: false, error: 'Suggestion not found or already resolved' }, 404);\n return c.json({ ok: true, item: result.item, suggestion: result.suggestion });\n });\n\n authenticated.post('/api/work-item-update-suggestions/:id/dismiss', async (c) => {\n const suggestion = workItems.dismissUpdateSuggestion(c.req.param('id'));\n if (!suggestion) return c.json({ ok: false, error: 'Suggestion not found or already resolved' }, 404);\n return c.json({ ok: true, suggestion });\n });\n\n authenticated.post('/api/work-items/:id/start-chat', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n const project = service.projects.get(item.projectId);\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const agentId = resolveProjectAgentId({\n config: service.currentConfig,\n projects: service.projects,\n explicitAgentId: item.ownerAgentId,\n projectId: project.id,\n });\n const peerId = `work_item_${Date.now()}`;\n const sessionKey = buildSessionKey({\n agentId,\n source: 'webchat',\n accountId: 'default',\n peerKind: 'direct',\n peerId,\n });\n await service.sessionIndexInstance.saveMessages(sessionKey, [], {\n metadata: buildWorkItemChatSessionMetadata({\n agentId,\n accountId: 'default',\n peerId,\n workItemId: item.id,\n title: item.title,\n updatedAt: item.updatedAt,\n }),\n });\n service.projects.attachSession(sessionKey, project.id);\n const session = await service.sessions.getSession(sessionKey);\n workItems.addLink(item.id, {\n kind: 'chat',\n targetId: sessionKey,\n title: session?.name || item.title,\n statusSnapshot: session?.status,\n }, 'chat_started');\n const updated = item.status === 'todo' || item.status === 'backlog'\n ? workItems.updateWorkItem(item.id, { status: 'in_progress' })\n : workItems.getWorkItem(item.id);\n return c.json({ ok: true, session, item: updated }, 201);\n });\n\n authenticated.post('/api/work-items/:id/create-goal', async (c) => {\n const item = workItems.getWorkItem(c.req.param('id'));\n if (!item) return c.json({ ok: false, error: 'Work item not found' }, 404);\n const project = service.projects.get(item.projectId);\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const attachments = await workItems.snapshotAttachmentsForGoal(item.id);\n if (!attachments) return c.json({ ok: false, error: 'Work item not found' }, 404);\n const context = await buildWorkItemAgentContext(item, { attachments, includeImages: false });\n const goal = goals.create({\n title: item.title,\n description: item.description || item.nextAction,\n priority: item.priority === 'urgent' ? 'high' : item.priority,\n agentId: item.ownerAgentId || project.defaultAgentId || undefined,\n projectId: project.id,\n source: 'api',\n config: service.currentConfig,\n });\n const goalWithContext = goals.setContextMessage({\n goalId: goal.id,\n text: context.text,\n attachments,\n }) ?? goal;\n workItems.addLink(item.id, {\n kind: 'goal',\n targetId: goal.id,\n title: goal.title,\n statusSnapshot: goal.status,\n }, 'goal_created');\n const updated = item.status === 'todo' || item.status === 'backlog'\n ? workItems.updateWorkItem(item.id, { status: 'in_progress' })\n : workItems.getWorkItem(item.id);\n return c.json({ ok: true, goal: goalWithContext, item: updated }, 201);\n });\n\n authenticated.post('/api/projects/:id/digest-memory', async (c) => {\n const project = service.projects.getWithDetails(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const goalIds = service.projects.listGoalIds(project.id, 100);\n const projectGoals = goalIds\n .map((id) => goals.get(id))\n .filter((goal): goal is GoalWithDetails => Boolean(goal));\n const loop = buildProjectLoopOverview({\n project,\n goals: projectGoals,\n recentWorkflowRuns: project.recentWorkflowRuns,\n failedWorkflowRuns: listFailedProjectWorkflowRuns(project.id),\n memoryRecords: listMemoryRecords({ projectId: project.id, status: 'active', limit: 5 }),\n });\n const record = upsertMemoryRecord({\n id: projectDigestMemoryRecordId(project.id),\n providerId: 'local',\n kind: 'daily_note',\n agentId: resolveProjectAgentId({\n config: service.currentConfig,\n projects: service.projects,\n projectId: project.id,\n }),\n workspaceId: project.workspaceRoot,\n projectId: project.id,\n content: buildProjectDigestMemoryContent({ ...loop, projectName: project.name }),\n source: {\n provider: 'project-digest',\n },\n confidence: 0.75,\n tags: ['project', 'project-digest', project.slug],\n status: 'active',\n sensitivity: 'normal',\n });\n return c.json({ ok: true, record }, 201);\n });\n\n authenticated.post('/api/projects/:id/blockers', async (c) => {\n const project = service.projects.getWithDetails(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const title = typeof body.title === 'string' ? body.title.trim() : '';\n if (!title) return c.json({ ok: false, error: 'Missing title' }, 400);\n const reason = typeof body.reason === 'string' ? body.reason.trim() : '';\n const goal = goals.create({\n title,\n description: reason || undefined,\n agentId: resolveProjectAgentId({\n config: service.currentConfig,\n projects: service.projects,\n projectId: project.id,\n }),\n priority: body.priority === 'low' || body.priority === 'normal' || body.priority === 'high' ? body.priority : 'high',\n source: 'api',\n projectId: project.id,\n });\n const blocked = goals.setStatus(goal.id, 'blocked', { reason: reason || title });\n if (reason) {\n goals.setContextMessage({ goalId: goal.id, text: reason });\n }\n return c.json({ ok: true, goal: blocked ?? goals.get(goal.id) }, 201);\n });\n\n authenticated.post('/api/projects/:id/pin', async (c) => {\n try {\n const project = service.projects.pin(c.req.param('id'));\n return c.json({ ok: true, project: enrichProjectWorkspace(service, project) });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.post('/api/projects/:id/unpin', async (c) => {\n try {\n const project = service.projects.unpin(c.req.param('id'));\n return c.json({ ok: true, project: enrichProjectWorkspace(service, project) });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.get('/api/projects/:id', async (c) => {\n const project = service.projects.getWithDetails(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n return c.json({ ok: true, project: enrichProjectWorkspace(service, project) });\n });\n\n authenticated.patch('/api/projects/:id', async (c) => {\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const status = parseProjectStatus(body.status);\n const defaultAgentPatch = optionalTextField(body, 'defaultAgentId');\n const defaultAgentId = defaultAgentPatch === undefined ? undefined : normalizeProjectAgentId(defaultAgentPatch);\n if (defaultAgentId && !isValidProjectAgentId(service.currentConfig, defaultAgentId)) {\n return c.json({ ok: false, error: 'Default agent not found' }, 400);\n }\n try {\n const project = service.projects.update(c.req.param('id'), {\n ...(textField(body, 'name') !== undefined ? { name: textField(body, 'name') } : {}),\n ...(optionalTextField(body, 'description') !== undefined ? { description: optionalTextField(body, 'description') } : {}),\n ...(status ? { status } : {}),\n ...(defaultAgentPatch !== undefined ? { defaultAgentId: defaultAgentId ?? null } : {}),\n ...(optionalTextField(body, 'workspaceRoot') !== undefined ? { workspaceRoot: optionalTextField(body, 'workspaceRoot') } : {}),\n createWorkspaceRoot: body.createWorkspaceRoot === true,\n ...(optionalTextField(body, 'brief') !== undefined ? { brief: optionalTextField(body, 'brief') } : {}),\n ...(optionalTextField(body, 'instructions') !== undefined ? { instructions: optionalTextField(body, 'instructions') } : {}),\n });\n return c.json({ ok: true, project: enrichProjectWorkspace(service, project) });\n } catch (error) {\n if (error instanceof ProjectWorkspaceConflictError) {\n return c.json({ ok: false, code: 'workspace_already_bound', error: error.message, project: error.project }, 409);\n }\n if (error instanceof ProjectWorkspaceMissingError) {\n return c.json({ ok: false, code: 'workspace_root_missing', error: error.message, workspaceRoot: error.workspaceRoot }, 409);\n }\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.delete('/api/projects/:id', async (c) => {\n service.projects.delete(c.req.param('id'));\n return c.json({ ok: true });\n });\n\n authenticated.get('/api/projects/:id/sessions', async (c) => {\n try {\n const keys = service.projects.listSessionKeys(c.req.param('id'), parseLimit(c.req.query('limit'), 100));\n const sessions = await Promise.all(keys.map((key) => service.sessions.getSession(key)));\n return c.json({\n ok: true,\n sessions: sessions.filter((session) => session && !isHiddenEmptyProjectChatShell(session)),\n });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.get('/api/projects/:id/goals', async (c) => {\n try {\n const ids = service.projects.listGoalIds(c.req.param('id'), parseLimit(c.req.query('limit'), 100));\n return c.json({ ok: true, goals: ids.map((id) => goals.get(id)).filter(Boolean) });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.get('/api/projects/:id/files', async (c) => {\n const resolved = await resolveProjectWorkspacePath(service, c.req.param('id'), c.req.query('path'));\n if (resolved.ok === false) return c.json({ ok: false, error: resolved.error }, resolved.status as 400);\n const { root, absolutePath: candidate } = resolved;\n let currentPath: string;\n try {\n currentPath = await realpath(candidate);\n if (!isWithinDirectory(root, currentPath)) {\n return c.json({ ok: false, error: 'Path is outside project workspace' }, 400);\n }\n const currentStat = await stat(currentPath);\n if (!currentStat.isDirectory()) {\n return c.json({ ok: false, error: 'Path is not a directory' }, 400);\n }\n } catch (err) {\n log.warn({ err, projectId: resolved.projectId, path: candidate }, 'project file path unavailable');\n return c.json({ ok: false, error: 'Path not found' }, 404);\n }\n\n try {\n const dirents = await readdir(currentPath, { withFileTypes: true });\n const entries = await Promise.all(dirents\n .filter((entry) => !SKIP_FILE_NAMES.has(entry.name))\n .map(async (entry) => {\n const displayPath = path.join(currentPath, entry.name);\n const absolutePath = await realpath(displayPath).catch(() => null);\n if (!absolutePath || !isWithinDirectory(root, absolutePath)) return null;\n const entryStat = await stat(absolutePath).catch(() => null);\n if (!entryStat) return null;\n const relativePath = path.relative(root, displayPath).split(path.sep).join('/');\n return {\n name: entry.name,\n path: relativePath,\n absolutePath,\n type: entryStat.isDirectory() ? 'directory' : 'file',\n size: entryStat?.isFile() ? entryStat.size : undefined,\n updatedAt: entryStat?.mtime.toISOString(),\n };\n }));\n const visibleEntries = entries.filter((entry): entry is NonNullable<typeof entry> => entry !== null);\n visibleEntries.sort((left, right) => {\n if (left.type !== right.type) return left.type === 'directory' ? -1 : 1;\n return left.name.localeCompare(right.name);\n });\n const relativeCurrentPath = path.relative(root, currentPath).split(path.sep).join('/');\n const parentRelativePath = relativeCurrentPath ? path.dirname(relativeCurrentPath).replaceAll('\\\\', '/') : null;\n return c.json({\n ok: true,\n root,\n path: relativeCurrentPath === '.' ? '' : relativeCurrentPath,\n parentPath: parentRelativePath === '.' ? '' : parentRelativePath,\n entries: visibleEntries,\n });\n } catch (err) {\n log.warn({ err, projectId: resolved.projectId, path: currentPath }, 'project file list failed');\n if ((err as NodeJS.ErrnoException)?.code === 'EACCES') {\n return c.json({ ok: false, error: 'Permission denied' }, 403);\n }\n return c.json({ ok: false, error: 'Failed to read project files' }, 500);\n }\n });\n\n authenticated.get('/api/projects/:id/files/read', async (c) => {\n const resolved = await resolveExistingProjectWorkspacePath(service, c.req.param('id'), c.req.query('path'));\n if (resolved.ok === false) return c.json({ ok: false, error: { message: resolved.error } }, resolved.status as 400);\n if (!resolved.stat.isFile()) {\n return c.json({ ok: false, error: { message: 'Not a file' } }, 400);\n }\n try {\n const content = await readFile(resolved.absolutePath, 'utf-8');\n return c.json({\n ok: true,\n payload: {\n content,\n path: resolved.relativePath,\n absolutePath: resolved.absolutePath,\n mtimeMs: resolved.stat.mtimeMs,\n },\n });\n } catch {\n return c.json({ ok: false, error: { message: 'Read failed' } }, 500);\n }\n });\n\n authenticated.get('/api/projects/:id/files/raw', async (c) => {\n const resolved = await resolveExistingProjectWorkspacePath(service, c.req.param('id'), c.req.query('path'));\n if (resolved.ok === false) return c.json({ ok: false, error: { message: resolved.error } }, resolved.status as 400);\n if (!resolved.stat.isFile()) {\n return c.json({ ok: false, error: { message: 'Not a file' } }, 400);\n }\n const ext = resolved.relativePath.split('.').pop()?.toLowerCase() ?? '';\n const contentType = PROJECT_FILE_MIME_BY_EXT[ext] || 'application/octet-stream';\n try {\n const buf = await readFile(resolved.absolutePath);\n return new Response(buf, {\n headers: {\n 'Content-Type': contentType,\n 'Cache-Control': 'private, max-age=3600',\n },\n });\n } catch {\n return c.json({ ok: false, error: { message: 'Read failed' } }, 500);\n }\n });\n\n authenticated.get('/api/projects/:id/files/resolve-reference', async (c) => {\n const rawPath = typeof c.req.query('path') === 'string' ? c.req.query('path')!.trim() : '';\n if (!rawPath) {\n return c.json({ ok: false, error: { code: 'INVALID_PATH', message: 'Missing path' } }, 400);\n }\n const resolved = await resolveProjectWorkspacePath(service, c.req.param('id'), rawPath);\n if (resolved.ok === false) {\n return c.json({ ok: false, error: { code: 'PROJECT_WORKSPACE_RESOLUTION_FAILED', message: resolved.error } }, resolved.status as 400);\n }\n let st: Awaited<ReturnType<typeof stat>> | null = null;\n let absolutePath = resolved.absolutePath;\n try {\n absolutePath = await realpath(resolved.absolutePath);\n if (!isWithinDirectory(resolved.root, absolutePath)) {\n return c.json({\n ok: false,\n error: { code: 'PROJECT_WORKSPACE_RESOLUTION_FAILED', message: 'Path is outside project workspace' },\n }, 400);\n }\n st = await stat(absolutePath);\n } catch {\n st = null;\n }\n const displayName = path.basename(rawPath);\n if (!st) {\n return c.json({\n ok: true,\n payload: {\n inputPath: rawPath,\n displayName,\n scope: 'missing',\n exists: false,\n absolutePath: resolved.absolutePath,\n capabilities: ['copyPath'],\n errorCode: 'FILE_NOT_FOUND',\n },\n });\n }\n return c.json({\n ok: true,\n payload: {\n inputPath: rawPath,\n displayName,\n scope: 'workspace',\n exists: true,\n isDirectory: st.isDirectory(),\n absolutePath,\n workspaceRelativePath: resolved.relativePath,\n capabilities: st.isDirectory()\n ? ['openExternal', 'revealInFolder', 'copyPath']\n : ['preview', 'edit', 'openExternal', 'revealInFolder', 'copyPath'],\n mtimeMs: st.mtimeMs,\n },\n });\n });\n\n authenticated.put('/api/projects/:id/files/write', async (c) => {\n let body: unknown;\n try {\n body = await c.req.json();\n } catch {\n return c.json({ ok: false, error: { message: 'Invalid JSON' } }, 400);\n }\n const bodyRecord = typeof body === 'object' && body !== null ? body as Record<string, unknown> : {};\n const pathRel = typeof bodyRecord.path === 'string' ? bodyRecord.path : '';\n const content = typeof bodyRecord.content === 'string' ? bodyRecord.content : '';\n if (!pathRel.trim()) {\n return c.json({ ok: false, error: { message: 'Missing path' } }, 400);\n }\n const resolved = await resolveProjectWorkspaceWritePath(service, c.req.param('id'), pathRel);\n if (resolved.ok === false) return c.json({ ok: false, error: { message: resolved.error } }, resolved.status as 400);\n if (resolved.existingStat && !resolved.existingStat.isFile()) {\n return c.json({ ok: false, error: { message: 'Not a file' } }, 400);\n }\n try {\n await writeFile(resolved.absolutePath, content, 'utf-8');\n const mtimeMs = (await stat(resolved.absolutePath).catch(() => ({ mtimeMs: Date.now() }))).mtimeMs;\n return c.json({\n ok: true,\n payload: { path: resolved.relativePath, mtimeMs },\n });\n } catch (err) {\n log.error({ err, projectId: resolved.projectId, path: resolved.absolutePath }, 'project file write failed');\n return c.json({ ok: false, error: { message: 'Write failed' } }, 500);\n }\n });\n\n authenticated.post('/api/projects/:id/sessions/:sessionKey', async (c) => {\n try {\n service.projects.attachSession(c.req.param('sessionKey'), c.req.param('id'));\n const session = await service.sessions.getSession(c.req.param('sessionKey'));\n return c.json({ ok: true, session });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.delete('/api/projects/:id/sessions/:sessionKey', async (c) => {\n try {\n const projectId = c.req.param('id');\n const sessionKey = c.req.param('sessionKey');\n if (!service.projects.get(projectId)) {\n return c.json({ ok: false, error: 'Project not found' }, 404);\n }\n const session = await service.sessions.getSession(sessionKey);\n if (!session) {\n return c.json({ ok: false, error: 'Session not found' }, 404);\n }\n if (session.projectId !== projectId) {\n return c.json({ ok: false, error: 'Session is not attached to this project' }, 409);\n }\n service.projects.detachSession(sessionKey);\n return c.json({ ok: true });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.post('/api/projects/:id/sessions/:sessionKey/summary-memory', async (c) => {\n const projectId = c.req.param('id');\n const sessionKey = c.req.param('sessionKey');\n const project = service.projects.get(projectId);\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n const session = getSessionMetadata(sessionKey);\n if (!session) return c.json({ ok: false, error: 'Session not found' }, 404);\n if (session.projectId !== projectId) {\n return c.json({ ok: false, error: 'Session is not attached to this project' }, 409);\n }\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const content = buildSessionSummaryMemoryContent(\n sessionKey,\n typeof body.summary === 'string' ? body.summary : undefined,\n );\n const record = upsertMemoryRecord({\n providerId: 'local',\n kind: 'session_summary',\n agentId: session.routing?.agentId ?? 'main',\n workspaceId: session.cwd,\n sessionKey,\n projectId,\n content,\n source: {\n provider: 'project-summary',\n sessionEntryId: sessionKey,\n },\n confidence: typeof body.confidence === 'number' ? body.confidence : 0.7,\n tags: ['project', 'session-summary', project.slug],\n status: 'active',\n sensitivity: 'normal',\n evidence: [{ sessionKey }],\n });\n return c.json({ ok: true, record }, 201);\n });\n\n authenticated.post('/api/projects/:id/goals/:goalId', async (c) => {\n try {\n service.projects.attachGoal(c.req.param('goalId'), c.req.param('id'));\n return c.json({ ok: true, goal: goals.get(c.req.param('goalId')) });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n\n authenticated.delete('/api/projects/:id/goals/:goalId', async (c) => {\n try {\n const projectId = c.req.param('id');\n const goalId = c.req.param('goalId');\n if (!service.projects.get(projectId)) {\n return c.json({ ok: false, error: 'Project not found' }, 404);\n }\n const goal = goals.get(goalId);\n if (!goal) {\n return c.json({ ok: false, error: 'Goal not found' }, 404);\n }\n if (goal.projectId !== projectId) {\n return c.json({ ok: false, error: 'Goal is not attached to this project' }, 409);\n }\n service.projects.detachGoal(goalId);\n return c.json({ ok: true });\n } catch (error) {\n return c.json({ ok: false, error: error instanceof Error ? error.message : String(error) }, 404);\n }\n });\n}\n"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { loadConfig } from "../config/loader.js";
2
- import "../config/index.js";
3
2
  import { isRestartEnabled } from "../config/commands.flags.js";
3
+ import "../config/index.js";
4
4
  import { runBootstrapMigrationsSync } from "../migrations/runner.js";
5
5
  import { restartGatewayProcessWithFreshPid } from "./respawn.js";
6
6
  import { acquireGatewayLock } from "./lock.js";
@@ -44,6 +44,7 @@ async function* runGatewayAgent(deps, message, channel, chatId, attachments, thi
44
44
  sessionKey: streamSessionKey,
45
45
  channel
46
46
  });
47
+ let registeredActiveWebchatRun = false;
47
48
  const publishStreamEvent = (event) => channel === "webchat" ? runRelay.publish(runId, event) ?? event : event;
48
49
  const emitAndYield = function* (events) {
49
50
  for (const event of events) {
@@ -79,7 +80,10 @@ async function* runGatewayAgent(deps, message, channel, chatId, attachments, thi
79
80
  if (!runAbort) throw new Error("run abort controller missing for webchat");
80
81
  const mergedSignal = runOptions?.signal ? AbortSignal.any([runOptions.signal, runAbort.signal]) : runAbort.signal;
81
82
  agentService.beginInboundTurn(sessionKey);
82
- activeWebchatRunBySession.set(sessionKey, runId);
83
+ if (!activeWebchatRunBySession.has(sessionKey)) {
84
+ activeWebchatRunBySession.set(sessionKey, runId);
85
+ registeredActiveWebchatRun = true;
86
+ }
83
87
  let streamError;
84
88
  try {
85
89
  const eventStream = agentService.turnDispatcher.processDirectStreaming(stampedMessage, sessionKey, prepared, thinking, {
@@ -122,7 +126,7 @@ async function* runGatewayAgent(deps, message, channel, chatId, attachments, thi
122
126
  summary: streamError
123
127
  };
124
128
  } finally {
125
- activeWebchatRunBySession.delete(sessionKey);
129
+ if (registeredActiveWebchatRun && activeWebchatRunBySession.get(sessionKey) === runId) activeWebchatRunBySession.delete(sessionKey);
126
130
  runAbortControllers.delete(runId);
127
131
  const assistantPlainText = agentService.getLastAssistantPlainText(sessionKey);
128
132
  const streamOutcome = agentService.persistentGoals.takeStreamOutcome(sessionKey);
@@ -1 +1 @@
1
- {"version":3,"file":"run-gateway-agent.js","names":[],"sources":["../../../../src/gateway/service/run-gateway-agent.ts"],"sourcesContent":["import crypto from 'crypto';\n\nimport type { AgentService } from '../../agent/service.js';\nimport type { Config } from '../../config/schema.js';\nimport type { MessageBus } from '../../infra/bus/index.js';\nimport { prependEnvelopeTimestamp } from '../../channels/envelope-timestamp.js';\nimport { resolveWebchatSessionKey } from '../resolve-webchat-session-key.js';\nimport type { SessionIndex } from '../../session/index.js';\nimport {\n createLogger,\n inboundCorrelationMetadataFromAsyncLogContext,\n updateAsyncLogContext,\n} from '../../utils/logger.js';\nimport { shouldSkipWebchatInboundByAbortCutoff } from '../../session/abort-cutoff.js';\n\nimport { formatAgentRunErrorForClient } from '../../agent/client-error-format.js';\n\nimport { ChatStreamMapper } from '../chat-stream/mapper.js';\nimport type { ChatStreamEvent } from '../chat-stream/protocol.js';\nimport type { AgentRunRelay } from '../agent-run-relay.js';\nimport { MAX_CHAT_ATTACHMENTS } from '../chat-limits.js';\nimport type { UserTurnAttachment } from '../user-turn-input.js';\nconst log = createLogger('Gateway:Service');\n\nexport type RunGatewayAgentYield = ChatStreamEvent;\n\nexport type RunGatewayAgentDeps = {\n config: Config;\n agentService: AgentService;\n bus: MessageBus;\n runRelay: AgentRunRelay;\n runAbortControllers: Map<string, AbortController>;\n activeWebchatRunBySession: Map<string, string>;\n sessionIndex: SessionIndex;\n emit: (type: string, payload: unknown) => void;\n};\n\n/**\n * @param runOptions.signal — When set (e.g. client disconnect), aborts in-flight generation and persists partial output.\n */\nexport async function *runGatewayAgent(\n deps: RunGatewayAgentDeps,\n message: string,\n channel: string,\n chatId: string,\n attachments?: UserTurnAttachment[],\n thinking?: string,\n runOptions?: { signal?: AbortSignal; clientCreatedAtMs?: number },\n): AsyncGenerator<RunGatewayAgentYield, { status: string; summary: string }, unknown> {\n const cappedAttachments =\n attachments && attachments.length > MAX_CHAT_ATTACHMENTS\n ? attachments.slice(0, MAX_CHAT_ATTACHMENTS)\n : attachments;\n if (attachments && cappedAttachments && attachments.length > cappedAttachments.length) {\n log.debug(\n { dropped: attachments.length - cappedAttachments.length, max: MAX_CHAT_ATTACHMENTS },\n 'Attachments capped for webchat',\n );\n }\n\n const runId = crypto.randomUUID();\n const {\n agentService,\n bus,\n runRelay,\n runAbortControllers,\n activeWebchatRunBySession,\n sessionIndex: sessionIndexFromDeps,\n emit,\n } = deps;\n const sessionIndex = sessionIndexFromDeps;\n\n let webchatSessionKey: string | undefined;\n let webchatSessionId: string | undefined;\n let webchatStaleSkip = false;\n if (channel === 'webchat') {\n const resolved = resolveWebchatSessionKey({ sessionKey: chatId });\n if (resolved.ok === false) {\n throw new Error(resolved.error);\n }\n webchatSessionKey = resolved.sessionKey;\n const meta = await sessionIndex.getSessionMetadata(webchatSessionKey);\n if (!meta) {\n throw new Error('Session not found; create sessions via POST /api/sessions');\n }\n webchatSessionId = meta?.sessionId;\n webchatStaleSkip = shouldSkipWebchatInboundByAbortCutoff(meta, runOptions?.clientCreatedAtMs);\n if (!webchatStaleSkip && meta?.abortCutoffTimestamp !== undefined) {\n await sessionIndex\n .updateSessionMetadata(webchatSessionKey, { abortCutoffTimestamp: undefined })\n .catch(() => {});\n }\n runRelay.ensureRun(runId, webchatSessionKey);\n runAbortControllers.set(runId, new AbortController());\n }\n\n const streamSessionKey = webchatSessionKey ?? chatId;\n const mapper = new ChatStreamMapper({ runId, sessionKey: streamSessionKey, channel });\n const publishStreamEvent = (event: ChatStreamEvent): ChatStreamEvent =>\n channel === 'webchat'\n ? ((runRelay.publish(runId, event as unknown as import('../agent-run-relay.js').RelayEvent) as unknown as ChatStreamEvent | undefined) ?? event)\n : event;\n const emitAndYield = function *(events: ChatStreamEvent[]): Generator<ChatStreamEvent> {\n for (const event of events) {\n const relayedEvent = publishStreamEvent(event);\n if (channel === 'webchat') emit('agent.stream', { sessionKey: streamSessionKey, event: relayedEvent });\n yield relayedEvent;\n }\n };\n\n yield* emitAndYield(mapper.start());\n\n try {\n if (channel === 'webchat' && webchatSessionKey) {\n if (webchatStaleSkip) {\n yield* emitAndYield(mapper.end('cancelled', 'Stale inbound after abort (clientCreatedAtMs before cutoff)'));\n runRelay.complete(runId);\n runAbortControllers.delete(runId);\n return {\n status: 'skipped',\n summary: 'Stale inbound after abort (clientCreatedAtMs before cutoff)',\n };\n }\n\n const sessionKey = webchatSessionKey;\n updateAsyncLogContext({\n sessionKey,\n ...(webchatSessionId ? { sessionId: webchatSessionId } : {}),\n });\n\n const timezone = agentService.resolveUserTimezoneForSession(sessionKey);\n const stampedMessage = message.trimStart().startsWith('/')\n ? message\n : prependEnvelopeTimestamp(message, timezone);\n const prepared = await agentService.prepareInboundAttachments(sessionKey, cappedAttachments);\n\n const runAbort = runAbortControllers.get(runId);\n if (!runAbort) {\n throw new Error('run abort controller missing for webchat');\n }\n const mergedSignal = runOptions?.signal\n ? AbortSignal.any([runOptions.signal, runAbort.signal])\n : runAbort.signal;\n\n agentService.beginInboundTurn(sessionKey);\n activeWebchatRunBySession.set(sessionKey, runId);\n let streamError: string | undefined;\n try {\n const eventStream = agentService.turnDispatcher.processDirectStreaming(\n stampedMessage,\n sessionKey,\n prepared,\n thinking,\n { signal: mergedSignal, runId },\n );\n\n for await (const event of eventStream) {\n yield* emitAndYield(mapper.map(event));\n }\n\n const endStatus = mergedSignal.aborted ? 'cancelled' : 'success';\n const endSummary = mergedSignal.aborted ? 'Interrupted' : 'Message processed successfully';\n yield* emitAndYield(mapper.end(endStatus, endSummary));\n runRelay.complete(runId);\n try {\n const metaAfter = await sessionIndex.getSessionMetadata(sessionKey);\n if (metaAfter?.name) {\n emit('session.updated', { key: sessionKey, name: metaAfter.name });\n }\n } catch {\n /* ignore */\n }\n return {\n status: mergedSignal.aborted ? 'aborted' : 'ok',\n summary: mergedSignal.aborted ? 'Interrupted' : 'Message processed successfully',\n };\n } catch (error) {\n const em = error instanceof Error ? error.message : String(error);\n log.error(\n {\n err: error,\n errorMessage: em,\n phase: 'gateway.agent_run',\n sessionKey,\n runId,\n channel: 'webchat',\n },\n `Agent processing failed: ${em}`,\n );\n streamError = em;\n const errorContent = formatAgentRunErrorForClient(streamError);\n yield* emitAndYield(mapper.error(errorContent));\n yield* emitAndYield(mapper.end('error', streamError));\n runRelay.complete(runId);\n return { status: 'error', summary: streamError };\n } finally {\n activeWebchatRunBySession.delete(sessionKey);\n runAbortControllers.delete(runId);\n const assistantPlainText = agentService.getLastAssistantPlainText(sessionKey);\n const streamOutcome = agentService.persistentGoals.takeStreamOutcome(sessionKey);\n try {\n await agentService.outboundCoordinator.emitSessionTurnComplete({\n sessionKey,\n channel: 'webchat',\n chatId: sessionKey,\n inboundUserText: message,\n assistantPlainText,\n aborted: mergedSignal.aborted,\n ...(streamError !== undefined ? { streamError } : {}),\n skipPersistentGoalPostTurn: streamOutcome?.skipPersistentGoalPostTurn ?? false,\n outboundMetadata: {},\n });\n } catch (goalErr) {\n log.warn(\n { err: goalErr, sessionKey },\n `Session turn complete failed: ${goalErr instanceof Error ? goalErr.message : String(goalErr)}`,\n );\n }\n agentService.endInboundTurn(sessionKey);\n }\n }\n\n const correlationMeta = inboundCorrelationMetadataFromAsyncLogContext();\n await bus.publishInbound({\n channel,\n sender_id: 'gateway',\n chat_id: chatId,\n content: message,\n ...(correlationMeta ? { metadata: correlationMeta } : {}),\n });\n\n const messageId = `msg_${runId.replace(/[^a-zA-Z0-9_-]/g, '_')}_1`;\n yield* emitAndYield([\n {\n type: 'assistant_message_start',\n runId,\n sessionKey: streamSessionKey,\n timestamp: Date.now(),\n payload: { messageId },\n },\n {\n type: 'assistant_delta',\n runId,\n sessionKey: streamSessionKey,\n timestamp: Date.now(),\n payload: { messageId, delta: 'Processing...\\n' },\n },\n ]);\n await new Promise((resolve) => setTimeout(resolve, 1000));\n yield* emitAndYield([\n {\n type: 'assistant_delta',\n runId,\n sessionKey: streamSessionKey,\n timestamp: Date.now(),\n payload: { messageId, delta: 'Done\\n' },\n },\n {\n type: 'assistant_message_end',\n runId,\n sessionKey: streamSessionKey,\n timestamp: Date.now(),\n payload: { messageId },\n },\n ]);\n yield* emitAndYield(mapper.end('success', 'Message processed'));\n return { status: 'ok', summary: 'Message processed' };\n } catch (error) {\n const em = error instanceof Error ? error.message : String(error);\n log.error(\n {\n err: error,\n errorMessage: em,\n phase: 'gateway.agent_run',\n runId,\n channel,\n chatId,\n },\n `Agent run failed: ${em}`,\n );\n throw error;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"run-gateway-agent.js","names":[],"sources":["../../../../src/gateway/service/run-gateway-agent.ts"],"sourcesContent":["import crypto from 'crypto';\n\nimport type { AgentService } from '../../agent/service.js';\nimport type { Config } from '../../config/schema.js';\nimport type { MessageBus } from '../../infra/bus/index.js';\nimport { prependEnvelopeTimestamp } from '../../channels/envelope-timestamp.js';\nimport { resolveWebchatSessionKey } from '../resolve-webchat-session-key.js';\nimport type { SessionIndex } from '../../session/index.js';\nimport {\n createLogger,\n inboundCorrelationMetadataFromAsyncLogContext,\n updateAsyncLogContext,\n} from '../../utils/logger.js';\nimport { shouldSkipWebchatInboundByAbortCutoff } from '../../session/abort-cutoff.js';\n\nimport { formatAgentRunErrorForClient } from '../../agent/client-error-format.js';\n\nimport { ChatStreamMapper } from '../chat-stream/mapper.js';\nimport type { ChatStreamEvent } from '../chat-stream/protocol.js';\nimport type { AgentRunRelay } from '../agent-run-relay.js';\nimport { MAX_CHAT_ATTACHMENTS } from '../chat-limits.js';\nimport type { UserTurnAttachment } from '../user-turn-input.js';\nconst log = createLogger('Gateway:Service');\n\nexport type RunGatewayAgentYield = ChatStreamEvent;\n\nexport type RunGatewayAgentDeps = {\n config: Config;\n agentService: AgentService;\n bus: MessageBus;\n runRelay: AgentRunRelay;\n runAbortControllers: Map<string, AbortController>;\n activeWebchatRunBySession: Map<string, string>;\n sessionIndex: SessionIndex;\n emit: (type: string, payload: unknown) => void;\n};\n\n/**\n * @param runOptions.signal — When set (e.g. client disconnect), aborts in-flight generation and persists partial output.\n */\nexport async function *runGatewayAgent(\n deps: RunGatewayAgentDeps,\n message: string,\n channel: string,\n chatId: string,\n attachments?: UserTurnAttachment[],\n thinking?: string,\n runOptions?: { signal?: AbortSignal; clientCreatedAtMs?: number },\n): AsyncGenerator<RunGatewayAgentYield, { status: string; summary: string }, unknown> {\n const cappedAttachments =\n attachments && attachments.length > MAX_CHAT_ATTACHMENTS\n ? attachments.slice(0, MAX_CHAT_ATTACHMENTS)\n : attachments;\n if (attachments && cappedAttachments && attachments.length > cappedAttachments.length) {\n log.debug(\n { dropped: attachments.length - cappedAttachments.length, max: MAX_CHAT_ATTACHMENTS },\n 'Attachments capped for webchat',\n );\n }\n\n const runId = crypto.randomUUID();\n const {\n agentService,\n bus,\n runRelay,\n runAbortControllers,\n activeWebchatRunBySession,\n sessionIndex: sessionIndexFromDeps,\n emit,\n } = deps;\n const sessionIndex = sessionIndexFromDeps;\n\n let webchatSessionKey: string | undefined;\n let webchatSessionId: string | undefined;\n let webchatStaleSkip = false;\n if (channel === 'webchat') {\n const resolved = resolveWebchatSessionKey({ sessionKey: chatId });\n if (resolved.ok === false) {\n throw new Error(resolved.error);\n }\n webchatSessionKey = resolved.sessionKey;\n const meta = await sessionIndex.getSessionMetadata(webchatSessionKey);\n if (!meta) {\n throw new Error('Session not found; create sessions via POST /api/sessions');\n }\n webchatSessionId = meta?.sessionId;\n webchatStaleSkip = shouldSkipWebchatInboundByAbortCutoff(meta, runOptions?.clientCreatedAtMs);\n if (!webchatStaleSkip && meta?.abortCutoffTimestamp !== undefined) {\n await sessionIndex\n .updateSessionMetadata(webchatSessionKey, { abortCutoffTimestamp: undefined })\n .catch(() => {});\n }\n runRelay.ensureRun(runId, webchatSessionKey);\n runAbortControllers.set(runId, new AbortController());\n }\n\n const streamSessionKey = webchatSessionKey ?? chatId;\n const mapper = new ChatStreamMapper({ runId, sessionKey: streamSessionKey, channel });\n let registeredActiveWebchatRun = false;\n const publishStreamEvent = (event: ChatStreamEvent): ChatStreamEvent =>\n channel === 'webchat'\n ? ((runRelay.publish(runId, event as unknown as import('../agent-run-relay.js').RelayEvent) as unknown as ChatStreamEvent | undefined) ?? event)\n : event;\n const emitAndYield = function *(events: ChatStreamEvent[]): Generator<ChatStreamEvent> {\n for (const event of events) {\n const relayedEvent = publishStreamEvent(event);\n if (channel === 'webchat') emit('agent.stream', { sessionKey: streamSessionKey, event: relayedEvent });\n yield relayedEvent;\n }\n };\n\n yield* emitAndYield(mapper.start());\n\n try {\n if (channel === 'webchat' && webchatSessionKey) {\n if (webchatStaleSkip) {\n yield* emitAndYield(mapper.end('cancelled', 'Stale inbound after abort (clientCreatedAtMs before cutoff)'));\n runRelay.complete(runId);\n runAbortControllers.delete(runId);\n return {\n status: 'skipped',\n summary: 'Stale inbound after abort (clientCreatedAtMs before cutoff)',\n };\n }\n\n const sessionKey = webchatSessionKey;\n updateAsyncLogContext({\n sessionKey,\n ...(webchatSessionId ? { sessionId: webchatSessionId } : {}),\n });\n\n const timezone = agentService.resolveUserTimezoneForSession(sessionKey);\n const stampedMessage = message.trimStart().startsWith('/')\n ? message\n : prependEnvelopeTimestamp(message, timezone);\n const prepared = await agentService.prepareInboundAttachments(sessionKey, cappedAttachments);\n\n const runAbort = runAbortControllers.get(runId);\n if (!runAbort) {\n throw new Error('run abort controller missing for webchat');\n }\n const mergedSignal = runOptions?.signal\n ? AbortSignal.any([runOptions.signal, runAbort.signal])\n : runAbort.signal;\n\n agentService.beginInboundTurn(sessionKey);\n if (!activeWebchatRunBySession.has(sessionKey)) {\n activeWebchatRunBySession.set(sessionKey, runId);\n registeredActiveWebchatRun = true;\n }\n let streamError: string | undefined;\n try {\n const eventStream = agentService.turnDispatcher.processDirectStreaming(\n stampedMessage,\n sessionKey,\n prepared,\n thinking,\n { signal: mergedSignal, runId },\n );\n\n for await (const event of eventStream) {\n yield* emitAndYield(mapper.map(event));\n }\n\n const endStatus = mergedSignal.aborted ? 'cancelled' : 'success';\n const endSummary = mergedSignal.aborted ? 'Interrupted' : 'Message processed successfully';\n yield* emitAndYield(mapper.end(endStatus, endSummary));\n runRelay.complete(runId);\n try {\n const metaAfter = await sessionIndex.getSessionMetadata(sessionKey);\n if (metaAfter?.name) {\n emit('session.updated', { key: sessionKey, name: metaAfter.name });\n }\n } catch {\n /* ignore */\n }\n return {\n status: mergedSignal.aborted ? 'aborted' : 'ok',\n summary: mergedSignal.aborted ? 'Interrupted' : 'Message processed successfully',\n };\n } catch (error) {\n const em = error instanceof Error ? error.message : String(error);\n log.error(\n {\n err: error,\n errorMessage: em,\n phase: 'gateway.agent_run',\n sessionKey,\n runId,\n channel: 'webchat',\n },\n `Agent processing failed: ${em}`,\n );\n streamError = em;\n const errorContent = formatAgentRunErrorForClient(streamError);\n yield* emitAndYield(mapper.error(errorContent));\n yield* emitAndYield(mapper.end('error', streamError));\n runRelay.complete(runId);\n return { status: 'error', summary: streamError };\n } finally {\n if (registeredActiveWebchatRun && activeWebchatRunBySession.get(sessionKey) === runId) {\n activeWebchatRunBySession.delete(sessionKey);\n }\n runAbortControllers.delete(runId);\n const assistantPlainText = agentService.getLastAssistantPlainText(sessionKey);\n const streamOutcome = agentService.persistentGoals.takeStreamOutcome(sessionKey);\n try {\n await agentService.outboundCoordinator.emitSessionTurnComplete({\n sessionKey,\n channel: 'webchat',\n chatId: sessionKey,\n inboundUserText: message,\n assistantPlainText,\n aborted: mergedSignal.aborted,\n ...(streamError !== undefined ? { streamError } : {}),\n skipPersistentGoalPostTurn: streamOutcome?.skipPersistentGoalPostTurn ?? false,\n outboundMetadata: {},\n });\n } catch (goalErr) {\n log.warn(\n { err: goalErr, sessionKey },\n `Session turn complete failed: ${goalErr instanceof Error ? goalErr.message : String(goalErr)}`,\n );\n }\n agentService.endInboundTurn(sessionKey);\n }\n }\n\n const correlationMeta = inboundCorrelationMetadataFromAsyncLogContext();\n await bus.publishInbound({\n channel,\n sender_id: 'gateway',\n chat_id: chatId,\n content: message,\n ...(correlationMeta ? { metadata: correlationMeta } : {}),\n });\n\n const messageId = `msg_${runId.replace(/[^a-zA-Z0-9_-]/g, '_')}_1`;\n yield* emitAndYield([\n {\n type: 'assistant_message_start',\n runId,\n sessionKey: streamSessionKey,\n timestamp: Date.now(),\n payload: { messageId },\n },\n {\n type: 'assistant_delta',\n runId,\n sessionKey: streamSessionKey,\n timestamp: Date.now(),\n payload: { messageId, delta: 'Processing...\\n' },\n },\n ]);\n await new Promise((resolve) => setTimeout(resolve, 1000));\n yield* emitAndYield([\n {\n type: 'assistant_delta',\n runId,\n sessionKey: streamSessionKey,\n timestamp: Date.now(),\n payload: { messageId, delta: 'Done\\n' },\n },\n {\n type: 'assistant_message_end',\n runId,\n sessionKey: streamSessionKey,\n timestamp: Date.now(),\n payload: { messageId },\n },\n ]);\n yield* emitAndYield(mapper.end('success', 'Message processed'));\n return { status: 'ok', summary: 'Message processed' };\n } catch (error) {\n const em = error instanceof Error ? error.message : String(error);\n log.error(\n {\n err: error,\n errorMessage: em,\n phase: 'gateway.agent_run',\n runId,\n channel,\n chatId,\n },\n `Agent run failed: ${em}`,\n );\n throw error;\n }\n}\n"],"mappings":"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"}
@@ -1,9 +1,9 @@
1
1
  import { createLogger } from "../utils/logger/index.js";
2
2
  import { init_logger } from "../utils/logger.js";
3
3
  import { init_loader, loadConfig } from "../config/loader.js";
4
+ import { loadUndiciRuntimeDeps } from "../infra/undici-fetch.js";
4
5
  import { toConversation } from "./channel-shared.js";
5
6
  import { createGatewayHttpClientFromConfig, resolveGatewayHttpBaseUrl } from "./gateway-http-client.js";
6
- import { loadUndiciRuntimeDeps } from "../infra/undici-fetch.js";
7
7
  //#region src/mcp/channel-bridge.ts
8
8
  init_loader();
9
9
  init_logger();