cloving 0.3.20 → 1.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/{LICENSE.md → LICENSE} +1 -1
- package/README.md +475 -182
- package/dist/src/authority/budgets.d.ts +12 -0
- package/dist/src/authority/budgets.js +42 -0
- package/dist/src/authority/commands.d.ts +7 -0
- package/dist/src/authority/commands.js +263 -0
- package/dist/src/authority/details.d.ts +28 -0
- package/dist/src/authority/details.js +33 -0
- package/dist/src/authority/dispatch-decision.d.ts +40 -0
- package/dist/src/authority/dispatch-decision.js +47 -0
- package/dist/src/authority/effect-requests.d.ts +2 -0
- package/dist/src/authority/effect-requests.js +139 -0
- package/dist/src/authority/effect-results.d.ts +4 -0
- package/dist/src/authority/effect-results.js +236 -0
- package/dist/src/authority/events.d.ts +2 -0
- package/dist/src/authority/events.js +45 -0
- package/dist/src/authority/gate-reduction.d.ts +8 -0
- package/dist/src/authority/gate-reduction.js +109 -0
- package/dist/src/authority/gates.d.ts +48 -0
- package/dist/src/authority/gates.js +77 -0
- package/dist/src/authority/history-state.d.ts +15 -0
- package/dist/src/authority/history-state.js +61 -0
- package/dist/src/authority/history.d.ts +13 -0
- package/dist/src/authority/history.js +37 -0
- package/dist/src/authority/instants.d.ts +3 -0
- package/dist/src/authority/instants.js +38 -0
- package/dist/src/authority/leases.d.ts +15 -0
- package/dist/src/authority/leases.js +113 -0
- package/dist/src/authority/operations.d.ts +101 -0
- package/dist/src/authority/operations.js +75 -0
- package/dist/src/authority/reconciliation.d.ts +27 -0
- package/dist/src/authority/reconciliation.js +147 -0
- package/dist/src/authority/reducer.d.ts +41 -0
- package/dist/src/authority/reducer.js +139 -0
- package/dist/src/authority/reduction-state.d.ts +36 -0
- package/dist/src/authority/reduction-state.js +68 -0
- package/dist/src/authority/reduction.d.ts +6 -0
- package/dist/src/authority/reduction.js +160 -0
- package/dist/src/authority/status-closure.d.ts +4 -0
- package/dist/src/authority/status-closure.js +57 -0
- package/dist/src/authority/status-effects.d.ts +17 -0
- package/dist/src/authority/status-effects.js +43 -0
- package/dist/src/authority/status-input.d.ts +45 -0
- package/dist/src/authority/status-input.js +9 -0
- package/dist/src/authority/status.d.ts +32 -0
- package/dist/src/authority/status.js +256 -0
- package/dist/src/authority/stop-sequence.d.ts +37 -0
- package/dist/src/authority/stop-sequence.js +91 -0
- package/dist/src/authority/transitions.d.ts +63 -0
- package/dist/src/authority/transitions.js +122 -0
- package/dist/src/broker/actor/adapter-calls.d.ts +13 -0
- package/dist/src/broker/actor/adapter-calls.js +34 -0
- package/dist/src/broker/actor/adapter-outcomes.d.ts +28 -0
- package/dist/src/broker/actor/adapter-outcomes.js +80 -0
- package/dist/src/broker/actor/authority-actor.d.ts +25 -0
- package/dist/src/broker/actor/authority-actor.js +169 -0
- package/dist/src/broker/actor/authority-changes.d.ts +31 -0
- package/dist/src/broker/actor/authority-changes.js +46 -0
- package/dist/src/broker/actor/authority-connection.d.ts +15 -0
- package/dist/src/broker/actor/authority-connection.js +44 -0
- package/dist/src/broker/actor/authority-conversion.d.ts +10 -0
- package/dist/src/broker/actor/authority-conversion.js +72 -0
- package/dist/src/broker/actor/authority-delivery.d.ts +13 -0
- package/dist/src/broker/actor/authority-delivery.js +162 -0
- package/dist/src/broker/actor/authority-logger.d.ts +2 -0
- package/dist/src/broker/actor/authority-logger.js +19 -0
- package/dist/src/broker/actor/authority-policy.d.ts +9 -0
- package/dist/src/broker/actor/authority-policy.js +11 -0
- package/dist/src/broker/actor/authority-queries.d.ts +45 -0
- package/dist/src/broker/actor/authority-queries.js +85 -0
- package/dist/src/broker/actor/authority-receipts.d.ts +28 -0
- package/dist/src/broker/actor/authority-receipts.js +84 -0
- package/dist/src/broker/actor/authority-release.d.ts +13 -0
- package/dist/src/broker/actor/authority-release.js +69 -0
- package/dist/src/broker/actor/authority-runtime.d.ts +60 -0
- package/dist/src/broker/actor/authority-runtime.js +204 -0
- package/dist/src/broker/actor/authority-session.d.ts +65 -0
- package/dist/src/broker/actor/authority-session.js +252 -0
- package/dist/src/broker/actor/authority-settings.d.ts +33 -0
- package/dist/src/broker/actor/authority-settings.js +63 -0
- package/dist/src/broker/actor/authority-upgrades.d.ts +16 -0
- package/dist/src/broker/actor/authority-upgrades.js +12 -0
- package/dist/src/broker/actor/authority-watchdog.d.ts +14 -0
- package/dist/src/broker/actor/authority-watchdog.js +41 -0
- package/dist/src/broker/actor/authority.d.ts +14 -0
- package/dist/src/broker/actor/authority.js +115 -0
- package/dist/src/broker/actor/delivery-intents.d.ts +68 -0
- package/dist/src/broker/actor/delivery-intents.js +77 -0
- package/dist/src/broker/actor/delivery-plan.d.ts +2 -0
- package/dist/src/broker/actor/delivery-plan.js +109 -0
- package/dist/src/broker/actor/delivery-results.d.ts +11 -0
- package/dist/src/broker/actor/delivery-results.js +63 -0
- package/dist/src/broker/actor/effect-delivery.d.ts +19 -0
- package/dist/src/broker/actor/effect-delivery.js +118 -0
- package/dist/src/broker/actor/effect-plan.d.ts +41 -0
- package/dist/src/broker/actor/effect-plan.js +173 -0
- package/dist/src/broker/actor/effect-queries.d.ts +27 -0
- package/dist/src/broker/actor/effect-queries.js +80 -0
- package/dist/src/broker/actor/effect-turn.d.ts +25 -0
- package/dist/src/broker/actor/effect-turn.js +84 -0
- package/dist/src/broker/actor/pin-check.d.ts +6 -0
- package/dist/src/broker/actor/pin-check.js +12 -0
- package/dist/src/broker/actor/runtime-parts.d.ts +23 -0
- package/dist/src/broker/actor/runtime-parts.js +34 -0
- package/dist/src/broker/actor/stop-plan.d.ts +20 -0
- package/dist/src/broker/actor/stop-plan.js +46 -0
- package/dist/src/broker/actor/stop-turn.d.ts +17 -0
- package/dist/src/broker/actor/stop-turn.js +42 -0
- package/dist/src/broker/actor/turn-draft.d.ts +31 -0
- package/dist/src/broker/actor/turn-draft.js +138 -0
- package/dist/src/broker/actor/turn-plan.d.ts +17 -0
- package/dist/src/broker/actor/turn-plan.js +136 -0
- package/dist/src/broker/actor/turn-refusals.d.ts +8 -0
- package/dist/src/broker/actor/turn-refusals.js +35 -0
- package/dist/src/broker/actor/turn-staging.d.ts +78 -0
- package/dist/src/broker/actor/turn-staging.js +34 -0
- package/dist/src/broker/actor/turn-state.d.ts +34 -0
- package/dist/src/broker/actor/turn-state.js +208 -0
- package/dist/src/broker/authority-admission.d.ts +21 -0
- package/dist/src/broker/authority-admission.js +70 -0
- package/dist/src/broker/authority-restore.d.ts +30 -0
- package/dist/src/broker/authority-restore.js +165 -0
- package/dist/src/broker/decision-restore.d.ts +16 -0
- package/dist/src/broker/decision-restore.js +158 -0
- package/dist/src/broker/decision-upgrade.d.ts +3 -0
- package/dist/src/broker/decision-upgrade.js +12 -0
- package/dist/src/broker/effect-restore.d.ts +20 -0
- package/dist/src/broker/effect-restore.js +111 -0
- package/dist/src/broker/effect-upgrade.d.ts +3 -0
- package/dist/src/broker/effect-upgrade.js +9 -0
- package/dist/src/broker/operation-digest.d.ts +1 -0
- package/dist/src/broker/operation-digest.js +4 -0
- package/dist/src/broker/socket-address.d.ts +9 -0
- package/dist/src/broker/socket-address.js +14 -0
- package/dist/src/broker/workflow-pin.d.ts +2 -0
- package/dist/src/broker/workflow-pin.js +5 -0
- package/dist/src/chats/destination.d.ts +4 -0
- package/dist/src/chats/destination.js +94 -0
- package/dist/src/chats/import.d.ts +13 -0
- package/dist/src/chats/import.js +71 -0
- package/dist/src/chats/normalize.d.ts +20 -0
- package/dist/src/chats/normalize.js +139 -0
- package/dist/src/chats/reader.d.ts +15 -0
- package/dist/src/chats/reader.js +87 -0
- package/dist/src/cli/arguments.d.ts +23 -0
- package/dist/src/cli/arguments.js +154 -0
- package/dist/src/cli/client.d.ts +15 -0
- package/dist/src/cli/client.js +122 -0
- package/dist/src/cli/commands.d.ts +14 -0
- package/dist/src/cli/commands.js +253 -0
- package/dist/src/cli/main.d.ts +1 -0
- package/dist/src/cli/main.js +80 -0
- package/dist/src/cli/render.d.ts +8 -0
- package/dist/src/cli/render.js +186 -0
- package/dist/src/cli/runtime-arguments.d.ts +73 -0
- package/dist/src/cli/runtime-arguments.js +248 -0
- package/dist/src/cli/runtime-directory.d.ts +4 -0
- package/dist/src/cli/runtime-directory.js +25 -0
- package/dist/src/cli/toolchain.d.ts +3 -0
- package/dist/src/cli/toolchain.js +74 -0
- package/dist/src/cli/usage.d.ts +4 -0
- package/dist/src/cli/usage.js +124 -0
- package/dist/src/cli/validate.d.ts +38 -0
- package/dist/src/cli/validate.js +116 -0
- package/dist/src/cli/watch-board-view.d.ts +22 -0
- package/dist/src/cli/watch-board-view.js +128 -0
- package/dist/src/cli/watch-board.d.ts +15 -0
- package/dist/src/cli/watch-board.js +174 -0
- package/dist/src/cli/watch-element.d.ts +11 -0
- package/dist/src/cli/watch-element.js +6 -0
- package/dist/src/cli/watch-model.d.ts +29 -0
- package/dist/src/cli/watch-model.js +261 -0
- package/dist/src/cli/watch-navigation.d.ts +9 -0
- package/dist/src/cli/watch-navigation.js +40 -0
- package/dist/src/cli/watch-page.d.ts +1 -0
- package/dist/src/cli/watch-page.js +272 -0
- package/dist/src/cli/watch-paths.d.ts +2 -0
- package/dist/src/cli/watch-paths.js +52 -0
- package/dist/src/cli/watch-phases.d.ts +7 -0
- package/dist/src/cli/watch-phases.js +148 -0
- package/dist/src/cli/watch-reads.d.ts +28 -0
- package/dist/src/cli/watch-reads.js +244 -0
- package/dist/src/cli/watch-render.d.ts +139 -0
- package/dist/src/cli/watch-render.js +95 -0
- package/dist/src/cli/watch-server.d.ts +10 -0
- package/dist/src/cli/watch-server.js +176 -0
- package/dist/src/cli/watch-stream.d.ts +11 -0
- package/dist/src/cli/watch-stream.js +128 -0
- package/dist/src/cli/watch-turn.d.ts +29 -0
- package/dist/src/cli/watch-turn.js +130 -0
- package/dist/src/cli/watch-view.d.ts +39 -0
- package/dist/src/cli/watch-view.js +223 -0
- package/dist/src/cli.d.ts +2 -0
- package/dist/src/cli.js +62 -0
- package/dist/src/daemon/claude-turn.d.ts +28 -0
- package/dist/src/daemon/claude-turn.js +135 -0
- package/dist/src/daemon/claude-worker.d.ts +26 -0
- package/dist/src/daemon/claude-worker.js +224 -0
- package/dist/src/daemon/codex-stream.d.ts +4 -0
- package/dist/src/daemon/codex-stream.js +113 -0
- package/dist/src/daemon/daemon.d.ts +46 -0
- package/dist/src/daemon/daemon.js +186 -0
- package/dist/src/daemon/delivery-router.d.ts +10 -0
- package/dist/src/daemon/delivery-router.js +34 -0
- package/dist/src/daemon/github-calls.d.ts +29 -0
- package/dist/src/daemon/github-calls.js +127 -0
- package/dist/src/daemon/github-issue-methods.d.ts +3 -0
- package/dist/src/daemon/github-issue-methods.js +99 -0
- package/dist/src/daemon/github-issue-privacy.d.ts +6 -0
- package/dist/src/daemon/github-issue-privacy.js +131 -0
- package/dist/src/daemon/github-merge.d.ts +18 -0
- package/dist/src/daemon/github-merge.js +259 -0
- package/dist/src/daemon/github-methods.d.ts +5 -0
- package/dist/src/daemon/github-methods.js +198 -0
- package/dist/src/daemon/github-operation.d.ts +38 -0
- package/dist/src/daemon/github-operation.js +57 -0
- package/dist/src/daemon/github-worker.d.ts +17 -0
- package/dist/src/daemon/github-worker.js +281 -0
- package/dist/src/daemon/host-environment.d.ts +8 -0
- package/dist/src/daemon/host-environment.js +14 -0
- package/dist/src/daemon/issue-queue.d.ts +9 -0
- package/dist/src/daemon/issue-queue.js +163 -0
- package/dist/src/daemon/notify-message.d.ts +14 -0
- package/dist/src/daemon/notify-message.js +48 -0
- package/dist/src/daemon/notify.d.ts +12 -0
- package/dist/src/daemon/notify.js +161 -0
- package/dist/src/daemon/operation-journal.d.ts +42 -0
- package/dist/src/daemon/operation-journal.js +53 -0
- package/dist/src/daemon/ticket-registration.d.ts +33 -0
- package/dist/src/daemon/ticket-registration.js +177 -0
- package/dist/src/daemon/ticket-source.d.ts +17 -0
- package/dist/src/daemon/ticket-source.js +36 -0
- package/dist/src/daemon/work-tree.d.ts +26 -0
- package/dist/src/daemon/work-tree.js +206 -0
- package/dist/src/effect-authorization.d.ts +21 -0
- package/dist/src/effect-authorization.js +14 -0
- package/dist/src/execution-pin.d.ts +4 -0
- package/dist/src/execution-pin.js +68 -0
- package/dist/src/host/start-delivery.d.ts +41 -0
- package/dist/src/host/start-delivery.js +68 -0
- package/dist/src/host/step-bridge-host.d.ts +79 -0
- package/dist/src/host/step-bridge-host.js +205 -0
- package/dist/src/host/step-claims.d.ts +31 -0
- package/dist/src/host/step-claims.js +85 -0
- package/dist/src/host/world-host.d.ts +21 -0
- package/dist/src/host/world-host.js +51 -0
- package/dist/src/host/world-reconciliation.d.ts +37 -0
- package/dist/src/host/world-reconciliation.js +75 -0
- package/dist/src/host/world-runs.d.ts +14 -0
- package/dist/src/host/world-runs.js +61 -0
- package/dist/src/operation-identity.d.ts +7 -0
- package/dist/src/operation-identity.js +59 -0
- package/dist/src/protocol.d.ts +35 -0
- package/dist/src/protocol.js +64 -0
- package/dist/src/resource-files.d.ts +1 -0
- package/dist/src/resource-files.js +29 -0
- package/dist/src/service/changes.d.ts +11 -0
- package/dist/src/service/changes.js +32 -0
- package/dist/src/service/decision-handler.d.ts +9 -0
- package/dist/src/service/decision-handler.js +233 -0
- package/dist/src/service/event-handler.d.ts +10 -0
- package/dist/src/service/event-handler.js +70 -0
- package/dist/src/service/expiry.d.ts +13 -0
- package/dist/src/service/expiry.js +53 -0
- package/dist/src/service/gateway.d.ts +21 -0
- package/dist/src/service/gateway.js +120 -0
- package/dist/src/service/registry.d.ts +40 -0
- package/dist/src/service/registry.js +13 -0
- package/dist/src/service/replies.d.ts +26 -0
- package/dist/src/service/replies.js +56 -0
- package/dist/src/service/run-handlers.d.ts +4 -0
- package/dist/src/service/run-handlers.js +271 -0
- package/dist/src/service/service.d.ts +58 -0
- package/dist/src/service/service.js +212 -0
- package/dist/src/service/submission-handler.d.ts +4 -0
- package/dist/src/service/submission-handler.js +206 -0
- package/dist/src/service/transport.d.ts +16 -0
- package/dist/src/service/transport.js +141 -0
- package/dist/src/service/worker-port.d.ts +85 -0
- package/dist/src/service/worker-port.js +126 -0
- package/dist/src/step-bridge.d.ts +57 -0
- package/dist/src/step-bridge.js +4 -0
- package/dist/src/steps/decision-gate.d.ts +2 -0
- package/dist/src/steps/decision-gate.js +8 -0
- package/dist/src/steps/load-cycle.d.ts +10 -0
- package/dist/src/steps/load-cycle.js +11 -0
- package/dist/src/steps/protected-effect.d.ts +2 -0
- package/dist/src/steps/protected-effect.js +8 -0
- package/dist/src/storage/decision-rows.d.ts +54 -0
- package/dist/src/storage/decision-rows.js +72 -0
- package/dist/src/storage/decision-snapshots.d.ts +17 -0
- package/dist/src/storage/decision-snapshots.js +25 -0
- package/dist/src/storage/domain-changes.d.ts +48 -0
- package/dist/src/storage/domain-changes.js +213 -0
- package/dist/src/storage/domain-rows.d.ts +85 -0
- package/dist/src/storage/domain-rows.js +129 -0
- package/dist/src/storage/domain-schema.d.ts +32 -0
- package/dist/src/storage/domain-schema.js +193 -0
- package/dist/src/storage/effect-changes.d.ts +5 -0
- package/dist/src/storage/effect-changes.js +105 -0
- package/dist/src/storage/effect-rows.d.ts +67 -0
- package/dist/src/storage/effect-rows.js +74 -0
- package/dist/src/storage/effect-schema.d.ts +1 -0
- package/dist/src/storage/effect-schema.js +59 -0
- package/dist/src/storage/statements.d.ts +9 -0
- package/dist/src/storage/statements.js +8 -0
- package/dist/src/submission.d.ts +42 -0
- package/dist/src/submission.js +71 -0
- package/dist/src/turn-profile.d.ts +13 -0
- package/dist/src/turn-profile.js +100 -0
- package/dist/src/workflow-admission.d.ts +45 -0
- package/dist/src/workflow-admission.js +151 -0
- package/dist/src/workflow-contracts.d.ts +27 -0
- package/dist/src/workflow-contracts.js +88 -0
- package/dist/src/workflow-declaration.d.ts +11 -0
- package/dist/src/workflow-declaration.js +57 -0
- package/dist/src/workflow-resources.d.ts +8 -0
- package/dist/src/workflow-resources.js +14 -0
- package/dist/src/workflows.d.ts +5 -0
- package/dist/src/workflows.js +3 -0
- package/dist/tools/compile-workflows.d.ts +1 -0
- package/dist/tools/compile-workflows.js +33 -0
- package/dist/tools/self-host-processes.d.ts +10 -0
- package/dist/tools/self-host-processes.js +151 -0
- package/dist/tools/self-host-workflows.d.ts +15 -0
- package/dist/tools/self-host-workflows.js +78 -0
- package/dist/tools/self-host.d.ts +1 -0
- package/dist/tools/self-host.js +261 -0
- package/dist/tools/self-update-host.d.ts +6 -0
- package/dist/tools/self-update-host.js +41 -0
- package/dist/tools/self-update.d.ts +10 -0
- package/dist/tools/self-update.js +105 -0
- package/dist/tools/workflow-manifest.d.ts +3 -0
- package/dist/tools/workflow-manifest.js +34 -0
- package/dist/workflows/develop-prd.d.ts +7 -0
- package/dist/workflows/develop-prd.js +97 -0
- package/dist/workflows/develop-ticket.d.ts +15 -0
- package/dist/workflows/develop-ticket.js +301 -0
- package/dist/workflows/issue-labels.d.ts +14 -0
- package/dist/workflows/issue-labels.js +36 -0
- package/package.json +82 -75
- package/dist/abstract_gpt/index.js +0 -55
- package/dist/cloving_gpt/adapters/Adapter.js +0 -2
- package/dist/cloving_gpt/adapters/azureopenai.js +0 -69
- package/dist/cloving_gpt/adapters/claude.js +0 -128
- package/dist/cloving_gpt/adapters/gemini.js +0 -135
- package/dist/cloving_gpt/adapters/gpt4all.js +0 -29
- package/dist/cloving_gpt/adapters/index.js +0 -2
- package/dist/cloving_gpt/adapters/mistral.js +0 -128
- package/dist/cloving_gpt/adapters/ollama.js +0 -128
- package/dist/cloving_gpt/adapters/openai.js +0 -100
- package/dist/cloving_gpt/index.js +0 -192
- package/dist/commands/analyze.js +0 -47
- package/dist/commands/chat.js +0 -14
- package/dist/commands/check.js +0 -7
- package/dist/commands/commit.js +0 -44
- package/dist/commands/config.js +0 -167
- package/dist/commands/describe.js +0 -235
- package/dist/commands/generate/code.js +0 -21
- package/dist/commands/generate/commit.js +0 -11
- package/dist/commands/generate/context.js +0 -82
- package/dist/commands/generate/docs.js +0 -11
- package/dist/commands/generate/documentation.js +0 -11
- package/dist/commands/generate/fizzbuzz.js +0 -35
- package/dist/commands/generate/init.js +0 -15
- package/dist/commands/generate/review.js +0 -11
- package/dist/commands/generate/sh.js +0 -95
- package/dist/commands/generate/shell.js +0 -11
- package/dist/commands/generate/unit_tests.js +0 -11
- package/dist/commands/init.js +0 -13
- package/dist/commands/models.js +0 -22
- package/dist/commands/project/build.js +0 -88
- package/dist/commands/project/complete.js +0 -12
- package/dist/commands/project/init.js +0 -82
- package/dist/commands/project/plan.js +0 -108
- package/dist/commands/proxy.js +0 -11
- package/dist/commands/review.js +0 -50
- package/dist/commands/tokens.js +0 -75
- package/dist/commands/unit_tests.js +0 -150
- package/dist/commands/update.js +0 -7
- package/dist/file2.js +0 -4
- package/dist/index.js +0 -136
- package/dist/managers/BlockManager.js +0 -120
- package/dist/managers/ChatManager.js +0 -653
- package/dist/managers/ChunkManager.js +0 -32
- package/dist/managers/CodeManager.js +0 -185
- package/dist/managers/CommitManager.js +0 -78
- package/dist/managers/DocsManager.js +0 -88
- package/dist/managers/DocumentationManager.js +0 -114
- package/dist/managers/InitManager.js +0 -230
- package/dist/managers/ProxyManager.js +0 -210
- package/dist/managers/ReviewManager.js +0 -131
- package/dist/managers/ShellManager.js +0 -163
- package/dist/managers/StreamManager.js +0 -308
- package/dist/managers/UnitTestManager.js +0 -243
- package/dist/managers/src/managers/ProxyManager.js +0 -1
- package/dist/newfile.js +0 -2
- package/dist/package.json +0 -86
- package/dist/utils/command_utils.js +0 -384
- package/dist/utils/config_utils.js +0 -249
- package/dist/utils/gitUtils.js +0 -42
- package/dist/utils/git_utils.js +0 -217
- package/dist/utils/modelUtils.js +0 -7
- package/dist/utils/model_utils.js +0 -7
- package/dist/utils/prompt_utils.js +0 -333
- package/dist/utils/prompts/CODEGEN_COULDNT_APPLY.md +0 -5
- package/dist/utils/prompts/CODEGEN_EXAMPLES.md +0 -82
- package/dist/utils/prompts/CODEGEN_INSTRUCTIONS.md +0 -43
- package/dist/utils/prompts/DOCS_INSTRUCTIONS.md +0 -9
- package/dist/utils/prompts/INIT_INSTRUCTIONS.md +0 -132
- package/dist/utils/prompts/REVIEW_INSTRUCTIONS.md +0 -49
- package/dist/utils/prompts/SHELL_INSTRUCTIONS.md +0 -15
- package/dist/utils/prompts/SPECIAL_FILES.md +0 -66
- package/dist/utils/prompts/index.js +0 -27
- package/dist/utils/string_utils.js +0 -505
- package/dist/utils/types.js +0 -2
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
const executed = promisify(execFile);
|
|
4
|
+
const outputBytes = 16 * 1024 * 1024;
|
|
5
|
+
const scorePattern = /greptile_confidence_score:\s*(\d+)/;
|
|
6
|
+
const commitPattern = /Last reviewed commit:[^\n]*?\/commit\/([0-9a-f]{7,40})/;
|
|
7
|
+
export const reviewer = "greptile-apps[bot]";
|
|
8
|
+
export const reviewLimits = {
|
|
9
|
+
summaryCharacters: 4_000,
|
|
10
|
+
findingCharacters: 3_000,
|
|
11
|
+
findingsBytes: 12_000,
|
|
12
|
+
};
|
|
13
|
+
function privateEnvironment(environment) {
|
|
14
|
+
try {
|
|
15
|
+
const value = JSON.parse(environment["CLOVING_PRIVATE_TEXTS"] ?? "[]");
|
|
16
|
+
return list(value).filter((item) => typeof item === "string");
|
|
17
|
+
}
|
|
18
|
+
catch {
|
|
19
|
+
return [];
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
function failureDetail(error, place) {
|
|
23
|
+
const stderr = field(error, "stderr");
|
|
24
|
+
const text = typeof stderr === "string" ? stderr : "";
|
|
25
|
+
const secrets = Object.entries(place.environment)
|
|
26
|
+
.filter(([name]) => /TOKEN|SECRET|PASSWORD|KEY/i.test(name))
|
|
27
|
+
.map(([, value]) => value);
|
|
28
|
+
const hidden = [...secrets, ...place.privateTexts]
|
|
29
|
+
.filter((value) => typeof value === "string" && value !== "")
|
|
30
|
+
.sort((left, right) => right.length - left.length);
|
|
31
|
+
const detail = hidden.reduce((redacted, value) => redacted.replaceAll(value, "[hidden]"), text);
|
|
32
|
+
return {
|
|
33
|
+
detail: detail.slice(-2_000),
|
|
34
|
+
status: Number(/\(HTTP (\d{3})\)/.exec(text)?.[1]),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
async function output(command, place) {
|
|
38
|
+
try {
|
|
39
|
+
const { stdout } = await executed(String(command[0]), command.slice(1), {
|
|
40
|
+
cwd: place.directory,
|
|
41
|
+
env: place.environment,
|
|
42
|
+
signal: place.signal,
|
|
43
|
+
maxBuffer: outputBytes,
|
|
44
|
+
});
|
|
45
|
+
return stdout;
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
const failure = new Error(place.reason, { cause: error });
|
|
49
|
+
if (place.reason === "check-failed")
|
|
50
|
+
throw failure;
|
|
51
|
+
throw Object.assign(failure, failureDetail(error, place));
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
export function calls(settings, signal) {
|
|
55
|
+
const environment = { ...process.env, ...settings.environment };
|
|
56
|
+
const privateTexts = [
|
|
57
|
+
...(settings.privateTexts ?? []),
|
|
58
|
+
...privateEnvironment(environment),
|
|
59
|
+
];
|
|
60
|
+
const place = (directory, reason) => ({
|
|
61
|
+
directory,
|
|
62
|
+
signal,
|
|
63
|
+
environment,
|
|
64
|
+
reason,
|
|
65
|
+
privateTexts,
|
|
66
|
+
});
|
|
67
|
+
return {
|
|
68
|
+
gh: (parts) => output([...settings.gh, ...parts], place(settings.repository, "github-call-failed")),
|
|
69
|
+
git: (directory, parts) => output(["git", ...parts], place(directory, "git-call-failed")),
|
|
70
|
+
run: (command, directory) => output(command, place(directory, "check-failed")),
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
function field(value, name) {
|
|
74
|
+
return Reflect.get(Object(value), name);
|
|
75
|
+
}
|
|
76
|
+
function list(value) {
|
|
77
|
+
return Array.isArray(value) ? value.map((item) => item) : [];
|
|
78
|
+
}
|
|
79
|
+
function byReviewer(comment) {
|
|
80
|
+
return field(field(comment, "user"), "login") === reviewer;
|
|
81
|
+
}
|
|
82
|
+
function scored(body, commit) {
|
|
83
|
+
const score = scorePattern.exec(body)?.[1];
|
|
84
|
+
const reviewed = commitPattern.exec(body)?.[1];
|
|
85
|
+
if (score === undefined || reviewed === undefined)
|
|
86
|
+
return undefined;
|
|
87
|
+
if (!commit.startsWith(reviewed))
|
|
88
|
+
return undefined;
|
|
89
|
+
const summary = body
|
|
90
|
+
.replace(/<!--[\s\S]*?-->/g, "")
|
|
91
|
+
.trim()
|
|
92
|
+
.slice(0, reviewLimits.summaryCharacters);
|
|
93
|
+
return { score: Number(score), summary };
|
|
94
|
+
}
|
|
95
|
+
export function scoreOf(comments, commit) {
|
|
96
|
+
return list(comments)
|
|
97
|
+
.filter(byReviewer)
|
|
98
|
+
.map((comment) => scored(String(field(comment, "body")), commit))
|
|
99
|
+
.findLast((item) => item !== undefined);
|
|
100
|
+
}
|
|
101
|
+
function findingOf(comment) {
|
|
102
|
+
const line = field(comment, "line") ?? field(comment, "original_line");
|
|
103
|
+
return {
|
|
104
|
+
path: String(field(comment, "path")),
|
|
105
|
+
line: typeof line === "number" ? line : null,
|
|
106
|
+
body: String(field(comment, "body")).slice(0, reviewLimits.findingCharacters),
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function reviewed(comment, commit) {
|
|
110
|
+
return (byReviewer(comment) &&
|
|
111
|
+
field(comment, "original_commit_id") === commit &&
|
|
112
|
+
typeof field(comment, "in_reply_to_id") !== "number");
|
|
113
|
+
}
|
|
114
|
+
export function findingsOf(comments, commit) {
|
|
115
|
+
const kept = [];
|
|
116
|
+
let bytes = 0;
|
|
117
|
+
for (const comment of list(comments)) {
|
|
118
|
+
if (!reviewed(comment, commit))
|
|
119
|
+
continue;
|
|
120
|
+
const finding = findingOf(comment);
|
|
121
|
+
bytes += Buffer.byteLength(JSON.stringify(finding));
|
|
122
|
+
if (bytes > reviewLimits.findingsBytes)
|
|
123
|
+
break;
|
|
124
|
+
kept.push(finding);
|
|
125
|
+
}
|
|
126
|
+
return kept;
|
|
127
|
+
}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { lstat, readFile } from "node:fs/promises";
|
|
3
|
+
import { basename, join } from "node:path";
|
|
4
|
+
import { existingTree, removeWorktree, repositoryPath, text, } from "./github-operation.js";
|
|
5
|
+
import { writeRecord } from "./operation-journal.js";
|
|
6
|
+
import { treePlace } from "./work-tree.js";
|
|
7
|
+
import { issuePrivacy, operatorPrivateTexts } from "./github-issue-privacy.js";
|
|
8
|
+
function issueFromUrl(url) {
|
|
9
|
+
const number = Number(/^https?:\/\/[^/\s]+\/[\w.-]+\/[\w.-]+\/issues\/([1-9]\d*)$/.exec(url)?.[1]);
|
|
10
|
+
if (!Number.isSafeInteger(number) || number < 1)
|
|
11
|
+
throw new Error("github-call-failed");
|
|
12
|
+
return { number, url };
|
|
13
|
+
}
|
|
14
|
+
function issueOf(issue) {
|
|
15
|
+
if (typeof issue !== "object" ||
|
|
16
|
+
issue === null ||
|
|
17
|
+
!("number" in issue) ||
|
|
18
|
+
typeof issue.number !== "number" ||
|
|
19
|
+
!("html_url" in issue) ||
|
|
20
|
+
typeof issue.html_url !== "string")
|
|
21
|
+
throw new Error("github-call-failed");
|
|
22
|
+
const parsed = issueFromUrl(issue.html_url);
|
|
23
|
+
if (issue.number !== parsed.number)
|
|
24
|
+
throw new Error("github-call-failed");
|
|
25
|
+
return parsed;
|
|
26
|
+
}
|
|
27
|
+
function issuePage(line) {
|
|
28
|
+
const page = JSON.parse(line);
|
|
29
|
+
if (!Array.isArray(page))
|
|
30
|
+
throw new Error("github-call-failed");
|
|
31
|
+
return page.map((issue) => issueOf(issue));
|
|
32
|
+
}
|
|
33
|
+
function repositoryName(reply) {
|
|
34
|
+
const repository = JSON.parse(reply);
|
|
35
|
+
if (typeof repository !== "object" ||
|
|
36
|
+
repository === null ||
|
|
37
|
+
!("nameWithOwner" in repository) ||
|
|
38
|
+
typeof repository.nameWithOwner !== "string" ||
|
|
39
|
+
!/^[\w.-]+\/[\w.-]+$/.test(repository.nameWithOwner))
|
|
40
|
+
throw new Error("github-call-failed");
|
|
41
|
+
return repository.nameWithOwner;
|
|
42
|
+
}
|
|
43
|
+
async function draftOf(operation) {
|
|
44
|
+
const name = text(operation, "draft");
|
|
45
|
+
if (basename(name) !== name || name.includes("\\"))
|
|
46
|
+
throw new Error("invalid-draft");
|
|
47
|
+
const path = join(existingTree(operation).path, name);
|
|
48
|
+
const stat = await lstat(path).catch(() => undefined);
|
|
49
|
+
if (stat === undefined || !stat.isFile())
|
|
50
|
+
throw new Error("draft-not-available");
|
|
51
|
+
return readFile(path, "utf8");
|
|
52
|
+
}
|
|
53
|
+
async function knownIssue(operation, marker) {
|
|
54
|
+
const output = await operation.calls.gh([
|
|
55
|
+
"api",
|
|
56
|
+
"--paginate",
|
|
57
|
+
`${repositoryPath}/issues?state=all&per_page=100`,
|
|
58
|
+
"--jq",
|
|
59
|
+
`[.[] | select((.body // "") | contains(${JSON.stringify(marker)})) | {number, html_url}] | @json`,
|
|
60
|
+
]);
|
|
61
|
+
return output.trim().split("\n").flatMap(issuePage)[0];
|
|
62
|
+
}
|
|
63
|
+
export async function createIssue(operation) {
|
|
64
|
+
operatorPrivateTexts(operation.settings);
|
|
65
|
+
const draft = await draftOf(operation);
|
|
66
|
+
const [heading = "", ...lines] = draft.split("\n");
|
|
67
|
+
if (!heading.startsWith("# ") || heading.slice(2).trim() === "")
|
|
68
|
+
throw new Error("invalid-draft");
|
|
69
|
+
const repository = repositoryName(await operation.calls.gh(["repo", "view", "--json", "nameWithOwner"]));
|
|
70
|
+
issuePrivacy(draft, {
|
|
71
|
+
settings: operation.settings,
|
|
72
|
+
repository,
|
|
73
|
+
});
|
|
74
|
+
const marker = `<!-- cloving-prd:${operation.target} -->`;
|
|
75
|
+
const known = await knownIssue(operation, marker);
|
|
76
|
+
if (known !== undefined)
|
|
77
|
+
return known;
|
|
78
|
+
if (existsSync(join(operation.folder, "post.json")))
|
|
79
|
+
throw new Error("post-uncertain");
|
|
80
|
+
await writeRecord(operation.folder, { name: "post.json", value: { marker } });
|
|
81
|
+
const printed = await operation.calls.gh([
|
|
82
|
+
"issue",
|
|
83
|
+
"create",
|
|
84
|
+
"--title",
|
|
85
|
+
heading.slice(2).trim(),
|
|
86
|
+
"--body",
|
|
87
|
+
`${lines.join("\n")}\n${marker}`,
|
|
88
|
+
]);
|
|
89
|
+
const url = printed.trim().split("\n").at(-1) ?? "";
|
|
90
|
+
return issueFromUrl(url);
|
|
91
|
+
}
|
|
92
|
+
export async function discard(operation) {
|
|
93
|
+
const place = treePlace({
|
|
94
|
+
worktrees: operation.settings.worktrees,
|
|
95
|
+
target: operation.target,
|
|
96
|
+
});
|
|
97
|
+
await removeWorktree(operation, place);
|
|
98
|
+
return { discarded: place.branch };
|
|
99
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { MethodSettings } from "./github-operation.ts";
|
|
2
|
+
export declare function issuePrivacy(text: string, options: {
|
|
3
|
+
readonly settings: MethodSettings;
|
|
4
|
+
readonly repository: string;
|
|
5
|
+
}): void;
|
|
6
|
+
export declare function operatorPrivateTexts(settings: MethodSettings): readonly string[];
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { homedir } from "node:os";
|
|
2
|
+
import { decodeHTMLStrict } from "entities/decode";
|
|
3
|
+
function entity(value) {
|
|
4
|
+
const encoded = `&${value};`;
|
|
5
|
+
const decoded = decodeHTMLStrict(encoded);
|
|
6
|
+
if (decoded === encoded)
|
|
7
|
+
throw new Error("private-path-in-change");
|
|
8
|
+
return decoded.replace(/\u00a0/g, " ");
|
|
9
|
+
}
|
|
10
|
+
function decoded(text) {
|
|
11
|
+
return text
|
|
12
|
+
.replace(/&(#x[\da-f]+|#\d+|[a-z][a-z\d]+);/gi, (_match, value) => entity(value))
|
|
13
|
+
.replace(/(?:%[\da-f]{2})+/gi, (value) => {
|
|
14
|
+
try {
|
|
15
|
+
return decodeURIComponent(value);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return value.replace(/%([\da-f]{2})/gi, (_match, code) => String.fromCharCode(Number.parseInt(code, 16)));
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
function linkEnd(text, opening) {
|
|
23
|
+
const closing = opening.mark === "[" ? "]" : ")";
|
|
24
|
+
let depth = 0;
|
|
25
|
+
for (let index = opening.index; index < text.length; index += 1) {
|
|
26
|
+
const character = text[index];
|
|
27
|
+
if (character === opening.mark)
|
|
28
|
+
depth += 1;
|
|
29
|
+
if (character === closing)
|
|
30
|
+
depth -= 1;
|
|
31
|
+
if (depth === 0)
|
|
32
|
+
return index;
|
|
33
|
+
}
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
function ambiguousDestination(text) {
|
|
37
|
+
return /["'<]/.test(text.replace(/"[^"]*"|'[^']*'|<[^>]*>/g, ""));
|
|
38
|
+
}
|
|
39
|
+
function visibleLinks(text) {
|
|
40
|
+
let result = "";
|
|
41
|
+
let cursor = 0;
|
|
42
|
+
let position = 0;
|
|
43
|
+
for (;;) {
|
|
44
|
+
const start = text.indexOf("[", position);
|
|
45
|
+
if (start === -1)
|
|
46
|
+
break;
|
|
47
|
+
const labelEnd = linkEnd(text, { index: start, mark: "[" });
|
|
48
|
+
if (labelEnd === undefined) {
|
|
49
|
+
position = start + 1;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const mark = text[labelEnd + 1];
|
|
53
|
+
if (mark !== "(" && mark !== "[") {
|
|
54
|
+
position = start + 1;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const end = linkEnd(text, { index: labelEnd + 1, mark });
|
|
58
|
+
if (end === undefined)
|
|
59
|
+
throw new Error("private-path-in-change");
|
|
60
|
+
if (mark === "(" && ambiguousDestination(text.slice(labelEnd + 2, end)))
|
|
61
|
+
throw new Error("private-path-in-change");
|
|
62
|
+
result += text.slice(cursor, start) + text.slice(start + 1, labelEnd);
|
|
63
|
+
cursor = end + 1;
|
|
64
|
+
position = cursor;
|
|
65
|
+
}
|
|
66
|
+
return result + text.slice(cursor);
|
|
67
|
+
}
|
|
68
|
+
function visible(text) {
|
|
69
|
+
return visibleLinks(text)
|
|
70
|
+
.replace(/<[^>]*>/g, "")
|
|
71
|
+
.replace(/[*`~[\]]/g, "");
|
|
72
|
+
}
|
|
73
|
+
function paths(text) {
|
|
74
|
+
const withoutUrls = text.replace(/https?:\/\/[^\s<>"')]+/gi, (url) => {
|
|
75
|
+
const query = url.search(/[?#]/);
|
|
76
|
+
return query === -1 ? "" : ` ${url.slice(query + 1)}`;
|
|
77
|
+
});
|
|
78
|
+
return [
|
|
79
|
+
/~\//,
|
|
80
|
+
/\.\.\//,
|
|
81
|
+
/[a-z]:[\\/]/i,
|
|
82
|
+
/\\\\[^\s\\]+\\[^\s\\]+/,
|
|
83
|
+
/(?:^|[^\p{L}\p{N}_./\\-])\/{1,2}[^/\s<>"'`]+\/[^\s<>"'`]+/u,
|
|
84
|
+
].some((pattern) => pattern.test(withoutUrls));
|
|
85
|
+
}
|
|
86
|
+
function unsafeLinks(text) {
|
|
87
|
+
const links = text.matchAll(/(?:\]\(\s*<?|<|^\s{0,3}\[[^\]]+\]:\s*<?|\b(?:href|src)\s*=\s*["']?\s*)([a-z][\w+.-]*):|\b([a-z][\w+.-]*):\/\//gim);
|
|
88
|
+
return [...links].some((match) => !["http", "https"].includes(String(match[1] ?? match[2]).toLowerCase()));
|
|
89
|
+
}
|
|
90
|
+
function mentions(text) {
|
|
91
|
+
return [...text.matchAll(/(?:^|[^\w@])@([a-z\d][a-z\d-]*)(\/)?/gi)].some((match) => match[2] !== "/");
|
|
92
|
+
}
|
|
93
|
+
function foreignIssues(text, repository) {
|
|
94
|
+
const references = [
|
|
95
|
+
...text.matchAll(/\b([\w.-]+\/[\w.-]+)#\d+/g),
|
|
96
|
+
...text.matchAll(/https?:\/\/[^/\s]+\/([\w.-]+\/[\w.-]+)\/(?:issues|pull)\/\d+/gi),
|
|
97
|
+
];
|
|
98
|
+
return references.some((match) => match[1]?.toLowerCase() !== repository.toLowerCase());
|
|
99
|
+
}
|
|
100
|
+
function privateText(text, options) {
|
|
101
|
+
const lowered = text.toLowerCase();
|
|
102
|
+
return (options.texts.some((item) => lowered.includes(item.toLowerCase())) ||
|
|
103
|
+
/gh[pousr]_|github_pat_|sk-ant-|-----BEGIN/i.test(text) ||
|
|
104
|
+
/[\w.!#$%&'*+/=?^`{|}~-]+@[\w.-]+\.[a-z]{2,}/i.test(text) ||
|
|
105
|
+
mentions(text) ||
|
|
106
|
+
paths(text) ||
|
|
107
|
+
unsafeLinks(text) ||
|
|
108
|
+
foreignIssues(text, options.repository));
|
|
109
|
+
}
|
|
110
|
+
export function issuePrivacy(text, options) {
|
|
111
|
+
const { settings, repository } = options;
|
|
112
|
+
const operatorTexts = operatorPrivateTexts(settings);
|
|
113
|
+
const texts = [
|
|
114
|
+
homedir(),
|
|
115
|
+
settings.repository,
|
|
116
|
+
settings.worktrees,
|
|
117
|
+
...operatorTexts,
|
|
118
|
+
];
|
|
119
|
+
const plain = decoded(text);
|
|
120
|
+
const unescaped = plain.replace(/\\([^\p{L}\p{N}\s])/gu, "$1");
|
|
121
|
+
const rendered = visible(unescaped);
|
|
122
|
+
const forms = [text, plain, unescaped, rendered, rendered.replace(/_/g, "")];
|
|
123
|
+
if (forms.some((form) => privateText(form, { texts, repository })))
|
|
124
|
+
throw new Error("private-path-in-change");
|
|
125
|
+
}
|
|
126
|
+
export function operatorPrivateTexts(settings) {
|
|
127
|
+
const texts = settings.privateTexts?.filter((item) => item.trim() !== "") ?? [];
|
|
128
|
+
if (texts.length === 0)
|
|
129
|
+
throw new Error("private-texts-not-set");
|
|
130
|
+
return texts;
|
|
131
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { type Operation } from "./github-operation.ts";
|
|
2
|
+
interface ReviewedPull {
|
|
3
|
+
readonly number: number;
|
|
4
|
+
readonly commit: string;
|
|
5
|
+
}
|
|
6
|
+
interface SuccessfulMerge {
|
|
7
|
+
readonly number: number;
|
|
8
|
+
readonly commit: string;
|
|
9
|
+
readonly updated: string;
|
|
10
|
+
readonly merged: string;
|
|
11
|
+
}
|
|
12
|
+
interface MergeRepair {
|
|
13
|
+
readonly reason: "check-failed" | "merge-conflict";
|
|
14
|
+
readonly output: string;
|
|
15
|
+
}
|
|
16
|
+
export type MergeResult = SuccessfulMerge | MergeRepair;
|
|
17
|
+
export declare function merge(operation: Operation, pull: ReviewedPull): Promise<MergeResult>;
|
|
18
|
+
export {};
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { setTimeout as delay } from "node:timers/promises";
|
|
3
|
+
import { readRecord, writeRecord } from "./operation-journal.js";
|
|
4
|
+
import { changeChecked, defaultBranch, existingTree, field, githubTiming, removeWorktree, repositoryPath, } from "./github-operation.js";
|
|
5
|
+
import { treePlace } from "./work-tree.js";
|
|
6
|
+
function commitOf(value, name) {
|
|
7
|
+
if (typeof value !== "object" || value === null)
|
|
8
|
+
throw new Error("github-call-failed");
|
|
9
|
+
const commit = Reflect.get(value, name);
|
|
10
|
+
if (typeof commit !== "string")
|
|
11
|
+
throw new Error("github-call-failed");
|
|
12
|
+
return commit;
|
|
13
|
+
}
|
|
14
|
+
async function knownMerge(operation, expected) {
|
|
15
|
+
const pull = JSON.parse(await operation.calls.gh([
|
|
16
|
+
"api",
|
|
17
|
+
`${repositoryPath}/pulls/${String(expected.number)}`,
|
|
18
|
+
]));
|
|
19
|
+
const head = commitOf(field(pull, "head"), "sha");
|
|
20
|
+
if (field(pull, "merged") !== true)
|
|
21
|
+
return { head, merged: undefined };
|
|
22
|
+
if (head !== expected.commit && head !== expected.updated)
|
|
23
|
+
throw new Error("merged-other-commit");
|
|
24
|
+
return { head, merged: commitOf(pull, "merge_commit_sha") };
|
|
25
|
+
}
|
|
26
|
+
async function abortMerge(operation, tree) {
|
|
27
|
+
const path = (await operation.calls.git(tree.path, [
|
|
28
|
+
"rev-parse",
|
|
29
|
+
"--git-path",
|
|
30
|
+
"MERGE_HEAD",
|
|
31
|
+
])).trim();
|
|
32
|
+
if (existsSync(path))
|
|
33
|
+
await operation.calls.git(tree.path, ["merge", "--abort"]);
|
|
34
|
+
}
|
|
35
|
+
async function restored(operation, place) {
|
|
36
|
+
await abortMerge(operation, place.tree);
|
|
37
|
+
await clean(operation, place.tree);
|
|
38
|
+
if ((await headOf(operation, place.tree)) === place.commit)
|
|
39
|
+
return;
|
|
40
|
+
await operation.calls.git(place.tree.path, ["reset", "--hard", place.commit]);
|
|
41
|
+
}
|
|
42
|
+
async function clean(operation, tree) {
|
|
43
|
+
const status = await operation.calls.git(tree.path, [
|
|
44
|
+
"status",
|
|
45
|
+
"--porcelain",
|
|
46
|
+
"--untracked-files=no",
|
|
47
|
+
]);
|
|
48
|
+
if (status.trim() !== "")
|
|
49
|
+
throw new Error("uncommitted-change");
|
|
50
|
+
}
|
|
51
|
+
async function headOf(operation, tree) {
|
|
52
|
+
return (await operation.calls.git(tree.path, ["rev-parse", "HEAD"])).trim();
|
|
53
|
+
}
|
|
54
|
+
async function fetched(operation, base) {
|
|
55
|
+
const { calls, settings } = operation;
|
|
56
|
+
await calls.git(settings.repository, ["fetch", "--quiet", "origin"]);
|
|
57
|
+
return (await calls.git(settings.repository, ["rev-parse", `origin/${base}`])).trim();
|
|
58
|
+
}
|
|
59
|
+
async function updatedTree(operation, place) {
|
|
60
|
+
const { calls } = operation;
|
|
61
|
+
const ancestor = (await calls.git(place.tree.path, ["merge-base", "HEAD", place.base])).trim();
|
|
62
|
+
if (ancestor === place.base)
|
|
63
|
+
return;
|
|
64
|
+
try {
|
|
65
|
+
await calls.git(place.tree.path, [
|
|
66
|
+
"merge",
|
|
67
|
+
"--no-ff",
|
|
68
|
+
"--no-edit",
|
|
69
|
+
place.base,
|
|
70
|
+
]);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
const conflicts = await calls.git(place.tree.path, [
|
|
74
|
+
"diff",
|
|
75
|
+
"--name-only",
|
|
76
|
+
"--diff-filter=U",
|
|
77
|
+
]);
|
|
78
|
+
await calls.git(place.tree.path, ["merge", "--abort"]);
|
|
79
|
+
throw new Error("merge-conflict", { cause: conflicts.trim() });
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
async function checked(operation, place) {
|
|
83
|
+
await changeChecked(operation, place);
|
|
84
|
+
const head = await headOf(operation, place.tree);
|
|
85
|
+
if (operation.settings.check !== undefined)
|
|
86
|
+
await operation.calls.run(operation.settings.check, place.tree.path);
|
|
87
|
+
await clean(operation, place.tree);
|
|
88
|
+
if ((await headOf(operation, place.tree)) !== head)
|
|
89
|
+
throw new Error("uncommitted-change");
|
|
90
|
+
if (head !== place.commit && operation.settings.check === undefined)
|
|
91
|
+
throw new Error("check-required");
|
|
92
|
+
return head;
|
|
93
|
+
}
|
|
94
|
+
async function refreshed(operation, place) {
|
|
95
|
+
await restored(operation, {
|
|
96
|
+
tree: place.tree,
|
|
97
|
+
commit: place.recorded ?? place.commit,
|
|
98
|
+
});
|
|
99
|
+
const base = await defaultBranch(operation);
|
|
100
|
+
let newest = await fetched(operation, base);
|
|
101
|
+
if (place.recorded !== undefined &&
|
|
102
|
+
(await operation.calls.git(place.tree.path, [
|
|
103
|
+
"merge-base",
|
|
104
|
+
place.recorded,
|
|
105
|
+
newest,
|
|
106
|
+
])).trim() === newest)
|
|
107
|
+
return place.recorded;
|
|
108
|
+
for (let attempt = 0; attempt < 3; attempt += 1) {
|
|
109
|
+
await updatedTree(operation, { tree: place.tree, base: newest });
|
|
110
|
+
const head = await checked(operation, { ...place, base });
|
|
111
|
+
const latest = await fetched(operation, base);
|
|
112
|
+
if (latest === newest)
|
|
113
|
+
return head;
|
|
114
|
+
newest = latest;
|
|
115
|
+
}
|
|
116
|
+
throw new Error("base-moved");
|
|
117
|
+
}
|
|
118
|
+
async function mergedNow(operation, pull) {
|
|
119
|
+
const reply = JSON.parse(await operation.calls.gh([
|
|
120
|
+
"api",
|
|
121
|
+
"-X",
|
|
122
|
+
"PUT",
|
|
123
|
+
`${repositoryPath}/pulls/${String(pull.number)}/merge`,
|
|
124
|
+
"-f",
|
|
125
|
+
"merge_method=merge",
|
|
126
|
+
"-f",
|
|
127
|
+
`sha=${pull.commit}`,
|
|
128
|
+
]));
|
|
129
|
+
return commitOf(reply, "sha");
|
|
130
|
+
}
|
|
131
|
+
async function waitForHead(operation, pull) {
|
|
132
|
+
const timing = operation.settings.timing ?? githubTiming;
|
|
133
|
+
for (let attempt = 0; attempt < 30; attempt += 1) {
|
|
134
|
+
if (attempt > 0)
|
|
135
|
+
await delay(timing.pollMilliseconds, undefined, {
|
|
136
|
+
signal: operation.signal,
|
|
137
|
+
});
|
|
138
|
+
const current = JSON.parse(await operation.calls.gh([
|
|
139
|
+
"api",
|
|
140
|
+
`${repositoryPath}/pulls/${String(pull.number)}`,
|
|
141
|
+
]));
|
|
142
|
+
if (commitOf(field(current, "head"), "sha") === pull.commit)
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
throw new Error("head-not-updated");
|
|
146
|
+
}
|
|
147
|
+
async function mergeUpdated(operation, pull) {
|
|
148
|
+
const timing = operation.settings.timing ?? githubTiming;
|
|
149
|
+
for (let attempt = 0;; attempt += 1) {
|
|
150
|
+
await waitForHead(operation, pull);
|
|
151
|
+
try {
|
|
152
|
+
return await mergedNow(operation, pull);
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
const status = field(error, "status");
|
|
156
|
+
if (attempt === 2 || (status !== 405 && status !== 409))
|
|
157
|
+
throw error;
|
|
158
|
+
await delay(timing.pollMilliseconds, undefined, {
|
|
159
|
+
signal: operation.signal,
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
async function removed(operation, place) {
|
|
165
|
+
const { settings, calls } = operation;
|
|
166
|
+
await calls
|
|
167
|
+
.gh([
|
|
168
|
+
"api",
|
|
169
|
+
"-X",
|
|
170
|
+
"DELETE",
|
|
171
|
+
`${repositoryPath}/git/refs/heads/${place.branch}`,
|
|
172
|
+
])
|
|
173
|
+
.catch(() => undefined);
|
|
174
|
+
await removeWorktree(operation, place);
|
|
175
|
+
await calls.git(settings.repository, [
|
|
176
|
+
"update-ref",
|
|
177
|
+
"-d",
|
|
178
|
+
`refs/remotes/origin/${place.branch}`,
|
|
179
|
+
]);
|
|
180
|
+
}
|
|
181
|
+
async function recordedHead(operation, commit) {
|
|
182
|
+
const record = await readRecord(operation.folder, "updated-head.json");
|
|
183
|
+
if (record === undefined)
|
|
184
|
+
return undefined;
|
|
185
|
+
const updated = field(record, "updated");
|
|
186
|
+
if (field(record, "commit") !== commit ||
|
|
187
|
+
typeof updated !== "string" ||
|
|
188
|
+
!/^[0-9a-f]{40,64}$/.test(updated))
|
|
189
|
+
throw new Error("git-call-failed");
|
|
190
|
+
return updated;
|
|
191
|
+
}
|
|
192
|
+
async function readyHead(operation, pull) {
|
|
193
|
+
const tree = existingTree(operation);
|
|
194
|
+
const updated = await refreshed(operation, {
|
|
195
|
+
tree,
|
|
196
|
+
commit: pull.commit,
|
|
197
|
+
recorded: pull.recorded,
|
|
198
|
+
});
|
|
199
|
+
if (updated === pull.commit)
|
|
200
|
+
return updated;
|
|
201
|
+
if (pull.recorded !== updated)
|
|
202
|
+
await writeRecord(operation.folder, {
|
|
203
|
+
name: "updated-head.json",
|
|
204
|
+
value: { commit: pull.commit, updated },
|
|
205
|
+
});
|
|
206
|
+
if (pull.remote !== updated)
|
|
207
|
+
await operation.calls.git(tree.path, [
|
|
208
|
+
"push",
|
|
209
|
+
"--quiet",
|
|
210
|
+
"origin",
|
|
211
|
+
`${updated}:refs/heads/${tree.branch}`,
|
|
212
|
+
]);
|
|
213
|
+
return updated;
|
|
214
|
+
}
|
|
215
|
+
function checkOutput(cause) {
|
|
216
|
+
return ["stdout", "stderr"]
|
|
217
|
+
.map((name) => {
|
|
218
|
+
const value = field(cause, name);
|
|
219
|
+
return typeof value === "string" ? value : "";
|
|
220
|
+
})
|
|
221
|
+
.join("")
|
|
222
|
+
.slice(-6_000);
|
|
223
|
+
}
|
|
224
|
+
export async function merge(operation, pull) {
|
|
225
|
+
try {
|
|
226
|
+
return await completedMerge(operation, pull);
|
|
227
|
+
}
|
|
228
|
+
catch (error) {
|
|
229
|
+
operation.signal.throwIfAborted();
|
|
230
|
+
if (!(error instanceof Error))
|
|
231
|
+
throw error;
|
|
232
|
+
const reason = error.message;
|
|
233
|
+
if (reason !== "check-failed" && reason !== "merge-conflict")
|
|
234
|
+
throw error;
|
|
235
|
+
const conflicts = typeof error.cause === "string" ? error.cause : "";
|
|
236
|
+
return {
|
|
237
|
+
reason,
|
|
238
|
+
output: reason === "check-failed" ? checkOutput(error.cause) : conflicts,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
async function completedMerge(operation, pull) {
|
|
243
|
+
const place = treePlace({
|
|
244
|
+
worktrees: operation.settings.worktrees,
|
|
245
|
+
target: operation.target,
|
|
246
|
+
});
|
|
247
|
+
const recorded = await recordedHead(operation, pull.commit);
|
|
248
|
+
const known = await knownMerge(operation, {
|
|
249
|
+
...pull,
|
|
250
|
+
updated: recorded ?? pull.commit,
|
|
251
|
+
});
|
|
252
|
+
const updated = known.merged === undefined
|
|
253
|
+
? await readyHead(operation, { ...pull, recorded, remote: known.head })
|
|
254
|
+
: (recorded ?? pull.commit);
|
|
255
|
+
const mergeCall = updated === pull.commit ? mergedNow : mergeUpdated;
|
|
256
|
+
const merged = known.merged ?? (await mergeCall(operation, { ...pull, commit: updated }));
|
|
257
|
+
await removed(operation, place);
|
|
258
|
+
return { number: pull.number, commit: pull.commit, updated, merged };
|
|
259
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type Operation } from "./github-operation.ts";
|
|
2
|
+
export type { GithubTiming, MethodSettings } from "./github-operation.ts";
|
|
3
|
+
export declare const methodReasons: ReadonlySet<string>;
|
|
4
|
+
export type Method = (operation: Operation) => Promise<unknown>;
|
|
5
|
+
export declare const methods: ReadonlyMap<string, Method>;
|