@jungjaehoon/mama-os 0.32.0 → 0.32.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/README.md +15 -13
- package/dist/agent/agent-loop.d.ts +10 -1
- package/dist/agent/agent-loop.d.ts.map +1 -1
- package/dist/agent/agent-loop.js +221 -103
- package/dist/agent/agent-loop.js.map +1 -1
- package/dist/agent/backend-model-policy.d.ts +9 -0
- package/dist/agent/backend-model-policy.d.ts.map +1 -0
- package/dist/agent/backend-model-policy.js +21 -0
- package/dist/agent/backend-model-policy.js.map +1 -0
- package/dist/agent/backend-model-runner-factory.d.ts +27 -0
- package/dist/agent/backend-model-runner-factory.d.ts.map +1 -0
- package/dist/agent/backend-model-runner-factory.js +85 -0
- package/dist/agent/backend-model-runner-factory.js.map +1 -0
- package/dist/agent/cline-cli-adapter.d.ts +124 -0
- package/dist/agent/cline-cli-adapter.d.ts.map +1 -0
- package/dist/agent/cline-cli-adapter.js +1040 -0
- package/dist/agent/cline-cli-adapter.js.map +1 -0
- package/dist/agent/cline-native-tool-policy.d.ts +3 -0
- package/dist/agent/cline-native-tool-policy.d.ts.map +1 -0
- package/dist/agent/cline-native-tool-policy.js +50 -0
- package/dist/agent/cline-native-tool-policy.js.map +1 -0
- package/dist/agent/code-act/constants.d.ts +1 -1
- package/dist/agent/code-act/constants.d.ts.map +1 -1
- package/dist/agent/code-act/constants.js +13 -1
- package/dist/agent/code-act/constants.js.map +1 -1
- package/dist/agent/code-act/host-bridge.d.ts.map +1 -1
- package/dist/agent/code-act/host-bridge.js +35 -74
- package/dist/agent/code-act/host-bridge.js.map +1 -1
- package/dist/agent/codex-app-server-process.d.ts +5 -0
- package/dist/agent/codex-app-server-process.d.ts.map +1 -1
- package/dist/agent/codex-app-server-process.js +30 -0
- package/dist/agent/codex-app-server-process.js.map +1 -1
- package/dist/agent/codex-auxiliary-tools.d.ts +17 -0
- package/dist/agent/codex-auxiliary-tools.d.ts.map +1 -0
- package/dist/agent/codex-auxiliary-tools.js +267 -0
- package/dist/agent/codex-auxiliary-tools.js.map +1 -0
- package/dist/agent/codex-home.d.ts.map +1 -1
- package/dist/agent/codex-home.js +1 -0
- package/dist/agent/codex-home.js.map +1 -1
- package/dist/agent/gateway-tool-catalog.d.ts +14 -0
- package/dist/agent/gateway-tool-catalog.d.ts.map +1 -0
- package/dist/agent/gateway-tool-catalog.js +41 -0
- package/dist/agent/gateway-tool-catalog.js.map +1 -0
- package/dist/agent/gateway-tool-executor.d.ts +12 -1
- package/dist/agent/gateway-tool-executor.d.ts.map +1 -1
- package/dist/agent/gateway-tool-executor.js +149 -15
- package/dist/agent/gateway-tool-executor.js.map +1 -1
- package/dist/agent/gateway-tools.md +5 -7
- package/dist/agent/managed-agent-runtime-sync.d.ts.map +1 -1
- package/dist/agent/managed-agent-runtime-sync.js +17 -3
- package/dist/agent/managed-agent-runtime-sync.js.map +1 -1
- package/dist/agent/managed-agent-validation.js +1 -1
- package/dist/agent/managed-agent-validation.js.map +1 -1
- package/dist/agent/model-runner.d.ts +11 -1
- package/dist/agent/model-runner.d.ts.map +1 -1
- package/dist/agent/model-runner.js +12 -1
- package/dist/agent/model-runner.js.map +1 -1
- package/dist/agent/session-pool.d.ts +10 -9
- package/dist/agent/session-pool.d.ts.map +1 -1
- package/dist/agent/session-pool.js +12 -47
- package/dist/agent/session-pool.js.map +1 -1
- package/dist/agent/tool-registry.d.ts +6 -4
- package/dist/agent/tool-registry.d.ts.map +1 -1
- package/dist/agent/tool-registry.js +62 -30
- package/dist/agent/tool-registry.js.map +1 -1
- package/dist/agent/types.d.ts +36 -4
- package/dist/agent/types.d.ts.map +1 -1
- package/dist/agent/types.js.map +1 -1
- package/dist/api/graph-api.d.ts.map +1 -1
- package/dist/api/graph-api.js +15 -5
- package/dist/api/graph-api.js.map +1 -1
- package/dist/api/index.d.ts +10 -0
- package/dist/api/index.d.ts.map +1 -1
- package/dist/api/index.js +7 -16
- package/dist/api/index.js.map +1 -1
- package/dist/cli/commands/connector.d.ts +6 -1
- package/dist/cli/commands/connector.d.ts.map +1 -1
- package/dist/cli/commands/connector.js +61 -45
- package/dist/cli/commands/connector.js.map +1 -1
- package/dist/cli/commands/init.d.ts +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +43 -10
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/run.d.ts.map +1 -1
- package/dist/cli/commands/run.js +12 -0
- package/dist/cli/commands/run.js.map +1 -1
- package/dist/cli/commands/setup.d.ts +22 -0
- package/dist/cli/commands/setup.d.ts.map +1 -1
- package/dist/cli/commands/setup.js +79 -28
- package/dist/cli/commands/setup.js.map +1 -1
- package/dist/cli/commands/start.d.ts +13 -9
- package/dist/cli/commands/start.d.ts.map +1 -1
- package/dist/cli/commands/start.js +190 -97
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +4 -0
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/config/config-manager.d.ts.map +1 -1
- package/dist/cli/config/config-manager.js +63 -14
- package/dist/cli/config/config-manager.js.map +1 -1
- package/dist/cli/config/types.d.ts +12 -5
- package/dist/cli/config/types.d.ts.map +1 -1
- package/dist/cli/config/types.js +3 -4
- package/dist/cli/config/types.js.map +1 -1
- package/dist/cli/index.js +6 -4
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/runtime/agent-loop-init.d.ts +1 -1
- package/dist/cli/runtime/agent-loop-init.d.ts.map +1 -1
- package/dist/cli/runtime/agent-loop-init.js +8 -3
- package/dist/cli/runtime/agent-loop-init.js.map +1 -1
- package/dist/cli/runtime/api-routes-init.d.ts +38 -1
- package/dist/cli/runtime/api-routes-init.d.ts.map +1 -1
- package/dist/cli/runtime/api-routes-init.js +150 -30
- package/dist/cli/runtime/api-routes-init.js.map +1 -1
- package/dist/cli/runtime/api-server-init.d.ts +4 -0
- package/dist/cli/runtime/api-server-init.d.ts.map +1 -1
- package/dist/cli/runtime/api-server-init.js +3 -1
- package/dist/cli/runtime/api-server-init.js.map +1 -1
- package/dist/cli/runtime/connector-bootstrap.d.ts +8 -0
- package/dist/cli/runtime/connector-bootstrap.d.ts.map +1 -0
- package/dist/cli/runtime/connector-bootstrap.js +14 -0
- package/dist/cli/runtime/connector-bootstrap.js.map +1 -0
- package/dist/cli/runtime/connector-init.d.ts +4 -1
- package/dist/cli/runtime/connector-init.d.ts.map +1 -1
- package/dist/cli/runtime/connector-init.js +2 -8
- package/dist/cli/runtime/connector-init.js.map +1 -1
- package/dist/cli/runtime/envelope-bootstrap.d.ts +2 -1
- package/dist/cli/runtime/envelope-bootstrap.d.ts.map +1 -1
- package/dist/cli/runtime/envelope-bootstrap.js +7 -15
- package/dist/cli/runtime/envelope-bootstrap.js.map +1 -1
- package/dist/cli/runtime/gateway-init.d.ts +1 -1
- package/dist/cli/runtime/gateway-init.d.ts.map +1 -1
- package/dist/cli/runtime/gateway-init.js.map +1 -1
- package/dist/cli/runtime/mama-core-init.d.ts +10 -2
- package/dist/cli/runtime/mama-core-init.d.ts.map +1 -1
- package/dist/cli/runtime/mama-core-init.js +52 -68
- package/dist/cli/runtime/mama-core-init.js.map +1 -1
- package/dist/cli/runtime/memory-agent-init.d.ts.map +1 -1
- package/dist/cli/runtime/memory-agent-init.js +18 -5
- package/dist/cli/runtime/memory-agent-init.js.map +1 -1
- package/dist/cli/runtime/scheduler-init.d.ts +4 -0
- package/dist/cli/runtime/scheduler-init.d.ts.map +1 -1
- package/dist/cli/runtime/scheduler-init.js +24 -3
- package/dist/cli/runtime/scheduler-init.js.map +1 -1
- package/dist/cli/runtime/shutdown.d.ts +4 -0
- package/dist/cli/runtime/shutdown.d.ts.map +1 -1
- package/dist/cli/runtime/shutdown.js +30 -6
- package/dist/cli/runtime/shutdown.js.map +1 -1
- package/dist/cli/runtime/utilities.d.ts +2 -0
- package/dist/cli/runtime/utilities.d.ts.map +1 -1
- package/dist/cli/runtime/utilities.js +33 -0
- package/dist/cli/runtime/utilities.js.map +1 -1
- package/dist/connectors/index.d.ts +4 -1
- package/dist/connectors/index.d.ts.map +1 -1
- package/dist/connectors/index.js +3 -2
- package/dist/connectors/index.js.map +1 -1
- package/dist/connectors/private-connector-policy.d.ts +150 -0
- package/dist/connectors/private-connector-policy.d.ts.map +1 -0
- package/dist/connectors/private-connector-policy.js +289 -0
- package/dist/connectors/private-connector-policy.js.map +1 -0
- package/dist/connectors/private-prompt-overlay.d.ts +17 -0
- package/dist/connectors/private-prompt-overlay.d.ts.map +1 -0
- package/dist/connectors/private-prompt-overlay.js +156 -0
- package/dist/connectors/private-prompt-overlay.js.map +1 -0
- package/dist/db/migrations/operator-task-external-lifecycle.d.ts +8 -0
- package/dist/db/migrations/operator-task-external-lifecycle.d.ts.map +1 -0
- package/dist/db/migrations/operator-task-external-lifecycle.js +169 -0
- package/dist/db/migrations/operator-task-external-lifecycle.js.map +1 -0
- package/dist/envelope/enforcer.js +8 -7
- package/dist/envelope/enforcer.js.map +1 -1
- package/dist/envelope/reactive-config.d.ts.map +1 -1
- package/dist/envelope/reactive-config.js +2 -1
- package/dist/envelope/reactive-config.js.map +1 -1
- package/dist/envelope/tool-connector-scope.d.ts.map +1 -1
- package/dist/envelope/tool-connector-scope.js +4 -0
- package/dist/envelope/tool-connector-scope.js.map +1 -1
- package/dist/gateways/discord.d.ts.map +1 -1
- package/dist/gateways/discord.js +11 -6
- package/dist/gateways/discord.js.map +1 -1
- package/dist/gateways/image-analyzer.d.ts +5 -0
- package/dist/gateways/image-analyzer.d.ts.map +1 -1
- package/dist/gateways/image-analyzer.js +8 -0
- package/dist/gateways/image-analyzer.js.map +1 -1
- package/dist/gateways/message-router.d.ts +11 -1
- package/dist/gateways/message-router.d.ts.map +1 -1
- package/dist/gateways/message-router.js +146 -52
- package/dist/gateways/message-router.js.map +1 -1
- package/dist/gateways/slack.d.ts.map +1 -1
- package/dist/gateways/slack.js +6 -2
- package/dist/gateways/slack.js.map +1 -1
- package/dist/gateways/telegram-message-ledger.d.ts +8 -1
- package/dist/gateways/telegram-message-ledger.d.ts.map +1 -1
- package/dist/gateways/telegram-message-ledger.js +141 -24
- package/dist/gateways/telegram-message-ledger.js.map +1 -1
- package/dist/gateways/telegram.d.ts +2 -0
- package/dist/gateways/telegram.d.ts.map +1 -1
- package/dist/gateways/telegram.js +19 -12
- package/dist/gateways/telegram.js.map +1 -1
- package/dist/gateways/types.d.ts +1 -1
- package/dist/gateways/types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/multi-agent/agent-process-manager.d.ts +14 -4
- package/dist/multi-agent/agent-process-manager.d.ts.map +1 -1
- package/dist/multi-agent/agent-process-manager.js +144 -47
- package/dist/multi-agent/agent-process-manager.js.map +1 -1
- package/dist/multi-agent/dashboard-agent-persona.d.ts +3 -3
- package/dist/multi-agent/dashboard-agent-persona.d.ts.map +1 -1
- package/dist/multi-agent/dashboard-agent-persona.js +10 -13
- package/dist/multi-agent/dashboard-agent-persona.js.map +1 -1
- package/dist/multi-agent/memory-agent-persona.d.ts +1 -1
- package/dist/multi-agent/memory-agent-persona.d.ts.map +1 -1
- package/dist/multi-agent/memory-agent-persona.js +1 -1
- package/dist/multi-agent/runtime-process.d.ts +3 -0
- package/dist/multi-agent/runtime-process.d.ts.map +1 -1
- package/dist/multi-agent/runtime-process.js +10 -2
- package/dist/multi-agent/runtime-process.js.map +1 -1
- package/dist/multi-agent/types.d.ts +12 -2
- package/dist/multi-agent/types.d.ts.map +1 -1
- package/dist/multi-agent/types.js.map +1 -1
- package/dist/multi-agent/wiki-agent-persona.d.ts +2 -2
- package/dist/multi-agent/wiki-agent-persona.js +2 -2
- package/dist/multi-agent/workflow-types.d.ts +1 -1
- package/dist/multi-agent/workflow-types.d.ts.map +1 -1
- package/dist/onboarding/complete-autonomous-prompt.d.ts +1 -1
- package/dist/onboarding/complete-autonomous-prompt.d.ts.map +1 -1
- package/dist/onboarding/complete-autonomous-prompt.js +9 -9
- package/dist/operator/board-slot-instructions.d.ts +1 -1
- package/dist/operator/board-slot-instructions.js +2 -2
- package/dist/operator/board-slot-instructions.js.map +1 -1
- package/dist/operator/briefs.d.ts +3 -0
- package/dist/operator/briefs.d.ts.map +1 -1
- package/dist/operator/briefs.js +64 -3
- package/dist/operator/briefs.js.map +1 -1
- package/dist/operator/console-brief.d.ts +6 -3
- package/dist/operator/console-brief.d.ts.map +1 -1
- package/dist/operator/console-brief.js +39 -9
- package/dist/operator/console-brief.js.map +1 -1
- package/dist/operator/external-lifecycle-candidates.d.ts +56 -0
- package/dist/operator/external-lifecycle-candidates.d.ts.map +1 -0
- package/dist/operator/external-lifecycle-candidates.js +415 -0
- package/dist/operator/external-lifecycle-candidates.js.map +1 -0
- package/dist/operator/external-lifecycle.d.ts +82 -0
- package/dist/operator/external-lifecycle.d.ts.map +1 -0
- package/dist/operator/external-lifecycle.js +27 -0
- package/dist/operator/external-lifecycle.js.map +1 -0
- package/dist/operator/file-coordination.d.ts +7 -0
- package/dist/operator/file-coordination.d.ts.map +1 -0
- package/dist/operator/file-coordination.js +84 -0
- package/dist/operator/file-coordination.js.map +1 -0
- package/dist/operator/operator-trigger-loop.d.ts +19 -4
- package/dist/operator/operator-trigger-loop.d.ts.map +1 -1
- package/dist/operator/operator-trigger-loop.js +151 -23
- package/dist/operator/operator-trigger-loop.js.map +1 -1
- package/dist/operator/pending-report-store.d.ts +62 -3
- package/dist/operator/pending-report-store.d.ts.map +1 -1
- package/dist/operator/pending-report-store.js +297 -40
- package/dist/operator/pending-report-store.js.map +1 -1
- package/dist/operator/report-carry-delivery.d.ts +35 -0
- package/dist/operator/report-carry-delivery.d.ts.map +1 -0
- package/dist/operator/report-carry-delivery.js +55 -0
- package/dist/operator/report-carry-delivery.js.map +1 -0
- package/dist/operator/report-carry.d.ts +50 -30
- package/dist/operator/report-carry.d.ts.map +1 -1
- package/dist/operator/report-carry.js +323 -71
- package/dist/operator/report-carry.js.map +1 -1
- package/dist/operator/situation-report.d.ts +30 -11
- package/dist/operator/situation-report.d.ts.map +1 -1
- package/dist/operator/situation-report.js +79 -35
- package/dist/operator/situation-report.js.map +1 -1
- package/dist/operator/task-ledger.d.ts +101 -0
- package/dist/operator/task-ledger.d.ts.map +1 -1
- package/dist/operator/task-ledger.js +599 -124
- package/dist/operator/task-ledger.js.map +1 -1
- package/dist/operator/temporal-runtime.d.ts.map +1 -1
- package/dist/operator/temporal-runtime.js +3 -1
- package/dist/operator/temporal-runtime.js.map +1 -1
- package/dist/operator/temporal-worker.js +1 -1
- package/dist/operator/trigger-author.d.ts +13 -1
- package/dist/operator/trigger-author.d.ts.map +1 -1
- package/dist/operator/trigger-author.js +35 -0
- package/dist/operator/trigger-author.js.map +1 -1
- package/dist/operator/worker-run.d.ts +1 -1
- package/dist/operator/worker-run.d.ts.map +1 -1
- package/dist/operator/worker-run.js +27 -9
- package/dist/operator/worker-run.js.map +1 -1
- package/dist/operator/workorder-consumer.d.ts +12 -1
- package/dist/operator/workorder-consumer.d.ts.map +1 -1
- package/dist/operator/workorder-consumer.js +125 -6
- package/dist/operator/workorder-consumer.js.map +1 -1
- package/dist/operator/workorder-hooks.d.ts +7 -2
- package/dist/operator/workorder-hooks.d.ts.map +1 -1
- package/dist/operator/workorder-hooks.js +22 -0
- package/dist/operator/workorder-hooks.js.map +1 -1
- package/dist/operator/workorder-publishers.d.ts +9 -2
- package/dist/operator/workorder-publishers.d.ts.map +1 -1
- package/dist/operator/workorder-publishers.js +167 -5
- package/dist/operator/workorder-publishers.js.map +1 -1
- package/dist/scheduler/cron-worker.d.ts +8 -4
- package/dist/scheduler/cron-worker.d.ts.map +1 -1
- package/dist/scheduler/cron-worker.js +56 -39
- package/dist/scheduler/cron-worker.js.map +1 -1
- package/dist/setup/setup-actions.d.ts +26 -0
- package/dist/setup/setup-actions.d.ts.map +1 -0
- package/dist/setup/setup-actions.js +371 -0
- package/dist/setup/setup-actions.js.map +1 -0
- package/dist/setup/setup-prompt.d.ts +1 -1
- package/dist/setup/setup-prompt.d.ts.map +1 -1
- package/dist/setup/setup-prompt.js +28 -33
- package/dist/setup/setup-prompt.js.map +1 -1
- package/dist/setup/setup-server.d.ts +6 -1
- package/dist/setup/setup-server.d.ts.map +1 -1
- package/dist/setup/setup-server.js +55 -9
- package/dist/setup/setup-server.js.map +1 -1
- package/dist/setup/setup-websocket.d.ts +14 -2
- package/dist/setup/setup-websocket.d.ts.map +1 -1
- package/dist/setup/setup-websocket.js +121 -37
- package/dist/setup/setup-websocket.js.map +1 -1
- package/package.json +2 -2
- package/public/setup.html +9 -6
- package/public/viewer/js/modules/agents.js +5 -4
- package/public/viewer/js/modules/settings.js +34 -10
- package/public/viewer/src/modules/agents.ts +5 -4
- package/public/viewer/src/modules/settings.ts +49 -11
- package/public/viewer/src/utils/api.ts +3 -2
- package/scripts/generate-gateway-tools.ts +13 -3
|
@@ -0,0 +1,1040 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ClineCLIAdapter = void 0;
|
|
4
|
+
exports.resolveClineDataDir = resolveClineDataDir;
|
|
5
|
+
exports.hasPersistedClineCredential = hasPersistedClineCredential;
|
|
6
|
+
const node_fs_1 = require("node:fs");
|
|
7
|
+
const node_path_1 = require("node:path");
|
|
8
|
+
const node_url_1 = require("node:url");
|
|
9
|
+
const node_crypto_1 = require("node:crypto");
|
|
10
|
+
const node_events_1 = require("node:events");
|
|
11
|
+
const node_os_1 = require("node:os");
|
|
12
|
+
const model_runner_js_1 = require("./model-runner.js");
|
|
13
|
+
const cline_native_tool_policy_js_1 = require("./cline-native-tool-policy.js");
|
|
14
|
+
const completed_terminal_result_js_1 = require("./code-act/completed-terminal-result.js");
|
|
15
|
+
const types_js_1 = require("./types.js");
|
|
16
|
+
const CLINE_CODE_ACT_TOOL_NAME = 'mcp__code-act__code_act';
|
|
17
|
+
const MAMA_CODE_ACT_TOOL_NAME = 'code_act';
|
|
18
|
+
const CLINE_MUTATION_SETTLEMENT_GRACE_MS = 5_250;
|
|
19
|
+
function isRecord(value) {
|
|
20
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
21
|
+
}
|
|
22
|
+
function stringValue(record, key) {
|
|
23
|
+
const value = record[key];
|
|
24
|
+
return typeof value === 'string' ? value : undefined;
|
|
25
|
+
}
|
|
26
|
+
function numberValue(record, key) {
|
|
27
|
+
const value = record[key];
|
|
28
|
+
return typeof value === 'number' ? value : undefined;
|
|
29
|
+
}
|
|
30
|
+
function normalizeToolOutput(value) {
|
|
31
|
+
if (typeof value === 'string') {
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
if (value === undefined) {
|
|
35
|
+
return '';
|
|
36
|
+
}
|
|
37
|
+
return JSON.stringify(value);
|
|
38
|
+
}
|
|
39
|
+
function classifyFailure(message) {
|
|
40
|
+
const normalized = message.toLowerCase();
|
|
41
|
+
if (/quota|rate.?limit|\b429\b/.test(normalized)) {
|
|
42
|
+
return 'rate_limit';
|
|
43
|
+
}
|
|
44
|
+
if (/unauthorized|authentication|invalid api key|credentials?|\b401\b|\b403\b/.test(normalized)) {
|
|
45
|
+
return 'auth_failure';
|
|
46
|
+
}
|
|
47
|
+
if (/context.{0,20}(length|window|overflow)|too many tokens/.test(normalized)) {
|
|
48
|
+
return 'context_overflow';
|
|
49
|
+
}
|
|
50
|
+
if (/timed? out|timeout/.test(normalized)) {
|
|
51
|
+
return 'timeout';
|
|
52
|
+
}
|
|
53
|
+
return 'crash';
|
|
54
|
+
}
|
|
55
|
+
function resolveClineDataDir(dataDir) {
|
|
56
|
+
if (dataDir === '~') {
|
|
57
|
+
return (0, node_os_1.homedir)();
|
|
58
|
+
}
|
|
59
|
+
if (dataDir.startsWith('~/')) {
|
|
60
|
+
return (0, node_path_1.resolve)((0, node_os_1.homedir)(), dataDir.slice(2));
|
|
61
|
+
}
|
|
62
|
+
return (0, node_path_1.resolve)(dataDir);
|
|
63
|
+
}
|
|
64
|
+
function safeProviderFailure(rawText, finishReason) {
|
|
65
|
+
const code = classifyFailure(rawText || finishReason);
|
|
66
|
+
let providerCode;
|
|
67
|
+
let providerMessage = '';
|
|
68
|
+
try {
|
|
69
|
+
const parsed = JSON.parse(rawText);
|
|
70
|
+
if (isRecord(parsed) && isRecord(parsed.error)) {
|
|
71
|
+
providerCode = stringValue(parsed.error, 'code')
|
|
72
|
+
?.replace(/[^A-Za-z0-9_.-]/g, '')
|
|
73
|
+
.slice(0, 64);
|
|
74
|
+
providerMessage = stringValue(parsed.error, 'message') ?? '';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
providerMessage = rawText;
|
|
79
|
+
}
|
|
80
|
+
const reason = finishReason.replace(/[^A-Za-z0-9_.-]/g, '').slice(0, 32) || 'unknown';
|
|
81
|
+
const suffix = providerCode ? `, provider=${providerCode}` : '';
|
|
82
|
+
if (code === 'rate_limit') {
|
|
83
|
+
const retryHint = providerMessage.match(/try again in\s+\d+\s*(?:days?|hours?|minutes?|seconds?|[dhms])(?:\s+\d+\s*(?:days?|hours?|minutes?|seconds?|[dhms])){0,3}/i)?.[0];
|
|
84
|
+
return {
|
|
85
|
+
code,
|
|
86
|
+
message: `Cline Hub run failed (rate_limit${suffix}): Daily free limit reached${retryHint ? `. ${retryHint}` : ''}`.slice(0, 320),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
if (code === 'auth_failure') {
|
|
90
|
+
return {
|
|
91
|
+
code,
|
|
92
|
+
message: `Cline Hub authentication failed${suffix}. Run: cline auth cline`.slice(0, 320),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
const label = code === 'context_overflow'
|
|
96
|
+
? 'context limit exceeded'
|
|
97
|
+
: code === 'timeout'
|
|
98
|
+
? 'request timed out'
|
|
99
|
+
: `run ended with finish reason ${reason}`;
|
|
100
|
+
return { code, message: `Cline Hub ${label}${suffix}`.slice(0, 320) };
|
|
101
|
+
}
|
|
102
|
+
function executableCandidates(command) {
|
|
103
|
+
if ((0, node_path_1.isAbsolute)(command) || command.includes('/')) {
|
|
104
|
+
return [(0, node_path_1.resolve)(command)];
|
|
105
|
+
}
|
|
106
|
+
const pathEntries = (process.env.PATH ?? '').split(node_path_1.delimiter).filter(Boolean);
|
|
107
|
+
const suffixes = process.platform === 'win32' ? ['', '.cmd', '.exe', '.bat'] : [''];
|
|
108
|
+
return pathEntries.flatMap((entry) => suffixes.map((suffix) => (0, node_path_1.join)(entry, `${command}${suffix}`)));
|
|
109
|
+
}
|
|
110
|
+
function resolveClineWrapper(command) {
|
|
111
|
+
for (const candidate of executableCandidates(command)) {
|
|
112
|
+
try {
|
|
113
|
+
(0, node_fs_1.accessSync)(candidate, node_fs_1.constants.X_OK);
|
|
114
|
+
return (0, node_fs_1.realpathSync)(candidate);
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// Continue through PATH candidates.
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
throw new Error(`Cline CLI executable not found: ${command}`);
|
|
121
|
+
}
|
|
122
|
+
function resolveClineSdkEntry(wrapperPath) {
|
|
123
|
+
let current = (0, node_path_1.dirname)(wrapperPath);
|
|
124
|
+
for (let depth = 0; depth < 8; depth += 1) {
|
|
125
|
+
const candidate = (0, node_path_1.join)(current, 'node_modules', '@cline', 'core', 'dist', 'index.js');
|
|
126
|
+
if ((0, node_fs_1.existsSync)(candidate)) {
|
|
127
|
+
return candidate;
|
|
128
|
+
}
|
|
129
|
+
const parent = (0, node_path_1.dirname)(current);
|
|
130
|
+
if (parent === current) {
|
|
131
|
+
break;
|
|
132
|
+
}
|
|
133
|
+
current = parent;
|
|
134
|
+
}
|
|
135
|
+
throw new Error(`The installed Cline CLI does not include its companion @cline/core runtime: ${wrapperPath}`);
|
|
136
|
+
}
|
|
137
|
+
function validateImportedSdk(value) {
|
|
138
|
+
if (!isRecord(value)) {
|
|
139
|
+
throw new Error('Cline companion SDK did not export an object');
|
|
140
|
+
}
|
|
141
|
+
const clineCore = value.ClineCore;
|
|
142
|
+
const providerManager = value.ProviderSettingsManager;
|
|
143
|
+
const clineCoreCreate = (typeof clineCore === 'function' || isRecord(clineCore)) &&
|
|
144
|
+
typeof clineCore.create === 'function';
|
|
145
|
+
if (!clineCoreCreate ||
|
|
146
|
+
typeof providerManager !== 'function' ||
|
|
147
|
+
typeof value.getPersistedProviderApiKey !== 'function' ||
|
|
148
|
+
typeof value.createTool !== 'function') {
|
|
149
|
+
throw new Error('Cline companion SDK is missing the Hub session API required by MAMA');
|
|
150
|
+
}
|
|
151
|
+
return value;
|
|
152
|
+
}
|
|
153
|
+
async function hasPersistedClineCredential(options = {}) {
|
|
154
|
+
const wrapperPath = resolveClineWrapper(options.command ?? process.env.MAMA_CLINE_COMMAND ?? process.env.CLINE_COMMAND ?? 'cline');
|
|
155
|
+
const sdkEntry = resolveClineSdkEntry(wrapperPath);
|
|
156
|
+
const imported = await import((0, node_url_1.pathToFileURL)(sdkEntry).href);
|
|
157
|
+
const sdk = validateImportedSdk(imported);
|
|
158
|
+
const dataDir = options.dataDir ? resolveClineDataDir(options.dataDir) : undefined;
|
|
159
|
+
const manager = new sdk.ProviderSettingsManager(dataDir ? { dataDir } : undefined);
|
|
160
|
+
const provider = options.provider ?? 'cline';
|
|
161
|
+
return Boolean(sdk.getPersistedProviderApiKey(provider, manager.getProviderSettings(provider)));
|
|
162
|
+
}
|
|
163
|
+
const defaultRuntimeFactory = async (input) => {
|
|
164
|
+
const wrapperPath = resolveClineWrapper(input.command);
|
|
165
|
+
const sdkEntry = resolveClineSdkEntry(wrapperPath);
|
|
166
|
+
if (input.dataDir) {
|
|
167
|
+
const requestedDataDir = resolveClineDataDir(input.dataDir);
|
|
168
|
+
const existingDataDir = process.env.CLINE_DATA_DIR?.trim();
|
|
169
|
+
if (existingDataDir && resolveClineDataDir(existingDataDir) !== requestedDataDir) {
|
|
170
|
+
throw new Error(`Cline Hub data directory is already bound to ${existingDataDir}; cannot switch to ${input.dataDir}`);
|
|
171
|
+
}
|
|
172
|
+
process.env.CLINE_DATA_DIR = requestedDataDir;
|
|
173
|
+
}
|
|
174
|
+
process.env.CLINE_WRAPPER_PATH = wrapperPath;
|
|
175
|
+
const imported = await import((0, node_url_1.pathToFileURL)(sdkEntry).href);
|
|
176
|
+
const sdk = validateImportedSdk(imported);
|
|
177
|
+
const providerManager = new sdk.ProviderSettingsManager(input.dataDir ? { dataDir: resolveClineDataDir(input.dataDir) } : undefined);
|
|
178
|
+
const providerSettings = providerManager.getProviderSettings(input.provider);
|
|
179
|
+
const apiKey = sdk.getPersistedProviderApiKey(input.provider, providerSettings);
|
|
180
|
+
const client = await sdk.ClineCore.create({
|
|
181
|
+
clientName: 'mama-os',
|
|
182
|
+
backendMode: 'hub',
|
|
183
|
+
hub: {
|
|
184
|
+
cwd: input.cwd,
|
|
185
|
+
workspaceRoot: input.cwd,
|
|
186
|
+
clientType: 'mama-os',
|
|
187
|
+
displayName: 'MAMA OS',
|
|
188
|
+
strategy: 'require-hub',
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
return {
|
|
192
|
+
client,
|
|
193
|
+
source: sdk.SessionSource?.CORE ?? 'core',
|
|
194
|
+
apiKey,
|
|
195
|
+
createTool: (definition) => sdk.createTool(definition),
|
|
196
|
+
};
|
|
197
|
+
};
|
|
198
|
+
function parseAgentResult(value) {
|
|
199
|
+
if (!isRecord(value)) {
|
|
200
|
+
throw new Error('Cline Hub returned no agent result');
|
|
201
|
+
}
|
|
202
|
+
const usage = isRecord(value.usage) ? value.usage : undefined;
|
|
203
|
+
return {
|
|
204
|
+
text: stringValue(value, 'text') ?? '',
|
|
205
|
+
finishReason: stringValue(value, 'finishReason') ?? 'unknown',
|
|
206
|
+
durationMs: numberValue(value, 'durationMs'),
|
|
207
|
+
usage: usage
|
|
208
|
+
? {
|
|
209
|
+
inputTokens: numberValue(usage, 'inputTokens'),
|
|
210
|
+
outputTokens: numberValue(usage, 'outputTokens'),
|
|
211
|
+
cacheReadTokens: numberValue(usage, 'cacheReadTokens'),
|
|
212
|
+
cacheWriteTokens: numberValue(usage, 'cacheWriteTokens'),
|
|
213
|
+
totalCost: numberValue(usage, 'totalCost'),
|
|
214
|
+
}
|
|
215
|
+
: undefined,
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
function toolFingerprint(bridge, allowedTools, disallowedTools, allowSpawnAgent, allowAgentTeams) {
|
|
219
|
+
return JSON.stringify({
|
|
220
|
+
projectedTools: (bridge?.tools ?? []).map((tool) => ({
|
|
221
|
+
name: tool.name,
|
|
222
|
+
description: tool.description,
|
|
223
|
+
inputSchema: tool.inputSchema,
|
|
224
|
+
})),
|
|
225
|
+
allowedTools,
|
|
226
|
+
disallowedTools,
|
|
227
|
+
allowSpawnAgent,
|
|
228
|
+
allowAgentTeams,
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
function buildToolPolicies(bridge, allowedTools, disallowedTools) {
|
|
232
|
+
const allowAll = allowedTools.includes('*');
|
|
233
|
+
const policies = {
|
|
234
|
+
'*': { enabled: allowAll, autoApprove: allowAll },
|
|
235
|
+
};
|
|
236
|
+
if (!allowAll) {
|
|
237
|
+
for (const tool of allowedTools) {
|
|
238
|
+
policies[tool] = { enabled: true, autoApprove: true };
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
for (const tool of disallowedTools) {
|
|
242
|
+
policies[tool] = { enabled: false, autoApprove: false };
|
|
243
|
+
}
|
|
244
|
+
for (const definition of bridge?.tools ?? []) {
|
|
245
|
+
const name = definition.name === MAMA_CODE_ACT_TOOL_NAME ? CLINE_CODE_ACT_TOOL_NAME : definition.name;
|
|
246
|
+
policies[name] = { enabled: true, autoApprove: true };
|
|
247
|
+
}
|
|
248
|
+
return policies;
|
|
249
|
+
}
|
|
250
|
+
function combineSignals(...signals) {
|
|
251
|
+
const present = signals.filter((signal) => signal !== undefined);
|
|
252
|
+
if (present.length === 0) {
|
|
253
|
+
return new AbortController().signal;
|
|
254
|
+
}
|
|
255
|
+
return present.length === 1 ? present[0] : AbortSignal.any(present);
|
|
256
|
+
}
|
|
257
|
+
function abortError(signal) {
|
|
258
|
+
return signal.reason instanceof Error
|
|
259
|
+
? signal.reason
|
|
260
|
+
: new model_runner_js_1.ModelRunnerError('Cline Hub request was aborted', 'unknown', false);
|
|
261
|
+
}
|
|
262
|
+
function raceWithAbort(operation, signal) {
|
|
263
|
+
if (signal.aborted) {
|
|
264
|
+
return Promise.reject(abortError(signal));
|
|
265
|
+
}
|
|
266
|
+
return new Promise((resolvePromise, rejectPromise) => {
|
|
267
|
+
const onAbort = () => rejectPromise(abortError(signal));
|
|
268
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
269
|
+
operation.then((value) => {
|
|
270
|
+
signal.removeEventListener('abort', onAbort);
|
|
271
|
+
resolvePromise(value);
|
|
272
|
+
}, (error) => {
|
|
273
|
+
signal.removeEventListener('abort', onAbort);
|
|
274
|
+
rejectPromise(error);
|
|
275
|
+
});
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
class ClineCLIAdapter extends node_events_1.EventEmitter {
|
|
279
|
+
backendType = 'cline';
|
|
280
|
+
options;
|
|
281
|
+
runtimeFactory;
|
|
282
|
+
sessions = new Map();
|
|
283
|
+
stableRoutes = new Map();
|
|
284
|
+
routesRequiringRebuild = new Set();
|
|
285
|
+
routeTails = new Map();
|
|
286
|
+
activeRoutes = new Set();
|
|
287
|
+
sessionLifecycleTail = Promise.resolve();
|
|
288
|
+
runtimePromise = null;
|
|
289
|
+
disposedRuntimes = new WeakSet();
|
|
290
|
+
runtimeWaiters = 0;
|
|
291
|
+
sessionId;
|
|
292
|
+
systemPrompt;
|
|
293
|
+
requestCount = 0;
|
|
294
|
+
failureCount = 0;
|
|
295
|
+
totalLatencyMs = 0;
|
|
296
|
+
lastRequestAt = null;
|
|
297
|
+
stopped = false;
|
|
298
|
+
maxSessions;
|
|
299
|
+
sessionTtlMs;
|
|
300
|
+
constructor(options = {}) {
|
|
301
|
+
super();
|
|
302
|
+
this.options = {
|
|
303
|
+
...options,
|
|
304
|
+
command: options.command ?? process.env.MAMA_CLINE_COMMAND ?? process.env.CLINE_COMMAND,
|
|
305
|
+
};
|
|
306
|
+
this.runtimeFactory = options.runtimeFactory ?? defaultRuntimeFactory;
|
|
307
|
+
this.sessionId = options.sessionId ?? 'cline';
|
|
308
|
+
this.systemPrompt = options.systemPrompt ?? '';
|
|
309
|
+
this.maxSessions = Math.max(1, options.maxSessions ?? 100);
|
|
310
|
+
this.sessionTtlMs = Math.max(1, options.sessionTtlMs ?? 1_800_000);
|
|
311
|
+
}
|
|
312
|
+
async prompt(content, callbacks, promptOptions) {
|
|
313
|
+
const startedAt = Date.now();
|
|
314
|
+
const routeId = promptOptions?.sessionId ?? promptOptions?.sessionKey ?? this.sessionId;
|
|
315
|
+
const stableRouteId = promptOptions?.sessionKey ?? routeId;
|
|
316
|
+
const timeoutMs = promptOptions?.requestTimeout ?? this.options.requestTimeout ?? 600_000;
|
|
317
|
+
const deadlineController = new AbortController();
|
|
318
|
+
let lockAcquired = false;
|
|
319
|
+
const timeoutHandle = setTimeout(() => {
|
|
320
|
+
const error = new model_runner_js_1.ModelRunnerError(`Cline Hub request timed out after ${timeoutMs}ms`, 'timeout', true);
|
|
321
|
+
deadlineController.abort(error);
|
|
322
|
+
if (lockAcquired) {
|
|
323
|
+
void this.abortRoute(routeId, error);
|
|
324
|
+
}
|
|
325
|
+
}, timeoutMs);
|
|
326
|
+
timeoutHandle.unref();
|
|
327
|
+
this.requestCount += 1;
|
|
328
|
+
this.lastRequestAt = startedAt;
|
|
329
|
+
try {
|
|
330
|
+
return await this.withRouteLock(stableRouteId, deadlineController.signal, () => {
|
|
331
|
+
lockAcquired = true;
|
|
332
|
+
this.activeRoutes.add(routeId);
|
|
333
|
+
}, async () => {
|
|
334
|
+
try {
|
|
335
|
+
return await this.runHubPrompt(routeId, stableRouteId, content, callbacks, promptOptions, deadlineController.signal, timeoutMs);
|
|
336
|
+
}
|
|
337
|
+
finally {
|
|
338
|
+
this.activeRoutes.delete(routeId);
|
|
339
|
+
}
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
catch (error) {
|
|
343
|
+
this.failureCount += 1;
|
|
344
|
+
const normalized = this.normalizeError(error);
|
|
345
|
+
if (lockAcquired && normalized instanceof model_runner_js_1.ModelRunnerError && normalized.code === 'timeout') {
|
|
346
|
+
await this.quarantineRoute(routeId);
|
|
347
|
+
}
|
|
348
|
+
callbacks?.onError?.(normalized);
|
|
349
|
+
throw normalized;
|
|
350
|
+
}
|
|
351
|
+
finally {
|
|
352
|
+
clearTimeout(timeoutHandle);
|
|
353
|
+
this.totalLatencyMs += Date.now() - startedAt;
|
|
354
|
+
if (this.routeTails.size === 0) {
|
|
355
|
+
this.emit('idle');
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
async withRouteLock(routeId, signal, onAcquired, run) {
|
|
360
|
+
const previous = this.routeTails.get(routeId) ?? Promise.resolve();
|
|
361
|
+
let acquired = false;
|
|
362
|
+
const current = previous
|
|
363
|
+
.catch(() => undefined)
|
|
364
|
+
.then(async () => {
|
|
365
|
+
if (signal.aborted) {
|
|
366
|
+
throw signal.reason instanceof Error
|
|
367
|
+
? signal.reason
|
|
368
|
+
: new model_runner_js_1.ModelRunnerError('Cline Hub request was aborted', 'unknown');
|
|
369
|
+
}
|
|
370
|
+
acquired = true;
|
|
371
|
+
onAcquired();
|
|
372
|
+
return await run();
|
|
373
|
+
});
|
|
374
|
+
const tail = current.then(() => undefined, () => undefined);
|
|
375
|
+
this.routeTails.set(routeId, tail);
|
|
376
|
+
void tail.then(() => {
|
|
377
|
+
if (this.routeTails.get(routeId) === tail) {
|
|
378
|
+
this.routeTails.delete(routeId);
|
|
379
|
+
}
|
|
380
|
+
});
|
|
381
|
+
return await new Promise((resolvePromise, rejectPromise) => {
|
|
382
|
+
const onAbort = () => {
|
|
383
|
+
if (!acquired) {
|
|
384
|
+
rejectPromise(abortError(signal));
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
388
|
+
current.then((value) => {
|
|
389
|
+
signal.removeEventListener('abort', onAbort);
|
|
390
|
+
resolvePromise(value);
|
|
391
|
+
}, (error) => {
|
|
392
|
+
signal.removeEventListener('abort', onAbort);
|
|
393
|
+
rejectPromise(error);
|
|
394
|
+
});
|
|
395
|
+
});
|
|
396
|
+
}
|
|
397
|
+
async withSessionLifecycleLock(signal, run) {
|
|
398
|
+
const current = this.sessionLifecycleTail
|
|
399
|
+
.catch(() => undefined)
|
|
400
|
+
.then(async () => {
|
|
401
|
+
if (signal.aborted) {
|
|
402
|
+
throw abortError(signal);
|
|
403
|
+
}
|
|
404
|
+
return await run();
|
|
405
|
+
});
|
|
406
|
+
this.sessionLifecycleTail = current.then(() => undefined, () => undefined);
|
|
407
|
+
return await raceWithAbort(current, signal);
|
|
408
|
+
}
|
|
409
|
+
async getRuntime(signal) {
|
|
410
|
+
if (this.stopped) {
|
|
411
|
+
throw new model_runner_js_1.ModelRunnerError('Cline Hub adapter is stopped', 'crash', false);
|
|
412
|
+
}
|
|
413
|
+
if (!this.runtimePromise) {
|
|
414
|
+
const pending = this.runtimeFactory({
|
|
415
|
+
command: this.options.command ?? 'cline',
|
|
416
|
+
cwd: this.options.cwd ?? process.cwd(),
|
|
417
|
+
dataDir: this.options.dataDir,
|
|
418
|
+
provider: this.options.provider ?? 'cline',
|
|
419
|
+
});
|
|
420
|
+
this.runtimePromise = pending;
|
|
421
|
+
void pending.catch(() => {
|
|
422
|
+
if (this.runtimePromise === pending) {
|
|
423
|
+
this.runtimePromise = null;
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
const pending = this.runtimePromise;
|
|
428
|
+
this.runtimeWaiters += 1;
|
|
429
|
+
try {
|
|
430
|
+
const runtime = await raceWithAbort(pending, signal);
|
|
431
|
+
if (this.stopped) {
|
|
432
|
+
void this.disposeRuntimeOnce(runtime, 'mama_shutdown').catch(() => undefined);
|
|
433
|
+
throw new model_runner_js_1.ModelRunnerError('Cline Hub adapter is stopped', 'crash', false);
|
|
434
|
+
}
|
|
435
|
+
return runtime;
|
|
436
|
+
}
|
|
437
|
+
catch (error) {
|
|
438
|
+
if (signal.aborted && this.runtimePromise === pending && this.runtimeWaiters === 1) {
|
|
439
|
+
this.runtimePromise = null;
|
|
440
|
+
void pending
|
|
441
|
+
.then((runtime) => this.disposeRuntimeOnce(runtime, 'mama_request_deadline'))
|
|
442
|
+
.catch(() => undefined);
|
|
443
|
+
}
|
|
444
|
+
throw error;
|
|
445
|
+
}
|
|
446
|
+
finally {
|
|
447
|
+
this.runtimeWaiters -= 1;
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
async abortRoute(routeId, reason) {
|
|
451
|
+
const pendingRuntime = this.runtimePromise;
|
|
452
|
+
const session = this.sessions.get(routeId);
|
|
453
|
+
if (!pendingRuntime || !session) {
|
|
454
|
+
return;
|
|
455
|
+
}
|
|
456
|
+
const runtime = await pendingRuntime.catch(() => null);
|
|
457
|
+
await runtime?.client.abort(session.hubSessionId, reason).catch(() => undefined);
|
|
458
|
+
}
|
|
459
|
+
async quarantineRoute(routeId) {
|
|
460
|
+
const session = this.sessions.get(routeId);
|
|
461
|
+
if (!session) {
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
if (this.sessions.get(routeId) === session) {
|
|
465
|
+
this.sessions.delete(routeId);
|
|
466
|
+
this.removeStableRoute(routeId);
|
|
467
|
+
this.markRouteForRebuild(routeId);
|
|
468
|
+
}
|
|
469
|
+
const pendingRuntime = this.runtimePromise;
|
|
470
|
+
if (pendingRuntime) {
|
|
471
|
+
void pendingRuntime
|
|
472
|
+
.then((runtime) => runtime.client.stop(session.hubSessionId))
|
|
473
|
+
.catch(() => undefined);
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
async disposeRuntimeOnce(runtime, reason) {
|
|
477
|
+
if (this.disposedRuntimes.has(runtime)) {
|
|
478
|
+
return;
|
|
479
|
+
}
|
|
480
|
+
this.disposedRuntimes.add(runtime);
|
|
481
|
+
await runtime.client.dispose(reason);
|
|
482
|
+
}
|
|
483
|
+
async runHubPrompt(routeId, stableRouteId, content, callbacks, promptOptions, deadlineSignal, timeoutMs) {
|
|
484
|
+
const runtime = await this.getRuntime(deadlineSignal);
|
|
485
|
+
const model = promptOptions?.model ?? this.options.model;
|
|
486
|
+
if (!model) {
|
|
487
|
+
throw new model_runner_js_1.ModelRunnerError('Cline model is required', 'auth_failure', false);
|
|
488
|
+
}
|
|
489
|
+
if (!runtime.apiKey && (this.options.provider ?? 'cline') === 'cline') {
|
|
490
|
+
const unauthenticatedRuntime = this.runtimePromise;
|
|
491
|
+
this.runtimePromise = null;
|
|
492
|
+
if (unauthenticatedRuntime) {
|
|
493
|
+
void this.disposeRuntimeOnce(runtime, 'mama_auth_reload').catch(() => undefined);
|
|
494
|
+
}
|
|
495
|
+
throw new model_runner_js_1.ModelRunnerError('Cline credentials are unavailable. Run: cline auth cline', 'auth_failure', false);
|
|
496
|
+
}
|
|
497
|
+
const previousRouteId = this.stableRoutes.get(stableRouteId);
|
|
498
|
+
if (previousRouteId && previousRouteId !== routeId) {
|
|
499
|
+
const previousSession = this.sessions.get(previousRouteId);
|
|
500
|
+
if (previousSession) {
|
|
501
|
+
await raceWithAbort(runtime.client.stop(previousSession.hubSessionId).catch(() => undefined), deadlineSignal);
|
|
502
|
+
this.sessions.delete(previousRouteId);
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
const requestedPolicy = promptOptions?.sessionPolicyFingerprint;
|
|
506
|
+
const allowedTools = promptOptions?.allowedTools ?? this.options.allowedTools ?? [];
|
|
507
|
+
const disallowedTools = promptOptions?.disallowedTools ?? this.options.disallowedTools ?? [];
|
|
508
|
+
const allowSpawnAgent = promptOptions?.allowSpawnAgent ?? this.options.allowSpawnAgent ?? false;
|
|
509
|
+
const allowAgentTeams = promptOptions?.allowAgentTeams ?? this.options.allowAgentTeams ?? false;
|
|
510
|
+
const requestedToolFingerprint = toolFingerprint(promptOptions?.hostToolBridge, allowedTools, disallowedTools, allowSpawnAgent, allowAgentTeams);
|
|
511
|
+
let session = this.sessions.get(routeId);
|
|
512
|
+
const mappedSessionWasMissing = session !== undefined &&
|
|
513
|
+
!(await raceWithAbort(runtime.client.get(session.hubSessionId), deadlineSignal));
|
|
514
|
+
if (mappedSessionWasMissing) {
|
|
515
|
+
this.sessions.delete(routeId);
|
|
516
|
+
this.removeStableRoute(routeId);
|
|
517
|
+
session = undefined;
|
|
518
|
+
}
|
|
519
|
+
const incompatibleSession = session &&
|
|
520
|
+
(promptOptions?.resumeSession === false ||
|
|
521
|
+
session.model !== model ||
|
|
522
|
+
session.policyFingerprint !== requestedPolicy ||
|
|
523
|
+
session.toolFingerprint !== requestedToolFingerprint)
|
|
524
|
+
? session
|
|
525
|
+
: undefined;
|
|
526
|
+
let systemPrompt = promptOptions?.systemPrompt ?? this.systemPrompt;
|
|
527
|
+
if (mappedSessionWasMissing && promptOptions?.resumeInstructions) {
|
|
528
|
+
systemPrompt = await raceWithAbort(promptOptions.resumeInstructions(), deadlineSignal);
|
|
529
|
+
}
|
|
530
|
+
if (incompatibleSession) {
|
|
531
|
+
await raceWithAbort(runtime.client.stop(incompatibleSession.hubSessionId).catch(() => undefined), deadlineSignal);
|
|
532
|
+
this.sessions.delete(routeId);
|
|
533
|
+
this.removeStableRoute(routeId);
|
|
534
|
+
session = undefined;
|
|
535
|
+
if (promptOptions?.resumeInstructions) {
|
|
536
|
+
systemPrompt = await raceWithAbort(promptOptions.resumeInstructions(), deadlineSignal);
|
|
537
|
+
}
|
|
538
|
+
}
|
|
539
|
+
if (!session &&
|
|
540
|
+
promptOptions?.resumeSession !== false &&
|
|
541
|
+
this.routesRequiringRebuild.has(routeId) &&
|
|
542
|
+
promptOptions?.resumeInstructions) {
|
|
543
|
+
systemPrompt = await raceWithAbort(promptOptions.resumeInstructions(), deadlineSignal);
|
|
544
|
+
}
|
|
545
|
+
if (!session) {
|
|
546
|
+
session = await this.withSessionLifecycleLock(deadlineSignal, async () => {
|
|
547
|
+
const existingSession = this.sessions.get(routeId);
|
|
548
|
+
if (existingSession) {
|
|
549
|
+
return existingSession;
|
|
550
|
+
}
|
|
551
|
+
await this.retireStaleSessions(runtime, routeId, deadlineSignal);
|
|
552
|
+
if (this.sessions.size >= this.maxSessions) {
|
|
553
|
+
throw new model_runner_js_1.ModelRunnerError('Cline Hub session capacity is fully active; retry after an active request completes', 'crash', true);
|
|
554
|
+
}
|
|
555
|
+
const createdSession = await this.startHubSession(runtime, routeId, model, systemPrompt, requestedPolicy, promptOptions?.hostToolBridge, requestedToolFingerprint, promptOptions?.requestTimeout, allowedTools, disallowedTools, allowSpawnAgent, allowAgentTeams, deadlineSignal);
|
|
556
|
+
this.sessions.set(routeId, createdSession);
|
|
557
|
+
return createdSession;
|
|
558
|
+
});
|
|
559
|
+
}
|
|
560
|
+
this.stableRoutes.set(stableRouteId, routeId);
|
|
561
|
+
this.routesRequiringRebuild.delete(routeId);
|
|
562
|
+
session.lastActiveAt = Date.now();
|
|
563
|
+
const attemptController = new AbortController();
|
|
564
|
+
const ownerSignal = promptOptions?.toolExecutionContext?.signal;
|
|
565
|
+
const pendingTools = new Map();
|
|
566
|
+
const attempt = {
|
|
567
|
+
bridge: promptOptions?.hostToolBridge,
|
|
568
|
+
controller: attemptController,
|
|
569
|
+
signal: combineSignals(ownerSignal, attemptController.signal, deadlineSignal),
|
|
570
|
+
completed: new Map(),
|
|
571
|
+
pendingTools,
|
|
572
|
+
claimedToolCallIds: new Set(),
|
|
573
|
+
executedToolCallIds: new Set(),
|
|
574
|
+
inFlightTools: new Set(),
|
|
575
|
+
};
|
|
576
|
+
session.activeAttempt = attempt;
|
|
577
|
+
const unsubscribe = runtime.client.subscribe((event) => this.processHubEvent(event, session, attempt, pendingTools, callbacks), { sessionId: session.hubSessionId });
|
|
578
|
+
const abortOwner = () => {
|
|
579
|
+
const error = new model_runner_js_1.ModelRunnerError('Cline Hub request was aborted by its owner', 'unknown');
|
|
580
|
+
attemptController.abort(error);
|
|
581
|
+
void runtime.client.abort(session.hubSessionId, error).catch(() => undefined);
|
|
582
|
+
};
|
|
583
|
+
ownerSignal?.addEventListener('abort', abortOwner, { once: true });
|
|
584
|
+
try {
|
|
585
|
+
if (ownerSignal?.aborted) {
|
|
586
|
+
abortOwner();
|
|
587
|
+
throw new model_runner_js_1.ModelRunnerError('Cline Hub request was aborted by its owner', 'unknown');
|
|
588
|
+
}
|
|
589
|
+
const rawResult = await raceWithAbort(runtime.client.send({ sessionId: session.hubSessionId, prompt: content, timeoutMs }), deadlineSignal);
|
|
590
|
+
const result = parseAgentResult(rawResult);
|
|
591
|
+
const completedToolExchanges = [...attempt.completed.values()];
|
|
592
|
+
const completedTerminal = attempt.terminalResult?.terminalCode && attempt.terminalResult.abort
|
|
593
|
+
? {
|
|
594
|
+
code: attempt.terminalResult.terminalCode,
|
|
595
|
+
message: attempt.terminalResult.content,
|
|
596
|
+
}
|
|
597
|
+
: (0, completed_terminal_result_js_1.completedCodeActTerminalError)(completedToolExchanges);
|
|
598
|
+
if (!completedTerminal && (attempt.terminalResult?.abort || attempt.terminalResult?.stop)) {
|
|
599
|
+
throw new model_runner_js_1.HostToolAbortError('MAMA host tool aborted the active Cline run', completedToolExchanges);
|
|
600
|
+
}
|
|
601
|
+
if (result.finishReason !== 'completed') {
|
|
602
|
+
const failure = safeProviderFailure(result.text.trim(), result.finishReason);
|
|
603
|
+
throw new model_runner_js_1.ModelRunnerError(failure.message, failure.code, failure.code !== 'auth_failure');
|
|
604
|
+
}
|
|
605
|
+
const unresolvedCodeActIds = [...pendingTools.values()]
|
|
606
|
+
.filter((toolUse) => toolUse.name === CLINE_CODE_ACT_TOOL_NAME)
|
|
607
|
+
.map((toolUse) => toolUse.id);
|
|
608
|
+
if (unresolvedCodeActIds.length > 0) {
|
|
609
|
+
throw new types_js_1.McpResultMissingError(unresolvedCodeActIds);
|
|
610
|
+
}
|
|
611
|
+
const promptResult = {
|
|
612
|
+
response: result.text,
|
|
613
|
+
session_id: session.hubSessionId,
|
|
614
|
+
cost_usd: result.usage?.totalCost,
|
|
615
|
+
duration_ms: result.durationMs,
|
|
616
|
+
usage: {
|
|
617
|
+
input_tokens: result.usage?.inputTokens ?? 0,
|
|
618
|
+
output_tokens: result.usage?.outputTokens ?? 0,
|
|
619
|
+
cache_creation_input_tokens: result.usage?.cacheWriteTokens,
|
|
620
|
+
cache_read_input_tokens: result.usage?.cacheReadTokens,
|
|
621
|
+
},
|
|
622
|
+
hasToolUse: false,
|
|
623
|
+
completedToolExchanges,
|
|
624
|
+
...(completedTerminal ? { terminalError: completedTerminal } : {}),
|
|
625
|
+
};
|
|
626
|
+
if (completedTerminal) {
|
|
627
|
+
callbacks?.onError?.(new model_runner_js_1.HostToolTerminalError(completedTerminal.code, completedTerminal.message, completedToolExchanges));
|
|
628
|
+
}
|
|
629
|
+
else {
|
|
630
|
+
callbacks?.onFinal?.({ content: result.text, toolUseBlocks: [] });
|
|
631
|
+
}
|
|
632
|
+
return promptResult;
|
|
633
|
+
}
|
|
634
|
+
catch (error) {
|
|
635
|
+
const inFlightAtInterruption = [...attempt.inFlightTools];
|
|
636
|
+
if (inFlightAtInterruption.length > 0) {
|
|
637
|
+
if (!attempt.signal.aborted) {
|
|
638
|
+
attemptController.abort(error instanceof Error
|
|
639
|
+
? error
|
|
640
|
+
: new model_runner_js_1.ModelRunnerError('Cline Hub tool transport was interrupted', 'crash', false));
|
|
641
|
+
}
|
|
642
|
+
await this.waitForToolSettlement(inFlightAtInterruption);
|
|
643
|
+
}
|
|
644
|
+
const completedToolExchanges = [...attempt.completed.values()];
|
|
645
|
+
const completedTerminal = attempt.terminalResult?.terminalCode && attempt.terminalResult.abort
|
|
646
|
+
? {
|
|
647
|
+
code: attempt.terminalResult.terminalCode,
|
|
648
|
+
message: attempt.terminalResult.content,
|
|
649
|
+
}
|
|
650
|
+
: (0, completed_terminal_result_js_1.completedCodeActTerminalError)(completedToolExchanges);
|
|
651
|
+
if (completedTerminal) {
|
|
652
|
+
throw new model_runner_js_1.HostToolTerminalError(completedTerminal.code, completedTerminal.message, completedToolExchanges);
|
|
653
|
+
}
|
|
654
|
+
if (attempt.terminalResult?.abort || attempt.terminalResult?.stop) {
|
|
655
|
+
throw new model_runner_js_1.HostToolAbortError('MAMA host tool aborted the active Cline run', completedToolExchanges);
|
|
656
|
+
}
|
|
657
|
+
if ((0, completed_terminal_result_js_1.completedCodeActMutationWasObserved)(completedToolExchanges)) {
|
|
658
|
+
throw new types_js_1.McpCompletedMutationInterruptedError(completedToolExchanges);
|
|
659
|
+
}
|
|
660
|
+
if (inFlightAtInterruption.length > 0) {
|
|
661
|
+
const unresolvedIds = [...attempt.pendingTools.values()]
|
|
662
|
+
.filter((toolUse) => toolUse.name === CLINE_CODE_ACT_TOOL_NAME)
|
|
663
|
+
.map((toolUse) => toolUse.id);
|
|
664
|
+
throw new types_js_1.McpResultMissingError(unresolvedIds.length > 0 ? unresolvedIds : [...attempt.claimedToolCallIds]);
|
|
665
|
+
}
|
|
666
|
+
throw error;
|
|
667
|
+
}
|
|
668
|
+
finally {
|
|
669
|
+
ownerSignal?.removeEventListener('abort', abortOwner);
|
|
670
|
+
unsubscribe();
|
|
671
|
+
if (session.activeAttempt === attempt) {
|
|
672
|
+
session.activeAttempt = undefined;
|
|
673
|
+
}
|
|
674
|
+
if (attempt.signal.aborted) {
|
|
675
|
+
if (this.sessions.get(routeId) === session) {
|
|
676
|
+
this.sessions.delete(routeId);
|
|
677
|
+
this.removeStableRoute(routeId);
|
|
678
|
+
this.markRouteForRebuild(routeId);
|
|
679
|
+
}
|
|
680
|
+
void runtime.client.stop(session.hubSessionId).catch(() => undefined);
|
|
681
|
+
}
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
async waitForToolSettlement(inFlight) {
|
|
685
|
+
let timeoutHandle;
|
|
686
|
+
const timeout = new Promise((resolvePromise) => {
|
|
687
|
+
timeoutHandle = setTimeout(resolvePromise, CLINE_MUTATION_SETTLEMENT_GRACE_MS);
|
|
688
|
+
timeoutHandle.unref();
|
|
689
|
+
});
|
|
690
|
+
await Promise.race([Promise.all(inFlight).then(() => undefined), timeout]);
|
|
691
|
+
if (timeoutHandle) {
|
|
692
|
+
clearTimeout(timeoutHandle);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
async startHubSession(runtime, routeId, model, systemPrompt, policyFingerprint, bridge, projectedToolFingerprint, requestTimeout, allowedTools, disallowedTools, allowSpawnAgent, allowAgentTeams, deadlineSignal) {
|
|
696
|
+
const session = {
|
|
697
|
+
routeId,
|
|
698
|
+
hubSessionId: '',
|
|
699
|
+
model,
|
|
700
|
+
policyFingerprint,
|
|
701
|
+
toolFingerprint: projectedToolFingerprint,
|
|
702
|
+
lastActiveAt: Date.now(),
|
|
703
|
+
};
|
|
704
|
+
const tools = (bridge?.tools ?? []).map((definition) => this.createProjectedTool(runtime, session, definition, requestTimeout));
|
|
705
|
+
const provider = this.options.provider ?? 'cline';
|
|
706
|
+
const cwd = this.options.cwd ?? process.cwd();
|
|
707
|
+
const toolPolicies = buildToolPolicies(bridge, allowedTools, disallowedTools);
|
|
708
|
+
const hasProjectedTools = (bridge?.tools.length ?? 0) > 0;
|
|
709
|
+
const hasNativeTools = allowedTools.includes('*') || allowedTools.length > 0;
|
|
710
|
+
const startPromise = runtime.client.start({
|
|
711
|
+
source: runtime.source,
|
|
712
|
+
interactive: true,
|
|
713
|
+
config: {
|
|
714
|
+
providerId: provider,
|
|
715
|
+
modelId: model,
|
|
716
|
+
apiKey: runtime.apiKey,
|
|
717
|
+
cwd,
|
|
718
|
+
workspaceRoot: cwd,
|
|
719
|
+
systemPrompt,
|
|
720
|
+
enableTools: hasNativeTools || hasProjectedTools,
|
|
721
|
+
enableSpawnAgent: allowSpawnAgent,
|
|
722
|
+
enableAgentTeams: allowAgentTeams,
|
|
723
|
+
disableMcpSettingsTools: !allowedTools.includes('*') && !allowedTools.some(cline_native_tool_policy_js_1.isClineMcpToolGrant),
|
|
724
|
+
toolPolicies,
|
|
725
|
+
},
|
|
726
|
+
localRuntime: { extraTools: tools },
|
|
727
|
+
sessionMetadata: {
|
|
728
|
+
source: 'mama-os',
|
|
729
|
+
routeId,
|
|
730
|
+
policyFingerprint,
|
|
731
|
+
},
|
|
732
|
+
});
|
|
733
|
+
let started;
|
|
734
|
+
try {
|
|
735
|
+
started = await raceWithAbort(startPromise, deadlineSignal);
|
|
736
|
+
}
|
|
737
|
+
catch (error) {
|
|
738
|
+
if (deadlineSignal.aborted) {
|
|
739
|
+
void startPromise
|
|
740
|
+
.then((lateSession) => runtime.client.stop(lateSession.sessionId))
|
|
741
|
+
.catch(() => undefined);
|
|
742
|
+
}
|
|
743
|
+
throw error;
|
|
744
|
+
}
|
|
745
|
+
if (!started.sessionId?.trim()) {
|
|
746
|
+
throw new Error('Cline Hub returned an empty session id');
|
|
747
|
+
}
|
|
748
|
+
session.hubSessionId = started.sessionId.trim();
|
|
749
|
+
return session;
|
|
750
|
+
}
|
|
751
|
+
createProjectedTool(runtime, session, definition, requestTimeout) {
|
|
752
|
+
const exposedName = definition.name === MAMA_CODE_ACT_TOOL_NAME ? CLINE_CODE_ACT_TOOL_NAME : definition.name;
|
|
753
|
+
return runtime.createTool({
|
|
754
|
+
name: exposedName,
|
|
755
|
+
description: definition.description,
|
|
756
|
+
inputSchema: { ...definition.inputSchema },
|
|
757
|
+
timeoutMs: Math.max(requestTimeout ?? this.options.requestTimeout ?? 600_000, 310_000),
|
|
758
|
+
retryable: false,
|
|
759
|
+
maxRetries: 0,
|
|
760
|
+
execute: async (input, context) => {
|
|
761
|
+
const attempt = session.activeAttempt;
|
|
762
|
+
const bridge = attempt?.bridge;
|
|
763
|
+
if (!attempt || !bridge) {
|
|
764
|
+
throw new Error(`MAMA bridge is not active for Cline session ${session.hubSessionId}`);
|
|
765
|
+
}
|
|
766
|
+
if (attempt.terminalResult?.abort ||
|
|
767
|
+
attempt.terminalResult?.stop ||
|
|
768
|
+
attempt.terminalResult?.terminalCode) {
|
|
769
|
+
throw new Error('MAMA host-tool attempt is already sealed');
|
|
770
|
+
}
|
|
771
|
+
const streamedToolUse = [...attempt.pendingTools.values()].find((toolUse) => toolUse.name === exposedName && !attempt.claimedToolCallIds.has(toolUse.id));
|
|
772
|
+
const callId = context.toolCallId?.trim() || streamedToolUse?.id || (0, node_crypto_1.randomUUID)();
|
|
773
|
+
attempt.claimedToolCallIds.add(callId);
|
|
774
|
+
const signal = combineSignals(context.signal, attempt.signal);
|
|
775
|
+
let settleTool = () => undefined;
|
|
776
|
+
const settlement = new Promise((resolvePromise) => {
|
|
777
|
+
settleTool = resolvePromise;
|
|
778
|
+
});
|
|
779
|
+
attempt.inFlightTools.add(settlement);
|
|
780
|
+
try {
|
|
781
|
+
const result = await bridge.execute({
|
|
782
|
+
callId,
|
|
783
|
+
name: definition.name,
|
|
784
|
+
input,
|
|
785
|
+
signal,
|
|
786
|
+
});
|
|
787
|
+
attempt.executedToolCallIds.add(callId);
|
|
788
|
+
const exchange = {
|
|
789
|
+
toolUse: {
|
|
790
|
+
type: 'tool_use',
|
|
791
|
+
id: callId,
|
|
792
|
+
name: exposedName,
|
|
793
|
+
input,
|
|
794
|
+
},
|
|
795
|
+
toolResult: {
|
|
796
|
+
type: 'tool_result',
|
|
797
|
+
tool_use_id: callId,
|
|
798
|
+
content: result.content,
|
|
799
|
+
is_error: result.isError,
|
|
800
|
+
},
|
|
801
|
+
};
|
|
802
|
+
attempt.completed.set(callId, exchange);
|
|
803
|
+
if (result.terminalCode || result.abort || result.stop) {
|
|
804
|
+
attempt.terminalResult = result;
|
|
805
|
+
void runtime.client
|
|
806
|
+
.abort(session.hubSessionId, new Error('MAMA host tool sealed run'))
|
|
807
|
+
.catch(() => undefined);
|
|
808
|
+
}
|
|
809
|
+
if (result.isError) {
|
|
810
|
+
throw new Error('MAMA projected tool returned an error');
|
|
811
|
+
}
|
|
812
|
+
return result.content;
|
|
813
|
+
}
|
|
814
|
+
finally {
|
|
815
|
+
settleTool();
|
|
816
|
+
attempt.inFlightTools.delete(settlement);
|
|
817
|
+
}
|
|
818
|
+
},
|
|
819
|
+
});
|
|
820
|
+
}
|
|
821
|
+
processHubEvent(raw, session, attempt, pendingTools, callbacks) {
|
|
822
|
+
if (!isRecord(raw) || raw.type !== 'agent_event' || !isRecord(raw.payload)) {
|
|
823
|
+
return;
|
|
824
|
+
}
|
|
825
|
+
if (stringValue(raw.payload, 'sessionId') !== session.hubSessionId ||
|
|
826
|
+
!isRecord(raw.payload.event)) {
|
|
827
|
+
return;
|
|
828
|
+
}
|
|
829
|
+
const event = raw.payload.event;
|
|
830
|
+
const eventType = stringValue(event, 'type');
|
|
831
|
+
const contentType = stringValue(event, 'contentType');
|
|
832
|
+
if (eventType === 'content_start' && contentType === 'text') {
|
|
833
|
+
const text = stringValue(event, 'text');
|
|
834
|
+
if (text) {
|
|
835
|
+
callbacks?.onDelta?.(text);
|
|
836
|
+
}
|
|
837
|
+
return;
|
|
838
|
+
}
|
|
839
|
+
if (contentType !== 'tool') {
|
|
840
|
+
return;
|
|
841
|
+
}
|
|
842
|
+
const toolCallId = stringValue(event, 'toolCallId');
|
|
843
|
+
if (!toolCallId) {
|
|
844
|
+
return;
|
|
845
|
+
}
|
|
846
|
+
if (eventType === 'content_start') {
|
|
847
|
+
const toolName = stringValue(event, 'toolName');
|
|
848
|
+
if (!toolName) {
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
const input = isRecord(event.input) ? event.input : {};
|
|
852
|
+
pendingTools.set(toolCallId, {
|
|
853
|
+
type: 'tool_use',
|
|
854
|
+
id: toolCallId,
|
|
855
|
+
name: toolName,
|
|
856
|
+
input,
|
|
857
|
+
});
|
|
858
|
+
callbacks?.onToolUse?.(toolName, input);
|
|
859
|
+
return;
|
|
860
|
+
}
|
|
861
|
+
if (eventType !== 'content_end') {
|
|
862
|
+
return;
|
|
863
|
+
}
|
|
864
|
+
const toolUse = pendingTools.get(toolCallId);
|
|
865
|
+
if (!toolUse) {
|
|
866
|
+
return;
|
|
867
|
+
}
|
|
868
|
+
const isError = typeof event.error === 'string' && event.error.length > 0;
|
|
869
|
+
if (attempt.executedToolCallIds.has(toolCallId) && !attempt.completed.has(toolCallId)) {
|
|
870
|
+
attempt.completed.set(toolCallId, {
|
|
871
|
+
toolUse,
|
|
872
|
+
toolResult: {
|
|
873
|
+
type: 'tool_result',
|
|
874
|
+
tool_use_id: toolCallId,
|
|
875
|
+
content: normalizeToolOutput(isError ? event.error : event.output),
|
|
876
|
+
is_error: isError,
|
|
877
|
+
},
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
pendingTools.delete(toolCallId);
|
|
881
|
+
attempt.claimedToolCallIds.delete(toolCallId);
|
|
882
|
+
callbacks?.onToolComplete?.(toolUse.name, toolCallId, isError);
|
|
883
|
+
}
|
|
884
|
+
removeStableRoute(routeId) {
|
|
885
|
+
for (const [stableRouteId, mappedRouteId] of this.stableRoutes) {
|
|
886
|
+
if (mappedRouteId === routeId) {
|
|
887
|
+
this.stableRoutes.delete(stableRouteId);
|
|
888
|
+
}
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
markRouteForRebuild(routeId) {
|
|
892
|
+
this.routesRequiringRebuild.delete(routeId);
|
|
893
|
+
this.routesRequiringRebuild.add(routeId);
|
|
894
|
+
while (this.routesRequiringRebuild.size > this.maxSessions) {
|
|
895
|
+
const oldest = this.routesRequiringRebuild.values().next().value;
|
|
896
|
+
if (!oldest) {
|
|
897
|
+
break;
|
|
898
|
+
}
|
|
899
|
+
this.routesRequiringRebuild.delete(oldest);
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
async retireRoute(runtime, routeId, signal) {
|
|
903
|
+
const session = this.sessions.get(routeId);
|
|
904
|
+
if (!session) {
|
|
905
|
+
return;
|
|
906
|
+
}
|
|
907
|
+
await raceWithAbort(runtime.client.stop(session.hubSessionId).catch(() => undefined), signal);
|
|
908
|
+
this.sessions.delete(routeId);
|
|
909
|
+
this.removeStableRoute(routeId);
|
|
910
|
+
}
|
|
911
|
+
async retireStaleSessions(runtime, protectedRouteId, signal) {
|
|
912
|
+
const expiry = Date.now() - this.sessionTtlMs;
|
|
913
|
+
const expired = [...this.sessions.entries()]
|
|
914
|
+
.filter(([routeId, session]) => routeId !== protectedRouteId &&
|
|
915
|
+
!this.activeRoutes.has(routeId) &&
|
|
916
|
+
!session.activeAttempt &&
|
|
917
|
+
session.lastActiveAt < expiry)
|
|
918
|
+
.map(([routeId]) => routeId);
|
|
919
|
+
for (const routeId of expired) {
|
|
920
|
+
await this.retireRoute(runtime, routeId, signal);
|
|
921
|
+
}
|
|
922
|
+
if (this.sessions.has(protectedRouteId)) {
|
|
923
|
+
return;
|
|
924
|
+
}
|
|
925
|
+
while (this.sessions.size >= this.maxSessions) {
|
|
926
|
+
const oldest = [...this.sessions.entries()]
|
|
927
|
+
.filter(([routeId, session]) => !this.activeRoutes.has(routeId) && !session.activeAttempt)
|
|
928
|
+
.sort((left, right) => left[1].lastActiveAt - right[1].lastActiveAt)[0]?.[0];
|
|
929
|
+
if (!oldest) {
|
|
930
|
+
return;
|
|
931
|
+
}
|
|
932
|
+
await this.retireRoute(runtime, oldest, signal);
|
|
933
|
+
}
|
|
934
|
+
}
|
|
935
|
+
normalizeError(error) {
|
|
936
|
+
if (error instanceof model_runner_js_1.ModelRunnerError ||
|
|
937
|
+
error instanceof model_runner_js_1.HostToolAbortError ||
|
|
938
|
+
error instanceof model_runner_js_1.HostToolTerminalError ||
|
|
939
|
+
error instanceof types_js_1.McpCompletedMutationInterruptedError ||
|
|
940
|
+
error instanceof types_js_1.McpResultMissingError) {
|
|
941
|
+
return error;
|
|
942
|
+
}
|
|
943
|
+
const rawMessage = error instanceof Error ? error.message : String(error);
|
|
944
|
+
const failure = safeProviderFailure(rawMessage, 'exception');
|
|
945
|
+
return new model_runner_js_1.ModelRunnerError(failure.message, failure.code, failure.code !== 'auth_failure');
|
|
946
|
+
}
|
|
947
|
+
getSessionPolicyStatus(options) {
|
|
948
|
+
const routeId = options.sessionId ?? options.sessionKey ?? this.sessionId;
|
|
949
|
+
const session = this.sessions.get(routeId);
|
|
950
|
+
if (!session) {
|
|
951
|
+
return 'missing';
|
|
952
|
+
}
|
|
953
|
+
const allowedTools = options.allowedTools ?? this.options.allowedTools ?? [];
|
|
954
|
+
const disallowedTools = options.disallowedTools ?? this.options.disallowedTools ?? [];
|
|
955
|
+
return session.policyFingerprint === options.sessionPolicyFingerprint &&
|
|
956
|
+
session.toolFingerprint ===
|
|
957
|
+
toolFingerprint(options.hostToolBridge, allowedTools, disallowedTools, options.allowSpawnAgent ?? this.options.allowSpawnAgent ?? false, options.allowAgentTeams ?? this.options.allowAgentTeams ?? false)
|
|
958
|
+
? 'compatible'
|
|
959
|
+
: 'mismatch';
|
|
960
|
+
}
|
|
961
|
+
setSessionId(id) {
|
|
962
|
+
this.sessionId = id;
|
|
963
|
+
}
|
|
964
|
+
setSystemPrompt(prompt) {
|
|
965
|
+
this.systemPrompt = prompt;
|
|
966
|
+
}
|
|
967
|
+
async sendMessage(content, callbacks) {
|
|
968
|
+
return this.prompt(content, callbacks, { resumeSession: true });
|
|
969
|
+
}
|
|
970
|
+
getSessionId() {
|
|
971
|
+
return this.sessionId;
|
|
972
|
+
}
|
|
973
|
+
isHealthy() {
|
|
974
|
+
return !this.stopped;
|
|
975
|
+
}
|
|
976
|
+
isReady() {
|
|
977
|
+
return !this.stopped;
|
|
978
|
+
}
|
|
979
|
+
getMetrics() {
|
|
980
|
+
return {
|
|
981
|
+
requestCount: this.requestCount,
|
|
982
|
+
failureCount: this.failureCount,
|
|
983
|
+
avgLatencyMs: this.requestCount > 0 ? Math.round(this.totalLatencyMs / this.requestCount) : 0,
|
|
984
|
+
lastRequestAt: this.lastRequestAt,
|
|
985
|
+
};
|
|
986
|
+
}
|
|
987
|
+
async stop() {
|
|
988
|
+
if (this.stopped) {
|
|
989
|
+
return;
|
|
990
|
+
}
|
|
991
|
+
this.stopped = true;
|
|
992
|
+
const pendingRuntime = this.runtimePromise;
|
|
993
|
+
const runtime = pendingRuntime ? await this.waitForCleanup(pendingRuntime, 1_000, null) : null;
|
|
994
|
+
if (!runtime) {
|
|
995
|
+
this.sessions.clear();
|
|
996
|
+
this.stableRoutes.clear();
|
|
997
|
+
this.routesRequiringRebuild.clear();
|
|
998
|
+
if (pendingRuntime) {
|
|
999
|
+
void pendingRuntime
|
|
1000
|
+
.then((lateRuntime) => this.disposeRuntimeOnce(lateRuntime, 'mama_shutdown'))
|
|
1001
|
+
.catch(() => undefined);
|
|
1002
|
+
}
|
|
1003
|
+
return;
|
|
1004
|
+
}
|
|
1005
|
+
const sessions = [...this.sessions.values()];
|
|
1006
|
+
const shutdownError = new model_runner_js_1.ModelRunnerError('Cline Hub adapter is shutting down', 'crash', false);
|
|
1007
|
+
for (const session of sessions) {
|
|
1008
|
+
session.activeAttempt?.controller.abort(shutdownError);
|
|
1009
|
+
if (session.activeAttempt) {
|
|
1010
|
+
void runtime.client.abort(session.hubSessionId, shutdownError).catch(() => undefined);
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
const inFlight = sessions.flatMap((session) => [
|
|
1014
|
+
...(session.activeAttempt?.inFlightTools ?? []),
|
|
1015
|
+
]);
|
|
1016
|
+
if (inFlight.length > 0) {
|
|
1017
|
+
await this.waitForToolSettlement(inFlight);
|
|
1018
|
+
}
|
|
1019
|
+
this.sessions.clear();
|
|
1020
|
+
this.stableRoutes.clear();
|
|
1021
|
+
this.routesRequiringRebuild.clear();
|
|
1022
|
+
this.activeRoutes.clear();
|
|
1023
|
+
void Promise.allSettled(sessions.map((session) => runtime.client.stop(session.hubSessionId)));
|
|
1024
|
+
await this.waitForCleanup(this.disposeRuntimeOnce(runtime, 'mama_shutdown'), 1_000, undefined);
|
|
1025
|
+
}
|
|
1026
|
+
async waitForCleanup(operation, timeoutMs, fallback) {
|
|
1027
|
+
let timeoutHandle;
|
|
1028
|
+
const timeout = new Promise((resolvePromise) => {
|
|
1029
|
+
timeoutHandle = setTimeout(() => resolvePromise(fallback), timeoutMs);
|
|
1030
|
+
timeoutHandle.unref();
|
|
1031
|
+
});
|
|
1032
|
+
const result = await Promise.race([operation, timeout]);
|
|
1033
|
+
if (timeoutHandle) {
|
|
1034
|
+
clearTimeout(timeoutHandle);
|
|
1035
|
+
}
|
|
1036
|
+
return result;
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
exports.ClineCLIAdapter = ClineCLIAdapter;
|
|
1040
|
+
//# sourceMappingURL=cline-cli-adapter.js.map
|