failproofai 1.0.0-beta.16 → 1.0.0-beta.18

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 (119) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/build-manifest.json +5 -5
  3. package/.next/standalone/.next/prerender-manifest.json +3 -3
  4. package/.next/standalone/.next/required-server-files.json +1 -1
  5. package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +2 -2
  6. package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
  7. package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
  8. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
  11. package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
  12. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
  13. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
  14. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
  15. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  16. package/.next/standalone/.next/server/app/_not-found/page/build-manifest.json +2 -2
  17. package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  18. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  19. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  20. package/.next/standalone/.next/server/app/_not-found.html +1 -1
  21. package/.next/standalone/.next/server/app/_not-found.rsc +14 -14
  22. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
  23. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
  24. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +9 -9
  25. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
  26. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
  27. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  28. package/.next/standalone/.next/server/app/audit/page/build-manifest.json +2 -2
  29. package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
  30. package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
  31. package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
  32. package/.next/standalone/.next/server/app/index.html +1 -1
  33. package/.next/standalone/.next/server/app/index.rsc +14 -14
  34. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  35. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +14 -14
  36. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
  37. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +9 -9
  38. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  39. package/.next/standalone/.next/server/app/page/build-manifest.json +2 -2
  40. package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
  41. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  42. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  43. package/.next/standalone/.next/server/app/policies/page/build-manifest.json +2 -2
  44. package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +10 -10
  45. package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
  46. package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
  47. package/.next/standalone/.next/server/app/project/[name]/page/build-manifest.json +2 -2
  48. package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
  49. package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
  50. package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
  51. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/build-manifest.json +2 -2
  52. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
  53. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
  54. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
  55. package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
  56. package/.next/standalone/.next/server/app/projects/page/build-manifest.json +2 -2
  57. package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
  58. package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
  59. package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
  60. package/.next/standalone/.next/server/app/settings/page/build-manifest.json +2 -2
  61. package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +4 -4
  62. package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
  63. package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  64. package/.next/standalone/.next/server/chunks/[root-of-the-server]__06hexd0._.js +1 -1
  65. package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +1 -1
  66. package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +1 -1
  67. package/.next/standalone/.next/server/chunks/node_modules_posthog-node_dist_entrypoints_index_node_mjs_01r25oi._.js +1 -1
  68. package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
  69. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0spkm68._.js +2 -2
  70. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__17itmx-._.js +1 -1
  71. package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__0no2gzh._.js → [root-of-the-server]__1a-my61._.js} +2 -2
  72. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1rv-sc9._.js +1 -1
  73. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1u-wx42._.js +2 -2
  74. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1vwv3db._.js +3 -0
  75. package/.next/standalone/.next/server/chunks/ssr/_0rjgfln._.js +1 -1
  76. package/.next/standalone/.next/server/chunks/ssr/_0vo2qyt._.js +1 -1
  77. package/.next/standalone/.next/server/chunks/ssr/_0xej-0e._.js +1 -1
  78. package/.next/standalone/.next/server/chunks/ssr/_10399ge._.js +1 -1
  79. package/.next/standalone/.next/server/chunks/ssr/_149k9oy._.js +1 -1
  80. package/.next/standalone/.next/server/chunks/ssr/_1_hwp06._.js +1 -1
  81. package/.next/standalone/.next/server/chunks/ssr/{_09tcu2b._.js → _1ifzifk._.js} +1 -1
  82. package/.next/standalone/.next/server/chunks/ssr/_1mnhi_r._.js +1 -1
  83. package/.next/standalone/.next/server/chunks/ssr/_1ror7k9._.js +1 -1
  84. package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +1 -1
  85. package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
  86. package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
  87. package/.next/standalone/.next/server/middleware-build-manifest.js +5 -5
  88. package/.next/standalone/.next/server/pages/404.html +1 -1
  89. package/.next/standalone/.next/server/pages/500.html +1 -1
  90. package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
  91. package/.next/standalone/.next/server/server-reference-manifest.json +15 -15
  92. package/.next/standalone/.next/static/chunks/{1_as8528fwqxf.js → 0rsx_d5zvy-dc.js} +1 -1
  93. package/.next/standalone/.next/static/chunks/{0fx3tgb_n0vz5.js → 16_af09907p72.js} +1 -1
  94. package/.next/standalone/.next/static/chunks/{2okcei5v0-xrx.js → 27nyktroru6xd.js} +1 -1
  95. package/.next/standalone/.next/static/chunks/{16yzosmvpinbh.js → 2_g_ltvh3jcgh.js} +1 -1
  96. package/.next/standalone/.next/static/chunks/{3xp43uu8jj8t4.js → 2cgpelmb2zoh-.js} +1 -1
  97. package/.next/standalone/.next/static/chunks/{2f2h7g8sm0bhr.js → 2kjsoq1g8t4qc.js} +1 -1
  98. package/.next/standalone/.next/static/chunks/{1nsy22eg5q-pi.js → 2q5ygkgs9l1gk.js} +1 -1
  99. package/.next/standalone/.next/static/chunks/{2n6wkcj5q_0yd.js → 2toc5dmy7efqk.js} +1 -1
  100. package/.next/standalone/.next/static/chunks/{2rl5gq4xl8oa2.js → 31fmsp1soxi07.js} +1 -1
  101. package/.next/standalone/.next/static/chunks/{43kqvfa-2jq0g.js → 3wq4n27ea5hkm.js} +1 -1
  102. package/.next/standalone/.next/static/chunks/{3vsiw3ayz3c7_.js → 3yxozwzbd09eg.js} +1 -1
  103. package/.next/standalone/.next/static/chunks/{turbopack-0ud32mdjjcn6y.js → turbopack-3diub4ctvn1n0.js} +1 -1
  104. package/.next/standalone/package.json +9 -9
  105. package/.next/standalone/server.js +1 -1
  106. package/dist/cli.mjs +175 -142
  107. package/dist/worker.mjs +1 -1
  108. package/package.json +9 -9
  109. package/src/hooks/configure-wizard.ts +34 -1
  110. package/src/hooks/daemon-service.ts +89 -62
  111. package/src/hooks/fp-reset.ts +16 -0
  112. package/src/hooks/harness-cli.ts +88 -11
  113. package/src/hooks/hook-activity-store.ts +29 -1
  114. package/src/hooks/migrations.ts +40 -15
  115. package/src/hooks/tui.ts +28 -0
  116. package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0hxmox-._.js +0 -3
  117. /package/.next/standalone/.next/static/{kSTfP_Tzl760gYDnYr-JC → d2alqN0WTpN7MpYISLm81}/_buildManifest.js +0 -0
  118. /package/.next/standalone/.next/static/{kSTfP_Tzl760gYDnYr-JC → d2alqN0WTpN7MpYISLm81}/_clientMiddlewareManifest.js +0 -0
  119. /package/.next/standalone/.next/static/{kSTfP_Tzl760gYDnYr-JC → d2alqN0WTpN7MpYISLm81}/_ssgManifest.js +0 -0
package/dist/cli.mjs CHANGED
@@ -19,7 +19,7 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
19
19
  var __require = /* @__PURE__ */ createRequire(import.meta.url);
20
20
 
21
21
  // package.json
