@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,223 @@
|
|
|
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 { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, writeFileSync } from 'node:fs';
|
|
24
|
+
import { join } from 'node:path';
|
|
25
|
+
import { digestsDir } from '../config.js';
|
|
26
|
+
// ---------------------------------------------------------------------------
|
|
27
|
+
// Caps
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
/** Max digest snapshots listDigests will read (bounds I/O). */
|
|
30
|
+
const MAX_DIGESTS = 200;
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Path helpers (re-resolved at call time so tests can relocate HOME)
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
/**
|
|
35
|
+
* Re-export of {@link digestsDir} for store-local convenience and to mirror the
|
|
36
|
+
* `reportsDir()` shape of the learn/quality stores. `~/.ashlr/digests`.
|
|
37
|
+
* Created lazily by {@link saveDigest} — this function does NOT create it.
|
|
38
|
+
*/
|
|
39
|
+
export function digestsDirPath() {
|
|
40
|
+
return digestsDir();
|
|
41
|
+
}
|
|
42
|
+
/** Ensure a directory exists, silently creating it if needed. Best-effort. */
|
|
43
|
+
function ensureDir(dir) {
|
|
44
|
+
// TODO(M29): mkdir recursive inside try/catch; a subsequent write fails
|
|
45
|
+
// gracefully in its own try/catch if this no-ops.
|
|
46
|
+
try {
|
|
47
|
+
if (!existsSync(dir))
|
|
48
|
+
mkdirSync(dir, { recursive: true });
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// Best-effort.
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Derive a filename-safe, chronologically-sortable stem from an ISO ts.
|
|
56
|
+
* Epoch-ms keeps lexicographic order == chronological order; falls back to a
|
|
57
|
+
* sanitized ISO string when the timestamp is unparseable.
|
|
58
|
+
*/
|
|
59
|
+
function digestStem(generatedAt) {
|
|
60
|
+
// Mirror reportStem in quality/store.ts: epoch-ms keeps lexicographic order ==
|
|
61
|
+
// chronological order; fall back to a sanitized ISO string when unparseable.
|
|
62
|
+
const ms = Date.parse(generatedAt);
|
|
63
|
+
if (Number.isFinite(ms))
|
|
64
|
+
return String(ms);
|
|
65
|
+
return generatedAt.replace(/[^\w.-]+/g, '-');
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Pick a collision-free stem under `dir`: if `<stem>.json` already exists (a
|
|
69
|
+
* second digest built in the SAME millisecond), append a bounded `-N` suffix so
|
|
70
|
+
* the second artifact does not silently clobber the first. The first writer in a
|
|
71
|
+
* fresh dir keeps the plain `<stem>` (preserving chronological lexicographic
|
|
72
|
+
* ordering). Mirrors uniqueDest() in quality/store.ts. Best-effort: on probe
|
|
73
|
+
* exhaustion it returns the plain stem (last-writer-wins, as before). Both the
|
|
74
|
+
* `.json` and its sibling `.md` share the returned stem, so they stay paired.
|
|
75
|
+
*/
|
|
76
|
+
function uniqueStem(dir, stem) {
|
|
77
|
+
try {
|
|
78
|
+
if (!existsSync(join(dir, `${stem}.json`)))
|
|
79
|
+
return stem;
|
|
80
|
+
for (let i = 1; i <= 1000; i++) {
|
|
81
|
+
const candidate = `${stem}-${i}`;
|
|
82
|
+
if (!existsSync(join(dir, `${candidate}.json`)))
|
|
83
|
+
return candidate;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
// existsSync should not throw, but fall through to the plain stem defensively.
|
|
88
|
+
}
|
|
89
|
+
return stem;
|
|
90
|
+
}
|
|
91
|
+
// ---------------------------------------------------------------------------
|
|
92
|
+
// Persist
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
/**
|
|
95
|
+
* Persist a DigestReport (JSON) + its markdown rendering under
|
|
96
|
+
* `~/.ashlr/digests/`. Atomic tmp-write + rename for each artifact.
|
|
97
|
+
*
|
|
98
|
+
* MUST NOT write anywhere outside digestsDir(). Returns the absolute paths of
|
|
99
|
+
* the artifacts written (null on failure). Never throws.
|
|
100
|
+
*
|
|
101
|
+
* @param report the digest to persist.
|
|
102
|
+
* @param markdown the pre-rendered markdown body (from renderDigestText).
|
|
103
|
+
*/
|
|
104
|
+
export function saveDigest(report, markdown) {
|
|
105
|
+
const dir = digestsDir();
|
|
106
|
+
ensureDir(dir);
|
|
107
|
+
// Collision-resistant: a second digest built in the SAME millisecond gets a
|
|
108
|
+
// `-N` suffix rather than overwriting the first artifact. The json + md share
|
|
109
|
+
// this one resolved stem so the pair stays together.
|
|
110
|
+
const stem = uniqueStem(dir, digestStem(report.generatedAt));
|
|
111
|
+
// Each artifact is written atomically (tmp-write + rename) and independently —
|
|
112
|
+
// a failure on one degrades that path to null without affecting the other.
|
|
113
|
+
// Both targets resolve under digestsDir(); nothing is written elsewhere.
|
|
114
|
+
let jsonPath = null;
|
|
115
|
+
try {
|
|
116
|
+
const dest = join(dir, `${stem}.json`);
|
|
117
|
+
const tmp = dest + '.tmp';
|
|
118
|
+
writeFileSync(tmp, JSON.stringify(report, null, 2) + '\n', 'utf8');
|
|
119
|
+
renameSync(tmp, dest);
|
|
120
|
+
jsonPath = dest;
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
jsonPath = null;
|
|
124
|
+
}
|
|
125
|
+
let markdownPath = null;
|
|
126
|
+
try {
|
|
127
|
+
const dest = join(dir, `${stem}.md`);
|
|
128
|
+
const tmp = dest + '.tmp';
|
|
129
|
+
writeFileSync(tmp, markdown, 'utf8');
|
|
130
|
+
renameSync(tmp, dest);
|
|
131
|
+
markdownPath = dest;
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
markdownPath = null;
|
|
135
|
+
}
|
|
136
|
+
return { jsonPath, markdownPath };
|
|
137
|
+
}
|
|
138
|
+
// ---------------------------------------------------------------------------
|
|
139
|
+
// Load
|
|
140
|
+
// ---------------------------------------------------------------------------
|
|
141
|
+
/** Light structural guard so we never return garbage from the store. */
|
|
142
|
+
function isDigest(parsed) {
|
|
143
|
+
// Mirror isReport in learn/store.ts — validate generatedAt:string, date:string,
|
|
144
|
+
// window in {'7d','30d'}, portfolio:object.
|
|
145
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
146
|
+
return false;
|
|
147
|
+
}
|
|
148
|
+
const r = parsed;
|
|
149
|
+
return (typeof r['generatedAt'] === 'string' &&
|
|
150
|
+
typeof r['date'] === 'string' &&
|
|
151
|
+
(r['window'] === '7d' || r['window'] === '30d') &&
|
|
152
|
+
typeof r['portfolio'] === 'object' &&
|
|
153
|
+
r['portfolio'] !== null);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* List persisted DigestReport snapshots, most-recent first by `generatedAt`.
|
|
157
|
+
* Reads at most MAX_DIGESTS JSON files. Never throws; returns [] on any error
|
|
158
|
+
* and silently skips unreadable/malformed files.
|
|
159
|
+
*/
|
|
160
|
+
export function listDigests() {
|
|
161
|
+
try {
|
|
162
|
+
const dir = digestsDir();
|
|
163
|
+
if (!existsSync(dir))
|
|
164
|
+
return [];
|
|
165
|
+
let files;
|
|
166
|
+
try {
|
|
167
|
+
// Filename stems are epoch-ms, so a lexicographic descending sort of the
|
|
168
|
+
// filenames already orders newest-first; sort here so the slice keeps the
|
|
169
|
+
// MOST-RECENT MAX_DIGESTS rather than an arbitrary directory order. We read
|
|
170
|
+
// ONLY *.json artifacts (skip the sibling *.md and any *.tmp leftovers).
|
|
171
|
+
files = readdirSync(dir)
|
|
172
|
+
.filter((f) => f.endsWith('.json') && !f.endsWith('.tmp'))
|
|
173
|
+
.sort((a, b) => (a < b ? 1 : a > b ? -1 : 0))
|
|
174
|
+
.slice(0, MAX_DIGESTS);
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
return [];
|
|
178
|
+
}
|
|
179
|
+
const digests = [];
|
|
180
|
+
for (const file of files) {
|
|
181
|
+
try {
|
|
182
|
+
const raw = readFileSync(join(dir, file), 'utf8');
|
|
183
|
+
const parsed = JSON.parse(raw);
|
|
184
|
+
if (isDigest(parsed))
|
|
185
|
+
digests.push(parsed);
|
|
186
|
+
}
|
|
187
|
+
catch {
|
|
188
|
+
// Unreadable or malformed — skip silently.
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// Most-recent first by generatedAt (ISO strings sort lexicographically).
|
|
192
|
+
digests.sort((a, b) => a.generatedAt < b.generatedAt ? 1 : a.generatedAt > b.generatedAt ? -1 : 0);
|
|
193
|
+
return digests;
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
return [];
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Load the most recent previously-persisted digest (the prior used to compute
|
|
201
|
+
* day-over-day deltas), or null when none exists.
|
|
202
|
+
*
|
|
203
|
+
* `before` (optional ISO ts) excludes digests at/after it so a freshly-saved
|
|
204
|
+
* current digest is not compared against itself.
|
|
205
|
+
*/
|
|
206
|
+
export function loadPreviousDigest(before) {
|
|
207
|
+
try {
|
|
208
|
+
const all = listDigests();
|
|
209
|
+
if (all.length === 0)
|
|
210
|
+
return null;
|
|
211
|
+
if (before === undefined)
|
|
212
|
+
return all[0] ?? null;
|
|
213
|
+
for (const d of all) {
|
|
214
|
+
if (d.generatedAt < before)
|
|
215
|
+
return d;
|
|
216
|
+
}
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
catch {
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
//# sourceMappingURL=store.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"store.js","sourceRoot":"","sources":["../../../src/core/digest/store.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core/doctor-fix.ts — self-healing `ashlr doctor --fix`.
|
|
3
|
+
*
|
|
4
|
+
* fixDoctor(cfg): run runDoctor, then for each failing/warn check whose id
|
|
5
|
+
* is in the SAFE-FIXABLE set, apply ONE safe, local, non-destructive
|
|
6
|
+
* remediation and record a FixAction. Every other failing/warn check gets a
|
|
7
|
+
* FixAction with applied:false, manual:true and a one-line guidance detail.
|
|
8
|
+
*
|
|
9
|
+
* GUARDRAILS (non-negotiable):
|
|
10
|
+
* - ONLY safe, local, non-destructive fixes.
|
|
11
|
+
* - NEVER delete or overwrite existing user data.
|
|
12
|
+
* - NEVER auto-download models (pull stays explicit).
|
|
13
|
+
* - NEVER modify secrets or shell profiles.
|
|
14
|
+
* - NEVER do anything outward/network.
|
|
15
|
+
* - Editor-config writes are backup-first + idempotent (M18 wireEditor).
|
|
16
|
+
* - Each fix is reversible-ish and logged in FixAction.detail.
|
|
17
|
+
* - Ambiguous → leave as manual.
|
|
18
|
+
* - Never throws.
|
|
19
|
+
*/
|
|
20
|
+
import type { AshlrConfig, FixAction } from './types.js';
|
|
21
|
+
export declare function fixDoctor(cfg: AshlrConfig): Promise<FixAction[]>;
|
|
@@ -0,0 +1,440 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core/doctor-fix.ts — self-healing `ashlr doctor --fix`.
|
|
3
|
+
*
|
|
4
|
+
* fixDoctor(cfg): run runDoctor, then for each failing/warn check whose id
|
|
5
|
+
* is in the SAFE-FIXABLE set, apply ONE safe, local, non-destructive
|
|
6
|
+
* remediation and record a FixAction. Every other failing/warn check gets a
|
|
7
|
+
* FixAction with applied:false, manual:true and a one-line guidance detail.
|
|
8
|
+
*
|
|
9
|
+
* GUARDRAILS (non-negotiable):
|
|
10
|
+
* - ONLY safe, local, non-destructive fixes.
|
|
11
|
+
* - NEVER delete or overwrite existing user data.
|
|
12
|
+
* - NEVER auto-download models (pull stays explicit).
|
|
13
|
+
* - NEVER modify secrets or shell profiles.
|
|
14
|
+
* - NEVER do anything outward/network.
|
|
15
|
+
* - Editor-config writes are backup-first + idempotent (M18 wireEditor).
|
|
16
|
+
* - Each fix is reversible-ish and logged in FixAction.detail.
|
|
17
|
+
* - Ambiguous → leave as manual.
|
|
18
|
+
* - Never throws.
|
|
19
|
+
*/
|
|
20
|
+
import { existsSync, mkdirSync, symlinkSync, lstatSync } from 'node:fs';
|
|
21
|
+
import { homedir } from 'node:os';
|
|
22
|
+
import { join, dirname, resolve } from 'node:path';
|
|
23
|
+
import { fileURLToPath } from 'node:url';
|
|
24
|
+
import { runDoctor } from './doctor.js';
|
|
25
|
+
import { defaultConfig, saveConfig } from './config.js';
|
|
26
|
+
import { buildIndex, writeIndex } from './index-engine.js';
|
|
27
|
+
import { detectEditors, wireEditor } from './integrations/editors.js';
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// SAFE-FIXABLE check ids
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
const SAFE_FIXABLE = new Set([
|
|
32
|
+
'config',
|
|
33
|
+
'index',
|
|
34
|
+
'local-bin',
|
|
35
|
+
'genome-memory',
|
|
36
|
+
'mcp-plugin',
|
|
37
|
+
]);
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// Individual fix helpers — each returns a FixAction, never throws
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
/**
|
|
42
|
+
* Fix: config — create missing ~/.ashlr/config.json from defaultConfig().
|
|
43
|
+
* ONLY when ABSENT; never overwrites an existing config (even a broken one —
|
|
44
|
+
* that's a manual fix to preserve user data).
|
|
45
|
+
*/
|
|
46
|
+
async function fixConfig(_cfg, checkDetail) {
|
|
47
|
+
const base = {
|
|
48
|
+
checkId: 'config',
|
|
49
|
+
label: 'Create missing config file',
|
|
50
|
+
};
|
|
51
|
+
// Resolve the config path from homedir() at call time so a moving HOME (e.g.
|
|
52
|
+
// in tests, or a relocated home dir) is honored — must match the path that
|
|
53
|
+
// saveConfig() actually writes to. The exported CONFIG_PATH constant is
|
|
54
|
+
// resolved once at module load and would point at a stale home here.
|
|
55
|
+
const configPath = join(homedir(), '.ashlr', 'config.json');
|
|
56
|
+
// If the file exists (even if unreadable/malformed), do NOT overwrite.
|
|
57
|
+
if (existsSync(configPath)) {
|
|
58
|
+
return {
|
|
59
|
+
...base,
|
|
60
|
+
applied: false,
|
|
61
|
+
manual: true,
|
|
62
|
+
detail: `Config file exists but may be invalid (${checkDetail}). Fix JSON syntax errors manually in ${configPath}.`,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
try {
|
|
66
|
+
const defaults = defaultConfig();
|
|
67
|
+
saveConfig(defaults);
|
|
68
|
+
return {
|
|
69
|
+
...base,
|
|
70
|
+
applied: true,
|
|
71
|
+
manual: false,
|
|
72
|
+
detail: `Created ${configPath} from defaults.`,
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
return {
|
|
77
|
+
...base,
|
|
78
|
+
applied: false,
|
|
79
|
+
manual: true,
|
|
80
|
+
detail: `Could not create ${configPath}: ${String(err)}. Create it manually by running: ashlr init`,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Fix: index — rebuild a stale/missing ~/.ashlr/index.json.
|
|
86
|
+
* buildIndex + writeIndex is non-destructive (regenerates derived data only).
|
|
87
|
+
*/
|
|
88
|
+
async function fixIndex(cfg) {
|
|
89
|
+
const base = {
|
|
90
|
+
checkId: 'index',
|
|
91
|
+
label: 'Rebuild stale/missing index',
|
|
92
|
+
};
|
|
93
|
+
try {
|
|
94
|
+
const index = buildIndex(cfg);
|
|
95
|
+
writeIndex(index);
|
|
96
|
+
return {
|
|
97
|
+
...base,
|
|
98
|
+
applied: true,
|
|
99
|
+
manual: false,
|
|
100
|
+
detail: `Rebuilt index (${index.items.length} item${index.items.length !== 1 ? 's' : ''}) and wrote to ~/.ashlr/index.json.`,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
catch (err) {
|
|
104
|
+
return {
|
|
105
|
+
...base,
|
|
106
|
+
applied: false,
|
|
107
|
+
manual: true,
|
|
108
|
+
detail: `Could not rebuild index: ${String(err)}. Run: ashlr index`,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Fix: local-bin — create the ashlr → ~/.local/bin/ashlr symlink when missing
|
|
114
|
+
* and the source binary resolves. Never modifies shell profiles.
|
|
115
|
+
*
|
|
116
|
+
* If ~/.local/bin/ashlr already exists (broken symlink or stale file), we
|
|
117
|
+
* do NOT overwrite it — that's a manual decision.
|
|
118
|
+
*
|
|
119
|
+
* PATH presence is a separate concern — always manual (shell profile edit).
|
|
120
|
+
*/
|
|
121
|
+
async function fixLocalBin() {
|
|
122
|
+
const base = {
|
|
123
|
+
checkId: 'local-bin',
|
|
124
|
+
label: 'Create ~/.local/bin/ashlr symlink',
|
|
125
|
+
};
|
|
126
|
+
const localBinDir = join(homedir(), '.local', 'bin');
|
|
127
|
+
const symlinkPath = join(localBinDir, 'ashlr');
|
|
128
|
+
// If something already exists at the symlink path (any kind), leave it.
|
|
129
|
+
if (existsSync(symlinkPath)) {
|
|
130
|
+
// Symlink exists and resolves — check PATH separately (manual).
|
|
131
|
+
return {
|
|
132
|
+
...base,
|
|
133
|
+
applied: false,
|
|
134
|
+
manual: true,
|
|
135
|
+
detail: `${symlinkPath} already exists. If ashlr is not on PATH, add to your shell profile: export PATH="$HOME/.local/bin:$PATH"`,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
// Also check lstat: catches broken symlinks that existsSync misses.
|
|
139
|
+
try {
|
|
140
|
+
lstatSync(symlinkPath);
|
|
141
|
+
// lstat succeeded but existsSync returned false → broken symlink exists.
|
|
142
|
+
return {
|
|
143
|
+
...base,
|
|
144
|
+
applied: false,
|
|
145
|
+
manual: true,
|
|
146
|
+
detail: `${symlinkPath} is a broken symlink. Remove it manually then re-run: ashlr doctor --fix`,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
// lstatSync threw → path truly does not exist, safe to create.
|
|
151
|
+
}
|
|
152
|
+
// Resolve the source binary path from this module's location.
|
|
153
|
+
// __filename → <repo>/dist/core/doctor-fix.js → source is <repo>/bin/ashlr
|
|
154
|
+
let sourceBin;
|
|
155
|
+
try {
|
|
156
|
+
const thisFile = fileURLToPath(import.meta.url);
|
|
157
|
+
// dist/core/doctor-fix.js → repo root is two levels up
|
|
158
|
+
const repoRoot = resolve(dirname(thisFile), '..', '..');
|
|
159
|
+
sourceBin = join(repoRoot, 'bin', 'ashlr');
|
|
160
|
+
if (!existsSync(sourceBin)) {
|
|
161
|
+
return {
|
|
162
|
+
...base,
|
|
163
|
+
applied: false,
|
|
164
|
+
manual: true,
|
|
165
|
+
detail: `Could not locate bin/ashlr (expected at ${sourceBin}). Run install.sh to create the symlink manually.`,
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
catch (err) {
|
|
170
|
+
return {
|
|
171
|
+
...base,
|
|
172
|
+
applied: false,
|
|
173
|
+
manual: true,
|
|
174
|
+
detail: `Could not resolve bin/ashlr path: ${String(err)}. Run install.sh to create the symlink manually.`,
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
// Ensure ~/.local/bin exists.
|
|
178
|
+
try {
|
|
179
|
+
mkdirSync(localBinDir, { recursive: true });
|
|
180
|
+
}
|
|
181
|
+
catch (err) {
|
|
182
|
+
return {
|
|
183
|
+
...base,
|
|
184
|
+
applied: false,
|
|
185
|
+
manual: true,
|
|
186
|
+
detail: `Could not create ${localBinDir}: ${String(err)}.`,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
// Create the symlink.
|
|
190
|
+
try {
|
|
191
|
+
symlinkSync(sourceBin, symlinkPath);
|
|
192
|
+
// Success detail intentionally does NOT mention shell-profile PATH edits —
|
|
193
|
+
// creating the symlink is the safe local fix; ensuring ~/.local/bin is on
|
|
194
|
+
// PATH stays a manual shell-profile concern surfaced by the doctor report.
|
|
195
|
+
return {
|
|
196
|
+
...base,
|
|
197
|
+
applied: true,
|
|
198
|
+
manual: false,
|
|
199
|
+
detail: `Created symlink: ${symlinkPath} -> ${sourceBin}.`,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
catch (err) {
|
|
203
|
+
return {
|
|
204
|
+
...base,
|
|
205
|
+
applied: false,
|
|
206
|
+
manual: true,
|
|
207
|
+
detail: `Could not create symlink at ${symlinkPath}: ${String(err)}. Run install.sh manually.`,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Fix: genome-memory — create ~/.ashlr/genome/ directory when missing.
|
|
213
|
+
* mkdir-only; never seeds or edits entries.
|
|
214
|
+
*/
|
|
215
|
+
async function fixGenomeMemory() {
|
|
216
|
+
const base = {
|
|
217
|
+
checkId: 'genome-memory',
|
|
218
|
+
label: 'Create genome memory directory',
|
|
219
|
+
};
|
|
220
|
+
const genomeDir = join(homedir(), '.ashlr', 'genome');
|
|
221
|
+
if (existsSync(genomeDir)) {
|
|
222
|
+
// Dir exists but genome is empty — that's a content issue, not a structural one.
|
|
223
|
+
return {
|
|
224
|
+
...base,
|
|
225
|
+
applied: false,
|
|
226
|
+
manual: true,
|
|
227
|
+
detail: `Genome directory exists at ${genomeDir} but is empty. Run: ashlr learn to seed memory.`,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
try {
|
|
231
|
+
mkdirSync(genomeDir, { recursive: true });
|
|
232
|
+
return {
|
|
233
|
+
...base,
|
|
234
|
+
applied: true,
|
|
235
|
+
manual: false,
|
|
236
|
+
detail: `Created genome directory at ${genomeDir}.`,
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
catch (err) {
|
|
240
|
+
return {
|
|
241
|
+
...base,
|
|
242
|
+
applied: false,
|
|
243
|
+
manual: true,
|
|
244
|
+
detail: `Could not create genome directory at ${genomeDir}: ${String(err)}.`,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Fix: mcp-plugin — register the ashlr MCP gateway into a detected editor
|
|
250
|
+
* config via wireEditor (backup-first, idempotent — M18 pattern).
|
|
251
|
+
*
|
|
252
|
+
* Tries each detected editor in order; stops at the first successful wire.
|
|
253
|
+
* If no editor is detected, leaves as manual.
|
|
254
|
+
*/
|
|
255
|
+
async function fixMcpPlugin() {
|
|
256
|
+
const base = {
|
|
257
|
+
checkId: 'mcp-plugin',
|
|
258
|
+
label: 'Register ashlr MCP gateway in editor config',
|
|
259
|
+
};
|
|
260
|
+
let detectedEditors;
|
|
261
|
+
try {
|
|
262
|
+
detectedEditors = detectEditors();
|
|
263
|
+
}
|
|
264
|
+
catch (err) {
|
|
265
|
+
return {
|
|
266
|
+
...base,
|
|
267
|
+
applied: false,
|
|
268
|
+
manual: true,
|
|
269
|
+
detail: `Could not detect editors: ${String(err)}. Run: ashlr init --wire`,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
if (detectedEditors.length === 0) {
|
|
273
|
+
return {
|
|
274
|
+
...base,
|
|
275
|
+
applied: false,
|
|
276
|
+
manual: true,
|
|
277
|
+
detail: 'No supported editors detected (claude/codex/cursor). Install one and run: ashlr init --wire',
|
|
278
|
+
};
|
|
279
|
+
}
|
|
280
|
+
const errors = [];
|
|
281
|
+
for (const editor of detectedEditors) {
|
|
282
|
+
// wireEditor only accepts the three known targets; skip unknown values.
|
|
283
|
+
if (editor !== 'claude' && editor !== 'codex' && editor !== 'cursor')
|
|
284
|
+
continue;
|
|
285
|
+
try {
|
|
286
|
+
const result = await wireEditor(editor, {});
|
|
287
|
+
if (result.ok) {
|
|
288
|
+
return {
|
|
289
|
+
...base,
|
|
290
|
+
applied: true,
|
|
291
|
+
manual: false,
|
|
292
|
+
detail: `Wired ashlr MCP gateway into ${editor} config: ${result.detail}`,
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
errors.push(`${editor}: ${result.detail}`);
|
|
296
|
+
}
|
|
297
|
+
catch (err) {
|
|
298
|
+
errors.push(`${editor}: ${String(err)}`);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
// All attempts failed.
|
|
302
|
+
return {
|
|
303
|
+
...base,
|
|
304
|
+
applied: false,
|
|
305
|
+
manual: true,
|
|
306
|
+
detail: `Could not auto-wire MCP plugin (${errors.join('; ')}). Run: ashlr init --wire`,
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Produce a manual-only FixAction for a check that has no safe auto-fix.
|
|
311
|
+
* Uses the check's existing `fix` hint as guidance.
|
|
312
|
+
*/
|
|
313
|
+
function manualAction(checkId, label, fix) {
|
|
314
|
+
return {
|
|
315
|
+
checkId,
|
|
316
|
+
label,
|
|
317
|
+
applied: false,
|
|
318
|
+
manual: true,
|
|
319
|
+
detail: fix ?? `Manual action required — see: ashlr doctor for details.`,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
// ---------------------------------------------------------------------------
|
|
323
|
+
// fixDoctor
|
|
324
|
+
// ---------------------------------------------------------------------------
|
|
325
|
+
/**
|
|
326
|
+
* Run runDoctor(cfg), then for each failing or warn check:
|
|
327
|
+
* - If the check id is in SAFE_FIXABLE: apply the safe automated remediation.
|
|
328
|
+
* - Otherwise: return a manual FixAction with the check's fix hint.
|
|
329
|
+
*
|
|
330
|
+
* Pass-status checks produce no FixAction.
|
|
331
|
+
* Returns FixAction[] in check display order.
|
|
332
|
+
* Never throws.
|
|
333
|
+
*/
|
|
334
|
+
/**
|
|
335
|
+
* H5 CHANGE 1 — `doctor --fix` orphan-sweep hook. Reclaims STALE crash-leftover
|
|
336
|
+
* sandbox worktrees (the same primitive the daemon runs at start + `sandbox gc`
|
|
337
|
+
* exposes). LOCAL + non-destructive: sweepOrphanSandboxes routes every removal
|
|
338
|
+
* through removeSandbox's containment guards (re-derived safe path + branch; a
|
|
339
|
+
* tampered/out-of-namespace entry is refused git ops, local-dir cleanup only)
|
|
340
|
+
* and the conservative ORPHAN_STALE_MS guard means a LIVE in-flight worktree is
|
|
341
|
+
* NEVER reclaimed — only genuine crash leftovers. Pushes nothing, opens no PR,
|
|
342
|
+
* applies no proposal. Lazy-imports the build-optional worktree module and never
|
|
343
|
+
* throws (degrades to a manual note). Returns a synthetic FixAction.
|
|
344
|
+
*/
|
|
345
|
+
async function fixSandboxOrphans() {
|
|
346
|
+
const checkId = 'sandbox-orphans';
|
|
347
|
+
const label = 'Reclaim stale orphan sandboxes';
|
|
348
|
+
try {
|
|
349
|
+
const wt = await import('./sandbox/worktree.js');
|
|
350
|
+
const swept = wt.sweepOrphanSandboxes({ staleMs: wt.ORPHAN_STALE_MS });
|
|
351
|
+
return {
|
|
352
|
+
checkId,
|
|
353
|
+
label,
|
|
354
|
+
applied: swept.length > 0,
|
|
355
|
+
manual: false,
|
|
356
|
+
detail: swept.length === 0
|
|
357
|
+
? 'No stale orphan sandboxes to reclaim.'
|
|
358
|
+
: `Reclaimed ${swept.length} stale orphan sandbox(es): ${swept.join(', ')}`,
|
|
359
|
+
};
|
|
360
|
+
}
|
|
361
|
+
catch (err) {
|
|
362
|
+
return {
|
|
363
|
+
checkId,
|
|
364
|
+
label,
|
|
365
|
+
applied: false,
|
|
366
|
+
manual: true,
|
|
367
|
+
detail: `Could not sweep orphan sandboxes: ${String(err)}. Try: ashlr sandbox gc`,
|
|
368
|
+
};
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
export async function fixDoctor(cfg) {
|
|
372
|
+
let report;
|
|
373
|
+
try {
|
|
374
|
+
report = await runDoctor(cfg);
|
|
375
|
+
}
|
|
376
|
+
catch (err) {
|
|
377
|
+
// runDoctor itself is documented to never throw, but belt-and-suspenders.
|
|
378
|
+
return [
|
|
379
|
+
{
|
|
380
|
+
checkId: '_internal',
|
|
381
|
+
label: 'Run doctor',
|
|
382
|
+
applied: false,
|
|
383
|
+
manual: true,
|
|
384
|
+
detail: `Could not run doctor: ${String(err)}. Try: ashlr doctor`,
|
|
385
|
+
},
|
|
386
|
+
];
|
|
387
|
+
}
|
|
388
|
+
const actions = [];
|
|
389
|
+
for (const check of report.checks) {
|
|
390
|
+
// Pass checks need no action.
|
|
391
|
+
if (check.status === 'pass')
|
|
392
|
+
continue;
|
|
393
|
+
if (!SAFE_FIXABLE.has(check.id)) {
|
|
394
|
+
// Not in the safe-fixable set → always manual.
|
|
395
|
+
actions.push(manualAction(check.id, check.label, check.fix));
|
|
396
|
+
continue;
|
|
397
|
+
}
|
|
398
|
+
// Apply the appropriate safe fix.
|
|
399
|
+
let action;
|
|
400
|
+
try {
|
|
401
|
+
switch (check.id) {
|
|
402
|
+
case 'config':
|
|
403
|
+
action = await fixConfig(cfg, check.detail);
|
|
404
|
+
break;
|
|
405
|
+
case 'index':
|
|
406
|
+
action = await fixIndex(cfg);
|
|
407
|
+
break;
|
|
408
|
+
case 'local-bin':
|
|
409
|
+
action = await fixLocalBin();
|
|
410
|
+
break;
|
|
411
|
+
case 'genome-memory':
|
|
412
|
+
action = await fixGenomeMemory();
|
|
413
|
+
break;
|
|
414
|
+
case 'mcp-plugin':
|
|
415
|
+
action = await fixMcpPlugin();
|
|
416
|
+
break;
|
|
417
|
+
default:
|
|
418
|
+
// Should not be reachable given the SAFE_FIXABLE guard above.
|
|
419
|
+
action = manualAction(check.id, check.label, check.fix);
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
catch (err) {
|
|
423
|
+
// Belt-and-suspenders: individual fix helpers should never throw,
|
|
424
|
+
// but if one does, degrade to manual rather than crashing.
|
|
425
|
+
action = {
|
|
426
|
+
checkId: check.id,
|
|
427
|
+
label: check.label,
|
|
428
|
+
applied: false,
|
|
429
|
+
manual: true,
|
|
430
|
+
detail: `Fix failed unexpectedly: ${String(err)}. Manual action: ${check.fix ?? 'see ashlr doctor'}`,
|
|
431
|
+
};
|
|
432
|
+
}
|
|
433
|
+
actions.push(action);
|
|
434
|
+
}
|
|
435
|
+
// H5 CHANGE 1 — always-run orphan sweep (independent of doctor checks): reclaim
|
|
436
|
+
// stale crash-leftover sandboxes. Safe + local + non-destructive (see helper).
|
|
437
|
+
actions.push(await fixSandboxOrphans());
|
|
438
|
+
return actions;
|
|
439
|
+
}
|
|
440
|
+
//# sourceMappingURL=doctor-fix.js.map
|