@akasecurity/ai-tc-claude-code 0.8.1 → 0.8.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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "aka",
3
- "version": "0.8.1",
3
+ "version": "0.8.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
@@ -31,7 +31,10 @@ The plugin installs Claude Code hooks that run locally with no `node_modules`, a
31
31
 
32
32
  - **SessionStart** — snapshot the session context.
33
33
  - **UserPromptSubmit** — scan prompts before they reach the model.
34
- - **PreToolUse** — scan tool inputs (Bash, Edit, Write, WebFetch) before they run.
34
+ - **PreToolUse** — scan tool inputs (Bash, Edit, Write, MultiEdit, NotebookEdit, WebFetch, Task, and
35
+ any `mcp__*` tool) before they run. Sensitive content in text a tool merely stores is masked in
36
+ place; in text a tool acts on — a shell command, a URL, an MCP argument — masking would change what
37
+ runs, so the call is blocked instead.
35
38
  - **PostToolUse** — scan tool outputs and file reads (Bash, Read, WebFetch) after they return.
36
39
  - **Stop** — reconcile token usage and finalize the session record.
37
40
 
package/commands/setup.md CHANGED
@@ -1,13 +1,30 @@
1
1
  ---
2
- description: Set up the AKA Control Plane plugin — redaction handling and historical access
2
+ description: Set up the AKA Control Plane plugin — evidence-first detection posture and historical access
3
3
  ---
4
4
 
5
5
  # AKA setup wizard
6
6
 
7
7
  You are onboarding the AKA Control Plane plugin for this machine. AKA works
8
8
  fully locally with **zero backend and zero Docker**: detection runs in-process
9
- and findings persist to a local SQLite store at `~/.aka/data/aka.db`. This
10
- wizard records two preferences. Ask the questions in order, then save once.
9
+ and findings persist to a local SQLite store at `~/.aka/data/aka.db`.
10
+
11
+ This wizard is **evidence-first**: instead of asking you to guess a global
12
+ redact/warn setting up front, it looks at your _actual_ history for real
13
+ leaked findings, triages them (silently filtering the routine false-positive
14
+ noise regex rules produce), and recommends a detection **posture per
15
+ category** (`secret`, `pii`, `financial`, `phi`, `code_context`, `code_flaw`,
16
+ `config`, `custom`) — shown to you with its reasoning — before anything is
17
+ written. If there isn't enough history to judge, or you decline the
18
+ historical review, it falls back to a conservative severity-derived floor
19
+ instead of guessing.
20
+
21
+ The false-positive/severity judgment itself runs in a **separate, transient
22
+ subprocess that writes no transcript** — the raw (unmasked) finding values are
23
+ never read into this conversation or your scannable history. You act only on the
24
+ raw-free plan that subprocess prints back.
25
+
26
+ Follow the steps below **in order**. Nothing is written to the policy store
27
+ until step 5 (or the floor branch in step 2).
11
28
 
12
29
  ## 0. Show the intro card
13
30
 
@@ -15,28 +32,20 @@ Run the intro script and show the user its output **exactly as printed** — it
15
32
  space-aligned monospace card (name, repository, version, what AKA adds). The script
16
33
  already prints it inside a Markdown code fence; reproduce that verbatim and do
17
34
  **not** add another code fence, strip the fence, or reformat it (unfenced, Markdown
18
- collapses the indentation and mangles the `●` line). Then continue with the two
19
- questions below.
35
+ collapses the indentation and mangles the `●` line).
20
36
 
21
37
  ```bash
22
38
  node "${CLAUDE_PLUGIN_ROOT}/scripts/intro.js" "${CLAUDE_PLUGIN_ROOT}/.claude-plugin/plugin.json"
23
39
  ```
24
40
 
25
- ## 1. Ask the two questions
41
+ ## 1. Ask historical-review consent
26
42
 
27
- Use the **AskUserQuestion** tool Claude Code's built-in interactive picker — to
28
- ask both questions. The plugin can't draw its own selectable UI (it can't
43
+ Ask this **before** anything about detection posture the posture
44
+ recommendation in step 4 is _derived from_ the answer to this question, so it
45
+ has to come first. Use the **AskUserQuestion** tool — Claude Code's built-in
46
+ interactive picker. The plugin can't draw its own selectable UI (it can't
29
47
  capture keystrokes), so do **not** print a fake option list or ask the user to
