@xopcai/xopc 0.0.122 → 0.0.124
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -11
- package/README.zh-CN.md +28 -11
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-CK3s5cJo.js → agent-avatar-dicebear-B5uSVAyJ.js} +1 -1
- package/dist/gateway/static/root/assets/agents-BjIxt67Z.js +2 -0
- package/dist/gateway/static/root/assets/{app-management-settings-panel-CWsNHtTs.js → app-management-settings-panel-CYCONLIL.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-C4b8y6iZ.js → appearance-settings-Clw3ryKg.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-QICTeGjX.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-DAtNW3Ia.js → archive-plugin-CXUGRp2i.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-Dm-RY54y.js → attachment-load-Cmiub3Wg.js} +1 -1
- package/dist/gateway/static/root/assets/{automation-suggestion-card-BKHewSVT.js → automation-suggestion-card-CU0-4nQ-.js} +1 -1
- package/dist/gateway/static/root/assets/automations-page-Car-jtiz.js +1 -0
- package/dist/gateway/static/root/assets/{binary-plugins-BG6Xnk71.js → binary-plugins-0Izz-N3p.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-DfndiO3h.js → block-editor-C1Kv0IkJ.js} +28 -28
- package/dist/gateway/static/root/assets/browser-settings-page-CMeBJzlS.js +8 -0
- package/dist/gateway/static/root/assets/{capability-presets-api-Cx93GLdw.js → capability-presets-api-BmQTM9Il.js} +1 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-DZEJEoCF.js +1 -0
- package/dist/gateway/static/root/assets/{channel-recipient-api-DdPTtEs8.js → channel-recipient-api-BeA2aVor.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-kkW-xFau.js +1 -0
- package/dist/gateway/static/root/assets/connectors-page-BvaQvO5F.js +2 -0
- package/dist/gateway/static/root/assets/{directory-picker-path-field-D835EHJd.js → directory-picker-path-field-2rjzUu57.js} +1 -1
- package/dist/gateway/static/root/assets/{dreaming-settings-CCa1F7Fg.js → dreaming-settings-DnHO686d.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-W2ITCPSA.js → extension-debug-page-BGLRuWVN.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-DrvUytvn.js → extension-page-D978ePp9.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-qM8aLT5u.js → extension-settings-page-B6Ih4Swx.js} +1 -1
- package/dist/gateway/static/root/assets/{fetch-ovkvM8KQ.js → fetch-BU5S0Sn7.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-BB3biuD0.js → gateway-config-api-BIPGwrl1.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-settings-CMEA3r5u.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry-CanQ8UcR.js → gateway-startup-retry-Cd0Zz30N.js} +1 -1
- package/dist/gateway/static/root/assets/{goal-create-dialog-CNqNdEkQ.js → goal-create-dialog-B-KHKeXN.js} +1 -1
- package/dist/gateway/static/root/assets/goal-detail-page-BxrSoWdj.js +1 -0
- package/dist/gateway/static/root/assets/{goals-config-api-BBOX6mUl.js → goals-config-api-B95KdGMj.js} +1 -1
- package/dist/gateway/static/root/assets/{goals-page-BP1kfvWv.js → goals-page-BTJzIl28.js} +2 -2
- package/dist/gateway/static/root/assets/{goals-settings-Bh3A7OZV.js → goals-settings-BJyEuLLm.js} +1 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-wkOjYNQT.js +1 -0
- package/dist/gateway/static/root/assets/index-BLaXr6Ev.css +1 -0
- package/dist/gateway/static/root/assets/index-c_9TVr_C.js +191 -0
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-B4TKJHla.js → keyboard-shortcuts-settings-BT8T4DyC.js} +1 -1
- package/dist/gateway/static/root/assets/logs-page-CrxBJUgI.js +2 -0
- package/dist/gateway/static/root/assets/{markdown-split-DcFtdLci.js → markdown-split-Dv66bO2b.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-B6SmeLVB.js → media-plugins-BhIQU5yS.js} +1 -1
- package/dist/gateway/static/root/assets/messages-O6TAtdFC.js +3 -0
- package/dist/gateway/static/root/assets/models-hub-panel-DOOpz6y1.js +2 -0
- package/dist/gateway/static/root/assets/notes-page-Br16pK9v.js +1 -0
- package/dist/gateway/static/root/assets/notes-workbench-PSJAi0ZC.js +2 -0
- package/dist/gateway/static/root/assets/{preview-open-alternatives-C29O19s7.js → preview-open-alternatives-DGzet1d7.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-CIGGgKuw.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-B2grhsBt.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-CXMORxBD.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-B4ad9GfB.js → save-bar-controls-Cqgb-jqa.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-DdYncfLR.js → schedule-field-DVZcI8Yt.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-BMTrDE-7.js → schema-form-Bj7sOxC8.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-Bi2wkBzU.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-B1L3G4IA.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-MwTW2eK4.js → settings-collapsible-section-BmXn-8N6.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-Dg6LBbcr.js → settings-form-section-BnqYMWHR.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-BfRSHJmO.js +1 -0
- package/dist/gateway/static/root/assets/{settings-page-layout-BX4T-OLF.js → settings-page-layout-CdWZU1hd.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-Ce1pcFtR.js → setup-status-panel-CWtPM7RK.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-DWE-dUFh.js → share-preview-page-IB1v8i86.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-ngbsBgij.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-BIe442Gv.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-BfchZRVa.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-Dd6Y35Cm.js → system-settings-panel-BxQ384RC.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-Cx6XV5A2.js → typed-models-lib-BkcpvFYO.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-D4sMbmy7.js → use-channel-catalog-Cd0FaEQ4.js} +1 -1
- package/dist/gateway/static/root/assets/{user-profile-settings-panel-Bx-hjMQc.js → user-profile-settings-panel-DQ7NnRSY.js} +1 -1
- package/dist/gateway/static/root/assets/{utils-D7b_vZnv.js → utils-YKhVf7Ka.js} +1 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-C5Ov8Uk_.js +1 -0
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel--TdohF5N.js → workflow-run-setup-panel-BYD9BtOq.js} +2 -2
- package/dist/gateway/static/root/assets/{workflow-start-dialog-B0lavx_o.js → workflow-start-dialog-BNJVCWoS.js} +1 -1
- package/dist/gateway/static/root/assets/workflows-page-BYF29ANm.js +18 -0
- package/dist/gateway/static/root/index.html +5 -5
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.d.ts +6 -1
- package/dist/src/agent/agent-manager.js +28 -12
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/context/workspace-templates/AGENTS.md +1 -1
- package/dist/src/agent/embedded/xopc-tools-bridge.js +11 -7
- package/dist/src/agent/embedded/xopc-tools-bridge.js.map +1 -1
- package/dist/src/agent/lifecycle/progress.js +3 -1
- package/dist/src/agent/lifecycle/progress.js.map +1 -1
- package/dist/src/agent/lifecycle/timeout-wrapper.d.ts +2 -2
- package/dist/src/agent/lifecycle/timeout-wrapper.js +4 -4
- package/dist/src/agent/lifecycle/timeout-wrapper.js.map +1 -1
- package/dist/src/agent/memory/summary-generator.d.ts +1 -1
- package/dist/src/agent/memory/summary-generator.js +1 -2
- package/dist/src/agent/memory/summary-generator.js.map +1 -1
- package/dist/src/agent/middleware/index.d.ts +1 -1
- package/dist/src/agent/middleware/self-verify.d.ts +44 -14
- package/dist/src/agent/middleware/self-verify.js +214 -44
- package/dist/src/agent/middleware/self-verify.js.map +1 -1
- package/dist/src/agent/orchestration/agent-event-handler.js +57 -15
- package/dist/src/agent/orchestration/agent-event-handler.js.map +1 -1
- package/dist/src/agent/prompt/sections/tooling.js +18 -13
- package/dist/src/agent/prompt/sections/tooling.js.map +1 -1
- package/dist/src/agent/prompt/system-reminder.js +2 -2
- package/dist/src/agent/prompt/system-reminder.js.map +1 -1
- package/dist/src/agent/sandbox/sanitize-env-vars.d.ts +2 -2
- package/dist/src/agent/sandbox/sanitize-env-vars.js +2 -2
- package/dist/src/agent/sandbox/sanitize-env-vars.js.map +1 -1
- package/dist/src/agent/sandbox/types.d.ts +2 -2
- package/dist/src/agent/sandbox/types.js.map +1 -1
- package/dist/src/agent/service/btw-query.js +1 -1
- package/dist/src/agent/service/btw-query.js.map +1 -1
- package/dist/src/agent/service/process-direct-one-shot.js +6 -2
- package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
- package/dist/src/agent/service/process-direct-streaming.js +12 -7
- package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
- package/dist/src/agent/service.js +2 -1
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/skills/skill-tool-gating.js +1 -1
- package/dist/src/agent/skills/skill-tool-gating.js.map +1 -1
- package/dist/src/agent/starter-agents.js +9 -9
- package/dist/src/agent/starter-agents.js.map +1 -1
- package/dist/src/agent/tools/apply-patch.d.ts +25 -0
- package/dist/src/agent/tools/apply-patch.js +256 -0
- package/dist/src/agent/tools/apply-patch.js.map +1 -0
- package/dist/src/agent/tools/delegate-tool.d.ts +1 -1
- package/dist/src/agent/tools/delegate-tool.js +3 -3
- package/dist/src/agent/tools/delegate-tool.js.map +1 -1
- package/dist/src/agent/tools/exec-command.d.ts +30 -0
- package/dist/src/agent/tools/exec-command.js +224 -0
- package/dist/src/agent/tools/exec-command.js.map +1 -0
- package/dist/src/agent/tools/execute-code-tool.js +7 -4
- package/dist/src/agent/tools/execute-code-tool.js.map +1 -1
- package/dist/src/agent/tools/factory.d.ts +3 -3
- package/dist/src/agent/tools/factory.js +8 -9
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/goal-tool.d.ts +5 -1
- package/dist/src/agent/tools/goal-tool.js +8 -2
- package/dist/src/agent/tools/goal-tool.js.map +1 -1
- package/dist/src/agent/tools/index.d.ts +4 -3
- package/dist/src/agent/tools/index.js +5 -4
- package/dist/src/agent/tools/skills-tools.d.ts +1 -1
- package/dist/src/agent/tools/skills-tools.js.map +1 -1
- package/dist/src/agent/tools/update-plan-tool.d.ts +11 -0
- package/dist/src/agent/tools/update-plan-tool.js +72 -0
- package/dist/src/agent/tools/update-plan-tool.js.map +1 -0
- package/dist/src/agent/workflow/builtins/debug-incident.d.ts +1 -1
- package/dist/src/agent/workflow/builtins/debug-incident.js +1 -1
- package/dist/src/agent/workflow/builtins/debug-incident.js.map +1 -1
- package/dist/src/agent/workflow/builtins/pr-review.d.ts +1 -1
- package/dist/src/agent/workflow/builtins/pr-review.js +1 -1
- package/dist/src/agent/workflow/builtins/pr-review.js.map +1 -1
- package/dist/src/agent/workflow/builtins/release-check.d.ts +1 -1
- package/dist/src/agent/workflow/builtins/release-check.js +1 -1
- package/dist/src/agent/workflow/builtins/release-check.js.map +1 -1
- package/dist/src/agent/workflow/step-labels.js +7 -3
- package/dist/src/agent/workflow/step-labels.js.map +1 -1
- package/dist/src/chat-commands/agent-edit.js +1 -1
- package/dist/src/chat-commands/agent-edit.js.map +1 -1
- package/dist/src/chat-commands/builtins/goal.js +4 -1
- package/dist/src/chat-commands/builtins/goal.js.map +1 -1
- package/dist/src/chat-commands/builtins/review.d.ts +1 -0
- package/dist/src/chat-commands/builtins/review.js +167 -0
- package/dist/src/chat-commands/builtins/review.js.map +1 -0
- package/dist/src/chat-commands/index.d.ts +1 -0
- package/dist/src/chat-commands/index.js +3 -1
- package/dist/src/chat-commands/index.js.map +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/gateway/lifecycle.js +1 -1
- package/dist/src/config/agent-profile.js +1 -1
- package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
- package/dist/src/gateway/agent-builtin-tools.js +3 -2
- package/dist/src/gateway/agent-builtin-tools.js.map +1 -1
- package/dist/src/gateway/agents-admin.js +1 -1
- package/dist/src/gateway/chat-stream/mapper.d.ts +6 -0
- package/dist/src/gateway/chat-stream/mapper.js +149 -6
- package/dist/src/gateway/chat-stream/mapper.js.map +1 -1
- package/dist/src/gateway/chat-stream/protocol.d.ts +51 -1
- package/dist/src/gateway/hono/routes/commands-skills.js +21 -0
- package/dist/src/gateway/hono/routes/commands-skills.js.map +1 -1
- package/dist/src/gateway/hono/routes/index.js +2 -0
- package/dist/src/gateway/hono/routes/index.js.map +1 -1
- package/dist/src/gateway/hono/routes/lazy-bundles.js +1 -0
- package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
- package/dist/src/gateway/hono/routes/projects.js +136 -14
- package/dist/src/gateway/hono/routes/projects.js.map +1 -1
- package/dist/src/gateway/hono/routes/search.d.ts +3 -0
- package/dist/src/gateway/hono/routes/search.js +47 -0
- package/dist/src/gateway/hono/routes/search.js.map +1 -0
- package/dist/src/gateway/security/dangerous-tools.js +1 -1
- package/dist/src/gateway/security/dangerous-tools.js.map +1 -1
- package/dist/src/infra/update-restart.js +1 -1
- package/dist/src/projects/index.d.ts +3 -0
- package/dist/src/projects/index.js +4 -1
- package/dist/src/projects/project-agent-suggestion.d.ts +14 -0
- package/dist/src/projects/project-agent-suggestion.js +19 -0
- package/dist/src/projects/project-agent-suggestion.js.map +1 -0
- package/dist/src/projects/project-kind.d.ts +13 -0
- package/dist/src/projects/project-kind.js +147 -0
- package/dist/src/projects/project-kind.js.map +1 -0
- package/dist/src/projects/project-service.d.ts +15 -0
- package/dist/src/projects/project-service.js +96 -3
- package/dist/src/projects/project-service.js.map +1 -1
- package/dist/src/projects/project-store.js +32 -8
- package/dist/src/projects/project-store.js.map +1 -1
- package/dist/src/projects/types.d.ts +4 -1
- package/dist/src/projects/workspace-project.d.ts +22 -0
- package/dist/src/projects/workspace-project.js +143 -0
- package/dist/src/projects/workspace-project.js.map +1 -0
- package/dist/src/review/review-git.d.ts +48 -0
- package/dist/src/review/review-git.js +333 -0
- package/dist/src/review/review-git.js.map +1 -0
- package/dist/src/review/review-types.d.ts +22 -0
- package/dist/src/review/review-types.js +29 -0
- package/dist/src/review/review-types.js.map +1 -0
- package/dist/src/session/session-context-for-llm.js +151 -0
- package/dist/src/session/session-context-for-llm.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/021_projects_fts.sql +21 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +3 -3
- package/dist/src/storage/sqlite/migrations/runner.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/tui/backends/embedded-backend.d.ts +8 -1
- package/dist/src/tui/backends/embedded-backend.js +60 -1
- package/dist/src/tui/backends/embedded-backend.js.map +1 -1
- package/dist/src/tui/backends/gateway-sse-backend.d.ts +9 -1
- package/dist/src/tui/backends/gateway-sse-backend.js +29 -0
- package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
- package/dist/src/tui/components/assistant-message.js +35 -0
- package/dist/src/tui/components/assistant-message.js.map +1 -1
- package/dist/src/tui/tui-agent-events.js +25 -0
- package/dist/src/tui/tui-agent-events.js.map +1 -1
- package/dist/src/tui/tui-backend.d.ts +20 -0
- package/dist/src/tui/tui-commands.d.ts +1 -0
- package/dist/src/tui/tui-commands.js +110 -4
- package/dist/src/tui/tui-commands.js.map +1 -1
- package/dist/src/tui/tui-picker-overlay.d.ts +2 -0
- package/dist/src/tui/tui-picker-overlay.js +153 -1
- package/dist/src/tui/tui-picker-overlay.js.map +1 -1
- package/dist/src/tui/tui.js +36 -2
- package/dist/src/tui/tui.js.map +1 -1
- package/dist/src/workflows/service/workflow-run-service.js +1 -1
- package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
- package/package.json +1 -1
- package/dist/gateway/static/root/assets/agents-SsQrj9B-.js +0 -2
- package/dist/gateway/static/root/assets/apps-page-CYb6fame.js +0 -1
- package/dist/gateway/static/root/assets/automations-page-DpOOq1nk.js +0 -1
- package/dist/gateway/static/root/assets/browser-settings-page-9nXxgh4u.js +0 -8
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-D528_YFy.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-Ck-3h5lI.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-DL-fAqE_.js +0 -2
- package/dist/gateway/static/root/assets/gateway-settings-mmmnIH27.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-Ceu5zrN6.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-YoYgKlfX.js +0 -1
- package/dist/gateway/static/root/assets/index-DdqSO9R2.js +0 -191
- package/dist/gateway/static/root/assets/index-jGB-2nI-.css +0 -1
- package/dist/gateway/static/root/assets/logs-page-BgVk5DvZ.js +0 -2
- package/dist/gateway/static/root/assets/messages-B5O4OIEo.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-panel-BU0x8PGP.js +0 -2
- package/dist/gateway/static/root/assets/notes-page-D6JYVP4I.js +0 -1
- package/dist/gateway/static/root/assets/notes-workbench-mqRJYnJS.js +0 -2
- package/dist/gateway/static/root/assets/project-detail-page-DOTgzoeh.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-DGUIb4y5.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-DVKKUj3u.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-BVbzUWxW.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-DrNNoSqE.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-CMDqgeMR.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-aKSraR8l.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-CS-FU_B-.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-BaF3u0LA.js +0 -2
- package/dist/gateway/static/root/assets/voice-api-key-field-CkhbRt1q.js +0 -1
- package/dist/gateway/static/root/assets/workflows-page-CZR05Bu_.js +0 -18
- package/dist/src/agent/tools/edit.d.ts +0 -14
- package/dist/src/agent/tools/edit.js +0 -132
- package/dist/src/agent/tools/edit.js.map +0 -1
- package/dist/src/agent/tools/shell.d.ts +0 -15
- package/dist/src/agent/tools/shell.js +0 -158
- package/dist/src/agent/tools/shell.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lazy-bundles.js","names":[],"sources":["../../../../../src/gateway/hono/routes/lazy-bundles.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport type { GatewayService } from '../../service.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nexport type AuthenticatedLazyRouteBundle = {\n id: string;\n match: (path: string) => boolean;\n load: () => Promise<{ register: (authenticated: Hono, deps: AuthenticatedRouteDeps) => void }>;\n};\n\nexport type AppLazyRouteBundle = {\n id: string;\n prefixes: readonly string[];\n match: (path: string) => boolean;\n load: () => Promise<{\n registerOnApp: (app: Hono, service: GatewayService) => void;\n }>;\n};\n\nfunction startsWithAny(path: string, prefixes: readonly string[]): boolean {\n return prefixes.some((prefix) => path === prefix || path.startsWith(`${prefix}/`));\n}\n\nexport const AUTHENTICATED_LAZY_ROUTE_BUNDLES: readonly AuthenticatedLazyRouteBundle[] = [\n {\n id: 'media',\n match: (path) => startsWithAny(path, ['/api/media']),\n load: async () => {\n const { registerMediaRoutes } = await import('./media.js');\n return { register: registerMediaRoutes };\n },\n },\n {\n id: 'workspace',\n match: (path) => startsWithAny(path, ['/api/workspace']),\n load: async () => {\n const { registerWorkspaceRoutes } = await import('./workspace.js');\n return { register: registerWorkspaceRoutes };\n },\n },\n {\n id: 'host-fs',\n match: (path) => startsWithAny(path, ['/api/host/fs']),\n load: async () => {\n const { registerHostFsRoutes } = await import('./host-fs.js');\n return { register: registerHostFsRoutes };\n },\n },\n {\n id: 'channels',\n match: (path) => startsWithAny(path, ['/api/channels']),\n load: async () => {\n const { registerChannelRoutes } = await import('./channels.js');\n return { register: registerChannelRoutes };\n },\n },\n {\n id: 'browser-install',\n match: (path) =>\n path === '/api/browser/playwright/install/stream' ||\n path === '/api/browser/cloakbrowser/install/stream',\n load: async () => {\n const { registerBrowserInstallRoutes } = await import('./browser-install.js');\n return { register: registerBrowserInstallRoutes };\n },\n },\n {\n id: 'browser',\n // `browser-install` above already matched the SSE install streams; this\n // catches the remaining /api/browser/* handlers (extension, cdp,\n // cloakbrowser doctor/launch/install, playwright doctor/install, cloud).\n match: (path) => startsWithAny(path, ['/api/browser']),\n load: async () => {\n const { registerBrowserRoutes } = await import('./browser.js');\n return { register: registerBrowserRoutes };\n },\n },\n {\n id: 'config',\n match: (path) =>\n startsWithAny(path, [\n '/api/config',\n '/api/heartbeat/trigger',\n // Secret reveal handlers live in config routes but use /api/gateway and\n // /api/tools paths; without these prefixes the extension-gateway bundle\n // matches first and returns 404 (no handler for multi-segment paths).\n '/api/gateway/reveal-auth-secret',\n '/api/tools/web/reveal-search-api-key',\n ]),\n load: async () => {\n const { registerConfigRoutes } = await import('./config.js');\n return { register: registerConfigRoutes };\n },\n },\n {\n id: 'doctor',\n match: (path) => startsWithAny(path, ['/api/doctor', '/api/migrations']),\n load: async () => {\n const { registerDoctorRoutes } = await import('./doctor.js');\n const { registerMigrationRoutes } = await import('./migrations.js');\n return {\n register: (authenticated, deps) => {\n registerDoctorRoutes(authenticated, deps);\n registerMigrationRoutes(authenticated, deps);\n },\n };\n },\n },\n {\n id: 'dreaming',\n match: (path) => startsWithAny(path, ['/api/dreaming']),\n load: async () => {\n const { registerDreamingRoutes } = await import('./dreaming.js');\n return { register: registerDreamingRoutes };\n },\n },\n {\n id: 'agents',\n match: (path) => startsWithAny(path, ['/api/agents', '/api/user-profile', '/api/voice/models']),\n load: async () => {\n const { registerAgentsRoutes } = await import('./agents.js');\n return { register: registerAgentsRoutes };\n },\n },\n {\n id: 'capability-presets',\n match: (path) => startsWithAny(path, ['/api/capability-presets', '/api/global-defaults']),\n load: async () => {\n const { registerCapabilityPresetsRoutes } = await import('./capability-presets.js');\n const { registerGlobalDefaultsRoutes } = await import('./global-defaults.js');\n return {\n register: (authenticated, deps) => {\n registerCapabilityPresetsRoutes(authenticated, deps);\n registerGlobalDefaultsRoutes(authenticated, deps);\n },\n };\n },\n },\n {\n id: 'auth-registry-extensions',\n match: (path) =>\n startsWithAny(path, [\n '/api/auth',\n '/api/registry',\n '/api/extensions',\n '/api/context',\n '/api/marketplace',\n ]),\n load: async () => {\n const { registerAuthRegistryExtensionsRoutes } = await import('./auth-registry-extensions.js');\n return { register: registerAuthRegistryExtensionsRoutes };\n },\n },\n {\n id: 'models',\n match: (path) =>\n startsWithAny(path, ['/api/models', '/api/models-json', '/api/providers', '/api/image']),\n load: async () => {\n const { registerModelsRoutes } = await import('./models.js');\n return { register: registerModelsRoutes };\n },\n },\n {\n id: 'ai-assist',\n match: (path) => startsWithAny(path, ['/api/ai']),\n load: async () => {\n const { registerAiAssistRoutes } = await import('./ai-assist.js');\n return { register: registerAiAssistRoutes };\n },\n },\n {\n id: 'commands-skills',\n match: (path) => startsWithAny(path, ['/api/commands', '/api/skills', '/api/chat/skills']),\n load: async () => {\n const { registerCommandsSkillsRoutes } = await import('./commands-skills.js');\n return { register: registerCommandsSkillsRoutes };\n },\n },\n {\n id: 'automations',\n match: (path) => startsWithAny(path, ['/api/automations', '/api/automation-runs']),\n load: async () => {\n const { registerAutomationRoutes } = await import('../../../automations/api/routes.js');\n return { register: registerAutomationRoutes };\n },\n },\n {\n id: 'goals',\n match: (path) => startsWithAny(path, ['/api/goals']),\n load: async () => {\n const { registerGoalsRoutes } = await import('./goals.js');\n return { register: registerGoalsRoutes };\n },\n },\n {\n id: 'notes',\n match: (path) => startsWithAny(path, ['/api/notes']),\n load: async () => {\n const { registerNotesRoutes } = await import('./notes.js');\n return { register: registerNotesRoutes };\n },\n },\n {\n id: 'home',\n match: (path) => startsWithAny(path, ['/api/home']),\n load: async () => {\n const { registerHomeRoutes } = await import('./home.js');\n return { register: registerHomeRoutes };\n },\n },\n {\n id: 'workflows',\n match: (path) => startsWithAny(path, ['/api/workflows']),\n load: async () => {\n const { registerWorkflowRoutes } = await import('./workflows.js');\n return { register: registerWorkflowRoutes };\n },\n },\n {\n id: 'logs',\n match: (path) => startsWithAny(path, ['/api/logs']),\n load: async () => {\n const { registerLogsRoutes } = await import('./logs.js');\n return { register: registerLogsRoutes };\n },\n },\n {\n id: 'shares',\n match: (path) => startsWithAny(path, ['/api/shares']),\n load: async () => {\n const { registerShareRoutes } = await import('./shares.js');\n return { register: registerShareRoutes };\n },\n },\n {\n id: 'site-shares',\n match: (path) => startsWithAny(path, ['/api/site-shares']),\n load: async () => {\n const { registerSiteShareRoutes } = await import('./site-shares.js');\n return { register: registerSiteShareRoutes };\n },\n },\n {\n id: 'tunnel',\n match: (path) => startsWithAny(path, ['/api/tunnel']),\n load: async () => {\n const { registerTunnelRoutes } = await import('./tunnel.js');\n return { register: registerTunnelRoutes };\n },\n },\n {\n id: 'exposure',\n match: (path) => startsWithAny(path, ['/api/exposure']),\n load: async () => {\n const { registerExposureRoutes } = await import('./exposure.js');\n return { register: registerExposureRoutes };\n },\n },\n {\n id: 'extension-gateway',\n match: (path) => startsWithAny(path, ['/api/gateway']),\n load: async () => {\n const { registerExtensionGatewayRoutes } = await import('./extension-gateway.js');\n return { register: registerExtensionGatewayRoutes };\n },\n },\n {\n id: 'update',\n match: (path) => startsWithAny(path, ['/api/update']),\n load: async () => {\n const { registerUpdateRoutes } = await import('./update.js');\n return { register: registerUpdateRoutes };\n },\n },\n {\n id: 'voice',\n match: (path) => startsWithAny(path, ['/api/voice']) && path !== '/api/voice/models',\n load: async () => {\n const { registerVoiceRoutes } = await import('./voice.js');\n return { register: registerVoiceRoutes };\n },\n },\n {\n id: 'connectors',\n match: (path) => startsWithAny(path, ['/api/connectors']),\n load: async () => {\n const { registerConnectorRoutes } = await import('./connectors.js');\n return { register: registerConnectorRoutes };\n },\n },\n {\n id: 'tui',\n match: (path) => startsWithAny(path, ['/api/tui']),\n load: async () => {\n const { registerTuiRoutes } = await import('./tui.js');\n return { register: registerTuiRoutes };\n },\n },\n {\n id: 'mcp',\n match: (path) => startsWithAny(path, ['/api/mcp']),\n load: async () => {\n const { registerMcpRoutes } = await import('./mcp.js');\n return { register: registerMcpRoutes };\n },\n },\n];\n\nexport const APP_LAZY_ROUTE_BUNDLES: readonly AppLazyRouteBundle[] = [\n {\n id: 'shares-public',\n prefixes: ['/s'],\n match: (path) => startsWithAny(path, ['/s']),\n load: async () => {\n const { registerSharePublicRoutes } = await import('./shares.js');\n return { registerOnApp: registerSharePublicRoutes };\n },\n },\n {\n id: 'tunnel-public',\n prefixes: [\n '/api/tunnel/pair/ping',\n '/api/tunnel/pair/validate-url',\n '/api/tunnel/exchange-token',\n ],\n match: (path) =>\n path === '/api/tunnel/exchange-token' ||\n path === '/api/tunnel/pair/ping' ||\n path === '/api/tunnel/pair/validate-url',\n load: async () => {\n const { registerTunnelPublicRoutes } = await import('./tunnel.js');\n return { registerOnApp: registerTunnelPublicRoutes };\n },\n },\n];\n\nexport function findAuthenticatedLazyRouteBundle(path: string): AuthenticatedLazyRouteBundle | undefined {\n return AUTHENTICATED_LAZY_ROUTE_BUNDLES.find((bundle) => bundle.match(path));\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"lazy-bundles.js","names":[],"sources":["../../../../../src/gateway/hono/routes/lazy-bundles.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport type { GatewayService } from '../../service.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\nexport type AuthenticatedLazyRouteBundle = {\n id: string;\n match: (path: string) => boolean;\n load: () => Promise<{ register: (authenticated: Hono, deps: AuthenticatedRouteDeps) => void }>;\n};\n\nexport type AppLazyRouteBundle = {\n id: string;\n prefixes: readonly string[];\n match: (path: string) => boolean;\n load: () => Promise<{\n registerOnApp: (app: Hono, service: GatewayService) => void;\n }>;\n};\n\nfunction startsWithAny(path: string, prefixes: readonly string[]): boolean {\n return prefixes.some((prefix) => path === prefix || path.startsWith(`${prefix}/`));\n}\n\nexport const AUTHENTICATED_LAZY_ROUTE_BUNDLES: readonly AuthenticatedLazyRouteBundle[] = [\n {\n id: 'media',\n match: (path) => startsWithAny(path, ['/api/media']),\n load: async () => {\n const { registerMediaRoutes } = await import('./media.js');\n return { register: registerMediaRoutes };\n },\n },\n {\n id: 'workspace',\n match: (path) => startsWithAny(path, ['/api/workspace']),\n load: async () => {\n const { registerWorkspaceRoutes } = await import('./workspace.js');\n return { register: registerWorkspaceRoutes };\n },\n },\n {\n id: 'host-fs',\n match: (path) => startsWithAny(path, ['/api/host/fs']),\n load: async () => {\n const { registerHostFsRoutes } = await import('./host-fs.js');\n return { register: registerHostFsRoutes };\n },\n },\n {\n id: 'channels',\n match: (path) => startsWithAny(path, ['/api/channels']),\n load: async () => {\n const { registerChannelRoutes } = await import('./channels.js');\n return { register: registerChannelRoutes };\n },\n },\n {\n id: 'browser-install',\n match: (path) =>\n path === '/api/browser/playwright/install/stream' ||\n path === '/api/browser/cloakbrowser/install/stream',\n load: async () => {\n const { registerBrowserInstallRoutes } = await import('./browser-install.js');\n return { register: registerBrowserInstallRoutes };\n },\n },\n {\n id: 'browser',\n // `browser-install` above already matched the SSE install streams; this\n // catches the remaining /api/browser/* handlers (extension, cdp,\n // cloakbrowser doctor/launch/install, playwright doctor/install, cloud).\n match: (path) => startsWithAny(path, ['/api/browser']),\n load: async () => {\n const { registerBrowserRoutes } = await import('./browser.js');\n return { register: registerBrowserRoutes };\n },\n },\n {\n id: 'config',\n match: (path) =>\n startsWithAny(path, [\n '/api/config',\n '/api/heartbeat/trigger',\n // Secret reveal handlers live in config routes but use /api/gateway and\n // /api/tools paths; without these prefixes the extension-gateway bundle\n // matches first and returns 404 (no handler for multi-segment paths).\n '/api/gateway/reveal-auth-secret',\n '/api/tools/web/reveal-search-api-key',\n ]),\n load: async () => {\n const { registerConfigRoutes } = await import('./config.js');\n return { register: registerConfigRoutes };\n },\n },\n {\n id: 'doctor',\n match: (path) => startsWithAny(path, ['/api/doctor', '/api/migrations']),\n load: async () => {\n const { registerDoctorRoutes } = await import('./doctor.js');\n const { registerMigrationRoutes } = await import('./migrations.js');\n return {\n register: (authenticated, deps) => {\n registerDoctorRoutes(authenticated, deps);\n registerMigrationRoutes(authenticated, deps);\n },\n };\n },\n },\n {\n id: 'dreaming',\n match: (path) => startsWithAny(path, ['/api/dreaming']),\n load: async () => {\n const { registerDreamingRoutes } = await import('./dreaming.js');\n return { register: registerDreamingRoutes };\n },\n },\n {\n id: 'agents',\n match: (path) => startsWithAny(path, ['/api/agents', '/api/user-profile', '/api/voice/models']),\n load: async () => {\n const { registerAgentsRoutes } = await import('./agents.js');\n return { register: registerAgentsRoutes };\n },\n },\n {\n id: 'capability-presets',\n match: (path) => startsWithAny(path, ['/api/capability-presets', '/api/global-defaults']),\n load: async () => {\n const { registerCapabilityPresetsRoutes } = await import('./capability-presets.js');\n const { registerGlobalDefaultsRoutes } = await import('./global-defaults.js');\n return {\n register: (authenticated, deps) => {\n registerCapabilityPresetsRoutes(authenticated, deps);\n registerGlobalDefaultsRoutes(authenticated, deps);\n },\n };\n },\n },\n {\n id: 'auth-registry-extensions',\n match: (path) =>\n startsWithAny(path, [\n '/api/auth',\n '/api/registry',\n '/api/extensions',\n '/api/context',\n '/api/marketplace',\n ]),\n load: async () => {\n const { registerAuthRegistryExtensionsRoutes } = await import('./auth-registry-extensions.js');\n return { register: registerAuthRegistryExtensionsRoutes };\n },\n },\n {\n id: 'models',\n match: (path) =>\n startsWithAny(path, ['/api/models', '/api/models-json', '/api/providers', '/api/image']),\n load: async () => {\n const { registerModelsRoutes } = await import('./models.js');\n return { register: registerModelsRoutes };\n },\n },\n {\n id: 'ai-assist',\n match: (path) => startsWithAny(path, ['/api/ai']),\n load: async () => {\n const { registerAiAssistRoutes } = await import('./ai-assist.js');\n return { register: registerAiAssistRoutes };\n },\n },\n {\n id: 'commands-skills',\n match: (path) => startsWithAny(path, ['/api/commands', '/api/review', '/api/skills', '/api/chat/skills']),\n load: async () => {\n const { registerCommandsSkillsRoutes } = await import('./commands-skills.js');\n return { register: registerCommandsSkillsRoutes };\n },\n },\n {\n id: 'automations',\n match: (path) => startsWithAny(path, ['/api/automations', '/api/automation-runs']),\n load: async () => {\n const { registerAutomationRoutes } = await import('../../../automations/api/routes.js');\n return { register: registerAutomationRoutes };\n },\n },\n {\n id: 'goals',\n match: (path) => startsWithAny(path, ['/api/goals']),\n load: async () => {\n const { registerGoalsRoutes } = await import('./goals.js');\n return { register: registerGoalsRoutes };\n },\n },\n {\n id: 'notes',\n match: (path) => startsWithAny(path, ['/api/notes']),\n load: async () => {\n const { registerNotesRoutes } = await import('./notes.js');\n return { register: registerNotesRoutes };\n },\n },\n {\n id: 'home',\n match: (path) => startsWithAny(path, ['/api/home']),\n load: async () => {\n const { registerHomeRoutes } = await import('./home.js');\n return { register: registerHomeRoutes };\n },\n },\n {\n id: 'workflows',\n match: (path) => startsWithAny(path, ['/api/workflows']),\n load: async () => {\n const { registerWorkflowRoutes } = await import('./workflows.js');\n return { register: registerWorkflowRoutes };\n },\n },\n {\n id: 'logs',\n match: (path) => startsWithAny(path, ['/api/logs']),\n load: async () => {\n const { registerLogsRoutes } = await import('./logs.js');\n return { register: registerLogsRoutes };\n },\n },\n {\n id: 'shares',\n match: (path) => startsWithAny(path, ['/api/shares']),\n load: async () => {\n const { registerShareRoutes } = await import('./shares.js');\n return { register: registerShareRoutes };\n },\n },\n {\n id: 'site-shares',\n match: (path) => startsWithAny(path, ['/api/site-shares']),\n load: async () => {\n const { registerSiteShareRoutes } = await import('./site-shares.js');\n return { register: registerSiteShareRoutes };\n },\n },\n {\n id: 'tunnel',\n match: (path) => startsWithAny(path, ['/api/tunnel']),\n load: async () => {\n const { registerTunnelRoutes } = await import('./tunnel.js');\n return { register: registerTunnelRoutes };\n },\n },\n {\n id: 'exposure',\n match: (path) => startsWithAny(path, ['/api/exposure']),\n load: async () => {\n const { registerExposureRoutes } = await import('./exposure.js');\n return { register: registerExposureRoutes };\n },\n },\n {\n id: 'extension-gateway',\n match: (path) => startsWithAny(path, ['/api/gateway']),\n load: async () => {\n const { registerExtensionGatewayRoutes } = await import('./extension-gateway.js');\n return { register: registerExtensionGatewayRoutes };\n },\n },\n {\n id: 'update',\n match: (path) => startsWithAny(path, ['/api/update']),\n load: async () => {\n const { registerUpdateRoutes } = await import('./update.js');\n return { register: registerUpdateRoutes };\n },\n },\n {\n id: 'voice',\n match: (path) => startsWithAny(path, ['/api/voice']) && path !== '/api/voice/models',\n load: async () => {\n const { registerVoiceRoutes } = await import('./voice.js');\n return { register: registerVoiceRoutes };\n },\n },\n {\n id: 'connectors',\n match: (path) => startsWithAny(path, ['/api/connectors']),\n load: async () => {\n const { registerConnectorRoutes } = await import('./connectors.js');\n return { register: registerConnectorRoutes };\n },\n },\n {\n id: 'tui',\n match: (path) => startsWithAny(path, ['/api/tui']),\n load: async () => {\n const { registerTuiRoutes } = await import('./tui.js');\n return { register: registerTuiRoutes };\n },\n },\n {\n id: 'mcp',\n match: (path) => startsWithAny(path, ['/api/mcp']),\n load: async () => {\n const { registerMcpRoutes } = await import('./mcp.js');\n return { register: registerMcpRoutes };\n },\n },\n];\n\nexport const APP_LAZY_ROUTE_BUNDLES: readonly AppLazyRouteBundle[] = [\n {\n id: 'shares-public',\n prefixes: ['/s'],\n match: (path) => startsWithAny(path, ['/s']),\n load: async () => {\n const { registerSharePublicRoutes } = await import('./shares.js');\n return { registerOnApp: registerSharePublicRoutes };\n },\n },\n {\n id: 'tunnel-public',\n prefixes: [\n '/api/tunnel/pair/ping',\n '/api/tunnel/pair/validate-url',\n '/api/tunnel/exchange-token',\n ],\n match: (path) =>\n path === '/api/tunnel/exchange-token' ||\n path === '/api/tunnel/pair/ping' ||\n path === '/api/tunnel/pair/validate-url',\n load: async () => {\n const { registerTunnelPublicRoutes } = await import('./tunnel.js');\n return { registerOnApp: registerTunnelPublicRoutes };\n },\n },\n];\n\nexport function findAuthenticatedLazyRouteBundle(path: string): AuthenticatedLazyRouteBundle | undefined {\n return AUTHENTICATED_LAZY_ROUTE_BUNDLES.find((bundle) => bundle.match(path));\n}\n"],"mappings":"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"}
|
|
@@ -5,7 +5,10 @@ import { getSessionMetadata } from "../../../storage/sqlite/session-repository.j
|
|
|
5
5
|
import { loadTranscriptRowsForSession } from "../../../storage/sqlite/transcript-repository.js";
|
|
6
6
|
import { listMemoryRecords, upsertMemoryRecord } from "../../../storage/sqlite/memory-records-repository.js";
|
|
7
7
|
import "../../../storage/sqlite/index.js";
|
|
8
|
+
import { ProjectWorkspaceConflictError, ProjectWorkspaceMissingError } from "../../../projects/workspace-project.js";
|
|
8
9
|
import { isValidProjectAgentId, normalizeProjectAgentId, resolveProjectAgentId } from "../../../projects/project-agent.js";
|
|
10
|
+
import { inferProjectKind } from "../../../projects/project-kind.js";
|
|
11
|
+
import { inferSuggestedProjectDefaultAgentId } from "../../../projects/project-agent-suggestion.js";
|
|
9
12
|
import { buildProjectLoopOverview } from "../../../projects/project-loop.js";
|
|
10
13
|
import "../../../projects/index.js";
|
|
11
14
|
import { createGatewayRouteLogger } from "../lib/route-logger.js";
|
|
@@ -101,27 +104,57 @@ function registerProjectsRoutes(authenticated, deps) {
|
|
|
101
104
|
authenticated.post("/api/projects", async (c) => {
|
|
102
105
|
const body = await c.req.json().catch(() => ({}));
|
|
103
106
|
const name = textField(body, "name")?.trim();
|
|
104
|
-
|
|
107
|
+
const workspaceRoot = textField(body, "workspaceRoot")?.trim();
|
|
108
|
+
if (!name && !workspaceRoot) return c.json({
|
|
105
109
|
ok: false,
|
|
106
110
|
error: "Missing name"
|
|
107
111
|
}, 400);
|
|
108
|
-
const
|
|
112
|
+
const hasDefaultAgentPatch = Object.hasOwn(body, "defaultAgentId");
|
|
113
|
+
const explicitDefaultAgentId = normalizeProjectAgentId(textField(body, "defaultAgentId"));
|
|
114
|
+
const defaultAgentId = hasDefaultAgentPatch ? explicitDefaultAgentId : inferSuggestedProjectDefaultAgentId({
|
|
115
|
+
config: service.currentConfig,
|
|
116
|
+
name,
|
|
117
|
+
description: textField(body, "description"),
|
|
118
|
+
workspaceRoot,
|
|
119
|
+
projectKind: textField(body, "projectKind")
|
|
120
|
+
});
|
|
109
121
|
if (!isValidProjectAgentId(service.currentConfig, defaultAgentId)) return c.json({
|
|
110
122
|
ok: false,
|
|
111
123
|
error: "Default agent not found"
|
|
112
124
|
}, 400);
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
+
try {
|
|
126
|
+
const project = service.projects.create({
|
|
127
|
+
name,
|
|
128
|
+
description: textField(body, "description"),
|
|
129
|
+
defaultAgentId,
|
|
130
|
+
workspaceRoot,
|
|
131
|
+
createWorkspaceRoot: body.createWorkspaceRoot === true,
|
|
132
|
+
projectKind: textField(body, "projectKind"),
|
|
133
|
+
brief: textField(body, "brief"),
|
|
134
|
+
instructions: textField(body, "instructions")
|
|
135
|
+
});
|
|
136
|
+
return c.json({
|
|
137
|
+
ok: true,
|
|
138
|
+
project
|
|
139
|
+
}, 201);
|
|
140
|
+
} catch (error) {
|
|
141
|
+
if (error instanceof ProjectWorkspaceConflictError) return c.json({
|
|
142
|
+
ok: false,
|
|
143
|
+
code: "workspace_already_bound",
|
|
144
|
+
error: error.message,
|
|
145
|
+
project: error.project
|
|
146
|
+
}, 409);
|
|
147
|
+
if (error instanceof ProjectWorkspaceMissingError) return c.json({
|
|
148
|
+
ok: false,
|
|
149
|
+
code: "workspace_root_missing",
|
|
150
|
+
error: error.message,
|
|
151
|
+
workspaceRoot: error.workspaceRoot
|
|
152
|
+
}, 409);
|
|
153
|
+
return c.json({
|
|
154
|
+
ok: false,
|
|
155
|
+
error: error instanceof Error ? error.message : String(error)
|
|
156
|
+
}, 400);
|
|
157
|
+
}
|
|
125
158
|
});
|
|
126
159
|
authenticated.get("/api/projects", async (c) => {
|
|
127
160
|
const status = parseProjectStatus(c.req.query("status"));
|
|
@@ -145,6 +178,82 @@ function registerProjectsRoutes(authenticated, deps) {
|
|
|
145
178
|
suggestions: sessionKey ? service.projects.suggestProjectsForSession(sessionKey) : []
|
|
146
179
|
});
|
|
147
180
|
});
|
|
181
|
+
authenticated.post("/api/projects/infer-defaults", async (c) => {
|
|
182
|
+
const body = await c.req.json().catch(() => ({}));
|
|
183
|
+
const input = {
|
|
184
|
+
name: textField(body, "name"),
|
|
185
|
+
description: textField(body, "description"),
|
|
186
|
+
workspaceRoot: textField(body, "workspaceRoot"),
|
|
187
|
+
projectKind: textField(body, "projectKind")
|
|
188
|
+
};
|
|
189
|
+
const inference = inferProjectKind(input);
|
|
190
|
+
const defaultAgentId = inferSuggestedProjectDefaultAgentId({
|
|
191
|
+
config: service.currentConfig,
|
|
192
|
+
...input
|
|
193
|
+
});
|
|
194
|
+
return c.json({
|
|
195
|
+
ok: true,
|
|
196
|
+
inference,
|
|
197
|
+
defaultAgentId
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
authenticated.post("/api/projects/resolve-workspace", async (c) => {
|
|
201
|
+
const body = await c.req.json().catch(() => ({}));
|
|
202
|
+
const workspacePath = textField(body, "workspacePath")?.trim();
|
|
203
|
+
if (!workspacePath) return c.json({
|
|
204
|
+
ok: false,
|
|
205
|
+
error: "Missing workspacePath"
|
|
206
|
+
}, 400);
|
|
207
|
+
const agentId = textField(body, "agentId")?.trim() || "main";
|
|
208
|
+
const suggestedDefaultAgentId = inferSuggestedProjectDefaultAgentId({
|
|
209
|
+
config: service.currentConfig,
|
|
210
|
+
workspaceRoot: workspacePath,
|
|
211
|
+
projectKind: textField(body, "projectKind")
|
|
212
|
+
});
|
|
213
|
+
let match;
|
|
214
|
+
try {
|
|
215
|
+
match = service.projects.resolveOrCreateForWorkspacePath({
|
|
216
|
+
workspacePath,
|
|
217
|
+
agentId,
|
|
218
|
+
defaultAgentId: suggestedDefaultAgentId,
|
|
219
|
+
autoCreate: body.autoCreate !== false
|
|
220
|
+
});
|
|
221
|
+
} catch (error) {
|
|
222
|
+
if (error instanceof ProjectWorkspaceConflictError) match = {
|
|
223
|
+
project: error.project,
|
|
224
|
+
reason: "exact",
|
|
225
|
+
created: false
|
|
226
|
+
};
|
|
227
|
+
else throw error;
|
|
228
|
+
}
|
|
229
|
+
if (!match) return c.json({
|
|
230
|
+
ok: true,
|
|
231
|
+
project: null
|
|
232
|
+
});
|
|
233
|
+
const sessionKey = textField(body, "sessionKey")?.trim();
|
|
234
|
+
const projectDefaultAgentId = normalizeProjectAgentId(match.project.defaultAgentId);
|
|
235
|
+
const shouldBindRequestedSession = !projectDefaultAgentId || projectDefaultAgentId === normalizeProjectAgentId(agentId);
|
|
236
|
+
if (sessionKey && shouldBindRequestedSession) {
|
|
237
|
+
if (!getSessionMetadata(sessionKey)) await service.sessionIndexInstance.saveMessages(sessionKey, [], { metadata: {
|
|
238
|
+
sourceChannel: "tui",
|
|
239
|
+
sourceChatId: `default:direct:${sessionKey}`,
|
|
240
|
+
sessionType: "chat",
|
|
241
|
+
projectId: match.project.id,
|
|
242
|
+
routing: {
|
|
243
|
+
agentId,
|
|
244
|
+
source: "tui",
|
|
245
|
+
accountId: "default",
|
|
246
|
+
peerKind: "direct",
|
|
247
|
+
peerId: sessionKey
|
|
248
|
+
}
|
|
249
|
+
} });
|
|
250
|
+
service.projects.attachSession(sessionKey, match.project.id);
|
|
251
|
+
}
|
|
252
|
+
return c.json({
|
|
253
|
+
ok: true,
|
|
254
|
+
...match
|
|
255
|
+
});
|
|
256
|
+
});
|
|
148
257
|
authenticated.get("/api/projects/:id/overview", async (c) => {
|
|
149
258
|
const project = service.projects.getWithDetails(c.req.param("id"));
|
|
150
259
|
if (!project) return c.json({
|
|
@@ -298,6 +407,7 @@ function registerProjectsRoutes(authenticated, deps) {
|
|
|
298
407
|
...status ? { status } : {},
|
|
299
408
|
...defaultAgentPatch !== void 0 ? { defaultAgentId: defaultAgentId ?? null } : {},
|
|
300
409
|
...optionalTextField(body, "workspaceRoot") !== void 0 ? { workspaceRoot: optionalTextField(body, "workspaceRoot") } : {},
|
|
410
|
+
createWorkspaceRoot: body.createWorkspaceRoot === true,
|
|
301
411
|
...optionalTextField(body, "brief") !== void 0 ? { brief: optionalTextField(body, "brief") } : {},
|
|
302
412
|
...optionalTextField(body, "instructions") !== void 0 ? { instructions: optionalTextField(body, "instructions") } : {}
|
|
303
413
|
});
|
|
@@ -306,6 +416,18 @@ function registerProjectsRoutes(authenticated, deps) {
|
|
|
306
416
|
project
|
|
307
417
|
});
|
|
308
418
|
} catch (error) {
|
|
419
|
+
if (error instanceof ProjectWorkspaceConflictError) return c.json({
|
|
420
|
+
ok: false,
|
|
421
|
+
code: "workspace_already_bound",
|
|
422
|
+
error: error.message,
|
|
423
|
+
project: error.project
|
|
424
|
+
}, 409);
|
|
425
|
+
if (error instanceof ProjectWorkspaceMissingError) return c.json({
|
|
426
|
+
ok: false,
|
|
427
|
+
code: "workspace_root_missing",
|
|
428
|
+
error: error.message,
|
|
429
|
+
workspaceRoot: error.workspaceRoot
|
|
430
|
+
}, 409);
|
|
309
431
|
return c.json({
|
|
310
432
|
ok: false,
|
|
311
433
|
error: error instanceof Error ? error.message : String(error)
|
|
@@ -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, realpath, stat } from 'node:fs/promises';\nimport * as path from 'node:path';\n\nimport type { GoalWithDetails } from '../../../goals/index.js';\nimport { GoalService } from '../../../goals/index.js';\nimport {\n buildProjectLoopOverview,\n isValidProjectAgentId,\n normalizeProjectAgentId,\n resolveProjectAgentId,\n type ProjectStatus,\n type ProjectWorkflowRunBrief,\n} from '../../../projects/index.js';\nimport {\n getSqliteDatabase,\n getSessionMetadata,\n listMemoryRecords,\n loadTranscriptRowsForSession,\n upsertMemoryRecord,\n} from '../../../storage/sqlite/index.js';\nimport { createGatewayRouteLogger } from '../lib/route-logger.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 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\nconst SKIP_FILE_NAMES = new Set(['.git', 'node_modules']);\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\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 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 goals = new GoalService();\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 if (!name) return c.json({ ok: false, error: 'Missing name' }, 400);\n const defaultAgentId = normalizeProjectAgentId(textField(body, 'defaultAgentId'));\n if (!isValidProjectAgentId(service.currentConfig, defaultAgentId)) {\n return c.json({ ok: false, error: 'Default agent not found' }, 400);\n }\n const project = service.projects.create({\n name,\n description: textField(body, 'description'),\n defaultAgentId,\n workspaceRoot: textField(body, 'workspaceRoot'),\n brief: textField(body, 'brief'),\n instructions: textField(body, 'instructions'),\n });\n return c.json({ ok: true, project }, 201);\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 });\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.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,\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.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 });\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 ...(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 });\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', 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({ ok: true, sessions: sessions.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/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 project = service.projects.get(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n if (!project.workspaceRoot?.trim()) {\n return c.json({ ok: false, error: 'Project workspace root is not set' }, 400);\n }\n\n let root: string;\n try {\n root = await realpath(project.workspaceRoot);\n const rootStat = await stat(root);\n if (!rootStat.isDirectory()) {\n return c.json({ ok: false, error: 'Project workspace root is not a directory' }, 400);\n }\n } catch (err) {\n log.warn({ err, projectId: project.id, path: project.workspaceRoot }, 'project workspace root unavailable');\n return c.json({ ok: false, error: 'Project workspace root is unavailable' }, 404);\n }\n\n const requestedPath = normalizeRelativePath(c.req.query('path'));\n const candidate = path.resolve(root, requestedPath);\n if (!isWithinDirectory(root, candidate)) {\n return c.json({ ok: false, error: 'Path is outside project workspace' }, 400);\n }\n\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: project.id, 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 absolutePath = path.join(currentPath, entry.name);\n const entryStat = await stat(absolutePath).catch(() => null);\n const relativePath = path.relative(root, absolutePath).split(path.sep).join('/');\n return {\n name: entry.name,\n path: relativePath,\n type: entry.isDirectory() ? 'directory' : 'file',\n size: entryStat?.isFile() ? entryStat.size : undefined,\n updatedAt: entryStat?.mtime.toISOString(),\n };\n }));\n entries.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,\n });\n } catch (err) {\n log.warn({ err, projectId: project.id, 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.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
|
+
{"version":3,"file":"projects.js","names":["path","record"],"sources":["../../../../../src/gateway/hono/routes/projects.ts"],"sourcesContent":["import type { Hono } from 'hono';\nimport { readdir, realpath, stat } from 'node:fs/promises';\nimport * as path from 'node:path';\n\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 resolveProjectAgentId,\n type ProjectStatus,\n type ProjectWorkflowRunBrief,\n} from '../../../projects/index.js';\nimport {\n getSqliteDatabase,\n getSessionMetadata,\n listMemoryRecords,\n loadTranscriptRowsForSession,\n upsertMemoryRecord,\n} from '../../../storage/sqlite/index.js';\nimport { createGatewayRouteLogger } from '../lib/route-logger.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 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\nconst SKIP_FILE_NAMES = new Set(['.git', 'node_modules']);\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\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 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 goals = new GoalService();\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 }, 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 });\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,\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.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 });\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 });\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({ ok: true, sessions: sessions.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/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 project = service.projects.get(c.req.param('id'));\n if (!project) return c.json({ ok: false, error: 'Project not found' }, 404);\n if (!project.workspaceRoot?.trim()) {\n return c.json({ ok: false, error: 'Project workspace root is not set' }, 400);\n }\n\n let root: string;\n try {\n root = await realpath(project.workspaceRoot);\n const rootStat = await stat(root);\n if (!rootStat.isDirectory()) {\n return c.json({ ok: false, error: 'Project workspace root is not a directory' }, 400);\n }\n } catch (err) {\n log.warn({ err, projectId: project.id, path: project.workspaceRoot }, 'project workspace root unavailable');\n return c.json({ ok: false, error: 'Project workspace root is unavailable' }, 404);\n }\n\n const requestedPath = normalizeRelativePath(c.req.query('path'));\n const candidate = path.resolve(root, requestedPath);\n if (!isWithinDirectory(root, candidate)) {\n return c.json({ ok: false, error: 'Path is outside project workspace' }, 400);\n }\n\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: project.id, 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 absolutePath = path.join(currentPath, entry.name);\n const entryStat = await stat(absolutePath).catch(() => null);\n const relativePath = path.relative(root, absolutePath).split(path.sep).join('/');\n return {\n name: entry.name,\n path: relativePath,\n type: entry.isDirectory() ? 'directory' : 'file',\n size: entryStat?.isFile() ? entryStat.size : undefined,\n updatedAt: entryStat?.mtime.toISOString(),\n };\n }));\n entries.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,\n });\n } catch (err) {\n log.warn({ err, projectId: project.id, 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.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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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
//#region src/gateway/hono/routes/search.ts
|
|
2
|
+
function parseLimit(value) {
|
|
3
|
+
const parsed = value ? Number.parseInt(value, 10) : 20;
|
|
4
|
+
return Math.min(50, Math.max(1, Number.isFinite(parsed) ? parsed : 20));
|
|
5
|
+
}
|
|
6
|
+
function parseTypes(value) {
|
|
7
|
+
if (!value?.trim()) return new Set(["project"]);
|
|
8
|
+
return new Set(value.split(",").map((type) => type.trim()).filter((type) => type === "project"));
|
|
9
|
+
}
|
|
10
|
+
function projectSubtitle(project) {
|
|
11
|
+
return project.description ?? project.workspaceRoot ?? project.brief ?? project.slug;
|
|
12
|
+
}
|
|
13
|
+
function registerSearchRoutes(authenticated, deps) {
|
|
14
|
+
const { service } = deps;
|
|
15
|
+
authenticated.get("/api/search", (c) => {
|
|
16
|
+
const query = c.req.query("q")?.trim() ?? "";
|
|
17
|
+
const limit = parseLimit(c.req.query("limit"));
|
|
18
|
+
const types = parseTypes(c.req.query("types"));
|
|
19
|
+
const hits = [];
|
|
20
|
+
if (query && types.has("project")) {
|
|
21
|
+
const projects = service.projects.list({
|
|
22
|
+
search: query,
|
|
23
|
+
limit,
|
|
24
|
+
offset: 0
|
|
25
|
+
}).items;
|
|
26
|
+
hits.push(...projects.map((project, index) => ({
|
|
27
|
+
kind: "project",
|
|
28
|
+
id: `project:${project.id}`,
|
|
29
|
+
title: project.name,
|
|
30
|
+
subtitle: projectSubtitle(project),
|
|
31
|
+
href: `/projects/${encodeURIComponent(project.id)}`,
|
|
32
|
+
score: index,
|
|
33
|
+
payload: { project }
|
|
34
|
+
})));
|
|
35
|
+
}
|
|
36
|
+
return c.json({
|
|
37
|
+
ok: true,
|
|
38
|
+
query,
|
|
39
|
+
hits,
|
|
40
|
+
total: hits.length
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
export { registerSearchRoutes };
|
|
46
|
+
|
|
47
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","names":[],"sources":["../../../../../src/gateway/hono/routes/search.ts"],"sourcesContent":["import type { Hono } from 'hono';\n\nimport type { Project } from '../../../projects/types.js';\nimport type { AuthenticatedRouteDeps } from './deps.js';\n\ntype GlobalSearchHitKind = 'project';\n\ntype GlobalSearchHit = {\n kind: GlobalSearchHitKind;\n id: string;\n title: string;\n subtitle?: string;\n href: string;\n score: number;\n payload: {\n project: Project;\n };\n};\n\nfunction parseLimit(value: string | undefined): number {\n const parsed = value ? Number.parseInt(value, 10) : 20;\n return Math.min(50, Math.max(1, Number.isFinite(parsed) ? parsed : 20));\n}\n\nfunction parseTypes(value: string | undefined): Set<GlobalSearchHitKind> {\n if (!value?.trim()) return new Set<GlobalSearchHitKind>(['project']);\n return new Set(\n value\n .split(',')\n .map((type) => type.trim())\n .filter((type): type is GlobalSearchHitKind => type === 'project'),\n );\n}\n\nfunction projectSubtitle(project: Project): string | undefined {\n return project.description ?? project.workspaceRoot ?? project.brief ?? project.slug;\n}\n\nexport function registerSearchRoutes(authenticated: Hono, deps: AuthenticatedRouteDeps): void {\n const { service } = deps;\n\n authenticated.get('/api/search', (c) => {\n const query = c.req.query('q')?.trim() ?? '';\n const limit = parseLimit(c.req.query('limit'));\n const types = parseTypes(c.req.query('types'));\n const hits: GlobalSearchHit[] = [];\n\n if (query && types.has('project')) {\n const projects = service.projects.list({ search: query, limit, offset: 0 }).items;\n hits.push(\n ...projects.map((project, index) => ({\n kind: 'project' as const,\n id: `project:${project.id}`,\n title: project.name,\n subtitle: projectSubtitle(project),\n href: `/projects/${encodeURIComponent(project.id)}`,\n score: index,\n payload: { project },\n })),\n );\n }\n\n return c.json({ ok: true, query, hits, total: hits.length });\n });\n}\n"],"mappings":";AAmBA,SAAS,WAAW,OAAmC;CACrD,MAAM,SAAS,QAAQ,OAAO,SAAS,OAAO,GAAG,GAAG;AACpD,QAAO,KAAK,IAAI,IAAI,KAAK,IAAI,GAAG,OAAO,SAAS,OAAO,GAAG,SAAS,GAAG,CAAC;;AAGzE,SAAS,WAAW,OAAqD;AACvE,KAAI,CAAC,OAAO,MAAM,CAAE,QAAO,IAAI,IAAyB,CAAC,UAAU,CAAC;AACpE,QAAO,IAAI,IACT,MACG,MAAM,IAAI,CACV,KAAK,SAAS,KAAK,MAAM,CAAC,CAC1B,QAAQ,SAAsC,SAAS,UAAU,CACrE;;AAGH,SAAS,gBAAgB,SAAsC;AAC7D,QAAO,QAAQ,eAAe,QAAQ,iBAAiB,QAAQ,SAAS,QAAQ;;AAGlF,SAAgB,qBAAqB,eAAqB,MAAoC;CAC5F,MAAM,EAAE,YAAY;AAEpB,eAAc,IAAI,gBAAgB,MAAM;EACtC,MAAM,QAAQ,EAAE,IAAI,MAAM,IAAI,EAAE,MAAM,IAAI;EAC1C,MAAM,QAAQ,WAAW,EAAE,IAAI,MAAM,QAAQ,CAAC;EAC9C,MAAM,QAAQ,WAAW,EAAE,IAAI,MAAM,QAAQ,CAAC;EAC9C,MAAM,OAA0B,EAAE;AAElC,MAAI,SAAS,MAAM,IAAI,UAAU,EAAE;GACjC,MAAM,WAAW,QAAQ,SAAS,KAAK;IAAE,QAAQ;IAAO;IAAO,QAAQ;IAAG,CAAC,CAAC;AAC5E,QAAK,KACH,GAAG,SAAS,KAAK,SAAS,WAAW;IACnC,MAAM;IACN,IAAI,WAAW,QAAQ;IACvB,OAAO,QAAQ;IACf,UAAU,gBAAgB,QAAQ;IAClC,MAAM,aAAa,mBAAmB,QAAQ,GAAG;IACjD,OAAO;IACP,SAAS,EAAE,SAAS;IACrB,EAAE,CACJ;;AAGH,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM;GAAO;GAAM,OAAO,KAAK;GAAQ,CAAC;GAC5D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dangerous-tools.js","names":[],"sources":["../../../../src/gateway/security/dangerous-tools.ts"],"sourcesContent":["/**\n * Tools denied via Gateway HTTP tool invoke endpoints by default.\n *\n * These are high-risk because they enable command execution, file mutation,\n * session orchestration, or control-plane actions that don't belong on a\n * non-interactive HTTP surface.\n */\nexport const DEFAULT_GATEWAY_HTTP_TOOL_DENY: readonly string[] = [\n // Direct command execution — immediate RCE surface\n 'exec',\n // Arbitrary child process creation\n 'spawn',\n // Shell command execution\n '
|
|
1
|
+
{"version":3,"file":"dangerous-tools.js","names":[],"sources":["../../../../src/gateway/security/dangerous-tools.ts"],"sourcesContent":["/**\n * Tools denied via Gateway HTTP tool invoke endpoints by default.\n *\n * These are high-risk because they enable command execution, file mutation,\n * session orchestration, or control-plane actions that don't belong on a\n * non-interactive HTTP surface.\n */\nexport const DEFAULT_GATEWAY_HTTP_TOOL_DENY: readonly string[] = [\n // Direct command execution — immediate RCE surface\n 'exec',\n // Arbitrary child process creation\n 'spawn',\n // Shell command execution\n 'exec_command',\n // Arbitrary file mutation on the host\n 'fs_write',\n // Arbitrary file deletion on the host\n 'fs_delete',\n // Arbitrary file move/rename on the host\n 'fs_move',\n // Patch application can rewrite arbitrary files\n 'apply_patch',\n // Session orchestration — spawning agents remotely is RCE\n 'sessions_spawn',\n // Cross-session injection — message injection across sessions\n 'sessions_send',\n // Persistent automation control plane — can create/update/remove scheduled runs\n 'cron',\n // Gateway control plane — prevents gateway reconfiguration via HTTP\n 'gateway',\n // Node command relay can reach system.run on paired hosts\n 'nodes',\n] as const;\n\nconst DANGEROUS_TOOL_SET: ReadonlySet<string> = new Set(DEFAULT_GATEWAY_HTTP_TOOL_DENY);\n\n/**\n * Check whether a tool name is in the default HTTP deny list.\n */\nexport function isDangerousHttpTool(toolName: string): boolean {\n return DANGEROUS_TOOL_SET.has(toolName.toLowerCase());\n}\n\n/**\n * Filter a list of tool names, removing those on the HTTP deny list.\n * Returns only the safe tools.\n */\nexport function filterDangerousHttpTools(toolNames: string[]): {\n allowed: string[];\n denied: string[];\n} {\n const allowed: string[] = [];\n const denied: string[] = [];\n for (const name of toolNames) {\n if (isDangerousHttpTool(name)) {\n denied.push(name);\n } else {\n allowed.push(name);\n }\n }\n return { allowed, denied };\n}\n"],"mappings":";;;;;;;;AAOA,MAAa,iCAAoD;CAE/D;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CAEA;CACD;AAED,MAAM,qBAA0C,IAAI,IAAI,+BAA+B;;;;AAKvF,SAAgB,oBAAoB,UAA2B;AAC7D,QAAO,mBAAmB,IAAI,SAAS,aAAa,CAAC;;;;;;AAOvD,SAAgB,yBAAyB,WAGvC;CACA,MAAM,UAAoB,EAAE;CAC5B,MAAM,SAAmB,EAAE;AAC3B,MAAK,MAAM,QAAQ,UACjB,KAAI,oBAAoB,KAAK,CAC3B,QAAO,KAAK,KAAK;KAEjB,SAAQ,KAAK,KAAK;AAGtB,QAAO;EAAE;EAAS;EAAQ"}
|
|
@@ -2,8 +2,8 @@ import { createLogger } from "../utils/logger/index.js";
|
|
|
2
2
|
import { init_logger } from "../utils/logger.js";
|
|
3
3
|
import { init_paths, resolveConfigPath } from "../config/paths.js";
|
|
4
4
|
import { init_loader, loadConfig } from "../config/loader.js";
|
|
5
|
-
import { isRestartEnabled } from "../config/commands.flags.js";
|
|
6
5
|
import { resolveGatewayService } from "../daemon/service.js";
|
|
6
|
+
import { isRestartEnabled } from "../config/commands.flags.js";
|
|
7
7
|
import { authorizeGatewaySigusr1Restart, writeGatewayRestartIntentSync } from "./restart.js";
|
|
8
8
|
import { findVerifiedGatewayListenerPidsOnPortSync, signalVerifiedGatewayPidSync } from "./gateway-processes.js";
|
|
9
9
|
//#region src/infra/update-restart.ts
|
|
@@ -2,6 +2,8 @@ export * from './types.js';
|
|
|
2
2
|
export * from './project-store.js';
|
|
3
3
|
export * from './project-service.js';
|
|
4
4
|
export * from './project-agent.js';
|
|
5
|
+
export * from './project-agent-suggestion.js';
|
|
6
|
+
export * from './project-kind.js';
|
|
5
7
|
export * from './project-loop.js';
|
|
6
8
|
export * from './session-bind.js';
|
|
7
9
|
export * from './goal-bind.js';
|
|
@@ -9,3 +11,4 @@ export * from './workflow-bind.js';
|
|
|
9
11
|
export * from './automation-bind.js';
|
|
10
12
|
export * from './memory-bind.js';
|
|
11
13
|
export * from './workspace.js';
|
|
14
|
+
export * from './workspace-project.js';
|
|
@@ -2,10 +2,13 @@ import { ProjectStore, slugifyProjectName } from "./project-store.js";
|
|
|
2
2
|
import { getProjectForSession, getProjectWorkspacePathForSession, resolveProjectWorkspacePath } from "./workspace.js";
|
|
3
3
|
import { bindGoalToProject, bindGoalsToProject, listProjectGoalIds, unbindGoalFromProject } from "./goal-bind.js";
|
|
4
4
|
import { bindSessionToProject, bindSessionsToProject, listProjectSessionKeys, moveSessionToProject, unbindSessionFromProject } from "./session-bind.js";
|
|
5
|
+
import { ProjectWorkspaceConflictError, ProjectWorkspaceMissingError, canonicalWorkspacePath, ensureWorkspaceDirectory, inferProjectNameFromWorkspaceRoot, isPathSameOrInsideWorkspace, isSafeAutoCreateWorkspaceRoot, resolveWorkspaceProjectRoot, workspaceDirectoryExists } from "./workspace-project.js";
|
|
5
6
|
import { ProjectService } from "./project-service.js";
|
|
6
7
|
import { isValidProjectAgentId, normalizeProjectAgentId, resolveProjectAgentId } from "./project-agent.js";
|
|
8
|
+
import { inferProjectKind } from "./project-kind.js";
|
|
9
|
+
import { CODING_PROJECT_AGENT_ID, inferSuggestedProjectDefaultAgentId, suggestProjectDefaultAgentId } from "./project-agent-suggestion.js";
|
|
7
10
|
import { buildProjectLoopOverview } from "./project-loop.js";
|
|
8
11
|
import { bindWorkflowRunToProject } from "./workflow-bind.js";
|
|
9
12
|
import { bindAutomationToProject } from "./automation-bind.js";
|
|
10
13
|
import { bindMemoryRecordToProject } from "./memory-bind.js";
|
|
11
|
-
export { ProjectService, ProjectStore, bindAutomationToProject, bindGoalToProject, bindGoalsToProject, bindMemoryRecordToProject, bindSessionToProject, bindSessionsToProject, bindWorkflowRunToProject, buildProjectLoopOverview, getProjectForSession, getProjectWorkspacePathForSession, isValidProjectAgentId, listProjectGoalIds, listProjectSessionKeys, moveSessionToProject, normalizeProjectAgentId, resolveProjectAgentId, resolveProjectWorkspacePath, slugifyProjectName, unbindGoalFromProject, unbindSessionFromProject };
|
|
14
|
+
export { CODING_PROJECT_AGENT_ID, ProjectService, ProjectStore, ProjectWorkspaceConflictError, ProjectWorkspaceMissingError, bindAutomationToProject, bindGoalToProject, bindGoalsToProject, bindMemoryRecordToProject, bindSessionToProject, bindSessionsToProject, bindWorkflowRunToProject, buildProjectLoopOverview, canonicalWorkspacePath, ensureWorkspaceDirectory, getProjectForSession, getProjectWorkspacePathForSession, inferProjectKind, inferProjectNameFromWorkspaceRoot, inferSuggestedProjectDefaultAgentId, isPathSameOrInsideWorkspace, isSafeAutoCreateWorkspaceRoot, isValidProjectAgentId, listProjectGoalIds, listProjectSessionKeys, moveSessionToProject, normalizeProjectAgentId, resolveProjectAgentId, resolveProjectWorkspacePath, resolveWorkspaceProjectRoot, slugifyProjectName, suggestProjectDefaultAgentId, unbindGoalFromProject, unbindSessionFromProject, workspaceDirectoryExists };
|