@zgeoff/atc 2.26.6 → 2.26.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zgeoff/atc",
3
- "version": "2.26.6",
3
+ "version": "2.26.7",
4
4
  "description": "Terminal control tower for coding-agent sessions",
5
5
  "homepage": "https://github.com/zgeoff/atc#readme",
6
6
  "bugs": "https://github.com/zgeoff/atc/issues",
@@ -1,5 +1,7 @@
1
1
  import { DaemonError } from '../protocol/daemon-error';
2
2
  import { isRecord } from '../shared/report';
3
+ import { sanitizeDetail } from '../shared/sanitize-detail';
4
+ import { truncateSummary } from '../shared/truncate-summary';
3
5
  import type {
4
6
  HarnessAttachment,
5
7
  HarnessExit,
@@ -925,10 +927,29 @@ function collectColdBoots(value: unknown): { readonly bootId: unknown; readonly
925
927
  }));
926
928
  }
927
929
 
930
+ // A refusal's message as detail a session list row can hold: credentials
931
+ // redacted while line breaks still bound a header's value, then control
932
+ // characters taken out so the text cannot redraw the row, and whitespace
933
+ // flattened to one line.
934
+ function buildSafeDetail(message: string): string {
935
+ return sanitizeDetail(message)
936
+ .replaceAll(/[\p{Cc}\p{Cf}]/gu, ' ')
937
+ .replaceAll(/\s+/gu, ' ')
938
+ .trim();
939
+ }
940
+
928
941
  // An end other than an exit, as a session's last message.
929
942
  function formatOutcome(outcome: Exclude<ImpSessionOutcome, { kind: 'exit' }>): string {
930
943
  if (outcome.kind === 'failed') {
931
- return `imp refused the session (${outcome.code ?? 'error'})`;
944
+ const code = outcome.code ?? 'error';
945
+ const detail = buildSafeDetail(outcome.message);
946
+
947
+ const line =
948
+ detail === ''
949
+ ? `imp refused the session (${code})`
950
+ : `imp refused the session (${code}): ${detail}`;
951
+
952
+ return truncateSummary(line);
932
953
  }
933
954
 
934
955
  if (outcome.kind === 'detached') {
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Replaces credential-shaped text with `[redacted]`, whatever its length:
3
+ * URL userinfo, whole authorization header values, values of secret-named
4
+ * parameters and headers — quoted values included, whole — and long
5
+ * token-like runs. Ordinary words pass through.
6
+ */
7
+ export function sanitizeDetail(text: string): string {
8
+ return text
9
+ .replaceAll(/(?<scheme>[a-z][a-z0-9+.-]*:\/\/)[^/@\s]+@/giu, '$<scheme>[redacted]@')
10
+ .replaceAll(
11
+ /(?<name>["']?authorization["']?\s*:\s*)(?:"(?:[^"\\]|\\.)*"|[^\n]*)/giu,
12
+ '$<name>[redacted]',
13
+ )
14
+ .replaceAll(
15
+ /(?<name>["']?[a-z0-9_.-]*(?:key|token|secret|password|passwd|credential|signature)[a-z0-9_.-]*["']?\s*[:=]\s*)(?:"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|[^\s;,;&"']+)/giu,
16
+ '$<name>[redacted]',
17
+ )
18
+ .replaceAll(/\b(?<scheme>bearer|basic)\s+[a-z0-9+/=._-]+/giu, '$<scheme> [redacted]')
19
+ .replaceAll(/[a-z0-9+/_=-]{32,}/giu, '[redacted]');
20
+ }