crewly 1.20.187 → 1.20.188

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 (141) hide show
  1. package/config/skills/agent/core/project-tickets/SKILL.md +3 -2
  2. package/config/skills/agent/core/project-tickets/execute.sh +4 -4
  3. package/config/skills/agent/core/project-tickets/execute.test.sh +2 -2
  4. package/dist/backend/backend/src/constants.d.ts +70 -12
  5. package/dist/backend/backend/src/constants.d.ts.map +1 -1
  6. package/dist/backend/backend/src/constants.js +70 -12
  7. package/dist/backend/backend/src/constants.js.map +1 -1
  8. package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.d.ts +1 -1
  9. package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.d.ts.map +1 -1
  10. package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.js +5 -1
  11. package/dist/backend/backend/src/controllers/project-tickets/project-tickets.controller.js.map +1 -1
  12. package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.d.ts +1 -1
  13. package/dist/backend/backend/src/controllers/project-tickets/project-tickets.routes.js +1 -1
  14. package/dist/backend/backend/src/controllers/system/usage.controller.d.ts +46 -0
  15. package/dist/backend/backend/src/controllers/system/usage.controller.d.ts.map +1 -0
  16. package/dist/backend/backend/src/controllers/system/usage.controller.js +181 -0
  17. package/dist/backend/backend/src/controllers/system/usage.controller.js.map +1 -0
  18. package/dist/backend/backend/src/index.d.ts +7 -0
  19. package/dist/backend/backend/src/index.d.ts.map +1 -1
  20. package/dist/backend/backend/src/index.js +59 -4
  21. package/dist/backend/backend/src/index.js.map +1 -1
  22. package/dist/backend/backend/src/routes/modules/system.routes.js +3 -3
  23. package/dist/backend/backend/src/routes/modules/system.routes.js.map +1 -1
  24. package/dist/backend/backend/src/services/agent/agent-registration.service.js +7 -7
  25. package/dist/backend/backend/src/services/agent/agent-registration.service.js.map +1 -1
  26. package/dist/backend/backend/src/services/messaging/owner-message-watchdog.service.d.ts +4 -2
  27. package/dist/backend/backend/src/services/messaging/owner-message-watchdog.service.d.ts.map +1 -1
  28. package/dist/backend/backend/src/services/messaging/owner-message-watchdog.service.js +6 -1
  29. package/dist/backend/backend/src/services/messaging/owner-message-watchdog.service.js.map +1 -1
  30. package/dist/backend/backend/src/services/messaging/queue-processor.service.js +2 -2
  31. package/dist/backend/backend/src/services/monitoring/activity-monitor.service.d.ts.map +1 -1
  32. package/dist/backend/backend/src/services/monitoring/activity-monitor.service.js +4 -2
  33. package/dist/backend/backend/src/services/monitoring/activity-monitor.service.js.map +1 -1
  34. package/dist/backend/backend/src/services/monitoring/antigravity-usage-sync.service.d.ts +130 -0
  35. package/dist/backend/backend/src/services/monitoring/antigravity-usage-sync.service.d.ts.map +1 -0
  36. package/dist/backend/backend/src/services/monitoring/antigravity-usage-sync.service.js +274 -0
  37. package/dist/backend/backend/src/services/monitoring/antigravity-usage-sync.service.js.map +1 -0
  38. package/dist/backend/backend/src/services/monitoring/codex-rollout-sync.service.d.ts +152 -0
  39. package/dist/backend/backend/src/services/monitoring/codex-rollout-sync.service.d.ts.map +1 -0
  40. package/dist/backend/backend/src/services/monitoring/codex-rollout-sync.service.js +311 -0
  41. package/dist/backend/backend/src/services/monitoring/codex-rollout-sync.service.js.map +1 -0
  42. package/dist/backend/backend/src/services/monitoring/token-usage.service.d.ts +53 -1
  43. package/dist/backend/backend/src/services/monitoring/token-usage.service.d.ts.map +1 -1
  44. package/dist/backend/backend/src/services/monitoring/token-usage.service.js +51 -3
  45. package/dist/backend/backend/src/services/monitoring/token-usage.service.js.map +1 -1
  46. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.d.ts +4 -4
  47. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.d.ts.map +1 -1
  48. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.js +1 -1
  49. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-decision.js.map +1 -1
  50. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.d.ts +4 -3
  51. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.d.ts.map +1 -1
  52. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.js +7 -4
  53. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot-messages.js.map +1 -1
  54. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.d.ts +40 -9
  55. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.d.ts.map +1 -1
  56. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.js +68 -20
  57. package/dist/backend/backend/src/services/project-tickets/ticket-autopilot.service.js.map +1 -1
  58. package/dist/backend/backend/src/services/spend/spend-cap-command.d.ts +48 -18
  59. package/dist/backend/backend/src/services/spend/spend-cap-command.d.ts.map +1 -1
  60. package/dist/backend/backend/src/services/spend/spend-cap-command.js +195 -62
  61. package/dist/backend/backend/src/services/spend/spend-cap-command.js.map +1 -1
  62. package/dist/backend/backend/src/services/spend/spend-cap.gate.d.ts +11 -15
  63. package/dist/backend/backend/src/services/spend/spend-cap.gate.d.ts.map +1 -1
  64. package/dist/backend/backend/src/services/spend/spend-cap.gate.js +8 -13
  65. package/dist/backend/backend/src/services/spend/spend-cap.gate.js.map +1 -1
  66. package/dist/backend/backend/src/services/spend/spend-cap.service.d.ts +179 -64
  67. package/dist/backend/backend/src/services/spend/spend-cap.service.d.ts.map +1 -1
  68. package/dist/backend/backend/src/services/spend/spend-cap.service.js +406 -149
  69. package/dist/backend/backend/src/services/spend/spend-cap.service.js.map +1 -1
  70. package/dist/backend/backend/src/services/spend/spend-cap.store.d.ts +52 -11
  71. package/dist/backend/backend/src/services/spend/spend-cap.store.d.ts.map +1 -1
  72. package/dist/backend/backend/src/services/spend/spend-cap.store.js +67 -21
  73. package/dist/backend/backend/src/services/spend/spend-cap.store.js.map +1 -1
  74. package/dist/backend/backend/src/services/spend/spend-cap.wiring.d.ts +3 -1
  75. package/dist/backend/backend/src/services/spend/spend-cap.wiring.d.ts.map +1 -1
  76. package/dist/backend/backend/src/services/spend/spend-cap.wiring.js +21 -7
  77. package/dist/backend/backend/src/services/spend/spend-cap.wiring.js.map +1 -1
  78. package/dist/backend/backend/src/services/spend/spend-ledger.service.d.ts +57 -36
  79. package/dist/backend/backend/src/services/spend/spend-ledger.service.d.ts.map +1 -1
  80. package/dist/backend/backend/src/services/spend/spend-ledger.service.js +80 -55
  81. package/dist/backend/backend/src/services/spend/spend-ledger.service.js.map +1 -1
  82. package/dist/backend/backend/src/services/task-pool/work-item-usage.d.ts +10 -1
  83. package/dist/backend/backend/src/services/task-pool/work-item-usage.d.ts.map +1 -1
  84. package/dist/backend/backend/src/services/task-pool/work-item-usage.js +2 -0
  85. package/dist/backend/backend/src/services/task-pool/work-item-usage.js.map +1 -1
  86. package/dist/backend/backend/src/services/usage/token-format.d.ts +49 -0
  87. package/dist/backend/backend/src/services/usage/token-format.d.ts.map +1 -0
  88. package/dist/backend/backend/src/services/usage/token-format.js +81 -0
  89. package/dist/backend/backend/src/services/usage/token-format.js.map +1 -0
  90. package/dist/backend/backend/src/services/usage/usage-stats.service.d.ts +132 -0
  91. package/dist/backend/backend/src/services/usage/usage-stats.service.d.ts.map +1 -0
  92. package/dist/backend/backend/src/services/usage/usage-stats.service.js +226 -0
  93. package/dist/backend/backend/src/services/usage/usage-stats.service.js.map +1 -0
  94. package/dist/backend/backend/src/types/decision.types.d.ts +2 -2
  95. package/dist/backend/backend/src/types/ticket-autopilot.types.d.ts +24 -7
  96. package/dist/backend/backend/src/types/ticket-autopilot.types.d.ts.map +1 -1
  97. package/dist/backend/backend/src/types/ticket-autopilot.types.js +29 -13
  98. package/dist/backend/backend/src/types/ticket-autopilot.types.js.map +1 -1
  99. package/dist/backend/build-info.json +2 -2
  100. package/dist/cli/backend/src/constants.d.ts +70 -12
  101. package/dist/cli/backend/src/constants.d.ts.map +1 -1
  102. package/dist/cli/backend/src/constants.js +70 -12
  103. package/dist/cli/backend/src/constants.js.map +1 -1
  104. package/dist/cli/backend/src/services/agent/agent-registration.service.js +7 -7
  105. package/dist/cli/backend/src/services/agent/agent-registration.service.js.map +1 -1
  106. package/dist/cli/backend/src/services/messaging/owner-message-watchdog.service.d.ts +4 -2
  107. package/dist/cli/backend/src/services/messaging/owner-message-watchdog.service.d.ts.map +1 -1
  108. package/dist/cli/backend/src/services/messaging/owner-message-watchdog.service.js +6 -1
  109. package/dist/cli/backend/src/services/messaging/owner-message-watchdog.service.js.map +1 -1
  110. package/dist/cli/backend/src/services/messaging/queue-processor.service.js +2 -2
  111. package/dist/cli/backend/src/services/monitoring/activity-monitor.service.d.ts.map +1 -1
  112. package/dist/cli/backend/src/services/monitoring/activity-monitor.service.js +4 -2
  113. package/dist/cli/backend/src/services/monitoring/activity-monitor.service.js.map +1 -1
  114. package/dist/cli/backend/src/services/monitoring/token-usage.service.d.ts +53 -1
  115. package/dist/cli/backend/src/services/monitoring/token-usage.service.d.ts.map +1 -1
  116. package/dist/cli/backend/src/services/monitoring/token-usage.service.js +51 -3
  117. package/dist/cli/backend/src/services/monitoring/token-usage.service.js.map +1 -1
  118. package/dist/cli/backend/src/services/spend/spend-cap.gate.d.ts +11 -15
  119. package/dist/cli/backend/src/services/spend/spend-cap.gate.d.ts.map +1 -1
  120. package/dist/cli/backend/src/services/spend/spend-cap.gate.js +8 -13
  121. package/dist/cli/backend/src/services/spend/spend-cap.gate.js.map +1 -1
  122. package/dist/cli/backend/src/services/task-pool/work-item-usage.d.ts +10 -1
  123. package/dist/cli/backend/src/services/task-pool/work-item-usage.d.ts.map +1 -1
  124. package/dist/cli/backend/src/services/task-pool/work-item-usage.js +2 -0
  125. package/dist/cli/backend/src/services/task-pool/work-item-usage.js.map +1 -1
  126. package/dist/cli/backend/src/services/usage/token-format.d.ts +49 -0
  127. package/dist/cli/backend/src/services/usage/token-format.d.ts.map +1 -0
  128. package/dist/cli/backend/src/services/usage/token-format.js +81 -0
  129. package/dist/cli/backend/src/services/usage/token-format.js.map +1 -0
  130. package/dist/cli/backend/src/types/decision.types.d.ts +2 -2
  131. package/dist/cli/backend/src/types/ticket-autopilot.types.d.ts +24 -7
  132. package/dist/cli/backend/src/types/ticket-autopilot.types.d.ts.map +1 -1
  133. package/dist/cli/backend/src/types/ticket-autopilot.types.js +29 -13
  134. package/dist/cli/backend/src/types/ticket-autopilot.types.js.map +1 -1
  135. package/frontend/dist/assets/{index-15c2faf2.js → index-49f50b45.js} +276 -276
  136. package/frontend/dist/index.html +1 -1
  137. package/package.json +1 -1
  138. package/dist/backend/backend/src/controllers/system/spend.controller.d.ts +0 -32
  139. package/dist/backend/backend/src/controllers/system/spend.controller.d.ts.map +0 -1
  140. package/dist/backend/backend/src/controllers/system/spend.controller.js +0 -100
  141. package/dist/backend/backend/src/controllers/system/spend.controller.js.map +0 -1