30
- "reply with a number"; let the picker collect the answers.
31
-
32
- Ask these two questions (a single AskUserQuestion call with both is fine):
33
-
34
- **Sensitive-data handling** — "When AKA detects sensitive data on its way to a model, it should:"
35
-
36
- - **Actively redact** → `redact` _(recommended)_ — replace secrets with safe
37
- placeholders before the request is sent.
38
- - **Warn only** → `warn` — flag the request and let the user decide; nothing is
39
- modified automatically. (Either mode can be changed per-project later.)
48
+ "reply with a number"; let the picker collect the answer.
40
49
 
41
50
  **Historical & memory access** — "Secrets often leak before AKA is installed. May I also review your temp files, agent memory & prior conversation transcripts?"
42
51
 
@@ -44,47 +53,206 @@ List **Grant full review** as the first (top) option:
44
53
 
45
54
  - **Grant full review** → `full` — scan scratch/temp files, agent memory & prior
46
55
  transcripts for leaked secrets (deepest coverage · one-time consent, revocable
47
- under Policies).
48
- - **Current session only** `session-only` — decline historical access; AKA
49
- reviews only what this session already touches. Even if declined, AKA can still
50
- review: the **working tree** (all source, config & dotfiles in the repo), **this
51
- session** (prompts, tool calls & files Claude reads or writes now), **git
52
- history** (commits reachable from HEAD, incl. removed-but-tracked secrets), and
53
- **pointed scans** (any path you explicitly hand AKA during a run).
56
+ under Policies). This is what lets AKA recommend a posture backed by your
57
+ real findings instead of a generic default.
58
+ - **Current session only** `session-only` decline historical access. AKA
59
+ starts in a conservative observe-first posture instead (step 2) and can
60
+ still review: the **working tree** (all source, config & dotfiles in the
61
+ repo), **this session** (prompts, tool calls & files Claude reads or writes
62
+ now), **git history** (commits reachable from HEAD, incl.
63
+ removed-but-tracked secrets), and **pointed scans** (any path you explicitly
64
+ hand AKA during a run).
65
+
66
+ Map the picked label to the flag value shown above (`full`/`session-only`).
67
+
68
+ ## 2. Save the historical answer, then branch
69
+
70
+ Run the onboarding writer with the answer from step 1. This must happen
71
+ **before** the backfill (step 3), because the backfill script reads
72
+ `historicalAccess` from the saved settings to decide whether it's allowed to
73
+ run. Omitting `--policy` is deliberate — the old global redact/warn toggle no
74
+ longer drives enforcement (posture is per-category now); its field is kept
75
+ for backward compatibility but this wizard doesn't ask about it.
76
+
77
+ ```bash
78
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/onboard.js" --historical <full|session-only>
79
+ ```
80
+
81
+ **Branch on the historical answer:**
82
+
83
+ - **If the user chose "Current session only" (`session-only`)** — there is no
84
+ history to calibrate a posture from. Write the severity-derived floor
85
+ immediately and skip straight to step 6 (first-run summary); steps 3–5 do
86
+ not run:
87
+
88
+ ```bash
89
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/onboard.js" --floor
90
+ ```
91
+
92
+ Briefly tell the user why: without evidence, AKA starts every high-impact
93
+ category (`secret`/`pii`/`financial`/`phi`/`code_flaw`/`custom`) at `warn`
94
+ so nothing is under-watched, and low-value/observe-only categories
95
+ (`code_context`/`config`) at `monitor` — conservative, no guessing. This can
96
+ be revisited any time via `/aka:setup` or Policies.
54
97
 
55
- Map the picked labels to the flag values shown above (`redact`/`warn`,
56
- `full`/`session-only`).
98
+ - **If the user chose "Grant full review" (`full`)** continue to step 3.
57
99
 
58
- ## 2. Save the answers
100
+ ## 3. Run the evidence triage — isolated judgment, nothing written yet
59
101
 
60
- Run the onboarding writer with the chosen values. Omit a flag to keep its
61
- default. This validates and persists to `~/.aka/settings/settings.json` (created
62
- `0600`, owner-only) and stamps the machine as onboarded:
102
+ Pipe the backfill's triage stream straight into the `apply-suppressions`
103
+ adapter in **PREVIEW** mode (no `--confirmed`):
63
104
 
