crewly 1.20.301 → 1.20.303

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 (203) hide show
  1. package/config/roles/developer/prompt.md +7 -0
  2. package/config/roles/fullstack-dev/prompt.md +7 -0
  3. package/config/roles/product-manager/prompt.md +7 -0
  4. package/config/skills/agent/core/receive-file/SKILL.md +4 -0
  5. package/config/skills/agent/core/request-file/SKILL.md +74 -0
  6. package/config/skills/agent/core/request-file/execute.sh +89 -0
  7. package/config/skills/agent/core/request-file/execute.test.sh +77 -0
  8. package/config/skills/agent/core/slack-file/SKILL.md +1 -1
  9. package/config/skills/orchestrator/usage-categories/SKILL.md +59 -0
  10. package/config/skills/orchestrator/usage-categories/execute.sh +81 -0
  11. package/config/skills/orchestrator/usage-categories/execute.test.sh +45 -0
  12. package/config/skills/orchestrator/usage-report/SKILL.md +71 -0
  13. package/config/skills/orchestrator/usage-report/execute.sh +84 -0
  14. package/config/skills/orchestrator/usage-report/execute.test.sh +39 -0
  15. package/config/skills/team-leader/usage-report/SKILL.md +71 -0
  16. package/config/skills/team-leader/usage-report/execute.sh +84 -0
  17. package/config/skills/team-leader/usage-report/execute.test.sh +39 -0
  18. package/dist/backend/backend/src/constants.d.ts +24 -4
  19. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  20. package/dist/backend/backend/src/constants.js +29 -6
  21. package/dist/backend/backend/src/constants.js.map +1 -1
  22. package/dist/backend/backend/src/controllers/apps/apps.controller.d.ts +9 -0
  23. package/dist/backend/backend/src/controllers/apps/apps.controller.d.ts.map +1 -1
  24. package/dist/backend/backend/src/controllers/apps/apps.controller.js +21 -0
  25. package/dist/backend/backend/src/controllers/apps/apps.controller.js.map +1 -1
  26. package/dist/backend/backend/src/controllers/apps/apps.routes.d.ts +2 -0
  27. package/dist/backend/backend/src/controllers/apps/apps.routes.d.ts.map +1 -1
  28. package/dist/backend/backend/src/controllers/apps/apps.routes.js +7 -1
  29. package/dist/backend/backend/src/controllers/apps/apps.routes.js.map +1 -1
  30. package/dist/backend/backend/src/controllers/usage-ledger/usage-ledger.controller.d.ts +36 -0
  31. package/dist/backend/backend/src/controllers/usage-ledger/usage-ledger.controller.d.ts.map +1 -0
  32. package/dist/backend/backend/src/controllers/usage-ledger/usage-ledger.controller.js +158 -0
  33. package/dist/backend/backend/src/controllers/usage-ledger/usage-ledger.controller.js.map +1 -0
  34. package/dist/backend/backend/src/controllers/usage-ledger/usage-ledger.routes.d.ts +15 -0
  35. package/dist/backend/backend/src/controllers/usage-ledger/usage-ledger.routes.d.ts.map +1 -0
  36. package/dist/backend/backend/src/controllers/usage-ledger/usage-ledger.routes.js +26 -0
  37. package/dist/backend/backend/src/controllers/usage-ledger/usage-ledger.routes.js.map +1 -0
  38. package/dist/backend/backend/src/index.d.ts +10 -0
  39. package/dist/backend/backend/src/index.d.ts.map +1 -1
  40. package/dist/backend/backend/src/index.js +75 -17
  41. package/dist/backend/backend/src/index.js.map +1 -1
  42. package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
  43. package/dist/backend/backend/src/routes/api.routes.js +3 -0
  44. package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
  45. package/dist/backend/backend/src/services/agent/follow-through.wiring.d.ts +32 -0
  46. package/dist/backend/backend/src/services/agent/follow-through.wiring.d.ts.map +1 -1
  47. package/dist/backend/backend/src/services/agent/follow-through.wiring.js +42 -1
  48. package/dist/backend/backend/src/services/agent/follow-through.wiring.js.map +1 -1
  49. package/dist/backend/backend/src/services/agent/resource-mode.service.d.ts +26 -6
  50. package/dist/backend/backend/src/services/agent/resource-mode.service.d.ts.map +1 -1
  51. package/dist/backend/backend/src/services/agent/resource-mode.service.js +59 -5
  52. package/dist/backend/backend/src/services/agent/resource-mode.service.js.map +1 -1
  53. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
  54. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js +1 -0
  55. package/dist/backend/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
  56. package/dist/backend/backend/src/services/apps/apps.wiring.d.ts.map +1 -1
  57. package/dist/backend/backend/src/services/apps/apps.wiring.js +14 -0
  58. package/dist/backend/backend/src/services/apps/apps.wiring.js.map +1 -1
  59. package/dist/backend/backend/src/services/apps/file-request-watch.service.d.ts +88 -0
  60. package/dist/backend/backend/src/services/apps/file-request-watch.service.d.ts.map +1 -0
  61. package/dist/backend/backend/src/services/apps/file-request-watch.service.js +170 -0
  62. package/dist/backend/backend/src/services/apps/file-request-watch.service.js.map +1 -0
  63. package/dist/backend/backend/src/services/monitoring/agent-turn-state.d.ts +35 -0
  64. package/dist/backend/backend/src/services/monitoring/agent-turn-state.d.ts.map +1 -1
  65. package/dist/backend/backend/src/services/monitoring/agent-turn-state.js +101 -0
  66. package/dist/backend/backend/src/services/monitoring/agent-turn-state.js.map +1 -1
  67. package/dist/backend/backend/src/services/monitoring/background-work-watchdog.d.ts +58 -0
  68. package/dist/backend/backend/src/services/monitoring/background-work-watchdog.d.ts.map +1 -0
  69. package/dist/backend/backend/src/services/monitoring/background-work-watchdog.js +100 -0
  70. package/dist/backend/backend/src/services/monitoring/background-work-watchdog.js.map +1 -0
  71. package/dist/backend/backend/src/services/monitoring/token-usage.service.d.ts.map +1 -1
  72. package/dist/backend/backend/src/services/monitoring/token-usage.service.js +3 -0
  73. package/dist/backend/backend/src/services/monitoring/token-usage.service.js.map +1 -1
  74. package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.d.ts +7 -0
  75. package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.d.ts.map +1 -1
  76. package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.js +15 -0
  77. package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.js.map +1 -1
  78. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
  79. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js +51 -33
  80. package/dist/backend/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
  81. package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.d.ts +24 -0
  82. package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.d.ts.map +1 -1
  83. package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.js +63 -1
  84. package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.js.map +1 -1
  85. package/dist/backend/backend/src/services/trace/trace-context.service.d.ts +42 -2
  86. package/dist/backend/backend/src/services/trace/trace-context.service.d.ts.map +1 -1
  87. package/dist/backend/backend/src/services/trace/trace-context.service.js +66 -5
  88. package/dist/backend/backend/src/services/trace/trace-context.service.js.map +1 -1
  89. package/dist/backend/backend/src/services/trace/trace-recorder.d.ts.map +1 -1
  90. package/dist/backend/backend/src/services/trace/trace-recorder.js +11 -0
  91. package/dist/backend/backend/src/services/trace/trace-recorder.js.map +1 -1
  92. package/dist/backend/backend/src/services/usage-ledger/categories-param.d.ts +28 -0
  93. package/dist/backend/backend/src/services/usage-ledger/categories-param.d.ts.map +1 -0
  94. package/dist/backend/backend/src/services/usage-ledger/categories-param.js +67 -0
  95. package/dist/backend/backend/src/services/usage-ledger/categories-param.js.map +1 -0
  96. package/dist/backend/backend/src/services/usage-ledger/excerpt.d.ts +37 -0
  97. package/dist/backend/backend/src/services/usage-ledger/excerpt.d.ts.map +1 -0
  98. package/dist/backend/backend/src/services/usage-ledger/excerpt.js +49 -0
  99. package/dist/backend/backend/src/services/usage-ledger/excerpt.js.map +1 -0
  100. package/dist/backend/backend/src/services/usage-ledger/index.d.ts +14 -0
  101. package/dist/backend/backend/src/services/usage-ledger/index.d.ts.map +1 -0
  102. package/dist/backend/backend/src/services/usage-ledger/index.js +14 -0
  103. package/dist/backend/backend/src/services/usage-ledger/index.js.map +1 -0
  104. package/dist/backend/backend/src/services/usage-ledger/ledger-hooks.d.ts +44 -0
  105. package/dist/backend/backend/src/services/usage-ledger/ledger-hooks.d.ts.map +1 -0
  106. package/dist/backend/backend/src/services/usage-ledger/ledger-hooks.js +52 -0
  107. package/dist/backend/backend/src/services/usage-ledger/ledger-hooks.js.map +1 -0
  108. package/dist/backend/backend/src/services/usage-ledger/ledger-rollup.d.ts +100 -0
  109. package/dist/backend/backend/src/services/usage-ledger/ledger-rollup.d.ts.map +1 -0
  110. package/dist/backend/backend/src/services/usage-ledger/ledger-rollup.js +189 -0
  111. package/dist/backend/backend/src/services/usage-ledger/ledger-rollup.js.map +1 -0
  112. package/dist/backend/backend/src/services/usage-ledger/owner-spans.d.ts +41 -0
  113. package/dist/backend/backend/src/services/usage-ledger/owner-spans.d.ts.map +1 -0
  114. package/dist/backend/backend/src/services/usage-ledger/owner-spans.js +71 -0
  115. package/dist/backend/backend/src/services/usage-ledger/owner-spans.js.map +1 -0
  116. package/dist/backend/backend/src/services/usage-ledger/team-directory.d.ts +47 -0
  117. package/dist/backend/backend/src/services/usage-ledger/team-directory.d.ts.map +1 -0
  118. package/dist/backend/backend/src/services/usage-ledger/team-directory.js +106 -0
  119. package/dist/backend/backend/src/services/usage-ledger/team-directory.js.map +1 -0
  120. package/dist/backend/backend/src/services/usage-ledger/unit-classifier.d.ts +101 -0
  121. package/dist/backend/backend/src/services/usage-ledger/unit-classifier.d.ts.map +1 -0
  122. package/dist/backend/backend/src/services/usage-ledger/unit-classifier.js +263 -0
  123. package/dist/backend/backend/src/services/usage-ledger/unit-classifier.js.map +1 -0
  124. package/dist/backend/backend/src/services/usage-ledger/usage-categories.store.d.ts +96 -0
  125. package/dist/backend/backend/src/services/usage-ledger/usage-categories.store.d.ts.map +1 -0
  126. package/dist/backend/backend/src/services/usage-ledger/usage-categories.store.js +166 -0
  127. package/dist/backend/backend/src/services/usage-ledger/usage-categories.store.js.map +1 -0
  128. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.backfill.d.ts +90 -0
  129. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.backfill.d.ts.map +1 -0
  130. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.backfill.js +294 -0
  131. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.backfill.js.map +1 -0
  132. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.recorder.d.ts +102 -0
  133. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.recorder.d.ts.map +1 -0
  134. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.recorder.js +314 -0
  135. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.recorder.js.map +1 -0
  136. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.runtime.d.ts +62 -0
  137. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.runtime.d.ts.map +1 -0
  138. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.runtime.js +106 -0
  139. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.runtime.js.map +1 -0
  140. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.store.d.ts +52 -0
  141. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.store.d.ts.map +1 -0
  142. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.store.js +95 -0
  143. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.store.js.map +1 -0
  144. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.types.d.ts +127 -0
  145. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.types.d.ts.map +1 -0
  146. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.types.js +19 -0
  147. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.types.js.map +1 -0
  148. package/dist/backend/backend/src/services/usage-ledger/usage-report.service.d.ts +124 -0
  149. package/dist/backend/backend/src/services/usage-ledger/usage-report.service.d.ts.map +1 -0
  150. package/dist/backend/backend/src/services/usage-ledger/usage-report.service.js +372 -0
  151. package/dist/backend/backend/src/services/usage-ledger/usage-report.service.js.map +1 -0
  152. package/dist/backend/backend/src/types/slack.types.d.ts +8 -0
  153. package/dist/backend/backend/src/types/slack.types.d.ts.map +1 -1
  154. package/dist/backend/backend/src/types/slack.types.js.map +1 -1
  155. package/dist/backend/build-info.json +2 -2
  156. package/dist/cli/backend/src/constants.d.ts +24 -4
  157. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  158. package/dist/cli/backend/src/constants.js +29 -6
  159. package/dist/cli/backend/src/constants.js.map +1 -1
  160. package/dist/cli/backend/src/services/agent/resource-mode.service.d.ts +26 -6
  161. package/dist/cli/backend/src/services/agent/resource-mode.service.d.ts.map +1 -1
  162. package/dist/cli/backend/src/services/agent/resource-mode.service.js +59 -5
  163. package/dist/cli/backend/src/services/agent/resource-mode.service.js.map +1 -1
  164. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.d.ts.map +1 -1
  165. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js +1 -0
  166. package/dist/cli/backend/src/services/ai/prompt-modules/skills-reference.module.js.map +1 -1
  167. package/dist/cli/backend/src/services/monitoring/agent-turn-state.d.ts +35 -0
  168. package/dist/cli/backend/src/services/monitoring/agent-turn-state.d.ts.map +1 -1
  169. package/dist/cli/backend/src/services/monitoring/agent-turn-state.js +101 -0
  170. package/dist/cli/backend/src/services/monitoring/agent-turn-state.js.map +1 -1
  171. package/dist/cli/backend/src/services/monitoring/token-usage.service.d.ts.map +1 -1
  172. package/dist/cli/backend/src/services/monitoring/token-usage.service.js +3 -0
  173. package/dist/cli/backend/src/services/monitoring/token-usage.service.js.map +1 -1
  174. package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.d.ts.map +1 -1
  175. package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.js +51 -33
  176. package/dist/cli/backend/src/services/slack/slack-orchestrator-bridge.js.map +1 -1
  177. package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.d.ts +24 -0
  178. package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.d.ts.map +1 -1
  179. package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.js +63 -1
  180. package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.js.map +1 -1
  181. package/dist/cli/backend/src/services/trace/trace-context.service.d.ts +42 -2
  182. package/dist/cli/backend/src/services/trace/trace-context.service.d.ts.map +1 -1
  183. package/dist/cli/backend/src/services/trace/trace-context.service.js +66 -5
  184. package/dist/cli/backend/src/services/trace/trace-context.service.js.map +1 -1
  185. package/dist/cli/backend/src/services/trace/trace-recorder.d.ts.map +1 -1
  186. package/dist/cli/backend/src/services/trace/trace-recorder.js +11 -0
  187. package/dist/cli/backend/src/services/trace/trace-recorder.js.map +1 -1
  188. package/dist/cli/backend/src/services/usage-ledger/ledger-hooks.d.ts +44 -0
  189. package/dist/cli/backend/src/services/usage-ledger/ledger-hooks.d.ts.map +1 -0
  190. package/dist/cli/backend/src/services/usage-ledger/ledger-hooks.js +52 -0
  191. package/dist/cli/backend/src/services/usage-ledger/ledger-hooks.js.map +1 -0
  192. package/dist/cli/backend/src/services/worktree/low-disk-guard.d.ts +109 -0
  193. package/dist/cli/backend/src/services/worktree/low-disk-guard.d.ts.map +1 -0
  194. package/dist/cli/backend/src/services/worktree/low-disk-guard.js +148 -0
  195. package/dist/cli/backend/src/services/worktree/low-disk-guard.js.map +1 -0
  196. package/dist/cli/backend/src/services/worktree/worktree-janitor.git.d.ts +224 -0
  197. package/dist/cli/backend/src/services/worktree/worktree-janitor.git.d.ts.map +1 -0
  198. package/dist/cli/backend/src/services/worktree/worktree-janitor.git.js +449 -0
  199. package/dist/cli/backend/src/services/worktree/worktree-janitor.git.js.map +1 -0
  200. package/dist/cli/backend/src/types/slack.types.d.ts +8 -0
  201. package/dist/cli/backend/src/types/slack.types.d.ts.map +1 -1
  202. package/dist/cli/backend/src/types/slack.types.js.map +1 -1
  203. package/package.json +1 -1
