@akasecurity/ai-tc-claude-code 0.9.10 → 0.9.12

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.
@@ -20630,6 +20630,15 @@ var FindingCategory = external_exports.enum([
20630
20630
  ]).meta({ id: "FindingCategory" });
20631
20631
  var FindingOrigin = external_exports.enum(["in-flight", "at-rest"]).meta({ id: "FindingOrigin" });
20632
20632
  var FindingStatus = external_exports.enum(["open", "handled", "resolved", "dismissed"]).meta({ id: "FindingStatus" });
20633
+ var SyncFailureReason = external_exports.enum(["deployment_refused", "payload_invalid", "detached_undelivered"]).meta({ id: "SyncFailureReason" });
20634
+ var FindingDeliveryState = external_exports.enum(["sent", "queued", "not_sent", "never_offered", "local_scan"]).meta({ id: "FindingDeliveryState" });
20635
+ var FindingDelivery = external_exports.object({
20636
+ state: FindingDeliveryState,
20637
+ // The delivery time for `sent`; the failure time for `not_sent` when recorded.
20638
+ at: external_exports.iso.datetime().optional(),
20639
+ // Only on `not_sent`, and only when a known reason was recorded.
20640
+ reason: SyncFailureReason.optional()
20641
+ }).meta({ id: "FindingDelivery" });
20633
20642
  var ResolutionMethod = external_exports.enum([
20634
20643
  "enforced-in-flight",
20635
20644
  "fixed-at-source",
@@ -20686,7 +20695,10 @@ var FindingInstance = external_exports.object({
20686
20695
  // The session that event belongs to, when it has one — the seam a
20687
20696
  // per-instance "view session" link needs. Absent for events captured
20688
20697
  // outside a session.
20689
- sessionId: external_exports.string().optional()
20698
+ sessionId: external_exports.string().optional(),
20699
+ // The delivery state of the event above (see FindingDelivery). Optional so
20700
+ // readers that do not project it stay valid.
20701
+ delivery: FindingDelivery.optional()
20690
20702
  }).meta({ id: "FindingInstance" });
20691
20703
  var FindingGroup = external_exports.object({
20692
20704
  id: external_exports.string(),
@@ -20703,13 +20715,11 @@ var FindingGroup = external_exports.object({
20703
20715
  latestDetectedAt: external_exports.iso.datetime(),
20704
20716
  instances: external_exports.array(FindingInstance),
20705
20717
  // Derived from instances' statuses with open-dominates precedence (see
20706
- // buildFindingGroups). Undefined only when no instance carries a status.
20718
+ // foldGroupStatus). Undefined only when no instance carries a status.
20707
20719
  status: FindingStatus.optional(),
20708
- // The distinct people across the WHOLE group, not just the `instances`
20709
- // preview — from the store's whole-group aggregate when it supplies one,
20710
- // else folded from the rows (see buildFindingGroups). Undefined when no
20711
- // instance carries a user, or when the store supplied whole-group folds
20712
- // without one.
20720
+ // The distinct people across the WHOLE group, not just the instances
20721
+ // carried here. Undefined when no instance carries a user, or when the
20722
+ // store supplied whole-group folds without one.
20713
20723
  users: external_exports.array(FindingUser).optional()
20714
20724
  }).meta({ id: "FindingGroup" });
20715
20725
  var FindingStats = external_exports.object({
@@ -20738,20 +20748,33 @@ var FindingFacets = external_exports.object({
20738
20748
  // counted under no value.
20739
20749
  status: external_exports.array(FindingFacetItem),
20740
20750
  // Host tool (attributes.tool_name). Present only on the instance-level
20741
- // reads, which can filter by it; the grouped read omits the dimension
20751
+ // reads, which can filter by it; the type-level read omits the dimension
20742
20752
  // because a group spans tools.
20743
- tool: external_exports.array(FindingFacetItem).optional()
20753
+ tool: external_exports.array(FindingFacetItem).optional(),
20754
+ // Delivery states (FindingDeliveryState). Present only on the
20755
+ // instance-level reads, like `tool`.
20756
+ deployment: external_exports.array(FindingFacetItem).optional()
20744
20757
  }).meta({ id: "FindingFacets" });
20745
- var ListGroupedFindingsQuery = external_exports.object({
20758
+ var FindingTypeSummary = FindingGroup.omit({ instances: true, match: true }).meta({
20759
+ id: "FindingTypeSummary"
20760
+ });
20761
+ var MAX_FINDING_TYPES_LIMIT = 100;
20762
+ var ListFindingTypesQuery = external_exports.object({
20746
20763
  // NOTE: severity filters by Severity (critical/high/medium/low), not by
20747
- // FindingAction.
20764
+ // FindingAction. It narrows TYPES: a type's severity is the one its newest
20765
+ // firing version carries, and this list pages types.
20766
+ //
20767
+ // That is NOT a claim the findings of a type share it. A rule can hold several
20768
+ // definition versions at different severities, so a type kept by this filter
20769
+ // can hold findings that individually do not match — see totals.findings on
20770
+ // ListFindingTypesResponse, which counts them all.
20748
20771
  severity: external_exports.array(Severity).optional(),
20749
20772
  subtype: external_exports.array(external_exports.string()).optional(),
20750
20773
  provider: external_exports.array(FindingProvider).optional(),
20751
20774
  action: external_exports.array(FindingAction).optional(),
20752
- // Matches a group's DERIVED status (see FindingGroup.status), not its
20753
- // individual instances' — so a filtered group's Status column always reads
20754
- // one of the requested values.
20775
+ // Matches a type's DERIVED status (see FindingGroup.status), not its
20776
+ // individual findings' — so a filtered row's status always reads one of the
20777
+ // requested values.
20755
20778
  status: external_exports.array(FindingStatus).optional(),
20756
20779
  q: external_exports.string().optional(),
20757
20780
  // Scope to findings whose event carries this session id (the Activity page's
@@ -20761,23 +20784,37 @@ var ListGroupedFindingsQuery = external_exports.object({
20761
20784
  // from a time-scoped page (Activity's range) can carry that scope. Absent
20762
20785
  // means all time — this list has no default window.
20763
20786
  from: external_exports.iso.datetime().optional(),
20764
- // A group or instance id that must appear in the page even when the cursor
20765
- // has already advanced past its sort position. This is what keeps the
20766
- // Findings page's one-shot ?finding= deep link resolving once the list
20767
- // paginates: the target group is appended out of sort order rather than
20768
- // scanning forward for it. Never affects totals, facets or the cursor.
20787
+ // A RULE id that must appear in the page even when the cursor has already
20788
+ // advanced past its sort position. This is what keeps the selected type
20789
+ // visible in the list once it paginates: the target is appended out of sort
20790
+ // order rather than scanned forward for. Never affects totals, facets or the
20791
+ // cursor. Unlike the grouped read this replaces, it names a rule only — an
20792
+ // instance id is resolved by `findingInstance`, which is a primary-key seek
20793
+ // and so is not bounded by what any page happens to hold.
20769
20794
  includeId: external_exports.string().optional(),
20770
- groupBy: external_exports.literal("type").optional(),
20771
- limit: external_exports.coerce.number().int().min(1).max(100).optional(),
20795
+ limit: external_exports.coerce.number().int().min(1).max(MAX_FINDING_TYPES_LIMIT).optional(),
20772
20796
  cursor: external_exports.string().optional()
20773
20797
  });
20774
- var ListGroupedFindingsResponse = external_exports.object({
20798
+ var ListFindingTypesResponse = external_exports.object({
20775
20799
  totals: external_exports.object({
20800
+ // Findings belonging to the matching TYPES — not findings that each match
20801
+ // the filters. The filters here select types, so a type that survives
20802
+ // contributes its whole instanceCount.
20803
+ //
20804
+ // `status` is the one exception, narrowed per finding via
20805
+ // countInstancesByStatus. `severity`, `provider` and `action` are not, so
20806
+ // this can exceed what the instance read reports for the same filters: a
20807
+ // rule whose severity moved between versions is kept on its newest and
20808
+ // still counts its older findings. Narrowing the other three needs
20809
+ // per-dimension counts the aggregate does not carry today.
20776
20810
  findings: external_exports.number().int().nonnegative(),
20777
- groups: external_exports.number().int().nonnegative()
20811
+ // Counts TYPES, which is the unit this read pages. The instance read's
20812
+ // own totals count findings; the two deliberately answer different
20813
+ // questions and are never summed.
20814
+ types: external_exports.number().int().nonnegative()
20778
20815
  }),
20779
20816
  facets: FindingFacets,
20780
- items: external_exports.array(FindingGroup),
20817
+ items: external_exports.array(FindingTypeSummary),
20781
20818
  nextCursor: external_exports.string().nullable(),
20782
20819
  // Present only on session-scoped queries (`sessionId` set): per ruleId, how
20783
20820
  // many times that rule fired in the session's persisted transcript. Findings
@@ -20785,7 +20822,7 @@ var ListGroupedFindingsResponse = external_exports.object({
20785
20822
  // every firing, so the two numbers legitimately differ — this map lets a
20786
20823
  // session-scoped view show both.
20787
20824
  sessionFirings: external_exports.record(external_exports.string(), external_exports.number().int().nonnegative()).optional()
20788
- }).meta({ id: "ListGroupedFindingsResponse" });
20825
+ }).meta({ id: "ListFindingTypesResponse" });
20789
20826
  var ApplyFindingActionRequest = external_exports.object({
20790
20827
  // 'quarantined' is system-assigned (see FindingAction) — clients may not set
20791
20828
  // it, so it is excluded from the request contract. The mapping helper
@@ -20814,16 +20851,19 @@ var FindingInstanceDetail = FindingInstance.extend({
20814
20851
  var MAX_FLAT_FINDINGS_LIMIT = 200;
20815
20852
  var ListFindingInstancesQuery = external_exports.object({
20816
20853
  severity: external_exports.array(Severity).optional(),
20817
- // Rule ids, the same vocabulary the grouped list's `subtype` carries.
20854
+ // Rule ids, the same vocabulary the types list's `subtype` carries. Pinning
20855
+ // ONE of them is how the master/detail view scopes its right-hand panel.
20818
20856
  subtype: external_exports.array(external_exports.string()).optional(),
20819
20857
  provider: external_exports.array(FindingProvider).optional(),
20820
20858
  action: external_exports.array(FindingAction).optional(),
20821
20859
  // Matches each instance's OWN derived status (deriveFindingStatus), unlike
20822
- // the grouped query's group-level fold.
20860
+ // the types query's type-level fold.
20823
20861
  status: external_exports.array(FindingStatus).optional(),
20824
20862
  // Exact host-tool names (attributes.tool_name, e.g. 'Bash'). A real filter,
20825
20863
  // where the free-text `q` can only match the rendered "via Bash" label.
20826
20864
  tool: external_exports.array(external_exports.string()).optional(),
20865
+ // The delivery state of each finding's event (see FindingDelivery).
20866
+ deployment: external_exports.array(FindingDeliveryState).optional(),
20827
20867
  // Exact repository / file-path matches, for the drill-down out of the
20828
20868
  // locations view. A row whose event carries no repo/file matches neither.
20829
20869
  repo: external_exports.string().optional(),
@@ -20836,37 +20876,50 @@ var ListFindingInstancesQuery = external_exports.object({
20836
20876
  });
20837
20877
  var ListFindingInstancesResponse = external_exports.object({
20838
20878
  // Instances matching the filters across the whole scope, not just this
20839
- // page — cursor-independent, like the grouped list's totals.
20879
+ // page — cursor-independent, like the types list's totals.
20840
20880
  totals: external_exports.object({ findings: external_exports.number().int().nonnegative() }),
20841
- // Counts in INSTANCES here, where the grouped response counts groups. Each
20881
+ // Counts in INSTANCES here, where the types response counts types. Each
20842
20882
  // dimension still excludes its own filter.
20843
20883
  facets: FindingFacets,
20844
20884
  items: external_exports.array(FindingInstanceDetail),
20845
20885
  nextCursor: external_exports.string().nullable()
20846
20886
  }).meta({ id: "ListFindingInstancesResponse" });
20847
- var FindingLocationFile = external_exports.object({
20848
- // Empty when the instances carried no file path (a prompt or a tool call
20849
- // with no file attribution).
20850
- file: external_exports.string(),
20851
- instanceCount: external_exports.number().int().nonnegative(),
20852
- maxSeverity: Severity,
20853
- latestDetectedAt: external_exports.iso.datetime(),
20854
- // Folded from the instances' derived statuses with the same
20855
- // open-dominates precedence a group uses.
20856
- status: FindingStatus.optional(),
20857
- // Distinct rules seen at this location, capped — the row shows them as
20858
- // chips, and the count is what conveys scale.
20859
- ruleIds: external_exports.array(external_exports.string())
20860
- }).meta({ id: "FindingLocationFile" });
20861
- var FindingLocationRepo = external_exports.object({
20887
+ var ListFindingInstancesPage = external_exports.object({
20888
+ items: external_exports.array(FindingInstanceDetail),
20889
+ nextCursor: external_exports.string().nullable()
20890
+ }).meta({ id: "ListFindingInstancesPage" });
20891
+ var FindingLocationSummary = external_exports.object({
20892
+ // Opaque, stable, minted from the pair by encodeLocationId. It exists
20893
+ // because a location's identity is two values and a URL param carries one:
20894
+ // `?loc=` names a location the way `?rule=` names a type. Only ever compared
20895
+ // for EQUALITY — the page's selection check, this read's `includeId`, the
20896
+ // client's page dedupe — never decoded, and never a sort key.
20897
+ id: external_exports.string(),
20862
20898
  /** Empty when the instances carried no repo attribute. */
20863
20899
  repo: external_exports.string(),
20900
+ // Empty when the instances carried no file path (a prompt, or a tool call
20901
+ // with no file attribution). Both halves empty is a real location — usually
20902
+ // the largest one in a store — and is selectable like any other.
20903
+ file: external_exports.string(),
20864
20904
  instanceCount: external_exports.number().int().nonnegative(),
20905
+ // The WORST severity present, not the first row's. It is this list's primary
20906
+ // sort key, so it is also what explains why a row is where it is, and it is
20907
+ // how a reader decides what to open without opening everything.
20865
20908
  maxSeverity: Severity,
20866
20909
  latestDetectedAt: external_exports.iso.datetime(),
20910
+ // Folded from the instances' derived statuses with the same open-dominates
20911
+ // precedence a group uses, so it answers "is anything left to do here" and
20912
+ // not much more: a location holding 1 open among 40 resolved reads like one
20913
+ // holding 40 open. That loss is accepted — the panel beside this list
20914
+ // carries each finding's own status, and instanceCount sits next to the
20915
+ // badge.
20867
20916
  status: FindingStatus.optional(),
20868
- files: external_exports.array(FindingLocationFile)
20869
- }).meta({ id: "FindingLocationRepo" });
20917
+ // Every distinct rule seen at this location, UNCAPPED — so the length is a
20918
+ // tally rather than a sample and a row can say how many there are. Bounded
20919
+ // by the ruleset, not by the store. The view bounds what it DISPLAYS.
20920
+ ruleIds: external_exports.array(external_exports.string())
20921
+ }).meta({ id: "FindingLocationSummary" });
20922
+ var MAX_FINDING_LOCATIONS_LIMIT = 100;
20870
20923
  var ListFindingLocationsQuery = external_exports.object({
20871
20924
  severity: external_exports.array(Severity).optional(),
20872
20925
  subtype: external_exports.array(external_exports.string()).optional(),
@@ -20876,21 +20929,47 @@ var ListFindingLocationsQuery = external_exports.object({
20876
20929
  // instances that match, and folds its status from those.
20877
20930
  status: external_exports.array(FindingStatus).optional(),
20878
20931
  tool: external_exports.array(external_exports.string()).optional(),
20932
+ // The delivery state of each finding's event (see FindingDelivery).
20933
+ deployment: external_exports.array(FindingDeliveryState).optional(),
20879
20934
  q: external_exports.string().optional(),
20880
20935
  sessionId: external_exports.string().optional(),
20881
20936
  from: external_exports.iso.datetime().optional(),
20882
- limit: external_exports.coerce.number().int().min(1).max(500).optional()
20937
+ // A LOCATION id (see FindingLocationSummary.id) that must appear in the page
20938
+ // even when the cursor has already advanced past its sort position — the
20939
+ // counterpart of ListFindingTypesQuery.includeId, and needed far more often
20940
+ // here. Selecting a row pushes the URL, which re-renders the server and resets
20941
+ // the client's page cache to page 0; with distinct (repo, file) pairs running
20942
+ // into the thousands, a selection sitting off page 0 is the ordinary case
20943
+ // rather than a deep-link corner. Never affects totals, facets or the cursor.
20944
+ includeId: external_exports.string().optional(),
20945
+ limit: external_exports.coerce.number().int().min(1).max(MAX_FINDING_LOCATIONS_LIMIT).optional(),
20946
+ cursor: external_exports.string().optional()
20883
20947
  });
20884
20948
  var ListFindingLocationsResponse = external_exports.object({
20885
20949
  totals: external_exports.object({
20950
+ // Findings matching the filters across the whole scope. Unlike the types
20951
+ // read's same-named field this needs no caveat: the filters here narrow
20952
+ // per finding, so this is the sum of every row's instanceCount.
20886
20953
  findings: external_exports.number().int().nonnegative(),
20887
- repos: external_exports.number().int().nonnegative(),
20888
- files: external_exports.number().int().nonnegative()
20954
+ // Counts LOCATIONS, the unit this read pages — the number the paginator
20955
+ // states. The facets beside it count FINDINGS (see below); a surface
20956
+ // showing both says which is which.
20957
+ locations: external_exports.number().int().nonnegative()
20889
20958
  }),
20890
- /** Sorted by max severity, then most recent. */
20891
- items: external_exports.array(FindingLocationRepo),
20892
- /** Whether `limit` truncated the repo list. */
20893
- hasMore: external_exports.boolean()
20959
+ // Counts in FINDINGS, where the types response counts types, each dimension
20960
+ // still excluding its own filter. Deliberately not locations: counting those
20961
+ // needs a set of location keys per dimension per value — memory tracking the
20962
+ // store times the vocabulary, in a read whose scan promises flat memory —
20963
+ // and the cheap per-location version is not an approximation but WRONG. A
20964
+ // location holding {claudecode, block} and {codex, warn} would survive
20965
+ // provider=claudecode AND action=warn, under which no single finding
20966
+ // matches, so the facet would contradict the instanceCount this whole view
20967
+ // rests on. Findings also keep the toolbar in the same unit as the page
20968
+ // tally and the panel it sits above.
20969
+ facets: FindingFacets,
20970
+ /** Sorted by max severity, then most recent, then (repo, file). */
20971
+ items: external_exports.array(FindingLocationSummary),
20972
+ nextCursor: external_exports.string().nullable()
20894
20973
  }).meta({ id: "ListFindingLocationsResponse" });
20895
20974
 
20896
20975
  // ../../packages/schema/src/zod/meta.ts
@@ -21054,6 +21133,10 @@ var CaptureAttributes = external_exports.object({
21054
21133
  // to 'allow' — the enforcement audit trail's link back to the grant that
21055
21134
  // authorized the bypass.
21056
21135
  exception_ids: external_exports.array(external_exports.guid()).optional(),
21136
+ // The persisted spellings of EventMetadata's messageId/conversationId — the
21137
+ // join back to the `llm_call` leaf for the same assistant turn.
21138
+ message_id: external_exports.string().optional(),
21139
+ conversation_id: external_exports.string().optional(),
21057
21140
  // Whole milliseconds this capture's inspection blocked its caller — the
21058
21141
  // plugin's own added latency (see EventMetadata.inspectionMs, whose value
21059
21142
  // this is). Promoted to the `inspection_ms` generated column so the facet is
@@ -21062,7 +21145,19 @@ var CaptureAttributes = external_exports.object({
21062
21145
  // inline json_extract and is not itself an optimization.
21063
21146
  // ABSENT on replayed captures (backfill / worktree scan) and on rows written
21064
21147
  // before the measurement shipped — never present as a placeholder 0.
21065
- inspection_ms: external_exports.number().int().nonnegative().optional()
21148
+ inspection_ms: external_exports.number().int().nonnegative().optional(),
21149
+ // What a `redact` this capture could not carry out became instead (see
21150
+ // EventMetadata.redactDegradedTo, whose value this is). Present only when a
21151
+ // degrade actually happened, so absence is the ordinary case rather than a
21152
+ // reader having to distinguish it from a zero.
21153
+ //
21154
+ // PER CAPTURE, while `inspection_findings.action_taken` is per finding —
21155
+ // so on a multi-finding row this does not say which finding degraded, and
21156
+ // its presence does not mean the fallback decided the capture's action. A
21157
+ // capture denied by another finding's own Block policy carries `block`
21158
+ // here too. The full statement is on EventMetadata.redactDegradedTo; it is
21159
+ // repeated rather than referenced because a store reader opens this file.
21160
+ redact_degraded_to: ActionTaken.optional()
21066
21161
  }).catchall(external_exports.unknown());
21067
21162
  var ToolCallInspection = external_exports.object({
21068
21163
  ruleId: external_exports.string().min(1),
@@ -21258,7 +21353,17 @@ var AuditEvent = external_exports.object({
21258
21353
  /** `share` to a first-party/internal destination. */
21259
21354
  internal: external_exports.boolean(),
21260
21355
  /** Event needs review (e.g. unverified egress). */
21261
- flagged: external_exports.boolean()
21356
+ flagged: external_exports.boolean(),
21357
+ /**
21358
+ * The body this event's `title` is drawn from was cleared by local body
21359
+ * expiry, so an EMPTY title here means "gone", not "never had one".
21360
+ *
21361
+ * A separate flag rather than a sentinel written into `title`: the title is
21362
+ * rendered text, and a store-layer module that invented display copy for it
21363
+ * would be choosing words the view is supposed to choose. Additive and
21364
+ * defaulted, so an older producer still validates.
21365
+ */
21366
+ bodyExpired: external_exports.boolean().default(false)
21262
21367
  }).meta({ id: "ActivityAuditEvent" });
21263
21368
  var ActivitySessionSummary = external_exports.object({
21264
21369
  id: external_exports.string(),
@@ -22055,6 +22160,14 @@ var ControlPlaneErrorBody = external_exports.object({
22055
22160
  message: external_exports.string().optional()
22056
22161
  }).optional()
22057
22162
  });
22163
+ var RemoteFailureKind = external_exports.enum([
22164
+ "unauthorized",
22165
+ "forbidden",
22166
+ "route-absent",
22167
+ "invalid-request",
22168
+ "rejected",
22169
+ "unreachable"
22170
+ ]);
22058
22171
  var AttachDeviceRequest = external_exports.object({
22059
22172
  // This machine's own continuity id, so re-attaching ROTATES the credential
22060
22173
  // on one machine record instead of producing a second one. Client-minted
@@ -22473,6 +22586,12 @@ var EventMetadata = external_exports.object({
22473
22586
  // to 'allow' — the enforcement audit trail's link back to the grant that
22474
22587
  // authorized the bypass. Absent on captures where no exception applied.
22475
22588
  exceptionIds: external_exports.array(external_exports.guid()).optional(),
22589
+ // The assistant message this capture belongs to, and the conversation it sits
22590
+ // in — set by the browser extension's network capture so a stored `response`
22591
+ // row can be joined to the `llm_call` leaf describing the same turn. Absent
22592
+ // on every other capture path, which has no such id.
22593
+ messageId: external_exports.string().optional(),
22594
+ conversationId: external_exports.string().optional(),
22476
22595
  // How long THIS capture's inspection blocked its caller, in whole
22477
22596
  // milliseconds — the plugin's own added latency, NOT the LLM call it sat in
22478
22597
  // front of. Measured inside `capture()` (@akasecurity/plugin-sdk) across
@@ -22485,7 +22604,37 @@ var EventMetadata = external_exports.object({
22485
22604
  // Absent is also what every pre-measurement client writes, and what a
22486
22605
  // clock failure degrades to — a reader must treat absence as "not measured"
22487
22606
  // and never as a zero, which would read as "inspection is free".
22488
- inspectionMs: external_exports.number().int().nonnegative().optional()
22607
+ inspectionMs: external_exports.number().int().nonnegative().optional(),
22608
+ // What a `redact` this capture COULD NOT CARRY OUT became instead — the
22609
+ // workspace's `redactFallback`, applied because the field could not be
22610
+ // masked in place (a shell command, a URL, or any argument on a host whose
22611
+ // hook contract offers no rewrite channel).
22612
+ //
22613
+ // It exists because the action alone cannot say why. A finding recorded as
22614
+ // `warn` reads identically whether its detection was ASSIGNED Warn or was
22615
+ // assigned Redact on a field that could not take one — and those are
22616
+ // different facts about the same row: the first is a policy the user chose,
22617
+ // the second is a masking the host could not perform. Absent means no
22618
+ // degrade happened, which is every ordinary capture.
22619
+ //
22620
+ // TWO LIMITS a reader of a stored row has to know, because the grain here
22621
+ // is the CAPTURE while `actionTaken` is per FINDING:
22622
+ //
22623
+ // - It does not say WHICH finding degraded. A capture carrying a degraded
22624
+ // `redact` alongside a finding ASSIGNED the same action stores both
22625
+ // identically and one reason for the pair; attributing it to both
22626
+ // describes the assigned one wrongly, and to neither loses the degrade.
22627
+ // - PRESENCE IS NOT CAUSATION. The value is the action the lost redact
22628
+ // became, not the reason the capture ended as it did — a capture denied
22629
+ // by some other finding's own Block policy still carries `block` here,
22630
+ // and clearing the workspace's fallback would not have let it through.
22631
+ // Gate on the value against what a fallback can produce; never read the
22632
+ // field's presence as "this was the fallback's doing".
22633
+ //
22634
+ // Both are pinned as behaviour in @akasecurity/plugin-sdk's runtime suite.
22635
+ // Closing either means moving the reason onto the finding row, which
22636
+ // already carries its own action.
22637
+ redactDegradedTo: ActionTaken.optional()
22489
22638
  }).meta({ id: "EventMetadata" });
22490
22639
  var Event = external_exports.object({
22491
22640
  id: external_exports.guid(),
@@ -22595,6 +22744,15 @@ var RotateKeyInput = external_exports.object({
22595
22744
  confirmation: external_exports.string()
22596
22745
  });
22597
22746
 
22747
+ // ../../packages/schema/src/zod/finding-delivery.ts
22748
+ var KNOWN_REASONS = SyncFailureReason.options;
22749
+
22750
+ // ../../packages/schema/src/zod/findings-group-build.ts
22751
+ function rankByOrder(members2) {
22752
+ return Object.fromEntries(members2.map((member, index) => [member, index]));
22753
+ }
22754
+ var SEVERITY_RANK = rankByOrder(Severity.options);
22755
+
22598
22756
  // ../../packages/schema/src/zod/installed-pack.ts
22599
22757
  var InstalledPack = external_exports.object({
22600
22758
  id: external_exports.guid(),
@@ -22661,6 +22819,11 @@ var Policy = external_exports.object({
22661
22819
  // test `prohibitedModels` passes and `reversibleRuleIds` fails.
22662
22820
  provenance: PolicyProvenance.optional()
22663
22821
  }).meta({ id: "Policy" });
22822
+ var KNOWN_BUILTIN_IDS = ["monitor", "warn", "redact", "vault", "block"];
22823
+ var BuiltinPolicyId = external_exports.enum(KNOWN_BUILTIN_IDS).meta({ id: "BuiltinPolicyId" });
22824
+ var RedactFallback = BuiltinPolicyId.extract(["monitor", "warn", "block"]).meta({
22825
+ id: "RedactFallback"
22826
+ });
22664
22827
  var PolicyBundle = external_exports.object({
22665
22828
  version: external_exports.string(),
22666
22829
  policies: external_exports.array(Policy),
@@ -22708,6 +22871,16 @@ var PolicyBundle = external_exports.object({
22708
22871
  // control plane), so no name resolution stands between the decision and the
22709
22872
  // comparison.
22710
22873
  prohibitedModels: external_exports.array(external_exports.string()).optional(),
22874
+ // What a resolved `redact` becomes on a field the host cannot rewrite, as
22875
+ // the ORGANIZATION would have it. Merged raise-only against the device's own
22876
+ // `WorkspaceSettings.redactFallback` (see strongerRedactFallback below), so
22877
+ // a control plane can tighten a machine and never loosen one — the same
22878
+ // direction `mergeRaiseOnly` enforces for policies.
22879
+ //
22880
+ // Optional so an older backend, and an older on-disk cache, still parses;
22881
+ // absent leaves the device's own setting in force, which is the behaviour
22882
+ // that predates the field and the safe direction to default.
22883
+ redactFallback: RedactFallback.optional(),
22711
22884
  customKeywords: external_exports.array(external_exports.string()),
22712
22885
  fetchedAt: external_exports.iso.datetime()
22713
22886
  }).meta({ id: "PolicyBundle" });
@@ -22737,11 +22910,6 @@ function severityFloorPolicy(category) {
22737
22910
  const peak = CATEGORY_PEAK_SEVERITY[category];
22738
22911
  return peak === "critical" || peak === "high" ? "warn" : "monitor";
22739
22912
  }
22740
- var KNOWN_BUILTIN_IDS = ["monitor", "warn", "redact", "vault", "block"];
22741
- var BuiltinPolicyId = external_exports.enum(KNOWN_BUILTIN_IDS).meta({ id: "BuiltinPolicyId" });
22742
- var RedactFallback = BuiltinPolicyId.extract(["monitor", "warn", "block"]).meta({
22743
- id: "RedactFallback"
22744
- });
22745
22913
  var BUILTIN_POLICY_SPECS = {
22746
22914
  monitor: {
22747
22915
  name: "Monitor",
@@ -23003,7 +23171,7 @@ var VaultConsent = external_exports.object({
23003
23171
  });
23004
23172
 
23005
23173
  // ../../packages/schema/src/zod/local.ts
23006
- var WORKSPACE_SETTINGS_SPEC_VERSION = 7;
23174
+ var WORKSPACE_SETTINGS_SPEC_VERSION = 8;
23007
23175
  var RunMode = external_exports.enum(["standalone", "attached"]);
23008
23176
  var ControlPlaneConnection = external_exports.object({
23009
23177
  endpoint: external_exports.string().min(1),
@@ -23022,6 +23190,15 @@ var HistorySyncConsent = external_exports.object({
23022
23190
  payloadVersion: external_exports.number().int().positive(),
23023
23191
  endpoint: external_exports.string()
23024
23192
  });
23193
+ var BODY_RETENTION_DEFAULT_DAYS = 30;
23194
+ var BodyRetention = external_exports.object({
23195
+ enabled: external_exports.boolean().default(false),
23196
+ // Never 0, and the ceiling is a fat-finger guard rather than a policy
23197
+ // limit — `enabled` is the real gate. A low value cannot reach a row the
23198
+ // sync ledger still owes: the sweep's age filter only ever NARROWS a
23199
+ // candidate set that is already bounded by "delivered, or never owed".
23200
+ retainDays: external_exports.number().int().min(1).max(3650).default(BODY_RETENTION_DEFAULT_DAYS)
23201
+ }).meta({ id: "BodyRetention" });
23025
23202
  var WorkspaceSettings = external_exports.object({
23026
23203
  specVersion: external_exports.number().int().positive().default(WORKSPACE_SETTINGS_SPEC_VERSION),
23027
23204
  runMode: RunMode.default("standalone"),
@@ -23065,12 +23242,18 @@ var WorkspaceSettings = external_exports.object({
23065
23242
  // covers the current payload and must be re-granted.
23066
23243
  modelJudgeConsent: ModelJudgeConsent.optional(),
23067
23244
  // Records that the user consented to the DEFERRED send — the outbox — along
23068
- // with the payload shape and the endpoint they agreed to. Since payload v2
23069
- // that covers both the pre-attach backlog and undelivered captures (which
23070
- // carry prompt/reply text in `content`); the key name predates the widening.
23071
- // Absent until granted, and a grant for a different endpoint or an older
23072
- // payload no longer counts.
23073
- historySyncConsent: HistorySyncConsent.optional()
23245
+ // with the payload shape and the endpoint they agreed to. Since payload v3
23246
+ // that covers the pre-attach backlog AND undelivered captures alike, and both
23247
+ // carry prompt/reply/tool-output text in `content`; the key name predates
23248
+ // both widenings. Absent until granted, and a grant for a different endpoint
23249
+ // or an older payload no longer counts.
23250
+ historySyncConsent: HistorySyncConsent.optional(),
23251
+ // Local body expiry (see BodyRetention). Off until switched on; expiring a
23252
+ // body never removes the row or its findings.
23253
+ bodyRetention: BodyRetention.default({
23254
+ enabled: false,
23255
+ retainDays: BODY_RETENTION_DEFAULT_DAYS
23256
+ })
23074
23257
  });
23075
23258
 
23076
23259
  // ../../packages/schema/src/zod/managed.ts
@@ -23083,10 +23266,22 @@ var ManagedSettingKey = external_exports.enum([
23083
23266
  "vaultInlineReveal",
23084
23267
  "modelJudgeConsent",
23085
23268
  "dataSharesInPlace",
23086
- "redactFallback"
23269
+ "redactFallback",
23270
+ // Pins the toggle and the day count together — see BodyRetention on why the
23271
+ // two are one unit. An administrator mandating a window wants the count
23272
+ // enforced with it, not one a user can widen while the toggle stays on.
23273
+ "bodyRetention"
23087
23274
  ]).meta({ id: "ManagedSettingKey" });
23275
+ function isManagedSettingKey(value) {
23276
+ return ManagedSettingKey.safeParse(value).success;
23277
+ }
23088
23278
  var ManagedSettingsValues = external_exports.object({
23089
23279
  runMode: external_exports.enum(["standalone", "attached"]).optional(),
23280
+ // `controlPlane` and `bodyRetention` are the two nested values, and both are
23281
+ // plain, non-strict objects: a key under either that this build does not know
23282
+ // is stripped and nothing reports it. The unknown-value split in
23283
+ // ManagedSettings below classifies top-level names only, so it stops at
23284
+ // these boundaries.
23090
23285
  controlPlane: external_exports.object({
23091
23286
  endpoint: external_exports.string().min(1),
23092
23287
  label: external_exports.string().min(1).optional()
@@ -23097,7 +23292,8 @@ var ManagedSettingsValues = external_exports.object({
23097
23292
  vaultInlineReveal: external_exports.enum(["masked", "full", "off"]).optional(),
23098
23293
  modelJudgeConsent: external_exports.boolean().optional(),
23099
23294
  dataSharesInPlace: external_exports.boolean().optional(),
23100
- redactFallback: RedactFallback.optional()
23295
+ redactFallback: RedactFallback.optional(),
23296
+ bodyRetention: BodyRetention.optional()
23101
23297
  }).meta({ id: "ManagedSettingsValues" });
23102
23298
  var ManagedSettings = external_exports.object({
23103
23299
  specVersion: external_exports.number().int().positive().default(MANAGED_SETTINGS_SPEC_VERSION),
@@ -23105,11 +23301,59 @@ var ManagedSettings = external_exports.object({
23105
23301
  // decision from a bug. Absent renders as a generic "your organization".
23106
23302
  organization: external_exports.string().min(1).optional(),
23107
23303
  // What the administrator pinned.
23108
- values: ManagedSettingsValues.default({}),
23304
+ //
23305
+ // Parsed as a RECORD rather than as the nested schema, and split below for
23306
+ // the same reason `lockedFields` is parsed as names: a plain `z.object`
23307
+ // drops an unrecognised key and succeeds, so a pin this build does not know
23308
+ // vanished and nothing anywhere said so. A pin with no lock is a supported
23309
+ // shape — it is a DEFAULT the user may still change — so that silence hit
23310
+ // exactly the file an administrator is most likely to write while a fleet
23311
+ // is mid-upgrade.
23312
+ //
23313
+ // Splitting here rather than calling `.strict()`: strict would REFUSE the
23314
+ // file, which is the outcome the lock half already rejected — an older
23315
+ // build then runs entirely unmanaged, every pin and lock gone. A bad KNOWN
23316
+ // value still fails, because the nested schema is re-run over the known
23317
+ // subset and its issues are re-raised on this parse.
23318
+ values: external_exports.record(external_exports.string(), external_exports.unknown()).default({}),
23109
23319
  // Which of those the user may not change. A key here with no matching value
23110
23320
  // freezes whatever the user last chose; a value with no lock is a DEFAULT
23111
23321
  // the user may still override. The two are separable on purpose.
23112
- lockedFields: external_exports.array(ManagedSettingKey).default([])
23322
+ //
23323
+ // Parsed as NAMES rather than as the enum, and split below: a name this
23324
+ // build does not know is dropped from the locked set and reported, never a
23325
+ // reason to refuse the file. The same shape reaches an older build whenever
23326
+ // an administrator locks a key a newer build added, and refusing it there
23327
+ // ran that build entirely unmanaged — every pin and lock gone — on exactly
23328
+ // the fleets most likely to carry a version skew. A name outside the enum
23329
+ // is still never HONOURED: the lockable set stays explicit above.
23330
+ lockedFields: external_exports.array(external_exports.string()).default([])
23331
+ }).transform(({ lockedFields, values, ...rest }, ctx) => {
23332
+ const known = [];
23333
+ const unknown2 = [];
23334
+ for (const name of lockedFields) {
23335
+ if (isManagedSettingKey(name)) known.push(name);
23336
+ else unknown2.push(name);
23337
+ }
23338
+ const knownValues = /* @__PURE__ */ Object.create(null);
23339
+ const unknownValues = [];
23340
+ for (const [name, value] of Object.entries(values)) {
23341
+ if (Object.hasOwn(ManagedSettingsValues.shape, name)) knownValues[name] = value;
23342
+ else unknownValues.push(name);
23343
+ }
23344
+ const pinned = ManagedSettingsValues.safeParse(knownValues);
23345
+ if (!pinned.success) {
23346
+ for (const issue2 of pinned.error.issues)
23347
+ ctx.addIssue({ ...issue2, path: ["values", ...issue2.path] });
23348
+ return external_exports.NEVER;
23349
+ }
23350
+ return {
23351
+ ...rest,
23352
+ values: pinned.data,
23353
+ lockedFields: known,
23354
+ ...unknown2.length > 0 ? { unknownLockedFields: unknown2 } : {},
23355
+ ...unknownValues.length > 0 ? { unknownValueFields: unknownValues } : {}
23356
+ };
23113
23357
  }).meta({ id: "ManagedSettings" });
23114
23358
 
23115
23359
  // ../../packages/schema/src/zod/project-files.ts
@@ -23227,7 +23471,11 @@ var FindingsTimeseriesPoint = external_exports.object({
23227
23471
  timestamp: external_exports.iso.date(),
23228
23472
  critical: external_exports.number().int().nonnegative(),
23229
23473
  high: external_exports.number().int().nonnegative(),
23230
- medium: external_exports.number().int().nonnegative()
23474
+ medium: external_exports.number().int().nonnegative(),
23475
+ // Optional and additive, so a producer written against the earlier
23476
+ // three-series contract keeps validating. A consumer plotting it resolves the
23477
+ // absent case itself — the chart point requires a number.
23478
+ low: external_exports.number().int().nonnegative().optional()
23231
23479
  }).meta({ id: "FindingsTimeseriesPoint" });
23232
23480
  var FindingsTimeseriesResponse = external_exports.object({
23233
23481
  range: TimeRange,
@@ -23253,6 +23501,10 @@ var ResolvedFeedItem = external_exports.object({
23253
23501
  findingKey: external_exports.string(),
23254
23502
  ruleId: external_exports.string(),
23255
23503
  severity: Severity,
23504
+ // Repository slug, and the file path RELATIVE to it. The pair is what
23505
+ // identifies the file: a bare path matches the same name in every repo.
23506
+ // Optional and additive; empty when the event carried no repo.
23507
+ repo: external_exports.string().optional(),
23256
23508
  path: external_exports.string(),
23257
23509
  // ISO-8601 datetime (matches FindingInstance.detectedAt / the rest of the
23258
23510
  // findings domain). The reader `.toISOString()`s the DB epoch-ms values.
@@ -23358,7 +23610,23 @@ var SaveSettingsInput = external_exports.object({
23358
23610
  modelJudgeConsent: ModelJudgeConsentChoice,
23359
23611
  historySyncConsent: HistorySyncConsentChoice,
23360
23612
  vaultConsent: external_exports.string(),
23361
- vaultInlineReveal: external_exports.string()
23613
+ vaultInlineReveal: external_exports.string(),
23614
+ // Widened to `string` like its neighbours rather than typed as
23615
+ // `RedactFallback`, on this module's own layering rule: shape here, VALUE at
23616
+ // the call site, so the domain check receives the type it was written for.
23617
+ //
23618
+ // NOT because a narrower schema would reject differently. `parseActionInput`
23619
+ // is a `safeParse` wrapper and throws for no field schema, so either spelling
23620
+ // reaches a recoverable `{ ok: false }` and there is no rejected promise to
23621
+ // trade against. The real cost runs the other way and is the part worth
23622
+ // knowing: a value this schema admits and the domain enum then rejects lands
23623
+ // on the action's shared refusal, which names NO field, where a shape
23624
+ // rejection reaches `malformedInput` and names the schema key.
23625
+ redactFallback: external_exports.string(),
23626
+ // Shape only, the way the enum fields above are strings only: the RANGE is
23627
+ // `BodyRetention`'s and the action checks it there, so there is one place
23628
+ // that decides what a legal horizon is rather than two that can drift.
23629
+ bodyRetention: external_exports.object({ enabled: external_exports.boolean(), retainDays: external_exports.number() })
23362
23630
  });
23363
23631
  var AttachInput = external_exports.object({
23364
23632
  endpoint: external_exports.string(),
@@ -23484,6 +23752,52 @@ var SetupHandoffOffer = external_exports.object({
23484
23752
  path: ["liveKeys"]
23485
23753
  });
23486
23754
 
23755
+ // ../../packages/schema/src/zod/web-capture.ts
23756
+ var WebUsageSource = external_exports.enum(["site", "estimated", "none"]);
23757
+ var WebUsage = external_exports.object({
23758
+ inputTokens: external_exports.number().int().nonnegative().optional(),
23759
+ outputTokens: external_exports.number().int().nonnegative().optional(),
23760
+ cacheReadInputTokens: external_exports.number().int().nonnegative().optional(),
23761
+ cacheCreationInputTokens: external_exports.number().int().nonnegative().optional()
23762
+ });
23763
+ var WebToolCall = external_exports.object({
23764
+ toolUseId: external_exports.string().min(1),
23765
+ toolName: external_exports.string().min(1),
23766
+ target: external_exports.string().optional(),
23767
+ isError: external_exports.boolean().optional(),
23768
+ inputSize: external_exports.number().int().nonnegative().optional(),
23769
+ outputSize: external_exports.number().int().nonnegative().optional()
23770
+ });
23771
+ var WebExchange = external_exports.object({
23772
+ messageId: external_exports.string().min(1),
23773
+ startedAt: external_exports.iso.datetime(),
23774
+ model: external_exports.string().optional(),
23775
+ usage: WebUsage.optional(),
23776
+ usageSource: WebUsageSource,
23777
+ stopReason: external_exports.string().optional(),
23778
+ conversationId: external_exports.string().optional(),
23779
+ turnIndex: external_exports.number().int().nonnegative().optional(),
23780
+ toolCalls: external_exports.array(WebToolCall).default([]),
23781
+ // Absent when the adapter recovered no text. Capped by the caller at
23782
+ // RESPONSE_TEXT_MAX_BYTES; `truncated` records that the cap was reached, so a
23783
+ // short capture is never mistaken for a short reply.
23784
+ responseText: external_exports.string().optional(),
23785
+ truncated: external_exports.boolean().default(false)
23786
+ });
23787
+ var RESPONSE_TEXT_MAX_BYTES = 2 * 1024 * 1024;
23788
+ var WebCaptureStatus = external_exports.object({
23789
+ patched: external_exports.boolean(),
23790
+ live: external_exports.boolean(),
23791
+ blind: external_exports.boolean(),
23792
+ sendsSeenDom: external_exports.number().int().nonnegative(),
23793
+ exchangesSeenNet: external_exports.number().int().nonnegative(),
23794
+ parseFailures: external_exports.number().int().nonnegative(),
23795
+ unparsedBodies: external_exports.number().int().nonnegative(),
23796
+ // The adapter-declared JSON key paths that were absent from a real payload —
23797
+ // the earliest signal that a site's contract moved.
23798
+ shapeMisses: external_exports.array(external_exports.string()).default([])
23799
+ });
23800
+
23487
23801
  // ../../packages/detections/src/posture/config-posture.ts
23488
23802
  var RULE_VERSION = "1";
23489
23803
  var KNOWN_TOOLS = /* @__PURE__ */ new Set([