failproofai 1.0.0-beta.14 → 1.0.0-beta.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.next/standalone/.next/BUILD_ID +1 -1
- package/.next/standalone/.next/build-manifest.json +5 -5
- package/.next/standalone/.next/prerender-manifest.json +3 -3
- package/.next/standalone/.next/required-server-files.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/_global-error/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page.js +2 -1
- package/.next/standalone/.next/server/app/_global-error/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_global-error.html +1 -1
- package/.next/standalone/.next/server/app/_global-error.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +7 -7
- package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/_not-found/page/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page.js +2 -1
- package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/_not-found.html +1 -1
- package/.next/standalone/.next/server/app/_not-found.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +9 -9
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/api/audit/invite/route.js +1 -1
- package/.next/standalone/.next/server/app/api/audit/invite/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/run/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/audit/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-request/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/login-verify/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/logout/route.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/logout/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/reminder/route.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/reminder/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route.js +1 -1
- package/.next/standalone/.next/server/app/api/auth/status/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/api/download/[project]/[session]/route.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/audit/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/audit/page.js +2 -1
- package/.next/standalone/.next/server/app/audit/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/audit/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/index.html +1 -1
- package/.next/standalone/.next/server/app/index.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
- package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +14 -14
- package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +4 -4
- package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +9 -9
- package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/.next/standalone/.next/server/app/page/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/page.js +2 -1
- package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/policies/page/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/policies/page/server-reference-manifest.json +10 -10
- package/.next/standalone/.next/server/app/policies/page.js +2 -1
- package/.next/standalone/.next/server/app/policies/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/policies/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js +2 -1
- package/.next/standalone/.next/server/app/project/[name]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/react-loadable-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page/server-reference-manifest.json +2 -2
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js +2 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/project/[name]/session/[sessionId]/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/projects/page/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/projects/page/server-reference-manifest.json +1 -1
- package/.next/standalone/.next/server/app/projects/page.js +2 -1
- package/.next/standalone/.next/server/app/projects/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/projects/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/app/settings/page/build-manifest.json +2 -2
- package/.next/standalone/.next/server/app/settings/page/server-reference-manifest.json +4 -4
- package/.next/standalone/.next/server/app/settings/page.js +2 -1
- package/.next/standalone/.next/server/app/settings/page.js.nft.json +1 -1
- package/.next/standalone/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__06hexd0._.js +3 -0
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__0_0xu5z._.js +1 -1
- package/.next/standalone/.next/server/chunks/_0lxbzdq._.js +1 -1
- package/.next/standalone/.next/server/chunks/_1zuiiy3._.js +1 -1
- package/.next/standalone/.next/server/chunks/lib_telemetry_ts_0dctyyw._.js +3 -0
- package/.next/standalone/.next/server/chunks/package_json_[json]_cjs_1nxcc4v._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0hxmox-._.js +3 -0
- package/.next/standalone/.next/server/chunks/ssr/{[root-of-the-server]__12y_xo0._.js → [root-of-the-server]__0no2gzh._.js} +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0spkm68._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__17itmx-._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1rv-sc9._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1u-wx42._.js +4 -0
- package/.next/standalone/.next/server/chunks/ssr/{_202d777._.js → _09tcu2b._.js} +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0rjgfln._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0vo2qyt._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_0xej-0e._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_10399ge._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_149k9oy._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1_hwp06._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1mnhi_r._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/_1ror7k9._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_audit__components_audit-dashboard_tsx_0p9ud47._.js +2 -2
- package/.next/standalone/.next/server/chunks/ssr/app_global-error_tsx_1kp6l3x._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/app_policies_hooks-client_tsx_19dqvpc._.js +1 -1
- package/.next/standalone/.next/server/chunks/ssr/src_hooks_fp-config_ts_04t589g._.js +4 -0
- package/.next/standalone/.next/server/middleware-build-manifest.js +5 -5
- package/.next/standalone/.next/server/pages/404.html +1 -1
- package/.next/standalone/.next/server/pages/500.html +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.js +1 -1
- package/.next/standalone/.next/server/server-reference-manifest.json +15 -15
- package/.next/standalone/.next/static/chunks/{0mot4rr-baiiq.js → 0fx3tgb_n0vz5.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1_0nr2fuuslbb.js → 16yzosmvpinbh.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0ynhunx0nt0n-.js → 1_as8528fwqxf.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1tyg866lrq4kh.js → 1nsy22eg5q-pi.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2zilodg05qgcf.js → 2f2h7g8sm0bhr.js} +1 -1
- package/.next/standalone/.next/static/chunks/{0pkz6r-cgdr3-.js → 2n6wkcj5q_0yd.js} +2 -2
- package/.next/standalone/.next/static/chunks/{30f--ye1ly8m6.js → 2okcei5v0-xrx.js} +1 -1
- package/.next/standalone/.next/static/chunks/{31fmsp1soxi07.js → 2rl5gq4xl8oa2.js} +1 -1
- package/.next/standalone/.next/static/chunks/{1wn2p7yzbcifa.js → 3vsiw3ayz3c7_.js} +1 -1
- package/.next/standalone/.next/static/chunks/{2hiai8kvhjcov.js → 3xp43uu8jj8t4.js} +1 -1
- package/.next/standalone/.next/static/chunks/43kqvfa-2jq0g.js +1 -0
- package/.next/standalone/.next/static/chunks/{turbopack-3diub4ctvn1n0.js → turbopack-0ud32mdjjcn6y.js} +1 -1
- package/.next/standalone/SECURITY.md +8 -2
- package/.next/standalone/app/actions/get-hooks-config.ts +0 -1
- package/.next/standalone/app/audit/_components/audit-dashboard.tsx +1 -3
- package/.next/standalone/app/audit/_components/audit-progress-strip.tsx +1 -1
- package/.next/standalone/app/audit/_components/come-back-better-section.tsx +1 -1
- package/.next/standalone/app/audit/_components/empty-state.tsx +0 -1
- package/.next/standalone/app/audit/_components/how-to-improve-section.tsx +1 -1
- package/.next/standalone/app/audit/_components/quirks-section.tsx +0 -1
- package/.next/standalone/app/audit/_components/report-footer.tsx +0 -2
- package/.next/standalone/app/audit/_components/run-progress.tsx +1 -1
- package/.next/standalone/app/audit/_components/strengths-section.tsx +0 -1
- package/.next/standalone/app/components/pause-notices.tsx +1 -1
- package/.next/standalone/app/components/raw-log-viewer.tsx +1 -1
- package/.next/standalone/app/components/toast.tsx +1 -1
- package/.next/standalone/app/policies/hooks-client.tsx +3 -2
- package/.next/standalone/app/settings/settings-client.tsx +1 -2
- package/.next/standalone/lib/auth/auth-store.ts +0 -1
- package/.next/standalone/package.json +10 -12
- package/.next/standalone/server.js +1 -1
- package/bin/failproofai.mjs +253 -33
- package/bin/failproofaid-shim.mjs +4 -4
- package/dist/cli.mjs +6337 -3869
- package/dist/worker.mjs +26 -21
- package/lib/auth/auth-store.ts +0 -1
- package/package.json +10 -12
- package/scripts/dev-hook.mjs +46 -5
- package/scripts/translate-docs/cache.ts +1 -1
- package/scripts/translate-docs/cli.ts +2 -2
- package/scripts/translate-docs/mintlify-nav.ts +1 -1
- package/src/audit/cache.ts +0 -1
- package/src/audit/dashboard-cache.ts +0 -2
- package/src/audit/report.ts +0 -1
- package/src/hooks/builtin-policies.ts +1 -1
- package/src/hooks/cloud-enrollment-cli.ts +0 -2
- package/src/hooks/cloud-enrollment.ts +1 -2
- package/src/hooks/cloud-managed-policies.ts +0 -1
- package/src/hooks/collector-config.ts +4 -20
- package/src/hooks/configure-wizard.ts +0 -4
- package/src/hooks/custom-hooks-loader.ts +0 -1
- package/src/hooks/daemon-client.ts +4 -28
- package/src/hooks/daemon-download.ts +0 -1
- package/src/hooks/daemon-service.ts +108 -16
- package/src/hooks/fp-config.ts +226 -12
- package/src/hooks/fp-home.ts +270 -56
- package/src/hooks/fp-reset.ts +482 -73
- package/src/hooks/hook-logger.ts +0 -1
- package/src/hooks/integrations.ts +0 -1
- package/src/hooks/loader-utils.ts +1 -1
- package/src/hooks/manager.ts +1 -1
- package/src/hooks/migrations.ts +381 -0
- package/src/hooks/onboarding-lock.ts +1 -2
- package/src/hooks/session-pause.ts +0 -1
- package/.next/standalone/.next/server/chunks/[root-of-the-server]__1uyc-z4._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__0vlyx3j._.js +0 -3
- package/.next/standalone/.next/server/chunks/ssr/[root-of-the-server]__1mmefsr._.js +0 -5
- package/.next/standalone/.next/static/chunks/2yy1767yfda67.js +0 -1
- package/.next/standalone/ino.ujh3/.failproofai/VERSION +0 -4
- package/.next/standalone/ino.ujh3/.failproofai/state/last-version +0 -1
- package/.next/standalone/ino.ujh3/.failproofai/state/telemetry-id +0 -1
- /package/.next/standalone/.next/static/{ZbPDZe0dNBNdNmo31aq_e → kSTfP_Tzl760gYDnYr-JC}/_buildManifest.js +0 -0
- /package/.next/standalone/.next/static/{ZbPDZe0dNBNdNmo31aq_e → kSTfP_Tzl760gYDnYr-JC}/_clientMiddlewareManifest.js +0 -0
- /package/.next/standalone/.next/static/{ZbPDZe0dNBNdNmo31aq_e → kSTfP_Tzl760gYDnYr-JC}/_ssgManifest.js +0 -0
package/src/hooks/fp-home.ts
CHANGED
|
@@ -320,6 +320,186 @@ export const codexSessionPathsFile = (home?: string) => resolve(stateDir(home),
|
|
|
320
320
|
|
|
321
321
|
export const logsDir = (home?: string) => atHome(home, "logs");
|
|
322
322
|
|
|
323
|
+
// ── Migration state ──────────────────────────────────────────────────────────
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Where a migration records what it did, and what it saved first.
|
|
327
|
+
*
|
|
328
|
+
* The migration CODE ships in the npm package, never here. A home written by
|
|
329
|
+
* 1.0.0 contains only 1.0.0's migrations, and the steps that get that machine
|
|
330
|
+
* forward are precisely the ones its old install never had — so the installed
|
|
331
|
+
* CLI, always the newest thing on the machine, is the only correct source. What
|
|
332
|
+
* belongs in the home is the STATE: which steps have run, and the files they
|
|
333
|
+
* saved before running. Exactly the split a database makes, where migrations are
|
|
334
|
+
* code in the repo and the applied set is a table.
|
|
335
|
+
*/
|
|
336
|
+
export const migrationsDir = (home?: string) => atHome(home, "migrations");
|
|
337
|
+
|
|
338
|
+
/** One line per step that has run: `{from, to, cli, at, durationMs, ok}`. */
|
|
339
|
+
export const migrationLedgerFile = (home?: string) =>
|
|
340
|
+
resolve(migrationsDir(home), "applied.json");
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Copies of the irreplaceable files, taken before the layout-`n` migration ran.
|
|
344
|
+
*
|
|
345
|
+
* NOT a copy of the whole home, and the reason is that `HOME_CLASSES` already
|
|
346
|
+
* made one unnecessary: a migration deletes only `derived` and `refetchable`
|
|
347
|
+
* paths, so there is no longer anything irreplaceable for it to lose by design.
|
|
348
|
+
* What remains worth insuring against is a BUG in a step — and for that, the few
|
|
349
|
+
* kilobytes of `config.json`, `credentials.json`, `policies-config.json`, the
|
|
350
|
+
* marker, and the retired layout's own config are a real undo, where a full-home
|
|
351
|
+
* copy would cost a duplicate of `bin/` and `hook-activity/` and need a
|
|
352
|
+
* two-rename window that also has to dodge a live daemon holding `run/`.
|
|
353
|
+
*/
|
|
354
|
+
export const migrationBackupDir = (layout: number, home?: string) =>
|
|
355
|
+
resolve(migrationsDir(home), `backup-layout${layout}`);
|
|
356
|
+
|
|
357
|
+
// ── What each path HOLDS ─────────────────────────────────────────────────────
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* What kind of data a path in the home holds, which is what decides whether an
|
|
361
|
+
* upgrade may throw it away.
|
|
362
|
+
*
|
|
363
|
+
* The rule, stated once: **derived and re-fetchable may be dropped; anything a
|
|
364
|
+
* person typed, anything not yet delivered, and anything that identifies the
|
|
365
|
+
* machine is carried.**
|
|
366
|
+
*/
|
|
367
|
+
export type DataClass =
|
|
368
|
+
/** A person set this and nothing regenerates it. Never deleted. */
|
|
369
|
+
| "user-typed"
|
|
370
|
+
/** Recorded here and not yet shipped anywhere. Never deleted. */
|
|
371
|
+
| "undelivered"
|
|
372
|
+
/** Stable ids and watermarks. Never deleted — a new one is a new machine. */
|
|
373
|
+
| "identity"
|
|
374
|
+
/** Rebuilt on demand. May be dropped. */
|
|
375
|
+
| "derived"
|
|
376
|
+
/** The server is the source of truth. May be dropped and re-fetched. */
|
|
377
|
+
| "refetchable"
|
|
378
|
+
/** Sockets, locks, binaries: live process state. Never touched by a reset. */
|
|
379
|
+
| "ephemeral";
|
|
380
|
+
|
|
381
|
+
/**
|
|
382
|
+
* Every path in the home, and what it holds.
|
|
383
|
+
*
|
|
384
|
+
* `resettablePaths()` is DERIVED from this rather than hand-listed beside it,
|
|
385
|
+
* and that is the whole point. Before this table one path was declared in four
|
|
386
|
+
* places — as a function above, again in `legacy` once it moved, again in the
|
|
387
|
+
* delete list, and again in `CARRIED_POLICY_CONFIG_KEYS` if it held carried
|
|
388
|
+
* keys — with nothing making the four agree. **Every silent-data-loss bug this
|
|
389
|
+
* module has had is one of those lists falling out of sync with a path that
|
|
390
|
+
* moved:** layout 1's `policies/` (hand-written source, deleted), layout 2's
|
|
391
|
+
* nested policy config (enabled policies, emptied), `cache/hook-activity` (the
|
|
392
|
+
* whole decision log, deleted with its parent), the layout-2 `credentials.toml`
|
|
393
|
+
* (a live token left behind), and `collector.sources.extra_paths` — which was
|
|
394
|
+
* on the delete list by way of `config.json` and would have taken every extra
|
|
395
|
+
* path a user typed at the next layout bump.
|
|
396
|
+
*
|
|
397
|
+
* Two consequences worth naming:
|
|
398
|
+
*
|
|
399
|
+
* - **Forgetting is now safe.** A path absent from this table is not deleted,
|
|
400
|
+
* because the delete list is a filter over what is here rather than a
|
|
401
|
+
* catch-all. The failure mode of an oversight becomes a stale file — loud
|
|
402
|
+
* and recoverable — instead of a deleted cloud token.
|
|
403
|
+
* - **`state/` is not classified as a whole**, because it is mixed: its
|
|
404
|
+
* `spool/` and `telemetry-id` are things we must never drop, and everything
|
|
405
|
+
* else under it is scratch. Listing the parent is exactly how a reset came
|
|
406
|
+
* to delete undelivered events and the machine's own telemetry identity.
|
|
407
|
+
*
|
|
408
|
+
* `home-classification.test.ts` asserts every exported path function in this
|
|
409
|
+
* module is either classified here or covered by a classified parent, so the
|
|
410
|
+
* next path added to the home cannot skip the one question that matters.
|
|
411
|
+
*/
|
|
412
|
+
export const HOME_CLASSES: readonly { path: (home?: string) => string; class: DataClass }[] = [
|
|
413
|
+
// ── Never deleted: a person typed it ──
|
|
414
|
+
// The cloud enrolment. Deleting it drops the machine out of cloud-managed
|
|
415
|
+
// policy silently — it keeps enforcing whatever it last had, reports healthy,
|
|
416
|
+
// and never reconciles again. Nothing re-derives a token.
|
|
417
|
+
{ path: credentialsFile, class: "user-typed" },
|
|
418
|
+
// Holds `daemon.configured` (the flag that makes the machine fail closed),
|
|
419
|
+
// the collector preferences, `[audit] auto`, the telemetry opt-out, and
|
|
420
|
+
// `collector.sources.*.extra_paths` — the entire output of `harness add-path`.
|
|
421
|
+
{ path: configFile, class: "user-typed" },
|
|
422
|
+
// The builtin enable/disable set and per-policy params. `resetHome` used to
|
|
423
|
+
// clear this and carry eight named keys back over; it is simply kept now.
|
|
424
|
+
{ path: globalPolicyConfigFile, class: "user-typed" },
|
|
425
|
+
// The user's own convention policies, the `lib/` they import and the data
|
|
426
|
+
// files they read. `at("policies")` was on the delete list once: hand-written
|
|
427
|
+
// source destroyed, while `isConfigured()` still read true so the wizard never
|
|
428
|
+
// re-asked and hooks kept firing against an empty policy set.
|
|
429
|
+
{ path: policiesDir, class: "user-typed" },
|
|
430
|
+
|
|
431
|
+
// ── Never deleted: recorded and not yet shipped ──
|
|
432
|
+
// Batches read out of transcripts and queued for upload. The reason losing
|
|
433
|
+
// these is PERMANENT and not merely slow is `cursorsDir` below: the watermark
|
|
434
|
+
// has already advanced past them, so nothing will ever read that range again.
|
|
435
|
+
{ path: spoolDir, class: "undelivered" },
|
|
436
|
+
{ path: failedDir, class: "undelivered" },
|
|
437
|
+
// The SDK spool (`events/` + `failed/`), same argument.
|
|
438
|
+
{ path: customAgentsDir, class: "undelivered" },
|
|
439
|
+
// The decision log the dashboard's activity tab reads. Neither derived nor
|
|
440
|
+
// re-fetchable: it is the record of what this machine did, and nothing
|
|
441
|
+
// regenerates it. Deleting its layout-1 parent threw away every decision a
|
|
442
|
+
// machine had recorded, which is why `migrateHookActivity()` exists.
|
|
443
|
+
{ path: hookActivityDir, class: "undelivered" },
|
|
444
|
+
// Requests the CLI wrote for the daemon to drain on its next tick. The file's
|
|
445
|
+
// existence IS the pending state, so deleting one silently cancels something
|
|
446
|
+
// a person asked for. Rust-only paths (`crates/failproofaid/src/paths.rs`),
|
|
447
|
+
// hence spelled here rather than exported — nothing on this side reads them.
|
|
448
|
+
{ path: (home) => resolve(stateDir(home), "flush-request.json"), class: "undelivered" },
|
|
449
|
+
{ path: (home) => resolve(stateDir(home), "backfill-request.json"), class: "undelivered" },
|
|
450
|
+
|
|
451
|
+
// ── Never deleted: it names the machine ──
|
|
452
|
+
// Per-source watermarks. Kept out of the reset so pages carried by
|
|
453
|
+
// `migrateHookActivity()` are not re-shipped in full — it MOVES them, which
|
|
454
|
+
// preserves the inode a cursor is keyed on. A cursor whose file is gone is
|
|
455
|
+
// inert (`retain_existing` drops it), so keeping them costs nothing.
|
|
456
|
+
{ path: cursorsDir, class: "identity" },
|
|
457
|
+
// The anonymous instance id both the CLI and the daemon report under. Tiers 1
|
|
458
|
+
// and 2 of `getInstanceId()` re-derive the same value, so most machines would
|
|
459
|
+
// survive losing it — but a machine that fell through to the daemon's own
|
|
460
|
+
// fallback would come back as a brand-new PostHog person, and no analysis
|
|
461
|
+
// spans that split.
|
|
462
|
+
{ path: telemetryIdFile, class: "identity" },
|
|
463
|
+
{ path: (home) => resolve(stateDir(home), "daemon-telemetry-id"), class: "identity" },
|
|
464
|
+
// The layout marker itself. Not user data, and `resetHome` rewrites it
|
|
465
|
+
// immediately — but listing it made a no-op reset report "removed 1 item" for
|
|
466
|
+
// a file it had just recreated.
|
|
467
|
+
{ path: versionFile, class: "identity" },
|
|
468
|
+
// The record of what this machine has been migrated through, and the copies a
|
|
469
|
+
// step took before running. A migration deleting its own audit trail would
|
|
470
|
+
// leave "what has this home been through?" answerable only by guessing, and
|
|
471
|
+
// deleting the backup is deleting the undo for the step that just ran.
|
|
472
|
+
{ path: migrationsDir, class: "identity" },
|
|
473
|
+
|
|
474
|
+
// ── May be dropped: rebuilt on demand ──
|
|
475
|
+
{ path: auditDir, class: "derived" },
|
|
476
|
+
{ path: collectorHealthFile, class: "derived" },
|
|
477
|
+
{ path: auditScheduleFile, class: "derived" },
|
|
478
|
+
{ path: codexSessionPathsFile, class: "derived" },
|
|
479
|
+
{ path: shimsDir, class: "derived" },
|
|
480
|
+
{ path: sessionPauseDir, class: "derived" },
|
|
481
|
+
{ path: logsDir, class: "derived" },
|
|
482
|
+
{ path: lastVersionFile, class: "derived" },
|
|
483
|
+
{ path: launcherMarker, class: "derived" },
|
|
484
|
+
{ path: onboardingLockFile, class: "derived" },
|
|
485
|
+
{ path: onboardingAttemptFile, class: "derived" },
|
|
486
|
+
|
|
487
|
+
// ── May be dropped: the server has it ──
|
|
488
|
+
// Re-fetched and digest-verified on the next daemon poll. This is the whole
|
|
489
|
+
// reason the delete list is per-entry rather than `rm -rf policies/`: one
|
|
490
|
+
// directory holds both the files a person wrote and the ones the fleet sent,
|
|
491
|
+
// and only the second kind may be thrown away.
|
|
492
|
+
{ path: cloudPoliciesDir, class: "refetchable" },
|
|
493
|
+
|
|
494
|
+
// ── Never touched ──
|
|
495
|
+
// A downloaded daemon binary is large, version-pinned and re-verified on use,
|
|
496
|
+
// so deleting it only forces a needless re-download.
|
|
497
|
+
{ path: binDir, class: "ephemeral" },
|
|
498
|
+
// Sockets and the singleton flock belong to a process that may be alive right
|
|
499
|
+
// now; removing them breaks it rather than resetting configuration.
|
|
500
|
+
{ path: runDir, class: "ephemeral" },
|
|
501
|
+
];
|
|
502
|
+
|
|
323
503
|
// ── Layout 1 (legacy) ────────────────────────────────────────────────────────
|
|
324
504
|
|
|
325
505
|
/**
|
|
@@ -385,11 +565,58 @@ export const legacy = {
|
|
|
385
565
|
* out something a future layout adds and this list has not been taught about
|
|
386
566
|
* — and so the function is auditable at a glance, which matters for anything
|
|
387
567
|
* that deletes user data.
|
|
568
|
+
*
|
|
569
|
+
* TWO HALVES, and they are not maintained the same way. The paths of layouts
|
|
570
|
+
* that no longer exist are listed by hand below, because a retired path has no
|
|
571
|
+
* definition left to hang a class off — it exists only in this file. The paths
|
|
572
|
+
* of the CURRENT layout are DERIVED from `HOME_CLASSES`, so a path that moves
|
|
573
|
+
* or is added cannot silently fall off (or onto) the list. See `HOME_CLASSES`
|
|
574
|
+
* for what each class means and which incidents the split is answering.
|
|
388
575
|
*/
|
|
389
576
|
export function resettablePaths(): string[] {
|
|
577
|
+
return [
|
|
578
|
+
...retiredLayoutPaths(),
|
|
579
|
+
// The current layout, by what each path HOLDS. `user-typed`, `undelivered`
|
|
580
|
+
// and `identity` are absent from this list by construction rather than by
|
|
581
|
+
// anyone remembering to leave them out.
|
|
582
|
+
...HOME_CLASSES.filter((e) => e.class === "derived" || e.class === "refetchable").map((e) =>
|
|
583
|
+
e.path(),
|
|
584
|
+
),
|
|
585
|
+
];
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
/**
|
|
589
|
+
* The paths of layouts this build no longer writes.
|
|
590
|
+
*
|
|
591
|
+
* Hand-listed, and they have to be: a retired path has no definition to carry a
|
|
592
|
+
* class, and `legacy` is the only place it still exists. Each entry is here
|
|
593
|
+
* because an upgrade would otherwise leave it behind — see the notes inline,
|
|
594
|
+
* every one of which records something that actually happened.
|
|
595
|
+
*
|
|
596
|
+
* Phase-splitting these per migration step is what the migration registry does
|
|
597
|
+
* with them next; until then they are one list because `resetHome` is one step.
|
|
598
|
+
*/
|
|
599
|
+
function retiredLayoutPaths(): string[] {
|
|
390
600
|
return [
|
|
391
601
|
// Layout 1
|
|
392
|
-
|
|
602
|
+
//
|
|
603
|
+
// NOT `legacy.policyConfig()`. It is `at("policies-config.json")` — the
|
|
604
|
+
// EXACT path layout 3 puts the live config back at, which `legacy`'s own
|
|
605
|
+
// note records and `detectLayout()` has a whole ordering rule about. Listing
|
|
606
|
+
// it here while `HOME_CLASSES` calls the same path `user-typed` would have
|
|
607
|
+
// the two halves of this function contradict each other, and the delete
|
|
608
|
+
// would win.
|
|
609
|
+
//
|
|
610
|
+
// Leaving it in place is also strictly better than what it replaced. The old
|
|
611
|
+
// sequence was delete-then-carry-eight-named-keys, so every key outside
|
|
612
|
+
// `CARRIED_POLICY_CONFIG_KEYS` was dropped on a layout-1 upgrade; now the
|
|
613
|
+
// file is simply not touched and keeps everything. `readCarriedPolicyConfig`
|
|
614
|
+
// is narrowed to layout 2's NESTED copy accordingly — that path really is
|
|
615
|
+
// deleted (`legacy.localPoliciesDir()`, below) and really does need carrying.
|
|
616
|
+
//
|
|
617
|
+
// The project-scope `policies-config.local.json` is a different file at a
|
|
618
|
+
// different path (`{cwd}/.failproofai/`, see `hooks-config.ts`); the global
|
|
619
|
+
// one below is a layout-1 artefact nothing reads.
|
|
393
620
|
legacy.policyConfigLocal(),
|
|
394
621
|
legacy.cloudCredentials(),
|
|
395
622
|
legacy.ingestCredentials(),
|
|
@@ -426,66 +653,53 @@ export function resettablePaths(): string[] {
|
|
|
426
653
|
// a `lib/` of helpers colliding with a stale `policies/lib/` was destroyed
|
|
427
654
|
// outright, and the policy that did move was left importing a file that no
|
|
428
655
|
// longer existed.
|
|
429
|
-
// The MACHINE-OWNED things, never the directory the user owns.
|
|
430
656
|
//
|
|
431
|
-
//
|
|
432
|
-
//
|
|
433
|
-
//
|
|
434
|
-
//
|
|
435
|
-
//
|
|
436
|
-
//
|
|
437
|
-
//
|
|
438
|
-
//
|
|
439
|
-
// was skipped and hooks kept firing against an empty policy set.
|
|
657
|
+
// Everything that used to follow here — `globalPolicyConfigFile()`,
|
|
658
|
+
// `cloudPoliciesDir()`, `at("state")`, `configFile()`, `credentialsFile()`,
|
|
659
|
+
// `auditDir()`, `customAgentsDir()`, `logsDir()` — was the CURRENT layout,
|
|
660
|
+
// hand-listed. It is derived from `HOME_CLASSES` now, and five of those
|
|
661
|
+
// entries stopped being deleted as a result, each for a reason recorded on
|
|
662
|
+
// its row: the cloud token, the whole of `config.json` (including the
|
|
663
|
+
// `extra_paths` a user typed), the undelivered spool, the SDK spool, and the
|
|
664
|
+
// machine's telemetry identity.
|
|
440
665
|
//
|
|
441
|
-
// `
|
|
442
|
-
//
|
|
443
|
-
//
|
|
444
|
-
//
|
|
445
|
-
//
|
|
446
|
-
//
|
|
447
|
-
//
|
|
448
|
-
//
|
|
666
|
+
// `at("state")` is the sharpest of them. It is MIXED — `spool/` and
|
|
667
|
+
// `telemetry-id` sit under it beside a dozen scratch files — so listing the
|
|
668
|
+
// parent is precisely how a reset came to delete events that were recorded,
|
|
669
|
+
// queued, and then unreachable forever, because `cursors/` deliberately
|
|
670
|
+
// survives and the watermark had already moved past them. Its scratch
|
|
671
|
+
// children are classified individually now and the parent is not listed at
|
|
672
|
+
// all, so anything under it this table has not been taught about survives
|
|
673
|
+
// rather than being swept up.
|
|
449
674
|
//
|
|
450
|
-
//
|
|
451
|
-
//
|
|
452
|
-
// also the destination `migratePolicyConfig()` carries layout 1's selection
|
|
453
|
-
// into, so the carry is written AFTER this list runs, and `resetHome` skips
|
|
454
|
-
// this entry when the reset is not a layout migration at all. See both.
|
|
675
|
+
// Two notes worth keeping from the old list, because they explain absences
|
|
676
|
+
// that still hold:
|
|
455
677
|
//
|
|
456
|
-
//
|
|
457
|
-
//
|
|
458
|
-
//
|
|
459
|
-
//
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
//
|
|
463
|
-
//
|
|
464
|
-
//
|
|
678
|
+
// `policies/` is `user-typed`, not absent by oversight. On layout 1 that
|
|
679
|
+
// directory IS the documented home for hand-written personal policies —
|
|
680
|
+
// `docs/configuration.mdx` names `~/.failproofai/policies/` as the user
|
|
681
|
+
// scope, and `manager.ts` read it. It stood on this list once: source files
|
|
682
|
+
// a person wrote, nothing regenerating them, nothing backing them up, and a
|
|
683
|
+
// reset message that named only "policy config, activity history and audit
|
|
684
|
+
// cache". Worse, the machine then reported itself configured —
|
|
685
|
+
// `isConfigured()` is a union that still sees the agent CLIs' untouched
|
|
686
|
+
// settings files — so the wizard was skipped and hooks kept firing against
|
|
687
|
+
// an empty policy set. Its `cloud-policies/` CHILD is `refetchable` and does
|
|
688
|
+
// still go, which is the whole reason this is a per-entry list and not
|
|
689
|
+
// `rm -rf policies/`.
|
|
690
|
+
//
|
|
691
|
+
// `cursors/` is `identity` for a reason load-bearing to the activity
|
|
692
|
+
// migration rather than a separate opinion. Cursors are keyed on
|
|
693
|
+
// `(device, inode)`; `migrateHookActivity()` MOVES pages, which preserves
|
|
465
694
|
// the inode, so a surviving cursor still points at the file it belongs to
|
|
466
695
|
// and resumes at the right offset. Delete the cursors and every carried page
|
|
467
|
-
// reads as new and re-ships in full —
|
|
468
|
-
//
|
|
469
|
-
//
|
|
470
|
-
|
|
471
|
-
//
|
|
472
|
-
//
|
|
473
|
-
//
|
|
474
|
-
//
|
|
475
|
-
configFile(),
|
|
476
|
-
credentialsFile(),
|
|
477
|
-
auditDir(),
|
|
478
|
-
// NOT hookActivityDir(). It is the DESTINATION `migrateHookActivity()` has
|
|
479
|
-
// just moved layout 1's log into, so listing it here deleted the migration
|
|
480
|
-
// moments after it happened — the reset runs every path in this list after
|
|
481
|
-
// the migrations. It is also the one directory here that is neither derived
|
|
482
|
-
// nor re-fetchable: a decision log is the record of what this machine did,
|
|
483
|
-
// and nothing regenerates it.
|
|
484
|
-
customAgentsDir(),
|
|
485
|
-
logsDir(),
|
|
486
|
-
// NOT bin/ — a downloaded daemon binary is large, version-pinned and
|
|
487
|
-
// re-verified on use, so deleting it only forces a needless re-download.
|
|
488
|
-
// NOT run/ — sockets belong to a running daemon; removing them out from
|
|
489
|
-
// under it breaks a live process rather than resetting configuration.
|
|
696
|
+
// reads as new and re-ships in full — the outcome the move exists to avoid.
|
|
697
|
+
// A cursor whose file is gone is inert (`retain_existing` drops it), so
|
|
698
|
+
// keeping them costs nothing when there is nothing to resume.
|
|
699
|
+
//
|
|
700
|
+
// And `hook-activity/` is `undelivered`, never listed: it is the DESTINATION
|
|
701
|
+
// `migrateHookActivity()` moves layout 1's log into, so listing it deleted
|
|
702
|
+
// the migration moments after it happened — the reset runs every path in
|
|
703
|
+
// this list after the migrations.
|
|
490
704
|
];
|
|
491
705
|
}
|