@@ -0,0 +1,294 @@
1
+ /**
2
+ * One-time rebuild of the ledger for the time before it existed.
3
+ *
4
+ * Sources: the token ledger (usage events) and the run traces (ticket roots,
5
+ * deliveries, busy turns, status changes). The traces expire after 90 days,
6
+ * the ledger does not, so this keeps what they know.
7
+ *
8
+ * Attribution of a usage event:
9
+ * - it already carries a trace id (the harness stamped it): `recorded`;
10
+ * - otherwise it goes to the trace the session's latest delivery named,
11
+ * when that delivery was at most {@link INFER_MAX_GAP_MS} before the event:
12
+ * `inferred`;
13
+ * - otherwise it lands in the agent's "(no ticket)" unit.
14
+ *
15
+ * Only facts older than the cutoff (the moment live recording began) are
16
+ * written, so history and live facts never overlap. The result goes to
17
+ * `backfill.jsonl`; the run is recorded in `state.json` and never repeats.
18
+ *
19
+ * @module services/usage-ledger/usage-ledger.backfill
20
+ */
21
+ import { createReadStream, promises as fs } from 'fs';
22
+ import * as path from 'path';
23
+ import * as readline from 'readline';
24
+ import { TRACE_CONSTANTS } from '../../constants.js';
25
+ import { atomicWriteJson } from '../../utils/file-io.utils.js';
26
+ import { eventCostUsd, eventTokens } from '../monitoring/token-usage.service.js';
27
+ import { cleanText, cut, EXCERPT_MAX, titleFromSummary } from './excerpt.js';
28
+ import { LEDGER_VERSION, UNTICKETED_PREFIX } from './usage-ledger.types.js';
29
+ /** An unticketed event this soon after a delivery is credited to the delivery's trace. */
30
+ export const INFER_MAX_GAP_MS = TRACE_CONSTANTS.IDLE_CLEAR_MS;
31
+ /** File with the ledger's own bookkeeping. */
32
+ export const STATE_FILE = 'state.json';
33
+ /**
34
+ * Read the ledger bookkeeping.
35
+ *
36
+ * @param dir - Ledger directory
37
+ * @returns State (empty when none)
38
+ */
39
+ export async function readLedgerState(dir) {
40
+ try {
41
+ return JSON.parse(await fs.readFile(path.join(dir, STATE_FILE), 'utf-8'));
42
+ }
43
+ catch {
44
+ return {};
45
+ }
46
+ }
47
+ /**
48
+ * Write the ledger bookkeeping.
49
+ *
50
+ * @param dir - Ledger directory
51
+ * @param state - State
52
+ */
53
+ export async function writeLedgerState(dir, state) {
54
+ await fs.mkdir(dir, { recursive: true });
55
+ await atomicWriteJson(path.join(dir, STATE_FILE), state);
56
+ }
57
+ /**
58
+ * Note when live recording began (once).
59
+ *
60
+ * @param dir - Ledger directory
61
+ * @param now - Now (ms)
62
+ * @returns The cutoff
63
+ */
64
+ export async function ensureLiveSince(dir, now = Date.now()) {
65
+ const state = await readLedgerState(dir);
66
+ if (state.liveSince)
67
+ return state.liveSince;
68
+ const liveSince = new Date(now).toISOString();
69
+ await writeLedgerState(dir, { ...state, liveSince });
70
+ return liveSince;
71
+ }
72
+ const hourOf = (ms) => new Date(Math.floor(ms / 3_600_000) * 3_600_000).toISOString();
73
+ /** Stream the lines of a file. */
74
+ async function* lines(file) {
75
+ const rl = readline.createInterface({ input: createReadStream(file, { encoding: 'utf-8' }), crlfDelay: Infinity });
76
+ for await (const line of rl)
77
+ yield line;
78
+ }
79
+ /**
80
+ * Rebuild history into `backfill.jsonl`.
81
+ *
82
+ * @param store - Ledger store
83
+ * @param sources - Where history comes from
84
+ * @param opts.cutoffMs - Only facts before this time are written
85
+ * @returns What happened
86
+ */
87
+ export async function runBackfill(store, sources, opts) {
88
+ const state = await readLedgerState(store.dir);
89
+ if (state.backfill)
90
+ return { ran: false, reason: `already done at ${state.backfill.doneAt}`, facts: 0, usageEvents: 0, inferredEvents: 0, traces: 0 };
91
+ const cutoff = opts.cutoffMs;
92
+ const facts = [];
93
+ const push = (f) => {
94
+ facts.push(f);
95
+ };
96
+ // ---- traces ----
97
+ let index = null;
98
+ try {
99
+ index = JSON.parse(await fs.readFile(path.join(sources.traceDir, TRACE_CONSTANTS.INDEX_FILE), 'utf-8'));
100
+ }
101
+ catch {
102
+ index = null;
103
+ }
104
+ const traces = index?.traces ?? {};
105
+ const known = new Set(Object.keys(traces));
106
+ /** session → deliveries (ms, trace), sorted later */
107
+ const deliveries = new Map();
108
+ /** `session|ts` → traces that recorded the same busy turn */
109
+ const busyOwners = new Map();
110
+ const busyEvents = [];
111
+ const seenAgents = new Set();
112
+ const lastOwner = new Map();
113
+ for (const [traceId, entry] of Object.entries(traces)) {
114
+ const created = Date.parse(entry.root.createdAt);
115
+ if (created >= cutoff)
116
+ continue;
117
+ const root = entry.root;
118
+ push({
119
+ v: LEDGER_VERSION,
120
+ ts: root.createdAt,
121
+ kind: 'unit.meta',
122
+ unitId: traceId,
123
+ ...(root.refs.ticketId ? { ticketId: root.refs.ticketId } : {}),
124
+ ...(root.refs.requestId ? { requestId: root.refs.requestId } : {}),
125
+ rootKind: root.kind,
126
+ openedAt: root.createdAt,
127
+ title: titleFromSummary(root.summary),
128
+ excerpt: cut(cleanText(root.summary), EXCERPT_MAX),
129
+ attribution: 'recorded',
130
+ });
131
+ const file = path.join(sources.traceDir, `${traceId}.jsonl`);
132
+ try {
133
+ await fs.access(file);
134
+ }
135
+ catch {
136
+ continue;
137
+ }
138
+ for await (const line of lines(file)) {
139
+ let event;
140
+ try {
141
+ event = JSON.parse(line);
142
+ }
143
+ catch {
144
+ continue;
145
+ }
146
+ const at = Date.parse(event.ts);
147
+ if (!Number.isFinite(at) || at >= cutoff)
148
+ continue;
149
+ const session = event.refs?.session ?? event.actor?.session;
150
+ if (event.type === 'turn.delivered') {
151
+ if (session) {
152
+ const list = deliveries.get(session) ?? [];
153
+ list.push({ at, traceId });
154
+ deliveries.set(session, list);
155
+ const key = `${traceId}|${session}`;
156
+ if (!seenAgents.has(key)) {
157
+ seenAgents.add(key);
158
+ const info = sources.directory.lookup(session);
159
+ push({
160
+ v: LEDGER_VERSION,
161
+ ts: event.ts,
162
+ kind: 'unit.agent',
163
+ unitId: traceId,
164
+ agent: session,
165
+ ...(info?.team ? { team: info.team } : {}),
166
+ ...(info?.project ? { project: info.project } : {}),
167
+ attribution: 'recorded',
168
+ });
169
+ }
170
+ }
171
+ if (event.actor?.kind === 'owner' && event.data?.kind === 'owner_message') {
172
+ const last = lastOwner.get(traceId);
173
+ if (last === undefined || Math.abs(at - last) >= 2_000) {
174
+ lastOwner.set(traceId, at);
175
+ push({ v: LEDGER_VERSION, ts: event.ts, kind: 'owner.message', unitId: traceId, attribution: 'recorded' });
176
+ }
177
+ }
178
+ }
179
+ else if (event.type === 'turn.ended') {
180
+ const busyMs = Number(event.data?.busyMs);
181
+ if (session && Number.isFinite(busyMs) && busyMs > 0) {
182
+ busyEvents.push({ traceId, session, at, busyMs });
183
+ const key = `${session}|${event.ts}`;
184
+ busyOwners.set(key, [...(busyOwners.get(key) ?? []), traceId]);
185
+ }
186
+ }
187
+ else if (event.type === 'request.status' || event.type === 'ticket.status') {
188
+ const to = typeof event.data?.to === 'string' ? event.data.to : '';
189
+ const projectId = typeof event.data?.projectId === 'string' ? event.data.projectId : '';
190
+ const project = projectId ? sources.directory.projectName(projectId) : undefined;
191
+ if (project)
192
+ push({ v: LEDGER_VERSION, ts: event.ts, kind: 'unit.meta', unitId: traceId, project, attribution: 'recorded' });
193
+ if (to === 'done' || to === 'cancelled')
194
+ push({ v: LEDGER_VERSION, ts: event.ts, kind: 'unit.closed', unitId: traceId, status: to, attribution: 'recorded' });
195
+ }
196
+ }
197
+ }
198
+ for (const list of deliveries.values())
199
+ list.sort((a, b) => a.at - b.at);
200
+ // ---- busy time ----
201
+ const busy = new Map();
202
+ for (const b of busyEvents) {
203
+ const share = 1 / (busyOwners.get(`${b.session}|${new Date(b.at).toISOString()}`)?.length ?? 1);
204
+ const hour = hourOf(b.at);
205
+ const key = [b.traceId, b.session, hour, share].join('|');
206
+ const info = sources.directory.lookup(b.session);
207
+ const fact = busy.get(key) ??
208
+ { v: LEDGER_VERSION, ts: hour, kind: 'busy', unitId: b.traceId, agent: b.session, ...(info?.team ? { team: info.team } : {}), turns: 0, busyMs: 0, share, attribution: 'recorded' };
209
+ fact.turns += 1;
210
+ fact.busyMs += b.busyMs;
211
+ busy.set(key, fact);
212
+ }
213
+ facts.push(...busy.values());
214
+ // ---- usage ----
215
+ const usage = new Map();
216
+ const noticket = new Set();
217
+ let usageEvents = 0;
218
+ let inferredEvents = 0;
219
+ sources.forEachUsage((session, event) => {
220
+ const at = Date.parse(event.timestamp);
221
+ if (!Number.isFinite(at) || at >= cutoff)
222
+ return;
223
+ usageEvents += 1;
224
+ let unitId;
225
+ let attribution = 'recorded';
226
+ if (event.traceId && known.has(event.traceId)) {
227
+ unitId = event.traceId;
228
+ }
229
+ else {
230
+ const list = deliveries.get(session) ?? [];
231
+ let found;
232
+ for (let i = list.length - 1; i >= 0; i--) {
233
+ if (list[i].at <= at) {
234
+ found = list[i];
235
+ break;
236
+ }
237
+ }
238
+ if (found && at - found.at <= INFER_MAX_GAP_MS) {
239
+ unitId = found.traceId;
240
+ attribution = 'inferred';
241
+ inferredEvents += 1;
242
+ }
243
+ else {
244
+ unitId = `${UNTICKETED_PREFIX}${session}`;
245
+ }
246
+ }
247
+ if (unitId.startsWith(UNTICKETED_PREFIX) && !noticket.has(unitId)) {
248
+ noticket.add(unitId);
249
+ push({ v: LEDGER_VERSION, ts: new Date(at).toISOString(), kind: 'unit.meta', unitId, rootKind: 'none', title: `(no ticket) ${session}`, attribution: 'inferred' });
250
+ }
251
+ const hour = hourOf(at);
252
+ const key = [unitId, session, event.model, hour, attribution].join('|');
253
+ const info = sources.directory.lookup(session);
254
+ const tokens = eventTokens(event);
255
+ const fact = usage.get(key) ??
256
+ {
257
+ v: LEDGER_VERSION,
258
+ ts: hour,
259
+ kind: 'usage',
260
+ unitId,
261
+ agent: session,
262
+ ...(info?.team ? { team: info.team } : {}),
263
+ model: event.model,
264
+ ...(event.runtime ? { runtime: event.runtime } : {}),
265
+ events: 0,
266
+ share: 1,
267
+ input: 0,
268
+ cachedInput: 0,
269
+ output: 0,
270
+ cacheWrite: 0,
271
+ budget: 0,
272
+ costUsd: 0,
273
+ attribution,
274
+ };
275
+ fact.events += 1;
276
+ fact.input += tokens.input;
277
+ fact.cachedInput += tokens.cachedInput;
278
+ fact.output += tokens.output;
279
+ fact.cacheWrite += tokens.cacheWrite;
280
+ fact.budget += tokens.budget;
281
+ fact.costUsd += eventCostUsd(event);
282
+ usage.set(key, fact);
283
+ });
284
+ facts.push(...usage.values());
285
+ for (let i = 0; i < facts.length; i += 5000)
286
+ store.appendMany(facts.slice(i, i + 5000), 'backfill');
287
+ await store.flush();
288
+ await writeLedgerState(store.dir, {
289
+ ...(await readLedgerState(store.dir)),
290
+ backfill: { doneAt: new Date().toISOString(), cutoff: new Date(cutoff).toISOString(), facts: facts.length, usageEvents, inferredEvents },
291
+ });
292
+ return { ran: true, facts: facts.length, usageEvents, inferredEvents, traces: Object.keys(traces).length };
293
+ }
294
+ //# sourceMappingURL=usage-ledger.backfill.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage-ledger.backfill.js","sourceRoot":"","sources":["../../../../../../backend/src/services/usage-ledger/usage-ledger.backfill.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Writes the usage ledger as work happens.
3
+ *
4
+ * Attribution comes from the trace context (which ticket an agent's turn is
5
+ * about, set when the harness delivers a message). The recorder listens to
6
+ * trace events and to token-usage events and appends facts; usage and busy
7
+ * time are summed per (unit, agent, model, hour) in memory and written as one
8
+ * delta fact per bucket on a timer, so the ledger stays small.
9
+ *
10
+ * Rules (specs/2026-10-11-usage-ledger.md):
11
+ * - A usage event belongs to the ticket(s) the agent's turn was about at the
12
+ * event's time. One ticket: all of it. A delivery naming n tickets: 1/n
13
+ * each. No ticket: a per-agent "(no ticket)" unit.
14
+ * - Busy time is recorded when a turn ends, in the ticket the turn started on
15
+ * and the one it is on now, split evenly.
16
+ * - Owner messages delivered to an agent on a ticket are owner-message facts;
17
+ * active spans are computed from them at report time.
18
+ *
19
+ * @module services/usage-ledger/usage-ledger.recorder
20
+ */
21
+ import { type TokenUsageEvent } from '../monitoring/token-usage.service.js';
22
+ import { type TraceContext } from '../trace/trace-context.service.js';
23
+ import type { TraceEvent } from '../trace/trace.types.js';
24
+ import { type RequestMeta } from './ledger-hooks.js';
25
+ import type { TeamLookup } from './team-directory.js';
26
+ import type { UsageLedgerStore } from './usage-ledger.store.js';
27
+ /** Dependencies of the recorder. */
28
+ export interface RecorderDeps {
29
+ store: UsageLedgerStore;
30
+ directory: TeamLookup;
31
+ /** Trace context accessor (default: the process-wide one) */
32
+ context?: () => TraceContext;
33
+ now?: () => number;
34
+ flushIntervalMs?: number;
35
+ }
36
+ /**
37
+ * Start of the UTC hour of a time.
38
+ *
39
+ * @param ms - Epoch ms
40
+ * @returns ISO string of the hour start
41
+ */
42
+ export declare function hourStart(ms: number): string;
43
+ /**
44
+ * Appends ledger facts from live events.
45
+ */
46
+ export declare class UsageLedgerRecorder {
47
+ private readonly deps;
48
+ private readonly context;
49
+ private readonly now;
50
+ private readonly opened;
51
+ private readonly agentsSeen;
52
+ private readonly closed;
53
+ private readonly lastOwner;
54
+ private readonly usage;
55
+ private readonly busy;
56
+ private detach;
57
+ private timer;
58
+ constructor(deps: RecorderDeps);
59
+ /**
60
+ * Start listening (trace events, usage events, new requests) and flushing.
61
+ */
62
+ start(): void;
63
+ /**
64
+ * Stop listening and write what is buffered.
65
+ */
66
+ stop(): Promise<void>;
67
+ /**
68
+ * Write the buffered usage / busy buckets and wait for the files.
69
+ */
70
+ flush(): Promise<void>;
71
+ /**
72
+ * A token-usage event was recorded: attribute it to the ticket(s) its
73
+ * session was working on at that time.
74
+ *
75
+ * @param session - Agent session
76
+ * @param event - The usage event
77
+ */
78
+ noteUsage(session: string, event: TokenUsageEvent): void;
79
+ /**
80
+ * A request got its trace: record what the ticket is about.
81
+ *
82
+ * @param meta - Request facts
83
+ */
84
+ noteRequest(meta: RequestMeta): void;
85
+ /**
86
+ * Fold one trace event into facts.
87
+ *
88
+ * @param event - The trace event
89
+ * @param share - Fraction of a shared fact this trace carries
90
+ */
91
+ onTraceEvent(event: TraceEvent, share: number): void;
92
+ private addBusy;
93
+ private noteOwnerMessage;
94
+ private noteAgent;
95
+ /**
96
+ * Write a unit's descriptive fact the first time the unit is seen (this
97
+ * process): ticket id, title, excerpt, kind, start. Later facts (the
98
+ * request's description, thread, project) fill the gaps.
99
+ */
100
+ private ensureUnit;
101
+ }
102
+ //# sourceMappingURL=usage-ledger.recorder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage-ledger.recorder.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/usage-ledger/usage-ledger.recorder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAA6B,KAAK,eAAe,EAAE,MAAM,sCAAsC,CAAC;AACvG,OAAO,EAAmB,KAAK,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACvF,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAwC,KAAK,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAE3F,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAkBhE,oCAAoC;AACpC,MAAM,WAAW,YAAY;IAC5B,KAAK,EAAE,gBAAgB,CAAC;IACxB,SAAS,EAAE,UAAU,CAAC;IACtB,6DAA6D;IAC7D,OAAO,CAAC,EAAE,MAAM,YAAY,CAAC;IAC7B,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAED;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE5C;AAED;;GAEG;AACH,qBAAa,mBAAmB;IAYnB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAXjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAe;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAqB;IAChD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAA6B;IACvD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAgC;IACtD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAA+B;IACpD,OAAO,CAAC,MAAM,CAA6B;IAC3C,OAAO,CAAC,KAAK,CAA+B;gBAEf,IAAI,EAAE,YAAY;IAK/C;;OAEG;IACH,KAAK,IAAI,IAAI;IAcb;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ3B;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ5B;;;;;;OAMG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,GAAG,IAAI;IAgDxD;;;;OAIG;IACH,WAAW,CAAC,IAAI,EAAE,WAAW,GAAG,IAAI;IAiBpC;;;;;OAKG;IACH,YAAY,CAAC,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI;IA2CpD,OAAO,CAAC,OAAO;IAuBf,OAAO,CAAC,gBAAgB;IAOxB,OAAO,CAAC,SAAS;IAiBjB;;;;OAIG;IACH,OAAO,CAAC,UAAU;CAmClB"}