@aliou/pi-neuralwatt 0.7.6 → 0.8.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.
Files changed (37) hide show
  1. package/README.md +4 -2
  2. package/{src/extensions → extensions}/command-quotas/command.ts +2 -2
  3. package/extensions/command-quotas/components/progress-bar.ts +38 -0
  4. package/{src/extensions → extensions}/command-quotas/components/quota-tabs.ts +4 -4
  5. package/{src/extensions → extensions}/command-quotas/components/quotas-display.ts +1 -1
  6. package/{src/extensions → extensions}/command-quotas/index.ts +3 -3
  7. package/extensions/provider/commands/settings/index.ts +246 -0
  8. package/{src/extensions → extensions}/provider/index.ts +28 -20
  9. package/{src/extensions → extensions}/provider/models/hidden.ts +3 -3
  10. package/{src/extensions → extensions}/provider/quota-store.ts +4 -4
  11. package/{src/extensions → extensions}/provider/sse-quotas.ts +1 -1
  12. package/{src/extensions → extensions}/quota-warnings/index.ts +6 -7
  13. package/{src/extensions → extensions}/quota-warnings/notifier.ts +2 -2
  14. package/{src/extensions → extensions}/sub-bar-integration/index.ts +9 -10
  15. package/{src/extensions → extensions}/sub-bar-integration/snapshot.ts +3 -3
  16. package/package.json +20 -14
  17. package/schema.json +50 -6
  18. package/src/config/defaults.ts +17 -0
  19. package/src/config/index.ts +9 -0
  20. package/src/config/loader.ts +74 -0
  21. package/src/config/migration/01-disable-legacy-model-ids-by-default.ts +44 -0
  22. package/src/config/migration/02-flat-to-nested-config.ts +149 -0
  23. package/src/config/migration/index.ts +16 -0
  24. package/src/config/types.ts +77 -0
  25. package/src/{types/quota-events.ts → events.ts} +25 -13
  26. package/src/lib/neuralwatt-api.ts +1 -1
  27. package/src/types/quota-result.ts +12 -0
  28. package/src/utils/quota-bar.ts +0 -38
  29. package/src/config.ts +0 -210
  30. /package/{src/lib/env.ts → extensions/_shared/auth.ts} +0 -0
  31. /package/{src/extensions → extensions}/provider/context-overflow.ts +0 -0
  32. /package/{src/extensions → extensions}/provider/models/cache.ts +0 -0
  33. /package/{src/extensions → extensions}/provider/models/index.ts +0 -0
  34. /package/{src/extensions → extensions}/provider/models/legacy.ts +0 -0
  35. /package/{src/extensions → extensions}/provider/models/public-models.ts +0 -0
  36. /package/{src/extensions → extensions}/provider/rate-limit-error.ts +0 -0
  37. /package/{src/extensions → extensions}/provider/stream-simple.ts +0 -0
package/README.md CHANGED
@@ -36,7 +36,7 @@ pi install npm:@aliou/pi-neuralwatt
36
36
  pi install git:github.com/aliou/pi-neuralwatt
37
37
 
38
38
  # Local development
