@ashlr/hub 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1158 -0
- package/LICENSE +21 -0
- package/README.md +833 -0
- package/bin/ashlr +8 -0
- package/dist/api/core.d.ts +28 -0
- package/dist/api/core.js +42 -0
- package/dist/api/core.js.map +1 -0
- package/dist/api/index.d.ts +9 -0
- package/dist/api/index.js +9 -0
- package/dist/api/index.js.map +1 -0
- package/dist/api/plugin.d.ts +12 -0
- package/dist/api/plugin.js +13 -0
- package/dist/api/plugin.js.map +1 -0
- package/dist/api/types.d.ts +9 -0
- package/dist/api/types.js +9 -0
- package/dist/api/types.js.map +1 -0
- package/dist/cli/args.d.ts +20 -0
- package/dist/cli/args.js +23 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/ask.d.ts +22 -0
- package/dist/cli/ask.js +240 -0
- package/dist/cli/ask.js.map +1 -0
- package/dist/cli/audit.d.ts +26 -0
- package/dist/cli/audit.js +199 -0
- package/dist/cli/audit.js.map +1 -0
- package/dist/cli/backlog.d.ts +26 -0
- package/dist/cli/backlog.js +322 -0
- package/dist/cli/backlog.js.map +1 -0
- package/dist/cli/completions.d.ts +18 -0
- package/dist/cli/completions.js +156 -0
- package/dist/cli/completions.js.map +1 -0
- package/dist/cli/daemon.d.ts +31 -0
- package/dist/cli/daemon.js +334 -0
- package/dist/cli/daemon.js.map +1 -0
- package/dist/cli/demo-sandbox.d.ts +78 -0
- package/dist/cli/demo-sandbox.js +227 -0
- package/dist/cli/demo-sandbox.js.map +1 -0
- package/dist/cli/demo.d.ts +76 -0
- package/dist/cli/demo.js +285 -0
- package/dist/cli/demo.js.map +1 -0
- package/dist/cli/digest.d.ts +46 -0
- package/dist/cli/digest.js +352 -0
- package/dist/cli/digest.js.map +1 -0
- package/dist/cli/doctor-init.d.ts +28 -0
- package/dist/cli/doctor-init.js +335 -0
- package/dist/cli/doctor-init.js.map +1 -0
- package/dist/cli/genome.d.ts +62 -0
- package/dist/cli/genome.js +1061 -0
- package/dist/cli/genome.js.map +1 -0
- package/dist/cli/gh.d.ts +27 -0
- package/dist/cli/gh.js +322 -0
- package/dist/cli/gh.js.map +1 -0
- package/dist/cli/goals.d.ts +55 -0
- package/dist/cli/goals.js +667 -0
- package/dist/cli/goals.js.map +1 -0
- package/dist/cli/health.d.ts +56 -0
- package/dist/cli/health.js +407 -0
- package/dist/cli/health.js.map +1 -0
- package/dist/cli/help.d.ts +51 -0
- package/dist/cli/help.js +436 -0
- package/dist/cli/help.js.map +1 -0
- package/dist/cli/inbox.d.ts +28 -0
- package/dist/cli/inbox.js +589 -0
- package/dist/cli/inbox.js.map +1 -0
- package/dist/cli/index.d.ts +41 -0
- package/dist/cli/index.js +1208 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/knowledge.d.ts +33 -0
- package/dist/cli/knowledge.js +575 -0
- package/dist/cli/knowledge.js.map +1 -0
- package/dist/cli/mcp.d.ts +26 -0
- package/dist/cli/mcp.js +487 -0
- package/dist/cli/mcp.js.map +1 -0
- package/dist/cli/models.d.ts +26 -0
- package/dist/cli/models.js +435 -0
- package/dist/cli/models.js.map +1 -0
- package/dist/cli/new.d.ts +32 -0
- package/dist/cli/new.js +565 -0
- package/dist/cli/new.js.map +1 -0
- package/dist/cli/notify.d.ts +20 -0
- package/dist/cli/notify.js +188 -0
- package/dist/cli/notify.js.map +1 -0
- package/dist/cli/onboard.d.ts +85 -0
- package/dist/cli/onboard.js +305 -0
- package/dist/cli/onboard.js.map +1 -0
- package/dist/cli/open.d.ts +38 -0
- package/dist/cli/open.js +86 -0
- package/dist/cli/open.js.map +1 -0
- package/dist/cli/orient.d.ts +14 -0
- package/dist/cli/orient.js +110 -0
- package/dist/cli/orient.js.map +1 -0
- package/dist/cli/picker.d.ts +21 -0
- package/dist/cli/picker.js +177 -0
- package/dist/cli/picker.js.map +1 -0
- package/dist/cli/plugins.d.ts +21 -0
- package/dist/cli/plugins.js +394 -0
- package/dist/cli/plugins.js.map +1 -0
- package/dist/cli/preflight.d.ts +29 -0
- package/dist/cli/preflight.js +131 -0
- package/dist/cli/preflight.js.map +1 -0
- package/dist/cli/pulse.d.ts +26 -0
- package/dist/cli/pulse.js +482 -0
- package/dist/cli/pulse.js.map +1 -0
- package/dist/cli/reflect.d.ts +42 -0
- package/dist/cli/reflect.js +381 -0
- package/dist/cli/reflect.js.map +1 -0
- package/dist/cli/run.d.ts +29 -0
- package/dist/cli/run.js +687 -0
- package/dist/cli/run.js.map +1 -0
- package/dist/cli/sandbox.d.ts +20 -0
- package/dist/cli/sandbox.js +345 -0
- package/dist/cli/sandbox.js.map +1 -0
- package/dist/cli/seams.d.ts +41 -0
- package/dist/cli/seams.js +167 -0
- package/dist/cli/seams.js.map +1 -0
- package/dist/cli/serve.d.ts +25 -0
- package/dist/cli/serve.js +249 -0
- package/dist/cli/serve.js.map +1 -0
- package/dist/cli/ship.d.ts +33 -0
- package/dist/cli/ship.js +433 -0
- package/dist/cli/ship.js.map +1 -0
- package/dist/cli/spec.d.ts +19 -0
- package/dist/cli/spec.js +478 -0
- package/dist/cli/spec.js.map +1 -0
- package/dist/cli/swarm.d.ts +42 -0
- package/dist/cli/swarm.js +1365 -0
- package/dist/cli/swarm.js.map +1 -0
- package/dist/cli/telemetry.d.ts +26 -0
- package/dist/cli/telemetry.js +364 -0
- package/dist/cli/telemetry.js.map +1 -0
- package/dist/cli/tui.d.ts +17 -0
- package/dist/cli/tui.js +52 -0
- package/dist/cli/tui.js.map +1 -0
- package/dist/cli/ui.d.ts +53 -0
- package/dist/cli/ui.js +66 -0
- package/dist/cli/ui.js.map +1 -0
- package/dist/cli/update.d.ts +38 -0
- package/dist/cli/update.js +682 -0
- package/dist/cli/update.js.map +1 -0
- package/dist/cli/vercel.d.ts +20 -0
- package/dist/cli/vercel.js +193 -0
- package/dist/cli/vercel.js.map +1 -0
- package/dist/cli/verify-safety.d.ts +96 -0
- package/dist/cli/verify-safety.js +509 -0
- package/dist/cli/verify-safety.js.map +1 -0
- package/dist/cli/wire.d.ts +22 -0
- package/dist/cli/wire.js +205 -0
- package/dist/cli/wire.js.map +1 -0
- package/dist/core/classify.d.ts +51 -0
- package/dist/core/classify.js +450 -0
- package/dist/core/classify.js.map +1 -0
- package/dist/core/config.d.ts +63 -0
- package/dist/core/config.js +474 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/daemon/loop.d.ts +74 -0
- package/dist/core/daemon/loop.js +618 -0
- package/dist/core/daemon/loop.js.map +1 -0
- package/dist/core/daemon/state.d.ts +66 -0
- package/dist/core/daemon/state.js +197 -0
- package/dist/core/daemon/state.js.map +1 -0
- package/dist/core/dashboard.d.ts +40 -0
- package/dist/core/dashboard.js +463 -0
- package/dist/core/dashboard.js.map +1 -0
- package/dist/core/digest/build.d.ts +51 -0
- package/dist/core/digest/build.js +230 -0
- package/dist/core/digest/build.js.map +1 -0
- package/dist/core/digest/deliver.d.ts +47 -0
- package/dist/core/digest/deliver.js +230 -0
- package/dist/core/digest/deliver.js.map +1 -0
- package/dist/core/digest/store.d.ts +57 -0
- package/dist/core/digest/store.js +223 -0
- package/dist/core/digest/store.js.map +1 -0
- package/dist/core/doctor-fix.d.ts +21 -0
- package/dist/core/doctor-fix.js +440 -0
- package/dist/core/doctor-fix.js.map +1 -0
- package/dist/core/doctor.d.ts +18 -0
- package/dist/core/doctor.js +806 -0
- package/dist/core/doctor.js.map +1 -0
- package/dist/core/env-bridge.d.ts +64 -0
- package/dist/core/env-bridge.js +103 -0
- package/dist/core/env-bridge.js.map +1 -0
- package/dist/core/genome/capture.d.ts +49 -0
- package/dist/core/genome/capture.js +352 -0
- package/dist/core/genome/capture.js.map +1 -0
- package/dist/core/genome/consolidate.d.ts +38 -0
- package/dist/core/genome/consolidate.js +426 -0
- package/dist/core/genome/consolidate.js.map +1 -0
- package/dist/core/genome/export.d.ts +29 -0
- package/dist/core/genome/export.js +102 -0
- package/dist/core/genome/export.js.map +1 -0
- package/dist/core/genome/playbook.d.ts +33 -0
- package/dist/core/genome/playbook.js +320 -0
- package/dist/core/genome/playbook.js.map +1 -0
- package/dist/core/genome/recall.d.ts +45 -0
- package/dist/core/genome/recall.js +293 -0
- package/dist/core/genome/recall.js.map +1 -0
- package/dist/core/genome/store.d.ts +62 -0
- package/dist/core/genome/store.js +711 -0
- package/dist/core/genome/store.js.map +1 -0
- package/dist/core/git.d.ts +34 -0
- package/dist/core/git.js +115 -0
- package/dist/core/git.js.map +1 -0
- package/dist/core/goals/advance.d.ts +82 -0
- package/dist/core/goals/advance.js +263 -0
- package/dist/core/goals/advance.js.map +1 -0
- package/dist/core/goals/planner.d.ts +58 -0
- package/dist/core/goals/planner.js +233 -0
- package/dist/core/goals/planner.js.map +1 -0
- package/dist/core/goals/store.d.ts +128 -0
- package/dist/core/goals/store.js +442 -0
- package/dist/core/goals/store.js.map +1 -0
- package/dist/core/inbox/apply.d.ts +36 -0
- package/dist/core/inbox/apply.js +407 -0
- package/dist/core/inbox/apply.js.map +1 -0
- package/dist/core/inbox/notify-proposal.d.ts +13 -0
- package/dist/core/inbox/notify-proposal.js +21 -0
- package/dist/core/inbox/notify-proposal.js.map +1 -0
- package/dist/core/inbox/store.d.ts +67 -0
- package/dist/core/inbox/store.js +258 -0
- package/dist/core/inbox/store.js.map +1 -0
- package/dist/core/index-engine.d.ts +62 -0
- package/dist/core/index-engine.js +486 -0
- package/dist/core/index-engine.js.map +1 -0
- package/dist/core/integrations/desktop-notify.d.ts +18 -0
- package/dist/core/integrations/desktop-notify.js +42 -0
- package/dist/core/integrations/desktop-notify.js.map +1 -0
- package/dist/core/integrations/editors.d.ts +50 -0
- package/dist/core/integrations/editors.js +216 -0
- package/dist/core/integrations/editors.js.map +1 -0
- package/dist/core/integrations/github.d.ts +66 -0
- package/dist/core/integrations/github.js +332 -0
- package/dist/core/integrations/github.js.map +1 -0
- package/dist/core/integrations/identity.d.ts +29 -0
- package/dist/core/integrations/identity.js +359 -0
- package/dist/core/integrations/identity.js.map +1 -0
- package/dist/core/integrations/notify.d.ts +23 -0
- package/dist/core/integrations/notify.js +96 -0
- package/dist/core/integrations/notify.js.map +1 -0
- package/dist/core/integrations/vercel.d.ts +37 -0
- package/dist/core/integrations/vercel.js +192 -0
- package/dist/core/integrations/vercel.js.map +1 -0
- package/dist/core/knowledge/ask.d.ts +34 -0
- package/dist/core/knowledge/ask.js +325 -0
- package/dist/core/knowledge/ask.js.map +1 -0
- package/dist/core/knowledge/graph.d.ts +51 -0
- package/dist/core/knowledge/graph.js +564 -0
- package/dist/core/knowledge/graph.js.map +1 -0
- package/dist/core/knowledge/index.d.ts +74 -0
- package/dist/core/knowledge/index.js +586 -0
- package/dist/core/knowledge/index.js.map +1 -0
- package/dist/core/learn/playbooks.d.ts +84 -0
- package/dist/core/learn/playbooks.js +241 -0
- package/dist/core/learn/playbooks.js.map +1 -0
- package/dist/core/learn/reflect.d.ts +87 -0
- package/dist/core/learn/reflect.js +435 -0
- package/dist/core/learn/reflect.js.map +1 -0
- package/dist/core/learn/store.d.ts +51 -0
- package/dist/core/learn/store.js +165 -0
- package/dist/core/learn/store.js.map +1 -0
- package/dist/core/learn/tuning.d.ts +48 -0
- package/dist/core/learn/tuning.js +201 -0
- package/dist/core/learn/tuning.js.map +1 -0
- package/dist/core/lifecycle/scaffold.d.ts +43 -0
- package/dist/core/lifecycle/scaffold.js +260 -0
- package/dist/core/lifecycle/scaffold.js.map +1 -0
- package/dist/core/lifecycle/ship.d.ts +48 -0
- package/dist/core/lifecycle/ship.js +513 -0
- package/dist/core/lifecycle/ship.js.map +1 -0
- package/dist/core/lifecycle/templates.d.ts +20 -0
- package/dist/core/lifecycle/templates.js +605 -0
- package/dist/core/lifecycle/templates.js.map +1 -0
- package/dist/core/mcp-gateway.d.ts +59 -0
- package/dist/core/mcp-gateway.js +385 -0
- package/dist/core/mcp-gateway.js.map +1 -0
- package/dist/core/mcp-native.d.ts +53 -0
- package/dist/core/mcp-native.js +507 -0
- package/dist/core/mcp-native.js.map +1 -0
- package/dist/core/mcp-registry.d.ts +36 -0
- package/dist/core/mcp-registry.js +180 -0
- package/dist/core/mcp-registry.js.map +1 -0
- package/dist/core/observability/budget-alert.d.ts +18 -0
- package/dist/core/observability/budget-alert.js +90 -0
- package/dist/core/observability/budget-alert.js.map +1 -0
- package/dist/core/observability/estimate.d.ts +27 -0
- package/dist/core/observability/estimate.js +188 -0
- package/dist/core/observability/estimate.js.map +1 -0
- package/dist/core/observability/forecast.d.ts +19 -0
- package/dist/core/observability/forecast.js +101 -0
- package/dist/core/observability/forecast.js.map +1 -0
- package/dist/core/observability/governance.d.ts +28 -0
- package/dist/core/observability/governance.js +101 -0
- package/dist/core/observability/governance.js.map +1 -0
- package/dist/core/observability/otlp.d.ts +88 -0
- package/dist/core/observability/otlp.js +217 -0
- package/dist/core/observability/otlp.js.map +1 -0
- package/dist/core/observability/rollup.d.ts +35 -0
- package/dist/core/observability/rollup.js +311 -0
- package/dist/core/observability/rollup.js.map +1 -0
- package/dist/core/observability/telemetry-sink.d.ts +63 -0
- package/dist/core/observability/telemetry-sink.js +350 -0
- package/dist/core/observability/telemetry-sink.js.map +1 -0
- package/dist/core/observability/usage-source.d.ts +60 -0
- package/dist/core/observability/usage-source.js +347 -0
- package/dist/core/observability/usage-source.js.map +1 -0
- package/dist/core/onboard.d.ts +27 -0
- package/dist/core/onboard.js +288 -0
- package/dist/core/onboard.js.map +1 -0
- package/dist/core/orient.d.ts +23 -0
- package/dist/core/orient.js +135 -0
- package/dist/core/orient.js.map +1 -0
- package/dist/core/phantom.d.ts +23 -0
- package/dist/core/phantom.js +279 -0
- package/dist/core/phantom.js.map +1 -0
- package/dist/core/plugins/host-api.d.ts +29 -0
- package/dist/core/plugins/host-api.js +113 -0
- package/dist/core/plugins/host-api.js.map +1 -0
- package/dist/core/plugins/integrity.d.ts +36 -0
- package/dist/core/plugins/integrity.js +73 -0
- package/dist/core/plugins/integrity.js.map +1 -0
- package/dist/core/plugins/manifest.d.ts +31 -0
- package/dist/core/plugins/manifest.js +316 -0
- package/dist/core/plugins/manifest.js.map +1 -0
- package/dist/core/plugins/registry.d.ts +87 -0
- package/dist/core/plugins/registry.js +415 -0
- package/dist/core/plugins/registry.js.map +1 -0
- package/dist/core/plugins/types.d.ts +182 -0
- package/dist/core/plugins/types.js +40 -0
- package/dist/core/plugins/types.js.map +1 -0
- package/dist/core/plugins/wrappers.d.ts +40 -0
- package/dist/core/plugins/wrappers.js +229 -0
- package/dist/core/plugins/wrappers.js.map +1 -0
- package/dist/core/portfolio/backlog.d.ts +40 -0
- package/dist/core/portfolio/backlog.js +177 -0
- package/dist/core/portfolio/backlog.js.map +1 -0
- package/dist/core/portfolio/scanners.d.ts +21 -0
- package/dist/core/portfolio/scanners.js +600 -0
- package/dist/core/portfolio/scanners.js.map +1 -0
- package/dist/core/providers.d.ts +34 -0
- package/dist/core/providers.js +250 -0
- package/dist/core/providers.js.map +1 -0
- package/dist/core/quality/conventions.d.ts +35 -0
- package/dist/core/quality/conventions.js +267 -0
- package/dist/core/quality/conventions.js.map +1 -0
- package/dist/core/quality/fixes.d.ts +56 -0
- package/dist/core/quality/fixes.js +209 -0
- package/dist/core/quality/fixes.js.map +1 -0
- package/dist/core/quality/health.d.ts +69 -0
- package/dist/core/quality/health.js +350 -0
- package/dist/core/quality/health.js.map +1 -0
- package/dist/core/quality/store.d.ts +56 -0
- package/dist/core/quality/store.js +195 -0
- package/dist/core/quality/store.js.map +1 -0
- package/dist/core/readiness.d.ts +112 -0
- package/dist/core/readiness.js +431 -0
- package/dist/core/readiness.js.map +1 -0
- package/dist/core/run/agent-loop.d.ts +40 -0
- package/dist/core/run/agent-loop.js +291 -0
- package/dist/core/run/agent-loop.js.map +1 -0
- package/dist/core/run/budget.d.ts +47 -0
- package/dist/core/run/budget.js +113 -0
- package/dist/core/run/budget.js.map +1 -0
- package/dist/core/run/engines.d.ts +75 -0
- package/dist/core/run/engines.js +199 -0
- package/dist/core/run/engines.js.map +1 -0
- package/dist/core/run/model-manager.d.ts +64 -0
- package/dist/core/run/model-manager.js +339 -0
- package/dist/core/run/model-manager.js.map +1 -0
- package/dist/core/run/orchestrator.d.ts +100 -0
- package/dist/core/run/orchestrator.js +1515 -0
- package/dist/core/run/orchestrator.js.map +1 -0
- package/dist/core/run/provider-client.d.ts +46 -0
- package/dist/core/run/provider-client.js +796 -0
- package/dist/core/run/provider-client.js.map +1 -0
- package/dist/core/run/retry.d.ts +19 -0
- package/dist/core/run/retry.js +68 -0
- package/dist/core/run/retry.js.map +1 -0
- package/dist/core/run/router.d.ts +50 -0
- package/dist/core/run/router.js +257 -0
- package/dist/core/run/router.js.map +1 -0
- package/dist/core/run/self-heal.d.ts +52 -0
- package/dist/core/run/self-heal.js +181 -0
- package/dist/core/run/self-heal.js.map +1 -0
- package/dist/core/run/streaming.d.ts +31 -0
- package/dist/core/run/streaming.js +122 -0
- package/dist/core/run/streaming.js.map +1 -0
- package/dist/core/run/verify.d.ts +30 -0
- package/dist/core/run/verify.js +204 -0
- package/dist/core/run/verify.js.map +1 -0
- package/dist/core/sandbox/audit.d.ts +31 -0
- package/dist/core/sandbox/audit.js +169 -0
- package/dist/core/sandbox/audit.js.map +1 -0
- package/dist/core/sandbox/policy.d.ts +61 -0
- package/dist/core/sandbox/policy.js +211 -0
- package/dist/core/sandbox/policy.js.map +1 -0
- package/dist/core/sandbox/worktree.d.ts +175 -0
- package/dist/core/sandbox/worktree.js +673 -0
- package/dist/core/sandbox/worktree.js.map +1 -0
- package/dist/core/seams/backlog.d.ts +47 -0
- package/dist/core/seams/backlog.js +47 -0
- package/dist/core/seams/backlog.js.map +1 -0
- package/dist/core/seams/daemon-coordinator.d.ts +72 -0
- package/dist/core/seams/daemon-coordinator.js +76 -0
- package/dist/core/seams/daemon-coordinator.js.map +1 -0
- package/dist/core/seams/genome.d.ts +45 -0
- package/dist/core/seams/genome.js +53 -0
- package/dist/core/seams/genome.js.map +1 -0
- package/dist/core/seams/identity.d.ts +40 -0
- package/dist/core/seams/identity.js +44 -0
- package/dist/core/seams/identity.js.map +1 -0
- package/dist/core/seams/inbox.d.ts +60 -0
- package/dist/core/seams/inbox.js +66 -0
- package/dist/core/seams/inbox.js.map +1 -0
- package/dist/core/seams/index.d.ts +20 -0
- package/dist/core/seams/index.js +21 -0
- package/dist/core/seams/index.js.map +1 -0
- package/dist/core/seams/portfolio.d.ts +50 -0
- package/dist/core/seams/portfolio.js +61 -0
- package/dist/core/seams/portfolio.js.map +1 -0
- package/dist/core/seams/registry.d.ts +42 -0
- package/dist/core/seams/registry.js +128 -0
- package/dist/core/seams/registry.js.map +1 -0
- package/dist/core/seams/run-swarm.d.ts +66 -0
- package/dist/core/seams/run-swarm.js +74 -0
- package/dist/core/seams/run-swarm.js.map +1 -0
- package/dist/core/seams/types.d.ts +123 -0
- package/dist/core/seams/types.js +35 -0
- package/dist/core/seams/types.js.map +1 -0
- package/dist/core/spec/spec-store.d.ts +62 -0
- package/dist/core/spec/spec-store.js +359 -0
- package/dist/core/spec/spec-store.js.map +1 -0
- package/dist/core/swarm/gate.d.ts +45 -0
- package/dist/core/swarm/gate.js +114 -0
- package/dist/core/swarm/gate.js.map +1 -0
- package/dist/core/swarm/planner.d.ts +32 -0
- package/dist/core/swarm/planner.js +293 -0
- package/dist/core/swarm/planner.js.map +1 -0
- package/dist/core/swarm/rollback.d.ts +56 -0
- package/dist/core/swarm/rollback.js +266 -0
- package/dist/core/swarm/rollback.js.map +1 -0
- package/dist/core/swarm/runner.d.ts +62 -0
- package/dist/core/swarm/runner.js +1263 -0
- package/dist/core/swarm/runner.js.map +1 -0
- package/dist/core/swarm/sign.d.ts +71 -0
- package/dist/core/swarm/sign.js +362 -0
- package/dist/core/swarm/sign.js.map +1 -0
- package/dist/core/swarm/store.d.ts +52 -0
- package/dist/core/swarm/store.js +195 -0
- package/dist/core/swarm/store.js.map +1 -0
- package/dist/core/tidy.d.ts +32 -0
- package/dist/core/tidy.js +354 -0
- package/dist/core/tidy.js.map +1 -0
- package/dist/core/tools-registry.d.ts +16 -0
- package/dist/core/tools-registry.js +308 -0
- package/dist/core/tools-registry.js.map +1 -0
- package/dist/core/types.d.ts +2545 -0
- package/dist/core/types.js +9 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/web/api.d.ts +53 -0
- package/dist/core/web/api.js +698 -0
- package/dist/core/web/api.js.map +1 -0
- package/dist/core/web/public/app.js +1906 -0
- package/dist/core/web/public/index.html +721 -0
- package/dist/core/web/public/styles.css +2007 -0
- package/dist/core/web/server.d.ts +18 -0
- package/dist/core/web/server.js +122 -0
- package/dist/core/web/server.js.map +1 -0
- package/dist/core/web/static.d.ts +18 -0
- package/dist/core/web/static.js +122 -0
- package/dist/core/web/static.js.map +1 -0
- package/dist/tui/app.d.ts +33 -0
- package/dist/tui/app.js +350 -0
- package/dist/tui/app.js.map +1 -0
- package/dist/tui/render.d.ts +20 -0
- package/dist/tui/render.js +558 -0
- package/dist/tui/render.js.map +1 -0
- package/package.json +80 -0
- package/schema/config.schema.json +223 -0
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core/digest/build.ts — M29 deterministic daily digest builder.
|
|
3
|
+
*
|
|
4
|
+
* buildDigest(cfg, opts) computes a deterministic DAILY DIGEST from the M13/M24
|
|
5
|
+
* DashboardSnapshot (incl. its M29 `portfolio` section, populated by
|
|
6
|
+
* core/dashboard.ts) plus day-over-day deltas vs the previous persisted digest
|
|
7
|
+
* (loadPreviousDigest). An OPTIONAL LLM narrative is OFF unless opts.narrative
|
|
8
|
+
* is explicitly set; when on it routes through getActiveClient — local-only
|
|
9
|
+
* unless allowCloud + a key.
|
|
10
|
+
*
|
|
11
|
+
* HARD SAFETY INVARIANTS (M29) enforced here:
|
|
12
|
+
* - READ-ONLY AGGREGATION: reads ONLY buildSnapshot(cfg) (which itself only
|
|
13
|
+
* reads local state) + loadPreviousDigest() (local disk). Writes NOTHING —
|
|
14
|
+
* persistence is deliver.ts's job. Never mutates a repo, never writes config.
|
|
15
|
+
* - NO OUTWARD ACTION BY DEFAULT: building a digest makes ZERO non-localhost
|
|
16
|
+
* connections on the default path. Narrative is the only egress and only when
|
|
17
|
+
* opts.allowCloud + a cloud key; local providers are localhost-only.
|
|
18
|
+
* - ENROLLMENT-SCOPED: the portfolio's health/goals sub-sections are sourced
|
|
19
|
+
* from buildSnapshot, which is enrollment-scoped (empty enrollment => empty).
|
|
20
|
+
* buildDigest introduces NO new path scan of its own.
|
|
21
|
+
* - LOCAL-FIRST: all numeric aggregation + the headline are deterministic with
|
|
22
|
+
* NO model. Narrative is EXPLICITLY OPT-IN (opts.narrative); the default path
|
|
23
|
+
* constructs NO model at all (not even a reachable local one). When opted in,
|
|
24
|
+
* it routes through getActiveClient(cfg, { allowCloud }) — local-only unless
|
|
25
|
+
* allowCloud + a cloud key (mirror M26 reflect's `narrative` gate).
|
|
26
|
+
* - BOUNDED + NEVER-THROWS: every step is wrapped; a missing snapshot/portfolio
|
|
27
|
+
* degrades to a zeroed digest. List sizes are inherited from the snapshot's
|
|
28
|
+
* already-capped portfolio lists.
|
|
29
|
+
*/
|
|
30
|
+
import { buildSnapshot } from '../dashboard.js';
|
|
31
|
+
import { getActiveClient } from '../run/provider-client.js';
|
|
32
|
+
import { loadPreviousDigest } from './store.js';
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// Defaults
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
/** Default cost/forecast window when none is supplied. */
|
|
37
|
+
const DEFAULT_WINDOW = '7d';
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// Empty / zeroed defaults (never-throws degradation targets)
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
/** A zeroed portfolio section used when the snapshot lacks one. */
|
|
42
|
+
function emptyPortfolio(window) {
|
|
43
|
+
// TODO(M29): single source of the empty PortfolioSummary; reused by both
|
|
44
|
+
// buildDigest (degradation) and core/dashboard.ts (initial value).
|
|
45
|
+
return {
|
|
46
|
+
health: { reposScored: 0, averageScore: 0, averageGrade: 'F', worstRepos: [] },
|
|
47
|
+
goalsInFlight: [],
|
|
48
|
+
backlogTop: [],
|
|
49
|
+
cost: { window, spentUsd: 0, localSavingsUsd: 0, projectedMonthlyUsd: 0 },
|
|
50
|
+
effectiveness: null,
|
|
51
|
+
today: emptyTodayDelta(),
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
/** A null-filled "today" delta block (no prior digest to compare against). */
|
|
55
|
+
function emptyTodayDelta() {
|
|
56
|
+
return {
|
|
57
|
+
previousAt: null,
|
|
58
|
+
pendingProposalsDelta: null,
|
|
59
|
+
dirtyReposDelta: null,
|
|
60
|
+
spendUsdDelta: null,
|
|
61
|
+
healthScoreDelta: null,
|
|
62
|
+
goalsInFlightDelta: null,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
// buildDigest
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
/**
|
|
69
|
+
* Build a deterministic DigestReport for "today".
|
|
70
|
+
*
|
|
71
|
+
* Contract:
|
|
72
|
+
* - Async; NEVER throws — any failed step degrades to its zeroed default.
|
|
73
|
+
* - Default path (no allowCloud) makes ZERO non-localhost connections.
|
|
74
|
+
* - Deterministic given the same snapshot + prior digest.
|
|
75
|
+
*
|
|
76
|
+
* Steps (TODO bodies):
|
|
77
|
+
* 1. snapshot = await buildSnapshot(cfg) (read-only; never throws).
|
|
78
|
+
* 2. portfolio = snapshot.portfolio ?? emptyPortfolio(window).
|
|
79
|
+
* 3. previous = loadPreviousDigest(generatedAt) — the prior day's digest.
|
|
80
|
+
* 4. Compute portfolio.today deltas vs `previous` (pending/dirty/spend/health/
|
|
81
|
+
* goals); leave each null when there is no prior.
|
|
82
|
+
* 5. Compose the deterministic `headline` (templated; no LLM).
|
|
83
|
+
* 6. OPTIONAL narrative — ONLY when opts.narrative === true (else NO model is
|
|
84
|
+
* constructed). Then getActiveClient(cfg, { allowCloud }) opens a provider
|
|
85
|
+
* (local-only unless allowCloud + key); set narrative + narrativeLocal.
|
|
86
|
+
* On any model error keep the deterministic report (no narrative).
|
|
87
|
+
*/
|
|
88
|
+
export async function buildDigest(cfg, opts) {
|
|
89
|
+
const window = opts?.window ?? DEFAULT_WINDOW;
|
|
90
|
+
const generatedAt = new Date().toISOString();
|
|
91
|
+
const date = generatedAt.slice(0, 10);
|
|
92
|
+
// Step 1 — read-only snapshot (never throws; degrade to a zeroed digest).
|
|
93
|
+
let portfolio = emptyPortfolio(window);
|
|
94
|
+
let repos = { total: 0, dirty: 0, stale: 0 };
|
|
95
|
+
let pendingProposals = 0;
|
|
96
|
+
let daemon = null;
|
|
97
|
+
try {
|
|
98
|
+
const snapshot = await buildSnapshot(cfg);
|
|
99
|
+
portfolio = snapshot.portfolio ?? emptyPortfolio(window);
|
|
100
|
+
repos = snapshot.repos;
|
|
101
|
+
pendingProposals = snapshot.inbox.pending;
|
|
102
|
+
daemon = snapshot.daemon
|
|
103
|
+
? { running: snapshot.daemon.running, todaySpentUsd: snapshot.daemon.todaySpentUsd }
|
|
104
|
+
: null;
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
// Degrade to zeroed digest.
|
|
108
|
+
}
|
|
109
|
+
// Steps 3-4 — day-over-day deltas vs the previous digest. The prior is loaded
|
|
110
|
+
// strictly-before `generatedAt` so a freshly-saved current digest is never
|
|
111
|
+
// compared against itself. Each delta is null when there is no prior to diff.
|
|
112
|
+
try {
|
|
113
|
+
const previous = loadPreviousDigest(generatedAt);
|
|
114
|
+
portfolio.today = computeTodayDelta({ portfolio, repos, pendingProposals }, previous);
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
portfolio.today = emptyTodayDelta();
|
|
118
|
+
}
|
|
119
|
+
// Step 5 — deterministic headline (templated; NO LLM).
|
|
120
|
+
const headline = composeHeadline({ portfolio, repos, pendingProposals, window });
|
|
121
|
+
// Step 6 — OPTIONAL narrative. EXPLICITLY OPT-IN (mirrors M26 reflect): no
|
|
122
|
+
// model — local OR cloud — is ever constructed unless opts.narrative === true.
|
|
123
|
+
// The DEFAULT `ashlr digest` path therefore makes ZERO model calls and ZERO
|
|
124
|
+
// non-localhost connections, even when a local provider (Ollama/LM Studio)
|
|
125
|
+
// happens to be running. When narrative IS requested, getActiveClient stays
|
|
126
|
+
// local-first: it returns a localhost provider only, unless opts.allowCloud +
|
|
127
|
+
// a cloud key. Any model error is swallowed (deterministic report preserved).
|
|
128
|
+
let narrative;
|
|
129
|
+
let narrativeLocal;
|
|
130
|
+
if (opts?.narrative === true) {
|
|
131
|
+
try {
|
|
132
|
+
const client = await getActiveClient(cfg, { allowCloud: opts?.allowCloud ?? false });
|
|
133
|
+
// ALLOWLIST (not denylist): only the known local providers count as local.
|
|
134
|
+
const isLocal = client.id === 'ollama' || client.id === 'lmstudio';
|
|
135
|
+
const res = await client.chat([
|
|
136
|
+
{
|
|
137
|
+
role: 'system',
|
|
138
|
+
content: 'You write a brief, factual daily engineering portfolio digest. ' +
|
|
139
|
+
'Summarize the provided metadata in 2-3 sentences. Never invent facts ' +
|
|
140
|
+
'or numbers beyond what is given.',
|
|
141
|
+
},
|
|
142
|
+
{ role: 'user', content: buildNarrativePrompt({ portfolio, repos, pendingProposals, headline }) },
|
|
143
|
+
]);
|
|
144
|
+
const text = (res.content ?? '').trim();
|
|
145
|
+
if (text) {
|
|
146
|
+
narrative = text;
|
|
147
|
+
narrativeLocal = isLocal;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
// No reachable provider / cloud refused without key / model error — keep
|
|
152
|
+
// the deterministic report with no narrative.
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
const report = {
|
|
156
|
+
generatedAt,
|
|
157
|
+
date,
|
|
158
|
+
window,
|
|
159
|
+
portfolio,
|
|
160
|
+
repos,
|
|
161
|
+
pendingProposals,
|
|
162
|
+
daemon,
|
|
163
|
+
headline,
|
|
164
|
+
};
|
|
165
|
+
if (narrative !== undefined) {
|
|
166
|
+
report.narrative = narrative;
|
|
167
|
+
report.narrativeLocal = narrativeLocal;
|
|
168
|
+
}
|
|
169
|
+
return report;
|
|
170
|
+
}
|
|
171
|
+
// ---------------------------------------------------------------------------
|
|
172
|
+
// Deterministic helpers (pure — no I/O, no model)
|
|
173
|
+
// ---------------------------------------------------------------------------
|
|
174
|
+
/** Round to a fixed number of decimals to keep deltas deterministic + tidy. */
|
|
175
|
+
function round(n, dp = 2) {
|
|
176
|
+
const f = 10 ** dp;
|
|
177
|
+
return Math.round(n * f) / f;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Compute the day-over-day `today` delta block for the current digest vs the
|
|
181
|
+
* previous persisted digest. Each field is null when there is no prior to diff.
|
|
182
|
+
* Pure function — deterministic given the same inputs.
|
|
183
|
+
*/
|
|
184
|
+
function computeTodayDelta(current, previous) {
|
|
185
|
+
if (previous === null)
|
|
186
|
+
return emptyTodayDelta();
|
|
187
|
+
return {
|
|
188
|
+
previousAt: previous.generatedAt,
|
|
189
|
+
pendingProposalsDelta: current.pendingProposals - previous.pendingProposals,
|
|
190
|
+
dirtyReposDelta: current.repos.dirty - previous.repos.dirty,
|
|
191
|
+
spendUsdDelta: round(current.portfolio.cost.spentUsd - previous.portfolio.cost.spentUsd),
|
|
192
|
+
healthScoreDelta: round(current.portfolio.health.averageScore - previous.portfolio.health.averageScore),
|
|
193
|
+
goalsInFlightDelta: current.portfolio.goalsInFlight.length - previous.portfolio.goalsInFlight.length,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Compose the deterministic, always-present headline. Templated — NO LLM.
|
|
198
|
+
* Summarizes the org view: repos, health, in-flight goals, pending proposals,
|
|
199
|
+
* and spend over the window.
|
|
200
|
+
*/
|
|
201
|
+
function composeHeadline(input) {
|
|
202
|
+
const { portfolio, repos, pendingProposals, window } = input;
|
|
203
|
+
const parts = [];
|
|
204
|
+
parts.push(`${repos.total} repo${repos.total === 1 ? '' : 's'}`);
|
|
205
|
+
parts.push(`${repos.dirty} dirty`);
|
|
206
|
+
if (portfolio.health.reposScored > 0) {
|
|
207
|
+
parts.push(`health ${portfolio.health.averageGrade} (${round(portfolio.health.averageScore, 0)})`);
|
|
208
|
+
}
|
|
209
|
+
parts.push(`${portfolio.goalsInFlight.length} goal${portfolio.goalsInFlight.length === 1 ? '' : 's'} in flight`);
|
|
210
|
+
parts.push(`${pendingProposals} pending`);
|
|
211
|
+
parts.push(`$${round(portfolio.cost.spentUsd)} spent (${window})`);
|
|
212
|
+
return parts.join(' · ');
|
|
213
|
+
}
|
|
214
|
+
/** Build the (bounded, metadata-only) prompt for the optional narrative. */
|
|
215
|
+
function buildNarrativePrompt(input) {
|
|
216
|
+
const { portfolio, repos, pendingProposals, headline } = input;
|
|
217
|
+
const goals = portfolio.goalsInFlight
|
|
218
|
+
.slice(0, 5)
|
|
219
|
+
.map((g) => `- ${g.objective} (${Math.round(g.fractionDone * 100)}%)`)
|
|
220
|
+
.join('\n');
|
|
221
|
+
return [
|
|
222
|
+
`Headline: ${headline}`,
|
|
223
|
+
`Repos: ${repos.total} total, ${repos.dirty} dirty, ${repos.stale} stale.`,
|
|
224
|
+
`Health: ${portfolio.health.reposScored} scored, avg ${round(portfolio.health.averageScore, 0)} (${portfolio.health.averageGrade}).`,
|
|
225
|
+
`Pending proposals: ${pendingProposals}.`,
|
|
226
|
+
`Spend (${portfolio.cost.window}): $${round(portfolio.cost.spentUsd)}; projected monthly $${round(portfolio.cost.projectedMonthlyUsd)}.`,
|
|
227
|
+
goals ? `Goals in flight:\n${goals}` : 'No goals in flight.',
|
|
228
|
+
].join('\n');
|
|
229
|
+
}
|
|
230
|
+
//# sourceMappingURL=build.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../../src/core/digest/build.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core/digest/deliver.ts — M29 digest rendering + delivery.
|
|
3
|
+
*
|
|
4
|
+
* renderDigestText(report) produces the human-readable (markdown) body.
|
|
5
|
+
* deliverDigest(report, cfg, opts) ALWAYS writes the local artifact (via the
|
|
6
|
+
* store) and calls notify() ONLY when opts.notify === true (opt-in).
|
|
7
|
+
*
|
|
8
|
+
* HARD SAFETY INVARIANTS (M29) enforced here:
|
|
9
|
+
* - NO OUTWARD ACTION BY DEFAULT: deliverDigest writes a LOCAL file by default.
|
|
10
|
+
* The ONLY outward path is notify(), reached ONLY when opts.notify === true.
|
|
11
|
+
* notify() is itself a strict no-op unless a Slack/Discord webhook is
|
|
12
|
+
* configured — so the default path makes ZERO outward network calls. The
|
|
13
|
+
* verifier proves it by asserting notify is NEVER invoked unless notify:true.
|
|
14
|
+
* - READ-ONLY AGGREGATION: the only write is the digest artifact under
|
|
15
|
+
* ~/.ashlr/digests/ (delegated to saveDigest). Never mutates a repo, never
|
|
16
|
+
* writes config, never applies/approves a proposal, never pushes/PRs/deploys.
|
|
17
|
+
* - BOUNDED + NEVER-THROWS: rendering + delivery are wrapped; a failed write or
|
|
18
|
+
* a failed notify degrades to a result flagging what happened, never throws.
|
|
19
|
+
*/
|
|
20
|
+
import type { AshlrConfig, DigestDeliveryResult, DigestReport } from '../types.js';
|
|
21
|
+
/**
|
|
22
|
+
* Render a DigestReport as a deterministic markdown body. Pure function — no
|
|
23
|
+
* I/O, no model, no secrets. Used both for the persisted `<stem>.md` artifact
|
|
24
|
+
* and as the notify() payload when delivery is opted in.
|
|
25
|
+
*
|
|
26
|
+
* Sections: headline; repos roll-up; pending proposals; health summary (avg +
|
|
27
|
+
* worst repos); in-flight goals; top backlog; cost + forecast; effectiveness
|
|
28
|
+
* headline; the "today" day-over-day delta block; optional narrative.
|
|
29
|
+
*
|
|
30
|
+
* METADATA ONLY — every field rendered is a count/score/title/path label that
|
|
31
|
+
* already lives in the (secret-free) DigestReport. Lists are bounded upstream.
|
|
32
|
+
*/
|
|
33
|
+
export declare function renderDigestText(report: DigestReport): string;
|
|
34
|
+
/**
|
|
35
|
+
* Deliver a digest. ALWAYS writes the local JSON + markdown artifact (via
|
|
36
|
+
* saveDigest). Calls notify() ONLY when opts.notify === true (opt-in) — that is
|
|
37
|
+
* the SINGLE outward path; everything else stops at local disk.
|
|
38
|
+
*
|
|
39
|
+
* Contract:
|
|
40
|
+
* - NEVER throws — failures degrade into the returned DigestDeliveryResult.
|
|
41
|
+
* - Default (no opts.notify) => `notified:false`, ZERO outward network calls.
|
|
42
|
+
* - notify() is itself a no-op unless a webhook is configured, so even with
|
|
43
|
+
* opts.notify:true `notified` is false when nothing is configured.
|
|
44
|
+
*/
|
|
45
|
+
export declare function deliverDigest(report: DigestReport, cfg: AshlrConfig, opts?: {
|
|
46
|
+
notify?: boolean;
|
|
47
|
+
}): Promise<DigestDeliveryResult>;
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core/digest/deliver.ts — M29 digest rendering + delivery.
|
|
3
|
+
*
|
|
4
|
+
* renderDigestText(report) produces the human-readable (markdown) body.
|
|
5
|
+
* deliverDigest(report, cfg, opts) ALWAYS writes the local artifact (via the
|
|
6
|
+
* store) and calls notify() ONLY when opts.notify === true (opt-in).
|
|
7
|
+
*
|
|
8
|
+
* HARD SAFETY INVARIANTS (M29) enforced here:
|
|
9
|
+
* - NO OUTWARD ACTION BY DEFAULT: deliverDigest writes a LOCAL file by default.
|
|
10
|
+
* The ONLY outward path is notify(), reached ONLY when opts.notify === true.
|
|
11
|
+
* notify() is itself a strict no-op unless a Slack/Discord webhook is
|
|
12
|
+
* configured — so the default path makes ZERO outward network calls. The
|
|
13
|
+
* verifier proves it by asserting notify is NEVER invoked unless notify:true.
|
|
14
|
+
* - READ-ONLY AGGREGATION: the only write is the digest artifact under
|
|
15
|
+
* ~/.ashlr/digests/ (delegated to saveDigest). Never mutates a repo, never
|
|
16
|
+
* writes config, never applies/approves a proposal, never pushes/PRs/deploys.
|
|
17
|
+
* - BOUNDED + NEVER-THROWS: rendering + delivery are wrapped; a failed write or
|
|
18
|
+
* a failed notify degrades to a result flagging what happened, never throws.
|
|
19
|
+
*/
|
|
20
|
+
import { notify } from '../integrations/notify.js';
|
|
21
|
+
import { saveDigest } from './store.js';
|
|
22
|
+
// ---------------------------------------------------------------------------
|
|
23
|
+
// Render helpers (pure, deterministic — no I/O, no model, no secrets)
|
|
24
|
+
// ---------------------------------------------------------------------------
|
|
25
|
+
/** Format a USD figure with two decimals, e.g. `$12.34`. */
|
|
26
|
+
function usd(n) {
|
|
27
|
+
const v = Number.isFinite(n) ? n : 0;
|
|
28
|
+
return `$${v.toFixed(2)}`;
|
|
29
|
+
}
|
|
30
|
+
/** Format a 0..1 fraction as a whole-percent string, e.g. `73%`. */
|
|
31
|
+
function pct(frac) {
|
|
32
|
+
const v = Number.isFinite(frac) ? frac : 0;
|
|
33
|
+
return `${Math.round(v * 100)}%`;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Render one signed "today" delta line, or null to omit it when the prior is
|
|
37
|
+
* missing (null delta) or the movement is zero (suppress noise). `digits`
|
|
38
|
+
* controls fractional precision; `money` renders the magnitude as USD.
|
|
39
|
+
*/
|
|
40
|
+
function deltaLine(label, value, opts) {
|
|
41
|
+
if (value === null || !Number.isFinite(value) || value === 0)
|
|
42
|
+
return null;
|
|
43
|
+
const digits = opts?.digits ?? 0;
|
|
44
|
+
const sign = value > 0 ? '+' : '-';
|
|
45
|
+
const mag = Math.abs(value);
|
|
46
|
+
const body = opts?.money ? usd(mag) : mag.toFixed(digits);
|
|
47
|
+
return `- ${label}: ${sign}${body}`;
|
|
48
|
+
}
|
|
49
|
+
/** Render the "today" delta block, or a single line when there is no prior. */
|
|
50
|
+
function renderToday(today) {
|
|
51
|
+
if (!today.previousAt) {
|
|
52
|
+
return ['## Today', '', '- No prior digest to compare against yet.'];
|
|
53
|
+
}
|
|
54
|
+
const lines = [
|
|
55
|
+
deltaLine('Pending proposals', today.pendingProposalsDelta),
|
|
56
|
+
deltaLine('Dirty repos', today.dirtyReposDelta),
|
|
57
|
+
deltaLine('Window spend', today.spendUsdDelta, { money: true }),
|
|
58
|
+
deltaLine('Avg health score', today.healthScoreDelta, { digits: 1 }),
|
|
59
|
+
deltaLine('In-flight goals', today.goalsInFlightDelta),
|
|
60
|
+
];
|
|
61
|
+
const movements = lines.filter((l) => l !== null);
|
|
62
|
+
const body = movements.length > 0 ? movements : ['- No material change since the prior digest.'];
|
|
63
|
+
return ['## Today', `_since ${today.previousAt}_`, '', ...body];
|
|
64
|
+
}
|
|
65
|
+
// ---------------------------------------------------------------------------
|
|
66
|
+
// Render
|
|
67
|
+
// ---------------------------------------------------------------------------
|
|
68
|
+
/**
|
|
69
|
+
* Render a DigestReport as a deterministic markdown body. Pure function — no
|
|
70
|
+
* I/O, no model, no secrets. Used both for the persisted `<stem>.md` artifact
|
|
71
|
+
* and as the notify() payload when delivery is opted in.
|
|
72
|
+
*
|
|
73
|
+
* Sections: headline; repos roll-up; pending proposals; health summary (avg +
|
|
74
|
+
* worst repos); in-flight goals; top backlog; cost + forecast; effectiveness
|
|
75
|
+
* headline; the "today" day-over-day delta block; optional narrative.
|
|
76
|
+
*
|
|
77
|
+
* METADATA ONLY — every field rendered is a count/score/title/path label that
|
|
78
|
+
* already lives in the (secret-free) DigestReport. Lists are bounded upstream.
|
|
79
|
+
*/
|
|
80
|
+
export function renderDigestText(report) {
|
|
81
|
+
const p = report.portfolio;
|
|
82
|
+
const out = [];
|
|
83
|
+
// Header + headline.
|
|
84
|
+
out.push(`# Ashlr Digest — ${report.date}`);
|
|
85
|
+
out.push('');
|
|
86
|
+
out.push(report.headline || 'Daily portfolio digest.');
|
|
87
|
+
out.push('');
|
|
88
|
+
// Repos roll-up + pending proposals + operator.
|
|
89
|
+
out.push('## Overview');
|
|
90
|
+
out.push('');
|
|
91
|
+
out.push(`- Repos: ${report.repos.total} total, ${report.repos.dirty} dirty, ${report.repos.stale} stale`);
|
|
92
|
+
out.push(`- Pending proposals: ${report.pendingProposals}`);
|
|
93
|
+
if (report.daemon) {
|
|
94
|
+
out.push(`- Daemon: ${report.daemon.running ? 'running' : 'stopped'} (today spend ${usd(report.daemon.todaySpentUsd)})`);
|
|
95
|
+
}
|
|
96
|
+
out.push('');
|
|
97
|
+
// Health summary.
|
|
98
|
+
out.push('## Health');
|
|
99
|
+
out.push('');
|
|
100
|
+
if (p.health.reposScored > 0) {
|
|
101
|
+
out.push(`- ${p.health.reposScored} repos scored — avg ${Math.round(p.health.averageScore)} (${p.health.averageGrade})`);
|
|
102
|
+
if (p.health.worstRepos.length > 0) {
|
|
103
|
+
out.push('- Lowest scoring:');
|
|
104
|
+
for (const r of p.health.worstRepos) {
|
|
105
|
+
out.push(` - ${r.repo}: ${Math.round(r.score)} (${r.grade})`);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
out.push('- No enrolled repos scored.');
|
|
111
|
+
}
|
|
112
|
+
out.push('');
|
|
113
|
+
// In-flight goals.
|
|
114
|
+
out.push('## Goals in flight');
|
|
115
|
+
out.push('');
|
|
116
|
+
if (p.goalsInFlight.length > 0) {
|
|
117
|
+
for (const g of p.goalsInFlight) {
|
|
118
|
+
const next = g.nextActionable ? ` — next: ${g.nextActionable}` : '';
|
|
119
|
+
out.push(`- ${g.objective} [${g.status}] ${pct(g.fractionDone)} (${g.proposed}/${g.totalMilestones} proposed)${next}`);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
else {
|
|
123
|
+
out.push('- No active goals.');
|
|
124
|
+
}
|
|
125
|
+
out.push('');
|
|
126
|
+
// Top backlog.
|
|
127
|
+
out.push('## Backlog (top)');
|
|
128
|
+
out.push('');
|
|
129
|
+
if (p.backlogTop.length > 0) {
|
|
130
|
+
for (const b of p.backlogTop) {
|
|
131
|
+
const repo = b.repo ? ` (${b.repo})` : '';
|
|
132
|
+
out.push(`- [${b.score}] ${b.title}${repo}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
out.push('- Backlog empty.');
|
|
137
|
+
}
|
|
138
|
+
out.push('');
|
|
139
|
+
// Cost + forecast.
|
|
140
|
+
out.push('## Cost');
|
|
141
|
+
out.push('');
|
|
142
|
+
out.push(`- Spend (${p.cost.window}): ${usd(p.cost.spentUsd)}`);
|
|
143
|
+
out.push(`- Local savings: ${usd(p.cost.localSavingsUsd)}`);
|
|
144
|
+
out.push(`- Projected monthly: ${usd(p.cost.projectedMonthlyUsd)}`);
|
|
145
|
+
out.push('');
|
|
146
|
+
// Effectiveness headline (only when a reflection report exists).
|
|
147
|
+
if (p.effectiveness) {
|
|
148
|
+
out.push('## Effectiveness');
|
|
149
|
+
out.push('');
|
|
150
|
+
const delta = p.effectiveness.effectivenessDeltaPct === null
|
|
151
|
+
? ''
|
|
152
|
+
: ` (${p.effectiveness.effectivenessDeltaPct >= 0 ? '+' : ''}${p.effectiveness.effectivenessDeltaPct.toFixed(1)} pts)`;
|
|
153
|
+
out.push(`- Success rate: ${pct(p.effectiveness.successRate)}${delta}`);
|
|
154
|
+
out.push(`- ${p.effectiveness.headline}`);
|
|
155
|
+
out.push('');
|
|
156
|
+
}
|
|
157
|
+
// Today day-over-day deltas.
|
|
158
|
+
out.push(...renderToday(p.today));
|
|
159
|
+
out.push('');
|
|
160
|
+
// Optional narrative (already produced by a model upstream; metadata-free text).
|
|
161
|
+
if (report.narrative) {
|
|
162
|
+
out.push('## Summary');
|
|
163
|
+
out.push('');
|
|
164
|
+
out.push(report.narrative);
|
|
165
|
+
if (report.narrativeLocal === false) {
|
|
166
|
+
out.push('');
|
|
167
|
+
out.push('_(narrative generated by a cloud model)_');
|
|
168
|
+
}
|
|
169
|
+
out.push('');
|
|
170
|
+
}
|
|
171
|
+
// Trim trailing blank lines for a clean artifact.
|
|
172
|
+
while (out.length > 0 && out[out.length - 1] === '')
|
|
173
|
+
out.pop();
|
|
174
|
+
return out.join('\n') + '\n';
|
|
175
|
+
}
|
|
176
|
+
// ---------------------------------------------------------------------------
|
|
177
|
+
// Deliver
|
|
178
|
+
// ---------------------------------------------------------------------------
|
|
179
|
+
/**
|
|
180
|
+
* Deliver a digest. ALWAYS writes the local JSON + markdown artifact (via
|
|
181
|
+
* saveDigest). Calls notify() ONLY when opts.notify === true (opt-in) — that is
|
|
182
|
+
* the SINGLE outward path; everything else stops at local disk.
|
|
183
|
+
*
|
|
184
|
+
* Contract:
|
|
185
|
+
* - NEVER throws — failures degrade into the returned DigestDeliveryResult.
|
|
186
|
+
* - Default (no opts.notify) => `notified:false`, ZERO outward network calls.
|
|
187
|
+
* - notify() is itself a no-op unless a webhook is configured, so even with
|
|
188
|
+
* opts.notify:true `notified` is false when nothing is configured.
|
|
189
|
+
*/
|
|
190
|
+
export async function deliverDigest(report, cfg, opts) {
|
|
191
|
+
// 1. Render the deterministic markdown body (pure; no I/O, no model, no secrets).
|
|
192
|
+
let markdown = '';
|
|
193
|
+
try {
|
|
194
|
+
markdown = renderDigestText(report);
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
// Degrade to an empty body rather than throwing; the artifact still persists.
|
|
198
|
+
markdown = '';
|
|
199
|
+
}
|
|
200
|
+
// 2. ALWAYS write the local artifact. The store writes ONLY under digestsDir()
|
|
201
|
+
// (~/.ashlr/digests/) via atomic tmp+rename, and is contractually non-throwing.
|
|
202
|
+
let jsonPath = null;
|
|
203
|
+
let markdownPath = null;
|
|
204
|
+
try {
|
|
205
|
+
const paths = saveDigest(report, markdown);
|
|
206
|
+
jsonPath = paths.jsonPath;
|
|
207
|
+
markdownPath = paths.markdownPath;
|
|
208
|
+
}
|
|
209
|
+
catch {
|
|
210
|
+
// Belt-and-suspenders: saveDigest already degrades internally.
|
|
211
|
+
jsonPath = null;
|
|
212
|
+
markdownPath = null;
|
|
213
|
+
}
|
|
214
|
+
// 3. Outward delivery is OPT-IN ONLY. The default path NEVER references notify(),
|
|
215
|
+
// so it makes ZERO outward network calls. notify() is itself a strict no-op
|
|
216
|
+
// unless a Slack/Discord webhook is configured, so even with notify:true
|
|
217
|
+
// `notified` stays false when nothing is configured.
|
|
218
|
+
let notified = false;
|
|
219
|
+
if (opts?.notify === true) {
|
|
220
|
+
try {
|
|
221
|
+
notified = await notify(markdown, cfg);
|
|
222
|
+
}
|
|
223
|
+
catch {
|
|
224
|
+
// notify() never throws, but degrade defensively to a false outcome.
|
|
225
|
+
notified = false;
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
return { jsonPath, markdownPath, notified };
|
|
229
|
+
}
|
|
230
|
+
//# sourceMappingURL=deliver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deliver.js","sourceRoot":"","sources":["../../../src/core/digest/deliver.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core/digest/store.ts — M29 digest artifact persistence.
|
|
3
|
+
*
|
|
4
|
+
* Pure FS layer under `~/.ashlr/digests/`. Mirrors the M26 learn store / M27
|
|
5
|
+
* quality store: atomic tmp-write + rename, never throws on reads, filename
|
|
6
|
+
* stems are epoch-ms so lexicographic order == chronological order, and the
|
|
7
|
+
* read path is bounded by MAX_DIGESTS.
|
|
8
|
+
*
|
|
9
|
+
* HARD SAFETY INVARIANTS (M29) enforced here:
|
|
10
|
+
* - READ-ONLY AGGREGATION: this module WRITES only under digestsDir()
|
|
11
|
+
* (~/.ashlr/digests/). It NEVER writes CONFIG_PATH, never mutates a repo
|
|
12
|
+
* working tree, never applies/approves a proposal. The verifier proves it by
|
|
13
|
+
* asserting every write target resolves under digestsDir().
|
|
14
|
+
* - NO OUTWARD ACTION: persistence is local disk only. ZERO network calls.
|
|
15
|
+
* - BOUNDED + NEVER-THROWS: every read/write is wrapped; failures degrade to
|
|
16
|
+
* null / []. listDigests reads at most MAX_DIGESTS files.
|
|
17
|
+
*
|
|
18
|
+
* Each digest is persisted as TWO sibling artifacts sharing a stem:
|
|
19
|
+
* <stem>.json — the canonical DigestReport (used as the prior for deltas).
|
|
20
|
+
* <stem>.md — the human-readable markdown rendering (renderDigestText).
|
|
21
|
+
* The markdown is advisory; loadPreviousDigest reads only the JSON.
|
|
22
|
+
*/
|
|
23
|
+
import type { DigestReport } from '../types.js';
|
|
24
|
+
/**
|
|
25
|
+
* Re-export of {@link digestsDir} for store-local convenience and to mirror the
|
|
26
|
+
* `reportsDir()` shape of the learn/quality stores. `~/.ashlr/digests`.
|
|
27
|
+
* Created lazily by {@link saveDigest} — this function does NOT create it.
|
|
28
|
+
*/
|
|
29
|
+
export declare function digestsDirPath(): string;
|
|
30
|
+
/**
|
|
31
|
+
* Persist a DigestReport (JSON) + its markdown rendering under
|
|
32
|
+
* `~/.ashlr/digests/`. Atomic tmp-write + rename for each artifact.
|
|
33
|
+
*
|
|
34
|
+
* MUST NOT write anywhere outside digestsDir(). Returns the absolute paths of
|
|
35
|
+
* the artifacts written (null on failure). Never throws.
|
|
36
|
+
*
|
|
37
|
+
* @param report the digest to persist.
|
|
38
|
+
* @param markdown the pre-rendered markdown body (from renderDigestText).
|
|
39
|
+
*/
|
|
40
|
+
export declare function saveDigest(report: DigestReport, markdown: string): {
|
|
41
|
+
jsonPath: string | null;
|
|
42
|
+
markdownPath: string | null;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* List persisted DigestReport snapshots, most-recent first by `generatedAt`.
|
|
46
|
+
* Reads at most MAX_DIGESTS JSON files. Never throws; returns [] on any error
|
|
47
|
+
* and silently skips unreadable/malformed files.
|
|
48
|
+
*/
|
|
49
|
+
export declare function listDigests(): DigestReport[];
|
|
50
|
+
/**
|
|
51
|
+
* Load the most recent previously-persisted digest (the prior used to compute
|
|
52
|
+
* day-over-day deltas), or null when none exists.
|
|
53
|
+
*
|
|
54
|
+
* `before` (optional ISO ts) excludes digests at/after it so a freshly-saved
|
|
55
|
+
* current digest is not compared against itself.
|
|
56
|
+
*/
|
|
57
|
+
export declare function loadPreviousDigest(before?: string): DigestReport | null;
|