crewly 1.20.198 → 1.20.199

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 (120) hide show
  1. package/dist/backend/backend/src/constants.d.ts +16 -0
  2. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  3. package/dist/backend/backend/src/constants.js +16 -0
  4. package/dist/backend/backend/src/constants.js.map +1 -1
  5. package/dist/backend/backend/src/controllers/system/usage.controller.d.ts +14 -0
  6. package/dist/backend/backend/src/controllers/system/usage.controller.d.ts.map +1 -1
  7. package/dist/backend/backend/src/controllers/system/usage.controller.js +35 -1
  8. package/dist/backend/backend/src/controllers/system/usage.controller.js.map +1 -1
  9. package/dist/backend/backend/src/index.d.ts.map +1 -1
  10. package/dist/backend/backend/src/index.js +11 -2
  11. package/dist/backend/backend/src/index.js.map +1 -1
  12. package/dist/backend/backend/src/services/experiments/experiment.service.d.ts +15 -1
  13. package/dist/backend/backend/src/services/experiments/experiment.service.d.ts.map +1 -1
  14. package/dist/backend/backend/src/services/experiments/experiment.service.js +41 -12
  15. package/dist/backend/backend/src/services/experiments/experiment.service.js.map +1 -1
  16. package/dist/backend/backend/src/services/messaging/message-queue.service.d.ts +21 -0
  17. package/dist/backend/backend/src/services/messaging/message-queue.service.d.ts.map +1 -1
  18. package/dist/backend/backend/src/services/messaging/message-queue.service.js +86 -11
  19. package/dist/backend/backend/src/services/messaging/message-queue.service.js.map +1 -1
  20. package/dist/backend/backend/src/services/messaging/sub-agent-message-queue.service.d.ts +4 -0
  21. package/dist/backend/backend/src/services/messaging/sub-agent-message-queue.service.d.ts.map +1 -1
  22. package/dist/backend/backend/src/services/messaging/sub-agent-message-queue.service.js +58 -15
  23. package/dist/backend/backend/src/services/messaging/sub-agent-message-queue.service.js.map +1 -1
  24. package/dist/backend/backend/src/services/monitoring/antigravity-usage-sync.service.d.ts +7 -0
  25. package/dist/backend/backend/src/services/monitoring/antigravity-usage-sync.service.d.ts.map +1 -1
  26. package/dist/backend/backend/src/services/monitoring/antigravity-usage-sync.service.js +21 -6
  27. package/dist/backend/backend/src/services/monitoring/antigravity-usage-sync.service.js.map +1 -1
  28. package/dist/backend/backend/src/services/monitoring/claude-transcript-sync.service.d.ts +49 -2
  29. package/dist/backend/backend/src/services/monitoring/claude-transcript-sync.service.d.ts.map +1 -1
  30. package/dist/backend/backend/src/services/monitoring/claude-transcript-sync.service.js +160 -55
  31. package/dist/backend/backend/src/services/monitoring/claude-transcript-sync.service.js.map +1 -1
  32. package/dist/backend/backend/src/services/monitoring/codex-rollout-sync.service.d.ts +7 -0
  33. package/dist/backend/backend/src/services/monitoring/codex-rollout-sync.service.d.ts.map +1 -1
  34. package/dist/backend/backend/src/services/monitoring/codex-rollout-sync.service.js +21 -7
  35. package/dist/backend/backend/src/services/monitoring/codex-rollout-sync.service.js.map +1 -1
  36. package/dist/backend/backend/src/services/monitoring/token-usage.service.d.ts +71 -1
  37. package/dist/backend/backend/src/services/monitoring/token-usage.service.d.ts.map +1 -1
  38. package/dist/backend/backend/src/services/monitoring/token-usage.service.js +193 -20
  39. package/dist/backend/backend/src/services/monitoring/token-usage.service.js.map +1 -1
  40. package/dist/backend/backend/src/services/slack/slack-agent-identity.service.d.ts.map +1 -1
  41. package/dist/backend/backend/src/services/slack/slack-agent-identity.service.js +5 -0
  42. package/dist/backend/backend/src/services/slack/slack-agent-identity.service.js.map +1 -1
  43. package/dist/backend/backend/src/services/slack/slack-cloud-config.service.d.ts.map +1 -1
  44. package/dist/backend/backend/src/services/slack/slack-cloud-config.service.js +5 -0
  45. package/dist/backend/backend/src/services/slack/slack-cloud-config.service.js.map +1 -1
  46. package/dist/backend/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
  47. package/dist/backend/backend/src/services/slack/slack-team-channel.service.js +5 -0
  48. package/dist/backend/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
  49. package/dist/backend/backend/src/services/spend/spend-cap.service.d.ts +24 -1
  50. package/dist/backend/backend/src/services/spend/spend-cap.service.d.ts.map +1 -1
  51. package/dist/backend/backend/src/services/spend/spend-cap.service.js +57 -0
  52. package/dist/backend/backend/src/services/spend/spend-cap.service.js.map +1 -1
  53. package/dist/backend/backend/src/services/spend/spend-cap.store.d.ts +37 -1
  54. package/dist/backend/backend/src/services/spend/spend-cap.store.d.ts.map +1 -1
  55. package/dist/backend/backend/src/services/spend/spend-cap.store.js +85 -14
  56. package/dist/backend/backend/src/services/spend/spend-cap.store.js.map +1 -1
  57. package/dist/backend/backend/src/services/spend/spend-cap.wiring.d.ts.map +1 -1
  58. package/dist/backend/backend/src/services/spend/spend-cap.wiring.js +1 -1
  59. package/dist/backend/backend/src/services/spend/spend-cap.wiring.js.map +1 -1
  60. package/dist/backend/backend/src/services/trace/trace-store.d.ts +3 -1
  61. package/dist/backend/backend/src/services/trace/trace-store.d.ts.map +1 -1
  62. package/dist/backend/backend/src/services/trace/trace-store.js +27 -15
  63. package/dist/backend/backend/src/services/trace/trace-store.js.map +1 -1
  64. package/dist/backend/backend/src/services/usage/usage-backfill.service.d.ts +96 -0
  65. package/dist/backend/backend/src/services/usage/usage-backfill.service.d.ts.map +1 -0
  66. package/dist/backend/backend/src/services/usage/usage-backfill.service.js +257 -0
  67. package/dist/backend/backend/src/services/usage/usage-backfill.service.js.map +1 -0
  68. package/dist/backend/backend/src/services/v3/kr-tracking.service.d.ts.map +1 -1
  69. package/dist/backend/backend/src/services/v3/kr-tracking.service.js +2 -1
  70. package/dist/backend/backend/src/services/v3/kr-tracking.service.js.map +1 -1
  71. package/dist/backend/backend/src/services/v3/okr-cascade.service.d.ts.map +1 -1
  72. package/dist/backend/backend/src/services/v3/okr-cascade.service.js +2 -1
  73. package/dist/backend/backend/src/services/v3/okr-cascade.service.js.map +1 -1
  74. package/dist/backend/backend/src/services/workflow/cron-task.service.d.ts +28 -0
  75. package/dist/backend/backend/src/services/workflow/cron-task.service.d.ts.map +1 -1
  76. package/dist/backend/backend/src/services/workflow/cron-task.service.js +121 -68
  77. package/dist/backend/backend/src/services/workflow/cron-task.service.js.map +1 -1
  78. package/dist/backend/backend/src/utils/file-io.utils.d.ts +114 -1
  79. package/dist/backend/backend/src/utils/file-io.utils.d.ts.map +1 -1
  80. package/dist/backend/backend/src/utils/file-io.utils.js +236 -6
  81. package/dist/backend/backend/src/utils/file-io.utils.js.map +1 -1
  82. package/dist/backend/build-info.json +2 -2
  83. package/dist/cli/backend/src/constants.d.ts +16 -0
  84. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  85. package/dist/cli/backend/src/constants.js +16 -0
  86. package/dist/cli/backend/src/constants.js.map +1 -1
  87. package/dist/cli/backend/src/services/messaging/message-queue.service.d.ts +21 -0
  88. package/dist/cli/backend/src/services/messaging/message-queue.service.d.ts.map +1 -1
  89. package/dist/cli/backend/src/services/messaging/message-queue.service.js +86 -11
  90. package/dist/cli/backend/src/services/messaging/message-queue.service.js.map +1 -1
  91. package/dist/cli/backend/src/services/messaging/sub-agent-message-queue.service.d.ts +4 -0
  92. package/dist/cli/backend/src/services/messaging/sub-agent-message-queue.service.d.ts.map +1 -1
  93. package/dist/cli/backend/src/services/messaging/sub-agent-message-queue.service.js +58 -15
  94. package/dist/cli/backend/src/services/messaging/sub-agent-message-queue.service.js.map +1 -1
  95. package/dist/cli/backend/src/services/monitoring/token-usage.service.d.ts +71 -1
  96. package/dist/cli/backend/src/services/monitoring/token-usage.service.d.ts.map +1 -1
  97. package/dist/cli/backend/src/services/monitoring/token-usage.service.js +193 -20
  98. package/dist/cli/backend/src/services/monitoring/token-usage.service.js.map +1 -1
  99. package/dist/cli/backend/src/services/slack/slack-agent-identity.service.d.ts.map +1 -1
  100. package/dist/cli/backend/src/services/slack/slack-agent-identity.service.js +5 -0
  101. package/dist/cli/backend/src/services/slack/slack-agent-identity.service.js.map +1 -1
  102. package/dist/cli/backend/src/services/slack/slack-team-channel.service.d.ts.map +1 -1
  103. package/dist/cli/backend/src/services/slack/slack-team-channel.service.js +5 -0
  104. package/dist/cli/backend/src/services/slack/slack-team-channel.service.js.map +1 -1
  105. package/dist/cli/backend/src/services/trace/trace-store.d.ts +3 -1
  106. package/dist/cli/backend/src/services/trace/trace-store.d.ts.map +1 -1
  107. package/dist/cli/backend/src/services/trace/trace-store.js +27 -15
  108. package/dist/cli/backend/src/services/trace/trace-store.js.map +1 -1
  109. package/dist/cli/backend/src/services/v3/kr-tracking.service.d.ts.map +1 -1
  110. package/dist/cli/backend/src/services/v3/kr-tracking.service.js +2 -1
  111. package/dist/cli/backend/src/services/v3/kr-tracking.service.js.map +1 -1
  112. package/dist/cli/backend/src/services/workflow/cron-task.service.d.ts +28 -0
  113. package/dist/cli/backend/src/services/workflow/cron-task.service.d.ts.map +1 -1
  114. package/dist/cli/backend/src/services/workflow/cron-task.service.js +121 -68
  115. package/dist/cli/backend/src/services/workflow/cron-task.service.js.map +1 -1
  116. package/dist/cli/backend/src/utils/file-io.utils.d.ts +114 -1
  117. package/dist/cli/backend/src/utils/file-io.utils.d.ts.map +1 -1
  118. package/dist/cli/backend/src/utils/file-io.utils.js +236 -6
  119. package/dist/cli/backend/src/utils/file-io.utils.js.map +1 -1
  120. package/package.json +1 -1
