@melaya/runner 1.1.70 → 1.1.72

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.
@@ -48,7 +48,7 @@ import { VAULT_HOST_CAPABILITY, VaultHostProcess, VaultRegistry, VaultService, a
48
48
  // Local REST API); the REST key stays in ~/.melaya-runner/vaults.
49
49
  import { ObsidianAppBridge } from "./obsidianApp.js";
50
50
  // Desktop app host channel: state changes for the app's tray and web UI (no-op under npx).
51
- import { hostStatus, isHosted, hostProgress, sendToHost } from "./hostChannel.js";
51
+ import { hostStatus, isHosted, hostProgress, sendToHost, hostAppVersion } from "./hostChannel.js";
52
52
  // Desktop app: files this runner wrote are offered to computer control as handles (no-op under npx).
53
53
  import { reportHostFile, reportOutputsSince } from "./hostFiles.js";
54
54
  // Computer control: computer:command / computer:stop relayed to the desktop app
@@ -614,6 +614,11 @@ export async function connect(opts) {
614
614
  deviceName: hostname(),
615
615
  platform: process.platform,
616
616
  },
617
+ // Hosted by the Melaya desktop app: say so, with the app's version, so
618
+ // the server keeps that computer's app version current on every start
619
+ // (the token row is minted once) and knows this runner updates with the
620
+ // app, never with a restart command.
621
+ ...(isHosted() ? { host: { kind: "desktop", ...(hostAppVersion() ? { appVersion: hostAppVersion() } : {}) } } : {}),
617
622
  });
618
623
  // Index statuses produced while disconnected (or before this socket).
619
624
  for (const ev of vaultService.latestStatuses())
package/dist/detect.js CHANGED
@@ -111,6 +111,16 @@ async function detectClaudeCode(force = false) {
111
111
  const names = await fetchClaudeFamilies(oauth.accessToken, force);
112
112
  return names.map((name) => ({ provider: "claude_code", name }));
113
113
  }
114
+ // The short-lived access token expired but the sign-in is still valid: the
115
+ // CLI only renews it when `claude` runs, and the runtime renews it through
116
+ // the CLI on first use (model.py _refresh_claude_oauth_via_cli). Report the
117
+ // user as signed in (known aliases; no API call with an expired token)
118
+ // instead of "not signed in". Never consume the refresh token here.
119
+ const refreshExpiresAt = Number(oauth.refreshTokenExpiresAt ?? 0);
120
+ if (oauth.accessToken && oauth.refreshToken && (!refreshExpiresAt || Date.now() < refreshExpiresAt)) {
121
+ const cached = networkCacheGet(`claude:${tokenKey(oauth.accessToken)}`, false);
122
+ return (cached ?? CLAUDE_ALIASES_FALLBACK).map((name) => ({ provider: "claude_code", name }));
123
+ }
114
124
  }
115
125
  catch { /* malformed creds → treat as logged out */ }
116
126
  return []; // not logged in / expired → don't advertise models
@@ -209,8 +219,10 @@ async function detectGithubCopilotWith(gh) {
209
219
  },
210
220
  signal: AbortSignal.timeout(6000),
211
221
  });
222
+ // No Copilot seat / revoked token → don't advertise (cached). Anything else
223
+ // (429, 5xx) is transient: null so it is not cached as "not signed in".
212
224
  if (!ex.ok)
213
- return []; // no Copilot seat / revoked → don't advertise
225
+ return ex.status === 401 || ex.status === 403 || ex.status === 404 ? [] : null;
214
226
  const exd = (await ex.json());
215
227
  if (!exd.token)
216
228
  return [];
@@ -83,9 +83,12 @@ export type RunnerToHostMessage = {
83
83
  /** Mirror of the contract's HostToRunnerMessage (computer messages kept loose). */
84
84
  export type HostToRunnerMessage = {
85
85
  type: "stop";
86
- } | {
86
+ }
87
+ /** `appVersion`: the desktop app's own version (additive; reported in runner:hello's `host` block). */
88
+ | {
87
89
  type: "start";
88
90
  token: string;
91
+ appVersion?: string;
89
92
  }
90
93
  /** Additive: rescan model providers now and publish the list through runner:models. */
91
94
  | {
@@ -114,6 +117,9 @@ export declare function redactReason(s: string): string;
114
117
  export declare function hostStatus(state: HostedRunnerState, lastError?: string, code?: HostedStatusCode): void;
115
118
  /** Background setup progress for the desktop app. No-op outside the app. */
116
119
  export declare function hostProgress(state: "running" | "done" | "failed", step?: string, waiting?: boolean): void;
120
+ /** The desktop app's own version, as its start message said; null outside the
121
+ * app and with an app older than the field. */
122
+ export declare function hostAppVersion(): string | null;
117
123
  /**
118
124
  * Wait for the token from the desktop app. Resolves with the token, or rejects
119
125
  * when nothing valid arrives within `timeoutMs`.
@@ -88,6 +88,12 @@ export function hostProgress(state, step, waiting) {
88
88
  ...(waiting ? { waiting: true } : {}),
89
89
  });
90
90
  }
91
+ let _hostAppVersion = null;
92
+ /** The desktop app's own version, as its start message said; null outside the
93
+ * app and with an app older than the field. */
94
+ export function hostAppVersion() {
95
+ return _hostAppVersion;
96
+ }
91
97
  /**
92
98
  * Wait for the token from the desktop app. Resolves with the token, or rejects
93
99
  * when nothing valid arrives within `timeoutMs`.
@@ -102,6 +108,8 @@ export function waitForHostToken(timeoutMs = 30_000) {
102
108
  const token = msg.token;
103
109
  if (typeof token !== "string" || !token.startsWith("mel_run_"))
104
110
  return;
111
+ const appVersion = msg.appVersion;
112
+ _hostAppVersion = typeof appVersion === "string" && /^[0-9A-Za-z.+-]{1,32}$/.test(appVersion) ? appVersion : null;
105
113
  clearTimeout(timer);
106
114
  off();
107
115
  resolve(token);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@melaya/runner",
3
- "version": "1.1.70",
3
+ "version": "1.1.72",
4
4
  "description": "Run Melaya AI pipelines locally with your own LM Studio or Ollama models",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Melaya Labs LLC",