auramaxx 0.0.13 → 0.0.15

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 (117) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-build-manifest.json +37 -37
  3. package/.next/app-path-routes-manifest.json +8 -8
  4. package/.next/build-manifest.json +2 -2
  5. package/.next/prerender-manifest.json +34 -34
  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.js.nft.json +1 -1
  10. package/.next/server/app/api/[...doc]/page_client-reference-manifest.js +1 -1
  11. package/.next/server/app/api/agent-requests/route_client-reference-manifest.js +1 -1
  12. package/.next/server/app/api/apps/install/route_client-reference-manifest.js +1 -1
  13. package/.next/server/app/api/apps/manifests/route_client-reference-manifest.js +1 -1
  14. package/.next/server/app/api/apps/static/[...path]/route_client-reference-manifest.js +1 -1
  15. package/.next/server/app/api/docs/plain/route.js.nft.json +1 -1
  16. package/.next/server/app/api/docs/plain/route_client-reference-manifest.js +1 -1
  17. package/.next/server/app/api/events/route_client-reference-manifest.js +1 -1
  18. package/.next/server/app/api/import-from-openclaw/[channel]/route_client-reference-manifest.js +1 -1
  19. package/.next/server/app/api/import-from-openclaw/route_client-reference-manifest.js +1 -1
  20. package/.next/server/app/api/import-from-openclaw/validate/[channel]/route_client-reference-manifest.js +1 -1
  21. package/.next/server/app/api/page.js.nft.json +1 -1
  22. package/.next/server/app/api/page_client-reference-manifest.js +1 -1
  23. package/.next/server/app/api/restart/route_client-reference-manifest.js +1 -1
  24. package/.next/server/app/api/update/route.js +7 -8
  25. package/.next/server/app/api/update/route_client-reference-manifest.js +1 -1
  26. package/.next/server/app/api/version/route.js +1 -1
  27. package/.next/server/app/api/version/route_client-reference-manifest.js +1 -1
  28. package/.next/server/app/api/workspace/[id]/apps/[wid]/route_client-reference-manifest.js +1 -1
  29. package/.next/server/app/api/workspace/[id]/apps/route_client-reference-manifest.js +1 -1
  30. package/.next/server/app/api/workspace/[id]/export/route_client-reference-manifest.js +1 -1
  31. package/.next/server/app/api/workspace/[id]/route_client-reference-manifest.js +1 -1
  32. package/.next/server/app/api/workspace/config/route_client-reference-manifest.js +1 -1
  33. package/.next/server/app/api/workspace/import/route_client-reference-manifest.js +1 -1
  34. package/.next/server/app/api/workspace/route_client-reference-manifest.js +1 -1
  35. package/.next/server/app/app-legacy-do-not-use/page_client-reference-manifest.js +1 -1
  36. package/.next/server/app/app-legacy-do-not-use.html +1 -1
  37. package/.next/server/app/app-legacy-do-not-use.rsc +1 -1
  38. package/.next/server/app/approve/[actionId]/page.js +1 -1
  39. package/.next/server/app/approve/[actionId]/page_client-reference-manifest.js +1 -1
  40. package/.next/server/app/docs/[...doc]/page.js.nft.json +1 -1
  41. package/.next/server/app/docs/[...doc]/page_client-reference-manifest.js +1 -1
  42. package/.next/server/app/docs/page.js.nft.json +1 -1
  43. package/.next/server/app/docs/page_client-reference-manifest.js +1 -1
  44. package/.next/server/app/health/page_client-reference-manifest.js +1 -1
  45. package/.next/server/app/health.html +1 -1
  46. package/.next/server/app/health.rsc +1 -1
  47. package/.next/server/app/hello/page_client-reference-manifest.js +1 -1
  48. package/.next/server/app/hello.html +1 -1
  49. package/.next/server/app/hello.rsc +1 -1
  50. package/.next/server/app/index.html +1 -1
  51. package/.next/server/app/index.rsc +3 -3
  52. package/.next/server/app/page.js +2 -2
  53. package/.next/server/app/page_client-reference-manifest.js +1 -1
  54. package/.next/server/app/privacy/page_client-reference-manifest.js +1 -1
  55. package/.next/server/app/privacy.html +1 -1
  56. package/.next/server/app/privacy.rsc +1 -1
  57. package/.next/server/app/share/[token]/page_client-reference-manifest.js +1 -1
  58. package/.next/server/app/terms/page_client-reference-manifest.js +1 -1
  59. package/.next/server/app/terms.html +1 -1
  60. package/.next/server/app/terms.rsc +1 -1
  61. package/.next/server/app/yo/page.js +2 -2
  62. package/.next/server/app/yo/page_client-reference-manifest.js +1 -1
  63. package/.next/server/app/yo.html +1 -1
  64. package/.next/server/app/yo.rsc +3 -3
  65. package/.next/server/app-paths-manifest.json +8 -8
  66. package/.next/server/functions-config-manifest.json +2 -2
  67. package/.next/server/pages/404.html +1 -1
  68. package/.next/server/pages/500.html +1 -1
  69. package/.next/server/server-reference-manifest.json +1 -1
  70. package/.next/static/chunks/app/approve/[actionId]/page-c862645e19371cea.js +1 -0
  71. package/.next/static/chunks/app/{page-16dfcd1c7cc88bcc.js → page-9cd218b297b9c7bf.js} +1 -1
  72. package/.next/static/chunks/app/yo/page-fceb03605805cb44.js +1 -0
  73. package/.next/trace +28 -28
  74. package/README.md +1 -1
  75. package/docs/AGENT_SETUP.md +1 -1
  76. package/docs/AUTH.md +1 -1
  77. package/docs/CLI.md +0 -3
  78. package/docs/MCP.md +14 -7
  79. package/docs/SKILLS.md +1 -1
  80. package/docs/api/secrets/credentials.md +9 -0
  81. package/docs/external/HOW_TO_AURAMAXX/WORKING_WITH_SECRETS.md +2 -1
  82. package/docs/external/POLICY.md +2 -2
  83. package/package.json +1 -1
  84. package/public/opengraph.webp +0 -0
  85. package/skills/auramaxx/HEARTBEAT.md +3 -0
  86. package/skills/auramaxx/SKILL.md +13 -31
  87. package/skills/auramaxx/docs/AGENT_SETUP.md +1 -1
  88. package/src/app/UnlockPageClient.tsx +10 -10
  89. package/src/app/api/update/route.ts +9 -10
  90. package/src/app/approve/[actionId]/page.tsx +2 -1
  91. package/src/app/page.tsx +9 -0
  92. package/src/app/yo/layout.tsx +9 -0
  93. package/src/app/yo/page.tsx +1 -1
  94. package/src/components/layout/SettingsDrawer.tsx +1 -1
  95. package/src/server/cli/commands/agent.ts +75 -18
  96. package/src/server/cli/commands/init.ts +9 -9
  97. package/src/server/cli/commands/skill.ts +5 -2
  98. package/src/server/cli/lib/credential-resolve.ts +20 -1
  99. package/src/server/cli/lib/local-agent-trust.ts +4 -3
  100. package/src/server/lib/agent-profiles.ts +4 -3
  101. package/src/server/lib/update-check.ts +4 -0
  102. package/src/server/mcp/server.ts +88 -19
  103. package/src/server/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.json +1 -1
  104. package/src/server/routes/actions.ts +2 -1
  105. package/src/server/routes/credentials.ts +48 -5
  106. package/src/server/tests/cli/agent-auth.test.ts +190 -0
  107. package/src/server/tests/cli/local-agent-trust.test.ts +11 -6
  108. package/src/server/tests/endpoints/credentials.test.ts +40 -18
  109. package/src/server/tests/endpoints/escalation-migration-gate.test.ts +1 -1
  110. package/src/server/tests/lib/agent-profiles.test.ts +6 -0
  111. package/src/server/tests/lib/update-check.test.ts +9 -1
  112. package/src/server/tests/mcp/server.test.ts +142 -0
  113. package/src/server/tsconfig.tsbuildinfo +1 -1
  114. package/.next/static/chunks/app/approve/[actionId]/page-2acca1f490424f21.js +0 -1
  115. package/.next/static/chunks/app/yo/page-719dc5f213fdfb30.js +0 -1
  116. /package/.next/static/{WshFGr6RxGYP6AbWuT9OG → 7S943hv6A_w-7tx0a47LZ}/_buildManifest.js +0 -0
  117. /package/.next/static/{WshFGr6RxGYP6AbWuT9OG → 7S943hv6A_w-7tx0a47LZ}/_ssgManifest.js +0 -0
