modelrig 0.0.1 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +94 -0
- package/LICENSE +201 -0
- package/README.md +145 -8
- package/data/PROVENANCE.md +19 -0
- package/data/pricing-manual.json +22 -0
- package/data/pricing-map.json +46362 -0
- package/data/pricing-overlay.json +419 -0
- package/dist/adapters/anthropic.d.ts +90 -0
- package/dist/adapters/anthropic.d.ts.map +1 -0
- package/dist/adapters/anthropic.js +296 -0
- package/dist/adapters/build-adapters.d.ts +11 -0
- package/dist/adapters/build-adapters.d.ts.map +1 -0
- package/dist/adapters/build-adapters.js +45 -0
- package/dist/adapters/deepseek.d.ts +47 -0
- package/dist/adapters/deepseek.d.ts.map +1 -0
- package/dist/adapters/deepseek.js +216 -0
- package/dist/adapters/gemini.d.ts +44 -0
- package/dist/adapters/gemini.d.ts.map +1 -0
- package/dist/adapters/gemini.js +262 -0
- package/dist/adapters/grok.d.ts +53 -0
- package/dist/adapters/grok.d.ts.map +1 -0
- package/dist/adapters/grok.js +232 -0
- package/dist/adapters/openai-compat.d.ts +80 -0
- package/dist/adapters/openai-compat.d.ts.map +1 -0
- package/dist/adapters/openai-compat.js +244 -0
- package/dist/adapters/openai-stream.d.ts +58 -0
- package/dist/adapters/openai-stream.d.ts.map +1 -0
- package/dist/adapters/openai-stream.js +120 -0
- package/dist/adapters/openai.d.ts +55 -0
- package/dist/adapters/openai.d.ts.map +1 -0
- package/dist/adapters/openai.js +281 -0
- package/dist/adapters/sampling.d.ts +28 -0
- package/dist/adapters/sampling.d.ts.map +1 -0
- package/dist/adapters/sampling.js +34 -0
- package/dist/adapters/tool-mapping.d.ts +92 -0
- package/dist/adapters/tool-mapping.d.ts.map +1 -0
- package/dist/adapters/tool-mapping.js +143 -0
- package/dist/artifacts/artifact.d.ts +137 -0
- package/dist/artifacts/artifact.d.ts.map +1 -0
- package/dist/artifacts/artifact.js +377 -0
- package/dist/artifacts/content-uploader.d.ts +87 -0
- package/dist/artifacts/content-uploader.d.ts.map +1 -0
- package/dist/artifacts/content-uploader.js +124 -0
- package/dist/artifacts/index.d.ts +63 -0
- package/dist/artifacts/index.d.ts.map +1 -0
- package/dist/artifacts/index.js +80 -0
- package/dist/artifacts/run-context.d.ts +129 -0
- package/dist/artifacts/run-context.d.ts.map +1 -0
- package/dist/artifacts/run-context.js +208 -0
- package/dist/artifacts/scrub.d.ts +60 -0
- package/dist/artifacts/scrub.d.ts.map +1 -0
- package/dist/artifacts/scrub.js +139 -0
- package/dist/artifacts/step.d.ts +26 -0
- package/dist/artifacts/step.d.ts.map +1 -0
- package/dist/artifacts/step.js +37 -0
- package/dist/artifacts/taint.d.ts +63 -0
- package/dist/artifacts/taint.d.ts.map +1 -0
- package/dist/artifacts/taint.js +76 -0
- package/dist/bakeoff/cache-sim.d.ts +99 -0
- package/dist/bakeoff/cache-sim.d.ts.map +1 -0
- package/dist/bakeoff/cache-sim.js +126 -0
- package/dist/bakeoff/engine.d.ts +52 -0
- package/dist/bakeoff/engine.d.ts.map +1 -0
- package/dist/bakeoff/engine.js +163 -0
- package/dist/bakeoff/eval-cases.d.ts +96 -0
- package/dist/bakeoff/eval-cases.d.ts.map +1 -0
- package/dist/bakeoff/eval-cases.js +105 -0
- package/dist/bakeoff/replay.d.ts +52 -0
- package/dist/bakeoff/replay.d.ts.map +1 -0
- package/dist/bakeoff/replay.js +94 -0
- package/dist/bakeoff/report.d.ts +41 -0
- package/dist/bakeoff/report.d.ts.map +1 -0
- package/dist/bakeoff/report.js +142 -0
- package/dist/bakeoff/samples.d.ts +77 -0
- package/dist/bakeoff/samples.d.ts.map +1 -0
- package/dist/bakeoff/samples.js +148 -0
- package/dist/bakeoff/stats.d.ts +13 -0
- package/dist/bakeoff/stats.d.ts.map +1 -0
- package/dist/bakeoff/stats.js +48 -0
- package/dist/bakeoff/types.d.ts +37 -0
- package/dist/bakeoff/types.d.ts.map +1 -0
- package/dist/bakeoff/types.js +10 -0
- package/dist/cli.d.ts +25 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +590 -0
- package/dist/config.d.ts +204 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +252 -0
- package/dist/deprecations.d.ts +32 -0
- package/dist/deprecations.d.ts.map +1 -0
- package/dist/deprecations.js +59 -0
- package/dist/feedback/coverage.d.ts +32 -0
- package/dist/feedback/coverage.d.ts.map +1 -0
- package/dist/feedback/coverage.js +95 -0
- package/dist/feedback/feedback.d.ts +35 -0
- package/dist/feedback/feedback.d.ts.map +1 -0
- package/dist/feedback/feedback.js +39 -0
- package/dist/gateway/http-protocol.d.ts +175 -0
- package/dist/gateway/http-protocol.d.ts.map +1 -0
- package/dist/gateway/http-protocol.js +105 -0
- package/dist/index.d.ts +242 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +576 -0
- package/dist/init/finder.d.ts +94 -0
- package/dist/init/finder.d.ts.map +1 -0
- package/dist/init/finder.js +343 -0
- package/dist/init/init-cli.d.ts +10 -0
- package/dist/init/init-cli.d.ts.map +1 -0
- package/dist/init/init-cli.js +86 -0
- package/dist/init/observe-cli.d.ts +19 -0
- package/dist/init/observe-cli.d.ts.map +1 -0
- package/dist/init/observe-cli.js +73 -0
- package/dist/init/observe.d.ts +81 -0
- package/dist/init/observe.d.ts.map +1 -0
- package/dist/init/observe.js +245 -0
- package/dist/init/run.d.ts +99 -0
- package/dist/init/run.d.ts.map +1 -0
- package/dist/init/run.js +281 -0
- package/dist/init/signatures.d.ts +39 -0
- package/dist/init/signatures.d.ts.map +1 -0
- package/dist/init/signatures.js +116 -0
- package/dist/matrix/aggregate.d.ts +89 -0
- package/dist/matrix/aggregate.d.ts.map +1 -0
- package/dist/matrix/aggregate.js +186 -0
- package/dist/query/grammar.d.ts +35 -0
- package/dist/query/grammar.d.ts.map +1 -0
- package/dist/query/grammar.js +279 -0
- package/dist/query/run.d.ts +8 -0
- package/dist/query/run.d.ts.map +1 -0
- package/dist/query/run.js +21 -0
- package/dist/registry/build.d.ts +219 -0
- package/dist/registry/build.d.ts.map +1 -0
- package/dist/registry/build.js +313 -0
- package/dist/registry/cache-policy.d.ts +94 -0
- package/dist/registry/cache-policy.d.ts.map +1 -0
- package/dist/registry/cache-policy.js +238 -0
- package/dist/registry/call-notes.d.ts +11 -0
- package/dist/registry/call-notes.d.ts.map +1 -0
- package/dist/registry/call-notes.js +110 -0
- package/dist/registry/claims.d.ts +63 -0
- package/dist/registry/claims.d.ts.map +1 -0
- package/dist/registry/claims.js +107 -0
- package/dist/registry/effective-rate.d.ts +151 -0
- package/dist/registry/effective-rate.d.ts.map +1 -0
- package/dist/registry/effective-rate.js +156 -0
- package/dist/registry/facts.d.ts +32 -0
- package/dist/registry/facts.d.ts.map +1 -0
- package/dist/registry/facts.js +136 -0
- package/dist/registry/fingerprint.d.ts +20 -0
- package/dist/registry/fingerprint.d.ts.map +1 -0
- package/dist/registry/fingerprint.js +150 -0
- package/dist/registry/parity.d.ts +52 -0
- package/dist/registry/parity.d.ts.map +1 -0
- package/dist/registry/parity.js +82 -0
- package/dist/registry/pricing-shape.d.ts +113 -0
- package/dist/registry/pricing-shape.d.ts.map +1 -0
- package/dist/registry/pricing-shape.js +123 -0
- package/dist/registry/pricing.d.ts +43 -0
- package/dist/registry/pricing.d.ts.map +1 -0
- package/dist/registry/pricing.js +127 -0
- package/dist/registry/rows.d.ts +16 -0
- package/dist/registry/rows.d.ts.map +1 -0
- package/dist/registry/rows.js +57 -0
- package/dist/registry/seed.d.ts +43 -0
- package/dist/registry/seed.d.ts.map +1 -0
- package/dist/registry/seed.js +97 -0
- package/dist/registry/select.d.ts +68 -0
- package/dist/registry/select.d.ts.map +1 -0
- package/dist/registry/select.js +141 -0
- package/dist/registry/staleness.d.ts +18 -0
- package/dist/registry/staleness.d.ts.map +1 -0
- package/dist/registry/staleness.js +39 -0
- package/dist/rigindex/bootstrap.d.ts +36 -0
- package/dist/rigindex/bootstrap.d.ts.map +1 -0
- package/dist/rigindex/bootstrap.js +97 -0
- package/dist/rigindex/fit.d.ts +24 -0
- package/dist/rigindex/fit.d.ts.map +1 -0
- package/dist/rigindex/fit.js +76 -0
- package/dist/rigindex/gates.d.ts +52 -0
- package/dist/rigindex/gates.d.ts.map +1 -0
- package/dist/rigindex/gates.js +109 -0
- package/dist/rigindex/graph.d.ts +31 -0
- package/dist/rigindex/graph.d.ts.map +1 -0
- package/dist/rigindex/graph.js +120 -0
- package/dist/rigindex/index.d.ts +23 -0
- package/dist/rigindex/index.d.ts.map +1 -0
- package/dist/rigindex/index.js +112 -0
- package/dist/rigindex/types.d.ts +76 -0
- package/dist/rigindex/types.d.ts.map +1 -0
- package/dist/rigindex/types.js +8 -0
- package/dist/routes/cache-lint.d.ts +41 -0
- package/dist/routes/cache-lint.d.ts.map +1 -0
- package/dist/routes/cache-lint.js +81 -0
- package/dist/routes/draft.d.ts +83 -0
- package/dist/routes/draft.d.ts.map +1 -0
- package/dist/routes/draft.js +135 -0
- package/dist/routes/loader.d.ts +63 -0
- package/dist/routes/loader.d.ts.map +1 -0
- package/dist/routes/loader.js +574 -0
- package/dist/routes/manifest.d.ts +24 -0
- package/dist/routes/manifest.d.ts.map +1 -0
- package/dist/routes/manifest.js +118 -0
- package/dist/routes/resolved-bundle.d.ts +79 -0
- package/dist/routes/resolved-bundle.d.ts.map +1 -0
- package/dist/routes/resolved-bundle.js +148 -0
- package/dist/routes/sampling-config.d.ts +32 -0
- package/dist/routes/sampling-config.d.ts.map +1 -0
- package/dist/routes/sampling-config.js +91 -0
- package/dist/routes/serveability.d.ts +52 -0
- package/dist/routes/serveability.d.ts.map +1 -0
- package/dist/routes/serveability.js +73 -0
- package/dist/routes/template.d.ts +18 -0
- package/dist/routes/template.d.ts.map +1 -0
- package/dist/routes/template.js +94 -0
- package/dist/run/ajv.d.ts +22 -0
- package/dist/run/ajv.d.ts.map +1 -0
- package/dist/run/ajv.js +32 -0
- package/dist/run/cache-handle.d.ts +58 -0
- package/dist/run/cache-handle.d.ts.map +1 -0
- package/dist/run/cache-handle.js +54 -0
- package/dist/run/cache-stamp.d.ts +65 -0
- package/dist/run/cache-stamp.d.ts.map +1 -0
- package/dist/run/cache-stamp.js +0 -0
- package/dist/run/capture-write.d.ts +33 -0
- package/dist/run/capture-write.d.ts.map +1 -0
- package/dist/run/capture-write.js +55 -0
- package/dist/run/cost.d.ts +26 -0
- package/dist/run/cost.d.ts.map +1 -0
- package/dist/run/cost.js +41 -0
- package/dist/run/dispatch.d.ts +99 -0
- package/dist/run/dispatch.d.ts.map +1 -0
- package/dist/run/dispatch.js +191 -0
- package/dist/run/envelope.d.ts +21 -0
- package/dist/run/envelope.d.ts.map +1 -0
- package/dist/run/envelope.js +45 -0
- package/dist/run/grounding.d.ts +56 -0
- package/dist/run/grounding.d.ts.map +1 -0
- package/dist/run/grounding.js +89 -0
- package/dist/run/raw.d.ts +88 -0
- package/dist/run/raw.d.ts.map +1 -0
- package/dist/run/raw.js +286 -0
- package/dist/run/record-attempt.d.ts +40 -0
- package/dist/run/record-attempt.d.ts.map +1 -0
- package/dist/run/record-attempt.js +99 -0
- package/dist/run/repair.d.ts +36 -0
- package/dist/run/repair.d.ts.map +1 -0
- package/dist/run/repair.js +61 -0
- package/dist/run/resolve.d.ts +99 -0
- package/dist/run/resolve.d.ts.map +1 -0
- package/dist/run/resolve.js +203 -0
- package/dist/run/retry.d.ts +19 -0
- package/dist/run/retry.d.ts.map +1 -0
- package/dist/run/retry.js +50 -0
- package/dist/run/run.d.ts +55 -0
- package/dist/run/run.d.ts.map +1 -0
- package/dist/run/run.js +540 -0
- package/dist/run/stream.d.ts +49 -0
- package/dist/run/stream.d.ts.map +1 -0
- package/dist/run/stream.js +87 -0
- package/dist/run/validate.d.ts +15 -0
- package/dist/run/validate.d.ts.map +1 -0
- package/dist/run/validate.js +55 -0
- package/dist/savings/cache-ledger.d.ts +108 -0
- package/dist/savings/cache-ledger.d.ts.map +1 -0
- package/dist/savings/cache-ledger.js +174 -0
- package/dist/savings/cache-reconcile.d.ts +64 -0
- package/dist/savings/cache-reconcile.d.ts.map +1 -0
- package/dist/savings/cache-reconcile.js +59 -0
- package/dist/savings/cache-stats.d.ts +63 -0
- package/dist/savings/cache-stats.d.ts.map +1 -0
- package/dist/savings/cache-stats.js +108 -0
- package/dist/savings/emit.d.ts +38 -0
- package/dist/savings/emit.d.ts.map +1 -0
- package/dist/savings/emit.js +100 -0
- package/dist/savings/odometer.d.ts +32 -0
- package/dist/savings/odometer.d.ts.map +1 -0
- package/dist/savings/odometer.js +70 -0
- package/dist/savings/swap-execute.d.ts +58 -0
- package/dist/savings/swap-execute.d.ts.map +1 -0
- package/dist/savings/swap-execute.js +130 -0
- package/dist/savings/swaps-client.d.ts +55 -0
- package/dist/savings/swaps-client.d.ts.map +1 -0
- package/dist/savings/swaps-client.js +95 -0
- package/dist/settings/api-fetcher.d.ts +39 -0
- package/dist/settings/api-fetcher.d.ts.map +1 -0
- package/dist/settings/api-fetcher.js +92 -0
- package/dist/settings/index.d.ts +10 -0
- package/dist/settings/index.d.ts.map +1 -0
- package/dist/settings/index.js +15 -0
- package/dist/settings/task-settings.d.ts +91 -0
- package/dist/settings/task-settings.d.ts.map +1 -0
- package/dist/settings/task-settings.js +116 -0
- package/dist/status.d.ts +77 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +113 -0
- package/dist/telemetry/artifact-store.d.ts +48 -0
- package/dist/telemetry/artifact-store.d.ts.map +1 -0
- package/dist/telemetry/artifact-store.js +189 -0
- package/dist/telemetry/cache-miss-streak.d.ts +79 -0
- package/dist/telemetry/cache-miss-streak.d.ts.map +1 -0
- package/dist/telemetry/cache-miss-streak.js +99 -0
- package/dist/telemetry/capture.d.ts +31 -0
- package/dist/telemetry/capture.d.ts.map +1 -0
- package/dist/telemetry/capture.js +81 -0
- package/dist/telemetry/exporter-setup.d.ts +28 -0
- package/dist/telemetry/exporter-setup.d.ts.map +1 -0
- package/dist/telemetry/exporter-setup.js +34 -0
- package/dist/telemetry/exporter.d.ts +137 -0
- package/dist/telemetry/exporter.d.ts.map +1 -0
- package/dist/telemetry/exporter.js +510 -0
- package/dist/telemetry/health.d.ts +76 -0
- package/dist/telemetry/health.d.ts.map +1 -0
- package/dist/telemetry/health.js +92 -0
- package/dist/telemetry/ingest-protocol.d.ts +310 -0
- package/dist/telemetry/ingest-protocol.d.ts.map +1 -0
- package/dist/telemetry/ingest-protocol.js +363 -0
- package/dist/telemetry/load-error-report.d.ts +24 -0
- package/dist/telemetry/load-error-report.d.ts.map +1 -0
- package/dist/telemetry/load-error-report.js +50 -0
- package/dist/telemetry/otel-map.d.ts +121 -0
- package/dist/telemetry/otel-map.d.ts.map +1 -0
- package/dist/telemetry/otel-map.js +224 -0
- package/dist/telemetry/otel-normalize.d.ts +104 -0
- package/dist/telemetry/otel-normalize.d.ts.map +1 -0
- package/dist/telemetry/otel-normalize.js +530 -0
- package/dist/telemetry/otlp-emitter.d.ts +52 -0
- package/dist/telemetry/otlp-emitter.d.ts.map +1 -0
- package/dist/telemetry/otlp-emitter.js +144 -0
- package/dist/telemetry/otlp-proto.d.ts +29 -0
- package/dist/telemetry/otlp-proto.d.ts.map +1 -0
- package/dist/telemetry/otlp-proto.js +266 -0
- package/dist/telemetry/sinks.d.ts +90 -0
- package/dist/telemetry/sinks.d.ts.map +1 -0
- package/dist/telemetry/sinks.js +180 -0
- package/dist/telemetry/store.d.ts +65 -0
- package/dist/telemetry/store.d.ts.map +1 -0
- package/dist/telemetry/store.js +547 -0
- package/dist/tenancy/api-key-format.d.ts +77 -0
- package/dist/tenancy/api-key-format.d.ts.map +1 -0
- package/dist/tenancy/api-key-format.js +110 -0
- package/dist/tenancy/constants.d.ts +23 -0
- package/dist/tenancy/constants.d.ts.map +1 -0
- package/dist/tenancy/constants.js +25 -0
- package/dist/tenancy/scrub.d.ts +47 -0
- package/dist/tenancy/scrub.d.ts.map +1 -0
- package/dist/tenancy/scrub.js +85 -0
- package/dist/types/config-teaching.d.ts +62 -0
- package/dist/types/config-teaching.d.ts.map +1 -0
- package/dist/types/config-teaching.js +183 -0
- package/dist/types/failures-teaching.d.ts +56 -0
- package/dist/types/failures-teaching.d.ts.map +1 -0
- package/dist/types/failures-teaching.js +177 -0
- package/dist/types/failures.d.ts +27 -0
- package/dist/types/failures.d.ts.map +1 -0
- package/dist/types/failures.js +41 -0
- package/dist/types/provider.d.ts +200 -0
- package/dist/types/provider.d.ts.map +1 -0
- package/dist/types/provider.js +40 -0
- package/dist/types/route.d.ts +205 -0
- package/dist/types/route.d.ts.map +1 -0
- package/dist/types/route.js +6 -0
- package/dist/types/telemetry.d.ts +206 -0
- package/dist/types/telemetry.d.ts.map +1 -0
- package/dist/types/telemetry.js +6 -0
- package/dist/validate-cli.d.ts +12 -0
- package/dist/validate-cli.d.ts.map +1 -0
- package/dist/validate-cli.js +57 -0
- package/dist/verify/capture.d.ts +66 -0
- package/dist/verify/capture.d.ts.map +1 -0
- package/dist/verify/capture.js +180 -0
- package/dist/verify/cli-run.d.ts +23 -0
- package/dist/verify/cli-run.d.ts.map +1 -0
- package/dist/verify/cli-run.js +57 -0
- package/dist/verify/diff.d.ts +48 -0
- package/dist/verify/diff.d.ts.map +1 -0
- package/dist/verify/diff.js +157 -0
- package/dist/verify/index.d.ts +17 -0
- package/dist/verify/index.d.ts.map +1 -0
- package/dist/verify/index.js +24 -0
- package/dist/verify/report.d.ts +14 -0
- package/dist/verify/report.d.ts.map +1 -0
- package/dist/verify/report.js +88 -0
- package/dist/verify/types.d.ts +101 -0
- package/dist/verify/types.d.ts.map +1 -0
- package/dist/verify/types.js +17 -0
- package/dist/verify/verify.d.ts +29 -0
- package/dist/verify/verify.d.ts.map +1 -0
- package/dist/verify/verify.js +148 -0
- package/dist/watch/budget.d.ts +19 -0
- package/dist/watch/budget.d.ts.map +1 -0
- package/dist/watch/budget.js +35 -0
- package/dist/watch/evaluate.d.ts +225 -0
- package/dist/watch/evaluate.d.ts.map +1 -0
- package/dist/watch/evaluate.js +155 -0
- package/dist/watch/monitor.d.ts +116 -0
- package/dist/watch/monitor.d.ts.map +1 -0
- package/dist/watch/monitor.js +199 -0
- package/dist/watch/proposals.d.ts +89 -0
- package/dist/watch/proposals.d.ts.map +1 -0
- package/dist/watch/proposals.js +197 -0
- package/dist/watch/run-record.d.ts +64 -0
- package/dist/watch/run-record.d.ts.map +1 -0
- package/dist/watch/run-record.js +86 -0
- package/dist/watch/run-reported.d.ts +20 -0
- package/dist/watch/run-reported.d.ts.map +1 -0
- package/dist/watch/run-reported.js +53 -0
- package/dist/watch/run.d.ts +73 -0
- package/dist/watch/run.d.ts.map +1 -0
- package/dist/watch/run.js +83 -0
- package/dist/watch/state-store.d.ts +48 -0
- package/dist/watch/state-store.d.ts.map +1 -0
- package/dist/watch/state-store.js +86 -0
- package/dist/watch/state.d.ts +21 -0
- package/dist/watch/state.d.ts.map +1 -0
- package/dist/watch/state.js +93 -0
- package/package.json +56 -14
- package/registry/LICENSE +20 -0
- package/registry/leaderboard.json +3639 -0
- package/registry/registry.json +7263 -0
- package/index.js +0 -3
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider call-site finder — `modelrig init` v0 (spec WS2).
|
|
3
|
+
*
|
|
4
|
+
* AST-lite on purpose: a balanced-brace reader over the call's options
|
|
5
|
+
* object, not a TypeScript parser. The job is to find call sites and read
|
|
6
|
+
* the handful of literals that matter (model, system prompt, schema hint,
|
|
7
|
+
* generation params) well enough to DRAFT a route a human will review. It is
|
|
8
|
+
* allowed to be unsure — every uncertainty is recorded as a `note` on the
|
|
9
|
+
* site rather than guessed into the output, because a confident wrong draft
|
|
10
|
+
* is worse than an honest incomplete one.
|
|
11
|
+
*
|
|
12
|
+
* Generic by construction: everything provider-specific lives in
|
|
13
|
+
* signatures.ts. No repo, framework, or company is special-cased.
|
|
14
|
+
*/
|
|
15
|
+
export interface CallSiteParams {
|
|
16
|
+
readonly temperature?: number;
|
|
17
|
+
readonly topP?: number;
|
|
18
|
+
readonly maxTokens?: number;
|
|
19
|
+
readonly timeoutMs?: number;
|
|
20
|
+
}
|
|
21
|
+
export interface CallSite {
|
|
22
|
+
readonly file: string;
|
|
23
|
+
/** 1-indexed line of the call expression. */
|
|
24
|
+
readonly line: number;
|
|
25
|
+
readonly provider: string;
|
|
26
|
+
/** Model id when it was a literal; null when it came from a variable. */
|
|
27
|
+
readonly model: string | null;
|
|
28
|
+
/** The identifier the model came from, when it wasn't a literal. */
|
|
29
|
+
readonly modelExpression: string | null;
|
|
30
|
+
/** Literal system prompt when inline; null when referenced or absent. */
|
|
31
|
+
readonly systemPrompt: string | null;
|
|
32
|
+
/** The caller asked for structured output (schema/JSON mode present). */
|
|
33
|
+
readonly wantsStructuredOutput: boolean;
|
|
34
|
+
/** How the schema was expressed, when we could tell: zod | json-schema | json-mode. */
|
|
35
|
+
readonly schemaHint: string | null;
|
|
36
|
+
readonly params: CallSiteParams;
|
|
37
|
+
/** How the site was recognized — SDK call shape, or the API host. */
|
|
38
|
+
readonly matchedBy: "sdk" | "host";
|
|
39
|
+
/** Honest uncertainties for the human reviewing the draft. */
|
|
40
|
+
readonly notes: readonly string[];
|
|
41
|
+
}
|
|
42
|
+
export interface FinderOptions {
|
|
43
|
+
/** Skip these directory names anywhere in the tree. */
|
|
44
|
+
readonly skipDirs?: readonly string[];
|
|
45
|
+
readonly extensions?: readonly string[];
|
|
46
|
+
/** Include test files. Off by default: a mock is not a call site. */
|
|
47
|
+
readonly includeTests?: boolean;
|
|
48
|
+
readonly maxFileBytes?: number;
|
|
49
|
+
/**
|
|
50
|
+
* Narrow the scan to these paths/globs (F-4). Matched against each file's
|
|
51
|
+
* repo-relative POSIX path; a file matching NONE is not read at all. A
|
|
52
|
+
* pattern with no glob metachar (`*`/`?`/`[`) is a directory-prefix match
|
|
53
|
+
* (`src/pipeline` ⇒ everything under it); otherwise it is a glob where `*`
|
|
54
|
+
* stays within a path segment and `**` spans them. Empty/undefined = no
|
|
55
|
+
* narrowing (scan everything), so the default behaviour is unchanged.
|
|
56
|
+
*/
|
|
57
|
+
readonly scope?: readonly string[];
|
|
58
|
+
}
|
|
59
|
+
/** Compile one scope pattern into a matcher over repo-relative POSIX paths.
|
|
60
|
+
* Bare paths (no glob metachar) match the file itself or anything beneath it,
|
|
61
|
+
* so `--scope src/pipeline` onboards one pipeline directory without ceremony. */
|
|
62
|
+
export declare function compileScope(pattern: string): (relPath: string) => boolean;
|
|
63
|
+
/** True when `relPath` matches ANY scope (or no scope is set). */
|
|
64
|
+
export declare function matchesScope(relPath: string, scope: readonly string[] | undefined): boolean;
|
|
65
|
+
export declare const DEFAULT_SKIP_DIRS: readonly string[];
|
|
66
|
+
export interface FileSystemLike {
|
|
67
|
+
readdirSync(path: string, options: {
|
|
68
|
+
withFileTypes: true;
|
|
69
|
+
}): Array<{
|
|
70
|
+
name: string;
|
|
71
|
+
isDirectory(): boolean;
|
|
72
|
+
isFile(): boolean;
|
|
73
|
+
}>;
|
|
74
|
+
readFileSync(path: string, encoding: "utf8"): string;
|
|
75
|
+
statSync(path: string): {
|
|
76
|
+
size: number;
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
/** Read the balanced `{...}` object starting at or after `from`. Returns null
|
|
80
|
+
* when the call has no object literal (e.g. a spread or a variable). */
|
|
81
|
+
export declare function readObjectLiteral(source: string, from: number): string | null;
|
|
82
|
+
/** Find provider call sites in one file's text. Exported for fixtures. */
|
|
83
|
+
export declare function findCallSitesInText(file: string, fileText: string): CallSite[];
|
|
84
|
+
export interface ScanResult {
|
|
85
|
+
readonly sites: readonly CallSite[];
|
|
86
|
+
readonly filesScanned: number;
|
|
87
|
+
/** Files skipped for size — reported, never silently dropped. */
|
|
88
|
+
readonly filesSkipped: readonly string[];
|
|
89
|
+
}
|
|
90
|
+
export declare function scanRepoForCallSites(root: string, fs: FileSystemLike, path: {
|
|
91
|
+
join: (...parts: string[]) => string;
|
|
92
|
+
relative: (from: string, to: string) => string;
|
|
93
|
+
}, options?: FinderOptions): ScanResult;
|
|
94
|
+
//# sourceMappingURL=finder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"finder.d.ts","sourceRoot":"","sources":["../../src/init/finder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Provider call-site finder — `modelrig init` v0 (spec WS2).
|
|
4
|
+
*
|
|
5
|
+
* AST-lite on purpose: a balanced-brace reader over the call's options
|
|
6
|
+
* object, not a TypeScript parser. The job is to find call sites and read
|
|
7
|
+
* the handful of literals that matter (model, system prompt, schema hint,
|
|
8
|
+
* generation params) well enough to DRAFT a route a human will review. It is
|
|
9
|
+
* allowed to be unsure — every uncertainty is recorded as a `note` on the
|
|
10
|
+
* site rather than guessed into the output, because a confident wrong draft
|
|
11
|
+
* is worse than an honest incomplete one.
|
|
12
|
+
*
|
|
13
|
+
* Generic by construction: everything provider-specific lives in
|
|
14
|
+
* signatures.ts. No repo, framework, or company is special-cased.
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.DEFAULT_SKIP_DIRS = void 0;
|
|
18
|
+
exports.compileScope = compileScope;
|
|
19
|
+
exports.matchesScope = matchesScope;
|
|
20
|
+
exports.readObjectLiteral = readObjectLiteral;
|
|
21
|
+
exports.findCallSitesInText = findCallSitesInText;
|
|
22
|
+
exports.scanRepoForCallSites = scanRepoForCallSites;
|
|
23
|
+
const signatures_1 = require("./signatures");
|
|
24
|
+
/** Compile one scope pattern into a matcher over repo-relative POSIX paths.
|
|
25
|
+
* Bare paths (no glob metachar) match the file itself or anything beneath it,
|
|
26
|
+
* so `--scope src/pipeline` onboards one pipeline directory without ceremony. */
|
|
27
|
+
function compileScope(pattern) {
|
|
28
|
+
const trimmed = pattern.replace(/\/+$/, "");
|
|
29
|
+
if (!/[*?[\]]/.test(trimmed)) {
|
|
30
|
+
return (relPath) => relPath === trimmed || relPath.startsWith(`${trimmed}/`);
|
|
31
|
+
}
|
|
32
|
+
// Glob → RegExp. `**` spans path segments; a lone `*` stops at one. Every
|
|
33
|
+
// other regex metacharacter is escaped so a literal `.` stays literal.
|
|
34
|
+
let re = "";
|
|
35
|
+
for (let i = 0; i < trimmed.length; i += 1) {
|
|
36
|
+
const ch = trimmed[i];
|
|
37
|
+
if (ch === "*") {
|
|
38
|
+
if (trimmed[i + 1] === "*") {
|
|
39
|
+
re += ".*";
|
|
40
|
+
i += 1;
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
re += "[^/]*";
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
else if (ch === "?") {
|
|
47
|
+
re += "[^/]";
|
|
48
|
+
}
|
|
49
|
+
else if ("\\^$.|+()[]{}".includes(ch)) {
|
|
50
|
+
re += `\\${ch}`;
|
|
51
|
+
}
|
|
52
|
+
else {
|
|
53
|
+
re += ch;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
const compiled = new RegExp(`^${re}$`);
|
|
57
|
+
return (relPath) => compiled.test(relPath);
|
|
58
|
+
}
|
|
59
|
+
/** True when `relPath` matches ANY scope (or no scope is set). */
|
|
60
|
+
function matchesScope(relPath, scope) {
|
|
61
|
+
if (scope === undefined || scope.length === 0)
|
|
62
|
+
return true;
|
|
63
|
+
return scope.some((pattern) => compileScope(pattern)(relPath));
|
|
64
|
+
}
|
|
65
|
+
exports.DEFAULT_SKIP_DIRS = [
|
|
66
|
+
"node_modules",
|
|
67
|
+
"dist",
|
|
68
|
+
"build",
|
|
69
|
+
".next",
|
|
70
|
+
".git",
|
|
71
|
+
"coverage",
|
|
72
|
+
"vendor",
|
|
73
|
+
".turbo",
|
|
74
|
+
];
|
|
75
|
+
const DEFAULT_EXTENSIONS = [".ts", ".tsx", ".js", ".jsx", ".mjs", ".cjs"];
|
|
76
|
+
const DEFAULT_MAX_FILE_BYTES = 1000000;
|
|
77
|
+
/** Read the balanced `{...}` object starting at or after `from`. Returns null
|
|
78
|
+
* when the call has no object literal (e.g. a spread or a variable). */
|
|
79
|
+
function readObjectLiteral(source, from) {
|
|
80
|
+
const open = source.indexOf("{", from);
|
|
81
|
+
if (open === -1)
|
|
82
|
+
return null;
|
|
83
|
+
// Anything but whitespace between the paren and the brace means the first
|
|
84
|
+
// argument is not an inline object — don't misread a later one.
|
|
85
|
+
const between = source.slice(from, open);
|
|
86
|
+
if (/[^\s(]/.test(between))
|
|
87
|
+
return null;
|
|
88
|
+
let depth = 0;
|
|
89
|
+
let inString = null;
|
|
90
|
+
let escaped = false;
|
|
91
|
+
for (let i = open; i < source.length; i += 1) {
|
|
92
|
+
const char = source[i];
|
|
93
|
+
if (inString !== null) {
|
|
94
|
+
if (escaped)
|
|
95
|
+
escaped = false;
|
|
96
|
+
else if (char === "\\")
|
|
97
|
+
escaped = true;
|
|
98
|
+
else if (char === inString)
|
|
99
|
+
inString = null;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
if (char === '"' || char === "'" || char === "`") {
|
|
103
|
+
inString = char;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
if (char === "{")
|
|
107
|
+
depth += 1;
|
|
108
|
+
else if (char === "}") {
|
|
109
|
+
depth -= 1;
|
|
110
|
+
if (depth === 0)
|
|
111
|
+
return source.slice(open, i + 1);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
return null; // unbalanced — treat as unreadable rather than guessing
|
|
115
|
+
}
|
|
116
|
+
/** Read `key: "literal"` at any nesting depth of the options object. */
|
|
117
|
+
function readStringOption(objectText, key) {
|
|
118
|
+
const pattern = new RegExp(`\\b${key}\\s*:\\s*(['"\`])((?:\\\\.|(?!\\1).)*)\\1`, "s");
|
|
119
|
+
const match = objectText.match(pattern);
|
|
120
|
+
return match === null ? null : match[2].replace(/\\n/g, "\n").replace(/\\(['"`])/g, "$1");
|
|
121
|
+
}
|
|
122
|
+
function readNumberOption(objectText, key) {
|
|
123
|
+
const match = objectText.match(new RegExp(`\\b${key}\\s*:\\s*(-?\\d+(?:\\.\\d+)?)`));
|
|
124
|
+
return match === null ? null : Number(match[1]);
|
|
125
|
+
}
|
|
126
|
+
/** The identifier a non-literal option refers to — reported, never resolved. */
|
|
127
|
+
function readIdentifierOption(objectText, key) {
|
|
128
|
+
const match = objectText.match(new RegExp(`\\b${key}\\s*:\\s*([A-Za-z_$][\\w$.]*)`));
|
|
129
|
+
return match === null ? null : match[1];
|
|
130
|
+
}
|
|
131
|
+
function hasKey(objectText, key) {
|
|
132
|
+
return new RegExp(`\\b${key}\\s*:`).test(objectText);
|
|
133
|
+
}
|
|
134
|
+
function lineOf(source, index) {
|
|
135
|
+
let line = 1;
|
|
136
|
+
for (let i = 0; i < index && i < source.length; i += 1) {
|
|
137
|
+
if (source[i] === "\n")
|
|
138
|
+
line += 1;
|
|
139
|
+
}
|
|
140
|
+
return line;
|
|
141
|
+
}
|
|
142
|
+
function detectSchemaHint(objectText, fileText, signature) {
|
|
143
|
+
for (const key of signature.schemaKeys) {
|
|
144
|
+
if (!hasKey(objectText, key))
|
|
145
|
+
continue;
|
|
146
|
+
const identifier = readIdentifierOption(objectText, key);
|
|
147
|
+
if (identifier !== null && /zod|Schema$/i.test(identifier))
|
|
148
|
+
return "zod";
|
|
149
|
+
if (key === "responseMimeType") {
|
|
150
|
+
return readStringOption(objectText, key) === "application/json" ? "json-mode" : null;
|
|
151
|
+
}
|
|
152
|
+
if (/json_schema|responseSchema|responseJsonSchema|output_schema/.test(key))
|
|
153
|
+
return "json-schema";
|
|
154
|
+
if (readStringOption(objectText, key) === "json_object")
|
|
155
|
+
return "json-mode";
|
|
156
|
+
if (/json_object/.test(objectText))
|
|
157
|
+
return "json-mode";
|
|
158
|
+
return "json-schema";
|
|
159
|
+
}
|
|
160
|
+
// A zod import plus a parse near the call is the common untyped-SDK shape.
|
|
161
|
+
if (/from\s+["']zod["']/.test(fileText) && /\bz\.object\s*\(/.test(fileText))
|
|
162
|
+
return "zod";
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
function extractParams(objectText) {
|
|
166
|
+
const params = {};
|
|
167
|
+
for (const [key, normalized] of Object.entries(signatures_1.PARAM_KEYS)) {
|
|
168
|
+
const value = readNumberOption(objectText, key);
|
|
169
|
+
if (value !== null && params[normalized] === undefined)
|
|
170
|
+
params[normalized] = value;
|
|
171
|
+
}
|
|
172
|
+
return params;
|
|
173
|
+
}
|
|
174
|
+
function buildSite(args) {
|
|
175
|
+
const { file, fileText, index, signature, matchedBy } = args;
|
|
176
|
+
const objectText = readObjectLiteral(fileText, index) ?? "";
|
|
177
|
+
const notes = [];
|
|
178
|
+
let model = null;
|
|
179
|
+
let modelExpression = null;
|
|
180
|
+
const modelKeys = signature.modelKeys.length > 0 ? signature.modelKeys : signatures_1.ALL_MODEL_KEYS;
|
|
181
|
+
for (const key of modelKeys) {
|
|
182
|
+
model = readStringOption(objectText, key);
|
|
183
|
+
if (model !== null)
|
|
184
|
+
break;
|
|
185
|
+
modelExpression = modelExpression ?? readIdentifierOption(objectText, key);
|
|
186
|
+
}
|
|
187
|
+
if (objectText === "") {
|
|
188
|
+
notes.push("The call's options were not an inline object, so nothing could be read from it — " +
|
|
189
|
+
"fill in the model and prompt by hand.");
|
|
190
|
+
}
|
|
191
|
+
else if (model === null) {
|
|
192
|
+
notes.push(modelExpression === null
|
|
193
|
+
? "No model id found at this call site — name the model in the draft before running it."
|
|
194
|
+
: `The model comes from \`${modelExpression}\`, not a literal — set the candidate by hand ` +
|
|
195
|
+
"(and check whether it varies at runtime, which is exactly what a route replaces).");
|
|
196
|
+
}
|
|
197
|
+
let systemPrompt = null;
|
|
198
|
+
for (const key of signature.systemKeys) {
|
|
199
|
+
systemPrompt = readStringOption(objectText, key);
|
|
200
|
+
if (systemPrompt !== null)
|
|
201
|
+
break;
|
|
202
|
+
}
|
|
203
|
+
// OpenAI/Anthropic-style: the system turn lives inside `messages`.
|
|
204
|
+
if (systemPrompt === null && /role\s*:\s*['"`]system['"`]/.test(objectText)) {
|
|
205
|
+
const match = objectText.match(/role\s*:\s*['"`]system['"`]\s*,\s*content\s*:\s*(['"`])((?:\\.|(?!\1).)*)\1/s);
|
|
206
|
+
if (match !== null)
|
|
207
|
+
systemPrompt = match[2];
|
|
208
|
+
}
|
|
209
|
+
if (systemPrompt === null && objectText !== "") {
|
|
210
|
+
notes.push("No inline system prompt found — it is probably built in a variable. Paste it into the " +
|
|
211
|
+
"drafted prompt file.");
|
|
212
|
+
}
|
|
213
|
+
const schemaHint = detectSchemaHint(objectText, fileText, signature);
|
|
214
|
+
const wantsStructuredOutput = schemaHint !== null || signature.schemaKeys.some((k) => hasKey(objectText, k));
|
|
215
|
+
return {
|
|
216
|
+
file,
|
|
217
|
+
line: lineOf(fileText, index),
|
|
218
|
+
provider: signature.provider,
|
|
219
|
+
model,
|
|
220
|
+
modelExpression: model === null ? modelExpression : null,
|
|
221
|
+
systemPrompt,
|
|
222
|
+
wantsStructuredOutput,
|
|
223
|
+
schemaHint,
|
|
224
|
+
params: extractParams(objectText),
|
|
225
|
+
matchedBy,
|
|
226
|
+
notes,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
/** Find provider call sites in one file's text. Exported for fixtures. */
|
|
230
|
+
function findCallSitesInText(file, fileText) {
|
|
231
|
+
const sites = [];
|
|
232
|
+
const seen = new Set();
|
|
233
|
+
for (const signature of signatures_1.PROVIDER_SIGNATURES) {
|
|
234
|
+
const sdkPresent = signature.packages.length === 0 ||
|
|
235
|
+
signature.packages.some((pkg) =>
|
|
236
|
+
// Static `from "pkg"`, CommonJS `require("pkg")`, AND dynamic
|
|
237
|
+
// `await import("pkg")` — lazy SDK loading is common in server code
|
|
238
|
+
// and missing it silently hides real call sites.
|
|
239
|
+
new RegExp(`(from|require\\(|import\\()\\s*["']${pkg.replace(/[/\\^$*+?.()|[\]{}]/g, "\\$&")}["']`).test(fileText));
|
|
240
|
+
if (sdkPresent) {
|
|
241
|
+
for (const pattern of signature.callPatterns) {
|
|
242
|
+
const regex = (0, signatures_1.freshPattern)(pattern);
|
|
243
|
+
let match = regex.exec(fileText);
|
|
244
|
+
while (match !== null) {
|
|
245
|
+
const index = match.index + match[0].length - 1;
|
|
246
|
+
if (!seen.has(index)) {
|
|
247
|
+
seen.add(index);
|
|
248
|
+
sites.push(buildSite({ file, fileText, index, signature, matchedBy: "sdk" }));
|
|
249
|
+
}
|
|
250
|
+
match = regex.exec(fileText);
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
// Host fallback: a raw fetch() to a provider API is still a call site.
|
|
255
|
+
// But a bare `const BASE_URL = "https://api.deepseek.com"` is NOT one —
|
|
256
|
+
// SDK-configured providers name their host in a constant, and reporting
|
|
257
|
+
// that as a call site produces a route nobody asked for. Require the
|
|
258
|
+
// mention to sit inside something request-shaped.
|
|
259
|
+
for (const host of signature.hosts) {
|
|
260
|
+
const hostRegex = new RegExp(host.replace(/\./g, "\\."), "g");
|
|
261
|
+
let match = hostRegex.exec(fileText);
|
|
262
|
+
while (match !== null) {
|
|
263
|
+
const before = fileText.slice(Math.max(0, match.index - 200), match.index);
|
|
264
|
+
const after = fileText.slice(match.index, match.index + 600);
|
|
265
|
+
const isRequest = /\b(fetch|request|axios|got|post)\s*\(/.test(before) && /\bbody\s*:/.test(after);
|
|
266
|
+
if (!isRequest) {
|
|
267
|
+
match = hostRegex.exec(fileText);
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
// A raw fetch puts the request in `body:`, usually wrapped in
|
|
271
|
+
// JSON.stringify(...). Aim the object reader at the payload itself
|
|
272
|
+
// rather than at the `body` key, or the wrapper hides it.
|
|
273
|
+
const bodyIndex = fileText.indexOf("body", match.index);
|
|
274
|
+
let index = bodyIndex === -1 ? match.index : bodyIndex + 4;
|
|
275
|
+
if (bodyIndex !== -1) {
|
|
276
|
+
const window = fileText.slice(bodyIndex, bodyIndex + 60);
|
|
277
|
+
const wrapper = window.indexOf("JSON.stringify(");
|
|
278
|
+
if (wrapper !== -1)
|
|
279
|
+
index = bodyIndex + wrapper + "JSON.stringify(".length;
|
|
280
|
+
else
|
|
281
|
+
index = fileText.indexOf(":", bodyIndex) + 1;
|
|
282
|
+
}
|
|
283
|
+
const near = [...seen].some((s) => Math.abs(s - index) < 400);
|
|
284
|
+
if (!near) {
|
|
285
|
+
seen.add(index);
|
|
286
|
+
sites.push(buildSite({ file, fileText, index, signature, matchedBy: "host" }));
|
|
287
|
+
}
|
|
288
|
+
match = hostRegex.exec(fileText);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
return sites.sort((a, b) => a.line - b.line);
|
|
293
|
+
}
|
|
294
|
+
function scanRepoForCallSites(root, fs, path, options = {}) {
|
|
295
|
+
const skipDirs = new Set(options.skipDirs ?? exports.DEFAULT_SKIP_DIRS);
|
|
296
|
+
const extensions = options.extensions ?? DEFAULT_EXTENSIONS;
|
|
297
|
+
const maxBytes = options.maxFileBytes ?? DEFAULT_MAX_FILE_BYTES;
|
|
298
|
+
const sites = [];
|
|
299
|
+
const skipped = [];
|
|
300
|
+
let filesScanned = 0;
|
|
301
|
+
const walk = (dir) => {
|
|
302
|
+
let entries;
|
|
303
|
+
try {
|
|
304
|
+
entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
305
|
+
}
|
|
306
|
+
catch {
|
|
307
|
+
return; // unreadable directory is not a reason to abort the scan
|
|
308
|
+
}
|
|
309
|
+
for (const entry of entries) {
|
|
310
|
+
const full = path.join(dir, entry.name);
|
|
311
|
+
if (entry.isDirectory()) {
|
|
312
|
+
if (skipDirs.has(entry.name))
|
|
313
|
+
continue;
|
|
314
|
+
walk(full);
|
|
315
|
+
continue;
|
|
316
|
+
}
|
|
317
|
+
if (!entry.isFile())
|
|
318
|
+
continue;
|
|
319
|
+
if (!extensions.some((ext) => entry.name.endsWith(ext)))
|
|
320
|
+
continue;
|
|
321
|
+
const isTest = /\.(test|spec)\.[jt]sx?$/.test(entry.name) || full.includes("__tests__") || full.includes("__mocks__");
|
|
322
|
+
if (isTest && options.includeTests !== true)
|
|
323
|
+
continue;
|
|
324
|
+
// F-4: a file outside every --scope is never read (not counted scanned).
|
|
325
|
+
if (!matchesScope(path.relative(root, full), options.scope))
|
|
326
|
+
continue;
|
|
327
|
+
try {
|
|
328
|
+
if (fs.statSync(full).size > maxBytes) {
|
|
329
|
+
skipped.push(path.relative(root, full));
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
const text = fs.readFileSync(full, "utf8");
|
|
333
|
+
filesScanned += 1;
|
|
334
|
+
sites.push(...findCallSitesInText(path.relative(root, full), text));
|
|
335
|
+
}
|
|
336
|
+
catch {
|
|
337
|
+
skipped.push(path.relative(root, full));
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
walk(root);
|
|
342
|
+
return { sites, filesScanned, filesSkipped: skipped };
|
|
343
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `modelrig init` command runner — lives here (not cli.ts) for the LOC cap
|
|
3
|
+
* (P1), beside the scaffold it drives (same split as observe-cli.ts and
|
|
4
|
+
* verify/cli-run.ts). Scans a repo for provider call sites and drafts a route
|
|
5
|
+
* bundle per site plus a MIGRATION.md map. It writes ONLY under
|
|
6
|
+
* <routes-dir>/drafts/; the target's source is never edited.
|
|
7
|
+
*/
|
|
8
|
+
import type { ObserveFlags } from "./observe-cli";
|
|
9
|
+
export declare function cmdInit(flags: ObserveFlags): number;
|
|
10
|
+
//# sourceMappingURL=init-cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"init-cli.d.ts","sourceRoot":"","sources":["../../src/init/init-cli.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAQH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAGlD,wBAAgB,OAAO,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAwFnD"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* `modelrig init` command runner — lives here (not cli.ts) for the LOC cap
|
|
4
|
+
* (P1), beside the scaffold it drives (same split as observe-cli.ts and
|
|
5
|
+
* verify/cli-run.ts). Scans a repo for provider call sites and drafts a route
|
|
6
|
+
* bundle per site plus a MIGRATION.md map. It writes ONLY under
|
|
7
|
+
* <routes-dir>/drafts/; the target's source is never edited.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.cmdInit = cmdInit;
|
|
11
|
+
const node_fs_1 = require("node:fs");
|
|
12
|
+
const node_path_1 = require("node:path");
|
|
13
|
+
const config_1 = require("../config");
|
|
14
|
+
const rows_1 = require("../registry/rows");
|
|
15
|
+
const observe_cli_1 = require("./observe-cli");
|
|
16
|
+
const run_1 = require("./run");
|
|
17
|
+
function cmdInit(flags) {
|
|
18
|
+
// `init --observe` is the observe-first (T0/T1) alias for `modelrig observe`.
|
|
19
|
+
if (flags.bare.has("observe"))
|
|
20
|
+
return (0, observe_cli_1.cmdObserve)(flags);
|
|
21
|
+
const root = (0, node_path_1.resolve)(flags.positional[0] ?? ".");
|
|
22
|
+
const config = (0, config_1.loadConfigFromEnv)();
|
|
23
|
+
const draftsDir = flags.named.get("out") ?? (0, node_path_1.join)(config.routesDir, "drafts");
|
|
24
|
+
const scope = (0, observe_cli_1.scopeFrom)(flags);
|
|
25
|
+
// Registry rows seed the challenger candidates. A missing/unbuilt registry
|
|
26
|
+
// is not fatal — drafts then carry the incumbent alone, and say so.
|
|
27
|
+
let registryRows = [];
|
|
28
|
+
try {
|
|
29
|
+
registryRows = (0, rows_1.loadRegistryRows)(config.registryPath);
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
registryRows = [];
|
|
33
|
+
}
|
|
34
|
+
const result = (0, run_1.runInit)({
|
|
35
|
+
root,
|
|
36
|
+
draftsDir,
|
|
37
|
+
fs: { readdirSync: node_fs_1.readdirSync, readFileSync: node_fs_1.readFileSync, statSync: node_fs_1.statSync, existsSync: node_fs_1.existsSync, mkdirSync: node_fs_1.mkdirSync, writeFileSync: node_fs_1.writeFileSync },
|
|
38
|
+
path: { join: node_path_1.join, relative: node_path_1.relative, dirname: node_path_1.dirname, basename: node_path_1.basename },
|
|
39
|
+
}, {
|
|
40
|
+
registryRows,
|
|
41
|
+
...(flags.bare.has("dry-run") ? { dryRun: true } : {}),
|
|
42
|
+
...(flags.bare.has("include-tests") ? { includeTests: true } : {}),
|
|
43
|
+
...(scope !== undefined ? { scope } : {}),
|
|
44
|
+
});
|
|
45
|
+
if (flags.bare.has("json")) {
|
|
46
|
+
console.log(JSON.stringify({
|
|
47
|
+
sitesFound: result.sitesFound,
|
|
48
|
+
filesScanned: result.filesScanned,
|
|
49
|
+
filesSkipped: result.filesSkipped,
|
|
50
|
+
routes: result.drafts.map((d) => ({
|
|
51
|
+
route: d.route,
|
|
52
|
+
file: d.site.file,
|
|
53
|
+
line: d.site.line,
|
|
54
|
+
provider: d.site.provider,
|
|
55
|
+
model: d.site.model,
|
|
56
|
+
notes: d.site.notes,
|
|
57
|
+
})),
|
|
58
|
+
written: result.written,
|
|
59
|
+
skipped: result.skipped,
|
|
60
|
+
}, null, 2));
|
|
61
|
+
return 0;
|
|
62
|
+
}
|
|
63
|
+
console.log(`modelrig init — scanned ${result.filesScanned} file(s) under ${root}` +
|
|
64
|
+
(scope !== undefined ? ` (scoped to ${scope.join(", ")})` : "") +
|
|
65
|
+
`\nfound ${result.sitesFound} provider call site(s)`);
|
|
66
|
+
if (result.sitesFound === 0) {
|
|
67
|
+
console.log("\nNothing to draft. If you know there are model calls here, they may sit behind a helper\n" +
|
|
68
|
+
"that hides the SDK — point init at the file that actually calls the provider.");
|
|
69
|
+
return 0;
|
|
70
|
+
}
|
|
71
|
+
for (const draft of result.drafts) {
|
|
72
|
+
console.log(` ${draft.site.file}:${draft.site.line} (${draft.site.provider}` +
|
|
73
|
+
`${draft.site.model !== null ? ` ${draft.site.model}` : ""}) → ${draft.route}`);
|
|
74
|
+
}
|
|
75
|
+
if (result.filesSkipped.length > 0) {
|
|
76
|
+
console.log(`\n${result.filesSkipped.length} file(s) skipped (too large or unreadable).`);
|
|
77
|
+
}
|
|
78
|
+
if (flags.bare.has("dry-run")) {
|
|
79
|
+
console.log("\n--dry-run: nothing written.");
|
|
80
|
+
return 0;
|
|
81
|
+
}
|
|
82
|
+
console.log(`\nwrote ${result.written.length} file(s) to ${draftsDir}` +
|
|
83
|
+
(result.skipped.length > 0 ? ` (${result.skipped.length} left alone — already there)` : "") +
|
|
84
|
+
`\nread ${(0, node_path_1.join)(draftsDir, "MIGRATION.md")} next. Your source was not touched.`);
|
|
85
|
+
return 0;
|
|
86
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `modelrig observe` command runner — lives here (not cli.ts) for the LOC cap
|
|
3
|
+
* (P1), beside the scaffold it drives (same split as verify/cli-run.ts and
|
|
4
|
+
* bakeoff/report.ts). Closes onboarding-test run-1's headline gap (F-1: the
|
|
5
|
+
* only observe on-ramp was a hand-wired SDK seam with no CLI). Like `init`, it
|
|
6
|
+
* NEVER edits the target's source — it writes only under its out dir.
|
|
7
|
+
*/
|
|
8
|
+
/** Structural view of the CLI's parsed flags — declared here so this module
|
|
9
|
+
* never imports cli.ts (which imports us), keeping the dependency one-way. */
|
|
10
|
+
export interface ObserveFlags {
|
|
11
|
+
readonly positional: readonly string[];
|
|
12
|
+
readonly named: ReadonlyMap<string, string>;
|
|
13
|
+
readonly bare: ReadonlySet<string>;
|
|
14
|
+
}
|
|
15
|
+
/** `--scope a,b` → the finder's scope narrowing (F-4). Comma-separated globs
|
|
16
|
+
* or path prefixes; absent = scan everything. Shared with `modelrig init`. */
|
|
17
|
+
export declare function scopeFrom(flags: ObserveFlags): readonly string[] | undefined;
|
|
18
|
+
export declare function cmdObserve(flags: ObserveFlags): number;
|
|
19
|
+
//# sourceMappingURL=observe-cli.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"observe-cli.d.ts","sourceRoot":"","sources":["../../src/init/observe-cli.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAOH;8EAC8E;AAC9E,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,UAAU,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC5C,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACpC;AAED;8EAC8E;AAC9E,wBAAgB,SAAS,CAAC,KAAK,EAAE,YAAY,GAAG,SAAS,MAAM,EAAE,GAAG,SAAS,CAK5E;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,YAAY,GAAG,MAAM,CAgEtD"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* `modelrig observe` command runner — lives here (not cli.ts) for the LOC cap
|
|
4
|
+
* (P1), beside the scaffold it drives (same split as verify/cli-run.ts and
|
|
5
|
+
* bakeoff/report.ts). Closes onboarding-test run-1's headline gap (F-1: the
|
|
6
|
+
* only observe on-ramp was a hand-wired SDK seam with no CLI). Like `init`, it
|
|
7
|
+
* NEVER edits the target's source — it writes only under its out dir.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.scopeFrom = scopeFrom;
|
|
11
|
+
exports.cmdObserve = cmdObserve;
|
|
12
|
+
const node_fs_1 = require("node:fs");
|
|
13
|
+
const node_path_1 = require("node:path");
|
|
14
|
+
const config_1 = require("../config");
|
|
15
|
+
const observe_1 = require("./observe");
|
|
16
|
+
/** `--scope a,b` → the finder's scope narrowing (F-4). Comma-separated globs
|
|
17
|
+
* or path prefixes; absent = scan everything. Shared with `modelrig init`. */
|
|
18
|
+
function scopeFrom(flags) {
|
|
19
|
+
const raw = flags.named.get("scope");
|
|
20
|
+
if (raw === undefined)
|
|
21
|
+
return undefined;
|
|
22
|
+
const scope = raw.split(",").map((s) => s.trim()).filter((s) => s !== "");
|
|
23
|
+
return scope.length > 0 ? scope : undefined;
|
|
24
|
+
}
|
|
25
|
+
function cmdObserve(flags) {
|
|
26
|
+
const root = (0, node_path_1.resolve)(flags.positional[0] ?? ".");
|
|
27
|
+
const config = (0, config_1.loadConfigFromEnv)();
|
|
28
|
+
// Sibling of the routes dir: <repo>/modelrig/observe by default.
|
|
29
|
+
const outDir = flags.named.get("out") ?? (0, node_path_1.join)((0, node_path_1.dirname)(config.routesDir), "observe");
|
|
30
|
+
const scope = scopeFrom(flags);
|
|
31
|
+
const result = (0, observe_1.runObserve)({
|
|
32
|
+
root,
|
|
33
|
+
outDir,
|
|
34
|
+
fs: { readdirSync: node_fs_1.readdirSync, readFileSync: node_fs_1.readFileSync, statSync: node_fs_1.statSync, existsSync: node_fs_1.existsSync, mkdirSync: node_fs_1.mkdirSync, writeFileSync: node_fs_1.writeFileSync },
|
|
35
|
+
path: { join: node_path_1.join, relative: node_path_1.relative, dirname: node_path_1.dirname, basename: node_path_1.basename },
|
|
36
|
+
}, {
|
|
37
|
+
...(flags.bare.has("dry-run") ? { dryRun: true } : {}),
|
|
38
|
+
...(flags.bare.has("include-tests") ? { includeTests: true } : {}),
|
|
39
|
+
...(scope !== undefined ? { scope } : {}),
|
|
40
|
+
});
|
|
41
|
+
if (flags.bare.has("json")) {
|
|
42
|
+
console.log(JSON.stringify({
|
|
43
|
+
sitesFound: result.sitesFound,
|
|
44
|
+
filesScanned: result.filesScanned,
|
|
45
|
+
filesSkipped: result.filesSkipped,
|
|
46
|
+
steps: result.plans.map((p) => ({
|
|
47
|
+
stepKey: p.stepKey,
|
|
48
|
+
file: p.site.file,
|
|
49
|
+
line: p.site.line,
|
|
50
|
+
provider: p.site.provider,
|
|
51
|
+
model: p.site.model,
|
|
52
|
+
})),
|
|
53
|
+
written: result.written,
|
|
54
|
+
skipped: result.skipped,
|
|
55
|
+
}, null, 2));
|
|
56
|
+
return 0;
|
|
57
|
+
}
|
|
58
|
+
console.log(`modelrig observe — scanned ${result.filesScanned} file(s) under ${root}` +
|
|
59
|
+
(scope !== undefined ? ` (scoped to ${scope.join(", ")})` : "") +
|
|
60
|
+
`\nfound ${result.sitesFound} model call site(s) → ${result.sitesFound} proposed step(s)`);
|
|
61
|
+
for (const plan of result.plans) {
|
|
62
|
+
console.log(` ${plan.site.file}:${plan.site.line} → step "${plan.stepKey}"`);
|
|
63
|
+
}
|
|
64
|
+
if (flags.bare.has("dry-run")) {
|
|
65
|
+
console.log("\n--dry-run: nothing written.");
|
|
66
|
+
return 0;
|
|
67
|
+
}
|
|
68
|
+
console.log(`\nwrote ${result.written.length} file(s) to ${outDir}` +
|
|
69
|
+
(result.skipped.length > 0 ? ` (${result.skipped.length} left alone — already there)` : "") +
|
|
70
|
+
`\nread ${(0, node_path_1.join)(outDir, "OBSERVE.md")} next — apply the wiring diffs one step at a time.` +
|
|
71
|
+
"\nObserve changes no behaviour; with MODELRIG_ARTIFACTS off your pipeline is byte-for-byte the same.");
|
|
72
|
+
return 0;
|
|
73
|
+
}
|