@oar-sh/oar 0.9.13 → 0.9.15

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 (74) hide show
  1. package/.github/extensions/web-relay/extension.mjs +9 -0
  2. package/.github/extensions/web-relay/server-lifecycle/managed-server.mjs +15 -1
  3. package/.github/extensions/web-relay/skills/question-bridge.mjs +4 -1
  4. package/CHANGELOG.md +396 -0
  5. package/README.md +12 -12
  6. package/bin/oar.js +677 -103
  7. package/package.json +7 -5
  8. package/server/claude-cloud-worker/claude-cloud-session-process.mjs +10 -4
  9. package/server/claude-worker/claude-session-process.mjs +39 -13
  10. package/server/claude-worker/claude-turn-publisher.mjs +20 -1
  11. package/server/claude-worker/subagent-timeline-recorder.mjs +75 -8
  12. package/server/copilot-worker/copilot-ask-user-tool.mjs +1 -1
  13. package/server/copilot-worker/copilot-prompt-context.mjs +3 -1
  14. package/server/copilot-worker/copilot-question-bridge.mjs +11 -6
  15. package/server/copilot-worker/copilot-sdk-adapter.mjs +11 -0
  16. package/server/copilot-worker/copilot-sdk-session-process.mjs +14 -1
  17. package/server/cursor-worker/cursor-ask-user-tool.mjs +1 -1
  18. package/server/cursor-worker/cursor-sdk-adapter.mjs +22 -7
  19. package/server/cursor-worker/cursor-session-worker.mjs +9 -2
  20. package/server/cursor-worker/cursor-turn-runner.mjs +18 -3
  21. package/server/grok-worker/grok-sdk-adapter.mjs +14 -0
  22. package/server/grok-worker/grok-turn-runner.mjs +13 -3
  23. package/server/public/app/api-client.js +3 -1
  24. package/server/public/app/ask-user-view.js +29 -4
  25. package/server/public/app/conversation-provider-indicator.mjs +18 -8
  26. package/server/public/app/question-answer-rule.mjs +15 -0
  27. package/server/public/app/question-multi-select.mjs +9 -2
  28. package/server/public/app/relay-event-view.mjs +5 -1
  29. package/server/public/app/settings-modal.js +17 -3
  30. package/server/public/index.html +9 -5
  31. package/server/relay-exit-codes.mjs +6 -0
  32. package/server/relay-self-restart.mjs +6 -1
  33. package/server/relay-tools.md +14 -11
  34. package/server/repositories/message-repository.mjs +29 -28
  35. package/server/repositories/subagent-timeline-statements.mjs +2 -0
  36. package/server/routes/ask-user-routes.mjs +41 -7
  37. package/server/routes/messages-routes.mjs +65 -10
  38. package/server/routes/preview-routes.mjs +73 -7
  39. package/server/routes/sessions-routes.mjs +49 -16
  40. package/server/server-runtime.mjs +156 -94
  41. package/server/services/cursor-session-root-service.mjs +70 -6
  42. package/server/services/data-dir-resolution.mjs +208 -19
  43. package/server/services/earlier-database-service.mjs +631 -0
  44. package/server/services/oar-cli-helpers.mjs +18 -5
  45. package/server/services/oar-state-layout.mjs +107 -0
  46. package/server/services/oar-state-migration-service.mjs +387 -96
  47. package/server/services/package-data-rescue-preinstall.mjs +22 -0
  48. package/server/services/package-data-rescue.mjs +137 -0
  49. package/server/services/preview-registry-service.mjs +3 -2
  50. package/server/services/push-dispatch-service.mjs +33 -6
  51. package/server/services/relay-event-service.mjs +183 -5
  52. package/server/services/relay-restart-queue.mjs +10 -3
  53. package/server/services/relay-singleton-guard.mjs +300 -36
  54. package/server/services/remote-relay-caller-context.mjs +7 -2
  55. package/server/services/remote-relay-dispatcher.mjs +30 -9
  56. package/server/services/session-activity-tracker.mjs +52 -15
  57. package/server/services/session-worker-launch-service.mjs +31 -1
  58. package/server/services/stale-turn-recovery.mjs +99 -0
  59. package/server/services/subagent-timeline-service.mjs +4 -1
  60. package/server/services/windows-autostart-service.mjs +415 -45
  61. package/server/services/windows-boot-autostart-service.mjs +962 -185
  62. package/shared/preview-instructions.mjs +17 -12
  63. package/shared/preview-tool-core.mjs +32 -14
  64. package/shared/question-answer-rule.mjs +63 -0
  65. package/shared/relay-events.mjs +54 -4
  66. package/shared/remote-relay-contract.mjs +20 -10
  67. package/shared/subagent-timeline.mjs +4 -0
  68. package/shared/windows-system-tools.mjs +25 -0
  69. package/shared/worker-runtime/config-loader.mjs +54 -8
  70. package/shared/worker-runtime/prompt-context.mjs +3 -1
  71. package/shared/worker-runtime/working-directory.mjs +65 -0
  72. package/.github/extensions/web-relay/README.md +0 -190
  73. package/server/README.md +0 -2187
  74. package/server/uploads/image_input.md +0 -540
