@akasecurity/ai-tc-claude-code 0.9.9 → 0.9.11

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
@@ -492,8 +492,8 @@ var require_ignore = __commonJS({
492
492
  });
493
493
 
494
494
  // ../../packages/plugin-sdk/src/config.ts
495
- import { existsSync as existsSync7 } from "fs";
496
- import { join as join12 } from "path";
495
+ import { existsSync as existsSync8 } from "fs";
496
+ import { join as join14 } from "path";
497
497
 
498
498
  // ../../packages/persistence/src/attached-derived.ts
499
499
  import { rmSync } from "fs";
@@ -2320,18 +2320,18 @@ var validateAsync = async (schema, value, _ctx) => {
2320
2320
  return result.issues.length === 0;
2321
2321
  };
2322
2322
  var _encode = (_Err) => {
2323
- const parse3 = _parse(_Err);
2323
+ const parse4 = _parse(_Err);
2324
2324
  const fn = (schema, value, _ctx, _params) => {
2325
2325
  const ctx = _ctx ? { ..._ctx, direction: "backward" } : { direction: "backward" };
2326
- return parse3(schema, value, ctx, finalizeParams(fn, _params));
2326
+ return parse4(schema, value, ctx, finalizeParams(fn, _params));
2327
2327
  };
2328
2328
  return fn;
2329
2329
  };
2330
2330
  var encode = /* @__PURE__ */ _encode($ZodRealError);
2331
2331
  var _decode = (_Err) => {
2332
- const parse3 = _parse(_Err);
2332
+ const parse4 = _parse(_Err);
2333
2333
  const fn = (schema, value, _ctx, _params) => {
2334
- return parse3(schema, value, _ctx, finalizeParams(fn, _params));
2334
+ return parse4(schema, value, _ctx, finalizeParams(fn, _params));
2335
2335
  };
2336
2336
  return fn;
2337
2337
  };
@@ -20385,13 +20385,11 @@ var FindingGroup = external_exports.object({
20385
20385
  latestDetectedAt: external_exports.iso.datetime(),
20386
20386
  instances: external_exports.array(FindingInstance),
20387
20387
  // Derived from instances' statuses with open-dominates precedence (see
20388
- // buildFindingGroups). Undefined only when no instance carries a status.
20388
+ // foldGroupStatus). Undefined only when no instance carries a status.
20389
20389
  status: FindingStatus.optional(),
20390
- // The distinct people across the WHOLE group, not just the `instances`
20391
- // preview — from the store's whole-group aggregate when it supplies one,
20392
- // else folded from the rows (see buildFindingGroups). Undefined when no
20393
- // instance carries a user, or when the store supplied whole-group folds
20394
- // without one.
20390
+ // The distinct people across the WHOLE group, not just the instances
20391
+ // carried here. Undefined when no instance carries a user, or when the
20392
+ // store supplied whole-group folds without one.
20395
20393
  users: external_exports.array(FindingUser).optional()
20396
20394
  }).meta({ id: "FindingGroup" });