@@ -0,0 +1,132 @@
1
+ /**
2
+ * Usage stats — tokens grouped by agent, team, project, work item, runtime
3
+ * or day, over the last N local days (`GET /api/system/usage`).
4
+ *
5
+ * The unit is the token unit ({@link eventTokens}: input incl. cached +
6
+ * output); cached input is reported beside it. Every event lands in exactly
7
+ * one row of a grouping (unattributable usage gets its own row), so each
8
+ * grouping sums to the same total — except `workItem`, which lists the top
9
+ * work items only.
10
+ *
11
+ * Attribution:
12
+ * - team: the session's team membership (the orc and unknown sessions are
13
+ * "(unattributed)");
14
+ * - work item: {@link computeWorkItemUsage} — the agent's usage between the
15
+ * item's start and completion (clipped to the window);
16
+ * - project: the work item running when the event happened, if it names a
17
+ * project (`metadata.projectId`) or its agent's team works on exactly one
18
+ * project; otherwise the session's team when it works on exactly one
19
+ * project; otherwise "(unattributed)".
20
+ *
21
+ * specs/2026-10-02-spend-cap.md §Stats
22
+ *
23
+ * @module services/usage/usage-stats.service
24
+ */
25
+ import { type TokenUsageEvent } from '../monitoring/token-usage.service.js';
26
+ import { type SessionUsageWindowSource } from '../task-pool/work-item-usage.js';
27
+ /** A grouping. */
28
+ export type UsageGroupBy = 'agent' | 'team' | 'project' | 'workItem' | 'runtime' | 'day';
29
+ /** Token figures. */
30
+ export interface UsageTokens {
31
+ /** Input tokens, cached included */
32
+ input: number;
33
+ /** Of `input`, the cached part */
34
+ cachedInput: number;
35
+ output: number;
36
+ /** input + output — the unit caps count */
37
+ total: number;
38
+ /** Usage events (model calls / turns) */
39
+ events: number;
40
+ }
41
+ /** One row of a grouping. */
42
+ export interface UsageRow extends UsageTokens {
43
+ /** Session / team id / project id / work item id / runtime / `YYYY-MM-DD` */
44
+ key: string;
45
+ label: string;
46
+ /** Share of the window total (0–1) */
47
+ share: number;
48
+ /** Dashboard link (work items) */
49
+ link?: string;
50
+ /** Extra facts: `team` / `agent` / `status` / `runtimes` */
51
+ meta?: Record<string, string | string[]>;
52
+ }
53
+ /** What `GET /api/system/usage` returns. */
54
+ export interface UsageStats {
55
+ days: number;
56
+ /** Window start (local midnight), ISO */
57
+ since: string;
58
+ /** Local day of now */
59
+ today: string;
60
+ totals: UsageTokens;
61
+ todayTotals: UsageTokens;
62
+ groupBy: UsageGroupBy[];
63
+ /** Rows of the first grouping */
64
+ rows: UsageRow[];
65
+ /** Rows of every requested grouping */
66
+ groups: Partial<Record<UsageGroupBy, UsageRow[]>>;
67
+ }
68
+ /** A team as stats need it. */
69
+ export interface UsageTeam {
70
+ id: string;
71
+ name: string;
72
+ members: Array<{
73
+ session: string;
74
+ name: string;
75
+ }>;
76
+ projectIds: string[];
77
+ }
78
+ /** A work item as stats need it. */
79
+ export interface UsageWorkItem {
80
+ id: string;
81
+ title: string;
82
+ status: string;
83
+ /** Agent session that ran it */
84
+ target?: string;
85
+ createdAt: string;
86
+ startedAt?: string;
87
+ completedAt?: string;
88
+ metadata?: Record<string, unknown>;
89
+ }
90
+ /** Collaborators. */
91
+ export interface UsageStatsDeps {
92
+ /** The token ledger (TokenUsageService) */
93
+ ledger: SessionUsageWindowSource & {
94
+ forEachEvent(visit: (sessionName: string, event: TokenUsageEvent) => void, since?: Date): void;
95
+ };
96
+ teams: () => Promise<UsageTeam[]>;
97
+ projects: () => Promise<Array<{
98
+ id: string;
99
+ name: string;
100
+ }>>;
101
+ workItems: () => Promise<UsageWorkItem[]>;
102
+ now?: () => Date;
103
+ }
104
+ /**
105
+ * Parse `groupBy` (one value or a comma list).
106
+ *
107
+ * @param raw - Query value
108
+ * @returns Valid groupings (default `agent`)
109
+ */
110
+ export declare function parseGroupBy(raw: unknown): UsageGroupBy[];
111
+ /**
112
+ * Token usage stats.
113
+ */
114
+ export declare class UsageStatsService {
115
+ private readonly deps;
116
+ private readonly now;
117
+ /** @param deps - Collaborators */
118
+ constructor(deps: UsageStatsDeps);
119
+ /**
120
+ * Aggregate the window.
121
+ *
122
+ * @param days - Local days, today included (clamped to 1…MAX_DAYS)
123
+ * @param groupBy - Groupings
124
+ * @returns Stats
125
+ */
126
+ query(days: number, groupBy: UsageGroupBy[]): Promise<UsageStats>;
127
+ /**
128
+ * Top work items in the window by tokens.
129
+ */
130
+ private workItemRows;
131
+ }
132
+ //# sourceMappingURL=usage-stats.service.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage-stats.service.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/services/usage/usage-stats.service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,226 @@
1
+ /**
2
+ * Usage stats — tokens grouped by agent, team, project, work item, runtime
3
+ * or day, over the last N local days (`GET /api/system/usage`).
4
+ *
5
+ * The unit is the token unit ({@link eventTokens}: input incl. cached +
6
+ * output); cached input is reported beside it. Every event lands in exactly
7
+ * one row of a grouping (unattributable usage gets its own row), so each
8
+ * grouping sums to the same total — except `workItem`, which lists the top
9
+ * work items only.
10
+ *
11
+ * Attribution:
12
+ * - team: the session's team membership (the orc and unknown sessions are
13
+ * "(unattributed)");
14
+ * - work item: {@link computeWorkItemUsage} — the agent's usage between the
15
+ * item's start and completion (clipped to the window);
16
+ * - project: the work item running when the event happened, if it names a
17
+ * project (`metadata.projectId`) or its agent's team works on exactly one
18
+ * project; otherwise the session's team when it works on exactly one
19
+ * project; otherwise "(unattributed)".
20
+ *
21
+ * specs/2026-10-02-spend-cap.md §Stats
22
+ *
23
+ * @module services/usage/usage-stats.service
24
+ */
25
+ import { ORCHESTRATOR_SESSION_NAME, SPEND_CAP_CONSTANTS, USAGE_CONSTANTS as U } from '../../constants.js';
26
+ import { eventTokens } from '../monitoring/token-usage.service.js';
27
+ import { localDateKey } from '../project-tickets/ticket-autopilot-decision.js';
28
+ import { runtimeOfEvent, windowDays } from '../spend/spend-ledger.service.js';
29
+ import { computeWorkItemUsage } from '../task-pool/work-item-usage.js';
30
+ /** Zero figures. */
31
+ function zero() {
32
+ return { input: 0, cachedInput: 0, output: 0, total: 0, events: 0 };
33
+ }
34
+ /** Add one event's tokens. */
35
+ function add(into, e) {
36
+ const t = eventTokens(e);
37
+ into.input += t.input;
38
+ into.cachedInput += t.cachedInput;
39
+ into.output += t.output;
40
+ into.total += t.total;
41
+ into.events += 1;
42
+ }
43
+ /**
44
+ * Parse `groupBy` (one value or a comma list).
45
+ *
46
+ * @param raw - Query value
47
+ * @returns Valid groupings (default `agent`)
48
+ */
49
+ export function parseGroupBy(raw) {
50
+ const parts = String(raw ?? '')
51
+ .split(',')
52
+ .map((s) => s.trim())
53
+ .filter((s) => U.GROUP_BY.includes(s));
54
+ return parts.length > 0 ? [...new Set(parts)] : ['agent'];
55
+ }
56
+ /**
57
+ * Token usage stats.
58
+ */
59
+ export class UsageStatsService {
60
+ deps;
61
+ now;
62
+ /** @param deps - Collaborators */
63
+ constructor(deps) {
64
+ this.deps = deps;
65
+ this.now = deps.now ?? (() => new Date());
66
+ }
67
+ /**
68
+ * Aggregate the window.
69
+ *
70
+ * @param days - Local days, today included (clamped to 1…MAX_DAYS)
71
+ * @param groupBy - Groupings
72
+ * @returns Stats
73
+ */
74
+ async query(days, groupBy) {
75
+ const now = this.now();
76
+ const n = Math.min(SPEND_CAP_CONSTANTS.MAX_DAYS, Math.max(1, Math.floor(Number.isFinite(days) ? days : SPEND_CAP_CONSTANTS.DEFAULT_DAYS)));
77
+ const { since } = windowDays(now, n);
78
+ const today = localDateKey(now);
79
+ const [teams, projects, items] = await Promise.all([
80
+ this.deps.teams().catch(() => []),
81
+ this.deps.projects().catch(() => []),
82
+ groupBy.includes('workItem') || groupBy.includes('project') ? this.deps.workItems().catch(() => []) : Promise.resolve([]),
83
+ ]);
84
+ const teamOf = new Map();
85
+ const nameOf = new Map([[ORCHESTRATOR_SESSION_NAME, 'Orc']]);
86
+ for (const t of teams) {
87
+ for (const m of t.members) {
88
+ if (!m.session)
89
+ continue;
90
+ if (!teamOf.has(m.session))
91
+ teamOf.set(m.session, t);
92
+ nameOf.set(m.session, m.name || m.session);
93
+ }
94
+ }
95
+ const projectName = new Map(projects.map((p) => [p.id, p.name]));
96
+ const teamProject = (t) => (t && t.projectIds.length === 1 ? t.projectIds[0] : null);
97
+ // Work item windows per session, for project attribution.
98
+ const windows = new Map();
99
+ for (const wi of items) {
100
+ if (!wi.target)
101
+ continue;
102
+ const pid = typeof wi.metadata?.projectId === 'string' ? wi.metadata.projectId : teamProject(teamOf.get(wi.target));
103
+ if (!pid)
104
+ continue;
105
+ const start = new Date(wi.startedAt ?? wi.createdAt).getTime();
106
+ const end = wi.completedAt ? new Date(wi.completedAt).getTime() : now.getTime();
107
+ if (!Number.isFinite(start) || !Number.isFinite(end) || end < start)
108
+ continue;
109
+ const list = windows.get(wi.target) ?? [];
110
+ list.push({ start, end, projectId: pid });
111
+ windows.set(wi.target, list);
112
+ }
113
+ for (const list of windows.values())
114
+ list.sort((a, b) => b.start - a.start);
115
+ const projectOfEvent = (session, ms) => {
116
+ const hit = windows.get(session)?.find((w) => w.start <= ms && ms <= w.end);
117
+ return hit?.projectId ?? teamProject(teamOf.get(session));
118
+ };
119
+ const totals = zero();
120
+ const todayTotals = zero();
121
+ const buckets = new Map();
122
+ const bucketOf = (g, key, label, meta) => {
123
+ let map = buckets.get(g);
124
+ if (!map) {
125
+ map = new Map();
126
+ buckets.set(g, map);
127
+ }
128
+ let row = map.get(key);
129
+ if (!row) {
130
+ row = { key, label, share: 0, ...zero(), ...(meta ? { meta } : {}) };
131
+ map.set(key, row);
132
+ }
133
+ return row;
134
+ };
135
+ const eventGroupings = groupBy.filter((g) => g !== 'workItem');
136
+ const runtimesOf = new Map();
137
+ this.deps.ledger.forEachEvent((session, e) => {
138
+ const ms = new Date(e.timestamp).getTime();
139
+ if (!Number.isFinite(ms) || ms > now.getTime())
140
+ return;
141
+ add(totals, e);
142
+ const day = localDateKey(new Date(ms));
143
+ if (day === today)
144
+ add(todayTotals, e);
145
+ const runtime = runtimeOfEvent(e);
146
+ runtimesOf.set(session, (runtimesOf.get(session) ?? new Set()).add(runtime));
147
+ for (const g of eventGroupings) {
148
+ let row;
149
+ if (g === 'agent') {
150
+ const team = teamOf.get(session);
151
+ row = bucketOf(g, session, nameOf.get(session) ?? session, team ? { team: team.name } : undefined);
152
+ }
153
+ else if (g === 'team') {
154
+ const team = teamOf.get(session);
155
+ row = team ? bucketOf(g, team.id, team.name) : bucketOf(g, U.UNATTRIBUTED, session === ORCHESTRATOR_SESSION_NAME ? 'Orc (no team)' : U.UNATTRIBUTED);
156
+ }
157
+ else if (g === 'runtime') {
158
+ row = bucketOf(g, runtime, runtime);
159
+ }
160
+ else if (g === 'day') {
161
+ row = bucketOf(g, day, day);
162
+ }
163
+ else {
164
+ const pid = projectOfEvent(session, ms);
165
+ row = pid ? bucketOf(g, pid, projectName.get(pid) ?? pid) : bucketOf(g, U.UNATTRIBUTED, U.UNATTRIBUTED);
166
+ }
167
+ add(row, e);
168
+ }
169
+ }, since);
170
+ const groups = {};
171
+ for (const g of groupBy) {
172
+ let rows;
173
+ if (g === 'workItem') {
174
+ rows = this.workItemRows(items, since, now, teamOf, nameOf);
175
+ }
176
+ else {
177
+ rows = [...(buckets.get(g)?.values() ?? [])];
178
+ if (g === 'agent')
179
+ for (const r of rows)
180
+ r.meta = { ...(r.meta ?? {}), runtimes: [...(runtimesOf.get(r.key) ?? [])].sort() };
181
+ if (g === 'day')
182
+ rows.sort((a, b) => a.key.localeCompare(b.key));
183
+ else
184
+ rows.sort((a, b) => b.total - a.total);
185
+ }
186
+ for (const r of rows)
187
+ r.share = totals.total > 0 ? r.total / totals.total : 0;
188
+ groups[g] = rows;
189
+ }
190
+ return { days: n, since: since.toISOString(), today, totals, todayTotals, groupBy, rows: groups[groupBy[0]] ?? [], groups };
191
+ }
192
+ /**
193
+ * Top work items in the window by tokens.
194
+ */
195
+ workItemRows(items, since, now, teamOf, nameOf) {
196
+ const rows = [];
197
+ for (const wi of items) {
198
+ if (!wi.target)
199
+ continue;
200
+ const startMs = new Date(wi.startedAt ?? wi.createdAt).getTime();
201
+ const endMs = wi.completedAt ? new Date(wi.completedAt).getTime() : now.getTime();
202
+ if (!Number.isFinite(startMs) || !Number.isFinite(endMs) || endMs < since.getTime() || startMs > now.getTime())
203
+ continue;
204
+ const clipped = { createdAt: wi.createdAt, startedAt: new Date(Math.max(startMs, since.getTime())).toISOString(), completedAt: wi.completedAt };
205
+ const usage = computeWorkItemUsage(clipped, wi.target, this.deps.ledger, now);
206
+ if (!usage || usage.totalTokens <= 0)
207
+ continue;
208
+ const team = teamOf.get(wi.target);
209
+ rows.push({
210
+ key: wi.id,
211
+ label: wi.title || wi.id,
212
+ share: 0,
213
+ input: usage.totalTokens - usage.outputTokens,
214
+ cachedInput: usage.cachedInputTokens,
215
+ output: usage.outputTokens,
216
+ total: usage.totalTokens,
217
+ events: 0,
218
+ link: `/workitems/${wi.id}`,
219
+ meta: { agent: nameOf.get(wi.target) ?? wi.target, status: wi.status, ...(team ? { team: team.name } : {}) },
220
+ });
221
+ }
222
+ rows.sort((a, b) => b.total - a.total);
223
+ return rows.slice(0, U.MAX_WORK_ITEM_ROWS);
224
+ }
225
+ }
226
+ //# sourceMappingURL=usage-stats.service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usage-stats.service.js","sourceRoot":"","sources":["../../../../../../backend/src/services/usage/usage-stats.service.ts"],"names":[],"mappings":"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"}
@@ -21,8 +21,8 @@ export type DecisionSensitiveKind = 'email' | 'publish' | 'deploy' | 'spend' | '
21
21
  * (specs/2026-10-01-runtime-terms-consent.md)