@@ -66,7 +66,7 @@ export function describeRelayAddress({ config, lanAddress = null, wslNat = false
66
66
  return { url, lines, qrUrl, tunnelUrl };
67
67
  }
68
68
 
69
- const VALUE_OPTIONS = ['--port', '--migrate-from', '--to'];
69
+ const VALUE_OPTIONS = ['--port', '--migrate-from', '--to', '--autostart'];
70
70
  const LAUNCHER_FLAGS = ['--install-extension', '--no-install-extension', '--migrate-from'];
71
71
  const COMMAND_OPTIONS = { '--setup': 'setup', '--start': 'start', '--stop': 'stop', '--status': 'status' };
72
72
  const CLI_COMMANDS = {
@@ -79,8 +79,10 @@ const CLI_COMMANDS = {
79
79
  doctor: {},
80
80
  help: {},
81
81
  version: {},
82
- setup: { flags: ['--lan', '--local', '--new-token', '--defaults', '--start'], values: ['--port', '--migrate-from'] },
82
+ setup: { flags: ['--lan', '--local', '--new-token', '--defaults', '--start'], values: ['--port', '--migrate-from', '--autostart'] },
83
83
  service: { words: ['install', 'remove', 'status'] },
84
+ autostart: { words: ['signin', 'boot', 'off', 'status'], flags: ['--replace'] },
85
+ uninstall: { flags: ['--purge'] },
84
86
  update: { flags: ['--beta'], values: ['--to'] },
85
87
  copilot: { flags: ['--install-extension', '--no-install-extension'], values: ['--port', '--migrate-from'], forwards: true },
86
88
  };
@@ -95,10 +97,16 @@ export function usageText() {
95
97
  ' oar restart Restart the relay (waits for running turns)',
96
98
  ' oar status Is the relay running, on which port, as a service',
97
99
  ' oar url Relay URL, with a QR code when a phone can reach it',
98
- ' oar setup Auth token, access and port; asks, or takes',
99
- ' [--port <port>] [--lan | --local] [--new-token] [--defaults] [--start]',
100
+ ' oar setup Auth token, access, port and autostart; asks, or takes',
101
+ ' [--port <port>] [--lan | --local] [--new-token] [--autostart signin|boot|off]',
102
+ ' [--defaults] [--start]',
103
+ ' oar autostart signin | boot | off | status [--replace]',
104
+ ' Start the relay at sign-in or at boot (Windows: boot asks for an admin once);',
105
+ ' --replace replaces hand-made entries, keeping a copy',
100
106
  ' oar service install | remove | status',
101
107
  ' Start the relay at login',
108
+ ' oar uninstall [--purge]',
109
+ ' Remove autostart and the package; the data stays (--purge deletes it)',
102
110
  ' oar copilot [--port <port>] [--install-extension] [--no-install-extension] [-- gh copilot args...]',
103
111
  ' Relay plus a Copilot terminal session',
104
112
  ' oar doctor Check the install and the provider CLIs',
@@ -194,6 +202,9 @@ export function buildSystemdUnit({ nodeBin, packageRoot, configPath, dataDir, lo
194
202
  // an install with a private Node, `node` and `npm` themselves.
195
203
  ...(pathEnv ? [`Environment="PATH=${escapeSystemdValue(pathEnv)}"`] : []),
196
204
  'Restart=on-failure',
205
+ // 78 (RELAY_STOP_EXIT_CODE): the relay stopped on purpose, its database
206
+ // or data folder needs a decision; restarting it cannot help.
207
+ 'RestartPreventExitStatus=78',
197
208
  'RestartSec=5',
198
209
  '',
199
210
  '[Install]',
@@ -231,7 +242,9 @@ export function buildServicePath({ nodeBin, envPath = '', homeDir = '' } = {}) {
231
242
  * accept the flag and run the scripts as before. `npm-install-scripts.test.mjs`
232
243
  * holds this list to the lockfile.
233
244
  */
234
- export const NPM_INSTALL_SCRIPT_PACKAGES = Object.freeze(['better-sqlite3', 'koffi']);
245
+ // @oar-sh/oar itself: its preinstall copies the data an earlier version
246
+ // kept inside the package before npm deletes it (package-data-rescue.mjs).
247
+ export const NPM_INSTALL_SCRIPT_PACKAGES = Object.freeze(['@oar-sh/oar', 'better-sqlite3', 'koffi']);
235
248
  export const NPM_ALLOW_SCRIPTS_ARG = `--allow-scripts=${NPM_INSTALL_SCRIPT_PACKAGES.join(',')}`;
236
249
 
237
250
  /**
@@ -0,0 +1,107 @@
1
+ import fs from 'fs';
2
+ import os from 'os';
3
+ import path from 'path';
4
+
5
+ import { resolveOarRoot } from './oar-state-migration-service.mjs';
6
+
7
+ // Pre-OAR managed config location — kept only as a migration source and as the
8
+ // config home for git checkouts, where nothing may change underfoot.
9
+ export function getLegacyManagedConfigDir(env = process.env, { platform = process.platform, pathImpl = path } = {}) {
10
+ if (platform === 'win32') {
11
+ return pathImpl.join(
12
+ env.LOCALAPPDATA || pathImpl.join(os.homedir(), 'AppData', 'Local'),
13
+ 'copilot-remote',
14
+ );
15
+ }
16
+ return pathImpl.join(
17
+ env.XDG_CONFIG_HOME || pathImpl.join(os.homedir(), '.config'),
18
+ 'copilot-remote',
19
+ );
20
+ }
21
+
22
+ export function isGitCheckout(packageRoot, { fsImpl = fs, pathImpl = path } = {}) {
23
+ try { return fsImpl.existsSync(pathImpl.join(packageRoot, '.git')); } catch { return false; }
24
+ }
25
+
26
+ /**
27
+ * Where launcher-managed state lives. A git checkout keeps every pre-OAR
28
+ * default (repo-local server/data, legacy managed config) so development and
29
+ * the two existing machines change nothing. A global install gets the OAR
30
+ * state root: config, data, logs all under ~/.oar (APPDATA\oar on Windows),
31
+ * which survives `npm i -g` updates.
32
+ */
33
+ export function resolveStateLayout({
34
+ packageRoot,
35
+ env = process.env,
36
+ platform = process.platform,
37
+ fsImpl = fs,
38
+ pathImpl = path,
39
+ } = {}) {
40
+ if (isGitCheckout(packageRoot, { fsImpl, pathImpl })) {
41
+ return { checkout: true, root: null, configDir: getLegacyManagedConfigDir(env, { platform, pathImpl }), dataDir: null };
42
+ }
43
+ const root = resolveOarRoot(env, platform);
44
+ return { checkout: false, root, configDir: root, dataDir: pathImpl.join(root, 'data') };
45
+ }
46
+
47
+ /**
48
+ * The data and log folders a relay of this install is started with, '' where
49
+ * the relay is left to its own server-relative default. Every launcher pins
50
+ * these — `oar start`, `oar copilot` and both Windows autostart launchers —
51
+ * so the relay finds the same database however it was started. A folder the
52
+ * environment names wins; a global install otherwise uses the OAR state root;
53
+ * a checkout pins nothing of its own.
54
+ */
55
+ export function resolveRelayStateDirs({
56
+ packageRoot,
57
+ env = process.env,
58
+ platform = process.platform,
59
+ fsImpl = fs,
60
+ pathImpl = path,
61
+ layout = resolveStateLayout({ packageRoot, env, platform, fsImpl, pathImpl }),
62
+ } = {}) {
63
+ const envDataDir = String(env?.COPILOT_WEB_RELAY_DATA_DIR || '').trim();
64
+ const envLogDir = String(env?.COPILOT_WEB_RELAY_LOG_DIR || '').trim();
65
+ return {
66
+ dataDir: envDataDir || layout?.dataDir || '',
67
+ logDir: envLogDir || (layout && !layout.checkout ? pathImpl.join(layout.root, 'logs') : ''),
68
+ };
69
+ }
70
+
71
+ /**
72
+ * The data and log folders an automatic launcher repair may pin: those of the
73
+ * install's layout alone, never ones only this relay's environment names (a
74
+ * short-lived relay started with a scratch data folder must not repoint the
75
+ * install's autostart). Null when the layout has none (a checkout), or when
76
+ * this relay runs on other folders than the layout's.
77
+ */
78
+ export function resolveLayoutStateDirs({
79
+ packageRoot,
80
+ env = process.env,
81
+ platform = process.platform,
82
+ fsImpl = fs,
83
+ pathImpl = path,
84
+ } = {}) {
85
+ const layout = resolveStateLayout({ packageRoot, env, platform, fsImpl, pathImpl });
86
+ const dirs = resolveRelayStateDirs({ env: {}, layout, platform, pathImpl });
87
+ if (!dirs.dataDir || !dirs.logDir) return null;
88
+ const own = resolveRelayStateDirs({ env, layout, platform, pathImpl });
89
+ const same = (a, b) => {
90
+ const normalize = (value) => {
91
+ const resolved = pathImpl.resolve(String(value));
92
+ return platform === 'win32' ? resolved.toLowerCase() : resolved;
93
+ };
94
+ return normalize(a) === normalize(b);
95
+ };
96
+ return same(dirs.dataDir, own.dataDir) && same(dirs.logDir, own.logDir) ? dirs : null;
97
+ }
98
+
99
+ /**
100
+ * The log folder `oar copilot` and `oar start` give the relay (and write its
101
+ * output to): the relay's log folder, else, in a checkout, `logs` in the
102
+ * legacy managed config folder.
103
+ */
104
+ export function getLauncherLogDir(env = process.env, layout = null, { platform = process.platform, pathImpl = path } = {}) {
105
+ return resolveRelayStateDirs({ env, layout, platform, pathImpl }).logDir
106
+ || pathImpl.join(getLegacyManagedConfigDir(env, { platform, pathImpl }), 'logs');
107
+ }