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
package/README.md CHANGED
@@ -41,7 +41,7 @@ npx auramaxx get OURSECRET
41
41
 
42
42
  Agent verify prompt:
43
43
 
44
- `Use auramaxx to get the secret OURSECRET.`
44
+ `Use auramaxx skill to get OURSECRET.`
45
45
 
46
46
  ## Agent Setup
47
47
 
@@ -157,7 +157,7 @@ auramaxx get OURSECRET
157
157
 
158
158
  Then ask your agent:
159
159
 
160
- `Use auramaxx to get the secret OURSECRET.`
160
+ `Use auramaxx skill to get OURSECRET.`
161
161
 
162
162
  ---
163
163
 
package/docs/AUTH.md CHANGED
@@ -230,7 +230,7 @@ Rejected:
230
230
  | Profile | Permissions | Read Scopes | Write Scopes | Excluded Fields | TTL | Max Reads |
231
231
  |---------|------------|-------------|-------------|-----------------|-----|-----------|
232
232
  | `strict` | `secret:read` | `agent:primary, agent:agent` | none | `password, cvv, privateKey, seedPhrase, refresh_token` | 1 hour | 50 |
233
- | `dev` | `wallet:list, secret:read, secret:write, action:create, action:read, action:resolve` | `agent:*` | `agent:*` | `cvv, seedPhrase, privateKey, refresh_token` | 7 days | 500 |
233
+ | `dev` | `wallet:list, secret:read, secret:write, action:create, action:read, action:resolve` | `agent:primary, agent:agent` | `agent:primary, agent:agent` | `cvv, seedPhrase, privateKey, refresh_token` | 7 days | 500 |
234
234
  | `admin` | `admin:*` | `*` | `*` | none | 7 days | unlimited |
235
235
 
236
236
  Strict one-shot (temp) approval claims are capped to 5 minutes (`300s`).
package/docs/MCP.md CHANGED
@@ -51,6 +51,15 @@ Use this flow first. It mirrors the `WORKING_WITH_SECRETS.md` command patterns.
51
51
 
52
52
  - This returns redacted output (`"secret": "*******"`) and sets `AURA_DONTLOOK` in MCP server process scope.
53
53
 
54
+ Explicit protected field request:
55
+
56
+ ```json
57
+ {
58
+ "name": "DONTLOOK",
59
+ "field": "password"
60
+ }
61
+ ```
62
+
54
63
  Command-scoped injection (recommended):
55
64
 
56
65
  ```json
@@ -90,6 +99,7 @@ Filter by name/tag/agent:
90
99
  ```json
91
100
  {
92
101
  "name": "DONTLOOK",
102
+ "field": "password",
93
103
  "envVar": "AURA_DONTNOTE",
94
104
  "command": ["/bin/zsh", "-lc", "printenv AURA_DONTNOTE"]
95
105
  }
@@ -164,7 +174,9 @@ Diary notes use canonical note field key `content` (`value` is accepted as a leg
164
174
  Note:
165
175
  - Typed tools (`get_secret`, `put_secret`, `del_secret`, `share_secret`, `inject_secret`, `write_diary`, `approve`) use the active MCP token directly.
166
176
  - `get_secret` and `inject_secret` are redacted by default (`secret: "*******"`). Set `dangerPlaintext: true` only for break-glass local debugging.
177
+ - `dangerPlaintext` only controls output masking. It does not request additional credential fields and does not trigger approval by itself.
167
178
  - `get_secret` uses the default env var name `AURA_{SECRETNAME}`.
179
+ - `get_secret` and `inject_secret` accept optional `field`. When set, MCP sends `requestedFields` to `/credentials/:id/read` so excluded-field approvals happen only for explicitly requested protected fields.
168
180
  - Both tools accept optional `command` (array of executable + args). When omitted, they return a `whatDo` guidance block and keep scope in MCP server process.
169
181
  - Typed helpers have **built-in 403 escalation** — on permission denied they automatically return a structured `requiresHumanApproval` response. You do not need to detect 403s yourself for typed tools.
170
182
  - `auth` does not auto-poll in background. It returns explicit `approveUrl` + `pollUrl` + `claim` guidance plus typed actions (`claimAction`, `retryAction`); callers must claim explicitly via `get_token`.
package/docs/SKILLS.md CHANGED
@@ -116,7 +116,7 @@ auramaxx set OURSECRET "hello from the agent"
116
116
 
117
117
  Ask your agent:
118
118
 
119
- `Use auramaxx to get the secret OURSECRET.`
119
+ `Use auramaxx skill to get OURSECRET.`
120
120
 
121
121
  ---
122
122
 
@@ -74,6 +74,15 @@ Read:
74
74
  ```http
75
75
  POST /credentials/:id/read
76
76
  Authorization: Bearer <token>
77
+ Content-Type: application/json
78
+
79
+ {
80
+ "requestedFields": ["password"]
81
+ }
77
82
  ```
78
83
 
79
84
  Response returns encrypted payload (never plaintext secret fields for non-admin agents).
85
+
86
+ `requestedFields` is optional:
87
+ - If omitted, excluded fields are redacted/omitted and no excluded-field approval is raised.
88
+ - If present and it explicitly includes an excluded field (for example `cvv`), the route can return `DENY_EXCLUDED_FIELD` and one-shot approval metadata.
@@ -21,8 +21,8 @@ Canonical token payload shape:
21
21
  },
