@oar-sh/oar 0.9.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.
Files changed (293) hide show
  1. package/.github/extensions/web-relay/README.md +190 -0
  2. package/.github/extensions/web-relay/extension.mjs +972 -0
  3. package/.github/extensions/web-relay/model-api/model-switching.mjs +338 -0
  4. package/.github/extensions/web-relay/polling/heartbeat.mjs +55 -0
  5. package/.github/extensions/web-relay/polling/polling-loop.mjs +1105 -0
  6. package/.github/extensions/web-relay/runtime/api-client.mjs +34 -0
  7. package/.github/extensions/web-relay/runtime/banner-state.mjs +126 -0
  8. package/.github/extensions/web-relay/runtime/config-loader.mjs +104 -0
  9. package/.github/extensions/web-relay/runtime/debug-log.mjs +27 -0
  10. package/.github/extensions/web-relay/runtime/send-and-wait-errors.mjs +170 -0
  11. package/.github/extensions/web-relay/runtime/session-binding.mjs +78 -0
  12. package/.github/extensions/web-relay/runtime/session-io.mjs +349 -0
  13. package/.github/extensions/web-relay/runtime/session-join-retry.mjs +44 -0
  14. package/.github/extensions/web-relay/runtime/session-registry.mjs +29 -0
  15. package/.github/extensions/web-relay/runtime/session-runtime-manager.mjs +156 -0
  16. package/.github/extensions/web-relay/runtime/session-sync-bridge.mjs +74 -0
  17. package/.github/extensions/web-relay/runtime/worker-websocket-link.mjs +325 -0
  18. package/.github/extensions/web-relay/runtime/workspace-root.mjs +55 -0
  19. package/.github/extensions/web-relay/server-lifecycle/managed-server.mjs +386 -0
  20. package/.github/extensions/web-relay/skills/prompt-context.mjs +160 -0
  21. package/.github/extensions/web-relay/skills/question-bridge.mjs +141 -0
  22. package/.github/extensions/web-relay/skills/question-routing-hooks.mjs +463 -0
  23. package/.github/extensions/web-relay/skills/reasoning-stream.mjs +285 -0
  24. package/.github/extensions/web-relay/skills/subagent-lifecycle.mjs +345 -0
  25. package/.github/extensions/web-relay/skills/tool-activity.mjs +243 -0
  26. package/.github/extensions/web-relay/utils/process-utils.mjs +25 -0
  27. package/.github/extensions/web-relay/utils/token-generation.mjs +58 -0
  28. package/CHANGELOG.md +25 -0
  29. package/LICENSE +21 -0
  30. package/README.md +717 -0
  31. package/bin/bat/oar.bat +46 -0
  32. package/bin/oar.js +665 -0
  33. package/package.json +68 -0
  34. package/server/README.md +1379 -0
  35. package/server/claude-worker/claude-attachments.mjs +134 -0
  36. package/server/claude-worker/claude-preview-tool.mjs +57 -0
  37. package/server/claude-worker/claude-sdk-adapter.mjs +420 -0
  38. package/server/claude-worker/claude-session-process.mjs +2391 -0
  39. package/server/claude-worker/claude-session-test-harness.mjs +236 -0
  40. package/server/claude-worker/claude-session-worker.mjs +186 -0
  41. package/server/claude-worker/claude-transcript-relocator.mjs +189 -0
  42. package/server/claude-worker/claude-turn-publisher.mjs +291 -0
  43. package/server/claude-worker/fixtures/workflow-run-record.json +1 -0
  44. package/server/claude-worker/sdk-message-normalizer.mjs +629 -0
  45. package/server/claude-worker/workflow-progress-digest.mjs +269 -0
  46. package/server/copilot-sdk-runtime.mjs +126 -0
  47. package/server/copilot-worker/copilot-attachments.mjs +97 -0
  48. package/server/copilot-worker/copilot-byok-provider.mjs +121 -0
  49. package/server/copilot-worker/copilot-continuation-signals.mjs +349 -0
  50. package/server/copilot-worker/copilot-plan-board.mjs +110 -0
  51. package/server/copilot-worker/copilot-prompt-context.mjs +86 -0
  52. package/server/copilot-worker/copilot-question-bridge.mjs +216 -0
  53. package/server/copilot-worker/copilot-sdk-adapter.mjs +494 -0
  54. package/server/copilot-worker/copilot-sdk-event-normalizer.mjs +800 -0
  55. package/server/copilot-worker/copilot-sdk-session-process.mjs +1729 -0
  56. package/server/copilot-worker/copilot-sdk-session-worker.mjs +167 -0
  57. package/server/copilot-worker/copilot-sdk-test-harness.mjs +329 -0
  58. package/server/copilot-worker/fixtures/abort-turn.json +588 -0
  59. package/server/copilot-worker/fixtures/ask-user-turn.json +1154 -0
  60. package/server/copilot-worker/fixtures/background-timer-continuation.json +445 -0
  61. package/server/copilot-worker/fixtures/background-timer-turn.json +497 -0
  62. package/server/copilot-worker/fixtures/happy-turn.json +566 -0
  63. package/server/copilot-worker/fixtures/quota-turn.json +647 -0
  64. package/server/copilot-worker/fixtures/reasoning-turn.json +625 -0
  65. package/server/copilot-worker/fixtures/resume-turn.json +700 -0
  66. package/server/copilot-worker/fixtures/subagent-turn.json +1378 -0
  67. package/server/copilot-worker/fixtures/tool-permission-turn.json +1293 -0
  68. package/server/cursor-worker/cursor-ask-user-tool.mjs +83 -0
  69. package/server/cursor-worker/cursor-attachments.mjs +88 -0
  70. package/server/cursor-worker/cursor-context-usage.mjs +85 -0
  71. package/server/cursor-worker/cursor-preview-tool.mjs +44 -0
  72. package/server/cursor-worker/cursor-sdk-adapter.mjs +554 -0
  73. package/server/cursor-worker/cursor-session-worker.mjs +145 -0
  74. package/server/cursor-worker/cursor-subagent-roster.mjs +81 -0
  75. package/server/cursor-worker/cursor-turn-runner.mjs +717 -0
  76. package/server/cursor-worker/sdk-message-normalizer.mjs +485 -0
  77. package/server/db-schema.mjs +932 -0
  78. package/server/features.mjs +106 -0
  79. package/server/grok-worker/acp-client.mjs +434 -0
  80. package/server/grok-worker/acp-host-services.mjs +277 -0
  81. package/server/grok-worker/grok-context-usage.mjs +77 -0
  82. package/server/grok-worker/grok-sdk-adapter.mjs +334 -0
  83. package/server/grok-worker/grok-session-worker.mjs +145 -0
  84. package/server/grok-worker/grok-turn-runner.mjs +523 -0
  85. package/server/grok-worker/sdk-message-normalizer.mjs +311 -0
  86. package/server/migrations/0001-add-structured-answer.mjs +80 -0
  87. package/server/migrations/0002-recent-workspace-roots-path-key.mjs +121 -0
  88. package/server/migrations/0003-push-subscriptions.mjs +87 -0
  89. package/server/public/app/action-confirmations.js +267 -0
  90. package/server/public/app/activity-replay-state.mjs +149 -0
  91. package/server/public/app/api-client.js +1082 -0
  92. package/server/public/app/ask-user-view.js +545 -0
  93. package/server/public/app/attachments-view.js +2112 -0
  94. package/server/public/app/auto-compact-window-options.mjs +59 -0
  95. package/server/public/app/background-tasks-view.mjs +494 -0
  96. package/server/public/app/bootstrap.js +4347 -0
  97. package/server/public/app/claude-auth-ui.js +394 -0
  98. package/server/public/app/claude-thinking-options.mjs +38 -0
  99. package/server/public/app/cli-install-ui.js +455 -0
  100. package/server/public/app/code-copy.mjs +85 -0
  101. package/server/public/app/composer-attachment-cache.mjs +151 -0
  102. package/server/public/app/composer-control-state.mjs +107 -0
  103. package/server/public/app/composer-paste.mjs +132 -0
  104. package/server/public/app/context-tier-options.mjs +68 -0
  105. package/server/public/app/context-usage-view.mjs +338 -0
  106. package/server/public/app/conversation-draft-timestamp-utils.mjs +11 -0
  107. package/server/public/app/conversation-preferences.mjs +91 -0
  108. package/server/public/app/conversation-provider-indicator.mjs +88 -0
  109. package/server/public/app/conversation-view.js +2898 -0
  110. package/server/public/app/cwd-menu-placement.mjs +85 -0
  111. package/server/public/app/cwd-picker.js +605 -0
  112. package/server/public/app/emoji-view.js +101 -0
  113. package/server/public/app/external-link-policy.mjs +80 -0
  114. package/server/public/app/file-preview-navigation.mjs +51 -0
  115. package/server/public/app/font-scaling.js +262 -0
  116. package/server/public/app/git-changes-view.js +339 -0
  117. package/server/public/app/git-diff-model.mjs +109 -0
  118. package/server/public/app/grok-auth-ui.js +387 -0
  119. package/server/public/app/image-downscale.mjs +174 -0
  120. package/server/public/app/in-flight-snapshot.mjs +40 -0
  121. package/server/public/app/infinite-loader.js +164 -0
  122. package/server/public/app/journal-view.js +1141 -0
  123. package/server/public/app/known-cwd-options.mjs +41 -0
  124. package/server/public/app/launch-cwd-path.mjs +23 -0
  125. package/server/public/app/live-message-dedupe.mjs +57 -0
  126. package/server/public/app/message-search-view.js +242 -0
  127. package/server/public/app/model-selector-options.mjs +31 -0
  128. package/server/public/app/model-vision-support.mjs +56 -0
  129. package/server/public/app/new-conversation-model-choice.mjs +67 -0
  130. package/server/public/app/plan-usage-view.mjs +307 -0
  131. package/server/public/app/preview-cards.mjs +273 -0
  132. package/server/public/app/preview-command.mjs +103 -0
  133. package/server/public/app/push-settings.js +370 -0
  134. package/server/public/app/pwa-install.js +456 -0
  135. package/server/public/app/question-schema-view.mjs +71 -0
  136. package/server/public/app/reasoning-effort-labels.mjs +42 -0
  137. package/server/public/app/relay-board-view.js +117 -0
  138. package/server/public/app/relay-dot-state.mjs +69 -0
  139. package/server/public/app/relay-error-ctas.mjs +52 -0
  140. package/server/public/app/relay-prompt-sanitizer.mjs +114 -0
  141. package/server/public/app/relay-thoughts.mjs +98 -0
  142. package/server/public/app/relay-watchdog-policy.mjs +29 -0
  143. package/server/public/app/repo-browser-preferences.mjs +79 -0
  144. package/server/public/app/repo-browser-tree-state.mjs +97 -0
  145. package/server/public/app/router.js +657 -0
  146. package/server/public/app/selection-guard.mjs +93 -0
  147. package/server/public/app/settings-modal.js +1484 -0
  148. package/server/public/app/settings-tabs.js +129 -0
  149. package/server/public/app/slash-autocomplete.mjs +188 -0
  150. package/server/public/app/slash-commands.mjs +183 -0
  151. package/server/public/app/socket-handlers.js +703 -0
  152. package/server/public/app/status-store.mjs +242 -0
  153. package/server/public/app/status-view.mjs +315 -0
  154. package/server/public/app/store.js +1454 -0
  155. package/server/public/app/stream-state.mjs +73 -0
  156. package/server/public/app/streaming-dom-patch.mjs +23 -0
  157. package/server/public/app/sync-outbox.mjs +208 -0
  158. package/server/public/app/tap-actions.js +62 -0
  159. package/server/public/app/thread-order.mjs +54 -0
  160. package/server/public/app/tmux-inspector-view.js +422 -0
  161. package/server/public/app/transcript-separators.mjs +282 -0
  162. package/server/public/app-icon-192.png +0 -0
  163. package/server/public/app-icon-512.png +0 -0
  164. package/server/public/app-icon.svg +4 -0
  165. package/server/public/favicon.ico +0 -0
  166. package/server/public/index.html +5743 -0
  167. package/server/public/manifest.webmanifest +32 -0
  168. package/server/public/sw.js +307 -0
  169. package/server/relay-exit-codes.mjs +4 -0
  170. package/server/relay-self-restart.mjs +170 -0
  171. package/server/relay-tools.md +27 -0
  172. package/server/relay.mjs +1026 -0
  173. package/server/repositories/image-conversation-repository.mjs +317 -0
  174. package/server/repositories/message-repository.mjs +434 -0
  175. package/server/repositories/question-repository.mjs +161 -0
  176. package/server/repositories/session-repository.mjs +320 -0
  177. package/server/repositories/share-visibility-statements.mjs +24 -0
  178. package/server/routes/ask-user-routes.mjs +292 -0
  179. package/server/routes/cache-routes.mjs +44 -0
  180. package/server/routes/git-routes.mjs +92 -0
  181. package/server/routes/messages-routes-test-harness.mjs +111 -0
  182. package/server/routes/messages-routes.mjs +7107 -0
  183. package/server/routes/preview-routes.mjs +108 -0
  184. package/server/routes/push-routes.mjs +59 -0
  185. package/server/routes/relay-board-routes.mjs +268 -0
  186. package/server/routes/sessions-routes.mjs +6150 -0
  187. package/server/server-runtime.mjs +7463 -0
  188. package/server/server.js +24 -0
  189. package/server/services/ask-user-routing-service.mjs +117 -0
  190. package/server/services/cache-rebuild-service.mjs +236 -0
  191. package/server/services/claude-auth-service.mjs +578 -0
  192. package/server/services/claude-context-usage.mjs +240 -0
  193. package/server/services/claude-session-root-service.mjs +228 -0
  194. package/server/services/cli-install-service.mjs +1152 -0
  195. package/server/services/cli-process-runner.mjs +181 -0
  196. package/server/services/cloudflared-tunnel-service.mjs +358 -0
  197. package/server/services/context-snapshot-service.mjs +499 -0
  198. package/server/services/context-usage-view.mjs +160 -0
  199. package/server/services/conversation-preferences-service.mjs +208 -0
  200. package/server/services/cursor-dashboard-usage.mjs +217 -0
  201. package/server/services/cursor-session-root-service.mjs +62 -0
  202. package/server/services/delete-archive-service.mjs +154 -0
  203. package/server/services/drives-path-helpers.mjs +66 -0
  204. package/server/services/fixtures/claude-auth-stub.sh +62 -0
  205. package/server/services/fixtures/cli-install-stub.sh +75 -0
  206. package/server/services/fixtures/grok-stub.sh +86 -0
  207. package/server/services/generated-image-cleanup-service.mjs +114 -0
  208. package/server/services/git-changes-service.mjs +195 -0
  209. package/server/services/github-billing-usage.mjs +133 -0
  210. package/server/services/grok-auth-service.mjs +593 -0
  211. package/server/services/grok-billing-usage.mjs +120 -0
  212. package/server/services/image-context-service.mjs +106 -0
  213. package/server/services/image-operation-service.mjs +135 -0
  214. package/server/services/keyed-mutex-service.mjs +82 -0
  215. package/server/services/mime-sniffer.mjs +118 -0
  216. package/server/services/oar-cli-helpers.mjs +109 -0
  217. package/server/services/oar-state-migration-service.mjs +243 -0
  218. package/server/services/plan-usage-claude.mjs +387 -0
  219. package/server/services/plan-usage-contract.mjs +271 -0
  220. package/server/services/plan-usage-copilot.mjs +421 -0
  221. package/server/services/plan-usage-cursor.mjs +566 -0
  222. package/server/services/plan-usage-grok.mjs +436 -0
  223. package/server/services/plan-usage-service.mjs +487 -0
  224. package/server/services/preview-health-probe.mjs +82 -0
  225. package/server/services/preview-proxy-server.mjs +498 -0
  226. package/server/services/preview-registry-service.mjs +457 -0
  227. package/server/services/preview-static-handler.mjs +237 -0
  228. package/server/services/provider-model-selection.mjs +91 -0
  229. package/server/services/provider-reasoning-effort.mjs +94 -0
  230. package/server/services/push-active-device-service.mjs +57 -0
  231. package/server/services/push-dispatch-service.mjs +459 -0
  232. package/server/services/rate-limit-service.mjs +63 -0
  233. package/server/services/relay-bridge-owner-service.mjs +84 -0
  234. package/server/services/relay-cli-launcher-service.mjs +209 -0
  235. package/server/services/relay-prompt-sanitizer.mjs +137 -0
  236. package/server/services/relay-queue-gate-service.mjs +38 -0
  237. package/server/services/relay-restart-orchestrator-service.mjs +935 -0
  238. package/server/services/relay-singleton-guard.mjs +124 -0
  239. package/server/services/safe-served-content.mjs +57 -0
  240. package/server/services/sdk-session-import-service.mjs +271 -0
  241. package/server/services/sdk-session-sync-service.mjs +207 -0
  242. package/server/services/session-history-refresh-service.mjs +497 -0
  243. package/server/services/session-transcript-service.mjs +419 -0
  244. package/server/services/session-worker-launch-service.mjs +786 -0
  245. package/server/services/session-worker-process-service.mjs +319 -0
  246. package/server/services/session-worker-registry-service.mjs +194 -0
  247. package/server/services/session-worker-stop-service.mjs +141 -0
  248. package/server/services/session-worker-supervisor-service.mjs +898 -0
  249. package/server/services/session-worker-websocket-service.mjs +483 -0
  250. package/server/services/ssh-tunnel-manager-service.mjs +423 -0
  251. package/server/services/status-event-service.mjs +158 -0
  252. package/server/services/tmux-inspector-access-policy.mjs +77 -0
  253. package/server/services/tmux-inspector-socket-service.mjs +191 -0
  254. package/server/services/tmux-inspector-stream-service.mjs +552 -0
  255. package/server/services/tunnel-worker-path-guard.mjs +107 -0
  256. package/server/services/upload-sweep.mjs +60 -0
  257. package/server/services/usage-snapshot-helpers.mjs +209 -0
  258. package/server/services/windows-autostart-service.mjs +115 -0
  259. package/server/services/workspace-root-defaults-service.mjs +34 -0
  260. package/server/services/workspace-root-path-policy.mjs +196 -0
  261. package/server/services/workspace-root-relaunch-service.mjs +132 -0
  262. package/server/services/workspace-symlink-guard.mjs +54 -0
  263. package/server/tools/capture-proxy.mjs +173 -0
  264. package/server/tty-console-bootstrap.mjs +75 -0
  265. package/server/uploads/README.md +36 -0
  266. package/server/uploads/image_input.md +540 -0
  267. package/server/windows-terminal-launcher.mjs +29 -0
  268. package/server/workspace-root.mjs +87 -0
  269. package/shared/ask-user-bridge.mjs +131 -0
  270. package/shared/auto-compact-window.mjs +116 -0
  271. package/shared/background-task-timeout.mjs +52 -0
  272. package/shared/claude-thinking.mjs +101 -0
  273. package/shared/context-window-fallbacks.mjs +148 -0
  274. package/shared/control-poller.mjs +115 -0
  275. package/shared/empty-turn-completion.mjs +20 -0
  276. package/shared/model-catalog-freshness.mjs +11 -0
  277. package/shared/model-descriptors.mjs +118 -0
  278. package/shared/model-id.mjs +147 -0
  279. package/shared/model-refresh.mjs +24 -0
  280. package/shared/openai-reasoning.mjs +13 -0
  281. package/shared/plan-lines.mjs +13 -0
  282. package/shared/preview-instructions.mjs +77 -0
  283. package/shared/preview-tool-core.mjs +191 -0
  284. package/shared/provider-routing.mjs +29 -0
  285. package/shared/question-schema.mjs +315 -0
  286. package/shared/question-timeout.mjs +18 -0
  287. package/shared/stream-emit-gating.mjs +28 -0
  288. package/shared/subagent-run-id.mjs +17 -0
  289. package/shared/thought-cap.mjs +13 -0
  290. package/shared/tool-activity.mjs +98 -0
  291. package/shared/turn-ceiling.mjs +53 -0
  292. package/shared/worker-bootstrap.mjs +44 -0
  293. package/shared/worker-crash-guard.mjs +60 -0
