@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,486 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* index-engine.ts
|
|
3
|
+
*
|
|
4
|
+
* Scans cfg.roots, builds an AshlrIndex of fully-populated IndexedItems,
|
|
5
|
+
* and persists / loads the index from ~/.ashlr/index.json.
|
|
6
|
+
*
|
|
7
|
+
* Walk strategy
|
|
8
|
+
* ─────────────
|
|
9
|
+
* Each entry in cfg.roots is one of:
|
|
10
|
+
* A) A github/<category> parent – walk category → repo (depth ≤ 3).
|
|
11
|
+
* B) A Desktop root – index top-level folders + notable loose
|
|
12
|
+
* files; do NOT descend into a dir already covered by a github root,
|
|
13
|
+
* and do NOT descend into node_modules / .git / dist.
|
|
14
|
+
*
|
|
15
|
+
* Symlinks are detected with lstat. They are indexed once as kind:'symlink'
|
|
16
|
+
* and are never followed for further repo discovery (avoids double-counting).
|
|
17
|
+
*
|
|
18
|
+
* One bad directory must never crash the whole walk – every stat/readdir call
|
|
19
|
+
* is wrapped in a try/catch and failures are silently skipped.
|
|
20
|
+
*/
|
|
21
|
+
import fs from 'node:fs';
|
|
22
|
+
import path from 'node:path';
|
|
23
|
+
import { INDEX_PATH, CONFIG_DIR } from './config.js';
|
|
24
|
+
import { categoryOf, describe, primaryLanguage, kindOf } from './classify.js';
|
|
25
|
+
import { isRepo, getGitStatus, getRemoteOrg } from './git.js';
|
|
26
|
+
// ─── constants ────────────────────────────────────────────────────────────────
|
|
27
|
+
/** Index format version – bump when the shape changes. */
|
|
28
|
+
const INDEX_VERSION = 1;
|
|
29
|
+
/** Directory names to never descend into during any walk. */
|
|
30
|
+
const SKIP_DIRS = new Set(['node_modules', '.git', 'dist', '.next', '.turbo', 'coverage', '__pycache__']);
|
|
31
|
+
/**
|
|
32
|
+
* Returns true for any Desktop top-level entry whose name starts with "."
|
|
33
|
+
* (hidden OS artefacts and tool-state dirs: .DS_Store, .vscode, .cursor,
|
|
34
|
+
* .claude, .ashlrcode, .downloads, .reorg-*, …). Skipping these prevents
|
|
35
|
+
* them from inflating the "(uncategorized)" bucket in `ashlr index`.
|
|
36
|
+
*/
|
|
37
|
+
function isDesktopDotfile(name) {
|
|
38
|
+
return name.startsWith('.');
|
|
39
|
+
}
|
|
40
|
+
// ─── helpers ──────────────────────────────────────────────────────────────────
|
|
41
|
+
/**
|
|
42
|
+
* Derive a stable, filesystem-friendly ID from an absolute path.
|
|
43
|
+
* Replace non-alphanumeric characters (except `-`) with `-` and
|
|
44
|
+
* collapse runs; strip leading/trailing `-`.
|
|
45
|
+
*/
|
|
46
|
+
function pathToId(absPath) {
|
|
47
|
+
return absPath
|
|
48
|
+
.replace(/^\//, '')
|
|
49
|
+
.replace(/[^a-zA-Z0-9]+/g, '-')
|
|
50
|
+
.replace(/^-+|-+$/g, '')
|
|
51
|
+
.toLowerCase();
|
|
52
|
+
}
|
|
53
|
+
/** Safe lstat — returns null on any error. */
|
|
54
|
+
function safeLstat(p) {
|
|
55
|
+
try {
|
|
56
|
+
return fs.lstatSync(p);
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/** Safe stat (follows symlinks) — returns null on any error. */
|
|
63
|
+
function safeStat(p) {
|
|
64
|
+
try {
|
|
65
|
+
return fs.statSync(p);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/** Safe readdir with file types — returns [] on any error. */
|
|
72
|
+
function safeReaddir(dir) {
|
|
73
|
+
try {
|
|
74
|
+
return fs.readdirSync(dir, { withFileTypes: true });
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/** Safe readlink — returns null on any error. */
|
|
81
|
+
function safeReadlink(p) {
|
|
82
|
+
try {
|
|
83
|
+
return fs.readlinkSync(p);
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Determine whether an item is "active" based on its last-modified ISO string
|
|
91
|
+
* and the configured staleDays threshold.
|
|
92
|
+
*/
|
|
93
|
+
function computeActive(lastModified, staleDays) {
|
|
94
|
+
const ms = Date.parse(lastModified);
|
|
95
|
+
if (Number.isNaN(ms))
|
|
96
|
+
return false;
|
|
97
|
+
return Date.now() - ms <= staleDays * 86_400_000;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Build a fully-populated IndexedItem for a single path.
|
|
101
|
+
*
|
|
102
|
+
* @param absPath Absolute path to the filesystem entry.
|
|
103
|
+
* @param cfg Current hub config.
|
|
104
|
+
* @param forcedKind When the caller has already determined the kind (e.g.
|
|
105
|
+
* symlinks detected before kindOf runs), pass it here.
|
|
106
|
+
*/
|
|
107
|
+
function buildItem(absPath, cfg, forcedKind) {
|
|
108
|
+
const lstat = safeLstat(absPath);
|
|
109
|
+
if (!lstat)
|
|
110
|
+
return null;
|
|
111
|
+
const isSymlink = lstat.isSymbolicLink();
|
|
112
|
+
const kind = forcedKind ?? kindOf(absPath);
|
|
113
|
+
// For the modification timestamp prefer the real target's mtime for
|
|
114
|
+
// symlinks so we don't always show the link creation time.
|
|
115
|
+
const statForTime = isSymlink ? (safeStat(absPath) ?? lstat) : lstat;
|
|
116
|
+
let lastModified = statForTime.mtime.toISOString();
|
|
117
|
+
// Link target (for symlinks)
|
|
118
|
+
const linkTarget = isSymlink
|
|
119
|
+
? (safeReadlink(absPath) ?? undefined)
|
|
120
|
+
: undefined;
|
|
121
|
+
// Git metadata (repos only)
|
|
122
|
+
let gitStatus = undefined;
|
|
123
|
+
let remote = null;
|
|
124
|
+
let org = null;
|
|
125
|
+
if (kind === 'repo') {
|
|
126
|
+
try {
|
|
127
|
+
gitStatus = getGitStatus(absPath) ?? undefined;
|
|
128
|
+
const remoteOrg = getRemoteOrg(absPath);
|
|
129
|
+
remote = remoteOrg.remote;
|
|
130
|
+
org = remoteOrg.org;
|
|
131
|
+
// Prefer git's last-commit timestamp over mtime when available.
|
|
132
|
+
if (gitStatus?.lastCommit) {
|
|
133
|
+
lastModified = gitStatus.lastCommit;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
// git unavailable or not a real repo — continue without git info
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
const active = computeActive(lastModified, cfg.staleDays);
|
|
141
|
+
const item = {
|
|
142
|
+
id: pathToId(absPath),
|
|
143
|
+
name: path.basename(absPath),
|
|
144
|
+
path: absPath,
|
|
145
|
+
kind,
|
|
146
|
+
category: categoryOf(absPath),
|
|
147
|
+
description: describe(absPath),
|
|
148
|
+
org,
|
|
149
|
+
remote,
|
|
150
|
+
language: kind === 'repo' ? primaryLanguage(absPath) : null,
|
|
151
|
+
lastModified,
|
|
152
|
+
active,
|
|
153
|
+
sizeBytes: lstat.isFile() ? lstat.size : undefined,
|
|
154
|
+
...(gitStatus !== undefined ? { git: gitStatus } : {}),
|
|
155
|
+
...(linkTarget !== undefined ? { linkTarget } : {}),
|
|
156
|
+
};
|
|
157
|
+
return item;
|
|
158
|
+
}
|
|
159
|
+
// ─── github walk ─────────────────────────────────────────────────────────────
|
|
160
|
+
/**
|
|
161
|
+
* Walk a single github/<category> root.
|
|
162
|
+
*
|
|
163
|
+
* Layout expected:
|
|
164
|
+
* <categoryRoot>/
|
|
165
|
+
* <repo>/ ← depth 1 repo
|
|
166
|
+
* <monorepo>/
|
|
167
|
+
* <nested-repo>/ ← depth 2 repo (e.g. artist-encyclopedias/factory)
|
|
168
|
+
*
|
|
169
|
+
* Symlinks at any depth are recorded as kind:'symlink' and NOT descended.
|
|
170
|
+
*/
|
|
171
|
+
function walkGithubCategory(categoryRoot, cfg, seenPaths, tryCachedRepo = () => null) {
|
|
172
|
+
const items = [];
|
|
173
|
+
for (const dirent of safeReaddir(categoryRoot)) {
|
|
174
|
+
const absPath = path.join(categoryRoot, dirent.name);
|
|
175
|
+
// Canonical/resolved path used for dedup (handles cases where two roots
|
|
176
|
+
// resolve to the same underlying directory).
|
|
177
|
+
let realPath;
|
|
178
|
+
try {
|
|
179
|
+
realPath = fs.realpathSync(absPath);
|
|
180
|
+
}
|
|
181
|
+
catch {
|
|
182
|
+
realPath = absPath;
|
|
183
|
+
}
|
|
184
|
+
if (seenPaths.has(realPath))
|
|
185
|
+
continue;
|
|
186
|
+
const lstat = safeLstat(absPath);
|
|
187
|
+
if (!lstat)
|
|
188
|
+
continue;
|
|
189
|
+
// ── Symlink ──
|
|
190
|
+
if (lstat.isSymbolicLink()) {
|
|
191
|
+
seenPaths.add(realPath);
|
|
192
|
+
const item = buildItem(absPath, cfg, 'symlink');
|
|
193
|
+
if (item)
|
|
194
|
+
items.push(item);
|
|
195
|
+
continue; // never follow symlinks for repo discovery
|
|
196
|
+
}
|
|
197
|
+
if (!lstat.isDirectory())
|
|
198
|
+
continue;
|
|
199
|
+
// ── Check depth-1 repo ──
|
|
200
|
+
if (isRepo(absPath)) {
|
|
201
|
+
seenPaths.add(realPath);
|
|
202
|
+
const item = tryCachedRepo(absPath) ?? buildItem(absPath, cfg, 'repo');
|
|
203
|
+
if (item)
|
|
204
|
+
items.push(item);
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
// ── Not a repo at depth-1: check for nested repos (depth 2) ──
|
|
208
|
+
// This handles monorepos like artist-encyclopedias/artist-encyclopedia-factory.
|
|
209
|
+
let foundNested = false;
|
|
210
|
+
for (const nested of safeReaddir(absPath)) {
|
|
211
|
+
if (SKIP_DIRS.has(nested.name))
|
|
212
|
+
continue;
|
|
213
|
+
const nestedPath = path.join(absPath, nested.name);
|
|
214
|
+
let nestedReal;
|
|
215
|
+
try {
|
|
216
|
+
nestedReal = fs.realpathSync(nestedPath);
|
|
217
|
+
}
|
|
218
|
+
catch {
|
|
219
|
+
nestedReal = nestedPath;
|
|
220
|
+
}
|
|
221
|
+
if (seenPaths.has(nestedReal))
|
|
222
|
+
continue;
|
|
223
|
+
const nestedLstat = safeLstat(nestedPath);
|
|
224
|
+
if (!nestedLstat)
|
|
225
|
+
continue;
|
|
226
|
+
if (nestedLstat.isSymbolicLink()) {
|
|
227
|
+
seenPaths.add(nestedReal);
|
|
228
|
+
const item = buildItem(nestedPath, cfg, 'symlink');
|
|
229
|
+
if (item)
|
|
230
|
+
items.push(item);
|
|
231
|
+
foundNested = true;
|
|
232
|
+
continue;
|
|
233
|
+
}
|
|
234
|
+
if (!nestedLstat.isDirectory())
|
|
235
|
+
continue;
|
|
236
|
+
if (isRepo(nestedPath)) {
|
|
237
|
+
seenPaths.add(nestedReal);
|
|
238
|
+
foundNested = true;
|
|
239
|
+
const item = tryCachedRepo(nestedPath) ?? buildItem(nestedPath, cfg, 'repo');
|
|
240
|
+
if (item)
|
|
241
|
+
items.push(item);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
// If we found nested repos, also index the parent dir as a doc-folder
|
|
245
|
+
// (it's a grouping container, not a repo itself).
|
|
246
|
+
if (foundNested) {
|
|
247
|
+
seenPaths.add(realPath);
|
|
248
|
+
const parentItem = buildItem(absPath, cfg, 'doc-folder');
|
|
249
|
+
if (parentItem)
|
|
250
|
+
items.push(parentItem);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
return items;
|
|
254
|
+
}
|
|
255
|
+
// ─── Desktop root walk ───────────────────────────────────────────────────────
|
|
256
|
+
/**
|
|
257
|
+
* Index the top-level entries of a Desktop root directory.
|
|
258
|
+
*
|
|
259
|
+
* Rules:
|
|
260
|
+
* - Skip anything already in seenPaths (already covered by github walk).
|
|
261
|
+
* - Skip SKIP_DIRS basenames.
|
|
262
|
+
* - Symlinks → kind:'symlink', do not follow.
|
|
263
|
+
* - Directories that are git repos → kind:'repo' (record but don't double-count).
|
|
264
|
+
* - Everything else → classify normally (doc-folder, doc, asset, other).
|
|
265
|
+
* - Do NOT recurse — only top-level entries.
|
|
266
|
+
*
|
|
267
|
+
* The github/ subdirectory itself is covered by the github walk; skip it here.
|
|
268
|
+
*/
|
|
269
|
+
function walkDesktopRoot(root, cfg, seenPaths, tryCachedRepo = () => null) {
|
|
270
|
+
const items = [];
|
|
271
|
+
for (const dirent of safeReaddir(root)) {
|
|
272
|
+
if (SKIP_DIRS.has(dirent.name))
|
|
273
|
+
continue;
|
|
274
|
+
// Skip dotfiles / hidden entries at the Desktop top-level (.DS_Store,
|
|
275
|
+
// .vscode, .claude, .ashlrcode, .downloads, .reorg-*, …).
|
|
276
|
+
if (isDesktopDotfile(dirent.name))
|
|
277
|
+
continue;
|
|
278
|
+
const absPath = path.join(root, dirent.name);
|
|
279
|
+
const lstat = safeLstat(absPath);
|
|
280
|
+
if (!lstat)
|
|
281
|
+
continue;
|
|
282
|
+
// ── Symlink ──
|
|
283
|
+
// Check symlinks BEFORE the realpath-based seenPaths guard. A top-level
|
|
284
|
+
// symlink (e.g. 'tts agents' -> github/side-projects/precious-grove)
|
|
285
|
+
// resolves to a repo path the github walk already added to seenPaths; if
|
|
286
|
+
// we deduped on the resolved realpath we'd drop the link entirely. Dedup
|
|
287
|
+
// symlinks by their OWN path so they are still emitted as kind:'symlink'.
|
|
288
|
+
if (lstat.isSymbolicLink()) {
|
|
289
|
+
if (seenPaths.has(absPath))
|
|
290
|
+
continue;
|
|
291
|
+
seenPaths.add(absPath);
|
|
292
|
+
const item = buildItem(absPath, cfg, 'symlink');
|
|
293
|
+
if (item)
|
|
294
|
+
items.push(item);
|
|
295
|
+
continue;
|
|
296
|
+
}
|
|
297
|
+
// Non-symlink: dedup by resolved realpath so a dir already covered by the
|
|
298
|
+
// github walk is not re-indexed.
|
|
299
|
+
let realPath;
|
|
300
|
+
try {
|
|
301
|
+
realPath = fs.realpathSync(absPath);
|
|
302
|
+
}
|
|
303
|
+
catch {
|
|
304
|
+
realPath = absPath;
|
|
305
|
+
}
|
|
306
|
+
if (seenPaths.has(realPath))
|
|
307
|
+
continue;
|
|
308
|
+
// ── Directory ──
|
|
309
|
+
if (lstat.isDirectory()) {
|
|
310
|
+
// Skip the github directory — it's covered by the dedicated github walk.
|
|
311
|
+
if (dirent.name === 'github') {
|
|
312
|
+
seenPaths.add(realPath);
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
seenPaths.add(realPath);
|
|
316
|
+
// Repos found at desktop top-level (unusual but possible).
|
|
317
|
+
const kind = isRepo(absPath) ? 'repo' : kindOf(absPath);
|
|
318
|
+
const item = (kind === 'repo' ? tryCachedRepo(absPath) : null) ??
|
|
319
|
+
buildItem(absPath, cfg, kind);
|
|
320
|
+
if (item)
|
|
321
|
+
items.push(item);
|
|
322
|
+
continue;
|
|
323
|
+
}
|
|
324
|
+
// ── Regular file ──
|
|
325
|
+
if (lstat.isFile()) {
|
|
326
|
+
seenPaths.add(realPath);
|
|
327
|
+
const item = buildItem(absPath, cfg, kindOf(absPath));
|
|
328
|
+
if (item)
|
|
329
|
+
items.push(item);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return items;
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Build a fresh (or incrementally updated) AshlrIndex by scanning all cfg.roots.
|
|
336
|
+
*
|
|
337
|
+
* Walk order:
|
|
338
|
+
* 1. Treat each root that ends in `/github/<category>` as a github category root.
|
|
339
|
+
* 2. Treat every remaining root as a "desktop" root (top-level only).
|
|
340
|
+
* 3. Track seenPaths (via realpath) across all roots to avoid double-counting.
|
|
341
|
+
*
|
|
342
|
+
* Incremental mode (opts.previousIndex present):
|
|
343
|
+
* For repos already in the previous index, compare the directory's current
|
|
344
|
+
* mtime against `previousIndex.generatedAt`. If the mtime is older (i.e.
|
|
345
|
+
* the directory has not been touched since the last index was built), reuse
|
|
346
|
+
* the prior IndexedItem directly — no stat/readdir/git calls needed.
|
|
347
|
+
* Any repo whose mtime is >= generatedAt (or that is new) is rebuilt normally.
|
|
348
|
+
*/
|
|
349
|
+
export function buildIndex(cfg, opts = {}) {
|
|
350
|
+
const seenPaths = new Set();
|
|
351
|
+
const allItems = [];
|
|
352
|
+
// ── Incremental cache ────────────────────────────────────────────────────
|
|
353
|
+
// Build a path→IndexedItem lookup from the previous index. Only used when
|
|
354
|
+
// previousIndex is supplied; otherwise the Map stays empty and every item
|
|
355
|
+
// is built from scratch (full rebuild).
|
|
356
|
+
const prevByPath = new Map();
|
|
357
|
+
const prevGeneratedMs = opts.previousIndex
|
|
358
|
+
? Date.parse(opts.previousIndex.generatedAt)
|
|
359
|
+
: NaN;
|
|
360
|
+
if (opts.previousIndex && !Number.isNaN(prevGeneratedMs)) {
|
|
361
|
+
for (const item of opts.previousIndex.items) {
|
|
362
|
+
prevByPath.set(item.path, item);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
/**
|
|
366
|
+
* Try to reuse a cached item for `absPath` (repos only).
|
|
367
|
+
*
|
|
368
|
+
* Returns the cached IndexedItem when:
|
|
369
|
+
* - the previousIndex was provided,
|
|
370
|
+
* - the item exists in the cache,
|
|
371
|
+
* - the item's kind is 'repo', AND
|
|
372
|
+
* - the directory's mtime < prevGeneratedMs (unchanged since last index).
|
|
373
|
+
*
|
|
374
|
+
* Returns null in all other cases, signalling that the item must be rebuilt.
|
|
375
|
+
*/
|
|
376
|
+
function tryCachedRepo(absPath) {
|
|
377
|
+
if (prevByPath.size === 0)
|
|
378
|
+
return null;
|
|
379
|
+
const cached = prevByPath.get(absPath);
|
|
380
|
+
if (!cached || cached.kind !== 'repo')
|
|
381
|
+
return null;
|
|
382
|
+
const lstat = safeLstat(absPath);
|
|
383
|
+
if (!lstat)
|
|
384
|
+
return null;
|
|
385
|
+
// mtime < prevGeneratedMs ⟹ directory unchanged since last build.
|
|
386
|
+
if (lstat.mtimeMs < prevGeneratedMs)
|
|
387
|
+
return cached;
|
|
388
|
+
return null;
|
|
389
|
+
}
|
|
390
|
+
// Partition roots into github-category roots vs desktop roots.
|
|
391
|
+
// A github-category root is any directory whose parent is named "github"
|
|
392
|
+
// OR that matches one of the category paths in cfg.categories.
|
|
393
|
+
const categoryPaths = new Set(Object.values(cfg.categories).map((p) => path.normalize(p)));
|
|
394
|
+
const githubRoots = [];
|
|
395
|
+
const desktopRoots = [];
|
|
396
|
+
for (const root of cfg.roots) {
|
|
397
|
+
const normalized = path.normalize(root);
|
|
398
|
+
const parentName = path.basename(path.dirname(normalized));
|
|
399
|
+
const baseName = path.basename(normalized);
|
|
400
|
+
if (categoryPaths.has(normalized) || parentName === 'github') {
|
|
401
|
+
// A category root itself (e.g. .../github/dev-tools).
|
|
402
|
+
githubRoots.push(root);
|
|
403
|
+
}
|
|
404
|
+
else if (baseName === 'github') {
|
|
405
|
+
// The github/ container root: each child directory is a category root
|
|
406
|
+
// (dev-tools, side-projects, …). Expand it into per-category github roots
|
|
407
|
+
// so walkGithubCategory descends to the actual repos.
|
|
408
|
+
for (const dirent of safeReaddir(normalized)) {
|
|
409
|
+
if (SKIP_DIRS.has(dirent.name))
|
|
410
|
+
continue;
|
|
411
|
+
const categoryRoot = path.join(normalized, dirent.name);
|
|
412
|
+
const lstat = safeLstat(categoryRoot);
|
|
413
|
+
if (!lstat)
|
|
414
|
+
continue;
|
|
415
|
+
// Don't follow symlinked category dirs; only real directories hold repos.
|
|
416
|
+
if (lstat.isDirectory() && !lstat.isSymbolicLink()) {
|
|
417
|
+
githubRoots.push(categoryRoot);
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
desktopRoots.push(root);
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
// Walk github category roots first so their realpath entries are in seenPaths
|
|
426
|
+
// before the desktop walk processes symlinks that point into github/.
|
|
427
|
+
for (const root of githubRoots) {
|
|
428
|
+
try {
|
|
429
|
+
const items = walkGithubCategory(root, cfg, seenPaths, tryCachedRepo);
|
|
430
|
+
allItems.push(...items);
|
|
431
|
+
}
|
|
432
|
+
catch {
|
|
433
|
+
// One bad root must not crash everything.
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
// Walk desktop roots (top-level only).
|
|
437
|
+
for (const root of desktopRoots) {
|
|
438
|
+
try {
|
|
439
|
+
const items = walkDesktopRoot(root, cfg, seenPaths, tryCachedRepo);
|
|
440
|
+
allItems.push(...items);
|
|
441
|
+
}
|
|
442
|
+
catch {
|
|
443
|
+
// One bad root must not crash everything.
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
// Primary root for the index metadata: first desktop root, falling back to
|
|
447
|
+
// the first root overall.
|
|
448
|
+
const primaryRoot = desktopRoots[0] ?? cfg.roots[0] ?? '';
|
|
449
|
+
return {
|
|
450
|
+
version: INDEX_VERSION,
|
|
451
|
+
generatedAt: new Date().toISOString(),
|
|
452
|
+
root: primaryRoot,
|
|
453
|
+
items: allItems,
|
|
454
|
+
};
|
|
455
|
+
}
|
|
456
|
+
/**
|
|
457
|
+
* Load the index from INDEX_PATH.
|
|
458
|
+
* Returns null if the file is absent, unreadable, or not valid JSON.
|
|
459
|
+
*/
|
|
460
|
+
export function loadIndex() {
|
|
461
|
+
try {
|
|
462
|
+
const raw = fs.readFileSync(INDEX_PATH, 'utf8');
|
|
463
|
+
const parsed = JSON.parse(raw);
|
|
464
|
+
// Minimal shape validation: must have version + items array.
|
|
465
|
+
if (typeof parsed !== 'object' ||
|
|
466
|
+
parsed === null ||
|
|
467
|
+
!('version' in parsed) ||
|
|
468
|
+
!('items' in parsed) ||
|
|
469
|
+
!Array.isArray(parsed.items)) {
|
|
470
|
+
return null;
|
|
471
|
+
}
|
|
472
|
+
return parsed;
|
|
473
|
+
}
|
|
474
|
+
catch {
|
|
475
|
+
return null;
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* Persist the index to INDEX_PATH as pretty-printed JSON.
|
|
480
|
+
* Creates CONFIG_DIR if it does not exist.
|
|
481
|
+
*/
|
|
482
|
+
export function writeIndex(index) {
|
|
483
|
+
fs.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
484
|
+
fs.writeFileSync(INDEX_PATH, JSON.stringify(index, null, 2), 'utf8');
|
|
485
|
+
}
|
|
486
|
+
//# sourceMappingURL=index-engine.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-engine.js","sourceRoot":"","sources":["../../src/core/index-engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* M32: desktop notifications — macOS only, opt-in, metadata only.
|
|
3
|
+
*
|
|
4
|
+
* Strict no-op unless BOTH hold: process.platform === 'darwin' AND
|
|
5
|
+
* cfg.notify.desktop === true (opt-in mirrors the webhook contract — when
|
|
6
|
+
* unset, nothing fires). Uses `osascript` via execFile (never a shell), with
|
|
7
|
+
* title/body escaped into the AppleScript string literal, a 2s timeout, and a
|
|
8
|
+
* never-throws contract.
|
|
9
|
+
*/
|
|
10
|
+
import type { AshlrConfig } from '../types.js';
|
|
11
|
+
/** True when desktop notifications are enabled by config + platform. */
|
|
12
|
+
export declare function desktopNotifyEnabled(cfg: AshlrConfig): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Show a desktop notification. Resolves true when osascript ran successfully,
|
|
15
|
+
* false otherwise (disabled / non-darwin / missing osascript / timeout).
|
|
16
|
+
* NEVER throws; NEVER blocks beyond the timeout.
|
|
17
|
+
*/
|
|
18
|
+
export declare function desktopNotify(title: string, body: string, cfg: AshlrConfig): Promise<boolean>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* M32: desktop notifications — macOS only, opt-in, metadata only.
|
|
3
|
+
*
|
|
4
|
+
* Strict no-op unless BOTH hold: process.platform === 'darwin' AND
|
|
5
|
+
* cfg.notify.desktop === true (opt-in mirrors the webhook contract — when
|
|
6
|
+
* unset, nothing fires). Uses `osascript` via execFile (never a shell), with
|
|
7
|
+
* title/body escaped into the AppleScript string literal, a 2s timeout, and a
|
|
8
|
+
* never-throws contract.
|
|
9
|
+
*/
|
|
10
|
+
import { execFile } from 'node:child_process';
|
|
11
|
+
const OSASCRIPT_TIMEOUT_MS = 2_000;
|
|
12
|
+
/** Escape a string for inclusion inside an AppleScript double-quoted literal. */
|
|
13
|
+
function escapeAppleScript(s) {
|
|
14
|
+
return s.replace(/\\/g, '\\\\').replace(/"/g, '\\"').replace(/\n/g, ' ');
|
|
15
|
+
}
|
|
16
|
+
/** True when desktop notifications are enabled by config + platform. */
|
|
17
|
+
export function desktopNotifyEnabled(cfg) {
|
|
18
|
+
if (process.platform !== 'darwin')
|
|
19
|
+
return false;
|
|
20
|
+
const notify = cfg.notify;
|
|
21
|
+
return notify?.desktop === true;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Show a desktop notification. Resolves true when osascript ran successfully,
|
|
25
|
+
* false otherwise (disabled / non-darwin / missing osascript / timeout).
|
|
26
|
+
* NEVER throws; NEVER blocks beyond the timeout.
|
|
27
|
+
*/
|
|
28
|
+
export function desktopNotify(title, body, cfg) {
|
|
29
|
+
if (!desktopNotifyEnabled(cfg))
|
|
30
|
+
return Promise.resolve(false);
|
|
31
|
+
const script = `display notification "${escapeAppleScript(body)}" ` +
|
|
32
|
+
`with title "${escapeAppleScript(title)}"`;
|
|
33
|
+
return new Promise((resolve) => {
|
|
34
|
+
try {
|
|
35
|
+
execFile('osascript', ['-e', script], { timeout: OSASCRIPT_TIMEOUT_MS }, (err) => resolve(!err));
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
resolve(false);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=desktop-notify.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"desktop-notify.js","sourceRoot":"","sources":["../../../src/core/integrations/desktop-notify.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAG9C,MAAM,oBAAoB,GAAG,KAAK,CAAC;AAEnC,iFAAiF;AACjF,SAAS,iBAAiB,CAAC,CAAS;IAClC,OAAO,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;AAC3E,CAAC;AAED,wEAAwE;AACxE,MAAM,UAAU,oBAAoB,CAAC,GAAgB;IACnD,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAChD,MAAM,MAAM,GAAI,GAA+C,CAAC,MAAM,CAAC;IACvE,OAAO,MAAM,EAAE,OAAO,KAAK,IAAI,CAAC;AAClC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa,EAAE,IAAY,EAAE,GAAgB;IACzE,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC;QAAE,OAAO,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IAE9D,MAAM,MAAM,GACV,yBAAyB,iBAAiB,CAAC,IAAI,CAAC,IAAI;QACpD,eAAe,iBAAiB,CAAC,KAAK,CAAC,GAAG,CAAC;IAE7C,OAAO,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,EAAE;QACtC,IAAI,CAAC;YACH,QAAQ,CACN,WAAW,EACX,CAAC,IAAI,EAAE,MAAM,CAAC,EACd,EAAE,OAAO,EAAE,oBAAoB,EAAE,EACjC,CAAC,GAAG,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,CACvB,CAAC;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* core/integrations/editors.ts — Editor MCP gateway wiring (M18).
|
|
3
|
+
*
|
|
4
|
+
* detectEditors(): detect which of claude / codex / cursor are present by
|
|
5
|
+
* their config directories or files.
|
|
6
|
+
*
|
|
7
|
+
* wireEditor(target, opts): wire the ashlr MCP gateway entry into one editor's
|
|
8
|
+
* mcpServers config, reusing the M3 install pattern (backup-first, deep-merge,
|
|
9
|
+
* idempotent, never clobbers existing servers). LOCAL only. `opts.configPath`
|
|
10
|
+
* overrides the default path so tests can run against TEMP files.
|
|
11
|
+
*
|
|
12
|
+
* SAFETY RULES (matching M3 contract):
|
|
13
|
+
* - Parse the config file FIRST; abort without writing on malformed JSON.
|
|
14
|
+
* - Backup (.bak) ONLY after a clean parse.
|
|
15
|
+
* - Idempotent: re-running when the entry is already present is a no-op.
|
|
16
|
+
* - Never clobber other mcpServers entries or other top-level config keys.
|
|
17
|
+
* - Never throws — all errors are caught and returned as {ok:false, detail}.
|
|
18
|
+
* - LOCAL only: writes only the target editor's config file.
|
|
19
|
+
*
|
|
20
|
+
* Genome note: ~/.ashlr already serves as the genome store; no extra wiring
|
|
21
|
+
* is needed here — the mcpServers entry is sufficient for the gateway.
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Detect which editors are installed on this machine by checking for the
|
|
25
|
+
* presence of their primary config directory or config file.
|
|
26
|
+
*
|
|
27
|
+
* Returns a subset of ['claude', 'codex', 'cursor'].
|
|
28
|
+
* Never throws.
|
|
29
|
+
*/
|
|
30
|
+
export declare function detectEditors(): string[];
|
|
31
|
+
/**
|
|
32
|
+
* Wire the ashlr MCP gateway into one editor's mcpServers config.
|
|
33
|
+
*
|
|
34
|
+
* Follows the M3 install pattern exactly:
|
|
35
|
+
* 1. Parse FIRST — abort without any write if config is malformed JSON.
|
|
36
|
+
* 2. Backup (.bak) after a clean parse, only if the file exists.
|
|
37
|
+
* 3. Idempotency — if the "ashlr" entry already matches, return ok without writing.
|
|
38
|
+
* 4. Deep-merge — spread existing config + mcpServers, add/update only "ashlr".
|
|
39
|
+
* 5. Write the merged result as pretty-printed JSON.
|
|
40
|
+
*
|
|
41
|
+
* @param target - Editor to wire: 'claude' | 'codex' | 'cursor'
|
|
42
|
+
* @param opts.configPath - Override the default config path (use a TEMP path in tests).
|
|
43
|
+
* @returns { ok: boolean; detail: string } — never throws.
|
|
44
|
+
*/
|
|
45
|
+
export declare function wireEditor(target: 'claude' | 'codex' | 'cursor', opts: {
|
|
46
|
+
configPath?: string;
|
|
47
|
+
}): Promise<{
|
|
48
|
+
ok: boolean;
|
|
49
|
+
detail: string;
|
|
50
|
+
}>;
|