@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,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core/plugins/integrity.ts — M33 plugin entry-file integrity check.
|
|
3
|
+
*
|
|
4
|
+
* CONTRACT RULES (non-negotiable):
|
|
5
|
+
* - hashEntry NEVER throws; returns null on any read failure.
|
|
6
|
+
* - verifyIntegrity NEVER throws; returns { ok: false } on missing pin,
|
|
7
|
+
* read failure, or hash mismatch.
|
|
8
|
+
* - Hashes are sha256 hex prefixed "sha256:".
|
|
9
|
+
* - recordIntegrity is NOT here — config writes are CLI responsibility.
|
|
10
|
+
* - Only the entry file is hashed (not the whole plugin directory).
|
|
11
|
+
*/
|
|
12
|
+
import type { AshlrConfig } from '../types.js';
|
|
13
|
+
/**
|
|
14
|
+
* Compute the sha256 hash of the file at `entryPath`.
|
|
15
|
+
* Returns the hash as a string prefixed "sha256:<hex>".
|
|
16
|
+
* Returns null if the file cannot be read (absent, permission denied, etc.).
|
|
17
|
+
*
|
|
18
|
+
* NEVER throws.
|
|
19
|
+
*/
|
|
20
|
+
export declare function hashEntry(entryPath: string): string | null;
|
|
21
|
+
/**
|
|
22
|
+
* Verify that the live hash of `entryPath` matches the hash pinned in
|
|
23
|
+
* cfg.plugins?.integrity[name].
|
|
24
|
+
*
|
|
25
|
+
* Returns { ok: true } when the hashes match.
|
|
26
|
+
* Returns { ok: false; reason } when:
|
|
27
|
+
* - No pin is recorded for this plugin (cfg.plugins?.integrity[name] absent).
|
|
28
|
+
* - The entry file cannot be read (hashEntry returns null).
|
|
29
|
+
* - The live hash does not match the pinned hash.
|
|
30
|
+
*
|
|
31
|
+
* NEVER throws.
|
|
32
|
+
*/
|
|
33
|
+
export declare function verifyIntegrity(cfg: AshlrConfig, name: string, entryPath: string): {
|
|
34
|
+
ok: boolean;
|
|
35
|
+
reason?: string;
|
|
36
|
+
};
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core/plugins/integrity.ts — M33 plugin entry-file integrity check.
|
|
3
|
+
*
|
|
4
|
+
* CONTRACT RULES (non-negotiable):
|
|
5
|
+
* - hashEntry NEVER throws; returns null on any read failure.
|
|
6
|
+
* - verifyIntegrity NEVER throws; returns { ok: false } on missing pin,
|
|
7
|
+
* read failure, or hash mismatch.
|
|
8
|
+
* - Hashes are sha256 hex prefixed "sha256:".
|
|
9
|
+
* - recordIntegrity is NOT here — config writes are CLI responsibility.
|
|
10
|
+
* - Only the entry file is hashed (not the whole plugin directory).
|
|
11
|
+
*/
|
|
12
|
+
import { readFileSync } from 'node:fs';
|
|
13
|
+
import { createHash } from 'node:crypto';
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
// hashEntry — compute sha256 of an entry file
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
/**
|
|
18
|
+
* Compute the sha256 hash of the file at `entryPath`.
|
|
19
|
+
* Returns the hash as a string prefixed "sha256:<hex>".
|
|
20
|
+
* Returns null if the file cannot be read (absent, permission denied, etc.).
|
|
21
|
+
*
|
|
22
|
+
* NEVER throws.
|
|
23
|
+
*/
|
|
24
|
+
export function hashEntry(entryPath) {
|
|
25
|
+
try {
|
|
26
|
+
const bytes = readFileSync(entryPath);
|
|
27
|
+
const hex = createHash('sha256').update(bytes).digest('hex');
|
|
28
|
+
return `sha256:${hex}`;
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
// File not found, permission denied, or other I/O error — return null.
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// verifyIntegrity — compare live hash against pinned hash in cfg
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
/**
|
|
39
|
+
* Verify that the live hash of `entryPath` matches the hash pinned in
|
|
40
|
+
* cfg.plugins?.integrity[name].
|
|
41
|
+
*
|
|
42
|
+
* Returns { ok: true } when the hashes match.
|
|
43
|
+
* Returns { ok: false; reason } when:
|
|
44
|
+
* - No pin is recorded for this plugin (cfg.plugins?.integrity[name] absent).
|
|
45
|
+
* - The entry file cannot be read (hashEntry returns null).
|
|
46
|
+
* - The live hash does not match the pinned hash.
|
|
47
|
+
*
|
|
48
|
+
* NEVER throws.
|
|
49
|
+
*/
|
|
50
|
+
export function verifyIntegrity(cfg, name, entryPath) {
|
|
51
|
+
try {
|
|
52
|
+
const pinnedHash = cfg.plugins?.integrity?.[name];
|
|
53
|
+
if (!pinnedHash) {
|
|
54
|
+
return { ok: false, reason: `no integrity pin recorded for plugin "${name}"` };
|
|
55
|
+
}
|
|
56
|
+
const liveHash = hashEntry(entryPath);
|
|
57
|
+
if (liveHash === null) {
|
|
58
|
+
return { ok: false, reason: `could not read entry file for plugin "${name}": ${entryPath}` };
|
|
59
|
+
}
|
|
60
|
+
if (liveHash !== pinnedHash) {
|
|
61
|
+
return {
|
|
62
|
+
ok: false,
|
|
63
|
+
reason: `integrity mismatch for plugin "${name}": pinned ${pinnedHash}, got ${liveHash}`,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
return { ok: true };
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
// Belt-and-suspenders: verifyIntegrity must never throw.
|
|
70
|
+
return { ok: false, reason: `unexpected error verifying integrity for plugin "${name}"` };
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=integrity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"integrity.js","sourceRoot":"","sources":["../../../src/core/plugins/integrity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAGzC,8EAA8E;AAC9E,8CAA8C;AAC9C,8EAA8E;AAE9E;;;;;;GAMG;AACH,MAAM,UAAU,SAAS,CAAC,SAAiB;IACzC,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,YAAY,CAAC,SAAS,CAAC,CAAC;QACtC,MAAM,GAAG,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC7D,OAAO,UAAU,GAAG,EAAE,CAAC;IACzB,CAAC;IAAC,MAAM,CAAC;QACP,uEAAuE;QACvE,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,8EAA8E;AAC9E,iEAAiE;AACjE,8EAA8E;AAE9E;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,eAAe,CAC7B,GAAgB,EAChB,IAAY,EACZ,SAAiB;IAEjB,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,GAAG,CAAC,OAAO,EAAE,SAAS,EAAE,CAAC,IAAI,CAAC,CAAC;QAElD,IAAI,CAAC,UAAU,EAAE,CAAC;YAChB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,yCAAyC,IAAI,GAAG,EAAE,CAAC;QACjF,CAAC;QAED,MAAM,QAAQ,GAAG,SAAS,CAAC,SAAS,CAAC,CAAC;QACtC,IAAI,QAAQ,KAAK,IAAI,EAAE,CAAC;YACtB,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,yCAAyC,IAAI,MAAM,SAAS,EAAE,EAAE,CAAC;QAC/F,CAAC;QAED,IAAI,QAAQ,KAAK,UAAU,EAAE,CAAC;YAC5B,OAAO;gBACL,EAAE,EAAE,KAAK;gBACT,MAAM,EAAE,kCAAkC,IAAI,aAAa,UAAU,SAAS,QAAQ,EAAE;aACzF,CAAC;QACJ,CAAC;QAED,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC;IACtB,CAAC;IAAC,MAAM,CAAC;QACP,yDAAyD;QACzD,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,oDAAoD,IAAI,GAAG,EAAE,CAAC;IAC5F,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core/plugins/manifest.ts — M33 plugin manifest reader + validator.
|
|
3
|
+
*
|
|
4
|
+
* CONTRACT RULES (non-negotiable):
|
|
5
|
+
* - readManifest NEVER throws; all errors are returned as { ok: false; reason }.
|
|
6
|
+
* - Bounded read: manifests exceeding 64 KB are rejected.
|
|
7
|
+
* - Proto-pollution: any object key equal to "__proto__", "constructor", or
|
|
8
|
+
* "prototype" anywhere in the parsed object rejects the manifest.
|
|
9
|
+
* - name must match ^[a-z][a-z0-9-]{0,39}$ AND equal basename(dir).
|
|
10
|
+
* - entry must resolve INSIDE the plugin dir (path-string containment).
|
|
11
|
+
* The entry file itself may not exist at discovery time — only the path
|
|
12
|
+
* is validated, not its presence.
|
|
13
|
+
* - apiVersion is evaluated against PLUGIN_API_VERSION with a hand-rolled
|
|
14
|
+
* range matcher (exact, ^, ~, x-wildcards). No runtime deps.
|
|
15
|
+
*/
|
|
16
|
+
import { type PluginManifest } from './types.js';
|
|
17
|
+
/**
|
|
18
|
+
* Read and fully validate <dir>/manifest.json.
|
|
19
|
+
*
|
|
20
|
+
* Returns { ok: true; manifest } on success.
|
|
21
|
+
* Returns { ok: false; reason } on any validation failure.
|
|
22
|
+
*
|
|
23
|
+
* NEVER throws — all errors are caught and returned as { ok: false }.
|
|
24
|
+
*/
|
|
25
|
+
export declare function readManifest(dir: string): {
|
|
26
|
+
ok: true;
|
|
27
|
+
manifest: PluginManifest;
|
|
28
|
+
} | {
|
|
29
|
+
ok: false;
|
|
30
|
+
reason: string;
|
|
31
|
+
};
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core/plugins/manifest.ts — M33 plugin manifest reader + validator.
|
|
3
|
+
*
|
|
4
|
+
* CONTRACT RULES (non-negotiable):
|
|
5
|
+
* - readManifest NEVER throws; all errors are returned as { ok: false; reason }.
|
|
6
|
+
* - Bounded read: manifests exceeding 64 KB are rejected.
|
|
7
|
+
* - Proto-pollution: any object key equal to "__proto__", "constructor", or
|
|
8
|
+
* "prototype" anywhere in the parsed object rejects the manifest.
|
|
9
|
+
* - name must match ^[a-z][a-z0-9-]{0,39}$ AND equal basename(dir).
|
|
10
|
+
* - entry must resolve INSIDE the plugin dir (path-string containment).
|
|
11
|
+
* The entry file itself may not exist at discovery time — only the path
|
|
12
|
+
* is validated, not its presence.
|
|
13
|
+
* - apiVersion is evaluated against PLUGIN_API_VERSION with a hand-rolled
|
|
14
|
+
* range matcher (exact, ^, ~, x-wildcards). No runtime deps.
|
|
15
|
+
*/
|
|
16
|
+
import { readFileSync, statSync } from 'node:fs';
|
|
17
|
+
import { join, basename, sep, resolve } from 'node:path';
|
|
18
|
+
import { PLUGIN_API_VERSION } from './types.js';
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Constants
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
/** Maximum allowed manifest.json size in bytes (64 KB). */
|
|
23
|
+
const MAX_MANIFEST_BYTES = 64 * 1024;
|
|
24
|
+
/** Valid plugin name pattern: ^[a-z][a-z0-9-]{0,39}$ */
|
|
25
|
+
const NAME_RE = /^[a-z][a-z0-9-]{0,39}$/;
|
|
26
|
+
/** Valid PluginCapability values. */
|
|
27
|
+
const VALID_CAPABILITIES = new Set([
|
|
28
|
+
'scanner',
|
|
29
|
+
'template',
|
|
30
|
+
'provider',
|
|
31
|
+
'command',
|
|
32
|
+
]);
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
// Proto-pollution guard
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
/**
|
|
37
|
+
* Recursively scan a parsed JSON value for __proto__, constructor, or
|
|
38
|
+
* prototype keys. Returns true if any such key is found (poison detected).
|
|
39
|
+
* Bounded: objects/arrays in a manifest.json are small; no stack overflow risk
|
|
40
|
+
* in practice, but we cap depth at 8 to be defensive.
|
|
41
|
+
*/
|
|
42
|
+
function hasPoisonKey(value, depth = 0) {
|
|
43
|
+
if (depth > 8)
|
|
44
|
+
return false;
|
|
45
|
+
if (value === null || typeof value !== 'object')
|
|
46
|
+
return false;
|
|
47
|
+
const keys = Object.keys(value);
|
|
48
|
+
for (const key of keys) {
|
|
49
|
+
if (key === '__proto__' || key === 'constructor' || key === 'prototype') {
|
|
50
|
+
return true;
|
|
51
|
+
}
|
|
52
|
+
if (hasPoisonKey(value[key], depth + 1)) {
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (Array.isArray(value)) {
|
|
57
|
+
for (const item of value) {
|
|
58
|
+
if (hasPoisonKey(item, depth + 1))
|
|
59
|
+
return true;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
// Hand-rolled semver range matcher
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
/**
|
|
68
|
+
* Parse a semver string "MAJOR.MINOR.PATCH" into a numeric triple.
|
|
69
|
+
* Returns null if the string is not parseable as a 3-part semver.
|
|
70
|
+
*/
|
|
71
|
+
function parseSemver(s) {
|
|
72
|
+
const parts = s.trim().split('.');
|
|
73
|
+
if (parts.length !== 3)
|
|
74
|
+
return null;
|
|
75
|
+
const nums = parts.map(Number);
|
|
76
|
+
if (nums.some((n) => !Number.isInteger(n) || n < 0))
|
|
77
|
+
return null;
|
|
78
|
+
return nums;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Evaluate whether `host` (the host's PLUGIN_API_VERSION) satisfies the
|
|
82
|
+
* plugin's `range` declaration.
|
|
83
|
+
*
|
|
84
|
+
* Supported range forms:
|
|
85
|
+
* - exact: "1.0.0" → host must be exactly 1.0.0
|
|
86
|
+
* - caret: "^1.0.0" → host major must match, host >= range version
|
|
87
|
+
* - tilde: "~1.0.0" → host major+minor must match, host >= range version
|
|
88
|
+
* - wildcard: "1.x" → host major must match; minor/patch free
|
|
89
|
+
* "1.0.x" → host major+minor must match; patch free
|
|
90
|
+
*
|
|
91
|
+
* Returns true iff host satisfies the range.
|
|
92
|
+
* Returns false for any unrecognised range form (strict unknown rejection).
|
|
93
|
+
*/
|
|
94
|
+
function semverSatisfies(range, host) {
|
|
95
|
+
const hostParsed = parseSemver(host);
|
|
96
|
+
if (!hostParsed)
|
|
97
|
+
return false;
|
|
98
|
+
const [hMaj, hMin, hPatch] = hostParsed;
|
|
99
|
+
const r = range.trim();
|
|
100
|
+
// Caret: ^MAJOR.MINOR.PATCH
|
|
101
|
+
if (r.startsWith('^')) {
|
|
102
|
+
const parsed = parseSemver(r.slice(1));
|
|
103
|
+
if (!parsed)
|
|
104
|
+
return false;
|
|
105
|
+
const [rMaj, rMin, rPatch] = parsed;
|
|
106
|
+
if (hMaj !== rMaj)
|
|
107
|
+
return false;
|
|
108
|
+
if (hMin < rMin)
|
|
109
|
+
return false;
|
|
110
|
+
if (hMin === rMin && hPatch < rPatch)
|
|
111
|
+
return false;
|
|
112
|
+
return true;
|
|
113
|
+
}
|
|
114
|
+
// Tilde: ~MAJOR.MINOR.PATCH
|
|
115
|
+
if (r.startsWith('~')) {
|
|
116
|
+
const parsed = parseSemver(r.slice(1));
|
|
117
|
+
if (!parsed)
|
|
118
|
+
return false;
|
|
119
|
+
const [rMaj, rMin, rPatch] = parsed;
|
|
120
|
+
if (hMaj !== rMaj || hMin !== rMin)
|
|
121
|
+
return false;
|
|
122
|
+
if (hPatch < rPatch)
|
|
123
|
+
return false;
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
// Wildcard: "1.x" or "1.0.x"
|
|
127
|
+
if (r.includes('x') || r.includes('X') || r.includes('*')) {
|
|
128
|
+
const parts = r.split('.');
|
|
129
|
+
// "1.x" (2 parts with x)
|
|
130
|
+
if (parts.length === 2) {
|
|
131
|
+
const maj = Number(parts[0]);
|
|
132
|
+
if (!Number.isInteger(maj) || maj < 0)
|
|
133
|
+
return false;
|
|
134
|
+
const minPart = (parts[1] ?? '').trim().toLowerCase();
|
|
135
|
+
if (minPart !== 'x' && minPart !== '*')
|
|
136
|
+
return false;
|
|
137
|
+
return hMaj === maj;
|
|
138
|
+
}
|
|
139
|
+
// "1.0.x" (3 parts with x in last position)
|
|
140
|
+
if (parts.length === 3) {
|
|
141
|
+
const maj = Number(parts[0]);
|
|
142
|
+
const min = Number(parts[1]);
|
|
143
|
+
const patchPart = (parts[2] ?? '').trim().toLowerCase();
|
|
144
|
+
if (!Number.isInteger(maj) || maj < 0)
|
|
145
|
+
return false;
|
|
146
|
+
if (!Number.isInteger(min) || min < 0)
|
|
147
|
+
return false;
|
|
148
|
+
if (patchPart !== 'x' && patchPart !== '*')
|
|
149
|
+
return false;
|
|
150
|
+
return hMaj === maj && hMin === min;
|
|
151
|
+
}
|
|
152
|
+
return false;
|
|
153
|
+
}
|
|
154
|
+
// Exact: "MAJOR.MINOR.PATCH"
|
|
155
|
+
const parsed = parseSemver(r);
|
|
156
|
+
if (!parsed)
|
|
157
|
+
return false;
|
|
158
|
+
const [rMaj, rMin, rPatch] = parsed;
|
|
159
|
+
return hMaj === rMaj && hMin === rMin && hPatch === rPatch;
|
|
160
|
+
}
|
|
161
|
+
// ---------------------------------------------------------------------------
|
|
162
|
+
// readManifest — public API
|
|
163
|
+
// ---------------------------------------------------------------------------
|
|
164
|
+
/**
|
|
165
|
+
* Read and fully validate <dir>/manifest.json.
|
|
166
|
+
*
|
|
167
|
+
* Returns { ok: true; manifest } on success.
|
|
168
|
+
* Returns { ok: false; reason } on any validation failure.
|
|
169
|
+
*
|
|
170
|
+
* NEVER throws — all errors are caught and returned as { ok: false }.
|
|
171
|
+
*/
|
|
172
|
+
export function readManifest(dir) {
|
|
173
|
+
try {
|
|
174
|
+
const manifestPath = join(dir, 'manifest.json');
|
|
175
|
+
// --- Bounded read (≤ 64 KB) ---
|
|
176
|
+
let size;
|
|
177
|
+
try {
|
|
178
|
+
const stat = statSync(manifestPath);
|
|
179
|
+
size = stat.size;
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
return { ok: false, reason: `manifest.json not found or unreadable in ${dir}` };
|
|
183
|
+
}
|
|
184
|
+
if (size > MAX_MANIFEST_BYTES) {
|
|
185
|
+
return {
|
|
186
|
+
ok: false,
|
|
187
|
+
reason: `manifest.json exceeds 64 KB limit (${size} bytes) in ${dir}`,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
// --- Read + parse ---
|
|
191
|
+
let raw;
|
|
192
|
+
try {
|
|
193
|
+
raw = readFileSync(manifestPath, 'utf8');
|
|
194
|
+
}
|
|
195
|
+
catch {
|
|
196
|
+
return { ok: false, reason: `could not read manifest.json in ${dir}` };
|
|
197
|
+
}
|
|
198
|
+
let parsed;
|
|
199
|
+
try {
|
|
200
|
+
parsed = JSON.parse(raw);
|
|
201
|
+
}
|
|
202
|
+
catch {
|
|
203
|
+
return { ok: false, reason: `manifest.json is not valid JSON in ${dir}` };
|
|
204
|
+
}
|
|
205
|
+
// --- Proto-pollution guard (before any property access) ---
|
|
206
|
+
if (hasPoisonKey(parsed)) {
|
|
207
|
+
return {
|
|
208
|
+
ok: false,
|
|
209
|
+
reason: `manifest.json contains forbidden key (__proto__/constructor/prototype) in ${dir}`,
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
// --- Top-level must be a plain object ---
|
|
213
|
+
if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
214
|
+
return { ok: false, reason: `manifest.json must be a plain object in ${dir}` };
|
|
215
|
+
}
|
|
216
|
+
const obj = parsed;
|
|
217
|
+
// --- Required string fields ---
|
|
218
|
+
if (typeof obj['name'] !== 'string' || obj['name'].length === 0) {
|
|
219
|
+
return { ok: false, reason: `manifest.json: "name" must be a non-empty string in ${dir}` };
|
|
220
|
+
}
|
|
221
|
+
if (typeof obj['version'] !== 'string' || obj['version'].length === 0) {
|
|
222
|
+
return {
|
|
223
|
+
ok: false,
|
|
224
|
+
reason: `manifest.json: "version" must be a non-empty string in ${dir}`,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
if (typeof obj['apiVersion'] !== 'string' || obj['apiVersion'].length === 0) {
|
|
228
|
+
return {
|
|
229
|
+
ok: false,
|
|
230
|
+
reason: `manifest.json: "apiVersion" must be a non-empty string in ${dir}`,
|
|
231
|
+
};
|
|
232
|
+
}
|
|
233
|
+
if (typeof obj['entry'] !== 'string' || obj['entry'].length === 0) {
|
|
234
|
+
return { ok: false, reason: `manifest.json: "entry" must be a non-empty string in ${dir}` };
|
|
235
|
+
}
|
|
236
|
+
const name = obj['name'];
|
|
237
|
+
const version = obj['version'];
|
|
238
|
+
const apiVersion = obj['apiVersion'];
|
|
239
|
+
const entry = obj['entry'];
|
|
240
|
+
// --- name pattern ---
|
|
241
|
+
if (!NAME_RE.test(name)) {
|
|
242
|
+
return {
|
|
243
|
+
ok: false,
|
|
244
|
+
reason: `manifest.json: name "${name}" does not match ^[a-z][a-z0-9-]{0,39}$ in ${dir}`,
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
// --- name === basename(dir) ---
|
|
248
|
+
const dirBase = basename(resolve(dir));
|
|
249
|
+
if (name !== dirBase) {
|
|
250
|
+
return {
|
|
251
|
+
ok: false,
|
|
252
|
+
reason: `manifest.json: name "${name}" must equal directory basename "${dirBase}" in ${dir}`,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
// --- apiVersion semver range compatibility ---
|
|
256
|
+
if (!semverSatisfies(apiVersion, PLUGIN_API_VERSION)) {
|
|
257
|
+
return {
|
|
258
|
+
ok: false,
|
|
259
|
+
reason: `manifest.json: apiVersion range "${apiVersion}" is not satisfied by host version ${PLUGIN_API_VERSION} in ${dir}`,
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
// --- capabilities: non-empty array of valid strings ---
|
|
263
|
+
if (!Array.isArray(obj['capabilities']) || obj['capabilities'].length === 0) {
|
|
264
|
+
return {
|
|
265
|
+
ok: false,
|
|
266
|
+
reason: `manifest.json: "capabilities" must be a non-empty array in ${dir}`,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
const capabilities = obj['capabilities'];
|
|
270
|
+
for (const cap of capabilities) {
|
|
271
|
+
if (typeof cap !== 'string' || !VALID_CAPABILITIES.has(cap)) {
|
|
272
|
+
return {
|
|
273
|
+
ok: false,
|
|
274
|
+
reason: `manifest.json: invalid capability "${String(cap)}" in ${dir}`,
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
// --- entry: relative, no absolute, no ".." traversal ---
|
|
279
|
+
// Entry must not be absolute.
|
|
280
|
+
if (entry.startsWith('/')) {
|
|
281
|
+
return {
|
|
282
|
+
ok: false,
|
|
283
|
+
reason: `manifest.json: entry "${entry}" must be a relative path in ${dir}`,
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
// Resolve entry inside dir and verify containment (path-string check).
|
|
287
|
+
const resolvedDir = resolve(dir) + sep;
|
|
288
|
+
const resolvedEntry = resolve(dir, entry);
|
|
289
|
+
// Containment: resolvedEntry must start with resolvedDir (with trailing sep
|
|
290
|
+
// to prevent "prefix" attacks like /plugins/foo-extra matching /plugins/foo/).
|
|
291
|
+
if (!resolvedEntry.startsWith(resolvedDir)) {
|
|
292
|
+
return {
|
|
293
|
+
ok: false,
|
|
294
|
+
reason: `manifest.json: entry "${entry}" resolves outside plugin directory in ${dir}`,
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
// --- Optional fields ---
|
|
298
|
+
const description = typeof obj['description'] === 'string' ? obj['description'] : undefined;
|
|
299
|
+
const homepage = typeof obj['homepage'] === 'string' ? obj['homepage'] : undefined;
|
|
300
|
+
const manifest = {
|
|
301
|
+
name,
|
|
302
|
+
version,
|
|
303
|
+
apiVersion,
|
|
304
|
+
entry,
|
|
305
|
+
capabilities: capabilities,
|
|
306
|
+
...(description !== undefined ? { description } : {}),
|
|
307
|
+
...(homepage !== undefined ? { homepage } : {}),
|
|
308
|
+
};
|
|
309
|
+
return { ok: true, manifest };
|
|
310
|
+
}
|
|
311
|
+
catch {
|
|
312
|
+
// Belt-and-suspenders: readManifest must never throw.
|
|
313
|
+
return { ok: false, reason: `unexpected error reading manifest in ${dir}` };
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../src/core/plugins/manifest.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core/plugins/registry.ts — M33 plugin discovery, load, and accessors.
|
|
3
|
+
*
|
|
4
|
+
* CONTRACT RULES (non-negotiable):
|
|
5
|
+
* - discoverPlugins NEVER imports plugin code. It only reads manifest.json.
|
|
6
|
+
* - loadEnabledPlugins gate chain (in order):
|
|
7
|
+
* 1. ASHLR_NO_PLUGINS=1 → return [] immediately.
|
|
8
|
+
* 2. killSwitchOn() → return [] + audit 'plugin:load' refused.
|
|
9
|
+
* 3. Only names in cfg.plugins?.enabled ?? [] (default empty → load NOTHING).
|
|
10
|
+
* 4. Manifest valid + apiVersion compatible (via readManifest).
|
|
11
|
+
* 5. verifyIntegrity passes.
|
|
12
|
+
* 6. await import(pathToFileURL(entry).href) in try/catch.
|
|
13
|
+
* 7. activate(host) raced against timeout.
|
|
14
|
+
* 8. Capability filter: drop contributions whose kind is not declared.
|
|
15
|
+
* - A failing plugin is skipped (audited), NEVER fatal.
|
|
16
|
+
* - Module-level memo cache: one load per process.
|
|
17
|
+
* - homedir() re-resolved at call time for test HOME relocation.
|
|
18
|
+
*
|
|
19
|
+
* ZERO RUNTIME DEPS: only Node builtins + local imports.
|
|
20
|
+
*/
|
|
21
|
+
import type { AshlrConfig, WorkItem, ProjectTemplate } from '../types.js';
|
|
22
|
+
import type { PluginManifest, PluginContributions, PluginCommandSpec, PluginProviderSpec } from './types.js';
|
|
23
|
+
/**
|
|
24
|
+
* Override the activate() timeout for tests. Pass undefined to reset to default.
|
|
25
|
+
* Named with underscore prefix per house test-seam convention.
|
|
26
|
+
*/
|
|
27
|
+
export declare function _setActivateTimeoutForTest(ms: number | undefined): void;
|
|
28
|
+
/**
|
|
29
|
+
* Reset the plugin cache. For tests only — allows re-loading after config changes.
|
|
30
|
+
* Named with underscore prefix per house test-seam convention.
|
|
31
|
+
*/
|
|
32
|
+
export declare function _resetPluginCacheForTest(): void;
|
|
33
|
+
/** A fully-loaded, activated plugin with its contributions. */
|
|
34
|
+
export interface LoadedPlugin {
|
|
35
|
+
name: string;
|
|
36
|
+
manifest: PluginManifest;
|
|
37
|
+
contributions: PluginContributions;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Discover all plugin directories under ~/.ashlr/plugins/.
|
|
41
|
+
* For each subdirectory, attempts to read and validate manifest.json.
|
|
42
|
+
*
|
|
43
|
+
* NEVER imports plugin code — manifest read only.
|
|
44
|
+
* NEVER throws.
|
|
45
|
+
*
|
|
46
|
+
* homedir() is resolved at call time so tests can relocate HOME.
|
|
47
|
+
*/
|
|
48
|
+
export declare function discoverPlugins(): Array<{
|
|
49
|
+
dir: string;
|
|
50
|
+
manifest?: PluginManifest;
|
|
51
|
+
ok: boolean;
|
|
52
|
+
reason?: string;
|
|
53
|
+
}>;
|
|
54
|
+
/**
|
|
55
|
+
* Load all enabled plugins per cfg.plugins.enabled gate chain.
|
|
56
|
+
*
|
|
57
|
+
* Gate chain (each step audited):
|
|
58
|
+
* 1. ASHLR_NO_PLUGINS=1 → return [].
|
|
59
|
+
* 2. killSwitchOn() → return [] + audit refused.
|
|
60
|
+
* 3. cfg.plugins?.enabled ?? [] (default empty → load NOTHING).
|
|
61
|
+
* 4. Manifest valid + apiVersion compatible.
|
|
62
|
+
* 5. verifyIntegrity passes.
|
|
63
|
+
* 6. await import(pathToFileURL(entry).href).
|
|
64
|
+
* 7. activate(host) raced against timeout.
|
|
65
|
+
* 8. Capability filter.
|
|
66
|
+
*
|
|
67
|
+
* A failing plugin is skipped (audited), never fatal.
|
|
68
|
+
* Results are cached per process (keyed on sorted enabled names).
|
|
69
|
+
*/
|
|
70
|
+
export declare function loadEnabledPlugins(cfg: AshlrConfig): Promise<LoadedPlugin[]>;
|
|
71
|
+
/**
|
|
72
|
+
* Get all plugin scanners, wrapped for safety (timeout, cap, scrub, namespace).
|
|
73
|
+
* Returns wrapped functions (repo: string) => Promise<WorkItem[]>.
|
|
74
|
+
*/
|
|
75
|
+
export declare function getPluginScanners(cfg: AshlrConfig): Promise<Array<(repo: string) => Promise<WorkItem[]>>>;
|
|
76
|
+
/**
|
|
77
|
+
* Get all plugin templates, validated (id-prefixed, path-checked).
|
|
78
|
+
*/
|
|
79
|
+
export declare function getPluginTemplates(cfg: AshlrConfig): Promise<ProjectTemplate[]>;
|
|
80
|
+
/**
|
|
81
|
+
* Get all plugin providers (raw, as contributed after capability filtering).
|
|
82
|
+
*/
|
|
83
|
+
export declare function getPluginProviders(cfg: AshlrConfig): Promise<PluginProviderSpec[]>;
|
|
84
|
+
/**
|
|
85
|
+
* Get all plugin commands, wrapped for safety (audit, exit-code catch).
|
|
86
|
+
*/
|
|
87
|
+
export declare function getPluginCommands(cfg: AshlrConfig): Promise<PluginCommandSpec[]>;
|