@mariozechner/pi-coding-agent 0.65.1 → 0.66.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.
@@ -33,6 +33,7 @@ import { CustomEditor } from "./components/custom-editor.js";
33
33
  import { CustomMessageComponent } from "./components/custom-message.js";
34
34
  import { DaxnutsComponent } from "./components/daxnuts.js";
35
35
  import { DynamicBorder } from "./components/dynamic-border.js";
36
+ import { EarendilAnnouncementComponent } from "./components/earendil-announcement.js";
36
37
  import { ExtensionEditorComponent } from "./components/extension-editor.js";
37
38
  import { ExtensionInputComponent } from "./components/extension-input.js";
38
39
  import { ExtensionSelectorComponent } from "./components/extension-selector.js";
@@ -53,6 +54,10 @@ import { getAvailableThemes, getAvailableThemesWithPaths, getEditorTheme, getMar
53
54
  function isExpandable(obj) {
54
55
  return typeof obj === "object" && obj !== null && "setExpanded" in obj && typeof obj.setExpanded === "function";
55
56
  }
57
+ const ANTHROPIC_SUBSCRIPTION_AUTH_WARNING = "Anthropic subscription auth is active. Third-party usage now draws from extra usage and is billed per token, not your Claude plan limits. Manage extra usage at https://claude.ai/settings/usage.";
58
+ function isAnthropicSubscriptionAuthKey(apiKey) {
59
+ return typeof apiKey === "string" && apiKey.startsWith("sk-ant-oat");
60
+ }
56
61
  export class InteractiveMode {
57
62
  options;
58
63
  runtimeHost;
@@ -80,6 +85,8 @@ export class InteractiveMode {
80
85
  lastSigintTime = 0;
81
86
  lastEscapeTime = 0;
82
87
  changelogMarkdown = undefined;
88
+ startupNoticesShown = false;
89
+ anthropicSubscriptionWarningShown = false;
83
90
  // Status line tracking (for mutating immediately-sequential status updates)
84
91
  lastStatusSpacer = undefined;
85
92
  lastStatusText = undefined;
@@ -281,6 +288,42 @@ export class InteractiveMode {
281
288
  this.editor.setAutocompleteProvider?.(this.autocompleteProvider);
282
289
  }
283
290
  }
291
+ shouldShowEarendilAnnouncement() {
292
+ const now = new Date();
293
+ return now.getFullYear() === 2026 && now.getMonth() === 3 && (now.getDate() === 8 || now.getDate() === 9);
294
+ }
295
+ showStartupNoticesIfNeeded() {
296
+ if (this.startupNoticesShown) {
297
+ return;
298
+ }
299
+ this.startupNoticesShown = true;
300
+ if (this.shouldShowEarendilAnnouncement()) {
301
+ if (this.chatContainer.children.length > 0) {
302
+ this.chatContainer.addChild(new Spacer(1));
303
+ }
304
+ this.chatContainer.addChild(new EarendilAnnouncementComponent());
305
+ }
306
+ if (!this.changelogMarkdown) {
307
+ return;
308
+ }
309
+ if (this.chatContainer.children.length > 0) {
310
+ this.chatContainer.addChild(new Spacer(1));
311
+ }
312
+ this.chatContainer.addChild(new DynamicBorder());
313
+ if (this.settingsManager.getCollapseChangelog()) {
314
+ const versionMatch = this.changelogMarkdown.match(/##\s+\[?(\d+\.\d+\.\d+)\]?/);
315
+ const latestVersion = versionMatch ? versionMatch[1] : this.version;
316
+ const condensedText = `Updated to v${latestVersion}. Use ${theme.bold("/changelog")} to view full changelog.`;
317
+ this.chatContainer.addChild(new Text(condensedText, 1, 0));
318
+ }
319
+ else {
320
+ this.chatContainer.addChild(new Text(theme.bold(theme.fg("accent", "What's New")), 1, 0));
321
+ this.chatContainer.addChild(new Spacer(1));
322
+ this.chatContainer.addChild(new Markdown(this.changelogMarkdown.trim(), 1, 0, this.getMarkdownThemeWithSettings()));
323
+ this.chatContainer.addChild(new Spacer(1));
324
+ }
325
+ this.chatContainer.addChild(new DynamicBorder());
326
+ }
284
327
  async init() {
285
328
  if (this.isInitialized)
286
329
  return;
@@ -324,36 +367,11 @@ export class InteractiveMode {
324
367
  this.headerContainer.addChild(new Spacer(1));
325
368
  this.headerContainer.addChild(this.builtInHeader);
326
369
  this.headerContainer.addChild(new Spacer(1));
327
- // Add changelog if provided
328
- if (this.changelogMarkdown) {
329
- this.headerContainer.addChild(new DynamicBorder());
330
- if (this.settingsManager.getCollapseChangelog()) {
331
- const versionMatch = this.changelogMarkdown.match(/##\s+\[?(\d+\.\d+\.\d+)\]?/);
332
- const latestVersion = versionMatch ? versionMatch[1] : this.version;
333
- const condensedText = `Updated to v${latestVersion}. Use ${theme.bold("/changelog")} to view full changelog.`;
334
- this.headerContainer.addChild(new Text(condensedText, 1, 0));
335
- }
336
- else {
337
- this.headerContainer.addChild(new Text(theme.bold(theme.fg("accent", "What's New")), 1, 0));
338
- this.headerContainer.addChild(new Spacer(1));
339
- this.headerContainer.addChild(new Markdown(this.changelogMarkdown.trim(), 1, 0, this.getMarkdownThemeWithSettings()));
340
- this.headerContainer.addChild(new Spacer(1));
341
- }
342
- this.headerContainer.addChild(new DynamicBorder());
343
- }
344
370
  }
345
371
  else {
346
372
  // Minimal header when silenced
347
373
  this.builtInHeader = new Text("", 0, 0);
348
374
  this.headerContainer.addChild(this.builtInHeader);
349
- if (this.changelogMarkdown) {
350
- // Still show changelog notification even in silent mode
351
- this.headerContainer.addChild(new Spacer(1));
352
- const versionMatch = this.changelogMarkdown.match(/##\s+\[?(\d+\.\d+\.\d+)\]?/);
353
- const latestVersion = versionMatch ? versionMatch[1] : this.version;
354
- const condensedText = `Updated to v${latestVersion}. Use ${theme.bold("/changelog")} to view full changelog.`;
355
- this.headerContainer.addChild(new Text(condensedText, 1, 0));
356
- }
357
375
  }
358
376
  this.ui.addChild(this.chatContainer);
359
377
  this.ui.addChild(this.pendingMessagesContainer);
@@ -439,6 +457,7 @@ export class InteractiveMode {
439
457
  if (modelFallbackMessage) {
440
458
  this.showWarning(modelFallbackMessage);
441
459
  }
460
+ void this.maybeWarnAboutAnthropicSubscriptionAuth();
442
461
  // Process initial messages
443
462
  if (initialMessage) {
444
463
  try {
@@ -970,10 +989,12 @@ export class InteractiveMode {
970
989
  const extensionRunner = this.session.extensionRunner;
971
990
  if (!extensionRunner) {
972
991
  this.showLoadedResources({ extensions: [], force: false });
992
+ this.showStartupNoticesIfNeeded();
973
993
  return;
974
994
  }
975
995
  this.setupExtensionShortcuts(extensionRunner);
976
996
  this.showLoadedResources({ force: false });
997
+ this.showStartupNoticesIfNeeded();
977
998
  }
978
999
  applyRuntimeSettings() {
979
1000
  this.footer.setSession(this.session);
@@ -2460,6 +2481,7 @@ export class InteractiveMode {
2460
2481
  this.updateEditorBorderColor();
2461
2482
  const thinkingStr = result.model.reasoning && result.thinkingLevel !== "off" ? ` (thinking: ${result.thinkingLevel})` : "";
2462
2483
  this.showStatus(`Switched to ${result.model.name || result.model.id}${thinkingStr}`);
2484
+ void this.maybeWarnAboutAnthropicSubscriptionAuth(result.model);
2463
2485
  }
2464
2486
  }
2465
2487
  catch (error) {
@@ -2899,6 +2921,7 @@ export class InteractiveMode {
2899
2921
  this.footer.invalidate();
2900
2922
  this.updateEditorBorderColor();
2901
2923
  this.showStatus(`Model: ${model.id}`);
2924
+ void this.maybeWarnAboutAnthropicSubscriptionAuth(model);
2902
2925
  this.checkDaxnutsEasterEgg(model);
2903
2926
  }
2904
2927
  catch (error) {
@@ -2930,6 +2953,31 @@ export class InteractiveMode {
2930
2953
  const uniqueProviders = new Set(models.map((m) => m.provider));
2931
2954
  this.footerDataProvider.setAvailableProviderCount(uniqueProviders.size);
2932
2955
  }
2956
+ async maybeWarnAboutAnthropicSubscriptionAuth(model = this.session.model) {
2957
+ if (this.anthropicSubscriptionWarningShown) {
2958
+ return;
2959
+ }
2960
+ if (!model || model.provider !== "anthropic") {
2961
+ return;
2962
+ }
2963
+ const storedCredential = this.session.modelRegistry.authStorage.get("anthropic");
2964
+ if (storedCredential?.type === "oauth") {
2965
+ this.anthropicSubscriptionWarningShown = true;
2966
+ this.showWarning(ANTHROPIC_SUBSCRIPTION_AUTH_WARNING);
2967
+ return;
2968
+ }
2969
+ try {
2970
+ const apiKey = await this.session.modelRegistry.getApiKeyForProvider(model.provider);
2971
+ if (!isAnthropicSubscriptionAuthKey(apiKey)) {
2972
+ return;
2973
+ }
2974
+ this.anthropicSubscriptionWarningShown = true;
2975
+ this.showWarning(ANTHROPIC_SUBSCRIPTION_AUTH_WARNING);
2976
+ }
2977
+ catch {
2978
+ // Ignore auth lookup failures for warning-only checks.
2979
+ }
2980
+ }
2933
2981
  showModelSelector(initialSearchInput) {
2934
2982
  this.showSelector((done) => {
2935
2983
  const selector = new ModelSelectorComponent(this.ui, this.session.model, this.settingsManager, this.session.modelRegistry, this.session.scopedModels, async (model) => {
@@ -2939,6 +2987,7 @@ export class InteractiveMode {
2939
2987
  this.updateEditorBorderColor();
2940
2988
  done();
2941
2989
  this.showStatus(`Model: ${model.id}`);
2990
+ void this.maybeWarnAboutAnthropicSubscriptionAuth(model);
2942
2991
  this.checkDaxnutsEasterEgg(model);
2943
2992
  }
2944
2993
  catch (error) {