@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,250 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider registry — probes local-model endpoints (LM Studio, Ollama) and
|
|
3
|
+
* resolves the active provider from the configured chain.
|
|
4
|
+
*
|
|
5
|
+
* Rules:
|
|
6
|
+
* - NEVER throws; all probes return typed results with up:false on failure.
|
|
7
|
+
* - Uses global fetch (Node 22+) with a 2-second AbortController timeout.
|
|
8
|
+
* - Cloud providers (e.g. 'anthropic') are treated as up when the relevant
|
|
9
|
+
* env var is present (ANTHROPIC_API_KEY), else skipped.
|
|
10
|
+
*/
|
|
11
|
+
// ---------------------------------------------------------------------------
|
|
12
|
+
// Internal helpers
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
/**
|
|
15
|
+
* Ensure a base URL has the expected path suffix.
|
|
16
|
+
* e.g. ensurePath('http://localhost:1234', '/v1/models') -> 'http://localhost:1234/v1/models'
|
|
17
|
+
* If the URL already ends with the path, it is returned unchanged.
|
|
18
|
+
*/
|
|
19
|
+
function ensurePath(base, suffix) {
|
|
20
|
+
const stripped = base.replace(/\/+$/, '');
|
|
21
|
+
if (stripped.endsWith(suffix))
|
|
22
|
+
return stripped;
|
|
23
|
+
return stripped + suffix;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Parse model names from an LM Studio /v1/models response (OpenAI shape).
|
|
27
|
+
* Returns empty array on any shape mismatch.
|
|
28
|
+
*/
|
|
29
|
+
function parseLmStudioModels(body) {
|
|
30
|
+
if (typeof body !== 'object' ||
|
|
31
|
+
body === null ||
|
|
32
|
+
!Array.isArray(body['data'])) {
|
|
33
|
+
return [];
|
|
34
|
+
}
|
|
35
|
+
const data = body.data;
|
|
36
|
+
return data
|
|
37
|
+
.filter((m) => typeof m['id'] === 'string')
|
|
38
|
+
.map((m) => m.id);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Parse model names from an Ollama /api/tags response.
|
|
42
|
+
* Returns empty array on any shape mismatch.
|
|
43
|
+
*/
|
|
44
|
+
function parseOllamaModels(body) {
|
|
45
|
+
if (typeof body !== 'object' ||
|
|
46
|
+
body === null ||
|
|
47
|
+
!Array.isArray(body['models'])) {
|
|
48
|
+
return [];
|
|
49
|
+
}
|
|
50
|
+
const models = body.models;
|
|
51
|
+
return models
|
|
52
|
+
.filter((m) => typeof m['name'] === 'string')
|
|
53
|
+
.map((m) => m.name);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Determine which response shape to use for a given probe URL.
|
|
57
|
+
* - URL ends with /v1/models → LM Studio (OpenAI) shape
|
|
58
|
+
* - URL ends with /api/tags → Ollama shape
|
|
59
|
+
* - Fallback: try LM Studio shape first, then Ollama
|
|
60
|
+
*/
|
|
61
|
+
function parseModels(url, body) {
|
|
62
|
+
if (url.endsWith('/v1/models'))
|
|
63
|
+
return parseLmStudioModels(body);
|
|
64
|
+
if (url.endsWith('/api/tags'))
|
|
65
|
+
return parseOllamaModels(body);
|
|
66
|
+
// Unknown path — try both shapes, take whichever yields results
|
|
67
|
+
const lm = parseLmStudioModels(body);
|
|
68
|
+
return lm.length > 0 ? lm : parseOllamaModels(body);
|
|
69
|
+
}
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
// Cloud provider env-var map
|
|
72
|
+
// Extend as new cloud providers are added to providerChain.
|
|
73
|
+
// ---------------------------------------------------------------------------
|
|
74
|
+
const CLOUD_PROVIDER_ENV = {
|
|
75
|
+
anthropic: 'ANTHROPIC_API_KEY',
|
|
76
|
+
openai: 'OPENAI_API_KEY',
|
|
77
|
+
gemini: 'GEMINI_API_KEY',
|
|
78
|
+
cohere: 'COHERE_API_KEY',
|
|
79
|
+
groq: 'GROQ_API_KEY',
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Returns true if a cloud provider's API key is present in process.env.
|
|
83
|
+
* Unknown cloud providers default to false (not considered up).
|
|
84
|
+
*/
|
|
85
|
+
function cloudProviderUp(id) {
|
|
86
|
+
const envVar = CLOUD_PROVIDER_ENV[id.toLowerCase()];
|
|
87
|
+
if (!envVar)
|
|
88
|
+
return false;
|
|
89
|
+
const val = process.env[envVar];
|
|
90
|
+
return typeof val === 'string' && val.trim().length > 0;
|
|
91
|
+
}
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
// Public API
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
/**
|
|
96
|
+
* Probe a single provider endpoint with a 2-second timeout.
|
|
97
|
+
*
|
|
98
|
+
* - For LM Studio: GET <url>/v1/models (appended if not already present)
|
|
99
|
+
* - For Ollama: GET <url>/api/tags (appended if not already present)
|
|
100
|
+
* - For other ids: url is used as-is (caller must supply full probe URL)
|
|
101
|
+
*
|
|
102
|
+
* Never throws — returns up:false with an error string on any failure.
|
|
103
|
+
*/
|
|
104
|
+
export async function probeEndpoint(id, url) {
|
|
105
|
+
// Determine the canonical probe URL
|
|
106
|
+
let probeUrl;
|
|
107
|
+
if (id === 'lmstudio') {
|
|
108
|
+
probeUrl = ensurePath(url, '/v1/models');
|
|
109
|
+
}
|
|
110
|
+
else if (id === 'ollama') {
|
|
111
|
+
probeUrl = ensurePath(url, '/api/tags');
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
probeUrl = url;
|
|
115
|
+
}
|
|
116
|
+
const controller = new AbortController();
|
|
117
|
+
const timer = setTimeout(() => controller.abort(), 2000);
|
|
118
|
+
try {
|
|
119
|
+
const response = await fetch(probeUrl, {
|
|
120
|
+
method: 'GET',
|
|
121
|
+
signal: controller.signal,
|
|
122
|
+
headers: { Accept: 'application/json' },
|
|
123
|
+
});
|
|
124
|
+
// NOTE: do NOT clearTimeout here — the abort signal must stay armed across
|
|
125
|
+
// the response-body read below so a server that streams/hangs the body is
|
|
126
|
+
// still bounded by the 2s timeout. Cleared in the finally block.
|
|
127
|
+
if (!response.ok) {
|
|
128
|
+
return {
|
|
129
|
+
id,
|
|
130
|
+
url: probeUrl,
|
|
131
|
+
up: false,
|
|
132
|
+
models: [],
|
|
133
|
+
error: `HTTP ${response.status} ${response.statusText}`,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
let body;
|
|
137
|
+
try {
|
|
138
|
+
body = await response.json();
|
|
139
|
+
}
|
|
140
|
+
catch {
|
|
141
|
+
return {
|
|
142
|
+
id,
|
|
143
|
+
url: probeUrl,
|
|
144
|
+
up: false,
|
|
145
|
+
models: [],
|
|
146
|
+
error: 'Response body is not valid JSON',
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
const models = parseModels(probeUrl, body);
|
|
150
|
+
return { id, url: probeUrl, up: true, models };
|
|
151
|
+
}
|
|
152
|
+
catch (err) {
|
|
153
|
+
let message;
|
|
154
|
+
if (err instanceof Error) {
|
|
155
|
+
message = err.name === 'AbortError' ? 'Probe timed out after 2s' : err.message;
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
message = String(err);
|
|
159
|
+
}
|
|
160
|
+
return { id, url: probeUrl, up: false, models: [], error: message };
|
|
161
|
+
}
|
|
162
|
+
finally {
|
|
163
|
+
// Disarm the timeout only after the body read has completed or failed,
|
|
164
|
+
// so the abort signal bounds both the fetch() and the response.json().
|
|
165
|
+
clearTimeout(timer);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Build the full ProviderRegistry from the current config.
|
|
170
|
+
*
|
|
171
|
+
* - Probes cfg.models.lmstudio and cfg.models.ollama in parallel.
|
|
172
|
+
* - Walks cfg.models.providerChain in order to find the first up provider.
|
|
173
|
+
* - Cloud providers (e.g. 'anthropic') count as up if their env key exists.
|
|
174
|
+
* - Local providers not in the config (unknown ids) are skipped gracefully.
|
|
175
|
+
*/
|
|
176
|
+
export async function getProviderRegistry(cfg) {
|
|
177
|
+
const chain = cfg.models.providerChain;
|
|
178
|
+
// Probe the two known local endpoints in parallel
|
|
179
|
+
const [lmResult, ollamaResult] = await Promise.all([
|
|
180
|
+
probeEndpoint('lmstudio', cfg.models.lmstudio),
|
|
181
|
+
probeEndpoint('ollama', cfg.models.ollama),
|
|
182
|
+
]);
|
|
183
|
+
// Build a lookup map for the probed local endpoints
|
|
184
|
+
const localEndpoints = {
|
|
185
|
+
lmstudio: lmResult,
|
|
186
|
+
ollama: ollamaResult,
|
|
187
|
+
};
|
|
188
|
+
// Assemble the providers list in chain order where possible,
|
|
189
|
+
// appending any probed endpoints not present in the chain.
|
|
190
|
+
const seenIds = new Set();
|
|
191
|
+
const providers = [];
|
|
192
|
+
for (const providerId of chain) {
|
|
193
|
+
if (seenIds.has(providerId))
|
|
194
|
+
continue;
|
|
195
|
+
seenIds.add(providerId);
|
|
196
|
+
if (localEndpoints[providerId] !== undefined) {
|
|
197
|
+
providers.push(localEndpoints[providerId]);
|
|
198
|
+
}
|
|
199
|
+
// Cloud providers are not added as ProviderEndpoint entries
|
|
200
|
+
// (they have no local URL to probe) — they participate only in
|
|
201
|
+
// activeProvider resolution below.
|
|
202
|
+
}
|
|
203
|
+
// Add any probed local endpoints that were not in the chain
|
|
204
|
+
for (const [id, endpoint] of Object.entries(localEndpoints)) {
|
|
205
|
+
if (!seenIds.has(id)) {
|
|
206
|
+
seenIds.add(id);
|
|
207
|
+
providers.push(endpoint);
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// Resolve activeProvider: first entry in chain that is considered "up"
|
|
211
|
+
let activeProvider = null;
|
|
212
|
+
for (const providerId of chain) {
|
|
213
|
+
const local = localEndpoints[providerId];
|
|
214
|
+
if (local !== undefined) {
|
|
215
|
+
if (local.up) {
|
|
216
|
+
activeProvider = providerId;
|
|
217
|
+
break;
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
else {
|
|
221
|
+
// Treat as a cloud provider — up if env key is present
|
|
222
|
+
if (cloudProviderUp(providerId)) {
|
|
223
|
+
activeProvider = providerId;
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
// Failover fallback: if the configured chain yielded no active provider but a
|
|
229
|
+
// probed local endpoint is actually up (e.g. a custom chain that omits an up
|
|
230
|
+
// local id), select the first up local endpoint. Keeps default behavior
|
|
231
|
+
// identical (the default chain already lists both local ids) while making
|
|
232
|
+
// failover correct for non-default chains.
|
|
233
|
+
if (activeProvider === null) {
|
|
234
|
+
for (const endpoint of providers) {
|
|
235
|
+
if (endpoint.up) {
|
|
236
|
+
activeProvider = endpoint.id;
|
|
237
|
+
break;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return { providers, activeProvider, chain };
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Convenience wrapper — returns the id of the active provider, or null.
|
|
245
|
+
*/
|
|
246
|
+
export async function resolveActiveProvider(cfg) {
|
|
247
|
+
const registry = await getProviderRegistry(cfg);
|
|
248
|
+
return registry.activeProvider;
|
|
249
|
+
}
|
|
250
|
+
//# sourceMappingURL=providers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"providers.js","sourceRoot":"","sources":["../../src/core/providers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* conventions.ts — Read-only PROJECT-STANDARDS probes for a single repo (M27).
|
|
3
|
+
*
|
|
4
|
+
* GUARDRAILS (enforced throughout this file):
|
|
5
|
+
* - READ-ONLY: pure FS reads (existsSync / statSync / readFileSync). NO writes,
|
|
6
|
+
* NO git mutations, NO installs, NO shell. NEVER mutates a user repo working tree.
|
|
7
|
+
* - Bounded: a fixed, small set of top-level presence checks + a shallow read of
|
|
8
|
+
* the root package.json; no deep tree traversal, no unbounded loops.
|
|
9
|
+
* - Never throws: returns [] on any error so callers (health.ts) stay unblocked.
|
|
10
|
+
* - No secrets: emitted ConventionFinding values are presence/label metadata only.
|
|
11
|
+
* - Enrollment-scoping is the CALLER's responsibility (health.ts) — this module
|
|
12
|
+
* is a pure probe over whatever absolute path it is handed.
|
|
13
|
+
*/
|
|
14
|
+
import type { ConventionFinding } from '../types.js';
|
|
15
|
+
/**
|
|
16
|
+
* Probe `repo` (an absolute path) for project-standard conventions.
|
|
17
|
+
*
|
|
18
|
+
* Returns a deterministic, ordered ConventionFinding[] covering:
|
|
19
|
+
* - README presence + thinness (< THIN_README_BYTES bytes)
|
|
20
|
+
* - LICENSE presence
|
|
21
|
+
* - lockfile presence (package-lock.json / yarn.lock / pnpm-lock.yaml / bun.lockb / Cargo.lock / …)
|
|
22
|
+
* - .gitignore presence
|
|
23
|
+
* - a test signal (test|tests|__tests__|spec dir, or a package.json "test" script)
|
|
24
|
+
* - a CI config presence (.github/workflows / .gitlab-ci.yml / .circleci / …)
|
|
25
|
+
* - (Node projects only) a package.json `license` field
|
|
26
|
+
* - (Node projects only) a package.json `repository` field
|
|
27
|
+
*
|
|
28
|
+
* Pure FS reads, bounded (fixed check list + one shallow package.json read; no
|
|
29
|
+
* deep traversal), NEVER mutates, NEVER throws (returns [] on failure).
|
|
30
|
+
*
|
|
31
|
+
* Mirrors the read-only presence/size heuristics in
|
|
32
|
+
* portfolio/scanners.ts#scanDocs / #scanTests. Enrollment-scoping is the
|
|
33
|
+
* caller's responsibility (health.ts).
|
|
34
|
+
*/
|
|
35
|
+
export declare function probeConventions(repo: string): ConventionFinding[];
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* conventions.ts — Read-only PROJECT-STANDARDS probes for a single repo (M27).
|
|
3
|
+
*
|
|
4
|
+
* GUARDRAILS (enforced throughout this file):
|
|
5
|
+
* - READ-ONLY: pure FS reads (existsSync / statSync / readFileSync). NO writes,
|
|
6
|
+
* NO git mutations, NO installs, NO shell. NEVER mutates a user repo working tree.
|
|
7
|
+
* - Bounded: a fixed, small set of top-level presence checks + a shallow read of
|
|
8
|
+
* the root package.json; no deep tree traversal, no unbounded loops.
|
|
9
|
+
* - Never throws: returns [] on any error so callers (health.ts) stay unblocked.
|
|
10
|
+
* - No secrets: emitted ConventionFinding values are presence/label metadata only.
|
|
11
|
+
* - Enrollment-scoping is the CALLER's responsibility (health.ts) — this module
|
|
12
|
+
* is a pure probe over whatever absolute path it is handed.
|
|
13
|
+
*/
|
|
14
|
+
import { existsSync, statSync, readFileSync } from 'node:fs';
|
|
15
|
+
import { join } from 'node:path';
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// Bounds / weights
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
/** Minimum README size (bytes) below which it is considered "thin". */
|
|
20
|
+
const THIN_README_BYTES = 300;
|
|
21
|
+
/** Fixed candidate name sets (no deep traversal — top-level presence only). */
|
|
22
|
+
const README_NAMES = ['README.md', 'README.txt', 'README', 'readme.md', 'Readme.md'];
|
|
23
|
+
const LICENSE_NAMES = ['LICENSE', 'LICENSE.md', 'LICENSE.txt', 'LICENCE', 'LICENCE.md', 'COPYING'];
|
|
24
|
+
const LOCKFILE_NAMES = [
|
|
25
|
+
'package-lock.json',
|
|
26
|
+
'yarn.lock',
|
|
27
|
+
'pnpm-lock.yaml',
|
|
28
|
+
'bun.lockb',
|
|
29
|
+
'Cargo.lock',
|
|
30
|
+
'poetry.lock',
|
|
31
|
+
'Pipfile.lock',
|
|
32
|
+
'go.sum',
|
|
33
|
+
'composer.lock',
|
|
34
|
+
'Gemfile.lock',
|
|
35
|
+
];
|
|
36
|
+
const TEST_DIR_NAMES = ['test', 'tests', '__tests__', 'spec'];
|
|
37
|
+
const CI_PATHS = ['.github/workflows', '.gitlab-ci.yml', '.circleci', 'azure-pipelines.yml', '.travis.yml'];
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// Helpers
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
/** True when ANY of `names` exists directly under `dir`. Never throws. */
|
|
42
|
+
function anyExists(dir, names) {
|
|
43
|
+
for (const name of names) {
|
|
44
|
+
try {
|
|
45
|
+
if (existsSync(join(dir, name)))
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
// ignore — treat as absent
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
/** Byte size of the first existing file in `names` under `dir`, else 0. */
|
|
55
|
+
function firstSize(dir, names) {
|
|
56
|
+
for (const name of names) {
|
|
57
|
+
const p = join(dir, name);
|
|
58
|
+
try {
|
|
59
|
+
if (existsSync(p))
|
|
60
|
+
return statSync(p).size;
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return 0;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return 0;
|
|
67
|
+
}
|
|
68
|
+
/** True when `name` exists directly under `dir` AND is a directory. Never throws. */
|
|
69
|
+
function dirExists(dir, name) {
|
|
70
|
+
try {
|
|
71
|
+
const p = join(dir, name);
|
|
72
|
+
return existsSync(p) && statSync(p).isDirectory();
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Shallow read of a repo's top-level package.json. Returns null when absent or
|
|
80
|
+
* malformed. Read-only; never throws.
|
|
81
|
+
*/
|
|
82
|
+
function readPackageJson(repo) {
|
|
83
|
+
const p = join(repo, 'package.json');
|
|
84
|
+
try {
|
|
85
|
+
if (!existsSync(p))
|
|
86
|
+
return null;
|
|
87
|
+
const raw = readFileSync(p, 'utf8');
|
|
88
|
+
const parsed = JSON.parse(raw);
|
|
89
|
+
if (typeof parsed === 'object' && parsed !== null && !Array.isArray(parsed)) {
|
|
90
|
+
return parsed;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// malformed — treat as absent
|
|
95
|
+
}
|
|
96
|
+
return null;
|
|
97
|
+
}
|
|
98
|
+
/** True when `pkg` has a non-empty "test" script. */
|
|
99
|
+
function hasTestScript(pkg) {
|
|
100
|
+
if (pkg === null)
|
|
101
|
+
return false;
|
|
102
|
+
const scripts = pkg['scripts'];
|
|
103
|
+
if (scripts === null || typeof scripts !== 'object' || Array.isArray(scripts))
|
|
104
|
+
return false;
|
|
105
|
+
const test = scripts['test'];
|
|
106
|
+
return typeof test === 'string' && test.trim() !== '';
|
|
107
|
+
}
|
|
108
|
+
/** True when `pkg` carries a non-empty string field at `key`. */
|
|
109
|
+
function hasStringField(pkg, key) {
|
|
110
|
+
const v = pkg[key];
|
|
111
|
+
return typeof v === 'string' && v.trim() !== '';
|
|
112
|
+
}
|
|
113
|
+
/** True when `pkg` carries a `repository` field (string or object form). */
|
|
114
|
+
function hasRepositoryField(pkg) {
|
|
115
|
+
const v = pkg['repository'];
|
|
116
|
+
if (typeof v === 'string')
|
|
117
|
+
return v.trim() !== '';
|
|
118
|
+
if (typeof v === 'object' && v !== null && !Array.isArray(v)) {
|
|
119
|
+
const url = v['url'];
|
|
120
|
+
return typeof url === 'string' && url.trim() !== '';
|
|
121
|
+
}
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
// probeConventions — the single public entry point
|
|
126
|
+
// ---------------------------------------------------------------------------
|
|
127
|
+
/**
|
|
128
|
+
* Probe `repo` (an absolute path) for project-standard conventions.
|
|
129
|
+
*
|
|
130
|
+
* Returns a deterministic, ordered ConventionFinding[] covering:
|
|
131
|
+
* - README presence + thinness (< THIN_README_BYTES bytes)
|
|
132
|
+
* - LICENSE presence
|
|
133
|
+
* - lockfile presence (package-lock.json / yarn.lock / pnpm-lock.yaml / bun.lockb / Cargo.lock / …)
|
|
134
|
+
* - .gitignore presence
|
|
135
|
+
* - a test signal (test|tests|__tests__|spec dir, or a package.json "test" script)
|
|
136
|
+
* - a CI config presence (.github/workflows / .gitlab-ci.yml / .circleci / …)
|
|
137
|
+
* - (Node projects only) a package.json `license` field
|
|
138
|
+
* - (Node projects only) a package.json `repository` field
|
|
139
|
+
*
|
|
140
|
+
* Pure FS reads, bounded (fixed check list + one shallow package.json read; no
|
|
141
|
+
* deep traversal), NEVER mutates, NEVER throws (returns [] on failure).
|
|
142
|
+
*
|
|
143
|
+
* Mirrors the read-only presence/size heuristics in
|
|
144
|
+
* portfolio/scanners.ts#scanDocs / #scanTests. Enrollment-scoping is the
|
|
145
|
+
* caller's responsibility (health.ts).
|
|
146
|
+
*/
|
|
147
|
+
export function probeConventions(repo) {
|
|
148
|
+
try {
|
|
149
|
+
const findings = [];
|
|
150
|
+
const pkg = readPackageJson(repo);
|
|
151
|
+
// 1. README presence + thinness ----------------------------------------
|
|
152
|
+
const hasReadme = anyExists(repo, README_NAMES);
|
|
153
|
+
if (!hasReadme) {
|
|
154
|
+
findings.push({
|
|
155
|
+
key: 'readme',
|
|
156
|
+
label: 'README',
|
|
157
|
+
ok: false,
|
|
158
|
+
weight: 3,
|
|
159
|
+
detail: 'No README file found at the repo root.',
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
else {
|
|
163
|
+
const size = firstSize(repo, README_NAMES);
|
|
164
|
+
const thin = size < THIN_README_BYTES;
|
|
165
|
+
findings.push({
|
|
166
|
+
key: 'readme',
|
|
167
|
+
label: 'README',
|
|
168
|
+
ok: !thin,
|
|
169
|
+
weight: 2,
|
|
170
|
+
detail: thin
|
|
171
|
+
? `README is only ${size} bytes (< ${THIN_README_BYTES}); consider expanding usage/setup.`
|
|
172
|
+
: `README present (${size} bytes).`,
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
// 2. LICENSE file presence ---------------------------------------------
|
|
176
|
+
const hasLicenseFile = anyExists(repo, LICENSE_NAMES);
|
|
177
|
+
findings.push({
|
|
178
|
+
key: 'license',
|
|
179
|
+
label: 'LICENSE file',
|
|
180
|
+
ok: hasLicenseFile,
|
|
181
|
+
weight: 3,
|
|
182
|
+
detail: hasLicenseFile
|
|
183
|
+
? 'LICENSE file present at the repo root.'
|
|
184
|
+
: 'No LICENSE file found at the repo root.',
|
|
185
|
+
});
|
|
186
|
+
// 3. lockfile presence --------------------------------------------------
|
|
187
|
+
const hasLockfile = anyExists(repo, LOCKFILE_NAMES);
|
|
188
|
+
findings.push({
|
|
189
|
+
key: 'lockfile',
|
|
190
|
+
label: 'Dependency lockfile',
|
|
191
|
+
ok: hasLockfile,
|
|
192
|
+
weight: 3,
|
|
193
|
+
detail: hasLockfile
|
|
194
|
+
? 'A dependency lockfile is present (reproducible installs).'
|
|
195
|
+
: 'No lockfile found (package-lock.json / yarn.lock / pnpm-lock.yaml / Cargo.lock / …).',
|
|
196
|
+
});
|
|
197
|
+
// 4. .gitignore presence ------------------------------------------------
|
|
198
|
+
const hasGitignore = anyExists(repo, ['.gitignore']);
|
|
199
|
+
findings.push({
|
|
200
|
+
key: 'gitignore',
|
|
201
|
+
label: '.gitignore',
|
|
202
|
+
ok: hasGitignore,
|
|
203
|
+
weight: 2,
|
|
204
|
+
detail: hasGitignore
|
|
205
|
+
? '.gitignore present at the repo root.'
|
|
206
|
+
: 'No .gitignore found at the repo root.',
|
|
207
|
+
});
|
|
208
|
+
// 5. test signal: a test dir OR a package.json "test" script -----------
|
|
209
|
+
const hasTestDir = TEST_DIR_NAMES.some(name => dirExists(repo, name));
|
|
210
|
+
const testScript = hasTestScript(pkg);
|
|
211
|
+
const hasTests = hasTestDir || testScript;
|
|
212
|
+
findings.push({
|
|
213
|
+
key: 'testdir',
|
|
214
|
+
label: 'Test suite signal',
|
|
215
|
+
ok: hasTests,
|
|
216
|
+
weight: 4,
|
|
217
|
+
detail: hasTests
|
|
218
|
+
? testScript
|
|
219
|
+
? 'package.json defines a "test" script.'
|
|
220
|
+
: 'A test directory (test/tests/__tests__/spec) is present.'
|
|
221
|
+
: 'No test directory or package.json "test" script found.',
|
|
222
|
+
});
|
|
223
|
+
// 6. CI config presence -------------------------------------------------
|
|
224
|
+
// .github/workflows is a directory; the rest are files — anyExists covers both.
|
|
225
|
+
const hasCi = anyExists(repo, CI_PATHS);
|
|
226
|
+
findings.push({
|
|
227
|
+
key: 'ci',
|
|
228
|
+
label: 'CI configuration',
|
|
229
|
+
ok: hasCi,
|
|
230
|
+
weight: 3,
|
|
231
|
+
detail: hasCi
|
|
232
|
+
? 'A CI config is present (.github/workflows / .gitlab-ci.yml / …).'
|
|
233
|
+
: 'No CI config found (.github/workflows / .gitlab-ci.yml / .circleci / …).',
|
|
234
|
+
});
|
|
235
|
+
// 7 & 8. package.json metadata fields (Node projects only) -------------
|
|
236
|
+
// Only probed when a parseable package.json exists, so non-Node repos are
|
|
237
|
+
// not penalized for missing npm-specific metadata.
|
|
238
|
+
if (pkg !== null) {
|
|
239
|
+
const hasLicenseField = hasStringField(pkg, 'license');
|
|
240
|
+
findings.push({
|
|
241
|
+
key: 'pkg-license',
|
|
242
|
+
label: 'package.json license field',
|
|
243
|
+
ok: hasLicenseField,
|
|
244
|
+
weight: 2,
|
|
245
|
+
detail: hasLicenseField
|
|
246
|
+
? 'package.json declares a "license" field.'
|
|
247
|
+
: 'package.json has no "license" field.',
|
|
248
|
+
});
|
|
249
|
+
const hasRepo = hasRepositoryField(pkg);
|
|
250
|
+
findings.push({
|
|
251
|
+
key: 'pkg-repository',
|
|
252
|
+
label: 'package.json repository field',
|
|
253
|
+
ok: hasRepo,
|
|
254
|
+
weight: 1,
|
|
255
|
+
detail: hasRepo
|
|
256
|
+
? 'package.json declares a "repository" field.'
|
|
257
|
+
: 'package.json has no "repository" field.',
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
return findings;
|
|
261
|
+
}
|
|
262
|
+
catch {
|
|
263
|
+
// Any unexpected failure — stay unblocked, report nothing.
|
|
264
|
+
return [];
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
//# sourceMappingURL=conventions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conventions.js","sourceRoot":"","sources":["../../../src/core/quality/conventions.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* fixes.ts — Deterministic advisory SAFE FIXES + PROPOSAL emission (M27).
|
|
3
|
+
*
|
|
4
|
+
* HARD SAFETY INVARIANTS (enforced throughout this file):
|
|
5
|
+
* - PROPOSAL-ONLY: emitFixProposals routes each SafeFix to the M23 Approval
|
|
6
|
+
* Inbox via createProposal() as a PENDING proposal (status 'pending', NEVER
|
|
7
|
+
* auto-advanced/applied). The default proposal kind is 'note' (advisory, no
|
|
8
|
+
* diff), origin 'manual'.
|
|
9
|
+
* - READ-ONLY / NO MUTATION: deriveSafeFixes is a pure function of a
|
|
10
|
+
* HealthScore. NEITHER function writes to a user repo, writes CONFIG, pushes,
|
|
11
|
+
* opens a PR, or deploys. There is NO apply path here.
|
|
12
|
+
* - OPTIONAL SANDBOX-PATCH (STRETCH, documented only): if a deterministic fix
|
|
13
|
+
* diff is ever generated, it MUST be produced in an M21 sandbox worktree
|
|
14
|
+
* (src/core/sandbox/*) and attached to a PENDING 'patch' proposal — NEVER
|
|
15
|
+
* written to the real tree, NEVER pushed. The DEFAULT is advisory 'note's.
|
|
16
|
+
* - Bounded: caps fixes emitted per run. Never throws (createProposal best-effort).
|
|
17
|
+
* - No secrets: SafeFix / proposal fields are advisory metadata only.
|
|
18
|
+
*/
|
|
19
|
+
import type { HealthScore, Proposal, SafeFix } from '../types.js';
|
|
20
|
+
/**
|
|
21
|
+
* Derive deterministic, advisory SafeFix[] from a per-repo HealthScore.
|
|
22
|
+
*
|
|
23
|
+
* Walks the score's failed convention probes (ok === false) and worst offenders,
|
|
24
|
+
* mapping each actionable, concretely-phraseable gap into an advisory SafeFix:
|
|
25
|
+
* - missing LICENSE -> { dimension:'docs', key:'docs.add-license' }
|
|
26
|
+
* - missing README -> { dimension:'docs', key:'docs.add-readme' }
|
|
27
|
+
* - missing .gitignore -> { dimension:'conventions', key:'conventions.add-gitignore' }
|
|
28
|
+
* - missing lockfile/CI -> { dimension:'conventions', key:'conventions.add-{lockfile,ci}' }
|
|
29
|
+
* - vulnerable/stale dep -> { dimension:'deps', key:'deps.upgrade:<pkg>' }
|
|
30
|
+
* - missing test -> { dimension:'tests', key:'tests.add-test[:…]' }
|
|
31
|
+
* - high TODO debt -> { dimension:'codeDebt', key:'codeDebt.resolve:…' }
|
|
32
|
+
*
|
|
33
|
+
* Pure function (no I/O), deterministic ordering, deduped by `key`, bounded to
|
|
34
|
+
* MAX_FIXES_PER_REPO. Every SafeFix defaults to proposalKind 'note' (advisory).
|
|
35
|
+
* NEVER mutates anything.
|
|
36
|
+
*/
|
|
37
|
+
export declare function deriveSafeFixes(score: HealthScore): SafeFix[];
|
|
38
|
+
/**
|
|
39
|
+
* Emit each SafeFix as a PENDING M23 Approval Inbox proposal.
|
|
40
|
+
*
|
|
41
|
+
* For each fix: createProposal({ repo, origin: 'manual', kind: 'note', title,
|
|
42
|
+
* summary }) — status is assigned 'pending' BY THE STORE and NEVER auto-advanced.
|
|
43
|
+
* Default kind is 'note' (advisory, no diff). M27 does NOT apply patches and does
|
|
44
|
+
* NOT mutate working trees here; this module advances no proposal status, pushes
|
|
45
|
+
* nothing, opens no PR, and deploys nothing — createProposal() is its ONLY effect.
|
|
46
|
+
*
|
|
47
|
+
* (STRETCH, NOT wired by default) A fix with proposalKind 'patch' would require
|
|
48
|
+
* generating its diff in an M21 sandbox worktree and attaching it as a PENDING
|
|
49
|
+
* 'patch' proposal with the sandboxId — never written to the real tree. This
|
|
50
|
+
* build emits NOTES ONLY; any 'patch'-kind SafeFix is downgraded to a 'note'
|
|
51
|
+
* proposal here (no diff is produced), keeping the inbox advisory.
|
|
52
|
+
*
|
|
53
|
+
* Returns the created Proposal[] (pending). Never throws (createProposal is
|
|
54
|
+
* best-effort and returns the in-memory proposal even on persistence failure).
|
|
55
|
+
*/
|
|
56
|
+
export declare function emitFixProposals(fixes: SafeFix[]): Proposal[];
|