@moneysiren/app 0.1.0-alpha.9

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 (140) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +45 -0
  3. package/dist/apps/cli/src/cli.d.ts +59 -0
  4. package/dist/apps/cli/src/cli.js +199 -0
  5. package/dist/apps/cli/src/commands/dashboard.d.ts +3 -0
  6. package/dist/apps/cli/src/commands/dashboard.js +239 -0
  7. package/dist/apps/cli/src/commands/doctor.d.ts +3 -0
  8. package/dist/apps/cli/src/commands/doctor.js +25 -0
  9. package/dist/apps/cli/src/commands/init.d.ts +3 -0
  10. package/dist/apps/cli/src/commands/init.js +18 -0
  11. package/dist/apps/cli/src/commands/install.d.ts +3 -0
  12. package/dist/apps/cli/src/commands/install.js +244 -0
  13. package/dist/apps/cli/src/commands/modes.d.ts +3 -0
  14. package/dist/apps/cli/src/commands/modes.js +73 -0
  15. package/dist/apps/cli/src/commands/notify.d.ts +3 -0
  16. package/dist/apps/cli/src/commands/notify.js +430 -0
  17. package/dist/apps/cli/src/commands/report.d.ts +3 -0
  18. package/dist/apps/cli/src/commands/report.js +206 -0
  19. package/dist/apps/cli/src/commands/runtime.d.ts +10 -0
  20. package/dist/apps/cli/src/commands/runtime.js +499 -0
  21. package/dist/apps/cli/src/commands/shared.d.ts +9 -0
  22. package/dist/apps/cli/src/commands/shared.js +29 -0
  23. package/dist/apps/cli/src/commands/summary.d.ts +3 -0
  24. package/dist/apps/cli/src/commands/summary.js +15 -0
  25. package/dist/apps/cli/src/commands/sync.d.ts +3 -0
  26. package/dist/apps/cli/src/commands/sync.js +393 -0
  27. package/dist/apps/cli/src/commands/theme.d.ts +3 -0
  28. package/dist/apps/cli/src/commands/theme.js +181 -0
  29. package/dist/apps/cli/src/desktop-runtime.d.ts +54 -0
  30. package/dist/apps/cli/src/desktop-runtime.js +720 -0
  31. package/dist/apps/cli/src/home.d.ts +7 -0
  32. package/dist/apps/cli/src/home.js +124 -0
  33. package/dist/apps/cli/src/index.d.ts +3 -0
  34. package/dist/apps/cli/src/index.js +14 -0
  35. package/dist/apps/cli/src/install-profile.d.ts +35 -0
  36. package/dist/apps/cli/src/install-profile.js +124 -0
  37. package/dist/apps/cli/src/install-selector.d.ts +10 -0
  38. package/dist/apps/cli/src/install-selector.js +66 -0
  39. package/dist/apps/cli/src/interactive.d.ts +3 -0
  40. package/dist/apps/cli/src/interactive.js +32 -0
  41. package/dist/apps/cli/src/postinstall.d.ts +3 -0
  42. package/dist/apps/cli/src/postinstall.js +42 -0
  43. package/dist/apps/cli/src/release-installer.d.ts +57 -0
  44. package/dist/apps/cli/src/release-installer.js +432 -0
  45. package/dist/apps/cli/src/runtime-adapter.d.ts +24 -0
  46. package/dist/apps/cli/src/runtime-adapter.js +185 -0
  47. package/dist/apps/cli/src/slash.d.ts +15 -0
  48. package/dist/apps/cli/src/slash.js +229 -0
  49. package/dist/apps/cli/src/summary-model.d.ts +51 -0
  50. package/dist/apps/cli/src/summary-model.js +136 -0
  51. package/dist/apps/cli/src/theme.d.ts +18 -0
  52. package/dist/apps/cli/src/theme.js +118 -0
  53. package/dist/apps/cli/src/version.d.ts +2 -0
  54. package/dist/apps/cli/src/version.js +2 -0
  55. package/dist/packages/config/src/index.d.ts +3 -0
  56. package/dist/packages/config/src/index.js +3 -0
  57. package/dist/packages/config/src/load.d.ts +3 -0
  58. package/dist/packages/config/src/load.js +80 -0
  59. package/dist/packages/config/src/schema.d.ts +49 -0
  60. package/dist/packages/config/src/schema.js +28 -0
  61. package/dist/packages/connectors/aws/src/cost-explorer.d.ts +34 -0
  62. package/dist/packages/connectors/aws/src/cost-explorer.js +43 -0
  63. package/dist/packages/connectors/aws/src/index.d.ts +35 -0
  64. package/dist/packages/connectors/aws/src/index.js +67 -0
  65. package/dist/packages/connectors/aws/src/normalize.d.ts +69 -0
  66. package/dist/packages/connectors/aws/src/normalize.js +141 -0
  67. package/dist/packages/connectors/aws/src/sdk-client.d.ts +6 -0
  68. package/dist/packages/connectors/aws/src/sdk-client.js +21 -0
  69. package/dist/packages/connectors/cloudflare/src/client.d.ts +23 -0
  70. package/dist/packages/connectors/cloudflare/src/client.js +107 -0
  71. package/dist/packages/connectors/cloudflare/src/index.d.ts +33 -0
  72. package/dist/packages/connectors/cloudflare/src/index.js +81 -0
  73. package/dist/packages/connectors/cloudflare/src/normalize.d.ts +113 -0
  74. package/dist/packages/connectors/cloudflare/src/normalize.js +288 -0
  75. package/dist/packages/connectors/mock/src/index.d.ts +58 -0
  76. package/dist/packages/connectors/mock/src/index.js +66 -0
  77. package/dist/packages/connectors/openai/src/index.d.ts +55 -0
  78. package/dist/packages/connectors/openai/src/index.js +169 -0
  79. package/dist/packages/connectors/openai/src/normalize.d.ts +91 -0
  80. package/dist/packages/connectors/openai/src/normalize.js +180 -0
  81. package/dist/packages/connectors/supabase/src/client.d.ts +22 -0
  82. package/dist/packages/connectors/supabase/src/client.js +132 -0
  83. package/dist/packages/connectors/supabase/src/index.d.ts +33 -0
  84. package/dist/packages/connectors/supabase/src/index.js +87 -0
  85. package/dist/packages/connectors/supabase/src/normalize.d.ts +106 -0
  86. package/dist/packages/connectors/supabase/src/normalize.js +266 -0
  87. package/dist/packages/core/src/collector.d.ts +12 -0
  88. package/dist/packages/core/src/collector.js +68 -0
  89. package/dist/packages/core/src/index.d.ts +5 -0
  90. package/dist/packages/core/src/index.js +4 -0
  91. package/dist/packages/core/src/provider.d.ts +18 -0
  92. package/dist/packages/core/src/provider.js +2 -0
  93. package/dist/packages/core/src/risk-engine.d.ts +9 -0
  94. package/dist/packages/core/src/risk-engine.js +4 -0
  95. package/dist/packages/core/src/snapshots.d.ts +49 -0
  96. package/dist/packages/core/src/snapshots.js +9 -0
  97. package/dist/packages/db/src/client.d.ts +11 -0
  98. package/dist/packages/db/src/client.js +14 -0
  99. package/dist/packages/db/src/index.d.ts +6 -0
  100. package/dist/packages/db/src/index.js +6 -0
  101. package/dist/packages/db/src/local-store.d.ts +161 -0
  102. package/dist/packages/db/src/local-store.js +623 -0
  103. package/dist/packages/db/src/migrate.d.ts +17 -0
  104. package/dist/packages/db/src/migrate.js +35 -0
  105. package/dist/packages/db/src/schema.d.ts +5 -0
  106. package/dist/packages/db/src/schema.js +120 -0
  107. package/dist/packages/db/src/sqlite-bin.d.ts +3 -0
  108. package/dist/packages/db/src/sqlite-bin.js +16 -0
  109. package/dist/packages/local-api/src/index.d.ts +2 -0
  110. package/dist/packages/local-api/src/index.js +2 -0
  111. package/dist/packages/local-api/src/server.d.ts +36 -0
  112. package/dist/packages/local-api/src/server.js +310 -0
  113. package/dist/packages/report/src/daily.d.ts +24 -0
  114. package/dist/packages/report/src/daily.js +9 -0
  115. package/dist/packages/report/src/index.d.ts +4 -0
  116. package/dist/packages/report/src/index.js +4 -0
  117. package/dist/packages/report/src/korean.d.ts +3 -0
  118. package/dist/packages/report/src/korean.js +62 -0
  119. package/dist/packages/report/src/slack.d.ts +34 -0
  120. package/dist/packages/report/src/slack.js +134 -0
  121. package/dist/packages/runtime/src/index.d.ts +2 -0
  122. package/dist/packages/runtime/src/index.js +2 -0
  123. package/dist/packages/runtime/src/runtime.d.ts +26 -0
  124. package/dist/packages/runtime/src/runtime.js +182 -0
  125. package/dist/packages/view-model/src/hud-model.d.ts +74 -0
  126. package/dist/packages/view-model/src/hud-model.js +295 -0
  127. package/dist/packages/view-model/src/index.d.ts +6 -0
  128. package/dist/packages/view-model/src/index.js +6 -0
  129. package/dist/packages/view-model/src/notification-preferences-model.d.ts +75 -0
  130. package/dist/packages/view-model/src/notification-preferences-model.js +400 -0
  131. package/dist/packages/view-model/src/notification-preferences.d.ts +6 -0
  132. package/dist/packages/view-model/src/notification-preferences.js +36 -0
  133. package/dist/packages/view-model/src/sync-state.d.ts +47 -0
  134. package/dist/packages/view-model/src/sync-state.js +140 -0
  135. package/dist/packages/view-model/src/usage-progress.d.ts +22 -0
  136. package/dist/packages/view-model/src/usage-progress.js +57 -0
  137. package/dist/packages/view-model/src/view-model.d.ts +215 -0
  138. package/dist/packages/view-model/src/view-model.js +826 -0
  139. package/package.json +40 -0
  140. package/scripts/postinstall.mjs +69 -0
