@getrift/rift 0.1.0-beta.18 → 0.1.0-beta.19
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/dist/src/capture/auto-repair.d.ts +110 -0
- package/dist/src/capture/auto-repair.d.ts.map +1 -0
- package/dist/src/capture/auto-repair.js +269 -0
- package/dist/src/capture/auto-repair.js.map +1 -0
- package/dist/src/capture/codex-cli-triage-provider.d.ts.map +1 -1
- package/dist/src/capture/codex-cli-triage-provider.js +4 -3
- package/dist/src/capture/codex-cli-triage-provider.js.map +1 -1
- package/dist/src/capture/recover-quarantine.d.ts +11 -0
- package/dist/src/capture/recover-quarantine.d.ts.map +1 -1
- package/dist/src/capture/recover-quarantine.js +30 -4
- package/dist/src/capture/recover-quarantine.js.map +1 -1
- package/dist/src/cli/commands/capture-recover.d.ts.map +1 -1
- package/dist/src/cli/commands/capture-recover.js +7 -0
- package/dist/src/cli/commands/capture-recover.js.map +1 -1
- package/dist/src/cli/commands/capture.d.ts.map +1 -1
- package/dist/src/cli/commands/capture.js +48 -1
- package/dist/src/cli/commands/capture.js.map +1 -1
- package/dist/src/cli/commands/feedback.d.ts +12 -0
- package/dist/src/cli/commands/feedback.d.ts.map +1 -1
- package/dist/src/cli/commands/feedback.js +84 -2
- package/dist/src/cli/commands/feedback.js.map +1 -1
- package/dist/src/cli/commands/onboard.d.ts +33 -2
- package/dist/src/cli/commands/onboard.d.ts.map +1 -1
- package/dist/src/cli/commands/onboard.js +243 -35
- package/dist/src/cli/commands/onboard.js.map +1 -1
- package/dist/src/cli/feedback/feedback-config.d.ts +43 -0
- package/dist/src/cli/feedback/feedback-config.d.ts.map +1 -1
- package/dist/src/cli/feedback/feedback-config.js +125 -4
- package/dist/src/cli/feedback/feedback-config.js.map +1 -1
- package/dist/src/cli/feedback/invite.d.ts +17 -0
- package/dist/src/cli/feedback/invite.d.ts.map +1 -0
- package/dist/src/cli/feedback/invite.js +67 -0
- package/dist/src/cli/feedback/invite.js.map +1 -0
- package/dist/src/cli/feedback/relay-secret-store.d.ts +32 -0
- package/dist/src/cli/feedback/relay-secret-store.d.ts.map +1 -0
- package/dist/src/cli/feedback/relay-secret-store.js +137 -0
- package/dist/src/cli/feedback/relay-secret-store.js.map +1 -0
- package/dist/src/cli/http-client.d.ts +17 -4
- package/dist/src/cli/http-client.d.ts.map +1 -1
- package/dist/src/cli/http-client.js +18 -7
- package/dist/src/cli/http-client.js.map +1 -1
- package/dist/src/cli/status/friend-header.d.ts.map +1 -1
- package/dist/src/cli/status/friend-header.js +63 -20
- package/dist/src/cli/status/friend-header.js.map +1 -1
- package/dist/src/config/schema.d.ts +79 -0
- package/dist/src/config/schema.d.ts.map +1 -1
- package/dist/src/config/schema.js +44 -0
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/diagnostics/codex-preflight.d.ts +33 -0
- package/dist/src/diagnostics/codex-preflight.d.ts.map +1 -0
- package/dist/src/diagnostics/codex-preflight.js +63 -0
- package/dist/src/diagnostics/codex-preflight.js.map +1 -0
- package/dist/src/diagnostics/doctor.d.ts +1 -1
- package/dist/src/diagnostics/doctor.d.ts.map +1 -1
- package/dist/src/diagnostics/doctor.js +69 -20
- package/dist/src/diagnostics/doctor.js.map +1 -1
- package/dist/src/diagnostics/repair-prompt.d.ts.map +1 -1
- package/dist/src/diagnostics/repair-prompt.js +10 -1
- package/dist/src/diagnostics/repair-prompt.js.map +1 -1
- package/dist/src/jobs/handlers/save.d.ts.map +1 -1
- package/dist/src/jobs/handlers/save.js +5 -4
- package/dist/src/jobs/handlers/save.js.map +1 -1
- package/dist/src/jobs/worker-entry.d.ts.map +1 -1
- package/dist/src/jobs/worker-entry.js +20 -7
- package/dist/src/jobs/worker-entry.js.map +1 -1
- package/dist/src/jobs/worker-process.d.ts +11 -0
- package/dist/src/jobs/worker-process.d.ts.map +1 -1
- package/dist/src/jobs/worker-process.js +37 -4
- package/dist/src/jobs/worker-process.js.map +1 -1
- package/dist/src/main.js +122 -42
- package/dist/src/main.js.map +1 -1
- package/dist/src/observability/onboarding-metric.d.ts +16 -0
- package/dist/src/observability/onboarding-metric.d.ts.map +1 -1
- package/dist/src/observability/onboarding-metric.js +8 -1
- package/dist/src/observability/onboarding-metric.js.map +1 -1
- package/dist/src/providers/codex-cli-metadata-extraction.d.ts +1 -0
- package/dist/src/providers/codex-cli-metadata-extraction.d.ts.map +1 -1
- package/dist/src/providers/codex-cli-metadata-extraction.js +6 -2
- package/dist/src/providers/codex-cli-metadata-extraction.js.map +1 -1
- package/dist/src/providers/codex-cli-model.d.ts +61 -0
- package/dist/src/providers/codex-cli-model.d.ts.map +1 -0
- package/dist/src/providers/codex-cli-model.js +194 -0
- package/dist/src/providers/codex-cli-model.js.map +1 -0
- package/dist/src/providers/codex-cli-runner.d.ts +16 -0
- package/dist/src/providers/codex-cli-runner.d.ts.map +1 -1
- package/dist/src/providers/codex-cli-runner.js +67 -12
- package/dist/src/providers/codex-cli-runner.js.map +1 -1
- package/dist/src/providers/conversation-generation.d.ts.map +1 -1
- package/dist/src/providers/conversation-generation.js +26 -13
- package/dist/src/providers/conversation-generation.js.map +1 -1
- package/dist/src/server/app.d.ts.map +1 -1
- package/dist/src/server/app.js +12 -8
- package/dist/src/server/app.js.map +1 -1
- package/dist/src/server/routes/friend-status.d.ts +37 -0
- package/dist/src/server/routes/friend-status.d.ts.map +1 -1
- package/dist/src/server/routes/friend-status.js +43 -9
- package/dist/src/server/routes/friend-status.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { type RecoverQuarantineDeps, type RecoveryReport } from "./recover-quarantine.js";
|
|
3
|
+
/**
|
|
4
|
+
* How many times a single parked session (at one fingerprint) is auto-retried
|
|
5
|
+
* before Rift stops and asks the user to run the manual repair. Low on purpose:
|
|
6
|
+
* the daemon retries roughly once per capture tick (hourly), so three attempts
|
|
7
|
+
* spans a few hours before declaring "could not save automatically", and the
|
|
8
|
+
* manual `rift doctor repair` path is always available regardless of budget.
|
|
9
|
+
*/
|
|
10
|
+
export declare const MAX_AUTO_REPAIR_ATTEMPTS = 3;
|
|
11
|
+
/**
|
|
12
|
+
* How long to stop attempting auto-repair after a pass fails ONLY because
|
|
13
|
+
* saving was down (Voyage revoked/outage — the save handler needs a valid
|
|
14
|
+
* Voyage key). This is an infrastructure backoff, distinct from the
|
|
15
|
+
* per-session retry budget: a save outage is not any one session's fault, so
|
|
16
|
+
* it must not exhaust a session (see `applyBudgetFromReport`), but it also
|
|
17
|
+
* shouldn't make the daemon re-summarize every parked session via Codex on
|
|
18
|
+
* every hourly tick for the whole outage. The cooldown bounds that cost to one
|
|
19
|
+
* pass per window; it is cleared early the moment a save succeeds. Sized to a
|
|
20
|
+
* few default capture ticks (interval default is 1h).
|
|
21
|
+
*/
|
|
22
|
+
export declare const SAVE_FAILURE_COOLDOWN_MS: number;
|
|
23
|
+
declare const RepairBudgetSchema: z.ZodObject<{
|
|
24
|
+
sessions: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
25
|
+
/** Failed auto-repair attempts for this session+fingerprint. */
|
|
26
|
+
attempts: z.ZodNumber;
|
|
27
|
+
last_attempt_at: z.ZodString;
|
|
28
|
+
last_error: z.ZodOptional<z.ZodString>;
|
|
29
|
+
}, "strip", z.ZodTypeAny, {
|
|
30
|
+
attempts: number;
|
|
31
|
+
last_attempt_at: string;
|
|
32
|
+
last_error?: string | undefined;
|
|
33
|
+
}, {
|
|
34
|
+
attempts: number;
|
|
35
|
+
last_attempt_at: string;
|
|
36
|
+
last_error?: string | undefined;
|
|
37
|
+
}>>>;
|
|
38
|
+
/**
|
|
39
|
+
* ISO timestamp until which auto-repair backs off because saving recently
|
|
40
|
+
* failed (infrastructure, not a session fault). Absent when not cooling down.
|
|
41
|
+
*/
|
|
42
|
+
save_blocked_until: z.ZodOptional<z.ZodString>;
|
|
43
|
+
}, "strip", z.ZodTypeAny, {
|
|
44
|
+
sessions: Record<string, {
|
|
45
|
+
attempts: number;
|
|
46
|
+
last_attempt_at: string;
|
|
47
|
+
last_error?: string | undefined;
|
|
48
|
+
}>;
|
|
49
|
+
save_blocked_until?: string | undefined;
|
|
50
|
+
}, {
|
|
51
|
+
sessions?: Record<string, {
|
|
52
|
+
attempts: number;
|
|
53
|
+
last_attempt_at: string;
|
|
54
|
+
last_error?: string | undefined;
|
|
55
|
+
}> | undefined;
|
|
56
|
+
save_blocked_until?: string | undefined;
|
|
57
|
+
}>;
|
|
58
|
+
export type RepairBudget = z.infer<typeof RepairBudgetSchema>;
|
|
59
|
+
export declare function loadRepairBudget(dataDir: string): RepairBudget;
|
|
60
|
+
export declare function saveRepairBudget(dataDir: string, budget: RepairBudget): Promise<void>;
|
|
61
|
+
/**
|
|
62
|
+
* Clear the global save-infra cooldown. Call this whenever ANY daemon save
|
|
63
|
+
* succeeds — a normal capture save proves the Voyage/save path is healthy
|
|
64
|
+
* again, which `maybeRunAutoRepair` can't observe on its own (it returns early
|
|
65
|
+
* while cooled down, so it never reaches a save to learn saving works). Without
|
|
66
|
+
* this, recovery would idle for up to the full cooldown window after an outage
|
|
67
|
+
* clears. Cheap and best-effort: a no-op (no write) when no cooldown is set.
|
|
68
|
+
*/
|
|
69
|
+
export declare function clearSaveFailureCooldown(dataDir: string): Promise<void>;
|
|
70
|
+
export interface ParkedClassification {
|
|
71
|
+
/** Total distinct parked sessions still un-recovered (state of the world). */
|
|
72
|
+
parked: number;
|
|
73
|
+
/** Parked sessions Rift is still auto-attempting (budget not exhausted). */
|
|
74
|
+
repairing: number;
|
|
75
|
+
/** Parked sessions whose retry budget is exhausted — need a manual save. */
|
|
76
|
+
failed: number;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Split the parked-oversized sessions into "Rift is still saving these" vs.
|
|
80
|
+
* "Rift gave up and the user must save these manually", using the retry
|
|
81
|
+
* budget. Drives the honest friend-facing status copy. Pure read — no IO
|
|
82
|
+
* beyond loading the quarantine records, recovery state, and budget.
|
|
83
|
+
*/
|
|
84
|
+
export declare function classifyParkedOversizedSessions(deps: Pick<RecoverQuarantineDeps, "dataDir" | "quarantineDir">, maxAttempts?: number): ParkedClassification;
|
|
85
|
+
/** Test-only: whether a background repair is currently running. */
|
|
86
|
+
export declare function isAutoRepairInFlight(): boolean;
|
|
87
|
+
export interface MaybeRunAutoRepairDeps {
|
|
88
|
+
/**
|
|
89
|
+
* Everything `runRecoverQuarantine` needs EXCEPT `skipSession` (this module
|
|
90
|
+
* supplies the budget gate). Provide the real Codex summarizer + a daemon
|
|
91
|
+
* `saveFn`; `dryRun` is never set here (auto-repair always saves).
|
|
92
|
+
*/
|
|
93
|
+
recover: Omit<RecoverQuarantineDeps, "skipSession" | "dryRun">;
|
|
94
|
+
/** Bounded retry ceiling; defaults to MAX_AUTO_REPAIR_ATTEMPTS. */
|
|
95
|
+
maxAttempts?: number;
|
|
96
|
+
/** Optional progress logger (daemon wires this to stderr). */
|
|
97
|
+
log?: (message: string) => void;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Run a background recovery pass over parked oversized sessions, if any are
|
|
101
|
+
* still within their retry budget and no repair is already running.
|
|
102
|
+
*
|
|
103
|
+
* Returns the recovery report, or null when nothing was attempted (already
|
|
104
|
+
* running, or no repairable sessions). Updates the retry budget from the
|
|
105
|
+
* report: a recovered session's budget entry is cleared, a failed session's
|
|
106
|
+
* attempt count is incremented (and exhausts after `maxAttempts`).
|
|
107
|
+
*/
|
|
108
|
+
export declare function maybeRunAutoRepair(deps: MaybeRunAutoRepairDeps): Promise<RecoveryReport | null>;
|
|
109
|
+
export {};
|
|
110
|
+
//# sourceMappingURL=auto-repair.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-repair.d.ts","sourceRoot":"","sources":["../../../src/capture/auto-repair.ts"],"names":[],"mappings":"AA8BA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,cAAc,EACpB,MAAM,yBAAyB,CAAC;AAEjC;;;;;;GAMG;AACH,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAE1C;;;;;;;;;;GAUG;AACH,eAAO,MAAM,wBAAwB,QAAqB,CAAC;AAW3D,QAAA,MAAM,kBAAkB;;QANtB,gEAAgE;;;;;;;;;;;;;IAQhE;;;OAGG;;;;;;;;;;;;;;;;EAEH,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAO9D,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,CAW9D;AAED,wBAAsB,gBAAgB,CACpC,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,YAAY,GACnB,OAAO,CAAC,IAAI,CAAC,CAGf;AAED;;;;;;;GAOG;AACH,wBAAsB,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAS7E;AAED,MAAM,WAAW,oBAAoB;IACnC,8EAA8E;IAC9E,MAAM,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,SAAS,EAAE,MAAM,CAAC;IAClB,4EAA4E;IAC5E,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;GAKG;AACH,wBAAgB,+BAA+B,CAC7C,IAAI,EAAE,IAAI,CAAC,qBAAqB,EAAE,SAAS,GAAG,eAAe,CAAC,EAC9D,WAAW,GAAE,MAAiC,GAC7C,oBAAoB,CActB;AAUD,mEAAmE;AACnE,wBAAgB,oBAAoB,IAAI,OAAO,CAE9C;AAED,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,OAAO,EAAE,IAAI,CAAC,qBAAqB,EAAE,aAAa,GAAG,QAAQ,CAAC,CAAC;IAC/D,mEAAmE;IACnE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED;;;;;;;;GAQG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,sBAAsB,GAC3B,OAAO,CAAC,cAAc,GAAG,IAAI,CAAC,CA8DhC"}
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Background self-repair for oversized Codex CLI sessions.
|
|
3
|
+
*
|
|
4
|
+
* Auto-capture parks sessions larger than `capture.codex_cli.max_session_bytes`
|
|
5
|
+
* in `data/quarantine/` rather than failing (see `auto-capture.ts`). Recovery
|
|
6
|
+
* — chunked summarize + one `/save` per session — already exists in
|
|
7
|
+
* `recover-quarantine.ts` and is reachable manually via
|
|
8
|
+
* `rift doctor repair capture-large-sessions`.
|
|
9
|
+
*
|
|
10
|
+
* This module makes that recovery happen ON ITS OWN so a friend never has to
|
|
11
|
+
* run the repair command. The daemon calls `maybeRunAutoRepair` after each
|
|
12
|
+
* capture run; it:
|
|
13
|
+
*
|
|
14
|
+
* 1. Reuses `runRecoverQuarantine` verbatim (no second recovery path), so
|
|
15
|
+
* idempotency and regrown-session replacement are preserved.
|
|
16
|
+
* 2. Bounds work with a per-session retry budget persisted to
|
|
17
|
+
* `data/quarantine-repair-budget.json`. A session that fails
|
|
18
|
+
* `MAX_AUTO_REPAIR_ATTEMPTS` times is no longer auto-attempted — it is
|
|
19
|
+
* surfaced to the user as a manual-fallback warning instead of being
|
|
20
|
+
* retried forever. The budget is keyed by `<sessionId>:<fingerprint>`,
|
|
21
|
+
* so a session that grows (new fingerprint) gets a fresh budget, exactly
|
|
22
|
+
* as recovery treats it as new work.
|
|
23
|
+
* 3. Never runs two repairs at once (a module-level in-flight guard), so an
|
|
24
|
+
* overlapping capture tick cannot launch a duplicate concurrent repair.
|
|
25
|
+
*
|
|
26
|
+
* The recovery itself is long (one Codex CLI call per chunk per session), so
|
|
27
|
+
* the daemon fires this without awaiting it — status/doctor reads stay fast.
|
|
28
|
+
*/
|
|
29
|
+
import fs from "node:fs";
|
|
30
|
+
import path from "node:path";
|
|
31
|
+
import { z } from "zod";
|
|
32
|
+
import { atomicWrite } from "../storage/atomic.js";
|
|
33
|
+
import { listParkedOversizedSessions, runRecoverQuarantine, } from "./recover-quarantine.js";
|
|
34
|
+
/**
|
|
35
|
+
* How many times a single parked session (at one fingerprint) is auto-retried
|
|
36
|
+
* before Rift stops and asks the user to run the manual repair. Low on purpose:
|
|
37
|
+
* the daemon retries roughly once per capture tick (hourly), so three attempts
|
|
38
|
+
* spans a few hours before declaring "could not save automatically", and the
|
|
39
|
+
* manual `rift doctor repair` path is always available regardless of budget.
|
|
40
|
+
*/
|
|
41
|
+
export const MAX_AUTO_REPAIR_ATTEMPTS = 3;
|
|
42
|
+
/**
|
|
43
|
+
* How long to stop attempting auto-repair after a pass fails ONLY because
|
|
44
|
+
* saving was down (Voyage revoked/outage — the save handler needs a valid
|
|
45
|
+
* Voyage key). This is an infrastructure backoff, distinct from the
|
|
46
|
+
* per-session retry budget: a save outage is not any one session's fault, so
|
|
47
|
+
* it must not exhaust a session (see `applyBudgetFromReport`), but it also
|
|
48
|
+
* shouldn't make the daemon re-summarize every parked session via Codex on
|
|
49
|
+
* every hourly tick for the whole outage. The cooldown bounds that cost to one
|
|
50
|
+
* pass per window; it is cleared early the moment a save succeeds. Sized to a
|
|
51
|
+
* few default capture ticks (interval default is 1h).
|
|
52
|
+
*/
|
|
53
|
+
export const SAVE_FAILURE_COOLDOWN_MS = 6 * 60 * 60 * 1000;
|
|
54
|
+
const REPAIR_BUDGET_FILE = "quarantine-repair-budget.json";
|
|
55
|
+
const RepairBudgetEntrySchema = z.object({
|
|
56
|
+
/** Failed auto-repair attempts for this session+fingerprint. */
|
|
57
|
+
attempts: z.number().int().nonnegative(),
|
|
58
|
+
last_attempt_at: z.string(),
|
|
59
|
+
last_error: z.string().optional(),
|
|
60
|
+
});
|
|
61
|
+
const RepairBudgetSchema = z.object({
|
|
62
|
+
sessions: z.record(z.string(), RepairBudgetEntrySchema).default({}),
|
|
63
|
+
/**
|
|
64
|
+
* ISO timestamp until which auto-repair backs off because saving recently
|
|
65
|
+
* failed (infrastructure, not a session fault). Absent when not cooling down.
|
|
66
|
+
*/
|
|
67
|
+
save_blocked_until: z.string().optional(),
|
|
68
|
+
});
|
|
69
|
+
/** Budget key — fingerprint-scoped so a regrown session retries fresh. */
|
|
70
|
+
function budgetKey(sessionId, fingerprint) {
|
|
71
|
+
return `${sessionId}:${fingerprint}`;
|
|
72
|
+
}
|
|
73
|
+
export function loadRepairBudget(dataDir) {
|
|
74
|
+
const file = path.join(dataDir, REPAIR_BUDGET_FILE);
|
|
75
|
+
if (!fs.existsSync(file))
|
|
76
|
+
return { sessions: {} };
|
|
77
|
+
let raw;
|
|
78
|
+
try {
|
|
79
|
+
raw = JSON.parse(fs.readFileSync(file, "utf-8"));
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return { sessions: {} };
|
|
83
|
+
}
|
|
84
|
+
const parsed = RepairBudgetSchema.safeParse(raw);
|
|
85
|
+
return parsed.success ? parsed.data : { sessions: {} };
|
|
86
|
+
}
|
|
87
|
+
export async function saveRepairBudget(dataDir, budget) {
|
|
88
|
+
const file = path.join(dataDir, REPAIR_BUDGET_FILE);
|
|
89
|
+
await atomicWrite(file, JSON.stringify(budget, null, 2));
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Clear the global save-infra cooldown. Call this whenever ANY daemon save
|
|
93
|
+
* succeeds — a normal capture save proves the Voyage/save path is healthy
|
|
94
|
+
* again, which `maybeRunAutoRepair` can't observe on its own (it returns early
|
|
95
|
+
* while cooled down, so it never reaches a save to learn saving works). Without
|
|
96
|
+
* this, recovery would idle for up to the full cooldown window after an outage
|
|
97
|
+
* clears. Cheap and best-effort: a no-op (no write) when no cooldown is set.
|
|
98
|
+
*/
|
|
99
|
+
export async function clearSaveFailureCooldown(dataDir) {
|
|
100
|
+
const budget = loadRepairBudget(dataDir);
|
|
101
|
+
if (budget.save_blocked_until === undefined)
|
|
102
|
+
return;
|
|
103
|
+
delete budget.save_blocked_until;
|
|
104
|
+
try {
|
|
105
|
+
await saveRepairBudget(dataDir, budget);
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
// best-effort
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Split the parked-oversized sessions into "Rift is still saving these" vs.
|
|
113
|
+
* "Rift gave up and the user must save these manually", using the retry
|
|
114
|
+
* budget. Drives the honest friend-facing status copy. Pure read — no IO
|
|
115
|
+
* beyond loading the quarantine records, recovery state, and budget.
|
|
116
|
+
*/
|
|
117
|
+
export function classifyParkedOversizedSessions(deps, maxAttempts = MAX_AUTO_REPAIR_ATTEMPTS) {
|
|
118
|
+
const parkedRecords = listParkedOversizedSessions(deps);
|
|
119
|
+
if (parkedRecords.length === 0) {
|
|
120
|
+
return { parked: 0, repairing: 0, failed: 0 };
|
|
121
|
+
}
|
|
122
|
+
const budget = loadRepairBudget(deps.dataDir);
|
|
123
|
+
let repairing = 0;
|
|
124
|
+
let failed = 0;
|
|
125
|
+
for (const record of parkedRecords) {
|
|
126
|
+
const entry = budget.sessions[budgetKey(record.session_id, record.fingerprint)];
|
|
127
|
+
if (entry && entry.attempts >= maxAttempts)
|
|
128
|
+
failed += 1;
|
|
129
|
+
else
|
|
130
|
+
repairing += 1;
|
|
131
|
+
}
|
|
132
|
+
return { parked: parkedRecords.length, repairing, failed };
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Module-level in-flight guard. A daemon is a single process, so a boolean
|
|
136
|
+
* flag is enough to ensure a long-running repair started by one capture tick
|
|
137
|
+
* is never duplicated by the next tick (or by the startup run overlapping the
|
|
138
|
+
* first interval). Reset in `finally` so a thrown repair doesn't wedge it.
|
|
139
|
+
*/
|
|
140
|
+
let repairInFlight = false;
|
|
141
|
+
/** Test-only: whether a background repair is currently running. */
|
|
142
|
+
export function isAutoRepairInFlight() {
|
|
143
|
+
return repairInFlight;
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Run a background recovery pass over parked oversized sessions, if any are
|
|
147
|
+
* still within their retry budget and no repair is already running.
|
|
148
|
+
*
|
|
149
|
+
* Returns the recovery report, or null when nothing was attempted (already
|
|
150
|
+
* running, or no repairable sessions). Updates the retry budget from the
|
|
151
|
+
* report: a recovered session's budget entry is cleared, a failed session's
|
|
152
|
+
* attempt count is incremented (and exhausts after `maxAttempts`).
|
|
153
|
+
*/
|
|
154
|
+
export async function maybeRunAutoRepair(deps) {
|
|
155
|
+
const log = deps.log ?? (() => { });
|
|
156
|
+
const maxAttempts = deps.maxAttempts ?? MAX_AUTO_REPAIR_ATTEMPTS;
|
|
157
|
+
const dataDir = deps.recover.dataDir;
|
|
158
|
+
if (repairInFlight) {
|
|
159
|
+
log("auto-repair: a repair is already running — skipping this tick");
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
const budget = loadRepairBudget(dataDir);
|
|
163
|
+
// Infrastructure backoff: a recent pass failed only because saving was down
|
|
164
|
+
// (Voyage). Don't re-summarize via Codex until the cooldown expires — a save
|
|
165
|
+
// outage that re-runs every tick is pure wasted cost. Cleared early when a
|
|
166
|
+
// save succeeds (see applyBudgetFromReport).
|
|
167
|
+
const nowMs = (deps.recover.now ? deps.recover.now() : new Date()).getTime();
|
|
168
|
+
const blockedUntilMs = budget.save_blocked_until
|
|
169
|
+
? Date.parse(budget.save_blocked_until)
|
|
170
|
+
: NaN;
|
|
171
|
+
if (!Number.isNaN(blockedUntilMs) && nowMs < blockedUntilMs) {
|
|
172
|
+
log(`auto-repair: saving recently failed — backing off until ${budget.save_blocked_until}`);
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
// Only attempt sessions still within budget. Exhausted ones are surfaced as
|
|
176
|
+
// a manual-fallback warning, not retried. Pass `deps.recover` so a caller
|
|
177
|
+
// that overrides `quarantineDir` is honored here too (not just inside
|
|
178
|
+
// `runRecoverQuarantine`), keeping the precheck and the recovery in sync.
|
|
179
|
+
const repairable = listParkedOversizedSessions(deps.recover).filter((record) => (budget.sessions[budgetKey(record.session_id, record.fingerprint)]?.attempts ?? 0) <
|
|
180
|
+
maxAttempts);
|
|
181
|
+
if (repairable.length === 0)
|
|
182
|
+
return null;
|
|
183
|
+
const repairableKeys = new Set(repairable.map((record) => budgetKey(record.session_id, record.fingerprint)));
|
|
184
|
+
repairInFlight = true;
|
|
185
|
+
log(`auto-repair: recovering ${repairable.length} parked Codex session${repairable.length === 1 ? "" : "s"} in the background`);
|
|
186
|
+
try {
|
|
187
|
+
const report = await runRecoverQuarantine({
|
|
188
|
+
...deps.recover,
|
|
189
|
+
skipSession: (record) => !repairableKeys.has(budgetKey(record.session_id, record.fingerprint)),
|
|
190
|
+
});
|
|
191
|
+
await applyBudgetFromReport(dataDir, report, deps.recover.now);
|
|
192
|
+
log(`auto-repair: ${report.recovered} recovered, ${report.failed + report.missing_source} could not be saved`);
|
|
193
|
+
return report;
|
|
194
|
+
}
|
|
195
|
+
finally {
|
|
196
|
+
repairInFlight = false;
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
/**
|
|
200
|
+
* Fold a recovery report into the retry budget: clear successes, increment
|
|
201
|
+
* failures. Re-reads the budget under the in-flight guard so it overlays the
|
|
202
|
+
* freshest on-disk value. Best-effort persistence — a budget write failure
|
|
203
|
+
* just means a session may get one extra attempt next tick, never a crash.
|
|
204
|
+
*/
|
|
205
|
+
async function applyBudgetFromReport(dataDir, report, now) {
|
|
206
|
+
const budget = loadRepairBudget(dataDir);
|
|
207
|
+
const nowDate = now ? now() : new Date();
|
|
208
|
+
const nowIso = nowDate.toISOString();
|
|
209
|
+
let changed = false;
|
|
210
|
+
for (const result of report.results) {
|
|
211
|
+
const key = budgetKey(result.session_id, result.fingerprint);
|
|
212
|
+
if (result.outcome === "recovered") {
|
|
213
|
+
if (budget.sessions[key]) {
|
|
214
|
+
delete budget.sessions[key];
|
|
215
|
+
changed = true;
|
|
216
|
+
}
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
// Only SESSION-LOCAL failures count against the budget: a chunk that won't
|
|
220
|
+
// summarize, or a session that parses to nothing. These are intrinsic to
|
|
221
|
+
// this session — retrying forever won't help, so cap them.
|
|
222
|
+
//
|
|
223
|
+
// A `save_failed` is deliberately NOT budgeted: the save path needs Voyage
|
|
224
|
+
// (the queue's save handler throws "save requires VOYAGE_API_KEY"), so a
|
|
225
|
+
// missing/revoked key or a Voyage outage makes EVERY session's save fail —
|
|
226
|
+
// an infrastructure problem, not the session's fault. Budgeting it would
|
|
227
|
+
// exhaust a session during the outage and then refuse to self-repair once
|
|
228
|
+
// the key is fixed, breaking the whole point of background recovery. Left
|
|
229
|
+
// un-budgeted, the session stays "repairing" and is retried on the next
|
|
230
|
+
// tick, so it self-heals the moment saving works again. (`missing_source`
|
|
231
|
+
// never reaches here — `listParkedOversizedSessions` already excludes a
|
|
232
|
+
// session whose jsonl is gone, so it's neither attempted nor classified.)
|
|
233
|
+
if (result.outcome === "failed" &&
|
|
234
|
+
(result.reason === "summarize_failed" || result.reason === "empty_session")) {
|
|
235
|
+
const prior = budget.sessions[key];
|
|
236
|
+
budget.sessions[key] = {
|
|
237
|
+
attempts: (prior?.attempts ?? 0) + 1,
|
|
238
|
+
last_attempt_at: nowIso,
|
|
239
|
+
...(result.error ? { last_error: result.error } : {}),
|
|
240
|
+
};
|
|
241
|
+
changed = true;
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
// Global save-infra cooldown. A save success proves the path works → clear
|
|
245
|
+
// any cooldown immediately. Otherwise, if this pass failed only because
|
|
246
|
+
// saving was down, start (or refresh) the backoff so we don't re-summarize
|
|
247
|
+
// every tick during a Voyage outage.
|
|
248
|
+
const anyRecovered = report.results.some((r) => r.outcome === "recovered");
|
|
249
|
+
const anySaveFailed = report.results.some((r) => r.outcome === "failed" && r.reason === "save_failed");
|
|
250
|
+
if (anyRecovered) {
|
|
251
|
+
if (budget.save_blocked_until !== undefined) {
|
|
252
|
+
delete budget.save_blocked_until;
|
|
253
|
+
changed = true;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
else if (anySaveFailed) {
|
|
257
|
+
budget.save_blocked_until = new Date(nowDate.getTime() + SAVE_FAILURE_COOLDOWN_MS).toISOString();
|
|
258
|
+
changed = true;
|
|
259
|
+
}
|
|
260
|
+
if (changed) {
|
|
261
|
+
try {
|
|
262
|
+
await saveRepairBudget(dataDir, budget);
|
|
263
|
+
}
|
|
264
|
+
catch {
|
|
265
|
+
// best-effort
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
//# sourceMappingURL=auto-repair.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auto-repair.js","sourceRoot":"","sources":["../../../src/capture/auto-repair.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex-cli-triage-provider.d.ts","sourceRoot":"","sources":["../../../src/capture/codex-cli-triage-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,YAAY,EAClB,MAAM,sBAAsB,CAAC;AAK9B,OAAO,KAAK,EACV,2BAA2B,EAC3B,UAAU,EACX,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"codex-cli-triage-provider.d.ts","sourceRoot":"","sources":["../../../src/capture/codex-cli-triage-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,WAAW,EAChB,KAAK,YAAY,EAClB,MAAM,sBAAsB,CAAC;AAK9B,OAAO,KAAK,EACV,2BAA2B,EAC3B,UAAU,EACX,MAAM,mBAAmB,CAAC;AAiD3B,qBAAa,sBAAuB,YAAW,2BAA2B;IAEtE,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,GAAE;QACxB,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,SAAS,CAAC,EAAE,MAAM,CAAC;KACf;IAGR,kBAAkB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM;IAIzC,MAAM,CAAC,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IAKjD,cAAc,CAClB,KAAK,EAAE,WAAW,GACjB,OAAO,CAAC;QAAE,MAAM,EAAE,YAAY,CAAC;QAAC,IAAI,EAAE,UAAU,CAAA;KAAE,CAAC;YA+BxC,SAAS;CAoCxB"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { TRIAGE_VERSION, } from "./triage-provider.js";
|
|
2
2
|
import { scoreHistoricalTriage, } from "./triage-lane.js";
|
|
3
|
-
import {
|
|
3
|
+
import { CODEX_CLI_OVERRIDE_PROVIDER } from "../providers/operator-overrides.js";
|
|
4
4
|
import { runCodexCliJson } from "../providers/codex-cli-runner.js";
|
|
5
5
|
const TRIAGE_PROMPT = `You are a triage classifier for a personal knowledge base. Given a conversation between a user and an AI assistant, decide whether it should be saved to long-term memory.
|
|
6
6
|
|
|
@@ -67,7 +67,7 @@ export class CodexCliTriageProvider {
|
|
|
67
67
|
summary: parsed.summary,
|
|
68
68
|
topics: parsed.topics,
|
|
69
69
|
rationale: parsed.rationale,
|
|
70
|
-
model:
|
|
70
|
+
model: parsed.model,
|
|
71
71
|
provider: CODEX_CLI_OVERRIDE_PROVIDER,
|
|
72
72
|
version: TRIAGE_VERSION,
|
|
73
73
|
score_breakdown: scoring.debug.score_breakdown,
|
|
@@ -78,7 +78,7 @@ export class CodexCliTriageProvider {
|
|
|
78
78
|
}
|
|
79
79
|
async runPrompt(input) {
|
|
80
80
|
const prompt = `${TRIAGE_PROMPT}${input.content}`;
|
|
81
|
-
const { output } = await runCodexCliJson({
|
|
81
|
+
const { output, model } = await runCodexCliJson({
|
|
82
82
|
prompt,
|
|
83
83
|
schema: TRIAGE_OUTPUT_SCHEMA,
|
|
84
84
|
...(this.options.cwd ? { cwd: this.options.cwd } : {}),
|
|
@@ -103,6 +103,7 @@ export class CodexCliTriageProvider {
|
|
|
103
103
|
summary: String(output.summary ?? ""),
|
|
104
104
|
topics: Array.isArray(output.topics) ? output.topics.map(String) : [],
|
|
105
105
|
rationale: String(output.rationale ?? ""),
|
|
106
|
+
model,
|
|
106
107
|
};
|
|
107
108
|
}
|
|
108
109
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codex-cli-triage-provider.js","sourceRoot":"","sources":["../../../src/capture/codex-cli-triage-provider.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,cAAc,GAGf,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EACL,qBAAqB,GAEtB,MAAM,kBAAkB,CAAC;AAK1B,OAAO,
|
|
1
|
+
{"version":3,"file":"codex-cli-triage-provider.js","sourceRoot":"","sources":["../../../src/capture/codex-cli-triage-provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -186,6 +186,16 @@ export interface RecoverQuarantineDeps {
|
|
|
186
186
|
dryRun?: boolean;
|
|
187
187
|
/** Optional clock for deterministic tests. */
|
|
188
188
|
now?: () => Date;
|
|
189
|
+
/**
|
|
190
|
+
* Optional per-session gate. When it returns true for a grouped record,
|
|
191
|
+
* that session is skipped entirely — not attempted, not summarized, not
|
|
192
|
+
* added to the report. The background auto-repair caller uses this to
|
|
193
|
+
* exclude sessions whose bounded retry budget is exhausted, so a
|
|
194
|
+
* permanently-failing session cannot be retried forever. The manual
|
|
195
|
+
* `rift doctor repair capture-large-sessions` path passes no gate, so its
|
|
196
|
+
* behavior (including regrown-session replacement) is unchanged.
|
|
197
|
+
*/
|
|
198
|
+
skipSession?: (record: QuarantineRecord) => boolean;
|
|
189
199
|
}
|
|
190
200
|
/**
|
|
191
201
|
* Read all Codex-CLI quarantine records under the configured directory.
|
|
@@ -222,6 +232,7 @@ export declare function saveRecoveryState(deps: Pick<RecoverQuarantineDeps, "dat
|
|
|
222
232
|
* surface a "run recovery" advisory that can never clear — recovery cannot
|
|
223
233
|
* recover a file that's gone.
|
|
224
234
|
*/
|
|
235
|
+
export declare function listParkedOversizedSessions(deps: Pick<RecoverQuarantineDeps, "dataDir" | "quarantineDir">): QuarantineRecord[];
|
|
225
236
|
export declare function countParkedOversizedSessions(deps: Pick<RecoverQuarantineDeps, "dataDir" | "quarantineDir">): number;
|
|
226
237
|
/**
|
|
227
238
|
* Split parser-emitted Codex content into byte-budgeted chunks at turn
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recover-quarantine.d.ts","sourceRoot":"","sources":["../../../src/capture/recover-quarantine.ts"],"names":[],"mappings":"AA8BA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAUxB;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,QAAa,CAAC;AAEvD,4EAA4E;AAC5E,eAAO,MAAM,wBAAwB,QAAY,CAAC;AAElD,eAAO,MAAM,gBAAgB,mCAAmC,CAAC;AAEjE,QAAA,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;EAS1B,CAAC;
|
|
1
|
+
{"version":3,"file":"recover-quarantine.d.ts","sourceRoot":"","sources":["../../../src/capture/recover-quarantine.ts"],"names":[],"mappings":"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"}
|
|
@@ -55,6 +55,20 @@ const QuarantineRecordSchema = z.object({
|
|
|
55
55
|
reason: z.string(),
|
|
56
56
|
quarantined_at: z.string(),
|
|
57
57
|
});
|
|
58
|
+
// The save/ingest *failure* path quarantines into the SAME `data/quarantine/`
|
|
59
|
+
// dir under the SAME `{source}_{timestamp}_{hash}.json` naming, so its records
|
|
60
|
+
// land in our glob. They are valid records of a different kind (a save/parse
|
|
61
|
+
// failure, shaped `{ payload | conversation_id, error, quarantined_at }`), not
|
|
62
|
+
// oversized-session recovery records — the discriminator is the `error` field,
|
|
63
|
+
// which oversized-session records never carry. We skip them SILENTLY (logging
|
|
64
|
+
// them as "malformed" every recovery pass spams the daemon log). Genuinely
|
|
65
|
+
// broken JSON / unknown shapes still log. A durable fix is to namespace the two
|
|
66
|
+
// quarantine kinds into separate dirs/prefixes so they can't collide — tracked
|
|
67
|
+
// as a follow-up; this is the low-risk loader-side guard.
|
|
68
|
+
const ForeignFailureQuarantineSchema = z.object({
|
|
69
|
+
error: z.string(),
|
|
70
|
+
quarantined_at: z.string(),
|
|
71
|
+
});
|
|
58
72
|
const RecoveredEntrySchema = z.object({
|
|
59
73
|
recovered_at: z.string(),
|
|
60
74
|
fingerprint: z.string(),
|
|
@@ -101,6 +115,10 @@ export function loadQuarantineRecords(deps) {
|
|
|
101
115
|
}
|
|
102
116
|
const result = QuarantineRecordSchema.safeParse(parsed);
|
|
103
117
|
if (!result.success) {
|
|
118
|
+
// A save/ingest failure record sharing this dir+naming is valid, just
|
|
119
|
+
// not ours — skip it without the per-pass "malformed" noise.
|
|
120
|
+
if (ForeignFailureQuarantineSchema.safeParse(parsed).success)
|
|
121
|
+
continue;
|
|
104
122
|
process.stderr.write(`recover-quarantine: skipping malformed record ${entry.name}\n`);
|
|
105
123
|
continue;
|
|
106
124
|
}
|
|
@@ -168,12 +186,12 @@ export async function saveRecoveryState(deps, state) {
|
|
|
168
186
|
* surface a "run recovery" advisory that can never clear — recovery cannot
|
|
169
187
|
* recover a file that's gone.
|
|
170
188
|
*/
|
|
171
|
-
export function
|
|
189
|
+
export function listParkedOversizedSessions(deps) {
|
|
172
190
|
const grouped = groupBySession(loadQuarantineRecords(deps));
|
|
173
191
|
if (grouped.length === 0)
|
|
174
|
-
return
|
|
192
|
+
return [];
|
|
175
193
|
const state = loadRecoveryState(deps);
|
|
176
|
-
|
|
194
|
+
const parked = [];
|
|
177
195
|
for (const record of grouped) {
|
|
178
196
|
const prior = state.recovered[recoveryKey(record.session_id)];
|
|
179
197
|
const covered = prior !== undefined && prior.fingerprint === record.fingerprint;
|
|
@@ -181,10 +199,13 @@ export function countParkedOversizedSessions(deps) {
|
|
|
181
199
|
continue;
|
|
182
200
|
if (!fs.existsSync(record.session_path))
|
|
183
201
|
continue;
|
|
184
|
-
parked
|
|
202
|
+
parked.push(record);
|
|
185
203
|
}
|
|
186
204
|
return parked;
|
|
187
205
|
}
|
|
206
|
+
export function countParkedOversizedSessions(deps) {
|
|
207
|
+
return listParkedOversizedSessions(deps).length;
|
|
208
|
+
}
|
|
188
209
|
/**
|
|
189
210
|
* Split parser-emitted Codex content into byte-budgeted chunks at turn
|
|
190
211
|
* boundaries. The parser format is `User: …\n\nAssistant: …\n\n…`, so
|
|
@@ -282,6 +303,11 @@ export async function runRecoverQuarantine(deps) {
|
|
|
282
303
|
};
|
|
283
304
|
for (const record of grouped) {
|
|
284
305
|
const key = recoveryKey(record.session_id);
|
|
306
|
+
// Caller-supplied gate (background auto-repair excludes budget-exhausted
|
|
307
|
+
// sessions). Skipped sessions are entirely invisible to the report so a
|
|
308
|
+
// gated-out session never inflates skipped/failed counts.
|
|
309
|
+
if (deps.skipSession?.(record))
|
|
310
|
+
continue;
|
|
285
311
|
// Skip only when the stored fingerprint matches the latest grouped
|
|
286
312
|
// fingerprint. A different fingerprint means the session has grown
|
|
287
313
|
// (or otherwise mutated) since the last recovery, so we re-recover
|