One approval for app and agent; /api/v2 files and show; app_api 2

- The app's device login asks for `app models` and, where discovery says
  login.device.agent_scope, `agent_scope=models memory link` in the same
  approval. The agent's token goes to the bundled CLI on stdin
  (`lembas login --token-stdin --server <url> --json`) and is never kept
  here; if the CLI does not take it, it is given up on the server. A
  computer linked already keeps its link; a server without agent_scope
  gets the old two steps.
- The server pane reads GET /api/v2/files and /files/content (mounts open
  like folders; `withheld` shown in the server's words). The "not offered
  yet" state is gone.
- A show card's file comes from GET /api/v2/chats/{chat}/show?node=&version=
  or ?shown= as plain text (new `api_text` command, 1 MB cap); args.path is
  read only for agent chats on this computer, locally.
- The gate is link protocol 3 plus app_api 2 (APP_API = 2), not the
  server's version number, which says 1.7.2 on dev until its first beta.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
HomerandClaude Opus 5.5 committed 2026-11-03 14:48:00 +00:00
1 parent b82d4c688a
commit ab0c1434c4
9 files changed
+383 -164

No files matched your search

+15 -10
View File
@@ -47,9 +47,22 @@ export function closeViewer() {
onChange(false)
}
/**
* Why a file has no text, in words: this computer's `withheld` is "binary" | "too_big"; the
* server's is { reason: "not_text" | "too_large", message } with the message in the person's
* language already.
*/
function withheldWords(withheld, size) {
if (typeof withheld === "object" && withheld.message) return String(withheld.message)
const reason = typeof withheld === "object" ? withheld.reason : withheld
return reason === "too_big" || reason === "too_large"
? t("This file is too big to show here (%(size)s).", { size: bytes(size) })
: t("This is not a text file; it cannot be shown here.")
}
/**
* Show a file. `file`: { name, path, where (words for its place), text, kind?, language?, line?,
* withheld?: "binary" | "too_big", size?, error? }.
* withheld? (see withheldWords), size?, error? }.
*/
export async function openViewer(file) {
teardown()
@@ -68,15 +81,7 @@ export async function openViewer(file) {
return
}
if (file.withheld) {
body.append(
h("p", {
class: "viewer__note",
text:
file.withheld === "too_big"
? t("This file is too big to show here (%(size)s).", { size: bytes(file.size) })
: t("This is not a text file; it cannot be shown here."),
}),
)
body.append(h("p", { class: "viewer__note", text: withheldWords(file.withheld, file.size) }))
return
}
const text = file.text ?? ""