@@ -13,8 +13,37 @@
13
13
  */
14
14
  export interface FileIOLogger {
15
15
  warn(message: string, meta?: Record<string, unknown>): void;
16
+ error?(message: string, meta?: Record<string, unknown>): void;
16
17
  debug?(message: string, meta?: Record<string, unknown>): void;
17
18
  }
19
+ /**
20
+ * A JSON store file exists but cannot be read or parsed, AND it could not be
21
+ * copied aside. The caller must not overwrite it: that would destroy the only
22
+ * copy of whatever it still holds (the 2026-10-03 token-ledger loss).
23
+ */
24
+ export declare class CorruptJsonFileError extends Error {
25
+ /** The store file that is bad */
26
+ readonly filePath: string;
27
+ /** Why it could not be used (parse or read error) */
28
+ readonly reason: string;
29
+ /**
30
+ * @param filePath - The bad store file
31
+ * @param reason - Parse / read error text
32
+ * @param copyError - Why copying it aside failed
33
+ */
34
+ constructor(filePath: string, reason: string, copyError: string);
35
+ }
36
+ /** Result of {@link readJsonStore} / {@link readJsonStoreSync}. */
37
+ export type JsonStoreRead<T> = {
38
+ status: 'missing';
39
+ } | {
40
+ status: 'ok';
41
+ data: T;
42
+ } | {
43
+ status: 'quarantined';
44
+ quarantinedTo: string;
45
+ reason: string;
46
+ };
18
47
  /**
19
48
  * Ensures a directory exists, creating it recursively if necessary.
20
49
  *
@@ -62,12 +91,96 @@ export declare function atomicWriteFile(filePath: string, content: string): Prom
62
91
  * @param data - Value to serialize (via `JSON.stringify`)
63
92
  */