@@ -0,0 +1,243 @@
1
+ import {
2
+ formatStoreMemoryActivity,
3
+ formatToolResultActivity as formatSharedToolResultActivity,
4
+ formatVoteMemoryActivity,
5
+ } from "../../../../shared/tool-activity.mjs";
6
+
7
+ export function normalizeActivityText(value, maxToolDetailLength = 140) {
8
+ const text = String(value || "").trim();
9
+ if (!text) return "";
10
+ return text.replace(/\s+/g, " ").slice(0, maxToolDetailLength);
11
+ }
12
+
13
+ export function parseMaybeJson(value) {
14
+ if (typeof value !== "string") return value;
15
+ const text = value.trim();
16
+ if (!text || (!text.startsWith("{") && !text.startsWith("["))) return value;
17
+ try {
18
+ return JSON.parse(text);
19
+ } catch {
20
+ return value;
21
+ }
22
+ }
23
+
24
+ export function parsedQuestionSources(request) {
25
+ const parsedToolArgs = parseMaybeJson(request?.toolArgs);
26
+ const parsedInput = parseMaybeJson(request?.input);
27
+ const parsedArguments = parseMaybeJson(request?.arguments);
28
+ const parsedArgs = parseMaybeJson(request?.args);
29
+ const parsedBody = parseMaybeJson(request?.body);
30
+ const parsedRequest = parseMaybeJson(request?.request);
31
+ return [
32
+ request,
33
+ parsedToolArgs,
34
+ parsedInput,
35
+ parsedArguments,
36
+ parsedArgs,
37
+ parsedBody,
38
+ parsedRequest,
39
+ parsedBody?.input,
40
+ parsedBody?.arguments,
41
+ parsedRequest?.input,
42
+ parsedRequest?.arguments,
43
+ ].filter(Boolean);
44
+ }
45
+
46
+ export function toolArgsSnapshot(request) {
47
+ const candidates = [
48
+ request?.toolArgs,
49
+ request?.arguments,
50
+ request?.args,
51
+ request?.input,
52
+ request?.payload,
53
+ request?.toolInput,
54
+ request?.toolCall?.arguments,
55
+ request?.toolCall?.input,
56
+ ];
57
+ for (const value of candidates) {
58
+ const parsed = parseMaybeJson(value);
59
+ if (parsed && typeof parsed === "object") return parsed;
60
+ }
61
+ return {};
62
+ }
63
+
64
+ export function extractToolName(request) {
65
+ const candidates = [
66
+ request?.toolName,
67
+ request?.name,
68
+ request?.tool?.name,
69
+ request?.tool?.id,
70
+ request?.toolCall?.name,
71
+ request?.toolCall?.toolName,
72
+ ];
73
+
74
+ for (const value of candidates) {
75
+ if (typeof value === "string" && value.trim()) return value.trim();
76
+ }
77
+ return "";
78
+ }
79
+
80
+ export function extractToolDetail(request, maxToolDetailLength = 140) {
81
+ const args = toolArgsSnapshot(request);
82
+ const name = extractToolName(request).toLowerCase();
83
+ const candidateText = normalizeActivityText(
84
+ args.question ||
85
+ args.prompt ||
86
+ args.description ||
87
+ args.intent ||
88
+ args.pattern ||
89
+ args.path ||
90
+ args.query ||
91
+ args.url ||
92
+ args.command ||
93
+ "",
94
+ maxToolDetailLength,
95
+ );
96
+
97
+ if (name.includes("ask_user") && candidateText) return `question=\"${candidateText}\"`;
98
+ if ((name.includes("glob") || name.includes("rg") || name.includes("grep")) && candidateText) return `query=\"${candidateText}\"`;
99
+ if (name.includes("powershell") && candidateText) return `command=\"${candidateText}\"`;
100
+ if (candidateText) return candidateText;
101
+ return "";
102
+ }
103
+
104
+ export function formatToolActivity(request, maxToolDetailLength = 140) {
105
+ const rawName = extractToolName(request);
106
+ if (!rawName) return null;
107
+
108
+ const lower = rawName.toLowerCase();
109
+ const detail = extractToolDetail(request, maxToolDetailLength);
110
+
111
+ if (lower.includes("store_memory")) {
112
+ return formatStoreMemoryActivity(rawName, toolArgsSnapshot(request));
113
+ }
114
+ if (lower.includes("vote_memory")) {
115
+ return formatVoteMemoryActivity(rawName, toolArgsSnapshot(request));
116
+ }
117
+
118
+ if (lower.includes("search (glob)") || /(^|[.\s_-])glob($|[.\s_-])/.test(lower)) {
119
+ return detail ? `Search (glob): ${detail}` : "Search (glob)";
120
+ }
121
+ if (lower.includes("search (grep)") || /(^|[.\s_-])(rg|grep)($|[.\s_-])/.test(lower)) {
122
+ return detail ? `Search (grep): ${detail}` : "Search (grep)";
123
+ }
124
+ if (lower.includes("web_search") || lower.includes("web search")) {
125
+ return detail ? `Web Search: ${detail}` : "Web Search";
126
+ }
127
+ if (lower.includes("web_fetch") || lower.includes("web fetch")) {
128
+ return detail ? `Web Fetch: ${detail}` : "Web Fetch";
129
+ }
130
+ if (lower.includes("ask_user")) {
131
+ return detail ? `Tool (ask_user): ${detail}` : "Tool (ask_user)";
132
+ }
133
+ if (lower.includes("report_intent")) {
134
+ return detail ? `● ${detail}` : "● Working…";
135
+ }
136
+ return detail ? `Tool (${rawName}): ${detail}` : `Tool (${rawName})`;
137
+ }
138
+
139
+ export function formatToolResultActivity(request, result, maxToolDetailLength = 140) {
140
+ return formatSharedToolResultActivity(extractToolName(request), result, maxToolDetailLength);
141
+ }
142
+
143
+ export function isAskUserTool(request) {
144
+ return extractToolName(request).toLowerCase().includes("ask_user");
145
+ }
146
+
147
+ export function extractQuestionPrompt(request) {
148
+ const candidates = [];
149
+ for (const source of parsedQuestionSources(request)) {
150
+ candidates.push(
151
+ source?.prompt,
152
+ source?.text,
153
+ source?.message,
154
+ source?.question,
155
+ source?.content,
156
+ source?.instruction,
157
+ );
158
+ }
159
+
160
+ for (const value of candidates) {
161
+ if (typeof value === "string" && value.trim()) return value.trim();
162
+ }
163
+
164
+ if (request && typeof request === "object") {
165
+ const keys = Object.keys(request).slice(0, 8);
166
+ if (keys.length) {
167
+ return `Clarification needed (${keys.join(", ")})`;
168
+ }
169
+ }
170
+
171
+ return "Clarification needed";
172
+ }
173
+
174
+ export function extractQuestionChoices(request) {
175
+ const rawCandidates = [];
176
+ for (const source of parsedQuestionSources(request)) {
177
+ rawCandidates.push(
178
+ source?.choices,
179
+ source?.options,
180
+ source?.items,
181
+ source?.suggestions,
182
+ );
183
+ // Also check JSON Schema format: requestedSchema.properties.*.oneOf or enum
184
+ const schema = source?.requestedSchema;
185
+ if (schema?.properties) {
186
+ for (const prop of Object.values(schema.properties)) {
187
+ if (Array.isArray(prop?.oneOf)) {
188
+ rawCandidates.push(prop.oneOf);
189
+ }
190
+ if (Array.isArray(prop?.enum)) {
191
+ rawCandidates.push(prop.enum);
192
+ }
193
+ }
194
+ }
195
+ }
196
+
197
+ const raw = rawCandidates.find((value) => Array.isArray(value)) || [];
198
+ if (!Array.isArray(raw)) return [];
199
+ return raw
200
+ .map((choice) => {
201
+ if (typeof choice === "string") return choice.trim();
202
+ if (choice && typeof choice === "object") {
203
+ // Support JSON Schema oneOf format: {const: "value", title: "Display Label"}
204
+ return String(choice.title || choice.label || choice.text || choice.value || choice.const || "").trim();
205
+ }
206
+ return "";
207
+ })
208
+ .filter(Boolean)
209
+ .slice(0, 8);
210
+ }
211
+
212
+ export function buildAskUserQuestionRequest(request) {
213
+ const args = toolArgsSnapshot(request);
214
+ return {
215
+ prompt:
216
+ args?.question ||
217
+ args?.prompt ||
218
+ args?.message ||
219
+ request?.question ||
220
+ request?.prompt ||
221
+ "Clarification needed",
222
+ choices: extractQuestionChoices({ ...request, ...args }),
223
+ allow_freeform: args?.allow_freeform,
224
+ request,
225
+ };
226
+ }
227
+
228
+ export function serializeRequest(request) {
229
+ if (!request || typeof request !== "object") return null;
230
+ const seen = new WeakSet();
231
+ try {
232
+ return JSON.stringify(request, (key, value) => {
233
+ if (typeof value === "function") return `[Function ${value.name || "anonymous"}]`;
234
+ if (typeof value === "object" && value !== null) {
235
+ if (seen.has(value)) return "[Circular]";
236
+ seen.add(value);
237
+ }
238
+ return value;
239
+ });
240
+ } catch {
241
+ return null;
242
+ }
243
+ }
@@ -0,0 +1,25 @@
1
+ export function delay(ms) {
2
+ return new Promise((resolve) => setTimeout(resolve, ms));
3
+ }
4
+
5
+ export function sleep(ms) {
6
+ return new Promise((resolve) => setTimeout(resolve, ms));
7
+ }
8
+
9
+ export function killProcessTree(proc) {
10
+ if (!proc || proc.exitCode !== null) return;
11
+
12
+ const isWindows = process.platform === "win32";
13
+ const pidTarget = (!isWindows && proc.spawnargs) ? -proc.pid : proc.pid;
14
+
15
+ try {
16
+ process.kill(pidTarget, "SIGTERM");
17
+ } catch {
18
+ return;
19
+ }
20
+
21
+ setTimeout(() => {
22
+ if (proc.exitCode !== null) return;
23
+ try { process.kill(pidTarget, "SIGKILL"); } catch {}
24
+ }, 1200);
25
+ }
@@ -0,0 +1,58 @@
1
+ import { randomBytes } from "crypto";
2
+
3
+ const TOKEN_FALLBACK_ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
4
+
5
+ function randomInt(maxExclusive) {
6
+ if (!Number.isInteger(maxExclusive) || maxExclusive <= 0) {
7
+ throw new Error("randomInt maxExclusive must be a positive integer");
8
+ }
9
+ const threshold = Math.floor(256 / maxExclusive) * maxExclusive;
10
+ while (true) {
11
+ const value = randomBytes(1)[0];
12
+ if (value < threshold) return value % maxExclusive;
13
+ }
14
+ }
15
+
16
+ function generateRandomToken(length, alphabet) {
17
+ if (!Number.isInteger(length) || length <= 0 || length > alphabet.length) {
18
+ throw new Error("Token length must be a positive integer up to alphabet size");
19
+ }
20
+ const pool = alphabet.split("");
21
+ let token = "";
22
+ for (let i = 0; i < length; i += 1) {
23
+ const idx = randomInt(pool.length);
24
+ token += pool[idx];
25
+ pool.splice(idx, 1);
26
+ }
27
+ return token;
28
+ }
29
+
30
+ function normalizedEntropy(value) {
31
+ const token = String(value || "");
32
+ if (!token.length) return 0;
33
+ const counts = new Map();
34
+ for (const ch of token) {
35
+ counts.set(ch, (counts.get(ch) || 0) + 1);
36
+ }
37
+ const unique = counts.size;
38
+ if (unique <= 1) return 0;
39
+ let entropy = 0;
40
+ for (const count of counts.values()) {
41
+ const p = count / token.length;
42
+ entropy -= p * Math.log2(p);
43
+ }
44
+ const maxEntropy = Math.log2(unique);
45
+ return maxEntropy > 0 ? entropy / maxEntropy : 0;
46
+ }
47
+
48
+ export function generateHighEntropyToken({
49
+ length = 16,
50
+ minEntropy = 0.95,
51
+ alphabet = TOKEN_FALLBACK_ALPHABET,
52
+ } = {}) {
53
+ for (let attempt = 0; attempt < 32; attempt += 1) {
54
+ const token = generateRandomToken(length, alphabet);
55
+ if (normalizedEntropy(token) >= minEntropy) return token;
56
+ }
57
+ throw new Error(`Could not generate fallback token with normalized entropy >= ${minEntropy}`);
58
+ }
package/CHANGELOG.md ADDED
@@ -0,0 +1,25 @@
1
+ # Changelog
2
+
3
+ All notable changes to OAR are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow semver.
5
+
6
+ ## [0.9.0] — 2026-09-02
7
+
8
+ ### Changed
9
+
10
+ - **The project is now OAR — Open Agent Relay** (`@oar-sh/oar`, binary `oar`,
11
+ home at [oar.sh](https://oar.sh)). It began life as `copilot-remote` and has
12
+ long outgrown the name: one relay now drives Copilot (CLI extension or SDK
13
+ engine), Claude (Agent SDK), Cursor, Grok, and OpenAI BYOK.
14
+ - Global installs keep their state in `~/.oar` (`%APPDATA%\oar` on Windows) so
15
+ `npm i -g` updates can never touch the database. Existing state from a git
16
+ checkout or the legacy managed config dir is migrated in once, copy-never-move,
17
+ with WAL checkpointing and integrity verification; the old tree is left behind
18
+ as the rollback path. Git checkouts keep their repo-local layout unchanged.
19
+ - The published npm package now contains only the runtime (an explicit `files`
20
+ allowlist); tests, docs, and screenshots stay in the repo.
21
+
22
+ ### Added
23
+
24
+ - `oar --migrate-from <old-checkout>` imports relay state from a pre-rename
25
+ checkout into `~/.oar`.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Simon
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.