cloving 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +329 -215
- package/dist/src/agent-harness-shell.d.ts +2 -1
- package/dist/src/agent-harness-shell.js +8 -5
- package/dist/src/authority/command-wait-checks.d.ts +8 -0
- package/dist/src/authority/command-wait-checks.js +88 -0
- package/dist/src/authority/command-wait-results.d.ts +15 -0
- package/dist/src/authority/command-wait-results.js +73 -0
- package/dist/src/authority/command-wait-view.d.ts +21 -0
- package/dist/src/authority/command-wait-view.js +34 -0
- package/dist/src/authority/command-waits.d.ts +39 -0
- package/dist/src/authority/command-waits.js +97 -0
- package/dist/src/authority/commands.js +22 -1
- package/dist/src/authority/dispatch-decision.d.ts +8 -0
- package/dist/src/authority/dispatch-decision.js +26 -1
- package/dist/src/authority/effect-requests.js +6 -3
- package/dist/src/authority/effect-results.js +4 -2
- package/dist/src/authority/history-state.d.ts +2 -0
- package/dist/src/authority/history-state.js +13 -1
- package/dist/src/authority/instants.d.ts +1 -0
- package/dist/src/authority/instants.js +21 -0
- package/dist/src/authority/reduction-state.d.ts +2 -0
- package/dist/src/authority/reduction-state.js +5 -0
- package/dist/src/authority/reduction.js +24 -0
- package/dist/src/authority/status-input.d.ts +2 -0
- package/dist/src/authority/status.d.ts +2 -0
- package/dist/src/authority/status.js +1 -0
- package/dist/src/authority/stop-sequence.d.ts +1 -0
- package/dist/src/authority/stop-sequence.js +2 -1
- package/dist/src/authority/transitions.d.ts +6 -4
- package/dist/src/authority/transitions.js +7 -0
- package/dist/src/broker/actor/authority-health.d.ts +9 -0
- package/dist/src/broker/actor/authority-health.js +24 -0
- package/dist/src/broker/actor/authority-queries.d.ts +2 -1
- package/dist/src/broker/actor/authority-queries.js +14 -5
- package/dist/src/broker/actor/authority-receipts.js +1 -1
- package/dist/src/broker/actor/authority-runtime.d.ts +4 -2
- package/dist/src/broker/actor/authority-runtime.js +29 -20
- package/dist/src/broker/actor/authority-session.d.ts +6 -19
- package/dist/src/broker/actor/authority-session.js +66 -88
- package/dist/src/broker/actor/authority-settings.d.ts +2 -1
- package/dist/src/broker/actor/authority-settings.js +6 -3
- package/dist/src/broker/actor/authority-upgrades.d.ts +23 -2
- package/dist/src/broker/actor/authority-upgrades.js +8 -2
- package/dist/src/broker/actor/authority-watchdog.d.ts +6 -2
- package/dist/src/broker/actor/authority-watchdog.js +31 -9
- package/dist/src/broker/actor/authority.js +3 -1
- package/dist/src/broker/actor/delivery-intents.js +2 -0
- package/dist/src/broker/actor/effect-delivery.d.ts +1 -1
- package/dist/src/broker/actor/effect-delivery.js +15 -2
- package/dist/src/broker/actor/effect-plan.js +11 -2
- package/dist/src/broker/actor/effect-queries.d.ts +4 -0
- package/dist/src/broker/actor/effect-queries.js +9 -1
- package/dist/src/broker/actor/effect-turn.js +2 -0
- package/dist/src/broker/actor/projection-memory.d.ts +43 -0
- package/dist/src/broker/actor/projection-memory.js +207 -0
- package/dist/src/broker/actor/runtime-parts.d.ts +5 -0
- package/dist/src/broker/actor/runtime-parts.js +8 -3
- package/dist/src/broker/actor/stop-plan.js +9 -3
- package/dist/src/broker/actor/stop-turn.d.ts +2 -0
- package/dist/src/broker/actor/stop-turn.js +24 -11
- package/dist/src/broker/actor/turn-draft.d.ts +1 -0
- package/dist/src/broker/actor/turn-draft.js +4 -0
- package/dist/src/broker/actor/turn-state.js +5 -1
- package/dist/src/broker/authority-admission.js +60 -0
- package/dist/src/broker/authority-restore.d.ts +2 -0
- package/dist/src/broker/authority-restore.js +35 -1
- package/dist/src/broker/command-wait-restore.d.ts +31 -0
- package/dist/src/broker/command-wait-restore.js +86 -0
- package/dist/src/broker/decision-restore.d.ts +1 -1
- package/dist/src/broker/decision-restore.js +1 -0
- package/dist/src/broker/effect-upgrade.d.ts +3 -0
- package/dist/src/broker/effect-upgrade.js +11 -2
- package/dist/src/cli/arguments.d.ts +13 -0
- package/dist/src/cli/arguments.js +43 -3
- package/dist/src/cli/chat-stores.d.ts +2 -0
- package/dist/src/cli/chat-stores.js +113 -0
- package/dist/src/cli/client.d.ts +7 -2
- package/dist/src/cli/client.js +13 -7
- package/dist/src/cli/command-requests.d.ts +46 -0
- package/dist/src/cli/command-requests.js +84 -0
- package/dist/src/cli/command-waits.d.ts +9 -0
- package/dist/src/cli/command-waits.js +51 -0
- package/dist/src/cli/commands.js +70 -88
- package/dist/src/cli/config-file.d.ts +2 -2
- package/dist/src/cli/config-file.js +4 -2
- package/dist/src/cli/config-notice.js +5 -2
- package/dist/src/cli/doctor-retention.d.ts +2 -0
- package/dist/src/cli/doctor-retention.js +93 -0
- package/dist/src/cli/doctor-workflows.d.ts +5 -2
- package/dist/src/cli/doctor-workflows.js +12 -7
- package/dist/src/cli/doctor.js +11 -9
- package/dist/src/cli/harness-probes.d.ts +2 -0
- package/dist/src/cli/harness-probes.js +1 -1
- package/dist/src/cli/harness-processes.d.ts +6 -0
- package/dist/src/cli/harness-processes.js +36 -0
- package/dist/src/cli/init-command.d.ts +9 -0
- package/dist/src/cli/init-command.js +52 -0
- package/dist/src/cli/init-prompt-command.d.ts +10 -0
- package/dist/src/cli/init-prompt-command.js +145 -0
- package/dist/src/cli/init-prompt.d.ts +35 -0
- package/dist/src/cli/init-prompt.js +74 -0
- package/dist/src/cli/init-selection.d.ts +13 -0
- package/dist/src/cli/init-selection.js +75 -0
- package/dist/src/cli/main.d.ts +2 -0
- package/dist/src/cli/main.js +37 -7
- package/dist/src/cli/mcp-server.d.ts +1 -0
- package/dist/src/cli/mcp-server.js +156 -0
- package/dist/src/cli/mcp-tools.d.ts +15 -0
- package/dist/src/cli/mcp-tools.js +242 -0
- package/dist/src/cli/queue-arguments.d.ts +15 -0
- package/dist/src/cli/queue-arguments.js +31 -0
- package/dist/src/cli/queue-render.d.ts +3 -0
- package/dist/src/cli/queue-render.js +26 -0
- package/dist/src/cli/reload-render.d.ts +2 -0
- package/dist/src/cli/reload-render.js +12 -0
- package/dist/src/cli/render.d.ts +1 -1
- package/dist/src/cli/render.js +54 -38
- package/dist/src/cli/report-ci-jobs.d.ts +23 -0
- package/dist/src/cli/report-ci-jobs.js +103 -0
- package/dist/src/cli/report-ci-usage.d.ts +9 -0
- package/dist/src/cli/report-ci-usage.js +185 -0
- package/dist/src/cli/report-ci.d.ts +13 -0
- package/dist/src/cli/report-ci.js +74 -0
- package/dist/src/cli/report-closures.d.ts +6 -0
- package/dist/src/cli/report-closures.js +97 -0
- package/dist/src/cli/report-flow.d.ts +7 -0
- package/dist/src/cli/report-flow.js +122 -0
- package/dist/src/cli/report-github-reader.d.ts +29 -0
- package/dist/src/cli/report-github-reader.js +157 -0
- package/dist/src/cli/report-github.d.ts +15 -8
- package/dist/src/cli/report-github.js +131 -150
- package/dist/src/cli/report-operator.d.ts +3 -0
- package/dist/src/cli/report-operator.js +40 -0
- package/dist/src/cli/report-ready.d.ts +3 -0
- package/dist/src/cli/report-ready.js +96 -0
- package/dist/src/cli/report-text.d.ts +9 -0
- package/dist/src/cli/report-text.js +33 -0
- package/dist/src/cli/report.d.ts +1 -0
- package/dist/src/cli/report.js +104 -27
- package/dist/src/cli/runtime-arguments.d.ts +18 -3
- package/dist/src/cli/runtime-arguments.js +29 -20
- package/dist/src/cli/schedule-arguments.d.ts +14 -0
- package/dist/src/cli/schedule-arguments.js +26 -0
- package/dist/src/cli/schedule-render.d.ts +22 -0
- package/dist/src/cli/schedule-render.js +73 -0
- package/dist/src/cli/terminal-text.d.ts +3 -0
- package/dist/src/cli/terminal-text.js +28 -0
- package/dist/src/cli/toolchain.d.ts +1 -0
- package/dist/src/cli/toolchain.js +1 -0
- package/dist/src/cli/usage-render.d.ts +1 -0
- package/dist/src/cli/usage-render.js +28 -1
- package/dist/src/cli/usage.d.ts +2 -2
- package/dist/src/cli/usage.js +89 -11
- package/dist/src/cli/watch-actions.js +2 -2
- package/dist/src/cli/watch-api-document.d.ts +430 -0
- package/dist/src/cli/watch-api-document.js +291 -0
- package/dist/src/cli/watch-api-run.d.ts +56 -0
- package/dist/src/cli/watch-api-run.js +112 -0
- package/dist/src/cli/watch-api.d.ts +17 -0
- package/dist/src/cli/watch-api.js +230 -0
- package/dist/src/cli/watch-board-view.js +19 -2
- package/dist/src/cli/watch-board.d.ts +4 -2
- package/dist/src/cli/watch-board.js +53 -43
- package/dist/src/cli/watch-card-forms.d.ts +1 -1
- package/dist/src/cli/watch-card-forms.js +11 -10
- package/dist/src/cli/watch-client.d.ts +1 -1
- package/dist/src/cli/watch-client.js +2 -11
- package/dist/src/cli/watch-header-view.d.ts +1 -5
- package/dist/src/cli/watch-header-view.js +17 -21
- package/dist/src/cli/watch-model.d.ts +5 -1
- package/dist/src/cli/watch-model.js +20 -11
- package/dist/src/cli/watch-page.js +15 -15
- package/dist/src/cli/watch-phases.d.ts +12 -3
- package/dist/src/cli/watch-phases.js +68 -11
- package/dist/src/cli/watch-pr-board.js +1 -1
- package/dist/src/cli/watch-pr-command.d.ts +1 -0
- package/dist/src/cli/watch-pull-request.js +18 -8
- package/dist/src/cli/watch-reads.d.ts +3 -0
- package/dist/src/cli/watch-reads.js +22 -20
- package/dist/src/cli/watch-render.d.ts +15 -0
- package/dist/src/cli/watch-run-input.d.ts +0 -1
- package/dist/src/cli/watch-run-input.js +0 -13
- package/dist/src/cli/watch-server.js +24 -10
- package/dist/src/cli/watch-view.d.ts +0 -3
- package/dist/src/cli/watch-view.js +13 -13
- package/dist/src/cli.js +73 -12
- package/dist/src/command-wait.d.ts +4 -0
- package/dist/src/command-wait.js +45 -0
- package/dist/src/configuration-change.d.ts +7 -0
- package/dist/src/configuration-change.js +14 -0
- package/dist/src/configuration-display.js +2 -0
- package/dist/src/configuration-schema.d.ts +14 -0
- package/dist/src/configuration-schema.js +6 -2
- package/dist/src/daemon/attachment-file.d.ts +6 -0
- package/dist/src/daemon/attachment-file.js +86 -0
- package/dist/src/daemon/attachments.d.ts +14 -0
- package/dist/src/daemon/attachments.js +17 -0
- package/dist/src/daemon/claude-recovery.d.ts +50 -0
- package/dist/src/daemon/claude-recovery.js +208 -0
- package/dist/src/daemon/claude-stream.d.ts +27 -0
- package/dist/src/daemon/claude-stream.js +63 -0
- package/dist/src/daemon/claude-turn.d.ts +11 -25
- package/dist/src/daemon/claude-turn.js +64 -81
- package/dist/src/daemon/claude-worker.d.ts +5 -4
- package/dist/src/daemon/claude-worker.js +127 -126
- package/dist/src/daemon/daemon-adapters.d.ts +9 -0
- package/dist/src/daemon/daemon-adapters.js +33 -5
- package/dist/src/daemon/daemon-loops.d.ts +5 -1
- package/dist/src/daemon/daemon-loops.js +18 -10
- package/dist/src/daemon/daemon.js +80 -61
- package/dist/src/daemon/github-attach.d.ts +2 -0
- package/dist/src/daemon/github-attach.js +222 -0
- package/dist/src/daemon/github-calls.js +1 -1
- package/dist/src/daemon/github-ci-filters.d.ts +6 -0
- package/dist/src/daemon/github-ci-filters.js +138 -0
- package/dist/src/daemon/github-ci-workflows.d.ts +10 -0
- package/dist/src/daemon/github-ci-workflows.js +148 -0
- package/dist/src/daemon/github-ci.js +22 -4
- package/dist/src/daemon/github-issue-methods.d.ts +2 -0
- package/dist/src/daemon/github-issue-methods.js +37 -2
- package/dist/src/daemon/github-merge-call.d.ts +2 -1
- package/dist/src/daemon/github-merge-call.js +10 -3
- package/dist/src/daemon/github-merge.js +52 -24
- package/dist/src/daemon/github-methods.js +18 -4
- package/dist/src/daemon/github-operation.d.ts +4 -0
- package/dist/src/daemon/github-operation.js +6 -0
- package/dist/src/daemon/github-worker.d.ts +4 -0
- package/dist/src/daemon/github-worker.js +6 -0
- package/dist/src/daemon/issue-queue.d.ts +4 -1
- package/dist/src/daemon/issue-queue.js +76 -78
- package/dist/src/daemon/merge-turns.d.ts +10 -0
- package/dist/src/daemon/merge-turns.js +37 -0
- package/dist/src/daemon/notify-events.d.ts +6 -0
- package/dist/src/daemon/notify-events.js +84 -0
- package/dist/src/daemon/notify-journal.js +1 -1
- package/dist/src/daemon/notify-message.d.ts +4 -1
- package/dist/src/daemon/notify-message.js +36 -0
- package/dist/src/daemon/notify.d.ts +1 -1
- package/dist/src/daemon/notify.js +5 -77
- package/dist/src/daemon/operation-journal.d.ts +1 -0
- package/dist/src/daemon/queue-control.d.ts +13 -0
- package/dist/src/daemon/queue-control.js +86 -0
- package/dist/src/daemon/queue-journal.d.ts +20 -0
- package/dist/src/daemon/queue-journal.js +89 -0
- package/dist/src/daemon/queue-status.d.ts +9 -3
- package/dist/src/daemon/queue-status.js +17 -4
- package/dist/src/daemon/record-archive.d.ts +19 -0
- package/dist/src/daemon/record-archive.js +82 -0
- package/dist/src/daemon/record-sweep.d.ts +24 -0
- package/dist/src/daemon/record-sweep.js +147 -0
- package/dist/src/daemon/resume-index-lock.d.ts +13 -0
- package/dist/src/daemon/resume-index-lock.js +160 -0
- package/dist/src/daemon/resume-worktree.d.ts +7 -0
- package/dist/src/daemon/resume-worktree.js +29 -0
- package/dist/src/daemon/retrying-turn.d.ts +2 -12
- package/dist/src/daemon/retrying-turn.js +98 -172
- package/dist/src/daemon/schedule-control.d.ts +26 -0
- package/dist/src/daemon/schedule-control.js +110 -0
- package/dist/src/daemon/schedule-journal.d.ts +2 -15
- package/dist/src/daemon/schedule-journal.js +67 -4
- package/dist/src/daemon/settings-reload.d.ts +26 -0
- package/dist/src/daemon/settings-reload.js +82 -0
- package/dist/src/daemon/ticket-registration.d.ts +2 -7
- package/dist/src/daemon/ticket-registration.js +15 -81
- package/dist/src/daemon/turn-attempt-journal.d.ts +38 -0
- package/dist/src/daemon/turn-attempt-journal.js +136 -0
- package/dist/src/daemon/turn-attempts.d.ts +47 -0
- package/dist/src/daemon/turn-attempts.js +166 -0
- package/dist/src/daemon/turn-details.d.ts +4 -0
- package/dist/src/daemon/turn-details.js +33 -0
- package/dist/src/daemon/turn-report.d.ts +8 -1
- package/dist/src/daemon/turn-report.js +39 -0
- package/dist/src/daemon/work-tree.d.ts +9 -0
- package/dist/src/daemon/work-tree.js +20 -0
- package/dist/src/daemon/worker-profile.d.ts +9 -0
- package/dist/src/daemon/worker-profile.js +44 -0
- package/dist/src/daemon/workflow-generations.d.ts +7 -4
- package/dist/src/daemon/workflow-generations.js +22 -14
- package/dist/src/daemon/workflow-reload.d.ts +41 -0
- package/dist/src/daemon/workflow-reload.js +244 -0
- package/dist/src/daemon/workflow-replay.d.ts +2 -1
- package/dist/src/daemon/workflow-replay.js +7 -3
- package/dist/src/daemon/workflow-schedules.d.ts +3 -0
- package/dist/src/daemon/workflow-schedules.js +98 -45
- package/dist/src/daemon/worktree-processes.d.ts +9 -0
- package/dist/src/daemon/worktree-processes.js +151 -0
- package/dist/src/doctor-report.d.ts +4 -6
- package/dist/src/doctor-report.js +8 -13
- package/dist/src/harness-start.d.ts +15 -0
- package/dist/src/harness-start.js +37 -0
- package/dist/src/host/command-wait.d.ts +38 -0
- package/dist/src/host/command-wait.js +115 -0
- package/dist/src/host/start-delivery.d.ts +5 -7
- package/dist/src/host/start-delivery.js +3 -15
- package/dist/src/host/step-bridge-host.d.ts +2 -0
- package/dist/src/host/step-bridge-host.js +21 -0
- package/dist/src/operation-identity.d.ts +1 -0
- package/dist/src/operation-identity.js +4 -0
- package/dist/src/private-config.schema.json +71 -0
- package/dist/src/project-config.schema.json +40 -0
- package/dist/src/project-settings.d.ts +16 -2
- package/dist/src/project-settings.js +35 -1
- package/dist/src/queue-spend.d.ts +4 -0
- package/dist/src/queue-spend.js +21 -0
- package/dist/src/queue-state.d.ts +26 -0
- package/dist/src/queue-state.js +34 -0
- package/dist/src/record-retention.d.ts +46 -0
- package/dist/src/record-retention.js +81 -0
- package/dist/src/relay/relay-service.d.ts +3 -0
- package/dist/src/relay/relay-service.js +5 -3
- package/dist/src/report-ci.d.ts +164 -0
- package/dist/src/report-ci.js +32 -0
- package/dist/src/report-effects.d.ts +15 -0
- package/dist/src/report-effects.js +212 -0
- package/dist/src/report-flow-types.d.ts +38 -0
- package/dist/src/report-flow-types.js +7 -0
- package/dist/src/report-flow.d.ts +43 -0
- package/dist/src/report-flow.js +193 -0
- package/dist/src/report-operator.d.ts +67 -0
- package/dist/src/report-operator.js +25 -0
- package/dist/src/report-quality.d.ts +221 -0
- package/dist/src/report-quality.js +94 -0
- package/dist/src/report-ready.d.ts +23 -0
- package/dist/src/report-ready.js +117 -0
- package/dist/src/report-statistics.d.ts +2 -1
- package/dist/src/report-statistics.js +40 -4
- package/dist/src/report.d.ts +588 -47
- package/dist/src/report.js +156 -41
- package/dist/src/schedule-progress.d.ts +33 -0
- package/dist/src/schedule-progress.js +45 -0
- package/dist/src/service/active-tickets.js +11 -6
- package/dist/src/service/command-waits.d.ts +34 -0
- package/dist/src/service/command-waits.js +86 -0
- package/dist/src/service/dispatcher.d.ts +4 -0
- package/dist/src/service/dispatcher.js +33 -0
- package/dist/src/service/expiry.js +2 -0
- package/dist/src/service/gateway.js +3 -1
- package/dist/src/service/queue-handlers.d.ts +4 -0
- package/dist/src/service/queue-handlers.js +32 -0
- package/dist/src/service/queue-spend.d.ts +6 -0
- package/dist/src/service/queue-spend.js +68 -0
- package/dist/src/service/registry.d.ts +28 -2
- package/dist/src/service/registry.js +48 -0
- package/dist/src/service/replies.d.ts +22 -8
- package/dist/src/service/replies.js +16 -2
- package/dist/src/service/run-handlers.js +37 -12
- package/dist/src/service/run-metadata.d.ts +15 -1
- package/dist/src/service/run-metadata.js +93 -8
- package/dist/src/service/service.d.ts +11 -3
- package/dist/src/service/service.js +22 -37
- package/dist/src/service/submission-handler.js +18 -4
- package/dist/src/service/worker-port.js +9 -1
- package/dist/src/service/worker-totals.d.ts +6 -0
- package/dist/src/service/worker-totals.js +8 -1
- package/dist/src/service/workflow-reload.d.ts +35 -0
- package/dist/src/service/workflow-reload.js +52 -0
- package/dist/src/step-bridge.d.ts +20 -0
- package/dist/src/steps/command-wait.d.ts +12 -0
- package/dist/src/steps/command-wait.js +26 -0
- package/dist/src/steps/open-decision-wait.d.ts +2 -0
- package/dist/src/steps/{decision-gate.js → open-decision-wait.js} +0 -7
- package/dist/src/steps/review-by-person.js +4 -1
- package/dist/src/steps/wait-for-command.d.ts +3 -0
- package/dist/src/steps/wait-for-command.js +17 -0
- package/dist/src/steps/wait-for-decision.js +1 -1
- package/dist/src/storage/command-wait-rows.d.ts +30 -0
- package/dist/src/storage/command-wait-rows.js +96 -0
- package/dist/src/storage/decision-snapshots.d.ts +8 -2
- package/dist/src/storage/decision-snapshots.js +16 -8
- package/dist/src/storage/domain-changes.d.ts +3 -1
- package/dist/src/storage/domain-changes.js +4 -0
- package/dist/src/storage/domain-schema.d.ts +16 -1
- package/dist/src/storage/domain-schema.js +35 -4
- package/dist/src/storage/effect-schema.d.ts +2 -0
- package/dist/src/storage/effect-schema.js +9 -0
- package/dist/src/storage/projection-changes.d.ts +12 -0
- package/dist/src/storage/projection-changes.js +194 -0
- package/dist/src/storage/projection-lookups.d.ts +7 -0
- package/dist/src/storage/projection-lookups.js +30 -0
- package/dist/src/testing-requests.d.ts +15 -0
- package/dist/src/testing-requests.js +93 -0
- package/dist/src/testing.d.ts +4 -10
- package/dist/src/testing.js +33 -86
- package/dist/src/worker-usage.d.ts +1 -0
- package/dist/src/worker-usage.js +3 -0
- package/dist/src/workflow-candidate.d.ts +1 -0
- package/dist/src/workflow-candidate.js +12 -1
- package/dist/src/workflow-contracts.d.ts +1 -0
- package/dist/src/workflow-contracts.js +9 -2
- package/dist/src/workflow-declaration.d.ts +1 -0
- package/dist/src/workflow-declaration.js +3 -0
- package/dist/src/workflow-discovery.d.ts +2 -13
- package/dist/src/workflow-discovery.js +1 -13
- package/dist/src/workflow-refusals.js +0 -1
- package/dist/src/workflows.d.ts +1 -1
- package/dist/src/workflows.js +1 -1
- package/dist/tools/compile-workflows.js +3 -0
- package/dist/tools/project-configuration.d.ts +7 -2
- package/dist/tools/project-configuration.js +30 -1
- package/dist/tools/red-green-command.d.ts +1 -0
- package/dist/tools/red-green-command.js +174 -0
- package/dist/tools/red-green-process.d.ts +10 -0
- package/dist/tools/red-green-process.js +59 -0
- package/dist/tools/self-host-processes.d.ts +2 -0
- package/dist/tools/self-host-processes.js +69 -26
- package/dist/tools/self-host-project.d.ts +2 -0
- package/dist/tools/self-host-project.js +30 -77
- package/dist/tools/self-host-runtime.js +1 -1
- package/dist/tools/self-host.js +76 -34
- package/dist/tools/template-command.d.ts +1 -0
- package/dist/tools/template-command.js +160 -0
- package/dist/tools/template-copy.d.ts +11 -0
- package/dist/tools/template-copy.js +130 -0
- package/dist/tools/template-files.d.ts +17 -0
- package/dist/tools/template-files.js +74 -0
- package/dist/tools/workflow-bundles.js +1 -0
- package/dist/tools/workflow-candidate-counts.js +2 -2
- package/dist/tools/workflow-candidate-program.d.ts +4 -2
- package/dist/tools/workflow-candidate-program.js +30 -11
- package/dist/tools/workflow-candidate-shape.d.ts +3 -0
- package/dist/tools/workflow-candidate-shape.js +90 -0
- package/dist/tools/workflow-candidate-source.d.ts +1 -0
- package/dist/tools/workflow-candidate-source.js +26 -4
- package/dist/tools/workflow-candidate-syntax.d.ts +2 -2
- package/dist/tools/workflow-candidate-syntax.js +24 -94
- package/dist/tools/workflow-command.js +1 -2
- package/dist/tools/workflow-folders.d.ts +2 -3
- package/dist/tools/workflow-folders.js +1 -1
- package/package.json +17 -9
- package/templates/develop/README.md +93 -4
- package/templates/develop/develop/flow-tests.ts +38 -1
- package/templates/develop/develop/interruption-tests.ts +157 -0
- package/templates/develop/develop/local.ts +1 -0
- package/templates/develop/develop/option-tests.ts +138 -9
- package/templates/develop/develop/pull.ts +5 -1
- package/templates/develop/develop/red-green.ts +55 -0
- package/templates/develop/develop/refusal-tests.ts +77 -0
- package/templates/develop/develop/report.ts +31 -11
- package/templates/develop/develop/round.ts +1 -0
- package/templates/develop/develop/scenarios.ts +27 -0
- package/templates/develop/develop/turn.ts +28 -7
- package/templates/develop/develop.declaration.json +1 -1
- package/templates/develop/develop.test.ts +4 -0
- package/templates/develop/template.json +29 -2
- package/templates/idea-to-issue/README.md +27 -0
- package/templates/idea-to-issue/idea-to-issue/effects.ts +52 -0
- package/templates/idea-to-issue/idea-to-issue/leave.ts +10 -0
- package/templates/idea-to-issue/idea-to-issue/next.ts +29 -0
- package/templates/idea-to-issue/idea-to-issue/post-person.ts +18 -0
- package/templates/idea-to-issue/idea-to-issue/post.ts +50 -0
- package/templates/idea-to-issue/idea-to-issue/queue.ts +27 -0
- package/templates/idea-to-issue/idea-to-issue/review.ts +42 -0
- package/templates/idea-to-issue/idea-to-issue/scenarios.ts +50 -0
- package/templates/idea-to-issue/idea-to-issue/turn.ts +40 -0
- package/templates/idea-to-issue/idea-to-issue.declaration.json +16 -0
- package/templates/idea-to-issue/idea-to-issue.test.ts +79 -0
- package/templates/idea-to-issue/idea-to-issue.ts +49 -0
- package/templates/idea-to-issue/template.json +81 -0
- package/templates/review-day/README.md +97 -0
- package/templates/review-day/review-day/critique.ts +58 -0
- package/templates/review-day/review-day/decision.ts +29 -0
- package/templates/review-day/review-day/facts.ts +69 -0
- package/templates/review-day/review-day/label.ts +29 -0
- package/templates/review-day/review-day/next.ts +28 -0
- package/templates/review-day/review-day/post.ts +27 -0
- package/templates/review-day/review-day/report.ts +98 -0
- package/templates/review-day/review-day/rules.ts +12 -0
- package/templates/review-day/review-day/scenarios.ts +76 -0
- package/templates/review-day/review-day/turn.ts +73 -0
- package/templates/review-day/review-day.declaration.json +16 -0
- package/templates/review-day/review-day.test.ts +362 -0
- package/templates/review-day/review-day.ts +37 -0
- package/templates/review-day/template.json +56 -0
- package/dist/src/cli/watch-start-view.d.ts +0 -18
- package/dist/src/cli/watch-start-view.js +0 -77
- package/dist/src/steps/decision-gate.d.ts +0 -3
- package/dist/workflows/develop-prd.d.ts +0 -7
- package/dist/workflows/develop-prd.js +0 -165
- package/dist/workflows/develop-ticket.d.ts +0 -9
- package/dist/workflows/develop-ticket.js +0 -207
- package/dist/workflows/issue-labels.d.ts +0 -16
- package/dist/workflows/issue-labels.js +0 -70
- package/dist/workflows/ticket-prompts.d.ts +0 -35
- package/dist/workflows/ticket-prompts.js +0 -147
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { readdir, readFile, stat } from "node:fs/promises";
|
|
2
|
+
import { homedir } from "node:os";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { parseArgs } from "node:util";
|
|
5
|
+
import { absoluteWorkflowFolder } from "../src/project-settings.js";
|
|
6
|
+
import { record } from "../src/protocol.js";
|
|
7
|
+
import { isCandidateDeclaration } from "../src/workflow-candidate.js";
|
|
8
|
+
import { projectConfiguration, projectRoot } from "./project-configuration.js";
|
|
9
|
+
import { copyTemplate } from "./template-copy.js";
|
|
10
|
+
import { exportedFunctions, readTemplate, templateList, templateRoot, } from "./template-files.js";
|
|
11
|
+
import { userLocation } from "./workflow-folders.js";
|
|
12
|
+
const usage = "Usage: cloving templates list [--json]\n cloving templates show <name> [--json]\n cloving templates copy <name> [--id <workflow-id>] [--json] [--repository <directory>]\n";
|
|
13
|
+
function invocation(argumentsList) {
|
|
14
|
+
const { values, positionals } = parseArgs({
|
|
15
|
+
args: [...argumentsList],
|
|
16
|
+
allowPositionals: true,
|
|
17
|
+
options: {
|
|
18
|
+
json: { type: "boolean" },
|
|
19
|
+
id: { type: "string" },
|
|
20
|
+
repository: { type: "string" },
|
|
21
|
+
help: { type: "boolean", short: "h" },
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
const [command, name, ...extra] = positionals;
|
|
25
|
+
if (values.help === true)
|
|
26
|
+
return { ...values, command: "help", name: "" };
|
|
27
|
+
if (!["list", "show", "copy"].includes(command ?? ""))
|
|
28
|
+
throw new Error("unknown-command");
|
|
29
|
+
if (extra.length > 0 || (command === "list") !== (name === undefined))
|
|
30
|
+
throw new Error("unexpected-argument");
|
|
31
|
+
if (command !== "copy" && (values.id !== undefined || values.repository))
|
|
32
|
+
throw new Error("unexpected-option");
|
|
33
|
+
return { ...values, command, name: name ?? "" };
|
|
34
|
+
}
|
|
35
|
+
export async function templateCommand(argumentsList) {
|
|
36
|
+
let selected;
|
|
37
|
+
try {
|
|
38
|
+
selected = invocation(argumentsList);
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
process.stderr.write("invalid-invocation: " + usage);
|
|
42
|
+
return 2;
|
|
43
|
+
}
|
|
44
|
+
if (selected.help) {
|
|
45
|
+
process.stdout.write(usage);
|
|
46
|
+
return 0;
|
|
47
|
+
}
|
|
48
|
+
try {
|
|
49
|
+
const root = templateRoot();
|
|
50
|
+
const json = selected.json === true;
|
|
51
|
+
if (selected.command === "list")
|
|
52
|
+
return await listed(root, { json });
|
|
53
|
+
if (selected.command === "show")
|
|
54
|
+
return await shown(root, { name: selected.name, json });
|
|
55
|
+
return await copied(root, {
|
|
56
|
+
name: selected.name,
|
|
57
|
+
id: selected.id ?? selected.name,
|
|
58
|
+
json,
|
|
59
|
+
repository: selected.repository ?? process.cwd(),
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
catch (error) {
|
|
63
|
+
process.stderr.write((error instanceof Error ? error.message : "template-command-failed") +
|
|
64
|
+
"\n");
|
|
65
|
+
return 1;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
async function listed(root, input) {
|
|
69
|
+
const templates = await templateList(root);
|
|
70
|
+
if (input.json)
|
|
71
|
+
process.stdout.write(JSON.stringify(templates) + "\n");
|
|
72
|
+
else
|
|
73
|
+
for (const template of templates)
|
|
74
|
+
process.stdout.write(`${template.name}: ${template.summary} (${String(template.points)} decision points)\n`);
|
|
75
|
+
return 0;
|
|
76
|
+
}
|
|
77
|
+
async function shown(root, input) {
|
|
78
|
+
const template = await readTemplate(root, input.name);
|
|
79
|
+
if (input.json) {
|
|
80
|
+
process.stdout.write(JSON.stringify({
|
|
81
|
+
template: template.description,
|
|
82
|
+
files: template.files,
|
|
83
|
+
}) + "\n");
|
|
84
|
+
return 0;
|
|
85
|
+
}
|
|
86
|
+
process.stdout.write(`${template.name}: ${String(template.description["summary"])}\n${pointText(template.points)}Files:\n${template.files.map((file) => ` ${file}\n`).join("")}`);
|
|
87
|
+
return 0;
|
|
88
|
+
}
|
|
89
|
+
async function copied(root, input) {
|
|
90
|
+
const repository = await projectRoot(input.repository);
|
|
91
|
+
const folder = join(repository, ".cloving", "workflows");
|
|
92
|
+
const folders = [folder, await userFolder(repository)];
|
|
93
|
+
const packageRoot = dirname(root);
|
|
94
|
+
const takenNames = await exportedFunctions([
|
|
95
|
+
join(packageRoot, "workflows"),
|
|
96
|
+
join(packageRoot, "dist", "workflows"),
|
|
97
|
+
...folders,
|
|
98
|
+
]);
|
|
99
|
+
const result = await copyTemplate({ ...input, root, folder, takenNames });
|
|
100
|
+
const queued = (await Promise.all(folders.map(queuedIn))).flat().sort();
|
|
101
|
+
if (input.json)
|
|
102
|
+
process.stdout.write(JSON.stringify({
|
|
103
|
+
workflowId: input.id,
|
|
104
|
+
template: input.name,
|
|
105
|
+
files: result.files,
|
|
106
|
+
queueWorkflows: queued,
|
|
107
|
+
}) + "\n");
|
|
108
|
+
else
|
|
109
|
+
process.stdout.write(`Copied the template ${input.name} to .cloving/workflows as the workflow ${input.id}.\nDecision points:\n${pointText(result.template.points)}Next: cloving workflows test ${input.id}\n`);
|
|
110
|
+
if (queued.length > 1)
|
|
111
|
+
process.stderr.write(`queue-workflow-conflict: ${queued.join(", ")} have "queue": true. Select "a person" for the select point of one copy: remove workflow.queue from its declaration.\n`);
|
|
112
|
+
return 0;
|
|
113
|
+
}
|
|
114
|
+
function pointText(points) {
|
|
115
|
+
return points
|
|
116
|
+
.map((value) => {
|
|
117
|
+
const point = record(value);
|
|
118
|
+
const options = point?.["options"];
|
|
119
|
+
const lines = (Array.isArray(options) ? options : []).map((option, index) => {
|
|
120
|
+
const fields = record(option);
|
|
121
|
+
return ` - ${String(fields?.["id"])}: ${String(fields?.["label"])}${index === 0 ? " (default)" : ""}\n`;
|
|
122
|
+
});
|
|
123
|
+
return ` ${String(point?.["id"])}: ${String(point?.["question"])}\n${lines.join("")}`;
|
|
124
|
+
})
|
|
125
|
+
.join("");
|
|
126
|
+
}
|
|
127
|
+
async function userFolder(repository) {
|
|
128
|
+
const settings = await projectConfiguration(repository, process.env);
|
|
129
|
+
const user = userLocation({
|
|
130
|
+
home: homedir(),
|
|
131
|
+
xdgConfigHome: process.env["XDG_CONFIG_HOME"],
|
|
132
|
+
userFolder: absoluteWorkflowFolder(settings.environment["CLOVING_WORKFLOW_FOLDER"]),
|
|
133
|
+
});
|
|
134
|
+
return join(user.root, ...user.parts);
|
|
135
|
+
}
|
|
136
|
+
async function queuedIn(folder) {
|
|
137
|
+
const names = await readdir(folder).catch(() => []);
|
|
138
|
+
const ids = await Promise.all(names
|
|
139
|
+
.filter((name) => name.endsWith(".declaration.json"))
|
|
140
|
+
.map((name) => queuedId(folder, name)));
|
|
141
|
+
return ids.flatMap((id) => (id === undefined ? [] : [id]));
|
|
142
|
+
}
|
|
143
|
+
async function queuedId(folder, name) {
|
|
144
|
+
const text = await readFile(join(folder, name), "utf8").catch(() => "");
|
|
145
|
+
let declaration;
|
|
146
|
+
try {
|
|
147
|
+
declaration = JSON.parse(text);
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
return undefined;
|
|
151
|
+
}
|
|
152
|
+
if (!isCandidateDeclaration(declaration) ||
|
|
153
|
+
declaration.workflow.queue !== true)
|
|
154
|
+
return undefined;
|
|
155
|
+
const source = join(folder, name.replace(/\.declaration\.json$/, ".ts"));
|
|
156
|
+
const entry = await stat(source).catch(() => undefined);
|
|
157
|
+
return entry?.isFile() === true ? declaration.workflow.workflowId : undefined;
|
|
158
|
+
}
|
|
159
|
+
if (process.argv[1] === import.meta.filename)
|
|
160
|
+
process.exitCode = await templateCommand(process.argv.slice(2));
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type Template } from "./template-files.ts";
|
|
2
|
+
export declare function copyTemplate(input: {
|
|
3
|
+
readonly root: string;
|
|
4
|
+
readonly name: string;
|
|
5
|
+
readonly id: string;
|
|
6
|
+
readonly folder: string;
|
|
7
|
+
readonly takenNames: ReadonlySet<string>;
|
|
8
|
+
}): Promise<{
|
|
9
|
+
readonly template: Template;
|
|
10
|
+
readonly files: readonly string[];
|
|
11
|
+
}>;
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { link, mkdir, mkdtemp, readFile, rm, writeFile, } from "node:fs/promises";
|
|
2
|
+
import { dirname, join } from "node:path";
|
|
3
|
+
import ts from "typescript";
|
|
4
|
+
import { record } from "../src/protocol.js";
|
|
5
|
+
import { readTemplate, templateName } from "./template-files.js";
|
|
6
|
+
export async function copyTemplate(input) {
|
|
7
|
+
if (!templateName.test(input.id) || input.id.length > 64)
|
|
8
|
+
throw new Error(`invalid-workflow-id: ${input.id}`);
|
|
9
|
+
const template = await readTemplate(input.root, input.name);
|
|
10
|
+
const sources = await Promise.all(template.files.map(async (file) => ({
|
|
11
|
+
file,
|
|
12
|
+
text: await readFile(join(input.root, input.name, file), "utf8"),
|
|
13
|
+
})));
|
|
14
|
+
const renaming = functionRenaming(sources, input);
|
|
15
|
+
const plan = sources.map(({ file, text }) => ({
|
|
16
|
+
target: input.id + file.slice(input.name.length),
|
|
17
|
+
content: copiedContent({ file, text }, renaming),
|
|
18
|
+
}));
|
|
19
|
+
await writePlan(input.folder, plan);
|
|
20
|
+
return { template, files: plan.map((item) => item.target) };
|
|
21
|
+
}
|
|
22
|
+
function camelName(id) {
|
|
23
|
+
return id.replace(/-([a-z0-9])/g, (_, letter) => letter.toUpperCase());
|
|
24
|
+
}
|
|
25
|
+
function functionRenaming(sources, input) {
|
|
26
|
+
const from = camelName(input.name);
|
|
27
|
+
const names = new Set(sources
|
|
28
|
+
.filter(({ file }) => file.endsWith(".ts"))
|
|
29
|
+
.flatMap(({ text }) => text.match(/[A-Za-z_$][\w$]*/g) ?? []));
|
|
30
|
+
for (const name of input.takenNames)
|
|
31
|
+
names.add(name);
|
|
32
|
+
let to = camelName(input.id);
|
|
33
|
+
while (to !== from && (names.has(to) || reservedWord(to)))
|
|
34
|
+
to += "Workflow";
|
|
35
|
+
return { template: input.name, id: input.id, from, to };
|
|
36
|
+
}
|
|
37
|
+
function reservedWord(name) {
|
|
38
|
+
const scanner = ts.createScanner(ts.ScriptTarget.Latest, true);
|
|
39
|
+
scanner.setText(name);
|
|
40
|
+
const kind = scanner.scan();
|
|
41
|
+
return ((kind >= ts.SyntaxKind.FirstReservedWord &&
|
|
42
|
+
kind <= ts.SyntaxKind.LastFutureReservedWord) ||
|
|
43
|
+
["await", "eval", "arguments"].includes(name));
|
|
44
|
+
}
|
|
45
|
+
function copiedContent(source, renaming) {
|
|
46
|
+
const { file, text } = source;
|
|
47
|
+
if (file.endsWith(".declaration.json"))
|
|
48
|
+
return copiedDeclaration(text, renaming);
|
|
49
|
+
if (!file.endsWith(".ts") || renaming.id === renaming.template)
|
|
50
|
+
return text;
|
|
51
|
+
return renamedSource(source, renaming);
|
|
52
|
+
}
|
|
53
|
+
function copiedDeclaration(text, renaming) {
|
|
54
|
+
const declaration = record(JSON.parse(text));
|
|
55
|
+
const workflow = record(declaration?.["workflow"]);
|
|
56
|
+
if (declaration === undefined || workflow === undefined)
|
|
57
|
+
throw new Error(`invalid-template: ${renaming.template}`);
|
|
58
|
+
return (JSON.stringify({
|
|
59
|
+
template: renaming.template,
|
|
60
|
+
...declaration,
|
|
61
|
+
workflow: { ...workflow, workflowId: renaming.id },
|
|
62
|
+
}, null, 2) + "\n");
|
|
63
|
+
}
|
|
64
|
+
function renamedSource(input, renaming) {
|
|
65
|
+
const { file, text } = input;
|
|
66
|
+
const source = ts.createSourceFile(file, text, ts.ScriptTarget.Latest, true);
|
|
67
|
+
const edits = [];
|
|
68
|
+
const prefix = new RegExp(`^(\\.\\.?/)${renaming.template}(?=[./])`);
|
|
69
|
+
const visit = (node) => {
|
|
70
|
+
if (ts.isIdentifier(node) && node.text === renaming.from)
|
|
71
|
+
edits.push({ start: node.getStart(), end: node.end, text: renaming.to });
|
|
72
|
+
if (ts.isStringLiteral(node) &&
|
|
73
|
+
(ts.isImportDeclaration(node.parent) ||
|
|
74
|
+
ts.isExportDeclaration(node.parent)) &&
|
|
75
|
+
prefix.test(node.text))
|
|
76
|
+
edits.push({
|
|
77
|
+
start: node.getStart() + 1,
|
|
78
|
+
end: node.end - 1,
|
|
79
|
+
text: node.text.replace(prefix, `$1${renaming.id}`),
|
|
80
|
+
});
|
|
81
|
+
ts.forEachChild(node, visit);
|
|
82
|
+
};
|
|
83
|
+
visit(source);
|
|
84
|
+
return edits
|
|
85
|
+
.sort((left, right) => right.start - left.start)
|
|
86
|
+
.reduce((current, edit) => current.slice(0, edit.start) + edit.text + current.slice(edit.end), text);
|
|
87
|
+
}
|
|
88
|
+
async function writePlan(folder, plan) {
|
|
89
|
+
await mkdir(folder, { recursive: true });
|
|
90
|
+
const staging = await mkdtemp(join(dirname(folder), ".template-copy-"));
|
|
91
|
+
const created = [];
|
|
92
|
+
try {
|
|
93
|
+
for (const item of plan) {
|
|
94
|
+
await mkdir(dirname(join(staging, item.target)), { recursive: true });
|
|
95
|
+
await writeFile(join(staging, item.target), item.content);
|
|
96
|
+
}
|
|
97
|
+
for (const item of plan)
|
|
98
|
+
await placed({ folder, staging, item }, created);
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
for (const path of created.reverse())
|
|
102
|
+
await rm(path, { recursive: true, force: true });
|
|
103
|
+
throw error;
|
|
104
|
+
}
|
|
105
|
+
finally {
|
|
106
|
+
await rm(staging, { recursive: true, force: true });
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
async function placed(input, created) {
|
|
110
|
+
const parts = input.item.target.split("/");
|
|
111
|
+
for (let depth = 1; depth < parts.length; depth += 1) {
|
|
112
|
+
const directory = join(input.folder, ...parts.slice(0, depth));
|
|
113
|
+
if (created.includes(directory))
|
|
114
|
+
continue;
|
|
115
|
+
await mkdir(directory).catch((error) => {
|
|
116
|
+
throw present(error, parts.slice(0, depth).join("/"));
|
|
117
|
+
});
|
|
118
|
+
created.push(directory);
|
|
119
|
+
}
|
|
120
|
+
const target = join(input.folder, input.item.target);
|
|
121
|
+
await link(join(input.staging, input.item.target), target).catch((error) => {
|
|
122
|
+
throw present(error, input.item.target);
|
|
123
|
+
});
|
|
124
|
+
created.push(target);
|
|
125
|
+
}
|
|
126
|
+
function present(error, target) {
|
|
127
|
+
return error instanceof Error && "code" in error && error.code === "EEXIST"
|
|
128
|
+
? new Error(`workflow-exists: ${target}`)
|
|
129
|
+
: error;
|
|
130
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type Fields } from "../src/protocol.ts";
|
|
2
|
+
export interface TemplateSummary {
|
|
3
|
+
readonly name: string;
|
|
4
|
+
readonly summary: string;
|
|
5
|
+
readonly points: number;
|
|
6
|
+
}
|
|
7
|
+
export interface Template {
|
|
8
|
+
readonly name: string;
|
|
9
|
+
readonly description: Fields;
|
|
10
|
+
readonly points: readonly unknown[];
|
|
11
|
+
readonly files: readonly string[];
|
|
12
|
+
}
|
|
13
|
+
export declare const templateName: RegExp;
|
|
14
|
+
export declare function templateRoot(start?: string): string;
|
|
15
|
+
export declare function templateList(root: string): Promise<readonly TemplateSummary[]>;
|
|
16
|
+
export declare function readTemplate(root: string, name: string): Promise<Template>;
|
|
17
|
+
export declare function exportedFunctions(folders: readonly string[]): Promise<ReadonlySet<string>>;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
3
|
+
import { dirname, join } from "node:path";
|
|
4
|
+
import { record } from "../src/protocol.js";
|
|
5
|
+
export const templateName = /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*$/;
|
|
6
|
+
const descriptionFiles = ["template.json", "README.md"];
|
|
7
|
+
export function templateRoot(start = import.meta.dirname) {
|
|
8
|
+
let directory = start;
|
|
9
|
+
while (!existsSync(join(directory, "package.json"))) {
|
|
10
|
+
const parent = dirname(directory);
|
|
11
|
+
if (parent === directory)
|
|
12
|
+
throw new Error("templates-not-found");
|
|
13
|
+
directory = parent;
|
|
14
|
+
}
|
|
15
|
+
return join(directory, "templates");
|
|
16
|
+
}
|
|
17
|
+
export async function templateList(root) {
|
|
18
|
+
const entries = await readdir(root, { withFileTypes: true });
|
|
19
|
+
const names = entries
|
|
20
|
+
.filter((entry) => entry.isDirectory() && templateName.test(entry.name))
|
|
21
|
+
.map((entry) => entry.name)
|
|
22
|
+
.sort();
|
|
23
|
+
const templates = await Promise.all(names.map((name) => readTemplate(root, name).catch(() => undefined)));
|
|
24
|
+
return templates.flatMap((template) => template === undefined
|
|
25
|
+
? []
|
|
26
|
+
: [
|
|
27
|
+
{
|
|
28
|
+
name: template.name,
|
|
29
|
+
summary: String(template.description["summary"]),
|
|
30
|
+
points: template.points.length,
|
|
31
|
+
},
|
|
32
|
+
]);
|
|
33
|
+
}
|
|
34
|
+
export async function readTemplate(root, name) {
|
|
35
|
+
if (!templateName.test(name))
|
|
36
|
+
throw new Error(`unknown-template: ${name}`);
|
|
37
|
+
const folder = join(root, name);
|
|
38
|
+
const text = await readFile(join(folder, "template.json"), "utf8").catch(() => {
|
|
39
|
+
throw new Error(`unknown-template: ${name}`);
|
|
40
|
+
});
|
|
41
|
+
const description = record(JSON.parse(text));
|
|
42
|
+
const points = description?.["points"];
|
|
43
|
+
if (description === undefined ||
|
|
44
|
+
typeof description["summary"] !== "string" ||
|
|
45
|
+
!Array.isArray(points))
|
|
46
|
+
throw new Error(`invalid-template: ${name}`);
|
|
47
|
+
return { name, description, points, files: await workflowFiles(folder) };
|
|
48
|
+
}
|
|
49
|
+
export async function exportedFunctions(folders) {
|
|
50
|
+
const names = new Set();
|
|
51
|
+
for (const folder of folders) {
|
|
52
|
+
const files = await readdir(folder).catch(() => []);
|
|
53
|
+
for (const file of files.filter((name) => /^[^.].*(?<!\.test|\.d)\.[jt]s$/.test(name))) {
|
|
54
|
+
const text = await readFile(join(folder, file), "utf8").catch(() => "");
|
|
55
|
+
for (const match of text.matchAll(/export\s+(?:async\s+)?function\s*\*?\s*([A-Za-z_$][\w$]*)/g))
|
|
56
|
+
names.add(String(match[1]));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return names;
|
|
60
|
+
}
|
|
61
|
+
async function workflowFiles(folder) {
|
|
62
|
+
const entries = await readdir(folder, {
|
|
63
|
+
recursive: true,
|
|
64
|
+
withFileTypes: true,
|
|
65
|
+
});
|
|
66
|
+
return entries
|
|
67
|
+
.filter((entry) => entry.isFile())
|
|
68
|
+
.map((entry) => join(entry.parentPath, entry.name)
|
|
69
|
+
.slice(folder.length + 1)
|
|
70
|
+
.split("\\")
|
|
71
|
+
.join("/"))
|
|
72
|
+
.filter((file) => !descriptionFiles.includes(file))
|
|
73
|
+
.sort();
|
|
74
|
+
}
|
|
@@ -153,6 +153,7 @@ export async function retainWorkflowBundle(input) {
|
|
|
153
153
|
}
|
|
154
154
|
const temporary = await mkdtemp(join(input.directory, ".pending-"));
|
|
155
155
|
try {
|
|
156
|
+
await mkdir(join(temporary, "workflows"), { mode: 0o700 });
|
|
156
157
|
for (const { name, bytes } of files) {
|
|
157
158
|
const path = join(temporary, name);
|
|
158
159
|
await mkdir(dirname(path), { recursive: true, mode: 0o700 });
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import ts from "typescript";
|
|
2
|
-
import { protectedCall, helperCall, } from "./workflow-candidate-syntax.js";
|
|
2
|
+
import { protectedCall, commandWaitCall, helperCall, } from "./workflow-candidate-syntax.js";
|
|
3
3
|
import { propertyName } from "./workflow-candidate-fields.js";
|
|
4
4
|
import { referenceSymbol } from "./workflow-source-effects.js";
|
|
5
5
|
const zero = { knownCallCount: 0, knownUnitTotal: 0 };
|
|
@@ -218,7 +218,7 @@ function nodeTotals(node, input) {
|
|
|
218
218
|
if (local && ts.isFunctionLike(node))
|
|
219
219
|
return local;
|
|
220
220
|
let total = local ??
|
|
221
|
-
(protectedCall(node, input.symbols)
|
|
221
|
+
(protectedCall(node, input.symbols) && !commandWaitCall(node, input.symbols)
|
|
222
222
|
? { knownCallCount: 1, knownUnitTotal: units(node, input.symbols) }
|
|
223
223
|
: zero);
|
|
224
224
|
ts.forEachChild(node, (child) => {
|
|
@@ -5,9 +5,11 @@ export interface CandidatePackageOptions {
|
|
|
5
5
|
readonly helpers?: Readonly<Record<string, string>>;
|
|
6
6
|
}
|
|
7
7
|
export declare function resolvedSymbol(checker: ts.TypeChecker, symbol: ts.Symbol | undefined): ts.Symbol | undefined;
|
|
8
|
-
export
|
|
8
|
+
export interface CandidateProgram {
|
|
9
9
|
readonly program: ts.Program;
|
|
10
10
|
readonly source: ts.SourceFile;
|
|
11
11
|
readonly sources: readonly ts.SourceFile[];
|
|
12
12
|
readonly modules: ReadonlyMap<string, ts.SourceFile>;
|
|
13
|
-
}
|
|
13
|
+
}
|
|
14
|
+
export declare function candidateProgram(text: string, installed?: CandidatePackageOptions): CandidateProgram;
|
|
15
|
+
export declare function candidateCompiler(installed?: CandidatePackageOptions): (text: string) => CandidateProgram;
|
|
@@ -10,9 +10,12 @@ export function resolvedSymbol(checker, symbol) {
|
|
|
10
10
|
return checker.getAliasedSymbol(symbol);
|
|
11
11
|
}
|
|
12
12
|
export function candidateProgram(text, installed = {}) {
|
|
13
|
+
return candidateCompiler(installed)(text);
|
|
14
|
+
}
|
|
15
|
+
export function candidateCompiler(installed = {}) {
|
|
13
16
|
const packageRoot = resolve(installed.packageRoot ?? candidatePackageRoot);
|
|
14
17
|
const candidate = join(packageRoot, "candidate.ts");
|
|
15
|
-
const sources = new Map([[candidate,
|
|
18
|
+
const sources = new Map([[candidate, ""]]);
|
|
16
19
|
for (const [name, content] of Object.entries(installed.helpers ?? {})) {
|
|
17
20
|
if (workflowHelperPath("candidate.ts", `./${name}`) !== name)
|
|
18
21
|
throw new Error("invalid-workflow-helper");
|
|
@@ -32,12 +35,18 @@ export function candidateProgram(text, installed = {}) {
|
|
|
32
35
|
noEmit: true,
|
|
33
36
|
};
|
|
34
37
|
const host = trustedHost({ sources, options, entries, packageRoot });
|
|
35
|
-
|
|
36
|
-
|
|
38
|
+
return (text) => {
|
|
39
|
+
sources.set(candidate, text);
|
|
40
|
+
const program = ts.createProgram([...sources.keys(), ...entries.values()], options, host);
|
|
41
|
+
return compiledCandidate(program, { candidate, sources, entries });
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function compiledCandidate(program, input) {
|
|
45
|
+
const source = program.getSourceFile(input.candidate);
|
|
37
46
|
if (!source)
|
|
38
47
|
throw new Error("candidate-analysis-unavailable");
|
|
39
48
|
const modules = new Map();
|
|
40
|
-
for (const [name, file] of entries) {
|
|
49
|
+
for (const [name, file] of input.entries) {
|
|
41
50
|
const declaration = program.getSourceFile(file);
|
|
42
51
|
if (!declaration)
|
|
43
52
|
throw new Error("candidate-surface-unavailable");
|
|
@@ -47,7 +56,7 @@ export function candidateProgram(text, installed = {}) {
|
|
|
47
56
|
program,
|
|
48
57
|
source,
|
|
49
58
|
modules,
|
|
50
|
-
sources: [...sources.keys()].map((name) => {
|
|
59
|
+
sources: [...input.sources.keys()].map((name) => {
|
|
51
60
|
const entry = program.getSourceFile(name);
|
|
52
61
|
if (!entry)
|
|
53
62
|
throw new Error("candidate-analysis-unavailable");
|
|
@@ -55,6 +64,21 @@ export function candidateProgram(text, installed = {}) {
|
|
|
55
64
|
}),
|
|
56
65
|
};
|
|
57
66
|
}
|
|
67
|
+
function sourceReader(readFile) {
|
|
68
|
+
const declarations = new Map();
|
|
69
|
+
return (file, languageVersion) => {
|
|
70
|
+
const content = readFile(file);
|
|
71
|
+
if (content === undefined)
|
|
72
|
+
return undefined;
|
|
73
|
+
const cached = declarations.get(file);
|
|
74
|
+
if (cached?.text === content)
|
|
75
|
+
return cached;
|
|
76
|
+
const source = ts.createSourceFile(file, content, languageVersion, true);
|
|
77
|
+
if (file.endsWith(".d.ts"))
|
|
78
|
+
declarations.set(file, source);
|
|
79
|
+
return source;
|
|
80
|
+
};
|
|
81
|
+
}
|
|
58
82
|
function trustedHost(input) {
|
|
59
83
|
const { sources, options, entries, packageRoot } = input;
|
|
60
84
|
const libraries = dirname(ts.getDefaultLibFilePath(options)) + sep;
|
|
@@ -72,12 +96,7 @@ function trustedHost(input) {
|
|
|
72
96
|
const host = ts.createCompilerHost(options);
|
|
73
97
|
host.readFile = readFile;
|
|
74
98
|
host.fileExists = (file) => readFile(file) !== undefined;
|
|
75
|
-
host.getSourceFile = (
|
|
76
|
-
const content = readFile(file);
|
|
77
|
-
return content === undefined
|
|
78
|
-
? undefined
|
|
79
|
-
: ts.createSourceFile(file, content, languageVersion, true);
|
|
80
|
-
};
|
|
99
|
+
host.getSourceFile = sourceReader(readFile);
|
|
81
100
|
host.resolveModuleNameLiterals = (names, containingFile) => names.map(({ text: name }) => {
|
|
82
101
|
const installed = entries.get(name);
|
|
83
102
|
if (installed)
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import ts from "typescript";
|
|
2
|
+
export function workflowShape(source) {
|
|
3
|
+
const exported = source.statements.filter((node) => ts.isFunctionDeclaration(node) &&
|
|
4
|
+
(ts.getModifiers(node) ?? []).some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword));
|
|
5
|
+
const candidate = exported[0];
|
|
6
|
+
if (exported.length !== 1 ||
|
|
7
|
+
!candidate ||
|
|
8
|
+
!ts.isFunctionDeclaration(candidate))
|
|
9
|
+
return false;
|
|
10
|
+
if (!workflowFunction(candidate))
|
|
11
|
+
return false;
|
|
12
|
+
const directives = [];
|
|
13
|
+
function visit(node) {
|
|
14
|
+
if (ts.isStringLiteral(node) && node.text === "use workflow")
|
|
15
|
+
directives.push(node);
|
|
16
|
+
ts.forEachChild(node, visit);
|
|
17
|
+
}
|
|
18
|
+
visit(source);
|
|
19
|
+
return directives.length === 1;
|
|
20
|
+
}
|
|
21
|
+
function workflowFunction(candidate) {
|
|
22
|
+
if (!candidate.name || !candidate.body || candidate.asteriskToken)
|
|
23
|
+
return false;
|
|
24
|
+
const modifiers = ts.getModifiers(candidate) ?? [];
|
|
25
|
+
if (!modifiers.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword) ||
|
|
26
|
+
modifiers.some((modifier) => modifier.kind === ts.SyntaxKind.DefaultKeyword))
|
|
27
|
+
return false;
|
|
28
|
+
const first = candidate.body.statements[0];
|
|
29
|
+
return first !== undefined && workflowDirective(first);
|
|
30
|
+
}
|
|
31
|
+
function workflowDirective(node) {
|
|
32
|
+
return (ts.isExpressionStatement(node) &&
|
|
33
|
+
ts.isStringLiteral(node.expression) &&
|
|
34
|
+
node.expression.text === "use workflow");
|
|
35
|
+
}
|
|
36
|
+
function unwrappedInitializer(node) {
|
|
37
|
+
if (ts.isParenthesizedExpression(node) ||
|
|
38
|
+
ts.isAsExpression(node) ||
|
|
39
|
+
ts.isSatisfiesExpression(node) ||
|
|
40
|
+
ts.isTypeAssertionExpression(node))
|
|
41
|
+
return node.expression;
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
function passiveCompound(node) {
|
|
45
|
+
if (ts.isArrayLiteralExpression(node))
|
|
46
|
+
return node.elements.every((element) => ts.isOmittedExpression(element) || passiveInitializer(element));
|
|
47
|
+
if (ts.isObjectLiteralExpression(node))
|
|
48
|
+
return node.properties.every((property) => ts.isPropertyAssignment(property) &&
|
|
49
|
+
!ts.isComputedPropertyName(property.name) &&
|
|
50
|
+
passiveInitializer(property.initializer));
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
function passiveInitializer(node) {
|
|
54
|
+
if (!node)
|
|
55
|
+
return false;
|
|
56
|
+
if (ts.isLiteralExpression(node))
|
|
57
|
+
return true;
|
|
58
|
+
if ([
|
|
59
|
+
ts.SyntaxKind.TrueKeyword,
|
|
60
|
+
ts.SyntaxKind.FalseKeyword,
|
|
61
|
+
ts.SyntaxKind.NullKeyword,
|
|
62
|
+
].includes(node.kind))
|
|
63
|
+
return true;
|
|
64
|
+
if (ts.isArrowFunction(node) || ts.isFunctionExpression(node))
|
|
65
|
+
return true;
|
|
66
|
+
if (ts.isPrefixUnaryExpression(node))
|
|
67
|
+
return ([ts.SyntaxKind.PlusToken, ts.SyntaxKind.MinusToken].includes(node.operator) && ts.isNumericLiteral(node.operand));
|
|
68
|
+
const inner = unwrappedInitializer(node);
|
|
69
|
+
return inner ? passiveInitializer(inner) : passiveCompound(node);
|
|
70
|
+
}
|
|
71
|
+
function passiveStatement(node, kind) {
|
|
72
|
+
if (ts.isVariableStatement(node))
|
|
73
|
+
return ((node.declarationList.flags & ts.NodeFlags.Const) !== 0 &&
|
|
74
|
+
node.declarationList.declarations.every((declaration) => (kind === "helper" ||
|
|
75
|
+
(ts.getCombinedModifierFlags(declaration) &
|
|
76
|
+
ts.ModifierFlags.Export) ===
|
|
77
|
+
0) &&
|
|
78
|
+
ts.isIdentifier(declaration.name) &&
|
|
79
|
+
passiveInitializer(declaration.initializer)));
|
|
80
|
+
if (ts.isExpressionStatement(node))
|
|
81
|
+
return ts.isStringLiteral(node.expression);
|
|
82
|
+
return (ts.isImportDeclaration(node) ||
|
|
83
|
+
ts.isTypeAliasDeclaration(node) ||
|
|
84
|
+
ts.isInterfaceDeclaration(node) ||
|
|
85
|
+
ts.isFunctionDeclaration(node) ||
|
|
86
|
+
ts.isEmptyStatement(node));
|
|
87
|
+
}
|
|
88
|
+
export function passiveCandidateModule(source, kind = "workflow") {
|
|
89
|
+
return source.statements.every((node) => passiveStatement(node, kind));
|
|
90
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type CandidatePackageOptions } from "./workflow-candidate-program.ts";
|
|
2
2
|
import type { CandidateAnalysis, InstalledWorkflowExports } from "../src/workflow-candidate.ts";
|
|
3
|
+
export declare function createWorkflowCandidateAnalyzer(installed?: CandidatePackageOptions): (text: string) => ReturnType<typeof analyzeWorkflowCandidate>;
|
|
3
4
|
export declare function analyzeWorkflowCandidate(text: string, installed?: CandidatePackageOptions): {
|
|
4
5
|
readonly analysis: CandidateAnalysis;
|
|
5
6
|
readonly installedExports: InstalledWorkflowExports;
|