64
93
  export declare function atomicWriteJson<T>(filePath: string, data: T): Promise<void>;
94
+ /**
95
+ * Synchronous {@link atomicWriteFile} for stores that persist synchronously
96
+ * (temp file in the same directory → fsync → rename).
97
+ *
98
+ * A failure (ENOSPC, EACCES) leaves the destination untouched, removes the
99
+ * temp file and rethrows. No in-process lock: a synchronous call cannot
100
+ * interleave with another one in the same process.
101
+ *
102
+ * **Precondition:** the parent directory must already exist.
103
+ *
104
+ * @param filePath - Destination file path
105
+ * @param content - String content to write
106
+ */
107
+ export declare function atomicWriteFileSync(filePath: string, content: string): void;
108
+ /**
109
+ * Where a bad store file is copied: `<file>.corrupt-<ISO timestamp>`
110
+ * (colons and dots replaced so the name is valid everywhere).
111
+ *
112
+ * @param filePath - Store file
113
+ * @param now - Clock (tests)
114
+ * @returns Quarantine path
115
+ */
116
+ export declare function quarantinePathFor(filePath: string, now?: Date): string;
117
+ /**
118
+ * Copy a store file that cannot be used to `<file>.corrupt-<ts>` and log an
119
+ * error. After this returns, the caller may start empty and overwrite the
120
+ * original.
121
+ *
122
+ * @param filePath - The bad store file
123
+ * @param reason - Why it cannot be used
124
+ * @param logger - Optional logger
125
+ * @returns The quarantine path
126
+ * @throws CorruptJsonFileError when the copy fails — the caller must then NOT
127
+ * overwrite the original
128
+ */
129
+ export declare function quarantineCorruptFile(filePath: string, reason: string, logger?: FileIOLogger): Promise<string>;
130
+ /**
131
+ * Synchronous {@link quarantineCorruptFile}.
132
+ *
133
+ * @param filePath - The bad store file
134
+ * @param reason - Why it cannot be used
135
+ * @param logger - Optional logger
136
+ * @returns The quarantine path
137
+ * @throws CorruptJsonFileError when the copy fails
138
+ */
139
+ export declare function quarantineCorruptFileSync(filePath: string, reason: string, logger?: FileIOLogger): string;
140
+ /**
141
+ * Read a JSON store, telling "missing" apart from "bad".
142
+ *
143
+ * - missing (`ENOENT`) → `{ status: 'missing' }` — start fresh;
144
+ * - parses (and passes `validate`) → `{ status: 'ok', data }`;
145
+ * - invalid JSON, or rejected by `validate` → copied to
146
+ * `<file>.corrupt-<ts>`, error logged, `{ status: 'quarantined' }`;
147
+ * - any other read error (EMFILE, EIO, EACCES…) → rethrown. The file may be
148
+ * good; the caller must not start empty and write over it.
149
+ *
150
+ * @param filePath - Store file
151
+ * @param options.validate - Optional shape check; return an error text to reject
152
+ * @param options.logger - Optional logger
153
+ * @returns What was found
154
+ * @throws CorruptJsonFileError when the file is bad and could not be copied aside
155
+ * @throws The read error itself for anything but ENOENT
156
+ */
157
+ export declare function readJsonStore<T>(filePath: string, options?: {
158
+ validate?: (data: unknown) => string | null;
159
+ logger?: FileIOLogger;
160
+ }): Promise<JsonStoreRead<T>>;
161
+ /**
162
+ * Synchronous {@link readJsonStore}.
163
+ *
164
+ * @param filePath - Store file
165
+ * @param options.validate - Optional shape check; return an error text to reject
166
+ * @param options.logger - Optional logger
167
+ * @returns What was found
168
+ * @throws CorruptJsonFileError when the file is bad and could not be copied aside
169
+ * @throws The read error itself for anything but ENOENT
170
+ */
171
+ export declare function readJsonStoreSync<T>(filePath: string, options?: {
172
+ validate?: (data: unknown) => string | null;
173
+ logger?: FileIOLogger;
174
+ }): JsonStoreRead<T>;
65
175
  /**
66
176
  * Read and parse a JSON file safely.
67
177
  *
68
178
  * - On `ENOENT` → returns `defaultValue` silently.
69
- * - On parse error → backs up the corrupt file as `<path>.corrupt.<ts>`
179
+ * - On parse error → backs up the corrupt file as `<path>.corrupt-<ts>`
70
180
  * and returns `defaultValue`.
181
+ * - If that backup fails (a full disk, permissions) → throws
182
+ * {@link CorruptJsonFileError}. Returning the default would let the caller
183
+ * write it over the only copy of the data.
71
184
  *
72
185
  * @param filePath - Path to the JSON file
73
186
  * @param defaultValue - Value to return when the file is missing or corrupt
@@ -1 +1 @@
1
- {"version":3,"file":"file-io.utils.d.ts","sourceRoot":"","sources":["../../../../../backend/src/utils/file-io.utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAKH;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;IAC5D,KAAK,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAC;CAC/D;AAaD;;;;GAIG;AACH,wBAAsB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE9D;AAuCD;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAE9F;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,iBAAiB,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAEnG;AAMD;;;;;;;;;;;;GAYG;AACH,wBAAsB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAuBtF;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAEjF;AAMD;;;;;;;;;;;GAWG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,EAAE,MAAM,CAAC,EAAE,YAAY,GAAG,OAAO,CAAC,CAAC,CAAC,CAyB1G;AAMD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAsB,cAAc,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,EAC9C,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,CAAC,EACf,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EACpC,MAAM,CAAC,EAAE,YAAY,GACpB,OAAO,CAAC,CAAC,CAAC,CAUZ;AAMD;;GAEG;AACH,wBAAgB,cAAc,IAAI,IAAI,CAGrC"}
1
+ {"version":3,"file":"file-io.utils.d.ts","sourceRoot":"","sources":["../../../../../backend/src/utils/file-io.utils.ts"],"names":[],"mappings":"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"}
@@ -8,6 +8,53 @@
8
8
  * @module utils/file-io.utils
9
9
  */
