merge origin/main (cross-store text checker); macOS platform pitfall renumbered to 79

This commit is contained in:
CRTkafa 2026-10-20 03:06:16 +07:00
commit 9db7180eb9
35 changed files with 618 additions and 60 deletions

View file

@ -86,6 +86,9 @@ export type Decision =
| { action: 'dry'; why: string }
| { action: 'refuse'; why: string };
/** --yes without a terminal: refused loudly (exit 1, stderr), never a silent dry run (pitfall 77). */
export const NOT_A_TTY = 'refused: writes through `storebound api` need an interactive terminal (stdout is not a TTY: piped or redirected). Nothing was sent. Run it without a pipe or redirect, or use the dedicated storebound command.';
/** What to do with one call. Pure. */
export function decide(g: GateInput): Decision {
if (g.getOnly && g.method.toUpperCase() !== 'GET') return { action: 'refuse', why: 'api get runs GET operations only' };
@ -94,7 +97,7 @@ export function decide(g: GateInput): Decision {
? 'owner-only operation: never through MCP or the desktop app; the owner runs it in a terminal'
: 'writes through `storebound api` are not available to MCP or the desktop app; run it in a terminal' };
if (g.dry || !g.yes) return { action: 'dry', why: g.dry ? '--dry' : 'writes are dry by default: add --yes (in a terminal) to send' };
if (!g.tty) return { action: 'dry', why: 'not an interactive terminal: by design, writes through `storebound api` are sent only from an interactive terminal (--yes alone is not enough)' };
if (!g.tty) return { action: 'refuse', why: NOT_A_TTY };
return g.kind === 'owner' ? { action: 'confirm', typed: true } : { action: 'send' };
}