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