ashlr-plugin 1.36.4
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/.agents/plugins/marketplace.json +20 -0
- package/.claude-plugin/marketplace.json +39 -0
- package/.claude-plugin/plugin.json +36 -0
- package/.codex/agents/README.md +9 -0
- package/.codex/agents/ashlr-explorer.md +36 -0
- package/.codex/agents/ashlr-worker.md +38 -0
- package/.codex-plugin/plugin.json +45 -0
- package/.mcp.json +14 -0
- package/LICENSE +21 -0
- package/README.md +311 -0
- package/agents/ashlr-code.md +69 -0
- package/agents/ashlr-explore.md +44 -0
- package/agents/ashlr-plan.md +54 -0
- package/bench/fixtures/notebook-large.ipynb +660 -0
- package/bench/fixtures/notebook-small.ipynb +39 -0
- package/bench/fixtures/tasklist-closed.json +62 -0
- package/bench/fixtures/tasklist-large-mixed.json +27 -0
- package/bench/fixtures/tasklist-sprint-open.json +79 -0
- package/bench/fixtures/websearch-bun-runtime.json +32 -0
- package/bench/fixtures/websearch-react-hooks-patterns.json +32 -0
- package/bench/fixtures/websearch-typescript-generics.json +38 -0
- package/bench/refs/node-sdk/.refrev +1 -0
- package/bench/refs/node-sdk/README.md +17 -0
- package/bench/refs/node-sdk/src/agent/agent.ts +163 -0
- package/bench/refs/node-sdk/src/agent/create-agent-ui-stream.ts +83 -0
- package/bench/refs/node-sdk/src/agent/tool-loop-agent.ts +238 -0
- package/bench/refs/node-sdk/src/embed/embed-many.ts +409 -0
- package/bench/refs/node-sdk/src/embed/embed-result.ts +50 -0
- package/bench/refs/node-sdk/src/embed/embed.ts +257 -0
- package/bench/refs/node-sdk/src/error/invalid-argument-error.ts +34 -0
- package/bench/refs/node-sdk/src/error/invalid-tool-input-error.ts +33 -0
- package/bench/refs/node-sdk/src/error/no-object-generated-error.ts +70 -0
- package/bench/refs/node-sdk/src/generate-image/generate-image-result.ts +42 -0
- package/bench/refs/node-sdk/src/generate-image/generate-image.ts +362 -0
- package/bench/refs/node-sdk/src/generate-object/generate-object-result.ts +67 -0
- package/bench/refs/node-sdk/src/generate-object/generate-object.ts +501 -0
- package/bench/refs/node-sdk/src/generate-object/inject-json-instruction.ts +30 -0
- package/bench/refs/node-sdk/src/generate-object/output-strategy.ts +415 -0
- package/bench/refs/node-sdk/src/generate-object/repair-text.ts +12 -0
- package/bench/refs/node-sdk/src/generate-object/stream-object.ts +960 -0
- package/bench/refs/node-sdk/src/generate-speech/generate-speech.ts +191 -0
- package/bench/refs/node-sdk/src/generate-text/generate-text.ts +1484 -0
- package/bench/refs/node-sdk/src/generate-text/stream-text.ts +2708 -0
- package/bench/refs/node-sdk/src/generate-text/tool-call.ts +59 -0
- package/bench/refs/node-sdk/src/generate-text/tool-result.ts +36 -0
- package/bench/refs/node-sdk/src/telemetry/create-telemetry-dispatcher.ts +146 -0
- package/bench/refs/node-sdk/src/telemetry/telemetry-registry.ts +15 -0
- package/bench/refs/node-sdk/src/telemetry/telemetry.ts +223 -0
- package/bench/refs/node-sdk/src/util/async-iterable-stream.ts +94 -0
- package/bench/refs/node-sdk/src/util/consume-stream.ts +31 -0
- package/bench/refs/node-sdk/src/util/create-stitchable-stream.ts +112 -0
- package/bench/refs/node-sdk/src/util/download/download.ts +74 -0
- package/bench/refs/node-sdk/src/util/error-handler.ts +1 -0
- package/bench/refs/node-sdk/src/util/fix-json.ts +401 -0
- package/bench/refs/node-sdk/src/util/merge-objects.ts +79 -0
- package/bench/refs/python-lib/.refrev +1 -0
- package/bench/refs/python-lib/README.md +18 -0
- package/bench/refs/python-lib/pandas/core/_numba/executor.py +249 -0
- package/bench/refs/python-lib/pandas/core/_numba/extensions.py +586 -0
- package/bench/refs/python-lib/pandas/core/_numba/kernels/mean_.py +198 -0
- package/bench/refs/python-lib/pandas/core/_numba/kernels/min_max_.py +178 -0
- package/bench/refs/python-lib/pandas/core/_numba/kernels/sum_.py +255 -0
- package/bench/refs/python-lib/pandas/core/_numba/kernels/var_.py +251 -0
- package/bench/refs/python-lib/pandas/core/accessor.py +520 -0
- package/bench/refs/python-lib/pandas/core/api.py +138 -0
- package/bench/refs/python-lib/pandas/core/array_algos/masked_accumulations.py +97 -0
- package/bench/refs/python-lib/pandas/core/array_algos/masked_reductions.py +252 -0
- package/bench/refs/python-lib/pandas/core/array_algos/putmask.py +150 -0
- package/bench/refs/python-lib/pandas/core/array_algos/quantile.py +232 -0
- package/bench/refs/python-lib/pandas/core/array_algos/replace.py +159 -0
- package/bench/refs/python-lib/pandas/core/array_algos/take.py +609 -0
- package/bench/refs/python-lib/pandas/core/arraylike.py +534 -0
- package/bench/refs/python-lib/pandas/core/arrays/_arrow_string_mixins.py +434 -0
- package/bench/refs/python-lib/pandas/core/arrays/_mixins.py +630 -0
- package/bench/refs/python-lib/pandas/core/arrays/_ranges.py +276 -0
- package/bench/refs/python-lib/pandas/core/arrays/_utils.py +77 -0
- package/bench/refs/python-lib/pandas/core/arrays/arrow/accessors.py +521 -0
- package/bench/refs/python-lib/pandas/core/arrays/arrow/extension_types.py +174 -0
- package/bench/refs/python-lib/pandas/core/arrays/boolean.py +454 -0
- package/bench/refs/python-lib/pandas/core/arrays/floating.py +192 -0
- package/bench/refs/python-lib/pandas/core/arrays/integer.py +296 -0
- package/bench/refs/python-lib/pandas/core/arrays/masked.py +2140 -0
- package/bench/refs/python-lib/pandas/core/arrays/numeric.py +305 -0
- package/bench/refs/python-lib/pandas/core/arrays/numpy_.py +701 -0
- package/bench/refs/python-lib/pandas/core/arrays/period.py +1586 -0
- package/bench/refs/python-lib/pandas/core/arrays/sparse/accessor.py +505 -0
- package/bench/refs/python-lib/pandas/core/arrays/sparse/scipy_sparse.py +208 -0
- package/bench/refs/rust-project/.refrev +1 -0
- package/bench/refs/rust-project/README.md +17 -0
- package/bench/refs/rust-project/tokio/src/doc/os.rs +68 -0
- package/bench/refs/rust-project/tokio/src/fs/dir_builder.rs +129 -0
- package/bench/refs/rust-project/tokio/src/fs/file.rs +1113 -0
- package/bench/refs/rust-project/tokio/src/fs/mocks.rs +176 -0
- package/bench/refs/rust-project/tokio/src/fs/mod.rs +324 -0
- package/bench/refs/rust-project/tokio/src/fs/open_options.rs +856 -0
- package/bench/refs/rust-project/tokio/src/fs/read.rs +80 -0
- package/bench/refs/rust-project/tokio/src/fs/read_dir.rs +357 -0
- package/bench/refs/rust-project/tokio/src/fs/write.rs +99 -0
- package/bench/refs/rust-project/tokio/src/future/maybe_done.rs +123 -0
- package/bench/refs/rust-project/tokio/src/future/try_join.rs +82 -0
- package/bench/refs/rust-project/tokio/src/io/async_buf_read.rs +117 -0
- package/bench/refs/rust-project/tokio/src/io/async_read.rs +133 -0
- package/bench/refs/rust-project/tokio/src/io/async_seek.rs +96 -0
- package/bench/refs/rust-project/tokio/src/io/async_write.rs +402 -0
- package/bench/refs/rust-project/tokio/src/io/blocking.rs +339 -0
- package/bench/refs/rust-project/tokio/src/io/interest.rs +345 -0
- package/bench/refs/rust-project/tokio/src/io/join.rs +130 -0
- package/bench/refs/rust-project/tokio/src/io/mod.rs +308 -0
- package/bench/refs/rust-project/tokio/src/io/poll_evented.rs +319 -0
- package/bench/refs/rust-project/tokio/src/io/read_buf.rs +344 -0
- package/bench/refs/rust-project/tokio/src/io/ready.rs +322 -0
- package/bench/refs/rust-project/tokio/src/io/split.rs +166 -0
- package/bench/refs/rust-project/tokio/src/io/stderr.rs +148 -0
- package/bench/refs/rust-project/tokio/src/io/stdin.rs +98 -0
- package/bench/refs/rust-project/tokio/src/io/stdio_common.rs +222 -0
- package/bench/refs/rust-project/tokio/src/io/stdout.rs +197 -0
- package/bench/refs/rust-project/tokio/src/io/util/buf_reader.rs +311 -0
- package/bench/refs/rust-project/tokio/src/io/util/buf_stream.rs +207 -0
- package/bench/refs/rust-project/tokio/src/io/util/buf_writer.rs +310 -0
- package/bench/refs/rust-project/tokio/src/io/util/chain.rs +144 -0
- package/commands/_spawn-patterns.json +32 -0
- package/commands/ashlr-allow.md +21 -0
- package/commands/ashlr-benchmark.md +53 -0
- package/commands/ashlr-brief.md +97 -0
- package/commands/ashlr-budget.md +76 -0
- package/commands/ashlr-compact.md +54 -0
- package/commands/ashlr-dashboard.md +37 -0
- package/commands/ashlr-doctor.md +56 -0
- package/commands/ashlr-eco-mode.md +92 -0
- package/commands/ashlr-genome-init.md +24 -0
- package/commands/ashlr-genome-keygen.md +36 -0
- package/commands/ashlr-genome-loop.md +118 -0
- package/commands/ashlr-genome-push.md +36 -0
- package/commands/ashlr-genome-rewrap.md +48 -0
- package/commands/ashlr-genome-team-init.md +67 -0
- package/commands/ashlr-handoff.md +23 -0
- package/commands/ashlr-help.md +86 -0
- package/commands/ashlr-hook-timings.md +30 -0
- package/commands/ashlr-leaderboard.md +50 -0
- package/commands/ashlr-ollama-setup.md +39 -0
- package/commands/ashlr-orchestrate-status.md +72 -0
- package/commands/ashlr-orchestrate.md +83 -0
- package/commands/ashlr-parallelize.md +63 -0
- package/commands/ashlr-report-crash.md +33 -0
- package/commands/ashlr-resume.md +72 -0
- package/commands/ashlr-savings.md +24 -0
- package/commands/ashlr-settings.md +50 -0
- package/commands/ashlr-spawn.md +61 -0
- package/commands/ashlr-start.md +60 -0
- package/commands/ashlr-status.md +64 -0
- package/commands/ashlr-team-invite.md +47 -0
- package/commands/ashlr-tier.md +122 -0
- package/commands/ashlr-tour.md +60 -0
- package/commands/ashlr-update.md +155 -0
- package/commands/ashlr-upgrade.md +96 -0
- package/commands/goal.md +58 -0
- package/commands/loop.md +40 -0
- package/docs/CNAME +1 -0
- package/docs/PRO_TIER.md +104 -0
- package/docs/README.md +21 -0
- package/docs/architecture.md +415 -0
- package/docs/ashlr-pipe.md +161 -0
- package/docs/assets/logo.svg +19 -0
- package/docs/assets/og.png +0 -0
- package/docs/assets/og.svg +41 -0
- package/docs/benchmarks-v2.json +355 -0
- package/docs/benchmarks.json +102 -0
- package/docs/benchmarks.md +211 -0
- package/docs/billing.md +185 -0
- package/docs/cloud-genome.md +155 -0
- package/docs/competitive-wozcode.md +92 -0
- package/docs/deploy.md +325 -0
- package/docs/email-templates.md +113 -0
- package/docs/embed-tuning.md +103 -0
- package/docs/genome.md +120 -0
- package/docs/github-oauth-onboarding.md +127 -0
- package/docs/hero-video-script.md +129 -0
- package/docs/index.html +2262 -0
- package/docs/install-prompt.md +78 -0
- package/docs/install-windows.md +132 -0
- package/docs/install.ps1 +171 -0
- package/docs/install.sh +146 -0
- package/docs/launch/README.md +114 -0
- package/docs/launch/hn.md +49 -0
- package/docs/launch/reddit.md +45 -0
- package/docs/launch/x.md +65 -0
- package/docs/launch-post.md +112 -0
- package/docs/legal.md +78 -0
- package/docs/llm-providers.md +99 -0
- package/docs/multi-host-mcp.md +217 -0
- package/docs/multi-turn-architecture.md +108 -0
- package/docs/operations/deployment.md +108 -0
- package/docs/operations/error-monitoring.md +70 -0
- package/docs/operations/weekly-digest.md +70 -0
- package/docs/operations.md +494 -0
- package/docs/platform-support.md +133 -0
- package/docs/policy-packs.md +188 -0
- package/docs/press-kit/fact-sheet.md +78 -0
- package/docs/press-kit/founder-bio.md +3 -0
- package/docs/press-kit/logo.svg +33 -0
- package/docs/press-kit/screenshots.md +146 -0
- package/docs/pricing.md +251 -0
- package/docs/pro-backend-architecture.md +523 -0
- package/docs/producthunt.md +52 -0
- package/docs/router-migration.md +110 -0
- package/docs/session-log-schema.md +68 -0
- package/docs/social.md +95 -0
- package/docs/team-genome.md +528 -0
- package/docs/telemetry.md +194 -0
- package/docs/test-isolation.md +100 -0
- package/docs/upgrade.md +159 -0
- package/hooks/_hook-errors.ts +87 -0
- package/hooks/_hook-perf-emit.ts +113 -0
- package/hooks/_hook-timing-ledger.ts +1133 -0
- package/hooks/_nudge-throttle.ts +127 -0
- package/hooks/_recent-blocks.ts +127 -0
- package/hooks/audit-upload.ts +86 -0
- package/hooks/codex-hooks.json +171 -0
- package/hooks/commit-attribution.ts +179 -0
- package/hooks/edit-batching-nudge.ts +154 -0
- package/hooks/genome-scribe-hook.ts +219 -0
- package/hooks/hooks.json +294 -0
- package/hooks/orient-nudge-hook.ts +242 -0
- package/hooks/policy-enforce.ts +214 -0
- package/hooks/post-tool-use-embedding.ts +93 -0
- package/hooks/post-tool-use-genome.sh +37 -0
- package/hooks/post-tool-use-genome.ts +69 -0
- package/hooks/posttooluse-correlate.ts +122 -0
- package/hooks/posttooluse-dedupe-output.ts +241 -0
- package/hooks/posttooluse-genome-refresh.ts +223 -0
- package/hooks/posttooluse-native-nudge.ts +205 -0
- package/hooks/posttooluse-stale-result.ts +277 -0
- package/hooks/pretooluse-bash.ts +63 -0
- package/hooks/pretooluse-budget-guard.ts +318 -0
- package/hooks/pretooluse-common.ts +985 -0
- package/hooks/pretooluse-eco-router.ts +196 -0
- package/hooks/pretooluse-edit.sh +93 -0
- package/hooks/pretooluse-edit.ts +197 -0
- package/hooks/pretooluse-glob.ts +70 -0
- package/hooks/pretooluse-grep.sh +85 -0
- package/hooks/pretooluse-grep.ts +96 -0
- package/hooks/pretooluse-notebookedit.ts +121 -0
- package/hooks/pretooluse-read.sh +118 -0
- package/hooks/pretooluse-read.ts +118 -0
- package/hooks/pretooluse-task.ts +130 -0
- package/hooks/pretooluse-webfetch.ts +66 -0
- package/hooks/pretooluse-websearch.ts +85 -0
- package/hooks/pretooluse-write.ts +128 -0
- package/hooks/pulse-emit.ts +197 -0
- package/hooks/session-end-consolidate.sh +35 -0
- package/hooks/session-end-consolidate.ts +188 -0
- package/hooks/session-end-stats-gc.ts +80 -0
- package/hooks/session-log-append.sh +94 -0
- package/hooks/session-log-append.ts +116 -0
- package/hooks/session-start.ts +993 -0
- package/hooks/sessionend-hook-health-nudge.ts +451 -0
- package/hooks/sessionend-savings-nudge.ts +318 -0
- package/hooks/sessionend-status-line-nudge.ts +296 -0
- package/hooks/sessionstart-brief.ts +140 -0
- package/hooks/sessionstart-cost-refactor.ts +95 -0
- package/hooks/sessionstart-efficient.ts +110 -0
- package/hooks/sessionstart-genome-author.ts +93 -0
- package/hooks/sessionstart-lean-tools.ts +98 -0
- package/hooks/sessionstart-search.ts +97 -0
- package/hooks/stop-accounting.ts +152 -0
- package/hooks/subagent-stop-rollup.ts +162 -0
- package/hooks/userpromptsubmit-brief-trigger.ts +156 -0
- package/package.json +56 -0
- package/ports/README.md +108 -0
- package/ports/cursor/mcp.json +11 -0
- package/ports/goose/recipe.yaml +26 -0
- package/scripts/ashlr-mcp.ts +40 -0
- package/scripts/auto-update.ts +177 -0
- package/scripts/baseline-scan.ts +831 -0
- package/scripts/bench-orchestrate.ts +377 -0
- package/scripts/benchmark-refs.ts +292 -0
- package/scripts/bootstrap.mjs +100 -0
- package/scripts/brief-eval.ts +234 -0
- package/scripts/bump-version.ts +82 -0
- package/scripts/bun-resolve.d.mts +11 -0
- package/scripts/bun-resolve.mjs +59 -0
- package/scripts/calibrate-grep.ts +467 -0
- package/scripts/capture-grep-workload.ts +260 -0
- package/scripts/check-tier.ts +61 -0
- package/scripts/check-version-sync.ts +97 -0
- package/scripts/cli-orchestrate-status.ts +386 -0
- package/scripts/cli-orchestrate.ts +303 -0
- package/scripts/cli.ts +478 -0
- package/scripts/cloud-smoke-test.ts +313 -0
- package/scripts/coach-report.ts +373 -0
- package/scripts/context-db-migrate.ts +137 -0
- package/scripts/context-status.ts +43 -0
- package/scripts/demo-run.ts +255 -0
- package/scripts/deploy-smoke.sh +140 -0
- package/scripts/doctor.ts +992 -0
- package/scripts/embed-file-worker.ts +104 -0
- package/scripts/embed-tune.ts +308 -0
- package/scripts/errors-report.ts +428 -0
- package/scripts/find-test-leak.ts +69 -0
- package/scripts/generate-badge.ts +357 -0
- package/scripts/genome-auto-consolidate.ts +533 -0
- package/scripts/genome-auto-propose.ts +578 -0
- package/scripts/genome-cloud-pull.ts +363 -0
- package/scripts/genome-cloud-push.ts +382 -0
- package/scripts/genome-cloud-sync.ts +587 -0
- package/scripts/genome-commit-watcher.ts +295 -0
- package/scripts/genome-init.ts +986 -0
- package/scripts/genome-key.ts +233 -0
- package/scripts/genome-keygen.ts +168 -0
- package/scripts/genome-link.ts +59 -0
- package/scripts/genome-refresh-worker.ts +364 -0
- package/scripts/genome-rewrap.ts +90 -0
- package/scripts/genome-synthesizer.ts +679 -0
- package/scripts/genome-team-init.ts +312 -0
- package/scripts/handoff-pack.ts +438 -0
- package/scripts/hook-bootstrap.mjs +75 -0
- package/scripts/hook-timing-reader.ts +371 -0
- package/scripts/hook-timings-report.ts +554 -0
- package/scripts/install-genome-hooks.ts +196 -0
- package/scripts/install-onnx-model.ts +154 -0
- package/scripts/install-permissions.ts +276 -0
- package/scripts/install-status-line.ts +150 -0
- package/scripts/mcp-entrypoint.sh +78 -0
- package/scripts/mcp-entrypoint.ts +130 -0
- package/scripts/mdx-angle-bracket-lint.ts +152 -0
- package/scripts/measure-cold-start.ts +126 -0
- package/scripts/migrate-stats-to-sqlite.ts +86 -0
- package/scripts/ollama-setup.ts +498 -0
- package/scripts/onboarding-wizard.ts +1691 -0
- package/scripts/orchestrate-emit-telemetry.ts +177 -0
- package/scripts/orchestrate-expand.ts +517 -0
- package/scripts/orchestrate-run.ts +744 -0
- package/scripts/print-legend.ts +50 -0
- package/scripts/product-metadata.ts +38 -0
- package/scripts/prune-old-memories.ts +208 -0
- package/scripts/publish.sh +88 -0
- package/scripts/read-calibration.ts +122 -0
- package/scripts/report-crash.ts +226 -0
- package/scripts/run-benchmark.ts +750 -0
- package/scripts/run-root-tests.ts +28 -0
- package/scripts/savings-dashboard.ts +1258 -0
- package/scripts/savings-report-extras.ts +447 -0
- package/scripts/savings-status-line.ts +873 -0
- package/scripts/session-event-emit.ts +266 -0
- package/scripts/session-greet.ts +686 -0
- package/scripts/session-log-report.ts +551 -0
- package/scripts/session-resume.ts +614 -0
- package/scripts/set-hook-mode.ts +83 -0
- package/scripts/smoke-cross-platform.ts +117 -0
- package/scripts/smoke-realtime.ts +257 -0
- package/scripts/smoke-tools.ts +21 -0
- package/scripts/stats-cloud-pull.ts +213 -0
- package/scripts/stats-cloud-sync.ts +261 -0
- package/scripts/telemetry-flush.ts +160 -0
- package/scripts/telemetry-status.ts +266 -0
- package/scripts/timing-budget.ts +35 -0
- package/scripts/ui-animation.ts +120 -0
- package/scripts/ui.ts +431 -0
- package/scripts/upgrade-flow.ts +775 -0
- package/scripts/weekly-digest.ts +394 -0
- package/servers/_accounting.ts +78 -0
- package/servers/_ask-router.ts +84 -0
- package/servers/_ast-chunker.ts +434 -0
- package/servers/_ast-helpers.ts +183 -0
- package/servers/_ast-languages.ts +153 -0
- package/servers/_ast-refactor/_shared.ts +221 -0
- package/servers/_ast-refactor/cross-file-rename.ts +560 -0
- package/servers/_ast-refactor/extract-function.ts +357 -0
- package/servers/_ast-refactor/file-local-rename.ts +172 -0
- package/servers/_ast-refactor.ts +41 -0
- package/servers/_ast-skeleton.ts +107 -0
- package/servers/_bash-summarizers-registry.ts +1096 -0
- package/servers/_crash-dump.ts +210 -0
- package/servers/_cwd-clamp.ts +342 -0
- package/servers/_edit-log.ts +28 -0
- package/servers/_edit-match.ts +236 -0
- package/servers/_edit-validate.ts +196 -0
- package/servers/_embed-calibration.ts +123 -0
- package/servers/_embedding-cache.ts +401 -0
- package/servers/_embedding-model.ts +329 -0
- package/servers/_events.ts +113 -0
- package/servers/_genome-cache.ts +154 -0
- package/servers/_genome-commits.ts +172 -0
- package/servers/_genome-crypto-v2.ts +242 -0
- package/servers/_genome-crypto.ts +259 -0
- package/servers/_genome-discoveries.ts +140 -0
- package/servers/_genome-embed-populator.ts +216 -0
- package/servers/_genome-freshness.ts +134 -0
- package/servers/_genome-issues.ts +171 -0
- package/servers/_genome-live.ts +263 -0
- package/servers/_genome-prs.ts +188 -0
- package/servers/_genome-search.ts +479 -0
- package/servers/_genome-sync.ts +297 -0
- package/servers/_history-tracker.ts +279 -0
- package/servers/_http-helpers.ts +151 -0
- package/servers/_identity-hash.ts +151 -0
- package/servers/_llm-providers/anthropic.ts +132 -0
- package/servers/_llm-providers/cloud.ts +195 -0
- package/servers/_llm-providers/index.ts +350 -0
- package/servers/_llm-providers/local.ts +127 -0
- package/servers/_llm-providers/onnx.ts +393 -0
- package/servers/_llm-providers/types.ts +27 -0
- package/servers/_manifest-v2.ts +447 -0
- package/servers/_mcp-host.ts +93 -0
- package/servers/_nudge-events.ts +451 -0
- package/servers/_orchestrate-executor.ts +316 -0
- package/servers/_prefetch.ts +435 -0
- package/servers/_pricing.ts +256 -0
- package/servers/_pro.ts +381 -0
- package/servers/_read-cache.ts +44 -0
- package/servers/_router-handlers.ts +46 -0
- package/servers/_router.ts +55 -0
- package/servers/_run-with-timeout.ts +173 -0
- package/servers/_savings-render.ts +214 -0
- package/servers/_stats-sqlite.ts +640 -0
- package/servers/_stats.ts +1183 -0
- package/servers/_status-line-cells.ts +469 -0
- package/servers/_streaks.ts +162 -0
- package/servers/_summarize.ts +208 -0
- package/servers/_task-graph-render.ts +217 -0
- package/servers/_task-graph.ts +545 -0
- package/servers/_telemetry.ts +719 -0
- package/servers/_test-parsers.ts +530 -0
- package/servers/_test-watch.ts +626 -0
- package/servers/_text-helpers.ts +37 -0
- package/servers/_token-measure.ts +160 -0
- package/servers/_tool-base.ts +248 -0
- package/servers/_weekly-digest.ts +391 -0
- package/servers/ask-server-handlers.ts +49 -0
- package/servers/ask-server.ts +174 -0
- package/servers/bash-server-handlers.ts +138 -0
- package/servers/bash-server.ts +1136 -0
- package/servers/bench.ts +186 -0
- package/servers/diff-semantic-server-handlers.ts +39 -0
- package/servers/diff-semantic-server.ts +566 -0
- package/servers/diff-server-handlers.ts +317 -0
- package/servers/diff-server.ts +20 -0
- package/servers/edit-server-handlers.ts +31 -0
- package/servers/edit-server.ts +209 -0
- package/servers/edit-structural-server-handlers.ts +322 -0
- package/servers/efficiency-server-handlers.ts +161 -0
- package/servers/efficiency-server.ts +1135 -0
- package/servers/flush-server-handlers.ts +21 -0
- package/servers/flush-server.ts +19 -0
- package/servers/genome-server-handlers.ts +118 -0
- package/servers/genome-server.ts +397 -0
- package/servers/github-server-handlers.ts +187 -0
- package/servers/github-server.ts +856 -0
- package/servers/glob-server-handlers.ts +233 -0
- package/servers/glob-server.ts +20 -0
- package/servers/grep-server-handlers.ts +61 -0
- package/servers/grep-server.ts +564 -0
- package/servers/http-server-handlers.ts +36 -0
- package/servers/http-server.ts +149 -0
- package/servers/logs-server-handlers.ts +42 -0
- package/servers/logs-server.ts +359 -0
- package/servers/ls-server-handlers.ts +166 -0
- package/servers/ls-server.ts +20 -0
- package/servers/multi-edit-server-handlers.ts +51 -0
- package/servers/multi-edit-server.ts +422 -0
- package/servers/notebook-edit-server-handlers.ts +34 -0
- package/servers/notebook-edit-server.ts +181 -0
- package/servers/orient-server-handlers.ts +52 -0
- package/servers/orient-server.ts +436 -0
- package/servers/pipe-server-handlers.ts +68 -0
- package/servers/pipe-server.ts +300 -0
- package/servers/read-server-handlers.ts +42 -0
- package/servers/read-server.ts +206 -0
- package/servers/rename-file-server-handlers.ts +67 -0
- package/servers/rename-file-server.ts +699 -0
- package/servers/savings-server-handlers.ts +27 -0
- package/servers/savings-server.ts +54 -0
- package/servers/search-replace-regex-server-handlers.ts +96 -0
- package/servers/search-replace-regex-server.ts +751 -0
- package/servers/sql-server-handlers.ts +58 -0
- package/servers/sql-server.ts +505 -0
- package/servers/task-server-handlers.ts +358 -0
- package/servers/task-server.ts +24 -0
- package/servers/test-server-handlers.ts +351 -0
- package/servers/test-server.ts +20 -0
- package/servers/tree-server-handlers.ts +503 -0
- package/servers/tree-server.ts +20 -0
- package/servers/webfetch-server-handlers.ts +166 -0
- package/servers/webfetch-server.ts +20 -0
- package/servers/websearch-server-handlers.ts +215 -0
- package/servers/websearch-server.ts +19 -0
- package/servers/write-server-handlers.ts +27 -0
- package/servers/write-server.ts +97 -0
- package/skills/ashlr-brief/SKILL.md +80 -0
- package/skills/ashlr-codex-doctor/SKILL.md +21 -0
- package/skills/ashlr-codex-efficient-tools/SKILL.md +17 -0
- package/skills/ashlr-codex-genome-refresh/SKILL.md +20 -0
- package/skills/ashlr-codex-parallel-explore/SKILL.md +20 -0
- package/skills/ashlr-codex-savings/SKILL.md +17 -0
- package/skills/ashlr-cost-refactor/SKILL.md +50 -0
- package/skills/ashlr-efficient/SKILL.md +64 -0
- package/skills/ashlr-genome-author/SKILL.md +43 -0
- package/skills/ashlr-lean-tools/SKILL.md +43 -0
- package/skills/ashlr-search/SKILL.md +46 -0
|
@@ -0,0 +1,533 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* ashlr genome auto-consolidate — drains `.ashlrcode/genome/proposals.jsonl`
|
|
4
|
+
* into the genome section files it targets, and truncates the queue when
|
|
5
|
+
* done.
|
|
6
|
+
*
|
|
7
|
+
* Behavior:
|
|
8
|
+
* - Gate on ≥ 3 pending proposals. Fewer → no-op exit 0.
|
|
9
|
+
* - Group by section path, merge contents as bulleted append onto the
|
|
10
|
+
* existing section body (simple offline-deterministic fallback).
|
|
11
|
+
* - Log every run to `~/.ashlr/genome-consolidation.log`.
|
|
12
|
+
* - ASHLR_GENOME_AUTO=0 → silent exit 0.
|
|
13
|
+
*
|
|
14
|
+
* Usage:
|
|
15
|
+
* bun run scripts/genome-auto-consolidate.ts --dir <path>
|
|
16
|
+
*
|
|
17
|
+
* The `consolidateProposals` import exists in the import graph so the
|
|
18
|
+
* plugin's dependency on core-efficiency stays explicit; we invoke the
|
|
19
|
+
* deterministic fallback directly because core-efficiency's consolidator
|
|
20
|
+
* reads a different queue (`evolution/pending.jsonl`, owned by the MCP
|
|
21
|
+
* server). The fallback below is the "simple merge-as-bullets" path the
|
|
22
|
+
* spec allows when no LLMSummarizer is available.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import {
|
|
26
|
+
appendFileSync,
|
|
27
|
+
existsSync,
|
|
28
|
+
mkdirSync,
|
|
29
|
+
readFileSync,
|
|
30
|
+
writeFileSync,
|
|
31
|
+
} from "fs";
|
|
32
|
+
import { homedir } from "os";
|
|
33
|
+
import { dirname, join, resolve } from "path";
|
|
34
|
+
// Imported for API-surface parity with the MCP server; the auto-consolidator
|
|
35
|
+
// uses the direct-fallback path so it stays offline and deterministic.
|
|
36
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
37
|
+
import { consolidateProposals } from "@ashlr/core-efficiency/genome";
|
|
38
|
+
import { summarizeIfLarge as _summarizeIfLargeImpl, PROMPTS, type SummarizeResult, type SummarizeOpts } from "../servers/_summarize";
|
|
39
|
+
|
|
40
|
+
// Mutable hook container so tests can inject stubs:
|
|
41
|
+
// _hooks.summarizeIfLarge — controls LLM synthesis
|
|
42
|
+
// _hooks.isLlmReachable — controls reachability probe (stub to false in offline tests)
|
|
43
|
+
export const _hooks = {
|
|
44
|
+
summarizeIfLarge: _summarizeIfLargeImpl as (rawText: string, opts: SummarizeOpts) => Promise<SummarizeResult>,
|
|
45
|
+
isLlmReachable: isLlmReachable as () => Promise<boolean>,
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
// ---------------------------------------------------------------------------
|
|
50
|
+
// LLM reachability probe
|
|
51
|
+
// ---------------------------------------------------------------------------
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Check whether any configured LLM endpoint is reachable.
|
|
55
|
+
*
|
|
56
|
+
* Priority: ASHLR_LLM_URL > ANTHROPIC_API_KEY > OPENAI_API_KEY.
|
|
57
|
+
* Uses a 2-second AbortSignal timeout so a hung endpoint doesn't block
|
|
58
|
+
* consolidation. Returns false on any error (network, auth, DNS, etc.).
|
|
59
|
+
*
|
|
60
|
+
* Calling convention: this is called once per `applyFallback` invocation
|
|
61
|
+
* when `ASHLR_GENOME_LLM_SYNTHESIS` is not explicitly "0".
|
|
62
|
+
*/
|
|
63
|
+
async function isLlmReachable(): Promise<boolean> {
|
|
64
|
+
// Explicit override: ASHLR_LLM_URL takes priority
|
|
65
|
+
const llmUrl = process.env["ASHLR_LLM_URL"];
|
|
66
|
+
if (llmUrl) {
|
|
67
|
+
try {
|
|
68
|
+
const res = await fetch(llmUrl, {
|
|
69
|
+
method: "HEAD",
|
|
70
|
+
signal: AbortSignal.timeout(2_000),
|
|
71
|
+
});
|
|
72
|
+
return res.ok || res.status < 500;
|
|
73
|
+
} catch {
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
// ANTHROPIC_API_KEY — probe the models endpoint
|
|
78
|
+
if (process.env["ANTHROPIC_API_KEY"]) {
|
|
79
|
+
try {
|
|
80
|
+
const res = await fetch("https://api.anthropic.com/v1/models", {
|
|
81
|
+
method: "GET",
|
|
82
|
+
headers: { "x-api-key": process.env["ANTHROPIC_API_KEY"]!, "anthropic-version": "2023-06-01" },
|
|
83
|
+
signal: AbortSignal.timeout(2_000),
|
|
84
|
+
});
|
|
85
|
+
// 401/403 means the API is reachable (key may be invalid, but network is up)
|
|
86
|
+
return res.status < 500;
|
|
87
|
+
} catch {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
// OPENAI_API_KEY — probe the models endpoint
|
|
92
|
+
if (process.env["OPENAI_API_KEY"]) {
|
|
93
|
+
try {
|
|
94
|
+
const res = await fetch("https://api.openai.com/v1/models", {
|
|
95
|
+
method: "GET",
|
|
96
|
+
headers: { "Authorization": `Bearer ${process.env["OPENAI_API_KEY"]!}` },
|
|
97
|
+
signal: AbortSignal.timeout(2_000),
|
|
98
|
+
});
|
|
99
|
+
return res.status < 500;
|
|
100
|
+
} catch {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
interface Proposal {
|
|
108
|
+
id: string;
|
|
109
|
+
agentId: string;
|
|
110
|
+
section: string;
|
|
111
|
+
operation: "append" | "update" | "create";
|
|
112
|
+
content: string;
|
|
113
|
+
rationale: string;
|
|
114
|
+
timestamp: string;
|
|
115
|
+
generation: number;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
interface AshlrConfig {
|
|
119
|
+
genomeAuto?: boolean;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const LOG_PATH = join(homedir(), ".ashlr", "genome-consolidation.log");
|
|
123
|
+
|
|
124
|
+
// ---------------------------------------------------------------------------
|
|
125
|
+
// Args
|
|
126
|
+
// ---------------------------------------------------------------------------
|
|
127
|
+
|
|
128
|
+
export function parseArgs(argv: string[]): { dir?: string } {
|
|
129
|
+
let dir: string | undefined;
|
|
130
|
+
for (let i = 0; i < argv.length; i++) {
|
|
131
|
+
const a = argv[i];
|
|
132
|
+
if (a === "--dir" && argv[i + 1]) dir = argv[++i];
|
|
133
|
+
}
|
|
134
|
+
return { dir };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// ---------------------------------------------------------------------------
|
|
138
|
+
// Auto-disable check
|
|
139
|
+
// ---------------------------------------------------------------------------
|
|
140
|
+
|
|
141
|
+
function isAutoEnabled(): boolean {
|
|
142
|
+
if (process.env.ASHLR_GENOME_AUTO === "0") return false;
|
|
143
|
+
const cfgPath = join(homedir(), ".ashlr", "config.json");
|
|
144
|
+
if (existsSync(cfgPath)) {
|
|
145
|
+
try {
|
|
146
|
+
const cfg = JSON.parse(readFileSync(cfgPath, "utf-8")) as AshlrConfig;
|
|
147
|
+
if (cfg.genomeAuto === false) return false;
|
|
148
|
+
} catch {
|
|
149
|
+
/* ignore */
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return true;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// ---------------------------------------------------------------------------
|
|
156
|
+
// Proposal queue IO
|
|
157
|
+
// ---------------------------------------------------------------------------
|
|
158
|
+
|
|
159
|
+
function readProposals(path: string): Proposal[] {
|
|
160
|
+
if (!existsSync(path)) return [];
|
|
161
|
+
const raw = readFileSync(path, "utf-8");
|
|
162
|
+
const out: Proposal[] = [];
|
|
163
|
+
for (const line of raw.split("\n")) {
|
|
164
|
+
const t = line.trim();
|
|
165
|
+
if (!t) continue;
|
|
166
|
+
try {
|
|
167
|
+
const j = JSON.parse(t) as Proposal;
|
|
168
|
+
if (j && typeof j.section === "string" && typeof j.content === "string") {
|
|
169
|
+
out.push(j);
|
|
170
|
+
}
|
|
171
|
+
} catch {
|
|
172
|
+
/* skip malformed */
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return out;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
function sectionFilePath(genomeDir: string, section: string): string {
|
|
179
|
+
return join(genomeDir, section);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
function bulletize(content: string): string {
|
|
183
|
+
const flat = content.replace(/\s+/g, " ").trim();
|
|
184
|
+
// Keep bullets reasonable length; append-only.
|
|
185
|
+
return `- ${flat}`;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
/**
|
|
189
|
+
* Route target for a proposal aimed at `knowledge/discoveries.md`.
|
|
190
|
+
*
|
|
191
|
+
* discoveries.md is a curated human-readable file — the 2026-04-21 audit
|
|
192
|
+
* found it was 66% bigger than the previous month's audit threshold,
|
|
193
|
+
* dominated by raw JSON/diff blobs captured by the auto-propose hook.
|
|
194
|
+
*
|
|
195
|
+
* This classifier downgrades proposals that look like auto-observed noise
|
|
196
|
+
* (JSON-wrapped tool results, raw file listings, git diff hunks) to a
|
|
197
|
+
* sibling `discoveries-auto.md` sink which is not indexed in the manifest
|
|
198
|
+
* and therefore does not participate in retrieval.
|
|
199
|
+
*
|
|
200
|
+
* Heuristics are conservative: a proposal is routed to the sink only when
|
|
201
|
+
* it clearly matches a known noise shape. When in doubt, keep in the
|
|
202
|
+
* curated file.
|
|
203
|
+
*/
|
|
204
|
+
export function isNoiseProposal(content: string): boolean {
|
|
205
|
+
const flat = content.trim();
|
|
206
|
+
if (flat.length === 0) return false;
|
|
207
|
+
|
|
208
|
+
// JSON blob captured from a tool result — the dominant noise shape.
|
|
209
|
+
// Tool-result JSON typically starts with `{"stdout":`, `{"type":`,
|
|
210
|
+
// `{"filePath":`, `{"mode":`, `{"result":`, or similar.
|
|
211
|
+
if (/^\{["']?(stdout|stderr|type|filePath|mode|result|numFiles|file)["']?\s*:/.test(flat)) {
|
|
212
|
+
return true;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
// Raw file listings: many lines that all look like absolute paths.
|
|
216
|
+
// `.tsv`-ish output (e.g. from `ls`, `find`, or glob tool).
|
|
217
|
+
const lines = flat.split("\n").filter((l) => l.trim().length > 0);
|
|
218
|
+
if (lines.length >= 3) {
|
|
219
|
+
const pathish = lines.filter((l) => /^\/[\w./\-@]+$/.test(l.trim())).length;
|
|
220
|
+
if (pathish / lines.length >= 0.7) return true;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Unified-diff fragments captured from Bash output — lots of +/- lines or
|
|
224
|
+
// hunk headers.
|
|
225
|
+
const diffish = lines.filter((l) => /^(\+\+\+ |--- |@@ |diff --git|\+[^+]|-[^-])/.test(l)).length;
|
|
226
|
+
if (lines.length >= 5 && diffish / lines.length >= 0.6) return true;
|
|
227
|
+
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Section path a proposal should actually land in. Returns the proposal's
|
|
233
|
+
* declared section unless it targets `discoveries.md` and looks like auto
|
|
234
|
+
* noise — in which case it's rerouted to `discoveries-auto.md`.
|
|
235
|
+
*/
|
|
236
|
+
export function routeSectionForProposal(section: string, content: string): string {
|
|
237
|
+
if (section === "knowledge/discoveries.md" && isNoiseProposal(content)) {
|
|
238
|
+
return "knowledge/discoveries-auto.md";
|
|
239
|
+
}
|
|
240
|
+
return section;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
/**
|
|
244
|
+
* Jaccard similarity on the token sets of two strings. Used as a cheap
|
|
245
|
+
* novelty gate so we don't re-append bullets that duplicate existing
|
|
246
|
+
* section content. Stopwords-agnostic — relies on the length floor in
|
|
247
|
+
* `tokenize` to skip grammatical filler.
|
|
248
|
+
*/
|
|
249
|
+
function tokenize(text: string): Set<string> {
|
|
250
|
+
const tokens = new Set<string>();
|
|
251
|
+
for (const raw of text.toLowerCase().split(/[^a-z0-9_\-]+/)) {
|
|
252
|
+
if (raw.length < 4) continue;
|
|
253
|
+
tokens.add(raw);
|
|
254
|
+
}
|
|
255
|
+
return tokens;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
function jaccard(a: Set<string>, b: Set<string>): number {
|
|
259
|
+
if (a.size === 0 || b.size === 0) return 0;
|
|
260
|
+
let intersection = 0;
|
|
261
|
+
for (const token of a) if (b.has(token)) intersection++;
|
|
262
|
+
const union = a.size + b.size - intersection;
|
|
263
|
+
return union === 0 ? 0 : intersection / union;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Similarity threshold above which a proposed bullet is considered a
|
|
268
|
+
* duplicate of an existing line. 0.6 is deliberately conservative — high
|
|
269
|
+
* enough to catch near-identical auto-observations but low enough that
|
|
270
|
+
* proposals genuinely rephrasing prior knowledge still land.
|
|
271
|
+
*/
|
|
272
|
+
const DUPLICATE_JACCARD_THRESHOLD = 0.6;
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* Return existing section content split into non-empty trimmed lines —
|
|
276
|
+
* used as the baseline for the duplicate-bullet check below.
|
|
277
|
+
*/
|
|
278
|
+
function readExistingLines(path: string): string[] {
|
|
279
|
+
if (!existsSync(path)) return [];
|
|
280
|
+
try {
|
|
281
|
+
return readFileSync(path, "utf-8")
|
|
282
|
+
.split("\n")
|
|
283
|
+
.map((l) => l.trim())
|
|
284
|
+
.filter((l) => l.length > 0);
|
|
285
|
+
} catch {
|
|
286
|
+
return [];
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Fallback: append bullets grouped by section to the section file.
|
|
292
|
+
*
|
|
293
|
+
* v1.13 adds a novelty gate — before appending, every proposal's content
|
|
294
|
+
* is compared (Jaccard token-overlap) against existing lines in the
|
|
295
|
+
* target section file. Proposals whose top similarity exceeds
|
|
296
|
+
* {@link DUPLICATE_JACCARD_THRESHOLD} are dropped so the file stops
|
|
297
|
+
* accumulating near-duplicate auto-observations over time.
|
|
298
|
+
*
|
|
299
|
+
* v1.15 (Phase 5.3): when ASHLR_GENOME_LLM_SYNTHESIS=1, raw proposal
|
|
300
|
+
* content is routed through summarizeIfLarge with the genome_synthesize
|
|
301
|
+
* prompt before Jaccard dedup. The LLM either returns 1-3 curated bullets
|
|
302
|
+
* or a {novel:false} sentinel that drops the whole batch. Falls back to
|
|
303
|
+
* the deterministic path on LLM error.
|
|
304
|
+
*/
|
|
305
|
+
export async function applyFallback(
|
|
306
|
+
genomeDir: string,
|
|
307
|
+
proposals: Proposal[],
|
|
308
|
+
): Promise<number> {
|
|
309
|
+
// LLM synthesis is enabled by default when any LLM endpoint is reachable
|
|
310
|
+
// (ASHLR_LLM_URL, ANTHROPIC_API_KEY, or OPENAI_API_KEY) AND
|
|
311
|
+
// ASHLR_GENOME_LLM_SYNTHESIS is not explicitly "0" (opt-out).
|
|
312
|
+
// Falls back to deterministic Jaccard path when no endpoint is reachable.
|
|
313
|
+
const synthEnv = process.env["ASHLR_GENOME_LLM_SYNTHESIS"];
|
|
314
|
+
const llmSynthesis =
|
|
315
|
+
synthEnv !== "0" && (synthEnv === "1" || (await _hooks.isLlmReachable()));
|
|
316
|
+
|
|
317
|
+
const bySection = new Map<string, Proposal[]>();
|
|
318
|
+
for (const p of proposals) {
|
|
319
|
+
const target = routeSectionForProposal(p.section, p.content);
|
|
320
|
+
const g = bySection.get(target) ?? [];
|
|
321
|
+
g.push(p);
|
|
322
|
+
bySection.set(target, g);
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
let applied = 0;
|
|
326
|
+
const stamp = new Date().toISOString().slice(0, 10);
|
|
327
|
+
|
|
328
|
+
for (const [section, items] of bySection) {
|
|
329
|
+
const target = sectionFilePath(genomeDir, section);
|
|
330
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
331
|
+
const existing = existsSync(target) ? readFileSync(target, "utf-8") : "";
|
|
332
|
+
const existingLines = readExistingLines(target);
|
|
333
|
+
const existingTokenSets = existingLines.map((line) => tokenize(line));
|
|
334
|
+
|
|
335
|
+
let acceptedBullets: string[] = [];
|
|
336
|
+
|
|
337
|
+
if (llmSynthesis) {
|
|
338
|
+
// LLM synthesis path: batch all raw proposal content and send to LLM.
|
|
339
|
+
const rawBatch = items.map((item) => item.content).join("\n");
|
|
340
|
+
let llmBullets: string[] | null = null;
|
|
341
|
+
try {
|
|
342
|
+
const result = await _hooks.summarizeIfLarge(rawBatch, {
|
|
343
|
+
systemPrompt: PROMPTS.genome_synthesize,
|
|
344
|
+
toolName: "genome-consolidate",
|
|
345
|
+
thresholdBytes: 200,
|
|
346
|
+
});
|
|
347
|
+
const llmText = result.text.trim();
|
|
348
|
+
// Strip any trailing bypass hint line added by summarizeIfLarge.
|
|
349
|
+
const lines = llmText.split("\n").filter((l) => l.trim().length > 0);
|
|
350
|
+
const contentLines = lines.filter((l) => !l.startsWith("[ashlr "));
|
|
351
|
+
// Check for novel:false sentinel — first non-whitespace line.
|
|
352
|
+
const firstLine = contentLines[0]?.trim() ?? "";
|
|
353
|
+
let parsed: unknown;
|
|
354
|
+
try { parsed = JSON.parse(firstLine); } catch { parsed = null; }
|
|
355
|
+
if (
|
|
356
|
+
parsed !== null &&
|
|
357
|
+
typeof parsed === "object" &&
|
|
358
|
+
(parsed as Record<string, unknown>)["novel"] === false
|
|
359
|
+
) {
|
|
360
|
+
const reason = (parsed as Record<string, unknown>)["reason"] ?? "no reason given";
|
|
361
|
+
logLine(
|
|
362
|
+
`${new Date().toISOString()} section=${section} llm-synthesis=novel:false reason=${String(reason)}`,
|
|
363
|
+
);
|
|
364
|
+
continue; // drop entire batch for this section
|
|
365
|
+
}
|
|
366
|
+
// Extract bullet lines (lines starting with "- ").
|
|
367
|
+
llmBullets = contentLines.filter((l) => l.startsWith("- "));
|
|
368
|
+
if (llmBullets.length === 0 && contentLines.length > 0) {
|
|
369
|
+
// LLM returned content but not in bullet form — wrap each line.
|
|
370
|
+
llmBullets = contentLines.map((l) => `- ${l.replace(/^[-*]\s*/, "")}`);
|
|
371
|
+
}
|
|
372
|
+
} catch {
|
|
373
|
+
// LLM error — fall through to deterministic path.
|
|
374
|
+
llmBullets = null;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
if (llmBullets !== null) {
|
|
378
|
+
// Run Jaccard dedup on LLM-synthesized bullets against existing content.
|
|
379
|
+
const acceptedBulletSets: Set<string>[] = [];
|
|
380
|
+
for (const bullet of llmBullets) {
|
|
381
|
+
const tokens = tokenize(bullet);
|
|
382
|
+
const isDuplicate =
|
|
383
|
+
existingTokenSets.some((et) => jaccard(tokens, et) >= DUPLICATE_JACCARD_THRESHOLD) ||
|
|
384
|
+
acceptedBulletSets.some((at) => jaccard(tokens, at) >= DUPLICATE_JACCARD_THRESHOLD);
|
|
385
|
+
if (isDuplicate) continue;
|
|
386
|
+
acceptedBulletSets.push(tokens);
|
|
387
|
+
acceptedBullets.push(bullet);
|
|
388
|
+
}
|
|
389
|
+
} else {
|
|
390
|
+
// Graceful degradation: LLM errored, run deterministic bulletize path.
|
|
391
|
+
const acceptedBulletSets: Set<string>[] = [];
|
|
392
|
+
for (const item of items) {
|
|
393
|
+
const bullet = bulletize(item.content);
|
|
394
|
+
const tokens = tokenize(bullet);
|
|
395
|
+
const isDuplicate =
|
|
396
|
+
existingTokenSets.some((et) => jaccard(tokens, et) >= DUPLICATE_JACCARD_THRESHOLD) ||
|
|
397
|
+
acceptedBulletSets.some((at) => jaccard(tokens, at) >= DUPLICATE_JACCARD_THRESHOLD);
|
|
398
|
+
if (isDuplicate) continue;
|
|
399
|
+
acceptedBulletSets.push(tokens);
|
|
400
|
+
acceptedBullets.push(bullet);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
} else {
|
|
404
|
+
// Deterministic path (default): Jaccard dedup on bulletized proposals.
|
|
405
|
+
const acceptedBulletSets: Set<string>[] = [];
|
|
406
|
+
for (const item of items) {
|
|
407
|
+
const bullet = bulletize(item.content);
|
|
408
|
+
const tokens = tokenize(bullet);
|
|
409
|
+
const isDuplicate =
|
|
410
|
+
existingTokenSets.some((et) => jaccard(tokens, et) >= DUPLICATE_JACCARD_THRESHOLD) ||
|
|
411
|
+
acceptedBulletSets.some((at) => jaccard(tokens, at) >= DUPLICATE_JACCARD_THRESHOLD);
|
|
412
|
+
if (isDuplicate) continue;
|
|
413
|
+
acceptedBulletSets.push(tokens);
|
|
414
|
+
acceptedBullets.push(bullet);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
if (acceptedBullets.length === 0) continue;
|
|
419
|
+
|
|
420
|
+
const header = `\n\n## Auto-observations · ${stamp}\n`;
|
|
421
|
+
const combined =
|
|
422
|
+
(existing.endsWith("\n") || existing === "" ? existing : existing + "\n") +
|
|
423
|
+
header +
|
|
424
|
+
acceptedBullets.join("\n") +
|
|
425
|
+
"\n";
|
|
426
|
+
writeFileSync(target, combined, "utf-8");
|
|
427
|
+
applied += acceptedBullets.length;
|
|
428
|
+
}
|
|
429
|
+
return applied;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
// ---------------------------------------------------------------------------
|
|
433
|
+
// Logging
|
|
434
|
+
// ---------------------------------------------------------------------------
|
|
435
|
+
|
|
436
|
+
function logLine(msg: string): void {
|
|
437
|
+
try {
|
|
438
|
+
mkdirSync(dirname(LOG_PATH), { recursive: true });
|
|
439
|
+
appendFileSync(LOG_PATH, msg + "\n", "utf-8");
|
|
440
|
+
} catch {
|
|
441
|
+
/* ignore */
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// ---------------------------------------------------------------------------
|
|
446
|
+
// Main
|
|
447
|
+
// ---------------------------------------------------------------------------
|
|
448
|
+
|
|
449
|
+
export interface ConsolidateResult {
|
|
450
|
+
ran: boolean;
|
|
451
|
+
reason: string;
|
|
452
|
+
before: number;
|
|
453
|
+
after: number;
|
|
454
|
+
applied: number;
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
export async function runConsolidate(dir: string): Promise<ConsolidateResult> {
|
|
458
|
+
const cwd = resolve(dir);
|
|
459
|
+
const genomeDir = join(cwd, ".ashlrcode", "genome");
|
|
460
|
+
if (!existsSync(genomeDir)) {
|
|
461
|
+
return { ran: false, reason: "no-genome", before: 0, after: 0, applied: 0 };
|
|
462
|
+
}
|
|
463
|
+
const proposalsPath = join(genomeDir, "proposals.jsonl");
|
|
464
|
+
const before = readProposals(proposalsPath);
|
|
465
|
+
if (before.length < 3) {
|
|
466
|
+
return {
|
|
467
|
+
ran: false,
|
|
468
|
+
reason: "below-threshold",
|
|
469
|
+
before: before.length,
|
|
470
|
+
after: before.length,
|
|
471
|
+
applied: 0,
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
let applied = 0;
|
|
476
|
+
try {
|
|
477
|
+
applied = await applyFallback(genomeDir, before);
|
|
478
|
+
} catch (e) {
|
|
479
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
480
|
+
logLine(
|
|
481
|
+
`${new Date().toISOString()} cwd=${cwd} error=${msg} before=${before.length}`,
|
|
482
|
+
);
|
|
483
|
+
return {
|
|
484
|
+
ran: false,
|
|
485
|
+
reason: "apply-failed",
|
|
486
|
+
before: before.length,
|
|
487
|
+
after: before.length,
|
|
488
|
+
applied: 0,
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
// Truncate queue.
|
|
493
|
+
try {
|
|
494
|
+
writeFileSync(proposalsPath, "", "utf-8");
|
|
495
|
+
} catch {
|
|
496
|
+
/* ignore */
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
logLine(
|
|
500
|
+
`${new Date().toISOString()} cwd=${cwd} before=${before.length} after=0 applied=${applied}`,
|
|
501
|
+
);
|
|
502
|
+
|
|
503
|
+
return {
|
|
504
|
+
ran: true,
|
|
505
|
+
reason: "ok",
|
|
506
|
+
before: before.length,
|
|
507
|
+
after: 0,
|
|
508
|
+
applied,
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
async function main(): Promise<void> {
|
|
513
|
+
if (!isAutoEnabled()) {
|
|
514
|
+
process.exit(0);
|
|
515
|
+
}
|
|
516
|
+
const { dir } = parseArgs(process.argv.slice(2));
|
|
517
|
+
const target = dir ?? process.env.PROJECT_ROOT ?? process.cwd();
|
|
518
|
+
try {
|
|
519
|
+
const result = await runConsolidate(target);
|
|
520
|
+
if (result.ran) {
|
|
521
|
+
process.stdout.write(
|
|
522
|
+
`ashlr-genome: consolidated ${result.applied} proposal${result.applied === 1 ? "" : "s"} into ${target}/.ashlrcode/genome/\n`,
|
|
523
|
+
);
|
|
524
|
+
}
|
|
525
|
+
} catch {
|
|
526
|
+
/* never block */
|
|
527
|
+
}
|
|
528
|
+
process.exit(0);
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
if (import.meta.main) {
|
|
532
|
+
await main();
|
|
533
|
+
}
|