byterover-cli 2.6.0 → 3.0.0
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/.env.production +1 -0
- package/README.md +240 -14
- package/dist/agent/core/domain/knowledge/conflict-detector.d.ts +38 -0
- package/dist/agent/core/domain/knowledge/conflict-detector.js +71 -0
- package/dist/agent/core/domain/knowledge/conflict-resolver.d.ts +17 -0
- package/dist/agent/core/domain/knowledge/conflict-resolver.js +118 -0
- package/dist/agent/core/domain/knowledge/utils.d.ts +4 -0
- package/dist/agent/core/domain/knowledge/utils.js +6 -0
- package/dist/agent/core/interfaces/i-curate-service.d.ts +6 -0
- package/dist/agent/infra/tools/implementations/curate-tool.d.ts +67 -34
- package/dist/agent/infra/tools/implementations/curate-tool.js +294 -47
- package/dist/agent/resources/prompts/system-prompt.yml +15 -8
- package/dist/agent/resources/tools/code_exec.txt +3 -0
- package/dist/agent/resources/tools/curate.txt +12 -3
- package/dist/oclif/commands/connectors/install.d.ts +2 -1
- package/dist/oclif/commands/connectors/install.js +38 -3
- package/dist/oclif/commands/curate/index.d.ts +18 -0
- package/dist/oclif/commands/curate/index.js +78 -1
- package/dist/oclif/commands/init.d.ts +12 -0
- package/dist/oclif/commands/init.js +75 -0
- package/dist/oclif/commands/locations.js +1 -1
- package/dist/oclif/commands/providers/connect.d.ts +31 -1
- package/dist/oclif/commands/providers/connect.js +307 -27
- package/dist/oclif/commands/pull.d.ts +1 -0
- package/dist/oclif/commands/pull.js +7 -0
- package/dist/oclif/commands/push.d.ts +1 -0
- package/dist/oclif/commands/push.js +8 -0
- package/dist/oclif/commands/review/approve.d.ts +17 -0
- package/dist/oclif/commands/review/approve.js +37 -0
- package/dist/oclif/commands/review/base-review-decision.d.ts +18 -0
- package/dist/oclif/commands/review/base-review-decision.js +71 -0
- package/dist/oclif/commands/review/pending.d.ts +13 -0
- package/dist/oclif/commands/review/pending.js +94 -0
- package/dist/oclif/commands/review/reject.d.ts +17 -0
- package/dist/oclif/commands/review/reject.js +38 -0
- package/dist/oclif/commands/space/list.d.ts +2 -2
- package/dist/oclif/commands/space/list.js +13 -35
- package/dist/oclif/commands/space/switch.d.ts +2 -7
- package/dist/oclif/commands/space/switch.js +13 -56
- package/dist/oclif/commands/status.d.ts +1 -0
- package/dist/oclif/commands/status.js +11 -1
- package/dist/oclif/commands/vc/add.d.ts +7 -0
- package/dist/oclif/commands/vc/add.js +29 -0
- package/dist/oclif/commands/vc/branch.d.ts +15 -0
- package/dist/oclif/commands/vc/branch.js +70 -0
- package/dist/oclif/commands/vc/checkout.d.ts +14 -0
- package/dist/oclif/commands/vc/checkout.js +47 -0
- package/dist/oclif/commands/vc/clone.d.ts +9 -0
- package/dist/oclif/commands/vc/clone.js +61 -0
- package/dist/oclif/commands/vc/commit.d.ts +10 -0
- package/dist/oclif/commands/vc/commit.js +32 -0
- package/dist/oclif/commands/vc/config.d.ts +10 -0
- package/dist/oclif/commands/vc/config.js +30 -0
- package/dist/oclif/commands/vc/fetch.d.ts +10 -0
- package/dist/oclif/commands/vc/fetch.js +42 -0
- package/dist/oclif/commands/vc/index.d.ts +6 -0
- package/dist/oclif/commands/vc/index.js +8 -0
- package/dist/oclif/commands/vc/init.d.ts +6 -0
- package/dist/oclif/commands/vc/init.js +25 -0
- package/dist/oclif/commands/vc/log.d.ts +13 -0
- package/dist/oclif/commands/vc/log.js +48 -0
- package/dist/oclif/commands/vc/merge.d.ts +19 -0
- package/dist/oclif/commands/vc/merge.js +130 -0
- package/dist/oclif/commands/vc/pull.d.ts +13 -0
- package/dist/oclif/commands/vc/pull.js +60 -0
- package/dist/oclif/commands/vc/push.d.ts +13 -0
- package/dist/oclif/commands/vc/push.js +60 -0
- package/dist/oclif/commands/vc/remote/add.d.ts +10 -0
- package/dist/oclif/commands/vc/remote/add.js +30 -0
- package/dist/oclif/commands/vc/remote/index.d.ts +6 -0
- package/dist/oclif/commands/vc/remote/index.js +16 -0
- package/dist/oclif/commands/vc/remote/set-url.d.ts +10 -0
- package/dist/oclif/commands/vc/remote/set-url.js +30 -0
- package/dist/oclif/commands/vc/reset.d.ts +13 -0
- package/dist/oclif/commands/vc/reset.js +62 -0
- package/dist/oclif/commands/vc/status.d.ts +8 -0
- package/dist/oclif/commands/vc/status.js +106 -0
- package/dist/oclif/hooks/init/validate-brv-config.d.ts +26 -0
- package/dist/oclif/hooks/init/validate-brv-config.js +62 -0
- package/dist/oclif/lib/daemon-client.d.ts +2 -0
- package/dist/oclif/lib/daemon-client.js +36 -10
- package/dist/oclif/lib/prompt-utils.d.ts +43 -0
- package/dist/oclif/lib/prompt-utils.js +84 -0
- package/dist/oclif/lib/spinner.d.ts +8 -0
- package/dist/oclif/lib/spinner.js +23 -0
- package/dist/oclif/lib/task-client.d.ts +5 -0
- package/dist/oclif/lib/task-client.js +15 -2
- package/dist/server/config/environment.d.ts +2 -0
- package/dist/server/config/environment.js +2 -0
- package/dist/server/constants.d.ts +3 -0
- package/dist/server/constants.js +9 -0
- package/dist/server/core/domain/entities/auth-token.d.ts +2 -0
- package/dist/server/core/domain/entities/auth-token.js +7 -1
- package/dist/server/core/domain/entities/curate-log-entry.d.ts +11 -0
- package/dist/server/core/domain/entities/space.d.ts +4 -0
- package/dist/server/core/domain/entities/space.js +8 -0
- package/dist/server/core/domain/entities/team.d.ts +2 -0
- package/dist/server/core/domain/entities/team.js +4 -0
- package/dist/server/core/domain/errors/git-error.d.ts +6 -0
- package/dist/server/core/domain/errors/git-error.js +12 -0
- package/dist/server/core/domain/errors/task-error.d.ts +4 -0
- package/dist/server/core/domain/errors/task-error.js +8 -0
- package/dist/server/core/domain/errors/vc-error.d.ts +5 -0
- package/dist/server/core/domain/errors/vc-error.js +8 -0
- package/dist/server/core/domain/knowledge/markdown-writer.d.ts +4 -1
- package/dist/server/core/domain/knowledge/markdown-writer.js +37 -7
- package/dist/server/core/domain/transport/schemas.d.ts +6 -6
- package/dist/server/core/interfaces/context-tree/i-context-tree-service.d.ts +11 -0
- package/dist/server/core/interfaces/process/i-task-lifecycle-hook.d.ts +6 -0
- package/dist/server/core/interfaces/services/i-git-service.d.ts +234 -0
- package/dist/server/core/interfaces/services/i-git-service.js +1 -0
- package/dist/server/core/interfaces/storage/i-curate-log-store.d.ts +5 -0
- package/dist/server/core/interfaces/storage/i-review-backup-store.d.ts +19 -0
- package/dist/server/core/interfaces/storage/i-review-backup-store.js +1 -0
- package/dist/server/core/interfaces/vc/i-vc-git-config-store.d.ts +8 -0
- package/dist/server/core/interfaces/vc/i-vc-git-config-store.js +1 -0
- package/dist/server/infra/config/auto-init.d.ts +0 -2
- package/dist/server/infra/config/auto-init.js +0 -1
- package/dist/server/infra/context-tree/file-context-tree-service.d.ts +2 -0
- package/dist/server/infra/context-tree/file-context-tree-service.js +13 -0
- package/dist/server/infra/daemon/brv-server.js +23 -3
- package/dist/server/infra/git/cogit-url.d.ts +17 -0
- package/dist/server/infra/git/cogit-url.js +39 -0
- package/dist/server/infra/git/git-http-wrapper.d.ts +20 -0
- package/dist/server/infra/git/git-http-wrapper.js +334 -0
- package/dist/server/infra/git/isomorphic-git-service.d.ts +78 -0
- package/dist/server/infra/git/isomorphic-git-service.js +983 -0
- package/dist/server/infra/http/review-api-handler.d.ts +13 -0
- package/dist/server/infra/http/review-api-handler.js +286 -0
- package/dist/server/infra/http/review-ui.d.ts +7 -0
- package/dist/server/infra/http/review-ui.js +606 -0
- package/dist/server/infra/mcp/tools/brv-curate-tool.d.ts +2 -2
- package/dist/server/infra/process/curate-log-handler.d.ts +18 -2
- package/dist/server/infra/process/curate-log-handler.js +50 -13
- package/dist/server/infra/process/feature-handlers.js +41 -1
- package/dist/server/infra/process/task-router.js +16 -0
- package/dist/server/infra/space/http-space-service.js +2 -0
- package/dist/server/infra/storage/file-curate-log-store.d.ts +10 -0
- package/dist/server/infra/storage/file-curate-log-store.js +35 -0
- package/dist/server/infra/storage/file-review-backup-store.d.ts +29 -0
- package/dist/server/infra/storage/file-review-backup-store.js +121 -0
- package/dist/server/infra/transport/handlers/auth-handler.js +9 -5
- package/dist/server/infra/transport/handlers/handler-types.d.ts +9 -0
- package/dist/server/infra/transport/handlers/handler-types.js +11 -0
- package/dist/server/infra/transport/handlers/index.d.ts +4 -0
- package/dist/server/infra/transport/handlers/index.js +2 -0
- package/dist/server/infra/transport/handlers/init-handler.d.ts +1 -0
- package/dist/server/infra/transport/handlers/init-handler.js +13 -1
- package/dist/server/infra/transport/handlers/pull-handler.d.ts +3 -0
- package/dist/server/infra/transport/handlers/pull-handler.js +5 -1
- package/dist/server/infra/transport/handlers/push-handler.d.ts +20 -0
- package/dist/server/infra/transport/handlers/push-handler.js +116 -14
- package/dist/server/infra/transport/handlers/reset-handler.d.ts +11 -0
- package/dist/server/infra/transport/handlers/reset-handler.js +37 -1
- package/dist/server/infra/transport/handlers/review-handler.d.ts +35 -0
- package/dist/server/infra/transport/handlers/review-handler.js +162 -0
- package/dist/server/infra/transport/handlers/space-handler.d.ts +3 -0
- package/dist/server/infra/transport/handlers/space-handler.js +4 -1
- package/dist/server/infra/transport/handlers/status-handler.d.ts +5 -0
- package/dist/server/infra/transport/handlers/status-handler.js +51 -16
- package/dist/server/infra/transport/handlers/vc-handler.d.ts +100 -0
- package/dist/server/infra/transport/handlers/vc-handler.js +1050 -0
- package/dist/server/infra/transport/socket-io-transport-server.d.ts +7 -0
- package/dist/server/infra/transport/socket-io-transport-server.js +12 -1
- package/dist/server/infra/transport/transport-connector.d.ts +1 -1
- package/dist/server/infra/transport/transport-connector.js +2 -1
- package/dist/server/infra/vc/file-vc-git-config-store.d.ts +11 -0
- package/dist/server/infra/vc/file-vc-git-config-store.js +43 -0
- package/dist/server/templates/skill/SKILL.md +167 -33
- package/dist/server/utils/curate-result-parser.d.ts +64 -0
- package/dist/server/utils/curate-result-parser.js +8 -0
- package/dist/server/utils/gitignore.d.ts +9 -0
- package/dist/server/utils/gitignore.js +47 -0
- package/dist/shared/transport/events/index.d.ts +6 -0
- package/dist/shared/transport/events/index.js +3 -0
- package/dist/shared/transport/events/init-events.d.ts +8 -0
- package/dist/shared/transport/events/init-events.js +1 -0
- package/dist/shared/transport/events/push-events.d.ts +6 -0
- package/dist/shared/transport/events/review-events.d.ts +41 -0
- package/dist/shared/transport/events/review-events.js +5 -0
- package/dist/shared/transport/events/vc-events.d.ts +257 -0
- package/dist/shared/transport/events/vc-events.js +67 -0
- package/dist/shared/transport/types/dto.d.ts +6 -1
- package/dist/tui/app/pages/init-project-page.d.ts +9 -0
- package/dist/tui/app/pages/init-project-page.js +54 -0
- package/dist/tui/app/pages/protected-routes.js +14 -6
- package/dist/tui/components/index.d.ts +0 -2
- package/dist/tui/components/index.js +0 -1
- package/dist/tui/features/activity/hooks/use-activity-logs.js +7 -1
- package/dist/tui/features/commands/definitions/index.js +3 -0
- package/dist/tui/features/commands/definitions/space-list.js +9 -18
- package/dist/tui/features/commands/definitions/space-switch.js +10 -6
- package/dist/tui/features/commands/definitions/vc-add.d.ts +2 -0
- package/dist/tui/features/commands/definitions/vc-add.js +15 -0
- package/dist/tui/features/commands/definitions/vc-branch.d.ts +2 -0
- package/dist/tui/features/commands/definitions/vc-branch.js +33 -0
- package/dist/tui/features/commands/definitions/vc-checkout.d.ts +2 -0
- package/dist/tui/features/commands/definitions/vc-checkout.js +32 -0
- package/dist/tui/features/commands/definitions/vc-clone.d.ts +2 -0
- package/dist/tui/features/commands/definitions/vc-clone.js +18 -0
- package/dist/tui/features/commands/definitions/vc-commit.d.ts +2 -0
- package/dist/tui/features/commands/definitions/vc-commit.js +32 -0
- package/dist/tui/features/commands/definitions/vc-config.d.ts +2 -0
- package/dist/tui/features/commands/definitions/vc-config.js +40 -0
- package/dist/tui/features/commands/definitions/vc-fetch.d.ts +2 -0
- package/dist/tui/features/commands/definitions/vc-fetch.js +37 -0
- package/dist/tui/features/commands/definitions/vc-init.d.ts +2 -0
- package/dist/tui/features/commands/definitions/vc-init.js +11 -0
- package/dist/tui/features/commands/definitions/vc-log.d.ts +2 -0
- package/dist/tui/features/commands/definitions/vc-log.js +25 -0
- package/dist/tui/features/commands/definitions/vc-merge.d.ts +2 -0
- package/dist/tui/features/commands/definitions/vc-merge.js +48 -0
- package/dist/tui/features/commands/definitions/vc-pull.d.ts +2 -0
- package/dist/tui/features/commands/definitions/vc-pull.js +42 -0
- package/dist/tui/features/commands/definitions/vc-push.d.ts +2 -0
- package/dist/tui/features/commands/definitions/vc-push.js +38 -0
- package/dist/tui/features/commands/definitions/vc-remote.d.ts +2 -0
- package/dist/tui/features/commands/definitions/vc-remote.js +57 -0
- package/dist/tui/features/commands/definitions/vc-reset.d.ts +2 -0
- package/dist/tui/features/commands/definitions/vc-reset.js +35 -0
- package/dist/tui/features/commands/definitions/vc-status.d.ts +2 -0
- package/dist/tui/features/commands/definitions/vc-status.js +11 -0
- package/dist/tui/features/commands/definitions/vc.d.ts +2 -0
- package/dist/tui/features/commands/definitions/vc.js +36 -0
- package/dist/tui/features/commands/hooks/use-slash-command-processor.js +5 -5
- package/dist/tui/features/log/api/execute-log.d.ts +8 -0
- package/dist/tui/features/log/api/execute-log.js +13 -0
- package/dist/tui/features/log/components/log-flow.d.ts +14 -0
- package/dist/tui/features/log/components/log-flow.js +29 -0
- package/dist/tui/features/log/utils/format-log.d.ts +3 -0
- package/dist/tui/features/log/utils/format-log.js +42 -0
- package/dist/tui/features/onboarding/hooks/use-app-view-mode.d.ts +9 -5
- package/dist/tui/features/onboarding/hooks/use-app-view-mode.js +12 -5
- package/dist/tui/features/push/components/push-flow.js +9 -2
- package/dist/tui/features/reset/components/reset-flow.js +2 -1
- package/dist/tui/features/status/components/status-view.js +2 -1
- package/dist/tui/features/status/utils/format-status.js +9 -0
- package/dist/tui/features/tasks/hooks/use-task-subscriptions.js +11 -0
- package/dist/tui/features/tasks/stores/tasks-store.d.ts +10 -0
- package/dist/tui/features/tasks/stores/tasks-store.js +16 -0
- package/dist/tui/features/vc/add/api/execute-vc-add.d.ts +8 -0
- package/dist/tui/features/vc/add/api/execute-vc-add.js +13 -0
- package/dist/tui/features/vc/add/components/vc-add-flow.d.ts +7 -0
- package/dist/tui/features/vc/add/components/vc-add-flow.js +35 -0
- package/dist/tui/features/vc/branch/api/execute-vc-branch.d.ts +8 -0
- package/dist/tui/features/vc/branch/api/execute-vc-branch.js +13 -0
- package/dist/tui/features/vc/branch/components/vc-branch-flow.d.ts +8 -0
- package/dist/tui/features/vc/branch/components/vc-branch-flow.js +53 -0
- package/dist/tui/features/vc/branch/utils/format-branch.d.ts +4 -0
- package/dist/tui/features/vc/branch/utils/format-branch.js +12 -0
- package/dist/tui/features/vc/checkout/api/execute-vc-checkout.d.ts +8 -0
- package/dist/tui/features/vc/checkout/api/execute-vc-checkout.js +13 -0
- package/dist/tui/features/vc/checkout/components/vc-checkout-flow.d.ts +8 -0
- package/dist/tui/features/vc/checkout/components/vc-checkout-flow.js +33 -0
- package/dist/tui/features/vc/clone/api/execute-vc-clone.d.ts +8 -0
- package/dist/tui/features/vc/clone/api/execute-vc-clone.js +13 -0
- package/dist/tui/features/vc/clone/components/vc-clone-flow.d.ts +7 -0
- package/dist/tui/features/vc/clone/components/vc-clone-flow.js +79 -0
- package/dist/tui/features/vc/commit/api/execute-vc-commit.d.ts +8 -0
- package/dist/tui/features/vc/commit/api/execute-vc-commit.js +13 -0
- package/dist/tui/features/vc/commit/components/vc-commit-flow.d.ts +7 -0
- package/dist/tui/features/vc/commit/components/vc-commit-flow.js +29 -0
- package/dist/tui/features/vc/config/api/execute-vc-config.d.ts +8 -0
- package/dist/tui/features/vc/config/api/execute-vc-config.js +13 -0
- package/dist/tui/features/vc/config/components/vc-config-flow.d.ts +9 -0
- package/dist/tui/features/vc/config/components/vc-config-flow.js +30 -0
- package/dist/tui/features/vc/fetch/api/execute-vc-fetch.d.ts +8 -0
- package/dist/tui/features/vc/fetch/api/execute-vc-fetch.js +13 -0
- package/dist/tui/features/vc/fetch/components/vc-fetch-flow.d.ts +8 -0
- package/dist/tui/features/vc/fetch/components/vc-fetch-flow.js +75 -0
- package/dist/tui/features/vc/init/api/execute-vc-init.d.ts +8 -0
- package/dist/tui/features/vc/init/api/execute-vc-init.js +13 -0
- package/dist/tui/features/vc/init/components/vc-init-flow.d.ts +10 -0
- package/dist/tui/features/vc/init/components/vc-init-flow.js +37 -0
- package/dist/tui/features/vc/merge/api/execute-vc-merge.d.ts +8 -0
- package/dist/tui/features/vc/merge/api/execute-vc-merge.js +13 -0
- package/dist/tui/features/vc/merge/components/vc-merge-flow.d.ts +11 -0
- package/dist/tui/features/vc/merge/components/vc-merge-flow.js +72 -0
- package/dist/tui/features/vc/pull/api/execute-vc-pull.d.ts +8 -0
- package/dist/tui/features/vc/pull/api/execute-vc-pull.js +13 -0
- package/dist/tui/features/vc/pull/components/vc-pull-flow.d.ts +9 -0
- package/dist/tui/features/vc/pull/components/vc-pull-flow.js +83 -0
- package/dist/tui/features/vc/push/api/execute-vc-push.d.ts +8 -0
- package/dist/tui/features/vc/push/api/execute-vc-push.js +13 -0
- package/dist/tui/features/vc/push/components/vc-push-flow.d.ts +8 -0
- package/dist/tui/features/vc/push/components/vc-push-flow.js +83 -0
- package/dist/tui/features/vc/remote/api/execute-vc-remote.d.ts +8 -0
- package/dist/tui/features/vc/remote/api/execute-vc-remote.js +13 -0
- package/dist/tui/features/vc/remote/components/vc-remote-flow.d.ts +9 -0
- package/dist/tui/features/vc/remote/components/vc-remote-flow.js +42 -0
- package/dist/tui/features/vc/reset/api/execute-vc-reset.d.ts +8 -0
- package/dist/tui/features/vc/reset/api/execute-vc-reset.js +13 -0
- package/dist/tui/features/vc/reset/components/vc-reset-flow.d.ts +10 -0
- package/dist/tui/features/vc/reset/components/vc-reset-flow.js +63 -0
- package/dist/tui/features/vc/status/api/execute-vc-status.d.ts +8 -0
- package/dist/tui/features/vc/status/api/execute-vc-status.js +13 -0
- package/dist/tui/features/vc/status/components/vc-status-flow.d.ts +10 -0
- package/dist/tui/features/vc/status/components/vc-status-flow.js +133 -0
- package/dist/tui/lib/environment.d.ts +8 -0
- package/dist/tui/lib/environment.js +8 -0
- package/dist/tui/utils/error-messages.d.ts +5 -1
- package/dist/tui/utils/error-messages.js +32 -3
- package/oclif.manifest.json +1124 -204
- package/package.json +9 -3
- package/dist/oclif/hooks/prerun/validate-brv-config-version.d.ts +0 -33
- package/dist/oclif/hooks/prerun/validate-brv-config-version.js +0 -86
- package/dist/tui/components/init.d.ts +0 -33
- package/dist/tui/components/init.js +0 -234
- package/dist/tui/features/space/api/get-spaces.d.ts +0 -16
- package/dist/tui/features/space/api/get-spaces.js +0 -17
- package/dist/tui/features/space/api/switch-space.d.ts +0 -11
- package/dist/tui/features/space/api/switch-space.js +0 -24
- package/dist/tui/features/space/components/space-list-view.d.ts +0 -12
- package/dist/tui/features/space/components/space-list-view.js +0 -56
- package/dist/tui/features/space/components/space-switch-flow.d.ts +0 -13
- package/dist/tui/features/space/components/space-switch-flow.js +0 -97
|
@@ -29,24 +29,21 @@ export function computeSummary(operations) {
|
|
|
29
29
|
break;
|
|
30
30
|
}
|
|
31
31
|
case 'UPSERT': {
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
if (op.message?.includes('created new')) {
|
|
33
|
+
summary.added++;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
summary.updated++;
|
|
37
|
+
}
|
|
34
38
|
break;
|
|
35
39
|
}
|
|
36
40
|
}
|
|
37
41
|
}
|
|
38
42
|
return summary;
|
|
39
43
|
}
|
|
40
|
-
// ── CurateLogHandler ──────────────────────────────────────────────────────────
|
|
41
|
-
/**
|
|
42
|
-
* Lifecycle hook that transparently logs curate task execution.
|
|
43
|
-
*
|
|
44
|
-
* Wired into TaskRouter via lifecycleHooks[]. Writes log entries to
|
|
45
|
-
* per-project FileCurateLogStore. All I/O errors are swallowed — logging
|
|
46
|
-
* must never block or affect curate task execution.
|
|
47
|
-
*/
|
|
48
44
|
export class CurateLogHandler {
|
|
49
45
|
createStore;
|
|
46
|
+
onPendingReviews;
|
|
50
47
|
/** Active task count per projectPath — used to evict idle stores. */
|
|
51
48
|
activeTaskCount = new Map();
|
|
52
49
|
/** Per-project store cache (one store per projectPath). Evicted when no active tasks remain. */
|
|
@@ -55,9 +52,11 @@ export class CurateLogHandler {
|
|
|
55
52
|
tasks = new Map();
|
|
56
53
|
/**
|
|
57
54
|
* @param createStore - Optional factory for testing. Default: FileCurateLogStore.
|
|
55
|
+
* @param onPendingReviews - Optional callback fired when curate completes with pending review ops.
|
|
58
56
|
*/
|
|
59
|
-
constructor(createStore) {
|
|
57
|
+
constructor(createStore, onPendingReviews) {
|
|
60
58
|
this.createStore = createStore;
|
|
59
|
+
this.onPendingReviews = onPendingReviews;
|
|
61
60
|
}
|
|
62
61
|
cleanup(taskId) {
|
|
63
62
|
const state = this.tasks.get(taskId);
|
|
@@ -73,6 +72,18 @@ export class CurateLogHandler {
|
|
|
73
72
|
}
|
|
74
73
|
}
|
|
75
74
|
}
|
|
75
|
+
/**
|
|
76
|
+
* Synchronously returns the pending review count from in-memory state.
|
|
77
|
+
* Included in the task:completed payload so the client receives it atomically
|
|
78
|
+
* without relying on a separate review:notify event that arrives after disk I/O.
|
|
79
|
+
*/
|
|
80
|
+
getTaskCompletionData(taskId) {
|
|
81
|
+
const state = this.tasks.get(taskId);
|
|
82
|
+
if (!state)
|
|
83
|
+
return {};
|
|
84
|
+
const pendingReviewCount = state.operations.filter((op) => op.reviewStatus === 'pending').length;
|
|
85
|
+
return pendingReviewCount > 0 ? { pendingReviewCount } : {};
|
|
86
|
+
}
|
|
76
87
|
async onTaskCancelled(taskId, _task) {
|
|
77
88
|
const state = this.tasks.get(taskId);
|
|
78
89
|
if (!state)
|
|
@@ -89,7 +100,7 @@ export class CurateLogHandler {
|
|
|
89
100
|
transportLog(`CurateLogHandler: failed to save cancelled entry for ${taskId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
90
101
|
});
|
|
91
102
|
}
|
|
92
|
-
async onTaskCompleted(taskId, result,
|
|
103
|
+
async onTaskCompleted(taskId, result, task) {
|
|
93
104
|
const state = this.tasks.get(taskId);
|
|
94
105
|
if (!state)
|
|
95
106
|
return;
|
|
@@ -105,6 +116,18 @@ export class CurateLogHandler {
|
|
|
105
116
|
await store.save(updated).catch((error) => {
|
|
106
117
|
transportLog(`CurateLogHandler: failed to save completed entry for ${taskId}: ${error instanceof Error ? error.message : String(error)}`);
|
|
107
118
|
});
|
|
119
|
+
// Notify about pending reviews (fire-and-forget)
|
|
120
|
+
if (this.onPendingReviews) {
|
|
121
|
+
const pendingCount = state.operations.filter((op) => op.reviewStatus === 'pending').length;
|
|
122
|
+
if (pendingCount > 0) {
|
|
123
|
+
try {
|
|
124
|
+
this.onPendingReviews({ clientId: task.clientId, pendingCount, projectPath: state.projectPath, taskId });
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// Best-effort notification — never block task completion
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
}
|
|
108
131
|
}
|
|
109
132
|
async onTaskCreate(task) {
|
|
110
133
|
if (!CURATE_TASK_TYPES.includes(task.type))
|
|
@@ -163,7 +186,21 @@ export class CurateLogHandler {
|
|
|
163
186
|
if (!state)
|
|
164
187
|
return;
|
|
165
188
|
const ops = extractCurateOperations(payload);
|
|
166
|
-
|
|
189
|
+
for (const op of ops) {
|
|
190
|
+
if (op.needsReview && op.status === 'success') {
|
|
191
|
+
op.reviewStatus = 'pending';
|
|
192
|
+
}
|
|
193
|
+
// Deduplicate by filePath: keep only the latest operation per file.
|
|
194
|
+
// This ensures the reviewer sees the final version, not intermediate states.
|
|
195
|
+
if (op.filePath) {
|
|
196
|
+
const existingIndex = state.operations.findIndex((existing) => existing.filePath === op.filePath);
|
|
197
|
+
if (existingIndex !== -1) {
|
|
198
|
+
state.operations[existingIndex] = op;
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
state.operations.push(op);
|
|
203
|
+
}
|
|
167
204
|
}
|
|
168
205
|
// ── Private helpers ─────────────────────────────────────────────────────────
|
|
169
206
|
getOrCreateStore(projectPath) {
|
|
@@ -4,8 +4,12 @@
|
|
|
4
4
|
* Registers all feature handlers (auth, init, status, etc.) on the transport server.
|
|
5
5
|
* These handlers implement the TUI ↔ Server event contract.
|
|
6
6
|
*/
|
|
7
|
+
import { join } from 'node:path';
|
|
8
|
+
import { ReviewEvents } from '../../../shared/transport/events/review-events.js';
|
|
7
9
|
import { getAuthConfig } from '../../config/auth.config.js';
|
|
8
10
|
import { getCurrentConfig } from '../../config/environment.js';
|
|
11
|
+
import { BRV_DIR } from '../../constants.js';
|
|
12
|
+
import { getProjectDataDir } from '../../utils/path-utils.js';
|
|
9
13
|
import { OAuthService } from '../auth/oauth-service.js';
|
|
10
14
|
import { OidcDiscoveryService } from '../auth/oidc-discovery-service.js';
|
|
11
15
|
import { SystemBrowserLauncher } from '../browser/system-browser-launcher.js';
|
|
@@ -21,16 +25,20 @@ import { FileContextTreeService } from '../context-tree/file-context-tree-servic
|
|
|
21
25
|
import { FileContextTreeSnapshotService } from '../context-tree/file-context-tree-snapshot-service.js';
|
|
22
26
|
import { FileContextTreeWriterService } from '../context-tree/file-context-tree-writer-service.js';
|
|
23
27
|
import { FsFileService } from '../file/fs-file-service.js';
|
|
28
|
+
import { IsomorphicGitService } from '../git/isomorphic-git-service.js';
|
|
24
29
|
import { CallbackHandler } from '../http/callback-handler.js';
|
|
25
30
|
import { HubInstallService } from '../hub/hub-install-service.js';
|
|
26
31
|
import { createHubKeychainStore } from '../hub/hub-keychain-store.js';
|
|
27
32
|
import { HubRegistryConfigStore } from '../hub/hub-registry-config-store.js';
|
|
28
33
|
import { HttpSpaceService } from '../space/http-space-service.js';
|
|
34
|
+
import { FileCurateLogStore } from '../storage/file-curate-log-store.js';
|
|
35
|
+
import { FileReviewBackupStore } from '../storage/file-review-backup-store.js';
|
|
29
36
|
import { createTokenStore } from '../storage/token-store.js';
|
|
30
37
|
import { HttpTeamService } from '../team/http-team-service.js';
|
|
31
38
|
import { FsTemplateLoader } from '../template/fs-template-loader.js';
|
|
32
|
-
import { AuthHandler, ConfigHandler, ConnectorsHandler, HubHandler, InitHandler, LocationsHandler, ModelHandler, ProviderHandler, PullHandler, PushHandler, ResetHandler, SpaceHandler, StatusHandler, } from '../transport/handlers/index.js';
|
|
39
|
+
import { AuthHandler, ConfigHandler, ConnectorsHandler, HubHandler, InitHandler, LocationsHandler, ModelHandler, ProviderHandler, PullHandler, PushHandler, ResetHandler, ReviewHandler, SpaceHandler, StatusHandler, VcHandler, } from '../transport/handlers/index.js';
|
|
33
40
|
import { HttpUserService } from '../user/http-user-service.js';
|
|
41
|
+
import { FileVcGitConfigStore } from '../vc/file-vc-git-config-store.js';
|
|
34
42
|
/**
|
|
35
43
|
* Setup all feature handlers on the transport server.
|
|
36
44
|
* These handlers implement the TUI ↔ Server event contract (auth:*, config:*, status:*, etc.).
|
|
@@ -85,9 +93,11 @@ export async function setupFeatureHandlers({ authStateStore, broadcastToProject,
|
|
|
85
93
|
const templateService = new RuleTemplateService(templateLoader);
|
|
86
94
|
const connectorManagerFactory = (projectRoot) => new ConnectorManager({ fileService, projectRoot, templateService });
|
|
87
95
|
// Project-scoped handlers (receive resolveProjectPath for client → project resolution)
|
|
96
|
+
const gitService = new IsomorphicGitService(authStateStore);
|
|
88
97
|
new StatusHandler({
|
|
89
98
|
contextTreeService,
|
|
90
99
|
contextTreeSnapshotService,
|
|
100
|
+
curateLogStoreFactory: (projectPath) => new FileCurateLogStore({ baseDir: getProjectDataDir(projectPath) }),
|
|
91
101
|
projectConfigStore,
|
|
92
102
|
resolveProjectPath,
|
|
93
103
|
tokenStore,
|
|
@@ -104,9 +114,12 @@ export async function setupFeatureHandlers({ authStateStore, broadcastToProject,
|
|
|
104
114
|
broadcastToProject,
|
|
105
115
|
cogitPushService,
|
|
106
116
|
contextFileReader,
|
|
117
|
+
contextTreeService,
|
|
107
118
|
contextTreeSnapshotService,
|
|
119
|
+
curateLogStoreFactory: (projectPath) => new FileCurateLogStore({ baseDir: getProjectDataDir(projectPath) }),
|
|
108
120
|
projectConfigStore,
|
|
109
121
|
resolveProjectPath,
|
|
122
|
+
reviewBackupStoreFactory: (projectPath) => new FileReviewBackupStore(join(projectPath, BRV_DIR)),
|
|
110
123
|
tokenStore,
|
|
111
124
|
transport,
|
|
112
125
|
webAppUrl: envConfig.webAppUrl,
|
|
@@ -114,6 +127,7 @@ export async function setupFeatureHandlers({ authStateStore, broadcastToProject,
|
|
|
114
127
|
new PullHandler({
|
|
115
128
|
broadcastToProject,
|
|
116
129
|
cogitPullService,
|
|
130
|
+
contextTreeService,
|
|
117
131
|
contextTreeSnapshotService,
|
|
118
132
|
contextTreeWriterService,
|
|
119
133
|
projectConfigStore,
|
|
@@ -124,13 +138,25 @@ export async function setupFeatureHandlers({ authStateStore, broadcastToProject,
|
|
|
124
138
|
new ResetHandler({
|
|
125
139
|
contextTreeService,
|
|
126
140
|
contextTreeSnapshotService,
|
|
141
|
+
curateLogStoreFactory: (projectPath) => new FileCurateLogStore({ baseDir: getProjectDataDir(projectPath) }),
|
|
142
|
+
resolveProjectPath,
|
|
143
|
+
reviewBackupStoreFactory: (projectPath) => new FileReviewBackupStore(join(projectPath, BRV_DIR)),
|
|
144
|
+
transport,
|
|
145
|
+
}).setup();
|
|
146
|
+
new ReviewHandler({
|
|
147
|
+
curateLogStoreFactory: (projectPath) => new FileCurateLogStore({ baseDir: getProjectDataDir(projectPath) }),
|
|
148
|
+
onResolved({ projectPath, taskId }) {
|
|
149
|
+
broadcastToProject(projectPath, ReviewEvents.NOTIFY, { pendingCount: 0, reviewUrl: '', taskId });
|
|
150
|
+
},
|
|
127
151
|
resolveProjectPath,
|
|
152
|
+
reviewBackupStoreFactory: (projectPath) => new FileReviewBackupStore(join(projectPath, BRV_DIR)),
|
|
128
153
|
transport,
|
|
129
154
|
}).setup();
|
|
130
155
|
new SpaceHandler({
|
|
131
156
|
broadcastToProject,
|
|
132
157
|
cogitPullService,
|
|
133
158
|
contextTreeMerger,
|
|
159
|
+
contextTreeService,
|
|
134
160
|
contextTreeSnapshotService,
|
|
135
161
|
contextTreeWriterService,
|
|
136
162
|
projectConfigStore,
|
|
@@ -171,5 +197,19 @@ export async function setupFeatureHandlers({ authStateStore, broadcastToProject,
|
|
|
171
197
|
tokenStore,
|
|
172
198
|
transport,
|
|
173
199
|
}).setup();
|
|
200
|
+
new VcHandler({
|
|
201
|
+
broadcastToProject,
|
|
202
|
+
contextTreeService,
|
|
203
|
+
gitRemoteBaseUrl: envConfig.gitRemoteBaseUrl,
|
|
204
|
+
gitService,
|
|
205
|
+
projectConfigStore,
|
|
206
|
+
resolveProjectPath,
|
|
207
|
+
spaceService,
|
|
208
|
+
teamService,
|
|
209
|
+
tokenStore,
|
|
210
|
+
transport,
|
|
211
|
+
vcGitConfigStore: new FileVcGitConfigStore(),
|
|
212
|
+
webAppUrl: envConfig.webAppUrl,
|
|
213
|
+
}).setup();
|
|
174
214
|
log('Feature handlers registered');
|
|
175
215
|
}
|
|
@@ -171,15 +171,31 @@ export class TaskRouter {
|
|
|
171
171
|
const { result, taskId } = data;
|
|
172
172
|
const task = this.tasks.get(taskId);
|
|
173
173
|
transportLog(`Task completed: ${taskId}`);
|
|
174
|
+
// Collect synchronous completion data from hooks (e.g. pendingReviewCount from CurateLogHandler).
|
|
175
|
+
// This runs before task:completed is emitted so the client receives everything atomically,
|
|
176
|
+
// avoiding the race where review:notify would otherwise arrive after task:completed.
|
|
177
|
+
const hookData = {};
|
|
178
|
+
for (const hook of this.lifecycleHooks) {
|
|
179
|
+
if (hook.getTaskCompletionData) {
|
|
180
|
+
try {
|
|
181
|
+
Object.assign(hookData, hook.getTaskCompletionData(taskId));
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
// Best-effort: never block task:completed delivery
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
174
188
|
if (task) {
|
|
175
189
|
this.transport.sendTo(task.clientId, TransportTaskEventNames.COMPLETED, {
|
|
176
190
|
...(task.logId ? { logId: task.logId } : {}),
|
|
191
|
+
...hookData,
|
|
177
192
|
result,
|
|
178
193
|
taskId,
|
|
179
194
|
});
|
|
180
195
|
}
|
|
181
196
|
broadcastToProjectRoom(this.projectRegistry, this.projectRouter, task?.projectPath, TransportTaskEventNames.COMPLETED, {
|
|
182
197
|
...(task?.logId ? { logId: task.logId } : {}),
|
|
198
|
+
...hookData,
|
|
183
199
|
result,
|
|
184
200
|
taskId,
|
|
185
201
|
}, task?.clientId);
|
|
@@ -67,8 +67,10 @@ export class HttpSpaceService {
|
|
|
67
67
|
id: spaceData.id,
|
|
68
68
|
isDefault: spaceData.is_default,
|
|
69
69
|
name: spaceData.name,
|
|
70
|
+
slug: spaceData.slug,
|
|
70
71
|
teamId: spaceData.team_id,
|
|
71
72
|
teamName: spaceData.team.name,
|
|
73
|
+
teamSlug: spaceData.team.slug,
|
|
72
74
|
});
|
|
73
75
|
}
|
|
74
76
|
}
|
|
@@ -18,6 +18,10 @@ export declare class FileCurateLogStore implements ICurateLogStore {
|
|
|
18
18
|
private readonly logDir;
|
|
19
19
|
private readonly maxEntries;
|
|
20
20
|
constructor(opts: FileCurateLogStoreOptions);
|
|
21
|
+
batchUpdateOperationReviewStatus(logId: string, updates: Array<{
|
|
22
|
+
operationIndex: number;
|
|
23
|
+
reviewStatus: 'approved' | 'rejected';
|
|
24
|
+
}>): Promise<boolean>;
|
|
21
25
|
/**
|
|
22
26
|
* Retrieve an entry by ID. Returns null if:
|
|
23
27
|
* - ID format is invalid (security: prevents path traversal)
|
|
@@ -49,6 +53,12 @@ export declare class FileCurateLogStore implements ICurateLogStore {
|
|
|
49
53
|
* After saving, prunes oldest entries if count exceeds maxEntries (best-effort).
|
|
50
54
|
*/
|
|
51
55
|
save(entry: CurateLogEntry): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Update the reviewStatus of a specific operation within a log entry.
|
|
58
|
+
* Reads the entry, updates the operation at the given index, and saves back atomically.
|
|
59
|
+
* Returns false if the entry or operation index is not found.
|
|
60
|
+
*/
|
|
61
|
+
updateOperationReviewStatus(logId: string, operationIndex: number, reviewStatus: 'approved' | 'rejected'): Promise<boolean>;
|
|
52
62
|
private entryPath;
|
|
53
63
|
private pruneOldest;
|
|
54
64
|
/**
|
|
@@ -5,10 +5,18 @@ import { z } from 'zod';
|
|
|
5
5
|
import { CURATE_LOG_DIR, CURATE_LOG_ID_PREFIX } from '../../constants.js';
|
|
6
6
|
// ── Zod schema for file validation ────────────────────────────────────────────
|
|
7
7
|
const CurateLogOperationFileSchema = z.object({
|
|
8
|
+
additionalFilePaths: z.array(z.string()).optional(),
|
|
9
|
+
confidence: z.enum(['high', 'low']).optional(),
|
|
8
10
|
filePath: z.string().optional(),
|
|
11
|
+
impact: z.enum(['high', 'low']).optional(),
|
|
9
12
|
message: z.string().optional(),
|
|
13
|
+
needsReview: z.boolean().optional(),
|
|
10
14
|
path: z.string(),
|
|
15
|
+
previousSummary: z.string().optional(),
|
|
16
|
+
reason: z.string().optional(),
|
|
17
|
+
reviewStatus: z.enum(['approved', 'pending', 'rejected']).optional(),
|
|
11
18
|
status: z.enum(['failed', 'success']),
|
|
19
|
+
summary: z.string().optional(),
|
|
12
20
|
type: z.enum(['ADD', 'DELETE', 'MERGE', 'UPDATE', 'UPSERT']),
|
|
13
21
|
});
|
|
14
22
|
const CurateLogSummaryFileSchema = z.object({
|
|
@@ -69,6 +77,18 @@ export class FileCurateLogStore {
|
|
|
69
77
|
this.logDir = join(opts.baseDir, CURATE_LOG_DIR);
|
|
70
78
|
this.maxEntries = opts.maxEntries ?? DEFAULT_MAX_ENTRIES;
|
|
71
79
|
}
|
|
80
|
+
async batchUpdateOperationReviewStatus(logId, updates) {
|
|
81
|
+
const entry = await this.getById(logId);
|
|
82
|
+
if (!entry)
|
|
83
|
+
return false;
|
|
84
|
+
for (const { operationIndex, reviewStatus } of updates) {
|
|
85
|
+
if (operationIndex < 0 || operationIndex >= entry.operations.length)
|
|
86
|
+
continue;
|
|
87
|
+
entry.operations[operationIndex].reviewStatus = reviewStatus;
|
|
88
|
+
}
|
|
89
|
+
await this.save(entry);
|
|
90
|
+
return true;
|
|
91
|
+
}
|
|
72
92
|
/**
|
|
73
93
|
* Retrieve an entry by ID. Returns null if:
|
|
74
94
|
* - ID format is invalid (security: prevents path traversal)
|
|
@@ -159,6 +179,21 @@ export class FileCurateLogStore {
|
|
|
159
179
|
// Prune oldest entries (best-effort — ignore errors)
|
|
160
180
|
this.pruneOldest().catch(() => { });
|
|
161
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* Update the reviewStatus of a specific operation within a log entry.
|
|
184
|
+
* Reads the entry, updates the operation at the given index, and saves back atomically.
|
|
185
|
+
* Returns false if the entry or operation index is not found.
|
|
186
|
+
*/
|
|
187
|
+
async updateOperationReviewStatus(logId, operationIndex, reviewStatus) {
|
|
188
|
+
const entry = await this.getById(logId);
|
|
189
|
+
if (!entry)
|
|
190
|
+
return false;
|
|
191
|
+
if (operationIndex < 0 || operationIndex >= entry.operations.length)
|
|
192
|
+
return false;
|
|
193
|
+
entry.operations[operationIndex].reviewStatus = reviewStatus;
|
|
194
|
+
await this.save(entry);
|
|
195
|
+
return true;
|
|
196
|
+
}
|
|
162
197
|
// ── Private helpers ─────────────────────────────────────────────────────────
|
|
163
198
|
entryPath(id) {
|
|
164
199
|
return join(this.logDir, `${id}.json`);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { IReviewBackupStore } from '../../core/interfaces/storage/i-review-backup-store.js';
|
|
2
|
+
/**
|
|
3
|
+
* File-based implementation of IReviewBackupStore.
|
|
4
|
+
*
|
|
5
|
+
* Stores pre-curate file content in {projectBrvDir}/review-backups/{relativePath}.
|
|
6
|
+
* The directory mirrors the context tree structure.
|
|
7
|
+
*
|
|
8
|
+
* First-write-wins: once a backup exists for a path, subsequent save() calls are no-ops.
|
|
9
|
+
* This ensures the backup always reflects the state at the time of the last push (snapshot version).
|
|
10
|
+
*/
|
|
11
|
+
export declare class FileReviewBackupStore implements IReviewBackupStore {
|
|
12
|
+
private readonly backupDir;
|
|
13
|
+
constructor(brvDir: string);
|
|
14
|
+
clear(): Promise<void>;
|
|
15
|
+
delete(relativePath: string): Promise<void>;
|
|
16
|
+
has(relativePath: string): Promise<boolean>;
|
|
17
|
+
/**
|
|
18
|
+
* List all backed-up file paths (relative to backup dir).
|
|
19
|
+
* Useful for the review UI to enumerate all files with backups.
|
|
20
|
+
*/
|
|
21
|
+
list(): Promise<string[]>;
|
|
22
|
+
read(relativePath: string): Promise<null | string>;
|
|
23
|
+
save(relativePath: string, content: string): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Remove empty ancestor directories up to and including the backup root.
|
|
26
|
+
* Called after each file deletion to keep the directory tree clean.
|
|
27
|
+
*/
|
|
28
|
+
private pruneEmptyDirs;
|
|
29
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { mkdir, readdir, readFile, rename, rm, stat, writeFile } from 'node:fs/promises';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
import { REVIEW_BACKUPS_DIR } from '../../constants.js';
|
|
4
|
+
/**
|
|
5
|
+
* File-based implementation of IReviewBackupStore.
|
|
6
|
+
*
|
|
7
|
+
* Stores pre-curate file content in {projectBrvDir}/review-backups/{relativePath}.
|
|
8
|
+
* The directory mirrors the context tree structure.
|
|
9
|
+
*
|
|
10
|
+
* First-write-wins: once a backup exists for a path, subsequent save() calls are no-ops.
|
|
11
|
+
* This ensures the backup always reflects the state at the time of the last push (snapshot version).
|
|
12
|
+
*/
|
|
13
|
+
export class FileReviewBackupStore {
|
|
14
|
+
backupDir;
|
|
15
|
+
constructor(brvDir) {
|
|
16
|
+
this.backupDir = join(brvDir, REVIEW_BACKUPS_DIR);
|
|
17
|
+
}
|
|
18
|
+
async clear() {
|
|
19
|
+
try {
|
|
20
|
+
await rm(this.backupDir, { force: true, recursive: true });
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
// Directory may not exist — that's fine
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async delete(relativePath) {
|
|
27
|
+
const absPath = join(this.backupDir, relativePath);
|
|
28
|
+
try {
|
|
29
|
+
await rm(absPath);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// File may not exist — that's fine
|
|
33
|
+
}
|
|
34
|
+
await this.pruneEmptyDirs(dirname(absPath));
|
|
35
|
+
}
|
|
36
|
+
async has(relativePath) {
|
|
37
|
+
try {
|
|
38
|
+
await stat(join(this.backupDir, relativePath));
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* List all backed-up file paths (relative to backup dir).
|
|
47
|
+
* Useful for the review UI to enumerate all files with backups.
|
|
48
|
+
*/
|
|
49
|
+
async list() {
|
|
50
|
+
const paths = [];
|
|
51
|
+
const scan = async (dir, prefix) => {
|
|
52
|
+
let entries;
|
|
53
|
+
try {
|
|
54
|
+
entries = await readdir(dir, { withFileTypes: true });
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const subdirTasks = [];
|
|
60
|
+
for (const entry of entries) {
|
|
61
|
+
const relativePath = prefix ? `${prefix}/${entry.name}` : entry.name;
|
|
62
|
+
if (entry.isDirectory()) {
|
|
63
|
+
subdirTasks.push(scan(join(dir, entry.name), relativePath));
|
|
64
|
+
}
|
|
65
|
+
else if (entry.isFile() && !entry.name.endsWith('.tmp')) {
|
|
66
|
+
paths.push(relativePath);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
await Promise.all(subdirTasks);
|
|
70
|
+
};
|
|
71
|
+
await scan(this.backupDir, '');
|
|
72
|
+
return paths;
|
|
73
|
+
}
|
|
74
|
+
async read(relativePath) {
|
|
75
|
+
try {
|
|
76
|
+
return await readFile(join(this.backupDir, relativePath), 'utf8');
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async save(relativePath, content) {
|
|
83
|
+
const backupPath = join(this.backupDir, relativePath);
|
|
84
|
+
// First-write-wins: skip if backup already exists
|
|
85
|
+
if (await this.has(relativePath))
|
|
86
|
+
return;
|
|
87
|
+
await mkdir(dirname(backupPath), { recursive: true });
|
|
88
|
+
// Write atomically: write to a .tmp sibling then rename so a crash mid-write
|
|
89
|
+
// never leaves a partial (corrupt) backup that first-write-wins would preserve.
|
|
90
|
+
const tmpPath = `${backupPath}.tmp`;
|
|
91
|
+
try {
|
|
92
|
+
await writeFile(tmpPath, content, 'utf8');
|
|
93
|
+
await rename(tmpPath, backupPath);
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
await rm(tmpPath, { force: true }).catch(() => { });
|
|
97
|
+
throw error;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Remove empty ancestor directories up to and including the backup root.
|
|
102
|
+
* Called after each file deletion to keep the directory tree clean.
|
|
103
|
+
*/
|
|
104
|
+
async pruneEmptyDirs(startDir) {
|
|
105
|
+
let dir = startDir;
|
|
106
|
+
while (dir.startsWith(this.backupDir) && dir !== this.backupDir) {
|
|
107
|
+
try {
|
|
108
|
+
// eslint-disable-next-line no-await-in-loop
|
|
109
|
+
const entries = await readdir(dir);
|
|
110
|
+
if (entries.length > 0)
|
|
111
|
+
return;
|
|
112
|
+
// eslint-disable-next-line no-await-in-loop
|
|
113
|
+
await rm(dir, { recursive: true });
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
dir = dirname(dir);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -50,7 +50,7 @@ export class AuthHandler {
|
|
|
50
50
|
const user = await this.userService.getCurrentUser(token.sessionKey);
|
|
51
51
|
this.transport.broadcast(AuthEvents.STATE_CHANGED, {
|
|
52
52
|
isAuthorized: true,
|
|
53
|
-
user: { email: user.email, hasOnboardedCli: user.hasOnboardedCli, id: user.id },
|
|
53
|
+
user: { email: user.email, hasOnboardedCli: user.hasOnboardedCli, id: user.id, name: user.name },
|
|
54
54
|
});
|
|
55
55
|
}
|
|
56
56
|
catch {
|
|
@@ -73,15 +73,16 @@ export class AuthHandler {
|
|
|
73
73
|
tokenType: tokenData.tokenType,
|
|
74
74
|
userEmail: user.email,
|
|
75
75
|
userId: user.id,
|
|
76
|
+
userName: user.name,
|
|
76
77
|
});
|
|
77
78
|
await this.tokenStore.save(authToken);
|
|
78
79
|
this.transport.broadcast(AuthEvents.LOGIN_COMPLETED, {
|
|
79
80
|
success: true,
|
|
80
|
-
user: { email: user.email, hasOnboardedCli: user.hasOnboardedCli, id: user.id },
|
|
81
|
+
user: { email: user.email, hasOnboardedCli: user.hasOnboardedCli, id: user.id, name: user.name },
|
|
81
82
|
});
|
|
82
83
|
this.transport.broadcast(AuthEvents.STATE_CHANGED, {
|
|
83
84
|
isAuthorized: true,
|
|
84
|
-
user: { email: user.email, hasOnboardedCli: user.hasOnboardedCli, id: user.id },
|
|
85
|
+
user: { email: user.email, hasOnboardedCli: user.hasOnboardedCli, id: user.id, name: user.name },
|
|
85
86
|
});
|
|
86
87
|
}
|
|
87
88
|
catch (error) {
|
|
@@ -152,6 +153,7 @@ export class AuthHandler {
|
|
|
152
153
|
email: user.email,
|
|
153
154
|
hasOnboardedCli: user.hasOnboardedCli,
|
|
154
155
|
id: user.id,
|
|
156
|
+
name: user.name,
|
|
155
157
|
},
|
|
156
158
|
};
|
|
157
159
|
}
|
|
@@ -172,11 +174,12 @@ export class AuthHandler {
|
|
|
172
174
|
tokenType: 'unnecessary',
|
|
173
175
|
userEmail: user.email,
|
|
174
176
|
userId: user.id,
|
|
177
|
+
userName: user.name,
|
|
175
178
|
});
|
|
176
179
|
await this.tokenStore.save(authToken);
|
|
177
180
|
this.transport.broadcast(AuthEvents.STATE_CHANGED, {
|
|
178
181
|
isAuthorized: true,
|
|
179
|
-
user: { email: user.email, hasOnboardedCli: user.hasOnboardedCli, id: user.id },
|
|
182
|
+
user: { email: user.email, hasOnboardedCli: user.hasOnboardedCli, id: user.id, name: user.name },
|
|
180
183
|
});
|
|
181
184
|
return { success: true, userEmail: user.email };
|
|
182
185
|
}
|
|
@@ -214,11 +217,12 @@ export class AuthHandler {
|
|
|
214
217
|
tokenType: refreshedTokenData.tokenType,
|
|
215
218
|
userEmail: user.email,
|
|
216
219
|
userId: user.id,
|
|
220
|
+
userName: user.name,
|
|
217
221
|
});
|
|
218
222
|
await this.tokenStore.save(newToken);
|
|
219
223
|
this.transport.broadcast(AuthEvents.STATE_CHANGED, {
|
|
220
224
|
isAuthorized: true,
|
|
221
|
-
user: { email: user.email, hasOnboardedCli: user.hasOnboardedCli, id: user.id },
|
|
225
|
+
user: { email: user.email, hasOnboardedCli: user.hasOnboardedCli, id: user.id, name: user.name },
|
|
222
226
|
});
|
|
223
227
|
return { success: true };
|
|
224
228
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ContextTreeChanges } from '../../../../shared/types/context-tree-changes.js';
|
|
2
|
+
import type { IContextTreeService } from '../../../core/interfaces/context-tree/i-context-tree-service.js';
|
|
2
3
|
/**
|
|
3
4
|
* Resolves a transport client ID to its associated project path.
|
|
4
5
|
* Returns undefined for global-scope clients that haven't been associated with a project.
|
|
@@ -21,3 +22,11 @@ export type ProjectBroadcaster = <T = unknown>(projectPath: string, event: strin
|
|
|
21
22
|
* Returns true if the changes object has any additions, modifications, or deletions.
|
|
22
23
|
*/
|
|
23
24
|
export declare function hasAnyChanges(changes: ContextTreeChanges): boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Throws GitVcInitializedError if the project has ByteRover version control initialized.
|
|
27
|
+
* Used by old snapshot-based handlers to block operations when the user has switched to /vc commands.
|
|
28
|
+
*/
|
|
29
|
+
export declare function guardAgainstGitVc(params: {
|
|
30
|
+
contextTreeService: IContextTreeService;
|
|
31
|
+
projectPath: string;
|
|
32
|
+
}): Promise<void>;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { GitVcInitializedError } from '../../../core/domain/errors/task-error.js';
|
|
1
2
|
/**
|
|
2
3
|
* Resolves the project path for a client, throwing if unavailable.
|
|
3
4
|
* Use this in handlers that REQUIRE a project context.
|
|
@@ -19,3 +20,13 @@ export function resolveRequiredProjectPath(resolver, clientId) {
|
|
|
19
20
|
export function hasAnyChanges(changes) {
|
|
20
21
|
return changes.added.length > 0 || changes.modified.length > 0 || changes.deleted.length > 0;
|
|
21
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Throws GitVcInitializedError if the project has ByteRover version control initialized.
|
|
25
|
+
* Used by old snapshot-based handlers to block operations when the user has switched to /vc commands.
|
|
26
|
+
*/
|
|
27
|
+
export async function guardAgainstGitVc(params) {
|
|
28
|
+
const hasGitVc = await params.contextTreeService.hasGitRepo(params.projectPath);
|
|
29
|
+
if (hasGitVc) {
|
|
30
|
+
throw new GitVcInitializedError('ByteRover version control is initialized');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -22,7 +22,11 @@ export { PushHandler } from './push-handler.js';
|
|
|
22
22
|
export type { PushHandlerDeps } from './push-handler.js';
|
|
23
23
|
export { ResetHandler } from './reset-handler.js';
|
|
24
24
|
export type { ResetHandlerDeps } from './reset-handler.js';
|
|
25
|
+
export { ReviewHandler } from './review-handler.js';
|
|
26
|
+
export type { ReviewHandlerDeps } from './review-handler.js';
|
|
25
27
|
export { SpaceHandler } from './space-handler.js';
|
|
26
28
|
export type { SpaceHandlerDeps } from './space-handler.js';
|
|
27
29
|
export { StatusHandler } from './status-handler.js';
|
|
28
30
|
export type { StatusHandlerDeps } from './status-handler.js';
|
|
31
|
+
export { VcHandler } from './vc-handler.js';
|
|
32
|
+
export type { IVcHandlerDeps } from './vc-handler.js';
|
|
@@ -10,5 +10,7 @@ export { ProviderHandler } from './provider-handler.js';
|
|
|
10
10
|
export { PullHandler } from './pull-handler.js';
|
|
11
11
|
export { PushHandler } from './push-handler.js';
|
|
12
12
|
export { ResetHandler } from './reset-handler.js';
|
|
13
|
+
export { ReviewHandler } from './review-handler.js';
|
|
13
14
|
export { SpaceHandler } from './space-handler.js';
|
|
14
15
|
export { StatusHandler } from './status-handler.js';
|
|
16
|
+
export { VcHandler } from './vc-handler.js';
|