@moneysiren/cli 0.1.0-alpha.1 → 0.1.0-alpha.2

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.
Files changed (34) hide show
  1. package/README.md +2 -2
  2. package/dist/apps/cli/src/cli.d.ts +3 -0
  3. package/dist/apps/cli/src/cli.js +9 -2
  4. package/dist/apps/cli/src/commands/modes.js +13 -11
  5. package/dist/apps/cli/src/commands/runtime.d.ts +2 -0
  6. package/dist/apps/cli/src/commands/runtime.js +167 -0
  7. package/dist/apps/cli/src/desktop-runtime.d.ts +31 -0
  8. package/dist/apps/cli/src/desktop-runtime.js +441 -0
  9. package/dist/apps/cli/src/home.js +16 -0
  10. package/dist/apps/cli/src/postinstall.js +1 -1
  11. package/dist/apps/cli/src/release-installer.d.ts +1 -1
  12. package/dist/apps/cli/src/release-installer.js +2 -2
  13. package/dist/apps/cli/src/slash.js +12 -0
  14. package/dist/apps/cli/src/version.d.ts +1 -1
  15. package/dist/apps/cli/src/version.js +1 -1
  16. package/dist/packages/config/src/load.js +3 -0
  17. package/dist/packages/config/src/schema.d.ts +3 -0
  18. package/dist/packages/config/src/schema.js +3 -0
  19. package/dist/packages/local-api/src/server.js +1 -1
  20. package/dist/packages/view-model/src/hud-model.d.ts +74 -0
  21. package/dist/packages/view-model/src/hud-model.js +295 -0
  22. package/dist/packages/view-model/src/index.d.ts +5 -2
  23. package/dist/packages/view-model/src/index.js +4 -1
  24. package/dist/packages/view-model/src/notification-preferences-model.d.ts +30 -2
  25. package/dist/packages/view-model/src/notification-preferences-model.js +183 -1
  26. package/dist/packages/view-model/src/notification-preferences.d.ts +1 -1
  27. package/dist/packages/view-model/src/notification-preferences.js +1 -1
  28. package/dist/packages/view-model/src/sync-state.d.ts +47 -0
  29. package/dist/packages/view-model/src/sync-state.js +140 -0
  30. package/dist/packages/view-model/src/usage-progress.d.ts +22 -0
  31. package/dist/packages/view-model/src/usage-progress.js +57 -0
  32. package/dist/packages/view-model/src/view-model.d.ts +22 -0
  33. package/dist/packages/view-model/src/view-model.js +142 -0
  34. package/package.json +3 -2
package/README.md CHANGED
@@ -67,7 +67,7 @@ Install the generated tarball into a temporary project:
67
67
  mkdir -p /tmp/moneysiren-alpha-review
68
68
  cd /tmp/moneysiren-alpha-review
69
69
  npm init -y
70
- npm install /path/to/moneysiren-cli-0.1.0-alpha.1.tgz
70
+ npm install /path/to/moneysiren-cli-0.1.0-alpha.2.tgz
71
71
  npm exec moneysiren
72
72
  npm exec moneysiren -- --version
73
73
  npm exec moneysiren -- /version
@@ -83,7 +83,7 @@ PowerShell equivalent for the temporary project:
83
83
  New-Item -ItemType Directory -Force -Path $env:TEMP\moneysiren-alpha-review
84
84
  Set-Location $env:TEMP\moneysiren-alpha-review
85
85
  npm init -y
86
- npm install C:\path\to\moneysiren-cli-0.1.0-alpha.1.tgz
86
+ npm install C:\path\to\moneysiren-cli-0.1.0-alpha.2.tgz
87
87
  npm exec moneysiren
88
88
  npm exec moneysiren -- --version
89
89
  npm exec moneysiren -- modes
@@ -1,4 +1,5 @@
1
1
  import { type CliLocalRuntimeAdapter } from "./runtime-adapter.js";
2
+ import type { CliDesktopRuntimeAdapter } from "./desktop-runtime.js";
2
3
  import { type Theme } from "./theme.js";
3
4
  import type { SlackReportTransport } from "../../../packages/report/src/index.js";
