@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
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { init_paths_state, resolveStateDir } from "../config/paths-state.js";
|
|
2
|
+
import { init_workspace_path, normalizeWorkspaceDir } from "../config/workspace-path.js";
|
|
3
|
+
import { init_agent_scope, resolveUserPath } from "../agent/agent-scope.js";
|
|
4
|
+
import { homedir, tmpdir } from "node:os";
|
|
5
|
+
import { basename, dirname, isAbsolute, join, parse, relative, resolve } from "node:path";
|
|
6
|
+
import { existsSync, mkdirSync, realpathSync, statSync } from "node:fs";
|
|
7
|
+
import { execFileSync } from "node:child_process";
|
|
8
|
+
//#region src/projects/workspace-project.ts
|
|
9
|
+
init_agent_scope();
|
|
10
|
+
init_workspace_path();
|
|
11
|
+
init_paths_state();
|
|
12
|
+
var ProjectWorkspaceConflictError = class extends Error {
|
|
13
|
+
constructor(project, message = `Workspace is already bound to project: ${project.name}`) {
|
|
14
|
+
super(message);
|
|
15
|
+
this.project = project;
|
|
16
|
+
this.name = "ProjectWorkspaceConflictError";
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
var ProjectWorkspaceMissingError = class extends Error {
|
|
20
|
+
constructor(workspaceRoot, message = `Workspace root does not exist: ${workspaceRoot}`) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.workspaceRoot = workspaceRoot;
|
|
23
|
+
this.name = "ProjectWorkspaceMissingError";
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
const PROJECT_ROOT_MARKERS = [
|
|
27
|
+
".git",
|
|
28
|
+
"pnpm-workspace.yaml",
|
|
29
|
+
"package.json",
|
|
30
|
+
"go.mod",
|
|
31
|
+
"pyproject.toml",
|
|
32
|
+
"Cargo.toml",
|
|
33
|
+
"deno.json",
|
|
34
|
+
"deno.jsonc",
|
|
35
|
+
"bun.lockb",
|
|
36
|
+
"pnpm-lock.yaml",
|
|
37
|
+
"yarn.lock",
|
|
38
|
+
"package-lock.json",
|
|
39
|
+
"composer.json",
|
|
40
|
+
"Gemfile"
|
|
41
|
+
];
|
|
42
|
+
function canonicalWorkspacePath(raw) {
|
|
43
|
+
const trimmed = raw?.trim();
|
|
44
|
+
if (!trimmed) return null;
|
|
45
|
+
const normalized = normalizeWorkspaceDir(resolveUserPath(trimmed));
|
|
46
|
+
if (!normalized) return null;
|
|
47
|
+
try {
|
|
48
|
+
if (!statSync(normalized).isDirectory()) return normalized;
|
|
49
|
+
return realpathSync.native(normalized);
|
|
50
|
+
} catch {
|
|
51
|
+
return normalized;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
function workspaceDirectoryExists(workspaceRoot) {
|
|
55
|
+
const canonical = canonicalWorkspacePath(workspaceRoot);
|
|
56
|
+
if (!canonical) return false;
|
|
57
|
+
try {
|
|
58
|
+
return statSync(canonical).isDirectory();
|
|
59
|
+
} catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
function ensureWorkspaceDirectory(workspaceRoot) {
|
|
64
|
+
mkdirSync(workspaceRoot, { recursive: true });
|
|
65
|
+
}
|
|
66
|
+
function directoryForWorkspaceProbe(pathValue) {
|
|
67
|
+
try {
|
|
68
|
+
return statSync(pathValue).isDirectory() ? pathValue : dirname(pathValue);
|
|
69
|
+
} catch {
|
|
70
|
+
return pathValue;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
function findGitRoot(startDir) {
|
|
74
|
+
try {
|
|
75
|
+
return canonicalWorkspacePath(execFileSync("git", [
|
|
76
|
+
"-C",
|
|
77
|
+
startDir,
|
|
78
|
+
"rev-parse",
|
|
79
|
+
"--show-toplevel"
|
|
80
|
+
], {
|
|
81
|
+
encoding: "utf8",
|
|
82
|
+
stdio: [
|
|
83
|
+
"ignore",
|
|
84
|
+
"pipe",
|
|
85
|
+
"ignore"
|
|
86
|
+
],
|
|
87
|
+
timeout: 1e3
|
|
88
|
+
}).trim());
|
|
89
|
+
} catch {
|
|
90
|
+
return null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function findMarkerRoot(startDir) {
|
|
94
|
+
let current = startDir;
|
|
95
|
+
while (true) {
|
|
96
|
+
if (PROJECT_ROOT_MARKERS.some((marker) => existsSync(join(current, marker)))) return current;
|
|
97
|
+
const parent = dirname(current);
|
|
98
|
+
if (parent === current) return null;
|
|
99
|
+
current = parent;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function resolveWorkspaceProjectRoot(raw) {
|
|
103
|
+
const canonical = canonicalWorkspacePath(raw);
|
|
104
|
+
if (!canonical) return null;
|
|
105
|
+
const startDir = directoryForWorkspaceProbe(canonical);
|
|
106
|
+
const gitRoot = findGitRoot(startDir);
|
|
107
|
+
if (gitRoot) return gitRoot;
|
|
108
|
+
return canonicalWorkspacePath(findMarkerRoot(startDir)) ?? canonical;
|
|
109
|
+
}
|
|
110
|
+
function normalizeComparablePath(pathValue) {
|
|
111
|
+
const resolved = resolve(pathValue);
|
|
112
|
+
return process.platform === "win32" ? resolved.toLowerCase() : resolved;
|
|
113
|
+
}
|
|
114
|
+
function isPathSameOrInsideWorkspace(workspaceRoot, candidatePath) {
|
|
115
|
+
const rel = relative(normalizeComparablePath(workspaceRoot), normalizeComparablePath(candidatePath));
|
|
116
|
+
return rel === "" || !!rel && !rel.startsWith("..") && !isAbsolute(rel);
|
|
117
|
+
}
|
|
118
|
+
function inferProjectNameFromWorkspaceRoot(workspaceRoot) {
|
|
119
|
+
const canonical = canonicalWorkspacePath(workspaceRoot);
|
|
120
|
+
if (!canonical) return null;
|
|
121
|
+
return basename(canonical).trim() || null;
|
|
122
|
+
}
|
|
123
|
+
function isSafeAutoCreateWorkspaceRoot(workspaceRoot) {
|
|
124
|
+
const canonical = canonicalWorkspacePath(workspaceRoot);
|
|
125
|
+
if (!canonical) return false;
|
|
126
|
+
const normalized = normalizeComparablePath(canonical);
|
|
127
|
+
if ([
|
|
128
|
+
homedir(),
|
|
129
|
+
tmpdir(),
|
|
130
|
+
resolveStateDir()
|
|
131
|
+
].map((p) => canonicalWorkspacePath(p)).filter((p) => Boolean(p)).map(normalizeComparablePath).includes(normalized)) return false;
|
|
132
|
+
if (normalizeComparablePath(canonical) === normalizeComparablePath(parse(canonical).root)) return false;
|
|
133
|
+
if (!basename(canonical).trim()) return false;
|
|
134
|
+
try {
|
|
135
|
+
return statSync(canonical).isDirectory();
|
|
136
|
+
} catch {
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
//#endregion
|
|
141
|
+
export { ProjectWorkspaceConflictError, ProjectWorkspaceMissingError, canonicalWorkspacePath, ensureWorkspaceDirectory, inferProjectNameFromWorkspaceRoot, isPathSameOrInsideWorkspace, isSafeAutoCreateWorkspaceRoot, resolveWorkspaceProjectRoot, workspaceDirectoryExists };
|
|
142
|
+
|
|
143
|
+
//# sourceMappingURL=workspace-project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace-project.js","names":[],"sources":["../../../src/projects/workspace-project.ts"],"sourcesContent":["import { existsSync, mkdirSync, realpathSync, statSync } from 'node:fs';\nimport { execFileSync } from 'node:child_process';\nimport { homedir, tmpdir } from 'node:os';\nimport { basename, dirname, isAbsolute, join, parse, relative, resolve } from 'node:path';\n\nimport { resolveUserPath } from '../agent/agent-scope.js';\nimport { normalizeWorkspaceDir } from '../config/workspace-path.js';\nimport { resolveStateDir } from '../config/paths-state.js';\nimport type { Project } from './types.js';\n\nexport type WorkspaceProjectMatchReason = 'exact' | 'contained' | 'auto_created';\n\nexport type WorkspaceProjectMatch = {\n project: Project;\n reason: WorkspaceProjectMatchReason;\n created: boolean;\n};\n\nexport class ProjectWorkspaceConflictError extends Error {\n constructor(readonly project: Project, message = `Workspace is already bound to project: ${project.name}`) {\n super(message);\n this.name = 'ProjectWorkspaceConflictError';\n }\n}\n\nexport class ProjectWorkspaceMissingError extends Error {\n constructor(readonly workspaceRoot: string, message = `Workspace root does not exist: ${workspaceRoot}`) {\n super(message);\n this.name = 'ProjectWorkspaceMissingError';\n }\n}\n\nconst PROJECT_ROOT_MARKERS = [\n '.git',\n 'pnpm-workspace.yaml',\n 'package.json',\n 'go.mod',\n 'pyproject.toml',\n 'Cargo.toml',\n 'deno.json',\n 'deno.jsonc',\n 'bun.lockb',\n 'pnpm-lock.yaml',\n 'yarn.lock',\n 'package-lock.json',\n 'composer.json',\n 'Gemfile',\n] as const;\n\nexport function canonicalWorkspacePath(raw: string | null | undefined): string | null {\n const trimmed = raw?.trim();\n if (!trimmed) return null;\n const resolved = resolveUserPath(trimmed);\n const normalized = normalizeWorkspaceDir(resolved);\n if (!normalized) return null;\n try {\n const stat = statSync(normalized);\n if (!stat.isDirectory()) return normalized;\n return realpathSync.native(normalized);\n } catch {\n return normalized;\n }\n}\n\nexport function workspaceDirectoryExists(workspaceRoot: string | null | undefined): boolean {\n const canonical = canonicalWorkspacePath(workspaceRoot);\n if (!canonical) return false;\n try {\n return statSync(canonical).isDirectory();\n } catch {\n return false;\n }\n}\n\nexport function ensureWorkspaceDirectory(workspaceRoot: string): void {\n mkdirSync(workspaceRoot, { recursive: true });\n}\n\nfunction directoryForWorkspaceProbe(pathValue: string): string {\n try {\n return statSync(pathValue).isDirectory() ? pathValue : dirname(pathValue);\n } catch {\n return pathValue;\n }\n}\n\nfunction findGitRoot(startDir: string): string | null {\n try {\n const output = execFileSync('git', ['-C', startDir, 'rev-parse', '--show-toplevel'], {\n encoding: 'utf8',\n stdio: ['ignore', 'pipe', 'ignore'],\n timeout: 1000,\n }).trim();\n return canonicalWorkspacePath(output);\n } catch {\n return null;\n }\n}\n\nfunction findMarkerRoot(startDir: string): string | null {\n let current = startDir;\n while (true) {\n if (PROJECT_ROOT_MARKERS.some((marker) => existsSync(join(current, marker)))) {\n return current;\n }\n const parent = dirname(current);\n if (parent === current) {\n return null;\n }\n current = parent;\n }\n}\n\nexport function resolveWorkspaceProjectRoot(raw: string | null | undefined): string | null {\n const canonical = canonicalWorkspacePath(raw);\n if (!canonical) return null;\n const startDir = directoryForWorkspaceProbe(canonical);\n const gitRoot = findGitRoot(startDir);\n if (gitRoot) return gitRoot;\n const markerRoot = findMarkerRoot(startDir);\n return canonicalWorkspacePath(markerRoot) ?? canonical;\n}\n\nfunction normalizeComparablePath(pathValue: string): string {\n const resolved = resolve(pathValue);\n return process.platform === 'win32' ? resolved.toLowerCase() : resolved;\n}\n\nexport function isPathSameOrInsideWorkspace(workspaceRoot: string, candidatePath: string): boolean {\n const root = normalizeComparablePath(workspaceRoot);\n const candidate = normalizeComparablePath(candidatePath);\n const rel = relative(root, candidate);\n return rel === '' || (!!rel && !rel.startsWith('..') && !isAbsolute(rel));\n}\n\nexport function inferProjectNameFromWorkspaceRoot(workspaceRoot: string | null | undefined): string | null {\n const canonical = canonicalWorkspacePath(workspaceRoot);\n if (!canonical) return null;\n const name = basename(canonical).trim();\n return name || null;\n}\n\nexport function isSafeAutoCreateWorkspaceRoot(workspaceRoot: string | null | undefined): boolean {\n const canonical = canonicalWorkspacePath(workspaceRoot);\n if (!canonical) return false;\n const normalized = normalizeComparablePath(canonical);\n const forbidden = [homedir(), tmpdir(), resolveStateDir()]\n .map((p) => canonicalWorkspacePath(p))\n .filter((p): p is string => Boolean(p))\n .map(normalizeComparablePath);\n if (forbidden.includes(normalized)) return false;\n // `normalizeWorkspaceDir` already rejects filesystem roots; keep this function\n // conservative for callers that pass unusual platform-specific roots.\n if (normalizeComparablePath(canonical) === normalizeComparablePath(parse(canonical).root)) return false;\n if (!basename(canonical).trim()) return false;\n try {\n return statSync(canonical).isDirectory();\n } catch {\n return false;\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>;
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
//#region src/review/review-git.ts
|
|
4
|
+
const execFileAsync = promisify(execFile);
|
|
5
|
+
async function git(args, cwd) {
|
|
6
|
+
const { stdout } = await execFileAsync("git", args, {
|
|
7
|
+
cwd,
|
|
8
|
+
maxBuffer: 8 * 1024 * 1024
|
|
9
|
+
});
|
|
10
|
+
return stdout;
|
|
11
|
+
}
|
|
12
|
+
async function gitDiffNoIndex(args, cwd) {
|
|
13
|
+
try {
|
|
14
|
+
return await git(args, cwd);
|
|
15
|
+
} catch (err) {
|
|
16
|
+
const rec = err && typeof err === "object" ? err : {};
|
|
17
|
+
if (typeof rec.stdout === "string") return rec.stdout;
|
|
18
|
+
throw err;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
async function resolveGitRoot(workspace) {
|
|
22
|
+
return (await git(["rev-parse", "--show-toplevel"], workspace)).trim() || workspace;
|
|
23
|
+
}
|
|
24
|
+
async function untrackedFileDiff(cwd) {
|
|
25
|
+
const files = (await git([
|
|
26
|
+
"ls-files",
|
|
27
|
+
"--others",
|
|
28
|
+
"--exclude-standard",
|
|
29
|
+
"-z"
|
|
30
|
+
], cwd).catch(() => "")).split("\0").map((item) => item.trim()).filter(Boolean);
|
|
31
|
+
if (files.length === 0) return "";
|
|
32
|
+
const chunks = [];
|
|
33
|
+
for (const file of files) {
|
|
34
|
+
const diff = await gitDiffNoIndex([
|
|
35
|
+
"diff",
|
|
36
|
+
"--no-index",
|
|
37
|
+
"--",
|
|
38
|
+
"/dev/null",
|
|
39
|
+
file
|
|
40
|
+
], cwd).catch(() => "");
|
|
41
|
+
if (diff.trim()) chunks.push(diff);
|
|
42
|
+
}
|
|
43
|
+
return chunks.join("\n");
|
|
44
|
+
}
|
|
45
|
+
function splitArgs(input) {
|
|
46
|
+
const out = [];
|
|
47
|
+
let cur = "";
|
|
48
|
+
let quote = null;
|
|
49
|
+
let escaped = false;
|
|
50
|
+
for (const ch of input) {
|
|
51
|
+
if (escaped) {
|
|
52
|
+
cur += ch;
|
|
53
|
+
escaped = false;
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
if (ch === "\\") {
|
|
57
|
+
escaped = true;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (quote) {
|
|
61
|
+
if (ch === quote) quote = null;
|
|
62
|
+
else cur += ch;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (ch === "\"" || ch === "'") {
|
|
66
|
+
quote = ch;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (/\s/.test(ch)) {
|
|
70
|
+
if (cur) {
|
|
71
|
+
out.push(cur);
|
|
72
|
+
cur = "";
|
|
73
|
+
}
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
cur += ch;
|
|
77
|
+
}
|
|
78
|
+
if (escaped) cur += "\\";
|
|
79
|
+
if (cur) out.push(cur);
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
82
|
+
function readOptionValue(tokens, index, flag) {
|
|
83
|
+
const token = tokens[index] ?? "";
|
|
84
|
+
const eq = token.indexOf("=");
|
|
85
|
+
if (eq > -1) return {
|
|
86
|
+
value: token.slice(eq + 1),
|
|
87
|
+
next: index + 1
|
|
88
|
+
};
|
|
89
|
+
const value = tokens[index + 1] ?? "";
|
|
90
|
+
if (!value || value.startsWith("--")) throw new Error(`Missing value for ${flag}`);
|
|
91
|
+
return {
|
|
92
|
+
value,
|
|
93
|
+
next: index + 2
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
function parseReviewTargetArgs(args) {
|
|
97
|
+
const tokens = splitArgs(args.trim());
|
|
98
|
+
let kind;
|
|
99
|
+
let baseBranch = "";
|
|
100
|
+
let sha = "";
|
|
101
|
+
let instructions = "";
|
|
102
|
+
const free = [];
|
|
103
|
+
for (let i = 0; i < tokens.length;) {
|
|
104
|
+
const token = tokens[i];
|
|
105
|
+
if (token === "--uncommitted") {
|
|
106
|
+
kind = "uncommitted";
|
|
107
|
+
i += 1;
|
|
108
|
+
continue;
|
|
109
|
+
}
|
|
110
|
+
if (token === "--base" || token.startsWith("--base=")) {
|
|
111
|
+
const value = readOptionValue(tokens, i, "--base");
|
|
112
|
+
kind = "base_branch";
|
|
113
|
+
baseBranch = value.value.trim();
|
|
114
|
+
i = value.next;
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (token === "--commit" || token.startsWith("--commit=")) {
|
|
118
|
+
const value = readOptionValue(tokens, i, "--commit");
|
|
119
|
+
kind = "commit";
|
|
120
|
+
sha = value.value.trim();
|
|
121
|
+
i = value.next;
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
if (token === "--custom" || token === "--instructions") {
|
|
125
|
+
instructions = tokens.slice(i + 1).join(" ").trim();
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
if (token.startsWith("--custom=") || token.startsWith("--instructions=")) {
|
|
129
|
+
instructions = token.slice(token.indexOf("=") + 1).trim();
|
|
130
|
+
i += 1;
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
free.push(token);
|
|
134
|
+
i += 1;
|
|
135
|
+
}
|
|
136
|
+
const extraInstructions = instructions || free.join(" ").trim();
|
|
137
|
+
if (!kind) kind = "uncommitted";
|
|
138
|
+
if (kind === "base_branch") {
|
|
139
|
+
if (!baseBranch) throw new Error("Missing base branch for review.");
|
|
140
|
+
return {
|
|
141
|
+
kind,
|
|
142
|
+
baseBranch,
|
|
143
|
+
...extraInstructions ? { instructions: extraInstructions } : {}
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
if (kind === "commit") {
|
|
147
|
+
if (!sha) throw new Error("Missing commit SHA for review.");
|
|
148
|
+
return {
|
|
149
|
+
kind,
|
|
150
|
+
sha,
|
|
151
|
+
...extraInstructions ? { instructions: extraInstructions } : {}
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
kind: "uncommitted",
|
|
156
|
+
...extraInstructions ? { instructions: extraInstructions } : {}
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
async function buildUncommittedReview(cwd, target) {
|
|
160
|
+
return {
|
|
161
|
+
cwd,
|
|
162
|
+
target,
|
|
163
|
+
targetLabel: "uncommitted changes",
|
|
164
|
+
status: await git(["status", "--short"], cwd).catch(() => ""),
|
|
165
|
+
stat: await git([
|
|
166
|
+
"diff",
|
|
167
|
+
"--stat",
|
|
168
|
+
"HEAD",
|
|
169
|
+
"--"
|
|
170
|
+
], cwd).catch(() => ""),
|
|
171
|
+
diff: [await git([
|
|
172
|
+
"diff",
|
|
173
|
+
"--find-renames",
|
|
174
|
+
"HEAD",
|
|
175
|
+
"--"
|
|
176
|
+
], cwd).catch(() => ""), await untrackedFileDiff(cwd)].filter((part) => part.trim()).join("\n")
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
async function buildBaseBranchReview(cwd, target) {
|
|
180
|
+
const mergeBase = (await git([
|
|
181
|
+
"merge-base",
|
|
182
|
+
"HEAD",
|
|
183
|
+
target.baseBranch
|
|
184
|
+
], cwd)).trim();
|
|
185
|
+
const status = await git(["status", "--short"], cwd).catch(() => "");
|
|
186
|
+
const stat = await git([
|
|
187
|
+
"diff",
|
|
188
|
+
"--stat",
|
|
189
|
+
mergeBase,
|
|
190
|
+
"HEAD",
|
|
191
|
+
"--"
|
|
192
|
+
], cwd).catch(() => "");
|
|
193
|
+
const diff = await git([
|
|
194
|
+
"diff",
|
|
195
|
+
"--find-renames",
|
|
196
|
+
mergeBase,
|
|
197
|
+
"HEAD",
|
|
198
|
+
"--"
|
|
199
|
+
], cwd).catch(() => "");
|
|
200
|
+
return {
|
|
201
|
+
cwd,
|
|
202
|
+
target,
|
|
203
|
+
targetLabel: `changes against ${target.baseBranch} (merge-base ${mergeBase.slice(0, 12)})`,
|
|
204
|
+
status,
|
|
205
|
+
stat,
|
|
206
|
+
diff
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
async function buildCommitReview(cwd, target) {
|
|
210
|
+
const title = (await git([
|
|
211
|
+
"log",
|
|
212
|
+
"-1",
|
|
213
|
+
"--format=%s",
|
|
214
|
+
target.sha
|
|
215
|
+
], cwd)).trim();
|
|
216
|
+
const nextTarget = {
|
|
217
|
+
...target,
|
|
218
|
+
...title ? { title } : {}
|
|
219
|
+
};
|
|
220
|
+
const stat = await git([
|
|
221
|
+
"show",
|
|
222
|
+
"--stat",
|
|
223
|
+
"--format=",
|
|
224
|
+
"--find-renames",
|
|
225
|
+
target.sha,
|
|
226
|
+
"--"
|
|
227
|
+
], cwd);
|
|
228
|
+
const diff = await git([
|
|
229
|
+
"show",
|
|
230
|
+
"--format=fuller",
|
|
231
|
+
"--find-renames",
|
|
232
|
+
"--patch",
|
|
233
|
+
target.sha,
|
|
234
|
+
"--"
|
|
235
|
+
], cwd);
|
|
236
|
+
return {
|
|
237
|
+
cwd,
|
|
238
|
+
target: nextTarget,
|
|
239
|
+
targetLabel: `commit ${target.sha}${title ? ` (${title})` : ""}`,
|
|
240
|
+
status: "",
|
|
241
|
+
stat,
|
|
242
|
+
diff
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
async function buildReviewDiffBundle(cwd, target) {
|
|
246
|
+
if (target.kind === "base_branch") return buildBaseBranchReview(cwd, target);
|
|
247
|
+
if (target.kind === "commit") return buildCommitReview(cwd, target);
|
|
248
|
+
return buildUncommittedReview(cwd, target);
|
|
249
|
+
}
|
|
250
|
+
function parseStatusCounts(status) {
|
|
251
|
+
let changedFiles = 0;
|
|
252
|
+
let untrackedFiles = 0;
|
|
253
|
+
for (const line of status.split("\n")) {
|
|
254
|
+
if (!line.trim()) continue;
|
|
255
|
+
if (line.startsWith("??")) untrackedFiles += 1;
|
|
256
|
+
else changedFiles += 1;
|
|
257
|
+
}
|
|
258
|
+
return {
|
|
259
|
+
changedFiles,
|
|
260
|
+
untrackedFiles,
|
|
261
|
+
isClean: changedFiles === 0 && untrackedFiles === 0
|
|
262
|
+
};
|
|
263
|
+
}
|
|
264
|
+
function normalizeBranchName(raw) {
|
|
265
|
+
return raw.replace(/^remotes\//, "").trim();
|
|
266
|
+
}
|
|
267
|
+
async function listBranches(cwd) {
|
|
268
|
+
const raw = await git([
|
|
269
|
+
"branch",
|
|
270
|
+
"--all",
|
|
271
|
+
"--format=%(refname:short)|%(HEAD)"
|
|
272
|
+
], cwd).catch(() => "");
|
|
273
|
+
const seen = /* @__PURE__ */ new Set();
|
|
274
|
+
const out = [];
|
|
275
|
+
for (const line of raw.split("\n")) {
|
|
276
|
+
const [nameRaw, headRaw] = line.split("|");
|
|
277
|
+
const name = normalizeBranchName(nameRaw ?? "");
|
|
278
|
+
if (!name || name.includes("HEAD ->") || seen.has(name)) continue;
|
|
279
|
+
seen.add(name);
|
|
280
|
+
const item = { name };
|
|
281
|
+
if (headRaw?.trim() === "*") item.current = true;
|
|
282
|
+
if (name.includes("/")) item.remote = true;
|
|
283
|
+
out.push(item);
|
|
284
|
+
}
|
|
285
|
+
return out;
|
|
286
|
+
}
|
|
287
|
+
async function listCommits(cwd) {
|
|
288
|
+
return (await git([
|
|
289
|
+
"log",
|
|
290
|
+
"--date=iso-strict",
|
|
291
|
+
"--format=%H%x00%h%x00%s%x00%aI",
|
|
292
|
+
"-n",
|
|
293
|
+
"100"
|
|
294
|
+
], cwd).catch(() => "")).split("\n").map((line) => {
|
|
295
|
+
const [sha, shortSha, subject, date] = line.split("\0");
|
|
296
|
+
if (!sha || !shortSha || !subject) return null;
|
|
297
|
+
const item = {
|
|
298
|
+
sha,
|
|
299
|
+
shortSha,
|
|
300
|
+
subject
|
|
301
|
+
};
|
|
302
|
+
if (date) item.date = date;
|
|
303
|
+
return item;
|
|
304
|
+
}).filter((item) => item != null);
|
|
305
|
+
}
|
|
306
|
+
function defaultBaseBranch(branches) {
|
|
307
|
+
for (const name of [
|
|
308
|
+
"origin/main",
|
|
309
|
+
"main",
|
|
310
|
+
"origin/master",
|
|
311
|
+
"master",
|
|
312
|
+
"develop"
|
|
313
|
+
]) if (branches.some((branch) => branch.name === name)) return name;
|
|
314
|
+
return branches.find((branch) => branch.remote && !branch.current)?.name ?? branches.find((branch) => !branch.current)?.name;
|
|
315
|
+
}
|
|
316
|
+
async function buildReviewContext(cwd) {
|
|
317
|
+
const statusRaw = await git(["status", "--short"], cwd).catch(() => "");
|
|
318
|
+
const branches = await listBranches(cwd);
|
|
319
|
+
const commits = await listCommits(cwd);
|
|
320
|
+
const context = {
|
|
321
|
+
cwd,
|
|
322
|
+
status: parseStatusCounts(statusRaw),
|
|
323
|
+
branches,
|
|
324
|
+
commits
|
|
325
|
+
};
|
|
326
|
+
const base = defaultBaseBranch(branches);
|
|
327
|
+
if (base) context.defaultBaseBranch = base;
|
|
328
|
+
return context;
|
|
329
|
+
}
|
|
330
|
+
//#endregion
|
|
331
|
+
export { buildReviewContext, buildReviewDiffBundle, git, parseReviewTargetArgs, resolveGitRoot };
|
|
332
|
+
|
|
333
|
+
//# sourceMappingURL=review-git.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-git.js","names":[],"sources":["../../../src/review/review-git.ts"],"sourcesContent":["import { execFile } from 'node:child_process';\nimport { promisify } from 'node:util';\n\nconst execFileAsync = promisify(execFile);\n\nexport type ReviewTarget =\n | { kind: 'uncommitted'; instructions?: string }\n | { kind: 'base_branch'; baseBranch: string; instructions?: string }\n | { kind: 'commit'; sha: string; title?: string; instructions?: string };\n\nexport interface ReviewDiffBundle {\n cwd: string;\n target: ReviewTarget;\n targetLabel: string;\n status: string;\n stat: string;\n diff: string;\n}\n\nexport interface ReviewContextBranch {\n name: string;\n current?: boolean;\n remote?: boolean;\n}\n\nexport interface ReviewContextCommit {\n sha: string;\n shortSha: string;\n subject: string;\n date?: string;\n}\n\nexport interface ReviewContext {\n cwd: string;\n defaultBaseBranch?: string;\n status: {\n changedFiles: number;\n untrackedFiles: number;\n isClean: boolean;\n };\n branches: ReviewContextBranch[];\n commits: ReviewContextCommit[];\n}\n\nexport async function git(args: string[], cwd: string): Promise<string> {\n const { stdout } = await execFileAsync('git', args, {\n cwd,\n maxBuffer: 8 * 1024 * 1024,\n });\n return stdout;\n}\n\nasync function gitDiffNoIndex(args: string[], cwd: string): Promise<string> {\n try {\n return await git(args, cwd);\n } catch (err) {\n const rec = err && typeof err === 'object' ? err as Record<string, unknown> : {};\n if (typeof rec.stdout === 'string') return rec.stdout;\n throw err;\n }\n}\n\nexport async function resolveGitRoot(workspace: string): Promise<string> {\n const root = (await git(['rev-parse', '--show-toplevel'], workspace)).trim();\n return root || workspace;\n}\n\nasync function untrackedFileDiff(cwd: string): Promise<string> {\n const raw = await git(['ls-files', '--others', '--exclude-standard', '-z'], cwd).catch(() => '');\n const files = raw.split('\\0').map((item) => item.trim()).filter(Boolean);\n if (files.length === 0) return '';\n\n const chunks: string[] = [];\n for (const file of files) {\n const diff = await gitDiffNoIndex(['diff', '--no-index', '--', '/dev/null', file], cwd).catch(() => '');\n if (diff.trim()) chunks.push(diff);\n }\n return chunks.join('\\n');\n}\n\nfunction splitArgs(input: string): string[] {\n const out: string[] = [];\n let cur = '';\n let quote: '\"' | \"'\" | null = null;\n let escaped = false;\n for (const ch of input) {\n if (escaped) {\n cur += ch;\n escaped = false;\n continue;\n }\n if (ch === '\\\\') {\n escaped = true;\n continue;\n }\n if (quote) {\n if (ch === quote) quote = null;\n else cur += ch;\n continue;\n }\n if (ch === '\"' || ch === \"'\") {\n quote = ch;\n continue;\n }\n if (/\\s/.test(ch)) {\n if (cur) {\n out.push(cur);\n cur = '';\n }\n continue;\n }\n cur += ch;\n }\n if (escaped) cur += '\\\\';\n if (cur) out.push(cur);\n return out;\n}\n\nfunction readOptionValue(tokens: string[], index: number, flag: string): { value: string; next: number } {\n const token = tokens[index] ?? '';\n const eq = token.indexOf('=');\n if (eq > -1) {\n return { value: token.slice(eq + 1), next: index + 1 };\n }\n const value = tokens[index + 1] ?? '';\n if (!value || value.startsWith('--')) {\n throw new Error(`Missing value for ${flag}`);\n }\n return { value, next: index + 2 };\n}\n\nexport function parseReviewTargetArgs(args: string): ReviewTarget {\n const tokens = splitArgs(args.trim());\n let kind: ReviewTarget['kind'] | undefined;\n let baseBranch = '';\n let sha = '';\n let instructions = '';\n const free: string[] = [];\n\n for (let i = 0; i < tokens.length;) {\n const token = tokens[i]!;\n if (token === '--uncommitted') {\n kind = 'uncommitted';\n i += 1;\n continue;\n }\n if (token === '--base' || token.startsWith('--base=')) {\n const value = readOptionValue(tokens, i, '--base');\n kind = 'base_branch';\n baseBranch = value.value.trim();\n i = value.next;\n continue;\n }\n if (token === '--commit' || token.startsWith('--commit=')) {\n const value = readOptionValue(tokens, i, '--commit');\n kind = 'commit';\n sha = value.value.trim();\n i = value.next;\n continue;\n }\n if (token === '--custom' || token === '--instructions') {\n instructions = tokens.slice(i + 1).join(' ').trim();\n break;\n }\n if (token.startsWith('--custom=') || token.startsWith('--instructions=')) {\n instructions = token.slice(token.indexOf('=') + 1).trim();\n i += 1;\n continue;\n }\n free.push(token);\n i += 1;\n }\n\n const extraInstructions = instructions || free.join(' ').trim();\n if (!kind) kind = 'uncommitted';\n if (kind === 'base_branch') {\n if (!baseBranch) throw new Error('Missing base branch for review.');\n return { kind, baseBranch, ...(extraInstructions ? { instructions: extraInstructions } : {}) };\n }\n if (kind === 'commit') {\n if (!sha) throw new Error('Missing commit SHA for review.');\n return { kind, sha, ...(extraInstructions ? { instructions: extraInstructions } : {}) };\n }\n return { kind: 'uncommitted', ...(extraInstructions ? { instructions: extraInstructions } : {}) };\n}\n\nasync function buildUncommittedReview(cwd: string, target: ReviewTarget & { kind: 'uncommitted' }): Promise<ReviewDiffBundle> {\n const status = await git(['status', '--short'], cwd).catch(() => '');\n const stat = await git(['diff', '--stat', 'HEAD', '--'], cwd).catch(() => '');\n const trackedDiff = await git(['diff', '--find-renames', 'HEAD', '--'], cwd).catch(() => '');\n const untrackedDiff = await untrackedFileDiff(cwd);\n return {\n cwd,\n target,\n targetLabel: 'uncommitted changes',\n status,\n stat,\n diff: [trackedDiff, untrackedDiff].filter((part) => part.trim()).join('\\n'),\n };\n}\n\nasync function buildBaseBranchReview(cwd: string, target: ReviewTarget & { kind: 'base_branch' }): Promise<ReviewDiffBundle> {\n const mergeBase = (await git(['merge-base', 'HEAD', target.baseBranch], cwd)).trim();\n const status = await git(['status', '--short'], cwd).catch(() => '');\n const stat = await git(['diff', '--stat', mergeBase, 'HEAD', '--'], cwd).catch(() => '');\n const diff = await git(['diff', '--find-renames', mergeBase, 'HEAD', '--'], cwd).catch(() => '');\n return {\n cwd,\n target,\n targetLabel: `changes against ${target.baseBranch} (merge-base ${mergeBase.slice(0, 12)})`,\n status,\n stat,\n diff,\n };\n}\n\nasync function buildCommitReview(cwd: string, target: ReviewTarget & { kind: 'commit' }): Promise<ReviewDiffBundle> {\n const title = (await git(['log', '-1', '--format=%s', target.sha], cwd)).trim();\n const nextTarget: ReviewTarget = {\n ...target,\n ...(title ? { title } : {}),\n };\n const stat = await git(['show', '--stat', '--format=', '--find-renames', target.sha, '--'], cwd);\n const diff = await git(['show', '--format=fuller', '--find-renames', '--patch', target.sha, '--'], cwd);\n return {\n cwd,\n target: nextTarget,\n targetLabel: `commit ${target.sha}${title ? ` (${title})` : ''}`,\n status: '',\n stat,\n diff,\n };\n}\n\nexport async function buildReviewDiffBundle(cwd: string, target: ReviewTarget): Promise<ReviewDiffBundle> {\n if (target.kind === 'base_branch') return buildBaseBranchReview(cwd, target);\n if (target.kind === 'commit') return buildCommitReview(cwd, target);\n return buildUncommittedReview(cwd, target);\n}\n\nfunction parseStatusCounts(status: string): ReviewContext['status'] {\n let changedFiles = 0;\n let untrackedFiles = 0;\n for (const line of status.split('\\n')) {\n if (!line.trim()) continue;\n if (line.startsWith('??')) untrackedFiles += 1;\n else changedFiles += 1;\n }\n return {\n changedFiles,\n untrackedFiles,\n isClean: changedFiles === 0 && untrackedFiles === 0,\n };\n}\n\nfunction normalizeBranchName(raw: string): string {\n return raw.replace(/^remotes\\//, '').trim();\n}\n\nasync function listBranches(cwd: string): Promise<ReviewContextBranch[]> {\n const raw = await git(['branch', '--all', '--format=%(refname:short)|%(HEAD)'], cwd).catch(() => '');\n const seen = new Set<string>();\n const out: ReviewContextBranch[] = [];\n for (const line of raw.split('\\n')) {\n const [nameRaw, headRaw] = line.split('|');\n const name = normalizeBranchName(nameRaw ?? '');\n if (!name || name.includes('HEAD ->') || seen.has(name)) continue;\n seen.add(name);\n const item: ReviewContextBranch = { name };\n if (headRaw?.trim() === '*') item.current = true;\n if (name.includes('/')) item.remote = true;\n out.push(item);\n }\n return out;\n}\n\nasync function listCommits(cwd: string): Promise<ReviewContextCommit[]> {\n const raw = await git(['log', '--date=iso-strict', '--format=%H%x00%h%x00%s%x00%aI', '-n', '100'], cwd).catch(() => '');\n return raw\n .split('\\n')\n .map((line): ReviewContextCommit | null => {\n const [sha, shortSha, subject, date] = line.split('\\0');\n if (!sha || !shortSha || !subject) return null;\n const item: ReviewContextCommit = { sha, shortSha, subject };\n if (date) item.date = date;\n return item;\n })\n .filter((item): item is ReviewContextCommit => item != null);\n}\n\nfunction defaultBaseBranch(branches: ReviewContextBranch[]): string | undefined {\n const preferred = ['origin/main', 'main', 'origin/master', 'master', 'develop'];\n for (const name of preferred) {\n if (branches.some((branch) => branch.name === name)) return name;\n }\n return branches.find((branch) => branch.remote && !branch.current)?.name\n ?? branches.find((branch) => !branch.current)?.name;\n}\n\nexport async function buildReviewContext(cwd: string): Promise<ReviewContext> {\n const statusRaw = await git(['status', '--short'], cwd).catch(() => '');\n const branches = await listBranches(cwd);\n const commits = await listCommits(cwd);\n const context: ReviewContext = {\n cwd,\n status: parseStatusCounts(statusRaw),\n branches,\n commits,\n };\n const base = defaultBaseBranch(branches);\n if (base) context.defaultBaseBranch = base;\n return context;\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type ReviewPriority = 0 | 1 | 2 | 3;
|
|
2
|
+
export interface ReviewFinding {
|
|
3
|
+
title: string;
|
|
4
|
+
body: string;
|
|
5
|
+
priority: ReviewPriority;
|
|
6
|
+
confidenceScore?: number;
|
|
7
|
+
filePath?: string;
|
|
8
|
+
lineStart?: number;
|
|
9
|
+
lineEnd?: number;
|
|
10
|
+
}
|
|
11
|
+
export interface ReviewOutput {
|
|
12
|
+
type: 'review';
|
|
13
|
+
target: string;
|
|
14
|
+
summary: string;
|
|
15
|
+
findings: ReviewFinding[];
|
|
16
|
+
overallCorrectness: 'patch is correct' | 'patch is incorrect' | 'unknown';
|
|
17
|
+
overallExplanation: string;
|
|
18
|
+
overallConfidenceScore?: number;
|
|
19
|
+
generatedAt: number;
|
|
20
|
+
source: 'model' | 'local';
|
|
21
|
+
}
|
|
22
|
+
export declare function formatReviewMarkdown(review: ReviewOutput): string;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region src/review/review-types.ts
|
|
2
|
+
function formatLocation(finding) {
|
|
3
|
+
if (!finding.filePath) return "";
|
|
4
|
+
if (!finding.lineStart) return finding.filePath;
|
|
5
|
+
const end = finding.lineEnd && finding.lineEnd !== finding.lineStart ? `-${finding.lineEnd}` : "";
|
|
6
|
+
return `${finding.filePath}:${finding.lineStart}${end}`;
|
|
7
|
+
}
|
|
8
|
+
function formatReviewMarkdown(review) {
|
|
9
|
+
const lines = ["Code review", ""];
|
|
10
|
+
if (review.findings.length === 0) lines.push("No findings.");
|
|
11
|
+
else {
|
|
12
|
+
lines.push("Findings:");
|
|
13
|
+
for (const finding of review.findings) {
|
|
14
|
+
const location = formatLocation(finding);
|
|
15
|
+
const suffix = location ? ` - ${location}` : "";
|
|
16
|
+
lines.push(`- [P${finding.priority}] ${finding.title}${suffix}`);
|
|
17
|
+
if (finding.body.trim()) lines.push(` ${finding.body.trim().replace(/\n+/g, "\n ")}`);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
lines.push("");
|
|
21
|
+
lines.push(`Overall correctness: ${review.overallCorrectness}`);
|
|
22
|
+
if (review.overallExplanation.trim()) lines.push(review.overallExplanation.trim());
|
|
23
|
+
if (typeof review.overallConfidenceScore === "number") lines.push(`Confidence: ${review.overallConfidenceScore.toFixed(2)}`);
|
|
24
|
+
return lines.join("\n");
|
|
25
|
+
}
|
|
26
|
+
//#endregion
|
|
27
|
+
export { formatReviewMarkdown };
|
|
28
|
+
|
|
29
|
+
//# sourceMappingURL=review-types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review-types.js","names":[],"sources":["../../../src/review/review-types.ts"],"sourcesContent":["export type ReviewPriority = 0 | 1 | 2 | 3;\n\nexport interface ReviewFinding {\n title: string;\n body: string;\n priority: ReviewPriority;\n confidenceScore?: number;\n filePath?: string;\n lineStart?: number;\n lineEnd?: number;\n}\n\nexport interface ReviewOutput {\n type: 'review';\n target: string;\n summary: string;\n findings: ReviewFinding[];\n overallCorrectness: 'patch is correct' | 'patch is incorrect' | 'unknown';\n overallExplanation: string;\n overallConfidenceScore?: number;\n generatedAt: number;\n source: 'model' | 'local';\n}\n\nfunction formatLocation(finding: ReviewFinding): string {\n if (!finding.filePath) return '';\n if (!finding.lineStart) return finding.filePath;\n const end = finding.lineEnd && finding.lineEnd !== finding.lineStart ? `-${finding.lineEnd}` : '';\n return `${finding.filePath}:${finding.lineStart}${end}`;\n}\n\nexport function formatReviewMarkdown(review: ReviewOutput): string {\n const lines: string[] = ['Code review', ''];\n if (review.findings.length === 0) {\n lines.push('No findings.');\n } else {\n lines.push('Findings:');\n for (const finding of review.findings) {\n const location = formatLocation(finding);\n const suffix = location ? ` - ${location}` : '';\n lines.push(`- [P${finding.priority}] ${finding.title}${suffix}`);\n if (finding.body.trim()) {\n lines.push(` ${finding.body.trim().replace(/\\n+/g, '\\n ')}`);\n }\n }\n }\n lines.push('');\n lines.push(`Overall correctness: ${review.overallCorrectness}`);\n if (review.overallExplanation.trim()) {\n lines.push(review.overallExplanation.trim());\n }\n if (typeof review.overallConfidenceScore === 'number') {\n lines.push(`Confidence: ${review.overallConfidenceScore.toFixed(2)}`);\n }\n return lines.join('\\n');\n}\n"],"mappings":";AAwBA,SAAS,eAAe,SAAgC;AACtD,KAAI,CAAC,QAAQ,SAAU,QAAO;AAC9B,KAAI,CAAC,QAAQ,UAAW,QAAO,QAAQ;CACvC,MAAM,MAAM,QAAQ,WAAW,QAAQ,YAAY,QAAQ,YAAY,IAAI,QAAQ,YAAY;AAC/F,QAAO,GAAG,QAAQ,SAAS,GAAG,QAAQ,YAAY;;AAGpD,SAAgB,qBAAqB,QAA8B;CACjE,MAAM,QAAkB,CAAC,eAAe,GAAG;AAC3C,KAAI,OAAO,SAAS,WAAW,EAC7B,OAAM,KAAK,eAAe;MACrB;AACL,QAAM,KAAK,YAAY;AACvB,OAAK,MAAM,WAAW,OAAO,UAAU;GACrC,MAAM,WAAW,eAAe,QAAQ;GACxC,MAAM,SAAS,WAAW,MAAM,aAAa;AAC7C,SAAM,KAAK,OAAO,QAAQ,SAAS,IAAI,QAAQ,QAAQ,SAAS;AAChE,OAAI,QAAQ,KAAK,MAAM,CACrB,OAAM,KAAK,KAAK,QAAQ,KAAK,MAAM,CAAC,QAAQ,QAAQ,OAAO,GAAG;;;AAIpE,OAAM,KAAK,GAAG;AACd,OAAM,KAAK,wBAAwB,OAAO,qBAAqB;AAC/D,KAAI,OAAO,mBAAmB,MAAM,CAClC,OAAM,KAAK,OAAO,mBAAmB,MAAM,CAAC;AAE9C,KAAI,OAAO,OAAO,2BAA2B,SAC3C,OAAM,KAAK,eAAe,OAAO,uBAAuB,QAAQ,EAAE,GAAG;AAEvE,QAAO,MAAM,KAAK,KAAK"}
|