10
10
  import * as fs from 'fs/promises';
11
+ import * as fsSync from 'fs';
12
+ /**
13
+ * A JSON store file exists but cannot be read or parsed, AND it could not be
14
+ * copied aside. The caller must not overwrite it: that would destroy the only
15
+ * copy of whatever it still holds (the 2026-10-03 token-ledger loss).
16
+ */
17
+ export class CorruptJsonFileError extends Error {
18
+ /** The store file that is bad */
19
+ filePath;
20
+ /** Why it could not be used (parse or read error) */
21
+ reason;
22
+ /**
23
+ * @param filePath - The bad store file
24
+ * @param reason - Parse / read error text
25
+ * @param copyError - Why copying it aside failed
26
+ */
27
+ constructor(filePath, reason, copyError) {
28
+ super(`Store file ${filePath} is unreadable (${reason}) and could not be set aside (${copyError}); refusing to overwrite it`);
29
+ this.name = 'CorruptJsonFileError';
30
+ this.filePath = filePath;
31
+ this.reason = reason;
32
+ }
33
+ }
34
+ /**
35
+ * Error text of an unknown thrown value.
36
+ *
37
+ * @param err - Thrown value
38
+ * @returns Message
39
+ */
40
+ function errText(err) {
41
+ return err instanceof Error ? err.message : String(err);
42
+ }
43
+ /**
44
+ * Log at error level when the logger has one, else warn.
45
+ *
46
+ * @param logger - Optional logger
47
+ * @param message - Message
48
+ * @param meta - Metadata
49
+ */
50
+ function logError(logger, message, meta) {
51
+ if (!logger)
52
+ return;
53
+ if (logger.error)
54
+ logger.error(message, meta);
55
+ else
56
+ logger.warn(message, meta);
57
+ }
11
58
  // ──────────────────────────────────────────────────────────────────────
