@phuetz/code-buddy 1.1.0 → 1.3.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/README.md +211 -163
- package/dist/agent/autonomous/agentic-coding-contract.d.ts +12 -12
- package/dist/agent/base-agent.d.ts +4 -0
- package/dist/agent/base-agent.js +6 -0
- package/dist/agent/codebuddy-agent.d.ts +1 -1
- package/dist/agent/codebuddy-agent.js +69 -14
- package/dist/agent/execution/agent-executor.js +122 -12
- package/dist/agent/execution/tool-dependency-graph.js +7 -0
- package/dist/agent/execution/tool-hooks.d.ts +6 -0
- package/dist/agent/execution/tool-hooks.js +13 -5
- package/dist/agent/execution/tool-selection-strategy.d.ts +11 -2
- package/dist/agent/execution/tool-selection-strategy.js +67 -10
- package/dist/agent/extended-thinking.d.ts +8 -0
- package/dist/agent/extended-thinking.js +27 -0
- package/dist/agent/facades/infrastructure-facade.d.ts +9 -2
- package/dist/agent/facades/infrastructure-facade.js +15 -6
- package/dist/agent/hermes-browser-backends.js +151 -11
- package/dist/agent/hermes-claw-migrate.d.ts +59 -0
- package/dist/agent/hermes-claw-migrate.js +427 -26
- package/dist/agent/hermes-parity-manifest.js +78 -71
- package/dist/agent/hermes-runtime-lifecycle.d.ts +67 -0
- package/dist/agent/hermes-runtime-lifecycle.js +468 -0
- package/dist/agent/middleware/index.d.ts +1 -0
- package/dist/agent/middleware/index.js +1 -0
- package/dist/agent/middleware/visual-validation-middleware.d.ts +17 -0
- package/dist/agent/middleware/visual-validation-middleware.js +67 -0
- package/dist/agent/model-benchmark.d.ts +77 -0
- package/dist/agent/model-benchmark.js +309 -0
- package/dist/agent/model-tier.d.ts +14 -0
- package/dist/agent/model-tier.js +71 -0
- package/dist/agent/multi-agent/agents/orchestrator-agent.js +17 -6
- package/dist/agent/multi-agent/multi-agent-system.js +3 -1
- package/dist/agent/multi-agent/session-fleet-bridge.d.ts +2 -0
- package/dist/agent/multi-agent/session-fleet-bridge.js +9 -1
- package/dist/agent/multi-agent/session-tools.js +22 -5
- package/dist/agent/reasoning/mcts.js +20 -6
- package/dist/agent/self-improvement/authored-artifact-gate.d.ts +18 -0
- package/dist/agent/self-improvement/authored-artifact-gate.js +42 -0
- package/dist/agent/self-improvement/authored-tool-runtime.d.ts +27 -0
- package/dist/agent/self-improvement/authored-tool-runtime.js +57 -0
- package/dist/agent/self-improvement/authored-tool-store.d.ts +24 -0
- package/dist/agent/self-improvement/authored-tool-store.js +57 -0
- package/dist/agent/self-improvement/llm-tool-proposer.d.ts +41 -0
- package/dist/agent/self-improvement/llm-tool-proposer.js +136 -0
- package/dist/agent/self-improvement/sandbox-scorer.d.ts +17 -0
- package/dist/agent/self-improvement/sandbox-scorer.js +43 -0
- package/dist/agent/self-improvement/self-knowledge.d.ts +8 -0
- package/dist/agent/self-improvement/self-knowledge.js +24 -0
- package/dist/agent/self-improvement/skill-benchmark.d.ts +9 -0
- package/dist/agent/self-improvement/skill-benchmark.js +22 -0
- package/dist/agent/self-improvement/skill-consolidator.d.ts +71 -0
- package/dist/agent/self-improvement/skill-consolidator.js +137 -0
- package/dist/agent/self-improvement/skill-engine.d.ts +42 -0
- package/dist/agent/self-improvement/skill-engine.js +87 -0
- package/dist/agent/self-improvement/skill-gate.d.ts +19 -0
- package/dist/agent/self-improvement/skill-gate.js +62 -0
- package/dist/agent/self-improvement/skill-mutator.d.ts +74 -0
- package/dist/agent/self-improvement/skill-mutator.js +223 -0
- package/dist/agent/self-improvement/skill-proposer.d.ts +40 -0
- package/dist/agent/self-improvement/skill-proposer.js +82 -0
- package/dist/agent/self-improvement/skill-types.d.ts +41 -0
- package/dist/agent/self-improvement/skill-types.js +13 -0
- package/dist/agent/self-improvement/tool-benchmark.d.ts +10 -0
- package/dist/agent/self-improvement/tool-benchmark.js +37 -0
- package/dist/agent/self-improvement/tool-engine.d.ts +54 -0
- package/dist/agent/self-improvement/tool-engine.js +101 -0
- package/dist/agent/self-improvement/tool-gate.d.ts +20 -0
- package/dist/agent/self-improvement/tool-gate.js +78 -0
- package/dist/agent/self-improvement/tool-proposer.d.ts +31 -0
- package/dist/agent/self-improvement/tool-proposer.js +34 -0
- package/dist/agent/self-improvement/tool-skill-mutator.d.ts +40 -0
- package/dist/agent/self-improvement/tool-skill-mutator.js +79 -0
- package/dist/agent/self-improvement/tool-types.d.ts +48 -0
- package/dist/agent/self-improvement/tool-types.js +9 -0
- package/dist/agent/self-improvement/types.d.ts +3 -1
- package/dist/agent/session-end-flush.d.ts +6 -1
- package/dist/agent/session-end-flush.js +20 -4
- package/dist/agent/streaming/streaming-handler.d.ts +7 -0
- package/dist/agent/streaming/streaming-handler.js +8 -1
- package/dist/agent/tool-executor.js +1 -0
- package/dist/agent/tool-handler.d.ts +5 -0
- package/dist/agent/tool-handler.js +133 -4
- package/dist/browser-automation/browser-operator-executor.js +15 -0
- package/dist/browser-automation/browser-use-runner.d.ts +96 -0
- package/dist/browser-automation/browser-use-runner.js +492 -0
- package/dist/browser-automation/camofox-runner.d.ts +107 -0
- package/dist/browser-automation/camofox-runner.js +287 -0
- package/dist/channels/dingtalk/index.js +3 -0
- package/dist/channels/discord/client.d.ts +9 -0
- package/dist/channels/discord/client.js +12 -0
- package/dist/channels/feishu/index.d.ts +167 -1
- package/dist/channels/feishu/index.js +432 -7
- package/dist/channels/gateway-lifecycle.d.ts +132 -0
- package/dist/channels/gateway-lifecycle.js +219 -0
- package/dist/channels/google-chat/index.d.ts +5 -1
- package/dist/channels/google-chat/index.js +5 -1
- package/dist/channels/imessage/index.d.ts +14 -0
- package/dist/channels/imessage/index.js +64 -17
- package/dist/channels/index.d.ts +4 -0
- package/dist/channels/index.js +4 -0
- package/dist/channels/irc/index.d.ts +73 -3
- package/dist/channels/irc/index.js +446 -11
- package/dist/channels/line/index.js +3 -0
- package/dist/channels/mattermost/index.d.ts +51 -4
- package/dist/channels/mattermost/index.js +303 -20
- package/dist/channels/nextcloud-talk/index.d.ts +89 -8
- package/dist/channels/nextcloud-talk/index.js +367 -16
- package/dist/channels/nostr/index.d.ts +121 -1
- package/dist/channels/nostr/index.js +396 -8
- package/dist/channels/ntfy/index.js +3 -0
- package/dist/channels/qq/index.js +3 -0
- package/dist/channels/slash-parity.d.ts +117 -0
- package/dist/channels/slash-parity.js +185 -0
- package/dist/channels/synology-chat/index.js +3 -0
- package/dist/channels/teams/index.d.ts +3 -0
- package/dist/channels/teams/index.js +3 -0
- package/dist/channels/telegram/client.d.ts +9 -0
- package/dist/channels/telegram/client.js +12 -0
- package/dist/channels/twilio-voice/index.js +3 -0
- package/dist/channels/webchat/index.d.ts +7 -1
- package/dist/channels/webchat/index.js +7 -1
- package/dist/channels/wecom/index.js +3 -0
- package/dist/channels/weixin/index.js +3 -0
- package/dist/channels/zalo/index.js +3 -0
- package/dist/cli/config-loader.js +1 -1
- package/dist/codebuddy/client.d.ts +30 -1
- package/dist/codebuddy/client.js +167 -20
- package/dist/codebuddy/providers/provider-chatgpt-responses.d.ts +5 -0
- package/dist/codebuddy/providers/provider-chatgpt-responses.js +7 -1
- package/dist/codebuddy/providers/provider-gemini-native.js +1 -1
- package/dist/codebuddy/providers/provider-openai-compat.d.ts +5 -0
- package/dist/codebuddy/providers/provider-openai-compat.js +82 -2
- package/dist/codebuddy/tool-definitions/computer-control-tools.js +32 -2
- package/dist/codebuddy/tool-definitions/core-tools.js +3 -3
- package/dist/codebuddy/tool-definitions/index.d.ts +2 -1
- package/dist/codebuddy/tool-definitions/index.js +2 -1
- package/dist/codebuddy/tool-definitions/multimodal-tools.d.ts +1 -0
- package/dist/codebuddy/tool-definitions/multimodal-tools.js +44 -1
- package/dist/codebuddy/tool-definitions/windows-tools.d.ts +2 -0
- package/dist/codebuddy/tool-definitions/windows-tools.js +34 -0
- package/dist/codebuddy/tools.d.ts +8 -1
- package/dist/codebuddy/tools.js +67 -24
- package/dist/commands/cli/hermes-commands.js +108 -0
- package/dist/commands/cli/improve-command.js +123 -0
- package/dist/commands/cli/native-engine-commands.js +102 -3
- package/dist/commands/cli/utility-commands.js +45 -0
- package/dist/commands/enhanced-command-handler.js +2 -2
- package/dist/commands/goal-cli.d.ts +30 -0
- package/dist/commands/goal-cli.js +210 -27
- package/dist/commands/handlers/goal-handler.d.ts +9 -2
- package/dist/commands/handlers/goal-handler.js +36 -9
- package/dist/commands/handlers/infra-handlers.js +36 -0
- package/dist/commands/handlers/memory-handlers.js +96 -1
- package/dist/commands/handlers/missing-handlers.d.ts +1 -1
- package/dist/commands/handlers/missing-handlers.js +26 -3
- package/dist/commands/headless-slash.d.ts +2 -0
- package/dist/commands/headless-slash.js +12 -0
- package/dist/commands/llm-provider-resolution.d.ts +5 -3
- package/dist/commands/llm-provider-resolution.js +87 -33
- package/dist/commands/ollama.d.ts +25 -0
- package/dist/commands/ollama.js +100 -0
- package/dist/commands/provider.d.ts +5 -0
- package/dist/commands/provider.js +106 -55
- package/dist/commands/skills-cli/index.js +123 -0
- package/dist/commands/slash/builtin-commands.js +1 -1
- package/dist/commands/spec-next.js +2 -1
- package/dist/commands/spec-plan.js +5 -16
- package/dist/commands/tunnel.d.ts +2 -0
- package/dist/commands/tunnel.js +48 -0
- package/dist/companion/percepts.js +11 -1
- package/dist/config/config-resolver.d.ts +2 -1
- package/dist/config/config-resolver.js +54 -41
- package/dist/config/constants.d.ts +28 -0
- package/dist/config/constants.js +7 -0
- package/dist/config/env-schema.js +756 -0
- package/dist/config/model-tools.js +4 -4
- package/dist/config/toml-config.d.ts +16 -0
- package/dist/config/toml-config.js +3 -0
- package/dist/context/bootstrap-loader.js +6 -23
- package/dist/context/context-manager-v2.js +1 -0
- package/dist/context/import-directive-parser.d.ts +4 -0
- package/dist/context/import-directive-parser.js +51 -6
- package/dist/context/instruction-excludes.d.ts +30 -1
- package/dist/context/instruction-excludes.js +71 -1
- package/dist/context/jit-context.d.ts +8 -10
- package/dist/context/jit-context.js +28 -106
- package/dist/context/project-context.d.ts +90 -0
- package/dist/context/project-context.js +295 -0
- package/dist/daemon/autonomous-daemon.d.ts +1 -1
- package/dist/daemon/autonomous-daemon.js +3 -3
- package/dist/daemon/autonomous-loop.d.ts +31 -1
- package/dist/daemon/autonomous-loop.js +91 -4
- package/dist/daemon/colab-goal.js +9 -1
- package/dist/daemon/cron-agent-bridge.d.ts +12 -3
- package/dist/daemon/cron-agent-bridge.js +25 -9
- package/dist/desktop/codebuddy-engine-adapter.d.ts +32 -0
- package/dist/desktop/codebuddy-engine-adapter.js +257 -80
- package/dist/desktop/engine-adapter.d.ts +14 -0
- package/dist/desktop-automation/automation-manager.js +16 -0
- package/dist/desktop-automation/omniparser-runner.d.ts +63 -0
- package/dist/desktop-automation/omniparser-runner.js +115 -0
- package/dist/desktop-automation/smart-snapshot.d.ts +11 -0
- package/dist/desktop-automation/smart-snapshot.js +72 -5
- package/dist/doctor/index.js +40 -23
- package/dist/events/types.d.ts +11 -0
- package/dist/fleet/colab-store.js +14 -2
- package/dist/fleet/peer-session-bridge.js +50 -12
- package/dist/fleet/peer-tool-bridge.js +14 -0
- package/dist/goals/goal-decomposer.d.ts +27 -0
- package/dist/goals/goal-decomposer.js +293 -0
- package/dist/goals/goal-judge-client.d.ts +15 -0
- package/dist/goals/goal-judge-client.js +45 -0
- package/dist/goals/goal-judge.d.ts +2 -0
- package/dist/goals/goal-judge.js +35 -6
- package/dist/goals/goal-loop.d.ts +14 -0
- package/dist/goals/goal-loop.js +47 -2
- package/dist/goals/goal-manager.d.ts +6 -0
- package/dist/goals/goal-manager.js +67 -14
- package/dist/goals/goal-state.d.ts +13 -0
- package/dist/goals/goal-state.js +83 -13
- package/dist/goals/goal-store.d.ts +3 -0
- package/dist/goals/goal-store.js +31 -15
- package/dist/harness/contract.d.ts +28 -28
- package/dist/hooks/user-hooks.js +17 -3
- package/dist/identity/identity-manager.js +3 -2
- package/dist/index.js +481 -26
- package/dist/input/text-to-speech.d.ts +2 -6
- package/dist/input/text-to-speech.js +2 -27
- package/dist/integrations/screenpipe/screenpipe-client.d.ts +10 -0
- package/dist/integrations/screenpipe/screenpipe-client.js +12 -2
- package/dist/integrations/tailscale.d.ts +13 -0
- package/dist/integrations/tailscale.js +87 -34
- package/dist/knowledge/workspace-indexer.js +53 -9
- package/dist/mcp/client.js +1 -0
- package/dist/mcp/mcp-desktop-tools.d.ts +23 -0
- package/dist/mcp/mcp-desktop-tools.js +158 -0
- package/dist/mcp/mcp-resources.js +2 -3
- package/dist/mcp/mcp-server.js +2 -0
- package/dist/memory/enhanced-memory.d.ts +10 -0
- package/dist/memory/enhanced-memory.js +33 -2
- package/dist/memory/index.d.ts +3 -1
- package/dist/memory/index.js +4 -1
- package/dist/memory/memory-auto-proposer.d.ts +23 -0
- package/dist/memory/memory-auto-proposer.js +308 -0
- package/dist/memory/memory-candidate-queue.d.ts +92 -0
- package/dist/memory/memory-candidate-queue.js +261 -0
- package/dist/memory/persistent-memory.d.ts +45 -2
- package/dist/memory/persistent-memory.js +236 -40
- package/dist/ml/bayesian-qualifier.d.ts +1 -1
- package/dist/ml/bayesian-qualifier.js +35 -2
- package/dist/openclaw/gateway-bridge.js +5 -0
- package/dist/plugins/marketplace.d.ts +1 -0
- package/dist/plugins/marketplace.js +7 -0
- package/dist/prompts/execution-discipline.d.ts +14 -0
- package/dist/prompts/execution-discipline.js +29 -0
- package/dist/prompts/variation-injector.js +9 -2
- package/dist/protocols/acp/acp-agentic-runner.d.ts +7 -6
- package/dist/protocols/acp/acp-agentic-runner.js +115 -18
- package/dist/protocols/acp/acp-session-store.d.ts +23 -0
- package/dist/protocols/acp/acp-session-store.js +77 -0
- package/dist/protocols/acp/acp-stdio-server.d.ts +7 -0
- package/dist/protocols/acp/acp-stdio-server.js +71 -16
- package/dist/providers/active-llm-registry.d.ts +37 -0
- package/dist/providers/active-llm-registry.js +186 -0
- package/dist/providers/auxiliary-provider.d.ts +25 -0
- package/dist/providers/auxiliary-provider.js +192 -0
- package/dist/providers/codex-oauth.d.ts +1 -1
- package/dist/providers/codex-oauth.js +27 -4
- package/dist/providers/index.d.ts +3 -0
- package/dist/providers/index.js +4 -0
- package/dist/providers/provider-catalog.d.ts +70 -0
- package/dist/providers/provider-catalog.js +738 -0
- package/dist/providers/provider-fallback.d.ts +35 -0
- package/dist/providers/provider-fallback.js +171 -0
- package/dist/providers/xai-oauth.d.ts +128 -0
- package/dist/providers/xai-oauth.js +735 -0
- package/dist/scheduler/cron-scheduler.d.ts +15 -3
- package/dist/scheduler/cron-scheduler.js +53 -7
- package/dist/scheduler/script-runner.d.ts +2 -0
- package/dist/scheduler/script-runner.js +19 -4
- package/dist/scheduler/watchdog-handlers.js +7 -20
- package/dist/search/usearch-index.js +7 -2
- package/dist/security/tool-policy/tool-groups.js +2 -0
- package/dist/sensory/dreaming.d.ts +45 -0
- package/dist/sensory/dreaming.js +114 -0
- package/dist/sensory/heartbeat-scheduler.d.ts +38 -0
- package/dist/sensory/heartbeat-scheduler.js +72 -0
- package/dist/sensory/reactions.d.ts +24 -0
- package/dist/sensory/reactions.js +31 -0
- package/dist/sensory/screen-reaction.d.ts +23 -0
- package/dist/sensory/screen-reaction.js +59 -0
- package/dist/sensory/sensory-bridge.d.ts +23 -0
- package/dist/sensory/sensory-bridge.js +85 -0
- package/dist/sensory/sensory-memory.d.ts +20 -0
- package/dist/sensory/sensory-memory.js +39 -0
- package/dist/sensory/speech-reaction.d.ts +21 -0
- package/dist/sensory/speech-reaction.js +83 -0
- package/dist/sensory/vision-reaction.d.ts +31 -0
- package/dist/sensory/vision-reaction.js +74 -0
- package/dist/server/index.js +106 -2
- package/dist/server/routes/mobile.d.ts +12 -4
- package/dist/server/routes/mobile.js +116 -1
- package/dist/server/tls-config.d.ts +35 -0
- package/dist/server/tls-config.js +142 -0
- package/dist/server/tunnel-manager.d.ts +20 -0
- package/dist/server/tunnel-manager.js +58 -0
- package/dist/server/websocket/fleet-bridge.js +5 -0
- package/dist/services/prompt-builder.d.ts +11 -0
- package/dist/services/prompt-builder.js +124 -17
- package/dist/shared/engine-types.d.ts +15 -1
- package/dist/sidecar/sidecar-bridge.d.ts +1 -0
- package/dist/sidecar/sidecar-bridge.js +21 -10
- package/dist/skills/parser.js +3 -0
- package/dist/skills/skill-importer.d.ts +58 -0
- package/dist/skills/skill-importer.js +261 -0
- package/dist/skills/skill-sources.d.ts +20 -0
- package/dist/skills/skill-sources.js +102 -0
- package/dist/skills/types.d.ts +6 -0
- package/dist/spec/spec-store.js +8 -1
- package/dist/talk-mode/providers/audioreader-tts.d.ts +1 -1
- package/dist/talk-mode/providers/audioreader-tts.js +8 -8
- package/dist/templates/project-scaffolding.js +3 -2
- package/dist/themes/theme-schema.d.ts +10 -10
- package/dist/tools/application-profiles.js +38 -0
- package/dist/tools/bash/bash-tool.d.ts +1 -0
- package/dist/tools/bash/bash-tool.js +16 -2
- package/dist/tools/bash/command-validator.js +3 -0
- package/dist/tools/bash/rtk-rewrite.d.ts +16 -0
- package/dist/tools/bash/rtk-rewrite.js +100 -0
- package/dist/tools/bash/streaming-executor.js +14 -1
- package/dist/tools/computer-control-tool.d.ts +16 -1
- package/dist/tools/computer-control-tool.js +317 -5
- package/dist/tools/document-generator.d.ts +14 -0
- package/dist/tools/document-generator.js +79 -0
- package/dist/tools/execute-code-rpc-invoker.d.ts +26 -2
- package/dist/tools/execute-code-rpc-invoker.js +46 -5
- package/dist/tools/metadata.js +28 -0
- package/dist/tools/office-macro-tool.d.ts +10 -0
- package/dist/tools/office-macro-tool.js +93 -0
- package/dist/tools/register-tool-handler.d.ts +25 -0
- package/dist/tools/register-tool-handler.js +100 -0
- package/dist/tools/registry/index.d.ts +2 -1
- package/dist/tools/registry/index.js +2 -1
- package/dist/tools/registry/memory-tools.d.ts +20 -0
- package/dist/tools/registry/memory-tools.js +225 -3
- package/dist/tools/registry/multimodal-tools.js +2 -2
- package/dist/tools/registry/vision-tools.d.ts +33 -0
- package/dist/tools/registry/vision-tools.js +308 -6
- package/dist/tools/registry/windows-tools.d.ts +2 -0
- package/dist/tools/registry/windows-tools.js +47 -0
- package/dist/tools/registry.d.ts +6 -0
- package/dist/tools/registry.js +8 -0
- package/dist/tools/route-peer-tool.js +14 -0
- package/dist/tools/screenshot-tool.js +14 -2
- package/dist/tools/text-to-speech-tool.d.ts +1 -1
- package/dist/tools/text-to-speech-tool.js +2 -12
- package/dist/tools/tool-selector.js +3 -59
- package/dist/utils/config-validation/schema.d.ts +40 -7
- package/dist/utils/config-validation/schema.js +130 -1
- package/dist/utils/cost-tracker.js +21 -1
- package/dist/utils/disk-guard.d.ts +180 -0
- package/dist/utils/disk-guard.js +404 -0
- package/dist/utils/init-project.d.ts +7 -0
- package/dist/utils/init-project.js +37 -0
- package/dist/utils/interactive-setup.js +35 -2
- package/dist/utils/model-utils.js +11 -2
- package/dist/utils/output-sanitizer.js +11 -0
- package/dist/utils/provider-detector.d.ts +8 -7
- package/dist/utils/provider-detector.js +19 -77
- package/dist/utils/settings-manager.d.ts +19 -0
- package/dist/utils/token-display.d.ts +3 -3
- package/dist/utils/token-display.js +22 -4
- package/dist/wizard/onboarding.d.ts +39 -0
- package/dist/wizard/onboarding.js +433 -21
- package/dist/wizard/provider-onboarding.d.ts +8 -23
- package/dist/wizard/provider-onboarding.js +39 -158
- package/package.json +4 -2
- package/dist/plugins/provider-onboarding.d.ts +0 -23
- package/dist/plugins/provider-onboarding.js +0 -116
- package/dist/utils/kokoro-tts.d.ts +0 -8
- package/dist/utils/kokoro-tts.js +0 -67
|
@@ -18,6 +18,7 @@ import { listApplicationProfiles, resolveApplicationProfile, } from './applicati
|
|
|
18
18
|
import { getActiveRunStore } from '../observability/run-store.js';
|
|
19
19
|
import { logger } from '../utils/logger.js';
|
|
20
20
|
import { getDesktopAutomation, getPermissionManager, getSystemControl, getSmartSnapshotManager, getScreenRecorder, } from '../desktop-automation/index.js';
|
|
21
|
+
import { OmniParserRunner } from "../desktop-automation/omniparser-runner.js";
|
|
21
22
|
const execFileAsync = promisify(execFile);
|
|
22
23
|
let visionGroundingProvider = null;
|
|
23
24
|
export function setVisionGroundingProvider(p) {
|
|
@@ -55,6 +56,7 @@ export class ComputerControlTool {
|
|
|
55
56
|
systemControl = getSystemControl();
|
|
56
57
|
snapshotManager = getSmartSnapshotManager();
|
|
57
58
|
screenRecorder = getScreenRecorder();
|
|
59
|
+
omniParser = new OmniParserRunner();
|
|
58
60
|
lastTargetFocusProof = null;
|
|
59
61
|
lastVisualContextProof = null;
|
|
60
62
|
/**
|
|
@@ -161,6 +163,20 @@ export class ComputerControlTool {
|
|
|
161
163
|
return run(() => this.excelGetCell(enrichedInput));
|
|
162
164
|
case 'excel_save_workbook':
|
|
163
165
|
return run(() => this.excelSaveWorkbook(enrichedInput));
|
|
166
|
+
case 'powerpoint_open_presentation':
|
|
167
|
+
return run(() => this.powerpointOpenPresentation(enrichedInput));
|
|
168
|
+
case 'powerpoint_add_slide':
|
|
169
|
+
return run(() => this.powerpointAddSlide(enrichedInput));
|
|
170
|
+
case 'powerpoint_set_text':
|
|
171
|
+
return run(() => this.powerpointSetText(enrichedInput));
|
|
172
|
+
case 'powerpoint_save_presentation':
|
|
173
|
+
return run(() => this.powerpointSavePresentation(enrichedInput));
|
|
174
|
+
case 'word_open_document':
|
|
175
|
+
return run(() => this.wordOpenDocument(enrichedInput));
|
|
176
|
+
case 'word_type_text':
|
|
177
|
+
return run(() => this.wordTypeText(enrichedInput));
|
|
178
|
+
case 'word_save_document':
|
|
179
|
+
return run(() => this.wordSaveDocument(enrichedInput));
|
|
164
180
|
case 'use_app_workflow':
|
|
165
181
|
case 'macro':
|
|
166
182
|
return run(() => this.executeMacro(enrichedInput));
|
|
@@ -417,7 +433,7 @@ export class ComputerControlTool {
|
|
|
417
433
|
const snapshot = await this.snapshotManager.takeSnapshot({
|
|
418
434
|
interactiveOnly: input.interactiveOnly ?? true,
|
|
419
435
|
});
|
|
420
|
-
|
|
436
|
+
let textRepresentation = this.snapshotManager.toTextRepresentation(snapshot);
|
|
421
437
|
// Capture and normalize screenshot for LLM
|
|
422
438
|
let screenshotData = {};
|
|
423
439
|
try {
|
|
@@ -447,6 +463,26 @@ export class ComputerControlTool {
|
|
|
447
463
|
catch (err) {
|
|
448
464
|
logger.debug('Screenshot capture failed in snapshot_with_screenshot', { error: err });
|
|
449
465
|
}
|
|
466
|
+
// Apply OmniParser if requested and screenshot was successful
|
|
467
|
+
if (input.useOmniParser && screenshotData.base64) {
|
|
468
|
+
const omniResult = await this.omniParser.parseScreen(screenshotData.base64, {
|
|
469
|
+
width: screenshotData.width,
|
|
470
|
+
height: screenshotData.height,
|
|
471
|
+
});
|
|
472
|
+
if (omniResult.elements.length > 0) {
|
|
473
|
+
// Override screenshot with the annotated (Set-of-Marks) image whose numbers match the ids below.
|
|
474
|
+
screenshotData.base64 = omniResult.annotatedImageBase64;
|
|
475
|
+
const unit = omniResult.elements[0]?.normalized ? 'ratio 0-1' : 'px';
|
|
476
|
+
const parsedText = omniResult.elements
|
|
477
|
+
.map((e) => `[${e.id}] ${e.type}${e.interactable ? ' (interactive)' : ''} "${e.content}" center=(${e.center[0]},${e.center[1]})`)
|
|
478
|
+
.join('\n');
|
|
479
|
+
textRepresentation += `\n\n[OmniParser Elements] (coords in ${unit}; use 'click' at an element center to act):\n${parsedText}`;
|
|
480
|
+
}
|
|
481
|
+
else {
|
|
482
|
+
// No elements => server down/misconfigured or empty parse. Keep the original snapshot, don't add noise.
|
|
483
|
+
logger.debug('OmniParser returned no elements; keeping original screenshot and snapshot text');
|
|
484
|
+
}
|
|
485
|
+
}
|
|
450
486
|
return {
|
|
451
487
|
success: true,
|
|
452
488
|
output: textRepresentation,
|
|
@@ -1512,7 +1548,7 @@ if ($clickButtonName) {
|
|
|
1512
1548
|
withDerivedAppWindowTarget(input, profile) {
|
|
1513
1549
|
const next = { ...input };
|
|
1514
1550
|
if (profile.id === 'notepad' && input.filePath && !next.windowTitle && !next.windowTitleRegex) {
|
|
1515
|
-
next.windowTitle =
|
|
1551
|
+
next.windowTitle = this.basenameForWindowTitle(input.filePath);
|
|
1516
1552
|
next.windowTitleMatch = 'contains';
|
|
1517
1553
|
}
|
|
1518
1554
|
return next;
|
|
@@ -1603,11 +1639,14 @@ if ($clickButtonName) {
|
|
|
1603
1639
|
}
|
|
1604
1640
|
}
|
|
1605
1641
|
if (profile?.id === 'notepad' && input.filePath && !next.windowTitle && !next.windowTitleRegex) {
|
|
1606
|
-
next.windowTitle =
|
|
1642
|
+
next.windowTitle = this.basenameForWindowTitle(input.filePath);
|
|
1607
1643
|
next.windowTitleMatch = 'contains';
|
|
1608
1644
|
}
|
|
1609
1645
|
return next;
|
|
1610
1646
|
}
|
|
1647
|
+
basenameForWindowTitle(filePath) {
|
|
1648
|
+
return filePath.includes('\\') ? path.win32.basename(filePath) : path.basename(filePath);
|
|
1649
|
+
}
|
|
1611
1650
|
async excelOpenWorkbook(input) {
|
|
1612
1651
|
const result = await this.runExcelAutomation({
|
|
1613
1652
|
operation: 'open',
|
|
@@ -1666,6 +1705,97 @@ if ($clickButtonName) {
|
|
|
1666
1705
|
data: result,
|
|
1667
1706
|
};
|
|
1668
1707
|
}
|
|
1708
|
+
async powerpointOpenPresentation(input) {
|
|
1709
|
+
const result = await this.runPowerpointAutomation({
|
|
1710
|
+
operation: 'open',
|
|
1711
|
+
filePath: input.filePath,
|
|
1712
|
+
});
|
|
1713
|
+
return {
|
|
1714
|
+
success: true,
|
|
1715
|
+
output: `PowerPoint presentation ready: ${result.presentationName ?? result.filePath ?? 'new presentation'}`,
|
|
1716
|
+
data: result,
|
|
1717
|
+
};
|
|
1718
|
+
}
|
|
1719
|
+
async powerpointAddSlide(input) {
|
|
1720
|
+
const result = await this.runPowerpointAutomation({
|
|
1721
|
+
operation: 'addSlide',
|
|
1722
|
+
filePath: input.filePath,
|
|
1723
|
+
layoutIndex: input.layoutIndex,
|
|
1724
|
+
});
|
|
1725
|
+
return {
|
|
1726
|
+
success: true,
|
|
1727
|
+
output: `PowerPoint slide added (index ${result.slideIndex})`,
|
|
1728
|
+
data: result,
|
|
1729
|
+
};
|
|
1730
|
+
}
|
|
1731
|
+
async powerpointSetText(input) {
|
|
1732
|
+
if (input.slideIndex === undefined || input.shapeIndex === undefined) {
|
|
1733
|
+
return { success: false, error: 'slideIndex and shapeIndex are required' };
|
|
1734
|
+
}
|
|
1735
|
+
const result = await this.runPowerpointAutomation({
|
|
1736
|
+
operation: 'setText',
|
|
1737
|
+
filePath: input.filePath,
|
|
1738
|
+
slideIndex: input.slideIndex,
|
|
1739
|
+
shapeIndex: input.shapeIndex,
|
|
1740
|
+
value: input.value ?? input.text ?? '',
|
|
1741
|
+
});
|
|
1742
|
+
return {
|
|
1743
|
+
success: true,
|
|
1744
|
+
output: `PowerPoint slide ${input.slideIndex} shape ${input.shapeIndex} text set.`,
|
|
1745
|
+
data: result,
|
|
1746
|
+
};
|
|
1747
|
+
}
|
|
1748
|
+
async powerpointSavePresentation(input) {
|
|
1749
|
+
const result = await this.runPowerpointAutomation({
|
|
1750
|
+
operation: 'save',
|
|
1751
|
+
filePath: input.filePath,
|
|
1752
|
+
saveAsPath: input.saveAsPath,
|
|
1753
|
+
});
|
|
1754
|
+
return {
|
|
1755
|
+
success: true,
|
|
1756
|
+
output: `PowerPoint presentation saved${result.filePath ? `: ${result.filePath}` : ''}`,
|
|
1757
|
+
data: result,
|
|
1758
|
+
};
|
|
1759
|
+
}
|
|
1760
|
+
async wordOpenDocument(input) {
|
|
1761
|
+
const result = await this.runWordAutomation({
|
|
1762
|
+
operation: 'open',
|
|
1763
|
+
filePath: input.filePath,
|
|
1764
|
+
});
|
|
1765
|
+
return {
|
|
1766
|
+
success: true,
|
|
1767
|
+
output: `Word document ready: ${result.documentName ?? result.filePath ?? 'new document'}`,
|
|
1768
|
+
data: result,
|
|
1769
|
+
};
|
|
1770
|
+
}
|
|
1771
|
+
async wordTypeText(input) {
|
|
1772
|
+
const value = input.value ?? input.text;
|
|
1773
|
+
if (value === undefined || value === null) {
|
|
1774
|
+
return { success: false, error: 'value (or text) is required for word_type_text' };
|
|
1775
|
+
}
|
|
1776
|
+
const result = await this.runWordAutomation({
|
|
1777
|
+
operation: 'typeText',
|
|
1778
|
+
filePath: input.filePath,
|
|
1779
|
+
value,
|
|
1780
|
+
});
|
|
1781
|
+
return {
|
|
1782
|
+
success: true,
|
|
1783
|
+
output: `Word document text appended.`,
|
|
1784
|
+
data: result,
|
|
1785
|
+
};
|
|
1786
|
+
}
|
|
1787
|
+
async wordSaveDocument(input) {
|
|
1788
|
+
const result = await this.runWordAutomation({
|
|
1789
|
+
operation: 'save',
|
|
1790
|
+
filePath: input.filePath,
|
|
1791
|
+
saveAsPath: input.saveAsPath,
|
|
1792
|
+
});
|
|
1793
|
+
return {
|
|
1794
|
+
success: true,
|
|
1795
|
+
output: `Word document saved${result.filePath ? `: ${result.filePath}` : ''}`,
|
|
1796
|
+
data: result,
|
|
1797
|
+
};
|
|
1798
|
+
}
|
|
1669
1799
|
// ============================================================================
|
|
1670
1800
|
// Mouse Actions
|
|
1671
1801
|
// ============================================================================
|
|
@@ -2697,6 +2827,186 @@ switch ($operation) {
|
|
|
2697
2827
|
value = $value
|
|
2698
2828
|
visible = $excel.Visible
|
|
2699
2829
|
} | ConvertTo-Json -Compress
|
|
2830
|
+
`;
|
|
2831
|
+
const stdout = await this.runPowerShellEncoded(script, 30000);
|
|
2832
|
+
return JSON.parse(stdout || '{}');
|
|
2833
|
+
}
|
|
2834
|
+
async runPowerpointAutomation(payload) {
|
|
2835
|
+
if (process.platform !== 'win32') {
|
|
2836
|
+
throw new Error('PowerPoint application profile currently requires Windows COM automation.');
|
|
2837
|
+
}
|
|
2838
|
+
const encodedPayload = Buffer.from(JSON.stringify(payload), 'utf8').toString('base64');
|
|
2839
|
+
const script = `
|
|
2840
|
+
$ErrorActionPreference = 'Stop'
|
|
2841
|
+
$payload = [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('${encodedPayload}')) | ConvertFrom-Json
|
|
2842
|
+
|
|
2843
|
+
function Get-PowerPointApplication {
|
|
2844
|
+
try {
|
|
2845
|
+
return [Runtime.InteropServices.Marshal]::GetActiveObject('PowerPoint.Application')
|
|
2846
|
+
} catch {
|
|
2847
|
+
return New-Object -ComObject PowerPoint.Application
|
|
2848
|
+
}
|
|
2849
|
+
}
|
|
2850
|
+
|
|
2851
|
+
function Resolve-Presentation($ppt, $filePath) {
|
|
2852
|
+
if ($filePath) {
|
|
2853
|
+
$fullPath = [System.IO.Path]::GetFullPath([string]$filePath)
|
|
2854
|
+
foreach ($pres in @($ppt.Presentations)) {
|
|
2855
|
+
try {
|
|
2856
|
+
if ($pres.FullName -eq $fullPath) { return $pres }
|
|
2857
|
+
} catch {}
|
|
2858
|
+
}
|
|
2859
|
+
if (Test-Path -LiteralPath $fullPath) {
|
|
2860
|
+
return $ppt.Presentations.Open($fullPath)
|
|
2861
|
+
}
|
|
2862
|
+
$pres = $ppt.Presentations.Add()
|
|
2863
|
+
$pres.SaveAs($fullPath)
|
|
2864
|
+
return $pres
|
|
2865
|
+
}
|
|
2866
|
+
|
|
2867
|
+
if ($ppt.Presentations.Count -gt 0) {
|
|
2868
|
+
return $ppt.ActivePresentation
|
|
2869
|
+
}
|
|
2870
|
+
return $ppt.Presentations.Add()
|
|
2871
|
+
}
|
|
2872
|
+
|
|
2873
|
+
$ppt = Get-PowerPointApplication
|
|
2874
|
+
$ppt.Visible = 1
|
|
2875
|
+
$presentation = Resolve-Presentation $ppt $payload.filePath
|
|
2876
|
+
$operation = [string]$payload.operation
|
|
2877
|
+
$slideIndex = $payload.slideIndex
|
|
2878
|
+
$shapeIndex = $payload.shapeIndex
|
|
2879
|
+
$value = $null
|
|
2880
|
+
|
|
2881
|
+
switch ($operation) {
|
|
2882
|
+
'open' {
|
|
2883
|
+
$value = $null
|
|
2884
|
+
}
|
|
2885
|
+
'addSlide' {
|
|
2886
|
+
$layoutIndex = 1
|
|
2887
|
+
if ($null -ne $payload.layoutIndex) { $layoutIndex = $payload.layoutIndex }
|
|
2888
|
+
# ppLayoutText = 2, ppLayoutTitle = 1
|
|
2889
|
+
$slideCount = $presentation.Slides.Count
|
|
2890
|
+
$slide = $presentation.Slides.Add($slideCount + 1, $layoutIndex)
|
|
2891
|
+
$slideIndex = $slide.SlideIndex
|
|
2892
|
+
}
|
|
2893
|
+
'setText' {
|
|
2894
|
+
if ($null -eq $slideIndex -or $null -eq $shapeIndex) { throw 'slideIndex and shapeIndex are required' }
|
|
2895
|
+
$slide = $presentation.Slides.Item([int]$slideIndex)
|
|
2896
|
+
$shape = $slide.Shapes.Item([int]$shapeIndex)
|
|
2897
|
+
if ($shape.HasTextFrame) {
|
|
2898
|
+
$shape.TextFrame.TextRange.Text = $payload.value
|
|
2899
|
+
} else {
|
|
2900
|
+
throw 'Shape does not have a text frame'
|
|
2901
|
+
}
|
|
2902
|
+
$value = $payload.value
|
|
2903
|
+
}
|
|
2904
|
+
'save' {
|
|
2905
|
+
if ($payload.saveAsPath) {
|
|
2906
|
+
$savePath = [System.IO.Path]::GetFullPath([string]$payload.saveAsPath)
|
|
2907
|
+
$presentation.SaveAs($savePath)
|
|
2908
|
+
} elseif ($payload.filePath) {
|
|
2909
|
+
$presentation.Save()
|
|
2910
|
+
} elseif ($presentation.Path) {
|
|
2911
|
+
$presentation.Save()
|
|
2912
|
+
} else {
|
|
2913
|
+
throw 'saveAsPath is required for an unsaved presentation.'
|
|
2914
|
+
}
|
|
2915
|
+
$value = $null
|
|
2916
|
+
}
|
|
2917
|
+
default {
|
|
2918
|
+
throw "Unknown PowerPoint operation '$operation'"
|
|
2919
|
+
}
|
|
2920
|
+
}
|
|
2921
|
+
|
|
2922
|
+
[pscustomobject]@{
|
|
2923
|
+
operation = $operation
|
|
2924
|
+
filePath = $presentation.FullName
|
|
2925
|
+
presentationName = $presentation.Name
|
|
2926
|
+
slideIndex = $slideIndex
|
|
2927
|
+
value = $value
|
|
2928
|
+
} | ConvertTo-Json -Compress
|
|
2929
|
+
`;
|
|
2930
|
+
const stdout = await this.runPowerShellEncoded(script, 30000);
|
|
2931
|
+
return JSON.parse(stdout || '{}');
|
|
2932
|
+
}
|
|
2933
|
+
async runWordAutomation(payload) {
|
|
2934
|
+
if (process.platform !== 'win32') {
|
|
2935
|
+
throw new Error('Word application profile currently requires Windows COM automation.');
|
|
2936
|
+
}
|
|
2937
|
+
const encodedPayload = Buffer.from(JSON.stringify(payload), 'utf8').toString('base64');
|
|
2938
|
+
const script = `
|
|
2939
|
+
$ErrorActionPreference = 'Stop'
|
|
2940
|
+
$payload = [System.Text.Encoding]::UTF8.GetString([Convert]::FromBase64String('${encodedPayload}')) | ConvertFrom-Json
|
|
2941
|
+
|
|
2942
|
+
function Get-WordApplication {
|
|
2943
|
+
try {
|
|
2944
|
+
return [Runtime.InteropServices.Marshal]::GetActiveObject('Word.Application')
|
|
2945
|
+
} catch {
|
|
2946
|
+
return New-Object -ComObject Word.Application
|
|
2947
|
+
}
|
|
2948
|
+
}
|
|
2949
|
+
|
|
2950
|
+
function Resolve-Document($word, $filePath) {
|
|
2951
|
+
if ($filePath) {
|
|
2952
|
+
$fullPath = [System.IO.Path]::GetFullPath([string]$filePath)
|
|
2953
|
+
foreach ($doc in @($word.Documents)) {
|
|
2954
|
+
try {
|
|
2955
|
+
if ($doc.FullName -eq $fullPath) { return $doc }
|
|
2956
|
+
} catch {}
|
|
2957
|
+
}
|
|
2958
|
+
if (Test-Path -LiteralPath $fullPath) {
|
|
2959
|
+
return $word.Documents.Open($fullPath)
|
|
2960
|
+
}
|
|
2961
|
+
$doc = $word.Documents.Add()
|
|
2962
|
+
$doc.SaveAs([string]$fullPath)
|
|
2963
|
+
return $doc
|
|
2964
|
+
}
|
|
2965
|
+
|
|
2966
|
+
if ($word.Documents.Count -gt 0) {
|
|
2967
|
+
return $word.ActiveDocument
|
|
2968
|
+
}
|
|
2969
|
+
return $word.Documents.Add()
|
|
2970
|
+
}
|
|
2971
|
+
|
|
2972
|
+
$word = Get-WordApplication
|
|
2973
|
+
$word.Visible = 1
|
|
2974
|
+
$document = Resolve-Document $word $payload.filePath
|
|
2975
|
+
$operation = [string]$payload.operation
|
|
2976
|
+
$value = $null
|
|
2977
|
+
|
|
2978
|
+
switch ($operation) {
|
|
2979
|
+
'open' {
|
|
2980
|
+
$value = $null
|
|
2981
|
+
}
|
|
2982
|
+
'typeText' {
|
|
2983
|
+
$document.Content.InsertAfter([string]$payload.value)
|
|
2984
|
+
$value = $payload.value
|
|
2985
|
+
}
|
|
2986
|
+
'save' {
|
|
2987
|
+
if ($payload.saveAsPath) {
|
|
2988
|
+
$savePath = [System.IO.Path]::GetFullPath([string]$payload.saveAsPath)
|
|
2989
|
+
$document.SaveAs([string]$savePath)
|
|
2990
|
+
} elseif ($payload.filePath) {
|
|
2991
|
+
$document.Save()
|
|
2992
|
+
} elseif ($document.Path) {
|
|
2993
|
+
$document.Save()
|
|
2994
|
+
} else {
|
|
2995
|
+
throw 'saveAsPath is required for an unsaved document.'
|
|
2996
|
+
}
|
|
2997
|
+
$value = $null
|
|
2998
|
+
}
|
|
2999
|
+
default {
|
|
3000
|
+
throw "Unknown Word operation '$operation'"
|
|
3001
|
+
}
|
|
3002
|
+
}
|
|
3003
|
+
|
|
3004
|
+
[pscustomobject]@{
|
|
3005
|
+
operation = $operation
|
|
3006
|
+
filePath = $document.FullName
|
|
3007
|
+
documentName = $document.Name
|
|
3008
|
+
value = $value
|
|
3009
|
+
} | ConvertTo-Json -Compress
|
|
2700
3010
|
`;
|
|
2701
3011
|
const stdout = await this.runPowerShellEncoded(script, 30000);
|
|
2702
3012
|
return JSON.parse(stdout || '{}');
|
|
@@ -5202,8 +5512,8 @@ $proc = Get-Process -Id $pid -ErrorAction SilentlyContinue
|
|
|
5202
5512
|
requiresApplicationConfirmation(input) {
|
|
5203
5513
|
if (input.simulateOnly)
|
|
5204
5514
|
return false;
|
|
5205
|
-
if (input.action.startsWith('excel_')) {
|
|
5206
|
-
return ['excel_open_workbook', 'excel_set_cell', 'excel_save_workbook'].includes(input.action);
|
|
5515
|
+
if (input.action.startsWith('excel_') || input.action.startsWith('powerpoint_') || input.action.startsWith('word_')) {
|
|
5516
|
+
return ['excel_open_workbook', 'excel_set_cell', 'excel_save_workbook', 'powerpoint_open_presentation', 'powerpoint_add_slide', 'powerpoint_set_text', 'powerpoint_save_presentation', 'word_open_document', 'word_type_text', 'word_save_document'].includes(input.action);
|
|
5207
5517
|
}
|
|
5208
5518
|
if (input.action === 'save_app_document') {
|
|
5209
5519
|
return true;
|
|
@@ -5240,6 +5550,8 @@ $proc = Get-Process -Id $pid -ErrorAction SilentlyContinue
|
|
|
5240
5550
|
'set_slider_value', 'select_tree_item', 'expand_tree_item', 'collapse_tree_item',
|
|
5241
5551
|
'click_dialog_button', 'handle_dialog',
|
|
5242
5552
|
'open_app', 'focus_app', 'save_app_document', 'excel_open_workbook', 'excel_set_cell', 'excel_save_workbook',
|
|
5553
|
+
'powerpoint_open_presentation', 'powerpoint_add_slide', 'powerpoint_set_text', 'powerpoint_save_presentation',
|
|
5554
|
+
'word_open_document', 'word_type_text', 'word_save_document',
|
|
5243
5555
|
'click', 'left_click', 'middle_click', 'double_click', 'right_click', 'move_mouse', 'drag', 'scroll',
|
|
5244
5556
|
'type', 'key', 'key_down', 'key_up', 'hotkey',
|
|
5245
5557
|
'focus_window', 'close_window', 'minimize_window', 'maximize_window', 'restore_window',
|
|
@@ -52,3 +52,17 @@ export declare function executeGenerateDocument(args: {
|
|
|
52
52
|
outputPath: string;
|
|
53
53
|
theme?: string;
|
|
54
54
|
}): Promise<ToolResult>;
|
|
55
|
+
/**
|
|
56
|
+
* Streaming variant of {@link executeGenerateDocument}: identical output, but
|
|
57
|
+
* yields the build phases (prepare → parse → build → write → verify → done) as
|
|
58
|
+
* they happen so a host UI (e.g. the Cowork trace panel) can show the steps
|
|
59
|
+
* unfold one by one instead of a single opaque "Created X" at the end. Used by
|
|
60
|
+
* the tool-handler streaming path (`STREAMING_TOOLS`).
|
|
61
|
+
*/
|
|
62
|
+
export declare function executeGenerateDocumentStreaming(args: {
|
|
63
|
+
type: string;
|
|
64
|
+
title: string;
|
|
65
|
+
content: string;
|
|
66
|
+
outputPath: string;
|
|
67
|
+
theme?: string;
|
|
68
|
+
}): AsyncGenerator<string, ToolResult, undefined>;
|
|
@@ -649,4 +649,83 @@ export async function executeGenerateDocument(args) {
|
|
|
649
649
|
},
|
|
650
650
|
};
|
|
651
651
|
}
|
|
652
|
+
/**
|
|
653
|
+
* Streaming variant of {@link executeGenerateDocument}: identical output, but
|
|
654
|
+
* yields the build phases (prepare → parse → build → write → verify → done) as
|
|
655
|
+
* they happen so a host UI (e.g. the Cowork trace panel) can show the steps
|
|
656
|
+
* unfold one by one instead of a single opaque "Created X" at the end. Used by
|
|
657
|
+
* the tool-handler streaming path (`STREAMING_TOOLS`).
|
|
658
|
+
*/
|
|
659
|
+
export async function* executeGenerateDocumentStreaming(args) {
|
|
660
|
+
const type = args.type;
|
|
661
|
+
const { title, content, outputPath, theme } = args;
|
|
662
|
+
const file = path.basename(outputPath);
|
|
663
|
+
const label = type.toUpperCase();
|
|
664
|
+
try {
|
|
665
|
+
const expectedExt = expectedExtensionForType(type);
|
|
666
|
+
if (path.extname(outputPath).toLowerCase() !== expectedExt) {
|
|
667
|
+
return { success: false, error: `outputPath must end with ${expectedExt} for ${label} documents` };
|
|
668
|
+
}
|
|
669
|
+
yield `📄 Preparing ${label} "${title}"…\n`;
|
|
670
|
+
const outDir = path.dirname(path.resolve(outputPath));
|
|
671
|
+
if (!fs.existsSync(outDir))
|
|
672
|
+
fs.mkdirSync(outDir, { recursive: true });
|
|
673
|
+
yield `📑 Parsing content…\n`;
|
|
674
|
+
const sections = parseMarkdownSections(content);
|
|
675
|
+
yield ` parsed ${sections.length} section(s)\n`;
|
|
676
|
+
const buildLabel = type === 'pptx' ? `Building ${sections.length + 1} slide(s)`
|
|
677
|
+
: type === 'xlsx' ? 'Building spreadsheet'
|
|
678
|
+
: type === 'docx' ? 'Building document'
|
|
679
|
+
: 'Rendering pages';
|
|
680
|
+
yield `🧩 ${buildLabel}…\n`;
|
|
681
|
+
let embeddedImages;
|
|
682
|
+
let rowCount = 0;
|
|
683
|
+
switch (type) {
|
|
684
|
+
case 'pptx':
|
|
685
|
+
await generatePptx(title, sections, outputPath, theme);
|
|
686
|
+
break;
|
|
687
|
+
case 'docx':
|
|
688
|
+
embeddedImages = await generateDocx(title, sections, outputPath);
|
|
689
|
+
break;
|
|
690
|
+
case 'xlsx':
|
|
691
|
+
rowCount = await generateXlsx(title, content, outputPath);
|
|
692
|
+
break;
|
|
693
|
+
case 'pdf':
|
|
694
|
+
await generatePdf(title, sections, outputPath);
|
|
695
|
+
break;
|
|
696
|
+
default: return { success: false, error: `Unknown document type: ${type}` };
|
|
697
|
+
}
|
|
698
|
+
yield `💾 Wrote ${file}\n`;
|
|
699
|
+
yield `✅ Verifying…\n`;
|
|
700
|
+
const docxValidation = type === 'docx' ? await validateDocxPackage(outputPath) : undefined;
|
|
701
|
+
const sizeKb = fs.existsSync(outputPath)
|
|
702
|
+
? Math.max(1, Math.round(fs.statSync(outputPath).size / 1024))
|
|
703
|
+
: 0;
|
|
704
|
+
logger.info(`Document generated (streaming): ${outputPath} (${type})`);
|
|
705
|
+
yield `✓ Created ${file} (${sizeKb} KB)\n`;
|
|
706
|
+
const embImgs = embeddedImages ?? [];
|
|
707
|
+
const embeddedImageLines = embImgs.length > 0
|
|
708
|
+
? ['Embedded images:', ...embImgs.map((i) => `- ${i.path}${i.caption ? ` (${i.caption})` : ''} [${i.width}x${i.height}]`)]
|
|
709
|
+
: [];
|
|
710
|
+
const validationLines = docxValidation
|
|
711
|
+
? [
|
|
712
|
+
'DOCX validation:',
|
|
713
|
+
`- relationships: ${docxValidation.relationshipCount}`,
|
|
714
|
+
`- embedded image relationships: ${docxValidation.embeddedRelationshipCount}`,
|
|
715
|
+
`- media files: ${docxValidation.mediaFileCount}`,
|
|
716
|
+
]
|
|
717
|
+
: [];
|
|
718
|
+
const xlsxLine = type === 'xlsx' ? [`Rows: ${rowCount}`] : [];
|
|
719
|
+
return {
|
|
720
|
+
success: true,
|
|
721
|
+
output: [`Created ${label}: ${outputPath}`, ...xlsxLine, ...embeddedImageLines, ...validationLines].join('\n'),
|
|
722
|
+
data: { outputPath, embeddedImages: embImgs, ...(docxValidation ? { docxValidation } : {}) },
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
catch (err) {
|
|
726
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
727
|
+
logger.error('Document generation (streaming) failed', { error: msg });
|
|
728
|
+
return { success: false, error: `Document generation failed: ${msg}` };
|
|
729
|
+
}
|
|
730
|
+
}
|
|
652
731
|
//# sourceMappingURL=document-generator.js.map
|
|
@@ -17,9 +17,17 @@
|
|
|
17
17
|
* override via env `CODEBUDDY_EXECUTE_CODE_TOOL_RPC_ALLOWLIST` (csv).
|
|
18
18
|
* 3. **fleetSafe** — the tool's registry metadata must declare
|
|
19
19
|
* `fleetSafe: true` (read-only by definition).
|
|
20
|
+
* 4. **Per-tool opt-in** — `CODEBUDDY_EXECUTE_CODE_RPC_TOOLS` (csv)
|
|
21
|
+
* adds specific executor-backed tools to the allowlist. These tools
|
|
22
|
+
* bypass the `fleetSafe` gate since they are explicitly opted in by the
|
|
23
|
+
* operator. Each tool name is validated against both the registry and
|
|
24
|
+
* this module's executor table; unknown or unsupported names are logged
|
|
25
|
+
* and skipped.
|
|
20
26
|
*
|
|
21
|
-
* No write/exec tool is reachable; the executors
|
|
22
|
-
* read.
|
|
27
|
+
* No write/exec tool is reachable by default; the default executors
|
|
28
|
+
* below physically only read. Tools added via RPC_TOOLS opt-in are the
|
|
29
|
+
* operator's responsibility. This mirrors the audited
|
|
30
|
+
* `peer-tool-bridge.ts` pattern.
|
|
23
31
|
*/
|
|
24
32
|
export interface ExecuteCodeRpcInvokeRequest {
|
|
25
33
|
tool: string;
|
|
@@ -35,11 +43,27 @@ export type ExecuteCodeRpcInvoker = (request: ExecuteCodeRpcInvokeRequest) => Pr
|
|
|
35
43
|
/** Truthy-flag parse — the single master gate. Read once, in the parent. */
|
|
36
44
|
export declare function isExecuteCodeToolRpcEnabled(raw?: string | undefined): boolean;
|
|
37
45
|
export declare function getExecuteCodeToolRpcAllowlist(raw?: string | undefined): Set<string>;
|
|
46
|
+
/**
|
|
47
|
+
* Parse `CODEBUDDY_EXECUTE_CODE_RPC_TOOLS` — a csv of additional tool names
|
|
48
|
+
* to add to the RPC allowlist. Each name is validated against the registry
|
|
49
|
+
* and this module's executor table; unknown or unsupported names are logged
|
|
50
|
+
* as warnings and silently skipped so a typo never opens an unintended tool.
|
|
51
|
+
*
|
|
52
|
+
* Tools listed here bypass the `fleetSafe` gate because the operator
|
|
53
|
+
* explicitly opted them in — requiring `fleetSafe: true` would defeat
|
|
54
|
+
* the purpose of this escape hatch.
|
|
55
|
+
*/
|
|
56
|
+
export declare function getExecuteCodeRpcExtraTools(raw?: string | undefined, isRegistered?: (name: string) => boolean, hasExecutor?: (name: string) => boolean): Set<string>;
|
|
38
57
|
interface InvokerOptions {
|
|
39
58
|
/** Root the read-only executors are confined to. Defaults to cwd. */
|
|
40
59
|
workspaceRoot: string;
|
|
41
60
|
allowlist?: Set<string>;
|
|
42
61
|
isFleetSafe?: (name: string) => boolean;
|
|
62
|
+
/**
|
|
63
|
+
* Additional tools to allow through RPC, bypassing the fleetSafe gate.
|
|
64
|
+
* Parsed from `CODEBUDDY_EXECUTE_CODE_RPC_TOOLS` by default.
|
|
65
|
+
*/
|
|
66
|
+
extraTools?: Set<string>;
|
|
43
67
|
}
|
|
44
68
|
/**
|
|
45
69
|
* Build the policy-gated invoker. The master flag is intentionally NOT
|
|
@@ -17,9 +17,17 @@
|
|
|
17
17
|
* override via env `CODEBUDDY_EXECUTE_CODE_TOOL_RPC_ALLOWLIST` (csv).
|
|
18
18
|
* 3. **fleetSafe** — the tool's registry metadata must declare
|
|
19
19
|
* `fleetSafe: true` (read-only by definition).
|
|
20
|
+
* 4. **Per-tool opt-in** — `CODEBUDDY_EXECUTE_CODE_RPC_TOOLS` (csv)
|
|
21
|
+
* adds specific executor-backed tools to the allowlist. These tools
|
|
22
|
+
* bypass the `fleetSafe` gate since they are explicitly opted in by the
|
|
23
|
+
* operator. Each tool name is validated against both the registry and
|
|
24
|
+
* this module's executor table; unknown or unsupported names are logged
|
|
25
|
+
* and skipped.
|
|
20
26
|
*
|
|
21
|
-
* No write/exec tool is reachable; the executors
|
|
22
|
-
* read.
|
|
27
|
+
* No write/exec tool is reachable by default; the default executors
|
|
28
|
+
* below physically only read. Tools added via RPC_TOOLS opt-in are the
|
|
29
|
+
* operator's responsibility. This mirrors the audited
|
|
30
|
+
* `peer-tool-bridge.ts` pattern.
|
|
23
31
|
*/
|
|
24
32
|
import { spawn } from 'child_process';
|
|
25
33
|
import { rgPath } from '@vscode/ripgrep';
|
|
@@ -28,6 +36,7 @@ import * as path from 'path';
|
|
|
28
36
|
import { logger } from '../utils/logger.js';
|
|
29
37
|
import { getToolRegistry } from './registry.js';
|
|
30
38
|
const DEFAULT_ALLOWLIST = ['view_file', 'list_directory', 'search'];
|
|
39
|
+
const EXECUTOR_TOOL_NAMES = new Set(DEFAULT_ALLOWLIST);
|
|
31
40
|
const READ_TRUNCATE_BYTES = 256 * 1024;
|
|
32
41
|
const LIST_DIRECTORY_MAX_ENTRIES = 256;
|
|
33
42
|
const SEARCH_TIMEOUT_MS = 30_000;
|
|
@@ -45,25 +54,57 @@ export function getExecuteCodeToolRpcAllowlist(raw = process.env.CODEBUDDY_EXECU
|
|
|
45
54
|
const items = raw.split(',').map((item) => item.trim()).filter(Boolean);
|
|
46
55
|
return items.length > 0 ? new Set(items) : new Set(DEFAULT_ALLOWLIST);
|
|
47
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Parse `CODEBUDDY_EXECUTE_CODE_RPC_TOOLS` — a csv of additional tool names
|
|
59
|
+
* to add to the RPC allowlist. Each name is validated against the registry
|
|
60
|
+
* and this module's executor table; unknown or unsupported names are logged
|
|
61
|
+
* as warnings and silently skipped so a typo never opens an unintended tool.
|
|
62
|
+
*
|
|
63
|
+
* Tools listed here bypass the `fleetSafe` gate because the operator
|
|
64
|
+
* explicitly opted them in — requiring `fleetSafe: true` would defeat
|
|
65
|
+
* the purpose of this escape hatch.
|
|
66
|
+
*/
|
|
67
|
+
export function getExecuteCodeRpcExtraTools(raw = process.env.CODEBUDDY_EXECUTE_CODE_RPC_TOOLS, isRegistered = (name) => !!getToolRegistry().getTool(name), hasExecutor = (name) => EXECUTOR_TOOL_NAMES.has(name)) {
|
|
68
|
+
if (!raw)
|
|
69
|
+
return new Set();
|
|
70
|
+
const items = raw.split(',').map((item) => item.trim()).filter(Boolean);
|
|
71
|
+
const validated = new Set();
|
|
72
|
+
for (const name of items) {
|
|
73
|
+
if (!isRegistered(name)) {
|
|
74
|
+
logger.warn('[execute-code-rpc] CODEBUDDY_EXECUTE_CODE_RPC_TOOLS: unknown tool, skipping', { tool: name });
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
if (!hasExecutor(name)) {
|
|
78
|
+
logger.warn('[execute-code-rpc] CODEBUDDY_EXECUTE_CODE_RPC_TOOLS: tool has no execute_code RPC executor, skipping', { tool: name });
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
validated.add(name);
|
|
82
|
+
}
|
|
83
|
+
return validated;
|
|
84
|
+
}
|
|
48
85
|
/**
|
|
49
86
|
* Build the policy-gated invoker. The master flag is intentionally NOT
|
|
50
87
|
* read here — the runner only constructs an invoker once it has already
|
|
51
88
|
* decided RPC is enabled, keeping the flag boundary in the parent.
|
|
52
89
|
*/
|
|
53
90
|
export function createExecuteCodeRpcInvoker(options) {
|
|
54
|
-
const
|
|
91
|
+
const baseAllowlist = options.allowlist ?? getExecuteCodeToolRpcAllowlist();
|
|
92
|
+
const extraTools = options.extraTools ?? getExecuteCodeRpcExtraTools();
|
|
93
|
+
const combinedAllowlist = new Set([...baseAllowlist, ...extraTools]);
|
|
55
94
|
const isFleetSafe = options.isFleetSafe ?? ((name) => getToolRegistry().isFleetSafe(name));
|
|
56
95
|
const workspaceRoot = path.resolve(options.workspaceRoot);
|
|
57
96
|
return async (request) => {
|
|
58
97
|
const tool = request.tool;
|
|
59
98
|
try {
|
|
60
|
-
if (!
|
|
99
|
+
if (!combinedAllowlist.has(tool)) {
|
|
61
100
|
return {
|
|
62
101
|
ok: false,
|
|
63
102
|
error: `TOOL_NOT_ALLOWED_FOR_EXECUTE_CODE_RPC: tool "${tool}" is not in the execute_code RPC allowlist`,
|
|
64
103
|
};
|
|
65
104
|
}
|
|
66
|
-
|
|
105
|
+
// Tools explicitly opted in via CODEBUDDY_EXECUTE_CODE_RPC_TOOLS
|
|
106
|
+
// bypass the fleetSafe gate — the operator accepted responsibility.
|
|
107
|
+
if (!extraTools.has(tool) && !isFleetSafe(tool)) {
|
|
67
108
|
return {
|
|
68
109
|
ok: false,
|
|
69
110
|
error: `TOOL_NOT_FLEET_SAFE: tool "${tool}" lacks fleetSafe metadata`,
|