crewly 1.20.302 → 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 (157) 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/orchestrator/usage-categories/SKILL.md +59 -0
  5. package/config/skills/orchestrator/usage-categories/execute.sh +81 -0
  6. package/config/skills/orchestrator/usage-categories/execute.test.sh +45 -0
  7. package/config/skills/orchestrator/usage-report/SKILL.md +71 -0
  8. package/config/skills/orchestrator/usage-report/execute.sh +84 -0
  9. package/config/skills/orchestrator/usage-report/execute.test.sh +39 -0
  10. package/config/skills/team-leader/usage-report/SKILL.md +71 -0
  11. package/config/skills/team-leader/usage-report/execute.sh +84 -0
  12. package/config/skills/team-leader/usage-report/execute.test.sh +39 -0
  13. package/dist/backend/backend/src/constants.d.ts +11 -0
  14. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  15. package/dist/backend/backend/src/constants.js +11 -0
  16. package/dist/backend/backend/src/constants.js.map +1 -1
  17. package/dist/backend/backend/src/controllers/usage-ledger/usage-ledger.controller.d.ts +36 -0
  18. package/dist/backend/backend/src/controllers/usage-ledger/usage-ledger.controller.d.ts.map +1 -0
  19. package/dist/backend/backend/src/controllers/usage-ledger/usage-ledger.controller.js +158 -0
  20. package/dist/backend/backend/src/controllers/usage-ledger/usage-ledger.controller.js.map +1 -0
  21. package/dist/backend/backend/src/controllers/usage-ledger/usage-ledger.routes.d.ts +15 -0
  22. package/dist/backend/backend/src/controllers/usage-ledger/usage-ledger.routes.d.ts.map +1 -0
  23. package/dist/backend/backend/src/controllers/usage-ledger/usage-ledger.routes.js +26 -0
  24. package/dist/backend/backend/src/controllers/usage-ledger/usage-ledger.routes.js.map +1 -0
  25. package/dist/backend/backend/src/index.d.ts +10 -0
  26. package/dist/backend/backend/src/index.d.ts.map +1 -1
  27. package/dist/backend/backend/src/index.js +75 -17
  28. package/dist/backend/backend/src/index.js.map +1 -1
  29. package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
  30. package/dist/backend/backend/src/routes/api.routes.js +3 -0
  31. package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
  32. package/dist/backend/backend/src/services/agent/follow-through.wiring.d.ts +32 -0
  33. package/dist/backend/backend/src/services/agent/follow-through.wiring.d.ts.map +1 -1
  34. package/dist/backend/backend/src/services/agent/follow-through.wiring.js +42 -1
  35. package/dist/backend/backend/src/services/agent/follow-through.wiring.js.map +1 -1
  36. package/dist/backend/backend/src/services/agent/resource-mode.service.d.ts +26 -6
  37. package/dist/backend/backend/src/services/agent/resource-mode.service.d.ts.map +1 -1
  38. package/dist/backend/backend/src/services/agent/resource-mode.service.js +59 -5
  39. package/dist/backend/backend/src/services/agent/resource-mode.service.js.map +1 -1
  40. package/dist/backend/backend/src/services/monitoring/agent-turn-state.d.ts +35 -0
  41. package/dist/backend/backend/src/services/monitoring/agent-turn-state.d.ts.map +1 -1
  42. package/dist/backend/backend/src/services/monitoring/agent-turn-state.js +101 -0
  43. package/dist/backend/backend/src/services/monitoring/agent-turn-state.js.map +1 -1
  44. package/dist/backend/backend/src/services/monitoring/background-work-watchdog.d.ts +58 -0
  45. package/dist/backend/backend/src/services/monitoring/background-work-watchdog.d.ts.map +1 -0
  46. package/dist/backend/backend/src/services/monitoring/background-work-watchdog.js +100 -0
  47. package/dist/backend/backend/src/services/monitoring/background-work-watchdog.js.map +1 -0
  48. package/dist/backend/backend/src/services/monitoring/token-usage.service.d.ts.map +1 -1
  49. package/dist/backend/backend/src/services/monitoring/token-usage.service.js +3 -0
  50. package/dist/backend/backend/src/services/monitoring/token-usage.service.js.map +1 -1
  51. package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.d.ts +7 -0
  52. package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.d.ts.map +1 -1
  53. package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.js +15 -0
  54. package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.js.map +1 -1
  55. package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.d.ts +24 -0
  56. package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.d.ts.map +1 -1
  57. package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.js +63 -1
  58. package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.js.map +1 -1
  59. package/dist/backend/backend/src/services/trace/trace-context.service.d.ts +42 -2
  60. package/dist/backend/backend/src/services/trace/trace-context.service.d.ts.map +1 -1
  61. package/dist/backend/backend/src/services/trace/trace-context.service.js +66 -5
  62. package/dist/backend/backend/src/services/trace/trace-context.service.js.map +1 -1
  63. package/dist/backend/backend/src/services/trace/trace-recorder.d.ts.map +1 -1
  64. package/dist/backend/backend/src/services/trace/trace-recorder.js +11 -0
  65. package/dist/backend/backend/src/services/trace/trace-recorder.js.map +1 -1
  66. package/dist/backend/backend/src/services/usage-ledger/categories-param.d.ts +28 -0
  67. package/dist/backend/backend/src/services/usage-ledger/categories-param.d.ts.map +1 -0
  68. package/dist/backend/backend/src/services/usage-ledger/categories-param.js +67 -0
  69. package/dist/backend/backend/src/services/usage-ledger/categories-param.js.map +1 -0
  70. package/dist/backend/backend/src/services/usage-ledger/excerpt.d.ts +37 -0
  71. package/dist/backend/backend/src/services/usage-ledger/excerpt.d.ts.map +1 -0
  72. package/dist/backend/backend/src/services/usage-ledger/excerpt.js +49 -0
  73. package/dist/backend/backend/src/services/usage-ledger/excerpt.js.map +1 -0
  74. package/dist/backend/backend/src/services/usage-ledger/index.d.ts +14 -0
  75. package/dist/backend/backend/src/services/usage-ledger/index.d.ts.map +1 -0
  76. package/dist/backend/backend/src/services/usage-ledger/index.js +14 -0
  77. package/dist/backend/backend/src/services/usage-ledger/index.js.map +1 -0
  78. package/dist/backend/backend/src/services/usage-ledger/ledger-hooks.d.ts +44 -0
  79. package/dist/backend/backend/src/services/usage-ledger/ledger-hooks.d.ts.map +1 -0
  80. package/dist/backend/backend/src/services/usage-ledger/ledger-hooks.js +52 -0
  81. package/dist/backend/backend/src/services/usage-ledger/ledger-hooks.js.map +1 -0
  82. package/dist/backend/backend/src/services/usage-ledger/ledger-rollup.d.ts +100 -0
  83. package/dist/backend/backend/src/services/usage-ledger/ledger-rollup.d.ts.map +1 -0
  84. package/dist/backend/backend/src/services/usage-ledger/ledger-rollup.js +189 -0
  85. package/dist/backend/backend/src/services/usage-ledger/ledger-rollup.js.map +1 -0
  86. package/dist/backend/backend/src/services/usage-ledger/owner-spans.d.ts +41 -0
  87. package/dist/backend/backend/src/services/usage-ledger/owner-spans.d.ts.map +1 -0
  88. package/dist/backend/backend/src/services/usage-ledger/owner-spans.js +71 -0
  89. package/dist/backend/backend/src/services/usage-ledger/owner-spans.js.map +1 -0
  90. package/dist/backend/backend/src/services/usage-ledger/team-directory.d.ts +47 -0
  91. package/dist/backend/backend/src/services/usage-ledger/team-directory.d.ts.map +1 -0
  92. package/dist/backend/backend/src/services/usage-ledger/team-directory.js +106 -0
  93. package/dist/backend/backend/src/services/usage-ledger/team-directory.js.map +1 -0
  94. package/dist/backend/backend/src/services/usage-ledger/unit-classifier.d.ts +101 -0
  95. package/dist/backend/backend/src/services/usage-ledger/unit-classifier.d.ts.map +1 -0
  96. package/dist/backend/backend/src/services/usage-ledger/unit-classifier.js +263 -0
  97. package/dist/backend/backend/src/services/usage-ledger/unit-classifier.js.map +1 -0
  98. package/dist/backend/backend/src/services/usage-ledger/usage-categories.store.d.ts +96 -0
  99. package/dist/backend/backend/src/services/usage-ledger/usage-categories.store.d.ts.map +1 -0
  100. package/dist/backend/backend/src/services/usage-ledger/usage-categories.store.js +166 -0
  101. package/dist/backend/backend/src/services/usage-ledger/usage-categories.store.js.map +1 -0
  102. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.backfill.d.ts +90 -0
  103. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.backfill.d.ts.map +1 -0
  104. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.backfill.js +294 -0
  105. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.backfill.js.map +1 -0
  106. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.recorder.d.ts +102 -0
  107. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.recorder.d.ts.map +1 -0
  108. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.recorder.js +314 -0
  109. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.recorder.js.map +1 -0
  110. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.runtime.d.ts +62 -0
  111. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.runtime.d.ts.map +1 -0
  112. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.runtime.js +106 -0
  113. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.runtime.js.map +1 -0
  114. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.store.d.ts +52 -0
  115. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.store.d.ts.map +1 -0
  116. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.store.js +95 -0
  117. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.store.js.map +1 -0
  118. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.types.d.ts +127 -0
  119. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.types.d.ts.map +1 -0
  120. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.types.js +19 -0
  121. package/dist/backend/backend/src/services/usage-ledger/usage-ledger.types.js.map +1 -0
  122. package/dist/backend/backend/src/services/usage-ledger/usage-report.service.d.ts +124 -0
  123. package/dist/backend/backend/src/services/usage-ledger/usage-report.service.d.ts.map +1 -0
  124. package/dist/backend/backend/src/services/usage-ledger/usage-report.service.js +372 -0
  125. package/dist/backend/backend/src/services/usage-ledger/usage-report.service.js.map +1 -0
  126. package/dist/backend/build-info.json +2 -2
  127. package/dist/cli/backend/src/constants.d.ts +11 -0
  128. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  129. package/dist/cli/backend/src/constants.js +11 -0
  130. package/dist/cli/backend/src/constants.js.map +1 -1
  131. package/dist/cli/backend/src/services/agent/resource-mode.service.d.ts +26 -6
  132. package/dist/cli/backend/src/services/agent/resource-mode.service.d.ts.map +1 -1
  133. package/dist/cli/backend/src/services/agent/resource-mode.service.js +59 -5
  134. package/dist/cli/backend/src/services/agent/resource-mode.service.js.map +1 -1
  135. package/dist/cli/backend/src/services/monitoring/agent-turn-state.d.ts +35 -0
  136. package/dist/cli/backend/src/services/monitoring/agent-turn-state.d.ts.map +1 -1
  137. package/dist/cli/backend/src/services/monitoring/agent-turn-state.js +101 -0
  138. package/dist/cli/backend/src/services/monitoring/agent-turn-state.js.map +1 -1
  139. package/dist/cli/backend/src/services/monitoring/token-usage.service.d.ts.map +1 -1
  140. package/dist/cli/backend/src/services/monitoring/token-usage.service.js +3 -0
  141. package/dist/cli/backend/src/services/monitoring/token-usage.service.js.map +1 -1
  142. package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.d.ts +24 -0
  143. package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.d.ts.map +1 -1
  144. package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.js +63 -1
  145. package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.js.map +1 -1
  146. package/dist/cli/backend/src/services/trace/trace-context.service.d.ts +42 -2
  147. package/dist/cli/backend/src/services/trace/trace-context.service.d.ts.map +1 -1
  148. package/dist/cli/backend/src/services/trace/trace-context.service.js +66 -5
  149. package/dist/cli/backend/src/services/trace/trace-context.service.js.map +1 -1
  150. package/dist/cli/backend/src/services/trace/trace-recorder.d.ts.map +1 -1
  151. package/dist/cli/backend/src/services/trace/trace-recorder.js +11 -0
  152. package/dist/cli/backend/src/services/trace/trace-recorder.js.map +1 -1
  153. package/dist/cli/backend/src/services/usage-ledger/ledger-hooks.d.ts +44 -0
  154. package/dist/cli/backend/src/services/usage-ledger/ledger-hooks.d.ts.map +1 -0
  155. package/dist/cli/backend/src/services/usage-ledger/ledger-hooks.js +52 -0
  156. package/dist/cli/backend/src/services/usage-ledger/ledger-hooks.js.map +1 -0
  157. package/package.json +1 -1