@@ -335,30 +335,30 @@ async function readPasswordFromStdin(timeoutMs = 15_000): Promise<string> {
335
335
  }
336
336
 
337
337
  async function configureLocalSocketTrust(token: string): Promise<void> {
338
- printSection('Local Agent Trust', 'Choose default local agent mode.');
338
+ printSection('Local Agent Trust', 'How much do you trust your agent?');
339
339
 
340
340
  const profile = resolveLocalAgentModeChoice(
341
341
  await promptSelect(
342
- ' Local agent mode',
342
+ ' How much do you trust your agent?',
343
343
  [
344
- { value: 'dev', label: 'dev', aliases: ['1', 'recommended'] },
345
- { value: 'strict', label: 'strict', aliases: ['2'] },
346
- { value: 'admin', label: 'admin', aliases: ['3', 'dangerous'] },
344
+ { value: 'admin', label: 'maxx (admin)', aliases: ['1', 'default', 'maxx', 'work'] },
345
+ { value: 'dev', label: 'mid (dev)', aliases: ['2', 'mid', 'dev', 'recommended'] },
346
+ { value: 'strict', label: 'sus (local)', aliases: ['3', 'sus', 'local', 'strict'] },
347
347
  ],
348
- 'dev',
348
+ 'admin',
349
349
  ),
350
350
  );
351
351
  await persistLocalAgentTrustDefaults(token, profile);
352
352
 
353
353
  if (profile === 'strict') {
354
- console.log(' ✓ Strict mode enabled. Local auto-approve is OFF; agent requests require manual approval.\n');
354
+ console.log(' ✓ Sus mode enabled. Local auto-approve is OFF; agent requests require manual approval.\n');
355
355
  return;
356
356
  }
357
357
  if (profile === 'admin') {
358
- console.log(' ✓ Admin mode enabled. WARNING: local agents get broad access.\n');
358
+ console.log(' ✓ Maxx mode enabled. WARNING: local agents get broad access.\n');
359
359
  return;
360
360
  }
361
- console.log(' ✓ Dev mode enabled. Local auto-approve remains ON with scoped profile.\n');
361
+ console.log(' ✓ Mid mode enabled. Local auto-approve remains ON with scoped profile.\n');
362
362
  }
363
363
 