@@ -0,0 +1,134 @@
1
+ export class SlackReportDeliveryError extends Error {
2
+ statusCode;
3
+ constructor(message, options = {}) {
4
+ super(message);
5
+ this.name = "SlackReportDeliveryError";
6
+ if (options.statusCode !== undefined) {
7
+ this.statusCode = options.statusCode;
8
+ }
9
+ }
10
+ }
11
+ const DEFAULT_SLACK_REPORT_TIMEOUT_MS = 5_000;
12
+ const MAX_SLACK_ERROR_MESSAGE_LENGTH = 500;
13
+ const MAX_SLACK_RESPONSE_BODY_LENGTH = 300;
14
+ const TRUNCATED_SUFFIX = "... [truncated]";
15
+ export function buildSlackReportPayload(text) {
16
+ const trimmedText = text.trim();
17
+ if (trimmedText.length === 0) {
18
+ throw new SlackReportDeliveryError("Slack report text must not be blank.");
19
+ }
20
+ return {
21
+ text: trimmedText,
22
+ mrkdwn: true,
23
+ };
24
+ }
25
+ export async function sendSlackReport(options) {
26
+ const webhookUrl = normalizeWebhookUrl(options.webhookUrl);
27
+ const payload = buildSlackReportPayload(options.text);
28
+ const transport = options.transport ?? fetchSlackReportTransport;
29
+ const timeoutMs = resolveSlackReportTimeoutMs(options.timeoutMs);
30
+ const controller = new AbortController();
31
+ let timeout;
32
+ let response;
33
+ try {
34
+ const transportPromise = transport({
35
+ webhookUrl,
36
+ payload,
37
+ signal: controller.signal,
38
+ });
39
+ transportPromise.catch(() => undefined);
40
+ const timeoutPromise = new Promise((_resolve, reject) => {
41
+ timeout = setTimeout(() => {
42
+ controller.abort();
43
+ reject(new SlackReportDeliveryError(`Slack report delivery timed out after ${timeoutMs}ms.`));
44
+ }, timeoutMs);
45
+ });
46
+ response = await Promise.race([transportPromise, timeoutPromise]);
47
+ }
48
+ catch (error) {
49
+ const message = error instanceof SlackReportDeliveryError
50
+ ? error.message
51
+ : `Slack report delivery failed: ${errorMessage(error)}`;
52
+ const errorOptions = error instanceof SlackReportDeliveryError && error.statusCode !== undefined
53
+ ? { statusCode: error.statusCode }
54
+ : {};
55
+ throw new SlackReportDeliveryError(sanitizeWebhookMessage(message, webhookUrl), errorOptions);
56
+ }
57
+ finally {
58
+ if (timeout !== undefined) {
59
+ clearTimeout(timeout);
60
+ }
61
+ }
62
+ if (!response.ok) {
63
+ const responseBody = formatResponseBodyDetail(response.body, webhookUrl);
64
+ const responseDetail = responseBody === undefined
65
+ ? ""
66
+ : ` Response: ${responseBody}`;
67
+ throw new SlackReportDeliveryError(sanitizeWebhookMessage(`Slack report delivery failed with HTTP ${response.status}.${responseDetail}`, webhookUrl), {
68
+ statusCode: response.status,
69
+ });
70
+ }
71
+ return {
72
+ status: "sent",
73
+ statusCode: response.status,
74
+ };
75
+ }
76
+ async function fetchSlackReportTransport(request) {
77
+ const response = await fetch(request.webhookUrl, {
78
+ method: "POST",
79
+ headers: {
80
+ "Content-Type": "application/json",
81
+ },
82
+ body: JSON.stringify(request.payload),
83
+ signal: request.signal,
84
+ });
85
+ const body = await response.text();
86
+ return {
87
+ ok: response.ok,
88
+ status: response.status,
89
+ ...(body.length === 0 ? {} : { body }),
90
+ };
91
+ }
92
+ function normalizeWebhookUrl(webhookUrl) {
93
+ const trimmed = webhookUrl.trim();
94
+ if (trimmed.length === 0) {
95
+ throw new SlackReportDeliveryError("SLACK_WEBHOOK_URL is required for Slack delivery.");
96
+ }
97
+ return trimmed;
98
+ }
99
+ function resolveSlackReportTimeoutMs(timeoutMs) {
100
+ if (timeoutMs === undefined) {
101
+ return DEFAULT_SLACK_REPORT_TIMEOUT_MS;
102
+ }
103
+ if (!Number.isSafeInteger(timeoutMs) || timeoutMs <= 0) {
104
+ throw new SlackReportDeliveryError("Slack report timeout must be a positive safe integer.");
105
+ }
106
+ return timeoutMs;
107
+ }
108
+ function formatResponseBodyDetail(body, webhookUrl) {
109
+ const trimmedBody = body?.trim();
110
+ if (trimmedBody === undefined || trimmedBody.length === 0) {
111
+ return undefined;
112
+ }
113
+ return limitText(redactSensitiveText(trimmedBody, webhookUrl), MAX_SLACK_RESPONSE_BODY_LENGTH);
114
+ }
115
+ function sanitizeWebhookMessage(message, webhookUrl) {
116
+ return limitText(redactSensitiveText(message, webhookUrl), MAX_SLACK_ERROR_MESSAGE_LENGTH);
117
+ }
118
+ function redactSensitiveText(message, webhookUrl) {
119
+ return message
120
+ .replaceAll(webhookUrl, "[REDACTED:webhook_url]")
121
+ .replace(/https:\/\/hooks\.slack\.com\/services\/[^\s"')]+/gi, "[REDACTED:webhook_url]")
122
+ .replace(/\bsk-[A-Za-z0-9_-]+/g, "[REDACTED:token]")
123
+ .replace(/\bxox[baprs]-[A-Za-z0-9-]+/gi, "[REDACTED:token]");
124
+ }
125
+ function limitText(message, maxLength) {
126
+ if (message.length <= maxLength) {
127
+ return message;
128
+ }
129
+ return `${message.slice(0, maxLength - TRUNCATED_SUFFIX.length)}${TRUNCATED_SUFFIX}`;
130
+ }
131
+ function errorMessage(error) {
132
+ return error instanceof Error ? error.message : String(error);
133
+ }
134
+ //# sourceMappingURL=slack.js.map
@@ -0,0 +1,2 @@
1
+ export { assertLoopbackHost, assertRuntimeHealthy, findRuntime, isLoopbackHost, readRuntimeLock, removeRuntimeLock, resolveRuntimeLockPath, writeRuntimeLock, type LocalRuntime, type RuntimeHealthCheckOptions, type RuntimeLockOptions, } from "./runtime.js";
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,2 @@
1
+ export { assertLoopbackHost, assertRuntimeHealthy, findRuntime, isLoopbackHost, readRuntimeLock, removeRuntimeLock, resolveRuntimeLockPath, writeRuntimeLock, } from "./runtime.js";
2
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1,26 @@
1
+ export interface LocalRuntime {
2
+ pid: number;
3
+ port: number;
4
+ baseUrl: string;
5
+ startedAt: string;
6
+ version: string;
7
+ }
8
+ export interface RuntimeLockOptions {
9
+ cwd?: string;
10
+ env?: Record<string, string | undefined>;
11
+ lockPath?: string;
12
+ platform?: NodeJS.Platform;
13
+ }
14
+ export interface RuntimeHealthCheckOptions {
15
+ fetchImpl?: typeof fetch;
16
+ timeoutMs?: number;
17
+ }
18
+ export declare function isLoopbackHost(host: string): boolean;
19
+ export declare function assertLoopbackHost(host: string): void;
20
+ export declare function resolveRuntimeLockPath(options?: RuntimeLockOptions): string;
21
+ export declare function readRuntimeLock(options?: RuntimeLockOptions): Promise<LocalRuntime | null>;
22
+ export declare function writeRuntimeLock(runtime: LocalRuntime, options?: RuntimeLockOptions): Promise<string>;
23
+ export declare function removeRuntimeLock(options?: RuntimeLockOptions): Promise<void>;
24
+ export declare function findRuntime(options?: RuntimeLockOptions): Promise<LocalRuntime | null>;
25
+ export declare function assertRuntimeHealthy(runtime: LocalRuntime, options?: RuntimeHealthCheckOptions): Promise<boolean>;
26
+ //# sourceMappingURL=runtime.d.ts.map
@@ -0,0 +1,182 @@
1
+ import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
2
+ import { homedir } from "node:os";
3
+ import { dirname, isAbsolute, join, posix, win32 } from "node:path";
4
+ const RUNTIME_LOCK_ENV_KEY = "MONEYSIREN_RUNTIME_LOCK_PATH";
5
+ const DEFAULT_HEALTH_TIMEOUT_MS = 2_000;
6
+ export function isLoopbackHost(host) {
7
+ const normalized = host.trim().toLowerCase().replace(/^\[/, "").replace(/\]$/, "");
8
+ return (normalized === "localhost" ||
9
+ normalized === "::1" ||
10
+ normalized === "0:0:0:0:0:0:0:1" ||
11
+ normalized.startsWith("127."));
12
+ }
13
+ export function assertLoopbackHost(host) {
14
+ if (!isLoopbackHost(host)) {
15
+ throw new Error("MoneySiren local runtime must bind to a loopback host.");
16
+ }
17
+ }
18
+ export function resolveRuntimeLockPath(options = {}) {
19
+ if (options.lockPath !== undefined && options.lockPath.trim().length > 0) {
20
+ return resolveRuntimePath(options.lockPath, options.cwd);
21
+ }
22
+ const configuredPath = options.env?.[RUNTIME_LOCK_ENV_KEY]?.trim();
23
+ if (configuredPath !== undefined && configuredPath.length > 0) {
24
+ return resolveRuntimePath(configuredPath, options.cwd);
25
+ }
26
+ return defaultRuntimeLockPath(options.env ?? process.env, options.platform ?? process.platform);
27
+ }
28
+ export async function readRuntimeLock(options = {}) {
29
+ const lockPath = resolveRuntimeLockPath(options);
30
+ try {
31
+ const parsed = JSON.parse(await readFile(lockPath, "utf8"));
32
+ return parseRuntime(parsed);
33
+ }
34
+ catch {
35
+ return null;
36
+ }
37
+ }
38
+ export async function writeRuntimeLock(runtime, options = {}) {
39
+ const parsedUrl = parseLoopbackUrl(runtime.baseUrl);
40
+ if (parsedUrl.port !== String(runtime.port)) {
41
+ throw new Error("Runtime lock baseUrl port must match the runtime port.");
42
+ }
43
+ const lockPath = resolveRuntimeLockPath(options);
44
+ await mkdir(dirname(lockPath), { recursive: true });
45
+ await writeFile(lockPath, `${JSON.stringify(runtime, null, 2)}\n`, "utf8");
46
+ return lockPath;
47
+ }
48
+ export async function removeRuntimeLock(options = {}) {
49
+ await rm(resolveRuntimeLockPath(options), {
50
+ force: true,
51
+ });
52
+ }
53
+ export async function findRuntime(options = {}) {
54
+ const runtime = await readRuntimeLock(options);
55
+ if (runtime === null) {
56
+ return null;
57
+ }
58
+ if (!isProcessAlive(runtime.pid)) {
59
+ await removeStaleRuntimeLock(options);
60
+ return null;
61
+ }
62
+ return runtime;
63
+ }
64
+ export async function assertRuntimeHealthy(runtime, options = {}) {
65
+ parseLoopbackUrl(runtime.baseUrl);
66
+ const fetchImpl = options.fetchImpl ?? fetch;
67
+ const controller = new AbortController();
68
+ const timeout = setTimeout(() => controller.abort(), options.timeoutMs ?? DEFAULT_HEALTH_TIMEOUT_MS);
69
+ try {
70
+ const response = await fetchImpl(`${runtime.baseUrl}/api/local/health`, {
71
+ method: "GET",
72
+ signal: controller.signal,
73
+ });
74
+ if (!response.ok) {
75
+ return false;
76
+ }
77
+ const payload = await response.json();
78
+ return payload.secretsReturned === false;
79
+ }
80
+ catch {
81
+ return false;
82
+ }
83
+ finally {
84
+ clearTimeout(timeout);
85
+ }
86
+ }
87
+ async function removeStaleRuntimeLock(options) {
88
+ try {
89
+ await removeRuntimeLock(options);
90
+ }
91
+ catch {
92
+ // A stale lock must not make status commands fail, especially after npm/global installs.
93
+ }
94
+ }
95
+ function parseRuntime(value) {
96
+ if (!isRecord(value)) {
97
+ return null;
98
+ }
99
+ const pid = value.pid;
100
+ const port = value.port;
101
+ const baseUrl = value.baseUrl;
102
+ const startedAt = value.startedAt;
103
+ const version = value.version;
104
+ if (typeof pid !== "number" ||
105
+ typeof port !== "number" ||
106
+ typeof baseUrl !== "string" ||
107
+ typeof startedAt !== "string" ||
108
+ typeof version !== "string" ||
109
+ !Number.isSafeInteger(pid) ||
110
+ !Number.isSafeInteger(port)) {
111
+ return null;
112
+ }
113
+ try {
114
+ parseLoopbackUrl(baseUrl);
115
+ }
116
+ catch {
117
+ return null;
118
+ }
119
+ return {
120
+ pid,
121
+ port,
122
+ baseUrl,
123
+ startedAt,
124
+ version,
125
+ };
126
+ }
127
+ function parseLoopbackUrl(value) {
128
+ const parsedUrl = new URL(value);
129
+ if (parsedUrl.protocol !== "http:") {
130
+ throw new Error("MoneySiren local runtime must use http on loopback.");
131
+ }
132
+ assertLoopbackHost(parsedUrl.hostname);
133
+ return parsedUrl;
134
+ }
135
+ function resolveRuntimePath(path, cwd = process.cwd()) {
136
+ return isAbsolute(path) ? path : join(cwd, path);
137
+ }
138
+ function defaultRuntimeLockPath(env, platform) {
139
+ if (platform === "darwin") {
140
+ return joinForPlatform(platform, resolveHomeDirectory(env), "Library", "Application Support", "MoneySiren", "runtime.json");
141
+ }
142
+ if (platform === "win32") {
143
+ return joinForPlatform(platform, resolveWindowsAppDataDirectory(env), "MoneySiren", "runtime.json");
144
+ }
145
+ const configHome = trimToNull(env.XDG_CONFIG_HOME) ?? joinForPlatform(platform, resolveHomeDirectory(env), ".config");
146
+ return joinForPlatform(platform, configHome, "moneysiren", "runtime.json");
147
+ }
148
+ function resolveWindowsAppDataDirectory(env) {
149
+ return trimToNull(env.APPDATA) ?? win32.join(resolveHomeDirectory(env), "AppData", "Roaming");
150
+ }
151
+ function resolveHomeDirectory(env) {
152
+ return trimToNull(env.HOME) ?? trimToNull(env.USERPROFILE) ?? homedir();
153
+ }
154
+ function trimToNull(value) {
155
+ const trimmed = value?.trim();
156
+ return trimmed === undefined || trimmed.length === 0 ? null : trimmed;
157
+ }
158
+ function joinForPlatform(platform, ...segments) {
159
+ return platform === "win32" ? win32.join(...segments) : posix.join(...segments);
160
+ }
161
+ function isProcessAlive(pid) {
162
+ if (pid <= 0) {
163
+ return false;
164
+ }
165
+ try {
166
+ process.kill(pid, 0);
167
+ return true;
168
+ }
169
+ catch (error) {
170
+ if (isNodeError(error) && error.code === "EPERM") {
171
+ return true;
172
+ }
173
+ return false;
174
+ }
175
+ }
176
+ function isRecord(value) {
177
+ return typeof value === "object" && value !== null;
178
+ }
179
+ function isNodeError(value) {
180
+ return value instanceof Error && "code" in value;
181
+ }
182
+ //# sourceMappingURL=runtime.js.map
@@ -0,0 +1,74 @@
1
+ import { type AggregateSyncStatus, type ItemSyncView, type RiskSeverity } from "./sync-state.js";
2
+ import { type UsageProgressView } from "./usage-progress.js";
3
+ import type { TodayLiveProviderView, TodayLiveView } from "./view-model.js";
4
+ import type { NotificationWidgetKey } from "./notification-preferences-model.js";
5
+ export type CreditAccuracy = "exact" | "estimated" | "bounded" | "unknown";
6
+ export interface CreditItemView {
7
+ itemKey: string;
8
+ expiresAt: string | null;
9
+ estimatedEarliestAt: string | null;
10
+ estimatedLatestAt: string | null;
11
+ accuracy: CreditAccuracy;
12
+ status: "active" | "expiring_soon" | "expired" | "unknown";
13
+ }
14
+ export interface CreditPoolView {
15
+ kind: "credit_pool";
16
+ id: string;
17
+ providerKey: "codex-app" | "codex-cli";
18
+ variant: "count" | "expiry";
19
+ availableCount: number | null;
20
+ totalEarnedCount: number | null;
21
+ credits: readonly CreditItemView[];
22
+ unresolvedCount: number;
23
+ nearestExpiryAt: string | null;
24
+ accuracy: CreditAccuracy;
25
+ sync: ItemSyncView;
26
+ riskSeverity: RiskSeverity;
27
+ target: {
28
+ type: "service";
29
+ providerKey: "codex-app" | "codex-cli";
30
+ };
31
+ }
32
+ export interface QuotaItemView {
33
+ kind: "quota";
34
+ id: string;
35
+ providerKey: string;
36
+ window: "five_hour" | "weekly" | "context" | "budget";
37
+ progress: UsageProgressView;
38
+ resetAt: string | null;
39
+ sync: ItemSyncView;
40
+ riskSeverity: RiskSeverity;
41
+ target: {
42
+ type: "service" | "dashboard";
43
+ providerKey?: string;
44
+ routeKey?: string;
45
+ };
46
+ }
47
+ export type HudItemView = QuotaItemView | CreditPoolView;
48
+ export interface HudViewModel {
49
+ generatedAt: string;
50
+ localOnly: true;
51
+ secretsReturned: false;
52
+ dataRevision: string;
53
+ sync: {
54
+ status: AggregateSyncStatus;
55
+ freshCount: number;
56
+ staleCount: number;
57
+ errorCount: number;
58
+ neutralCount: number;
59
+ lastSuccessAt: string | null;
60
+ };
61
+ risk: {
62
+ severity: RiskSeverity;
63
+ warningCount: number;
64
+ criticalCount: number;
65
+ };
66
+ items: readonly HudItemView[];
67
+ }
68
+ export declare const CODEX_APP_PROVIDER_KEY = "codex-app";
69
+ export declare const CODEX_CLI_PROVIDER_KEY = "codex-cli";
70
+ export declare function buildHudViewModel(todayLive: TodayLiveView): HudViewModel;
71
+ export declare function filterHudViewModelByWidgets(model: HudViewModel, selectedWidgets: readonly NotificationWidgetKey[]): HudViewModel;
72
+ export declare function buildCreditPoolFromProvider(provider: TodayLiveProviderView, generatedAt: string): CreditPoolView | null;
73
+ export declare function buildCreditPoolsFromProvider(provider: TodayLiveProviderView, generatedAt: string): CreditPoolView[];
74
+ //# sourceMappingURL=hud-model.d.ts.map