12
59
  // Module-level lock maps (singleton per process — no class needed)
13
60
  // ──────────────────────────────────────────────────────────────────────
@@ -125,6 +172,185 @@ export async function atomicWriteFile(filePath, content) {
125
172
  export async function atomicWriteJson(filePath, data) {
126
173
  await atomicWriteFile(filePath, JSON.stringify(data, null, 2));
127
174
  }
175
+ /**
176
+ * Synchronous {@link atomicWriteFile} for stores that persist synchronously
177
+ * (temp file in the same directory → fsync → rename).
178
+ *
179
+ * A failure (ENOSPC, EACCES) leaves the destination untouched, removes the
180
+ * temp file and rethrows. No in-process lock: a synchronous call cannot
181
+ * interleave with another one in the same process.
182
+ *
183
+ * **Precondition:** the parent directory must already exist.
184
+ *
185
+ * @param filePath - Destination file path
186
+ * @param content - String content to write
187
+ */
188
+ export function atomicWriteFileSync(filePath, content) {
189
+ const tempPath = `${filePath}.tmp.${Date.now()}.${Math.random().toString(36).substring(2)}`;
190
+ let fd = null;
191
+ try {
192
+ fd = fsSync.openSync(tempPath, 'w');
193
+ fsSync.writeFileSync(fd, content, 'utf8');
194
+ fsSync.fsyncSync(fd);
195
+ fsSync.closeSync(fd);
196
+ fd = null;
197
+ fsSync.renameSync(tempPath, filePath);
198
+ }
199
+ catch (error) {
200
+ if (fd !== null) {
201
+ try {
202
+ fsSync.closeSync(fd);
203
+ }
204
+ catch { /* ignore */ }
205
+ }
206
+ try {
207
+ fsSync.unlinkSync(tempPath);
208
+ }
209
+ catch { /* ignore */ }
210
+ throw error;
211
+ }
212
+ }
213
+ // ──────────────────────────────────────────────────────────────────────
214
+ // Corrupt-store quarantine
215
+ // ──────────────────────────────────────────────────────────────────────
216
+ /**
217
+ * Where a bad store file is copied: `<file>.corrupt-<ISO timestamp>`
218
+ * (colons and dots replaced so the name is valid everywhere).
219
+ *
220
+ * @param filePath - Store file
221
+ * @param now - Clock (tests)
222
+ * @returns Quarantine path
223
+ */
224
+ export function quarantinePathFor(filePath, now = new Date()) {
225
+ return `${filePath}.corrupt-${now.toISOString().replace(/[:.]/g, '-')}`;
226
+ }
227
+ /**
228
+ * Copy a store file that cannot be used to `<file>.corrupt-<ts>` and log an
229
+ * error. After this returns, the caller may start empty and overwrite the
230
+ * original.
231
+ *
232
+ * @param filePath - The bad store file
233
+ * @param reason - Why it cannot be used
234
+ * @param logger - Optional logger
235
+ * @returns The quarantine path
236
+ * @throws CorruptJsonFileError when the copy fails — the caller must then NOT
237
+ * overwrite the original
238
+ */
239
+ export async function quarantineCorruptFile(filePath, reason, logger) {
240
+ const target = quarantinePathFor(filePath);
241
+ try {
242
+ await fs.copyFile(filePath, target);
243
+ }
244
+ catch (copyErr) {
245
+ logError(logger, 'Store file is unreadable and could not be set aside; it will not be overwritten', {
246
+ filePath, reason, copyError: errText(copyErr),
247
+ });
248
+ throw new CorruptJsonFileError(filePath, reason, errText(copyErr));
249
+ }
250
+ logError(logger, 'Store file was unreadable; copied aside and starting empty', { filePath, quarantinedTo: target, reason });
251
+ return target;
252
+ }
253
+ /**
254
+ * Synchronous {@link quarantineCorruptFile}.
255
+ *
256
+ * @param filePath - The bad store file
257
+ * @param reason - Why it cannot be used
258
+ * @param logger - Optional logger
259
+ * @returns The quarantine path
260
+ * @throws CorruptJsonFileError when the copy fails
261
+ */
262
+ export function quarantineCorruptFileSync(filePath, reason, logger) {
263
+ const target = quarantinePathFor(filePath);
264
+ try {
265
+ fsSync.copyFileSync(filePath, target);
266
+ }
267
+ catch (copyErr) {
268
+ logError(logger, 'Store file is unreadable and could not be set aside; it will not be overwritten', {
269
+ filePath, reason, copyError: errText(copyErr),
270
+ });
271
+ throw new CorruptJsonFileError(filePath, reason, errText(copyErr));
272
+ }
273
+ logError(logger, 'Store file was unreadable; copied aside and starting empty', { filePath, quarantinedTo: target, reason });
274
+ return target;
275
+ }
276
+ /**
277
+ * Read a JSON store, telling "missing" apart from "bad".
278
+ *
279
+ * - missing (`ENOENT`) → `{ status: 'missing' }` — start fresh;
280
+ * - parses (and passes `validate`) → `{ status: 'ok', data }`;
281
+ * - invalid JSON, or rejected by `validate` → copied to
282
+ * `<file>.corrupt-<ts>`, error logged, `{ status: 'quarantined' }`;
283
+ * - any other read error (EMFILE, EIO, EACCES…) → rethrown. The file may be
284
+ * good; the caller must not start empty and write over it.
285
+ *
286
+ * @param filePath - Store file
287
+ * @param options.validate - Optional shape check; return an error text to reject
288
+ * @param options.logger - Optional logger
289
+ * @returns What was found
290
+ * @throws CorruptJsonFileError when the file is bad and could not be copied aside
291
+ * @throws The read error itself for anything but ENOENT
292
+ */
293
+ export async function readJsonStore(filePath, options = {}) {
294
+ let raw;
295
+ try {
296
+ raw = await fs.readFile(filePath, 'utf-8');
297
+ }
298
+ catch (err) {
299
+ if (err.code === 'ENOENT')
300
+ return { status: 'missing' };
301
+ // EMFILE, EIO, EACCES…: the file may be perfectly good. Never set it
302
+ // aside (the store would start empty and overwrite it); let the caller
303
+ // refuse to write until a read succeeds.
304
+ throw err;
305
+ }
306
+ const parsed = parseStore(raw, options.validate);
307
+ if (parsed.ok)
308
+ return { status: 'ok', data: parsed.data };
309
+ return { status: 'quarantined', quarantinedTo: await quarantineCorruptFile(filePath, parsed.reason, options.logger), reason: parsed.reason };
310
+ }
311
+ /**
312
+ * Synchronous {@link readJsonStore}.
313
+ *
314
+ * @param filePath - Store file
315
+ * @param options.validate - Optional shape check; return an error text to reject
316
+ * @param options.logger - Optional logger
317
+ * @returns What was found
318
+ * @throws CorruptJsonFileError when the file is bad and could not be copied aside
319
+ * @throws The read error itself for anything but ENOENT
320
+ */
321
+ export function readJsonStoreSync(filePath, options = {}) {
322
+ let raw;
323
+ try {
324
+ raw = fsSync.readFileSync(filePath, 'utf-8');
325
+ }
326
+ catch (err) {
327
+ if (err.code === 'ENOENT')
328
+ return { status: 'missing' };
329
+ throw err; // see readJsonStore: a read error is not corruption
330
+ }
331
+ const parsed = parseStore(raw, options.validate);
332
+ if (parsed.ok)
333
+ return { status: 'ok', data: parsed.data };
334
+ return { status: 'quarantined', quarantinedTo: quarantineCorruptFileSync(filePath, parsed.reason, options.logger), reason: parsed.reason };
335
+ }
336
+ /**
337
+ * Parse store text and run the optional shape check.
338
+ *
339
+ * @param raw - File text
340
+ * @param validate - Optional shape check
341
+ * @returns Parsed data, or why it was rejected
342
+ */
343
+ function parseStore(raw, validate) {
344
+ let data;
345
+ try {
346
+ data = JSON.parse(raw);
347
+ }
348
+ catch (err) {
349
+ return { ok: false, reason: `invalid JSON (${raw.length} bytes): ${errText(err)}` };
350
+ }
351
+ const rejected = validate?.(data) ?? null;
352
+ return rejected ? { ok: false, reason: rejected } : { ok: true, data };
353
+ }
128
354
  // ──────────────────────────────────────────────────────────────────────
129
355
  // Safe read
130
356
  // ──────────────────────────────────────────────────────────────────────
@@ -132,8 +358,11 @@ export async function atomicWriteJson(filePath, data) {
132
358
  * Read and parse a JSON file safely.
133
359
  *
134
360
  * - On `ENOENT` → returns `defaultValue` silently.
135
- * - On parse error → backs up the corrupt file as `<path>.corrupt.<ts>`
361
+ * - On parse error → backs up the corrupt file as `<path>.corrupt-<ts>`
136
362
  * and returns `defaultValue`.
363
+ * - If that backup fails (a full disk, permissions) → throws
364
+ * {@link CorruptJsonFileError}. Returning the default would let the caller
365
+ * write it over the only copy of the data.
137
366
  *
138
367
  * @param filePath - Path to the JSON file
139
368
  * @param defaultValue - Value to return when the file is missing or corrupt
@@ -155,15 +384,16 @@ export async function safeReadJson(filePath, defaultValue, logger) {
155
384
  try {
156
385
  return JSON.parse(raw);
157
386
  }
158
- catch {
159
- // Corrupt JSON — back up the file so we can debug later
160
- const backupPath = `${filePath}.corrupt.${Date.now()}`;
387
+ catch (parseErr) {
388
+ // Corrupt JSON — back up the file before anyone can write over it
389
+ const backupPath = quarantinePathFor(filePath);
161
390
  try {
162
391
  await fs.copyFile(filePath, backupPath);
163
392
  logger?.warn('Backed up corrupt JSON file', { filePath, backupPath });
164
393
  }
165
- catch {
166
- logger?.warn('Failed to back up corrupt JSON file', { filePath });
394
+ catch (copyErr) {
395
+ logError(logger, 'Failed to back up corrupt JSON file; refusing to fall back to the default', { filePath });
396
+ throw new CorruptJsonFileError(filePath, `invalid JSON: ${errText(parseErr)}`, errText(copyErr));
167
397
  }
168
398
  return defaultValue;
169
399
  }
@@ -1 +1 @@
1
- {"version":3,"file":"file-io.utils.js","sourceRoot":"","sources":["../../../../../backend/src/utils/file-io.utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"file-io.utils.js","sourceRoot":"","sources":["../../../../../backend/src/utils/file-io.utils.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
1
  {
2
- "commit": "5e3c72b5643811738cd50a6c40a9572a57d5f099",
3
- "builtAt": "2026-10-03T12:41:47.102Z"
2
+ "commit": "f843dd39cad10eeda2de8ca81f9ab78985f95af0",
3
+ "builtAt": "2026-10-03T13:09:32.583Z"
4
4
  }
@@ -5696,6 +5696,22 @@ export declare const REPLY_ROUTING_CONSTANTS: {
5696
5696
  /** Decision ids (`D-12`) */
5697
5697
  readonly DECISION_PATTERN: RegExp;
5698
5698
  };
5699
+ /**
5700
+ * Usage ledger backfill (`POST /api/system/usage/backfill`, owner only).
5701
+ * specs/2026-10-03-usage-ledger-durability.md §Backfill
5702
+ */
5703
+ export declare const USAGE_BACKFILL_CONSTANTS: {
5704
+ /** Longest range one request may rebuild, in days */
5705
+ readonly MAX_DAYS: 120;
5706
+ /** Most ledger backup files one request may read */
5707
+ readonly MAX_LEDGER_FILES: 10;
5708
+ /** Largest ledger backup file read (the live ledger was 2.8 MB) */
5709
+ readonly MAX_LEDGER_FILE_BYTES: number;
5710
+ /** Names a ledger backup may have: `*.json`, `*.corrupt-*`, `*.corrupt.*`, `*.bak-*` */
5711
+ readonly LEDGER_FILE_NAME_PATTERN: RegExp;
5712
+ /** The one error a rejected ledger file gets: never file contents, never "missing" vs "unreadable" */
5713
+ readonly LEDGER_FILE_ERROR: "not a usable ledger file";
5714
+ };
5699
5715
  /**
5700
5716
  * Daily token caps with a hard stop, team caps and temporary boosts
5701
5717
  * (specs/2026-10-02-spend-cap.md). The unit is TOKENS, not dollars (owner,