@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
|
@@ -0,0 +1,704 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { DEFAULT_CONFIG } from '../foundation/config.js';
|
|
4
|
+
import { readPlanningSessions } from '../report/planning.js';
|
|
5
|
+
import { formatDuration } from '../report/report.js';
|
|
6
|
+
import { parseFrontmatter, parseSpecMdFromFolder, parseTaskMd } from '../spec/parser.js';
|
|
7
|
+
import { getArchiveDir, getChangesDir, getRejectedDir } from './layout.js';
|
|
8
|
+
import { deriveSpecState } from './state.js';
|
|
9
|
+
function matchesFolder(folderName, query) {
|
|
10
|
+
const trimmed = query.trim();
|
|
11
|
+
const num = Number.parseInt(trimmed, 10);
|
|
12
|
+
const padded = !Number.isNaN(num) ? String(num).padStart(3, '0') : trimmed;
|
|
13
|
+
if (folderName === trimmed || folderName === padded)
|
|
14
|
+
return true;
|
|
15
|
+
if (folderName.startsWith(`${trimmed}-`) || folderName.startsWith(`${padded}-`))
|
|
16
|
+
return true;
|
|
17
|
+
if (folderName.endsWith(`-${trimmed}`))
|
|
18
|
+
return true;
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
function numericTaskTarget(value) {
|
|
22
|
+
if (typeof value === 'number' && Number.isInteger(value) && value >= 0) {
|
|
23
|
+
return String(value);
|
|
24
|
+
}
|
|
25
|
+
if (typeof value === 'string' && /^\d+$/.test(value.trim())) {
|
|
26
|
+
return value.trim();
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
function stringList(value) {
|
|
31
|
+
if (!Array.isArray(value))
|
|
32
|
+
return [];
|
|
33
|
+
return value
|
|
34
|
+
.filter((entry) => typeof entry === 'string' && entry.trim() !== '')
|
|
35
|
+
.map((entry) => entry.trim());
|
|
36
|
+
}
|
|
37
|
+
function attributionEntries(value) {
|
|
38
|
+
if (!Array.isArray(value))
|
|
39
|
+
return [];
|
|
40
|
+
const entries = [];
|
|
41
|
+
for (const entry of value) {
|
|
42
|
+
if (entry === null || typeof entry !== 'object' || Array.isArray(entry))
|
|
43
|
+
continue;
|
|
44
|
+
const { path: rawPath, attribution: rawAttribution } = entry;
|
|
45
|
+
if (typeof rawPath !== 'string' || rawPath.trim() === '')
|
|
46
|
+
continue;
|
|
47
|
+
const attribution = typeof rawAttribution === 'string' && rawAttribution.trim() !== ''
|
|
48
|
+
? rawAttribution.trim()
|
|
49
|
+
: typeof rawAttribution === 'number' && Number.isFinite(rawAttribution)
|
|
50
|
+
? String(rawAttribution)
|
|
51
|
+
: 'unknown';
|
|
52
|
+
entries.push({ path: rawPath.trim(), attribution });
|
|
53
|
+
}
|
|
54
|
+
return entries;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Projects one typed `recertification` event into a display row. Only explicit,
|
|
58
|
+
* well-formed values are surfaced; everything else is unavailable. The row is
|
|
59
|
+
* built solely from the already parsed event, never from marker files.
|
|
60
|
+
*/
|
|
61
|
+
function buildRecertification(taskNumber, event) {
|
|
62
|
+
const data = event.data ?? {};
|
|
63
|
+
const differingPaths = [...new Set(stringList(data.differingPaths))].sort();
|
|
64
|
+
const recorded = attributionEntries(data.attribution);
|
|
65
|
+
const byPath = new Map();
|
|
66
|
+
for (const entry of recorded) {
|
|
67
|
+
if (!byPath.has(entry.path))
|
|
68
|
+
byPath.set(entry.path, entry.attribution);
|
|
69
|
+
}
|
|
70
|
+
const allPaths = [...new Set([...differingPaths, ...recorded.map((entry) => entry.path)])].sort();
|
|
71
|
+
const attribution = allPaths.map((path) => ({
|
|
72
|
+
path,
|
|
73
|
+
attribution: byPath.get(path) ?? 'unknown',
|
|
74
|
+
}));
|
|
75
|
+
const rawTimestamp = typeof event.timestamp === 'string' ? event.timestamp.trim() : '';
|
|
76
|
+
const timestamp = rawTimestamp && !Number.isNaN(new Date(rawTimestamp).getTime()) ? rawTimestamp : null;
|
|
77
|
+
const outcome = data.outcome === 'passed' ? 'passed' : data.outcome === 'requeued' ? 'requeued' : null;
|
|
78
|
+
const verify = typeof data.command === 'string' && data.command.trim() !== '' ? data.command.trim() : null;
|
|
79
|
+
const exitCode = typeof data.exitCode === 'number' && Number.isFinite(data.exitCode) ? data.exitCode : null;
|
|
80
|
+
const timedOut = typeof data.timedOut === 'boolean' ? data.timedOut : null;
|
|
81
|
+
return {
|
|
82
|
+
taskNumber,
|
|
83
|
+
timestamp,
|
|
84
|
+
outcome,
|
|
85
|
+
differingPaths,
|
|
86
|
+
attribution,
|
|
87
|
+
verify,
|
|
88
|
+
exitCode,
|
|
89
|
+
timedOut,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
export async function resolveSpecFolder(projectRoot, idOrPrefix, config = DEFAULT_CONFIG) {
|
|
93
|
+
const trimmed = idOrPrefix.trim();
|
|
94
|
+
if (!trimmed) {
|
|
95
|
+
throw new Error('Spec ID or prefix cannot be empty');
|
|
96
|
+
}
|
|
97
|
+
const specsDir = getChangesDir(config.paths.openspecRoot, projectRoot);
|
|
98
|
+
const archiveDir = getArchiveDir(config.paths.openspecRoot, projectRoot);
|
|
99
|
+
const rejectedDir = getRejectedDir(config.paths.openspecRoot, projectRoot);
|
|
100
|
+
// If directly pointing to an existing folder
|
|
101
|
+
if (path.isAbsolute(trimmed) || trimmed.includes(path.sep)) {
|
|
102
|
+
const candidatePath = path.isAbsolute(trimmed) ? trimmed : path.resolve(projectRoot, trimmed);
|
|
103
|
+
const stat = await fs.stat(candidatePath).catch(() => null);
|
|
104
|
+
if (stat?.isDirectory()) {
|
|
105
|
+
const location = candidatePath === archiveDir || candidatePath.startsWith(`${archiveDir}${path.sep}`)
|
|
106
|
+
? 'archived'
|
|
107
|
+
: candidatePath === rejectedDir || candidatePath.startsWith(`${rejectedDir}${path.sep}`)
|
|
108
|
+
? 'rejected'
|
|
109
|
+
: 'active';
|
|
110
|
+
return { folderPath: candidatePath, isArchived: location === 'archived', location };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// 1. Search active specs
|
|
114
|
+
let activeEntries = [];
|
|
115
|
+
try {
|
|
116
|
+
activeEntries = await fs.readdir(specsDir);
|
|
117
|
+
}
|
|
118
|
+
catch {
|
|
119
|
+
activeEntries = [];
|
|
120
|
+
}
|
|
121
|
+
const archiveRel = path.relative(specsDir, archiveDir);
|
|
122
|
+
const archiveFolder = !archiveRel.startsWith('..') && !path.isAbsolute(archiveRel)
|
|
123
|
+
? archiveRel.split(path.sep)[0]
|
|
124
|
+
: 'archive';
|
|
125
|
+
const rejectedRel = path.relative(specsDir, rejectedDir);
|
|
126
|
+
const rejectedFolder = !rejectedRel.startsWith('..') && !path.isAbsolute(rejectedRel)
|
|
127
|
+
? rejectedRel.split(path.sep)[0]
|
|
128
|
+
: 'rejected';
|
|
129
|
+
for (const entry of activeEntries) {
|
|
130
|
+
if (entry.startsWith('.') ||
|
|
131
|
+
entry.startsWith('_') ||
|
|
132
|
+
entry === archiveFolder ||
|
|
133
|
+
entry === rejectedFolder) {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (matchesFolder(entry, trimmed)) {
|
|
137
|
+
const fullPath = path.join(specsDir, entry);
|
|
138
|
+
const stat = await fs.stat(fullPath).catch(() => null);
|
|
139
|
+
if (stat?.isDirectory()) {
|
|
140
|
+
return { folderPath: fullPath, isArchived: false, location: 'active' };
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
// 2. Search archive directory
|
|
145
|
+
const archived = await searchFolder(archiveDir, trimmed, 'archived');
|
|
146
|
+
if (archived)
|
|
147
|
+
return archived;
|
|
148
|
+
// 3. Search rejected directory
|
|
149
|
+
const rejected = await searchFolder(rejectedDir, trimmed, 'rejected');
|
|
150
|
+
if (rejected)
|
|
151
|
+
return rejected;
|
|
152
|
+
throw new Error(`Spec "${idOrPrefix}" not found in specs or archive`);
|
|
153
|
+
}
|
|
154
|
+
/** Search one canonical location directory for a folder matching the query. */
|
|
155
|
+
async function searchFolder(dir, query, location) {
|
|
156
|
+
let entries = [];
|
|
157
|
+
try {
|
|
158
|
+
entries = await fs.readdir(dir);
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
return null;
|
|
162
|
+
}
|
|
163
|
+
for (const entry of entries) {
|
|
164
|
+
if (entry.startsWith('.') || entry.startsWith('_')) {
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
if (matchesFolder(entry, query)) {
|
|
168
|
+
const fullPath = path.join(dir, entry);
|
|
169
|
+
const stat = await fs.stat(fullPath).catch(() => null);
|
|
170
|
+
if (stat?.isDirectory()) {
|
|
171
|
+
return { folderPath: fullPath, isArchived: location === 'archived', location };
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
export async function getSpecDetails(projectRoot, specIdOrPrefix, config = DEFAULT_CONFIG) {
|
|
178
|
+
const { folderPath, location } = await resolveSpecFolder(projectRoot, specIdOrPrefix, config);
|
|
179
|
+
return buildSpecDetails(projectRoot, folderPath, location, config);
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Builds the complete change detail for an already resolved folder in any of
|
|
183
|
+
* the three canonical locations. Selector discovery stays with the caller.
|
|
184
|
+
*/
|
|
185
|
+
export async function getSpecDetailsFromFolder(projectRoot, folderPath, location, config = DEFAULT_CONFIG) {
|
|
186
|
+
return buildSpecDetails(projectRoot, folderPath, location, config);
|
|
187
|
+
}
|
|
188
|
+
async function buildSpecDetails(projectRoot, folderPath, location, _config) {
|
|
189
|
+
const isArchived = location === 'archived';
|
|
190
|
+
const folderName = path.basename(folderPath);
|
|
191
|
+
const idMatch = folderName.match(/^(\d+)/);
|
|
192
|
+
const id = idMatch ? idMatch[1] : folderName;
|
|
193
|
+
const specData = await parseSpecMdFromFolder(folderPath);
|
|
194
|
+
if (!specData) {
|
|
195
|
+
throw new Error(`Neither proposal.md nor spec.md found in ${folderPath}`);
|
|
196
|
+
}
|
|
197
|
+
// Capability writes are declared solely by delta spec folders under `specs/`.
|
|
198
|
+
const deltasDir = path.join(folderPath, 'specs');
|
|
199
|
+
const writtenCapabilities = (await fs.readdir(deltasDir, { withFileTypes: true }).catch(() => []))
|
|
200
|
+
.filter((entry) => entry.isDirectory())
|
|
201
|
+
.map((entry) => entry.name)
|
|
202
|
+
.sort();
|
|
203
|
+
const runDir = path.join(folderPath, '.run');
|
|
204
|
+
const approvedPath = path.join(runDir, 'approved');
|
|
205
|
+
let approvedHash = null;
|
|
206
|
+
try {
|
|
207
|
+
const hashContent = await fs.readFile(approvedPath, 'utf8');
|
|
208
|
+
approvedHash = hashContent.trim() || null;
|
|
209
|
+
}
|
|
210
|
+
catch { }
|
|
211
|
+
// Correlated planning lifecycle pairs in start order. A malformed or missing
|
|
212
|
+
// log yields an empty list and never blocks the remaining details.
|
|
213
|
+
const planningSessions = (await readPlanningSessions(folderPath)).flatMap((session) => {
|
|
214
|
+
const started = session.started;
|
|
215
|
+
if (!started)
|
|
216
|
+
return [];
|
|
217
|
+
return [
|
|
218
|
+
{
|
|
219
|
+
sessionId: session.sessionId,
|
|
220
|
+
startTime: started.timestamp,
|
|
221
|
+
harness: started.data.harness,
|
|
222
|
+
model: started.data.model,
|
|
223
|
+
...(started.data.agent ? { agent: started.data.agent } : {}),
|
|
224
|
+
exitCode: session.exited?.data.exitCode ?? null,
|
|
225
|
+
wallSeconds: session.exited?.data.wallSeconds ?? null,
|
|
226
|
+
},
|
|
227
|
+
];
|
|
228
|
+
});
|
|
229
|
+
const tasksDir = path.join(folderPath, 'tasks');
|
|
230
|
+
let taskEntries = [];
|
|
231
|
+
try {
|
|
232
|
+
taskEntries = (await fs.readdir(tasksDir))
|
|
233
|
+
.filter((e) => e.endsWith('.md'))
|
|
234
|
+
.sort((a, b) => {
|
|
235
|
+
const numA = Number.parseInt(a, 10);
|
|
236
|
+
const numB = Number.parseInt(b, 10);
|
|
237
|
+
if (!Number.isNaN(numA) && !Number.isNaN(numB)) {
|
|
238
|
+
return numA - numB;
|
|
239
|
+
}
|
|
240
|
+
return a.localeCompare(b);
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
catch { }
|
|
244
|
+
// Parse events
|
|
245
|
+
const eventsDir = path.join(runDir, 'events');
|
|
246
|
+
let eventFiles = [];
|
|
247
|
+
try {
|
|
248
|
+
eventFiles = (await fs.readdir(eventsDir))
|
|
249
|
+
.filter((e) => e.endsWith('.jsonl'))
|
|
250
|
+
.sort((a, b) => {
|
|
251
|
+
const numA = Number.parseInt(a, 10);
|
|
252
|
+
const numB = Number.parseInt(b, 10);
|
|
253
|
+
if (!Number.isNaN(numA) && !Number.isNaN(numB)) {
|
|
254
|
+
return numA - numB;
|
|
255
|
+
}
|
|
256
|
+
return a.localeCompare(b);
|
|
257
|
+
});
|
|
258
|
+
}
|
|
259
|
+
catch { }
|
|
260
|
+
const taskEventsMap = new Map();
|
|
261
|
+
const timeline = [];
|
|
262
|
+
// Typed recertification decisions from numbered task streams only, kept with
|
|
263
|
+
// their original stream order so ties break deterministically.
|
|
264
|
+
const recertificationEvents = [];
|
|
265
|
+
let eventSeq = 0;
|
|
266
|
+
for (const eventFile of eventFiles) {
|
|
267
|
+
const taskNum = path.basename(eventFile, '.jsonl');
|
|
268
|
+
const eventFilePath = path.join(eventsDir, eventFile);
|
|
269
|
+
try {
|
|
270
|
+
const fileContent = await fs.readFile(eventFilePath, 'utf8');
|
|
271
|
+
const lines = fileContent.split('\n');
|
|
272
|
+
const taskEvents = [];
|
|
273
|
+
for (const line of lines) {
|
|
274
|
+
const trimmed = line.trim();
|
|
275
|
+
if (!trimmed)
|
|
276
|
+
continue;
|
|
277
|
+
try {
|
|
278
|
+
const parsed = JSON.parse(trimmed);
|
|
279
|
+
const event = {
|
|
280
|
+
taskNumber: String(parsed.taskNumber || taskNum),
|
|
281
|
+
type: String(parsed.type || 'unknown'),
|
|
282
|
+
timestamp: String(parsed.timestamp || ''),
|
|
283
|
+
data: typeof parsed.data === 'object' && parsed.data !== null
|
|
284
|
+
? parsed.data
|
|
285
|
+
: undefined,
|
|
286
|
+
};
|
|
287
|
+
taskEvents.push(event);
|
|
288
|
+
timeline.push(event);
|
|
289
|
+
if (event.type === 'recertification' && /^\d+$/.test(taskNum)) {
|
|
290
|
+
recertificationEvents.push({ seq: eventSeq, streamTask: taskNum, event });
|
|
291
|
+
}
|
|
292
|
+
eventSeq++;
|
|
293
|
+
}
|
|
294
|
+
catch { }
|
|
295
|
+
}
|
|
296
|
+
taskEventsMap.set(taskNum, taskEvents);
|
|
297
|
+
}
|
|
298
|
+
catch { }
|
|
299
|
+
}
|
|
300
|
+
// Sort overall timeline chronologically
|
|
301
|
+
timeline.sort((a, b) => {
|
|
302
|
+
const timeA = new Date(a.timestamp).getTime();
|
|
303
|
+
const timeB = new Date(b.timestamp).getTime();
|
|
304
|
+
if (!Number.isNaN(timeA) && !Number.isNaN(timeB) && timeA !== timeB) {
|
|
305
|
+
return timeA - timeB;
|
|
306
|
+
}
|
|
307
|
+
return a.timestamp.localeCompare(b.timestamp);
|
|
308
|
+
});
|
|
309
|
+
const recertifications = recertificationEvents
|
|
310
|
+
.map(({ seq, streamTask, event }) => ({
|
|
311
|
+
seq,
|
|
312
|
+
row: buildRecertification(numericTaskTarget(event.data?.task) ?? streamTask, event),
|
|
313
|
+
}))
|
|
314
|
+
.sort((a, b) => {
|
|
315
|
+
const timeA = a.row.timestamp ? new Date(a.row.timestamp).getTime() : null;
|
|
316
|
+
const timeB = b.row.timestamp ? new Date(b.row.timestamp).getTime() : null;
|
|
317
|
+
if (timeA !== null && timeB !== null && timeA !== timeB) {
|
|
318
|
+
return timeA - timeB;
|
|
319
|
+
}
|
|
320
|
+
const numA = Number.parseInt(a.row.taskNumber, 10);
|
|
321
|
+
const numB = Number.parseInt(b.row.taskNumber, 10);
|
|
322
|
+
if (numA !== numB) {
|
|
323
|
+
return numA - numB;
|
|
324
|
+
}
|
|
325
|
+
return a.seq - b.seq;
|
|
326
|
+
})
|
|
327
|
+
.map((entry) => entry.row);
|
|
328
|
+
const tasks = [];
|
|
329
|
+
for (const taskFileName of taskEntries) {
|
|
330
|
+
const taskNumber = taskFileName.replace(/\.md$/, '');
|
|
331
|
+
const taskPath = path.join(tasksDir, taskFileName);
|
|
332
|
+
const taskContent = await fs.readFile(taskPath, 'utf8');
|
|
333
|
+
const taskData = parseTaskMd(taskContent);
|
|
334
|
+
// Derive task status
|
|
335
|
+
let status = 'pending';
|
|
336
|
+
const donePath = path.join(runDir, 'done', taskNumber);
|
|
337
|
+
const isDone = await fs
|
|
338
|
+
.stat(donePath)
|
|
339
|
+
.then(() => true)
|
|
340
|
+
.catch(() => false);
|
|
341
|
+
const deadPath = path.join(runDir, 'dead', `${taskNumber}.md`);
|
|
342
|
+
let deadReason;
|
|
343
|
+
let deadDiagnostic;
|
|
344
|
+
let regressedReason;
|
|
345
|
+
let regressedDiagnostic;
|
|
346
|
+
const regressedPath = path.join(runDir, 'regressed', `${taskNumber}.md`);
|
|
347
|
+
const regressedContent = await fs.readFile(regressedPath, 'utf8').catch(() => null);
|
|
348
|
+
const deadContent = await fs.readFile(deadPath, 'utf8').catch(() => null);
|
|
349
|
+
if (regressedContent !== null) {
|
|
350
|
+
status = 'regressed';
|
|
351
|
+
const parsedRegressed = parseFrontmatter(regressedContent);
|
|
352
|
+
regressedReason =
|
|
353
|
+
typeof parsedRegressed.data.reason === 'string' ? parsedRegressed.data.reason : undefined;
|
|
354
|
+
regressedDiagnostic = parsedRegressed.body.trim() || undefined;
|
|
355
|
+
}
|
|
356
|
+
else if (deadContent !== null) {
|
|
357
|
+
status = 'dead';
|
|
358
|
+
const parsedDead = parseFrontmatter(deadContent);
|
|
359
|
+
deadReason = typeof parsedDead.data.reason === 'string' ? parsedDead.data.reason : undefined;
|
|
360
|
+
deadDiagnostic = parsedDead.body.trim() || undefined;
|
|
361
|
+
}
|
|
362
|
+
else if (isDone) {
|
|
363
|
+
status = 'done';
|
|
364
|
+
}
|
|
365
|
+
else {
|
|
366
|
+
const runningPath = path.join(runDir, 'running', `${taskNumber}.pid`);
|
|
367
|
+
const isRunning = await fs
|
|
368
|
+
.stat(runningPath)
|
|
369
|
+
.then(() => true)
|
|
370
|
+
.catch(() => false);
|
|
371
|
+
if (isRunning) {
|
|
372
|
+
status = 'running';
|
|
373
|
+
}
|
|
374
|
+
else {
|
|
375
|
+
status = 'pending';
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
// Read result file if present
|
|
379
|
+
const resultPath = path.join(runDir, 'results', `${taskNumber}.md`);
|
|
380
|
+
let resultContent;
|
|
381
|
+
const rawResult = await fs.readFile(resultPath, 'utf8').catch(() => null);
|
|
382
|
+
if (rawResult !== null) {
|
|
383
|
+
resultContent = rawResult.trim() || undefined;
|
|
384
|
+
}
|
|
385
|
+
const taskEvents = taskEventsMap.get(taskNumber) || [];
|
|
386
|
+
tasks.push({
|
|
387
|
+
taskNumber,
|
|
388
|
+
fileName: taskFileName,
|
|
389
|
+
title: taskData.title,
|
|
390
|
+
status,
|
|
391
|
+
verify: taskData.verify,
|
|
392
|
+
scope: taskData.scope,
|
|
393
|
+
entry: taskData.entry,
|
|
394
|
+
skills: taskData.skills,
|
|
395
|
+
acceptance: taskData.acceptance,
|
|
396
|
+
deadReason,
|
|
397
|
+
deadDiagnostic,
|
|
398
|
+
regressedReason,
|
|
399
|
+
regressedDiagnostic,
|
|
400
|
+
resultContent,
|
|
401
|
+
events: taskEvents,
|
|
402
|
+
});
|
|
403
|
+
}
|
|
404
|
+
// Derive spec status
|
|
405
|
+
let status = 'pending';
|
|
406
|
+
if (isArchived) {
|
|
407
|
+
status = 'done';
|
|
408
|
+
}
|
|
409
|
+
else if (!approvedHash) {
|
|
410
|
+
status = 'unapproved';
|
|
411
|
+
}
|
|
412
|
+
else if (tasks.some((t) => t.status === 'regressed')) {
|
|
413
|
+
status = 'regressed';
|
|
414
|
+
}
|
|
415
|
+
else if (tasks.some((t) => t.status === 'dead')) {
|
|
416
|
+
status = 'dead';
|
|
417
|
+
}
|
|
418
|
+
else if (tasks.some((t) => t.status === 'running')) {
|
|
419
|
+
status = 'running';
|
|
420
|
+
}
|
|
421
|
+
else if (tasks.length > 0 && tasks.every((t) => t.status === 'done')) {
|
|
422
|
+
status = 'done';
|
|
423
|
+
}
|
|
424
|
+
else {
|
|
425
|
+
try {
|
|
426
|
+
const derived = await deriveSpecState(projectRoot, folderPath);
|
|
427
|
+
status = derived.status;
|
|
428
|
+
}
|
|
429
|
+
catch {
|
|
430
|
+
status = 'pending';
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
return {
|
|
434
|
+
id,
|
|
435
|
+
folderName,
|
|
436
|
+
folderPath,
|
|
437
|
+
isArchived,
|
|
438
|
+
location,
|
|
439
|
+
title: specData.title,
|
|
440
|
+
status,
|
|
441
|
+
approvedHash,
|
|
442
|
+
dependsOn: specData.dependsOn,
|
|
443
|
+
features: { reads: specData.features.reads, writes: writtenCapabilities },
|
|
444
|
+
goal: specData.goal,
|
|
445
|
+
contract: specData.contract,
|
|
446
|
+
nonGoals: specData.nonGoals,
|
|
447
|
+
delta: specData.delta,
|
|
448
|
+
tasks,
|
|
449
|
+
planningSessions,
|
|
450
|
+
recertifications,
|
|
451
|
+
timeline,
|
|
452
|
+
};
|
|
453
|
+
}
|
|
454
|
+
/**
|
|
455
|
+
* Projects the latest pre-spawn `verify_ran` event of one task into the
|
|
456
|
+
* `Pre-spawn verify:` show line. Returns null when the task recorded no
|
|
457
|
+
* pre-spawn result, so output for every other task stays unchanged. Only the
|
|
458
|
+
* already parsed event stream is read; missing or malformed values render as
|
|
459
|
+
* unavailable rather than being guessed.
|
|
460
|
+
*/
|
|
461
|
+
function formatPreSpawnVerify(events) {
|
|
462
|
+
let latest;
|
|
463
|
+
for (const event of events) {
|
|
464
|
+
if (event.type === 'verify_ran' && event.data?.phase === 'pre_spawn') {
|
|
465
|
+
latest = event;
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
if (!latest)
|
|
469
|
+
return null;
|
|
470
|
+
const data = latest.data ?? {};
|
|
471
|
+
const exitCode = typeof data.exitCode === 'number' && Number.isFinite(data.exitCode)
|
|
472
|
+
? String(data.exitCode)
|
|
473
|
+
: 'unavailable';
|
|
474
|
+
const expected = typeof data.expected === 'string' && data.expected.trim() !== ''
|
|
475
|
+
? data.expected.trim()
|
|
476
|
+
: 'unavailable';
|
|
477
|
+
const outcome = data.mismatch === true ? 'mismatch' : 'matched';
|
|
478
|
+
const missing = formatMissingPaths(data.missingPaths);
|
|
479
|
+
return ` Pre-spawn verify: exit ${exitCode}, expected ${expected}, ${outcome}${missing ?? ''}`;
|
|
480
|
+
}
|
|
481
|
+
/**
|
|
482
|
+
* Renders the `missing <path>, <path>` suffix for a pre-spawn event's recorded
|
|
483
|
+
* missing named paths. Only a non-empty array whose every entry is a non-empty
|
|
484
|
+
* string qualifies, so an empty, absent, or malformed value contributes nothing
|
|
485
|
+
* and leaves the pre-spawn line exactly as it was.
|
|
486
|
+
*/
|
|
487
|
+
function formatMissingPaths(value) {
|
|
488
|
+
if (!Array.isArray(value) || value.length === 0)
|
|
489
|
+
return null;
|
|
490
|
+
if (!value.every((entry) => typeof entry === 'string' && entry.trim() !== '')) {
|
|
491
|
+
return null;
|
|
492
|
+
}
|
|
493
|
+
return `, missing ${value.map((entry) => entry.trim()).join(', ')}`;
|
|
494
|
+
}
|
|
495
|
+
/**
|
|
496
|
+
* Counts a task's `retry` events split into total and automatic. Automatic
|
|
497
|
+
* retries are exactly those whose event data carries `automatic: true`.
|
|
498
|
+
* Returns null when the task recorded no retry, so every other task's output
|
|
499
|
+
* stays unchanged.
|
|
500
|
+
*/
|
|
501
|
+
function retryCounts(events) {
|
|
502
|
+
let total = 0;
|
|
503
|
+
let automatic = 0;
|
|
504
|
+
for (const event of events) {
|
|
505
|
+
if (event.type !== 'retry')
|
|
506
|
+
continue;
|
|
507
|
+
total += 1;
|
|
508
|
+
if (event.data?.automatic === true)
|
|
509
|
+
automatic += 1;
|
|
510
|
+
}
|
|
511
|
+
return total > 0 ? { total, automatic } : null;
|
|
512
|
+
}
|
|
513
|
+
/** Projects a task's `retry` events into the `Retries:` line, or null. */
|
|
514
|
+
function formatRetries(events) {
|
|
515
|
+
const counts = retryCounts(events);
|
|
516
|
+
if (!counts)
|
|
517
|
+
return null;
|
|
518
|
+
return ` Retries: ${counts.total} (${counts.automatic} automatic)`;
|
|
519
|
+
}
|
|
520
|
+
/**
|
|
521
|
+
* Projects the task's latest `stuck` event into the `Stuck:` line, but only
|
|
522
|
+
* while it is still the task's current state. A later `retry` event means a
|
|
523
|
+
* human already retried the task, so the line disappears. Returns null when
|
|
524
|
+
* the task recorded no stuck event or is no longer stuck.
|
|
525
|
+
*/
|
|
526
|
+
function formatStuck(events) {
|
|
527
|
+
let stuck;
|
|
528
|
+
let stuckIndex = -1;
|
|
529
|
+
let lastRetry = -1;
|
|
530
|
+
for (let index = 0; index < events.length; index += 1) {
|
|
531
|
+
const event = events[index];
|
|
532
|
+
if (event.type === 'retry') {
|
|
533
|
+
lastRetry = index;
|
|
534
|
+
}
|
|
535
|
+
else if (event.type === 'stuck') {
|
|
536
|
+
stuck = event;
|
|
537
|
+
stuckIndex = index;
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
if (!stuck || lastRetry > stuckIndex)
|
|
541
|
+
return null;
|
|
542
|
+
const fingerprint = typeof stuck.data?.fingerprint === 'string' && stuck.data.fingerprint.trim() !== ''
|
|
543
|
+
? stuck.data.fingerprint.trim()
|
|
544
|
+
: 'unavailable';
|
|
545
|
+
return ` Stuck: same failure twice (${fingerprint})`;
|
|
546
|
+
}
|
|
547
|
+
function formatEventData(data) {
|
|
548
|
+
if (!data || Object.keys(data).length === 0)
|
|
549
|
+
return '';
|
|
550
|
+
const entries = Object.entries(data).map(([k, v]) => `${k}: ${v}`);
|
|
551
|
+
return ` (${entries.join(', ')})`;
|
|
552
|
+
}
|
|
553
|
+
export function formatSpecDetails(details) {
|
|
554
|
+
const lines = [];
|
|
555
|
+
const location = details.isArchived ? 'archived' : 'active';
|
|
556
|
+
const approval = details.approvedHash ? `approved (${details.approvedHash})` : 'unapproved';
|
|
557
|
+
lines.push(`Spec: ${details.folderName} (${details.id})`);
|
|
558
|
+
lines.push(`Title: ${details.title}`);
|
|
559
|
+
lines.push(`Status: [${details.status}]`);
|
|
560
|
+
lines.push(`Location: ${location}`);
|
|
561
|
+
lines.push(`Approval: ${approval}`);
|
|
562
|
+
const dependsOnStr = details.dependsOn.length > 0 ? details.dependsOn.join(', ') : 'none';
|
|
563
|
+
lines.push(`Depends on: ${dependsOnStr}`);
|
|
564
|
+
lines.push('Features:');
|
|
565
|
+
const readsStr = details.features.reads.length > 0 ? details.features.reads.join(', ') : 'none';
|
|
566
|
+
const writesStr = details.features.writes.length > 0 ? details.features.writes.join(', ') : 'none';
|
|
567
|
+
lines.push(` Reads: ${readsStr}`);
|
|
568
|
+
lines.push(` Writes: ${writesStr}`);
|
|
569
|
+
if (details.goal) {
|
|
570
|
+
lines.push('');
|
|
571
|
+
lines.push('Goal:');
|
|
572
|
+
const goalLines = details.goal.split('\n');
|
|
573
|
+
for (const gLine of goalLines) {
|
|
574
|
+
lines.push(` ${gLine}`);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
if (details.contract) {
|
|
578
|
+
lines.push('');
|
|
579
|
+
lines.push('Contract:');
|
|
580
|
+
const contractLines = details.contract.split('\n');
|
|
581
|
+
for (const cLine of contractLines) {
|
|
582
|
+
lines.push(` ${cLine}`);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
lines.push('');
|
|
586
|
+
lines.push('Tasks:');
|
|
587
|
+
if (details.tasks.length === 0) {
|
|
588
|
+
lines.push(' (no tasks)');
|
|
589
|
+
}
|
|
590
|
+
else {
|
|
591
|
+
for (const task of details.tasks) {
|
|
592
|
+
let indicator = '[ ]';
|
|
593
|
+
if (task.status === 'done') {
|
|
594
|
+
indicator = '[x]';
|
|
595
|
+
}
|
|
596
|
+
else if (task.status === 'running') {
|
|
597
|
+
indicator = '[>]';
|
|
598
|
+
}
|
|
599
|
+
else if (task.status === 'dead') {
|
|
600
|
+
indicator = '[!]';
|
|
601
|
+
}
|
|
602
|
+
const deadTag = task.deadReason ? ` (reason: ${task.deadReason})` : '';
|
|
603
|
+
lines.push(` ${indicator} ${task.taskNumber}. ${task.title} [${task.status}]${deadTag}`);
|
|
604
|
+
if (task.verify) {
|
|
605
|
+
lines.push(` Verify: ${task.verify}`);
|
|
606
|
+
}
|
|
607
|
+
const preSpawnVerify = formatPreSpawnVerify(task.events);
|
|
608
|
+
if (preSpawnVerify) {
|
|
609
|
+
lines.push(preSpawnVerify);
|
|
610
|
+
}
|
|
611
|
+
const retries = formatRetries(task.events);
|
|
612
|
+
if (retries) {
|
|
613
|
+
lines.push(retries);
|
|
614
|
+
}
|
|
615
|
+
const stuck = formatStuck(task.events);
|
|
616
|
+
if (stuck) {
|
|
617
|
+
lines.push(stuck);
|
|
618
|
+
}
|
|
619
|
+
if (task.scope.length > 0) {
|
|
620
|
+
lines.push(` Scope: ${task.scope.join(', ')}`);
|
|
621
|
+
}
|
|
622
|
+
if (task.acceptance.length > 0) {
|
|
623
|
+
lines.push(' Acceptance:');
|
|
624
|
+
for (const item of task.acceptance) {
|
|
625
|
+
const itemIndicator = task.status === 'done' ? '[x]' : '[ ]';
|
|
626
|
+
lines.push(` - ${itemIndicator} ${item}`);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
if (task.deadDiagnostic) {
|
|
630
|
+
lines.push(' Failure diagnostic:');
|
|
631
|
+
const diagLines = task.deadDiagnostic.split('\n');
|
|
632
|
+
for (const dLine of diagLines) {
|
|
633
|
+
lines.push(` ${dLine}`);
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
if (task.resultContent) {
|
|
637
|
+
lines.push(' Result:');
|
|
638
|
+
const resLines = task.resultContent.split('\n');
|
|
639
|
+
for (const rLine of resLines) {
|
|
640
|
+
lines.push(` ${rLine}`);
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
lines.push('');
|
|
646
|
+
lines.push('Planning Sessions:');
|
|
647
|
+
if (details.planningSessions.length === 0) {
|
|
648
|
+
lines.push(' (no planning sessions)');
|
|
649
|
+
}
|
|
650
|
+
else {
|
|
651
|
+
for (const session of details.planningSessions) {
|
|
652
|
+
const agent = session.agent ? ` agent: ${session.agent}` : '';
|
|
653
|
+
const model = session.model ?? 'unavailable';
|
|
654
|
+
const exit = session.exitCode === null ? 'unavailable' : String(session.exitCode);
|
|
655
|
+
const wall = session.wallSeconds === null ? 'unavailable' : formatDuration(session.wallSeconds * 1000);
|
|
656
|
+
lines.push(` ${session.startTime} ${session.harness}/${model}${agent} exit: ${exit} wall: ${wall}`);
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
// Derived, append-only recertification view. It is rendered only when typed
|
|
660
|
+
// decisions exist and never replaces the raw event timeline below.
|
|
661
|
+
if (details.recertifications.length > 0) {
|
|
662
|
+
lines.push('');
|
|
663
|
+
lines.push('Recertifications:');
|
|
664
|
+
for (const row of details.recertifications) {
|
|
665
|
+
const label = row.outcome === 'passed'
|
|
666
|
+
? 'recertified'
|
|
667
|
+
: row.outcome === 'requeued'
|
|
668
|
+
? 'requeued for agent work'
|
|
669
|
+
: 'unavailable';
|
|
670
|
+
lines.push(` Task ${row.taskNumber} ${row.timestamp ?? 'unavailable'} [${label}]`);
|
|
671
|
+
lines.push(` Verify: ${row.verify ?? 'unavailable'}`);
|
|
672
|
+
lines.push(` Exit code: ${row.exitCode ?? 'unavailable'}`);
|
|
673
|
+
lines.push(` Timed out: ${row.timedOut === null ? 'unavailable' : row.timedOut ? 'yes' : 'no'}`);
|
|
674
|
+
if (row.attribution.length > 0) {
|
|
675
|
+
lines.push(' Differing paths:');
|
|
676
|
+
for (const entry of row.attribution) {
|
|
677
|
+
const attribution = entry.attribution === 'ambiguous' || entry.attribution === 'unknown'
|
|
678
|
+
? entry.attribution
|
|
679
|
+
: `attributed to task ${entry.attribution}`;
|
|
680
|
+
lines.push(` - ${entry.path} — ${attribution}`);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
lines.push('');
|
|
686
|
+
lines.push('Event Timeline:');
|
|
687
|
+
if (details.timeline.length === 0) {
|
|
688
|
+
lines.push(' (no events recorded)');
|
|
689
|
+
}
|
|
690
|
+
else {
|
|
691
|
+
for (const event of details.timeline) {
|
|
692
|
+
const eventData = formatEventData(event.data);
|
|
693
|
+
lines.push(` ${event.timestamp} [Task ${event.taskNumber}] ${event.type}${eventData}`);
|
|
694
|
+
}
|
|
695
|
+
}
|
|
696
|
+
return lines.join('\n');
|
|
697
|
+
}
|
|
698
|
+
/**
|
|
699
|
+
* Alias for {@link formatSpecDetails} matching the show-output name used by
|
|
700
|
+
* the status-inspection spec. Displays the dead reason (including
|
|
701
|
+
* `undeclared_test_change`) and its failure diagnostic.
|
|
702
|
+
*/
|
|
703
|
+
export const formatShowOutput = formatSpecDetails;
|
|
704
|
+
//# sourceMappingURL=show.js.map
|