@moneysiren/app 0.1.0-alpha.10
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 +45 -0
- package/dist/apps/cli/src/cli.d.ts +59 -0
- package/dist/apps/cli/src/cli.js +199 -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 +244 -0
- package/dist/apps/cli/src/commands/modes.d.ts +3 -0
- package/dist/apps/cli/src/commands/modes.js +73 -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 +10 -0
- package/dist/apps/cli/src/commands/runtime.js +499 -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/desktop-runtime.d.ts +54 -0
- package/dist/apps/cli/src/desktop-runtime.js +720 -0
- package/dist/apps/cli/src/home.d.ts +7 -0
- package/dist/apps/cli/src/home.js +124 -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/release-installer.d.ts +57 -0
- package/dist/apps/cli/src/release-installer.js +432 -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 +229 -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/apps/cli/src/version.d.ts +2 -0
- package/dist/apps/cli/src/version.js +2 -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 +80 -0
- package/dist/packages/config/src/schema.d.ts +49 -0
- package/dist/packages/config/src/schema.js +28 -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/hud-model.d.ts +74 -0
- package/dist/packages/view-model/src/hud-model.js +295 -0
- package/dist/packages/view-model/src/index.d.ts +6 -0
- package/dist/packages/view-model/src/index.js +6 -0
- package/dist/packages/view-model/src/notification-preferences-model.d.ts +75 -0
- package/dist/packages/view-model/src/notification-preferences-model.js +400 -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/sync-state.d.ts +47 -0
- package/dist/packages/view-model/src/sync-state.js +140 -0
- package/dist/packages/view-model/src/usage-progress.d.ts +22 -0
- package/dist/packages/view-model/src/usage-progress.js +57 -0
- package/dist/packages/view-model/src/view-model.d.ts +215 -0
- package/dist/packages/view-model/src/view-model.js +826 -0
- package/package.json +40 -0
- package/scripts/postinstall.mjs +69 -0
|
@@ -0,0 +1,400 @@
|
|
|
1
|
+
export const NOTIFICATION_WIDGET_KEYS = [
|
|
2
|
+
"month_forecast",
|
|
3
|
+
"today_live_cost",
|
|
4
|
+
"risk_high_count",
|
|
5
|
+
"stale_connection_count",
|
|
6
|
+
"aws_month_forecast",
|
|
7
|
+
"openai_today_cost",
|
|
8
|
+
"openai_today_tokens",
|
|
9
|
+
"claude_five_hour_percent",
|
|
10
|
+
"claude_weekly_percent",
|
|
11
|
+
"codex_five_hour_percent",
|
|
12
|
+
"codex_weekly_percent",
|
|
13
|
+
"codex_reset_credit_count",
|
|
14
|
+
"codex_reset_credit_expiry",
|
|
15
|
+
"supabase_usage_health",
|
|
16
|
+
"cloudflare_month_to_date",
|
|
17
|
+
];
|
|
18
|
+
export const LOCAL_CLI_DASHBOARD_METRIC_KEYS = [
|
|
19
|
+
"context_percent",
|
|
20
|
+
"last_request_tokens",
|
|
21
|
+
"total_tokens",
|
|
22
|
+
"five_hour_limit_percent",
|
|
23
|
+
"weekly_limit_percent",
|
|
24
|
+
"five_hour_remaining_tokens",
|
|
25
|
+
"weekly_remaining_tokens",
|
|
26
|
+
"usage_reset_credits",
|
|
27
|
+
"usage_reset_credit_estimate",
|
|
28
|
+
"context_tokens",
|
|
29
|
+
"input_tokens",
|
|
30
|
+
"output_tokens",
|
|
31
|
+
"cache_tokens",
|
|
32
|
+
"reasoning_tokens",
|
|
33
|
+
"sessions",
|
|
34
|
+
"turns",
|
|
35
|
+
"tool_calls",
|
|
36
|
+
"log_files",
|
|
37
|
+
];
|
|
38
|
+
export const DASHBOARD_VIEW_KEYS = ["overview", "today", "forecast", "risks"];
|
|
39
|
+
export const DASHBOARD_WIDGET_SIZES = ["compact", "normal", "wide", "full"];
|
|
40
|
+
export const DASHBOARD_WIDGET_KEYS_BY_VIEW = {
|
|
41
|
+
overview: [
|
|
42
|
+
"overview_meta",
|
|
43
|
+
"overview_metrics",
|
|
44
|
+
"overview_trend",
|
|
45
|
+
"overview_grouping",
|
|
46
|
+
"overview_services",
|
|
47
|
+
"overview_insights",
|
|
48
|
+
],
|
|
49
|
+
today: [
|
|
50
|
+
"today_main",
|
|
51
|
+
"today_rail",
|
|
52
|
+
],
|
|
53
|
+
forecast: [
|
|
54
|
+
"forecast_metrics",
|
|
55
|
+
"forecast_table",
|
|
56
|
+
"forecast_breakdown",
|
|
57
|
+
],
|
|
58
|
+
risks: [
|
|
59
|
+
"risks_summary",
|
|
60
|
+
"risks_table",
|
|
61
|
+
],
|
|
62
|
+
};
|
|
63
|
+
export const DEFAULT_SELECTED_NOTIFICATION_WIDGET_KEYS = [
|
|
64
|
+
"month_forecast",
|
|
65
|
+
"today_live_cost",
|
|
66
|
+
"risk_high_count",
|
|
67
|
+
"stale_connection_count",
|
|
68
|
+
"openai_today_tokens",
|
|
69
|
+
"codex_five_hour_percent",
|
|
70
|
+
"codex_reset_credit_count",
|
|
71
|
+
"codex_reset_credit_expiry",
|
|
72
|
+
];
|
|
73
|
+
const LEGACY_SELECTED_NOTIFICATION_WIDGET_KEY_SETS = [
|
|
74
|
+
[
|
|
75
|
+
"month_forecast",
|
|
76
|
+
"today_live_cost",
|
|
77
|
+
"risk_high_count",
|
|
78
|
+
"stale_connection_count",
|
|
79
|
+
"openai_today_tokens",
|
|
80
|
+
"codex_five_hour_percent",
|
|
81
|
+
],
|
|
82
|
+
[
|
|
83
|
+
"month_forecast",
|
|
84
|
+
"today_live_cost",
|
|
85
|
+
"risk_high_count",
|
|
86
|
+
"stale_connection_count",
|
|
87
|
+
"openai_today_tokens",
|
|
88
|
+
"codex_five_hour_percent",
|
|
89
|
+
"codex_reset_credit_expiry",
|
|
90
|
+
],
|
|
91
|
+
];
|
|
92
|
+
export const DEFAULT_LOCAL_CLI_DASHBOARD_METRIC_KEYS = [
|
|
93
|
+
"context_percent",
|
|
94
|
+
"last_request_tokens",
|
|
95
|
+
"total_tokens",
|
|
96
|
+
"usage_reset_credits",
|
|
97
|
+
];
|
|
98
|
+
export const DEFAULT_DASHBOARD_WIDGET_LAYOUTS = {
|
|
99
|
+
overview: defaultDashboardWidgetLayout("overview"),
|
|
100
|
+
today: defaultDashboardWidgetLayout("today"),
|
|
101
|
+
forecast: defaultDashboardWidgetLayout("forecast"),
|
|
102
|
+
risks: defaultDashboardWidgetLayout("risks"),
|
|
103
|
+
};
|
|
104
|
+
export const DEFAULT_NOTIFICATION_THRESHOLD_RULES = [
|
|
105
|
+
{
|
|
106
|
+
widgetKey: "risk_high_count",
|
|
107
|
+
operator: "gte",
|
|
108
|
+
value: 1,
|
|
109
|
+
cooldownMinutes: 60,
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
widgetKey: "today_live_cost",
|
|
113
|
+
operator: "gte",
|
|
114
|
+
value: 10,
|
|
115
|
+
cooldownMinutes: 180,
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
widgetKey: "codex_weekly_percent",
|
|
119
|
+
operator: "gte",
|
|
120
|
+
value: 90,
|
|
121
|
+
cooldownMinutes: 360,
|
|
122
|
+
},
|
|
123
|
+
];
|
|
124
|
+
export const DEFAULT_NOTIFICATION_PREFERENCES = {
|
|
125
|
+
enabled: true,
|
|
126
|
+
digestEnabled: true,
|
|
127
|
+
digestInterval: "daily",
|
|
128
|
+
quietHours: {
|
|
129
|
+
start: "22:00",
|
|
130
|
+
end: "08:00",
|
|
131
|
+
},
|
|
132
|
+
selectedWidgets: DEFAULT_SELECTED_NOTIFICATION_WIDGET_KEYS,
|
|
133
|
+
thresholdRules: DEFAULT_NOTIFICATION_THRESHOLD_RULES,
|
|
134
|
+
desktopEnabled: false,
|
|
135
|
+
dashboard: {
|
|
136
|
+
localCliMetricKeys: DEFAULT_LOCAL_CLI_DASHBOARD_METRIC_KEYS,
|
|
137
|
+
widgetLayouts: DEFAULT_DASHBOARD_WIDGET_LAYOUTS,
|
|
138
|
+
budget: {
|
|
139
|
+
monthlyBudgetMinor: null,
|
|
140
|
+
currency: "USD",
|
|
141
|
+
warningPercent: 80,
|
|
142
|
+
criticalPercent: 100,
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
hud: {
|
|
146
|
+
alwaysOnTop: true,
|
|
147
|
+
fontScale: 0.95,
|
|
148
|
+
opacity: 0.94,
|
|
149
|
+
selectedWidgets: DEFAULT_SELECTED_NOTIFICATION_WIDGET_KEYS,
|
|
150
|
+
},
|
|
151
|
+
};
|
|
152
|
+
export function parseNotificationPreferences(value) {
|
|
153
|
+
if (!isRecord(value)) {
|
|
154
|
+
return cloneNotificationPreferences(DEFAULT_NOTIFICATION_PREFERENCES);
|
|
155
|
+
}
|
|
156
|
+
const selectedWidgets = parseSelectedWidgets(value.selectedWidgets);
|
|
157
|
+
return {
|
|
158
|
+
enabled: typeof value.enabled === "boolean" ? value.enabled : DEFAULT_NOTIFICATION_PREFERENCES.enabled,
|
|
159
|
+
digestEnabled: typeof value.digestEnabled === "boolean"
|
|
160
|
+
? value.digestEnabled
|
|
161
|
+
: DEFAULT_NOTIFICATION_PREFERENCES.digestEnabled,
|
|
162
|
+
digestInterval: parseDigestInterval(value.digestInterval),
|
|
163
|
+
quietHours: parseQuietHours(value.quietHours),
|
|
164
|
+
selectedWidgets,
|
|
165
|
+
thresholdRules: parseThresholdRules(value.thresholdRules),
|
|
166
|
+
desktopEnabled: typeof value.desktopEnabled === "boolean"
|
|
167
|
+
? value.desktopEnabled
|
|
168
|
+
: DEFAULT_NOTIFICATION_PREFERENCES.desktopEnabled,
|
|
169
|
+
dashboard: parseDashboardDisplayPreferences(value.dashboard),
|
|
170
|
+
hud: parseHudPreferences(value.hud, selectedWidgets),
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
export function cloneNotificationPreferences(preferences) {
|
|
174
|
+
return {
|
|
175
|
+
enabled: preferences.enabled,
|
|
176
|
+
digestEnabled: preferences.digestEnabled,
|
|
177
|
+
digestInterval: preferences.digestInterval,
|
|
178
|
+
quietHours: {
|
|
179
|
+
...preferences.quietHours,
|
|
180
|
+
},
|
|
181
|
+
selectedWidgets: [...preferences.selectedWidgets],
|
|
182
|
+
thresholdRules: preferences.thresholdRules.map((rule) => ({ ...rule })),
|
|
183
|
+
desktopEnabled: preferences.desktopEnabled,
|
|
184
|
+
dashboard: parseDashboardDisplayPreferences(preferences.dashboard),
|
|
185
|
+
hud: parseHudPreferences(preferences.hud),
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
function parseDashboardDisplayPreferences(value) {
|
|
189
|
+
const record = isRecord(value) ? value : {};
|
|
190
|
+
return {
|
|
191
|
+
localCliMetricKeys: parseLocalCliDashboardMetricKeys(record.localCliMetricKeys),
|
|
192
|
+
budget: parseDashboardBudgetPreferences(record.budget),
|
|
193
|
+
widgetLayouts: parseDashboardWidgetLayouts(record.widgetLayouts),
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
function parseDashboardWidgetLayouts(value) {
|
|
197
|
+
const record = isRecord(value) ? value : {};
|
|
198
|
+
return {
|
|
199
|
+
overview: parseDashboardWidgetLayout("overview", record.overview),
|
|
200
|
+
today: parseDashboardWidgetLayout("today", record.today),
|
|
201
|
+
forecast: parseDashboardWidgetLayout("forecast", record.forecast),
|
|
202
|
+
risks: parseDashboardWidgetLayout("risks", record.risks),
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
function parseDashboardWidgetLayout(viewKey, value) {
|
|
206
|
+
const validWidgetKeys = new Set(DASHBOARD_WIDGET_KEYS_BY_VIEW[viewKey]);
|
|
207
|
+
const defaults = defaultDashboardWidgetLayout(viewKey);
|
|
208
|
+
const defaultByKey = new Map(defaults.map((item) => [item.widgetKey, item]));
|
|
209
|
+
const parsed = Array.isArray(value)
|
|
210
|
+
? value
|
|
211
|
+
.map((item) => {
|
|
212
|
+
if (!isRecord(item) || typeof item.widgetKey !== "string" || !validWidgetKeys.has(item.widgetKey)) {
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
const widgetKey = item.widgetKey;
|
|
216
|
+
const fallback = defaultByKey.get(widgetKey);
|
|
217
|
+
return {
|
|
218
|
+
widgetKey,
|
|
219
|
+
visible: typeof item.visible === "boolean" ? item.visible : fallback?.visible ?? true,
|
|
220
|
+
size: parseDashboardWidgetSize(item.size, fallback?.size ?? "normal"),
|
|
221
|
+
};
|
|
222
|
+
})
|
|
223
|
+
.filter((item) => item !== null)
|
|
224
|
+
: [];
|
|
225
|
+
const seen = new Set();
|
|
226
|
+
const normalized = parsed.filter((item) => {
|
|
227
|
+
if (seen.has(item.widgetKey)) {
|
|
228
|
+
return false;
|
|
229
|
+
}
|
|
230
|
+
seen.add(item.widgetKey);
|
|
231
|
+
return true;
|
|
232
|
+
});
|
|
233
|
+
const missing = defaults.filter((item) => !seen.has(item.widgetKey));
|
|
234
|
+
return [...normalized, ...missing];
|
|
235
|
+
}
|
|
236
|
+
function defaultDashboardWidgetLayout(viewKey) {
|
|
237
|
+
return DASHBOARD_WIDGET_KEYS_BY_VIEW[viewKey].map((widgetKey) => ({
|
|
238
|
+
widgetKey,
|
|
239
|
+
visible: true,
|
|
240
|
+
size: defaultDashboardWidgetSize(widgetKey),
|
|
241
|
+
}));
|
|
242
|
+
}
|
|
243
|
+
function defaultDashboardWidgetSize(widgetKey) {
|
|
244
|
+
if (widgetKey === "overview_metrics" || widgetKey === "overview_services" || widgetKey === "risks_table") {
|
|
245
|
+
return "full";
|
|
246
|
+
}
|
|
247
|
+
if (widgetKey === "today_main" || widgetKey === "forecast_table") {
|
|
248
|
+
return "wide";
|
|
249
|
+
}
|
|
250
|
+
if (widgetKey === "forecast_breakdown" || widgetKey === "today_rail") {
|
|
251
|
+
return "compact";
|
|
252
|
+
}
|
|
253
|
+
return "normal";
|
|
254
|
+
}
|
|
255
|
+
function parseDashboardWidgetSize(value, fallback) {
|
|
256
|
+
return typeof value === "string" && DASHBOARD_WIDGET_SIZES.includes(value)
|
|
257
|
+
? value
|
|
258
|
+
: fallback;
|
|
259
|
+
}
|
|
260
|
+
function parseDashboardBudgetPreferences(value) {
|
|
261
|
+
const record = isRecord(value) ? value : {};
|
|
262
|
+
const monthlyBudgetMinor = parseOptionalPositiveInteger(record.monthlyBudgetMinor);
|
|
263
|
+
const warningPercent = clampNumber(record.warningPercent, 1, 999, DEFAULT_NOTIFICATION_PREFERENCES.dashboard.budget.warningPercent);
|
|
264
|
+
const criticalPercent = clampNumber(record.criticalPercent, warningPercent, 999, DEFAULT_NOTIFICATION_PREFERENCES.dashboard.budget.criticalPercent);
|
|
265
|
+
return {
|
|
266
|
+
monthlyBudgetMinor,
|
|
267
|
+
currency: parseCurrency(record.currency, DEFAULT_NOTIFICATION_PREFERENCES.dashboard.budget.currency),
|
|
268
|
+
warningPercent,
|
|
269
|
+
criticalPercent,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
function parseHudPreferences(value, fallbackSelectedWidgets = DEFAULT_NOTIFICATION_PREFERENCES.hud.selectedWidgets) {
|
|
273
|
+
const record = isRecord(value) ? value : {};
|
|
274
|
+
return {
|
|
275
|
+
alwaysOnTop: typeof record.alwaysOnTop === "boolean"
|
|
276
|
+
? record.alwaysOnTop
|
|
277
|
+
: DEFAULT_NOTIFICATION_PREFERENCES.hud.alwaysOnTop,
|
|
278
|
+
fontScale: clampNumber(record.fontScale, 0.8, 1.3, DEFAULT_NOTIFICATION_PREFERENCES.hud.fontScale),
|
|
279
|
+
opacity: clampNumber(record.opacity, 0, 1, DEFAULT_NOTIFICATION_PREFERENCES.hud.opacity),
|
|
280
|
+
selectedWidgets: parseSelectedWidgets(record.selectedWidgets, fallbackSelectedWidgets),
|
|
281
|
+
};
|
|
282
|
+
}
|
|
283
|
+
function parseLocalCliDashboardMetricKeys(value, fallbackMetricKeys = DEFAULT_LOCAL_CLI_DASHBOARD_METRIC_KEYS) {
|
|
284
|
+
const metricKeys = new Set(LOCAL_CLI_DASHBOARD_METRIC_KEYS);
|
|
285
|
+
const selected = Array.isArray(value)
|
|
286
|
+
? value.filter((item) => typeof item === "string" && metricKeys.has(item))
|
|
287
|
+
: [...fallbackMetricKeys];
|
|
288
|
+
return selected.length === 0 ? [...fallbackMetricKeys] : [...new Set(selected)];
|
|
289
|
+
}
|
|
290
|
+
function parseDigestInterval(value) {
|
|
291
|
+
return value === "six-hours" || value === "daily" || value === "weekly"
|
|
292
|
+
? value
|
|
293
|
+
: DEFAULT_NOTIFICATION_PREFERENCES.digestInterval;
|
|
294
|
+
}
|
|
295
|
+
function parseQuietHours(value) {
|
|
296
|
+
const record = isRecord(value) ? value : {};
|
|
297
|
+
return {
|
|
298
|
+
start: parseTime(record.start, DEFAULT_NOTIFICATION_PREFERENCES.quietHours.start),
|
|
299
|
+
end: parseTime(record.end, DEFAULT_NOTIFICATION_PREFERENCES.quietHours.end),
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
function parseSelectedWidgets(value, fallbackSelectedWidgets = DEFAULT_SELECTED_NOTIFICATION_WIDGET_KEYS) {
|
|
303
|
+
const widgetKeys = new Set(NOTIFICATION_WIDGET_KEYS);
|
|
304
|
+
const selected = Array.isArray(value)
|
|
305
|
+
? value.filter((item) => typeof item === "string" && widgetKeys.has(item))
|
|
306
|
+
: [...fallbackSelectedWidgets];
|
|
307
|
+
if (selected.length === 0) {
|
|
308
|
+
return [...fallbackSelectedWidgets];
|
|
309
|
+
}
|
|
310
|
+
const uniqueSelected = [...new Set(selected)];
|
|
311
|
+
return isLegacySelectedWidgetDefault(uniqueSelected)
|
|
312
|
+
? [...DEFAULT_SELECTED_NOTIFICATION_WIDGET_KEYS]
|
|
313
|
+
: migrateSelectedWidgets(uniqueSelected);
|
|
314
|
+
}
|
|
315
|
+
function migrateSelectedWidgets(selectedWidgets) {
|
|
316
|
+
if (!selectedWidgets.includes("codex_reset_credit_expiry") ||
|
|
317
|
+
selectedWidgets.includes("codex_reset_credit_count")) {
|
|
318
|
+
return [...selectedWidgets];
|
|
319
|
+
}
|
|
320
|
+
const migrated = [];
|
|
321
|
+
for (const widgetKey of selectedWidgets) {
|
|
322
|
+
if (widgetKey === "codex_reset_credit_expiry") {
|
|
323
|
+
migrated.push("codex_reset_credit_count");
|
|
324
|
+
}
|
|
325
|
+
migrated.push(widgetKey);
|
|
326
|
+
}
|
|
327
|
+
return migrated;
|
|
328
|
+
}
|
|
329
|
+
function isLegacySelectedWidgetDefault(selectedWidgets) {
|
|
330
|
+
return LEGACY_SELECTED_NOTIFICATION_WIDGET_KEY_SETS.some((legacySet) => legacySet.length === selectedWidgets.length &&
|
|
331
|
+
legacySet.every((widgetKey, index) => selectedWidgets[index] === widgetKey));
|
|
332
|
+
}
|
|
333
|
+
function parseThresholdRules(value) {
|
|
334
|
+
if (!Array.isArray(value)) {
|
|
335
|
+
return DEFAULT_NOTIFICATION_THRESHOLD_RULES.map((rule) => ({ ...rule }));
|
|
336
|
+
}
|
|
337
|
+
const rules = value
|
|
338
|
+
.map((item) => isRecord(item) ? item : null)
|
|
339
|
+
.filter((item) => item !== null)
|
|
340
|
+
.map((item) => {
|
|
341
|
+
const widgetKey = parseWidgetKey(item.widgetKey);
|
|
342
|
+
const operator = parseOperator(item.operator);
|
|
343
|
+
const numericValue = parseNonNegativeNumber(item.value);
|
|
344
|
+
const cooldownMinutes = parseNonNegativeNumber(item.cooldownMinutes);
|
|
345
|
+
if (widgetKey === null || operator === null || numericValue === null || cooldownMinutes === null) {
|
|
346
|
+
return null;
|
|
347
|
+
}
|
|
348
|
+
return {
|
|
349
|
+
widgetKey,
|
|
350
|
+
operator,
|
|
351
|
+
value: numericValue,
|
|
352
|
+
cooldownMinutes,
|
|
353
|
+
};
|
|
354
|
+
})
|
|
355
|
+
.filter((item) => item !== null);
|
|
356
|
+
return rules.length === 0 ? DEFAULT_NOTIFICATION_THRESHOLD_RULES.map((rule) => ({ ...rule })) : rules;
|
|
357
|
+
}
|
|
358
|
+
function parseWidgetKey(value) {
|
|
359
|
+
return typeof value === "string" && NOTIFICATION_WIDGET_KEYS.includes(value)
|
|
360
|
+
? value
|
|
361
|
+
: null;
|
|
362
|
+
}
|
|
363
|
+
function parseOperator(value) {
|
|
364
|
+
return value === "gte" || value === "lte" || value === "eq" ? value : null;
|
|
365
|
+
}
|
|
366
|
+
function parseNonNegativeNumber(value) {
|
|
367
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
368
|
+
return null;
|
|
369
|
+
}
|
|
370
|
+
return Math.max(0, value);
|
|
371
|
+
}
|
|
372
|
+
function parseOptionalPositiveInteger(value) {
|
|
373
|
+
if (value === null || value === undefined || value === "") {
|
|
374
|
+
return null;
|
|
375
|
+
}
|
|
376
|
+
if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) {
|
|
377
|
+
return null;
|
|
378
|
+
}
|
|
379
|
+
return Math.round(value);
|
|
380
|
+
}
|
|
381
|
+
function parseCurrency(value, fallback) {
|
|
382
|
+
if (typeof value !== "string") {
|
|
383
|
+
return fallback;
|
|
384
|
+
}
|
|
385
|
+
const normalized = value.trim().toUpperCase();
|
|
386
|
+
return /^[A-Z]{3}$/.test(normalized) ? normalized : fallback;
|
|
387
|
+
}
|
|
388
|
+
function clampNumber(value, min, max, fallback) {
|
|
389
|
+
if (typeof value !== "number" || !Number.isFinite(value)) {
|
|
390
|
+
return fallback;
|
|
391
|
+
}
|
|
392
|
+
return Math.min(max, Math.max(min, Math.round(value * 100) / 100));
|
|
393
|
+
}
|
|
394
|
+
function parseTime(value, fallback) {
|
|
395
|
+
return typeof value === "string" && /^\d{2}:\d{2}$/.test(value) ? value : fallback;
|
|
396
|
+
}
|
|
397
|
+
function isRecord(value) {
|
|
398
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
399
|
+
}
|
|
400
|
+
//# sourceMappingURL=notification-preferences-model.js.map
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { type NotificationPreferenceFileOptions, type NotificationPreferences } from "./notification-preferences-model.js";
|
|
2
|
+
export { cloneNotificationPreferences, DEFAULT_NOTIFICATION_PREFERENCES, DEFAULT_NOTIFICATION_THRESHOLD_RULES, DEFAULT_LOCAL_CLI_DASHBOARD_METRIC_KEYS, DEFAULT_DASHBOARD_WIDGET_LAYOUTS, DEFAULT_SELECTED_NOTIFICATION_WIDGET_KEYS, DASHBOARD_VIEW_KEYS, DASHBOARD_WIDGET_KEYS_BY_VIEW, DASHBOARD_WIDGET_SIZES, LOCAL_CLI_DASHBOARD_METRIC_KEYS, NOTIFICATION_WIDGET_KEYS, parseNotificationPreferences, type DashboardBudgetPreferences, type DashboardDisplayPreferences, type DashboardViewKey, type DashboardWidgetKey, type DashboardWidgetLayoutItem, type DashboardWidgetLayoutPreferences, type DashboardWidgetSize, type DigestInterval, type LocalCliDashboardMetricKey, type NotificationPreferenceFileOptions, type NotificationPreferences, type NotificationThresholdRule, type NotificationWidgetKey, type ThresholdOperator, } from "./notification-preferences-model.js";
|
|
3
|
+
export declare function readNotificationPreferencesFile(options?: NotificationPreferenceFileOptions): Promise<NotificationPreferences>;
|
|
4
|
+
export declare function writeNotificationPreferencesFile(preferences: NotificationPreferences, options?: NotificationPreferenceFileOptions): Promise<NotificationPreferences>;
|
|
5
|
+
export declare function resolveNotificationPreferencesPath(options?: NotificationPreferenceFileOptions): string;
|
|
6
|
+
//# sourceMappingURL=notification-preferences.d.ts.map
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, isAbsolute, join } from "node:path";
|
|
3
|
+
import { cloneNotificationPreferences, DEFAULT_NOTIFICATION_PREFERENCES, parseNotificationPreferences, } from "./notification-preferences-model.js";
|
|
4
|
+
export { cloneNotificationPreferences, DEFAULT_NOTIFICATION_PREFERENCES, DEFAULT_NOTIFICATION_THRESHOLD_RULES, DEFAULT_LOCAL_CLI_DASHBOARD_METRIC_KEYS, DEFAULT_DASHBOARD_WIDGET_LAYOUTS, DEFAULT_SELECTED_NOTIFICATION_WIDGET_KEYS, DASHBOARD_VIEW_KEYS, DASHBOARD_WIDGET_KEYS_BY_VIEW, DASHBOARD_WIDGET_SIZES, LOCAL_CLI_DASHBOARD_METRIC_KEYS, NOTIFICATION_WIDGET_KEYS, parseNotificationPreferences, } from "./notification-preferences-model.js";
|
|
5
|
+
const PREFERENCES_PATH_ENV = "MONEYSIREN_NOTIFICATION_PREFS_PATH";
|
|
6
|
+
const DEFAULT_PREFERENCES_PATH = ".moneysiren/notification-preferences.json";
|
|
7
|
+
export async function readNotificationPreferencesFile(options = {}) {
|
|
8
|
+
try {
|
|
9
|
+
const parsed = JSON.parse(await readFile(resolveNotificationPreferencesPath(options), "utf8"));
|
|
10
|
+
return parseNotificationPreferences(parsed);
|
|
11
|
+
}
|
|
12
|
+
catch {
|
|
13
|
+
return cloneNotificationPreferences(DEFAULT_NOTIFICATION_PREFERENCES);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export async function writeNotificationPreferencesFile(preferences, options = {}) {
|
|
17
|
+
const normalized = parseNotificationPreferences(preferences);
|
|
18
|
+
const path = resolveNotificationPreferencesPath(options);
|
|
19
|
+
await mkdir(dirname(path), { recursive: true });
|
|
20
|
+
await writeFile(path, `${JSON.stringify(normalized, null, 2)}\n`, "utf8");
|
|
21
|
+
return normalized;
|
|
22
|
+
}
|
|
23
|
+
export function resolveNotificationPreferencesPath(options = {}) {
|
|
24
|
+
if (options.path !== undefined && options.path.trim().length > 0) {
|
|
25
|
+
return resolveLocalPath(options.path, options.cwd);
|
|
26
|
+
}
|
|
27
|
+
const configuredPath = options.env?.[PREFERENCES_PATH_ENV]?.trim();
|
|
28
|
+
if (configuredPath !== undefined && configuredPath.length > 0) {
|
|
29
|
+
return resolveLocalPath(configuredPath, options.cwd);
|
|
30
|
+
}
|
|
31
|
+
return resolveLocalPath(DEFAULT_PREFERENCES_PATH, options.cwd);
|
|
32
|
+
}
|
|
33
|
+
function resolveLocalPath(path, cwd = process.cwd()) {
|
|
34
|
+
return isAbsolute(path) ? path : join(cwd, path);
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=notification-preferences.js.map
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export type AggregateSyncStatus = "ok" | "partial" | "stale" | "error" | "empty";
|
|
2
|
+
export type RiskSeverity = "info" | "warning" | "critical";
|
|
3
|
+
export type SyncStateValue = "fresh" | "stale" | "error" | "not_configured" | "unavailable" | "locked";
|
|
4
|
+
export type SyncErrorCode = "not_configured" | "auth_expired" | "permission_denied" | "rate_limited" | "timeout" | "network" | "upstream_unavailable" | "schema_changed" | "invalid_data" | "local_source_missing" | "local_io" | "internal";
|
|
5
|
+
export interface SyncErrorView {
|
|
6
|
+
code: SyncErrorCode;
|
|
7
|
+
retryable: boolean;
|
|
8
|
+
userActionRequired: boolean;
|
|
9
|
+
message: string;
|
|
10
|
+
}
|
|
11
|
+
export interface ItemSyncView {
|
|
12
|
+
state: SyncStateValue;
|
|
13
|
+
observedAt: string | null;
|
|
14
|
+
lastAttemptAt: string | null;
|
|
15
|
+
lastSuccessAt: string | null;
|
|
16
|
+
freshUntil: string | null;
|
|
17
|
+
staleUntil: string | null;
|
|
18
|
+
ageSeconds: number | null;
|
|
19
|
+
source: string;
|
|
20
|
+
error: SyncErrorView | null;
|
|
21
|
+
lastRefreshFailed: boolean;
|
|
22
|
+
}
|
|
23
|
+
export declare function createSyncError(code: SyncErrorCode, message?: string): SyncErrorView;
|
|
24
|
+
export declare function syncViewFromFreshness(options: {
|
|
25
|
+
freshness: "live" | "stale" | "error" | "unavailable" | "not_configured" | "locked";
|
|
26
|
+
checkedAt: string | null;
|
|
27
|
+
generatedAt: string;
|
|
28
|
+
ttlSeconds?: number | null;
|
|
29
|
+
source: string;
|
|
30
|
+
message?: string | null;
|
|
31
|
+
lastAttemptAt?: string | null;
|
|
32
|
+
lastSuccessAt?: string | null;
|
|
33
|
+
freshUntil?: string | null;
|
|
34
|
+
staleUntil?: string | null;
|
|
35
|
+
lastRefreshFailed?: boolean;
|
|
36
|
+
}): ItemSyncView;
|
|
37
|
+
export declare function summarizeAggregateSync(items: readonly ItemSyncView[]): {
|
|
38
|
+
status: AggregateSyncStatus;
|
|
39
|
+
freshCount: number;
|
|
40
|
+
staleCount: number;
|
|
41
|
+
errorCount: number;
|
|
42
|
+
neutralCount: number;
|
|
43
|
+
lastSuccessAt: string | null;
|
|
44
|
+
};
|
|
45
|
+
export declare function syncStateFromFreshness(freshness: "live" | "stale" | "error" | "unavailable" | "not_configured" | "locked"): SyncStateValue;
|
|
46
|
+
export declare function isNeutralSyncState(state: SyncStateValue): boolean;
|
|
47
|
+
//# sourceMappingURL=sync-state.d.ts.map
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
export function createSyncError(code, message) {
|
|
2
|
+
return {
|
|
3
|
+
code,
|
|
4
|
+
retryable: isRetryableSyncError(code),
|
|
5
|
+
userActionRequired: isUserActionRequiredSyncError(code),
|
|
6
|
+
message: sanitizeSyncMessage(message ?? defaultSyncErrorMessage(code)),
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
export function syncViewFromFreshness(options) {
|
|
10
|
+
const state = syncStateFromFreshness(options.freshness);
|
|
11
|
+
const observedAt = options.checkedAt;
|
|
12
|
+
const ageSeconds = observedAt === null
|
|
13
|
+
? null
|
|
14
|
+
: Math.max(0, Math.floor((Date.parse(options.generatedAt) - Date.parse(observedAt)) / 1000));
|
|
15
|
+
const defaultFreshUntil = observedAt === null || options.ttlSeconds === null || options.ttlSeconds === undefined
|
|
16
|
+
? null
|
|
17
|
+
: new Date(Date.parse(observedAt) + options.ttlSeconds * 1000).toISOString();
|
|
18
|
+
return {
|
|
19
|
+
state,
|
|
20
|
+
observedAt,
|
|
21
|
+
lastAttemptAt: options.lastAttemptAt ?? observedAt,
|
|
22
|
+
lastSuccessAt: options.lastSuccessAt ?? (state === "error" ? null : observedAt),
|
|
23
|
+
freshUntil: options.freshUntil ?? defaultFreshUntil,
|
|
24
|
+
staleUntil: options.staleUntil ?? null,
|
|
25
|
+
ageSeconds: Number.isFinite(ageSeconds) ? ageSeconds : null,
|
|
26
|
+
source: options.source,
|
|
27
|
+
error: state === "error" || state === "locked" || state === "not_configured"
|
|
28
|
+
? createSyncError(errorCodeFromState(state, options.message), options.message ?? undefined)
|
|
29
|
+
: null,
|
|
30
|
+
lastRefreshFailed: options.lastRefreshFailed ?? state === "error",
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export function summarizeAggregateSync(items) {
|
|
34
|
+
const actionable = items.filter((item) => !isNeutralSyncState(item.state));
|
|
35
|
+
const freshCount = actionable.filter((item) => item.state === "fresh").length;
|
|
36
|
+
const staleCount = actionable.filter((item) => item.state === "stale").length;
|
|
37
|
+
const errorCount = actionable.filter((item) => item.state === "error" || item.state === "locked").length;
|
|
38
|
+
const neutralCount = items.length - actionable.length;
|
|
39
|
+
const lastSuccessAt = latestIso(items.map((item) => item.lastSuccessAt).filter((value) => value !== null));
|
|
40
|
+
const status = actionable.length === 0
|
|
41
|
+
? "empty"
|
|
42
|
+
: errorCount > 0 && (freshCount > 0 || staleCount > 0)
|
|
43
|
+
? "partial"
|
|
44
|
+
: errorCount === actionable.length
|
|
45
|
+
? "error"
|
|
46
|
+
: freshCount > 0 && staleCount > 0
|
|
47
|
+
? "partial"
|
|
48
|
+
: staleCount === actionable.length
|
|
49
|
+
? "stale"
|
|
50
|
+
: "ok";
|
|
51
|
+
return {
|
|
52
|
+
status,
|
|
53
|
+
freshCount,
|
|
54
|
+
staleCount,
|
|
55
|
+
errorCount,
|
|
56
|
+
neutralCount,
|
|
57
|
+
lastSuccessAt,
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
export function syncStateFromFreshness(freshness) {
|
|
61
|
+
if (freshness === "live") {
|
|
62
|
+
return "fresh";
|
|
63
|
+
}
|
|
64
|
+
if (freshness === "not_configured" || freshness === "unavailable" || freshness === "locked") {
|
|
65
|
+
return freshness;
|
|
66
|
+
}
|
|
67
|
+
return freshness;
|
|
68
|
+
}
|
|
69
|
+
export function isNeutralSyncState(state) {
|
|
70
|
+
return state === "not_configured" || state === "unavailable";
|
|
71
|
+
}
|
|
72
|
+
function errorCodeFromState(state, message) {
|
|
73
|
+
if (state === "not_configured") {
|
|
74
|
+
return "not_configured";
|
|
75
|
+
}
|
|
76
|
+
if (state === "locked") {
|
|
77
|
+
return "local_io";
|
|
78
|
+
}
|
|
79
|
+
if (message !== undefined && message !== null) {
|
|
80
|
+
const normalized = message.toLowerCase();
|
|
81
|
+
if (normalized.includes("permission") || normalized.includes("403")) {
|
|
82
|
+
return "permission_denied";
|
|
83
|
+
}
|
|
84
|
+
if (normalized.includes("401") || normalized.includes("expired")) {
|
|
85
|
+
return "auth_expired";
|
|
86
|
+
}
|
|
87
|
+
if (normalized.includes("429") || normalized.includes("rate limit")) {
|
|
88
|
+
return "rate_limited";
|
|
89
|
+
}
|
|
90
|
+
if (normalized.includes("timeout")) {
|
|
91
|
+
return "timeout";
|
|
92
|
+
}
|
|
93
|
+
if (normalized.includes("network") || normalized.includes("enotfound") || normalized.includes("econn")) {
|
|
94
|
+
return "network";
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return "internal";
|
|
98
|
+
}
|
|
99
|
+
function isRetryableSyncError(code) {
|
|
100
|
+
return code === "rate_limited" || code === "timeout" || code === "network" || code === "upstream_unavailable";
|
|
101
|
+
}
|
|
102
|
+
function isUserActionRequiredSyncError(code) {
|
|
103
|
+
return code === "not_configured" ||
|
|
104
|
+
code === "auth_expired" ||
|
|
105
|
+
code === "permission_denied" ||
|
|
106
|
+
code === "local_source_missing" ||
|
|
107
|
+
code === "local_io";
|
|
108
|
+
}
|
|
109
|
+
function defaultSyncErrorMessage(code) {
|
|
110
|
+
if (code === "auth_expired") {
|
|
111
|
+
return "Login may have expired. Sign in again and retry.";
|
|
112
|
+
}
|
|
113
|
+
if (code === "permission_denied") {
|
|
114
|
+
return "Permission is not sufficient for this read-only check.";
|
|
115
|
+
}
|
|
116
|
+
if (code === "not_configured" || code === "local_source_missing") {
|
|
117
|
+
return "Local source or credential is not configured.";
|
|
118
|
+
}
|
|
119
|
+
if (code === "rate_limited") {
|
|
120
|
+
return "Provider request limit was reached. Retry later.";
|
|
121
|
+
}
|
|
122
|
+
if (code === "schema_changed") {
|
|
123
|
+
return "Provider response shape changed.";
|
|
124
|
+
}
|
|
125
|
+
return "Live sync failed.";
|
|
126
|
+
}
|
|
127
|
+
function sanitizeSyncMessage(value) {
|
|
128
|
+
return value
|
|
129
|
+
.replace(/https:\/\/hooks\.slack\.com\/services\/[A-Za-z0-9/_-]+/g, "[redacted]")
|
|
130
|
+
.replace(/\b(?:sk|sbp|xox[baprs])[-_][A-Za-z0-9_-]+\b/gi, "[redacted]")
|
|
131
|
+
.replace(/\bacct[_-][A-Za-z0-9_-]+\b/gi, "[redacted]")
|
|
132
|
+
.replace(/\b(?:proj|project|invoice)[_-][A-Za-z0-9_-]+\b/gi, "[redacted]")
|
|
133
|
+
.replace(/[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}/gi, "[redacted]");
|
|
134
|
+
}
|
|
135
|
+
function latestIso(values) {
|
|
136
|
+
return values.length === 0
|
|
137
|
+
? null
|
|
138
|
+
: [...values].sort((first, second) => second.localeCompare(first))[0] ?? null;
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=sync-state.js.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface UsageProgressView {
|
|
2
|
+
usedPercent: number | null;
|
|
3
|
+
remainingPercent: number | null;
|
|
4
|
+
warningAtPercent: number;
|
|
5
|
+
criticalAtPercent: number;
|
|
6
|
+
}
|
|
7
|
+
export type UsageProgressSeverity = "info" | "warning" | "critical";
|
|
8
|
+
export declare function usageProgressFromUsedPercent(value: number | null | undefined, thresholds?: {
|
|
9
|
+
warningAtPercent?: number;
|
|
10
|
+
criticalAtPercent?: number;
|
|
11
|
+
}): UsageProgressView;
|
|
12
|
+
export declare function usageProgressFromRemainingPercent(value: number | null | undefined, thresholds?: {
|
|
13
|
+
warningAtPercent?: number;
|
|
14
|
+
criticalAtPercent?: number;
|
|
15
|
+
}): UsageProgressView;
|
|
16
|
+
export declare function usageProgressFromTokens(usedTokens: number | null | undefined, remainingTokens: number | null | undefined, thresholds?: {
|
|
17
|
+
warningAtPercent?: number;
|
|
18
|
+
criticalAtPercent?: number;
|
|
19
|
+
}): UsageProgressView;
|
|
20
|
+
export declare function usageProgressSeverity(progress: UsageProgressView): UsageProgressSeverity;
|
|
21
|
+
export declare function normalizePercent(value: number | null | undefined): number | null;
|
|
22
|
+
//# sourceMappingURL=usage-progress.d.ts.map
|