22
22
  * - `reply_question`: a question an agent asked the owner in a reply, turned
23
23
  * into a card on its behalf (specs/2026-10-01-reply-open-items.md)
24
- * - `spend_cap`: an agent hit its daily spend cap — raise it for today or
25
- * keep it stopped (specs/2026-10-02-spend-cap.md)
24
+ * - `spend_cap`: an agent / team / all agents hit a daily token cap — boost it
25
+ * for today (+X or unlimited) or keep it stopped (specs/2026-10-02-spend-cap.md)
26
26
  */
27
27
  export type DecisionKind = 'browser_action' | 'runtime_terms' | 'reply_question' | 'spend_cap';
28
28
  /** How a decision came to be: asked live, or carded by the open-items backfill. */
@@ -13,9 +13,17 @@ export interface TicketAutopilotSettings {
13
13
  /** Session that triages; absent = the lead of the project's team */
14
14
  driver?: string;
15
15
  /**
16
- * Daily spend (USD) of the project's team agents since local midnight at
17
- * which the autopilot pauses for the rest of the day. Absent = the default
18
- * ({@link TICKET_AUTOPILOT_CONSTANTS.DEFAULT_DAILY_BUDGET_USD}).
16
+ * Daily tokens (input incl. cached + output) of the project's team agents
17
+ * since local midnight at which the autopilot pauses for the rest of the
18
+ * day. Absent = the default
19
+ * ({@link TICKET_AUTOPILOT_CONSTANTS.DEFAULT_DAILY_BUDGET_TOKENS}). A usage
20
+ * boost on the project's teams raises it for the day.
21
+ */
22
+ dailyBudgetTokens?: number;
23
+ /**
24
+ * Pre-token budget in USD. Read only to migrate it: converted with
25
+ * {@link USAGE_CONSTANTS.TOKENS_PER_USD} (see {@link legacyBudgetTokens}).
26
+ * @deprecated
19
27
  */
20
28
  dailyBudgetUsd?: number;
21
29
  /** In-progress tickets one member may hold at a time (default 1) */
@@ -26,7 +34,7 @@ export interface ResolvedTicketAutopilotSettings {
26
34
  enabled: boolean;
27
35
  /** The configured driver, or null (= the project team's lead) */
28
36
  driver: string | null;
29
- dailyBudgetUsd: number;
37
+ dailyBudgetTokens: number;
30
38
  maxInFlightPerMember: number;
31
39
  }
32
40
  /** A change request for the settings (API / skill body). */
@@ -34,7 +42,9 @@ export interface TicketAutopilotSettingsInput {
34
42
  enabled?: unknown;
35
43
  /** A session name; `null` or `''` resets to the team lead */
36
44
  driver?: unknown;
37
- /** A positive number; `null` resets to the default */
45
+ /** Tokens: a positive number or text like "20M"; `null` resets to the default */
46
+ dailyBudgetTokens?: unknown;
47
+ /** Rejected: budgets are in tokens now */
38
48
  dailyBudgetUsd?: unknown;
39
49
  /** An integer 1..limit; `null` resets to the default */
40
50
  maxInFlightPerMember?: unknown;
@@ -53,6 +63,13 @@ export type TicketAutopilotInputResult = {
53
63
  * @param stored - `Project.ticketAutopilot` (may be undefined or partial)
54
64
  * @returns Settings with defaults
55
65
  */
66
+ /**
67
+ * The token budget a stored pre-token USD budget converts to, or null.
68
+ *
69
+ * @param stored - Stored settings
70
+ * @returns Tokens (USD × TOKENS_PER_USD), or null when there is no USD budget
71
+ */
72
+ export declare function legacyBudgetTokens(stored: Partial<TicketAutopilotSettings> | undefined | null): number | null;
56
73
  export declare function resolveTicketAutopilotSettings(stored: Partial<TicketAutopilotSettings> | undefined | null): ResolvedTicketAutopilotSettings;
57
74
  /**
58
75
  * Apply a change request to the stored settings, validating every field.
@@ -65,8 +82,8 @@ export declare function resolveTicketAutopilotSettings(stored: Partial<TicketAut
65
82
  *
66
83
  * @example
67
84
  * ```typescript
68
- * applyTicketAutopilotInput(undefined, { enabled: true, dailyBudgetUsd: 10 });
69
- * // → { ok: true, settings: { enabled: true, dailyBudgetUsd: 10 } }
85
+ * applyTicketAutopilotInput(undefined, { enabled: true, dailyBudgetTokens: '10M' });
86
+ * // → { ok: true, settings: { enabled: true, dailyBudgetTokens: 10000000 } }
70
87
  * ```
71
88
  */
72
89
  export declare function applyTicketAutopilotInput(current: Partial<TicketAutopilotSettings> | undefined | null, input: TicketAutopilotSettingsInput): TicketAutopilotInputResult;
@@ -1 +1 @@
1
- {"version":3,"file":"ticket-autopilot.types.d.ts","sourceRoot":"","sources":["../../../../../backend/src/types/ticket-autopilot.types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,+EAA+E;AAC/E,MAAM,WAAW,uBAAuB;IACtC,kCAAkC;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,oEAAoE;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oEAAoE;IACpE,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,6CAA6C;AAC7C,MAAM,WAAW,+BAA+B;IAC9C,OAAO,EAAE,OAAO,CAAC;IACjB,iEAAiE;IACjE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,4DAA4D;AAC5D,MAAM,WAAW,4BAA4B;IAC3C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,6DAA6D;IAC7D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,sDAAsD;IACtD,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,wDAAwD;IACxD,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,oDAAoD;AACpD,MAAM,MAAM,0BAA0B,GAClC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,uBAAuB,CAAA;CAAE,GAC/C;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjC;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,OAAO,CAAC,uBAAuB,CAAC,GAAG,SAAS,GAAG,IAAI,GAAG,+BAA+B,CAY3I;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,OAAO,CAAC,uBAAuB,CAAC,GAAG,SAAS,GAAG,IAAI,EAC5D,KAAK,EAAE,4BAA4B,GAClC,0BAA0B,CAmC5B"}
1
+ {"version":3,"file":"ticket-autopilot.types.d.ts","sourceRoot":"","sources":["../../../../../backend/src/types/ticket-autopilot.types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAKH,+EAA+E;AAC/E,MAAM,WAAW,uBAAuB;IACtC,kCAAkC;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,oEAAoE;IACpE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;;;;OAMG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;OAIG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,oEAAoE;IACpE,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,6CAA6C;AAC7C,MAAM,WAAW,+BAA+B;IAC9C,OAAO,EAAE,OAAO,CAAC;IACjB,iEAAiE;IACjE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,MAAM,CAAC;CAC9B;AAED,4DAA4D;AAC5D,MAAM,WAAW,4BAA4B;IAC3C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,6DAA6D;IAC7D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,iFAAiF;IACjF,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,0CAA0C;IAC1C,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,wDAAwD;IACxD,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,oDAAoD;AACpD,MAAM,MAAM,0BAA0B,GAClC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,uBAAuB,CAAA;CAAE,GAC/C;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC;AAEjC;;;;;GAKG;AACH;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,OAAO,CAAC,uBAAuB,CAAC,GAAG,SAAS,GAAG,IAAI,GAAG,MAAM,GAAG,IAAI,CAG7G;AAED,wBAAgB,8BAA8B,CAAC,MAAM,EAAE,OAAO,CAAC,uBAAuB,CAAC,GAAG,SAAS,GAAG,IAAI,GAAG,+BAA+B,CAY3I;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,OAAO,CAAC,uBAAuB,CAAC,GAAG,SAAS,GAAG,IAAI,EAC5D,KAAK,EAAE,4BAA4B,GAClC,0BAA0B,CAuC5B"}
@@ -6,20 +6,31 @@
6
6
  *
7
7
  * @module types/ticket-autopilot.types
8
8
  */
9
- import { TICKET_AUTOPILOT_CONSTANTS } from '../constants.js';
9
+ import { TICKET_AUTOPILOT_CONSTANTS, USAGE_CONSTANTS } from '../constants.js';
10
+ import { parseTokenAmount } from '../services/usage/token-format.js';
10
11
  /**
11
12
  * Fill in the defaults of stored (possibly absent) settings.
12
13
  *
13
14
  * @param stored - `Project.ticketAutopilot` (may be undefined or partial)
14
15
  * @returns Settings with defaults
15
16
  */
17
+ /**
18
+ * The token budget a stored pre-token USD budget converts to, or null.
19
+ *
20
+ * @param stored - Stored settings
21
+ * @returns Tokens (USD × TOKENS_PER_USD), or null when there is no USD budget
22
+ */
23
+ export function legacyBudgetTokens(stored) {
24
+ const usd = stored?.dailyBudgetUsd;
25
+ return typeof usd === 'number' && Number.isFinite(usd) && usd > 0 ? Math.round(usd * USAGE_CONSTANTS.TOKENS_PER_USD) : null;
26
+ }
16
27
  export function resolveTicketAutopilotSettings(stored) {
17
- const budget = stored?.dailyBudgetUsd;
28
+ const budget = stored?.dailyBudgetTokens ?? legacyBudgetTokens(stored) ?? undefined;
18
29
  const cap = stored?.maxInFlightPerMember;
19
30
  return {
20
31
  enabled: stored?.enabled === true,
21
32
  driver: typeof stored?.driver === 'string' && stored.driver.trim() ? stored.driver.trim() : null,
22
- dailyBudgetUsd: typeof budget === 'number' && Number.isFinite(budget) && budget > 0 ? budget : TICKET_AUTOPILOT_CONSTANTS.DEFAULT_DAILY_BUDGET_USD,
33
+ dailyBudgetTokens: typeof budget === 'number' && Number.isFinite(budget) && budget > 0 ? budget : TICKET_AUTOPILOT_CONSTANTS.DEFAULT_DAILY_BUDGET_TOKENS,
23
34
  maxInFlightPerMember: typeof cap === 'number' && Number.isInteger(cap) && cap >= 1 && cap <= TICKET_AUTOPILOT_CONSTANTS.MAX_IN_FLIGHT_PER_MEMBER_LIMIT
24
35
  ? cap
25
36
  : TICKET_AUTOPILOT_CONSTANTS.DEFAULT_MAX_IN_FLIGHT_PER_MEMBER,
@@ -36,16 +47,18 @@ export function resolveTicketAutopilotSettings(stored) {
36
47
  *
37
48
  * @example
38
49
  * ```typescript
39
- * applyTicketAutopilotInput(undefined, { enabled: true, dailyBudgetUsd: 10 });
40
- * // → { ok: true, settings: { enabled: true, dailyBudgetUsd: 10 } }
50
+ * applyTicketAutopilotInput(undefined, { enabled: true, dailyBudgetTokens: '10M' });
51
+ * // → { ok: true, settings: { enabled: true, dailyBudgetTokens: 10000000 } }
41
52
  * ```
42
53
  */
43
54
  export function applyTicketAutopilotInput(current, input) {
44
55
  const next = { enabled: current?.enabled === true };
45
56
  if (typeof current?.driver === 'string' && current.driver.trim())
46
57
  next.driver = current.driver.trim();
47
- if (typeof current?.dailyBudgetUsd === 'number')
48
- next.dailyBudgetUsd = current.dailyBudgetUsd;
58
+ if (typeof current?.dailyBudgetTokens === 'number')
59
+ next.dailyBudgetTokens = current.dailyBudgetTokens;
60
+ else if (legacyBudgetTokens(current) !== null)
61
+ next.dailyBudgetTokens = legacyBudgetTokens(current);
49
62
  if (typeof current?.maxInFlightPerMember === 'number')
50
63
  next.maxInFlightPerMember = current.maxInFlightPerMember;
51
64
  if (input.enabled !== undefined) {
@@ -62,13 +75,16 @@ export function applyTicketAutopilotInput(current, input) {
62
75
  return { ok: false, error: 'driver must be a session name (or null for the team lead)' };
63
76
  }
64
77
  if (input.dailyBudgetUsd !== undefined) {
65
- if (input.dailyBudgetUsd === null)
66
- delete next.dailyBudgetUsd;
78
+ return { ok: false, error: 'Budgets are in tokens now: send dailyBudgetTokens (e.g. 20000000 or "20M") instead of dailyBudgetUsd' };
79
+ }
80
+ if (input.dailyBudgetTokens !== undefined) {
81
+ if (input.dailyBudgetTokens === null)
82
+ delete next.dailyBudgetTokens;
67
83
  else {
68
- const n = typeof input.dailyBudgetUsd === 'string' ? Number(input.dailyBudgetUsd) : input.dailyBudgetUsd;
69
- if (typeof n !== 'number' || !Number.isFinite(n) || n <= 0)
70
- return { ok: false, error: 'dailyBudgetUsd must be a positive number of US dollars' };
71
- next.dailyBudgetUsd = n;
84
+ const n = parseTokenAmount(input.dailyBudgetTokens);
85
+ if (n === null)
86
+ return { ok: false, error: 'dailyBudgetTokens must be a positive number of tokens (e.g. 20000000 or "20M")' };
87
+ next.dailyBudgetTokens = n;
72
88
  }
73
89
  }
74
90
  if (input.maxInFlightPerMember !== undefined) {
@@ -1 +1 @@
1
- {"version":3,"file":"ticket-autopilot.types.js","sourceRoot":"","sources":["../../../../../backend/src/types/ticket-autopilot.types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ticket-autopilot.types.js","sourceRoot":"","sources":["../../../../../backend/src/types/ticket-autopilot.types.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
1
  {
2
- "commit": "ee83295e1087777c0bb76233e92bef63750b935d",
3
- "builtAt": "2026-10-02T03:03:02.125Z"
2
+ "commit": "f459f514888eabc36a75c45af4e0390130ba2fd4",
3
+ "builtAt": "2026-10-02T04:38:22.163Z"
4
4
  }