@akasecurity/ai-tc-claude-code 0.9.0 → 0.9.2
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/.claude-plugin/plugin.json +1 -1
- package/README.md +3 -1
- package/commands/setup.md +112 -29
- package/package.json +4 -4
- package/scripts/apply-suppressions.js +4607 -848
- package/scripts/backfill.js +2346 -639
- package/scripts/filescan.js +3554 -756
- package/scripts/firstrun.js +2132 -583
- package/scripts/intro.js +908 -168
- package/scripts/onboard.js +2140 -582
- package/scripts/post-tool-use.js +2344 -628
- package/scripts/pre-tool-use.js +2349 -633
- package/scripts/query.js +2133 -584
- package/scripts/reconcile.js +2158 -603
- package/scripts/remediate.js +2341 -640
- package/scripts/session-start.js +2216 -657
- package/scripts/start-light.js +911 -171
- package/scripts/statusline.js +2146 -587
- package/scripts/stop.js +965 -188
- package/scripts/triage-rubric.md +4 -3
- package/scripts/user-prompt-submit.js +2352 -636
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "aka",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.2",
|
|
4
4
|
"description": "AI Traffic Control — inspect and govern AI prompts in Claude Code. Detection runs locally; events are recorded to a local SQLite store on your machine.",
|
|
5
5
|
"homepage": "https://github.com/akasecurity/ai-tc",
|
|
6
6
|
"author": { "name": "AKA Security" }
|
package/README.md
CHANGED
|
@@ -7,7 +7,9 @@
|
|
|
7
7
|
|
|
8
8
|
The Claude Code plugin for **[AI Traffic Control](https://github.com/akasecurity/ai-tc)** (`ai-tc`). It hooks into a Claude Code session and inspects its traffic — prompts, tool calls, tool results, file reads — scanning each event against your rule packs and applying inline **warn / redact / block** policies. Every event is recorded to a local SQLite store at `~/.aka/data/aka.db`.
|
|
9
9
|
|
|
10
|
-
Detection runs entirely on your machine. There's no account and no backend — nothing
|
|
10
|
+
Detection runs entirely on your machine. There's no account and no backend — nothing is sent anywhere to be scanned.[^egress]
|
|
11
|
+
|
|
12
|
+
[^egress]: Live detection and enforcement run locally. The one exception is the **opt-in** `/aka:setup` calibration below: to rate what an initial history scan finds, its judge step sends those findings to the model API through the `claude` CLI — the same provider your Claude session already uses. For each finding that means the raw (unmasked) value including any secret, plus roughly 120 characters of the surrounding transcript text on either side (any other secrets detected in that window are masked). It runs only after you explicitly opt in, and it keeps those values out of your local Claude transcript — but a copy of them does leave the machine. Withdrawing the grant later stops future scans; it cannot recall what was already sent.
|
|
11
13
|
|
|
12
14
|
## Install
|
|
13
15
|
|
package/commands/setup.md
CHANGED
|
@@ -15,10 +15,18 @@ dashboard. Everything the user sees is derived from their _actual_ history — n
|
|
|
15
15
|
a fabricated or demo number. When there isn't enough history to judge, the wizard
|
|
16
16
|
falls back to a conservative severity-derived floor instead of guessing.
|
|
17
17
|
|
|
18
|
-
The false-positive/severity judgment
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
raw
|
|
18
|
+
The false-positive/severity judgment needs the raw (unmasked) findings to rate
|
|
19
|
+
them accurately, so it **sends them to the model API** through separate `claude`
|
|
20
|
+
CLI subprocesses (a large history is judged in several batches). Two things
|
|
21
|
+
cross for each finding: its **raw value**, and about **120 characters of the
|
|
22
|
+
surrounding transcript text** on either side of it (any other secrets detected in
|
|
23
|
+
that window are masked). Those subprocesses ask the `claude` CLI to write
|
|
24
|
+
no transcript, so the raw values do not enter this conversation or your scannable
|
|
25
|
+
history — but a copy of them **does leave the machine**, sent to the model
|
|
26
|
+
provider like any other Claude prompt. You act only on the raw-free plan the
|
|
27
|
+
subprocesses print back. The scan that produces those values is offered for
|
|
28
|
+
explicit consent in step 1, and that consent must state the model-API egress
|
|
29
|
+
plainly before it is given.
|
|
22
30
|
|
|
23
31
|
Follow the steps below **in order**. Nothing is written to the policy store
|
|
24
32
|
until step 5 (or a floor fallback in step 3 if the calibration can't complete).
|
|
@@ -63,8 +71,8 @@ node "${CLAUDE_PLUGIN_ROOT}/scripts/intro.js" "${CLAUDE_PLUGIN_ROOT}/.claude-plu
|
|
|
63
71
|
Before showing any recommended posture — the start-light default table in
|
|
64
72
|
step 2 or the calibrated posture in step 4 — look at the **current project's**
|
|
65
73
|
working tree yourself, with your own Read/Glob tools. There is no script for
|
|
66
|
-
this: it is your own reasoning over facts you read directly, not the
|
|
67
|
-
|
|
74
|
+
this: it is your own reasoning over facts you read directly, not the triage
|
|
75
|
+
subprocess's raw-free plan, and it needs no user interaction.
|
|
68
76
|
|
|
69
77
|
**In scope:** the manifest's declared frameworks/dependencies
|
|
70
78
|
(`package.json` or equivalent), payment or other third-party API SDKs among
|
|
@@ -101,7 +109,7 @@ posture the user reads, not a separate write. Persisting a tightened level happe
|
|
|
101
109
|
only where the wizard already writes a per-category override — the adjust fork's
|
|
102
110
|
`onboard.js --posture` write (step 4b), where the user picks each category's level
|
|
103
111
|
explicitly. The keep-defaults path writes the severity floor (`--floor`, step 2)
|
|
104
|
-
and the calibrated accept path applies the
|
|
112
|
+
and the calibrated accept path applies the triage subprocess's saved plan
|
|
105
113
|
verbatim (`--confirmed --plan`, step 5); neither carries the tightening on its
|
|
106
114
|
own, so a tightened level the user wants persisted is chosen through the adjust
|
|
107
115
|
fork. Do **not** bolt on an extra `onboard.js --posture` overlay to auto-re-persist
|
|
@@ -124,18 +132,36 @@ interactive picker. The plugin can't draw its own selectable UI (it can't
|
|
|
124
132
|
capture keystrokes), so do **not** print a fake option list or ask the user to
|
|
125
133
|
"reply with a number"; let the picker collect the answer.
|
|
126
134
|
|
|
127
|
-
**
|
|
135
|
+
**Disclose the model-API egress plainly before you show the picker — this is what
|
|
136
|
+
the user is consenting to, so it must be visible before they choose.** State it in
|
|
137
|
+
your own words, without softening it: if they say yes, AKA scans the last 30 days
|
|
138
|
+
of Claude history, and to rate what it finds it **sends the raw, unmasked values —
|
|
139
|
+
including any secrets — to the model API through the `claude` CLI**. Name what
|
|
140
|
+
travels with each one: **its raw value, and about 120 characters of the
|
|
141
|
+
surrounding transcript text on either side** (any other secrets detected in that
|
|
142
|
+
window are masked). That is real network egress to the model provider (the same one your
|
|
143
|
+
Claude session already uses), not a purely local review. **A copy of each value
|
|
144
|
+
leaves the machine.** The transcripts those values came from stay on disk
|
|
145
|
+
untouched — nothing here removes them; that is the separate redaction step in
|
|
146
|
+
step 6. The values are kept out of your local Claude transcript, and the findings
|
|
147
|
+
are also recorded, masked, to the local store. The grant is revocable from the
|
|
148
|
+
dashboard's **Settings → Historical access**, which stops future scans — it
|
|
149
|
+
cannot recall anything already sent. Do not present the picker until you have
|
|
150
|
+
said this.
|
|
151
|
+
|
|
152
|
+
**Want me to look over what Claude's been up to?** — "I'll scan Claude's recent work — transcripts, temp files, agent memory — and send what I find to the model to rate it, so I can tune what I bring you next."
|
|
128
153
|
|
|
129
154
|
Offer exactly two options:
|
|
130
155
|
|
|
131
|
-
- **Yes, take a look** — "
|
|
156
|
+
- **Yes, take a look** — "scan my real work here; raw findings go to the model to be rated, then tune what you bring me"
|
|
132
157
|
- **Not now** — "start light and I'll learn as we go"
|
|
133
158
|
|
|
134
159
|
Choosing **Yes, take a look** records the same historical-review consent the wizard has
|
|
135
|
-
always recorded — the identical scope
|
|
136
|
-
|
|
137
|
-
about what AKA may access. Those granular scope and revocation details
|
|
138
|
-
inspectable on request and in the dashboard
|
|
160
|
+
always recorded — the identical scope (which includes the model-API judgment disclosed
|
|
161
|
+
above), the one-time grant, and the same revocation semantics — so the simpler question
|
|
162
|
+
broadens nothing about what AKA may access. Those granular scope and revocation details
|
|
163
|
+
stay inspectable on request and in the dashboard, under **Settings → Historical access**,
|
|
164
|
+
whose own copy repeats the model-API disclosure.
|
|
139
165
|
|
|
140
166
|
## 2. Save the answer, then branch
|
|
141
167
|
|
|
@@ -221,10 +247,62 @@ it.
|
|
|
221
247
|
step 6 already follows when no calibration frame was emitted). Step 7
|
|
222
248
|
then runs as written.
|
|
223
249
|
|
|
224
|
-
## 3. Run the evidence triage —
|
|
250
|
+
## 3. Run the evidence triage — off-transcript judgment, nothing written yet
|
|
225
251
|
|
|
226
|
-
|
|
227
|
-
|
|
252
|
+
**Model-judge consent — a distinct opt-in, asked here before the pipe.** The
|
|
253
|
+
false-positive/severity judgment runs by sending each finding to the Anthropic
|
|
254
|
+
model API through `claude`. That is a separate egress from the historical-read
|
|
255
|
+
consent collected in step 1 (which only let AKA _read_ the local transcripts), so
|
|
256
|
+
it needs its own explicit grant. Before running the pipe, state plainly what
|
|
257
|
+
leaves the machine, then use **AskUserQuestion** — the built-in picker (never a
|
|
258
|
+
printed numbered list) — to collect the answer.
|
|
259
|
+
|
|
260
|
+
Say plainly, before the picker: to sort real leaks from routine noise, AKA sends
|
|
261
|
+
each finding's `rawMatch` (the raw detected value) plus the surrounding context
|
|
262
|
+
window to the model API via `claude`. The **`filePath` is not sent**, and any
|
|
263
|
+
secrets detected in that context window are **masked** before it goes — so the
|
|
264
|
+
finding's own value is the only raw value that leaves. Nothing else about the
|
|
265
|
+
finding or the file crosses. Note that masking covers the secrets AKA's rules
|
|
266
|
+
detect; ordinary text in that window travels as-is.
|
|
267
|
+
|
|
268
|
+
**Send findings to the model to sort real leaks from noise?** — "I'll send each
|
|
269
|
+
detected value, plus a bit of surrounding context with any secrets in it masked,
|
|
270
|
+
to the model to tell real leaks from routine noise. The file path stays local."
|
|
271
|
+
|
|
272
|
+
- **Yes, send them** — "let the model triage what I found"
|
|
273
|
+
- **No, keep it local** — "skip the model triage and start from the safe defaults"
|
|
274
|
+
|
|
275
|
+
Present both options flat — this grant sends the user's data off the machine, so
|
|
276
|
+
do **not** mark either one recommended.
|
|
277
|
+
|
|
278
|
+
**Branch on the choice:**
|
|
279
|
+
|
|
280
|
+
- **If the user chose "Yes, send them"** — record the model-judge consent, then
|
|
281
|
+
run the pipe below:
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
node "${CLAUDE_PLUGIN_ROOT}/scripts/onboard.js" --model-judge-consent
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
- **If the user chose "No, keep it local"** — do **not** run the pipe. The judge
|
|
288
|
+
refuses to run without consent (it would only print a clean skip line), so there
|
|
289
|
+
is no calibrated plan to confirm. Fall back to the conservative severity floor,
|
|
290
|
+
tell the user the model triage was skipped, and continue to step 6:
|
|
291
|
+
|
|
292
|
+
```bash
|
|
293
|
+
node "${CLAUDE_PLUGIN_ROOT}/scripts/onboard.js" --floor
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
Say plainly: the model triage was declined, so AKA is starting from the
|
|
297
|
+
conservative severity floor instead of a calibrated posture, and it can be
|
|
298
|
+
re-run any time with `/aka:setup`. Declining here only skips this run — it does
|
|
299
|
+
**not** withdraw a grant made earlier; a stored grant is revoked under
|
|
300
|
+
**Settings → Model-judge consent** in the dashboard. **Skip steps 4 and 5** —
|
|
301
|
+
there is no plan to confirm — and rejoin the spine at step 6 with **no
|
|
302
|
+
`--surfaced`** (the same floor-fallback rule step 6 already follows).
|
|
303
|
+
|
|
304
|
+
On the **Yes, send them** path, pipe the backfill's triage stream straight into
|
|
305
|
+
the `apply-suppressions` adapter in **PREVIEW** mode (no `--confirmed`):
|
|
228
306
|
|
|
229
307
|
```bash
|
|
230
308
|
node "${CLAUDE_PLUGIN_ROOT}/scripts/backfill.js" --triage | node "${CLAUDE_PLUGIN_ROOT}/scripts/apply-suppressions.js"
|
|
@@ -233,8 +311,11 @@ node "${CLAUDE_PLUGIN_ROOT}/scripts/backfill.js" --triage | node "${CLAUDE_PLUGI
|
|
|
233
311
|
The backfill sweeps prior Claude Code transcripts (last 30 days, all projects)
|
|
234
312
|
and streams one masked-plus-raw triage hit per line; masked findings are
|
|
235
313
|
recorded to the local store as a side effect. The adapter runs the
|
|
236
|
-
false-positive/severity **judgment in
|
|
237
|
-
|
|
314
|
+
false-positive/severity **judgment in separate `claude` subprocesses that send the
|
|
315
|
+
raw hits — each one's value and its surrounding transcript text (other secrets in
|
|
316
|
+
that window masked) — to the model API** (a large history is split into several batches; each asks
|
|
317
|
+
the CLI to write no local transcript), then prints back a **raw-free plan** you
|
|
318
|
+
can safely show the user:
|
|
238
319
|
the calibrated-result card (the real-count headline and the recommended posture),
|
|
239
320
|
the per-category reasoning, the masked false positives it would suppress, any
|
|
240
321
|
categories it skipped, and its notes.
|
|
@@ -269,7 +350,8 @@ names its pattern and count from — never invent either off-signal.
|
|
|
269
350
|
|
|
270
351
|
Everything you show the user in step 4 comes from **this command's output**. You
|
|
271
352
|
never read the raw finding values yourself — do not echo, quote, or reconstruct
|
|
272
|
-
them;
|
|
353
|
+
them; the judge subprocesses send them to the model API and return only the
|
|
354
|
+
raw-free plan, so they never enter this conversation.
|
|
273
355
|
|
|
274
356
|
**Failed or truncated triage — never proceed silently (fallback).** If this
|
|
275
357
|
command exits non-zero, or the adapter reports a truncated / sentinel-less
|
|
@@ -685,23 +767,24 @@ interface + terminal dashboard and on-demand scans."
|
|
|
685
767
|
- **Not now** — "skip — you can add it anytime with the one-liner below"
|
|
686
768
|
|
|
687
769
|
**Yes, add it** is the install authorization — run the bootstrap installer
|
|
688
|
-
directly, with no second picker (it
|
|
689
|
-
|
|
770
|
+
directly, with no second picker (it downloads the self-contained `aka` binary for
|
|
771
|
+
their platform — no Node.js or npm required — and links it onto PATH). Run the
|
|
772
|
+
line for their OS:
|
|
690
773
|
|
|
691
774
|
```bash
|
|
692
775
|
# macOS / Linux
|
|
693
|
-
curl -fsSL https://raw.githubusercontent.com/akasecurity/ai-tc/
|
|
776
|
+
curl -fsSL https://raw.githubusercontent.com/akasecurity/ai-tc/bin-latest/tools/installer/install.sh | sh
|
|
694
777
|
|
|
695
778
|
# Windows (PowerShell)
|
|
696
|
-
irm https://raw.githubusercontent.com/akasecurity/ai-tc/
|
|
779
|
+
irm https://raw.githubusercontent.com/akasecurity/ai-tc/bin-latest/tools/installer/install.ps1 | iex
|
|
697
780
|
```
|
|
698
781
|
|
|
699
|
-
The one-liner pins to the
|
|
700
|
-
each release
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
instead, set `AKA_INSTALL_REF=
|
|
704
|
-
|
|
782
|
+
The one-liner pins to the latest published binary release **tag** (`bin-latest`),
|
|
783
|
+
never `main` — each binary release (`bin-v*`) moves that tag to its commit, and
|
|
784
|
+
the installer verifies the downloaded binary against the release's `SHA256SUMS`
|
|
785
|
+
(fail-closed), so a corrupted or tampered download is refused. To pin an exact
|
|
786
|
+
version instead, set `AKA_INSTALL_REF=bin-v<version>` before running the line. If
|
|
787
|
+
no `bin-v*` release exists yet the one-liner fails closed rather than guessing.
|
|
705
788
|
|
|
706
789
|
After it completes, point them at `aka init` then `aka dashboard`. If they chose
|
|
707
790
|
**Not now**, show the one-liner once so they can add it later, and move on —
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@akasecurity/ai-tc-claude-code",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.2",
|
|
4
4
|
"description": "AI Traffic Control — inspect and govern AI prompts in Claude Code",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -28,11 +28,11 @@
|
|
|
28
28
|
"vitest": "^4.1.10",
|
|
29
29
|
"zod": "^4.0.0",
|
|
30
30
|
"@akasecurity/eslint-config": "0.8.0",
|
|
31
|
-
"@akasecurity/plugin-sdk": "0.8.0",
|
|
32
31
|
"@akasecurity/persistence": "0.8.0",
|
|
33
|
-
"@akasecurity/
|
|
32
|
+
"@akasecurity/plugin-runtime": "0.8.0",
|
|
33
|
+
"@akasecurity/plugin-sdk": "0.8.0",
|
|
34
34
|
"@akasecurity/schema": "0.8.0",
|
|
35
|
-
"@akasecurity/
|
|
35
|
+
"@akasecurity/scanner": "0.8.0"
|
|
36
36
|
},
|
|
37
37
|
"scripts": {
|
|
38
38
|
"build": "tsup",
|