@@ -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"}
@@ -0,0 +1,314 @@
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 { eventCostUsd, eventTokens } from '../monitoring/token-usage.service.js';
22
+ import { getTraceContext } from '../trace/trace-context.service.js';
23
+ import { setRequestObserver, setUsageObserver } from './ledger-hooks.js';
24
+ import { cleanText, cut, EXCERPT_MAX, TITLE_MAX, titleFromSummary } from './excerpt.js';
25
+ import { LEDGER_VERSION, UNTICKETED_PREFIX, } from './usage-ledger.types.js';
26
+ /** Statuses that close a ticket / request. */
27
+ const TERMINAL_STATUSES = new Set(['done', 'cancelled']);
28
+ /** Owner messages closer than this on one unit are the same message delivered twice. */
29
+ const OWNER_DEDUPE_MS = 2_000;
30
+ /** Default flush interval of the in-memory buckets. */
31
+ const FLUSH_INTERVAL_MS = 60_000;
32
+ /**
33
+ * Start of the UTC hour of a time.
34
+ *
35
+ * @param ms - Epoch ms
36
+ * @returns ISO string of the hour start
37
+ */
38
+ export function hourStart(ms) {
39
+ return new Date(Math.floor(ms / 3_600_000) * 3_600_000).toISOString();
40
+ }
41
+ /**
42
+ * Appends ledger facts from live events.
43
+ */
44
+ export class UsageLedgerRecorder {
45
+ deps;
46
+ context;
47
+ now;
48
+ opened = new Set();
49
+ agentsSeen = new Set();
50
+ closed = new Set();
51
+ lastOwner = new Map();
52
+ usage = new Map();
53
+ busy = new Map();
54
+ detach = null;
55
+ timer = null;
56
+ constructor(deps) {
57
+ this.deps = deps;
58
+ this.context = deps.context ?? getTraceContext;
59
+ this.now = deps.now ?? (() => Date.now());
60
+ }
61
+ /**
62
+ * Start listening (trace events, usage events, new requests) and flushing.
63
+ */
64
+ start() {
65
+ if (this.detach)
66
+ return;
67
+ const removeListener = this.context().addListener((event, meta) => this.onTraceEvent(event, meta.share));
68
+ setUsageObserver((session, event) => this.noteUsage(session, event));
69
+ setRequestObserver((meta) => this.noteRequest(meta));
70
+ this.detach = () => {
71
+ removeListener();
72
+ setUsageObserver(null);
73
+ setRequestObserver(null);
74
+ };
75
+ this.timer = setInterval(() => void this.flush(), this.deps.flushIntervalMs ?? FLUSH_INTERVAL_MS);
76
+ this.timer.unref?.();
77
+ }
78
+ /**
79
+ * Stop listening and write what is buffered.
80
+ */
81
+ async stop() {
82
+ this.detach?.();
83
+ this.detach = null;
84
+ if (this.timer)
85
+ clearInterval(this.timer);
86
+ this.timer = null;
87
+ await this.flush();
88
+ }
89
+ /**
90
+ * Write the buffered usage / busy buckets and wait for the files.
91
+ */
92
+ async flush() {
93
+ const facts = [...this.usage.values(), ...this.busy.values()];
94
+ this.usage.clear();
95
+ this.busy.clear();
96
+ this.deps.store.appendMany(facts);
97
+ await this.deps.store.flush();
98
+ }
99
+ /**
100
+ * A token-usage event was recorded: attribute it to the ticket(s) its
101
+ * session was working on at that time.
102
+ *
103
+ * @param session - Agent session
104
+ * @param event - The usage event
105
+ */
106
+ noteUsage(session, event) {
107
+ const at = Date.parse(event.timestamp);
108
+ const when = Number.isFinite(at) ? at : this.now();
109
+ const ctx = this.context();
110
+ let units = ctx.tracesAt(session, when);
111
+ if (event.traceId && units[0] !== event.traceId)
112
+ units = [event.traceId];
113
+ if (units.length === 0)
114
+ units = [`${UNTICKETED_PREFIX}${session}`];
115
+ const share = 1 / units.length;
116
+ const tokens = eventTokens(event);
117
+ const costUsd = eventCostUsd(event);
118
+ const info = this.deps.directory.lookup(session);
119
+ const hour = hourStart(when);
120
+ for (const unitId of units) {
121
+ this.ensureUnit(unitId, when);
122
+ this.noteAgent(unitId, session, when);
123
+ const key = [unitId, session, event.model, hour, share].join('|');
124
+ const fact = this.usage.get(key) ??
125
+ {
126
+ v: LEDGER_VERSION,
127
+ ts: hour,
128
+ kind: 'usage',
129
+ unitId,
130
+ agent: session,
131
+ ...(info?.team ? { team: info.team } : {}),
132
+ model: event.model,
133
+ ...(event.runtime ? { runtime: event.runtime } : {}),
134
+ events: 0,
135
+ share,
136
+ input: 0,
137
+ cachedInput: 0,
138
+ output: 0,
139
+ cacheWrite: 0,
140
+ budget: 0,
141
+ costUsd: 0,
142
+ attribution: 'recorded',
143
+ };
144
+ fact.events += 1;
145
+ fact.input += tokens.input;
146
+ fact.cachedInput += tokens.cachedInput;
147
+ fact.output += tokens.output;
148
+ fact.cacheWrite += tokens.cacheWrite;
149
+ fact.budget += tokens.budget;
150
+ fact.costUsd += costUsd;
151
+ this.usage.set(key, fact);
152
+ }
153
+ }
154
+ /**
155
+ * A request got its trace: record what the ticket is about.
156
+ *
157
+ * @param meta - Request facts
158
+ */
159
+ noteRequest(meta) {
160
+ this.ensureUnit(meta.traceId);
161
+ this.deps.store.append({
162
+ v: LEDGER_VERSION,
163
+ ts: meta.createdAt ?? new Date(this.now()).toISOString(),
164
+ kind: 'unit.meta',
165
+ unitId: meta.traceId,
166
+ ...(meta.ticketId ? { ticketId: meta.ticketId } : {}),
167
+ requestId: meta.requestId,
168
+ title: cut(cleanText(meta.title), TITLE_MAX),
169
+ ...(meta.description ? { excerpt: cut(cleanText(meta.description), EXCERPT_MAX) } : {}),
170
+ ...(meta.channel ? { channel: meta.channel } : {}),
171
+ ...(meta.threadRef ? { threadRef: meta.threadRef } : {}),
172
+ attribution: 'recorded',
173
+ });
174
+ }
175
+ /**
176
+ * Fold one trace event into facts.
177
+ *
178
+ * @param event - The trace event
179
+ * @param share - Fraction of a shared fact this trace carries
180
+ */
181
+ onTraceEvent(event, share) {
182
+ const unitId = event.traceId;
183
+ const at = Date.parse(event.ts);
184
+ const when = Number.isFinite(at) ? at : this.now();
185
+ switch (event.type) {
186
+ case 'turn.delivered': {
187
+ this.ensureUnit(unitId, when);
188
+ if (event.refs.session)
189
+ this.noteAgent(unitId, event.refs.session, when);
190
+ if (event.actor.kind === 'owner' && event.data?.kind === 'owner_message')
191
+ this.noteOwnerMessage(unitId, when);
192
+ break;
193
+ }
194
+ case 'turn.ended': {
195
+ const busyMs = Number(event.data?.busyMs);
196
+ const session = event.refs.session ?? event.actor.session;
197
+ if (!session || !Number.isFinite(busyMs) || busyMs <= 0)
198
+ break;
199
+ this.ensureUnit(unitId, when);
200
+ this.noteAgent(unitId, session, when);
201
+ this.addBusy(unitId, session, when, busyMs, share);
202
+ break;
203
+ }
204
+ case 'request.status':
205
+ case 'ticket.status': {
206
+ const to = typeof event.data?.to === 'string' ? event.data.to : '';
207
+ this.ensureUnit(unitId, when);
208
+ const projectId = typeof event.data?.projectId === 'string' ? event.data.projectId : '';
209
+ const project = projectId ? this.deps.directory.projectName(projectId) : undefined;
210
+ if (project) {
211
+ this.deps.store.append({ v: LEDGER_VERSION, ts: event.ts, kind: 'unit.meta', unitId, project, attribution: 'recorded' });
212
+ }
213
+ if (TERMINAL_STATUSES.has(to)) {
214
+ const key = `${unitId}|${to}`;
215
+ if (!this.closed.has(key)) {
216
+ this.closed.add(key);
217
+ this.deps.store.append({ v: LEDGER_VERSION, ts: event.ts, kind: 'unit.closed', unitId, status: to, attribution: 'recorded' });
218
+ }
219
+ }
220
+ break;
221
+ }
222
+ default:
223
+ break;
224
+ }
225
+ }
226
+ addBusy(unitId, agent, when, busyMs, share) {
227
+ const hour = hourStart(when);
228
+ const key = [unitId, agent, hour, share].join('|');
229
+ const info = this.deps.directory.lookup(agent);
230
+ const fact = this.busy.get(key) ??
231
+ {
232
+ v: LEDGER_VERSION,
233
+ ts: hour,
234
+ kind: 'busy',
235
+ unitId,
236
+ agent,
237
+ ...(info?.team ? { team: info.team } : {}),
238
+ turns: 0,
239
+ busyMs: 0,
240
+ share,
241
+ attribution: 'recorded',
242
+ };
243
+ fact.turns += 1;
244
+ fact.busyMs += busyMs;
245
+ this.busy.set(key, fact);
246
+ }
247
+ noteOwnerMessage(unitId, when) {
248
+ const last = this.lastOwner.get(unitId);
249
+ if (last !== undefined && Math.abs(when - last) < OWNER_DEDUPE_MS)
250
+ return;
251
+ this.lastOwner.set(unitId, when);
252
+ this.deps.store.append({ v: LEDGER_VERSION, ts: new Date(when).toISOString(), kind: 'owner.message', unitId, attribution: 'recorded' });
253
+ }
254
+ noteAgent(unitId, agent, when) {
255
+ const key = `${unitId}|${agent}`;
256
+ if (this.agentsSeen.has(key))
257
+ return;
258
+ this.agentsSeen.add(key);
259
+ const info = this.deps.directory.lookup(agent);
260
+ this.deps.store.append({
261
+ v: LEDGER_VERSION,
262
+ ts: new Date(when).toISOString(),
263
+ kind: 'unit.agent',
264
+ unitId,
265
+ agent,
266
+ ...(info?.team ? { team: info.team } : {}),
267
+ ...(info?.project ? { project: info.project } : {}),
268
+ attribution: 'recorded',
269
+ });
270
+ }
271
+ /**
272
+ * Write a unit's descriptive fact the first time the unit is seen (this
273
+ * process): ticket id, title, excerpt, kind, start. Later facts (the
274
+ * request's description, thread, project) fill the gaps.
275
+ */
276
+ ensureUnit(unitId, when = this.now()) {
277
+ if (this.opened.has(unitId))
278
+ return;
279
+ this.opened.add(unitId);
280
+ const ts = new Date(when).toISOString();
281
+ if (unitId.startsWith(UNTICKETED_PREFIX)) {
282
+ this.deps.store.append({
283
+ v: LEDGER_VERSION,
284
+ ts,
285
+ kind: 'unit.meta',
286
+ unitId,
287
+ rootKind: 'none',
288
+ title: `(no ticket) ${unitId.slice(UNTICKETED_PREFIX.length)}`,
289
+ attribution: 'recorded',
290
+ });
291
+ return;
292
+ }
293
+ let root;
294
+ try {
295
+ root = this.context().store.getEntry(unitId)?.root;
296
+ }
297
+ catch {
298
+ root = undefined;
299
+ }
300
+ const clean = root ? cleanText(root.summary) : '';
301
+ this.deps.store.append({
302
+ v: LEDGER_VERSION,
303
+ ts,
304
+ kind: 'unit.meta',
305
+ unitId,
306
+ ...(root?.refs.ticketId ? { ticketId: root.refs.ticketId } : {}),
307
+ ...(root?.refs.requestId ? { requestId: root.refs.requestId } : {}),
308
+ ...(root ? { rootKind: root.kind, openedAt: root.createdAt } : {}),
309
+ ...(root ? { title: titleFromSummary(root.summary), excerpt: cut(clean, EXCERPT_MAX) } : {}),
310
+ attribution: 'recorded',
311
+ });
312
+ }
313
+ }
314
+ //# sourceMappingURL=usage-ledger.recorder.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage-ledger.recorder.js","sourceRoot":"","sources":["../../../../../../backend/src/services/usage-ledger/usage-ledger.recorder.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Wires the usage ledger: store, recorder, rollup, categories, report.
3
+ * One instance per process (see {@link getUsageLedger}).
4
+ *
5
+ * @module services/usage-ledger/usage-ledger.runtime
6
+ */
7
+ import { LedgerRollup } from './ledger-rollup.js';
8
+ import { type TeamLookup } from './team-directory.js';
9
+ import { UsageCategoriesStore } from './usage-categories.store.js';
10
+ import { type BackfillResult } from './usage-ledger.backfill.js';
11
+ import { UsageLedgerRecorder } from './usage-ledger.recorder.js';
12
+ import { UsageLedgerStore } from './usage-ledger.store.js';
13
+ import { type CategoryLlm } from './unit-classifier.js';
14
+ import { UsageReportService } from './usage-report.service.js';
15
+ /** Overrides for tests. */
16
+ export interface UsageLedgerOptions {
17
+ /** Crewly home (default CREWLY_HOME) */
18
+ home?: string;
19
+ directory?: TeamLookup;
20
+ llm?: CategoryLlm | null;
21
+ }
22
+ /**
23
+ * The assembled ledger.
24
+ */
25
+ export declare class UsageLedger {
26
+ readonly store: UsageLedgerStore;
27
+ readonly rollup: LedgerRollup;
28
+ readonly categories: UsageCategoriesStore;
29
+ readonly directory: TeamLookup;
30
+ readonly recorder: UsageLedgerRecorder;
31
+ readonly reports: UsageReportService;
32
+ private readonly home;
33
+ private backfillTimer;
34
+ constructor(options?: UsageLedgerOptions);
35
+ /**
36
+ * Start recording and schedule the one-time history rebuild.
37
+ */
38
+ start(): Promise<void>;
39
+ /**
40
+ * Stop recording and write what is buffered.
41
+ */
42
+ stop(): Promise<void>;
43
+ /**
44
+ * Rebuild history (once; later calls do nothing).
45
+ *
46
+ * @returns What happened
47
+ */
48
+ backfill(): Promise<BackfillResult>;
49
+ }
50
+ /**
51
+ * The process-wide ledger.
52
+ *
53
+ * @returns The ledger (created on first use)
54
+ */
55
+ export declare function getUsageLedger(): UsageLedger;
56
+ /**
57
+ * Replace the process-wide ledger (tests).
58
+ *
59
+ * @param ledger - Ledger, or null to rebuild lazily
60
+ */
61
+ export declare function setUsageLedgerForTesting(ledger: UsageLedger | null): void;
62
+ //# sourceMappingURL=usage-ledger.runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage-ledger.runtime.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/usage-ledger/usage-ledger.runtime.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAiB,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,6BAA6B,CAAC;AACnE,OAAO,EAAgC,KAAK,cAAc,EAAE,MAAM,4BAA4B,CAAC;AAC/F,OAAO,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAmB,MAAM,yBAAyB,CAAC;AAC5E,OAAO,EAAsC,KAAK,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC5F,OAAO,EAAE,kBAAkB,EAAE,MAAM,2BAA2B,CAAC;AAK/D,2BAA2B;AAC3B,MAAM,WAAW,kBAAkB;IAClC,wCAAwC;IACxC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,UAAU,CAAC;IACvB,GAAG,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;CACzB;AAED;;GAEG;AACH,qBAAa,WAAW;IACvB,QAAQ,CAAC,KAAK,EAAE,gBAAgB,CAAC;IACjC,QAAQ,CAAC,MAAM,eAAsB;IACrC,QAAQ,CAAC,UAAU,EAAE,oBAAoB,CAAC;IAC1C,QAAQ,CAAC,SAAS,EAAE,UAAU,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,mBAAmB,CAAC;IACvC,QAAQ,CAAC,OAAO,EAAE,kBAAkB,CAAC;IACrC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,aAAa,CAA+B;gBAExC,OAAO,GAAE,kBAAuB;IAoB5C;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAW5B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAK3B;;;;OAIG;IACG,QAAQ,IAAI,OAAO,CAAC,cAAc,CAAC;CAazC;AAID;;;;GAIG;AACH,wBAAgB,cAAc,IAAI,WAAW,CAG5C;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CAEzE"}
@@ -0,0 +1,106 @@
1
+ /**
2
+ * Wires the usage ledger: store, recorder, rollup, categories, report.
3
+ * One instance per process (see {@link getUsageLedger}).
4
+ *
5
+ * @module services/usage-ledger/usage-ledger.runtime
6
+ */
7
+ import * as path from 'path';
8
+ import { TRACE_CONSTANTS } from '../../constants.js';
9
+ import { getCrewlyHomePath } from '../core/crewly-home.utils.js';
10
+ import { LoggerService } from '../core/logger.service.js';
11
+ import { TokenUsageService } from '../monitoring/token-usage.service.js';
12
+ import { LedgerRollup } from './ledger-rollup.js';
13
+ import { TeamDirectory } from './team-directory.js';
14
+ import { UsageCategoriesStore } from './usage-categories.store.js';
15
+ import { ensureLiveSince, runBackfill } from './usage-ledger.backfill.js';
16
+ import { UsageLedgerRecorder } from './usage-ledger.recorder.js';
17
+ import { UsageLedgerStore, LEDGER_DIR_NAME } from './usage-ledger.store.js';
18
+ import { defaultCategoryLlm, UnitClassifier } from './unit-classifier.js';
19
+ import { UsageReportService } from './usage-report.service.js';
20
+ /** Delay before the one-time history rebuild, so startup is not slowed. */
21
+ const BACKFILL_DELAY_MS = 120_000;
22
+ /**
23
+ * The assembled ledger.
24
+ */
25
+ export class UsageLedger {
26
+ store;
27
+ rollup = new LedgerRollup();
28
+ categories;
29
+ directory;
30
+ recorder;
31
+ reports;
32
+ home;
33
+ backfillTimer = null;
34
+ constructor(options = {}) {
35
+ this.home = options.home ?? getCrewlyHomePath();
36
+ const dir = path.join(this.home, LEDGER_DIR_NAME);
37
+ this.store = new UsageLedgerStore(dir);
38
+ this.categories = new UsageCategoriesStore(dir);
39
+ this.directory = options.directory ?? new TeamDirectory(this.home);
40
+ this.recorder = new UsageLedgerRecorder({ store: this.store, directory: this.directory });
41
+ const classifier = new UnitClassifier(dir, options.llm === undefined ? defaultCategoryLlm() : options.llm);
42
+ this.reports = new UsageReportService({
43
+ rollup: this.rollup,
44
+ directory: this.directory,
45
+ classifier,
46
+ categories: async () => (await this.categories.list()).categories,
47
+ sync: async () => {
48
+ await this.recorder.flush();
49
+ await this.rollup.refresh(this.store);
50
+ },
51
+ });
52
+ }
53
+ /**
54
+ * Start recording and schedule the one-time history rebuild.
55
+ */
56
+ async start() {
57
+ await ensureLiveSince(this.store.dir);
58
+ this.recorder.start();
59
+ this.backfillTimer = setTimeout(() => {
60
+ void this.backfill().catch((err) => LoggerService.getInstance().createComponentLogger('UsageLedger').warn('Ledger backfill failed', { error: err instanceof Error ? err.message : String(err) }));
61
+ }, BACKFILL_DELAY_MS);
62
+ this.backfillTimer.unref?.();
63
+ }
64
+ /**
65
+ * Stop recording and write what is buffered.
66
+ */
67
+ async stop() {
68
+ if (this.backfillTimer)
69
+ clearTimeout(this.backfillTimer);
70
+ await this.recorder.stop();
71
+ }
72
+ /**
73
+ * Rebuild history (once; later calls do nothing).
74
+ *
75
+ * @returns What happened
76
+ */
77
+ async backfill() {
78
+ await this.directory.ready();
79
+ const liveSince = await ensureLiveSince(this.store.dir);
80
+ return runBackfill(this.store, {
81
+ forEachUsage: (visit) => TokenUsageService.getInstance().forEachEvent(visit),
82
+ traceDir: path.join(this.home, TRACE_CONSTANTS.DIR_NAME),
83
+ directory: this.directory,
84
+ }, { cutoffMs: Date.parse(liveSince) });
85
+ }
86
+ }
87
+ let instance = null;
88
+ /**
89
+ * The process-wide ledger.
90
+ *
91
+ * @returns The ledger (created on first use)
92
+ */
93
+ export function getUsageLedger() {
94
+ if (!instance)
95
+ instance = new UsageLedger();
96
+ return instance;
97
+ }
98
+ /**
99
+ * Replace the process-wide ledger (tests).
100
+ *
101
+ * @param ledger - Ledger, or null to rebuild lazily
102
+ */
103
+ export function setUsageLedgerForTesting(ledger) {
104
+ instance = ledger;
105
+ }
106
+ //# sourceMappingURL=usage-ledger.runtime.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage-ledger.runtime.js","sourceRoot":"","sources":["../../../../../../backend/src/services/usage-ledger/usage-ledger.runtime.ts"],"names":[],"mappings":"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"}