#30 (pull #67) gave src/tty.ts a full write door onto registerApp, rotateAppKey and revokeApp — register, rotate, revoke, all from the terminal. Neither the page (src/routes.ts, src/page.ts) nor the JSON API (src/routes.ts) reaches any of the three; README.md's "An app's identity" section says so plainly. AGENTS.md's shape is "one implementation, many doors" and "what a person can do on the page they can do here [the terminal], and nothing more" — right now the terminal does more than the page, which inverts that rule.
Done looks like
[ ] A page under admin-only view (or a section of /) lists apps (listApps), with forms or controls that call registerApp, rotateAppKey and revokeApp the same way the terminal's two-field prompt does, refusing a non-admin exactly as the action already does.
[ ] POST /api/apps, POST /api/apps/:id/rotate, POST /api/apps/:id/revoke (or equivalent) in src/routes.ts, same status-mapping convention as the rest of the JSON API (answer(...)), covered in the adoption kit if apps are meant to self-serve a key (they are not — this is admin-only).
[ ] A freshly issued key shown once, the same KEY_SHOWN_ONCE sentence src/actions.ts now exports for the terminal, so the page and the terminal say the identical sentence.
[ ] README's "An app's identity" section stops saying no route or page reaches these actions.
Risks: copy the terminal's once-only key handling carefully — a page that puts the key in a redirect target, a flash cookie or server-rendered state that survives a refresh repeats a secret that should not survive one.
#30 (pull #67) gave
src/tty.tsa full write door ontoregisterApp,rotateAppKeyandrevokeApp— register, rotate, revoke, all from the terminal. Neither the page (src/routes.ts,src/page.ts) nor the JSON API (src/routes.ts) reaches any of the three;README.md's "An app's identity" section says so plainly.AGENTS.md's shape is "one implementation, many doors" and "what a person can do on the page they can do here [the terminal], and nothing more" — right now the terminal does more than the page, which inverts that rule.Done looks like
/) lists apps (listApps), with forms or controls that callregisterApp,rotateAppKeyandrevokeAppthe same way the terminal's two-field prompt does, refusing a non-admin exactly as the action already does.POST /api/apps,POST /api/apps/:id/rotate,POST /api/apps/:id/revoke(or equivalent) insrc/routes.ts, same status-mapping convention as the rest of the JSON API (answer(...)), covered in the adoption kit if apps are meant to self-serve a key (they are not — this is admin-only).KEY_SHOWN_ONCEsentencesrc/actions.tsnow exports for the terminal, so the page and the terminal say the identical sentence.Files:
src/routes.ts,src/page.ts,src/routes.test.ts(or wherever route tests live),README.md.Risks: copy the terminal's once-only key handling carefully — a page that puts the key in a redirect target, a flash cookie or server-rendered state that survives a refresh repeats a secret that should not survive one.