okengine 0.1.4
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/AGENTS.md +91 -0
- package/README.md +327 -0
- package/docs/spec/complete-example.md +1188 -0
- package/docs/spec/console.md +739 -0
- package/docs/spec/four-applications.md +1188 -0
- package/docs/spec/unified-theory.md +489 -0
- package/package.json +152 -0
- package/spec/manifest.v1.schema.json +624 -0
- package/src/auth/api-keys.ts +168 -0
- package/src/auth/attenuation.ts +116 -0
- package/src/auth/auth.test.ts +273 -0
- package/src/auth/cross-plane.ts +98 -0
- package/src/auth/index.ts +112 -0
- package/src/auth/invites.ts +66 -0
- package/src/auth/invoke-as.ts +49 -0
- package/src/auth/operator.ts +178 -0
- package/src/auth/planes.ts +102 -0
- package/src/auth/plugin.ts +44 -0
- package/src/auth/roles.ts +84 -0
- package/src/auth/sessions.ts +418 -0
- package/src/auth/tables.ts +131 -0
- package/src/cli/args.ts +50 -0
- package/src/cli/branch.ts +75 -0
- package/src/cli/build.ts +86 -0
- package/src/cli/client-add.test.ts +140 -0
- package/src/cli/client-add.ts +164 -0
- package/src/cli/completion.test.ts +58 -0
- package/src/cli/completion.ts +296 -0
- package/src/cli/dev-app-runner.ts +77 -0
- package/src/cli/dev.test.ts +435 -0
- package/src/cli/dev.ts +594 -0
- package/src/cli/doc-drift.test.ts +146 -0
- package/src/cli/doc-drift.ts +397 -0
- package/src/cli/docker-cli.test.ts +221 -0
- package/src/cli/docker.ts +127 -0
- package/src/cli/doctor-diff-examples.ts +92 -0
- package/src/cli/doctor-diff.test.ts +91 -0
- package/src/cli/doctor-diff.ts +274 -0
- package/src/cli/doctor-pii.test.ts +98 -0
- package/src/cli/doctor-pii.ts +151 -0
- package/src/cli/doctor.test.ts +150 -0
- package/src/cli/doctor.ts +223 -0
- package/src/cli/eval.ts +122 -0
- package/src/cli/exit.ts +19 -0
- package/src/cli/gates-list.test.ts +47 -0
- package/src/cli/gates-list.ts +84 -0
- package/src/cli/images.ts +277 -0
- package/src/cli/index.ts +99 -0
- package/src/cli/json-out.test.ts +129 -0
- package/src/cli/load-config.ts +71 -0
- package/src/cli/mcp-from-console.ts +50 -0
- package/src/cli/privacy-erase.ts +73 -0
- package/src/cli/registry.ts +455 -0
- package/src/cli/safe-defaults.test.ts +92 -0
- package/src/cli/schema.ts +196 -0
- package/src/cli/stack.ts +82 -0
- package/src/cli/start.ts +106 -0
- package/src/cli/upgrade.ts +105 -0
- package/src/cli/vault-cmd.ts +140 -0
- package/src/client/budget-entry.ts +34 -0
- package/src/client/budget.test.ts +17 -0
- package/src/client/create.test.ts +159 -0
- package/src/client/create.ts +152 -0
- package/src/client/errors.ts +60 -0
- package/src/client/index.ts +35 -0
- package/src/client/notes-contract.test.ts +289 -0
- package/src/client/transport.test.ts +123 -0
- package/src/client/transport.ts +254 -0
- package/src/client/types.ts +282 -0
- package/src/compiler/aot.test.ts +248 -0
- package/src/compiler/aot.ts +182 -0
- package/src/compiler/differential.test.ts +241 -0
- package/src/compiler/dynamic.ts +54 -0
- package/src/compiler/effects-infer.ts +541 -0
- package/src/compiler/emit.ts +40 -0
- package/src/compiler/extract.test.ts +177 -0
- package/src/compiler/extract.ts +1368 -0
- package/src/compiler/fixtures/raw/raw-unannotated.ts +28 -0
- package/src/compiler/fixtures/skyport/oke.config.ts +24 -0
- package/src/compiler/fixtures/skyport/src/ai.ts +15 -0
- package/src/compiler/fixtures/skyport/src/app.ts +10 -0
- package/src/compiler/fixtures/skyport/src/channels.ts +6 -0
- package/src/compiler/fixtures/skyport/src/core.ts +3 -0
- package/src/compiler/fixtures/skyport/src/flows/bookings/index.ts +57 -0
- package/src/compiler/fixtures/skyport/src/flows/bookings/signals.ts +11 -0
- package/src/compiler/fixtures/skyport/src/flows/payments/index.ts +14 -0
- package/src/compiler/fixtures/skyport/src/flows/support/index.ts +20 -0
- package/src/compiler/fixtures/skyport/src/gates.ts +14 -0
- package/src/compiler/fixtures/skyport/src/journeys.ts +9 -0
- package/src/compiler/fixtures/skyport/src/schema.ts +3 -0
- package/src/compiler/fixtures/skyport/src/vault.ts +6 -0
- package/src/compiler/fixtures/skyport.expected.json +241 -0
- package/src/compiler/fixtures/triggers/five-triggers.ts +69 -0
- package/src/compiler/http-parse.ts +214 -0
- package/src/compiler/index.ts +67 -0
- package/src/compiler/response.ts +89 -0
- package/src/compiler/sucrose.ts +238 -0
- package/src/config/index.ts +167 -0
- package/src/console/budget.test.ts +73 -0
- package/src/console/index.ts +30 -0
- package/src/console/server/access.test.ts +370 -0
- package/src/console/server/access.ts +777 -0
- package/src/console/server/ai.test.ts +172 -0
- package/src/console/server/ai.ts +632 -0
- package/src/console/server/app.ts +294 -0
- package/src/console/server/auth-rate.test.ts +81 -0
- package/src/console/server/auth-rate.ts +72 -0
- package/src/console/server/bind.ts +25 -0
- package/src/console/server/channels.test.ts +179 -0
- package/src/console/server/channels.ts +469 -0
- package/src/console/server/claim.test.ts +66 -0
- package/src/console/server/claim.ts +134 -0
- package/src/console/server/clock.test.ts +239 -0
- package/src/console/server/clock.ts +390 -0
- package/src/console/server/console.test.ts +338 -0
- package/src/console/server/diff.test.ts +299 -0
- package/src/console/server/diff.ts +352 -0
- package/src/console/server/dry-run.audit.test.ts +118 -0
- package/src/console/server/flows-invoke.test.ts +148 -0
- package/src/console/server/flows.ts +3633 -0
- package/src/console/server/gates.test.ts +360 -0
- package/src/console/server/gates.ts +869 -0
- package/src/console/server/index.ts +141 -0
- package/src/console/server/live.test.ts +30 -0
- package/src/console/server/live.ts +109 -0
- package/src/console/server/plugin.ts +50 -0
- package/src/console/server/plugins.test.ts +131 -0
- package/src/console/server/plugins.ts +429 -0
- package/src/console/server/runs-pii.ts +98 -0
- package/src/console/server/security-headers.ts +97 -0
- package/src/console/server/security.gate.test.ts +286 -0
- package/src/console/server/serve.ts +319 -0
- package/src/console/server/signals.test.ts +88 -0
- package/src/console/server/signals.ts +282 -0
- package/src/console/server/state.ts +982 -0
- package/src/console/server/store.test.ts +233 -0
- package/src/console/server/store.ts +861 -0
- package/src/console/server/structural.ts +95 -0
- package/src/console/server/vault.test.ts +251 -0
- package/src/console/server/vault.ts +430 -0
- package/src/console/ui/access/AccessA11yView.tsx +237 -0
- package/src/console/ui/access/a11y.test.tsx +122 -0
- package/src/console/ui/access/acknowledgement.test.ts +13 -0
- package/src/console/ui/access/acknowledgement.ts +35 -0
- package/src/console/ui/access/blast-radius.test.ts +26 -0
- package/src/console/ui/access/blast-radius.ts +40 -0
- package/src/console/ui/access/confirmation.test.ts +38 -0
- package/src/console/ui/access/confirmation.ts +36 -0
- package/src/console/ui/access/fixture.ts +203 -0
- package/src/console/ui/access/grantable.test.ts +17 -0
- package/src/console/ui/access/grantable.ts +36 -0
- package/src/console/ui/access/hygiene.test.ts +12 -0
- package/src/console/ui/access/hygiene.ts +39 -0
- package/src/console/ui/access/index.ts +54 -0
- package/src/console/ui/access/provenance.test.ts +12 -0
- package/src/console/ui/access/provenance.ts +29 -0
- package/src/console/ui/access/search.test.ts +17 -0
- package/src/console/ui/access/search.ts +72 -0
- package/src/console/ui/access/types.ts +111 -0
- package/src/console/ui/ai/AiA11yView.tsx +265 -0
- package/src/console/ui/ai/a11y.test.tsx +99 -0
- package/src/console/ui/ai/findings.ts +41 -0
- package/src/console/ui/ai/fixture.ts +182 -0
- package/src/console/ui/ai/format.ts +90 -0
- package/src/console/ui/ai/group.test.ts +37 -0
- package/src/console/ui/ai/group.ts +88 -0
- package/src/console/ui/ai/index.ts +66 -0
- package/src/console/ui/ai/promotion.test.ts +77 -0
- package/src/console/ui/ai/promotion.ts +150 -0
- package/src/console/ui/ai/search.test.ts +40 -0
- package/src/console/ui/ai/search.ts +89 -0
- package/src/console/ui/ai/types.ts +139 -0
- package/src/console/ui/architecture/ArchitectureA11yView.tsx +163 -0
- package/src/console/ui/architecture/a11y.test.tsx +97 -0
- package/src/console/ui/architecture/boundary.ts +42 -0
- package/src/console/ui/architecture/declared.ts +165 -0
- package/src/console/ui/architecture/fixture.ts +74 -0
- package/src/console/ui/architecture/index.ts +84 -0
- package/src/console/ui/architecture/layers.ts +64 -0
- package/src/console/ui/architecture/layout.ts +68 -0
- package/src/console/ui/architecture/pathologies.ts +260 -0
- package/src/console/ui/architecture/search.ts +145 -0
- package/src/console/ui/architecture/traffic.ts +102 -0
- package/src/console/ui/architecture/types.ts +144 -0
- package/src/console/ui/architecture/view.test.ts +165 -0
- package/src/console/ui/architecture/view.ts +516 -0
- package/src/console/ui/channels/ChannelsA11yView.tsx +180 -0
- package/src/console/ui/channels/a11y.test.tsx +96 -0
- package/src/console/ui/channels/confirmation.test.ts +37 -0
- package/src/console/ui/channels/confirmation.ts +27 -0
- package/src/console/ui/channels/fallback.test.ts +15 -0
- package/src/console/ui/channels/fallback.ts +20 -0
- package/src/console/ui/channels/findings.ts +38 -0
- package/src/console/ui/channels/fixture.ts +134 -0
- package/src/console/ui/channels/group.ts +25 -0
- package/src/console/ui/channels/index.ts +57 -0
- package/src/console/ui/channels/locale.test.ts +17 -0
- package/src/console/ui/channels/locale.ts +31 -0
- package/src/console/ui/channels/mask.test.ts +14 -0
- package/src/console/ui/channels/mask.ts +12 -0
- package/src/console/ui/channels/search.ts +58 -0
- package/src/console/ui/channels/taxonomy.test.ts +17 -0
- package/src/console/ui/channels/taxonomy.ts +49 -0
- package/src/console/ui/channels/types.ts +117 -0
- package/src/console/ui/clock/ClockA11yView.tsx +182 -0
- package/src/console/ui/clock/a11y.test.tsx +99 -0
- package/src/console/ui/clock/confirmation.test.ts +32 -0
- package/src/console/ui/clock/confirmation.ts +34 -0
- package/src/console/ui/clock/findings.ts +40 -0
- package/src/console/ui/clock/fixture.ts +111 -0
- package/src/console/ui/clock/health.test.ts +25 -0
- package/src/console/ui/clock/health.ts +61 -0
- package/src/console/ui/clock/index.ts +49 -0
- package/src/console/ui/clock/search.test.ts +39 -0
- package/src/console/ui/clock/search.ts +76 -0
- package/src/console/ui/clock/timeline.test.ts +44 -0
- package/src/console/ui/clock/timeline.ts +41 -0
- package/src/console/ui/clock/types.ts +78 -0
- package/src/console/ui/clock/waiting-on.test.ts +34 -0
- package/src/console/ui/clock/waiting-on.ts +83 -0
- package/src/console/ui/confirmation.unify.test.ts +92 -0
- package/src/console/ui/diff/DiffA11yView.tsx +85 -0
- package/src/console/ui/diff/a11y.test.tsx +99 -0
- package/src/console/ui/diff/fixture.ts +85 -0
- package/src/console/ui/diff/group.test.ts +58 -0
- package/src/console/ui/diff/group.ts +97 -0
- package/src/console/ui/diff/index.ts +38 -0
- package/src/console/ui/diff/search.test.ts +32 -0
- package/src/console/ui/diff/search.ts +75 -0
- package/src/console/ui/diff/summary.ts +74 -0
- package/src/console/ui/diff/types.ts +48 -0
- package/src/console/ui/dist/assets/index-B71Yl_SS.js +10 -0
- package/src/console/ui/dist/assets/panel-access-Dd37LU2c.js +64 -0
- package/src/console/ui/dist/assets/panel-ai-CC7LR6-J.js +1 -0
- package/src/console/ui/dist/assets/panel-architecture-B5b3iKCz.js +1 -0
- package/src/console/ui/dist/assets/panel-channels-CeNjTKXp.js +1 -0
- package/src/console/ui/dist/assets/panel-clock-DgFTLoHV.js +1 -0
- package/src/console/ui/dist/assets/panel-diff-DxehccqB.js +1 -0
- package/src/console/ui/dist/assets/panel-flows-BtrVn-Eg.js +45 -0
- package/src/console/ui/dist/assets/panel-gates-Z9MKRGdH.js +1 -0
- package/src/console/ui/dist/assets/panel-overview-Bd48d9km.js +1 -0
- package/src/console/ui/dist/assets/panel-plugins-DWd0TowH.js +1 -0
- package/src/console/ui/dist/assets/panel-runs-BwsWqKeB.js +1 -0
- package/src/console/ui/dist/assets/panel-signals-9najbZY2.js +1 -0
- package/src/console/ui/dist/assets/panel-store-OHkP2pDp.js +1 -0
- package/src/console/ui/dist/assets/panel-traces-tn2JoY8U.js +1 -0
- package/src/console/ui/dist/assets/panel-vault-BbfWdox0.js +1 -0
- package/src/console/ui/dist/assets/rolldown-runtime-CNC7AqOf.js +1 -0
- package/src/console/ui/dist/assets/style-Cnl7WLya.css +3 -0
- package/src/console/ui/dist/index.html +14 -0
- package/src/console/ui/flows/FlowsA11yView.tsx +155 -0
- package/src/console/ui/flows/a11y.test.tsx +105 -0
- package/src/console/ui/flows/buffer.test.ts +91 -0
- package/src/console/ui/flows/buffer.ts +118 -0
- package/src/console/ui/flows/confirmation.ts +131 -0
- package/src/console/ui/flows/contract.test.ts +89 -0
- package/src/console/ui/flows/contract.ts +353 -0
- package/src/console/ui/flows/fixture.ts +81 -0
- package/src/console/ui/flows/graph.test.ts +101 -0
- package/src/console/ui/flows/graph.ts +549 -0
- package/src/console/ui/flows/index.ts +87 -0
- package/src/console/ui/flows/save-as-test.test.ts +47 -0
- package/src/console/ui/flows/save-as-test.ts +99 -0
- package/src/console/ui/flows/search.ts +255 -0
- package/src/console/ui/flows/tiers.ts +140 -0
- package/src/console/ui/gates/GatesA11yView.tsx +192 -0
- package/src/console/ui/gates/a11y.test.tsx +116 -0
- package/src/console/ui/gates/audit.test.ts +40 -0
- package/src/console/ui/gates/audit.ts +63 -0
- package/src/console/ui/gates/denial.test.ts +36 -0
- package/src/console/ui/gates/denial.ts +51 -0
- package/src/console/ui/gates/findings.ts +19 -0
- package/src/console/ui/gates/fixture.ts +189 -0
- package/src/console/ui/gates/group.test.ts +30 -0
- package/src/console/ui/gates/group.ts +102 -0
- package/src/console/ui/gates/index.ts +47 -0
- package/src/console/ui/gates/search.test.ts +49 -0
- package/src/console/ui/gates/search.ts +115 -0
- package/src/console/ui/gates/types.ts +121 -0
- package/src/console/ui/overview/OverviewA11yView.tsx +152 -0
- package/src/console/ui/overview/a11y.test.tsx +113 -0
- package/src/console/ui/overview/busiest.ts +26 -0
- package/src/console/ui/overview/compose.ts +133 -0
- package/src/console/ui/overview/cost.test.ts +39 -0
- package/src/console/ui/overview/cost.ts +138 -0
- package/src/console/ui/overview/fixture.ts +161 -0
- package/src/console/ui/overview/golden.ts +57 -0
- package/src/console/ui/overview/index.ts +59 -0
- package/src/console/ui/overview/rank.test.ts +136 -0
- package/src/console/ui/overview/rank.ts +210 -0
- package/src/console/ui/overview/slo.test.ts +73 -0
- package/src/console/ui/overview/slo.ts +229 -0
- package/src/console/ui/overview/types.ts +121 -0
- package/src/console/ui/overview/verdict.ts +131 -0
- package/src/console/ui/plugins/PluginsA11yView.tsx +227 -0
- package/src/console/ui/plugins/a11y.test.tsx +97 -0
- package/src/console/ui/plugins/command.test.ts +22 -0
- package/src/console/ui/plugins/command.ts +27 -0
- package/src/console/ui/plugins/findings.ts +39 -0
- package/src/console/ui/plugins/fixture.ts +233 -0
- package/src/console/ui/plugins/group.test.ts +38 -0
- package/src/console/ui/plugins/group.ts +67 -0
- package/src/console/ui/plugins/index.ts +40 -0
- package/src/console/ui/plugins/search.ts +67 -0
- package/src/console/ui/plugins/types.ts +115 -0
- package/src/console/ui/runs/RunsA11yView.tsx +267 -0
- package/src/console/ui/runs/a11y.test.tsx +99 -0
- package/src/console/ui/runs/explain.test.ts +23 -0
- package/src/console/ui/runs/explain.ts +32 -0
- package/src/console/ui/runs/fixture.ts +189 -0
- package/src/console/ui/runs/group.test.ts +24 -0
- package/src/console/ui/runs/group.ts +85 -0
- package/src/console/ui/runs/histogram.test.ts +31 -0
- package/src/console/ui/runs/histogram.ts +85 -0
- package/src/console/ui/runs/index.ts +75 -0
- package/src/console/ui/runs/project.ts +122 -0
- package/src/console/ui/runs/query.test.ts +50 -0
- package/src/console/ui/runs/query.ts +283 -0
- package/src/console/ui/runs/search.test.ts +45 -0
- package/src/console/ui/runs/search.ts +141 -0
- package/src/console/ui/runs/trace-link.test.ts +30 -0
- package/src/console/ui/runs/trace-link.ts +99 -0
- package/src/console/ui/runs/types.ts +137 -0
- package/src/console/ui/shell/App.tsx +56 -0
- package/src/console/ui/shell/client.ts +1715 -0
- package/src/console/ui/shell/components/ui.tsx +110 -0
- package/src/console/ui/shell/index.html +12 -0
- package/src/console/ui/shell/layout/Shell.tsx +95 -0
- package/src/console/ui/shell/main.tsx +281 -0
- package/src/console/ui/shell/panels/Access.tsx +5 -0
- package/src/console/ui/shell/panels/Ai.tsx +5 -0
- package/src/console/ui/shell/panels/Architecture.tsx +5 -0
- package/src/console/ui/shell/panels/Channels.tsx +5 -0
- package/src/console/ui/shell/panels/Clock.tsx +5 -0
- package/src/console/ui/shell/panels/Diff.tsx +5 -0
- package/src/console/ui/shell/panels/Flows.tsx +5 -0
- package/src/console/ui/shell/panels/Gates.tsx +5 -0
- package/src/console/ui/shell/panels/Overview.tsx +6 -0
- package/src/console/ui/shell/panels/Plugins.tsx +5 -0
- package/src/console/ui/shell/panels/Runs.tsx +5 -0
- package/src/console/ui/shell/panels/Signals.tsx +5 -0
- package/src/console/ui/shell/panels/Store.tsx +5 -0
- package/src/console/ui/shell/panels/Traces.tsx +5 -0
- package/src/console/ui/shell/panels/Vault.tsx +5 -0
- package/src/console/ui/shell/panels/access/AccessPanel.tsx +813 -0
- package/src/console/ui/shell/panels/ai/AiPanel.tsx +563 -0
- package/src/console/ui/shell/panels/architecture/ArchitecturePanel.tsx +377 -0
- package/src/console/ui/shell/panels/channels/ChannelsPanel.tsx +454 -0
- package/src/console/ui/shell/panels/clock/ClockPanel.tsx +479 -0
- package/src/console/ui/shell/panels/diff/DiffPanel.tsx +275 -0
- package/src/console/ui/shell/panels/flows/ContractEditor.tsx +301 -0
- package/src/console/ui/shell/panels/flows/FlowDrawer.tsx +350 -0
- package/src/console/ui/shell/panels/flows/FlowsPanel.tsx +502 -0
- package/src/console/ui/shell/panels/gates/GatesPanel.tsx +482 -0
- package/src/console/ui/shell/panels/overview/OverviewPanel.tsx +428 -0
- package/src/console/ui/shell/panels/plugins/PluginsPanel.tsx +413 -0
- package/src/console/ui/shell/panels/runs/RunsPanel.tsx +649 -0
- package/src/console/ui/shell/panels/signals/SignalsPanel.tsx +840 -0
- package/src/console/ui/shell/panels/store/StorePanel.tsx +787 -0
- package/src/console/ui/shell/panels/traces/TracesPanel.tsx +539 -0
- package/src/console/ui/shell/panels/vault/VaultPanel.tsx +449 -0
- package/src/console/ui/shell/plugin/Sandbox.tsx +29 -0
- package/src/console/ui/shell/setup/Wizard.tsx +189 -0
- package/src/console/ui/shell/styles.css +75 -0
- package/src/console/ui/signals/SignalsA11yView.tsx +276 -0
- package/src/console/ui/signals/a11y.test.tsx +99 -0
- package/src/console/ui/signals/confirmation.test.ts +39 -0
- package/src/console/ui/signals/confirmation.ts +63 -0
- package/src/console/ui/signals/dry-run.test.ts +18 -0
- package/src/console/ui/signals/dry-run.ts +36 -0
- package/src/console/ui/signals/durable.test.ts +22 -0
- package/src/console/ui/signals/durable.ts +41 -0
- package/src/console/ui/signals/findings.ts +33 -0
- package/src/console/ui/signals/fixture.ts +242 -0
- package/src/console/ui/signals/group.test.ts +32 -0
- package/src/console/ui/signals/group.ts +49 -0
- package/src/console/ui/signals/index.ts +52 -0
- package/src/console/ui/signals/monitor.test.ts +30 -0
- package/src/console/ui/signals/monitor.ts +79 -0
- package/src/console/ui/signals/schema-form.test.ts +34 -0
- package/src/console/ui/signals/schema-form.ts +112 -0
- package/src/console/ui/signals/search.ts +102 -0
- package/src/console/ui/signals/types.ts +71 -0
- package/src/console/ui/store/StoreA11yView.tsx +199 -0
- package/src/console/ui/store/a11y.test.tsx +99 -0
- package/src/console/ui/store/cache-view.test.ts +13 -0
- package/src/console/ui/store/cache-view.ts +36 -0
- package/src/console/ui/store/confirmation.test.ts +38 -0
- package/src/console/ui/store/confirmation.ts +55 -0
- package/src/console/ui/store/dry-run.test.ts +15 -0
- package/src/console/ui/store/dry-run.ts +29 -0
- package/src/console/ui/store/fixture.ts +163 -0
- package/src/console/ui/store/group.test.ts +21 -0
- package/src/console/ui/store/group.ts +41 -0
- package/src/console/ui/store/index.ts +40 -0
- package/src/console/ui/store/search.ts +78 -0
- package/src/console/ui/store/types.ts +65 -0
- package/src/console/ui/store/will-not-fire.test.ts +19 -0
- package/src/console/ui/store/will-not-fire.ts +40 -0
- package/src/console/ui/traces/TracesA11yView.tsx +200 -0
- package/src/console/ui/traces/a11y.test.tsx +97 -0
- package/src/console/ui/traces/chain.test.ts +61 -0
- package/src/console/ui/traces/chain.ts +144 -0
- package/src/console/ui/traces/critical-path.test.ts +24 -0
- package/src/console/ui/traces/critical-path.ts +59 -0
- package/src/console/ui/traces/filter.test.ts +78 -0
- package/src/console/ui/traces/filter.ts +112 -0
- package/src/console/ui/traces/fixture.ts +126 -0
- package/src/console/ui/traces/fold.test.ts +67 -0
- package/src/console/ui/traces/fold.ts +170 -0
- package/src/console/ui/traces/index.ts +64 -0
- package/src/console/ui/traces/mini.ts +65 -0
- package/src/console/ui/traces/replay.test.ts +24 -0
- package/src/console/ui/traces/replay.ts +35 -0
- package/src/console/ui/traces/sampling.test.ts +26 -0
- package/src/console/ui/traces/sampling.ts +66 -0
- package/src/console/ui/traces/search.ts +148 -0
- package/src/console/ui/traces/tier.ts +72 -0
- package/src/console/ui/traces/types.ts +125 -0
- package/src/console/ui/tsconfig.json +20 -0
- package/src/console/ui/vault/VaultA11yView.tsx +177 -0
- package/src/console/ui/vault/a11y.test.tsx +97 -0
- package/src/console/ui/vault/blast-radius.test.ts +35 -0
- package/src/console/ui/vault/blast-radius.ts +55 -0
- package/src/console/ui/vault/confirmation.test.ts +41 -0
- package/src/console/ui/vault/confirmation.ts +39 -0
- package/src/console/ui/vault/dormant.test.ts +37 -0
- package/src/console/ui/vault/dormant.ts +28 -0
- package/src/console/ui/vault/export-safe.test.ts +30 -0
- package/src/console/ui/vault/export-safe.ts +65 -0
- package/src/console/ui/vault/fixture.ts +75 -0
- package/src/console/ui/vault/group.test.ts +25 -0
- package/src/console/ui/vault/group.ts +50 -0
- package/src/console/ui/vault/index.ts +45 -0
- package/src/console/ui/vault/search.ts +62 -0
- package/src/console/ui/vault/types.ts +57 -0
- package/src/console/ui/vite.config.ts +84 -0
- package/src/console/xss.gate.test.ts +118 -0
- package/src/docker/compose.ts +226 -0
- package/src/docker/credentials.ts +25 -0
- package/src/docker/derive.ts +83 -0
- package/src/docker/docker.test.ts +185 -0
- package/src/docker/dockerfile.integration.test.ts +170 -0
- package/src/docker/dockerfile.ts +39 -0
- package/src/docker/helpers.ts +103 -0
- package/src/docker/index.ts +52 -0
- package/src/docker/pin.ts +90 -0
- package/src/docker/recipes/index.ts +33 -0
- package/src/docker/recipes/postgres.ts +18 -0
- package/src/docker/recipes/redis.ts +18 -0
- package/src/docker/stack.integration.test.ts +140 -0
- package/src/docker/stack.ts +62 -0
- package/src/docker/types.ts +134 -0
- package/src/drivers/ai-anthropic.ts +128 -0
- package/src/drivers/ai-mock.ts +82 -0
- package/src/drivers/ai-openai-compatible.ts +139 -0
- package/src/drivers/ai-providers.test.ts +163 -0
- package/src/drivers/ai-types.ts +83 -0
- package/src/drivers/bun-native-completeness.test.ts +155 -0
- package/src/drivers/channel-console.ts +118 -0
- package/src/drivers/channel-fcm.ts +96 -0
- package/src/drivers/channel-resend.ts +27 -0
- package/src/drivers/channel-smtp.ts +33 -0
- package/src/drivers/channel-types.ts +160 -0
- package/src/drivers/channel-unifonic.ts +79 -0
- package/src/drivers/channel-wa-cloud.ts +84 -0
- package/src/drivers/channel-webpush.ts +317 -0
- package/src/drivers/conformance.test.ts +89 -0
- package/src/drivers/conformance.ts +162 -0
- package/src/drivers/fs.ts +73 -0
- package/src/drivers/index.ts +194 -0
- package/src/drivers/kv-lua.ts +222 -0
- package/src/drivers/memory.ts +472 -0
- package/src/drivers/pgvector.ts +130 -0
- package/src/drivers/postgres.ts +221 -0
- package/src/drivers/redis.ts +254 -0
- package/src/drivers/s3.ts +129 -0
- package/src/drivers/signal-engine.ts +690 -0
- package/src/drivers/signal-memory.ts +27 -0
- package/src/drivers/signal-nats.ts +131 -0
- package/src/drivers/signal-postgres.ts +1089 -0
- package/src/drivers/signal-redis.ts +275 -0
- package/src/drivers/signal-types.ts +328 -0
- package/src/drivers/sqlite.ts +53 -0
- package/src/drivers/types.ts +334 -0
- package/src/drivers/vault-dotenv-parse.ts +56 -0
- package/src/drivers/vault-env.ts +101 -0
- package/src/drivers/vault-infisical.ts +61 -0
- package/src/drivers/vault-managed.ts +42 -0
- package/src/drivers/vault-memory.ts +38 -0
- package/src/drivers/vault-openbao.ts +80 -0
- package/src/drivers/vault-sops.ts +252 -0
- package/src/drivers/vault-types.ts +84 -0
- package/src/elements/ai/declare.ts +206 -0
- package/src/elements/ai/eval.ts +113 -0
- package/src/elements/ai/pii.ts +108 -0
- package/src/elements/ai/runtime.ts +540 -0
- package/src/elements/ai/schema.ts +194 -0
- package/src/elements/ai.test.ts +393 -0
- package/src/elements/ai.ts +56 -0
- package/src/elements/channel/consent.ts +81 -0
- package/src/elements/channel/costs.test.ts +62 -0
- package/src/elements/channel/costs.ts +130 -0
- package/src/elements/channel/declare.ts +141 -0
- package/src/elements/channel/email-auth.test.ts +47 -0
- package/src/elements/channel/email-auth.ts +109 -0
- package/src/elements/channel/locale.ts +97 -0
- package/src/elements/channel/mask.test.ts +19 -0
- package/src/elements/channel/mask.ts +60 -0
- package/src/elements/channel/mime.ts +23 -0
- package/src/elements/channel/outcomes.test.ts +40 -0
- package/src/elements/channel/outcomes.ts +126 -0
- package/src/elements/channel/receipts.ts +121 -0
- package/src/elements/channel/runtime.ts +500 -0
- package/src/elements/channel/suppression.ts +136 -0
- package/src/elements/channel.test.ts +232 -0
- package/src/elements/channel.ts +109 -0
- package/src/elements/clock/actions.ts +170 -0
- package/src/elements/clock/declare.ts +58 -0
- package/src/elements/clock/dst.ts +197 -0
- package/src/elements/clock/durable.ts +140 -0
- package/src/elements/clock/duration.ts +29 -0
- package/src/elements/clock/health.test.ts +103 -0
- package/src/elements/clock/health.ts +112 -0
- package/src/elements/clock/leader.ts +127 -0
- package/src/elements/clock/reconcile.ts +241 -0
- package/src/elements/clock/runtime.ts +243 -0
- package/src/elements/clock/schedule.ts +262 -0
- package/src/elements/clock/time-travel.ts +53 -0
- package/src/elements/clock.test.ts +365 -0
- package/src/elements/clock.ts +80 -0
- package/src/elements/gate/declare.ts +134 -0
- package/src/elements/gate/permissions.ts +104 -0
- package/src/elements/gate/runtime.ts +177 -0
- package/src/elements/gate/strategies.ts +388 -0
- package/src/elements/gate.test.ts +145 -0
- package/src/elements/gate.ts +41 -0
- package/src/elements/index.ts +169 -0
- package/src/elements/signal/chaos-child.ts +47 -0
- package/src/elements/signal/declare.ts +77 -0
- package/src/elements/signal/dry-run-replay.test.ts +95 -0
- package/src/elements/signal/dry-run-write-isolation.test.ts +94 -0
- package/src/elements/signal/reconcile.test.ts +23 -0
- package/src/elements/signal/reconcile.ts +122 -0
- package/src/elements/signal/runtime.ts +94 -0
- package/src/elements/signal.test.ts +457 -0
- package/src/elements/signal.ts +26 -0
- package/src/elements/store/cache.ts +197 -0
- package/src/elements/store/classify.ts +125 -0
- package/src/elements/store/declare.ts +200 -0
- package/src/elements/store/files-policy.test.ts +31 -0
- package/src/elements/store/files-policy.ts +70 -0
- package/src/elements/store/replica.ts +68 -0
- package/src/elements/store/runtime.ts +393 -0
- package/src/elements/store/sql-condition.ts +205 -0
- package/src/elements/store/sql-session.ts +579 -0
- package/src/elements/store/table.ts +282 -0
- package/src/elements/store.test.ts +370 -0
- package/src/elements/store.ts +99 -0
- package/src/elements/vault/declare.ts +143 -0
- package/src/elements/vault/fingerprint.ts +30 -0
- package/src/elements/vault/redact.ts +52 -0
- package/src/elements/vault/runtime.ts +461 -0
- package/src/elements/vault.test.ts +296 -0
- package/src/elements/vault.ts +44 -0
- package/src/index.ts +183 -0
- package/src/kernel/adopt-routes.ts +194 -0
- package/src/kernel/app.ts +1068 -0
- package/src/kernel/auth-resolve.ts +93 -0
- package/src/kernel/boot.test.ts +173 -0
- package/src/kernel/boot.ts +439 -0
- package/src/kernel/budget-entry.ts +55 -0
- package/src/kernel/budget.test.ts +19 -0
- package/src/kernel/call.test.ts +83 -0
- package/src/kernel/capability.ts +113 -0
- package/src/kernel/dry-run.test.ts +64 -0
- package/src/kernel/dry-run.ts +171 -0
- package/src/kernel/effects.test.ts +89 -0
- package/src/kernel/effects.ts +140 -0
- package/src/kernel/errors.registry.test.ts +39 -0
- package/src/kernel/errors.ts +225 -0
- package/src/kernel/flow.test.ts +154 -0
- package/src/kernel/flow.ts +290 -0
- package/src/kernel/fx.test.ts +245 -0
- package/src/kernel/fx.ts +996 -0
- package/src/kernel/hook-timing.test.ts +72 -0
- package/src/kernel/hook-timing.ts +190 -0
- package/src/kernel/hooks.test.ts +181 -0
- package/src/kernel/hooks.ts +275 -0
- package/src/kernel/index.ts +278 -0
- package/src/kernel/journal.ts +405 -0
- package/src/kernel/journey.ts +75 -0
- package/src/kernel/on.ts +74 -0
- package/src/kernel/pipeline.test.ts +349 -0
- package/src/kernel/pipeline.ts +245 -0
- package/src/kernel/plug.ts +82 -0
- package/src/kernel/plugin/capabilities.test.ts +84 -0
- package/src/kernel/plugin/conflicts.test.ts +106 -0
- package/src/kernel/plugin/decorate.test.ts +111 -0
- package/src/kernel/plugin/scoping.test.ts +138 -0
- package/src/kernel/plugin.ts +485 -0
- package/src/kernel/rate-limit.ts +25 -0
- package/src/kernel/registry.ts +398 -0
- package/src/kernel/router.test.ts +114 -0
- package/src/kernel/router.ts +556 -0
- package/src/kernel/routing-budget.test.ts +19 -0
- package/src/kernel/run-telemetry.ts +70 -0
- package/src/kernel/triggers.ts +324 -0
- package/src/kernel/unit.ts +88 -0
- package/src/manifest/diff.test.ts +866 -0
- package/src/manifest/diff.ts +1670 -0
- package/src/manifest/fixtures/base.manifest.json +112 -0
- package/src/manifest/fixtures/skyport.excerpt.json +51 -0
- package/src/manifest/fixtures/skyport.manifest.json +153 -0
- package/src/manifest/index.ts +27 -0
- package/src/manifest/types.ts +358 -0
- package/src/manifest/undeclared.test.ts +82 -0
- package/src/manifest/undeclared.ts +65 -0
- package/src/manifest/validate.test.ts +105 -0
- package/src/manifest/validate.ts +174 -0
- package/src/mcp/authorization.ts +340 -0
- package/src/mcp/confirmation.ts +174 -0
- package/src/mcp/data.ts +90 -0
- package/src/mcp/index.ts +80 -0
- package/src/mcp/injection.gate.test.ts +176 -0
- package/src/mcp/mcp.test.ts +348 -0
- package/src/mcp/protocol.ts +172 -0
- package/src/mcp/server.ts +283 -0
- package/src/mcp/session.ts +139 -0
- package/src/mcp/tools.ts +391 -0
- package/src/plugins/catalogue.test.ts +48 -0
- package/src/plugins/catalogue.ts +113 -0
- package/src/plugins/node-import-scan.test.ts +28 -0
- package/src/plugins/node-import-scan.ts +98 -0
- package/src/plugins/supply-chain.test.ts +48 -0
- package/src/plugins/supply-chain.ts +460 -0
- package/src/release/index.ts +30 -0
- package/src/release/limits.ts +20 -0
- package/src/release/measure.ts +443 -0
- package/src/release/publish.ts +56 -0
- package/src/runs/bench.test.ts +93 -0
- package/src/runs/collect.ts +144 -0
- package/src/runs/drivers/clickhouse.ts +108 -0
- package/src/runs/drivers/files.ts +201 -0
- package/src/runs/drivers/memory.ts +94 -0
- package/src/runs/drivers/postgres.ts +110 -0
- package/src/runs/duckdb.ts +99 -0
- package/src/runs/index.ts +82 -0
- package/src/runs/outlier.ts +180 -0
- package/src/runs/parquet.ts +210 -0
- package/src/runs/privacy.ts +49 -0
- package/src/runs/runs.test.ts +324 -0
- package/src/runs/runtime.ts +229 -0
- package/src/runs/shred.ts +243 -0
- package/src/runs/telemetry.ts +10 -0
- package/src/runs/types.ts +179 -0
- package/src/runtime/bun.ts +140 -0
- package/src/runtime/cold-start.bench.ts +20 -0
- package/src/runtime/index.ts +46 -0
- package/src/runtime/primitives.ts +242 -0
- package/src/runtime/security.test.ts +170 -0
- package/src/runtime/security.ts +168 -0
- package/src/runtime/serve.test.ts +223 -0
- package/src/runtime/types.ts +217 -0
- package/src/runtime/web-standard.ts +77 -0
- package/src/test/create-test-app.test.ts +161 -0
- package/src/test/create-test-app.ts +533 -0
- package/src/test/index.ts +21 -0
- package/src/test/provisions.integration.test.ts +174 -0
- package/src/upgrade/codemods.test.ts +58 -0
- package/src/upgrade/codemods.ts +83 -0
- package/src/validation/index.ts +23 -0
- package/src/validation/standard-schema.test.ts +96 -0
- package/src/validation/standard-schema.ts +316 -0
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format cron health four numbers for display (console §9.6).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { ClockCronRecord, CronHealth } from "./types.ts";
|
|
6
|
+
|
|
7
|
+
/** Display lines for the four health numbers. */
|
|
8
|
+
export interface HealthLines {
|
|
9
|
+
readonly drift: string;
|
|
10
|
+
readonly overdue: string;
|
|
11
|
+
readonly missedWithPolicy: string;
|
|
12
|
+
readonly lease: string;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Format health for a cron row.
|
|
17
|
+
*
|
|
18
|
+
* @param health - Health payload
|
|
19
|
+
*/
|
|
20
|
+
export function formatHealth(health: CronHealth): HealthLines {
|
|
21
|
+
return {
|
|
22
|
+
drift:
|
|
23
|
+
health.driftMs == null
|
|
24
|
+
? "drift unknown"
|
|
25
|
+
: `drift ${formatSignedMs(health.driftMs)}`,
|
|
26
|
+
overdue: health.overdue ? "overdue" : "on time",
|
|
27
|
+
missedWithPolicy: `${health.missedRuns} missed · catch-up ${health.catchUp}`,
|
|
28
|
+
lease: health.leaderInstanceId
|
|
29
|
+
? `lease ${health.leaderInstanceId}`
|
|
30
|
+
: "no lease",
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Filter crons by query.
|
|
36
|
+
*
|
|
37
|
+
* @param crons - Cron rows
|
|
38
|
+
* @param q - Query
|
|
39
|
+
*/
|
|
40
|
+
export function filterCrons(
|
|
41
|
+
crons: readonly ClockCronRecord[],
|
|
42
|
+
q: string,
|
|
43
|
+
): readonly ClockCronRecord[] {
|
|
44
|
+
const needle = q.trim().toLowerCase();
|
|
45
|
+
if (!needle) return crons;
|
|
46
|
+
return crons.filter(
|
|
47
|
+
(c) =>
|
|
48
|
+
c.name.toLowerCase().includes(needle) ||
|
|
49
|
+
(c.effectiveCron?.toLowerCase().includes(needle) ?? false) ||
|
|
50
|
+
(c.effectiveEvery?.toLowerCase().includes(needle) ?? false) ||
|
|
51
|
+
c.flowIds.some((id) => id.toLowerCase().includes(needle)),
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function formatSignedMs(ms: number): string {
|
|
56
|
+
const sign = ms >= 0 ? "+" : "-";
|
|
57
|
+
const abs = Math.abs(ms);
|
|
58
|
+
if (abs < 1_000) return `${sign}${abs}ms`;
|
|
59
|
+
if (abs < 60_000) return `${sign}${Math.round(abs / 1000)}s`;
|
|
60
|
+
return `${sign}${Math.round(abs / 60_000)}m`;
|
|
61
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clock panel pure modules (console §9.6).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export type {
|
|
6
|
+
CatchUpPolicy,
|
|
7
|
+
ClockCronRecord,
|
|
8
|
+
ClockListResponse,
|
|
9
|
+
CronHealth,
|
|
10
|
+
CronStatus,
|
|
11
|
+
DstAmbiguityView,
|
|
12
|
+
TimelineEvent,
|
|
13
|
+
WaitingOnCount,
|
|
14
|
+
WaitingOnRecord,
|
|
15
|
+
} from "./types.ts";
|
|
16
|
+
|
|
17
|
+
export { CLOCK_LIST_FIXTURE } from "./fixture.ts";
|
|
18
|
+
|
|
19
|
+
export {
|
|
20
|
+
parseClockSearch,
|
|
21
|
+
serializeClockSearch,
|
|
22
|
+
openCron,
|
|
23
|
+
openWake,
|
|
24
|
+
closeClockDetail,
|
|
25
|
+
type ClockSearch,
|
|
26
|
+
} from "./search.ts";
|
|
27
|
+
|
|
28
|
+
export { forwardTimeline, formatTimelineWhen } from "./timeline.ts";
|
|
29
|
+
|
|
30
|
+
export {
|
|
31
|
+
aggregateByLabel,
|
|
32
|
+
waitingOnBanner,
|
|
33
|
+
formatWakeIn,
|
|
34
|
+
filterWaitingOn,
|
|
35
|
+
} from "./waiting-on.ts";
|
|
36
|
+
|
|
37
|
+
export { formatHealth, filterCrons, type HealthLines } from "./health.ts";
|
|
38
|
+
|
|
39
|
+
export {
|
|
40
|
+
overdueCronFindings,
|
|
41
|
+
type OverdueCronFinding,
|
|
42
|
+
} from "./findings.ts";
|
|
43
|
+
|
|
44
|
+
export {
|
|
45
|
+
runNowConfirmation,
|
|
46
|
+
validateTypedConfirm,
|
|
47
|
+
UNDO_WINDOW_MS,
|
|
48
|
+
type ConfirmationPattern,
|
|
49
|
+
} from "./confirmation.ts";
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clock URL search.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, expect, test } from "bun:test";
|
|
6
|
+
import {
|
|
7
|
+
closeClockDetail,
|
|
8
|
+
openCron,
|
|
9
|
+
openWake,
|
|
10
|
+
parseClockSearch,
|
|
11
|
+
serializeClockSearch,
|
|
12
|
+
} from "./search.ts";
|
|
13
|
+
|
|
14
|
+
describe("clock search", () => {
|
|
15
|
+
test("round-trips open cron + action", () => {
|
|
16
|
+
const s = openCron({}, "nightly");
|
|
17
|
+
expect(s.cron).toBe("nightly");
|
|
18
|
+
const withAction = { ...s, action: "run" as const };
|
|
19
|
+
expect(serializeClockSearch(withAction)).toEqual({
|
|
20
|
+
cron: "nightly",
|
|
21
|
+
action: "run",
|
|
22
|
+
});
|
|
23
|
+
expect(parseClockSearch({ cron: "nightly", action: "run" })).toEqual(
|
|
24
|
+
withAction,
|
|
25
|
+
);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test("openWake clears cron", () => {
|
|
29
|
+
const s = openWake({ cron: "x" }, "run_1");
|
|
30
|
+
expect(s.wake).toBe("run_1");
|
|
31
|
+
expect(s.cron).toBeUndefined();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("closeClockDetail", () => {
|
|
35
|
+
expect(closeClockDetail({ cron: "a", wake: "b", action: "edit", q: "z" })).toEqual({
|
|
36
|
+
q: "z",
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URL search state for the Clock panel.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { z } from "zod";
|
|
6
|
+
|
|
7
|
+
const ClockSearchSchema = z.object({
|
|
8
|
+
q: z.string().optional(),
|
|
9
|
+
/** Open cron name. */
|
|
10
|
+
cron: z.string().optional(),
|
|
11
|
+
/** Open waiting-on run id. */
|
|
12
|
+
wake: z.string().optional(),
|
|
13
|
+
/** Active action in the detail pane. */
|
|
14
|
+
action: z.enum(["run", "edit"]).optional(),
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
/** Parsed Clock URL search. */
|
|
18
|
+
export type ClockSearch = z.infer<typeof ClockSearchSchema>;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Parse Clock panel search params.
|
|
22
|
+
*
|
|
23
|
+
* @param search - Raw router search
|
|
24
|
+
*/
|
|
25
|
+
export function parseClockSearch(
|
|
26
|
+
search: Record<string, unknown>,
|
|
27
|
+
): ClockSearch {
|
|
28
|
+
const parsed = ClockSearchSchema.safeParse(search);
|
|
29
|
+
return parsed.success ? parsed.data : {};
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Serialize Clock search for navigation (omit empties).
|
|
34
|
+
*
|
|
35
|
+
* @param search - Search state
|
|
36
|
+
*/
|
|
37
|
+
export function serializeClockSearch(
|
|
38
|
+
search: ClockSearch,
|
|
39
|
+
): Record<string, string> {
|
|
40
|
+
const out: Record<string, string> = {};
|
|
41
|
+
if (search.q) out.q = search.q;
|
|
42
|
+
if (search.cron) out.cron = search.cron;
|
|
43
|
+
if (search.wake) out.wake = search.wake;
|
|
44
|
+
if (search.action) out.action = search.action;
|
|
45
|
+
return out;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Open a cron in the URL.
|
|
50
|
+
*
|
|
51
|
+
* @param search - Current search
|
|
52
|
+
* @param name - Cron name
|
|
53
|
+
*/
|
|
54
|
+
export function openCron(search: ClockSearch, name: string): ClockSearch {
|
|
55
|
+
return { ...search, cron: name, wake: undefined, action: undefined };
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* Open a waiting-on run in the URL.
|
|
60
|
+
*
|
|
61
|
+
* @param search - Current search
|
|
62
|
+
* @param runId - Run id
|
|
63
|
+
*/
|
|
64
|
+
export function openWake(search: ClockSearch, runId: string): ClockSearch {
|
|
65
|
+
return { ...search, wake: runId, cron: undefined, action: undefined };
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Close open detail.
|
|
70
|
+
*
|
|
71
|
+
* @param search - Current search
|
|
72
|
+
*/
|
|
73
|
+
export function closeClockDetail(search: ClockSearch): ClockSearch {
|
|
74
|
+
const { cron: _c, wake: _w, action: _a, ...rest } = search;
|
|
75
|
+
return rest;
|
|
76
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Forward timeline helpers.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, expect, test } from "bun:test";
|
|
6
|
+
import { CLOCK_LIST_FIXTURE } from "./fixture.ts";
|
|
7
|
+
import { formatTimelineWhen, forwardTimeline } from "./timeline.ts";
|
|
8
|
+
|
|
9
|
+
describe("forwardTimeline", () => {
|
|
10
|
+
test("keeps next-24h events sorted", () => {
|
|
11
|
+
const now = CLOCK_LIST_FIXTURE.now;
|
|
12
|
+
const events = forwardTimeline(
|
|
13
|
+
[
|
|
14
|
+
...CLOCK_LIST_FIXTURE.timeline,
|
|
15
|
+
{
|
|
16
|
+
at: now + 48 * 3_600_000,
|
|
17
|
+
kind: "cron",
|
|
18
|
+
name: "too-far",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
at: now - 1,
|
|
22
|
+
kind: "wake",
|
|
23
|
+
name: "past",
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
now,
|
|
27
|
+
);
|
|
28
|
+
expect(events.every((e) => e.at >= now && e.at < now + 86_400_000)).toBe(
|
|
29
|
+
true,
|
|
30
|
+
);
|
|
31
|
+
expect(events.find((e) => e.name === "too-far")).toBeUndefined();
|
|
32
|
+
expect(events.find((e) => e.name === "past")).toBeUndefined();
|
|
33
|
+
for (let i = 1; i < events.length; i++) {
|
|
34
|
+
expect(events[i]!.at).toBeGreaterThanOrEqual(events[i - 1]!.at);
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
describe("formatTimelineWhen", () => {
|
|
40
|
+
test("formats relative wake", () => {
|
|
41
|
+
expect(formatTimelineWhen(60_000, 0)).toBe("in 1m");
|
|
42
|
+
expect(formatTimelineWhen(3_600_000, 0)).toBe("in 1h");
|
|
43
|
+
});
|
|
44
|
+
});
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Forward timeline helpers — next 24h list, not a grid (console §9.6).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { TimelineEvent } from "./types.ts";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Filter timeline events to those within the next 24h from `now`.
|
|
9
|
+
*
|
|
10
|
+
* @param events - Timeline events
|
|
11
|
+
* @param now - Anchor epoch-ms
|
|
12
|
+
*/
|
|
13
|
+
export function forwardTimeline(
|
|
14
|
+
events: readonly TimelineEvent[],
|
|
15
|
+
now: number,
|
|
16
|
+
): readonly TimelineEvent[] {
|
|
17
|
+
const until = now + 24 * 60 * 60 * 1000;
|
|
18
|
+
return events
|
|
19
|
+
.filter((e) => e.at >= now && e.at < until)
|
|
20
|
+
.slice()
|
|
21
|
+
.sort((a, b) => a.at - b.at || a.name.localeCompare(b.name));
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Format an absolute time relative to `now` for the timeline row.
|
|
26
|
+
*
|
|
27
|
+
* @param at - Event epoch-ms
|
|
28
|
+
* @param now - Anchor
|
|
29
|
+
*/
|
|
30
|
+
export function formatTimelineWhen(at: number, now: number): string {
|
|
31
|
+
const delta = at - now;
|
|
32
|
+
if (delta < 0) return "past";
|
|
33
|
+
if (delta < 60_000) return `in ${Math.round(delta / 1000)}s`;
|
|
34
|
+
if (delta < 3_600_000) return `in ${Math.round(delta / 60_000)}m`;
|
|
35
|
+
if (delta < 86_400_000) {
|
|
36
|
+
const h = Math.floor(delta / 3_600_000);
|
|
37
|
+
const m = Math.round((delta % 3_600_000) / 60_000);
|
|
38
|
+
return m > 0 ? `in ${h}h ${m}m` : `in ${h}h`;
|
|
39
|
+
}
|
|
40
|
+
return new Date(at).toISOString();
|
|
41
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Clock panel view types (console §9.6).
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/** Cron lifecycle status. */
|
|
6
|
+
export type CronStatus = "active" | "paused" | "orphaned";
|
|
7
|
+
|
|
8
|
+
/** Catch-up policy matching ClockRuntime physics. */
|
|
9
|
+
export type CatchUpPolicy = "one";
|
|
10
|
+
|
|
11
|
+
/** Four-number cron health. */
|
|
12
|
+
export interface CronHealth {
|
|
13
|
+
readonly driftMs: number | null;
|
|
14
|
+
readonly overdue: boolean;
|
|
15
|
+
readonly missedRuns: number;
|
|
16
|
+
readonly catchUp: CatchUpPolicy;
|
|
17
|
+
readonly leaderInstanceId?: string;
|
|
18
|
+
readonly leaderLeaseUntil?: number;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/** DST ambiguity payload (only when expression+zone hit gap/overlap). */
|
|
22
|
+
export interface DstAmbiguityView {
|
|
23
|
+
readonly kind: "gap" | "overlap";
|
|
24
|
+
readonly reason: string;
|
|
25
|
+
readonly on: string;
|
|
26
|
+
readonly localTime: string;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/** One cron row from `console.clock.list`. */
|
|
30
|
+
export interface ClockCronRecord {
|
|
31
|
+
readonly name: string;
|
|
32
|
+
readonly status: CronStatus;
|
|
33
|
+
readonly timezone: string;
|
|
34
|
+
readonly overridable: boolean;
|
|
35
|
+
readonly declaredCron?: string;
|
|
36
|
+
readonly declaredEvery?: string;
|
|
37
|
+
readonly effectiveCron?: string;
|
|
38
|
+
readonly effectiveEvery?: string;
|
|
39
|
+
readonly lastRunAt?: number;
|
|
40
|
+
readonly nextRunAt?: number;
|
|
41
|
+
readonly health: CronHealth;
|
|
42
|
+
readonly dstAmbiguity: DstAmbiguityView | null;
|
|
43
|
+
readonly external: boolean;
|
|
44
|
+
readonly flowIds: readonly string[];
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Sleeping durable run in the waiting-on list. */
|
|
48
|
+
export interface WaitingOnRecord {
|
|
49
|
+
readonly runId: string;
|
|
50
|
+
readonly flow: string;
|
|
51
|
+
readonly label: string;
|
|
52
|
+
readonly wakeAt: number;
|
|
53
|
+
readonly wakeInMs: number;
|
|
54
|
+
readonly step: string | null;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Aggregate by sleep label. */
|
|
58
|
+
export interface WaitingOnCount {
|
|
59
|
+
readonly label: string;
|
|
60
|
+
readonly count: number;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Forward timeline event. */
|
|
64
|
+
export interface TimelineEvent {
|
|
65
|
+
readonly at: number;
|
|
66
|
+
readonly kind: "cron" | "wake";
|
|
67
|
+
readonly name: string;
|
|
68
|
+
readonly meta?: string;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** List response envelope. */
|
|
72
|
+
export interface ClockListResponse {
|
|
73
|
+
readonly now: number;
|
|
74
|
+
readonly crons: readonly ClockCronRecord[];
|
|
75
|
+
readonly waitingOn: readonly WaitingOnRecord[];
|
|
76
|
+
readonly waitingOnCounts: readonly WaitingOnCount[];
|
|
77
|
+
readonly timeline: readonly TimelineEvent[];
|
|
78
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Waiting-on helpers.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { describe, expect, test } from "bun:test";
|
|
6
|
+
import { CLOCK_LIST_FIXTURE } from "./fixture.ts";
|
|
7
|
+
import {
|
|
8
|
+
aggregateByLabel,
|
|
9
|
+
formatWakeIn,
|
|
10
|
+
waitingOnBanner,
|
|
11
|
+
} from "./waiting-on.ts";
|
|
12
|
+
|
|
13
|
+
describe("waiting-on", () => {
|
|
14
|
+
test("aggregates by label", () => {
|
|
15
|
+
const counts = aggregateByLabel(CLOCK_LIST_FIXTURE.waitingOn);
|
|
16
|
+
expect(counts[0]).toEqual({ label: "trial-period", count: 2 });
|
|
17
|
+
expect(counts.find((c) => c.label === "verify-window")?.count).toBe(1);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
test("banner summarizes sleeping system", () => {
|
|
21
|
+
const banner = waitingOnBanner(
|
|
22
|
+
CLOCK_LIST_FIXTURE.waitingOn.length,
|
|
23
|
+
CLOCK_LIST_FIXTURE.waitingOnCounts,
|
|
24
|
+
);
|
|
25
|
+
expect(banner).toContain("3 sleeping");
|
|
26
|
+
expect(banner).toContain("trial-period");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("formatWakeIn", () => {
|
|
30
|
+
expect(formatWakeIn(0)).toBe("due");
|
|
31
|
+
expect(formatWakeIn(45_000)).toBe("45s");
|
|
32
|
+
expect(formatWakeIn(120_000)).toBe("2m");
|
|
33
|
+
});
|
|
34
|
+
});
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Waiting-on list helpers — sleeping durable runs from the journal.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import type { WaitingOnCount, WaitingOnRecord } from "./types.ts";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Aggregate waiting-on rows by sleep label (UI mirror of server counts).
|
|
9
|
+
*
|
|
10
|
+
* @param rows - Waiting-on rows
|
|
11
|
+
*/
|
|
12
|
+
export function aggregateByLabel(
|
|
13
|
+
rows: readonly WaitingOnRecord[],
|
|
14
|
+
): readonly WaitingOnCount[] {
|
|
15
|
+
const counts = new Map<string, number>();
|
|
16
|
+
for (const r of rows) {
|
|
17
|
+
const label = r.label || "(unlabelled)";
|
|
18
|
+
counts.set(label, (counts.get(label) ?? 0) + 1);
|
|
19
|
+
}
|
|
20
|
+
return [...counts.entries()]
|
|
21
|
+
.map(([label, count]) => ({ label, count }))
|
|
22
|
+
.sort((a, b) => b.count - a.count || a.label.localeCompare(b.label));
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Banner summary: "3 sleeping — 2 trial-period, 1 verify-window".
|
|
27
|
+
*
|
|
28
|
+
* @param total - Total sleeping
|
|
29
|
+
* @param counts - Per-label counts
|
|
30
|
+
*/
|
|
31
|
+
export function waitingOnBanner(
|
|
32
|
+
total: number,
|
|
33
|
+
counts: readonly WaitingOnCount[],
|
|
34
|
+
): string {
|
|
35
|
+
if (total === 0) return "Nothing waiting";
|
|
36
|
+
const parts = counts
|
|
37
|
+
.slice(0, 4)
|
|
38
|
+
.map((c) => `${c.count} ${c.label}`)
|
|
39
|
+
.join(", ");
|
|
40
|
+
return `${total} sleeping — ${parts}`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Format wake-in duration.
|
|
45
|
+
*
|
|
46
|
+
* @param ms - Milliseconds until wake
|
|
47
|
+
*/
|
|
48
|
+
export function formatWakeIn(ms: number): string {
|
|
49
|
+
if (ms <= 0) return "due";
|
|
50
|
+
if (ms < 1_000) return `${ms}ms`;
|
|
51
|
+
const sec = Math.floor(ms / 1_000);
|
|
52
|
+
if (sec < 60) return `${sec}s`;
|
|
53
|
+
const min = Math.floor(sec / 60);
|
|
54
|
+
if (min < 60) return `${min}m`;
|
|
55
|
+
const hr = Math.floor(min / 60);
|
|
56
|
+
if (hr < 48) {
|
|
57
|
+
const rem = min % 60;
|
|
58
|
+
return rem > 0 ? `${hr}h ${rem}m` : `${hr}h`;
|
|
59
|
+
}
|
|
60
|
+
const days = Math.floor(hr / 24);
|
|
61
|
+
return `${days}d`;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Filter waiting-on by query string.
|
|
66
|
+
*
|
|
67
|
+
* @param rows - Rows
|
|
68
|
+
* @param q - Query
|
|
69
|
+
*/
|
|
70
|
+
export function filterWaitingOn(
|
|
71
|
+
rows: readonly WaitingOnRecord[],
|
|
72
|
+
q: string,
|
|
73
|
+
): readonly WaitingOnRecord[] {
|
|
74
|
+
const needle = q.trim().toLowerCase();
|
|
75
|
+
if (!needle) return rows;
|
|
76
|
+
return rows.filter(
|
|
77
|
+
(r) =>
|
|
78
|
+
r.label.toLowerCase().includes(needle) ||
|
|
79
|
+
r.flow.toLowerCase().includes(needle) ||
|
|
80
|
+
r.runId.toLowerCase().includes(needle) ||
|
|
81
|
+
(r.step?.toLowerCase().includes(needle) ?? false),
|
|
82
|
+
);
|
|
83
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed-confirmation unification — every panel must call the shared
|
|
3
|
+
* `validateTypedConfirm` from `flows/confirmation.ts`, not a local reimplementation.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { describe, expect, test } from "bun:test";
|
|
7
|
+
import { readdir } from "node:fs/promises";
|
|
8
|
+
import { join } from "node:path";
|
|
9
|
+
import { validateTypedConfirm as shared } from "./flows/confirmation.ts";
|
|
10
|
+
import { validateTypedConfirm as fromAccess } from "./access/confirmation.ts";
|
|
11
|
+
import { validateTypedConfirm as fromChannels } from "./channels/confirmation.ts";
|
|
12
|
+
import { validateTypedConfirm as fromClock } from "./clock/confirmation.ts";
|
|
13
|
+
import { validateTypedConfirm as fromSignals } from "./signals/confirmation.ts";
|
|
14
|
+
import { validateTypedConfirm as fromStore } from "./store/confirmation.ts";
|
|
15
|
+
import { validateTypedConfirm as fromVault } from "./vault/confirmation.ts";
|
|
16
|
+
|
|
17
|
+
const UI_ROOT = import.meta.dir;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Collect `*.ts` / `*.tsx` under a directory (skip dist / node_modules).
|
|
21
|
+
*
|
|
22
|
+
* @param dir - Root
|
|
23
|
+
*/
|
|
24
|
+
async function collectSources(dir: string): Promise<string[]> {
|
|
25
|
+
const out: string[] = [];
|
|
26
|
+
const entries = await readdir(dir, { withFileTypes: true });
|
|
27
|
+
for (const entry of entries) {
|
|
28
|
+
const path = join(dir, entry.name);
|
|
29
|
+
if (entry.isDirectory()) {
|
|
30
|
+
if (entry.name === "dist" || entry.name === "node_modules") continue;
|
|
31
|
+
out.push(...(await collectSources(path)));
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (/\.tsx?$/.test(entry.name)) out.push(path);
|
|
35
|
+
}
|
|
36
|
+
return out;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
describe("validateTypedConfirm unification", () => {
|
|
40
|
+
test("every panel confirmation module re-exports the shared implementation", () => {
|
|
41
|
+
expect(fromAccess).toBe(shared);
|
|
42
|
+
expect(fromChannels).toBe(shared);
|
|
43
|
+
expect(fromClock).toBe(shared);
|
|
44
|
+
expect(fromSignals).toBe(shared);
|
|
45
|
+
expect(fromStore).toBe(shared);
|
|
46
|
+
expect(fromVault).toBe(shared);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test("no panel reimplements typed-confirm validation locally", async () => {
|
|
50
|
+
const files = await collectSources(UI_ROOT);
|
|
51
|
+
const localImpl: string[] = [];
|
|
52
|
+
for (const file of files) {
|
|
53
|
+
if (file.endsWith("/flows/confirmation.ts")) continue;
|
|
54
|
+
if (file.endsWith(".test.ts") || file.endsWith(".test.tsx")) continue;
|
|
55
|
+
const text = await Bun.file(file).text();
|
|
56
|
+
// A local function body (not a re-export) would declare the name with `(`.
|
|
57
|
+
if (/function\s+validateTypedConfirm\s*\(/.test(text)) {
|
|
58
|
+
localImpl.push(file);
|
|
59
|
+
}
|
|
60
|
+
if (
|
|
61
|
+
/const\s+validateTypedConfirm\s*=/.test(text) &&
|
|
62
|
+
!/export\s*\{[^}]*validateTypedConfirm/.test(text)
|
|
63
|
+
) {
|
|
64
|
+
// Allow `import { validateTypedConfirm }` — flag only local const assignment.
|
|
65
|
+
if (!/import\s*\{[^}]*validateTypedConfirm/.test(text)) {
|
|
66
|
+
localImpl.push(file);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
expect(localImpl).toEqual([]);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
test("call sites cover Signals · Store · Clock · Access · Channels · Vault · Flows", async () => {
|
|
74
|
+
const expected = [
|
|
75
|
+
"shell/panels/signals/SignalsPanel.tsx",
|
|
76
|
+
"shell/panels/store/StorePanel.tsx",
|
|
77
|
+
"shell/panels/clock/ClockPanel.tsx",
|
|
78
|
+
"shell/panels/access/AccessPanel.tsx",
|
|
79
|
+
"shell/panels/channels/ChannelsPanel.tsx",
|
|
80
|
+
"shell/panels/vault/VaultPanel.tsx",
|
|
81
|
+
"shell/panels/flows/FlowDrawer.tsx",
|
|
82
|
+
];
|
|
83
|
+
const missing: string[] = [];
|
|
84
|
+
for (const rel of expected) {
|
|
85
|
+
const text = await Bun.file(join(UI_ROOT, rel)).text();
|
|
86
|
+
if (!text.includes("validateTypedConfirm(")) {
|
|
87
|
+
missing.push(rel);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
expect(missing).toEqual([]);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Static Manifest Diff markup for the axe gate — same landmarks as the live panel.
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { formatCiGate, groupByCategory } from "./group.ts";
|
|
6
|
+
import { DIFF_LIST_FIXTURE } from "./fixture.ts";
|
|
7
|
+
|
|
8
|
+
/** Props for {@link DiffA11yView}. */
|
|
9
|
+
export interface DiffA11yViewProps {
|
|
10
|
+
/** Focused Manifest path. */
|
|
11
|
+
readonly path?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Accessible Manifest Diff list for CI.
|
|
16
|
+
*
|
|
17
|
+
* @param props - Open selection
|
|
18
|
+
*/
|
|
19
|
+
export function DiffA11yView(props: DiffA11yViewProps) {
|
|
20
|
+
const data = DIFF_LIST_FIXTURE;
|
|
21
|
+
const groups = groupByCategory(data.changes);
|
|
22
|
+
const focusPath = props.path ?? data.changes[3]?.path;
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<div className="diff-a11y">
|
|
26
|
+
<a href="#diff-main">Skip to main content</a>
|
|
27
|
+
<header>
|
|
28
|
+
<h1>Manifest Diff</h1>
|
|
29
|
+
<p>
|
|
30
|
+
Blast radius of a deploy — contract, permission, effect, and no-impact
|
|
31
|
+
changes. Read-only compare of current Manifest vs baseline.
|
|
32
|
+
</p>
|
|
33
|
+
<label>
|
|
34
|
+
Filter changes
|
|
35
|
+
<input aria-label="Filter changes" defaultValue="" />
|
|
36
|
+
</label>
|
|
37
|
+
</header>
|
|
38
|
+
|
|
39
|
+
<section aria-label="CI gate summary" role="status">
|
|
40
|
+
<h2>CI gate</h2>
|
|
41
|
+
<p>
|
|
42
|
+
{data.blockedCount} undeclared break
|
|
43
|
+
{data.blockedCount === 1 ? "" : "s"} blocked ·{" "}
|
|
44
|
+
{data.acknowledgedCount} acknowledged with breaking: true
|
|
45
|
+
</p>
|
|
46
|
+
</section>
|
|
47
|
+
|
|
48
|
+
<main id="diff-main">
|
|
49
|
+
{groups.map((group) => (
|
|
50
|
+
<section
|
|
51
|
+
key={group.category}
|
|
52
|
+
aria-label={group.label}
|
|
53
|
+
>
|
|
54
|
+
<h2>{group.label}</h2>
|
|
55
|
+
<ul>
|
|
56
|
+
{group.items.map((item) => {
|
|
57
|
+
const gate = formatCiGate(item.ciGate);
|
|
58
|
+
const selected = item.path === focusPath;
|
|
59
|
+
return (
|
|
60
|
+
<li key={item.path}>
|
|
61
|
+
<article
|
|
62
|
+
aria-current={selected ? "true" : undefined}
|
|
63
|
+
>
|
|
64
|
+
<h3>
|
|
65
|
+
<code>{item.path}</code>
|
|
66
|
+
</h3>
|
|
67
|
+
<p>{item.summary}</p>
|
|
68
|
+
{item.blastLine ? (
|
|
69
|
+
<p role="status">{item.blastLine}</p>
|
|
70
|
+
) : null}
|
|
71
|
+
{item.weeklyBillLine ? (
|
|
72
|
+
<p>Weekly bill: {item.weeklyBillLine}</p>
|
|
73
|
+
) : null}
|
|
74
|
+
{gate ? <p role="status">{gate}</p> : null}
|
|
75
|
+
</article>
|
|
76
|
+
</li>
|
|
77
|
+
);
|
|
78
|
+
})}
|
|
79
|
+
</ul>
|
|
80
|
+
</section>
|
|
81
|
+
))}
|
|
82
|
+
</main>
|
|
83
|
+
</div>
|
|
84
|
+
);
|
|
85
|
+
}
|