@akasecurity/cli 0.9.7 → 0.9.8

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.
Files changed (102) hide show
  1. package/README.md +5 -1
  2. package/dist/cli.js +1594 -504
  3. package/extension/manifest.json +1 -1
  4. package/native-host/host.js +1824 -309
  5. package/native-host/scan-worker.js +118 -0
  6. package/native-host/sync.js +19413 -0
  7. package/package.json +6 -4
  8. package/web-ui/rules/core-code-context/localhost-ref.json +2 -2
  9. package/web-ui/web-ui/.next/BUILD_ID +1 -1
  10. package/web-ui/web-ui/.next/app-build-manifest.json +88 -88
  11. package/web-ui/web-ui/.next/app-path-routes-manifest.json +7 -7
  12. package/web-ui/web-ui/.next/build-manifest.json +2 -2
  13. package/web-ui/web-ui/.next/prerender-manifest.json +3 -3
  14. package/web-ui/web-ui/.next/server/app/(app)/activity/page.js +2 -2
  15. package/web-ui/web-ui/.next/server/app/(app)/activity/page.js.nft.json +1 -1
  16. package/web-ui/web-ui/.next/server/app/(app)/activity/page_client-reference-manifest.js +1 -1
  17. package/web-ui/web-ui/.next/server/app/(app)/data-shares/page.js +2 -2
  18. package/web-ui/web-ui/.next/server/app/(app)/data-shares/page.js.nft.json +1 -1
  19. package/web-ui/web-ui/.next/server/app/(app)/data-shares/page_client-reference-manifest.js +1 -1
  20. package/web-ui/web-ui/.next/server/app/(app)/detections/page.js +2 -2
  21. package/web-ui/web-ui/.next/server/app/(app)/detections/page.js.nft.json +1 -1
  22. package/web-ui/web-ui/.next/server/app/(app)/detections/page_client-reference-manifest.js +1 -1
  23. package/web-ui/web-ui/.next/server/app/(app)/exceptions/[id]/page.js +2 -2
  24. package/web-ui/web-ui/.next/server/app/(app)/exceptions/[id]/page.js.nft.json +1 -1
  25. package/web-ui/web-ui/.next/server/app/(app)/exceptions/[id]/page_client-reference-manifest.js +1 -1
  26. package/web-ui/web-ui/.next/server/app/(app)/exceptions/new/page.js +2 -2
  27. package/web-ui/web-ui/.next/server/app/(app)/exceptions/new/page.js.nft.json +1 -1
  28. package/web-ui/web-ui/.next/server/app/(app)/exceptions/new/page_client-reference-manifest.js +1 -1
  29. package/web-ui/web-ui/.next/server/app/(app)/exceptions/page.js +2 -2
  30. package/web-ui/web-ui/.next/server/app/(app)/exceptions/page.js.nft.json +1 -1
  31. package/web-ui/web-ui/.next/server/app/(app)/exceptions/page_client-reference-manifest.js +1 -1
  32. package/web-ui/web-ui/.next/server/app/(app)/findings/page.js +2 -2
  33. package/web-ui/web-ui/.next/server/app/(app)/findings/page.js.nft.json +1 -1
  34. package/web-ui/web-ui/.next/server/app/(app)/findings/page_client-reference-manifest.js +1 -1
  35. package/web-ui/web-ui/.next/server/app/(app)/inventory/page.js +2 -2
  36. package/web-ui/web-ui/.next/server/app/(app)/inventory/page.js.nft.json +1 -1
  37. package/web-ui/web-ui/.next/server/app/(app)/inventory/page_client-reference-manifest.js +1 -1
  38. package/web-ui/web-ui/.next/server/app/(app)/policies/page.js +1 -1
  39. package/web-ui/web-ui/.next/server/app/(app)/policies/page.js.nft.json +1 -1
  40. package/web-ui/web-ui/.next/server/app/(app)/policies/page_client-reference-manifest.js +1 -1
  41. package/web-ui/web-ui/.next/server/app/(app)/scan/page.js +2 -2
  42. package/web-ui/web-ui/.next/server/app/(app)/scan/page.js.nft.json +1 -1
  43. package/web-ui/web-ui/.next/server/app/(app)/scan/page_client-reference-manifest.js +1 -1
  44. package/web-ui/web-ui/.next/server/app/(app)/security/page.js +2 -2
  45. package/web-ui/web-ui/.next/server/app/(app)/security/page.js.nft.json +1 -1
  46. package/web-ui/web-ui/.next/server/app/(app)/security/page_client-reference-manifest.js +1 -1
  47. package/web-ui/web-ui/.next/server/app/(app)/settings/page.js +2 -2
  48. package/web-ui/web-ui/.next/server/app/(app)/settings/page.js.nft.json +1 -1
  49. package/web-ui/web-ui/.next/server/app/(app)/settings/page_client-reference-manifest.js +1 -1
  50. package/web-ui/web-ui/.next/server/app/(app)/updates/page.js +1 -1
  51. package/web-ui/web-ui/.next/server/app/(app)/updates/page.js.nft.json +1 -1
  52. package/web-ui/web-ui/.next/server/app/(app)/updates/page_client-reference-manifest.js +1 -1
  53. package/web-ui/web-ui/.next/server/app/(app)/vault/page.js +1 -1
  54. package/web-ui/web-ui/.next/server/app/(app)/vault/page.js.nft.json +1 -1
  55. package/web-ui/web-ui/.next/server/app/(app)/vault/page_client-reference-manifest.js +1 -1
  56. package/web-ui/web-ui/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  57. package/web-ui/web-ui/.next/server/app/_not-found.html +1 -1
  58. package/web-ui/web-ui/.next/server/app/_not-found.rsc +1 -1
  59. package/web-ui/web-ui/.next/server/app/index.html +1 -1
  60. package/web-ui/web-ui/.next/server/app/index.rsc +1 -1
  61. package/web-ui/web-ui/.next/server/app/page_client-reference-manifest.js +1 -1
  62. package/web-ui/web-ui/.next/server/app-paths-manifest.json +7 -7
  63. package/web-ui/web-ui/.next/server/chunks/258.js +1 -1
  64. package/web-ui/web-ui/.next/server/chunks/271.js +2 -2
  65. package/web-ui/web-ui/.next/server/chunks/314.js +783 -0
  66. package/web-ui/web-ui/.next/server/chunks/523.js +1 -1
  67. package/web-ui/web-ui/.next/server/chunks/{477.js → 844.js} +138 -138
  68. package/web-ui/web-ui/.next/server/chunks/967.js +1 -1
  69. package/web-ui/web-ui/.next/server/functions-config-manifest.json +4 -4
  70. package/web-ui/web-ui/.next/server/middleware-manifest.json +5 -5
  71. package/web-ui/web-ui/.next/server/pages/404.html +1 -1
  72. package/web-ui/web-ui/.next/server/pages/500.html +1 -1
  73. package/web-ui/web-ui/.next/server/pages-manifest.json +1 -1
  74. package/web-ui/web-ui/.next/server/server-reference-manifest.js +1 -1
  75. package/web-ui/web-ui/.next/server/server-reference-manifest.json +1 -1
  76. package/web-ui/web-ui/.next/static/chunks/622-0520747def5cc37b.js +62 -0
  77. package/web-ui/web-ui/.next/static/chunks/699-f5e42f0ed71707d9.js +1 -0
  78. package/web-ui/web-ui/.next/static/chunks/app/(app)/activity/{page-2011aeec5114533f.js → page-ee3b9956abc7cf1b.js} +1 -1
  79. package/web-ui/web-ui/.next/static/chunks/app/(app)/data-shares/page-9997c04ce4d4a451.js +1 -0
  80. package/web-ui/web-ui/.next/static/chunks/app/(app)/detections/page-5c9b3e6f6d832127.js +1 -0
  81. package/web-ui/web-ui/.next/static/chunks/app/(app)/exceptions/[id]/page-5f56a9fa25e7af46.js +1 -0
  82. package/web-ui/web-ui/.next/static/chunks/app/(app)/exceptions/new/page-38dcdc2eb2e47f53.js +1 -0
  83. package/web-ui/web-ui/.next/static/chunks/app/(app)/exceptions/page-94d735bc414c9b5c.js +1 -0
  84. package/web-ui/web-ui/.next/static/chunks/app/(app)/findings/{page-5e9249b49d619cf7.js → page-073d0b64e942914f.js} +1 -1
  85. package/web-ui/web-ui/.next/static/chunks/app/(app)/inventory/page-71344cf66ee67b51.js +1 -0
  86. package/web-ui/web-ui/.next/static/chunks/app/(app)/scan/page-24429599495731bf.js +1 -0
  87. package/web-ui/web-ui/.next/static/chunks/app/(app)/settings/{page-bc4551c2cd096584.js → page-f633645e1112fcb9.js} +1 -1
  88. package/web-ui/web-ui/.next/static/chunks/app/(app)/updates/{page-d0b9a88e5cff5d9b.js → page-429f377f34456a96.js} +1 -1
  89. package/web-ui/web-ui/.next/static/chunks/app/(app)/vault/{page-de6afbc0036fcb0d.js → page-21c59276737a8b9e.js} +1 -1
  90. package/web-ui/web-ui/dist/scan-worker.js +118 -0
  91. package/web-ui/web-ui/.next/server/chunks/129.js +0 -783
  92. package/web-ui/web-ui/.next/static/chunks/622-e65110f232ad3136.js +0 -62
  93. package/web-ui/web-ui/.next/static/chunks/699-3a550a0d6101e35c.js +0 -1
  94. package/web-ui/web-ui/.next/static/chunks/app/(app)/data-shares/page-e8fbf441cdc78d7e.js +0 -1
  95. package/web-ui/web-ui/.next/static/chunks/app/(app)/detections/page-0cf86550a9f22cf8.js +0 -1
  96. package/web-ui/web-ui/.next/static/chunks/app/(app)/exceptions/[id]/page-3b57fa7a28949fdf.js +0 -1
  97. package/web-ui/web-ui/.next/static/chunks/app/(app)/exceptions/new/page-5524f6b8dd008924.js +0 -1
  98. package/web-ui/web-ui/.next/static/chunks/app/(app)/exceptions/page-5fcea0008a2c0bfc.js +0 -1
  99. package/web-ui/web-ui/.next/static/chunks/app/(app)/inventory/page-b1676f9a9b4673f1.js +0 -1
  100. package/web-ui/web-ui/.next/static/chunks/app/(app)/scan/page-3560c03478bda4c7.js +0 -1
  101. /package/web-ui/web-ui/.next/static/{YqH1rSLTmXzavf3MtB9ZX → zjNAa9qOfKutYwuhfySp_}/_buildManifest.js +0 -0
  102. /package/web-ui/web-ui/.next/static/{YqH1rSLTmXzavf3MtB9ZX → zjNAa9qOfKutYwuhfySp_}/_ssgManifest.js +0 -0
