clay-server 2.47.0-beta.2 → 2.47.0-beta.4
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/lib/claude-hook-installer.js +0 -1
- package/lib/codex-defaults.js +12 -2
- package/lib/project-connection.js +2 -1
- package/lib/project-notifications.js +3 -1
- package/lib/project-session-spawn.js +366 -0
- package/lib/project-sessions.js +17 -9
- package/lib/project.js +47 -29
- package/lib/public/app.js +2 -2
- package/lib/public/css/mates.css +0 -196
- package/lib/public/modules/app-messages.js +3 -23
- package/lib/public/modules/app-notifications.js +12 -4
- package/lib/public/modules/app-panels.js +6 -3
- package/lib/public/modules/app-rate-limit.js +41 -13
- package/lib/public/modules/app-rendering.js +2 -0
- package/lib/public/modules/input.js +4 -5
- package/lib/public/modules/mate-sidebar.js +0 -3
- package/lib/public/modules/tui-grab.js +12 -3
- package/lib/sdk-bridge.js +55 -36
- package/lib/sdk-message-processor.js +4 -6
- package/lib/session-spawn-mcp-server.js +56 -0
- package/lib/sessions.js +3 -0
- package/lib/ws-schema.js +0 -14
- package/lib/yoke/adapters/claude.js +25 -0
- package/lib/yoke/adapters/codex.js +34 -21
- package/lib/yoke/adapters/kiro.js +33 -19
- package/lib/yoke/index.js +18 -6
- package/lib/yoke/vendor-registry.js +55 -0
- package/package.json +3 -3
- package/lib/mate-datastore.js +0 -359
- package/lib/project-mate-datastore.js +0 -232
- package/lib/public/modules/mate-datastore-ui.js +0 -280
|
@@ -3,7 +3,6 @@ import { escapeHtml } from './utils.js';
|
|
|
3
3
|
import { iconHtml, refreshIcons } from './icons.js';
|
|
4
4
|
import { store } from './store.js';
|
|
5
5
|
import { hideKnowledge } from './mate-knowledge.js';
|
|
6
|
-
import { hideMateDatastorePanel } from './mate-datastore-ui.js';
|
|
7
6
|
import { isSchedulerOpen, closeScheduler } from './scheduler.js';
|
|
8
7
|
import { hideNotes } from './sticky-notes.js';
|
|
9
8
|
import { openSearch as openSessionSearch } from './session-search.js';
|
|
@@ -135,7 +134,6 @@ export function initMateSidebar(wsGetter) {
|
|
|
135
134
|
}
|
|
136
135
|
|
|
137
136
|
export function showMateSidebar(mateId, mateData) {
|
|
138
|
-
if (hideMateDatastorePanel) hideMateDatastorePanel();
|
|
139
137
|
currentMateId = mateId;
|
|
140
138
|
currentMate = mateData;
|
|
141
139
|
cachedSessions = [];
|
|
@@ -359,7 +357,6 @@ export function getMateSessions() {
|
|
|
359
357
|
}
|
|
360
358
|
|
|
361
359
|
export function hideMateSidebar() {
|
|
362
|
-
if (hideMateDatastorePanel) hideMateDatastorePanel();
|
|
363
360
|
currentMateId = null;
|
|
364
361
|
currentMate = null;
|
|
365
362
|
cachedSessions = [];
|
|
@@ -24,6 +24,8 @@
|
|
|
24
24
|
// Codex sessions never receive a transcript_state (no JSONL), so the
|
|
25
25
|
// overlay stays disabled — selection copy still works normally.
|
|
26
26
|
|
|
27
|
+
import { store } from './store.js';
|
|
28
|
+
|
|
27
29
|
import { copyToClipboard, showToast } from './utils.js';
|
|
28
30
|
import { getWs } from './ws-ref.js';
|
|
29
31
|
|
|
@@ -629,9 +631,16 @@ function requestTranscript(localId) {
|
|
|
629
631
|
export function attachTuiGrab(xterm, containerEl, localId, opts) {
|
|
630
632
|
if (!xterm || !containerEl || !localId) return;
|
|
631
633
|
clearActive();
|
|
632
|
-
//
|
|
633
|
-
|
|
634
|
-
|
|
634
|
+
// Vendors without TUI sessions have no transcript to match against.
|
|
635
|
+
if (opts && opts.vendor) {
|
|
636
|
+
var vendors = store.get('vendorInfo') || {};
|
|
637
|
+
var info = vendors[opts.vendor];
|
|
638
|
+
var legacyTuiVendors = ["claude"];
|
|
639
|
+
var supportsTui = info
|
|
640
|
+
? Array.isArray(info.sessionModes) && info.sessionModes.indexOf("tui") !== -1
|
|
641
|
+
: legacyTuiVendors.indexOf(opts.vendor) !== -1;
|
|
642
|
+
if (!supportsTui) return;
|
|
643
|
+
}
|
|
635
644
|
|
|
636
645
|
var overlayEl = buildOverlay(containerEl);
|
|
637
646
|
active = {
|
package/lib/sdk-bridge.js
CHANGED
|
@@ -10,6 +10,7 @@ var { splitShellSegments, attachSkillDiscovery } = require("./sdk-skill-discover
|
|
|
10
10
|
var { isSafeBashSegment } = require("./safe-bash-commands");
|
|
11
11
|
var { createMessageQueue } = require("./sdk-message-queue");
|
|
12
12
|
var { attachMessageProcessor } = require("./sdk-message-processor");
|
|
13
|
+
var yoke = require("./yoke");
|
|
13
14
|
|
|
14
15
|
// Extract serializable tool descriptors from MCP server instances.
|
|
15
16
|
// Used for IPC to worker processes (McpSdkServerConfigWithInstance is not serializable).
|
|
@@ -112,10 +113,11 @@ function createSDKBridge(opts) {
|
|
|
112
113
|
var dangerouslySkipPermissions = opts.dangerouslySkipPermissions || false;
|
|
113
114
|
// mcpServers may be either a static object or a getter function. The
|
|
114
115
|
// getter form lets callers gate individual servers at call time (e.g.
|
|
115
|
-
// clay-browser is only exposed while the Chrome extension is connected)
|
|
116
|
+
// clay-browser is only exposed while the Chrome extension is connected)
|
|
117
|
+
// and bind session-scoped servers (clay-sessions) to the querying session.
|
|
116
118
|
var _mcpServersSrc = opts.mcpServers || null;
|
|
117
|
-
function getMcpServers() {
|
|
118
|
-
if (typeof _mcpServersSrc === "function") return _mcpServersSrc() || null;
|
|
119
|
+
function getMcpServers(forSession) {
|
|
120
|
+
if (typeof _mcpServersSrc === "function") return _mcpServersSrc(forSession) || null;
|
|
119
121
|
return _mcpServersSrc;
|
|
120
122
|
}
|
|
121
123
|
var getRemoteMcpServers = opts.getRemoteMcpServers || null;
|
|
@@ -127,7 +129,6 @@ function createSDKBridge(opts) {
|
|
|
127
129
|
var _cachedFreshAuthAt = 0;
|
|
128
130
|
|
|
129
131
|
function getFreshAuthState(force) {
|
|
130
|
-
var yoke = require("./yoke");
|
|
131
132
|
var now = Date.now();
|
|
132
133
|
if (!force && _cachedFreshAuthState && now - _cachedFreshAuthAt < 15000) {
|
|
133
134
|
return _cachedFreshAuthState;
|
|
@@ -150,10 +151,13 @@ function createSDKBridge(opts) {
|
|
|
150
151
|
}
|
|
151
152
|
|
|
152
153
|
function getLoginCommand(vendor) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
154
|
+
var info = yoke.getVendorInfo(vendor);
|
|
155
|
+
return (info && info.loginCommand) || "claude login";
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function supportsOsUserIsolation(vendor) {
|
|
159
|
+
var info = yoke.getVendorInfo(vendor);
|
|
160
|
+
return !info || info.osUserIsolation !== false;
|
|
157
161
|
}
|
|
158
162
|
|
|
159
163
|
function notifyAuthRequired(session, title, body, authLinuxUser, canAutoLogin, loginCommand) {
|
|
@@ -220,15 +224,25 @@ function createSDKBridge(opts) {
|
|
|
220
224
|
}
|
|
221
225
|
|
|
222
226
|
function sendModelInfoForVendor(vendor, model) {
|
|
227
|
+
var resolvedVendor = vendor || (adapter && adapter.vendor) || "claude";
|
|
223
228
|
send({
|
|
224
229
|
type: "model_info",
|
|
225
230
|
model: model || "",
|
|
226
|
-
models: getModelsForVendor(
|
|
227
|
-
vendor:
|
|
231
|
+
models: getModelsForVendor(resolvedVendor),
|
|
232
|
+
vendor: resolvedVendor,
|
|
233
|
+
capabilities: (sm.capabilitiesByVendor && sm.capabilitiesByVendor[resolvedVendor]) || {},
|
|
228
234
|
availableVendors: sm.availableVendors || [],
|
|
229
235
|
installedVendors: sm.installedVendors || [],
|
|
230
236
|
});
|
|
231
237
|
}
|
|
238
|
+
|
|
239
|
+
function rememberAdapterReady(vendor, result) {
|
|
240
|
+
if (!vendor || !result) return;
|
|
241
|
+
sm.modelsByVendor = sm.modelsByVendor || {};
|
|
242
|
+
sm.capabilitiesByVendor = sm.capabilitiesByVendor || {};
|
|
243
|
+
if (Array.isArray(result.models)) sm.modelsByVendor[vendor] = result.models;
|
|
244
|
+
sm.capabilitiesByVendor[vendor] = result.capabilities || {};
|
|
245
|
+
}
|
|
232
246
|
var onTurnDone = opts.onTurnDone || null;
|
|
233
247
|
|
|
234
248
|
// --- Idle session reaper ---
|
|
@@ -534,12 +548,6 @@ function createSDKBridge(opts) {
|
|
|
534
548
|
}
|
|
535
549
|
}
|
|
536
550
|
|
|
537
|
-
// Auto-approve Mate datastore tools. These are scoped to the active Mate
|
|
538
|
-
// project and already enforce SQL policy server-side.
|
|
539
|
-
if (toolName.indexOf("mcp__clay-datastore__") === 0) {
|
|
540
|
-
return { behavior: "allow", updatedInput: input };
|
|
541
|
-
}
|
|
542
|
-
|
|
543
551
|
// Auto-approve clay-history tools. Mounted only on Clay (host agent)
|
|
544
552
|
// sessions and strictly read-only by design — search and read across
|
|
545
553
|
// the user's own workspace data.
|
|
@@ -869,7 +877,8 @@ function createSDKBridge(opts) {
|
|
|
869
877
|
var canAutoLogin = !usersModule.isMultiUser()
|
|
870
878
|
|| !!authLinuxUser
|
|
871
879
|
|| (authUser && authUser.role === "admin");
|
|
872
|
-
var
|
|
880
|
+
var authInfo = yoke.getVendorInfo(session.vendor);
|
|
881
|
+
var authVendorLabel = (authInfo && authInfo.displayName) || "Claude Code";
|
|
873
882
|
var authTitle = authVendorLabel + " is not logged in.";
|
|
874
883
|
var authMsg = {
|
|
875
884
|
type: "auth_required",
|
|
@@ -1070,10 +1079,9 @@ function createSDKBridge(opts) {
|
|
|
1070
1079
|
async function startQuery(session, text, images, linuxUser) {
|
|
1071
1080
|
async function ensureVendorReady(vendor) {
|
|
1072
1081
|
if (!vendor) return null;
|
|
1073
|
-
if (linuxUser && vendor
|
|
1082
|
+
if (linuxUser && !supportsOsUserIsolation(vendor)) return null;
|
|
1074
1083
|
var vendorAdapter = adapters[vendor] || null;
|
|
1075
1084
|
if (!vendorAdapter) {
|
|
1076
|
-
var yoke = require("./yoke");
|
|
1077
1085
|
vendorAdapter = await yoke.lazyCreateAdapter(adapters, vendor, {
|
|
1078
1086
|
cwd: cwd,
|
|
1079
1087
|
dangerouslySkipPermissions: dangerouslySkipPermissions,
|
|
@@ -1083,8 +1091,11 @@ function createSDKBridge(opts) {
|
|
|
1083
1091
|
clayAuthToken: clayAuthToken,
|
|
1084
1092
|
slug: slug,
|
|
1085
1093
|
});
|
|
1086
|
-
}
|
|
1087
|
-
|
|
1094
|
+
}
|
|
1095
|
+
var needsReadyMetadata = !sm.capabilitiesByVendor || !sm.capabilitiesByVendor[vendor]
|
|
1096
|
+
|| !sm.modelsByVendor || !sm.modelsByVendor[vendor];
|
|
1097
|
+
if (vendorAdapter && needsReadyMetadata && typeof vendorAdapter.init === "function") {
|
|
1098
|
+
var readyResult = await vendorAdapter.init({
|
|
1088
1099
|
cwd: cwd,
|
|
1089
1100
|
dangerouslySkipPermissions: dangerouslySkipPermissions,
|
|
1090
1101
|
linuxUser: linuxUser || undefined,
|
|
@@ -1093,6 +1104,7 @@ function createSDKBridge(opts) {
|
|
|
1093
1104
|
clayAuthToken: clayAuthToken,
|
|
1094
1105
|
slug: slug,
|
|
1095
1106
|
});
|
|
1107
|
+
rememberAdapterReady(vendor, readyResult);
|
|
1096
1108
|
}
|
|
1097
1109
|
if (vendorAdapter) {
|
|
1098
1110
|
sm.availableVendors = getAvailableVendors(linuxUser);
|
|
@@ -1100,6 +1112,11 @@ function createSDKBridge(opts) {
|
|
|
1100
1112
|
if (!sm.modelsByVendor[vendor] && typeof vendorAdapter.supportedModels === "function") {
|
|
1101
1113
|
sm.modelsByVendor[vendor] = await vendorAdapter.supportedModels();
|
|
1102
1114
|
}
|
|
1115
|
+
var vendorModels = getModelsForVendor(vendor);
|
|
1116
|
+
var modelForVendor = resolveModelInList(vendorModels, sm.currentModel)
|
|
1117
|
+
|| modelEntryValue(vendorModels[0])
|
|
1118
|
+
|| "";
|
|
1119
|
+
sendModelInfoForVendor(vendor, modelForVendor);
|
|
1103
1120
|
}
|
|
1104
1121
|
return vendorAdapter;
|
|
1105
1122
|
}
|
|
@@ -1108,11 +1125,13 @@ function createSDKBridge(opts) {
|
|
|
1108
1125
|
// OS-isolated session would expose the daemon user's HOME and Kiro
|
|
1109
1126
|
// credentials to another user, so refuse until the adapter has a
|
|
1110
1127
|
// per-user worker path.
|
|
1111
|
-
if (linuxUser && session.vendor
|
|
1112
|
-
|
|
1128
|
+
if (linuxUser && !supportsOsUserIsolation(session.vendor)) {
|
|
1129
|
+
var isolatedVendorInfo = yoke.getVendorInfo(session.vendor);
|
|
1130
|
+
var isolatedVendorName = (isolatedVendorInfo && isolatedVendorInfo.displayName) || session.vendor || "This vendor";
|
|
1131
|
+
console.error("[sdk-bridge] Refusing " + isolatedVendorName + " for OS-isolated user " + linuxUser + ": per-user spawning is not implemented");
|
|
1113
1132
|
sendAndRecord(session, {
|
|
1114
1133
|
type: "error",
|
|
1115
|
-
text: "
|
|
1134
|
+
text: isolatedVendorName + " is not available for OS-isolated users yet.",
|
|
1116
1135
|
});
|
|
1117
1136
|
sendAndRecord(session, { type: "done", code: 1 });
|
|
1118
1137
|
return;
|
|
@@ -1139,7 +1158,9 @@ function createSDKBridge(opts) {
|
|
|
1139
1158
|
}
|
|
1140
1159
|
// If still not available after lazy check, send auth_required
|
|
1141
1160
|
if (session.vendor && !adapters[session.vendor]) {
|
|
1142
|
-
var
|
|
1161
|
+
var missingVendorInfo = yoke.getVendorInfo(session.vendor);
|
|
1162
|
+
var vendorName = (missingVendorInfo && missingVendorInfo.displayName)
|
|
1163
|
+
|| session.vendor.charAt(0).toUpperCase() + session.vendor.slice(1);
|
|
1143
1164
|
var authUser = session.ownerId ? usersModule.findUserById(session.ownerId) : null;
|
|
1144
1165
|
var authLinuxUser = authUser && authUser.linuxUser ? authUser.linuxUser : null;
|
|
1145
1166
|
var canAutoLogin = !usersModule.isMultiUser()
|
|
@@ -1311,7 +1332,7 @@ function createSDKBridge(opts) {
|
|
|
1311
1332
|
|
|
1312
1333
|
var codexConfig = getCodexConfig(sm);
|
|
1313
1334
|
var kiroConfig = getKiroConfig(sm);
|
|
1314
|
-
var mergedMcpServers = mergeMcpServers(getMcpServers(), getRemoteMcpServers) || undefined;
|
|
1335
|
+
var mergedMcpServers = mergeMcpServers(getMcpServers(session), getRemoteMcpServers) || undefined;
|
|
1315
1336
|
|
|
1316
1337
|
// Derive an explicit session title for fresh queries so the SDK records
|
|
1317
1338
|
// it at session creation and skips its own auto-generation. This also
|
|
@@ -1520,25 +1541,26 @@ function createSDKBridge(opts) {
|
|
|
1520
1541
|
}
|
|
1521
1542
|
|
|
1522
1543
|
// Claude: check if binary is in PATH
|
|
1523
|
-
if (tryLookup("claude")) result.push("claude");
|
|
1544
|
+
if (tryLookup(yoke.getVendorInfo("claude").binaryName)) result.push("claude");
|
|
1524
1545
|
|
|
1525
1546
|
// Codex: check bundled binary or PATH
|
|
1526
1547
|
var codexBin = null;
|
|
1527
1548
|
try {
|
|
1528
1549
|
codexBin = require("./yoke/codex-app-server").findCodexPath();
|
|
1529
1550
|
} catch (e) {}
|
|
1530
|
-
if ((codexBin && fs.existsSync(codexBin)) || tryLookup("codex")) result.push("codex");
|
|
1551
|
+
if ((codexBin && fs.existsSync(codexBin)) || tryLookup(yoke.getVendorInfo("codex").binaryName)) result.push("codex");
|
|
1531
1552
|
|
|
1532
1553
|
// Kiro has no per-user ACP spawn path yet. Do not advertise the daemon's
|
|
1533
1554
|
// binary to an OS-isolated user, even if that user also has Kiro installed.
|
|
1534
|
-
|
|
1555
|
+
var kiroInfo = yoke.getVendorInfo("kiro");
|
|
1556
|
+
if (!linuxUser || kiroInfo.osUserIsolation) {
|
|
1535
1557
|
var kiroBin = null;
|
|
1536
1558
|
try {
|
|
1537
1559
|
kiroBin = require("./yoke/kiro-acp-server").findKiroPath();
|
|
1538
1560
|
} catch (e) {}
|
|
1539
|
-
if ((kiroBin && fs.existsSync(kiroBin)) || tryLookup(
|
|
1561
|
+
if ((kiroBin && fs.existsSync(kiroBin)) || tryLookup(kiroInfo.binaryName)) result.push("kiro");
|
|
1540
1562
|
} else {
|
|
1541
|
-
console.log("[sdk-bridge]
|
|
1563
|
+
console.log("[sdk-bridge] " + kiroInfo.displayName + " hidden for OS-isolated user " + linuxUser + ": per-user spawning is not implemented");
|
|
1542
1564
|
}
|
|
1543
1565
|
|
|
1544
1566
|
return result;
|
|
@@ -1546,7 +1568,7 @@ function createSDKBridge(opts) {
|
|
|
1546
1568
|
|
|
1547
1569
|
function getAvailableVendors(linuxUser) {
|
|
1548
1570
|
return Object.keys(adapters).filter(function(vendor) {
|
|
1549
|
-
return !(linuxUser && vendor
|
|
1571
|
+
return !(linuxUser && !supportsOsUserIsolation(vendor));
|
|
1550
1572
|
});
|
|
1551
1573
|
}
|
|
1552
1574
|
|
|
@@ -1591,10 +1613,7 @@ function createSDKBridge(opts) {
|
|
|
1591
1613
|
}
|
|
1592
1614
|
sm.availableModels = result.models || [];
|
|
1593
1615
|
// Store per-vendor models and capabilities
|
|
1594
|
-
|
|
1595
|
-
sm.modelsByVendor[defaultVendor] = result.models || [];
|
|
1596
|
-
sm.capabilitiesByVendor = sm.capabilitiesByVendor || {};
|
|
1597
|
-
sm.capabilitiesByVendor[defaultVendor] = result.capabilities || {};
|
|
1616
|
+
rememberAdapterReady(defaultVendor, result);
|
|
1598
1617
|
} catch (e) {
|
|
1599
1618
|
if (e && e.name !== "AbortError" && !(e.message && e.message.indexOf("aborted") !== -1)) {
|
|
1600
1619
|
send({ type: "error", text: "Failed to load " + defaultVendor + " SDK: " + (e.message || e) });
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
var usersModule = require("./users");
|
|
2
|
+
var yoke = require("./yoke");
|
|
2
3
|
|
|
3
4
|
function attachMessageProcessor(ctx) {
|
|
4
5
|
var sm = ctx.sm;
|
|
@@ -50,12 +51,9 @@ function attachMessageProcessor(ctx) {
|
|
|
50
51
|
var canAutoLogin = !usersModule.isMultiUser()
|
|
51
52
|
|| !!authLinuxUser
|
|
52
53
|
|| (authUser && authUser.role === "admin");
|
|
53
|
-
var
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
var loginCommand = session.vendor === "codex"
|
|
57
|
-
? "codex login --device-auth"
|
|
58
|
-
: (session.vendor === "kiro" ? "kiro-cli login" : "claude login");
|
|
54
|
+
var vendorInfo = yoke.getVendorInfo(session.vendor);
|
|
55
|
+
var authTitle = ((vendorInfo && vendorInfo.displayName) || "Claude Code") + " is not logged in.";
|
|
56
|
+
var loginCommand = (vendorInfo && vendorInfo.loginCommand) || "claude login";
|
|
59
57
|
var _nmLogin = getNotificationsModule();
|
|
60
58
|
sendAndRecord(session, {
|
|
61
59
|
type: "auth_required",
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
// Session Spawn MCP Server for Clay
|
|
2
|
+
// Provides SDK-free tool definitions for agent-driven session fan-out.
|
|
3
|
+
|
|
4
|
+
var z;
|
|
5
|
+
try { z = require("zod"); } catch (e) { z = null; }
|
|
6
|
+
|
|
7
|
+
function buildShape(props, required) {
|
|
8
|
+
if (!z) return {};
|
|
9
|
+
var shape = {};
|
|
10
|
+
var keys = Object.keys(props);
|
|
11
|
+
for (var i = 0; i < keys.length; i++) {
|
|
12
|
+
var key = keys[i];
|
|
13
|
+
var prop = props[key];
|
|
14
|
+
var field;
|
|
15
|
+
if (prop.type === "number") field = z.number();
|
|
16
|
+
else if (prop.type === "boolean") field = z.boolean();
|
|
17
|
+
else if (prop.enum) field = z.enum(prop.enum);
|
|
18
|
+
else field = z.string();
|
|
19
|
+
if (prop.description) field = field.describe(prop.description);
|
|
20
|
+
if (!required || required.indexOf(key) === -1) field = field.optional();
|
|
21
|
+
shape[key] = field;
|
|
22
|
+
}
|
|
23
|
+
return shape;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function getToolDefs(handlers) {
|
|
27
|
+
return [
|
|
28
|
+
{
|
|
29
|
+
name: "spawn_sessions",
|
|
30
|
+
description: "Create sibling work sessions in this project. Set forkFromCurrent to copy this session's full conversation context into every child. Children share the project's working directory, so prefer parallel analysis or other non-conflicting work over concurrent edits. Results can be polled with check_spawned_sessions; spawned children cannot spawn further sessions.",
|
|
31
|
+
inputSchema: buildShape({
|
|
32
|
+
sessions: { type: "string", description: "JSON array of objects: [{\"title\":\"Task title\",\"prompt\":\"Task instructions\"}]" },
|
|
33
|
+
vendor: { type: "string", description: "Optional vendor id. Defaults to the parent session vendor, then the project default." },
|
|
34
|
+
forkFromCurrent: { type: "boolean", description: "Children start with a copy of this session's full conversation context. Defaults to false." },
|
|
35
|
+
}, ["sessions"]),
|
|
36
|
+
handler: function (args) {
|
|
37
|
+
return handlers.spawn(args || {});
|
|
38
|
+
},
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
name: "check_spawned_sessions",
|
|
42
|
+
description: "Check the status of sessions spawned by this session. By default only direct children of the calling session are returned.",
|
|
43
|
+
inputSchema: buildShape({
|
|
44
|
+
parentOnly: { type: "boolean", description: "When false, return all spawned sessions in this project. Defaults to true." },
|
|
45
|
+
}),
|
|
46
|
+
handler: function (args) {
|
|
47
|
+
return handlers.check(args || {});
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
];
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
module.exports = {
|
|
54
|
+
buildShape: buildShape,
|
|
55
|
+
getToolDefs: getToolDefs,
|
|
56
|
+
};
|
package/lib/sessions.js
CHANGED
|
@@ -108,6 +108,7 @@ function createSessionManager(opts) {
|
|
|
108
108
|
if (typeof session.favoriteOrder === "number") metaObj.favoriteOrder = session.favoriteOrder;
|
|
109
109
|
if (session.lastRewindUuid) metaObj.lastRewindUuid = session.lastRewindUuid;
|
|
110
110
|
if (session.loop) metaObj.loop = session.loop;
|
|
111
|
+
if (session.spawn) metaObj.spawn = session.spawn;
|
|
111
112
|
if (session.debateState) metaObj.debateState = session.debateState;
|
|
112
113
|
if (session.debateSetupMode) metaObj.debateSetupMode = true;
|
|
113
114
|
var meta = JSON.stringify(metaObj);
|
|
@@ -207,6 +208,7 @@ function createSessionManager(opts) {
|
|
|
207
208
|
};
|
|
208
209
|
if (m.vendor) session.vendor = m.vendor;
|
|
209
210
|
if (m.loop) session.loop = m.loop;
|
|
211
|
+
if (m.spawn) session.spawn = m.spawn;
|
|
210
212
|
if (m.debateState) session.debateState = m.debateState;
|
|
211
213
|
if (m.debateSetupMode) session.debateSetupMode = true;
|
|
212
214
|
if (m.ownerId) session.ownerId = m.ownerId;
|
|
@@ -394,6 +396,7 @@ function createSessionManager(opts) {
|
|
|
394
396
|
isProcessing: s.isProcessing,
|
|
395
397
|
lastActivity: s.lastActivity || s.createdAt || 0,
|
|
396
398
|
loop: loop,
|
|
399
|
+
spawn: s.spawn || null,
|
|
397
400
|
ownerId: s.ownerId || null,
|
|
398
401
|
sessionVisibility: s.sessionVisibility || "shared",
|
|
399
402
|
bookmarked: !!s.bookmarked,
|
package/lib/ws-schema.js
CHANGED
|
@@ -473,20 +473,6 @@ var schema = {
|
|
|
473
473
|
"memory_delete": { direction: "c2s", handler: "lib/project.js", description: "Delete a memory entry by index" },
|
|
474
474
|
"memory_deleted": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "Memory entry was deleted" },
|
|
475
475
|
|
|
476
|
-
// -----------------------------------------------------------------------
|
|
477
|
-
// Mate datastore
|
|
478
|
-
// -----------------------------------------------------------------------
|
|
479
|
-
"mate_db_tables": { direction: "c2s", handler: "lib/project-mate-datastore.js", description: "List schema objects in the current Mate datastore" },
|
|
480
|
-
"mate_db_describe": { direction: "c2s", handler: "lib/project-mate-datastore.js", description: "Describe a table or view in the current Mate datastore" },
|
|
481
|
-
"mate_db_query": { direction: "c2s", handler: "lib/project-mate-datastore.js", description: "Run read-only SQL against the current Mate datastore" },
|
|
482
|
-
"mate_db_exec": { direction: "c2s", handler: "lib/project-mate-datastore.js", description: "Run schema or write SQL against the current Mate datastore" },
|
|
483
|
-
"mate_db_tables_result": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "Schema objects returned from a Mate datastore" },
|
|
484
|
-
"mate_db_describe_result": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "Table description returned from a Mate datastore" },
|
|
485
|
-
"mate_db_query_result": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "Query results from a Mate datastore" },
|
|
486
|
-
"mate_db_exec_result": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "Execution summary from a Mate datastore" },
|
|
487
|
-
"mate_db_error": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "Mate datastore error" },
|
|
488
|
-
"mate_db_change": { direction: "s2c", handler: "lib/public/modules/app-messages.js", description: "Mate datastore changed" },
|
|
489
|
-
|
|
490
476
|
// -----------------------------------------------------------------------
|
|
491
477
|
// Loop (automated task runner)
|
|
492
478
|
// -----------------------------------------------------------------------
|
|
@@ -1180,6 +1180,11 @@ function createClaudeAdapter(opts) {
|
|
|
1180
1180
|
slashCommands: [],
|
|
1181
1181
|
fastModeState: null,
|
|
1182
1182
|
capabilities: {
|
|
1183
|
+
effort: true,
|
|
1184
|
+
fork: true,
|
|
1185
|
+
rollback: false,
|
|
1186
|
+
sessionListing: true,
|
|
1187
|
+
sessionRename: true,
|
|
1183
1188
|
thinking: true,
|
|
1184
1189
|
betas: true,
|
|
1185
1190
|
rewind: true,
|
|
@@ -1556,6 +1561,11 @@ function createClaudeAdapter(opts) {
|
|
|
1556
1561
|
slashCommands: r.slashCommands || [],
|
|
1557
1562
|
fastModeState: r.fastModeState || null,
|
|
1558
1563
|
capabilities: {
|
|
1564
|
+
effort: true,
|
|
1565
|
+
fork: true,
|
|
1566
|
+
rollback: false,
|
|
1567
|
+
sessionListing: true,
|
|
1568
|
+
sessionRename: true,
|
|
1559
1569
|
thinking: true,
|
|
1560
1570
|
betas: true,
|
|
1561
1571
|
rewind: true,
|
|
@@ -1628,6 +1638,11 @@ function createClaudeAdapter(opts) {
|
|
|
1628
1638
|
slashCommands: [],
|
|
1629
1639
|
fastModeState: null,
|
|
1630
1640
|
capabilities: {
|
|
1641
|
+
effort: true,
|
|
1642
|
+
fork: true,
|
|
1643
|
+
rollback: false,
|
|
1644
|
+
sessionListing: true,
|
|
1645
|
+
sessionRename: true,
|
|
1631
1646
|
thinking: true,
|
|
1632
1647
|
betas: true,
|
|
1633
1648
|
rewind: true,
|
|
@@ -1708,6 +1723,11 @@ function createClaudeAdapter(opts) {
|
|
|
1708
1723
|
slashCommands: r.slashCommands || [],
|
|
1709
1724
|
fastModeState: r.fastModeState || null,
|
|
1710
1725
|
capabilities: {
|
|
1726
|
+
effort: true,
|
|
1727
|
+
fork: true,
|
|
1728
|
+
rollback: false,
|
|
1729
|
+
sessionListing: true,
|
|
1730
|
+
sessionRename: true,
|
|
1711
1731
|
thinking: true,
|
|
1712
1732
|
betas: true,
|
|
1713
1733
|
rewind: true,
|
|
@@ -1737,4 +1757,9 @@ function createClaudeAdapter(opts) {
|
|
|
1737
1757
|
module.exports = {
|
|
1738
1758
|
createClaudeAdapter: createClaudeAdapter,
|
|
1739
1759
|
createMessageQueue: createMessageQueue,
|
|
1760
|
+
contractTestKit: {
|
|
1761
|
+
createMessageQueue: createMessageQueue,
|
|
1762
|
+
createQueryHandle: createQueryHandle,
|
|
1763
|
+
normalizeEvent: flattenEvent,
|
|
1764
|
+
},
|
|
1740
1765
|
};
|
|
@@ -597,6 +597,27 @@ function flattenEvent(notification, state) {
|
|
|
597
597
|
return events;
|
|
598
598
|
}
|
|
599
599
|
|
|
600
|
+
function createEventState(model) {
|
|
601
|
+
return {
|
|
602
|
+
blockCounter: 0,
|
|
603
|
+
threadId: null,
|
|
604
|
+
turnStarted: false,
|
|
605
|
+
lastUsage: null,
|
|
606
|
+
lastInputTokens: null,
|
|
607
|
+
done: false,
|
|
608
|
+
aborted: false,
|
|
609
|
+
loopStarted: false,
|
|
610
|
+
model: model || "gpt-5.6-terra",
|
|
611
|
+
textBlocks: {},
|
|
612
|
+
textLengths: {},
|
|
613
|
+
thinkingBlocks: {},
|
|
614
|
+
thinkingLengths: {},
|
|
615
|
+
toolBlocks: {},
|
|
616
|
+
commandInputs: {},
|
|
617
|
+
planTexts: {},
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
|
|
600
621
|
// --- QueryHandle ---
|
|
601
622
|
|
|
602
623
|
function createCodexQueryHandle(appServer, queryOpts) {
|
|
@@ -611,25 +632,7 @@ function createCodexQueryHandle(appServer, queryOpts) {
|
|
|
611
632
|
return state.aborted || (abortController && abortController.signal && abortController.signal.aborted);
|
|
612
633
|
}
|
|
613
634
|
|
|
614
|
-
var state =
|
|
615
|
-
blockCounter: 0,
|
|
616
|
-
threadId: null,
|
|
617
|
-
turnStarted: false,
|
|
618
|
-
lastUsage: null,
|
|
619
|
-
lastInputTokens: null, // from thread/tokenUsage/updated
|
|
620
|
-
done: false,
|
|
621
|
-
aborted: false,
|
|
622
|
-
loopStarted: false,
|
|
623
|
-
model: queryOpts.model || "gpt-5.6-terra",
|
|
624
|
-
// Track incremental text deltas
|
|
625
|
-
textBlocks: {}, // itemId -> true (text_start sent)
|
|
626
|
-
textLengths: {}, // itemId -> last sent length
|
|
627
|
-
thinkingBlocks: {}, // itemId -> blockId
|
|
628
|
-
thinkingLengths: {}, // itemId -> last sent length
|
|
629
|
-
toolBlocks: {}, // itemId -> blockId (for tool_start dedup)
|
|
630
|
-
commandInputs: {}, // itemId -> command captured from approval/start events
|
|
631
|
-
planTexts: {}, // itemId -> streamed plan text
|
|
632
|
-
};
|
|
635
|
+
var state = createEventState(queryOpts.model);
|
|
633
636
|
|
|
634
637
|
// Internal event buffer for async iterator
|
|
635
638
|
var eventBuffer = [];
|
|
@@ -867,7 +870,7 @@ function createCodexQueryHandle(appServer, queryOpts) {
|
|
|
867
870
|
var threadParams = {
|
|
868
871
|
model: queryOpts.model || "gpt-5.6-terra",
|
|
869
872
|
sandbox: queryOpts.sandboxMode || "workspace-write",
|
|
870
|
-
approvalPolicy: queryOpts.approvalPolicy || "on-
|
|
873
|
+
approvalPolicy: queryOpts.approvalPolicy || "on-request",
|
|
871
874
|
cwd: queryOpts.cwd,
|
|
872
875
|
skipGitRepoCheck: true,
|
|
873
876
|
};
|
|
@@ -1139,6 +1142,11 @@ function createCodexAdapter(opts) {
|
|
|
1139
1142
|
slashCommands: skillNames || [],
|
|
1140
1143
|
fastModeState: null,
|
|
1141
1144
|
capabilities: {
|
|
1145
|
+
effort: true,
|
|
1146
|
+
fork: true,
|
|
1147
|
+
rollback: true,
|
|
1148
|
+
sessionListing: false,
|
|
1149
|
+
sessionRename: false,
|
|
1142
1150
|
thinking: true,
|
|
1143
1151
|
betas: false,
|
|
1144
1152
|
rewind: false,
|
|
@@ -1463,7 +1471,7 @@ function createCodexAdapter(opts) {
|
|
|
1463
1471
|
if (queryOpts.toolPolicy === "allow-all") {
|
|
1464
1472
|
handleOpts.approvalPolicy = "never";
|
|
1465
1473
|
} else {
|
|
1466
|
-
handleOpts.approvalPolicy = codexOpts.approvalPolicy || "on-
|
|
1474
|
+
handleOpts.approvalPolicy = codexOpts.approvalPolicy || "on-request";
|
|
1467
1475
|
}
|
|
1468
1476
|
|
|
1469
1477
|
// Sandbox mode
|
|
@@ -1590,4 +1598,9 @@ function createCodexAdapter(opts) {
|
|
|
1590
1598
|
|
|
1591
1599
|
module.exports = {
|
|
1592
1600
|
createCodexAdapter: createCodexAdapter,
|
|
1601
|
+
contractTestKit: {
|
|
1602
|
+
createEventState: createEventState,
|
|
1603
|
+
createQueryHandle: createCodexQueryHandle,
|
|
1604
|
+
normalizeEvent: flattenEvent,
|
|
1605
|
+
},
|
|
1593
1606
|
};
|
|
@@ -377,30 +377,19 @@ function finalToolContent(state, callId, update) {
|
|
|
377
377
|
return extractRawOutput(update.rawOutput);
|
|
378
378
|
}
|
|
379
379
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
var abortController = queryOpts.abortController;
|
|
384
|
-
var systemPrompt = queryOpts.systemPrompt || "";
|
|
385
|
-
var canUseTool = queryOpts.canUseTool || null;
|
|
386
|
-
var onFinished = queryOpts.onFinished || null;
|
|
387
|
-
|
|
388
|
-
function isCancelled() {
|
|
389
|
-
return state.aborted || (abortController && abortController.signal && abortController.signal.aborted);
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
var state = {
|
|
380
|
+
function createEventState(opts) {
|
|
381
|
+
opts = opts || {};
|
|
382
|
+
return {
|
|
393
383
|
blockCounter: 0,
|
|
394
|
-
sessionId:
|
|
395
|
-
model:
|
|
396
|
-
engine:
|
|
384
|
+
sessionId: opts.resumeSessionId || null,
|
|
385
|
+
model: opts.model || "auto",
|
|
386
|
+
engine: opts.engine || KIRO_DEFAULTS.engine,
|
|
397
387
|
lastInputTokens: null,
|
|
398
|
-
contextWindow:
|
|
388
|
+
contextWindow: opts.contextWindow || null,
|
|
399
389
|
done: false,
|
|
400
390
|
aborted: false,
|
|
401
391
|
loopStarted: false,
|
|
402
392
|
loadingSession: false,
|
|
403
|
-
// per-turn block tracking (reset each turn)
|
|
404
393
|
textBlockOpen: false,
|
|
405
394
|
textBlockId: null,
|
|
406
395
|
thinkBlockOpen: false,
|
|
@@ -409,6 +398,21 @@ function createKiroQueryHandle(acp, queryOpts) {
|
|
|
409
398
|
toolMeta: {},
|
|
410
399
|
toolContent: {},
|
|
411
400
|
};
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// --- QueryHandle ---
|
|
404
|
+
|
|
405
|
+
function createKiroQueryHandle(acp, queryOpts) {
|
|
406
|
+
var abortController = queryOpts.abortController;
|
|
407
|
+
var systemPrompt = queryOpts.systemPrompt || "";
|
|
408
|
+
var canUseTool = queryOpts.canUseTool || null;
|
|
409
|
+
var onFinished = queryOpts.onFinished || null;
|
|
410
|
+
|
|
411
|
+
function isCancelled() {
|
|
412
|
+
return state.aborted || (abortController && abortController.signal && abortController.signal.aborted);
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
var state = createEventState(queryOpts);
|
|
412
416
|
|
|
413
417
|
// Async iterator plumbing
|
|
414
418
|
var eventBuffer = [];
|
|
@@ -864,6 +868,11 @@ function createKiroAdapter(opts) {
|
|
|
864
868
|
slashCommands: skillNames || [],
|
|
865
869
|
fastModeState: null,
|
|
866
870
|
capabilities: {
|
|
871
|
+
effort: false,
|
|
872
|
+
fork: false,
|
|
873
|
+
rollback: false,
|
|
874
|
+
sessionListing: false,
|
|
875
|
+
sessionRename: false,
|
|
867
876
|
thinking: true,
|
|
868
877
|
betas: false,
|
|
869
878
|
rewind: false,
|
|
@@ -872,7 +881,7 @@ function createKiroAdapter(opts) {
|
|
|
872
881
|
elicitation: false,
|
|
873
882
|
fileCheckpointing: false,
|
|
874
883
|
contextCompacting: true,
|
|
875
|
-
toolPolicy: ["ask"
|
|
884
|
+
toolPolicy: ["ask"],
|
|
876
885
|
},
|
|
877
886
|
};
|
|
878
887
|
}
|
|
@@ -1153,4 +1162,9 @@ function createKiroAdapter(opts) {
|
|
|
1153
1162
|
|
|
1154
1163
|
module.exports = {
|
|
1155
1164
|
createKiroAdapter: createKiroAdapter,
|
|
1165
|
+
contractTestKit: {
|
|
1166
|
+
createEventState: createEventState,
|
|
1167
|
+
createQueryHandle: createKiroQueryHandle,
|
|
1168
|
+
normalizeEvent: flattenUpdate,
|
|
1169
|
+
},
|
|
1156
1170
|
};
|