Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: secrets.mjs — view config.json credentials status on device

Shows handle, AC token, Claude creds, WiFi saved networks, boot device,
and version. Values hidden by default, press enter to reveal/hide.
Helps diagnose what's baked into the USB vs what's missing.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+208
+1
fedac/native/pieces/list.mjs
··· 13 13 const TOOLS = [ 14 14 { name: "os", desc: "system updates (OTA)" }, 15 15 { name: "samples", desc: "sample library" }, 16 + { name: "secrets", desc: "config & credentials" }, 16 17 { name: "wifi", desc: "network picker" }, 17 18 { name: "code", desc: "AI assistant (Claude)" }, 18 19 { name: "terminal", desc: "shell (PTY)" },
+207
fedac/native/pieces/secrets.mjs
··· 1 + // secrets.mjs — Show config.json secrets status on AC Native 2 + // Values hidden by default, tap/enter on a row to reveal, tap again to hide. 3 + // Jumped to from prompt via "secrets" command. 4 + 5 + let items = []; // { key, status, value, revealed } 6 + let selectedIdx = 0; 7 + let frame = 0; 8 + let storageDevice = ""; 9 + 10 + function boot({ system }) { 11 + storageDevice = system?.bootDevice || "?"; 12 + items = []; 13 + 14 + // Read config.json 15 + const raw = system?.readFile?.("/mnt/config.json"); 16 + let cfg = {}; 17 + if (raw) { 18 + try { cfg = JSON.parse(raw); } catch {} 19 + } 20 + 21 + // Handle 22 + items.push({ 23 + key: "handle", 24 + status: cfg.handle ? "set" : "missing", 25 + value: cfg.handle ? "@" + cfg.handle : "", 26 + revealed: true, // always show handle 27 + }); 28 + 29 + // AC token 30 + items.push({ 31 + key: "ac token", 32 + status: cfg.token ? "set (" + cfg.token.length + " chars)" : "missing", 33 + value: cfg.token || "", 34 + revealed: false, 35 + }); 36 + 37 + // User sub 38 + items.push({ 39 + key: "user sub", 40 + status: cfg.sub ? "set" : "missing", 41 + value: cfg.sub || "", 42 + revealed: false, 43 + }); 44 + 45 + // Email 46 + items.push({ 47 + key: "email", 48 + status: cfg.email ? "set" : "missing", 49 + value: cfg.email || "", 50 + revealed: false, 51 + }); 52 + 53 + // Claude credentials 54 + const cc = cfg.claudeCreds; 55 + if (cc) { 56 + const tokenPreview = cc.claudeAiOauth?.accessToken ? "token:" + cc.claudeAiOauth.accessToken.length + "chars" : "no token"; 57 + items.push({ 58 + key: "claude creds", 59 + status: "set (" + tokenPreview + ")", 60 + value: JSON.stringify(cc).slice(0, 200), 61 + revealed: false, 62 + }); 63 + } else { 64 + items.push({ key: "claude creds", status: "missing", value: "", revealed: false }); 65 + } 66 + 67 + // Claude state 68 + items.push({ 69 + key: "claude state", 70 + status: cfg.claudeState ? "set" : "missing", 71 + value: cfg.claudeState ? JSON.stringify(cfg.claudeState).slice(0, 200) : "", 72 + revealed: false, 73 + }); 74 + 75 + // WiFi saved creds 76 + const wifiRaw = system?.readFile?.("/mnt/wifi_creds.json"); 77 + if (wifiRaw) { 78 + try { 79 + const nets = JSON.parse(wifiRaw); 80 + const ssids = nets.map(n => n.ssid).join(", "); 81 + items.push({ 82 + key: "wifi creds", 83 + status: nets.length + " networks", 84 + value: ssids, 85 + revealed: false, 86 + }); 87 + } catch { 88 + items.push({ key: "wifi creds", status: "parse error", value: wifiRaw.slice(0, 100), revealed: false }); 89 + } 90 + } else { 91 + items.push({ key: "wifi creds", status: "no file", value: "", revealed: false }); 92 + } 93 + 94 + // Piece 95 + items.push({ 96 + key: "default piece", 97 + status: cfg.piece || "notepat", 98 + value: cfg.piece || "notepat", 99 + revealed: true, 100 + }); 101 + 102 + // Boot device 103 + items.push({ 104 + key: "boot device", 105 + status: storageDevice, 106 + value: storageDevice, 107 + revealed: true, 108 + }); 109 + 110 + // Version 111 + items.push({ 112 + key: "version", 113 + status: system?.version || "unknown", 114 + value: system?.version || "unknown", 115 + revealed: true, 116 + }); 117 + } 118 + 119 + function act({ event: e, sound, system }) { 120 + if (!e.is("keyboard:down")) return; 121 + 122 + if (e.is("keyboard:down:escape") || e.is("keyboard:down:backspace")) { 123 + system?.jump?.("prompt"); 124 + return; 125 + } 126 + 127 + if (e.is("keyboard:down:arrowdown") || e.is("keyboard:down:tab")) { 128 + selectedIdx = (selectedIdx + 1) % Math.max(1, items.length); 129 + sound?.synth({ type: "sine", tone: 440, duration: 0.03, volume: 0.08, attack: 0.002, decay: 0.025 }); 130 + return; 131 + } 132 + if (e.is("keyboard:down:arrowup")) { 133 + selectedIdx = (selectedIdx - 1 + items.length) % Math.max(1, items.length); 134 + sound?.synth({ type: "sine", tone: 440, duration: 0.03, volume: 0.08, attack: 0.002, decay: 0.025 }); 135 + return; 136 + } 137 + 138 + // Toggle reveal 139 + if (e.is("keyboard:down:enter") || e.is("keyboard:down:return") || e.is("keyboard:down:space")) { 140 + if (items[selectedIdx]) { 141 + items[selectedIdx].revealed = !items[selectedIdx].revealed; 142 + sound?.synth({ type: "sine", tone: items[selectedIdx].revealed ? 523 : 392, duration: 0.04, volume: 0.08, attack: 0.002, decay: 0.03 }); 143 + } 144 + return; 145 + } 146 + } 147 + 148 + function paint({ wipe, ink, box, write, screen }) { 149 + frame++; 150 + const T = __theme.update(); 151 + const w = screen.width, h = screen.height; 152 + const pad = 10; 153 + const font = "font_1"; 154 + 155 + wipe(T.bg[0], T.bg[1], T.bg[2]); 156 + 157 + ink(T.fg, T.fg + 10, T.fg); 158 + write("secrets", { x: pad, y: 10, size: 2, font: "matrix" }); 159 + 160 + ink(T.fgMute, T.fgMute, T.fgMute + 10); 161 + write(storageDevice + " /mnt/config.json", { x: pad, y: 34, size: 1, font }); 162 + 163 + const listY = 50; 164 + const rowH = 22; 165 + 166 + for (let i = 0; i < items.length; i++) { 167 + const item = items[i]; 168 + const ry = listY + i * rowH; 169 + const selected = i === selectedIdx; 170 + 171 + if (ry > h - 20) break; 172 + 173 + // Selection highlight 174 + if (selected) { 175 + ink(30, 45, 55); 176 + box(pad - 2, ry - 2, w - pad * 2 + 4, rowH - 2, true); 177 + } 178 + 179 + // Key name 180 + ink(selected ? 200 : 120, selected ? 200 : 120, selected ? 220 : 140); 181 + write(item.key, { x: pad, y: ry, size: 1, font }); 182 + 183 + // Status (always visible) 184 + const statusColor = item.status.startsWith("missing") || item.status.startsWith("no ") 185 + ? [200, 80, 80] : [80, 180, 100]; 186 + ink(...statusColor); 187 + write(item.status, { x: pad + 90, y: ry, size: 1, font }); 188 + 189 + // Value (only if revealed and has content) 190 + if (item.revealed && item.value) { 191 + ink(160, 160, 120); 192 + const maxChars = Math.floor((w - pad * 2 - 90) / 6); 193 + write(item.value.slice(0, maxChars), { x: pad + 4, y: ry + 10, size: 1, font }); 194 + } else if (!item.revealed && item.value) { 195 + ink(60, 60, 70); 196 + write("enter to reveal", { x: pad + 90, y: ry + 10, size: 1, font }); 197 + } 198 + } 199 + 200 + // Bottom 201 + ink(T.fgMute, T.fgMute + 10, T.fgMute); 202 + write("arrows: select enter: reveal/hide esc: back", { x: pad, y: h - 12, size: 1, font }); 203 + } 204 + 205 + function sim() {} 206 + 207 + export { boot, paint, act, sim };