byterover-cli 2.6.0 → 3.0.1
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 +1018 -98
- 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
|
@@ -0,0 +1,606 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the complete HTML page for the local HITL review UI.
|
|
3
|
+
*
|
|
4
|
+
* Self-contained: all CSS and JS are inline. No external dependencies.
|
|
5
|
+
* Shows semantic summaries of previous/current versions for each operation.
|
|
6
|
+
*/
|
|
7
|
+
export function getReviewPageHtml() {
|
|
8
|
+
return `<!DOCTYPE html>
|
|
9
|
+
<html lang="en">
|
|
10
|
+
<head>
|
|
11
|
+
<meta charset="utf-8">
|
|
12
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
13
|
+
<title>ByteRover Review</title>
|
|
14
|
+
<style>
|
|
15
|
+
:root {
|
|
16
|
+
--bg: #0d1117;
|
|
17
|
+
--bg-secondary: #161b22;
|
|
18
|
+
--bg-tertiary: #21262d;
|
|
19
|
+
--border: #30363d;
|
|
20
|
+
--text: #e6edf3;
|
|
21
|
+
--text-muted: #8b949e;
|
|
22
|
+
--green: #238636;
|
|
23
|
+
--green-bg: rgba(46, 160, 67, 0.15);
|
|
24
|
+
--red: #da3633;
|
|
25
|
+
--red-bg: rgba(248, 81, 73, 0.1);
|
|
26
|
+
--blue: #58a6ff;
|
|
27
|
+
--yellow: #d29922;
|
|
28
|
+
--font-mono: 'SF Mono', 'Fira Code', 'Cascadia Code', Menlo, Consolas, monospace;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
* { box-sizing: border-box; margin: 0; padding: 0; }
|
|
32
|
+
|
|
33
|
+
body {
|
|
34
|
+
background: var(--bg);
|
|
35
|
+
color: var(--text);
|
|
36
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif;
|
|
37
|
+
font-size: 14px;
|
|
38
|
+
line-height: 1.5;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
header {
|
|
42
|
+
background: var(--bg-secondary);
|
|
43
|
+
border-bottom: 1px solid var(--border);
|
|
44
|
+
padding: 12px 24px;
|
|
45
|
+
display: flex;
|
|
46
|
+
align-items: center;
|
|
47
|
+
gap: 12px;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
header h1 {
|
|
51
|
+
font-size: 18px;
|
|
52
|
+
font-weight: 600;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
header .badge {
|
|
56
|
+
background: var(--yellow);
|
|
57
|
+
color: var(--bg);
|
|
58
|
+
font-size: 12px;
|
|
59
|
+
font-weight: 600;
|
|
60
|
+
padding: 2px 8px;
|
|
61
|
+
border-radius: 10px;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.container {
|
|
65
|
+
max-width: 1200px;
|
|
66
|
+
margin: 0 auto;
|
|
67
|
+
padding: 24px;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
.loading, .empty, .error {
|
|
71
|
+
text-align: center;
|
|
72
|
+
padding: 48px 24px;
|
|
73
|
+
color: var(--text-muted);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
.error { color: var(--red); }
|
|
77
|
+
|
|
78
|
+
.file-card {
|
|
79
|
+
background: var(--bg-secondary);
|
|
80
|
+
border: 1px solid var(--border);
|
|
81
|
+
border-radius: 6px;
|
|
82
|
+
margin-bottom: 16px;
|
|
83
|
+
overflow: hidden;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.file-header {
|
|
87
|
+
display: flex;
|
|
88
|
+
align-items: center;
|
|
89
|
+
justify-content: space-between;
|
|
90
|
+
padding: 12px 16px;
|
|
91
|
+
border-bottom: 1px solid var(--border);
|
|
92
|
+
user-select: none;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.file-path {
|
|
96
|
+
font-family: var(--font-mono);
|
|
97
|
+
font-size: 13px;
|
|
98
|
+
font-weight: 500;
|
|
99
|
+
color: var(--blue);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
.file-meta {
|
|
103
|
+
display: flex;
|
|
104
|
+
align-items: center;
|
|
105
|
+
gap: 8px;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
.op-badge {
|
|
109
|
+
font-size: 11px;
|
|
110
|
+
font-weight: 600;
|
|
111
|
+
padding: 2px 6px;
|
|
112
|
+
border-radius: 4px;
|
|
113
|
+
text-transform: uppercase;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
.op-badge.DELETE { background: var(--red-bg); color: var(--red); }
|
|
117
|
+
.op-badge.UPDATE, .op-badge.UPSERT { background: var(--green-bg); color: var(--green); }
|
|
118
|
+
.op-badge.MERGE { background: rgba(88, 166, 255, 0.15); color: var(--blue); }
|
|
119
|
+
.op-badge.ADD { background: var(--green-bg); color: var(--green); }
|
|
120
|
+
|
|
121
|
+
.reason-text {
|
|
122
|
+
font-size: 12px;
|
|
123
|
+
color: var(--text-muted);
|
|
124
|
+
margin-left: 8px;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
.actions {
|
|
128
|
+
display: flex;
|
|
129
|
+
gap: 8px;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
.btn {
|
|
133
|
+
border: none;
|
|
134
|
+
border-radius: 6px;
|
|
135
|
+
cursor: pointer;
|
|
136
|
+
font-size: 13px;
|
|
137
|
+
font-weight: 500;
|
|
138
|
+
padding: 6px 16px;
|
|
139
|
+
transition: opacity 0.15s;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.btn:hover { opacity: 0.85; }
|
|
143
|
+
.btn:disabled { opacity: 0.4; cursor: not-allowed; }
|
|
144
|
+
|
|
145
|
+
.btn-approve {
|
|
146
|
+
background: var(--green);
|
|
147
|
+
color: #fff;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.btn-reject {
|
|
151
|
+
background: var(--red);
|
|
152
|
+
color: #fff;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
.btn-secondary {
|
|
156
|
+
background: var(--bg-tertiary);
|
|
157
|
+
border: 1px solid var(--border);
|
|
158
|
+
color: var(--text);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.summary-content {
|
|
162
|
+
padding: 12px 16px;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
.summary-block {
|
|
166
|
+
padding: 8px 12px;
|
|
167
|
+
border-radius: 4px;
|
|
168
|
+
margin-bottom: 8px;
|
|
169
|
+
font-size: 13px;
|
|
170
|
+
line-height: 1.6;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
.summary-block:last-child {
|
|
174
|
+
margin-bottom: 0;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
.summary-block.previous {
|
|
178
|
+
background: var(--red-bg);
|
|
179
|
+
border-left: 3px solid var(--red);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
.summary-block.current {
|
|
183
|
+
background: var(--green-bg);
|
|
184
|
+
border-left: 3px solid var(--green);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
.summary-label {
|
|
188
|
+
font-size: 11px;
|
|
189
|
+
font-weight: 600;
|
|
190
|
+
text-transform: uppercase;
|
|
191
|
+
letter-spacing: 0.5px;
|
|
192
|
+
margin-bottom: 2px;
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
.summary-block.previous .summary-label { color: var(--red); }
|
|
196
|
+
.summary-block.current .summary-label { color: var(--green); }
|
|
197
|
+
|
|
198
|
+
.summary-text {
|
|
199
|
+
color: var(--text);
|
|
200
|
+
white-space: pre-line;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
.no-summary {
|
|
204
|
+
color: var(--text-muted);
|
|
205
|
+
font-style: italic;
|
|
206
|
+
font-size: 13px;
|
|
207
|
+
padding: 8px 12px;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
.decided {
|
|
211
|
+
padding: 16px;
|
|
212
|
+
text-align: center;
|
|
213
|
+
font-weight: 500;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
.decided.approved { color: var(--green); }
|
|
217
|
+
.decided.rejected { color: var(--red); }
|
|
218
|
+
|
|
219
|
+
.summary-bar {
|
|
220
|
+
display: flex;
|
|
221
|
+
gap: 16px;
|
|
222
|
+
padding: 12px 0;
|
|
223
|
+
color: var(--text-muted);
|
|
224
|
+
font-size: 13px;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
.bulk-actions {
|
|
228
|
+
display: flex;
|
|
229
|
+
gap: 8px;
|
|
230
|
+
margin-bottom: 16px;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/* ── Diff styles (retained for future use) ─────────────────────────── */
|
|
234
|
+
|
|
235
|
+
.diff-container {
|
|
236
|
+
overflow-x: auto;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
.diff-loading {
|
|
240
|
+
padding: 16px;
|
|
241
|
+
color: var(--text-muted);
|
|
242
|
+
font-style: italic;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
table.diff {
|
|
246
|
+
width: 100%;
|
|
247
|
+
border-collapse: collapse;
|
|
248
|
+
font-family: var(--font-mono);
|
|
249
|
+
font-size: 12px;
|
|
250
|
+
line-height: 20px;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
table.diff td {
|
|
254
|
+
padding: 0 12px;
|
|
255
|
+
white-space: pre-wrap;
|
|
256
|
+
word-break: break-all;
|
|
257
|
+
vertical-align: top;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
table.diff .line-num {
|
|
261
|
+
color: var(--text-muted);
|
|
262
|
+
text-align: right;
|
|
263
|
+
width: 50px;
|
|
264
|
+
min-width: 50px;
|
|
265
|
+
user-select: none;
|
|
266
|
+
padding: 0 8px;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
table.diff tr.added { background: var(--green-bg); }
|
|
270
|
+
table.diff tr.removed { background: var(--red-bg); }
|
|
271
|
+
table.diff tr.context { background: transparent; }
|
|
272
|
+
|
|
273
|
+
table.diff tr.added .line-num { color: var(--green); }
|
|
274
|
+
table.diff tr.removed .line-num { color: var(--red); }
|
|
275
|
+
|
|
276
|
+
table.diff .marker {
|
|
277
|
+
width: 20px;
|
|
278
|
+
min-width: 20px;
|
|
279
|
+
text-align: center;
|
|
280
|
+
user-select: none;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
table.diff tr.added .marker { color: var(--green); }
|
|
284
|
+
table.diff tr.removed .marker { color: var(--red); }
|
|
285
|
+
</style>
|
|
286
|
+
</head>
|
|
287
|
+
<body>
|
|
288
|
+
<header>
|
|
289
|
+
<h1>ByteRover Review</h1>
|
|
290
|
+
<span class="badge" id="pending-count">...</span>
|
|
291
|
+
</header>
|
|
292
|
+
|
|
293
|
+
<div class="container">
|
|
294
|
+
<div id="summary-bar" class="summary-bar"></div>
|
|
295
|
+
<div id="bulk-actions" class="bulk-actions" style="display:none">
|
|
296
|
+
<button class="btn btn-approve" onclick="bulkDecide('approved')">Approve All</button>
|
|
297
|
+
<button class="btn btn-reject" onclick="bulkDecide('rejected')">Reject All</button>
|
|
298
|
+
</div>
|
|
299
|
+
<div id="content">
|
|
300
|
+
<div class="loading">Loading pending reviews...</div>
|
|
301
|
+
</div>
|
|
302
|
+
</div>
|
|
303
|
+
|
|
304
|
+
<script>
|
|
305
|
+
// ── State ──────────────────────────────────────────────────────────────────
|
|
306
|
+
|
|
307
|
+
const params = new URLSearchParams(window.location.search);
|
|
308
|
+
const project = params.get('project') || '';
|
|
309
|
+
let fileData = [];
|
|
310
|
+
|
|
311
|
+
// ── Diff algorithm (retained for future use — currently un-wired) ───────
|
|
312
|
+
|
|
313
|
+
function computeLineDiff(oldText, newText) {
|
|
314
|
+
const oldLines = oldText.split('\\n');
|
|
315
|
+
const newLines = newText.split('\\n');
|
|
316
|
+
const m = oldLines.length;
|
|
317
|
+
const n = newLines.length;
|
|
318
|
+
|
|
319
|
+
// Build LCS table
|
|
320
|
+
const dp = Array.from({length: m + 1}, () => new Array(n + 1).fill(0));
|
|
321
|
+
for (let i = 1; i <= m; i++) {
|
|
322
|
+
for (let j = 1; j <= n; j++) {
|
|
323
|
+
dp[i][j] = oldLines[i-1] === newLines[j-1]
|
|
324
|
+
? dp[i-1][j-1] + 1
|
|
325
|
+
: Math.max(dp[i-1][j], dp[i][j-1]);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
// Backtrack to get diff
|
|
330
|
+
const result = [];
|
|
331
|
+
let i = m, j = n;
|
|
332
|
+
while (i > 0 || j > 0) {
|
|
333
|
+
if (i > 0 && j > 0 && oldLines[i-1] === newLines[j-1]) {
|
|
334
|
+
result.unshift({type: 'context', oldNum: i, newNum: j, text: oldLines[i-1]});
|
|
335
|
+
i--; j--;
|
|
336
|
+
} else if (j > 0 && (i === 0 || dp[i][j-1] >= dp[i-1][j])) {
|
|
337
|
+
result.unshift({type: 'added', oldNum: null, newNum: j, text: newLines[j-1]});
|
|
338
|
+
j--;
|
|
339
|
+
} else {
|
|
340
|
+
result.unshift({type: 'removed', oldNum: i, newNum: null, text: oldLines[i-1]});
|
|
341
|
+
i--;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return result;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
function renderDiff(diffLines) {
|
|
349
|
+
if (diffLines.length === 0) {
|
|
350
|
+
return '<div class="diff-loading">No changes detected</div>';
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
let html = '<table class="diff">';
|
|
354
|
+
for (const line of diffLines) {
|
|
355
|
+
const cls = line.type;
|
|
356
|
+
const marker = line.type === 'added' ? '+' : line.type === 'removed' ? '-' : ' ';
|
|
357
|
+
const oldN = line.oldNum ?? '';
|
|
358
|
+
const newN = line.newNum ?? '';
|
|
359
|
+
const escaped = escapeHtml(line.text);
|
|
360
|
+
html += '<tr class="' + cls + '">'
|
|
361
|
+
+ '<td class="line-num">' + oldN + '</td>'
|
|
362
|
+
+ '<td class="line-num">' + newN + '</td>'
|
|
363
|
+
+ '<td class="marker">' + marker + '</td>'
|
|
364
|
+
+ '<td>' + escaped + '</td>'
|
|
365
|
+
+ '</tr>';
|
|
366
|
+
}
|
|
367
|
+
html += '</table>';
|
|
368
|
+
return html;
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// ── Utilities ───────────────────────────────────────────────────────────
|
|
372
|
+
|
|
373
|
+
function escapeHtml(text) {
|
|
374
|
+
return text.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"');
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
// ── API calls ──────────────────────────────────────────────────────────────
|
|
378
|
+
|
|
379
|
+
async function fetchPending() {
|
|
380
|
+
const res = await fetch('/api/review/pending?project=' + encodeURIComponent(project));
|
|
381
|
+
if (!res.ok) throw new Error('Failed to fetch pending reviews');
|
|
382
|
+
return res.json();
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
async function fetchDiff(path) {
|
|
386
|
+
const res = await fetch('/api/review/diff?project=' + encodeURIComponent(project) + '&path=' + encodeURIComponent(path));
|
|
387
|
+
if (!res.ok) throw new Error('Failed to fetch diff');
|
|
388
|
+
return res.json();
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
async function submitDecision(path, decision) {
|
|
392
|
+
const res = await fetch('/api/review/decide', {
|
|
393
|
+
method: 'POST',
|
|
394
|
+
headers: {'Content-Type': 'application/json'},
|
|
395
|
+
body: JSON.stringify({project, path, decision}),
|
|
396
|
+
});
|
|
397
|
+
if (!res.ok) throw new Error('Failed to submit decision');
|
|
398
|
+
return res.json();
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
// ── Summary rendering ──────────────────────────────────────────────────
|
|
402
|
+
|
|
403
|
+
function renderSummaryContent(file) {
|
|
404
|
+
// Use file-level summaries (read from actual files at serve time, always up-to-date)
|
|
405
|
+
const lastOp = file.operations[file.operations.length - 1];
|
|
406
|
+
const opType = lastOp.type;
|
|
407
|
+
const previousSummary = file.previousSummary;
|
|
408
|
+
const summary = file.currentSummary;
|
|
409
|
+
|
|
410
|
+
// No summaries available at all
|
|
411
|
+
if (!previousSummary && !summary) {
|
|
412
|
+
return '<div class="no-summary">No summary available for this change.</div>';
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
let html = '';
|
|
416
|
+
|
|
417
|
+
if (opType === 'DELETE') {
|
|
418
|
+
// DELETE: show only what was removed
|
|
419
|
+
if (previousSummary) {
|
|
420
|
+
html += '<div class="summary-block previous">'
|
|
421
|
+
+ '<div class="summary-label">Removed</div>'
|
|
422
|
+
+ '<div class="summary-text">' + escapeHtml(previousSummary) + '</div>'
|
|
423
|
+
+ '</div>';
|
|
424
|
+
}
|
|
425
|
+
} else if (opType === 'ADD') {
|
|
426
|
+
// ADD: show only the new content
|
|
427
|
+
if (summary) {
|
|
428
|
+
html += '<div class="summary-block current">'
|
|
429
|
+
+ '<div class="summary-label">New</div>'
|
|
430
|
+
+ '<div class="summary-text">' + escapeHtml(summary) + '</div>'
|
|
431
|
+
+ '</div>';
|
|
432
|
+
}
|
|
433
|
+
} else {
|
|
434
|
+
// UPDATE, UPSERT, MERGE: show both versions
|
|
435
|
+
if (previousSummary) {
|
|
436
|
+
html += '<div class="summary-block previous">'
|
|
437
|
+
+ '<div class="summary-label">Previous</div>'
|
|
438
|
+
+ '<div class="summary-text">' + escapeHtml(previousSummary) + '</div>'
|
|
439
|
+
+ '</div>';
|
|
440
|
+
}
|
|
441
|
+
if (summary) {
|
|
442
|
+
html += '<div class="summary-block current">'
|
|
443
|
+
+ '<div class="summary-label">Current</div>'
|
|
444
|
+
+ '<div class="summary-text">' + escapeHtml(summary) + '</div>'
|
|
445
|
+
+ '</div>';
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
return html || '<div class="no-summary">No summary available for this change.</div>';
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
// ── Rendering ──────────────────────────────────────────────────────────
|
|
453
|
+
|
|
454
|
+
function renderFileCard(file, index) {
|
|
455
|
+
const opBadges = file.operations.map(op =>
|
|
456
|
+
'<span class="op-badge ' + op.type + '">' + op.type + '</span>'
|
|
457
|
+
).join('');
|
|
458
|
+
|
|
459
|
+
const reasons = file.operations
|
|
460
|
+
.filter(op => op.reason)
|
|
461
|
+
.map(op => op.reason);
|
|
462
|
+
const reasonHtml = reasons.length > 0
|
|
463
|
+
? '<span class="reason-text">' + escapeHtml(reasons[0]) + '</span>'
|
|
464
|
+
: '';
|
|
465
|
+
|
|
466
|
+
const summaryHtml = renderSummaryContent(file);
|
|
467
|
+
|
|
468
|
+
return '<div class="file-card" id="file-' + index + '">'
|
|
469
|
+
+ '<div class="file-header">'
|
|
470
|
+
+ ' <div><span class="file-path">' + escapeHtml(file.path) + '</span>' + reasonHtml + '</div>'
|
|
471
|
+
+ ' <div class="file-meta">'
|
|
472
|
+
+ ' ' + opBadges
|
|
473
|
+
+ ' <div class="actions">'
|
|
474
|
+
+ ' <button class="btn btn-approve" onclick="decide(event,' + index + ',\\'approved\\')">Approve</button>'
|
|
475
|
+
+ ' <button class="btn btn-reject" onclick="decide(event,' + index + ',\\'rejected\\')">Reject</button>'
|
|
476
|
+
+ ' </div>'
|
|
477
|
+
+ ' </div>'
|
|
478
|
+
+ '</div>'
|
|
479
|
+
+ '<div class="summary-content">' + summaryHtml + '</div>'
|
|
480
|
+
+ '</div>';
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
async function decide(event, index, decision) {
|
|
484
|
+
event.stopPropagation();
|
|
485
|
+
const file = fileData[index];
|
|
486
|
+
if (!file) return;
|
|
487
|
+
|
|
488
|
+
const card = document.getElementById('file-' + index);
|
|
489
|
+
const buttons = card.querySelectorAll('.btn');
|
|
490
|
+
buttons.forEach(b => b.disabled = true);
|
|
491
|
+
|
|
492
|
+
try {
|
|
493
|
+
await submitDecision(file.path, decision);
|
|
494
|
+
// Replace card content with decided state
|
|
495
|
+
const summaryContent = card.querySelector('.summary-content');
|
|
496
|
+
if (summaryContent) summaryContent.style.display = 'none';
|
|
497
|
+
const header = card.querySelector('.file-header');
|
|
498
|
+
const label = decision === 'approved' ? 'Approved' : 'Rejected';
|
|
499
|
+
const cls = decision === 'approved' ? 'approved' : 'rejected';
|
|
500
|
+
header.innerHTML = '<div><span class="file-path">' + escapeHtml(file.path) + '</span></div>'
|
|
501
|
+
+ '<div class="decided ' + cls + '">' + label + '</div>';
|
|
502
|
+
header.style.cursor = 'default';
|
|
503
|
+
|
|
504
|
+
// Update count
|
|
505
|
+
updatePendingCount();
|
|
506
|
+
} catch (e) {
|
|
507
|
+
buttons.forEach(b => b.disabled = false);
|
|
508
|
+
alert('Error: ' + e.message);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
async function bulkDecide(decision) {
|
|
513
|
+
const pending = fileData.filter((_, i) => {
|
|
514
|
+
const card = document.getElementById('file-' + i);
|
|
515
|
+
return card && !card.querySelector('.decided');
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
for (let i = 0; i < fileData.length; i++) {
|
|
519
|
+
const card = document.getElementById('file-' + i);
|
|
520
|
+
if (card && !card.querySelector('.decided')) {
|
|
521
|
+
await decide({stopPropagation() {}}, i, decision);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
function updatePendingCount() {
|
|
527
|
+
const remaining = fileData.filter((_, i) => {
|
|
528
|
+
const card = document.getElementById('file-' + i);
|
|
529
|
+
return card && !card.querySelector('.decided');
|
|
530
|
+
}).length;
|
|
531
|
+
document.getElementById('pending-count').textContent = remaining + ' pending';
|
|
532
|
+
|
|
533
|
+
if (remaining === 0) {
|
|
534
|
+
clearInterval(poller);
|
|
535
|
+
document.getElementById('bulk-actions').style.display = 'none';
|
|
536
|
+
document.getElementById('summary-bar').textContent = 'All reviews completed.';
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
|
|
540
|
+
// Poll every 5 s so the page reflects external decisions (e.g., brv review approve via CLI).
|
|
541
|
+
// When the server reports 0 pending items, mark any locally-undecided cards as resolved.
|
|
542
|
+
let poller = setInterval(async () => {
|
|
543
|
+
if (!project || fileData.length === 0) return;
|
|
544
|
+
try {
|
|
545
|
+
const data = await fetchPending();
|
|
546
|
+
const serverPaths = new Set((data.files || []).map(f => f.path));
|
|
547
|
+
let anyUpdated = false;
|
|
548
|
+
|
|
549
|
+
for (let i = 0; i < fileData.length; i++) {
|
|
550
|
+
const card = document.getElementById('file-' + i);
|
|
551
|
+
if (!card || card.querySelector('.decided')) continue;
|
|
552
|
+
if (!serverPaths.has(fileData[i].path)) {
|
|
553
|
+
// Item was resolved externally
|
|
554
|
+
const header = card.querySelector('.file-header');
|
|
555
|
+
if (header) {
|
|
556
|
+
header.innerHTML = '<div><span class="file-path">' + escapeHtml(fileData[i].path) + '</span></div>'
|
|
557
|
+
+ '<div class="decided approved">Resolved</div>';
|
|
558
|
+
}
|
|
559
|
+
const summaryContent = card.querySelector('.summary-content');
|
|
560
|
+
if (summaryContent) summaryContent.style.display = 'none';
|
|
561
|
+
anyUpdated = true;
|
|
562
|
+
}
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
if (anyUpdated) updatePendingCount();
|
|
566
|
+
} catch {
|
|
567
|
+
// Ignore transient poll errors
|
|
568
|
+
}
|
|
569
|
+
}, 5000);
|
|
570
|
+
|
|
571
|
+
// ── Init ───────────────────────────────────────────────────────────────────
|
|
572
|
+
|
|
573
|
+
async function init() {
|
|
574
|
+
const contentEl = document.getElementById('content');
|
|
575
|
+
|
|
576
|
+
if (!project) {
|
|
577
|
+
contentEl.innerHTML = '<div class="error">Missing project parameter in URL</div>';
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
try {
|
|
582
|
+
const data = await fetchPending();
|
|
583
|
+
fileData = data.files || [];
|
|
584
|
+
|
|
585
|
+
document.getElementById('pending-count').textContent = fileData.length + ' pending';
|
|
586
|
+
|
|
587
|
+
if (fileData.length === 0) {
|
|
588
|
+
contentEl.innerHTML = '<div class="empty">No pending reviews for this project.</div>';
|
|
589
|
+
return;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
document.getElementById('summary-bar').textContent =
|
|
593
|
+
fileData.length + ' file(s) pending review in ' + (data.projectPath || 'unknown project');
|
|
594
|
+
document.getElementById('bulk-actions').style.display = 'flex';
|
|
595
|
+
|
|
596
|
+
contentEl.innerHTML = fileData.map((f, i) => renderFileCard(f, i)).join('');
|
|
597
|
+
} catch (e) {
|
|
598
|
+
contentEl.innerHTML = '<div class="error">Failed to load reviews: ' + escapeHtml(e.message) + '</div>';
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
init();
|
|
603
|
+
</script>
|
|
604
|
+
</body>
|
|
605
|
+
</html>`;
|
|
606
|
+
}
|
|
@@ -7,14 +7,14 @@ export declare const BrvCurateInputSchema: z.ZodObject<{
|
|
|
7
7
|
files: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
8
8
|
folder: z.ZodOptional<z.ZodString>;
|
|
9
9
|
}, "strip", z.ZodTypeAny, {
|
|
10
|
+
files?: string[] | undefined;
|
|
10
11
|
context?: string | undefined;
|
|
11
12
|
cwd?: string | undefined;
|
|
12
|
-
files?: string[] | undefined;
|
|
13
13
|
folder?: string | undefined;
|
|
14
14
|
}, {
|
|
15
|
+
files?: string[] | undefined;
|
|
15
16
|
context?: string | undefined;
|
|
16
17
|
cwd?: string | undefined;
|
|
17
|
-
files?: string[] | undefined;
|
|
18
18
|
folder?: string | undefined;
|
|
19
19
|
}>;
|
|
20
20
|
/**
|
|
@@ -11,8 +11,17 @@ export declare function computeSummary(operations: CurateLogOperation[]): Curate
|
|
|
11
11
|
* per-project FileCurateLogStore. All I/O errors are swallowed — logging
|
|
12
12
|
* must never block or affect curate task execution.
|
|
13
13
|
*/
|
|
14
|
+
/** Info passed to the onPendingReviews callback after curate completes with pending review ops. */
|
|
15
|
+
export type PendingReviewsInfo = {
|
|
16
|
+
/** Transport client ID of the task originator — used for direct sendTo delivery. */
|
|
17
|
+
clientId: string;
|
|
18
|
+
pendingCount: number;
|
|
19
|
+
projectPath: string;
|
|
20
|
+
taskId: string;
|
|
21
|
+
};
|
|
14
22
|
export declare class CurateLogHandler implements ITaskLifecycleHook {
|
|
15
23
|
private readonly createStore?;
|
|
24
|
+
private readonly onPendingReviews?;
|
|
16
25
|
/** Active task count per projectPath — used to evict idle stores. */
|
|
17
26
|
private readonly activeTaskCount;
|
|
18
27
|
/** Per-project store cache (one store per projectPath). Evicted when no active tasks remain. */
|
|
@@ -21,11 +30,18 @@ export declare class CurateLogHandler implements ITaskLifecycleHook {
|
|
|
21
30
|
private readonly tasks;
|
|
22
31
|
/**
|
|
23
32
|
* @param createStore - Optional factory for testing. Default: FileCurateLogStore.
|
|
33
|
+
* @param onPendingReviews - Optional callback fired when curate completes with pending review ops.
|
|
24
34
|
*/
|
|
25
|
-
constructor(createStore?: ((projectPath: string) => ICurateLogStore) | undefined);
|
|
35
|
+
constructor(createStore?: ((projectPath: string) => ICurateLogStore) | undefined, onPendingReviews?: ((info: PendingReviewsInfo) => void) | undefined);
|
|
26
36
|
cleanup(taskId: string): void;
|
|
37
|
+
/**
|
|
38
|
+
* Synchronously returns the pending review count from in-memory state.
|
|
39
|
+
* Included in the task:completed payload so the client receives it atomically
|
|
40
|
+
* without relying on a separate review:notify event that arrives after disk I/O.
|
|
41
|
+
*/
|
|
42
|
+
getTaskCompletionData(taskId: string): Record<string, unknown>;
|
|
27
43
|
onTaskCancelled(taskId: string, _task: TaskInfo): Promise<void>;
|
|
28
|
-
onTaskCompleted(taskId: string, result: string,
|
|
44
|
+
onTaskCompleted(taskId: string, result: string, task: TaskInfo): Promise<void>;
|
|
29
45
|
onTaskCreate(task: TaskInfo): Promise<void | {
|
|
30
46
|
logId?: string;
|
|
31
47
|
}>;
|