@agentrix/shared 2.2.4 → 2.2.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.
package/dist/index.cjs CHANGED
@@ -1,11 +1,10 @@
1
1
  'use strict';
2
2
 
3
3
  var zod = require('zod');
4
- var node_fs = require('node:fs');
5
- var node_path = require('node:path');
6
- var os = require('node:os');
7
4
  var tweetnacl = require('tweetnacl');
8
5
  var base64js = require('base64-js');
6
+ var CryptoJS = require('crypto-js');
7
+ var errors = require('./errors-myQvpVrM.cjs');
9
8
 
10
9
  function _interopNamespaceDefault(e) {
11
10
  var n = Object.create(null);
@@ -24,7 +23,6 @@ function _interopNamespaceDefault(e) {
24
23
  return Object.freeze(n);
25
24
  }
26
25
 
27
- var os__namespace = /*#__PURE__*/_interopNamespaceDefault(os);
28
26
  var base64js__namespace = /*#__PURE__*/_interopNamespaceDefault(base64js);
29
27
 
30
28
  const ApiErrorSchema = zod.z.object({
@@ -1352,6 +1350,235 @@ const RpcResponseSchema = zod.z.object({
1352
1350
  }).optional()
1353
1351
  });
1354
1352
 
1353
+ async function hmac_sha512(key, data) {
1354
+ const keyWordArray = CryptoJS.lib.WordArray.create(key);
1355
+ const dataWordArray = CryptoJS.lib.WordArray.create(data);
1356
+ const hmac = CryptoJS.HmacSHA512(dataWordArray, keyWordArray);
1357
+ const words = hmac.words;
1358
+ const sigBytes = hmac.sigBytes;
1359
+ const result = new Uint8Array(sigBytes);
1360
+ for (let i = 0; i < sigBytes; i++) {
1361
+ const byte = words[i >>> 2] >>> 24 - i % 4 * 8 & 255;
1362
+ result[i] = byte;
1363
+ }
1364
+ return result;
1365
+ }
1366
+
1367
+ async function deriveSecretKeyTreeRoot(seed, usage) {
1368
+ const I = await hmac_sha512(new TextEncoder().encode(usage + " Master Seed"), seed);
1369
+ return {
1370
+ key: I.slice(0, 32),
1371
+ chainCode: I.slice(32)
1372
+ };
1373
+ }
1374
+ async function deriveSecretKeyTreeChild(chainCode, index) {
1375
+ const data = new Uint8Array([0, ...new TextEncoder().encode(index)]);
1376
+ const I = await hmac_sha512(chainCode, data);
1377
+ return {
1378
+ key: I.subarray(0, 32),
1379
+ chainCode: I.subarray(32)
1380
+ };
1381
+ }
1382
+ async function deriveKey(master, usage, path) {
1383
+ let state = await deriveSecretKeyTreeRoot(master, usage);
1384
+ let remaining = [...path];
1385
+ while (remaining.length > 0) {
1386
+ let index = remaining[0];
1387
+ remaining = remaining.slice(1);
1388
+ state = await deriveSecretKeyTreeChild(state.chainCode, index);
1389
+ }
1390
+ return state.key;
1391
+ }
1392
+
1393
+ function encodeBase64(buffer, variant = "base64") {
1394
+ if (variant === "base64url") {
1395
+ return encodeBase64Url(buffer);
1396
+ }
1397
+ return base64js__namespace.fromByteArray(buffer);
1398
+ }
1399
+ function encodeBase64Url(buffer) {
1400
+ return base64js__namespace.fromByteArray(buffer).replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
1401
+ }
1402
+ function decodeBase64(base64, variant = "base64") {
1403
+ if (!base64) {
1404
+ throw new Error("Invalid base64 input: must be a non-empty string");
1405
+ }
1406
+ const cleaned = base64.replace(/\s/g, "");
1407
+ if (!cleaned) {
1408
+ throw new Error("Invalid base64 input: empty after removing whitespace");
1409
+ }
1410
+ try {
1411
+ if (variant === "base64url") {
1412
+ let base64Standard = cleaned.replace(/-/g, "+").replace(/_/g, "/");
1413
+ const padding = (4 - base64Standard.length % 4) % 4;
1414
+ if (padding > 0) {
1415
+ base64Standard += "=".repeat(padding);
1416
+ }
1417
+ return base64js__namespace.toByteArray(base64Standard);
1418
+ }
1419
+ return base64js__namespace.toByteArray(cleaned);
1420
+ } catch (error) {
1421
+ throw new Error(`Failed to decode base64 (variant: ${variant}): ${error instanceof Error ? error.message : String(error)}`);
1422
+ }
1423
+ }
1424
+ function getRandomBytes(size) {
1425
+ return tweetnacl.randomBytes(size);
1426
+ }
1427
+ function generateAESKey() {
1428
+ return getRandomBytes(tweetnacl.secretbox.keyLength);
1429
+ }
1430
+ function generateAESKeyBase64(variant = "base64") {
1431
+ const key = generateAESKey();
1432
+ return encodeBase64(key, variant);
1433
+ }
1434
+ function encryptAES(data, dataKey) {
1435
+ if (dataKey.length !== tweetnacl.secretbox.keyLength) {
1436
+ throw new Error(`Invalid key length: expected ${tweetnacl.secretbox.keyLength}, got ${dataKey.length}`);
1437
+ }
1438
+ const nonce = getRandomBytes(tweetnacl.secretbox.nonceLength);
1439
+ const plaintext = new TextEncoder().encode(JSON.stringify(data));
1440
+ const encrypted = tweetnacl.secretbox(plaintext, nonce, dataKey);
1441
+ const bundle = new Uint8Array(1 + nonce.length + encrypted.length);
1442
+ bundle.set([0], 0);
1443
+ bundle.set(nonce, 1);
1444
+ bundle.set(encrypted, 1 + nonce.length);
1445
+ return bundle;
1446
+ }
1447
+ function decryptAES(bundle, dataKey) {
1448
+ if (dataKey.length !== tweetnacl.secretbox.keyLength) {
1449
+ return null;
1450
+ }
1451
+ if (bundle.length < 1) {
1452
+ return null;
1453
+ }
1454
+ if (bundle[0] !== 0) {
1455
+ return null;
1456
+ }
1457
+ const minLength = 1 + tweetnacl.secretbox.nonceLength + tweetnacl.secretbox.overheadLength;
1458
+ if (bundle.length < minLength) {
1459
+ return null;
1460
+ }
1461
+ const nonce = bundle.slice(1, 1 + tweetnacl.secretbox.nonceLength);
1462
+ const ciphertext = bundle.slice(1 + tweetnacl.secretbox.nonceLength);
1463
+ try {
1464
+ const decrypted = tweetnacl.secretbox.open(ciphertext, nonce, dataKey);
1465
+ if (!decrypted) {
1466
+ return null;
1467
+ }
1468
+ return JSON.parse(new TextDecoder().decode(decrypted));
1469
+ } catch (error) {
1470
+ return null;
1471
+ }
1472
+ }
1473
+ async function createKeyPairWithUit8Array(masterSecret) {
1474
+ const contentDataKey = await deriveKey(masterSecret, "Agentrix EnCoder", ["content"]);
1475
+ return tweetnacl.box.keyPair.fromSecretKey(contentDataKey);
1476
+ }
1477
+ async function createKeyPair(masterSecret, variant = "base64") {
1478
+ return await createKeyPairWithUit8Array(decodeBase64(masterSecret, variant));
1479
+ }
1480
+ function decryptWithEphemeralKey(encryptedBundle, secretKey) {
1481
+ const ephemeralPublicKey = encryptedBundle.slice(0, 32);
1482
+ const nonce = encryptedBundle.slice(32, 32 + tweetnacl.box.nonceLength);
1483
+ const encrypted = encryptedBundle.slice(32 + tweetnacl.box.nonceLength);
1484
+ const decrypted = tweetnacl.box.open(encrypted, nonce, ephemeralPublicKey, secretKey);
1485
+ if (!decrypted) {
1486
+ return null;
1487
+ }
1488
+ return decrypted;
1489
+ }
1490
+ function encryptWithEphemeralKey(data, publicKey) {
1491
+ const ephemeralKeyPair = tweetnacl.box.keyPair();
1492
+ const nonce = getRandomBytes(tweetnacl.box.nonceLength);
1493
+ const encrypted = tweetnacl.box(data, nonce, publicKey, ephemeralKeyPair.secretKey);
1494
+ const result = new Uint8Array(ephemeralKeyPair.publicKey.length + nonce.length + encrypted.length);
1495
+ result.set(ephemeralKeyPair.publicKey, 0);
1496
+ result.set(nonce, ephemeralKeyPair.publicKey.length);
1497
+ result.set(encrypted, ephemeralKeyPair.publicKey.length + nonce.length);
1498
+ return result;
1499
+ }
1500
+ function encryptSdkMessage(message, dataKey) {
1501
+ const encryptedWithVersion = encryptAES(message, dataKey);
1502
+ const encryptedWithoutVersion = encryptedWithVersion.slice(1);
1503
+ return encodeBase64(encryptedWithoutVersion);
1504
+ }
1505
+ function decryptSdkMessage(encryptedMessage, dataKey) {
1506
+ try {
1507
+ const encryptedWithoutVersion = decodeBase64(encryptedMessage);
1508
+ const encryptedWithVersion = new Uint8Array(1 + encryptedWithoutVersion.length);
1509
+ encryptedWithVersion.set([0], 0);
1510
+ encryptedWithVersion.set(encryptedWithoutVersion, 1);
1511
+ return decryptAES(encryptedWithVersion, dataKey);
1512
+ } catch (error) {
1513
+ return null;
1514
+ }
1515
+ }
1516
+ function encryptMachineEncryptionKey(machinePublicKey, aesKey, userPublicKey) {
1517
+ if (machinePublicKey.length !== 32) {
1518
+ throw new Error(`Invalid machine public key length: expected 32, got ${machinePublicKey.length}`);
1519
+ }
1520
+ if (aesKey.length !== tweetnacl.secretbox.keyLength) {
1521
+ throw new Error(`Invalid AES key length: expected ${tweetnacl.secretbox.keyLength}, got ${aesKey.length}`);
1522
+ }
1523
+ if (userPublicKey.length !== 32) {
1524
+ throw new Error(`Invalid user public key length: expected 32, got ${userPublicKey.length}`);
1525
+ }
1526
+ const combined = new Uint8Array(machinePublicKey.length + aesKey.length);
1527
+ combined.set(machinePublicKey, 0);
1528
+ combined.set(aesKey, machinePublicKey.length);
1529
+ const encrypted = encryptWithEphemeralKey(combined, userPublicKey);
1530
+ return encodeBase64(encrypted);
1531
+ }
1532
+ function decryptMachineEncryptionKey(encryptedData, userPrivateKey) {
1533
+ if (userPrivateKey.length !== 32) {
1534
+ return null;
1535
+ }
1536
+ try {
1537
+ const encryptedBundle = decodeBase64(encryptedData);
1538
+ const decrypted = decryptWithEphemeralKey(encryptedBundle, userPrivateKey);
1539
+ if (!decrypted) {
1540
+ return null;
1541
+ }
1542
+ const expectedLength = 32 + tweetnacl.secretbox.keyLength;
1543
+ if (decrypted.length !== expectedLength) {
1544
+ return null;
1545
+ }
1546
+ const machinePublicKey = decrypted.slice(0, 32);
1547
+ const aesKey = decrypted.slice(32);
1548
+ return { machinePublicKey, aesKey };
1549
+ } catch (error) {
1550
+ return null;
1551
+ }
1552
+ }
1553
+ function createTaskEncryptionPayload(machineEncryptionKey) {
1554
+ const taskDataKey = generateAESKey();
1555
+ return {
1556
+ taskDataKey,
1557
+ dataEncryptionKey: encodeBase64(
1558
+ encryptWithEphemeralKey(taskDataKey, machineEncryptionKey.machinePublicKey)
1559
+ ),
1560
+ ownerEncryptedDataKey: encodeBase64(
1561
+ encryptAES(encodeBase64(taskDataKey), machineEncryptionKey.aesKey)
1562
+ )
1563
+ };
1564
+ }
1565
+ function encryptFileContent(fileContentBase64, dataKey) {
1566
+ const encryptedWithVersion = encryptAES(fileContentBase64, dataKey);
1567
+ const encryptedWithoutVersion = encryptedWithVersion.slice(1);
1568
+ return encodeBase64(encryptedWithoutVersion);
1569
+ }
1570
+ function decryptFileContent(encryptedContent, dataKey) {
1571
+ try {
1572
+ const encryptedWithoutVersion = decodeBase64(encryptedContent);
1573
+ const encryptedWithVersion = new Uint8Array(1 + encryptedWithoutVersion.length);
1574
+ encryptedWithVersion.set([0], 0);
1575
+ encryptedWithVersion.set(encryptedWithoutVersion, 1);
1576
+ return decryptAES(encryptedWithVersion, dataKey);
1577
+ } catch (error) {
1578
+ return null;
1579
+ }
1580
+ }
1581
+
1355
1582
  const AskUserOptionSchema = zod.z.object({
1356
1583
  label: zod.z.string(),
1357
1584
  // Option label (1-5 words)
@@ -1400,8 +1627,11 @@ function isCompanionHeartbeatMessage(message) {
1400
1627
  function isCompanionReminderMessage(message) {
1401
1628
  return typeof message === "object" && message !== null && "type" in message && message.type === "companion_reminder";
1402
1629
  }
1630
+ function isSubTaskAskUserMessage(message) {
1631
+ return typeof message === "object" && message !== null && "type" in message && message.type === "sub_task_ask_user";
1632
+ }
1403
1633
  function isSDKMessage(message) {
1404
- return typeof message === "object" && message !== null && "type" in message && message.type !== "ask_user" && message.type !== "ask_user_response" && message.type !== "companion_heartbeat" && message.type !== "companion_reminder";
1634
+ return typeof message === "object" && message !== null && "type" in message && message.type !== "ask_user" && message.type !== "ask_user_response" && message.type !== "companion_heartbeat" && message.type !== "companion_reminder" && message.type !== "sub_task_ask_user";
1405
1635
  }
1406
1636
  function isSDKUserMessage(message) {
1407
1637
  return isSDKMessage(message) && message.type === "user";
@@ -1410,7 +1640,10 @@ const EventBaseSchema = zod.z.object({
1410
1640
  eventId: zod.z.string()
1411
1641
  });
1412
1642
  const createEventId = () => {
1413
- return `event-${crypto.randomUUID()}`;
1643
+ const bytes = getRandomBytes(16);
1644
+ const hex = Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
1645
+ const uuid = `${hex.slice(0, 8)}-${hex.slice(8, 12)}-4${hex.slice(13, 16)}-${(parseInt(hex.slice(16, 18), 16) & 63 | 128).toString(16).padStart(2, "0")}${hex.slice(18, 20)}-${hex.slice(20, 32)}`;
1646
+ return `event-${uuid}`;
1414
1647
  };
1415
1648
  const EventAckSchema = EventBaseSchema.extend({
1416
1649
  status: zod.z.enum(["success", "failed"]),
@@ -2050,308 +2283,21 @@ function workerAuth(token, machineId, taskId) {
2050
2283
  };
2051
2284
  }
2052
2285
 
2053
- let agentContext = null;
2054
- function setAgentContext(context) {
2055
- agentContext = context;
2056
- }
2057
- function getAgentContext() {
2058
- if (!agentContext) {
2059
- throw new Error("Agent context not initialized. Call setAgentContext() first.");
2060
- }
2061
- return agentContext;
2062
- }
2063
-
2064
- const FRAMEWORK_TYPES = ["claude", "codex"];
2065
-
2066
- const AgentMetadataSchema = zod.z.object({
2286
+ const CompanionWorkspaceFileSchema = zod.z.object({
2067
2287
  name: zod.z.string(),
2068
- version: zod.z.string(),
2069
- description: zod.z.string().optional()
2288
+ path: zod.z.string(),
2289
+ // relative to workspace root
2290
+ size: zod.z.number(),
2291
+ modifiedAt: zod.z.number(),
2292
+ isDirectory: zod.z.boolean()
2070
2293
  });
2071
- const ClaudeConfigSchema = zod.z.object({
2072
- // SDK native model configuration
2073
- model: zod.z.string().optional(),
2074
- fallbackModel: zod.z.string().optional(),
2075
- maxTurns: zod.z.number().int().positive().optional(),
2076
- // SDK native extra arguments
2077
- extraArgs: zod.z.record(zod.z.string(), zod.z.string().nullable()).optional(),
2078
- systemPrompt: zod.z.object({
2079
- path: zod.z.string(),
2080
- mode: zod.z.enum(["append", "replace"]).optional().default("append")
2081
- }).optional(),
2082
- settings: zod.z.object({
2083
- permissionMode: zod.z.enum(["default", "acceptEdits", "bypassPermissions", "plan"]).optional(),
2084
- allowedTools: zod.z.array(zod.z.string()).optional()
2085
- }).optional(),
2086
- pullRequestPrompt: zod.z.object({
2087
- path: zod.z.string(),
2088
- mode: zod.z.enum(["append", "replace"]).optional().default("append")
2089
- }).optional(),
2090
- // SDK MCP Tools - scripts that export createSdkMcpServer()
2091
- sdkMcpTools: zod.z.array(zod.z.string()).optional()
2092
- });
2093
-
2094
- class AgentError extends Error {
2095
- constructor(message) {
2096
- super(message);
2097
- this.name = "AgentError";
2098
- }
2099
- }
2100
- class AgentNotFoundError extends AgentError {
2101
- constructor(agentId) {
2102
- super(`Agent not found: ${agentId}`);
2103
- this.name = "AgentNotFoundError";
2104
- }
2105
- }
2106
- class AgentConfigValidationError extends AgentError {
2107
- constructor(message, errors) {
2108
- super(message);
2109
- this.errors = errors;
2110
- this.name = "AgentConfigValidationError";
2111
- }
2112
- }
2113
- class FrameworkNotSupportedError extends AgentError {
2114
- constructor(agentId, framework) {
2115
- super(`Agent "${agentId}" does not support framework: ${framework}`);
2116
- this.name = "FrameworkNotSupportedError";
2117
- }
2118
- }
2119
- class AgentLoadError extends AgentError {
2120
- constructor(message, cause) {
2121
- super(message);
2122
- this.cause = cause;
2123
- this.name = "AgentLoadError";
2124
- }
2125
- }
2126
- class MissingAgentFileError extends AgentError {
2127
- constructor(filePath) {
2128
- super(`Required agent file missing: ${filePath}`);
2129
- this.name = "MissingAgentFileError";
2130
- }
2131
- }
2132
-
2133
- function validateAgentDirectory(agentDir) {
2134
- const errors = [];
2135
- const warnings = [];
2136
- if (!node_fs.existsSync(agentDir)) {
2137
- errors.push(`Agent directory does not exist: ${agentDir}`);
2138
- return { valid: false, errors, warnings };
2139
- }
2140
- if (!node_fs.statSync(agentDir).isDirectory()) {
2141
- errors.push(`Path is not a directory: ${agentDir}`);
2142
- return { valid: false, errors, warnings };
2143
- }
2144
- const agentJsonPath = node_path.join(agentDir, "agent.json");
2145
- if (!node_fs.existsSync(agentJsonPath)) {
2146
- errors.push("Missing required file: agent.json");
2147
- }
2148
- const readmePath = node_path.join(agentDir, "README.md");
2149
- if (!node_fs.existsSync(readmePath)) {
2150
- warnings.push("Missing README.md (recommended)");
2151
- }
2152
- return {
2153
- valid: errors.length === 0,
2154
- errors,
2155
- warnings
2156
- };
2157
- }
2158
- function validateFrameworkDirectory(frameworkDir, framework) {
2159
- const errors = [];
2160
- const warnings = [];
2161
- if (!node_fs.existsSync(frameworkDir)) {
2162
- errors.push(`Framework directory does not exist: ${frameworkDir}`);
2163
- return { valid: false, errors, warnings };
2164
- }
2165
- const configPath = node_path.join(frameworkDir, "config.json");
2166
- if (!node_fs.existsSync(configPath)) {
2167
- errors.push(`Missing required file: ${framework}/config.json`);
2168
- }
2169
- if (framework === "claude") {
2170
- const mcpServersDir = node_path.join(frameworkDir, "mcp-servers");
2171
- if (!node_fs.existsSync(mcpServersDir)) {
2172
- warnings.push("Missing mcp-servers directory (optional)");
2173
- }
2174
- const skillsDir = node_path.join(frameworkDir, "skills");
2175
- if (!node_fs.existsSync(skillsDir)) {
2176
- warnings.push("Missing skills directory (optional)");
2177
- }
2178
- }
2179
- return {
2180
- valid: errors.length === 0,
2181
- errors,
2182
- warnings
2183
- };
2184
- }
2185
- function assertFileExists(filePath, description) {
2186
- if (!node_fs.existsSync(filePath)) {
2187
- throw new MissingAgentFileError(description || filePath);
2188
- }
2189
- }
2190
- function assertAgentExists(agentDir, agentId) {
2191
- if (!node_fs.existsSync(agentDir)) {
2192
- throw new AgentNotFoundError(agentId);
2193
- }
2194
- }
2195
-
2196
- function discoverPlugins(pluginsDir) {
2197
- if (!node_fs.existsSync(pluginsDir)) {
2198
- return [];
2199
- }
2200
- return node_fs.readdirSync(pluginsDir, { withFileTypes: true }).filter((dirent) => dirent.isDirectory()).map((dirent) => node_path.join(pluginsDir, dirent.name)).filter((pluginPath) => isValidPluginDirectory(pluginPath));
2201
- }
2202
- function isValidPluginDirectory(pluginDir) {
2203
- const manifestPath = node_path.join(pluginDir, ".claude-plugin", "plugin.json");
2204
- return node_fs.existsSync(manifestPath);
2205
- }
2206
-
2207
- async function loadAgentConfig(options) {
2208
- const { agentId, framework, validateOnly = false, agentDir: providedAgentDir } = options;
2209
- const agentContext = getAgentContext();
2210
- const agentDir = providedAgentDir || agentContext.resolveAgentDir(agentId);
2211
- assertAgentExists(agentDir, agentId);
2212
- const validation = validateAgentDirectory(agentDir);
2213
- if (!validation.valid) {
2214
- throw new AgentConfigValidationError(
2215
- `Agent directory validation failed for "${agentId}"`,
2216
- validation.errors
2217
- );
2218
- }
2219
- if (validation.warnings.length > 0) {
2220
- console.warn(`[AGENT] Warnings for agent "${agentId}":`, validation.warnings);
2221
- }
2222
- const metadata = await loadAgentMetadata(agentDir);
2223
- const frameworkDirName = framework === "claude" ? "claude" : `.${framework}`;
2224
- const frameworkDir = node_path.join(agentDir, frameworkDirName);
2225
- if (!node_fs.existsSync(frameworkDir)) {
2226
- throw new FrameworkNotSupportedError(agentId, framework);
2227
- }
2228
- if (validateOnly) {
2229
- return {
2230
- metadata,
2231
- framework
2232
- };
2233
- }
2234
- if (framework === "claude") {
2235
- const claudeConfig = await loadClaudeConfiguration(agentDir);
2236
- return {
2237
- metadata,
2238
- framework,
2239
- claude: claudeConfig
2240
- };
2241
- }
2242
- throw new AgentLoadError(`Framework "${framework}" loader not implemented`);
2243
- }
2244
- async function loadAgentMetadata(agentDir) {
2245
- const agentJsonPath = node_path.join(agentDir, "agent.json");
2246
- assertFileExists(agentJsonPath, "agent.json");
2247
- try {
2248
- const content = node_fs.readFileSync(agentJsonPath, "utf-8");
2249
- const rawData = JSON.parse(content);
2250
- const metadata = AgentMetadataSchema.parse(rawData);
2251
- return metadata;
2252
- } catch (error) {
2253
- if (error instanceof SyntaxError) {
2254
- throw new AgentConfigValidationError("Invalid JSON in agent.json");
2255
- }
2256
- throw new AgentConfigValidationError(
2257
- `Invalid agent metadata: ${error instanceof Error ? error.message : String(error)}`
2258
- );
2259
- }
2260
- }
2261
- async function loadClaudeConfiguration(agentDir, metadata) {
2262
- const claudeDir = node_path.join(agentDir, "claude");
2263
- const validation = validateFrameworkDirectory(claudeDir, "claude");
2264
- if (!validation.valid) {
2265
- throw new AgentConfigValidationError(
2266
- "Claude framework directory validation failed",
2267
- validation.errors
2268
- );
2269
- }
2270
- const config = await loadClaudeConfig(claudeDir);
2271
- let systemPrompt;
2272
- if (config.systemPrompt) {
2273
- systemPrompt = await loadSystemPrompt(claudeDir, config.systemPrompt.path);
2274
- }
2275
- let prPromptTemplate;
2276
- if (config.pullRequestPrompt) {
2277
- prPromptTemplate = await loadSystemPrompt(claudeDir, config.pullRequestPrompt.path);
2278
- }
2279
- const pluginsDir = node_path.join(claudeDir, "plugins");
2280
- const plugins = discoverPlugins(pluginsDir);
2281
- return {
2282
- config,
2283
- systemPrompt,
2284
- prPromptTemplate,
2285
- plugins
2286
- };
2287
- }
2288
- async function loadClaudeConfig(claudeDir) {
2289
- const configPath = node_path.join(claudeDir, "config.json");
2290
- assertFileExists(configPath, "claude/config.json");
2291
- try {
2292
- const content = node_fs.readFileSync(configPath, "utf-8");
2293
- const rawConfig = JSON.parse(content);
2294
- const config = ClaudeConfigSchema.parse(rawConfig);
2295
- return config;
2296
- } catch (error) {
2297
- if (error instanceof SyntaxError) {
2298
- throw new AgentConfigValidationError(
2299
- "Invalid JSON in claude/config.json"
2300
- );
2301
- }
2302
- throw new AgentConfigValidationError(
2303
- `Invalid Claude configuration: ${error instanceof Error ? error.message : String(error)}`
2304
- );
2305
- }
2306
- }
2307
- async function loadSystemPrompt(claudeDir, promptFile) {
2308
- const promptPath = node_path.join(claudeDir, promptFile);
2309
- if (!node_fs.existsSync(promptPath)) {
2310
- throw new MissingAgentFileError(`claude/${promptFile}`);
2311
- }
2312
- try {
2313
- return node_fs.readFileSync(promptPath, "utf-8");
2314
- } catch (error) {
2315
- throw new AgentLoadError(
2316
- `Failed to read system prompt: ${error instanceof Error ? error.message : String(error)}`
2317
- );
2318
- }
2319
- }
2320
- function replacePromptPlaceholders(template, cwd, extra) {
2321
- const vars = {
2322
- WORKING_DIR: cwd,
2323
- PLATFORM: process.platform,
2324
- OS_VERSION: `${os__namespace.type()} ${os__namespace.release()}`,
2325
- DATE: (/* @__PURE__ */ new Date()).toISOString().split("T")[0],
2326
- ...extra
2327
- };
2328
- let result = template.replace(
2329
- /\{\{#if\s+(\w+)\s*(==|!=)\s*(\w+)\}\}([\s\S]*?)\{\{\/if\}\}/g,
2330
- (_match, key, op, expected, content) => {
2331
- const actual = vars[key] ?? "";
2332
- const matches = op === "==" ? actual === expected : actual !== expected;
2333
- return matches ? content : "";
2334
- }
2335
- );
2336
- for (const [key, value] of Object.entries(vars)) {
2337
- result = result.replace(new RegExp(`\\{\\{${key}\\}\\}`, "g"), value);
2338
- }
2339
- return result;
2340
- }
2341
-
2342
- const CompanionWorkspaceFileSchema = zod.z.object({
2343
- name: zod.z.string(),
2344
- path: zod.z.string(),
2345
- // relative to workspace root
2346
- size: zod.z.number(),
2347
- modifiedAt: zod.z.number(),
2348
- isDirectory: zod.z.boolean()
2349
- });
2350
- const RegisterCompanionRequestSchema = zod.z.object({
2351
- machineId: zod.z.string().min(1),
2352
- // Optional: provision companion chat virtual task E2EE keys (local mode sharing).
2353
- dataEncryptionKey: zod.z.string().optional(),
2354
- ownerEncryptedDataKey: zod.z.string().optional()
2294
+ const RegisterCompanionRequestSchema = zod.z.object({
2295
+ machineId: zod.z.string().min(1),
2296
+ // Optional: provision companion chat virtual task E2EE keys (local mode sharing).
2297
+ dataEncryptionKey: zod.z.string().optional(),
2298
+ ownerEncryptedDataKey: zod.z.string().optional(),
2299
+ // Optional: preferred language for companion bootstrap/kickoff copy.
2300
+ preferredLanguage: zod.z.enum(["en", "zh-Hans"]).optional()
2355
2301
  });
2356
2302
  const RegisterCompanionResponseSchema = zod.z.object({
2357
2303
  agentId: zod.z.string(),
@@ -2365,252 +2311,6 @@ const CompanionEnsureResponseSchema = zod.z.object({
2365
2311
  homeDir: zod.z.string()
2366
2312
  });
2367
2313
 
2368
- const cryptoModule = typeof globalThis.crypto !== "undefined" ? globalThis.crypto : (async () => {
2369
- try {
2370
- const nodeCrypto = await import('node:crypto');
2371
- return nodeCrypto.webcrypto;
2372
- } catch {
2373
- throw new Error("Web Crypto API not available");
2374
- }
2375
- })();
2376
- async function getCrypto() {
2377
- if (typeof cryptoModule === "object" && cryptoModule !== null && "subtle" in cryptoModule) {
2378
- return cryptoModule;
2379
- }
2380
- return await cryptoModule;
2381
- }
2382
- async function hmac_sha512(key, data) {
2383
- const crypto = await getCrypto();
2384
- const cryptoKey = await crypto.subtle.importKey(
2385
- "raw",
2386
- key,
2387
- { name: "HMAC", hash: "SHA-512" },
2388
- false,
2389
- ["sign"]
2390
- );
2391
- const signature = await crypto.subtle.sign(
2392
- "HMAC",
2393
- cryptoKey,
2394
- data
2395
- );
2396
- return new Uint8Array(signature);
2397
- }
2398
-
2399
- async function deriveSecretKeyTreeRoot(seed, usage) {
2400
- const I = await hmac_sha512(new TextEncoder().encode(usage + " Master Seed"), seed);
2401
- return {
2402
- key: I.slice(0, 32),
2403
- chainCode: I.slice(32)
2404
- };
2405
- }
2406
- async function deriveSecretKeyTreeChild(chainCode, index) {
2407
- const data = new Uint8Array([0, ...new TextEncoder().encode(index)]);
2408
- const I = await hmac_sha512(chainCode, data);
2409
- return {
2410
- key: I.subarray(0, 32),
2411
- chainCode: I.subarray(32)
2412
- };
2413
- }
2414
- async function deriveKey(master, usage, path) {
2415
- let state = await deriveSecretKeyTreeRoot(master, usage);
2416
- let remaining = [...path];
2417
- while (remaining.length > 0) {
2418
- let index = remaining[0];
2419
- remaining = remaining.slice(1);
2420
- state = await deriveSecretKeyTreeChild(state.chainCode, index);
2421
- }
2422
- return state.key;
2423
- }
2424
-
2425
- function encodeBase64(buffer, variant = "base64") {
2426
- if (variant === "base64url") {
2427
- return encodeBase64Url(buffer);
2428
- }
2429
- return base64js__namespace.fromByteArray(buffer);
2430
- }
2431
- function encodeBase64Url(buffer) {
2432
- return base64js__namespace.fromByteArray(buffer).replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
2433
- }
2434
- function decodeBase64(base64, variant = "base64") {
2435
- if (!base64) {
2436
- throw new Error("Invalid base64 input: must be a non-empty string");
2437
- }
2438
- const cleaned = base64.replace(/\s/g, "");
2439
- if (!cleaned) {
2440
- throw new Error("Invalid base64 input: empty after removing whitespace");
2441
- }
2442
- try {
2443
- if (variant === "base64url") {
2444
- let base64Standard = cleaned.replace(/-/g, "+").replace(/_/g, "/");
2445
- const padding = (4 - base64Standard.length % 4) % 4;
2446
- if (padding > 0) {
2447
- base64Standard += "=".repeat(padding);
2448
- }
2449
- return base64js__namespace.toByteArray(base64Standard);
2450
- }
2451
- return base64js__namespace.toByteArray(cleaned);
2452
- } catch (error) {
2453
- throw new Error(`Failed to decode base64 (variant: ${variant}): ${error instanceof Error ? error.message : String(error)}`);
2454
- }
2455
- }
2456
- function getRandomBytes(size) {
2457
- return tweetnacl.randomBytes(size);
2458
- }
2459
- function generateAESKey() {
2460
- return getRandomBytes(tweetnacl.secretbox.keyLength);
2461
- }
2462
- function generateAESKeyBase64(variant = "base64") {
2463
- const key = generateAESKey();
2464
- return encodeBase64(key, variant);
2465
- }
2466
- function encryptAES(data, dataKey) {
2467
- if (dataKey.length !== tweetnacl.secretbox.keyLength) {
2468
- throw new Error(`Invalid key length: expected ${tweetnacl.secretbox.keyLength}, got ${dataKey.length}`);
2469
- }
2470
- const nonce = getRandomBytes(tweetnacl.secretbox.nonceLength);
2471
- const plaintext = new TextEncoder().encode(JSON.stringify(data));
2472
- const encrypted = tweetnacl.secretbox(plaintext, nonce, dataKey);
2473
- const bundle = new Uint8Array(1 + nonce.length + encrypted.length);
2474
- bundle.set([0], 0);
2475
- bundle.set(nonce, 1);
2476
- bundle.set(encrypted, 1 + nonce.length);
2477
- return bundle;
2478
- }
2479
- function decryptAES(bundle, dataKey) {
2480
- if (dataKey.length !== tweetnacl.secretbox.keyLength) {
2481
- return null;
2482
- }
2483
- if (bundle.length < 1) {
2484
- return null;
2485
- }
2486
- if (bundle[0] !== 0) {
2487
- return null;
2488
- }
2489
- const minLength = 1 + tweetnacl.secretbox.nonceLength + tweetnacl.secretbox.overheadLength;
2490
- if (bundle.length < minLength) {
2491
- return null;
2492
- }
2493
- const nonce = bundle.slice(1, 1 + tweetnacl.secretbox.nonceLength);
2494
- const ciphertext = bundle.slice(1 + tweetnacl.secretbox.nonceLength);
2495
- try {
2496
- const decrypted = tweetnacl.secretbox.open(ciphertext, nonce, dataKey);
2497
- if (!decrypted) {
2498
- return null;
2499
- }
2500
- return JSON.parse(new TextDecoder().decode(decrypted));
2501
- } catch (error) {
2502
- return null;
2503
- }
2504
- }
2505
- async function createKeyPairWithUit8Array(masterSecret) {
2506
- const contentDataKey = await deriveKey(masterSecret, "Agentrix EnCoder", ["content"]);
2507
- return tweetnacl.box.keyPair.fromSecretKey(contentDataKey);
2508
- }
2509
- async function createKeyPair(masterSecret, variant = "base64") {
2510
- return await createKeyPairWithUit8Array(decodeBase64(masterSecret, variant));
2511
- }
2512
- function decryptWithEphemeralKey(encryptedBundle, secretKey) {
2513
- const ephemeralPublicKey = encryptedBundle.slice(0, 32);
2514
- const nonce = encryptedBundle.slice(32, 32 + tweetnacl.box.nonceLength);
2515
- const encrypted = encryptedBundle.slice(32 + tweetnacl.box.nonceLength);
2516
- const decrypted = tweetnacl.box.open(encrypted, nonce, ephemeralPublicKey, secretKey);
2517
- if (!decrypted) {
2518
- return null;
2519
- }
2520
- return decrypted;
2521
- }
2522
- function encryptWithEphemeralKey(data, publicKey) {
2523
- const ephemeralKeyPair = tweetnacl.box.keyPair();
2524
- const nonce = getRandomBytes(tweetnacl.box.nonceLength);
2525
- const encrypted = tweetnacl.box(data, nonce, publicKey, ephemeralKeyPair.secretKey);
2526
- const result = new Uint8Array(ephemeralKeyPair.publicKey.length + nonce.length + encrypted.length);
2527
- result.set(ephemeralKeyPair.publicKey, 0);
2528
- result.set(nonce, ephemeralKeyPair.publicKey.length);
2529
- result.set(encrypted, ephemeralKeyPair.publicKey.length + nonce.length);
2530
- return result;
2531
- }
2532
- function encryptSdkMessage(message, dataKey) {
2533
- const encryptedWithVersion = encryptAES(message, dataKey);
2534
- const encryptedWithoutVersion = encryptedWithVersion.slice(1);
2535
- return encodeBase64(encryptedWithoutVersion);
2536
- }
2537
- function decryptSdkMessage(encryptedMessage, dataKey) {
2538
- try {
2539
- const encryptedWithoutVersion = decodeBase64(encryptedMessage);
2540
- const encryptedWithVersion = new Uint8Array(1 + encryptedWithoutVersion.length);
2541
- encryptedWithVersion.set([0], 0);
2542
- encryptedWithVersion.set(encryptedWithoutVersion, 1);
2543
- return decryptAES(encryptedWithVersion, dataKey);
2544
- } catch (error) {
2545
- return null;
2546
- }
2547
- }
2548
- function encryptMachineEncryptionKey(machinePublicKey, aesKey, userPublicKey) {
2549
- if (machinePublicKey.length !== 32) {
2550
- throw new Error(`Invalid machine public key length: expected 32, got ${machinePublicKey.length}`);
2551
- }
2552
- if (aesKey.length !== tweetnacl.secretbox.keyLength) {
2553
- throw new Error(`Invalid AES key length: expected ${tweetnacl.secretbox.keyLength}, got ${aesKey.length}`);
2554
- }
2555
- if (userPublicKey.length !== 32) {
2556
- throw new Error(`Invalid user public key length: expected 32, got ${userPublicKey.length}`);
2557
- }
2558
- const combined = new Uint8Array(machinePublicKey.length + aesKey.length);
2559
- combined.set(machinePublicKey, 0);
2560
- combined.set(aesKey, machinePublicKey.length);
2561
- const encrypted = encryptWithEphemeralKey(combined, userPublicKey);
2562
- return encodeBase64(encrypted);
2563
- }
2564
- function decryptMachineEncryptionKey(encryptedData, userPrivateKey) {
2565
- if (userPrivateKey.length !== 32) {
2566
- return null;
2567
- }
2568
- try {
2569
- const encryptedBundle = decodeBase64(encryptedData);
2570
- const decrypted = decryptWithEphemeralKey(encryptedBundle, userPrivateKey);
2571
- if (!decrypted) {
2572
- return null;
2573
- }
2574
- const expectedLength = 32 + tweetnacl.secretbox.keyLength;
2575
- if (decrypted.length !== expectedLength) {
2576
- return null;
2577
- }
2578
- const machinePublicKey = decrypted.slice(0, 32);
2579
- const aesKey = decrypted.slice(32);
2580
- return { machinePublicKey, aesKey };
2581
- } catch (error) {
2582
- return null;
2583
- }
2584
- }
2585
- function createTaskEncryptionPayload(machineEncryptionKey) {
2586
- const taskDataKey = generateAESKey();
2587
- return {
2588
- taskDataKey,
2589
- dataEncryptionKey: encodeBase64(
2590
- encryptWithEphemeralKey(taskDataKey, machineEncryptionKey.machinePublicKey)
2591
- ),
2592
- ownerEncryptedDataKey: encodeBase64(
2593
- encryptAES(encodeBase64(taskDataKey), machineEncryptionKey.aesKey)
2594
- )
2595
- };
2596
- }
2597
- function encryptFileContent(fileContentBase64, dataKey) {
2598
- const encryptedWithVersion = encryptAES(fileContentBase64, dataKey);
2599
- const encryptedWithoutVersion = encryptedWithVersion.slice(1);
2600
- return encodeBase64(encryptedWithoutVersion);
2601
- }
2602
- function decryptFileContent(encryptedContent, dataKey) {
2603
- try {
2604
- const encryptedWithoutVersion = decodeBase64(encryptedContent);
2605
- const encryptedWithVersion = new Uint8Array(1 + encryptedWithoutVersion.length);
2606
- encryptedWithVersion.set([0], 0);
2607
- encryptedWithVersion.set(encryptedWithoutVersion, 1);
2608
- return decryptAES(encryptedWithVersion, dataKey);
2609
- } catch (error) {
2610
- return null;
2611
- }
2612
- }
2613
-
2614
2314
  const RTC_CHUNK_HEADER_SIZE = 16;
2615
2315
  const RtcChunkFlags = {
2616
2316
  Start: 1,
@@ -2963,15 +2663,21 @@ function getFileExtension(filePath) {
2963
2663
  return filePath.substring(lastDot).toLowerCase();
2964
2664
  }
2965
2665
 
2666
+ exports.AgentConfigValidationError = errors.AgentConfigValidationError;
2667
+ exports.AgentError = errors.AgentError;
2668
+ exports.AgentLoadError = errors.AgentLoadError;
2669
+ exports.AgentMetadataSchema = errors.AgentMetadataSchema;
2670
+ exports.AgentNotFoundError = errors.AgentNotFoundError;
2671
+ exports.ClaudeConfigSchema = errors.ClaudeConfigSchema;
2672
+ exports.FRAMEWORK_TYPES = errors.FRAMEWORK_TYPES;
2673
+ exports.FrameworkNotSupportedError = errors.FrameworkNotSupportedError;
2674
+ exports.MissingAgentFileError = errors.MissingAgentFileError;
2675
+ exports.getAgentContext = errors.getAgentContext;
2676
+ exports.setAgentContext = errors.setAgentContext;
2966
2677
  exports.ActiveAgentSchema = ActiveAgentSchema;
2967
2678
  exports.AddChatMemberRequestSchema = AddChatMemberRequestSchema;
2968
2679
  exports.AddChatMemberResponseSchema = AddChatMemberResponseSchema;
2969
- exports.AgentConfigValidationError = AgentConfigValidationError;
2970
2680
  exports.AgentCustomConfigSchema = AgentCustomConfigSchema;
2971
- exports.AgentError = AgentError;
2972
- exports.AgentLoadError = AgentLoadError;
2973
- exports.AgentMetadataSchema = AgentMetadataSchema;
2974
- exports.AgentNotFoundError = AgentNotFoundError;
2975
2681
  exports.AgentPermissionsSchema = AgentPermissionsSchema;
2976
2682
  exports.AgentSchema = AgentSchema;
2977
2683
  exports.AgentTypeSchema = AgentTypeSchema;
@@ -3005,7 +2711,6 @@ exports.ChatTypeSchema = ChatTypeSchema;
3005
2711
  exports.ChatWithMembersSchema = ChatWithMembersSchema;
3006
2712
  exports.ChatWorkersStatusRequestSchema = ChatWorkersStatusRequestSchema;
3007
2713
  exports.ChatWorkersStatusResponseSchema = ChatWorkersStatusResponseSchema;
3008
- exports.ClaudeConfigSchema = ClaudeConfigSchema;
3009
2714
  exports.CloudJoinApprovalRequestSchema = CloudJoinApprovalRequestSchema;
3010
2715
  exports.CloudJoinRequestSchema = CloudJoinRequestSchema;
3011
2716
  exports.CloudJoinResultQuerySchema = CloudJoinResultQuerySchema;
@@ -3061,14 +2766,12 @@ exports.ENTRY_FILE_PATTERNS = ENTRY_FILE_PATTERNS;
3061
2766
  exports.EnvironmentVariableSchema = EnvironmentVariableSchema;
3062
2767
  exports.EventAckSchema = EventAckSchema;
3063
2768
  exports.EventSchemaMap = EventSchemaMap;
3064
- exports.FRAMEWORK_TYPES = FRAMEWORK_TYPES;
3065
2769
  exports.FileItemSchema = FileItemSchema;
3066
2770
  exports.FileStatsSchema = FileStatsSchema;
3067
2771
  exports.FileVisibilitySchema = FileVisibilitySchema;
3068
2772
  exports.FillEventsRequestSchema = FillEventsRequestSchema;
3069
2773
  exports.FindTaskByAgentRequestSchema = FindTaskByAgentRequestSchema;
3070
2774
  exports.FindTaskByAgentResponseSchema = FindTaskByAgentResponseSchema;
3071
- exports.FrameworkNotSupportedError = FrameworkNotSupportedError;
3072
2775
  exports.GetAgentResponseSchema = GetAgentResponseSchema;
3073
2776
  exports.GetChatResponseSchema = GetChatResponseSchema;
3074
2777
  exports.GetEnvironmentVariablesResponseSchema = GetEnvironmentVariablesResponseSchema;
@@ -3129,7 +2832,6 @@ exports.MachineRtcRequestSchema = MachineRtcRequestSchema;
3129
2832
  exports.MachineRtcResponseSchema = MachineRtcResponseSchema;
3130
2833
  exports.MergePullRequestEventSchema = MergePullRequestEventSchema;
3131
2834
  exports.MergeRequestEventSchema = MergeRequestEventSchema;
3132
- exports.MissingAgentFileError = MissingAgentFileError;
3133
2835
  exports.OAuthAccountInfoSchema = OAuthAccountInfoSchema;
3134
2836
  exports.OAuthBindCallbackResponseSchema = OAuthBindCallbackResponseSchema;
3135
2837
  exports.OAuthBindQuerySchema = OAuthBindQuerySchema;
@@ -3250,8 +2952,6 @@ exports.WorkerStatusRequestSchema = WorkerStatusRequestSchema;
3250
2952
  exports.WorkerStatusValueSchema = WorkerStatusValueSchema;
3251
2953
  exports.WorkspaceFileRequestSchema = WorkspaceFileRequestSchema;
3252
2954
  exports.WorkspaceFileResponseSchema = WorkspaceFileResponseSchema;
3253
- exports.assertAgentExists = assertAgentExists;
3254
- exports.assertFileExists = assertFileExists;
3255
2955
  exports.baseTaskSchema = baseTaskSchema;
3256
2956
  exports.buildRtcChunkFrame = buildRtcChunkFrame;
3257
2957
  exports.cancelTaskRequestSchema = cancelTaskRequestSchema;
@@ -3270,7 +2970,6 @@ exports.decryptMachineEncryptionKey = decryptMachineEncryptionKey;
3270
2970
  exports.decryptSdkMessage = decryptSdkMessage;
3271
2971
  exports.decryptWithEphemeralKey = decryptWithEphemeralKey;
3272
2972
  exports.detectPreview = detectPreview;
3273
- exports.discoverPlugins = discoverPlugins;
3274
2973
  exports.encodeBase64 = encodeBase64;
3275
2974
  exports.encodeBase64Url = encodeBase64Url;
3276
2975
  exports.encodeRtcChunkHeader = encodeRtcChunkHeader;
@@ -3281,7 +2980,6 @@ exports.encryptSdkMessage = encryptSdkMessage;
3281
2980
  exports.encryptWithEphemeralKey = encryptWithEphemeralKey;
3282
2981
  exports.generateAESKey = generateAESKey;
3283
2982
  exports.generateAESKeyBase64 = generateAESKeyBase64;
3284
- exports.getAgentContext = getAgentContext;
3285
2983
  exports.getRandomBytes = getRandomBytes;
3286
2984
  exports.isAskUserMessage = isAskUserMessage;
3287
2985
  exports.isAskUserResponseMessage = isAskUserResponseMessage;
@@ -3289,18 +2987,14 @@ exports.isCompanionHeartbeatMessage = isCompanionHeartbeatMessage;
3289
2987
  exports.isCompanionReminderMessage = isCompanionReminderMessage;
3290
2988
  exports.isSDKMessage = isSDKMessage;
3291
2989
  exports.isSDKUserMessage = isSDKUserMessage;
3292
- exports.loadAgentConfig = loadAgentConfig;
2990
+ exports.isSubTaskAskUserMessage = isSubTaskAskUserMessage;
3293
2991
  exports.machineAuth = machineAuth;
3294
2992
  exports.permissionResponseRequestSchema = permissionResponseRequestSchema;
3295
- exports.replacePromptPlaceholders = replacePromptPlaceholders;
3296
2993
  exports.resumeTaskRequestSchema = resumeTaskRequestSchema;
3297
2994
  exports.resumeTaskSchema = resumeTaskSchema;
3298
- exports.setAgentContext = setAgentContext;
3299
2995
  exports.splitRtcChunkFrame = splitRtcChunkFrame;
3300
2996
  exports.startTaskSchema = startTaskSchema;
3301
2997
  exports.stopTaskRequestSchema = stopTaskRequestSchema;
3302
2998
  exports.userAuth = userAuth;
3303
- exports.validateAgentDirectory = validateAgentDirectory;
3304
- exports.validateFrameworkDirectory = validateFrameworkDirectory;
3305
2999
  exports.workerAuth = workerAuth;
3306
3000
  exports.workerTaskEvents = workerTaskEvents;