@rynx-ai/daemon 0.1.0 → 0.1.10-beta.2

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 (109) hide show
  1. package/dist/app-browser-host-supervisor.d.ts +97 -0
  2. package/dist/app-browser-host-supervisor.js +529 -0
  3. package/dist/browser-artifact-management.d.ts +20 -0
  4. package/dist/browser-artifact-management.js +61 -0
  5. package/dist/browser-cli-args.d.ts +20 -0
  6. package/dist/browser-cli-args.js +100 -0
  7. package/dist/browser-runner-session-context.d.ts +24 -0
  8. package/dist/browser-runner-session-context.js +113 -0
  9. package/dist/cdp-keyboard-input.d.ts +6 -0
  10. package/dist/cdp-keyboard-input.js +209 -0
  11. package/dist/channel-store.d.ts +0 -6
  12. package/dist/channel-store.js +2 -18
  13. package/dist/chrome-for-testing-release-resolver.d.ts +34 -0
  14. package/dist/chrome-for-testing-release-resolver.js +214 -0
  15. package/dist/chrome-for-testing-store.d.ts +85 -0
  16. package/dist/chrome-for-testing-store.js +836 -0
  17. package/dist/chrome-inspection-gateway.d.ts +58 -0
  18. package/dist/chrome-inspection-gateway.js +806 -0
  19. package/dist/chrome-inspection-manager.d.ts +94 -0
  20. package/dist/chrome-inspection-manager.js +573 -0
  21. package/dist/cli.js +478 -30
  22. package/dist/control-client.d.ts +122 -0
  23. package/dist/control-client.js +855 -0
  24. package/dist/control-deps.js +37 -6
  25. package/dist/control-endpoint.d.ts +14 -0
  26. package/dist/control-endpoint.js +124 -0
  27. package/dist/control-link-store.d.ts +16 -0
  28. package/dist/control-link-store.js +53 -0
  29. package/dist/daemon-build-status.d.ts +8 -0
  30. package/dist/daemon-build-status.js +18 -0
  31. package/dist/daemon-owner.d.ts +14 -0
  32. package/dist/daemon-owner.js +104 -0
  33. package/dist/daemon-server.d.ts +29 -2
  34. package/dist/daemon-server.js +1113 -26
  35. package/dist/db.js +196 -10
  36. package/dist/desktop-browser-host-client.d.ts +35 -0
  37. package/dist/desktop-browser-host-client.js +415 -0
  38. package/dist/direct-runtime-authenticator.d.ts +13 -0
  39. package/dist/direct-runtime-authenticator.js +132 -0
  40. package/dist/direct-runtime-config.d.ts +20 -0
  41. package/dist/direct-runtime-config.js +101 -0
  42. package/dist/embedded-browser-profile-cleanup.d.ts +58 -0
  43. package/dist/embedded-browser-profile-cleanup.js +338 -0
  44. package/dist/headless-browser-host.d.ts +14 -0
  45. package/dist/headless-browser-host.js +2173 -0
  46. package/dist/index-daemon.js +55 -5
  47. package/dist/installation-id.d.ts +33 -0
  48. package/dist/installation-id.js +692 -0
  49. package/dist/maintenance-management.d.ts +11 -0
  50. package/dist/maintenance-management.js +13 -0
  51. package/dist/migrations/cleanup-legacy-sessions.d.ts +0 -3
  52. package/dist/migrations/cleanup-legacy-sessions.js +10 -28
  53. package/dist/plugin-cli.d.ts +30 -0
  54. package/dist/plugin-cli.js +270 -0
  55. package/dist/plugin-host-rpc.d.ts +85 -0
  56. package/dist/plugin-host-rpc.js +878 -0
  57. package/dist/plugin-install-restart.d.ts +13 -0
  58. package/dist/plugin-install-restart.js +24 -0
  59. package/dist/plugin-installer.d.ts +71 -15
  60. package/dist/plugin-installer.js +521 -155
  61. package/dist/plugin-management-service.d.ts +58 -0
  62. package/dist/plugin-management-service.js +240 -0
  63. package/dist/plugin-package.d.ts +61 -0
  64. package/dist/plugin-package.js +732 -0
  65. package/dist/plugin-runtime-control.d.ts +2 -0
  66. package/dist/plugin-runtime-control.js +37 -0
  67. package/dist/plugin-store.d.ts +37 -8
  68. package/dist/plugin-store.js +80 -15
  69. package/dist/plugin-supervisor.d.ts +160 -0
  70. package/dist/plugin-supervisor.js +1143 -0
  71. package/dist/pm2.d.ts +3 -1
  72. package/dist/pm2.js +92 -18
  73. package/dist/provider-cli-service.d.ts +46 -0
  74. package/dist/provider-cli-service.js +510 -0
  75. package/dist/registry.d.ts +6 -19
  76. package/dist/registry.js +22 -87
  77. package/dist/remote-runtime-access-store.d.ts +62 -0
  78. package/dist/remote-runtime-access-store.js +393 -0
  79. package/dist/remote-runtime-admin.d.ts +35 -0
  80. package/dist/remote-runtime-admin.js +110 -0
  81. package/dist/remote-runtime-connection-manager.d.ts +103 -0
  82. package/dist/remote-runtime-connection-manager.js +1575 -0
  83. package/dist/remote-runtime-credential-store.d.ts +45 -0
  84. package/dist/remote-runtime-credential-store.js +639 -0
  85. package/dist/remote-runtime-target-control.d.ts +51 -0
  86. package/dist/remote-runtime-target-control.js +488 -0
  87. package/dist/remote-runtime-target-store.d.ts +56 -0
  88. package/dist/remote-runtime-target-store.js +326 -0
  89. package/dist/runtime-share-addresses.d.ts +21 -0
  90. package/dist/runtime-share-addresses.js +50 -0
  91. package/dist/session-browser-capability-store.d.ts +13 -0
  92. package/dist/session-browser-capability-store.js +58 -0
  93. package/dist/session-emulator-binding-store.d.ts +10 -0
  94. package/dist/session-emulator-binding-store.js +61 -0
  95. package/dist/session-launch-operations.d.ts +41 -0
  96. package/dist/session-launch-operations.js +124 -0
  97. package/dist/session-log-store.js +29 -0
  98. package/dist/session-meta-store.d.ts +3 -2
  99. package/dist/session-meta-store.js +59 -7
  100. package/dist/session-pending-message-store.d.ts +2 -0
  101. package/dist/session-pending-message-store.js +41 -0
  102. package/dist/session-resource-store.d.ts +32 -0
  103. package/dist/session-resource-store.js +700 -0
  104. package/dist/setup.d.ts +16 -0
  105. package/dist/setup.js +144 -5
  106. package/dist/skills-catalog.js +8 -4
  107. package/dist/update.d.ts +11 -2
  108. package/dist/update.js +0 -27
  109. package/package.json +23 -10
