@cat-factory/orchestration 0.289.3 → 0.290.0
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/dist/modules/reports/ReportsService.d.ts +15 -3
- package/dist/modules/reports/ReportsService.d.ts.map +1 -1
- package/dist/modules/reports/ReportsService.js +26 -8
- package/dist/modules/reports/ReportsService.js.map +1 -1
- package/dist/modules/reports/reports.logic.d.ts +20 -1
- package/dist/modules/reports/reports.logic.d.ts.map +1 -1
- package/dist/modules/reports/reports.logic.js +23 -0
- package/dist/modules/reports/reports.logic.js.map +1 -1
- package/package.json +11 -11
|
@@ -20,7 +20,14 @@ export interface ReportsBreakdown {
|
|
|
20
20
|
totals: ReportTotals;
|
|
21
21
|
/** The heaviest slices by metered cost, capped by the caller's `limit` when it named one. */
|
|
22
22
|
rows: ReportSpendRow[];
|
|
23
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* True when the window held more slices than `limit`, so `rows` is a prefix of them.
|
|
25
|
+
*
|
|
26
|
+
* The cap itself is computed by `capSlices`, the same helper the panel projection uses, and
|
|
27
|
+
* carries an exact `omitted` count; this narrows it to a boolean because the public
|
|
28
|
+
* `GET /api/v1/usage/spend` response schema is frozen on one. Publishing the count is an
|
|
29
|
+
* additive change to that schema whenever it is worth a version bump.
|
|
30
|
+
*/
|
|
24
31
|
truncated: boolean;
|
|
25
32
|
}
|
|
26
33
|
export interface ReportsServiceDependencies {
|
|
@@ -72,8 +79,8 @@ export declare class ReportsService {
|
|
|
72
79
|
* question (what did this repository cost, what did that ticket cost) actually needs.
|
|
73
80
|
*
|
|
74
81
|
* A separate method rather than a `dimension` option on `summarize`, because the two differ
|
|
75
|
-
* in what they COST: the panel renders every slice together and pays for
|
|
76
|
-
* where this is one `GROUP BY` and returning the other
|
|
82
|
+
* in what they COST: the panel renders every slice together and pays for thirteen aggregates,
|
|
83
|
+
* where this is one `GROUP BY` and returning the other twelve would be work nobody asked for.
|
|
77
84
|
* Everything else about it is deliberately the same read, so a number here and the same
|
|
78
85
|
* number in the panel come from one code path.
|
|
79
86
|
*
|
|
@@ -81,6 +88,11 @@ export declare class ReportsService {
|
|
|
81
88
|
* population either way, so a capped breakdown still reports what was spent and only loses
|
|
82
89
|
* the identity of the tail. That is why the cap is applied here rather than pushed into the
|
|
83
90
|
* `GROUP BY` as a SQL `LIMIT`, which would take the totals down with it.
|
|
91
|
+
*
|
|
92
|
+
* The cap runs through `capSlices`, the same helper the panel projection caps its two
|
|
93
|
+
* activity-scaled dimensions with, so there is ONE place a spend breakdown is shortened and
|
|
94
|
+
* one definition of which end it keeps. This read then reports the cap as the boolean its
|
|
95
|
+
* frozen public response schema carries; see `truncated`.
|
|
84
96
|
*/
|
|
85
97
|
breakdown(accountId: string, dimension: ReportSpendDimension, window: ReportWindow, workspaceId?: string | null, limit?: number): Promise<ReportsBreakdown>;
|
|
86
98
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReportsService.d.ts","sourceRoot":"","sources":["../../../src/modules/reports/ReportsService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"ReportsService.d.ts","sourceRoot":"","sources":["../../../src/modules/reports/ReportsService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,oBAAoB,EACpB,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,YAAY,EACZ,WAAW,EACZ,MAAM,wBAAwB,CAAA;AAE/B,OAAO,KAAK,EACV,KAAK,EAKL,iBAAiB,EACjB,qBAAqB,EACtB,MAAM,qBAAqB,CAAA;AAuB5B;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,SAAS,EAAE,oBAAoB,CAAA;IAC/B,MAAM,EAAE,YAAY,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,EAAE,MAAM,CAAA;IAChB,MAAM,EAAE,iBAAiB,CAAA;IACzB,eAAe,EAAE,MAAM,GAAG,IAAI,CAAA;IAC9B,kFAAkF;IAClF,MAAM,EAAE,YAAY,CAAA;IACpB,6FAA6F;IAC7F,IAAI,EAAE,cAAc,EAAE,CAAA;IACtB;;;;;;;OAOG;IACH,SAAS,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,0BAA0B;IACzC,iBAAiB,EAAE,iBAAiB,CAAA;IACpC;;;;;;OAMG;IACH,qBAAqB,CAAC,EAAE,qBAAqB,CAAA;IAC7C,KAAK,EAAE,KAAK,CAAA;IACZ;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,cAAc;IACb,OAAO,CAAC,QAAQ,CAAC,IAAI;IAAjC,YAA6B,IAAI,EAAE,0BAA0B,EAAI;IAE3D,SAAS,CACb,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,YAAY,EACpB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,GAC1B,OAAO,CAAC,WAAW,CAAC,CAgFtB;IAED;;;;;;;;;;;;;;;;;;;;OAoBG;IACG,SAAS,CACb,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,oBAAoB,EAC/B,MAAM,EAAE,YAAY,EACpB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,EAC3B,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,gBAAgB,CAAC,CAkC3B;IAED;;;;;OAKG;IACH,OAAO,CAAC,WAAW;CA6BpB"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { REPORT_SLICE_LIMIT } from '@cat-factory/contracts';
|
|
2
|
+
import { REPORT_WINDOWS, alignWindowStart, buildSpendTrend, capSlices, foldTotals, toActivityRow, toSpendRow, } from './reports.logic.js';
|
|
2
3
|
/**
|
|
3
4
|
* Cross-cutting usage analytics: composes the rollups behind {@link ReportsRepository} and
|
|
4
5
|
* {@link SpendRollupRepository} into the Reports view: spend sliced by model, agent kind,
|
|
@@ -36,7 +37,7 @@ export class ReportsService {
|
|
|
36
37
|
const range = { since, until };
|
|
37
38
|
const repo = this.deps.reportsRepository;
|
|
38
39
|
const { source, spend } = this.spendSource(preferred);
|
|
39
|
-
const [byModel, byAgentKind, spendByWorkspace, spendByService, spendByRepo, spendByTaskType, spendByTicket, spendByRun, activityByWorkspace, activityByService, activityByTaskType, trend, rolledUpThrough,] = await Promise.all([
|
|
40
|
+
const [byModel, byAgentKind, spendByWorkspace, spendByService, spendByRepo, spendByTaskType, spendByTicket, spendByRun, activityByWorkspace, activityByService, activityByRepo, activityByTaskType, trend, rolledUpThrough,] = await Promise.all([
|
|
40
41
|
spend.byDimension(scope, 'model', range),
|
|
41
42
|
spend.byDimension(scope, 'agentKind', range),
|
|
42
43
|
spend.byDimension(scope, 'workspace', range),
|
|
@@ -47,11 +48,18 @@ export class ReportsService {
|
|
|
47
48
|
spend.byDimension(scope, 'run', range),
|
|
48
49
|
repo.activityByDimension(scope, 'workspace', range),
|
|
49
50
|
repo.activityByDimension(scope, 'service', range),
|
|
51
|
+
repo.activityByDimension(scope, 'repo', range),
|
|
50
52
|
repo.activityByDimension(scope, 'taskType', range),
|
|
51
53
|
spend.trend(scope, range, bucketMs),
|
|
52
54
|
spend.watermark(),
|
|
53
55
|
]);
|
|
54
56
|
const spendByModel = byModel.map(toSpendRow);
|
|
57
|
+
// Only the activity-scaled dimensions are capped. Everything else keys on a catalog and
|
|
58
|
+
// stays small on its own, so capping it would drop slices for nothing. The two that are
|
|
59
|
+
// capped announce it in `capped` below; the totals fold from the UNCAPPED model breakdown,
|
|
60
|
+
// so what a cap costs the reader is the identity of the tail and never its money.
|
|
61
|
+
const ticket = capSlices('ticket', spendByTicket.map(toSpendRow), REPORT_SLICE_LIMIT);
|
|
62
|
+
const run = capSlices('run', spendByRun.map(toSpendRow), REPORT_SLICE_LIMIT);
|
|
55
63
|
return {
|
|
56
64
|
window,
|
|
57
65
|
generatedAt: until,
|
|
@@ -70,12 +78,14 @@ export class ReportsService {
|
|
|
70
78
|
byService: spendByService.map(toSpendRow),
|
|
71
79
|
byRepo: spendByRepo.map(toSpendRow),
|
|
72
80
|
byTaskType: spendByTaskType.map(toSpendRow),
|
|
73
|
-
byTicket:
|
|
74
|
-
byRun:
|
|
81
|
+
byTicket: ticket.rows,
|
|
82
|
+
byRun: run.rows,
|
|
75
83
|
},
|
|
84
|
+
capped: [ticket.cap, run.cap].filter((cap) => cap !== null),
|
|
76
85
|
activity: {
|
|
77
86
|
byWorkspace: activityByWorkspace.map(toActivityRow),
|
|
78
87
|
byService: activityByService.map(toActivityRow),
|
|
88
|
+
byRepo: activityByRepo.map(toActivityRow),
|
|
79
89
|
byTaskType: activityByTaskType.map(toActivityRow),
|
|
80
90
|
},
|
|
81
91
|
trend: { bucketMs, points: buildSpendTrend(trend, since, until, bucketMs) },
|
|
@@ -87,8 +97,8 @@ export class ReportsService {
|
|
|
87
97
|
* question (what did this repository cost, what did that ticket cost) actually needs.
|
|
88
98
|
*
|
|
89
99
|
* A separate method rather than a `dimension` option on `summarize`, because the two differ
|
|
90
|
-
* in what they COST: the panel renders every slice together and pays for
|
|
91
|
-
* where this is one `GROUP BY` and returning the other
|
|
100
|
+
* in what they COST: the panel renders every slice together and pays for thirteen aggregates,
|
|
101
|
+
* where this is one `GROUP BY` and returning the other twelve would be work nobody asked for.
|
|
92
102
|
* Everything else about it is deliberately the same read, so a number here and the same
|
|
93
103
|
* number in the panel come from one code path.
|
|
94
104
|
*
|
|
@@ -96,6 +106,11 @@ export class ReportsService {
|
|
|
96
106
|
* population either way, so a capped breakdown still reports what was spent and only loses
|
|
97
107
|
* the identity of the tail. That is why the cap is applied here rather than pushed into the
|
|
98
108
|
* `GROUP BY` as a SQL `LIMIT`, which would take the totals down with it.
|
|
109
|
+
*
|
|
110
|
+
* The cap runs through `capSlices`, the same helper the panel projection caps its two
|
|
111
|
+
* activity-scaled dimensions with, so there is ONE place a spend breakdown is shortened and
|
|
112
|
+
* one definition of which end it keeps. This read then reports the cap as the boolean its
|
|
113
|
+
* frozen public response schema carries; see `truncated`.
|
|
99
114
|
*/
|
|
100
115
|
async breakdown(accountId, dimension, window, workspaceId, limit) {
|
|
101
116
|
const { windowMs, bucketMs, source: preferred } = REPORT_WINDOWS[window];
|
|
@@ -112,6 +127,9 @@ export class ReportsService {
|
|
|
112
127
|
spend.watermark(),
|
|
113
128
|
]);
|
|
114
129
|
const rows = groups.map(toSpendRow);
|
|
130
|
+
// An absent `limit` means "serve the whole breakdown", which is a cap of nothing rather
|
|
131
|
+
// than a different code path.
|
|
132
|
+
const capped = limit === undefined ? { rows, cap: null } : capSlices(dimension, rows, limit);
|
|
115
133
|
return {
|
|
116
134
|
dimension,
|
|
117
135
|
window,
|
|
@@ -125,8 +143,8 @@ export class ReportsService {
|
|
|
125
143
|
// cap for the same reason: a total over the returned prefix would under-report the
|
|
126
144
|
// window while still reading as the window's total.
|
|
127
145
|
totals: foldTotals(rows),
|
|
128
|
-
truncated:
|
|
129
|
-
rows:
|
|
146
|
+
truncated: capped.cap !== null,
|
|
147
|
+
rows: capped.rows,
|
|
130
148
|
};
|
|
131
149
|
}
|
|
132
150
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ReportsService.js","sourceRoot":"","sources":["../../../src/modules/reports/ReportsService.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"ReportsService.js","sourceRoot":"","sources":["../../../src/modules/reports/ReportsService.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ReportActivityRow, ReportSpendRow, ReportSpendSource, ReportTotals, ReportTrendPoint, ReportWindow } from '@cat-factory/contracts';
|
|
1
|
+
import type { ReportActivityRow, ReportSpendCap, ReportSpendDimension, ReportSpendRow, ReportSpendSource, ReportTotals, ReportTrendPoint, ReportWindow } from '@cat-factory/contracts';
|
|
2
2
|
import type { ReportActivityGroup, ReportSpendGroup, ReportSpendTrendBucket } from '@cat-factory/kernel';
|
|
3
3
|
/**
|
|
4
4
|
* The window's start, snapped DOWN to a bucket edge.
|
|
@@ -41,6 +41,25 @@ export declare function toActivityRow(group: ReportActivityGroup): ReportActivit
|
|
|
41
41
|
* costs nothing and avoids a sixth aggregate query purely to restate it.
|
|
42
42
|
*/
|
|
43
43
|
export declare function foldTotals(rows: ReportSpendRow[]): ReportTotals;
|
|
44
|
+
/**
|
|
45
|
+
* Take the heaviest `limit` slices of a breakdown and say what that left behind.
|
|
46
|
+
*
|
|
47
|
+
* Only the activity-scaled dimensions are passed through here (`run` is one row per pipeline
|
|
48
|
+
* execution, `ticket` one per tracker issue a run touched); everything else keys on a catalog
|
|
49
|
+
* and is served whole. The cap is applied to the AGGREGATED rows rather than pushed into the
|
|
50
|
+
* `GROUP BY` as a SQL `LIMIT`, which is what makes the returned `omitted` an exact count of
|
|
51
|
+
* the tail rather than a boolean "there was more". Rows arrive heaviest-first from the store,
|
|
52
|
+
* so the prefix is the heavy end a cost question is actually about.
|
|
53
|
+
*
|
|
54
|
+
* The `cap` is null when nothing was dropped: a projection whose `capped` list is empty is
|
|
55
|
+
* complete everywhere, which is what lets the reader trust an ordinary breakdown without
|
|
56
|
+
* checking anything. Window totals are folded from an UNCAPPED breakdown, so they still cover
|
|
57
|
+
* the tail this drops.
|
|
58
|
+
*/
|
|
59
|
+
export declare function capSlices(dimension: ReportSpendDimension, rows: ReportSpendRow[], limit: number): {
|
|
60
|
+
rows: ReportSpendRow[];
|
|
61
|
+
cap: ReportSpendCap | null;
|
|
62
|
+
};
|
|
44
63
|
/**
|
|
45
64
|
* Fold the sparse trend buckets into a contiguous, zero-filled, oldest-first series
|
|
46
65
|
* spanning `[since, until]` at `bucketMs` resolution — so a quiet period reads as a flat
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reports.logic.d.ts","sourceRoot":"","sources":["../../../src/modules/reports/reports.logic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EACjB,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACb,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EACV,mBAAmB,EACnB,gBAAgB,EAChB,sBAAsB,EACvB,MAAM,qBAAqB,CAAA;AAM5B;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE1F;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,cAAc,EAAE,MAAM,CACjC,YAAY,EACZ;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,CAclE,CAAA;AAED,6FAA6F;AAC7F,wBAAgB,UAAU,CAAC,KAAK,EAAE,gBAAgB,GAAG,cAAc,CAUlE;AAED,qDAAqD;AACrD,wBAAgB,aAAa,CAAC,KAAK,EAAE,mBAAmB,GAAG,iBAAiB,CAW3E;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,YAAY,CAgB/D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,sBAAsB,EAAE,EACjC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACf,gBAAgB,EAAE,CAyBpB"}
|
|
1
|
+
{"version":3,"file":"reports.logic.d.ts","sourceRoot":"","sources":["../../../src/modules/reports/reports.logic.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,iBAAiB,EACjB,cAAc,EACd,oBAAoB,EACpB,cAAc,EACd,iBAAiB,EACjB,YAAY,EACZ,gBAAgB,EAChB,YAAY,EACb,MAAM,wBAAwB,CAAA;AAC/B,OAAO,KAAK,EACV,mBAAmB,EACnB,gBAAgB,EAChB,sBAAsB,EACvB,MAAM,qBAAqB,CAAA;AAM5B;;;;;;;;;;GAUG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE1F;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,cAAc,EAAE,MAAM,CACjC,YAAY,EACZ;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,iBAAiB,CAAA;CAAE,CAclE,CAAA;AAED,6FAA6F;AAC7F,wBAAgB,UAAU,CAAC,KAAK,EAAE,gBAAgB,GAAG,cAAc,CAUlE;AAED,qDAAqD;AACrD,wBAAgB,aAAa,CAAC,KAAK,EAAE,mBAAmB,GAAG,iBAAiB,CAW3E;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,IAAI,EAAE,cAAc,EAAE,GAAG,YAAY,CAgB/D;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,SAAS,CACvB,SAAS,EAAE,oBAAoB,EAC/B,IAAI,EAAE,cAAc,EAAE,EACtB,KAAK,EAAE,MAAM,GACZ;IAAE,IAAI,EAAE,cAAc,EAAE,CAAC;IAAC,GAAG,EAAE,cAAc,GAAG,IAAI,CAAA;CAAE,CAMxD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,sBAAsB,EAAE,EACjC,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,GACf,gBAAgB,EAAE,CAyBpB"}
|
|
@@ -90,6 +90,29 @@ export function foldTotals(rows) {
|
|
|
90
90
|
}
|
|
91
91
|
return totals;
|
|
92
92
|
}
|
|
93
|
+
/**
|
|
94
|
+
* Take the heaviest `limit` slices of a breakdown and say what that left behind.
|
|
95
|
+
*
|
|
96
|
+
* Only the activity-scaled dimensions are passed through here (`run` is one row per pipeline
|
|
97
|
+
* execution, `ticket` one per tracker issue a run touched); everything else keys on a catalog
|
|
98
|
+
* and is served whole. The cap is applied to the AGGREGATED rows rather than pushed into the
|
|
99
|
+
* `GROUP BY` as a SQL `LIMIT`, which is what makes the returned `omitted` an exact count of
|
|
100
|
+
* the tail rather than a boolean "there was more". Rows arrive heaviest-first from the store,
|
|
101
|
+
* so the prefix is the heavy end a cost question is actually about.
|
|
102
|
+
*
|
|
103
|
+
* The `cap` is null when nothing was dropped: a projection whose `capped` list is empty is
|
|
104
|
+
* complete everywhere, which is what lets the reader trust an ordinary breakdown without
|
|
105
|
+
* checking anything. Window totals are folded from an UNCAPPED breakdown, so they still cover
|
|
106
|
+
* the tail this drops.
|
|
107
|
+
*/
|
|
108
|
+
export function capSlices(dimension, rows, limit) {
|
|
109
|
+
if (rows.length <= limit)
|
|
110
|
+
return { rows, cap: null };
|
|
111
|
+
return {
|
|
112
|
+
rows: rows.slice(0, limit),
|
|
113
|
+
cap: { dimension, returned: limit, omitted: rows.length - limit },
|
|
114
|
+
};
|
|
115
|
+
}
|
|
93
116
|
/**
|
|
94
117
|
* Fold the sparse trend buckets into a contiguous, zero-filled, oldest-first series
|
|
95
118
|
* spanning `[since, until]` at `bucketMs` resolution — so a quiet period reads as a flat
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"reports.logic.js","sourceRoot":"","sources":["../../../src/modules/reports/reports.logic.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"reports.logic.js","sourceRoot":"","sources":["../../../src/modules/reports/reports.logic.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cat-factory/orchestration",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.290.0",
|
|
4
4
|
"description": "Delivery-workflow engine for the Agent Architecture Board (execution, bootstrap, pipelines, board, boardScan, requirements, and composition root).",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -24,19 +24,19 @@
|
|
|
24
24
|
"access": "public"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@cat-factory/agents": "0.146.
|
|
28
|
-
"@cat-factory/caching": "0.20.
|
|
29
|
-
"@cat-factory/contracts": "0.
|
|
30
|
-
"@cat-factory/integrations": "0.166.
|
|
31
|
-
"@cat-factory/kernel": "0.
|
|
32
|
-
"@cat-factory/prompt-fragments": "1.1.
|
|
33
|
-
"@cat-factory/sandbox": "0.12.
|
|
34
|
-
"@cat-factory/spend": "0.16.
|
|
35
|
-
"@cat-factory/workspaces": "0.28.
|
|
27
|
+
"@cat-factory/agents": "0.146.4",
|
|
28
|
+
"@cat-factory/caching": "0.20.53",
|
|
29
|
+
"@cat-factory/contracts": "0.334.0",
|
|
30
|
+
"@cat-factory/integrations": "0.166.20",
|
|
31
|
+
"@cat-factory/kernel": "0.323.0",
|
|
32
|
+
"@cat-factory/prompt-fragments": "1.1.15",
|
|
33
|
+
"@cat-factory/sandbox": "0.12.27",
|
|
34
|
+
"@cat-factory/spend": "0.16.24",
|
|
35
|
+
"@cat-factory/workspaces": "0.28.41",
|
|
36
36
|
"ai": "^7.0.83"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
-
"@cat-factory/sandbox-fixtures": "0.8.
|
|
39
|
+
"@cat-factory/sandbox-fixtures": "0.8.15",
|
|
40
40
|
"typescript": "7.0.2",
|
|
41
41
|
"vitest": "^4.1.11"
|
|
42
42
|
},
|