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
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/CLI.md CHANGED
@@ -12,7 +12,6 @@ The most common commands. All use the `aura` alias (or `npx auramaxx`).
12
12
  | `aura get <name>` | Read a credential (`--json` for full payload) |
13
13
  | `aura set <name> <value>` | Create or update a secret |
14
14
  | `aura list` | List credential names |
15
- | `aura diary write --entry "<text>"` | Append an authenticated daily diary entry (stored as provided) |
16
15
  | `aura share <name>` | Create a shareable secret gist link |
17
16
  | `aura inject <name> [-- <cmd>]` | Save to env var and optionally run command |
18
17
  | `aura del <name>` | Delete a credential |
@@ -135,7 +134,6 @@ aura auth request --profile dev --action '{"endpoint":"/send","method":"POST","b
135
134
  aura auth claim <reqId> --json # canonical claim path; auto-retries transient pending polls (default: 3 retries, 250ms interval)
136
135
  aura auth claim <reqId> --pending-retries 8 --pending-retry-interval-ms 200 --json
137
136
  aura get OURSECRET --reqId <reqId> # strict retry path; fails with missing_or_expired_claim if claim not bound
138
- aura diary write --entry "Heartbeat: no pending requests, sync ok"
139
137
 
140
138
  # Advanced
141
139
  aura api GET /health --no-auth # Call any API endpoint
@@ -169,7 +167,6 @@ Full list visible via `aura --help --all`. Summary:
169
167
  | `mcp` | Start MCP server for Claude Code, Cursor, etc. |
170
168
  | `skill` | Install AuraMaxx skills for agents |
171
169
  | `auth` | Request/poll agent auth approvals |
172
- | `diary` | Append daily diary entries (auth-aware) |
173
170
  | `actions` | Internal: human actions and token management (use `auth` instead) |
174
171
  | `approve` | Admin-only shortcut: approve a pending action by id |
175
172
  | `api` | Call any wallet API endpoint from CLI |
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
  }
@@ -101,7 +111,7 @@ Filter by name/tag/agent:
101
111
  - `docs://auth`
102
112
  - `docs://guide`
103
113
 
104
- ## Tools (13)
114
+ ## Tools
105
115
 
106
116
  | # | Tool | Description |
107
117
  |---|------|-------------|
@@ -117,7 +127,6 @@ Filter by name/tag/agent:
117
127
  | 10 | `approve` | Admin-only shortcut: approve a pending human action by id |
118
128
  | 11 | `status` | Get server setup/unlock health state |
119
129
  | 12 | `start` | Start the AuraMaxx server in headless mode if not already running |
120
- | 13 | `write_diary` | Append an entry to a daily diary note |
121
130
 
122
131
  `api` is the generic fallback for non-sensitive endpoints; the other tools provide typed, higher-level operations.
123
132
 
@@ -150,10 +159,6 @@ python3 ~/.codex/skills/.system/skill-installer/scripts/install-skill-from-githu
150
159
  --ref <branch-or-commit>
151
160
  ```
152
161
 
153
- `write_diary` appends to `{YYYY-MM-DD}_LOGS` notes using the `daily-logs` agent when available, then `primary`.
154
- Diary appends preserve entry text as-is (no auto-inserted `HH:MM UTC` prefix).
155
- Diary notes use canonical note field key `content` (`value` is accepted as a legacy alias and normalized).
156
-
157
162
  ## Credential read flow via MCP
158
163
 
159
164
  1. Obtain token (`auth` tool, or socket bootstrap, or `AURA_TOKEN` env var)
@@ -162,9 +167,11 @@ Diary notes use canonical note field key `content` (`value` is accepted as a leg
162
167
  4. Use `command` when you need immediate command-scoped injection; omit `command` to set env var in MCP process and receive WHATDO guidance
163
168
 
164
169
  Note:
165
- - Typed tools (`get_secret`, `put_secret`, `del_secret`, `share_secret`, `inject_secret`, `write_diary`, `approve`) use the active MCP token directly.
170
+ - Typed tools (`get_secret`, `put_secret`, `del_secret`, `share_secret`, `inject_secret`, `approve`) use the active MCP token directly.
166
171
  - `get_secret` and `inject_secret` are redacted by default (`secret: "*******"`). Set `dangerPlaintext: true` only for break-glass local debugging.
172
+ - `dangerPlaintext` only controls output masking. It does not request additional credential fields and does not trigger approval by itself.
167
173
  - `get_secret` uses the default env var name `AURA_{SECRETNAME}`.
174
+ - `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
175
  - 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
