[Plugins] Readable, viewport-safe HITL approval prompt (compact args + spill file)#6
Open
swarup-padhi-glean wants to merge 10 commits into
Open
[Plugins] Readable, viewport-safe HITL approval prompt (compact args + spill file)#6swarup-padhi-glean wants to merge 10 commits into
swarup-padhi-glean wants to merge 10 commits into
Conversation
The approval prompt ran the whole arguments object through JSON.stringify(_, null, 2), which escapes every newline inside a string value. A Markdown body or table therefore collapsed into one unreadable line of literal "\n". Render each top-level arg by shape instead: scalars inline, long/multi-line strings as a de-escaped block with real newlines, nested values as compact JSON — joined by a blank line so a multi-line value cannot blur into the next key. Values past a 2 KB cap are truncated with a nudge to pass large content via file_args. Stays plain text (no Markdown rendering on the elicitation surface) and only affects the Claude Code / Codex message; Cursor keeps its one-liner. formatArguments is now exported and unit-tested.
swarup-padhi-glean
added a commit
that referenced
this pull request
Jun 19, 2026
Sync onto current main (0.2.24): accept removal of packages/codex (codex dist mirror dropped on main), keep both #6 formatArguments and main's updated Cursor approval message in buildApprovalMessage, resolve the 3 plugin manifests to glean-vnext v0.2.26, rebuild dist.
Sync onto current main (0.2.24): accept removal of packages/codex (codex dist mirror dropped on main), keep both #6 formatArguments and main's updated Cursor approval message in buildApprovalMessage, resolve the 3 plugin manifests to glean-vnext v0.2.26, rebuild dist.
5e62e11 to
45d61e2
Compare
The block pretty-print could grow tall enough that Claude Code pushed the Accept/Decline buttons out of view. Now the inline prompt shows at most a few one-line-per-argument entries (multi-line/long values collapsed and truncated, never expanded). Whenever anything is truncated or an argument is omitted, the full arguments are written to a Markdown file under the OS temp dir (rendered nicely: string values verbatim so Markdown like tables renders, nested values as JSON), and the prompt shows the path. Keeps the elicitation block within ~7 lines so the approval buttons stay visible. Cursor's one-line prompt is unchanged.
… styling Feedback from live testing: - Raise per-argument inline width 80 -> 120 chars (ellipsis was appearing too early). - Allow up to 8 argument-section lines (7 args + 1 file-path line when spilling) instead of 4. - Write the spill file to a single fixed path under PLUGIN_DATA_DIR (CLAUDE_PLUGIN_DATA, via start.sh), overwritten each approval, instead of a unique file under the OS temp dir. - Distinguish structure from values in plain text: UPPERCASE keys and indent the argument lines under the Arguments: label.
Sync onto main after #13 (promote remote tools + all-manifest version check). Resolve the 3 manifests to 0.2.26 (above main's 0.2.25); rebuild dist so it carries both the promoted tools and the approval formatting.
eshwar-sundar-glean
approved these changes
Jun 19, 2026
| "enabledPlugins": { | ||
| "glean-vnext@glean-plugins-vnext": true | ||
| } | ||
| "enabledPlugins": {} |
Collaborator
There was a problem hiding this comment.
Why? We should probably add extraKnownMarketplaces if you are seeing an issue with this
| // Per-argument inline width before truncating with an ellipsis. | ||
| const maxApprovalArgChars = 120; | ||
|
|
||
| function safeJson(value: unknown): string { |
Collaborator
There was a problem hiding this comment.
#suggest
add a utils file and move all the utils there
| } | ||
| } | ||
|
|
||
| function isEmptyArgs(args: unknown): boolean { |
Collaborator
There was a problem hiding this comment.
same as above, utils file
| } else if (value !== null && typeof value === "object") { | ||
| const json = safeJson(value); | ||
| if (json.length > maxApprovalArgChars) { | ||
| rendered = `${json.slice(0, maxApprovalArgChars)}…`; |
Collaborator
There was a problem hiding this comment.
maybe suffix with (truncated)?
| ...lines.map((line) => ` ${line}`), | ||
| ]; | ||
| if (needsFile) { | ||
| const filePath = await writeApprovalArgsFile(toolName, args); |
Collaborator
There was a problem hiding this comment.
#blocking
Do test this out.
We should try to run this in /sandbox mode in claude, we are writing files outside project dir
…ings revert - Move the approval-argument formatting helpers into a dedicated src/tools/approval-args.ts (Eshwar: extract utils). - Suffix truncated inline values with (truncated) (Eshwar). - Wrap the spill-file write in try/catch so a blocked write (e.g. Claude /sandbox restricting writes outside the project dir) degrades to a note instead of breaking the approval gate (Eshwar #blocking — also to be verified live in /sandbox). - Revert the stray .claude/settings.json enabledPlugins emptying back to main (Eshwar).
…itation-args Resolve the rebuilt-dist conflict by rebuilding from merged source (keeps both #14's loopback auth and the approval formatting); bump manifests to 0.2.27 (above main's 0.2.26).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



Problem
When
ENABLE_HITLis on,run_toolshows arequires_approvalaction's arguments in anelicitInputprompt. Two issues with the original rendering:JSON.stringify(args, null, 2), which escapes newlines inside string values, so a Markdown body/table collapsed into one line of literal\n.Fix
The inline approval message is now compact and line-capped so the buttons always stay visible, with full detail spilled to a file when needed.
Inline message (Claude Code / Codex):
Arguments:— distinguishes structure from values in plain text (the elicitation surface can't style fonts).(truncated); nested objects shown as compact JSON.Spill file (only when something is truncated or omitted):
PLUGIN_DATA_DIR), overwritten on each approval; the prompt shows the path.Cursor keeps its one-line prompt (it shows tool + args in its own UI).
Example inline prompt (fabricated values):
Scope & non-goals
file_args, which keeps huge inputs out ofargumentsentirely.Code
src/tools/approval-args.ts(buildCompactArgs,formatArgumentsForFile,writeApprovalArgsFile);run-tool.tsbuilds the message and gates the file write.Tests
(truncated), nested compaction, line-budget cap) and the file formatter; the HITL handler test asserts the prompt stays within the line budget and the spill file holds the full content. Build + typecheck + tests all green.Verification
/sandboxmode: the full-args file writes successfully to the plugin's managed data dir (the same location the plugin already uses for its own state), so the sandbox permits it; the try/catch covers the edge case where a write is blocked.