@appliqation/dashboard 0.1.1
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/LICENSE +21 -0
- package/README.md +60 -0
- package/dist/cli/index.js +75 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/table.js +15 -0
- package/dist/cli/table.js.map +1 -0
- package/dist/config/env.js +10 -0
- package/dist/config/env.js.map +1 -0
- package/dist/report/aggregate.js +116 -0
- package/dist/report/aggregate.js.map +1 -0
- package/dist/report/cost.js +18 -0
- package/dist/report/cost.js.map +1 -0
- package/dist/store/auditStore.js +52 -0
- package/dist/store/auditStore.js.map +1 -0
- package/package.json +37 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Appliqation Pty Ltd
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Appliqation Dashboard
|
|
2
|
+
|
|
3
|
+
**Reads the audit trail every agent in the [Appliqation agent family](https://github.com/appliqation/appliqation-autopilot) writes, and prints an aggregated report: how many runs, how many tokens, and what actually happened, over a period.**
|
|
4
|
+
|
|
5
|
+
Genuinely separate from Appliqation itself — this agent family is a parallel system that *uses* Appliqation, not a feature of it, so its own audit trail lives in infrastructure this family owns (a MongoDB you configure, or a plain local JSONL file), never inside appq. This tool has no LLM, no appq connection, no credentials beyond pointing at that store.
|
|
6
|
+
|
|
7
|
+
## How it works
|
|
8
|
+
|
|
9
|
+
Every sibling agent (`appliqation-autotest`, `appliqation-scriptgen`, `appliqation-defect-fix`, `appliqation-pr-raise`, `appliqation-explorer`, `appliqation-autopilot`) optionally writes one record per invocation — token usage, duration, and its own real `--json` outcome — via [`@appliqation/agent-core`](https://github.com/appliqation/appliqation-agent-core)'s `audit/sink.ts`, entirely opt-in and best-effort (a broken audit store never affects the real run). This tool reads the same store back and aggregates it.
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
appliqation-dashboard report --group-by month
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
2026-08-01 to 2026-08-31, grouped by month
|
|
17
|
+
|
|
18
|
+
Period Agent Runs In tokens Out tokens Cache read Duration Derived Est. cost
|
|
19
|
+
------- ----------------------- ---- --------- ---------- ---------- -------- ------------------- ---------
|
|
20
|
+
2026-08 appliqation-autotest 42 850000 120000 600000 95.2s avg 118 test cases judged $4.20
|
|
21
|
+
2026-08 appliqation-explorer 6 210000 40000 50000 210.5s avg 5 completed passes $1.10
|
|
22
|
+
2026-08 appliqation-pr-raise 8 0 0 0 3.1s avg 6 PRs opened/updated -
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Quick start
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install -g @appliqation/dashboard
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Create a `.env` file (in whatever directory you'll run it from) pointing at the same audit
|
|
32
|
+
store your agents write to — see [Configuration](#configuration) below.
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
appliqation-dashboard report [--since <date>] [--until <date>] [--group-by day|week|month|quarter|year] [--agent <name>]
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Defaults to the last 30 days, grouped by day, all agents. `--group-by` accepts `day`/`week`/`month`/`quarter`/`year`.
|
|
39
|
+
|
|
40
|
+
## Configuration
|
|
41
|
+
|
|
42
|
+
Copy `.env.example` to `.env`. Point `AUDIT_MONGO_URI`/`AUDIT_MONGO_DB`/`AUDIT_MONGO_COLLECTION` (or `AUDIT_JSONL_PATH`) at the **same store** the sibling agents' own `.env` files write to — this tool errors clearly if neither is configured, rather than silently printing an empty report. `MODEL_PRICING` optionally points at a small JSON file of per-model `$/1M tokens` prices to estimate cost; omitted entirely from the report if unset — never a stale hardcoded price.
|
|
43
|
+
|
|
44
|
+
## Development
|
|
45
|
+
|
|
46
|
+
```bash
|
|
47
|
+
git clone https://github.com/appliqation/appliqation-dashboard.git
|
|
48
|
+
cd appliqation-dashboard
|
|
49
|
+
npm install
|
|
50
|
+
cp .env.example .env # point at the same audit store your agents write to
|
|
51
|
+
npm run dev -- report [--group-by month]
|
|
52
|
+
npm run typecheck
|
|
53
|
+
npm test
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
See `CLAUDE.md` for a map of this repo if you're working in it with an AI coding assistant.
|
|
57
|
+
|
|
58
|
+
## License
|
|
59
|
+
|
|
60
|
+
MIT — see [LICENSE](./LICENSE).
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// `report`: read the audit trail written by every sibling agent's
|
|
3
|
+
// safeRecord()/AuditSink (see @appliqation/agent-core's audit/sink.ts) and
|
|
4
|
+
// print an aggregated table — invocations, token usage, an agent-specific
|
|
5
|
+
// derived count, and (if MODEL_PRICING is configured) an estimated cost, per
|
|
6
|
+
// period. Genuinely read-only, no LLM, no appq connection — see README.md.
|
|
7
|
+
import { Command } from 'commander';
|
|
8
|
+
import { config } from '../config/env.js';
|
|
9
|
+
import { resolveQuerySource } from '../store/auditStore.js';
|
|
10
|
+
import { aggregate } from '../report/aggregate.js';
|
|
11
|
+
import { loadModelPricing } from '../report/cost.js';
|
|
12
|
+
import { printTable } from './table.js';
|
|
13
|
+
const GROUP_BY_VALUES = ['day', 'week', 'month', 'quarter', 'year'];
|
|
14
|
+
const DEFAULT_RANGE_DAYS = 30;
|
|
15
|
+
function formatUsd(n) {
|
|
16
|
+
return n === undefined ? '-' : `$${n.toFixed(2)}`;
|
|
17
|
+
}
|
|
18
|
+
function formatSeconds(millis, invocations) {
|
|
19
|
+
if (invocations === 0)
|
|
20
|
+
return '-';
|
|
21
|
+
return `${(millis / invocations / 1000).toFixed(1)}s avg`;
|
|
22
|
+
}
|
|
23
|
+
const program = new Command();
|
|
24
|
+
program.name('appliqation-dashboard').description("Read-only reporting CLI for the Appliqation agent family's audit trail.");
|
|
25
|
+
program
|
|
26
|
+
.command('report')
|
|
27
|
+
.description('Aggregate the audit trail (see @appliqation/agent-core\'s audit/sink.ts) by period and agent: invocation ' +
|
|
28
|
+
'count, token usage, an agent-specific derived count (e.g. test cases judged, PRs opened), and an ' +
|
|
29
|
+
'estimated $ cost if MODEL_PRICING is configured. Defaults to the last 30 days, grouped by day, all agents.')
|
|
30
|
+
.option('--since <date>', 'ISO date — defaults to 30 days before --until')
|
|
31
|
+
.option('--until <date>', 'ISO date — defaults to now')
|
|
32
|
+
.option('--group-by <period>', `one of: ${GROUP_BY_VALUES.join(', ')}`, 'day')
|
|
33
|
+
.option('--agent <name>', 'filter to one agent, e.g. appliqation-autotest')
|
|
34
|
+
.action(async (opts) => {
|
|
35
|
+
if (!GROUP_BY_VALUES.includes(opts.groupBy)) {
|
|
36
|
+
throw new Error(`--group-by must be one of: ${GROUP_BY_VALUES.join(', ')} — got "${opts.groupBy}"`);
|
|
37
|
+
}
|
|
38
|
+
const groupBy = opts.groupBy;
|
|
39
|
+
const until = opts.until ? new Date(opts.until) : new Date();
|
|
40
|
+
const since = opts.since ? new Date(opts.since) : new Date(until.getTime() - DEFAULT_RANGE_DAYS * 24 * 60 * 60 * 1000);
|
|
41
|
+
const source = resolveQuerySource({
|
|
42
|
+
auditMongoUri: config.auditMongoUri,
|
|
43
|
+
auditMongoDb: config.auditMongoDb,
|
|
44
|
+
auditMongoCollection: config.auditMongoCollection,
|
|
45
|
+
auditJsonlPath: config.auditJsonlPath,
|
|
46
|
+
});
|
|
47
|
+
let records = await source.queryRecords({ since, until });
|
|
48
|
+
if (opts.agent)
|
|
49
|
+
records = records.filter((r) => r.agent === opts.agent);
|
|
50
|
+
const pricing = await loadModelPricing(config.modelPricingPath);
|
|
51
|
+
const buckets = aggregate(records, groupBy, pricing);
|
|
52
|
+
console.log(`\n${since.toISOString().slice(0, 10)} to ${until.toISOString().slice(0, 10)}, grouped by ${groupBy}\n`);
|
|
53
|
+
const rows = [];
|
|
54
|
+
for (const bucket of buckets) {
|
|
55
|
+
for (const stats of bucket.agents) {
|
|
56
|
+
rows.push([
|
|
57
|
+
bucket.key,
|
|
58
|
+
stats.agent,
|
|
59
|
+
String(stats.invocations),
|
|
60
|
+
String(stats.inputTokens),
|
|
61
|
+
String(stats.outputTokens),
|
|
62
|
+
String(stats.cacheReadTokens),
|
|
63
|
+
formatSeconds(stats.totalDurationMillis, stats.invocations),
|
|
64
|
+
stats.derivedLabel ? `${stats.derivedCount} ${stats.derivedLabel}` : '-',
|
|
65
|
+
formatUsd(stats.estimatedCostUsd),
|
|
66
|
+
]);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
printTable(['Period', 'Agent', 'Runs', 'In tokens', 'Out tokens', 'Cache read', 'Duration', 'Derived', 'Est. cost'], rows);
|
|
70
|
+
if (records.length === 0) {
|
|
71
|
+
console.log('\nNo audit records found in this range. Check AUDIT_MONGO_*/AUDIT_JSONL_PATH points at the store the agents actually write to.');
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
program.parseAsync(process.argv);
|
|
75
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// A small manual padded-column table printer — no charting/table dependency
|
|
2
|
+
// needed for something this simple.
|
|
3
|
+
export function printTable(headers, rows) {
|
|
4
|
+
if (rows.length === 0) {
|
|
5
|
+
console.log('(no data in this range)');
|
|
6
|
+
return;
|
|
7
|
+
}
|
|
8
|
+
const widths = headers.map((h, i) => Math.max(h.length, ...rows.map((r) => (r[i] ?? '').length)));
|
|
9
|
+
const line = (cells) => cells.map((c, i) => (c ?? '').padEnd(widths[i])).join(' ');
|
|
10
|
+
console.log(line(headers));
|
|
11
|
+
console.log(widths.map((w) => '-'.repeat(w)).join(' '));
|
|
12
|
+
for (const row of rows)
|
|
13
|
+
console.log(line(row));
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=table.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"table.js","sourceRoot":"","sources":["../../src/cli/table.ts"],"names":[],"mappings":"AAAA,4EAA4E;AAC5E,oCAAoC;AAEpC,MAAM,UAAU,UAAU,CAAC,OAAiB,EAAE,IAAgB;IAC5D,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;QACvC,OAAO;IACT,CAAC;IACD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;IAClG,MAAM,IAAI,GAAG,CAAC,KAAe,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9F,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,CAAC;IAC3B,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACzD,KAAK,MAAM,GAAG,IAAI,IAAI;QAAE,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AACjD,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import 'dotenv/config';
|
|
2
|
+
import { optional } from '@appliqation/agent-core/config';
|
|
3
|
+
export const config = {
|
|
4
|
+
auditMongoUri: optional('AUDIT_MONGO_URI'),
|
|
5
|
+
auditMongoDb: optional('AUDIT_MONGO_DB'),
|
|
6
|
+
auditMongoCollection: optional('AUDIT_MONGO_COLLECTION'),
|
|
7
|
+
auditJsonlPath: optional('AUDIT_JSONL_PATH'),
|
|
8
|
+
modelPricingPath: optional('MODEL_PRICING'),
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=env.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"env.js","sourceRoot":"","sources":["../../src/config/env.ts"],"names":[],"mappings":"AAAA,OAAO,eAAe,CAAC;AACvB,OAAO,EAAE,QAAQ,EAAE,MAAM,gCAAgC,CAAC;AAE1D,MAAM,CAAC,MAAM,MAAM,GAAG;IACpB,aAAa,EAAE,QAAQ,CAAC,iBAAiB,CAAC;IAC1C,YAAY,EAAE,QAAQ,CAAC,gBAAgB,CAAC;IACxC,oBAAoB,EAAE,QAAQ,CAAC,wBAAwB,CAAC;IACxD,cAAc,EAAE,QAAQ,CAAC,kBAAkB,CAAC;IAC5C,gBAAgB,EAAE,QAAQ,CAAC,eAAe,CAAC;CAC5C,CAAC"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
// Pure aggregation over a flat list of AuditRecords — no I/O, no Date.now()
|
|
2
|
+
// (the CLI passes in the range explicitly), so this is fully unit-testable
|
|
3
|
+
// against fixed records.
|
|
4
|
+
import { estimateCost } from './cost.js';
|
|
5
|
+
function isoWeekKey(d) {
|
|
6
|
+
// Standard ISO 8601 week-of-year algorithm.
|
|
7
|
+
const date = new Date(Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate()));
|
|
8
|
+
const dayNum = date.getUTCDay() || 7;
|
|
9
|
+
date.setUTCDate(date.getUTCDate() + 4 - dayNum);
|
|
10
|
+
const yearStart = new Date(Date.UTC(date.getUTCFullYear(), 0, 1));
|
|
11
|
+
const weekNum = Math.ceil(((date.getTime() - yearStart.getTime()) / 86400000 + 1) / 7);
|
|
12
|
+
return `${date.getUTCFullYear()}-W${String(weekNum).padStart(2, '0')}`;
|
|
13
|
+
}
|
|
14
|
+
function bucketKey(date, groupBy) {
|
|
15
|
+
const year = date.getUTCFullYear();
|
|
16
|
+
const month = date.getUTCMonth(); // 0-indexed
|
|
17
|
+
switch (groupBy) {
|
|
18
|
+
case 'day':
|
|
19
|
+
return date.toISOString().slice(0, 10);
|
|
20
|
+
case 'week':
|
|
21
|
+
return isoWeekKey(date);
|
|
22
|
+
case 'month':
|
|
23
|
+
return `${year}-${String(month + 1).padStart(2, '0')}`;
|
|
24
|
+
case 'quarter':
|
|
25
|
+
return `${year}-Q${Math.floor(month / 3) + 1}`;
|
|
26
|
+
case 'year':
|
|
27
|
+
return String(year);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function sum(records, pick) {
|
|
31
|
+
return records.reduce((total, r) => total + pick(r), 0);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Agent-specific derived counts — a short, explicit switch, not a generic
|
|
35
|
+
* schema-sniffer. Each sibling agent's `outcome` is its own already-built
|
|
36
|
+
* --json summary object (see each repo's cli/audit.ts), so this just knows
|
|
37
|
+
* the one field per agent worth surfacing as a headline number.
|
|
38
|
+
*/
|
|
39
|
+
function deriveExtra(agent, records) {
|
|
40
|
+
switch (agent) {
|
|
41
|
+
case 'appliqation-autotest': {
|
|
42
|
+
const count = sum(records, (r) => {
|
|
43
|
+
const results = r.outcome.results;
|
|
44
|
+
return Array.isArray(results) ? results.length : 0;
|
|
45
|
+
});
|
|
46
|
+
return { count, label: 'test cases judged' };
|
|
47
|
+
}
|
|
48
|
+
case 'appliqation-pr-raise': {
|
|
49
|
+
const count = records.filter((r) => Boolean(r.outcome.pr)).length;
|
|
50
|
+
return { count, label: 'PRs opened/updated' };
|
|
51
|
+
}
|
|
52
|
+
case 'appliqation-scriptgen':
|
|
53
|
+
case 'appliqation-defect-fix': {
|
|
54
|
+
const count = records.filter((r) => r.outcome.verified === true).length;
|
|
55
|
+
return { count, label: 'verified' };
|
|
56
|
+
}
|
|
57
|
+
case 'appliqation-explorer': {
|
|
58
|
+
const count = records.filter((r) => r.outcome.budgetExceeded === false).length;
|
|
59
|
+
return { count, label: 'completed passes' };
|
|
60
|
+
}
|
|
61
|
+
default:
|
|
62
|
+
return undefined;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
export function aggregate(records, groupBy, pricing) {
|
|
66
|
+
const byBucket = new Map();
|
|
67
|
+
for (const r of records) {
|
|
68
|
+
const key = bucketKey(new Date(r.startedAt), groupBy);
|
|
69
|
+
if (!byBucket.has(key))
|
|
70
|
+
byBucket.set(key, []);
|
|
71
|
+
byBucket.get(key).push(r);
|
|
72
|
+
}
|
|
73
|
+
return [...byBucket.entries()]
|
|
74
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
75
|
+
.map(([key, bucketRecords]) => {
|
|
76
|
+
const byAgent = new Map();
|
|
77
|
+
for (const r of bucketRecords) {
|
|
78
|
+
if (!byAgent.has(r.agent))
|
|
79
|
+
byAgent.set(r.agent, []);
|
|
80
|
+
byAgent.get(r.agent).push(r);
|
|
81
|
+
}
|
|
82
|
+
const agents = [...byAgent.entries()]
|
|
83
|
+
.sort(([a], [b]) => a.localeCompare(b))
|
|
84
|
+
.map(([agent, agentRecords]) => {
|
|
85
|
+
const derived = deriveExtra(agent, agentRecords);
|
|
86
|
+
// Cost has to be computed per-record (each may carry a different
|
|
87
|
+
// model string) then summed — a bucket-level aggregate token
|
|
88
|
+
// count alone can't be priced correctly once multiple models are
|
|
89
|
+
// mixed together.
|
|
90
|
+
let estimatedCostUsd;
|
|
91
|
+
if (pricing) {
|
|
92
|
+
for (const r of agentRecords) {
|
|
93
|
+
if (!r.model)
|
|
94
|
+
continue;
|
|
95
|
+
const cost = estimateCost(r.model, r.usage?.inputTokens ?? 0, r.usage?.outputTokens ?? 0, pricing);
|
|
96
|
+
if (cost !== undefined)
|
|
97
|
+
estimatedCostUsd = (estimatedCostUsd ?? 0) + cost;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return {
|
|
101
|
+
agent,
|
|
102
|
+
invocations: agentRecords.length,
|
|
103
|
+
inputTokens: sum(agentRecords, (r) => r.usage?.inputTokens ?? 0),
|
|
104
|
+
outputTokens: sum(agentRecords, (r) => r.usage?.outputTokens ?? 0),
|
|
105
|
+
cacheWriteTokens: sum(agentRecords, (r) => r.usage?.cacheWriteTokens ?? 0),
|
|
106
|
+
cacheReadTokens: sum(agentRecords, (r) => r.usage?.cacheReadTokens ?? 0),
|
|
107
|
+
totalDurationMillis: sum(agentRecords, (r) => r.durationMillis),
|
|
108
|
+
derivedCount: derived?.count,
|
|
109
|
+
derivedLabel: derived?.label,
|
|
110
|
+
estimatedCostUsd,
|
|
111
|
+
};
|
|
112
|
+
});
|
|
113
|
+
return { key, agents };
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=aggregate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"aggregate.js","sourceRoot":"","sources":["../../src/report/aggregate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Optional cost estimation — omitted entirely from the report when no
|
|
2
|
+
// pricing is configured, never a stale hardcoded price silently baked into
|
|
3
|
+
// the tool. Prices change; this file never guesses one.
|
|
4
|
+
import { readFile } from 'node:fs/promises';
|
|
5
|
+
export async function loadModelPricing(path) {
|
|
6
|
+
if (!path)
|
|
7
|
+
return undefined;
|
|
8
|
+
const text = await readFile(path, 'utf8');
|
|
9
|
+
return JSON.parse(text);
|
|
10
|
+
}
|
|
11
|
+
/** Looks up a model string against the pricing table — tries an exact match, then a substring match (a bucket's `model` field can be a combined "executor:X validator:Y" string). */
|
|
12
|
+
export function estimateCost(model, inputTokens, outputTokens, pricing) {
|
|
13
|
+
const entry = pricing[model] ?? Object.entries(pricing).find(([name]) => model.includes(name))?.[1];
|
|
14
|
+
if (!entry)
|
|
15
|
+
return undefined;
|
|
16
|
+
return (inputTokens / 1_000_000) * entry.inputPer1M + (outputTokens / 1_000_000) * entry.outputPer1M;
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=cost.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cost.js","sourceRoot":"","sources":["../../src/report/cost.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,2EAA2E;AAC3E,wDAAwD;AAExD,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAS5C,MAAM,CAAC,KAAK,UAAU,gBAAgB,CAAC,IAAwB;IAC7D,IAAI,CAAC,IAAI;QAAE,OAAO,SAAS,CAAC;IAC5B,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC1C,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAiB,CAAC;AAC1C,CAAC;AAED,qLAAqL;AACrL,MAAM,UAAU,YAAY,CAAC,KAAa,EAAE,WAAmB,EAAE,YAAoB,EAAE,OAAqB;IAC1G,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IACpG,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAC;IAC7B,OAAO,CAAC,WAAW,GAAG,SAAS,CAAC,GAAG,KAAK,CAAC,UAAU,GAAG,CAAC,YAAY,GAAG,SAAS,CAAC,GAAG,KAAK,CAAC,WAAW,CAAC;AACvG,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
// Read-side counterpart to @appliqation/agent-core's audit/sink.ts write-side
|
|
2
|
+
// sinks — same two backends (Mongo, JSONL file), same precedence. Unlike
|
|
3
|
+
// resolveAuditSink() (whose whole point is to no-op safely when
|
|
4
|
+
// unconfigured, since every consuming agent's audit logging is optional),
|
|
5
|
+
// resolveQuerySource() throws when neither is configured: reporting is this
|
|
6
|
+
// tool's entire purpose, so a silent empty report would be misleading —
|
|
7
|
+
// better a clear "nothing configured" error than a report that looks like
|
|
8
|
+
// "zero runs happened."
|
|
9
|
+
import { MongoClient } from 'mongodb';
|
|
10
|
+
import { readFile } from 'node:fs/promises';
|
|
11
|
+
export function createMongoQuerySource(opts) {
|
|
12
|
+
return {
|
|
13
|
+
async queryRecords({ since, until }) {
|
|
14
|
+
const client = new MongoClient(opts.uri);
|
|
15
|
+
try {
|
|
16
|
+
await client.connect();
|
|
17
|
+
const collection = client.db(opts.dbName).collection(opts.collection);
|
|
18
|
+
return await collection.find({ startedAt: { $gte: since.getTime(), $lte: until.getTime() } }).toArray();
|
|
19
|
+
}
|
|
20
|
+
finally {
|
|
21
|
+
await client.close();
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export function createJsonlQuerySource(opts) {
|
|
27
|
+
return {
|
|
28
|
+
async queryRecords({ since, until }) {
|
|
29
|
+
const text = await readFile(opts.filePath, 'utf8');
|
|
30
|
+
const sinceMs = since.getTime();
|
|
31
|
+
const untilMs = until.getTime();
|
|
32
|
+
return text
|
|
33
|
+
.split('\n')
|
|
34
|
+
.filter((line) => line.trim().length > 0)
|
|
35
|
+
.map((line) => JSON.parse(line))
|
|
36
|
+
.filter((r) => r.startedAt >= sinceMs && r.startedAt <= untilMs);
|
|
37
|
+
},
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export function resolveQuerySource(env) {
|
|
41
|
+
if (env.auditMongoUri) {
|
|
42
|
+
if (!env.auditMongoDb || !env.auditMongoCollection) {
|
|
43
|
+
throw new Error('AUDIT_MONGO_URI is set but AUDIT_MONGO_DB/AUDIT_MONGO_COLLECTION are missing — no collection-name fallback.');
|
|
44
|
+
}
|
|
45
|
+
return createMongoQuerySource({ uri: env.auditMongoUri, dbName: env.auditMongoDb, collection: env.auditMongoCollection });
|
|
46
|
+
}
|
|
47
|
+
if (env.auditJsonlPath)
|
|
48
|
+
return createJsonlQuerySource({ filePath: env.auditJsonlPath });
|
|
49
|
+
throw new Error('No audit store configured — set AUDIT_MONGO_URI (+ AUDIT_MONGO_DB/AUDIT_MONGO_COLLECTION) or AUDIT_JSONL_PATH. ' +
|
|
50
|
+
'This must point at the same store the agent family\'s own CLIs were configured to write to.');
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=auditStore.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auditStore.js","sourceRoot":"","sources":["../../src/store/auditStore.ts"],"names":[],"mappings":"AAAA,8EAA8E;AAC9E,yEAAyE;AACzE,gEAAgE;AAChE,0EAA0E;AAC1E,4EAA4E;AAC5E,wEAAwE;AACxE,0EAA0E;AAC1E,wBAAwB;AAExB,OAAO,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAO5C,MAAM,UAAU,sBAAsB,CAAC,IAAyD;IAC9F,OAAO;QACL,KAAK,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE;YACjC,MAAM,MAAM,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACzC,IAAI,CAAC;gBACH,MAAM,MAAM,CAAC,OAAO,EAAE,CAAC;gBACvB,MAAM,UAAU,GAAG,MAAM,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,UAAU,CAAc,IAAI,CAAC,UAAU,CAAC,CAAC;gBACnF,OAAO,MAAM,UAAU,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,EAAE,IAAI,EAAE,KAAK,CAAC,OAAO,EAAE,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC;YAC1G,CAAC;oBAAS,CAAC;gBACT,MAAM,MAAM,CAAC,KAAK,EAAE,CAAC;YACvB,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,IAA0B;IAC/D,OAAO;QACL,KAAK,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE;YACjC,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;YACnD,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC;YAChC,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC;YAChC,OAAO,IAAI;iBACR,KAAK,CAAC,IAAI,CAAC;iBACX,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,CAAC;iBACxC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAgB,CAAC;iBAC9C,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS,IAAI,OAAO,IAAI,CAAC,CAAC,SAAS,IAAI,OAAO,CAAC,CAAC;QACrE,CAAC;KACF,CAAC;AACJ,CAAC;AASD,MAAM,UAAU,kBAAkB,CAAC,GAAmB;IACpD,IAAI,GAAG,CAAC,aAAa,EAAE,CAAC;QACtB,IAAI,CAAC,GAAG,CAAC,YAAY,IAAI,CAAC,GAAG,CAAC,oBAAoB,EAAE,CAAC;YACnD,MAAM,IAAI,KAAK,CAAC,6GAA6G,CAAC,CAAC;QACjI,CAAC;QACD,OAAO,sBAAsB,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,CAAC,YAAY,EAAE,UAAU,EAAE,GAAG,CAAC,oBAAoB,EAAE,CAAC,CAAC;IAC5H,CAAC;IACD,IAAI,GAAG,CAAC,cAAc;QAAE,OAAO,sBAAsB,CAAC,EAAE,QAAQ,EAAE,GAAG,CAAC,cAAc,EAAE,CAAC,CAAC;IACxF,MAAM,IAAI,KAAK,CACb,iHAAiH;QAC/G,6FAA6F,CAChG,CAAC;AACJ,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@appliqation/dashboard",
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Read-only reporting CLI for the Appliqation agent family's audit trail \u2014 how much testing the agentic system did, and how many tokens it used, over a period.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"appliqation-dashboard": "./dist/cli/index.js"
|
|
8
|
+
},
|
|
9
|
+
"engines": {
|
|
10
|
+
"node": ">=20"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist/",
|
|
14
|
+
"README.md",
|
|
15
|
+
"LICENSE"
|
|
16
|
+
],
|
|
17
|
+
"scripts": {
|
|
18
|
+
"build": "tsc -p tsconfig.build.json",
|
|
19
|
+
"dev": "tsx src/cli/index.ts",
|
|
20
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
21
|
+
"lint": "eslint src --ext .ts",
|
|
22
|
+
"test": "vitest run",
|
|
23
|
+
"test:watch": "vitest"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@appliqation/agent-core": "^0.1.0",
|
|
27
|
+
"commander": "^13.1.0",
|
|
28
|
+
"dotenv": "^16.4.7",
|
|
29
|
+
"mongodb": "^6.10.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^22.13.10",
|
|
33
|
+
"tsx": "^4.19.3",
|
|
34
|
+
"typescript": "^5.8.2",
|
|
35
|
+
"vitest": "^3.2.7"
|
|
36
|
+
}
|
|
37
|
+
}
|