auramaxx 0.0.13 → 0.0.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +24 -24
  3. package/.next/app-path-routes-manifest.json +6 -6
  4. package/.next/build-manifest.json +2 -2
  5. package/.next/prerender-manifest.json +36 -36
  6. package/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  7. package/.next/server/app/_not-found.html +1 -1
  8. package/.next/server/app/_not-found.rsc +1 -1
  9. package/.next/server/app/api/[...doc]/page_client-reference-manifest.js +1 -1
  10. package/.next/server/app/api/agent-requests/route_client-reference-manifest.js +1 -1
  11. package/.next/server/app/api/apps/install/route_client-reference-manifest.js +1 -1
  12. package/.next/server/app/api/apps/manifests/route_client-reference-manifest.js +1 -1
  13. package/.next/server/app/api/apps/static/[...path]/route_client-reference-manifest.js +1 -1
  14. package/.next/server/app/api/docs/plain/route_client-reference-manifest.js +1 -1
  15. package/.next/server/app/api/events/route_client-reference-manifest.js +1 -1
  16. package/.next/server/app/api/import-from-openclaw/[channel]/route_client-reference-manifest.js +1 -1
  17. package/.next/server/app/api/import-from-openclaw/route_client-reference-manifest.js +1 -1
  18. package/.next/server/app/api/import-from-openclaw/validate/[channel]/route_client-reference-manifest.js +1 -1
  19. package/.next/server/app/api/page_client-reference-manifest.js +1 -1
  20. package/.next/server/app/api/restart/route_client-reference-manifest.js +1 -1
  21. package/.next/server/app/api/update/route.js +7 -8
  22. package/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  23. package/.next/server/app/api/version/route.js +1 -1
  24. package/.next/server/app/api/version/route_client-reference-manifest.js +1 -1
  25. package/.next/server/app/api/workspace/[id]/apps/[wid]/route_client-reference-manifest.js +1 -1
  26. package/.next/server/app/api/workspace/[id]/apps/route_client-reference-manifest.js +1 -1
  27. package/.next/server/app/api/workspace/[id]/export/route_client-reference-manifest.js +1 -1
  28. package/.next/server/app/api/workspace/[id]/route_client-reference-manifest.js +1 -1
  29. package/.next/server/app/api/workspace/config/route_client-reference-manifest.js +1 -1
  30. package/.next/server/app/api/workspace/import/route_client-reference-manifest.js +1 -1
  31. package/.next/server/app/api/workspace/route_client-reference-manifest.js +1 -1
  32. package/.next/server/app/app-legacy-do-not-use/page_client-reference-manifest.js +1 -1
  33. package/.next/server/app/app-legacy-do-not-use.html +1 -1
  34. package/.next/server/app/app-legacy-do-not-use.rsc +1 -1
  35. package/.next/server/app/approve/[actionId]/page_client-reference-manifest.js +1 -1
  36. package/.next/server/app/docs/[...doc]/page_client-reference-manifest.js +1 -1
  37. package/.next/server/app/docs/page_client-reference-manifest.js +1 -1
  38. package/.next/server/app/health/page_client-reference-manifest.js +1 -1
  39. package/.next/server/app/health.html +1 -1
  40. package/.next/server/app/health.rsc +1 -1
  41. package/.next/server/app/hello/page_client-reference-manifest.js +1 -1
  42. package/.next/server/app/hello.html +1 -1
  43. package/.next/server/app/hello.rsc +1 -1
  44. package/.next/server/app/index.html +1 -1
  45. package/.next/server/app/index.rsc +2 -2
  46. package/.next/server/app/page.js +1 -1
  47. package/.next/server/app/page_client-reference-manifest.js +1 -1
  48. package/.next/server/app/privacy/page_client-reference-manifest.js +1 -1
  49. package/.next/server/app/privacy.html +1 -1
  50. package/.next/server/app/privacy.rsc +1 -1
  51. package/.next/server/app/share/[token]/page_client-reference-manifest.js +1 -1
  52. package/.next/server/app/terms/page_client-reference-manifest.js +1 -1
  53. package/.next/server/app/terms.html +1 -1
  54. package/.next/server/app/terms.rsc +1 -1
  55. package/.next/server/app/yo/page.js +1 -1
  56. package/.next/server/app/yo/page_client-reference-manifest.js +1 -1
  57. package/.next/server/app/yo.html +1 -1
  58. package/.next/server/app/yo.rsc +2 -2
  59. package/.next/server/app-paths-manifest.json +6 -6
  60. package/.next/server/functions-config-manifest.json +1 -1
  61. package/.next/server/pages/404.html +1 -1
  62. package/.next/server/pages/500.html +1 -1
  63. package/.next/server/server-reference-manifest.json +1 -1
  64. package/.next/static/chunks/app/{page-16dfcd1c7cc88bcc.js → page-617dd0e03d79e94f.js} +1 -1
  65. package/.next/static/chunks/app/yo/page-fceb03605805cb44.js +1 -0
  66. package/.next/trace +28 -28
  67. package/README.md +1 -1
  68. package/docs/AGENT_SETUP.md +1 -1
  69. package/docs/AUTH.md +1 -1
  70. package/docs/MCP.md +12 -0
  71. package/docs/SKILLS.md +1 -1
  72. package/docs/api/secrets/credentials.md +9 -0
  73. package/docs/external/POLICY.md +2 -2
  74. package/package.json +1 -1
  75. package/skills/auramaxx/SKILL.md +13 -31
  76. package/skills/auramaxx/docs/AGENT_SETUP.md +1 -1
  77. package/src/app/UnlockPageClient.tsx +9 -9
  78. package/src/app/api/update/route.ts +9 -10
  79. package/src/app/yo/page.tsx +1 -1
  80. package/src/server/cli/commands/agent.ts +58 -0
  81. package/src/server/cli/commands/init.ts +9 -9
  82. package/src/server/cli/lib/credential-resolve.ts +20 -1
  83. package/src/server/cli/lib/local-agent-trust.ts +4 -3
  84. package/src/server/lib/agent-profiles.ts +4 -3
  85. package/src/server/lib/update-check.ts +4 -0
  86. package/src/server/mcp/server.ts +83 -14
  87. package/src/server/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  88. package/src/server/routes/credentials.ts +48 -5
  89. package/src/server/tests/cli/agent-auth.test.ts +114 -0
  90. package/src/server/tests/cli/local-agent-trust.test.ts +11 -6
  91. package/src/server/tests/endpoints/credentials.test.ts +40 -18
  92. package/src/server/tests/endpoints/escalation-migration-gate.test.ts +1 -1
  93. package/src/server/tests/lib/agent-profiles.test.ts +6 -0
  94. package/src/server/tests/lib/update-check.test.ts +9 -1
  95. package/.next/static/chunks/app/yo/page-719dc5f213fdfb30.js +0 -1
  96. /package/.next/static/{WshFGr6RxGYP6AbWuT9OG → 8ep63d3doVXsmbm1zj5k5}/_buildManifest.js +0 -0
  97. /package/.next/static/{WshFGr6RxGYP6AbWuT9OG → 8ep63d3doVXsmbm1zj5k5}/_ssgManifest.js +0 -0
@@ -43,7 +43,9 @@ import {
43
43
  resolveDiaryDate,
44
44
  } from '../lib/diary';
45
45
  import {
46
+ canonicalizeCredentialFieldKey,
46
47
  getCredentialFieldValue,
48
+ getCredentialPrimaryFieldKey,
47
49
  NOTE_CONTENT_KEY,
48
50
  } from '../../../shared/credential-field-schema';
49
51
  import { defaultSecretEnvVarName, normalizeEnvVarName } from '../lib/secret-env';
@@ -1013,7 +1015,7 @@ async function resolveCredentialByName(
1013
1015
  name: string,
1014
1016
  authTokenOverride?: string,
1015
1017
  ): Promise<
1016
- | { credentialId: string; credentialName: string }
1018
+ | { credentialId: string; credentialName: string; credentialType?: string }
1017
1019
  | { error: string; escalation?: McpToolResponse }
