@lumenflow/cli 3.9.8 → 3.10.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.
@@ -0,0 +1,111 @@
1
+ #!/usr/bin/env node
2
+ // Copyright (c) 2026 Hellmai Ltd
3
+ // SPDX-License-Identifier: AGPL-3.0-only
4
+ import { existsSync, readFileSync } from 'node:fs';
5
+ import { join } from 'node:path';
6
+ import { Command } from 'commander';
7
+ import { createHttpControlPlaneSyncPort, parseWorkspaceControlPlaneConfig, } from '@lumenflow/control-plane-sdk';
8
+ import { CONFIG_FILES } from '@lumenflow/core/wu-constants';
9
+ import { parseYAML } from '@lumenflow/core/wu-yaml';
10
+ import { runCLI } from './cli-entry-point.js';
11
+ const LOG_PREFIX = '[approval:list]';
12
+ const WORKSPACE_PATH = CONFIG_FILES.WORKSPACE_CONFIG;
13
+ const STATUS_VALUES = new Set(['pending', 'approved', 'rejected', 'expired']);
14
+ function parseOptions(argv = process.argv) {
15
+ const program = new Command()
16
+ .name('approval-list')
17
+ .description('List approvals from the configured control-plane')
18
+ .option('--status <status>', 'Filter by status: pending, approved, rejected, expired')
19
+ .option('--type <type>', 'Filter by approval type')
20
+ .option('--limit <count>', 'Maximum approvals to return')
21
+ .option('--workspace-id <id>', 'Override workspace_id from workspace.yaml')
22
+ .option('--json', 'Output JSON response', false)
23
+ .exitOverride();
24
+ try {
25
+ program.parse(argv);
26
+ }
27
+ catch (error) {
28
+ const commanderError = error;
29
+ if (commanderError.code === 'commander.helpDisplayed' ||
30
+ commanderError.code === 'commander.version') {
31
+ process.exit(0);
32
+ }
33
+ throw error;
34
+ }
35
+ const parsed = program.opts();
36
+ const statusRaw = parsed.status?.trim();
37
+ const status = statusRaw;
38
+ if (statusRaw && !STATUS_VALUES.has(status)) {
39
+ throw new Error(`Invalid --status: ${statusRaw}`);
40
+ }
41
+ let limit;
42
+ if (parsed.limit) {
43
+ const parsedLimit = Number.parseInt(parsed.limit, 10);
44
+ if (!Number.isInteger(parsedLimit) || parsedLimit <= 0) {
45
+ throw new Error(`Invalid --limit: ${parsed.limit}`);
46
+ }
47
+ limit = parsedLimit;
48
+ }
49
+ return {
50
+ status,
51
+ type: parsed.type?.trim(),
52
+ limit,
53
+ workspaceId: parsed.workspaceId?.trim(),
54
+ json: parsed.json ?? false,
55
+ };
56
+ }
57
+ function resolveApprovalContext(workspaceRoot, environment, workspaceIdOverride) {
58
+ const workspaceFilePath = join(workspaceRoot, WORKSPACE_PATH);
59
+ if (!existsSync(workspaceFilePath)) {
60
+ throw new Error(`Missing workspace config: ${workspaceFilePath}`);
61
+ }
62
+ const workspaceDocument = parseYAML(readFileSync(workspaceFilePath, 'utf-8'));
63
+ const parsed = parseWorkspaceControlPlaneConfig(workspaceDocument);
64
+ const workspaceId = workspaceIdOverride ?? parsed.id;
65
+ if (!workspaceId) {
66
+ throw new Error('workspace.yaml must include id or pass --workspace-id');
67
+ }
68
+ return {
69
+ workspaceId,
70
+ syncPort: createHttpControlPlaneSyncPort(parsed.control_plane, undefined, {
71
+ environment,
72
+ }),
73
+ };
74
+ }
75
+ function formatListResult(result) {
76
+ const lines = [];
77
+ lines.push(`${LOG_PREFIX} ${result.approvals.length} approval(s)`);
78
+ for (const approval of result.approvals) {
79
+ lines.push(`- ${approval.approval_id} [${approval.status}] ${approval.type}`);
80
+ }
81
+ if (result.next_cursor) {
82
+ lines.push(`${LOG_PREFIX} next_cursor=${result.next_cursor}`);
83
+ }
84
+ return lines.join('\n');
85
+ }
86
+ export async function runApprovalList(options, input = {}) {
87
+ const { workspaceId, syncPort } = resolveApprovalContext(input.workspaceRoot ?? process.cwd(), input.environment ?? process.env, options.workspaceId);
88
+ if (!syncPort.listApprovals) {
89
+ throw new Error('Control-plane adapter does not support listApprovals');
90
+ }
91
+ const payload = {
92
+ workspace_id: workspaceId,
93
+ ...(options.status ? { status: options.status } : {}),
94
+ ...(options.type ? { type: options.type } : {}),
95
+ ...(options.limit ? { limit: options.limit } : {}),
96
+ };
97
+ return syncPort.listApprovals(payload);
98
+ }
99
+ export async function main(argv = process.argv) {
100
+ const options = parseOptions(argv);
101
+ const result = await runApprovalList(options);
102
+ if (options.json) {
103
+ console.log(JSON.stringify(result, null, 2));
104
+ return;
105
+ }
106
+ console.log(formatListResult(result));
107
+ }
108
+ if (import.meta.main) {
109
+ void runCLI(main);
110
+ }
111
+ //# sourceMappingURL=approval-list.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval-list.js","sourceRoot":"","sources":["../src/approval-list.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,121 @@
1
+ #!/usr/bin/env node
2
+ // Copyright (c) 2026 Hellmai Ltd
3
+ // SPDX-License-Identifier: AGPL-3.0-only
4
+ import { existsSync, readFileSync } from 'node:fs';
5
+ import { join } from 'node:path';
6
+ import { Command } from 'commander';
7
+ import { createHttpControlPlaneSyncPort, parseWorkspaceControlPlaneConfig, } from '@lumenflow/control-plane-sdk';
8
+ import { CONFIG_FILES } from '@lumenflow/core/wu-constants';
9
+ import { parseYAML } from '@lumenflow/core/wu-yaml';
10
+ import { runCLI } from './cli-entry-point.js';
11
+ const LOG_PREFIX = '[approval:request]';
12
+ const WORKSPACE_PATH = CONFIG_FILES.WORKSPACE_CONFIG;
13
+ const DEFAULT_REQUESTER_TYPE = 'agent';
14
+ const REQUESTER_TYPE_VALUES = new Set(['agent', 'user']);
15
+ function asRecord(value) {
16
+ if (typeof value !== 'object' || value === null || Array.isArray(value)) {
17
+ throw new Error('Expected a JSON object payload');
18
+ }
19
+ return value;
20
+ }
21
+ function parseJsonRecord(value, label) {
22
+ try {
23
+ return asRecord(JSON.parse(value));
24
+ }
25
+ catch (error) {
26
+ const reason = error instanceof Error ? error.message : String(error);
27
+ throw new Error(`Invalid ${label}: ${reason}`, { cause: error });
28
+ }
29
+ }
30
+ function parseOptions(argv = process.argv) {
31
+ const program = new Command()
32
+ .name('approval-request')
33
+ .description('Request an approval from the configured control-plane')
34
+ .requiredOption('--type <type>', 'Approval type (for example: wu_assignment)')
35
+ .requiredOption('--subject <json>', 'JSON object describing the approval subject')
36
+ .option('--context <json>', 'Optional JSON object with additional context')
37
+ .option('--requester-id <id>', 'Requester identifier')
38
+ .option('--requester-type <type>', 'Requester type: agent or user', DEFAULT_REQUESTER_TYPE)
39
+ .option('--expires-at <iso>', 'Optional expiry timestamp (ISO-8601)')
40
+ .option('--workspace-id <id>', 'Override workspace_id from workspace.yaml')
41
+ .option('--json', 'Output JSON response', false)
42
+ .exitOverride();
43
+ try {
44
+ program.parse(argv);
45
+ }
46
+ catch (error) {
47
+ const commanderError = error;
48
+ if (commanderError.code === 'commander.helpDisplayed' ||
49
+ commanderError.code === 'commander.version') {
50
+ process.exit(0);
51
+ }
52
+ throw error;
53
+ }
54
+ const parsed = program.opts();
55
+ const requesterTypeRaw = (parsed.requesterType ?? DEFAULT_REQUESTER_TYPE).trim();
56
+ if (!REQUESTER_TYPE_VALUES.has(requesterTypeRaw)) {
57
+ throw new Error(`Invalid --requester-type: ${requesterTypeRaw}`);
58
+ }
59
+ return {
60
+ type: parsed.type.trim(),
61
+ subject: parsed.subject,
62
+ context: parsed.context,
63
+ requesterId: parsed.requesterId?.trim(),
64
+ requesterType: requesterTypeRaw,
65
+ expiresAt: parsed.expiresAt?.trim(),
66
+ workspaceId: parsed.workspaceId?.trim(),
67
+ json: parsed.json ?? false,
68
+ };
69
+ }
70
+ function resolveApprovalContext(workspaceRoot, environment, workspaceIdOverride) {
71
+ const workspaceFilePath = join(workspaceRoot, WORKSPACE_PATH);
72
+ if (!existsSync(workspaceFilePath)) {
73
+ throw new Error(`Missing workspace config: ${workspaceFilePath}`);
74
+ }
75
+ const workspaceDocument = parseYAML(readFileSync(workspaceFilePath, 'utf-8'));
76
+ const parsed = parseWorkspaceControlPlaneConfig(workspaceDocument);
77
+ const workspaceId = workspaceIdOverride ?? parsed.id;
78
+ if (!workspaceId) {
79
+ throw new Error('workspace.yaml must include id or pass --workspace-id');
80
+ }
81
+ return {
82
+ workspaceId,
83
+ syncPort: createHttpControlPlaneSyncPort(parsed.control_plane, undefined, {
84
+ environment,
85
+ }),
86
+ };
87
+ }
88
+ function formatResultLine(result) {
89
+ return `${LOG_PREFIX} Created ${result.approval_id} (${result.status}) for type ${result.type}`;
90
+ }
91
+ export async function runApprovalRequest(options, input = {}) {
92
+ const subject = parseJsonRecord(options.subject, '--subject');
93
+ const context = options.context ? parseJsonRecord(options.context, '--context') : undefined;
94
+ const { workspaceId, syncPort } = resolveApprovalContext(input.workspaceRoot ?? process.cwd(), input.environment ?? process.env, options.workspaceId);
95
+ if (!syncPort.requestApproval) {
96
+ throw new Error('Control-plane adapter does not support requestApproval');
97
+ }
98
+ const payload = {
99
+ workspace_id: workspaceId,
100
+ type: options.type,
101
+ subject,
102
+ requester_type: options.requesterType,
103
+ ...(options.requesterId ? { requester_id: options.requesterId } : {}),
104
+ ...(options.expiresAt ? { expires_at: options.expiresAt } : {}),
105
+ ...(context ? { context } : {}),
106
+ };
107
+ return syncPort.requestApproval(payload);
108
+ }
109
+ export async function main(argv = process.argv) {
110
+ const options = parseOptions(argv);
111
+ const result = (await runApprovalRequest(options));
112
+ if (options.json) {
113
+ console.log(JSON.stringify(result, null, 2));
114
+ return;
115
+ }
116
+ console.log(formatResultLine(result));
117
+ }
118
+ if (import.meta.main) {
119
+ void runCLI(main);
120
+ }
121
+ //# sourceMappingURL=approval-request.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval-request.js","sourceRoot":"","sources":["../src/approval-request.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,107 @@
1
+ #!/usr/bin/env node
2
+ // Copyright (c) 2026 Hellmai Ltd
3
+ // SPDX-License-Identifier: AGPL-3.0-only
4
+ import { existsSync, readFileSync } from 'node:fs';
5
+ import { join } from 'node:path';
6
+ import { Command } from 'commander';
7
+ import { createHttpControlPlaneSyncPort, parseWorkspaceControlPlaneConfig, } from '@lumenflow/control-plane-sdk';
8
+ import { CONFIG_FILES } from '@lumenflow/core/wu-constants';
9
+ import { parseYAML } from '@lumenflow/core/wu-yaml';
10
+ import { runCLI } from './cli-entry-point.js';
11
+ const LOG_PREFIX = '[approval:review]';
12
+ const WORKSPACE_PATH = CONFIG_FILES.WORKSPACE_CONFIG;
13
+ const DEFAULT_REVIEWER_TYPE = 'user';
14
+ const REVIEWER_TYPE_VALUES = new Set(['agent', 'user']);
15
+ const DECISION_VALUES = new Set(['approved', 'rejected', 'expired']);
16
+ function parseOptions(argv = process.argv) {
17
+ const program = new Command()
18
+ .name('approval-review')
19
+ .description('Resolve a pending approval in the configured control-plane')
20
+ .requiredOption('--id <approvalId>', 'Approval identifier')
21
+ .requiredOption('--decision <decision>', 'Decision: approved, rejected, or expired')
22
+ .option('--reason <reason>', 'Optional decision reason')
23
+ .option('--reviewer-id <id>', 'Reviewer identifier')
24
+ .option('--reviewer-type <type>', 'Reviewer type: agent or user', DEFAULT_REVIEWER_TYPE)
25
+ .option('--workspace-id <id>', 'Override workspace_id from workspace.yaml')
26
+ .option('--json', 'Output JSON response', false)
27
+ .exitOverride();
28
+ try {
29
+ program.parse(argv);
30
+ }
31
+ catch (error) {
32
+ const commanderError = error;
33
+ if (commanderError.code === 'commander.helpDisplayed' ||
34
+ commanderError.code === 'commander.version') {
35
+ process.exit(0);
36
+ }
37
+ throw error;
38
+ }
39
+ const parsed = program.opts();
40
+ const decision = parsed.decision.trim();
41
+ if (!DECISION_VALUES.has(decision)) {
42
+ throw new Error(`Invalid --decision: ${parsed.decision}`);
43
+ }
44
+ const reviewerTypeRaw = (parsed.reviewerType ?? DEFAULT_REVIEWER_TYPE).trim();
45
+ if (!REVIEWER_TYPE_VALUES.has(reviewerTypeRaw)) {
46
+ throw new Error(`Invalid --reviewer-type: ${reviewerTypeRaw}`);
47
+ }
48
+ return {
49
+ approvalId: parsed.id.trim(),
50
+ decision,
51
+ reason: parsed.reason?.trim(),
52
+ reviewerId: parsed.reviewerId?.trim(),
53
+ reviewerType: reviewerTypeRaw,
54
+ workspaceId: parsed.workspaceId?.trim(),
55
+ json: parsed.json ?? false,
56
+ };
57
+ }
58
+ function resolveApprovalContext(workspaceRoot, environment, workspaceIdOverride) {
59
+ const workspaceFilePath = join(workspaceRoot, WORKSPACE_PATH);
60
+ if (!existsSync(workspaceFilePath)) {
61
+ throw new Error(`Missing workspace config: ${workspaceFilePath}`);
62
+ }
63
+ const workspaceDocument = parseYAML(readFileSync(workspaceFilePath, 'utf-8'));
64
+ const parsed = parseWorkspaceControlPlaneConfig(workspaceDocument);
65
+ const workspaceId = workspaceIdOverride ?? parsed.id;
66
+ if (!workspaceId) {
67
+ throw new Error('workspace.yaml must include id or pass --workspace-id');
68
+ }
69
+ return {
70
+ workspaceId,
71
+ syncPort: createHttpControlPlaneSyncPort(parsed.control_plane, undefined, {
72
+ environment,
73
+ }),
74
+ };
75
+ }
76
+ function formatResultLine(result) {
77
+ const reasonSuffix = result.decision_reason ? ` (${result.decision_reason})` : '';
78
+ return `${LOG_PREFIX} Updated ${result.approval_id} -> ${result.status}${reasonSuffix}`;
79
+ }
80
+ export async function runApprovalReview(options, input = {}) {
81
+ const { workspaceId, syncPort } = resolveApprovalContext(input.workspaceRoot ?? process.cwd(), input.environment ?? process.env, options.workspaceId);
82
+ if (!syncPort.resolveApproval) {
83
+ throw new Error('Control-plane adapter does not support resolveApproval');
84
+ }
85
+ const payload = {
86
+ workspace_id: workspaceId,
87
+ approval_id: options.approvalId,
88
+ decision: options.decision,
89
+ reviewer_type: options.reviewerType,
90
+ ...(options.reason ? { reason: options.reason } : {}),
91
+ ...(options.reviewerId ? { reviewer_id: options.reviewerId } : {}),
92
+ };
93
+ return syncPort.resolveApproval(payload);
94
+ }
95
+ export async function main(argv = process.argv) {
96
+ const options = parseOptions(argv);
97
+ const result = (await runApprovalReview(options));
98
+ if (options.json) {
99
+ console.log(JSON.stringify(result, null, 2));
100
+ return;
101
+ }
102
+ console.log(formatResultLine(result));
103
+ }
104
+ if (import.meta.main) {
105
+ void runCLI(main);
106
+ }
107
+ //# sourceMappingURL=approval-review.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval-review.js","sourceRoot":"","sources":["../src/approval-review.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,181 @@
1
+ #!/usr/bin/env node
2
+ // Copyright (c) 2026 Hellmai Ltd
3
+ // SPDX-License-Identifier: AGPL-3.0-only
4
+ import { existsSync, readFileSync } from 'node:fs';
5
+ import { Command } from 'commander';
6
+ import { runCLI } from './cli-entry-point.js';
7
+ const DEFAULT_COSTS_PATH = '.lumenflow/telemetry/costs.ndjson';
8
+ const DEFAULT_GROUP_KEY = 'unknown';
9
+ const LOG_PREFIX = '[cost:summary]';
10
+ const SOURCE_TYPE_COST = 'cost';
11
+ function asNonEmptyString(value) {
12
+ if (typeof value !== 'string')
13
+ return undefined;
14
+ const trimmed = value.trim();
15
+ return trimmed.length > 0 ? trimmed : undefined;
16
+ }
17
+ function asFiniteNumber(value) {
18
+ return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
19
+ }
20
+ export function parseCostEventLine(line) {
21
+ const trimmed = line.trim();
22
+ if (trimmed.length === 0) {
23
+ return null;
24
+ }
25
+ let parsed;
26
+ try {
27
+ parsed = JSON.parse(trimmed);
28
+ }
29
+ catch {
30
+ return null;
31
+ }
32
+ if (typeof parsed !== 'object' || parsed === null) {
33
+ return null;
34
+ }
35
+ const record = parsed;
36
+ const sourceTypeRaw = asNonEmptyString(record.source_type);
37
+ const timestamp = asNonEmptyString(record.timestamp);
38
+ const operation = asNonEmptyString(record.operation);
39
+ const model = asNonEmptyString(record.model);
40
+ const inputTokens = asFiniteNumber(record.input_tokens);
41
+ const outputTokens = asFiniteNumber(record.output_tokens);
42
+ const costUsd = asFiniteNumber(record.cost_usd);
43
+ if (!timestamp || !operation || !model) {
44
+ return null;
45
+ }
46
+ if (inputTokens === undefined || outputTokens === undefined || costUsd === undefined) {
47
+ return null;
48
+ }
49
+ if (sourceTypeRaw !== undefined && sourceTypeRaw !== SOURCE_TYPE_COST) {
50
+ return null;
51
+ }
52
+ return {
53
+ timestamp,
54
+ sourceType: SOURCE_TYPE_COST,
55
+ operation,
56
+ model,
57
+ inputTokens,
58
+ outputTokens,
59
+ costUsd,
60
+ wuId: asNonEmptyString(record.wu_id),
61
+ agentId: asNonEmptyString(record.agent_id),
62
+ sessionId: asNonEmptyString(record.session_id),
63
+ };
64
+ }
65
+ export function readCostEvents(costsPath = DEFAULT_COSTS_PATH) {
66
+ if (!existsSync(costsPath)) {
67
+ return [];
68
+ }
69
+ const content = readFileSync(costsPath, 'utf-8');
70
+ return content
71
+ .split('\n')
72
+ .map((line) => parseCostEventLine(line))
73
+ .filter((event) => event !== null);
74
+ }
75
+ function sortRowsDescending(rows) {
76
+ return [...rows].sort((a, b) => b.costUsd - a.costUsd || b.eventCount - a.eventCount);
77
+ }
78
+ function buildGroupedRows(events, keySelector) {
79
+ const byKey = new Map();
80
+ for (const event of events) {
81
+ const key = keySelector(event) ?? DEFAULT_GROUP_KEY;
82
+ const current = byKey.get(key) ?? {
83
+ key,
84
+ costUsd: 0,
85
+ inputTokens: 0,
86
+ outputTokens: 0,
87
+ eventCount: 0,
88
+ };
89
+ current.costUsd += event.costUsd;
90
+ current.inputTokens += event.inputTokens;
91
+ current.outputTokens += event.outputTokens;
92
+ current.eventCount += 1;
93
+ byKey.set(key, current);
94
+ }
95
+ return sortRowsDescending(Array.from(byKey.values()));
96
+ }
97
+ export function summarizeCostEvents(events) {
98
+ const summary = {
99
+ totalCostUsd: 0,
100
+ totalInputTokens: 0,
101
+ totalOutputTokens: 0,
102
+ eventCount: 0,
103
+ byModel: buildGroupedRows(events, (event) => event.model),
104
+ byAgent: buildGroupedRows(events, (event) => event.agentId),
105
+ byWu: buildGroupedRows(events, (event) => event.wuId),
106
+ };
107
+ for (const event of events) {
108
+ summary.totalCostUsd += event.costUsd;
109
+ summary.totalInputTokens += event.inputTokens;
110
+ summary.totalOutputTokens += event.outputTokens;
111
+ summary.eventCount += 1;
112
+ }
113
+ return summary;
114
+ }
115
+ function formatRows(title, rows) {
116
+ const lines = [];
117
+ lines.push(title);
118
+ if (rows.length === 0) {
119
+ lines.push(' (none)');
120
+ return lines;
121
+ }
122
+ for (const row of rows) {
123
+ lines.push(` - ${row.key}: $${row.costUsd.toFixed(6)} (${row.eventCount} events, in=${row.inputTokens}, out=${row.outputTokens})`);
124
+ }
125
+ return lines;
126
+ }
127
+ export function formatCostSummary(summary) {
128
+ const lines = [];
129
+ lines.push('Cost Summary');
130
+ lines.push(` Events: ${summary.eventCount}`);
131
+ lines.push(` Total Cost (USD): $${summary.totalCostUsd.toFixed(6)}`);
132
+ lines.push(` Total Input Tokens: ${summary.totalInputTokens}`);
133
+ lines.push(` Total Output Tokens: ${summary.totalOutputTokens}`);
134
+ lines.push('');
135
+ lines.push(...formatRows('By Model:', summary.byModel));
136
+ lines.push('');
137
+ lines.push(...formatRows('By Agent:', summary.byAgent));
138
+ lines.push('');
139
+ lines.push(...formatRows('By WU:', summary.byWu));
140
+ return lines.join('\n');
141
+ }
142
+ function parseArgs() {
143
+ const program = new Command()
144
+ .name('cost-summary')
145
+ .description('Summarize local cost telemetry from .lumenflow/telemetry/costs.ndjson')
146
+ .option('--json', 'Output JSON instead of human-readable text', false)
147
+ .option('--path <path>', `Path to costs NDJSON file (default: ${DEFAULT_COSTS_PATH})`)
148
+ .exitOverride();
149
+ try {
150
+ program.parse(process.argv);
151
+ }
152
+ catch (err) {
153
+ const error = err;
154
+ if (error.code === 'commander.helpDisplayed' || error.code === 'commander.version') {
155
+ process.exit(0);
156
+ }
157
+ throw err;
158
+ }
159
+ const options = program.opts();
160
+ return {
161
+ json: options.json ?? false,
162
+ path: options.path ?? DEFAULT_COSTS_PATH,
163
+ };
164
+ }
165
+ export async function main() {
166
+ const options = parseArgs();
167
+ const events = readCostEvents(options.path);
168
+ const summary = summarizeCostEvents(events);
169
+ if (events.length === 0) {
170
+ console.log(`${LOG_PREFIX} No cost telemetry found at ${options.path}`);
171
+ }
172
+ if (options.json) {
173
+ console.log(JSON.stringify(summary, null, 2));
174
+ return;
175
+ }
176
+ console.log(formatCostSummary(summary));
177
+ }
178
+ if (import.meta.main) {
179
+ void runCLI(main);
180
+ }
181
+ //# sourceMappingURL=cost-summary.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cost-summary.js","sourceRoot":"","sources":["../src/cost-summary.ts"],"names":[],"mappings":"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"}