@bookedsolid/rea 0.30.1 → 0.32.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/.husky/prepare-commit-msg +80 -6
- package/MIGRATING.md +24 -15
- package/dist/cli/audit-specialists.d.ts +106 -24
- package/dist/cli/audit-specialists.js +239 -64
- package/dist/cli/delegation-advisory.d.ts +161 -0
- package/dist/cli/delegation-advisory.js +433 -0
- package/dist/cli/doctor.d.ts +110 -39
- package/dist/cli/doctor.js +302 -90
- package/dist/cli/hook.d.ts +6 -0
- package/dist/cli/hook.js +45 -22
- package/dist/cli/index.js +1 -1
- package/dist/cli/install/settings-merge.js +25 -0
- package/dist/cli/roster.d.ts +119 -0
- package/dist/cli/roster.js +141 -0
- package/dist/hooks/_lib/halt-check.d.ts +78 -0
- package/dist/hooks/_lib/halt-check.js +106 -0
- package/dist/hooks/_lib/payload.d.ts +86 -0
- package/dist/hooks/_lib/payload.js +166 -0
- package/dist/hooks/_lib/segments.d.ts +100 -0
- package/dist/hooks/_lib/segments.js +444 -0
- package/dist/hooks/attribution-advisory/index.d.ts +72 -0
- package/dist/hooks/attribution-advisory/index.js +233 -0
- package/dist/hooks/bash-scanner/protected-scan.js +14 -2
- package/dist/hooks/pr-issue-link-gate/index.d.ts +91 -0
- package/dist/hooks/pr-issue-link-gate/index.js +127 -0
- package/dist/hooks/security-disclosure-gate/index.d.ts +91 -0
- package/dist/hooks/security-disclosure-gate/index.js +502 -0
- package/dist/policy/loader.d.ts +23 -0
- package/dist/policy/loader.js +46 -0
- package/dist/policy/profiles.d.ts +23 -0
- package/dist/policy/profiles.js +16 -0
- package/dist/policy/types.d.ts +61 -0
- package/hooks/_lib/protected-paths.sh +10 -3
- package/hooks/attribution-advisory.sh +139 -131
- package/hooks/delegation-advisory.sh +162 -0
- package/hooks/pr-issue-link-gate.sh +114 -45
- package/hooks/security-disclosure-gate.sh +148 -316
- package/hooks/settings-protection.sh +13 -9
- package/package.json +1 -1
- package/profiles/bst-internal-no-codex.yaml +12 -0
- package/profiles/bst-internal.yaml +13 -0
- package/profiles/client-engagement.yaml +11 -0
- package/profiles/lit-wc.yaml +10 -0
- package/profiles/minimal.yaml +11 -0
- package/profiles/open-source-no-codex.yaml +11 -0
- package/profiles/open-source.yaml +11 -0
- package/templates/attribution-advisory.dogfood-staged.sh +170 -0
- package/templates/pr-issue-link-gate.dogfood-staged.sh +134 -0
- package/templates/prepare-commit-msg.husky.sh +80 -6
- package/templates/security-disclosure-gate.dogfood-staged.sh +171 -0
- package/templates/settings-protection.dogfood.patch +58 -0
|
@@ -36,28 +36,65 @@ set -u
|
|
|
36
36
|
COMMIT_MSG_FILE="${1:-}"
|
|
37
37
|
COMMIT_SOURCE="${2:-}"
|
|
38
38
|
|
|
39
|
+
REA_ROOT=$(git rev-parse --show-toplevel 2>/dev/null || pwd)
|
|
40
|
+
|
|
41
|
+
# Forward declaration — the extension-chain runner is defined further
|
|
42
|
+
# down (after $REA_ROOT is set so the dir lookup is anchored). We call
|
|
43
|
+
# it from every "augmenter skipped" exit point so consumer fragments
|
|
44
|
+
# under .husky/prepare-commit-msg.d/* run regardless of whether rea's
|
|
45
|
+
# own augmenter ran. The function fires fragments in lex order,
|
|
46
|
+
# logs-and-continues on non-zero exits, and is a no-op if the dir is
|
|
47
|
+
# absent or empty.
|
|
48
|
+
#
|
|
49
|
+
# 0.32.0 Phase 3: the pre-0.32.0 layout exited early at every
|
|
50
|
+
# precondition gate, which made the extension surface unreachable
|
|
51
|
+
# when (a) attribution was disabled, (b) HALT was active, or (c)
|
|
52
|
+
# REA_SKIP_ATTRIBUTION was set. The new layout runs the chain at the
|
|
53
|
+
# end of every exit path EXCEPT when the message file itself is
|
|
54
|
+
# missing/unparseable (no point running fragments against a path that
|
|
55
|
+
# doesn't exist).
|
|
56
|
+
run_extension_chain() {
|
|
57
|
+
ext_dir="${REA_ROOT}/.husky/prepare-commit-msg.d"
|
|
58
|
+
if [ -d "$ext_dir" ]; then
|
|
59
|
+
for frag in "$ext_dir"/*; do
|
|
60
|
+
[ -e "$frag" ] || continue
|
|
61
|
+
[ -f "$frag" ] || continue
|
|
62
|
+
[ -x "$frag" ] || continue
|
|
63
|
+
if ! "$frag" "$COMMIT_MSG_FILE" "$COMMIT_SOURCE"; then
|
|
64
|
+
printf 'rea: prepare-commit-msg.d fragment exited non-zero: %s (continuing)\n' \
|
|
65
|
+
"$(basename "$frag")" >&2
|
|
66
|
+
fi
|
|
67
|
+
done
|
|
68
|
+
fi
|
|
69
|
+
}
|
|
70
|
+
|
|
39
71
|
# Skip conditions: any missing precondition exits 0 silently. The hook
|
|
40
72
|
# is purely additive; refusing here would break commits with no upside.
|
|
41
73
|
|
|
42
|
-
# Missing message file → nothing to augment
|
|
74
|
+
# Missing message file → nothing to augment AND nothing for fragments
|
|
75
|
+
# to act on either. Exit immediately without running the chain.
|
|
43
76
|
if [ -z "$COMMIT_MSG_FILE" ] || [ ! -f "$COMMIT_MSG_FILE" ]; then
|
|
44
77
|
exit 0
|
|
45
78
|
fi
|
|
46
79
|
|
|
47
|
-
# Per-invocation override
|
|
80
|
+
# Per-invocation override — skip the augmenter, but still run consumer
|
|
81
|
+
# fragments. The flag is named REA_SKIP_ATTRIBUTION, not REA_SKIP_HOOK,
|
|
82
|
+
# precisely so the rest of the chain runs.
|
|
48
83
|
if [ -n "${REA_SKIP_ATTRIBUTION:-}" ]; then
|
|
84
|
+
run_extension_chain
|
|
49
85
|
exit 0
|
|
50
86
|
fi
|
|
51
87
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
#
|
|
88
|
+
# HALT kill switch — refuse to mutate anything while frozen. The
|
|
89
|
+
# extension chain is also skipped under HALT: a frozen system means
|
|
90
|
+
# "no agent-side actions" and consumer fragments are agent-side too.
|
|
55
91
|
if [ -f "${REA_ROOT}/.rea/HALT" ]; then
|
|
56
92
|
exit 0
|
|
57
93
|
fi
|
|
58
94
|
|
|
59
95
|
POLICY_FILE="${REA_ROOT}/.rea/policy.yaml"
|
|
60
96
|
if [ ! -f "$POLICY_FILE" ]; then
|
|
97
|
+
run_extension_chain
|
|
61
98
|
exit 0
|
|
62
99
|
fi
|
|
63
100
|
|
|
@@ -172,6 +209,7 @@ print(enabled); print(name); print(email); print(skip_merge)
|
|
|
172
209
|
PY
|
|
173
210
|
)
|
|
174
211
|
if [ -z "$CO_AUTHOR_PARSE" ]; then
|
|
212
|
+
run_extension_chain
|
|
175
213
|
exit 0
|
|
176
214
|
fi
|
|
177
215
|
ENABLED=$(printf '%s\n' "$CO_AUTHOR_PARSE" | sed -n '1p')
|
|
@@ -179,11 +217,15 @@ PY
|
|
|
179
217
|
CO_EMAIL=$(printf '%s\n' "$CO_AUTHOR_PARSE" | sed -n '3p')
|
|
180
218
|
SKIP_MERGE=$(printf '%s\n' "$CO_AUTHOR_PARSE" | sed -n '4p')
|
|
181
219
|
else
|
|
182
|
-
# Neither rea CLI nor python3 reachable — silent no-op
|
|
220
|
+
# Neither rea CLI nor python3 reachable — silent no-op for the
|
|
221
|
+
# augmenter, but still run consumer fragments. The chain doesn't
|
|
222
|
+
# need policy values; it just runs `.husky/prepare-commit-msg.d/*`.
|
|
223
|
+
run_extension_chain
|
|
183
224
|
exit 0
|
|
184
225
|
fi
|
|
185
226
|
|
|
186
227
|
if [ "$ENABLED" != "true" ]; then
|
|
228
|
+
run_extension_chain
|
|
187
229
|
exit 0
|
|
188
230
|
fi
|
|
189
231
|
|
|
@@ -204,11 +246,13 @@ if [ -z "$CO_NAME" ] || [ -z "$CO_EMAIL" ]; then
|
|
|
204
246
|
"$([ -z "$CO_NAME" ] && [ -z "$CO_EMAIL" ] && printf '+')" \
|
|
205
247
|
"$([ -z "$CO_EMAIL" ] && printf email)" >&2
|
|
206
248
|
printf 'rea: edit .rea/policy.yaml — set name + email, OR set enabled: false.\n' >&2
|
|
249
|
+
run_extension_chain
|
|
207
250
|
exit 0
|
|
208
251
|
fi
|
|
209
252
|
|
|
210
253
|
# skip_merge: true → skip when commit source is 'merge'.
|
|
211
254
|
if [ "$SKIP_MERGE" = "true" ] && [ "$COMMIT_SOURCE" = "merge" ]; then
|
|
255
|
+
run_extension_chain
|
|
212
256
|
exit 0
|
|
213
257
|
fi
|
|
214
258
|
|
|
@@ -226,6 +270,7 @@ LOWER_EMAIL=$(printf '%s' "$CO_EMAIL" | tr '[:upper:]' '[:lower:]')
|
|
|
226
270
|
ESCAPED_EMAIL=$(printf '%s' "$LOWER_EMAIL" | sed 's/[.[\*^$(){}+?|]/\\&/g')
|
|
227
271
|
if grep -iE "^co-authored-by:[[:space:]]*[^<]*<${ESCAPED_EMAIL}>[[:space:]]*$" \
|
|
228
272
|
"$COMMIT_MSG_FILE" >/dev/null 2>&1; then
|
|
273
|
+
run_extension_chain
|
|
229
274
|
exit 0
|
|
230
275
|
fi
|
|
231
276
|
|
|
@@ -311,4 +356,33 @@ awk '
|
|
|
311
356
|
} > "${COMMIT_MSG_FILE}.rea-tmp" && mv "${COMMIT_MSG_FILE}.rea-tmp" "$COMMIT_MSG_FILE"
|
|
312
357
|
|
|
313
358
|
rm -f "$TMP_BODY_TRIMMED"
|
|
359
|
+
|
|
360
|
+
# ── Extension-hook chaining ───────────────────────────────────────────────────
|
|
361
|
+
# 0.32.0 — `.husky/prepare-commit-msg.d/*` extension surface mirrors
|
|
362
|
+
# the `.husky/commit-msg.d/*` and `.husky/pre-push.d/*` patterns from
|
|
363
|
+
# 0.13.0. Source every executable file under
|
|
364
|
+
# `.husky/prepare-commit-msg.d/` in lexical order. Missing directory
|
|
365
|
+
# is a no-op (backward compatible). Each fragment receives the same
|
|
366
|
+
# `$1` (commit message file path) and `$2` (commit source) that git
|
|
367
|
+
# delivered to this hook so consumers can layer on their own
|
|
368
|
+
# augmenters (lint-staged --on-prepare, branch-name-injection,
|
|
369
|
+
# ticket-reference-prepend, …) without losing rea coverage.
|
|
370
|
+
#
|
|
371
|
+
# Fragments run AFTER rea's attribution augmenter so the
|
|
372
|
+
# `Co-Authored-By` trailer is already in the file before any consumer
|
|
373
|
+
# fragment reads it; that lets a fragment reorder trailers, dedupe,
|
|
374
|
+
# or run its own template substitution against the augmented body.
|
|
375
|
+
#
|
|
376
|
+
# A non-zero exit from a fragment does NOT fail the commit — this
|
|
377
|
+
# hook is purely additive (its bash counterpart `commit-msg` is the
|
|
378
|
+
# blocking gate). We log the failure to stderr and continue so a
|
|
379
|
+
# broken consumer fragment can't take down `git commit`.
|
|
380
|
+
#
|
|
381
|
+
# The actual chain body lives in `run_extension_chain` (defined near
|
|
382
|
+
# the top of the file). The reason for the early definition: several
|
|
383
|
+
# augmenter-skip exit paths (enabled: false, missing identity, idempo-
|
|
384
|
+
# tency hit, skip_merge match) need to run the chain too, so consumer
|
|
385
|
+
# fragments fire regardless of whether rea's own augmenter activated.
|
|
386
|
+
run_extension_chain
|
|
387
|
+
|
|
314
388
|
exit 0
|
package/MIGRATING.md
CHANGED
|
@@ -78,13 +78,16 @@ are on the vanilla-git path — install husky first.
|
|
|
78
78
|
The only files rea touches are explicitly enumerated above. Everything
|
|
79
79
|
else is the consumer's surface.
|
|
80
80
|
|
|
81
|
-
## Extension surface (added in 0.13.0)
|
|
81
|
+
## Extension surface (added in 0.13.0; expanded in 0.32.0)
|
|
82
82
|
|
|
83
|
-
`.husky/pre-push.d
|
|
84
|
-
**upgrade-safe** place to
|
|
85
|
-
|
|
86
|
-
its own governance work succeeds.
|
|
87
|
-
fails the hook (matches husky's
|
|
83
|
+
`.husky/pre-push.d/*`, `.husky/commit-msg.d/*`, and (as of 0.32.0)
|
|
84
|
+
`.husky/prepare-commit-msg.d/*` are the **upgrade-safe** place to
|
|
85
|
+
layer your own gates. Files in those directories must be executable;
|
|
86
|
+
rea sources them in lex order AFTER its own governance work succeeds.
|
|
87
|
+
A non-zero exit from any fragment fails the hook (matches husky's
|
|
88
|
+
normal chaining) — EXCEPT for the `prepare-commit-msg.d/*` lane,
|
|
89
|
+
which logs and continues so a broken fragment can't take down `git
|
|
90
|
+
commit`.
|
|
88
91
|
|
|
89
92
|
- Fragment receives positional args from git (`<remote-name> <remote-url>`
|
|
90
93
|
for pre-push, `<commit-msg-file>` for commit-msg).
|
|
@@ -158,26 +161,32 @@ Two paths, depending on whether you intend to use the rea augmenter.
|
|
|
158
161
|
|
|
159
162
|
**Path A — you want the augmenter (Co-Authored-By trailer)**
|
|
160
163
|
|
|
161
|
-
Move your branch-prefix logic into
|
|
162
|
-
rea's prepare-commit-msg body
|
|
163
|
-
|
|
164
|
-
|
|
164
|
+
Move your branch-prefix logic into a `.husky/prepare-commit-msg.d/*`
|
|
165
|
+
fragment. As of **0.32.0** rea's prepare-commit-msg body sources every
|
|
166
|
+
executable file in `.husky/prepare-commit-msg.d/` in lexical order
|
|
167
|
+
AFTER its own attribution augmenter runs (mirrors the
|
|
168
|
+
`commit-msg.d/*` and `pre-push.d/*` extension surfaces from 0.13.0).
|
|
169
|
+
Each fragment receives the same `$1` (commit-message file path) and
|
|
170
|
+
`$2` (commit source) git delivered to the hook:
|
|
165
171
|
|
|
166
172
|
```bash
|
|
167
|
-
mkdir -p .husky/commit-msg.d
|
|
168
|
-
cat > .husky/commit-msg.d/00-branch-prefix <<'EOF'
|
|
173
|
+
mkdir -p .husky/prepare-commit-msg.d
|
|
174
|
+
cat > .husky/prepare-commit-msg.d/00-branch-prefix <<'EOF'
|
|
169
175
|
#!/bin/sh
|
|
170
|
-
#
|
|
171
|
-
# (runs AFTER rea's augmenter, before the commit is finalized).
|
|
176
|
+
# Runs AFTER rea's Co-Authored-By augmenter. $1 = commit-msg file.
|
|
172
177
|
BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo unknown)
|
|
173
178
|
case $(head -1 "$1") in
|
|
174
179
|
"[$BRANCH]"*) ;; # already prefixed
|
|
175
180
|
*) printf '[%s] %s' "$BRANCH" "$(cat "$1")" > "$1" ;;
|
|
176
181
|
esac
|
|
177
182
|
EOF
|
|
178
|
-
chmod +x .husky/commit-msg.d/00-branch-prefix
|
|
183
|
+
chmod +x .husky/prepare-commit-msg.d/00-branch-prefix
|
|
179
184
|
```
|
|
180
185
|
|
|
186
|
+
A non-zero exit from a fragment does NOT fail the commit (the augmenter
|
|
187
|
+
hook is purely additive; the blocking gate is `commit-msg`). Broken
|
|
188
|
+
fragments log to stderr and the hook continues.
|
|
189
|
+
|
|
181
190
|
Then remove the old `.husky/prepare-commit-msg`:
|
|
182
191
|
|
|
183
192
|
```bash
|
|
@@ -1,20 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `rea audit specialists` —
|
|
2
|
+
* `rea audit specialists` — reader CLI for delegation-telemetry
|
|
3
|
+
* (0.29.0; `--since` / `--session` added 0.31.0).
|
|
3
4
|
*
|
|
4
|
-
* Walks `.rea/audit.jsonl
|
|
5
|
-
* `tool_name === 'rea.delegation_signal'`,
|
|
6
|
-
* `metadata.subagent_type`, and prints a table (default) or
|
|
7
|
-
* document (`--json`).
|
|
5
|
+
* Walks `.rea/audit.jsonl` (plus any rotated files when `--since` is
|
|
6
|
+
* given), filters records by `tool_name === 'rea.delegation_signal'`,
|
|
7
|
+
* groups by `metadata.subagent_type`, and prints a table (default) or
|
|
8
|
+
* JSON document (`--json`).
|
|
8
9
|
*
|
|
9
|
-
* #
|
|
10
|
+
* # Session filtering
|
|
10
11
|
*
|
|
11
|
-
*
|
|
12
|
-
* engineer scope-cut deferred both to 0.29.1. The filter is:
|
|
12
|
+
* Three ways to scope, in precedence order:
|
|
13
13
|
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
14
|
+
* 1. `--session <id>` — explicit. Filters to records whose
|
|
15
|
+
* `metadata.session_id_observed` matches `<id>`. The literal
|
|
16
|
+
* `--session all` disables filtering entirely (show every
|
|
17
|
+
* session). Wins over the env var.
|
|
18
|
+
* 2. `$CLAUDE_SESSION_ID` — when set and `--session` is omitted,
|
|
19
|
+
* filters to the current Claude Code session.
|
|
20
|
+
* 3. neither — no filter; every record in the walked files is shown,
|
|
21
|
+
* and a note tells the operator what they're seeing.
|
|
22
|
+
*
|
|
23
|
+
* # `--since <rotated-file>`
|
|
24
|
+
*
|
|
25
|
+
* By default the reader walks only the current `.rea/audit.jsonl`.
|
|
26
|
+
* `--since audit-YYYYMMDD-HHMMSS.jsonl` extends the walk backward: the
|
|
27
|
+
* named rotated file and every rotated file after it (timestamp-
|
|
28
|
+
* ascending) are scanned, then the current `audit.jsonl` as the tail.
|
|
29
|
+
* Mirrors `rea audit verify --since`. The filename must match the
|
|
30
|
+
* canonical rotated-audit shape or the CLI exits 1.
|
|
18
31
|
*
|
|
19
32
|
* # Output shape
|
|
20
33
|
*
|
|
@@ -23,8 +36,8 @@
|
|
|
23
36
|
* code-reviewer 5 2026-05-12T21:28:00Z
|
|
24
37
|
* deep-dive 2 2026-05-12T21:14:00Z
|
|
25
38
|
*
|
|
26
|
-
* JSON mode prints `{ session_filter, records, groups }`
|
|
27
|
-
* `records` is the raw filtered subset (for piping into jq) and
|
|
39
|
+
* JSON mode prints `{ session_filter, records, groups, files_scanned }`
|
|
40
|
+
* where `records` is the raw filtered subset (for piping into jq) and
|
|
28
41
|
* `groups` is the per-subagent rollup.
|
|
29
42
|
*/
|
|
30
43
|
import type { Command } from 'commander';
|
|
@@ -34,17 +47,48 @@ export interface AuditSpecialistsOptions {
|
|
|
34
47
|
json?: boolean;
|
|
35
48
|
/**
|
|
36
49
|
* Override session filtering. Production callers omit (the CLI reads
|
|
37
|
-
* `CLAUDE_SESSION_ID` from the env). Tests set this
|
|
38
|
-
* mutate `process.env`.
|
|
50
|
+
* `--session` then `CLAUDE_SESSION_ID` from the env). Tests set this
|
|
51
|
+
* so they don't mutate `process.env`.
|
|
39
52
|
*
|
|
40
53
|
* - `string` → filter to records whose `session_id_observed` matches.
|
|
41
54
|
* - `null` → no filter (show all records).
|
|
42
|
-
* - `undefined` → derive from env.
|
|
55
|
+
* - `undefined` → derive from `--session` flag then env.
|
|
43
56
|
*/
|
|
44
57
|
sessionFilter?: string | null;
|
|
58
|
+
/**
|
|
59
|
+
* 0.31.0 — explicit `--session <id>` flag value. Resolution rules:
|
|
60
|
+
*
|
|
61
|
+
* - `'all'` (case-insensitive) → no filter (equivalent to
|
|
62
|
+
* `sessionFilter: null`), `session_filter_source: 'option'`.
|
|
63
|
+
* - any other non-empty string → filter to that session,
|
|
64
|
+
* `session_filter_source: 'option'`.
|
|
65
|
+
* - `undefined` → fall through to `sessionFilter`, then env.
|
|
66
|
+
*
|
|
67
|
+
* `sessionFilter` (the test seam) still wins over this when both are
|
|
68
|
+
* set — tests inject `sessionFilter` directly and don't pass
|
|
69
|
+
* `sessionOption`.
|
|
70
|
+
*/
|
|
71
|
+
sessionOption?: string;
|
|
72
|
+
/**
|
|
73
|
+
* 0.31.0 — `--since <rotated-file>` flag value. When set, the named
|
|
74
|
+
* rotated audit file plus every later rotated file (timestamp-
|
|
75
|
+
* ascending) are walked before the current `.rea/audit.jsonl`.
|
|
76
|
+
* Must match `audit-YYYYMMDD-HHMMSS(-N).jsonl`. Validation failure
|
|
77
|
+
* throws `AuditSpecialistsSinceError` so the commander wrapper can
|
|
78
|
+
* exit 1 with a clear message.
|
|
79
|
+
*/
|
|
80
|
+
since?: string;
|
|
45
81
|
/** Override CWD. Tests set this; production uses `process.cwd()`. */
|
|
46
82
|
baseDir?: string;
|
|
47
83
|
}
|
|
84
|
+
/**
|
|
85
|
+
* Thrown by `computeAuditSpecialists` when `--since` names something
|
|
86
|
+
* that is not a valid rotated-audit basename, or names a rotated file
|
|
87
|
+
* that does not exist. The commander wrapper catches it and exits 1.
|
|
88
|
+
*/
|
|
89
|
+
export declare class AuditSpecialistsSinceError extends Error {
|
|
90
|
+
constructor(message: string);
|
|
91
|
+
}
|
|
48
92
|
interface DelegationGroup {
|
|
49
93
|
subagent_type: string;
|
|
50
94
|
count: number;
|
|
@@ -53,7 +97,7 @@ interface DelegationGroup {
|
|
|
53
97
|
/** Breakdown of which delegation_tool fired (Agent vs. Skill). */
|
|
54
98
|
by_tool: Record<DelegationTool, number>;
|
|
55
99
|
}
|
|
56
|
-
interface DelegationRecord {
|
|
100
|
+
export interface DelegationRecord {
|
|
57
101
|
timestamp: string;
|
|
58
102
|
session_id_observed: string;
|
|
59
103
|
delegation_tool: DelegationTool;
|
|
@@ -78,11 +122,48 @@ interface AuditSpecialistsResult {
|
|
|
78
122
|
files_scanned: string[];
|
|
79
123
|
}
|
|
80
124
|
/**
|
|
81
|
-
*
|
|
82
|
-
*
|
|
83
|
-
*
|
|
125
|
+
* List rotated audit files in `.rea/`, timestamp-ascending. Filenames
|
|
126
|
+
* follow `audit-YYYYMMDD-HHMMSS(-N).jsonl`. Sorted via
|
|
127
|
+
* `rotatedAuditSortKey` — the `YYYYMMDD-HHMMSS` block lexically (it is
|
|
128
|
+
* fixed-width zero-padded, so lexical == chronological) then the `-N`
|
|
129
|
+
* intra-second suffix NUMERICALLY (a plain lexical sort of the whole
|
|
130
|
+
* basename misorders two-digit suffixes — see `rotatedAuditSortKey`).
|
|
131
|
+
* Mirrors the private helper in `audit.ts` — kept local so this reader
|
|
132
|
+
* doesn't import the verify command's internals.
|
|
133
|
+
*
|
|
134
|
+
* Exported (0.31.0 round-2 P3) so `delegation-advisory.ts` can resolve
|
|
135
|
+
* the rotated-file set without duplicating the `ROTATED_AUDIT_RE` glob:
|
|
136
|
+
* the advisory's "did this session delegate" predicate must scan rotated
|
|
137
|
+
* segments too, or a delegation recorded before an audit rotation is
|
|
138
|
+
* invisible to the nudge and the session gets a false-positive advisory.
|
|
139
|
+
*/
|
|
140
|
+
export declare function listRotatedAuditFiles(reaDir: string): Promise<string[]>;
|
|
141
|
+
/**
|
|
142
|
+
* Resolve the ordered list of absolute audit-file paths to walk.
|
|
143
|
+
*
|
|
144
|
+
* - `since === undefined` → just the current `.rea/audit.jsonl` (when
|
|
145
|
+
* it exists). Pre-0.31.0 behavior.
|
|
146
|
+
* - `since` set → validate it names a real rotated file, then walk
|
|
147
|
+
* that file + every later rotated file (timestamp-ascending), with
|
|
148
|
+
* the current `audit.jsonl` as the tail.
|
|
149
|
+
*
|
|
150
|
+
* The current `audit.jsonl` is included at the END of the walk
|
|
151
|
+
* whenever it exists — it is always the newest segment of the chain.
|
|
152
|
+
* A `--since` that names a non-rotated string, or a rotated file that
|
|
153
|
+
* isn't present on disk, throws `AuditSpecialistsSinceError`.
|
|
154
|
+
*/
|
|
155
|
+
export declare function resolveAuditFileWalk(baseDir: string, since: string | undefined): Promise<string[]>;
|
|
156
|
+
/**
|
|
157
|
+
* Read the audit file(s) and return delegation records (filtered +
|
|
158
|
+
* parsed into a reader-friendly shape). Malformed lines are skipped
|
|
159
|
+
* silently — `rea audit verify` is the right tool for chain integrity.
|
|
160
|
+
*
|
|
161
|
+
* `since` defaults to `undefined` (current `.rea/audit.jsonl` only) so
|
|
162
|
+
* existing callers — including `computeDelegationAdvisory` in
|
|
163
|
+
* `delegation-advisory.ts` — keep their pre-0.31.0 single-file
|
|
164
|
+
* behavior without passing the argument.
|
|
84
165
|
*/
|
|
85
|
-
export declare function loadDelegationRecords(baseDir: string, sessionFilter: string | null): Promise<{
|
|
166
|
+
export declare function loadDelegationRecords(baseDir: string, sessionFilter: string | null, since?: string): Promise<{
|
|
86
167
|
records: DelegationRecord[];
|
|
87
168
|
filesScanned: string[];
|
|
88
169
|
}>;
|
|
@@ -99,8 +180,9 @@ export declare function groupBySubagent(records: DelegationRecord[]): Delegation
|
|
|
99
180
|
*/
|
|
100
181
|
export declare function computeAuditSpecialists(options?: AuditSpecialistsOptions): Promise<AuditSpecialistsResult>;
|
|
101
182
|
/**
|
|
102
|
-
* Commander entrypoint. Reads, renders, exits 0
|
|
103
|
-
*
|
|
183
|
+
* Commander entrypoint. Reads, renders, exits 0 on success / 1 when
|
|
184
|
+
* `--since` is malformed or names a missing rotated file. The CLI is
|
|
185
|
+
* read-only — no audit-chain writes.
|
|
104
186
|
*/
|
|
105
187
|
export declare function runAuditSpecialists(options: AuditSpecialistsOptions): Promise<void>;
|
|
106
188
|
/**
|