@matteeh/osq 0.1.0 → 0.2.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 +415 -72
- package/dist/cli/approve.d.ts +13 -3
- package/dist/cli/approve.d.ts.map +1 -1
- package/dist/cli/approve.js +59 -4
- package/dist/cli/approve.js.map +1 -1
- package/dist/cli/bin.js +0 -0
- package/dist/cli/confirm.d.ts +21 -0
- package/dist/cli/confirm.d.ts.map +1 -0
- package/dist/cli/confirm.js +28 -0
- package/dist/cli/confirm.js.map +1 -0
- package/dist/cli/doctor.d.ts +13 -0
- package/dist/cli/doctor.d.ts.map +1 -0
- package/dist/cli/doctor.js +23 -0
- package/dist/cli/doctor.js.map +1 -0
- package/dist/cli/done.d.ts +12 -0
- package/dist/cli/done.d.ts.map +1 -0
- package/dist/cli/done.js +26 -0
- package/dist/cli/done.js.map +1 -0
- package/dist/cli/inbox.d.ts +22 -0
- package/dist/cli/inbox.d.ts.map +1 -0
- package/dist/cli/inbox.js +41 -0
- package/dist/cli/inbox.js.map +1 -0
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +127 -8
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/init.d.ts +1 -0
- package/dist/cli/init.d.ts.map +1 -1
- package/dist/cli/init.js +9 -3
- package/dist/cli/init.js.map +1 -1
- package/dist/cli/lint.d.ts +26 -0
- package/dist/cli/lint.d.ts.map +1 -0
- package/dist/cli/lint.js +60 -0
- package/dist/cli/lint.js.map +1 -0
- package/dist/cli/migrate.d.ts +18 -0
- package/dist/cli/migrate.d.ts.map +1 -0
- package/dist/cli/migrate.js +42 -0
- package/dist/cli/migrate.js.map +1 -0
- package/dist/cli/new.js +1 -1
- package/dist/cli/new.js.map +1 -1
- package/dist/cli/plan-queue.d.ts +50 -0
- package/dist/cli/plan-queue.d.ts.map +1 -0
- package/dist/cli/plan-queue.js +167 -0
- package/dist/cli/plan-queue.js.map +1 -0
- package/dist/cli/plan.d.ts +35 -0
- package/dist/cli/plan.d.ts.map +1 -0
- package/dist/cli/plan.js +153 -0
- package/dist/cli/plan.js.map +1 -0
- package/dist/cli/queue.d.ts +9 -0
- package/dist/cli/queue.d.ts.map +1 -0
- package/dist/cli/queue.js +24 -0
- package/dist/cli/queue.js.map +1 -0
- package/dist/cli/reject.d.ts +8 -0
- package/dist/cli/reject.d.ts.map +1 -0
- package/dist/cli/reject.js +18 -0
- package/dist/cli/reject.js.map +1 -0
- package/dist/cli/report.d.ts +1 -1
- package/dist/cli/report.d.ts.map +1 -1
- package/dist/cli/report.js +141 -14
- package/dist/cli/report.js.map +1 -1
- package/dist/cli/retry.d.ts +7 -0
- package/dist/cli/retry.d.ts.map +1 -0
- package/dist/cli/retry.js +29 -0
- package/dist/cli/retry.js.map +1 -0
- package/dist/cli/serve.d.ts +30 -0
- package/dist/cli/serve.d.ts.map +1 -0
- package/dist/cli/serve.js +136 -0
- package/dist/cli/serve.js.map +1 -0
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +7 -1
- package/dist/cli/setup.js.map +1 -1
- package/dist/cli/show.d.ts +2 -1
- package/dist/cli/show.d.ts.map +1 -1
- package/dist/cli/show.js +20 -3
- package/dist/cli/show.js.map +1 -1
- package/dist/cli/status.d.ts +1 -1
- package/dist/cli/status.d.ts.map +1 -1
- package/dist/cli/status.js +2 -2
- package/dist/cli/status.js.map +1 -1
- package/dist/cli/watch.d.ts +9 -6
- package/dist/cli/watch.d.ts.map +1 -1
- package/dist/cli/watch.js +15 -2
- package/dist/cli/watch.js.map +1 -1
- package/dist/core/foundation/config-codex.d.ts +22 -0
- package/dist/core/foundation/config-codex.d.ts.map +1 -0
- package/dist/core/foundation/config-codex.js +58 -0
- package/dist/core/foundation/config-codex.js.map +1 -0
- package/dist/core/foundation/config-doctor.d.ts +14 -0
- package/dist/core/foundation/config-doctor.d.ts.map +1 -0
- package/dist/core/foundation/config-doctor.js +29 -0
- package/dist/core/foundation/config-doctor.js.map +1 -0
- package/dist/core/foundation/config-env.d.ts +3 -0
- package/dist/core/foundation/config-env.d.ts.map +1 -0
- package/dist/core/foundation/config-env.js +22 -0
- package/dist/core/foundation/config-env.js.map +1 -0
- package/dist/core/foundation/config-gates.d.ts +22 -0
- package/dist/core/foundation/config-gates.d.ts.map +1 -0
- package/dist/core/foundation/config-gates.js +43 -0
- package/dist/core/foundation/config-gates.js.map +1 -0
- package/dist/core/foundation/config-pi.d.ts +64 -0
- package/dist/core/foundation/config-pi.d.ts.map +1 -0
- package/dist/core/foundation/config-pi.js +131 -0
- package/dist/core/foundation/config-pi.js.map +1 -0
- package/dist/core/foundation/config-planning.d.ts +24 -0
- package/dist/core/foundation/config-planning.d.ts.map +1 -0
- package/dist/core/foundation/config-planning.js +60 -0
- package/dist/core/foundation/config-planning.js.map +1 -0
- package/dist/core/foundation/config-queue.d.ts +15 -0
- package/dist/core/foundation/config-queue.d.ts.map +1 -0
- package/dist/core/foundation/config-queue.js +24 -0
- package/dist/core/foundation/config-queue.js.map +1 -0
- package/dist/core/foundation/config-serve.d.ts +20 -0
- package/dist/core/foundation/config-serve.d.ts.map +1 -0
- package/dist/core/foundation/config-serve.js +35 -0
- package/dist/core/foundation/config-serve.js.map +1 -0
- package/dist/core/{config.d.ts → foundation/config.d.ts} +34 -3
- package/dist/core/foundation/config.d.ts.map +1 -0
- package/dist/core/{config.js → foundation/config.js} +35 -18
- package/dist/core/foundation/config.js.map +1 -0
- package/dist/core/foundation/doctor-managed.d.ts +13 -0
- package/dist/core/foundation/doctor-managed.d.ts.map +1 -0
- package/dist/core/foundation/doctor-managed.js +77 -0
- package/dist/core/foundation/doctor-managed.js.map +1 -0
- package/dist/core/foundation/doctor.d.ts +19 -0
- package/dist/core/foundation/doctor.d.ts.map +1 -0
- package/dist/core/foundation/doctor.js +187 -0
- package/dist/core/foundation/doctor.js.map +1 -0
- package/dist/core/foundation/harness-catalog.d.ts +96 -0
- package/dist/core/foundation/harness-catalog.d.ts.map +1 -0
- package/dist/core/foundation/harness-catalog.js +182 -0
- package/dist/core/foundation/harness-catalog.js.map +1 -0
- package/dist/core/foundation/init-blocks.d.ts +33 -0
- package/dist/core/foundation/init-blocks.d.ts.map +1 -0
- package/dist/core/foundation/init-blocks.js +165 -0
- package/dist/core/foundation/init-blocks.js.map +1 -0
- package/dist/core/foundation/init-managed.d.ts +10 -0
- package/dist/core/foundation/init-managed.d.ts.map +1 -0
- package/dist/core/foundation/init-managed.js +115 -0
- package/dist/core/foundation/init-managed.js.map +1 -0
- package/dist/core/foundation/init.d.ts +18 -0
- package/dist/core/foundation/init.d.ts.map +1 -0
- package/dist/core/foundation/init.js +113 -0
- package/dist/core/foundation/init.js.map +1 -0
- package/dist/core/{logger.d.ts → foundation/logger.d.ts} +1 -0
- package/dist/core/foundation/logger.d.ts.map +1 -0
- package/dist/core/{logger.js → foundation/logger.js} +18 -2
- package/dist/core/foundation/logger.js.map +1 -0
- package/dist/core/{new.d.ts → foundation/new.d.ts} +3 -0
- package/dist/core/foundation/new.d.ts.map +1 -0
- package/dist/core/foundation/new.js +206 -0
- package/dist/core/foundation/new.js.map +1 -0
- package/dist/core/foundation/package-root.d.ts +9 -0
- package/dist/core/foundation/package-root.d.ts.map +1 -0
- package/dist/core/foundation/package-root.js +11 -0
- package/dist/core/foundation/package-root.js.map +1 -0
- package/dist/core/lifecycle/done.d.ts +17 -0
- package/dist/core/lifecycle/done.d.ts.map +1 -0
- package/dist/core/lifecycle/done.js +97 -0
- package/dist/core/lifecycle/done.js.map +1 -0
- package/dist/core/lifecycle/reject.d.ts +26 -0
- package/dist/core/lifecycle/reject.d.ts.map +1 -0
- package/dist/core/lifecycle/reject.js +83 -0
- package/dist/core/lifecycle/reject.js.map +1 -0
- package/dist/core/lifecycle/retry-transition.d.ts +23 -0
- package/dist/core/lifecycle/retry-transition.d.ts.map +1 -0
- package/dist/core/lifecycle/retry-transition.js +41 -0
- package/dist/core/lifecycle/retry-transition.js.map +1 -0
- package/dist/core/lifecycle/retry.d.ts +18 -0
- package/dist/core/lifecycle/retry.d.ts.map +1 -0
- package/dist/core/lifecycle/retry.js +179 -0
- package/dist/core/lifecycle/retry.js.map +1 -0
- package/dist/core/report/approval-flags.d.ts +29 -0
- package/dist/core/report/approval-flags.d.ts.map +1 -0
- package/dist/core/report/approval-flags.js +138 -0
- package/dist/core/report/approval-flags.js.map +1 -0
- package/dist/core/report/planning-economics.d.ts +39 -0
- package/dist/core/report/planning-economics.d.ts.map +1 -0
- package/dist/core/report/planning-economics.js +168 -0
- package/dist/core/report/planning-economics.js.map +1 -0
- package/dist/core/report/planning-observed.d.ts +59 -0
- package/dist/core/report/planning-observed.d.ts.map +1 -0
- package/dist/core/report/planning-observed.js +135 -0
- package/dist/core/report/planning-observed.js.map +1 -0
- package/dist/core/report/planning-records.d.ts +69 -0
- package/dist/core/report/planning-records.d.ts.map +1 -0
- package/dist/core/report/planning-records.js +149 -0
- package/dist/core/report/planning-records.js.map +1 -0
- package/dist/core/report/planning-slice-lookup.d.ts +13 -0
- package/dist/core/report/planning-slice-lookup.d.ts.map +1 -0
- package/dist/core/report/planning-slice-lookup.js +146 -0
- package/dist/core/report/planning-slice-lookup.js.map +1 -0
- package/dist/core/report/planning-slice-measures.d.ts +17 -0
- package/dist/core/report/planning-slice-measures.d.ts.map +1 -0
- package/dist/core/report/planning-slice-measures.js +85 -0
- package/dist/core/report/planning-slice-measures.js.map +1 -0
- package/dist/core/report/planning-slice-record.d.ts +4 -0
- package/dist/core/report/planning-slice-record.d.ts.map +1 -0
- package/dist/core/report/planning-slice-record.js +66 -0
- package/dist/core/report/planning-slice-record.js.map +1 -0
- package/dist/core/report/planning-slice-turns.d.ts +13 -0
- package/dist/core/report/planning-slice-turns.d.ts.map +1 -0
- package/dist/core/report/planning-slice-turns.js +41 -0
- package/dist/core/report/planning-slice-turns.js.map +1 -0
- package/dist/core/report/planning-slice.d.ts +70 -0
- package/dist/core/report/planning-slice.d.ts.map +1 -0
- package/dist/core/report/planning-slice.js +147 -0
- package/dist/core/report/planning-slice.js.map +1 -0
- package/dist/core/report/planning.d.ts +31 -0
- package/dist/core/report/planning.d.ts.map +1 -0
- package/dist/core/report/planning.js +75 -0
- package/dist/core/report/planning.js.map +1 -0
- package/dist/core/report/report-events.d.ts +52 -0
- package/dist/core/report/report-events.d.ts.map +1 -0
- package/dist/core/report/report-events.js +198 -0
- package/dist/core/report/report-events.js.map +1 -0
- package/dist/core/report/report-pre-spawn.d.ts +25 -0
- package/dist/core/report/report-pre-spawn.d.ts.map +1 -0
- package/dist/core/report/report-pre-spawn.js +40 -0
- package/dist/core/report/report-pre-spawn.js.map +1 -0
- package/dist/core/report/report-retries.d.ts +30 -0
- package/dist/core/report/report-retries.d.ts.map +1 -0
- package/dist/core/report/report-retries.js +100 -0
- package/dist/core/report/report-retries.js.map +1 -0
- package/dist/core/report/report.d.ts +276 -0
- package/dist/core/report/report.d.ts.map +1 -0
- package/dist/core/report/report.js +1421 -0
- package/dist/core/report/report.js.map +1 -0
- package/dist/core/{lock.d.ts → run/lock.d.ts} +6 -0
- package/dist/core/run/lock.d.ts.map +1 -0
- package/dist/core/{lock.js → run/lock.js} +7 -15
- package/dist/core/run/lock.js.map +1 -0
- package/dist/core/run/manifest.d.ts +39 -0
- package/dist/core/run/manifest.d.ts.map +1 -0
- package/dist/core/run/manifest.js +137 -0
- package/dist/core/run/manifest.js.map +1 -0
- package/dist/core/run/scope-hash.d.ts +71 -0
- package/dist/core/run/scope-hash.d.ts.map +1 -0
- package/dist/core/run/scope-hash.js +177 -0
- package/dist/core/run/scope-hash.js.map +1 -0
- package/dist/core/run/scope.d.ts +30 -0
- package/dist/core/run/scope.d.ts.map +1 -0
- package/dist/core/run/scope.js +193 -0
- package/dist/core/run/scope.js.map +1 -0
- package/dist/core/run/summary.d.ts +8 -0
- package/dist/core/run/summary.d.ts.map +1 -0
- package/dist/core/run/summary.js +25 -0
- package/dist/core/run/summary.js.map +1 -0
- package/dist/core/run/verification.d.ts +23 -0
- package/dist/core/run/verification.d.ts.map +1 -0
- package/dist/core/run/verification.js +78 -0
- package/dist/core/run/verification.js.map +1 -0
- package/dist/core/spec/approve.d.ts +31 -0
- package/dist/core/spec/approve.d.ts.map +1 -0
- package/dist/core/spec/approve.js +111 -0
- package/dist/core/spec/approve.js.map +1 -0
- package/dist/core/spec/delta.d.ts +77 -0
- package/dist/core/spec/delta.d.ts.map +1 -0
- package/dist/core/spec/delta.js +581 -0
- package/dist/core/spec/delta.js.map +1 -0
- package/dist/core/spec/digest-flags.d.ts +21 -0
- package/dist/core/spec/digest-flags.d.ts.map +1 -0
- package/dist/core/spec/digest-flags.js +194 -0
- package/dist/core/spec/digest-flags.js.map +1 -0
- package/dist/core/spec/digest-verify-starts.d.ts +5 -0
- package/dist/core/spec/digest-verify-starts.d.ts.map +1 -0
- package/dist/core/spec/digest-verify-starts.js +31 -0
- package/dist/core/spec/digest-verify-starts.js.map +1 -0
- package/dist/core/spec/digest.d.ts +42 -0
- package/dist/core/spec/digest.d.ts.map +1 -0
- package/dist/core/spec/digest.js +170 -0
- package/dist/core/spec/digest.js.map +1 -0
- package/dist/core/spec/hasher.d.ts +11 -0
- package/dist/core/spec/hasher.d.ts.map +1 -0
- package/dist/core/{hasher.js → spec/hasher.js} +27 -3
- package/dist/core/spec/hasher.js.map +1 -0
- package/dist/core/spec/linter.d.ts +79 -0
- package/dist/core/spec/linter.d.ts.map +1 -0
- package/dist/core/spec/linter.js +826 -0
- package/dist/core/spec/linter.js.map +1 -0
- package/dist/core/spec/migrate.d.ts +54 -0
- package/dist/core/spec/migrate.d.ts.map +1 -0
- package/dist/core/spec/migrate.js +297 -0
- package/dist/core/spec/migrate.js.map +1 -0
- package/dist/core/spec/openspec-version.d.ts +30 -0
- package/dist/core/spec/openspec-version.d.ts.map +1 -0
- package/dist/core/spec/openspec-version.js +118 -0
- package/dist/core/spec/openspec-version.js.map +1 -0
- package/dist/core/spec/parser.d.ts +82 -0
- package/dist/core/spec/parser.d.ts.map +1 -0
- package/dist/core/spec/parser.js +221 -0
- package/dist/core/spec/parser.js.map +1 -0
- package/dist/core/spec/verify-paths.d.ts +18 -0
- package/dist/core/spec/verify-paths.d.ts.map +1 -0
- package/dist/core/spec/verify-paths.js +139 -0
- package/dist/core/spec/verify-paths.js.map +1 -0
- package/dist/core/spec/verify-starts.d.ts +45 -0
- package/dist/core/spec/verify-starts.d.ts.map +1 -0
- package/dist/core/spec/verify-starts.js +61 -0
- package/dist/core/spec/verify-starts.js.map +1 -0
- package/dist/core/status/inbox-cursor.d.ts +10 -0
- package/dist/core/status/inbox-cursor.d.ts.map +1 -0
- package/dist/core/status/inbox-cursor.js +33 -0
- package/dist/core/status/inbox-cursor.js.map +1 -0
- package/dist/core/status/inbox-projection.d.ts +15 -0
- package/dist/core/status/inbox-projection.d.ts.map +1 -0
- package/dist/core/status/inbox-projection.js +20 -0
- package/dist/core/status/inbox-projection.js.map +1 -0
- package/dist/core/status/inbox-text.d.ts +4 -0
- package/dist/core/status/inbox-text.d.ts.map +1 -0
- package/dist/core/status/inbox-text.js +48 -0
- package/dist/core/status/inbox-text.js.map +1 -0
- package/dist/core/status/inbox.d.ts +53 -0
- package/dist/core/status/inbox.d.ts.map +1 -0
- package/dist/core/status/inbox.js +167 -0
- package/dist/core/status/inbox.js.map +1 -0
- package/dist/core/status/layout.d.ts +29 -0
- package/dist/core/status/layout.d.ts.map +1 -0
- package/dist/core/status/layout.js +77 -0
- package/dist/core/status/layout.js.map +1 -0
- package/dist/core/status/queue-parser.d.ts +13 -0
- package/dist/core/status/queue-parser.d.ts.map +1 -0
- package/dist/core/status/queue-parser.js +88 -0
- package/dist/core/status/queue-parser.js.map +1 -0
- package/dist/core/status/queue-planning.d.ts +62 -0
- package/dist/core/status/queue-planning.d.ts.map +1 -0
- package/dist/core/status/queue-planning.js +158 -0
- package/dist/core/status/queue-planning.js.map +1 -0
- package/dist/core/status/queue-report-detail.d.ts +50 -0
- package/dist/core/status/queue-report-detail.d.ts.map +1 -0
- package/dist/core/status/queue-report-detail.js +140 -0
- package/dist/core/status/queue-report-detail.js.map +1 -0
- package/dist/core/status/queue-report.d.ts +14 -0
- package/dist/core/status/queue-report.d.ts.map +1 -0
- package/dist/core/status/queue-report.js +41 -0
- package/dist/core/status/queue-report.js.map +1 -0
- package/dist/core/status/queue-state.d.ts +53 -0
- package/dist/core/status/queue-state.d.ts.map +1 -0
- package/dist/core/status/queue-state.js +167 -0
- package/dist/core/status/queue-state.js.map +1 -0
- package/dist/core/status/queue.d.ts +7 -0
- package/dist/core/status/queue.d.ts.map +1 -0
- package/dist/core/status/queue.js +4 -0
- package/dist/core/status/queue.js.map +1 -0
- package/dist/core/status/show.d.ts +102 -0
- package/dist/core/status/show.d.ts.map +1 -0
- package/dist/core/status/show.js +704 -0
- package/dist/core/status/show.js.map +1 -0
- package/dist/core/status/state.d.ts +56 -0
- package/dist/core/status/state.d.ts.map +1 -0
- package/dist/core/status/state.js +187 -0
- package/dist/core/status/state.js.map +1 -0
- package/dist/core/status/status.d.ts +23 -0
- package/dist/core/status/status.d.ts.map +1 -0
- package/dist/core/status/status.js +173 -0
- package/dist/core/status/status.js.map +1 -0
- package/dist/core/web/web-data-change.d.ts +10 -0
- package/dist/core/web/web-data-change.d.ts.map +1 -0
- package/dist/core/web/web-data-change.js +106 -0
- package/dist/core/web/web-data-change.js.map +1 -0
- package/dist/core/web/web-data-folders.d.ts +39 -0
- package/dist/core/web/web-data-folders.d.ts.map +1 -0
- package/dist/core/web/web-data-folders.js +125 -0
- package/dist/core/web/web-data-folders.js.map +1 -0
- package/dist/core/web/web-data-graph.d.ts +8 -0
- package/dist/core/web/web-data-graph.d.ts.map +1 -0
- package/dist/core/web/web-data-graph.js +113 -0
- package/dist/core/web/web-data-graph.js.map +1 -0
- package/dist/core/web/web-data-lifecycle.d.ts +43 -0
- package/dist/core/web/web-data-lifecycle.d.ts.map +1 -0
- package/dist/core/web/web-data-lifecycle.js +141 -0
- package/dist/core/web/web-data-lifecycle.js.map +1 -0
- package/dist/core/web/web-data-observations.d.ts +30 -0
- package/dist/core/web/web-data-observations.d.ts.map +1 -0
- package/dist/core/web/web-data-observations.js +181 -0
- package/dist/core/web/web-data-observations.js.map +1 -0
- package/dist/core/web/web-data-tokens.d.ts +29 -0
- package/dist/core/web/web-data-tokens.d.ts.map +1 -0
- package/dist/core/web/web-data-tokens.js +62 -0
- package/dist/core/web/web-data-tokens.js.map +1 -0
- package/dist/core/web/web-data-types.d.ts +156 -0
- package/dist/core/web/web-data-types.d.ts.map +1 -0
- package/dist/core/web/web-data-types.js +15 -0
- package/dist/core/web/web-data-types.js.map +1 -0
- package/dist/core/web/web-data.d.ts +10 -0
- package/dist/core/web/web-data.d.ts.map +1 -0
- package/dist/core/web/web-data.js +8 -0
- package/dist/core/web/web-data.js.map +1 -0
- package/dist/core/web/web-events.d.ts +54 -0
- package/dist/core/web/web-events.d.ts.map +1 -0
- package/dist/core/web/web-events.js +162 -0
- package/dist/core/web/web-events.js.map +1 -0
- package/dist/core/web/web-export.d.ts +18 -0
- package/dist/core/web/web-export.d.ts.map +1 -0
- package/dist/core/web/web-export.js +112 -0
- package/dist/core/web/web-export.js.map +1 -0
- package/dist/core/web/web-server.d.ts +34 -0
- package/dist/core/web/web-server.d.ts.map +1 -0
- package/dist/core/web/web-server.js +182 -0
- package/dist/core/web/web-server.js.map +1 -0
- package/dist/core/web/web-static.d.ts +20 -0
- package/dist/core/web/web-static.d.ts.map +1 -0
- package/dist/core/web/web-static.js +104 -0
- package/dist/core/web/web-static.js.map +1 -0
- package/dist/harness/{agy.d.ts → agy/agy.d.ts} +8 -6
- package/dist/harness/agy/agy.d.ts.map +1 -0
- package/dist/harness/{agy.js → agy/agy.js} +49 -34
- package/dist/harness/agy/agy.js.map +1 -0
- package/dist/harness/claude/claude-turns.d.ts +29 -0
- package/dist/harness/claude/claude-turns.d.ts.map +1 -0
- package/dist/harness/claude/claude-turns.js +162 -0
- package/dist/harness/claude/claude-turns.js.map +1 -0
- package/dist/harness/claude/claude-usage.d.ts +12 -0
- package/dist/harness/claude/claude-usage.d.ts.map +1 -0
- package/dist/harness/claude/claude-usage.js +144 -0
- package/dist/harness/claude/claude-usage.js.map +1 -0
- package/dist/harness/codex/codex-observe-usage.d.ts +6 -0
- package/dist/harness/codex/codex-observe-usage.d.ts.map +1 -0
- package/dist/harness/codex/codex-observe-usage.js +215 -0
- package/dist/harness/codex/codex-observe-usage.js.map +1 -0
- package/dist/harness/codex/codex-prompt.d.ts +17 -0
- package/dist/harness/codex/codex-prompt.d.ts.map +1 -0
- package/dist/harness/codex/codex-prompt.js +43 -0
- package/dist/harness/codex/codex-prompt.js.map +1 -0
- package/dist/harness/codex/codex-stream.d.ts +23 -0
- package/dist/harness/codex/codex-stream.d.ts.map +1 -0
- package/dist/harness/codex/codex-stream.js +182 -0
- package/dist/harness/codex/codex-stream.js.map +1 -0
- package/dist/harness/codex/codex-usage.d.ts +26 -0
- package/dist/harness/codex/codex-usage.d.ts.map +1 -0
- package/dist/harness/codex/codex-usage.js +122 -0
- package/dist/harness/codex/codex-usage.js.map +1 -0
- package/dist/harness/codex/codex.d.ts +16 -0
- package/dist/harness/codex/codex.d.ts.map +1 -0
- package/dist/harness/codex/codex.js +92 -0
- package/dist/harness/codex/codex.js.map +1 -0
- package/dist/harness/index.d.ts +11 -2
- package/dist/harness/index.d.ts.map +1 -1
- package/dist/harness/index.js +24 -9
- package/dist/harness/index.js.map +1 -1
- package/dist/harness/mock.d.ts +5 -2
- package/dist/harness/mock.d.ts.map +1 -1
- package/dist/harness/mock.js +10 -11
- package/dist/harness/mock.js.map +1 -1
- package/dist/harness/opencode/opencode-observe-usage.d.ts +4 -0
- package/dist/harness/opencode/opencode-observe-usage.d.ts.map +1 -0
- package/dist/harness/opencode/opencode-observe-usage.js +100 -0
- package/dist/harness/opencode/opencode-observe-usage.js.map +1 -0
- package/dist/harness/opencode/opencode-usage.d.ts +24 -0
- package/dist/harness/opencode/opencode-usage.d.ts.map +1 -0
- package/dist/harness/opencode/opencode-usage.js +181 -0
- package/dist/harness/opencode/opencode-usage.js.map +1 -0
- package/dist/harness/{opencode.d.ts → opencode/opencode.d.ts} +10 -7
- package/dist/harness/opencode/opencode.d.ts.map +1 -0
- package/dist/harness/{opencode.js → opencode/opencode.js} +159 -70
- package/dist/harness/opencode/opencode.js.map +1 -0
- package/dist/harness/pi/pi-args.d.ts +9 -0
- package/dist/harness/pi/pi-args.d.ts.map +1 -0
- package/dist/harness/pi/pi-args.js +33 -0
- package/dist/harness/pi/pi-args.js.map +1 -0
- package/dist/harness/pi/pi-stream.d.ts +27 -0
- package/dist/harness/pi/pi-stream.d.ts.map +1 -0
- package/dist/harness/pi/pi-stream.js +176 -0
- package/dist/harness/pi/pi-stream.js.map +1 -0
- package/dist/harness/pi/pi-tools.d.ts +5 -0
- package/dist/harness/pi/pi-tools.d.ts.map +1 -0
- package/dist/harness/pi/pi-tools.js +31 -0
- package/dist/harness/pi/pi-tools.js.map +1 -0
- package/dist/harness/pi/pi.d.ts +11 -0
- package/dist/harness/pi/pi.d.ts.map +1 -0
- package/dist/harness/pi/pi.js +109 -0
- package/dist/harness/pi/pi.js.map +1 -0
- package/dist/harness/prompt.d.ts +11 -0
- package/dist/harness/prompt.d.ts.map +1 -0
- package/dist/harness/prompt.js +105 -0
- package/dist/harness/prompt.js.map +1 -0
- package/dist/harness/types.d.ts +287 -8
- package/dist/harness/types.d.ts.map +1 -1
- package/dist/harness/types.js +125 -0
- package/dist/harness/types.js.map +1 -1
- package/dist/index.d.ts +13 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -1
- package/dist/index.js.map +1 -1
- package/dist/watcher/archive-verify.d.ts +9 -0
- package/dist/watcher/archive-verify.d.ts.map +1 -0
- package/dist/watcher/archive-verify.js +80 -0
- package/dist/watcher/archive-verify.js.map +1 -0
- package/dist/watcher/archiver.d.ts +14 -2
- package/dist/watcher/archiver.d.ts.map +1 -1
- package/dist/watcher/archiver.js +112 -33
- package/dist/watcher/archiver.js.map +1 -1
- package/dist/watcher/attempt.d.ts +19 -0
- package/dist/watcher/attempt.d.ts.map +1 -0
- package/dist/watcher/attempt.js +94 -0
- package/dist/watcher/attempt.js.map +1 -0
- package/dist/watcher/auto-retry.d.ts +11 -0
- package/dist/watcher/auto-retry.d.ts.map +1 -0
- package/dist/watcher/auto-retry.js +180 -0
- package/dist/watcher/auto-retry.js.map +1 -0
- package/dist/watcher/build.d.ts +24 -0
- package/dist/watcher/build.d.ts.map +1 -0
- package/dist/watcher/build.js +169 -0
- package/dist/watcher/build.js.map +1 -0
- package/dist/watcher/change-verify.d.ts +25 -0
- package/dist/watcher/change-verify.d.ts.map +1 -0
- package/dist/watcher/change-verify.js +57 -0
- package/dist/watcher/change-verify.js.map +1 -0
- package/dist/watcher/dev.d.ts +51 -0
- package/dist/watcher/dev.d.ts.map +1 -0
- package/dist/watcher/dev.js +124 -0
- package/dist/watcher/dev.js.map +1 -0
- package/dist/watcher/failure-reason.d.ts +7 -0
- package/dist/watcher/failure-reason.d.ts.map +1 -0
- package/dist/watcher/failure-reason.js +2 -0
- package/dist/watcher/failure-reason.js.map +1 -0
- package/dist/watcher/fingerprint.d.ts +19 -0
- package/dist/watcher/fingerprint.d.ts.map +1 -0
- package/dist/watcher/fingerprint.js +53 -0
- package/dist/watcher/fingerprint.js.map +1 -0
- package/dist/watcher/heartbeat.d.ts +33 -0
- package/dist/watcher/heartbeat.d.ts.map +1 -0
- package/dist/watcher/heartbeat.js +135 -0
- package/dist/watcher/heartbeat.js.map +1 -0
- package/dist/watcher/lock.d.ts +10 -0
- package/dist/watcher/lock.d.ts.map +1 -0
- package/dist/watcher/lock.js +14 -0
- package/dist/watcher/lock.js.map +1 -0
- package/dist/watcher/loop.d.ts +26 -6
- package/dist/watcher/loop.d.ts.map +1 -1
- package/dist/watcher/loop.js +154 -37
- package/dist/watcher/loop.js.map +1 -1
- package/dist/watcher/measures.d.ts +46 -0
- package/dist/watcher/measures.d.ts.map +1 -0
- package/dist/watcher/measures.js +203 -0
- package/dist/watcher/measures.js.map +1 -0
- package/dist/watcher/outcome.d.ts +32 -0
- package/dist/watcher/outcome.d.ts.map +1 -0
- package/dist/watcher/outcome.js +127 -0
- package/dist/watcher/outcome.js.map +1 -0
- package/dist/watcher/regression.d.ts +43 -0
- package/dist/watcher/regression.d.ts.map +1 -0
- package/dist/watcher/regression.js +175 -0
- package/dist/watcher/regression.js.map +1 -0
- package/dist/watcher/runner.d.ts +6 -68
- package/dist/watcher/runner.d.ts.map +1 -1
- package/dist/watcher/runner.js +74 -523
- package/dist/watcher/runner.js.map +1 -1
- package/dist/watcher/spawn.d.ts +48 -0
- package/dist/watcher/spawn.d.ts.map +1 -0
- package/dist/watcher/spawn.js +130 -0
- package/dist/watcher/spawn.js.map +1 -0
- package/dist/watcher/task-verify.d.ts +59 -0
- package/dist/watcher/task-verify.d.ts.map +1 -0
- package/dist/watcher/task-verify.js +108 -0
- package/dist/watcher/task-verify.js.map +1 -0
- package/dist/watcher/verify.d.ts +44 -0
- package/dist/watcher/verify.d.ts.map +1 -0
- package/dist/watcher/verify.js +156 -0
- package/dist/watcher/verify.js.map +1 -0
- package/package.json +21 -9
- package/templates/PLANNER.md +77 -0
- package/templates/openspec/config.yaml +24 -0
- package/templates/openspec/schemas/osq/README.md +30 -0
- package/templates/openspec/schemas/osq/schema.yaml +133 -0
- package/templates/openspec/schemas/osq/templates/proposal.md +66 -0
- package/templates/openspec/schemas/osq/templates/spec.md +13 -0
- package/templates/openspec/schemas/osq/templates/tasks.md +11 -0
- package/templates/proposal.md +66 -0
- package/templates/tasks.md +5 -0
- package/ui/dist/assets/index-CZYeQ8la.js +9 -0
- package/ui/dist/assets/index-D6zVSjO7.css +1 -0
- package/ui/dist/index.html +14 -0
- package/dist/core/approve.d.ts +0 -11
- package/dist/core/approve.d.ts.map +0 -1
- package/dist/core/approve.js +0 -52
- package/dist/core/approve.js.map +0 -1
- package/dist/core/config.d.ts.map +0 -1
- package/dist/core/config.js.map +0 -1
- package/dist/core/hasher.d.ts +0 -4
- package/dist/core/hasher.d.ts.map +0 -1
- package/dist/core/hasher.js.map +0 -1
- package/dist/core/init.d.ts +0 -12
- package/dist/core/init.d.ts.map +0 -1
- package/dist/core/init.js +0 -151
- package/dist/core/init.js.map +0 -1
- package/dist/core/linter.d.ts +0 -8
- package/dist/core/linter.d.ts.map +0 -1
- package/dist/core/linter.js +0 -100
- package/dist/core/linter.js.map +0 -1
- package/dist/core/lock.d.ts.map +0 -1
- package/dist/core/lock.js.map +0 -1
- package/dist/core/logger.d.ts.map +0 -1
- package/dist/core/logger.js.map +0 -1
- package/dist/core/new.d.ts.map +0 -1
- package/dist/core/new.js +0 -79
- package/dist/core/new.js.map +0 -1
- package/dist/core/parser.d.ts +0 -32
- package/dist/core/parser.d.ts.map +0 -1
- package/dist/core/parser.js +0 -87
- package/dist/core/parser.js.map +0 -1
- package/dist/core/report.d.ts +0 -54
- package/dist/core/report.d.ts.map +0 -1
- package/dist/core/report.js +0 -475
- package/dist/core/report.js.map +0 -1
- package/dist/core/show.d.ts +0 -50
- package/dist/core/show.d.ts.map +0 -1
- package/dist/core/show.js +0 -374
- package/dist/core/show.js.map +0 -1
- package/dist/core/state.d.ts +0 -25
- package/dist/core/state.d.ts.map +0 -1
- package/dist/core/state.js +0 -180
- package/dist/core/state.js.map +0 -1
- package/dist/core/status.d.ts +0 -10
- package/dist/core/status.d.ts.map +0 -1
- package/dist/core/status.js +0 -106
- package/dist/core/status.js.map +0 -1
- package/dist/harness/agy.d.ts.map +0 -1
- package/dist/harness/agy.js.map +0 -1
- package/dist/harness/opencode.d.ts.map +0 -1
- package/dist/harness/opencode.js.map +0 -1
package/dist/watcher/runner.js
CHANGED
|
@@ -1,302 +1,26 @@
|
|
|
1
|
-
import { spawn } from 'node:child_process';
|
|
2
1
|
import fs from 'node:fs/promises';
|
|
3
2
|
import path from 'node:path';
|
|
4
|
-
import { hashChangeFolder } from '../core/hasher.js';
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
if (success) {
|
|
17
|
-
return `task ${taskNumber} verified (passed)`;
|
|
18
|
-
}
|
|
19
|
-
const detail = extra ? `, ${extra}` : '';
|
|
20
|
-
return `task ${taskNumber} dead (reason: ${reason}${detail})`;
|
|
21
|
-
}
|
|
22
|
-
export async function tickTaskCheckbox(specFolderPath, taskNumber) {
|
|
23
|
-
const tasksMdPath = path.join(specFolderPath, 'tasks.md');
|
|
24
|
-
let content = '';
|
|
25
|
-
try {
|
|
26
|
-
content = await fs.readFile(tasksMdPath, 'utf8');
|
|
27
|
-
}
|
|
28
|
-
catch {
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
const regex = new RegExp(`^(\\s*-\\s*\\[)[ ](\\]\\s*${taskNumber}\\b.*)$`, 'm');
|
|
32
|
-
const updated = content.replace(regex, '$1x$2');
|
|
33
|
-
if (updated !== content) {
|
|
34
|
-
await fs.writeFile(tasksMdPath, updated, 'utf8');
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
/**
|
|
38
|
-
* Single code path for process lifecycle observation: the events.jsonl entry and
|
|
39
|
-
* its human readable summary are always emitted together.
|
|
40
|
-
*/
|
|
41
|
-
async function recordLifecycleEvent(specFolderPath, taskNumber, event, summary, logger, level = 'info') {
|
|
42
|
-
await appendHarnessEvent(specFolderPath, taskNumber, event);
|
|
43
|
-
if (level === 'verbose') {
|
|
44
|
-
logger?.verbose(summary);
|
|
45
|
-
}
|
|
46
|
-
else {
|
|
47
|
-
logger?.info(summary);
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
/**
|
|
51
|
-
* Append the `dead` event that always travels with a dead marker. The event
|
|
52
|
-
* stream is the append-only source of truth for failure history, so it must
|
|
53
|
-
* agree with the marker at every exit. A lock collision never writes a dead
|
|
54
|
-
* marker and therefore never records a dead event.
|
|
55
|
-
*/
|
|
56
|
-
async function recordDeadEvent(specFolderPath, taskNumber, reason) {
|
|
57
|
-
await appendHarnessEvent(specFolderPath, taskNumber, {
|
|
58
|
-
type: 'dead',
|
|
59
|
-
timestamp: new Date().toISOString(),
|
|
60
|
-
data: { task: taskNumber, reason },
|
|
61
|
-
});
|
|
62
|
-
}
|
|
63
|
-
/**
|
|
64
|
-
* Append the `done` event that always travels with a `done/<n>` marker.
|
|
65
|
-
*/
|
|
66
|
-
async function recordDoneEvent(specFolderPath, taskNumber) {
|
|
67
|
-
await appendHarnessEvent(specFolderPath, taskNumber, {
|
|
68
|
-
type: 'done',
|
|
69
|
-
timestamp: new Date().toISOString(),
|
|
70
|
-
data: { task: taskNumber },
|
|
71
|
-
});
|
|
72
|
-
}
|
|
73
|
-
const heartbeatAccumulators = new Map();
|
|
74
|
-
function createHeartbeatAccumulator() {
|
|
75
|
-
return { byteOffset: 0, eventCount: 0, totalTokens: 0, toolCount: 0, cost: 0, hasCost: false };
|
|
76
|
-
}
|
|
77
|
-
/**
|
|
78
|
-
* Snapshot of task progress. Counters are maintained in memory and advanced
|
|
79
|
-
* with only the bytes appended since the previous poll; the event file may not
|
|
80
|
-
* exist yet, in which case counters are zero.
|
|
81
|
-
*/
|
|
82
|
-
export async function computeTaskHeartbeatStats(specFolderPath, taskNumber, startTime) {
|
|
83
|
-
const elapsedSeconds = Number(((Date.now() - startTime) / 1000).toFixed(1));
|
|
84
|
-
const eventFilePath = path.join(specFolderPath, '.run', 'events', `${taskNumber}.jsonl`);
|
|
85
|
-
let content = '';
|
|
86
|
-
try {
|
|
87
|
-
content = await fs.readFile(eventFilePath, 'utf8');
|
|
88
|
-
}
|
|
89
|
-
catch {
|
|
90
|
-
heartbeatAccumulators.delete(eventFilePath);
|
|
91
|
-
return { elapsedSeconds, eventCount: 0, totalTokens: 0, toolCount: 0 };
|
|
92
|
-
}
|
|
93
|
-
let accumulator = heartbeatAccumulators.get(eventFilePath);
|
|
94
|
-
if (!accumulator || accumulator.byteOffset > content.length) {
|
|
95
|
-
accumulator = createHeartbeatAccumulator();
|
|
96
|
-
}
|
|
97
|
-
const fresh = content.slice(accumulator.byteOffset);
|
|
98
|
-
const lastNewline = fresh.lastIndexOf('\n');
|
|
99
|
-
if (lastNewline !== -1) {
|
|
100
|
-
const complete = fresh.slice(0, lastNewline);
|
|
101
|
-
accumulator.byteOffset += lastNewline + 1;
|
|
102
|
-
for (const line of complete.split('\n')) {
|
|
103
|
-
if (!line.trim()) {
|
|
104
|
-
continue;
|
|
105
|
-
}
|
|
106
|
-
accumulator.eventCount += 1;
|
|
107
|
-
let parsed;
|
|
108
|
-
try {
|
|
109
|
-
parsed = JSON.parse(line);
|
|
110
|
-
}
|
|
111
|
-
catch {
|
|
112
|
-
// Ignore malformed lines rather than losing the whole heartbeat.
|
|
113
|
-
continue;
|
|
114
|
-
}
|
|
115
|
-
const event = asRecord(parsed);
|
|
116
|
-
if (!event) {
|
|
117
|
-
continue;
|
|
118
|
-
}
|
|
119
|
-
const data = asRecord(event.data);
|
|
120
|
-
if (event.type === 'tokens') {
|
|
121
|
-
accumulator.totalTokens += Number(data?.totalTokens ?? 0) || 0;
|
|
122
|
-
const cost = Number(data?.cost);
|
|
123
|
-
if (Number.isFinite(cost)) {
|
|
124
|
-
accumulator.cost += cost;
|
|
125
|
-
accumulator.hasCost = true;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
else if (event.type === 'tool') {
|
|
129
|
-
accumulator.toolCount += 1;
|
|
130
|
-
const summary = data?.summary;
|
|
131
|
-
if (typeof summary === 'string') {
|
|
132
|
-
accumulator.lastToolSummary = summary;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
heartbeatAccumulators.set(eventFilePath, accumulator);
|
|
138
|
-
const stats = {
|
|
139
|
-
elapsedSeconds,
|
|
140
|
-
eventCount: accumulator.eventCount,
|
|
141
|
-
totalTokens: accumulator.totalTokens,
|
|
142
|
-
toolCount: accumulator.toolCount,
|
|
143
|
-
};
|
|
144
|
-
if (accumulator.hasCost) {
|
|
145
|
-
stats.cost = accumulator.cost;
|
|
146
|
-
}
|
|
147
|
-
if (accumulator.lastToolSummary !== undefined) {
|
|
148
|
-
stats.lastToolSummary = accumulator.lastToolSummary;
|
|
149
|
-
}
|
|
150
|
-
return stats;
|
|
151
|
-
}
|
|
152
|
-
/**
|
|
153
|
-
* Drop the in-memory counters for a finished task so the map does not grow
|
|
154
|
-
* across watcher cycles.
|
|
155
|
-
*/
|
|
156
|
-
export function clearTaskHeartbeatStats(specFolderPath, taskNumber) {
|
|
157
|
-
const eventFilePath = path.join(specFolderPath, '.run', 'events', `${taskNumber}.jsonl`);
|
|
158
|
-
heartbeatAccumulators.delete(eventFilePath);
|
|
159
|
-
}
|
|
160
|
-
const STATUS_SPINNER_PREFIX_WIDTH = 2; // spinner frame plus a single space
|
|
161
|
-
const ELLIPSIS = '…';
|
|
162
|
-
function truncateToWidth(text, width) {
|
|
163
|
-
if (width <= 0) {
|
|
164
|
-
return '';
|
|
165
|
-
}
|
|
166
|
-
if (text.length <= width) {
|
|
167
|
-
return text;
|
|
168
|
-
}
|
|
169
|
-
if (width === 1) {
|
|
170
|
-
return ELLIPSIS;
|
|
171
|
-
}
|
|
172
|
-
return `${text.slice(0, width - 1)}${ELLIPSIS}`;
|
|
173
|
-
}
|
|
174
|
-
/**
|
|
175
|
-
* Single-line running status row. The logger owns the animated spinner and
|
|
176
|
-
* prepends `<frame> `, so this text is truncated to leave room for that prefix
|
|
177
|
-
* while fitting `terminalWidth` columns.
|
|
178
|
-
*/
|
|
179
|
-
export function formatTaskStatusRow(taskNumber, stats, terminalWidth = process.stderr.columns ?? 80) {
|
|
180
|
-
const segments = [
|
|
181
|
-
`task ${taskNumber}`,
|
|
182
|
-
`${stats.elapsedSeconds}s`,
|
|
183
|
-
`${stats.toolCount} tools`,
|
|
184
|
-
`${stats.totalTokens} tokens`,
|
|
185
|
-
];
|
|
186
|
-
if (typeof stats.cost === 'number' && Number.isFinite(stats.cost)) {
|
|
187
|
-
segments.push(`$${stats.cost.toFixed(4)}`);
|
|
188
|
-
}
|
|
189
|
-
const budget = terminalWidth - STATUS_SPINNER_PREFIX_WIDTH;
|
|
190
|
-
const base = segments.join(' · ');
|
|
191
|
-
if (!stats.lastToolSummary) {
|
|
192
|
-
return truncateToWidth(base, budget);
|
|
193
|
-
}
|
|
194
|
-
const separator = ' · ';
|
|
195
|
-
const summaryBudget = budget - base.length - separator.length;
|
|
196
|
-
if (summaryBudget <= 1) {
|
|
197
|
-
return truncateToWidth(base, budget);
|
|
198
|
-
}
|
|
199
|
-
return `${base}${separator}${truncateToWidth(stats.lastToolSummary, summaryBudget)}`;
|
|
200
|
-
}
|
|
201
|
-
/** Periodic heartbeat line shared by the 1s TTY row and the non-TTY log. */
|
|
202
|
-
export function formatTaskHeartbeatLine(taskNumber, stats) {
|
|
203
|
-
return `task ${taskNumber} heartbeat (elapsed: ${stats.elapsedSeconds}s, events: ${stats.eventCount}, tokens: ${stats.totalTokens})`;
|
|
204
|
-
}
|
|
205
|
-
/**
|
|
206
|
-
* Curated task-started line: a single info line carrying the task title
|
|
207
|
-
* truncated so the whole line fits the terminal width. The lifecycle details
|
|
208
|
-
* (pid, timeout) travel with it so the marker and the log line stay in sync.
|
|
209
|
-
*/
|
|
210
|
-
export function formatTaskStartedLine(taskNumber, title, pid, timeoutSeconds, symbols, terminalWidth = process.stderr.columns ?? 80) {
|
|
211
|
-
const symbol = resolveSymbol('▶', '[task]', symbols);
|
|
212
|
-
const prefix = `${symbol} task ${taskNumber} started (pid: ${pid ?? 'unknown'}, timeout: ${timeoutSeconds}s): `;
|
|
213
|
-
const budget = Math.max(0, terminalWidth - prefix.length);
|
|
214
|
-
return `${prefix}${truncateToWidth(title, budget)}`;
|
|
215
|
-
}
|
|
216
|
-
/**
|
|
217
|
-
* Curated task-outcome line: verified or dead with the failure reason and the
|
|
218
|
-
* elapsed seconds since the task began.
|
|
219
|
-
*/
|
|
220
|
-
export function formatTaskOutcomeLine(taskNumber, success, reason, elapsedSeconds, symbols) {
|
|
221
|
-
if (success) {
|
|
222
|
-
return `${resolveSymbol('✓', '[ok]', symbols)} task ${taskNumber} verified (elapsed: ${elapsedSeconds}s)`;
|
|
223
|
-
}
|
|
224
|
-
return `${resolveSymbol('✗', '[dead]', symbols)} task ${taskNumber} dead (reason: ${reason}, elapsed: ${elapsedSeconds}s)`;
|
|
225
|
-
}
|
|
226
|
-
/**
|
|
227
|
-
* Return the last text message emitted on the agent's event stream, or null
|
|
228
|
-
* when the stream has no text at all. Synthesis reads exclusively from
|
|
229
|
-
* first-class `text` events carrying the completed assistant message; raw
|
|
230
|
-
* harness payload shapes are never inspected. The stream is the append-only
|
|
231
|
-
* `.run/events/<n>.jsonl` file, so this survives a watcher restart.
|
|
232
|
-
*/
|
|
233
|
-
export async function extractFinalTextFromStream(specFolderPath, taskNumber) {
|
|
234
|
-
const eventFilePath = path.join(specFolderPath, '.run', 'events', `${taskNumber}.jsonl`);
|
|
235
|
-
let content = '';
|
|
236
|
-
try {
|
|
237
|
-
content = await fs.readFile(eventFilePath, 'utf8');
|
|
238
|
-
}
|
|
239
|
-
catch {
|
|
240
|
-
return null;
|
|
241
|
-
}
|
|
242
|
-
let finalText = null;
|
|
243
|
-
for (const line of content.split('\n')) {
|
|
244
|
-
if (!line.trim()) {
|
|
245
|
-
continue;
|
|
246
|
-
}
|
|
247
|
-
let parsed;
|
|
248
|
-
try {
|
|
249
|
-
parsed = JSON.parse(line);
|
|
250
|
-
}
|
|
251
|
-
catch {
|
|
252
|
-
continue;
|
|
253
|
-
}
|
|
254
|
-
const event = asRecord(parsed);
|
|
255
|
-
if (event?.type !== 'text') {
|
|
256
|
-
continue;
|
|
257
|
-
}
|
|
258
|
-
const text = asRecord(event.data)?.text;
|
|
259
|
-
if (typeof text === 'string' && text.trim().length > 0) {
|
|
260
|
-
finalText = text;
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
|
-
return finalText?.trim() ? finalText : null;
|
|
264
|
-
}
|
|
265
|
-
/**
|
|
266
|
-
* Write a result file synthesized from the agent's final stream message. The
|
|
267
|
-
* frontmatter flags it as `synthesized: true` and a comment attributes it to
|
|
268
|
-
* the watcher so a reader never mistakes it for an agent-authored result.
|
|
269
|
-
*/
|
|
270
|
-
export async function synthesizeResultFile(resultsDir, taskNumber, finalText) {
|
|
271
|
-
await fs.mkdir(resultsDir, { recursive: true });
|
|
272
|
-
const resultPath = path.join(resultsDir, `${taskNumber}.md`);
|
|
273
|
-
const body = finalText.endsWith('\n') ? finalText : `${finalText}\n`;
|
|
274
|
-
const content = [
|
|
275
|
-
'---',
|
|
276
|
-
'synthesized: true',
|
|
277
|
-
'---',
|
|
278
|
-
"<!-- Synthesized by the osq watcher from the agent's final stream message.",
|
|
279
|
-
' The agent exited without writing a result file. -->',
|
|
280
|
-
'',
|
|
281
|
-
body,
|
|
282
|
-
].join('\n');
|
|
283
|
-
await fs.writeFile(resultPath, content, 'utf8');
|
|
284
|
-
return resultPath;
|
|
285
|
-
}
|
|
3
|
+
import { hashChangeFolder } from '../core/spec/hasher.js';
|
|
4
|
+
import { parseTaskMd } from '../core/spec/parser.js';
|
|
5
|
+
import { runChangeVerifyGate } from './change-verify.js';
|
|
6
|
+
import { clearTaskHeartbeatStats, computeTaskHeartbeatStats, formatTaskHeartbeatLine, formatTaskStatusRow, } from './heartbeat.js';
|
|
7
|
+
import { acquireTaskLock, releaseTaskLock } from './lock.js';
|
|
8
|
+
import { createTaskMeasures } from './measures.js';
|
|
9
|
+
import { formatTaskOutcomeLine, recordDeadEvent, recordDoneEvent, tickTaskCheckbox, writeDeadMarker, writeDoneMarker, } from './outcome.js';
|
|
10
|
+
import { buildDoneMetadata, guardScopeRegression } from './regression.js';
|
|
11
|
+
import { ensureTaskResult, spawnTaskAgent } from './spawn.js';
|
|
12
|
+
import { checkMissingVerifyPaths, runPreSpawnVerify, verifyRedFailure } from './task-verify.js';
|
|
13
|
+
import { captureTestGate, findUndeclaredTestChanges, runVerificationGate } from './verify.js';
|
|
14
|
+
/** Top-level sequential task pipeline; each phase delegates to its lifecycle module. */
|
|
286
15
|
export async function runTask(projectRoot, specFolderPath, taskNumber, config, adapter, logger) {
|
|
287
16
|
const runDir = path.join(specFolderPath, '.run');
|
|
288
|
-
const deadDir = path.join(runDir, 'dead');
|
|
289
|
-
const doneDir = path.join(runDir, 'done');
|
|
290
17
|
const startTime = Date.now();
|
|
291
18
|
const useSymbols = logger?.symbols === true;
|
|
292
19
|
const interactive = logger?.interactive === true;
|
|
293
|
-
const
|
|
294
|
-
const heartbeatIntervalMs = heartbeatSeconds * 1000;
|
|
20
|
+
const heartbeatIntervalMs = (config.log?.heartbeatSeconds ?? 60) * 1000;
|
|
295
21
|
let heartbeatTimer = null;
|
|
296
22
|
let heartbeatActive = true;
|
|
297
23
|
let lastHeartbeatLogAt = startTime;
|
|
298
|
-
// One timer owns both observation modes: the 1s TTY status row and the
|
|
299
|
-
// periodic non-TTY heartbeat log. TTY heartbeats are demoted to verbose.
|
|
300
24
|
const stopHeartbeat = () => {
|
|
301
25
|
heartbeatActive = false;
|
|
302
26
|
if (heartbeatTimer) {
|
|
@@ -305,64 +29,58 @@ export async function runTask(projectRoot, specFolderPath, taskNumber, config, a
|
|
|
305
29
|
}
|
|
306
30
|
logger?.clearStatus();
|
|
307
31
|
};
|
|
308
|
-
const logOutcome = (success, reason) => {
|
|
32
|
+
const logOutcome = (success, reason, extra) => {
|
|
309
33
|
stopHeartbeat();
|
|
310
34
|
const elapsedSeconds = Number(((Date.now() - startTime) / 1000).toFixed(1));
|
|
311
|
-
logger?.info(formatTaskOutcomeLine(taskNumber, success, reason, elapsedSeconds, useSymbols));
|
|
35
|
+
logger?.info(formatTaskOutcomeLine(taskNumber, success, reason, elapsedSeconds, useSymbols, extra));
|
|
36
|
+
};
|
|
37
|
+
let measures = null;
|
|
38
|
+
const finish = (result) => measures ? measures.emitEnd().then(() => result) : Promise.resolve(result);
|
|
39
|
+
const fail = async (reason, marker, error, extra) => {
|
|
40
|
+
await measures?.emitEnd();
|
|
41
|
+
await writeDeadMarker(runDir, taskNumber, marker, projectRoot);
|
|
42
|
+
await recordDeadEvent(specFolderPath, taskNumber, reason);
|
|
43
|
+
logOutcome(false, reason, extra);
|
|
44
|
+
return { success: false, reason, error };
|
|
312
45
|
};
|
|
313
|
-
const approvedPath = path.join(runDir, 'approved');
|
|
314
46
|
let approvedHash = '';
|
|
315
47
|
try {
|
|
316
|
-
approvedHash = (await fs.readFile(
|
|
48
|
+
approvedHash = (await fs.readFile(path.join(runDir, 'approved'), 'utf8')).trim();
|
|
317
49
|
}
|
|
318
50
|
catch {
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
await recordDeadEvent(specFolderPath, taskNumber, 'spec_conflict');
|
|
322
|
-
logger?.info(formatTaskOutcomeSummary(taskNumber, false, 'spec_conflict'));
|
|
323
|
-
logOutcome(false, 'spec_conflict');
|
|
324
|
-
return { success: false, reason: 'spec_conflict', error: 'Missing .run/approved' };
|
|
51
|
+
const marker = '---\nreason: spec_conflict\n---\nSpec has not been approved (missing .run/approved).\n';
|
|
52
|
+
return fail('spec_conflict', marker, 'Missing .run/approved');
|
|
325
53
|
}
|
|
326
54
|
const currentHash = await hashChangeFolder(specFolderPath);
|
|
327
55
|
if (currentHash !== approvedHash) {
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
logger?.info(formatTaskOutcomeSummary(taskNumber, false, 'spec_conflict'));
|
|
332
|
-
logOutcome(false, 'spec_conflict');
|
|
333
|
-
return {
|
|
334
|
-
success: false,
|
|
335
|
-
reason: 'spec_conflict',
|
|
336
|
-
error: `Folder hash mismatch: expected ${approvedHash}, got ${currentHash}`,
|
|
337
|
-
};
|
|
56
|
+
const marker = `---\nreason: spec_conflict\napproved_hash: "${approvedHash}"\ncurrent_hash: "${currentHash}"\n---\nChange folder modified after approval. Expected ${approvedHash}, computed ${currentHash}.\n`;
|
|
57
|
+
const error = `Folder hash mismatch: expected ${approvedHash}, got ${currentHash}`;
|
|
58
|
+
return fail('spec_conflict', marker, error);
|
|
338
59
|
}
|
|
339
60
|
const taskPath = path.join(specFolderPath, 'tasks', `${taskNumber}.md`);
|
|
340
61
|
let taskContent = '';
|
|
341
62
|
try {
|
|
342
63
|
taskContent = await fs.readFile(taskPath, 'utf8');
|
|
343
64
|
}
|
|
344
|
-
catch
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
await recordDeadEvent(specFolderPath, taskNumber, 'crashed');
|
|
348
|
-
logger?.info(formatTaskOutcomeSummary(taskNumber, false, 'crashed'));
|
|
349
|
-
logOutcome(false, 'crashed');
|
|
350
|
-
return { success: false, reason: 'crashed', error: 'Task file not found' };
|
|
65
|
+
catch {
|
|
66
|
+
const marker = `---\nreason: crashed\n---\nTask file not found: ${taskPath}\n`;
|
|
67
|
+
return fail('crashed', marker, 'Task file not found');
|
|
351
68
|
}
|
|
352
69
|
const taskData = parseTaskMd(taskContent);
|
|
353
|
-
const
|
|
70
|
+
const regression = await guardScopeRegression(projectRoot, specFolderPath, taskNumber, config);
|
|
71
|
+
if (regression) {
|
|
72
|
+
logOutcome(false, 'regressed', regression.error);
|
|
73
|
+
return regression;
|
|
74
|
+
}
|
|
75
|
+
const lockResult = await acquireTaskLock(runDir, taskNumber);
|
|
354
76
|
if (!lockResult.acquired) {
|
|
355
|
-
// A lock collision means another process is actively running this task, not
|
|
356
|
-
// that the task failed. It writes no dead marker, so it must not append a
|
|
357
|
-
// dead event either; only a dead marker write may record a dead event.
|
|
358
|
-
logger?.info(formatTaskOutcomeSummary(taskNumber, false, 'already_running'));
|
|
359
77
|
logOutcome(false, 'already_running');
|
|
360
78
|
return { success: false, reason: 'already_running', error: 'Task is already running' };
|
|
361
79
|
}
|
|
362
80
|
if (heartbeatIntervalMs > 0) {
|
|
363
81
|
const tickIntervalMs = interactive ? Math.min(heartbeatIntervalMs, 1000) : heartbeatIntervalMs;
|
|
364
82
|
heartbeatTimer = setInterval(() => {
|
|
365
|
-
computeTaskHeartbeatStats(specFolderPath, taskNumber, startTime)
|
|
83
|
+
computeTaskHeartbeatStats(specFolderPath, taskNumber, startTime, projectRoot)
|
|
366
84
|
.then((stats) => {
|
|
367
85
|
if (!heartbeatActive)
|
|
368
86
|
return;
|
|
@@ -383,214 +101,47 @@ export async function runTask(projectRoot, specFolderPath, taskNumber, config, a
|
|
|
383
101
|
heartbeatTimer.unref();
|
|
384
102
|
}
|
|
385
103
|
try {
|
|
386
|
-
const
|
|
387
|
-
const
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
return startedPromise ?? Promise.resolve();
|
|
395
|
-
}
|
|
396
|
-
startedRecorded = true;
|
|
397
|
-
startedPromise = recordLifecycleEvent(specFolderPath, taskNumber, {
|
|
398
|
-
type: 'started',
|
|
399
|
-
timestamp: new Date().toISOString(),
|
|
400
|
-
data: { pid, timeoutSeconds },
|
|
401
|
-
}, formatTaskStartedLine(taskNumber, taskData.title, pid, timeoutSeconds, useSymbols), logger);
|
|
402
|
-
return startedPromise;
|
|
403
|
-
};
|
|
404
|
-
const spawnResult = await adapter.spawn({
|
|
104
|
+
const testGate = await captureTestGate(projectRoot, taskData.scope, taskData.testsModify);
|
|
105
|
+
const verifyCtx = { projectRoot, specFolderPath, taskNumber, taskData, config, logger };
|
|
106
|
+
const preSpawn = await runPreSpawnVerify(verifyCtx);
|
|
107
|
+
if (!preSpawn.ok)
|
|
108
|
+
return fail('verify_precondition', preSpawn.marker, preSpawn.error);
|
|
109
|
+
measures = createTaskMeasures(projectRoot, specFolderPath, taskNumber, taskData);
|
|
110
|
+
await measures.emitStart();
|
|
111
|
+
const spawnOutcome = await spawnTaskAgent({
|
|
405
112
|
projectRoot,
|
|
406
113
|
specFolderPath,
|
|
407
114
|
taskNumber,
|
|
408
|
-
|
|
409
|
-
verifyCommand: taskData.verify,
|
|
410
|
-
scope: taskData.scope,
|
|
411
|
-
entry: taskData.entry,
|
|
412
|
-
skills: taskData.skills,
|
|
413
|
-
tier: 'coding',
|
|
414
|
-
timeoutSeconds,
|
|
115
|
+
taskData,
|
|
415
116
|
config,
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
// before the callback) still yields exactly one `started` event.
|
|
420
|
-
await recordStarted(spawnResult.pid);
|
|
421
|
-
const elapsedMs = spawnResult.elapsedMs ?? Date.now() - spawnStartMs;
|
|
422
|
-
const elapsedSeconds = Number((elapsedMs / 1000).toFixed(1));
|
|
423
|
-
await recordLifecycleEvent(specFolderPath, taskNumber, {
|
|
424
|
-
type: 'exited',
|
|
425
|
-
timestamp: new Date().toISOString(),
|
|
426
|
-
data: {
|
|
427
|
-
exitCode: spawnResult.exitCode,
|
|
428
|
-
pid: spawnResult.pid,
|
|
429
|
-
signal: spawnResult.signal ?? undefined,
|
|
430
|
-
timedOut: spawnResult.timedOut,
|
|
431
|
-
elapsedSeconds,
|
|
432
|
-
},
|
|
433
|
-
}, `task ${taskNumber} exited (code: ${spawnResult.exitCode}, elapsed: ${elapsedSeconds}s)`, logger, 'verbose');
|
|
434
|
-
if (spawnResult.exitCode !== 0 || spawnResult.timedOut) {
|
|
435
|
-
const failureReason = spawnResult.timedOut ? 'timeout' : 'crashed';
|
|
436
|
-
await fs.mkdir(deadDir, { recursive: true });
|
|
437
|
-
const deadMarkerLines = [
|
|
438
|
-
'---',
|
|
439
|
-
`reason: ${failureReason}`,
|
|
440
|
-
`exit_code: ${spawnResult.exitCode}`,
|
|
441
|
-
];
|
|
442
|
-
if (spawnResult.signal) {
|
|
443
|
-
deadMarkerLines.push(`signal: ${spawnResult.signal}`);
|
|
444
|
-
}
|
|
445
|
-
deadMarkerLines.push('---');
|
|
446
|
-
deadMarkerLines.push(`Agent ${spawnResult.timedOut ? 'timed out' : 'crashed'} with code ${spawnResult.exitCode}: ${spawnResult.error || ''}\n`);
|
|
447
|
-
await fs.writeFile(path.join(deadDir, `${taskNumber}.md`), deadMarkerLines.join('\n'), 'utf8');
|
|
448
|
-
await recordDeadEvent(specFolderPath, taskNumber, failureReason);
|
|
449
|
-
logger?.info(formatTaskOutcomeSummary(taskNumber, false, failureReason, failureReason === 'crashed' ? `code: ${spawnResult.exitCode}` : undefined));
|
|
450
|
-
logOutcome(false, failureReason);
|
|
451
|
-
return {
|
|
452
|
-
success: false,
|
|
453
|
-
reason: failureReason,
|
|
454
|
-
error: spawnResult.error || `Agent exited with code ${spawnResult.exitCode}`,
|
|
455
|
-
};
|
|
456
|
-
}
|
|
457
|
-
const resultPath = path.join(runDir, 'results', `${taskNumber}.md`);
|
|
458
|
-
let hasResult = false;
|
|
459
|
-
try {
|
|
460
|
-
await fs.stat(resultPath);
|
|
461
|
-
hasResult = true;
|
|
462
|
-
}
|
|
463
|
-
catch { }
|
|
464
|
-
if (!hasResult) {
|
|
465
|
-
const finalText = await extractFinalTextFromStream(specFolderPath, taskNumber);
|
|
466
|
-
if (finalText) {
|
|
467
|
-
await synthesizeResultFile(path.join(runDir, 'results'), taskNumber, finalText);
|
|
468
|
-
await appendHarnessEvent(specFolderPath, taskNumber, {
|
|
469
|
-
type: 'result_written',
|
|
470
|
-
timestamp: new Date().toISOString(),
|
|
471
|
-
data: { path: resultPath, synthesized: true },
|
|
472
|
-
});
|
|
473
|
-
logger?.verbose(`task ${taskNumber} result synthesized from agent message`);
|
|
474
|
-
}
|
|
475
|
-
else {
|
|
476
|
-
await fs.mkdir(deadDir, { recursive: true });
|
|
477
|
-
await fs.writeFile(path.join(deadDir, `${taskNumber}.md`), `---\nreason: no_result\n---\nAgent exited without writing result file at .run/results/${taskNumber}.md and produced no final text.\n`, 'utf8');
|
|
478
|
-
await recordDeadEvent(specFolderPath, taskNumber, 'no_result');
|
|
479
|
-
logger?.info(formatTaskOutcomeSummary(taskNumber, false, 'no_result'));
|
|
480
|
-
logOutcome(false, 'no_result');
|
|
481
|
-
return {
|
|
482
|
-
success: false,
|
|
483
|
-
reason: 'no_result',
|
|
484
|
-
error: `Agent exited without writing .run/results/${taskNumber}.md`,
|
|
485
|
-
};
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
await appendHarnessEvent(specFolderPath, taskNumber, {
|
|
489
|
-
type: 'verify_ran',
|
|
490
|
-
timestamp: new Date().toISOString(),
|
|
491
|
-
data: { command: taskData.verify },
|
|
492
|
-
});
|
|
493
|
-
const verifyTimeoutMs = (config.timeouts.verifyTimeoutSeconds ?? 600) * 1000;
|
|
494
|
-
let verifyTimedOut = false;
|
|
495
|
-
const verifyPromise = new Promise((resolve, reject) => {
|
|
496
|
-
const child = spawn(taskData.verify, {
|
|
497
|
-
cwd: projectRoot,
|
|
498
|
-
shell: true,
|
|
499
|
-
detached: true,
|
|
500
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
501
|
-
});
|
|
502
|
-
let timer = null;
|
|
503
|
-
let killTimer = null;
|
|
504
|
-
if (verifyTimeoutMs > 0) {
|
|
505
|
-
timer = setTimeout(() => {
|
|
506
|
-
verifyTimedOut = true;
|
|
507
|
-
const childPid = child.pid;
|
|
508
|
-
if (childPid) {
|
|
509
|
-
try {
|
|
510
|
-
process.kill(-childPid, 'SIGTERM');
|
|
511
|
-
}
|
|
512
|
-
catch {
|
|
513
|
-
try {
|
|
514
|
-
child.kill('SIGTERM');
|
|
515
|
-
}
|
|
516
|
-
catch { }
|
|
517
|
-
}
|
|
518
|
-
killTimer = setTimeout(() => {
|
|
519
|
-
try {
|
|
520
|
-
process.kill(-childPid, 'SIGKILL');
|
|
521
|
-
}
|
|
522
|
-
catch {
|
|
523
|
-
try {
|
|
524
|
-
child.kill('SIGKILL');
|
|
525
|
-
}
|
|
526
|
-
catch { }
|
|
527
|
-
}
|
|
528
|
-
}, 5000);
|
|
529
|
-
}
|
|
530
|
-
}, verifyTimeoutMs);
|
|
531
|
-
}
|
|
532
|
-
let stderr = '';
|
|
533
|
-
let stdout = '';
|
|
534
|
-
child.stderr?.on('data', (d) => {
|
|
535
|
-
stderr += d.toString();
|
|
536
|
-
});
|
|
537
|
-
child.stdout?.on('data', (d) => {
|
|
538
|
-
stdout += d.toString();
|
|
539
|
-
});
|
|
540
|
-
child.on('error', (err) => {
|
|
541
|
-
if (timer)
|
|
542
|
-
clearTimeout(timer);
|
|
543
|
-
if (killTimer)
|
|
544
|
-
clearTimeout(killTimer);
|
|
545
|
-
reject(err);
|
|
546
|
-
});
|
|
547
|
-
child.on('close', (code) => {
|
|
548
|
-
if (timer)
|
|
549
|
-
clearTimeout(timer);
|
|
550
|
-
if (killTimer)
|
|
551
|
-
clearTimeout(killTimer);
|
|
552
|
-
if (verifyTimedOut) {
|
|
553
|
-
reject(new Error(`Verify command timed out after ${config.timeouts.verifyTimeoutSeconds ?? 600}s`));
|
|
554
|
-
}
|
|
555
|
-
else if (code !== 0) {
|
|
556
|
-
reject(new Error(stderr || stdout || `Process exited with code ${code}`));
|
|
557
|
-
}
|
|
558
|
-
else {
|
|
559
|
-
resolve();
|
|
560
|
-
}
|
|
561
|
-
});
|
|
117
|
+
adapter,
|
|
118
|
+
logger,
|
|
119
|
+
logOutcome,
|
|
562
120
|
});
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
const
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
if (verifyTimedOut) {
|
|
571
|
-
deadLines.push('timed_out: true');
|
|
572
|
-
}
|
|
573
|
-
deadLines.push(`command: "${taskData.verify}"`);
|
|
574
|
-
deadLines.push('---');
|
|
575
|
-
deadLines.push(`Watcher independent verify ${verifyTimedOut ? 'timed out' : 'failed'}:\n${msg}\n`);
|
|
576
|
-
await fs.writeFile(path.join(deadDir, `${taskNumber}.md`), deadLines.join('\n'), 'utf8');
|
|
577
|
-
await recordDeadEvent(specFolderPath, taskNumber, 'verify_red');
|
|
578
|
-
logger?.info(formatTaskOutcomeSummary(taskNumber, false, 'verify_red', verifyTimedOut ? 'timed_out: true' : undefined));
|
|
579
|
-
logOutcome(false, 'verify_red');
|
|
580
|
-
return {
|
|
581
|
-
success: false,
|
|
582
|
-
reason: 'verify_red',
|
|
583
|
-
error: `Verify failed: ${msg}`,
|
|
584
|
-
};
|
|
121
|
+
if (!spawnOutcome.ok)
|
|
122
|
+
return finish(spawnOutcome.result);
|
|
123
|
+
const undeclared = await findUndeclaredTestChanges(projectRoot, testGate.snapshot, testGate);
|
|
124
|
+
if (undeclared.length > 0) {
|
|
125
|
+
const marker = `---\nreason: undeclared_test_change\n---\nPreexisting test files were modified or deleted without both tests.modify: true and an authorizing scope entry:\n${undeclared.map((file) => `- ${file}`).join('\n')}\n`;
|
|
126
|
+
const error = `Undeclared test changes: ${undeclared.join(', ')}`;
|
|
127
|
+
return fail('undeclared_test_change', marker, error);
|
|
585
128
|
}
|
|
586
|
-
|
|
587
|
-
|
|
129
|
+
const ensured = await ensureTaskResult({ specFolderPath, taskNumber, logger, logOutcome });
|
|
130
|
+
if (!ensured.ok)
|
|
131
|
+
return finish(ensured.result);
|
|
132
|
+
const missingPath = await checkMissingVerifyPaths(projectRoot, taskData, fail);
|
|
133
|
+
if (missingPath)
|
|
134
|
+
return missingPath;
|
|
135
|
+
const verifyResult = await runVerificationGate(projectRoot, taskData.verify, config.timeouts.verifyTimeoutSeconds ?? 600, { specFolderPath, taskNumber });
|
|
136
|
+
if (!verifyResult.passed) {
|
|
137
|
+
return verifyRedFailure(taskData.verify, verifyResult, fail);
|
|
588
138
|
}
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
139
|
+
const gate = await runChangeVerifyGate(projectRoot, specFolderPath, config);
|
|
140
|
+
if (!gate.ok)
|
|
141
|
+
return fail('change_verify_red', gate.marker, gate.error, gate.extra);
|
|
142
|
+
await measures.emitEnd();
|
|
143
|
+
await writeDoneMarker(runDir, taskNumber, await buildDoneMetadata(projectRoot, taskData.scope));
|
|
592
144
|
await recordDoneEvent(specFolderPath, taskNumber);
|
|
593
|
-
logger?.info(formatTaskOutcomeSummary(taskNumber, true));
|
|
594
145
|
logOutcome(true);
|
|
595
146
|
await tickTaskCheckbox(specFolderPath, taskNumber);
|
|
596
147
|
return { success: true };
|
|
@@ -598,7 +149,7 @@ export async function runTask(projectRoot, specFolderPath, taskNumber, config, a
|
|
|
598
149
|
finally {
|
|
599
150
|
stopHeartbeat();
|
|
600
151
|
clearTaskHeartbeatStats(specFolderPath, taskNumber);
|
|
601
|
-
await
|
|
152
|
+
await releaseTaskLock(runDir, taskNumber);
|
|
602
153
|
}
|
|
603
154
|
}
|
|
604
155
|
//# sourceMappingURL=runner.js.map
|