baxian 0.0.1 → 0.2.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 (291) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +19 -1
  3. package/dist/agent/bootstrap-poller.d.ts +34 -0
  4. package/dist/agent/bootstrap-poller.d.ts.map +1 -0
  5. package/dist/agent/bootstrap-poller.js +93 -0
  6. package/dist/agent/bootstrap-poller.js.map +1 -0
  7. package/dist/agent/bootstrap.d.ts +39 -0
  8. package/dist/agent/bootstrap.d.ts.map +1 -0
  9. package/dist/agent/bootstrap.js +214 -0
  10. package/dist/agent/bootstrap.js.map +1 -0
  11. package/dist/agent/index.d.ts +8 -0
  12. package/dist/agent/index.d.ts.map +1 -0
  13. package/dist/agent/index.js +8 -0
  14. package/dist/agent/index.js.map +1 -0
  15. package/dist/agent/manager.d.ts +280 -0
  16. package/dist/agent/manager.d.ts.map +1 -0
  17. package/dist/agent/manager.js +3666 -0
  18. package/dist/agent/manager.js.map +1 -0
  19. package/dist/agent/marker-protocol.d.ts +12 -0
  20. package/dist/agent/marker-protocol.d.ts.map +1 -0
  21. package/dist/agent/marker-protocol.js +52 -0
  22. package/dist/agent/marker-protocol.js.map +1 -0
  23. package/dist/agent/pane-streamer-manager.d.ts +24 -0
  24. package/dist/agent/pane-streamer-manager.d.ts.map +1 -0
  25. package/dist/agent/pane-streamer-manager.js +107 -0
  26. package/dist/agent/pane-streamer-manager.js.map +1 -0
  27. package/dist/agent/pane-streamer.d.ts +97 -0
  28. package/dist/agent/pane-streamer.d.ts.map +1 -0
  29. package/dist/agent/pane-streamer.js +382 -0
  30. package/dist/agent/pane-streamer.js.map +1 -0
  31. package/dist/agent/post-approve-marker-watcher.d.ts +29 -0
  32. package/dist/agent/post-approve-marker-watcher.d.ts.map +1 -0
  33. package/dist/agent/post-approve-marker-watcher.js +160 -0
  34. package/dist/agent/post-approve-marker-watcher.js.map +1 -0
  35. package/dist/agent/preflight.d.ts +9 -0
  36. package/dist/agent/preflight.d.ts.map +1 -0
  37. package/dist/agent/preflight.js +164 -0
  38. package/dist/agent/preflight.js.map +1 -0
  39. package/dist/agent/prompt.d.ts +44 -0
  40. package/dist/agent/prompt.d.ts.map +1 -0
  41. package/dist/agent/prompt.js +252 -0
  42. package/dist/agent/prompt.js.map +1 -0
  43. package/dist/agent/repo-store.d.ts +27 -0
  44. package/dist/agent/repo-store.d.ts.map +1 -0
  45. package/dist/agent/repo-store.js +152 -0
  46. package/dist/agent/repo-store.js.map +1 -0
  47. package/dist/agent/runner.d.ts +46 -0
  48. package/dist/agent/runner.d.ts.map +1 -0
  49. package/dist/agent/runner.js +241 -0
  50. package/dist/agent/runner.js.map +1 -0
  51. package/dist/agent/spec-review-marker-watcher.d.ts +33 -0
  52. package/dist/agent/spec-review-marker-watcher.d.ts.map +1 -0
  53. package/dist/agent/spec-review-marker-watcher.js +180 -0
  54. package/dist/agent/spec-review-marker-watcher.js.map +1 -0
  55. package/dist/agent/tmux-probe-poller.d.ts +78 -0
  56. package/dist/agent/tmux-probe-poller.d.ts.map +1 -0
  57. package/dist/agent/tmux-probe-poller.js +418 -0
  58. package/dist/agent/tmux-probe-poller.js.map +1 -0
  59. package/dist/agent/tmux.d.ts +78 -0
  60. package/dist/agent/tmux.d.ts.map +1 -0
  61. package/dist/agent/tmux.js +395 -0
  62. package/dist/agent/tmux.js.map +1 -0
  63. package/dist/agent/worktree.d.ts +10 -0
  64. package/dist/agent/worktree.d.ts.map +1 -0
  65. package/dist/agent/worktree.js +41 -0
  66. package/dist/agent/worktree.js.map +1 -0
  67. package/dist/api/agents.d.ts +3 -0
  68. package/dist/api/agents.d.ts.map +1 -0
  69. package/dist/api/agents.js +29 -0
  70. package/dist/api/agents.js.map +1 -0
  71. package/dist/api/config.d.ts +5 -0
  72. package/dist/api/config.d.ts.map +1 -0
  73. package/dist/api/config.js +114 -0
  74. package/dist/api/config.js.map +1 -0
  75. package/dist/api/events.d.ts +3 -0
  76. package/dist/api/events.d.ts.map +1 -0
  77. package/dist/api/events.js +11 -0
  78. package/dist/api/events.js.map +1 -0
  79. package/dist/api/pollers.d.ts +3 -0
  80. package/dist/api/pollers.d.ts.map +1 -0
  81. package/dist/api/pollers.js +4 -0
  82. package/dist/api/pollers.js.map +1 -0
  83. package/dist/api/probe.d.ts +9 -0
  84. package/dist/api/probe.d.ts.map +1 -0
  85. package/dist/api/probe.js +87 -0
  86. package/dist/api/probe.js.map +1 -0
  87. package/dist/api/projects.d.ts +3 -0
  88. package/dist/api/projects.d.ts.map +1 -0
  89. package/dist/api/projects.js +602 -0
  90. package/dist/api/projects.js.map +1 -0
  91. package/dist/api/restart.d.ts +3 -0
  92. package/dist/api/restart.d.ts.map +1 -0
  93. package/dist/api/restart.js +20 -0
  94. package/dist/api/restart.js.map +1 -0
  95. package/dist/api/tasks.d.ts +3 -0
  96. package/dist/api/tasks.d.ts.map +1 -0
  97. package/dist/api/tasks.js +136 -0
  98. package/dist/api/tasks.js.map +1 -0
  99. package/dist/app.d.ts +51 -0
  100. package/dist/app.d.ts.map +1 -0
  101. package/dist/app.js +169 -0
  102. package/dist/app.js.map +1 -0
  103. package/dist/cli.d.ts +20 -0
  104. package/dist/cli.d.ts.map +1 -0
  105. package/dist/cli.js +319 -0
  106. package/dist/cli.js.map +1 -0
  107. package/dist/config/backup.d.ts +3 -0
  108. package/dist/config/backup.d.ts.map +1 -0
  109. package/dist/config/backup.js +44 -0
  110. package/dist/config/backup.js.map +1 -0
  111. package/dist/config/index.d.ts +5 -0
  112. package/dist/config/index.d.ts.map +1 -0
  113. package/dist/config/index.js +5 -0
  114. package/dist/config/index.js.map +1 -0
  115. package/dist/config/loader.d.ts +42 -0
  116. package/dist/config/loader.d.ts.map +1 -0
  117. package/dist/config/loader.js +197 -0
  118. package/dist/config/loader.js.map +1 -0
  119. package/dist/config/mutex.d.ts +2 -0
  120. package/dist/config/mutex.d.ts.map +1 -0
  121. package/dist/config/mutex.js +7 -0
  122. package/dist/config/mutex.js.map +1 -0
  123. package/dist/config/normalizer.d.ts +2 -0
  124. package/dist/config/normalizer.d.ts.map +1 -0
  125. package/dist/config/normalizer.js +42 -0
  126. package/dist/config/normalizer.js.map +1 -0
  127. package/dist/config/validator.d.ts +7 -0
  128. package/dist/config/validator.d.ts.map +1 -0
  129. package/dist/config/validator.js +278 -0
  130. package/dist/config/validator.js.map +1 -0
  131. package/dist/errors.d.ts +5 -0
  132. package/dist/errors.d.ts.map +1 -0
  133. package/dist/errors.js +9 -0
  134. package/dist/errors.js.map +1 -0
  135. package/dist/event/broker.d.ts +11 -0
  136. package/dist/event/broker.d.ts.map +1 -0
  137. package/dist/event/broker.js +47 -0
  138. package/dist/event/broker.js.map +1 -0
  139. package/dist/event/bus.d.ts +12 -0
  140. package/dist/event/bus.d.ts.map +1 -0
  141. package/dist/event/bus.js +35 -0
  142. package/dist/event/bus.js.map +1 -0
  143. package/dist/event/handlers.d.ts +6 -0
  144. package/dist/event/handlers.d.ts.map +1 -0
  145. package/dist/event/handlers.js +1121 -0
  146. package/dist/event/handlers.js.map +1 -0
  147. package/dist/event/index.d.ts +4 -0
  148. package/dist/event/index.d.ts.map +1 -0
  149. package/dist/event/index.js +4 -0
  150. package/dist/event/index.js.map +1 -0
  151. package/dist/event/log.d.ts +9 -0
  152. package/dist/event/log.d.ts.map +1 -0
  153. package/dist/event/log.js +43 -0
  154. package/dist/event/log.js.map +1 -0
  155. package/dist/event/publish.d.ts +37 -0
  156. package/dist/event/publish.d.ts.map +1 -0
  157. package/dist/event/publish.js +197 -0
  158. package/dist/event/publish.js.map +1 -0
  159. package/dist/event/ws.d.ts +3 -0
  160. package/dist/event/ws.d.ts.map +1 -0
  161. package/dist/event/ws.js +169 -0
  162. package/dist/event/ws.js.map +1 -0
  163. package/dist/github/index.d.ts +4 -0
  164. package/dist/github/index.d.ts.map +1 -0
  165. package/dist/github/index.js +3 -0
  166. package/dist/github/index.js.map +1 -0
  167. package/dist/github/mapper.d.ts +51 -0
  168. package/dist/github/mapper.d.ts.map +1 -0
  169. package/dist/github/mapper.js +191 -0
  170. package/dist/github/mapper.js.map +1 -0
  171. package/dist/github/poller.d.ts +64 -0
  172. package/dist/github/poller.d.ts.map +1 -0
  173. package/dist/github/poller.js +513 -0
  174. package/dist/github/poller.js.map +1 -0
  175. package/dist/github/resolver.d.ts +8 -0
  176. package/dist/github/resolver.d.ts.map +1 -0
  177. package/dist/github/resolver.js +24 -0
  178. package/dist/github/resolver.js.map +1 -0
  179. package/dist/index.d.ts +11 -0
  180. package/dist/index.d.ts.map +1 -0
  181. package/dist/index.js +310 -0
  182. package/dist/index.js.map +1 -0
  183. package/dist/lifecycle/restart-sentinel.d.ts +18 -0
  184. package/dist/lifecycle/restart-sentinel.d.ts.map +1 -0
  185. package/dist/lifecycle/restart-sentinel.js +61 -0
  186. package/dist/lifecycle/restart-sentinel.js.map +1 -0
  187. package/dist/lifecycle/restart.d.ts +21 -0
  188. package/dist/lifecycle/restart.d.ts.map +1 -0
  189. package/dist/lifecycle/restart.js +57 -0
  190. package/dist/lifecycle/restart.js.map +1 -0
  191. package/dist/shared/constants.d.ts +18 -0
  192. package/dist/shared/constants.d.ts.map +1 -0
  193. package/dist/shared/constants.js +60 -0
  194. package/dist/shared/constants.js.map +1 -0
  195. package/dist/shared/index.d.ts +3 -0
  196. package/dist/shared/index.d.ts.map +1 -0
  197. package/dist/shared/index.js +3 -0
  198. package/dist/shared/index.js.map +1 -0
  199. package/dist/shared/types.d.ts +263 -0
  200. package/dist/shared/types.d.ts.map +1 -0
  201. package/dist/shared/types.js +2 -0
  202. package/dist/shared/types.js.map +1 -0
  203. package/dist/skill/index.d.ts +2 -0
  204. package/dist/skill/index.d.ts.map +1 -0
  205. package/dist/skill/index.js +2 -0
  206. package/dist/skill/index.js.map +1 -0
  207. package/dist/skill/registry.d.ts +30 -0
  208. package/dist/skill/registry.d.ts.map +1 -0
  209. package/dist/skill/registry.js +174 -0
  210. package/dist/skill/registry.js.map +1 -0
  211. package/dist/skills/UPSTREAM.md +38 -0
  212. package/dist/skills/baxian-rules/SKILL.md +68 -0
  213. package/dist/skills/merge-sync/SKILL.md +42 -0
  214. package/dist/skills/pr-feedback/SKILL.md +117 -0
  215. package/dist/skills/pr-recheck/SKILL.md +52 -0
  216. package/dist/skills/pr-review/SKILL.md +60 -0
  217. package/dist/skills/spells/SKILL.md +41 -0
  218. package/dist/skills/task-check/SKILL.md +26 -0
  219. package/dist/state/agent-store.d.ts +21 -0
  220. package/dist/state/agent-store.d.ts.map +1 -0
  221. package/dist/state/agent-store.js +145 -0
  222. package/dist/state/agent-store.js.map +1 -0
  223. package/dist/state/error-record-store.d.ts +40 -0
  224. package/dist/state/error-record-store.d.ts.map +1 -0
  225. package/dist/state/error-record-store.js +203 -0
  226. package/dist/state/error-record-store.js.map +1 -0
  227. package/dist/state/index.d.ts +5 -0
  228. package/dist/state/index.d.ts.map +1 -0
  229. package/dist/state/index.js +5 -0
  230. package/dist/state/index.js.map +1 -0
  231. package/dist/state/init.d.ts +2 -0
  232. package/dist/state/init.d.ts.map +1 -0
  233. package/dist/state/init.js +13 -0
  234. package/dist/state/init.js.map +1 -0
  235. package/dist/state/lock.d.ts +9 -0
  236. package/dist/state/lock.d.ts.map +1 -0
  237. package/dist/state/lock.js +36 -0
  238. package/dist/state/lock.js.map +1 -0
  239. package/dist/state/post-approve-store.d.ts +23 -0
  240. package/dist/state/post-approve-store.d.ts.map +1 -0
  241. package/dist/state/post-approve-store.js +79 -0
  242. package/dist/state/post-approve-store.js.map +1 -0
  243. package/dist/state/process-lock.d.ts +24 -0
  244. package/dist/state/process-lock.d.ts.map +1 -0
  245. package/dist/state/process-lock.js +175 -0
  246. package/dist/state/process-lock.js.map +1 -0
  247. package/dist/state/snapshot.d.ts +38 -0
  248. package/dist/state/snapshot.d.ts.map +1 -0
  249. package/dist/state/snapshot.js +134 -0
  250. package/dist/state/snapshot.js.map +1 -0
  251. package/dist/state/task-store.d.ts +25 -0
  252. package/dist/state/task-store.d.ts.map +1 -0
  253. package/dist/state/task-store.js +167 -0
  254. package/dist/state/task-store.js.map +1 -0
  255. package/dist/terminal/attach.d.ts +7 -0
  256. package/dist/terminal/attach.d.ts.map +1 -0
  257. package/dist/terminal/attach.js +26 -0
  258. package/dist/terminal/attach.js.map +1 -0
  259. package/dist/terminal/index.d.ts +3 -0
  260. package/dist/terminal/index.d.ts.map +1 -0
  261. package/dist/terminal/index.js +3 -0
  262. package/dist/terminal/index.js.map +1 -0
  263. package/dist/terminal/key-sanitizer.d.ts +2 -0
  264. package/dist/terminal/key-sanitizer.d.ts.map +1 -0
  265. package/dist/terminal/key-sanitizer.js +9 -0
  266. package/dist/terminal/key-sanitizer.js.map +1 -0
  267. package/dist/terminal/stream-ws.d.ts +3 -0
  268. package/dist/terminal/stream-ws.d.ts.map +1 -0
  269. package/dist/terminal/stream-ws.js +426 -0
  270. package/dist/terminal/stream-ws.js.map +1 -0
  271. package/dist/terminal/ws-auth.d.ts +5 -0
  272. package/dist/terminal/ws-auth.d.ts.map +1 -0
  273. package/dist/terminal/ws-auth.js +45 -0
  274. package/dist/terminal/ws-auth.js.map +1 -0
  275. package/dist/timing/debounced-task.d.ts +9 -0
  276. package/dist/timing/debounced-task.d.ts.map +1 -0
  277. package/dist/timing/debounced-task.js +23 -0
  278. package/dist/timing/debounced-task.js.map +1 -0
  279. package/dist/timing/periodic-task-runner.d.ts +21 -0
  280. package/dist/timing/periodic-task-runner.d.ts.map +1 -0
  281. package/dist/timing/periodic-task-runner.js +61 -0
  282. package/dist/timing/periodic-task-runner.js.map +1 -0
  283. package/dist/web/assets/index-53CBbz4w.js +4 -0
  284. package/dist/web/assets/index-B9D6BV08.css +1 -0
  285. package/dist/web/assets/react-BG4Iuztk.js +40 -0
  286. package/dist/web/assets/router-B_Nv0oRz.js +12 -0
  287. package/dist/web/assets/xterm-CFbL2ovg.css +32 -0
  288. package/dist/web/assets/xterm-D5X2JljJ.js +9 -0
  289. package/dist/web/index.html +17 -0
  290. package/package.json +44 -5
  291. package/index.js +0 -1
