@attalabs/vinaya 0.22.0 → 0.24.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/README.md +14 -3
- package/aeg-root/contracts/archivist-tranche-archivist.md +2 -2
- package/aeg-root/contracts/brief-developer.md +1 -0
- package/aeg-root/contracts/developer-reviewer.md +3 -3
- package/aeg-root/contracts/reviewer-archivist.md +3 -3
- package/aeg-root/enforcement.md +26 -20
- package/aeg-root/process.md +8 -4
- package/aeg-root/roles/archivist.md +2 -2
- package/aeg-root/roles/brief-author.md +9 -3
- package/aeg-root/roles/developer.md +63 -31
- package/aeg-root/roles/planner.md +1 -1
- package/aeg-root/roles/principal.md +14 -0
- package/aeg-root/roles/reviewer.md +32 -15
- package/aeg-root/roles/security.md +15 -5
- package/aeg-root/skills/aeg/SKILL.md +9 -5
- package/aeg-root/skills/aeg-roles/SKILL.md +2 -2
- package/aeg-root/skills/brief-authoring/SKILL.md +39 -27
- package/aeg-root/state-machine.md +9 -11
- package/aeg-root/templates/brief-template.md +6 -6
- package/aeg-root/templates/pr-report-template.md +10 -7
- package/aeg-root/tranche-model.md +6 -2
- package/dist/checks/bin/check-body-bare-digits.js +559 -140
- package/dist/checks/bin/check-branch-topology.js +630 -145
- package/dist/checks/bin/check-brief-shape.js +600 -143
- package/dist/checks/bin/check-changeset-coverage.js +942 -162
- package/dist/checks/bin/check-closes-n.js +630 -145
- package/dist/checks/bin/check-coherence.js +641 -148
- package/dist/checks/bin/check-dead-branch-push.js +559 -140
- package/dist/checks/bin/check-dispatch-readiness.js +639 -146
- package/dist/checks/bin/check-doc-coverage-push.js +696 -219
- package/dist/checks/bin/check-doc-coverage.js +696 -219
- package/dist/checks/bin/check-doctrine-no-procedures.js +4800 -0
- package/dist/checks/bin/check-doctrine-portability.js +691 -147
- package/dist/checks/bin/check-evidence-fresh.js +1048 -222
- package/dist/checks/bin/check-exec-bits.js +4937 -0
- package/dist/checks/bin/check-first-push-dispatch.js +630 -145
- package/dist/checks/bin/check-issue-assignment.js +630 -145
- package/dist/checks/bin/check-main-branch-refusal.js +565 -141
- package/dist/checks/bin/check-no-disk-state.js +559 -140
- package/dist/checks/bin/check-pr-report-density.js +4467 -0
- package/dist/checks/bin/check-quoted-command.js +656 -164
- package/dist/checks/bin/check-reader-resolvable-prose.js +652 -163
- package/dist/checks/bin/check-registry-gates.js +602 -145
- package/dist/checks/bin/check-retired-vocabulary.js +652 -163
- package/dist/checks/bin/check-review-gate.js +677 -142
- package/dist/checks/bin/check-single-plan-pr.js +559 -140
- package/dist/checks/bin/check-test-plan.js +560 -141
- package/dist/checks/bin/check-token-collection-wired.js +559 -140
- package/dist/checks/bin/check-token-report.js +559 -140
- package/dist/checks/bin/check-workspace-escape.js +992 -146
- package/dist/index.js +8884 -5627
- package/package.json +1 -1
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/actions.ts +173 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/anchored-region.ts +118 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/archive-task.ts +206 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/baseline-capture.ts +65 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/blast-radius-domains.ts +198 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/branch-topology-gate.ts +85 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/brief-render.ts +462 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/brief-validation.ts +912 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/claude-code-transcript.ts +460 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/coherence-checks.ts +806 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/consumer-enumeration.ts +75 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/dead-branch-push-audit.ts +55 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/dead-branch-push-guard.ts +77 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/derive-section7.ts +66 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/derive-tranche.ts +94 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/diagram-model.ts +372 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/direct-main-push.ts +39 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/dispatch-gate.ts +268 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/doc-owners.ts +314 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/build-doc-nav.ts +38 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/docs-coherence.ts +136 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/index.ts +29 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/legacy-anchors.ts +48 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/nav-helpers.ts +17 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/node-route.ts +134 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/parse-doc.ts +43 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/published-prose.ts +306 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/surfaced-manifest.ts +89 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/docs/types.ts +33 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/doctrine-no-procedures.ts +94 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/doctrine-portability.ts +293 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/doctrine-source.ts +23 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/ensure-label.ts +28 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/file-classify.ts +51 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/first-push-dispatch-gate.ts +80 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/gate-audience.ts +171 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/index.ts +323 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/issue-assignment.ts +102 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/issue-validation.ts +746 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/leftover-detection.ts +68 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/local-anchor-coverage.ts +245 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/main-branch-refusal.ts +64 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/manifest-validity.ts +81 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/markdown-table.ts +76 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/metering-io-guard.ts +119 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/milestone-validation.ts +240 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/no-disk-state.ts +50 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/parse-ledger.ts +77 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/parse-registry.ts +105 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/parse-token-report.ts +177 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/parse-tranche.ts +183 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/pr-report-density.ts +116 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/pr-tier.ts +81 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/premise-check.ts +160 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/quoted-command.ts +275 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/reader-resolvable-prose.ts +320 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/registry-checks.ts +255 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/registry-parse.ts +164 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/registry-scaffold.ts +216 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/report-tokens.ts +261 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/retired-vocabulary.ts +163 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/review-gate.ts +378 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/review-status.ts +200 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/single-plan-pr.ts +73 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/state-machine-model.ts +269 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/state-source.ts +14 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/status-block.ts +8 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/sum-ledger.ts +26 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/symbol-collisions.ts +78 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/test-plan-gate.ts +117 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/test-plan-section.ts +65 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/types.ts +174 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/verdict-extraction.ts +199 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/vocabulary-citation.ts +114 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/waiver-label.ts +52 -0
- package/studio-standalone/_node_modules/@attalabs/aeg-core/src/workspace-escape.ts +172 -0
- package/studio-standalone/apps/vinaya-studio/web/.next/BUILD_ID +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/build-manifest.json +3 -3
- package/studio-standalone/apps/vinaya-studio/web/.next/prerender-manifest.json +3 -3
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.html +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/api/coherence/route.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/backlog/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/[name]/tranches/[slug]/tasks/[taskId]/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/projects/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page/server-reference-manifest.json +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page.js.nft.json +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/app/studio/tranches/page_client-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/[root-of-the-server]__02a-3g8._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/1q96_modules_@clerk_nextjs_dist_esm_app-router_client_keyless-creator-reader_0lom2js.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0053k9k._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0112h-k._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0o771t1._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__0puovz5._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1hs0dcu._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/{[root-of-the-server]__069-_41._.js → [root-of-the-server]__1pndh3_._.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/[root-of-the-server]__1wc4-ip._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_03x_w6q._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0gvm3og._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_0lwxg63._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1fqw88f._.js +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/_1n0cnq-._.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/apps_vinaya-studio_web_src_app_studio_projects_[name]_tranches_[slug]_05ufo8i._.js +3 -3
- package/studio-standalone/apps/vinaya-studio/web/.next/server/chunks/ssr/node_modules_1vo08dj._.js +2 -2
- package/studio-standalone/apps/vinaya-studio/web/.next/server/middleware-build-manifest.js +3 -3
- package/studio-standalone/apps/vinaya-studio/web/.next/server/pages/500.html +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.js +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/server/server-reference-manifest.json +3 -3
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{37hnluhzj9bei.js → 0zebsmmk1bvnb.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{267o-tsrnuwnv.js → 1uogpj5w2n5ju.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/.next/static/chunks/{1hufpuody6vjv.js → 3m1kgax7j2vgs.js} +1 -1
- package/studio-standalone/apps/vinaya-studio/web/package.json +2 -2
- /package/studio-standalone/_node_modules/@attalabs/vinaya/studio-standalone/_node_modules/@attalabs/{aeg-core → vinaya/studio-standalone/_node_modules/@attalabs/vinaya/studio-standalone/_node_modules/@attalabs/aeg-core}/bin/verify-coherence.ts +0 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{Fmyc42qzLwFcWWHLLNy-G → QY2GhiI47-765D9DHGy1I}/_buildManifest.js +0 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{Fmyc42qzLwFcWWHLLNy-G → QY2GhiI47-765D9DHGy1I}/_clientMiddlewareManifest.js +0 -0
- /package/studio-standalone/apps/vinaya-studio/web/.next/static/{Fmyc42qzLwFcWWHLLNy-G → QY2GhiI47-765D9DHGy1I}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* report-tokens — the **portable** half of the token-report contract
|
|
3
|
+
* (`aeg-root/tranche-model.md` §12, layers 1 and 3). No value this file reads,
|
|
4
|
+
* computes or emits is host-specific: it defines the summary shape every
|
|
5
|
+
* collection adapter must produce, and renders that shape into the frozen
|
|
6
|
+
* `Tokens: …` grammar `parse-token-report.ts` reads back. A host is named
|
|
7
|
+
* below only to point at the one shipped adapter and to record a retraction —
|
|
8
|
+
* never to branch on, and never in rendered output.
|
|
9
|
+
*
|
|
10
|
+
* `TranscriptSummary` **is the seam.** A host adapter's whole job is to
|
|
11
|
+
* produce one — from a session transcript, an API usage response, a meter the
|
|
12
|
+
* harness exposes, or figures an operator supplies by hand. AEG ships exactly
|
|
13
|
+
* one such adapter, for Claude Code, in `claude-code-transcript.ts`; a repo
|
|
14
|
+
* on another harness writes its own and reuses everything here unchanged.
|
|
15
|
+
* Adding host knowledge to this file would silently re-couple the portable
|
|
16
|
+
* layers to one vendor — that coupling is the defect the split exists to
|
|
17
|
+
* prevent, and this file is where it would reappear first.
|
|
18
|
+
*
|
|
19
|
+
* Historical note (misc-hardening-v1 task 1, #675): this module retracted
|
|
20
|
+
* §12's earlier claim that a role reports exact tokens "from `/cost`" — an
|
|
21
|
+
* operator-typed slash command no unattended agent session can invoke, in
|
|
22
|
+
* that host or any other. §12 records the retraction; the fix was to collect
|
|
23
|
+
* from a real per-turn source instead.
|
|
24
|
+
*
|
|
25
|
+
* Pure — no `fs`, no `process.env`. The CLI shim (`bin/report-tokens.ts`)
|
|
26
|
+
* does the I/O; these functions take values and produce the report.
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* The four usage figures a role reports, in host-neutral terms. Every
|
|
31
|
+
* collection adapter maps its host's own field names onto these, so no field
|
|
32
|
+
* name from a host's own API or transcript format appears downstream of the
|
|
33
|
+
* adapter — including in this file.
|
|
34
|
+
*/
|
|
35
|
+
export type UsageComponents = {
|
|
36
|
+
inputTokens: number
|
|
37
|
+
outputTokens: number
|
|
38
|
+
cacheCreationInputTokens: number
|
|
39
|
+
cacheReadInputTokens: number
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* **The adapter seam.** What a host's collection step must produce for one
|
|
44
|
+
* role-turn, and the only thing the portable layers below consume. Named for
|
|
45
|
+
* the shipped adapter's source (a session transcript), but the shape is not
|
|
46
|
+
* transcript-specific: an adapter that reads an API usage response or takes
|
|
47
|
+
* operator-supplied figures produces this same object.
|
|
48
|
+
*/
|
|
49
|
+
export type TranscriptSummary = {
|
|
50
|
+
components: UsageComponents
|
|
51
|
+
/** The model id for the turn, or `null` when the host does not report one. */
|
|
52
|
+
model: string | null
|
|
53
|
+
/**
|
|
54
|
+
* How many distinct usage records were summed. Callers use `0` as the
|
|
55
|
+
* "nothing usable was collected" signal — a real turn always has at least
|
|
56
|
+
* one — rather than letting a zeroed summary format as a plausible `0/0/—`.
|
|
57
|
+
*/
|
|
58
|
+
messageCount: number
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export type TokensLineInput = {
|
|
62
|
+
phase: string
|
|
63
|
+
role: string
|
|
64
|
+
/**
|
|
65
|
+
* `null` only when the role is operator-metered — its host exposes no
|
|
66
|
+
* usage to the agent at all — which produces the all-`—` numbers segment
|
|
67
|
+
* the parser already tolerates. Never a convenience escape for a
|
|
68
|
+
* self-metering role whose collection step merely failed: that case is an
|
|
69
|
+
* error to report, not a blank to emit (`aeg-root/tranche-model.md` §12).
|
|
70
|
+
*/
|
|
71
|
+
summary: TranscriptSummary | null
|
|
72
|
+
/** Overrides the model the adapter derived, if given. */
|
|
73
|
+
modelOverride?: string
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Format the one-line `Tokens: <phase> — <role> — <model> — <in>/<out>/<cost>`
|
|
78
|
+
* report that `parse-token-report.ts`'s `parseTokensLines` consumes. The
|
|
79
|
+
* grammar is frozen (three parsers depend on it) — this function must never
|
|
80
|
+
* change its shape, only what feeds it.
|
|
81
|
+
*
|
|
82
|
+
* `Tokens in` is the full input-side total (`inputTokens +
|
|
83
|
+
* cacheCreationInputTokens + cacheReadInputTokens`) — genuinely every
|
|
84
|
+
* token that went in, not a partial figure. Cache reads can outweigh fresh
|
|
85
|
+
* input by two orders of magnitude on a long session, so that total is
|
|
86
|
+
* never the whole story on its own; `formatBreakdown` reports the four
|
|
87
|
+
* components separately for anyone reading the reporter's own output,
|
|
88
|
+
* rather than letting the single blended cell stand as if it were.
|
|
89
|
+
*
|
|
90
|
+
* Cost is always reported as `—`: no maintained, accurate $/token pricing
|
|
91
|
+
* table for current models lives in this package (the one in
|
|
92
|
+
* `@atta/adapter-langgraph` is a different product's provider-pricing
|
|
93
|
+
* table, out of this task's surface, and does not cover these model ids) —
|
|
94
|
+
* an unverified guess baked into a PR's permanent history is worse than an
|
|
95
|
+
* honest unknown.
|
|
96
|
+
*/
|
|
97
|
+
/**
|
|
98
|
+
* An embedded newline could forge a synthetic row/line neither writer ever
|
|
99
|
+
* intended, regardless of which grammar's own delimiter is in play — shared
|
|
100
|
+
* by both sanitizers below.
|
|
101
|
+
*/
|
|
102
|
+
function stripNewlines(value: string): string {
|
|
103
|
+
return value.replace(/\r?\n/g, ' ')
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Table-row sanitizer: escapes `|` (the cell delimiter `splitTableRow`
|
|
108
|
+
* already expects `\|` for on read — the same escape convention, applied on
|
|
109
|
+
* write) on top of `stripNewlines`. Used by `formatTokenReportRow` for every
|
|
110
|
+
* free-text cell — `phase`, `role`, the derived `model`, and `date` —
|
|
111
|
+
* because any of them can arrive from an untrusted CLI flag or a git branch
|
|
112
|
+
* name, both of which can legally contain `|` and newlines (found live: a
|
|
113
|
+
* crafted branch name produced a row whose columns silently shifted past
|
|
114
|
+
* `parseTokenReportEntries`, discarding real measured usage with no error).
|
|
115
|
+
*/
|
|
116
|
+
function sanitizeForTableCell(value: string): string {
|
|
117
|
+
return stripNewlines(value).replace(/\|/g, '\\|')
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* `Tokens: …` line sanitizer. `parse-token-report.ts`'s `SEGMENT_SEP`
|
|
122
|
+
* (`/\s+[—–-]\s+/`) is a whitespace-flanked dash — and a field-local fix
|
|
123
|
+
* (removing the flanking whitespace around a dash the field itself
|
|
124
|
+
* contains) is provably incomplete: the JOIN ITSELF contributes whitespace
|
|
125
|
+
* on both sides of every field (the literal `" — "` between segments), so a
|
|
126
|
+
* field merely ENDING or STARTING with a dash reconstructs the exact same
|
|
127
|
+
* pattern from the boundary alone — `"9 -"` joined with the next field's
|
|
128
|
+
* leading `" — "` reads back as `"...9 - — ..."`, a real `SEGMENT_SEP`
|
|
129
|
+
* match, with no dash-adjacent whitespace inside the field at all to strip
|
|
130
|
+
* (found live: `--phase "9 -" --role "Dev -"` silently dropped the real
|
|
131
|
+
* `tokensIn`). No amount of field-local whitespace-stripping closes this —
|
|
132
|
+
* the hazard is the CHARACTER, reachable from any position once anything
|
|
133
|
+
* joins around it, not a particular spacing.
|
|
134
|
+
*
|
|
135
|
+
* The fix that actually closes it: remove the character itself from the
|
|
136
|
+
* field's vocabulary, but ONLY where it's actually reachable by
|
|
137
|
+
* `SEGMENT_SEP` — a dash counts as reachable on a given side when that
|
|
138
|
+
* side is whitespace, OR is the very edge of the field (every field in
|
|
139
|
+
* this grammar sits directly against a `" — "` join or the `"Tokens: "`
|
|
140
|
+
* prefix, so an edge is guaranteed adjacent to boundary whitespace once
|
|
141
|
+
* concatenated). A dash is substituted only when BOTH sides are reachable
|
|
142
|
+
* — matching exactly what `SEGMENT_SEP` itself requires (whitespace on
|
|
143
|
+
* both sides) once the guaranteed boundary whitespace is accounted for.
|
|
144
|
+
* An ordinary hyphenated identifier like `"claude-sonnet-5"` has
|
|
145
|
+
* non-whitespace, non-edge neighbors on both sides of every hyphen and is
|
|
146
|
+
* left completely untouched — a whole-field substitution (an earlier draft
|
|
147
|
+
* of this fix) needlessly mangled every such identifier, which is why this
|
|
148
|
+
* checks each dash's actual neighbors instead of blanket-replacing the
|
|
149
|
+
* class. This is also less lossy than the whitespace-stripping this
|
|
150
|
+
* replaces: two phase labels that only differed in spacing around a
|
|
151
|
+
* hazardous hyphen (`"9-fix"` — never hazardous, untouched — vs.
|
|
152
|
+
* `"9 - fix"` — hazardous, substituted) used to sanitize to byte-identical
|
|
153
|
+
* output; substitution preserves spacing, changing only the one character
|
|
154
|
+
* that must never survive verbatim in a hazardous position.
|
|
155
|
+
*/
|
|
156
|
+
const DASH_LOOKALIKES: Record<string, string> = {
|
|
157
|
+
'-': '‑', // U+2011 NON-BREAKING HYPHEN
|
|
158
|
+
'–': '‒', // U+2012 FIGURE DASH
|
|
159
|
+
'—': '―' // U+2015 HORIZONTAL BAR
|
|
160
|
+
}
|
|
161
|
+
const DASH_CHARS = new Set(Object.keys(DASH_LOOKALIKES))
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* `formatTokenReportRow`'s own table cells escape `|` as `\|` because
|
|
165
|
+
* `splitTableRow` reads that convention back on the other side (`#313`).
|
|
166
|
+
* This line has no such reader — nothing unescapes a backslash out of it —
|
|
167
|
+
* so a literal `\|` here would just be a backslash followed by a visible
|
|
168
|
+
* bar, one more hazardous character rather than fewer. A same-glyph
|
|
169
|
+
* lookalike, matching `DASH_LOOKALIKES`'s own approach, neutralizes the
|
|
170
|
+
* delimiter unconditionally (unlike a dash, no ordinary model id legitimately
|
|
171
|
+
* contains a pipe, so there is no adjacency case to preserve): an
|
|
172
|
+
* attacker-controlled `model` field (`#313`'s live reproduction: a transcript
|
|
173
|
+
* whose `message.model` read `attacker | evil-injected-cell | extra`) must
|
|
174
|
+
* not survive with a real `|` if this line is later quoted verbatim inside
|
|
175
|
+
* an actual markdown table cell by anything downstream — `pr report --write`
|
|
176
|
+
* already escapes correctly at its own render step (`formatTokenReportRow`),
|
|
177
|
+
* but this line, not that one, is what `#313`'s reproduction actually
|
|
178
|
+
* printed, and it carries no such guarantee of its own once it leaves here.
|
|
179
|
+
*/
|
|
180
|
+
const PIPE_LOOKALIKE = '|' // U+FF5C FULLWIDTH VERTICAL LINE
|
|
181
|
+
|
|
182
|
+
function sanitizeForTokensLine(value: string): string {
|
|
183
|
+
const stripped = stripNewlines(value)
|
|
184
|
+
let result = ''
|
|
185
|
+
for (let i = 0; i < stripped.length; i++) {
|
|
186
|
+
const ch = stripped[i] as string
|
|
187
|
+
if (ch === '|') {
|
|
188
|
+
result += PIPE_LOOKALIKE
|
|
189
|
+
continue
|
|
190
|
+
}
|
|
191
|
+
if (DASH_CHARS.has(ch)) {
|
|
192
|
+
const leftReachable = i === 0 || /\s/.test(stripped[i - 1] as string)
|
|
193
|
+
const rightReachable = i === stripped.length - 1 || /\s/.test(stripped[i + 1] as string)
|
|
194
|
+
if (leftReachable && rightReachable) {
|
|
195
|
+
result += DASH_LOOKALIKES[ch]
|
|
196
|
+
continue
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
result += ch
|
|
200
|
+
}
|
|
201
|
+
return result
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** Shared by `formatTokensLine` and `formatTokenReportRow` — one place that turns a summary into the model/tokensIn/tokensOut cells both grammars report, so the two shapes can never drift on the arithmetic. `model` is `null` rather than the `—` placeholder when neither `modelOverride` nor the summary supplies one — that placeholder is a sentinel THIS module emits, never untrusted content, and must never be run through either grammar's sanitizer (which would rewrite its `—` into something that no longer reads as "unknown"). Each caller substitutes the literal `—` for `null` itself, after sanitizing everything that came from `input`. */
|
|
205
|
+
function renderCells(input: TokensLineInput): { model: string | null; tokensIn: string; tokensOut: string } {
|
|
206
|
+
const model = input.modelOverride ?? input.summary?.model ?? null
|
|
207
|
+
if (!input.summary) return { model, tokensIn: '—', tokensOut: '—' }
|
|
208
|
+
const { inputTokens, cacheCreationInputTokens, cacheReadInputTokens, outputTokens } = input.summary.components
|
|
209
|
+
const tokensIn = inputTokens + cacheCreationInputTokens + cacheReadInputTokens
|
|
210
|
+
return { model, tokensIn: String(tokensIn), tokensOut: String(outputTokens) }
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export function formatTokensLine(input: TokensLineInput): string {
|
|
214
|
+
const { model, tokensIn, tokensOut } = renderCells(input)
|
|
215
|
+
const phase = sanitizeForTokensLine(input.phase)
|
|
216
|
+
const role = sanitizeForTokensLine(input.role)
|
|
217
|
+
const safeModel = model === null ? '—' : sanitizeForTokensLine(model)
|
|
218
|
+
if (!input.summary) {
|
|
219
|
+
return `Tokens: ${phase} — ${role} — ${safeModel} — —`
|
|
220
|
+
}
|
|
221
|
+
return `Tokens: ${phase} — ${role} — ${safeModel} — ${tokensIn}/${tokensOut}/—`
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
export type TokenReportRowInput = TokensLineInput & {
|
|
225
|
+
/** `YYYY-MM-DD`. Caller-supplied, never derived here — this file stays `Date.now()`-free per its purity charter above. */
|
|
226
|
+
date: string
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* The same cells `formatTokensLine` reports, rendered as one `| Phase | Role
|
|
231
|
+
* | Agent/Model | Tokens in | Tokens out | Cost | Date |` markdown-table row
|
|
232
|
+
* — the shape `aeg-root/roles/developer.md`'s "Token report" heading and
|
|
233
|
+
* `parse-token-report.ts`'s `parseTokenReportEntries` (table form) both
|
|
234
|
+
* already expect. `Cost` is always `—`, same reasoning as `formatTokensLine`'s
|
|
235
|
+
* own Cost cell: no maintained per-model pricing table exists in this package.
|
|
236
|
+
*/
|
|
237
|
+
export function formatTokenReportRow(input: TokenReportRowInput): string {
|
|
238
|
+
const { model, tokensIn, tokensOut } = renderCells(input)
|
|
239
|
+
const phase = sanitizeForTableCell(input.phase)
|
|
240
|
+
const role = sanitizeForTableCell(input.role)
|
|
241
|
+
const safeModel = model === null ? '—' : sanitizeForTableCell(model)
|
|
242
|
+
const date = sanitizeForTableCell(input.date)
|
|
243
|
+
return `| ${phase} | ${role} | ${safeModel} | ${tokensIn} | ${tokensOut} | — | ${date} |`
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Human-readable component breakdown for the reporter's own console output
|
|
248
|
+
* — never folded silently into the single `Tokens in` cell. Not parsed by
|
|
249
|
+
* anything; informational only.
|
|
250
|
+
*/
|
|
251
|
+
export function formatBreakdown(summary: TranscriptSummary): string {
|
|
252
|
+
const { inputTokens, cacheCreationInputTokens, cacheReadInputTokens, outputTokens } = summary.components
|
|
253
|
+
return [
|
|
254
|
+
` fresh input tokens: ${inputTokens}`,
|
|
255
|
+
` cache creation tokens: ${cacheCreationInputTokens}`,
|
|
256
|
+
` cache read tokens: ${cacheReadInputTokens}`,
|
|
257
|
+
` output tokens: ${outputTokens}`,
|
|
258
|
+
` model: ${summary.model ?? '—'}`,
|
|
259
|
+
` messages summed: ${summary.messageCount}`
|
|
260
|
+
].join('\n')
|
|
261
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Retired vocabulary — mechanisms genuinely gone from AEG's own methodology
|
|
3
|
+
* (the decision log, the lock, the `team-leader` role, the `D-###` decision
|
|
4
|
+
* id, …) with no legitimate positive occurrence anywhere but the exempt
|
|
5
|
+
* lists below. This is `retired-vocabulary.test.ts`'s `RETIRED` array and
|
|
6
|
+
* the non-citation members of its `RETIRED_IN_PRODUCT` array (both target
|
|
7
|
+
* the same retired-mechanism concern; the split between the two vitest
|
|
8
|
+
* arrays there is organic history, not a semantic boundary) — the file this
|
|
9
|
+
* module was extracted from names the incident: five review rounds each
|
|
10
|
+
* declared the decision-log claim swept, and each time it resurfaced a few
|
|
11
|
+
* lines from where the previous pass fixed it. A rule enforced by attention,
|
|
12
|
+
* not a gate.
|
|
13
|
+
*
|
|
14
|
+
* Deliberately NOT `RETIRED_IN_PRODUCT`'s forge-number / tranche-slug /
|
|
15
|
+
* legacy-slug patterns: those ban a LIVE, unexplained citation, not a
|
|
16
|
+
* retired concept, and are already this package's own
|
|
17
|
+
* `checkUnresolvableReferences` (`reader-resolvable-prose.ts`) — shipping
|
|
18
|
+
* both under two check names would double-report the identical match. This
|
|
19
|
+
* module is deliberately the narrower half of that file's original scan.
|
|
20
|
+
*
|
|
21
|
+
* Content copied verbatim from `retired-vocabulary.test.ts`'s `RETIRED`
|
|
22
|
+
* (minus its citation members), `EXEMPT`, and the non-citation entries of
|
|
23
|
+
* `PATTERN_EXEMPT`, never re-derived — this module's whole purpose is
|
|
24
|
+
* giving that list a CheckSpec adapter, not re-litigating it. Every pattern
|
|
25
|
+
* here is POSIX-ERE-safe (no `\d`/`\w`/`\s`, no lookaheads) by the same
|
|
26
|
+
* discipline `reader-resolvable-prose.ts` documents, so `grep -E` (the
|
|
27
|
+
* vitest suite) and native `RegExp` (this evaluator) agree on every match.
|
|
28
|
+
*
|
|
29
|
+
* Zero I/O: every input (file paths + contents) is read by the adapter and
|
|
30
|
+
* passed in, same charter as `reader-resolvable-prose.ts`.
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
export type VocabSourceFile = { path: string; content: string }
|
|
34
|
+
|
|
35
|
+
export type VocabFinding = {
|
|
36
|
+
file: string
|
|
37
|
+
line: number
|
|
38
|
+
pattern: string
|
|
39
|
+
message: string
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** The retired mechanisms this scan bans as claims of current-ness — see the module header for what is deliberately NOT here. */
|
|
43
|
+
export const RETIRED_PATTERNS: readonly string[] = [
|
|
44
|
+
// the deleted decision-id format
|
|
45
|
+
String.raw`\bD-[0-9]{3}\b`,
|
|
46
|
+
'D-(###|NNN|nnn|xxx)',
|
|
47
|
+
// the retired record as a live, writable, required artifact, every
|
|
48
|
+
// inflection but never "decision logic"
|
|
49
|
+
'decision (entry|logged)',
|
|
50
|
+
'decision-log entry',
|
|
51
|
+
'decision log entry',
|
|
52
|
+
'decision log(s|ged|ging)?([^a-z]|$)',
|
|
53
|
+
'decision-log',
|
|
54
|
+
'decision entr',
|
|
55
|
+
'decisions? (are |is )?logged',
|
|
56
|
+
'log entries',
|
|
57
|
+
String.raw`decisions\.md`,
|
|
58
|
+
'decisions-legacy',
|
|
59
|
+
'CONTRADICTION',
|
|
60
|
+
'assumes Tier 3',
|
|
61
|
+
// the lock
|
|
62
|
+
'Lock: ?YES',
|
|
63
|
+
'Lock: ?NO',
|
|
64
|
+
'lock approvals?',
|
|
65
|
+
'approves locks',
|
|
66
|
+
'Conforms to lock',
|
|
67
|
+
'Challenges lock',
|
|
68
|
+
// checks deleted with the machinery
|
|
69
|
+
'checkDecisionNumbersFresh',
|
|
70
|
+
// the role that no longer exists
|
|
71
|
+
String.raw`roles/team-leader\.md`,
|
|
72
|
+
// the wreckage a citation strip leaves when it deletes the contents of a
|
|
73
|
+
// parenthetical and not the punctuation around it — the shape is banned,
|
|
74
|
+
// not one instance of it. `()` is deliberately absent: it is an ordinary
|
|
75
|
+
// function call, and banning it would make any TypeScript source unusable.
|
|
76
|
+
String.raw`\(,`,
|
|
77
|
+
String.raw`,\)`,
|
|
78
|
+
String.raw`\(\.\)`
|
|
79
|
+
]
|
|
80
|
+
|
|
81
|
+
/** Paths where a retired-vocabulary mention is legitimate: frozen archives and historical records. Substring match, same as the vitest suite's own `EXEMPT`. */
|
|
82
|
+
export const RETIRED_EXEMPT_SUBSTRINGS: readonly string[] = [
|
|
83
|
+
'docs/decisions-legacy.md',
|
|
84
|
+
'apps/herald-ai/docs/',
|
|
85
|
+
'apps/vada-ai/docs/',
|
|
86
|
+
'aeg-root/tranches/completed/',
|
|
87
|
+
'packages/aeg-core/src/docs/published-prose',
|
|
88
|
+
'packages/aeg-core/src/retired-vocabulary.test.ts',
|
|
89
|
+
'packages/aeg-core/src/retired-vocabulary.ts',
|
|
90
|
+
'/fixtures/',
|
|
91
|
+
'/node_modules/',
|
|
92
|
+
'/.next/',
|
|
93
|
+
'/.turbo/'
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Per-pattern exemptions on top of `RETIRED_EXEMPT_SUBSTRINGS`, for the
|
|
98
|
+
* handful of patterns with a real, load-bearing false-positive shape (a
|
|
99
|
+
* live doc that legitimately discusses the retired concept by name, or a
|
|
100
|
+
* same-shaped live feature). Copied verbatim from `retired-vocabulary.test.ts`'s
|
|
101
|
+
* `PATTERN_EXEMPT` — including entries for `apps/herald-ai`/`apps/vada-ai`
|
|
102
|
+
* paths this repo does not carry, since a nonexistent path costs nothing to
|
|
103
|
+
* keep and this module's whole point is not re-deriving the list.
|
|
104
|
+
*/
|
|
105
|
+
export const PATTERN_EXEMPT: Readonly<Record<string, readonly string[]>> = {
|
|
106
|
+
[String.raw`\bD-[0-9]{3}\b`]: ['./CLAUDE.md'],
|
|
107
|
+
[String.raw`decisions\.md`]: [
|
|
108
|
+
'docs-index.md',
|
|
109
|
+
'apps/vada-ai/specs/legacy/README.md',
|
|
110
|
+
'apps/vada-ai/specs/vada-product-spec.md',
|
|
111
|
+
'apps/vada-ai/web/CLAUDE.md',
|
|
112
|
+
'apps/vada-ai/CLAUDE.md'
|
|
113
|
+
],
|
|
114
|
+
'decisions-legacy': [
|
|
115
|
+
'packages/aeg-core/src/file-classify.ts',
|
|
116
|
+
'packages/aeg-core/src/file-classify.test.ts',
|
|
117
|
+
'packages/aeg-core/src/pr-tier.test.ts',
|
|
118
|
+
'docs-index.md',
|
|
119
|
+
'.claude/skills/database/SKILL.md',
|
|
120
|
+
'.claude/skills/vada-architecture/SKILL.md',
|
|
121
|
+
'apps/vada-ai/specs/vada-byok-principles.md',
|
|
122
|
+
'apps/vada-ai/web/CLAUDE.md',
|
|
123
|
+
'apps/vada-ai/CLAUDE.md'
|
|
124
|
+
],
|
|
125
|
+
CONTRADICTION: ['apps/vada-ai/specs/vada-reviewers-spec.md']
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function lineNumbers(content: string, pattern: RegExp): number[] {
|
|
129
|
+
const out: number[] = []
|
|
130
|
+
const lines = content.split('\n')
|
|
131
|
+
for (let i = 0; i < lines.length; i++) {
|
|
132
|
+
if (pattern.test(lines[i] ?? '')) out.push(i + 1)
|
|
133
|
+
}
|
|
134
|
+
return out
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Sweeps `files` for `RETIRED_PATTERNS`, skipping any file whose path
|
|
139
|
+
* contains a `RETIRED_EXEMPT_SUBSTRINGS` entry, or that pattern's own
|
|
140
|
+
* `PATTERN_EXEMPT` entry. Matching is per-line, case-sensitive — the same
|
|
141
|
+
* semantics `grep -E` (with no `-i`) gives the vitest suite this was
|
|
142
|
+
* extracted from.
|
|
143
|
+
*/
|
|
144
|
+
export function scanRetiredVocabulary(files: readonly VocabSourceFile[]): VocabFinding[] {
|
|
145
|
+
const findings: VocabFinding[] = []
|
|
146
|
+
for (const file of files) {
|
|
147
|
+
if (RETIRED_EXEMPT_SUBSTRINGS.some((e) => file.path.includes(e))) continue
|
|
148
|
+
for (const pattern of RETIRED_PATTERNS) {
|
|
149
|
+
const patternExempt = PATTERN_EXEMPT[pattern] ?? []
|
|
150
|
+
if (patternExempt.some((e) => file.path.includes(e))) continue
|
|
151
|
+
const re = new RegExp(pattern)
|
|
152
|
+
for (const line of lineNumbers(file.content, re)) {
|
|
153
|
+
findings.push({
|
|
154
|
+
file: file.path,
|
|
155
|
+
line,
|
|
156
|
+
pattern,
|
|
157
|
+
message: `claims a retired AEG mechanism is still live (matches /${pattern}/)`
|
|
158
|
+
})
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return findings
|
|
163
|
+
}
|