4
5
  import type { AwsCostExplorerClientAdapter } from "../../../packages/connectors/aws/src/index.js";
@@ -23,6 +24,7 @@ export interface CliRuntime {
23
24
  liveClients?: CliLiveClients;
24
25
  fetch?: typeof fetch;
25
26
  localRuntime?: CliLocalRuntimeAdapter;
27
+ desktopRuntime?: CliDesktopRuntimeAdapter;
26
28
  openUrl?: (url: string) => Promise<void> | void;
27
29
  }
28
30
  export interface CliLiveClients {
@@ -46,6 +48,7 @@ export interface CliExecutionContext {
46
48
  interactive: boolean;
47
49
  theme: Theme;
48
50
  localRuntime?: CliLocalRuntimeAdapter;
51
+ desktopRuntime?: CliDesktopRuntimeAdapter;
49
52
  }
50
53
  export interface CliResult {
51
54
  exitCode: number;
@@ -5,7 +5,7 @@ import { runInstallCommand } from "./commands/install.js";
5
5
  import { runModesCommand } from "./commands/modes.js";
6
6
  import { runNotifyCommand } from "./commands/notify.js";
7
7
  import { runReportCommand } from "./commands/report.js";
8
- import { runDesktopCommand, runOpenCommand, runServeCommand } from "./commands/runtime.js";
8
+ import { runDesktopCommand, runHudCommand, runOpenCommand, runServeCommand, runStartCommand } from "./commands/runtime.js";
9
9
  import { runSummaryCommand } from "./commands/summary.js";
10
10
  import { runSyncCommand } from "./commands/sync.js";
11
11
  import { runThemeCommand } from "./commands/theme.js";
@@ -61,6 +61,7 @@ export async function runCli(args, runtime = {}) {
61
61
  }),
62
62
  theme,
63
63
  ...(runtime.localRuntime === undefined ? {} : { localRuntime: runtime.localRuntime }),
64
+ ...(runtime.desktopRuntime === undefined ? {} : { desktopRuntime: runtime.desktopRuntime }),
64
65
  };
65
66
  context.stdin = runtime.stdin ?? process.stdin;
66
67
  context.output = runtime.output ?? process.stdout;
@@ -130,6 +131,12 @@ async function dispatchCommand(args, context) {
130
131
  if (command === "serve") {
131
132
  return runServeCommand(rest, context);
132
133
  }
134
+ if (command === "start") {
135
+ return runStartCommand(rest, context);
136
+ }
137
+ if (command === "hud") {
138
+ return runHudCommand(rest, context);
139
+ }
133
140
  if (command === "open") {
134
141
  return runOpenCommand(rest, context);
135
142
  }
@@ -152,7 +159,7 @@ async function dispatchCommand(args, context) {
152
159
  return runThemeCommand(rest, context);
153
160
  }
154
161
  context.stderr(`Unknown command: ${command}`);
155
- context.stderr("Run `moneysiren --help` for usage.");
162
+ context.stderr("Run `msiren --help` or `moneysiren --help` for usage.");
156
163
  return 1;
157
164
  }