22
- var version2 = "1.0.0-beta.16", package_default;
22
+ var version2 = "1.0.0-beta.18", package_default;
23
23
  var init_package = __esm(() => {
24
24
  package_default = {
25
25
  name: "failproofai",
@@ -135,16 +135,16 @@ var init_package = __esm(() => {
135
135
  sharp: "0.35.0"
136
136
  },
137
137
  optionalDependencies: {
138
- "@failproofai/failproofaid-linux-x64": "1.0.0-beta.16",
139
- "@failproofai/failproofaid-linux-arm64": "1.0.0-beta.16",
140
- "@failproofai/failproofaid-darwin-x64": "1.0.0-beta.16",
141
- "@failproofai/failproofaid-darwin-arm64": "1.0.0-beta.16"
138
+ "@failproofai/failproofaid-linux-x64": "1.0.0-beta.18",
139
+ "@failproofai/failproofaid-linux-arm64": "1.0.0-beta.18",
140
+ "@failproofai/failproofaid-darwin-x64": "1.0.0-beta.18",
141
+ "@failproofai/failproofaid-darwin-arm64": "1.0.0-beta.18"
142
142
  },
143
143
  failproofaidBinaries: {
144
- "linux-x64": "b82471309d2e52724781d8074bae55444892030eb1b48305ef74053bb7938931",
145
- "linux-arm64": "5a0bdc9f726844e7ed109c896bb894e84a51c7592fe4aed26eceea78c97fde04",
146
- "darwin-x64": "08881822befb31fe13974d2861fc50b6b2c1c72741986656e8f9087586202d88",
147
- "darwin-arm64": "cc85096de72f3e5813145b7c906ea6a2d4788f39f4dae6a86532d88107802cab"
144
+ "linux-x64": "54bf7cc41ee8b5a2ea9430459c1fe9b8b03ece25c18d8bee49441feee93c7057",
145
+ "linux-arm64": "1f5e7c4be2d9c591cf4fd39e5fc122e71f507115cdb2ad1a27c5f30f22a30028",
146
+ "darwin-x64": "ae510969144aaec5e8891cfa5cdf7374c5efbd7554547046efa5913aab5c3ab2",
147
+ "darwin-arm64": "bc8d96e295aa9a68590be6e12d4bf3711749a31371206e63ccc36dd42b275e18"
148
148
  }
149
149
  };
150
150
  });
@@ -5060,6 +5060,16 @@ function getAllHookActivityEntries() {
5060
5060
  }
5061
5061
  return [...currentEntries, ...archiveEntries];
5062
5062
  }
5063
+ function withRenamedCloudFields(raw) {
5064
+ const entry = raw;
5065
+ if (entry.cloudVersion === undefined && typeof raw.cloudRevision === "number") {
5066
+ entry.cloudVersion = raw.cloudRevision;
5067
+ }
5068
+ if (entry.cloudDeployment === undefined && typeof raw.cloudGeneration === "number") {
5069
+ entry.cloudDeployment = raw.cloudGeneration;
5070
+ }
5071
+ return entry;
5072
+ }
5063
5073
  function readJsonlFile(filePath) {
5064
5074
  const content = readFileSafe(filePath);
5065
5075
  if (!content.trim())
@@ -5068,7 +5078,7 @@ function readJsonlFile(filePath) {
5068
5078
  for (const line of content.trim().split(`
5069
5079
  `)) {
5070
5080
  try {
5071
- entries.push(JSON.parse(line));
5081
+ entries.push(withRenamedCloudFields(JSON.parse(line)));
5072
5082
  } catch {}
5073
5083
  }
5074
5084
  return entries;
@@ -11010,6 +11020,9 @@ function migrateConventionPolicies() {
11010
11020
  }
11011
11021
  if (entry.isDirectory() && statSync15(target).isDirectory()) {
11012
11022
  mergeInto(source, target, `${name}/`);
11023
+ try {
11024
+ rmdirSync(source);
11025
+ } catch {}
11013
11026
  }
11014
11027
  }
11015
11028
  };
@@ -11876,6 +11889,15 @@ function appendLedger(entry) {
11876
11889
  `, "utf8");
11877
11890
  } catch {}
11878
11891
  }
11892
+ function filesToBackUp() {
11893
+ const seen = new Set;
11894
+ for (const at2 of [...BACKED_UP, ...BACKED_UP_LEGACY]) {
11895
+ const path3 = at2();
11896
+ if (existsSync20(path3))
11897
+ seen.add(path3);
11898
+ }
11899
+ return [...seen];
11900
+ }
11879
11901
  function backupBeforeMigrating(from) {
11880
11902
  const dir = migrationBackupDir(from);
11881
11903
  const saved = [];
@@ -11885,14 +11907,7 @@ function backupBeforeMigrating(from) {
11885
11907
  } catch {
11886
11908
  return [];
11887
11909
  }
11888
- const seen = new Set;
11889
- for (const at2 of [...BACKED_UP, ...BACKED_UP_LEGACY]) {
11890
- const source = at2();
11891
- if (seen.has(source))
11892
- continue;
11893
- seen.add(source);
11894
- if (!existsSync20(source))
11895
- continue;
11910
+ for (const source of filesToBackUp()) {
11896
11911
  try {
11897
11912
  copyFileSync2(source, resolve16(dir, basename4(source)));
11898
11913
  saved.push(basename4(source));
@@ -11967,7 +11982,7 @@ function describePlan(from) {
11967
11982
  ...chain.map((m) => ` ${m.from} → ${m.to} ${m.describe}`),
11968
11983
  ``,
11969
11984
  `These would be copied to ${migrationBackupDir(from)} first:`,
11970
- ...[...BACKED_UP, ...BACKED_UP_LEGACY].map((at2) => at2()).filter((p) => existsSync20(p)).map((p) => ` ${basename4(p)}`),
11985
+ ...filesToBackUp().map((p) => ` ${basename4(p)}`),
11971
11986
  ``,
11972
11987
  `Settings, cloud enrolment, policy selection, your own policy files, decision`,
11973
11988
  `history and undelivered events are carried, not removed — see \`HOME_CLASSES\`.`
@@ -12011,7 +12026,13 @@ var init_migrations = __esm(() => {
12011
12026
  }
12012
12027
  ];
12013
12028
  BACKED_UP = [configFile, credentialsFile, globalPolicyConfigFile, versionFile];
12014
- BACKED_UP_LEGACY = [legacy.configToml, legacy.credentialsToml, legacy.policyConfig];
12029
+ BACKED_UP_LEGACY = [
12030
+ legacy.configToml,
12031
+ legacy.credentialsToml,
12032
+ legacy.policyConfig,
12033
+ legacy.cloudCredentials,
12034
+ legacy.ingestCredentials
12035
+ ];
12015
12036
  });
12016
12037
 
12017
12038
  // src/hooks/fp-reset.ts
@@ -12076,6 +12097,9 @@ function migrateConventionPolicies2() {
12076
12097
  }
12077
12098
  if (entry.isDirectory() && statSync16(target).isDirectory()) {
12078
12099
  mergeInto(source, target, `${name}/`);
12100
+ try {
12101
+ rmdirSync2(source);
12102
+ } catch {}
12079
12103
  }
12080
12104
  }
12081
12105
  };
