clay-server 5.2.0-beta.5 → 5.2.0-beta.6

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.
Files changed (151) hide show
  1. package/lib/claude-hook-installer.js +1 -267
  2. package/lib/claude-jsonl-watcher.js +1 -204
  3. package/lib/clay-skill-install.js +1 -33
  4. package/lib/cli-sessions.js +1 -300
  5. package/lib/codex-defaults.js +1 -28
  6. package/lib/context-usage.js +3 -2
  7. package/lib/daemon.js +5 -55
  8. package/lib/default-ai-runtime.js +4 -8
  9. package/lib/email-mcp-server.js +1 -1
  10. package/lib/kiro-defaults.js +1 -22
  11. package/lib/mcp-proxy.js +2 -32
  12. package/lib/mcp-query-bridge.js +1 -1
  13. package/lib/mcp-source-adapters.js +1 -91
  14. package/lib/mcp-source-context.js +1 -42
  15. package/lib/mcp-source-discovery.js +1 -169
  16. package/lib/mcp-source-plugins.js +1 -68
  17. package/lib/mcp-source-restrictions.js +1 -47
  18. package/lib/mcp-tool-policy.js +1 -26
  19. package/lib/os-user-diagnostics.js +2 -4
  20. package/lib/os-users.js +4 -65
  21. package/lib/project-connection.js +8 -7
  22. package/lib/project-http.js +4 -4
  23. package/lib/project-mcp.js +2 -2
  24. package/lib/project-pair-result-delivery.js +2 -2
  25. package/lib/project-pair-usage.js +12 -13
  26. package/lib/project-pending-message-queue.js +3 -1
  27. package/lib/project-session-history-actions.js +5 -3
  28. package/lib/project-session-pair.js +1 -1
  29. package/lib/project-session-runtime-actions.js +2 -1
  30. package/lib/project-session-spawn.js +2 -3
  31. package/lib/project-session-vendor.js +2 -1
  32. package/lib/project-sessions.js +18 -26
  33. package/lib/project-user-message.js +1 -0
  34. package/lib/project-vendor-login.js +6 -36
  35. package/lib/public/app.js +1 -0
  36. package/lib/public/css/messages.css +6 -2
  37. package/lib/public/modules/app-favicon.js +11 -2
  38. package/lib/public/modules/app-header.js +4 -2
  39. package/lib/public/modules/app-loop-ui.js +2 -0
  40. package/lib/public/modules/app-messages.js +36 -5
  41. package/lib/public/modules/app-notifications.js +1 -2
  42. package/lib/public/modules/app-panels.js +61 -123
  43. package/lib/public/modules/app-rate-limit.js +7 -27
  44. package/lib/public/modules/chat-render-runtime.js +3 -0
  45. package/lib/public/modules/mcp-connection-view.js +1 -1
  46. package/lib/public/modules/permission-control.js +5 -4
  47. package/lib/public/modules/scheduler.js +2 -0
  48. package/lib/public/modules/session-create-form.js +10 -10
  49. package/lib/public/modules/settings-defaults.js +27 -28
  50. package/lib/public/modules/tools.js +2 -1
  51. package/lib/public/modules/tui-grab.js +1 -2
  52. package/lib/public/modules/vendor-login-browser.js +5 -3
  53. package/lib/public/modules/vendor-login.js +2 -2
  54. package/lib/public/modules/vendor-priority.js +15 -1
  55. package/lib/public/muse-avatar.svg +4 -0
  56. package/lib/safe-bash-commands.js +3 -45
  57. package/lib/sdk-bridge.js +127 -395
  58. package/lib/sdk-foreground-admission.js +16 -0
  59. package/lib/sdk-mcp-descriptors.js +2 -37
  60. package/lib/sdk-message-processor.js +50 -17
  61. package/lib/sdk-quota-snapshot.js +1 -1
  62. package/lib/sdk-response-recovery.js +1 -155
  63. package/lib/sdk-worker.js +2 -677
  64. package/lib/server.js +1 -1
  65. package/lib/session-fork-history.js +21 -0
  66. package/lib/session-hygiene.js +3 -35
  67. package/lib/session-permission-mode.js +4 -3
  68. package/lib/session-skill-scope.js +11 -0
  69. package/lib/sessions.js +17 -89
  70. package/lib/tool-llm.js +1 -1
  71. package/lib/tui-transcript-index.js +1 -132
  72. package/lib/vendor-login-browser.js +1 -11
  73. package/lib/yoke/acp-agent-profiles.js +5 -3
  74. package/lib/yoke/adapters/antigravity.js +3 -14
  75. package/lib/yoke/adapters/claude-query-contract.js +9 -0
  76. package/lib/yoke/adapters/claude.js +7 -42
  77. package/lib/yoke/adapters/codex-query-contract.js +24 -0
  78. package/lib/yoke/adapters/codex.js +1 -0
  79. package/lib/yoke/adapters/kiro.js +3 -1
  80. package/lib/yoke/adapters/muse-query-contract.js +7 -0
  81. package/lib/yoke/adapters/muse.js +122 -0
  82. package/lib/yoke/auth-events.js +17 -0
  83. package/lib/yoke/claude-hook-installer.js +267 -0
  84. package/lib/yoke/claude-jsonl-watcher.js +204 -0
  85. package/lib/yoke/claude-maintenance.js +55 -0
  86. package/lib/yoke/claude-permission-patterns.js +53 -0
  87. package/lib/yoke/claude-response-recovery.js +155 -0
  88. package/lib/yoke/claude-transcript-hygiene.js +34 -0
  89. package/lib/yoke/clay-skill-install.js +33 -0
  90. package/lib/yoke/cli-sessions.js +300 -0
  91. package/lib/yoke/codex-app-server.js +7 -12
  92. package/lib/yoke/configuration.js +13 -0
  93. package/lib/yoke/discovery.js +70 -0
  94. package/lib/yoke/errors.js +8 -0
  95. package/lib/yoke/host-environment.js +7 -0
  96. package/lib/yoke/index.js +9 -51
  97. package/lib/yoke/interface.js +116 -0
  98. package/lib/yoke/kiro-acp-server.js +5 -5
  99. package/lib/yoke/legacy-sessions.js +89 -0
  100. package/lib/yoke/login-protocol.js +25 -0
  101. package/lib/yoke/maintenance.js +12 -0
  102. package/lib/yoke/mcp-proxy.js +32 -0
  103. package/lib/yoke/mcp-source-adapters.js +91 -0
  104. package/lib/yoke/mcp-source-context.js +42 -0
  105. package/lib/yoke/mcp-source-discovery.js +169 -0
  106. package/lib/yoke/mcp-source-plugins.js +68 -0
  107. package/lib/yoke/mcp-source-restrictions.js +47 -0
  108. package/lib/yoke/mcp-tool-policy-normalize.js +28 -0
  109. package/lib/yoke/model-preferences.js +6 -0
  110. package/lib/yoke/muse-artifacts.js +36 -0
  111. package/lib/yoke/muse-controls.js +50 -0
  112. package/lib/yoke/muse-input.js +64 -0
  113. package/lib/yoke/muse-items.js +157 -0
  114. package/lib/yoke/muse-policy.js +52 -0
  115. package/lib/yoke/muse-query.js +428 -0
  116. package/lib/yoke/muse-runtime.js +211 -0
  117. package/lib/yoke/muse-services.js +79 -0
  118. package/lib/yoke/muse-skills.js +79 -0
  119. package/lib/yoke/muse-turns.js +71 -0
  120. package/lib/yoke/options/acp.js +2 -0
  121. package/lib/yoke/options/antigravity.js +2 -0
  122. package/lib/yoke/options/claude.js +21 -0
  123. package/lib/yoke/options/codex-defaults.js +29 -0
  124. package/lib/yoke/options/codex-settings.js +21 -0
  125. package/lib/yoke/options/codex.js +6 -0
  126. package/lib/yoke/options/kiro-defaults.js +22 -0
  127. package/lib/yoke/options/kiro.js +5 -0
  128. package/lib/yoke/options/muse.js +5 -0
  129. package/lib/yoke/provider-contract.js +5 -0
  130. package/lib/yoke/providers/antigravity-executable.js +8 -0
  131. package/lib/yoke/providers/claude-executable.js +40 -0
  132. package/lib/yoke/providers/claude-model-descriptions.js +14 -0
  133. package/lib/yoke/providers/claude-process.js +97 -0
  134. package/lib/yoke/providers/claude-provision.js +75 -0
  135. package/lib/yoke/providers/codex-errors.js +8 -0
  136. package/lib/yoke/providers/muse-executable.js +17 -0
  137. package/lib/yoke/provisioning.js +6 -0
  138. package/lib/yoke/query-options.js +10 -0
  139. package/lib/yoke/response-recovery.js +41 -0
  140. package/lib/yoke/sdk-mcp-descriptors.js +37 -0
  141. package/lib/yoke/sdk-server-factory.js +7 -0
  142. package/lib/yoke/session-history.js +8 -0
  143. package/lib/yoke/session-tool-transport.js +31 -13
  144. package/lib/yoke/settings.js +23 -0
  145. package/lib/yoke/source-locations.js +4 -0
  146. package/lib/yoke/title-query.js +18 -7
  147. package/lib/yoke/tui-transcript-index.js +132 -0
  148. package/lib/yoke/usage.js +48 -0
  149. package/lib/yoke/user-input.js +13 -0
  150. package/lib/yoke/vendor-registry.js +81 -1
  151. package/package.json +3 -2
