uxnan-bridge 0.0.1-alpha.20260621

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 (255) hide show
  1. package/README.md +150 -0
  2. package/dist/src/account-status.d.ts +13 -0
  3. package/dist/src/account-status.js +78 -0
  4. package/dist/src/account-status.js.map +1 -0
  5. package/dist/src/adapters/base-adapter.d.ts +18 -0
  6. package/dist/src/adapters/base-adapter.js +15 -0
  7. package/dist/src/adapters/base-adapter.js.map +1 -0
  8. package/dist/src/adapters/claude-adapter.d.ts +102 -0
  9. package/dist/src/adapters/claude-adapter.js +486 -0
  10. package/dist/src/adapters/claude-adapter.js.map +1 -0
  11. package/dist/src/adapters/claude-tools.d.ts +25 -0
  12. package/dist/src/adapters/claude-tools.js +146 -0
  13. package/dist/src/adapters/claude-tools.js.map +1 -0
  14. package/dist/src/adapters/codex-adapter.d.ts +116 -0
  15. package/dist/src/adapters/codex-adapter.js +912 -0
  16. package/dist/src/adapters/codex-adapter.js.map +1 -0
  17. package/dist/src/adapters/codex-app-server.d.ts +74 -0
  18. package/dist/src/adapters/codex-app-server.js +225 -0
  19. package/dist/src/adapters/codex-app-server.js.map +1 -0
  20. package/dist/src/adapters/codex-approval.d.ts +88 -0
  21. package/dist/src/adapters/codex-approval.js +160 -0
  22. package/dist/src/adapters/codex-approval.js.map +1 -0
  23. package/dist/src/adapters/codex-tools.d.ts +18 -0
  24. package/dist/src/adapters/codex-tools.js +106 -0
  25. package/dist/src/adapters/codex-tools.js.map +1 -0
  26. package/dist/src/adapters/content-blocks.d.ts +68 -0
  27. package/dist/src/adapters/content-blocks.js +205 -0
  28. package/dist/src/adapters/content-blocks.js.map +1 -0
  29. package/dist/src/adapters/echo-agent-adapter.d.ts +23 -0
  30. package/dist/src/adapters/echo-agent-adapter.js +72 -0
  31. package/dist/src/adapters/echo-agent-adapter.js.map +1 -0
  32. package/dist/src/adapters/gemini-adapter.d.ts +87 -0
  33. package/dist/src/adapters/gemini-adapter.js +594 -0
  34. package/dist/src/adapters/gemini-adapter.js.map +1 -0
  35. package/dist/src/adapters/gemini-tools.d.ts +4 -0
  36. package/dist/src/adapters/gemini-tools.js +48 -0
  37. package/dist/src/adapters/gemini-tools.js.map +1 -0
  38. package/dist/src/adapters/opencode-adapter.d.ts +74 -0
  39. package/dist/src/adapters/opencode-adapter.js +418 -0
  40. package/dist/src/adapters/opencode-adapter.js.map +1 -0
  41. package/dist/src/adapters/opencode-tools.d.ts +2 -0
  42. package/dist/src/adapters/opencode-tools.js +41 -0
  43. package/dist/src/adapters/opencode-tools.js.map +1 -0
  44. package/dist/src/adapters/pi-adapter.d.ts +92 -0
  45. package/dist/src/adapters/pi-adapter.js +467 -0
  46. package/dist/src/adapters/pi-adapter.js.map +1 -0
  47. package/dist/src/adapters/pi-tools.d.ts +10 -0
  48. package/dist/src/adapters/pi-tools.js +72 -0
  49. package/dist/src/adapters/pi-tools.js.map +1 -0
  50. package/dist/src/adapters/process-agent-adapter.d.ts +24 -0
  51. package/dist/src/adapters/process-agent-adapter.js +111 -0
  52. package/dist/src/adapters/process-agent-adapter.js.map +1 -0
  53. package/dist/src/adapters/resolve-claude.d.ts +13 -0
  54. package/dist/src/adapters/resolve-claude.js +57 -0
  55. package/dist/src/adapters/resolve-claude.js.map +1 -0
  56. package/dist/src/adapters/resolve-codex.d.ts +13 -0
  57. package/dist/src/adapters/resolve-codex.js +48 -0
  58. package/dist/src/adapters/resolve-codex.js.map +1 -0
  59. package/dist/src/adapters/resolve-gemini.d.ts +13 -0
  60. package/dist/src/adapters/resolve-gemini.js +47 -0
  61. package/dist/src/adapters/resolve-gemini.js.map +1 -0
  62. package/dist/src/adapters/resolve-opencode.d.ts +11 -0
  63. package/dist/src/adapters/resolve-opencode.js +49 -0
  64. package/dist/src/adapters/resolve-opencode.js.map +1 -0
  65. package/dist/src/adapters/resolve-pi.d.ts +13 -0
  66. package/dist/src/adapters/resolve-pi.js +46 -0
  67. package/dist/src/adapters/resolve-pi.js.map +1 -0
  68. package/dist/src/adapters/run-options.d.ts +22 -0
  69. package/dist/src/adapters/run-options.js +48 -0
  70. package/dist/src/adapters/run-options.js.map +1 -0
  71. package/dist/src/adapters/spawn.d.ts +20 -0
  72. package/dist/src/adapters/spawn.js +16 -0
  73. package/dist/src/adapters/spawn.js.map +1 -0
  74. package/dist/src/agents/agent-manager.d.ts +98 -0
  75. package/dist/src/agents/agent-manager.js +433 -0
  76. package/dist/src/agents/agent-manager.js.map +1 -0
  77. package/dist/src/agents/attachments.d.ts +28 -0
  78. package/dist/src/agents/attachments.js +121 -0
  79. package/dist/src/agents/attachments.js.map +1 -0
  80. package/dist/src/bridge-context.d.ts +45 -0
  81. package/dist/src/bridge-context.js +2 -0
  82. package/dist/src/bridge-context.js.map +1 -0
  83. package/dist/src/bridge-status.d.ts +12 -0
  84. package/dist/src/bridge-status.js +17 -0
  85. package/dist/src/bridge-status.js.map +1 -0
  86. package/dist/src/bridge.d.ts +37 -0
  87. package/dist/src/bridge.js +446 -0
  88. package/dist/src/bridge.js.map +1 -0
  89. package/dist/src/cli.d.ts +2 -0
  90. package/dist/src/cli.js +194 -0
  91. package/dist/src/cli.js.map +1 -0
  92. package/dist/src/conversation/session-history.d.ts +27 -0
  93. package/dist/src/conversation/session-history.js +1082 -0
  94. package/dist/src/conversation/session-history.js.map +1 -0
  95. package/dist/src/conversation/thread-store.d.ts +74 -0
  96. package/dist/src/conversation/thread-store.js +366 -0
  97. package/dist/src/conversation/thread-store.js.map +1 -0
  98. package/dist/src/daemon-config.d.ts +123 -0
  99. package/dist/src/daemon-config.js +64 -0
  100. package/dist/src/daemon-config.js.map +1 -0
  101. package/dist/src/daemon-state.d.ts +27 -0
  102. package/dist/src/daemon-state.js +76 -0
  103. package/dist/src/daemon-state.js.map +1 -0
  104. package/dist/src/git/git-runner.d.ts +24 -0
  105. package/dist/src/git/git-runner.js +63 -0
  106. package/dist/src/git/git-runner.js.map +1 -0
  107. package/dist/src/git/git-service.d.ts +76 -0
  108. package/dist/src/git/git-service.js +435 -0
  109. package/dist/src/git/git-service.js.map +1 -0
  110. package/dist/src/handler-router.d.ts +34 -0
  111. package/dist/src/handler-router.js +67 -0
  112. package/dist/src/handler-router.js.map +1 -0
  113. package/dist/src/handlers/account-handler.d.ts +4 -0
  114. package/dist/src/handlers/account-handler.js +27 -0
  115. package/dist/src/handlers/account-handler.js.map +1 -0
  116. package/dist/src/handlers/agent-handler.d.ts +2 -0
  117. package/dist/src/handlers/agent-handler.js +8 -0
  118. package/dist/src/handlers/agent-handler.js.map +1 -0
  119. package/dist/src/handlers/bridge-control-handler.d.ts +2 -0
  120. package/dist/src/handlers/bridge-control-handler.js +64 -0
  121. package/dist/src/handlers/bridge-control-handler.js.map +1 -0
  122. package/dist/src/handlers/desktop-handler.d.ts +12 -0
  123. package/dist/src/handlers/desktop-handler.js +5 -0
  124. package/dist/src/handlers/desktop-handler.js.map +1 -0
  125. package/dist/src/handlers/git-handler.d.ts +2 -0
  126. package/dist/src/handlers/git-handler.js +82 -0
  127. package/dist/src/handlers/git-handler.js.map +1 -0
  128. package/dist/src/handlers/index.d.ts +8 -0
  129. package/dist/src/handlers/index.js +22 -0
  130. package/dist/src/handlers/index.js.map +1 -0
  131. package/dist/src/handlers/not-implemented.d.ts +10 -0
  132. package/dist/src/handlers/not-implemented.js +21 -0
  133. package/dist/src/handlers/not-implemented.js.map +1 -0
  134. package/dist/src/handlers/notifications-handler.d.ts +2 -0
  135. package/dist/src/handlers/notifications-handler.js +62 -0
  136. package/dist/src/handlers/notifications-handler.js.map +1 -0
  137. package/dist/src/handlers/params.d.ts +11 -0
  138. package/dist/src/handlers/params.js +72 -0
  139. package/dist/src/handlers/params.js.map +1 -0
  140. package/dist/src/handlers/project-handler.d.ts +2 -0
  141. package/dist/src/handlers/project-handler.js +6 -0
  142. package/dist/src/handlers/project-handler.js.map +1 -0
  143. package/dist/src/handlers/thread-context-handler.d.ts +2 -0
  144. package/dist/src/handlers/thread-context-handler.js +211 -0
  145. package/dist/src/handlers/thread-context-handler.js.map +1 -0
  146. package/dist/src/handlers/workspace-handler.d.ts +2 -0
  147. package/dist/src/handlers/workspace-handler.js +101 -0
  148. package/dist/src/handlers/workspace-handler.js.map +1 -0
  149. package/dist/src/hooks/claude-approval-hook.d.ts +7 -0
  150. package/dist/src/hooks/claude-approval-hook.js +95 -0
  151. package/dist/src/hooks/claude-approval-hook.js.map +1 -0
  152. package/dist/src/hooks/gemini-approval-hook.d.ts +7 -0
  153. package/dist/src/hooks/gemini-approval-hook.js +113 -0
  154. package/dist/src/hooks/gemini-approval-hook.js.map +1 -0
  155. package/dist/src/index.d.ts +62 -0
  156. package/dist/src/index.js +65 -0
  157. package/dist/src/index.js.map +1 -0
  158. package/dist/src/keyring-secret-store.d.ts +36 -0
  159. package/dist/src/keyring-secret-store.js +70 -0
  160. package/dist/src/keyring-secret-store.js.map +1 -0
  161. package/dist/src/lock-file.d.ts +18 -0
  162. package/dist/src/lock-file.js +60 -0
  163. package/dist/src/lock-file.js.map +1 -0
  164. package/dist/src/logger.d.ts +28 -0
  165. package/dist/src/logger.js +99 -0
  166. package/dist/src/logger.js.map +1 -0
  167. package/dist/src/pairing/pairing-code-service.d.ts +45 -0
  168. package/dist/src/pairing/pairing-code-service.js +183 -0
  169. package/dist/src/pairing/pairing-code-service.js.map +1 -0
  170. package/dist/src/projects/project-registry.d.ts +14 -0
  171. package/dist/src/projects/project-registry.js +60 -0
  172. package/dist/src/projects/project-registry.js.map +1 -0
  173. package/dist/src/push/push-sender.d.ts +21 -0
  174. package/dist/src/push/push-sender.js +96 -0
  175. package/dist/src/push/push-sender.js.map +1 -0
  176. package/dist/src/push/push-service.d.ts +122 -0
  177. package/dist/src/push/push-service.js +260 -0
  178. package/dist/src/push/push-service.js.map +1 -0
  179. package/dist/src/qr.d.ts +17 -0
  180. package/dist/src/qr.js +31 -0
  181. package/dist/src/qr.js.map +1 -0
  182. package/dist/src/secret-store.d.ts +23 -0
  183. package/dist/src/secret-store.js +27 -0
  184. package/dist/src/secret-store.js.map +1 -0
  185. package/dist/src/secure-device-state.d.ts +16 -0
  186. package/dist/src/secure-device-state.js +63 -0
  187. package/dist/src/secure-device-state.js.map +1 -0
  188. package/dist/src/service-installer.d.ts +57 -0
  189. package/dist/src/service-installer.js +254 -0
  190. package/dist/src/service-installer.js.map +1 -0
  191. package/dist/src/session-state.d.ts +14 -0
  192. package/dist/src/session-state.js +19 -0
  193. package/dist/src/session-state.js.map +1 -0
  194. package/dist/src/transport/crypto.d.ts +43 -0
  195. package/dist/src/transport/crypto.js +78 -0
  196. package/dist/src/transport/crypto.js.map +1 -0
  197. package/dist/src/transport/lan-server.d.ts +33 -0
  198. package/dist/src/transport/lan-server.js +105 -0
  199. package/dist/src/transport/lan-server.js.map +1 -0
  200. package/dist/src/transport/local-hosts.d.ts +17 -0
  201. package/dist/src/transport/local-hosts.js +30 -0
  202. package/dist/src/transport/local-hosts.js.map +1 -0
  203. package/dist/src/transport/mdns-advertiser.d.ts +83 -0
  204. package/dist/src/transport/mdns-advertiser.js +282 -0
  205. package/dist/src/transport/mdns-advertiser.js.map +1 -0
  206. package/dist/src/transport/message-io.d.ts +33 -0
  207. package/dist/src/transport/message-io.js +87 -0
  208. package/dist/src/transport/message-io.js.map +1 -0
  209. package/dist/src/transport/outbound-log.d.ts +24 -0
  210. package/dist/src/transport/outbound-log.js +78 -0
  211. package/dist/src/transport/outbound-log.js.map +1 -0
  212. package/dist/src/transport/relay-client.d.ts +19 -0
  213. package/dist/src/transport/relay-client.js +27 -0
  214. package/dist/src/transport/relay-client.js.map +1 -0
  215. package/dist/src/transport/secure-channel.d.ts +33 -0
  216. package/dist/src/transport/secure-channel.js +81 -0
  217. package/dist/src/transport/secure-channel.js.map +1 -0
  218. package/dist/src/transport/server-handshake.d.ts +49 -0
  219. package/dist/src/transport/server-handshake.js +137 -0
  220. package/dist/src/transport/server-handshake.js.map +1 -0
  221. package/dist/src/transport/session-handler.d.ts +19 -0
  222. package/dist/src/transport/session-handler.js +134 -0
  223. package/dist/src/transport/session-handler.js.map +1 -0
  224. package/dist/src/transport/session-registry.d.ts +58 -0
  225. package/dist/src/transport/session-registry.js +91 -0
  226. package/dist/src/transport/session-registry.js.map +1 -0
  227. package/dist/src/transport/trust-store.d.ts +23 -0
  228. package/dist/src/transport/trust-store.js +33 -0
  229. package/dist/src/transport/trust-store.js.map +1 -0
  230. package/dist/src/transport/ws-adapter.d.ts +7 -0
  231. package/dist/src/transport/ws-adapter.js +16 -0
  232. package/dist/src/transport/ws-adapter.js.map +1 -0
  233. package/dist/src/version.d.ts +1 -0
  234. package/dist/src/version.js +13 -0
  235. package/dist/src/version.js.map +1 -0
  236. package/dist/src/workspace/browse-service.d.ts +10 -0
  237. package/dist/src/workspace/browse-service.js +97 -0
  238. package/dist/src/workspace/browse-service.js.map +1 -0
  239. package/dist/src/workspace/checkpoint-service.d.ts +21 -0
  240. package/dist/src/workspace/checkpoint-service.js +219 -0
  241. package/dist/src/workspace/checkpoint-service.js.map +1 -0
  242. package/dist/src/workspace/path-guard.d.ts +7 -0
  243. package/dist/src/workspace/path-guard.js +51 -0
  244. package/dist/src/workspace/path-guard.js.map +1 -0
  245. package/dist/src/workspace/workspace-service.d.ts +8 -0
  246. package/dist/src/workspace/workspace-service.js +111 -0
  247. package/dist/src/workspace/workspace-service.js.map +1 -0
  248. package/package.json +46 -0
  249. package/scripts/extract-gemini-hook.mjs +16 -0
  250. package/scripts/fake-approval-bridge.mjs +23 -0
  251. package/scripts/install-service-linux.sh +38 -0
  252. package/scripts/install-service-macos.sh +38 -0
  253. package/scripts/install-service-windows.ps1 +26 -0
  254. package/scripts/test-gemini-hook-e2e.mjs +168 -0
  255. package/scripts/write-gemini-settings.mjs +31 -0