@@ -13009,6 +13033,7 @@ function runPrompt(p) {
13009
13033
  if (key.ctrl && (key.name === "c" || key.name === "d") || key.name === "escape") {
13010
13034
  finish(null);
13011
13035
  } else if (key.name === "left" && p.allowBack) {
13036
+ p.onBack?.();
13012
13037
  finish(BACK);
13013
13038
  } else if (key.name === "up") {
13014
13039
  cursor = cursor > 0 ? cursor - 1 : choices.length - 1;
@@ -13089,6 +13114,7 @@ function multiSelect(opts) {
13089
13114
  },
13090
13115
  warnLine: () => warn ? c.warn(`Select at least ${minSelected}.`) : null,
13091
13116
  allowBack: opts.allowBack,
13117
+ onBack: opts.onBack ? () => opts.onBack?.(choices.filter((_, i) => checked[i]).map((ch) => ch.value)) : undefined,
13092
13118
  footer: opts.hint ?? (opts.allowBack ? "↑/↓ move · space select · ctrl+a all · ← back · enter confirm" : "↑/↓ move · space select · ctrl+a all · enter confirm"),
13093
13119
  onKey: (key, cursor) => {
13094
13120
  if (key.name === "space") {
@@ -26263,6 +26289,7 @@ refreshed. Re-run \`failproofai config\` once you can use sudo.
26263
26289
  const hasCustomFiles = describeCustomPolicies(cwd).fileCount > 0;
26264
26290
  let presets = null;
26265
26291
  let clisSel = null;
26292
+ const carried = { clis: null };
26266
26293
  while (clisSel === null) {
26267
26294
  const priorPresets = presets;
26268
26295
  presets = await multiSelect({
@@ -26275,7 +26302,7 @@ refreshed. Re-run \`failproofai config\` once you can use sudo.
26275
26302
  });
26276
26303
  if (presets === null)
26277
26304
  return cancel();
26278
- const priorClis = clisSel;
26305
+ const priorClis = carried.clis;
26279
26306
  const picked = await multiSelect({
26280
26307
  message: "Which harnesses should it protect?",
26281
26308
  choices: [
@@ -26291,6 +26318,9 @@ refreshed. Re-run \`failproofai config\` once you can use sudo.
26291
26318
  summaryNoun: "harnesses",
26292
26319
  hint: "detected CLIs are pre-selected · space toggles · ctrl+a all · ← back · ↵ confirm",
26293
26320
  allowBack: true,
26321
+ onBack: (checkedNow) => {
26322
+ carried.clis = checkedNow;
26323
+ },
26294
26324
  stdin,
26295
26325
  stdout
26296
26326
  });
@@ -26886,6 +26916,8 @@ __export(exports_harness_cli, {
26886
26916
  addPath: () => addPath,
26887
26917
  HARNESS_KEYS: () => HARNESS_KEYS
26888
26918
  });
26919
+ import { homedir as homedir27 } from "node:os";
26920
+ import { resolve as resolve26 } from "node:path";
26889
26921
  function unknownHarness(name) {
26890
26922
  return fail([
26891
26923
  `Unknown harness: ${name}`,
@@ -26924,6 +26956,22 @@ function writePaths(harness, paths) {
26924
26956
  }
26925
26957
  });
26926
26958
  }
26959
+ function comparableLabel(raw) {
26960
+ return raw.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
26961
+ }
26962
+ function comparablePath(raw) {
26963
+ const home = homedir27();
26964
+ const expanded = raw === "~" ? home : raw.startsWith("~/") ? resolve26(home, raw.slice(2)) : raw;
26965
+ return expanded.replace(/\/+$/, "");
26966
+ }
26967
+ function effectiveLabel(entry) {
26968
+ const given = labelOf(entry);
26969
+ if (given)
26970
+ return comparableLabel(given);
26971
+ const path3 = comparablePath(pathOf(entry));
26972
+ const base = path3.split("/").filter(Boolean).pop() ?? "";
26973
+ return comparableLabel(base.replace(/^\.+/, ""));
26974
+ }
26927
26975
  function addPath(harness, entry) {
26928
26976
  if (!HARNESS_KEYS.includes(harness))
26929
26977
  return unknownHarness(harness);
@@ -26937,7 +26985,7 @@ function addPath(harness, entry) {
26937
26985
  if (existing.includes(trimmed)) {
26938
26986
  return ok([`${harness}: ${trimmed} is already configured.`]);
26939
26987
  }
26940
- const samePath = existing.find((e) => pathOf(e) === pathOf(trimmed));
26988
+ const samePath = existing.find((e) => comparablePath(pathOf(e)) === comparablePath(pathOf(trimmed)));
26941
26989
  if (samePath) {
26942
26990
  return fail([
26943
26991
  `${harness} already captures ${pathOf(trimmed)} as ${JSON.stringify(samePath)}.`,
@@ -26947,21 +26995,28 @@ function addPath(harness, entry) {
26947
26995
  ]);
26948
26996
  }
26949
26997
  const wanted = labelOf(trimmed);
26950
- if (wanted) {
26951
- const sameLabel = existing.find((e) => labelOf(e) === wanted);
26952
- if (sameLabel) {
26953
- return fail([
26954
- `${harness} already uses the label ${JSON.stringify(wanted)} for ${pathOf(sameLabel)}.`,
26955
- "",
26956
- "Labels namespace agent ids, so two paths cannot share one."
26957
- ]);
26958
- }
26998
+ const effective = effectiveLabel(trimmed);
26999
+ const sameLabel = effective ? existing.find((e) => effectiveLabel(e) === effective) : undefined;
27000
+ if (sameLabel) {
27001
+ return fail([
27002
+ `${harness} already uses the label ${JSON.stringify(effective)} for ${pathOf(sameLabel)}.`,
27003
+ "",
27004
+ "Labels namespace agent ids, so two paths cannot share one — and the daemon",
27005
+ "lowercases them and collapses punctuation to `-`, so labels that differ only",
27006
+ "in case or spacing collide. An unlabelled path takes its folder name.",
27007
+ "",
27008
+ "Give this one an explicit label:",
27009
+ ` failproofai harness add-path ${harness} <label>=${pathOf(trimmed)}`
27010
+ ]);
26959
27011
  }
26960
27012
  writePaths(harness, [...existing, trimmed]);
26961
27013
  return ok([
26962
- `${harness}: now also capturing ${pathOf(trimmed)}`,
27014
+ `${harness}: configured to also capture ${pathOf(trimmed)}`,
26963
27015
  wanted ? ` agent ids will be namespaced ${wanted}-*` : " a label will be derived from the folder name; `failproofai harness list` shows it",
26964
27016
  ` written to ${configFile()}`,
27017
+ "",
27018
+ " The daemon validates it on the next read and reports what it rejected —",
27019
+ " `failproofai harness list` shows what is actually being captured.",
26965
27020
  ...TAKES_EFFECT_HINT
26966
27021
  ]);
26967
27022
  }
@@ -27484,12 +27539,12 @@ __export(exports_fp_home, {
27484
27539
  LAYOUT_VERSION: () => LAYOUT_VERSION2,
27485
27540
  HOME_CLASSES: () => HOME_CLASSES2
27486
27541
  });
27487
- import { homedir as homedir27 } from "node:os";
27488
- import { resolve as resolve26 } from "node:path";
27542
+ import { homedir as homedir28 } from "node:os";
27543
+ import { resolve as resolve27 } from "node:path";
27489
27544
  function failproofaiHome2(home) {
27490
27545
  if (home)
27491
- return resolve26(home, ".failproofai");
27492
- return process.env.FAILPROOFAI_HOME || resolve26(homedir27(), ".failproofai");
27546
+ return resolve27(home, ".failproofai");
27547
+ return process.env.FAILPROOFAI_HOME || resolve27(homedir28(), ".failproofai");
27493
27548
  }
27494
27549
  function resettablePaths2() {
27495
27550
  return [
@@ -27517,7 +27572,7 @@ function retiredLayoutPaths2() {
27517
27572
  legacy2.localPoliciesDir()
27518
27573
  ];
27519
27574
  }
27520
- var LAYOUT_VERSION2 = 3, at2 = (...parts) => resolve26(failproofaiHome2(), ...parts), atHome2 = (home, ...parts) => home ? resolve26(failproofaiHome2(home), ...parts) : at2(...parts), versionFile2 = (home) => atHome2(home, "VERSION"), configFile2 = (home) => atHome2(home, "config.json"), credentialsFile2 = (home) => atHome2(home, "credentials.json"), binDir2 = (home) => atHome2(home, "bin"), daemonBinary = (version3, home) => resolve26(binDir2(home), `failproofaid-${version3}`), policiesDir2 = (home) => atHome2(home, "policies"), customPoliciesDir2, globalPolicyConfigFile2 = (home) => atHome2(home, "policies-config.json"), cloudPoliciesDir2 = (home) => resolve26(policiesDir2(home), "cloud-policies"), cursorsDir2 = (source, home) => source ? resolve26(atHome2(home, "cursors"), source) : atHome2(home, "cursors"), customAgentsDir2 = (home) => atHome2(home, "custom-agents"), customAgentsEventsDir = (home) => resolve26(customAgentsDir2(home), "events"), customAgentsFailedDir = (home) => resolve26(customAgentsDir2(home), "failed"), auditDir2 = (home) => atHome2(home, "audit"), auditDashboardFile2 = (home) => resolve26(auditDir2(home), "dashboard.json"), auditCacheDir2 = (home) => resolve26(auditDir2(home), "cache"), hookActivityDir2 = (home) => atHome2(home, "hook-activity"), runDir2 = (home) => atHome2(home, "run"), daemonSocket2 = () => process.env.FAILPROOFAI_DAEMON_SOCKET || resolve26(runDir2(), "failproofaid.sock"), workerSocket = (home) => resolve26(runDir2(home), "worker.sock"), daemonLock = (home) => resolve26(runDir2(home), "failproofaid.lock"), auditLockFile2 = (home) => resolve26(runDir2(home), "audit.lock"), stateDir2 = (home) => atHome2(home, "state"), shimsDir2 = (home) => resolve26(stateDir2(home), "shims"), spoolDir2 = (home) => resolve26(stateDir2(home), "spool"), failedDir2 = (home) => resolve26(stateDir2(home), "failed"), collectorHealthFile2 = (home) => resolve26(stateDir2(home), "collector-health.json"), sessionPauseDir2 = () => resolve26(stateDir2(), "sessions"), auditScheduleFile2 = (home) => resolve26(stateDir2(home), "audit-schedule.json"), telemetryIdFile2 = (home) => resolve26(stateDir2(home), "telemetry-id"), launcherMarker2 = (home) => resolve26(stateDir2(home), "launcher-configured"), onboardingAttemptFile2 = (home) => resolve26(stateDir2(home), "onboarding-attempt.json"), lastVersionFile2 = (home) => resolve26(stateDir2(home), "last-version"), onboardingLockFile2 = (home) => resolve26(stateDir2(home), "onboarding.lock"), codexSessionPathsFile2 = (home) => resolve26(stateDir2(home), "codex-session-paths.json"), logsDir2 = (home) => atHome2(home, "logs"), migrationsDir2 = (home) => atHome2(home, "migrations"), migrationLedgerFile2 = (home) => resolve26(migrationsDir2(home), "applied.json"), migrationBackupDir2 = (layout, home) => resolve26(migrationsDir2(home), `backup-layout${layout}`), HOME_CLASSES2, legacy2;
27575
+ var LAYOUT_VERSION2 = 3, at2 = (...parts) => resolve27(failproofaiHome2(), ...parts), atHome2 = (home, ...parts) => home ? resolve27(failproofaiHome2(home), ...parts) : at2(...parts), versionFile2 = (home) => atHome2(home, "VERSION"), configFile2 = (home) => atHome2(home, "config.json"), credentialsFile2 = (home) => atHome2(home, "credentials.json"), binDir2 = (home) => atHome2(home, "bin"), daemonBinary = (version3, home) => resolve27(binDir2(home), `failproofaid-${version3}`), policiesDir2 = (home) => atHome2(home, "policies"), customPoliciesDir2, globalPolicyConfigFile2 = (home) => atHome2(home, "policies-config.json"), cloudPoliciesDir2 = (home) => resolve27(policiesDir2(home), "cloud-policies"), cursorsDir2 = (source, home) => source ? resolve27(atHome2(home, "cursors"), source) : atHome2(home, "cursors"), customAgentsDir2 = (home) => atHome2(home, "custom-agents"), customAgentsEventsDir = (home) => resolve27(customAgentsDir2(home), "events"), customAgentsFailedDir = (home) => resolve27(customAgentsDir2(home), "failed"), auditDir2 = (home) => atHome2(home, "audit"), auditDashboardFile2 = (home) => resolve27(auditDir2(home), "dashboard.json"), auditCacheDir2 = (home) => resolve27(auditDir2(home), "cache"), hookActivityDir2 = (home) => atHome2(home, "hook-activity"), runDir2 = (home) => atHome2(home, "run"), daemonSocket2 = () => process.env.FAILPROOFAI_DAEMON_SOCKET || resolve27(runDir2(), "failproofaid.sock"), workerSocket = (home) => resolve27(runDir2(home), "worker.sock"), daemonLock = (home) => resolve27(runDir2(home), "failproofaid.lock"), auditLockFile2 = (home) => resolve27(runDir2(home), "audit.lock"), stateDir2 = (home) => atHome2(home, "state"), shimsDir2 = (home) => resolve27(stateDir2(home), "shims"), spoolDir2 = (home) => resolve27(stateDir2(home), "spool"), failedDir2 = (home) => resolve27(stateDir2(home), "failed"), collectorHealthFile2 = (home) => resolve27(stateDir2(home), "collector-health.json"), sessionPauseDir2 = () => resolve27(stateDir2(), "sessions"), auditScheduleFile2 = (home) => resolve27(stateDir2(home), "audit-schedule.json"), telemetryIdFile2 = (home) => resolve27(stateDir2(home), "telemetry-id"), launcherMarker2 = (home) => resolve27(stateDir2(home), "launcher-configured"), onboardingAttemptFile2 = (home) => resolve27(stateDir2(home), "onboarding-attempt.json"), lastVersionFile2 = (home) => resolve27(stateDir2(home), "last-version"), onboardingLockFile2 = (home) => resolve27(stateDir2(home), "onboarding.lock"), codexSessionPathsFile2 = (home) => resolve27(stateDir2(home), "codex-session-paths.json"), logsDir2 = (home) => atHome2(home, "logs"), migrationsDir2 = (home) => atHome2(home, "migrations"), migrationLedgerFile2 = (home) => resolve27(migrationsDir2(home), "applied.json"), migrationBackupDir2 = (layout, home) => resolve27(migrationsDir2(home), `backup-layout${layout}`), HOME_CLASSES2, legacy2;
27521
27576
  var init_fp_home2 = __esm(() => {
27522
27577
  customPoliciesDir2 = policiesDir2;
27523
27578
  HOME_CLASSES2 = [
@@ -27529,11 +27584,11 @@ var init_fp_home2 = __esm(() => {
27529
27584
  { path: failedDir2, class: "undelivered" },
27530
27585
  { path: customAgentsDir2, class: "undelivered" },
27531
27586
  { path: hookActivityDir2, class: "undelivered" },
27532
- { path: (home) => resolve26(stateDir2(home), "flush-request.json"), class: "undelivered" },
27533
- { path: (home) => resolve26(stateDir2(home), "backfill-request.json"), class: "undelivered" },
27587
+ { path: (home) => resolve27(stateDir2(home), "flush-request.json"), class: "undelivered" },
27588
+ { path: (home) => resolve27(stateDir2(home), "backfill-request.json"), class: "undelivered" },
27534
27589
  { path: cursorsDir2, class: "identity" },
27535
27590
  { path: telemetryIdFile2, class: "identity" },
27536
- { path: (home) => resolve26(stateDir2(home), "daemon-telemetry-id"), class: "identity" },
27591
+ { path: (home) => resolve27(stateDir2(home), "daemon-telemetry-id"), class: "identity" },
27537
27592
  { path: versionFile2, class: "identity" },
27538
27593
  { path: migrationsDir2, class: "identity" },
27539
27594
  { path: auditDir2, class: "derived" },
@@ -27589,7 +27644,7 @@ __export(exports_migrations2, {
27589
27644
  MIGRATIONS: () => MIGRATIONS2
27590
27645
  });
27591
27646
  import { copyFileSync as copyFileSync4, existsSync as existsSync36, mkdirSync as mkdirSync25, readFileSync as readFileSync29, rmSync as rmSync12, writeFileSync as writeFileSync23 } from "node:fs";
27592
- import { basename as basename7, dirname as dirname22, resolve as resolve27 } from "node:path";
27647
+ import { basename as basename7, dirname as dirname22, resolve as resolve28 } from "node:path";
27593
27648
  function planMigration2(from, registry = MIGRATIONS2) {
27594
27649
  if (from >= LAYOUT_VERSION)
27595
27650
  return [];
@@ -27641,6 +27696,15 @@ function appendLedger2(entry) {
27641
27696
  `, "utf8");
27642
27697
  } catch {}
27643
27698
  }
27699
+ function filesToBackUp2() {
27700
+ const seen = new Set;
27701
+ for (const at3 of [...BACKED_UP2, ...BACKED_UP_LEGACY2]) {
27702
+ const path3 = at3();
27703
+ if (existsSync36(path3))
27704
+ seen.add(path3);
27705
+ }
27706
+ return [...seen];
27707
+ }
27644
27708
  function backupBeforeMigrating2(from) {
27645
27709
  const dir = migrationBackupDir(from);
27646
27710
  const saved = [];
@@ -27650,16 +27714,9 @@ function backupBeforeMigrating2(from) {
27650
27714
  } catch {
27651
27715
  return [];
27652
27716
  }
27653
- const seen = new Set;
27654
- for (const at3 of [...BACKED_UP2, ...BACKED_UP_LEGACY2]) {
27655
- const source = at3();
27656
- if (seen.has(source))
27657
- continue;
27658
- seen.add(source);
27659
- if (!existsSync36(source))
27660
- continue;
27717
+ for (const source of filesToBackUp2()) {
27661
27718
  try {
27662
- copyFileSync4(source, resolve27(dir, basename7(source)));
27719
+ copyFileSync4(source, resolve28(dir, basename7(source)));
27663
27720
  saved.push(basename7(source));
27664
27721
  } catch {}
27665
27722
  }
@@ -27732,7 +27789,7 @@ function describePlan2(from) {
27732
27789
  ...chain.map((m) => ` ${m.from} → ${m.to} ${m.describe}`),
27733
27790
  ``,
27734
27791
  `These would be copied to ${migrationBackupDir(from)} first:`,
27735
- ...[...BACKED_UP2, ...BACKED_UP_LEGACY2].map((at3) => at3()).filter((p) => existsSync36(p)).map((p) => ` ${basename7(p)}`),
27792
+ ...filesToBackUp2().map((p) => ` ${basename7(p)}`),
27736
27793
  ``,
27737
27794
  `Settings, cloud enrolment, policy selection, your own policy files, decision`,
27738
27795
  `history and undelivered events are carried, not removed — see \`HOME_CLASSES\`.`
@@ -27745,7 +27802,7 @@ function restoreBackup2(layout) {
27745
27802
  const restored = [];
27746
27803
  for (const at3 of [...BACKED_UP2, ...BACKED_UP_LEGACY2]) {
27747
27804
  const target = at3();
27748
- const source = resolve27(dir, basename7(target));
27805
+ const source = resolve28(dir, basename7(target));
27749
27806
  if (!existsSync36(source))
27750
27807
  continue;
27751
27808
  try {
@@ -27776,7 +27833,13 @@ var init_migrations2 = __esm(() => {
27776
27833
  }
27777
27834
  ];
27778
27835
  BACKED_UP2 = [configFile, credentialsFile, globalPolicyConfigFile, versionFile];
27779
- BACKED_UP_LEGACY2 = [legacy.configToml, legacy.credentialsToml, legacy.policyConfig];
27836
+ BACKED_UP_LEGACY2 = [
27837
+ legacy.configToml,
27838
+ legacy.credentialsToml,
27839
+ legacy.policyConfig,
27840
+ legacy.cloudCredentials,
27841
+ legacy.ingestCredentials
27842
+ ];
27780
27843
  });
27781
27844
 
27782
27845
  // src/hooks/daemon-service.ts
@@ -27818,8 +27881,8 @@ import {
27818
27881
  unlinkSync as unlinkSync5,
27819
27882
  rmSync as rmSync13
27820
27883
  } from "node:fs";
27821
- import { homedir as homedir28, tmpdir as tmpdir3, userInfo as userInfo2 } from "node:os";
27822
- import { resolve as resolve28 } from "node:path";
27884
+ import { homedir as homedir29, tmpdir as tmpdir3, userInfo as userInfo2 } from "node:os";
27885
+ import { resolve as resolve29 } from "node:path";
27823
27886
  import { execFileSync as execFileSync5 } from "node:child_process";
27824
27887
  function setDaemonConfigured2(value, installedVersion) {
27825
27888
  try {
@@ -27846,7 +27909,7 @@ function resolveFailproofaidBinaryPath2() {
27846
27909
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
27847
27910
  if (packageRoot) {
27848
27911
  for (const profile of ["release", "debug"]) {
27849
- const candidate = resolve28(packageRoot, "target", profile, "failproofaid");
27912
+ const candidate = resolve29(packageRoot, "target", profile, "failproofaid");
27850
27913
  if (existsSync37(candidate))
27851
27914
  return candidate;
27852
27915
  }
@@ -27877,7 +27940,7 @@ function resolveWorkerCommand2() {
27877
27940
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
27878
27941
  if (!packageRoot)
27879
27942
  return null;
27880
- const workerScript = resolve28(packageRoot, "dist", "worker.mjs");
27943
+ const workerScript = resolve29(packageRoot, "dist", "worker.mjs");
27881
27944
  if (!existsSync37(workerScript))
27882
27945
  return null;
27883
27946
  return `${shellQuote2(process.execPath)} ${shellQuote2(workerScript)}`;
@@ -27888,7 +27951,7 @@ function resolveCliCommand2() {
27888
27951
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
27889
27952
  if (!packageRoot)
27890
27953
  return null;
27891
- const cliScript = resolve28(packageRoot, "dist", "cli.mjs");
27954
+ const cliScript = resolve29(packageRoot, "dist", "cli.mjs");
27892
27955
  if (!existsSync37(cliScript))
27893
27956
  return null;
27894
27957
  return `${shellQuote2(process.execPath)} ${shellQuote2(cliScript)}`;
@@ -27902,7 +27965,7 @@ function workerScriptPath2() {
27902
27965
  const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT;
27903
27966
  if (!packageRoot)
27904
27967
  return null;
27905
- const workerScript = resolve28(packageRoot, "dist", "worker.mjs");
27968
+ const workerScript = resolve29(packageRoot, "dist", "worker.mjs");
27906
27969
  return existsSync37(workerScript) ? workerScript : null;
27907
27970
  }
27908
27971
  function assertUnitSafe2(value, field) {
@@ -27929,10 +27992,10 @@ function systemdUnitDir2() {
27929
27992
  return process.env.FAILPROOFAI_SYSTEMD_DIR || "/etc/systemd/system";
27930
27993
  }
27931
27994
  function systemdUnitPath2(user = serviceUser2()) {
27932
- return resolve28(systemdUnitDir2(), systemdUnitName2(user));
27995
+ return resolve29(systemdUnitDir2(), systemdUnitName2(user));
27933
27996
  }
27934
27997
  function legacySystemdUserUnitPath2() {
27935
- return resolve28(homedir28(), ".config", "systemd", "user", "failproofaid.service");
27998
+ return resolve29(homedir29(), ".config", "systemd", "user", "failproofaid.service");
27936
27999
  }
27937
28000
  function launchdLabel2(user = serviceUser2()) {
27938
28001
  return `ai.failproof.failproofaid.${user}`;
@@ -27941,7 +28004,7 @@ function launchdPlistPath2(user = serviceUser2()) {
27941
28004
  return `/Library/LaunchDaemons/${launchdLabel2(user)}.plist`;
27942
28005
  }
27943
28006
  function legacyLaunchAgentPlistPath2() {
27944
- return resolve28(homedir28(), "Library", "LaunchAgents", "ai.failproof.failproofaid.plist");
28007
+ return resolve29(homedir29(), "Library", "LaunchAgents", "ai.failproof.failproofaid.plist");
27945
28008
  }
27946
28009
  function legacySharedLaunchDaemonPath2() {
27947
28010
  return "/Library/LaunchDaemons/ai.failproof.failproofaid.plist";
@@ -27989,8 +28052,8 @@ function runPrivileged2(command, args) {
27989
28052
  execFileSync5(cmd, argv, { stdio: "ignore", timeout: SERVICE_CMD_TIMEOUT_MS2 });
27990
28053
  }
27991
28054
  function writePrivilegedFile2(destination, contents, mode = "0644") {
27992
- const stagingDir = mkdtempSync2(resolve28(tmpdir3(), "failproofaid-stage-"));
27993
- const staging = resolve28(stagingDir, "service-definition");
28055
+ const stagingDir = mkdtempSync2(resolve29(tmpdir3(), "failproofaid-stage-"));
28056
+ const staging = resolve29(stagingDir, "service-definition");
27994
28057
  try {
27995
28058
  writeFileSync24(staging, contents, "utf8");
27996
28059
  runPrivileged2("install", ["-m", mode, staging, destination]);
@@ -28045,7 +28108,7 @@ function systemdUnitContents2(binaryPath, workerCmd, cliCmd = null) {
28045
28108
  `).join("");
28046
28109
  const user = assertUnitSafe2(serviceUser2(), "User");
28047
28110
  assertUnitSafe2(binaryPath, "ExecStart");
28048
- assertUnitSafe2(homedir28(), "HOME");
28111
+ assertUnitSafe2(homedir29(), "HOME");
28049
28112
  const conditionPaths = [binaryPath, workerScriptPath2()].filter((p) => typeof p === "string" && existsSync37(p));
28050
28113
  const conditionLines = conditionPaths.map((p) => `ConditionPathExists=${assertUnitSafe2(p, "ConditionPathExists")}
28051
28114
  `).join("");
@@ -28059,7 +28122,7 @@ User=${user}
28059
28122
  # Set explicitly rather than relying on systemd deriving it from User=:
28060
28123
  # failproofaid stores per-user state and refuses to start without HOME, so this
28061
28124
  # required variable is not left to a version-dependent default.
28062
- Environment="HOME=${homedir28()}"
28125
+ Environment="HOME=${homedir29()}"
28063
28126
  ${envLines}ExecStart=${binaryPath}
28064
28127
  Restart=on-failure
28065
28128
  RestartSec=2
@@ -28107,9 +28170,9 @@ ${env.map(([key, value]) => ` <key>${key}</key>
28107
28170
  <key>UserName</key>
28108
28171
  <string>${escapeXml2(serviceUser2())}</string>
28109
28172
  ${envBlock} <key>StandardOutPath</key>
28110
- <string>${escapeXml2(resolve28(logDir2, "failproofaid.log"))}</string>
28173
+ <string>${escapeXml2(resolve29(logDir2, "failproofaid.log"))}</string>
28111
28174
  <key>StandardErrorPath</key>
28112
- <string>${escapeXml2(resolve28(logDir2, "failproofaid.err.log"))}</string>
28175
+ <string>${escapeXml2(resolve29(logDir2, "failproofaid.err.log"))}</string>
28113
28176
  </dict>
28114
28177
  </plist>
28115
28178
  `;
@@ -28369,65 +28432,33 @@ async function ensureDaemonServiceCurrent2() {
28369
28432
  }
28370
28433
  return { outcome: "rewritten", daemonRunning: true };
28371
28434
  }
28372
- async function refreshDaemonToCliVersion() {
28373
- const lines = [];
28374
- if (daemonServiceStatus2() === "not-installed") {
28435
+ async function refreshDaemonToCliVersion(deps = {}) {
28436
+ const status = deps.status ?? daemonServiceStatus2;
28437
+ const install = deps.install ?? installDaemonService2;
28438
+ const prime = deps.prime ?? primeElevation2;
28439
+ const interactive = deps.interactive ?? (() => Boolean(process.stdin.isTTY && process.stdout.isTTY));
28440
+ if (status() === "not-installed") {
28375
28441
  return { ok: true, lines: ["No failproofaid service on this machine; nothing to update."] };
28376
28442
  }
28377
- const binary = await ensureFailproofaidBinary2();
28378
- if (!binary.path) {
28379
- return {
28380
- ok: false,
28381
- lines: [
28382
- `Could not put the failproofaid ${version2} binary in place: ${binary.reason ?? "unknown reason"}`,
28383
- `The installed daemon is unchanged. It refuses to start against a layout it does`,
28384
- `not speak, so if this machine has just been migrated, run \`failproofai config\`.`
28385
- ]
28386
- };
28387
- }
28388
- lines.push(`failproofaid ${version2} binary in place.`);
28389
- const upgrade = await ensureDaemonServiceCurrent2();
28390
- if (upgrade.outcome === "failed") {
28391
- return {
28392
- ok: false,
28393
- lines: [
28394
- ...lines,
28395
- `The service definition could not be refreshed: ${upgrade.reason ?? "unknown reason"}`,
28396
- ...upgrade.daemonRunning === false ? [
28397
- `failproofaid is NOT running. On a machine configured to require it, every tool`,
28398
- `call denies until it is back — run \`failproofai config\` to rebuild the service.`
28399
- ] : []
28400
- ]
28401
- };
28402
- }
28403
- const restart = daemonRestartCommand2();
28404
- try {
28405
- if (process.platform === "darwin") {
28406
- runPrivileged2("launchctl", ["kickstart", "-k", `system/${launchdLabel2()}`]);
28407
- } else {
28408
- runPrivileged2("systemctl", ["restart", systemdUnitName2()]);
28409
- }
28410
- } catch {
28411
- return {
28412
- ok: false,
28413
- lines: [
28414
- ...lines,
28415
- `Could not restart failproofaid without a password. Run this yourself:`,
28416
- ` ${restart ?? "restart the failproofaid service"}`
28417
- ]
28418
- };
28419
- }
28420
- if (!await waitForDaemonRunning2()) {
28443
+ if (interactive())
28444
+ prime();
28445
+ const result = await install();
28446
+ if (!result.installed) {
28421
28447
  return {
28422
28448
  ok: false,
28423
28449
  lines: [
28424
- ...lines,
28425
- `failproofaid was restarted but did not come back up. \`${daemonStatusCommand2()}\` will say why.`,
28426
- `On a machine configured to require it, every tool call denies until it does.`
28450
+ `failproofaid ${version2} could not be installed: ${result.reason ?? "unknown reason"}`,
28451
+ `The previous daemon is untouched. On a machine configured to require it,`,
28452
+ `enforcement continues; collection and cloud policy may be stale until this`,
28453
+ `succeeds. \`${daemonStatusCommand2() ?? "systemctl status"}\` will say more.`
28427
28454
  ]
28428
28455
  };
28429
28456
  }
28430
- return { ok: true, lines: [...lines, `failproofaid restarted and running.`] };
28457
+ writeVersionFile({ daemon: version2 });
28458
+ return {
28459
+ ok: true,
28460
+ lines: [`failproofaid ${version2} installed, service restarted and holding.`]
28461
+ };
28431
28462
  }
28432
28463
  async function uninstallDaemonService2() {
28433
28464
  setDaemonConfigured2(false);
@@ -28960,7 +28991,7 @@ function runPrompt2(p) {
28960
28991
  `${c2.dim(BAR2)} ${c2.dim(summary)}`
28961
28992
  ]);
28962
28993
  };
28963
- return new Promise((resolve29) => {
28994
+ return new Promise((resolve30) => {
28964
28995
  hideCursor2(stdout);
28965
28996
  repaint2(stdout, region, build());
28966
28997
  readline3.emitKeypressEvents(stdin);
@@ -28976,7 +29007,7 @@ function runPrompt2(p) {
28976
29007
  const finish = (result) => {
28977
29008
  cleanup();
28978
29009
  collapse(result);
28979
- resolve29(result);
29010
+ resolve30(result);
28980
29011
  };
28981
29012
  function onKey(_s, key) {
28982
29013
  if (!key)
@@ -28984,6 +29015,7 @@ function runPrompt2(p) {
28984
29015
  if (key.ctrl && (key.name === "c" || key.name === "d") || key.name === "escape") {
28985
29016
  finish(null);
28986
29017
  } else if (key.name === "left" && p.allowBack) {
29018
+ p.onBack?.();
28987
29019
  finish(BACK2);
28988
29020
  } else if (key.name === "up") {
28989
29021
  cursor2 = cursor2 > 0 ? cursor2 - 1 : choices.length - 1;
@@ -29064,6 +29096,7 @@ function multiSelect2(opts) {
29064
29096
  },
29065
29097
  warnLine: () => warn ? c2.warn(`Select at least ${minSelected}.`) : null,
29066
29098
  allowBack: opts.allowBack,
29099
+ onBack: opts.onBack ? () => opts.onBack?.(choices.filter((_, i) => checked[i]).map((ch) => ch.value)) : undefined,
29067
29100
  footer: opts.hint ?? (opts.allowBack ? "↑/↓ move · space select · ctrl+a all · ← back · enter confirm" : "↑/↓ move · space select · ctrl+a all · enter confirm"),
29068
29101
  onKey: (key, cursor2) => {
29069
29102
  if (key.name === "space") {
@@ -29104,7 +29137,7 @@ function promptText2(opts) {
29104
29137
  return error ? { ok: false, error } : { ok: true, value };
29105
29138
  };
29106
29139
  if (!stdin.isTTY) {
29107
- return new Promise((resolve29) => {
29140
+ return new Promise((resolve30) => {
29108
29141
  let buf = "";
29109
29142
  const onData = (chunk) => {
29110
29143
  buf += String(chunk);
@@ -29117,13 +29150,13 @@ function promptText2(opts) {
29117
29150
  stdin.removeListener("end", done);
29118
29151
  const r = accept(buf.split(`
29119
29152
  `)[0] ?? "");
29120
- resolve29(r.ok ? r.value : null);
29153
+ resolve30(r.ok ? r.value : null);
29121
29154
  };
29122
29155
  stdin.on("data", onData);
29123
29156
  stdin.on("end", done);
29124
29157
  });
29125
29158
  }
29126
- return new Promise((resolve29) => {
29159
+ return new Promise((resolve30) => {
29127
29160
  let value = "";
29128
29161
  const draw = (error) => {
29129
29162
  const cols = stdout.columns || 80;
@@ -29153,14 +29186,14 @@ function promptText2(opts) {
29153
29186
  return;
29154
29187
  if (key.ctrl && (key.name === "c" || key.name === "d") || key.name === "escape") {
29155
29188
  cleanup();
29156
- resolve29(null);
29189
+ resolve30(null);
29157
29190
  return;
29158
29191
  }
29159
29192
  if (key.name === "return" || key.name === "enter") {
29160
29193
  const r = accept(value);
29161
29194
  if (r.ok) {
29162
29195
  cleanup();
29163
- resolve29(r.value);
29196
+ resolve30(r.value);
29164
29197
  } else {
29165
29198
  draw(r.error);
29166
29199
  }
@@ -29229,7 +29262,7 @@ __export(exports_manager, {
29229
29262
  });
29230
29263
  import { execSync as execSync7 } from "node:child_process";
29231
29264
  import { existsSync as existsSync39 } from "node:fs";
29232
- import { resolve as resolve29, basename as basename8 } from "node:path";
29265
+ import { resolve as resolve30, basename as basename8 } from "node:path";
29233
29266
  import { platform as platform5, arch as arch4, release as release3, hostname as hostname5 } from "node:os";
29234
29267
  function getSettingsPath2(scope, cwd) {
29235
29268
  return claudeCode.getSettingsPath(scope, cwd);
@@ -29337,8 +29370,8 @@ async function installHooksImpl2(policyNames, scope = "user", cwd, includeBeta =
29337
29370
  delete configToWrite.customPoliciesPath;
29338
29371
  delete configToWrite.customPoliciesPaths;
29339
29372
  } else if (customPoliciesPath && (typeof customPoliciesPath === "string" || customPoliciesPath.length > 0)) {
29340
- const incoming = (typeof customPoliciesPath === "string" ? [customPoliciesPath] : customPoliciesPath).map((path3) => resolve29(path3));
29341
- const carried = (previousConfig.customPoliciesPaths ?? (previousConfig.customPoliciesPath ? [previousConfig.customPoliciesPath] : [])).map((path3) => resolve29(path3)).filter((path3) => {
29373
+ const incoming = (typeof customPoliciesPath === "string" ? [customPoliciesPath] : customPoliciesPath).map((path3) => resolve30(path3));
29374
+ const carried = (previousConfig.customPoliciesPaths ?? (previousConfig.customPoliciesPath ? [previousConfig.customPoliciesPath] : [])).map((path3) => resolve30(path3)).filter((path3) => {
29342
29375
  if (existsSync39(path3))
29343
29376
  return true;
29344
29377
  console.log(`Dropping custom policies path (file no longer exists): ${path3}`);
@@ -29730,7 +29763,7 @@ Failproof AI Hook Policies
29730
29763
  console.log(`
29731
29764
  ── Custom Policies ───────────────────────`);
29732
29765
  for (const path3 of explicitPaths) {
29733
- const absPath = resolve29(findProjectConfigDir(cwd ?? process.cwd()), path3);
29766
+ const absPath = resolve30(findProjectConfigDir(cwd ?? process.cwd()), path3);
29734
29767
  console.log(` ${absPath}`);
29735
29768
  if (!existsSync39(absPath)) {
29736
29769
  console.log(` \x1B[31m✗ File not found: ${absPath}\x1B[0m`);
@@ -29751,7 +29784,7 @@ Failproof AI Hook Policies
29751
29784
  console.log();
29752
29785
  }
29753
29786
  const base = findProjectConfigDir(cwd ?? process.cwd());
29754
- const projectDir = resolve29(base, ".failproofai", "policies");
29787
+ const projectDir = resolve30(base, ".failproofai", "policies");
29755
29788
  const userDir = customPoliciesDir();
29756
29789
  const sameDir = userDir === projectDir;
29757
29790
  const conventionDirs = [
@@ -29999,7 +30032,7 @@ async function promptCliTargetSelection(detected, action = "install") {
29999
30032
  lastLineCount = lines.length;
30000
30033
  }
30001
30034
  const itemCount = options.length;
30002
- return new Promise((resolve30) => {
30035
+ return new Promise((resolve31) => {
30003
30036
  render();
30004
30037
  readline4.emitKeypressEvents(process.stdin);
30005
30038
  const wasRaw = process.stdin.isRaw;
@@ -30032,7 +30065,7 @@ async function promptCliTargetSelection(detected, action = "install") {
30032
30065
  cleanup();
30033
30066
  process.stdout.write(`
30034
30067
  `);
30035
- resolve30(options[cursor2].value);
30068
+ resolve31(options[cursor2].value);
30036
30069
  }
30037
30070
  }
30038
30071
  process.stdin.on("keypress", onKey);
@@ -30185,7 +30218,7 @@ async function promptPolicySelection2(preSelected, options = {}) {
30185
30218
  `);
30186
30219
  lastLineCount = lines.length;
30187
30220
  }
30188
- return new Promise((resolve30) => {
30221
+ return new Promise((resolve31) => {
30189
30222
  render();
30190
30223
  process.stdin.setRawMode(true);
30191
30224
  process.stdin.resume();
@@ -30222,7 +30255,7 @@ async function promptPolicySelection2(preSelected, options = {}) {
30222
30255
  ${dim(STEP_DONE)} Policies
30223
30256
  ${dim(BAR)} ${dim(`${selected.length} selected`)}
30224
30257
  `);
30225
- resolve30(selected);
30258
+ resolve31(selected);
30226
30259
  } else if (key.name === "escape") {
30227
30260
  search = "";
30228
30261
  cursor2 = 0;
@@ -30884,7 +30917,7 @@ __export(exports_launch2, {
30884
30917
  });
30885
30918
  import { spawn as spawn3 } from "child_process";
30886
30919
  import { realpathSync as realpathSync5, existsSync as existsSync40 } from "node:fs";
30887
- import { resolve as resolve30, dirname as dirname23 } from "node:path";
30920
+ import { resolve as resolve31, dirname as dirname23 } from "node:path";
30888
30921
  import { fileURLToPath as fileURLToPath3 } from "node:url";
30889
30922
  import { createInterface as createInterface2 } from "node:readline";
30890
30923
  function launch2(mode) {
@@ -30908,8 +30941,8 @@ function launch2(mode) {
30908
30941
  process.env.PORT = port;
30909
30942
  process.env.HOSTNAME = bindHost;
30910
30943
  cmd = "node";
30911
- const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve30(dirname23(realpathSync5(fileURLToPath3(import.meta.url))), "..");
30912
- const serverJsPath = resolve30(packageRoot, ".next/standalone/server.js");
30944
+ const packageRoot = process.env.FAILPROOFAI_PACKAGE_ROOT ?? resolve31(dirname23(realpathSync5(fileURLToPath3(import.meta.url))), "..");
30945
+ const serverJsPath = resolve31(packageRoot, ".next/standalone/server.js");
30913
30946
  if (!existsSync40(serverJsPath)) {
30914
30947
  let shadowMessage = null;
30915
30948
  try {
@@ -31007,17 +31040,17 @@ var init_cli_error2 = __esm(() => {
31007
31040
 
31008
31041
  // bin/failproofai.mjs
31009
31042
  import { realpathSync as realpathSync6 } from "fs";
31010
- import { dirname as dirname24, resolve as resolve31 } from "path";
31043
+ import { dirname as dirname24, resolve as resolve32 } from "path";
31011
31044
  import { fileURLToPath as fileURLToPath4 } from "url";
31012
31045
  // package.json
31013
- var version = "1.0.0-beta.16";
31046
+ var version = "1.0.0-beta.18";
31014
31047
 
31015
31048
  // bin/failproofai.mjs
31016
31049
  if (!process.env.FAILPROOFAI_PACKAGE_ROOT) {
31017
- process.env.FAILPROOFAI_PACKAGE_ROOT = resolve31(dirname24(realpathSync6(fileURLToPath4(import.meta.url))), "..");
31050
+ process.env.FAILPROOFAI_PACKAGE_ROOT = resolve32(dirname24(realpathSync6(fileURLToPath4(import.meta.url))), "..");
31018
31051
  }
31019
31052
  if (!process.env.FAILPROOFAI_DIST_PATH) {
31020
- process.env.FAILPROOFAI_DIST_PATH = resolve31(dirname24(realpathSync6(fileURLToPath4(import.meta.url))), "..", "dist");
31053
+ process.env.FAILPROOFAI_DIST_PATH = resolve32(dirname24(realpathSync6(fileURLToPath4(import.meta.url))), "..", "dist");
31021
31054
  }
31022
31055
  var args = process.argv.slice(2);
31023
31056
  if (args[0] === "p")