@ag-eco/agentplate-cli 0.13.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/LICENSE +21 -0
- package/README.md +462 -0
- package/agents/ap-co-creation.md +90 -0
- package/agents/builder.md +144 -0
- package/agents/coordinator.md +377 -0
- package/agents/lead.md +435 -0
- package/agents/merger.md +164 -0
- package/agents/monitor.md +214 -0
- package/agents/orchestrator.md +239 -0
- package/agents/reviewer.md +140 -0
- package/agents/scout.md +125 -0
- package/agents/supervisor.md +427 -0
- package/package.json +66 -0
- package/src/agents/capabilities.test.ts +85 -0
- package/src/agents/capabilities.ts +125 -0
- package/src/agents/checkpoint.test.ts +88 -0
- package/src/agents/checkpoint.ts +101 -0
- package/src/agents/copilot-hooks-deployer.test.ts +162 -0
- package/src/agents/copilot-hooks-deployer.ts +93 -0
- package/src/agents/guard-rules.test.ts +372 -0
- package/src/agents/guard-rules.ts +97 -0
- package/src/agents/headless-mail-injector.test.ts +709 -0
- package/src/agents/headless-mail-injector.ts +377 -0
- package/src/agents/headless-prompt.test.ts +102 -0
- package/src/agents/headless-prompt.ts +68 -0
- package/src/agents/hooks-deployer.test.ts +3119 -0
- package/src/agents/hooks-deployer.ts +804 -0
- package/src/agents/identity.test.ts +604 -0
- package/src/agents/identity.ts +384 -0
- package/src/agents/lifecycle.test.ts +196 -0
- package/src/agents/lifecycle.ts +183 -0
- package/src/agents/mail-poll-detect.test.ts +153 -0
- package/src/agents/mail-poll-detect.ts +73 -0
- package/src/agents/manifest.test.ts +1026 -0
- package/src/agents/manifest.ts +376 -0
- package/src/agents/overlay.test.ts +1058 -0
- package/src/agents/overlay.ts +490 -0
- package/src/agents/scope-detect.test.ts +190 -0
- package/src/agents/scope-detect.ts +146 -0
- package/src/agents/turn-lock.test.ts +181 -0
- package/src/agents/turn-lock.ts +235 -0
- package/src/agents/turn-runner-dispatch.test.ts +182 -0
- package/src/agents/turn-runner-dispatch.ts +105 -0
- package/src/agents/turn-runner.test.ts +2312 -0
- package/src/agents/turn-runner.ts +1383 -0
- package/src/beads/client.test.ts +217 -0
- package/src/beads/client.ts +230 -0
- package/src/beads/molecules.test.ts +338 -0
- package/src/beads/molecules.ts +198 -0
- package/src/commands/agents.test.ts +328 -0
- package/src/commands/agents.ts +299 -0
- package/src/commands/clean.test.ts +797 -0
- package/src/commands/clean.ts +791 -0
- package/src/commands/completions.test.ts +348 -0
- package/src/commands/completions.ts +981 -0
- package/src/commands/coordinator.test.ts +2975 -0
- package/src/commands/coordinator.ts +1841 -0
- package/src/commands/costs.test.ts +1183 -0
- package/src/commands/costs.ts +599 -0
- package/src/commands/dashboard.test.ts +954 -0
- package/src/commands/dashboard.ts +1212 -0
- package/src/commands/discover.test.ts +288 -0
- package/src/commands/discover.ts +202 -0
- package/src/commands/doctor.test.ts +303 -0
- package/src/commands/doctor.ts +311 -0
- package/src/commands/ecosystem.test.ts +226 -0
- package/src/commands/ecosystem.ts +248 -0
- package/src/commands/errors.test.ts +654 -0
- package/src/commands/errors.ts +197 -0
- package/src/commands/feed.test.ts +709 -0
- package/src/commands/feed.ts +260 -0
- package/src/commands/group.test.ts +475 -0
- package/src/commands/group.ts +546 -0
- package/src/commands/hooks.test.ts +458 -0
- package/src/commands/hooks.ts +263 -0
- package/src/commands/init.test.ts +1011 -0
- package/src/commands/init.ts +967 -0
- package/src/commands/inspect.test.ts +1239 -0
- package/src/commands/inspect.ts +648 -0
- package/src/commands/log.test.ts +1913 -0
- package/src/commands/log.ts +958 -0
- package/src/commands/logs.test.ts +801 -0
- package/src/commands/logs.ts +483 -0
- package/src/commands/mail.test.ts +1501 -0
- package/src/commands/mail.ts +848 -0
- package/src/commands/merge.test.ts +864 -0
- package/src/commands/merge.ts +381 -0
- package/src/commands/metrics.test.ts +458 -0
- package/src/commands/metrics.ts +129 -0
- package/src/commands/monitor.test.ts +191 -0
- package/src/commands/monitor.ts +409 -0
- package/src/commands/nudge.test.ts +579 -0
- package/src/commands/nudge.ts +646 -0
- package/src/commands/orchestrator.ts +42 -0
- package/src/commands/prime.test.ts +612 -0
- package/src/commands/prime.ts +359 -0
- package/src/commands/replay.test.ts +757 -0
- package/src/commands/replay.ts +231 -0
- package/src/commands/run.test.ts +469 -0
- package/src/commands/run.ts +353 -0
- package/src/commands/serve/agent-actions.test.ts +210 -0
- package/src/commands/serve/agent-actions.ts +192 -0
- package/src/commands/serve/build.test.ts +202 -0
- package/src/commands/serve/build.ts +206 -0
- package/src/commands/serve/coordinator-actions.test.ts +339 -0
- package/src/commands/serve/coordinator-actions.ts +410 -0
- package/src/commands/serve/dev.test.ts +168 -0
- package/src/commands/serve/dev.ts +117 -0
- package/src/commands/serve/mail-actions.test.ts +312 -0
- package/src/commands/serve/mail-actions.ts +167 -0
- package/src/commands/serve/rest.test.ts +1680 -0
- package/src/commands/serve/rest.ts +1130 -0
- package/src/commands/serve/static.ts +51 -0
- package/src/commands/serve/ws.test.ts +361 -0
- package/src/commands/serve/ws.ts +332 -0
- package/src/commands/serve.test.ts +459 -0
- package/src/commands/serve.ts +654 -0
- package/src/commands/sling.test.ts +1583 -0
- package/src/commands/sling.ts +1351 -0
- package/src/commands/spec.test.ts +179 -0
- package/src/commands/spec.ts +105 -0
- package/src/commands/status.test.ts +614 -0
- package/src/commands/status.ts +403 -0
- package/src/commands/stop.test.ts +964 -0
- package/src/commands/stop.ts +319 -0
- package/src/commands/supervisor.test.ts +185 -0
- package/src/commands/supervisor.ts +537 -0
- package/src/commands/trace.test.ts +762 -0
- package/src/commands/trace.ts +205 -0
- package/src/commands/update.test.ts +466 -0
- package/src/commands/update.ts +263 -0
- package/src/commands/upgrade.test.ts +48 -0
- package/src/commands/upgrade.ts +240 -0
- package/src/commands/watch.test.ts +257 -0
- package/src/commands/watch.ts +308 -0
- package/src/commands/worktree.test.ts +1297 -0
- package/src/commands/worktree.ts +451 -0
- package/src/config.test.ts +1535 -0
- package/src/config.ts +1064 -0
- package/src/doctor/agents.test.ts +523 -0
- package/src/doctor/agents.ts +399 -0
- package/src/doctor/config-check.test.ts +191 -0
- package/src/doctor/config-check.ts +183 -0
- package/src/doctor/consistency.test.ts +807 -0
- package/src/doctor/consistency.ts +347 -0
- package/src/doctor/databases.test.ts +350 -0
- package/src/doctor/databases.ts +243 -0
- package/src/doctor/dependencies.test.ts +296 -0
- package/src/doctor/dependencies.ts +272 -0
- package/src/doctor/ecosystem.test.ts +308 -0
- package/src/doctor/ecosystem.ts +156 -0
- package/src/doctor/logs.test.ts +253 -0
- package/src/doctor/logs.ts +295 -0
- package/src/doctor/merge-queue.test.ts +315 -0
- package/src/doctor/merge-queue.ts +167 -0
- package/src/doctor/providers.test.ts +409 -0
- package/src/doctor/providers.ts +250 -0
- package/src/doctor/serve.test.ts +95 -0
- package/src/doctor/serve.ts +86 -0
- package/src/doctor/structure.test.ts +423 -0
- package/src/doctor/structure.ts +285 -0
- package/src/doctor/types.ts +43 -0
- package/src/doctor/version.test.ts +241 -0
- package/src/doctor/version.ts +132 -0
- package/src/doctor/watchdog.test.ts +167 -0
- package/src/doctor/watchdog.ts +214 -0
- package/src/e2e/init-sling-lifecycle.test.ts +283 -0
- package/src/errors.test.ts +350 -0
- package/src/errors.ts +217 -0
- package/src/events/store.test.ts +660 -0
- package/src/events/store.ts +369 -0
- package/src/events/tailer.test.ts +719 -0
- package/src/events/tailer.ts +332 -0
- package/src/events/tool-filter.test.ts +330 -0
- package/src/events/tool-filter.ts +126 -0
- package/src/index.ts +533 -0
- package/src/insights/analyzer.test.ts +466 -0
- package/src/insights/analyzer.ts +203 -0
- package/src/insights/quality-gates.test.ts +141 -0
- package/src/insights/quality-gates.ts +156 -0
- package/src/json.test.ts +72 -0
- package/src/json.ts +53 -0
- package/src/loam/client.test.ts +752 -0
- package/src/loam/client.ts +664 -0
- package/src/logging/color.test.ts +252 -0
- package/src/logging/color.ts +105 -0
- package/src/logging/format.test.ts +110 -0
- package/src/logging/format.ts +255 -0
- package/src/logging/logger.test.ts +814 -0
- package/src/logging/logger.ts +266 -0
- package/src/logging/reporter.test.ts +259 -0
- package/src/logging/reporter.ts +110 -0
- package/src/logging/sanitizer.test.ts +190 -0
- package/src/logging/sanitizer.ts +57 -0
- package/src/logging/theme.ts +140 -0
- package/src/mail/broadcast.test.ts +204 -0
- package/src/mail/broadcast.ts +92 -0
- package/src/mail/client.test.ts +774 -0
- package/src/mail/client.ts +236 -0
- package/src/mail/store.test.ts +898 -0
- package/src/mail/store.ts +425 -0
- package/src/merge/lock.test.ts +149 -0
- package/src/merge/lock.ts +140 -0
- package/src/merge/predict.test.ts +387 -0
- package/src/merge/predict.ts +249 -0
- package/src/merge/queue.test.ts +426 -0
- package/src/merge/queue.ts +246 -0
- package/src/merge/resolver.test.ts +1993 -0
- package/src/merge/resolver.ts +926 -0
- package/src/metrics/pricing.test.ts +258 -0
- package/src/metrics/pricing.ts +135 -0
- package/src/metrics/store.test.ts +978 -0
- package/src/metrics/store.ts +501 -0
- package/src/metrics/summary.test.ts +398 -0
- package/src/metrics/summary.ts +178 -0
- package/src/metrics/transcript.test.ts +483 -0
- package/src/metrics/transcript.ts +114 -0
- package/src/runtimes/__fixtures__/claude-stream-fixture.ts +22 -0
- package/src/runtimes/aider.test.ts +124 -0
- package/src/runtimes/aider.ts +147 -0
- package/src/runtimes/amp.test.ts +164 -0
- package/src/runtimes/amp.ts +154 -0
- package/src/runtimes/claude.test.ts +1474 -0
- package/src/runtimes/claude.ts +579 -0
- package/src/runtimes/codex.test.ts +805 -0
- package/src/runtimes/codex.ts +273 -0
- package/src/runtimes/connections.test.ts +214 -0
- package/src/runtimes/connections.ts +103 -0
- package/src/runtimes/copilot.test.ts +707 -0
- package/src/runtimes/copilot.ts +316 -0
- package/src/runtimes/cursor.test.ts +497 -0
- package/src/runtimes/cursor.ts +205 -0
- package/src/runtimes/gemini.test.ts +537 -0
- package/src/runtimes/gemini.ts +243 -0
- package/src/runtimes/goose.test.ts +133 -0
- package/src/runtimes/goose.ts +157 -0
- package/src/runtimes/headless-connection.test.ts +264 -0
- package/src/runtimes/headless-connection.ts +158 -0
- package/src/runtimes/opencode.test.ts +325 -0
- package/src/runtimes/opencode.ts +188 -0
- package/src/runtimes/pi-guards.test.ts +486 -0
- package/src/runtimes/pi-guards.ts +367 -0
- package/src/runtimes/pi.test.ts +789 -0
- package/src/runtimes/pi.ts +305 -0
- package/src/runtimes/registry.test.ts +196 -0
- package/src/runtimes/registry.ts +99 -0
- package/src/runtimes/sapling.test.ts +1267 -0
- package/src/runtimes/sapling.ts +710 -0
- package/src/runtimes/types.ts +266 -0
- package/src/schema-consistency.test.ts +246 -0
- package/src/sessions/compat.test.ts +281 -0
- package/src/sessions/compat.ts +105 -0
- package/src/sessions/store.test.ts +1748 -0
- package/src/sessions/store.ts +858 -0
- package/src/test-helpers.test.ts +124 -0
- package/src/test-helpers.ts +145 -0
- package/src/test-setup.test.ts +31 -0
- package/src/test-setup.ts +28 -0
- package/src/tools/loam/api.ts +368 -0
- package/src/tools/loam/cli.ts +278 -0
- package/src/tools/loam/commands/add.ts +52 -0
- package/src/tools/loam/commands/archive.ts +214 -0
- package/src/tools/loam/commands/audit.ts +276 -0
- package/src/tools/loam/commands/compact.ts +1062 -0
- package/src/tools/loam/commands/completions.ts +79 -0
- package/src/tools/loam/commands/config.ts +381 -0
- package/src/tools/loam/commands/delete-domain.ts +121 -0
- package/src/tools/loam/commands/delete.ts +316 -0
- package/src/tools/loam/commands/diff.ts +200 -0
- package/src/tools/loam/commands/doctor.ts +1113 -0
- package/src/tools/loam/commands/edit.ts +226 -0
- package/src/tools/loam/commands/init.ts +31 -0
- package/src/tools/loam/commands/learn.ts +179 -0
- package/src/tools/loam/commands/move.ts +323 -0
- package/src/tools/loam/commands/onboard.ts +374 -0
- package/src/tools/loam/commands/outcome.ts +185 -0
- package/src/tools/loam/commands/prime.ts +688 -0
- package/src/tools/loam/commands/prune.ts +614 -0
- package/src/tools/loam/commands/query.ts +218 -0
- package/src/tools/loam/commands/rank.ts +180 -0
- package/src/tools/loam/commands/ready.ts +189 -0
- package/src/tools/loam/commands/record.ts +1210 -0
- package/src/tools/loam/commands/restore.ts +166 -0
- package/src/tools/loam/commands/search.ts +327 -0
- package/src/tools/loam/commands/setup.ts +887 -0
- package/src/tools/loam/commands/status.ts +103 -0
- package/src/tools/loam/commands/sync.ts +298 -0
- package/src/tools/loam/commands/update.ts +19 -0
- package/src/tools/loam/commands/upgrade.ts +93 -0
- package/src/tools/loam/commands/validate.ts +190 -0
- package/src/tools/loam/index.ts +62 -0
- package/src/tools/loam/log.ts +127 -0
- package/src/tools/loam/registry/builtins.ts +409 -0
- package/src/tools/loam/registry/custom.ts +431 -0
- package/src/tools/loam/registry/init.ts +55 -0
- package/src/tools/loam/registry/template.ts +40 -0
- package/src/tools/loam/registry/type-registry.ts +113 -0
- package/src/tools/loam/schemas/config-schema.ts +489 -0
- package/src/tools/loam/schemas/config.ts +245 -0
- package/src/tools/loam/schemas/index.ts +18 -0
- package/src/tools/loam/schemas/record-schema.ts +191 -0
- package/src/tools/loam/schemas/record.ts +115 -0
- package/src/tools/loam/utils/active-work.ts +205 -0
- package/src/tools/loam/utils/anchor-validity.ts +80 -0
- package/src/tools/loam/utils/archive.ts +146 -0
- package/src/tools/loam/utils/audit.ts +667 -0
- package/src/tools/loam/utils/bm25.ts +238 -0
- package/src/tools/loam/utils/budget.ts +142 -0
- package/src/tools/loam/utils/config.ts +344 -0
- package/src/tools/loam/utils/dir-anchors.ts +62 -0
- package/src/tools/loam/utils/domain-rules.ts +114 -0
- package/src/tools/loam/utils/expertise.ts +393 -0
- package/src/tools/loam/utils/format-helpers.ts +96 -0
- package/src/tools/loam/utils/format.ts +1234 -0
- package/src/tools/loam/utils/git-context.ts +50 -0
- package/src/tools/loam/utils/git.ts +183 -0
- package/src/tools/loam/utils/hooks.ts +299 -0
- package/src/tools/loam/utils/index.ts +52 -0
- package/src/tools/loam/utils/json-output.ts +13 -0
- package/src/tools/loam/utils/lock.ts +76 -0
- package/src/tools/loam/utils/markers.ts +48 -0
- package/src/tools/loam/utils/numeric-flags.ts +20 -0
- package/src/tools/loam/utils/palette.ts +44 -0
- package/src/tools/loam/utils/prime-ranking.ts +135 -0
- package/src/tools/loam/utils/recipe-discovery.ts +195 -0
- package/src/tools/loam/utils/runtime-flags.ts +28 -0
- package/src/tools/loam/utils/scoring.ts +94 -0
- package/src/tools/loam/utils/version.ts +116 -0
- package/src/tools/sprout/commands/block.ts +64 -0
- package/src/tools/sprout/commands/blocked.ts +86 -0
- package/src/tools/sprout/commands/close.ts +129 -0
- package/src/tools/sprout/commands/completions.ts +198 -0
- package/src/tools/sprout/commands/config.ts +238 -0
- package/src/tools/sprout/commands/create.ts +164 -0
- package/src/tools/sprout/commands/dep.ts +148 -0
- package/src/tools/sprout/commands/doctor.ts +979 -0
- package/src/tools/sprout/commands/init.ts +83 -0
- package/src/tools/sprout/commands/label.ts +178 -0
- package/src/tools/sprout/commands/list.ts +210 -0
- package/src/tools/sprout/commands/migrate.ts +133 -0
- package/src/tools/sprout/commands/onboard.ts +207 -0
- package/src/tools/sprout/commands/plan-show.ts +278 -0
- package/src/tools/sprout/commands/plan.ts +2526 -0
- package/src/tools/sprout/commands/prime.ts +399 -0
- package/src/tools/sprout/commands/ready.ts +245 -0
- package/src/tools/sprout/commands/search.ts +221 -0
- package/src/tools/sprout/commands/show.ts +277 -0
- package/src/tools/sprout/commands/stats.ts +146 -0
- package/src/tools/sprout/commands/sync.ts +134 -0
- package/src/tools/sprout/commands/tpl.ts +364 -0
- package/src/tools/sprout/commands/unblock.ts +115 -0
- package/src/tools/sprout/commands/update.ts +257 -0
- package/src/tools/sprout/commands/upgrade.ts +91 -0
- package/src/tools/sprout/config-schema.ts +152 -0
- package/src/tools/sprout/config.ts +355 -0
- package/src/tools/sprout/filter.ts +107 -0
- package/src/tools/sprout/format.ts +43 -0
- package/src/tools/sprout/id.ts +22 -0
- package/src/tools/sprout/index.ts +204 -0
- package/src/tools/sprout/log.ts +76 -0
- package/src/tools/sprout/markers.ts +22 -0
- package/src/tools/sprout/output.ts +121 -0
- package/src/tools/sprout/plan-backref.ts +93 -0
- package/src/tools/sprout/plan-context.ts +81 -0
- package/src/tools/sprout/plan-domain.ts +139 -0
- package/src/tools/sprout/plan-lifecycle.ts +65 -0
- package/src/tools/sprout/plan-loam.ts +207 -0
- package/src/tools/sprout/plan-schema.ts +209 -0
- package/src/tools/sprout/sort.ts +31 -0
- package/src/tools/sprout/store.ts +172 -0
- package/src/tools/sprout/types.ts +118 -0
- package/src/tools/sprout/validation.ts +119 -0
- package/src/tools/sprout/version.ts +1 -0
- package/src/tools/sprout/yaml.ts +387 -0
- package/src/tools/trellis/commands/archive.ts +87 -0
- package/src/tools/trellis/commands/completions.ts +610 -0
- package/src/tools/trellis/commands/config.ts +382 -0
- package/src/tools/trellis/commands/create.ts +252 -0
- package/src/tools/trellis/commands/diff.ts +150 -0
- package/src/tools/trellis/commands/doctor.ts +771 -0
- package/src/tools/trellis/commands/emit.ts +365 -0
- package/src/tools/trellis/commands/history.ts +83 -0
- package/src/tools/trellis/commands/import.ts +198 -0
- package/src/tools/trellis/commands/init.ts +81 -0
- package/src/tools/trellis/commands/list.ts +103 -0
- package/src/tools/trellis/commands/onboard.ts +156 -0
- package/src/tools/trellis/commands/pin.ts +172 -0
- package/src/tools/trellis/commands/prime.ts +193 -0
- package/src/tools/trellis/commands/render.ts +122 -0
- package/src/tools/trellis/commands/schema.ts +353 -0
- package/src/tools/trellis/commands/show.ts +115 -0
- package/src/tools/trellis/commands/stats.ts +65 -0
- package/src/tools/trellis/commands/sync.ts +112 -0
- package/src/tools/trellis/commands/tree.ts +123 -0
- package/src/tools/trellis/commands/update.ts +330 -0
- package/src/tools/trellis/commands/upgrade.ts +95 -0
- package/src/tools/trellis/commands/validate.ts +166 -0
- package/src/tools/trellis/config-schema.ts +81 -0
- package/src/tools/trellis/config.ts +108 -0
- package/src/tools/trellis/frontmatter.ts +348 -0
- package/src/tools/trellis/id.ts +24 -0
- package/src/tools/trellis/index.ts +209 -0
- package/src/tools/trellis/markers.ts +28 -0
- package/src/tools/trellis/output.ts +84 -0
- package/src/tools/trellis/render.ts +212 -0
- package/src/tools/trellis/store.ts +144 -0
- package/src/tools/trellis/types.ts +82 -0
- package/src/tools/trellis/validate.ts +199 -0
- package/src/tools/trellis/yaml.ts +309 -0
- package/src/tracker/beads.test.ts +454 -0
- package/src/tracker/beads.ts +56 -0
- package/src/tracker/factory.test.ts +90 -0
- package/src/tracker/factory.ts +65 -0
- package/src/tracker/sprout.test.ts +461 -0
- package/src/tracker/sprout.ts +182 -0
- package/src/tracker/types.ts +52 -0
- package/src/trellis/client.test.ts +107 -0
- package/src/trellis/client.ts +179 -0
- package/src/types.ts +970 -0
- package/src/utils/bin.test.ts +10 -0
- package/src/utils/bin.ts +37 -0
- package/src/utils/browser.test.ts +49 -0
- package/src/utils/browser.ts +48 -0
- package/src/utils/fs.test.ts +119 -0
- package/src/utils/fs.ts +62 -0
- package/src/utils/pid.test.ts +152 -0
- package/src/utils/pid.ts +130 -0
- package/src/utils/process-scan.test.ts +53 -0
- package/src/utils/process-scan.ts +76 -0
- package/src/utils/time.test.ts +43 -0
- package/src/utils/time.ts +37 -0
- package/src/utils/version.test.ts +33 -0
- package/src/utils/version.ts +70 -0
- package/src/version.ts +5 -0
- package/src/watchdog/daemon.test.ts +3721 -0
- package/src/watchdog/daemon.ts +1257 -0
- package/src/watchdog/health.test.ts +830 -0
- package/src/watchdog/health.ts +434 -0
- package/src/watchdog/triage.test.ts +205 -0
- package/src/watchdog/triage.ts +205 -0
- package/src/worktree/manager.test.ts +720 -0
- package/src/worktree/manager.ts +405 -0
- package/src/worktree/process.test.ts +172 -0
- package/src/worktree/process.ts +131 -0
- package/src/worktree/tmux.test.ts +1616 -0
- package/src/worktree/tmux.ts +721 -0
- package/templates/CLAUDE.md.tmpl +100 -0
- package/templates/copilot-hooks.json.tmpl +13 -0
- package/templates/hooks.json.tmpl +109 -0
- package/templates/overlay.md.tmpl +88 -0
- package/ui/dist/apple-touch-icon-bdy6teep.png +0 -0
- package/ui/dist/chunk-8s31f05k.css +1 -0
- package/ui/dist/chunk-vm5rz679.js +300 -0
- package/ui/dist/favicon-nzb39vza.svg +4 -0
- package/ui/dist/index.html +17 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const MARKER_START = "<!-- loam:start -->";
|
|
2
|
+
const MARKER_END = "<!-- loam:end -->";
|
|
3
|
+
|
|
4
|
+
export { MARKER_START, MARKER_END };
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Check whether content contains the loam marker section.
|
|
8
|
+
*/
|
|
9
|
+
export function hasMarkerSection(content: string): boolean {
|
|
10
|
+
return content.includes(MARKER_START);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Replace the marker-bounded section with new content.
|
|
15
|
+
* Returns null if no markers found.
|
|
16
|
+
*/
|
|
17
|
+
export function replaceMarkerSection(content: string, newSection: string): string | null {
|
|
18
|
+
const startIdx = content.indexOf(MARKER_START);
|
|
19
|
+
const endIdx = content.indexOf(MARKER_END);
|
|
20
|
+
if (startIdx === -1 || endIdx === -1) return null;
|
|
21
|
+
|
|
22
|
+
const before = content.substring(0, startIdx);
|
|
23
|
+
const after = content.substring(endIdx + MARKER_END.length);
|
|
24
|
+
|
|
25
|
+
return before + newSection + after;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Remove the marker-bounded section entirely.
|
|
30
|
+
* Cleans up extra newlines left behind.
|
|
31
|
+
*/
|
|
32
|
+
export function removeMarkerSection(content: string): string {
|
|
33
|
+
const startIdx = content.indexOf(MARKER_START);
|
|
34
|
+
const endIdx = content.indexOf(MARKER_END);
|
|
35
|
+
if (startIdx === -1 || endIdx === -1) return content;
|
|
36
|
+
|
|
37
|
+
const before = content.substring(0, startIdx);
|
|
38
|
+
const after = content.substring(endIdx + MARKER_END.length);
|
|
39
|
+
|
|
40
|
+
return `${(before + after).replace(/\n{3,}/g, "\n\n").trim()}\n`;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Wrap a snippet in loam markers.
|
|
45
|
+
*/
|
|
46
|
+
export function wrapInMarkers(snippet: string): string {
|
|
47
|
+
return `${MARKER_START}\n${snippet}${MARKER_END}`;
|
|
48
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// Strict numeric-flag parsers. `Number.parseFloat("10abc")` silently strips
|
|
2
|
+
// trailing garbage and `Number.parseInt("3.7", 10)` truncates to 3 — both
|
|
3
|
+
// would let typos through and write nonsense (NaN, partial values) to
|
|
4
|
+
// .loam/expertise/*.jsonl. Use a regex gate + Number() to reject anything
|
|
5
|
+
// that isn't a clean numeric literal. Convention: mx-5b9578.
|
|
6
|
+
|
|
7
|
+
const POSITIVE_INT_RE = /^\d+$/;
|
|
8
|
+
const NON_NEGATIVE_NUMBER_RE = /^\d+(\.\d+)?$/;
|
|
9
|
+
|
|
10
|
+
export function parseStrictPositiveInt(raw: string): number | null {
|
|
11
|
+
if (!POSITIVE_INT_RE.test(raw)) return null;
|
|
12
|
+
const n = Number(raw);
|
|
13
|
+
return Number.isFinite(n) && n >= 1 ? n : null;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function parseStrictNonNegativeNumber(raw: string): number | null {
|
|
17
|
+
if (!NON_NEGATIVE_NUMBER_RE.test(raw)) return null;
|
|
18
|
+
const n = Number(raw);
|
|
19
|
+
return Number.isFinite(n) && n >= 0 ? n : null;
|
|
20
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
|
|
3
|
+
// Loam brand color: brown / soil
|
|
4
|
+
export const brand = chalk.rgb(139, 90, 43);
|
|
5
|
+
|
|
6
|
+
// Shared semantic colors
|
|
7
|
+
export const accent = chalk.rgb(255, 183, 77); // amber — IDs, references
|
|
8
|
+
export const muted = chalk.rgb(120, 120, 110); // stone gray — metadata
|
|
9
|
+
|
|
10
|
+
// Status icons (Set D — minimal, maximum terminal compatibility)
|
|
11
|
+
export const icons = {
|
|
12
|
+
pass: brand("✓"), // success / pass
|
|
13
|
+
warn: chalk.yellow("!"), // warning / blocked
|
|
14
|
+
fail: chalk.red("✗"), // error / fail
|
|
15
|
+
open: brand("-"), // open / pending
|
|
16
|
+
active: chalk.cyan(">"), // in_progress / active
|
|
17
|
+
done: chalk.dim("x"), // closed / done
|
|
18
|
+
} as const;
|
|
19
|
+
|
|
20
|
+
// Quiet mode state
|
|
21
|
+
let _quiet = false;
|
|
22
|
+
|
|
23
|
+
export function setQuiet(v: boolean): void {
|
|
24
|
+
_quiet = v;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function isQuiet(): boolean {
|
|
28
|
+
return _quiet;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Message formatters — mirroring visual-spec.md patterns
|
|
32
|
+
export function printSuccess(msg: string): void {
|
|
33
|
+
if (_quiet) return;
|
|
34
|
+
console.log(`${icons.pass} ${brand(msg)}`);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function printError(msg: string): void {
|
|
38
|
+
console.error(`${icons.fail} ${chalk.red(msg)}`);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function printWarning(msg: string): void {
|
|
42
|
+
if (_quiet) return;
|
|
43
|
+
console.log(`${icons.warn} ${chalk.yellow(msg)}`);
|
|
44
|
+
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { DEFAULT_PRIME_TIER_WEIGHTS, type PrimeTierWeights } from "../schemas/config.ts";
|
|
2
|
+
import type { ExpertiseRecord } from "../schemas/record.ts";
|
|
3
|
+
import { TRACKERS, type TrackerName } from "./active-work.ts";
|
|
4
|
+
import { fileLivesUnderDir } from "./dir-anchors.ts";
|
|
5
|
+
import type { ActiveContext } from "./git.ts";
|
|
6
|
+
import { fileMatchesAny } from "./git.ts";
|
|
7
|
+
import { computeConfirmationScore } from "./scoring.ts";
|
|
8
|
+
|
|
9
|
+
// Trust-tier ranking for `lm prime` full-mode output (v0.10 slice 3 of the
|
|
10
|
+
// prime overhaul). The corpus is ordered so the most trustworthy records
|
|
11
|
+
// surface first within the budget cap: star-confirmed > foundational >
|
|
12
|
+
// tactical > observational. Within-tier ties preserve insertion order so a
|
|
13
|
+
// stable run-to-run shape lets agents notice when the top of the list shifts.
|
|
14
|
+
|
|
15
|
+
export type ResolvedTierWeights = Required<PrimeTierWeights>;
|
|
16
|
+
|
|
17
|
+
export function resolveTierWeights(override?: PrimeTierWeights): ResolvedTierWeights {
|
|
18
|
+
return { ...DEFAULT_PRIME_TIER_WEIGHTS, ...(override ?? {}) };
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function computeTrustScore(r: ExpertiseRecord, weights: ResolvedTierWeights): number {
|
|
22
|
+
const stars = computeConfirmationScore(r);
|
|
23
|
+
const tier = weights[r.classification] ?? 0;
|
|
24
|
+
return stars * weights.star + tier;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function sortByTrust<T extends ExpertiseRecord>(
|
|
28
|
+
records: T[],
|
|
29
|
+
weights: ResolvedTierWeights,
|
|
30
|
+
): T[] {
|
|
31
|
+
// Stable sort: equal scores keep insertion order so within-tier output is
|
|
32
|
+
// deterministic. Array.prototype.sort is stable in Node ≥ 12 but the
|
|
33
|
+
// index decorator makes the contract explicit and survives engine quirks.
|
|
34
|
+
const decorated = records.map((r, i) => ({
|
|
35
|
+
r,
|
|
36
|
+
i,
|
|
37
|
+
score: computeTrustScore(r, weights),
|
|
38
|
+
}));
|
|
39
|
+
decorated.sort((a, b) => b.score - a.score || a.i - b.i);
|
|
40
|
+
return decorated.map((d) => d.r);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// "Why surfaced now" reasons — one per record, picked in priority order so the
|
|
44
|
+
// strongest signal wins. The agent-facing suffix shows the picked reason; the
|
|
45
|
+
// structured shape stays in the type system for future consumers (warren UI,
|
|
46
|
+
// audit reports).
|
|
47
|
+
export type SurfaceReason =
|
|
48
|
+
| { kind: "file_match"; anchor: string }
|
|
49
|
+
| { kind: "tracker_match"; tracker: TrackerName; id: string }
|
|
50
|
+
| { kind: "stars"; count: number }
|
|
51
|
+
| { kind: "recent"; daysAgo: number }
|
|
52
|
+
| { kind: "universal" };
|
|
53
|
+
|
|
54
|
+
// Recency window for the "recent authorship" reason. Aligned with the
|
|
55
|
+
// tactical shelf-life floor so newly-recorded conventions get a why-surfaced
|
|
56
|
+
// hint even before they accumulate confirmations.
|
|
57
|
+
export const RECENT_AUTHORSHIP_DAYS = 7;
|
|
58
|
+
|
|
59
|
+
export function whySurfaced(r: ExpertiseRecord, ctx: ActiveContext | null): SurfaceReason {
|
|
60
|
+
if (ctx) {
|
|
61
|
+
const files = "files" in r && Array.isArray(r.files) ? r.files : undefined;
|
|
62
|
+
if (files && files.length > 0) {
|
|
63
|
+
for (const f of files) {
|
|
64
|
+
if (fileMatchesAny(f, ctx.changedFiles)) {
|
|
65
|
+
return { kind: "file_match", anchor: f };
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (Array.isArray(r.dir_anchors) && r.dir_anchors.length > 0) {
|
|
70
|
+
for (const d of r.dir_anchors) {
|
|
71
|
+
for (const cf of ctx.changedFiles) {
|
|
72
|
+
if (fileLivesUnderDir(cf, d)) {
|
|
73
|
+
return { kind: "file_match", anchor: d };
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
for (const t of TRACKERS) {
|
|
79
|
+
const active = ctx.trackers[t];
|
|
80
|
+
const evValue = r.evidence?.[t];
|
|
81
|
+
if (
|
|
82
|
+
typeof active === "string" &&
|
|
83
|
+
active !== "" &&
|
|
84
|
+
typeof evValue === "string" &&
|
|
85
|
+
active === evValue
|
|
86
|
+
) {
|
|
87
|
+
return { kind: "tracker_match", tracker: t, id: active };
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const stars = computeConfirmationScore(r);
|
|
92
|
+
if (stars > 0) return { kind: "stars", count: stars };
|
|
93
|
+
const recordedAt = new Date(r.recorded_at);
|
|
94
|
+
if (!Number.isNaN(recordedAt.getTime())) {
|
|
95
|
+
const days = Math.floor((Date.now() - recordedAt.getTime()) / (1000 * 60 * 60 * 24));
|
|
96
|
+
if (days < RECENT_AUTHORSHIP_DAYS) {
|
|
97
|
+
return { kind: "recent", daysAgo: Math.max(0, days) };
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return { kind: "universal" };
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function formatSurfaceReason(reason: SurfaceReason): string {
|
|
104
|
+
switch (reason.kind) {
|
|
105
|
+
case "file_match":
|
|
106
|
+
return `why: file match (${reason.anchor})`;
|
|
107
|
+
case "tracker_match":
|
|
108
|
+
return `why: in-progress ${reason.tracker}:${reason.id}`;
|
|
109
|
+
case "stars": {
|
|
110
|
+
const formatted = Number.isInteger(reason.count)
|
|
111
|
+
? `★${reason.count}`
|
|
112
|
+
: `★${reason.count.toFixed(1)}`;
|
|
113
|
+
return `why: ${formatted} confirmations`;
|
|
114
|
+
}
|
|
115
|
+
case "recent":
|
|
116
|
+
return reason.daysAgo === 0 ? "why: recorded today" : `why: recorded ${reason.daysAgo}d ago`;
|
|
117
|
+
case "universal":
|
|
118
|
+
return "why: applies broadly (no anchors)";
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Build a per-record-id annotation map for downstream formatters. Records
|
|
123
|
+
// without an id are skipped — pre-id corpora exist in older projects and the
|
|
124
|
+
// formatters key on id-bearing lines.
|
|
125
|
+
export function buildSurfaceAnnotations(
|
|
126
|
+
records: ExpertiseRecord[],
|
|
127
|
+
ctx: ActiveContext | null,
|
|
128
|
+
): Map<string, string> {
|
|
129
|
+
const map = new Map<string, string>();
|
|
130
|
+
for (const r of records) {
|
|
131
|
+
if (!r.id) continue;
|
|
132
|
+
map.set(r.id, formatSurfaceReason(whySurfaced(r, ctx)));
|
|
133
|
+
}
|
|
134
|
+
return map;
|
|
135
|
+
}
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { existsSync } from "node:fs";
|
|
3
|
+
import { readdir } from "node:fs/promises";
|
|
4
|
+
import { createRequire } from "node:module";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
|
|
7
|
+
export interface RecipeResult {
|
|
8
|
+
success: boolean;
|
|
9
|
+
message: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface ProviderRecipe {
|
|
13
|
+
install(cwd: string): Promise<RecipeResult>;
|
|
14
|
+
check(cwd: string): Promise<RecipeResult>;
|
|
15
|
+
remove(cwd: string): Promise<RecipeResult>;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export type RecipeSource = "builtin" | "filesystem-ts" | "filesystem-sh" | "npm";
|
|
19
|
+
|
|
20
|
+
export interface RecipeWithSource {
|
|
21
|
+
name: string;
|
|
22
|
+
source: RecipeSource;
|
|
23
|
+
recipe: ProviderRecipe;
|
|
24
|
+
path?: string;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export interface FilesystemRecipeListing {
|
|
28
|
+
name: string;
|
|
29
|
+
source: "filesystem-ts" | "filesystem-sh";
|
|
30
|
+
path: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export const NPM_RECIPE_PREFIX = "loam-recipe-";
|
|
34
|
+
|
|
35
|
+
export function recipesDir(cwd: string): string {
|
|
36
|
+
return join(cwd, ".loam", "recipes");
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function validateRecipeShape(obj: unknown): obj is ProviderRecipe {
|
|
40
|
+
if (!obj || typeof obj !== "object") return false;
|
|
41
|
+
const r = obj as Record<string, unknown>;
|
|
42
|
+
return (
|
|
43
|
+
typeof r.install === "function" &&
|
|
44
|
+
typeof r.check === "function" &&
|
|
45
|
+
typeof r.remove === "function"
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function makeShellRecipe(name: string, scriptPath: string): ProviderRecipe {
|
|
50
|
+
const run = (action: "install" | "check" | "remove", cwd: string): Promise<RecipeResult> =>
|
|
51
|
+
new Promise((resolve) => {
|
|
52
|
+
const child = spawn(scriptPath, [action], {
|
|
53
|
+
cwd,
|
|
54
|
+
env: {
|
|
55
|
+
...process.env,
|
|
56
|
+
LOAM_RECIPE_NAME: name,
|
|
57
|
+
LOAM_RECIPE_ACTION: action,
|
|
58
|
+
},
|
|
59
|
+
stdio: ["ignore", "pipe", "pipe"],
|
|
60
|
+
});
|
|
61
|
+
let stdout = "";
|
|
62
|
+
let stderr = "";
|
|
63
|
+
child.stdout?.on("data", (d: Buffer) => {
|
|
64
|
+
stdout += d.toString();
|
|
65
|
+
});
|
|
66
|
+
child.stderr?.on("data", (d: Buffer) => {
|
|
67
|
+
stderr += d.toString();
|
|
68
|
+
});
|
|
69
|
+
child.on("error", (err) => {
|
|
70
|
+
resolve({
|
|
71
|
+
success: false,
|
|
72
|
+
message: `Failed to execute ${scriptPath}: ${err.message}`,
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
child.on("close", (code) => {
|
|
76
|
+
const out = stdout.trim();
|
|
77
|
+
const err = stderr.trim();
|
|
78
|
+
const ok = code === 0;
|
|
79
|
+
const fallback = ok
|
|
80
|
+
? `${name} ${action} succeeded`
|
|
81
|
+
: `${name} ${action} exited with code ${code ?? "?"}${err ? `: ${err}` : ""}`;
|
|
82
|
+
resolve({ success: ok, message: out || fallback });
|
|
83
|
+
});
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
return {
|
|
87
|
+
install: (cwd) => run("install", cwd),
|
|
88
|
+
check: (cwd) => run("check", cwd),
|
|
89
|
+
remove: (cwd) => run("remove", cwd),
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export async function loadFilesystemRecipe(
|
|
94
|
+
name: string,
|
|
95
|
+
cwd: string,
|
|
96
|
+
): Promise<RecipeWithSource | null> {
|
|
97
|
+
const dir = recipesDir(cwd);
|
|
98
|
+
const tsPath = join(dir, `${name}.ts`);
|
|
99
|
+
const shPath = join(dir, `${name}.sh`);
|
|
100
|
+
|
|
101
|
+
if (existsSync(tsPath)) {
|
|
102
|
+
const mod = (await import(tsPath)) as { default?: unknown };
|
|
103
|
+
// Spec is `export default { install, check, remove }`. Reject named-only
|
|
104
|
+
// exports — accepting them silently let users ship recipes that resolved
|
|
105
|
+
// in development (where they remembered the right named imports) but
|
|
106
|
+
// surprised the next consumer who imported them as a default.
|
|
107
|
+
if (mod.default === undefined) {
|
|
108
|
+
throw new Error(
|
|
109
|
+
`Recipe "${name}" at ${tsPath} has no default export. ProviderRecipes must be exposed via \`export default { install, check, remove }\`; named exports alone are not accepted. See examples/recipes/internal-ide.ts for a template.`,
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
if (!validateRecipeShape(mod.default)) {
|
|
113
|
+
throw new Error(
|
|
114
|
+
`Recipe "${name}" at ${tsPath} default export is not a valid ProviderRecipe (must have async install/check/remove functions). See examples/recipes/internal-ide.ts for a template.`,
|
|
115
|
+
);
|
|
116
|
+
}
|
|
117
|
+
return { name, source: "filesystem-ts", recipe: mod.default, path: tsPath };
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
if (existsSync(shPath)) {
|
|
121
|
+
return {
|
|
122
|
+
name,
|
|
123
|
+
source: "filesystem-sh",
|
|
124
|
+
recipe: makeShellRecipe(name, shPath),
|
|
125
|
+
path: shPath,
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return null;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export async function loadNpmRecipe(name: string, cwd: string): Promise<RecipeWithSource | null> {
|
|
133
|
+
const pkgName = `${NPM_RECIPE_PREFIX}${name}`;
|
|
134
|
+
const requireFn = createRequire(import.meta.url);
|
|
135
|
+
let resolved: string;
|
|
136
|
+
try {
|
|
137
|
+
resolved = requireFn.resolve(pkgName, { paths: [cwd] });
|
|
138
|
+
} catch {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
const mod = (await import(resolved)) as { default?: unknown };
|
|
142
|
+
if (mod.default === undefined) {
|
|
143
|
+
throw new Error(
|
|
144
|
+
`Recipe package "${pkgName}" has no default export. ProviderRecipes must be exposed via \`export default { install, check, remove }\`; named exports alone are not accepted.`,
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
if (!validateRecipeShape(mod.default)) {
|
|
148
|
+
throw new Error(
|
|
149
|
+
`Recipe package "${pkgName}" default export is not a valid ProviderRecipe (must have async install/check/remove functions).`,
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
return { name, source: "npm", recipe: mod.default, path: resolved };
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export async function listFilesystemRecipes(cwd: string): Promise<FilesystemRecipeListing[]> {
|
|
156
|
+
const dir = recipesDir(cwd);
|
|
157
|
+
if (!existsSync(dir)) return [];
|
|
158
|
+
const entries = await readdir(dir);
|
|
159
|
+
const out: FilesystemRecipeListing[] = [];
|
|
160
|
+
for (const entry of entries) {
|
|
161
|
+
if (entry.endsWith(".ts")) {
|
|
162
|
+
out.push({
|
|
163
|
+
name: entry.slice(0, -3),
|
|
164
|
+
source: "filesystem-ts",
|
|
165
|
+
path: join(dir, entry),
|
|
166
|
+
});
|
|
167
|
+
} else if (entry.endsWith(".sh")) {
|
|
168
|
+
out.push({
|
|
169
|
+
name: entry.slice(0, -3),
|
|
170
|
+
source: "filesystem-sh",
|
|
171
|
+
path: join(dir, entry),
|
|
172
|
+
});
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
return out.sort((a, b) => a.name.localeCompare(b.name));
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export async function resolveRecipe(
|
|
179
|
+
name: string,
|
|
180
|
+
cwd: string,
|
|
181
|
+
builtins: Record<string, ProviderRecipe>,
|
|
182
|
+
): Promise<RecipeWithSource | null> {
|
|
183
|
+
const fs = await loadFilesystemRecipe(name, cwd);
|
|
184
|
+
if (fs) return fs;
|
|
185
|
+
|
|
186
|
+
const npm = await loadNpmRecipe(name, cwd);
|
|
187
|
+
if (npm) return npm;
|
|
188
|
+
|
|
189
|
+
const builtin = builtins[name];
|
|
190
|
+
if (builtin) {
|
|
191
|
+
return { name, source: "builtin", recipe: builtin };
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
return null;
|
|
195
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// Process-wide runtime flags set during CLI bootstrap. Mirrors the
|
|
2
|
+
// setQuiet/isQuiet pattern in palette.ts so global CLI options can opt
|
|
3
|
+
// commands out of strict policies without threading the flag through
|
|
4
|
+
// every function signature.
|
|
5
|
+
|
|
6
|
+
let _allowUnknownTypes = false;
|
|
7
|
+
let _allowDomainMismatch = false;
|
|
8
|
+
|
|
9
|
+
export function setAllowUnknownTypes(value: boolean): void {
|
|
10
|
+
_allowUnknownTypes = value;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function isAllowUnknownTypes(): boolean {
|
|
14
|
+
return _allowUnknownTypes;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function setAllowDomainMismatch(value: boolean): void {
|
|
18
|
+
_allowDomainMismatch = value;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function isAllowDomainMismatch(): boolean {
|
|
22
|
+
return _allowDomainMismatch;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function resetRuntimeFlags(): void {
|
|
26
|
+
_allowUnknownTypes = false;
|
|
27
|
+
_allowDomainMismatch = false;
|
|
28
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import type { ExpertiseRecord, Outcome } from "../schemas/record.ts";
|
|
2
|
+
|
|
3
|
+
export type { Outcome };
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* An ExpertiseRecord with outcome history for confirmation-frequency scoring.
|
|
7
|
+
* Since ExpertiseRecord now includes outcomes?: Outcome[], this is an alias.
|
|
8
|
+
*/
|
|
9
|
+
export type ScoredRecord = ExpertiseRecord;
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Returns the number of successful outcomes for a record.
|
|
13
|
+
* Successful outcomes indicate confirmed, working applications of the record.
|
|
14
|
+
*/
|
|
15
|
+
export function getSuccessCount(record: ScoredRecord): number {
|
|
16
|
+
if (!record.outcomes || record.outcomes.length === 0) return 0;
|
|
17
|
+
return record.outcomes.filter((o) => o.status === "success").length;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Returns the number of failed outcomes for a record.
|
|
22
|
+
*/
|
|
23
|
+
export function getFailureCount(record: ScoredRecord): number {
|
|
24
|
+
if (!record.outcomes || record.outcomes.length === 0) return 0;
|
|
25
|
+
return record.outcomes.filter((o) => o.status === "failure").length;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Returns the total number of recorded outcomes (applications) for a record.
|
|
30
|
+
*/
|
|
31
|
+
export function getTotalApplications(record: ScoredRecord): number {
|
|
32
|
+
return record.outcomes?.length ?? 0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Returns the success rate (0-1) for a record.
|
|
37
|
+
* Partial outcomes are counted as 0.5 (half success).
|
|
38
|
+
* Returns 0 for records with no outcomes.
|
|
39
|
+
*/
|
|
40
|
+
export function getSuccessRate(record: ScoredRecord): number {
|
|
41
|
+
const total = getTotalApplications(record);
|
|
42
|
+
if (total === 0) return 0;
|
|
43
|
+
const partialCount = record.outcomes?.filter((o) => o.status === "partial").length ?? 0;
|
|
44
|
+
const successCount = getSuccessCount(record);
|
|
45
|
+
return (successCount + partialCount * 0.5) / total;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Computes the confirmation-frequency score for a record.
|
|
50
|
+
*
|
|
51
|
+
* The score is the count of successful confirmations (applications where
|
|
52
|
+
* the record's guidance was applied and the outcome was "success").
|
|
53
|
+
* Partial outcomes contribute 0.5 to the score.
|
|
54
|
+
*
|
|
55
|
+
* Records with no outcomes return 0.
|
|
56
|
+
* Records with only failures return 0.
|
|
57
|
+
*/
|
|
58
|
+
export function computeConfirmationScore(record: ScoredRecord): number {
|
|
59
|
+
if (!record.outcomes || record.outcomes.length === 0) return 0;
|
|
60
|
+
const successCount = getSuccessCount(record);
|
|
61
|
+
const partialCount = record.outcomes.filter((o) => o.status === "partial").length;
|
|
62
|
+
return successCount + partialCount * 0.5;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Applies a confirmation-frequency boost to a base score (e.g., a BM25 relevance score).
|
|
67
|
+
*
|
|
68
|
+
* Records with no outcomes (score = 0) are returned unchanged.
|
|
69
|
+
* Records with confirmed applications receive a multiplicative boost proportional
|
|
70
|
+
* to their confirmation score.
|
|
71
|
+
*
|
|
72
|
+
* @param baseScore - The base relevance score (e.g., from BM25)
|
|
73
|
+
* @param record - The record to score
|
|
74
|
+
* @param boostFactor - Multiplier controlling boost magnitude (default: 0.1)
|
|
75
|
+
* @returns The boosted score
|
|
76
|
+
*/
|
|
77
|
+
export function applyConfirmationBoost(
|
|
78
|
+
baseScore: number,
|
|
79
|
+
record: ScoredRecord,
|
|
80
|
+
boostFactor = 0.1,
|
|
81
|
+
): number {
|
|
82
|
+
const confirmationScore = computeConfirmationScore(record);
|
|
83
|
+
if (confirmationScore === 0) return baseScore;
|
|
84
|
+
return baseScore * (1 + boostFactor * confirmationScore);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Sorts records by confirmation-frequency score, highest first.
|
|
89
|
+
* Records with equal scores maintain their original relative order (stable sort).
|
|
90
|
+
* Records with no outcomes (score = 0) sort to the end.
|
|
91
|
+
*/
|
|
92
|
+
export function sortByConfirmationScore<T extends ScoredRecord>(records: T[]): T[] {
|
|
93
|
+
return [...records].sort((a, b) => computeConfirmationScore(b) - computeConfirmationScore(a));
|
|
94
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { execFileSync } from "node:child_process";
|
|
2
|
+
import { VERSION } from "../../../version.ts";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Current CLI version. loam is now bundled in @ag-eco/agentplate-cli, so the
|
|
6
|
+
* version comes from the shared package version (src/version.ts) rather than a
|
|
7
|
+
* package.json read relative to this file.
|
|
8
|
+
*/
|
|
9
|
+
export function getCurrentVersion(): string {
|
|
10
|
+
return VERSION;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Fetch the latest published version of loam-cli from npm.
|
|
15
|
+
* Returns null if the registry is unreachable.
|
|
16
|
+
*/
|
|
17
|
+
export function getLatestVersion(): string | null {
|
|
18
|
+
try {
|
|
19
|
+
const result = execFileSync("npm", ["view", "@ag-eco/loam-cli", "version"], {
|
|
20
|
+
encoding: "utf-8",
|
|
21
|
+
timeout: 10000,
|
|
22
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
23
|
+
});
|
|
24
|
+
return result.trim();
|
|
25
|
+
} catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Split a semver string into its main (major.minor.patch) segment and its
|
|
32
|
+
* optional prerelease tail. Build metadata (after `+`) is ignored per semver
|
|
33
|
+
* 2.0.0 precedence rules.
|
|
34
|
+
*/
|
|
35
|
+
function splitSemver(v: string): { main: string; prerelease: string | null } {
|
|
36
|
+
const noBuild = v.split("+", 1)[0] ?? v;
|
|
37
|
+
const dashIdx = noBuild.indexOf("-");
|
|
38
|
+
if (dashIdx === -1) return { main: noBuild, prerelease: null };
|
|
39
|
+
return {
|
|
40
|
+
main: noBuild.slice(0, dashIdx),
|
|
41
|
+
prerelease: noBuild.slice(dashIdx + 1),
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Parse a single main-version segment to a non-negative integer. Returns 0
|
|
47
|
+
* for empty / non-numeric input so e.g. `"1.2"` still compares cleanly
|
|
48
|
+
* against `"1.2.0"`.
|
|
49
|
+
*/
|
|
50
|
+
function parseMainSegment(s: string | undefined): number {
|
|
51
|
+
if (!s) return 0;
|
|
52
|
+
const n = Number(s);
|
|
53
|
+
return Number.isFinite(n) && n >= 0 ? Math.trunc(n) : 0;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Compare two prerelease identifier lists per semver 2.0.0 §11.4:
|
|
58
|
+
* - identifiers are split on '.'
|
|
59
|
+
* - numeric identifiers compare numerically and rank below non-numeric
|
|
60
|
+
* - non-numeric identifiers compare lexically (ASCII)
|
|
61
|
+
* - a longer prerelease list wins when all leading identifiers match
|
|
62
|
+
*/
|
|
63
|
+
function comparePrerelease(a: string, b: string): -1 | 0 | 1 {
|
|
64
|
+
const idsA = a.split(".");
|
|
65
|
+
const idsB = b.split(".");
|
|
66
|
+
const len = Math.max(idsA.length, idsB.length);
|
|
67
|
+
for (let i = 0; i < len; i++) {
|
|
68
|
+
const x = idsA[i];
|
|
69
|
+
const y = idsB[i];
|
|
70
|
+
if (x === undefined) return -1;
|
|
71
|
+
if (y === undefined) return 1;
|
|
72
|
+
const xNumeric = /^\d+$/.test(x);
|
|
73
|
+
const yNumeric = /^\d+$/.test(y);
|
|
74
|
+
if (xNumeric && yNumeric) {
|
|
75
|
+
const nx = Number(x);
|
|
76
|
+
const ny = Number(y);
|
|
77
|
+
if (nx < ny) return -1;
|
|
78
|
+
if (nx > ny) return 1;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (xNumeric) return -1;
|
|
82
|
+
if (yNumeric) return 1;
|
|
83
|
+
if (x < y) return -1;
|
|
84
|
+
if (x > y) return 1;
|
|
85
|
+
}
|
|
86
|
+
return 0;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Compare two semver strings (major.minor.patch with optional prerelease).
|
|
91
|
+
* Returns -1 if a < b, 0 if equal, 1 if a > b.
|
|
92
|
+
*
|
|
93
|
+
* Handles prerelease / non-numeric segments per semver 2.0.0: a version with
|
|
94
|
+
* a prerelease tail (e.g. "1.2.3-beta") ranks below the same main version
|
|
95
|
+
* without one ("1.2.3"), and never causes a misleading 0 result when the
|
|
96
|
+
* main components differ.
|
|
97
|
+
*/
|
|
98
|
+
export function compareSemver(a: string, b: string): -1 | 0 | 1 {
|
|
99
|
+
const sa = splitSemver(a);
|
|
100
|
+
const sb = splitSemver(b);
|
|
101
|
+
const partsA = sa.main.split(".");
|
|
102
|
+
const partsB = sb.main.split(".");
|
|
103
|
+
|
|
104
|
+
for (let i = 0; i < 3; i++) {
|
|
105
|
+
const segA = parseMainSegment(partsA[i]);
|
|
106
|
+
const segB = parseMainSegment(partsB[i]);
|
|
107
|
+
if (segA < segB) return -1;
|
|
108
|
+
if (segA > segB) return 1;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// Main parts equal — apply prerelease precedence.
|
|
112
|
+
if (sa.prerelease === null && sb.prerelease === null) return 0;
|
|
113
|
+
if (sa.prerelease === null) return 1; // a is release, b is prerelease
|
|
114
|
+
if (sb.prerelease === null) return -1;
|
|
115
|
+
return comparePrerelease(sa.prerelease, sb.prerelease);
|
|
116
|
+
}
|