@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.
- package/.claude-plugin/plugin.json +1 -1
- package/README.md +4 -1
- package/commands/setup.md +216 -48
- package/hooks/hooks.json +1 -1
- package/package.json +6 -5
- package/scripts/apply-suppressions.js +23531 -0
- package/scripts/backfill.js +1537 -895
- package/scripts/filescan.js +1335 -864
- package/scripts/firstrun.js +1367 -869
- package/scripts/intro.js +78 -11
- package/scripts/onboard.js +5773 -40
- package/scripts/post-tool-use.js +1371 -879
- package/scripts/pre-tool-use.js +1471 -892
- package/scripts/query.js +1328 -857
- package/scripts/reconcile.js +1339 -869
- package/scripts/session-start.js +1390 -911
- package/scripts/statusline.js +1327 -856
- package/scripts/stop.js +97 -19
- package/scripts/triage-rubric.md +84 -0
- package/scripts/user-prompt-submit.js +1342 -871
package/scripts/stop.js
CHANGED
|
@@ -15233,6 +15233,11 @@ var AuditEventType = external_exports.enum([
|
|
|
15233
15233
|
"prompt",
|
|
15234
15234
|
"response",
|
|
15235
15235
|
"code_change",
|
|
15236
|
+
// The events.kind of a scanned tool call, widened in to keep this a
|
|
15237
|
+
// superset. Narrower than 'tool_call' above and not a duplicate of it:
|
|
15238
|
+
// 'tool_call' is the reconciler's structural row for every call, while
|
|
15239
|
+
// 'tool_use' exists only where a hook enforced against the arguments.
|
|
15240
|
+
"tool_use",
|
|
15236
15241
|
// One row per config-inventory scan, hung off the session root. It is the
|
|
15237
15242
|
// fact the posture inspection findings reference (findings require an
|
|
15238
15243
|
// audit_event_id), and its started_at is the "scanned Nm ago" the read
|
|
@@ -15621,7 +15626,7 @@ var ActivityOverviewResponse = external_exports.object({
|
|
|
15621
15626
|
}).meta({ id: "ActivityOverviewResponse" });
|
|
15622
15627
|
|
|
15623
15628
|
// ../../packages/schema/src/zod/event.ts
|
|
15624
|
-
var EventKind = external_exports.enum(["prompt", "response", "code_change"]).meta({ id: "EventKind" });
|
|
15629
|
+
var EventKind = external_exports.enum(["prompt", "response", "code_change", "tool_use"]).meta({ id: "EventKind" });
|
|
15625
15630
|
var SourceTool = external_exports.enum(["claude-code", "claude-desktop", "cursor", "chatgpt", "github-copilot", "cli", "unknown"]).meta({ id: "SourceTool" });
|
|
15626
15631
|
var EventMetadata = external_exports.object({
|
|
15627
15632
|
sessionId: external_exports.string().optional(),
|
|
@@ -15934,7 +15939,7 @@ var DetectionException = external_exports.object({
|
|
|
15934
15939
|
justification: external_exports.string().min(1),
|
|
15935
15940
|
conditions: ExceptionConditions.nullable(),
|
|
15936
15941
|
createdBy: external_exports.string(),
|
|
15937
|
-
createdVia: external_exports.enum(["cli-approve", "cli-add", "web-approve", "web-add", "api"]),
|
|
15942
|
+
createdVia: external_exports.enum(["cli-approve", "cli-add", "web-approve", "web-add", "api", "setup-triage"]),
|
|
15938
15943
|
createdAt: external_exports.iso.datetime(),
|
|
15939
15944
|
updatedAt: external_exports.iso.datetime(),
|
|
15940
15945
|
// Revocation is terminal and retained — consumed/expired/revoked rows are
|
|
@@ -16105,6 +16110,24 @@ var PolicyBundle = external_exports.object({
|
|
|
16105
16110
|
}).meta({ id: "PolicyBundle" });
|
|
16106
16111
|
var OBSERVE_ONLY_CATEGORIES = ["config"];
|
|
16107
16112
|
var ENFORCEABLE_CATEGORIES = DetectionCategory.options.filter((c) => !OBSERVE_ONLY_CATEGORIES.includes(c));
|
|
16113
|
+
var CATEGORY_PEAK_SEVERITY = {
|
|
16114
|
+
secret: "critical",
|
|
16115
|
+
financial: "critical",
|
|
16116
|
+
// core-financial/credit-card
|
|
16117
|
+
code_flaw: "critical",
|
|
16118
|
+
pii: "high",
|
|
16119
|
+
phi: "high",
|
|
16120
|
+
custom: "high",
|
|
16121
|
+
// user-defined; conservative
|
|
16122
|
+
code_context: "low",
|
|
16123
|
+
config: "low"
|
|
16124
|
+
// observe-only; floors to monitor regardless
|
|
16125
|
+
};
|
|
16126
|
+
function severityFloorPolicy(category) {
|
|
16127
|
+
if (OBSERVE_ONLY_CATEGORIES.includes(category)) return "monitor";
|
|
16128
|
+
const peak = CATEGORY_PEAK_SEVERITY[category];
|
|
16129
|
+
return peak === "critical" || peak === "high" ? "warn" : "monitor";
|
|
16130
|
+
}
|
|
16108
16131
|
var PolicyKind = external_exports.enum(["builtin", "custom"]).meta({ id: "PolicyKind" });
|
|
16109
16132
|
var KNOWN_BUILTIN_IDS = ["monitor", "warn", "redact", "block"];
|
|
16110
16133
|
var BuiltinPolicyId = external_exports.enum(KNOWN_BUILTIN_IDS).meta({ id: "BuiltinPolicyId" });
|
|
@@ -16130,6 +16153,12 @@ var BUILTIN_POLICY_SPECS = {
|
|
|
16130
16153
|
description: "Refuse the request entirely whenever any rule in this detection matches."
|
|
16131
16154
|
}
|
|
16132
16155
|
};
|
|
16156
|
+
function builtinPolicyToAction(id) {
|
|
16157
|
+
return BUILTIN_POLICY_SPECS[id].action;
|
|
16158
|
+
}
|
|
16159
|
+
var DEFAULT_ACTIONS = Object.fromEntries(
|
|
16160
|
+
DetectionCategory.options.map((c) => [c, builtinPolicyToAction(severityFloorPolicy(c))])
|
|
16161
|
+
);
|
|
16133
16162
|
var BUILTIN_POLICIES = Object.fromEntries(
|
|
16134
16163
|
KNOWN_BUILTIN_IDS.map((id) => [id, { id, ...BUILTIN_POLICY_SPECS[id] }])
|
|
16135
16164
|
);
|
|
@@ -16832,6 +16861,36 @@ var ExportSharesQuery = external_exports.object({
|
|
|
16832
16861
|
kind: external_exports.array(DestinationKind).optional()
|
|
16833
16862
|
});
|
|
16834
16863
|
|
|
16864
|
+
// ../../packages/schema/src/zod/triage.ts
|
|
16865
|
+
var TriageHit = external_exports.object({
|
|
16866
|
+
ruleId: external_exports.string(),
|
|
16867
|
+
category: DetectionCategory,
|
|
16868
|
+
severity: Severity,
|
|
16869
|
+
maskedMatch: external_exports.string(),
|
|
16870
|
+
rawMatch: external_exports.string(),
|
|
16871
|
+
context: external_exports.string(),
|
|
16872
|
+
filePath: external_exports.string().optional(),
|
|
16873
|
+
confidence: external_exports.number().min(0).max(1),
|
|
16874
|
+
id: external_exports.string().optional(),
|
|
16875
|
+
valueFingerprint: external_exports.string().optional(),
|
|
16876
|
+
keyVersion: external_exports.number().int().nonnegative().optional()
|
|
16877
|
+
});
|
|
16878
|
+
var TriagePolicy = BuiltinPolicyId;
|
|
16879
|
+
var TriageCategoryRec = external_exports.object({
|
|
16880
|
+
category: DetectionCategory,
|
|
16881
|
+
action: TriagePolicy,
|
|
16882
|
+
reasoning: external_exports.string(),
|
|
16883
|
+
genuineCount: external_exports.number().int().nonnegative(),
|
|
16884
|
+
fpCount: external_exports.number().int().nonnegative(),
|
|
16885
|
+
// TriageHit ids judged false-positive in this category. fpCount must equal
|
|
16886
|
+
// this array's length — enforced by the consumer, not this schema.
|
|
16887
|
+
fpIds: external_exports.array(external_exports.string())
|
|
16888
|
+
});
|
|
16889
|
+
var TriageRecommendation = external_exports.object({
|
|
16890
|
+
perCategory: external_exports.array(TriageCategoryRec),
|
|
16891
|
+
notes: external_exports.string()
|
|
16892
|
+
});
|
|
16893
|
+
|
|
16835
16894
|
// ../../packages/persistence/src/ids.ts
|
|
16836
16895
|
import { createHash } from "crypto";
|
|
16837
16896
|
|
|
@@ -16840,6 +16899,17 @@ import { chmodSync, mkdirSync } from "fs";
|
|
|
16840
16899
|
var DATA_DIR_MODE = 448;
|
|
16841
16900
|
var DATA_FILE_MODE = 384;
|
|
16842
16901
|
|
|
16902
|
+
// ../../packages/persistence/src/internal/json.ts
|
|
16903
|
+
function parseJsonObject(s) {
|
|
16904
|
+
if (s == null) return void 0;
|
|
16905
|
+
try {
|
|
16906
|
+
const parsed = JSON.parse(s);
|
|
16907
|
+
if (typeof parsed === "object" && parsed !== null) return parsed;
|
|
16908
|
+
} catch {
|
|
16909
|
+
}
|
|
16910
|
+
return void 0;
|
|
16911
|
+
}
|
|
16912
|
+
|
|
16843
16913
|
// ../../packages/persistence/src/repositories/activity.ts
|
|
16844
16914
|
var LIVE_ACTIVITY_WINDOW_MS = 30 * 6e4;
|
|
16845
16915
|
|
|
@@ -16921,14 +16991,19 @@ function readWorkspaceSettings(base = defaultDataDir()) {
|
|
|
16921
16991
|
}
|
|
16922
16992
|
}
|
|
16923
16993
|
function readJson(file2) {
|
|
16994
|
+
let text;
|
|
16924
16995
|
try {
|
|
16925
|
-
|
|
16926
|
-
return typeof parsed === "object" && parsed !== null ? parsed : null;
|
|
16996
|
+
text = readFileSync2(file2, "utf8");
|
|
16927
16997
|
} catch {
|
|
16928
16998
|
return null;
|
|
16929
16999
|
}
|
|
17000
|
+
return parseJsonObject(text) ?? null;
|
|
16930
17001
|
}
|
|
16931
17002
|
|
|
17003
|
+
// ../../packages/persistence/src/warn-era-cap.ts
|
|
17004
|
+
import { existsSync as existsSync2, writeFileSync as writeFileSync3 } from "fs";
|
|
17005
|
+
import { join as join5 } from "path";
|
|
17006
|
+
|
|
16932
17007
|
// ../../packages/plugin-sdk/src/provider-env.ts
|
|
16933
17008
|
var DEFAULT_ANTHROPIC_HOST = "api.anthropic.com";
|
|
16934
17009
|
var booleanish = external_exports.string().optional().transform((v) => {
|
|
@@ -17001,7 +17076,7 @@ function resolveProviderSafe() {
|
|
|
17001
17076
|
// ../../packages/plugin-sdk/src/config-inventory.ts
|
|
17002
17077
|
import { readdirSync, readFileSync as readFileSync4, realpathSync, statSync as statSync2 } from "fs";
|
|
17003
17078
|
import { homedir as homedir2 } from "os";
|
|
17004
|
-
import { basename as basename2, join as
|
|
17079
|
+
import { basename as basename2, join as join7 } from "path";
|
|
17005
17080
|
|
|
17006
17081
|
// ../../packages/detections/src/matchers/keyword.ts
|
|
17007
17082
|
var KeywordMatcher2 = class {
|
|
@@ -17109,8 +17184,8 @@ var CONFIG_POSTURE_RULES = [
|
|
|
17109
17184
|
];
|
|
17110
17185
|
|
|
17111
17186
|
// ../../packages/plugin-sdk/src/repo.ts
|
|
17112
|
-
import { existsSync as
|
|
17113
|
-
import { basename, dirname, isAbsolute, join as
|
|
17187
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3, statSync } from "fs";
|
|
17188
|
+
import { basename, dirname, isAbsolute, join as join6, sep as sep2 } from "path";
|
|
17114
17189
|
|
|
17115
17190
|
// ../../packages/plugin-sdk/src/events.ts
|
|
17116
17191
|
import { createHash as createHash3, randomUUID as randomUUID9 } from "crypto";
|
|
@@ -17122,29 +17197,32 @@ import { createHash as createHash4 } from "crypto";
|
|
|
17122
17197
|
import { arch, hostname as hostname3, platform, release } from "os";
|
|
17123
17198
|
|
|
17124
17199
|
// ../../packages/plugin-sdk/src/nudge.ts
|
|
17125
|
-
import { mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as
|
|
17126
|
-
import { join as
|
|
17200
|
+
import { mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync4 } from "fs";
|
|
17201
|
+
import { join as join8 } from "path";
|
|
17127
17202
|
|
|
17128
17203
|
// ../../packages/plugin-sdk/src/project-files.ts
|
|
17129
17204
|
var import_ignore = __toESM(require_ignore(), 1);
|
|
17130
|
-
import { existsSync as
|
|
17131
|
-
import { basename as basename3, join as
|
|
17205
|
+
import { existsSync as existsSync4, readdirSync as readdirSync2, readFileSync as readFileSync6 } from "fs";
|
|
17206
|
+
import { basename as basename3, join as join9, relative, sep as sep3 } from "path";
|
|
17132
17207
|
|
|
17133
17208
|
// ../../packages/plugin-sdk/src/runtime.ts
|
|
17134
17209
|
import { randomUUID as randomUUID10 } from "crypto";
|
|
17135
17210
|
|
|
17211
|
+
// ../../packages/plugin-sdk/src/suppressions.ts
|
|
17212
|
+
var THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1e3;
|
|
17213
|
+
|
|
17136
17214
|
// ../../packages/plugin-sdk/src/throttle.ts
|
|
17137
|
-
import { mkdirSync as mkdirSync4, statSync as statSync3, writeFileSync as
|
|
17138
|
-
import { join as
|
|
17215
|
+
import { mkdirSync as mkdirSync4, statSync as statSync3, writeFileSync as writeFileSync5 } from "fs";
|
|
17216
|
+
import { join as join10 } from "path";
|
|
17139
17217
|
function throttled(dataDir2, markerName, windowMs) {
|
|
17140
|
-
const marker =
|
|
17218
|
+
const marker = join10(dataDir2, markerName);
|
|
17141
17219
|
try {
|
|
17142
17220
|
if (Date.now() - statSync3(marker).mtimeMs < windowMs) return true;
|
|
17143
17221
|
} catch {
|
|
17144
17222
|
}
|
|
17145
17223
|
try {
|
|
17146
17224
|
mkdirSync4(dataDir2, { recursive: true, mode: DATA_DIR_MODE });
|
|
17147
|
-
|
|
17225
|
+
writeFileSync5(marker, String(Date.now()), { mode: DATA_FILE_MODE });
|
|
17148
17226
|
} catch {
|
|
17149
17227
|
}
|
|
17150
17228
|
return false;
|
|
@@ -17152,7 +17230,7 @@ function throttled(dataDir2, markerName, windowMs) {
|
|
|
17152
17230
|
|
|
17153
17231
|
// src/history/reconcile-trigger.ts
|
|
17154
17232
|
import { spawn } from "child_process";
|
|
17155
|
-
import { dirname as dirname2, join as
|
|
17233
|
+
import { dirname as dirname2, join as join12 } from "path";
|
|
17156
17234
|
import { fileURLToPath } from "url";
|
|
17157
17235
|
|
|
17158
17236
|
// src/history/tail.ts
|
|
@@ -17164,9 +17242,9 @@ import {
|
|
|
17164
17242
|
openSync,
|
|
17165
17243
|
readFileSync as readFileSync7,
|
|
17166
17244
|
readSync,
|
|
17167
|
-
writeFileSync as
|
|
17245
|
+
writeFileSync as writeFileSync6
|
|
17168
17246
|
} from "fs";
|
|
17169
|
-
import { join as
|
|
17247
|
+
import { join as join11 } from "path";
|
|
17170
17248
|
var SAFE_SESSION_ID = /^[A-Za-z0-9._-]+$/;
|
|
17171
17249
|
function safeSessionId(sessionId) {
|
|
17172
17250
|
if (SAFE_SESSION_ID.test(sessionId) && sessionId !== "." && sessionId !== "..") {
|
|
@@ -17183,7 +17261,7 @@ function triggerReconcile(dataDir2, sessionId, transcriptPath) {
|
|
|
17183
17261
|
const marker = `${RECONCILE_MARKER_PREFIX}-${safeSessionId(sessionId)}`;
|
|
17184
17262
|
if (throttled(dataDir2, marker, RECONCILE_THROTTLE_MS)) return;
|
|
17185
17263
|
const here = dirname2(fileURLToPath(import.meta.url));
|
|
17186
|
-
const child = spawn(process.execPath, [
|
|
17264
|
+
const child = spawn(process.execPath, [join12(here, "reconcile.js"), sessionId, transcriptPath], {
|
|
17187
17265
|
detached: true,
|
|
17188
17266
|
stdio: "ignore"
|
|
17189
17267
|
});
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# AKA setup-wizard triage prompt (draft — validation harness artifact)
|
|
2
|
+
|
|
3
|
+
You are the AKA Control Plane setup wizard's inline triage step. You have just
|
|
4
|
+
scanned a workspace (working tree and/or history) and detected a set of raw
|
|
5
|
+
hits — matches from AKA's deterministic regex detection rules, shown to you
|
|
6
|
+
with their real (unmasked) value and surrounding context so you can judge them
|
|
7
|
+
accurately. This is a one-time, transient look: the raw values are **never
|
|
8
|
+
persisted** — only your verdicts are written, as neutral exceptions and
|
|
9
|
+
per-category policies.
|
|
10
|
+
|
|
11
|
+
You will receive the hits below as a JSONL block, one `TriageHit` object per
|
|
12
|
+
line:
|
|
13
|
+
|
|
14
|
+
```
|
|
15
|
+
{"ruleId":"...","category":"...","severity":"...","maskedMatch":"...","rawMatch":"...","context":"...","filePath":"...","confidence":0.9}
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Step 1 — Silently filter false positives
|
|
19
|
+
|
|
20
|
+
Deterministic regex rules produce false positives as an expected cost —
|
|
21
|
+
placeholders, documentation examples, canonical fake values (`AKIAIOSFODNN7EXAMPLE`,
|
|
22
|
+
`123-45-6789`, `xxxx-xxxx-xxxx-xxxx`), and similar. Recognizing these is normal,
|
|
23
|
+
routine work, not a failure of the rules or the codebase — do **not** frame it
|
|
24
|
+
negatively (no "sloppy", "bad practice", or similar) in your reasoning or notes.
|
|
25
|
+
Silently drop what is clearly a false positive from your risk assessment; only
|
|
26
|
+
carry genuine hits forward as evidence of real exposure. Still count both —
|
|
27
|
+
your recommendation records `genuineCount` and `fpCount` per category so a
|
|
28
|
+
human reviewer can see the split.
|
|
29
|
+
|
|
30
|
+
## Step 2 — Calibrate a recommendation per category
|
|
31
|
+
|
|
32
|
+
For each category present in the hits, choose exactly one action, biased
|
|
33
|
+
toward the **least-restrictive action that still covers the real risk**:
|
|
34
|
+
|
|
35
|
+
| Action | Meaning |
|
|
36
|
+
| --------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
37
|
+
| `monitor` | Log only; nothing is blocked, warned, or altered. Right for FP-only or low-value audit-trail categories. |
|
|
38
|
+
| `warn` | Flag the request and let the user decide; nothing is modified automatically. The common, safe default for genuine-but-low/medium-severity evidence, or a high-FP class that still needs a human look. |
|
|
39
|
+
| `redact` | Replace the value with a safe placeholder before it leaves the machine — but **only in tool I/O** (file writes, bash, etc.). **`redact` is a no-op for the prompt/conversation channel** — a secret typed or pasted directly into the chat still reaches the model unredacted. Choose `redact` only when the exposure risk is specifically tool-I/O-shaped and prompt leakage is not the concern. |
|
|
40
|
+
| `block` | Refuse the action outright. Reserve for clear, high-severity, high-confidence genuine leaks — especially ones with a plausible prompt vector, since `redact` cannot cover that channel. |
|
|
41
|
+
|
|
42
|
+
Guidance:
|
|
43
|
+
|
|
44
|
+
- All-FP or irrelevant evidence (or low-value audit-trail signal, e.g. bare
|
|
45
|
+
`code_context` paths) → `monitor`.
|
|
46
|
+
- Genuine hits at low/medium severity, or a category with heavy FP density
|
|
47
|
+
that still deserves a human glance → `warn`. This is the expected common
|
|
48
|
+
outcome on a well-behaved corpus — recommending `warn` across the board is a
|
|
49
|
+
good, safe result, not under-protection.
|
|
50
|
+
- Genuine sensitive values that mainly travel through tool I/O (not the
|
|
51
|
+
prompt/conversation) → `redact`.
|
|
52
|
+
- Clear, high-severity, high-confidence genuine leaks, especially ones that
|
|
53
|
+
could reach the model via the prompt itself (where `redact` is a no-op) →
|
|
54
|
+
`block`.
|
|
55
|
+
|
|
56
|
+
## Output
|
|
57
|
+
|
|
58
|
+
Respond with your reasoning if you like, but end your reply with **exactly
|
|
59
|
+
one** fenced JSON block containing a `TriageRecommendation`:
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"perCategory": [
|
|
64
|
+
{
|
|
65
|
+
"category": "secret",
|
|
66
|
+
"action": "block",
|
|
67
|
+
"reasoning": "one or two sentences, no negative framing of the FPs",
|
|
68
|
+
"genuineCount": 2,
|
|
69
|
+
"fpCount": 2
|
|
70
|
+
}
|
|
71
|
+
],
|
|
72
|
+
"notes": ""
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
- Emit one `perCategory` entry for every category that appears in the input
|
|
77
|
+
hits (do not invent categories that were not present).
|
|
78
|
+
- `action` must be exactly one of `monitor`, `warn`, `redact`, `block`.
|
|
79
|
+
- `genuineCount` and `fpCount` are your counts of genuine vs. false-positive
|
|
80
|
+
hits you identified within that category (both required, both ≥ 0).
|
|
81
|
+
- `notes` is optional free text (empty string if nothing to add) for anything
|
|
82
|
+
that doesn't fit a single category — e.g. cross-category observations.
|
|
83
|
+
- The fenced ```json block must be the last thing in your reply and must
|
|
84
|
+
contain nothing but that one JSON object.
|