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,166 @@
1
+ /**
2
+ * The owner's own categories for usage reports ("self-media", "book", …).
3
+ *
4
+ * Categories are optional and never written into ticket facts: they only
5
+ * decide how a report groups tickets. Each definition has a natural-language
6
+ * description and optional hints (keywords, team names, project names). The
7
+ * set carries a version that changes whenever a definition changes; the
8
+ * classification cache is keyed on it.
9
+ *
10
+ * @module services/usage-ledger/usage-categories.store
11
+ */
12
+ import { createHash } from 'crypto';
13
+ import { promises as fs } from 'fs';
14
+ import * as path from 'path';
15
+ import { atomicWriteJson } from '../../utils/file-io.utils.js';
16
+ import { getCrewlyHomePath } from '../core/crewly-home.utils.js';
17
+ import { LEDGER_DIR_NAME } from './usage-ledger.store.js';
18
+ /** File holding the definitions. */
19
+ export const CATEGORIES_FILE = 'categories.json';
20
+ /** Longest name / description / hint accepted. */
21
+ const MAX_TEXT = 400;
22
+ const MAX_HINTS = 60;
23
+ const MAX_CATEGORIES = 40;
24
+ /**
25
+ * Clean a list of hints.
26
+ *
27
+ * @param value - Candidate list
28
+ * @returns Trimmed, de-duplicated strings (empty list becomes undefined)
29
+ */
30
+ function cleanList(value) {
31
+ if (!Array.isArray(value))
32
+ return undefined;
33
+ const out = [...new Set(value.filter((v) => typeof v === 'string').map((v) => v.trim().slice(0, 120)).filter(Boolean))];
34
+ return out.length > 0 ? out.slice(0, MAX_HINTS) : undefined;
35
+ }
36
+ /**
37
+ * Validate and normalise a definition.
38
+ *
39
+ * @param input - Candidate
40
+ * @returns The definition, or an error text
41
+ */
42
+ export function normalizeCategory(input) {
43
+ if (!input || typeof input !== 'object')
44
+ return 'category must be an object';
45
+ const raw = input;
46
+ const name = typeof raw.name === 'string' ? raw.name.trim().slice(0, 60) : '';
47
+ if (!name)
48
+ return 'category needs a name';
49
+ if (name.toLowerCase() === 'other')
50
+ return '"other" is reserved for tickets that match nothing';
51
+ const description = typeof raw.description === 'string' && raw.description.trim() ? raw.description.trim().slice(0, MAX_TEXT) : undefined;
52
+ const keywords = cleanList(raw.keywords);
53
+ const teams = cleanList(raw.teams);
54
+ const projects = cleanList(raw.projects);
55
+ return {
56
+ name,
57
+ ...(description ? { description } : {}),
58
+ ...(keywords ? { keywords } : {}),
59
+ ...(teams ? { teams } : {}),
60
+ ...(projects ? { projects } : {}),
61
+ };
62
+ }
63
+ /**
64
+ * Identity of a set of definitions: the same definitions always give the same
65
+ * id, so a classification cache survives a set being re-entered unchanged.
66
+ *
67
+ * @param defs - Definitions
68
+ * @returns `default` for none, else a short hash
69
+ */
70
+ export function categorySetId(defs) {
71
+ if (defs.length === 0)
72
+ return 'default';
73
+ const canonical = defs.map((d) => [d.name.toLowerCase(), d.description ?? '', d.keywords ?? [], d.teams ?? [], d.projects ?? []]);
74
+ return createHash('sha1').update(JSON.stringify(canonical)).digest('hex').slice(0, 10);
75
+ }
76
+ /**
77
+ * File-backed category definitions.
78
+ */
79
+ export class UsageCategoriesStore {
80
+ dir;
81
+ file;
82
+ /**
83
+ * @param dir - Ledger directory (default `~/.crewly/usage-ledger`)
84
+ */
85
+ constructor(dir = path.join(getCrewlyHomePath(), LEDGER_DIR_NAME)) {
86
+ this.dir = dir;
87
+ this.file = path.join(dir, CATEGORIES_FILE);
88
+ }
89
+ async read() {
90
+ try {
91
+ const parsed = JSON.parse(await fs.readFile(this.file, 'utf-8'));
92
+ const categories = (Array.isArray(parsed.categories) ? parsed.categories : [])
93
+ .map(normalizeCategory)
94
+ .filter((c) => typeof c !== 'string');
95
+ return { version: Number(parsed.version) || 0, updatedAt: parsed.updatedAt ?? '', categories };
96
+ }
97
+ catch {
98
+ return { version: 0, updatedAt: '', categories: [] };
99
+ }
100
+ }
101
+ async write(categories, previousVersion) {
102
+ const next = { version: previousVersion + 1, updatedAt: new Date().toISOString(), categories };
103
+ await fs.mkdir(this.dir, { recursive: true });
104
+ await atomicWriteJson(this.file, next);
105
+ return next;
106
+ }
107
+ /**
108
+ * The current definitions.
109
+ *
110
+ * @returns Version, set id and definitions
111
+ */
112
+ async list() {
113
+ const file = await this.read();
114
+ return { version: file.version, setId: categorySetId(file.categories), updatedAt: file.updatedAt, categories: file.categories };
115
+ }
116
+ /**
117
+ * Add or replace one category (matched by name, case-insensitive).
118
+ *
119
+ * @param input - The definition
120
+ * @returns The new state, or an error text
121
+ */
122
+ async set(input) {
123
+ const def = normalizeCategory(input);
124
+ if (typeof def === 'string')
125
+ return def;
126
+ const file = await this.read();
127
+ const rest = file.categories.filter((c) => c.name.toLowerCase() !== def.name.toLowerCase());
128
+ if (rest.length >= MAX_CATEGORIES)
129
+ return `at most ${MAX_CATEGORIES} categories`;
130
+ const written = await this.write([...rest, def], file.version);
131
+ return { version: written.version, categories: written.categories };
132
+ }
133
+ /**
134
+ * Replace every definition.
135
+ *
136
+ * @param inputs - The new set (empty clears it)
137
+ * @returns The new state, or an error text
138
+ */
139
+ async replaceAll(inputs) {
140
+ const defs = [];
141
+ for (const input of inputs.slice(0, MAX_CATEGORIES)) {
142
+ const def = normalizeCategory(input);
143
+ if (typeof def === 'string')
144
+ return def;
145
+ defs.push(def);
146
+ }
147
+ const file = await this.read();
148
+ const written = await this.write(defs, file.version);
149
+ return { version: written.version, categories: written.categories };
150
+ }
151
+ /**
152
+ * Remove one category.
153
+ *
154
+ * @param name - Its name (case-insensitive)
155
+ * @returns The new state, or null when there was no such category
156
+ */
157
+ async remove(name) {
158
+ const file = await this.read();
159
+ const rest = file.categories.filter((c) => c.name.toLowerCase() !== name.trim().toLowerCase());
160
+ if (rest.length === file.categories.length)
161
+ return null;
162
+ const written = await this.write(rest, file.version);
163
+ return { version: written.version, categories: written.categories };
164
+ }
165
+ }
166
+ //# sourceMappingURL=usage-categories.store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage-categories.store.js","sourceRoot":"","sources":["../../../../../../backend/src/services/usage-ledger/usage-categories.store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,90 @@
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 { type TokenUsageEvent } from '../monitoring/token-usage.service.js';
22
+ import type { TeamLookup } from './team-directory.js';
23
+ import type { UsageLedgerStore } from './usage-ledger.store.js';
24
+ /** An unticketed event this soon after a delivery is credited to the delivery's trace. */
25
+ export declare const INFER_MAX_GAP_MS: number;
26
+ /** File with the ledger's own bookkeeping. */
27
+ export declare const STATE_FILE = "state.json";
28
+ /** Bookkeeping persisted beside the facts. */
29
+ export interface LedgerState {
30
+ /** When live recording began (the backfill cutoff) */
31
+ liveSince?: string;
32
+ backfill?: {
33
+ doneAt: string;
34
+ cutoff: string;
35
+ facts: number;
36
+ usageEvents: number;
37
+ inferredEvents: number;
38
+ };
39
+ }
40
+ /** Where history comes from. */
41
+ export interface BackfillSources {
42
+ /** Usage events of every session */
43
+ forEachUsage: (visit: (session: string, event: TokenUsageEvent) => void) => void;
44
+ /** The traces directory (index.json + `<id>.jsonl`) */
45
+ traceDir: string;
46
+ directory: TeamLookup;
47
+ }
48
+ /** What a backfill did. */
49
+ export interface BackfillResult {
50
+ ran: boolean;
51
+ reason?: string;
52
+ facts: number;
53
+ usageEvents: number;
54
+ inferredEvents: number;
55
+ traces: number;
56
+ }
57
+ /**
58
+ * Read the ledger bookkeeping.
59
+ *
60
+ * @param dir - Ledger directory
61
+ * @returns State (empty when none)
62
+ */
63
+ export declare function readLedgerState(dir: string): Promise<LedgerState>;
64
+ /**
65
+ * Write the ledger bookkeeping.
66
+ *
67
+ * @param dir - Ledger directory
68
+ * @param state - State
69
+ */
70
+ export declare function writeLedgerState(dir: string, state: LedgerState): Promise<void>;
71
+ /**
72
+ * Note when live recording began (once).
73
+ *
74
+ * @param dir - Ledger directory
75
+ * @param now - Now (ms)
76
+ * @returns The cutoff
77
+ */
78
+ export declare function ensureLiveSince(dir: string, now?: number): Promise<string>;
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 declare function runBackfill(store: UsageLedgerStore, sources: BackfillSources, opts: {
88
+ cutoffMs: number;
89
+ }): Promise<BackfillResult>;
90
+ //# sourceMappingURL=usage-ledger.backfill.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage-ledger.backfill.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/usage-ledger/usage-ledger.backfill.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAOH,OAAO,EAA6B,KAAK,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAGvG,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAGhE,0FAA0F;AAC1F,eAAO,MAAM,gBAAgB,QAAgC,CAAC;AAE9D,8CAA8C;AAC9C,eAAO,MAAM,UAAU,eAAe,CAAC;AAEvC,8CAA8C;AAC9C,MAAM,WAAW,WAAW;IAC3B,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAA;KAAE,CAAC;CAC1G;AAED,gCAAgC;AAChC,MAAM,WAAW,eAAe;IAC/B,oCAAoC;IACpC,YAAY,EAAE,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,eAAe,KAAK,IAAI,KAAK,IAAI,CAAC;IACjF,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,UAAU,CAAC;CACtB;AAED,2BAA2B;AAC3B,MAAM,WAAW,cAAc;IAC9B,GAAG,EAAE,OAAO,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CACf;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAMvE;AAED;;;;;GAKG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAGrF;AAED;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,GAAE,MAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CAM5F;AAUD;;;;;;;GAOG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,gBAAgB,EAAE,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,GAAG,OAAO,CAAC,cAAc,CAAC,CAsMxI"}
@@ -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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"}