@adrrr/tarmac 0.9.0 → 0.10.0

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/dist/schema.js CHANGED
@@ -63,10 +63,19 @@ export function guardVersions(seen) {
63
63
  const state = noVersion > 0 ? 'no-version' : unchecked.length > 0 ? 'unchecked' : 'ok';
64
64
  return { state, versions, noVersion, unchecked };
65
65
  }
66
- /** What a human should be told, or `null` when there is nothing worth saying. */
66
+ /** What a human should be told, in the halves a page shows it in. `null` when there is nothing. */
67
+ export function schemaNoteParts(guard) {
68
+ const said = schemaSaid(guard);
69
+ return said.length === 0 ? null : { key: 'schema', lead: said[0], rest: said.slice(1).join(' ') };
70
+ }
71
+ /** The same notice, whole. What every caller outside the page still asks for. */
67
72
  export function schemaNotice(guard) {
73
+ const parts = schemaNoteParts(guard);
74
+ return parts === null ? null : `${parts.lead} ${parts.rest}`.trim();
75
+ }
76
+ function schemaSaid(guard) {
68
77
  if (guard.state === 'ok' || guard.state === 'nothing')
69
- return null;
78
+ return [];
70
79
  const said = [];
71
80
  if (guard.noVersion > 0) {
72
81
  const total = guard.noVersion + guard.versions.length;
@@ -83,5 +92,5 @@ export function schemaNotice(guard) {
83
92
  // and has no scripts/ directory. Capturing a fixture is a maintainer's move, documented
84
93
  // in the README, not something to send a user looking for.
85
94
  said.push(`Nothing is blocked and no reading is hidden; if a column starts coming up empty, update tarmac or report it at ${ISSUES_URL}.`);
86
- return said.join(' ');
95
+ return said;
87
96
  }
package/dist/sessions.js CHANGED
@@ -36,6 +36,31 @@ const KNOWN_STATUS = new Map([
36
36
  const WAITING = 'waiting';
37
37
  /** Whether this reading is halted on a human. The one status the renderers treat as a state. */
38
38
  export const isWaiting = (s) => s.status === WAITING;
39
+ /**
40
+ * The kind a terminal calls itself, and the anchor the two rules below reason from. A
41
+ * background entry has since been seen beside them — `kind: 'background'`, no `pid`, its word
42
+ * under `state` rather than `status` — so the two are no longer a reading of that CLI's help.
43
+ * It is still the anchor and never the list: one observed alternative is not the vocabulary,
44
+ * and the question asked is only whether anything on this machine still calls itself
45
+ * `interactive`.
46
+ */
47
+ export const INTERACTIVE = 'interactive';
48
+ /**
49
+ * Whether this fleet still speaks the kind we know. If NOTHING calls itself `interactive`, the
50
+ * word moved rather than every terminal on the machine going background at once — and the
51
+ * readers say so by treating them all as what they almost certainly still are. Same tolerance
52
+ * `buildFleet` already applies to telemetry: a signal true of every row is a change in the
53
+ * source.
54
+ */
55
+ export const anchoredOnKind = (rows) => rows.some((r) => r.kind === INTERACTIVE);
56
+ /**
57
+ * A background entry, under the anchor above. An ABSENT kind is not evidence of one: the same
58
+ * rule the status follows, where unrecognised means unknown, never "the quiet one". The two
59
+ * mistakes are not the same size — an agent read as a terminal is a row expecting a frame that
60
+ * will not come, while a terminal read as an agent is someone's open session dropped out of
61
+ * every count that is about them.
62
+ */
63
+ export const isBackgroundAgent = (r, anchored) => anchored && r.kind !== null && r.kind !== INTERACTIVE;
39
64
  /** @param text raw stdout of `claude agents --json` */
40
65
  export function parseAgents(text) {
41
66
  let raw;
package/dist/wrapper.js CHANGED
@@ -157,15 +157,20 @@ esac
157
157
  # --- drop the snapshot (best effort, atomic: temp file + rename in the same dir) ---
158
158
  if [ -n "$sid" ] && mkdir -p "$TARMAC_DIR" 2>/dev/null; then
159
159
  tmp="$TARMAC_DIR/${TEMP_PREFIX}$sid.$$.tmp"
160
- # \`2>/dev/null\` comes FIRST, and the order is the whole point: redirections are applied
161
- # left to right, so \`> "$tmp" 2>/dev/null\` opens the temp file while stderr is STILL the
162
- # user's terminal the shell prints its own \`cannot create …: Permission denied\` there,
163
- # and the \`2>\` that was meant to swallow it only takes effect afterwards. On a snapshot
164
- # directory that has become read-only that is one line of noise per FRAME, on the terminal
165
- # of a script whose first rule is to be invisible. Exit code and display are untouched
166
- # (\`printf\` is a regular built-in, so a failed redirection only fails the command), which
167
- # is exactly why nothing but stderr itself catches this. RULE 1.
168
- if printf '%s\\n' "$payload" 2>/dev/null > "$tmp"; then
160
+ # The \`2>/dev/null\` is on the GROUP, and that placement is the whole point: a redirection
161
+ # that cannot be performed is reported by the shell itself, not by \`printf\`, so it has to
162
+ # be silenced by something already in force when the failing redirection is attempted. On
163
+ # the simple command it is not \`> "$tmp" 2>/dev/null\` opens the temp file while stderr is
164
+ # STILL the user's terminal, and even \`2>/dev/null > "$tmp"\`, which reads as the fix and
165
+ # was one under every POSIX sh, leaves zsh printing \`permission denied\` on the terminal.
166
+ # The group is entered first, so its stderr is /dev/null before the command inside it is
167
+ # attempted, and that holds under every shell here. On a snapshot directory that has become
168
+ # read-only the difference is one line of noise per FRAME, on the terminal of a script whose
169
+ # first rule is to be invisible. Exit code and display are untouched either way (\`printf\` is
170
+ # a regular built-in, so a failed redirection only fails the command, and a group carries
171
+ # the status of what it ran), which is exactly why nothing but stderr itself catches this.
172
+ # RULE 1.
173
+ if { printf '%s\\n' "$payload" > "$tmp"; } 2>/dev/null; then
169
174
  mv -f "$tmp" "$TARMAC_DIR/$sid.json" 2>/dev/null || rm -f "$tmp" 2>/dev/null
170
175
  else
171
176
  rm -f "$tmp" 2>/dev/null
@@ -293,7 +298,19 @@ else
293
298
  case "$rest" in
294
299
  *'"'*)
295
300
  rest=\${rest#*'"'}
296
- printf '%s\\n' "\${rest%%'"'*}"
301
+ # Cut first, print second, and the two lines are not one on purpose. Spelled
302
+ # \`printf '%s\\n' "\${rest%%'"'*}"\` — a quoted pattern inside a quoted expansion —
303
+ # zsh reads the inner \`'\` as a literal character rather than as quoting, and the
304
+ # script ends on an unmatched \`"\`: a parse error, so nothing runs and the status
305
+ # line is blank. No POSIX sh does that, and no distribution ships zsh as
306
+ # \`/bin/sh\`, but linking it there is one command and this file's promise is that
307
+ # the wrapper runs wherever it is pointed. Dropping the outer quotes is the other
308
+ # way to make it parse, and it is wrong: unquoted, \`Fable 5\` reaches \`printf\` as
309
+ # two arguments and prints on two lines, and a \`*\` in a display name is expanded
310
+ # against the working directory. An assignment splits nothing and globs nothing,
311
+ # so the cut is safe unquoted and the value is quoted where it is used.
312
+ display=\${rest%%'"'*}
313
+ printf '%s\\n' "$display"
297
314
  ;;
298
315
  esac
299
316
  ;;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@adrrr/tarmac",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Fleet observability for Claude Code — reads documented surfaces only, never an internal format",
5
5
  "keywords": [
6
6
  "claude",