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.
- package/config/roles/developer/prompt.md +7 -0
- package/config/roles/fullstack-dev/prompt.md +7 -0
- package/config/roles/product-manager/prompt.md +7 -0
- package/config/skills/orchestrator/usage-categories/SKILL.md +59 -0
- package/config/skills/orchestrator/usage-categories/execute.sh +81 -0
- package/config/skills/orchestrator/usage-categories/execute.test.sh +45 -0
- package/config/skills/orchestrator/usage-report/SKILL.md +71 -0
- package/config/skills/orchestrator/usage-report/execute.sh +84 -0
- package/config/skills/orchestrator/usage-report/execute.test.sh +39 -0
- package/config/skills/team-leader/usage-report/SKILL.md +71 -0
- package/config/skills/team-leader/usage-report/execute.sh +84 -0
- package/config/skills/team-leader/usage-report/execute.test.sh +39 -0
- package/dist/backend/backend/src/constants.d.ts +11 -0
- package/dist/backend/backend/src/constants.d.ts.map +1 -1
- package/dist/backend/backend/src/constants.js +11 -0
- package/dist/backend/backend/src/constants.js.map +1 -1
- package/dist/backend/backend/src/controllers/usage-ledger/usage-ledger.controller.d.ts +36 -0
- package/dist/backend/backend/src/controllers/usage-ledger/usage-ledger.controller.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/usage-ledger/usage-ledger.controller.js +158 -0
- package/dist/backend/backend/src/controllers/usage-ledger/usage-ledger.controller.js.map +1 -0
- package/dist/backend/backend/src/controllers/usage-ledger/usage-ledger.routes.d.ts +15 -0
- package/dist/backend/backend/src/controllers/usage-ledger/usage-ledger.routes.d.ts.map +1 -0
- package/dist/backend/backend/src/controllers/usage-ledger/usage-ledger.routes.js +26 -0
- package/dist/backend/backend/src/controllers/usage-ledger/usage-ledger.routes.js.map +1 -0
- package/dist/backend/backend/src/index.d.ts +10 -0
- package/dist/backend/backend/src/index.d.ts.map +1 -1
- package/dist/backend/backend/src/index.js +75 -17
- package/dist/backend/backend/src/index.js.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.d.ts.map +1 -1
- package/dist/backend/backend/src/routes/api.routes.js +3 -0
- package/dist/backend/backend/src/routes/api.routes.js.map +1 -1
- package/dist/backend/backend/src/services/agent/follow-through.wiring.d.ts +32 -0
- package/dist/backend/backend/src/services/agent/follow-through.wiring.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/follow-through.wiring.js +42 -1
- package/dist/backend/backend/src/services/agent/follow-through.wiring.js.map +1 -1
- package/dist/backend/backend/src/services/agent/resource-mode.service.d.ts +26 -6
- package/dist/backend/backend/src/services/agent/resource-mode.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/agent/resource-mode.service.js +59 -5
- package/dist/backend/backend/src/services/agent/resource-mode.service.js.map +1 -1
- package/dist/backend/backend/src/services/monitoring/agent-turn-state.d.ts +35 -0
- package/dist/backend/backend/src/services/monitoring/agent-turn-state.d.ts.map +1 -1
- package/dist/backend/backend/src/services/monitoring/agent-turn-state.js +101 -0
- package/dist/backend/backend/src/services/monitoring/agent-turn-state.js.map +1 -1
- package/dist/backend/backend/src/services/monitoring/background-work-watchdog.d.ts +58 -0
- package/dist/backend/backend/src/services/monitoring/background-work-watchdog.d.ts.map +1 -0
- package/dist/backend/backend/src/services/monitoring/background-work-watchdog.js +100 -0
- package/dist/backend/backend/src/services/monitoring/background-work-watchdog.js.map +1 -0
- package/dist/backend/backend/src/services/monitoring/token-usage.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/monitoring/token-usage.service.js +3 -0
- package/dist/backend/backend/src/services/monitoring/token-usage.service.js.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.d.ts +7 -0
- package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.d.ts.map +1 -1
- package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.js +15 -0
- package/dist/backend/backend/src/services/reconciler/reconciler-data-provider.js.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.d.ts +24 -0
- package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.js +63 -1
- package/dist/backend/backend/src/services/slack/slack-typing-placeholder.service.js.map +1 -1
- package/dist/backend/backend/src/services/trace/trace-context.service.d.ts +42 -2
- package/dist/backend/backend/src/services/trace/trace-context.service.d.ts.map +1 -1
- package/dist/backend/backend/src/services/trace/trace-context.service.js +66 -5
- package/dist/backend/backend/src/services/trace/trace-context.service.js.map +1 -1
- package/dist/backend/backend/src/services/trace/trace-recorder.d.ts.map +1 -1
- package/dist/backend/backend/src/services/trace/trace-recorder.js +11 -0
- package/dist/backend/backend/src/services/trace/trace-recorder.js.map +1 -1
- package/dist/backend/backend/src/services/usage-ledger/categories-param.d.ts +28 -0
- package/dist/backend/backend/src/services/usage-ledger/categories-param.d.ts.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/categories-param.js +67 -0
- package/dist/backend/backend/src/services/usage-ledger/categories-param.js.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/excerpt.d.ts +37 -0
- package/dist/backend/backend/src/services/usage-ledger/excerpt.d.ts.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/excerpt.js +49 -0
- package/dist/backend/backend/src/services/usage-ledger/excerpt.js.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/index.d.ts +14 -0
- package/dist/backend/backend/src/services/usage-ledger/index.d.ts.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/index.js +14 -0
- package/dist/backend/backend/src/services/usage-ledger/index.js.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/ledger-hooks.d.ts +44 -0
- package/dist/backend/backend/src/services/usage-ledger/ledger-hooks.d.ts.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/ledger-hooks.js +52 -0
- package/dist/backend/backend/src/services/usage-ledger/ledger-hooks.js.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/ledger-rollup.d.ts +100 -0
- package/dist/backend/backend/src/services/usage-ledger/ledger-rollup.d.ts.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/ledger-rollup.js +189 -0
- package/dist/backend/backend/src/services/usage-ledger/ledger-rollup.js.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/owner-spans.d.ts +41 -0
- package/dist/backend/backend/src/services/usage-ledger/owner-spans.d.ts.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/owner-spans.js +71 -0
- package/dist/backend/backend/src/services/usage-ledger/owner-spans.js.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/team-directory.d.ts +47 -0
- package/dist/backend/backend/src/services/usage-ledger/team-directory.d.ts.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/team-directory.js +106 -0
- package/dist/backend/backend/src/services/usage-ledger/team-directory.js.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/unit-classifier.d.ts +101 -0
- package/dist/backend/backend/src/services/usage-ledger/unit-classifier.d.ts.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/unit-classifier.js +263 -0
- package/dist/backend/backend/src/services/usage-ledger/unit-classifier.js.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-categories.store.d.ts +96 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-categories.store.d.ts.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-categories.store.js +166 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-categories.store.js.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-ledger.backfill.d.ts +90 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-ledger.backfill.d.ts.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-ledger.backfill.js +294 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-ledger.backfill.js.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-ledger.recorder.d.ts +102 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-ledger.recorder.d.ts.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-ledger.recorder.js +314 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-ledger.recorder.js.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-ledger.runtime.d.ts +62 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-ledger.runtime.d.ts.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-ledger.runtime.js +106 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-ledger.runtime.js.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-ledger.store.d.ts +52 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-ledger.store.d.ts.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-ledger.store.js +95 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-ledger.store.js.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-ledger.types.d.ts +127 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-ledger.types.d.ts.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-ledger.types.js +19 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-ledger.types.js.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-report.service.d.ts +124 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-report.service.d.ts.map +1 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-report.service.js +372 -0
- package/dist/backend/backend/src/services/usage-ledger/usage-report.service.js.map +1 -0
- package/dist/backend/build-info.json +2 -2
- package/dist/cli/backend/src/constants.d.ts +11 -0
- package/dist/cli/backend/src/constants.d.ts.map +1 -1
- package/dist/cli/backend/src/constants.js +11 -0
- package/dist/cli/backend/src/constants.js.map +1 -1
- package/dist/cli/backend/src/services/agent/resource-mode.service.d.ts +26 -6
- package/dist/cli/backend/src/services/agent/resource-mode.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/agent/resource-mode.service.js +59 -5
- package/dist/cli/backend/src/services/agent/resource-mode.service.js.map +1 -1
- package/dist/cli/backend/src/services/monitoring/agent-turn-state.d.ts +35 -0
- package/dist/cli/backend/src/services/monitoring/agent-turn-state.d.ts.map +1 -1
- package/dist/cli/backend/src/services/monitoring/agent-turn-state.js +101 -0
- package/dist/cli/backend/src/services/monitoring/agent-turn-state.js.map +1 -1
- package/dist/cli/backend/src/services/monitoring/token-usage.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/monitoring/token-usage.service.js +3 -0
- package/dist/cli/backend/src/services/monitoring/token-usage.service.js.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.d.ts +24 -0
- package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.js +63 -1
- package/dist/cli/backend/src/services/slack/slack-typing-placeholder.service.js.map +1 -1
- package/dist/cli/backend/src/services/trace/trace-context.service.d.ts +42 -2
- package/dist/cli/backend/src/services/trace/trace-context.service.d.ts.map +1 -1
- package/dist/cli/backend/src/services/trace/trace-context.service.js +66 -5
- package/dist/cli/backend/src/services/trace/trace-context.service.js.map +1 -1
- package/dist/cli/backend/src/services/trace/trace-recorder.d.ts.map +1 -1
- package/dist/cli/backend/src/services/trace/trace-recorder.js +11 -0
- package/dist/cli/backend/src/services/trace/trace-recorder.js.map +1 -1
- package/dist/cli/backend/src/services/usage-ledger/ledger-hooks.d.ts +44 -0
- package/dist/cli/backend/src/services/usage-ledger/ledger-hooks.d.ts.map +1 -0
- package/dist/cli/backend/src/services/usage-ledger/ledger-hooks.js +52 -0
- package/dist/cli/backend/src/services/usage-ledger/ledger-hooks.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Usage ledger endpoints: per-ticket time / token reports and the owner's
|
|
3
|
+
* report categories.
|
|
4
|
+
*
|
|
5
|
+
* - `GET /api/usage-ledger/report?since=7d&until=&by=category|team|project|agent|ticket&categories=&limit=`
|
|
6
|
+
* - `GET /api/usage-ledger/categories`
|
|
7
|
+
* - `PUT /api/usage-ledger/categories` `{ categories: CategoryDef[] }` (replaces all)
|
|
8
|
+
* - `POST /api/usage-ledger/categories` `CategoryDef` (adds or replaces one)
|
|
9
|
+
* - `DELETE /api/usage-ledger/categories/:name`
|
|
10
|
+
* - `GET /api/usage-ledger/units/:id` facts of one ticket (unit id or ticket label)
|
|
11
|
+
* - `POST /api/usage-ledger/backfill` one-time history rebuild (no-op once done)
|
|
12
|
+
*
|
|
13
|
+
* specs/2026-10-11-usage-ledger.md
|
|
14
|
+
*
|
|
15
|
+
* @module controllers/usage-ledger/usage-ledger.controller
|
|
16
|
+
*/
|
|
17
|
+
import type { Request, Response } from 'express';
|
|
18
|
+
import { type UsageLedger } from '../../services/usage-ledger/usage-ledger.runtime.js';
|
|
19
|
+
/** Ledger accessor (tests inject a fake). */
|
|
20
|
+
export type LedgerAccessor = () => UsageLedger;
|
|
21
|
+
/**
|
|
22
|
+
* Build the handlers.
|
|
23
|
+
*
|
|
24
|
+
* @param ledger - Ledger accessor
|
|
25
|
+
* @returns Express handlers
|
|
26
|
+
*/
|
|
27
|
+
export declare function createUsageLedgerHandlers(ledger?: LedgerAccessor): {
|
|
28
|
+
report(req: Request, res: Response): Promise<void>;
|
|
29
|
+
listCategories(_req: Request, res: Response): Promise<void>;
|
|
30
|
+
replaceCategories(req: Request, res: Response): Promise<void>;
|
|
31
|
+
setCategory(req: Request, res: Response): Promise<void>;
|
|
32
|
+
removeCategory(req: Request, res: Response): Promise<void>;
|
|
33
|
+
getUnit(req: Request, res: Response): Promise<void>;
|
|
34
|
+
backfill(_req: Request, res: Response): Promise<void>;
|
|
35
|
+
};
|
|
36
|
+
//# sourceMappingURL=usage-ledger.controller.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage-ledger.controller.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/controllers/usage-ledger/usage-ledger.controller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAGjD,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,qDAAqD,CAAC;AAGvG,6CAA6C;AAC7C,MAAM,MAAM,cAAc,GAAG,MAAM,WAAW,CAAC;AAI/C;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,GAAE,cAA+B;gBAE7D,OAAO,OAAO,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;yBA0C7B,OAAO,OAAO,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;2BAQpC,OAAO,OAAO,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;qBAkB5C,OAAO,OAAO,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;wBAanC,OAAO,OAAO,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;iBAa7C,OAAO,OAAO,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;mBAwBpC,OAAO,OAAO,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;EAQ5D"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Usage ledger endpoints: per-ticket time / token reports and the owner's
|
|
3
|
+
* report categories.
|
|
4
|
+
*
|
|
5
|
+
* - `GET /api/usage-ledger/report?since=7d&until=&by=category|team|project|agent|ticket&categories=&limit=`
|
|
6
|
+
* - `GET /api/usage-ledger/categories`
|
|
7
|
+
* - `PUT /api/usage-ledger/categories` `{ categories: CategoryDef[] }` (replaces all)
|
|
8
|
+
* - `POST /api/usage-ledger/categories` `CategoryDef` (adds or replaces one)
|
|
9
|
+
* - `DELETE /api/usage-ledger/categories/:name`
|
|
10
|
+
* - `GET /api/usage-ledger/units/:id` facts of one ticket (unit id or ticket label)
|
|
11
|
+
* - `POST /api/usage-ledger/backfill` one-time history rebuild (no-op once done)
|
|
12
|
+
*
|
|
13
|
+
* specs/2026-10-11-usage-ledger.md
|
|
14
|
+
*
|
|
15
|
+
* @module controllers/usage-ledger/usage-ledger.controller
|
|
16
|
+
*/
|
|
17
|
+
import { formatError } from '../../utils/format-error.js';
|
|
18
|
+
import { parseCategoriesParam } from '../../services/usage-ledger/categories-param.js';
|
|
19
|
+
import { getUsageLedger } from '../../services/usage-ledger/usage-ledger.runtime.js';
|
|
20
|
+
import { parseSince, REPORT_DIMENSIONS } from '../../services/usage-ledger/usage-report.service.js';
|
|
21
|
+
const first = (v) => (typeof v === 'string' && v.trim() ? v.trim() : undefined);
|
|
22
|
+
/**
|
|
23
|
+
* Build the handlers.
|
|
24
|
+
*
|
|
25
|
+
* @param ledger - Ledger accessor
|
|
26
|
+
* @returns Express handlers
|
|
27
|
+
*/
|
|
28
|
+
export function createUsageLedgerHandlers(ledger = getUsageLedger) {
|
|
29
|
+
return {
|
|
30
|
+
async report(req, res) {
|
|
31
|
+
try {
|
|
32
|
+
const now = Date.now();
|
|
33
|
+
const since = parseSince(first(req.query.since) ?? '7d', now);
|
|
34
|
+
const until = first(req.query.until) ? parseSince(first(req.query.until), now) : now;
|
|
35
|
+
if (since === null || until === null) {
|
|
36
|
+
res.status(400).json({ success: false, error: 'since / until must look like 7d, 24h, 2w or an ISO date' });
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
const by = (first(req.query.by) ?? 'category');
|
|
40
|
+
if (!REPORT_DIMENSIONS.includes(by)) {
|
|
41
|
+
res.status(400).json({ success: false, error: `by must be one of ${REPORT_DIMENSIONS.join(', ')}` });
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const l = ledger();
|
|
45
|
+
let defs;
|
|
46
|
+
let only;
|
|
47
|
+
const categoriesArg = first(req.query.categories);
|
|
48
|
+
if (categoriesArg) {
|
|
49
|
+
const parsed = parseCategoriesParam(categoriesArg, (await l.categories.list()).categories);
|
|
50
|
+
if (typeof parsed === 'string') {
|
|
51
|
+
res.status(400).json({ success: false, error: parsed });
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
defs = parsed.defs;
|
|
55
|
+
only = parsed.only;
|
|
56
|
+
}
|
|
57
|
+
const limit = Number(first(req.query.limit));
|
|
58
|
+
const report = await l.reports.report({
|
|
59
|
+
sinceMs: since,
|
|
60
|
+
untilMs: until,
|
|
61
|
+
by,
|
|
62
|
+
...(defs ? { categories: defs } : {}),
|
|
63
|
+
...(only && only.length > 0 ? { only } : {}),
|
|
64
|
+
...(Number.isFinite(limit) && limit > 0 ? { limit } : {}),
|
|
65
|
+
});
|
|
66
|
+
res.json({ success: true, data: report });
|
|
67
|
+
}
|
|
68
|
+
catch (error) {
|
|
69
|
+
res.status(500).json({ success: false, error: formatError(error) });
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
async listCategories(_req, res) {
|
|
73
|
+
try {
|
|
74
|
+
res.json({ success: true, data: await ledger().categories.list() });
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
res.status(500).json({ success: false, error: formatError(error) });
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
async replaceCategories(req, res) {
|
|
81
|
+
try {
|
|
82
|
+
const body = req.body;
|
|
83
|
+
if (!Array.isArray(body?.categories)) {
|
|
84
|
+
res.status(400).json({ success: false, error: 'body must be { "categories": [...] }' });
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const result = await ledger().categories.replaceAll(body.categories);
|
|
88
|
+
if (typeof result === 'string') {
|
|
89
|
+
res.status(400).json({ success: false, error: result });
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
res.json({ success: true, data: result });
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
res.status(500).json({ success: false, error: formatError(error) });
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
async setCategory(req, res) {
|
|
99
|
+
try {
|
|
100
|
+
const result = await ledger().categories.set(req.body);
|
|
101
|
+
if (typeof result === 'string') {
|
|
102
|
+
res.status(400).json({ success: false, error: result });
|
|
103
|
+
return;
|
|
104
|
+
}
|
|
105
|
+
res.json({ success: true, data: result });
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
res.status(500).json({ success: false, error: formatError(error) });
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
async removeCategory(req, res) {
|
|
112
|
+
try {
|
|
113
|
+
const result = await ledger().categories.remove(String(req.params.name ?? ''));
|
|
114
|
+
if (!result) {
|
|
115
|
+
res.status(404).json({ success: false, error: 'no such category' });
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
res.json({ success: true, data: result });
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
res.status(500).json({ success: false, error: formatError(error) });
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
async getUnit(req, res) {
|
|
125
|
+
try {
|
|
126
|
+
const l = ledger();
|
|
127
|
+
await l.recorder.flush();
|
|
128
|
+
await l.rollup.refresh(l.store);
|
|
129
|
+
const id = String(req.params.id ?? '');
|
|
130
|
+
const unit = l.rollup.units.get(id) ?? [...l.rollup.units.values()].find((u) => u.ticketId === id || u.requestId === id);
|
|
131
|
+
if (!unit) {
|
|
132
|
+
res.status(404).json({ success: false, error: 'no such ticket in the ledger' });
|
|
133
|
+
return;
|
|
134
|
+
}
|
|
135
|
+
res.json({
|
|
136
|
+
success: true,
|
|
137
|
+
data: {
|
|
138
|
+
...unit,
|
|
139
|
+
agents: [...unit.agents.entries()].map(([agent, info]) => ({ agent, ...info })),
|
|
140
|
+
ownerMessages: unit.ownerMessages.length,
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
res.status(500).json({ success: false, error: formatError(error) });
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
async backfill(_req, res) {
|
|
149
|
+
try {
|
|
150
|
+
res.json({ success: true, data: await ledger().backfill() });
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
res.status(500).json({ success: false, error: formatError(error) });
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
//# sourceMappingURL=usage-ledger.controller.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage-ledger.controller.js","sourceRoot":"","sources":["../../../../../../backend/src/controllers/usage-ledger/usage-ledger.controller.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Routes of the usage ledger (`/api/usage-ledger`).
|
|
3
|
+
*
|
|
4
|
+
* @module controllers/usage-ledger/usage-ledger.routes
|
|
5
|
+
*/
|
|
6
|
+
import { Router } from 'express';
|
|
7
|
+
import { type LedgerAccessor } from './usage-ledger.controller.js';
|
|
8
|
+
/**
|
|
9
|
+
* Create the usage ledger router.
|
|
10
|
+
*
|
|
11
|
+
* @param ledger - Ledger accessor (default: the process-wide ledger)
|
|
12
|
+
* @returns Express router
|
|
13
|
+
*/
|
|
14
|
+
export declare function createUsageLedgerRouter(ledger?: LedgerAccessor): Router;
|
|
15
|
+
//# sourceMappingURL=usage-ledger.routes.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage-ledger.routes.d.ts","sourceRoot":"","sources":["../../../../../../backend/src/controllers/usage-ledger/usage-ledger.routes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAA6B,KAAK,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAE9F;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,CAAC,EAAE,cAAc,GAAG,MAAM,CAWvE"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Routes of the usage ledger (`/api/usage-ledger`).
|
|
3
|
+
*
|
|
4
|
+
* @module controllers/usage-ledger/usage-ledger.routes
|
|
5
|
+
*/
|
|
6
|
+
import { Router } from 'express';
|
|
7
|
+
import { createUsageLedgerHandlers } from './usage-ledger.controller.js';
|
|
8
|
+
/**
|
|
9
|
+
* Create the usage ledger router.
|
|
10
|
+
*
|
|
11
|
+
* @param ledger - Ledger accessor (default: the process-wide ledger)
|
|
12
|
+
* @returns Express router
|
|
13
|
+
*/
|
|
14
|
+
export function createUsageLedgerRouter(ledger) {
|
|
15
|
+
const h = createUsageLedgerHandlers(ledger);
|
|
16
|
+
const router = Router();
|
|
17
|
+
router.get('/report', h.report);
|
|
18
|
+
router.get('/categories', h.listCategories);
|
|
19
|
+
router.put('/categories', h.replaceCategories);
|
|
20
|
+
router.post('/categories', h.setCategory);
|
|
21
|
+
router.delete('/categories/:name', h.removeCategory);
|
|
22
|
+
router.get('/units/:id', h.getUnit);
|
|
23
|
+
router.post('/backfill', h.backfill);
|
|
24
|
+
return router;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=usage-ledger.routes.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"usage-ledger.routes.js","sourceRoot":"","sources":["../../../../../../backend/src/controllers/usage-ledger/usage-ledger.routes.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,yBAAyB,EAAuB,MAAM,8BAA8B,CAAC;AAE9F;;;;;GAKG;AACH,MAAM,UAAU,uBAAuB,CAAC,MAAuB;IAC9D,MAAM,CAAC,GAAG,yBAAyB,CAAC,MAAM,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC;IACxB,MAAM,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;IAChC,MAAM,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC,CAAC,cAAc,CAAC,CAAC;IAC5C,MAAM,CAAC,GAAG,CAAC,aAAa,EAAE,CAAC,CAAC,iBAAiB,CAAC,CAAC;IAC/C,MAAM,CAAC,IAAI,CAAC,aAAa,EAAE,CAAC,CAAC,WAAW,CAAC,CAAC;IAC1C,MAAM,CAAC,MAAM,CAAC,mBAAmB,EAAE,CAAC,CAAC,cAAc,CAAC,CAAC;IACrD,MAAM,CAAC,GAAG,CAAC,YAAY,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC;IACpC,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC;IACrC,OAAO,MAAM,CAAC;AACf,CAAC"}
|
|
@@ -67,6 +67,7 @@ export declare class CrewlyServer {
|
|
|
67
67
|
/** Owner promises past due and never nudged at boot; their agents are restored and reminded once */
|
|
68
68
|
private openCommitmentsAtBoot;
|
|
69
69
|
private healthMonitoringInterval;
|
|
70
|
+
private backgroundWatchdog;
|
|
70
71
|
constructor(config?: Partial<StartupConfig>);
|
|
71
72
|
private initializeServices;
|
|
72
73
|
private configureMiddleware;
|
|
@@ -354,6 +355,15 @@ export declare class CrewlyServer {
|
|
|
354
355
|
*/
|
|
355
356
|
private startOwnerThreadSentinel;
|
|
356
357
|
private startOwnerMessageWatchdog;
|
|
358
|
+
/**
|
|
359
|
+
* The one hook every stop path runs: what the stopped agent owes goes back
|
|
360
|
+
* in the queue and the agent is brought back with a reminder.
|
|
361
|
+
*
|
|
362
|
+
* @param sessionName - The agent that stopped
|
|
363
|
+
* @param why - Reason text
|
|
364
|
+
* @returns True when the agent is being brought back
|
|
365
|
+
*/
|
|
366
|
+
private restoreStoppedOwing;
|
|
357
367
|
/**
|
|
358
368
|
* An agent went down with messages still queued for it: start it again so
|
|
359
369
|
* they are delivered (registration drains the queue). Without this the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../backend/src/index.ts"],"names":[],"mappings":";AA4CA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../backend/src/index.ts"],"names":[],"mappings":";AA4CA,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAqUjD,qBAAa,YAAY;IACxB,OAAO,CAAC,GAAG,CAAsB;IACjC,OAAO,CAAC,UAAU,CAAkC;IACpD,OAAO,CAAC,EAAE,CAAiB;IAC3B,iFAAiF;IACjF,OAAO,CAAC,cAAc,CAAuB;IAC7C,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,MAAM,CAAqE;IACnF,gFAAgF;IAChF,OAAO,CAAC,iBAAiB,CAAC,CAAyD;IAEnF,OAAO,CAAC,cAAc,CAAkB;IACxC,OAAO,CAAC,WAAW,CAAe;IAClC,OAAO,CAAC,gBAAgB,CAAoB;IAC5C,OAAO,CAAC,uBAAuB,CAA2B;IAC1D,OAAO,CAAC,sBAAsB,CAA0B;IACxD,OAAO,CAAC,4BAA4B,CAAgC;IACpE,OAAO,CAAC,uBAAuB,CAA2B;IAC1D,OAAO,CAAC,aAAa,CAAiB;IACtC,OAAO,CAAC,eAAe,CAAmB;IAC1C,OAAO,CAAC,mBAAmB,CAAuB;IAClD,OAAO,CAAC,qBAAqB,CAAyB;IACtD,OAAO,CAAC,wBAAwB,CAA4B;IAC5D,OAAO,CAAC,eAAe,CAAmB;IAC1C,qEAAqE;IACrE,OAAO,CAAC,qBAAqB,CAAsC;IACnE,OAAO,CAAC,sBAAsB,CAAuC;IACrE,OAAO,CAAC,sBAAsB,CAAiD;IAC/E,OAAO,CAAC,iBAAiB,CAAkC;IAC3D,OAAO,CAAC,0BAA0B,CAA2C;IAC7E,kGAAkG;IAClG,OAAO,CAAC,sBAAsB,CAAuC;IAGrE,OAAO,CAAC,+BAA+B,CAAgD;IACvF,+FAA+F;IAC/F,OAAO,CAAC,oBAAoB,CAAqC;IACjE,8HAA8H;IAC9H,OAAO,CAAC,0BAA0B,CAA2C;IAC7E,OAAO,CAAC,6BAA6B,CAA8C;IACnF,OAAO,CAAC,wBAAwB,CAAyC;IACzE,OAAO,CAAC,2BAA2B,CAA+B;IAClE,OAAO,CAAC,0BAA0B,CAA8B;IAChE,OAAO,CAAC,iBAAiB,CAAkC;IAC3D,OAAO,CAAC,kBAAkB,CAA0C;IACpE,8DAA8D;IAC9D,OAAO,CAAC,iBAAiB,CAAmG;IAK5H,OAAO,CAAC,aAAa,CAAuE;IAC5F,OAAO,CAAC,gBAAgB,CAET;IAGf,OAAO,CAAC,cAAc,CAAS;IAC/B,oEAAoE;IACpE,OAAO,CAAC,qBAAqB,CAA6C;IAC1E,OAAO,CAAC,qBAAqB,CAA2G;IACxI,0EAA0E;IAC1E,OAAO,CAAC,eAAe,CAAuC;IAC9D,OAAO,CAAC,gBAAgB,CAAiG;IACzH,oFAAoF;IACpF,OAAO,CAAC,oBAAoB,CAAK;IACjC,2EAA2E;IAC3E,OAAO,CAAC,sBAAsB,CAA8B;IAC5D,yGAAyG;IACzG,OAAO,CAAC,sBAAsB,CAAuB;IACrD;;;OAGG;IACH,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAMhC;IACH,oGAAoG;IACpG,OAAO,CAAC,qBAAqB,CAAwB;IACrD,OAAO,CAAC,wBAAwB,CAA+B;IAC/D,OAAO,CAAC,kBAAkB,CAAuC;gBAErD,MAAM,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC;IAsE3C,OAAO,CAAC,kBAAkB;IA2vC1B,OAAO,CAAC,mBAAmB;IAuE3B,OAAO,CAAC,eAAe;IA4MvB,OAAO,CAAC,kBAAkB;IA0BpB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAq4E5B;;;OAGG;YACW,2BAA2B;IAuCzC;;;OAGG;YACW,8BAA8B;IAsB5C;;;OAGG;YACW,gCAAgC;IAsB9C;;;OAGG;YACW,8BAA8B;IAsB5C;;;;OAIG;YACW,8BAA8B;IA8M5C;;;;;;;;;;;;OAYG;YACW,6BAA6B;IAsB3C,kEAAkE;IAClE,OAAO,CAAC,iBAAiB,CAA4E;IAErG;;;;;;OAMG;YACW,uBAAuB;IAsCrC;;;;;OAKG;YACW,eAAe;IAuB7B;;;;;OAKG;YACW,iCAAiC;IAgL/C;;;;OAIG;YACW,2BAA2B;YA0B3B,qBAAqB;IAsBnC;;;;;;OAMG;IACH,OAAO,CAAC,0BAA0B;IAwBlC;;;;;;;OAOG;IACH,OAAO,CAAC,kBAAkB;YAqCZ,eAAe;YAoFf,kBAAkB;IAgBhC,OAAO,CAAC,WAAW,CAAK;IAExB,OAAO,CAAC,sBAAsB;IAsC9B;;;;;;;;;;;;OAYG;IACH,OAAO,CAAC,oBAAoB;IAwB5B;;;;;;OAMG;IACH,OAAO,CAAC,eAAe;IAsBvB;;;;OAIG;IACH,OAAO,CAAC,eAAe;IAyEvB;;;;;;;OAOG;YACW,2BAA2B;IAczC;;;;;OAKG;IACH,OAAO,CAAC,kBAAkB;IAsG1B;;;;;;OAMG;IACH,OAAO,CAAC,eAAe;IA4DvB;;;;;;;OAOG;IACH,OAAO,CAAC,0BAA0B;IAuClC;;;;;OAKG;YACW,0BAA0B;IAoExC;;;;OAIG;YACW,qBAAqB;IA+DnC;;OAEG;IACH,OAAO,CAAC,0BAA0B;IAuBlC;;;;;;OAMG;IACH;;;;;;;OAOG;YACW,yBAAyB;YASzB,kBAAkB;IAmBhC;;;;;OAKG;YACW,8BAA8B;IA6C5C;;;;OAIG;YACW,+BAA+B;IA2C7C;;;;;;OAMG;YACW,kBAAkB;IA6BhC,OAAO,CAAC,qBAAqB;IAoC7B;;;;OAIG;IACH,OAAO,CAAC,kBAAkB;IAoE1B;;;;;;;;;OASG;IACH;;;;;;;;;;;;;;OAcG;IACH,sEAAsE;IACtE,OAAO,CAAC,QAAQ,CAAC,YAAY,CAA6B;IAE1D;;;;;;;;OAQG;IACH;;OAEG;IACH;;;;;OAKG;YACW,sBAAsB;YA4CtB,eAAe;YA6Cf,kBAAkB;IA2IhC;;;;;;OAMG;YACW,0BAA0B;IAkFxC;;;;;;;OAOG;YACW,wBAAwB;YAuCxB,yBAAyB;IA2FvC;;;;;;;OAOG;IACH,OAAO,CAAC,mBAAmB;IAoB3B;;;;;;;;;OASG;IACH,OAAO,CAAC,oBAAoB;IA8B5B;;;;;;;OAOG;IACH,OAAO,CAAC,oBAAoB;IAkB5B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,cAAc;IA2BtB;;;;OAIG;IACH,OAAO,CAAC,oBAAoB;IAkB5B;;;;;OAKG;IACH,OAAO,CAAC,wBAAwB;IAmChC;;;;;;OAMG;IACH,OAAO,CAAC,qBAAqB;YAmIf,wBAAwB;IAWtC,OAAO,CAAC,qBAAqB;IA8H7B,OAAO,CAAC,cAAc;IActB;;;;;;;;OAQG;IACG,QAAQ,CAAC,OAAO,GAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;QAAC,WAAW,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAyX1H,SAAS,IAAI,aAAa;CAG1B;AAyDD,eAAe,YAAY,CAAC"}
|
|
@@ -142,7 +142,10 @@ import { getRuntimeFallbackService } from './services/runtime-fallback/runtime-f
|
|
|
142
142
|
import { getSlackAgentIdentityService } from './services/slack/slack-agent-identity.service.js';
|
|
143
143
|
import { getChatV2Service } from './services/chat-v2/chat-v2.singleton.js';
|
|
144
144
|
import { isOwnerStopped } from './services/agent/owner-stopped.registry.js';
|
|
145
|
-
import {
|
|
145
|
+
import { pausedTeamOfSession } from './services/team/team-pause.registry.js';
|
|
146
|
+
import { getFollowThrough } from './services/agent/follow-through.service.js';
|
|
147
|
+
import { BackgroundWorkWatchdog } from './services/monitoring/background-work-watchdog.js';
|
|
148
|
+
import { createFollowThrough, settleFollowThrough, idlePendingWorkCheck, releaseWorkForStop, restoreStoppedOwingWork, owedWorkReminder, OWED_REMINDER_MARKER } from './services/agent/follow-through.wiring.js';
|
|
146
149
|
import { isSessionPaused } from './services/team/team-pause.registry.js';
|
|
147
150
|
import { findPackageRoot } from './utils/package-root.js';
|
|
148
151
|
import { getLocalApiBaseUrl, setLocalApiPort } from './utils/local-api-url.utils.js';
|
|
@@ -184,6 +187,7 @@ import { sessionsToRestore } from './services/agent/restore-filter.js';
|
|
|
184
187
|
import { ProjectMemoryService } from './services/memory/project-memory.service.js';
|
|
185
188
|
import { TaskHistorySubscriber } from './services/memory/task-history.subscriber.js';
|
|
186
189
|
import { TeamHealthWatchdogService, LiveTeamHealthDataProvider, loadTeamHealthConfig, setTeamHealthWatchdogSingleton, getTeamHealthWatchdogSingleton, } from './services/team-health/index.js';
|
|
190
|
+
import { getUsageLedger } from './services/usage-ledger/usage-ledger.runtime.js';
|
|
187
191
|
import { traceHarness, traceTurnActivity } from './services/trace/trace-recorder.js';
|
|
188
192
|
import { inputCircuitStats, setInputCircuitOpenListener } from './services/session/input-circuit-breaker.js';
|
|
189
193
|
import { looksLikeShellPrompt } from './utils/screen-excerpt.js';
|
|
@@ -350,6 +354,7 @@ export class CrewlyServer {
|
|
|
350
354
|
/** Owner promises past due and never nudged at boot; their agents are restored and reminded once */
|
|
351
355
|
openCommitmentsAtBoot = [];
|
|
352
356
|
healthMonitoringInterval = null;
|
|
357
|
+
backgroundWatchdog = null;
|
|
353
358
|
constructor(config) {
|
|
354
359
|
// Resolve ~ to actual home directory
|
|
355
360
|
const resolveHomePath = (inputPath) => {
|
|
@@ -1297,7 +1302,14 @@ export class CrewlyServer {
|
|
|
1297
1302
|
setSlackImageService(slackImageService);
|
|
1298
1303
|
// Wire agent:idle events to thread status queue for delegation completion
|
|
1299
1304
|
this.eventBusService.on('eventPublished', (event) => {
|
|
1305
|
+
if (event.type === 'agent:busy' && event.sessionName)
|
|
1306
|
+
getSlackTypingPlaceholderService()?.releaseHold(event.sessionName);
|
|
1307
|
+
if ((event.type === 'agent:idle' || event.type === 'agent:busy') && event.sessionName) {
|
|
1308
|
+
ResourceModeService.getInstance().noteWorkingStatus(event.sessionName, event.type === 'agent:idle');
|
|
1309
|
+
}
|
|
1300
1310
|
if (event.type === 'agent:inactive' && event.sessionName) {
|
|
1311
|
+
// A runtime that exited while the agent owed work: same hook as the other stop paths.
|
|
1312
|
+
void this.restoreStoppedOwing(event.sessionName, 'runtime exited');
|
|
1301
1313
|
this.wakeIfMessagesQueued(event.sessionName);
|
|
1302
1314
|
}
|
|
1303
1315
|
// A turn started: the harness's "working on it" watch may be waiting
|
|
@@ -1385,6 +1397,7 @@ export class CrewlyServer {
|
|
|
1385
1397
|
// 2026-05-16: queued WIs for inactive Atlas could not get woken
|
|
1386
1398
|
// because the floor was held by idle product/marketing agents).
|
|
1387
1399
|
liveDataProvider.setAgentRegistrationService(this.apiController.agentRegistrationService);
|
|
1400
|
+
liveDataProvider.setAgentStoppedHook((name, why) => { void this.restoreStoppedOwing(name, why); });
|
|
1388
1401
|
// Initialize Reconciler Service (V2 — system truth recomputation)
|
|
1389
1402
|
{
|
|
1390
1403
|
const reconcilerLogger = LoggerService.getInstance().createComponentLogger('ReconcilerInit');
|
|
@@ -1960,6 +1973,14 @@ export class CrewlyServer {
|
|
|
1960
1973
|
crewlyHome: this.config.crewlyHome,
|
|
1961
1974
|
sendToAgent: (session, text) => this.apiController.agentRegistrationService.sendMessageToAgent(session, text),
|
|
1962
1975
|
});
|
|
1976
|
+
// Background subagents / forks that stopped writing are not busy work:
|
|
1977
|
+
// the agent is told and no longer counted busy (2026-10-12, Pia).
|
|
1978
|
+
this.backgroundWatchdog?.stop();
|
|
1979
|
+
this.backgroundWatchdog = new BackgroundWorkWatchdog({
|
|
1980
|
+
turnState: AgentTurnStateService.getInstance(),
|
|
1981
|
+
sendToAgent: (session, text) => this.apiController.agentRegistrationService.sendMessageToAgent(session, text),
|
|
1982
|
+
});
|
|
1983
|
+
this.backgroundWatchdog.start();
|
|
1963
1984
|
// An agent that owes work — a WorkItem (queued, accepted or running),
|
|
1964
1985
|
// an assigned ticket, a promise to the owner, an unfulfilled "doing X
|
|
1965
1986
|
// now" — is never idle-stopped. Under memory pressure it still can
|
|
@@ -1970,20 +1991,7 @@ export class CrewlyServer {
|
|
|
1970
1991
|
// a slot frees, with a reminder of what it promised (the work itself is
|
|
1971
1992
|
// already queued for it by the releaser).
|
|
1972
1993
|
idleDetection.setOwedStopHook((sessionName) => {
|
|
1973
|
-
void (
|
|
1974
|
-
const reminder = owedWorkReminder(await TaskPoolService.getInstance().getAllItems(), sessionName);
|
|
1975
|
-
if (!reminder)
|
|
1976
|
-
return;
|
|
1977
|
-
SubAgentMessageQueue.getInstance().enqueue(sessionName, reminder);
|
|
1978
|
-
this.logger.info('Stopped agent owes work — it will be restarted when a slot frees', { sessionName });
|
|
1979
|
-
const { scheduleDeferredStartRetry } = await import('./services/messaging/deferred-start-retry.js');
|
|
1980
|
-
const { activateAgentBySession } = await import('./controllers/team/team.controller.js');
|
|
1981
|
-
await scheduleDeferredStartRetry(sessionName, {
|
|
1982
|
-
activate: (name) => activateAgentBySession(this.apiController, name),
|
|
1983
|
-
hasPending: (name) => SubAgentMessageQueue.getInstance().hasPending(name),
|
|
1984
|
-
firstPauseMs: 60_000,
|
|
1985
|
-
});
|
|
1986
|
-
})().catch(() => undefined);
|
|
1994
|
+
void this.restoreStoppedOwing(sessionName, 'idle stop under memory pressure');
|
|
1987
1995
|
});
|
|
1988
1996
|
idleDetection.start();
|
|
1989
1997
|
// Adaptive agent limits (pressure mode cap + start queue).
|
|
@@ -2031,12 +2039,21 @@ export class CrewlyServer {
|
|
|
2031
2039
|
// An agent mid-conversation with the owner is the last one stopped
|
|
2032
2040
|
// for a slot, and its owner thread hears when it is
|
|
2033
2041
|
// (specs/2026-10-08-owner-thread-sentinel.md).
|
|
2034
|
-
owesOwnerThread: (name) => getOwnerThreadSentinel()?.
|
|
2035
|
-
onStoppedForSlot: (name) =>
|
|
2042
|
+
owesOwnerThread: (name) => getOwnerThreadSentinel()?.owesOwner(name) === true || getFollowThrough()?.holdsIntent(name) === true,
|
|
2043
|
+
onStoppedForSlot: (name) => {
|
|
2044
|
+
reportOwnerThreadBlocking(name, { kind: 'stopped', why: 'slot' });
|
|
2045
|
+
// Same hook as every other stop path: what it owes goes back to the queue and it is brought back.
|
|
2046
|
+
void this.restoreStoppedOwing(name, 'stopped to free a running-agent slot');
|
|
2047
|
+
},
|
|
2036
2048
|
onStartDeferred: (name) => reportOwnerThreadBlocking(name, { kind: 'start_deferred' }),
|
|
2037
2049
|
stopAgent: async (name, role) => {
|
|
2038
2050
|
// Its work survives the stop: back in the queue, redelivered on the next start.
|
|
2039
2051
|
await releaseWorkForStop(name, 'stopped to free a running-agent slot');
|
|
2052
|
+
// An agent that still owes the answer keeps its "will pick this up" placeholder:
|
|
2053
|
+
// the turn-end settle the stop triggers must not call the thread answered.
|
|
2054
|
+
const owed = TaskPoolService.getInstance().getAllItems().then((items) => owedWorkReminder(items, name) !== null);
|
|
2055
|
+
if (await owed.catch(() => false))
|
|
2056
|
+
await getSlackTypingPlaceholderService()?.holdForRestart(name);
|
|
2040
2057
|
await agentRegistration.terminateAgentSession(name, role);
|
|
2041
2058
|
await StorageService.getInstance().updateAgentStatus(name, CREWLY_CONSTANTS.AGENT_STATUSES.INACTIVE, 'idle_exit');
|
|
2042
2059
|
},
|
|
@@ -3844,6 +3861,9 @@ export class CrewlyServer {
|
|
|
3844
3861
|
const tokenUsageService = TokenUsageService.getInstance();
|
|
3845
3862
|
await tokenUsageService.loadFromDisk();
|
|
3846
3863
|
tokenUsageService.startPeriodicFlush();
|
|
3864
|
+
// Per-ticket time / token accounting (specs/2026-10-11-usage-ledger.md):
|
|
3865
|
+
// records facts from here on and rebuilds history once, shortly after boot.
|
|
3866
|
+
await getUsageLedger().start();
|
|
3847
3867
|
// Read Claude Code's own session transcripts on an interval so
|
|
3848
3868
|
// the Usage dashboard reflects claude-code agents, and so the
|
|
3849
3869
|
// context monitor gets a real context size for them (Claude
|
|
@@ -6238,6 +6258,34 @@ export class CrewlyServer {
|
|
|
6238
6258
|
});
|
|
6239
6259
|
}
|
|
6240
6260
|
}
|
|
6261
|
+
/**
|
|
6262
|
+
* The one hook every stop path runs: what the stopped agent owes goes back
|
|
6263
|
+
* in the queue and the agent is brought back with a reminder.
|
|
6264
|
+
*
|
|
6265
|
+
* @param sessionName - The agent that stopped
|
|
6266
|
+
* @param why - Reason text
|
|
6267
|
+
* @returns True when the agent is being brought back
|
|
6268
|
+
*/
|
|
6269
|
+
restoreStoppedOwing(sessionName, why) {
|
|
6270
|
+
if (sessionName === ORCHESTRATOR_SESSION_NAME)
|
|
6271
|
+
return Promise.resolve(false);
|
|
6272
|
+
return restoreStoppedOwingWork(sessionName, why, {
|
|
6273
|
+
listWorkItems: () => TaskPoolService.getInstance().getAllItems(),
|
|
6274
|
+
isHeldBack: (name) => isOwnerStopped(name) || !!pausedTeamOfSession(name),
|
|
6275
|
+
hasReminder: (name) => SubAgentMessageQueue.getInstance().peek(name).some((m) => m.data.startsWith(OWED_REMINDER_MARKER)),
|
|
6276
|
+
enqueue: (name, text) => SubAgentMessageQueue.getInstance().enqueue(name, text),
|
|
6277
|
+
holdPlaceholders: (name) => getSlackTypingPlaceholderService()?.holdForRestart(name) ?? Promise.resolve(0),
|
|
6278
|
+
restart: async (name) => {
|
|
6279
|
+
const { scheduleDeferredStartRetry } = await import('./services/messaging/deferred-start-retry.js');
|
|
6280
|
+
const { activateAgentBySession } = await import('./controllers/team/team.controller.js');
|
|
6281
|
+
void scheduleDeferredStartRetry(name, {
|
|
6282
|
+
activate: (n) => activateAgentBySession(this.apiController, n),
|
|
6283
|
+
hasPending: (n) => SubAgentMessageQueue.getInstance().hasPending(n),
|
|
6284
|
+
firstPauseMs: 60_000,
|
|
6285
|
+
});
|
|
6286
|
+
},
|
|
6287
|
+
});
|
|
6288
|
+
}
|
|
6241
6289
|
/**
|
|
6242
6290
|
* An agent went down with messages still queued for it: start it again so
|
|
6243
6291
|
* they are delivered (registration drains the queue). Without this the
|
|
@@ -6708,6 +6756,7 @@ export class CrewlyServer {
|
|
|
6708
6756
|
}, timeoutMs);
|
|
6709
6757
|
try {
|
|
6710
6758
|
// Clear health monitoring interval first
|
|
6759
|
+
this.backgroundWatchdog?.stop();
|
|
6711
6760
|
if (this.healthMonitoringInterval) {
|
|
6712
6761
|
clearInterval(this.healthMonitoringInterval);
|
|
6713
6762
|
this.healthMonitoringInterval = null;
|
|
@@ -6935,6 +6984,15 @@ export class CrewlyServer {
|
|
|
6935
6984
|
WorktreeJanitorService.getInstance().stop();
|
|
6936
6985
|
// Stop auditor scheduler
|
|
6937
6986
|
AuditorSchedulerService.getInstance().stop();
|
|
6987
|
+
// Write the usage ledger's buffered buckets
|
|
6988
|
+
try {
|
|
6989
|
+
await getUsageLedger().stop();
|
|
6990
|
+
}
|
|
6991
|
+
catch (ledgerErr) {
|
|
6992
|
+
this.logger.warn('Usage ledger flush on shutdown failed (non-fatal)', {
|
|
6993
|
+
error: ledgerErr instanceof Error ? ledgerErr.message : String(ledgerErr),
|
|
6994
|
+
});
|
|
6995
|
+
}
|
|
6938
6996
|
// Persist the token ledger: it flushes every 5 minutes, so a restart
|
|
6939
6997
|
// used to drop everything recorded since the last tick (2026-09-18).
|
|
6940
6998
|
try {
|