64
105
  ```bash
65
- node "${CLAUDE_PLUGIN_ROOT}/scripts/onboard.js" --policy <redact|warn> --historical <full|session-only>
106
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/backfill.js" --triage | node "${CLAUDE_PLUGIN_ROOT}/scripts/apply-suppressions.js"
66
107
  ```
67
108
 
68
- ## 2.5 Scan history (only if they granted full review)
109
+ The backfill sweeps prior Claude Code transcripts (last 30 days, all projects)
110
+ and streams one masked-plus-raw triage hit per line; masked findings are
111
+ recorded to the local store as a side effect. The adapter runs the
112
+ false-positive/severity **judgment in a separate transient subprocess** (no
113
+ transcript), then prints back a **raw-free plan** you can safely show the user:
114
+ the per-category posture it would apply, the masked false positives it would
115
+ suppress, any categories it skipped, and its notes.
116
+
117
+ The preview also **persists that exact raw-free plan to a temp file and prints
118
+ its path** — a line beginning `Plan saved to: <path>`. Capture that path: step 5
119
+ applies **this saved plan verbatim**, so the confirm step performs no second scan
120
+ and no second judgment. (The plan file carries only masked/fingerprint/enum data;
121
+ it is deleted after a successful apply.)
122
+
123
+ Everything you show the user in step 4 comes from **this command's output**. You
124
+ never read the raw finding values yourself — do not echo, quote, or reconstruct
125
+ them; by design they stay inside the isolated subprocess.
126
+
127
+ **Failed or truncated triage — never proceed silently (fallback).** If this
128
+ command exits non-zero, or the adapter reports a truncated / sentinel-less
129
+ stream, the calibration could **not** complete. Do not guess a posture and do
130
+ not leave setup half-applied. Apply the conservative severity floor, **tell the
131
+ user it happened**, and continue to step 6:
69
132
 
