@phuetz/code-buddy 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +160 -164
- package/dist/agent/autonomous/agentic-coding-contract.d.ts +6 -6
- package/dist/agent/codebuddy-agent.d.ts +1 -1
- package/dist/agent/codebuddy-agent.js +101 -13
- 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/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/lesson-auto-proposer.js +10 -0
- package/dist/agent/middleware/index.d.ts +1 -0
- package/dist/agent/middleware/index.js +1 -0
- package/dist/agent/middleware/session-duration.d.ts +36 -0
- package/dist/agent/middleware/session-duration.js +78 -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/session-end-flush.d.ts +71 -0
- package/dist/agent/session-end-flush.js +233 -0
- 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 +130 -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 +1 -0
- 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 +1 -1
- package/dist/codebuddy/tools.js +27 -24
- package/dist/commands/cli/hermes-commands.js +108 -0
- package/dist/commands/cli/native-engine-commands.js +107 -3
- package/dist/commands/cli/utility-commands.js +45 -0
- package/dist/commands/enhanced-command-handler.js +5 -0
- package/dist/commands/goal-cli.d.ts +71 -0
- package/dist/commands/goal-cli.js +280 -0
- package/dist/commands/handlers/goal-handler.d.ts +34 -0
- package/dist/commands/handlers/goal-handler.js +155 -0
- package/dist/commands/handlers/index.d.ts +1 -0
- package/dist/commands/handlers/index.js +2 -0
- package/dist/commands/handlers/infra-handlers.js +36 -0
- package/dist/commands/handlers/memory-handlers.js +96 -1
- 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/slash/builtin-commands.js +20 -0
- 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/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 +770 -0
- package/dist/config/feature-flags.js +7 -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/context-manager-v2.d.ts +39 -0
- package/dist/context/context-manager-v2.js +91 -0
- package/dist/daemon/agent-task-executor.js +12 -1
- package/dist/daemon/autonomous-daemon.d.ts +1 -1
- package/dist/daemon/autonomous-daemon.js +5 -3
- package/dist/daemon/autonomous-loop.d.ts +21 -1
- package/dist/daemon/autonomous-loop.js +69 -0
- package/dist/daemon/colab-goal.d.ts +38 -0
- package/dist/daemon/colab-goal.js +81 -0
- 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.d.ts +21 -0
- package/dist/fleet/colab-store.js +28 -0
- package/dist/fleet/peer-session-bridge.d.ts +1 -1
- package/dist/fleet/peer-session-bridge.js +243 -2
- package/dist/fleet/peer-session-store.d.ts +3 -0
- package/dist/fleet/peer-tool-bridge.js +14 -0
- package/dist/fleet/privacy-lint.d.ts +8 -0
- package/dist/fleet/privacy-lint.js +22 -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 +38 -0
- package/dist/goals/goal-judge.js +158 -0
- package/dist/goals/goal-loop.d.ts +37 -0
- package/dist/goals/goal-loop.js +101 -0
- package/dist/goals/goal-manager.d.ts +77 -0
- package/dist/goals/goal-manager.js +289 -0
- package/dist/goals/goal-state.d.ts +99 -0
- package/dist/goals/goal-state.js +315 -0
- package/dist/goals/goal-store.d.ts +28 -0
- package/dist/goals/goal-store.js +87 -0
- package/dist/goals/index.d.ts +5 -0
- package/dist/goals/index.js +6 -0
- package/dist/hooks/use-input-handler.js +36 -1
- package/dist/hooks/user-hooks.js +17 -3
- package/dist/index.js +506 -25
- 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-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/observability/run-store.d.ts +1 -1
- 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/server/index.js +17 -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.d.ts +13 -1
- package/dist/server/websocket/fleet-bridge.js +16 -0
- package/dist/services/prompt-builder.d.ts +1 -0
- package/dist/services/prompt-builder.js +49 -8
- 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/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/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/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/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 +7 -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
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { EventEmitter } from 'events';
|
|
2
2
|
export interface TTSConfig {
|
|
3
3
|
enabled: boolean;
|
|
4
|
-
provider: 'edge-tts' | 'espeak' | 'say' | 'piper' | 'audioreader'
|
|
4
|
+
provider: 'edge-tts' | 'espeak' | 'say' | 'piper' | 'audioreader';
|
|
5
5
|
voice?: string;
|
|
6
6
|
rate?: string;
|
|
7
7
|
volume?: string;
|
|
@@ -62,13 +62,9 @@ export declare class TextToSpeechManager extends EventEmitter {
|
|
|
62
62
|
*/
|
|
63
63
|
private speakWithPiper;
|
|
64
64
|
/**
|
|
65
|
-
* Speak with AudioReader
|
|
65
|
+
* Speak with AudioReader via local API
|
|
66
66
|
*/
|
|
67
67
|
private speakWithAudioReader;
|
|
68
|
-
/**
|
|
69
|
-
* Speak with local Kokoro TTS model (quantized ONNX hexgrad/Kokoro-82M)
|
|
70
|
-
*/
|
|
71
|
-
private speakWithKokoro;
|
|
72
68
|
/**
|
|
73
69
|
* Play audio file using available player
|
|
74
70
|
*/
|
|
@@ -80,9 +80,6 @@ export class TextToSpeechManager extends EventEmitter {
|
|
|
80
80
|
* Check if TTS is available
|
|
81
81
|
*/
|
|
82
82
|
async isAvailable() {
|
|
83
|
-
if (this.config.provider === 'kokoro') {
|
|
84
|
-
return { available: true };
|
|
85
|
-
}
|
|
86
83
|
// AudioReader uses HTTP API, not a CLI binary
|
|
87
84
|
if (this.config.provider === 'audioreader') {
|
|
88
85
|
try {
|
|
@@ -166,9 +163,6 @@ export class TextToSpeechManager extends EventEmitter {
|
|
|
166
163
|
case 'audioreader':
|
|
167
164
|
await this.speakWithAudioReader(text);
|
|
168
165
|
break;
|
|
169
|
-
case 'kokoro':
|
|
170
|
-
await this.speakWithKokoro(text);
|
|
171
|
-
break;
|
|
172
166
|
default:
|
|
173
167
|
await this.speakWithEdgeTTS(text, language);
|
|
174
168
|
}
|
|
@@ -303,7 +297,7 @@ export class TextToSpeechManager extends EventEmitter {
|
|
|
303
297
|
});
|
|
304
298
|
}
|
|
305
299
|
/**
|
|
306
|
-
* Speak with AudioReader
|
|
300
|
+
* Speak with AudioReader via local API
|
|
307
301
|
*/
|
|
308
302
|
async speakWithAudioReader(text) {
|
|
309
303
|
const voice = this.config.voice || 'ff_siwis';
|
|
@@ -311,7 +305,7 @@ export class TextToSpeechManager extends EventEmitter {
|
|
|
311
305
|
method: 'POST',
|
|
312
306
|
headers: { 'Content-Type': 'application/json' },
|
|
313
307
|
body: JSON.stringify({
|
|
314
|
-
model: '
|
|
308
|
+
model: 'audioreader',
|
|
315
309
|
input: text,
|
|
316
310
|
voice,
|
|
317
311
|
speed: 1.0,
|
|
@@ -334,25 +328,6 @@ export class TextToSpeechManager extends EventEmitter {
|
|
|
334
328
|
catch { /* ignore */ }
|
|
335
329
|
}
|
|
336
330
|
}
|
|
337
|
-
/**
|
|
338
|
-
* Speak with local Kokoro TTS model (quantized ONNX hexgrad/Kokoro-82M)
|
|
339
|
-
*/
|
|
340
|
-
async speakWithKokoro(text) {
|
|
341
|
-
const { kokoroTtsService } = await import('../utils/kokoro-tts.js');
|
|
342
|
-
const voice = this.config.voice || 'af_bella';
|
|
343
|
-
const buffer = await kokoroTtsService.generateSpeech(text, voice);
|
|
344
|
-
const audioFile = path.join(this.tempDir, `tts_${Date.now()}.wav`);
|
|
345
|
-
fs.writeFileSync(audioFile, buffer);
|
|
346
|
-
try {
|
|
347
|
-
await this.playAudio(audioFile);
|
|
348
|
-
}
|
|
349
|
-
finally {
|
|
350
|
-
try {
|
|
351
|
-
fs.unlinkSync(audioFile);
|
|
352
|
-
}
|
|
353
|
-
catch { /* ignore */ }
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
331
|
/**
|
|
357
332
|
* Play audio file using available player
|
|
358
333
|
*/
|
|
@@ -7,6 +7,11 @@
|
|
|
7
7
|
* say / hear?" from screen+audio history — local-first, no cloud. Base URL is
|
|
8
8
|
* configurable via `SCREENPIPE_URL` (default http://localhost:3030).
|
|
9
9
|
*
|
|
10
|
+
* Recent screenpipe builds require a Bearer token on the local API. Pass it via
|
|
11
|
+
* `apiKey` (or `SCREENPIPE_API_KEY`) and it is attached as `Authorization:
|
|
12
|
+
* Bearer <key>` to every request. When unset, requests are sent unauthenticated
|
|
13
|
+
* exactly as before, so local no-auth instances keep working.
|
|
14
|
+
*
|
|
10
15
|
* `fetchImpl` is injectable for tests.
|
|
11
16
|
*/
|
|
12
17
|
export type ScreenpipeContentType = 'all' | 'ocr' | 'audio' | 'ui';
|
|
@@ -37,6 +42,7 @@ export interface ScreenpipeSearchResult {
|
|
|
37
42
|
type FetchLike = (url: string, init?: {
|
|
38
43
|
method?: string;
|
|
39
44
|
signal?: AbortSignal;
|
|
45
|
+
headers?: Record<string, string>;
|
|
40
46
|
}) => Promise<{
|
|
41
47
|
ok: boolean;
|
|
42
48
|
status: number;
|
|
@@ -45,10 +51,14 @@ type FetchLike = (url: string, init?: {
|
|
|
45
51
|
export declare class ScreenpipeClient {
|
|
46
52
|
readonly baseUrl: string;
|
|
47
53
|
private readonly doFetch;
|
|
54
|
+
private readonly apiKey?;
|
|
48
55
|
constructor(opts?: {
|
|
49
56
|
baseUrl?: string;
|
|
50
57
|
fetchImpl?: FetchLike;
|
|
58
|
+
apiKey?: string;
|
|
51
59
|
});
|
|
60
|
+
/** Build request headers, attaching Bearer auth when an API key is configured. */
|
|
61
|
+
private buildHeaders;
|
|
52
62
|
/** True if a screenpipe server answers on the health endpoint. */
|
|
53
63
|
health(timeoutMs?: number): Promise<boolean>;
|
|
54
64
|
/** Search captured screen/audio content. */
|
|
@@ -1,14 +1,23 @@
|
|
|
1
1
|
export class ScreenpipeClient {
|
|
2
2
|
baseUrl;
|
|
3
3
|
doFetch;
|
|
4
|
+
apiKey;
|
|
4
5
|
constructor(opts = {}) {
|
|
5
6
|
this.baseUrl = (opts.baseUrl || process.env['SCREENPIPE_URL'] || 'http://localhost:3030').replace(/\/$/, '');
|
|
6
7
|
this.doFetch = opts.fetchImpl ?? globalThis.fetch;
|
|
8
|
+
const apiKey = opts.apiKey ?? process.env['SCREENPIPE_API_KEY'];
|
|
9
|
+
if (apiKey)
|
|
10
|
+
this.apiKey = apiKey;
|
|
11
|
+
}
|
|
12
|
+
/** Build request headers, attaching Bearer auth when an API key is configured. */
|
|
13
|
+
buildHeaders() {
|
|
14
|
+
return this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : undefined;
|
|
7
15
|
}
|
|
8
16
|
/** True if a screenpipe server answers on the health endpoint. */
|
|
9
17
|
async health(timeoutMs = 2500) {
|
|
10
18
|
try {
|
|
11
|
-
const
|
|
19
|
+
const headers = this.buildHeaders();
|
|
20
|
+
const res = await this.withTimeout((signal) => this.doFetch(`${this.baseUrl}/health`, { signal, ...(headers ? { headers } : {}) }), timeoutMs);
|
|
12
21
|
return res.ok;
|
|
13
22
|
}
|
|
14
23
|
catch {
|
|
@@ -33,7 +42,8 @@ export class ScreenpipeClient {
|
|
|
33
42
|
if (opts.endTime)
|
|
34
43
|
params.set('end_time', opts.endTime);
|
|
35
44
|
const url = `${this.baseUrl}/search?${params.toString()}`;
|
|
36
|
-
const
|
|
45
|
+
const headers = this.buildHeaders();
|
|
46
|
+
const res = await this.withTimeout((signal) => this.doFetch(url, { signal, ...(headers ? { headers } : {}) }), timeoutMs);
|
|
37
47
|
if (!res.ok) {
|
|
38
48
|
throw new Error(`screenpipe /search returned ${res.status}`);
|
|
39
49
|
}
|
|
@@ -32,6 +32,12 @@ export interface TailscaleStatus {
|
|
|
32
32
|
/** Tailscale version */
|
|
33
33
|
version: string;
|
|
34
34
|
}
|
|
35
|
+
export interface TailnetOllamaPeer {
|
|
36
|
+
hostname: string;
|
|
37
|
+
ip: string;
|
|
38
|
+
baseURL: string;
|
|
39
|
+
models: string[];
|
|
40
|
+
}
|
|
35
41
|
export declare class TailscaleManager {
|
|
36
42
|
private static instance;
|
|
37
43
|
private config;
|
|
@@ -47,6 +53,11 @@ export declare class TailscaleManager {
|
|
|
47
53
|
* Get live Tailscale status from the CLI.
|
|
48
54
|
*/
|
|
49
55
|
getStatus(): Promise<TailscaleStatus>;
|
|
56
|
+
/**
|
|
57
|
+
* Discover Ollama peers on the tailnet and return their OpenAI-compatible
|
|
58
|
+
* endpoints with the models they expose.
|
|
59
|
+
*/
|
|
60
|
+
discoverOllamaPeers(): Promise<TailnetOllamaPeer[]>;
|
|
50
61
|
/**
|
|
51
62
|
* Start Tailscale Serve (tailnet-only HTTPS).
|
|
52
63
|
*/
|
|
@@ -81,4 +92,6 @@ export declare class TailscaleManager {
|
|
|
81
92
|
generateAuthHeaders(): Record<string, string>;
|
|
82
93
|
getConfig(): TailscaleConfig | null;
|
|
83
94
|
setConfig(config: Partial<TailscaleConfig>): void;
|
|
95
|
+
private readStatusPayload;
|
|
96
|
+
private listOllamaModels;
|
|
84
97
|
}
|
|
@@ -47,8 +47,8 @@ export class TailscaleManager {
|
|
|
47
47
|
* Get live Tailscale status from the CLI.
|
|
48
48
|
*/
|
|
49
49
|
async getStatus() {
|
|
50
|
-
const
|
|
51
|
-
if (!
|
|
50
|
+
const payload = await this.readStatusPayload();
|
|
51
|
+
if (!payload) {
|
|
52
52
|
return {
|
|
53
53
|
installed: false,
|
|
54
54
|
running: false,
|
|
@@ -60,41 +60,51 @@ export class TailscaleManager {
|
|
|
60
60
|
version: '',
|
|
61
61
|
};
|
|
62
62
|
}
|
|
63
|
+
const status = {
|
|
64
|
+
installed: true,
|
|
65
|
+
running: !!payload.BackendState && payload.BackendState === 'Running',
|
|
66
|
+
hostname: payload.Self?.HostName || '',
|
|
67
|
+
tailnetName: payload.MagicDNSSuffix || payload.CurrentTailnet?.Name || '',
|
|
68
|
+
ip: payload.TailscaleIPs?.[0] || payload.Self?.TailscaleIPs?.[0] || '',
|
|
69
|
+
serving: this.serving,
|
|
70
|
+
serveUrl: this.getServeUrl(),
|
|
71
|
+
version: '',
|
|
72
|
+
};
|
|
73
|
+
// Get version separately (status --json doesn't always include it)
|
|
63
74
|
try {
|
|
64
|
-
const { stdout } = await execFileAsync('tailscale', ['
|
|
65
|
-
|
|
66
|
-
const status = {
|
|
67
|
-
installed: true,
|
|
68
|
-
running: !!data.BackendState && data.BackendState === 'Running',
|
|
69
|
-
hostname: data.Self?.HostName || '',
|
|
70
|
-
tailnetName: data.MagicDNSSuffix || data.CurrentTailnet?.Name || '',
|
|
71
|
-
ip: data.TailscaleIPs?.[0] || data.Self?.TailscaleIPs?.[0] || '',
|
|
72
|
-
serving: this.serving,
|
|
73
|
-
serveUrl: this.getServeUrl(),
|
|
74
|
-
version: '',
|
|
75
|
-
};
|
|
76
|
-
// Get version separately (status --json doesn't always include it)
|
|
77
|
-
try {
|
|
78
|
-
const { stdout: ver } = await execFileAsync('tailscale', ['version'], { timeout: EXEC_TIMEOUT });
|
|
79
|
-
status.version = ver.trim().split('\n')[0] ?? '';
|
|
80
|
-
}
|
|
81
|
-
catch { /* non-critical */ }
|
|
82
|
-
this.cachedStatus = status;
|
|
83
|
-
return status;
|
|
75
|
+
const { stdout: ver } = await execFileAsync('tailscale', ['version'], { timeout: EXEC_TIMEOUT });
|
|
76
|
+
status.version = ver.trim().split('\n')[0] ?? '';
|
|
84
77
|
}
|
|
85
|
-
catch
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
78
|
+
catch { /* non-critical */ }
|
|
79
|
+
this.cachedStatus = status;
|
|
80
|
+
return status;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Discover Ollama peers on the tailnet and return their OpenAI-compatible
|
|
84
|
+
* endpoints with the models they expose.
|
|
85
|
+
*/
|
|
86
|
+
async discoverOllamaPeers() {
|
|
87
|
+
const payload = await this.readStatusPayload();
|
|
88
|
+
if (!payload)
|
|
89
|
+
return [];
|
|
90
|
+
const peers = payload.Peer ?? {};
|
|
91
|
+
const discovered = [];
|
|
92
|
+
for (const info of Object.values(peers)) {
|
|
93
|
+
if (!info?.Online)
|
|
94
|
+
continue;
|
|
95
|
+
const ip = info.TailscaleIPs?.[0]?.trim();
|
|
96
|
+
if (!ip)
|
|
97
|
+
continue;
|
|
98
|
+
const hostname = (info.HostName ?? info.DNSName ?? '').trim();
|
|
99
|
+
if (!hostname)
|
|
100
|
+
continue;
|
|
101
|
+
const baseURL = `http://${ip}:11434/v1`;
|
|
102
|
+
const models = await this.listOllamaModels(baseURL);
|
|
103
|
+
if (!models.length)
|
|
104
|
+
continue;
|
|
105
|
+
discovered.push({ hostname, ip, baseURL, models });
|
|
97
106
|
}
|
|
107
|
+
return discovered;
|
|
98
108
|
}
|
|
99
109
|
/**
|
|
100
110
|
* Start Tailscale Serve (tailnet-only HTTPS).
|
|
@@ -250,5 +260,48 @@ export class TailscaleManager {
|
|
|
250
260
|
};
|
|
251
261
|
}
|
|
252
262
|
}
|
|
263
|
+
async readStatusPayload() {
|
|
264
|
+
const installed = await this.isInstalled();
|
|
265
|
+
if (!installed)
|
|
266
|
+
return null;
|
|
267
|
+
try {
|
|
268
|
+
const { stdout } = await execFileAsync('tailscale', ['status', '--json'], { timeout: EXEC_TIMEOUT });
|
|
269
|
+
return JSON.parse(stdout);
|
|
270
|
+
}
|
|
271
|
+
catch (err) {
|
|
272
|
+
logger.debug(`Tailscale status failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
async listOllamaModels(baseURL) {
|
|
277
|
+
const probeUrls = [`${baseURL}/models`, `${baseURL.replace(/\/v1$/, '')}/api/tags`];
|
|
278
|
+
for (const url of probeUrls) {
|
|
279
|
+
try {
|
|
280
|
+
const response = await fetch(url, { signal: AbortSignal.timeout(8_000) });
|
|
281
|
+
if (!response.ok)
|
|
282
|
+
continue;
|
|
283
|
+
const json = await response.json();
|
|
284
|
+
const ids = (json.data ?? json.models ?? [])
|
|
285
|
+
.map((item) => {
|
|
286
|
+
const record = item;
|
|
287
|
+
const id = typeof record.id === 'string'
|
|
288
|
+
? record.id.trim()
|
|
289
|
+
: typeof record.model === 'string'
|
|
290
|
+
? record.model.trim()
|
|
291
|
+
: typeof record.name === 'string'
|
|
292
|
+
? record.name.trim()
|
|
293
|
+
: '';
|
|
294
|
+
return id || null;
|
|
295
|
+
})
|
|
296
|
+
.filter((value) => Boolean(value));
|
|
297
|
+
if (ids.length > 0)
|
|
298
|
+
return ids;
|
|
299
|
+
}
|
|
300
|
+
catch {
|
|
301
|
+
// try next probe
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return [];
|
|
305
|
+
}
|
|
253
306
|
}
|
|
254
307
|
//# sourceMappingURL=tailscale.js.map
|
|
@@ -52,6 +52,9 @@ class BruteForceIndex {
|
|
|
52
52
|
this.vectors = new Map(data);
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
|
+
remove(id) {
|
|
56
|
+
this.vectors.delete(id);
|
|
57
|
+
}
|
|
55
58
|
}
|
|
56
59
|
const DEFAULT_CONFIG = {
|
|
57
60
|
workspaceRoot: process.cwd(),
|
|
@@ -132,17 +135,57 @@ export class WorkspaceIndexer extends EventEmitter {
|
|
|
132
135
|
ignore: this.config.ignorePatterns,
|
|
133
136
|
absolute: false,
|
|
134
137
|
});
|
|
138
|
+
const mtimeCachePath = path.join(path.dirname(this.config.indexPath), 'mtimes.json');
|
|
139
|
+
let mtimeCache = {};
|
|
140
|
+
try {
|
|
141
|
+
if (fs.existsSync(mtimeCachePath)) {
|
|
142
|
+
mtimeCache = JSON.parse(await fs.readFile(mtimeCachePath, 'utf-8'));
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch (e) {
|
|
146
|
+
logger.warn('Failed to load mtime cache, starting fresh.');
|
|
147
|
+
}
|
|
148
|
+
const newMtimeCache = {};
|
|
149
|
+
const filesToIndex = [];
|
|
150
|
+
const currentFiles = new Set(files);
|
|
151
|
+
for (const file of files) {
|
|
152
|
+
const fullPath = path.join(this.config.workspaceRoot, file);
|
|
153
|
+
try {
|
|
154
|
+
const stats = await fs.promises.stat(fullPath);
|
|
155
|
+
newMtimeCache[file] = stats.mtimeMs;
|
|
156
|
+
if (mtimeCache[file] !== stats.mtimeMs) {
|
|
157
|
+
filesToIndex.push(file);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
catch (err) {
|
|
161
|
+
// Can't stat, skip
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const filesToRemove = new Set();
|
|
165
|
+
for (const file of filesToIndex) {
|
|
166
|
+
filesToRemove.add(file);
|
|
167
|
+
}
|
|
168
|
+
for (const entry of this.entries.values()) {
|
|
169
|
+
if (!currentFiles.has(entry.filePath)) {
|
|
170
|
+
filesToRemove.add(entry.filePath);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
if (filesToRemove.size > 0) {
|
|
174
|
+
for (const [id, entry] of this.entries.entries()) {
|
|
175
|
+
if (filesToRemove.has(entry.filePath)) {
|
|
176
|
+
this.entries.delete(id);
|
|
177
|
+
if (this.vectorIndex instanceof BruteForceIndex) {
|
|
178
|
+
this.vectorIndex.remove(id);
|
|
179
|
+
}
|
|
180
|
+
else if (this.vectorIndex && this.vectorIndex.remove) {
|
|
181
|
+
this.vectorIndex.remove(String(id));
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
135
186
|
let processedFiles = 0;
|
|
136
187
|
let totalChunks = 0;
|
|
137
|
-
|
|
138
|
-
// For this PoC, we rebuild the index.
|
|
139
|
-
this.entries.clear();
|
|
140
|
-
this.nextId = 0;
|
|
141
|
-
if (this.vectorIndex.clear)
|
|
142
|
-
this.vectorIndex.clear();
|
|
143
|
-
else if (this.vectorIndex instanceof BruteForceIndex)
|
|
144
|
-
this.vectorIndex = new BruteForceIndex(384);
|
|
145
|
-
for (const file of files) {
|
|
188
|
+
for (const file of filesToIndex) {
|
|
146
189
|
const fullPath = path.join(this.config.workspaceRoot, file);
|
|
147
190
|
try {
|
|
148
191
|
const content = await fs.readFile(fullPath, 'utf-8');
|
|
@@ -178,6 +221,7 @@ export class WorkspaceIndexer extends EventEmitter {
|
|
|
178
221
|
// Skip unreadable files
|
|
179
222
|
}
|
|
180
223
|
}
|
|
224
|
+
await fs.writeFile(mtimeCachePath, JSON.stringify(newMtimeCache, null, 2));
|
|
181
225
|
await this.saveIndexMetadata();
|
|
182
226
|
logger.info(`Workspace indexing complete: ${processedFiles} files, ${totalChunks} chunks.`);
|
|
183
227
|
this.emit('indexing:complete', { files: processedFiles, chunks: totalChunks });
|
package/dist/mcp/client.js
CHANGED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Desktop Tools — expose Code Buddy's desktop-automation over the MCP server.
|
|
3
|
+
*
|
|
4
|
+
* This is the cross-platform equivalent of mediar-ai's Terminator MCP agent, but
|
|
5
|
+
* backed by Code Buddy's own already-validated automation stack (nut-js input +
|
|
6
|
+
* AT-SPI/accessibility snapshots + screenshots), so it works on Linux/macOS/Windows
|
|
7
|
+
* without porting a Windows-only framework.
|
|
8
|
+
*
|
|
9
|
+
* Safety model (mirrors the peer.tool / execute_code RPC opt-in pattern):
|
|
10
|
+
* - Read-only tools are ALWAYS exposed: `desktop_screenshot`, `desktop_snapshot`.
|
|
11
|
+
* - Control tools that actuate the real desktop (`desktop_click`, `desktop_type`,
|
|
12
|
+
* `desktop_move_mouse`, `desktop_key`) are GATED behind
|
|
13
|
+
* CODEBUDDY_MCP_DESKTOP_CONTROL=1 (fail-closed: not registered when unset).
|
|
14
|
+
*/
|
|
15
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
16
|
+
/** Control tools actuate the real desktop — opt-in only. */
|
|
17
|
+
export declare function desktopControlEnabled(): boolean;
|
|
18
|
+
/** Reset the lazily-created manager (tests). */
|
|
19
|
+
export declare function resetDesktopMcpTools(): void;
|
|
20
|
+
/**
|
|
21
|
+
* Register desktop-automation tools with the MCP server.
|
|
22
|
+
*/
|
|
23
|
+
export declare function registerDesktopTools(server: McpServer): void;
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP Desktop Tools — expose Code Buddy's desktop-automation over the MCP server.
|
|
3
|
+
*
|
|
4
|
+
* This is the cross-platform equivalent of mediar-ai's Terminator MCP agent, but
|
|
5
|
+
* backed by Code Buddy's own already-validated automation stack (nut-js input +
|
|
6
|
+
* AT-SPI/accessibility snapshots + screenshots), so it works on Linux/macOS/Windows
|
|
7
|
+
* without porting a Windows-only framework.
|
|
8
|
+
*
|
|
9
|
+
* Safety model (mirrors the peer.tool / execute_code RPC opt-in pattern):
|
|
10
|
+
* - Read-only tools are ALWAYS exposed: `desktop_screenshot`, `desktop_snapshot`.
|
|
11
|
+
* - Control tools that actuate the real desktop (`desktop_click`, `desktop_type`,
|
|
12
|
+
* `desktop_move_mouse`, `desktop_key`) are GATED behind
|
|
13
|
+
* CODEBUDDY_MCP_DESKTOP_CONTROL=1 (fail-closed: not registered when unset).
|
|
14
|
+
*/
|
|
15
|
+
import { z } from 'zod';
|
|
16
|
+
import { logger } from '../utils/logger.js';
|
|
17
|
+
/** Control tools actuate the real desktop — opt-in only. */
|
|
18
|
+
export function desktopControlEnabled() {
|
|
19
|
+
const v = process.env['CODEBUDDY_MCP_DESKTOP_CONTROL'];
|
|
20
|
+
return v === '1' || v === 'true';
|
|
21
|
+
}
|
|
22
|
+
// Lazily initialize a single automation manager (native provider → mock fallback).
|
|
23
|
+
let managerPromise = null;
|
|
24
|
+
async function getManager() {
|
|
25
|
+
if (!managerPromise) {
|
|
26
|
+
managerPromise = (async () => {
|
|
27
|
+
const { getDesktopAutomation } = await import('../desktop-automation/index.js');
|
|
28
|
+
const mgr = getDesktopAutomation({ provider: 'native', fallbackProviders: ['nutjs', 'mock'] });
|
|
29
|
+
await mgr.initialize();
|
|
30
|
+
return mgr;
|
|
31
|
+
})().catch((err) => {
|
|
32
|
+
managerPromise = null; // allow retry on next call
|
|
33
|
+
throw err;
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
return managerPromise;
|
|
37
|
+
}
|
|
38
|
+
/** Reset the lazily-created manager (tests). */
|
|
39
|
+
export function resetDesktopMcpTools() {
|
|
40
|
+
managerPromise = null;
|
|
41
|
+
}
|
|
42
|
+
function ok(text) {
|
|
43
|
+
return { content: [{ type: 'text', text }] };
|
|
44
|
+
}
|
|
45
|
+
function fail(text) {
|
|
46
|
+
return { content: [{ type: 'text', text }], isError: true };
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Register desktop-automation tools with the MCP server.
|
|
50
|
+
*/
|
|
51
|
+
export function registerDesktopTools(server) {
|
|
52
|
+
// ---- Read-only: screenshot ------------------------------------------------
|
|
53
|
+
server.tool('desktop_screenshot', 'Capture a screenshot of the desktop (fullscreen by default, or a region). Returns the saved PNG path and dimensions. Read-only.', {
|
|
54
|
+
region: z
|
|
55
|
+
.object({ x: z.number(), y: z.number(), width: z.number(), height: z.number() })
|
|
56
|
+
.optional()
|
|
57
|
+
.describe('Optional region {x,y,width,height}; omit for fullscreen'),
|
|
58
|
+
output_path: z.string().optional().describe('Optional output PNG path'),
|
|
59
|
+
}, async (args) => {
|
|
60
|
+
try {
|
|
61
|
+
const { ScreenshotTool } = await import('../tools/screenshot-tool.js');
|
|
62
|
+
const tool = new ScreenshotTool();
|
|
63
|
+
const result = args.region
|
|
64
|
+
? await tool.captureRegion(args.region.x, args.region.y, args.region.width, args.region.height)
|
|
65
|
+
: await tool.capture({ fullscreen: true, ...(args.output_path ? { outputPath: args.output_path } : {}) });
|
|
66
|
+
if (!result.success)
|
|
67
|
+
return fail(`Screenshot failed: ${result.error ?? 'unknown error'}`);
|
|
68
|
+
return ok(result.output ?? JSON.stringify(result.data ?? {}, null, 2));
|
|
69
|
+
}
|
|
70
|
+
catch (err) {
|
|
71
|
+
return fail(`Screenshot error: ${err instanceof Error ? err.message : String(err)}`);
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
// ---- Read-only: accessibility snapshot -----------------------------------
|
|
75
|
+
server.tool('desktop_snapshot', 'Enumerate on-screen UI elements (accessibility tree) with numeric refs, roles, labels, and click coordinates. Read-only. Use the returned coordinates with desktop_click.', {
|
|
76
|
+
interactive_only: z.boolean().optional().describe('Only return interactive elements (buttons, inputs, links)'),
|
|
77
|
+
max_elements: z.number().optional().describe('Cap the number of elements returned (default 60, max 200)'),
|
|
78
|
+
window: z.string().optional().describe('Window title to scope to (default: whole desktop / focused window)'),
|
|
79
|
+
}, async (args) => {
|
|
80
|
+
try {
|
|
81
|
+
const { getSmartSnapshotManager } = await import('../desktop-automation/smart-snapshot.js');
|
|
82
|
+
const snap = await getSmartSnapshotManager().takeSnapshot({
|
|
83
|
+
...(args.interactive_only ? { interactiveOnly: true } : {}),
|
|
84
|
+
...(args.window ? { window: args.window } : {}),
|
|
85
|
+
});
|
|
86
|
+
const cap = Math.max(1, Math.min(200, args.max_elements ?? 60));
|
|
87
|
+
const shown = snap.elements.slice(0, cap);
|
|
88
|
+
const lines = shown.map((el) => `[${el.ref}] ${el.role} ${JSON.stringify(el.name)}${el.interactive ? ' (interactive)' : ''} @ ${Math.round(el.center.x)},${Math.round(el.center.y)} [${el.bounds.width}x${el.bounds.height}]`);
|
|
89
|
+
const header = `${snap.elements.length} element(s) on "${snap.source}" (${snap.screenSize.width}x${snap.screenSize.height}); showing ${shown.length}:`;
|
|
90
|
+
return ok(`${header}\n${lines.join('\n')}`);
|
|
91
|
+
}
|
|
92
|
+
catch (err) {
|
|
93
|
+
return fail(`Snapshot error: ${err instanceof Error ? err.message : String(err)}`);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
// ---- Control tools (opt-in, actuate the real desktop) --------------------
|
|
97
|
+
if (!desktopControlEnabled()) {
|
|
98
|
+
logger.debug('MCP desktop control tools disabled. Set CODEBUDDY_MCP_DESKTOP_CONTROL=1 to expose desktop_click/type/move_mouse/key.');
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
server.tool('desktop_click', 'Click the mouse at screen coordinates. Requires CODEBUDDY_MCP_DESKTOP_CONTROL=1. Actuates the real desktop.', {
|
|
102
|
+
x: z.number().describe('X coordinate'),
|
|
103
|
+
y: z.number().describe('Y coordinate'),
|
|
104
|
+
button: z.enum(['left', 'right', 'middle']).optional().describe('Mouse button (default left)'),
|
|
105
|
+
double: z.boolean().optional().describe('Double-click when true'),
|
|
106
|
+
}, async (args) => {
|
|
107
|
+
try {
|
|
108
|
+
const mgr = await getManager();
|
|
109
|
+
await mgr.click(args.x, args.y, {
|
|
110
|
+
...(args.button ? { button: args.button } : {}),
|
|
111
|
+
...(args.double ? { clicks: 2 } : {}),
|
|
112
|
+
});
|
|
113
|
+
return ok(`Clicked ${args.button ?? 'left'}${args.double ? ' (double)' : ''} at ${args.x},${args.y}.`);
|
|
114
|
+
}
|
|
115
|
+
catch (err) {
|
|
116
|
+
return fail(`Click error: ${err instanceof Error ? err.message : String(err)}`);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
server.tool('desktop_move_mouse', 'Move the mouse cursor to screen coordinates. Requires CODEBUDDY_MCP_DESKTOP_CONTROL=1.', { x: z.number().describe('X coordinate'), y: z.number().describe('Y coordinate') }, async (args) => {
|
|
120
|
+
try {
|
|
121
|
+
const mgr = await getManager();
|
|
122
|
+
await mgr.moveMouse(args.x, args.y);
|
|
123
|
+
return ok(`Moved mouse to ${args.x},${args.y}.`);
|
|
124
|
+
}
|
|
125
|
+
catch (err) {
|
|
126
|
+
return fail(`Move error: ${err instanceof Error ? err.message : String(err)}`);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
server.tool('desktop_type', 'Type text at the current focus. Requires CODEBUDDY_MCP_DESKTOP_CONTROL=1. Actuates the real keyboard.', { text: z.string().describe('Text to type') }, async (args) => {
|
|
130
|
+
try {
|
|
131
|
+
const mgr = await getManager();
|
|
132
|
+
await mgr.type(args.text);
|
|
133
|
+
return ok(`Typed ${args.text.length} character(s).`);
|
|
134
|
+
}
|
|
135
|
+
catch (err) {
|
|
136
|
+
return fail(`Type error: ${err instanceof Error ? err.message : String(err)}`);
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
server.tool('desktop_key', 'Press a key (optionally with modifiers), e.g. "enter", "escape", "tab", "f5". Requires CODEBUDDY_MCP_DESKTOP_CONTROL=1.', {
|
|
140
|
+
key: z.string().describe('Key name, e.g. enter, escape, tab, a, f5'),
|
|
141
|
+
modifiers: z
|
|
142
|
+
.array(z.enum(['ctrl', 'alt', 'shift', 'meta', 'cmd', 'win']))
|
|
143
|
+
.optional()
|
|
144
|
+
.describe('Modifier keys to hold'),
|
|
145
|
+
}, async (args) => {
|
|
146
|
+
try {
|
|
147
|
+
const mgr = await getManager();
|
|
148
|
+
await mgr.keyPress(args.key, args.modifiers && args.modifiers.length > 0
|
|
149
|
+
? { modifiers: args.modifiers }
|
|
150
|
+
: undefined);
|
|
151
|
+
return ok(`Pressed ${args.modifiers?.length ? args.modifiers.join('+') + '+' : ''}${args.key}.`);
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
return fail(`Key error: ${err instanceof Error ? err.message : String(err)}`);
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=mcp-desktop-tools.js.map
|
package/dist/mcp/mcp-server.js
CHANGED
|
@@ -38,6 +38,7 @@ import * as fs from 'fs';
|
|
|
38
38
|
import { registerAgentTools } from './mcp-agent-tools.js';
|
|
39
39
|
import { registerMemoryTools } from './mcp-memory-tools.js';
|
|
40
40
|
import { registerSessionTools } from './mcp-session-tools.js';
|
|
41
|
+
import { registerDesktopTools } from './mcp-desktop-tools.js';
|
|
41
42
|
import { registerResources } from './mcp-resources.js';
|
|
42
43
|
import { registerPrompts } from './mcp-prompts.js';
|
|
43
44
|
// Read version from package.json (avoid import.meta.url for ts-jest compat)
|
|
@@ -123,6 +124,7 @@ export class CodeBuddyMCPServer {
|
|
|
123
124
|
registerAgentTools(this.mcpServer, getAgent);
|
|
124
125
|
registerMemoryTools(this.mcpServer);
|
|
125
126
|
registerSessionTools(this.mcpServer, getAgent);
|
|
127
|
+
registerDesktopTools(this.mcpServer);
|
|
126
128
|
registerResources(this.mcpServer);
|
|
127
129
|
registerPrompts(this.mcpServer);
|
|
128
130
|
}
|
|
@@ -99,6 +99,7 @@ export interface MemorySearchOptions {
|
|
|
99
99
|
minImportance?: number;
|
|
100
100
|
limit?: number;
|
|
101
101
|
includeExpired?: boolean;
|
|
102
|
+
explorationFactor?: number;
|
|
102
103
|
}
|
|
103
104
|
export interface MemoryConfig {
|
|
104
105
|
enabled: boolean;
|
|
@@ -128,6 +129,7 @@ export declare class EnhancedMemory extends EventEmitter {
|
|
|
128
129
|
private dbRepository;
|
|
129
130
|
private embeddingProvider;
|
|
130
131
|
private bayesianQualifier;
|
|
132
|
+
private disposed;
|
|
131
133
|
constructor(config?: Partial<MemoryConfig>);
|
|
132
134
|
/**
|
|
133
135
|
* Initialize memory system
|
|
@@ -278,6 +280,14 @@ export declare class EnhancedMemory extends EventEmitter {
|
|
|
278
280
|
score: number;
|
|
279
281
|
uncertainty: number;
|
|
280
282
|
};
|
|
283
|
+
/**
|
|
284
|
+
* Active Learning: Retrieve memories with the highest uncertainty (BALD score)
|
|
285
|
+
* so the system can solicit user feedback and improve its relevance model.
|
|
286
|
+
*/
|
|
287
|
+
getActiveLearningTargets(limit?: number, query?: string): Promise<{
|
|
288
|
+
memory: MemoryEntry;
|
|
289
|
+
baldScore: number;
|
|
290
|
+
}[]>;
|
|
281
291
|
}
|
|
282
292
|
export declare function getEnhancedMemory(config?: Partial<MemoryConfig>): EnhancedMemory;
|
|
283
293
|
export declare function resetEnhancedMemory(): void;
|