@infinitedusky/indusk-mcp 1.67.0 → 1.70.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/admin/.next/BUILD_ID +1 -1
- package/admin/.next/build/chunks/[turbopack-node]_transforms_postcss_ts_0laknpb._.js +1 -1
- package/admin/.next/build/chunks/{node_modules__pnpm_0w6x5el._.js → node_modules__pnpm_0e-dfa2._.js} +54 -99
- package/admin/.next/build-manifest.json +5 -5
- package/admin/.next/diagnostics/route-bundle-stats.json +18 -18
- package/admin/.next/fallback-build-manifest.json +3 -3
- package/admin/.next/next-server.js.nft.json +1 -1
- package/admin/.next/required-server-files.js +2 -1
- package/admin/.next/required-server-files.json +2 -1
- package/admin/.next/server/app/_global-error/page/build-manifest.json +2 -2
- package/admin/.next/server/app/_global-error/page.js +2 -2
- package/admin/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/admin/.next/server/app/_global-error.html +1 -1
- package/admin/.next/server/app/_global-error.rsc +1 -1
- package/admin/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/admin/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/admin/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/admin/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/admin/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/admin/.next/server/app/_not-found/page/build-manifest.json +2 -2
- package/admin/.next/server/app/_not-found/page.js +2 -2
- package/admin/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/admin/.next/server/app/api/plans/accept/route.js +3 -3
- package/admin/.next/server/app/api/plans/accept/route.js.nft.json +1 -1
- package/admin/.next/server/app/api/plans/approve/route.js +2 -2
- package/admin/.next/server/app/api/plans/approve/route.js.nft.json +1 -1
- package/admin/.next/server/app/api/plans/build/route.js +3 -3
- package/admin/.next/server/app/api/plans/build/route.js.nft.json +1 -1
- package/admin/.next/server/app/api/plans/review/route.js +2 -2
- package/admin/.next/server/app/api/plans/review/route.js.nft.json +1 -1
- package/admin/.next/server/app/api/plans/route.js +2 -2
- package/admin/.next/server/app/api/plans/route.js.nft.json +1 -1
- package/admin/.next/server/app/api/sessions/[id]/events/route.js +1 -1
- package/admin/.next/server/app/api/sessions/[id]/events/route.js.nft.json +1 -1
- package/admin/.next/server/app/api/sessions/[id]/reply/route.js +1 -1
- package/admin/.next/server/app/api/sessions/[id]/reply/route.js.nft.json +1 -1
- package/admin/.next/server/app/api/sessions/[id]/say/route.js +1 -1
- package/admin/.next/server/app/api/sessions/[id]/say/route.js.nft.json +1 -1
- package/admin/.next/server/app/api/sessions/[id]/stop/route.js +1 -1
- package/admin/.next/server/app/api/sessions/[id]/stop/route.js.nft.json +1 -1
- package/admin/.next/server/app/api/sessions/route.js +1 -1
- package/admin/.next/server/app/api/sessions/route.js.nft.json +1 -1
- package/admin/.next/server/app/api/trust/route.js +1 -1
- package/admin/.next/server/app/api/trust/route.js.nft.json +1 -1
- package/admin/.next/server/app/p/[project]/page/build-manifest.json +2 -2
- package/admin/.next/server/app/p/[project]/page.js +7 -6
- package/admin/.next/server/app/p/[project]/page.js.nft.json +1 -1
- package/admin/.next/server/app/p/[project]/plan/[name]/page/build-manifest.json +2 -2
- package/admin/.next/server/app/p/[project]/plan/[name]/page.js +7 -6
- package/admin/.next/server/app/p/[project]/plan/[name]/page.js.nft.json +1 -1
- package/admin/.next/server/app/p/[project]/plan/[name]/page_client-reference-manifest.js +1 -1
- package/admin/.next/server/app/p/[project]/promises/page/build-manifest.json +2 -2
- package/admin/.next/server/app/p/[project]/promises/page.js +7 -6
- package/admin/.next/server/app/p/[project]/promises/page.js.nft.json +1 -1
- package/admin/.next/server/app/p/[project]/promises/page_client-reference-manifest.js +1 -1
- package/admin/.next/server/app/p/[project]/research/[slug]/page/build-manifest.json +2 -2
- package/admin/.next/server/app/p/[project]/research/[slug]/page.js +7 -6
- package/admin/.next/server/app/p/[project]/research/[slug]/page.js.nft.json +1 -1
- package/admin/.next/server/app/p/[project]/scorecards/page/build-manifest.json +2 -2
- package/admin/.next/server/app/p/[project]/scorecards/page.js +7 -6
- package/admin/.next/server/app/p/[project]/scorecards/page.js.nft.json +1 -1
- package/admin/.next/server/app/page/build-manifest.json +2 -2
- package/admin/.next/server/app/page.js +5 -5
- package/admin/.next/server/app/page.js.nft.json +1 -1
- package/admin/.next/server/chunks/[externals]_http_0x7xzop._.js +3 -0
- package/admin/.next/server/chunks/[externals]_https_0kkoal9._.js +3 -0
- package/admin/.next/server/chunks/[root-of-the-server]__0062qi.._.js +3 -0
- package/admin/.next/server/chunks/{[root-of-the-server]__0bo41_p._.js → [root-of-the-server]__0fuoipz._.js} +2 -2
- package/admin/.next/server/chunks/{[root-of-the-server]__0bdk4l-._.js → [root-of-the-server]__0k_~4x4._.js} +2 -2
- package/admin/.next/server/chunks/[root-of-the-server]__0mnuupi._.js +3 -0
- package/admin/.next/server/chunks/[root-of-the-server]__0tev88s._.js +3 -0
- package/admin/.next/server/chunks/[root-of-the-server]__0uf3bsr._.js +3 -0
- package/admin/.next/server/chunks/{[root-of-the-server]__0ei~-kn._.js → [root-of-the-server]__0wahzqx._.js} +2 -2
- package/admin/.next/server/chunks/[root-of-the-server]__11~aeq7._.js +3 -0
- package/admin/.next/server/chunks/[root-of-the-server]__12_vzme._.js +44 -0
- package/admin/.next/server/chunks/[root-of-the-server]__12yez36._.js +3 -0
- package/admin/.next/server/chunks/_079asol._.js +2 -2
- package/admin/.next/server/chunks/_0m581dh._.js +1 -1
- package/admin/.next/server/chunks/apps_03ts-ky._.js +9 -0
- package/admin/.next/server/chunks/apps_03zah2e._.js +9 -0
- package/admin/.next/server/chunks/apps_0a77sik._.js +9 -0
- package/admin/.next/server/chunks/apps_0rtg94j._.js +9 -0
- package/admin/.next/server/chunks/apps_0t8ww8~._.js +9 -0
- package/admin/.next/server/chunks/apps_0xektax._.js +3 -0
- package/admin/.next/server/chunks/apps_indusk-mcp_dist_lib_0097b-v._.js +4 -0
- package/admin/.next/server/chunks/apps_indusk-mcp_dist_lib_0xitfse._.js +4 -0
- package/admin/.next/server/chunks/apps_indusk-mcp_dist_lib_admin_recorder-loop_04syz1h.js +3 -0
- package/admin/.next/server/chunks/apps_indusk-mcp_dist_lib_build_index_03bpdb5.js +6 -4
- package/admin/.next/server/chunks/apps_indusk-mcp_dist_lib_plans_index_03eohu3.js +4 -4
- package/admin/.next/server/chunks/ssr/11sa_next_dist_0oij~o~._.js +1 -1
- package/admin/.next/server/chunks/ssr/11sa_next_dist_esm_build_templates_app-page_09csghm.js +1 -1
- package/admin/.next/server/chunks/ssr/[root-of-the-server]__05_r2eo._.js +1 -1
- package/admin/.next/server/chunks/ssr/[root-of-the-server]__07s8rx0._.js +1 -1
- package/admin/.next/server/chunks/ssr/[root-of-the-server]__0i4u9ut._.js +3 -0
- package/admin/.next/server/chunks/ssr/[root-of-the-server]__0m2d_gf._.js +3 -0
- package/admin/.next/server/chunks/ssr/[root-of-the-server]__0ot0o-3._.js +1 -1
- package/admin/.next/server/chunks/ssr/[root-of-the-server]__0soic-e._.js +1 -1
- package/admin/.next/server/chunks/ssr/[root-of-the-server]__0~eo2op._.js +3 -0
- package/admin/.next/server/chunks/ssr/[root-of-the-server]__11~p-z2._.js +3 -0
- package/admin/.next/server/chunks/ssr/_048afy-._.js +1 -1
- package/admin/.next/server/chunks/ssr/_04j3uuz._.js +3 -0
- package/admin/.next/server/chunks/ssr/_0n53yak._.js +3 -0
- package/admin/.next/server/chunks/ssr/apps_0dy1ra_._.js +5 -0
- package/admin/.next/server/chunks/ssr/apps_indusk-admin_src_03kj9h3._.js +1 -1
- package/admin/.next/server/chunks/ssr/apps_indusk-admin_src_components_0dp94.6._.js +1 -1
- package/admin/.next/server/chunks/ssr/apps_indusk-admin_src_components_Promises_tsx_0fhcnw4._.js +1 -1
- package/admin/.next/server/chunks/ssr/apps_indusk-mcp_dist_lib_promises_health_00bggwp.js +4 -0
- package/admin/.next/server/chunks/ssr/{[root-of-the-server]__073eg2p._.js → node_modules__pnpm_00aq603._.js} +2 -2
- package/admin/.next/server/edge/chunks/139l_next_dist_esm_build_templates_edge-wrapper_07_eywe.js +3 -0
- package/admin/.next/server/edge/chunks/_0d8yj-m._.js +3 -0
- package/admin/.next/server/instrumentation/middleware-manifest.json +12 -0
- package/admin/.next/server/instrumentation.js +4 -0
- package/admin/.next/server/instrumentation.js.nft.json +1 -0
- package/admin/.next/server/middleware-build-manifest.js +5 -5
- package/admin/.next/server/pages/500.html +1 -1
- package/admin/.next/static/chunks/{033_76_kz_tpp.js → 07hrbrru2wowq.js} +1 -1
- package/admin/.next/static/chunks/{187ewcrb2avxo.js → 0yb-zhcwww~54.js} +2 -2
- package/admin/.next/static/chunks/133kjqxxtod3a.js +1 -0
- package/admin/.next/static/chunks/{turbopack-0qbu8l-8inv.o.js → turbopack-173p-ctqje1hd.js} +1 -1
- package/dist/bin/cli.js +78 -0
- package/dist/bin/commands/checks.js +16 -2
- package/dist/bin/commands/editor.d.ts +10 -0
- package/dist/bin/commands/editor.js +62 -0
- package/dist/bin/commands/init.js +3 -38
- package/dist/bin/commands/plans.d.ts +12 -0
- package/dist/bin/commands/plans.js +56 -4
- package/dist/bin/commands/promises.d.ts +34 -4
- package/dist/bin/commands/promises.js +97 -7
- package/dist/bin/commands/release.d.ts +9 -0
- package/dist/bin/commands/release.js +152 -0
- package/dist/bin/commands/server.d.ts +23 -0
- package/dist/bin/commands/server.js +125 -0
- package/dist/bin/commands/ui.d.ts +2 -1
- package/dist/bin/commands/ui.js +7 -2
- package/dist/bin/commands/update.js +33 -56
- package/dist/lib/admin/daemon.d.ts +17 -5
- package/dist/lib/admin/daemon.js +57 -50
- package/dist/lib/admin/recorder-loop.d.ts +39 -0
- package/dist/lib/admin/recorder-loop.js +79 -0
- package/dist/lib/agents/lock.d.ts +7 -0
- package/dist/lib/agents/lock.js +20 -0
- package/dist/lib/always-on/durable-write.d.ts +4 -1
- package/dist/lib/always-on/durable-write.js +5 -2
- package/dist/lib/always-on/heartbeat.d.ts +2 -1
- package/dist/lib/always-on/heartbeat.js +1 -1
- package/dist/lib/always-on/pass.d.ts +2 -2
- package/dist/lib/always-on/pass.js +4 -11
- package/dist/lib/always-on/schedule.js +5 -0
- package/dist/lib/audit/inputs.d.ts +51 -0
- package/dist/lib/audit/inputs.js +135 -0
- package/dist/lib/build/build-session.js +3 -1
- package/dist/lib/build/index.d.ts +1 -0
- package/dist/lib/build/index.js +1 -0
- package/dist/lib/build/next-step.d.ts +2 -0
- package/dist/lib/build/next-step.js +3 -0
- package/dist/lib/build/read-plan.d.ts +1 -0
- package/dist/lib/build/read-plan.js +1 -0
- package/dist/lib/build/review.d.ts +2 -2
- package/dist/lib/build/review.js +2 -1
- package/dist/lib/build/runner.d.ts +12 -8
- package/dist/lib/build/runner.js +7 -2
- package/dist/lib/build/step-model.d.ts +14 -0
- package/dist/lib/build/step-model.js +25 -0
- package/dist/lib/checks/record.d.ts +6 -0
- package/dist/lib/checks/record.js +10 -0
- package/dist/lib/checks/steps.d.ts +2 -0
- package/dist/lib/checks/steps.js +57 -2
- package/dist/lib/cleanup/gate.d.ts +21 -6
- package/dist/lib/cleanup/gate.js +26 -16
- package/dist/lib/config.d.ts +47 -0
- package/dist/lib/falsification/skip.d.ts +2 -4
- package/dist/lib/falsification/skip.js +2 -17
- package/dist/lib/git.d.ts +6 -0
- package/dist/lib/git.js +18 -1
- package/dist/lib/hook-command.d.ts +19 -0
- package/dist/lib/hook-command.js +56 -3
- package/dist/lib/lifecycle.d.ts +2 -2
- package/dist/lib/lifecycle.js +6 -1
- package/dist/lib/models/next-session.d.ts +27 -0
- package/dist/lib/models/next-session.js +94 -0
- package/dist/lib/models/phase-model.d.ts +8 -0
- package/dist/lib/models/phase-model.js +11 -0
- package/dist/lib/models/tier-names.d.ts +14 -0
- package/dist/lib/models/tier-names.js +16 -0
- package/dist/lib/models/tiers.d.ts +67 -0
- package/dist/lib/models/tiers.js +136 -0
- package/dist/lib/pending-release.d.ts +1 -2
- package/dist/lib/pending-release.js +4 -13
- package/dist/lib/plans/bookkeeping.js +3 -1
- package/dist/lib/plans/land.d.ts +5 -1
- package/dist/lib/plans/land.js +32 -4
- package/dist/lib/process-identity.d.ts +41 -0
- package/dist/lib/process-identity.js +71 -0
- package/dist/lib/promises/age.d.ts +9 -0
- package/dist/lib/promises/age.js +20 -0
- package/dist/lib/promises/health-line.d.ts +69 -0
- package/dist/lib/promises/health-line.js +82 -0
- package/dist/lib/promises/health.d.ts +160 -1
- package/dist/lib/promises/health.js +209 -6
- package/dist/lib/promises/heard.d.ts +28 -0
- package/dist/lib/promises/heard.js +64 -0
- package/dist/lib/promises/inbox.d.ts +45 -0
- package/dist/lib/promises/inbox.js +68 -0
- package/dist/lib/promises/incidents.d.ts +33 -0
- package/dist/lib/promises/incidents.js +11 -9
- package/dist/lib/promises/record-commit.d.ts +24 -0
- package/dist/lib/promises/record-commit.js +125 -0
- package/dist/lib/promises/record.d.ts +75 -0
- package/dist/lib/promises/record.js +195 -0
- package/dist/lib/promises/registry.d.ts +9 -1
- package/dist/lib/promises/registry.js +2 -0
- package/dist/lib/promises/reminders.d.ts +30 -0
- package/dist/lib/promises/reminders.js +91 -0
- package/dist/lib/promises/slack.d.ts +6 -0
- package/dist/lib/promises/slack.js +15 -0
- package/dist/lib/promises/sources.js +8 -2
- package/dist/lib/promises/store.d.ts +78 -0
- package/dist/lib/promises/store.js +229 -0
- package/dist/lib/promises/test-incident.d.ts +53 -0
- package/dist/lib/promises/test-incident.js +113 -0
- package/dist/lib/promises/vocabulary.d.ts +7 -2
- package/dist/lib/promises/vocabulary.js +7 -2
- package/dist/lib/promises/watch.d.ts +16 -0
- package/dist/lib/promises/watch.js +15 -10
- package/dist/lib/release/announce.d.ts +12 -0
- package/dist/lib/release/announce.js +27 -0
- package/dist/lib/release/bugfix-plan.d.ts +34 -0
- package/dist/lib/release/bugfix-plan.js +147 -0
- package/dist/lib/release/junit.d.ts +24 -0
- package/dist/lib/release/junit.js +98 -0
- package/dist/lib/release/record.d.ts +37 -0
- package/dist/lib/release/record.js +47 -0
- package/dist/lib/release/route.d.ts +70 -0
- package/dist/lib/release/route.js +147 -0
- package/dist/lib/release/run.d.ts +87 -0
- package/dist/lib/release/run.js +53 -0
- package/dist/lib/release/settle.d.ts +16 -0
- package/dist/lib/release/settle.js +45 -0
- package/dist/lib/release/suspects.d.ts +13 -0
- package/dist/lib/release/suspects.js +33 -0
- package/dist/lib/rituals/skip.d.ts +20 -0
- package/dist/lib/rituals/skip.js +33 -0
- package/dist/lib/server/connect.d.ts +51 -0
- package/dist/lib/server/connect.js +60 -0
- package/dist/lib/server/deploy.d.ts +64 -0
- package/dist/lib/server/deploy.js +175 -0
- package/dist/lib/server/fly-config.d.ts +15 -0
- package/dist/lib/server/fly-config.js +26 -0
- package/dist/lib/server/fly-state.d.ts +25 -0
- package/dist/lib/server/fly-state.js +52 -0
- package/dist/lib/server/fly.d.ts +18 -0
- package/dist/lib/server/fly.js +29 -0
- package/dist/lib/server/image.d.ts +7 -0
- package/dist/lib/server/image.js +39 -0
- package/dist/lib/server/plan-deploy.d.ts +47 -0
- package/dist/lib/server/plan-deploy.js +70 -0
- package/dist/lib/server/redact.d.ts +16 -0
- package/dist/lib/server/redact.js +13 -0
- package/dist/lib/server/secrets-file.d.ts +21 -0
- package/dist/lib/server/secrets-file.js +42 -0
- package/dist/lib/session/manager.js +2 -15
- package/dist/lib/telemetry/daemon.d.ts +0 -26
- package/dist/lib/telemetry/daemon.js +5 -10
- package/dist/lib/telemetry/server.d.ts +9 -2
- package/dist/lib/telemetry/server.js +1 -1
- package/dist/lib/telemetry/status.d.ts +2 -1
- package/dist/lib/telemetry/status.js +5 -10
- package/dist/lib/telemetry/stop.d.ts +3 -6
- package/dist/lib/telemetry/stop.js +2 -8
- package/dist/lib/version-check.d.ts +6 -5
- package/dist/lib/version-check.js +18 -6
- package/dist/lib/worktree/plan-worktree-commands.js +20 -3
- package/dist/lib/worktree/plan-worktrees.js +17 -4
- package/dist/tools/promise-tools.js +26 -1
- package/editor/indusk.vsix +0 -0
- package/hooks/CLAUDE.md +19 -4
- package/hooks/_commit-anchor.js +15 -4
- package/hooks/_inbox.js +75 -0
- package/hooks/_phase-tier.js +110 -0
- package/hooks/break-inbox.js +118 -0
- package/hooks/check-gates.js +63 -8
- package/hooks/stash-guard.js +151 -0
- package/hooks/validate-impl-structure.js +20 -1
- package/package.json +32 -2
- package/skills/audit.md +96 -0
- package/skills/catchup.md +18 -6
- package/skills/cleanup.md +2 -2
- package/skills/falsify.md +1 -1
- package/skills/planner.md +11 -2
- package/skills/retrospective.md +24 -9
- package/skills/work.md +11 -1
- package/templates/planning/CLAUDE.md +18 -4
- package/templates/server/Dockerfile +40 -0
- package/templates/server/fly.toml +78 -0
- package/admin/.next/server/chunks/[root-of-the-server]__0iocjuv._.js +0 -3
- package/admin/.next/server/chunks/[root-of-the-server]__12m1y6a._.js +0 -3
- package/admin/.next/server/chunks/apps_0e6y.pd._.js +0 -9
- package/admin/.next/server/chunks/apps_0nuxis9._.js +0 -9
- package/admin/.next/server/chunks/apps_0qroxnv._.js +0 -9
- package/admin/.next/server/chunks/apps_0w4cnhf._.js +0 -9
- package/admin/.next/server/chunks/apps_11jb.pq._.js +0 -9
- package/admin/.next/server/chunks/ssr/[root-of-the-server]__0trztae._.js +0 -3
- package/admin/.next/server/chunks/ssr/[root-of-the-server]__0xdjthd._.js +0 -3
- package/admin/.next/server/chunks/ssr/[root-of-the-server]__10rgh1r._.js +0 -3
- package/admin/.next/server/chunks/ssr/_0wce~lz._.js +0 -3
- package/admin/.next/server/chunks/ssr/apps_0dzo~r8._.js +0 -5
- package/admin/.next/server/chunks/ssr/apps_indusk-admin_src_lib_promise-health_ts_0qlhtf_._.js +0 -3
- package/admin/.next/static/chunks/09g._ssq89-79.js +0 -1
- package/dist/bin/commands/infra.d.ts +0 -3
- package/dist/bin/commands/infra.js +0 -225
- package/dist/filtering-exporter.d.ts +0 -29
- package/dist/filtering-exporter.js +0 -65
- package/dist/instrumentation.d.ts +0 -17
- package/dist/instrumentation.js +0 -53
- package/dist/lib/beam/format.d.ts +0 -7
- package/dist/lib/beam/format.js +0 -82
- package/dist/lib/beam/graph-client.d.ts +0 -18
- package/dist/lib/beam/graph-client.js +0 -41
- package/dist/lib/beam/pipeline.d.ts +0 -15
- package/dist/lib/beam/pipeline.js +0 -25
- package/dist/lib/beam/queries/anchor-lookup.d.ts +0 -6
- package/dist/lib/beam/queries/anchor-lookup.js +0 -32
- package/dist/lib/beam/queries/cgc-relationships.d.ts +0 -6
- package/dist/lib/beam/queries/cgc-relationships.js +0 -54
- package/dist/lib/beam/queries/eval-findings.d.ts +0 -6
- package/dist/lib/beam/queries/eval-findings.js +0 -32
- package/dist/lib/beam/queries/neighbor-facts.d.ts +0 -6
- package/dist/lib/beam/queries/neighbor-facts.js +0 -31
- package/dist/lib/beam/queries/structural-neighbors.d.ts +0 -6
- package/dist/lib/beam/queries/structural-neighbors.js +0 -41
- package/dist/lib/beam/queries/target-facts.d.ts +0 -6
- package/dist/lib/beam/queries/target-facts.js +0 -32
- package/dist/lib/beam/runner.d.ts +0 -14
- package/dist/lib/beam/runner.js +0 -145
- package/dist/lib/beam/types.d.ts +0 -49
- package/dist/lib/beam/types.js +0 -7
- package/dist/lib/eval/judge-runner.d.ts +0 -28
- package/dist/lib/eval/judge-runner.js +0 -252
- package/dist/lib/eval/persistent-judge.d.ts +0 -20
- package/dist/lib/eval/persistent-judge.js +0 -192
- package/dist/lib/graphiti-client.d.ts +0 -93
- package/dist/lib/graphiti-client.js +0 -209
- package/dist/lib/scm/detect.d.ts +0 -37
- package/dist/lib/scm/detect.js +0 -83
- package/dist/lib/semantic-graph/adapter.d.ts +0 -55
- package/dist/lib/semantic-graph/adapter.js +0 -12
- package/dist/lib/semantic-graph/adapters/cgc.d.ts +0 -28
- package/dist/lib/semantic-graph/adapters/cgc.js +0 -163
- package/dist/lib/semantic-graph/events.d.ts +0 -156
- package/dist/lib/semantic-graph/events.js +0 -93
- package/dist/lib/semantic-graph/graphiti-log-wrapper.d.ts +0 -43
- package/dist/lib/semantic-graph/graphiti-log-wrapper.js +0 -117
- package/dist/lib/semantic-graph/index.d.ts +0 -14
- package/dist/lib/semantic-graph/index.js +0 -16
- package/dist/lib/semantic-graph/jj.d.ts +0 -42
- package/dist/lib/semantic-graph/jj.js +0 -98
- package/dist/lib/semantic-graph/log-reader.d.ts +0 -22
- package/dist/lib/semantic-graph/log-reader.js +0 -50
- package/dist/lib/semantic-graph/log-writer.d.ts +0 -24
- package/dist/lib/semantic-graph/log-writer.js +0 -38
- package/dist/lib/semantic-graph/paths.d.ts +0 -13
- package/dist/lib/semantic-graph/paths.js +0 -18
- package/dist/lib/semantic-graph/replay.d.ts +0 -52
- package/dist/lib/semantic-graph/replay.js +0 -58
- package/dist/lib/semantic-graph/runtime-client.d.ts +0 -58
- package/dist/lib/semantic-graph/runtime-client.js +0 -208
- package/dist/lib/semantic-graph/sync-engine.d.ts +0 -41
- package/dist/lib/semantic-graph/sync-engine.js +0 -174
- package/dist/lib/verify/roots.d.ts +0 -40
- package/dist/lib/verify/roots.js +0 -57
- package/dist/logger.d.ts +0 -19
- package/dist/logger.js +0 -46
- package/dist/tools/graph-tools.d.ts +0 -6
- package/dist/tools/graph-tools.js +0 -698
- /package/admin/.next/static/{ucvgwNe7y8LeVmL4xFJY1 → 5EsQZx8ke6XV61Ii4plOw}/_buildManifest.js +0 -0
- /package/admin/.next/static/{ucvgwNe7y8LeVmL4xFJY1 → 5EsQZx8ke6XV61Ii4plOw}/_clientMiddlewareManifest.js +0 -0
- /package/admin/.next/static/{ucvgwNe7y8LeVmL4xFJY1 → 5EsQZx8ke6XV61Ii4plOw}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
2
|
+
import { join, posix } from "node:path";
|
|
3
|
+
import { planFolders } from "../promises/plan-folder.js";
|
|
4
|
+
import { readPromises } from "../promises/registry.js";
|
|
5
|
+
import { readImpl } from "../promises/rows.js";
|
|
6
|
+
import { recordTestFailure } from "../promises/test-incident.js";
|
|
7
|
+
import { ownerReopener } from "../promises/watch.js";
|
|
8
|
+
import { openOrExtendBugfixPlan } from "./bugfix-plan.js";
|
|
9
|
+
/** A test path as a row and a JUnit report both spell it: repo-relative, no `./`. */
|
|
10
|
+
function normalise(path) {
|
|
11
|
+
return posix.normalize(path.trim()).replace(/^\.\//, "");
|
|
12
|
+
}
|
|
13
|
+
export function routeFailure(root, file) {
|
|
14
|
+
const want = normalise(file);
|
|
15
|
+
const rows = [];
|
|
16
|
+
const unreadable = [];
|
|
17
|
+
for (const folder of planFolders(root)) {
|
|
18
|
+
const implPath = join(folder.dir, "impl.md");
|
|
19
|
+
if (!existsSync(implPath))
|
|
20
|
+
continue;
|
|
21
|
+
const impl = readImpl(readFileSync(implPath, "utf-8"));
|
|
22
|
+
if (!impl.ok) {
|
|
23
|
+
unreadable.push(folder.plan);
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
for (const row of impl.trajectory.rows) {
|
|
27
|
+
if (!(row.test ?? []).some((t) => normalise(t) === want))
|
|
28
|
+
continue;
|
|
29
|
+
rows.push({
|
|
30
|
+
plan: folder.plan,
|
|
31
|
+
archived: folder.archived,
|
|
32
|
+
id: row.id,
|
|
33
|
+
promises: row.purpose?.promises ?? [],
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return { promises: [...new Set(rows.flatMap((r) => r.promises))], rows, unreadable };
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Route each failing file (ADR D6, D7): a file whose rows' `For` names a
|
|
41
|
+
* promise becomes an incident on each such promise — one per promise, every
|
|
42
|
+
* file it claims in it — opened or extended through `recordTestFailure`, and
|
|
43
|
+
* the owner reopened through the path `watch` uses. A file no promise in the
|
|
44
|
+
* registry claims goes to a draft bugfix plan, opened or extended (D8).
|
|
45
|
+
*
|
|
46
|
+
* promise: a-failing-slow-test-breaks-its-promise
|
|
47
|
+
*/
|
|
48
|
+
export async function routeFailures(root, settled, facts) {
|
|
49
|
+
const unrouted = {
|
|
50
|
+
failed: settled.failed,
|
|
51
|
+
incidents: [],
|
|
52
|
+
plans: [],
|
|
53
|
+
planProblems: [],
|
|
54
|
+
unreadable: [],
|
|
55
|
+
};
|
|
56
|
+
if (settled.failed.length === 0)
|
|
57
|
+
return unrouted;
|
|
58
|
+
const first = readPromises(root);
|
|
59
|
+
if (!first.ok) {
|
|
60
|
+
// A registry that cannot be read is no place to write an incident.
|
|
61
|
+
return {
|
|
62
|
+
...unrouted,
|
|
63
|
+
refused: "missing" in first
|
|
64
|
+
? `no promise registry at ${first.missing}`
|
|
65
|
+
: `the promise registry has malformed entries: ${first.problems.map((p) => p.file).join(", ")}`,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
const { claims, unreadable } = claimsOf(root, settled.failed, first.registry.promises);
|
|
69
|
+
const incidents = [];
|
|
70
|
+
const byFile = new Map();
|
|
71
|
+
for (const [name, files] of claims) {
|
|
72
|
+
// Read again for each promise, since the incident one opened is on disk now.
|
|
73
|
+
const read = readPromises(root);
|
|
74
|
+
const registry = read.ok ? read.registry : first.registry;
|
|
75
|
+
const promise = live(registry.promises, name);
|
|
76
|
+
if (!promise)
|
|
77
|
+
continue;
|
|
78
|
+
const owner = await ownerReopener(root, promise);
|
|
79
|
+
const change = recordTestFailure(registry, promise, {
|
|
80
|
+
tests: files.map((file) => ({ file, names: settled.tests?.[file] ?? [] })),
|
|
81
|
+
release: { version: facts.version, commit: facts.commit },
|
|
82
|
+
suspects: facts.suspects,
|
|
83
|
+
now: facts.now,
|
|
84
|
+
}, owner.taken());
|
|
85
|
+
const reopen = owner.reopen(change.id, change.kind);
|
|
86
|
+
incidents.push({ ...change, promise: promise.name, owner: promise.owner, reopen });
|
|
87
|
+
for (const file of files)
|
|
88
|
+
byFile.set(file, [...(byFile.get(file) ?? []), change.id]);
|
|
89
|
+
}
|
|
90
|
+
const { failed, plans, planProblems } = await routeUnclaimed(root, settled, byFile, facts);
|
|
91
|
+
return { failed, incidents, plans, planProblems, unreadable };
|
|
92
|
+
}
|
|
93
|
+
/** Each failing file an incident claimed says so; every other one goes to its bugfix plan (D8). */
|
|
94
|
+
async function routeUnclaimed(root, settled, incidentsByFile, facts) {
|
|
95
|
+
const plans = [];
|
|
96
|
+
const planProblems = [];
|
|
97
|
+
const failed = [];
|
|
98
|
+
for (const { file } of settled.failed) {
|
|
99
|
+
const ids = incidentsByFile.get(file);
|
|
100
|
+
if (ids) {
|
|
101
|
+
failed.push({ file, routed: ids.map((id) => `incident ${id}`).join(", ") });
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
try {
|
|
105
|
+
const plan = await openOrExtendBugfixPlan(root, {
|
|
106
|
+
file,
|
|
107
|
+
names: settled.tests?.[file] ?? [],
|
|
108
|
+
rows: routeFailure(root, file).rows,
|
|
109
|
+
release: { version: facts.version, commit: facts.commit },
|
|
110
|
+
suspects: facts.suspects,
|
|
111
|
+
now: facts.now,
|
|
112
|
+
});
|
|
113
|
+
if (!plans.some((p) => p.plan === plan.plan))
|
|
114
|
+
plans.push(plan);
|
|
115
|
+
failed.push({ file, routed: `plan ${plan.plan}` });
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
planProblems.push(`${file}: ${err instanceof Error ? err.message : String(err)}`);
|
|
119
|
+
failed.push({ file, routed: "unrouted" });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return { failed, plans, planProblems };
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Which live promise claims which failing files: each promise a naming row's
|
|
126
|
+
* `For` cell names, with every file it claims, and the impls that could not
|
|
127
|
+
* be read on the way.
|
|
128
|
+
*/
|
|
129
|
+
function claimsOf(root, failed, promises) {
|
|
130
|
+
const unreadable = new Set();
|
|
131
|
+
const claims = new Map();
|
|
132
|
+
for (const { file } of failed) {
|
|
133
|
+
const route = routeFailure(root, file);
|
|
134
|
+
for (const plan of route.unreadable)
|
|
135
|
+
unreadable.add(plan);
|
|
136
|
+
for (const name of route.promises) {
|
|
137
|
+
const promise = live(promises, name);
|
|
138
|
+
if (promise)
|
|
139
|
+
claims.set(promise.name, [...(claims.get(promise.name) ?? []), file]);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return { claims, unreadable: [...unreadable].sort() };
|
|
143
|
+
}
|
|
144
|
+
/** The registry's live promise a row names, by its name or an earlier one; none when retired or unknown. */
|
|
145
|
+
function live(promises, name) {
|
|
146
|
+
return promises.find((p) => p.state !== "retired" && (p.name === name || p.aliases.includes(name)));
|
|
147
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { GreenRun } from "../checks/record.js";
|
|
2
|
+
import type { WorkflowSteps } from "../config.js";
|
|
3
|
+
/**
|
|
4
|
+
* `indusk release` as a function of its inputs (release-records-its-failures
|
|
5
|
+
* D1, D3): the declared release, run in the declared order. The commands, the
|
|
6
|
+
* clock, the code key and the green-run record arrive as `deps`, so the order
|
|
7
|
+
* and the outcome rules are unit-testable without a process, a git tree or a
|
|
8
|
+
* home directory.
|
|
9
|
+
*
|
|
10
|
+
* Order: slow tests if `when: before` (a red run stops here), the release
|
|
11
|
+
* `command` (a failure stops here: no slow tests after it), slow tests if
|
|
12
|
+
* `when: after`. A slow run a fully green run already covered is skipped.
|
|
13
|
+
* Outcome: `done_when: published` is done once the command succeeds;
|
|
14
|
+
* `done_when: green` only when the slow run is green (or was covered).
|
|
15
|
+
*
|
|
16
|
+
* Commands are what the project declares, run as written from the project
|
|
17
|
+
* root — never a path of dusk's own.
|
|
18
|
+
*
|
|
19
|
+
* promise: a-release-runs-as-its-project-declares
|
|
20
|
+
* promise: slow-checks-run-once-per-tree
|
|
21
|
+
* promise: landing-and-release-name-the-projects-commands
|
|
22
|
+
*/
|
|
23
|
+
export interface ReleaseDeps {
|
|
24
|
+
steps: WorkflowSteps;
|
|
25
|
+
/** Run a shell command from the project root; the exit code. */
|
|
26
|
+
exec(command: string): {
|
|
27
|
+
code: number;
|
|
28
|
+
};
|
|
29
|
+
now(): Date;
|
|
30
|
+
/** The key of the code the slow tests cover now, or `null` when there is no honest key. */
|
|
31
|
+
codeKey(): string | null;
|
|
32
|
+
/** The latest fully green run that covered `key`. */
|
|
33
|
+
coveringRun(key: string): GreenRun | null;
|
|
34
|
+
/** Record a fully green slow run, as `indusk checks slow` would. */
|
|
35
|
+
recordGreen(run: {
|
|
36
|
+
key: string;
|
|
37
|
+
at: string;
|
|
38
|
+
command: string;
|
|
39
|
+
}): void;
|
|
40
|
+
/**
|
|
41
|
+
* The seam where a red slow run's failures are read, rerun and routed
|
|
42
|
+
* (Build Phases 2–4). Absent: no failure is read, and a red run records
|
|
43
|
+
* `failed: []`.
|
|
44
|
+
*/
|
|
45
|
+
settleFailures?(slow: SlowRun): SettledFailures;
|
|
46
|
+
}
|
|
47
|
+
/** One failing file and where it was routed: `incident <id>` or `plan <name>`. */
|
|
48
|
+
export interface FailedFile {
|
|
49
|
+
file: string;
|
|
50
|
+
routed: string;
|
|
51
|
+
}
|
|
52
|
+
export interface SettledFailures {
|
|
53
|
+
failed: FailedFile[];
|
|
54
|
+
flakes: string[];
|
|
55
|
+
environment?: {
|
|
56
|
+
failed: number;
|
|
57
|
+
total: number;
|
|
58
|
+
};
|
|
59
|
+
/** The failed tests' names per failing file, from the report: what an incident names; not on the record. */
|
|
60
|
+
tests?: Record<string, string[]>;
|
|
61
|
+
}
|
|
62
|
+
export interface SlowRun {
|
|
63
|
+
command: string;
|
|
64
|
+
exit: number;
|
|
65
|
+
/** When the run began: a report older than this is an earlier run's. */
|
|
66
|
+
startedAt: Date;
|
|
67
|
+
}
|
|
68
|
+
export type SlowResult = "green" | "red" | "skipped" | "not run";
|
|
69
|
+
export interface ReleaseOutcome {
|
|
70
|
+
/** `false` when the project declares no release command; nothing ran. */
|
|
71
|
+
declared: boolean;
|
|
72
|
+
published: boolean;
|
|
73
|
+
done: boolean;
|
|
74
|
+
slow: {
|
|
75
|
+
ran: boolean;
|
|
76
|
+
green: boolean;
|
|
77
|
+
skipped: boolean;
|
|
78
|
+
result: SlowResult;
|
|
79
|
+
/** The green run that covered the code, when the slow run was skipped. */
|
|
80
|
+
covering?: GreenRun;
|
|
81
|
+
};
|
|
82
|
+
/** What the run records on the release record. */
|
|
83
|
+
recorded: SettledFailures;
|
|
84
|
+
/** What a reader should look at when the release is published and not done, or a run was red. */
|
|
85
|
+
openFailures: string[];
|
|
86
|
+
}
|
|
87
|
+
export declare function runRelease(deps: ReleaseDeps): ReleaseOutcome;
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
const EMPTY = { failed: [], flakes: [] };
|
|
2
|
+
export function runRelease(deps) {
|
|
3
|
+
const release = deps.steps.release ?? {};
|
|
4
|
+
const slowSpec = release.slow_tests;
|
|
5
|
+
const outcome = {
|
|
6
|
+
declared: Boolean(release.command),
|
|
7
|
+
published: false,
|
|
8
|
+
done: false,
|
|
9
|
+
slow: { ran: false, green: false, skipped: false, result: "not run" },
|
|
10
|
+
recorded: EMPTY,
|
|
11
|
+
openFailures: [],
|
|
12
|
+
};
|
|
13
|
+
if (!release.command)
|
|
14
|
+
return outcome;
|
|
15
|
+
const runSlow = () => {
|
|
16
|
+
if (!slowSpec)
|
|
17
|
+
return true;
|
|
18
|
+
const key = deps.codeKey();
|
|
19
|
+
const covering = key ? deps.coveringRun(key) : null;
|
|
20
|
+
if (covering) {
|
|
21
|
+
outcome.slow = { ran: false, green: true, skipped: true, result: "skipped", covering };
|
|
22
|
+
return true;
|
|
23
|
+
}
|
|
24
|
+
const started = deps.now();
|
|
25
|
+
const at = started.toISOString();
|
|
26
|
+
const run = {
|
|
27
|
+
command: slowSpec.command,
|
|
28
|
+
exit: deps.exec(slowSpec.command).code,
|
|
29
|
+
startedAt: started,
|
|
30
|
+
};
|
|
31
|
+
const green = run.exit === 0;
|
|
32
|
+
outcome.slow = { ran: true, green, skipped: false, result: green ? "green" : "red" };
|
|
33
|
+
if (green) {
|
|
34
|
+
if (key && deps.codeKey() === key)
|
|
35
|
+
deps.recordGreen({ key, at, command: slowSpec.command });
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
outcome.recorded = deps.settleFailures?.(run) ?? EMPTY;
|
|
39
|
+
outcome.openFailures = outcome.recorded.failed.length
|
|
40
|
+
? outcome.recorded.failed.map((f) => f.file)
|
|
41
|
+
: [slowSpec.command];
|
|
42
|
+
return false;
|
|
43
|
+
};
|
|
44
|
+
if (slowSpec?.when === "before" && !runSlow())
|
|
45
|
+
return outcome;
|
|
46
|
+
outcome.published = deps.exec(release.command).code === 0;
|
|
47
|
+
if (!outcome.published)
|
|
48
|
+
return outcome;
|
|
49
|
+
if (slowSpec?.when === "after")
|
|
50
|
+
runSlow();
|
|
51
|
+
outcome.done = release.done_when === "green" ? outcome.slow.green || !slowSpec : true;
|
|
52
|
+
return outcome;
|
|
53
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { WorkflowSteps } from "../config.js";
|
|
2
|
+
import type { SettledFailures } from "./run.js";
|
|
3
|
+
/**
|
|
4
|
+
* A red slow run, settled (release-records-its-failures D4, D5): the failing
|
|
5
|
+
* files are read from the declared JUnit report; when more than half the
|
|
6
|
+
* report's files failed it is the environment and nothing else is said; else
|
|
7
|
+
* the failing files are run once more through `slow_tests.rerun` (`{files}`
|
|
8
|
+
* substituted) and the report is read again — a file the rerun does not leave
|
|
9
|
+
* failing is a flake.
|
|
10
|
+
*
|
|
11
|
+
* promise: a-failure-is-read-from-the-report
|
|
12
|
+
* promise: a-flake-opens-nothing
|
|
13
|
+
*/
|
|
14
|
+
export declare function settleFromReport(steps: WorkflowSteps, root: string, exec: (command: string) => {
|
|
15
|
+
code: number;
|
|
16
|
+
}, since?: Date): SettledFailures;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { failedFiles } from "./junit.js";
|
|
2
|
+
/**
|
|
3
|
+
* A red slow run, settled (release-records-its-failures D4, D5): the failing
|
|
4
|
+
* files are read from the declared JUnit report; when more than half the
|
|
5
|
+
* report's files failed it is the environment and nothing else is said; else
|
|
6
|
+
* the failing files are run once more through `slow_tests.rerun` (`{files}`
|
|
7
|
+
* substituted) and the report is read again — a file the rerun does not leave
|
|
8
|
+
* failing is a flake.
|
|
9
|
+
*
|
|
10
|
+
* promise: a-failure-is-read-from-the-report
|
|
11
|
+
* promise: a-flake-opens-nothing
|
|
12
|
+
*/
|
|
13
|
+
export function settleFromReport(steps, root, exec, since) {
|
|
14
|
+
const spec = steps.release?.slow_tests;
|
|
15
|
+
if (!spec)
|
|
16
|
+
return { failed: [], flakes: [] };
|
|
17
|
+
const first = failedFiles(spec.report, root, since);
|
|
18
|
+
if (!first.readable || first.files.size === 0)
|
|
19
|
+
return { failed: [], flakes: [] };
|
|
20
|
+
if (first.files.size * 2 > first.total) {
|
|
21
|
+
return {
|
|
22
|
+
failed: [],
|
|
23
|
+
flakes: [],
|
|
24
|
+
environment: { failed: first.files.size, total: first.total },
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
const names = [...first.files.keys()].sort();
|
|
28
|
+
let still = names;
|
|
29
|
+
let last = first;
|
|
30
|
+
if (spec.rerun) {
|
|
31
|
+
exec(spec.rerun.replaceAll("{files}", names.map(shellQuote).join(" ")));
|
|
32
|
+
const second = failedFiles(spec.report, root, since);
|
|
33
|
+
if (second.readable) {
|
|
34
|
+
still = names.filter((f) => !second.passed.has(f));
|
|
35
|
+
last = second;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
failed: still.map((file) => ({ file, routed: "unrouted" })),
|
|
40
|
+
flakes: names.filter((f) => !still.includes(f)),
|
|
41
|
+
tests: Object.fromEntries(still.map((f) => [f, last.files.get(f) ?? first.files.get(f) ?? []])),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
/** One shell word: single-quoted, an embedded quote as `'\''`. */
|
|
45
|
+
const shellQuote = (text) => `'${text.replaceAll("'", "'\\''")}'`;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { GreenRun } from "../checks/record.js";
|
|
2
|
+
import type { WorkflowSteps } from "../config.js";
|
|
3
|
+
import type { Suspects } from "../promises/test-incident.js";
|
|
4
|
+
/**
|
|
5
|
+
* The commits that may have broken the slow tests (release-records-its-failures
|
|
6
|
+
* D9): `git log <sha>..HEAD` over the release's `covers` paths (the whole
|
|
7
|
+
* repository when it declares none), from the commit the last green slow run
|
|
8
|
+
* was made on. A run recorded without a `sha`, or a `sha` git no longer has,
|
|
9
|
+
* names none and says why — never a guess at a range.
|
|
10
|
+
*
|
|
11
|
+
* promise: a-failing-slow-test-breaks-its-promise
|
|
12
|
+
*/
|
|
13
|
+
export declare function suspectsSince(root: string, steps: WorkflowSteps, green: GreenRun | null): Suspects;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { gitSync } from "../bookkeeping/git.js";
|
|
2
|
+
/**
|
|
3
|
+
* The commits that may have broken the slow tests (release-records-its-failures
|
|
4
|
+
* D9): `git log <sha>..HEAD` over the release's `covers` paths (the whole
|
|
5
|
+
* repository when it declares none), from the commit the last green slow run
|
|
6
|
+
* was made on. A run recorded without a `sha`, or a `sha` git no longer has,
|
|
7
|
+
* names none and says why — never a guess at a range.
|
|
8
|
+
*
|
|
9
|
+
* promise: a-failing-slow-test-breaks-its-promise
|
|
10
|
+
*/
|
|
11
|
+
export function suspectsSince(root, steps, green) {
|
|
12
|
+
const covers = steps.release?.covers ?? ["."];
|
|
13
|
+
if (!green)
|
|
14
|
+
return { since: null, unnamed: "no green slow run is recorded", covers, commits: [] };
|
|
15
|
+
if (!green.sha || green.sha === "unknown") {
|
|
16
|
+
return {
|
|
17
|
+
since: null,
|
|
18
|
+
unnamed: `the last green slow run (${green.at}) recorded no commit to count from`,
|
|
19
|
+
covers,
|
|
20
|
+
commits: [],
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
const log = gitSync(root, "log", "--format=%h %s", `${green.sha}..HEAD`, "--", ...covers);
|
|
24
|
+
if (log.code !== 0) {
|
|
25
|
+
return {
|
|
26
|
+
since: null,
|
|
27
|
+
unnamed: `git could not list the commits since ${green.sha.slice(0, 7)}, the last green slow run's`,
|
|
28
|
+
covers,
|
|
29
|
+
commits: [],
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
return { since: green.sha, covers, commits: log.out.split("\n").filter(Boolean) };
|
|
33
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export interface SkipCheck {
|
|
2
|
+
skipped: boolean;
|
|
3
|
+
reason: string | null;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Whether the impl (full file content, frontmatter included) opts out of a
|
|
7
|
+
* ritual. Opt-out requires both fields in frontmatter:
|
|
8
|
+
*
|
|
9
|
+
* <ritual>: skipped
|
|
10
|
+
* <ritual>_reason: "a non-empty reason"
|
|
11
|
+
*
|
|
12
|
+
* Returns `{ skipped: true, reason }` only if both are present and the reason
|
|
13
|
+
* is non-empty after trimming. Any other state — a bare flag, a flag set to
|
|
14
|
+
* anything but `skipped`, a missing, empty or non-string reason, another
|
|
15
|
+
* ritual's pair, unparsable frontmatter — returns `{ skipped: false, reason: null }`.
|
|
16
|
+
*
|
|
17
|
+
* The two-field shape keeps the reason unambiguous against YAML parsers:
|
|
18
|
+
* colons inside quoted YAML strings are fragile across parsers.
|
|
19
|
+
*/
|
|
20
|
+
export declare function isRitualSkipped(implContent: string, ritual: "falsification" | "cleanup" | "audit"): SkipCheck;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import matter from "gray-matter";
|
|
2
|
+
/**
|
|
3
|
+
* Whether the impl (full file content, frontmatter included) opts out of a
|
|
4
|
+
* ritual. Opt-out requires both fields in frontmatter:
|
|
5
|
+
*
|
|
6
|
+
* <ritual>: skipped
|
|
7
|
+
* <ritual>_reason: "a non-empty reason"
|
|
8
|
+
*
|
|
9
|
+
* Returns `{ skipped: true, reason }` only if both are present and the reason
|
|
10
|
+
* is non-empty after trimming. Any other state — a bare flag, a flag set to
|
|
11
|
+
* anything but `skipped`, a missing, empty or non-string reason, another
|
|
12
|
+
* ritual's pair, unparsable frontmatter — returns `{ skipped: false, reason: null }`.
|
|
13
|
+
*
|
|
14
|
+
* The two-field shape keeps the reason unambiguous against YAML parsers:
|
|
15
|
+
* colons inside quoted YAML strings are fragile across parsers.
|
|
16
|
+
*/
|
|
17
|
+
export function isRitualSkipped(implContent, ritual) {
|
|
18
|
+
try {
|
|
19
|
+
const { data } = matter(implContent);
|
|
20
|
+
if (data[ritual] !== "skipped")
|
|
21
|
+
return { skipped: false, reason: null };
|
|
22
|
+
const reasonRaw = data[`${ritual}_reason`];
|
|
23
|
+
if (typeof reasonRaw !== "string")
|
|
24
|
+
return { skipped: false, reason: null };
|
|
25
|
+
const reason = reasonRaw.trim();
|
|
26
|
+
if (!reason)
|
|
27
|
+
return { skipped: false, reason: null };
|
|
28
|
+
return { skipped: true, reason };
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
return { skipped: false, reason: null };
|
|
32
|
+
}
|
|
33
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import type { LineWriter } from "./redact.js";
|
|
2
|
+
import type { SecretsFile } from "./secrets-file.js";
|
|
3
|
+
/**
|
|
4
|
+
* `indusk server connect`: point a project at a recording server the person
|
|
5
|
+
* runs, wherever it runs (server-provisioning, ADR D1, D4, D6).
|
|
6
|
+
*
|
|
7
|
+
* The server is read back first — a mark sent through its intake and found
|
|
8
|
+
* through its query API, at the addresses the project will use. Only then is
|
|
9
|
+
* anything written: the project's `promises.jaeger` names the server and the
|
|
10
|
+
* *name* of the credential's variable, and the value goes to the machine's
|
|
11
|
+
* secrets file. A server that does not answer is never named; a project that
|
|
12
|
+
* names one reads *watcher blind* forever after.
|
|
13
|
+
*
|
|
14
|
+
* promise: a-project-connects-to-its-server-in-one-command
|
|
15
|
+
* promise: a-server-is-read-back-before-the-command-ends
|
|
16
|
+
*/
|
|
17
|
+
export interface ConnectInput {
|
|
18
|
+
projectRoot: string;
|
|
19
|
+
projectName: string;
|
|
20
|
+
queryUrl: string;
|
|
21
|
+
otlpUrl: string;
|
|
22
|
+
credential: string;
|
|
23
|
+
}
|
|
24
|
+
export interface ConnectDeps {
|
|
25
|
+
probe(target: {
|
|
26
|
+
queryUrl: string;
|
|
27
|
+
otlpUrl: string;
|
|
28
|
+
credential: string;
|
|
29
|
+
}): Promise<void>;
|
|
30
|
+
secrets: SecretsFile;
|
|
31
|
+
out: LineWriter;
|
|
32
|
+
}
|
|
33
|
+
export interface Connected {
|
|
34
|
+
credentialEnv: string;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* The variable a project's credential is stored under: one per project, so
|
|
38
|
+
* two projects never share one. The name is for people; the suffix is a short
|
|
39
|
+
* hash of where the project lives — its repository, so every worktree of one
|
|
40
|
+
* repository shares it, or the folder when it is not one. Two projects in
|
|
41
|
+
* folders of the same name shared a variable before, and connecting one
|
|
42
|
+
* replaced the other's credential (server-provisioning A25).
|
|
43
|
+
*/
|
|
44
|
+
export declare function credentialEnvFor(projectRoot: string, projectName: string): string;
|
|
45
|
+
export declare function connect(input: ConnectInput, deps: ConnectDeps): Promise<Connected>;
|
|
46
|
+
/** The real read-back: the heartbeat probe every promise read already runs. */
|
|
47
|
+
export declare function probeServer(project: string): (target: {
|
|
48
|
+
queryUrl: string;
|
|
49
|
+
otlpUrl: string;
|
|
50
|
+
credential: string;
|
|
51
|
+
}) => Promise<void>;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { realpathSync } from "node:fs";
|
|
3
|
+
import { dirname } from "node:path";
|
|
4
|
+
import { readConfig, writeConfig } from "../config.js";
|
|
5
|
+
import { probeWatcher } from "../promises/probe.js";
|
|
6
|
+
import { jaegerEndpoint } from "../promises/telemetry.js";
|
|
7
|
+
import { gitCommonDirOf } from "../worktree/layout.js";
|
|
8
|
+
/**
|
|
9
|
+
* The variable a project's credential is stored under: one per project, so
|
|
10
|
+
* two projects never share one. The name is for people; the suffix is a short
|
|
11
|
+
* hash of where the project lives — its repository, so every worktree of one
|
|
12
|
+
* repository shares it, or the folder when it is not one. Two projects in
|
|
13
|
+
* folders of the same name shared a variable before, and connecting one
|
|
14
|
+
* replaced the other's credential (server-provisioning A25).
|
|
15
|
+
*/
|
|
16
|
+
export function credentialEnvFor(projectRoot, projectName) {
|
|
17
|
+
const slug = projectName
|
|
18
|
+
.toUpperCase()
|
|
19
|
+
.replace(/[^A-Z0-9]+/g, "_")
|
|
20
|
+
.replace(/^_+|_+$/g, "");
|
|
21
|
+
const common = gitCommonDirOf(projectRoot);
|
|
22
|
+
const where = common ? dirname(common) : projectRoot;
|
|
23
|
+
let real = where;
|
|
24
|
+
try {
|
|
25
|
+
real = realpathSync(where);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
// A path that cannot be resolved still names itself.
|
|
29
|
+
}
|
|
30
|
+
const hash = createHash("sha256").update(real).digest("hex").slice(0, 6).toUpperCase();
|
|
31
|
+
return `INDUSK_SERVER_${slug || "PROJECT"}_${hash}_CREDENTIAL`;
|
|
32
|
+
}
|
|
33
|
+
export async function connect(input, deps) {
|
|
34
|
+
const config = readConfig(input.projectRoot);
|
|
35
|
+
if (!config) {
|
|
36
|
+
throw new Error(`no InDusk config at ${input.projectRoot} — run \`indusk init\` there first`);
|
|
37
|
+
}
|
|
38
|
+
deps.out.line(`Reading the server back: a mark through ${input.otlpUrl}, found through ${input.queryUrl} …`);
|
|
39
|
+
await deps.probe({
|
|
40
|
+
queryUrl: input.queryUrl,
|
|
41
|
+
otlpUrl: input.otlpUrl,
|
|
42
|
+
credential: input.credential,
|
|
43
|
+
});
|
|
44
|
+
const credentialEnv = credentialEnvFor(input.projectRoot, input.projectName);
|
|
45
|
+
deps.secrets.set(credentialEnv, input.credential);
|
|
46
|
+
writeConfig(input.projectRoot, {
|
|
47
|
+
...config,
|
|
48
|
+
promises: {
|
|
49
|
+
...(config.promises ?? { domains: [] }),
|
|
50
|
+
jaeger: { url: input.queryUrl, otlp_url: input.otlpUrl, credential_env: credentialEnv },
|
|
51
|
+
},
|
|
52
|
+
});
|
|
53
|
+
deps.out.line(`Connected: production reads ${input.queryUrl}.`);
|
|
54
|
+
deps.out.line(`The credential is stored as ${credentialEnv} in ${deps.secrets.path}; the project names the variable, never the value.`);
|
|
55
|
+
return { credentialEnv };
|
|
56
|
+
}
|
|
57
|
+
/** The real read-back: the heartbeat probe every promise read already runs. */
|
|
58
|
+
export function probeServer(project) {
|
|
59
|
+
return (target) => probeWatcher({ endpoint: jaegerEndpoint(target.queryUrl, target.credential), intakeUrl: target.otlpUrl }, { project });
|
|
60
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { type Connected, type ConnectInput } from "./connect.js";
|
|
2
|
+
import type { FlyCli } from "./fly.js";
|
|
3
|
+
import { type LineWriter } from "./redact.js";
|
|
4
|
+
import type { SecretsFile } from "./secrets-file.js";
|
|
5
|
+
/**
|
|
6
|
+
* `indusk server deploy`: one command creates a project's recording server
|
|
7
|
+
* in the person's own Fly account and connects the project to it
|
|
8
|
+
* (server-provisioning ADR D1–D6).
|
|
9
|
+
*
|
|
10
|
+
* It reads what exists, plans the missing steps, runs them through the
|
|
11
|
+
* person's `fly`, records which app is this project's server, and ends by
|
|
12
|
+
* connecting — which reads the server back before naming it. Every line it
|
|
13
|
+
* prints, Fly's output included, goes through a writer that knows the
|
|
14
|
+
* password and the webhook.
|
|
15
|
+
*
|
|
16
|
+
* promise: a-fly-deploy-is-one-command
|
|
17
|
+
* promise: the-recording-server-runs-from-a-published-image
|
|
18
|
+
*/
|
|
19
|
+
export declare const IMAGE = "ghcr.io/infinitedusky/indusk-always-on";
|
|
20
|
+
export declare const SERVER_USER = "indusk";
|
|
21
|
+
export interface DeployInput {
|
|
22
|
+
projectRoot: string;
|
|
23
|
+
projectName: string;
|
|
24
|
+
app?: string;
|
|
25
|
+
org?: string;
|
|
26
|
+
region?: string;
|
|
27
|
+
version: string;
|
|
28
|
+
slackWebhook?: string | null;
|
|
29
|
+
rotate?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* A packed tarball to build the image from on this machine, for a version no
|
|
32
|
+
* release has published yet (the live check, a server change under test).
|
|
33
|
+
* Without it, deploy pulls the published image and never builds (A20).
|
|
34
|
+
*/
|
|
35
|
+
buildFrom?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface DeployDeps {
|
|
38
|
+
fly: FlyCli;
|
|
39
|
+
connect(input: ConnectInput, out: LineWriter): Promise<Connected>;
|
|
40
|
+
secrets: SecretsFile;
|
|
41
|
+
/** Where every line goes, before redaction. */
|
|
42
|
+
print(line: string): void;
|
|
43
|
+
/** A new server password. */
|
|
44
|
+
random(): string;
|
|
45
|
+
/** A directory for the generated Fly config. */
|
|
46
|
+
tempDir(): string;
|
|
47
|
+
/**
|
|
48
|
+
* A suffix that makes each `--build-from` tag new: Fly's registry outlives
|
|
49
|
+
* a destroyed app, and a reused tag deployed the previous build (A8).
|
|
50
|
+
*/
|
|
51
|
+
stamp?(): string;
|
|
52
|
+
/** Build the server image from a tarball through the package's template, tagged `tag`, and push it to the app's Fly registry. */
|
|
53
|
+
buildImage?(tarball: string, tag: string): Promise<void>;
|
|
54
|
+
/** The wait between read-back attempts while a new server comes up. */
|
|
55
|
+
sleep?(ms: number): Promise<void>;
|
|
56
|
+
now?(): number;
|
|
57
|
+
}
|
|
58
|
+
export declare class DeployRefused extends Error {
|
|
59
|
+
constructor(message: string);
|
|
60
|
+
}
|
|
61
|
+
export declare function defaultAppName(projectName: string): string;
|
|
62
|
+
export declare function deploy(input: DeployInput, deps: DeployDeps): Promise<void>;
|
|
63
|
+
/** How long a new server may take to become reachable: its addresses and certificate. */
|
|
64
|
+
export declare const REACHABLE_WITHIN_MS: number;
|