@steipete/summarize 0.10.0 → 0.11.1
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 +80 -28
- package/README.md +115 -30
- package/dist/cli.js +1 -1
- package/dist/esm/cache.js +67 -65
- package/dist/esm/cache.js.map +1 -1
- package/dist/esm/cli-main.js +27 -27
- package/dist/esm/cli-main.js.map +1 -1
- package/dist/esm/cli.js +2 -2
- package/dist/esm/cli.js.map +1 -1
- package/dist/esm/config.js +310 -166
- package/dist/esm/config.js.map +1 -1
- package/dist/esm/content/asset.js +53 -50
- package/dist/esm/content/asset.js.map +1 -1
- package/dist/esm/content/index.js +1 -1
- package/dist/esm/content/index.js.map +1 -1
- package/dist/esm/costs.js +1 -1
- package/dist/esm/costs.js.map +1 -1
- package/dist/esm/daemon/agent.js +165 -164
- package/dist/esm/daemon/agent.js.map +1 -1
- package/dist/esm/daemon/auto-mode.js +3 -3
- package/dist/esm/daemon/auto-mode.js.map +1 -1
- package/dist/esm/daemon/chat.js +16 -14
- package/dist/esm/daemon/chat.js.map +1 -1
- package/dist/esm/daemon/cli-entrypoint.js +72 -0
- package/dist/esm/daemon/cli-entrypoint.js.map +1 -0
- package/dist/esm/daemon/cli.js +63 -87
- package/dist/esm/daemon/cli.js.map +1 -1
- package/dist/esm/daemon/config.js +15 -15
- package/dist/esm/daemon/config.js.map +1 -1
- package/dist/esm/daemon/constants.js +6 -6
- package/dist/esm/daemon/constants.js.map +1 -1
- package/dist/esm/daemon/env-merge.js.map +1 -1
- package/dist/esm/daemon/env-snapshot.js +36 -31
- package/dist/esm/daemon/env-snapshot.js.map +1 -1
- package/dist/esm/daemon/flow-context.js +59 -28
- package/dist/esm/daemon/flow-context.js.map +1 -1
- package/dist/esm/daemon/launchd.js +100 -55
- package/dist/esm/daemon/launchd.js.map +1 -1
- package/dist/esm/daemon/meta.js +5 -5
- package/dist/esm/daemon/meta.js.map +1 -1
- package/dist/esm/daemon/models.js +54 -31
- package/dist/esm/daemon/models.js.map +1 -1
- package/dist/esm/daemon/process-registry.js +15 -15
- package/dist/esm/daemon/process-registry.js.map +1 -1
- package/dist/esm/daemon/schtasks.js +42 -42
- package/dist/esm/daemon/schtasks.js.map +1 -1
- package/dist/esm/daemon/server.js +248 -244
- package/dist/esm/daemon/server.js.map +1 -1
- package/dist/esm/daemon/summarize-progress.js +11 -11
- package/dist/esm/daemon/summarize-progress.js.map +1 -1
- package/dist/esm/daemon/summarize.js +29 -29
- package/dist/esm/daemon/summarize.js.map +1 -1
- package/dist/esm/daemon/systemd.js +47 -47
- package/dist/esm/daemon/systemd.js.map +1 -1
- package/dist/esm/firecrawl.js +12 -12
- package/dist/esm/firecrawl.js.map +1 -1
- package/dist/esm/flags.js +32 -32
- package/dist/esm/flags.js.map +1 -1
- package/dist/esm/index.js +3 -3
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/language.js +1 -1
- package/dist/esm/language.js.map +1 -1
- package/dist/esm/llm/cli.js +128 -64
- package/dist/esm/llm/cli.js.map +1 -1
- package/dist/esm/llm/errors.js +1 -1
- package/dist/esm/llm/errors.js.map +1 -1
- package/dist/esm/llm/generate-text.js +107 -98
- package/dist/esm/llm/generate-text.js.map +1 -1
- package/dist/esm/llm/google-models.js +17 -17
- package/dist/esm/llm/google-models.js.map +1 -1
- package/dist/esm/llm/html-to-markdown.js +3 -3
- package/dist/esm/llm/html-to-markdown.js.map +1 -1
- package/dist/esm/llm/model-id.js +38 -16
- package/dist/esm/llm/model-id.js.map +1 -1
- package/dist/esm/llm/prompt.js +5 -5
- package/dist/esm/llm/prompt.js.map +1 -1
- package/dist/esm/llm/providers/anthropic.js +33 -33
- package/dist/esm/llm/providers/anthropic.js.map +1 -1
- package/dist/esm/llm/providers/google.js +19 -19
- package/dist/esm/llm/providers/google.js.map +1 -1
- package/dist/esm/llm/providers/models.js +30 -30
- package/dist/esm/llm/providers/models.js.map +1 -1
- package/dist/esm/llm/providers/openai.js +35 -34
- package/dist/esm/llm/providers/openai.js.map +1 -1
- package/dist/esm/llm/providers/shared.js +8 -8
- package/dist/esm/llm/providers/shared.js.map +1 -1
- package/dist/esm/llm/transcript-to-markdown.js +9 -5
- package/dist/esm/llm/transcript-to-markdown.js.map +1 -1
- package/dist/esm/llm/usage.js +18 -18
- package/dist/esm/llm/usage.js.map +1 -1
- package/dist/esm/logging/daemon.js +21 -21
- package/dist/esm/logging/daemon.js.map +1 -1
- package/dist/esm/logging/ring-file.js +5 -5
- package/dist/esm/logging/ring-file.js.map +1 -1
- package/dist/esm/markitdown.js +21 -19
- package/dist/esm/markitdown.js.map +1 -1
- package/dist/esm/media-cache.js +39 -39
- package/dist/esm/media-cache.js.map +1 -1
- package/dist/esm/model-auto.js +175 -106
- package/dist/esm/model-auto.js.map +1 -1
- package/dist/esm/model-spec.js +52 -42
- package/dist/esm/model-spec.js.map +1 -1
- package/dist/esm/pricing/litellm.js +4 -4
- package/dist/esm/pricing/litellm.js.map +1 -1
- package/dist/esm/processes.js +1 -1
- package/dist/esm/processes.js.map +1 -1
- package/dist/esm/prompts/index.js +1 -1
- package/dist/esm/prompts/index.js.map +1 -1
- package/dist/esm/refresh-free.js +81 -81
- package/dist/esm/refresh-free.js.map +1 -1
- package/dist/esm/run/attachments.js +47 -44
- package/dist/esm/run/attachments.js.map +1 -1
- package/dist/esm/run/bird.js +26 -26
- package/dist/esm/run/bird.js.map +1 -1
- package/dist/esm/run/cache-state.js +7 -7
- package/dist/esm/run/cache-state.js.map +1 -1
- package/dist/esm/run/cli-fallback-state.js +45 -0
- package/dist/esm/run/cli-fallback-state.js.map +1 -0
- package/dist/esm/run/cli-preflight.js +24 -24
- package/dist/esm/run/cli-preflight.js.map +1 -1
- package/dist/esm/run/constants.js +12 -12
- package/dist/esm/run/constants.js.map +1 -1
- package/dist/esm/run/cookies/twitter.js +47 -47
- package/dist/esm/run/cookies/twitter.js.map +1 -1
- package/dist/esm/run/env.js +21 -15
- package/dist/esm/run/env.js.map +1 -1
- package/dist/esm/run/fetch-with-timeout.js +4 -4
- package/dist/esm/run/fetch-with-timeout.js.map +1 -1
- package/dist/esm/run/finish-line.js +68 -68
- package/dist/esm/run/finish-line.js.map +1 -1
- package/dist/esm/run/flows/asset/extract.js +15 -15
- package/dist/esm/run/flows/asset/extract.js.map +1 -1
- package/dist/esm/run/flows/asset/input.js +47 -66
- package/dist/esm/run/flows/asset/input.js.map +1 -1
- package/dist/esm/run/flows/asset/media-policy.js +1 -1
- package/dist/esm/run/flows/asset/media-policy.js.map +1 -1
- package/dist/esm/run/flows/asset/media.js +49 -40
- package/dist/esm/run/flows/asset/media.js.map +1 -1
- package/dist/esm/run/flows/asset/output.js +12 -12
- package/dist/esm/run/flows/asset/output.js.map +1 -1
- package/dist/esm/run/flows/asset/preprocess.js +79 -44
- package/dist/esm/run/flows/asset/preprocess.js.map +1 -1
- package/dist/esm/run/flows/asset/summary.js +173 -106
- package/dist/esm/run/flows/asset/summary.js.map +1 -1
- package/dist/esm/run/flows/url/extract.js +26 -26
- package/dist/esm/run/flows/url/extract.js.map +1 -1
- package/dist/esm/run/flows/url/flow.js +104 -98
- package/dist/esm/run/flows/url/flow.js.map +1 -1
- package/dist/esm/run/flows/url/markdown.js +57 -57
- package/dist/esm/run/flows/url/markdown.js.map +1 -1
- package/dist/esm/run/flows/url/slides-output.js +61 -59
- package/dist/esm/run/flows/url/slides-output.js.map +1 -1
- package/dist/esm/run/flows/url/slides-text.js +85 -85
- package/dist/esm/run/flows/url/slides-text.js.map +1 -1
- package/dist/esm/run/flows/url/summary.js +174 -107
- package/dist/esm/run/flows/url/summary.js.map +1 -1
- package/dist/esm/run/format.js +10 -10
- package/dist/esm/run/format.js.map +1 -1
- package/dist/esm/run/help.js +141 -135
- package/dist/esm/run/help.js.map +1 -1
- package/dist/esm/run/logging.js +10 -10
- package/dist/esm/run/logging.js.map +1 -1
- package/dist/esm/run/markdown.js +12 -12
- package/dist/esm/run/markdown.js.map +1 -1
- package/dist/esm/run/media-cache-state.js +5 -5
- package/dist/esm/run/media-cache-state.js.map +1 -1
- package/dist/esm/run/model-attempts.js.map +1 -1
- package/dist/esm/run/openrouter.js +11 -11
- package/dist/esm/run/openrouter.js.map +1 -1
- package/dist/esm/run/progress.js +1 -1
- package/dist/esm/run/progress.js.map +1 -1
- package/dist/esm/run/run-config.js +16 -16
- package/dist/esm/run/run-config.js.map +1 -1
- package/dist/esm/run/run-context.js +2 -2
- package/dist/esm/run/run-context.js.map +1 -1
- package/dist/esm/run/run-env.js +55 -54
- package/dist/esm/run/run-env.js.map +1 -1
- package/dist/esm/run/run-input.js +3 -3
- package/dist/esm/run/run-input.js.map +1 -1
- package/dist/esm/run/run-metrics.js +16 -16
- package/dist/esm/run/run-metrics.js.map +1 -1
- package/dist/esm/run/run-models.js +28 -23
- package/dist/esm/run/run-models.js.map +1 -1
- package/dist/esm/run/run-output.js +3 -3
- package/dist/esm/run/run-output.js.map +1 -1
- package/dist/esm/run/run-settings.js +83 -34
- package/dist/esm/run/run-settings.js.map +1 -1
- package/dist/esm/run/run-stream.js +4 -4
- package/dist/esm/run/run-stream.js.map +1 -1
- package/dist/esm/run/runner.js +166 -127
- package/dist/esm/run/runner.js.map +1 -1
- package/dist/esm/run/slides-cli.js +43 -42
- package/dist/esm/run/slides-cli.js.map +1 -1
- package/dist/esm/run/slides-render.js +36 -36
- package/dist/esm/run/slides-render.js.map +1 -1
- package/dist/esm/run/stdin-temp-file.js +77 -0
- package/dist/esm/run/stdin-temp-file.js.map +1 -0
- package/dist/esm/run/stream-output.js +7 -7
- package/dist/esm/run/stream-output.js.map +1 -1
- package/dist/esm/run/streaming.js +16 -16
- package/dist/esm/run/streaming.js.map +1 -1
- package/dist/esm/run/summary-engine.js +57 -51
- package/dist/esm/run/summary-engine.js.map +1 -1
- package/dist/esm/run/summary-llm.js +3 -3
- package/dist/esm/run/summary-llm.js.map +1 -1
- package/dist/esm/run/terminal.js +4 -4
- package/dist/esm/run/terminal.js.map +1 -1
- package/dist/esm/run/tips.js +2 -2
- package/dist/esm/run/tips.js.map +1 -1
- package/dist/esm/run/transcriber-cli.js +49 -49
- package/dist/esm/run/transcriber-cli.js.map +1 -1
- package/dist/esm/run.js +1 -1
- package/dist/esm/run.js.map +1 -1
- package/dist/esm/shared/contracts.js +1 -1
- package/dist/esm/shared/contracts.js.map +1 -1
- package/dist/esm/shared/sse-events.js +16 -16
- package/dist/esm/shared/sse-events.js.map +1 -1
- package/dist/esm/shared/streaming-merge.js +3 -3
- package/dist/esm/shared/streaming-merge.js.map +1 -1
- package/dist/esm/slides/extract.js +258 -249
- package/dist/esm/slides/extract.js.map +1 -1
- package/dist/esm/slides/index.js +3 -3
- package/dist/esm/slides/index.js.map +1 -1
- package/dist/esm/slides/settings.js +14 -14
- package/dist/esm/slides/settings.js.map +1 -1
- package/dist/esm/slides/store.js +9 -9
- package/dist/esm/slides/store.js.map +1 -1
- package/dist/esm/tty/format.js +13 -13
- package/dist/esm/tty/format.js.map +1 -1
- package/dist/esm/tty/osc-progress.js +1 -1
- package/dist/esm/tty/osc-progress.js.map +1 -1
- package/dist/esm/tty/progress/fetch-html.js +14 -14
- package/dist/esm/tty/progress/fetch-html.js.map +1 -1
- package/dist/esm/tty/progress/transcript.js +70 -62
- package/dist/esm/tty/progress/transcript.js.map +1 -1
- package/dist/esm/tty/spinner.js +20 -9
- package/dist/esm/tty/spinner.js.map +1 -1
- package/dist/esm/tty/theme.js +92 -92
- package/dist/esm/tty/theme.js.map +1 -1
- package/dist/esm/tty/website-progress.js +32 -32
- package/dist/esm/tty/website-progress.js.map +1 -1
- package/dist/esm/version.js +29 -29
- package/dist/esm/version.js.map +1 -1
- package/dist/types/cache.d.ts +6 -6
- package/dist/types/config.d.ts +49 -7
- package/dist/types/content/asset.d.ts +8 -6
- package/dist/types/content/index.d.ts +1 -1
- package/dist/types/costs.d.ts +3 -3
- package/dist/types/daemon/agent.d.ts +1 -1
- package/dist/types/daemon/auto-mode.d.ts +3 -3
- package/dist/types/daemon/chat.d.ts +2 -2
- package/dist/types/daemon/cli-entrypoint.d.ts +2 -0
- package/dist/types/daemon/config.d.ts +2 -2
- package/dist/types/daemon/env-merge.d.ts +1 -1
- package/dist/types/daemon/env-snapshot.d.ts +1 -1
- package/dist/types/daemon/flow-context.d.ts +7 -7
- package/dist/types/daemon/launchd.d.ts +8 -0
- package/dist/types/daemon/models.d.ts +6 -2
- package/dist/types/daemon/process-registry.d.ts +5 -5
- package/dist/types/daemon/server.d.ts +2 -2
- package/dist/types/daemon/summarize-progress.d.ts +1 -1
- package/dist/types/daemon/summarize.d.ts +7 -7
- package/dist/types/firecrawl.d.ts +1 -1
- package/dist/types/flags.d.ts +11 -11
- package/dist/types/index.d.ts +4 -4
- package/dist/types/language.d.ts +1 -1
- package/dist/types/llm/attachments.d.ts +1 -1
- package/dist/types/llm/cli.d.ts +3 -3
- package/dist/types/llm/generate-text.d.ts +7 -7
- package/dist/types/llm/html-to-markdown.d.ts +3 -3
- package/dist/types/llm/model-id.d.ts +1 -1
- package/dist/types/llm/prompt.d.ts +2 -2
- package/dist/types/llm/providers/anthropic.d.ts +3 -3
- package/dist/types/llm/providers/google.d.ts +3 -3
- package/dist/types/llm/providers/models.d.ts +2 -2
- package/dist/types/llm/providers/openai.d.ts +4 -4
- package/dist/types/llm/providers/shared.d.ts +2 -2
- package/dist/types/llm/transcript-to-markdown.d.ts +4 -2
- package/dist/types/llm/usage.d.ts +1 -1
- package/dist/types/logging/daemon.d.ts +4 -4
- package/dist/types/markitdown.d.ts +1 -1
- package/dist/types/media-cache.d.ts +2 -2
- package/dist/types/model-auto.d.ts +14 -4
- package/dist/types/model-spec.d.ts +10 -10
- package/dist/types/pricing/litellm.d.ts +1 -1
- package/dist/types/processes.d.ts +1 -1
- package/dist/types/prompts/index.d.ts +1 -1
- package/dist/types/run/attachments.d.ts +7 -7
- package/dist/types/run/bird.d.ts +2 -2
- package/dist/types/run/cache-state.d.ts +2 -2
- package/dist/types/run/cli-fallback-state.d.ts +6 -0
- package/dist/types/run/constants.d.ts +1 -1
- package/dist/types/run/cookies/twitter.d.ts +1 -1
- package/dist/types/run/env.d.ts +1 -1
- package/dist/types/run/finish-line.d.ts +5 -5
- package/dist/types/run/flows/asset/extract.d.ts +4 -4
- package/dist/types/run/flows/asset/input.d.ts +9 -3
- package/dist/types/run/flows/asset/media.d.ts +1 -1
- package/dist/types/run/flows/asset/output.d.ts +5 -5
- package/dist/types/run/flows/asset/preprocess.d.ts +23 -17
- package/dist/types/run/flows/asset/summary.d.ts +19 -17
- package/dist/types/run/flows/url/extract.d.ts +1 -1
- package/dist/types/run/flows/url/flow.d.ts +1 -1
- package/dist/types/run/flows/url/markdown.d.ts +6 -6
- package/dist/types/run/flows/url/slides-output.d.ts +7 -7
- package/dist/types/run/flows/url/slides-text.d.ts +9 -9
- package/dist/types/run/flows/url/summary.d.ts +11 -11
- package/dist/types/run/flows/url/types.d.ts +26 -22
- package/dist/types/run/format.d.ts +3 -3
- package/dist/types/run/help.d.ts +1 -1
- package/dist/types/run/media-cache-state.d.ts +2 -2
- package/dist/types/run/model-attempts.d.ts +1 -1
- package/dist/types/run/run-config.d.ts +4 -4
- package/dist/types/run/run-context.d.ts +3 -1
- package/dist/types/run/run-env.d.ts +3 -1
- package/dist/types/run/run-input.d.ts +2 -2
- package/dist/types/run/run-metrics.d.ts +3 -3
- package/dist/types/run/run-models.d.ts +3 -2
- package/dist/types/run/run-output.d.ts +1 -1
- package/dist/types/run/run-settings.d.ts +15 -6
- package/dist/types/run/run-stream.d.ts +2 -2
- package/dist/types/run/runner.d.ts +3 -2
- package/dist/types/run/slides-render.d.ts +4 -4
- package/dist/types/run/stdin-temp-file.d.ts +9 -0
- package/dist/types/run/stream-output.d.ts +1 -1
- package/dist/types/run/streaming.d.ts +4 -4
- package/dist/types/run/summary-engine.d.ts +11 -11
- package/dist/types/run/summary-llm.d.ts +5 -5
- package/dist/types/run/types.d.ts +4 -4
- package/dist/types/run.d.ts +1 -1
- package/dist/types/shared/contracts.d.ts +2 -2
- package/dist/types/shared/sse-events.d.ts +9 -9
- package/dist/types/slides/extract.d.ts +5 -4
- package/dist/types/slides/index.d.ts +5 -5
- package/dist/types/slides/store.d.ts +2 -2
- package/dist/types/slides/types.d.ts +2 -2
- package/dist/types/tty/osc-progress.d.ts +5 -5
- package/dist/types/tty/progress/fetch-html.d.ts +3 -3
- package/dist/types/tty/progress/transcript.d.ts +3 -3
- package/dist/types/tty/spinner.d.ts +2 -2
- package/dist/types/tty/theme.d.ts +2 -2
- package/dist/types/tty/website-progress.d.ts +3 -3
- package/dist/types/version.d.ts +1 -1
- package/docs/agent.md +38 -4
- package/docs/assets/site.js +46 -46
- package/docs/chrome-extension.md +11 -5
- package/docs/cli.md +59 -13
- package/docs/config.md +59 -10
- package/docs/extract-only.md +2 -0
- package/docs/index.html +33 -14
- package/docs/llm.md +7 -4
- package/docs/media.md +5 -4
- package/docs/model-auto.md +3 -2
- package/docs/nvidia-onnx-transcription.md +3 -3
- package/docs/openai.md +1 -1
- package/docs/releasing.md +3 -0
- package/docs/site/404.html +4 -1
- package/docs/site/assets/site.js +46 -46
- package/docs/site/docs/chrome-extension.html +18 -6
- package/docs/site/docs/config.html +29 -8
- package/docs/site/docs/extract-only.html +16 -4
- package/docs/site/docs/firecrawl.html +12 -3
- package/docs/site/docs/index.html +35 -6
- package/docs/site/docs/llm.html +19 -5
- package/docs/site/docs/openai.html +18 -5
- package/docs/site/docs/website.html +29 -9
- package/docs/site/docs/youtube.html +12 -3
- package/docs/site/index.html +33 -14
- package/docs/slides.md +13 -5
- package/docs/smoketest.md +29 -20
- package/docs/timestamps.md +21 -0
- package/docs/website.md +2 -1
- package/docs/youtube.md +4 -0
- package/package.json +36 -35
package/dist/esm/config.js
CHANGED
|
@@ -1,35 +1,82 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
4
|
-
import { isCliThemeName, listCliThemes } from
|
|
1
|
+
import JSON5 from "json5";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { isCliThemeName, listCliThemes } from "./tty/theme.js";
|
|
5
5
|
function isRecord(value) {
|
|
6
|
-
return typeof value ===
|
|
6
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
7
7
|
}
|
|
8
8
|
function parseOptionalBaseUrl(raw) {
|
|
9
|
-
return typeof raw ===
|
|
9
|
+
return typeof raw === "string" && raw.trim().length > 0 ? raw.trim() : undefined;
|
|
10
|
+
}
|
|
11
|
+
function resolveLegacyApiKeysEnv(apiKeys) {
|
|
12
|
+
if (!apiKeys)
|
|
13
|
+
return {};
|
|
14
|
+
const mapped = {};
|
|
15
|
+
if (typeof apiKeys.openai === "string")
|
|
16
|
+
mapped.OPENAI_API_KEY = apiKeys.openai;
|
|
17
|
+
if (typeof apiKeys.anthropic === "string")
|
|
18
|
+
mapped.ANTHROPIC_API_KEY = apiKeys.anthropic;
|
|
19
|
+
if (typeof apiKeys.google === "string")
|
|
20
|
+
mapped.GEMINI_API_KEY = apiKeys.google;
|
|
21
|
+
if (typeof apiKeys.xai === "string")
|
|
22
|
+
mapped.XAI_API_KEY = apiKeys.xai;
|
|
23
|
+
if (typeof apiKeys.openrouter === "string")
|
|
24
|
+
mapped.OPENROUTER_API_KEY = apiKeys.openrouter;
|
|
25
|
+
if (typeof apiKeys.zai === "string")
|
|
26
|
+
mapped.Z_AI_API_KEY = apiKeys.zai;
|
|
27
|
+
if (typeof apiKeys.apify === "string")
|
|
28
|
+
mapped.APIFY_API_TOKEN = apiKeys.apify;
|
|
29
|
+
if (typeof apiKeys.firecrawl === "string")
|
|
30
|
+
mapped.FIRECRAWL_API_KEY = apiKeys.firecrawl;
|
|
31
|
+
if (typeof apiKeys.fal === "string")
|
|
32
|
+
mapped.FAL_KEY = apiKeys.fal;
|
|
33
|
+
return mapped;
|
|
34
|
+
}
|
|
35
|
+
export function resolveConfigEnv(config) {
|
|
36
|
+
if (!config)
|
|
37
|
+
return {};
|
|
38
|
+
return {
|
|
39
|
+
...resolveLegacyApiKeysEnv(config.apiKeys),
|
|
40
|
+
...(config.env ?? {}),
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export function mergeConfigEnv({ env, config, }) {
|
|
44
|
+
const configEnv = resolveConfigEnv(config);
|
|
45
|
+
if (Object.keys(configEnv).length === 0)
|
|
46
|
+
return env;
|
|
47
|
+
let changed = false;
|
|
48
|
+
const merged = { ...env };
|
|
49
|
+
for (const [key, value] of Object.entries(configEnv)) {
|
|
50
|
+
const current = merged[key];
|
|
51
|
+
if (typeof current === "string" && current.trim().length > 0)
|
|
52
|
+
continue;
|
|
53
|
+
merged[key] = value;
|
|
54
|
+
changed = true;
|
|
55
|
+
}
|
|
56
|
+
return changed ? merged : env;
|
|
10
57
|
}
|
|
11
58
|
function parseProviderBaseUrlConfig(raw, path, providerName) {
|
|
12
|
-
if (typeof raw ===
|
|
59
|
+
if (typeof raw === "undefined")
|
|
13
60
|
return undefined;
|
|
14
61
|
if (!isRecord(raw)) {
|
|
15
62
|
throw new Error(`Invalid config file ${path}: "${providerName}" must be an object.`);
|
|
16
63
|
}
|
|
17
64
|
const baseUrl = parseOptionalBaseUrl(raw.baseUrl);
|
|
18
|
-
return typeof baseUrl ===
|
|
65
|
+
return typeof baseUrl === "string" ? { baseUrl } : undefined;
|
|
19
66
|
}
|
|
20
67
|
function parseAutoRuleKind(value) {
|
|
21
|
-
return value ===
|
|
22
|
-
value ===
|
|
23
|
-
value ===
|
|
24
|
-
value ===
|
|
25
|
-
value ===
|
|
26
|
-
value ===
|
|
68
|
+
return value === "text" ||
|
|
69
|
+
value === "website" ||
|
|
70
|
+
value === "youtube" ||
|
|
71
|
+
value === "image" ||
|
|
72
|
+
value === "video" ||
|
|
73
|
+
value === "file"
|
|
27
74
|
? value
|
|
28
75
|
: null;
|
|
29
76
|
}
|
|
30
77
|
function parseCliProvider(value, path) {
|
|
31
|
-
const trimmed = typeof value ===
|
|
32
|
-
if (trimmed ===
|
|
78
|
+
const trimmed = typeof value === "string" ? value.trim().toLowerCase() : "";
|
|
79
|
+
if (trimmed === "claude" || trimmed === "codex" || trimmed === "gemini" || trimmed === "agent") {
|
|
33
80
|
return trimmed;
|
|
34
81
|
}
|
|
35
82
|
throw new Error(`Invalid config file ${path}: unknown CLI provider "${String(value)}".`);
|
|
@@ -40,7 +87,7 @@ function parseStringArray(raw, path, label) {
|
|
|
40
87
|
}
|
|
41
88
|
const items = [];
|
|
42
89
|
for (const entry of raw) {
|
|
43
|
-
if (typeof entry !==
|
|
90
|
+
if (typeof entry !== "string") {
|
|
44
91
|
throw new Error(`Invalid config file ${path}: "${label}" must be an array of strings.`);
|
|
45
92
|
}
|
|
46
93
|
const trimmed = entry.trim();
|
|
@@ -51,21 +98,21 @@ function parseStringArray(raw, path, label) {
|
|
|
51
98
|
return items;
|
|
52
99
|
}
|
|
53
100
|
function parseLoggingLevel(raw, path) {
|
|
54
|
-
if (typeof raw !==
|
|
101
|
+
if (typeof raw !== "string") {
|
|
55
102
|
throw new Error(`Invalid config file ${path}: "logging.level" must be a string.`);
|
|
56
103
|
}
|
|
57
104
|
const trimmed = raw.trim().toLowerCase();
|
|
58
|
-
if (trimmed ===
|
|
105
|
+
if (trimmed === "debug" || trimmed === "info" || trimmed === "warn" || trimmed === "error") {
|
|
59
106
|
return trimmed;
|
|
60
107
|
}
|
|
61
108
|
throw new Error(`Invalid config file ${path}: "logging.level" must be one of "debug", "info", "warn", "error".`);
|
|
62
109
|
}
|
|
63
110
|
function parseLoggingFormat(raw, path) {
|
|
64
|
-
if (typeof raw !==
|
|
111
|
+
if (typeof raw !== "string") {
|
|
65
112
|
throw new Error(`Invalid config file ${path}: "logging.format" must be a string.`);
|
|
66
113
|
}
|
|
67
114
|
const trimmed = raw.trim().toLowerCase();
|
|
68
|
-
if (trimmed ===
|
|
115
|
+
if (trimmed === "json" || trimmed === "pretty") {
|
|
69
116
|
return trimmed;
|
|
70
117
|
}
|
|
71
118
|
throw new Error(`Invalid config file ${path}: "logging.format" must be one of "json" or "pretty".`);
|
|
@@ -86,12 +133,12 @@ function parseCliProviderConfig(raw, path, label) {
|
|
|
86
133
|
if (!isRecord(raw)) {
|
|
87
134
|
throw new Error(`Invalid config file ${path}: "cli.${label}" must be an object.`);
|
|
88
135
|
}
|
|
89
|
-
if (typeof raw.enabled !==
|
|
136
|
+
if (typeof raw.enabled !== "undefined") {
|
|
90
137
|
throw new Error(`Invalid config file ${path}: "cli.${label}.enabled" is not supported. Use "cli.enabled" instead.`);
|
|
91
138
|
}
|
|
92
|
-
const binaryValue = typeof raw.binary ===
|
|
93
|
-
const modelValue = typeof raw.model ===
|
|
94
|
-
const extraArgs = typeof raw.extraArgs ===
|
|
139
|
+
const binaryValue = typeof raw.binary === "string" ? raw.binary.trim() : undefined;
|
|
140
|
+
const modelValue = typeof raw.model === "string" ? raw.model.trim() : undefined;
|
|
141
|
+
const extraArgs = typeof raw.extraArgs === "undefined"
|
|
95
142
|
? undefined
|
|
96
143
|
: parseStringArray(raw.extraArgs, path, `cli.${label}.extraArgs`);
|
|
97
144
|
return {
|
|
@@ -100,6 +147,33 @@ function parseCliProviderConfig(raw, path, label) {
|
|
|
100
147
|
...(extraArgs && extraArgs.length > 0 ? { extraArgs } : {}),
|
|
101
148
|
};
|
|
102
149
|
}
|
|
150
|
+
function parseCliAutoFallbackConfig(raw, path, label) {
|
|
151
|
+
if (!isRecord(raw)) {
|
|
152
|
+
throw new Error(`Invalid config file ${path}: "cli.${label}" must be an object.`);
|
|
153
|
+
}
|
|
154
|
+
const enabled = typeof raw.enabled === "boolean"
|
|
155
|
+
? raw.enabled
|
|
156
|
+
: typeof raw.enabled === "undefined"
|
|
157
|
+
? undefined
|
|
158
|
+
: (() => {
|
|
159
|
+
throw new Error(`Invalid config file ${path}: "cli.${label}.enabled" must be a boolean.`);
|
|
160
|
+
})();
|
|
161
|
+
const onlyWhenNoApiKeys = typeof raw.onlyWhenNoApiKeys === "boolean"
|
|
162
|
+
? raw.onlyWhenNoApiKeys
|
|
163
|
+
: typeof raw.onlyWhenNoApiKeys === "undefined"
|
|
164
|
+
? undefined
|
|
165
|
+
: (() => {
|
|
166
|
+
throw new Error(`Invalid config file ${path}: "cli.${label}.onlyWhenNoApiKeys" must be a boolean.`);
|
|
167
|
+
})();
|
|
168
|
+
const order = typeof raw.order === "undefined"
|
|
169
|
+
? undefined
|
|
170
|
+
: parseCliProviderList(raw.order, path, `cli.${label}.order`);
|
|
171
|
+
return {
|
|
172
|
+
...(typeof enabled === "boolean" ? { enabled } : {}),
|
|
173
|
+
...(typeof onlyWhenNoApiKeys === "boolean" ? { onlyWhenNoApiKeys } : {}),
|
|
174
|
+
...(Array.isArray(order) && order.length > 0 ? { order } : {}),
|
|
175
|
+
};
|
|
176
|
+
}
|
|
103
177
|
function parseWhenKinds(raw, path) {
|
|
104
178
|
if (!Array.isArray(raw)) {
|
|
105
179
|
throw new Error(`Invalid config file ${path}: "model.rules[].when" must be an array of kinds.`);
|
|
@@ -124,7 +198,7 @@ function parseModelCandidates(raw, path) {
|
|
|
124
198
|
}
|
|
125
199
|
const candidates = [];
|
|
126
200
|
for (const entry of raw) {
|
|
127
|
-
if (typeof entry !==
|
|
201
|
+
if (typeof entry !== "string") {
|
|
128
202
|
throw new Error(`Invalid config file ${path}: "model.rules[].candidates" must be an array of strings.`);
|
|
129
203
|
}
|
|
130
204
|
const trimmed = entry.trim();
|
|
@@ -143,23 +217,23 @@ function parseTokenBand(raw, path) {
|
|
|
143
217
|
}
|
|
144
218
|
const candidates = parseModelCandidates(raw.candidates, path);
|
|
145
219
|
const token = (() => {
|
|
146
|
-
if (typeof raw.token ===
|
|
220
|
+
if (typeof raw.token === "undefined")
|
|
147
221
|
return undefined;
|
|
148
222
|
if (!isRecord(raw.token)) {
|
|
149
223
|
throw new Error(`Invalid config file ${path}: "model.rules[].bands[].token" must be an object.`);
|
|
150
224
|
}
|
|
151
|
-
const min = typeof raw.token.min ===
|
|
152
|
-
const max = typeof raw.token.max ===
|
|
153
|
-
if (typeof min ===
|
|
225
|
+
const min = typeof raw.token.min === "number" ? raw.token.min : undefined;
|
|
226
|
+
const max = typeof raw.token.max === "number" ? raw.token.max : undefined;
|
|
227
|
+
if (typeof min === "number" && (!Number.isFinite(min) || min < 0)) {
|
|
154
228
|
throw new Error(`Invalid config file ${path}: "model.rules[].bands[].token.min" must be >= 0.`);
|
|
155
229
|
}
|
|
156
|
-
if (typeof max ===
|
|
230
|
+
if (typeof max === "number" && (!Number.isFinite(max) || max < 0)) {
|
|
157
231
|
throw new Error(`Invalid config file ${path}: "model.rules[].bands[].token.max" must be >= 0.`);
|
|
158
232
|
}
|
|
159
|
-
if (typeof min ===
|
|
233
|
+
if (typeof min === "number" && typeof max === "number" && min > max) {
|
|
160
234
|
throw new Error(`Invalid config file ${path}: "model.rules[].bands[].token.min" must be <= "token.max".`);
|
|
161
235
|
}
|
|
162
|
-
return typeof min ===
|
|
236
|
+
return typeof min === "number" || typeof max === "number" ? { min, max } : undefined;
|
|
163
237
|
})();
|
|
164
238
|
return { ...(token ? { token } : {}), candidates };
|
|
165
239
|
}
|
|
@@ -169,15 +243,15 @@ function assertNoComments(raw, path) {
|
|
|
169
243
|
let line = 1;
|
|
170
244
|
let col = 1;
|
|
171
245
|
for (let i = 0; i < raw.length; i += 1) {
|
|
172
|
-
const ch = raw[i] ??
|
|
173
|
-
const next = raw[i + 1] ??
|
|
246
|
+
const ch = raw[i] ?? "";
|
|
247
|
+
const next = raw[i + 1] ?? "";
|
|
174
248
|
if (inString) {
|
|
175
249
|
if (escaped) {
|
|
176
250
|
escaped = false;
|
|
177
251
|
col += 1;
|
|
178
252
|
continue;
|
|
179
253
|
}
|
|
180
|
-
if (ch ===
|
|
254
|
+
if (ch === "\\") {
|
|
181
255
|
escaped = true;
|
|
182
256
|
col += 1;
|
|
183
257
|
continue;
|
|
@@ -185,7 +259,7 @@ function assertNoComments(raw, path) {
|
|
|
185
259
|
if (ch === inString) {
|
|
186
260
|
inString = null;
|
|
187
261
|
}
|
|
188
|
-
if (ch ===
|
|
262
|
+
if (ch === "\n") {
|
|
189
263
|
line += 1;
|
|
190
264
|
col = 1;
|
|
191
265
|
}
|
|
@@ -200,13 +274,13 @@ function assertNoComments(raw, path) {
|
|
|
200
274
|
col += 1;
|
|
201
275
|
continue;
|
|
202
276
|
}
|
|
203
|
-
if (ch ===
|
|
277
|
+
if (ch === "/" && next === "/") {
|
|
204
278
|
throw new Error(`Invalid config file ${path}: comments are not allowed (found // at ${line}:${col}).`);
|
|
205
279
|
}
|
|
206
|
-
if (ch ===
|
|
280
|
+
if (ch === "/" && next === "*") {
|
|
207
281
|
throw new Error(`Invalid config file ${path}: comments are not allowed (found /* at ${line}:${col}).`);
|
|
208
282
|
}
|
|
209
|
-
if (ch ===
|
|
283
|
+
if (ch === "\n") {
|
|
210
284
|
line += 1;
|
|
211
285
|
col = 1;
|
|
212
286
|
}
|
|
@@ -219,10 +293,10 @@ export function loadSummarizeConfig({ env }) {
|
|
|
219
293
|
const home = env.HOME?.trim() || env.USERPROFILE?.trim() || null;
|
|
220
294
|
if (!home)
|
|
221
295
|
return { config: null, path: null };
|
|
222
|
-
const path = join(home,
|
|
296
|
+
const path = join(home, ".summarize", "config.json");
|
|
223
297
|
let raw;
|
|
224
298
|
try {
|
|
225
|
-
raw = readFileSync(path,
|
|
299
|
+
raw = readFileSync(path, "utf8");
|
|
226
300
|
}
|
|
227
301
|
catch {
|
|
228
302
|
return { config: null, path };
|
|
@@ -240,21 +314,21 @@ export function loadSummarizeConfig({ env }) {
|
|
|
240
314
|
throw new Error(`Invalid config file ${path}: expected an object at the top level`);
|
|
241
315
|
}
|
|
242
316
|
const parseModelConfig = (raw, label) => {
|
|
243
|
-
if (typeof raw ===
|
|
317
|
+
if (typeof raw === "undefined")
|
|
244
318
|
return undefined;
|
|
245
319
|
// Shorthand:
|
|
246
320
|
// - "auto" -> { mode: "auto" }
|
|
247
321
|
// - "<provider>/<model>" or "openrouter/<provider>/<model>" -> { id: "..." }
|
|
248
322
|
// - "<name>" -> { name: "<name>" }
|
|
249
|
-
if (typeof raw ===
|
|
323
|
+
if (typeof raw === "string") {
|
|
250
324
|
const value = raw.trim();
|
|
251
325
|
if (value.length === 0) {
|
|
252
326
|
throw new Error(`Invalid config file ${path}: "${label}" must not be empty.`);
|
|
253
327
|
}
|
|
254
|
-
if (value.toLowerCase() ===
|
|
255
|
-
return { mode:
|
|
328
|
+
if (value.toLowerCase() === "auto") {
|
|
329
|
+
return { mode: "auto" };
|
|
256
330
|
}
|
|
257
|
-
if (value.includes(
|
|
331
|
+
if (value.includes("/")) {
|
|
258
332
|
return { id: value };
|
|
259
333
|
}
|
|
260
334
|
return { name: value };
|
|
@@ -262,30 +336,30 @@ export function loadSummarizeConfig({ env }) {
|
|
|
262
336
|
if (!isRecord(raw)) {
|
|
263
337
|
throw new Error(`Invalid config file ${path}: "${label}" must be an object.`);
|
|
264
338
|
}
|
|
265
|
-
if (typeof raw.name ===
|
|
339
|
+
if (typeof raw.name === "string") {
|
|
266
340
|
const name = raw.name.trim();
|
|
267
341
|
if (name.length === 0) {
|
|
268
342
|
throw new Error(`Invalid config file ${path}: "${label}.name" must not be empty.`);
|
|
269
343
|
}
|
|
270
|
-
if (name.toLowerCase() ===
|
|
344
|
+
if (name.toLowerCase() === "auto") {
|
|
271
345
|
throw new Error(`Invalid config file ${path}: "${label}.name" must not be "auto".`);
|
|
272
346
|
}
|
|
273
347
|
return { name };
|
|
274
348
|
}
|
|
275
|
-
if (typeof raw.id ===
|
|
349
|
+
if (typeof raw.id === "string") {
|
|
276
350
|
const id = raw.id.trim();
|
|
277
351
|
if (id.length === 0) {
|
|
278
352
|
throw new Error(`Invalid config file ${path}: "${label}.id" must not be empty.`);
|
|
279
353
|
}
|
|
280
|
-
if (!id.includes(
|
|
354
|
+
if (!id.includes("/")) {
|
|
281
355
|
throw new Error(`Invalid config file ${path}: "${label}.id" must be provider-prefixed (e.g. "openai/gpt-5-mini").`);
|
|
282
356
|
}
|
|
283
357
|
return { id };
|
|
284
358
|
}
|
|
285
|
-
const hasRules = typeof raw.rules !==
|
|
286
|
-
if (raw.mode ===
|
|
359
|
+
const hasRules = typeof raw.rules !== "undefined";
|
|
360
|
+
if (raw.mode === "auto" || (!("mode" in raw) && hasRules)) {
|
|
287
361
|
const rules = (() => {
|
|
288
|
-
if (typeof raw.rules ===
|
|
362
|
+
if (typeof raw.rules === "undefined")
|
|
289
363
|
return undefined;
|
|
290
364
|
if (!Array.isArray(raw.rules)) {
|
|
291
365
|
throw new Error(`Invalid config file ${path}: "${label}.rules" must be an array.`);
|
|
@@ -294,9 +368,9 @@ export function loadSummarizeConfig({ env }) {
|
|
|
294
368
|
for (const entry of raw.rules) {
|
|
295
369
|
if (!isRecord(entry))
|
|
296
370
|
continue;
|
|
297
|
-
const when = typeof entry.when ===
|
|
298
|
-
const hasCandidates = typeof entry.candidates !==
|
|
299
|
-
const hasBands = typeof entry.bands !==
|
|
371
|
+
const when = typeof entry.when === "undefined" ? undefined : parseWhenKinds(entry.when, path);
|
|
372
|
+
const hasCandidates = typeof entry.candidates !== "undefined";
|
|
373
|
+
const hasBands = typeof entry.bands !== "undefined";
|
|
300
374
|
if (hasCandidates && hasBands) {
|
|
301
375
|
throw new Error(`Invalid config file ${path}: "${label}.rules[]" must use either "candidates" or "bands" (not both).`);
|
|
302
376
|
}
|
|
@@ -317,18 +391,18 @@ export function loadSummarizeConfig({ env }) {
|
|
|
317
391
|
}
|
|
318
392
|
return rulesParsed;
|
|
319
393
|
})();
|
|
320
|
-
return { mode:
|
|
394
|
+
return { mode: "auto", ...(rules ? { rules } : {}) };
|
|
321
395
|
}
|
|
322
396
|
throw new Error(`Invalid config file ${path}: "${label}" must include either "id", "name", or { "mode": "auto" }.`);
|
|
323
397
|
};
|
|
324
398
|
const model = (() => {
|
|
325
|
-
return parseModelConfig(parsed.model,
|
|
399
|
+
return parseModelConfig(parsed.model, "model");
|
|
326
400
|
})();
|
|
327
401
|
const language = (() => {
|
|
328
402
|
const value = parsed.language;
|
|
329
|
-
if (typeof value ===
|
|
403
|
+
if (typeof value === "undefined")
|
|
330
404
|
return undefined;
|
|
331
|
-
if (typeof value !==
|
|
405
|
+
if (typeof value !== "string") {
|
|
332
406
|
throw new Error(`Invalid config file ${path}: "language" must be a string.`);
|
|
333
407
|
}
|
|
334
408
|
const trimmed = value.trim();
|
|
@@ -339,9 +413,9 @@ export function loadSummarizeConfig({ env }) {
|
|
|
339
413
|
})();
|
|
340
414
|
const prompt = (() => {
|
|
341
415
|
const value = parsed.prompt;
|
|
342
|
-
if (typeof value ===
|
|
416
|
+
if (typeof value === "undefined")
|
|
343
417
|
return undefined;
|
|
344
|
-
if (typeof value !==
|
|
418
|
+
if (typeof value !== "string") {
|
|
345
419
|
throw new Error(`Invalid config file ${path}: "prompt" must be a string.`);
|
|
346
420
|
}
|
|
347
421
|
const trimmed = value.trim();
|
|
@@ -352,11 +426,11 @@ export function loadSummarizeConfig({ env }) {
|
|
|
352
426
|
})();
|
|
353
427
|
const models = (() => {
|
|
354
428
|
const root = parsed;
|
|
355
|
-
if (typeof root.bags !==
|
|
429
|
+
if (typeof root.bags !== "undefined") {
|
|
356
430
|
throw new Error(`Invalid config file ${path}: legacy key "bags" is no longer supported. Use "models" instead.`);
|
|
357
431
|
}
|
|
358
432
|
const raw = root.models;
|
|
359
|
-
if (typeof raw ===
|
|
433
|
+
if (typeof raw === "undefined")
|
|
360
434
|
return undefined;
|
|
361
435
|
if (!isRecord(raw)) {
|
|
362
436
|
throw new Error(`Invalid config file ${path}: "models" must be an object.`);
|
|
@@ -368,7 +442,7 @@ export function loadSummarizeConfig({ env }) {
|
|
|
368
442
|
if (!key)
|
|
369
443
|
continue;
|
|
370
444
|
const keyLower = key.toLowerCase();
|
|
371
|
-
if (keyLower ===
|
|
445
|
+
if (keyLower === "auto") {
|
|
372
446
|
throw new Error(`Invalid config file ${path}: model name "auto" is reserved.`);
|
|
373
447
|
}
|
|
374
448
|
if (seen.has(keyLower)) {
|
|
@@ -377,13 +451,13 @@ export function loadSummarizeConfig({ env }) {
|
|
|
377
451
|
if (/\s/.test(key)) {
|
|
378
452
|
throw new Error(`Invalid config file ${path}: model name "${key}" must not contain spaces.`);
|
|
379
453
|
}
|
|
380
|
-
if (key.includes(
|
|
454
|
+
if (key.includes("/")) {
|
|
381
455
|
throw new Error(`Invalid config file ${path}: model name "${key}" must not include "/".`);
|
|
382
456
|
}
|
|
383
457
|
const parsedModel = parseModelConfig(value, `models.${key}`);
|
|
384
458
|
if (!parsedModel)
|
|
385
459
|
continue;
|
|
386
|
-
if (
|
|
460
|
+
if ("name" in parsedModel) {
|
|
387
461
|
throw new Error(`Invalid config file ${path}: "models.${key}" must not reference another model.`);
|
|
388
462
|
}
|
|
389
463
|
seen.add(keyLower);
|
|
@@ -393,90 +467,90 @@ export function loadSummarizeConfig({ env }) {
|
|
|
393
467
|
})();
|
|
394
468
|
const cache = (() => {
|
|
395
469
|
const value = parsed.cache;
|
|
396
|
-
if (typeof value ===
|
|
470
|
+
if (typeof value === "undefined")
|
|
397
471
|
return undefined;
|
|
398
472
|
if (!isRecord(value)) {
|
|
399
473
|
throw new Error(`Invalid config file ${path}: "cache" must be an object.`);
|
|
400
474
|
}
|
|
401
|
-
const enabled = typeof value.enabled ===
|
|
475
|
+
const enabled = typeof value.enabled === "boolean" ? value.enabled : undefined;
|
|
402
476
|
const maxMbRaw = value.maxMb;
|
|
403
|
-
const maxMb = typeof maxMbRaw ===
|
|
477
|
+
const maxMb = typeof maxMbRaw === "number" && Number.isFinite(maxMbRaw) && maxMbRaw > 0
|
|
404
478
|
? maxMbRaw
|
|
405
|
-
: typeof maxMbRaw ===
|
|
479
|
+
: typeof maxMbRaw === "undefined"
|
|
406
480
|
? undefined
|
|
407
481
|
: (() => {
|
|
408
482
|
throw new Error(`Invalid config file ${path}: "cache.maxMb" must be a number.`);
|
|
409
483
|
})();
|
|
410
484
|
const ttlDaysRaw = value.ttlDays;
|
|
411
|
-
const ttlDays = typeof ttlDaysRaw ===
|
|
485
|
+
const ttlDays = typeof ttlDaysRaw === "number" && Number.isFinite(ttlDaysRaw) && ttlDaysRaw > 0
|
|
412
486
|
? ttlDaysRaw
|
|
413
|
-
: typeof ttlDaysRaw ===
|
|
487
|
+
: typeof ttlDaysRaw === "undefined"
|
|
414
488
|
? undefined
|
|
415
489
|
: (() => {
|
|
416
490
|
throw new Error(`Invalid config file ${path}: "cache.ttlDays" must be a number.`);
|
|
417
491
|
})();
|
|
418
|
-
const pathValue = typeof value.path ===
|
|
492
|
+
const pathValue = typeof value.path === "string" && value.path.trim().length > 0
|
|
419
493
|
? value.path.trim()
|
|
420
|
-
: typeof value.path ===
|
|
494
|
+
: typeof value.path === "undefined"
|
|
421
495
|
? undefined
|
|
422
496
|
: (() => {
|
|
423
497
|
throw new Error(`Invalid config file ${path}: "cache.path" must be a string.`);
|
|
424
498
|
})();
|
|
425
499
|
const media = (() => {
|
|
426
500
|
const mediaValue = value.media;
|
|
427
|
-
if (typeof mediaValue ===
|
|
501
|
+
if (typeof mediaValue === "undefined")
|
|
428
502
|
return undefined;
|
|
429
503
|
if (!isRecord(mediaValue)) {
|
|
430
504
|
throw new Error(`Invalid config file ${path}: "cache.media" must be an object.`);
|
|
431
505
|
}
|
|
432
|
-
const mediaEnabled = typeof mediaValue.enabled ===
|
|
506
|
+
const mediaEnabled = typeof mediaValue.enabled === "boolean" ? mediaValue.enabled : undefined;
|
|
433
507
|
const mediaMaxRaw = mediaValue.maxMb;
|
|
434
|
-
const mediaMaxMb = typeof mediaMaxRaw ===
|
|
508
|
+
const mediaMaxMb = typeof mediaMaxRaw === "number" && Number.isFinite(mediaMaxRaw) && mediaMaxRaw > 0
|
|
435
509
|
? mediaMaxRaw
|
|
436
|
-
: typeof mediaMaxRaw ===
|
|
510
|
+
: typeof mediaMaxRaw === "undefined"
|
|
437
511
|
? undefined
|
|
438
512
|
: (() => {
|
|
439
513
|
throw new Error(`Invalid config file ${path}: "cache.media.maxMb" must be a number.`);
|
|
440
514
|
})();
|
|
441
515
|
const mediaTtlRaw = mediaValue.ttlDays;
|
|
442
|
-
const mediaTtlDays = typeof mediaTtlRaw ===
|
|
516
|
+
const mediaTtlDays = typeof mediaTtlRaw === "number" && Number.isFinite(mediaTtlRaw) && mediaTtlRaw > 0
|
|
443
517
|
? mediaTtlRaw
|
|
444
|
-
: typeof mediaTtlRaw ===
|
|
518
|
+
: typeof mediaTtlRaw === "undefined"
|
|
445
519
|
? undefined
|
|
446
520
|
: (() => {
|
|
447
521
|
throw new Error(`Invalid config file ${path}: "cache.media.ttlDays" must be a number.`);
|
|
448
522
|
})();
|
|
449
|
-
const mediaPath = typeof mediaValue.path ===
|
|
523
|
+
const mediaPath = typeof mediaValue.path === "string" && mediaValue.path.trim().length > 0
|
|
450
524
|
? mediaValue.path.trim()
|
|
451
|
-
: typeof mediaValue.path ===
|
|
525
|
+
: typeof mediaValue.path === "undefined"
|
|
452
526
|
? undefined
|
|
453
527
|
: (() => {
|
|
454
528
|
throw new Error(`Invalid config file ${path}: "cache.media.path" must be a string.`);
|
|
455
529
|
})();
|
|
456
|
-
const verifyRaw = typeof mediaValue.verify ===
|
|
457
|
-
const verify = verifyRaw ===
|
|
530
|
+
const verifyRaw = typeof mediaValue.verify === "string" ? mediaValue.verify.trim().toLowerCase() : "";
|
|
531
|
+
const verify = verifyRaw === "none" || verifyRaw === "size" || verifyRaw === "hash"
|
|
458
532
|
? verifyRaw
|
|
459
533
|
: verifyRaw.length > 0
|
|
460
534
|
? (() => {
|
|
461
535
|
throw new Error(`Invalid config file ${path}: "cache.media.verify" must be one of "none", "size", "hash".`);
|
|
462
536
|
})()
|
|
463
537
|
: undefined;
|
|
464
|
-
return mediaEnabled || mediaMaxMb || mediaTtlDays || mediaPath || typeof verify ===
|
|
538
|
+
return mediaEnabled || mediaMaxMb || mediaTtlDays || mediaPath || typeof verify === "string"
|
|
465
539
|
? {
|
|
466
|
-
...(typeof mediaEnabled ===
|
|
467
|
-
...(typeof mediaMaxMb ===
|
|
468
|
-
...(typeof mediaTtlDays ===
|
|
469
|
-
...(typeof mediaPath ===
|
|
470
|
-
...(typeof verify ===
|
|
540
|
+
...(typeof mediaEnabled === "boolean" ? { enabled: mediaEnabled } : {}),
|
|
541
|
+
...(typeof mediaMaxMb === "number" ? { maxMb: mediaMaxMb } : {}),
|
|
542
|
+
...(typeof mediaTtlDays === "number" ? { ttlDays: mediaTtlDays } : {}),
|
|
543
|
+
...(typeof mediaPath === "string" ? { path: mediaPath } : {}),
|
|
544
|
+
...(typeof verify === "string" ? { verify } : {}),
|
|
471
545
|
}
|
|
472
546
|
: undefined;
|
|
473
547
|
})();
|
|
474
548
|
return enabled || maxMb || ttlDays || pathValue || media
|
|
475
549
|
? {
|
|
476
|
-
...(typeof enabled ===
|
|
477
|
-
...(typeof maxMb ===
|
|
478
|
-
...(typeof ttlDays ===
|
|
479
|
-
...(typeof pathValue ===
|
|
550
|
+
...(typeof enabled === "boolean" ? { enabled } : {}),
|
|
551
|
+
...(typeof maxMb === "number" ? { maxMb } : {}),
|
|
552
|
+
...(typeof ttlDays === "number" ? { ttlDays } : {}),
|
|
553
|
+
...(typeof pathValue === "string" ? { path: pathValue } : {}),
|
|
480
554
|
...(media ? { media } : {}),
|
|
481
555
|
}
|
|
482
556
|
: undefined;
|
|
@@ -485,69 +559,69 @@ export function loadSummarizeConfig({ env }) {
|
|
|
485
559
|
const value = parsed.media;
|
|
486
560
|
if (!isRecord(value))
|
|
487
561
|
return undefined;
|
|
488
|
-
const videoMode = value.videoMode ===
|
|
489
|
-
value.videoMode ===
|
|
490
|
-
value.videoMode ===
|
|
562
|
+
const videoMode = value.videoMode === "auto" ||
|
|
563
|
+
value.videoMode === "transcript" ||
|
|
564
|
+
value.videoMode === "understand"
|
|
491
565
|
? value.videoMode
|
|
492
566
|
: undefined;
|
|
493
567
|
return videoMode ? { videoMode } : undefined;
|
|
494
568
|
})();
|
|
495
569
|
const slides = (() => {
|
|
496
570
|
const value = parsed.slides;
|
|
497
|
-
if (typeof value ===
|
|
571
|
+
if (typeof value === "undefined")
|
|
498
572
|
return undefined;
|
|
499
573
|
if (!isRecord(value)) {
|
|
500
574
|
throw new Error(`Invalid config file ${path}: "slides" must be an object.`);
|
|
501
575
|
}
|
|
502
|
-
const enabled = typeof value.enabled ===
|
|
503
|
-
const ocr = typeof value.ocr ===
|
|
504
|
-
const dir = typeof value.dir ===
|
|
576
|
+
const enabled = typeof value.enabled === "boolean" ? value.enabled : undefined;
|
|
577
|
+
const ocr = typeof value.ocr === "boolean" ? value.ocr : undefined;
|
|
578
|
+
const dir = typeof value.dir === "string" && value.dir.trim().length > 0
|
|
505
579
|
? value.dir.trim()
|
|
506
|
-
: typeof value.dir ===
|
|
580
|
+
: typeof value.dir === "undefined"
|
|
507
581
|
? undefined
|
|
508
582
|
: (() => {
|
|
509
583
|
throw new Error(`Invalid config file ${path}: "slides.dir" must be a string.`);
|
|
510
584
|
})();
|
|
511
585
|
const sceneRaw = value.sceneThreshold;
|
|
512
|
-
const sceneThreshold = typeof sceneRaw ===
|
|
586
|
+
const sceneThreshold = typeof sceneRaw === "number" && Number.isFinite(sceneRaw) && sceneRaw >= 0.1 && sceneRaw <= 1
|
|
513
587
|
? sceneRaw
|
|
514
|
-
: typeof sceneRaw ===
|
|
588
|
+
: typeof sceneRaw === "undefined"
|
|
515
589
|
? undefined
|
|
516
590
|
: (() => {
|
|
517
591
|
throw new Error(`Invalid config file ${path}: "slides.sceneThreshold" must be a number between 0.1 and 1.0.`);
|
|
518
592
|
})();
|
|
519
593
|
const maxRaw = value.max;
|
|
520
|
-
const max = typeof maxRaw ===
|
|
594
|
+
const max = typeof maxRaw === "number" &&
|
|
521
595
|
Number.isFinite(maxRaw) &&
|
|
522
596
|
Number.isInteger(maxRaw) &&
|
|
523
597
|
maxRaw > 0
|
|
524
598
|
? maxRaw
|
|
525
|
-
: typeof maxRaw ===
|
|
599
|
+
: typeof maxRaw === "undefined"
|
|
526
600
|
? undefined
|
|
527
601
|
: (() => {
|
|
528
602
|
throw new Error(`Invalid config file ${path}: "slides.max" must be an integer.`);
|
|
529
603
|
})();
|
|
530
604
|
const minRaw = value.minDuration;
|
|
531
|
-
const minDuration = typeof minRaw ===
|
|
605
|
+
const minDuration = typeof minRaw === "number" && Number.isFinite(minRaw) && minRaw >= 0
|
|
532
606
|
? minRaw
|
|
533
|
-
: typeof minRaw ===
|
|
607
|
+
: typeof minRaw === "undefined"
|
|
534
608
|
? undefined
|
|
535
609
|
: (() => {
|
|
536
610
|
throw new Error(`Invalid config file ${path}: "slides.minDuration" must be a number.`);
|
|
537
611
|
})();
|
|
538
612
|
return enabled ||
|
|
539
|
-
typeof ocr ===
|
|
613
|
+
typeof ocr === "boolean" ||
|
|
540
614
|
dir ||
|
|
541
|
-
typeof sceneThreshold ===
|
|
542
|
-
typeof max ===
|
|
543
|
-
typeof minDuration ===
|
|
615
|
+
typeof sceneThreshold === "number" ||
|
|
616
|
+
typeof max === "number" ||
|
|
617
|
+
typeof minDuration === "number"
|
|
544
618
|
? {
|
|
545
|
-
...(typeof enabled ===
|
|
546
|
-
...(typeof ocr ===
|
|
547
|
-
...(typeof dir ===
|
|
548
|
-
...(typeof sceneThreshold ===
|
|
549
|
-
...(typeof max ===
|
|
550
|
-
...(typeof minDuration ===
|
|
619
|
+
...(typeof enabled === "boolean" ? { enabled } : {}),
|
|
620
|
+
...(typeof ocr === "boolean" ? { ocr } : {}),
|
|
621
|
+
...(typeof dir === "string" ? { dir } : {}),
|
|
622
|
+
...(typeof sceneThreshold === "number" ? { sceneThreshold } : {}),
|
|
623
|
+
...(typeof max === "number" ? { max } : {}),
|
|
624
|
+
...(typeof minDuration === "number" ? { minDuration } : {}),
|
|
551
625
|
}
|
|
552
626
|
: undefined;
|
|
553
627
|
})();
|
|
@@ -555,29 +629,44 @@ export function loadSummarizeConfig({ env }) {
|
|
|
555
629
|
const value = parsed.cli;
|
|
556
630
|
if (!isRecord(value))
|
|
557
631
|
return undefined;
|
|
558
|
-
if (typeof value.disabled !==
|
|
632
|
+
if (typeof value.disabled !== "undefined") {
|
|
559
633
|
throw new Error(`Invalid config file ${path}: "cli.disabled" is not supported. Use "cli.enabled" instead.`);
|
|
560
634
|
}
|
|
561
|
-
const enabled = typeof value.enabled !==
|
|
562
|
-
? parseCliProviderList(value.enabled, path,
|
|
635
|
+
const enabled = typeof value.enabled !== "undefined"
|
|
636
|
+
? parseCliProviderList(value.enabled, path, "cli.enabled")
|
|
563
637
|
: undefined;
|
|
564
|
-
const claude = value.claude ? parseCliProviderConfig(value.claude, path,
|
|
565
|
-
const codex = value.codex ? parseCliProviderConfig(value.codex, path,
|
|
566
|
-
const gemini = value.gemini ? parseCliProviderConfig(value.gemini, path,
|
|
567
|
-
const
|
|
638
|
+
const claude = value.claude ? parseCliProviderConfig(value.claude, path, "claude") : undefined;
|
|
639
|
+
const codex = value.codex ? parseCliProviderConfig(value.codex, path, "codex") : undefined;
|
|
640
|
+
const gemini = value.gemini ? parseCliProviderConfig(value.gemini, path, "gemini") : undefined;
|
|
641
|
+
const agent = value.agent ? parseCliProviderConfig(value.agent, path, "agent") : undefined;
|
|
642
|
+
if (typeof value.autoFallback !== "undefined" && typeof value.magicAuto !== "undefined") {
|
|
643
|
+
throw new Error(`Invalid config file ${path}: use only one of "cli.autoFallback" or legacy "cli.magicAuto".`);
|
|
644
|
+
}
|
|
645
|
+
const autoFallback = (() => {
|
|
646
|
+
if (typeof value.autoFallback !== "undefined") {
|
|
647
|
+
return parseCliAutoFallbackConfig(value.autoFallback, path, "autoFallback");
|
|
648
|
+
}
|
|
649
|
+
if (typeof value.magicAuto !== "undefined") {
|
|
650
|
+
return parseCliAutoFallbackConfig(value.magicAuto, path, "magicAuto");
|
|
651
|
+
}
|
|
652
|
+
return undefined;
|
|
653
|
+
})();
|
|
654
|
+
const promptOverride = typeof value.promptOverride === "string" && value.promptOverride.trim().length > 0
|
|
568
655
|
? value.promptOverride.trim()
|
|
569
656
|
: undefined;
|
|
570
|
-
const allowTools = typeof value.allowTools ===
|
|
571
|
-
const cwd = typeof value.cwd ===
|
|
572
|
-
const extraArgs = typeof value.extraArgs ===
|
|
657
|
+
const allowTools = typeof value.allowTools === "boolean" ? value.allowTools : undefined;
|
|
658
|
+
const cwd = typeof value.cwd === "string" && value.cwd.trim().length > 0 ? value.cwd.trim() : undefined;
|
|
659
|
+
const extraArgs = typeof value.extraArgs === "undefined"
|
|
573
660
|
? undefined
|
|
574
|
-
: parseStringArray(value.extraArgs, path,
|
|
661
|
+
: parseStringArray(value.extraArgs, path, "cli.extraArgs");
|
|
575
662
|
return enabled ||
|
|
576
663
|
claude ||
|
|
577
664
|
codex ||
|
|
578
665
|
gemini ||
|
|
666
|
+
agent ||
|
|
667
|
+
autoFallback ||
|
|
579
668
|
promptOverride ||
|
|
580
|
-
typeof allowTools ===
|
|
669
|
+
typeof allowTools === "boolean" ||
|
|
581
670
|
cwd ||
|
|
582
671
|
(extraArgs && extraArgs.length > 0)
|
|
583
672
|
? {
|
|
@@ -585,8 +674,10 @@ export function loadSummarizeConfig({ env }) {
|
|
|
585
674
|
...(claude ? { claude } : {}),
|
|
586
675
|
...(codex ? { codex } : {}),
|
|
587
676
|
...(gemini ? { gemini } : {}),
|
|
677
|
+
...(agent ? { agent } : {}),
|
|
678
|
+
...(autoFallback ? { autoFallback } : {}),
|
|
588
679
|
...(promptOverride ? { promptOverride } : {}),
|
|
589
|
-
...(typeof allowTools ===
|
|
680
|
+
...(typeof allowTools === "boolean" ? { allowTools } : {}),
|
|
590
681
|
...(cwd ? { cwd } : {}),
|
|
591
682
|
...(extraArgs && extraArgs.length > 0 ? { extraArgs } : {}),
|
|
592
683
|
}
|
|
@@ -594,59 +685,59 @@ export function loadSummarizeConfig({ env }) {
|
|
|
594
685
|
})();
|
|
595
686
|
const output = (() => {
|
|
596
687
|
const value = parsed.output;
|
|
597
|
-
if (typeof value ===
|
|
688
|
+
if (typeof value === "undefined")
|
|
598
689
|
return undefined;
|
|
599
690
|
if (!isRecord(value)) {
|
|
600
691
|
throw new Error(`Invalid config file ${path}: "output" must be an object.`);
|
|
601
692
|
}
|
|
602
|
-
const language = typeof value.language ===
|
|
693
|
+
const language = typeof value.language === "string" && value.language.trim().length > 0
|
|
603
694
|
? value.language.trim()
|
|
604
695
|
: undefined;
|
|
605
|
-
return typeof language ===
|
|
696
|
+
return typeof language === "string" ? { language } : undefined;
|
|
606
697
|
})();
|
|
607
698
|
const ui = (() => {
|
|
608
699
|
const value = parsed.ui;
|
|
609
|
-
if (typeof value ===
|
|
700
|
+
if (typeof value === "undefined")
|
|
610
701
|
return undefined;
|
|
611
702
|
if (!isRecord(value)) {
|
|
612
703
|
throw new Error(`Invalid config file ${path}: "ui" must be an object.`);
|
|
613
704
|
}
|
|
614
|
-
const themeRaw = typeof value.theme ===
|
|
705
|
+
const themeRaw = typeof value.theme === "string" ? value.theme.trim().toLowerCase() : "";
|
|
615
706
|
if (themeRaw && !isCliThemeName(themeRaw)) {
|
|
616
|
-
throw new Error(`Invalid config file ${path}: "ui.theme" must be one of ${listCliThemes().join(
|
|
707
|
+
throw new Error(`Invalid config file ${path}: "ui.theme" must be one of ${listCliThemes().join(", ")}.`);
|
|
617
708
|
}
|
|
618
709
|
const theme = themeRaw.length > 0 ? themeRaw : undefined;
|
|
619
710
|
return theme ? { theme } : undefined;
|
|
620
711
|
})();
|
|
621
712
|
const logging = (() => {
|
|
622
713
|
const value = parsed.logging;
|
|
623
|
-
if (typeof value ===
|
|
714
|
+
if (typeof value === "undefined")
|
|
624
715
|
return undefined;
|
|
625
716
|
if (!isRecord(value)) {
|
|
626
717
|
throw new Error(`Invalid config file ${path}: "logging" must be an object.`);
|
|
627
718
|
}
|
|
628
|
-
const enabled = typeof value.enabled ===
|
|
629
|
-
const level = typeof value.level ===
|
|
630
|
-
const format = typeof value.format ===
|
|
631
|
-
const file = typeof value.file ===
|
|
719
|
+
const enabled = typeof value.enabled === "boolean" ? value.enabled : undefined;
|
|
720
|
+
const level = typeof value.level === "undefined" ? undefined : parseLoggingLevel(value.level, path);
|
|
721
|
+
const format = typeof value.format === "undefined" ? undefined : parseLoggingFormat(value.format, path);
|
|
722
|
+
const file = typeof value.file === "string" && value.file.trim().length > 0
|
|
632
723
|
? value.file.trim()
|
|
633
|
-
: typeof value.file ===
|
|
724
|
+
: typeof value.file === "undefined"
|
|
634
725
|
? undefined
|
|
635
726
|
: (() => {
|
|
636
727
|
throw new Error(`Invalid config file ${path}: "logging.file" must be a string.`);
|
|
637
728
|
})();
|
|
638
729
|
const maxMbRaw = value.maxMb;
|
|
639
|
-
const maxMb = typeof maxMbRaw ===
|
|
730
|
+
const maxMb = typeof maxMbRaw === "number" && Number.isFinite(maxMbRaw) && maxMbRaw > 0
|
|
640
731
|
? maxMbRaw
|
|
641
|
-
: typeof maxMbRaw ===
|
|
732
|
+
: typeof maxMbRaw === "undefined"
|
|
642
733
|
? undefined
|
|
643
734
|
: (() => {
|
|
644
735
|
throw new Error(`Invalid config file ${path}: "logging.maxMb" must be a number.`);
|
|
645
736
|
})();
|
|
646
737
|
const maxFilesRaw = value.maxFiles;
|
|
647
|
-
const maxFiles = typeof maxFilesRaw ===
|
|
738
|
+
const maxFiles = typeof maxFilesRaw === "number" && Number.isFinite(maxFilesRaw) && maxFilesRaw > 0
|
|
648
739
|
? Math.trunc(maxFilesRaw)
|
|
649
|
-
: typeof maxFilesRaw ===
|
|
740
|
+
: typeof maxFilesRaw === "undefined"
|
|
650
741
|
? undefined
|
|
651
742
|
: (() => {
|
|
652
743
|
throw new Error(`Invalid config file ${path}: "logging.maxFiles" must be a number.`);
|
|
@@ -655,46 +746,97 @@ export function loadSummarizeConfig({ env }) {
|
|
|
655
746
|
level ||
|
|
656
747
|
format ||
|
|
657
748
|
file ||
|
|
658
|
-
typeof maxMb ===
|
|
659
|
-
typeof maxFiles ===
|
|
749
|
+
typeof maxMb === "number" ||
|
|
750
|
+
typeof maxFiles === "number"
|
|
660
751
|
? {
|
|
661
|
-
...(typeof enabled ===
|
|
752
|
+
...(typeof enabled === "boolean" ? { enabled } : {}),
|
|
662
753
|
...(level ? { level } : {}),
|
|
663
754
|
...(format ? { format } : {}),
|
|
664
755
|
...(file ? { file } : {}),
|
|
665
|
-
...(typeof maxMb ===
|
|
666
|
-
...(typeof maxFiles ===
|
|
756
|
+
...(typeof maxMb === "number" ? { maxMb } : {}),
|
|
757
|
+
...(typeof maxFiles === "number" ? { maxFiles } : {}),
|
|
667
758
|
}
|
|
668
759
|
: undefined;
|
|
669
760
|
})();
|
|
670
761
|
const openai = (() => {
|
|
671
762
|
const value = parsed.openai;
|
|
672
|
-
if (typeof value ===
|
|
763
|
+
if (typeof value === "undefined")
|
|
673
764
|
return undefined;
|
|
674
765
|
if (!isRecord(value)) {
|
|
675
766
|
throw new Error(`Invalid config file ${path}: "openai" must be an object.`);
|
|
676
767
|
}
|
|
677
768
|
const baseUrl = parseOptionalBaseUrl(value.baseUrl);
|
|
678
|
-
const useChatCompletions = typeof value.useChatCompletions ===
|
|
769
|
+
const useChatCompletions = typeof value.useChatCompletions === "boolean" ? value.useChatCompletions : undefined;
|
|
679
770
|
const whisperUsdPerMinuteRaw = value.whisperUsdPerMinute;
|
|
680
|
-
const whisperUsdPerMinute = typeof whisperUsdPerMinuteRaw ===
|
|
771
|
+
const whisperUsdPerMinute = typeof whisperUsdPerMinuteRaw === "number" &&
|
|
681
772
|
Number.isFinite(whisperUsdPerMinuteRaw) &&
|
|
682
773
|
whisperUsdPerMinuteRaw > 0
|
|
683
774
|
? whisperUsdPerMinuteRaw
|
|
684
775
|
: undefined;
|
|
685
|
-
return typeof baseUrl ===
|
|
686
|
-
typeof useChatCompletions ===
|
|
687
|
-
typeof whisperUsdPerMinute ===
|
|
776
|
+
return typeof baseUrl === "string" ||
|
|
777
|
+
typeof useChatCompletions === "boolean" ||
|
|
778
|
+
typeof whisperUsdPerMinute === "number"
|
|
688
779
|
? {
|
|
689
|
-
...(typeof baseUrl ===
|
|
690
|
-
...(typeof useChatCompletions ===
|
|
691
|
-
...(typeof whisperUsdPerMinute ===
|
|
780
|
+
...(typeof baseUrl === "string" ? { baseUrl } : {}),
|
|
781
|
+
...(typeof useChatCompletions === "boolean" ? { useChatCompletions } : {}),
|
|
782
|
+
...(typeof whisperUsdPerMinute === "number" ? { whisperUsdPerMinute } : {}),
|
|
692
783
|
}
|
|
693
784
|
: undefined;
|
|
694
785
|
})();
|
|
695
|
-
const anthropic = parseProviderBaseUrlConfig(parsed.anthropic, path,
|
|
696
|
-
const google = parseProviderBaseUrlConfig(parsed.google, path,
|
|
697
|
-
const xai = parseProviderBaseUrlConfig(parsed.xai, path,
|
|
786
|
+
const anthropic = parseProviderBaseUrlConfig(parsed.anthropic, path, "anthropic");
|
|
787
|
+
const google = parseProviderBaseUrlConfig(parsed.google, path, "google");
|
|
788
|
+
const xai = parseProviderBaseUrlConfig(parsed.xai, path, "xai");
|
|
789
|
+
const configEnv = (() => {
|
|
790
|
+
const value = parsed.env;
|
|
791
|
+
if (typeof value === "undefined")
|
|
792
|
+
return undefined;
|
|
793
|
+
if (!isRecord(value)) {
|
|
794
|
+
throw new Error(`Invalid config file ${path}: "env" must be an object.`);
|
|
795
|
+
}
|
|
796
|
+
const env = {};
|
|
797
|
+
for (const [rawKey, rawValue] of Object.entries(value)) {
|
|
798
|
+
const key = rawKey.trim();
|
|
799
|
+
if (key.length === 0) {
|
|
800
|
+
throw new Error(`Invalid config file ${path}: "env" contains an empty key.`);
|
|
801
|
+
}
|
|
802
|
+
if (typeof rawValue !== "string") {
|
|
803
|
+
throw new Error(`Invalid config file ${path}: "env.${rawKey}" must be a string.`);
|
|
804
|
+
}
|
|
805
|
+
env[key] = rawValue;
|
|
806
|
+
}
|
|
807
|
+
return Object.keys(env).length > 0 ? env : undefined;
|
|
808
|
+
})();
|
|
809
|
+
const apiKeys = (() => {
|
|
810
|
+
const value = parsed.apiKeys;
|
|
811
|
+
if (typeof value === "undefined")
|
|
812
|
+
return undefined;
|
|
813
|
+
if (!isRecord(value)) {
|
|
814
|
+
throw new Error(`Invalid config file ${path}: "apiKeys" must be an object.`);
|
|
815
|
+
}
|
|
816
|
+
const keys = {};
|
|
817
|
+
const allowed = [
|
|
818
|
+
"openai",
|
|
819
|
+
"anthropic",
|
|
820
|
+
"google",
|
|
821
|
+
"xai",
|
|
822
|
+
"openrouter",
|
|
823
|
+
"zai",
|
|
824
|
+
"apify",
|
|
825
|
+
"firecrawl",
|
|
826
|
+
"fal",
|
|
827
|
+
];
|
|
828
|
+
for (const [key, val] of Object.entries(value)) {
|
|
829
|
+
const k = key.trim().toLowerCase();
|
|
830
|
+
if (!allowed.includes(k)) {
|
|
831
|
+
throw new Error(`Invalid config file ${path}: unknown apiKeys provider "${key}".`);
|
|
832
|
+
}
|
|
833
|
+
if (typeof val !== "string" || val.trim().length === 0) {
|
|
834
|
+
throw new Error(`Invalid config file ${path}: "apiKeys.${key}" must be a non-empty string.`);
|
|
835
|
+
}
|
|
836
|
+
keys[k] = val.trim();
|
|
837
|
+
}
|
|
838
|
+
return Object.keys(keys).length > 0 ? keys : undefined;
|
|
839
|
+
})();
|
|
698
840
|
return {
|
|
699
841
|
config: {
|
|
700
842
|
...(model ? { model } : {}),
|
|
@@ -712,6 +854,8 @@ export function loadSummarizeConfig({ env }) {
|
|
|
712
854
|
...(google ? { google } : {}),
|
|
713
855
|
...(xai ? { xai } : {}),
|
|
714
856
|
...(logging ? { logging } : {}),
|
|
857
|
+
...(configEnv ? { env: configEnv } : {}),
|
|
858
|
+
...(apiKeys ? { apiKeys } : {}),
|
|
715
859
|
},
|
|
716
860
|
path,
|
|
717
861
|
};
|