158
165
  async function dispatchSlashCommand(args, context) {
@@ -17,28 +17,30 @@ export async function runModesCommand(args, context) {
17
17
  context.stdout(`Platform: ${platformLabel()}`);
18
18
  context.stdout(`Install profile: ${formatInstallSurfaces(selectedSurfaces)}${profile === null ? " (recommended default)" : ""}`);
19
19
  context.stdout("npm install: npm install -g @moneysiren/cli@alpha");
20
+ context.stdout("Short command: msiren");
20
21
  context.stdout(`Runtime lock: ${runtimeLockHint()}`);
21
22
  context.stdout("");
22
23
  context.stdout("1. CLI automation");
23
24
  context.stdout(` Status: ${surfaceStatus("cli", selectedSurfaces)} from the npm CLI package`);
24
- context.stdout(" Try: moneysiren doctor");
25
- context.stdout(" Try: moneysiren sync --provider mock");
25
+ context.stdout(" Try: msiren doctor");
26
+ context.stdout(" Try: msiren sync --provider mock");
26
27
  context.stdout("");
27
28
  context.stdout("2. Local web dashboard/runtime");
28
29
  context.stdout(` Status: ${surfaceStatus("web", selectedSurfaces)} GitHub Release web runtime archive is installed by the CLI`);
29
- context.stdout(" Install: moneysiren install --web");
30
- context.stdout(" Try: moneysiren serve [--port <port>]");
31
- context.stdout(" Try: moneysiren dashboard check");
32
- context.stdout(" Note: the npm CLI starts the local API; full dashboard runtime ships as a release asset.");
30
+ context.stdout(" Install: msiren install --web");
31
+ context.stdout(" Try: msiren start");
32
+ context.stdout(" Try: msiren dashboard check");
33
+ context.stdout(" Note: msiren start runs the installed GitHub Release web runtime.");
33
34
  context.stdout("");
34
35
  context.stdout("3. Desktop tray/notifier");
35
36
  context.stdout(` Status: ${surfaceStatus("hud", selectedSurfaces)} Windows/macOS target is the thin Tauri tray shell from GitHub Releases`);
36
- context.stdout(" Install: moneysiren install --hud");
37
- context.stdout(" Try: moneysiren desktop status");
38
- context.stdout(" Try: moneysiren notify once --dry-run");
37
+ context.stdout(" Install: msiren install --hud");
38
+ context.stdout(" Try: msiren hud");
39
+ context.stdout(" Try: msiren desktop status");
40
+ context.stdout(" Try: msiren notify once --dry-run");
39
41
  context.stdout("");
40
- context.stdout("Install recommended set: moneysiren install --all");
41
- context.stdout("Change selection only: moneysiren install --profile-only");
42
+ context.stdout("Install recommended set: msiren install --all");
43
+ context.stdout("Change selection only: msiren install --profile-only");
42
44
  return 0;
43
45
  }
44
46
  function surfaceStatus(surface, selectedSurfaces) {
@@ -1,5 +1,7 @@
1
1
  import type { CliExecutionContext } from "../cli.js";
2
2
  export declare function runServeCommand(args: readonly string[], context: CliExecutionContext): Promise<number>;
3
+ export declare function runStartCommand(args: readonly string[], context: CliExecutionContext): Promise<number>;
4
+ export declare function runHudCommand(args: readonly string[], context: CliExecutionContext): Promise<number>;
3
5
  export declare function runOpenCommand(args: readonly string[], context: CliExecutionContext): Promise<number>;
4
6
  export declare function runDesktopCommand(args: readonly string[], context: CliExecutionContext): Promise<number>;
5
7
  //# sourceMappingURL=runtime.d.ts.map
@@ -1,5 +1,8 @@
1
+ import { createFallbackDesktopRuntimeAdapter, } from "../desktop-runtime.js";
1
2
  import { createFallbackLocalRuntimeAdapter, } from "../runtime-adapter.js";
2
3
  const SERVE_USAGE = "Usage: moneysiren serve [--port <port>]";
4
+ const START_USAGE = "Usage: msiren start [--port <port>] [--open|--no-open] [--hud]";
5
+ const HUD_USAGE = "Usage: msiren hud [--port <port>]";
3
6
  const OPEN_USAGE = "Usage: moneysiren open";
4
7
  const DESKTOP_USAGE = "Usage: moneysiren desktop status";
5
8
  export async function runServeCommand(args, context) {
@@ -18,6 +21,62 @@ export async function runServeCommand(args, context) {
18
21
  });
19
22
  return writeStartRuntimeResult(context, result, "MoneySiren local runtime");
20
23
  }
24
+ export async function runStartCommand(args, context) {
25
+ if (args.includes("--help") || args.includes("-h")) {
26
+ context.stdout(START_USAGE);
27
+ return 0;
28
+ }
29
+ const parsed = parseStartArgs(args);
30
+ if (parsed === undefined) {
31
+ context.stderr(START_USAGE);
32
+ return 1;
33
+ }
34
+ const adapter = desktopRuntimeAdapter(context);
35
+ const web = await adapter.startWebRuntime({
36
+ openBrowser: parsed.openBrowser,
37
+ ...(parsed.port === undefined ? {} : { port: parsed.port }),
38
+ });
39
+ const webExitCode = writeDesktopRuntimeResult(context, web, "MoneySiren dashboard runtime");
40
+ if (webExitCode !== 0) {
41
+ return webExitCode;
42
+ }
43
+ if (web.status !== "unavailable" && parsed.openBrowser) {
44
+ await context.openUrl(web.dashboardUrl);
45
+ context.stdout(`Dashboard URL: ${web.dashboardUrl}`);
46
+ }
47
+ if (!parsed.launchHud) {
48
+ context.stdout("HUD: run `msiren hud` to open the floating desktop widget.");
49
+ return 0;
50
+ }
51
+ const hud = await adapter.startHud({
52
+ ...(parsed.port === undefined ? {} : { port: parsed.port }),
53
+ });
54
+ return writeDesktopShellResult(context, hud, "MoneySiren HUD");
55
+ }
56
+ export async function runHudCommand(args, context) {
57
+ if (args.includes("--help") || args.includes("-h")) {
58
+ context.stdout(HUD_USAGE);
59
+ return 0;
60
+ }
61
+ const parsed = parseHudArgs(args);
62
+ if (parsed === undefined) {
63
+ context.stderr(HUD_USAGE);
64
+ return 1;
65
+ }
66
+ const adapter = desktopRuntimeAdapter(context);
67
+ const web = await adapter.startWebRuntime({
68
+ openBrowser: false,
69
+ ...(parsed.port === undefined ? {} : { port: parsed.port }),
70
+ });
71
+ const webExitCode = writeDesktopRuntimeResult(context, web, "MoneySiren dashboard runtime");
72
+ if (webExitCode !== 0) {
73
+ return webExitCode;
74
+ }
75
+ const hud = await adapter.startHud({
76
+ ...(parsed.port === undefined ? {} : { port: parsed.port }),
77
+ });
78
+ return writeDesktopShellResult(context, hud, "MoneySiren HUD");
79
+ }
21
80
  export async function runOpenCommand(args, context) {
22
81
  if (args.includes("--help") || args.includes("-h")) {
23
82
  context.stdout(OPEN_USAGE);
@@ -81,6 +140,9 @@ export async function runDesktopCommand(args, context) {
81
140
  function runtimeAdapter(context) {
82
141
  return context.localRuntime ?? createFallbackLocalRuntimeAdapter(context);
83
142
  }
143
+ function desktopRuntimeAdapter(context) {
144
+ return context.desktopRuntime ?? createFallbackDesktopRuntimeAdapter(context);
145
+ }
84
146
  async function findHealthyRuntime(adapter) {
85
147
  const runtime = await adapter.findRuntime();
86
148
  if (runtime === null) {
@@ -103,6 +165,45 @@ function writeStartRuntimeResult(context, result, heading) {
103
165
  }
104
166
  return 1;
105
167
  }
168
+ function writeDesktopRuntimeResult(context, result, heading) {
169
+ if (result.status !== "unavailable") {
170
+ context.stdout(heading);
171
+ context.stdout(`Runtime: ${result.status}`);
172
+ context.stdout(`Dashboard URL: ${result.dashboardUrl}`);
173
+ if (result.pid !== undefined) {
174
+ context.stdout(`PID: ${result.pid}`);
175
+ }
176
+ for (const note of result.notes) {
177
+ context.stdout(`Note: ${note}`);
178
+ }
179
+ return 0;
180
+ }
181
+ context.stderr(`${heading}: unavailable`);
182
+ context.stderr(result.reason);
183
+ for (const line of result.guidance) {
184
+ context.stderr(line);
185
+ }
186
+ return 1;
187
+ }
188
+ function writeDesktopShellResult(context, result, heading) {
189
+ if (result.status !== "unavailable") {
190
+ context.stdout(heading);
191
+ context.stdout(`Desktop shell: ${result.status}`);
192
+ if (result.pid !== undefined) {
193
+ context.stdout(`PID: ${result.pid}`);
194
+ }
195
+ for (const note of result.notes) {
196
+ context.stdout(`Note: ${note}`);
197
+ }
198
+ return 0;
199
+ }
200
+ context.stderr(`${heading}: unavailable`);
201
+ context.stderr(result.reason);
202
+ for (const line of result.guidance) {
203
+ context.stderr(line);
204
+ }
205
+ return 1;
206
+ }
106
207
  function parseServeArgs(args) {
107
208
  let port;
108
209
  for (let index = 0; index < args.length; index += 1) {
@@ -127,6 +228,72 @@ function parseServeArgs(args) {
127
228
  }
128
229
  return Number.isSafeInteger(port) && port > 0 && port <= 65_535 ? { port } : undefined;
129
230
  }
231
+ function parseStartArgs(args) {
232
+ let launchHud = false;
233
+ let openBrowser = true;
234
+ let port;
235
+ for (let index = 0; index < args.length; index += 1) {
236
+ const arg = args[index];
237
+ if (arg === "--hud") {
238
+ launchHud = true;
239
+ continue;
240
+ }
241
+ if (arg === "--open") {
242
+ openBrowser = true;
243
+ continue;
244
+ }
245
+ if (arg === "--no-open") {
246
+ openBrowser = false;
247
+ continue;
248
+ }
249
+ if (arg === "--port") {
250
+ const value = args[index + 1];
251
+ if (value === undefined || value.startsWith("--")) {
252
+ return undefined;
253
+ }
254
+ port = parsePort(value);
255
+ index += 1;
256
+ continue;
257
+ }
258
+ if (arg?.startsWith("--port=")) {
259
+ port = parsePort(arg.slice("--port=".length));
260
+ continue;
261
+ }
262
+ return undefined;
263
+ }
264
+ if (port !== undefined && (!Number.isSafeInteger(port) || port <= 0 || port > 65_535)) {
265
+ return undefined;
266
+ }
267
+ return {
268
+ launchHud,
269
+ openBrowser,
270
+ ...(port === undefined ? {} : { port }),
271
+ };
272
+ }
273
+ function parseHudArgs(args) {
274
+ let port;
275
+ for (let index = 0; index < args.length; index += 1) {
276
+ const arg = args[index];
277
+ if (arg === "--port") {
278
+ const value = args[index + 1];
279
+ if (value === undefined || value.startsWith("--")) {
280
+ return undefined;
281
+ }
282
+ port = parsePort(value);
283
+ index += 1;
284
+ continue;
285
+ }
286
+ if (arg?.startsWith("--port=")) {
287
+ port = parsePort(arg.slice("--port=".length));
288
+ continue;
289
+ }
290
+ return undefined;
291
+ }
292
+ if (port !== undefined && (!Number.isSafeInteger(port) || port <= 0 || port > 65_535)) {
293
+ return undefined;
294
+ }
295
+ return port === undefined ? {} : { port };
296
+ }
130
297
  function parsePort(value) {
131
298
  return Number.parseInt(value, 10);
132
299
  }
@@ -0,0 +1,31 @@
1
+ import type { CliExecutionContext } from "./cli.js";
2
+ export interface StartWebRuntimeOptions {
3
+ openBrowser: boolean;
4
+ port?: number;
5
+ }
6
+ export interface StartHudOptions {
7
+ port?: number;
8
+ }
9
+ export type DesktopRuntimeResult = {
10
+ status: "running" | "started";
11
+ dashboardUrl: string;
12
+ pid?: number;
13
+ notes: readonly string[];
14
+ } | DesktopRuntimeUnavailableResult;
15
+ export type DesktopShellResult = {
16
+ status: "opened" | "started";
17
+ executablePath: string;
18
+ pid?: number;
19
+ notes: readonly string[];
20
+ } | DesktopRuntimeUnavailableResult;
21
+ export interface DesktopRuntimeUnavailableResult {
22
+ status: "unavailable";
23
+ reason: string;
24
+ guidance: readonly string[];
25
+ }
26
+ export interface CliDesktopRuntimeAdapter {
27
+ startWebRuntime(options: StartWebRuntimeOptions): Promise<DesktopRuntimeResult>;
28
+ startHud(options: StartHudOptions): Promise<DesktopShellResult>;
29
+ }
30
+ export declare function createFallbackDesktopRuntimeAdapter(context: CliExecutionContext): CliDesktopRuntimeAdapter;
31
+ //# sourceMappingURL=desktop-runtime.d.ts.map