@@ -0,0 +1,152 @@
1
+ import { homedir } from 'node:os';
2
+ import { shellQuote } from './runner.js';
3
+ export function createRepoStoreCache() {
4
+ return { homes: new Map(), mutex: new Map(), lastFetchAt: new Map() };
5
+ }
6
+ const GITHUB_HTTPS_RE = /^https?:\/\/github\.com\/([^/]+\/[^/]+?)(?:\.git)?\/?$/;
7
+ const GITHUB_SSH_SCP_RE = /^git@github\.com:([^/]+\/[^/]+?)(?:\.git)?\/?$/;
8
+ const GITHUB_SSH_URL_RE = /^ssh:\/\/git@github\.com\/([^/]+\/[^/]+?)(?:\.git)?\/?$/;
9
+ export function normalizeRepoUrl(url) {
10
+ if (!url)
11
+ return null;
12
+ const trimmed = url.trim();
13
+ return (trimmed.match(GITHUB_HTTPS_RE)?.[1]
14
+ ?? trimmed.match(GITHUB_SSH_SCP_RE)?.[1]
15
+ ?? trimmed.match(GITHUB_SSH_URL_RE)?.[1]
16
+ ?? null);
17
+ }
18
+ const FETCH_THROTTLE_MS = 30_000;
19
+ export class RepoStore {
20
+ runner;
21
+ repoSlug;
22
+ mode;
23
+ host;
24
+ cache;
25
+ constructor(runner, repoSlug, mode, host, cache) {
26
+ this.runner = runner;
27
+ this.repoSlug = repoSlug;
28
+ this.mode = mode;
29
+ this.host = host;
30
+ this.cache = cache;
31
+ }
32
+ async ensure() {
33
+ const absRepoPath = await this.resolveAbsPath();
34
+ const cacheKey = `${this.hostKey()}:${absRepoPath}`;
35
+ return this.runUnderMutex(cacheKey, async () => {
36
+ await this.cloneIfNeeded(absRepoPath);
37
+ await this.fetchIfStale(cacheKey, absRepoPath);
38
+ return absRepoPath;
39
+ });
40
+ }
41
+ async refresh(absRepoPath) {
42
+ const cacheKey = `${this.hostKey()}:${absRepoPath}`;
43
+ await this.runUnderMutex(cacheKey, () => this.fetchIfStale(cacheKey, absRepoPath));
44
+ }
45
+ async readFileFromBranch(absRepoPath, branch, filePath) {
46
+ // FETCH_HEAD 共享:并发 readFileFromBranch 会互相覆盖 → 用 runUnderMutex 串行化。
47
+ const cacheKey = `${this.hostKey()}:${absRepoPath}`;
48
+ return this.runUnderMutex(cacheKey, async () => {
49
+ const fetchCmd = `cd ${shellQuote(absRepoPath)} && git fetch origin ${shellQuote(branch)}`;
50
+ const fetchResult = await this.runner.exec(fetchCmd);
51
+ if (fetchResult.exitCode !== 0) {
52
+ throw new Error(`git fetch origin ${branch} failed at ${absRepoPath}: ${fetchResult.stderr || fetchResult.stdout}`);
53
+ }
54
+ // FETCH_HEAD is the only ref guaranteed updated by `git fetch origin <branch>`.
55
+ const showCmd = `cd ${shellQuote(absRepoPath)} && git show FETCH_HEAD:${shellQuote(filePath)}`;
56
+ const showResult = await this.runner.exec(showCmd);
57
+ if (showResult.exitCode === 0)
58
+ return showResult.stdout;
59
+ const stderr = (showResult.stderr || '').toLowerCase();
60
+ if (stderr.includes('does not exist')
61
+ || stderr.includes('exists on disk, but not in')
62
+ || stderr.includes("path '")
63
+ || stderr.includes('fatal: path')
64
+ || stderr.includes('unknown revision')) {
65
+ return null;
66
+ }
67
+ throw new Error(`git show FETCH_HEAD:${filePath} failed at ${absRepoPath}: ${showResult.stderr || showResult.stdout}`);
68
+ });
69
+ }
70
+ hostKey() {
71
+ if (this.mode === 'local')
72
+ return 'local';
73
+ if (!this.host)
74
+ throw new Error('Remote mode requires host config');
75
+ // Prefix remote keys so an SSH alias named "local" cannot collide with local mode.
76
+ return this.host.user
77
+ ? `remote:${this.host.user}@${this.host.hostname}`
78
+ : `remote:${this.host.hostname}`;
79
+ }
80
+ async resolveAbsPath() {
81
+ const home = await this.resolveHome();
82
+ // GitHub slugs are case-insensitive; case flips must not fork the store.
83
+ return `${home}/.baxian/repos/${this.repoSlug.toLowerCase()}`;
84
+ }
85
+ async resolveHome() {
86
+ const key = this.hostKey();
87
+ if (this.mode === 'local') {
88
+ const cached = this.cache.homes.get(key);
89
+ if (cached)
90
+ return cached;
91
+ const home = homedir();
92
+ this.cache.homes.set(key, home);
93
+ return home;
94
+ }
95
+ const cached = this.cache.homes.get(key);
96
+ if (cached)
97
+ return cached;
98
+ const result = await this.runner.exec('printf %s "$HOME"');
99
+ if (result.exitCode !== 0 || !result.stdout) {
100
+ throw new Error(`Failed to resolve $HOME on ${key}: ${result.stderr}`);
101
+ }
102
+ const home = result.stdout.trim();
103
+ this.cache.homes.set(key, home);
104
+ return home;
105
+ }
106
+ async cloneIfNeeded(absRepoPath) {
107
+ const dirExists = (await this.runner.exec(`test -d ${shellQuote(absRepoPath)}`)).exitCode === 0;
108
+ const gitExists = (await this.runner.exec(`test -d ${shellQuote(`${absRepoPath}/.git`)}`)).exitCode === 0;
109
+ if (dirExists && !gitExists) {
110
+ throw new Error(`${absRepoPath} exists but is not a git repository. Remove it manually or change project.repo.`);
111
+ }
112
+ if (!dirExists) {
113
+ const parent = absRepoPath.replace(/\/[^/]+$/, '');
114
+ const mk = await this.runner.exec(`mkdir -p ${shellQuote(parent)}`);
115
+ if (mk.exitCode !== 0)
116
+ throw new Error(`Failed to mkdir ${parent}: ${mk.stderr}`);
117
+ // --no-upstream is a gh flag; do NOT prefix with `--` (that would forward to git clone).
118
+ const clone = await this.runner.exec(`gh repo clone ${shellQuote(this.repoSlug)} ${shellQuote(absRepoPath)} --no-upstream`);
119
+ if (clone.exitCode !== 0) {
120
+ throw new Error(`gh repo clone ${this.repoSlug} failed: ${clone.stderr || clone.stdout}`);
121
+ }
122
+ return;
123
+ }
124
+ const originResult = await this.runner.exec(`git -C ${shellQuote(absRepoPath)} remote get-url origin`);
125
+ if (originResult.exitCode !== 0) {
126
+ throw new Error(`Failed to read origin URL at ${absRepoPath}: ${originResult.stderr}`);
127
+ }
128
+ // GitHub treats owner/repo as case-insensitive.
129
+ const normalized = normalizeRepoUrl(originResult.stdout.trim());
130
+ if (normalized?.toLowerCase() !== this.repoSlug.toLowerCase()) {
131
+ throw new Error(`Existing repo at ${absRepoPath} has origin "${originResult.stdout.trim()}" which does not match project.repo "${this.repoSlug}". Remove the directory or change project.repo.`);
132
+ }
133
+ }
134
+ async fetchIfStale(cacheKey, absRepoPath) {
135
+ const last = this.cache.lastFetchAt.get(cacheKey) ?? 0;
136
+ if (Date.now() - last < FETCH_THROTTLE_MS)
137
+ return;
138
+ // set-head is best-effort because empty repos have no default branch yet.
139
+ const result = await this.runner.exec(`cd ${shellQuote(absRepoPath)} && git fetch --all --prune && (git remote set-head origin --auto || true)`);
140
+ if (result.exitCode !== 0) {
141
+ throw new Error(`git fetch failed at ${absRepoPath}: ${result.stderr}`);
142
+ }
143
+ this.cache.lastFetchAt.set(cacheKey, Date.now());
144
+ }
145
+ async runUnderMutex(key, fn) {
146
+ const prev = this.cache.mutex.get(key) ?? Promise.resolve();
147
+ const cur = prev.then(fn, fn);
148
+ this.cache.mutex.set(key, cur.then(() => undefined, () => undefined));
149
+ return cur;
150
+ }
151
+ }
152
+ //# sourceMappingURL=repo-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"repo-store.js","sourceRoot":"","sources":["../../src/agent/repo-store.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import type { HostConfig } from '../shared/index.js';
2
+ export interface ExecResult {
3
+ stdout: string;
4
+ stderr: string;
5
+ exitCode: number;
6
+ }
7
+ export type RemoteShellMode = 'login' | 'login-interactive';
8
+ export interface ExecOptions {
9
+ timeout?: number;
10
+ signal?: AbortSignal;
11
+ maxBuffer?: number;
12
+ remoteShell?: RemoteShellMode;
13
+ stdin?: Buffer;
14
+ }
15
+ export interface CommandRunner {
16
+ exec(command: string, options?: ExecOptions): Promise<ExecResult>;
17
+ writeFile(path: string, content: Buffer | string): Promise<void>;
18
+ /** stdin bypasses argv ARG_MAX (~1MB). */
19
+ execWithStdin(command: string, stdin: Buffer, options?: ExecOptions): Promise<ExecResult>;
20
+ }
21
+ export declare class LocalRunner implements CommandRunner {
22
+ exec(command: string, options?: ExecOptions): Promise<ExecResult>;
23
+ writeFile(filePath: string, content: Buffer | string): Promise<void>;
24
+ execWithStdin(command: string, stdin: Buffer, options?: ExecOptions): Promise<ExecResult>;
25
+ }
26
+ export declare function ensureMuxDir(): Promise<void>;
27
+ export declare function __resetMuxDirReadyForTests(): void;
28
+ export interface BuildSshOptionsArgs {
29
+ connectTimeoutSec?: number;
30
+ }
31
+ export declare function buildSshOptions(args?: BuildSshOptionsArgs): string;
32
+ export declare class SshRunner implements CommandRunner {
33
+ private host;
34
+ private local;
35
+ constructor(host: HostConfig, local?: CommandRunner);
36
+ exec(command: string, options?: ExecOptions): Promise<ExecResult>;
37
+ writeFile(filePath: string, content: Buffer | string): Promise<void>;
38
+ /** Login wrapper may consume stdin via rc — use execRawRemoteWithStdin for clean stdin. */
39
+ execWithStdin(command: string, stdin: Buffer, options?: ExecOptions): Promise<ExecResult>;
40
+ /** No login wrapper — clean stdin for load-buffer; remote runs with non-login PATH. */
41
+ execRawRemoteWithStdin(remoteCommand: string, stdin: Buffer, options?: ExecOptions): Promise<ExecResult>;
42
+ }
43
+ export declare function shellQuote(s: string): string;
44
+ export declare function wrapRemoteCommand(command: string, mode?: RemoteShellMode): string;
45
+ export declare function createRunner(mode: 'local' | 'remote', host?: HostConfig): CommandRunner;
46
+ //# sourceMappingURL=runner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/agent/runner.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAErD,MAAM,WAAW,UAAU;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;CAClB;AAGD,MAAM,MAAM,eAAe,GAAG,OAAO,GAAG,mBAAmB,CAAC;AAE5D,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAClE,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE,0CAA0C;IAC1C,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;CAC3F;AAKD,qBAAa,WAAY,YAAW,aAAa;IACzC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,UAAU,CAAC;IAIrE,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKpE,aAAa,CACjB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,UAAU,CAAC;CAGvB;AAgID,wBAAgB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAa5C;AAGD,wBAAgB,0BAA0B,IAAI,IAAI,CAEjD;AAED,MAAM,WAAW,mBAAmB;IAClC,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B;AAED,wBAAgB,eAAe,CAAC,IAAI,GAAE,mBAAwB,GAAG,MAAM,CActE;AAED,qBAAa,SAAU,YAAW,aAAa;IAG3C,OAAO,CAAC,IAAI;IAFd,OAAO,CAAC,KAAK,CAAgB;gBAEnB,IAAI,EAAE,UAAU,EACxB,KAAK,CAAC,EAAE,aAAa;IAKjB,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,UAAU,CAAC;IASrE,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAa1E,2FAA2F;IACrF,aAAa,CACjB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,UAAU,CAAC;IAQtB,uFAAuF;IACjF,sBAAsB,CAC1B,aAAa,EAAE,MAAM,EACrB,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,UAAU,CAAC;CAMvB;AAED,wBAAgB,UAAU,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAE5C;AAGD,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,GAAE,eAAyB,GAAG,MAAM,CAI1F;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,OAAO,GAAG,QAAQ,EAAE,IAAI,CAAC,EAAE,UAAU,GAAG,aAAa,CAMvF"}
@@ -0,0 +1,241 @@
1
+ import { spawn } from 'node:child_process';
2
+ import { randomBytes } from 'node:crypto';
3
+ import { mkdir, writeFile as fsWriteFile } from 'node:fs/promises';
4
+ import { homedir } from 'node:os';
5
+ import { dirname, join } from 'node:path';
6
+ const KILL_GRACE_MS = 2000;
7
+ const DEFAULT_MAX_BUFFER = 16 * 1024 * 1024;
8
+ export class LocalRunner {
9
+ async exec(command, options = {}) {
10
+ return runShell(command, options);
11
+ }
12
+ async writeFile(filePath, content) {
13
+ await mkdir(dirname(filePath), { recursive: true });
14
+ await fsWriteFile(filePath, content);
15
+ }
16
+ async execWithStdin(command, stdin, options = {}) {
17
+ return runShell(command, { ...options, stdin });
18
+ }
19
+ }
20
+ function runShell(command, options) {
21
+ return new Promise((resolve, reject) => {
22
+ if (options.signal?.aborted) {
23
+ reject(new Error('Command aborted'));
24
+ return;
25
+ }
26
+ let timeoutHit = false;
27
+ let aborted = false;
28
+ let settled = false;
29
+ let bufferExceeded = false;
30
+ let bufferedBytes = 0;
31
+ let stdout = '';
32
+ let stderr = '';
33
+ let killTimer = null;
34
+ const maxBuffer = options.maxBuffer === undefined ? DEFAULT_MAX_BUFFER : options.maxBuffer;
35
+ const internalAbort = new AbortController();
36
+ const onUserAbort = () => {
37
+ aborted = true;
38
+ internalAbort.abort();
39
+ };
40
+ if (options.signal) {
41
+ options.signal.addEventListener('abort', onUserAbort, { once: true });
42
+ }
43
+ // detached → process-group kill prevents orphaning ssh/git children.
44
+ const child = spawn('/bin/bash', ['-c', command], { detached: true });
45
+ if (options.stdin) {
46
+ // EPIPE on child exit during write — convert to abort.
47
+ child.stdin?.on('error', () => {
48
+ bufferExceeded = false;
49
+ internalAbort.abort();
50
+ });
51
+ child.stdin?.write(options.stdin);
52
+ child.stdin?.end();
53
+ }
54
+ else {
55
+ child.stdin?.end();
56
+ }
57
+ const killGroup = (sig) => {
58
+ if (typeof child.pid !== 'number')
59
+ return;
60
+ try {
61
+ process.kill(-child.pid, sig);
62
+ }
63
+ catch {
64
+ // group already gone
65
+ }
66
+ };
67
+ internalAbort.signal.addEventListener('abort', () => killGroup('SIGTERM'), { once: true });
68
+ const timer = options.timeout
69
+ ? setTimeout(() => {
70
+ timeoutHit = true;
71
+ internalAbort.abort();
72
+ killTimer = setTimeout(() => killGroup('SIGKILL'), KILL_GRACE_MS);
73
+ killTimer.unref();
74
+ }, options.timeout)
75
+ : null;
76
+ timer?.unref();
77
+ const cleanup = () => {
78
+ if (timer)
79
+ clearTimeout(timer);
80
+ if (killTimer)
81
+ clearTimeout(killTimer);
82
+ if (options.signal)
83
+ options.signal.removeEventListener('abort', onUserAbort);
84
+ };
85
+ const finish = (fn) => {
86
+ if (settled)
87
+ return;
88
+ settled = true;
89
+ cleanup();
90
+ fn();
91
+ };
92
+ const accumulate = (chunk) => {
93
+ if (bufferExceeded)
94
+ return null;
95
+ if (maxBuffer > 0 && bufferedBytes + chunk.length > maxBuffer) {
96
+ bufferExceeded = true;
97
+ internalAbort.abort();
98
+ return null;
99
+ }
100
+ bufferedBytes += chunk.length;
101
+ return chunk.toString();
102
+ };
103
+ child.stdout?.on('data', (chunk) => {
104
+ const piece = accumulate(chunk);
105
+ if (piece !== null)
106
+ stdout += piece;
107
+ });
108
+ child.stderr?.on('data', (chunk) => {
109
+ const piece = accumulate(chunk);
110
+ if (piece !== null)
111
+ stderr += piece;
112
+ });
113
+ child.on('error', (err) => {
114
+ finish(() => {
115
+ if (bufferExceeded)
116
+ return reject(new Error(`Command output exceeded maxBuffer (${maxBuffer} bytes)`));
117
+ if (timeoutHit)
118
+ return reject(new Error(`Command timed out after ${options.timeout}ms`));
119
+ if (aborted)
120
+ return reject(new Error('Command aborted'));
121
+ reject(err);
122
+ });
123
+ });
124
+ child.on('close', (code, signal) => {
125
+ finish(() => {
126
+ if (bufferExceeded)
127
+ return reject(new Error(`Command output exceeded maxBuffer (${maxBuffer} bytes)`));
128
+ if (timeoutHit)
129
+ return reject(new Error(`Command timed out after ${options.timeout}ms`));
130
+ if (aborted)
131
+ return reject(new Error('Command aborted'));
132
+ resolve({
133
+ stdout,
134
+ stderr,
135
+ exitCode: code ?? (signal ? 128 : 1),
136
+ });
137
+ });
138
+ });
139
+ });
140
+ }
141
+ // OpenSSH ControlMaster lets a backlog of short commands share one TCP+SSH session per target,
142
+ // cutting per-call TCP handshake + key exchange (~tens-of-ms each on LAN, much more on WAN).
143
+ // Caveats this design accepts: socket lives under the local user's HOME (multi-user boxes get
144
+ // per-user mux pools), and a crashed master leaves a stale socket — ControlMaster=auto detects
145
+ // and falls back to a fresh connection in that case.
146
+ const SSH_MUX_DIR = join(homedir(), '.baxian', 'ssh-mux');
147
+ const SSH_CONTROL_PERSIST = '5m';
148
+ let muxDirReady;
149
+ export function ensureMuxDir() {
150
+ if (!muxDirReady) {
151
+ // Read-only HOME / permission glitches must not strand the whole SSH path:
152
+ // ControlMaster=auto falls back to a fresh TCP connection when ControlPath is
153
+ // unreachable. Log + reset the singleton so a transient failure can recover next call.
154
+ muxDirReady = mkdir(SSH_MUX_DIR, { recursive: true, mode: 0o700 })
155
+ .then(() => undefined)
156
+ .catch(err => {
157
+ console.warn(`[runner] ensureMuxDir(${SSH_MUX_DIR}) failed; SSH will run without mux this call:`, err);
158
+ muxDirReady = undefined;
159
+ });
160
+ }
161
+ return muxDirReady;
162
+ }
163
+ // Test-only: reset the singleton so each spec exercises the first-call path.
164
+ export function __resetMuxDirReadyForTests() {
165
+ muxDirReady = undefined;
166
+ }
167
+ export function buildSshOptions(args = {}) {
168
+ const connectTimeoutSec = args.connectTimeoutSec ?? 10;
169
+ // shellQuote on the path so a HOME containing spaces / shell metacharacters cannot
170
+ // word-split into multiple argv slots (which would mangle the -- delimiter that follows).
171
+ const controlPath = shellQuote(join(SSH_MUX_DIR, 'cm-%C'));
172
+ return [
173
+ '-o BatchMode=yes',
174
+ `-o ConnectTimeout=${connectTimeoutSec}`,
175
+ '-o ServerAliveInterval=2',
176
+ '-o ServerAliveCountMax=2',
177
+ '-o ControlMaster=auto',
178
+ `-o ControlPath=${controlPath}`,
179
+ `-o ControlPersist=${SSH_CONTROL_PERSIST}`,
180
+ ].join(' ');
181
+ }
182
+ export class SshRunner {
183
+ host;
184
+ local;
185
+ constructor(host, local) {
186
+ this.host = host;
187
+ this.local = local ?? new LocalRunner();
188
+ }
189
+ async exec(command, options = {}) {
190
+ await ensureMuxDir();
191
+ const target = this.host.user ? `${this.host.user}@${this.host.hostname}` : this.host.hostname;
192
+ const wrapped = wrapRemoteCommand(command, options.remoteShell ?? 'login');
193
+ const ssh = `ssh ${buildSshOptions()} -- ${shellQuote(target)} ${shellQuote(wrapped)}`;
194
+ return this.local.exec(ssh, options);
195
+ }
196
+ // openssl avoids GNU/BSD base64 flag drift; payloads must stay below ARG_MAX.
197
+ async writeFile(filePath, content) {
198
+ const buf = typeof content === 'string' ? Buffer.from(content, 'utf8') : content;
199
+ const b64 = buf.toString('base64');
200
+ const eof = `BAXIAN_EOF_${randomBytes(4).toString('hex')}`;
201
+ const cmd = `mkdir -p ${shellQuote(dirname(filePath))} && ` +
202
+ `openssl base64 -d -A > ${shellQuote(filePath)} <<'${eof}'\n${b64}\n${eof}`;
203
+ const r = await this.exec(cmd);
204
+ if (r.exitCode !== 0) {
205
+ throw new Error(`writeFile remote failed (${filePath}): ${r.stderr}`);
206
+ }
207
+ }
208
+ /** Login wrapper may consume stdin via rc — use execRawRemoteWithStdin for clean stdin. */
209
+ async execWithStdin(command, stdin, options = {}) {
210
+ await ensureMuxDir();
211
+ const target = this.host.user ? `${this.host.user}@${this.host.hostname}` : this.host.hostname;
212
+ const wrapped = wrapRemoteCommand(command, options.remoteShell ?? 'login');
213
+ const ssh = `ssh ${buildSshOptions()} -- ${shellQuote(target)} ${shellQuote(wrapped)}`;
214
+ return this.local.execWithStdin(ssh, stdin, options);
215
+ }
216
+ /** No login wrapper — clean stdin for load-buffer; remote runs with non-login PATH. */
217
+ async execRawRemoteWithStdin(remoteCommand, stdin, options = {}) {
218
+ await ensureMuxDir();
219
+ const target = this.host.user ? `${this.host.user}@${this.host.hostname}` : this.host.hostname;
220
+ const ssh = `ssh ${buildSshOptions()} -- ${shellQuote(target)} ${shellQuote(remoteCommand)}`;
221
+ return this.local.execWithStdin(ssh, stdin, options);
222
+ }
223
+ }
224
+ export function shellQuote(s) {
225
+ return `'${s.replace(/'/g, "'\\''")}'`;
226
+ }
227
+ // sh as outer shell so fish accepts the $SHELL handoff.
228
+ export function wrapRemoteCommand(command, mode = 'login') {
229
+ const flags = mode === 'login-interactive' ? '-l -i -c' : '-l -c';
230
+ const inner = `exec "\${SHELL:-/bin/sh}" ${flags} "$1"`;
231
+ return `sh -c ${shellQuote(inner)} _ ${shellQuote(command)}`;
232
+ }
233
+ export function createRunner(mode, host) {
234
+ if (mode === 'remote') {
235
+ if (!host)
236
+ throw new Error('Remote mode requires host config');
237
+ return new SshRunner(host);
238
+ }
239
+ return new LocalRunner();
240
+ }
241
+ //# sourceMappingURL=runner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runner.js","sourceRoot":"","sources":["../../src/agent/runner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,33 @@
1
+ import type { AgentConfig } from '../shared/index.js';
2
+ import type { EventBus } from '../event/bus.js';
3
+ import type { PaneStreamerManager } from './pane-streamer-manager.js';
4
+ import { type ShortMarkerKind } from './marker-protocol.js';
5
+ export type SpecMarkerKind = Extract<ShortMarkerKind, 'spec-ready' | 'spec-review-complete' | 'spec-fix-complete'>;
6
+ export interface SpecReviewMarkerWatcherDeps {
7
+ paneStreamerManager: PaneStreamerManager;
8
+ eventBus: EventBus;
9
+ resolveAgent: (agentId: string) => AgentConfig | undefined;
10
+ }
11
+ export interface SpecReviewMarkerStartArgs {
12
+ taskId: string;
13
+ projectId: string;
14
+ agentId: string;
15
+ kind: SpecMarkerKind;
16
+ token: string;
17
+ skipSnapshot?: boolean;
18
+ }
19
+ export declare class SpecReviewMarkerWatcher {
20
+ private readonly deps;
21
+ private readonly entries;
22
+ constructor(deps: SpecReviewMarkerWatcherDeps);
23
+ start(args: SpecReviewMarkerStartArgs): Promise<void>;
24
+ /** Stops a single kind; without kind stops all kinds for the task. */
25
+ stop(taskId: string, kind?: SpecMarkerKind): void;
26
+ has(taskId: string, kind: SpecMarkerKind): boolean;
27
+ private onPaneData;
28
+ private emitCompletion;
29
+ private onSessionGone;
30
+ private emitArmFailureIntervention;
31
+ private emitInterventionFireAndForget;
32
+ }
33
+ //# sourceMappingURL=spec-review-marker-watcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"spec-review-marker-watcher.d.ts","sourceRoot":"","sources":["../../src/agent/spec-review-marker-watcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,WAAW,EAGZ,MAAM,oBAAoB,CAAC;AAC5B,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAoB,KAAK,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAI9E,MAAM,MAAM,cAAc,GAAG,OAAO,CAClC,eAAe,EACf,YAAY,GAAG,sBAAsB,GAAG,mBAAmB,CAC5D,CAAC;AAmBF,MAAM,WAAW,2BAA2B;IAC1C,mBAAmB,EAAE,mBAAmB,CAAC;IACzC,QAAQ,EAAE,QAAQ,CAAC;IACnB,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,WAAW,GAAG,SAAS,CAAC;CAC5D;AAED,MAAM,WAAW,yBAAyB;IACxC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,cAAc,CAAC;IACrB,KAAK,EAAE,MAAM,CAAC;IAEd,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAMD,qBAAa,uBAAuB;IAGtB,OAAO,CAAC,QAAQ,CAAC,IAAI;IAFjC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAiC;gBAE5B,IAAI,EAAE,2BAA2B;IAExD,KAAK,CAAC,IAAI,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC;IAoD3D,sEAAsE;IACtE,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,cAAc,GAAG,IAAI;IAgBjD,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,cAAc,GAAG,OAAO;IAIlD,OAAO,CAAC,UAAU;YA8BJ,cAAc;IAoB5B,OAAO,CAAC,aAAa;YAcP,0BAA0B;YAa1B,6BAA6B;CA2B5C"}