364
364
  async function configureApiKey(
@@ -121,7 +121,7 @@ function patchHeartbeatFile(heartbeatPath: string): boolean {
121
121
  '1. Call `GET /what_is_happening` (prefer `?since=<last_timestamp_ms>`).',
122
122
  '2. Review in order: `summary` → `highlights` → `humanActions` → `recentEvents` → `syncHealth`.',
123
123
  '3. Prioritize engagement first (most important to least): pending approvals needing human action → new errors/sync issues → unusual secret access activity → routine no-change status.',
124
- '4. Write a conversational, human-readable update (not replay dumps), delta-first.',
124
+ '4. Write a short, high-signal update in productive brainrot tone: conversational + direct, never robotic.',
125
125
  '5. Always include auth counts from `summary.authorizations` (`pending/approved/rejected`) and accessed secret names from `summary.secrets.names`.',
126
126
  '6. For pending approvals: counts first, grouped reason, short IDs only unless escalated.',
127
127
  '7. If `summary.secrets.count > 0`, say exactly which secret(s) were accessed (top 1-3 names) and by whom when possible (`summary.secrets.byAgent`).',
@@ -130,7 +130,10 @@ function patchHeartbeatFile(heartbeatPath: string): boolean {
130
130
  '10. If no material change, use `HEARTBEAT_VIBES` style (brainrot + vault status + aura quote) while still including auth/secrets counts.',
131
131
  '11. Do not write placeholder diary text like `heartbeat: logged`.',
132
132
  '12. If diary write fails after retry, reply `FOLLOWUP_NEEDED: diary_write_failed <reason>`.',
133
- '13. Response style: `HEARTBEAT_OK - Checked AuraMaxx, all good.` for no-change; otherwise `Checked AuraMaxx - ...` with a short conversational summary.',
133
+ '13. Response style:',
134
+ ' - no-change: `HEARTBEAT_OK: aura stable. Auth X pending / Y approved / Z rejected. Secrets none touched. Delta no material change.`',
135
+ ' - changed: `Checked AuraMaxx: [delta first]. Auth X/Y/Z. Secrets [top names]. Why it matters [impact]. Next move [plan].`',
136
+ '14. Avoid stiff phrases like `No approvals are currently pending` or long replay paragraphs; keep it punchy (2-5 sentences max unless follow-up is needed).',
134
137
  '',
135
138
  ].join('\n');
136
139
 
@@ -146,10 +146,23 @@ export async function readCredential(
146
146
  readToken: string,
147
147
  credentialId: string,
148
148
  decryptFn: (encrypted: string) => string,
149
+ requestedFields?: string[],
149
150
  ): Promise<DecryptedCredential> {
151
+ const normalizedRequestedFields = Array.from(new Set(
152
+ (requestedFields || [])
153
+ .map((value) => String(value || '').trim())
154
+ .filter((value) => value.length > 0),
155
+ ));
156
+ const requestBody = normalizedRequestedFields.length > 0
157
+ ? JSON.stringify({ requestedFields: normalizedRequestedFields })
158
+ : undefined;
150
159
  const res = await fetch(`${baseUrl}/credentials/${credentialId}/read`, {
151
160
  method: 'POST',
152
- headers: { Authorization: `Bearer ${readToken}` },
161
+ headers: {
162
+ Authorization: `Bearer ${readToken}`,
163
+ ...(requestBody ? { 'Content-Type': 'application/json' } : {}),
164
+ },
165
+ ...(requestBody ? { body: requestBody } : {}),
153
166
  signal: AbortSignal.timeout(5000),
154
167
  });
155
168
  if (!res.ok) {
@@ -190,9 +203,13 @@ export async function resolveMappings(
190
203
  }
191
204
 
192
205
  const uniqueTargets = new Map<string, AuraMapping>();
206
+ const requestedFieldsByTarget = new Map<string, Set<string>>();
193
207
  for (const mapping of mappings) {
194
208
  const key = `${(mapping.agent || '').toLowerCase()}::${mapping.credentialName.toLowerCase()}`;
195
209
  if (!uniqueTargets.has(key)) uniqueTargets.set(key, mapping);
210
+ const requested = requestedFieldsByTarget.get(key) || new Set<string>();
211
+ requested.add(mapping.field);
212
+ requestedFieldsByTarget.set(key, requested);
196
213
  }
197
214
 
198
215
  const targetList = [...uniqueTargets.values()];
@@ -228,11 +245,13 @@ export async function resolveMappings(
228
245
  }
229
246
 
230
247
  try {
248
+ const requestedFields = Array.from(requestedFieldsByTarget.get(cacheKey) || []);
231
249
  const decrypted = await readCredential(
232
250
  baseUrl,
233
251
  readToken,
234
252
  meta.id,
235
253
  decryptFn,
254
+ requestedFields,
236
255
  );
237
256
  credentialCache.set(cacheKey, decrypted);
238
257
  } catch (err) {
@@ -9,9 +9,10 @@ export interface LocalAgentTrustDefaults {
9
9
 
10
10
  export function resolveLocalAgentModeChoice(input: string): LocalAgentProfileMode {
11
11
  const normalized = input.trim().toLowerCase();
12
- if (normalized === '2' || normalized === 'strict') return 'strict';
13
- if (normalized === '3' || normalized === 'admin') return 'admin';
14
- return 'dev';
12
+ if (normalized === '1' || normalized === 'admin' || normalized === 'maxx' || normalized === 'work') return 'admin';
13
+ if (normalized === '3' || normalized === 'strict' || normalized === 'sus' || normalized === 'local') return 'strict';
14
+ if (normalized === '2' || normalized === 'dev' || normalized === 'mid' || normalized === 'recommended') return 'dev';
15
+ return 'admin';
15
16
  }
16
17
 
17
18
  export function toLocalAgentTrustDefaults(profile: LocalAgentProfileMode): LocalAgentTrustDefaults {
@@ -94,13 +94,14 @@ const BUILTIN_PROFILES: AgentPolicyProfileV1[] = [
94
94
  rationale: 'Use for day-to-day local dev workflows without granting financial operations.',
95
95
  permissions: ['wallet:list', 'secret:read', 'secret:write', 'action:create', 'action:read', 'action:resolve'],
96
96
  credentialAccess: {
97
- readScopes: ['agent:*'],
98
- writeScopes: ['agent:*'],
97
+ // Keep legacy `agent` alias for migrated installs while scoping to primary-only access.
98
+ readScopes: ['agent:primary', 'agent:agent'],
99
+ writeScopes: ['agent:primary', 'agent:agent'],
99
100
  excludeFields: ['cvv', 'seedPhrase', 'privateKey', 'refresh_token'],
100
101
  maxReads: 500,
101
102
  },
102
103
  tokenDefaults: { ttlSeconds: 7 * 24 * 60 * 60, maxReads: 500 },
103
- warnings: ['Includes secret:write. Prefer dedicated non-primary agents for agent-managed credentials.'],
104
+ warnings: ['Includes secret:write. Credential scope is limited to the primary agent (legacy alias included).'],
104
105
  },
105
106
  {
106
107
  id: 'admin',
@@ -34,6 +34,10 @@ export function buildUpdateCommand(packageName = 'auramaxx'): string {
34
34
  return `npm install -g ${packageName} --foreground-scripts`;
35
35
  }
36
36
 
37
+ export function buildUpdateForceCommand(packageName = 'auramaxx'): string {
38
+ return `${buildUpdateCommand(packageName)} --force`;
39
+ }
40
+
37
41
  export function buildNpxLatestCommand(packageName = 'auramaxx', args: string[] = []): string {
38
42
  const suffix = args.length > 0 ? ` ${args.join(' ')}` : '';
39
43
  return `npx --yes ${packageName}@latest${suffix}`;
@@ -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,9 +1585,19 @@ server.tool(
1549
1585
  }
1550
1586
  }
1551
1587
 
1552
- const secretValue = extractPrimarySecretValue(decrypted.fields);
1553
- if (!secretValue) {
1554
- return { content: [{ type: 'text' as const, text: JSON.stringify({ error: `Credential "${credentialName || name}" has no extractable secret value` }) }] };
1588
+ let secretValue = '';
1589
+ if (requestedField) {
1590
+ const requestedValue = findCredentialFieldValue(decrypted.type || resolved.credentialType, decrypted.fields, requestedField);
1591
+ if (requestedValue === undefined) {
1592
+ const availableFields = decrypted.fields.map((entry) => entry.key).join(', ');
1593
+ return { content: [{ type: 'text' as const, text: JSON.stringify({ error: `Field "${requestedField}" not found on credential "${credentialName || name}"`, availableFields }) }] };
1594
+ }
1595
+ secretValue = requestedValue;
1596
+ } else {
1597
+ secretValue = extractPrimarySecretValue(decrypted.fields);
1598
+ if (!secretValue) {
1599
+ return { content: [{ type: 'text' as const, text: JSON.stringify({ error: `Credential "${credentialName || name}" has no extractable secret value` }) }] };
1600
+ }
1555
1601
  }
1556
1602
 
1557
1603
  const resolvedEnvVar = defaultSecretEnvVarName(credentialName || name);
@@ -1933,9 +1979,10 @@ server.tool(
1933
1979
  // ── inject_secret ──────────────────────────────────────────────────────
1934
1980
  server.tool(
1935
1981
  '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.',
1982
+ '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
1983
  {
1938
1984
  name: z.string().describe('Name or tag of the credential to inject'),
1985
+ field: z.string().optional().describe('Optional explicit field key to inject instead of the credential primary field.'),
1939
1986
  envVar: z.string().optional().describe('Optional environment variable name (defaults to AURA_{SECRETNAME}, e.g. "AURA_OPENAI_API_KEY")'),
1940
1987
  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
1988
  dangerPlaintext: z.boolean().optional().describe('If true, include plaintext secret in output (unsafe). Defaults to false (masked).'),
@@ -1944,12 +1991,14 @@ server.tool(
1944
1991
  async (input) => {
1945
1992
  const {
1946
1993
  name,
1994
+ field,
1947
1995
  envVar,
1948
1996
  command,
1949
1997
  dangerPlaintext,
1950
1998
  reqId,
1951
- } = input as { name: string; envVar?: string; command?: string[]; dangerPlaintext?: boolean; reqId?: string };
1999
+ } = input as { name: string; field?: string; envVar?: string; command?: string[]; dangerPlaintext?: boolean; reqId?: string };
1952
2000
  const revealPlaintext = dangerPlaintext === true;
2001
+ const requestedField = String(field || '').trim();
1953
2002
  const resolvedEnvVar = normalizeEnvVarName(envVar || defaultSecretEnvVarName(name));
1954
2003
  if (!resolvedEnvVar) {
1955
2004
  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 +2017,7 @@ server.tool(
1968
2017
  const credentialNameFromBinding = authContext.mode === 'one_shot' ? authContext.binding?.credentialName : undefined;
1969
2018
 
1970
2019
  const resolved = credentialIdFromBinding
1971
- ? { credentialId: credentialIdFromBinding, credentialName: credentialNameFromBinding || name }
2020
+ ? { credentialId: credentialIdFromBinding, credentialName: credentialNameFromBinding || name, credentialType: undefined }
1972
2021
  : await resolveCredentialByName(name, authToken);
1973
2022
  if ('error' in resolved) {
1974
2023
  if ('escalation' in resolved && resolved.escalation) return resolved.escalation;
@@ -1976,6 +2025,17 @@ server.tool(
1976
2025
  }
1977
2026
 
1978
2027
  const base = WALLET_BASE();
2028
+ const requestedFields = requestedField
2029
+ ? [requestedField]
2030
+ : resolved.credentialType
2031
+ ? [getCredentialPrimaryFieldKey(resolved.credentialType)]
2032
+ : [];
2033
+ const readPayload = requestedFields.length > 0
2034
+ ? { requestedFields }
2035
+ : {};
2036
+ const readBody = requestedFields.length > 0
2037
+ ? JSON.stringify(readPayload)
2038
+ : undefined;
1979
2039
  if (authContext.mode === 'one_shot' && authContext.reqId && authContext.binding) {
1980
2040
  const bindingError = validateOneShotCredentialReadBinding({
1981
2041
  reqId: authContext.reqId,
@@ -1994,11 +2054,13 @@ server.tool(
1994
2054
  method: 'POST',
1995
2055
  headers: {
1996
2056
  'Authorization': `Bearer ${authToken}`,
2057
+ ...(readBody ? { 'Content-Type': 'application/json' } : {}),
1997
2058
  'X-Secret-Surface': 'inject_secret',
1998
2059
  'X-Secret-EnvVar': resolvedEnvVar,
1999
2060
  'X-Credential-Name': resolved.credentialName || name,
2000
2061
  'X-Aura-Original-Command': `mcp inject_secret ${JSON.stringify(name)}`,
2001
2062
  },
2063
+ ...(readBody ? { body: readBody } : {}),
2002
2064
  signal: AbortSignal.timeout(5000),
2003
2065
  });
2004
2066
 
@@ -2012,7 +2074,7 @@ server.tool(
2012
2074
  permissions: ['secret:read'],
2013
2075
  endpoint: `/credentials/${resolved.credentialId}/read`,
2014
2076
  method: 'POST',
2015
- body: {},
2077
+ body: readPayload,
2016
2078
  });
2017
2079
  }
2018
2080
  return { content: [{ type: 'text' as const, text: JSON.stringify({ error: `Read failed (${res.status}): ${text}` }) }] };
@@ -2021,11 +2083,18 @@ server.tool(
2021
2083
  const data = await res.json() as { encrypted: string };
2022
2084
  const decrypted = decryptCredentialPayload(data.encrypted);
2023
2085
 
2024
- // Extract primary secret field
2025
- secretValue = extractPrimarySecretValue(decrypted.fields);
2026
-
2027
- if (!secretValue) {
2028
- return { content: [{ type: 'text' as const, text: JSON.stringify({ error: `Credential "${name}" has no extractable secret value` }) }] };
2086
+ if (requestedField) {
2087
+ const requestedValue = findCredentialFieldValue(decrypted.type || resolved.credentialType, decrypted.fields, requestedField);
2088
+ if (requestedValue === undefined) {
2089
+ const availableFields = decrypted.fields.map((entry) => entry.key).join(', ');
2090
+ return { content: [{ type: 'text' as const, text: JSON.stringify({ error: `Field "${requestedField}" not found on credential "${resolved.credentialName || name}"`, availableFields }) }] };
2091
+ }
2092
+ secretValue = requestedValue;
2093
+ } else {
2094
+ secretValue = extractPrimarySecretValue(decrypted.fields);
2095
+ if (!secretValue) {
2096
+ return { content: [{ type: 'text' as const, text: JSON.stringify({ error: `Credential "${name}" has no extractable secret value` }) }] };
2097
+ }
2029
2098
  }
2030
2099
  } catch (err) {
2031
2100
  return { content: [{ type: 'text' as const, text: JSON.stringify({ error: `inject_secret read failed: ${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":4080.0858749999998,"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":6413.059167000001,"failed":false}],[":tests/auth/permissions.test.ts",{"duration":6673.536915999999,"failed":false}],[":tests/auth/middleware.test.ts",{"duration":8759.18275,"failed":false}],[":tests/lib/sessions.test.ts",{"duration":80.44737499999997,"failed":false}],[":tests/lib/auth.test.ts",{"duration":4095.9412919999995,"failed":false}],[":tests/endpoints/unlock.test.ts",{"duration":10394.113917,"failed":false}],[":tests/endpoints/wallet.test.ts",{"duration":4688.91025,"failed":false}],[":tests/endpoints/approve.test.ts",{"duration":497.64808300000004,"failed":false}],[":tests/endpoints/fund.test.ts",{"duration":1739.703958,"failed":false}],[":tests/endpoints/send.test.ts",{"duration":2330.7616669999998,"failed":false}],[":tests/endpoints/auth.test.ts",{"duration":1678.686916,"failed":false}],[":tests/endpoints/setup.test.ts",{"duration":4925.4596249999995,"failed":false}],[":tests/lib/uniswap.test.ts",{"duration":12.830749999999995,"failed":false}],[":tests/auth/apikeys.test.ts",{"duration":10943.105167,"failed":false}],[":tests/endpoints/wallet-data.test.ts",{"duration":2516.620667,"failed":false}],[":tests/endpoints/swap.test.ts",{"duration":2045.7226249999999,"failed":false}],[":tests/endpoints/token-clearing.test.ts",{"duration":1299.981875,"failed":false}],[":tests/endpoints/rate-limit.test.ts",{"duration":2072.681375,"failed":false}],[":tests/endpoints/solana-swap.test.ts",{"duration":1022.9342909999999,"failed":false}],[":tests/endpoints/solana-wallet.test.ts",{"duration":1344.735792,"failed":false}],[":tests/endpoints/solana-send.test.ts",{"duration":1062.2614170000002,"failed":false}],[":tests/lib/sessions-currency.test.ts",{"duration":93.34312499999999,"failed":false}],[":tests/endpoints/solana-fund.test.ts",{"duration":1369.6695,"failed":false}],[":tests/lib/solana-wallet.test.ts",{"duration":149.332917,"failed":false}],[":tests/lib/address.test.ts",{"duration":2.6223750000000052,"failed":false}],[":tests/lib/strategy/sources.test.ts",{"duration":19.652749999999997,"failed":false}],[":tests/lib/strategy/loader.test.ts",{"duration":12.884332999999998,"failed":false}],[":tests/lib/strategy/executor.test.ts",{"duration":11.662749999999988,"failed":false}],[":tests/lib/strategy/state.test.ts",{"duration":10.546458999999999,"failed":false}],[":tests/lib/strategy/hooks.test.ts",{"duration":16.040250000000015,"failed":false}],[":tests/endpoints/widgets.test.ts",{"duration":2127.785625,"failed":false}],[":tests/lib/strategy/message.test.ts",{"duration":114.59958300000002,"failed":false}],[":tests/endpoints/actions.test.ts",{"duration":2456.5247090000003,"failed":false}],[":tests/endpoints/vault.test.ts",{"duration":7419.710874999999,"failed":false}],[":tests/integration/adapter-resolve.test.ts",{"duration":3331.277875,"failed":false}],[":tests/lib/adapters.test.ts",{"duration":30.631124999999997,"failed":false}],[":tests/lib/strategy/tick.test.ts",{"duration":7.374167,"failed":false}],[":tests/lib/relay.test.ts",{"duration":5.019999999999982,"failed":false}],[":tests/lib/ai.test.ts",{"duration":5.997749999999996,"failed":false}],[":tests/endpoints/launch.test.ts",{"duration":33345.279542000004,"failed":false}],[":tests/widget-installer.test.ts",{"duration":154.704459,"failed":false}],[":tests/mcp/tools.test.ts",{"duration":17.772499999999994,"failed":false}],[":tests/ai-integration/scenarios.test.ts",{"duration":7.4487499999999045,"failed":true}],[":tests/mcp/server.test.ts",{"duration":1465.489834,"failed":false}],[":tests/ai-integration/live.test.ts",{"duration":77572.38508299999,"failed":false}],[":tests/auth/apikeys-validate.test.ts",{"duration":9938.500916,"failed":false}],[":tests/lib/adapters-test.test.ts",{"duration":24647.903333000002,"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.692542000000003,"failed":false}],[":tests/cli/process.test.ts",{"duration":57.403958,"failed":false}],[":tests/cli/init-steps.test.ts",{"duration":10.969333000000006,"failed":false}],[":tests/cli/init-flow.test.ts",{"duration":2329.560167,"failed":false}],[":tests/cli/http.test.ts",{"duration":1581.040333,"failed":false}],[":tests/lib/verified-summary.test.ts",{"duration":7.0299579999999935,"failed":false}],[":tests/lib/defaults.test.ts",{"duration":68.398459,"failed":false}],[":tests/endpoints/defaults.test.ts",{"duration":5841.581958999999,"failed":false}],[":tests/lib/adapters-chat.test.ts",{"duration":25.645249999999976,"failed":false}],[":tests/setup-integration/terminal-flow.test.ts",{"duration":248.770042,"failed":false}],[":tests/endpoints/transactions.test.ts",{"duration":1090.902125,"failed":false}],[":tests/cron/scheduler.test.ts",{"duration":11.840542,"failed":false}],[":tests/endpoints/portfolio.test.ts",{"duration":275.87408400000004,"failed":false}],[":tests/cron/native-price.test.ts",{"duration":80.20424999999989,"failed":false}],[":tests/resolve.test.ts",{"duration":13.036125000000084,"failed":false}],[":tests/lib/prices.test.ts",{"duration":50.52241700000013,"failed":false}],[":tests/swap-quote.test.ts",{"duration":1009.3182499999999,"failed":false}],[":tests/send-token.test.ts",{"duration":988.631083,"failed":false}],[":tests/endpoints/price.test.ts",{"duration":36.503582999999935,"failed":false}],[":tests/lib/price.test.ts",{"duration":5.893500000000003,"failed":false}],[":tests/endpoints/token-search.test.ts",{"duration":44.32499999999993,"failed":false}],[":tests/lib/token-search.test.ts",{"duration":63.291291999999984,"failed":false}],[":tests/lib/token-safety.test.ts",{"duration":5.879292000000007,"failed":false}],[":tests/endpoints/token-safety.test.ts",{"duration":33.88024999999993,"failed":false}],[":tests/lib/batch.test.ts",{"duration":4.744375000000005,"failed":false}],[":tests/endpoints/batch.test.ts",{"duration":42.573457999999846,"failed":false}],[":tests/endpoints/token-balance.test.ts",{"duration":32.50795799999992,"failed":false}],[":tests/lib/events-decoder.test.ts",{"duration":5.0207499999999925,"failed":false}],[":tests/lib/events-enricher.test.ts",{"duration":5.3929580000000215,"failed":false}],[":tests/endpoints/address-transactions.test.ts",{"duration":1000.6757920000001,"failed":false}],[":tests/endpoints/bookmarks.test.ts",{"duration":1279.267041,"failed":false}],[":tests/endpoints/addressbook.test.ts",{"duration":1067.5747500000002,"failed":false}],[":tests/lib/strategy/session-logger.test.ts",{"duration":1468.45775,"failed":false}],[":tests/cron/incoming-scan.test.ts",{"duration":321.18891699999995,"failed":false}],[":tests/lib/auto-unlock.test.ts",{"duration":1022.7568749999999,"failed":false}],[":tests/lib/widget-tokens-tier.test.ts",{"duration":226.36699999999996,"failed":false}],[":tests/cron/strategy-runner.test.ts",{"duration":5.555291999999994,"failed":false}],[":tests/endpoints/strategy-routes.test.ts",{"duration":11067.915083,"failed":false}],[":tests/endpoints/apps.test.ts",{"duration":20776.13675,"failed":false}],[":tests/lib/events-fetcher.test.ts",{"duration":7.772790999999984,"failed":false}],[":tests/app-installer.test.ts",{"duration":128.42795900000002,"failed":false}],[":tests/lib/app-tokens-tier.test.ts",{"duration":247.269042,"failed":false}],[":tests/setup-integration/onboarding-e2e.test.ts",{"duration":445.7834579999999,"failed":true}],[":tests/cron/orphan-cleanup.test.ts",{"duration":4.394666999999998,"failed":false}],[":tests/lib/strategy/repository.test.ts",{"duration":41.04454199999998,"failed":false}],[":tests/setup-integration/autonomous-agent.test.ts",{"duration":7.406667000000027,"failed":true}],[":tests/lib/websocket-auth.test.ts",{"duration":228.09824999999998,"failed":false}],[":tests/lib/credentials.test.ts",{"duration":7244.236916,"failed":false}],[":tests/lib/credential-access.test.ts",{"duration":4.496959000000004,"failed":false}],[":tests/lib/credential-scope.test.ts",{"duration":3.911790999999994,"failed":false}],[":tests/endpoints/credential-ops.test.ts",{"duration":3012.519625,"failed":false}],[":tests/endpoints/credentials.test.ts",{"duration":26961.16275,"failed":false}],[":tests/lib/credential-transport.test.ts",{"duration":100.9825,"failed":false}],[":tests/lib/credential-vault.test.ts",{"duration":4433.612583,"failed":false}],[":tests/lib/resolve-action.test.ts",{"duration":5.200542000000013,"failed":false}],[":tests/credential-import.test.ts",{"duration":19.59904200000001,"failed":false}],[":tests/endpoints/passkey.test.ts",{"duration":13994.460458,"failed":false}],[":tests/lib/oauth2-refresh.test.ts",{"duration":4.189582999999999,"failed":false}],[":tests/lib/totp.test.ts",{"duration":5.6655839999999955,"failed":false}],[":tests/lib/passkey-credential.test.ts",{"duration":6.855125000000001,"failed":false}],[":tests/cli/env.test.ts",{"duration":8.122291999999987,"failed":false}],[":tests/dotenv-parser.test.ts",{"duration":4.285124999999994,"failed":false}],[":tests/cli/socket.test.ts",{"duration":203.840084,"failed":false}],[":tests/cli/vault.test.ts",{"duration":5.563457999999997,"failed":false}],[":tests/cli/credential-resolve.test.ts",{"duration":2.6506669999999986,"failed":false}],[":tests/cli/env-check-server-vault.test.ts",{"duration":239.821708,"failed":false}],[":tests/e2e-agent/validation.test.ts",{"duration":7.176417000000001,"failed":false}],[":tests/e2e-agent/artifacts.test.ts",{"duration":2.1517920000000004,"failed":false}],[":tests/e2e-agent/ci-lanes.test.ts",{"duration":1.1575419999999994,"failed":false}],[":tests/lib/api-registry/validation.test.ts",{"duration":7.92649999999999,"failed":false}],[":tests/lib/aura-parser.test.ts",{"duration":10.717959000000008,"failed":false}],[":tests/lib/agent-auth/contracts.test.ts",{"duration":8.928665999999993,"failed":false}],[":tests/cli/doctor.test.ts",{"duration":13.734708999999995,"failed":false}],[":tests/endpoints/import.test.ts",{"duration":8375.402458,"failed":false}],[":tests/endpoints/passkey-credentials.test.ts",{"duration":2524.953291,"failed":false}],[":tests/lib/credential-health.test.ts",{"duration":2.7282909999999987,"failed":false}],[":tests/lib/agent-profiles.test.ts",{"duration":3.490583999999984,"failed":false}],[":tests/mcp/profile-policy.test.ts",{"duration":3.0271250000000123,"failed":false}],[":tests/endpoints/profile-parity.test.ts",{"duration":9.213209000000006,"failed":true}],[":tests/lib/profile-parity.test.ts",{"duration":1.614333000000002,"failed":false}],[":tests/endpoints/credential-access-audit.test.ts",{"duration":1780.9782919999998,"failed":false}],[":tests/lib/project-scope.test.ts",{"duration":8.030417,"failed":false}],[":tests/docs/job-docs-validation.test.ts",{"duration":32.666083,"failed":false}],[":tests/endpoints/credential-shares.test.ts",{"duration":5782.297167,"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":3.4474169999999873,"failed":false}],[":tests/cli/token.test.ts",{"duration":1.4730000000000132,"failed":false}],[":tests/endpoints/heartbeat.test.ts",{"duration":4058.10775,"failed":false}],[":tests/cli/bin-entrypoint.test.ts",{"duration":3965.3672079999997,"failed":false}],[":tests/sandbox/cli.test.ts",{"duration":269.86533299999996,"failed":false}],[":tests/cli/vault-auth.test.ts",{"duration":195.026916,"failed":false}],[":tests/lib/encrypt.test.ts",{"duration":739.603,"failed":false}],[":tests/cli/vault-share-gist.test.ts",{"duration":14.503625,"failed":false}],[":tests/lib/secret-gist-share.test.ts",{"duration":1.6444999999999936,"failed":false}],[":tests/cli/vault-list-filters.test.ts",{"duration":14.040582999999984,"failed":false}],[":tests/cli/start.test.ts",{"duration":1.9482500000000016,"failed":false}],[":tests/cli/wallet.test.ts",{"duration":1.4312499999999915,"failed":false}],[":tests/cli/prompt-select.test.ts",{"duration":4.526584,"failed":false}],[":tests/cli/quickhack.test.ts",{"duration":1.9109579999999937,"failed":false}],[":tests/lib/human-action-summary.test.ts",{"duration":2.183374999999998,"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.0180000000000007,"failed":false}],[":tests/lib/dont-ask-again-policy.test.ts",{"duration":1.1674579999999963,"failed":false}],[":tests/lib/update-check.test.ts",{"duration":1.3457500000000095,"failed":false}],[":tests/lib/auto-execute.test.ts",{"duration":106.970417,"failed":false}],[":tests/lib/auth-action.test.ts",{"duration":1971.094417,"failed":false}],[":tests/cli/auth-action-flag.test.ts",{"duration":2.953084000000004,"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":2370.5335,"failed":false}],[":tests/sandbox/cli-cd-suite.test.ts",{"duration":953.0126659999999,"failed":false}],[":tests/mcp/contract.test.ts",{"duration":151.07174999999998,"failed":false}],[":tests/lib/credential-paths.test.ts",{"duration":3779.089958,"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.523459000000003,"failed":false}],[":tests/cli/restart-run.test.ts",{"duration":2.4307500000000033,"failed":false}],[":tests/endpoints/approve-action.test.ts",{"duration":982.046125,"failed":false}],[":tests/cli/escalation.test.ts",{"duration":3.6188750000000027,"failed":false}],[":tests/cli/actions-auth.test.ts",{"duration":53.00212499999998,"failed":false}],[":tests/lib/temp-policy.test.ts",{"duration":2.6212909999999994,"failed":false}],[":tests/endpoints/escalation-migration-gate.test.ts",{"duration":11600.137458000001,"failed":false}],[":tests/lib/escalation-responder.test.ts",{"duration":22.55212499999999,"failed":false}],[":tests/cli/service.test.ts",{"duration":40.734375,"failed":false}],[":tests/cli/init-runtime.test.ts",{"duration":6.353541999999976,"failed":false}],[":tests/cli/agent.test.ts",{"duration":5.218541999999999,"failed":false}],[":tests/runtime-agent-smoke.test.ts",{"duration":1125.018291,"failed":false}],[":tests/endpoints/agent.test.ts",{"duration":5885.352958,"failed":false}],[":tests/lib/credential-agent.test.ts",{"duration":3014.652917,"failed":false}],[":tests/cli/agent-auth.test.ts",{"duration":637.7750000000001,"failed":false}],[":tests/cli/agent-share-gist.test.ts",{"duration":13.641041000000016,"failed":false}],[":tests/cli/agent-list-filters.test.ts",{"duration":12.53479200000001,"failed":false}],[":tests/cli/env-check-server-agent.test.ts",{"duration":297.161208,"failed":false}],[":tests/lib/import-from-openclaw-paths.test.ts",{"duration":0,"failed":true}],[":tests/endpoints/agent-profiles.test.ts",{"duration":3342.858333,"failed":false}]]}
@@ -80,7 +80,8 @@ router.get('/:id/summary', async (req: Request<{ id: string }>, res: Response) =
80
80
 
81
81
  // Impact descriptions (skip zero-value limits)
82
82
  const impact: string[] = [];
83
- if (metadata.limit && metadata.limit > 0) impact.push(`Fund limit: ${metadata.limit} ETH`);
83
+ // Default fund limit line (kept for reference, intentionally disabled).
84
+ // if (metadata.limit && metadata.limit > 0) impact.push(`Fund limit: ${metadata.limit} ETH`);
84
85
  if (metadata.limits?.send && metadata.limits.send > 0) impact.push(`Send limit: ${metadata.limits.send} ETH`);
85
86
  if (metadata.limits?.swap && metadata.limits.swap > 0) impact.push(`Swap limit: ${metadata.limits.swap} ETH`);
86
87
  if (metadata.ttl) impact.push(`Token TTL: ${Math.round(metadata.ttl / 60)} minutes`);
@@ -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}"`;