@xopcai/xopc 0.0.123 → 0.0.125
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/Combination-BzaXOLd9.js +41 -0
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-Bicr3ZBg.js → agent-avatar-dicebear-BKDKICZV.js} +1 -1
- package/dist/gateway/static/root/assets/agents-BnTB7-c5.js +2 -0
- package/dist/gateway/static/root/assets/app-management-settings-panel-DI4BqHKW.js +1 -0
- package/dist/gateway/static/root/assets/appearance-settings-6_ie3NQ4.js +1 -0
- package/dist/gateway/static/root/assets/apps-page-B6bG65SW.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-Bpy64GjU.js → archive-plugin-kUHEJ1HK.js} +1 -1
- package/dist/gateway/static/root/assets/{attachment-load-DMkp4xSb.js → attachment-load-Dm-9prpU.js} +1 -1
- package/dist/gateway/static/root/assets/automation-suggestion-card-OTxQTPnC.js +1 -0
- package/dist/gateway/static/root/assets/automations-page-1lVbo0dS.js +1 -0
- package/dist/gateway/static/root/assets/{binary-plugins-DA9C5mCw.js → binary-plugins-DllA_jQ0.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-CiSXk_YC.js → block-editor-Cm6CWNj1.js} +5 -5
- package/dist/gateway/static/root/assets/browser-settings-page-CzDBlOK0.js +8 -0
- package/dist/gateway/static/root/assets/capability-presets-api-VJ89b6I2.js +1 -0
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-BaPj8wC2.js +1 -0
- package/dist/gateway/static/root/assets/{channel-recipient-api-CDhrhfhN.js → channel-recipient-api-B5PwBEUx.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-Df4m7p1k.js +1 -0
- package/dist/gateway/static/root/assets/code-editor-gbRgS14t.js +1 -0
- package/dist/gateway/static/root/assets/connectors-page-BMTphmHS.js +2 -0
- package/dist/gateway/static/root/assets/{directory-picker-path-field-7jKfbH0J.js → directory-picker-path-field-DySMzOF6.js} +1 -1
- package/dist/gateway/static/root/assets/dist-By6Rh2ee.js +1 -0
- package/dist/gateway/static/root/assets/dist-CkobR7mk.js +1 -0
- package/dist/gateway/static/root/assets/dist-DokQNVMQ.js +1 -0
- package/dist/gateway/static/root/assets/dreaming-settings-D_AjSnV_.js +3 -0
- package/dist/gateway/static/root/assets/extension-debug-page-BaM0FpW7.js +1 -0
- package/dist/gateway/static/root/assets/extension-page-DuZWVOGA.js +1 -0
- package/dist/gateway/static/root/assets/extension-settings-page-DarVtbmJ.js +1 -0
- package/dist/gateway/static/root/assets/{fetch-Dtpbbe0s.js → fetch-NFKfkqrd.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-config-api-BN6pyX2c.js → gateway-config-api-CFEm9rgy.js} +1 -1
- package/dist/gateway/static/root/assets/gateway-settings-BMk2S5td.js +1 -0
- package/dist/gateway/static/root/assets/{gateway-startup-retry-BIET2x3y.js → gateway-startup-retry-Dtwh_yGg.js} +1 -1
- package/dist/gateway/static/root/assets/goal-create-dialog-BKP7ylcG.js +1 -0
- package/dist/gateway/static/root/assets/goal-detail-page-C2cTxf71.js +1 -0
- package/dist/gateway/static/root/assets/{goals-config-api-CQm2r1Ty.js → goals-config-api-DTWZNA_Y.js} +1 -1
- package/dist/gateway/static/root/assets/goals-page-CTmA3hWK.js +2 -0
- package/dist/gateway/static/root/assets/goals-settings-Bhct0ZT-.js +1 -0
- package/dist/gateway/static/root/assets/heartbeat-settings-C-UxSU4a.js +1 -0
- package/dist/gateway/static/root/assets/{html-workspace-editor-CQLWDiwE.js → html-workspace-editor-DV90ddkE.js} +1 -1
- package/dist/gateway/static/root/assets/index-BNHDd2j1.css +1 -0
- package/dist/gateway/static/root/assets/index-BPXLPMuY.js +193 -0
- package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-DCjy2y4d.js +1 -0
- package/dist/gateway/static/root/assets/logs-page-CGc3_CQU.js +2 -0
- package/dist/gateway/static/root/assets/{markdown-editor-AssmZFx4.js → markdown-editor-BFOjBBla.js} +2 -2
- package/dist/gateway/static/root/assets/markdown-split-BaqxP-GQ.js +1 -0
- package/dist/gateway/static/root/assets/{media-plugins-DS44pJzr.js → media-plugins-DQ_EXloK.js} +1 -1
- package/dist/gateway/static/root/assets/messages-CjuIJcZl.js +3 -0
- package/dist/gateway/static/root/assets/models-hub-panel-Drz4UQMb.js +2 -0
- package/dist/gateway/static/root/assets/notes-page-CY1ylng1.js +1 -0
- package/dist/gateway/static/root/assets/notes-workbench-X7IaD--t.js +2 -0
- package/dist/gateway/static/root/assets/page-tabs-EIZhLppK.js +1 -0
- package/dist/gateway/static/root/assets/{preview-open-alternatives-Dej6zHnr.js → preview-open-alternatives-r_uB4Epr.js} +1 -1
- package/dist/gateway/static/root/assets/project-detail-page-DE5adRBE.js +1 -0
- package/dist/gateway/static/root/assets/projects-page-CuOb1k6F.js +1 -0
- package/dist/gateway/static/root/assets/remote-access-hub-BOxNrUVA.js +1 -0
- package/dist/gateway/static/root/assets/{save-bar-controls-Zu1FzH6z.js → save-bar-controls-B132Uf-2.js} +1 -1
- package/dist/gateway/static/root/assets/{schedule-field-BW78mKc0.js → schedule-field-B5qshALm.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-Cc-IOydE.js → schema-form-CvLmkdS9.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-CY0IQcGW.js +1 -0
- package/dist/gateway/static/root/assets/settings-advanced-gate-D4NBNVCB.js +1 -0
- package/dist/gateway/static/root/assets/{settings-collapsible-section-DIpIYht_.js → settings-collapsible-section-pRlvqsAf.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-form-section-BFxBNxOG.js → settings-form-section-BBYUDLVd.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-C4fivemT.js → settings-page-DaO7zYZM.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-layout-CLx4o2PN.js → settings-page-layout-D8g9PAek.js} +1 -1
- package/dist/gateway/static/root/assets/setup-status-panel-Bks0CLLT.js +1 -0
- package/dist/gateway/static/root/assets/{share-preview-page-ZswWCrDu.js → share-preview-page-v6-IOp8t.js} +1 -1
- package/dist/gateway/static/root/assets/shares-settings-CEZsKm9r.js +1 -0
- package/dist/gateway/static/root/assets/skill-reload-api-oTkHbb9W.js +1 -0
- package/dist/gateway/static/root/assets/skills-page-DigsbZ6K.js +2 -0
- package/dist/gateway/static/root/assets/{system-settings-panel-3ZNcGRhS.js → system-settings-panel-HUU2FFjM.js} +1 -1
- package/dist/gateway/static/root/assets/{typed-models-lib-bpzZjiVF.js → typed-models-lib-AH160QHh.js} +1 -1
- package/dist/gateway/static/root/assets/{use-channel-catalog-BCjZLZ3O.js → use-channel-catalog-BXzDmjCQ.js} +1 -1
- package/dist/gateway/static/root/assets/{user-profile-settings-panel-CIXafITi.js → user-profile-settings-panel-DxwnQvQ3.js} +1 -1
- package/dist/gateway/static/root/assets/{utils-DXMtz5j_.js → utils-i5POEtqd.js} +1 -1
- package/dist/gateway/static/root/assets/{vendor-codemirror-CNP1wPe7.js → vendor-codemirror-BvNgyE1Q.js} +1 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-CEJklEgb.js +1 -0
- package/dist/gateway/static/root/assets/work-item-detail-page-CD6FL_Rs.js +1 -0
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-ClVVMgN-.js +3 -0
- package/dist/gateway/static/root/assets/{workflow-start-dialog-B4sZpTDQ.js → workflow-start-dialog-Dv4ZA1T0.js} +1 -1
- package/dist/gateway/static/root/assets/workflows-page-OLQiUpoW.js +18 -0
- package/dist/gateway/static/root/index.html +8 -7
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.d.ts +6 -1
- package/dist/src/agent/agent-manager.js +34 -14
- package/dist/src/agent/agent-manager.js.map +1 -1
- package/dist/src/agent/child-agent-factory.d.ts +2 -0
- package/dist/src/agent/child-agent-factory.js +2 -0
- package/dist/src/agent/child-agent-factory.js.map +1 -1
- package/dist/src/agent/coding/index.d.ts +1 -0
- package/dist/src/agent/coding/index.js +2 -0
- package/dist/src/agent/coding/turn-diff-tracker.d.ts +67 -0
- package/dist/src/agent/coding/turn-diff-tracker.js +233 -0
- package/dist/src/agent/coding/turn-diff-tracker.js.map +1 -0
- 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/dreaming/config.d.ts +2 -2
- package/dist/src/agent/memory/dreaming/config.js +3 -3
- package/dist/src/agent/memory/dreaming/config.js.map +1 -1
- package/dist/src/agent/memory/dreaming/constants.d.ts +1 -1
- package/dist/src/agent/memory/dreaming/constants.js +1 -1
- package/dist/src/agent/memory/dreaming/constants.js.map +1 -1
- package/dist/src/agent/memory/dreaming/deep-promotion.d.ts +1 -0
- package/dist/src/agent/memory/dreaming/deep-promotion.js +11 -20
- package/dist/src/agent/memory/dreaming/deep-promotion.js.map +1 -1
- package/dist/src/agent/memory/dreaming/events.d.ts +3 -3
- package/dist/src/agent/memory/dreaming/events.js +6 -6
- package/dist/src/agent/memory/dreaming/events.js.map +1 -1
- package/dist/src/agent/memory/dreaming/last-run.d.ts +2 -2
- package/dist/src/agent/memory/dreaming/last-run.js +1 -1
- package/dist/src/agent/memory/dreaming/last-run.js.map +1 -1
- package/dist/src/agent/memory/dreaming/light-sweep.d.ts +1 -1
- package/dist/src/agent/memory/dreaming/light-sweep.js +3 -3
- package/dist/src/agent/memory/dreaming/light-sweep.js.map +1 -1
- package/dist/src/agent/memory/dreaming/preview.d.ts +1 -0
- package/dist/src/agent/memory/dreaming/preview.js +2 -2
- package/dist/src/agent/memory/dreaming/preview.js.map +1 -1
- package/dist/src/agent/memory/dreaming/rem-patterns.d.ts +1 -1
- package/dist/src/agent/memory/dreaming/rem-patterns.js +13 -13
- package/dist/src/agent/memory/dreaming/rem-patterns.js.map +1 -1
- package/dist/src/agent/memory/dreaming/scope.d.ts +14 -0
- package/dist/src/agent/memory/dreaming/scope.js +27 -0
- package/dist/src/agent/memory/dreaming/scope.js.map +1 -0
- package/dist/src/agent/memory/dreaming/short-term-store.d.ts +4 -4
- package/dist/src/agent/memory/dreaming/short-term-store.js +17 -17
- package/dist/src/agent/memory/dreaming/short-term-store.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.d.ts +2 -0
- package/dist/src/agent/orchestration/agent-event-handler.js +69 -14
- package/dist/src/agent/orchestration/agent-event-handler.js.map +1 -1
- package/dist/src/agent/orchestration/agent-orchestrator.js +22 -12
- package/dist/src/agent/orchestration/agent-orchestrator.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/command-validator.js +12 -0
- package/dist/src/agent/sandbox/command-validator.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.d.ts +2 -1
- package/dist/src/agent/service.js +19 -6
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/session/session-inspector.d.ts +5 -3
- package/dist/src/agent/session/session-inspector.js +16 -7
- package/dist/src/agent/session/session-inspector.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/source-context/types.d.ts +1 -1
- package/dist/src/agent/source-context/types.js +1 -1
- package/dist/src/agent/source-context/types.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 +310 -0
- package/dist/src/agent/tools/apply-patch.js.map +1 -0
- package/dist/src/agent/tools/concurrency.d.ts +8 -0
- package/dist/src/agent/tools/concurrency.js +31 -0
- package/dist/src/agent/tools/concurrency.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/dreaming-tool.d.ts +2 -0
- package/dist/src/agent/tools/dreaming-tool.js +13 -10
- package/dist/src/agent/tools/dreaming-tool.js.map +1 -1
- package/dist/src/agent/tools/exec-command.d.ts +30 -0
- package/dist/src/agent/tools/exec-command.js +228 -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/executor.d.ts +6 -4
- package/dist/src/agent/tools/executor.js +7 -4
- package/dist/src/agent/tools/executor.js.map +1 -1
- package/dist/src/agent/tools/factory.d.ts +6 -3
- package/dist/src/agent/tools/factory.js +14 -9
- package/dist/src/agent/tools/factory.js.map +1 -1
- package/dist/src/agent/tools/find.js +2 -0
- package/dist/src/agent/tools/find.js.map +1 -1
- package/dist/src/agent/tools/grep.js +2 -0
- package/dist/src/agent/tools/grep.js.map +1 -1
- package/dist/src/agent/tools/index.d.ts +5 -2
- package/dist/src/agent/tools/index.js +7 -4
- package/dist/src/agent/tools/list-dir.js +2 -0
- package/dist/src/agent/tools/list-dir.js.map +1 -1
- package/dist/src/agent/tools/memory-tool.d.ts +1 -0
- package/dist/src/agent/tools/memory-tool.js +2 -2
- package/dist/src/agent/tools/memory-tool.js.map +1 -1
- package/dist/src/agent/tools/metadata.d.ts +15 -0
- package/dist/src/agent/tools/metadata.js +26 -0
- package/dist/src/agent/tools/metadata.js.map +1 -0
- package/dist/src/agent/tools/read.js +2 -0
- package/dist/src/agent/tools/read.js.map +1 -1
- 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/tools/write.js +6 -0
- package/dist/src/agent/tools/write.js.map +1 -1
- 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/agent/workflow/subagent-runner.d.ts +1 -0
- package/dist/src/agent/workflow/subagent-runner.js +5 -1
- package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
- package/dist/src/agent/workflow/workflow-child-tools.js +5 -0
- package/dist/src/agent/workflow/workflow-child-tools.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/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/connectors/health.d.ts +2 -1
- package/dist/src/connectors/health.js +59 -1
- package/dist/src/connectors/health.js.map +1 -1
- package/dist/src/connectors/install.d.ts +1 -0
- package/dist/src/connectors/install.js +28 -1
- package/dist/src/connectors/install.js.map +1 -1
- package/dist/src/connectors/instances.js +7 -0
- package/dist/src/connectors/instances.js.map +1 -1
- package/dist/src/connectors/materialize.js +2 -1
- package/dist/src/connectors/materialize.js.map +1 -1
- package/dist/src/connectors/registries/modelscope.js +38 -13
- package/dist/src/connectors/registries/modelscope.js.map +1 -1
- package/dist/src/connectors/types.d.ts +2 -0
- 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/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/dreaming-automation-reconciler.d.ts +1 -0
- package/dist/src/gateway/dreaming-automation-reconciler.js +62 -42
- package/dist/src/gateway/dreaming-automation-reconciler.js.map +1 -1
- package/dist/src/gateway/hono/app.js +7 -1
- package/dist/src/gateway/hono/app.js.map +1 -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/connectors.js +46 -2
- package/dist/src/gateway/hono/routes/connectors.js.map +1 -1
- package/dist/src/gateway/hono/routes/dreaming.js +111 -66
- package/dist/src/gateway/hono/routes/dreaming.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 +886 -45
- 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/hono/routes/sessions.js +1 -0
- package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
- package/dist/src/gateway/security/dangerous-tools.js +1 -1
- package/dist/src/gateway/security/dangerous-tools.js.map +1 -1
- package/dist/src/gateway/service.js +17 -8
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/infra/update-restart.js +1 -1
- package/dist/src/mcp/channel-bridge.js +1 -1
- package/dist/src/media/store.js +1 -1
- package/dist/src/media/store.js.map +1 -1
- package/dist/src/media/types.d.ts +1 -1
- package/dist/src/media/uri.js +2 -1
- package/dist/src/media/uri.js.map +1 -1
- package/dist/src/projects/index.d.ts +2 -0
- package/dist/src/projects/index.js +3 -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 +1 -0
- package/dist/src/projects/project-service.js +1 -1
- 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 +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.d.ts +2 -0
- package/dist/src/session/session-context-for-llm.js +165 -1
- package/dist/src/session/session-context-for-llm.js.map +1 -1
- package/dist/src/session/store.js +2 -2
- package/dist/src/session/store.js.map +1 -1
- package/dist/src/storage/sqlite/migrations/021_projects_fts.sql +21 -0
- package/dist/src/storage/sqlite/migrations/022_work_items.sql +61 -0
- package/dist/src/storage/sqlite/migrations/023_work_item_attachments.sql +15 -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/storage/sqlite/schema.sql +78 -0
- package/dist/src/tui/backends/embedded-backend.d.ts +1 -0
- package/dist/src/tui/backends/embedded-backend.js +20 -0
- package/dist/src/tui/backends/embedded-backend.js.map +1 -1
- package/dist/src/tui/backends/gateway-sse-backend.d.ts +2 -0
- package/dist/src/tui/backends/gateway-sse-backend.js +7 -0
- package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
- package/dist/src/tui/components/assistant-message.js +47 -2
- package/dist/src/tui/components/assistant-message.js.map +1 -1
- package/dist/src/tui/components/tool-execution.d.ts +8 -0
- package/dist/src/tui/components/tool-execution.js +87 -77
- package/dist/src/tui/components/tool-execution.js.map +1 -1
- package/dist/src/tui/components/visual-truncate.d.ts +1 -0
- package/dist/src/tui/components/visual-truncate.js +28 -1
- package/dist/src/tui/components/visual-truncate.js.map +1 -1
- package/dist/src/tui/tool-summary.d.ts +22 -0
- package/dist/src/tui/tool-summary.js +212 -0
- package/dist/src/tui/tool-summary.js.map +1 -0
- 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 +4 -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-tool-diff.d.ts +15 -0
- package/dist/src/tui/tui-tool-diff.js +178 -7
- package/dist/src/tui/tui-tool-diff.js.map +1 -1
- package/dist/src/tui/tui.js +16 -3
- package/dist/src/tui/tui.js.map +1 -1
- package/dist/src/work-items/agent-context.d.ts +3 -0
- package/dist/src/work-items/agent-context.js +39 -0
- package/dist/src/work-items/agent-context.js.map +1 -0
- package/dist/src/work-items/index.d.ts +4 -0
- package/dist/src/work-items/index.js +4 -0
- package/dist/src/work-items/types.d.ts +112 -0
- package/dist/src/work-items/types.js +1 -0
- package/dist/src/work-items/work-item-service.d.ts +33 -0
- package/dist/src/work-items/work-item-service.js +180 -0
- package/dist/src/work-items/work-item-service.js.map +1 -0
- package/dist/src/work-items/work-item-store.d.ts +21 -0
- package/dist/src/work-items/work-item-store.js +302 -0
- package/dist/src/work-items/work-item-store.js.map +1 -0
- package/dist/src/workflows/service/workflow-run-service.js +4 -3
- package/dist/src/workflows/service/workflow-run-service.js.map +1 -1
- package/dist/src/workflows/service/workflow-session-bridge.js +3 -0
- package/dist/src/workflows/service/workflow-session-bridge.js.map +1 -1
- package/package.json +1 -1
- package/dist/gateway/static/root/assets/Combination-HAlzriaz.js +0 -41
- package/dist/gateway/static/root/assets/agents-CxDSFHGx.js +0 -2
- package/dist/gateway/static/root/assets/app-management-settings-panel-CbEy9sR1.js +0 -1
- package/dist/gateway/static/root/assets/appearance-settings-CTHja6n9.js +0 -1
- package/dist/gateway/static/root/assets/apps-page-CyZdgqvm.js +0 -1
- package/dist/gateway/static/root/assets/automation-suggestion-card-KnYaP7NT.js +0 -1
- package/dist/gateway/static/root/assets/automations-page-8VLKM4au.js +0 -1
- package/dist/gateway/static/root/assets/browser-settings-page-5tPg0DcP.js +0 -8
- package/dist/gateway/static/root/assets/capability-presets-api-CEJ44WCU.js +0 -1
- package/dist/gateway/static/root/assets/capability-presets-settings-panel-BJW3aVST.js +0 -1
- package/dist/gateway/static/root/assets/channels-settings-CorUCTrs.js +0 -1
- package/dist/gateway/static/root/assets/code-editor-dZTY2dRW.js +0 -1
- package/dist/gateway/static/root/assets/connectors-page-VKstC3sP.js +0 -2
- package/dist/gateway/static/root/assets/dist-Mys7eFJ5.js +0 -1
- package/dist/gateway/static/root/assets/dist-wO9a2_ID.js +0 -1
- package/dist/gateway/static/root/assets/dreaming-settings-m1-wmz4o.js +0 -1
- package/dist/gateway/static/root/assets/extension-debug-page-C9qQQrBS.js +0 -1
- package/dist/gateway/static/root/assets/extension-page-DcBBMEGl.js +0 -1
- package/dist/gateway/static/root/assets/extension-settings-page-BQ-jMMP9.js +0 -1
- package/dist/gateway/static/root/assets/gateway-settings-hQtgVmSR.js +0 -1
- package/dist/gateway/static/root/assets/goal-create-dialog-BuIMDx6C.js +0 -1
- package/dist/gateway/static/root/assets/goal-detail-page-FEypCq74.js +0 -1
- package/dist/gateway/static/root/assets/goals-page-C4-2_MLG.js +0 -2
- package/dist/gateway/static/root/assets/goals-settings-DDrdRMxB.js +0 -1
- package/dist/gateway/static/root/assets/heartbeat-settings-BJVok3Sl.js +0 -1
- package/dist/gateway/static/root/assets/index-CBDr5xjB.css +0 -1
- package/dist/gateway/static/root/assets/index-T0SaNd5a.js +0 -191
- package/dist/gateway/static/root/assets/keyboard-shortcuts-settings-C2TuQppb.js +0 -1
- package/dist/gateway/static/root/assets/logs-page-DwkwPgid.js +0 -2
- package/dist/gateway/static/root/assets/markdown-split-DhONQ81k.js +0 -1
- package/dist/gateway/static/root/assets/messages-avfvyZuQ.js +0 -3
- package/dist/gateway/static/root/assets/models-hub-panel-huNY4A1G.js +0 -2
- package/dist/gateway/static/root/assets/notes-page-DdfGuEZ1.js +0 -1
- package/dist/gateway/static/root/assets/notes-workbench-B0bT9Hqa.js +0 -2
- package/dist/gateway/static/root/assets/project-detail-page-CjxhPorG.js +0 -1
- package/dist/gateway/static/root/assets/projects-page-C4Z5OJMF.js +0 -1
- package/dist/gateway/static/root/assets/remote-access-hub-CVCOPUVd.js +0 -1
- package/dist/gateway/static/root/assets/sessions-page-B4qExXHC.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-Ce8yLTBi.js +0 -1
- package/dist/gateway/static/root/assets/setup-status-panel-Kyc4eUf0.js +0 -1
- package/dist/gateway/static/root/assets/shares-settings-Bu76CMiC.js +0 -1
- package/dist/gateway/static/root/assets/skill-reload-api-D-CFg86j.js +0 -1
- package/dist/gateway/static/root/assets/skills-page-CUU4f6Ss.js +0 -2
- package/dist/gateway/static/root/assets/voice-api-key-field-C1MrQD8R.js +0 -1
- package/dist/gateway/static/root/assets/workflow-run-setup-panel-DqizIcY5.js +0 -3
- package/dist/gateway/static/root/assets/workflows-page-B3sVNPFk.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
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { canonicalWorkspacePath } from "./workspace-project.js";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { existsSync, readdirSync, statSync } from "node:fs";
|
|
4
|
+
//#region src/projects/project-kind.ts
|
|
5
|
+
const STRONG_CODE_MARKERS = [
|
|
6
|
+
".git",
|
|
7
|
+
"package.json",
|
|
8
|
+
"pnpm-lock.yaml",
|
|
9
|
+
"yarn.lock",
|
|
10
|
+
"package-lock.json",
|
|
11
|
+
"tsconfig.json",
|
|
12
|
+
"go.mod",
|
|
13
|
+
"Cargo.toml",
|
|
14
|
+
"pyproject.toml",
|
|
15
|
+
"requirements.txt",
|
|
16
|
+
"pom.xml",
|
|
17
|
+
"build.gradle",
|
|
18
|
+
"Makefile",
|
|
19
|
+
"Dockerfile",
|
|
20
|
+
"deno.json",
|
|
21
|
+
"deno.jsonc",
|
|
22
|
+
"composer.json",
|
|
23
|
+
"Gemfile"
|
|
24
|
+
];
|
|
25
|
+
const WEAK_CODE_DIRECTORIES = [
|
|
26
|
+
"src",
|
|
27
|
+
"app",
|
|
28
|
+
"lib",
|
|
29
|
+
"tests",
|
|
30
|
+
"test",
|
|
31
|
+
"__tests__",
|
|
32
|
+
".github"
|
|
33
|
+
];
|
|
34
|
+
const CODE_EXTENSIONS = new Set([
|
|
35
|
+
".c",
|
|
36
|
+
".cc",
|
|
37
|
+
".cpp",
|
|
38
|
+
".cs",
|
|
39
|
+
".css",
|
|
40
|
+
".go",
|
|
41
|
+
".h",
|
|
42
|
+
".hpp",
|
|
43
|
+
".html",
|
|
44
|
+
".java",
|
|
45
|
+
".js",
|
|
46
|
+
".jsx",
|
|
47
|
+
".kt",
|
|
48
|
+
".mjs",
|
|
49
|
+
".php",
|
|
50
|
+
".py",
|
|
51
|
+
".rb",
|
|
52
|
+
".rs",
|
|
53
|
+
".sh",
|
|
54
|
+
".swift",
|
|
55
|
+
".ts",
|
|
56
|
+
".tsx"
|
|
57
|
+
]);
|
|
58
|
+
function normalizeOverride(value) {
|
|
59
|
+
const normalized = value?.trim().toLowerCase();
|
|
60
|
+
return normalized === "coding" || normalized === "general" ? normalized : "auto";
|
|
61
|
+
}
|
|
62
|
+
function hasSourceExtension(name) {
|
|
63
|
+
const lower = name.toLowerCase();
|
|
64
|
+
for (const extension of CODE_EXTENSIONS) if (lower.endsWith(extension)) return true;
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
function readDirectoryNames(pathValue) {
|
|
68
|
+
try {
|
|
69
|
+
return readdirSync(pathValue).slice(0, 200);
|
|
70
|
+
} catch {
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function directoryExists(pathValue) {
|
|
75
|
+
try {
|
|
76
|
+
return statSync(pathValue).isDirectory();
|
|
77
|
+
} catch {
|
|
78
|
+
return false;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function inferProjectKind(input) {
|
|
82
|
+
const override = normalizeOverride(input.projectKind);
|
|
83
|
+
if (override === "coding") return {
|
|
84
|
+
kind: "coding",
|
|
85
|
+
confidence: 1,
|
|
86
|
+
reasons: ["selected coding project type"]
|
|
87
|
+
};
|
|
88
|
+
if (override === "general") return {
|
|
89
|
+
kind: "general",
|
|
90
|
+
confidence: 1,
|
|
91
|
+
reasons: ["selected general project type"]
|
|
92
|
+
};
|
|
93
|
+
const workspaceRoot = canonicalWorkspacePath(input.workspaceRoot);
|
|
94
|
+
const reasons = [];
|
|
95
|
+
let score = 0;
|
|
96
|
+
if (workspaceRoot && directoryExists(workspaceRoot)) {
|
|
97
|
+
for (const marker of STRONG_CODE_MARKERS) if (existsSync(join(workspaceRoot, marker))) {
|
|
98
|
+
score += 4;
|
|
99
|
+
reasons.push(`found ${marker}`);
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
for (const dir of WEAK_CODE_DIRECTORIES) if (directoryExists(join(workspaceRoot, dir))) {
|
|
103
|
+
score += 1;
|
|
104
|
+
reasons.push(`found ${dir}/`);
|
|
105
|
+
break;
|
|
106
|
+
}
|
|
107
|
+
if (readDirectoryNames(workspaceRoot).some(hasSourceExtension)) {
|
|
108
|
+
score += 2;
|
|
109
|
+
reasons.push("found source files");
|
|
110
|
+
} else for (const dir of [
|
|
111
|
+
"src",
|
|
112
|
+
"app",
|
|
113
|
+
"lib"
|
|
114
|
+
]) {
|
|
115
|
+
const childDir = join(workspaceRoot, dir);
|
|
116
|
+
if (directoryExists(childDir) && readDirectoryNames(childDir).some(hasSourceExtension)) {
|
|
117
|
+
score += 2;
|
|
118
|
+
reasons.push(`found source files in ${dir}/`);
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
if (score >= 4) return {
|
|
124
|
+
kind: "coding",
|
|
125
|
+
confidence: .9,
|
|
126
|
+
reasons
|
|
127
|
+
};
|
|
128
|
+
if (score >= 3) return {
|
|
129
|
+
kind: "coding",
|
|
130
|
+
confidence: .75,
|
|
131
|
+
reasons
|
|
132
|
+
};
|
|
133
|
+
if (workspaceRoot) return {
|
|
134
|
+
kind: "general",
|
|
135
|
+
confidence: .55,
|
|
136
|
+
reasons
|
|
137
|
+
};
|
|
138
|
+
return {
|
|
139
|
+
kind: "unknown",
|
|
140
|
+
confidence: .25,
|
|
141
|
+
reasons
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
//#endregion
|
|
145
|
+
export { inferProjectKind };
|
|
146
|
+
|
|
147
|
+
//# sourceMappingURL=project-kind.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project-kind.js","names":[],"sources":["../../../src/projects/project-kind.ts"],"sourcesContent":["import { existsSync, readdirSync, statSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { canonicalWorkspacePath } from './workspace-project.js';\n\nexport type ProjectKind = 'coding' | 'general' | 'unknown';\nexport type ProjectKindOverride = 'auto' | 'coding' | 'general';\n\nexport type ProjectKindInference = {\n kind: ProjectKind;\n confidence: number;\n reasons: string[];\n};\n\nconst STRONG_CODE_MARKERS = [\n '.git',\n 'package.json',\n 'pnpm-lock.yaml',\n 'yarn.lock',\n 'package-lock.json',\n 'tsconfig.json',\n 'go.mod',\n 'Cargo.toml',\n 'pyproject.toml',\n 'requirements.txt',\n 'pom.xml',\n 'build.gradle',\n 'Makefile',\n 'Dockerfile',\n 'deno.json',\n 'deno.jsonc',\n 'composer.json',\n 'Gemfile',\n] as const;\n\nconst WEAK_CODE_DIRECTORIES = ['src', 'app', 'lib', 'tests', 'test', '__tests__', '.github'] as const;\nconst CODE_EXTENSIONS = new Set([\n '.c',\n '.cc',\n '.cpp',\n '.cs',\n '.css',\n '.go',\n '.h',\n '.hpp',\n '.html',\n '.java',\n '.js',\n '.jsx',\n '.kt',\n '.mjs',\n '.php',\n '.py',\n '.rb',\n '.rs',\n '.sh',\n '.swift',\n '.ts',\n '.tsx',\n]);\n\nfunction normalizeOverride(value: string | null | undefined): ProjectKindOverride {\n const normalized = value?.trim().toLowerCase();\n return normalized === 'coding' || normalized === 'general' ? normalized : 'auto';\n}\n\nfunction hasSourceExtension(name: string): boolean {\n const lower = name.toLowerCase();\n for (const extension of CODE_EXTENSIONS) {\n if (lower.endsWith(extension)) return true;\n }\n return false;\n}\n\nfunction readDirectoryNames(pathValue: string): string[] {\n try {\n return readdirSync(pathValue).slice(0, 200);\n } catch {\n return [];\n }\n}\n\nfunction directoryExists(pathValue: string): boolean {\n try {\n return statSync(pathValue).isDirectory();\n } catch {\n return false;\n }\n}\n\nexport function inferProjectKind(input: {\n name?: string | null;\n description?: string | null;\n workspaceRoot?: string | null;\n projectKind?: string | null;\n}): ProjectKindInference {\n const override = normalizeOverride(input.projectKind);\n if (override === 'coding') return { kind: 'coding', confidence: 1, reasons: ['selected coding project type'] };\n if (override === 'general') return { kind: 'general', confidence: 1, reasons: ['selected general project type'] };\n\n const workspaceRoot = canonicalWorkspacePath(input.workspaceRoot);\n const reasons: string[] = [];\n let score = 0;\n\n if (workspaceRoot && directoryExists(workspaceRoot)) {\n for (const marker of STRONG_CODE_MARKERS) {\n if (existsSync(join(workspaceRoot, marker))) {\n score += 4;\n reasons.push(`found ${marker}`);\n break;\n }\n }\n\n for (const dir of WEAK_CODE_DIRECTORIES) {\n if (directoryExists(join(workspaceRoot, dir))) {\n score += 1;\n reasons.push(`found ${dir}/`);\n break;\n }\n }\n\n if (readDirectoryNames(workspaceRoot).some(hasSourceExtension)) {\n score += 2;\n reasons.push('found source files');\n } else {\n for (const dir of ['src', 'app', 'lib']) {\n const childDir = join(workspaceRoot, dir);\n if (directoryExists(childDir) && readDirectoryNames(childDir).some(hasSourceExtension)) {\n score += 2;\n reasons.push(`found source files in ${dir}/`);\n break;\n }\n }\n }\n }\n\n if (score >= 4) return { kind: 'coding', confidence: 0.9, reasons };\n if (score >= 3) return { kind: 'coding', confidence: 0.75, reasons };\n if (workspaceRoot) return { kind: 'general', confidence: 0.55, reasons };\n return { kind: 'unknown', confidence: 0.25, reasons };\n}\n"],"mappings":";;;;AAcA,MAAM,sBAAsB;CAC1B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD;AAED,MAAM,wBAAwB;CAAC;CAAO;CAAO;CAAO;CAAS;CAAQ;CAAa;CAAU;AAC5F,MAAM,kBAAkB,IAAI,IAAI;CAC9B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACD,CAAC;AAEF,SAAS,kBAAkB,OAAuD;CAChF,MAAM,aAAa,OAAO,MAAM,CAAC,aAAa;AAC9C,QAAO,eAAe,YAAY,eAAe,YAAY,aAAa;;AAG5E,SAAS,mBAAmB,MAAuB;CACjD,MAAM,QAAQ,KAAK,aAAa;AAChC,MAAK,MAAM,aAAa,gBACtB,KAAI,MAAM,SAAS,UAAU,CAAE,QAAO;AAExC,QAAO;;AAGT,SAAS,mBAAmB,WAA6B;AACvD,KAAI;AACF,SAAO,YAAY,UAAU,CAAC,MAAM,GAAG,IAAI;SACrC;AACN,SAAO,EAAE;;;AAIb,SAAS,gBAAgB,WAA4B;AACnD,KAAI;AACF,SAAO,SAAS,UAAU,CAAC,aAAa;SAClC;AACN,SAAO;;;AAIX,SAAgB,iBAAiB,OAKR;CACvB,MAAM,WAAW,kBAAkB,MAAM,YAAY;AACrD,KAAI,aAAa,SAAU,QAAO;EAAE,MAAM;EAAU,YAAY;EAAG,SAAS,CAAC,+BAA+B;EAAE;AAC9G,KAAI,aAAa,UAAW,QAAO;EAAE,MAAM;EAAW,YAAY;EAAG,SAAS,CAAC,gCAAgC;EAAE;CAEjH,MAAM,gBAAgB,uBAAuB,MAAM,cAAc;CACjE,MAAM,UAAoB,EAAE;CAC5B,IAAI,QAAQ;AAEZ,KAAI,iBAAiB,gBAAgB,cAAc,EAAE;AACnD,OAAK,MAAM,UAAU,oBACnB,KAAI,WAAW,KAAK,eAAe,OAAO,CAAC,EAAE;AAC3C,YAAS;AACT,WAAQ,KAAK,SAAS,SAAS;AAC/B;;AAIJ,OAAK,MAAM,OAAO,sBAChB,KAAI,gBAAgB,KAAK,eAAe,IAAI,CAAC,EAAE;AAC7C,YAAS;AACT,WAAQ,KAAK,SAAS,IAAI,GAAG;AAC7B;;AAIJ,MAAI,mBAAmB,cAAc,CAAC,KAAK,mBAAmB,EAAE;AAC9D,YAAS;AACT,WAAQ,KAAK,qBAAqB;QAElC,MAAK,MAAM,OAAO;GAAC;GAAO;GAAO;GAAM,EAAE;GACvC,MAAM,WAAW,KAAK,eAAe,IAAI;AACzC,OAAI,gBAAgB,SAAS,IAAI,mBAAmB,SAAS,CAAC,KAAK,mBAAmB,EAAE;AACtF,aAAS;AACT,YAAQ,KAAK,yBAAyB,IAAI,GAAG;AAC7C;;;;AAMR,KAAI,SAAS,EAAG,QAAO;EAAE,MAAM;EAAU,YAAY;EAAK;EAAS;AACnE,KAAI,SAAS,EAAG,QAAO;EAAE,MAAM;EAAU,YAAY;EAAM;EAAS;AACpE,KAAI,cAAe,QAAO;EAAE,MAAM;EAAW,YAAY;EAAM;EAAS;AACxE,QAAO;EAAE,MAAM;EAAW,YAAY;EAAM;EAAS"}
|
|
@@ -25,6 +25,7 @@ export declare class ProjectService {
|
|
|
25
25
|
resolveOrCreateForWorkspacePath(input: {
|
|
26
26
|
workspacePath: string;
|
|
27
27
|
agentId?: string;
|
|
28
|
+
defaultAgentId?: string;
|
|
28
29
|
autoCreate?: boolean;
|
|
29
30
|
}): WorkspaceProjectMatch | null;
|
|
30
31
|
update(id: string, input: UpdateProjectInput): Project;
|
|
@@ -101,7 +101,7 @@ var ProjectService = class {
|
|
|
101
101
|
project: this.create({
|
|
102
102
|
name: inferProjectNameFromWorkspaceRoot(workspaceRoot) ?? void 0,
|
|
103
103
|
workspaceRoot,
|
|
104
|
-
defaultAgentId: input.agentId
|
|
104
|
+
defaultAgentId: Object.hasOwn(input, "defaultAgentId") ? input.defaultAgentId : input.agentId
|
|
105
105
|
}),
|
|
106
106
|
reason: "auto_created",
|
|
107
107
|
created: true
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-service.js","names":[],"sources":["../../../src/projects/project-service.ts"],"sourcesContent":["import { getSessionMetadata } from '../storage/sqlite/index.js';\nimport { ProjectStore } from './project-store.js';\nimport { bindGoalToProject, listProjectGoalIds, unbindGoalFromProject } from './goal-bind.js';\nimport { bindSessionToProject, listProjectSessionKeys, unbindSessionFromProject } from './session-bind.js';\nimport type { CreateProjectInput, Project, ProjectListQuery, ProjectListResult, ProjectWithDetails, UpdateProjectInput } from './types.js';\nimport {\n canonicalWorkspacePath,\n ensureWorkspaceDirectory,\n inferProjectNameFromWorkspaceRoot,\n isPathSameOrInsideWorkspace,\n isSafeAutoCreateWorkspaceRoot,\n ProjectWorkspaceConflictError,\n ProjectWorkspaceMissingError,\n resolveWorkspaceProjectRoot,\n workspaceDirectoryExists,\n type WorkspaceProjectMatch,\n} from './workspace-project.js';\n\nexport type ProjectSuggestion = {\n projectId: string;\n projectName: string;\n score: number;\n reason: string;\n};\n\nexport class ProjectService {\n constructor(private readonly store = new ProjectStore()) {}\n\n private listAllProjects(): Project[] {\n const items: Project[] = [];\n let offset = 0;\n const limit = 500;\n while (true) {\n const page = this.list({ limit, offset });\n items.push(...page.items);\n if (!page.hasMore || page.items.length === 0) break;\n offset += page.items.length;\n }\n return items;\n }\n\n create(input: CreateProjectInput): Project {\n const rawWorkspaceRoot = input.workspaceRoot?.trim();\n const workspaceRoot = rawWorkspaceRoot ? canonicalWorkspacePath(rawWorkspaceRoot) : undefined;\n if (rawWorkspaceRoot && !workspaceRoot) {\n throw new Error('Invalid workspace root');\n }\n if (workspaceRoot) {\n const existing = this.findByWorkspaceRoot(workspaceRoot);\n if (existing) throw new ProjectWorkspaceConflictError(existing);\n if (!workspaceDirectoryExists(workspaceRoot)) {\n if (input.createWorkspaceRoot === true) {\n ensureWorkspaceDirectory(workspaceRoot);\n } else {\n throw new ProjectWorkspaceMissingError(workspaceRoot);\n }\n }\n }\n const name = input.name?.trim() || inferProjectNameFromWorkspaceRoot(workspaceRoot) || '';\n const slug = input.slug?.trim() || this.store.generateSlug(name);\n return this.store.create({ ...input, name, slug, workspaceRoot });\n }\n\n get(id: string): Project | null {\n return this.store.get(id);\n }\n\n getBySlug(slug: string): Project | null {\n return this.store.findBySlug(slug);\n }\n\n list(query?: ProjectListQuery): ProjectListResult {\n return this.store.list(query);\n }\n\n findByWorkspaceRoot(workspaceRoot: string, options: { excludeProjectId?: string } = {}): Project | null {\n const target = canonicalWorkspacePath(workspaceRoot);\n if (!target) return null;\n for (const project of this.listAllProjects()) {\n if (options.excludeProjectId && project.id === options.excludeProjectId) continue;\n const projectRoot = canonicalWorkspacePath(project.workspaceRoot);\n if (projectRoot && isPathSameOrInsideWorkspace(projectRoot, target) && isPathSameOrInsideWorkspace(target, projectRoot)) {\n return project;\n }\n }\n return null;\n }\n\n resolveForWorkspacePath(workspacePath: string): { project: Project; reason: 'exact' | 'contained' } | null {\n const target = canonicalWorkspacePath(workspacePath);\n if (!target) return null;\n let best: { project: Project; root: string; reason: 'exact' | 'contained' } | null = null;\n for (const project of this.listAllProjects()) {\n const root = canonicalWorkspacePath(project.workspaceRoot);\n if (!root || !isPathSameOrInsideWorkspace(root, target)) continue;\n const reason = isPathSameOrInsideWorkspace(root, target) && isPathSameOrInsideWorkspace(target, root) ? 'exact' : 'contained';\n if (!best || root.length > best.root.length) {\n best = { project, root, reason };\n }\n }\n return best ? { project: best.project, reason: best.reason } : null;\n }\n\n resolveOrCreateForWorkspacePath(input: {\n workspacePath: string;\n agentId?: string;\n autoCreate?: boolean;\n }): WorkspaceProjectMatch | null {\n const existing = this.resolveForWorkspacePath(input.workspacePath);\n if (existing) return { project: existing.project, reason: existing.reason, created: false };\n if (!input.autoCreate) return null;\n const workspaceRoot = resolveWorkspaceProjectRoot(input.workspacePath) ?? canonicalWorkspacePath(input.workspacePath);\n if (!workspaceRoot || !isSafeAutoCreateWorkspaceRoot(workspaceRoot)) return null;\n const rootExisting = this.resolveForWorkspacePath(workspaceRoot);\n if (rootExisting) return { project: rootExisting.project, reason: rootExisting.reason, created: false };\n const project = this.create({\n name: inferProjectNameFromWorkspaceRoot(workspaceRoot) ?? undefined,\n workspaceRoot,\n defaultAgentId: input.agentId,\n });\n return { project, reason: 'auto_created', created: true };\n }\n\n update(id: string, input: UpdateProjectInput): Project {\n const patch = { ...input };\n if (input.workspaceRoot !== undefined && input.workspaceRoot !== null && input.workspaceRoot.trim()) {\n const workspaceRoot = canonicalWorkspacePath(input.workspaceRoot);\n if (!workspaceRoot) {\n throw new Error('Invalid workspace root');\n }\n const existing = this.findByWorkspaceRoot(workspaceRoot, { excludeProjectId: id });\n if (existing) throw new ProjectWorkspaceConflictError(existing);\n if (!workspaceDirectoryExists(workspaceRoot)) {\n if (input.createWorkspaceRoot === true) {\n ensureWorkspaceDirectory(workspaceRoot);\n } else {\n throw new ProjectWorkspaceMissingError(workspaceRoot);\n }\n }\n patch.workspaceRoot = workspaceRoot;\n }\n return this.store.update(id, patch);\n }\n\n delete(id: string): void {\n this.store.delete(id);\n }\n\n getWithDetails(id: string): ProjectWithDetails | null {\n return this.store.getWithDetails(id);\n }\n\n attachSession(sessionKey: string, projectId: string): void {\n bindSessionToProject(sessionKey, projectId);\n }\n\n detachSession(sessionKey: string): void {\n unbindSessionFromProject(sessionKey);\n }\n\n listSessionKeys(projectId: string, limit?: number, offset?: number): string[] {\n return listProjectSessionKeys(projectId, limit, offset);\n }\n\n attachGoal(goalId: string, projectId: string): void {\n bindGoalToProject(goalId, projectId);\n }\n\n detachGoal(goalId: string): void {\n unbindGoalFromProject(goalId);\n }\n\n listGoalIds(projectId: string, limit?: number, offset?: number): string[] {\n return listProjectGoalIds(projectId, limit, offset);\n }\n\n suggestProjectsForSession(sessionKey: string): ProjectSuggestion[] {\n const session = getSessionMetadata(sessionKey);\n if (!session) return [];\n const projects = this.list({ status: 'active', limit: 500 }).items;\n const haystack = [session.key, session.name, session.routing?.agentId, session.sourceChannel, ...(session.tags ?? [])]\n .filter(Boolean)\n .join(' ')\n .toLowerCase();\n const suggestions: ProjectSuggestion[] = [];\n for (const project of projects) {\n let score = 0;\n const reasons: string[] = [];\n if (haystack.includes(project.slug.toLowerCase())) {\n score += 10;\n reasons.push('session metadata matches project slug');\n }\n for (const token of project.name.toLowerCase().split(/\\s+/).filter((t) => t.length >= 3)) {\n if (haystack.includes(token)) {\n score += 3;\n reasons.push(`matches ${token}`);\n break;\n }\n }\n if (score > 0) {\n suggestions.push({ projectId: project.id, projectName: project.name, score, reason: reasons.join(', ') });\n }\n }\n return suggestions.sort((a, b) => b.score - a.score).slice(0, 5);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"project-service.js","names":[],"sources":["../../../src/projects/project-service.ts"],"sourcesContent":["import { getSessionMetadata } from '../storage/sqlite/index.js';\nimport { ProjectStore } from './project-store.js';\nimport { bindGoalToProject, listProjectGoalIds, unbindGoalFromProject } from './goal-bind.js';\nimport { bindSessionToProject, listProjectSessionKeys, unbindSessionFromProject } from './session-bind.js';\nimport type { CreateProjectInput, Project, ProjectListQuery, ProjectListResult, ProjectWithDetails, UpdateProjectInput } from './types.js';\nimport {\n canonicalWorkspacePath,\n ensureWorkspaceDirectory,\n inferProjectNameFromWorkspaceRoot,\n isPathSameOrInsideWorkspace,\n isSafeAutoCreateWorkspaceRoot,\n ProjectWorkspaceConflictError,\n ProjectWorkspaceMissingError,\n resolveWorkspaceProjectRoot,\n workspaceDirectoryExists,\n type WorkspaceProjectMatch,\n} from './workspace-project.js';\n\nexport type ProjectSuggestion = {\n projectId: string;\n projectName: string;\n score: number;\n reason: string;\n};\n\nexport class ProjectService {\n constructor(private readonly store = new ProjectStore()) {}\n\n private listAllProjects(): Project[] {\n const items: Project[] = [];\n let offset = 0;\n const limit = 500;\n while (true) {\n const page = this.list({ limit, offset });\n items.push(...page.items);\n if (!page.hasMore || page.items.length === 0) break;\n offset += page.items.length;\n }\n return items;\n }\n\n create(input: CreateProjectInput): Project {\n const rawWorkspaceRoot = input.workspaceRoot?.trim();\n const workspaceRoot = rawWorkspaceRoot ? canonicalWorkspacePath(rawWorkspaceRoot) : undefined;\n if (rawWorkspaceRoot && !workspaceRoot) {\n throw new Error('Invalid workspace root');\n }\n if (workspaceRoot) {\n const existing = this.findByWorkspaceRoot(workspaceRoot);\n if (existing) throw new ProjectWorkspaceConflictError(existing);\n if (!workspaceDirectoryExists(workspaceRoot)) {\n if (input.createWorkspaceRoot === true) {\n ensureWorkspaceDirectory(workspaceRoot);\n } else {\n throw new ProjectWorkspaceMissingError(workspaceRoot);\n }\n }\n }\n const name = input.name?.trim() || inferProjectNameFromWorkspaceRoot(workspaceRoot) || '';\n const slug = input.slug?.trim() || this.store.generateSlug(name);\n return this.store.create({ ...input, name, slug, workspaceRoot });\n }\n\n get(id: string): Project | null {\n return this.store.get(id);\n }\n\n getBySlug(slug: string): Project | null {\n return this.store.findBySlug(slug);\n }\n\n list(query?: ProjectListQuery): ProjectListResult {\n return this.store.list(query);\n }\n\n findByWorkspaceRoot(workspaceRoot: string, options: { excludeProjectId?: string } = {}): Project | null {\n const target = canonicalWorkspacePath(workspaceRoot);\n if (!target) return null;\n for (const project of this.listAllProjects()) {\n if (options.excludeProjectId && project.id === options.excludeProjectId) continue;\n const projectRoot = canonicalWorkspacePath(project.workspaceRoot);\n if (projectRoot && isPathSameOrInsideWorkspace(projectRoot, target) && isPathSameOrInsideWorkspace(target, projectRoot)) {\n return project;\n }\n }\n return null;\n }\n\n resolveForWorkspacePath(workspacePath: string): { project: Project; reason: 'exact' | 'contained' } | null {\n const target = canonicalWorkspacePath(workspacePath);\n if (!target) return null;\n let best: { project: Project; root: string; reason: 'exact' | 'contained' } | null = null;\n for (const project of this.listAllProjects()) {\n const root = canonicalWorkspacePath(project.workspaceRoot);\n if (!root || !isPathSameOrInsideWorkspace(root, target)) continue;\n const reason = isPathSameOrInsideWorkspace(root, target) && isPathSameOrInsideWorkspace(target, root) ? 'exact' : 'contained';\n if (!best || root.length > best.root.length) {\n best = { project, root, reason };\n }\n }\n return best ? { project: best.project, reason: best.reason } : null;\n }\n\n resolveOrCreateForWorkspacePath(input: {\n workspacePath: string;\n agentId?: string;\n defaultAgentId?: string;\n autoCreate?: boolean;\n }): WorkspaceProjectMatch | null {\n const existing = this.resolveForWorkspacePath(input.workspacePath);\n if (existing) return { project: existing.project, reason: existing.reason, created: false };\n if (!input.autoCreate) return null;\n const workspaceRoot = resolveWorkspaceProjectRoot(input.workspacePath) ?? canonicalWorkspacePath(input.workspacePath);\n if (!workspaceRoot || !isSafeAutoCreateWorkspaceRoot(workspaceRoot)) return null;\n const rootExisting = this.resolveForWorkspacePath(workspaceRoot);\n if (rootExisting) return { project: rootExisting.project, reason: rootExisting.reason, created: false };\n const project = this.create({\n name: inferProjectNameFromWorkspaceRoot(workspaceRoot) ?? undefined,\n workspaceRoot,\n defaultAgentId: Object.hasOwn(input, 'defaultAgentId') ? input.defaultAgentId : input.agentId,\n });\n return { project, reason: 'auto_created', created: true };\n }\n\n update(id: string, input: UpdateProjectInput): Project {\n const patch = { ...input };\n if (input.workspaceRoot !== undefined && input.workspaceRoot !== null && input.workspaceRoot.trim()) {\n const workspaceRoot = canonicalWorkspacePath(input.workspaceRoot);\n if (!workspaceRoot) {\n throw new Error('Invalid workspace root');\n }\n const existing = this.findByWorkspaceRoot(workspaceRoot, { excludeProjectId: id });\n if (existing) throw new ProjectWorkspaceConflictError(existing);\n if (!workspaceDirectoryExists(workspaceRoot)) {\n if (input.createWorkspaceRoot === true) {\n ensureWorkspaceDirectory(workspaceRoot);\n } else {\n throw new ProjectWorkspaceMissingError(workspaceRoot);\n }\n }\n patch.workspaceRoot = workspaceRoot;\n }\n return this.store.update(id, patch);\n }\n\n delete(id: string): void {\n this.store.delete(id);\n }\n\n getWithDetails(id: string): ProjectWithDetails | null {\n return this.store.getWithDetails(id);\n }\n\n attachSession(sessionKey: string, projectId: string): void {\n bindSessionToProject(sessionKey, projectId);\n }\n\n detachSession(sessionKey: string): void {\n unbindSessionFromProject(sessionKey);\n }\n\n listSessionKeys(projectId: string, limit?: number, offset?: number): string[] {\n return listProjectSessionKeys(projectId, limit, offset);\n }\n\n attachGoal(goalId: string, projectId: string): void {\n bindGoalToProject(goalId, projectId);\n }\n\n detachGoal(goalId: string): void {\n unbindGoalFromProject(goalId);\n }\n\n listGoalIds(projectId: string, limit?: number, offset?: number): string[] {\n return listProjectGoalIds(projectId, limit, offset);\n }\n\n suggestProjectsForSession(sessionKey: string): ProjectSuggestion[] {\n const session = getSessionMetadata(sessionKey);\n if (!session) return [];\n const projects = this.list({ status: 'active', limit: 500 }).items;\n const haystack = [session.key, session.name, session.routing?.agentId, session.sourceChannel, ...(session.tags ?? [])]\n .filter(Boolean)\n .join(' ')\n .toLowerCase();\n const suggestions: ProjectSuggestion[] = [];\n for (const project of projects) {\n let score = 0;\n const reasons: string[] = [];\n if (haystack.includes(project.slug.toLowerCase())) {\n score += 10;\n reasons.push('session metadata matches project slug');\n }\n for (const token of project.name.toLowerCase().split(/\\s+/).filter((t) => t.length >= 3)) {\n if (haystack.includes(token)) {\n score += 3;\n reasons.push(`matches ${token}`);\n break;\n }\n }\n if (score > 0) {\n suggestions.push({ projectId: project.id, projectName: project.name, score, reason: reasons.join(', ') });\n }\n }\n return suggestions.sort((a, b) => b.score - a.score).slice(0, 5);\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { getSqliteDatabase, runSqliteWriteTransaction } from "../storage/sqlite/transaction.js";
|
|
2
|
+
import { escapeFts5Query } from "../storage/sqlite/fts.js";
|
|
2
3
|
import { randomUUID } from "node:crypto";
|
|
3
4
|
//#region src/projects/project-store.ts
|
|
4
5
|
function trimOptional(value) {
|
|
@@ -43,6 +44,25 @@ function projectSortColumn(sortBy) {
|
|
|
43
44
|
default: return "updated_at";
|
|
44
45
|
}
|
|
45
46
|
}
|
|
47
|
+
function projectSortExpression(sortBy) {
|
|
48
|
+
const column = projectSortColumn(sortBy);
|
|
49
|
+
return column === "LOWER(name)" ? "LOWER(p.name)" : `p.${column}`;
|
|
50
|
+
}
|
|
51
|
+
function projectFtsContent(project) {
|
|
52
|
+
return [
|
|
53
|
+
project.name,
|
|
54
|
+
project.slug,
|
|
55
|
+
project.description,
|
|
56
|
+
project.workspaceRoot,
|
|
57
|
+
project.brief,
|
|
58
|
+
project.instructions,
|
|
59
|
+
project.defaultAgentId
|
|
60
|
+
].filter((value) => Boolean(value?.trim())).join("\n");
|
|
61
|
+
}
|
|
62
|
+
function syncProjectFts(db, project) {
|
|
63
|
+
db.prepare(`DELETE FROM projects_fts WHERE project_id = ?`).run(project.id);
|
|
64
|
+
db.prepare(`INSERT INTO projects_fts (content, project_id) VALUES (?, ?)`).run(projectFtsContent(project), project.id);
|
|
65
|
+
}
|
|
46
66
|
var ProjectStore = class {
|
|
47
67
|
create(input) {
|
|
48
68
|
const now = Date.now();
|
|
@@ -67,6 +87,7 @@ var ProjectStore = class {
|
|
|
67
87
|
project_id, name, slug, description, status, default_agent_id, workspace_root,
|
|
68
88
|
brief, instructions, created_at, updated_at, last_active_at
|
|
69
89
|
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(project.id, project.name, project.slug, project.description ?? null, project.status, project.defaultAgentId ?? null, project.workspaceRoot ?? null, project.brief ?? null, project.instructions ?? null, project.createdAt, project.updatedAt, project.lastActiveAt ?? null);
|
|
90
|
+
syncProjectFts(db, project);
|
|
70
91
|
});
|
|
71
92
|
return project;
|
|
72
93
|
}
|
|
@@ -81,25 +102,26 @@ var ProjectStore = class {
|
|
|
81
102
|
list(query = {}) {
|
|
82
103
|
const conditions = [];
|
|
83
104
|
const params = [];
|
|
105
|
+
const search = query.search?.trim();
|
|
106
|
+
const ftsQuery = search ? escapeFts5Query(search) : "";
|
|
84
107
|
if (query.status) {
|
|
85
108
|
const statuses = Array.isArray(query.status) ? query.status : [query.status];
|
|
86
|
-
conditions.push(`status IN (${statuses.map(() => "?").join(", ")})`);
|
|
109
|
+
conditions.push(`p.status IN (${statuses.map(() => "?").join(", ")})`);
|
|
87
110
|
params.push(...statuses);
|
|
88
111
|
}
|
|
89
|
-
if (
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
params.push(like, like, like);
|
|
112
|
+
if (ftsQuery) {
|
|
113
|
+
conditions.push(`p.project_id IN (SELECT project_id FROM projects_fts WHERE projects_fts MATCH ?)`);
|
|
114
|
+
params.push(ftsQuery);
|
|
93
115
|
}
|
|
94
116
|
const where = conditions.length ? `WHERE ${conditions.join(" AND ")}` : "";
|
|
95
117
|
const limit = clampLimit(query.limit, 50);
|
|
96
118
|
const offset = Math.max(0, Math.floor(query.offset ?? 0));
|
|
97
119
|
const sortOrder = query.sortOrder === "asc" ? "ASC" : "DESC";
|
|
98
|
-
const sortColumn =
|
|
120
|
+
const sortColumn = projectSortExpression(query.sortBy);
|
|
99
121
|
const db = getSqliteDatabase();
|
|
100
|
-
const total = db.prepare(`SELECT COUNT(*) AS total FROM projects ${where}`).get(...params).total;
|
|
122
|
+
const total = db.prepare(`SELECT COUNT(*) AS total FROM projects p ${where}`).get(...params).total;
|
|
101
123
|
return {
|
|
102
|
-
items: db.prepare(`SELECT
|
|
124
|
+
items: db.prepare(`SELECT p.* FROM projects p ${where} ORDER BY ${sortColumn} ${sortOrder} LIMIT ? OFFSET ?`).all(...params, limit, offset).map(projectFromRow),
|
|
103
125
|
total,
|
|
104
126
|
limit,
|
|
105
127
|
offset,
|
|
@@ -124,6 +146,7 @@ var ProjectStore = class {
|
|
|
124
146
|
db.prepare(`UPDATE projects SET
|
|
125
147
|
name = ?, description = ?, status = ?, default_agent_id = ?, workspace_root = ?, brief = ?, instructions = ?, updated_at = ?
|
|
126
148
|
WHERE project_id = ?`).run(next.name, next.description ?? null, next.status, next.defaultAgentId ?? null, next.workspaceRoot ?? null, next.brief ?? null, next.instructions ?? null, next.updatedAt, id);
|
|
149
|
+
syncProjectFts(db, next);
|
|
127
150
|
});
|
|
128
151
|
return this.get(id);
|
|
129
152
|
}
|
|
@@ -134,6 +157,7 @@ var ProjectStore = class {
|
|
|
134
157
|
db.prepare(`UPDATE workflow_runs SET project_id = NULL WHERE project_id = ?`).run(id);
|
|
135
158
|
db.prepare(`UPDATE automations SET project_id = NULL WHERE project_id = ?`).run(id);
|
|
136
159
|
db.prepare(`UPDATE memory_records SET project_id = NULL WHERE project_id = ?`).run(id);
|
|
160
|
+
db.prepare(`DELETE FROM projects_fts WHERE project_id = ?`).run(id);
|
|
137
161
|
db.prepare(`DELETE FROM projects WHERE project_id = ?`).run(id);
|
|
138
162
|
});
|
|
139
163
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"project-store.js","names":[],"sources":["../../../src/projects/project-store.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport { getSqliteDatabase, runSqliteWriteTransaction } from '../storage/sqlite/transaction.js';\nimport type {\n CreateProjectInput,\n Project,\n ProjectListQuery,\n ProjectListResult,\n ProjectStatus,\n ProjectWithDetails,\n UpdateProjectInput,\n} from './types.js';\n\nexport type ProjectRow = {\n project_id: string;\n name: string;\n slug: string;\n description: string | null;\n status: string;\n default_agent_id: string | null;\n workspace_root: string | null;\n brief: string | null;\n instructions: string | null;\n created_at: number;\n updated_at: number;\n last_active_at: number | null;\n};\n\nfunction trimOptional(value: string | null | undefined): string | undefined {\n if (value == null) return undefined;\n const trimmed = value.trim();\n return trimmed || undefined;\n}\n\nfunction nullableText(value: string | null | undefined): string | null {\n if (value == null) return null;\n const trimmed = value.trim();\n return trimmed || null;\n}\n\nfunction projectFromRow(row: ProjectRow): Project {\n return {\n id: row.project_id,\n name: row.name,\n slug: row.slug,\n description: row.description ?? undefined,\n status: row.status as ProjectStatus,\n defaultAgentId: row.default_agent_id ?? undefined,\n workspaceRoot: row.workspace_root ?? undefined,\n brief: row.brief ?? undefined,\n instructions: row.instructions ?? undefined,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n lastActiveAt: row.last_active_at ?? undefined,\n };\n}\n\nfunction clampLimit(limit: number | undefined, fallback = 50): number {\n return Math.min(500, Math.max(1, Math.floor(limit ?? fallback)));\n}\n\nfunction normalizeName(name: string): string {\n const trimmed = name.trim();\n if (!trimmed) throw new Error('Project name is required');\n return trimmed;\n}\n\nexport function slugifyProjectName(name: string): string {\n const slug = name\n .trim()\n .toLowerCase()\n .normalize('NFKD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .replace(/[^\\p{L}\\p{N}]+/gu, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 80);\n return slug || `project-${Date.now()}`;\n}\n\nfunction projectSortColumn(sortBy: ProjectListQuery['sortBy']): string {\n switch (sortBy) {\n case 'createdAt':\n return 'created_at';\n case 'name':\n return 'LOWER(name)';\n case 'updatedAt':\n default:\n return 'updated_at';\n }\n}\n\nexport class ProjectStore {\n create(input: CreateProjectInput): Project {\n const now = Date.now();\n const name = normalizeName(input.name);\n const slug = input.slug?.trim() || slugifyProjectName(name);\n const project: Project = {\n id: randomUUID(),\n name,\n slug,\n description: trimOptional(input.description),\n status: 'active',\n defaultAgentId: trimOptional(input.defaultAgentId),\n workspaceRoot: trimOptional(input.workspaceRoot),\n brief: trimOptional(input.brief),\n instructions: trimOptional(input.instructions),\n createdAt: now,\n updatedAt: now,\n lastActiveAt: now,\n };\n\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `INSERT INTO projects (\n project_id, name, slug, description, status, default_agent_id, workspace_root,\n brief, instructions, created_at, updated_at, last_active_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n ).run(\n project.id,\n project.name,\n project.slug,\n project.description ?? null,\n project.status,\n project.defaultAgentId ?? null,\n project.workspaceRoot ?? null,\n project.brief ?? null,\n project.instructions ?? null,\n project.createdAt,\n project.updatedAt,\n project.lastActiveAt ?? null,\n );\n });\n return project;\n }\n\n get(id: string): Project | null {\n const row = getSqliteDatabase()\n .prepare(`SELECT * FROM projects WHERE project_id = ?`)\n .get(id) as ProjectRow | undefined;\n return row ? projectFromRow(row) : null;\n }\n\n findBySlug(slug: string): Project | null {\n const row = getSqliteDatabase()\n .prepare(`SELECT * FROM projects WHERE slug = ?`)\n .get(slug.trim()) as ProjectRow | undefined;\n return row ? projectFromRow(row) : null;\n }\n\n list(query: ProjectListQuery = {}): ProjectListResult {\n const conditions: string[] = [];\n const params: Array<string | number> = [];\n if (query.status) {\n const statuses = Array.isArray(query.status) ? query.status : [query.status];\n conditions.push(`status IN (${statuses.map(() => '?').join(', ')})`);\n params.push(...statuses);\n }\n if (query.search?.trim()) {\n const like = `%${query.search.trim().toLowerCase()}%`;\n conditions.push(`(LOWER(name) LIKE ? OR LOWER(slug) LIKE ? OR LOWER(COALESCE(description, '')) LIKE ?)`);\n params.push(like, like, like);\n }\n const where = conditions.length ? `WHERE ${conditions.join(' AND ')}` : '';\n const limit = clampLimit(query.limit, 50);\n const offset = Math.max(0, Math.floor(query.offset ?? 0));\n const sortOrder = query.sortOrder === 'asc' ? 'ASC' : 'DESC';\n const sortColumn = projectSortColumn(query.sortBy);\n const db = getSqliteDatabase();\n const total = (db.prepare(`SELECT COUNT(*) AS total FROM projects ${where}`).get(...params) as { total: number }).total;\n const rows = db\n .prepare(`SELECT * FROM projects ${where} ORDER BY ${sortColumn} ${sortOrder} LIMIT ? OFFSET ?`)\n .all(...params, limit, offset) as ProjectRow[];\n return { items: rows.map(projectFromRow), total, limit, offset, hasMore: offset + limit < total };\n }\n\n update(id: string, input: UpdateProjectInput): Project {\n const before = this.get(id);\n if (!before) throw new Error(`Project not found: ${id}`);\n const next = {\n ...before,\n ...(input.name !== undefined ? { name: normalizeName(input.name) } : {}),\n ...(input.description !== undefined ? { description: nullableText(input.description) ?? undefined } : {}),\n ...(input.status !== undefined ? { status: input.status } : {}),\n ...(input.defaultAgentId !== undefined ? { defaultAgentId: nullableText(input.defaultAgentId) ?? undefined } : {}),\n ...(input.workspaceRoot !== undefined ? { workspaceRoot: nullableText(input.workspaceRoot) ?? undefined } : {}),\n ...(input.brief !== undefined ? { brief: nullableText(input.brief) ?? undefined } : {}),\n ...(input.instructions !== undefined ? { instructions: nullableText(input.instructions) ?? undefined } : {}),\n updatedAt: Date.now(),\n } satisfies Project;\n\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `UPDATE projects SET\n name = ?, description = ?, status = ?, default_agent_id = ?, workspace_root = ?, brief = ?, instructions = ?, updated_at = ?\n WHERE project_id = ?`,\n ).run(\n next.name,\n next.description ?? null,\n next.status,\n next.defaultAgentId ?? null,\n next.workspaceRoot ?? null,\n next.brief ?? null,\n next.instructions ?? null,\n next.updatedAt,\n id,\n );\n });\n return this.get(id)!;\n }\n\n delete(id: string): void {\n runSqliteWriteTransaction((db) => {\n db.prepare(`UPDATE sessions SET project_id = NULL WHERE project_id = ?`).run(id);\n db.prepare(`UPDATE goals SET project_id = NULL WHERE project_id = ?`).run(id);\n db.prepare(`UPDATE workflow_runs SET project_id = NULL WHERE project_id = ?`).run(id);\n db.prepare(`UPDATE automations SET project_id = NULL WHERE project_id = ?`).run(id);\n db.prepare(`UPDATE memory_records SET project_id = NULL WHERE project_id = ?`).run(id);\n db.prepare(`DELETE FROM projects WHERE project_id = ?`).run(id);\n });\n }\n\n getSessionCount(id: string): number {\n return (getSqliteDatabase()\n .prepare(`SELECT COUNT(*) AS total FROM sessions WHERE project_id = ? AND hidden_from_session_list = 0`)\n .get(id) as { total: number }).total;\n }\n\n getGoalCount(id: string): number {\n return (getSqliteDatabase().prepare(`SELECT COUNT(*) AS total FROM goals WHERE project_id = ?`).get(id) as { total: number }).total;\n }\n\n getActiveGoalCount(id: string): number {\n return (getSqliteDatabase()\n .prepare(`SELECT COUNT(*) AS total FROM goals WHERE project_id = ? AND status IN ('active', 'paused', 'blocked', 'needs_input')`)\n .get(id) as { total: number }).total;\n }\n\n getRecentSessions(id: string, limit = 5): ProjectWithDetails['recentSessions'] {\n const rows = getSqliteDatabase()\n .prepare(\n `SELECT session_key, name, updated_at, agent_id FROM sessions\n WHERE project_id = ? AND hidden_from_session_list = 0 ORDER BY updated_at DESC LIMIT ?`,\n )\n .all(id, clampLimit(limit, 5)) as Array<{ session_key: string; name: string | null; updated_at: number; agent_id: string }>;\n return rows.map((row) => ({\n key: row.session_key,\n name: row.name ?? undefined,\n updatedAt: new Date(row.updated_at).toISOString(),\n agentId: row.agent_id,\n }));\n }\n\n getRecentWorkflowRuns(id: string, limit = 5): ProjectWithDetails['recentWorkflowRuns'] {\n const rows = getSqliteDatabase()\n .prepare(\n `SELECT run_id, definition_id, status, created_at_ms FROM workflow_runs\n WHERE project_id = ? ORDER BY created_at_ms DESC LIMIT ?`,\n )\n .all(id, clampLimit(limit, 5)) as Array<{ run_id: string; definition_id: string; status: string; created_at_ms: number }>;\n return rows.map((row) => ({ runId: row.run_id, definitionId: row.definition_id, status: row.status, createdAt: row.created_at_ms }));\n }\n\n getWithDetails(id: string): ProjectWithDetails | null {\n const project = this.get(id);\n if (!project) return null;\n return {\n ...project,\n sessionCount: this.getSessionCount(id),\n goalCount: this.getGoalCount(id),\n activeGoalCount: this.getActiveGoalCount(id),\n recentSessions: this.getRecentSessions(id),\n recentWorkflowRuns: this.getRecentWorkflowRuns(id),\n };\n }\n\n generateSlug(name: string): string {\n const base = slugifyProjectName(name);\n let candidate = base;\n let counter = 2;\n while (this.findBySlug(candidate)) {\n candidate = `${base}-${counter}`;\n counter += 1;\n }\n return candidate;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"project-store.js","names":[],"sources":["../../../src/projects/project-store.ts"],"sourcesContent":["import { randomUUID } from 'node:crypto';\n\nimport { escapeFts5Query } from '../storage/sqlite/fts.js';\nimport { getSqliteDatabase, runSqliteWriteTransaction } from '../storage/sqlite/transaction.js';\nimport type {\n CreateProjectInput,\n Project,\n ProjectListQuery,\n ProjectListResult,\n ProjectStatus,\n ProjectWithDetails,\n UpdateProjectInput,\n} from './types.js';\n\nexport type ProjectRow = {\n project_id: string;\n name: string;\n slug: string;\n description: string | null;\n status: string;\n default_agent_id: string | null;\n workspace_root: string | null;\n brief: string | null;\n instructions: string | null;\n created_at: number;\n updated_at: number;\n last_active_at: number | null;\n};\n\nfunction trimOptional(value: string | null | undefined): string | undefined {\n if (value == null) return undefined;\n const trimmed = value.trim();\n return trimmed || undefined;\n}\n\nfunction nullableText(value: string | null | undefined): string | null {\n if (value == null) return null;\n const trimmed = value.trim();\n return trimmed || null;\n}\n\nfunction projectFromRow(row: ProjectRow): Project {\n return {\n id: row.project_id,\n name: row.name,\n slug: row.slug,\n description: row.description ?? undefined,\n status: row.status as ProjectStatus,\n defaultAgentId: row.default_agent_id ?? undefined,\n workspaceRoot: row.workspace_root ?? undefined,\n brief: row.brief ?? undefined,\n instructions: row.instructions ?? undefined,\n createdAt: row.created_at,\n updatedAt: row.updated_at,\n lastActiveAt: row.last_active_at ?? undefined,\n };\n}\n\nfunction clampLimit(limit: number | undefined, fallback = 50): number {\n return Math.min(500, Math.max(1, Math.floor(limit ?? fallback)));\n}\n\nfunction normalizeName(name: string): string {\n const trimmed = name.trim();\n if (!trimmed) throw new Error('Project name is required');\n return trimmed;\n}\n\nexport function slugifyProjectName(name: string): string {\n const slug = name\n .trim()\n .toLowerCase()\n .normalize('NFKD')\n .replace(/[\\u0300-\\u036f]/g, '')\n .replace(/[^\\p{L}\\p{N}]+/gu, '-')\n .replace(/^-+|-+$/g, '')\n .slice(0, 80);\n return slug || `project-${Date.now()}`;\n}\n\nfunction projectSortColumn(sortBy: ProjectListQuery['sortBy']): string {\n switch (sortBy) {\n case 'createdAt':\n return 'created_at';\n case 'name':\n return 'LOWER(name)';\n case 'updatedAt':\n default:\n return 'updated_at';\n }\n}\n\nfunction projectSortExpression(sortBy: ProjectListQuery['sortBy']): string {\n const column = projectSortColumn(sortBy);\n return column === 'LOWER(name)' ? 'LOWER(p.name)' : `p.${column}`;\n}\n\nfunction projectFtsContent(project: Project): string {\n return [\n project.name,\n project.slug,\n project.description,\n project.workspaceRoot,\n project.brief,\n project.instructions,\n project.defaultAgentId,\n ]\n .filter((value): value is string => Boolean(value?.trim()))\n .join('\\n');\n}\n\nfunction syncProjectFts(\n db: ReturnType<typeof getSqliteDatabase>,\n project: Project,\n): void {\n db.prepare(`DELETE FROM projects_fts WHERE project_id = ?`).run(project.id);\n db.prepare(`INSERT INTO projects_fts (content, project_id) VALUES (?, ?)`).run(\n projectFtsContent(project),\n project.id,\n );\n}\n\nexport class ProjectStore {\n create(input: CreateProjectInput): Project {\n const now = Date.now();\n const name = normalizeName(input.name);\n const slug = input.slug?.trim() || slugifyProjectName(name);\n const project: Project = {\n id: randomUUID(),\n name,\n slug,\n description: trimOptional(input.description),\n status: 'active',\n defaultAgentId: trimOptional(input.defaultAgentId),\n workspaceRoot: trimOptional(input.workspaceRoot),\n brief: trimOptional(input.brief),\n instructions: trimOptional(input.instructions),\n createdAt: now,\n updatedAt: now,\n lastActiveAt: now,\n };\n\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `INSERT INTO projects (\n project_id, name, slug, description, status, default_agent_id, workspace_root,\n brief, instructions, created_at, updated_at, last_active_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`,\n ).run(\n project.id,\n project.name,\n project.slug,\n project.description ?? null,\n project.status,\n project.defaultAgentId ?? null,\n project.workspaceRoot ?? null,\n project.brief ?? null,\n project.instructions ?? null,\n project.createdAt,\n project.updatedAt,\n project.lastActiveAt ?? null,\n );\n syncProjectFts(db, project);\n });\n return project;\n }\n\n get(id: string): Project | null {\n const row = getSqliteDatabase()\n .prepare(`SELECT * FROM projects WHERE project_id = ?`)\n .get(id) as ProjectRow | undefined;\n return row ? projectFromRow(row) : null;\n }\n\n findBySlug(slug: string): Project | null {\n const row = getSqliteDatabase()\n .prepare(`SELECT * FROM projects WHERE slug = ?`)\n .get(slug.trim()) as ProjectRow | undefined;\n return row ? projectFromRow(row) : null;\n }\n\n list(query: ProjectListQuery = {}): ProjectListResult {\n const conditions: string[] = [];\n const params: Array<string | number> = [];\n const search = query.search?.trim();\n const ftsQuery = search ? escapeFts5Query(search) : '';\n if (query.status) {\n const statuses = Array.isArray(query.status) ? query.status : [query.status];\n conditions.push(`p.status IN (${statuses.map(() => '?').join(', ')})`);\n params.push(...statuses);\n }\n if (ftsQuery) {\n conditions.push(`p.project_id IN (SELECT project_id FROM projects_fts WHERE projects_fts MATCH ?)`);\n params.push(ftsQuery);\n }\n const where = conditions.length ? `WHERE ${conditions.join(' AND ')}` : '';\n const limit = clampLimit(query.limit, 50);\n const offset = Math.max(0, Math.floor(query.offset ?? 0));\n const sortOrder = query.sortOrder === 'asc' ? 'ASC' : 'DESC';\n const sortColumn = projectSortExpression(query.sortBy);\n const db = getSqliteDatabase();\n const total = (db.prepare(`SELECT COUNT(*) AS total FROM projects p ${where}`).get(...params) as { total: number }).total;\n const rows = db\n .prepare(`SELECT p.* FROM projects p ${where} ORDER BY ${sortColumn} ${sortOrder} LIMIT ? OFFSET ?`)\n .all(...params, limit, offset) as ProjectRow[];\n return { items: rows.map(projectFromRow), total, limit, offset, hasMore: offset + limit < total };\n }\n\n update(id: string, input: UpdateProjectInput): Project {\n const before = this.get(id);\n if (!before) throw new Error(`Project not found: ${id}`);\n const next = {\n ...before,\n ...(input.name !== undefined ? { name: normalizeName(input.name) } : {}),\n ...(input.description !== undefined ? { description: nullableText(input.description) ?? undefined } : {}),\n ...(input.status !== undefined ? { status: input.status } : {}),\n ...(input.defaultAgentId !== undefined ? { defaultAgentId: nullableText(input.defaultAgentId) ?? undefined } : {}),\n ...(input.workspaceRoot !== undefined ? { workspaceRoot: nullableText(input.workspaceRoot) ?? undefined } : {}),\n ...(input.brief !== undefined ? { brief: nullableText(input.brief) ?? undefined } : {}),\n ...(input.instructions !== undefined ? { instructions: nullableText(input.instructions) ?? undefined } : {}),\n updatedAt: Date.now(),\n } satisfies Project;\n\n runSqliteWriteTransaction((db) => {\n db.prepare(\n `UPDATE projects SET\n name = ?, description = ?, status = ?, default_agent_id = ?, workspace_root = ?, brief = ?, instructions = ?, updated_at = ?\n WHERE project_id = ?`,\n ).run(\n next.name,\n next.description ?? null,\n next.status,\n next.defaultAgentId ?? null,\n next.workspaceRoot ?? null,\n next.brief ?? null,\n next.instructions ?? null,\n next.updatedAt,\n id,\n );\n syncProjectFts(db, next);\n });\n return this.get(id)!;\n }\n\n delete(id: string): void {\n runSqliteWriteTransaction((db) => {\n db.prepare(`UPDATE sessions SET project_id = NULL WHERE project_id = ?`).run(id);\n db.prepare(`UPDATE goals SET project_id = NULL WHERE project_id = ?`).run(id);\n db.prepare(`UPDATE workflow_runs SET project_id = NULL WHERE project_id = ?`).run(id);\n db.prepare(`UPDATE automations SET project_id = NULL WHERE project_id = ?`).run(id);\n db.prepare(`UPDATE memory_records SET project_id = NULL WHERE project_id = ?`).run(id);\n db.prepare(`DELETE FROM projects_fts WHERE project_id = ?`).run(id);\n db.prepare(`DELETE FROM projects WHERE project_id = ?`).run(id);\n });\n }\n\n getSessionCount(id: string): number {\n return (getSqliteDatabase()\n .prepare(`SELECT COUNT(*) AS total FROM sessions WHERE project_id = ? AND hidden_from_session_list = 0`)\n .get(id) as { total: number }).total;\n }\n\n getGoalCount(id: string): number {\n return (getSqliteDatabase().prepare(`SELECT COUNT(*) AS total FROM goals WHERE project_id = ?`).get(id) as { total: number }).total;\n }\n\n getActiveGoalCount(id: string): number {\n return (getSqliteDatabase()\n .prepare(`SELECT COUNT(*) AS total FROM goals WHERE project_id = ? AND status IN ('active', 'paused', 'blocked', 'needs_input')`)\n .get(id) as { total: number }).total;\n }\n\n getRecentSessions(id: string, limit = 5): ProjectWithDetails['recentSessions'] {\n const rows = getSqliteDatabase()\n .prepare(\n `SELECT session_key, name, updated_at, agent_id FROM sessions\n WHERE project_id = ? AND hidden_from_session_list = 0 ORDER BY updated_at DESC LIMIT ?`,\n )\n .all(id, clampLimit(limit, 5)) as Array<{ session_key: string; name: string | null; updated_at: number; agent_id: string }>;\n return rows.map((row) => ({\n key: row.session_key,\n name: row.name ?? undefined,\n updatedAt: new Date(row.updated_at).toISOString(),\n agentId: row.agent_id,\n }));\n }\n\n getRecentWorkflowRuns(id: string, limit = 5): ProjectWithDetails['recentWorkflowRuns'] {\n const rows = getSqliteDatabase()\n .prepare(\n `SELECT run_id, definition_id, status, created_at_ms FROM workflow_runs\n WHERE project_id = ? ORDER BY created_at_ms DESC LIMIT ?`,\n )\n .all(id, clampLimit(limit, 5)) as Array<{ run_id: string; definition_id: string; status: string; created_at_ms: number }>;\n return rows.map((row) => ({ runId: row.run_id, definitionId: row.definition_id, status: row.status, createdAt: row.created_at_ms }));\n }\n\n getWithDetails(id: string): ProjectWithDetails | null {\n const project = this.get(id);\n if (!project) return null;\n return {\n ...project,\n sessionCount: this.getSessionCount(id),\n goalCount: this.getGoalCount(id),\n activeGoalCount: this.getActiveGoalCount(id),\n recentSessions: this.getRecentSessions(id),\n recentWorkflowRuns: this.getRecentWorkflowRuns(id),\n };\n }\n\n generateSlug(name: string): string {\n const base = slugifyProjectName(name);\n let candidate = base;\n let counter = 2;\n while (this.findBySlug(candidate)) {\n candidate = `${base}-${counter}`;\n counter += 1;\n }\n return candidate;\n }\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
export type ReviewTarget = {
|
|
2
|
+
kind: 'uncommitted';
|
|
3
|
+
instructions?: string;
|
|
4
|
+
} | {
|
|
5
|
+
kind: 'base_branch';
|
|
6
|
+
baseBranch: string;
|
|
7
|
+
instructions?: string;
|
|
8
|
+
} | {
|
|
9
|
+
kind: 'commit';
|
|
10
|
+
sha: string;
|
|
11
|
+
title?: string;
|
|
12
|
+
instructions?: string;
|
|
13
|
+
};
|
|
14
|
+
export interface ReviewDiffBundle {
|
|
15
|
+
cwd: string;
|
|
16
|
+
target: ReviewTarget;
|
|
17
|
+
targetLabel: string;
|
|
18
|
+
status: string;
|
|
19
|
+
stat: string;
|
|
20
|
+
diff: string;
|
|
21
|
+
}
|
|
22
|
+
export interface ReviewContextBranch {
|
|
23
|
+
name: string;
|
|
24
|
+
current?: boolean;
|
|
25
|
+
remote?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface ReviewContextCommit {
|
|
28
|
+
sha: string;
|
|
29
|
+
shortSha: string;
|
|
30
|
+
subject: string;
|
|
31
|
+
date?: string;
|
|
32
|
+
}
|
|
33
|
+
export interface ReviewContext {
|
|
34
|
+
cwd: string;
|
|
35
|
+
defaultBaseBranch?: string;
|
|
36
|
+
status: {
|
|
37
|
+
changedFiles: number;
|
|
38
|
+
untrackedFiles: number;
|
|
39
|
+
isClean: boolean;
|
|
40
|
+
};
|
|
41
|
+
branches: ReviewContextBranch[];
|
|
42
|
+
commits: ReviewContextCommit[];
|
|
43
|
+
}
|
|
44
|
+
export declare function git(args: string[], cwd: string): Promise<string>;
|
|
45
|
+
export declare function resolveGitRoot(workspace: string): Promise<string>;
|
|
46
|
+
export declare function parseReviewTargetArgs(args: string): ReviewTarget;
|
|
47
|
+
export declare function buildReviewDiffBundle(cwd: string, target: ReviewTarget): Promise<ReviewDiffBundle>;
|
|
48
|
+
export declare function buildReviewContext(cwd: string): Promise<ReviewContext>;
|