@@ -0,0 +1,157 @@
1
+ function itemInput(item) {
2
+ if (!item || typeof item.args !== "string") return {};
3
+ try {
4
+ return JSON.parse(item.args);
5
+ } catch (e) {
6
+ return {
7
+ rawArgs: item.args
8
+ };
9
+ }
10
+ }
11
+
12
+ function toolName(item) {
13
+ var name = String(item && (item.tool || item.toolName) || "Tool").toLowerCase();
14
+ if (name.indexOf("shell") !== -1 || name.indexOf("command") !== -1) return "Bash";
15
+ if (name.indexOf("read") !== -1) return "Read";
16
+ if (name.indexOf("write") !== -1 || name.indexOf("create") !== -1) return "Write";
17
+ if (name.indexOf("edit") !== -1 || name.indexOf("delete") !== -1) return "Edit";
18
+ if (name.indexOf("search") !== -1 || name.indexOf("grep") !== -1) return "Grep";
19
+ return item && (item.tool || item.toolName) || "Tool";
20
+ }
21
+
22
+ function createRenderer(state, push) {
23
+ var streamedItems = {};
24
+ var openBlocks = {};
25
+ var notices = {};
26
+ function closeBlocks(turnId) {
27
+ Object.keys(openBlocks).forEach(function(id) {
28
+ if (turnId && openBlocks[id] !== turnId) return;
29
+ push({
30
+ yokeType: "block_stop",
31
+ blockId: id
32
+ });
33
+ delete openBlocks[id];
34
+ });
35
+ if (!turnId) { state.thinkingBlocks = {}; state.textBlocks = {}; state.toolBlocks = {}; }
36
+ }
37
+ function emitNotice(item, id) {
38
+ if (item.status === "inProgress" || item.kind === "userMessage") return;
39
+ var failed = ["failed", "rejected", "timedOut"].includes(item.status)
40
+ || (item.kind === "compaction" && item.outcome === "failed")
41
+ || (item.kind === "hookRun" && ["failed", "blocked", "timedOut"].includes(item.runStatus))
42
+ || (item.kind === "subagent" && item.result && item.result.errorKind);
43
+ var text = "";
44
+ if (failed) {
45
+ var labels = { reminderChild: "A background task", hookRun: "A hook", compaction: "Context maintenance", sideChat: "A side conversation", subagent: "A task", workflow: "A workflow", userShell: "A command", webSearch: "A search" };
46
+ var label = labels[item.kind] || "A Muse operation";
47
+ // Unknown kinds have no established human-facing fields. Do not dump them.
48
+ var detail = labels[item.kind] ? (item.failureReason || item.reason || item.message || "") : "";
49
+ if (item.kind === "subagent" && !detail && item.result) detail = item.result.summary || "";
50
+ text = label + " failed" + (detail ? ": " + detail : ".");
51
+ } else if (item.status === "completed") {
52
+ // Only documented action results belong in chat. Reminder/hook/compaction/
53
+ // side-chat bookkeeping and unknown protocol fallback text stay silent.
54
+ if (item.kind === "subagent" && item.result) text = item.result.text || item.result.summary || "";
55
+ else if (item.kind === "workflow") text = item.finalSummary || item.message || "";
56
+ else if (item.kind === "userShell") text = item.visibleOutput || "";
57
+ else if (item.kind === "webSearch") text = item.fallbackText || "";
58
+ }
59
+ var key = id + (failed ? ":failure" : ":summary");
60
+ if (typeof text !== "string" || !text.trim() || notices[key]) return;
61
+ notices[key] = true;
62
+ push({ yokeType: "informational", level: failed ? "warning" : "info", content: text });
63
+ }
64
+ function emitItem(item) {
65
+ if (!item || state.stopped) return;
66
+ var id = item.itemId || "muse-item";
67
+ if (item.kind === "agentMessage" || item.kind === "reasoning") {
68
+ var previous = state.textBlocks[id] || "";
69
+ var value = item.kind === "reasoning" && Array.isArray(item.summary) ? item.summary.join("\n") : item.text || "";
70
+ var blockId = state.thinkingBlocks[id] || id;
71
+ if (item.kind === "reasoning") state.thinkingBlocks[id] = blockId;
72
+ if (!previous && value) {
73
+ openBlocks[blockId] = item.turnId;
74
+ push({
75
+ yokeType: item.kind === "reasoning" ? "thinking_start" : "text_start",
76
+ blockId: blockId
77
+ });
78
+ }
79
+ if (value.length > previous.length) push({
80
+ yokeType: item.kind === "reasoning" ? "thinking_delta" : "text_delta",
81
+ blockId: blockId,
82
+ text: value.substring(previous.length)
83
+ });
84
+ if (value.length >= previous.length) state.textBlocks[id] = value;
85
+ if (item.status !== "inProgress" && openBlocks[blockId]) {
86
+ push({
87
+ yokeType: "block_stop",
88
+ blockId: blockId
89
+ });
90
+ delete openBlocks[blockId];
91
+ }
92
+ return;
93
+ }
94
+ if (item.kind === "toolCall") {
95
+ if (!state.toolBlocks[id]) {
96
+ state.toolBlocks[id] = true;
97
+ push({
98
+ yokeType: "tool_start",
99
+ blockId: id,
100
+ toolId: id,
101
+ toolName: toolName(item)
102
+ });
103
+ push({
104
+ yokeType: "tool_executing",
105
+ blockId: id,
106
+ toolId: id,
107
+ toolName: toolName(item),
108
+ input: itemInput(item)
109
+ });
110
+ }
111
+ if (item.status && item.status !== "inProgress" && state.toolBlocks[id] !== "completed") {
112
+ state.toolBlocks[id] = "completed";
113
+ push({
114
+ yokeType: "tool_result",
115
+ blockId: id,
116
+ toolId: id,
117
+ content: item.visibleOutput || item.message || item.failureReason || "",
118
+ isError: item.status !== "completed"
119
+ });
120
+ }
121
+ return;
122
+ }
123
+ emitNotice(item, id);
124
+ }
125
+ function renderFrame(frame) {
126
+ var params = frame.params || {};
127
+ var item = params.item;
128
+ var owner = item && item.turnId || streamedItems[params.itemId] && streamedItems[params.itemId].turnId;
129
+ if (!(state.liveTurnIds && state.liveTurnIds.has(owner) || state.activeTurn && owner === state.activeTurn.turnId)) return false;
130
+ if (item) streamedItems[item.itemId] = Object.assign({}, item); else if (frame.method === "item/delta") {
131
+ item = streamedItems[params.itemId];
132
+ if (item) {
133
+ var field = params.field || "text";
134
+ if (field.indexOf("summary.") === 0) {
135
+ var index = Number(field.split(".")[1]);
136
+ item.summary = (item.summary || []).slice();
137
+ item.summary[index] = (item.summary[index] || "") + params.delta;
138
+ } else if (field === "text") item.text = (item.text || "") + params.delta; else if (field === "output") item.visibleOutput = (item.visibleOutput || "") + params.delta;
139
+ }
140
+ }
141
+ if (item) emitItem(item);
142
+ return true;
143
+ }
144
+ return {
145
+ emitItem: emitItem,
146
+ renderFrame: renderFrame,
147
+ closeBlocks: closeBlocks,
148
+ hasItem: function(id) {
149
+ return !!streamedItems[id];
150
+ }
151
+ };
152
+ }
153
+
154
+ module.exports = {
155
+ createRenderer: createRenderer,
156
+ itemInput: itemInput
157
+ };
@@ -0,0 +1,52 @@
1
+ var itemInput = require("./muse-items").itemInput;
2
+
3
+ function normalizeMcpServers(servers) {
4
+ var config = {};
5
+ if (servers == null) return config;
6
+ if (!Array.isArray(servers)) throw new Error("Invalid Muse session MCP servers");
7
+ for (var i = 0; i < servers.length; i++) {
8
+ var server = servers[i] || {};
9
+ if (!server.name || !server.command || typeof server.name !== "string" || typeof server.command !== "string" || !Array.isArray(server.args || [])) throw new Error("Invalid Muse session MCP server");
10
+ if (["__proto__", "constructor", "prototype"].includes(server.name) || Object.prototype.hasOwnProperty.call(config, server.name)) throw new Error("Invalid or duplicate Muse MCP server name");
11
+ var env = {};
12
+ var entries = Array.isArray(server.env) ? server.env : [];
13
+ for (var j = 0; j < entries.length; j++) if (entries[j] && entries[j].name) env[entries[j].name] = String(entries[j].value == null ? "" : entries[j].value);
14
+ config[server.name] = {
15
+ transport: "stdio",
16
+ command: server.command,
17
+ args: server.args || [],
18
+ env: env,
19
+ mode: "required"
20
+ };
21
+ }
22
+ return config;
23
+ }
24
+
25
+ function chooseApprovalDecision(request, canUseTool, signal) {
26
+ var choices = Array.isArray(request && request.availableChoices) ? request.availableChoices : [];
27
+ if (!choices.length || typeof canUseTool !== "function") return Promise.reject(new Error("Muse approval cannot be decided safely"));
28
+ if (signal && signal.aborted) return Promise.reject(new Error("Muse approval cancelled"));
29
+ return Promise.resolve(canUseTool(request.toolName || "Tool", itemInput({
30
+ args: request.rawArgs
31
+ }), {
32
+ request: request,
33
+ signal: signal
34
+ })).then(function(result) {
35
+ if (signal && signal.aborted) throw new Error("Muse approval cancelled");
36
+ var allowed = result && result.behavior === "allow";
37
+ if (!allowed && !(result && result.behavior === "deny")) throw new Error("Muse approval returned an unsupported decision");
38
+ for (var i = 0; i < choices.length; i++) if (choices[i].scope === "once" && (choices[i].decision === (allowed ? "approved" : "denied") || !allowed && choices[i].decision === "abort")) {
39
+ var decision = {
40
+ choiceId: choices[i].choiceId
41
+ };
42
+ if (choices[i].acceptsFeedback && result.message) decision.feedback = result.message;
43
+ return decision;
44
+ }
45
+ throw new Error("Muse approval has no matching safe choice");
46
+ });
47
+ }
48
+
49
+ module.exports = {
50
+ normalizeMcpServers: normalizeMcpServers,
51
+ chooseApprovalDecision: chooseApprovalDecision
52
+ };
@@ -0,0 +1,428 @@
1
+ var queryAbort = require("./query-abort");
2
+
3
+ var runtimeTools = require("./muse-runtime");
4
+
5
+ var policy = require("./muse-policy");
6
+
7
+ function createMuseQueryHandle(adapter, queryOpts) {
8
+ var state = {
9
+ client: null,
10
+ connection: null,
11
+ session: null,
12
+ sessionId: queryOpts.resumeSessionId || null,
13
+ model: queryOpts.model || null,
14
+ effort: queryOpts.effort || null,
15
+ toolPolicy: "ask",
16
+ messages: [],
17
+ messageSequence: 0,
18
+ active: false,
19
+ ended: false,
20
+ inputEnded: false,
21
+ stopped: false,
22
+ events: [],
23
+ waiter: null,
24
+ textBlocks: {},
25
+ thinkingBlocks: {},
26
+ toolBlocks: {},
27
+ activeTurn: null,
28
+ liveTurnIds: new Set(),
29
+ abortController: queryOpts.abortController || new AbortController(),
30
+ started: false
31
+ };
32
+ var removeAbort = function() {};
33
+ var handle;
34
+ var failure = null;
35
+ var cleanup = null;
36
+ var runtime = null;
37
+ var itemFrames = [];
38
+ var skillDelivery = require("./muse-skills").create(Object.assign({}, queryOpts, { cwd: queryOpts.cwd || adapter.cwd }), function() { return runtime; }, push, assertLive);
39
+ var emitArtifact = require("./muse-artifacts").create(function() { return runtime; }, push);
40
+ var renderer = require("./muse-items").createRenderer(state, push);
41
+ var turns = require("./muse-turns").create({ state: state, renderer: renderer, emitArtifact: emitArtifact,
42
+ runtime: function() { return runtime; }, ready: flushFrames, push: push, outcomeEvent: outcomeEvent, fail: fail, close: function() { return handle.close(); } });
43
+ function push(event) {
44
+ if (state.stopped || state.ended) return;
45
+ if (state.waiter) {
46
+ var resolve = state.waiter;
47
+ state.waiter = null;
48
+ resolve({
49
+ value: event,
50
+ done: false
51
+ });
52
+ } else state.events.push(event);
53
+ }
54
+ function finish() {
55
+ if (state.waiter) {
56
+ var resolve = state.waiter;
57
+ state.waiter = null;
58
+ resolve({
59
+ value: undefined,
60
+ done: true
61
+ });
62
+ }
63
+ }
64
+ function assertLive() {
65
+ if (state.stopped || state.ended || adapter.shuttingDown) throw new Error("Muse Code query was stopped");
66
+ }
67
+ function activateTurn(turn) {
68
+ state.activeTurn = turn;
69
+ }
70
+ function flushFrames() {
71
+ var frames = itemFrames.splice(0);
72
+ for (var i = 0; i < frames.length; i++) renderer.renderFrame(frames[i]);
73
+ }
74
+ function chooseApproval(request) {
75
+ if (state.stopped || state.abortController.signal.aborted) return Promise.reject(new Error("Muse approval cancelled"));
76
+ return runtime.wait(policy.chooseApprovalDecision(request, queryOpts.canUseTool, state.abortController.signal));
77
+ }
78
+ function fail(error) {
79
+ if (state.stopped || failure) return;
80
+ failure = error;
81
+ state.messages = [];
82
+ push(runtimeTools.isAuthError(error) ? {
83
+ yokeType: "auth_required",
84
+ vendor: "muse"
85
+ } : {
86
+ yokeType: "error",
87
+ text: error.message || String(error)
88
+ });
89
+ handle.close().catch(function(closeError) {
90
+ adapter.lastCloseError = closeError;
91
+ });
92
+ }
93
+ async function selectModel(model) {
94
+ if (!model) return null;
95
+ if (!adapter.catalog.some(function(row) {
96
+ return row.value === model;
97
+ })) {
98
+ var result = await runtime.waitRequest(state.connection.request("model/list", {}));
99
+ adapter.catalog = runtimeTools.normalizeCatalog(result);
100
+ }
101
+ assertLive();
102
+ return runtimeTools.modelSelection(adapter.catalog, model);
103
+ }
104
+ function validateEffort(effort) {
105
+ var vocabulary = [ "none", "minimal", "low", "medium", "high", "xhigh", "max", "ultra" ];
106
+ if (!vocabulary.includes(effort)) throw new Error("Unsupported Muse reasoning effort: " + effort);
107
+ var row = adapter.catalog.find(function(model) {
108
+ return model.value === state.model;
109
+ });
110
+ if (row && !row.effortUnknown && !row.supportedEffortLevels.includes(effort)) {
111
+ throw new Error("Muse model does not support reasoning effort: " + effort);
112
+ }
113
+ }
114
+ async function ensureSession() {
115
+ assertLive();
116
+ if (state.session) return state.session;
117
+ var sdk = await adapter.loadSdk();
118
+ assertLive();
119
+ runtime = runtimeTools.createRuntime(adapter, sdk, {
120
+ command: adapter.binaryPath,
121
+ args: [ "serve" ],
122
+ cwd: queryOpts.cwd || adapter.cwd,
123
+ userInputDialogs: queryOpts.userInputMode !== "fallback" && typeof queryOpts.onUserInputRequest === "function",
124
+ env: Object.assign({}, process.env, queryOpts.env || {})
125
+ });
126
+ runtime.fail = fail;
127
+ runtime.onUserInput = require("./muse-input").createRouter(runtime, queryOpts, state.abortController.signal);
128
+ runtime.onFrame = function(frame) {
129
+ turns.onFrame(frame);
130
+ if (frame.method.indexOf("item/") === 0) {
131
+ if (!renderer.renderFrame(frame)) itemFrames.push(frame);
132
+ }
133
+ if (frame.method === "session/modelChanged") {
134
+ var previousModel = state.model;
135
+ state.model = frame.params.modelId;
136
+ if (typeof queryOpts.onModelSwitch === "function" && previousModel && previousModel !== state.model) queryOpts.onModelSwitch({ fromModel: previousModel, toModel: state.model, source: frame.params.source });
137
+ }
138
+ if (frame.method === "userInput/settled") runtime.onUserInput.settle(frame.params.userInputId);
139
+ if (frame.method === "userInput/requested") runtime.onUserInput(frame.params).catch(fail);
140
+ if (frame.method === "usage/changed") {
141
+ var quota = require("./muse-services").quotaEvent(frame.params);
142
+ if (quota) push(quota);
143
+ }
144
+ if (frame.method === "session/contextUsage") state.contextUsage = frame.params;
145
+ if (frame.method === "approval/requested" && queryOpts.resumeSessionId && !state.started) {
146
+ state.resumedTurnId = state.resumedTurnId || frame.params.turnId;
147
+ }
148
+ };
149
+ var spawned = await runtime.initialize();
150
+ assertLive();
151
+ state.connection = spawned.connection;
152
+ var museOpts = queryOpts.adapterOptions && queryOpts.adapterOptions.MUSE || {};
153
+ var mcpServers = policy.normalizeMcpServers(museOpts.mcpServers);
154
+ var hasMcp = Object.keys(mcpServers).length > 0;
155
+ var config = hasMcp ? {
156
+ mcpServers: mcpServers
157
+ } : undefined;
158
+ if (hasMcp && !(spawned.initializeResult.grantedCapabilities || []).includes("sessionMcp")) {
159
+ throw new Error("Muse host does not support the required sessionMcp capability");
160
+ }
161
+ var selection = await selectModel(state.model);
162
+ if (state.effort) validateEffort(state.effort);
163
+ var verb = state.sessionId ? "session/resume" : "session/start";
164
+ var params = state.sessionId ? {
165
+ sessionId: state.sessionId,
166
+ config: config,
167
+ history: "inline"
168
+ } : {
169
+ workspaceRoot: queryOpts.cwd || adapter.cwd,
170
+ config: config,
171
+ approvalMode: museOpts.readOnly ? "denyUnmatched" : "onRequest"
172
+ };
173
+ if (selection && verb === "session/start") {
174
+ params.modelId = selection.modelId;
175
+ if (selection.providerId) params.providerId = selection.providerId;
176
+ }
177
+ var result = await runtime.waitRequest(state.connection.command(verb, params));
178
+ assertLive();
179
+ state.sessionId = result.session.sessionId;
180
+ var opening = {
181
+ verb: verb,
182
+ result: result
183
+ };
184
+ state.session = new sdk.Session({
185
+ connection: state.connection,
186
+ durability: sdk.readSessionDurability(spawned.initializeResult),
187
+ opening: opening,
188
+ sessionId: state.sessionId
189
+ });
190
+ runtime.session = state.session;
191
+ state.session.onApproval(chooseApproval);
192
+ state.session.onApprovalError(function(problem) {
193
+ fail(problem.error || new Error("Muse approval failed: " + problem.kind));
194
+ });
195
+ state.session.onGapError(function(problem) {
196
+ fail(problem.error || new Error("Muse view gap could not be filled"));
197
+ });
198
+ runtimeTools.seedHistory(state.session, opening, runtime.onFrame);
199
+ state.resumedTurnId = state.session.fold.activeTurnId;
200
+ state.contextUsage = result.history && result.history.snapshot && result.history.snapshot.state.contextUsage || null;
201
+ runtime.opening = false;
202
+ var held = runtime.held.splice(0);
203
+ for (var i = 0; i < held.length; i++) runtime.apply(held[i]);
204
+ assertLive();
205
+ if (runtime.dead) throw new Error("Muse host exited while opening the session");
206
+ if (verb === "session/resume") {
207
+ await runtime.waitRequest(state.connection.command("session/setApprovalMode", {
208
+ sessionId: state.sessionId,
209
+ mode: museOpts.readOnly ? "denyUnmatched" : "onRequest"
210
+ }));
211
+ if (selection) await runtime.waitRequest(state.connection.command("session/setModel", {
212
+ sessionId: state.sessionId,
213
+ model: selection
214
+ }));
215
+ }
216
+ assertLive();
217
+ if (verb === "session/resume") {
218
+ state.resumedTurnId = state.resumedTurnId || result.session.activeTurnId || state.session.fold.activeTurnId;
219
+ if ((result.pendingRequests || []).length) {
220
+ var pending = await runtime.waitRequest(state.connection.request("approval/listPending", {
221
+ sessionId: state.sessionId
222
+ }));
223
+ for (var promptIndex = 0; promptIndex < (pending.userInputs || []).length; promptIndex++) {
224
+ var promptRequest = pending.userInputs[promptIndex];
225
+ state.resumedTurnId = state.resumedTurnId || promptRequest.turnId;
226
+ runtime.onUserInput(promptRequest).catch(fail);
227
+ }
228
+ for (var pendingIndex = 0; pendingIndex < (pending.approvals || []).length; pendingIndex++) {
229
+ var approval = pending.approvals[pendingIndex];
230
+ state.resumedTurnId = state.resumedTurnId || approval.turnId;
231
+ runtime.apply({
232
+ method: "approval/requested",
233
+ params: approval
234
+ });
235
+ }
236
+ }
237
+ }
238
+ assertLive();
239
+ push({
240
+ yokeType: "session_started",
241
+ sessionId: state.sessionId
242
+ });
243
+ return state.session;
244
+ }
245
+ function outcomeEvent(outcome) {
246
+ if (!outcome || outcome.kind === "unqueued" || outcome.kind === "completed" && outcome.params && (outcome.params.terminal === "cancelled" || outcome.params.terminal === "cancelledByUser")) return {
247
+ yokeType: "interrupted"
248
+ };
249
+ if (outcome.kind === "terminalUnknown") return {
250
+ yokeType: "error",
251
+ text: "Muse host exited before the turn outcome was known"
252
+ };
253
+ var params = outcome.params || {};
254
+ if (params.terminal === "failed") return params.error && params.error.kind === "authRequired" ? {
255
+ yokeType: "auth_required",
256
+ vendor: "muse"
257
+ } : {
258
+ yokeType: "error",
259
+ text: params.error && params.error.message || params.reason || "Muse Code turn failed."
260
+ };
261
+ if (params.terminal !== "completed") return {
262
+ yokeType: "error",
263
+ text: "Unknown Muse turn outcome: " + params.terminal
264
+ };
265
+ return {
266
+ yokeType: "result",
267
+ messageType: "assistant",
268
+ sessionId: state.sessionId,
269
+ usage: params.usage ? {
270
+ input_tokens: params.usage.inputTokens,
271
+ output_tokens: params.usage.outputTokens,
272
+ cache_read_input_tokens: params.usage.cacheReadTokens == null ? params.usage.cachedTokens : params.usage.cacheReadTokens,
273
+ cache_creation_input_tokens: params.usage.cacheWriteTokens || 0
274
+ } : null,
275
+ cost: null,
276
+ duration: params.durationMs || null
277
+ };
278
+ }
279
+ async function runMessage(text, images, skill, sequence) {
280
+ state.active = true;
281
+ try {
282
+ var session = await ensureSession();
283
+ assertLive();
284
+ if (state.resumedTurnId) {
285
+ var resumed = session.turn(state.resumedTurnId);
286
+ state.resumedTurnId = null;
287
+ activateTurn(resumed);
288
+ var resumedBoundary = await turns.follow(resumed, false);
289
+ assertLive();
290
+ if (resumedBoundary.kind === "failed" || resumedBoundary.event && resumedBoundary.event.yokeType !== "result") return;
291
+ push({ yokeType: "runtime_specific", vendor: "muse",
292
+ eventType: resumedBoundary.kind === "foreground" ? "resumed_foreground_completed" : "resumed_turn_completed", raw: resumedBoundary.outcome });
293
+ }
294
+ var prepared = await skillDelivery.prepare(text || "", skill);
295
+ assertLive();
296
+ skill = prepared.skill;
297
+ var prompt = prepared.text;
298
+ if (!state.started) {
299
+ state.started = true;
300
+ prompt = [ queryOpts.systemPrompt, queryOpts.appendSystemPrompt, prompt ].filter(function(part) {
301
+ return !!part;
302
+ }).join("\n\n");
303
+ }
304
+ state.activeTurn = null;
305
+ if (prepared.scoped) skillDelivery.check();
306
+ push({ yokeType: "turn_activity", phase: "waiting" });
307
+ var turn = await runtime.wait(session.sendUserTurn({
308
+ input: require("./muse-input").inputParts(prompt, images).concat(skill ? [{ type: "skill", selector: skill.selector, arguments: skill.arguments }] : []),
309
+ reasoningEffort: state.effort || undefined
310
+ }));
311
+ assertLive();
312
+ activateTurn(turn);
313
+ await turns.follow(turn, true, sequence);
314
+ } catch (e) {
315
+ fail(e);
316
+ } finally {
317
+ state.active = false;
318
+ state.activeTurn = null;
319
+ if (state.messages.length && !state.stopped) {
320
+ var next = state.messages.shift();
321
+ runMessage(next.text, next.images, next.skill, next.sequence).catch(function(error) {
322
+ adapter.lastCloseError = error;
323
+ });
324
+ } else if (state.inputEnded && !turns.pending()) await handle.close();
325
+ else if (!state.stopped && turns.background()) push({ yokeType: "foreground_available" });
326
+ }
327
+ }
328
+ handle = {
329
+ [Symbol.asyncIterator]: function() {
330
+ return {
331
+ next: function() {
332
+ if (state.events.length) return Promise.resolve({
333
+ value: state.events.shift(),
334
+ done: false
335
+ });
336
+ if (state.ended) return Promise.resolve({
337
+ value: undefined,
338
+ done: true
339
+ });
340
+ return new Promise(function(resolve) {
341
+ state.waiter = resolve;
342
+ });
343
+ }
344
+ };
345
+ },
346
+ pushMessage: function(text, images, skill) {
347
+ if (state.stopped || state.ended || state.inputEnded) return false;
348
+ state.messages.push({
349
+ text: text, sequence: ++state.messageSequence,
350
+ images: images, skill: skill
351
+ });
352
+ if (!state.active) {
353
+ var next = state.messages.shift();
354
+ runMessage(next.text, next.images, next.skill, next.sequence).catch(function(error) {
355
+ adapter.lastCloseError = error;
356
+ });
357
+ }
358
+ return true;
359
+ },
360
+ // Clay's callback remains the authority even when its UI permits all tools.
361
+ setToolPolicy: async function(value) {
362
+ assertLive();
363
+ if (["ask", "allow-all"].indexOf(value) < 0) throw new Error("Unsupported Muse tool policy: " + value);
364
+ state.toolPolicy = value;
365
+ return { policy: value, nativeApprovalMode: "onRequest", authority: "canUseTool" };
366
+ },
367
+ stopTask: async function(taskId) {
368
+ assertLive();
369
+ if (!taskId) return handle.abort();
370
+ if (!state.connection || !state.session) throw new Error("Muse task stop requires an opened session");
371
+ await runtime.waitRequest(state.connection.command("task/stop", {
372
+ sessionId: state.sessionId,
373
+ taskId: taskId
374
+ }));
375
+ },
376
+ getContextUsage: function() {
377
+ var context = state.contextUsage;
378
+ return Promise.resolve(context ? {
379
+ input_tokens: context.usedTokens,
380
+ contextWindow: context.windowTokens
381
+ } : null);
382
+ },
383
+ endInput: function() {
384
+ state.inputEnded = true;
385
+ if (!state.active && !state.messages.length && !turns.pending()) handle.close().catch(function(error) {
386
+ adapter.lastCloseError = error;
387
+ });
388
+ },
389
+ abort: function() {
390
+ if (state.ended || state.stopped) return cleanup;
391
+ state.events = [];
392
+ var liveTurns = new Set(state.liveTurnIds);
393
+ if (state.activeTurn) liveTurns.add(state.activeTurn.turnId);
394
+ if (state.connection) liveTurns.forEach(function(turnId) {
395
+ state.connection.command("turn/cancel", { sessionId: state.sessionId, turnId: turnId }).catch(function(error) {
396
+ adapter.lastCancelError = error;
397
+ });
398
+ });
399
+ push({
400
+ yokeType: "interrupted"
401
+ });
402
+ return handle.close();
403
+ },
404
+ close: function() {
405
+ if (cleanup) return cleanup;
406
+ state.stopped = true;
407
+ state.inputEnded = true;
408
+ state.messages = [];
409
+ state.ended = true;
410
+ removeAbort();
411
+ state.abortController.abort();
412
+ finish();
413
+ adapter.handles.delete(handle);
414
+ cleanup = runtime ? runtime.close() : Promise.resolve();
415
+ return cleanup;
416
+ }
417
+ };
418
+ Object.assign(handle, require("./muse-controls").create({ state: state, assertLive: assertLive, selectModel: selectModel, validateEffort: validateEffort, skills: skillDelivery, runtime: function() { return runtime; }, handle: handle }));
419
+ adapter.handles.add(handle);
420
+ removeAbort = queryAbort.bindAbort(state.abortController, function() {
421
+ handle.abort();
422
+ });
423
+ return handle;
424
+ }
425
+
426
+ module.exports = {
427
+ createMuseQueryHandle: createMuseQueryHandle
428
+ };