@agentrix/shared 2.2.3 → 2.2.5

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,305 +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)
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()
2352
2301
  });
2353
2302
  const RegisterCompanionResponseSchema = zod.z.object({
2354
2303
  agentId: zod.z.string(),
@@ -2359,243 +2308,9 @@ const RegisterCompanionResponseSchema = zod.z.object({
2359
2308
  });
2360
2309
  const CompanionEnsureResponseSchema = zod.z.object({
2361
2310
  agentDir: zod.z.string(),
2362
- workspaceDir: zod.z.string()
2311
+ homeDir: zod.z.string()
2363
2312
  });
2364
2313
 
2365
- const cryptoModule = typeof globalThis.crypto !== "undefined" ? globalThis.crypto : (async () => {
2366
- try {
2367
- const nodeCrypto = await import('node:crypto');
2368
- return nodeCrypto.webcrypto;
2369
- } catch {
2370
- throw new Error("Web Crypto API not available");
2371
- }
2372
- })();
2373
- async function getCrypto() {
2374
- if (typeof cryptoModule === "object" && cryptoModule !== null && "subtle" in cryptoModule) {
2375
- return cryptoModule;
2376
- }
2377
- return await cryptoModule;
2378
- }
2379
- async function hmac_sha512(key, data) {
2380
- const crypto = await getCrypto();
2381
- const cryptoKey = await crypto.subtle.importKey(
2382
- "raw",
2383
- key,
2384
- { name: "HMAC", hash: "SHA-512" },
2385
- false,
2386
- ["sign"]
2387
- );
2388
- const signature = await crypto.subtle.sign(
2389
- "HMAC",
2390
- cryptoKey,
2391
- data
2392
- );
2393
- return new Uint8Array(signature);
2394
- }
2395
-
2396
- async function deriveSecretKeyTreeRoot(seed, usage) {
2397
- const I = await hmac_sha512(new TextEncoder().encode(usage + " Master Seed"), seed);
2398
- return {
2399
- key: I.slice(0, 32),
2400
- chainCode: I.slice(32)
2401
- };
2402
- }
2403
- async function deriveSecretKeyTreeChild(chainCode, index) {
2404
- const data = new Uint8Array([0, ...new TextEncoder().encode(index)]);
2405
- const I = await hmac_sha512(chainCode, data);
2406
- return {
2407
- key: I.subarray(0, 32),
2408
- chainCode: I.subarray(32)
2409
- };
2410
- }
2411
- async function deriveKey(master, usage, path) {
2412
- let state = await deriveSecretKeyTreeRoot(master, usage);
2413
- let remaining = [...path];
2414
- while (remaining.length > 0) {
2415
- let index = remaining[0];
2416
- remaining = remaining.slice(1);
2417
- state = await deriveSecretKeyTreeChild(state.chainCode, index);
2418
- }
2419
- return state.key;
2420
- }
2421
-
2422
- function encodeBase64(buffer, variant = "base64") {
2423
- if (variant === "base64url") {
2424
- return encodeBase64Url(buffer);
2425
- }
2426
- return base64js__namespace.fromByteArray(buffer);
2427
- }
2428
- function encodeBase64Url(buffer) {
2429
- return base64js__namespace.fromByteArray(buffer).replaceAll("+", "-").replaceAll("/", "_").replaceAll("=", "");
2430
- }
2431
- function decodeBase64(base64, variant = "base64") {
2432
- if (!base64) {
2433
- throw new Error("Invalid base64 input: must be a non-empty string");
2434
- }
2435
- const cleaned = base64.replace(/\s/g, "");
2436
- if (!cleaned) {
2437
- throw new Error("Invalid base64 input: empty after removing whitespace");
2438
- }
2439
- try {
2440
- if (variant === "base64url") {
2441
- let base64Standard = cleaned.replace(/-/g, "+").replace(/_/g, "/");
2442
- const padding = (4 - base64Standard.length % 4) % 4;
2443
- if (padding > 0) {
2444
- base64Standard += "=".repeat(padding);
2445
- }
2446
- return base64js__namespace.toByteArray(base64Standard);
2447
- }
2448
- return base64js__namespace.toByteArray(cleaned);
2449
- } catch (error) {
2450
- throw new Error(`Failed to decode base64 (variant: ${variant}): ${error instanceof Error ? error.message : String(error)}`);
2451
- }
2452
- }
2453
- function getRandomBytes(size) {
2454
- return tweetnacl.randomBytes(size);
2455
- }
2456
- function generateAESKey() {
2457
- return getRandomBytes(tweetnacl.secretbox.keyLength);
2458
- }
2459
- function generateAESKeyBase64(variant = "base64") {
2460
- const key = generateAESKey();
2461
- return encodeBase64(key, variant);
2462
- }
2463
- function encryptAES(data, dataKey) {
2464
- if (dataKey.length !== tweetnacl.secretbox.keyLength) {
2465
- throw new Error(`Invalid key length: expected ${tweetnacl.secretbox.keyLength}, got ${dataKey.length}`);
2466
- }
2467
- const nonce = getRandomBytes(tweetnacl.secretbox.nonceLength);
2468
- const plaintext = new TextEncoder().encode(JSON.stringify(data));
2469
- const encrypted = tweetnacl.secretbox(plaintext, nonce, dataKey);
2470
- const bundle = new Uint8Array(1 + nonce.length + encrypted.length);
2471
- bundle.set([0], 0);
2472
- bundle.set(nonce, 1);
2473
- bundle.set(encrypted, 1 + nonce.length);
2474
- return bundle;
2475
- }
2476
- function decryptAES(bundle, dataKey) {
2477
- if (dataKey.length !== tweetnacl.secretbox.keyLength) {
2478
- return null;
2479
- }
2480
- if (bundle.length < 1) {
2481
- return null;
2482
- }
2483
- if (bundle[0] !== 0) {
2484
- return null;
2485
- }
2486
- const minLength = 1 + tweetnacl.secretbox.nonceLength + tweetnacl.secretbox.overheadLength;
2487
- if (bundle.length < minLength) {
2488
- return null;
2489
- }
2490
- const nonce = bundle.slice(1, 1 + tweetnacl.secretbox.nonceLength);
2491
- const ciphertext = bundle.slice(1 + tweetnacl.secretbox.nonceLength);
2492
- try {
2493
- const decrypted = tweetnacl.secretbox.open(ciphertext, nonce, dataKey);
2494
- if (!decrypted) {
2495
- return null;
2496
- }
2497
- return JSON.parse(new TextDecoder().decode(decrypted));
2498
- } catch (error) {
2499
- return null;
2500
- }
2501
- }
2502
- async function createKeyPairWithUit8Array(masterSecret) {
2503
- const contentDataKey = await deriveKey(masterSecret, "Agentrix EnCoder", ["content"]);
2504
- return tweetnacl.box.keyPair.fromSecretKey(contentDataKey);
2505
- }
2506
- async function createKeyPair(masterSecret, variant = "base64") {
2507
- return await createKeyPairWithUit8Array(decodeBase64(masterSecret, variant));
2508
- }
2509
- function decryptWithEphemeralKey(encryptedBundle, secretKey) {
2510
- const ephemeralPublicKey = encryptedBundle.slice(0, 32);
2511
- const nonce = encryptedBundle.slice(32, 32 + tweetnacl.box.nonceLength);
2512
- const encrypted = encryptedBundle.slice(32 + tweetnacl.box.nonceLength);
2513
- const decrypted = tweetnacl.box.open(encrypted, nonce, ephemeralPublicKey, secretKey);
2514
- if (!decrypted) {
2515
- return null;
2516
- }
2517
- return decrypted;
2518
- }
2519
- function encryptWithEphemeralKey(data, publicKey) {
2520
- const ephemeralKeyPair = tweetnacl.box.keyPair();
2521
- const nonce = getRandomBytes(tweetnacl.box.nonceLength);
2522
- const encrypted = tweetnacl.box(data, nonce, publicKey, ephemeralKeyPair.secretKey);
2523
- const result = new Uint8Array(ephemeralKeyPair.publicKey.length + nonce.length + encrypted.length);
2524
- result.set(ephemeralKeyPair.publicKey, 0);
2525
- result.set(nonce, ephemeralKeyPair.publicKey.length);
2526
- result.set(encrypted, ephemeralKeyPair.publicKey.length + nonce.length);
2527
- return result;
2528
- }
2529
- function encryptSdkMessage(message, dataKey) {
2530
- const encryptedWithVersion = encryptAES(message, dataKey);
2531
- const encryptedWithoutVersion = encryptedWithVersion.slice(1);
2532
- return encodeBase64(encryptedWithoutVersion);
2533
- }
2534
- function decryptSdkMessage(encryptedMessage, dataKey) {
2535
- try {
2536
- const encryptedWithoutVersion = decodeBase64(encryptedMessage);
2537
- const encryptedWithVersion = new Uint8Array(1 + encryptedWithoutVersion.length);
2538
- encryptedWithVersion.set([0], 0);
2539
- encryptedWithVersion.set(encryptedWithoutVersion, 1);
2540
- return decryptAES(encryptedWithVersion, dataKey);
2541
- } catch (error) {
2542
- return null;
2543
- }
2544
- }
2545
- function encryptMachineEncryptionKey(machinePublicKey, aesKey, userPublicKey) {
2546
- if (machinePublicKey.length !== 32) {
2547
- throw new Error(`Invalid machine public key length: expected 32, got ${machinePublicKey.length}`);
2548
- }
2549
- if (aesKey.length !== tweetnacl.secretbox.keyLength) {
2550
- throw new Error(`Invalid AES key length: expected ${tweetnacl.secretbox.keyLength}, got ${aesKey.length}`);
2551
- }
2552
- if (userPublicKey.length !== 32) {
2553
- throw new Error(`Invalid user public key length: expected 32, got ${userPublicKey.length}`);
2554
- }
2555
- const combined = new Uint8Array(machinePublicKey.length + aesKey.length);
2556
- combined.set(machinePublicKey, 0);
2557
- combined.set(aesKey, machinePublicKey.length);
2558
- const encrypted = encryptWithEphemeralKey(combined, userPublicKey);
2559
- return encodeBase64(encrypted);
2560
- }
2561
- function decryptMachineEncryptionKey(encryptedData, userPrivateKey) {
2562
- if (userPrivateKey.length !== 32) {
2563
- return null;
2564
- }
2565
- try {
2566
- const encryptedBundle = decodeBase64(encryptedData);
2567
- const decrypted = decryptWithEphemeralKey(encryptedBundle, userPrivateKey);
2568
- if (!decrypted) {
2569
- return null;
2570
- }
2571
- const expectedLength = 32 + tweetnacl.secretbox.keyLength;
2572
- if (decrypted.length !== expectedLength) {
2573
- return null;
2574
- }
2575
- const machinePublicKey = decrypted.slice(0, 32);
2576
- const aesKey = decrypted.slice(32);
2577
- return { machinePublicKey, aesKey };
2578
- } catch (error) {
2579
- return null;
2580
- }
2581
- }
2582
- function encryptFileContent(fileContentBase64, dataKey) {
2583
- const encryptedWithVersion = encryptAES(fileContentBase64, dataKey);
2584
- const encryptedWithoutVersion = encryptedWithVersion.slice(1);
2585
- return encodeBase64(encryptedWithoutVersion);
2586
- }
2587
- function decryptFileContent(encryptedContent, dataKey) {
2588
- try {
2589
- const encryptedWithoutVersion = decodeBase64(encryptedContent);
2590
- const encryptedWithVersion = new Uint8Array(1 + encryptedWithoutVersion.length);
2591
- encryptedWithVersion.set([0], 0);
2592
- encryptedWithVersion.set(encryptedWithoutVersion, 1);
2593
- return decryptAES(encryptedWithVersion, dataKey);
2594
- } catch (error) {
2595
- return null;
2596
- }
2597
- }
2598
-
2599
2314
  const RTC_CHUNK_HEADER_SIZE = 16;
2600
2315
  const RtcChunkFlags = {
2601
2316
  Start: 1,
@@ -2948,15 +2663,21 @@ function getFileExtension(filePath) {
2948
2663
  return filePath.substring(lastDot).toLowerCase();
2949
2664
  }
2950
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;
2951
2677
  exports.ActiveAgentSchema = ActiveAgentSchema;
2952
2678
  exports.AddChatMemberRequestSchema = AddChatMemberRequestSchema;
2953
2679
  exports.AddChatMemberResponseSchema = AddChatMemberResponseSchema;
2954
- exports.AgentConfigValidationError = AgentConfigValidationError;
2955
2680
  exports.AgentCustomConfigSchema = AgentCustomConfigSchema;
2956
- exports.AgentError = AgentError;
2957
- exports.AgentLoadError = AgentLoadError;
2958
- exports.AgentMetadataSchema = AgentMetadataSchema;
2959
- exports.AgentNotFoundError = AgentNotFoundError;
2960
2681
  exports.AgentPermissionsSchema = AgentPermissionsSchema;
2961
2682
  exports.AgentSchema = AgentSchema;
2962
2683
  exports.AgentTypeSchema = AgentTypeSchema;
@@ -2990,7 +2711,6 @@ exports.ChatTypeSchema = ChatTypeSchema;
2990
2711
  exports.ChatWithMembersSchema = ChatWithMembersSchema;
2991
2712
  exports.ChatWorkersStatusRequestSchema = ChatWorkersStatusRequestSchema;
2992
2713
  exports.ChatWorkersStatusResponseSchema = ChatWorkersStatusResponseSchema;
2993
- exports.ClaudeConfigSchema = ClaudeConfigSchema;
2994
2714
  exports.CloudJoinApprovalRequestSchema = CloudJoinApprovalRequestSchema;
2995
2715
  exports.CloudJoinRequestSchema = CloudJoinRequestSchema;
2996
2716
  exports.CloudJoinResultQuerySchema = CloudJoinResultQuerySchema;
@@ -3046,14 +2766,12 @@ exports.ENTRY_FILE_PATTERNS = ENTRY_FILE_PATTERNS;
3046
2766
  exports.EnvironmentVariableSchema = EnvironmentVariableSchema;
3047
2767
  exports.EventAckSchema = EventAckSchema;
3048
2768
  exports.EventSchemaMap = EventSchemaMap;
3049
- exports.FRAMEWORK_TYPES = FRAMEWORK_TYPES;
3050
2769
  exports.FileItemSchema = FileItemSchema;
3051
2770
  exports.FileStatsSchema = FileStatsSchema;
3052
2771
  exports.FileVisibilitySchema = FileVisibilitySchema;
3053
2772
  exports.FillEventsRequestSchema = FillEventsRequestSchema;
3054
2773
  exports.FindTaskByAgentRequestSchema = FindTaskByAgentRequestSchema;
3055
2774
  exports.FindTaskByAgentResponseSchema = FindTaskByAgentResponseSchema;
3056
- exports.FrameworkNotSupportedError = FrameworkNotSupportedError;
3057
2775
  exports.GetAgentResponseSchema = GetAgentResponseSchema;
3058
2776
  exports.GetChatResponseSchema = GetChatResponseSchema;
3059
2777
  exports.GetEnvironmentVariablesResponseSchema = GetEnvironmentVariablesResponseSchema;
@@ -3114,7 +2832,6 @@ exports.MachineRtcRequestSchema = MachineRtcRequestSchema;
3114
2832
  exports.MachineRtcResponseSchema = MachineRtcResponseSchema;
3115
2833
  exports.MergePullRequestEventSchema = MergePullRequestEventSchema;
3116
2834
  exports.MergeRequestEventSchema = MergeRequestEventSchema;
3117
- exports.MissingAgentFileError = MissingAgentFileError;
3118
2835
  exports.OAuthAccountInfoSchema = OAuthAccountInfoSchema;
3119
2836
  exports.OAuthBindCallbackResponseSchema = OAuthBindCallbackResponseSchema;
3120
2837
  exports.OAuthBindQuerySchema = OAuthBindQuerySchema;
@@ -3235,8 +2952,6 @@ exports.WorkerStatusRequestSchema = WorkerStatusRequestSchema;
3235
2952
  exports.WorkerStatusValueSchema = WorkerStatusValueSchema;
3236
2953
  exports.WorkspaceFileRequestSchema = WorkspaceFileRequestSchema;
3237
2954
  exports.WorkspaceFileResponseSchema = WorkspaceFileResponseSchema;
3238
- exports.assertAgentExists = assertAgentExists;
3239
- exports.assertFileExists = assertFileExists;
3240
2955
  exports.baseTaskSchema = baseTaskSchema;
3241
2956
  exports.buildRtcChunkFrame = buildRtcChunkFrame;
3242
2957
  exports.cancelTaskRequestSchema = cancelTaskRequestSchema;
@@ -3245,6 +2960,7 @@ exports.createEventId = createEventId;
3245
2960
  exports.createKeyPair = createKeyPair;
3246
2961
  exports.createKeyPairWithUit8Array = createKeyPairWithUit8Array;
3247
2962
  exports.createMergeRequestSchema = createMergeRequestSchema;
2963
+ exports.createTaskEncryptionPayload = createTaskEncryptionPayload;
3248
2964
  exports.createTaskSchema = createTaskSchema;
3249
2965
  exports.decodeBase64 = decodeBase64;
3250
2966
  exports.decodeRtcChunkHeader = decodeRtcChunkHeader;
@@ -3254,7 +2970,6 @@ exports.decryptMachineEncryptionKey = decryptMachineEncryptionKey;
3254
2970
  exports.decryptSdkMessage = decryptSdkMessage;
3255
2971
  exports.decryptWithEphemeralKey = decryptWithEphemeralKey;
3256
2972
  exports.detectPreview = detectPreview;
3257
- exports.discoverPlugins = discoverPlugins;
3258
2973
  exports.encodeBase64 = encodeBase64;
3259
2974
  exports.encodeBase64Url = encodeBase64Url;
3260
2975
  exports.encodeRtcChunkHeader = encodeRtcChunkHeader;
@@ -3265,7 +2980,6 @@ exports.encryptSdkMessage = encryptSdkMessage;
3265
2980
  exports.encryptWithEphemeralKey = encryptWithEphemeralKey;
3266
2981
  exports.generateAESKey = generateAESKey;
3267
2982
  exports.generateAESKeyBase64 = generateAESKeyBase64;
3268
- exports.getAgentContext = getAgentContext;
3269
2983
  exports.getRandomBytes = getRandomBytes;
3270
2984
  exports.isAskUserMessage = isAskUserMessage;
3271
2985
  exports.isAskUserResponseMessage = isAskUserResponseMessage;
@@ -3273,18 +2987,14 @@ exports.isCompanionHeartbeatMessage = isCompanionHeartbeatMessage;
3273
2987
  exports.isCompanionReminderMessage = isCompanionReminderMessage;
3274
2988
  exports.isSDKMessage = isSDKMessage;
3275
2989
  exports.isSDKUserMessage = isSDKUserMessage;
3276
- exports.loadAgentConfig = loadAgentConfig;
2990
+ exports.isSubTaskAskUserMessage = isSubTaskAskUserMessage;
3277
2991
  exports.machineAuth = machineAuth;
3278
2992
  exports.permissionResponseRequestSchema = permissionResponseRequestSchema;
3279
- exports.replacePromptPlaceholders = replacePromptPlaceholders;
3280
2993
  exports.resumeTaskRequestSchema = resumeTaskRequestSchema;
3281
2994
  exports.resumeTaskSchema = resumeTaskSchema;
3282
- exports.setAgentContext = setAgentContext;
3283
2995
  exports.splitRtcChunkFrame = splitRtcChunkFrame;
3284
2996
  exports.startTaskSchema = startTaskSchema;
3285
2997
  exports.stopTaskRequestSchema = stopTaskRequestSchema;
3286
2998
  exports.userAuth = userAuth;
3287
- exports.validateAgentDirectory = validateAgentDirectory;
3288
- exports.validateFrameworkDirectory = validateFrameworkDirectory;
3289
2999
  exports.workerAuth = workerAuth;
3290
3000
  exports.workerTaskEvents = workerTaskEvents;