22
22
  "walletAccess": ["0x..."],
23
23
  "credentialAccess": {
24
- "read": ["agent:*"],
25
- "write": ["agent:*"],
24
+ "read": ["agent:primary"],
25
+ "write": ["agent:primary"],
26
26
  "excludeFields": ["cvv", "password"],
27
27
  "ttl": 3600,
28
28
  "maxReads": 500
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "auramaxx",
3
- "version": "0.0.13",
3
+ "version": "0.0.14",
4
4
  "description": "Securely share passwords, API keys and wallets with your agent.",
5
5
  "keywords": [
6
6
  "onepassword",
@@ -23,48 +23,30 @@ Always use this skill when user intent matches any of these:
23
23
  - "give me my credit card details"
24
24
  - "run this command with my <secret>"
25
25
 
26
- ## Auth Precedence
27
-
28
- CLI auth order:
29
-
30
- 1. `AURA_TOKEN` env
31
- 2. socket bootstrap
32
- 3. `/auth` fallback
33
-
34
- Notes:
35
-
36
- - No stored-session fallback in this chain.
37
- - If `--profile` / `--profile-version` are omitted, CLI resolves from `trust.localProfile` / `trust.localProfileVersion`, then seed defaults (`admin`, `v1`).
38
- - `AURA_AUTH_PROFILE` / `AURA_AGENT_PROFILE` are not used for CLI fallback profile selection.
39
-
40
26
  ## Retrieval Flow (Do This First)
41
27
 
42
28
  For login/API key/card/password requests:
43
29
 
44
- 1. List first with a scoped query.
45
- 2. Select the matching credential.
46
- 3. Then run `get` (for read) or `inject` (for command execution).
30
+ 1. Use `npx auramaxx get SECRET` first to trigger the protected read.
31
+ 2. If it returns `reqId` + `approveUrl`, send the `approveUrl` to the human.
32
+ 3. After approval, claim the request by `reqId`.
33
+ 4. Retry the original read once with `--reqId`.
47
34
 
48
35
  Examples:
49
36
 
50
37
  ```bash
51
- aura list --name facebook --json
52
- aura list --name stripe --json
53
- aura list --name visa --json
38
+ npx auramaxx get SECRET
39
+ aura auth claim <reqId> --json
40
+ npx auramaxx get SECRET --reqId <reqId>
54
41
  ```
55
42
 
56
- If ambiguous, narrow by field:
43
+ If you need to find the exact credential name first, list with a scoped query:
57
44
 
58
45
  ```bash
46
+ aura list --name facebook --json
59
47
  aura list --name facebook --field username --json
60
48
  ```
61
49
 
62
- API equivalent:
63
-
64
- ```text
65
- GET /credentials?q=facebook
66
- ```
67
-
68
50
  ## Concrete CLI Examples
69
51
 
70
52
  ```bash
@@ -102,11 +84,11 @@ aura get FACEBOOK_LOGIN --reqId <reqId>
102
84
 
103
85
  ## 403 Handling
104
86
 
105
- If response includes `reqId`:
87
+ If the denial response includes `reqId` + `approveUrl`:
106
88
 
107
- 1. Ask human to approve.
108
- 2. Claim token (`aura auth claim <reqId> --json`).
109
- 3. Retry original command with same `reqId` when required.
89
+ 1. Send the human the direct `approveUrl`.
90
+ 2. Claim with `aura auth claim <reqId> --json`.
91
+ 3. Retry the original command with `--reqId <reqId>`.
110
92
 
111
93
  If 403 has no `reqId`:
112
94
 
@@ -146,7 +146,7 @@ auramaxx get OURSECRET
146
146
 
147
147
  Then ask your agent:
148
148
 
149
- `Use auramaxx to get the secret OURSECRET.`
149
+ `Use auramaxx skill to get OURSECRET.`
150
150
 
151
151
  ---
152
152
 
@@ -47,23 +47,23 @@ type LocalPolicySettings = {
47
47
  projectScopeMode: ProjectScopeMode;
48
48
  };
49
49
 
50
- const LOCAL_POLICY_PROFILES: LocalAgentMode[] = ['strict', 'dev', 'admin'];
50
+ const LOCAL_POLICY_PROFILES: LocalAgentMode[] = ['admin', 'dev', 'strict'];
51
51
  const LOCAL_PROJECT_SCOPE_MODES: ProjectScopeMode[] = ['auto', 'strict', 'off'];
52
52
  const LOCAL_PROFILE_ITEM_OPTIONS = [
53
53
  {
54
- value: 'strict',
55
- label: 'strict',
56
- description: 'Minimal local token scope with explicit allowlists.',
54
+ value: 'admin',
55
+ label: 'maxx (admin)',
56
+ description: 'Full access. Use only when you fully trust the agent.',
57
57
  },
58
58
  {
59
59
  value: 'dev',
60
- label: 'dev',
61
- description: 'Balanced local automation with scoped defaults.',
60
+ label: 'mid (dev)',
61
+ description: 'Access to most things. Human approval for stuff like CVV.',
62
62
  },
63
63
  {
64
- value: 'admin',
65
- label: 'admin (dangerous)',
66
- description: 'Broad token scope. Use only in tightly controlled local environments.',
64
+ value: 'strict',
65
+ label: 'sus (local)',
66
+ description: 'Most locked down. Every request needs manual approval.',
67
67
  },
68
68
  ] as const;
69
69
  const LOCAL_PROJECT_SCOPE_ITEM_OPTIONS = [
@@ -3,12 +3,13 @@ import { spawn } from 'child_process';
3
3
  import { join } from 'path';
4
4
  import { mkdirSync } from 'fs';
5
5
  import { homedir } from 'os';
6
- import { buildUpdateCommand, buildUpdateFallbackCommand } from '@/server/lib/update-check';
6
+ import { buildUpdateCommand, buildUpdateFallbackCommand, buildUpdateForceCommand } from '@/server/lib/update-check';
7
7
  import { clearVersionCheckCache } from '@/server/lib/version-check-cache';
8
8
 
9
9
  export async function POST() {
10
10
  try {
11
11
  const primaryCommand = buildUpdateCommand();
12
+ const forceCommand = buildUpdateForceCommand();
12
13
  const fallbackCommand = buildUpdateFallbackCommand();
13
14
  const projectRoot = process.cwd();
14
15
  const cliEntrypoint = join(projectRoot, 'bin', 'auramaxx.js');
@@ -19,7 +20,6 @@ export async function POST() {
19
20
 
20
21
  const stopCommand = `${JSON.stringify(process.execPath)} ${JSON.stringify(cliEntrypoint)} stop`;
21
22
  const startCommand = `${JSON.stringify(process.execPath)} ${JSON.stringify(cliEntrypoint)} start`;
22
- const uninstallCommand = 'npm uninstall -g auramaxx';
23
23
 
24
24
  // Detached worker allows update to stop/restart services without
25
25
  // depending on the current dashboard process staying alive.
@@ -28,10 +28,10 @@ const { execSync } = require('child_process');
28
28
  const fs = require('fs');
29
29
  const logPath = process.env.AURA_UPDATE_LOG;
30
30
  const primaryCommand = process.env.AURA_UPDATE_PRIMARY;
31
+ const forceCommand = process.env.AURA_UPDATE_FORCE;
31
32
  const fallbackCommand = process.env.AURA_UPDATE_FALLBACK;
32
33
  const stopCommand = process.env.AURA_UPDATE_STOP;
33
34
  const startCommand = process.env.AURA_UPDATE_START;
34
- const uninstallCommand = process.env.AURA_UPDATE_UNINSTALL;
35
35
 
36
36
  function now() {
37
37
  return new Date().toISOString();
@@ -73,15 +73,14 @@ if (run(primaryCommand, { allowFailure: true })) {
73
73
  process.exit(0);
74
74
  }
75
75
 
76
- append(\`[\${now()}] primary install failed; retrying clean reinstall\`);
77
- run(uninstallCommand, { allowFailure: true });
78
- if (run(primaryCommand, { allowFailure: true })) {
76
+ append(\`[\${now()}] primary install failed; retrying forced install\`);
77
+ if (run(forceCommand, { allowFailure: true })) {
79
78
  run(startCommand, { allowFailure: true });
80
- append(\`[\${now()}] update workflow completed (clean reinstall)\`);
79
+ append(\`[\${now()}] update workflow completed (forced install)\`);
81
80
  process.exit(0);
82
81
  }
83
82
 
84
- append(\`[\${now()}] clean reinstall failed; falling back to npx start\`);
83
+ append(\`[\${now()}] forced install failed; falling back to npx start\`);
85
84
  const fallbackOk = run(fallbackCommand, { allowFailure: true });
86
85
  append(\`[\${now()}] update workflow completed (\${fallbackOk ? 'npx fallback' : 'failed'})\`);
87
86
  process.exit(fallbackOk ? 0 : 1);
@@ -93,10 +92,10 @@ process.exit(fallbackOk ? 0 : 1);
93
92
  ...process.env,
94
93
  AURA_UPDATE_LOG: logPath,
95
94
  AURA_UPDATE_PRIMARY: primaryCommand,
95
+ AURA_UPDATE_FORCE: forceCommand,
96
96
  AURA_UPDATE_FALLBACK: fallbackCommand,
97
97
  AURA_UPDATE_STOP: stopCommand,
98
98
  AURA_UPDATE_START: startCommand,
99
- AURA_UPDATE_UNINSTALL: uninstallCommand,
100
99
  },
101
100
  detached: true,
102
101
  stdio: 'ignore',
@@ -107,7 +106,7 @@ process.exit(fallbackOk ? 0 : 1);
107
106
  return NextResponse.json({
108
107
  success: true,
109
108
  deferred: true,
110
- message: 'Update workflow started: stop -> install -> start, retry uninstall/install, then npx fallback.',
109
+ message: 'Update workflow started: stop -> install -> force-install retry -> npx fallback.',
111
110
  output: `Running in background. Log: ${logPath}`,
112
111
  logPath,
113
112
  pid: worker.pid,
@@ -310,7 +310,7 @@ export default function YoPage() {
310
310
  rel="noopener noreferrer"
311
311
  className="text-[10px] text-[var(--color-text-muted,#6b7280)] hover:text-[var(--color-text,#0a0a0a)] transition-colors"
312
312
  >
313
- by @hi_im_nico, with love
313
+ 🗿 by @hi_im_nico, with love
314
314
  </a>
315
315
  </div>
316
316
  </div>
@@ -51,6 +51,30 @@ interface AuthSession {
51
51
  privateKeyPem?: string;
52
52
  }
53
53
 
54
+ function decodeAgentTokenPayload(
55
+ token: string,
56
+ ): { permissions?: unknown } | undefined {
57
+ const trimmed = token.trim();
58
+ if (!trimmed) return undefined;
59
+ const [payloadSegment] = trimmed.split('.', 1);
60
+ if (!payloadSegment) return undefined;
61
+ try {
62
+ const decoded = Buffer.from(payloadSegment, 'base64url').toString('utf8');
63
+ const parsed = JSON.parse(decoded) as unknown;
64
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return undefined;
65
+ return parsed as { permissions?: unknown };
66
+ } catch {
67
+ return undefined;
68
+ }
69
+ }
70
+
71
+ function resolveAdminPermissionFromToken(token: string): boolean | undefined {
72
+ const payload = decodeAgentTokenPayload(token);
73
+ if (!payload) return undefined;
74
+ if (!Array.isArray(payload.permissions)) return false;
75
+ return payload.permissions.some((permission) => permission === 'admin:*');
76
+ }
77
+
54
78
  async function getAuthToken(
55
79
  keypair: EphemeralKeypair,
56
80
  authSelection?: ProfileIssuanceSelection,
@@ -109,6 +133,13 @@ async function getReadToken(input: {
109
133
  authSelection?: ProfileIssuanceSelection;
110
134
  fallbackDecryptPrivateKeyPem: string;
111
135
  }): Promise<{ readToken: string; decryptPrivateKeyPem: string }> {
136
+ const hasAdminPermission = resolveAdminPermissionFromToken(input.authToken);
137
+ if (hasAdminPermission === false) {
138
+ // Non-admin session tokens cannot call /actions/token.
139
+ // Skip delegated token minting to avoid a guaranteed 403 escalation cycle.
140
+ return { readToken: input.authToken, decryptPrivateKeyPem: input.fallbackDecryptPrivateKeyPem };
141
+ }
142
+
112
143
  try {
113
144
  const readToken = await createReadToken(
114
145
  serverUrl(),
@@ -245,15 +276,26 @@ async function readCredential(
245
276
  options?: {
246
277
  retryCommandTemplate?: string;
247
278
  originalCommand?: string;
279
+ requestedFields?: string[];
248
280
  },
249
281
  ): Promise<DecryptedCredential> {
250
282
  const originalCommand = String(options?.originalCommand || '').trim();
283
+ const requestedFields = Array.from(new Set(
284
+ (options?.requestedFields || [])
285
+ .map((value) => String(value || '').trim())
286
+ .filter((value) => value.length > 0),
287
+ ));
288
+ const requestBody = requestedFields.length > 0
289
+ ? JSON.stringify({ requestedFields })
290
+ : undefined;
251
291
  const res = await fetch(`${serverUrl()}/credentials/${credentialId}/read`, {
252
292
  method: 'POST',
253
293
  headers: {
254
294
  'Authorization': `Bearer ${readToken}`,
295
+ ...(requestBody ? { 'Content-Type': 'application/json' } : {}),
255
296
  ...(originalCommand ? { 'X-Aura-Original-Command': originalCommand } : {}),
256
297
  },
298
+ ...(requestBody ? { body: requestBody } : {}),
257
299
  signal: AbortSignal.timeout(8_000),
258
300
  });
259
301
  if (!res.ok) {
@@ -1250,9 +1292,13 @@ export async function runAgentCli(args: string[]): Promise<number> {
1250
1292
  if (!readAuthContext) return 1;
1251
1293
 
1252
1294
  try {
1295
+ const requestedFields = [
1296
+ getCredentialPrimaryFieldKey(normalizeCredentialType(target.type)),
1297
+ ];
1253
1298
  const decrypted = await readCredential(target.id, readAuthContext.readToken, readAuthContext.privateKeyPem, {
1254
1299
  retryCommandTemplate,
1255
1300
  originalCommand,
1301
+ requestedFields,
1256
1302
  });
1257
1303
  const primarySecret = resolvePrimarySecretField(
1258
1304
  normalizeCredentialType(decrypted.type || target.type),
@@ -1299,11 +1345,23 @@ export async function runAgentCli(args: string[]): Promise<number> {
1299
1345
  });
1300
1346
  if (!readAuthContext) return 1;
1301
1347
 
1348
+ const resolvedTargetType = normalizeCredentialType(target.type);
1349
+ const requestedReadFields = flagJson
1350
+ ? (fieldName
1351
+ ? [canonicalizeCredentialFieldKey(resolvedTargetType, fieldName)]
1352
+ : ['*'])
1353
+ : execCommand.length > 0
1354
+ ? [getCredentialPrimaryFieldKey(resolvedTargetType)]
1355
+ : fieldName
1356
+ ? [canonicalizeCredentialFieldKey(resolvedTargetType, fieldName)]
1357
+ : [getCredentialPrimaryFieldKey(resolvedTargetType)];
1358
+
1302
1359
  let decrypted: DecryptedCredential;
1303
1360
  try {
1304
1361
  decrypted = await readCredential(target.id, readAuthContext.readToken, readAuthContext.privateKeyPem, {
1305
1362
  retryCommandTemplate,
1306
1363
  originalCommand,
1364
+ requestedFields: requestedReadFields,
1307
1365
  });
1308
1366
  } finally {
1309
1367
  finalizeReadAuthContext(readAuthContext);
@@ -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(
@@ -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}`;