70
- **Only when the user picked "Grant full review" (`historical=full`)**, run the
71
- backfill. It sweeps prior Claude Code transcripts (last 30 days, all projects)
72
- for secrets that leaked before AKA was installed and records them into the local
73
- store, so they show up in the first-run summary and `/findings`. The scan is
74
- idempotent it skips messages already recorded so re-running `/aka:setup` is
75
- safe and never duplicates findings. Show its output **exactly as printed** (it
76
- self-fences; do not add another fence or reformat). Skip this step entirely when
77
- they chose `session-only`.
133
+ ```bash
134
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/onboard.js" --floor
135
+ ```
136
+
137
+ Say plainly: the historical scan couldn't finish, so AKA is starting from the
138
+ conservative severity floor (high-impact categories at `warn`, observe-only at
139
+ `monitor`) instead of a calibrated posture, and it can be re-run any time with
140
+ `/aka:setup`.
141
+
142
+ **Nothing to calibrate.** If the adapter reports there were no triage hits to
143
+ review (an empty or intentionally-skipped scan), there's no evidence to
144
+ calibrate from: take the same floor branch (`onboard.js --floor`), tell the
145
+ user the scan found nothing to calibrate from, and skip to step 6.
146
+
147
+ Otherwise continue to step 4.
148
+
149
+ ## 4. Show the calibration and get explicit confirmation — before any write
150
+
151
+ The preview output is raw-free and has three parts. Show the user **all** of
152
+ them.
153
+
154
+ **Known limitation — the showcase is a first-run artifact.** The backfill records
155
+ each masked finding to the local store as a side effect, so a second `/aka:setup`
156
+ over the _same_ history dedups those already-recorded findings to zero triage hits
157
+ and the showcase comes back empty (the adapter reports "no triage hits to
158
+ review"). That is expected, not a failure: a re-run recalibrates **only if there
159
+ is genuinely new history** since the last run. The **first run's** showcase is the
160
+ one that matters — it is not reconstructed from the store on a re-run (the raw
161
+ values it needs are deliberately never persisted). If a re-run shows nothing to
162
+ calibrate, take the floor branch as usual and tell the user the scan found no new
163
+ history.
164
+
165
+ 1. **The per-category posture plan.** The action
166
+ (`monitor`/`warn`/`redact`/`block`) the writeback would set for every
167
+ category present in the evidence. Show it in full.
168
+ - **Surface every downgrade — this is not optional.** The preview flags any
169
+ category whose action would be **LOWERED** from a stronger existing setting
170
+ (e.g. an existing `block`/`redact` dropping to `warn`/`monitor`) and prints
171
+ a `WARNING` line summarizing them. Call these out prominently: a user who
172
+ hardened a category must **explicitly approve weakening it**. Never let an
173
+ enforcement downgrade through on the "apply as recommended" path without the
174
+ user having seen it.
175
+ - A category the adapter had to **skip** for its suppressions can still carry
176
+ a posture change; it appears in this plan too, so the user sees any posture
177
+ change even on a skipped category.
178
+ 2. **The intelligence showcase.** The masked-only per-category reasoning and
179
+ notes the judgment produced. Frame it as "look what it caught — and correctly
180
+ dismissed": the false-positive discard is as much the pitch as the catch (a
181
+ plain regex scanner would scream "161 CRITICAL secrets!"; AKA says "…all
182
+ placeholders — `warn` is enough"). Keep the framing neutral — no "sloppy" or
183
+ "bad practice".
184
+ 3. **The false positives to be suppressed (the human gate).** The masked value,
185
+ rule, and masked context for each detection the writeback would suppress.
186
+ This is the checkpoint that stops a genuine secret being silenced: the user
187
+ reads the masked evidence and approves it.
188
+
189
+ Then use **AskUserQuestion** (the real picker, never a printed numbered list) to
190
+ confirm:
191
+
192
+ **Apply this calibration?** — "Apply this detection posture and suppress the
193
+ false positives shown above?"
194
+
195
+ - **Yes, apply** _(recommended)_ — write the posture and suppressions exactly as
196
+ previewed.
197
+ - **Let me adjust a category** — override one or more categories before saving
198
+ (for example, keep a category the plan would lower).
199
+
200
+ If they choose to adjust, ask a follow-up **AskUserQuestion** per category,
201
+ offering the four actions with honest semantics so they choose with full
202
+ information: `monitor` logs only; `warn` flags the request and lets them decide;
203
+ `redact` strips the value from **tool I/O** but is a **no-op on the
204
+ prompt/conversation channel** (a secret pasted into chat still reaches the
205
+ model); `block` refuses the action outright. Collect the overrides as a
206
+ `{category: action}` map. Do **not** proceed to step 5 until the user has
207
+ explicitly confirmed.
208
+
209
+ ## 5. Write the posture and suppressions
210
+
211
+ On confirmation, run the adapter again with `--confirmed --plan <path>`, passing
212
+ the **plan-file path the preview printed in step 3** (`Plan saved to: <path>`). It
213
+ reads that saved plan back and applies it **exactly as previewed** — it overwrites
214
+ the per-category posture and writes one 30-day suppression per confirmed false
215
+ positive **without re-running the backfill or the judge**. There is deliberately
216
+ **no `backfill.js` pipe here**: re-scanning and re-judging would produce a fresh,
217
+ non-deterministic plan and silently defeat the human gate the user just approved.
218
+
219
+ The posture overwrite and the suppression writes are applied as a **single
220
+ all-or-nothing transaction**: a mid-batch failure rolls back the posture change
221
+ too, so the store is never left half-applied. That is why the floor fallback below
222
+ is safe — a non-zero exit means **nothing** persisted, so re-applying the
223
+ conservative floor cannot collide with a partially-written posture.
224
+
225
+ ```bash
226
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/apply-suppressions.js" --confirmed --plan <path>
227
+ ```
228
+
229
+ If `--plan` is missing or the file is unreadable/invalid, the adapter **fails loud
230
+ (non-zero) and writes nothing** — it never falls back to a re-judge. Treat that
231
+ like the `--confirmed` failure below: tell the user the write did not complete,
232
+ fall back to the floor, and continue to step 6.
233
+
234
+ If the user chose to **adjust** categories in step 4, apply their overrides on
235
+ top afterwards. `onboard.js --posture` overwrites only the categories in the map
236
+ it's given, leaving the rest as written by the adapter:
78
237
 
79
238
  ```bash
80
- node "${CLAUDE_PLUGIN_ROOT}/scripts/backfill.js"
239
+ node "${CLAUDE_PLUGIN_ROOT}/scripts/onboard.js" --posture '{"secret":"block"}'
81
240
  ```
82
241
 
83
- ## 3. Show the first-run summary
242
+ (The JSON is illustrative — pass only the categories the user changed, values
243
+ one of `monitor`/`warn`/`redact`/`block`.) This is the only point in the wizard
244
+ where a posture is persisted.
245
+
246
+ If the `--confirmed` run exits non-zero, tell the user the write did not
247
+ complete, fall back to the floor (`onboard.js --floor`), and continue to step 6
248
+ so setup still finishes.
249
+
250
+ ## 6. Show the first-run summary
84
251
 
85
252
  Run the first-run script and show its output **exactly as printed** (the
86
- install-complete summary with live findings/recommendation counts and the health
87
- score). The script already prints it inside a Markdown code fence; reproduce that
253
+ install-complete summary with live findings/recommendation counts, the health
254
+ score, and now the per-category posture just written or floored). The
255
+ script already prints it inside a Markdown code fence; reproduce that
88
256
  verbatim and do **not** add another code fence, strip the fence, or reformat it (it
89
257
  is space-aligned monospace that Markdown would otherwise collapse).
