Commit 9d06ee4
authored
feat(cli): machine-output mode — stream discipline, flag propagation, scrubber (#1234)
Three-layer redesign that delivers pipe-safe --json/--dry-run while
scaling to every command and child process socket-cli spawns.
Layer 1 — stream discipline (CLAUDE.md SHARED STANDARDS):
- stdout carries ONLY the data a command was asked to produce.
- stderr carries everything else: progress, spinners, status, warnings,
errors, dry-run previews, context, banners, prompts.
- Under --json/--markdown, stdout MUST parse as the declared format.
- Targeted audit of output formatters: dry-run previews, scan-report
status lines ("Writing json report to …"), coana-fix "Copying …"
message, oops dry-run preview all moved from stdout to stderr.
Layer 2 — per-(tool, subcommand) flag propagation
(utils/spawn/machine-mode.mts):
- coana: --silent + --socket-mode <tempfile>; read file.
- sfw: transparent — forward to inner PM (npm/pnpm/yarn/yarn-berry/zpm/pip).
- npm: --json + --loglevel=error on JSON-aware subcommands.
- pnpm: --reporter=json on JSON-emitting subcommands; --reporter=silent
otherwise, via a fallbackArgs rule so the two reporter flags never
collide.
- yarn classic: --json --silent.
- yarn berry: --json where supported + full YARN_ENABLE_* env quieting.
- yarn 6 / zpm: --json on supported cmds; --silent on install+add.
- vltpkg: --view=json uniformly.
- pip/pip3/uv/cargo/gem/go: per-tool quiet/json flags.
- Universal env injection: NO_COLOR, FORCE_COLOR=0, CLICOLOR_FORCE=0.
Layer 3 — output scrubber (utils/output/scrubber.mts):
- Transform stream that catches the residue from tools that don't cooperate
(synp "Created …" line, zpm ANSI leaks, gem progress dots, unknown
binaries). NDJSON-aware line classifier:
1. NUL sentinel spans (socket-cli's own output) → stdout.
2. JSON.parse succeeds → stdout.
3. Known noise patterns (log prefixes, status glyphs) → stderr.
4. Unknown → stderr (safe default).
- Uses ansiRegex() from @socketsecurity/lib/ansi for OSC+CSI stripping.
- Tracing via SOCKET_SCRUB_TRACE=1 for debugging.
- Tool-specific adapters (synp, zpm, gem) plug into the classifier
registry — small, inspectable, jc-style.
- Soft buffer cap (maxBufferChars) surfaces a one-time "exceeded cap;
scrubbing continues without fallback" warning. A hard cap with
passthrough is deliberately deferred — a child tool emitting 100 MB
without a newline is an upstream bug, and silently flushing a partial
line as payload would corrupt the stream.
Layer 4 — sentinel wrapping (utils/output/emit-payload.mts):
- emitPayload() wraps the primary payload in NUL-bracketed sentinels
(\0SOCKET_PAYLOAD_BEGIN\0 / \0SOCKET_PAYLOAD_END\0) under machine mode
so the scrubber extracts it unambiguously.
- NUL never appears in legitimate JSON/Markdown, so sentinels are
zero-ambiguity even against a cooperating child tool. Doc comments in
mode.mts and scrubber.mts explicitly call out the NUL-bracketing so
the guarantee is grounded in prose, not invisible source bytes.
Ambient mode context (utils/output/ambient-mode.mts):
- meowWithSubcommands / meowOrExit call setMachineOutputMode() once per
invocation with the parsed flags, resetting prior state so sequential
vitest cases don't leak mode.
- Spawn wrappers consult getMachineOutputMode() to decide whether to
apply flag forwarding and scrubbing.
Flag rename:
- --no-log → --quiet. Reframed description: "Route non-essential output
(status, progress, warnings) to stderr so stdout carries only the
payload. Implied by --json and --markdown."
Deletions:
- utils/output/no-log.mts + setNoLogMode/isNoLogMode module-level state.
- out() wrapper in utils/dry-run/output.mts — plain logger.error now.
Tests:
- 74 new unit tests across mode, emit-payload, scrubber, pipe-safety,
machine-mode.
- 134 existing test assertions updated to expect dry-run text on stderr
(mockLogger.error) rather than stdout (mockLogger.log).
- All 5,202 unit tests pass; type-check and lint clean.
Follow-ups tracked separately:
- Cross-repo: structured NDJSON event contract ("reason" field per
cargo's --message-format=json).
- Upstream: coana native --machine-output that routes logger to stderr;
zpm NO_COLOR respect; synp --quiet/--json flags.
- Full socket-cli-wide sweep of the remaining ~500 logger.log call sites
for stream-discipline conformance (lib-side fix to @socketsecurity/lib
will automate most of this).1 parent f479f27 commit 9d06ee4
68 files changed
Lines changed: 2188 additions & 261 deletions
File tree
- packages/cli
- src
- commands
- fix
- oops
- organization
- scan
- utils
- cli
- dlx
- dry-run
- output
- adapters
- spawn
- test/unit
- commands
- analytics
- audit-log
- config
- fix
- manifest
- npm
- npx
- oops
- optimize
- organization
- package
- pnpm
- pycli
- repository
- scan
- threat-feed
- wrapper
- yarn
- utils
- dry-run
- output
- spawn
Some content is hidden
Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
114 | 114 | | |
115 | 115 | | |
116 | 116 | | |
| 117 | + | |
117 | 118 | | |
118 | 119 | | |
119 | 120 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
99 | 99 | | |
100 | 100 | | |
101 | 101 | | |
102 | | - | |
103 | | - | |
104 | | - | |
| 102 | + | |
| 103 | + | |
| 104 | + | |
| 105 | + | |
| 106 | + | |
105 | 107 | | |
| 108 | + | |
| 109 | + | |
| 110 | + | |
| 111 | + | |
106 | 112 | | |
107 | 113 | | |
108 | 114 | | |
| |||
214 | 220 | | |
215 | 221 | | |
216 | 222 | | |
| 223 | + | |
217 | 224 | | |
218 | 225 | | |
219 | 226 | | |
| |||
254 | 261 | | |
255 | 262 | | |
256 | 263 | | |
257 | | - | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
258 | 267 | | |
259 | 268 | | |
260 | 269 | | |
| |||
427 | 436 | | |
428 | 437 | | |
429 | 438 | | |
| 439 | + | |
430 | 440 | | |
431 | 441 | | |
432 | 442 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
60 | 60 | | |
61 | 61 | | |
62 | 62 | | |
63 | | - | |
64 | | - | |
65 | | - | |
66 | | - | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
67 | 69 | | |
68 | 70 | | |
69 | | - | |
70 | | - | |
| 71 | + | |
| 72 | + | |
71 | 73 | | |
72 | | - | |
| 74 | + | |
73 | 75 | | |
74 | | - | |
| 76 | + | |
75 | 77 | | |
76 | | - | |
| 78 | + | |
77 | 79 | | |
78 | | - | |
79 | | - | |
80 | | - | |
| 80 | + | |
| 81 | + | |
| 82 | + | |
81 | 83 | | |
82 | 84 | | |
83 | 85 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | 1 | | |
2 | 2 | | |
3 | 3 | | |
| 4 | + | |
4 | 5 | | |
5 | 6 | | |
6 | 7 | | |
| |||
59 | 60 | | |
60 | 61 | | |
61 | 62 | | |
62 | | - | |
| 63 | + | |
| 64 | + | |
| 65 | + | |
63 | 66 | | |
64 | 67 | | |
65 | 68 | | |
| |||
71 | 74 | | |
72 | 75 | | |
73 | 76 | | |
74 | | - | |
75 | | - | |
76 | | - | |
77 | | - | |
78 | | - | |
| 77 | + | |
| 78 | + | |
| 79 | + | |
| 80 | + | |
79 | 81 | | |
80 | 82 | | |
81 | 83 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
111 | 111 | | |
112 | 112 | | |
113 | 113 | | |
114 | | - | |
| 114 | + | |
115 | 115 | | |
116 | 116 | | |
117 | 117 | | |
| |||
129 | 129 | | |
130 | 130 | | |
131 | 131 | | |
132 | | - | |
| 132 | + | |
133 | 133 | | |
134 | 134 | | |
135 | 135 | | |
| |||
Lines changed: 9 additions & 2 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
10 | 10 | | |
11 | 11 | | |
12 | 12 | | |
| 13 | + | |
13 | 14 | | |
14 | 15 | | |
15 | 16 | | |
| |||
173 | 174 | | |
174 | 175 | | |
175 | 176 | | |
| 177 | + | |
| 178 | + | |
| 179 | + | |
176 | 180 | | |
| 181 | + | |
177 | 182 | | |
178 | 183 | | |
179 | 184 | | |
| |||
238 | 243 | | |
239 | 244 | | |
240 | 245 | | |
241 | | - | |
| 246 | + | |
| 247 | + | |
| 248 | + | |
242 | 249 | | |
243 | 250 | | |
244 | 251 | | |
245 | 252 | | |
246 | 253 | | |
247 | | - | |
| 254 | + | |
248 | 255 | | |
249 | 256 | | |
250 | 257 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
269 | 269 | | |
270 | 270 | | |
271 | 271 | | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
272 | 278 | | |
273 | 279 | | |
274 | 280 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
44 | 48 | | |
45 | 49 | | |
46 | 50 | | |
| |||
510 | 514 | | |
511 | 515 | | |
512 | 516 | | |
| 517 | + | |
| 518 | + | |
513 | 519 | | |
| 520 | + | |
514 | 521 | | |
515 | 522 | | |
516 | 523 | | |
517 | 524 | | |
| 525 | + | |
| 526 | + | |
518 | 527 | | |
| 528 | + | |
519 | 529 | | |
520 | 530 | | |
521 | 531 | | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
522 | 541 | | |
523 | 542 | | |
524 | 543 | | |
| |||
937 | 956 | | |
938 | 957 | | |
939 | 958 | | |
| 959 | + | |
| 960 | + | |
940 | 961 | | |
| 962 | + | |
941 | 963 | | |
942 | 964 | | |
943 | 965 | | |
944 | 966 | | |
945 | 967 | | |
| 968 | + | |
| 969 | + | |
946 | 970 | | |
| 971 | + | |
947 | 972 | | |
948 | 973 | | |
949 | 974 | | |
950 | 975 | | |
| 976 | + | |
| 977 | + | |
| 978 | + | |
| 979 | + | |
| 980 | + | |
| 981 | + | |
| 982 | + | |
| 983 | + | |
| 984 | + | |
951 | 985 | | |
952 | 986 | | |
953 | 987 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
62 | 62 | | |
63 | 63 | | |
64 | 64 | | |
| 65 | + | |
| 66 | + | |
| 67 | + | |
| 68 | + | |
65 | 69 | | |
66 | 70 | | |
67 | 71 | | |
| |||
500 | 504 | | |
501 | 505 | | |
502 | 506 | | |
| 507 | + | |
| 508 | + | |
| 509 | + | |
| 510 | + | |
| 511 | + | |
| 512 | + | |
| 513 | + | |
| 514 | + | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
503 | 524 | | |
504 | 525 | | |
505 | 526 | | |
| |||
511 | 532 | | |
512 | 533 | | |
513 | 534 | | |
514 | | - | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
515 | 538 | | |
516 | 539 | | |
517 | 540 | | |
518 | 541 | | |
519 | 542 | | |
520 | 543 | | |
| 544 | + | |
521 | 545 | | |
522 | 546 | | |
523 | 547 | | |
| |||
534 | 558 | | |
535 | 559 | | |
536 | 560 | | |
537 | | - | |
538 | | - | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
| 567 | + | |
| 568 | + | |
| 569 | + | |
539 | 570 | | |
540 | 571 | | |
541 | 572 | | |
| |||
0 commit comments