@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/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
- const parsed = JSON.parse(readFileSync2(file2, "utf8"));
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 join6 } from "path";
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 existsSync2, readFileSync as readFileSync3, statSync } from "fs";
17113
- import { basename, dirname, isAbsolute, join as join5, sep as sep2 } from "path";
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 writeFileSync3 } from "fs";
17126
- import { join as join7 } from "path";
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 existsSync3, readdirSync as readdirSync2, readFileSync as readFileSync6 } from "fs";
17131
- import { basename as basename3, join as join8, relative, sep as sep3 } from "path";
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 writeFileSync4 } from "fs";
17138
- import { join as join9 } from "path";
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 = join9(dataDir2, markerName);
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
- writeFileSync4(marker, String(Date.now()), { mode: DATA_FILE_MODE });
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 join11 } from "path";
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 writeFileSync5
17245
+ writeFileSync as writeFileSync6
17168
17246
  } from "fs";
17169
- import { join as join10 } from "path";
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, [join11(here, "reconcile.js"), sessionId, transcriptPath], {
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.