@melaya/runner 1.1.71 → 1.1.73

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.
@@ -1,4 +1,4 @@
1
- export declare const COMPUTER_HELPER_VERSION = "1.0.1";
1
+ export declare const COMPUTER_HELPER_VERSION = "1.2.0";
2
2
  export declare const COMPUTER_HELPER_MANIFEST: Record<string, {
3
3
  url: string;
4
4
  sha256: string;
@@ -5,14 +5,14 @@
5
5
  // Pinned computer helper releases for the runner CLI host (computerHostCli.ts),
6
6
  // keyed by `${process.platform}-${process.arch}`. A download is only accepted
7
7
  // when its sha256 matches.
8
- export const COMPUTER_HELPER_VERSION = "1.0.1";
8
+ export const COMPUTER_HELPER_VERSION = "1.2.0";
9
9
  export const COMPUTER_HELPER_MANIFEST = {
10
10
  "linux-arm64": {
11
- "url": "https://api.melaya.org/desktop/helpers/1.0.1/melaya-computer-linux-aarch64",
12
- "sha256": "f5e6825fc00b589178b0540ed6f2e350dc8ac77bb97e08ae17395282465fec36"
11
+ "url": "https://api.melaya.org/desktop/helpers/1.2.0/melaya-computer-linux-aarch64",
12
+ "sha256": "8f1ddb5a4bdcc7bda35439de6ec1aa962e16b199dcb510e52fb48c00782eeef9"
13
13
  },
14
14
  "linux-x64": {
15
- "url": "https://api.melaya.org/desktop/helpers/1.0.1/melaya-computer-linux-x86_64",
16
- "sha256": "795933f10803f2bc25c95207e5a196ff6413e2e55f038ccd54c3f6f19e7c764c"
15
+ "url": "https://api.melaya.org/desktop/helpers/1.2.0/melaya-computer-linux-x86_64",
16
+ "sha256": "1431df7dd6f6a5d8412e4120fdadc82c247965a1139b03dd585ce93b21d5e88a"
17
17
  }
18
18
  };
@@ -77,10 +77,11 @@ export type ComputerCapabilitiesLike = Record<string, unknown> & {
77
77
  kinds: string[];
78
78
  host?: "desktop" | "cli";
79
79
  };
80
- export declare const COMPUTER_ACTION_KINDS: readonly ["screen", "screenshot", "find", "get_text", "current_app", "list_windows", "list_apps", "list_displays", "clipboard_read", "ocr", "wait", "hover", "move", "scroll", "focus_window", "open_app", "open_url", "open_file", "click", "type", "press", "drag", "select", "set_value", "toggle", "window", "clipboard_write", "file_dialog", "batch", "zoom", "cursor_position", "read_table", "expect", "mouse", "hold_key", "select_text", "quit_app", "save_dialog", "handoff", "keep_awake"];
80
+ export declare const COMPUTER_ACTION_KINDS: readonly ["screen", "screenshot", "find", "get_text", "current_app", "list_windows", "list_apps", "list_displays", "clipboard_read", "ocr", "wait", "hover", "move", "scroll", "focus_window", "open_app", "open_url", "open_file", "click", "type", "press", "drag", "select", "set_value", "toggle", "window", "clipboard_write", "file_dialog", "batch", "zoom", "cursor_position", "read_table", "expect", "mouse", "hold_key", "select_text", "quit_app", "save_dialog", "handoff", "keep_awake", "path"];
81
81
  /** Kinds that do not act on an app window: an empty allowlist does not block them. */
82
82
  export declare const APP_INDEPENDENT_KINDS: Set<string>;
83
- export declare const COMPUTER_MAX_BATCH_STEPS = 100;
83
+ /** Steps per batch: a whole drawing in one call (raised from 100 on 2026-10-23). */
84
+ export declare const COMPUTER_MAX_BATCH_STEPS = 5000;
84
85
  /** The lowest app tier that allows this action (same rule as the server and the helpers). */
85
86
  export declare function requiredTierOf(action: Record<string, unknown>): ComputerAppTier;
86
87
  /**
@@ -120,7 +121,7 @@ export declare function checkCommand(msg: {
120
121
  * accepted when its sha256 matches. Empty until the first release: use
121
122
  * MELAYA_COMPUTER_HELPER or --computer-helper meanwhile.
122
123
  */
123
- export declare const HELPER_VERSION = "1.0.1";
124
+ export declare const HELPER_VERSION = "1.2.0";
124
125
  export declare const HELPER_MANIFEST: Record<string, {
125
126
  url: string;
126
127
  sha256: string;
@@ -184,6 +185,8 @@ export declare class HelperProcess {
184
185
  * Aborts one command (or every one). A command that has not answered `stopped`
185
186
  * within the grace period gets the helper killed; it restarts on the next command.
186
187
  */
188
+ /** Releases every key / button the helper holds (helper 1.2.0+; older helpers ignore the op). */
189
+ release(): void;
187
190
  cancel(target?: string): void;
188
191
  get running(): boolean;
189
192
  dispose(): void;
@@ -56,6 +56,8 @@ export const COMPUTER_ACTION_KINDS = [
56
56
  "toggle", "window", "clipboard_write", "file_dialog", "batch",
57
57
  "zoom", "cursor_position", "read_table", "expect", "mouse", "hold_key", "select_text", "quit_app",
58
58
  "save_dialog", "handoff", "keep_awake",
59
+ // helper 1.2.0 (2026-10-23): pointer paths (planned by the server, replayed by the helper)
60
+ "path",
59
61
  ];
60
62
  const READ_KINDS = new Set([
61
63
  "screen", "screenshot", "find", "get_text", "current_app", "list_windows", "list_apps",
@@ -67,7 +69,8 @@ const KIND_SET = new Set(COMPUTER_ACTION_KINDS);
67
69
  export const APP_INDEPENDENT_KINDS = new Set(["list_apps", "list_displays", "cursor_position", "keep_awake", "handoff"]);
68
70
  /** File handles need the desktop app's handle store (it sends `resolved.path`); the CLI has none. */
69
71
  const NEEDS_FILE_HANDLES = new Set(["open_file", "file_dialog", "save_dialog"]);
70
- export const COMPUTER_MAX_BATCH_STEPS = 100;
72
+ /** Steps per batch: a whole drawing in one call (raised from 100 on 2026-10-23). */
73
+ export const COMPUTER_MAX_BATCH_STEPS = 5000;
71
74
  const DEFAULT_DEADLINE_MS = 15_000;
72
75
  const MAX_DEADLINE_MS = 31 * 60_000;
73
76
  const PROTOCOL_VERSION = 1;
@@ -465,6 +468,10 @@ export class HelperProcess {
465
468
  * Aborts one command (or every one). A command that has not answered `stopped`
466
469
  * within the grace period gets the helper killed; it restarts on the next command.
467
470
  */
471
+ /** Releases every key / button the helper holds (helper 1.2.0+; older helpers ignore the op). */
472
+ release() {
473
+ this.send({ op: "release" });
474
+ }
468
475
  cancel(target) {
469
476
  this.send(target ? { op: "cancel", target } : { op: "cancel" });
470
477
  if (!target || !this.child)
@@ -734,6 +741,11 @@ export function createCliComputerHost(options = {}) {
734
741
  const forced = !expectFailed && ["stopped", "timeout", "user_interrupted", "screen_locked", "secure_desktop"].includes(code);
735
742
  if (onError || forced) {
736
743
  const msg = r.error?.message || "";
744
+ // A batch that did not finish leaves nothing pressed (hold_key / mouse down without their up).
745
+ try {
746
+ helper?.release();
747
+ }
748
+ catch { /* best effort */ }
737
749
  return { ok: false, kind: "batch", error: { code, message: `Step ${i + 1} failed: ${msg}` }, steps: results, elapsedMs: Date.now() - started };
738
750
  }
739
751
  }
@@ -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())
@@ -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.71",
3
+ "version": "1.1.73",
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",