package/dist/db.js CHANGED
@@ -1,25 +1,30 @@
1
1
  /**
2
2
  * `~/.rynx/rynx.db` — the daemon's SQLite store. Concerns kept apart:
3
- * - `channels` — a channel = a plugin type + its config/credentials (`options`).
4
- * The transport/connection, configured & authorized on its own.
5
- * - `instances` — a runnable binding: a channel + an agent (1:1 with a channel,
3
+ * - `channels` — a chat type + its plugin-owned config/credentials.
4
+ * - `instances` a runnable binding: a chat channel + an agent (1:1 with a channel,
6
5
  * enforced by a UNIQUE channel_id). This is what the daemon mounts.
7
- * - `plugins` — installed plugins (CLI-managed) the loader imports.
8
- * - `session_items` — the canonical, append-only conversation log (one row per
9
- * {@link import("@rynx-ai/core").SessionItem}); see {@link import("./session-log-store.js")}.
6
+ * - `plugins` — static manifests, grants and immutable install locations.
7
+ * - `plugin_session_launch_operations` — durable idempotency/tombstones.
8
+ * - `control_links` — generic, one-use links to the local session console.
9
+ * - `runtime_pairing_claims` / `runtime_client_grants` — one-use enrollment
10
+ * claims and the durable client identities they issue for direct runtimes.
11
+ * - `runtime_targets` / `runtime_direct_routes` / `runtime_pending_enrollments`
12
+ * — client-local daemon trust, replaceable location, and crash recovery.
13
+ * - `session_items` — the canonical, append-only conversation log; see
14
+ * {@link import("./session-log-store.js")}.
10
15
  *
11
16
  * Connections are cached per resolved path so tests can point `RYNX_DB` /
12
17
  * `RYNX_HOME` at a temp dir. Override with `RYNX_DB` (full path) or `RYNX_HOME`.
13
18
  */