176
  - 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
177
  - `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.
@@ -30,7 +30,8 @@ auramaxx get OURSECRET --field username # specific field
30
30
  auramaxx get OURSECRET --json # full credential payload
31
31
  auramaxx get OURSECRET --totp # current TOTP code only
32
32
  auramaxx get OURSECRET --agent primary # restrict match to a agent
33
- auramaxx get OURSECRET --first # pick first match if name is ambiguous
33
+ auramaxx get OURSECRET # if name is ambiguous, first match is selected by default
34
+ auramaxx get OURSECRET --first # compatibility flag (same behavior)
34
35
  auramaxx get OURSECRET --reqId <reqId> # retry with claimed one-shot approval token
35
36
  ```
36
37
 
@@ -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.15",
4
4
  "description": "Securely share passwords, API keys and wallets with your agent.",
5
5
  "keywords": [
6
6
  "onepassword",
Binary file
@@ -30,6 +30,8 @@ This runs periodically, but you can check in anytime you want.
30
30
  - If diary write fails with auth/approval issues, ask the human to open the approval link and approve, then retry once.
31
31
  - Diary note naming is `{YYYY-MM-DD}_LOGS` (UTC day).
32
32
  - Use plain facts. Lead with what changed, not a full replay.
33
+ - Tone target: productive brainrot with real signal, not corporate filler.
34
+ - Avoid dry phrasing like `No approvals are currently pending` and avoid wall-of-text replay dumps.
33
35
  - If nothing changed, say `Delta: no material change` and compress repeated runs (`unchanged xN`).
34
36
  - For pending approvals, show counts first and only short IDs unless there is new escalation.
35
37
  - Always include auth counts from `summary.authorizations` (`pending/approved/rejected`).
@@ -92,5 +94,6 @@ HEARTBEAT_VIBES: [brainrot status update] [vault status] [random aura quote] [di
92
94
 
93
95
  - `HEARTBEAT_OK: Auth: 3 pending / 1 approved / 0 rejected. Secrets: deploy-key, stripe-live. Delta: 1 new excluded-field approval request (chang/cvv). Why it matters: checkout helper is blocked waiting for approval and secret reads rose. Next move: monitor for 30m and escalate if still pending. diary entry written for 2026-02-18`
94
96
  - `HEARTBEAT_OK: Auth: 3 pending / 1 approved / 0 rejected. Secrets: none touched. Delta: no material change (unchanged x3). Why it matters: no new risk; pending queue stable at 3 excluded-field reads. Next move: keep polling and only escalate on age>30m or count increase. diary entry written for 2026-02-18`
97
+ - `HEARTBEAT_OK: aura stable rn. Auth: 0 pending / 2 approved / 21 rejected. Secrets: cred-jaoxkbxq (x2), cred-j0erpizt. Delta: no blockers, just repeated admin/excluded-field CVV denial spam. Why it matters: looks like noisy retries, not active compromise. Next move: watch for repeat burst; escalate if reject rate stays weird. diary entry written for 2026-02-28`
95
98
  - `FOLLOWUP_NEEDED: Auth: 6 pending / 1 approved / 2 rejected. Secrets: deploy-key, prod-db-pass. Delta: syncHealth strategy_runner degraded for 12m and pending approvals rose 3->6. Why it matters: execution and auth flow are both backing up. Human action needed: open dashboard and clear/deny stale approval requests, then restart runner if still degraded.`
96
99
  - `HEARTBEAT_VIBES: been auramaxxing all day no cap, vault is untouched, zero secrets needed, all chains synced and vibing; quote: we are so back. aura at all-time highs.; diary entry written for 2026-02-18`
@@ -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 = [
@@ -607,7 +607,7 @@ export default function UnlockPage() {
607
607
  setPolicySettings(saved);
608
608
  setPolicyForm(saved);
609
609
  setDangerConfirmOpen(false);
610
- setPolicySaveSuccess('Local trust policy saved. Changes apply to newly issued local tokens only.');
610
+ setPolicySaveSuccess('Local trust policy saved. Make sure you restart AuraMaxx to apply the new policy. Changes apply to newly issued local tokens only.');
611
611
  } catch (err) {
612
612
  const message = (err as Error).message || 'Failed to save policy settings';
613
613
  setDangerConfirmOpen(false);
@@ -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,
@@ -114,7 +114,8 @@ export default function ApproveActionPage() {
114
114
  const impactItems = action?.impact || [];
115
115
  const isLimitBasedRequest = impactItems.some((item) => /^(Fund|Send|Swap) limit:/i.test(item));
116
116
  const hasFundPermission = scopeItems.some((item) => item.trim().toLowerCase() === 'fund');
117
- const hideApproveUi = action?.type === 'fund' || hasFundPermission || isLimitBasedRequest;
117
+ const isAuthApproval = action?.type === 'auth';
118
+ const hideApproveUi = !isAuthApproval && (action?.type === 'fund' || hasFundPermission || isLimitBasedRequest);
118
119
  const riskLevel = (action?.risk || 'unknown').toUpperCase();
119
120
  const profileName = action?.profile;
120
121
  const isAdminProfile = profileName?.trim().toLowerCase() === 'admin';
package/src/app/page.tsx CHANGED
@@ -16,11 +16,20 @@ export const metadata: Metadata = {
16
16
  siteName: SEO_TITLE,
17
17
  title: SEO_TITLE,
18
18
  description: SEO_DESCRIPTION,
19
+ images: [
20
+ {
21
+ url: '/opengraph.webp',
22
+ width: 1512,
23
+ height: 982,
24
+ alt: SEO_TITLE,
25
+ },
26
+ ],
19
27
  },
20
28
  twitter: {
21
29
  card: 'summary_large_image',
22
30
  title: SEO_TITLE,
23
31
  description: SEO_DESCRIPTION,
32
+ images: ['/opengraph.webp'],
24
33
  },
25
34
  };
26
35
 
@@ -16,11 +16,20 @@ export const metadata: Metadata = {
16
16
  siteName: SEO_TITLE,
17
17
  title: SEO_TITLE,
18
18
  description: SEO_DESCRIPTION,
19
+ images: [
20
+ {
21
+ url: '/opengraph.webp',
22
+ width: 1512,
23
+ height: 982,
24
+ alt: SEO_TITLE,
25
+ },
26
+ ],
19
27
  },
20
28
  twitter: {
21
29
  card: 'summary_large_image',
22
30
  title: SEO_TITLE,
23
31
  description: SEO_DESCRIPTION,
32
+ images: ['/opengraph.webp'],
24
33
  },
25
34
  };
26
35
 
@@ -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>
@@ -795,7 +795,7 @@ export function SettingsDrawer({
795
795
  )}
796
796
 
797
797
  <div className="text-[9px] text-[var(--color-text-muted)] px-3 py-2">
798
- Policy changes apply to newly issued local tokens only.
798
+ Make sure you restart AuraMaxx to apply the new policy. Policy changes apply to newly issued local tokens only.
799
799
  </div>
800
800
 
801
801
  {policySaveError && <div className="text-[10px] text-[var(--color-danger)]">{policySaveError}</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) {
@@ -579,16 +621,6 @@ async function resolveCredentialTarget(
579
621
  throw new Error(`PROJECT_SCOPE_DENIED: No allowed credential found for "${name}" in agent "${options.agentName}".`);
580
622
  }
581
623
 
582
- if (agentFiltered.length > 1 && !options.first) {
583
- const lines = [`Multiple credentials match "${name}":`];
584
- for (const m of agentFiltered) {
585
- const resolvedAgent = agentNames.get(m.agentId) || m.agentId;
586
- lines.push(` - ${m.name} (${m.type}, agent: ${resolvedAgent}, id: ${m.id})`);
587
- }
588
- lines.push('Use --first to select the first match, or specify --agent.');
589
- throw new Error(lines.join('\n'));
590
- }
591
-
592
624
  return { target: agentFiltered[0], agentNames };
593
625
  }
594
626
 
@@ -630,7 +662,7 @@ function showHelp(): void {
630
662
  ' --tags <a,b,c> Comma-separated tags (set only)',
631
663
  ' --agent <v> Restrict to agent name',
632
664
  ' --json JSON output',
633
- ' --first Use first match if ambiguous',
665
+ ' --first Compatibility flag (first match is already default)',
634
666
  ' --totp Print current TOTP code only (get)',
635
667
  ' --danger-plaintext Print plaintext secret in local socket get output (unsafe)',
636
668
  ' --expires-after <v> Share expiry: 15m|1h|24h|7d|30d (default: 24h)',
@@ -1250,20 +1282,33 @@ export async function runAgentCli(args: string[]): Promise<number> {
1250
1282
  if (!readAuthContext) return 1;
1251
1283
 
1252
1284
  try {
1285
+ const resolvedType = normalizeCredentialType(target.type);
1286
+ const requestedFieldKey = fieldName
1287
+ ? canonicalizeCredentialFieldKey(resolvedType, fieldName)
1288
+ : getCredentialPrimaryFieldKey(resolvedType);
1289
+ const requestedFields = [
1290
+ requestedFieldKey,
1291
+ ];
1253
1292
  const decrypted = await readCredential(target.id, readAuthContext.readToken, readAuthContext.privateKeyPem, {
1254
1293
  retryCommandTemplate,
1255
1294
  originalCommand,
1295
+ requestedFields,
1256
1296
  });
1257
- const primarySecret = resolvePrimarySecretField(
1258
- normalizeCredentialType(decrypted.type || target.type),
1259
- decrypted.fields,
1260
- );
1261
- if (!primarySecret) {
1262
- console.error('No sensitive field found on credential.');
1297
+ const effectiveType = normalizeCredentialType(decrypted.type || target.type);
1298
+ const allFields = mergeCredentialFields(effectiveType, decrypted.fields, target.meta);
1299
+ const selectedField = fieldName
1300
+ ? findField(effectiveType, allFields, fieldName)
1301
+ : resolvePrimarySecretField(effectiveType, allFields);
1302
+ if (!selectedField) {
1303
+ if (fieldName) {
1304
+ console.error(`Field "${fieldName}" not found on credential.`);
1305
+ } else {
1306
+ console.error('No sensitive field found on credential.');
1307
+ }
1263
1308
  return 1;
1264
1309
  }
1265
1310
 
1266
- return await runSecretExec(execCommand, envVarName, primarySecret.value);
1311
+ return await runSecretExec(execCommand, envVarName, selectedField.value);
1267
1312
  } finally {
1268
1313
  finalizeReadAuthContext(readAuthContext);
1269
1314
  }
@@ -1299,11 +1344,23 @@ export async function runAgentCli(args: string[]): Promise<number> {
1299
1344
  });
1300
1345
  if (!readAuthContext) return 1;
1301
1346
 
1347
+ const resolvedTargetType = normalizeCredentialType(target.type);
1348
+ const requestedReadFields = flagJson
1349
+ ? (fieldName
1350
+ ? [canonicalizeCredentialFieldKey(resolvedTargetType, fieldName)]
1351
+ : ['*'])
1352
+ : execCommand.length > 0
1353
+ ? [getCredentialPrimaryFieldKey(resolvedTargetType)]
1354
+ : fieldName
1355
+ ? [canonicalizeCredentialFieldKey(resolvedTargetType, fieldName)]
1356
+ : [getCredentialPrimaryFieldKey(resolvedTargetType)];
1357
+
1302
1358
  let decrypted: DecryptedCredential;
1303
1359
  try {
1304
1360
  decrypted = await readCredential(target.id, readAuthContext.readToken, readAuthContext.privateKeyPem, {
1305
1361
  retryCommandTemplate,
1306
1362
  originalCommand,
1363
+ requestedFields: requestedReadFields,
1307
1364
  });
1308
1365
  } finally {
1309
1366
  finalizeReadAuthContext(readAuthContext);