20397
20395
  var FindingStats = external_exports.object({
@@ -20420,20 +20418,30 @@ var FindingFacets = external_exports.object({
20420
20418
  // counted under no value.
20421
20419
  status: external_exports.array(FindingFacetItem),
20422
20420
  // Host tool (attributes.tool_name). Present only on the instance-level
20423
- // reads, which can filter by it; the grouped read omits the dimension
20421
+ // reads, which can filter by it; the type-level read omits the dimension
20424
20422
  // because a group spans tools.
20425
20423
  tool: external_exports.array(FindingFacetItem).optional()
20426
20424
  }).meta({ id: "FindingFacets" });
20427
- var ListGroupedFindingsQuery = external_exports.object({
20425
+ var FindingTypeSummary = FindingGroup.omit({ instances: true, match: true }).meta({
20426
+ id: "FindingTypeSummary"
20427
+ });
20428
+ var MAX_FINDING_TYPES_LIMIT = 100;
20429
+ var ListFindingTypesQuery = external_exports.object({
20428
20430
  // NOTE: severity filters by Severity (critical/high/medium/low), not by
20429
- // FindingAction.
20431
+ // FindingAction. It narrows TYPES: a type's severity is the one its newest
20432
+ // firing version carries, and this list pages types.
20433
+ //
20434
+ // That is NOT a claim the findings of a type share it. A rule can hold several
20435
+ // definition versions at different severities, so a type kept by this filter
20436
+ // can hold findings that individually do not match — see totals.findings on
20437
+ // ListFindingTypesResponse, which counts them all.
20430
20438
  severity: external_exports.array(Severity).optional(),
20431
20439
  subtype: external_exports.array(external_exports.string()).optional(),
20432
20440
  provider: external_exports.array(FindingProvider).optional(),
20433
20441
  action: external_exports.array(FindingAction).optional(),
20434
- // Matches a group's DERIVED status (see FindingGroup.status), not its
20435
- // individual instances' — so a filtered group's Status column always reads
20436
- // one of the requested values.
20442
+ // Matches a type's DERIVED status (see FindingGroup.status), not its
20443
+ // individual findings' — so a filtered row's status always reads one of the
20444
+ // requested values.
20437
20445
  status: external_exports.array(FindingStatus).optional(),
20438
20446
  q: external_exports.string().optional(),
20439
20447
  // Scope to findings whose event carries this session id (the Activity page's
@@ -20443,23 +20451,37 @@ var ListGroupedFindingsQuery = external_exports.object({
20443
20451
  // from a time-scoped page (Activity's range) can carry that scope. Absent
20444
20452
  // means all time — this list has no default window.
20445
20453
  from: external_exports.iso.datetime().optional(),
20446
- // A group or instance id that must appear in the page even when the cursor
20447
- // has already advanced past its sort position. This is what keeps the
20448
- // Findings page's one-shot ?finding= deep link resolving once the list
20449
- // paginates: the target group is appended out of sort order rather than
20450
- // scanning forward for it. Never affects totals, facets or the cursor.
20454
+ // A RULE id that must appear in the page even when the cursor has already
20455
+ // advanced past its sort position. This is what keeps the selected type
20456
+ // visible in the list once it paginates: the target is appended out of sort
20457
+ // order rather than scanned forward for. Never affects totals, facets or the
20458
+ // cursor. Unlike the grouped read this replaces, it names a rule only — an
20459
+ // instance id is resolved by `findingInstance`, which is a primary-key seek
20460
+ // and so is not bounded by what any page happens to hold.
20451
20461
  includeId: external_exports.string().optional(),
20452
- groupBy: external_exports.literal("type").optional(),
20453
- limit: external_exports.coerce.number().int().min(1).max(100).optional(),
20462
+ limit: external_exports.coerce.number().int().min(1).max(MAX_FINDING_TYPES_LIMIT).optional(),
20454
20463
  cursor: external_exports.string().optional()
20455
20464
  });
20456
- var ListGroupedFindingsResponse = external_exports.object({
20465
+ var ListFindingTypesResponse = external_exports.object({
20457
20466
  totals: external_exports.object({
20467
+ // Findings belonging to the matching TYPES — not findings that each match
20468
+ // the filters. The filters here select types, so a type that survives
20469
+ // contributes its whole instanceCount.
20470
+ //
20471
+ // `status` is the one exception, narrowed per finding via
20472
+ // countInstancesByStatus. `severity`, `provider` and `action` are not, so
20473
+ // this can exceed what the instance read reports for the same filters: a
20474
+ // rule whose severity moved between versions is kept on its newest and
20475
+ // still counts its older findings. Narrowing the other three needs
20476
+ // per-dimension counts the aggregate does not carry today.
20458
20477
  findings: external_exports.number().int().nonnegative(),
20459
- groups: external_exports.number().int().nonnegative()
20478
+ // Counts TYPES, which is the unit this read pages. The instance read's
20479
+ // own totals count findings; the two deliberately answer different
20480
+ // questions and are never summed.
20481
+ types: external_exports.number().int().nonnegative()
20460
20482
  }),
20461
20483
  facets: FindingFacets,
20462
- items: external_exports.array(FindingGroup),
20484
+ items: external_exports.array(FindingTypeSummary),
20463
20485
  nextCursor: external_exports.string().nullable(),
20464
20486
  // Present only on session-scoped queries (`sessionId` set): per ruleId, how
20465
20487
  // many times that rule fired in the session's persisted transcript. Findings
@@ -20467,7 +20489,7 @@ var ListGroupedFindingsResponse = external_exports.object({
20467
20489
  // every firing, so the two numbers legitimately differ — this map lets a
20468
20490
  // session-scoped view show both.
20469
20491
  sessionFirings: external_exports.record(external_exports.string(), external_exports.number().int().nonnegative()).optional()
20470
- }).meta({ id: "ListGroupedFindingsResponse" });
20492
+ }).meta({ id: "ListFindingTypesResponse" });
20471
20493
  var ApplyFindingActionRequest = external_exports.object({
20472
20494
  // 'quarantined' is system-assigned (see FindingAction) — clients may not set
20473
20495
  // it, so it is excluded from the request contract. The mapping helper
@@ -20496,12 +20518,13 @@ var FindingInstanceDetail = FindingInstance.extend({
20496
20518
  var MAX_FLAT_FINDINGS_LIMIT = 200;
20497
20519
  var ListFindingInstancesQuery = external_exports.object({
20498
20520
  severity: external_exports.array(Severity).optional(),
20499
- // Rule ids, the same vocabulary the grouped list's `subtype` carries.
20521
+ // Rule ids, the same vocabulary the types list's `subtype` carries. Pinning
20522
+ // ONE of them is how the master/detail view scopes its right-hand panel.
20500
20523
  subtype: external_exports.array(external_exports.string()).optional(),
20501
20524
  provider: external_exports.array(FindingProvider).optional(),
20502
20525
  action: external_exports.array(FindingAction).optional(),
20503
20526
  // Matches each instance's OWN derived status (deriveFindingStatus), unlike
20504
- // the grouped query's group-level fold.
20527
+ // the types query's type-level fold.
20505
20528
  status: external_exports.array(FindingStatus).optional(),
20506
20529
  // Exact host-tool names (attributes.tool_name, e.g. 'Bash'). A real filter,
20507
20530
  // where the free-text `q` can only match the rendered "via Bash" label.
@@ -20518,37 +20541,46 @@ var ListFindingInstancesQuery = external_exports.object({
20518
20541
  });
20519
20542
  var ListFindingInstancesResponse = external_exports.object({
20520
20543
  // Instances matching the filters across the whole scope, not just this
20521
- // page — cursor-independent, like the grouped list's totals.
20544
+ // page — cursor-independent, like the types list's totals.
20522
20545
  totals: external_exports.object({ findings: external_exports.number().int().nonnegative() }),
20523
- // Counts in INSTANCES here, where the grouped response counts groups. Each
20546
+ // Counts in INSTANCES here, where the types response counts types. Each
20524
20547
  // dimension still excludes its own filter.
20525
20548
  facets: FindingFacets,
20526
20549
  items: external_exports.array(FindingInstanceDetail),
20527
20550
  nextCursor: external_exports.string().nullable()
20528
20551
  }).meta({ id: "ListFindingInstancesResponse" });
20529
- var FindingLocationFile = external_exports.object({
20530
- // Empty when the instances carried no file path (a prompt or a tool call
20531
- // with no file attribution).
20532
- file: external_exports.string(),
20533
- instanceCount: external_exports.number().int().nonnegative(),
20534
- maxSeverity: Severity,
20535
- latestDetectedAt: external_exports.iso.datetime(),
20536
- // Folded from the instances' derived statuses with the same
20537
- // open-dominates precedence a group uses.
20538
- status: FindingStatus.optional(),
20539
- // Distinct rules seen at this location, capped — the row shows them as
20540
- // chips, and the count is what conveys scale.
20541
- ruleIds: external_exports.array(external_exports.string())
20542
- }).meta({ id: "FindingLocationFile" });
20543
- var FindingLocationRepo = external_exports.object({
20552
+ var FindingLocationSummary = external_exports.object({
20553
+ // Opaque, stable, minted from the pair by encodeLocationId. It exists
20554
+ // because a location's identity is two values and a URL param carries one:
20555
+ // `?loc=` names a location the way `?rule=` names a type. Only ever compared
20556
+ // for EQUALITY — the page's selection check, this read's `includeId`, the
20557
+ // client's page dedupe — never decoded, and never a sort key.
20558
+ id: external_exports.string(),
20544
20559
  /** Empty when the instances carried no repo attribute. */
20545
20560
  repo: external_exports.string(),
20561
+ // Empty when the instances carried no file path (a prompt, or a tool call
20562
+ // with no file attribution). Both halves empty is a real location — usually
20563
+ // the largest one in a store — and is selectable like any other.
20564
+ file: external_exports.string(),
20546
20565
  instanceCount: external_exports.number().int().nonnegative(),
20566
+ // The WORST severity present, not the first row's. It is this list's primary
20567
+ // sort key, so it is also what explains why a row is where it is, and it is
20568
+ // how a reader decides what to open without opening everything.
20547
20569
  maxSeverity: Severity,
20548
20570
  latestDetectedAt: external_exports.iso.datetime(),
20571
+ // Folded from the instances' derived statuses with the same open-dominates
20572
+ // precedence a group uses, so it answers "is anything left to do here" and
20573
+ // not much more: a location holding 1 open among 40 resolved reads like one
20574
+ // holding 40 open. That loss is accepted — the panel beside this list
20575
+ // carries each finding's own status, and instanceCount sits next to the
20576
+ // badge.
20549
20577
  status: FindingStatus.optional(),
20550
- files: external_exports.array(FindingLocationFile)
20551
- }).meta({ id: "FindingLocationRepo" });
20578
+ // Every distinct rule seen at this location, UNCAPPED — so the length is a
20579
+ // tally rather than a sample and a row can say how many there are. Bounded
20580
+ // by the ruleset, not by the store. The view bounds what it DISPLAYS.
20581
+ ruleIds: external_exports.array(external_exports.string())
20582
+ }).meta({ id: "FindingLocationSummary" });
20583
+ var MAX_FINDING_LOCATIONS_LIMIT = 100;
20552
20584
  var ListFindingLocationsQuery = external_exports.object({
20553
20585
  severity: external_exports.array(Severity).optional(),
20554
20586
  subtype: external_exports.array(external_exports.string()).optional(),
@@ -20561,18 +20593,42 @@ var ListFindingLocationsQuery = external_exports.object({
20561
20593
  q: external_exports.string().optional(),
20562
20594
  sessionId: external_exports.string().optional(),
20563
20595
  from: external_exports.iso.datetime().optional(),
20564
- limit: external_exports.coerce.number().int().min(1).max(500).optional()
20596
+ // A LOCATION id (see FindingLocationSummary.id) that must appear in the page
20597
+ // even when the cursor has already advanced past its sort position — the
20598
+ // counterpart of ListFindingTypesQuery.includeId, and needed far more often
20599
+ // here. Selecting a row pushes the URL, which re-renders the server and resets
20600
+ // the client's page cache to page 0; with distinct (repo, file) pairs running
20601
+ // into the thousands, a selection sitting off page 0 is the ordinary case
20602
+ // rather than a deep-link corner. Never affects totals, facets or the cursor.
20603
+ includeId: external_exports.string().optional(),
20604
+ limit: external_exports.coerce.number().int().min(1).max(MAX_FINDING_LOCATIONS_LIMIT).optional(),
20605
+ cursor: external_exports.string().optional()
20565
20606
  });
20566
20607
  var ListFindingLocationsResponse = external_exports.object({
20567
20608
  totals: external_exports.object({
20609
+ // Findings matching the filters across the whole scope. Unlike the types
20610
+ // read's same-named field this needs no caveat: the filters here narrow
20611
+ // per finding, so this is the sum of every row's instanceCount.
20568
20612
  findings: external_exports.number().int().nonnegative(),
20569
- repos: external_exports.number().int().nonnegative(),
20570
- files: external_exports.number().int().nonnegative()
20613
+ // Counts LOCATIONS, the unit this read pages — the number the paginator
20614
+ // states. The facets beside it count FINDINGS (see below); a surface
20615
+ // showing both says which is which.
20616
+ locations: external_exports.number().int().nonnegative()
20571
20617
  }),
20572
- /** Sorted by max severity, then most recent. */
20573
- items: external_exports.array(FindingLocationRepo),
20574
- /** Whether `limit` truncated the repo list. */
20575
- hasMore: external_exports.boolean()
20618
+ // Counts in FINDINGS, where the types response counts types, each dimension
20619
+ // still excluding its own filter. Deliberately not locations: counting those
20620
+ // needs a set of location keys per dimension per value — memory tracking the
20621
+ // store times the vocabulary, in a read whose scan promises flat memory —
20622
+ // and the cheap per-location version is not an approximation but WRONG. A
20623
+ // location holding {claudecode, block} and {codex, warn} would survive
20624
+ // provider=claudecode AND action=warn, under which no single finding
20625
+ // matches, so the facet would contradict the instanceCount this whole view
20626
+ // rests on. Findings also keep the toolbar in the same unit as the page
20627
+ // tally and the panel it sits above.
20628
+ facets: FindingFacets,
20629
+ /** Sorted by max severity, then most recent, then (repo, file). */
20630
+ items: external_exports.array(FindingLocationSummary),
20631
+ nextCursor: external_exports.string().nullable()
20576
20632
  }).meta({ id: "ListFindingLocationsResponse" });
20577
20633
 
20578
20634
  // ../../packages/schema/src/zod/meta.ts
@@ -21737,6 +21793,14 @@ var ControlPlaneErrorBody = external_exports.object({
21737
21793
  message: external_exports.string().optional()
21738
21794
  }).optional()
21739
21795
  });
21796
+ var RemoteFailureKind = external_exports.enum([
21797
+ "unauthorized",
21798
+ "forbidden",
21799
+ "route-absent",
21800
+ "invalid-request",
21801
+ "rejected",
21802
+ "unreachable"
21803
+ ]);
21740
21804
  var AttachDeviceRequest = external_exports.object({
21741
21805
  // This machine's own continuity id, so re-attaching ROTATES the credential
21742
21806
  // on one machine record instead of producing a second one. Client-minted
@@ -21798,6 +21862,26 @@ var AttachTokenResponse = external_exports.union([
21798
21862
  AttachTokenExpired,
21799
21863
  external_exports.object({ status: printable(64) })
21800
21864
  ]);
21865
+ var DeviceCommandKind = external_exports.enum(["shares_rescan"]);
21866
+ var DeviceCommand = external_exports.object({
21867
+ id: printable(128).min(1),
21868
+ kind: DeviceCommandKind,
21869
+ issuedAt: printable(64).min(1),
21870
+ expiresAt: printable(64).min(1)
21871
+ }).strict();
21872
+ var DeviceCommandPollResponse = external_exports.object({ command: DeviceCommand.nullable() });
21873
+ var DeviceCommandFailureReason = external_exports.enum(["scan_failed", "no_projects", "expired"]);
21874
+ var DeviceCommandAckBody = external_exports.discriminatedUnion("outcome", [
21875
+ external_exports.object({
21876
+ outcome: external_exports.literal("reported"),
21877
+ projectsScanned: external_exports.number().int().nonnegative()
21878
+ }).strict(),
21879
+ external_exports.object({
21880
+ outcome: external_exports.literal("failed"),
21881
+ reason: DeviceCommandFailureReason,
21882
+ projectsScanned: external_exports.number().int().nonnegative()
21883
+ }).strict()
21884
+ ]);
21801
21885
 
21802
21886
  // ../../packages/schema/src/zod/registry.ts
21803
21887
  var Namespace = external_exports.string().regex(/^[a-z][a-z0-9-]*$/);
@@ -21964,7 +22048,7 @@ var PackManifest = external_exports.object({
21964
22048
  }).meta({ id: "PackManifest" });
21965
22049
 
21966
22050
  // ../../packages/schema/src/zod/detection.ts
21967
- var OriginEnum = external_exports.enum(["library"]).meta({ id: "OriginEnum" });
22051
+ var OriginEnum = external_exports.enum(["library", "custom"]).meta({ id: "OriginEnum" });
21968
22052
  var DetectionFilterEnum = external_exports.enum(["all", "library", "custom", "customized", "updates"]);
21969
22053
  var LibraryStateEnum = external_exports.enum(["new", "imported", "update"]).meta({ id: "LibraryStateEnum" });
21970
22054
  var DetectionCounts = external_exports.object({
@@ -22159,8 +22243,9 @@ var Event = external_exports.object({
22159
22243
  metadata: EventMetadata.optional()
22160
22244
  }).meta({ id: "Event" });
22161
22245
  var IngestEvent = Event.meta({ id: "IngestEvent" });
22246
+ var INGEST_BATCH_MAX = 100;
22162
22247
  var IngestBatch = external_exports.object({
22163
- events: external_exports.array(IngestEvent).min(1).max(100),
22248
+ events: external_exports.array(IngestEvent).min(1).max(INGEST_BATCH_MAX),
22164
22249
  // Dedup policy for this batch. Id-dedup ALWAYS applies. 'content-hash'
22165
22250
  // additionally rejects any event whose contentHash the store has already
22166
22251
  // recorded — for re-runnable bulk ingest (worktree scan, transcript
@@ -22286,6 +22371,225 @@ var PatchInstalledPackRequest = external_exports.object({
22286
22371
  message: "At least one field must be provided"
22287
22372
  }).meta({ id: "PatchInstalledPackRequest" });
22288
22373
 
22374
+ // ../../packages/schema/src/zod/policy.ts
22375
+ var PolicyScope = external_exports.enum(["global", "repo", "user"]).meta({ id: "PolicyScope" });
22376
+ var PolicyTarget = external_exports.union([external_exports.object({ ruleId: external_exports.string() }), external_exports.object({ category: DetectionCategory })]).meta({ id: "PolicyTarget" });
22377
+ var PolicyKind = external_exports.enum(["builtin", "custom"]).meta({ id: "PolicyKind" });
22378
+ var PolicyProvenance = external_exports.enum(["builtin", "authored"]).meta({ id: "PolicyProvenance" });
22379
+ var Policy = external_exports.object({
22380
+ id: external_exports.guid(),
22381
+ scope: PolicyScope,
22382
+ target: PolicyTarget,
22383
+ action: ActionTaken,
22384
+ enabled: external_exports.boolean().default(true),
22385
+ customKeywords: external_exports.array(external_exports.string()).optional(),
22386
+ // Display name — optional so older policy rows without name still parse.
22387
+ // Added for the findings API (policy.name column migration).
22388
+ name: external_exports.string().optional(),
22389
+ // Whether an AUTHORED policy governs this row's target — not a claim about
22390
+ // which row this is. A producer that collapses several rows onto one target
22391
+ // must carry the marker onto whichever row survives, or the collapse decides
22392
+ // the answer; a survivor may therefore be a built-in expansion still marked
22393
+ // 'authored' because an authored sibling targeted the same thing.
22394
+ // Optional so an older producer — and an older on-disk cache — still parses;
22395
+ // absent reads as 'builtin', which is the behaviour that predates the field.
22396
+ //
22397
+ // Deliberately NOT `kind`/PolicyKind: that name and that enum answer which
22398
+ // built-in archetype catalog entry a policy is, which every catalog surface
22399
+ // reads and which a caller may state. This one is a statement the PRODUCER
22400
+ // of a bundle makes about a row, and only the bundle builder ever stamps it
22401
+ // — the CRUD routes neither accept nor set it.
22402
+ //
22403
+ // A device consumes this in exactly one direction: an 'authored' policy
22404
+ // arriving from a control plane marks the rules it targets as not
22405
+ // locally re-assignable. That can only ever ADD a refusal, never relax one,
22406
+ // which is what makes it safe to honour from an unsigned cache — the same
22407
+ // test `prohibitedModels` passes and `reversibleRuleIds` fails.
22408
+ provenance: PolicyProvenance.optional()
22409
+ }).meta({ id: "Policy" });
22410
+ var PolicyBundle = external_exports.object({
22411
+ version: external_exports.string(),
22412
+ policies: external_exports.array(Policy),
22413
+ // Rules from the installed marketplace packs (snapshotted by the
22414
+ // control plane). The plugin registers these in addition to its bundled
22415
+ // packs. Optional so older backends — and older on-disk caches — that omit
22416
+ // the field still parse; consumers read `bundle.rules ?? []`.
22417
+ rules: external_exports.array(Rule).optional(),
22418
+ // When true, `rules` IS the complete effective ruleset and the runtime must
22419
+ // NOT merge its compiled-in bundled packs — the standalone gateway sets this
22420
+ // after reading the user's installed snapshot (installed_packs, enabled
22421
+ // packs only), which is how detection updates stay manual: new bundled
22422
+ // rules run only after the user applies the pack update. Absent/false keeps
22423
+ // the historical composition (bundled packs + rules) — older caches.
22424
+ rulesComplete: external_exports.boolean().optional(),
22425
+ // Active detection exceptions, evaluation subset only (see
22426
+ // ExceptionBundleEntry). Optional so older bundle producers — and older
22427
+ // on-disk caches — that omit the field still parse; consumers read
22428
+ // `bundle.exceptions ?? []`.
22429
+ exceptions: external_exports.array(ExceptionBundleEntry).optional(),
22430
+ // Rule ids whose pack is assigned a REVERSIBLE archetype (Redact & Vault).
22431
+ // A second axis over the same `redact` action, carried beside the policies
22432
+ // rather than on them: nothing writes ruleId-targeted policies to disk, so
22433
+ // widening Policy itself would change a persisted shape to express something
22434
+ // only the in-memory bundle needs. Optional so an older producer — or an
22435
+ // older on-disk cache — still parses; consumers read `?? []` and get the
22436
+ // pre-existing one-way behaviour, which is the safe direction to default.
22437
+ reversibleRuleIds: external_exports.array(external_exports.string()).optional(),
22438
+ // Installed pack version, keyed by ruleId, for rules in `rules` that came
22439
+ // from a versioned installed pack. Optional so older backends — and older
22440
+ // on-disk caches — that omit the field still parse; consumers fall back to
22441
+ // the rule's own spec version. NOT the bundle version above — see
22442
+ // installedRuleset's ruleVersions for the source of truth.
22443
+ ruleVersions: external_exports.record(external_exports.string(), external_exports.string()).optional(),
22444
+ // Model ids (the raw `model` string a harness reports, e.g.
22445
+ // `claude-opus-4-1`) the tenant has PROHIBITED. The plugin refuses to switch
22446
+ // a session onto one (PreModelSwitch) and refuses a turn that would run on
22447
+ // one (UserPromptSubmit). Optional so an older backend — and an older
22448
+ // on-disk cache — still parses; consumers read `?? []`, which is the
22449
+ // unenforced behaviour that predates this field and the safe direction to
22450
+ // default.
22451
+ //
22452
+ // Ids, not display names: the governance decision is keyed on the exact
22453
+ // string the harness reports (`model_status_override.versionId` in the
22454
+ // control plane), so no name resolution stands between the decision and the
22455
+ // comparison.
22456
+ prohibitedModels: external_exports.array(external_exports.string()).optional(),
22457
+ customKeywords: external_exports.array(external_exports.string()),
22458
+ fetchedAt: external_exports.iso.datetime()
22459
+ }).meta({ id: "PolicyBundle" });
22460
+ var POLICY_BUNDLE_SHAPE_ID = [
22461
+ ...Object.keys(PolicyBundle.shape),
22462
+ ...Object.keys(Policy.shape).map((key) => `policies.${key}`),
22463
+ ...PolicyTarget.options.flatMap((member) => "shape" in member ? Object.keys(member.shape) : []).map((key) => `policies.target.${key}`),
22464
+ ...Object.keys(ExceptionBundleEntry.shape).map((key) => `exceptions.${key}`)
22465
+ ].sort().join(",");
22466
+ var OBSERVE_ONLY_CATEGORIES = ["config"];
22467
+ var ENFORCEABLE_CATEGORIES = DetectionCategory.options.filter((c) => !OBSERVE_ONLY_CATEGORIES.includes(c));
22468
+ var CATEGORY_PEAK_SEVERITY = {
22469
+ secret: "critical",
22470
+ financial: "critical",
22471
+ // core-financial/credit-card
22472
+ code_flaw: "critical",
22473
+ pii: "high",
22474
+ phi: "high",
22475
+ custom: "high",
22476
+ // user-defined; conservative
22477
+ code_context: "low",
22478
+ config: "low"
22479
+ // observe-only; floors to monitor regardless
22480
+ };
22481
+ function severityFloorPolicy(category) {
22482
+ if (OBSERVE_ONLY_CATEGORIES.includes(category)) return "monitor";
22483
+ const peak = CATEGORY_PEAK_SEVERITY[category];
22484
+ return peak === "critical" || peak === "high" ? "warn" : "monitor";
22485
+ }
22486
+ var KNOWN_BUILTIN_IDS = ["monitor", "warn", "redact", "vault", "block"];
22487
+ var BuiltinPolicyId = external_exports.enum(KNOWN_BUILTIN_IDS).meta({ id: "BuiltinPolicyId" });
22488
+ var RedactFallback = BuiltinPolicyId.extract(["monitor", "warn", "block"]).meta({
22489
+ id: "RedactFallback"
22490
+ });
22491
+ var BUILTIN_POLICY_SPECS = {
22492
+ monitor: {
22493
+ name: "Monitor",
22494
+ action: "log",
22495
+ reversible: false,
22496
+ description: "Log every match for audit. The request is allowed through untouched."
22497
+ },
22498
+ warn: {
22499
+ name: "Warn",
22500
+ action: "warn",
22501
+ reversible: false,
22502
+ description: "Allow the request, but warn the user inline before it is sent."
22503
+ },
22504
+ redact: {
22505
+ name: "Redact",
22506
+ action: "redact",
22507
+ reversible: false,
22508
+ description: "Strip the matched value from the request and destroy it, then continue. What was removed cannot be recovered."
22509
+ },
22510
+ vault: {
22511
+ name: "Redact & Vault",
22512
+ action: "redact",
22513
+ reversible: true,
22514
+ description: "Strip the matched value from the request and keep an encrypted, recoverable copy in the local vault, leaving a pointer in its place. Needs the vault consent granted under Settings; without it this behaves as Redact."
22515
+ },
22516
+ block: {
22517
+ name: "Block",
22518
+ action: "block",
22519
+ reversible: false,
22520
+ description: "Refuse the request entirely whenever any rule in this detection matches."
22521
+ }
22522
+ };
22523
+ function builtinPolicyToAction(id) {
22524
+ return BUILTIN_POLICY_SPECS[id].action;
22525
+ }
22526
+ var PALETTE_WEAKEST_FIRST = [
22527
+ ...new Set(KNOWN_BUILTIN_IDS.map(builtinPolicyToAction))
22528
+ ];
22529
+ var BELOW_PALETTE = ACTION_TAKEN_KEYS.filter(
22530
+ (action) => !PALETTE_WEAKEST_FIRST.includes(action)
22531
+ );
22532
+ var ACTION_STRENGTH_ORDER = [
22533
+ ...BELOW_PALETTE,
22534
+ ...PALETTE_WEAKEST_FIRST
22535
+ ];
22536
+ var PackPolicyFloor = external_exports.object({
22537
+ /**
22538
+ * The weakest archetype the device may assign. Stated as a BuiltinPolicyId
22539
+ * rather than a raw ActionTaken because that is the vocabulary the user
22540
+ * picks from — a floor a UI cannot name is one it cannot explain.
22541
+ */
22542
+ floor: BuiltinPolicyId,
22543
+ /**
22544
+ * True when the organization AUTHORED a policy governing this pack rather
22545
+ * than stating a minimum: it gave the answer, so the pack is not
22546
+ * re-assignable locally in either direction.
22547
+ */
22548
+ locked: external_exports.boolean()
22549
+ }).describe("PackPolicyFloor");
22550
+ var CATEGORY_EXPRESSIBLE_IDS = KNOWN_BUILTIN_IDS.filter(
22551
+ (id) => !BUILTIN_POLICY_SPECS[id].reversible
22552
+ );
22553
+ var CATEGORY_INEXPRESSIBLE_IDS = KNOWN_BUILTIN_IDS.filter(
22554
+ (id) => BUILTIN_POLICY_SPECS[id].reversible
22555
+ );
22556
+ var CategoryPolicyId = external_exports.enum(CATEGORY_EXPRESSIBLE_IDS).meta({ id: "CategoryPolicyId" });
22557
+ var DEFAULT_ACTIONS = Object.fromEntries(
22558
+ DetectionCategory.options.map((c) => [c, builtinPolicyToAction(severityFloorPolicy(c))])
22559
+ );
22560
+ var BUILTIN_POLICIES = Object.fromEntries(
22561
+ KNOWN_BUILTIN_IDS.map((id) => [id, { id, ...BUILTIN_POLICY_SPECS[id] }])
22562
+ );
22563
+ var UsedByItem = external_exports.object({
22564
+ id: external_exports.string(),
22565
+ name: external_exports.string(),
22566
+ ruleCount: external_exports.number().int().nonnegative(),
22567
+ enabled: external_exports.boolean()
22568
+ }).meta({ id: "UsedByItem" });
22569
+ var PolicyListItem = external_exports.object({
22570
+ id: external_exports.string(),
22571
+ kind: PolicyKind,
22572
+ name: external_exports.string(),
22573
+ enabled: external_exports.boolean(),
22574
+ usedByCount: external_exports.number().int().nonnegative()
22575
+ }).meta({ id: "PolicyListItem" });
22576
+ var ListPoliciesResponse = external_exports.object({ items: external_exports.array(PolicyListItem) }).meta({ id: "ListPoliciesResponse" });
22577
+ var PolicyDetail = external_exports.object({
22578
+ specVersion: external_exports.literal(1),
22579
+ id: external_exports.string(),
22580
+ kind: PolicyKind,
22581
+ name: external_exports.string(),
22582
+ enabled: external_exports.boolean(),
22583
+ description: external_exports.string(),
22584
+ usedBy: external_exports.array(UsedByItem)
22585
+ }).meta({ id: "PolicyDetail" });
22586
+ var PolicyStatsResponse = external_exports.object({
22587
+ policies: external_exports.number().int().nonnegative(),
22588
+ builtin: external_exports.number().int().nonnegative(),
22589
+ custom: external_exports.number().int().nonnegative(),
22590
+ detectionsGoverned: external_exports.number().int().nonnegative()
22591
+ }).meta({ id: "PolicyStatsResponse" });
22592
+
22289
22593
  // ../../packages/schema/src/zod/vault.ts
22290
22594
  var CATEGORY_ALTERNATION = DetectionCategory.options.join("|");
22291
22595
  var POINTER_TOKEN_PATTERN = new RegExp(
@@ -22322,6 +22626,14 @@ var VaultEntry = external_exports.object({
22322
22626
  // How many times this value has been detected on this machine — the reuse
22323
22627
  // signal the vault dashboard reads. Distinct from VaultDeref.pointerCount.
22324
22628
  occurrenceCount: external_exports.number().int().nonnegative(),
22629
+ // True when a PERSON asked for this value to be replaced — the surfaced-
22630
+ // secrets strike — rather than a pack enforcing its assignment. One value is
22631
+ // one row however many paths vault it, so this is what tells a policy sweep
22632
+ // that the row carries somebody's own instruction and not just an assignment
22633
+ // that has since been lowered. STICKY and MONOTONIC: a later automatic
22634
+ // vaulting of the same value must never clear it — what the user said about
22635
+ // the value does not expire.
22636
+ userAuthorized: external_exports.boolean(),
22325
22637
  firstSeen: external_exports.string(),
22326
22638
  lastSeen: external_exports.string()
22327
22639
  });
@@ -22438,7 +22750,7 @@ var VaultConsent = external_exports.object({
22438
22750
  });
22439
22751
 
22440
22752
  // ../../packages/schema/src/zod/local.ts
22441
- var WORKSPACE_SETTINGS_SPEC_VERSION = 6;
22753
+ var WORKSPACE_SETTINGS_SPEC_VERSION = 7;
22442
22754
  var MODEL_JUDGE_PAYLOAD_VERSION = 1;
22443
22755
  var RunMode = external_exports.enum(["standalone", "attached"]);
22444
22756
  var ControlPlaneConnection = external_exports.object({
@@ -22480,6 +22792,19 @@ var WorkspaceSettings = external_exports.object({
22480
22792
  vaultKeyCustody: VaultKeyCustody.default("file"),
22481
22793
  // How a pointer renders in assistant prose on screen (see VaultInlineReveal).
22482
22794
  vaultInlineReveal: VaultInlineReveal.default("masked"),
22795
+ // What a `redact` policy degrades to on a FIELD the host cannot rewrite in
22796
+ // place. Not a handling policy: the policy has already resolved to redact,
22797
+ // and this only says what happens when the host offers no channel to carry it
22798
+ // out — Antigravity's PreToolUse has no updatedInput at all, and Codex and
22799
+ // Claude Code decline to mask a field that EXECUTES because masking would
22800
+ // change what runs. Per FIELD rather than per host, so a host that can
22801
+ // rewrite some inputs keeps true redaction on those.
22802
+ //
22803
+ // Spelled in the built-in policy vocabulary rather than as a fresh enum, so
22804
+ // an attached machine's merge is `strongerAction` over the one action ladder
22805
+ // and no second rank order exists to drift from it. 'deny' is a host wire
22806
+ // word and stays out of the stored value.
22807
+ redactFallback: RedactFallback.default("warn"),
22483
22808
  // Absent until /aka:setup completes; its presence is what "onboarded" means.
22484
22809
  onboardedAt: external_exports.iso.datetime().optional(),
22485
22810
  // Records that the user consented to sending findings to the model API for
@@ -22487,10 +22812,12 @@ var WorkspaceSettings = external_exports.object({
22487
22812
  // Absent until granted; a stale payloadVersion means the consent no longer
22488
22813
  // covers the current payload and must be re-granted.
22489
22814
  modelJudgeConsent: ModelJudgeConsent.optional(),
22490
- // Records that the user consented to sending the activity already recorded on
22491
- // this machine to the deployment it is attached to, along with the payload
22492
- // shape and the endpoint they agreed to. Absent until granted, and a grant for
22493
- // a different endpoint or an older payload no longer counts.
22815
+ // Records that the user consented to the DEFERRED send — the outbox — along
22816
+ // with the payload shape and the endpoint they agreed to. Since payload v3
22817
+ // that covers the pre-attach backlog AND undelivered captures alike, and both
22818
+ // carry prompt/reply/tool-output text in `content`; the key name predates
22819
+ // both widenings. Absent until granted, and a grant for a different endpoint
22820
+ // or an older payload no longer counts.
22494
22821
  historySyncConsent: HistorySyncConsent.optional()
22495
22822
  });
22496
22823
  function defaultWorkspaceSettings() {
@@ -22507,8 +22834,12 @@ var ManagedSettingKey = external_exports.enum([
22507
22834
  "vaultKeyCustody",
22508
22835
  "vaultInlineReveal",
22509
22836
  "modelJudgeConsent",
22510
- "dataSharesInPlace"
22837
+ "dataSharesInPlace",
22838
+ "redactFallback"
22511
22839
  ]).meta({ id: "ManagedSettingKey" });
22840
+ function isManagedSettingKey(value) {
22841
+ return ManagedSettingKey.safeParse(value).success;
22842
+ }
22512
22843
  var ManagedSettingsValues = external_exports.object({
22513
22844
  runMode: external_exports.enum(["standalone", "attached"]).optional(),
22514
22845
  controlPlane: external_exports.object({
@@ -22520,7 +22851,8 @@ var ManagedSettingsValues = external_exports.object({
22520
22851
  vaultKeyCustody: external_exports.enum(["file", "keychain"]).optional(),
22521
22852
  vaultInlineReveal: external_exports.enum(["masked", "full", "off"]).optional(),
22522
22853
  modelJudgeConsent: external_exports.boolean().optional(),
22523
- dataSharesInPlace: external_exports.boolean().optional()
22854
+ dataSharesInPlace: external_exports.boolean().optional(),
22855
+ redactFallback: RedactFallback.optional()
22524
22856
  }).meta({ id: "ManagedSettingsValues" });
22525
22857
  var ManagedSettings = external_exports.object({
22526
22858
  specVersion: external_exports.number().int().positive().default(MANAGED_SETTINGS_SPEC_VERSION),
@@ -22532,174 +22864,29 @@ var ManagedSettings = external_exports.object({
22532
22864
  // Which of those the user may not change. A key here with no matching value
22533
22865
  // freezes whatever the user last chose; a value with no lock is a DEFAULT
22534
22866
  // the user may still override. The two are separable on purpose.
22535
- lockedFields: external_exports.array(ManagedSettingKey).default([])
22867
+ //
22868
+ // Parsed as NAMES rather than as the enum, and split below: a name this
22869
+ // build does not know is dropped from the locked set and reported, never a
22870
+ // reason to refuse the file. The same shape reaches an older build whenever
22871
+ // an administrator locks a key a newer build added, and refusing it there
22872
+ // ran that build entirely unmanaged — every pin and lock gone — on exactly
22873
+ // the fleets most likely to carry a version skew. A name outside the enum
22874
+ // is still never HONOURED: the lockable set stays explicit above.
22875
+ lockedFields: external_exports.array(external_exports.string()).default([])
22876
+ }).transform(({ lockedFields, ...rest }) => {
22877
+ const known = [];
22878
+ const unknown2 = [];
22879
+ for (const name of lockedFields) {
22880
+ if (isManagedSettingKey(name)) known.push(name);
22881
+ else unknown2.push(name);
22882
+ }
22883
+ return {
22884
+ ...rest,
22885
+ lockedFields: known,
22886
+ ...unknown2.length > 0 ? { unknownLockedFields: unknown2 } : {}
22887
+ };
22536
22888
  }).meta({ id: "ManagedSettings" });
22537
22889
 
22538
- // ../../packages/schema/src/zod/policy.ts
22539
- var PolicyScope = external_exports.enum(["global", "repo", "user"]).meta({ id: "PolicyScope" });
22540
- var PolicyTarget = external_exports.union([external_exports.object({ ruleId: external_exports.string() }), external_exports.object({ category: DetectionCategory })]).meta({ id: "PolicyTarget" });
22541
- var Policy = external_exports.object({
22542
- id: external_exports.guid(),
22543
- scope: PolicyScope,
22544
- target: PolicyTarget,
22545
- action: ActionTaken,
22546
- enabled: external_exports.boolean().default(true),
22547
- customKeywords: external_exports.array(external_exports.string()).optional(),
22548
- // Display name — optional so older policy rows without name still parse.
22549
- // Added for the findings API (policy.name column migration).
22550
- name: external_exports.string().optional()
22551
- }).meta({ id: "Policy" });
22552
- var PolicyBundle = external_exports.object({
22553
- version: external_exports.string(),
22554
- policies: external_exports.array(Policy),
22555
- // Rules from the installed marketplace packs (snapshotted by the
22556
- // control plane). The plugin registers these in addition to its bundled
22557
- // packs. Optional so older backends — and older on-disk caches — that omit
22558
- // the field still parse; consumers read `bundle.rules ?? []`.
22559
- rules: external_exports.array(Rule).optional(),
22560
- // When true, `rules` IS the complete effective ruleset and the runtime must
22561
- // NOT merge its compiled-in bundled packs — the standalone gateway sets this
22562
- // after reading the user's installed snapshot (installed_packs, enabled
22563
- // packs only), which is how detection updates stay manual: new bundled
22564
- // rules run only after the user applies the pack update. Absent/false keeps
22565
- // the historical composition (bundled packs + rules) — older caches.
22566
- rulesComplete: external_exports.boolean().optional(),
22567
- // Active detection exceptions, evaluation subset only (see
22568
- // ExceptionBundleEntry). Optional so older bundle producers — and older
22569
- // on-disk caches — that omit the field still parse; consumers read
22570
- // `bundle.exceptions ?? []`.
22571
- exceptions: external_exports.array(ExceptionBundleEntry).optional(),
22572
- // Rule ids whose pack is assigned a REVERSIBLE archetype (Redact & Vault).
22573
- // A second axis over the same `redact` action, carried beside the policies
22574
- // rather than on them: nothing writes ruleId-targeted policies to disk, so
22575
- // widening Policy itself would change a persisted shape to express something
22576
- // only the in-memory bundle needs. Optional so an older producer — or an
22577
- // older on-disk cache — still parses; consumers read `?? []` and get the
22578
- // pre-existing one-way behaviour, which is the safe direction to default.
22579
- reversibleRuleIds: external_exports.array(external_exports.string()).optional(),
22580
- // Installed pack version, keyed by ruleId, for rules in `rules` that came
22581
- // from a versioned installed pack. Optional so older backends — and older
22582
- // on-disk caches — that omit the field still parse; consumers fall back to
22583
- // the rule's own spec version. NOT the bundle version above — see
22584
- // installedRuleset's ruleVersions for the source of truth.
22585
- ruleVersions: external_exports.record(external_exports.string(), external_exports.string()).optional(),
22586
- // Model ids (the raw `model` string a harness reports, e.g.
22587
- // `claude-opus-4-1`) the tenant has PROHIBITED. The plugin refuses to switch
22588
- // a session onto one (PreModelSwitch) and refuses a turn that would run on
22589
- // one (UserPromptSubmit). Optional so an older backend — and an older
22590
- // on-disk cache — still parses; consumers read `?? []`, which is the
22591
- // unenforced behaviour that predates this field and the safe direction to
22592
- // default.
22593
- //
22594
- // Ids, not display names: the governance decision is keyed on the exact
22595
- // string the harness reports (`model_status_override.versionId` in the
22596
- // control plane), so no name resolution stands between the decision and the
22597
- // comparison.
22598
- prohibitedModels: external_exports.array(external_exports.string()).optional(),
22599
- customKeywords: external_exports.array(external_exports.string()),
22600
- fetchedAt: external_exports.iso.datetime()
22601
- }).meta({ id: "PolicyBundle" });
22602
- var OBSERVE_ONLY_CATEGORIES = ["config"];
22603
- var ENFORCEABLE_CATEGORIES = DetectionCategory.options.filter((c) => !OBSERVE_ONLY_CATEGORIES.includes(c));
22604
- var CATEGORY_PEAK_SEVERITY = {
22605
- secret: "critical",
22606
- financial: "critical",
22607
- // core-financial/credit-card
22608
- code_flaw: "critical",
22609
- pii: "high",
22610
- phi: "high",
22611
- custom: "high",
22612
- // user-defined; conservative
22613
- code_context: "low",
22614
- config: "low"
22615
- // observe-only; floors to monitor regardless
22616
- };
22617
- function severityFloorPolicy(category) {
22618
- if (OBSERVE_ONLY_CATEGORIES.includes(category)) return "monitor";
22619
- const peak = CATEGORY_PEAK_SEVERITY[category];
22620
- return peak === "critical" || peak === "high" ? "warn" : "monitor";
22621
- }
22622
- var PolicyKind = external_exports.enum(["builtin", "custom"]).meta({ id: "PolicyKind" });
22623
- var KNOWN_BUILTIN_IDS = ["monitor", "warn", "redact", "vault", "block"];
22624
- var BuiltinPolicyId = external_exports.enum(KNOWN_BUILTIN_IDS).meta({ id: "BuiltinPolicyId" });
22625
- var BUILTIN_POLICY_SPECS = {
22626
- monitor: {
22627
- name: "Monitor",
22628
- action: "log",
22629
- reversible: false,
22630
- description: "Log every match for audit. The request is allowed through untouched."
22631
- },
22632
- warn: {
22633
- name: "Warn",
22634
- action: "warn",
22635
- reversible: false,
22636
- description: "Allow the request, but warn the user inline before it is sent."
22637
- },
22638
- redact: {
22639
- name: "Redact",
22640
- action: "redact",
22641
- reversible: false,
22642
- description: "Strip the matched value from the request and destroy it, then continue. What was removed cannot be recovered."
22643
- },
22644
- vault: {
22645
- name: "Redact & Vault",
22646
- action: "redact",
22647
- reversible: true,
22648
- description: "Strip the matched value from the request and keep an encrypted, recoverable copy in the local vault, leaving a pointer in its place. Needs the vault consent granted under Settings; without it this behaves as Redact."
22649
- },
22650
- block: {
22651
- name: "Block",
22652
- action: "block",
22653
- reversible: false,
22654
- description: "Refuse the request entirely whenever any rule in this detection matches."
22655
- }
22656
- };
22657
- function builtinPolicyToAction(id) {
22658
- return BUILTIN_POLICY_SPECS[id].action;
22659
- }
22660
- var CATEGORY_EXPRESSIBLE_IDS = KNOWN_BUILTIN_IDS.filter(
22661
- (id) => !BUILTIN_POLICY_SPECS[id].reversible
22662
- );
22663
- var CATEGORY_INEXPRESSIBLE_IDS = KNOWN_BUILTIN_IDS.filter(
22664
- (id) => BUILTIN_POLICY_SPECS[id].reversible
22665
- );
22666
- var CategoryPolicyId = external_exports.enum(CATEGORY_EXPRESSIBLE_IDS).meta({ id: "CategoryPolicyId" });
22667
- var DEFAULT_ACTIONS = Object.fromEntries(
22668
- DetectionCategory.options.map((c) => [c, builtinPolicyToAction(severityFloorPolicy(c))])
22669
- );
22670
- var BUILTIN_POLICIES = Object.fromEntries(
22671
- KNOWN_BUILTIN_IDS.map((id) => [id, { id, ...BUILTIN_POLICY_SPECS[id] }])
22672
- );
22673
- var UsedByItem = external_exports.object({
22674
- id: external_exports.string(),
22675
- name: external_exports.string(),
22676
- ruleCount: external_exports.number().int().nonnegative(),
22677
- enabled: external_exports.boolean()
22678
- }).meta({ id: "UsedByItem" });
22679
- var PolicyListItem = external_exports.object({
22680
- id: external_exports.string(),
22681
- kind: PolicyKind,
22682
- name: external_exports.string(),
22683
- enabled: external_exports.boolean(),
22684
- usedByCount: external_exports.number().int().nonnegative()
22685
- }).meta({ id: "PolicyListItem" });
22686
- var ListPoliciesResponse = external_exports.object({ items: external_exports.array(PolicyListItem) }).meta({ id: "ListPoliciesResponse" });
22687
- var PolicyDetail = external_exports.object({
22688
- specVersion: external_exports.literal(1),
22689
- id: external_exports.string(),
22690
- kind: PolicyKind,
22691
- name: external_exports.string(),
22692
- enabled: external_exports.boolean(),
22693
- description: external_exports.string(),
22694
- usedBy: external_exports.array(UsedByItem)
22695
- }).meta({ id: "PolicyDetail" });
22696
- var PolicyStatsResponse = external_exports.object({
22697
- policies: external_exports.number().int().nonnegative(),
22698
- builtin: external_exports.number().int().nonnegative(),
22699
- custom: external_exports.number().int().nonnegative(),
22700
- detectionsGoverned: external_exports.number().int().nonnegative()
22701
- }).meta({ id: "PolicyStatsResponse" });
22702
-
22703
22890
  // ../../packages/schema/src/zod/project-files.ts
22704
22891
  var ProjectFileInput = external_exports.object({
22705
22892
  path: external_exports.string().min(1),
@@ -22815,7 +23002,11 @@ var FindingsTimeseriesPoint = external_exports.object({
22815
23002
  timestamp: external_exports.iso.date(),
22816
23003
  critical: external_exports.number().int().nonnegative(),
22817
23004
  high: external_exports.number().int().nonnegative(),
22818
- medium: external_exports.number().int().nonnegative()
23005
+ medium: external_exports.number().int().nonnegative(),
23006
+ // Optional and additive, so a producer written against the earlier
23007
+ // three-series contract keeps validating. A consumer plotting it resolves the
23008
+ // absent case itself — the chart point requires a number.
23009
+ low: external_exports.number().int().nonnegative().optional()
22819
23010
  }).meta({ id: "FindingsTimeseriesPoint" });
22820
23011
  var FindingsTimeseriesResponse = external_exports.object({
22821
23012
  range: TimeRange,
@@ -22841,6 +23032,10 @@ var ResolvedFeedItem = external_exports.object({
22841
23032
  findingKey: external_exports.string(),
22842
23033
  ruleId: external_exports.string(),
22843
23034
  severity: Severity,
23035
+ // Repository slug, and the file path RELATIVE to it. The pair is what
23036
+ // identifies the file: a bare path matches the same name in every repo.
23037
+ // Optional and additive; empty when the event carried no repo.
23038
+ repo: external_exports.string().optional(),
22844
23039
  path: external_exports.string(),
22845
23040
  // ISO-8601 datetime (matches FindingInstance.detectedAt / the rest of the
22846
23041
  // findings domain). The reader `.toISOString()`s the DB epoch-ms values.
@@ -22939,10 +23134,12 @@ var DismissRecommendedActionResponse = external_exports.object({ id: external_ex
22939
23134
  var RecommendedActionIdParam = external_exports.object({ id: external_exports.string() });
22940
23135
 
22941
23136
  // ../../packages/schema/src/zod/settings-action.ts
23137
+ var HistorySyncConsentChoice = external_exports.enum(["granted", "revoked", "unchanged"]).meta({ id: "HistorySyncConsentChoice" });
23138
+ var ModelJudgeConsentChoice = external_exports.enum(["granted", "revoked", "unchanged"]).meta({ id: "ModelJudgeConsentChoice" });
22942
23139
  var SaveSettingsInput = external_exports.object({
22943
23140
  historicalAccess: external_exports.string(),
22944
- modelJudgeConsent: external_exports.boolean(),
22945
- historySyncConsent: external_exports.boolean(),
23141
+ modelJudgeConsent: ModelJudgeConsentChoice,
23142
+ historySyncConsent: HistorySyncConsentChoice,
22946
23143
  vaultConsent: external_exports.string(),
22947
23144
  vaultInlineReveal: external_exports.string()
22948
23145
  });
@@ -23110,10 +23307,30 @@ function ensureDataDirSync(dir) {
23110
23307
  function tightenFile(file2) {
23111
23308
  chmodBestEffort(file2, DATA_FILE_MODE);
23112
23309
  }
23310
+ function writeExclusiveOwnerOnlySync(file2, data) {
23311
+ writeFileSync(file2, data, { mode: DATA_FILE_MODE, flag: "wx" });
23312
+ }
23313
+ function writeOwnerOnlyFileSync(file2, data) {
23314
+ const tmp = `${file2}.${String(process.pid)}.tmp`;
23315
+ try {
23316
+ rmSync2(tmp, { force: true });
23317
+ } catch {
23318
+ }
23319
+ try {
23320
+ writeExclusiveOwnerOnlySync(tmp, data);
23321
+ renameSync(tmp, file2);
23322
+ } finally {
23323
+ try {
23324
+ rmSync2(tmp, { force: true });
23325
+ } catch {
23326
+ }
23327
+ }
23328
+ tightenFile(file2);
23329
+ }
23113
23330
 
23114
23331
  // ../../packages/persistence/src/database.ts
23115
- import { randomUUID as randomUUID10 } from "crypto";
23116
- import { join as join4, sep } from "path";
23332
+ import { randomUUID as randomUUID11 } from "crypto";
23333
+ import { dirname as dirname2, join as join7, sep } from "path";
23117
23334
  import { DatabaseSync } from "node:sqlite";
23118
23335
 
23119
23336
  // ../../packages/persistence/src/ids.ts
@@ -23140,6 +23357,20 @@ function parseJsonObject(s) {
23140
23357
 
23141
23358
  // ../../packages/persistence/src/repositories/activity.ts
23142
23359
  var LIVE_ACTIVITY_WINDOW_MS = 30 * 6e4;
23360
+ var DB_EVENT_TYPE_TO_KIND = {
23361
+ session: "session",
23362
+ prompt: "prompt",
23363
+ response: "response",
23364
+ tool_call: "tool",
23365
+ hook: "hook",
23366
+ detection: "detection",
23367
+ share: "share",
23368
+ permission: "permission",
23369
+ commit: "commit",
23370
+ error: "error",
23371
+ active: "active"
23372
+ };
23373
+ var TIMELINE_EVENT_TYPES = Object.keys(DB_EVENT_TYPE_TO_KIND).map((kind) => `'${kind}'`).join(", ");
23143
23374
  var DEFAULT_HARNESS = HARNESS.ClaudeCode;
23144
23375
 
23145
23376
  // ../../packages/persistence/src/repositories/exceptions.ts
@@ -23153,105 +23384,64 @@ var ACTIVE_REVEAL_GRANT_PREDICATE = `capability = 'reveal_to_model'
23153
23384
  AND conditions IS NULL
23154
23385
  AND ${ACTIVE_PREDICATE}`;
23155
23386
 
23387
+ // ../../packages/persistence/src/repositories/resolution-sql.ts
23388
+ function latestResolutionColumnSql(column, findingsAlias) {
23389
+ return `(
23390
+ SELECT fr.${column} FROM finding_resolution fr
23391
+ WHERE fr.finding_key = ${findingsAlias}.finding_key
23392
+ ORDER BY fr.created_at DESC, fr.rowid DESC
23393
+ LIMIT 1
23394
+ )`;
23395
+ }
23396
+ function latestResolutionStatusSql(findingsAlias) {
23397
+ return latestResolutionColumnSql("status", findingsAlias);
23398
+ }
23399
+
23400
+ // ../../packages/persistence/src/repositories/findings.ts
23401
+ var FINDING_ROW_COLUMNS_SQL = `f.id AS id, d.rule_id AS rule_id, d.category AS category,
23402
+ d.severity AS severity, f.masked_match AS masked_match,
23403
+ f.action_taken AS action_taken, f.confidence AS confidence,
23404
+ e.started_at AS occurred_at,
23405
+ e.source_tool AS source_tool,
23406
+ e.repo AS repo,
23407
+ e.file_path AS file,
23408
+ e.tool_name AS tool_name,
23409
+ f.audit_event_id AS event_id, e.root_session_id AS session_id,
23410
+ e.event_type AS kind, f.finding_key AS finding_key,
23411
+ ${latestResolutionStatusSql("f")} AS latest_status`;
23412
+
23156
23413
  // ../../packages/persistence/src/repositories/history-sync.ts
23157
23414
  var STRUCTURAL_EVENT_TYPES = ["session", "llm_call", "tool_call"];
23158
23415
  var TYPE_LIST = STRUCTURAL_EVENT_TYPES.map((t) => `'${t}'`).join(", ");
23416
+ var OUTBOX_CAPTURE_EVENT_TYPES = ["prompt", "response", "tool_use"];
23417
+ var CAPTURE_TYPE_LIST = OUTBOX_CAPTURE_EVENT_TYPES.map((t) => `'${t}'`).join(", ");
23159
23418
 
23160
23419
  // ../../packages/persistence/src/repositories/installed-packs.ts
23161
- import { createHash as createHash2, randomUUID as randomUUID3 } from "crypto";
23420
+ import { createHash as createHash2, randomUUID as randomUUID4 } from "crypto";
23162
23421
 
23163
- // ../../packages/persistence/src/repositories/inventory-assets.ts
23164
- import { randomUUID as randomUUID4 } from "crypto";
23165
- var VALID_HARNESS_IDS = new Set(HarnessId.options);
23166
- var HARNESS_LABELS = {
23167
- [HARNESS.ClaudeCode]: "Claude Code",
23168
- [HARNESS.Cursor]: "Cursor",
23169
- [HARNESS.Codex]: "Codex",
23170
- [HARNESS.Antigravity]: "Antigravity"
23171
- };
23172
- var HARNESS_LIVENESS_WINDOW_MS = 30 * 24 * 60 * 60 * 1e3;
23173
- var stripSeparators = (value) => value.toLowerCase().replace(/[\s-]/g, "");
23174
- var TITLE_NEEDLES = {
23175
- ClaudeCode: stripSeparators(SOURCE_TOOL.ClaudeCode),
23176
- Cursor: stripSeparators(SOURCE_TOOL.Cursor),
23177
- Codex: stripSeparators(SOURCE_TOOL.Codex),
23178
- Antigravity: stripSeparators(SOURCE_TOOL.Antigravity)
23179
- };
23180
-
23181
- // ../../packages/persistence/src/repositories/policies.ts
23182
- import { randomUUID as randomUUID5 } from "crypto";
23183
-
23184
- // ../../packages/persistence/src/repositories/project-files.ts
23185
- import { randomUUID as randomUUID6 } from "crypto";
23186
-
23187
- // ../../packages/persistence/src/repositories/resolutions.ts
23188
- import { randomUUID as randomUUID7 } from "crypto";
23189
-
23190
- // ../../packages/persistence/src/repositories/secret-vault.ts
23191
- import { randomUUID as randomUUID8 } from "crypto";
23192
-
23193
- // ../../packages/persistence/src/repositories/security.ts
23194
- var SCAN_COVERAGE = {
23195
- [HARNESS.Antigravity]: { coverage: 60, supported: true },
23196
- [HARNESS.Api]: { coverage: 0, supported: false },
23197
- [HARNESS.ChatGpt]: { coverage: 40, supported: true },
23198
- [HARNESS.ClaudeAi]: { coverage: 40, supported: true },
23199
- [HARNESS.ClaudeCode]: { coverage: 100, supported: true },
23200
- [HARNESS.Codex]: { coverage: 80, supported: true },
23201
- [HARNESS.Copilot]: { coverage: 0, supported: false },
23202
- [HARNESS.Cursor]: { coverage: 0, supported: false }
23203
- };
23204
-
23205
- // ../../packages/persistence/src/repositories/shares.ts
23206
- import { randomUUID as randomUUID9 } from "crypto";
23207
-
23208
- // ../../packages/persistence/src/file-lock.ts
23209
- import { randomUUID as randomUUID11 } from "crypto";
23210
- import {
23211
- closeSync,
23212
- existsSync as existsSync2,
23213
- openSync,
23214
- readFileSync as readFileSync2,
23215
- rmSync as rmSync5,
23216
- statSync as statSync3,
23217
- writeFileSync as writeFileSync2
23218
- } from "fs";
23219
- import { hostname as hostname3 } from "os";
23220
- var PARK = new Int32Array(new SharedArrayBuffer(4));
23221
-
23222
- // ../../packages/persistence/src/finding-key.ts
23223
- import { createHash as createHash3 } from "crypto";
23224
-
23225
- // ../../packages/persistence/src/fingerprint.ts
23226
- import { createHmac, randomBytes } from "crypto";
23227
- import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
23228
- import { join as join5 } from "path";
23229
- import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
23230
-
23231
- // ../../packages/persistence/src/history-preview.ts
23232
- import { existsSync as existsSync4 } from "fs";
23422
+ // ../../packages/persistence/src/policy-floor.ts
23423
+ import { readFileSync as readFileSync5 } from "fs";
23233
23424
  import { join as join6 } from "path";
23234
- import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
23235
23425
 
23236
23426
  // ../../packages/persistence/src/local-layout.ts
23237
23427
  import { renameSync as renameSync3 } from "fs";
23238
23428
  import { mkdir } from "fs/promises";
23239
23429
  import { homedir } from "os";
23240
- import { join as join7 } from "path";
23430
+ import { join as join4 } from "path";
23241
23431
  function defaultDataDir() {
23242
- return join7(homedir(), ".aka");
23432
+ return join4(homedir(), ".aka");
23243
23433
  }
23244
23434
  function settingsDir(base = defaultDataDir()) {
23245
- return join7(base, "settings");
23435
+ return join4(base, "settings");
23246
23436
  }
23247
23437
  function dataDir(base = defaultDataDir()) {
23248
- return join7(base, "data");
23438
+ return join4(base, "data");
23249
23439
  }
23250
23440
  function dbPath(base = defaultDataDir()) {
23251
- return join7(dataDir(base), "aka.db");
23441
+ return join4(dataDir(base), "aka.db");
23252
23442
  }
23253
23443
  function keysDir(base = defaultDataDir()) {
23254
- return join7(base, "keys");
23444
+ return join4(base, "keys");
23255
23445
  }
23256
23446
  function ensureLayoutDirSync(dir = defaultDataDir()) {
23257
23447
  ensureDataDirSync(dir);
@@ -23264,16 +23454,34 @@ function migrateLegacyLayout(base = defaultDataDir()) {
23264
23454
  for (const { name, dest } of moves) {
23265
23455
  try {
23266
23456
  ensureDataDirSync(dest);
23267
- const moved = join7(dest, name);
23268
- renameSync3(join7(base, name), moved);
23457
+ const moved = join4(dest, name);
23458
+ renameSync3(join4(base, name), moved);
23269
23459
  tightenFile(moved);
23270
23460
  } catch {
23271
23461
  }
23272
23462
  }
23273
23463
  }
23274
23464
 
23275
- // ../../packages/persistence/src/managed-settings.ts
23465
+ // ../../packages/persistence/src/settings.ts
23276
23466
  import { readFileSync as readFileSync4 } from "fs";
23467
+ import { join as join5 } from "path";
23468
+
23469
+ // ../../packages/persistence/src/file-lock.ts
23470
+ import { randomUUID as randomUUID3 } from "crypto";
23471
+ import {
23472
+ closeSync,
23473
+ existsSync as existsSync2,
23474
+ openSync,
23475
+ readFileSync as readFileSync2,
23476
+ rmSync as rmSync5,
23477
+ statSync as statSync3,
23478
+ writeFileSync as writeFileSync2
23479
+ } from "fs";
23480
+ import { hostname as hostname3 } from "os";
23481
+ var PARK = new Int32Array(new SharedArrayBuffer(4));
23482
+
23483
+ // ../../packages/persistence/src/managed-settings.ts
23484
+ import { readFileSync as readFileSync3 } from "fs";
23277
23485
  import { posix, win32 } from "path";
23278
23486
  function managedSettingsPaths(platform2 = process.platform) {
23279
23487
  if (platform2 === "darwin") {
@@ -23287,11 +23495,12 @@ function managedSettingsPaths(platform2 = process.platform) {
23287
23495
  }
23288
23496
  return [posix.join("/etc", "aka", MANAGED_SETTINGS_FILENAME)];
23289
23497
  }
23290
- function readManagedSettings(paths = managedSettingsPaths()) {
23498
+ var testOnlyManagedPaths = null;
23499
+ function readManagedSettings(paths = testOnlyManagedPaths ?? managedSettingsPaths()) {
23291
23500
  for (const path of paths) {
23292
23501
  let text;
23293
23502
  try {
23294
- text = readFileSync4(path, "utf8");
23503
+ text = readFileSync3(path, "utf8");
23295
23504
  } catch {
23296
23505
  continue;
23297
23506
  }
@@ -23321,6 +23530,7 @@ function overlayManagedSettings(settings, managed, now = () => /* @__PURE__ */ n
23321
23530
  if (values.vaultKeyCustody !== void 0) merged.vaultKeyCustody = values.vaultKeyCustody;
23322
23531
  if (values.vaultInlineReveal !== void 0) merged.vaultInlineReveal = values.vaultInlineReveal;
23323
23532
  if (values.dataSharesInPlace !== void 0) merged.dataSharesInPlace = values.dataSharesInPlace;
23533
+ if (values.redactFallback !== void 0) merged.redactFallback = values.redactFallback;
23324
23534
  if (values.vaultConsent !== void 0) {
23325
23535
  merged.vaultConsent = values.vaultConsent ? (
23326
23536
  // Keep an existing valid grant so its acknowledgedAt survives; mint one
@@ -23338,14 +23548,12 @@ function overlayManagedSettings(settings, managed, now = () => /* @__PURE__ */ n
23338
23548
  }
23339
23549
 
23340
23550
  // ../../packages/persistence/src/settings.ts
23341
- import { readFileSync as readFileSync5 } from "fs";
23342
- import { join as join8 } from "path";
23343
23551
  var SETTINGS_FILENAME = "settings.json";
23344
23552
  function readWorkspaceSettings(base = defaultDataDir()) {
23345
23553
  return overlayManagedSettings(readUserSettings(base), readManagedSettings());
23346
23554
  }
23347
23555
  function readUserSettings(base) {
23348
- const record2 = readJson(join8(settingsDir(base), SETTINGS_FILENAME));
23556
+ const record2 = readJson(join5(settingsDir(base), SETTINGS_FILENAME));
23349
23557
  if (!record2) return defaultWorkspaceSettings();
23350
23558
  try {
23351
23559
  return WorkspaceSettings.parse(record2);
@@ -23356,16 +23564,127 @@ function readUserSettings(base) {
23356
23564
  function readJson(file2) {
23357
23565
  let text;
23358
23566
  try {
23359
- text = readFileSync5(file2, "utf8");
23567
+ text = readFileSync4(file2, "utf8");
23360
23568
  } catch {
23361
23569
  return null;
23362
23570
  }
23363
23571
  return parseJsonObject(text) ?? null;
23364
23572
  }
23365
23573
 
23574
+ // ../../packages/persistence/src/semver.ts
23575
+ function parse3(version2) {
23576
+ const match = /^(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z-.]+))?$/.exec(version2.trim());
23577
+ if (!match) return null;
23578
+ return {
23579
+ core: [Number(match[1]), Number(match[2]), Number(match[3])],
23580
+ pre: match[4] ? match[4].split(".") : []
23581
+ };
23582
+ }
23583
+ function comparePre(a, b) {
23584
+ if (a.length === 0 && b.length === 0) return 0;
23585
+ if (a.length === 0) return 1;
23586
+ if (b.length === 0) return -1;
23587
+ const len = Math.min(a.length, b.length);
23588
+ for (let i = 0; i < len; i++) {
23589
+ const ai = a[i] ?? "";
23590
+ const bi = b[i] ?? "";
23591
+ if (ai === bi) continue;
23592
+ const an = /^\d+$/.test(ai);
23593
+ const bn = /^\d+$/.test(bi);
23594
+ if (an && !bn) return -1;
23595
+ if (!an && bn) return 1;
23596
+ if (an && bn) return Number(ai) < Number(bi) ? -1 : 1;
23597
+ return ai < bi ? -1 : 1;
23598
+ }
23599
+ return a.length === b.length ? 0 : a.length < b.length ? -1 : 1;
23600
+ }
23601
+ function compareBinaryVersions(a, b) {
23602
+ const pa = parse3(a);
23603
+ const pb = parse3(b);
23604
+ if (!pa || !pb) return 0;
23605
+ for (let i = 0; i < 3; i++) {
23606
+ const av = pa.core[i] ?? 0;
23607
+ const bv = pb.core[i] ?? 0;
23608
+ if (av !== bv) return av < bv ? -1 : 1;
23609
+ }
23610
+ return comparePre(pa.pre, pb.pre);
23611
+ }
23612
+ function isParseableBinaryVersion(version2) {
23613
+ return parse3(version2) !== null;
23614
+ }
23615
+
23616
+ // ../../packages/persistence/src/repositories/inventory-assets.ts
23617
+ import { randomUUID as randomUUID5 } from "crypto";
23618
+ var VALID_HARNESS_IDS = new Set(HarnessId.options);
23619
+ var HARNESS_LABELS = {
23620
+ [HARNESS.ClaudeCode]: "Claude Code",
23621
+ [HARNESS.Cursor]: "Cursor",
23622
+ [HARNESS.Codex]: "Codex",
23623
+ [HARNESS.Antigravity]: "Antigravity"
23624
+ };
23625
+ var HARNESS_LIVENESS_WINDOW_MS = 30 * 24 * 60 * 60 * 1e3;
23626
+ var stripSeparators = (value) => value.toLowerCase().replace(/[\s-]/g, "");
23627
+ var TITLE_NEEDLES = {
23628
+ ClaudeCode: stripSeparators(SOURCE_TOOL.ClaudeCode),
23629
+ Cursor: stripSeparators(SOURCE_TOOL.Cursor),
23630
+ Codex: stripSeparators(SOURCE_TOOL.Codex),
23631
+ Antigravity: stripSeparators(SOURCE_TOOL.Antigravity)
23632
+ };
23633
+
23634
+ // ../../packages/persistence/src/repositories/policies.ts
23635
+ import { randomUUID as randomUUID6 } from "crypto";
23636
+
23637
+ // ../../packages/persistence/src/repositories/project-files.ts
23638
+ import { randomUUID as randomUUID7 } from "crypto";
23639
+
23640
+ // ../../packages/persistence/src/repositories/resolutions.ts
23641
+ import { randomUUID as randomUUID8 } from "crypto";
23642
+
23643
+ // ../../packages/persistence/src/repositories/secret-vault.ts
23644
+ import { randomUUID as randomUUID9 } from "crypto";
23645
+
23646
+ // ../../packages/persistence/src/repositories/security.ts
23647
+ var SCAN_COVERAGE = {
23648
+ [HARNESS.Antigravity]: { coverage: 60, supported: true },
23649
+ [HARNESS.Api]: { coverage: 0, supported: false },
23650
+ [HARNESS.ChatGpt]: { coverage: 40, supported: true },
23651
+ [HARNESS.ClaudeAi]: { coverage: 40, supported: true },
23652
+ [HARNESS.ClaudeCode]: { coverage: 100, supported: true },
23653
+ [HARNESS.Codex]: { coverage: 80, supported: true },
23654
+ [HARNESS.Copilot]: { coverage: 0, supported: false },
23655
+ [HARNESS.Cursor]: { coverage: 0, supported: false }
23656
+ };
23657
+
23658
+ // ../../packages/persistence/src/repositories/shares.ts
23659
+ import { randomUUID as randomUUID10 } from "crypto";
23660
+
23661
+ // ../../packages/persistence/src/database.ts
23662
+ var CAPTURE_GRAIN = new Set(EventKind.options);
23663
+
23664
+ // ../../packages/persistence/src/egress-wire.ts
23665
+ import { createHash as createHash3 } from "crypto";
23666
+
23667
+ // ../../packages/persistence/src/finding-key.ts
23668
+ import { createHash as createHash4 } from "crypto";
23669
+
23670
+ // ../../packages/persistence/src/fingerprint.ts
23671
+ import { createHmac, randomBytes } from "crypto";
23672
+ import { existsSync as existsSync3, readFileSync as readFileSync6 } from "fs";
23673
+ import { join as join8 } from "path";
23674
+ import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
23675
+
23676
+ // ../../packages/persistence/src/history-backfill.ts
23677
+ import { existsSync as existsSync4 } from "fs";
23678
+ import { join as join9 } from "path";
23679
+
23680
+ // ../../packages/persistence/src/history-preview.ts
23681
+ import { existsSync as existsSync5 } from "fs";
23682
+ import { join as join10 } from "path";
23683
+ import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
23684
+
23366
23685
  // ../../packages/persistence/src/store-symlinks.ts
23367
- import { existsSync as existsSync5, lstatSync as lstatSync3, readlinkSync, realpathSync, statSync as statSync4 } from "fs";
23368
- import { dirname as dirname2, join as join9, resolve } from "path";
23686
+ import { existsSync as existsSync6, lstatSync as lstatSync3, readlinkSync, realpathSync, statSync as statSync4 } from "fs";
23687
+ import { dirname as dirname3, join as join11, resolve } from "path";
23369
23688
  var STORE_DB = "the store database (including the prompt corpus)";
23370
23689
  var STORE_SETTINGS = "your settings file";
23371
23690
  function storeContents(home) {
@@ -23374,7 +23693,7 @@ function storeContents(home) {
23374
23693
  [settingsDir(home), STORE_SETTINGS],
23375
23694
  [dataDir(home), STORE_DB],
23376
23695
  [keysDir(home), "the vault key"],
23377
- [join9(settingsDir(home), "settings.json"), STORE_SETTINGS],
23696
+ [join11(settingsDir(home), "settings.json"), STORE_SETTINGS],
23378
23697
  [dbPath(home), STORE_DB]
23379
23698
  ]);
23380
23699
  }
@@ -23389,7 +23708,7 @@ function symlinkedStorePaths(home, platform2 = process.platform) {
23389
23708
  holds,
23390
23709
  // existsSync follows the link, so a target that is gone reads as
23391
23710
  // absent here while lstat above still sees the link itself.
23392
- missing: !existsSync5(path),
23711
+ missing: !existsSync6(path),
23393
23712
  mode: targetMode(path, platform2)
23394
23713
  }
23395
23714
  ];
@@ -23402,7 +23721,7 @@ function linkTarget(path) {
23402
23721
  try {
23403
23722
  return realpathSync(path);
23404
23723
  } catch {
23405
- return resolve(dirname2(path), readlinkSync(path));
23724
+ return resolve(dirname3(path), readlinkSync(path));
23406
23725
  }
23407
23726
  }
23408
23727
  function targetMode(path, platform2) {
@@ -23426,15 +23745,15 @@ import {
23426
23745
  // ../../packages/persistence/src/vault/key-provider.ts
23427
23746
  import { execFileSync } from "child_process";
23428
23747
  import { randomBytes as randomBytes2 } from "crypto";
23429
- import { chmodSync as chmodSync3, readFileSync as readFileSync6, renameSync as renameSync4, rmSync as rmSync6, statSync as statSync5, writeFileSync as writeFileSync3 } from "fs";
23430
- import { join as join10 } from "path";
23748
+ import { chmodSync as chmodSync3, readFileSync as readFileSync7, renameSync as renameSync4, rmSync as rmSync6, statSync as statSync5, writeFileSync as writeFileSync3 } from "fs";
23749
+ import { join as join12 } from "path";
23431
23750
 
23432
23751
  // ../../packages/persistence/src/vault/vault.ts
23433
23752
  import { randomBytes as randomBytes3, randomUUID as randomUUID12 } from "crypto";
23434
23753
 
23435
23754
  // ../../packages/persistence/src/warn-era-cap.ts
23436
- import { existsSync as existsSync6, writeFileSync as writeFileSync4 } from "fs";
23437
- import { join as join11 } from "path";
23755
+ import { existsSync as existsSync7, writeFileSync as writeFileSync4 } from "fs";
23756
+ import { join as join13 } from "path";
23438
23757
 
23439
23758
  // ../../packages/plugin-sdk/src/provider-env.ts
23440
23759
  var DEFAULT_ANTHROPIC_HOST = "api.anthropic.com";
@@ -23488,8 +23807,8 @@ function resolveProvider() {
23488
23807
  function loadConfig(base = defaultDataDir(), resolveProviderFn = resolveProvider) {
23489
23808
  try {
23490
23809
  ensureLayoutDirSync(base);
23491
- const settingsFile = join12(settingsDir(base), "settings.json");
23492
- if (existsSync7(settingsFile)) tightenFile(settingsFile);
23810
+ const settingsFile = join14(settingsDir(base), "settings.json");
23811
+ if (existsSync8(settingsFile)) tightenFile(settingsFile);
23493
23812
  } catch {
23494
23813
  }
23495
23814
  migrateLegacyLayout(base);
@@ -23512,9 +23831,9 @@ function resolveProviderSafe(resolveProviderFn) {
23512
23831
  }
23513
23832
 
23514
23833
  // ../../packages/plugin-sdk/src/config-inventory.ts
23515
- import { readdirSync as readdirSync2, readFileSync as readFileSync8, realpathSync as realpathSync2, statSync as statSync7 } from "fs";
23834
+ import { readdirSync as readdirSync2, readFileSync as readFileSync9, realpathSync as realpathSync2, statSync as statSync7 } from "fs";
23516
23835
  import { homedir as homedir2 } from "os";
23517
- import { basename as basename3, join as join14 } from "path";
23836
+ import { basename as basename3, join as join16 } from "path";
23518
23837
 
23519
23838
  // ../../packages/detections/src/egress/registry.ts
23520
23839
  var EXTRACTOR_VERSION = "1";
@@ -24272,24 +24591,20 @@ var CPU_CORROBORATION_SHARE = 0.2;
24272
24591
  var CORROBORATION_FLOOR_MS = BUDGET_MS * CPU_CORROBORATION_SHARE;
24273
24592
 
24274
24593
  // ../../packages/plugin-sdk/src/repo.ts
24275
- import { existsSync as existsSync8, readFileSync as readFileSync7, statSync as statSync6 } from "fs";
24276
- import { basename as basename2, dirname as dirname3, isAbsolute, join as join13, sep as sep2 } from "path";
24594
+ import { existsSync as existsSync9, readFileSync as readFileSync8, statSync as statSync6 } from "fs";
24595
+ import { basename as basename2, dirname as dirname4, isAbsolute, join as join15, sep as sep2 } from "path";
24277
24596
 
24278
24597
  // ../../packages/plugin-sdk/src/events.ts
24279
- import { createHash as createHash4, randomUUID as randomUUID13 } from "crypto";
24598
+ import { createHash as createHash5, randomUUID as randomUUID13 } from "crypto";
24280
24599
 
24281
24600
  // ../../packages/plugin-sdk/src/isolated-scan.ts
24282
- import { existsSync as existsSync9 } from "fs";
24601
+ import { existsSync as existsSync10 } from "fs";
24283
24602
  import { fileURLToPath } from "url";
24284
24603
  import { Worker } from "worker_threads";
24285
24604
 
24286
- // ../../packages/plugin-sdk/src/ignore-layers.ts
24287
- var import_ignore = __toESM(require_ignore(), 1);
24288
- import { readFileSync as readFileSync9 } from "fs";
24289
- import { join as join15 } from "path";
24290
-
24291
- // ../../packages/plugin-sdk/src/inventory-resolver.ts
24292
- import { arch, hostname as hostname4, platform, release } from "os";
24605
+ // ../../packages/plugin-sdk/src/host-floor.ts
24606
+ import { readFileSync as readFileSync11 } from "fs";
24607
+ import { join as join18 } from "path";
24293
24608
 
24294
24609
  // ../../packages/plugin-sdk/src/model-governance.ts
24295
24610
  import {
@@ -24301,20 +24616,142 @@ import {
24301
24616
  readSync,
24302
24617
  writeFileSync as writeFileSync5
24303
24618
  } from "fs";
24304
- import { join as join16 } from "path";
24619
+ import { join as join17 } from "path";
24305
24620
  var TAIL_BYTES = 256 * 1024;
24621
+ function readTail(path) {
24622
+ const fd = openSync2(path, "r");
24623
+ try {
24624
+ const { size } = fstatSync(fd);
24625
+ if (size <= TAIL_BYTES) return { text: readFileSync10(fd, "utf8"), truncated: false };
24626
+ const buffer = Buffer.allocUnsafe(TAIL_BYTES);
24627
+ let filled = 0;
24628
+ while (filled < TAIL_BYTES) {
24629
+ const n = readSync(fd, buffer, filled, TAIL_BYTES - filled, size - TAIL_BYTES + filled);
24630
+ if (n === 0) break;
24631
+ filled += n;
24632
+ }
24633
+ return { text: buffer.subarray(0, filled).toString("utf8"), truncated: true };
24634
+ } finally {
24635
+ closeSync2(fd);
24636
+ }
24637
+ }
24638
+ function modelFromTranscriptTail(transcriptPath, fromRecord) {
24639
+ if (transcriptPath === void 0 || transcriptPath === "") return void 0;
24640
+ try {
24641
+ const { text: slice, truncated } = readTail(transcriptPath);
24642
+ const lines = slice.split("\n");
24643
+ if (truncated) lines.shift();
24644
+ for (let i = lines.length - 1; i >= 0; i--) {
24645
+ const line = lines[i];
24646
+ if (line === void 0 || line === "") continue;
24647
+ let parsed;
24648
+ try {
24649
+ parsed = JSON.parse(line);
24650
+ } catch {
24651
+ continue;
24652
+ }
24653
+ const model = fromRecord(parsed);
24654
+ if (model !== void 0 && model !== "") return model;
24655
+ }
24656
+ return void 0;
24657
+ } catch {
24658
+ return void 0;
24659
+ }
24660
+ }
24661
+
24662
+ // ../../packages/plugin-sdk/src/host-floor.ts
24663
+ var HOST_FEATURE = {
24664
+ ModelSwitch: "model-switch",
24665
+ VaultPointerDisplay: "vault-pointer-display"
24666
+ };
24667
+ var HOST_FLOORS = {
24668
+ [HOST_FEATURE.ModelSwitch]: {
24669
+ label: "model-switch protection",
24670
+ hookEvents: ["PreModelSwitch", "PostModelSwitch"],
24671
+ since: "2.1.251"
24672
+ },
24673
+ [HOST_FEATURE.VaultPointerDisplay]: {
24674
+ label: "vault pointer display",
24675
+ hookEvents: ["MessageDisplay"],
24676
+ since: "2.1.152"
24677
+ }
24678
+ };
24679
+ var hostVersionFromRecord = (record2) => {
24680
+ if (typeof record2 !== "object" || record2 === null) return void 0;
24681
+ const { version: version2 } = record2;
24682
+ return typeof version2 === "string" && version2 !== "" ? version2 : void 0;
24683
+ };
24684
+ function hostVersionFromTranscript(transcriptPath) {
24685
+ return modelFromTranscriptTail(transcriptPath, hostVersionFromRecord);
24686
+ }
24687
+ function hostFloorGaps(hostVersion) {
24688
+ if (hostVersion === void 0) return [];
24689
+ const gaps = [];
24690
+ for (const [feature, row] of Object.entries(HOST_FLOORS)) {
24691
+ if (compareBinaryVersions(hostVersion, row.since) < 0) {
24692
+ gaps.push({ feature, label: row.label, since: row.since });
24693
+ }
24694
+ }
24695
+ return gaps;
24696
+ }
24697
+ function requiredHostVersion(gaps) {
24698
+ let highest;
24699
+ for (const gap of gaps) {
24700
+ if (highest === void 0 || compareBinaryVersions(gap.since, highest) > 0) highest = gap.since;
24701
+ }
24702
+ return highest;
24703
+ }
24704
+ function hostFloorNotice(hostVersion) {
24705
+ if (hostVersion === void 0) return null;
24706
+ const gaps = hostFloorGaps(hostVersion);
24707
+ const required2 = requiredHostVersion(gaps);
24708
+ if (required2 === void 0) return null;
24709
+ return `This Claude Code (${hostVersion}) is older than AKA needs \u2014 some of AKA's protections are inactive in this session. Update Claude Code to ${required2} or newer to turn them on. Everything else AKA does is working normally. Run \`aka status\` for detail.`;
24710
+ }
24711
+ var HOST_VERSION_MARKER = "host-version.json";
24712
+ function recordHostVersion(dataDir2, version2) {
24713
+ if (version2 === void 0 || !isParseableBinaryVersion(version2)) return;
24714
+ try {
24715
+ const current = readHostVersionCache(dataDir2);
24716
+ if (current !== null && compareBinaryVersions(version2, current.version) <= 0) return;
24717
+ const cache = { version: version2, observedAt: Date.now() };
24718
+ ensureDataDirSync(dataDir2);
24719
+ writeOwnerOnlyFileSync(join18(dataDir2, HOST_VERSION_MARKER), JSON.stringify(cache));
24720
+ } catch {
24721
+ }
24722
+ }
24723
+ function readHostVersionCache(dataDir2) {
24724
+ try {
24725
+ const parsed = JSON.parse(readFileSync11(join18(dataDir2, HOST_VERSION_MARKER), "utf8"));
24726
+ if (typeof parsed !== "object" || parsed === null) return null;
24727
+ const { version: version2, observedAt } = parsed;
24728
+ if (typeof version2 !== "string" || !isParseableBinaryVersion(version2)) return null;
24729
+ if (typeof observedAt !== "number" || !Number.isFinite(observedAt)) return null;
24730
+ return { version: version2, observedAt };
24731
+ } catch {
24732
+ return null;
24733
+ }
24734
+ }
24735
+
24736
+ // ../../packages/plugin-sdk/src/ignore-layers.ts
24737
+ var import_ignore = __toESM(require_ignore(), 1);
24738
+ import { readFileSync as readFileSync12 } from "fs";
24739
+ import { join as join19 } from "path";
24740
+
24741
+ // ../../packages/plugin-sdk/src/inventory-resolver.ts
24742
+ import { arch, hostname as hostname4, platform, release } from "os";
24306
24743
 
24307
24744
  // ../../packages/plugin-sdk/src/nudge.ts
24308
- import { mkdirSync as mkdirSync3, readFileSync as readFileSync11, writeFileSync as writeFileSync6 } from "fs";
24309
- import { join as join17 } from "path";
24745
+ import { mkdirSync as mkdirSync3, readFileSync as readFileSync13, writeFileSync as writeFileSync6 } from "fs";
24746
+ import { join as join20 } from "path";
24310
24747
 
24311
24748
  // ../../packages/plugin-sdk/src/paths.ts
24312
24749
  import { readdirSync as readdirSync3, realpathSync as realpathSync3 } from "fs";
24313
- import { basename as basename4, dirname as dirname4, sep as sep3 } from "path";
24750
+ import { basename as basename4, dirname as dirname5, sep as sep3 } from "path";
24314
24751
 
24315
24752
  // ../../packages/plugin-sdk/src/project-files.ts
24316
- import { existsSync as existsSync10, readdirSync as readdirSync4 } from "fs";
24317
- import { basename as basename5, join as join18 } from "path";
24753
+ import { existsSync as existsSync11, readdirSync as readdirSync4 } from "fs";
24754
+ import { basename as basename5, join as join21 } from "path";
24318
24755
 
24319
24756
  // ../../packages/plugin-sdk/src/provider-env-antigravity.ts
24320
24757
  var optionalBaseUrl2 = external_exports.preprocess((v) => {
@@ -24350,9 +24787,9 @@ var THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1e3;
24350
24787
 
24351
24788
  // ../../packages/plugin-sdk/src/throttle.ts
24352
24789
  import { mkdirSync as mkdirSync4, statSync as statSync8, writeFileSync as writeFileSync7 } from "fs";
24353
- import { join as join19 } from "path";
24790
+ import { join as join22 } from "path";
24354
24791
  function throttled(dataDir2, markerName, windowMs) {
24355
- const marker = join19(dataDir2, markerName);
24792
+ const marker = join22(dataDir2, markerName);
24356
24793
  try {
24357
24794
  if (Date.now() - statSync8(marker).mtimeMs < windowMs) return true;
24358
24795
  } catch {
@@ -24367,27 +24804,27 @@ function throttled(dataDir2, markerName, windowMs) {
24367
24804
 
24368
24805
  // src/history/reconcile-trigger.ts
24369
24806
  import { spawn } from "child_process";
24370
- import { dirname as dirname5, join as join21 } from "path";
24807
+ import { dirname as dirname6, join as join24 } from "path";
24371
24808
  import { fileURLToPath as fileURLToPath2 } from "url";
24372
24809
 
24373
24810
  // src/history/tail.ts
24374
- import { createHash as createHash5 } from "crypto";
24811
+ import { createHash as createHash6 } from "crypto";
24375
24812
  import {
24376
24813
  closeSync as closeSync3,
24377
24814
  fstatSync as fstatSync2,
24378
24815
  mkdirSync as mkdirSync5,
24379
24816
  openSync as openSync3,
24380
- readFileSync as readFileSync12,
24817
+ readFileSync as readFileSync14,
24381
24818
  readSync as readSync2,
24382
24819
  writeFileSync as writeFileSync8
24383
24820
  } from "fs";
24384
- import { join as join20 } from "path";
24821
+ import { join as join23 } from "path";
24385
24822
  var SAFE_SESSION_ID = /^[A-Za-z0-9._-]+$/;
24386
24823
  function safeSessionId(sessionId) {
24387
24824
  if (SAFE_SESSION_ID.test(sessionId) && sessionId !== "." && sessionId !== "..") {
24388
24825
  return sessionId;
24389
24826
  }
24390
- return createHash5("sha256").update(sessionId).digest("hex");
24827
+ return createHash6("sha256").update(sessionId).digest("hex");
24391
24828
  }
24392
24829
 
24393
24830
  // src/history/reconcile-trigger.ts
@@ -24397,8 +24834,8 @@ function triggerReconcile(dataDir2, sessionId, transcriptPath) {
24397
24834
  try {
24398
24835
  const marker = `${RECONCILE_MARKER_PREFIX}-${safeSessionId(sessionId)}`;
24399
24836
  if (throttled(dataDir2, marker, RECONCILE_THROTTLE_MS)) return;
24400
- const here = dirname5(fileURLToPath2(import.meta.url));
24401
- const child = spawn(process.execPath, [join21(here, "reconcile.js"), sessionId, transcriptPath], {
24837
+ const here = dirname6(fileURLToPath2(import.meta.url));
24838
+ const child = spawn(process.execPath, [join24(here, "reconcile.js"), sessionId, transcriptPath], {
24402
24839
  detached: true,
24403
24840
  stdio: "ignore"
24404
24841
  });
@@ -24407,6 +24844,68 @@ function triggerReconcile(dataDir2, sessionId, transcriptPath) {
24407
24844
  }
24408
24845
  }
24409
24846
 
24847
+ // src/hooks/host-floor-notice.ts
24848
+ import { mkdirSync as mkdirSync6, readdirSync as readdirSync5, rmSync as rmSync7, statSync as statSync9, writeFileSync as writeFileSync9 } from "fs";
24849
+ import { join as join25 } from "path";
24850
+ var CLAIM_DIR = "host-floor-claims";
24851
+ var CLAIM_TTL_MS = 12 * 60 * 60 * 1e3;
24852
+ var CLAIM_SWEEP_MS = 7 * 24 * 60 * 60 * 1e3;
24853
+ function sweep(dir) {
24854
+ try {
24855
+ for (const name of readdirSync5(dir)) {
24856
+ const path = join25(dir, name);
24857
+ try {
24858
+ if (Date.now() - statSync9(path).mtimeMs > CLAIM_SWEEP_MS) rmSync7(path, { force: true });
24859
+ } catch {
24860
+ }
24861
+ }
24862
+ } catch {
24863
+ }
24864
+ }
24865
+ function tryClaim(dataDir2, sessionId) {
24866
+ if (sessionId === void 0 || sessionId === "") return () => void 0;
24867
+ const dir = join25(dataDir2, CLAIM_DIR);
24868
+ const path = join25(dir, encodeURIComponent(sessionId));
24869
+ try {
24870
+ if (Date.now() - statSync9(path).mtimeMs < CLAIM_TTL_MS) return null;
24871
+ rmSync7(path, { force: true });
24872
+ } catch {
24873
+ }
24874
+ try {
24875
+ mkdirSync6(dir, { recursive: true, mode: DATA_DIR_MODE });
24876
+ writeFileSync9(path, String(Date.now()), { flag: "wx", mode: DATA_FILE_MODE });
24877
+ } catch (err) {
24878
+ if (err.code === "EEXIST") return null;
24879
+ return () => void 0;
24880
+ }
24881
+ sweep(dir);
24882
+ return () => {
24883
+ try {
24884
+ rmSync7(path, { force: true });
24885
+ } catch {
24886
+ }
24887
+ };
24888
+ }
24889
+ function warnIfHostBelowFloor(config2, sessionId, transcriptPath, write = (message) => void process.stderr.write(message)) {
24890
+ try {
24891
+ const release2 = tryClaim(config2.dataDir, sessionId);
24892
+ if (release2 === null) return;
24893
+ let settled = false;
24894
+ try {
24895
+ const version2 = hostVersionFromTranscript(transcriptPath);
24896
+ if (version2 === void 0) return;
24897
+ recordHostVersion(config2.dataDir, version2);
24898
+ const notice = hostFloorNotice(version2);
24899
+ if (notice !== null) write(`[aka] ${notice}
24900
+ `);
24901
+ settled = true;
24902
+ } finally {
24903
+ if (!settled) release2();
24904
+ }
24905
+ } catch {
24906
+ }
24907
+ }
24908
+
24410
24909
  // src/hooks/shared.ts
24411
24910
  async function readStdin() {
24412
24911
  return new Promise((resolve2) => {
@@ -24453,37 +24952,39 @@ function parseStopPayload(input2) {
24453
24952
  }
24454
24953
 
24455
24954
  // src/hooks/store-health.ts
24456
- import { mkdirSync as mkdirSync6, readFileSync as readFileSync18, writeFileSync as writeFileSync9 } from "fs";
24457
- import { dirname as dirname6, join as join28 } from "path";
24955
+ import { mkdirSync as mkdirSync7, readFileSync as readFileSync20, writeFileSync as writeFileSync10 } from "fs";
24956
+ import { dirname as dirname7, join as join32 } from "path";
24458
24957
 
24459
- // ../../packages/plugin-runtime/src/attached/egress-wire.ts
24460
- import { createHash as createHash6 } from "crypto";
24958
+ // ../../packages/remote/src/http.ts
24959
+ import { request as httpRequest } from "http";
24960
+ import { request as httpsRequest } from "https";
24961
+ var MAX_RESPONSE_BYTES = 8 * 1024 * 1024;
24962
+
24963
+ // ../../packages/remote/src/client.ts
24964
+ var SLASH = "/".charCodeAt(0);
24461
24965
 
24462
24966
  // ../../packages/plugin-runtime/src/attached/forward-drops.ts
24463
- import { readFileSync as readFileSync13 } from "fs";
24464
- import { join as join22 } from "path";
24967
+ import { readFileSync as readFileSync15 } from "fs";
24968
+ import { join as join26 } from "path";
24465
24969
 
24466
24970
  // ../../packages/plugin-runtime/src/attached/forward-policy.ts
24467
24971
  import { randomUUID as randomUUID15 } from "crypto";
24468
- import { readFileSync as readFileSync14 } from "fs";
24972
+ import { readFileSync as readFileSync16 } from "fs";
24469
24973
  import { readFile, rename, writeFile } from "fs/promises";
24470
- import { join as join23 } from "path";
24974
+ import { join as join27 } from "path";
24471
24975
 
24472
24976
  // ../../packages/plugin-runtime/src/attached/history-state.ts
24473
- import { readFileSync as readFileSync15 } from "fs";
24474
- import { join as join24 } from "path";
24977
+ import { readFileSync as readFileSync17 } from "fs";
24978
+ import { join as join28 } from "path";
24475
24979
 
24476
24980
  // ../../packages/plugin-runtime/src/attached/history-sync.ts
24477
24981
  import { createHash as createHash7 } from "crypto";
24478
24982
  import { hostname as hostname5 } from "os";
24479
24983
 
24480
- // ../../packages/remote/src/http.ts
24481
- import { request as httpRequest } from "http";
24482
- import { request as httpsRequest } from "https";
24483
- var MAX_RESPONSE_BYTES = 8 * 1024 * 1024;
24484
-
24485
- // ../../packages/remote/src/client.ts
24486
- var SLASH = "/".charCodeAt(0);
24984
+ // ../../packages/plugin-runtime/src/attached/capture-rebuild.ts
24985
+ var CORRELATION_ID = EventMetadata.shape.correlationId;
24986
+ var TRACE_ID = EventMetadata.shape.traceId;
24987
+ var EXCEPTION_ID = EventMetadata.shape.exceptionIds.unwrap().element;
24487
24988
 
24488
24989
  // ../../packages/plugin-runtime/src/attached/history-sync-trigger.ts
24489
24990
  import { spawn as spawn2 } from "child_process";
@@ -24491,12 +24992,12 @@ import { fileURLToPath as fileURLToPath3 } from "url";
24491
24992
  var HISTORY_SYNC_THROTTLE_MS = 5 * 60 * 1e3;
24492
24993
 
24493
24994
  // ../../packages/plugin-runtime/src/attached/plugin-block.ts
24494
- import { readFileSync as readFileSync16 } from "fs";
24995
+ import { readFileSync as readFileSync18 } from "fs";
24495
24996
 
24496
24997
  // ../../packages/plugin-runtime/src/attached/policy-store.ts
24497
24998
  import { randomUUID as randomUUID16 } from "crypto";
24498
24999
  import { readFile as readFile2, rm, writeFile as writeFile2 } from "fs/promises";
24499
- import { join as join25 } from "path";
25000
+ import { join as join29 } from "path";
24500
25001
 
24501
25002
  // ../../packages/plugin-runtime/src/attached/atomic-publish.ts
24502
25003
  import { rename as rename2 } from "fs/promises";
@@ -24505,17 +25006,17 @@ import { rename as rename2 } from "fs/promises";
24505
25006
  var POSTURE_REPORT_INTERVAL_MS = 60 * 60 * 1e3;
24506
25007
 
24507
25008
  // ../../packages/plugin-runtime/src/attached/posture-snapshot.ts
24508
- import { statSync as statSync9 } from "fs";
25009
+ import { statSync as statSync10 } from "fs";
24509
25010
  import { DatabaseSync as DatabaseSync4 } from "node:sqlite";
24510
25011
 
24511
25012
  // ../../packages/plugin-runtime/src/attached/posture-store.ts
24512
25013
  import { randomUUID as randomUUID17 } from "crypto";
24513
25014
  import { readFile as readFile3, rm as rm2, writeFile as writeFile3 } from "fs/promises";
24514
- import { join as join26 } from "path";
25015
+ import { join as join30 } from "path";
24515
25016
 
24516
25017
  // ../../packages/plugin-runtime/src/attached/sync-state.ts
24517
- import { readFileSync as readFileSync17 } from "fs";
24518
- import { join as join27 } from "path";
25018
+ import { readFileSync as readFileSync19 } from "fs";
25019
+ import { join as join31 } from "path";
24519
25020
 
24520
25021
  // ../../packages/plugin-runtime/src/attached/status.ts
24521
25022
  var REFUSAL_LINES = {
@@ -24549,12 +25050,12 @@ var EXCEPTION_RETENTION_MS = 90 * 24 * 60 * 60 * 1e3;
24549
25050
  // src/hooks/store-health.ts
24550
25051
  var STORE_REDIRECT_MARKER = "store-redirect-last-session";
24551
25052
  function markerDirs(dataDir2) {
24552
- return [dataDir2, dirname6(dataDir2)];
25053
+ return [dataDir2, dirname7(dataDir2)];
24553
25054
  }
24554
25055
  function alreadyClaimed(dirs, marker, sessionId) {
24555
25056
  return dirs.some((dir) => {
24556
25057
  try {
24557
- return readFileSync18(join28(dir, marker), "utf8") === sessionId;
25058
+ return readFileSync20(join32(dir, marker), "utf8") === sessionId;
24558
25059
  } catch {
24559
25060
  return false;
24560
25061
  }
@@ -24563,8 +25064,8 @@ function alreadyClaimed(dirs, marker, sessionId) {
24563
25064
  function recordClaim(dirs, marker, sessionId) {
24564
25065
  for (const dir of dirs) {
24565
25066
  try {
24566
- mkdirSync6(dir, { recursive: true, mode: DATA_DIR_MODE });
24567
- writeFileSync9(join28(dir, marker), sessionId, { mode: DATA_FILE_MODE });
25067
+ mkdirSync7(dir, { recursive: true, mode: DATA_DIR_MODE });
25068
+ writeFileSync10(join32(dir, marker), sessionId, { mode: DATA_FILE_MODE });
24568
25069
  return;
24569
25070
  } catch {
24570
25071
  }
@@ -24589,7 +25090,7 @@ function formatMode(mode) {
24589
25090
  }
24590
25091
  function warnIfStoreRedirected(config2, sessionId, write = (message) => void process.stderr.write(message)) {
24591
25092
  try {
24592
- const paths = symlinkedStorePaths(dirname6(config2.dataDir));
25093
+ const paths = symlinkedStorePaths(dirname7(config2.dataDir));
24593
25094
  if (paths.length === 0) return;
24594
25095
  if (!sessionId) {
24595
25096
  write(storeRedirectedMessage(paths));
@@ -24609,6 +25110,7 @@ async function main() {
24609
25110
  if (trigger === void 0) return;
24610
25111
  const config2 = loadConfig();
24611
25112
  warnIfStoreRedirected(config2, trigger.sessionId);
25113
+ warnIfHostBelowFloor(config2, trigger.sessionId, trigger.transcriptPath);
24612
25114
  triggerReconcile(config2.dataDir, trigger.sessionId, trigger.transcriptPath);
24613
25115
  }
24614
25116
  try {