@jonit-dev/night-watch-cli 1.7.29 → 1.7.31
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/bin/night-watch.mjs +1 -1
- package/dist/cli.d.ts +3 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/{src/cli.js → cli.js} +1 -0
- package/dist/cli.js.map +1 -0
- package/dist/{src/commands → commands}/audit.d.ts +2 -2
- package/dist/commands/audit.d.ts.map +1 -0
- package/dist/commands/audit.js +105 -0
- package/dist/commands/audit.js.map +1 -0
- package/dist/{src/commands → commands}/board.d.ts +1 -1
- package/dist/commands/board.d.ts.map +1 -0
- package/dist/commands/board.js +664 -0
- package/dist/commands/board.js.map +1 -0
- package/dist/{src/commands → commands}/cancel.d.ts +3 -3
- package/dist/commands/cancel.d.ts.map +1 -0
- package/dist/{src/commands → commands}/cancel.js +18 -20
- package/dist/commands/cancel.js.map +1 -0
- package/dist/commands/dashboard/tab-actions.d.ts.map +1 -0
- package/dist/commands/dashboard/tab-actions.js.map +1 -0
- package/dist/{src/commands → commands}/dashboard/tab-config.d.ts +3 -3
- package/dist/commands/dashboard/tab-config.d.ts.map +1 -0
- package/dist/{src/commands → commands}/dashboard/tab-config.js +250 -187
- package/dist/commands/dashboard/tab-config.js.map +1 -0
- package/dist/{src/commands → commands}/dashboard/tab-logs.d.ts +1 -1
- package/dist/commands/dashboard/tab-logs.d.ts.map +1 -0
- package/dist/{src/commands → commands}/dashboard/tab-logs.js +62 -38
- package/dist/commands/dashboard/tab-logs.js.map +1 -0
- package/dist/{src/commands → commands}/dashboard/tab-schedules.d.ts +1 -1
- package/dist/commands/dashboard/tab-schedules.d.ts.map +1 -0
- package/dist/{src/commands → commands}/dashboard/tab-schedules.js +85 -76
- package/dist/commands/dashboard/tab-schedules.js.map +1 -0
- package/dist/{src/commands → commands}/dashboard/tab-status.d.ts +7 -7
- package/dist/commands/dashboard/tab-status.d.ts.map +1 -0
- package/dist/{src/commands → commands}/dashboard/tab-status.js +98 -95
- package/dist/commands/dashboard/tab-status.js.map +1 -0
- package/dist/{src/commands → commands}/dashboard/types.d.ts +3 -4
- package/dist/commands/dashboard/types.d.ts.map +1 -0
- package/dist/commands/dashboard/types.js.map +1 -0
- package/dist/{src/commands → commands}/dashboard.d.ts +2 -2
- package/dist/commands/dashboard.d.ts.map +1 -0
- package/dist/{src/commands → commands}/dashboard.js +32 -33
- package/dist/commands/dashboard.js.map +1 -0
- package/dist/{src/commands → commands}/doctor.d.ts +2 -2
- package/dist/commands/doctor.d.ts.map +1 -0
- package/dist/{src/commands → commands}/doctor.js +40 -43
- package/dist/commands/doctor.js.map +1 -0
- package/dist/{src/commands → commands}/history.d.ts +1 -1
- package/dist/commands/history.d.ts.map +1 -0
- package/dist/{src/commands → commands}/history.js +11 -18
- package/dist/commands/history.js.map +1 -0
- package/dist/{src/commands → commands}/init.d.ts +1 -1
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/{src/commands → commands}/init.js +62 -36
- package/dist/commands/init.js.map +1 -0
- package/dist/{src/commands → commands}/install.d.ts +2 -2
- package/dist/commands/install.d.ts.map +1 -0
- package/dist/{src/commands → commands}/install.js +48 -50
- package/dist/commands/install.js.map +1 -0
- package/dist/{src/commands → commands}/logs.d.ts +1 -1
- package/dist/commands/logs.d.ts.map +1 -0
- package/dist/{src/commands → commands}/logs.js +29 -30
- package/dist/commands/logs.js.map +1 -0
- package/dist/{src/commands → commands}/prd-state.d.ts +1 -1
- package/dist/commands/prd-state.d.ts.map +1 -0
- package/dist/{src/commands → commands}/prd-state.js +14 -14
- package/dist/commands/prd-state.js.map +1 -0
- package/dist/{src/commands → commands}/prd.d.ts +1 -1
- package/dist/commands/prd.d.ts.map +1 -0
- package/dist/{src/commands → commands}/prd.js +57 -66
- package/dist/commands/prd.js.map +1 -0
- package/dist/{src/commands → commands}/prds.d.ts +1 -1
- package/dist/commands/prds.d.ts.map +1 -0
- package/dist/{src/commands → commands}/prds.js +51 -53
- package/dist/commands/prds.js.map +1 -0
- package/dist/{src/commands → commands}/prs.d.ts +1 -1
- package/dist/commands/prs.d.ts.map +1 -0
- package/dist/{src/commands → commands}/prs.js +22 -24
- package/dist/commands/prs.js.map +1 -0
- package/dist/{src/commands → commands}/qa.d.ts +2 -2
- package/dist/commands/qa.d.ts.map +1 -0
- package/dist/{src/commands → commands}/qa.js +50 -51
- package/dist/commands/qa.js.map +1 -0
- package/dist/{src/commands → commands}/retry.d.ts +1 -1
- package/dist/commands/retry.d.ts.map +1 -0
- package/dist/{src/commands → commands}/retry.js +9 -10
- package/dist/commands/retry.js.map +1 -0
- package/dist/{src/commands → commands}/review.d.ts +2 -2
- package/dist/commands/review.d.ts.map +1 -0
- package/dist/{src/commands → commands}/review.js +68 -59
- package/dist/commands/review.js.map +1 -0
- package/dist/{src/commands → commands}/run.d.ts +2 -2
- package/dist/commands/run.d.ts.map +1 -0
- package/dist/{src/commands → commands}/run.js +87 -83
- package/dist/commands/run.js.map +1 -0
- package/dist/{src/commands → commands}/serve.d.ts +2 -2
- package/dist/commands/serve.d.ts.map +1 -0
- package/dist/{src/commands → commands}/serve.js +18 -18
- package/dist/commands/serve.js.map +1 -0
- package/dist/{src/commands → commands}/slice.d.ts +2 -2
- package/dist/commands/slice.d.ts.map +1 -0
- package/dist/{src/commands → commands}/slice.js +50 -46
- package/dist/commands/slice.js.map +1 -0
- package/dist/{src/commands → commands}/state.d.ts +1 -1
- package/dist/commands/state.d.ts.map +1 -0
- package/dist/{src/commands → commands}/state.js +20 -22
- package/dist/commands/state.js.map +1 -0
- package/dist/{src/commands → commands}/status.d.ts +1 -1
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/{src/commands → commands}/status.js +75 -54
- package/dist/commands/status.js.map +1 -0
- package/dist/{src/commands → commands}/uninstall.d.ts +1 -1
- package/dist/commands/uninstall.d.ts.map +1 -0
- package/dist/{src/commands → commands}/uninstall.js +12 -14
- package/dist/commands/uninstall.js.map +1 -0
- package/dist/{src/commands → commands}/update.d.ts +1 -1
- package/dist/commands/update.d.ts.map +1 -0
- package/dist/{src/commands → commands}/update.js +23 -23
- package/dist/commands/update.js.map +1 -0
- package/package.json +18 -42
- package/LICENSE +0 -21
- package/README.md +0 -132
- package/dist/shared/types.d.ts +0 -226
- package/dist/shared/types.d.ts.map +0 -1
- package/dist/shared/types.js +0 -7
- package/dist/shared/types.js.map +0 -1
- package/dist/src/agents/soul-compiler.d.ts +0 -11
- package/dist/src/agents/soul-compiler.d.ts.map +0 -1
- package/dist/src/agents/soul-compiler.js +0 -157
- package/dist/src/agents/soul-compiler.js.map +0 -1
- package/dist/src/board/factory.d.ts +0 -3
- package/dist/src/board/factory.d.ts.map +0 -1
- package/dist/src/board/factory.js +0 -10
- package/dist/src/board/factory.js.map +0 -1
- package/dist/src/board/providers/github-graphql.d.ts +0 -16
- package/dist/src/board/providers/github-graphql.d.ts.map +0 -1
- package/dist/src/board/providers/github-graphql.js +0 -43
- package/dist/src/board/providers/github-graphql.js.map +0 -1
- package/dist/src/board/providers/github-projects.d.ts +0 -51
- package/dist/src/board/providers/github-projects.d.ts.map +0 -1
- package/dist/src/board/providers/github-projects.js +0 -672
- package/dist/src/board/providers/github-projects.js.map +0 -1
- package/dist/src/board/types.d.ts +0 -60
- package/dist/src/board/types.d.ts.map +0 -1
- package/dist/src/board/types.js +0 -4
- package/dist/src/board/types.js.map +0 -1
- package/dist/src/cli.d.ts +0 -3
- package/dist/src/cli.d.ts.map +0 -1
- package/dist/src/cli.js.map +0 -1
- package/dist/src/commands/audit.d.ts.map +0 -1
- package/dist/src/commands/audit.js +0 -98
- package/dist/src/commands/audit.js.map +0 -1
- package/dist/src/commands/board.d.ts.map +0 -1
- package/dist/src/commands/board.js +0 -294
- package/dist/src/commands/board.js.map +0 -1
- package/dist/src/commands/cancel.d.ts.map +0 -1
- package/dist/src/commands/cancel.js.map +0 -1
- package/dist/src/commands/dashboard/tab-actions.d.ts.map +0 -1
- package/dist/src/commands/dashboard/tab-actions.js.map +0 -1
- package/dist/src/commands/dashboard/tab-config.d.ts.map +0 -1
- package/dist/src/commands/dashboard/tab-config.js.map +0 -1
- package/dist/src/commands/dashboard/tab-logs.d.ts.map +0 -1
- package/dist/src/commands/dashboard/tab-logs.js.map +0 -1
- package/dist/src/commands/dashboard/tab-schedules.d.ts.map +0 -1
- package/dist/src/commands/dashboard/tab-schedules.js.map +0 -1
- package/dist/src/commands/dashboard/tab-status.d.ts.map +0 -1
- package/dist/src/commands/dashboard/tab-status.js.map +0 -1
- package/dist/src/commands/dashboard/types.d.ts.map +0 -1
- package/dist/src/commands/dashboard/types.js.map +0 -1
- package/dist/src/commands/dashboard.d.ts.map +0 -1
- package/dist/src/commands/dashboard.js.map +0 -1
- package/dist/src/commands/doctor.d.ts.map +0 -1
- package/dist/src/commands/doctor.js.map +0 -1
- package/dist/src/commands/history.d.ts.map +0 -1
- package/dist/src/commands/history.js.map +0 -1
- package/dist/src/commands/init.d.ts.map +0 -1
- package/dist/src/commands/init.js.map +0 -1
- package/dist/src/commands/install.d.ts.map +0 -1
- package/dist/src/commands/install.js.map +0 -1
- package/dist/src/commands/logs.d.ts.map +0 -1
- package/dist/src/commands/logs.js.map +0 -1
- package/dist/src/commands/prd-state.d.ts.map +0 -1
- package/dist/src/commands/prd-state.js.map +0 -1
- package/dist/src/commands/prd.d.ts.map +0 -1
- package/dist/src/commands/prd.js.map +0 -1
- package/dist/src/commands/prds.d.ts.map +0 -1
- package/dist/src/commands/prds.js.map +0 -1
- package/dist/src/commands/prs.d.ts.map +0 -1
- package/dist/src/commands/prs.js.map +0 -1
- package/dist/src/commands/qa.d.ts.map +0 -1
- package/dist/src/commands/qa.js.map +0 -1
- package/dist/src/commands/retry.d.ts.map +0 -1
- package/dist/src/commands/retry.js.map +0 -1
- package/dist/src/commands/review.d.ts.map +0 -1
- package/dist/src/commands/review.js.map +0 -1
- package/dist/src/commands/run.d.ts.map +0 -1
- package/dist/src/commands/run.js.map +0 -1
- package/dist/src/commands/serve.d.ts.map +0 -1
- package/dist/src/commands/serve.js.map +0 -1
- package/dist/src/commands/slice.d.ts.map +0 -1
- package/dist/src/commands/slice.js.map +0 -1
- package/dist/src/commands/state.d.ts.map +0 -1
- package/dist/src/commands/state.js.map +0 -1
- package/dist/src/commands/status.d.ts.map +0 -1
- package/dist/src/commands/status.js.map +0 -1
- package/dist/src/commands/uninstall.d.ts.map +0 -1
- package/dist/src/commands/uninstall.js.map +0 -1
- package/dist/src/commands/update.d.ts.map +0 -1
- package/dist/src/commands/update.js.map +0 -1
- package/dist/src/config.d.ts +0 -23
- package/dist/src/config.d.ts.map +0 -1
- package/dist/src/config.js +0 -671
- package/dist/src/config.js.map +0 -1
- package/dist/src/constants.d.ts +0 -67
- package/dist/src/constants.d.ts.map +0 -1
- package/dist/src/constants.js +0 -131
- package/dist/src/constants.js.map +0 -1
- package/dist/src/server/index.d.ts +0 -23
- package/dist/src/server/index.d.ts.map +0 -1
- package/dist/src/server/index.js +0 -1704
- package/dist/src/server/index.js.map +0 -1
- package/dist/src/slack/channel-manager.d.ts +0 -32
- package/dist/src/slack/channel-manager.d.ts.map +0 -1
- package/dist/src/slack/channel-manager.js +0 -128
- package/dist/src/slack/channel-manager.js.map +0 -1
- package/dist/src/slack/client.d.ts +0 -76
- package/dist/src/slack/client.d.ts.map +0 -1
- package/dist/src/slack/client.js +0 -193
- package/dist/src/slack/client.js.map +0 -1
- package/dist/src/slack/deliberation.d.ts +0 -87
- package/dist/src/slack/deliberation.d.ts.map +0 -1
- package/dist/src/slack/deliberation.js +0 -1354
- package/dist/src/slack/deliberation.js.map +0 -1
- package/dist/src/slack/index.d.ts +0 -6
- package/dist/src/slack/index.d.ts.map +0 -1
- package/dist/src/slack/index.js +0 -5
- package/dist/src/slack/index.js.map +0 -1
- package/dist/src/slack/interaction-listener.d.ts +0 -130
- package/dist/src/slack/interaction-listener.d.ts.map +0 -1
- package/dist/src/slack/interaction-listener.js +0 -1329
- package/dist/src/slack/interaction-listener.js.map +0 -1
- package/dist/src/storage/json-state-migrator.d.ts +0 -24
- package/dist/src/storage/json-state-migrator.d.ts.map +0 -1
- package/dist/src/storage/json-state-migrator.js +0 -197
- package/dist/src/storage/json-state-migrator.js.map +0 -1
- package/dist/src/storage/repositories/index.d.ts +0 -25
- package/dist/src/storage/repositories/index.d.ts.map +0 -1
- package/dist/src/storage/repositories/index.js +0 -45
- package/dist/src/storage/repositories/index.js.map +0 -1
- package/dist/src/storage/repositories/interfaces.d.ts +0 -60
- package/dist/src/storage/repositories/interfaces.d.ts.map +0 -1
- package/dist/src/storage/repositories/interfaces.js +0 -6
- package/dist/src/storage/repositories/interfaces.js.map +0 -1
- package/dist/src/storage/repositories/sqlite/agent-persona-repository.d.ts +0 -33
- package/dist/src/storage/repositories/sqlite/agent-persona-repository.d.ts.map +0 -1
- package/dist/src/storage/repositories/sqlite/agent-persona-repository.js +0 -715
- package/dist/src/storage/repositories/sqlite/agent-persona-repository.js.map +0 -1
- package/dist/src/storage/repositories/sqlite/execution-history-repository.d.ts +0 -21
- package/dist/src/storage/repositories/sqlite/execution-history-repository.d.ts.map +0 -1
- package/dist/src/storage/repositories/sqlite/execution-history-repository.js +0 -94
- package/dist/src/storage/repositories/sqlite/execution-history-repository.js.map +0 -1
- package/dist/src/storage/repositories/sqlite/prd-state-repository.d.ts +0 -17
- package/dist/src/storage/repositories/sqlite/prd-state-repository.d.ts.map +0 -1
- package/dist/src/storage/repositories/sqlite/prd-state-repository.js +0 -74
- package/dist/src/storage/repositories/sqlite/prd-state-repository.js.map +0 -1
- package/dist/src/storage/repositories/sqlite/project-registry-repository.d.ts +0 -17
- package/dist/src/storage/repositories/sqlite/project-registry-repository.d.ts.map +0 -1
- package/dist/src/storage/repositories/sqlite/project-registry-repository.js +0 -43
- package/dist/src/storage/repositories/sqlite/project-registry-repository.js.map +0 -1
- package/dist/src/storage/repositories/sqlite/roadmap-state-repository.d.ts +0 -14
- package/dist/src/storage/repositories/sqlite/roadmap-state-repository.d.ts.map +0 -1
- package/dist/src/storage/repositories/sqlite/roadmap-state-repository.js +0 -47
- package/dist/src/storage/repositories/sqlite/roadmap-state-repository.js.map +0 -1
- package/dist/src/storage/repositories/sqlite/slack-discussion-repository.d.ts +0 -20
- package/dist/src/storage/repositories/sqlite/slack-discussion-repository.d.ts.map +0 -1
- package/dist/src/storage/repositories/sqlite/slack-discussion-repository.js +0 -88
- package/dist/src/storage/repositories/sqlite/slack-discussion-repository.js.map +0 -1
- package/dist/src/storage/sqlite/client.d.ts +0 -23
- package/dist/src/storage/sqlite/client.d.ts.map +0 -1
- package/dist/src/storage/sqlite/client.js +0 -47
- package/dist/src/storage/sqlite/client.js.map +0 -1
- package/dist/src/storage/sqlite/migrations.d.ts +0 -11
- package/dist/src/storage/sqlite/migrations.d.ts.map +0 -1
- package/dist/src/storage/sqlite/migrations.js +0 -94
- package/dist/src/storage/sqlite/migrations.js.map +0 -1
- package/dist/src/templates/prd-template.d.ts +0 -11
- package/dist/src/templates/prd-template.d.ts.map +0 -1
- package/dist/src/templates/prd-template.js +0 -166
- package/dist/src/templates/prd-template.js.map +0 -1
- package/dist/src/templates/slicer-prompt.d.ts +0 -54
- package/dist/src/templates/slicer-prompt.d.ts.map +0 -1
- package/dist/src/templates/slicer-prompt.js +0 -163
- package/dist/src/templates/slicer-prompt.js.map +0 -1
- package/dist/src/types.d.ts +0 -140
- package/dist/src/types.d.ts.map +0 -1
- package/dist/src/types.js +0 -5
- package/dist/src/types.js.map +0 -1
- package/dist/src/utils/avatar-generator.d.ts +0 -6
- package/dist/src/utils/avatar-generator.d.ts.map +0 -1
- package/dist/src/utils/avatar-generator.js +0 -133
- package/dist/src/utils/avatar-generator.js.map +0 -1
- package/dist/src/utils/checks.d.ts +0 -55
- package/dist/src/utils/checks.d.ts.map +0 -1
- package/dist/src/utils/checks.js +0 -246
- package/dist/src/utils/checks.js.map +0 -1
- package/dist/src/utils/config-writer.d.ts +0 -16
- package/dist/src/utils/config-writer.d.ts.map +0 -1
- package/dist/src/utils/config-writer.js +0 -45
- package/dist/src/utils/config-writer.js.map +0 -1
- package/dist/src/utils/crontab.d.ts +0 -62
- package/dist/src/utils/crontab.d.ts.map +0 -1
- package/dist/src/utils/crontab.js +0 -168
- package/dist/src/utils/crontab.js.map +0 -1
- package/dist/src/utils/execution-history.d.ts +0 -54
- package/dist/src/utils/execution-history.d.ts.map +0 -1
- package/dist/src/utils/execution-history.js +0 -80
- package/dist/src/utils/execution-history.js.map +0 -1
- package/dist/src/utils/github.d.ts +0 -40
- package/dist/src/utils/github.d.ts.map +0 -1
- package/dist/src/utils/github.js +0 -126
- package/dist/src/utils/github.js.map +0 -1
- package/dist/src/utils/notify.d.ts +0 -64
- package/dist/src/utils/notify.d.ts.map +0 -1
- package/dist/src/utils/notify.js +0 -405
- package/dist/src/utils/notify.js.map +0 -1
- package/dist/src/utils/prd-states.d.ts +0 -16
- package/dist/src/utils/prd-states.d.ts.map +0 -1
- package/dist/src/utils/prd-states.js +0 -28
- package/dist/src/utils/prd-states.js.map +0 -1
- package/dist/src/utils/registry.d.ts +0 -45
- package/dist/src/utils/registry.d.ts.map +0 -1
- package/dist/src/utils/registry.js +0 -86
- package/dist/src/utils/registry.js.map +0 -1
- package/dist/src/utils/roadmap-parser.d.ts +0 -45
- package/dist/src/utils/roadmap-parser.d.ts.map +0 -1
- package/dist/src/utils/roadmap-parser.js +0 -136
- package/dist/src/utils/roadmap-parser.js.map +0 -1
- package/dist/src/utils/roadmap-scanner.d.ts +0 -92
- package/dist/src/utils/roadmap-scanner.d.ts.map +0 -1
- package/dist/src/utils/roadmap-scanner.js +0 -349
- package/dist/src/utils/roadmap-scanner.js.map +0 -1
- package/dist/src/utils/roadmap-state.d.ts +0 -90
- package/dist/src/utils/roadmap-state.d.ts.map +0 -1
- package/dist/src/utils/roadmap-state.js +0 -154
- package/dist/src/utils/roadmap-state.js.map +0 -1
- package/dist/src/utils/script-result.d.ts +0 -12
- package/dist/src/utils/script-result.d.ts.map +0 -1
- package/dist/src/utils/script-result.js +0 -46
- package/dist/src/utils/script-result.js.map +0 -1
- package/dist/src/utils/shell.d.ts +0 -27
- package/dist/src/utils/shell.d.ts.map +0 -1
- package/dist/src/utils/shell.js +0 -64
- package/dist/src/utils/shell.js.map +0 -1
- package/dist/src/utils/status-data.d.ts +0 -148
- package/dist/src/utils/status-data.d.ts.map +0 -1
- package/dist/src/utils/status-data.js +0 -548
- package/dist/src/utils/status-data.js.map +0 -1
- package/dist/src/utils/ui.d.ts +0 -55
- package/dist/src/utils/ui.d.ts.map +0 -1
- package/dist/src/utils/ui.js +0 -121
- package/dist/src/utils/ui.js.map +0 -1
- package/scripts/night-watch-audit-cron.sh +0 -149
- package/scripts/night-watch-cron.sh +0 -484
- package/scripts/night-watch-helpers.sh +0 -499
- package/scripts/night-watch-pr-reviewer-cron.sh +0 -528
- package/scripts/night-watch-qa-cron.sh +0 -281
- package/scripts/night-watch-slicer-cron.sh +0 -90
- package/scripts/test-helpers.bats +0 -77
- package/templates/night-watch-pr-reviewer.md +0 -174
- package/templates/night-watch-qa.md +0 -157
- package/templates/night-watch-slicer.md +0 -219
- package/templates/night-watch.config.json +0 -30
- package/templates/night-watch.md +0 -94
- package/templates/prd-executor.md +0 -235
- package/templates/prd.md +0 -26
- package/web/dist/assets/index-BiJf9LFT.js +0 -458
- package/web/dist/assets/index-OpSgvsYu.css +0 -1
- package/web/dist/avatars/carlos.webp +0 -0
- package/web/dist/avatars/dev.webp +0 -0
- package/web/dist/avatars/maya.webp +0 -0
- package/web/dist/avatars/priya.webp +0 -0
- package/web/dist/index.html +0 -82
- /package/dist/{src/commands → commands}/dashboard/tab-actions.d.ts +0 -0
- /package/dist/{src/commands → commands}/dashboard/tab-actions.js +0 -0
- /package/dist/{src/commands → commands}/dashboard/types.js +0 -0
|
@@ -1,281 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
# Night Watch QA Cron Runner (project-agnostic)
|
|
5
|
-
# Usage: night-watch-qa-cron.sh /path/to/project
|
|
6
|
-
#
|
|
7
|
-
# NOTE: This script expects environment variables to be set by the caller.
|
|
8
|
-
# The Node.js CLI will inject config values via environment variables.
|
|
9
|
-
# Required env vars (with defaults shown):
|
|
10
|
-
# NW_QA_MAX_RUNTIME=3600 - Maximum runtime in seconds (1 hour)
|
|
11
|
-
# NW_PROVIDER_CMD=claude - AI provider CLI to use (claude, codex, etc.)
|
|
12
|
-
# NW_BRANCH_PATTERNS=feat/,night-watch/ - Comma-separated branch prefixes to match
|
|
13
|
-
# NW_QA_SKIP_LABEL=skip-qa - Label to skip QA on a PR
|
|
14
|
-
# NW_QA_ARTIFACTS=both - Artifact mode (both, tests, report)
|
|
15
|
-
# NW_QA_AUTO_INSTALL_PLAYWRIGHT=1 - Auto-install Playwright browsers
|
|
16
|
-
# NW_DRY_RUN=0 - Set to 1 for dry-run mode (prints diagnostics only)
|
|
17
|
-
|
|
18
|
-
PROJECT_DIR="${1:?Usage: $0 /path/to/project}"
|
|
19
|
-
PROJECT_NAME=$(basename "${PROJECT_DIR}")
|
|
20
|
-
LOG_DIR="${PROJECT_DIR}/logs"
|
|
21
|
-
LOG_FILE="${LOG_DIR}/night-watch-qa.log"
|
|
22
|
-
MAX_RUNTIME="${NW_QA_MAX_RUNTIME:-3600}" # 1 hour
|
|
23
|
-
MAX_LOG_SIZE="524288" # 512 KB
|
|
24
|
-
PROVIDER_CMD="${NW_PROVIDER_CMD:-claude}"
|
|
25
|
-
BRANCH_PATTERNS_RAW="${NW_BRANCH_PATTERNS:-feat/,night-watch/}"
|
|
26
|
-
SKIP_LABEL="${NW_QA_SKIP_LABEL:-skip-qa}"
|
|
27
|
-
QA_ARTIFACTS="${NW_QA_ARTIFACTS:-both}"
|
|
28
|
-
QA_AUTO_INSTALL_PLAYWRIGHT="${NW_QA_AUTO_INSTALL_PLAYWRIGHT:-1}"
|
|
29
|
-
|
|
30
|
-
# Ensure NVM / Node / Claude are on PATH
|
|
31
|
-
export NVM_DIR="${HOME}/.nvm"
|
|
32
|
-
[ -s "${NVM_DIR}/nvm.sh" ] && . "${NVM_DIR}/nvm.sh"
|
|
33
|
-
|
|
34
|
-
# NOTE: Environment variables should be set by the caller (Node.js CLI).
|
|
35
|
-
# The .env.night-watch sourcing has been removed - config is now injected via env vars.
|
|
36
|
-
|
|
37
|
-
mkdir -p "${LOG_DIR}"
|
|
38
|
-
|
|
39
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
40
|
-
# shellcheck source=night-watch-helpers.sh
|
|
41
|
-
source "${SCRIPT_DIR}/night-watch-helpers.sh"
|
|
42
|
-
PROJECT_RUNTIME_KEY=$(project_runtime_key "${PROJECT_DIR}")
|
|
43
|
-
# NOTE: Lock file path must match qaLockPath() in src/utils/status-data.ts
|
|
44
|
-
LOCK_FILE="/tmp/night-watch-qa-${PROJECT_RUNTIME_KEY}.lock"
|
|
45
|
-
|
|
46
|
-
emit_result() {
|
|
47
|
-
local status="${1:?status required}"
|
|
48
|
-
local details="${2:-}"
|
|
49
|
-
if [ -n "${details}" ]; then
|
|
50
|
-
echo "NIGHT_WATCH_RESULT:${status}|${details}"
|
|
51
|
-
else
|
|
52
|
-
echo "NIGHT_WATCH_RESULT:${status}"
|
|
53
|
-
fi
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
# Validate provider
|
|
57
|
-
if ! validate_provider "${PROVIDER_CMD}"; then
|
|
58
|
-
echo "ERROR: Unknown provider: ${PROVIDER_CMD}" >&2
|
|
59
|
-
exit 1
|
|
60
|
-
fi
|
|
61
|
-
|
|
62
|
-
rotate_log
|
|
63
|
-
|
|
64
|
-
if ! acquire_lock "${LOCK_FILE}"; then
|
|
65
|
-
emit_result "skip_locked"
|
|
66
|
-
exit 0
|
|
67
|
-
fi
|
|
68
|
-
|
|
69
|
-
cd "${PROJECT_DIR}"
|
|
70
|
-
|
|
71
|
-
# Convert comma-separated branch prefixes into a regex that matches branch starts.
|
|
72
|
-
BRANCH_REGEX=""
|
|
73
|
-
IFS=',' read -r -a BRANCH_PATTERNS <<< "${BRANCH_PATTERNS_RAW}"
|
|
74
|
-
for pattern in "${BRANCH_PATTERNS[@]}"; do
|
|
75
|
-
trimmed_pattern=$(printf '%s' "${pattern}" | sed -e 's/^[[:space:]]*//' -e 's/[[:space:]]*$//')
|
|
76
|
-
if [ -n "${trimmed_pattern}" ]; then
|
|
77
|
-
BRANCH_REGEX="${BRANCH_REGEX}${BRANCH_REGEX:+|}^${trimmed_pattern}"
|
|
78
|
-
fi
|
|
79
|
-
done
|
|
80
|
-
|
|
81
|
-
if [ -z "${BRANCH_REGEX}" ]; then
|
|
82
|
-
BRANCH_REGEX='^(feat/|night-watch/)'
|
|
83
|
-
fi
|
|
84
|
-
|
|
85
|
-
# List open PRs with their details for filtering
|
|
86
|
-
PR_JSON=$(gh pr list --state open --json number,headRefName,title,labels 2>/dev/null || echo "[]")
|
|
87
|
-
|
|
88
|
-
# Count PRs matching branch patterns
|
|
89
|
-
OPEN_PRS=$(
|
|
90
|
-
echo "${PR_JSON}" \
|
|
91
|
-
| jq -r '.[].headRefName' 2>/dev/null \
|
|
92
|
-
| { grep -E "${BRANCH_REGEX}" || true; } \
|
|
93
|
-
| wc -l \
|
|
94
|
-
| tr -d '[:space:]'
|
|
95
|
-
)
|
|
96
|
-
|
|
97
|
-
if [ "${OPEN_PRS}" -eq 0 ]; then
|
|
98
|
-
log "SKIP: No open PRs matching branch patterns (${BRANCH_PATTERNS_RAW})"
|
|
99
|
-
emit_result "skip_no_open_prs"
|
|
100
|
-
exit 0
|
|
101
|
-
fi
|
|
102
|
-
|
|
103
|
-
REPO=$(gh repo view --json nameWithOwner --jq '.nameWithOwner' 2>/dev/null || echo "")
|
|
104
|
-
|
|
105
|
-
# Collect PRs that need QA
|
|
106
|
-
PRS_NEEDING_QA=""
|
|
107
|
-
QA_NEEDED=0
|
|
108
|
-
|
|
109
|
-
while IFS=$'\t' read -r pr_number pr_branch pr_title pr_labels; do
|
|
110
|
-
if [ -z "${pr_number}" ] || [ -z "${pr_branch}" ]; then
|
|
111
|
-
continue
|
|
112
|
-
fi
|
|
113
|
-
|
|
114
|
-
# Filter by branch pattern
|
|
115
|
-
if ! printf '%s\n' "${pr_branch}" | grep -Eq "${BRANCH_REGEX}"; then
|
|
116
|
-
continue
|
|
117
|
-
fi
|
|
118
|
-
|
|
119
|
-
# Skip PRs with the skip label
|
|
120
|
-
if echo "${pr_labels}" | grep -q "${SKIP_LABEL}"; then
|
|
121
|
-
log "SKIP-QA: PR #${pr_number} (${pr_branch}) has '${SKIP_LABEL}' label"
|
|
122
|
-
continue
|
|
123
|
-
fi
|
|
124
|
-
|
|
125
|
-
# Skip PRs with [skip-qa] in their title
|
|
126
|
-
if echo "${pr_title}" | grep -qi '\[skip-qa\]'; then
|
|
127
|
-
log "SKIP-QA: PR #${pr_number} (${pr_branch}) has [skip-qa] in title"
|
|
128
|
-
continue
|
|
129
|
-
fi
|
|
130
|
-
|
|
131
|
-
# Skip PRs that already have a QA comment (idempotency)
|
|
132
|
-
ALL_COMMENTS=$(
|
|
133
|
-
{
|
|
134
|
-
gh pr view "${pr_number}" --json comments --jq '.comments[].body' 2>/dev/null || true
|
|
135
|
-
if [ -n "${REPO}" ]; then
|
|
136
|
-
gh api "repos/${REPO}/issues/${pr_number}/comments" --jq '.[].body' 2>/dev/null || true
|
|
137
|
-
fi
|
|
138
|
-
} | sort -u
|
|
139
|
-
)
|
|
140
|
-
if echo "${ALL_COMMENTS}" | grep -q '<!-- night-watch-qa-marker -->'; then
|
|
141
|
-
log "SKIP-QA: PR #${pr_number} (${pr_branch}) already has QA comment"
|
|
142
|
-
continue
|
|
143
|
-
fi
|
|
144
|
-
|
|
145
|
-
QA_NEEDED=1
|
|
146
|
-
PRS_NEEDING_QA="${PRS_NEEDING_QA} #${pr_number}"
|
|
147
|
-
done < <(
|
|
148
|
-
echo "${PR_JSON}" \
|
|
149
|
-
| jq -r '.[] | [.number, .headRefName, .title, ([.labels[].name] | join(","))] | @tsv' 2>/dev/null || true
|
|
150
|
-
)
|
|
151
|
-
|
|
152
|
-
if [ "${QA_NEEDED}" -eq 0 ]; then
|
|
153
|
-
log "SKIP: All ${OPEN_PRS} open PR(s) matching patterns already have QA comments"
|
|
154
|
-
emit_result "skip_all_qa_done"
|
|
155
|
-
exit 0
|
|
156
|
-
fi
|
|
157
|
-
|
|
158
|
-
PRS_NEEDING_QA=$(echo "${PRS_NEEDING_QA}" \
|
|
159
|
-
| sed -e 's/^[[:space:]]*//' -e 's/[[:space:]][[:space:]]*/ /g' -e 's/[[:space:]]*$//')
|
|
160
|
-
PRS_NEEDING_QA_CSV="${PRS_NEEDING_QA// /,}"
|
|
161
|
-
|
|
162
|
-
if [ -n "${NW_DEFAULT_BRANCH:-}" ]; then
|
|
163
|
-
DEFAULT_BRANCH="${NW_DEFAULT_BRANCH}"
|
|
164
|
-
else
|
|
165
|
-
DEFAULT_BRANCH=$(detect_default_branch "${PROJECT_DIR}")
|
|
166
|
-
fi
|
|
167
|
-
QA_WORKTREE_DIR="$(dirname "${PROJECT_DIR}")/${PROJECT_NAME}-nw-qa-runner"
|
|
168
|
-
|
|
169
|
-
log "START: Found PR(s) needing QA:${PRS_NEEDING_QA}"
|
|
170
|
-
|
|
171
|
-
cleanup_worktrees "${PROJECT_DIR}"
|
|
172
|
-
|
|
173
|
-
# Dry-run mode: print diagnostics and exit
|
|
174
|
-
if [ "${NW_DRY_RUN:-0}" = "1" ]; then
|
|
175
|
-
echo "=== Dry Run: QA Runner ==="
|
|
176
|
-
echo "Provider: ${PROVIDER_CMD}"
|
|
177
|
-
echo "Branch Patterns: ${BRANCH_PATTERNS_RAW}"
|
|
178
|
-
echo "Skip Label: ${SKIP_LABEL}"
|
|
179
|
-
echo "QA Artifacts: ${QA_ARTIFACTS}"
|
|
180
|
-
echo "Auto-install Playwright: ${QA_AUTO_INSTALL_PLAYWRIGHT}"
|
|
181
|
-
echo "Open PRs needing QA:${PRS_NEEDING_QA}"
|
|
182
|
-
echo "Default Branch: ${DEFAULT_BRANCH}"
|
|
183
|
-
echo "QA Worktree: ${QA_WORKTREE_DIR}"
|
|
184
|
-
echo "Timeout: ${MAX_RUNTIME}s"
|
|
185
|
-
exit 0
|
|
186
|
-
fi
|
|
187
|
-
|
|
188
|
-
EXIT_CODE=0
|
|
189
|
-
|
|
190
|
-
# Process each PR that needs QA
|
|
191
|
-
for pr_ref in ${PRS_NEEDING_QA}; do
|
|
192
|
-
pr_num="${pr_ref#\#}"
|
|
193
|
-
|
|
194
|
-
cleanup_worktrees "${PROJECT_DIR}"
|
|
195
|
-
if ! prepare_detached_worktree "${PROJECT_DIR}" "${QA_WORKTREE_DIR}" "${DEFAULT_BRANCH}" "${LOG_FILE}"; then
|
|
196
|
-
log "FAIL: Unable to create isolated QA worktree ${QA_WORKTREE_DIR} for PR #${pr_num}"
|
|
197
|
-
EXIT_CODE=1
|
|
198
|
-
break
|
|
199
|
-
fi
|
|
200
|
-
|
|
201
|
-
log "QA: Checking out PR #${pr_num} in worktree"
|
|
202
|
-
if ! (cd "${QA_WORKTREE_DIR}" && gh pr checkout "${pr_num}" >> "${LOG_FILE}" 2>&1); then
|
|
203
|
-
log "WARN: Failed to checkout PR #${pr_num}, skipping"
|
|
204
|
-
EXIT_CODE=1
|
|
205
|
-
cleanup_worktrees "${PROJECT_DIR}"
|
|
206
|
-
continue
|
|
207
|
-
fi
|
|
208
|
-
|
|
209
|
-
case "${PROVIDER_CMD}" in
|
|
210
|
-
claude)
|
|
211
|
-
if (
|
|
212
|
-
cd "${QA_WORKTREE_DIR}" && timeout "${MAX_RUNTIME}" \
|
|
213
|
-
claude -p "/night-watch-qa" \
|
|
214
|
-
--dangerously-skip-permissions \
|
|
215
|
-
>> "${LOG_FILE}" 2>&1
|
|
216
|
-
); then
|
|
217
|
-
log "QA: PR #${pr_num} — provider completed successfully"
|
|
218
|
-
else
|
|
219
|
-
local_exit=$?
|
|
220
|
-
log "QA: PR #${pr_num} — provider exited with code ${local_exit}"
|
|
221
|
-
if [ ${local_exit} -eq 124 ]; then
|
|
222
|
-
EXIT_CODE=124
|
|
223
|
-
break
|
|
224
|
-
fi
|
|
225
|
-
EXIT_CODE=${local_exit}
|
|
226
|
-
fi
|
|
227
|
-
;;
|
|
228
|
-
codex)
|
|
229
|
-
if (
|
|
230
|
-
cd "${QA_WORKTREE_DIR}" && timeout "${MAX_RUNTIME}" \
|
|
231
|
-
codex --quiet \
|
|
232
|
-
--yolo \
|
|
233
|
-
--prompt "$(cat "${QA_WORKTREE_DIR}/.claude/commands/night-watch-qa.md")" \
|
|
234
|
-
>> "${LOG_FILE}" 2>&1
|
|
235
|
-
); then
|
|
236
|
-
log "QA: PR #${pr_num} — provider completed successfully"
|
|
237
|
-
else
|
|
238
|
-
local_exit=$?
|
|
239
|
-
log "QA: PR #${pr_num} — provider exited with code ${local_exit}"
|
|
240
|
-
if [ ${local_exit} -eq 124 ]; then
|
|
241
|
-
EXIT_CODE=124
|
|
242
|
-
break
|
|
243
|
-
fi
|
|
244
|
-
EXIT_CODE=${local_exit}
|
|
245
|
-
fi
|
|
246
|
-
;;
|
|
247
|
-
*)
|
|
248
|
-
log "ERROR: Unknown provider: ${PROVIDER_CMD}"
|
|
249
|
-
exit 1
|
|
250
|
-
;;
|
|
251
|
-
esac
|
|
252
|
-
|
|
253
|
-
cleanup_worktrees "${PROJECT_DIR}"
|
|
254
|
-
done
|
|
255
|
-
|
|
256
|
-
cleanup_worktrees "${PROJECT_DIR}"
|
|
257
|
-
|
|
258
|
-
if [ ${EXIT_CODE} -eq 0 ]; then
|
|
259
|
-
log "DONE: QA runner completed successfully"
|
|
260
|
-
if [ -n "${REPO}" ]; then
|
|
261
|
-
emit_result "success_qa" "prs=${PRS_NEEDING_QA_CSV}|repo=${REPO}"
|
|
262
|
-
else
|
|
263
|
-
emit_result "success_qa" "prs=${PRS_NEEDING_QA_CSV}"
|
|
264
|
-
fi
|
|
265
|
-
elif [ ${EXIT_CODE} -eq 124 ]; then
|
|
266
|
-
log "TIMEOUT: QA runner killed after ${MAX_RUNTIME}s"
|
|
267
|
-
if [ -n "${REPO}" ]; then
|
|
268
|
-
emit_result "timeout" "prs=${PRS_NEEDING_QA_CSV}|repo=${REPO}"
|
|
269
|
-
else
|
|
270
|
-
emit_result "timeout" "prs=${PRS_NEEDING_QA_CSV}"
|
|
271
|
-
fi
|
|
272
|
-
else
|
|
273
|
-
log "FAIL: QA runner exited with code ${EXIT_CODE}"
|
|
274
|
-
if [ -n "${REPO}" ]; then
|
|
275
|
-
emit_result "failure" "prs=${PRS_NEEDING_QA_CSV}|repo=${REPO}"
|
|
276
|
-
else
|
|
277
|
-
emit_result "failure" "prs=${PRS_NEEDING_QA_CSV}"
|
|
278
|
-
fi
|
|
279
|
-
fi
|
|
280
|
-
|
|
281
|
-
exit "${EXIT_CODE}"
|
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
set -euo pipefail
|
|
3
|
-
|
|
4
|
-
# Night Watch Slicer Cron Runner (project-agnostic)
|
|
5
|
-
# Usage: night-watch-slicer-cron.sh /path/to/project
|
|
6
|
-
#
|
|
7
|
-
# This is a thin wrapper that acquires a lock and calls `night-watch slice`.
|
|
8
|
-
# The CLI command handles all the logic directly in TypeScript.
|
|
9
|
-
#
|
|
10
|
-
# NOTE: This script expects environment variables to be set by the caller.
|
|
11
|
-
# The Node.js CLI will inject config values via environment variables.
|
|
12
|
-
# Required env vars (with defaults shown):
|
|
13
|
-
# NW_SLICER_MAX_RUNTIME=600 - Maximum runtime in seconds (10 minutes)
|
|
14
|
-
# NW_PROVIDER_CMD=claude - AI provider CLI to use (claude, codex, etc.)
|
|
15
|
-
# NW_DRY_RUN=0 - Set to 1 for dry-run mode (prints diagnostics only)
|
|
16
|
-
|
|
17
|
-
PROJECT_DIR="${1:?Usage: $0 /path/to/project}"
|
|
18
|
-
PROJECT_NAME=$(basename "${PROJECT_DIR}")
|
|
19
|
-
LOG_DIR="${PROJECT_DIR}/logs"
|
|
20
|
-
LOG_FILE="${LOG_DIR}/night-watch-slicer.log"
|
|
21
|
-
LOCK_FILE=""
|
|
22
|
-
MAX_RUNTIME="${NW_SLICER_MAX_RUNTIME:-600}" # 10 minutes
|
|
23
|
-
MAX_LOG_SIZE="524288" # 512 KB
|
|
24
|
-
PROVIDER_CMD="${NW_PROVIDER_CMD:-claude}"
|
|
25
|
-
|
|
26
|
-
# Ensure NVM / Node / Night Watch CLI are on PATH
|
|
27
|
-
export NVM_DIR="${HOME}/.nvm"
|
|
28
|
-
[ -s "${NVM_DIR}/nvm.sh" ] && . "${NVM_DIR}/nvm.sh"
|
|
29
|
-
|
|
30
|
-
mkdir -p "${LOG_DIR}"
|
|
31
|
-
|
|
32
|
-
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
33
|
-
# shellcheck source=night-watch-helpers.sh
|
|
34
|
-
source "${SCRIPT_DIR}/night-watch-helpers.sh"
|
|
35
|
-
PROJECT_RUNTIME_KEY=$(project_runtime_key "${PROJECT_DIR}")
|
|
36
|
-
LOCK_FILE="/tmp/night-watch-slicer-${PROJECT_RUNTIME_KEY}.lock"
|
|
37
|
-
|
|
38
|
-
# Validate provider
|
|
39
|
-
if ! validate_provider "${PROVIDER_CMD}"; then
|
|
40
|
-
echo "ERROR: Unknown provider: ${PROVIDER_CMD}" >&2
|
|
41
|
-
exit 1
|
|
42
|
-
fi
|
|
43
|
-
|
|
44
|
-
rotate_log
|
|
45
|
-
|
|
46
|
-
if ! acquire_lock "${LOCK_FILE}"; then
|
|
47
|
-
exit 0
|
|
48
|
-
fi
|
|
49
|
-
|
|
50
|
-
cleanup_on_exit() {
|
|
51
|
-
rm -f "${LOCK_FILE}"
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
trap cleanup_on_exit EXIT
|
|
55
|
-
|
|
56
|
-
log "START: Running roadmap slicer for ${PROJECT_DIR}"
|
|
57
|
-
|
|
58
|
-
# Dry-run mode: print diagnostics and exit
|
|
59
|
-
if [ "${NW_DRY_RUN:-0}" = "1" ]; then
|
|
60
|
-
echo "=== Dry Run: Roadmap Slicer ==="
|
|
61
|
-
echo "Provider: ${PROVIDER_CMD}"
|
|
62
|
-
echo "Project Dir: ${PROJECT_DIR}"
|
|
63
|
-
echo "Timeout: ${MAX_RUNTIME}s"
|
|
64
|
-
exit 0
|
|
65
|
-
fi
|
|
66
|
-
|
|
67
|
-
# Resolve night-watch CLI
|
|
68
|
-
CLI_BIN=""
|
|
69
|
-
if ! CLI_BIN=$(resolve_night_watch_cli); then
|
|
70
|
-
log "ERROR: Could not resolve night-watch CLI"
|
|
71
|
-
exit 1
|
|
72
|
-
fi
|
|
73
|
-
|
|
74
|
-
# Run the slice command with timeout
|
|
75
|
-
EXIT_CODE=0
|
|
76
|
-
if timeout "${MAX_RUNTIME}" "${CLI_BIN}" slice >> "${LOG_FILE}" 2>&1; then
|
|
77
|
-
EXIT_CODE=0
|
|
78
|
-
else
|
|
79
|
-
EXIT_CODE=$?
|
|
80
|
-
fi
|
|
81
|
-
|
|
82
|
-
if [ ${EXIT_CODE} -eq 0 ]; then
|
|
83
|
-
log "DONE: Slicer completed successfully"
|
|
84
|
-
elif [ ${EXIT_CODE} -eq 124 ]; then
|
|
85
|
-
log "TIMEOUT: Slicer killed after ${MAX_RUNTIME}s"
|
|
86
|
-
else
|
|
87
|
-
log "FAIL: Slicer exited with code ${EXIT_CODE}"
|
|
88
|
-
fi
|
|
89
|
-
|
|
90
|
-
exit ${EXIT_CODE}
|
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bats
|
|
2
|
-
|
|
3
|
-
# Tests for night-watch-helpers.sh claim functions
|
|
4
|
-
|
|
5
|
-
setup() {
|
|
6
|
-
# Source the helpers
|
|
7
|
-
SCRIPT_DIR="$(cd "$(dirname "${BATS_TEST_FILENAME}")" && pwd)"
|
|
8
|
-
|
|
9
|
-
# Set required globals
|
|
10
|
-
export LOG_FILE="/tmp/night-watch-test-$$.log"
|
|
11
|
-
|
|
12
|
-
source "${SCRIPT_DIR}/night-watch-helpers.sh"
|
|
13
|
-
|
|
14
|
-
# Create temp PRD directory
|
|
15
|
-
TEST_PRD_DIR=$(mktemp -d)
|
|
16
|
-
echo "# Test PRD" > "${TEST_PRD_DIR}/01-test-prd.md"
|
|
17
|
-
echo "# Test PRD 2" > "${TEST_PRD_DIR}/02-test-prd.md"
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
teardown() {
|
|
21
|
-
rm -rf "${TEST_PRD_DIR}"
|
|
22
|
-
rm -f "${LOG_FILE}"
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
@test "claim_prd creates .claim file with JSON" {
|
|
26
|
-
claim_prd "${TEST_PRD_DIR}" "01-test-prd.md"
|
|
27
|
-
|
|
28
|
-
[ -f "${TEST_PRD_DIR}/01-test-prd.md.claim" ]
|
|
29
|
-
|
|
30
|
-
local content
|
|
31
|
-
content=$(cat "${TEST_PRD_DIR}/01-test-prd.md.claim")
|
|
32
|
-
|
|
33
|
-
# Check JSON contains expected fields
|
|
34
|
-
echo "${content}" | grep -q '"timestamp":'
|
|
35
|
-
echo "${content}" | grep -q '"hostname":'
|
|
36
|
-
echo "${content}" | grep -q '"pid":'
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
@test "is_claimed returns 0 for active claim" {
|
|
40
|
-
claim_prd "${TEST_PRD_DIR}" "01-test-prd.md"
|
|
41
|
-
|
|
42
|
-
run is_claimed "${TEST_PRD_DIR}" "01-test-prd.md" 7200
|
|
43
|
-
[ "$status" -eq 0 ]
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
@test "is_claimed returns 1 for stale claim" {
|
|
47
|
-
# Write a claim with an old timestamp (1 second)
|
|
48
|
-
printf '{"timestamp":1000000000,"hostname":"test","pid":1}\n' \
|
|
49
|
-
> "${TEST_PRD_DIR}/01-test-prd.md.claim"
|
|
50
|
-
|
|
51
|
-
run is_claimed "${TEST_PRD_DIR}" "01-test-prd.md" 7200
|
|
52
|
-
[ "$status" -eq 1 ]
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
@test "is_claimed returns 1 for no claim" {
|
|
56
|
-
run is_claimed "${TEST_PRD_DIR}" "01-test-prd.md" 7200
|
|
57
|
-
[ "$status" -eq 1 ]
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
@test "release_claim removes .claim file" {
|
|
61
|
-
claim_prd "${TEST_PRD_DIR}" "01-test-prd.md"
|
|
62
|
-
[ -f "${TEST_PRD_DIR}/01-test-prd.md.claim" ]
|
|
63
|
-
|
|
64
|
-
release_claim "${TEST_PRD_DIR}" "01-test-prd.md"
|
|
65
|
-
[ ! -f "${TEST_PRD_DIR}/01-test-prd.md.claim" ]
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
@test "find_eligible_prd skips claimed PRD" {
|
|
69
|
-
# Claim the first PRD
|
|
70
|
-
claim_prd "${TEST_PRD_DIR}" "01-test-prd.md"
|
|
71
|
-
|
|
72
|
-
# find_eligible_prd should skip 01 and return 02
|
|
73
|
-
local result
|
|
74
|
-
result=$(find_eligible_prd "${TEST_PRD_DIR}" 7200)
|
|
75
|
-
|
|
76
|
-
[ "${result}" = "02-test-prd.md" ]
|
|
77
|
-
}
|
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
You are the Night Watch PR Reviewer agent. Your job is to check open PRs for three things:
|
|
2
|
-
1. Merge conflicts -- rebase onto the base branch and resolve them.
|
|
3
|
-
2. Review comments with a score below 80 -- address the feedback.
|
|
4
|
-
3. Failed CI jobs -- diagnose and fix the failures.
|
|
5
|
-
|
|
6
|
-
## Context
|
|
7
|
-
|
|
8
|
-
The repo has two GitHub Actions workflows that run on PRs:
|
|
9
|
-
- **`.github/workflows/pr-review.yml`** -- AI review that posts a score (0-100) as a comment.
|
|
10
|
-
- **`.github/workflows/ci.yml`** -- CI pipeline with jobs: `typecheck`, `lint`, `test`, `build`, and `verify`.
|
|
11
|
-
|
|
12
|
-
A PR needs attention if **any** of the following: merge conflicts present, review score below 80, or any CI job failed.
|
|
13
|
-
|
|
14
|
-
## Important: Early Exit
|
|
15
|
-
|
|
16
|
-
- If there are **no open PRs** on `night-watch/` or `feat/` branches, **stop immediately** and report "No PRs to review."
|
|
17
|
-
- If all open PRs have **no merge conflicts**, **passing CI**, and **review score >= 80** (or no review score yet), **stop immediately** and report "All PRs are in good shape."
|
|
18
|
-
- Do **NOT** loop or retry. Process each PR **once** per run. After processing all PRs, stop.
|
|
19
|
-
- Do **NOT** re-check PRs after pushing fixes -- the CI will re-run automatically on the next push.
|
|
20
|
-
|
|
21
|
-
## Instructions
|
|
22
|
-
|
|
23
|
-
1. **Find open PRs** created by Night Watch:
|
|
24
|
-
```
|
|
25
|
-
gh pr list --state open --json number,title,headRefName,url
|
|
26
|
-
```
|
|
27
|
-
Filter for PRs on `night-watch/` or `feat/` branches.
|
|
28
|
-
|
|
29
|
-
2. **For each PR**, check three things:
|
|
30
|
-
|
|
31
|
-
### A. Check for Merge Conflicts
|
|
32
|
-
|
|
33
|
-
```
|
|
34
|
-
gh pr view <number> --json mergeStateStatus --jq '.mergeStateStatus'
|
|
35
|
-
```
|
|
36
|
-
If the result is `DIRTY` or `CONFLICTING`, the PR has merge conflicts that **must** be resolved before anything else.
|
|
37
|
-
|
|
38
|
-
### B. Check CI Status
|
|
39
|
-
|
|
40
|
-
Fetch the CI check status for the PR:
|
|
41
|
-
```
|
|
42
|
-
gh pr checks <number> --json name,state,conclusion
|
|
43
|
-
```
|
|
44
|
-
If any check has `conclusion` of `failure` (or `state` is not `completed`/`success`), the PR has CI failures that need fixing.
|
|
45
|
-
|
|
46
|
-
To get details on why a CI job failed, fetch the workflow run logs:
|
|
47
|
-
```
|
|
48
|
-
gh run list --branch <branch-name> --limit 1 --json databaseId,conclusion,status
|
|
49
|
-
```
|
|
50
|
-
Then view the failed job logs:
|
|
51
|
-
```
|
|
52
|
-
gh run view <run-id> --log-failed
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
### C. Check Review Score
|
|
56
|
-
|
|
57
|
-
Fetch the **comments** (NOT reviews -- the bot posts as a regular issue comment):
|
|
58
|
-
```
|
|
59
|
-
gh pr view <number> --json comments --jq '.comments[].body'
|
|
60
|
-
```
|
|
61
|
-
If that returns nothing, also try:
|
|
62
|
-
```
|
|
63
|
-
gh api repos/{owner}/{repo}/issues/<number>/comments --jq '.[].body'
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
Parse the review score from the comment body. Look for patterns like:
|
|
67
|
-
- `**Overall Score:** XX/100`
|
|
68
|
-
- `**Score:** XX/100`
|
|
69
|
-
- `Overall Score:** XX/100`
|
|
70
|
-
Extract the numeric score. If multiple comments have scores, use the **most recent** one.
|
|
71
|
-
|
|
72
|
-
3. **Determine if PR needs work**:
|
|
73
|
-
- If no merge conflicts **AND** score >= 80 **AND** all CI checks pass --> skip this PR.
|
|
74
|
-
- If merge conflicts present **OR** score < 80 **OR** any CI check failed --> fix the issues.
|
|
75
|
-
|
|
76
|
-
4. **Fix the PR**:
|
|
77
|
-
|
|
78
|
-
a. **Create an isolated review worktree**:
|
|
79
|
-
```
|
|
80
|
-
git fetch origin
|
|
81
|
-
git worktree add --detach ../${PROJECT_NAME}-nw-review-<branch-name> origin/${DEFAULT_BRANCH}
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
b. **Check out the PR branch inside that worktree**:
|
|
85
|
-
```
|
|
86
|
-
cd ../${PROJECT_NAME}-nw-review-<branch-name>
|
|
87
|
-
git checkout <branch-name>
|
|
88
|
-
git pull origin <branch-name>
|
|
89
|
-
```
|
|
90
|
-
Run package install (npm install, yarn install, or pnpm install as appropriate).
|
|
91
|
-
|
|
92
|
-
c. **Resolve merge conflicts** (if `mergeStateStatus` was `DIRTY` or `CONFLICTING`):
|
|
93
|
-
- Get the base branch: `gh pr view <number> --json baseRefName --jq '.baseRefName'`
|
|
94
|
-
- Rebase the PR branch onto the latest base branch:
|
|
95
|
-
```
|
|
96
|
-
git fetch origin
|
|
97
|
-
git rebase origin/<base-branch>
|
|
98
|
-
```
|
|
99
|
-
- For each conflicted file, examine the conflict markers carefully. Preserve the PR's intended changes while incorporating upstream updates. Resolve each conflict, then stage it:
|
|
100
|
-
```
|
|
101
|
-
git add <resolved-file>
|
|
102
|
-
```
|
|
103
|
-
- Continue the rebase: `git rebase --continue`
|
|
104
|
-
- Repeat until the rebase completes without conflicts.
|
|
105
|
-
- Push the clean branch: `git push --force-with-lease origin <branch-name>`
|
|
106
|
-
- **Do NOT leave any conflict markers (`<<<<<<<`, `=======`, `>>>>>>>`) in any file.**
|
|
107
|
-
|
|
108
|
-
d. **Address CI failures** (if any):
|
|
109
|
-
- Read the failed job logs carefully to understand the root cause.
|
|
110
|
-
- **typecheck failures**: Fix TypeScript type errors.
|
|
111
|
-
- **lint failures**: Fix ESLint violations.
|
|
112
|
-
- **test failures**: Fix broken tests or update tests to match code changes.
|
|
113
|
-
- **build failures**: Fix compilation/bundling errors.
|
|
114
|
-
- **verify failures**: This runs after all others -- usually means one of the above needs fixing.
|
|
115
|
-
|
|
116
|
-
e. **Address review feedback** (if score < 80):
|
|
117
|
-
- Read the review comments carefully. Extract areas for improvement, bugs found, issues found, and specific file/line suggestions.
|
|
118
|
-
- Fix bugs identified.
|
|
119
|
-
- Improve error handling if flagged.
|
|
120
|
-
- Add missing tests if coverage was noted.
|
|
121
|
-
- Refactor code if structure was criticized.
|
|
122
|
-
- Follow all project conventions from AI assistant documentation files (e.g., CLAUDE.md, AGENTS.md, or similar).
|
|
123
|
-
|
|
124
|
-
f. **Run verification**: Run the project's test/lint commands (e.g., `npm test`, `npm run lint`, `npm run verify` or equivalent). Fix until it passes.
|
|
125
|
-
|
|
126
|
-
g. **Commit and push** the fixes (only if there are staged changes beyond the rebase):
|
|
127
|
-
```
|
|
128
|
-
git add <files>
|
|
129
|
-
git commit -m "fix: address PR review feedback and CI failures
|
|
130
|
-
|
|
131
|
-
- <bullet point for each fix>
|
|
132
|
-
|
|
133
|
-
<If merge conflicts resolved>Rebased onto <base-branch> and resolved merge conflicts.<end>
|
|
134
|
-
<If review score existed>Review score was <XX>/100.<end>
|
|
135
|
-
<If CI failed>CI failures fixed: <job1>, <job2>.<end>
|
|
136
|
-
|
|
137
|
-
Addressed:
|
|
138
|
-
- <issue 1>
|
|
139
|
-
- <issue 2>
|
|
140
|
-
|
|
141
|
-
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>"
|
|
142
|
-
|
|
143
|
-
git push origin <branch-name>
|
|
144
|
-
```
|
|
145
|
-
Note: if the only change was a conflict-free rebase, the `--force-with-lease` push from step (c) is sufficient -- no extra commit needed.
|
|
146
|
-
|
|
147
|
-
h. **Comment on the PR** summarizing what was addressed:
|
|
148
|
-
```
|
|
149
|
-
gh pr comment <number> --body "## Night Watch PR Fix
|
|
150
|
-
|
|
151
|
-
<If merge conflicts resolved>### Merge Conflicts Resolved:
|
|
152
|
-
Rebased onto `<base-branch>`. Resolved conflicts in: <file1>, <file2>.<end>
|
|
153
|
-
|
|
154
|
-
<If review score existed>Previous review score: **<XX>/100**<end>
|
|
155
|
-
|
|
156
|
-
### Changes made:
|
|
157
|
-
- <fix 1>
|
|
158
|
-
- <fix 2>
|
|
159
|
-
|
|
160
|
-
<If CI was fixed>### CI Failures Fixed:
|
|
161
|
-
- <job>: <what was wrong and how it was fixed><end>
|
|
162
|
-
|
|
163
|
-
\`npm run verify\` passes locally. Ready for re-review.
|
|
164
|
-
|
|
165
|
-
Night Watch PR Reviewer"
|
|
166
|
-
```
|
|
167
|
-
|
|
168
|
-
i. **Clean up worktree**: `git worktree remove ../${PROJECT_NAME}-nw-review-<branch-name>`
|
|
169
|
-
|
|
170
|
-
5. **Repeat** for all open PRs that need work.
|
|
171
|
-
|
|
172
|
-
6. When done, return to ${DEFAULT_BRANCH}: `git checkout ${DEFAULT_BRANCH}`
|
|
173
|
-
|
|
174
|
-
Start now. Check for open PRs that need merge conflicts resolved, review feedback addressed, or CI failures fixed.
|