@moneysiren/cli 0.1.0-alpha.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/LICENSE +21 -0
- package/README.md +155 -0
- package/dist/apps/cli/src/cli.d.ts +56 -0
- package/dist/apps/cli/src/cli.js +182 -0
- package/dist/apps/cli/src/commands/dashboard.d.ts +3 -0
- package/dist/apps/cli/src/commands/dashboard.js +239 -0
- package/dist/apps/cli/src/commands/doctor.d.ts +3 -0
- package/dist/apps/cli/src/commands/doctor.js +25 -0
- package/dist/apps/cli/src/commands/init.d.ts +3 -0
- package/dist/apps/cli/src/commands/init.js +18 -0
- package/dist/apps/cli/src/commands/install.d.ts +3 -0
- package/dist/apps/cli/src/commands/install.js +116 -0
- package/dist/apps/cli/src/commands/modes.d.ts +3 -0
- package/dist/apps/cli/src/commands/modes.js +65 -0
- package/dist/apps/cli/src/commands/notify.d.ts +3 -0
- package/dist/apps/cli/src/commands/notify.js +430 -0
- package/dist/apps/cli/src/commands/report.d.ts +3 -0
- package/dist/apps/cli/src/commands/report.js +206 -0
- package/dist/apps/cli/src/commands/runtime.d.ts +5 -0
- package/dist/apps/cli/src/commands/runtime.js +133 -0
- package/dist/apps/cli/src/commands/shared.d.ts +9 -0
- package/dist/apps/cli/src/commands/shared.js +29 -0
- package/dist/apps/cli/src/commands/summary.d.ts +3 -0
- package/dist/apps/cli/src/commands/summary.js +15 -0
- package/dist/apps/cli/src/commands/sync.d.ts +3 -0
- package/dist/apps/cli/src/commands/sync.js +393 -0
- package/dist/apps/cli/src/commands/theme.d.ts +3 -0
- package/dist/apps/cli/src/commands/theme.js +181 -0
- package/dist/apps/cli/src/home.d.ts +7 -0
- package/dist/apps/cli/src/home.js +97 -0
- package/dist/apps/cli/src/index.d.ts +3 -0
- package/dist/apps/cli/src/index.js +14 -0
- package/dist/apps/cli/src/install-profile.d.ts +35 -0
- package/dist/apps/cli/src/install-profile.js +124 -0
- package/dist/apps/cli/src/install-selector.d.ts +10 -0
- package/dist/apps/cli/src/install-selector.js +66 -0
- package/dist/apps/cli/src/interactive.d.ts +3 -0
- package/dist/apps/cli/src/interactive.js +32 -0
- package/dist/apps/cli/src/postinstall.d.ts +3 -0
- package/dist/apps/cli/src/postinstall.js +42 -0
- package/dist/apps/cli/src/runtime-adapter.d.ts +24 -0
- package/dist/apps/cli/src/runtime-adapter.js +185 -0
- package/dist/apps/cli/src/slash.d.ts +15 -0
- package/dist/apps/cli/src/slash.js +202 -0
- package/dist/apps/cli/src/summary-model.d.ts +51 -0
- package/dist/apps/cli/src/summary-model.js +136 -0
- package/dist/apps/cli/src/theme.d.ts +18 -0
- package/dist/apps/cli/src/theme.js +118 -0
- package/dist/packages/config/src/index.d.ts +3 -0
- package/dist/packages/config/src/index.js +3 -0
- package/dist/packages/config/src/load.d.ts +3 -0
- package/dist/packages/config/src/load.js +77 -0
- package/dist/packages/config/src/schema.d.ts +46 -0
- package/dist/packages/config/src/schema.js +25 -0
- package/dist/packages/connectors/aws/src/cost-explorer.d.ts +34 -0
- package/dist/packages/connectors/aws/src/cost-explorer.js +43 -0
- package/dist/packages/connectors/aws/src/index.d.ts +35 -0
- package/dist/packages/connectors/aws/src/index.js +67 -0
- package/dist/packages/connectors/aws/src/normalize.d.ts +69 -0
- package/dist/packages/connectors/aws/src/normalize.js +141 -0
- package/dist/packages/connectors/aws/src/sdk-client.d.ts +6 -0
- package/dist/packages/connectors/aws/src/sdk-client.js +21 -0
- package/dist/packages/connectors/cloudflare/src/client.d.ts +23 -0
- package/dist/packages/connectors/cloudflare/src/client.js +107 -0
- package/dist/packages/connectors/cloudflare/src/index.d.ts +33 -0
- package/dist/packages/connectors/cloudflare/src/index.js +81 -0
- package/dist/packages/connectors/cloudflare/src/normalize.d.ts +113 -0
- package/dist/packages/connectors/cloudflare/src/normalize.js +288 -0
- package/dist/packages/connectors/mock/src/index.d.ts +58 -0
- package/dist/packages/connectors/mock/src/index.js +66 -0
- package/dist/packages/connectors/openai/src/index.d.ts +55 -0
- package/dist/packages/connectors/openai/src/index.js +169 -0
- package/dist/packages/connectors/openai/src/normalize.d.ts +91 -0
- package/dist/packages/connectors/openai/src/normalize.js +180 -0
- package/dist/packages/connectors/supabase/src/client.d.ts +22 -0
- package/dist/packages/connectors/supabase/src/client.js +132 -0
- package/dist/packages/connectors/supabase/src/index.d.ts +33 -0
- package/dist/packages/connectors/supabase/src/index.js +87 -0
- package/dist/packages/connectors/supabase/src/normalize.d.ts +106 -0
- package/dist/packages/connectors/supabase/src/normalize.js +266 -0
- package/dist/packages/core/src/collector.d.ts +12 -0
- package/dist/packages/core/src/collector.js +68 -0
- package/dist/packages/core/src/index.d.ts +5 -0
- package/dist/packages/core/src/index.js +4 -0
- package/dist/packages/core/src/provider.d.ts +18 -0
- package/dist/packages/core/src/provider.js +2 -0
- package/dist/packages/core/src/risk-engine.d.ts +9 -0
- package/dist/packages/core/src/risk-engine.js +4 -0
- package/dist/packages/core/src/snapshots.d.ts +49 -0
- package/dist/packages/core/src/snapshots.js +9 -0
- package/dist/packages/db/src/client.d.ts +11 -0
- package/dist/packages/db/src/client.js +14 -0
- package/dist/packages/db/src/index.d.ts +6 -0
- package/dist/packages/db/src/index.js +6 -0
- package/dist/packages/db/src/local-store.d.ts +161 -0
- package/dist/packages/db/src/local-store.js +623 -0
- package/dist/packages/db/src/migrate.d.ts +17 -0
- package/dist/packages/db/src/migrate.js +35 -0
- package/dist/packages/db/src/schema.d.ts +5 -0
- package/dist/packages/db/src/schema.js +120 -0
- package/dist/packages/db/src/sqlite-bin.d.ts +3 -0
- package/dist/packages/db/src/sqlite-bin.js +16 -0
- package/dist/packages/local-api/src/index.d.ts +2 -0
- package/dist/packages/local-api/src/index.js +2 -0
- package/dist/packages/local-api/src/server.d.ts +36 -0
- package/dist/packages/local-api/src/server.js +310 -0
- package/dist/packages/report/src/daily.d.ts +24 -0
- package/dist/packages/report/src/daily.js +9 -0
- package/dist/packages/report/src/index.d.ts +4 -0
- package/dist/packages/report/src/index.js +4 -0
- package/dist/packages/report/src/korean.d.ts +3 -0
- package/dist/packages/report/src/korean.js +62 -0
- package/dist/packages/report/src/slack.d.ts +34 -0
- package/dist/packages/report/src/slack.js +134 -0
- package/dist/packages/runtime/src/index.d.ts +2 -0
- package/dist/packages/runtime/src/index.js +2 -0
- package/dist/packages/runtime/src/runtime.d.ts +26 -0
- package/dist/packages/runtime/src/runtime.js +182 -0
- package/dist/packages/view-model/src/index.d.ts +3 -0
- package/dist/packages/view-model/src/index.js +3 -0
- package/dist/packages/view-model/src/notification-preferences-model.d.ts +47 -0
- package/dist/packages/view-model/src/notification-preferences-model.js +218 -0
- package/dist/packages/view-model/src/notification-preferences.d.ts +6 -0
- package/dist/packages/view-model/src/notification-preferences.js +36 -0
- package/dist/packages/view-model/src/view-model.d.ts +193 -0
- package/dist/packages/view-model/src/view-model.js +684 -0
- package/package.json +49 -0
- package/scripts/postinstall.mjs +11 -0
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { initializeLocalStore, readLocalStore, recordLocalReportRun, } from "../../../../packages/db/src/index.js";
|
|
2
|
+
import { renderDailyReport, sendSlackReport, } from "../../../../packages/report/src/index.js";
|
|
3
|
+
import { loadCliConfig, resolveDbPath } from "./shared.js";
|
|
4
|
+
const DAILY_REPORT_TIME_ZONE_ENV_KEY = "MONEYSIREN_REPORT_TIME_ZONE";
|
|
5
|
+
const DEFAULT_DAILY_REPORT_TIME_ZONE = "Asia/Seoul";
|
|
6
|
+
export async function runReportCommand(args, context) {
|
|
7
|
+
const parsedArgs = parseDailyReportArgs(args);
|
|
8
|
+
if (parsedArgs === undefined) {
|
|
9
|
+
context.stderr("Usage: moneysiren report daily --lang ko [--send slack]");
|
|
10
|
+
return 1;
|
|
11
|
+
}
|
|
12
|
+
const config = loadCliConfig(context.env);
|
|
13
|
+
const dbPath = resolveDbPath(context.cwd, config.dbPath);
|
|
14
|
+
await initializeLocalStore({ dbPath });
|
|
15
|
+
const now = context.now();
|
|
16
|
+
const generatedAt = now.toISOString();
|
|
17
|
+
const reportDate = formatDailyReportDate(now, resolveDailyReportTimeZone(context.env));
|
|
18
|
+
const store = await readLocalStore({ dbPath });
|
|
19
|
+
const reportInput = {
|
|
20
|
+
reportDate,
|
|
21
|
+
generatedAt,
|
|
22
|
+
providerSummaries: buildProviderSummaries(store),
|
|
23
|
+
reportRunStatus: parsedArgs.deliveryTarget === "slack" ? "sent" : "rendered",
|
|
24
|
+
};
|
|
25
|
+
if (parsedArgs.deliveryTarget === "slack") {
|
|
26
|
+
return sendDailyReportToSlack({
|
|
27
|
+
context,
|
|
28
|
+
dbPath,
|
|
29
|
+
reportDate,
|
|
30
|
+
generatedAt,
|
|
31
|
+
reportInput,
|
|
32
|
+
webhookEnvKey: config.slack.requiredEnvKey,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
await recordLocalReportRun({
|
|
36
|
+
dbPath,
|
|
37
|
+
createdAt: generatedAt,
|
|
38
|
+
reportDate,
|
|
39
|
+
language: "ko",
|
|
40
|
+
deliveryTarget: "stdout",
|
|
41
|
+
status: "rendered",
|
|
42
|
+
});
|
|
43
|
+
context.stdout(renderDailyReport(reportInput, { lang: "ko" }));
|
|
44
|
+
context.stdout("Report run recorded: stdout");
|
|
45
|
+
return 0;
|
|
46
|
+
}
|
|
47
|
+
function parseDailyReportArgs(args) {
|
|
48
|
+
const [reportKind, ...rest] = args;
|
|
49
|
+
if (reportKind !== "daily") {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
52
|
+
let lang;
|
|
53
|
+
let deliveryTarget = "stdout";
|
|
54
|
+
for (let index = 0; index < rest.length; index += 1) {
|
|
55
|
+
const arg = rest[index];
|
|
56
|
+
if (arg === "--lang") {
|
|
57
|
+
const value = rest[index + 1];
|
|
58
|
+
if (value === undefined) {
|
|
59
|
+
return undefined;
|
|
60
|
+
}
|
|
61
|
+
lang = value;
|
|
62
|
+
index += 1;
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
65
|
+
if (arg?.startsWith("--lang=")) {
|
|
66
|
+
lang = arg.slice("--lang=".length);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (arg === "--send") {
|
|
70
|
+
const value = rest[index + 1];
|
|
71
|
+
if (value !== "slack") {
|
|
72
|
+
return undefined;
|
|
73
|
+
}
|
|
74
|
+
deliveryTarget = "slack";
|
|
75
|
+
index += 1;
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
78
|
+
if (arg?.startsWith("--send=")) {
|
|
79
|
+
const value = arg.slice("--send=".length);
|
|
80
|
+
if (value !== "slack") {
|
|
81
|
+
return undefined;
|
|
82
|
+
}
|
|
83
|
+
deliveryTarget = "slack";
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
if (lang !== "ko") {
|
|
89
|
+
return undefined;
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
deliveryTarget,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function resolveDailyReportTimeZone(env) {
|
|
96
|
+
const configuredTimeZone = env[DAILY_REPORT_TIME_ZONE_ENV_KEY]?.trim();
|
|
97
|
+
return configuredTimeZone === undefined || configuredTimeZone.length === 0
|
|
98
|
+
? DEFAULT_DAILY_REPORT_TIME_ZONE
|
|
99
|
+
: configuredTimeZone;
|
|
100
|
+
}
|
|
101
|
+
function formatDailyReportDate(date, timeZone) {
|
|
102
|
+
let parts;
|
|
103
|
+
try {
|
|
104
|
+
parts = new Intl.DateTimeFormat("en-US", {
|
|
105
|
+
timeZone,
|
|
106
|
+
year: "numeric",
|
|
107
|
+
month: "2-digit",
|
|
108
|
+
day: "2-digit",
|
|
109
|
+
}).formatToParts(date);
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
if (error instanceof RangeError) {
|
|
113
|
+
throw new Error(`${DAILY_REPORT_TIME_ZONE_ENV_KEY} must be a valid IANA time zone.`);
|
|
114
|
+
}
|
|
115
|
+
throw error;
|
|
116
|
+
}
|
|
117
|
+
const year = parts.find((part) => part.type === "year")?.value;
|
|
118
|
+
const month = parts.find((part) => part.type === "month")?.value;
|
|
119
|
+
const day = parts.find((part) => part.type === "day")?.value;
|
|
120
|
+
if (year === undefined || month === undefined || day === undefined) {
|
|
121
|
+
throw new Error(`Could not format daily report date for ${timeZone}.`);
|
|
122
|
+
}
|
|
123
|
+
return `${year}-${month}-${day}`;
|
|
124
|
+
}
|
|
125
|
+
async function sendDailyReportToSlack(input) {
|
|
126
|
+
const webhookUrl = input.context.env[input.webhookEnvKey]?.trim();
|
|
127
|
+
if (webhookUrl === undefined || webhookUrl.length === 0) {
|
|
128
|
+
await recordSlackReportRun(input, "error");
|
|
129
|
+
input.context.stderr(`${input.webhookEnvKey} is required for Slack delivery.`);
|
|
130
|
+
return 1;
|
|
131
|
+
}
|
|
132
|
+
const text = renderDailyReport(input.reportInput, { lang: "ko" });
|
|
133
|
+
try {
|
|
134
|
+
const options = input.context.slackTransport === undefined
|
|
135
|
+
? {
|
|
136
|
+
webhookUrl,
|
|
137
|
+
text,
|
|
138
|
+
}
|
|
139
|
+
: {
|
|
140
|
+
webhookUrl,
|
|
141
|
+
text,
|
|
142
|
+
transport: input.context.slackTransport,
|
|
143
|
+
};
|
|
144
|
+
await sendSlackReport(options);
|
|
145
|
+
await recordSlackReportRun(input, "sent");
|
|
146
|
+
input.context.stdout("Slack report sent: slack");
|
|
147
|
+
return 0;
|
|
148
|
+
}
|
|
149
|
+
catch (error) {
|
|
150
|
+
await recordSlackReportRun(input, "error");
|
|
151
|
+
input.context.stderr(error instanceof Error ? error.message : String(error));
|
|
152
|
+
return 1;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
async function recordSlackReportRun(input, status) {
|
|
156
|
+
await recordLocalReportRun({
|
|
157
|
+
dbPath: input.dbPath,
|
|
158
|
+
createdAt: input.generatedAt,
|
|
159
|
+
reportDate: input.reportDate,
|
|
160
|
+
language: "ko",
|
|
161
|
+
deliveryTarget: "slack",
|
|
162
|
+
status,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
165
|
+
function buildProviderSummaries(store) {
|
|
166
|
+
return store.providers.map((provider) => {
|
|
167
|
+
const usageSnapshots = store.usageSnapshots.filter((snapshot) => snapshot.providerKey === provider.key);
|
|
168
|
+
const billingSnapshots = store.billingSnapshots.filter((snapshot) => snapshot.providerKey === provider.key);
|
|
169
|
+
const serviceHealthSnapshots = store.serviceHealthSnapshots.filter((snapshot) => snapshot.providerKey === provider.key);
|
|
170
|
+
const costEstimates = store.costEstimates.filter((snapshot) => snapshot.providerKey === provider.key);
|
|
171
|
+
const alerts = store.alerts.filter((alert) => alert.providerKey === provider.key);
|
|
172
|
+
const currency = costEstimates[0]?.currency ?? billingSnapshots[0]?.currency ?? "USD";
|
|
173
|
+
return {
|
|
174
|
+
provider: provider.key,
|
|
175
|
+
displayName: provider.displayName,
|
|
176
|
+
syncStatus: summarizeSyncStatus([
|
|
177
|
+
usageSnapshots.length,
|
|
178
|
+
billingSnapshots.length,
|
|
179
|
+
serviceHealthSnapshots.length,
|
|
180
|
+
costEstimates.length,
|
|
181
|
+
]),
|
|
182
|
+
usageSnapshotCount: usageSnapshots.length,
|
|
183
|
+
billingSnapshotCount: billingSnapshots.length,
|
|
184
|
+
healthStatus: summarizeHealth(serviceHealthSnapshots.map((snapshot) => snapshot.status)),
|
|
185
|
+
estimatedAmountMinor: costEstimates.reduce((total, snapshot) => total + snapshot.estimatedAmountMinor, 0),
|
|
186
|
+
currency,
|
|
187
|
+
alertCount: alerts.length,
|
|
188
|
+
};
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
function summarizeSyncStatus(snapshotCounts) {
|
|
192
|
+
return snapshotCounts.some((count) => count > 0) ? "ok" : "error";
|
|
193
|
+
}
|
|
194
|
+
function summarizeHealth(statuses) {
|
|
195
|
+
if (statuses.includes("down")) {
|
|
196
|
+
return "down";
|
|
197
|
+
}
|
|
198
|
+
if (statuses.includes("degraded")) {
|
|
199
|
+
return "degraded";
|
|
200
|
+
}
|
|
201
|
+
if (statuses.includes("unknown") || statuses.length === 0) {
|
|
202
|
+
return "unknown";
|
|
203
|
+
}
|
|
204
|
+
return "ok";
|
|
205
|
+
}
|
|
206
|
+
//# sourceMappingURL=report.js.map
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { CliExecutionContext } from "../cli.js";
|
|
2
|
+
export declare function runServeCommand(args: readonly string[], context: CliExecutionContext): Promise<number>;
|
|
3
|
+
export declare function runOpenCommand(args: readonly string[], context: CliExecutionContext): Promise<number>;
|
|
4
|
+
export declare function runDesktopCommand(args: readonly string[], context: CliExecutionContext): Promise<number>;
|
|
5
|
+
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { createFallbackLocalRuntimeAdapter, } from "../runtime-adapter.js";
|
|
2
|
+
const SERVE_USAGE = "Usage: moneysiren serve [--port <port>]";
|
|
3
|
+
const OPEN_USAGE = "Usage: moneysiren open";
|
|
4
|
+
const DESKTOP_USAGE = "Usage: moneysiren desktop status";
|
|
5
|
+
export async function runServeCommand(args, context) {
|
|
6
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
7
|
+
context.stdout(SERVE_USAGE);
|
|
8
|
+
return 0;
|
|
9
|
+
}
|
|
10
|
+
const parsed = parseServeArgs(args);
|
|
11
|
+
if (parsed === undefined) {
|
|
12
|
+
context.stderr(SERVE_USAGE);
|
|
13
|
+
return 1;
|
|
14
|
+
}
|
|
15
|
+
const result = await runtimeAdapter(context).startRuntime({
|
|
16
|
+
headless: false,
|
|
17
|
+
...(parsed.port === undefined ? {} : { port: parsed.port }),
|
|
18
|
+
});
|
|
19
|
+
return writeStartRuntimeResult(context, result, "MoneySiren local runtime");
|
|
20
|
+
}
|
|
21
|
+
export async function runOpenCommand(args, context) {
|
|
22
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
23
|
+
context.stdout(OPEN_USAGE);
|
|
24
|
+
return 0;
|
|
25
|
+
}
|
|
26
|
+
if (args.length > 0) {
|
|
27
|
+
context.stderr(OPEN_USAGE);
|
|
28
|
+
return 1;
|
|
29
|
+
}
|
|
30
|
+
const adapter = runtimeAdapter(context);
|
|
31
|
+
const runtime = await findHealthyRuntime(adapter);
|
|
32
|
+
const startResult = runtime === null
|
|
33
|
+
? await adapter.startRuntime({
|
|
34
|
+
headless: true,
|
|
35
|
+
})
|
|
36
|
+
: {
|
|
37
|
+
status: "running",
|
|
38
|
+
runtime,
|
|
39
|
+
};
|
|
40
|
+
if (startResult.status === "unavailable") {
|
|
41
|
+
return writeStartRuntimeResult(context, startResult, "MoneySiren open");
|
|
42
|
+
}
|
|
43
|
+
context.stdout("MoneySiren local API runtime ready");
|
|
44
|
+
context.stdout(`Runtime: ${startResult.status}`);
|
|
45
|
+
context.stdout(`Local API URL: ${startResult.runtime.baseUrl}`);
|
|
46
|
+
context.stdout("Dashboard UI: not opened because this runtime URL is a JSON API.");
|
|
47
|
+
context.stdout("Start the web dashboard:");
|
|
48
|
+
context.stdout(" pnpm --filter @moneysiren/web dev");
|
|
49
|
+
context.stdout("Then open: http://localhost:3000");
|
|
50
|
+
return 0;
|
|
51
|
+
}
|
|
52
|
+
export async function runDesktopCommand(args, context) {
|
|
53
|
+
const [subcommand, ...rest] = args;
|
|
54
|
+
if (subcommand === "--help" || subcommand === "-h" || subcommand === "help") {
|
|
55
|
+
context.stdout(DESKTOP_USAGE);
|
|
56
|
+
return 0;
|
|
57
|
+
}
|
|
58
|
+
if (subcommand !== "status" || rest.length > 0) {
|
|
59
|
+
context.stderr(DESKTOP_USAGE);
|
|
60
|
+
return 1;
|
|
61
|
+
}
|
|
62
|
+
const adapter = runtimeAdapter(context);
|
|
63
|
+
const runtime = await adapter.findRuntime();
|
|
64
|
+
context.stdout("MoneySiren desktop status");
|
|
65
|
+
if (runtime === null) {
|
|
66
|
+
context.stdout("Runtime: not running");
|
|
67
|
+
context.stdout("Runtime lock: not found");
|
|
68
|
+
context.stdout("Desktop shell: not detected by CLI");
|
|
69
|
+
context.stdout("Next step: run `moneysiren serve` or start the native tray app.");
|
|
70
|
+
return 0;
|
|
71
|
+
}
|
|
72
|
+
const healthy = await adapter.assertRuntimeHealthy(runtime);
|
|
73
|
+
context.stdout(`Runtime: ${healthy ? "healthy" : "unhealthy"}`);
|
|
74
|
+
context.stdout(`Base URL: ${runtime.baseUrl}`);
|
|
75
|
+
context.stdout(`PID: ${runtime.pid}`);
|
|
76
|
+
context.stdout(`Started at: ${runtime.startedAt}`);
|
|
77
|
+
context.stdout(`Version: ${runtime.version}`);
|
|
78
|
+
context.stdout("Desktop shell: not detected by CLI");
|
|
79
|
+
return healthy ? 0 : 1;
|
|
80
|
+
}
|
|
81
|
+
function runtimeAdapter(context) {
|
|
82
|
+
return context.localRuntime ?? createFallbackLocalRuntimeAdapter(context);
|
|
83
|
+
}
|
|
84
|
+
async function findHealthyRuntime(adapter) {
|
|
85
|
+
const runtime = await adapter.findRuntime();
|
|
86
|
+
if (runtime === null) {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
return await adapter.assertRuntimeHealthy(runtime) ? runtime : null;
|
|
90
|
+
}
|
|
91
|
+
function writeStartRuntimeResult(context, result, heading) {
|
|
92
|
+
if (result.status !== "unavailable") {
|
|
93
|
+
context.stdout(heading);
|
|
94
|
+
context.stdout(`Runtime: ${result.status}`);
|
|
95
|
+
context.stdout(`Base URL: ${result.runtime.baseUrl}`);
|
|
96
|
+
context.stdout(`PID: ${result.runtime.pid}`);
|
|
97
|
+
return 0;
|
|
98
|
+
}
|
|
99
|
+
context.stderr(`${heading}: unavailable`);
|
|
100
|
+
context.stderr(result.reason);
|
|
101
|
+
for (const line of result.guidance) {
|
|
102
|
+
context.stderr(line);
|
|
103
|
+
}
|
|
104
|
+
return 1;
|
|
105
|
+
}
|
|
106
|
+
function parseServeArgs(args) {
|
|
107
|
+
let port;
|
|
108
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
109
|
+
const arg = args[index];
|
|
110
|
+
if (arg === "--port") {
|
|
111
|
+
const value = args[index + 1];
|
|
112
|
+
if (value === undefined || value.startsWith("--")) {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
port = parsePort(value);
|
|
116
|
+
index += 1;
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
if (arg?.startsWith("--port=")) {
|
|
120
|
+
port = parsePort(arg.slice("--port=".length));
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
return undefined;
|
|
124
|
+
}
|
|
125
|
+
if (port === undefined) {
|
|
126
|
+
return {};
|
|
127
|
+
}
|
|
128
|
+
return Number.isSafeInteger(port) && port > 0 && port <= 65_535 ? { port } : undefined;
|
|
129
|
+
}
|
|
130
|
+
function parsePort(value) {
|
|
131
|
+
return Number.parseInt(value, 10);
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=runtime.js.map
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type MoneySirenConfig } from "../../../../packages/config/src/index.js";
|
|
2
|
+
export interface ParsedFlagResult {
|
|
3
|
+
value?: string;
|
|
4
|
+
remainingArgs: string[];
|
|
5
|
+
}
|
|
6
|
+
export declare function loadCliConfig(env: Record<string, string | undefined>): MoneySirenConfig;
|
|
7
|
+
export declare function resolveDbPath(cwd: string, configuredDbPath: string): string;
|
|
8
|
+
export declare function readFlag(args: readonly string[], flagName: string): ParsedFlagResult;
|
|
9
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { isAbsolute, join } from "node:path";
|
|
2
|
+
import { loadMoneySirenConfig } from "../../../../packages/config/src/index.js";
|
|
3
|
+
export function loadCliConfig(env) {
|
|
4
|
+
return loadMoneySirenConfig(env);
|
|
5
|
+
}
|
|
6
|
+
export function resolveDbPath(cwd, configuredDbPath) {
|
|
7
|
+
return isAbsolute(configuredDbPath) ? configuredDbPath : join(cwd, configuredDbPath);
|
|
8
|
+
}
|
|
9
|
+
export function readFlag(args, flagName) {
|
|
10
|
+
const remainingArgs = [];
|
|
11
|
+
let value;
|
|
12
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
13
|
+
const arg = args[index];
|
|
14
|
+
if (arg === flagName) {
|
|
15
|
+
value = args[index + 1];
|
|
16
|
+
index += 1;
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
if (arg?.startsWith(`${flagName}=`)) {
|
|
20
|
+
value = arg.slice(flagName.length + 1);
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (arg !== undefined) {
|
|
24
|
+
remainingArgs.push(arg);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return value === undefined ? { remainingArgs } : { value, remainingArgs };
|
|
28
|
+
}
|
|
29
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { readSanitizedSummary } from "../summary-model.js";
|
|
2
|
+
const SUMMARY_USAGE = "Usage: moneysiren summary --json";
|
|
3
|
+
export async function runSummaryCommand(args, context) {
|
|
4
|
+
if (args.includes("--help") || args.includes("-h")) {
|
|
5
|
+
context.stdout(SUMMARY_USAGE);
|
|
6
|
+
return 0;
|
|
7
|
+
}
|
|
8
|
+
if (args.length !== 1 || args[0] !== "--json") {
|
|
9
|
+
context.stderr(SUMMARY_USAGE);
|
|
10
|
+
return 1;
|
|
11
|
+
}
|
|
12
|
+
context.stdout(JSON.stringify(await readSanitizedSummary(context), null, 2));
|
|
13
|
+
return 0;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=summary.js.map
|