1018
1020
  > {
1019
1021
  const base = WALLET_BASE();
@@ -1045,7 +1047,7 @@ async function resolveCredentialByName(
1045
1047
  }
1046
1048
  if (!res.ok) continue;
1047
1049
 
1048
- const data = await res.json() as { credentials: Array<{ id: string; name: string; agentId: string }> };
1050
+ const data = await res.json() as { credentials: Array<{ id: string; name: string; type?: string; agentId: string }> };
1049
1051
  if (!data.credentials || data.credentials.length === 0) continue;
1050
1052
 
1051
1053
  const decision = evaluateProjectScopeAccess({
@@ -1075,7 +1077,11 @@ async function resolveCredentialByName(
1075
1077
  const scopedCandidates = data.credentials.filter((c) => allowedIds.has(c.id));
1076
1078
  if (scopedCandidates.length === 0) continue;
1077
1079
 
1078
- return { credentialId: scopedCandidates[0].id, credentialName: scopedCandidates[0].name };
1080
+ return {
1081
+ credentialId: scopedCandidates[0].id,
1082
+ credentialName: scopedCandidates[0].name,
1083
+ credentialType: scopedCandidates[0].type,
1084
+ };
1079
1085
  }
1080
1086
  } catch (err) {
1081
1087
  return { error: `Search failed: ${err}` };
@@ -1184,6 +1190,20 @@ function extractPrimarySecretValue(
1184
1190
  return noteField || sensitiveField || fields[0]?.value || '';
1185
1191
  }
1186
1192
 
1193
+ function findCredentialFieldValue(
1194
+ credentialType: string | undefined,
1195
+ fields: Array<{ key: string; value: string; type?: string; sensitive?: boolean }>,
1196
+ requestedField: string,
1197
+ ): string | undefined {
1198
+ const trimmed = String(requestedField || '').trim();
1199
+ if (!trimmed) return undefined;
1200
+ const directMatch = fields.find((field) => field.key.toLowerCase() === trimmed.toLowerCase());
1201
+ if (directMatch) return directMatch.value;
1202
+ const canonicalKey = canonicalizeCredentialFieldKey(String(credentialType || 'custom'), trimmed).toLowerCase();
1203
+ const canonicalMatch = fields.find((field) => field.key.toLowerCase() === canonicalKey);
1204
+ return canonicalMatch?.value;
1205
+ }
1206
+
1187
1207
  function renderSecretValue(secretValue: string, dangerPlaintext: boolean): string {
1188
1208
  return dangerPlaintext ? secretValue : '*******';
1189
1209
  }
@@ -1444,9 +1464,10 @@ function applyClaimResponseToPendingAuth(
1444
1464
  // ── get_secret ─────────────────────────────────────────────────────────
1445
1465
  server.tool(
1446
1466
  'get_secret',
1447
- 'Look up a stored credential/secret by name or tag, inject its primary value into a default env var, and return redacted metadata unless dangerPlaintext is explicitly enabled.',
1467
+ 'Look up a stored credential/secret by name or tag, inject its primary value (or explicit field) into a default env var, and return redacted metadata unless dangerPlaintext is explicitly enabled.',
1448
1468
  {
1449
1469
  name: z.string().describe('Name or tag to search for (e.g. "GitHub", "openai", "deploy")'),
1470
+ field: z.string().optional().describe('Optional explicit field key to read (e.g. "password", "cvv"). When omitted, reads the credential primary field.'),
1450
1471
  command: z.array(z.string()).optional().describe('Optional command + args to spawn with injected env var (e.g. ["node", "script.js"]). If omitted, sets env var in MCP server process and returns WHATDO guidance.'),
1451
1472
  dangerPlaintext: z.boolean().optional().describe('If true, include plaintext secret in output (unsafe). Defaults to false (masked).'),
1452
1473
  reqId: z.string().optional().describe('Optional approval request id for one-shot claim retry binding'),
@@ -1454,11 +1475,13 @@ server.tool(
1454
1475
  async (input) => {
1455
1476
  const {
1456
1477
  name,
1478
+ field,
1457
1479
  command,
1458
1480
  dangerPlaintext,
1459
1481
  reqId,
1460
- } = input as { name: string; command?: string[]; dangerPlaintext?: boolean; reqId?: string };
1482
+ } = input as { name: string; field?: string; command?: string[]; dangerPlaintext?: boolean; reqId?: string };
1461
1483
  const revealPlaintext = dangerPlaintext === true;
1484
+ const requestedField = String(field || '').trim();
1462
1485
 
1463
1486
  if (isGetSecretRateLimited()) {
1464
1487
  return { content: [{ type: 'text' as const, text: JSON.stringify({ error: 'Rate limited — too many get_secret requests. Try again in 1 minute.' }) }] };
@@ -1473,7 +1496,7 @@ server.tool(
1473
1496
  const credentialNameFromBinding = authContext.mode === 'one_shot' ? authContext.binding?.credentialName : undefined;
1474
1497
 
1475
1498
  const resolved = credentialIdFromBinding
1476
- ? { credentialId: credentialIdFromBinding, credentialName: credentialNameFromBinding || name }
1499
+ ? { credentialId: credentialIdFromBinding, credentialName: credentialNameFromBinding || name, credentialType: undefined }
1477
1500
  : await resolveCredentialByName(name, authToken);
1478
1501
  if ('error' in resolved) {
1479
1502
  if ('escalation' in resolved && resolved.escalation) return resolved.escalation;
@@ -1481,6 +1504,17 @@ server.tool(
1481
1504
  }
1482
1505
 
1483
1506
  const { credentialId, credentialName } = resolved;
1507
+ const requestedFields = requestedField
1508
+ ? [requestedField]
1509
+ : resolved.credentialType
1510
+ ? [getCredentialPrimaryFieldKey(resolved.credentialType)]
1511
+ : [];
1512
+ const readPayload = requestedFields.length > 0
1513
+ ? { requestedFields }
1514
+ : {};
1515
+ const readBody = requestedFields.length > 0
1516
+ ? JSON.stringify(readPayload)
1517
+ : undefined;
1484
1518
  if (authContext.mode === 'one_shot' && authContext.reqId && authContext.binding) {
1485
1519
  const bindingError = validateOneShotCredentialReadBinding({
1486
1520
  reqId: authContext.reqId,
@@ -1499,10 +1533,12 @@ server.tool(
1499
1533
  method: 'POST',
1500
1534
  headers: {
1501
1535
  'Authorization': `Bearer ${authToken}`,
1536
+ ...(readBody ? { 'Content-Type': 'application/json' } : {}),
1502
1537
  'X-Secret-Surface': 'get_secret',
1503
1538
  'X-Credential-Name': credentialName || name,
1504
1539
  'X-Aura-Original-Command': `mcp get_secret ${JSON.stringify(name)}`,
1505
1540
  },
1541
+ ...(readBody ? { body: readBody } : {}),
1506
1542
  signal: AbortSignal.timeout(5000),
1507
1543
  });
1508
1544
 
@@ -1516,7 +1552,7 @@ server.tool(
1516
1552
  permissions: ['secret:read'],
1517
1553
  endpoint: `/credentials/${credentialId}/read`,
1518
1554
  method: 'POST',
1519
- body: {},
1555
+ body: readPayload,
1520
1556
  });
1521
1557
  }
1522
1558
  return { content: [{ type: 'text' as const, text: JSON.stringify({ error: `Read failed (${res.status}): ${text}` }) }] };
@@ -1549,8 +1585,17 @@ server.tool(
1549
1585
  }
1550
1586
  }
1551
1587
 
1552
- const secretValue = extractPrimarySecretValue(decrypted.fields);
1588
+ const requestedValue = requestedField
1589
+ ? findCredentialFieldValue(decrypted.type || resolved.credentialType, decrypted.fields, requestedField)
1590
+ : undefined;
1591
+ const secretValue = requestedValue !== undefined
1592
+ ? requestedValue
1593
+ : extractPrimarySecretValue(decrypted.fields);
1553
1594
  if (!secretValue) {
1595
+ if (requestedField && requestedValue === undefined) {
1596
+ const availableFields = decrypted.fields.map((entry) => entry.key).join(', ');
1597
+ return { content: [{ type: 'text' as const, text: JSON.stringify({ error: `Field "${requestedField}" not found on credential "${credentialName || name}"`, availableFields }) }] };
1598
+ }
1554
1599
  return { content: [{ type: 'text' as const, text: JSON.stringify({ error: `Credential "${credentialName || name}" has no extractable secret value` }) }] };
1555
1600
  }
1556
1601
 
@@ -1933,9 +1978,10 @@ server.tool(
1933
1978
  // ── inject_secret ──────────────────────────────────────────────────────
1934
1979
  server.tool(
1935
1980
  'inject_secret',
1936
- 'Look up a credential by name, extract its primary secret field, and inject it into env for MCP process or a child command. Output is redacted unless dangerPlaintext is enabled.',
1981
+ 'Look up a credential by name, extract its primary secret field (or explicit field), and inject it into env for MCP process or a child command. Output is redacted unless dangerPlaintext is enabled.',
1937
1982
  {
1938
1983
  name: z.string().describe('Name or tag of the credential to inject'),
1984
+ field: z.string().optional().describe('Optional explicit field key to inject instead of the credential primary field.'),
1939
1985
  envVar: z.string().optional().describe('Optional environment variable name (defaults to AURA_{SECRETNAME}, e.g. "AURA_OPENAI_API_KEY")'),
1940
1986
  command: z.array(z.string()).optional().describe('Optional command + args to spawn with injected env var (e.g. ["node", "script.js"]). If omitted, sets env var in MCP server process and returns WHATDO guidance.'),
1941
1987
  dangerPlaintext: z.boolean().optional().describe('If true, include plaintext secret in output (unsafe). Defaults to false (masked).'),
@@ -1944,12 +1990,14 @@ server.tool(
1944
1990
  async (input) => {
1945
1991
  const {
1946
1992
  name,
1993
+ field,
1947
1994
  envVar,
1948
1995
  command,
1949
1996
  dangerPlaintext,
1950
1997
  reqId,
1951
- } = input as { name: string; envVar?: string; command?: string[]; dangerPlaintext?: boolean; reqId?: string };
1998
+ } = input as { name: string; field?: string; envVar?: string; command?: string[]; dangerPlaintext?: boolean; reqId?: string };
1952
1999
  const revealPlaintext = dangerPlaintext === true;
2000
+ const requestedField = String(field || '').trim();
1953
2001
  const resolvedEnvVar = normalizeEnvVarName(envVar || defaultSecretEnvVarName(name));
1954
2002
  if (!resolvedEnvVar) {
1955
2003
  return { content: [{ type: 'text' as const, text: JSON.stringify({ error: 'Invalid envVar. Expected shell env var format like AURA_SECRET or GITHUB_PAT.' }) }] };
@@ -1968,7 +2016,7 @@ server.tool(
1968
2016
  const credentialNameFromBinding = authContext.mode === 'one_shot' ? authContext.binding?.credentialName : undefined;
1969
2017
 
1970
2018
  const resolved = credentialIdFromBinding
1971
- ? { credentialId: credentialIdFromBinding, credentialName: credentialNameFromBinding || name }
2019
+ ? { credentialId: credentialIdFromBinding, credentialName: credentialNameFromBinding || name, credentialType: undefined }
1972
2020
  : await resolveCredentialByName(name, authToken);
1973
2021
  if ('error' in resolved) {
1974
2022
  if ('escalation' in resolved && resolved.escalation) return resolved.escalation;
@@ -1976,6 +2024,17 @@ server.tool(
1976
2024
  }
1977
2025
 
1978
2026
  const base = WALLET_BASE();
2027
+ const requestedFields = requestedField
2028
+ ? [requestedField]
2029
+ : resolved.credentialType
2030
+ ? [getCredentialPrimaryFieldKey(resolved.credentialType)]
2031
+ : [];
2032
+ const readPayload = requestedFields.length > 0
2033
+ ? { requestedFields }
2034
+ : {};
2035
+ const readBody = requestedFields.length > 0
2036
+ ? JSON.stringify(readPayload)
2037
+ : undefined;
1979
2038
  if (authContext.mode === 'one_shot' && authContext.reqId && authContext.binding) {
1980
2039
  const bindingError = validateOneShotCredentialReadBinding({
1981
2040
  reqId: authContext.reqId,
@@ -1994,11 +2053,13 @@ server.tool(
1994
2053
  method: 'POST',
1995
2054
  headers: {
1996
2055
  'Authorization': `Bearer ${authToken}`,
2056
+ ...(readBody ? { 'Content-Type': 'application/json' } : {}),
1997
2057
  'X-Secret-Surface': 'inject_secret',
1998
2058
  'X-Secret-EnvVar': resolvedEnvVar,
1999
2059
  'X-Credential-Name': resolved.credentialName || name,
2000
2060
  'X-Aura-Original-Command': `mcp inject_secret ${JSON.stringify(name)}`,
2001
2061
  },
2062
+ ...(readBody ? { body: readBody } : {}),
2002
2063
  signal: AbortSignal.timeout(5000),
2003
2064
  });
2004
2065
 
@@ -2012,7 +2073,7 @@ server.tool(
2012
2073
  permissions: ['secret:read'],
2013
2074
  endpoint: `/credentials/${resolved.credentialId}/read`,
2014
2075
  method: 'POST',
2015
- body: {},
2076
+ body: readPayload,
2016
2077
  });
2017
2078
  }
2018
2079
  return { content: [{ type: 'text' as const, text: JSON.stringify({ error: `Read failed (${res.status}): ${text}` }) }] };
@@ -2021,10 +2082,18 @@ server.tool(
2021
2082
  const data = await res.json() as { encrypted: string };
2022
2083
  const decrypted = decryptCredentialPayload(data.encrypted);
2023
2084
 
2024
- // Extract primary secret field
2025
- secretValue = extractPrimarySecretValue(decrypted.fields);
2085
+ const requestedValue = requestedField
2086
+ ? findCredentialFieldValue(decrypted.type || resolved.credentialType, decrypted.fields, requestedField)
2087
+ : undefined;
2088
+ secretValue = requestedValue !== undefined
2089
+ ? requestedValue
2090
+ : extractPrimarySecretValue(decrypted.fields);
2026
2091
 
2027
2092
  if (!secretValue) {
2093
+ if (requestedField && requestedValue === undefined) {
2094
+ const availableFields = decrypted.fields.map((entry) => entry.key).join(', ');
2095
+ return { content: [{ type: 'text' as const, text: JSON.stringify({ error: `Field "${requestedField}" not found on credential "${resolved.credentialName || name}"`, availableFields }) }] };
2096
+ }
2028
2097
  return { content: [{ type: 'text' as const, text: JSON.stringify({ error: `Credential "${name}" has no extractable secret value` }) }] };
2029
2098
  }
2030
2099
  } catch (err) {
@@ -1 +1 @@
1
- {"version":"4.0.18","results":[[":tests/send.test.ts",{"duration":162.08154100000002,"failed":false}],[":tests/approve.test.ts",{"duration":257.27824999999996,"failed":false}],[":tests/unlock.test.ts",{"duration":213.61050000000003,"failed":false}],[":tests/setup.test.ts",{"duration":128.30779199999998,"failed":false}],[":tests/e2e.test.ts",{"duration":4341.373875,"failed":false}],[":tests/wallet.test.ts",{"duration":1768.446334,"failed":false}],[":tests/auth.test.ts",{"duration":174.709292,"failed":false}],[":tests/fund.test.ts",{"duration":820.6141660000001,"failed":false}],[":tests/integration/agent-flow.test.ts",{"duration":6350.61575,"failed":false}],[":tests/auth/permissions.test.ts",{"duration":6955.744291999999,"failed":false}],[":tests/auth/middleware.test.ts",{"duration":8667.608209,"failed":false}],[":tests/lib/sessions.test.ts",{"duration":100.3447920000001,"failed":false}],[":tests/lib/auth.test.ts",{"duration":4552.982083,"failed":false}],[":tests/endpoints/unlock.test.ts",{"duration":10486.351083,"failed":false}],[":tests/endpoints/wallet.test.ts",{"duration":4370.477584,"failed":false}],[":tests/endpoints/approve.test.ts",{"duration":497.64808300000004,"failed":false}],[":tests/endpoints/fund.test.ts",{"duration":1897.905,"failed":false}],[":tests/endpoints/send.test.ts",{"duration":2268.8852079999997,"failed":false}],[":tests/endpoints/auth.test.ts",{"duration":1334.914333,"failed":false}],[":tests/endpoints/setup.test.ts",{"duration":5293.225625,"failed":false}],[":tests/lib/uniswap.test.ts",{"duration":21.776292000000012,"failed":false}],[":tests/auth/apikeys.test.ts",{"duration":10995.417958,"failed":false}],[":tests/endpoints/wallet-data.test.ts",{"duration":2099.3379170000003,"failed":false}],[":tests/endpoints/swap.test.ts",{"duration":1653.693583,"failed":false}],[":tests/endpoints/token-clearing.test.ts",{"duration":1247.484042,"failed":false}],[":tests/endpoints/rate-limit.test.ts",{"duration":2154.356209,"failed":false}],[":tests/endpoints/solana-swap.test.ts",{"duration":998.2979999999999,"failed":false}],[":tests/endpoints/solana-wallet.test.ts",{"duration":1363.0256249999998,"failed":false}],[":tests/endpoints/solana-send.test.ts",{"duration":1039.8317080000002,"failed":false}],[":tests/lib/sessions-currency.test.ts",{"duration":56.1837079999998,"failed":false}],[":tests/endpoints/solana-fund.test.ts",{"duration":1418.0586249999997,"failed":false}],[":tests/lib/solana-wallet.test.ts",{"duration":161.13887499999998,"failed":false}],[":tests/lib/address.test.ts",{"duration":3.510084000000006,"failed":false}],[":tests/lib/strategy/sources.test.ts",{"duration":21.01504100000001,"failed":false}],[":tests/lib/strategy/loader.test.ts",{"duration":59.308375,"failed":false}],[":tests/lib/strategy/executor.test.ts",{"duration":7.492707999999993,"failed":false}],[":tests/lib/strategy/state.test.ts",{"duration":6.136792,"failed":false}],[":tests/lib/strategy/hooks.test.ts",{"duration":14.00120800000002,"failed":false}],[":tests/endpoints/widgets.test.ts",{"duration":2127.785625,"failed":false}],[":tests/lib/strategy/message.test.ts",{"duration":127.83229099999997,"failed":false}],[":tests/endpoints/actions.test.ts",{"duration":2396.4307919999997,"failed":false}],[":tests/endpoints/vault.test.ts",{"duration":7419.710874999999,"failed":false}],[":tests/integration/adapter-resolve.test.ts",{"duration":3486.7960000000003,"failed":false}],[":tests/lib/adapters.test.ts",{"duration":38.35904199999999,"failed":false}],[":tests/lib/strategy/tick.test.ts",{"duration":6.34379100000001,"failed":false}],[":tests/lib/relay.test.ts",{"duration":4.984791000000001,"failed":false}],[":tests/lib/ai.test.ts",{"duration":6.82841599999999,"failed":false}],[":tests/endpoints/launch.test.ts",{"duration":35837.233333,"failed":false}],[":tests/widget-installer.test.ts",{"duration":154.704459,"failed":false}],[":tests/mcp/tools.test.ts",{"duration":15.441082999999992,"failed":false}],[":tests/ai-integration/scenarios.test.ts",{"duration":7.4487499999999045,"failed":true}],[":tests/mcp/server.test.ts",{"duration":1333.480375,"failed":false}],[":tests/ai-integration/live.test.ts",{"duration":77572.38508299999,"failed":false}],[":tests/auth/apikeys-validate.test.ts",{"duration":10219.787667,"failed":false}],[":tests/lib/adapters-test.test.ts",{"duration":25429.400542,"failed":false}],[":tests/setup-integration/wizard-flow.test.ts",{"duration":124.21662500000002,"failed":false}],[":tests/setup-integration/adapter-test.test.ts",{"duration":166.0367080000001,"failed":false}],[":tests/setup-integration/edge-cases.test.ts",{"duration":156.02324999999996,"failed":false}],[":tests/setup-integration/apikey-validation.test.ts",{"duration":147.53583400000002,"failed":false}],[":tests/setup-integration/fresh-setup.test.ts",{"duration":107.81912499999999,"failed":false}],[":tests/lib/network.test.ts",{"duration":12.689417000000006,"failed":false}],[":tests/cli/process.test.ts",{"duration":33.650542,"failed":false}],[":tests/cli/init-steps.test.ts",{"duration":4.78708300000001,"failed":false}],[":tests/cli/init-flow.test.ts",{"duration":2517.034083,"failed":false}],[":tests/cli/http.test.ts",{"duration":1563.349083,"failed":false}],[":tests/lib/verified-summary.test.ts",{"duration":8.588290999999998,"failed":false}],[":tests/lib/defaults.test.ts",{"duration":89.18312500000002,"failed":false}],[":tests/endpoints/defaults.test.ts",{"duration":6137.610333,"failed":false}],[":tests/lib/adapters-chat.test.ts",{"duration":28.19304200000002,"failed":false}],[":tests/setup-integration/terminal-flow.test.ts",{"duration":248.770042,"failed":false}],[":tests/endpoints/transactions.test.ts",{"duration":1127.6649169999998,"failed":false}],[":tests/cron/scheduler.test.ts",{"duration":16.875292,"failed":false}],[":tests/endpoints/portfolio.test.ts",{"duration":381.701917,"failed":false}],[":tests/cron/native-price.test.ts",{"duration":58.4565419999999,"failed":false}],[":tests/resolve.test.ts",{"duration":13.15741700000001,"failed":false}],[":tests/lib/prices.test.ts",{"duration":103.56858299999999,"failed":false}],[":tests/swap-quote.test.ts",{"duration":945.5037500000001,"failed":false}],[":tests/send-token.test.ts",{"duration":996.399292,"failed":false}],[":tests/endpoints/price.test.ts",{"duration":61.327583000000004,"failed":false}],[":tests/lib/price.test.ts",{"duration":4.805790999999999,"failed":false}],[":tests/endpoints/token-search.test.ts",{"duration":35.89754199999993,"failed":false}],[":tests/lib/token-search.test.ts",{"duration":65.472708,"failed":false}],[":tests/lib/token-safety.test.ts",{"duration":5.724790999999996,"failed":false}],[":tests/endpoints/token-safety.test.ts",{"duration":41.85649999999987,"failed":false}],[":tests/lib/batch.test.ts",{"duration":11.763874999999999,"failed":false}],[":tests/endpoints/batch.test.ts",{"duration":48.719875,"failed":false}],[":tests/endpoints/token-balance.test.ts",{"duration":29.900082999999995,"failed":false}],[":tests/lib/events-decoder.test.ts",{"duration":4.558958999999987,"failed":false}],[":tests/lib/events-enricher.test.ts",{"duration":4.474500000000035,"failed":false}],[":tests/endpoints/address-transactions.test.ts",{"duration":962.0601669999999,"failed":false}],[":tests/endpoints/bookmarks.test.ts",{"duration":1349.6050840000003,"failed":false}],[":tests/endpoints/addressbook.test.ts",{"duration":995.706459,"failed":false}],[":tests/lib/strategy/session-logger.test.ts",{"duration":1471.763333,"failed":false}],[":tests/cron/incoming-scan.test.ts",{"duration":385.8459999999999,"failed":false}],[":tests/lib/auto-unlock.test.ts",{"duration":1104.2137500000001,"failed":false}],[":tests/lib/widget-tokens-tier.test.ts",{"duration":226.36699999999996,"failed":false}],[":tests/cron/strategy-runner.test.ts",{"duration":6.080332999999996,"failed":false}],[":tests/endpoints/strategy-routes.test.ts",{"duration":11390.736792,"failed":false}],[":tests/endpoints/apps.test.ts",{"duration":21435.455708999998,"failed":false}],[":tests/lib/events-fetcher.test.ts",{"duration":6.5429169999999885,"failed":false}],[":tests/app-installer.test.ts",{"duration":114.05204099999997,"failed":false}],[":tests/lib/app-tokens-tier.test.ts",{"duration":276.60683300000005,"failed":false}],[":tests/setup-integration/onboarding-e2e.test.ts",{"duration":445.7834579999999,"failed":true}],[":tests/cron/orphan-cleanup.test.ts",{"duration":6.764916999999997,"failed":false}],[":tests/lib/strategy/repository.test.ts",{"duration":28.425665999999865,"failed":false}],[":tests/setup-integration/autonomous-agent.test.ts",{"duration":7.406667000000027,"failed":true}],[":tests/lib/websocket-auth.test.ts",{"duration":235.461,"failed":false}],[":tests/lib/credentials.test.ts",{"duration":7320.739874999999,"failed":false}],[":tests/lib/credential-access.test.ts",{"duration":3.4029999999999916,"failed":false}],[":tests/lib/credential-scope.test.ts",{"duration":3.2806659999999965,"failed":false}],[":tests/endpoints/credential-ops.test.ts",{"duration":3004.8909169999997,"failed":false}],[":tests/endpoints/credentials.test.ts",{"duration":27923.241459,"failed":false}],[":tests/lib/credential-transport.test.ts",{"duration":138.75,"failed":false}],[":tests/lib/credential-vault.test.ts",{"duration":4433.612583,"failed":false}],[":tests/lib/resolve-action.test.ts",{"duration":4.514791000000002,"failed":false}],[":tests/credential-import.test.ts",{"duration":19.897791999999995,"failed":false}],[":tests/endpoints/passkey.test.ts",{"duration":14553.136708,"failed":false}],[":tests/lib/oauth2-refresh.test.ts",{"duration":3.752541000000008,"failed":false}],[":tests/lib/totp.test.ts",{"duration":7.506458999999992,"failed":false}],[":tests/lib/passkey-credential.test.ts",{"duration":9.192250000000001,"failed":false}],[":tests/cli/env.test.ts",{"duration":8.821500000000015,"failed":false}],[":tests/dotenv-parser.test.ts",{"duration":3.3828749999999985,"failed":false}],[":tests/cli/socket.test.ts",{"duration":164.548791,"failed":false}],[":tests/cli/vault.test.ts",{"duration":5.563457999999997,"failed":false}],[":tests/cli/credential-resolve.test.ts",{"duration":2.6654999999999944,"failed":false}],[":tests/cli/env-check-server-vault.test.ts",{"duration":239.821708,"failed":false}],[":tests/e2e-agent/validation.test.ts",{"duration":8.998582999999996,"failed":false}],[":tests/e2e-agent/artifacts.test.ts",{"duration":3.1474170000000044,"failed":false}],[":tests/e2e-agent/ci-lanes.test.ts",{"duration":1.272790999999998,"failed":false}],[":tests/lib/api-registry/validation.test.ts",{"duration":5.377708000000013,"failed":false}],[":tests/lib/aura-parser.test.ts",{"duration":10.007750000000001,"failed":false}],[":tests/lib/agent-auth/contracts.test.ts",{"duration":11.581041999999997,"failed":false}],[":tests/cli/doctor.test.ts",{"duration":9.576459,"failed":false}],[":tests/endpoints/import.test.ts",{"duration":8348.137416,"failed":false}],[":tests/endpoints/passkey-credentials.test.ts",{"duration":2573.4603340000003,"failed":false}],[":tests/lib/credential-health.test.ts",{"duration":3.1082080000000047,"failed":false}],[":tests/lib/agent-profiles.test.ts",{"duration":3.3868339999999932,"failed":false}],[":tests/mcp/profile-policy.test.ts",{"duration":3.01100000000001,"failed":false}],[":tests/endpoints/profile-parity.test.ts",{"duration":9.213209000000006,"failed":true}],[":tests/lib/profile-parity.test.ts",{"duration":1.7047079999999966,"failed":false}],[":tests/endpoints/credential-access-audit.test.ts",{"duration":1768.71025,"failed":false}],[":tests/lib/project-scope.test.ts",{"duration":8.761667000000003,"failed":false}],[":tests/docs/job-docs-validation.test.ts",{"duration":33.986999999999995,"failed":false}],[":tests/endpoints/credential-shares.test.ts",{"duration":6208.950334,"failed":false}],[":tests/lib/task-lifecycle.test.ts",{"duration":7.928124999999994,"failed":false}],[":tests/endpoints/tasks-lifecycle.test.ts",{"duration":191.46470899999997,"failed":false}],[":tests/cli/local-agent-trust.test.ts",{"duration":2.7987499999999983,"failed":false}],[":tests/cli/token.test.ts",{"duration":1.4059579999999983,"failed":false}],[":tests/endpoints/heartbeat.test.ts",{"duration":4575.689417,"failed":false}],[":tests/cli/bin-entrypoint.test.ts",{"duration":4248.5371669999995,"failed":false}],[":tests/sandbox/cli.test.ts",{"duration":332.983625,"failed":false}],[":tests/cli/vault-auth.test.ts",{"duration":195.026916,"failed":false}],[":tests/lib/encrypt.test.ts",{"duration":763.462208,"failed":false}],[":tests/cli/vault-share-gist.test.ts",{"duration":14.503625,"failed":false}],[":tests/lib/secret-gist-share.test.ts",{"duration":1.757791999999995,"failed":false}],[":tests/cli/vault-list-filters.test.ts",{"duration":14.040582999999984,"failed":false}],[":tests/cli/start.test.ts",{"duration":1.8407080000000065,"failed":false}],[":tests/cli/wallet.test.ts",{"duration":1.465874999999997,"failed":false}],[":tests/cli/prompt-select.test.ts",{"duration":4.252083999999996,"failed":false}],[":tests/cli/quickhack.test.ts",{"duration":1.982292000000001,"failed":false}],[":tests/lib/human-action-summary.test.ts",{"duration":2.1798750000000098,"failed":false}],[":tests/pipeline-db/paths.test.ts",{"duration":5.902790999999979,"failed":false}],[":tests/pipeline-db/bootstrap.test.ts",{"duration":39.007125,"failed":false}],[":tests/pipeline-db/snapshot.test.ts",{"duration":29.974833999999987,"failed":false}],[":tests/pipeline-db/dual-write.test.ts",{"duration":60.147583,"failed":false}],[":tests/pipeline-db/importer.test.ts",{"duration":33.614417,"failed":false}],[":tests/pipeline-lifecycle/service.test.ts",{"duration":32.389666000000005,"failed":false}],[":tests/pipeline-lifecycle/taskctl.test.ts",{"duration":2885.294625,"failed":false}],[":tests/pipeline-lifecycle/agent-cron-integration.test.ts",{"duration":28.44970900000004,"failed":false}],[":tests/pipeline-db/cutover-plan.test.ts",{"duration":2.5047919999999806,"failed":false}],[":tests/lib/approval-link.test.ts",{"duration":1.0141670000000005,"failed":false}],[":tests/lib/dont-ask-again-policy.test.ts",{"duration":1.2326669999999922,"failed":false}],[":tests/lib/update-check.test.ts",{"duration":1.4486670000000004,"failed":false}],[":tests/lib/auto-execute.test.ts",{"duration":108.225667,"failed":false}],[":tests/lib/auth-action.test.ts",{"duration":1998.647583,"failed":false}],[":tests/cli/auth-action-flag.test.ts",{"duration":3.1158340000000067,"failed":false}],[":tests/pipeline-lifecycle/tags.test.ts",{"duration":321.27825,"failed":false}],[":tests/endpoints/nuke.test.ts",{"duration":69.0028749999999,"failed":false}],[":tests/endpoints/apikeys.test.ts",{"duration":11085.063833,"failed":false}],[":tests/endpoints/security.test.ts",{"duration":9164.535417000001,"failed":false}],[":tests/endpoints/dashboard.test.ts",{"duration":103.2655420000001,"failed":false}],[":tests/endpoints/logs.test.ts",{"duration":183.44812500000035,"failed":false}],[":tests/endpoints/views.test.ts",{"duration":17.28716600000007,"failed":false}],[":tests/endpoints/flags.test.ts",{"duration":12.482625000000098,"failed":false}],[":tests/endpoints/lock.test.ts",{"duration":11063.760583,"failed":false}],[":tests/endpoints/backup.test.ts",{"duration":6926.148333000001,"failed":false}],[":tests/auth/approval-permissions-regression.test.ts",{"duration":2333.866833,"failed":false}],[":tests/sandbox/cli-cd-suite.test.ts",{"duration":578.572375,"failed":false}],[":tests/mcp/contract.test.ts",{"duration":78.60249999999999,"failed":false}],[":tests/lib/credential-paths.test.ts",{"duration":3899.7734170000003,"failed":false}],[":tests/runtime-vault-smoke.test.ts",{"duration":1521.938291,"failed":false}],[":tests/cli/taskctl-lock-smoke.test.ts",{"duration":0,"failed":false}],[":tests/cli/start-run.test.ts",{"duration":6.923584000000005,"failed":false}],[":tests/cli/restart-run.test.ts",{"duration":4.698082999999997,"failed":false}],[":tests/endpoints/approve-action.test.ts",{"duration":1056.1783329999998,"failed":false}],[":tests/cli/escalation.test.ts",{"duration":3.389707999999999,"failed":false}],[":tests/cli/actions-auth.test.ts",{"duration":39.753000000000014,"failed":false}],[":tests/lib/temp-policy.test.ts",{"duration":2.585374999999999,"failed":false}],[":tests/endpoints/escalation-migration-gate.test.ts",{"duration":11955.108208,"failed":false}],[":tests/lib/escalation-responder.test.ts",{"duration":24.61208400000001,"failed":false}],[":tests/cli/service.test.ts",{"duration":38.05449999999999,"failed":false}],[":tests/cli/init-runtime.test.ts",{"duration":4.873333000000002,"failed":false}],[":tests/cli/agent.test.ts",{"duration":7.902833000000001,"failed":false}],[":tests/runtime-agent-smoke.test.ts",{"duration":1154.7805830000002,"failed":false}],[":tests/endpoints/agent.test.ts",{"duration":6459.912458000001,"failed":false}],[":tests/lib/credential-agent.test.ts",{"duration":3084.496541,"failed":false}],[":tests/cli/agent-auth.test.ts",{"duration":528.433583,"failed":false}],[":tests/cli/agent-share-gist.test.ts",{"duration":16.512332999999984,"failed":false}],[":tests/cli/agent-list-filters.test.ts",{"duration":18.725041000000004,"failed":false}],[":tests/cli/env-check-server-agent.test.ts",{"duration":292.08354199999997,"failed":false}],[":tests/lib/import-from-openclaw-paths.test.ts",{"duration":0,"failed":true}],[":tests/endpoints/agent-profiles.test.ts",{"duration":3425.8750000000005,"failed":false}]]}
1
+ {"version":"4.0.18","results":[[":tests/send.test.ts",{"duration":162.08154100000002,"failed":false}],[":tests/approve.test.ts",{"duration":257.27824999999996,"failed":false}],[":tests/unlock.test.ts",{"duration":213.61050000000003,"failed":false}],[":tests/setup.test.ts",{"duration":128.30779199999998,"failed":false}],[":tests/e2e.test.ts",{"duration":3924.8372500000005,"failed":false}],[":tests/wallet.test.ts",{"duration":1768.446334,"failed":false}],[":tests/auth.test.ts",{"duration":174.709292,"failed":false}],[":tests/fund.test.ts",{"duration":820.6141660000001,"failed":false}],[":tests/integration/agent-flow.test.ts",{"duration":6088.6245,"failed":false}],[":tests/auth/permissions.test.ts",{"duration":6761.803000000001,"failed":false}],[":tests/auth/middleware.test.ts",{"duration":8629.632875,"failed":false}],[":tests/lib/sessions.test.ts",{"duration":171.32058299999994,"failed":false}],[":tests/lib/auth.test.ts",{"duration":4089.3444170000002,"failed":false}],[":tests/endpoints/unlock.test.ts",{"duration":10232.476333999999,"failed":false}],[":tests/endpoints/wallet.test.ts",{"duration":4418.335292,"failed":false}],[":tests/endpoints/approve.test.ts",{"duration":497.64808300000004,"failed":false}],[":tests/endpoints/fund.test.ts",{"duration":1718.8159589999998,"failed":false}],[":tests/endpoints/send.test.ts",{"duration":2154.865875,"failed":false}],[":tests/endpoints/auth.test.ts",{"duration":1208.190834,"failed":false}],[":tests/endpoints/setup.test.ts",{"duration":4987.754667,"failed":false}],[":tests/lib/uniswap.test.ts",{"duration":12.576917000000009,"failed":false}],[":tests/auth/apikeys.test.ts",{"duration":10823.350042,"failed":false}],[":tests/endpoints/wallet-data.test.ts",{"duration":2309.976375,"failed":false}],[":tests/endpoints/swap.test.ts",{"duration":2005.271917,"failed":false}],[":tests/endpoints/token-clearing.test.ts",{"duration":1286.3398750000001,"failed":false}],[":tests/endpoints/rate-limit.test.ts",{"duration":2103.539209,"failed":false}],[":tests/endpoints/solana-swap.test.ts",{"duration":1051.7639170000002,"failed":false}],[":tests/endpoints/solana-wallet.test.ts",{"duration":1333.433125,"failed":false}],[":tests/endpoints/solana-send.test.ts",{"duration":984.4620829999999,"failed":false}],[":tests/lib/sessions-currency.test.ts",{"duration":99.97837500000014,"failed":false}],[":tests/endpoints/solana-fund.test.ts",{"duration":1388.2830829999998,"failed":false}],[":tests/lib/solana-wallet.test.ts",{"duration":145.200958,"failed":false}],[":tests/lib/address.test.ts",{"duration":2.2885830000000027,"failed":false}],[":tests/lib/strategy/sources.test.ts",{"duration":20.033541,"failed":false}],[":tests/lib/strategy/loader.test.ts",{"duration":13.489082999999994,"failed":false}],[":tests/lib/strategy/executor.test.ts",{"duration":9.343333000000001,"failed":false}],[":tests/lib/strategy/state.test.ts",{"duration":9.851000000000013,"failed":false}],[":tests/lib/strategy/hooks.test.ts",{"duration":14.077292,"failed":false}],[":tests/endpoints/widgets.test.ts",{"duration":2127.785625,"failed":false}],[":tests/lib/strategy/message.test.ts",{"duration":113.09245800000002,"failed":false}],[":tests/endpoints/actions.test.ts",{"duration":2485.513375,"failed":false}],[":tests/endpoints/vault.test.ts",{"duration":7419.710874999999,"failed":false}],[":tests/integration/adapter-resolve.test.ts",{"duration":3415.2646250000003,"failed":false}],[":tests/lib/adapters.test.ts",{"duration":42.87712499999998,"failed":false}],[":tests/lib/strategy/tick.test.ts",{"duration":6.5871250000000146,"failed":false}],[":tests/lib/relay.test.ts",{"duration":5.1127500000000055,"failed":false}],[":tests/lib/ai.test.ts",{"duration":6.845791999999989,"failed":false}],[":tests/endpoints/launch.test.ts",{"duration":39822.157459,"failed":false}],[":tests/widget-installer.test.ts",{"duration":154.704459,"failed":false}],[":tests/mcp/tools.test.ts",{"duration":19.034333000000004,"failed":false}],[":tests/ai-integration/scenarios.test.ts",{"duration":7.4487499999999045,"failed":true}],[":tests/mcp/server.test.ts",{"duration":1053.348542,"failed":false}],[":tests/ai-integration/live.test.ts",{"duration":77572.38508299999,"failed":false}],[":tests/auth/apikeys-validate.test.ts",{"duration":10064.624082999999,"failed":false}],[":tests/lib/adapters-test.test.ts",{"duration":24669.032584,"failed":false}],[":tests/setup-integration/wizard-flow.test.ts",{"duration":124.21662500000002,"failed":false}],[":tests/setup-integration/adapter-test.test.ts",{"duration":166.0367080000001,"failed":false}],[":tests/setup-integration/edge-cases.test.ts",{"duration":156.02324999999996,"failed":false}],[":tests/setup-integration/apikey-validation.test.ts",{"duration":147.53583400000002,"failed":false}],[":tests/setup-integration/fresh-setup.test.ts",{"duration":107.81912499999999,"failed":false}],[":tests/lib/network.test.ts",{"duration":9.380416999999994,"failed":false}],[":tests/cli/process.test.ts",{"duration":59.56675,"failed":false}],[":tests/cli/init-steps.test.ts",{"duration":4.803083999999998,"failed":false}],[":tests/cli/init-flow.test.ts",{"duration":2356.2355420000004,"failed":false}],[":tests/cli/http.test.ts",{"duration":1539.509333,"failed":false}],[":tests/lib/verified-summary.test.ts",{"duration":6.6548329999999964,"failed":false}],[":tests/lib/defaults.test.ts",{"duration":60.831541000000016,"failed":false}],[":tests/endpoints/defaults.test.ts",{"duration":5807.414542,"failed":false}],[":tests/lib/adapters-chat.test.ts",{"duration":26.964458999999977,"failed":false}],[":tests/setup-integration/terminal-flow.test.ts",{"duration":248.770042,"failed":false}],[":tests/endpoints/transactions.test.ts",{"duration":1173.7453750000002,"failed":false}],[":tests/cron/scheduler.test.ts",{"duration":10.118041999999988,"failed":false}],[":tests/endpoints/portfolio.test.ts",{"duration":331.652916,"failed":false}],[":tests/cron/native-price.test.ts",{"duration":77.54324999999994,"failed":false}],[":tests/resolve.test.ts",{"duration":13.599375000000009,"failed":false}],[":tests/lib/prices.test.ts",{"duration":54.92983299999992,"failed":false}],[":tests/swap-quote.test.ts",{"duration":959.055208,"failed":false}],[":tests/send-token.test.ts",{"duration":953.917041,"failed":false}],[":tests/endpoints/price.test.ts",{"duration":48.3732500000001,"failed":false}],[":tests/lib/price.test.ts",{"duration":4.861209000000002,"failed":false}],[":tests/endpoints/token-search.test.ts",{"duration":41.01174999999989,"failed":false}],[":tests/lib/token-search.test.ts",{"duration":71.24962500000001,"failed":false}],[":tests/lib/token-safety.test.ts",{"duration":4.6863329999999905,"failed":false}],[":tests/endpoints/token-safety.test.ts",{"duration":42.42004199999997,"failed":false}],[":tests/lib/batch.test.ts",{"duration":5.325082999999992,"failed":false}],[":tests/endpoints/batch.test.ts",{"duration":51.468083999999976,"failed":false}],[":tests/endpoints/token-balance.test.ts",{"duration":33.105999999999995,"failed":false}],[":tests/lib/events-decoder.test.ts",{"duration":4.991375000000005,"failed":false}],[":tests/lib/events-enricher.test.ts",{"duration":5.042708000000005,"failed":false}],[":tests/endpoints/address-transactions.test.ts",{"duration":995.369167,"failed":false}],[":tests/endpoints/bookmarks.test.ts",{"duration":1299.437417,"failed":false}],[":tests/endpoints/addressbook.test.ts",{"duration":1003.398917,"failed":false}],[":tests/lib/strategy/session-logger.test.ts",{"duration":1463.488292,"failed":false}],[":tests/cron/incoming-scan.test.ts",{"duration":342.919041,"failed":false}],[":tests/lib/auto-unlock.test.ts",{"duration":995.2187919999999,"failed":false}],[":tests/lib/widget-tokens-tier.test.ts",{"duration":226.36699999999996,"failed":false}],[":tests/cron/strategy-runner.test.ts",{"duration":6.173999999999992,"failed":false}],[":tests/endpoints/strategy-routes.test.ts",{"duration":10984.715292,"failed":false}],[":tests/endpoints/apps.test.ts",{"duration":20728.988500000003,"failed":false}],[":tests/lib/events-fetcher.test.ts",{"duration":6.63654200000002,"failed":false}],[":tests/app-installer.test.ts",{"duration":121.90758300000002,"failed":false}],[":tests/lib/app-tokens-tier.test.ts",{"duration":273.176875,"failed":false}],[":tests/setup-integration/onboarding-e2e.test.ts",{"duration":445.7834579999999,"failed":true}],[":tests/cron/orphan-cleanup.test.ts",{"duration":6.969750000000005,"failed":false}],[":tests/lib/strategy/repository.test.ts",{"duration":38.93041599999992,"failed":false}],[":tests/setup-integration/autonomous-agent.test.ts",{"duration":7.406667000000027,"failed":true}],[":tests/lib/websocket-auth.test.ts",{"duration":224.16829199999998,"failed":false}],[":tests/lib/credentials.test.ts",{"duration":7162.027333,"failed":false}],[":tests/lib/credential-access.test.ts",{"duration":4.621292000000011,"failed":false}],[":tests/lib/credential-scope.test.ts",{"duration":3.140375000000006,"failed":false}],[":tests/endpoints/credential-ops.test.ts",{"duration":2956.245,"failed":false}],[":tests/endpoints/credentials.test.ts",{"duration":26834.984207999998,"failed":false}],[":tests/lib/credential-transport.test.ts",{"duration":116.04087499999997,"failed":false}],[":tests/lib/credential-vault.test.ts",{"duration":4433.612583,"failed":false}],[":tests/lib/resolve-action.test.ts",{"duration":4.583040999999994,"failed":false}],[":tests/credential-import.test.ts",{"duration":18.054874999999996,"failed":false}],[":tests/endpoints/passkey.test.ts",{"duration":13870.052208000001,"failed":false}],[":tests/lib/oauth2-refresh.test.ts",{"duration":3.757000000000005,"failed":false}],[":tests/lib/totp.test.ts",{"duration":6.120041999999998,"failed":false}],[":tests/lib/passkey-credential.test.ts",{"duration":7.424291999999994,"failed":false}],[":tests/cli/env.test.ts",{"duration":7.1997499999999945,"failed":false}],[":tests/dotenv-parser.test.ts",{"duration":7.199292,"failed":false}],[":tests/cli/socket.test.ts",{"duration":185.29004200000003,"failed":false}],[":tests/cli/vault.test.ts",{"duration":5.563457999999997,"failed":false}],[":tests/cli/credential-resolve.test.ts",{"duration":2.5222920000000073,"failed":false}],[":tests/cli/env-check-server-vault.test.ts",{"duration":239.821708,"failed":false}],[":tests/e2e-agent/validation.test.ts",{"duration":8.834457999999984,"failed":false}],[":tests/e2e-agent/artifacts.test.ts",{"duration":2.4147920000000056,"failed":false}],[":tests/e2e-agent/ci-lanes.test.ts",{"duration":1.2617089999999962,"failed":false}],[":tests/lib/api-registry/validation.test.ts",{"duration":5.282042000000004,"failed":false}],[":tests/lib/aura-parser.test.ts",{"duration":8.742790999999997,"failed":false}],[":tests/lib/agent-auth/contracts.test.ts",{"duration":7.681333000000009,"failed":false}],[":tests/cli/doctor.test.ts",{"duration":9.505791999999985,"failed":false}],[":tests/endpoints/import.test.ts",{"duration":8501.442541999999,"failed":false}],[":tests/endpoints/passkey-credentials.test.ts",{"duration":2548.2423750000003,"failed":false}],[":tests/lib/credential-health.test.ts",{"duration":2.742500000000007,"failed":false}],[":tests/lib/agent-profiles.test.ts",{"duration":4.791916000000015,"failed":false}],[":tests/mcp/profile-policy.test.ts",{"duration":3.4552499999999924,"failed":false}],[":tests/endpoints/profile-parity.test.ts",{"duration":9.213209000000006,"failed":true}],[":tests/lib/profile-parity.test.ts",{"duration":1.5870000000000033,"failed":false}],[":tests/endpoints/credential-access-audit.test.ts",{"duration":1706.509292,"failed":false}],[":tests/lib/project-scope.test.ts",{"duration":6.9360420000000005,"failed":false}],[":tests/docs/job-docs-validation.test.ts",{"duration":29.556416999999996,"failed":false}],[":tests/endpoints/credential-shares.test.ts",{"duration":5810.327,"failed":false}],[":tests/lib/task-lifecycle.test.ts",{"duration":7.928124999999994,"failed":false}],[":tests/endpoints/tasks-lifecycle.test.ts",{"duration":191.46470899999997,"failed":false}],[":tests/cli/local-agent-trust.test.ts",{"duration":4.082082999999997,"failed":false}],[":tests/cli/token.test.ts",{"duration":1.5038330000000002,"failed":false}],[":tests/endpoints/heartbeat.test.ts",{"duration":4186.430625,"failed":false}],[":tests/cli/bin-entrypoint.test.ts",{"duration":3969.1315409999997,"failed":false}],[":tests/sandbox/cli.test.ts",{"duration":289.17449999999997,"failed":false}],[":tests/cli/vault-auth.test.ts",{"duration":195.026916,"failed":false}],[":tests/lib/encrypt.test.ts",{"duration":739.814959,"failed":false}],[":tests/cli/vault-share-gist.test.ts",{"duration":14.503625,"failed":false}],[":tests/lib/secret-gist-share.test.ts",{"duration":1.593874999999997,"failed":false}],[":tests/cli/vault-list-filters.test.ts",{"duration":14.040582999999984,"failed":false}],[":tests/cli/start.test.ts",{"duration":1.595084,"failed":false}],[":tests/cli/wallet.test.ts",{"duration":1.361959000000013,"failed":false}],[":tests/cli/prompt-select.test.ts",{"duration":4.046291999999994,"failed":false}],[":tests/cli/quickhack.test.ts",{"duration":2.6738749999999953,"failed":false}],[":tests/lib/human-action-summary.test.ts",{"duration":2.1484590000000026,"failed":false}],[":tests/pipeline-db/paths.test.ts",{"duration":5.902790999999979,"failed":false}],[":tests/pipeline-db/bootstrap.test.ts",{"duration":39.007125,"failed":false}],[":tests/pipeline-db/snapshot.test.ts",{"duration":29.974833999999987,"failed":false}],[":tests/pipeline-db/dual-write.test.ts",{"duration":60.147583,"failed":false}],[":tests/pipeline-db/importer.test.ts",{"duration":33.614417,"failed":false}],[":tests/pipeline-lifecycle/service.test.ts",{"duration":32.389666000000005,"failed":false}],[":tests/pipeline-lifecycle/taskctl.test.ts",{"duration":2885.294625,"failed":false}],[":tests/pipeline-lifecycle/agent-cron-integration.test.ts",{"duration":28.44970900000004,"failed":false}],[":tests/pipeline-db/cutover-plan.test.ts",{"duration":2.5047919999999806,"failed":false}],[":tests/lib/approval-link.test.ts",{"duration":1.0255830000000046,"failed":false}],[":tests/lib/dont-ask-again-policy.test.ts",{"duration":1.217250000000007,"failed":false}],[":tests/lib/update-check.test.ts",{"duration":1.3213750000000033,"failed":false}],[":tests/lib/auto-execute.test.ts",{"duration":108.23875000000001,"failed":false}],[":tests/lib/auth-action.test.ts",{"duration":1955.904625,"failed":false}],[":tests/cli/auth-action-flag.test.ts",{"duration":3.093834000000001,"failed":false}],[":tests/pipeline-lifecycle/tags.test.ts",{"duration":321.27825,"failed":false}],[":tests/endpoints/nuke.test.ts",{"duration":69.0028749999999,"failed":false}],[":tests/endpoints/apikeys.test.ts",{"duration":11085.063833,"failed":false}],[":tests/endpoints/security.test.ts",{"duration":9164.535417000001,"failed":false}],[":tests/endpoints/dashboard.test.ts",{"duration":103.2655420000001,"failed":false}],[":tests/endpoints/logs.test.ts",{"duration":183.44812500000035,"failed":false}],[":tests/endpoints/views.test.ts",{"duration":17.28716600000007,"failed":false}],[":tests/endpoints/flags.test.ts",{"duration":12.482625000000098,"failed":false}],[":tests/endpoints/lock.test.ts",{"duration":11063.760583,"failed":false}],[":tests/endpoints/backup.test.ts",{"duration":6926.148333000001,"failed":false}],[":tests/auth/approval-permissions-regression.test.ts",{"duration":2318.2909170000003,"failed":false}],[":tests/sandbox/cli-cd-suite.test.ts",{"duration":615.319,"failed":false}],[":tests/mcp/contract.test.ts",{"duration":104.87708299999998,"failed":false}],[":tests/lib/credential-paths.test.ts",{"duration":3863.718,"failed":false}],[":tests/runtime-vault-smoke.test.ts",{"duration":1521.938291,"failed":false}],[":tests/cli/taskctl-lock-smoke.test.ts",{"duration":0,"failed":false}],[":tests/cli/start-run.test.ts",{"duration":5.826916999999995,"failed":false}],[":tests/cli/restart-run.test.ts",{"duration":4.38683300000001,"failed":false}],[":tests/endpoints/approve-action.test.ts",{"duration":1019.0898749999999,"failed":false}],[":tests/cli/escalation.test.ts",{"duration":2.666415999999998,"failed":false}],[":tests/cli/actions-auth.test.ts",{"duration":21.518292000000002,"failed":false}],[":tests/lib/temp-policy.test.ts",{"duration":2.778499999999994,"failed":false}],[":tests/endpoints/escalation-migration-gate.test.ts",{"duration":11809.859042,"failed":false}],[":tests/lib/escalation-responder.test.ts",{"duration":30.654416999999995,"failed":false}],[":tests/cli/service.test.ts",{"duration":37.195584,"failed":false}],[":tests/cli/init-runtime.test.ts",{"duration":4.815833999999995,"failed":false}],[":tests/cli/agent.test.ts",{"duration":4.056166999999988,"failed":false}],[":tests/runtime-agent-smoke.test.ts",{"duration":1155.657334,"failed":false}],[":tests/endpoints/agent.test.ts",{"duration":5853.5660419999995,"failed":false}],[":tests/lib/credential-agent.test.ts",{"duration":3026.8250000000003,"failed":false}],[":tests/cli/agent-auth.test.ts",{"duration":540.6860419999999,"failed":false}],[":tests/cli/agent-share-gist.test.ts",{"duration":27.42041599999999,"failed":false}],[":tests/cli/agent-list-filters.test.ts",{"duration":12.318375000000003,"failed":false}],[":tests/cli/env-check-server-agent.test.ts",{"duration":379.80316700000003,"failed":false}],[":tests/lib/import-from-openclaw-paths.test.ts",{"duration":0,"failed":true}],[":tests/endpoints/agent-profiles.test.ts",{"duration":3356.1236670000003,"failed":false}]]}
@@ -51,6 +51,7 @@ import {
51
51
  summarizeCredentialHealthFlags,
52
52
  } from '../lib/credential-health';
53
53
  import {
54
+ canonicalizeCredentialFieldKey,
54
55
  NOTE_CONTENT_KEY,
55
56
  getCredentialFieldValue,
56
57
  normalizeCredentialFieldsForType,
@@ -480,6 +481,40 @@ function parseRequestedPolicyInput(body: unknown): {
480
481
  };
481
482
  }
482
483
 
484
+ function parseRequestedReadFieldsInput(
485
+ body: unknown,
486
+ credentialType: CredentialType,
487
+ ): { requestedFields: string[]; requestsAllFields: boolean } {
488
+ const bodyPayload = body && typeof body === 'object' && !Array.isArray(body)
489
+ ? body as Record<string, unknown>
490
+ : {};
491
+ const requestedFieldsRaw: string[] = [];
492
+
493
+ const appendRequestedField = (value: unknown): void => {
494
+ if (typeof value !== 'string') return;
495
+ const trimmed = value.trim();
496
+ if (!trimmed) return;
497
+ requestedFieldsRaw.push(trimmed);
498
+ };
499
+
500
+ if (Array.isArray(bodyPayload.requestedFields)) {
501
+ for (const value of bodyPayload.requestedFields) {
502
+ appendRequestedField(value);
503
+ }
504
+ }
505
+ appendRequestedField(bodyPayload.requestedField);
506
+ appendRequestedField(bodyPayload.field);
507
+
508
+ const requestsAllFields = requestedFieldsRaw.some((value) => value === '*');
509
+ const requestedFields = Array.from(new Set(
510
+ requestedFieldsRaw
511
+ .filter((value) => value !== '*')
512
+ .map((value) => normalizeScope(canonicalizeCredentialFieldKey(credentialType, value))),
513
+ ));
514
+
515
+ return { requestedFields, requestsAllFields };
516
+ }
517
+
483
518
  function buildCredentialRouteContract(input: {
484
519
  routeId: CredentialRouteContractId;
485
520
  credentialId: string;
@@ -1817,13 +1852,21 @@ router.post('/:id/read', async (req: Request<{ id: string }>, res: Response) =>
1817
1852
  ? []
1818
1853
  : resolveExcludeFields(auth.token.credentialAccess?.excludeFields, credential.type);
1819
1854
  const baseExcludedNormalized = new Set(baseExclude.map(field => normalizeScope(field)));
1855
+ const requestedReadFields = parseRequestedReadFieldsInput(req.body, credential.type);
1856
+ const excludedFieldsPresent = Array.from(new Set(
1857
+ secrets
1858
+ .map((field) => normalizeScope(field.key))
1859
+ .filter((fieldKey) => baseExcludedNormalized.has(fieldKey)),
1860
+ ));
1820
1861
  const requestedExcludedFields = isAdmin(auth)
1821
1862
  ? []
1822
- : Array.from(new Set(
1823
- secrets
1824
- .map((field) => field.key)
1825
- .filter((fieldKey) => baseExcludedNormalized.has(normalizeScope(fieldKey))),
1826
- ));
1863
+ : requestedReadFields.requestsAllFields
1864
+ ? excludedFieldsPresent
1865
+ : Array.from(new Set(
1866
+ requestedReadFields.requestedFields
1867
+ .map((field) => normalizeScope(field))
1868
+ .filter((fieldKey) => baseExcludedNormalized.has(fieldKey)),
1869
+ ));
1827
1870
  if (requestedExcludedFields.length > 0) {
1828
1871
  const approvalTtl = await resolveOneShotApprovalTtl(auth);
1829
1872
  const approvalSummaryBase = `${auth.token.agentId || 'agent'} requests excluded fields (${requestedExcludedFields.join(', ')}) from credential "${credential.name}"`;
@@ -23,6 +23,15 @@ function hasClaimSecret(init: RequestInit | undefined, expected: string): boolea
23
23
  return false;
24
24
  }
25
25
 
26
+ function makeTestAgentToken(permissions: string[]): string {
27
+ const payload = Buffer.from(JSON.stringify({
28
+ agentId: 'cli-agent',
29
+ permissions,
30
+ exp: Date.now() + 60_000,
31
+ }), 'utf8').toString('base64url');
32
+ return `${payload}.sig`;
33
+ }
34
+
26
35
  const mocks = vi.hoisted(() => ({
27
36
  bootstrapViaSocket: vi.fn(),
28
37
  bootstrapViaAuthRequest: vi.fn(),
@@ -1234,6 +1243,44 @@ describe('agent CLI auth behavior', () => {
1234
1243
  expect(getApprovalContext('req-rejected')).not.toBeNull();
1235
1244
  });
1236
1245
 
1246
+ it('auth claim maps 200 rejected status to claim_rejected and clears context', async () => {
1247
+ process.env.WALLET_DATA_DIR = fs.mkdtempSync(path.join(os.tmpdir(), 'auramaxx-agent-auth-'));
1248
+ putApprovalContext({
1249
+ reqId: 'req-rejected-status',
1250
+ secret: 'sec-rejected-status',
1251
+ privateKeyPem: 'mock-private-key',
1252
+ approvalScope: 'session_token',
1253
+ ttlSeconds: 300,
1254
+ retryCommandTemplate: 'npx auramaxx agent get "github" --reqId <reqId>',
1255
+ });
1256
+
1257
+ vi.spyOn(globalThis, 'fetch').mockImplementation(async (input: RequestInfo | URL, init?: RequestInit) => {
1258
+ const url = new URL(typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url);
1259
+ const method = init?.method || 'GET';
1260
+ if (url.pathname === '/auth/req-rejected-status' && method === 'GET' && hasClaimSecret(init, 'sec-rejected-status')) {
1261
+ return new Response(JSON.stringify({ success: true, status: 'rejected' }), {
1262
+ status: 200,
1263
+ headers: { 'Content-Type': 'application/json' },
1264
+ });
1265
+ }
1266
+ throw new Error(`Unexpected fetch path: ${method} ${url.pathname}${url.search}`);
1267
+ });
1268
+
1269
+ const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
1270
+ const exitCode = await runAuthCli(['claim', 'req-rejected-status', '--json']);
1271
+ expect(exitCode).toBe(1);
1272
+
1273
+ const payload = JSON.parse(String(logSpy.mock.calls[0][0])) as {
1274
+ claimStatus?: string;
1275
+ errorCode?: string;
1276
+ retryReady?: boolean;
1277
+ };
1278
+ expect(payload.claimStatus).toBe('rejected');
1279
+ expect(payload.errorCode).toBe('claim_rejected');
1280
+ expect(payload.retryReady).toBe(false);
1281
+ expect(getApprovalContext('req-rejected-status')).toBeNull();
1282
+ });
1283
+
1237
1284
  it('auth request --help exits without creating an auth request', async () => {
1238
1285
  const fetchSpy = vi.spyOn(globalThis, 'fetch').mockImplementation(async () => {
1239
1286
  throw new Error('fetch should not run for --help');
@@ -1489,4 +1536,71 @@ describe('agent CLI auth behavior', () => {
1489
1536
  expect(mocks.createReadToken.mock.calls[0]?.[1]).toBe('fallback-auth-token');
1490
1537
  expect(logSpy).toHaveBeenCalledWith('enc(gh-secret)');
1491
1538
  });
1539
+
1540
+ it('skips delegated read token mint when fallback token is parseable non-admin', async () => {
1541
+ const nonAdminToken = makeTestAgentToken(['secret:read']);
1542
+ mocks.bootstrapViaSocket.mockRejectedValueOnce(new Error('Cannot connect to AuraMaxx: connect ENOENT /tmp/aura-cli.sock'));
1543
+ mocks.bootstrapViaAuthRequest.mockResolvedValueOnce(nonAdminToken);
1544
+ mocks.generateEphemeralKeypair.mockReturnValueOnce({
1545
+ publicKeyPem: 'ephemeral-public-key',
1546
+ privateKeyPem: 'ephemeral-private-key',
1547
+ publicKeyBase64: Buffer.from('ephemeral-public-key', 'utf8').toString('base64'),
1548
+ });
1549
+ mocks.decryptWithPrivateKey.mockImplementation((encrypted: string, privateKeyPem: string) => {
1550
+ expect(privateKeyPem).toBe('ephemeral-private-key');
1551
+ return encrypted;
1552
+ });
1553
+
1554
+ vi.spyOn(globalThis, 'fetch').mockImplementation(async (input: RequestInfo | URL, init?: RequestInit) => {
1555
+ const url = new URL(typeof input === 'string' ? input : input instanceof URL ? input.toString() : input.url);
1556
+ const method = init?.method || 'GET';
1557
+
1558
+ if (url.pathname === '/credentials' && method === 'GET' && url.searchParams.get('q') === 'github') {
1559
+ return new Response(JSON.stringify({
1560
+ credentials: [{
1561
+ id: 'cred-github',
1562
+ name: 'github',
1563
+ type: 'note',
1564
+ agentId: 'primary',
1565
+ meta: {},
1566
+ }],
1567
+ }), { status: 200, headers: { 'Content-Type': 'application/json' } });
1568
+ }
1569
+
1570
+ if (url.pathname === '/setup/agents' && method === 'GET') {
1571
+ return new Response(JSON.stringify({
1572
+ agents: [{ id: 'primary', name: 'primary', isPrimary: true }],
1573
+ }), { status: 200, headers: { 'Content-Type': 'application/json' } });
1574
+ }
1575
+
1576
+ if (url.pathname === '/setup' && method === 'GET') {
1577
+ return new Response(JSON.stringify({ projectScopeMode: 'auto' }), {
1578
+ status: 200,
1579
+ headers: { 'Content-Type': 'application/json' },
1580
+ });
1581
+ }
1582
+
1583
+ if (url.pathname === '/credentials/cred-github/read' && method === 'POST') {
1584
+ const headers = init?.headers as Record<string, string>;
1585
+ expect(headers.Authorization).toBe(`Bearer ${nonAdminToken}`);
1586
+ return new Response(JSON.stringify({
1587
+ encrypted: JSON.stringify({
1588
+ id: 'cred-github',
1589
+ agentId: 'primary',
1590
+ type: 'note',
1591
+ fields: [{ key: 'value', value: 'gh-secret', sensitive: true }],
1592
+ }),
1593
+ }), { status: 200, headers: { 'Content-Type': 'application/json' } });
1594
+ }
1595
+
1596
+ throw new Error(`Unexpected fetch path: ${method} ${url.pathname}${url.search}`);
1597
+ });
1598
+
1599
+ const logSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
1600
+ const exitCode = await runAgentCli(['get', 'github']);
1601
+
1602
+ expect(exitCode).toBe(0);
1603
+ expect(mocks.createReadToken).not.toHaveBeenCalled();
1604
+ expect(logSpy).toHaveBeenCalledWith('enc(gh-secret)');
1605
+ });
1492
1606
  });
@@ -19,15 +19,20 @@ describe('local agent trust helpers', () => {
19
19
  });
20
20
 
21
21
  it('resolves mode selection for numbered and named inputs', () => {
22
- expect(resolveLocalAgentModeChoice('')).toBe('dev');
23
- expect(resolveLocalAgentModeChoice('1')).toBe('dev');
22
+ expect(resolveLocalAgentModeChoice('')).toBe('admin');
23
+ expect(resolveLocalAgentModeChoice('1')).toBe('admin');
24
+ expect(resolveLocalAgentModeChoice('maxx')).toBe('admin');
25
+ expect(resolveLocalAgentModeChoice('work')).toBe('admin');
26
+ expect(resolveLocalAgentModeChoice('admin')).toBe('admin');
27
+
28
+ expect(resolveLocalAgentModeChoice('2')).toBe('dev');
29
+ expect(resolveLocalAgentModeChoice('mid')).toBe('dev');
24
30
  expect(resolveLocalAgentModeChoice('dev')).toBe('dev');
25
31
 
26
- expect(resolveLocalAgentModeChoice('2')).toBe('strict');
32
+ expect(resolveLocalAgentModeChoice('3')).toBe('strict');
33
+ expect(resolveLocalAgentModeChoice('sus')).toBe('strict');
34
+ expect(resolveLocalAgentModeChoice('local')).toBe('strict');
27
35
  expect(resolveLocalAgentModeChoice('strict')).toBe('strict');
28
-
29
- expect(resolveLocalAgentModeChoice('3')).toBe('admin');
30
- expect(resolveLocalAgentModeChoice('admin')).toBe('admin');
31
36
  });
32
37
 
33
38
  it('derives auto-approve defaults per profile mode', () => {