@@ -0,0 +1,435 @@
1
+ /**
2
+ * Git operations, returning the shared result types. Each method runs git in the
3
+ * given project `cwd`. Failures surface as {@link GitCommandError}.
4
+ *
5
+ * Source: architecture/02a-system-architecture.md §5.8.6.
6
+ */
7
+ import { readFile, rm } from 'node:fs/promises';
8
+ import { join } from 'node:path';
9
+ import { GitCommandError, runGh, runGit } from './git-runner.js';
10
+ export class GitService {
11
+ async status(cwd) {
12
+ const [branch, upstream, aheadBehind, files] = await Promise.all([
13
+ this.#currentBranch(cwd),
14
+ this.#upstream(cwd),
15
+ this.#aheadBehind(cwd),
16
+ this.#changedFiles(cwd),
17
+ ]);
18
+ const diffTotals = files.reduce((totals, file) => ({
19
+ additions: totals.additions + (file.additions ?? 0),
20
+ deletions: totals.deletions + (file.deletions ?? 0),
21
+ changedFileCount: totals.changedFileCount + 1,
22
+ }), { additions: 0, deletions: 0, changedFileCount: 0 });
23
+ return {
24
+ branch,
25
+ isDirty: files.length > 0,
26
+ ...aheadBehind,
27
+ files,
28
+ diffTotals,
29
+ ...(upstream ? { upstream } : {}),
30
+ };
31
+ }
32
+ /**
33
+ * Returns the working-tree diff. With `path`, returns just that file's diff —
34
+ * for an untracked file (no diff vs HEAD) it synthesises an all-additions
35
+ * unified diff from the file contents so the phone can render it.
36
+ */
37
+ async diff(cwd, path) {
38
+ const ref = (await this.#hasHead(cwd)) ? ['HEAD'] : [];
39
+ const pathArgs = path ? ['--', path] : [];
40
+ const { stdout: diff } = await runGit(cwd, ['diff', ...ref, ...pathArgs]);
41
+ const { stdout: numstat } = await runGit(cwd, ['diff', '--numstat', ...ref, ...pathArgs]);
42
+ let { additions, deletions } = this.#sumNumstat(numstat);
43
+ let text = diff;
44
+ if (path && diff.trim() === '' && (await this.#isUntracked(cwd, path))) {
45
+ const synth = await this.#untrackedDiff(cwd, path);
46
+ text = synth.diff;
47
+ additions = synth.additions;
48
+ deletions = 0;
49
+ }
50
+ return { diff: text, additions, deletions };
51
+ }
52
+ async commit(cwd, message, paths) {
53
+ if (paths && paths.length > 0) {
54
+ await runGit(cwd, ['add', '--', ...paths]);
55
+ }
56
+ else {
57
+ await runGit(cwd, ['add', '-A']);
58
+ }
59
+ await runGit(cwd, ['commit', '-m', message]);
60
+ const { stdout } = await runGit(cwd, ['rev-parse', 'HEAD']);
61
+ return { sha: stdout.trim(), message };
62
+ }
63
+ /**
64
+ * Undoes the most recent commit, keeping its changes in the working tree
65
+ * (`git reset --soft HEAD~1`) so the user can re-stage/re-commit before
66
+ * pushing. Non-destructive: no file content is lost.
67
+ */
68
+ async undoCommit(cwd) {
69
+ await runGit(cwd, ['reset', '--soft', 'HEAD~1']);
70
+ }
71
+ /** Lists the current branch plus all local and remote branches. */
72
+ async branches(cwd) {
73
+ const [current, localOut, remoteOut] = await Promise.all([
74
+ this.#currentBranch(cwd),
75
+ runGit(cwd, ['branch', '--format=%(refname:short)']),
76
+ runGit(cwd, ['branch', '-r', '--format=%(refname:short)']),
77
+ ]);
78
+ const local = localOut.stdout
79
+ .split('\n')
80
+ .map((b) => b.trim())
81
+ .filter(Boolean);
82
+ const remote = remoteOut.stdout
83
+ .split('\n')
84
+ .map((b) => b.trim())
85
+ .filter((b) => b && !b.endsWith('/HEAD') && !b.includes('->'));
86
+ return { current, local, remote };
87
+ }
88
+ /** Stages the given paths (`git add`). */
89
+ async stage(cwd, paths) {
90
+ if (paths.length === 0)
91
+ return;
92
+ await runGit(cwd, ['add', '--', ...paths]);
93
+ }
94
+ /** Unstages the given paths, keeping working-tree changes (`git restore --staged`). */
95
+ async unstage(cwd, paths) {
96
+ if (paths.length === 0)
97
+ return;
98
+ await runGit(cwd, ['restore', '--staged', '--', ...paths]);
99
+ }
100
+ /**
101
+ * Discards working-tree changes for the given paths. Tracked files are
102
+ * restored from HEAD (index + worktree); untracked files are deleted. This is
103
+ * destructive and irreversible — callers must confirm first.
104
+ */
105
+ async discard(cwd, paths) {
106
+ if (paths.length === 0)
107
+ return;
108
+ const untracked = new Set((await this.#changedFiles(cwd)).filter((f) => f.status === 'untracked').map((f) => f.path));
109
+ const tracked = paths.filter((p) => !untracked.has(p));
110
+ const toDelete = paths.filter((p) => untracked.has(p));
111
+ if (tracked.length > 0) {
112
+ await runGit(cwd, ['restore', '--staged', '--worktree', '--', ...tracked]);
113
+ }
114
+ for (const path of toDelete) {
115
+ await rm(join(cwd, path), { force: true, recursive: true });
116
+ }
117
+ }
118
+ /**
119
+ * Opens a pull request via the GitHub CLI (`gh pr create`). Requires `gh` to
120
+ * be installed and authenticated; failures surface as {@link GitCommandError}
121
+ * with an actionable message. Returns the PR URL.
122
+ */
123
+ async createPr(cwd, title, body, base, head) {
124
+ // Make sure the head branch (defaults to the current one) is on the remote
125
+ // first — a local-only branch can't be the head of a PR otherwise. This is
126
+ // also how "commit on a local branch then PR" publishes that branch.
127
+ const branch = head ?? (await this.#currentBranch(cwd));
128
+ if (base && base === branch) {
129
+ throw new GitCommandError('gh pr create failed', `head and base are the same branch (${branch})`, null);
130
+ }
131
+ await runGit(cwd, ['push', '-u', 'origin', branch]);
132
+ // Pre-flight: a PR needs at least one commit on the head not in the base.
133
+ // Without this gh can appear to "succeed" with nothing to deliver.
134
+ const baseRef = await this.#baseRef(cwd, base);
135
+ if (baseRef) {
136
+ const { stdout } = await runGit(cwd, ['rev-list', '--count', `${baseRef}..${branch}`]);
137
+ if ((Number(stdout.trim()) || 0) === 0) {
138
+ throw new GitCommandError('gh pr create failed', `no commits to compare between ${baseRef} and ${branch} — ` +
139
+ 'commit and push something first', null);
140
+ }
141
+ }
142
+ const args = ['pr', 'create', '--title', title, '--body', body ?? '', '--head', branch];
143
+ if (base)
144
+ args.push('--base', base);
145
+ const { stdout } = await runGh(cwd, args);
146
+ const url = stdout.trim().split('\n').pop()?.trim() ?? '';
147
+ const match = url.match(/\/pull\/(\d+)/);
148
+ // Only report success when gh actually returned a PR URL.
149
+ if (!match || !/^https?:\/\//.test(url)) {
150
+ throw new GitCommandError('gh pr create failed', url || 'the GitHub CLI did not return a pull-request URL', null);
151
+ }
152
+ return { url, number: Number(match[1]) };
153
+ }
154
+ /** The base ref to diff a PR against — `origin/<base>` or the remote HEAD. */
155
+ async #baseRef(cwd, base) {
156
+ if (base)
157
+ return `origin/${base}`;
158
+ try {
159
+ const { stdout } = await runGit(cwd, ['symbolic-ref', 'refs/remotes/origin/HEAD']);
160
+ const ref = stdout.trim().replace(/^refs\/remotes\//, '');
161
+ return ref || undefined;
162
+ }
163
+ catch {
164
+ return undefined;
165
+ }
166
+ }
167
+ async push(cwd, remote, branch) {
168
+ await runGit(cwd, ['push', remote, branch]);
169
+ return { success: true, remote, branch };
170
+ }
171
+ async pull(cwd, remote, branch) {
172
+ const args = ['pull', ...(remote ? [remote] : []), ...(branch ? [branch] : [])];
173
+ await runGit(cwd, args);
174
+ return { success: true };
175
+ }
176
+ async checkout(cwd, branch) {
177
+ await runGit(cwd, ['checkout', branch]);
178
+ }
179
+ /**
180
+ * Switches to {@link target}, keeping each branch's work independent.
181
+ *
182
+ * - `carryChanges: true` → the working-tree changes follow you to the target
183
+ * (`git checkout` moves them; a conflict surfaces as an error).
184
+ * - `carryChanges: false` → the current branch's changes are stashed under a
185
+ * branch-tagged label so they stay put and are NOT lost. On switching back
186
+ * that branch's stash is automatically restored.
187
+ *
188
+ * Either way, any changes previously *left* on the target branch are restored
189
+ * after checkout.
190
+ */
191
+ async switchBranch(cwd, target, carryChanges) {
192
+ const current = await this.#currentBranch(cwd);
193
+ if (target === current)
194
+ return;
195
+ if (!carryChanges) {
196
+ const { stdout } = await runGit(cwd, ['status', '--porcelain']);
197
+ if (stdout.trim()) {
198
+ await runGit(cwd, ['stash', 'push', '--include-untracked', '-m', autoStashLabel(current)]);
199
+ }
200
+ }
201
+ await runGit(cwd, ['checkout', target]);
202
+ await this.#restoreAutoStash(cwd, target);
203
+ }
204
+ /** Pops the auto-stash that belongs to {@link branch}, if one exists. */
205
+ async #restoreAutoStash(cwd, branch) {
206
+ const { stdout } = await runGit(cwd, ['stash', 'list', '--format=%gd %gs']);
207
+ const label = autoStashLabel(branch);
208
+ for (const line of stdout.split('\n')) {
209
+ const ref = line.trim().split(/\s+/)[0];
210
+ if (ref && line.includes(label)) {
211
+ await runGit(cwd, ['stash', 'pop', ref]);
212
+ return;
213
+ }
214
+ }
215
+ }
216
+ async createBranch(cwd, name) {
217
+ await runGit(cwd, ['branch', name]);
218
+ return { branch: name };
219
+ }
220
+ async createWorktree(cwd, branch, path) {
221
+ const exists = await this.#branchExists(cwd, branch);
222
+ const args = exists
223
+ ? ['worktree', 'add', path, branch]
224
+ : ['worktree', 'add', '-b', branch, path];
225
+ await runGit(cwd, args);
226
+ return { path, branch };
227
+ }
228
+ /**
229
+ * Revert [commit] (e.g. `HEAD`, a sha) — creates a NEW commit that undoes it,
230
+ * preserving history (unlike `undoCommit`'s soft reset). `--no-edit` keeps the
231
+ * default revert message; fails (and surfaces) on a conflict.
232
+ */
233
+ async revert(cwd, commit) {
234
+ await runGit(cwd, ['revert', '--no-edit', commit]);
235
+ }
236
+ /**
237
+ * Delete a local branch. With `force: false` this is `git branch -d`, which
238
+ * **refuses** a branch not fully merged (the safe default — the error is
239
+ * surfaced to the phone); `force: true` is `-D` (delete regardless).
240
+ */
241
+ async deleteBranch(cwd, branch, force) {
242
+ await runGit(cwd, ['branch', force ? '-D' : '-d', branch]);
243
+ }
244
+ /**
245
+ * Remove a worktree. With `force: false`, `git worktree remove` **refuses** a
246
+ * worktree with uncommitted/untracked changes (safe default — surfaced);
247
+ * `force: true` adds `--force`. Also prunes stale admin entries afterward.
248
+ *
249
+ * `git` refuses to remove the worktree you are *standing in*, so we run the
250
+ * removal from the repo's MAIN worktree (resolved via `worktree list`),
251
+ * letting the phone remove the very worktree backing the active thread.
252
+ */
253
+ async removeWorktree(cwd, path, force) {
254
+ const runFrom = await this.#mainWorktree(cwd);
255
+ const args = force ? ['worktree', 'remove', '--force', path] : ['worktree', 'remove', path];
256
+ await runGit(runFrom, args);
257
+ // Best-effort: drop any now-stale worktree admin files.
258
+ await runGit(runFrom, ['worktree', 'prune']).catch(() => undefined);
259
+ }
260
+ /** The repo's primary worktree path (the first `worktree list` entry), or [cwd]. */
261
+ async #mainWorktree(cwd) {
262
+ try {
263
+ const { stdout } = await runGit(cwd, ['worktree', 'list', '--porcelain']);
264
+ const first = stdout.split('\n').find((line) => line.startsWith('worktree '));
265
+ if (first) {
266
+ const main = first.slice('worktree '.length).trim();
267
+ if (main)
268
+ return main;
269
+ }
270
+ }
271
+ catch {
272
+ // not a git repo / detached — fall back to the given cwd
273
+ }
274
+ return cwd;
275
+ }
276
+ async #currentBranch(cwd) {
277
+ // `branch --show-current` works on an unborn branch (no commits yet) and
278
+ // returns '' on a detached HEAD.
279
+ try {
280
+ const { stdout } = await runGit(cwd, ['branch', '--show-current']);
281
+ const branch = stdout.trim();
282
+ if (branch)
283
+ return branch;
284
+ }
285
+ catch {
286
+ // fall through
287
+ }
288
+ return 'HEAD';
289
+ }
290
+ async #aheadBehind(cwd) {
291
+ try {
292
+ const { stdout } = await runGit(cwd, [
293
+ 'rev-list',
294
+ '--left-right',
295
+ '--count',
296
+ '@{upstream}...HEAD',
297
+ ]);
298
+ const [behind, ahead] = stdout.trim().split(/\s+/).map(Number);
299
+ return { ahead: ahead || 0, behind: behind || 0 };
300
+ }
301
+ catch {
302
+ return { ahead: 0, behind: 0 };
303
+ }
304
+ }
305
+ async #changedFiles(cwd) {
306
+ const [{ stdout }, counts] = await Promise.all([
307
+ runGit(cwd, ['status', '--porcelain']),
308
+ this.#perFileCounts(cwd),
309
+ ]);
310
+ const files = [];
311
+ for (const line of stdout.split('\n')) {
312
+ if (line.length < 4)
313
+ continue;
314
+ const xy = line.slice(0, 2);
315
+ let path = line.slice(3);
316
+ const arrow = path.indexOf(' -> ');
317
+ if (arrow !== -1)
318
+ path = path.slice(arrow + 4);
319
+ const count = counts.get(path);
320
+ files.push({
321
+ path,
322
+ status: mapStatus(xy),
323
+ additions: count?.additions ?? 0,
324
+ deletions: count?.deletions ?? 0,
325
+ });
326
+ }
327
+ return files;
328
+ }
329
+ /** Per-file +/- counts via `git diff --numstat` (tracked changes only). */
330
+ async #perFileCounts(cwd) {
331
+ const ref = (await this.#hasHead(cwd)) ? ['HEAD'] : [];
332
+ const { stdout } = await runGit(cwd, ['diff', '--numstat', ...ref]);
333
+ const counts = new Map();
334
+ for (const line of stdout.split('\n')) {
335
+ const [add, del, path] = line.trim().split('\t');
336
+ if (!path)
337
+ continue;
338
+ counts.set(path, {
339
+ additions: add === '-' ? 0 : Number(add) || 0,
340
+ deletions: del === '-' ? 0 : Number(del) || 0,
341
+ });
342
+ }
343
+ return counts;
344
+ }
345
+ #sumNumstat(numstat) {
346
+ let additions = 0;
347
+ let deletions = 0;
348
+ for (const line of numstat.split('\n')) {
349
+ const [add, del] = line.trim().split('\t');
350
+ if (add && add !== '-')
351
+ additions += Number(add) || 0;
352
+ if (del && del !== '-')
353
+ deletions += Number(del) || 0;
354
+ }
355
+ return { additions, deletions };
356
+ }
357
+ async #upstream(cwd) {
358
+ try {
359
+ const { stdout } = await runGit(cwd, [
360
+ 'rev-parse',
361
+ '--abbrev-ref',
362
+ '--symbolic-full-name',
363
+ '@{upstream}',
364
+ ]);
365
+ const ref = stdout.trim();
366
+ return ref || undefined;
367
+ }
368
+ catch {
369
+ return undefined;
370
+ }
371
+ }
372
+ async #isUntracked(cwd, path) {
373
+ const { stdout } = await runGit(cwd, ['status', '--porcelain', '--', path]);
374
+ return stdout.startsWith('??');
375
+ }
376
+ /** Builds an all-additions unified diff for an untracked file's contents. */
377
+ async #untrackedDiff(cwd, path) {
378
+ let content;
379
+ try {
380
+ content = await readFile(join(cwd, path), 'utf8');
381
+ }
382
+ catch {
383
+ return { diff: '', additions: 0 };
384
+ }
385
+ const lines = content.split('\n');
386
+ if (lines.length > 0 && lines[lines.length - 1] === '')
387
+ lines.pop();
388
+ const header = `diff --git a/${path} b/${path}\n` +
389
+ `new file mode 100644\n--- /dev/null\n+++ b/${path}\n` +
390
+ `@@ -0,0 +1,${lines.length} @@\n`;
391
+ const body = lines.map((l) => `+${l}`).join('\n');
392
+ return { diff: header + body, additions: lines.length };
393
+ }
394
+ async #hasHead(cwd) {
395
+ try {
396
+ await runGit(cwd, ['rev-parse', '--verify', '--quiet', 'HEAD']);
397
+ return true;
398
+ }
399
+ catch {
400
+ return false;
401
+ }
402
+ }
403
+ async #branchExists(cwd, branch) {
404
+ try {
405
+ await runGit(cwd, ['rev-parse', '--verify', '--quiet', `refs/heads/${branch}`]);
406
+ return true;
407
+ }
408
+ catch {
409
+ return false;
410
+ }
411
+ }
412
+ }
413
+ /** Label used to tag a branch's auto-stash so it can be restored on return. */
414
+ function autoStashLabel(branch) {
415
+ return `uxnan-auto:${branch}`;
416
+ }
417
+ function mapStatus(xy) {
418
+ if (xy === '??')
419
+ return 'untracked';
420
+ if (xy.includes('U') || xy === 'AA' || xy === 'DD')
421
+ return 'conflicted';
422
+ const code = xy.trim()[0];
423
+ switch (code) {
424
+ case 'A':
425
+ return 'added';
426
+ case 'D':
427
+ return 'deleted';
428
+ case 'R':
429
+ return 'renamed';
430
+ case 'M':
431
+ default:
432
+ return 'modified';
433
+ }
434
+ }
435
+ //# sourceMappingURL=git-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"git-service.js","sourceRoot":"","sources":["../../../src/git/git-service.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Routes JSON-RPC requests to registered handlers.
3
+ *
4
+ * - Unknown methods → -32601 (method not found).
5
+ * - Malformed envelopes → -32600 (invalid request).
6
+ * - Handlers may throw {@link RpcError} (mapped to its code) or any error
7
+ * (mapped to -32603 internal error).
8
+ *
9
+ * Source: architecture/02a-system-architecture.md §5.8.2 (handler-router).
10
+ */
11
+ import { type JsonRpcRequest, type JsonRpcResponse } from '@uxnan/shared';
12
+ import type { BridgeContext } from './bridge-context.js';
13
+ /**
14
+ * Identity of the phone session a request arrived on (the secure transport knows
15
+ * it after the handshake). Threaded to handlers so per-phone operations (e.g.
16
+ * `notifications/*`) target the right session when several phones are concurrent.
17
+ */
18
+ export interface RequestSession {
19
+ /** Relay session id (the push registration key). */
20
+ sessionId: string;
21
+ /** Trusted-device id of the phone. */
22
+ deviceId: string;
23
+ }
24
+ export type RpcHandler = (params: unknown, ctx: BridgeContext, session?: RequestSession) => Promise<unknown> | unknown;
25
+ export declare class HandlerRouter {
26
+ #private;
27
+ constructor(ctx: BridgeContext);
28
+ register(method: string, handler: RpcHandler): void;
29
+ has(method: string): boolean;
30
+ /** Dispatch an already-parsed JSON-RPC request. Never throws. */
31
+ dispatch(request: JsonRpcRequest, session?: RequestSession): Promise<JsonRpcResponse>;
32
+ /** Validate a raw (untrusted) message envelope, then dispatch it. */
33
+ dispatchRaw(raw: unknown, session?: RequestSession): Promise<JsonRpcResponse>;
34
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Routes JSON-RPC requests to registered handlers.
3
+ *
4
+ * - Unknown methods → -32601 (method not found).
5
+ * - Malformed envelopes → -32600 (invalid request).
6
+ * - Handlers may throw {@link RpcError} (mapped to its code) or any error
7
+ * (mapped to -32603 internal error).
8
+ *
9
+ * Source: architecture/02a-system-architecture.md §5.8.2 (handler-router).
10
+ */
11
+ import { JsonRpcErrorCode, RpcError, isKnownMethod, makeErrorResponse, makeResponse, validateJsonRpcRequest, } from '@uxnan/shared';
12
+ export class HandlerRouter {
13
+ #handlers = new Map();
14
+ #ctx;
15
+ constructor(ctx) {
16
+ this.#ctx = ctx;
17
+ }
18
+ register(method, handler) {
19
+ this.#handlers.set(method, handler);
20
+ }
21
+ has(method) {
22
+ return this.#handlers.has(method);
23
+ }
24
+ /** Dispatch an already-parsed JSON-RPC request. Never throws. */
25
+ async dispatch(request, session) {
26
+ const { id, method } = request;
27
+ if (!isKnownMethod(method) || !this.#handlers.has(method)) {
28
+ return makeErrorResponse(id, RpcError.methodNotFound(method).toErrorObject());
29
+ }
30
+ const handler = this.#handlers.get(method);
31
+ try {
32
+ const result = await handler(request.params, this.#ctx, session);
33
+ return makeResponse(id, result ?? null);
34
+ }
35
+ catch (err) {
36
+ return makeErrorResponse(id, this.#toErrorObject(err));
37
+ }
38
+ }
39
+ /** Validate a raw (untrusted) message envelope, then dispatch it. */
40
+ async dispatchRaw(raw, session) {
41
+ const validation = validateJsonRpcRequest(raw);
42
+ if (!validation.valid) {
43
+ const id = this.#extractId(raw);
44
+ return makeErrorResponse(id, {
45
+ code: JsonRpcErrorCode.InvalidRequest,
46
+ message: 'Invalid request',
47
+ data: validation.errors,
48
+ });
49
+ }
50
+ return this.dispatch(validation.data, session);
51
+ }
52
+ #toErrorObject(err) {
53
+ if (err instanceof RpcError)
54
+ return err.toErrorObject();
55
+ const message = err instanceof Error ? err.message : 'Internal error';
56
+ return { code: JsonRpcErrorCode.InternalError, message };
57
+ }
58
+ #extractId(raw) {
59
+ if (raw && typeof raw === 'object' && 'id' in raw) {
60
+ const id = raw.id;
61
+ if (typeof id === 'string' || typeof id === 'number')
62
+ return id;
63
+ }
64
+ return null;
65
+ }
66
+ }
67
+ //# sourceMappingURL=handler-router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handler-router.js","sourceRoot":"","sources":["../../src/handler-router.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { HandlerRouter } from '../handler-router.js';
2
+ /** Auth methods whose CLI login flow is still deferred. */
3
+ export declare const ACCOUNT_STUB_METHODS: readonly ["auth/login", "auth/logout"];
4
+ export declare function registerAccountHandlers(router: HandlerRouter): void;
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Account/auth JSON-RPC handlers.
3
+ *
4
+ * `auth/status` returns a SANITIZED per-agent snapshot (never tokens — see
5
+ * `account-status.ts`). `auth/login`/`auth/logout` remain stubs: driving a CLI's
6
+ * interactive login flow is a follow-up (FOR-DEV). NEVER expose tokens (§5.8.9).
7
+ */
8
+ import { RpcError } from '@uxnan/shared';
9
+ import { getAuthStatus } from '../account-status.js';
10
+ import { requireString } from './params.js';
11
+ import { registerStubs } from './not-implemented.js';
12
+ /** Auth methods whose CLI login flow is still deferred. */
13
+ export const ACCOUNT_STUB_METHODS = ['auth/login', 'auth/logout'];
14
+ export function registerAccountHandlers(router) {
15
+ router.register('auth/status', (p, ctx) => {
16
+ const agentId = requireString(p, 'agentId');
17
+ if (!ctx.agentManager.hasAdapter(agentId)) {
18
+ throw RpcError.invalidParams(`unknown agent: ${agentId}`);
19
+ }
20
+ return getAuthStatus(agentId, {
21
+ isAvailable: (id) => ctx.agentManager.isAvailable(id),
22
+ platform: process.platform,
23
+ });
24
+ });
25
+ registerStubs(router, ACCOUNT_STUB_METHODS);
26
+ }
27
+ //# sourceMappingURL=account-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"account-handler.js","sourceRoot":"","sources":["../../../src/handlers/account-handler.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,QAAQ,EAAgB,MAAM,eAAe,CAAC;AAGvD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,2DAA2D;AAC3D,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,YAAY,EAAE,aAAa,CAAU,CAAC;AAE3E,MAAM,UAAU,uBAAuB,CAAC,MAAqB;IAC3D,MAAM,CAAC,QAAQ,CAAC,aAAa,EAAE,CAAC,CAAC,EAAE,GAAkB,EAAE,EAAE;QACvD,MAAM,OAAO,GAAG,aAAa,CAAC,CAAC,EAAE,SAAS,CAAY,CAAC;QACvD,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAC1C,MAAM,QAAQ,CAAC,aAAa,CAAC,kBAAkB,OAAO,EAAE,CAAC,CAAC;QAC5D,CAAC;QACD,OAAO,aAAa,CAAC,OAAO,EAAE;YAC5B,WAAW,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,GAAG,CAAC,YAAY,CAAC,WAAW,CAAC,EAAE,CAAC;YACrD,QAAQ,EAAE,OAAO,CAAC,QAAQ;SAC3B,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,aAAa,CAAC,MAAM,EAAE,oBAAoB,CAAC,CAAC;AAC9C,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { HandlerRouter } from '../handler-router.js';
2
+ export declare function registerAgentHandlers(router: HandlerRouter): void;
@@ -0,0 +1,8 @@
1
+ import { requireString } from './params.js';
2
+ export function registerAgentHandlers(router) {
3
+ router.register('agent/list', (_p, ctx) => ({ agents: ctx.agentManager.listAgents() }));
4
+ router.register('agent/models', async (p, ctx) => ({
5
+ models: await ctx.agentManager.getModels(requireString(p, 'agentId')),
6
+ }));
7
+ }
8
+ //# sourceMappingURL=agent-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-handler.js","sourceRoot":"","sources":["../../../src/handlers/agent-handler.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,MAAM,UAAU,qBAAqB,CAAC,MAAqB;IACzD,MAAM,CAAC,QAAQ,CACb,YAAY,EACZ,CAAC,EAAE,EAAE,GAAkB,EAAmB,EAAE,CAAC,CAAC,EAAE,MAAM,EAAE,GAAG,CAAC,YAAY,CAAC,UAAU,EAAE,EAAE,CAAC,CACzF,CAAC;IACF,MAAM,CAAC,QAAQ,CACb,cAAc,EACd,KAAK,EAAE,CAAC,EAAE,GAAkB,EAA8B,EAAE,CAAC,CAAC;QAC5D,MAAM,EAAE,MAAM,GAAG,CAAC,YAAY,CAAC,SAAS,CAAC,aAAa,CAAC,CAAC,EAAE,SAAS,CAAY,CAAC;KACjF,CAAC,CACH,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { HandlerRouter } from '../handler-router.js';
2
+ export declare function registerBridgeControlHandlers(router: HandlerRouter): void;