90
258
 
@@ -92,7 +260,7 @@ is space-aligned monospace that Markdown would otherwise collapse).
92
260
  node "${CLAUDE_PLUGIN_ROOT}/scripts/firstrun.js"
93
261
  ```
94
262
 
95
- ## 3.5 Offer the AKA CLI + local dashboard (opt-in)
263
+ ## 7. Offer the AKA CLI + local dashboard (opt-in)
96
264
 
97
265
  Now that the plugin is set up, offer the optional **AKA CLI + local dashboard** —
98
266
  a richer, still-fully-local surface over the same `~/.aka` store this plugin
@@ -136,8 +304,8 @@ what happened, show the one-liner so they can retry later, and continue the
136
304
  wizard normally. The plugin is already fully set up and works on its own; a
137
305
  failed CLI install changes nothing about that.
138
306
 
139
- ## 4. Report the result
307
+ ## 8. Report the result
140
308
 
141
- - The first-run summary already confirms the saved handling and points at
309
+ - The first-run summary already confirms the saved posture and points at
142
310
  `/health`. Add at most one short sentence: detection runs locally and nothing
143
311
  leaves the machine.
package/hooks/hooks.json CHANGED
@@ -24,7 +24,7 @@
24
24
  ],
25
25
  "PreToolUse": [
26
26
  {
27
- "matcher": "Bash|Edit|Write|WebFetch",
27
+ "matcher": "Bash|Edit|Write|WebFetch|MultiEdit|NotebookEdit|Task|mcp__.*",
28
28
  "hooks": [
29
29
  {
30
30
  "type": "command",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akasecurity/ai-tc-claude-code",
3
- "version": "0.8.1",
3
+ "version": "0.8.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",
@@ -21,22 +21,23 @@
21
21
  "access": "public"
22
22
  },
23
23
  "devDependencies": {
24
- "@types/node": "^26.1.1",
24
+ "@types/node": "^24.13.3",
25
25
  "eslint": "^9.0.0",
26
26
  "tsup": "^8.0.0",
27
27
  "typescript": "^5.8.0",
28
28
  "vitest": "^4.1.10",
29
+ "zod": "^4.0.0",
29
30
  "@akasecurity/eslint-config": "0.8.0",
30
31
  "@akasecurity/persistence": "0.8.0",
31
32
  "@akasecurity/plugin-runtime": "0.8.0",
32
33
  "@akasecurity/plugin-sdk": "0.8.0",
33
- "@akasecurity/scanner": "0.8.0",
34
- "@akasecurity/schema": "0.8.0"
34
+ "@akasecurity/schema": "0.8.0",
35
+ "@akasecurity/scanner": "0.8.0"
35
36
  },
36
37
  "scripts": {
37
38
  "build": "tsup",
38
39
  "dev": "tsup --watch",
39
- "lint": "eslint src",
40
+ "lint": "eslint src test",
40
41
  "test": "vitest run",
41
42
  "typecheck": "tsc --noEmit"
42
43
  }