39
- pi -e ./src/extensions/provider/index.ts
39
+ pi -e ./extensions/provider/index.ts
40
40
  ```
41
41
 
42
42
  ## Usage
@@ -80,9 +80,11 @@ Configure features with `/neuralwatt:settings`:
80
80
 
81
81
  The provider itself cannot be disabled — it is always loaded.
82
82
 
83
+ Configuration uses nested per-feature sections. Existing flat config files are migrated automatically, with a backup written next to the migrated config.
84
+
83
85
  ## Adding or Updating Models
84
86
 
85
- Models are hardcoded in `src/extensions/provider/models.ts` and validated against the live API. To update:
87
+ Models are hardcoded in `extensions/provider/models/public-models.ts` and validated against the live API. To update:
86
88
 
87
89
  1. Run `pnpm test` — it fetches `/v1/models` and compares against hardcoded definitions
88
90
  2. Fix any discrepancies (missing models, changed context windows)
@@ -3,8 +3,8 @@ import {
3
3
  type ExtensionAPI,
4
4
  getAgentDir,
5
5
  } from "@earendil-works/pi-coding-agent";
6
- import { getNeuralwattApiKey } from "../../lib/env";
7
- import { fetchQuotas } from "../../lib/neuralwatt-api";
6
+ import { fetchQuotas } from "../../src/lib/neuralwatt-api";
7
+ import { getNeuralwattApiKey } from "../_shared/auth";
8
8
  import { QuotasComponent } from "./components/quotas-display";
9
9
 
10
10
  function missingAuthMessage(): string {
@@ -0,0 +1,38 @@
1
+ import type { Theme } from "@earendil-works/pi-coding-agent";
2
+ import type { Severity } from "../../../src/utils/quota-bar";
3
+
4
+ export type BarStyle = "filled-used" | "filled-remaining";
5
+
6
+ /**
7
+ * Render a progress bar.
8
+ *
9
+ * filled-used: filled region = used portion (colored by severity of remaining%)
10
+ * filled-remaining: filled region = remaining portion (colored by severity of remaining%)
11
+ */
12
+ export function renderProgressBar(
13
+ percent: number,
14
+ width: number,
15
+ theme: Theme,
16
+ severity: Severity,
17
+ style: BarStyle = "filled-remaining",
18
+ ): string {
19
+ const clamped = Math.max(0, Math.min(100, Math.round(percent)));
20
+ const filledCount = Math.round((clamped / 100) * width);
21
+
22
+ const parts: string[] = [];
23
+ for (let idx = 0; idx < width; idx++) {
24
+ const isFilled = idx < filledCount;
25
+ if (style === "filled-used") {
26
+ // filled = used (severity color), empty = remaining (dim)
27
+ parts.push(
28
+ isFilled ? theme.fg(severity, "\u2593") : theme.fg("success", "\u2591"),
29
+ );
30
+ } else {
31
+ // filled = remaining (severity color), empty = used (dim)
32
+ parts.push(
33
+ isFilled ? theme.fg(severity, "\u2588") : theme.fg("dim", "\u2591"),
34
+ );
35
+ }
36
+ }
37
+ return parts.join("");
38
+ }
@@ -1,17 +1,17 @@
1
1
  import type { Theme } from "@earendil-works/pi-coding-agent";
2
2
  import { truncateToWidth } from "@earendil-works/pi-tui";
3
- import type { NeuralwattQuotas } from "../../../types/quota-api";
3
+ import type { NeuralwattQuotas } from "../../../src/types/quota-api";
4
4
  import {
5
5
  percentCreditsRemaining,
6
6
  percentEnergyRemaining,
7
- renderProgressBar,
8
7
  severityFromPercent,
9
- } from "../../../utils/quota-bar";
8
+ } from "../../../src/utils/quota-bar";
10
9
  import {
11
10
  formatKwh,
12
11
  formatTokens,
13
12
  formatUsd,
14
- } from "../../../utils/quota-format";
13
+ } from "../../../src/utils/quota-format";
14
+ import { renderProgressBar } from "./progress-bar";
15
15
 
16
16
  /**
17
17
  * Subscription tab — plan details, energy quota, billing period.
@@ -2,7 +2,7 @@ import type { Theme } from "@earendil-works/pi-coding-agent";
2
2
  import { DynamicBorder } from "@earendil-works/pi-coding-agent";
3
3
  import type { Component, TUI } from "@earendil-works/pi-tui";
4
4
  import { Loader, matchesKey, truncateToWidth } from "@earendil-works/pi-tui";
5
- import type { NeuralwattQuotas } from "../../../types/quota-api";
5
+ import type { NeuralwattQuotas } from "../../../src/types/quota-api";
6
6
  import {
7
7
  renderCreditsTab,
8
8
  renderSubscriptionTab,
@@ -1,9 +1,9 @@
1
1
  import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
2
+ import { configLoader } from "../../src/config";
2
3
  import {
3
- configLoader,
4
4
  NEURALWATT_EXTENSIONS_REGISTER_EVENT,
5
5
  NEURALWATT_EXTENSIONS_REQUEST_EVENT,
6
- } from "../../config";
6
+ } from "../../src/events";
7
7
  import { registerQuotasCommand } from "./command";
8
8
 
9
9
  export default async function (pi: ExtensionAPI) {
@@ -11,7 +11,7 @@ export default async function (pi: ExtensionAPI) {
11
11
 
12
12
  const config = configLoader.getConfig();
13
13
 
14
- if (config.quotaCommand) {
14
+ if (config.quotaCommand.enabled) {
15
15
  registerQuotasCommand(pi);
16
16
  }
17
17
 
@@ -0,0 +1,246 @@
1
+ import {
2
+ registerSettingsCommand,
3
+ type SettingsSection,
4
+ } from "@aliou/pi-utils-settings";
5
+ import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
6
+ import type { SettingItem } from "@earendil-works/pi-tui";
7
+ import {
8
+ configLoader,
9
+ type NeuralwattConfig,
10
+ type NeuralwattRawConfig,
11
+ type ResolvedNeuralwattConfig,
12
+ } from "../../../../src/config";
13
+ import {
14
+ NEURALWATT_CONFIG_UPDATED_EVENT,
15
+ type NeuralwattFeatureId,
16
+ } from "../../../../src/events";
17
+
18
+ export interface RegisterNeuralwattSettingsOptions {
19
+ getLoadedFeatures: () => Set<NeuralwattFeatureId>;
20
+ }
21
+
22
+ function emitConfigUpdated(pi: ExtensionAPI): void {
23
+ pi.events.emit(NEURALWATT_CONFIG_UPDATED_EVENT, {
24
+ config: configLoader.getConfig(),
25
+ });
26
+ }
27
+
28
+ function featureRow(
29
+ id: NeuralwattFeatureId,
30
+ label: string,
31
+ description: string,
32
+ configValue: boolean,
33
+ isLoaded: boolean,
34
+ ): SettingItem {
35
+ if (isLoaded) {
36
+ return {
37
+ id,
38
+ label,
39
+ description,
40
+ currentValue: configValue ? "enabled" : "disabled",
41
+ values: ["enabled", "disabled"],
42
+ };
43
+ }
44
+ return {
45
+ id,
46
+ label,
47
+ description: `${description} (Not loaded by Pi)`,
48
+ currentValue: "unavailable",
49
+ values: [],
50
+ };
51
+ }
52
+
53
+ function optionalFeatureValue(value: unknown): boolean | undefined {
54
+ if (typeof value === "boolean") return value;
55
+ if (value && typeof value === "object") {
56
+ const enabled = (value as { enabled?: boolean }).enabled;
57
+ if (typeof enabled === "boolean") return enabled;
58
+ }
59
+ return undefined;
60
+ }
61
+
62
+ function featureValue(value: unknown, fallback: boolean): boolean {
63
+ return optionalFeatureValue(value) ?? fallback;
64
+ }
65
+
66
+ function toNestedConfig(config: NeuralwattRawConfig): NeuralwattConfig {
67
+ const provider = "provider" in config ? config.provider : undefined;
68
+
69
+ return {
70
+ provider: {
71
+ ...(provider ?? {}),
72
+ includeLegacyModelIds:
73
+ provider?.includeLegacyModelIds ??
74
+ ("includeLegacyModelIds" in config
75
+ ? config.includeLegacyModelIds
76
+ : undefined),
77
+ includeHiddenModels:
78
+ provider?.includeHiddenModels ??
79
+ ("includeHiddenModels" in config
80
+ ? config.includeHiddenModels
81
+ : undefined),
82
+ },
83
+ quotaCommand: {
84
+ ...(typeof config.quotaCommand === "object" ? config.quotaCommand : {}),
85
+ enabled: optionalFeatureValue(config.quotaCommand),
86
+ },
87
+ quotaWarnings: {
88
+ ...(typeof config.quotaWarnings === "object" ? config.quotaWarnings : {}),
89
+ enabled: optionalFeatureValue(config.quotaWarnings),
90
+ },
91
+ subBarIntegration: {
92
+ ...(typeof config.subBarIntegration === "object"
93
+ ? config.subBarIntegration
94
+ : {}),
95
+ enabled: optionalFeatureValue(config.subBarIntegration),
96
+ },
97
+ };
98
+ }
99
+
100
+ export function registerNeuralwattSettings(
101
+ pi: ExtensionAPI,
102
+ options: RegisterNeuralwattSettingsOptions,
103
+ ): void {
104
+ const { getLoadedFeatures } = options;
105
+
106
+ registerSettingsCommand<NeuralwattRawConfig, ResolvedNeuralwattConfig>(pi, {
107
+ commandName: "neuralwatt:settings",
108
+ title: "Neuralwatt Settings",
109
+ configStore: configLoader,
110
+ buildSections: (tabConfig, resolved): SettingsSection[] => {
111
+ const loaded = getLoadedFeatures();
112
+ return [
113
+ {
114
+ label: "Features",
115
+ items: [
116
+ featureRow(
117
+ "quotaCommand",
118
+ "Quota command",
119
+ "Toggle the /neuralwatt:quota command, showing your API usage at a glance",
120
+ featureValue(
121
+ tabConfig?.quotaCommand,
122
+ resolved.quotaCommand.enabled,
123
+ ),
124
+ loaded.has("quotaCommand"),
125
+ ),
126
+ featureRow(
127
+ "quotaWarnings",
128
+ "Quota warnings",
129
+ "Toggle notifications when credits or energy are running low",
130
+ featureValue(
131
+ tabConfig?.quotaWarnings,
132
+ resolved.quotaWarnings.enabled,
133
+ ),
134
+ loaded.has("quotaWarnings"),
135
+ ),
136
+ featureRow(
137
+ "subBarIntegration",
138
+ "Sub-bar integration",
139
+ "Toggle integration with the status bar and sub-core",
140
+ featureValue(
141
+ tabConfig?.subBarIntegration,
142
+ resolved.subBarIntegration.enabled,
143
+ ),
144
+ loaded.has("subBarIntegration"),
145
+ ),
146
+ ],
147
+ },
148
+ {
149
+ label: "Other settings",
150
+ items: [
151
+ {
152
+ id: "includeLegacyModelIds",
153
+ label: "Legacy model IDs",
154
+ description:
155
+ "Include deprecated Neuralwatt model IDs as aliases in the model picker",
156
+ currentValue:
157
+ ((tabConfig &&
158
+ "provider" in tabConfig &&
159
+ tabConfig.provider?.includeLegacyModelIds) ??
160
+ (tabConfig &&
161
+ "includeLegacyModelIds" in tabConfig &&
162
+ tabConfig.includeLegacyModelIds) ??
163
+ resolved.provider.includeLegacyModelIds)
164
+ ? "include"
165
+ : "ignore",
166
+ values: ["include", "ignore"],
167
+ },
168
+ {
169
+ id: "includeHiddenModels",
170
+ label: "Hidden models",
171
+ description:
172
+ "Include Neuralwatt models that are accessible via API key but not advertised in the public model list",
173
+ currentValue:
174
+ ((tabConfig &&
175
+ "provider" in tabConfig &&
176
+ tabConfig.provider?.includeHiddenModels) ??
177
+ (tabConfig &&
178
+ "includeHiddenModels" in tabConfig &&
179
+ tabConfig.includeHiddenModels) ??
180
+ resolved.provider.includeHiddenModels)
181
+ ? "include"
182
+ : "ignore",
183
+ values: ["include", "ignore"],
184
+ },
185
+ ],
186
+ },
187
+ ];
188
+ },
189
+ onSettingChange: (id, newValue, config) => {
190
+ // Non-feature toggles are handled first so they are not blocked by the
191
+ // loaded-features guard (they are managed directly by the provider).
192
+ if (id === "includeLegacyModelIds") {
193
+ const nestedConfig = toNestedConfig(config);
194
+ return {
195
+ ...nestedConfig,
196
+ provider: {
197
+ ...nestedConfig.provider,
198
+ includeLegacyModelIds: newValue === "include",
199
+ },
200
+ };
201
+ }
202
+
203
+ if (id === "includeHiddenModels") {
204
+ const nestedConfig = toNestedConfig(config);
205
+ return {
206
+ ...nestedConfig,
207
+ provider: {
208
+ ...nestedConfig.provider,
209
+ includeHiddenModels: newValue === "include",
210
+ },
211
+ };
212
+ }
213
+
214
+ if (!getLoadedFeatures().has(id as NeuralwattFeatureId)) {
215
+ return null;
216
+ }
217
+
218
+ const enabled = newValue === "enabled";
219
+ switch (id) {
220
+ case "quotaCommand":
221
+ return {
222
+ ...toNestedConfig(config),
223
+ quotaCommand: { ...toNestedConfig(config).quotaCommand, enabled },
224
+ };
225
+ case "quotaWarnings":
226
+ return {
227
+ ...toNestedConfig(config),
228
+ quotaWarnings: { ...toNestedConfig(config).quotaWarnings, enabled },
229
+ };
230
+ case "subBarIntegration":
231
+ return {
232
+ ...toNestedConfig(config),
233
+ subBarIntegration: {
234
+ ...toNestedConfig(config).subBarIntegration,
235
+ enabled,
236
+ },
237
+ };
238
+ default:
239
+ return null;
240
+ }
241
+ },
242
+ onSave: async () => {
243
+ emitConfigUpdated(pi);
244
+ },
245
+ });
246
+ }
@@ -1,25 +1,22 @@
1
- import { getApiProvider } from "@earendil-works/pi-ai";
1
+ import { getApiProvider } from "@earendil-works/pi-ai/compat";
2
2
  import type {
3
3
  ExtensionAPI,
4
4
  ProviderModelConfig,
5
5
  } from "@earendil-works/pi-coding-agent";
6
+ import { configLoader } from "../../src/config";
6
7
  import {
7
- configLoader,
8
- emitConfigUpdated,
9
8
  NEURALWATT_CONFIG_UPDATED_EVENT,
10
9
  NEURALWATT_EXTENSIONS_REGISTER_EVENT,
11
10
  NEURALWATT_EXTENSIONS_REQUEST_EVENT,
12
- type NeuralwattFeatureId,
13
- registerNeuralwattSettings,
14
- } from "../../config";
15
- import { getNeuralwattApiKey } from "../../lib/env";
16
- import { fetchQuotas } from "../../lib/neuralwatt-api";
17
- import type { NeuralwattQuotas } from "../../types/quota-api";
18
- import {
19
11
  NEURALWATT_QUOTAS_REQUEST_EVENT,
20
12
  NEURALWATT_QUOTAS_UPDATED_EVENT,
13
+ type NeuralwattFeatureId,
21
14
  type NeuralwattQuotasUpdatedPayload,
22
- } from "../../types/quota-events";
15
+ } from "../../src/events";
16
+ import { fetchQuotas } from "../../src/lib/neuralwatt-api";
17
+ import type { NeuralwattQuotas } from "../../src/types/quota-api";
18
+ import { getNeuralwattApiKey } from "../_shared/auth";
19
+ import { registerNeuralwattSettings } from "./commands/settings";
23
20
  import { normalizeNeuralwattContextOverflowError } from "./context-overflow";
24
21
  import {
25
22
  getNeuralwattModels,
@@ -38,16 +35,23 @@ import { wrapNeuralwattStreamSimple } from "./stream-simple";
38
35
 
39
36
  const HEADER_EMIT_THROTTLE_MS = 5_000;
40
37
 
38
+ function emitConfigUpdated(pi: ExtensionAPI): void {
39
+ pi.events.emit(NEURALWATT_CONFIG_UPDATED_EVENT, {
40
+ config: configLoader.getConfig(),
41
+ });
42
+ }
43
+
41
44
  function registerNeuralwattProvider(
42
45
  pi: ExtensionAPI,
43
46
  onSseQuota: (line: string) => void,
44
47
  hiddenModels: ProviderModelConfig[] = [],
45
48
  ): void {
46
- const { includeLegacyModelIds, includeHiddenModels } =
47
- configLoader.getConfig();
49
+ const { provider: providerConfig } = configLoader.getConfig();
48
50
 
49
- const publicModels = getNeuralwattModels({ includeLegacyModelIds });
50
- const resolvedHiddenModels = includeHiddenModels
51
+ const publicModels = getNeuralwattModels({
52
+ includeLegacyModelIds: providerConfig.includeLegacyModelIds,
53
+ });
54
+ const resolvedHiddenModels = providerConfig.includeHiddenModels
51
55
  ? dedupeHiddenModels(hiddenModels, publicModels)
52
56
  : [];
53
57
 
@@ -109,7 +113,7 @@ export default async function (pi: ExtensionAPI) {
109
113
  // load time. `session_start` then revalidates from the live API and writes
110
114
  // the cache back. First run with no cache still warns once.
111
115
  let hiddenModels: ProviderModelConfig[] = [];
112
- if (configLoader.getConfig().includeHiddenModels) {
116
+ if (configLoader.getConfig().provider.includeHiddenModels) {
113
117
  hiddenModels = loadCachedHiddenModels();
114
118
  }
115
119
  let hiddenModelsLoaded = false;
@@ -139,7 +143,7 @@ export default async function (pi: ExtensionAPI) {
139
143
  // cache so previously discovered models are available immediately without
140
144
  // waiting for the next session_start revalidation.
141
145
  if (
142
- configLoader.getConfig().includeHiddenModels &&
146
+ configLoader.getConfig().provider.includeHiddenModels &&
143
147
  !hiddenModelsLoaded &&
144
148
  hiddenModels.length === 0
145
149
  ) {
@@ -257,15 +261,19 @@ export default async function (pi: ExtensionAPI) {
257
261
 
258
262
  pi.on("session_start", async (_event, ctx) => {
259
263
  pendingRateLimitInfo = undefined;
260
- for (const message of configLoader.drainMessages()) {
261
- ctx.ui.notify(message, "warning");
264
+ const messages = [...new Set(configLoader.drainMessages())];
265
+ if (messages.length > 0) {
266
+ ctx.ui.notify(messages.join("\n"), "info");
262
267
  }
263
268
 
264
269
  loadedFeatures.clear();
265
270
  pi.events.emit(NEURALWATT_EXTENSIONS_REQUEST_EVENT, undefined);
266
271
  emitConfigUpdated(pi);
267
272
 
268
- if (!hiddenModelsLoaded && configLoader.getConfig().includeHiddenModels) {
273
+ if (
274
+ !hiddenModelsLoaded &&
275
+ configLoader.getConfig().provider.includeHiddenModels
276
+ ) {
269
277
  hiddenModelsLoaded = true;
270
278
  hiddenModelsAbort?.abort();
271
279
  hiddenModelsAbort = new AbortController();
@@ -2,9 +2,9 @@ import type {
2
2
  AuthStorage,
3
3
  ProviderModelConfig,
4
4
  } from "@earendil-works/pi-coding-agent";
5
- import { getNeuralwattApiKey } from "../../../lib/env";
6
- import { fetchNeuralwattModels } from "../../../lib/neuralwatt-api";
7
- import type { NeuralwattApiModel } from "../../../types/models-api";
5
+ import { fetchNeuralwattModels } from "../../../src/lib/neuralwatt-api";
6
+ import type { NeuralwattApiModel } from "../../../src/types/models-api";
7
+ import { getNeuralwattApiKey } from "../../_shared/auth";
8
8
  import { NEURALWATT_MODELS } from "./public-models";
9
9
 
10
10
  // Per-ID overrides for known hidden models. The authenticated /v1/models endpoint
@@ -1,8 +1,8 @@
1
1
  import type { AuthStorage } from "@earendil-works/pi-coding-agent";
2
- import { getNeuralwattApiKey } from "../../lib/env";
3
- import { fetchQuotas } from "../../lib/neuralwatt-api";
4
- import type { NeuralwattQuotas } from "../../types/quota-api";
5
- import { parseQuotaHeaders } from "../../types/quota-events";
2
+ import { parseQuotaHeaders } from "../../src/events";
3
+ import { fetchQuotas } from "../../src/lib/neuralwatt-api";
4
+ import type { NeuralwattQuotas } from "../../src/types/quota-api";
5
+ import { getNeuralwattApiKey } from "../_shared/auth";
6
6
 
7
7
  export function buildQuotasFromHeaders(
8
8
  headers: Record<string, string>,
@@ -1,4 +1,4 @@
1
- import type { NeuralwattQuotas } from "../../types/quota-api";
1
+ import type { NeuralwattQuotas } from "../../src/types/quota-api";
2
2
 
3
3
  const JOULES_PER_KWH = 3_600_000;
4
4
 
@@ -2,29 +2,28 @@ import type {
2
2
  ExtensionAPI,
3
3
  ExtensionContext,
4
4
  } from "@earendil-works/pi-coding-agent";
5
+ import { configLoader } from "../../src/config";
5
6
  import {
6
- configLoader,
7
7
  NEURALWATT_CONFIG_UPDATED_EVENT,
8
8
  NEURALWATT_EXTENSIONS_REGISTER_EVENT,
9
9
  NEURALWATT_EXTENSIONS_REQUEST_EVENT,
10
- type NeuralwattConfigUpdatedPayload,
11
- } from "../../config";
12
- import {
13
10
  NEURALWATT_QUOTAS_UPDATED_EVENT,
11
+ type NeuralwattConfigUpdatedPayload,
14
12
  type NeuralwattQuotasUpdatedPayload,
15
- } from "../../types/quota-events";
13
+ } from "../../src/events";
16
14
  import { checkQuotas, clearAlertState } from "./notifier";
17
15
 
18
16
  export default async function (pi: ExtensionAPI) {
19
17
  await configLoader.load();
20
18
 
21
- let enabled = configLoader.getConfig().quotaWarnings;
19
+ let enabled = configLoader.getConfig().quotaWarnings.enabled;
22
20
  let currentProvider: string | undefined;
23
21
  let currentContext: ExtensionContext | undefined;
24
22
 
25
23
  // Listen for config changes at runtime
26
24
  pi.events.on(NEURALWATT_CONFIG_UPDATED_EVENT, (data: unknown) => {
27
- enabled = (data as NeuralwattConfigUpdatedPayload).config.quotaWarnings;
25
+ enabled = (data as NeuralwattConfigUpdatedPayload).config.quotaWarnings
26
+ .enabled;
28
27
 
29
28
  if (!enabled) {
30
29
  clearAlertState();
@@ -1,6 +1,6 @@
1
1
  import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
2
- import type { NeuralwattQuotas } from "../../types/quota-api";
3
- import { formatKwh, formatUsd } from "../../utils/quota-format";
2
+ import type { NeuralwattQuotas } from "../../src/types/quota-api";
3
+ import { formatKwh, formatUsd } from "../../src/utils/quota-format";
4
4
 
5
5
  export type WarningSeverity = "warning" | "critical";
6
6
 
@@ -4,24 +4,22 @@ import type {
4
4
  ExtensionContext,
5
5
  Theme,
6
6
  } from "@earendil-works/pi-coding-agent";
7
+ import { configLoader } from "../../src/config";
7
8
  import {
8
- configLoader,
9
9
  NEURALWATT_CONFIG_UPDATED_EVENT,
10
10
  NEURALWATT_EXTENSIONS_REGISTER_EVENT,
11
11
  NEURALWATT_EXTENSIONS_REQUEST_EVENT,
12
- type NeuralwattConfigUpdatedPayload,
13
- } from "../../config";
14
- import type { NeuralwattQuotas } from "../../types/quota-api";
15
- import {
16
12
  NEURALWATT_QUOTAS_REQUEST_EVENT,
17
13
  NEURALWATT_QUOTAS_UPDATED_EVENT,
14
+ type NeuralwattConfigUpdatedPayload,
18
15
  type NeuralwattQuotasUpdatedPayload,
19
- } from "../../types/quota-events";
16
+ } from "../../src/events";
17
+ import type { NeuralwattQuotas } from "../../src/types/quota-api";
20
18
  import {
21
19
  percentCreditsRemaining,
22
20
  percentEnergyRemaining,
23
- } from "../../utils/quota-bar";
24
- import { formatKwh, formatUsd } from "../../utils/quota-format";
21
+ } from "../../src/utils/quota-bar";
22
+ import { formatKwh, formatUsd } from "../../src/utils/quota-format";
25
23
  import { toUsageSnapshot } from "./snapshot";
26
24
 
27
25
  function formatStatus(quotas: NeuralwattQuotas, theme: Theme): string {
@@ -57,7 +55,7 @@ function formatStatus(quotas: NeuralwattQuotas, theme: Theme): string {
57
55
  export default async function (pi: ExtensionAPI) {
58
56
  await configLoader.load();
59
57
 
60
- let enabled = configLoader.getConfig().subBarIntegration;
58
+ let enabled = configLoader.getConfig().subBarIntegration.enabled;
61
59
  let subCoreReady = false;
62
60
  let currentProvider: string | undefined;
63
61
  let currentAuthStorage: AuthStorage | undefined;
@@ -65,7 +63,8 @@ export default async function (pi: ExtensionAPI) {
65
63
 
66
64
  // Listen for config changes at runtime
67
65
  pi.events.on(NEURALWATT_CONFIG_UPDATED_EVENT, (data: unknown) => {
68
- enabled = (data as NeuralwattConfigUpdatedPayload).config.subBarIntegration;
66
+ enabled = (data as NeuralwattConfigUpdatedPayload).config.subBarIntegration
67
+ .enabled;
69
68
  });
70
69
 
71
70
  function isActive(): boolean {
@@ -1,9 +1,9 @@
1
- import type { NeuralwattQuotas } from "../../types/quota-api";
1
+ import type { NeuralwattQuotas } from "../../src/types/quota-api";
2
2
  import {
3
3
  percentCreditsRemaining,
4
4
  percentEnergyRemaining,
5
- } from "../../utils/quota-bar";
6
- import { formatKwh } from "../../utils/quota-format";
5
+ } from "../../src/utils/quota-bar";
6
+ import { formatKwh } from "../../src/utils/quota-format";
7
7
 
8
8
  interface RateWindow {
9
9
  label: string;