14
19
  import { randomUUID } from "node:crypto";
15
20
  import { chmodSync, existsSync, mkdirSync, readFileSync, renameSync } from "node:fs";
21
+ import { homedir } from "node:os";
16
22
  import { dirname, join } from "node:path";
17
23
  import Database from "better-sqlite3";
18
- import { rynxHome } from "@rynx-ai/core";
19
24
  const connections = new Map();
20
25
  /** Absolute path to the SQLite file (override via `RYNX_DB`, else `~/.rynx/rynx.db`). */
21
26
  export function dbPath() {
22
- return process.env.RYNX_DB?.trim() || join(rynxHome(), "rynx.db");
27
+ return process.env.RYNX_DB?.trim() || join(daemonHome(), "rynx.db");
23
28
  }
24
29
  /** Open (or reuse) the database at the current path, migrating + importing on first open. */
25
30
  export function db() {
@@ -50,7 +55,12 @@ function migrate(conn) {
50
55
  source TEXT NOT NULL,
51
56
  version TEXT,
52
57
  enabled INTEGER NOT NULL DEFAULT 1,
53
- installed_at TEXT NOT NULL
58
+ installed_at TEXT NOT NULL,
59
+ updated_at TEXT,
60
+ install_path TEXT,
61
+ manifest TEXT,
62
+ integrity TEXT,
63
+ grants TEXT
54
64
  );
55
65
  CREATE TABLE IF NOT EXISTS channels (
56
66
  id TEXT PRIMARY KEY,
@@ -81,8 +91,59 @@ function migrate(conn) {
81
91
  UNIQUE(session_id, position)
82
92
  );
83
93
  CREATE INDEX IF NOT EXISTS idx_session_items_session ON session_items(session_id, position);
94
+ CREATE TABLE IF NOT EXISTS session_resources (
95
+ id TEXT PRIMARY KEY,
96
+ session_id TEXT NOT NULL,
97
+ client_upload_id TEXT NOT NULL,
98
+ upload_id TEXT NOT NULL UNIQUE,
99
+ filename TEXT NOT NULL,
100
+ media_type TEXT NOT NULL CHECK(media_type IN ('image/png', 'image/jpeg', 'image/webp')),
101
+ byte_length INTEGER NOT NULL,
102
+ uploaded_bytes INTEGER NOT NULL DEFAULT 0,
103
+ sha256 TEXT,
104
+ width INTEGER,
105
+ height INTEGER,
106
+ state TEXT NOT NULL DEFAULT 'uploading'
107
+ CHECK(state IN ('uploading', 'staged', 'committed')),
108
+ message_item_id TEXT,
109
+ created_at INTEGER NOT NULL,
110
+ committed_at INTEGER,
111
+ UNIQUE(session_id, client_upload_id)
112
+ );
113
+ CREATE INDEX IF NOT EXISTS idx_session_resources_session
114
+ ON session_resources(session_id, created_at);
115
+ CREATE INDEX IF NOT EXISTS idx_session_resources_message
116
+ ON session_resources(message_item_id);
117
+ CREATE TABLE IF NOT EXISTS session_message_operations (
118
+ session_id TEXT NOT NULL,
119
+ client_message_id TEXT NOT NULL,
120
+ request_hash TEXT NOT NULL,
121
+ state TEXT NOT NULL DEFAULT 'prepared'
122
+ CHECK(state IN (
123
+ 'prepared',
124
+ 'injecting',
125
+ 'injected',
126
+ 'mirrored',
127
+ 'outcome_unknown',
128
+ 'failed_not_started'
129
+ )),
130
+ error TEXT,
131
+ created_at INTEGER NOT NULL,
132
+ updated_at INTEGER NOT NULL,
133
+ PRIMARY KEY(session_id, client_message_id)
134
+ );
135
+ CREATE TABLE IF NOT EXISTS session_message_operation_resources (
136
+ session_id TEXT NOT NULL,
137
+ client_message_id TEXT NOT NULL,
138
+ resource_id TEXT NOT NULL UNIQUE REFERENCES session_resources(id) ON DELETE CASCADE,
139
+ PRIMARY KEY(session_id, client_message_id, resource_id),
140
+ FOREIGN KEY(session_id, client_message_id)
141
+ REFERENCES session_message_operations(session_id, client_message_id)
142
+ ON DELETE CASCADE
143
+ );
84
144
  CREATE TABLE IF NOT EXISTS sessions (
85
145
  id TEXT PRIMARY KEY,
146
+ provider TEXT,
86
147
  agent TEXT,
87
148
  config TEXT,
88
149
  model TEXT,
@@ -92,6 +153,117 @@ function migrate(conn) {
92
153
  created_at TEXT NOT NULL,
93
154
  updated_at TEXT
94
155
  );
156
+ CREATE TABLE IF NOT EXISTS session_pending_messages (
157
+ session_id TEXT PRIMARY KEY REFERENCES sessions(id) ON DELETE CASCADE,
158
+ message TEXT NOT NULL,
159
+ state TEXT NOT NULL DEFAULT 'queued' CHECK(state IN ('queued', 'outcome_unknown')),
160
+ created_at TEXT NOT NULL
161
+ );
162
+ CREATE TABLE IF NOT EXISTS session_emulator_bindings (
163
+ session_id TEXT PRIMARY KEY REFERENCES sessions(id) ON DELETE CASCADE,
164
+ binding_id TEXT NOT NULL UNIQUE,
165
+ backend TEXT NOT NULL CHECK(backend IN ('ios', 'android')),
166
+ device_id TEXT NOT NULL,
167
+ device_name TEXT,
168
+ attached_at TEXT NOT NULL,
169
+ UNIQUE(backend, device_id)
170
+ );
171
+ CREATE TABLE IF NOT EXISTS plugin_session_launch_operations (
172
+ plugin_id TEXT NOT NULL,
173
+ scope_id TEXT NOT NULL,
174
+ operation_id TEXT NOT NULL,
175
+ request_hash TEXT NOT NULL,
176
+ session_id TEXT NOT NULL,
177
+ state TEXT NOT NULL DEFAULT 'active' CHECK(state IN ('active', 'deleted')),
178
+ created_at TEXT NOT NULL,
179
+ updated_at TEXT NOT NULL,
180
+ deleted_at TEXT,
181
+ PRIMARY KEY(plugin_id, scope_id, operation_id),
182
+ CHECK(
183
+ (state = 'active' AND deleted_at IS NULL)
184
+ OR
185
+ (state = 'deleted' AND deleted_at IS NOT NULL)
186
+ )
187
+ );
188
+ CREATE INDEX IF NOT EXISTS idx_plugin_session_launch_operations_session
189
+ ON plugin_session_launch_operations(session_id);
190
+ CREATE TABLE IF NOT EXISTS control_links (
191
+ token TEXT PRIMARY KEY,
192
+ plugin_id TEXT NOT NULL,
193
+ session_id TEXT NOT NULL,
194
+ created_at TEXT NOT NULL,
195
+ expires_at TEXT NOT NULL,
196
+ used_at TEXT
197
+ );
198
+ CREATE INDEX IF NOT EXISTS idx_control_links_expires
199
+ ON control_links(expires_at);
200
+ CREATE TABLE IF NOT EXISTS runtime_pairing_claims (
201
+ claim_id TEXT PRIMARY KEY,
202
+ secret_hash TEXT NOT NULL,
203
+ authorities TEXT NOT NULL,
204
+ client_label TEXT,
205
+ created_at TEXT NOT NULL,
206
+ expires_at TEXT NOT NULL,
207
+ consumed_at TEXT,
208
+ consumed_client_id TEXT,
209
+ consumed_client_public_key TEXT,
210
+ consumed_grant_id TEXT,
211
+ CHECK (
212
+ (consumed_at IS NULL
213
+ AND consumed_client_id IS NULL
214
+ AND consumed_client_public_key IS NULL
215
+ AND consumed_grant_id IS NULL)
216
+ OR
217
+ (consumed_at IS NOT NULL
218
+ AND consumed_client_id IS NOT NULL
219
+ AND consumed_client_public_key IS NOT NULL
220
+ AND consumed_grant_id IS NOT NULL)
221
+ )
222
+ );
223
+ CREATE INDEX IF NOT EXISTS idx_runtime_pairing_claims_expires
224
+ ON runtime_pairing_claims(expires_at);
225
+ CREATE TABLE IF NOT EXISTS runtime_client_grants (
226
+ grant_id TEXT PRIMARY KEY,
227
+ client_id TEXT NOT NULL,
228
+ client_public_key TEXT NOT NULL UNIQUE,
229
+ client_label TEXT,
230
+ authorities TEXT NOT NULL,
231
+ created_at TEXT NOT NULL,
232
+ revoked_at TEXT,
233
+ last_used_at TEXT
234
+ );
235
+ CREATE INDEX IF NOT EXISTS idx_runtime_client_grants_client
236
+ ON runtime_client_grants(client_id);
237
+ CREATE TABLE IF NOT EXISTS runtime_targets (
238
+ daemon_id TEXT PRIMARY KEY,
239
+ display_name TEXT NOT NULL,
240
+ identity_public_key TEXT NOT NULL,
241
+ credential_ref TEXT NOT NULL UNIQUE,
242
+ created_at TEXT NOT NULL,
243
+ updated_at TEXT NOT NULL
244
+ );
245
+ CREATE TABLE IF NOT EXISTS runtime_direct_routes (
246
+ daemon_id TEXT PRIMARY KEY REFERENCES runtime_targets(daemon_id) ON DELETE CASCADE,
247
+ endpoint TEXT NOT NULL,
248
+ tls_ca_certificate_pem TEXT,
249
+ updated_at TEXT NOT NULL
250
+ );
251
+ CREATE TABLE IF NOT EXISTS runtime_pending_enrollments (
252
+ claim_id TEXT PRIMARY KEY,
253
+ daemon_id TEXT NOT NULL UNIQUE,
254
+ identity_public_key TEXT NOT NULL,
255
+ credential_ref TEXT NOT NULL UNIQUE,
256
+ offer_fingerprint TEXT NOT NULL,
257
+ expires_at TEXT NOT NULL,
258
+ created_at TEXT NOT NULL
259
+ );
260
+ CREATE INDEX IF NOT EXISTS idx_runtime_pending_enrollments_expires
261
+ ON runtime_pending_enrollments(expires_at);
262
+ `);
263
+ // Breaking plugin-runtime cutover: remove obsolete core-owned state.
264
+ conn.exec(`
265
+ DROP TABLE IF EXISTS control_sessions;
266
+ DROP TABLE IF EXISTS plugin_daemon_worker_settings;
95
267
  `);
96
268
  // `sessions` is the unified machine-session record (console + every channel).
97
269
  // Add the identity columns to a pre-existing table (SQLite has no
@@ -99,7 +271,18 @@ function migrate(conn) {
99
271
  // this change — they were all console sessions.
100
272
  addColumnIfMissing(conn, "sessions", "source", "TEXT");
101
273
  addColumnIfMissing(conn, "sessions", "updated_at", "TEXT");
274
+ addColumnIfMissing(conn, "sessions", "provider", "TEXT");
275
+ const sessionColumns = conn.prepare("PRAGMA table_info(sessions)").all();
276
+ if (sessionColumns.some((column) => column.name === "executor")) {
277
+ conn.exec("UPDATE sessions SET provider = executor WHERE provider IS NULL AND executor IS NOT NULL");
278
+ }
279
+ addColumnIfMissing(conn, "plugins", "updated_at", "TEXT");
280
+ addColumnIfMissing(conn, "plugins", "install_path", "TEXT");
281
+ addColumnIfMissing(conn, "plugins", "manifest", "TEXT");
282
+ addColumnIfMissing(conn, "plugins", "integrity", "TEXT");
283
+ addColumnIfMissing(conn, "plugins", "grants", "TEXT");
102
284
  conn.exec("UPDATE sessions SET source = 'console' WHERE source IS NULL");
285
+ conn.exec("UPDATE plugins SET updated_at = installed_at WHERE updated_at IS NULL");
103
286
  importLegacyConfig(conn);
104
287
  }
105
288
  /** Idempotently add a column to an existing table (no-op if already present). */
@@ -121,7 +304,7 @@ function importLegacyConfig(conn) {
121
304
  const { n } = conn.prepare("SELECT COUNT(*) AS n FROM channels").get();
122
305
  if (n > 0)
123
306
  return;
124
- const legacy = process.env.RYNX_CONFIG?.trim() || join(rynxHome(), "config.json");
307
+ const legacy = process.env.RYNX_CONFIG?.trim() || join(daemonHome(), "config.json");
125
308
  if (!existsSync(legacy))
126
309
  return;
127
310
  let channels;
@@ -168,3 +351,6 @@ function importLegacyConfig(conn) {
168
351
  /* leave the source in place if it can't be renamed */
169
352
  }
170
353
  }
354
+ function daemonHome() {
355
+ return process.env.RYNX_HOME?.trim() || join(homedir(), ".rynx");
356
+ }
@@ -0,0 +1,35 @@
1
+ import { type DesktopBrowserHostCommandFrame, type DesktopBrowserHostErrorCode, type DesktopBrowserHostEvent, type DesktopBrowserHostLeaseFrame, type DesktopBrowserHostPresentation, type DesktopBrowserHostSurfaceCapability, type DesktopBrowserHostSurfaceFrame } from "@rynx-ai/protocol/desktop-browser-host";
2
+ export interface ResidentDesktopBrowserHostConnectOptions {
3
+ hostInstanceId: string;
4
+ /** Advertise only handlers that are installed in this main-process Host. */
5
+ capabilities: {
6
+ semanticPageBinding: boolean;
7
+ presentation: DesktopBrowserHostPresentation;
8
+ surface: DesktopBrowserHostSurfaceCapability;
9
+ };
10
+ signal?: AbortSignal;
11
+ }
12
+ export interface ResidentDesktopBrowserHostFailure {
13
+ code: DesktopBrowserHostErrorCode;
14
+ message: string;
15
+ }
16
+ /**
17
+ * Process-private lease used by Electron main. The management credential is
18
+ * resolved and consumed in this package and never returned to the app renderer.
19
+ */
20
+ export interface ResidentDesktopBrowserHostCommandRequest {
21
+ readonly frame: DesktopBrowserHostCommandFrame;
22
+ /** Aborts at the daemon-supplied absolute deadline or on lease loss. */
23
+ readonly signal: AbortSignal;
24
+ reply(result: unknown): Promise<void>;
25
+ reject(failure: ResidentDesktopBrowserHostFailure): Promise<void>;
26
+ }
27
+ export interface ResidentDesktopBrowserHostConnection extends AsyncIterable<ResidentDesktopBrowserHostCommandRequest> {
28
+ readonly lease: DesktopBrowserHostLeaseFrame;
29
+ readonly closed: Promise<void>;
30
+ emit(event: DesktopBrowserHostEvent): Promise<void>;
31
+ emitSurfaceFrame(frame: Omit<DesktopBrowserHostSurfaceFrame, "leaseId">): Promise<void>;
32
+ close(): Promise<void>;
33
+ }
34
+ /** Open the sole resident daemon's authenticated loopback Desktop Host lease. */
35
+ export declare function connectResidentDesktopBrowserHost(options: ResidentDesktopBrowserHostConnectOptions): Promise<ResidentDesktopBrowserHostConnection>;