package/dist/cli.js CHANGED
@@ -51,7 +51,7 @@ var require_ignore = __commonJS({
51
51
  var REGEX_SPLITALL_CRLF = /\r?\n/g;
52
52
  var REGEX_TEST_INVALID_PATH = /^\.{0,2}\/|^\.{1,2}$/;
53
53
  var REGEX_TEST_TRAILING_SLASH = /\/$/;
54
- var SLASH = "/";
54
+ var SLASH2 = "/";
55
55
  var TMP_KEY_IGNORE = "node-ignore";
56
56
  if (typeof Symbol !== "undefined") {
57
57
  TMP_KEY_IGNORE = /* @__PURE__ */ Symbol.for("node-ignore");
@@ -423,11 +423,11 @@ var require_ignore = __commonJS({
423
423
  if (!REGEX_TEST_TRAILING_SLASH.test(path)) {
424
424
  return this.test(path);
425
425
  }
426
- const slices = path.split(SLASH).filter(Boolean);
426
+ const slices = path.split(SLASH2).filter(Boolean);
427
427
  slices.pop();
428
428
  if (slices.length) {
429
429
  const parent = this._t(
430
- slices.join(SLASH) + SLASH,
430
+ slices.join(SLASH2) + SLASH2,
431
431
  this._testCache,
432
432
  true,
433
433
  slices
@@ -443,14 +443,14 @@ var require_ignore = __commonJS({
443
443
  return cache[path];
444
444
  }
445
445
  if (!slices) {
446
- slices = path.split(SLASH).filter(Boolean);
446
+ slices = path.split(SLASH2).filter(Boolean);
447
447
  }
448
448
  slices.pop();
449
449
  if (!slices.length) {
450
450
  return cache[path] = this._rules.test(path, checkUnignored, MODE_IGNORE);
451
451
  }
452
452
  const parent = this._t(
453
- slices.join(SLASH) + SLASH,
453
+ slices.join(SLASH2) + SLASH2,
454
454
  cache,
455
455
  checkUnignored,
456
456
  slices
@@ -16451,6 +16451,125 @@ var ConfigScanRecord = external_exports.object({
16451
16451
  findings: external_exports.array(ConfigPostureFindingInput).optional()
16452
16452
  });
16453
16453
 
16454
+ // ../packages/schema/src/zod/control-plane.ts
16455
+ var ATTACHED_CREDENTIAL_FILENAME = "control-plane-credential.json";
16456
+ var ATTACHED_CREDENTIAL_SPEC_VERSION = 1;
16457
+ var AttachedCredential = external_exports.object({
16458
+ specVersion: external_exports.literal(ATTACHED_CREDENTIAL_SPEC_VERSION),
16459
+ // The control-plane endpoint this credential was minted against.
16460
+ endpoint: external_exports.string().min(1),
16461
+ // The bearer credential itself. Never logged, never rendered — status
16462
+ // surfaces show `keyPrefix` and nothing else.
16463
+ apiKey: external_exports.string().min(1),
16464
+ // First few characters of the key, safe to display so a user can match the
16465
+ // credential against their organization's key list.
16466
+ keyPrefix: external_exports.string().min(1).max(16).optional(),
16467
+ mintedAt: external_exports.iso.datetime().optional()
16468
+ });
16469
+ var MAX_DATE_MS = 253402300799999;
16470
+ var MAX_INT4 = 2147483647;
16471
+ var StorePosturePack = external_exports.object({
16472
+ packId: external_exports.string().min(1),
16473
+ // 'namespace/packId'
16474
+ version: external_exports.string().min(1),
16475
+ enabled: external_exports.boolean(),
16476
+ // Stringified pass-through of the local store's `installed_packs.updated_at`
16477
+ // — the column format is store-version-dependent (epoch millis vs ISO), so
16478
+ // the wire shape assumes neither.
16479
+ updatedAt: external_exports.string().nullable()
16480
+ }).meta({ id: "StorePosturePack" });
16481
+ var StorePosturePolicyCounts = external_exports.object({
16482
+ total: external_exports.number().int().min(0),
16483
+ disabled: external_exports.number().int().min(0),
16484
+ // Exhaustive per-action map; the builder pre-fills every action with 0.
16485
+ //
16486
+ // Spelled out member-by-member rather than `z.record(ActionTaken, …)`. Zod
16487
+ // enforces exhaustiveness either way, but z.record emits `propertyNames` +
16488
+ // `additionalProperties` into a generated schema document, and a type
16489
+ // generator renders THAT with every key optional — a sender built against
16490
+ // the generated type would typecheck and still be rejected at runtime. An
16491
+ // explicit object emits `properties` + `required`, so generated types
16492
+ // demand all five.
16493
+ //
16494
+ // `satisfies Record<ActionTaken, …>` keeps the link to the enum: adding an
16495
+ // ActionTaken member is a COMPILE error here instead of silent drift.
16496
+ // `.strict()` is load-bearing — it rejects an unknown action key, which a
16497
+ // bare object would silently STRIP, accepting a miscounted map as valid.
16498
+ byAction: external_exports.object({
16499
+ warn: external_exports.number().int().min(0),
16500
+ redact: external_exports.number().int().min(0),
16501
+ block: external_exports.number().int().min(0),
16502
+ allow: external_exports.number().int().min(0),
16503
+ log: external_exports.number().int().min(0)
16504
+ }).strict()
16505
+ }).meta({ id: "StorePosturePolicyCounts" });
16506
+ var StorePosturePlugin = external_exports.object({
16507
+ /** Package name of the reporting plugin. */
16508
+ package: external_exports.string().min(1).max(200),
16509
+ version: external_exports.string().min(1).max(64),
16510
+ /** Version of the bundled core, when the build records one separately. */
16511
+ ossVersion: external_exports.string().max(64).nullable(),
16512
+ /**
16513
+ * `version` of the policy bundle this machine last fetched. Bounded at 200
16514
+ * rather than the 64 a bare sha256 hex digest needs today, so a later
16515
+ * format with an algorithm prefix does not start rejecting the channel.
16516
+ */
16517
+ policyBundleVersion: external_exports.string().max(200).nullable(),
16518
+ /** Epoch millis, on the CLIENT clock, of that fetch. */
16519
+ policyFetchedAt: external_exports.number().int().min(0).max(MAX_DATE_MS).nullable()
16520
+ }).meta({ id: "StorePosturePlugin" });
16521
+ var StorePostureSnapshot = external_exports.object({
16522
+ deviceId: external_exports.guid(),
16523
+ hostname: external_exports.string().min(1).max(253),
16524
+ // Epoch millis on the CLIENT clock. Bounded by what a receiving store
16525
+ // accepts (see MAX_DATE_MS), not by what a JavaScript Date can hold.
16526
+ capturedAt: external_exports.number().int().min(0).max(MAX_DATE_MS),
16527
+ // False is a measurement, not an error state: "no local store exists on
16528
+ // this machine".
16529
+ storePresent: external_exports.boolean(),
16530
+ schemaVersion: external_exports.number().int().min(0).max(MAX_INT4).nullable(),
16531
+ // PRAGMA user_version
16532
+ findingsTotal: external_exports.number().int().min(0).max(MAX_INT4),
16533
+ // Epoch millis, bounded like `capturedAt` — see MAX_DATE_MS on what that
16534
+ // bound does and does not do. Worth stating for these two specifically:
16535
+ // they are read from the local store's own ROWS rather than from this
16536
+ // machine's clock, so a damaged or hand-edited store is enough to produce
16537
+ // an out-of-range value with no clock skew involved.
16538
+ findingsFirstAt: external_exports.number().int().min(0).max(MAX_DATE_MS).nullable(),
16539
+ findingsLastAt: external_exports.number().int().min(0).max(MAX_DATE_MS).nullable(),
16540
+ packs: external_exports.array(StorePosturePack).max(500),
16541
+ policyCounts: StorePosturePolicyCounts,
16542
+ // OPTIONAL, not nullable: a reporter that predates this member keeps
16543
+ // getting its 200 without a payload change.
16544
+ plugin: StorePosturePlugin.optional()
16545
+ }).meta({ id: "StorePostureSnapshot" });
16546
+ var CAPTURE_VERSION_PREFIX = "capture/";
16547
+ var RecordAuditEventRequest = AuditEventInput.extend({
16548
+ inspections: external_exports.array(ToolCallInspection).default([])
16549
+ }).refine((v) => v.inspections.every((i) => !i.ruleVersion.startsWith(CAPTURE_VERSION_PREFIX)), {
16550
+ message: `inspections[].ruleVersion must not start with \`${CAPTURE_VERSION_PREFIX}\` \u2014 that namespace is reserved for capture definitions the control plane mints itself`,
16551
+ path: ["inspections"]
16552
+ }).meta({ id: "RecordAuditEventRequest" });
16553
+ var IngestAck = external_exports.object({
16554
+ accepted: external_exports.number().int().nonnegative(),
16555
+ duplicates: external_exports.number().int().nonnegative()
16556
+ });
16557
+ var PRINTABLE = /^[^\p{Cc}\p{Cf}]*$/u;
16558
+ var printable = (max) => external_exports.string().max(max).regex(PRINTABLE, "must not contain control characters");
16559
+ var PluginWhoami = external_exports.object({
16560
+ tenantName: printable(200),
16561
+ userEmail: printable(320),
16562
+ role: printable(64),
16563
+ keyKind: printable(64),
16564
+ serverTime: printable(64)
16565
+ });
16566
+ var ControlPlaneErrorBody = external_exports.object({
16567
+ error: external_exports.object({
16568
+ code: external_exports.string().optional(),
16569
+ message: external_exports.string().optional()
16570
+ }).optional()
16571
+ });
16572
+
16454
16573
  // ../packages/schema/src/zod/registry.ts
16455
16574
  var Namespace = external_exports.string().regex(/^[a-z][a-z0-9-]*$/);
16456
16575
  var PackId = external_exports.string().regex(/^[a-z][a-z0-9-]*$/);
@@ -16753,15 +16872,15 @@ function summaryToDetectionListItem(s) {
16753
16872
  }
16754
16873
  function rowToDetectionDetail(row, findingsLast30d, update) {
16755
16874
  const rules = row.rules.flatMap((r) => {
16756
- const parsed = Matcher.safeParse(r.matcher);
16757
- if (!parsed.success) return [];
16875
+ const parsed2 = Matcher.safeParse(r.matcher);
16876
+ if (!parsed2.success) return [];
16758
16877
  return [
16759
16878
  {
16760
16879
  id: r.id,
16761
16880
  name: r.name,
16762
16881
  category: r.category,
16763
16882
  severity: r.severity,
16764
- matcher: parsed.data
16883
+ matcher: parsed2.data
16765
16884
  }
16766
16885
  ];
16767
16886
  });
@@ -17419,8 +17538,8 @@ function toApiAction(dbVal) {
17419
17538
  }
17420
17539
  function toApiCategory(dbVal) {
17421
17540
  if (dbVal === "code_context") return "source_code";
17422
- const parsed = FindingCategory.safeParse(dbVal);
17423
- return parsed.success ? parsed.data : "custom";
17541
+ const parsed2 = FindingCategory.safeParse(dbVal);
17542
+ return parsed2.success ? parsed2.data : "custom";
17424
17543
  }
17425
17544
  function toApiProvider(sourceTool) {
17426
17545
  return TOOL_TO_HARNESS[sourceTool] ?? HARNESS.Api;
@@ -18024,6 +18143,9 @@ var ModelJudgeConsent = external_exports.object({
18024
18143
  acknowledgedAt: external_exports.iso.datetime(),
18025
18144
  payloadVersion: external_exports.number().int().positive()
18026
18145
  });
18146
+ function isModelJudgeConsentValid(consent) {
18147
+ return consent?.payloadVersion === MODEL_JUDGE_PAYLOAD_VERSION;
18148
+ }
18027
18149
  var WorkspaceSettings = external_exports.object({
18028
18150
  specVersion: external_exports.number().int().positive().default(WORKSPACE_SETTINGS_SPEC_VERSION),
18029
18151
  runMode: RunMode.default("standalone"),
@@ -18057,6 +18179,12 @@ var WorkspaceSettings = external_exports.object({
18057
18179
  function defaultWorkspaceSettings() {
18058
18180
  return WorkspaceSettings.parse({});
18059
18181
  }
18182
+ function isAttached(settings) {
18183
+ return settings.runMode === "attached" && settings.controlPlane !== void 0;
18184
+ }
18185
+ function controlPlaneName(connection) {
18186
+ return connection.label ?? connection.endpoint;
18187
+ }
18060
18188
  function toInventoryRow(input, id, now) {
18061
18189
  return {
18062
18190
  id,
@@ -18202,6 +18330,7 @@ var ManagedSettings = external_exports.object({
18202
18330
  // the user may still override. The two are separable on purpose.
18203
18331
  lockedFields: external_exports.array(ManagedSettingKey).default([])
18204
18332
  }).meta({ id: "ManagedSettings" });
18333
+ var NO_MANAGED_CONTEXT = { present: false, lockedFields: [] };
18205
18334
 
18206
18335
  // ../packages/schema/src/zod/policy.ts
18207
18336
  var PolicyScope = external_exports.enum(["global", "repo", "user"]).meta({ id: "PolicyScope" });
@@ -18324,8 +18453,8 @@ function builtinPolicyIsReversible(id) {
18324
18453
  return BUILTIN_POLICY_SPECS[id].reversible;
18325
18454
  }
18326
18455
  function policyIdIsReversible(policyId) {
18327
- const parsed = BuiltinPolicyId.safeParse(policyId ?? DEFAULT_PACK_POLICY_ID);
18328
- const id = parsed.success ? parsed.data : DEFAULT_PACK_POLICY_ID;
18456
+ const parsed2 = BuiltinPolicyId.safeParse(policyId ?? DEFAULT_PACK_POLICY_ID);
18457
+ const id = parsed2.success ? parsed2.data : DEFAULT_PACK_POLICY_ID;
18329
18458
  return builtinPolicyIsReversible(id);
18330
18459
  }
18331
18460
  var DEFAULT_ACTIONS = Object.fromEntries(
@@ -18337,12 +18466,12 @@ var BUILTIN_POLICIES = Object.fromEntries(
18337
18466
  var DEFAULT_PACK_POLICY_ID = "monitor";
18338
18467
  function policyDisplayName(policyId) {
18339
18468
  const id = policyId ?? DEFAULT_PACK_POLICY_ID;
18340
- const parsed = BuiltinPolicyId.safeParse(id);
18341
- return parsed.success ? BUILTIN_POLICIES[parsed.data].name : id;
18469
+ const parsed2 = BuiltinPolicyId.safeParse(id);
18470
+ return parsed2.success ? BUILTIN_POLICIES[parsed2.data].name : id;
18342
18471
  }
18343
18472
  function policyIdToAction(policyId) {
18344
- const parsed = BuiltinPolicyId.safeParse(policyId ?? DEFAULT_PACK_POLICY_ID);
18345
- const id = parsed.success ? parsed.data : DEFAULT_PACK_POLICY_ID;
18473
+ const parsed2 = BuiltinPolicyId.safeParse(policyId ?? DEFAULT_PACK_POLICY_ID);
18474
+ const id = parsed2.success ? parsed2.data : DEFAULT_PACK_POLICY_ID;
18346
18475
  return BUILTIN_POLICIES[id].action;
18347
18476
  }
18348
18477
  var UsedByItem = external_exports.object({
@@ -19366,8 +19495,8 @@ var installCodexPlugin = manager2.install;
19366
19495
  var updateCodexPlugin = manager2.update;
19367
19496
 
19368
19497
  // ../packages/local-ops/src/egress-record.ts
19369
- import { statSync as statSync7 } from "fs";
19370
- import { dirname as dirname6, relative, resolve } from "path";
19498
+ import { statSync as statSync9 } from "fs";
19499
+ import { dirname as dirname7, relative, resolve as resolve2 } from "path";
19371
19500
 
19372
19501
  // ../packages/detections/src/egress/registry.ts
19373
19502
  var EXTRACTOR_VERSION = "1";
@@ -20160,11 +20289,11 @@ function extractEgress(text) {
20160
20289
  if (scheme === void 0) continue;
20161
20290
  const candidate = matched.replace(TRAILING_PUNCTUATION, "");
20162
20291
  if (candidate === "") continue;
20163
- const parsed = parseCandidate(candidate, scheme);
20164
- if (parsed === null) continue;
20292
+ const parsed2 = parseCandidate(candidate, scheme);
20293
+ if (parsed2 === null) continue;
20165
20294
  const index = lineIndexAt(lineStarts, start);
20166
20295
  hits.push({
20167
- ...parsed,
20296
+ ...parsed2,
20168
20297
  method: inferMethod(text, start, start + matched.length),
20169
20298
  line: index + 1,
20170
20299
  snippet: snippetAt(index, start)
@@ -20174,9 +20303,9 @@ function extractEgress(text) {
20174
20303
  const start = match.index;
20175
20304
  if (isInsideSpan(urlSpans, start)) continue;
20176
20305
  const index = lineIndexAt(lineStarts, start);
20177
- const parsed = parseBareIp(match[0], ipContextOf(index));
20178
- if (parsed === null) continue;
20179
- hits.push({ ...parsed, method: "REF", line: index + 1, snippet: snippetAt(index, start) });
20306
+ const parsed2 = parseBareIp(match[0], ipContextOf(index));
20307
+ if (parsed2 === null) continue;
20308
+ hits.push({ ...parsed2, method: "REF", line: index + 1, snippet: snippetAt(index, start) });
20180
20309
  }
20181
20310
  return hits.sort(compareHits);
20182
20311
  }
@@ -20188,21 +20317,21 @@ function parseCandidate(candidate, scheme) {
20188
20317
  placeholders2 += 1;
20189
20318
  return VAR_TOKEN;
20190
20319
  });
20191
- let parsed;
20320
+ let parsed2;
20192
20321
  try {
20193
- parsed = new URL(normalized.split(VAR_TOKEN).join(VAR_SENTINEL));
20322
+ parsed2 = new URL(normalized.split(VAR_TOKEN).join(VAR_SENTINEL));
20194
20323
  } catch {
20195
20324
  return null;
20196
20325
  }
20197
- const host = parsed.hostname.toLowerCase();
20326
+ const host = parsed2.hostname.toLowerCase();
20198
20327
  if (host === "" || host.includes(VAR_SENTINEL)) return null;
20199
- const authority = parsed.host.toLowerCase();
20200
- const path = maskWebhookPath(host, parsed.pathname);
20328
+ const authority = parsed2.host.toLowerCase();
20329
+ const path = maskWebhookPath(host, parsed2.pathname);
20201
20330
  const url2 = `${transport}://${authority}${path}`.split(VAR_SENTINEL).join(VAR_TOKEN);
20202
20331
  return {
20203
20332
  url: url2,
20204
20333
  host,
20205
- port: parsed.port === "" ? null : Number(parsed.port),
20334
+ port: parsed2.port === "" ? null : Number(parsed2.port),
20206
20335
  transport,
20207
20336
  template: placeholders2 > 0
20208
20337
  };
@@ -20396,15 +20525,15 @@ function makeHit(ecosystem, pkg, line, rawLine) {
20396
20525
  return { ecosystem, pkg, line, snippet: redactSnippet(rawLine) };
20397
20526
  }
20398
20527
  function extractPackageJson(text) {
20399
- const parsed = parseJson(text);
20400
- if (parsed === null) return [];
20528
+ const parsed2 = parseJson(text);
20529
+ if (parsed2 === null) return [];
20401
20530
  const seen = /* @__PURE__ */ new Set();
20402
20531
  const hits = [];
20403
- for (const pkg of objectKeys(parsed.dependencies)) {
20532
+ for (const pkg of objectKeys(parsed2.dependencies)) {
20404
20533
  seen.add(pkg);
20405
20534
  hits.push(hitAtQuotedKey("npm", pkg, text, "dependencies"));
20406
20535
  }
20407
- for (const pkg of objectKeys(parsed.optionalDependencies)) {
20536
+ for (const pkg of objectKeys(parsed2.optionalDependencies)) {
20408
20537
  if (seen.has(pkg)) continue;
20409
20538
  seen.add(pkg);
20410
20539
  hits.push(hitAtQuotedKey("npm", pkg, text, "optionalDependencies"));
@@ -20588,9 +20717,9 @@ function extractCargoToml(text) {
20588
20717
  return hits;
20589
20718
  }
20590
20719
  function extractComposerJson(text) {
20591
- const parsed = parseJson(text);
20592
- if (parsed === null) return [];
20593
- const pkgs = objectKeys(parsed.require).filter((pkg) => pkg !== "php" && !pkg.startsWith("ext-"));
20720
+ const parsed2 = parseJson(text);
20721
+ if (parsed2 === null) return [];
20722
+ const pkgs = objectKeys(parsed2.require).filter((pkg) => pkg !== "php" && !pkg.startsWith("ext-"));
20594
20723
  return pkgs.map((pkg) => hitAtQuotedKey("composer", pkg, text, "require"));
20595
20724
  }
20596
20725
  var CSPROJ_PACKAGE_REFERENCE = /<PackageReference\s+Include="([^"]+)"/;
@@ -20643,14 +20772,14 @@ function eachLine(text, fn) {
20643
20772
  }
20644
20773
  }
20645
20774
  function parseJson(text) {
20646
- let parsed;
20775
+ let parsed2;
20647
20776
  try {
20648
- parsed = JSON.parse(text);
20777
+ parsed2 = JSON.parse(text);
20649
20778
  } catch {
20650
20779
  return null;
20651
20780
  }
20652
- if (typeof parsed !== "object" || parsed === null) return null;
20653
- const record2 = parsed;
20781
+ if (typeof parsed2 !== "object" || parsed2 === null) return null;
20782
+ const record2 = parsed2;
20654
20783
  return {
20655
20784
  dependencies: record2.dependencies,
20656
20785
  optionalDependencies: record2.optionalDependencies,
@@ -21171,46 +21300,9 @@ var POLYNOMIAL_PROBES = ["abc-", "a.", "a ", "a=", "x", "0", "a@", "a/", "ab"].m
21171
21300
  var CPU_CORROBORATION_SHARE = 0.2;
21172
21301
  var CORROBORATION_FLOOR_MS = BUDGET_MS * CPU_CORROBORATION_SHARE;
21173
21302
 
21174
- // ../packages/persistence/src/database.ts
21175
- import { randomUUID as randomUUID10 } from "crypto";
21176
- import { join as join4, sep as sep2 } from "path";
21177
- import { DatabaseSync } from "node:sqlite";
21178
-
21179
- // ../packages/persistence/src/ids.ts
21180
- import { createHash } from "crypto";
21181
- function sha256Hex(input) {
21182
- return createHash("sha256").update(input).digest("hex");
21183
- }
21184
- function inventoryId(objectType, identityKey) {
21185
- return sha256Hex(canonicalIdentity(["inventory", objectType, identityKey]));
21186
- }
21187
- function sourceProjectId(url2) {
21188
- return sha256Hex(canonicalIdentity(["source_project", url2]));
21189
- }
21190
- function classifiedDataId(cls) {
21191
- return sha256Hex(canonicalIdentity(["classified_data", cls]));
21192
- }
21193
- function inspectionDefinitionId(ruleId, version2) {
21194
- return sha256Hex(canonicalIdentity(["inspection_definition", ruleId, version2]));
21195
- }
21196
- function llmCallId(sessionId, messageId) {
21197
- return sha256Hex(canonicalIdentity(["audit_event_llm_call", sessionId, messageId]));
21198
- }
21199
- function toolCallId(sessionId, toolUseId) {
21200
- return sha256Hex(canonicalIdentity(["audit_event_tool_call", sessionId, toolUseId]));
21201
- }
21202
- var NO_SESSION = "no_session";
21203
- var NO_PATH = "no_path";
21204
- function captureId(sessionId, contentHash, filePath = null) {
21205
- return sha256Hex(
21206
- canonicalIdentity(["capture", sessionId ?? NO_SESSION, contentHash, filePath ?? NO_PATH])
21207
- );
21208
- }
21209
-
21210
- // ../packages/persistence/src/internal/snapshot.ts
21211
- import { randomUUID } from "crypto";
21212
- import { existsSync as existsSync3, readdirSync as readdirSync2, renameSync as renameSync2, rmSync as rmSync2, statSync } from "fs";
21213
- import { basename, dirname as dirname3, join as join3 } from "path";
21303
+ // ../packages/persistence/src/control-plane-credential.ts
21304
+ import { chmodSync as chmodSync2, lstatSync as lstatSync2, readFileSync as readFileSync3, rmSync as rmSync2, statSync } from "fs";
21305
+ import { join as join3 } from "path";
21214
21306
 
21215
21307
  // ../packages/persistence/src/paths.ts
21216
21308
  import {
@@ -21337,7 +21429,131 @@ function publishByLink(tmp, file2, data) {
21337
21429
  }
21338
21430
  }
21339
21431
 
21432
+ // ../packages/persistence/src/control-plane-credential.ts
21433
+ function controlPlaneCredentialPath(settingsDir2) {
21434
+ return join3(settingsDir2, ATTACHED_CREDENTIAL_FILENAME);
21435
+ }
21436
+ var LOOPBACK_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1", "::1", "[::1]"]);
21437
+ function isSafeEndpoint(endpoint) {
21438
+ let parsed2;
21439
+ try {
21440
+ parsed2 = new URL(endpoint);
21441
+ } catch {
21442
+ return false;
21443
+ }
21444
+ if (parsed2.protocol === "https:") return true;
21445
+ return parsed2.protocol === "http:" && LOOPBACK_HOSTS.has(parsed2.hostname);
21446
+ }
21447
+ function repairOrRefuseMode(file2) {
21448
+ const link = lstatSync2(file2, { throwIfNoEntry: false });
21449
+ if (link === void 0) return "absent";
21450
+ if (link.isSymbolicLink()) return "untrusted";
21451
+ const stat = statSync(file2, { throwIfNoEntry: false });
21452
+ if (stat === void 0) return "absent";
21453
+ const uid = process.getuid?.();
21454
+ if (uid !== void 0 && stat.uid !== uid) return "untrusted";
21455
+ if (process.platform !== "win32" && (stat.mode & 511) !== DATA_FILE_MODE) {
21456
+ try {
21457
+ chmodSync2(file2, DATA_FILE_MODE);
21458
+ } catch {
21459
+ return "untrusted";
21460
+ }
21461
+ }
21462
+ return "ok";
21463
+ }
21464
+ function readControlPlaneCredentialState(settingsDir2, connection) {
21465
+ const file2 = controlPlaneCredentialPath(settingsDir2);
21466
+ let raw;
21467
+ const gate = repairOrRefuseMode(file2);
21468
+ if (gate === "absent") return { usable: false, reason: "absent" };
21469
+ if (gate === "untrusted") return { usable: false, reason: "untrusted-file" };
21470
+ try {
21471
+ raw = readFileSync3(file2, "utf8");
21472
+ } catch (err) {
21473
+ const code = err.code;
21474
+ return { usable: false, reason: code === "ENOENT" ? "absent" : "unreadable" };
21475
+ }
21476
+ let parsed2;
21477
+ try {
21478
+ parsed2 = JSON.parse(raw);
21479
+ } catch {
21480
+ return { usable: false, reason: "malformed" };
21481
+ }
21482
+ const result = AttachedCredential.safeParse(parsed2);
21483
+ if (!result.success) return { usable: false, reason: "malformed" };
21484
+ if (!isSafeEndpoint(result.data.endpoint)) {
21485
+ return { usable: false, reason: "unsafe-endpoint" };
21486
+ }
21487
+ if (connection !== void 0 && connection.endpoint !== result.data.endpoint) {
21488
+ return {
21489
+ usable: false,
21490
+ reason: "endpoint-mismatch",
21491
+ credentialEndpoint: result.data.endpoint,
21492
+ settingsEndpoint: connection.endpoint
21493
+ };
21494
+ }
21495
+ return { usable: true, credential: result.data };
21496
+ }
21497
+ function writeControlPlaneCredential(settingsDir2, credential) {
21498
+ if (!isSafeEndpoint(credential.endpoint)) {
21499
+ throw new Error(
21500
+ `refusing to store a control-plane credential for a non-HTTPS endpoint: ${credential.endpoint}`
21501
+ );
21502
+ }
21503
+ ensureDataDirSync(settingsDir2);
21504
+ writeOwnerOnlyFileSync(
21505
+ controlPlaneCredentialPath(settingsDir2),
21506
+ `${JSON.stringify(credential, null, 2)}
21507
+ `
21508
+ );
21509
+ }
21510
+ function removeControlPlaneCredential(settingsDir2) {
21511
+ const file2 = controlPlaneCredentialPath(settingsDir2);
21512
+ const existed = lstatSync2(file2, { throwIfNoEntry: false }) !== void 0;
21513
+ rmSync2(file2, { force: true });
21514
+ return existed;
21515
+ }
21516
+
21517
+ // ../packages/persistence/src/database.ts
21518
+ import { randomUUID as randomUUID10 } from "crypto";
21519
+ import { join as join5, sep as sep2 } from "path";
21520
+ import { DatabaseSync } from "node:sqlite";
21521
+
21522
+ // ../packages/persistence/src/ids.ts
21523
+ import { createHash } from "crypto";
21524
+ function sha256Hex(input) {
21525
+ return createHash("sha256").update(input).digest("hex");
21526
+ }
21527
+ function inventoryId(objectType, identityKey) {
21528
+ return sha256Hex(canonicalIdentity(["inventory", objectType, identityKey]));
21529
+ }
21530
+ function sourceProjectId(url2) {
21531
+ return sha256Hex(canonicalIdentity(["source_project", url2]));
21532
+ }
21533
+ function classifiedDataId(cls) {
21534
+ return sha256Hex(canonicalIdentity(["classified_data", cls]));
21535
+ }
21536
+ function inspectionDefinitionId(ruleId, version2) {
21537
+ return sha256Hex(canonicalIdentity(["inspection_definition", ruleId, version2]));
21538
+ }
21539
+ function llmCallId(sessionId, messageId) {
21540
+ return sha256Hex(canonicalIdentity(["audit_event_llm_call", sessionId, messageId]));
21541
+ }
21542
+ function toolCallId(sessionId, toolUseId) {
21543
+ return sha256Hex(canonicalIdentity(["audit_event_tool_call", sessionId, toolUseId]));
21544
+ }
21545
+ var NO_SESSION = "no_session";
21546
+ var NO_PATH = "no_path";
21547
+ function captureId(sessionId, contentHash, filePath = null) {
21548
+ return sha256Hex(
21549
+ canonicalIdentity(["capture", sessionId ?? NO_SESSION, contentHash, filePath ?? NO_PATH])
21550
+ );
21551
+ }
21552
+
21340
21553
  // ../packages/persistence/src/internal/snapshot.ts
21554
+ import { randomUUID } from "crypto";
21555
+ import { existsSync as existsSync3, readdirSync as readdirSync2, renameSync as renameSync2, rmSync as rmSync3, statSync as statSync2 } from "fs";
21556
+ import { basename, dirname as dirname3, join as join4 } from "path";
21341
21557
  function backupPath(file2, tag) {
21342
21558
  return `${file2}.${tag}.${String(Date.now())}.${randomUUID().slice(0, 8)}.bak`;
21343
21559
  }
@@ -21347,15 +21563,15 @@ var STAGED_NAME_SUFFIX = `.bak${SNAPSHOT_STAGING_SUFFIX}`;
21347
21563
  var SNAPSHOT_STAGING_COPY = "copy";
21348
21564
  function createSnapshotStaging(backup) {
21349
21565
  const stage = `${backup}${SNAPSHOT_STAGING_SUFFIX}`;
21350
- rmSync2(stage, { recursive: true, force: true });
21566
+ rmSync3(stage, { recursive: true, force: true });
21351
21567
  mkdirOwnerOnlySync(stage);
21352
21568
  tightenDir(stage);
21353
- return { stage, copy: join3(stage, SNAPSHOT_STAGING_COPY) };
21569
+ return { stage, copy: join4(stage, SNAPSHOT_STAGING_COPY) };
21354
21570
  }
21355
21571
  function idleMs(entry) {
21356
- for (const candidate of [join3(entry, SNAPSHOT_STAGING_COPY), entry]) {
21572
+ for (const candidate of [join4(entry, SNAPSHOT_STAGING_COPY), entry]) {
21357
21573
  try {
21358
- return Date.now() - statSync(candidate).mtimeMs;
21574
+ return Date.now() - statSync2(candidate).mtimeMs;
21359
21575
  } catch {
21360
21576
  }
21361
21577
  }
@@ -21372,11 +21588,11 @@ function reapStalePartials(file2) {
21372
21588
  }
21373
21589
  for (const name of entries) {
21374
21590
  if (!name.startsWith(prefix) || !name.endsWith(STAGED_NAME_SUFFIX)) continue;
21375
- const staging = join3(dir, name);
21591
+ const staging = join4(dir, name);
21376
21592
  try {
21377
21593
  const idle = idleMs(staging);
21378
21594
  if (idle !== null && idle > STALE_PARTIAL_MS) {
21379
- rmSync2(staging, { recursive: true, force: true });
21595
+ rmSync3(staging, { recursive: true, force: true });
21380
21596
  }
21381
21597
  } catch {
21382
21598
  }
@@ -21390,13 +21606,13 @@ function snapshotStore(db, backup) {
21390
21606
  renameSync2(copy, backup);
21391
21607
  } catch (error51) {
21392
21608
  try {
21393
- rmSync2(stage, { recursive: true, force: true });
21609
+ rmSync3(stage, { recursive: true, force: true });
21394
21610
  } catch {
21395
21611
  }
21396
21612
  throw error51;
21397
21613
  }
21398
21614
  try {
21399
- rmSync2(stage, { recursive: true, force: true });
21615
+ rmSync3(stage, { recursive: true, force: true });
21400
21616
  } catch {
21401
21617
  }
21402
21618
  }
@@ -21411,7 +21627,7 @@ function moveStoreAside(file2, backup) {
21411
21627
  renameSync2(sidecar, moved);
21412
21628
  undo.push([moved, sidecar]);
21413
21629
  } catch {
21414
- rmSync2(sidecar, { force: true });
21630
+ rmSync3(sidecar, { force: true });
21415
21631
  }
21416
21632
  }
21417
21633
  } catch (error51) {
@@ -21427,14 +21643,14 @@ function moveStoreAside(file2, backup) {
21427
21643
  }
21428
21644
  function discardStore(file2, backup) {
21429
21645
  try {
21430
- rmSync2(file2, { force: true });
21646
+ rmSync3(file2, { force: true });
21431
21647
  for (const sidecar of dbSidecars(file2)) {
21432
- rmSync2(sidecar, { force: true });
21648
+ rmSync3(sidecar, { force: true });
21433
21649
  }
21434
21650
  } catch (error51) {
21435
21651
  if (existsSync3(file2)) {
21436
21652
  try {
21437
- rmSync2(backup, { force: true });
21653
+ rmSync3(backup, { force: true });
21438
21654
  } catch {
21439
21655
  }
21440
21656
  }
@@ -21666,10 +21882,31 @@ function applyMigrations(db, file2) {
21666
21882
  if (drained) applyLegacyDropMigration(db, file2);
21667
21883
  }
21668
21884
  }
21885
+ function readLegacyTables(db) {
21886
+ let holdsRows = false;
21887
+ const marks = [];
21888
+ for (const table of ["events", "findings"]) {
21889
+ try {
21890
+ const row = db.prepare(`SELECT count(*) AS n, ifnull(max(rowid), -1) AS hi FROM ${table}`).get();
21891
+ if (row === void 0) {
21892
+ holdsRows = true;
21893
+ marks.push(`${table}:unreadable`);
21894
+ continue;
21895
+ }
21896
+ if (row.n > 0) holdsRows = true;
21897
+ marks.push(`${table}:${String(row.n)}:${String(row.hi)}`);
21898
+ } catch {
21899
+ holdsRows = true;
21900
+ marks.push(`${table}:unreadable`);
21901
+ }
21902
+ }
21903
+ return { holdsRows, mark: marks.join("|") };
21904
+ }
21669
21905
  function applyLegacyDropMigration(db, file2) {
21670
21906
  const migration = SQLITE_MIGRATIONS.find((m) => m.tag === LEGACY_DROP_MIGRATION_TAG);
21671
21907
  if (!migration) return;
21672
- if (file2) {
21908
+ const before = file2 === void 0 ? void 0 : readLegacyTables(db);
21909
+ if (file2 !== void 0 && before?.holdsRows === true) {
21673
21910
  try {
21674
21911
  backupBeforeLegacyDrop(db, file2);
21675
21912
  } catch (error51) {
@@ -21683,6 +21920,12 @@ function applyLegacyDropMigration(db, file2) {
21683
21920
  () => {
21684
21921
  const alreadyDropped = db.prepare("SELECT 1 FROM migration_ledger WHERE tag = ?").get(migration.tag);
21685
21922
  if (alreadyDropped) return;
21923
+ if (before !== void 0 && readLegacyTables(db).mark !== before.mark) {
21924
+ akaWarn(
21925
+ "legacy events/findings rows changed after the pre-drop snapshot decision; deferring the drop so the next open can copy them first."
21926
+ );
21927
+ return;
21928
+ }
21686
21929
  for (const statement of splitStatements(migration.sql)) {
21687
21930
  db.exec(statement);
21688
21931
  }
@@ -22037,8 +22280,8 @@ function safeJson(s, fallback) {
22037
22280
  function parseJsonObject(s) {
22038
22281
  if (s == null) return void 0;
22039
22282
  try {
22040
- const parsed = JSON.parse(s);
22041
- if (typeof parsed === "object" && parsed !== null) return parsed;
22283
+ const parsed2 = JSON.parse(s);
22284
+ if (typeof parsed2 === "object" && parsed2 !== null) return parsed2;
22042
22285
  } catch {
22043
22286
  }
22044
22287
  return void 0;
@@ -22049,16 +22292,16 @@ function encodeKeysetCursor(payload) {
22049
22292
  return Buffer.from(JSON.stringify(payload)).toString("base64url");
22050
22293
  }
22051
22294
  function decodeKeysetCursor(cursor) {
22052
- const parsed = parseJsonObject(Buffer.from(cursor, "base64url").toString("utf8"));
22053
- if (parsed !== void 0 && "startedAtMs" in parsed && "id" in parsed && // `Number.isInteger`, not `typeof === 'number'`. Every timestamp this
22295
+ const parsed2 = parseJsonObject(Buffer.from(cursor, "base64url").toString("utf8"));
22296
+ if (parsed2 !== void 0 && "startedAtMs" in parsed2 && "id" in parsed2 && // `Number.isInteger`, not `typeof === 'number'`. Every timestamp this
22054
22297
  // resumes from is epoch millis, and a payload carrying ±Infinity or a
22055
22298
  // fraction binds cleanly rather than failing — returning an EMPTY page with
22056
22299
  // a null cursor, which a caller reads as "end of list". That is the one
22057
22300
  // outcome a cursor that does not decode must never produce, since the
22058
22301
  // documented behaviour above is to restart from the top. (`1e999` is valid
22059
22302
  // JSON and parses to Infinity; a bare `NaN` is not, so it cannot arrive.)
22060
- Number.isInteger(parsed.startedAtMs) && typeof parsed.id === "string") {
22061
- return parsed;
22303
+ Number.isInteger(parsed2.startedAtMs) && typeof parsed2.id === "string") {
22304
+ return parsed2;
22062
22305
  }
22063
22306
  return null;
22064
22307
  }
@@ -22123,18 +22366,18 @@ var DB_EVENT_TYPE_TO_KIND = {
22123
22366
  };
22124
22367
  function safeParseStringArray(raw) {
22125
22368
  if (!raw) return [];
22126
- const parsed = safeJson(raw, null);
22127
- return Array.isArray(parsed) ? parsed : [];
22369
+ const parsed2 = safeJson(raw, null);
22370
+ return Array.isArray(parsed2) ? parsed2 : [];
22128
22371
  }
22129
22372
  var DEFAULT_HARNESS = HARNESS.ClaudeCode;
22130
22373
  function toHarness(raw) {
22131
- const parsed = Harness.safeParse(raw);
22132
- return parsed.success ? parsed.data : DEFAULT_HARNESS;
22374
+ const parsed2 = Harness.safeParse(raw);
22375
+ return parsed2.success ? parsed2.data : DEFAULT_HARNESS;
22133
22376
  }
22134
22377
  function resolveLifecycle(row, lastActivityMs, nowMs) {
22135
22378
  if (row.status) {
22136
- const parsed = SessionStatus.safeParse(row.status);
22137
- if (parsed.success) return { status: parsed.data, endedAtMs: row.ended_at };
22379
+ const parsed2 = SessionStatus.safeParse(row.status);
22380
+ if (parsed2.success) return { status: parsed2.data, endedAtMs: row.ended_at };
22138
22381
  }
22139
22382
  if (row.ended_at !== null) return { status: "completed", endedAtMs: row.ended_at };
22140
22383
  if (lastActivityMs >= nowMs - LIVE_ACTIVITY_WINDOW_MS) {
@@ -23093,9 +23336,9 @@ var SqliteDetectionsRepository = class {
23093
23336
  const ruleIds = /* @__PURE__ */ new Set();
23094
23337
  for (const r of rows) {
23095
23338
  if (intToBool(r.enabled)) active += 1;
23096
- const parsed = parseRules(r.rulesJson);
23097
- rules += parsed.length;
23098
- for (const rule of parsed) {
23339
+ const parsed2 = parseRules(r.rulesJson);
23340
+ rules += parsed2.length;
23341
+ for (const rule of parsed2) {
23099
23342
  if (typeof rule.id === "string") ruleIds.add(rule.id);
23100
23343
  }
23101
23344
  }
@@ -23629,12 +23872,12 @@ function encodeGroupCursor(group) {
23629
23872
  return Buffer.from(JSON.stringify(payload)).toString("base64url");
23630
23873
  }
23631
23874
  function decodeGroupCursor(cursor) {
23632
- const parsed = parseJsonObject(Buffer.from(cursor, "base64url").toString("utf8"));
23633
- if (parsed !== void 0 && typeof parsed.sev === "string" && typeof parsed.t === "string" && typeof parsed.id === "string") {
23875
+ const parsed2 = parseJsonObject(Buffer.from(cursor, "base64url").toString("utf8"));
23876
+ if (parsed2 !== void 0 && typeof parsed2.sev === "string" && typeof parsed2.t === "string" && typeof parsed2.id === "string") {
23634
23877
  return {
23635
- severity: parsed.sev,
23636
- latestDetectedAt: parsed.t,
23637
- id: parsed.id
23878
+ severity: parsed2.sev,
23879
+ latestDetectedAt: parsed2.t,
23880
+ id: parsed2.id
23638
23881
  };
23639
23882
  }
23640
23883
  return null;
@@ -24768,16 +25011,16 @@ var SqliteInstalledPacksRepository = class {
24768
25011
  continue;
24769
25012
  }
24770
25013
  for (const entry of raw) {
24771
- const parsed = Rule.safeParse(entry);
24772
- if (parsed.success) {
24773
- out.rules.push(parsed.data);
24774
- out.ruleActions.set(parsed.data.id, action);
24775
- out.ruleVersions.set(parsed.data.id, row.version);
24776
- if (reversible) out.reversibleRules.add(parsed.data.id);
24777
- else out.reversibleRules.delete(parsed.data.id);
25014
+ const parsed2 = Rule.safeParse(entry);
25015
+ if (parsed2.success) {
25016
+ out.rules.push(parsed2.data);
25017
+ out.ruleActions.set(parsed2.data.id, action);
25018
+ out.ruleVersions.set(parsed2.data.id, row.version);
25019
+ if (reversible) out.reversibleRules.add(parsed2.data.id);
25020
+ else out.reversibleRules.delete(parsed2.data.id);
24778
25021
  } else {
24779
25022
  out.invalidRules += 1;
24780
- reject(pack, printableRuleId(entry), firstIssueReason(parsed.error));
25023
+ reject(pack, printableRuleId(entry), firstIssueReason(parsed2.error));
24781
25024
  }
24782
25025
  }
24783
25026
  }
@@ -26167,15 +26410,15 @@ function encodeReuseCursor(payload) {
26167
26410
  return Buffer.from(JSON.stringify(payload)).toString("base64url");
26168
26411
  }
26169
26412
  function decodeReuseCursor(cursor) {
26170
- const parsed = parseJsonObject(Buffer.from(cursor, "base64url").toString("utf8"));
26171
- if (parsed !== void 0 && // `Number.isInteger`, not `typeof === 'number'`: a payload carrying
26413
+ const parsed2 = parseJsonObject(Buffer.from(cursor, "base64url").toString("utf8"));
26414
+ if (parsed2 !== void 0 && // `Number.isInteger`, not `typeof === 'number'`: a payload carrying
26172
26415
  // ±Infinity or a fraction binds cleanly and returns an EMPTY page with a
26173
26416
  // null cursor, which the caller reads as "end of list" — the one outcome a
26174
26417
  // malformed cursor must never produce, since restarting from the top is the
26175
26418
  // documented behaviour and the only recoverable one. (`1e999` is valid JSON
26176
26419
  // and parses to Infinity; a bare `NaN` is not, so it cannot arrive here.)
26177
- Number.isInteger(parsed.occurrences) && typeof parsed.pointerId === "string") {
26178
- return { occurrences: parsed.occurrences, pointerId: parsed.pointerId };
26420
+ Number.isInteger(parsed2.occurrences) && typeof parsed2.pointerId === "string") {
26421
+ return { occurrences: parsed2.occurrences, pointerId: parsed2.pointerId };
26179
26422
  }
26180
26423
  return null;
26181
26424
  }
@@ -27904,7 +28147,7 @@ function openAndInitialize(file2) {
27904
28147
  }
27905
28148
  function openLocalDatabase(dir) {
27906
28149
  ensureDataDirSync(dir);
27907
- const file2 = join4(dir, DB_FILENAME);
28150
+ const file2 = join5(dir, DB_FILENAME);
27908
28151
  reapStalePartials(file2);
27909
28152
  const {
27910
28153
  db,
@@ -28140,9 +28383,9 @@ import {
28140
28383
  closeSync,
28141
28384
  existsSync as existsSync4,
28142
28385
  openSync,
28143
- readFileSync as readFileSync3,
28144
- rmSync as rmSync3,
28145
- statSync as statSync2,
28386
+ readFileSync as readFileSync4,
28387
+ rmSync as rmSync4,
28388
+ statSync as statSync3,
28146
28389
  writeFileSync as writeFileSync2
28147
28390
  } from "fs";
28148
28391
  import { hostname as hostname3 } from "os";
@@ -28176,13 +28419,13 @@ function lockPathFor(file2) {
28176
28419
  function readLockBody(lock) {
28177
28420
  let raw;
28178
28421
  try {
28179
- raw = readFileSync3(lock, "utf8");
28422
+ raw = readFileSync4(lock, "utf8");
28180
28423
  } catch {
28181
28424
  return null;
28182
28425
  }
28183
28426
  try {
28184
- const parsed = JSON.parse(raw);
28185
- const { pid, token, at, host } = parsed;
28427
+ const parsed2 = JSON.parse(raw);
28428
+ const { pid, token, at, host } = parsed2;
28186
28429
  if (typeof pid !== "number" || typeof token !== "string" || typeof at !== "number") return null;
28187
28430
  return { pid, token, at, host: typeof host === "string" ? host : "" };
28188
28431
  } catch {
@@ -28207,7 +28450,7 @@ function directoryAcceptsCreates(lock) {
28207
28450
  return false;
28208
28451
  } finally {
28209
28452
  try {
28210
- rmSync3(probe, { force: true });
28453
+ rmSync4(probe, { force: true });
28211
28454
  } catch {
28212
28455
  }
28213
28456
  }
@@ -28240,7 +28483,7 @@ function tryAcquire(lock, file2) {
28240
28483
  closeSync(fd);
28241
28484
  } catch {
28242
28485
  }
28243
- rmSync3(lock, { force: true });
28486
+ rmSync4(lock, { force: true });
28244
28487
  return null;
28245
28488
  }
28246
28489
  try {
@@ -28252,7 +28495,7 @@ function tryAcquire(lock, file2) {
28252
28495
  function isAbandoned(body, lock, staleMs) {
28253
28496
  if (!body) {
28254
28497
  try {
28255
- return Date.now() - statSync2(lock).mtimeMs >= staleMs;
28498
+ return Date.now() - statSync3(lock).mtimeMs >= staleMs;
28256
28499
  } catch {
28257
28500
  return false;
28258
28501
  }
@@ -28276,13 +28519,13 @@ function breakIfStale(lock, staleMs) {
28276
28519
  }
28277
28520
  try {
28278
28521
  if (!existsSync4(lock) || !isAbandoned(readLockBody(lock), lock, staleMs)) return false;
28279
- rmSync3(lock, { force: true });
28522
+ rmSync4(lock, { force: true });
28280
28523
  return true;
28281
28524
  } catch {
28282
28525
  return false;
28283
28526
  } finally {
28284
28527
  try {
28285
- rmSync3(breaker, { force: true });
28528
+ rmSync4(breaker, { force: true });
28286
28529
  } catch {
28287
28530
  }
28288
28531
  }
@@ -28290,8 +28533,8 @@ function breakIfStale(lock, staleMs) {
28290
28533
  var BREAKER_ABANDONED_MS = 1e4;
28291
28534
  function reapAbandonedBreaker(breaker) {
28292
28535
  try {
28293
- if (Date.now() - statSync2(breaker).mtimeMs >= BREAKER_ABANDONED_MS) {
28294
- rmSync3(breaker, { force: true });
28536
+ if (Date.now() - statSync3(breaker).mtimeMs >= BREAKER_ABANDONED_MS) {
28537
+ rmSync4(breaker, { force: true });
28295
28538
  }
28296
28539
  } catch {
28297
28540
  }
@@ -28302,7 +28545,7 @@ function abandonWindow(staleMs) {
28302
28545
  function release(lock, token) {
28303
28546
  try {
28304
28547
  if (readLockBody(lock)?.token !== token) return;
28305
- rmSync3(lock, { force: true });
28548
+ rmSync4(lock, { force: true });
28306
28549
  } catch {
28307
28550
  }
28308
28551
  }
@@ -28360,20 +28603,20 @@ function computeFindingKey(input) {
28360
28603
 
28361
28604
  // ../packages/persistence/src/fingerprint.ts
28362
28605
  import { createHmac, randomBytes } from "crypto";
28363
- import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
28364
- import { join as join5 } from "path";
28606
+ import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
28607
+ import { join as join6 } from "path";
28365
28608
  import { DatabaseSync as DatabaseSync2 } from "node:sqlite";
28366
28609
  var EXCEPTION_KEY_FILENAME = "exception.key";
28367
28610
  var KEY_MATERIAL_BYTES = 32;
28368
28611
  function keyFilePath(dataDir2) {
28369
- return join5(dataDir2, EXCEPTION_KEY_FILENAME);
28612
+ return join6(dataDir2, EXCEPTION_KEY_FILENAME);
28370
28613
  }
28371
28614
  function parseKeyFile(raw) {
28372
- const parsed = JSON.parse(raw);
28373
- if (typeof parsed !== "object" || parsed === null) {
28615
+ const parsed2 = JSON.parse(raw);
28616
+ if (typeof parsed2 !== "object" || parsed2 === null) {
28374
28617
  throw new Error("exception key file is corrupt: not a JSON object");
28375
28618
  }
28376
- const { version: version2, material } = parsed;
28619
+ const { version: version2, material } = parsed2;
28377
28620
  if (typeof version2 !== "number" || !Number.isInteger(version2) || version2 < 1) {
28378
28621
  throw new Error("exception key file is corrupt: bad version");
28379
28622
  }
@@ -28404,7 +28647,7 @@ var FloorUnreadableError = class extends Error {
28404
28647
  }
28405
28648
  };
28406
28649
  function storedKeyVersionFloor(dataDir2) {
28407
- const file2 = join5(dataDir2, DB_FILENAME);
28650
+ const file2 = join6(dataDir2, DB_FILENAME);
28408
28651
  if (!existsSync5(file2)) return 0;
28409
28652
  let db;
28410
28653
  try {
@@ -28465,7 +28708,7 @@ function occupantMessage(file2, kind) {
28465
28708
  function readFingerprintKey(dataDir2) {
28466
28709
  let raw;
28467
28710
  try {
28468
- raw = readFileSync4(keyFilePath(dataDir2), "utf8");
28711
+ raw = readFileSync5(keyFilePath(dataDir2), "utf8");
28469
28712
  } catch (err) {
28470
28713
  if (err.code === "ENOENT") return null;
28471
28714
  throw err instanceof Error ? err : new Error(String(err));
@@ -28504,28 +28747,32 @@ function keyStateOf(key) {
28504
28747
  import { renameSync as renameSync3 } from "fs";
28505
28748
  import { mkdir } from "fs/promises";
28506
28749
  import { homedir as homedir3 } from "os";
28507
- import { join as join6 } from "path";
28750
+ import { join as join7 } from "path";
28508
28751
  function defaultDataDir() {
28509
- return join6(homedir3(), ".aka");
28752
+ return join7(homedir3(), ".aka");
28510
28753
  }
28511
28754
  function settingsDir(base = defaultDataDir()) {
28512
- return join6(base, "settings");
28755
+ return join7(base, "settings");
28513
28756
  }
28514
28757
  function dataDir(base = defaultDataDir()) {
28515
- return join6(base, "data");
28758
+ return join7(base, "data");
28516
28759
  }
28517
28760
  function dbPath(base = defaultDataDir()) {
28518
- return join6(dataDir(base), "aka.db");
28761
+ return join7(dataDir(base), "aka.db");
28519
28762
  }
28520
28763
  function keysDir(base = defaultDataDir()) {
28521
- return join6(base, "keys");
28764
+ return join7(base, "keys");
28765
+ }
28766
+ async function ensureDataDir(dir = defaultDataDir()) {
28767
+ await mkdir(dir, { recursive: true, mode: DATA_DIR_MODE });
28768
+ tightenDir(dir);
28522
28769
  }
28523
28770
  function ensureLayoutDirSync(dir = defaultDataDir()) {
28524
28771
  ensureDataDirSync(dir);
28525
28772
  }
28526
28773
 
28527
28774
  // ../packages/persistence/src/managed-settings.ts
28528
- import { readFileSync as readFileSync5 } from "fs";
28775
+ import { readFileSync as readFileSync6 } from "fs";
28529
28776
  import { posix, win32 } from "path";
28530
28777
  function managedSettingsPaths(platform2 = process.platform) {
28531
28778
  if (platform2 === "darwin") {
@@ -28543,17 +28790,25 @@ function readManagedSettings(paths = managedSettingsPaths()) {
28543
28790
  for (const path of paths) {
28544
28791
  let text;
28545
28792
  try {
28546
- text = readFileSync5(path, "utf8");
28793
+ text = readFileSync6(path, "utf8");
28547
28794
  } catch {
28548
28795
  continue;
28549
28796
  }
28550
28797
  const record2 = parseJsonObject(text);
28551
28798
  if (!record2) continue;
28552
- const parsed = ManagedSettings.safeParse(record2);
28553
- if (parsed.success) return parsed.data;
28799
+ const parsed2 = ManagedSettings.safeParse(record2);
28800
+ if (parsed2.success) return parsed2.data;
28554
28801
  }
28555
28802
  return null;
28556
28803
  }
28804
+ function managedContextOf(managed) {
28805
+ if (!managed) return NO_MANAGED_CONTEXT;
28806
+ return {
28807
+ present: true,
28808
+ ...managed.organization === void 0 ? {} : { organization: managed.organization },
28809
+ lockedFields: managed.lockedFields
28810
+ };
28811
+ }
28557
28812
  function overlayManagedSettings(settings, managed, now = () => /* @__PURE__ */ new Date()) {
28558
28813
  if (!managed) return settings;
28559
28814
  const { values } = managed;
@@ -28588,16 +28843,20 @@ function overlayManagedSettings(settings, managed, now = () => /* @__PURE__ */ n
28588
28843
  }
28589
28844
  return merged;
28590
28845
  }
28846
+ function lockedAmong(context, requested) {
28847
+ if (!context.present) return [];
28848
+ return requested.filter((key) => context.lockedFields.includes(key));
28849
+ }
28591
28850
 
28592
28851
  // ../packages/persistence/src/settings.ts
28593
- import { readFileSync as readFileSync6 } from "fs";
28594
- import { join as join7 } from "path";
28852
+ import { readFileSync as readFileSync7 } from "fs";
28853
+ import { join as join8 } from "path";
28595
28854
  var SETTINGS_FILENAME = "settings.json";
28596
28855
  function readWorkspaceSettings(base = defaultDataDir()) {
28597
28856
  return overlayManagedSettings(readUserSettings(base), readManagedSettings());
28598
28857
  }
28599
28858
  function readUserSettings(base) {
28600
- const record2 = readJson(join7(settingsDir(base), SETTINGS_FILENAME));
28859
+ const record2 = readJson(join8(settingsDir(base), SETTINGS_FILENAME));
28601
28860
  if (!record2) return defaultWorkspaceSettings();
28602
28861
  try {
28603
28862
  return WorkspaceSettings.parse(record2);
@@ -28605,16 +28864,153 @@ function readUserSettings(base) {
28605
28864
  return defaultWorkspaceSettings();
28606
28865
  }
28607
28866
  }
28867
+ var ManagedFieldError = class extends Error {
28868
+ fields;
28869
+ constructor(fields) {
28870
+ super(`refusing to write administratively locked settings: ${fields.join(", ")}`);
28871
+ this.name = "ManagedFieldError";
28872
+ this.fields = fields;
28873
+ }
28874
+ };
28875
+ function lockableKeysTouched(current, applied) {
28876
+ const keys = [];
28877
+ const changed = (key) => key in applied && applied[key] !== current[key];
28878
+ const descriptorChanged = "controlPlane" in applied && (applied.controlPlane?.endpoint !== current.controlPlane?.endpoint || applied.controlPlane?.label !== current.controlPlane?.label);
28879
+ if (changed("runMode") || descriptorChanged) keys.push("runMode");
28880
+ if (changed("historicalAccess")) keys.push("historicalAccess");
28881
+ if (changed("vaultKeyCustody")) keys.push("vaultKeyCustody");
28882
+ if (changed("vaultInlineReveal")) keys.push("vaultInlineReveal");
28883
+ if (changed("dataSharesInPlace")) keys.push("dataSharesInPlace");
28884
+ if ("vaultConsent" in applied && isVaultConsentValid(applied.vaultConsent) !== isVaultConsentValid(current.vaultConsent)) {
28885
+ keys.push("vaultConsent");
28886
+ }
28887
+ if ("modelJudgeConsent" in applied && isModelJudgeConsentValid(applied.modelJudgeConsent) !== isModelJudgeConsentValid(current.modelJudgeConsent)) {
28888
+ keys.push("modelJudgeConsent");
28889
+ }
28890
+ return keys;
28891
+ }
28892
+ function pinnedKeys(managed) {
28893
+ if (!managed) return [];
28894
+ const { values } = managed;
28895
+ const keys = [];
28896
+ if (values.runMode !== void 0 || values.controlPlane !== void 0) keys.push("runMode");
28897
+ if (values.historicalAccess !== void 0) keys.push("historicalAccess");
28898
+ if (values.vaultConsent !== void 0) keys.push("vaultConsent");
28899
+ if (values.vaultKeyCustody !== void 0) keys.push("vaultKeyCustody");
28900
+ if (values.vaultInlineReveal !== void 0) keys.push("vaultInlineReveal");
28901
+ if (values.modelJudgeConsent !== void 0) keys.push("modelJudgeConsent");
28902
+ if (values.dataSharesInPlace !== void 0) keys.push("dataSharesInPlace");
28903
+ return keys;
28904
+ }
28905
+ function withoutManagedKeys(applied, managed, pinned, touched) {
28906
+ if (!managed.present) return applied;
28907
+ const strip = (key) => (managed.lockedFields.includes(key) || pinned.includes(key)) && !touched.includes(key);
28908
+ const out = { ...applied };
28909
+ if (strip("runMode")) {
28910
+ delete out.runMode;
28911
+ delete out.controlPlane;
28912
+ }
28913
+ if (strip("historicalAccess")) delete out.historicalAccess;
28914
+ if (strip("vaultConsent")) delete out.vaultConsent;
28915
+ if (strip("vaultKeyCustody")) delete out.vaultKeyCustody;
28916
+ if (strip("vaultInlineReveal")) delete out.vaultInlineReveal;
28917
+ if (strip("modelJudgeConsent")) delete out.modelJudgeConsent;
28918
+ if (strip("dataSharesInPlace")) delete out.dataSharesInPlace;
28919
+ return out;
28920
+ }
28921
+ function applyOnboarding(answers, base = defaultDataDir(), managedOverride) {
28922
+ const dir = settingsDir(base);
28923
+ ensureDataDirSync(dir);
28924
+ const file2 = join8(dir, SETTINGS_FILENAME);
28925
+ const managedSettings = managedOverride === void 0 ? readManagedSettings() : managedOverride;
28926
+ const managed = managedContextOf(managedSettings);
28927
+ return withFileLock(file2, () => {
28928
+ const current = readUserSettings(base);
28929
+ const applied = typeof answers === "function" ? answers(current) : answers;
28930
+ const effective = overlayManagedSettings(current, managedSettings);
28931
+ const touched = lockableKeysTouched(effective, applied);
28932
+ const refused = lockedAmong(managed, touched);
28933
+ if (refused.length > 0) throw new ManagedFieldError(refused);
28934
+ const merged = WorkspaceSettings.parse({
28935
+ ...current,
28936
+ // Locked keys are stripped rather than merged. Everything still here is,
28937
+ // by the refusal above, an unchanged ECHO of the administrator's value —
28938
+ // so dropping it discards no answer of the user's, and writing it would
28939
+ // persist the pin into their file, where it would outlive the managed
28940
+ // file and read as their own choice once the lock was gone.
28941
+ ...withoutManagedKeys(applied, managed, pinnedKeys(managedSettings), touched),
28942
+ // First setup stamps the time; later edits keep the original completion mark.
28943
+ onboardedAt: applied.onboardedAt ?? current.onboardedAt ?? (/* @__PURE__ */ new Date()).toISOString()
28944
+ });
28945
+ writeOwnerOnlyFileSync(file2, `${JSON.stringify(merged, null, 2)}
28946
+ `);
28947
+ return merged;
28948
+ });
28949
+ }
28608
28950
  function readJson(file2) {
28609
28951
  let text;
28610
28952
  try {
28611
- text = readFileSync6(file2, "utf8");
28953
+ text = readFileSync7(file2, "utf8");
28612
28954
  } catch {
28613
28955
  return null;
28614
28956
  }
28615
28957
  return parseJsonObject(text) ?? null;
28616
28958
  }
28617
28959
 
28960
+ // ../packages/persistence/src/store-symlinks.ts
28961
+ import { existsSync as existsSync6, lstatSync as lstatSync3, readlinkSync, realpathSync as realpathSync2, statSync as statSync4 } from "fs";
28962
+ import { dirname as dirname4, join as join9, resolve } from "path";
28963
+ var STORE_DB = "the store database (including the prompt corpus)";
28964
+ var STORE_SETTINGS = "your settings file";
28965
+ function storeContents(home) {
28966
+ return /* @__PURE__ */ new Map([
28967
+ [home, "the store (including the prompt corpus in aka.db)"],
28968
+ [settingsDir(home), STORE_SETTINGS],
28969
+ [dataDir(home), STORE_DB],
28970
+ [keysDir(home), "the vault key"],
28971
+ [join9(settingsDir(home), "settings.json"), STORE_SETTINGS],
28972
+ [dbPath(home), STORE_DB]
28973
+ ]);
28974
+ }
28975
+ function storeTargets(home) {
28976
+ return [...storeContents(home).keys()];
28977
+ }
28978
+ function symlinkedStorePaths(home, platform2 = process.platform) {
28979
+ return [...storeContents(home)].flatMap(([path, holds]) => {
28980
+ try {
28981
+ if (!lstatSync3(path).isSymbolicLink()) return [];
28982
+ return [
28983
+ {
28984
+ path,
28985
+ target: linkTarget(path),
28986
+ holds,
28987
+ // existsSync follows the link, so a target that is gone reads as
28988
+ // absent here while lstat above still sees the link itself.
28989
+ missing: !existsSync6(path),
28990
+ mode: targetMode(path, platform2)
28991
+ }
28992
+ ];
28993
+ } catch {
28994
+ return [];
28995
+ }
28996
+ });
28997
+ }
28998
+ function linkTarget(path) {
28999
+ try {
29000
+ return realpathSync2(path);
29001
+ } catch {
29002
+ return resolve(dirname4(path), readlinkSync(path));
29003
+ }
29004
+ }
29005
+ function targetMode(path, platform2) {
29006
+ if (platform2 === "win32") return void 0;
29007
+ try {
29008
+ return statSync4(path).mode & 511;
29009
+ } catch {
29010
+ return void 0;
29011
+ }
29012
+ }
29013
+
28618
29014
  // ../packages/persistence/src/vault/crypto.ts
28619
29015
  import {
28620
29016
  createCipheriv,
@@ -28726,8 +29122,8 @@ function formatPointer(category, keyVersion, pointerId, tag) {
28726
29122
  // ../packages/persistence/src/vault/key-provider.ts
28727
29123
  import { execFileSync as execFileSync2 } from "child_process";
28728
29124
  import { randomBytes as randomBytes2 } from "crypto";
28729
- import { chmodSync as chmodSync2, readFileSync as readFileSync7, renameSync as renameSync4, rmSync as rmSync4, statSync as statSync3, writeFileSync as writeFileSync3 } from "fs";
28730
- import { join as join8 } from "path";
29125
+ import { chmodSync as chmodSync3, readFileSync as readFileSync8, renameSync as renameSync4, rmSync as rmSync5, statSync as statSync5, writeFileSync as writeFileSync3 } from "fs";
29126
+ import { join as join10 } from "path";
28731
29127
  var VAULT_OCCUPANT_REASON = {
28732
29128
  symlink: "the path is a symlink; remove it so a keyring can be created",
28733
29129
  gone: "the path was occupied but holds no keyring (removed while it was being created)",
@@ -28746,11 +29142,11 @@ var KEY_MATERIAL_BYTES2 = 32;
28746
29142
  var KEYCHAIN_SERVICE = "aka-vault";
28747
29143
  var KEYCHAIN_ACCOUNT = "keyring";
28748
29144
  function parseKeyring(raw) {
28749
- const parsed = JSON.parse(raw);
28750
- if (typeof parsed !== "object" || parsed === null) {
29145
+ const parsed2 = JSON.parse(raw);
29146
+ if (typeof parsed2 !== "object" || parsed2 === null) {
28751
29147
  throw new Error("vault key file is corrupt: not a JSON object");
28752
29148
  }
28753
- const { current, keys } = parsed;
29149
+ const { current, keys } = parsed2;
28754
29150
  if (typeof current !== "number" || !Number.isInteger(current) || current < 1) {
28755
29151
  throw new Error("vault key file is corrupt: bad current version");
28756
29152
  }
@@ -28826,28 +29222,28 @@ function claimRotationLock(lock, owner) {
28826
29222
  throw asError(err);
28827
29223
  }
28828
29224
  try {
28829
- writeFileSync3(join8(lock, LOCK_OWNER_FILE), `${owner}
29225
+ writeFileSync3(join10(lock, LOCK_OWNER_FILE), `${owner}
28830
29226
  `, { mode: DATA_FILE_MODE });
28831
29227
  return true;
28832
29228
  } catch (err) {
28833
- rmSync4(lock, { recursive: true, force: true });
29229
+ rmSync5(lock, { recursive: true, force: true });
28834
29230
  throw asError(err);
28835
29231
  }
28836
29232
  }
28837
29233
  function acquireRotationLock(keysDir2) {
28838
- const lock = join8(keysDir2, `${VAULT_KEY_FILENAME}.lock`);
29234
+ const lock = join10(keysDir2, `${VAULT_KEY_FILENAME}.lock`);
28839
29235
  const owner = randomBytes2(16).toString("hex");
28840
29236
  if (claimRotationLock(lock, owner)) return { lock, owner };
28841
29237
  let held;
28842
29238
  try {
28843
- held = statSync3(lock);
29239
+ held = statSync5(lock);
28844
29240
  } catch {
28845
29241
  throw new Error(ROTATION_IN_PROGRESS);
28846
29242
  }
28847
29243
  if (Date.now() - held.mtimeMs < ROTATION_LOCK_STALE_MS) throw new Error(ROTATION_IN_PROGRESS);
28848
29244
  const aside = `${lock}.stale.${owner}`;
28849
29245
  try {
28850
- const now = statSync3(lock);
29246
+ const now = statSync5(lock);
28851
29247
  if (now.ino !== held.ino || now.mtimeMs !== held.mtimeMs) {
28852
29248
  throw new Error(ROTATION_IN_PROGRESS);
28853
29249
  }
@@ -28856,17 +29252,17 @@ function acquireRotationLock(keysDir2) {
28856
29252
  if (err instanceof Error && err.message === ROTATION_IN_PROGRESS) throw err;
28857
29253
  throw new Error(ROTATION_IN_PROGRESS, { cause: err });
28858
29254
  }
28859
- rmSync4(aside, { recursive: true, force: true });
29255
+ rmSync5(aside, { recursive: true, force: true });
28860
29256
  if (!claimRotationLock(lock, owner)) throw new Error(ROTATION_IN_PROGRESS);
28861
29257
  return { lock, owner };
28862
29258
  }
28863
29259
  function releaseRotationLock(lease) {
28864
29260
  try {
28865
- if (readFileSync7(join8(lease.lock, LOCK_OWNER_FILE), "utf8").trim() !== lease.owner) return;
29261
+ if (readFileSync8(join10(lease.lock, LOCK_OWNER_FILE), "utf8").trim() !== lease.owner) return;
28866
29262
  } catch {
28867
29263
  return;
28868
29264
  }
28869
- rmSync4(lease.lock, { recursive: true, force: true });
29265
+ rmSync5(lease.lock, { recursive: true, force: true });
28870
29266
  }
28871
29267
  function withRotationLock(keysDir2, work) {
28872
29268
  ensureDataDirSync(keysDir2);
@@ -28883,7 +29279,7 @@ var FileKeyProvider = class {
28883
29279
  this.#keysDir = keysDir2;
28884
29280
  }
28885
29281
  get filePath() {
28886
- return join8(this.#keysDir, VAULT_KEY_FILENAME);
29282
+ return join10(this.#keysDir, VAULT_KEY_FILENAME);
28887
29283
  }
28888
29284
  loadOrCreate() {
28889
29285
  return asAsync(() => {
@@ -28913,7 +29309,7 @@ var FileKeyProvider = class {
28913
29309
  #read() {
28914
29310
  let raw;
28915
29311
  try {
28916
- raw = readFileSync7(this.filePath, "utf8");
29312
+ raw = readFileSync8(this.filePath, "utf8");
28917
29313
  } catch (err) {
28918
29314
  if (err.code === "ENOENT") return null;
28919
29315
  throw err instanceof Error ? err : new Error(String(err));
@@ -28970,7 +29366,7 @@ var FileKeyProvider = class {
28970
29366
  };
28971
29367
  function tightenFileMode(file2) {
28972
29368
  try {
28973
- chmodSync2(file2, DATA_FILE_MODE);
29369
+ chmodSync3(file2, DATA_FILE_MODE);
28974
29370
  } catch {
28975
29371
  }
28976
29372
  }
@@ -29235,25 +29631,25 @@ var SecretVault = class {
29235
29631
  * model. Every call that gets as far as an identified row writes an audit row.
29236
29632
  */
29237
29633
  async detokenize(token, opts) {
29238
- const parsed = parsePointer(token);
29239
- if (!parsed) return UNAVAILABLE;
29634
+ const parsed2 = parsePointer(token);
29635
+ if (!parsed2) return UNAVAILABLE;
29240
29636
  let signKey;
29241
29637
  try {
29242
- const epoch = await this.#keys.materialFor(parsed.keyVersion);
29638
+ const epoch = await this.#keys.materialFor(parsed2.keyVersion);
29243
29639
  signKey = deriveSubkeys(epoch.material).sign;
29244
29640
  } catch {
29245
29641
  return UNAVAILABLE;
29246
29642
  }
29247
- if (!verifyPointerTag(signKey, parsed.keyVersion, parsed.pointerId, parsed.category, parsed.tag)) {
29643
+ if (!verifyPointerTag(signKey, parsed2.keyVersion, parsed2.pointerId, parsed2.category, parsed2.tag)) {
29248
29644
  return UNAVAILABLE;
29249
29645
  }
29250
- const pointerId = base32Encode(parsed.pointerId);
29646
+ const pointerId = base32Encode(parsed2.pointerId);
29251
29647
  const row = this.#repo.byPointerId(pointerId);
29252
29648
  if (!row) {
29253
29649
  this.#audit(pointerId, opts, "unavailable");
29254
29650
  return UNAVAILABLE;
29255
29651
  }
29256
- if (row.category !== parsed.category) return UNAVAILABLE;
29652
+ if (row.category !== parsed2.category) return UNAVAILABLE;
29257
29653
  if (opts.target === "model") {
29258
29654
  const grantId = opts.grantId;
29259
29655
  const verify = this.#verifyGrant;
@@ -29290,7 +29686,7 @@ var SecretVault = class {
29290
29686
  // moved the epoch past the one this token names, and a format bump may
29291
29687
  // have moved the constant past the generation this row was sealed
29292
29688
  // under — the AAD follows the row in both cases, never the token.
29293
- bindingInput(row.keyVersion, parsed.pointerId, row.category, row.formatVersion)
29689
+ bindingInput(row.keyVersion, parsed2.pointerId, row.category, row.formatVersion)
29294
29690
  );
29295
29691
  } catch {
29296
29692
  raw = null;
@@ -29508,19 +29904,19 @@ var SecretVault = class {
29508
29904
  // preview. Verifying needs the historical epoch's key, which is why these
29509
29905
  // surfaces are async.
29510
29906
  async #rowFor(token) {
29511
- const parsed = parsePointer(token);
29512
- if (!parsed) return null;
29907
+ const parsed2 = parsePointer(token);
29908
+ if (!parsed2) return null;
29513
29909
  try {
29514
- const epoch = await this.#keys.materialFor(parsed.keyVersion);
29910
+ const epoch = await this.#keys.materialFor(parsed2.keyVersion);
29515
29911
  const signKey = deriveSubkeys(epoch.material).sign;
29516
- if (!verifyPointerTag(signKey, parsed.keyVersion, parsed.pointerId, parsed.category, parsed.tag)) {
29912
+ if (!verifyPointerTag(signKey, parsed2.keyVersion, parsed2.pointerId, parsed2.category, parsed2.tag)) {
29517
29913
  return null;
29518
29914
  }
29519
29915
  } catch {
29520
29916
  return null;
29521
29917
  }
29522
- const row = this.#repo.byPointerId(base32Encode(parsed.pointerId));
29523
- if (row?.category !== parsed.category) return null;
29918
+ const row = this.#repo.byPointerId(base32Encode(parsed2.pointerId));
29919
+ if (row?.category !== parsed2.category) return null;
29524
29920
  return row;
29525
29921
  }
29526
29922
  #audit(pointerId, opts, outcome) {
@@ -29540,12 +29936,12 @@ var SecretVault = class {
29540
29936
  };
29541
29937
 
29542
29938
  // ../packages/persistence/src/warn-era-cap.ts
29543
- import { existsSync as existsSync6, writeFileSync as writeFileSync4 } from "fs";
29544
- import { join as join9 } from "path";
29939
+ import { existsSync as existsSync7, writeFileSync as writeFileSync4 } from "fs";
29940
+ import { join as join11 } from "path";
29545
29941
 
29546
29942
  // ../packages/plugin-sdk/src/config.ts
29547
- import { existsSync as existsSync7 } from "fs";
29548
- import { join as join10 } from "path";
29943
+ import { existsSync as existsSync8 } from "fs";
29944
+ import { join as join12 } from "path";
29549
29945
 
29550
29946
  // ../packages/plugin-sdk/src/provider-env.ts
29551
29947
  var booleanish = external_exports.string().optional().transform((v) => {
@@ -29566,9 +29962,9 @@ var providerEnvShape = {
29566
29962
  var ProviderEnvSchema = external_exports.object(providerEnvShape);
29567
29963
 
29568
29964
  // ../packages/plugin-sdk/src/config-inventory.ts
29569
- import { readdirSync as readdirSync3, readFileSync as readFileSync9, realpathSync as realpathSync2, statSync as statSync5 } from "fs";
29965
+ import { readdirSync as readdirSync3, readFileSync as readFileSync10, realpathSync as realpathSync3, statSync as statSync7 } from "fs";
29570
29966
  import { homedir as homedir4 } from "os";
29571
- import { basename as basename3, join as join12 } from "path";
29967
+ import { basename as basename3, join as join14 } from "path";
29572
29968
 
29573
29969
  // ../rules/code-flaws/auth-jwt-no-verify.json
29574
29970
  var auth_jwt_no_verify_default = {
@@ -30291,10 +30687,10 @@ var localhost_ref_default = {
30291
30687
  severity: "low",
30292
30688
  matcher: {
30293
30689
  type: "regex",
30294
- pattern: "\\b(?:localhost|127\\.0\\.0\\.1|0\\.0\\.0\\.0|::1)\\b",
30690
+ pattern: "(?<![A-Za-z0-9_])(?:localhost|127\\.0\\.0\\.1|0\\.0\\.0\\.0|(?<![A-Za-z0-9_]\\[)::1(?!:|\\.[0-9]))(?![A-Za-z0-9_])",
30295
30691
  flags: "g"
30296
30692
  },
30297
- examples: ["localhost", "127.0.0.1"]
30693
+ examples: ["localhost", "127.0.0.1", "0.0.0.0", "::1"]
30298
30694
  };
30299
30695
 
30300
30696
  // ../rules/core-code-context/stack-trace.json
@@ -31603,8 +31999,8 @@ function bundledDetections() {
31603
31999
  }
31604
32000
 
31605
32001
  // ../packages/plugin-sdk/src/repo.ts
31606
- import { existsSync as existsSync8, readFileSync as readFileSync8, statSync as statSync4 } from "fs";
31607
- import { basename as basename2, dirname as dirname4, isAbsolute, join as join11, sep as sep3 } from "path";
32002
+ import { existsSync as existsSync9, readFileSync as readFileSync9, statSync as statSync6 } from "fs";
32003
+ import { basename as basename2, dirname as dirname5, isAbsolute, join as join13, sep as sep3 } from "path";
31608
32004
  function resolveRepoIdentity(cwd) {
31609
32005
  try {
31610
32006
  const root = findGitRoot(cwd);
@@ -31642,36 +32038,36 @@ function resolveHeadRoot(cwd) {
31642
32038
  function findGitRoot(start) {
31643
32039
  let dir = start;
31644
32040
  for (; ; ) {
31645
- if (existsSync8(join11(dir, ".git"))) return dir;
31646
- const parent = dirname4(dir);
32041
+ if (existsSync9(join13(dir, ".git"))) return dir;
32042
+ const parent = dirname5(dir);
31647
32043
  if (parent === dir) return void 0;
31648
32044
  dir = parent;
31649
32045
  }
31650
32046
  }
31651
32047
  function resolveGitContext(root) {
31652
- const dotGit = join11(root, ".git");
32048
+ const dotGit = join13(root, ".git");
31653
32049
  try {
31654
- if (statSync4(dotGit).isDirectory()) {
31655
- return { configPath: join11(dotGit, "config"), headRoot: root };
32050
+ if (statSync6(dotGit).isDirectory()) {
32051
+ return { configPath: join13(dotGit, "config"), headRoot: root };
31656
32052
  }
31657
32053
  } catch {
31658
32054
  return void 0;
31659
32055
  }
31660
32056
  const target = /^gitdir:\s*(.+?)\s*$/m.exec(safeRead(dotGit) ?? "")?.[1];
31661
32057
  if (!target) return void 0;
31662
- const gitdir = isAbsolute(target) ? target : join11(root, target);
31663
- if (existsSync8(join11(gitdir, "config"))) {
31664
- return { configPath: join11(gitdir, "config"), headRoot: root };
32058
+ const gitdir = isAbsolute(target) ? target : join13(root, target);
32059
+ if (existsSync9(join13(gitdir, "config"))) {
32060
+ return { configPath: join13(gitdir, "config"), headRoot: root };
31665
32061
  }
31666
- const commonRaw = safeRead(join11(gitdir, "commondir"))?.trim();
32062
+ const commonRaw = safeRead(join13(gitdir, "commondir"))?.trim();
31667
32063
  if (!commonRaw) return void 0;
31668
- const commonGitDir = isAbsolute(commonRaw) ? commonRaw : join11(gitdir, commonRaw);
31669
- const headRoot = basename2(commonGitDir) === ".git" ? dirname4(commonGitDir) : root;
31670
- return { configPath: join11(commonGitDir, "config"), headRoot };
32064
+ const commonGitDir = isAbsolute(commonRaw) ? commonRaw : join13(gitdir, commonRaw);
32065
+ const headRoot = basename2(commonGitDir) === ".git" ? dirname5(commonGitDir) : root;
32066
+ return { configPath: join13(commonGitDir, "config"), headRoot };
31671
32067
  }
31672
32068
  function safeRead(path) {
31673
32069
  try {
31674
- return readFileSync8(path, "utf8");
32070
+ return readFileSync9(path, "utf8");
31675
32071
  } catch {
31676
32072
  return void 0;
31677
32073
  }
@@ -31712,17 +32108,17 @@ function slugFromUrl(url2) {
31712
32108
  import { createHash as createHash4, randomUUID as randomUUID13 } from "crypto";
31713
32109
 
31714
32110
  // ../packages/plugin-sdk/src/isolated-scan.ts
31715
- import { existsSync as existsSync9 } from "fs";
32111
+ import { existsSync as existsSync10 } from "fs";
31716
32112
  import { fileURLToPath as fileURLToPath2 } from "url";
31717
32113
  import { Worker } from "worker_threads";
31718
32114
 
31719
32115
  // ../packages/plugin-sdk/src/ignore-layers.ts
31720
32116
  var import_ignore = __toESM(require_ignore(), 1);
31721
- import { readFileSync as readFileSync10 } from "fs";
31722
- import { join as join13 } from "path";
32117
+ import { readFileSync as readFileSync11 } from "fs";
32118
+ import { join as join15 } from "path";
31723
32119
  function readIgnoreLayer(dir, filename, anchorLen) {
31724
32120
  try {
31725
- return { matcher: (0, import_ignore.default)().add(readFileSync10(join13(dir, filename), "utf8")), anchorLen };
32121
+ return { matcher: (0, import_ignore.default)().add(readFileSync11(join15(dir, filename), "utf8")), anchorLen };
31726
32122
  } catch {
31727
32123
  return void 0;
31728
32124
  }
@@ -31753,12 +32149,12 @@ function withLayer(layers, layer) {
31753
32149
  import { arch, hostname as hostname4, platform, release as release2 } from "os";
31754
32150
 
31755
32151
  // ../packages/plugin-sdk/src/nudge.ts
31756
- import { mkdirSync as mkdirSync2, readFileSync as readFileSync11, writeFileSync as writeFileSync5 } from "fs";
31757
- import { join as join14 } from "path";
32152
+ import { mkdirSync as mkdirSync2, readFileSync as readFileSync12, writeFileSync as writeFileSync5 } from "fs";
32153
+ import { join as join16 } from "path";
31758
32154
 
31759
32155
  // ../packages/plugin-sdk/src/paths.ts
31760
- import { readdirSync as readdirSync4, realpathSync as realpathSync3 } from "fs";
31761
- import { basename as basename4, dirname as dirname5, sep as sep4 } from "path";
32156
+ import { readdirSync as readdirSync4, realpathSync as realpathSync4 } from "fs";
32157
+ import { basename as basename4, dirname as dirname6, sep as sep4 } from "path";
31762
32158
  function toPosix(path) {
31763
32159
  return path.split(sep4).join("/");
31764
32160
  }
@@ -31768,7 +32164,7 @@ function findProjectRoot(startDir, recognizeMarker) {
31768
32164
  let root = null;
31769
32165
  for (let level = 0; level < MAX_PROJECT_ROOT_LEVELS; level += 1) {
31770
32166
  if (directoryHasMarker(dir, recognizeMarker)) root = dir;
31771
- const parent = dirname5(dir);
32167
+ const parent = dirname6(dir);
31772
32168
  if (parent === dir) break;
31773
32169
  dir = parent;
31774
32170
  }
@@ -31786,13 +32182,13 @@ function directoryHasMarker(dir, recognizeMarker) {
31786
32182
  }
31787
32183
  function resolveNonGitProject(startDir, recognizeMarker) {
31788
32184
  const projectRoot = findProjectRoot(startDir, recognizeMarker);
31789
- const realRoot = realpathSync3(projectRoot);
32185
+ const realRoot = realpathSync4(projectRoot);
31790
32186
  return { root: projectRoot, projectKey: `path:${realRoot}`, project: basename4(realRoot) };
31791
32187
  }
31792
32188
 
31793
32189
  // ../packages/plugin-sdk/src/project-files.ts
31794
- import { existsSync as existsSync10, readdirSync as readdirSync5 } from "fs";
31795
- import { basename as basename5, join as join15 } from "path";
32190
+ import { existsSync as existsSync11, readdirSync as readdirSync5 } from "fs";
32191
+ import { basename as basename5, join as join17 } from "path";
31796
32192
  var SKIP_DIRS = /* @__PURE__ */ new Set([
31797
32193
  ".git",
31798
32194
  "node_modules",
@@ -31889,8 +32285,8 @@ function resolveProjectFiles(cwd, opts = {}) {
31889
32285
  }
31890
32286
  if (entry.isDirectory()) {
31891
32287
  if (SKIP_DIRS.has(entry.name) || isIgnored(dirLayers, dirRel, entry.name, true)) continue;
31892
- const fullPath = join15(dir, entry.name);
31893
- if (existsSync10(join15(fullPath, ".git"))) continue;
32288
+ const fullPath = join17(dir, entry.name);
32289
+ if (existsSync11(join17(fullPath, ".git"))) continue;
31894
32290
  if (depth >= bounds.maxDepth) {
31895
32291
  walk.omitted = true;
31896
32292
  continue;
@@ -31962,15 +32358,15 @@ import { randomUUID as randomUUID14 } from "crypto";
31962
32358
  var THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1e3;
31963
32359
 
31964
32360
  // ../packages/plugin-sdk/src/throttle.ts
31965
- import { mkdirSync as mkdirSync3, statSync as statSync6, writeFileSync as writeFileSync6 } from "fs";
31966
- import { join as join16 } from "path";
32361
+ import { mkdirSync as mkdirSync3, statSync as statSync8, writeFileSync as writeFileSync6 } from "fs";
32362
+ import { join as join18 } from "path";
31967
32363
 
31968
32364
  // ../packages/local-ops/src/egress-record.ts
31969
32365
  function recordProjectEgress(db, target, egress, base = defaultDataDir()) {
31970
32366
  try {
31971
32367
  if (!readWorkspaceSettings(base).dataSharesInPlace) return null;
31972
- const abs = resolve(target);
31973
- const targetDir = statSync7(abs).isDirectory() ? abs : dirname6(abs);
32368
+ const abs = resolve2(target);
32369
+ const targetDir = statSync9(abs).isDirectory() ? abs : dirname7(abs);
31974
32370
  const identity = resolveRepoIdentity(abs);
31975
32371
  const worktreeRoot = resolveWorktreeRoot(abs);
31976
32372
  let root;
@@ -32012,8 +32408,8 @@ function recordProjectEgress(db, target, egress, base = defaultDataDir()) {
32012
32408
 
32013
32409
  // ../packages/local-ops/src/fs-scan.ts
32014
32410
  import { createHash as createHash5, randomUUID as randomUUID15 } from "crypto";
32015
- import { readdirSync as readdirSync6, readFileSync as readFileSync12, statSync as statSync8 } from "fs";
32016
- import { basename as basename6, extname, join as join17, resolve as resolve2 } from "path";
32411
+ import { readdirSync as readdirSync6, readFileSync as readFileSync13, statSync as statSync10 } from "fs";
32412
+ import { basename as basename6, extname, join as join19, resolve as resolve3 } from "path";
32017
32413
  var AKAIGNORE_FILENAME = ".akaignore";
32018
32414
  var SKIP_DIRS2 = /* @__PURE__ */ new Set([
32019
32415
  "node_modules",
@@ -32029,7 +32425,7 @@ var MAX_BYTES = 1e6;
32029
32425
  function* collectFiles(target) {
32030
32426
  let st;
32031
32427
  try {
32032
- st = statSync8(target);
32428
+ st = statSync10(target);
32033
32429
  } catch {
32034
32430
  return;
32035
32431
  }
@@ -32057,7 +32453,7 @@ function* visit(dir, dirRel, markLayers, skipLayers, inIgnoredDir) {
32057
32453
  readIgnoreLayer(dir, AKAIGNORE_FILENAME, dirRel.length)
32058
32454
  );
32059
32455
  for (const entry of dirents) {
32060
- const path = join17(dir, entry.name);
32456
+ const path = join19(dir, entry.name);
32061
32457
  if (entry.isDirectory()) {
32062
32458
  const skipState = evaluateIgnore(dirSkipLayers, dirRel, entry.name, true);
32063
32459
  if (skipState !== "unignored" && (SKIP_DIRS2.has(entry.name) || entry.name.startsWith(".") || skipState === "ignored")) {
@@ -32069,7 +32465,7 @@ function* visit(dir, dirRel, markLayers, skipLayers, inIgnoredDir) {
32069
32465
  if (evaluateIgnore(dirSkipLayers, dirRel, entry.name, false) === "ignored") continue;
32070
32466
  let size;
32071
32467
  try {
32072
- size = statSync8(path).size;
32468
+ size = statSync10(path).size;
32073
32469
  } catch {
32074
32470
  continue;
32075
32471
  }
@@ -32108,10 +32504,10 @@ async function scanPathIntoStore(db, target, opts = {}) {
32108
32504
  }
32109
32505
  return fingerprintKey;
32110
32506
  }
32111
- for (const { path: file2, gitignored } of collectFiles(resolve2(target))) {
32507
+ for (const { path: file2, gitignored } of collectFiles(resolve3(target))) {
32112
32508
  let text;
32113
32509
  try {
32114
- text = readFileSync12(file2, "utf8");
32510
+ text = readFileSync13(file2, "utf8");
32115
32511
  } catch {
32116
32512
  continue;
32117
32513
  }
@@ -32164,12 +32560,12 @@ async function scanPathIntoStore(db, target, opts = {}) {
32164
32560
  }
32165
32561
 
32166
32562
  // ../packages/local-ops/src/project-inventory.ts
32167
- import { statSync as statSync9 } from "fs";
32168
- import { resolve as resolve3 } from "path";
32563
+ import { statSync as statSync11 } from "fs";
32564
+ import { resolve as resolve4 } from "path";
32169
32565
  function recordProjectInventory(db, target) {
32170
32566
  try {
32171
- const abs = resolve3(target);
32172
- statSync9(abs);
32567
+ const abs = resolve4(target);
32568
+ statSync11(abs);
32173
32569
  const identity = resolveRepoIdentity(abs);
32174
32570
  if (!identity) return null;
32175
32571
  const sourceProjectId2 = db.sourceProject.upsert({
@@ -32198,17 +32594,17 @@ function recordProjectInventory(db, target) {
32198
32594
 
32199
32595
  // ../packages/local-ops/src/update-cache.ts
32200
32596
  import { spawn } from "child_process";
32201
- import { existsSync as existsSync11, readFileSync as readFileSync13, rmSync as rmSync5 } from "fs";
32202
- import { join as join18 } from "path";
32597
+ import { existsSync as existsSync12, readFileSync as readFileSync14, rmSync as rmSync6 } from "fs";
32598
+ import { join as join20 } from "path";
32203
32599
  var CHECK_TTL_MS = 24 * 60 * 60 * 1e3;
32204
32600
  function cachePath(home) {
32205
- return join18(dataDir(home), "update-check.json");
32601
+ return join20(dataDir(home), "update-check.json");
32206
32602
  }
32207
32603
  function readCache(home) {
32208
32604
  const path = cachePath(home);
32209
- if (!existsSync11(path)) return null;
32605
+ if (!existsSync12(path)) return null;
32210
32606
  try {
32211
- const raw = JSON.parse(readFileSync13(path, "utf8"));
32607
+ const raw = JSON.parse(readFileSync14(path, "utf8"));
32212
32608
  if (!isRecord(raw) || typeof raw.checkedAt !== "number" || !isRecord(raw.report)) return null;
32213
32609
  return raw;
32214
32610
  } catch {
@@ -32216,7 +32612,7 @@ function readCache(home) {
32216
32612
  }
32217
32613
  }
32218
32614
  function writeCache(home, cache) {
32219
- if (!existsSync11(dataDir(home))) return;
32615
+ if (!existsSync12(dataDir(home))) return;
32220
32616
  try {
32221
32617
  writeOwnerOnlyFileSync(cachePath(home), `${JSON.stringify(cache, null, 2)}
32222
32618
  `);
@@ -32228,7 +32624,7 @@ function isStale(cache, ttlMs = CHECK_TTL_MS) {
32228
32624
  }
32229
32625
  function clearCache(home) {
32230
32626
  try {
32231
- rmSync5(cachePath(home), { force: true });
32627
+ rmSync6(cachePath(home), { force: true });
32232
32628
  } catch {
32233
32629
  }
32234
32630
  }
@@ -32361,6 +32757,16 @@ var COMMAND_SPECS = [
32361
32757
  summary: "Reveal a vaulted secret by its pointer (every reveal is audited)",
32362
32758
  args: ["show"]
32363
32759
  },
32760
+ {
32761
+ name: "attach",
32762
+ argHint: "--url <url>",
32763
+ summary: "Register this machine against your organization's AKA deployment"
32764
+ },
32765
+ { name: "detach", summary: "Stop reporting to a deployment; record locally only" },
32766
+ {
32767
+ name: "status",
32768
+ summary: "Show what this machine is attached to, and whether policy is current"
32769
+ },
32364
32770
  {
32365
32771
  name: "tui",
32366
32772
  argHint: "[view]",
@@ -32391,18 +32797,872 @@ function commandsHelp() {
32391
32797
  return COMMAND_SPECS.map((s) => ` ${label(s).padEnd(width)}${s.summary}`).join("\n");
32392
32798
  }
32393
32799
 
32394
- // src/commands/check-updates.ts
32395
- import { existsSync as existsSync12 } from "fs";
32396
- import { parseArgs } from "util";
32800
+ // src/commands/attach.ts
32801
+ import { rmSync as rmSync7 } from "fs";
32802
+ import { join as join26 } from "path";
32803
+
32804
+ // ../packages/plugin-runtime/src/attached/forward-drops.ts
32805
+ import { readFileSync as readFileSync15 } from "fs";
32806
+ import { join as join21 } from "path";
32807
+ var FORWARD_DROPS_FILENAME = "attached-forward-drops.json";
32808
+ function forwardDropsPath(dataDir2) {
32809
+ return join21(dataDir2, FORWARD_DROPS_FILENAME);
32810
+ }
32811
+ function readForwardDrops(dataDir2) {
32812
+ try {
32813
+ const parsed2 = JSON.parse(readFileSync15(forwardDropsPath(dataDir2), "utf8"));
32814
+ if (typeof parsed2 !== "object" || parsed2 === null) return null;
32815
+ const record2 = parsed2;
32816
+ if (typeof record2.droppedForwards !== "number" || !Number.isFinite(record2.droppedForwards)) {
32817
+ return null;
32818
+ }
32819
+ if (record2.droppedForwards <= 0) return null;
32820
+ if (typeof record2.lastDropAtMs !== "number" || !Number.isFinite(record2.lastDropAtMs)) {
32821
+ return null;
32822
+ }
32823
+ return { droppedForwards: record2.droppedForwards, lastDropAtMs: record2.lastDropAtMs };
32824
+ } catch {
32825
+ return null;
32826
+ }
32827
+ }
32828
+
32829
+ // ../packages/plugin-runtime/src/attached/forward-policy.ts
32830
+ import { randomUUID as randomUUID16 } from "crypto";
32831
+ import { readFileSync as readFileSync16 } from "fs";
32832
+ import { readFile, rename, writeFile } from "fs/promises";
32833
+ import { join as join22 } from "path";
32834
+ var FAILURES = /* @__PURE__ */ new Set([
32835
+ "unauthorized",
32836
+ "forbidden",
32837
+ "unreachable"
32838
+ ]);
32839
+ var FORWARD_STATE_FILENAME = "attached-state.json";
32840
+ var STATE_FILENAME = FORWARD_STATE_FILENAME;
32841
+ function parseBreakerState(raw, nowMs) {
32842
+ try {
32843
+ const parsed2 = JSON.parse(raw);
32844
+ if (typeof parsed2 !== "object" || parsed2 === null) return null;
32845
+ const record2 = parsed2;
32846
+ const failures = typeof record2.consecutiveFailures === "number" && record2.consecutiveFailures >= 0 ? record2.consecutiveFailures : 0;
32847
+ const openedAtMs = typeof record2.openedAtMs === "number" && Number.isFinite(record2.openedAtMs) && record2.openedAtMs <= nowMs ? record2.openedAtMs : null;
32848
+ const lastFailure = typeof record2.lastFailure === "string" && FAILURES.has(record2.lastFailure) ? record2.lastFailure : null;
32849
+ return { consecutiveFailures: failures, openedAtMs, lastFailure };
32850
+ } catch {
32851
+ return null;
32852
+ }
32853
+ }
32854
+ function readForwardHealth(dir, nowMs = Date.now()) {
32855
+ try {
32856
+ return parseBreakerState(readFileSync16(join22(dir, STATE_FILENAME), "utf8"), nowMs);
32857
+ } catch {
32858
+ return null;
32859
+ }
32860
+ }
32861
+
32862
+ // ../packages/plugin-runtime/src/attached/policy-store.ts
32863
+ import { randomUUID as randomUUID17 } from "crypto";
32864
+ import { readFile as readFile2, rm, writeFile as writeFile2 } from "fs/promises";
32865
+ import { join as join23 } from "path";
32866
+
32867
+ // ../packages/plugin-runtime/src/attached/atomic-publish.ts
32868
+ import { rename as rename2 } from "fs/promises";
32869
+ var RETRYABLE = /* @__PURE__ */ new Set(["EPERM", "EACCES", "EBUSY"]);
32870
+ var ATTEMPTS = 5;
32871
+ var delay = (ms) => new Promise((resolve6) => {
32872
+ setTimeout(resolve6, ms);
32873
+ });
32874
+ async function publishByRename(tmp, file2, move = rename2) {
32875
+ for (let attempt = 1; ; attempt += 1) {
32876
+ try {
32877
+ await move(tmp, file2);
32878
+ return;
32879
+ } catch (err) {
32880
+ const code = err.code;
32881
+ if (attempt >= ATTEMPTS || code === void 0 || !RETRYABLE.has(code)) throw err;
32882
+ await delay(attempt * 10);
32883
+ }
32884
+ }
32885
+ }
32886
+
32887
+ // ../packages/plugin-runtime/src/attached/policy-store.ts
32888
+ function createPolicyStore(dir = dataDir()) {
32889
+ const file2 = join23(dir, "policy-cache.json");
32890
+ async function read() {
32891
+ try {
32892
+ const raw = await readFile2(file2, "utf8");
32893
+ const parsed2 = JSON.parse(raw);
32894
+ if (typeof parsed2 !== "object" || parsed2 === null) return null;
32895
+ const record2 = parsed2;
32896
+ const bundle = PolicyBundle.parse(record2.bundle);
32897
+ const fetchedAtMs = typeof record2.fetchedAtMs === "number" ? record2.fetchedAtMs : 0;
32898
+ const etag = typeof record2.etag === "string" ? record2.etag : void 0;
32899
+ return { bundle, fetchedAtMs, ...etag === void 0 ? {} : { etag } };
32900
+ } catch {
32901
+ return null;
32902
+ }
32903
+ }
32904
+ async function write(bundle, etag) {
32905
+ await ensureDataDir(dir);
32906
+ const stored = {
32907
+ bundle,
32908
+ fetchedAtMs: Date.now(),
32909
+ ...etag === void 0 ? {} : { etag }
32910
+ };
32911
+ const tmp = `${file2}.${randomUUID17()}.tmp`;
32912
+ try {
32913
+ await writeFile2(tmp, JSON.stringify(stored), {
32914
+ encoding: "utf8",
32915
+ mode: DATA_FILE_MODE,
32916
+ flag: "wx"
32917
+ });
32918
+ await publishByRename(tmp, file2);
32919
+ } catch (err) {
32920
+ await rm(tmp, { force: true }).catch(() => void 0);
32921
+ throw err;
32922
+ }
32923
+ }
32924
+ return { read, write, file: file2 };
32925
+ }
32926
+
32927
+ // ../packages/remote/src/http.ts
32928
+ import { request as httpRequest } from "http";
32929
+ import { request as httpsRequest } from "https";
32930
+ var DEFAULT_TIMEOUT_MS2 = 1e4;
32931
+ var MAX_RESPONSE_BYTES = 8 * 1024 * 1024;
32932
+ var RemoteRequestError = class extends Error {
32933
+ constructor(status) {
32934
+ super(`control-plane request failed with status ${String(status)}`);
32935
+ this.status = status;
32936
+ this.name = "RemoteRequestError";
32937
+ }
32938
+ status;
32939
+ };
32940
+ var RemoteRequestInvalid = class extends Error {
32941
+ constructor(route, cause) {
32942
+ super(`refusing to send a malformed body to ${route}`);
32943
+ this.cause = cause;
32944
+ this.name = "RemoteRequestInvalid";
32945
+ }
32946
+ cause;
32947
+ };
32948
+ var RemoteResponseInvalid = class extends Error {
32949
+ constructor(route, detail) {
32950
+ super(`control plane answered ${route} with ${detail}`);
32951
+ this.name = "RemoteResponseInvalid";
32952
+ }
32953
+ };
32954
+ var RemoteTransportError = class extends Error {
32955
+ /**
32956
+ * The status the peer sent, when headers arrived and only the BODY was
32957
+ * refused.
32958
+ *
32959
+ * Undefined for the ordinary case this class was written for — no answer at
32960
+ * all. It exists because two paths reject after a status has already been
32961
+ * delivered: an oversized body and an aborted response. Discarding it there
32962
+ * reported a deployment answering 401 with a verbose body as a network
32963
+ * outage, which sends the reader to look at their network instead of their
32964
+ * credential.
32965
+ */
32966
+ constructor(reason, status) {
32967
+ super(`control-plane request did not complete: ${reason}`);
32968
+ this.status = status;
32969
+ this.name = "RemoteTransportError";
32970
+ }
32971
+ status;
32972
+ };
32973
+ async function send(options) {
32974
+ const url2 = new URL(options.url);
32975
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS2;
32976
+ const send_ = url2.protocol === "http:" ? httpRequest : httpsRequest;
32977
+ const requestOptions = {
32978
+ method: options.method,
32979
+ headers: {
32980
+ // CALLER HEADERS FIRST, so this module's own are not overridable. Spread
32981
+ // last they win, and two of the values below are ones no caller may
32982
+ // replace: `x-api-key` is the credential, and `content-length` is the
32983
+ // byte count that stops a multi-byte body being truncated by the
32984
+ // receiver. `SendOptions.headers` is a free-form record on an exported
32985
+ // function, so "no caller does that today" is not the guarantee to rely
32986
+ // on. The one header any caller actually passes — `if-none-match` on the
32987
+ // conditional GET — is untouched by this order.
32988
+ ...options.headers,
32989
+ // The credential. One header, matching what the deployment authenticates
32990
+ // on; a second copy in an `Authorization` header would be one more place
32991
+ // it can be logged by an intermediary for no gain.
32992
+ "x-api-key": options.apiKey,
32993
+ accept: "application/json",
32994
+ ...options.body === void 0 ? {} : {
32995
+ "content-type": "application/json",
32996
+ // Byte length, not string length: a multi-byte body sent with a
32997
+ // character count is truncated by the receiver.
32998
+ "content-length": String(Buffer.byteLength(options.body))
32999
+ }
33000
+ }
33001
+ };
33002
+ return new Promise((resolve6, reject) => {
33003
+ let settled = false;
33004
+ const fail = (reason, status) => {
33005
+ if (settled) return;
33006
+ settled = true;
33007
+ reject(new RemoteTransportError(reason, status));
33008
+ };
33009
+ const req = send_(url2, requestOptions, (res) => {
33010
+ const chunks = [];
33011
+ let size = 0;
33012
+ res.on("data", (chunk) => {
33013
+ size += chunk.length;
33014
+ if (size > MAX_RESPONSE_BYTES) {
33015
+ fail(`response exceeded ${String(MAX_RESPONSE_BYTES)} bytes`, res.statusCode);
33016
+ res.destroy();
33017
+ req.destroy();
33018
+ return;
33019
+ }
33020
+ chunks.push(chunk);
33021
+ });
33022
+ res.on("aborted", () => {
33023
+ fail("the response was aborted", res.statusCode);
33024
+ });
33025
+ res.on("end", () => {
33026
+ if (settled) return;
33027
+ settled = true;
33028
+ resolve6({
33029
+ status: res.statusCode ?? 0,
33030
+ headers: res.headers,
33031
+ body: Buffer.concat(chunks).toString("utf8")
33032
+ });
33033
+ });
33034
+ });
33035
+ const deadline = setTimeout(() => {
33036
+ fail(`no response within ${String(timeoutMs)}ms`);
33037
+ req.destroy();
33038
+ }, timeoutMs);
33039
+ deadline.unref();
33040
+ req.on("upgrade", (_res, socket) => {
33041
+ fail("the deployment answered with a protocol upgrade");
33042
+ socket.destroy();
33043
+ });
33044
+ req.on("close", () => {
33045
+ fail("the connection closed before a response was read");
33046
+ clearTimeout(deadline);
33047
+ });
33048
+ req.on("error", (err) => {
33049
+ fail(err.message);
33050
+ });
33051
+ if (options.body !== void 0) req.write(options.body);
33052
+ req.end();
33053
+ });
33054
+ }
33055
+
33056
+ // ../packages/remote/src/client.ts
33057
+ var ROUTES = {
33058
+ events: "/v1/events",
33059
+ auditEvents: "/v1/audit-events",
33060
+ inventory: "/v1/inventory",
33061
+ storePosture: "/v1/store-posture",
33062
+ policyBundle: "/v1/policy-bundle",
33063
+ whoami: "/v1/plugin/whoami"
33064
+ };
33065
+ function headerValue(response, name) {
33066
+ const raw = response.headers[name];
33067
+ if (raw === void 0) return void 0;
33068
+ return Array.isArray(raw) ? raw[0] : raw;
33069
+ }
33070
+ function okBody(response) {
33071
+ if (response.status < 200 || response.status >= 300) {
33072
+ throw new RemoteRequestError(response.status);
33073
+ }
33074
+ return response.body;
33075
+ }
33076
+ function parsed(schema, body, route) {
33077
+ let json2;
33078
+ try {
33079
+ json2 = JSON.parse(body);
33080
+ } catch {
33081
+ throw new RemoteResponseInvalid(route, "a body that is not JSON");
33082
+ }
33083
+ const result = schema.safeParse(json2);
33084
+ if (!result.success) {
33085
+ throw new RemoteResponseInvalid(route, "a body this client cannot read");
33086
+ }
33087
+ return result.data;
33088
+ }
33089
+ function withoutTrailingSlashes(endpoint) {
33090
+ let end = endpoint.length;
33091
+ while (end > 0 && endpoint.charCodeAt(end - 1) === SLASH) end -= 1;
33092
+ return endpoint.slice(0, end);
33093
+ }
33094
+ var SLASH = "/".charCodeAt(0);
33095
+ function createRemoteClient(options) {
33096
+ const base = withoutTrailingSlashes(options.endpoint);
33097
+ const url2 = (route) => `${base}${route}`;
33098
+ const common = { apiKey: options.apiKey, timeoutMs: options.timeoutMs };
33099
+ return {
33100
+ async ingestEvents(batch) {
33101
+ const response = await send({
33102
+ ...common,
33103
+ method: "POST",
33104
+ url: url2(ROUTES.events),
33105
+ body: JSON.stringify(batch)
33106
+ });
33107
+ return parsed(IngestAck, okBody(response), ROUTES.events);
33108
+ },
33109
+ async ingestInventory(context) {
33110
+ const response = await send({
33111
+ ...common,
33112
+ method: "POST",
33113
+ url: url2(ROUTES.inventory),
33114
+ body: JSON.stringify(context)
33115
+ });
33116
+ return parsed(ResolvedInventory, okBody(response), ROUTES.inventory);
33117
+ },
33118
+ async recordAuditEvent(event) {
33119
+ const validated = RecordAuditEventRequest.safeParse(event);
33120
+ if (!validated.success) throw new RemoteRequestInvalid(ROUTES.auditEvents, validated.error);
33121
+ const submission = validated.data;
33122
+ const response = await send({
33123
+ ...common,
33124
+ method: "POST",
33125
+ url: url2(ROUTES.auditEvents),
33126
+ body: JSON.stringify(submission)
33127
+ });
33128
+ okBody(response);
33129
+ },
33130
+ async reportStorePosture(snapshot) {
33131
+ const response = await send({
33132
+ ...common,
33133
+ method: "POST",
33134
+ url: url2(ROUTES.storePosture),
33135
+ body: JSON.stringify(snapshot)
33136
+ });
33137
+ okBody(response);
33138
+ },
33139
+ async getPolicyBundle(etag) {
33140
+ const response = await send({
33141
+ ...common,
33142
+ method: "GET",
33143
+ url: url2(ROUTES.policyBundle),
33144
+ ...etag === void 0 ? {} : { headers: { "if-none-match": etag } }
33145
+ });
33146
+ if (response.status === 304) {
33147
+ return { changed: false, etag: headerValue(response, "etag") ?? etag };
33148
+ }
33149
+ const bundle = parsed(PolicyBundle, okBody(response), ROUTES.policyBundle);
33150
+ return { changed: true, bundle, etag: headerValue(response, "etag") };
33151
+ },
33152
+ async whoami() {
33153
+ const response = await send({ ...common, method: "GET", url: url2(ROUTES.whoami) });
33154
+ return parsed(PluginWhoami, okBody(response), ROUTES.whoami);
33155
+ }
33156
+ };
33157
+ }
33158
+
33159
+ // ../packages/plugin-runtime/src/attached/posture-reporter.ts
33160
+ var POSTURE_REPORT_INTERVAL_MS = 60 * 60 * 1e3;
33161
+
33162
+ // ../packages/plugin-runtime/src/attached/posture-snapshot.ts
33163
+ import { statSync as statSync12 } from "fs";
33164
+ import { DatabaseSync as DatabaseSync3 } from "node:sqlite";
33165
+
33166
+ // ../packages/plugin-runtime/src/attached/posture-store.ts
33167
+ import { randomUUID as randomUUID18 } from "crypto";
33168
+ import { readFile as readFile3, rm as rm2, writeFile as writeFile3 } from "fs/promises";
33169
+ import { join as join24 } from "path";
33170
+
33171
+ // ../packages/plugin-runtime/src/attached/sync-state.ts
33172
+ import { readFileSync as readFileSync17 } from "fs";
33173
+ import { join as join25 } from "path";
33174
+ var SYNC_STATE_FILENAME = "attached-sync-state.json";
33175
+ var OUTCOMES = /* @__PURE__ */ new Set([
33176
+ "ok",
33177
+ "not-modified",
33178
+ "unauthorized",
33179
+ "forbidden",
33180
+ "unreachable",
33181
+ "invalid-bundle"
33182
+ ]);
33183
+ function syncStatePath(dataDir2) {
33184
+ return join25(dataDir2, SYNC_STATE_FILENAME);
33185
+ }
33186
+ function readSyncState(dataDir2) {
33187
+ try {
33188
+ const parsed2 = JSON.parse(readFileSync17(syncStatePath(dataDir2), "utf8"));
33189
+ if (typeof parsed2 !== "object" || parsed2 === null) return null;
33190
+ const record2 = parsed2;
33191
+ if (typeof record2.outcome !== "string" || !OUTCOMES.has(record2.outcome)) return null;
33192
+ if (typeof record2.atMs !== "number") return null;
33193
+ return { outcome: record2.outcome, atMs: record2.atMs };
33194
+ } catch {
33195
+ return null;
33196
+ }
33197
+ }
33198
+
33199
+ // ../packages/plugin-runtime/src/attached/status.ts
33200
+ var REFUSAL_LINES = {
33201
+ unauthorized: "KEY REJECTED \u2014 re-attach with a valid plugin key",
33202
+ forbidden: "ACCESS REFUSED \u2014 key is valid but not permitted; ask your org admin"
33203
+ };
33204
+ var OUTCOME_LINES = {
33205
+ ok: "policy synced",
33206
+ "not-modified": "policy up to date",
33207
+ unauthorized: REFUSAL_LINES.unauthorized,
33208
+ forbidden: REFUSAL_LINES.forbidden,
33209
+ unreachable: "control plane unreachable at last attempt",
33210
+ "invalid-bundle": "control plane sent a policy bundle this build cannot read"
33211
+ };
33212
+ function ageLine(fromMs, nowMs) {
33213
+ const deltaMs = Math.max(0, nowMs - fromMs);
33214
+ const minutes = Math.floor(deltaMs / 6e4);
33215
+ if (minutes < 1) return "just now";
33216
+ if (minutes < 60) return `${String(minutes)}m ago`;
33217
+ const hours = Math.floor(minutes / 60);
33218
+ if (hours < 24) return `${String(hours)}h ago`;
33219
+ return `${String(Math.floor(hours / 24))}d ago`;
33220
+ }
33221
+ function renderAttachedStatus(deps) {
33222
+ try {
33223
+ const nowMs = (deps.now ?? (() => Date.now()))();
33224
+ const settings = readWorkspaceSettings(deps.base);
33225
+ if (!isAttached(settings) || settings.controlPlane === void 0) {
33226
+ return ["AKA: standalone (not attached)", " no control plane configured"].join("\n");
33227
+ }
33228
+ const connection = settings.controlPlane;
33229
+ const state = readControlPlaneCredentialState(deps.settingsDir, connection);
33230
+ const lines = [
33231
+ // The mismatch case earns its own headline. An administrator can repoint
33232
+ // `controlPlane` across a fleet and cannot write the credential file, so
33233
+ // this is an ordinary migration rather than a fault — and reporting it as
33234
+ // a bare "not attached" would send every affected user looking for a file
33235
+ // that is present and intact.
33236
+ state.usable ? "AKA: attached" : state.reason === "endpoint-mismatch" ? "AKA: attached \u2014 credential is for another deployment, re-attach" : "AKA: attached \u2014 no usable credential, re-attach",
33237
+ // ALLOW-LISTED, field by field. The credential itself is deliberately
33238
+ // absent and must stay that way; `keyPrefix` is the non-secret half.
33239
+ //
33240
+ // And every one of them goes through `printable`, which is about the
33241
+ // field's CONTENT rather than which fields appear. The allow-list above
33242
+ // decides what is rendered; it says nothing about what those strings
33243
+ // hold. None of these is authored by this machine — `label` comes from
33244
+ // `aka attach --label` or from a `settings.json` an administrator can pin
33245
+ // fleet-wide, and the endpoint and `keyPrefix` come off the credential
33246
+ // file — and all of them land in a status block a user reads to decide
33247
+ // whether their machine is managed. An ANSI escape in any of them can
33248
+ // repaint that block or hide a line, which is the same argument
33249
+ // `printable` was written for one field over.
33250
+ ` plane ${printable2(controlPlaneName(connection))}`,
33251
+ ` attached ${printable2(connection.attachedAt, 40)}`
33252
+ ];
33253
+ if (state.usable && state.credential.keyPrefix !== void 0) {
33254
+ lines.push(` key ${printable2(state.credential.keyPrefix, 16)}\u2026`);
33255
+ }
33256
+ if (!state.usable && state.reason === "endpoint-mismatch") {
33257
+ lines.push(` credential ${printable2(state.credentialEndpoint, 200)}`);
33258
+ }
33259
+ return [
33260
+ ...lines,
33261
+ ...policyLines(deps.dataDir, nowMs),
33262
+ ...forwardLines(deps.dataDir, nowMs)
33263
+ ].join("\n");
33264
+ } catch {
33265
+ return "AKA: status unavailable";
33266
+ }
33267
+ }
33268
+ function policyLines(dataDir2, nowMs) {
33269
+ const lines = [];
33270
+ const state = readSyncState(dataDir2);
33271
+ if (state) {
33272
+ lines.push(` sync ${OUTCOME_LINES[state.outcome]} (${ageLine(state.atMs, nowMs)})`);
33273
+ } else {
33274
+ lines.push(" sync no attempt recorded yet");
33275
+ }
33276
+ return lines;
33277
+ }
33278
+ function dropLines(dataDir2, nowMs) {
33279
+ const drops = readForwardDrops(dataDir2);
33280
+ if (!drops) return [];
33281
+ return [
33282
+ ` at least ${String(drops.droppedForwards)} events dropped past the batch budget, last ${ageLine(drops.lastDropAtMs, nowMs)}`
33283
+ ];
33284
+ }
33285
+ function forwardLines(dataDir2, nowMs) {
33286
+ const drops = dropLines(dataDir2, nowMs);
33287
+ const health = readForwardHealth(dataDir2, nowMs);
33288
+ if (!health) return [" forward no failures recorded", ...drops];
33289
+ const { consecutiveFailures, openedAtMs, lastFailure } = health;
33290
+ if (openedAtMs === null && consecutiveFailures === 0) {
33291
+ return [" forward reporting normally", ...drops];
33292
+ }
33293
+ const lines = openedAtMs !== null ? (
33294
+ // `openedAtMs` is re-stamped on every half-open probe, so the gap to now
33295
+ // is bounded by one cooldown however long the control plane has been down — it
33296
+ // dates the last ATTEMPT, never the outage. The failure count is the
33297
+ // part that grows, so that is the number shown as the magnitude.
33298
+ [
33299
+ ` forward NOT REPORTING \u2014 ${String(consecutiveFailures)} consecutive failures, last tried ${ageLine(openedAtMs, nowMs)}`
33300
+ ]
33301
+ ) : (
33302
+ // Closed but non-zero: failing without having reached the threshold yet.
33303
+ [` forward ${String(consecutiveFailures)} failures since the last success`]
33304
+ );
33305
+ if (lastFailure === "unauthorized" || lastFailure === "forbidden") {
33306
+ lines.push(` ${REFUSAL_LINES[lastFailure]}`);
33307
+ }
33308
+ return [...lines, ...drops];
33309
+ }
33310
+ function printable2(value, max = 80) {
33311
+ const stripped = value.replace(/[\p{Cc}\p{Cf}]/gu, "");
33312
+ return stripped.length > max ? `${stripped.slice(0, max)}\u2026` : stripped;
33313
+ }
33314
+ async function renderPolicyLine(dataDir2, nowMs = Date.now()) {
33315
+ try {
33316
+ const cached2 = await createPolicyStore(dataDir2).read();
33317
+ if (!cached2) return " policy none cached";
33318
+ return ` policy ${printable2(cached2.bundle.version)} (fetched ${ageLine(cached2.fetchedAtMs, nowMs)})`;
33319
+ } catch {
33320
+ return " policy unreadable";
33321
+ }
33322
+ }
33323
+
33324
+ // ../packages/plugin-runtime/src/attached/sync-trigger.ts
33325
+ import { spawn as spawn2 } from "child_process";
33326
+ import { fileURLToPath as fileURLToPath3 } from "url";
33327
+ var SYNC_THROTTLE_MS = 15 * 60 * 1e3;
33328
+
33329
+ // ../packages/plugin-runtime/src/attached/factory.ts
33330
+ import { hostname as hostname5 } from "os";
33331
+
33332
+ // ../packages/plugin-runtime/src/standalone-gateway.ts
33333
+ import { randomUUID as randomUUID19 } from "crypto";
33334
+
33335
+ // ../packages/plugin-runtime/src/handle-session-start.ts
33336
+ import { randomUUID as randomUUID20 } from "crypto";
33337
+ var EXCEPTION_RETENTION_MS = 90 * 24 * 60 * 60 * 1e3;
32397
33338
 
32398
33339
  // src/lib/args.ts
32399
- import { resolve as resolve4 } from "path";
33340
+ import { resolve as resolve5 } from "path";
32400
33341
  var HOME_OPTION = { home: { type: "string" } };
32401
33342
  function homeBase(home) {
32402
- return home === void 0 ? defaultDataDir() : resolve4(home);
33343
+ return home === void 0 ? defaultDataDir() : resolve5(home);
33344
+ }
33345
+
33346
+ // src/lib/prompter.ts
33347
+ import { createInterface } from "readline";
33348
+ function processHiddenChar(state, ch) {
33349
+ if (state.done) return state;
33350
+ if (state.esc === "esc") {
33351
+ return ch === "[" || ch === "O" ? { ...state, esc: "seq" } : { ...state, esc: "none" };
33352
+ }
33353
+ if (state.esc === "seq") {
33354
+ return ch >= "@" && ch <= "~" ? { ...state, esc: "none" } : state;
33355
+ }
33356
+ if (ch === "\r" || ch === "\n") return { ...state, done: "submit" };
33357
+ if (ch === "") return { ...state, done: "cancel" };
33358
+ if (ch === "\x7F" || ch === "\b") return { ...state, value: state.value.slice(0, -1) };
33359
+ if (ch === "\x1B") return { ...state, esc: "esc" };
33360
+ if (ch < " ") return state;
33361
+ return { ...state, value: state.value + ch };
33362
+ }
33363
+ var CLEANUP_SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"];
33364
+ function processIo() {
33365
+ return {
33366
+ input: process.stdin,
33367
+ output: process.stdout,
33368
+ errorOutput: process.stderr,
33369
+ signals: {
33370
+ once: (signal, handler) => {
33371
+ process.once(signal, handler);
33372
+ },
33373
+ off: (signal, handler) => {
33374
+ process.removeListener(signal, handler);
33375
+ },
33376
+ raise: (signal) => {
33377
+ process.kill(process.pid, signal);
33378
+ }
33379
+ }
33380
+ };
33381
+ }
33382
+ function terminalPrompter(io = processIo()) {
33383
+ return {
33384
+ out: (text) => {
33385
+ io.output.write(text);
33386
+ },
33387
+ err: (text) => {
33388
+ io.errorOutput.write(text);
33389
+ },
33390
+ isInteractive: io.input.isTTY && io.output.isTTY,
33391
+ ask(question) {
33392
+ return new Promise((resolve6) => {
33393
+ const rl = createInterface({ input: io.input, output: io.output });
33394
+ rl.question(question, (answer) => {
33395
+ rl.close();
33396
+ resolve6(answer);
33397
+ });
33398
+ });
33399
+ },
33400
+ // Raw mode so nothing is echoed; characters are folded through
33401
+ // processHiddenChar. The captured value stays in this closure and is
33402
+ // handed to the caller only — never written anywhere. TTY restoration is
33403
+ // guaranteed via a one-shot `restore` that also runs on stdin errors and
33404
+ // fatal signals: a security tool must never brick the terminal it was
33405
+ // invoked from.
33406
+ askHidden(question) {
33407
+ return new Promise((resolve6, reject) => {
33408
+ const stdin = io.input;
33409
+ io.output.write(question);
33410
+ stdin.setRawMode(true);
33411
+ stdin.resume();
33412
+ let state = { value: "", esc: "none" };
33413
+ let restored = false;
33414
+ const restore = () => {
33415
+ if (restored) return;
33416
+ restored = true;
33417
+ stdin.removeListener("data", onData);
33418
+ stdin.removeListener("error", onError);
33419
+ for (const sig of CLEANUP_SIGNALS) io.signals.off(sig, onSignal);
33420
+ try {
33421
+ stdin.setRawMode(false);
33422
+ } catch {
33423
+ }
33424
+ stdin.pause();
33425
+ };
33426
+ const finish = (err) => {
33427
+ restore();
33428
+ io.output.write("\n");
33429
+ if (err) reject(err);
33430
+ else resolve6(state.value);
33431
+ };
33432
+ const onError = (err) => {
33433
+ finish(err);
33434
+ };
33435
+ const onSignal = (sig) => {
33436
+ restore();
33437
+ io.signals.raise(sig);
33438
+ };
33439
+ const onData = (chunk) => {
33440
+ try {
33441
+ for (const ch of chunk.toString("utf8")) {
33442
+ state = processHiddenChar(state, ch);
33443
+ if (state.done === "submit") {
33444
+ finish();
33445
+ return;
33446
+ }
33447
+ if (state.done === "cancel") {
33448
+ finish(new Error("cancelled"));
33449
+ return;
33450
+ }
33451
+ }
33452
+ } catch (err) {
33453
+ finish(err instanceof Error ? err : new Error(String(err)));
33454
+ }
33455
+ };
33456
+ stdin.on("data", onData);
33457
+ stdin.once("error", onError);
33458
+ for (const sig of CLEANUP_SIGNALS) io.signals.once(sig, onSignal);
33459
+ });
33460
+ },
33461
+ async readAllStdin() {
33462
+ const chunks = [];
33463
+ for await (const chunk of io.input) {
33464
+ chunks.push(chunk);
33465
+ }
33466
+ return Buffer.concat(chunks).toString("utf8");
33467
+ }
33468
+ };
33469
+ }
33470
+
33471
+ // src/commands/attach.ts
33472
+ var POLICY_CACHE_FILENAME = "policy-cache.json";
33473
+ var USAGE = `Usage: aka attach --url <https-url> [--label <name>] [--key-stdin]
33474
+
33475
+ Registers this machine against your organization's AKA deployment.
33476
+
33477
+ --url <url> Where the deployment lives. https, or http on loopback.
33478
+ --label <name> What to call it on screen. Defaults to the URL.
33479
+ --key-stdin Read the access key from stdin instead of prompting.
33480
+ --home <dir> Use an alternate AKA home instead of ~/.aka.
33481
+
33482
+ The key is never accepted as a command-line argument \u2014 it would be visible to
33483
+ every process on this machine and recorded in your shell history.`;
33484
+ function parseAttachArgs(argv) {
33485
+ const parsed2 = { keyStdin: false };
33486
+ for (let i = 0; i < argv.length; i += 1) {
33487
+ const arg = argv[i];
33488
+ if (arg === "--key" || arg?.startsWith("--key=")) {
33489
+ return {
33490
+ error: "aka attach does not take --key: a key on the command line is visible to every process on this machine and is written to your shell history. Run without it to be prompted, or pipe the key in with --key-stdin."
33491
+ };
33492
+ }
33493
+ if (arg === "--key-stdin") {
33494
+ parsed2.keyStdin = true;
33495
+ } else if (arg === "--url") {
33496
+ parsed2.url = argv[++i];
33497
+ } else if (arg?.startsWith("--url=")) {
33498
+ parsed2.url = arg.slice("--url=".length);
33499
+ } else if (arg === "--label") {
33500
+ parsed2.label = argv[++i];
33501
+ } else if (arg?.startsWith("--label=")) {
33502
+ parsed2.label = arg.slice("--label=".length);
33503
+ } else if (arg === "--home") {
33504
+ parsed2.home = argv[++i];
33505
+ } else if (arg?.startsWith("--home=")) {
33506
+ parsed2.home = arg.slice("--home=".length);
33507
+ } else {
33508
+ return { error: `unknown option ${String(arg)}` };
33509
+ }
33510
+ }
33511
+ if (parsed2.label !== void 0 && CONTROL_CHARS.test(parsed2.label)) {
33512
+ return {
33513
+ error: "aka attach does not take a --label containing control characters. The label is printed into `aka status`, which a user reads to decide whether their machine is managed, and an escape sequence there can repaint or hide lines of that block."
33514
+ };
33515
+ }
33516
+ return parsed2;
33517
+ }
33518
+ var CONTROL_CHARS = /[\p{Cc}\p{Cf}]/u;
33519
+ var isError = (v) => "error" in v;
33520
+ async function runAttach(argv, deps = {}) {
33521
+ const io = deps.prompter ?? terminalPrompter();
33522
+ const exit = deps.exit ?? ((code) => process.exit(code));
33523
+ const args = parseAttachArgs(argv);
33524
+ if (isError(args)) {
33525
+ io.err(`${args.error}
33526
+
33527
+ ${USAGE}`);
33528
+ exit(2);
33529
+ return;
33530
+ }
33531
+ const base = deps.base ?? homeBase(args.home);
33532
+ const endpoint = args.url;
33533
+ if (endpoint === void 0 || endpoint === "") {
33534
+ io.err(USAGE);
33535
+ exit(2);
33536
+ return;
33537
+ }
33538
+ if (!isSafeEndpoint(endpoint)) {
33539
+ io.err(
33540
+ `refusing to attach to ${endpoint}: an access key must not travel in the clear. Use an https URL (http is accepted only for a loopback deployment).`
33541
+ );
33542
+ exit(2);
33543
+ return;
33544
+ }
33545
+ const apiKey = (args.keyStdin ? (await io.readAllStdin()).trim() : io.isInteractive ? (await io.askHidden("Access key (input hidden): ")).trim() : "").trim();
33546
+ if (apiKey === "") {
33547
+ io.err(
33548
+ io.isInteractive || args.keyStdin ? "no access key was provided; nothing was changed." : "no terminal to prompt on. Pipe the key in with --key-stdin."
33549
+ );
33550
+ exit(2);
33551
+ return;
33552
+ }
33553
+ let identity;
33554
+ try {
33555
+ identity = await (deps.verify ?? verifyWithControlPlane)(endpoint, apiKey);
33556
+ } catch {
33557
+ io.err(
33558
+ `could not verify that key against ${endpoint}. Nothing was changed \u2014 check the URL and that the key has not been revoked.`
33559
+ );
33560
+ exit(1);
33561
+ return;
33562
+ }
33563
+ const previous = readControlPlaneCredentialState(settingsDir(base));
33564
+ try {
33565
+ writeControlPlaneCredential(settingsDir(base), {
33566
+ specVersion: 1,
33567
+ endpoint,
33568
+ apiKey,
33569
+ mintedAt: (/* @__PURE__ */ new Date()).toISOString()
33570
+ });
33571
+ applyOnboarding(
33572
+ {
33573
+ runMode: "attached",
33574
+ controlPlane: {
33575
+ endpoint,
33576
+ attachedAt: (/* @__PURE__ */ new Date()).toISOString(),
33577
+ ...args.label === void 0 ? {} : { label: args.label }
33578
+ }
33579
+ },
33580
+ base
33581
+ );
33582
+ } catch (err) {
33583
+ try {
33584
+ if (previous.usable) writeControlPlaneCredential(settingsDir(base), previous.credential);
33585
+ else removeControlPlaneCredential(settingsDir(base));
33586
+ } catch {
33587
+ }
33588
+ io.err(
33589
+ err instanceof ManagedFieldError ? "your organization manages this setting on this machine, so it cannot be attached here." : "could not save the attachment; this machine is left as it was."
33590
+ );
33591
+ exit(1);
33592
+ return;
33593
+ }
33594
+ io.out(
33595
+ [
33596
+ `Attached to ${args.label ?? endpoint}.`,
33597
+ ` organization ${identity.tenantName}`,
33598
+ ` you ${identity.userEmail}`,
33599
+ "",
33600
+ "Policy arrives on the next session. Run `aka status` to see it.",
33601
+ ""
33602
+ ].join("\n")
33603
+ );
33604
+ }
33605
+ async function verifyWithControlPlane(endpoint, apiKey) {
33606
+ const who = await createRemoteClient({ endpoint, apiKey }).whoami();
33607
+ return { tenantName: who.tenantName, userEmail: who.userEmail };
33608
+ }
33609
+ function runDetach(argv, deps = {}) {
33610
+ const io = deps.prompter ?? terminalPrompter();
33611
+ const exit = deps.exit ?? ((code) => process.exit(code));
33612
+ const args = parseAttachArgs(argv);
33613
+ if (isError(args)) {
33614
+ io.err(args.error);
33615
+ exit(2);
33616
+ return;
33617
+ }
33618
+ const base = deps.base ?? homeBase(args.home);
33619
+ const had = readControlPlaneCredentialState(settingsDir(base)).usable;
33620
+ try {
33621
+ applyOnboarding({ runMode: "standalone", controlPlane: void 0 }, base);
33622
+ } catch (err) {
33623
+ io.err(
33624
+ err instanceof ManagedFieldError ? "your organization manages this setting on this machine, so it cannot be detached here." : "could not clear the attachment; this machine is left as it was."
33625
+ );
33626
+ exit(1);
33627
+ return;
33628
+ }
33629
+ removeControlPlaneCredential(settingsDir(base));
33630
+ clearDerived(dataDir(base));
33631
+ io.out(
33632
+ had ? "Detached. This machine records locally only; that deployment is sent nothing.\n" : "This machine was not attached; nothing to do.\n"
33633
+ );
33634
+ }
33635
+ function clearDerived(dir) {
33636
+ for (const name of [
33637
+ POLICY_CACHE_FILENAME,
33638
+ SYNC_STATE_FILENAME,
33639
+ FORWARD_STATE_FILENAME,
33640
+ FORWARD_DROPS_FILENAME
33641
+ ]) {
33642
+ rmSync7(join26(dir, name), { force: true });
33643
+ }
33644
+ }
33645
+ async function runStatus(argv, deps = {}) {
33646
+ const io = deps.prompter ?? terminalPrompter();
33647
+ const args = parseAttachArgs(argv);
33648
+ if (isError(args)) {
33649
+ io.err(args.error);
33650
+ (deps.exit ?? ((code) => process.exit(code)))(2);
33651
+ return;
33652
+ }
33653
+ const base = deps.base ?? homeBase(args.home);
33654
+ const dataDir2 = dataDir(base);
33655
+ const block = renderAttachedStatus({ base, settingsDir: settingsDir(base), dataDir: dataDir2 });
33656
+ const attached = !block.startsWith("AKA: standalone");
33657
+ io.out(attached ? `${block}
33658
+ ${await renderPolicyLine(dataDir2)}
33659
+ ` : `${block}
33660
+ `);
32403
33661
  }
32404
33662
 
32405
33663
  // src/commands/check-updates.ts
33664
+ import { existsSync as existsSync13 } from "fs";
33665
+ import { parseArgs } from "util";
32406
33666
  function runCheckUpdates(argv) {
32407
33667
  const { values } = parseArgs({ args: argv, options: HOME_OPTION });
32408
33668
  const home = homeBase(values.home);
@@ -32424,7 +33684,7 @@ function runCheckUpdates(argv) {
32424
33684
  out.write(`${String(ups.length)} update(s) available \u2014 run \`aka update\` to apply.
32425
33685
  `);
32426
33686
  }
32427
- if (existsSync12(dataDir(home))) {
33687
+ if (existsSync13(dataDir(home))) {
32428
33688
  const notifiedPluginIds = readCache(home)?.notifiedPluginIds ?? [];
32429
33689
  writeCache(home, { checkedAt: Date.now(), report, notifiedPluginIds });
32430
33690
  }
@@ -32577,16 +33837,16 @@ function runCompletion(argv) {
32577
33837
  }
32578
33838
 
32579
33839
  // src/commands/dashboard.ts
32580
- import { spawn as spawn3 } from "child_process";
32581
- import { existsSync as existsSync13 } from "fs";
33840
+ import { spawn as spawn4 } from "child_process";
33841
+ import { existsSync as existsSync14 } from "fs";
32582
33842
  import { createRequire as createRequire2 } from "module";
32583
33843
  import { createServer } from "net";
32584
- import { dirname as dirname7, join as join19 } from "path";
32585
- import { fileURLToPath as fileURLToPath3, pathToFileURL } from "url";
33844
+ import { dirname as dirname8, join as join27 } from "path";
33845
+ import { fileURLToPath as fileURLToPath4, pathToFileURL } from "url";
32586
33846
  import { parseArgs as parseArgs2 } from "util";
32587
33847
 
32588
33848
  // src/lib/open-url.ts
32589
- import { spawn as spawn2 } from "child_process";
33849
+ import { spawn as spawn3 } from "child_process";
32590
33850
  function openUrlCommand(platform2, url2) {
32591
33851
  if (platform2 === "darwin") return { command: "open", args: [url2] };
32592
33852
  if (platform2 === "win32") return { command: "cmd", args: ["/c", "start", "", url2] };
@@ -32596,7 +33856,7 @@ var DETACHED = Object.freeze({ stdio: "ignore", detached: true });
32596
33856
  function openUrl(url2, deps = {}) {
32597
33857
  const { command, args } = openUrlCommand(deps.platform ?? process.platform, url2);
32598
33858
  try {
32599
- const child = (deps.spawn ?? spawn2)(command, [...args], DETACHED);
33859
+ const child = (deps.spawn ?? spawn3)(command, [...args], DETACHED);
32600
33860
  child.on("error", () => {
32601
33861
  });
32602
33862
  child.unref();
@@ -32606,10 +33866,10 @@ function openUrl(url2, deps = {}) {
32606
33866
 
32607
33867
  // src/commands/dashboard.ts
32608
33868
  var require3 = createRequire2(import.meta.url);
32609
- var here = dirname7(fileURLToPath3(import.meta.url));
33869
+ var here = dirname8(fileURLToPath4(import.meta.url));
32610
33870
  var BIND_HOST = "127.0.0.1";
32611
33871
  function pkgBase() {
32612
- return isSea() ? dirname7(process.execPath) : join19(here, "..");
33872
+ return isSea() ? dirname8(process.execPath) : join27(here, "..");
32613
33873
  }
32614
33874
  function isPortFree(port) {
32615
33875
  return new Promise((resolve6) => {
@@ -32663,17 +33923,17 @@ async function runDashboard(argv) {
32663
33923
  refreshUpdateMirror(dataDir());
32664
33924
  const base = pkgBase();
32665
33925
  const bundledServer = [
32666
- join19(base, "web-ui", "server.js"),
32667
- join19(base, "web-ui", "web-ui", "server.js")
32668
- ].find((p) => existsSync13(p));
33926
+ join27(base, "web-ui", "server.js"),
33927
+ join27(base, "web-ui", "web-ui", "server.js")
33928
+ ].find((p) => existsSync14(p));
32669
33929
  if (bundledServer) {
32670
33930
  launchStandalone(bundledServer, port, shouldOpen, url2);
32671
33931
  return;
32672
33932
  }
32673
- const webUiDir = dirname7(require3.resolve("@akasecurity/web-ui/package.json"));
33933
+ const webUiDir = dirname8(require3.resolve("@akasecurity/web-ui/package.json"));
32674
33934
  const nextBin = require3.resolve("next/dist/bin/next", { paths: [webUiDir] });
32675
33935
  const startNext = () => {
32676
- const child = spawn3(
33936
+ const child = spawn4(
32677
33937
  process.execPath,
32678
33938
  [nextBin, "start", "--port", port, "--hostname", BIND_HOST],
32679
33939
  {
@@ -32684,12 +33944,12 @@ async function runDashboard(argv) {
32684
33944
  onReadyOpen(child, shouldOpen, url2, `Starting the AKA dashboard at ${url2}
32685
33945
  `);
32686
33946
  };
32687
- if (existsSync13(join19(webUiDir, ".next", "BUILD_ID"))) {
33947
+ if (existsSync14(join27(webUiDir, ".next", "BUILD_ID"))) {
32688
33948
  startNext();
32689
33949
  return;
32690
33950
  }
32691
33951
  process.stdout.write("Building the web-ui (first run \u2014 this can take a minute)\u2026\n");
32692
- const build = spawn3(process.execPath, [nextBin, "build"], { cwd: webUiDir, stdio: "inherit" });
33952
+ const build = spawn4(process.execPath, [nextBin, "build"], { cwd: webUiDir, stdio: "inherit" });
32693
33953
  build.on("exit", (code) => {
32694
33954
  if (code !== 0) {
32695
33955
  process.stderr.write("aka dashboard: web-ui build failed\n");
@@ -32706,8 +33966,8 @@ function launchStandalone(serverJs, port, shouldOpen, url2) {
32706
33966
  process.exitCode = 1;
32707
33967
  return;
32708
33968
  }
32709
- const child = spawn3(reinvoke.command, reinvoke.args, {
32710
- cwd: dirname7(serverJs),
33969
+ const child = spawn4(reinvoke.command, reinvoke.args, {
33970
+ cwd: dirname8(serverJs),
32711
33971
  stdio: ["inherit", "pipe", "inherit"],
32712
33972
  // Inherit the parent env so the child server sees PATH etc.; PORT/HOSTNAME tell
32713
33973
  // Next's standalone server where to bind (its only port input).
@@ -32946,131 +34206,6 @@ function formatTimestamp(iso) {
32946
34206
  return iso.slice(0, 16).replace("T", " ");
32947
34207
  }
32948
34208
 
32949
- // src/lib/prompter.ts
32950
- import { createInterface } from "readline";
32951
- function processHiddenChar(state, ch) {
32952
- if (state.done) return state;
32953
- if (state.esc === "esc") {
32954
- return ch === "[" || ch === "O" ? { ...state, esc: "seq" } : { ...state, esc: "none" };
32955
- }
32956
- if (state.esc === "seq") {
32957
- return ch >= "@" && ch <= "~" ? { ...state, esc: "none" } : state;
32958
- }
32959
- if (ch === "\r" || ch === "\n") return { ...state, done: "submit" };
32960
- if (ch === "") return { ...state, done: "cancel" };
32961
- if (ch === "\x7F" || ch === "\b") return { ...state, value: state.value.slice(0, -1) };
32962
- if (ch === "\x1B") return { ...state, esc: "esc" };
32963
- if (ch < " ") return state;
32964
- return { ...state, value: state.value + ch };
32965
- }
32966
- var CLEANUP_SIGNALS = ["SIGINT", "SIGTERM", "SIGHUP"];
32967
- function processIo() {
32968
- return {
32969
- input: process.stdin,
32970
- output: process.stdout,
32971
- errorOutput: process.stderr,
32972
- signals: {
32973
- once: (signal, handler) => {
32974
- process.once(signal, handler);
32975
- },
32976
- off: (signal, handler) => {
32977
- process.removeListener(signal, handler);
32978
- },
32979
- raise: (signal) => {
32980
- process.kill(process.pid, signal);
32981
- }
32982
- }
32983
- };
32984
- }
32985
- function terminalPrompter(io = processIo()) {
32986
- return {
32987
- out: (text) => {
32988
- io.output.write(text);
32989
- },
32990
- err: (text) => {
32991
- io.errorOutput.write(text);
32992
- },
32993
- isInteractive: io.input.isTTY && io.output.isTTY,
32994
- ask(question) {
32995
- return new Promise((resolve6) => {
32996
- const rl = createInterface({ input: io.input, output: io.output });
32997
- rl.question(question, (answer) => {
32998
- rl.close();
32999
- resolve6(answer);
33000
- });
33001
- });
33002
- },
33003
- // Raw mode so nothing is echoed; characters are folded through
33004
- // processHiddenChar. The captured value stays in this closure and is
33005
- // handed to the caller only — never written anywhere. TTY restoration is
33006
- // guaranteed via a one-shot `restore` that also runs on stdin errors and
33007
- // fatal signals: a security tool must never brick the terminal it was
33008
- // invoked from.
33009
- askHidden(question) {
33010
- return new Promise((resolve6, reject) => {
33011
- const stdin = io.input;
33012
- io.output.write(question);
33013
- stdin.setRawMode(true);
33014
- stdin.resume();
33015
- let state = { value: "", esc: "none" };
33016
- let restored = false;
33017
- const restore = () => {
33018
- if (restored) return;
33019
- restored = true;
33020
- stdin.removeListener("data", onData);
33021
- stdin.removeListener("error", onError);
33022
- for (const sig of CLEANUP_SIGNALS) io.signals.off(sig, onSignal);
33023
- try {
33024
- stdin.setRawMode(false);
33025
- } catch {
33026
- }
33027
- stdin.pause();
33028
- };
33029
- const finish = (err) => {
33030
- restore();
33031
- io.output.write("\n");
33032
- if (err) reject(err);
33033
- else resolve6(state.value);
33034
- };
33035
- const onError = (err) => {
33036
- finish(err);
33037
- };
33038
- const onSignal = (sig) => {
33039
- restore();
33040
- io.signals.raise(sig);
33041
- };
33042
- const onData = (chunk) => {
33043
- try {
33044
- for (const ch of chunk.toString("utf8")) {
33045
- state = processHiddenChar(state, ch);
33046
- if (state.done === "submit") {
33047
- finish();
33048
- return;
33049
- }
33050
- if (state.done === "cancel") {
33051
- finish(new Error("cancelled"));
33052
- return;
33053
- }
33054
- }
33055
- } catch (err) {
33056
- finish(err instanceof Error ? err : new Error(String(err)));
33057
- }
33058
- };
33059
- stdin.on("data", onData);
33060
- stdin.once("error", onError);
33061
- for (const sig of CLEANUP_SIGNALS) io.signals.once(sig, onSignal);
33062
- });
33063
- },
33064
- async readAllStdin() {
33065
- const chunks = [];
33066
- for await (const chunk of io.input) {
33067
- chunks.push(chunk);
33068
- }
33069
- return Buffer.concat(chunks).toString("utf8");
33070
- }
33071
- };
33072
- }
33073
-
33074
34209
  // src/commands/exception.ts
33075
34210
  var EXCEPTION_HELP = `Manage detection exceptions (explicit, audited bypasses).
33076
34211
 
@@ -33854,15 +34989,15 @@ async function runException(argv, io = terminalPrompter()) {
33854
34989
 
33855
34990
  // src/commands/extension.ts
33856
34991
  import { execFileSync as execFileSync3 } from "child_process";
33857
- import { existsSync as existsSync14, mkdirSync as mkdirSync4, readFileSync as readFileSync14, renameSync as renameSync5, writeFileSync as writeFileSync7 } from "fs";
34992
+ import { existsSync as existsSync15, mkdirSync as mkdirSync4, readFileSync as readFileSync18, renameSync as renameSync5, writeFileSync as writeFileSync7 } from "fs";
33858
34993
  import { createRequire as createRequire3 } from "module";
33859
34994
  import { homedir as homedir5 } from "os";
33860
- import { dirname as dirname8, join as join20 } from "path";
33861
- import { fileURLToPath as fileURLToPath4 } from "url";
34995
+ import { dirname as dirname9, join as join28 } from "path";
34996
+ import { fileURLToPath as fileURLToPath5 } from "url";
33862
34997
  var require4 = createRequire3(import.meta.url);
33863
- var here2 = dirname8(fileURLToPath4(import.meta.url));
34998
+ var here2 = dirname9(fileURLToPath5(import.meta.url));
33864
34999
  function cliRoot() {
33865
- return isSea() ? dirname8(process.execPath) : join20(here2, "..");
35000
+ return isSea() ? dirname9(process.execPath) : join28(here2, "..");
33866
35001
  }
33867
35002
  var EXTENSION_IDS = [
33868
35003
  // Derived from the "key" in plugins/browser-extension/manifest.json.
@@ -33879,30 +35014,30 @@ function nativeHostManifest(hostPath) {
33879
35014
  };
33880
35015
  }
33881
35016
  function resolveHostScript(root = cliRoot()) {
33882
- const bundled = join20(root, "native-host", "host.js");
33883
- if (existsSync14(bundled)) return bundled;
35017
+ const bundled = join28(root, "native-host", "host.js");
35018
+ if (existsSync15(bundled)) return bundled;
33884
35019
  try {
33885
35020
  const pkgJson = require4.resolve("@akasecurity/plugin-browser-extension/package.json");
33886
- const devBuilt = join20(dirname8(pkgJson), "native-host", "host.js");
33887
- if (existsSync14(devBuilt)) return devBuilt;
35021
+ const devBuilt = join28(dirname9(pkgJson), "native-host", "host.js");
35022
+ if (existsSync15(devBuilt)) return devBuilt;
33888
35023
  } catch {
33889
35024
  }
33890
35025
  return null;
33891
35026
  }
33892
35027
  function resolveExtensionDist(root = cliRoot()) {
33893
- const bundled = join20(root, "extension");
33894
- if (existsSync14(bundled)) return bundled;
35028
+ const bundled = join28(root, "extension");
35029
+ if (existsSync15(bundled)) return bundled;
33895
35030
  try {
33896
35031
  const pkgJson = require4.resolve("@akasecurity/plugin-browser-extension/package.json");
33897
- const devDist = join20(dirname8(pkgJson), "dist");
33898
- if (existsSync14(devDist)) return devDist;
35032
+ const devDist = join28(dirname9(pkgJson), "dist");
35033
+ if (existsSync15(devDist)) return devDist;
33899
35034
  } catch {
33900
35035
  }
33901
35036
  return null;
33902
35037
  }
33903
35038
  function chromeManifestDir(platform2 = process.platform) {
33904
35039
  if (platform2 === "darwin") {
33905
- return join20(
35040
+ return join28(
33906
35041
  homedir5(),
33907
35042
  "Library",
33908
35043
  "Application Support",
@@ -33912,9 +35047,9 @@ function chromeManifestDir(platform2 = process.platform) {
33912
35047
  );
33913
35048
  }
33914
35049
  if (platform2 === "win32") {
33915
- return join20(homedir5(), ".aka", "native-messaging");
35050
+ return join28(homedir5(), ".aka", "native-messaging");
33916
35051
  }
33917
- return join20(homedir5(), ".config", "google-chrome", "NativeMessagingHosts");
35052
+ return join28(homedir5(), ".config", "google-chrome", "NativeMessagingHosts");
33918
35053
  }
33919
35054
  function resolveNodeForLauncher() {
33920
35055
  if (!isSea()) return process.execPath;
@@ -33928,7 +35063,7 @@ function resolveNodeForLauncher() {
33928
35063
  }
33929
35064
  }
33930
35065
  function launcherPath(manifestDir, platform2) {
33931
- return join20(
35066
+ return join28(
33932
35067
  manifestDir,
33933
35068
  platform2 === "win32" ? `${NATIVE_HOST_NAME}.cmd` : `${NATIVE_HOST_NAME}.sh`
33934
35069
  );
@@ -33978,7 +35113,7 @@ function runExtension(argv) {
33978
35113
  return;
33979
35114
  }
33980
35115
  if (sub === "status") {
33981
- runStatus(chromeManifestDir());
35116
+ runStatus2(chromeManifestDir());
33982
35117
  return;
33983
35118
  }
33984
35119
  process.stderr.write(
@@ -34005,7 +35140,7 @@ function runInstall(manifestDir, hostScript = resolveHostScript(), extensionDist
34005
35140
  }
34006
35141
  mkdirSync4(manifestDir, { recursive: true });
34007
35142
  const launcher = writeLauncher(manifestDir, hostScript, nodePath, process.platform);
34008
- const manifestPath = join20(manifestDir, `${NATIVE_HOST_NAME}.json`);
35143
+ const manifestPath = join28(manifestDir, `${NATIVE_HOST_NAME}.json`);
34009
35144
  const tmp = `${manifestPath}.tmp`;
34010
35145
  writeFileSync7(tmp, `${JSON.stringify(nativeHostManifest(launcher), null, 2)}
34011
35146
  `, {
@@ -34040,21 +35175,21 @@ Next: load the extension in Chrome \u2014
34040
35175
  );
34041
35176
  }
34042
35177
  function manifestFault(manifestPath) {
34043
- let parsed;
35178
+ let parsed2;
34044
35179
  try {
34045
- parsed = JSON.parse(readFileSync14(manifestPath, "utf8"));
35180
+ parsed2 = JSON.parse(readFileSync18(manifestPath, "utf8"));
34046
35181
  } catch (err) {
34047
35182
  return `could not be read (${err instanceof Error ? err.message : String(err)})`;
34048
35183
  }
34049
- const granted = parsed?.allowed_origins;
35184
+ const granted = parsed2?.allowed_origins;
34050
35185
  if (!Array.isArray(granted)) return "has no allowed_origins list";
34051
35186
  const missing = EXTENSION_IDS.filter((id) => !granted.includes(`chrome-extension://${id}/`));
34052
35187
  if (missing.length === 0) return null;
34053
35188
  return `does not grant ${missing.length === 1 ? "the extension id" : "the extension ids"} ${missing.join(", ")}`;
34054
35189
  }
34055
- function runStatus(manifestDir) {
34056
- const manifestPath = join20(manifestDir, `${NATIVE_HOST_NAME}.json`);
34057
- if (!existsSync14(manifestPath)) {
35190
+ function runStatus2(manifestDir) {
35191
+ const manifestPath = join28(manifestDir, `${NATIVE_HOST_NAME}.json`);
35192
+ if (!existsSync15(manifestPath)) {
34058
35193
  process.stdout.write(
34059
35194
  `native-messaging host: not installed
34060
35195
  manifest: ${manifestPath}
@@ -34076,13 +35211,13 @@ function runStatus(manifestDir) {
34076
35211
  }
34077
35212
 
34078
35213
  // src/commands/init.ts
34079
- import { existsSync as existsSync16, lstatSync as lstatSync2, readdirSync as readdirSync7, readlinkSync, realpathSync as realpathSync4, statSync as statSync10 } from "fs";
34080
- import { dirname as dirname9, join as join21, resolve as resolve5 } from "path";
35214
+ import { existsSync as existsSync17, lstatSync as lstatSync4, readdirSync as readdirSync7, statSync as statSync13 } from "fs";
35215
+ import { join as join29 } from "path";
34081
35216
  import * as readline from "readline/promises";
34082
35217
  import { parseArgs as parseArgs6 } from "util";
34083
35218
 
34084
35219
  // src/commands/plugins.ts
34085
- import { existsSync as existsSync15 } from "fs";
35220
+ import { existsSync as existsSync16 } from "fs";
34086
35221
  import { parseArgs as parseArgs5 } from "util";
34087
35222
  function runPlugins(argv) {
34088
35223
  const [sub, ...rest] = argv;
@@ -34099,7 +35234,7 @@ async function listPlugins(argv) {
34099
35234
  const { values } = parseArgs5({ args: argv, options: HOME_OPTION });
34100
35235
  const home = homeBase(values.home);
34101
35236
  const active = /* @__PURE__ */ new Set();
34102
- if (existsSync15(dbPath(home))) {
35237
+ if (existsSync16(dbPath(home))) {
34103
35238
  const db = openLocalDatabase(dataDir(home));
34104
35239
  try {
34105
35240
  const recent = await db.findings.recentFindings({ limit: 1e3 });
@@ -34190,28 +35325,13 @@ Then run \`aka init\` to set up the local store.
34190
35325
 
34191
35326
  // src/commands/init.ts
34192
35327
  var PLUGIN_OFFER_IDENTITY = `${PRODUCT_NAME} \u2014 ${PRODUCT_TAGLINE}`;
34193
- var STORE_DB = "the store database (including the prompt corpus)";
34194
- var STORE_SETTINGS = "your settings file";
34195
- function storeContents(home) {
34196
- return /* @__PURE__ */ new Map([
34197
- [home, "the store (including the prompt corpus in aka.db)"],
34198
- [settingsDir(home), STORE_SETTINGS],
34199
- [dataDir(home), STORE_DB],
34200
- [keysDir(home), "the vault key"],
34201
- [join21(settingsDir(home), "settings.json"), STORE_SETTINGS],
34202
- [dbPath(home), STORE_DB]
34203
- ]);
34204
- }
34205
- function storeTargets(home) {
34206
- return [...storeContents(home).keys()];
34207
- }
34208
35328
  function storeModeTargets(home) {
34209
35329
  const targets = new Set(storeTargets(home));
34210
35330
  for (const dir of [dataDir(home), keysDir(home)]) {
34211
35331
  try {
34212
35332
  for (const entry of readdirSync7(dir, { withFileTypes: true })) {
34213
35333
  if (entry.name.endsWith(".partial") && !entry.isDirectory()) continue;
34214
- targets.add(join21(dir, entry.name));
35334
+ targets.add(join29(dir, entry.name));
34215
35335
  }
34216
35336
  } catch {
34217
35337
  }
@@ -34222,48 +35342,13 @@ function looseStorePaths(home) {
34222
35342
  if (process.platform === "win32") return [];
34223
35343
  return storeModeTargets(home).filter((p) => {
34224
35344
  try {
34225
- if (lstatSync2(p).isSymbolicLink()) return false;
34226
- return (statSync10(p).mode & 63) !== 0;
35345
+ if (lstatSync4(p).isSymbolicLink()) return false;
35346
+ return (statSync13(p).mode & 63) !== 0;
34227
35347
  } catch {
34228
35348
  return false;
34229
35349
  }
34230
35350
  });
34231
35351
  }
34232
- function symlinkedStorePaths(home, platform2 = process.platform) {
34233
- return [...storeContents(home)].flatMap(([path, holds]) => {
34234
- try {
34235
- if (!lstatSync2(path).isSymbolicLink()) return [];
34236
- return [
34237
- {
34238
- path,
34239
- target: linkTarget(path),
34240
- holds,
34241
- // existsSync follows the link, so a target that is gone reads as
34242
- // absent here while lstat above still sees the link itself.
34243
- missing: !existsSync16(path),
34244
- mode: targetMode(path, platform2)
34245
- }
34246
- ];
34247
- } catch {
34248
- return [];
34249
- }
34250
- });
34251
- }
34252
- function linkTarget(path) {
34253
- try {
34254
- return realpathSync4(path);
34255
- } catch {
34256
- return resolve5(dirname9(path), readlinkSync(path));
34257
- }
34258
- }
34259
- function targetMode(path, platform2) {
34260
- if (platform2 === "win32") return void 0;
34261
- try {
34262
- return statSync10(path).mode & 511;
34263
- } catch {
34264
- return void 0;
34265
- }
34266
- }
34267
35352
  function symlinkWarnings(paths, platform2 = process.platform) {
34268
35353
  const seeAlso = '(see the "Data at rest" note in SECURITY.md)';
34269
35354
  return paths.map(({ path, target, holds, missing, mode }) => {
@@ -34291,7 +35376,7 @@ function assertStoreLinksResolve(home) {
34291
35376
  }
34292
35377
  function isBrokenLink(path) {
34293
35378
  try {
34294
- return lstatSync2(path).isSymbolicLink() && !existsSync16(path);
35379
+ return lstatSync4(path).isSymbolicLink() && !existsSync17(path);
34295
35380
  } catch {
34296
35381
  return false;
34297
35382
  }
@@ -34305,14 +35390,14 @@ function assertStorePathsAreDirectories(home) {
34305
35390
  }
34306
35391
  function isSymlink2(path) {
34307
35392
  try {
34308
- return lstatSync2(path).isSymbolicLink();
35393
+ return lstatSync4(path).isSymbolicLink();
34309
35394
  } catch {
34310
35395
  return false;
34311
35396
  }
34312
35397
  }
34313
35398
  function existsAsNonDirectory(path) {
34314
35399
  try {
34315
- return !statSync10(path).isDirectory();
35400
+ return !statSync13(path).isDirectory();
34316
35401
  } catch {
34317
35402
  return false;
34318
35403
  }
@@ -34328,12 +35413,12 @@ async function runInit(argv) {
34328
35413
  ensureLayoutDirSync(home);
34329
35414
  const settings = settingsDir(home);
34330
35415
  ensureLayoutDirSync(settings);
34331
- const settingsFile = join21(settings, "settings.json");
35416
+ const settingsFile = join29(settings, "settings.json");
34332
35417
  let settingsCreated = false;
34333
- if (!existsSync16(settingsFile)) {
35418
+ if (!existsSync17(settingsFile)) {
34334
35419
  try {
34335
35420
  settingsCreated = withFileLock(settingsFile, () => {
34336
- if (existsSync16(settingsFile)) return false;
35421
+ if (existsSync17(settingsFile)) return false;
34337
35422
  writeOwnerOnlyFileSync(
34338
35423
  settingsFile,
34339
35424
  `${JSON.stringify(defaultWorkspaceSettings(), null, 2)}
@@ -34362,7 +35447,7 @@ async function runInit(argv) {
34362
35447
  const symlinked = symlinkedStorePaths(home);
34363
35448
  process.stdout.write(
34364
35449
  `\u2713 Initialized AKA at ${home}
34365
- settings: ${settingsFile}${settingsCreated ? "" : existsSync16(settingsFile) ? " (kept existing)" : " (not written \u2014 another process was writing it)"}
35450
+ settings: ${settingsFile}${settingsCreated ? "" : existsSync17(settingsFile) ? " (kept existing)" : " (not written \u2014 another process was writing it)"}
34366
35451
  database: ${dbPath(home)}
34367
35452
  seeded ${String(policyCount)} default policies, ${String(packCount)} detection pack(s)
34368
35453
  ` + (updatesAvailable > 0 ? ` \u2B06 ${String(updatesAvailable)} detection pack update(s) available \u2014 review with \`aka detections\`, apply with \`aka detections update --all\`
@@ -34412,7 +35497,7 @@ async function confirm(question) {
34412
35497
  }
34413
35498
 
34414
35499
  // src/commands/scan.ts
34415
- import { statSync as statSync11 } from "fs";
35500
+ import { statSync as statSync14 } from "fs";
34416
35501
  import { parseArgs as parseArgs7 } from "util";
34417
35502
  function severityRank(s) {
34418
35503
  return Severity.options.indexOf(s);
@@ -34447,8 +35532,8 @@ async function runScan(argv) {
34447
35532
  }
34448
35533
  let failOn;
34449
35534
  if (values["fail-on"] !== void 0) {
34450
- const parsed = Severity.safeParse(values["fail-on"]);
34451
- if (!parsed.success) {
35535
+ const parsed2 = Severity.safeParse(values["fail-on"]);
35536
+ if (!parsed2.success) {
34452
35537
  process.stderr.write(
34453
35538
  `aka scan: invalid --fail-on '${values["fail-on"]}' (expected ${Severity.options.join(", ")})
34454
35539
  `
@@ -34456,10 +35541,10 @@ async function runScan(argv) {
34456
35541
  process.exitCode = 1;
34457
35542
  return;
34458
35543
  }
34459
- failOn = parsed.data;
35544
+ failOn = parsed2.data;
34460
35545
  }
34461
35546
  try {
34462
- statSync11(target);
35547
+ statSync14(target);
34463
35548
  } catch {
34464
35549
  process.stderr.write(`aka scan: no such file or directory: ${target}
34465
35550
  `);
@@ -35266,10 +36351,10 @@ import { parseArgs as parseArgs10 } from "util";
35266
36351
 
35267
36352
  // src/lib/install-origin.ts
35268
36353
  import { dirname as dirname10 } from "path";
35269
- import { fileURLToPath as fileURLToPath5 } from "url";
36354
+ import { fileURLToPath as fileURLToPath6 } from "url";
35270
36355
  function cliInstallOrigin() {
35271
36356
  try {
35272
- return { moduleDir: dirname10(fileURLToPath5(import.meta.url)) };
36357
+ return { moduleDir: dirname10(fileURLToPath6(import.meta.url)) };
35273
36358
  } catch {
35274
36359
  return { moduleDir: void 0 };
35275
36360
  }
@@ -35445,8 +36530,8 @@ async function runShow2(argv, io) {
35445
36530
  if (candidate === void 0 || candidate === "") {
35446
36531
  throw new Error(`usage: aka vault show '[[aka:...]]'`);
35447
36532
  }
35448
- const parsed = PointerToken.safeParse(candidate);
35449
- if (!parsed.success) {
36533
+ const parsed2 = PointerToken.safeParse(candidate);
36534
+ if (!parsed2.success) {
35450
36535
  throw new Error(
35451
36536
  "that is not a vault pointer \u2014 expected the full [[aka:...]] token (quote it in the shell)"
35452
36537
  );
@@ -35461,7 +36546,7 @@ async function runShow2(argv, io) {
35461
36546
  // Read live so a consent revocation applies to the very next call.
35462
36547
  isConsented: () => isVaultConsentValid(readWorkspaceSettings(base).vaultConsent)
35463
36548
  });
35464
- const value = await vault.detokenize(parsed.data, {
36549
+ const value = await vault.detokenize(parsed2.data, {
35465
36550
  target: "human",
35466
36551
  reason: "explicit-reveal"
35467
36552
  });
@@ -35470,7 +36555,7 @@ async function runShow2(argv, io) {
35470
36555
  }
35471
36556
  io.out(`${value}
35472
36557
  `);
35473
- const descriptor = await vault.describePointer(parsed.data);
36558
+ const descriptor = await vault.describePointer(parsed2.data);
35474
36559
  if (descriptor) io.out(`${descriptorLine(descriptor)}
35475
36560
  `);
35476
36561
  } finally {
@@ -35517,12 +36602,12 @@ function signalExitCode(signal) {
35517
36602
  return number4 === void 0 ? 1 : 128 + number4;
35518
36603
  }
35519
36604
  function dispatchExternal(command, argv, deps = {}) {
35520
- const spawn4 = deps.spawn ?? spawnSync2;
36605
+ const spawn5 = deps.spawn ?? spawnSync2;
35521
36606
  const platform2 = deps.platform ?? process.platform;
35522
36607
  const exists = deps.exists ?? commandOnPath;
35523
36608
  if (!externalDispatchSupported(platform2)) return { found: false, status: 1 };
35524
36609
  const target = `aka-${command}`;
35525
- const result = spawn4(target, argv, { stdio: "inherit" });
36610
+ const result = spawn5(target, argv, { stdio: "inherit" });
35526
36611
  if (result.error) {
35527
36612
  if (result.error.code === "ENOENT" && !exists(target)) return { found: false, status: 1 };
35528
36613
  process.stderr.write(`aka: ${target}: ${result.error.message}
@@ -35548,6 +36633,11 @@ var COMMANDS = {
35548
36633
  extension: runExtension,
35549
36634
  exception: (argv) => runException(argv),
35550
36635
  vault: (argv) => runVault(argv),
36636
+ attach: (argv) => runAttach(argv),
36637
+ detach: (argv) => {
36638
+ runDetach(argv);
36639
+ },
36640
+ status: (argv) => runStatus(argv),
35551
36641
  tui: runTui,
35552
36642
  update: runUpdate,
35553
36643
  "check-updates": runCheckUpdates,
@@ -35570,7 +36660,7 @@ var SKIP_NOTICE = /* @__PURE__ */ new Set([
35570
36660
  "__dashboard-server",
35571
36661
  "completion"
35572
36662
  ]);
35573
- var USAGE = `aka \u2014 AI Traffic Control (local-first, everything stays on your machine)
36663
+ var USAGE2 = `aka \u2014 AI Traffic Control (local-first; see the egress footnote in the README)
35574
36664
 
35575
36665
  Usage: aka <command> [options]
35576
36666
 
@@ -35602,7 +36692,7 @@ async function main(argv = process.argv.slice(2), dispatchDeps = {}) {
35602
36692
  }
35603
36693
  const [command, ...rawRest] = argv;
35604
36694
  if (!command || command === "-h" || command === "--help") {
35605
- process.stdout.write(USAGE);
36695
+ process.stdout.write(USAGE2);
35606
36696
  return;
35607
36697
  }
35608
36698
  const noUpdateCheck = rawRest.includes("--no-update-check");
@@ -35618,7 +36708,7 @@ async function main(argv = process.argv.slice(2), dispatchDeps = {}) {
35618
36708
  if (!handler) {
35619
36709
  process.stderr.write(`aka: unknown command '${command}'
35620
36710
 
35621
- ${USAGE}`);
36711
+ ${USAGE2}`);
35622
36712
  process.exitCode = 1;
35623
36713
  return;
35624
36714
  }