@cjhyy/code-shell-core 0.5.0-rc.2 → 0.6.0-rc.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/README.md +13 -10
- package/dist/agent/agent-definition-registry.d.ts +3 -0
- package/dist/agent/agent-definition-registry.js +3 -1
- package/dist/agent/agent-definition.d.ts +15 -0
- package/dist/agent/agent-definition.js +27 -3
- package/dist/arena/context/context-tools.js +47 -4
- package/dist/arena/ledger.js +9 -1
- package/dist/arena/strategies/utils.d.ts +1 -4
- package/dist/arena/strategies/utils.js +7 -84
- package/dist/automation/cron-expr.d.ts +10 -0
- package/dist/automation/cron-expr.js +23 -5
- package/dist/automation/runner.d.ts +21 -4
- package/dist/automation/runner.js +48 -12
- package/dist/automation/scheduler.d.ts +38 -0
- package/dist/automation/scheduler.js +89 -12
- package/dist/automation/store.js +5 -2
- package/dist/capability-control/disabled-lists.d.ts +25 -0
- package/dist/capability-control/disabled-lists.js +57 -0
- package/dist/capability-control/overlay.d.ts +15 -0
- package/dist/capability-control/overlay.js +27 -0
- package/dist/cc-orchestrator/agent-adapter.d.ts +50 -0
- package/dist/cc-orchestrator/agent-adapter.js +133 -0
- package/dist/cc-orchestrator/cc-capability.d.ts +19 -0
- package/dist/cc-orchestrator/cc-capability.js +53 -0
- package/dist/cc-orchestrator/codex-session-discovery.d.ts +24 -0
- package/dist/cc-orchestrator/codex-session-discovery.js +191 -0
- package/dist/cc-orchestrator/codex-session-history.d.ts +25 -0
- package/dist/cc-orchestrator/codex-session-history.js +187 -0
- package/dist/cc-orchestrator/external-agent-changes.d.ts +19 -0
- package/dist/cc-orchestrator/external-agent-changes.js +214 -0
- package/dist/cc-orchestrator/external-agent-driver.d.ts +18 -0
- package/dist/cc-orchestrator/external-agent-driver.js +69 -0
- package/dist/cc-orchestrator/index.d.ts +8 -0
- package/dist/cc-orchestrator/index.js +8 -0
- package/dist/cc-orchestrator/relevance-judge.d.ts +15 -0
- package/dist/cc-orchestrator/relevance-judge.js +29 -0
- package/dist/cc-orchestrator/session-discovery.d.ts +46 -0
- package/dist/cc-orchestrator/session-discovery.js +125 -0
- package/dist/cc-orchestrator/session-history.d.ts +19 -0
- package/dist/cc-orchestrator/session-history.js +67 -0
- package/dist/cli/agent-server-stdio.d.ts +15 -1
- package/dist/cli/agent-server-stdio.js +115 -17
- package/dist/cli/agent-server-tcp.js +40 -26
- package/dist/context/compaction.d.ts +56 -0
- package/dist/context/compaction.js +186 -0
- package/dist/context/manager.js +25 -4
- package/dist/cost-tracker.js +5 -61
- package/dist/credentials/cipher.d.ts +49 -0
- package/dist/credentials/cipher.js +45 -0
- package/dist/credentials/cookie-jar.d.ts +24 -0
- package/dist/credentials/cookie-jar.js +40 -0
- package/dist/credentials/index.d.ts +7 -0
- package/dist/credentials/index.js +5 -0
- package/dist/credentials/inject-credential-tool.d.ts +20 -0
- package/dist/credentials/inject-credential-tool.js +130 -0
- package/dist/credentials/store.d.ts +72 -0
- package/dist/credentials/store.js +184 -0
- package/dist/credentials/types.d.ts +56 -0
- package/dist/credentials/use-credential-tool.d.ts +29 -0
- package/dist/credentials/use-credential-tool.js +205 -0
- package/dist/credentials/use-gate.d.ts +56 -0
- package/dist/credentials/use-gate.js +52 -0
- package/dist/data/model-metadata.d.ts +77 -0
- package/dist/data/model-metadata.js +56 -0
- package/dist/data/model-metadata.json +216 -0
- package/dist/data/openrouter-models.d.ts +18 -7
- package/dist/data/openrouter-models.js +35 -8
- package/dist/engine/aux-key.d.ts +10 -0
- package/dist/engine/aux-key.js +11 -0
- package/dist/engine/dynamic-tool-defs.d.ts +19 -0
- package/dist/engine/dynamic-tool-defs.js +36 -0
- package/dist/engine/engine.d.ts +267 -138
- package/dist/engine/engine.js +957 -191
- package/dist/engine/friendly-error.d.ts +18 -0
- package/dist/engine/friendly-error.js +63 -0
- package/dist/engine/goal.d.ts +145 -0
- package/dist/engine/goal.js +144 -0
- package/dist/engine/image-policy.d.ts +13 -0
- package/dist/engine/image-policy.js +24 -0
- package/dist/engine/model-connections-pool.d.ts +17 -0
- package/dist/engine/model-connections-pool.js +66 -0
- package/dist/engine/model-facade.d.ts +10 -0
- package/dist/engine/model-facade.js +25 -0
- package/dist/engine/patch-orphaned-tools.js +3 -0
- package/dist/engine/resolve-llm-config.d.ts +16 -0
- package/dist/engine/resolve-llm-config.js +44 -0
- package/dist/engine/runtime.js +2 -1
- package/dist/engine/sandbox-cache-key.d.ts +10 -0
- package/dist/engine/sandbox-cache-key.js +9 -0
- package/dist/engine/sandbox-config.d.ts +31 -0
- package/dist/engine/sandbox-config.js +38 -0
- package/dist/engine/session-usage.d.ts +19 -0
- package/dist/engine/session-usage.js +25 -0
- package/dist/engine/steer-queue.d.ts +32 -0
- package/dist/engine/steer-queue.js +26 -0
- package/dist/engine/streaming-tool-queue.d.ts +12 -0
- package/dist/engine/streaming-tool-queue.js +50 -10
- package/dist/engine/turn-loop.d.ts +67 -3
- package/dist/engine/turn-loop.js +292 -41
- package/dist/engine/types.d.ts +175 -0
- package/dist/engine/types.js +13 -0
- package/dist/external-agents/config.d.ts +2 -0
- package/dist/external-agents/config.js +15 -0
- package/dist/external-agents/types.d.ts +31 -0
- package/dist/external-agents/types.js +1 -0
- package/dist/git/utils.js +11 -6
- package/dist/git/worktree.d.ts +48 -0
- package/dist/git/worktree.js +86 -10
- package/dist/hooks/goal-stop-hook.d.ts +28 -0
- package/dist/hooks/goal-stop-hook.js +186 -9
- package/dist/hooks/registry.d.ts +8 -0
- package/dist/hooks/registry.js +19 -0
- package/dist/hooks/shell-runner.js +10 -21
- package/dist/index.d.ts +49 -6
- package/dist/index.js +60 -4
- package/dist/llm/capabilities/param-specs.d.ts +14 -0
- package/dist/llm/capabilities/param-specs.js +62 -0
- package/dist/llm/capabilities/rules.js +4 -0
- package/dist/llm/capabilities/types.d.ts +10 -0
- package/dist/llm/client-base.d.ts +28 -1
- package/dist/llm/client-base.js +119 -13
- package/dist/llm/model-cache.js +4 -2
- package/dist/llm/model-pool.d.ts +14 -0
- package/dist/llm/model-pool.js +13 -0
- package/dist/llm/provider-auth.d.ts +41 -0
- package/dist/llm/provider-auth.js +76 -0
- package/dist/llm/provider-catalog.d.ts +4 -0
- package/dist/llm/providers/anthropic.js +64 -14
- package/dist/llm/providers/openai.d.ts +36 -0
- package/dist/llm/providers/openai.js +257 -51
- package/dist/llm/reasoning-setting.d.ts +3 -3
- package/dist/llm/reasoning-setting.js +9 -1
- package/dist/llm/stream-watchdog.js +5 -1
- package/dist/llm/token-counter.js +9 -2
- package/dist/llm/types.d.ts +4 -0
- package/dist/logging/sanitize-messages.js +22 -0
- package/dist/lsp/manager.d.ts +1 -1
- package/dist/lsp/manager.js +40 -10
- package/dist/model-catalog/builtin.d.ts +12 -0
- package/dist/model-catalog/builtin.js +407 -0
- package/dist/model-catalog/gen-connections.d.ts +20 -0
- package/dist/model-catalog/gen-connections.js +28 -0
- package/dist/model-catalog/index.d.ts +41 -0
- package/dist/model-catalog/index.js +90 -0
- package/dist/model-catalog/params.d.ts +20 -0
- package/dist/model-catalog/params.js +45 -0
- package/dist/model-catalog/resolve.d.ts +48 -0
- package/dist/model-catalog/resolve.js +33 -0
- package/dist/model-catalog/save-entry.d.ts +32 -0
- package/dist/model-catalog/save-entry.js +104 -0
- package/dist/model-catalog/types.d.ts +561 -0
- package/dist/model-catalog/types.js +93 -0
- package/dist/model-catalog/upsert.d.ts +9 -0
- package/dist/model-catalog/upsert.js +8 -0
- package/dist/onboarding.d.ts +12 -82
- package/dist/onboarding.js +61 -326
- package/dist/plugins/gitOps.d.ts +19 -0
- package/dist/plugins/gitOps.js +73 -4
- package/dist/plugins/installer/checkUpdate.d.ts +16 -0
- package/dist/plugins/installer/checkUpdate.js +32 -0
- package/dist/plugins/installer/codex/convertCommands.d.ts +19 -0
- package/dist/plugins/installer/codex/convertCommands.js +46 -0
- package/dist/plugins/installer/codex/convertMcp.d.ts +5 -2
- package/dist/plugins/installer/codex/convertMcp.js +45 -5
- package/dist/plugins/installer/install.js +25 -1
- package/dist/plugins/installer/installFromArchive.d.ts +43 -0
- package/dist/plugins/installer/installFromArchive.js +134 -0
- package/dist/plugins/installer/installFromSource.js +8 -2
- package/dist/plugins/installer/loadPluginAgents.js +6 -2
- package/dist/plugins/installer/loadPluginMcp.d.ts +9 -2
- package/dist/plugins/installer/loadPluginMcp.js +35 -2
- package/dist/plugins/installer/pruneDisabled.d.ts +24 -0
- package/dist/plugins/installer/pruneDisabled.js +73 -0
- package/dist/plugins/installer/types.d.ts +5 -2
- package/dist/plugins/installer/types.js +1 -0
- package/dist/plugins/installer/uninstall.js +4 -0
- package/dist/plugins/installer/unzip.d.ts +14 -0
- package/dist/plugins/installer/unzip.js +82 -0
- package/dist/plugins/installer/update.d.ts +14 -0
- package/dist/plugins/installer/update.js +53 -21
- package/dist/plugins/loadPluginHooks.d.ts +47 -1
- package/dist/plugins/loadPluginHooks.js +73 -1
- package/dist/plugins/marketplaceManager.d.ts +7 -0
- package/dist/plugins/marketplaceManager.js +20 -0
- package/dist/plugins/pluginCommandHook.js +4 -18
- package/dist/plugins/pluginContent.d.ts +30 -0
- package/dist/plugins/pluginContent.js +83 -0
- package/dist/plugins/pluginInstaller.d.ts +13 -0
- package/dist/plugins/pluginInstaller.js +42 -8
- package/dist/plugins/schemas.js +1 -0
- package/dist/plugins/types.d.ts +6 -0
- package/dist/preset/index.d.ts +7 -1
- package/dist/preset/index.js +96 -6
- package/dist/product/types.d.ts +1 -1
- package/dist/prompt/composer.d.ts +27 -0
- package/dist/prompt/composer.js +67 -21
- package/dist/prompt/instruction-scanner.js +5 -3
- package/dist/prompt/section-loader.js +1 -0
- package/dist/prompt/sections/base.md +1 -0
- package/dist/prompt/sections/browser.md +10 -0
- package/dist/prompt/sections/coding.md +4 -0
- package/dist/protocol/chat-session-manager.d.ts +8 -2
- package/dist/protocol/chat-session-manager.js +36 -0
- package/dist/protocol/chat-session.d.ts +65 -0
- package/dist/protocol/chat-session.js +94 -2
- package/dist/protocol/client.d.ts +27 -0
- package/dist/protocol/client.js +38 -0
- package/dist/protocol/server.d.ts +112 -0
- package/dist/protocol/server.js +586 -16
- package/dist/protocol/transport.js +3 -2
- package/dist/protocol/types.d.ts +46 -0
- package/dist/protocol/types.js +16 -0
- package/dist/quota/credentials.d.ts +3 -0
- package/dist/quota/credentials.js +80 -0
- package/dist/quota/index.d.ts +36 -0
- package/dist/quota/index.js +155 -0
- package/dist/quota/types.d.ts +48 -0
- package/dist/quota/types.js +13 -0
- package/dist/review/review-prompt.d.ts +28 -0
- package/dist/review/review-prompt.js +81 -0
- package/dist/run/FileRunStore.js +8 -3
- package/dist/run/RunApprovalBackend.js +25 -5
- package/dist/run/RunManager.d.ts +12 -0
- package/dist/run/RunManager.js +35 -0
- package/dist/run/factory.d.ts +1 -1
- package/dist/runtime/background-shell.d.ts +139 -0
- package/dist/runtime/background-shell.js +495 -0
- package/dist/runtime/output-clean.d.ts +24 -0
- package/dist/runtime/output-clean.js +41 -0
- package/dist/runtime/ring-file.d.ts +64 -0
- package/dist/runtime/ring-file.js +174 -0
- package/dist/runtime/safe-spawn.js +15 -34
- package/dist/runtime/spawn-common.d.ts +148 -0
- package/dist/runtime/spawn-common.js +303 -0
- package/dist/runtime/truncate-output.d.ts +22 -0
- package/dist/runtime/truncate-output.js +49 -0
- package/dist/runtime/utf8-cut.d.ts +11 -0
- package/dist/runtime/utf8-cut.js +23 -0
- package/dist/services/auto-dream.d.ts +4 -0
- package/dist/services/auto-dream.js +26 -26
- package/dist/services/diagnostics.d.ts +1 -2
- package/dist/services/diagnostics.js +12 -7
- package/dist/services/extract-memories.d.ts +14 -1
- package/dist/services/extract-memories.js +45 -6
- package/dist/services/memory-orchestrator.d.ts +21 -0
- package/dist/services/memory-orchestrator.js +125 -50
- package/dist/services/session-memory.js +24 -12
- package/dist/session/file-history.d.ts +124 -1
- package/dist/session/file-history.js +222 -6
- package/dist/session/memory.d.ts +116 -2
- package/dist/session/memory.js +250 -28
- package/dist/session/session-manager.d.ts +40 -0
- package/dist/session/session-manager.js +113 -3
- package/dist/session/simple-diff.d.ts +23 -0
- package/dist/session/simple-diff.js +84 -0
- package/dist/session/transcript.d.ts +25 -1
- package/dist/session/transcript.js +35 -2
- package/dist/session/undo-target.d.ts +67 -0
- package/dist/session/undo-target.js +144 -0
- package/dist/settings/disk-defaults.d.ts +9 -2
- package/dist/settings/disk-defaults.js +11 -2
- package/dist/settings/feature-flags.d.ts +64 -0
- package/dist/settings/feature-flags.js +61 -0
- package/dist/settings/manager.d.ts +68 -1
- package/dist/settings/manager.js +266 -29
- package/dist/settings/migrate-config.d.ts +45 -0
- package/dist/settings/migrate-config.js +125 -0
- package/dist/settings/schema-export.d.ts +25 -0
- package/dist/settings/schema-export.js +38 -0
- package/dist/settings/schema.d.ts +1186 -771
- package/dist/settings/schema.js +268 -97
- package/dist/skills/scanner.d.ts +9 -0
- package/dist/skills/scanner.js +30 -2
- package/dist/stt/resolve-transcribe.d.ts +31 -0
- package/dist/stt/resolve-transcribe.js +108 -0
- package/dist/stt/transcribe.d.ts +51 -0
- package/dist/stt/transcribe.js +65 -0
- package/dist/tool-system/browser-bridge.d.ts +226 -0
- package/dist/tool-system/browser-bridge.js +163 -0
- package/dist/tool-system/builtin/agent-heartbeat.d.ts +49 -0
- package/dist/tool-system/builtin/agent-heartbeat.js +89 -0
- package/dist/tool-system/builtin/agent-notifications.d.ts +12 -3
- package/dist/tool-system/builtin/agent-notifications.js +9 -3
- package/dist/tool-system/builtin/agent-output-file.d.ts +38 -0
- package/dist/tool-system/builtin/agent-output-file.js +72 -0
- package/dist/tool-system/builtin/agent-registry.d.ts +12 -0
- package/dist/tool-system/builtin/agent-registry.js +8 -0
- package/dist/tool-system/builtin/agent.d.ts +21 -1
- package/dist/tool-system/builtin/agent.js +489 -42
- package/dist/tool-system/builtin/apply-patch/applier.js +66 -8
- package/dist/tool-system/builtin/apply-patch/backup-targets.d.ts +10 -0
- package/dist/tool-system/builtin/apply-patch/backup-targets.js +30 -0
- package/dist/tool-system/builtin/apply-patch/index.js +0 -15
- package/dist/tool-system/builtin/background-jobs.d.ts +76 -0
- package/dist/tool-system/builtin/background-jobs.js +124 -0
- package/dist/tool-system/builtin/background-shell-tools.d.ts +20 -0
- package/dist/tool-system/builtin/background-shell-tools.js +108 -0
- package/dist/tool-system/builtin/background-work.d.ts +67 -0
- package/dist/tool-system/builtin/background-work.js +86 -0
- package/dist/tool-system/builtin/bash-output-style.d.ts +32 -0
- package/dist/tool-system/builtin/bash-output-style.js +40 -0
- package/dist/tool-system/builtin/bash.d.ts +5 -2
- package/dist/tool-system/builtin/bash.js +98 -62
- package/dist/tool-system/builtin/browser-tools.d.ts +33 -0
- package/dist/tool-system/builtin/browser-tools.js +312 -0
- package/dist/tool-system/builtin/cancel-goal.d.ts +31 -0
- package/dist/tool-system/builtin/cancel-goal.js +64 -0
- package/dist/tool-system/builtin/check-quota.d.ts +15 -0
- package/dist/tool-system/builtin/check-quota.js +34 -0
- package/dist/tool-system/builtin/config.js +7 -0
- package/dist/tool-system/builtin/cron.d.ts +7 -0
- package/dist/tool-system/builtin/cron.js +55 -3
- package/dist/tool-system/builtin/drive-claude-code.d.ts +30 -0
- package/dist/tool-system/builtin/drive-claude-code.js +157 -0
- package/dist/tool-system/builtin/edit-model-catalog.d.ts +3 -0
- package/dist/tool-system/builtin/edit-model-catalog.js +94 -0
- package/dist/tool-system/builtin/edit.js +20 -16
- package/dist/tool-system/builtin/eol.d.ts +29 -0
- package/dist/tool-system/builtin/eol.js +37 -0
- package/dist/tool-system/builtin/file-cache.d.ts +6 -0
- package/dist/tool-system/builtin/file-cache.js +8 -0
- package/dist/tool-system/builtin/generate-image.d.ts +35 -0
- package/dist/tool-system/builtin/generate-image.js +278 -50
- package/dist/tool-system/builtin/generate-video.d.ts +55 -0
- package/dist/tool-system/builtin/generate-video.js +361 -0
- package/dist/tool-system/builtin/glob.js +0 -7
- package/dist/tool-system/builtin/grep.js +6 -8
- package/dist/tool-system/builtin/image-providers.d.ts +86 -0
- package/dist/tool-system/builtin/image-providers.js +190 -0
- package/dist/tool-system/builtin/image-uploader.d.ts +33 -0
- package/dist/tool-system/builtin/image-uploader.js +74 -0
- package/dist/tool-system/builtin/index.d.ts +7 -1
- package/dist/tool-system/builtin/index.js +249 -25
- package/dist/tool-system/builtin/mcp-tools.js +23 -3
- package/dist/tool-system/builtin/memory.js +45 -7
- package/dist/tool-system/builtin/notebook-edit.js +0 -7
- package/dist/tool-system/builtin/powershell.js +4 -1
- package/dist/tool-system/builtin/read.js +10 -10
- package/dist/tool-system/builtin/repl.js +4 -1
- package/dist/tool-system/builtin/skill.js +9 -0
- package/dist/tool-system/builtin/sleep.js +3 -2
- package/dist/tool-system/builtin/tool-search.js +25 -7
- package/dist/tool-system/builtin/video-providers.d.ts +154 -0
- package/dist/tool-system/builtin/video-providers.js +235 -0
- package/dist/tool-system/builtin/web-fetch.js +12 -2
- package/dist/tool-system/builtin/web-search.js +21 -7
- package/dist/tool-system/builtin/worktree.d.ts +2 -1
- package/dist/tool-system/builtin/worktree.js +31 -4
- package/dist/tool-system/builtin/write.js +0 -6
- package/dist/tool-system/context.d.ts +154 -6
- package/dist/tool-system/executor.d.ts +3 -1
- package/dist/tool-system/executor.js +172 -88
- package/dist/tool-system/investigation-guard.js +1 -1
- package/dist/tool-system/mcp-manager.d.ts +42 -4
- package/dist/tool-system/mcp-manager.js +186 -20
- package/dist/tool-system/path-policy.d.ts +5 -0
- package/dist/tool-system/path-policy.js +307 -8
- package/dist/tool-system/permission.d.ts +36 -1
- package/dist/tool-system/permission.js +281 -69
- package/dist/tool-system/plan-mode-allowlist.d.ts +13 -2
- package/dist/tool-system/plan-mode-allowlist.js +24 -2
- package/dist/tool-system/registry.d.ts +1 -0
- package/dist/tool-system/registry.js +16 -2
- package/dist/tool-system/sandbox/index.d.ts +8 -0
- package/dist/tool-system/sandbox/index.js +7 -2
- package/dist/tool-system/validate-tool-metadata.d.ts +36 -0
- package/dist/tool-system/validate-tool-metadata.js +63 -0
- package/dist/types.d.ts +217 -6
- package/dist/updater.js +20 -9
- package/dist/utils/envUtils.d.ts +0 -9
- package/dist/utils/envUtils.js +3 -28
- package/dist/utils/exec.d.ts +40 -0
- package/dist/utils/exec.js +144 -0
- package/dist/utils/json.d.ts +12 -0
- package/dist/utils/json.js +92 -0
- package/dist/utils/theme.d.ts +1 -1
- package/dist/utils/theme.js +1 -1
- package/dist/utils/toolDisplay.js +0 -1
- package/package.json +13 -7
- package/dist/agent/coordinator.d.ts +0 -49
- package/dist/agent/coordinator.js +0 -77
- package/dist/settings/manager.test.js +0 -73
- package/dist/tool-system/builtin/remote-trigger.d.ts +0 -6
- package/dist/tool-system/builtin/remote-trigger.js +0 -54
- package/dist/tool-system/builtin/send-message.d.ts +0 -6
- package/dist/tool-system/builtin/send-message.js +0 -47
- /package/dist/{settings/manager.test.d.ts → credentials/types.js} +0 -0
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in GenerateVideo tool (TODO 7.1 块3) — text-to-video via a
|
|
3
|
+
* {@link VideoProvider} adapter (submit / poll / download).
|
|
4
|
+
*
|
|
5
|
+
* Video generation is always slow (tens of seconds to minutes), so this tool
|
|
6
|
+
* is fire-and-forget by design: it submits the job, returns a handle
|
|
7
|
+
* immediately, and polls in the BACKGROUND. When the job finishes it writes
|
|
8
|
+
* the file to `<cwd>/.code-shell/generated_videos/` and enqueues a completion
|
|
9
|
+
* notification (same notificationQueue path as background agents / shells), so
|
|
10
|
+
* the main turn is never blocked (consistent with TODO 3.2 / 4.1).
|
|
11
|
+
*
|
|
12
|
+
* Concrete provider adapters (Seedance / Kling) are not wired yet — their
|
|
13
|
+
* private APIs need confirmed docs. Until then the only resolvable provider is
|
|
14
|
+
* the test-injected fake, so in production this tool is dormant (returns a
|
|
15
|
+
* "no video provider configured" message) rather than half-working.
|
|
16
|
+
*/
|
|
17
|
+
import { writeFile, mkdir } from "node:fs/promises";
|
|
18
|
+
import { join } from "node:path";
|
|
19
|
+
import { SettingsManager } from "../../settings/manager.js";
|
|
20
|
+
import { notificationQueue } from "./agent-notifications.js";
|
|
21
|
+
import { backgroundJobRegistry } from "./background-jobs.js";
|
|
22
|
+
import { logger } from "../../logging/logger.js";
|
|
23
|
+
import { getVideoProvider, DEFAULT_VIDEO_MODEL, } from "./video-providers.js";
|
|
24
|
+
import { getImageUploader } from "./image-uploader.js";
|
|
25
|
+
import { effectiveApiKey } from "./generate-image.js";
|
|
26
|
+
import { getMergedCatalog, findCatalogEntry } from "../../model-catalog/index.js";
|
|
27
|
+
import { genInstancesFromConnections } from "../../model-catalog/gen-connections.js";
|
|
28
|
+
const MAX_IMAGES = 9;
|
|
29
|
+
/**
|
|
30
|
+
* Normalize image inputs (URLs or local paths) into public URLs the provider
|
|
31
|
+
* can consume. `images[]` wins over the single `image`. Local paths are
|
|
32
|
+
* uploaded via the injected {@link ImageUploader}; URLs pass through. Caps at
|
|
33
|
+
* {@link MAX_IMAGES} (fal reference-to-video allows up to 9).
|
|
34
|
+
*/
|
|
35
|
+
export async function __normalizeImagesForTests(images, image, uploader, creds, signal) {
|
|
36
|
+
const raw = images && images.length ? images : image ? [image] : [];
|
|
37
|
+
if (raw.length > MAX_IMAGES) {
|
|
38
|
+
return { ok: false, error: `too many images: ${raw.length} (max ${MAX_IMAGES})` };
|
|
39
|
+
}
|
|
40
|
+
const urls = [];
|
|
41
|
+
for (const item of raw) {
|
|
42
|
+
const r = await uploader.toUrl(item, creds, signal);
|
|
43
|
+
if (!r.ok)
|
|
44
|
+
return { ok: false, error: r.error };
|
|
45
|
+
urls.push(r.url);
|
|
46
|
+
}
|
|
47
|
+
return { ok: true, urls };
|
|
48
|
+
}
|
|
49
|
+
/** Video provider `kind`s that have an adapter, in resolution preference. */
|
|
50
|
+
const VIDEO_PROVIDER_KINDS = ["fal"];
|
|
51
|
+
const DEFAULT_POLL_INTERVAL_MS = 5_000;
|
|
52
|
+
/** Safety cap so a stuck job's background loop can't poll forever. */
|
|
53
|
+
const MAX_POLL_MS = 15 * 60 * 1000;
|
|
54
|
+
export const generateVideoToolDef = {
|
|
55
|
+
name: "GenerateVideo",
|
|
56
|
+
description: "Generate a video from a text prompt. The job runs in the background (video generation is " +
|
|
57
|
+
"slow); you are notified automatically when it finishes, and the .mp4 is saved into the " +
|
|
58
|
+
"workspace. Do NOT sleep or poll — continue with other work. Requires a configured video " +
|
|
59
|
+
"provider.",
|
|
60
|
+
inputSchema: {
|
|
61
|
+
type: "object",
|
|
62
|
+
properties: {
|
|
63
|
+
prompt: { type: "string", description: "Description of the video to generate" },
|
|
64
|
+
provider: {
|
|
65
|
+
type: "string",
|
|
66
|
+
description: "Video provider kind to use. Defaults to the first configured video provider.",
|
|
67
|
+
},
|
|
68
|
+
model: { type: "string", description: "Video model id. Defaults to the provider's default." },
|
|
69
|
+
image: { type: "string", description: "Image URL (http/https) for image-to-video. When set, an image-to-video model is used." },
|
|
70
|
+
images: {
|
|
71
|
+
type: "array",
|
|
72
|
+
items: { type: "string" },
|
|
73
|
+
description: "Image URLs or local file paths for image/reference-to-video. 1 image → image-to-video; 2+ → reference-to-video (max 9). Local paths are auto-uploaded. Refer to them in prompt as @Image1, @Image2.",
|
|
74
|
+
},
|
|
75
|
+
videos: {
|
|
76
|
+
type: "array",
|
|
77
|
+
items: { type: "string" },
|
|
78
|
+
description: "Reference/continuation video URLs (http/https only — NOT local paths) for video extension. Forces reference-to-video (Seedance model required). Up to 3. Refer to them in prompt as @Video1, @Video2 (e.g. \"continue from @Video1\").",
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
required: ["prompt"],
|
|
82
|
+
},
|
|
83
|
+
};
|
|
84
|
+
// Test seam: inject a VideoProvider so the background poll loop can be tested
|
|
85
|
+
// end-to-end without a real adapter or network. Null → normal resolution.
|
|
86
|
+
let injectedProvider = null;
|
|
87
|
+
export function __setVideoProviderForTests(p) {
|
|
88
|
+
injectedProvider = p;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Tool-visibility guard: GenerateVideo is hidden until a video provider is
|
|
92
|
+
* actually configured. With no real adapters wired yet (VIDEO_PROVIDER_KINDS
|
|
93
|
+
* is empty), this returns false in production so the model never sees a tool
|
|
94
|
+
* it can't use — the tool becomes visible automatically once an adapter +
|
|
95
|
+
* matching settings provider exist. Short TTL cache like GenerateImage.
|
|
96
|
+
*/
|
|
97
|
+
const availCache = new Map();
|
|
98
|
+
const AVAIL_TTL_MS = 1000;
|
|
99
|
+
export function isGenerateVideoAvailable(cwd = process.cwd(), nowMs = Date.now()) {
|
|
100
|
+
const hit = availCache.get(cwd);
|
|
101
|
+
if (hit && nowMs - hit.at < AVAIL_TTL_MS)
|
|
102
|
+
return hit.value;
|
|
103
|
+
let value = false;
|
|
104
|
+
try {
|
|
105
|
+
value = resolveVideoProvider(cwd) !== null;
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
value = false;
|
|
109
|
+
}
|
|
110
|
+
availCache.set(cwd, { at: nowMs, value });
|
|
111
|
+
return value;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* List configured, usable video providers (TODO 7.1). Returns [] when no
|
|
115
|
+
* adapters are wired (VIDEO_PROVIDER_KINDS empty) or none configured.
|
|
116
|
+
*/
|
|
117
|
+
export function listConfiguredVideoProviders(cwd = process.cwd()) {
|
|
118
|
+
try {
|
|
119
|
+
const settings = new SettingsManager(cwd, "full").get();
|
|
120
|
+
// Canonical videoGen.providers[] first (TODO 7.1) — but only kinds that
|
|
121
|
+
// have a wired adapter (VIDEO_PROVIDER_KINDS); a configured-but-unadapted
|
|
122
|
+
// entry isn't usable yet.
|
|
123
|
+
const videoGen = settings.videoGen;
|
|
124
|
+
if (videoGen?.providers?.length) {
|
|
125
|
+
const list = videoGen.providers;
|
|
126
|
+
return list
|
|
127
|
+
.filter((p) => !!effectiveApiKey(p, list) && getVideoProvider(p.kind) !== null)
|
|
128
|
+
.map((p) => ({ id: p.id, kind: p.kind, catalogId: p.catalogId }));
|
|
129
|
+
}
|
|
130
|
+
// Legacy LLM providers[] back-compat (field dropped from schema; read via
|
|
131
|
+
// .passthrough() with an inline cast).
|
|
132
|
+
const legacyProviders = settings.providers ?? [];
|
|
133
|
+
return legacyProviders
|
|
134
|
+
.filter((p) => p.apiKey && VIDEO_PROVIDER_KINDS.includes(p.kind))
|
|
135
|
+
.map((p) => ({ kind: p.kind }));
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
return [];
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
/** Dynamic GenerateVideo description naming configured providers (TODO 7.1). */
|
|
142
|
+
export function generateVideoToolDefFor(cwd) {
|
|
143
|
+
const providers = listConfiguredVideoProviders(cwd);
|
|
144
|
+
if (providers.length === 0)
|
|
145
|
+
return generateVideoToolDef;
|
|
146
|
+
const names = providers.map((p) => p.id ?? p.kind).join(", ");
|
|
147
|
+
const catalog = getMergedCatalog();
|
|
148
|
+
const paramLines = providers
|
|
149
|
+
.map((p) => {
|
|
150
|
+
const entry = findCatalogEntry(catalog, p.catalogId, p.kind);
|
|
151
|
+
return entry?.paramsDoc ? ` - ${p.id ?? p.kind}: ${entry.paramsDoc}` : null;
|
|
152
|
+
})
|
|
153
|
+
.filter((x) => x !== null);
|
|
154
|
+
const paramsBlock = paramLines.length ? `\nParams per provider:\n${paramLines.join("\n")}` : "";
|
|
155
|
+
return {
|
|
156
|
+
...generateVideoToolDef,
|
|
157
|
+
description: generateVideoToolDef.description +
|
|
158
|
+
` Configured provider(s): ${names}. Pass \`provider\` to pick one.` +
|
|
159
|
+
paramsBlock,
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
function resolveVideoProvider(cwd, preferKind) {
|
|
163
|
+
const settings = new SettingsManager(cwd, "full").get();
|
|
164
|
+
// 0. Unified store (统一模型接入方案): modelConnections (tag=video) +
|
|
165
|
+
// credentials, taking precedence over legacy videoGen.providers[].
|
|
166
|
+
const conns = settings.modelConnections;
|
|
167
|
+
const creds = settings.credentials;
|
|
168
|
+
if (Array.isArray(conns) && conns.some((c) => c.tag === "video")) {
|
|
169
|
+
const list = genInstancesFromConnections(conns, (Array.isArray(creds) ? creds : []), getMergedCatalog(), "video");
|
|
170
|
+
const def = settings.defaults?.video;
|
|
171
|
+
const usable = (p) => !!p.apiKey && getVideoProvider(p.kind) !== null;
|
|
172
|
+
const credsOf = (p) => ({ baseUrl: p.baseUrl, apiKey: p.apiKey });
|
|
173
|
+
if (preferKind) {
|
|
174
|
+
const chosen = list.find((p) => (p.id === preferKind || p.kind === preferKind) && usable(p));
|
|
175
|
+
if (chosen)
|
|
176
|
+
return { kind: chosen.kind, creds: credsOf(chosen), defaultModel: chosen.defaultModel };
|
|
177
|
+
return null;
|
|
178
|
+
}
|
|
179
|
+
const preferred = def ? list.find((p) => p.id === def) : undefined;
|
|
180
|
+
const chosen = (preferred && usable(preferred) ? preferred : undefined) ?? list.find(usable);
|
|
181
|
+
if (chosen)
|
|
182
|
+
return { kind: chosen.kind, creds: credsOf(chosen), defaultModel: chosen.defaultModel };
|
|
183
|
+
if (def || preferKind)
|
|
184
|
+
return null;
|
|
185
|
+
}
|
|
186
|
+
const videoGen = settings.videoGen;
|
|
187
|
+
if (videoGen?.providers?.length) {
|
|
188
|
+
const list = videoGen.providers;
|
|
189
|
+
const usable = (p) => !!effectiveApiKey(p, list) && getVideoProvider(p.kind) !== null;
|
|
190
|
+
const credsOf = (p) => ({ baseUrl: p.baseUrl, apiKey: effectiveApiKey(p, list) });
|
|
191
|
+
if (preferKind) {
|
|
192
|
+
const chosen = list.find((p) => (p.id === preferKind || p.kind === preferKind) && usable(p));
|
|
193
|
+
if (chosen)
|
|
194
|
+
return { kind: chosen.kind, creds: credsOf(chosen), defaultModel: chosen.defaultModel };
|
|
195
|
+
return null;
|
|
196
|
+
}
|
|
197
|
+
const preferred = videoGen.defaultProvider
|
|
198
|
+
? list.find((p) => p.id === videoGen.defaultProvider)
|
|
199
|
+
: undefined;
|
|
200
|
+
const chosen = (preferred && usable(preferred) ? preferred : undefined) ?? list.find(usable);
|
|
201
|
+
if (chosen)
|
|
202
|
+
return { kind: chosen.kind, creds: credsOf(chosen), defaultModel: chosen.defaultModel };
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
// Back-compat: scan legacy LLM providers[] for a video-capable kind. The
|
|
206
|
+
// field was dropped from the schema; un-migrated settings.json still carry it
|
|
207
|
+
// via .passthrough(), so read it through an inline cast.
|
|
208
|
+
const legacyProviders = settings.providers ?? [];
|
|
209
|
+
const kinds = preferKind ? [preferKind] : VIDEO_PROVIDER_KINDS;
|
|
210
|
+
for (const kind of kinds) {
|
|
211
|
+
const provider = legacyProviders.find((p) => p.kind === kind);
|
|
212
|
+
if (provider && provider.apiKey) {
|
|
213
|
+
return { kind, creds: { baseUrl: provider.baseUrl, apiKey: provider.apiKey } };
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
return null;
|
|
217
|
+
}
|
|
218
|
+
export function __resolveVideoProviderForTests(cwd, preferKind) {
|
|
219
|
+
return resolveVideoProvider(cwd, preferKind);
|
|
220
|
+
}
|
|
221
|
+
export async function generateVideoTool(args, ctx) {
|
|
222
|
+
const prompt = args.prompt;
|
|
223
|
+
if (typeof prompt !== "string" || !prompt.trim()) {
|
|
224
|
+
return "Error: prompt is required";
|
|
225
|
+
}
|
|
226
|
+
const cwd = ctx?.cwd ?? process.cwd();
|
|
227
|
+
const sessionId = ctx?.sessionId;
|
|
228
|
+
const preferKind = typeof args.provider === "string" && args.provider ? args.provider : undefined;
|
|
229
|
+
const overrideModel = typeof args.model === "string" && args.model ? args.model : undefined;
|
|
230
|
+
const image = typeof args.image === "string" && args.image ? args.image : undefined;
|
|
231
|
+
const imagesArg = Array.isArray(args.images)
|
|
232
|
+
? args.images.filter((x) => typeof x === "string")
|
|
233
|
+
: undefined;
|
|
234
|
+
// videos pass through verbatim to fal's video_urls (no upload) — http(s) only.
|
|
235
|
+
const videosArg = Array.isArray(args.videos)
|
|
236
|
+
? args.videos.filter((x) => typeof x === "string")
|
|
237
|
+
: undefined;
|
|
238
|
+
const pollIntervalMs = typeof args.pollIntervalMs === "number" && args.pollIntervalMs > 0
|
|
239
|
+
? args.pollIntervalMs
|
|
240
|
+
: DEFAULT_POLL_INTERVAL_MS;
|
|
241
|
+
// Resolve the provider + adapter. The test seam wins so the background loop
|
|
242
|
+
// is exercised without a real adapter.
|
|
243
|
+
let kind;
|
|
244
|
+
let creds;
|
|
245
|
+
let adapter;
|
|
246
|
+
let defaultModel;
|
|
247
|
+
if (injectedProvider) {
|
|
248
|
+
adapter = injectedProvider;
|
|
249
|
+
kind = injectedProvider.kind;
|
|
250
|
+
creds = { baseUrl: "test", apiKey: "test" };
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
const resolved = resolveVideoProvider(cwd, preferKind);
|
|
254
|
+
if (!resolved) {
|
|
255
|
+
return preferKind
|
|
256
|
+
? `Error: no video provider of kind "${preferKind}" available. Configure it (with an apiKey) in settings.`
|
|
257
|
+
: "Error: no video provider available. Video generation requires a configured video provider (none are wired yet).";
|
|
258
|
+
}
|
|
259
|
+
const a = getVideoProvider(resolved.kind);
|
|
260
|
+
if (!a)
|
|
261
|
+
return `Error: video generation is not supported for provider kind "${resolved.kind}".`;
|
|
262
|
+
adapter = a;
|
|
263
|
+
kind = resolved.kind;
|
|
264
|
+
creds = resolved.creds;
|
|
265
|
+
defaultModel = resolved.defaultModel;
|
|
266
|
+
}
|
|
267
|
+
const model = overrideModel ?? defaultModel ?? DEFAULT_VIDEO_MODEL[kind] ?? kind;
|
|
268
|
+
// Normalize image inputs (local paths → uploaded URLs) before submit. The
|
|
269
|
+
// provider only ever receives URLs and routes t2v/i2v/ref2v by count.
|
|
270
|
+
const uploader = getImageUploader(kind) ?? getImageUploader("fal");
|
|
271
|
+
const norm = await __normalizeImagesForTests(imagesArg, image, uploader, { baseUrl: creds.baseUrl, apiKey: creds.apiKey }, ctx?.signal);
|
|
272
|
+
if (!norm.ok)
|
|
273
|
+
return `Error: ${norm.error}`;
|
|
274
|
+
const submit = await adapter.submit({ prompt, model, image: undefined, images: norm.urls, videos: videosArg, creds, signal: ctx?.signal });
|
|
275
|
+
if (!submit.ok) {
|
|
276
|
+
return `Error submitting video job: ${submit.error}`;
|
|
277
|
+
}
|
|
278
|
+
const jobId = submit.jobId;
|
|
279
|
+
// Background poll → download → write → notify. Fire-and-forget: never await.
|
|
280
|
+
// Register the job so it shows up in the goal judge's background-task list
|
|
281
|
+
// (so the judge can tell "waiting on a finite render" from "nothing left to
|
|
282
|
+
// do" — the s-mqe0ox7n-a8d11c26 busy-loop bug). The video does NOT park the
|
|
283
|
+
// engine anymore; its completion notification wakes the idle session (server
|
|
284
|
+
// maybeWakeIdleSession). The registry is keyed by the fal jobId namespaced so
|
|
285
|
+
// two providers can't collide.
|
|
286
|
+
const jobKey = `video-${jobId}`;
|
|
287
|
+
const promptPreview = prompt.length > 80 ? `${prompt.slice(0, 80)}…` : prompt;
|
|
288
|
+
backgroundJobRegistry.start(jobKey, sessionId ?? "", `生成视频中:${promptPreview}`);
|
|
289
|
+
void pollToCompletion(adapter, jobId, creds, cwd, sessionId, prompt, pollIntervalMs)
|
|
290
|
+
.then((outcome) => backgroundJobRegistry.finish(jobKey, outcome))
|
|
291
|
+
.catch((err) => backgroundJobRegistry.finish(jobKey, { status: "failed", finalText: err.message }));
|
|
292
|
+
return [
|
|
293
|
+
`Video generation started in the background.`,
|
|
294
|
+
`job_id: ${jobId} (internal — do not show to user)`,
|
|
295
|
+
`prompt: ${prompt}`,
|
|
296
|
+
``,
|
|
297
|
+
`It will be saved into .code-shell/generated_videos/ and you'll be notified automatically when it finishes.`,
|
|
298
|
+
`If you have no other work right now, END YOUR TURN — the system wakes you when the video is ready. NEVER run \`sleep\` or poll the provider yourself.`,
|
|
299
|
+
].join("\n");
|
|
300
|
+
}
|
|
301
|
+
async function pollToCompletion(adapter, jobId, creds, cwd, sessionId, prompt, pollIntervalMs) {
|
|
302
|
+
const started = Date.now();
|
|
303
|
+
try {
|
|
304
|
+
for (;;) {
|
|
305
|
+
if (Date.now() - started > MAX_POLL_MS) {
|
|
306
|
+
const msg = `video job ${jobId} timed out after ${Math.round(MAX_POLL_MS / 1000)}s`;
|
|
307
|
+
notifyVideo(sessionId, "failed", prompt, undefined, msg);
|
|
308
|
+
return { status: "failed", finalText: msg };
|
|
309
|
+
}
|
|
310
|
+
const res = await adapter.poll({ jobId, creds });
|
|
311
|
+
if (!res.ok) {
|
|
312
|
+
notifyVideo(sessionId, "failed", prompt, undefined, res.error);
|
|
313
|
+
return { status: "failed", finalText: res.error };
|
|
314
|
+
}
|
|
315
|
+
if (res.status === "failed") {
|
|
316
|
+
notifyVideo(sessionId, "failed", prompt, undefined, res.error);
|
|
317
|
+
return { status: "failed", finalText: res.error };
|
|
318
|
+
}
|
|
319
|
+
if (res.status === "succeeded")
|
|
320
|
+
break;
|
|
321
|
+
await new Promise((r) => setTimeout(r, pollIntervalMs));
|
|
322
|
+
}
|
|
323
|
+
const dl = await adapter.download({ jobId, creds });
|
|
324
|
+
if (!dl.ok) {
|
|
325
|
+
notifyVideo(sessionId, "failed", prompt, undefined, dl.error);
|
|
326
|
+
return { status: "failed", finalText: dl.error };
|
|
327
|
+
}
|
|
328
|
+
const dir = join(cwd, ".code-shell", "generated_videos");
|
|
329
|
+
await mkdir(dir, { recursive: true });
|
|
330
|
+
const path = join(dir, `${Date.now()}.${dl.ext || "mp4"}`);
|
|
331
|
+
await writeFile(path, dl.bytes);
|
|
332
|
+
notifyVideo(sessionId, "completed", prompt, path, undefined, dl.url);
|
|
333
|
+
return { status: "completed", finalText: path };
|
|
334
|
+
}
|
|
335
|
+
catch (err) {
|
|
336
|
+
notifyVideo(sessionId, "failed", prompt, undefined, err.message);
|
|
337
|
+
return { status: "failed", finalText: err.message };
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
function notifyVideo(sessionId, status, prompt, path, error, url) {
|
|
341
|
+
if (!sessionId) {
|
|
342
|
+
logger.warn("video_completion_without_session", { status });
|
|
343
|
+
return;
|
|
344
|
+
}
|
|
345
|
+
// Include the fal-hosted URL on success so the model can pass it to a follow-up
|
|
346
|
+
// GenerateVideo `videos:[url]` to extend this clip (no re-upload). Expiring URL.
|
|
347
|
+
const extendHint = url
|
|
348
|
+
? ` To extend this video, call GenerateVideo again with videos:["${url}"] (Seedance model). URL may expire.`
|
|
349
|
+
: "";
|
|
350
|
+
notificationQueue.enqueue({
|
|
351
|
+
agentId: `video-${Date.now()}`,
|
|
352
|
+
name: "video generation",
|
|
353
|
+
description: status === "completed"
|
|
354
|
+
? `Video generated: ${path} (prompt: ${prompt})`
|
|
355
|
+
: `Video generation failed (prompt: ${prompt})`,
|
|
356
|
+
status,
|
|
357
|
+
finalText: status === "completed" ? `Video saved to ${path}.${extendHint}` : undefined,
|
|
358
|
+
error: status === "failed" ? error : undefined,
|
|
359
|
+
enqueuedAt: Date.now(),
|
|
360
|
+
}, sessionId);
|
|
361
|
+
}
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
import { glob } from "glob";
|
|
5
5
|
import { stat } from "node:fs/promises";
|
|
6
6
|
import * as path from "node:path";
|
|
7
|
-
import { enforcePathPolicy } from "../path-policy.js";
|
|
8
7
|
export const globToolDef = {
|
|
9
8
|
name: "Glob",
|
|
10
9
|
description: "Fast file pattern matching. Returns matching file paths sorted by modification time. " +
|
|
@@ -32,12 +31,6 @@ export async function globTool(args, ctx) {
|
|
|
32
31
|
? argPath
|
|
33
32
|
: path.resolve(baseDir, argPath)
|
|
34
33
|
: baseDir;
|
|
35
|
-
// Path policy: refuse to glob a search root the policy classifies as
|
|
36
|
-
// ask/deny for read. Stops a Glob("**/*", "/home/user/.ssh") from
|
|
37
|
-
// enumerating the keys directory under the existence-check radar.
|
|
38
|
-
const blocked = enforcePathPolicy(cwd, "read", ctx?.cwd);
|
|
39
|
-
if (blocked)
|
|
40
|
-
return blocked;
|
|
41
34
|
try {
|
|
42
35
|
const matches = await glob(pattern, {
|
|
43
36
|
cwd,
|
|
@@ -4,7 +4,6 @@
|
|
|
4
4
|
import { execFile } from "node:child_process";
|
|
5
5
|
import { promisify } from "node:util";
|
|
6
6
|
import { resolve, sep, isAbsolute } from "node:path";
|
|
7
|
-
import { enforcePathPolicy } from "../path-policy.js";
|
|
8
7
|
const execFileAsync = promisify(execFile);
|
|
9
8
|
/**
|
|
10
9
|
* Strip the cwd prefix from each line so results display as relative
|
|
@@ -59,11 +58,6 @@ export async function grepTool(args, ctx) {
|
|
|
59
58
|
? argPath
|
|
60
59
|
: resolve(baseDir, argPath)
|
|
61
60
|
: baseDir;
|
|
62
|
-
// Path policy: reading file contents under ~/.ssh, ~/.aws etc. by way
|
|
63
|
-
// of grep is the same exfiltration risk as Read. Gate the search root.
|
|
64
|
-
const blocked = enforcePathPolicy(searchPath, "read", ctx?.cwd);
|
|
65
|
-
if (blocked)
|
|
66
|
-
return blocked;
|
|
67
61
|
const fileGlob = args.glob;
|
|
68
62
|
const context = args.context || 0;
|
|
69
63
|
const maxResults = args.max_results || 50;
|
|
@@ -77,7 +71,7 @@ export async function grepTool(args, ctx) {
|
|
|
77
71
|
if (isNoMatchExit(rgErr))
|
|
78
72
|
return "No matches found.";
|
|
79
73
|
try {
|
|
80
|
-
return await runGrep(pattern, searchPath, context, maxResults, outputMode, caseInsensitive);
|
|
74
|
+
return await runGrep(pattern, searchPath, fileGlob, context, maxResults, outputMode, caseInsensitive);
|
|
81
75
|
}
|
|
82
76
|
catch (grepErr) {
|
|
83
77
|
if (isNoMatchExit(grepErr))
|
|
@@ -122,7 +116,7 @@ async function runRipgrep(pattern, path, fileGlob, context, maxResults, outputMo
|
|
|
122
116
|
}
|
|
123
117
|
return result;
|
|
124
118
|
}
|
|
125
|
-
async function runGrep(pattern, path, context, maxResults, outputMode, caseInsensitive) {
|
|
119
|
+
async function runGrep(pattern, path, fileGlob, context, maxResults, outputMode, caseInsensitive) {
|
|
126
120
|
const args = ["-r", "--color=never"];
|
|
127
121
|
if (caseInsensitive)
|
|
128
122
|
args.push("-i");
|
|
@@ -138,6 +132,10 @@ async function runGrep(pattern, path, context, maxResults, outputMode, caseInsen
|
|
|
138
132
|
args.push("-C", String(context));
|
|
139
133
|
}
|
|
140
134
|
args.push("-m", String(maxResults));
|
|
135
|
+
// Honor the file glob so the grep fallback matches ripgrep's --glob behavior
|
|
136
|
+
// (previously the glob was silently dropped on the fallback path).
|
|
137
|
+
if (fileGlob)
|
|
138
|
+
args.push(`--include=${fileGlob}`);
|
|
141
139
|
args.push("-E", pattern);
|
|
142
140
|
args.push("--exclude-dir=node_modules", "--exclude-dir=.git", "--exclude-dir=dist");
|
|
143
141
|
args.push(path);
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ImageProvider — adapter interface for text-to-image generation (TODO 7.1).
|
|
3
|
+
*
|
|
4
|
+
* Lifts the hardcoded OpenAI `gpt-image-2` call out of generate-image.ts so
|
|
5
|
+
* GenerateImage can target multiple providers (OpenAI now; Gemini next) and
|
|
6
|
+
* take an optional provider/model. Each adapter takes resolved credentials +
|
|
7
|
+
* the request and returns a base64 PNG (or an error string). The tool layer
|
|
8
|
+
* owns credential resolution from settings, file writing, and user-facing
|
|
9
|
+
* formatting — adapters are pure "creds + prompt → bytes".
|
|
10
|
+
*
|
|
11
|
+
* `fetch` is injected so adapters are unit-testable without network. Production
|
|
12
|
+
* call sites pass the global `fetch`.
|
|
13
|
+
*/
|
|
14
|
+
export interface ImageProviderCreds {
|
|
15
|
+
baseUrl: string;
|
|
16
|
+
apiKey: string;
|
|
17
|
+
}
|
|
18
|
+
/** A decoded reference/input image for image-to-image (edit) requests. */
|
|
19
|
+
export interface InputImage {
|
|
20
|
+
/** File name hint (used as the multipart part filename). */
|
|
21
|
+
filename: string;
|
|
22
|
+
/** MIME type, e.g. "image/png" | "image/jpeg" | "image/webp". */
|
|
23
|
+
mimeType: string;
|
|
24
|
+
/** Raw bytes (NOT base64) — the tool layer decodes the workspace file. */
|
|
25
|
+
bytes: Uint8Array;
|
|
26
|
+
}
|
|
27
|
+
export interface ImageGenerateRequest {
|
|
28
|
+
prompt: string;
|
|
29
|
+
size: string;
|
|
30
|
+
quality: string;
|
|
31
|
+
model: string;
|
|
32
|
+
creds: ImageProviderCreds;
|
|
33
|
+
/**
|
|
34
|
+
* Optional reference images. When present, this becomes an image-TO-image
|
|
35
|
+
* (edit) request rather than text-to-image: the provider conditions the
|
|
36
|
+
* output on these inputs (OpenAI `/images/edits`, Gemini inline_data parts).
|
|
37
|
+
* Empty/undefined = plain text-to-image.
|
|
38
|
+
*/
|
|
39
|
+
inputImages?: InputImage[];
|
|
40
|
+
/** Optional cancellation signal forwarded to fetch. */
|
|
41
|
+
signal?: AbortSignal;
|
|
42
|
+
}
|
|
43
|
+
export type ImageGenerateResult = {
|
|
44
|
+
ok: true;
|
|
45
|
+
b64: string;
|
|
46
|
+
} | {
|
|
47
|
+
ok: false;
|
|
48
|
+
error: string;
|
|
49
|
+
};
|
|
50
|
+
export interface ImageProvider {
|
|
51
|
+
/** Adapter id — matches the settings provider `kind` it consumes. */
|
|
52
|
+
readonly kind: string;
|
|
53
|
+
generate(req: ImageGenerateRequest): Promise<ImageGenerateResult>;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* OpenAI Images API adapter (`/images/generations`, b64_json). Identical wire
|
|
57
|
+
* behavior to the pre-refactor generate-image.ts: POST model/prompt/size/
|
|
58
|
+
* quality/n, read data[0].b64_json.
|
|
59
|
+
*/
|
|
60
|
+
export declare class OpenAIImageProvider implements ImageProvider {
|
|
61
|
+
private readonly fetchImpl;
|
|
62
|
+
readonly kind = "openai";
|
|
63
|
+
constructor(fetchImpl?: typeof fetch);
|
|
64
|
+
generate(req: ImageGenerateRequest): Promise<ImageGenerateResult>;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Gemini Images adapter — the `generateContent` endpoint
|
|
68
|
+
* (`/models/{model}:generateContent`), API key in the `x-goog-api-key`
|
|
69
|
+
* header, prompt as a text content-part, PNG returned base64 in
|
|
70
|
+
* `candidates[].content.parts[].inline_data.data` (REST may camelCase it to
|
|
71
|
+
* `inlineData`; we read both). Wire shape per ai.google.dev image-generation
|
|
72
|
+
* docs. The OpenAI-style `size`/`quality` args don't map 1:1 to Gemini's
|
|
73
|
+
* aspectRatio/imageSize, so we only forward the prompt + IMAGE modality and
|
|
74
|
+
* leave Gemini's own defaults for dimensions (a later pass can map size →
|
|
75
|
+
* aspectRatio if needed).
|
|
76
|
+
*/
|
|
77
|
+
export declare class GeminiImageProvider implements ImageProvider {
|
|
78
|
+
private readonly fetchImpl;
|
|
79
|
+
readonly kind = "google";
|
|
80
|
+
constructor(fetchImpl?: typeof fetch);
|
|
81
|
+
generate(req: ImageGenerateRequest): Promise<ImageGenerateResult>;
|
|
82
|
+
}
|
|
83
|
+
/** Default model per provider kind when the caller doesn't specify one. */
|
|
84
|
+
export declare const DEFAULT_IMAGE_MODEL: Record<string, string>;
|
|
85
|
+
/** Registry of available image-provider adapters, keyed by `kind`. */
|
|
86
|
+
export declare function getImageProvider(kind: string, fetchImpl?: typeof fetch): ImageProvider | null;
|